diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index e24547a6abff..5711d2f8322b 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -14,7 +14,9 @@ disabled: - x-pack/test/api_integration/config.ts - x-pack/test/fleet_api_integration/config.base.ts - x-pack/test/security_solution_api_integration/config/ess/config.base.ts + - x-pack/test/security_solution_api_integration/config/ess/config.base.basic.ts - x-pack/test/security_solution_api_integration/config/serverless/config.base.ts + - x-pack/test/security_solution_api_integration/config/serverless/config.base.essentials.ts - x-pack/test/security_solution_endpoint/config.base.ts - x-pack/test/security_solution_endpoint_api_int/config.base.ts @@ -156,7 +158,9 @@ enabled: - test/server_integration/http/ssl_with_p12/config.js - test/server_integration/http/ssl/config.js - test/ui_capabilities/newsfeed_err/config.ts - - x-pack/test/accessibility/config.ts + - x-pack/test/accessibility/apps/group1/config.ts + - x-pack/test/accessibility/apps/group2/config.ts + - x-pack/test/accessibility/apps/group3/config.ts - x-pack/test/localization/config.ja_jp.ts - x-pack/test/localization/config.fr_fr.ts - x-pack/test/localization/config.zh_cn.ts @@ -164,8 +168,10 @@ enabled: - x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts - x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts - x-pack/test/alerting_api_integration/security_and_spaces/group3/config.ts + - x-pack/test/alerting_api_integration/security_and_spaces/group4/config.ts - x-pack/test/alerting_api_integration/security_and_spaces/group3/config_with_schedule_circuit_breaker.ts - x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts + - x-pack/test/alerting_api_integration/security_and_spaces/group4/config_non_dedicated_task_runner.ts - x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/config.ts - x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/config.ts - x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/config.ts @@ -185,6 +191,7 @@ enabled: - x-pack/test/api_integration/apis/es/config.ts - x-pack/test/api_integration/apis/features/config.ts - x-pack/test/api_integration/apis/file_upload/config.ts + - x-pack/test/api_integration/apis/grok_debugger/config.ts - x-pack/test/api_integration/apis/kibana/config.ts - x-pack/test/api_integration/apis/lists/config.ts - x-pack/test/api_integration/apis/logs_ui/config.ts @@ -222,12 +229,10 @@ enabled: - x-pack/test/cases_api_integration/spaces_only/config.ts - x-pack/test/cloud_security_posture_functional/config.ts - x-pack/test/cloud_security_posture_api/config.ts + - x-pack/test/dataset_quality_api_integration/basic/config.ts - x-pack/test/detection_engine_api_integration/basic/config.ts - x-pack/test/detection_engine_api_integration/security_and_spaces/group1/config.ts - - x-pack/test/detection_engine_api_integration/security_and_spaces/group4/config.ts - - x-pack/test/detection_engine_api_integration/security_and_spaces/group5/config.ts - x-pack/test/detection_engine_api_integration/security_and_spaces/group10/config.ts - - x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/config.ts - x-pack/test/disable_ems/config.ts - x-pack/test/encrypted_saved_objects_api_integration/config.ts - x-pack/test/examples/config.ts @@ -318,6 +323,7 @@ enabled: - x-pack/test/functional/apps/transform/feature_controls/config.ts - x-pack/test/functional/apps/upgrade_assistant/config.ts - x-pack/test/functional/apps/uptime/config.ts + - x-pack/test/functional/apps/user_profiles/config.ts - x-pack/test/functional/apps/visualize/config.ts - x-pack/test/functional/apps/watcher/config.ts - x-pack/test/functional/config_security_basic.ts @@ -328,7 +334,6 @@ enabled: - x-pack/test/kubernetes_security/basic/config.ts - x-pack/test/licensing_plugin/config.public.ts - x-pack/test/licensing_plugin/config.ts - - x-pack/test/lists_api_integration/security_and_spaces/config.ts - x-pack/test/monitoring_api_integration/config.ts - x-pack/test/observability_api_integration/basic/config.ts - x-pack/test/observability_api_integration/trial/config.ts @@ -411,6 +416,8 @@ enabled: - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group3.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group4.ts + - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts + - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group6.ts - x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts - x-pack/test_serverless/functional/test_suites/search/config.ts - x-pack/test_serverless/functional/test_suites/search/config.examples.ts @@ -419,6 +426,8 @@ enabled: - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group3.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group4.ts + - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts + - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group6.ts - x-pack/test_serverless/functional/test_suites/security/config.ts - x-pack/test_serverless/functional/test_suites/security/config.examples.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.ts @@ -426,6 +435,8 @@ enabled: - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group3.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group4.ts + - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts + - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group6.ts - x-pack/performance/journeys/ecommerce_dashboard.ts - x-pack/performance/journeys/ecommerce_dashboard_map_only.ts - x-pack/performance/journeys/flight_dashboard.ts @@ -445,7 +456,6 @@ enabled: - x-pack/performance/journeys/apm_service_inventory.ts - x-pack/test/custom_branding/config.ts - x-pack/test/profiling_api_integration/cloud/config.ts - - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/serverless.config.ts @@ -474,3 +484,17 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/large_prebuilt_rules_package/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/update_prebuilt_rules_package/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/update_prebuilt_rules_package/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/ess.config.ts + - x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/serverless.config.ts + - x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/ess.config.ts + + diff --git a/.buildkite/pipeline-utils/buildkite/client.ts b/.buildkite/pipeline-utils/buildkite/client.ts index fe3f2041646e..313b48b56e49 100644 --- a/.buildkite/pipeline-utils/buildkite/client.ts +++ b/.buildkite/pipeline-utils/buildkite/client.ts @@ -7,16 +7,21 @@ */ import axios, { AxiosInstance } from 'axios'; -import { execSync } from 'child_process'; +import { execSync, ExecSyncOptions } from 'child_process'; import { dump } from 'js-yaml'; import { parseLinkHeader } from './parse_link_header'; import { Artifact } from './types/artifact'; import { Build, BuildStatus } from './types/build'; import { Job, JobState } from './types/job'; +type ExecType = + | ((command: string, execOpts: ExecSyncOptions) => Buffer | null) + | ((command: string, execOpts: ExecSyncOptions) => string | null); + export interface BuildkiteClientConfig { baseUrl?: string; token?: string; + exec?: ExecType; } export interface BuildkiteGroup { @@ -24,7 +29,9 @@ export interface BuildkiteGroup { steps: BuildkiteStep[]; } -export interface BuildkiteStep { +export type BuildkiteStep = BuildkiteCommandStep | BuildkiteInputStep; + +export interface BuildkiteCommandStep { command: string; label: string; parallelism?: number; @@ -43,6 +50,50 @@ export interface BuildkiteStep { env?: { [key: string]: string }; } +interface BuildkiteInputTextField { + text: string; + key: string; + hint?: string; + required?: boolean; + default?: string; +} + +interface BuildkiteInputSelectField { + select: string; + key: string; + hint?: string; + required?: boolean; + default?: string; + multiple?: boolean; + options: Array<{ + label: string; + value: string; + }>; +} + +export interface BuildkiteInputStep { + input: string; + prompt?: string; + fields: Array; + if?: string; + allow_dependency_failure?: boolean; + branches?: string; + parallelism?: number; + agents?: { + queue: string; + }; + timeout_in_minutes?: number; + key?: string; + depends_on?: string | string[]; + retry?: { + automatic: Array<{ + exit_status: string; + limit: number; + }>; + }; + env?: { [key: string]: string }; +} + export interface BuildkiteTriggerBuildParams { commit: string; branch: string; @@ -61,6 +112,7 @@ export interface BuildkiteTriggerBuildParams { export class BuildkiteClient { http: AxiosInstance; + exec: ExecType; constructor(config: BuildkiteClientConfig = {}) { const BUILDKITE_BASE_URL = @@ -78,6 +130,8 @@ export class BuildkiteClient { }, }); + this.exec = config.exec ?? execSync; + // this.agentHttp = axios.create({ // baseURL: BUILDKITE_AGENT_BASE_URL, // headers: { @@ -97,6 +151,32 @@ export class BuildkiteClient { return resp.data as Build; }; + getBuildsAfterDate = async ( + pipelineSlug: string, + date: string, + numberOfBuilds: number + ): Promise => { + const response = await this.http.get( + `v2/organizations/elastic/pipelines/${pipelineSlug}/builds?created_from=${date}&per_page=${numberOfBuilds}` + ); + return response.data as Build[]; + }; + + getBuildForCommit = async (pipelineSlug: string, commit: string): Promise => { + if (commit.length !== 40) { + throw new Error(`Invalid commit hash: ${commit}, this endpoint works with full SHAs only`); + } + + const response = await this.http.get( + `v2/organizations/elastic/pipelines/${pipelineSlug}/builds?commit=${commit}` + ); + const builds = response.data as Build[]; + if (builds.length === 0) { + return null; + } + return builds[0]; + }; + getCurrentBuild = (includeRetriedJobs = false) => { if (!process.env.BUILDKITE_PIPELINE_SLUG || !process.env.BUILDKITE_BUILD_NUMBER) { throw new Error( @@ -235,31 +315,52 @@ export class BuildkiteClient { }; setMetadata = (key: string, value: string) => { - execSync(`buildkite-agent meta-data set '${key}'`, { + this.exec(`buildkite-agent meta-data set '${key}'`, { input: value, stdio: ['pipe', 'inherit', 'inherit'], }); }; + getMetadata(key: string, defaultValue: string | null = null): string | null { + try { + const stdout = this.exec(`buildkite-agent meta-data get '${key}'`, { + stdio: ['pipe'], + }); + return stdout?.toString().trim() || defaultValue; + } catch (e) { + if (e.message.includes('404 Not Found')) { + return defaultValue; + } else { + throw e; + } + } + } + setAnnotation = ( context: string, style: 'info' | 'success' | 'warning' | 'error', - value: string + value: string, + append: boolean = false ) => { - execSync(`buildkite-agent annotate --context '${context}' --style '${style}'`, { - input: value, - stdio: ['pipe', 'inherit', 'inherit'], - }); + this.exec( + `buildkite-agent annotate --context '${context}' --style '${style}' ${ + append ? '--append' : '' + }`, + { + input: value, + stdio: ['pipe', 'inherit', 'inherit'], + } + ); }; uploadArtifacts = (pattern: string) => { - execSync(`buildkite-agent artifact upload '${pattern}'`, { + this.exec(`buildkite-agent artifact upload '${pattern}'`, { stdio: ['ignore', 'inherit', 'inherit'], }); }; uploadSteps = (steps: Array) => { - execSync(`buildkite-agent pipeline upload`, { + this.exec(`buildkite-agent pipeline upload`, { input: dump({ steps }), stdio: ['pipe', 'inherit', 'inherit'], }); diff --git a/.buildkite/pipeline-utils/ci-stats/client.ts b/.buildkite/pipeline-utils/ci-stats/client.ts index 6a5c048464c7..d7367b89947a 100644 --- a/.buildkite/pipeline-utils/ci-stats/client.ts +++ b/.buildkite/pipeline-utils/ci-stats/client.ts @@ -201,7 +201,7 @@ export class CiStatsClient { headers: this.defaultHeaders, }); } catch (error) { - console.error('CI Stats request error:', error); + console.error('CI Stats request error:', error?.response?.data?.message); if (attempt < maxAttempts) { const sec = attempt * 3; @@ -210,7 +210,7 @@ export class CiStatsClient { continue; } - throw error; + throw new Error('Failed to connect to CI Stats.'); } } } diff --git a/.buildkite/pipeline-utils/ci-stats/on_complete.ts b/.buildkite/pipeline-utils/ci-stats/on_complete.ts index 0b93fd6b0673..ea95442dab88 100644 --- a/.buildkite/pipeline-utils/ci-stats/on_complete.ts +++ b/.buildkite/pipeline-utils/ci-stats/on_complete.ts @@ -28,7 +28,15 @@ export async function onComplete() { const report = await ciStats.getPrReport(process.env.CI_STATS_BUILD_ID); if (report?.md) { - buildkite.setMetadata('pr_comment:ci_stats_report:body', report.md); + // buildkite has a metadata size limit of 100kb, so we only add this, if it's small enough + if (new Blob([report.md]).size < 100000) { + buildkite.setMetadata('pr_comment:ci_stats_report:body', report.md); + } else { + buildkite.setMetadata( + 'pr_comment:ci_stats_report:body', + 'The CI Stats report is too large to be displayed here, check out the CI build annotation for this information.' + ); + } const annotationType = report?.success ? 'info' : 'error'; buildkite.setAnnotation('ci-stats-report', annotationType, report.md); diff --git a/.buildkite/pipeline-utils/github/github.ts b/.buildkite/pipeline-utils/github/github.ts index fc6ab42a69a5..ff1bd2e65ccf 100644 --- a/.buildkite/pipeline-utils/github/github.ts +++ b/.buildkite/pipeline-utils/github/github.ts @@ -91,3 +91,7 @@ export const doAnyChangesMatch = async ( return anyFilesMatchRequired; }; + +export function getGithubClient() { + return github; +} diff --git a/.buildkite/pipeline-utils/index.ts b/.buildkite/pipeline-utils/index.ts index 113ab1ac2458..b8da40de58f2 100644 --- a/.buildkite/pipeline-utils/index.ts +++ b/.buildkite/pipeline-utils/index.ts @@ -10,3 +10,4 @@ export * from './buildkite'; export * as CiStats from './ci-stats'; export * from './github'; export * as TestFailures from './test-failures'; +export * from './utils'; diff --git a/.buildkite/pipeline-utils/utils.ts b/.buildkite/pipeline-utils/utils.ts new file mode 100644 index 000000000000..e9a5cf919333 --- /dev/null +++ b/.buildkite/pipeline-utils/utils.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { execSync } from 'child_process'; + +const getKibanaDir = (() => { + let kibanaDir: string | undefined; + return () => { + if (!kibanaDir) { + kibanaDir = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }) + .toString() + .trim(); + } + + return kibanaDir; + }; +})(); + +export { getKibanaDir }; diff --git a/.buildkite/pipelines/artifacts.yml b/.buildkite/pipelines/artifacts.yml index 4a52ee740282..64ebe01e9227 100644 --- a/.buildkite/pipelines/artifacts.yml +++ b/.buildkite/pipelines/artifacts.yml @@ -61,7 +61,7 @@ steps: - exit_status: '*' limit: 1 - - command: KIBANA_DOCKER_CONTEXT=ubi9 .buildkite/scripts/steps/artifacts/docker_context.sh + - command: KIBANA_DOCKER_CONTEXT=ubi .buildkite/scripts/steps/artifacts/docker_context.sh label: 'Docker Context Verification' agents: queue: n2-2 diff --git a/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml index 8e64513b1490..8d1b778b6798 100644 --- a/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml +++ b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml @@ -95,6 +95,32 @@ steps: - exit_status: '*' limit: 1 + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management.sh + label: 'Serverless Rule Management - Security Solution Cypress Tests' + if: "build.env('SKIP_CYPRESS') != '1' && build.env('SKIP_CYPRESS') != 'true'" + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh + label: 'Serverless Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + if: "build.env('SKIP_CYPRESS') != '1' && build.env('SKIP_CYPRESS') != 'true'" + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + - command: .buildkite/scripts/steps/functional/defend_workflows_serverless.sh label: 'Defend Workflows Cypress Tests on Serverless' if: "build.env('SKIP_CYPRESS') != '1' && build.env('SKIP_CYPRESS') != 'true'" diff --git a/.buildkite/pipelines/flaky_tests/groups.json b/.buildkite/pipelines/flaky_tests/groups.json index 1a5799a86285..99f88fe590a1 100644 --- a/.buildkite/pipelines/flaky_tests/groups.json +++ b/.buildkite/pipelines/flaky_tests/groups.json @@ -23,6 +23,23 @@ { "key": "cypress/security_serverless_explore", "name": "[Serverless] Security Solution Explore - Cypress" + }, + { + "key": "cypress/security_solution_rule_management", + "name": "Security Solution Rule Management - Cypress" + }, + { + "key": "cypress/security_serverless_rule_management", + "name": "[Serverless] Security Solution Rule Management - Cypress" + }, + + { + "key": "cypress/security_solution_rule_management_prebuilt_rules", + "name": "Security Solution Rule Management - Prebuilt Rules - Cypress" + }, + { + "key": "cypress/security_serverless_rule_management_prebuilt_rules", + "name": "[Serverless] Security Solution Rule Management - Prebuilt Rules - Cypress" }, { "key": "cypress/defend_workflows", diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 8b00db428a71..f92089099cbc 100644 --- a/.buildkite/pipelines/on_merge.yml +++ b/.buildkite/pipelines/on_merge.yml @@ -115,6 +115,54 @@ steps: - exit_status: '*' limit: 1 + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management.sh + label: 'Serverless Rule Management - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh + label: 'Serverless Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_solution_rule_management.sh + label: 'Rule Management - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_solution_rule_management_prebuilt_rules.sh + label: 'Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + - command: .buildkite/scripts/steps/functional/security_solution.sh label: 'Security Solution Cypress Tests' agents: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index 49215bbd00f1..8238afbee4fd 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -93,6 +93,30 @@ steps: - exit_status: '*' limit: 1 + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management.sh + label: 'Serverless Rule Management - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh + label: 'Serverless Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + - command: .buildkite/scripts/steps/functional/security_solution.sh label: 'Security Solution Cypress Tests' agents: @@ -117,6 +141,30 @@ steps: - exit_status: '*' limit: 1 + - command: .buildkite/scripts/steps/functional/security_solution_rule_management.sh + label: 'Rule Management - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/steps/functional/security_solution_rule_management_prebuilt_rules.sh + label: 'Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 60 + parallelism: 6 + retry: + automatic: + - exit_status: '*' + limit: 1 + - command: .buildkite/scripts/steps/functional/security_solution_investigations.sh label: 'Investigations - Security Solution Cypress Tests' agents: diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml index 3e8a2358a9d3..7cdc07ec861f 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml @@ -11,6 +11,8 @@ steps: TARGET_ENV: production CHECK_SLO: true CHECK_SLO_TAG: kibana + CHECK_SLO_WAITING_PERIOD: 15m + CHECK_SLO_BURN_RATE_THRESHOLD: 0.1 soft_fail: true - label: ":rocket: control-plane e2e tests" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml index feac7bdb1784..2ee943d72ee0 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml @@ -46,13 +46,3 @@ steps: USE_GROUP_LABEL: true agents: image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.6" - - - group: "Observability" - steps: - - label: ":judge::seedling: Trigger Manual Tests Phase - Observability" - command: "make -C /agent trigger-manual-verification-phase" - env: - NOTIFICATION_APPENDIX: " please execute your manual testing plan." - USE_GROUP_LABEL: true - agents: - image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.6" diff --git a/.buildkite/pipelines/security_solution/api_integration.yml b/.buildkite/pipelines/security_solution/api_integration.yml index b4c6cece31c4..0fbc23bcab68 100644 --- a/.buildkite/pipelines/security_solution/api_integration.yml +++ b/.buildkite/pipelines/security_solution/api_integration.yml @@ -1,7 +1,7 @@ steps: - - label: Running exception_workflows:runner:serverless + - label: Running exception_workflows:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_workflows:qa:serverless - key: exception_workflows:runner:serverless + key: exception_workflows:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -10,9 +10,9 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_date_numeric_types:runner:serverless + - label: Running exception_operators_date_numeric_types:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_date_numeric_types:qa:serverless - key: exception_operators_date_numeric_types:runner:serverless + key: exception_operators_date_numeric_types:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -21,9 +21,20 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_keyword_text_long:runner:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_keyword_text_long:qa:serverless - key: exception_operators_keyword_text_long:runner:serverless + - label: Running exception_operators_keyword:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_keyword:qa:serverless + key: exception_operators_keyword:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '*' + limit: 2 + + - label: Running exception_operators_ips:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_ips:qa:serverless + key: exception_operators_ips:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -32,9 +43,9 @@ steps: - exit_status: '*' limit: 2 - - label: Running exception_operators_ips_text_array:runner:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_ips_text_array:qa:serverless - key: exception_operators_ips_text_array:runner:serverless + - label: Running exception_operators_long:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_long:qa:serverless + key: exception_operators_long:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -42,10 +53,22 @@ steps: automatic: - exit_status: '1' limit: 2 + - - label: Running rule_creation:runner:serverless + - label: Running exception_operators_text:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh exception_operators_text:qa:serverless + key: exception_operators_text:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_creation:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh rule_creation:qa:serverless - key: rule_creation:runner:serverless + key: rule_creation:qa:serverless agents: queue: n2-4-spot timeout_in_minutes: 120 @@ -64,4 +87,92 @@ steps: automatic: - exit_status: '1' limit: 2 - + + - label: Running entity_analytics:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh entity_analytics:qa:serverless + key: entity_analytics:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_management:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_management:qa:serverless + key: prebuilt_rules_management:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_large_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_large_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running prebuilt_rules_update_prebuilt_rules_package:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_update_prebuilt_rules_package:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running rule_execution_logic:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh rule_execution_logic:qa:serverless + key: rule_execution_logic:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running user_roles:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh user_roles:qa:serverless + key: user_roles:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + + - label: Running telemetry:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api-integration-tests.sh telemetry:qa:serverless + key: telemetry:qa:serverless + agents: + queue: n2-4-spot + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '1' + limit: 2 + \ No newline at end of file diff --git a/.buildkite/pipelines/security_solution/security_solution_cypress.yml b/.buildkite/pipelines/security_solution/security_solution_cypress.yml index 247505ef1c85..77e7fea57435 100644 --- a/.buildkite/pipelines/security_solution/security_solution_cypress.yml +++ b/.buildkite/pipelines/security_solution/security_solution_cypress.yml @@ -30,6 +30,30 @@ steps: # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. timeout_in_minutes: 300 parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management + label: 'Serverless MKI QA Rule Management - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 8 + retry: + automatic: + - exit_status: '*' + limit: 1 + + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management:prebuilt_rules + label: 'Serverless MKI QA Rule Management - Prebuilt Rules - Security Solution Cypress Tests' + agents: + queue: n2-4-spot + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 6 retry: automatic: - exit_status: '*' diff --git a/.buildkite/pipelines/serverless_deployment/create_deployment_tag.yml b/.buildkite/pipelines/serverless_deployment/create_deployment_tag.yml new file mode 100644 index 000000000000..e6aa863d2710 --- /dev/null +++ b/.buildkite/pipelines/serverless_deployment/create_deployment_tag.yml @@ -0,0 +1,37 @@ +## Creates deploy@ tag on Kibana + +agents: + queue: kibana-default + +steps: + - label: "List potential commits" + commands: + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state initialize + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state collect_commits + - ts-node .buildkite/scripts/serverless/create_deploy_tag/list_commit_candidates.ts 50 + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state wait_for_selection + key: select_commit + env: + AUTO_SELECT_COMMIT: $AUTO_SELECT_COMMIT + + - wait: ~ + + - label: "Collect commit info" + commands: + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state collect_commit_info + - bash .buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.sh + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state wait_for_confirmation + key: collect_data + depends_on: select_commit + env: + AUTO_SELECT_COMMIT: $AUTO_SELECT_COMMIT + + - wait: ~ + + - label: ":ship: Create Deploy Tag" + commands: + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state create_deploy_tag + - bash .buildkite/scripts/serverless/create_deploy_tag/create_deploy_tag.sh + - ts-node .buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts --state tag_created + env: + DRY_RUN: $DRY_RUN diff --git a/.buildkite/pull_requests.json b/.buildkite/pull_requests.json index 41de2dc843d4..65a3ff6ba200 100644 --- a/.buildkite/pull_requests.json +++ b/.buildkite/pull_requests.json @@ -55,14 +55,14 @@ "repoName": "kibana", "pipelineSlug": "kibana-kme-test", - "enabled": false, + "enabled": true, "allow_org_users": true, "allowed_repo_permissions": ["admin", "write"], "allowed_list": ["barlowm", "renovate[bot]"], "set_commit_status": true, - "commit_status_context": "kibana-ci", + "commit_status_context": "kibana-ci-test", "build_on_commit": true, - "build_on_comment": true, + "build_on_comment": false, "trigger_comment_regex": "^(?:(?:buildkite\\W+)?(?:build|test)\\W+(?:this|it))", "always_trigger_comment_regex": "^(?:(?:buildkite\\W+)?(?:build|test)\\W+(?:this|it))", "skip_ci_labels": [], diff --git a/.buildkite/scripts/lifecycle/pre_build.sh b/.buildkite/scripts/lifecycle/pre_build.sh index 62f94dd493fa..b8ccaf04f9bb 100755 --- a/.buildkite/scripts/lifecycle/pre_build.sh +++ b/.buildkite/scripts/lifecycle/pre_build.sh @@ -8,8 +8,6 @@ if [[ "${GITHUB_BUILD_COMMIT_STATUS_ENABLED:-}" != "true" ]]; then "$(dirname "${0}")/commit_status_start.sh" fi -export CI_STATS_TOKEN="$(retry 5 5 vault read -field=api_token secret/kibana-issues/dev/kibana_ci_stats)" -export CI_STATS_HOST="$(retry 5 5 vault read -field=api_host secret/kibana-issues/dev/kibana_ci_stats)" ts-node "$(dirname "${0}")/ci_stats_start.ts" diff --git a/.buildkite/scripts/lifecycle/pre_command.sh b/.buildkite/scripts/lifecycle/pre_command.sh index 9cfa973b2802..10a43f4ac9b0 100755 --- a/.buildkite/scripts/lifecycle/pre_command.sh +++ b/.buildkite/scripts/lifecycle/pre_command.sh @@ -77,16 +77,16 @@ EOF { CI_STATS_BUILD_ID="$(buildkite-agent meta-data get ci_stats_build_id --default '')" export CI_STATS_BUILD_ID + + CI_STATS_TOKEN="$(retry 5 5 vault read -field=api_token secret/kibana-issues/dev/kibana_ci_stats)" + export CI_STATS_TOKEN + + CI_STATS_HOST="$(retry 5 5 vault read -field=api_host secret/kibana-issues/dev/kibana_ci_stats)" + export CI_STATS_HOST if [[ "$CI_STATS_BUILD_ID" ]]; then echo "CI Stats Build ID: $CI_STATS_BUILD_ID" - CI_STATS_TOKEN="$(retry 5 5 vault read -field=api_token secret/kibana-issues/dev/kibana_ci_stats)" - export CI_STATS_TOKEN - - CI_STATS_HOST="$(retry 5 5 vault read -field=api_host secret/kibana-issues/dev/kibana_ci_stats)" - export CI_STATS_HOST - KIBANA_CI_STATS_CONFIG=$(jq -n \ --arg buildId "$CI_STATS_BUILD_ID" \ --arg apiUrl "https://$CI_STATS_HOST" \ @@ -139,6 +139,9 @@ export SYNTHETICS_REMOTE_KIBANA_PASSWORD SYNTHETICS_REMOTE_KIBANA_URL=${SYNTHETICS_REMOTE_KIBANA_URL-"$(retry 5 5 vault read -field=url secret/kibana-issues/dev/kibana-ci-synthetics-remote-credentials)"} export SYNTHETICS_REMOTE_KIBANA_URL +DEPLOY_TAGGER_SLACK_WEBHOOK_URL=${DEPLOY_TAGGER_SLACK_WEBHOOK_URL:-"$(retry 5 5 vault read -field=DEPLOY_TAGGER_SLACK_WEBHOOK_URL secret/kibana-issues/dev/kibana-serverless-release-tools)"} +export DEPLOY_TAGGER_SLACK_WEBHOOK_URL + # Setup Failed Test Reporter Elasticsearch credentials { TEST_FAILURES_ES_CLOUD_ID=$(retry 5 5 vault read -field=cloud_id secret/kibana-issues/dev/failed_tests_reporter_es) diff --git a/.buildkite/scripts/packer_cache.sh b/.buildkite/scripts/packer_cache.sh index 727accaeead8..66d663180ec3 100755 --- a/.buildkite/scripts/packer_cache.sh +++ b/.buildkite/scripts/packer_cache.sh @@ -14,5 +14,9 @@ for version in $(cat versions.json | jq -r '.versions[].version'); do node scripts/es snapshot --download-only --base-path "$ES_CACHE_DIR" --version "$version" done +for version in $(cat versions.json | jq -r '.versions[].version'); do + node x-pack/plugins/security_solution/scripts/endpoint/agent_downloader --version "$version" +done + echo "--- Cloning repos for docs build" node scripts/validate_next_docs --clone-only diff --git a/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.sh b/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.sh new file mode 100755 index 000000000000..5763e68f15fc --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# SO migration comparison lives in the Kibana dev app code, needs bootstrapping +.buildkite/scripts/bootstrap.sh + +echo "--- Collecting commit info" +ts-node .buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.ts + +if [[ "$AUTO_SELECT_COMMIT" == "true" || "$AUTO_SELECT_COMMIT" == "1" ]]; then + echo "--- Auto promoting to RC, skipping confirmation" +else + echo "--- Uploading confirmation step" + cat << EOF | buildkite-agent pipeline upload + steps: + - block: "Confirm deployment" + prompt: "Are you sure you want to deploy to production? (dry run: ${DRY_RUN:-false})" + depends_on: collect_data +EOF +fi diff --git a/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.ts b/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.ts new file mode 100644 index 000000000000..ce30a3a71d8e --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/collect_commit_info.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { COMMIT_INFO_CTX, exec } from './shared'; +import { + toGitCommitExtract, + getCurrentQARelease, + getSelectedCommitHash, + getCommitByHash, + makeCommitInfoHtml, +} from './info_sections/commit_info'; +import { + getArtifactBuild, + getOnMergePRBuild, + getQAFBuildContainingCommit, + makeBuildkiteBuildInfoHtml, +} from './info_sections/build_info'; +import { + compareSOSnapshots, + makeSOComparisonBlockHtml, + makeSOComparisonErrorHtml, +} from './info_sections/so_snapshot_comparison'; +import { makeUsefulLinksHtml } from './info_sections/useful_links'; + +async function main() { + const previousSha = await getCurrentQARelease(); + const selectedSha = getSelectedCommitHash(); + + // Current commit info + const previousCommit = await getCommitByHash(previousSha); + const previousCommitInfo = toGitCommitExtract(previousCommit); + addBuildkiteInfoSection(makeCommitInfoHtml('Current commit on QA:', previousCommitInfo)); + + // Target commit info + const selectedCommit = await getCommitByHash(selectedSha); + const selectedCommitInfo = toGitCommitExtract(selectedCommit); + addBuildkiteInfoSection(makeCommitInfoHtml('Target commit to deploy:', selectedCommitInfo)); + + // Buildkite build info + const buildkiteBuild = await getOnMergePRBuild(selectedSha); + const nextBuildContainingCommit = await getQAFBuildContainingCommit( + selectedSha, + selectedCommitInfo.date! + ); + const artifactBuild = await getArtifactBuild(selectedSha); + addBuildkiteInfoSection( + makeBuildkiteBuildInfoHtml('Relevant build info:', { + 'Merge build': buildkiteBuild, + 'Artifact container build': artifactBuild, + 'Next QAF test build containing this commit': nextBuildContainingCommit, + }) + ); + + // Save Object migration comparison + const comparisonResult = compareSOSnapshots(previousSha, selectedSha); + if (comparisonResult) { + addBuildkiteInfoSection(makeSOComparisonBlockHtml(comparisonResult)); + } else { + addBuildkiteInfoSection(makeSOComparisonErrorHtml()); + } + + // Useful links + addBuildkiteInfoSection( + makeUsefulLinksHtml('Useful links:', { + previousCommitHash: previousSha, + selectedCommitHash: selectedSha, + }) + ); +} + +function addBuildkiteInfoSection(html: string) { + exec(`buildkite-agent annotate --append --style 'info' --context '${COMMIT_INFO_CTX}'`, { + input: html + '
', + }); +} + +main() + .then(() => { + console.log('Commit-related information added.'); + }) + .catch((error) => { + console.error(error); + process.exit(1); + }) + .finally(() => { + // When running locally, we can see what calls were made to execSync to debug + if (!process.env.CI) { + // @ts-ignore + console.log(exec.calls); + } + }); diff --git a/.buildkite/scripts/serverless/create_deploy_tag/create_deploy_tag.sh b/.buildkite/scripts/serverless/create_deploy_tag/create_deploy_tag.sh new file mode 100755 index 000000000000..b0d7660054bc --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/create_deploy_tag.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +DEPLOY_TAG="deploy@$(date +%s)" +KIBANA_COMMIT_SHA=$(buildkite-agent meta-data get selected-commit-hash) + +if [[ -z "$KIBANA_COMMIT_SHA" ]]; then + echo "Commit sha is not set, exiting." + exit 1 +fi + +echo "--- Creating deploy tag $DEPLOY_TAG at $KIBANA_COMMIT_SHA" + +# Set git identity to whomever triggered the buildkite job +git config user.email "$BUILDKITE_BUILD_CREATOR_EMAIL" +git config user.name "$BUILDKITE_BUILD_CREATOR" + +# Create a tag for the deploy +git tag -a "$DEPLOY_TAG" "$KIBANA_COMMIT_SHA" \ + -m "Tagging release $KIBANA_COMMIT_SHA as: $DEPLOY_TAG, by $BUILDKITE_BUILD_CREATOR_EMAIL" + +# Set meta-data for the deploy tag +buildkite-agent meta-data set deploy-tag "$DEPLOY_TAG" + +# Push the tag to GitHub +if [[ -z "${DRY_RUN:-}" ]]; then + echo "Pushing tag to GitHub..." + git push origin --tags +else + echo "Skipping tag push to GitHub due to DRY_RUN=$DRY_RUN" +fi + +echo "Created deploy tag: $DEPLOY_TAG - your QA release should start @ https://buildkite.com/elastic/kibana-serverless-release/builds?branch=$DEPLOY_TAG" diff --git a/.buildkite/scripts/serverless/create_deploy_tag/info_sections/build_info.ts b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/build_info.ts new file mode 100644 index 000000000000..733045870354 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/build_info.ts @@ -0,0 +1,194 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { components } from '@octokit/openapi-types'; +import { buildkite, buildkiteBuildStateToEmoji, CommitWithStatuses, octokit } from '../shared'; +import { Build } from '#pipeline-utils/buildkite'; + +const QA_FTR_TEST_SLUG = 'appex-qa-serverless-kibana-ftr-tests'; +const KIBANA_ARTIFACT_BUILD_SLUG = 'kibana-artifacts-container-image'; +const KIBANA_PR_BUILD_SLUG = 'kibana-on-merge'; + +export interface BuildkiteBuildExtract { + success: boolean; + stateEmoji: string; + url: string; + buildNumber: number; + slug: string; + commit: string; + startedAt: string; + finishedAt: string; + kibanaCommit: string; +} + +export async function getOnMergePRBuild(commitSha: string): Promise { + const buildkiteBuild = await buildkite.getBuildForCommit(KIBANA_PR_BUILD_SLUG, commitSha); + + if (!buildkiteBuild) { + return null; + } + + const stateEmoji = buildkiteBuildStateToEmoji(buildkiteBuild.state); + + return { + success: buildkiteBuild.state === 'passed', + stateEmoji, + slug: KIBANA_PR_BUILD_SLUG, + url: buildkiteBuild.web_url, + buildNumber: buildkiteBuild.number, + commit: commitSha, + kibanaCommit: buildkiteBuild.commit, + startedAt: buildkiteBuild.started_at, + finishedAt: buildkiteBuild.finished_at, + }; +} + +export async function getArtifactBuild(commitSha: string): Promise { + const build = await buildkite.getBuildForCommit(KIBANA_ARTIFACT_BUILD_SLUG, commitSha); + + if (!build) { + return null; + } + + return { + success: build.state === 'passed', + stateEmoji: buildkiteBuildStateToEmoji(build.state), + url: build.web_url, + slug: KIBANA_ARTIFACT_BUILD_SLUG, + buildNumber: build.number, + commit: build.commit, + kibanaCommit: build.commit, + startedAt: build.started_at, + finishedAt: build.finished_at, + }; +} + +export async function getQAFBuildContainingCommit( + commitSha: string, + date: string +): Promise { + // List of commits + const commitShaList = await getCommitListCached(); + + // List of QAF builds + const qafBuilds = await buildkite.getBuildsAfterDate(QA_FTR_TEST_SLUG, date, 30); + + // Find the first build that contains this commit + const build = qafBuilds.find((kbBuild) => { + // Check if build.commit is after commitSha? + const kibanaCommitSha = tryGetKibanaBuildHashFromQAFBuild(kbBuild); + const buildkiteBuildShaIndex = commitShaList.findIndex((c) => c.sha === kibanaCommitSha); + const commitShaIndex = commitShaList.findIndex((c) => c.sha === commitSha); + + return ( + commitShaIndex !== -1 && + buildkiteBuildShaIndex !== -1 && + buildkiteBuildShaIndex < commitShaIndex + ); + }); + + if (!build) { + return null; + } + + return { + success: build.state === 'passed', + stateEmoji: buildkiteBuildStateToEmoji(build.state), + url: build.web_url, + slug: QA_FTR_TEST_SLUG, + buildNumber: build.number, + commit: build.commit, + kibanaCommit: tryGetKibanaBuildHashFromQAFBuild(build), + startedAt: build.started_at, + finishedAt: build.finished_at, + }; +} +function tryGetKibanaBuildHashFromQAFBuild(build: Build) { + try { + const metaDataKeys = Object.keys(build.meta_data || {}); + const anyKibanaProjectKey = + metaDataKeys.find((key) => key.startsWith('project::bk-serverless')) || 'missing'; + const kibanaBuildInfo = JSON.parse(build.meta_data[anyKibanaProjectKey]); + return kibanaBuildInfo?.kibana_build_hash; + } catch (e) { + console.error(e); + return null; + } +} + +let _commitListCache: Array | null = null; +async function getCommitListCached() { + if (!_commitListCache) { + const resp = await octokit.request<'GET /repos/{owner}/{repo}/commits'>( + 'GET /repos/{owner}/{repo}/commits', + { + owner: 'elastic', + repo: 'kibana', + headers: { + accept: 'application/vnd.github.v3+json', + 'X-GitHub-Api-Version': '2022-11-28', + }, + } + ); + _commitListCache = resp.data; + } + return _commitListCache; +} + +function makeBuildInfoSnippetHtml(name: string, build: BuildkiteBuildExtract | null) { + if (!build) { + return `[❓] ${name} - no build found`; + } else { + const statedAt = build.startedAt + ? `started at ${new Date(build.startedAt).toUTCString()}` + : 'not started yet'; + const finishedAt = build.finishedAt + ? `finished at ${new Date(build.finishedAt).toUTCString()}` + : 'not finished yet'; + return `[${build.stateEmoji}] ${name} #${build.buildNumber} - ${statedAt}, ${finishedAt}`; + } +} + +export function makeBuildkiteBuildInfoHtml( + heading: string, + builds: Record +): string { + let html = `

${heading}

`; + for (const [name, build] of Object.entries(builds)) { + html += `
| ${makeBuildInfoSnippetHtml(name, build)}
\n`; + } + html += '
'; + + return html; +} + +export function makeCommitInfoWithBuildResultsHtml(commits: CommitWithStatuses[]) { + const commitWithBuildResultsHtml = commits.map((commitInfo) => { + const checks = commitInfo.checks; + const prBuildSnippet = makeBuildInfoSnippetHtml('on merge job', checks.onMergeBuild); + const ftrBuildSnippet = makeBuildInfoSnippetHtml('qaf/ftr tests', checks.ftrBuild); + const artifactBuildSnippet = makeBuildInfoSnippetHtml('artifact build', checks.artifactBuild); + const titleWithLink = commitInfo.title.replace( + /#(\d{4,6})/, + `$&` + ); + + return `
+
+ +
${titleWithLink} by ${commitInfo.author} on ${commitInfo.date}
+
| ${prBuildSnippet}
+
| ${artifactBuildSnippet}
+
| ${ftrBuildSnippet}
+
+
+
`; + }); + + return commitWithBuildResultsHtml.join('\n'); +} diff --git a/.buildkite/scripts/serverless/create_deploy_tag/info_sections/commit_info.ts b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/commit_info.ts new file mode 100644 index 000000000000..31af2ec7f191 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/commit_info.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { RestEndpointMethodTypes } from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'; +import { buildkite, octokit, SELECTED_COMMIT_META_KEY, CURRENT_COMMIT_META_KEY } from '../shared'; + +export type GithubCommitType = RestEndpointMethodTypes['repos']['getCommit']['response']['data']; +export type ListedGithubCommitType = + RestEndpointMethodTypes['repos']['listCommits']['response']['data'][0]; + +const KIBANA_PR_BASE = 'https://github.com/elastic/kibana/pull'; + +export interface GitCommitExtract { + sha: string; + title: string; + message: string; + link: string; + date: string | undefined; + author: string | undefined; + prLink: string | undefined; +} + +export async function getCurrentQARelease() { + const releasesFile = await octokit.request(`GET /repos/{owner}/{repo}/contents/{path}`, { + owner: 'elastic', + repo: 'serverless-gitops', + path: 'services/kibana/versions.yaml', + }); + + // @ts-ignore + const fileContent = Buffer.from(releasesFile.data.content, 'base64').toString('utf8'); + + const sha = fileContent.match(`qa: "([a-z0-9]+)"`)?.[1]; + + if (!sha) { + throw new Error('Could not find QA hash in current releases file'); + } else { + buildkite.setMetadata(CURRENT_COMMIT_META_KEY, sha); + return sha; + } +} + +export function getSelectedCommitHash() { + const commitHash = buildkite.getMetadata(SELECTED_COMMIT_META_KEY); + if (!commitHash) { + throw new Error( + `Could not find selected commit (by '${SELECTED_COMMIT_META_KEY}' in buildkite meta-data)` + ); + } + return commitHash; +} + +export async function getCommitByHash(hash: string): Promise { + const commit = await octokit.repos.getCommit({ + owner: 'elastic', + repo: 'kibana', + ref: hash, + }); + + return commit.data; +} + +export async function getRecentCommits(commitCount: number): Promise { + const kibanaCommits: ListedGithubCommitType[] = ( + await octokit.repos.listCommits({ + owner: 'elastic', + repo: 'kibana', + per_page: Number(commitCount), + }) + ).data; + + return kibanaCommits.map(toGitCommitExtract); +} + +export function toGitCommitExtract( + commit: GithubCommitType | ListedGithubCommitType +): GitCommitExtract { + const title = commit.commit.message.split('\n')[0]; + const prNumber = title.match(/#(\d{4,6})/)?.[1]; + const prLink = prNumber ? `${KIBANA_PR_BASE}/${prNumber}` : undefined; + + return { + sha: commit.sha, + message: commit.commit.message, + title, + link: commit.html_url, + date: commit.commit.author?.date || commit.commit.committer?.date, + author: commit.author?.login || commit.committer?.login, + prLink, + }; +} + +export function makeCommitInfoHtml(sectionTitle: string, commitInfo: GitCommitExtract): string { + const titleWithLink = commitInfo.title.replace( + /#(\d{4,6})/, + `$&` + ); + + const commitDateUTC = new Date(commitInfo.date!).toUTCString(); + + return `
+

${sectionTitle}

+
+${commitInfo.sha} + by ${commitInfo.author} + on ${commitDateUTC} +
+
:merged-pr: ${titleWithLink}
+
`; +} diff --git a/.buildkite/scripts/serverless/create_deploy_tag/info_sections/so_snapshot_comparison.ts b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/so_snapshot_comparison.ts new file mode 100644 index 000000000000..19917730cca0 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/so_snapshot_comparison.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import path from 'path'; +import { readFileSync } from 'fs'; +import { exec } from '../shared'; +import { BuildkiteClient, getKibanaDir } from '#pipeline-utils'; + +export function compareSOSnapshots( + previousSha: string, + selectedSha: string +): null | { + hasChanges: boolean; + changed: string[]; + command: string; +} { + assertValidSha(previousSha); + assertValidSha(selectedSha); + + const command = `node scripts/snapshot_plugin_types compare --from ${previousSha} --to ${selectedSha}`; + const outputPath = path.resolve(getKibanaDir(), 'so_comparison.json'); + + try { + exec(`${command} --outputPath ${outputPath}`, { stdio: 'inherit' }); + + const soComparisonResult = JSON.parse(readFileSync(outputPath).toString()); + + const buildkite = new BuildkiteClient({ exec }); + buildkite.uploadArtifacts(outputPath); + + return { + hasChanges: soComparisonResult.hasChanges, + changed: soComparisonResult.changed, + command, + }; + } catch (ex) { + console.error(ex); + return null; + } +} + +export function makeSOComparisonBlockHtml(comparisonResult: { + hasChanges: boolean; + changed: string[]; + command: string; +}): string { + if (comparisonResult.hasChanges) { + return `
+

Plugin Saved Object migration changes: *yes, ${comparisonResult.changed.length} plugin(s)*

+
Changed plugins: ${comparisonResult.changed.join(', ')}
+Find detailed info in the archived artifacts, or run the command yourself: +
${comparisonResult.command}
+
`; + } else { + return `
+

Plugin Saved Object migration changes: none

+No changes between targets, you can run the command yourself to verify: +
${comparisonResult.command}
+
`; + } +} + +export function makeSOComparisonErrorHtml(): string { + return `
+

Plugin Saved Object migration changes: N/A

+
Could not compare plugin migrations. Check the logs for more info.
+
`; +} + +function assertValidSha(sha: string) { + if (!sha.match(/^[a-f0-9]{8,40}$/)) { + throw new Error(`Invalid sha: ${sha}`); + } +} diff --git a/.buildkite/scripts/serverless/create_deploy_tag/info_sections/useful_links.ts b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/useful_links.ts new file mode 100644 index 000000000000..c5c042f9ce0a --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/info_sections/useful_links.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +function link(text: string, url: string) { + return `${text}`; +} + +function getLinkForGPCTLNonProd(commit: string) { + return `https://overview.qa.cld.elstc.co/app/dashboards#/view/serverless-tooling-gpctl-deployment-status?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&service-name=kibana&_a=(controlGroupInput:(chainingSystem:HIERARCHICAL,controlStyle:oneLine,ignoreParentSettings:(ignoreFilters:!f,ignoreQuery:!f,ignoreTimerange:!f,ignoreValidations:!f),panels:('18201b8e-3aae-4459-947d-21e007b6a3a5':(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:commit-hash,id:'18201b8e-3aae-4459-947d-21e007b6a3a5',selectedOptions:!('${commit}'),title:commit-hash),grow:!t,order:1,type:optionsListControl,width:medium),'41060e65-ce4c-414e-b8cf-492ccb19245f':(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:service-name,id:'41060e65-ce4c-414e-b8cf-492ccb19245f',selectedOptions:!(kibana),title:service-name),grow:!t,order:0,type:optionsListControl,width:medium),ed96828e-efe9-43ad-be3f-0e04218f79af:(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:to-env,id:ed96828e-efe9-43ad-be3f-0e04218f79af,selectedOptions:!(qa),title:to-env),grow:!t,order:2,type:optionsListControl,width:medium))))`; +} + +function getLinkForGPCTLProd(commit: string) { + return `https://overview.elastic-cloud.com/app/dashboards#/view/serverless-tooling-gpctl-deployment-status?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&service-name=kibana&_a=(controlGroupInput:(chainingSystem:HIERARCHICAL,controlStyle:oneLine,ignoreParentSettings:(ignoreFilters:!f,ignoreQuery:!f,ignoreTimerange:!f,ignoreValidations:!f),panels:('18201b8e-3aae-4459-947d-21e007b6a3a5':(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:commit-hash,id:'18201b8e-3aae-4459-947d-21e007b6a3a5',selectedOptions:!('${commit}'),title:commit-hash),grow:!t,order:1,type:optionsListControl,width:medium),'41060e65-ce4c-414e-b8cf-492ccb19245f':(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:service-name,id:'41060e65-ce4c-414e-b8cf-492ccb19245f',selectedOptions:!(kibana),title:service-name),grow:!t,order:0,type:optionsListControl,width:medium),ed96828e-efe9-43ad-be3f-0e04218f79af:(explicitInput:(dataViewId:'serverless.logs-*',enhancements:(),fieldName:to-env,id:ed96828e-efe9-43ad-be3f-0e04218f79af,selectedOptions:!(production),title:to-env),grow:!t,order:2,type:optionsListControl,width:medium))))`; +} + +export function getUsefulLinks({ + selectedCommitHash, + previousCommitHash, +}: { + previousCommitHash: string; + selectedCommitHash: string; +}): Record { + return { + 'Commits contained in deploy': `https://github.com/elastic/kibana/compare/${previousCommitHash}...${selectedCommitHash}`, + 'Argo Workflow (use Elastic Cloud Staging VPN)': `https://argo-workflows.cd.internal.qa.elastic.cloud/workflows?label=hash%3D${selectedCommitHash}`, + 'GPCTL Deployment Status dashboard for nonprod': getLinkForGPCTLNonProd(selectedCommitHash), + 'GPCTL Deployment Status dashboard for prod': getLinkForGPCTLProd(selectedCommitHash), + 'Quality Gate pipeline': `https://buildkite.com/elastic/kibana-tests/builds?branch=main`, + 'Kibana Serverless Release pipeline': `https://buildkite.com/elastic/kibana-serverless-release/builds?commit=${selectedCommitHash}`, + }; +} + +export function makeUsefulLinksHtml( + heading: string, + data: { + previousCommitHash: string; + selectedCommitHash: string; + } +) { + return ( + `

${heading}

` + + Object.entries(getUsefulLinks(data)) + .map(([name, url]) => `
:link: ${link(name, url)}
`) + .join('\n') + ); +} diff --git a/.buildkite/scripts/serverless/create_deploy_tag/list_commit_candidates.ts b/.buildkite/scripts/serverless/create_deploy_tag/list_commit_candidates.ts new file mode 100755 index 000000000000..7b2017420009 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/list_commit_candidates.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { buildkite, COMMIT_INFO_CTX, CommitWithStatuses, SELECTED_COMMIT_META_KEY } from './shared'; +import { + getArtifactBuild, + getOnMergePRBuild, + getQAFBuildContainingCommit, + makeCommitInfoWithBuildResultsHtml, +} from './info_sections/build_info'; +import { getRecentCommits, GitCommitExtract } from './info_sections/commit_info'; +import { BuildkiteInputStep } from '#pipeline-utils'; + +async function main(commitCountArg: string) { + console.log('--- Listing commits'); + const commitCount = parseInt(commitCountArg, 10); + const commitData = await collectAvailableCommits(commitCount); + const commitsWithStatuses = await enrichWithStatuses(commitData); + + console.log('--- Updating buildkite context with listed commits'); + const commitListWithBuildResultsHtml = makeCommitInfoWithBuildResultsHtml(commitsWithStatuses); + buildkite.setAnnotation(COMMIT_INFO_CTX, 'info', commitListWithBuildResultsHtml); + + if (process.env.AUTO_SELECT_COMMIT?.match(/(1|true)/i)) { + console.log('--- Finding suitable candidate for auto-promotion'); + + const passingCommitCandidate = commitsWithStatuses.find((commit) => { + return ( + commit.checks.onMergeBuild?.success && + commit.checks.ftrBuild?.success && + commit.checks.artifactBuild?.success + ); + }); + + if (!passingCommitCandidate) { + throw new Error( + `Could not find a suitable candidate for auto-promotion in the last ${commitCount} commits. Stopping.` + ); + } + + console.log('Selected candidate: ', passingCommitCandidate); + + console.log('--- Setting buildkite meta-data for auto-promotion'); + buildkite.setMetadata(SELECTED_COMMIT_META_KEY, passingCommitCandidate.sha); + } else { + console.log('--- Generating buildkite input step'); + addBuildkiteInputStep(); + } +} + +async function collectAvailableCommits(commitCount: number): Promise { + console.log('--- Collecting recent kibana commits'); + + const recentCommits = await getRecentCommits(commitCount); + + if (!recentCommits) { + throw new Error('Could not find any, while listing recent commits'); + } + + return recentCommits; +} + +async function enrichWithStatuses(commits: GitCommitExtract[]): Promise { + console.log('--- Enriching with build statuses'); + + const commitsWithStatuses: CommitWithStatuses[] = await Promise.all( + commits.map(async (commit) => { + const onMergeBuild = await getOnMergePRBuild(commit.sha); + + if (!commit.date) { + return { + ...commit, + checks: { + onMergeBuild, + ftrBuild: null, + artifactBuild: null, + }, + }; + } + + const nextFTRBuild = await getQAFBuildContainingCommit(commit.sha, commit.date); + const artifactBuild = await getArtifactBuild(commit.sha); + + return { + ...commit, + checks: { + onMergeBuild, + ftrBuild: nextFTRBuild, + artifactBuild, + }, + }; + }) + ); + + return commitsWithStatuses; +} + +function addBuildkiteInputStep() { + const inputStep: BuildkiteInputStep = { + input: 'Select commit to deploy', + prompt: 'Select commit to deploy.', + key: 'select-commit', + fields: [ + { + text: 'Enter the selected commit SHA', + key: SELECTED_COMMIT_META_KEY, + }, + ], + }; + + buildkite.uploadSteps([inputStep]); +} + +main(process.argv[2]) + .then(() => { + console.log('Commit selector generated, added as a buildkite input step.'); + }) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/.buildkite/scripts/serverless/create_deploy_tag/mock_exec.ts b/.buildkite/scripts/serverless/create_deploy_tag/mock_exec.ts new file mode 100644 index 000000000000..c3d4bbba61cd --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/mock_exec.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * This file has a wrapper for exec, that stores answers for queries from a file, to be able to use it in tests. + */ + +import { execSync, ExecSyncOptions } from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import { getKibanaDir } from '#pipeline-utils'; + +const PREPARED_RESPONSES_PATH = + '.buildkite/scripts/serverless/create_deploy_tag/prepared_responses.json'; + +/** + * This module allows for a stand-in for execSync that stores calls, and responds from a file of recorded responses. + * Most of the components in this module are lazy, so that they are only initialized if needed. + * @param fake - if set to true, it will use the fake, prepared exec, if false, it will use child_process.execSync + * @param id - an optional ID, used to distinguish between different instances of exec. + */ +const getExec = (fake = false, id: string = randomId()) => { + return fake ? makeMockExec(id) : exec; +}; + +/** + * Lazy getter for a storage for calls to the mock exec. + */ +const getCallStorage: () => Record> = (() => { + let callStorage: Record> | null = null; + + return () => { + if (!callStorage) { + callStorage = new Proxy>>( + {}, + { + get: (target, prop: string) => { + if (!target[prop]) { + target[prop] = []; + } + return target[prop]; + }, + } + ); + } + return callStorage; + }; +})(); + +/** + * Lazy getter for the responses file. + */ +const loadFakeResponses = (() => { + let responses: any; + return () => { + if (!responses) { + const responsesFile = path.resolve(getKibanaDir(), PREPARED_RESPONSES_PATH); + if (fs.existsSync(responsesFile)) { + const responsesContent = fs.readFileSync(responsesFile).toString(); + responses = JSON.parse(responsesContent); + } else { + fs.writeFileSync(responsesFile, '{}'); + console.log(responsesFile, 'created'); + responses = {}; + } + } + + return responses; + }; +})(); + +const makeMockExec = (id: string) => { + console.warn("--- Using mock exec, don't use this on CI. ---"); + const callStorage = getCallStorage(); + const calls = callStorage[id]; + + const mockExecInstance = (command: string, opts: ExecSyncOptions = {}): string | null => { + const responses = loadFakeResponses(); + calls.push({ command, opts }); + + if (typeof responses[command] !== 'undefined') { + return responses[command]; + } else { + console.warn(`No response for command: ${command}`); + responses[command] = ''; + fs.writeFileSync( + path.resolve(getKibanaDir(), PREPARED_RESPONSES_PATH), + JSON.stringify(responses, null, 2) + ); + return exec(command, opts); + } + }; + + mockExecInstance.id = id; + mockExecInstance.calls = calls; + + return mockExecInstance; +}; + +const exec = (command: string, opts: any = {}) => { + const result = execSync(command, { encoding: 'utf-8', cwd: getKibanaDir(), ...opts }); + if (result) { + return result.toString().trim(); + } else { + return null; + } +}; + +const randomId = () => (Math.random() * 10e15).toString(36); + +export { getExec, getCallStorage }; diff --git a/.buildkite/scripts/serverless/create_deploy_tag/prepared_responses.json b/.buildkite/scripts/serverless/create_deploy_tag/prepared_responses.json new file mode 100644 index 000000000000..046244851bff --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/prepared_responses.json @@ -0,0 +1,13 @@ +{ + "buildkite-agent annotate --append --style 'info' --context 'commit-info'": "ok", + "buildkite-agent meta-data get \"commit-sha\"": "906987c2860b53b91d449bc164957857adddc06a", + "node scripts/snapshot_plugin_types compare --from b5aa37525578 --to 906987c2860b53b91d449bc164957857adddc06a --outputPath 'so_comparison.json'": "ok", + "buildkite-agent artifact upload 'so_comparison.json'": "ok", + "buildkite-agent meta-data get 'release_state'": "", + "buildkite-agent meta-data get 'state_data'": "", + "buildkite-agent meta-data set 'release_state'": "ok", + "buildkite-agent meta-data set 'state_data'": "ok", + "buildkite-agent annotate --context 'wizard-main' --style 'info'": "ok", + "buildkite-agent annotate --context 'wizard-instruction' --style 'info'": "ok", + "buildkite-agent annotate --context 'wizard-instruction' --style 'warning'": "ok" +} diff --git a/.buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts b/.buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts new file mode 100644 index 000000000000..8a8a287ab7e5 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/release_wizard_messaging.ts @@ -0,0 +1,385 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + buildkite, + COMMIT_INFO_CTX, + CURRENT_COMMIT_META_KEY, + DEPLOY_TAG_META_KEY, + DRY_RUN_CTX, + octokit, + SELECTED_COMMIT_META_KEY, + sendSlackMessage, +} from './shared'; +import { GithubCommitType } from './info_sections/commit_info'; +import { getUsefulLinks } from './info_sections/useful_links'; + +const WIZARD_CTX_INSTRUCTION = 'wizard-instruction'; +const WIZARD_CTX_DEFAULT = 'wizard-main'; + +const IS_DRY_RUN = process.env.DRY_RUN?.match(/(1|true)/i); +const IS_AUTOMATED_RUN = process.env.AUTO_SELECT_COMMIT?.match(/(1|true)/i); + +type StateNames = + | 'start' + | 'initialize' + | 'collect_commits' + | 'wait_for_selection' + | 'collect_commit_info' + | 'wait_for_confirmation' + | 'create_deploy_tag' + | 'tag_created' + | 'end' + | 'error_generic' + | string; + +interface StateShape { + name: string; + description: string; + instruction?: string; + instructionStyle?: 'success' | 'warning' | 'error' | 'info'; + display: boolean; + skipWhenAutomated?: boolean; + pre?: (state: StateShape) => Promise; + post?: (state: StateShape) => Promise; +} + +const states: Record = { + start: { + name: 'Starting state', + description: 'No description', + display: false, + post: async () => { + if (IS_DRY_RUN) { + buildkite.setAnnotation( + DRY_RUN_CTX, + 'warning', + `Dry run: tag won't be pushed, slack won't be notified.` + ); + } + + buildkite.setAnnotation(COMMIT_INFO_CTX, 'info', `

:kibana: Recent commits...

`); + }, + }, + initialize: { + name: 'Initializing', + description: 'The job is starting up.', + instruction: 'Wait while we bootstrap. Follow the instructions displayed in this block.', + instructionStyle: 'info', + display: true, + }, + collect_commits: { + name: 'Collecting commits', + description: 'Collecting potential commits for the release.', + instruction: `Please wait, while we're collecting the list of available commits.`, + instructionStyle: 'info', + display: true, + }, + wait_for_selection: { + name: 'Waiting for selection', + description: 'Waiting for the Release Manager to select a commit.', + instruction: `Please find, copy and enter a commit SHA to the buildkite input box to proceed.`, + instructionStyle: 'warning', + skipWhenAutomated: true, + display: true, + }, + collect_commit_info: { + name: 'Collecting commit info', + description: 'Collecting supplementary info about the selected commit.', + instruction: `Please wait, while we're collecting data about the commits.`, + instructionStyle: 'info', + display: true, + pre: async () => { + buildkite.setAnnotation(COMMIT_INFO_CTX, 'info', `

:kibana: Selected commit info:

`); + }, + }, + wait_for_confirmation: { + name: 'Waiting for confirmation', + description: 'Waiting for the Release Manager to confirm the release.', + instruction: `Please review the collected information above and unblock the release on Buildkite, if you're satisfied.`, + instructionStyle: 'warning', + skipWhenAutomated: true, + display: true, + }, + create_deploy_tag: { + name: 'Creating deploy tag', + description: 'Creating the deploy tag, this will be picked up by another pipeline.', + instruction: `Please wait, while we're creating the deploy@timestamp tag.`, + instructionStyle: 'info', + display: true, + }, + tag_created: { + name: 'Release tag created', + description: 'The initial step release is completed, follow up jobs will be triggered soon.', + instruction: `

Deploy tag successfully created!

`, + post: async () => { + // The deployTag here is only for communication, if it's missing, it's not a big deal, but it's an error + const deployTag = + buildkite.getMetadata(DEPLOY_TAG_META_KEY) || + (console.error(`${DEPLOY_TAG_META_KEY} not found in buildkite meta-data`), 'unknown'); + const selectedCommit = buildkite.getMetadata(SELECTED_COMMIT_META_KEY); + const currentCommitSha = buildkite.getMetadata(CURRENT_COMMIT_META_KEY); + + buildkite.setAnnotation( + WIZARD_CTX_INSTRUCTION, + 'success', + `

Deploy tag successfully created!


+Your deployment will appear here on buildkite.` + ); + + if (!selectedCommit) { + // If we get here with no selected commit set, it's either an unsynced change in keys, or some weird error. + throw new Error( + `Couldn't find selected commit in buildkite meta-data (with key '${SELECTED_COMMIT_META_KEY}').` + ); + } + + const targetCommitData = ( + await octokit.repos.getCommit({ + owner: 'elastic', + repo: 'kibana', + ref: selectedCommit, + }) + ).data; + + await sendReleaseSlackAnnouncement({ + targetCommitData, + currentCommitSha, + deployTag, + }); + }, + instructionStyle: 'success', + display: true, + }, + end: { + name: 'End of the release process', + description: 'The release process has ended.', + display: false, + }, + error_generic: { + name: 'Encountered an error', + description: 'An error occurred during the release process.', + instruction: `

Please check the build logs for more information.

`, + instructionStyle: 'error', + display: false, + }, +}; + +/** + * This module is a central interface for updating the messaging interface for the wizard. + * It's implemented as a state machine that updates the wizard state as we transition between states. + * Use: `node /release_wizard_messaging.ts --state [--data ]` + */ +export async function main(args: string[]) { + if (!args.includes('--state')) { + throw new Error('Missing --state argument'); + } + const targetState = args.slice(args.indexOf('--state') + 1)[0]; + + let data: any; + if (args.includes('--data')) { + data = args.slice(args.indexOf('--data') + 1)[0]; + } + + const resultingTargetState = await transition(targetState, data); + if (resultingTargetState === 'tag_created') { + return await transition('end'); + } else { + return resultingTargetState; + } +} + +export async function transition(targetStateName: StateNames, data?: any) { + // use the buildkite agent to find what state we are in: + const currentStateName = buildkite.getMetadata('release_state') || 'start'; + const stateData = JSON.parse(buildkite.getMetadata('state_data') || '{}'); + + if (!currentStateName) { + throw new Error('Could not find current state in buildkite meta-data'); + } + + // find the index of the current state in the core flow + const currentStateIndex = Object.keys(states).indexOf(currentStateName); + const targetStateIndex = Object.keys(states).indexOf(targetStateName); + + if (currentStateIndex === -1) { + throw new Error(`Could not find current state '${currentStateName}' in core flow`); + } + const currentState = states[currentStateName]; + + if (targetStateIndex === -1) { + throw new Error(`Could not find target state '${targetStateName}' in core flow`); + } + const targetState = states[targetStateName]; + + if (currentStateIndex + 1 !== targetStateIndex) { + await tryCall(currentState.post, stateData); + stateData[currentStateName] = 'nok'; + } else { + const result = await tryCall(currentState.post, stateData); + stateData[currentStateName] = result ? 'ok' : 'nok'; + } + stateData[targetStateName] = 'pending'; + + await tryCall(targetState.pre, stateData); + + buildkite.setMetadata('release_state', targetStateName); + buildkite.setMetadata('state_data', JSON.stringify(stateData)); + + updateWizardState(stateData); + updateWizardInstruction(targetStateName, stateData); + + return targetStateName; +} + +function updateWizardState(stateData: Record) { + const wizardHeader = IS_AUTOMATED_RUN + ? `

:kibana: Kibana Serverless automated promotion :robot_face:

` + : `

:kibana: Kibana Serverless deployment wizard :mage:

`; + + const wizardSteps = Object.keys(states) + .filter((stateName) => states[stateName].display) + .filter((stateName) => !(IS_AUTOMATED_RUN && states[stateName].skipWhenAutomated)) + .map((stateName) => { + const stateInfo = states[stateName]; + const stateStatus = stateData[stateName]; + const stateEmoji = { + ok: ':white_check_mark:', + nok: ':x:', + pending: ':hourglass_flowing_sand:', + missing: ':white_circle:', + }[stateStatus || 'missing']; + + if (stateStatus === 'pending') { + return `
[${stateEmoji}] ${stateInfo.name}
  - ${stateInfo.description}
`; + } else { + return `
[${stateEmoji}] ${stateInfo.name}
`; + } + }); + + const wizardHtml = `
+${wizardHeader} +${wizardSteps.join('\n')} +
`; + + buildkite.setAnnotation(WIZARD_CTX_DEFAULT, 'info', wizardHtml); +} + +function updateWizardInstruction(targetState: string, stateData: any) { + const { instructionStyle, instruction } = states[targetState]; + + if (IS_AUTOMATED_RUN) { + buildkite.setAnnotation( + WIZARD_CTX_INSTRUCTION, + 'info', + `It's an automated run, no action needed.` + ); + } else if (instruction) { + buildkite.setAnnotation( + WIZARD_CTX_INSTRUCTION, + instructionStyle || 'info', + `${instruction}` + ); + } +} + +async function tryCall(fn: any, ...args: any[]) { + if (typeof fn === 'function') { + try { + const result = await fn(...args); + return result !== false; + } catch (error) { + console.error(error); + return false; + } + } else { + return true; + } +} + +async function sendReleaseSlackAnnouncement({ + targetCommitData, + currentCommitSha, + deployTag, +}: { + targetCommitData: GithubCommitType; + currentCommitSha: string | undefined | null; + deployTag: string; +}) { + const textBlock = (...str: string[]) => ({ type: 'mrkdwn', text: str.join('\n') }); + const buildShortname = `kibana-serverless-release #${process.env.BUILDKITE_BUILD_NUMBER}`; + + const mergedAtDate = targetCommitData.commit?.committer?.date; + const mergedAtUtcString = mergedAtDate ? new Date(mergedAtDate).toUTCString() : 'unknown'; + const targetCommitSha = targetCommitData.sha; + const targetCommitShort = targetCommitSha.slice(0, 12); + const compareResponse = ( + await octokit.repos.compareCommits({ + owner: 'elastic', + repo: 'kibana', + base: currentCommitSha || 'main', + head: targetCommitSha, + }) + ).data; + const compareLink = currentCommitSha + ? `<${compareResponse.html_url}|${compareResponse.total_commits} new commits>` + : 'a new commit'; + + const mainMessage = [ + `:ship_it_parrot: Promotion of ${compareLink} to QA has been <${process.env.BUILDKITE_BUILD_URL}|initiated>!\n`, + `*Remember:* Promotion to Staging is currently a manual process and will proceed once the build is signed off in QA.\n`, + `cc: @kibana-serverless-promotion-notify`, + ]; + + const linksSection = { + 'Initiated by': process.env.BUILDKITE_BUILD_CREATOR || 'unknown', + 'Pre-release job': `<${process.env.BUILDKITE_BUILD_URL}|${buildShortname}>`, + 'Git tag': ``, + Commit: ``, + 'Merged at': mergedAtUtcString, + }; + + const usefulLinksSection = getUsefulLinks({ + previousCommitHash: currentCommitSha || 'main', + selectedCommitHash: targetCommitSha, + }); + + return sendSlackMessage({ + blocks: [ + { + type: 'section', + text: textBlock(...mainMessage), + }, + { + type: 'section', + fields: Object.entries(linksSection).map(([name, link]) => textBlock(`*${name}*:`, link)), + }, + { + type: 'section', + text: { + type: 'mrkdwn', + text: + '*Useful links:*\n\n' + + Object.entries(usefulLinksSection) + .map(([name, link]) => ` • <${link}|${name}>`) + .join('\n'), + }, + }, + ], + }); +} + +main(process.argv.slice(2)).then( + (targetState) => { + console.log('Transition completed to: ' + targetState); + }, + (error) => { + console.error(error); + process.exit(1); + } +); diff --git a/.buildkite/scripts/serverless/create_deploy_tag/shared.ts b/.buildkite/scripts/serverless/create_deploy_tag/shared.ts new file mode 100644 index 000000000000..abd4abb5f8f4 --- /dev/null +++ b/.buildkite/scripts/serverless/create_deploy_tag/shared.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import axios from 'axios'; + +import { getExec } from './mock_exec'; +import { GitCommitExtract } from './info_sections/commit_info'; +import { BuildkiteBuildExtract } from './info_sections/build_info'; +import { BuildkiteClient, getGithubClient } from '#pipeline-utils'; + +const SELECTED_COMMIT_META_KEY = 'selected-commit-hash'; +const CURRENT_COMMIT_META_KEY = 'current-commit-hash'; + +const DEPLOY_TAG_META_KEY = 'deploy-tag'; +const COMMIT_INFO_CTX = 'commit-info'; +const DRY_RUN_CTX = 'dry-run'; + +const octokit = getGithubClient(); + +const exec = getExec(!process.env.CI); + +const buildkite = new BuildkiteClient({ exec }); + +const buildkiteBuildStateToEmoji = (state: string) => { + return ( + { + running: '⏳', + scheduled: '⏳', + passed: '✅', + failed: '❌', + blocked: '❌', + canceled: '❌', + canceling: '❌', + skipped: '❌', + not_run: '❌', + finished: '✅', + }[state] || '❓' + ); +}; + +export { + octokit, + exec, + buildkite, + buildkiteBuildStateToEmoji, + SELECTED_COMMIT_META_KEY, + COMMIT_INFO_CTX, + DEPLOY_TAG_META_KEY, + CURRENT_COMMIT_META_KEY, + DRY_RUN_CTX, +}; + +export interface CommitWithStatuses extends GitCommitExtract { + title: string; + author: string | undefined; + checks: { + onMergeBuild: BuildkiteBuildExtract | null; + ftrBuild: BuildkiteBuildExtract | null; + artifactBuild: BuildkiteBuildExtract | null; + }; +} + +export function sendSlackMessage(payload: any) { + if (process.env.DRY_RUN?.match(/(1|true)/i)) { + const message = + typeof payload === 'string' + ? payload + : JSON.stringify( + payload, + // The slack playground doesn't like long strings + (_key, value) => (value?.length > 301 ? value.slice(0, 300) : value), + 0 + ); + const slackPlaygroundLink = `https://app.slack.com/block-kit-builder/#${encodeURIComponent( + message + )}`; + + buildkite.setAnnotation( + DRY_RUN_CTX, + 'warning', + `Preview slack message here.` + ); + console.log('DRY_RUN, not sending slack message:', slackPlaygroundLink); + + return Promise.resolve(); + } else if (!process.env.DEPLOY_TAGGER_SLACK_WEBHOOK_URL) { + console.log('No SLACK_WEBHOOK_URL set, not sending slack message'); + return Promise.resolve(); + } else { + return axios + .post( + process.env.DEPLOY_TAGGER_SLACK_WEBHOOK_URL, + typeof payload === 'string' ? payload : JSON.stringify(payload) + ) + .catch((error) => { + if (axios.isAxiosError(error) && error.response) { + console.error( + "Couldn't send slack message.", + error.response.status, + error.response.statusText, + error.message + ); + } else { + console.error("Couldn't send slack message.", error.message); + } + }); + } +} diff --git a/.buildkite/scripts/steps/artifacts/docker_context.sh b/.buildkite/scripts/steps/artifacts/docker_context.sh index b6fe4834465f..de90621ada2d 100755 --- a/.buildkite/scripts/steps/artifacts/docker_context.sh +++ b/.buildkite/scripts/steps/artifacts/docker_context.sh @@ -26,8 +26,9 @@ case $KIBANA_DOCKER_CONTEXT in ubi8) DOCKER_CONTEXT_FILE="kibana-ubi8-$FULL_VERSION-docker-build-context.tar.gz" ;; - ubi9) - DOCKER_CONTEXT_FILE="kibana-ubi9-$FULL_VERSION-docker-build-context.tar.gz" + ubi) + # Currently ubi9. After ubi8 we're moving to a version agnostic filename + DOCKER_CONTEXT_FILE="kibana-ubi-$FULL_VERSION-docker-build-context.tar.gz" ;; ironbank) DOCKER_CONTEXT_FILE="kibana-ironbank-$FULL_VERSION-docker-build-context.tar.gz" diff --git a/.buildkite/scripts/steps/cloud/purge_deployments.ts b/.buildkite/scripts/steps/cloud/purge_deployments.ts index a166f09b73d6..845e6740cd48 100644 --- a/.buildkite/scripts/steps/cloud/purge_deployments.ts +++ b/.buildkite/scripts/steps/cloud/purge_deployments.ts @@ -23,12 +23,11 @@ const DAY_IN_SECONDS = 60 * 60 * 24; for (const deployment of prDeployments) { try { const prNumber = deployment.name.match(/^kibana-pr-([0-9]+)$/)[1]; - const prJson = execSync(`gh pr view '${prNumber}' --json state,labels,commits`).toString(); + const prJson = execSync(`gh pr view '${prNumber}' --json state,labels,updatedAt`).toString(); const pullRequest = JSON.parse(prJson); const prOpen = pullRequest.state === 'OPEN'; - const lastCommit = pullRequest.commits.slice(-1)[0]; - const lastCommitTimestamp = new Date(lastCommit.committedDate).getTime() / 1000; + const lastCommitTimestamp = new Date(pullRequest.updatedAt).getTime() / 1000; const persistDeployment = Boolean( pullRequest.labels.filter((label: any) => label.name === 'ci:cloud-persist-deployment').length diff --git a/.buildkite/scripts/steps/cloud/purge_projects.ts b/.buildkite/scripts/steps/cloud/purge_projects.ts index f89aa65fa855..c3c427c6a388 100644 --- a/.buildkite/scripts/steps/cloud/purge_projects.ts +++ b/.buildkite/scripts/steps/cloud/purge_projects.ts @@ -66,12 +66,11 @@ async function purgeProjects() { const NOW = new Date().getTime() / 1000; const DAY_IN_SECONDS = 60 * 60 * 24; const prJson = execSync( - `gh pr view '${project.prNumber}' --json state,labels,commits` + `gh pr view '${project.prNumber}' --json state,labels,updatedAt` ).toString(); const pullRequest = JSON.parse(prJson); const prOpen = pullRequest.state === 'OPEN'; - const lastCommit = pullRequest.commits.slice(-1)[0]; - const lastCommitTimestamp = new Date(lastCommit.committedDate).getTime() / 1000; + const lastCommitTimestamp = new Date(pullRequest.updatedAt).getTime() / 1000; const persistDeployment = Boolean( pullRequest.labels.filter((label: any) => label.name === 'ci:project-persist-deployment') diff --git a/.buildkite/scripts/steps/functional/security_serverless_rule_management.sh b/.buildkite/scripts/steps/functional/security_serverless_rule_management.sh new file mode 100644 index 000000000000..5d360e0db4f2 --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_rule_management.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Rule Management Cypress Tests on Serverless" + +cd x-pack/test/security_solution_cypress + +set +e +yarn cypress:rule_management:run:serverless; status=$?; yarn junit:merge || :; exit $status diff --git a/.buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh b/.buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh new file mode 100644 index 000000000000..bc7dc3269d8c --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_rule_management_prebuilt_rules.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Rule Management - Prebuilt Rules - Cypress Tests on Serverless" + +cd x-pack/test/security_solution_cypress + +set +e +yarn cypress:rule_management:prebuilt_rules:run:serverless; status=$?; yarn junit:merge || :; exit $status diff --git a/.buildkite/scripts/steps/functional/security_solution_rule_management.sh b/.buildkite/scripts/steps/functional/security_solution_rule_management.sh new file mode 100644 index 000000000000..847cb42896cf --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_solution_rule_management.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Rule Management - Security Solution Cypress Tests" + +cd x-pack/test/security_solution_cypress + +set +e +yarn cypress:rule_management:run:ess; status=$?; yarn junit:merge || :; exit $status diff --git a/.buildkite/scripts/steps/functional/security_solution_rule_management_prebuilt_rules.sh b/.buildkite/scripts/steps/functional/security_solution_rule_management_prebuilt_rules.sh new file mode 100644 index 000000000000..d8b19ad3363b --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_solution_rule_management_prebuilt_rules.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Rule Management - Prebuilt Rules - Security Solution Cypress Tests" + +cd x-pack/test/security_solution_cypress + +set +e +yarn cypress:rule_management:prebuilt_rules:run:ess; status=$?; yarn junit:merge || :; exit $status diff --git a/.buildkite/scripts/steps/serverless/build_and_deploy.sh b/.buildkite/scripts/steps/serverless/build_and_deploy.sh index 6c5b72a0b492..dba1103e3a91 100644 --- a/.buildkite/scripts/steps/serverless/build_and_deploy.sh +++ b/.buildkite/scripts/steps/serverless/build_and_deploy.sh @@ -105,3 +105,5 @@ EOF is_pr_with_label "ci:project-deploy-elasticsearch" && deploy "elasticsearch" is_pr_with_label "ci:project-deploy-observability" && deploy "observability" is_pr_with_label "ci:project-deploy-security" && deploy "security" + +exit 0; diff --git a/.buildkite/scripts/steps/storybooks/build_and_upload.ts b/.buildkite/scripts/steps/storybooks/build_and_upload.ts index 83f1ecb2a759..19fed0e78885 100644 --- a/.buildkite/scripts/steps/storybooks/build_and_upload.ts +++ b/.buildkite/scripts/steps/storybooks/build_and_upload.ts @@ -16,7 +16,6 @@ const STORYBOOKS = [ 'canvas', 'cases', 'cell_actions', - 'ci_composite', 'cloud_chat', 'coloring', 'chart_icons', @@ -93,14 +92,12 @@ const upload = () => { console.log('--- Generating Storybooks HTML'); process.chdir(path.join('.', 'built_assets', 'storybook')); - fs.renameSync('ci_composite', 'composite'); const storybooks = execSync(`ls -1d */`) .toString() .trim() .split('\n') - .map((filePath) => filePath.replace('/', '')) - .filter((filePath) => filePath !== 'composite'); + .map((filePath) => filePath.replace('/', '')); const listHtml = storybooks .map((storybook) => `
  • ${storybook}
  • `) @@ -110,8 +107,6 @@ const upload = () => {

    Storybooks

    -

    Composite Storybook

    -

    All

      ${listHtml}
    diff --git a/.ci/.storybook/main.js b/.ci/.storybook/main.js deleted file mode 100644 index c4e017179021..000000000000 --- a/.ci/.storybook/main.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -const config = require('@kbn/storybook').defaultConfig; -const aliases = require('../../src/dev/storybook/aliases').storybookAliases; - -config.refs = {}; - -// Required due to https://github.com/storybookjs/storybook/issues/13834 -config.babel = async (options) => ({ - ...options, - plugins: ['@babel/plugin-transform-typescript', ...options.plugins], -}); - -for (const alias of Object.keys(aliases).filter((a) => a !== 'ci_composite')) { - // snake_case -> Title Case - const title = alias - .replace(/_/g, ' ') - .split(' ') - .map((n) => n[0].toUpperCase() + n.slice(1)) - .join(' '); - - config.refs[alias] = { - title: title, - url: `${process.env.STORYBOOK_BASE_URL}/${alias}`, - }; -} - -module.exports = config; diff --git a/.eslintrc.js b/.eslintrc.js index 82193a7e2ecb..23706483a442 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -941,7 +941,7 @@ module.exports = { ], rules: { '@kbn/i18n/strings_should_be_translated_with_i18n': 'warn', - '@kbn/i18n/strings_should_be_translated_with_formatted_message': 'warn', + '@kbn/i18n/i18n_translate_should_start_with_the_right_id': 'warn', }, }, { @@ -1539,6 +1539,17 @@ module.exports = { }, }, + /** + * Serverless Search overrides + */ + { + // All files + files: ['x-pack/plugins/serverless_search/**/*.{ts,tsx}', 'packages/kbn-search-*'], + rules: { + '@kbn/telemetry/event_generating_elements_should_be_instrumented': 'error', + }, + }, + /** * Canvas overrides */ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 109bab65da3d..f84e5470f0dc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -54,6 +54,8 @@ x-pack/plugins/banners @elastic/appex-sharedux packages/kbn-bazel-runner @elastic/kibana-operations examples/bfetch_explorer @elastic/appex-sharedux src/plugins/bfetch @elastic/appex-sharedux +packages/kbn-calculate-auto @elastic/obs-ux-management-team +packages/kbn-calculate-width-from-char-count @elastic/kibana-visualizations x-pack/plugins/canvas @elastic/kibana-presentation x-pack/test/cases_api_integration/common/plugins/cases @elastic/response-ops packages/kbn-cases-components @elastic/response-ops @@ -301,6 +303,7 @@ x-pack/plugins/cross_cluster_replication @elastic/platform-deployment-management packages/kbn-crypto @elastic/kibana-security packages/kbn-crypto-browser @elastic/kibana-core x-pack/plugins/custom_branding @elastic/appex-sharedux +packages/kbn-custom-icons @elastic/obs-ux-logs-team packages/kbn-custom-integrations @elastic/obs-ux-logs-team src/plugins/custom_integrations @elastic/fleet packages/kbn-cypress-config @elastic/kibana-operations @@ -344,6 +347,7 @@ packages/kbn-ebt-tools @elastic/kibana-core packages/kbn-ecs @elastic/kibana-core @elastic/security-threat-hunting-investigations x-pack/packages/security-solution/ecs_data_quality_dashboard @elastic/security-threat-hunting-investigations x-pack/plugins/ecs_data_quality_dashboard @elastic/security-threat-hunting-investigations +packages/kbn-elastic-agent-utils @elastic/obs-ux-logs-team x-pack/packages/kbn-elastic-assistant @elastic/security-solution x-pack/plugins/elastic_assistant @elastic/security-solution test/plugin_functional/plugins/elasticsearch_client_plugin @elastic/kibana-core @@ -365,7 +369,7 @@ src/plugins/es_ui_shared @elastic/platform-deployment-management packages/kbn-eslint-config @elastic/kibana-operations packages/kbn-eslint-plugin-disable @elastic/kibana-operations packages/kbn-eslint-plugin-eslint @elastic/kibana-operations -packages/kbn-eslint-plugin-i18n @elastic/obs-knowledge-team +packages/kbn-eslint-plugin-i18n @elastic/obs-knowledge-team @elastic/kibana-operations packages/kbn-eslint-plugin-imports @elastic/kibana-operations packages/kbn-eslint-plugin-telemetry @elastic/obs-knowledge-team x-pack/test/encrypted_saved_objects_api_integration/plugins/api_consumer_plugin @elastic/kibana-security @@ -513,8 +517,10 @@ x-pack/packages/ml/agg_utils @elastic/ml-ui x-pack/packages/ml/anomaly_utils @elastic/ml-ui x-pack/packages/ml/category_validator @elastic/ml-ui x-pack/packages/ml/chi2test @elastic/ml-ui +x-pack/packages/ml/creation_wizard_utils @elastic/ml-ui x-pack/packages/ml/data_frame_analytics_utils @elastic/ml-ui x-pack/packages/ml/data_grid @elastic/ml-ui +x-pack/packages/ml/data_view_utils @elastic/ml-ui x-pack/packages/ml/date_picker @elastic/ml-ui x-pack/packages/ml/date_utils @elastic/ml-ui x-pack/packages/ml/error_utils @elastic/ml-ui @@ -533,7 +539,9 @@ x-pack/packages/ml/route_utils @elastic/ml-ui x-pack/packages/ml/runtime_field_utils @elastic/ml-ui x-pack/packages/ml/string_hash @elastic/ml-ui x-pack/packages/ml/trained_models_utils @elastic/ml-ui +x-pack/packages/ml/ui_actions @elastic/ml-ui x-pack/packages/ml/url_state @elastic/ml-ui +packages/kbn-mock-idp-plugin @elastic/kibana-security packages/kbn-monaco @elastic/appex-sharedux x-pack/plugins/monitoring_collection @elastic/obs-ux-infra_services-team x-pack/plugins/monitoring @elastic/obs-ux-infra_services-team @@ -547,12 +555,14 @@ x-pack/plugins/observability_ai_assistant @elastic/obs-knowledge-team x-pack/packages/observability/alert_details @elastic/obs-ux-management-team x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops +x-pack/packages/observability/get_padded_alert_time_range_util @elastic/obs-ux-management-team x-pack/plugins/observability_log_explorer @elastic/obs-ux-logs-team x-pack/plugins/observability_onboarding @elastic/obs-ux-logs-team x-pack/plugins/observability @elastic/obs-ux-management-team x-pack/plugins/observability_shared @elastic/observability-ui x-pack/test/security_api_integration/plugins/oidc_provider @elastic/kibana-security test/common/plugins/otel_metrics @elastic/obs-ux-infra_services-team +packages/kbn-openapi-bundler @elastic/security-detection-rule-management packages/kbn-openapi-generator @elastic/security-detection-rule-management packages/kbn-optimizer @elastic/kibana-operations packages/kbn-optimizer-webpack-helpers @elastic/kibana-operations @@ -560,6 +570,7 @@ packages/kbn-osquery-io-ts-types @elastic/security-asset-management x-pack/plugins/osquery @elastic/security-defend-workflows examples/partial_results_example @elastic/kibana-data-discovery x-pack/plugins/painless_lab @elastic/platform-deployment-management +packages/kbn-panel-loader @elastic/kibana-presentation packages/kbn-peggy @elastic/kibana-operations packages/kbn-peggy-loader @elastic/kibana-operations packages/kbn-performance-testing-dataset-extractor @elastic/kibana-performance-testing @@ -638,6 +649,9 @@ packages/kbn-search-response-warnings @elastic/kibana-data-discovery x-pack/plugins/searchprofiler @elastic/platform-deployment-management x-pack/test/security_api_integration/packages/helpers @elastic/kibana-security x-pack/plugins/security @elastic/kibana-security +x-pack/packages/security/plugin_types_common @elastic/kibana-security +x-pack/packages/security/plugin_types_public @elastic/kibana-security +x-pack/packages/security/plugin_types_server @elastic/kibana-security x-pack/plugins/security_solution_ess @elastic/security-solution x-pack/packages/security-solution/features @elastic/security-threat-hunting-explore x-pack/test/cases_api_integration/common/plugins/security_solution @elastic/response-ops @@ -748,7 +762,6 @@ test/server_integration/plugins/status_plugin_b @elastic/kibana-core packages/kbn-std @elastic/kibana-core packages/kbn-stdio-dev-helpers @elastic/kibana-operations packages/kbn-storybook @elastic/kibana-operations -packages/kbn-subscription-tracking @elastic/security-threat-hunting-investigations x-pack/plugins/synthetics @elastic/obs-ux-infra_services-team x-pack/test/alerting_api_integration/common/plugins/task_manager_fixture @elastic/response-ops x-pack/test/plugin_api_perf/plugins/task_manager_performance @elastic/response-ops @@ -864,7 +877,7 @@ packages/kbn-zod-helpers @elastic/security-detection-rule-management /test/functional/apps/management/ccs_compatibility/_data_views_ccs.ts @elastic/kibana-data-discovery /test/functional/apps/management/data_views @elastic/kibana-data-discovery /test/plugin_functional/test_suites/data_plugin @elastic/kibana-data-discovery -/x-pack/test/accessibility/apps/search_sessions.ts @elastic/kibana-data-discovery +/x-pack/test/accessibility/apps/group3/search_sessions.ts @elastic/kibana-data-discovery /x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js @elastic/kibana-data-discovery /x-pack/test/api_integration/apis/search @elastic/kibana-data-discovery /x-pack/test/examples/search_examples @elastic/kibana-data-discovery @@ -882,6 +895,9 @@ packages/kbn-zod-helpers @elastic/security-detection-rule-management /x-pack/test_serverless/api_integration/test_suites/common/scripts_tests @elastic/kibana-data-discovery /x-pack/test_serverless/api_integration/test_suites/common/search_oss @elastic/kibana-data-discovery /x-pack/test_serverless/api_integration/test_suites/common/search_xpack @elastic/kibana-data-discovery +/x-pack/test_serverless/functional/test_suites/common/context @elastic/kibana-data-discovery +/x-pack/test_serverless/functional/test_suites/common/discover @elastic/kibana-data-discovery +/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/discover_customization_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/field_formats @elastic/kibana-data-discovery @@ -889,6 +905,7 @@ packages/kbn-zod-helpers @elastic/security-detection-rule-management /x-pack/test_serverless/functional/test_suites/common/examples/search @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/search_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/unified_field_list_examples @elastic/kibana-data-discovery +/x-pack/test_serverless/functional/test_suites/common/management/data_views @elastic/kibana-data-discovery # Visualizations /src/plugins/visualize/ @elastic/kibana-visualizations @@ -1063,8 +1080,8 @@ x-pack/plugins/infra/server/lib/alerting @elastic/obs-ux-management-team #CC# /src/plugins/kibana_react/public/code_editor/ @elastic/kibana-presentation # Machine Learning -/x-pack/test/accessibility/apps/ml.ts @elastic/ml-ui -/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts @elastic/ml-ui +/x-pack/test/accessibility/apps/group2/ml.ts @elastic/ml-ui +/x-pack/test/accessibility/apps/group3/ml_embeddables_in_dashboard.ts @elastic/ml-ui /x-pack/test/api_integration/apis/ml/ @elastic/ml-ui /x-pack/test/api_integration_basic/apis/ml/ @elastic/ml-ui /x-pack/test/functional/apps/ml/ @elastic/ml-ui @@ -1078,7 +1095,7 @@ x-pack/plugins/infra/server/lib/alerting @elastic/obs-ux-management-team /x-pack/test/screenshot_creation/services/ml_screenshots.ts @elastic/ml-ui # Additional plugins and packages maintained by the ML team. -/x-pack/test/accessibility/apps/transform.ts @elastic/ml-ui +/x-pack/test/accessibility/apps/group2/transform.ts @elastic/ml-ui /x-pack/test/api_integration/apis/aiops/ @elastic/ml-ui /x-pack/test/api_integration/apis/transform/ @elastic/ml-ui /x-pack/test/api_integration_basic/apis/transform/ @elastic/ml-ui @@ -1165,10 +1182,10 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /test/interactive_setup_api_integration/ @elastic/kibana-security /test/interactive_setup_functional/ @elastic/kibana-security /test/plugin_functional/test_suites/core_plugins/rendering.ts @elastic/kibana-security -/x-pack/test/accessibility/apps/login_page.ts @elastic/kibana-security -/x-pack/test/accessibility/apps/roles.ts @elastic/kibana-security -/x-pack/test/accessibility/apps/spaces.ts @elastic/kibana-security -/x-pack/test/accessibility/apps/users.ts @elastic/kibana-security +/x-pack/test/accessibility/apps/group1/login_page.ts @elastic/kibana-security +/x-pack/test/accessibility/apps/group1/roles.ts @elastic/kibana-security +/x-pack/test/accessibility/apps/group1/spaces.ts @elastic/kibana-security +/x-pack/test/accessibility/apps/group1/users.ts @elastic/kibana-security /x-pack/test/api_integration/apis/security/ @elastic/kibana-security /x-pack/test/api_integration/apis/spaces/ @elastic/kibana-security /x-pack/test/ui_capabilities/ @elastic/kibana-security @@ -1211,7 +1228,6 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/test/functional/es_archives/endpoint/ @elastic/security-solution /x-pack/test/plugin_functional/test_suites/resolver/ @elastic/security-solution /x-pack/test/detection_engine_api_integration @elastic/security-solution -/x-pack/test/lists_api_integration @elastic/security-solution /x-pack/test/api_integration/apis/security_solution @elastic/security-solution #CC# /x-pack/plugins/security_solution/ @elastic/security-solution @@ -1251,7 +1267,6 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ ## Security Solution sub teams - Threat Hunting Explore /x-pack/plugins/security_solution/common/api/tags @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/common/api/risk_score @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/matrix_histogram @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/network @elastic/security-threat-hunting-explore @@ -1310,9 +1325,7 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring @elastic/security-detection-rule-management /x-pack/plugins/security_solution/common/detection_engine/rule_management @elastic/security-detection-rule-management -/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules @elastic/security-detection-rule-management /x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management @elastic/security-detection-rule-management -/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details @elastic/security-detection-rule-management /x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules @elastic/security-detection-rule-management /x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/rule_management @elastic/security-detection-rule-management /x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules @elastic/security-detection-rule-management @@ -1361,7 +1374,6 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/detection_engine/rule_exceptions @elastic/security-detection-engine /x-pack/plugins/security_solution/public/detections/containers/detection_engine/lists @elastic/security-detection-engine /x-pack/plugins/security_solution/public/detections/pages/alerts @elastic/security-detection-engine -/x-pack/plugins/security_solution/public/entity_analytics @elastic/security-detection-engine /x-pack/plugins/security_solution/public/exceptions @elastic/security-detection-engine /x-pack/plugins/security_solution/server/lib/detection_engine/migrations @elastic/security-detection-engine @@ -1379,14 +1391,16 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine /x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit @elastic/security-detection-engine /x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists @elastic/security-detection-engine -/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-detection-engine /x-pack/test/security_solution_cypress/cypress/e2e/exceptions @elastic/security-detection-engine /x-pack/test/security_solution_cypress/cypress/e2e/overview @elastic/security-detection-engine -x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions @elastic/security-detection-engine -x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation @elastic/security-detection-engine -x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions @elastic/security-detection-engine -x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine @elastic/security-detection-engine /x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users @elastic/security-detection-engine +/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists @elastic/security-detection-engine ## Security Threat Intelligence - Under Security Platform /x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine @@ -1409,7 +1423,7 @@ x-pack/test/security_solution_api_integration/test_suites/detections_response/de /x-pack/plugins/security_solution/server/routes @elastic/security-detections-response @elastic/security-threat-hunting /x-pack/plugins/security_solution/server/utils @elastic/security-detections-response @elastic/security-threat-hunting x-pack/test/security_solution_api_integration/test_suites/detections_response/utils @elastic/security-detections-response - +x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-detections-response ## Security Solution sub teams - security-defend-workflows /x-pack/plugins/security_solution/public/management/ @elastic/security-defend-workflows @@ -1432,6 +1446,7 @@ x-pack/test/security_solution_api_integration/test_suites/detections_response/ut ## Security Solution sub teams - security-telemetry (Data Engineering) x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics +x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-data-analytics ## Security Solution sub teams - security-engineering-productivity /x-pack/test/security_solution_cypress/* @elastic/security-engineering-productivity @@ -1458,6 +1473,10 @@ x-pack/plugins/security_solution/public/overview/components/entity_analytics x-pack/plugins/security_solution/server/lib/entity_analytics @elastic/security-entity-analytics x-pack/plugins/security_solution/server/lib/risk_score @elastic/security-entity-analytics x-pack/test/security_solution_api_integration/test_suites/entity_analytics @elastic/security-entity-analytics +x-pack/plugins/security_solution/public/flyout/entity_details @elastic/security-entity-analytics +x-pack/plugins/security_solution/common/api/entity_analytics @elastic/security-entity-analytics +/x-pack/plugins/security_solution/public/entity_analytics @elastic/security-entity-analytics +/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-entity-analytics # Security Defend Workflows - OSQuery Ownership /x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions @elastic/security-defend-workflows diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5974a1ee9a58..d07f60cf0925 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,6 +10,7 @@ Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios +- [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) diff --git a/.github/paths-labeller.yml b/.github/paths-labeller.yml index 1c1b2742001b..4f4057935265 100644 --- a/.github/paths-labeller.yml +++ b/.github/paths-labeller.yml @@ -21,3 +21,5 @@ - "x-pack/plugins/synthetics/**/*.*" - "x-pack/plugins/ux/**/*.*" - "x-pack/plugins/observability/public/components/shared/exploratory_view/**/*.*" + - "Team:obs-ux-management": + - "x-pack/plugins/observability/**/*.*" diff --git a/.github/workflows/create-deploy-tag.yml b/.github/workflows/create-deploy-tag.yml index 7ce79f2bd1c0..67fa6ca6216a 100644 --- a/.github/workflows/create-deploy-tag.yml +++ b/.github/workflows/create-deploy-tag.yml @@ -22,7 +22,7 @@ concurrency: jobs: create-deploy-tag: # Temporary, we need a way to limit this to a GitHub team instead of specific users - if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck","jbudz","mistic","delanni","Ikuni17","pheyos","dmlemeshko"]', github.triggering_actor) + if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck","jbudz","mistic","delanni","Ikuni17","pheyos","dmlemeshko","mikecote"]', github.triggering_actor) runs-on: ubuntu-latest permissions: contents: write diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 64143589d016..7f74652b8a44 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 99efdc253e53..cd120689d617 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index 4a976c737c79..6649c83b16df 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -573,6 +573,29 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "aiops", + "id": "def-public.AiopsAppDependencies.uiActions", + "type": "Object", + "tags": [], + "label": "uiActions", + "description": [ + "\nUI actions." + ], + "signature": [ + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.UiActionsStart", + "text": "UiActionsStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "aiops", "id": "def-public.AiopsAppDependencies.i18n", diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index abd069d6bcc7..4ed965017b6c 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 69 | 1 | 4 | 1 | +| 70 | 1 | 4 | 1 | ## Client diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 9505e1de3807..5d20f77f3e3a 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -1388,6 +1388,56 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "alerting", + "id": "def-server.sanitizeBulkErrorResponse", + "type": "Function", + "tags": [], + "label": "sanitizeBulkErrorResponse", + "description": [], + "signature": [ + "(response: ", + "BulkResponse", + " | ", + "TransportResult", + "<", + "BulkResponse", + ", unknown>) => ", + "BulkResponse", + " | ", + "TransportResult", + "<", + "BulkResponse", + ", unknown>" + ], + "path": "x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "alerting", + "id": "def-server.sanitizeBulkErrorResponse.$1", + "type": "CompoundType", + "tags": [], + "label": "response", + "description": [], + "signature": [ + "BulkResponse", + " | ", + "TransportResult", + "<", + "BulkResponse", + ", unknown>" + ], + "path": "x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [ @@ -3433,11 +3483,11 @@ }, { "plugin": "observability", - "path": "x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts" + "path": "x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts" }, { "plugin": "observability", - "path": "x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts" + "path": "x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts" }, { "plugin": "ml", @@ -5005,9 +5055,9 @@ }, "; getAuditLogger: () => ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.AuditLogger", "text": "AuditLogger" }, @@ -7406,12 +7456,15 @@ "parentPluginId": "alerting", "id": "def-common.MaintenanceWindowSOProperties", "type": "Interface", - "tags": [], + "tags": [ + "deprecated" + ], "label": "MaintenanceWindowSOProperties", "description": [], "path": "x-pack/plugins/alerting/common/maintenance_window.ts", - "deprecated": false, + "deprecated": true, "trackAdoption": false, + "references": [], "children": [ { "parentPluginId": "alerting", @@ -7521,6 +7574,21 @@ "path": "x-pack/plugins/alerting/common/maintenance_window.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-common.MaintenanceWindowSOProperties.scopedQuery", + "type": "CompoundType", + "tags": [], + "label": "scopedQuery", + "description": [], + "signature": [ + "ScopedQueryAttributes", + " | null | undefined" + ], + "path": "x-pack/plugins/alerting/common/maintenance_window.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -10187,7 +10255,9 @@ "parentPluginId": "alerting", "id": "def-common.MaintenanceWindow", "type": "Type", - "tags": [], + "tags": [ + "deprecated" + ], "label": "MaintenanceWindow", "description": [], "signature": [ @@ -10217,8 +10287,94 @@ "; eventStartTime: string | null; eventEndTime: string | null; id: string; }" ], "path": "x-pack/plugins/alerting/common/maintenance_window.ts", - "deprecated": false, + "deprecated": true, "trackAdoption": false, + "references": [ + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/tooltip_content.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/tooltip_content.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/types.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/types.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/index.mock.ts" + }, + { + "plugin": "triggersActionsUi", + "path": "x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/index.mock.ts" + } + ], "initialIsOpen": false }, { @@ -10237,7 +10393,9 @@ "section": "def-common.RRuleParams", "text": "RRuleParams" }, - "; categoryIds?: string[] | null | undefined; }" + "; categoryIds?: string[] | null | undefined; scopedQuery?: ", + "ScopedQueryAttributes", + " | null | undefined; }" ], "path": "x-pack/plugins/alerting/common/maintenance_window.ts", "deprecated": false, @@ -10263,7 +10421,9 @@ "parentPluginId": "alerting", "id": "def-common.MaintenanceWindowSOAttributes", "type": "Type", - "tags": [], + "tags": [ + "deprecated" + ], "label": "MaintenanceWindowSOAttributes", "description": [], "signature": [ @@ -10284,8 +10444,9 @@ } ], "path": "x-pack/plugins/alerting/common/maintenance_window.ts", - "deprecated": false, + "deprecated": true, "trackAdoption": false, + "references": [], "initialIsOpen": false }, { diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 2a7c56b3ec1e..70e7256fe556 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 810 | 1 | 779 | 50 | +| 813 | 1 | 782 | 51 | ## Client diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index 897cd39513a7..c0893d3b78d0 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -418,7 +418,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search 2023-10-31\" | \"POST /api/apm/services/{serviceName}/annotation 2023-10-31\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /api/apm/settings/agent-configuration 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/view 2023-10-31\" | \"DELETE /api/apm/settings/agent-configuration 2023-10-31\" | \"PUT /api/apm/settings/agent-configuration 2023-10-31\" | \"POST /api/apm/settings/agent-configuration/search 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/environments 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/agent_name 2023-10-31\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps 2023-10-31\" | \"POST /api/apm/sourcemaps 2023-10-31\" | \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema 2023-10-31\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys 2023-10-31\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/get_latest_agent_versions\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/most_used_charts\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\" | \"GET /internal/apm/mobile-services/{serviceName}/main_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/detailed_statistics\" | \"GET /internal/apm/diagnostics\" | \"POST /internal/apm/assistant/get_apm_timeseries\" | \"GET /internal/apm/assistant/get_service_summary\" | \"GET /internal/apm/assistant/get_error_document\" | \"POST /internal/apm/assistant/get_correlation_values\" | \"GET /internal/apm/assistant/get_downstream_dependencies\" | \"POST /internal/apm/assistant/get_services_list\" | \"GET /internal/apm/services/{serviceName}/profiling/flamegraph\" | \"GET /internal/apm/profiling/status\" | \"GET /internal/apm/services/{serviceName}/profiling/functions\" | \"POST /internal/apm/custom-dashboard\" | \"DELETE /internal/apm/custom-dashboard\" | \"GET /internal/apm/services/{serviceName}/dashboards\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/index_pattern\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search 2023-10-31\" | \"POST /api/apm/services/{serviceName}/annotation 2023-10-31\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /api/apm/settings/agent-configuration 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/view 2023-10-31\" | \"DELETE /api/apm/settings/agent-configuration 2023-10-31\" | \"PUT /api/apm/settings/agent-configuration 2023-10-31\" | \"POST /api/apm/settings/agent-configuration/search 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/environments 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/agent_name 2023-10-31\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps 2023-10-31\" | \"POST /api/apm/sourcemaps 2023-10-31\" | \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema 2023-10-31\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys 2023-10-31\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/get_latest_agent_versions\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/mobile-services/{serviceName}/error/http_error_rate\" | \"GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics\" | \"POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/error_terms\" | \"POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/crashes/distribution\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/most_used_charts\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\" | \"GET /internal/apm/mobile-services/{serviceName}/main_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/detailed_statistics\" | \"GET /internal/apm/diagnostics\" | \"POST /internal/apm/assistant/get_apm_timeseries\" | \"GET /internal/apm/assistant/get_service_summary\" | \"GET /internal/apm/assistant/get_error_document\" | \"POST /internal/apm/assistant/get_correlation_values\" | \"GET /internal/apm/assistant/get_downstream_dependencies\" | \"POST /internal/apm/assistant/get_services_list\" | \"GET /internal/apm/services/{serviceName}/profiling/flamegraph\" | \"GET /internal/apm/profiling/status\" | \"GET /internal/apm/services/{serviceName}/profiling/functions\" | \"POST /internal/apm/custom-dashboard\" | \"DELETE /internal/apm/custom-dashboard\" | \"GET /internal/apm/services/{serviceName}/dashboards\"" ], "path": "x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -597,7 +597,11 @@ "Type", "; endIndex: ", "Type", - "; }>]>; }> | undefined; handler: ({}: ", + "; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", "APMRouteHandlerResources", " & { params: { path: { serviceName: string; }; query: { start: number; end: number; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", "Branded", @@ -617,7 +621,7 @@ "ApmDocumentType", ".TransactionEvent; rollupInterval: ", "RollupInterval", - "; } & { startIndex: number; endIndex: number; }; }; }) => Promise<{ functions: ", + "; } & { startIndex: number; endIndex: number; } & { kuery: string; }; }; }) => Promise<{ functions: ", { "pluginId": "@kbn/profiling-utils", "scope": "common", @@ -699,7 +703,11 @@ "LiteralC", "<", "RollupInterval", - ".None>]>; }>]>; }> | undefined; handler: ({}: ", + ".None>]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", "APMRouteHandlerResources", " & { params: { path: { serviceName: string; }; query: { start: number; end: number; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", "Branded", @@ -719,7 +727,7 @@ "ApmDocumentType", ".TransactionEvent; rollupInterval: ", "RollupInterval", - "; }; }; }) => Promise<{ flamegraph: ", + "; } & { kuery: string; }; }; }) => Promise<{ flamegraph: ", { "pluginId": "@kbn/profiling-utils", "scope": "common", @@ -1661,6 +1669,446 @@ "MobileFiltersResponse", "; }>; } & ", "APMRouteCreateOptions", + "; \"GET /internal/apm/mobile-services/{serviceName}/crashes/distribution\": { endpoint: \"GET /internal/apm/mobile-services/{serviceName}/crashes/distribution\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "PartialC", + "<{ groupId: ", + "StringC", + "; }>, ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ offset: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { groupId?: string | undefined; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; } & { offset?: string | undefined; }; }; }) => Promise<", + "CrashDistributionResponse", + ">; } & ", + "APMRouteCreateOptions", + "; \"GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics\": { endpoint: \"GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "PartialC", + "<{ sortField: ", + "StringC", + "; sortDirection: ", + "UnionC", + "<[", + "LiteralC", + "<\"asc\">, ", + "LiteralC", + "<\"desc\">]>; }>, ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>]>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { sortField?: string | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; }; }; }) => Promise<{ errorGroups: ", + "MobileCrashGroupMainStatisticsResponse", + "; }>; } & ", + "APMRouteCreateOptions", + "; \"POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics\": { endpoint: \"POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ offset: ", + "StringC", + "; }>, ", + "TypeC", + "<{ numBuckets: ", + "Type", + "; }>]>; body: ", + "TypeC", + "<{ groupIds: ", + "Type", + "; }>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; } & { offset?: string | undefined; } & { numBuckets: number; }; body: { groupIds: string[]; }; }; }) => Promise<", + "MobileCrashesGroupPeriodsResponse", + ">; } & ", + "APMRouteCreateOptions", + "; \"GET /internal/apm/mobile-services/{serviceName}/error_terms\": { endpoint: \"GET /internal/apm/mobile-services/{serviceName}/error_terms\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ size: ", + "Type", + "; fieldName: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { kuery: string; } & { start: number; end: number; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { size: number; fieldName: string; }; }; }) => Promise<{ terms: ", + "MobileErrorTermsByFieldResponse", + "; }>; } & ", + "APMRouteCreateOptions", + "; \"POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics\": { endpoint: \"POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ offset: ", + "StringC", + "; }>, ", + "TypeC", + "<{ numBuckets: ", + "Type", + "; }>]>; body: ", + "TypeC", + "<{ groupIds: ", + "Type", + "; }>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; } & { offset?: string | undefined; } & { numBuckets: number; }; body: { groupIds: string[]; }; }; }) => Promise<", + "MobileErrorGroupPeriodsResponse", + ">; } & ", + "APMRouteCreateOptions", + "; \"GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics\": { endpoint: \"GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "PartialC", + "<{ sortField: ", + "StringC", + "; sortDirection: ", + "UnionC", + "<[", + "LiteralC", + "<\"asc\">, ", + "LiteralC", + "<\"desc\">]>; }>, ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>]>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { sortField?: string | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; }; }; }) => Promise<{ errorGroups: ", + "MobileErrorGroupMainStatisticsResponse", + "; }>; } & ", + "APMRouteCreateOptions", + "; \"GET /internal/apm/mobile-services/{serviceName}/error/http_error_rate\": { endpoint: \"GET /internal/apm/mobile-services/{serviceName}/error/http_error_rate\"; params?: ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ serviceName: ", + "StringC", + "; }>; query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"ENVIRONMENT_NOT_DEFINED\">, ", + "LiteralC", + "<\"ENVIRONMENT_ALL\">, ", + "BrandC", + "<", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">]>; }>, ", + "TypeC", + "<{ kuery: ", + "StringC", + "; }>, ", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "PartialC", + "<{ offset: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", + "APMRouteHandlerResources", + " & { params: { path: { serviceName: string; }; query: { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", + "Branded", + "; } & { kuery: string; } & { start: number; end: number; } & { offset?: string | undefined; }; }; }) => Promise<", + "MobileHttpErrorsTimeseries", + ">; } & ", + "APMRouteCreateOptions", "; \"GET /internal/apm/services/{serviceName}/agent_instances\": { endpoint: \"GET /internal/apm/services/{serviceName}/agent_instances\"; params?: ", "TypeC", "<{ path: ", @@ -5855,7 +6303,41 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">]>; }>]>; }> | undefined; handler: ({}: ", + ">]>; }>, ", + "TypeC", + "<{ documentType: ", + "UnionC", + "<[", + "LiteralC", + "<", + "ApmDocumentType", + ".ServiceTransactionMetric>, ", + "LiteralC", + "<", + "ApmDocumentType", + ".TransactionMetric>, ", + "LiteralC", + "<", + "ApmDocumentType", + ".TransactionEvent>]>; rollupInterval: ", + "UnionC", + "<[", + "LiteralC", + "<", + "RollupInterval", + ".OneMinute>, ", + "LiteralC", + "<", + "RollupInterval", + ".TenMinutes>, ", + "LiteralC", + "<", + "RollupInterval", + ".SixtyMinutes>, ", + "LiteralC", + "<", + "RollupInterval", + ".None>]>; }>]>; }> | undefined; handler: ({}: ", "APMRouteHandlerResources", " & { params: { path: { serviceName: string; serviceNodeName: string; }; query: { kuery: string; } & { start: number; end: number; } & { environment: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", "Branded", @@ -5867,7 +6349,15 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }; }; }) => Promise<", + ">; } & { documentType: ", + "ApmDocumentType", + ".TransactionMetric | ", + "ApmDocumentType", + ".ServiceTransactionMetric | ", + "ApmDocumentType", + ".TransactionEvent; rollupInterval: ", + "RollupInterval", + "; }; }; }) => Promise<", "ServiceNodeMetadataResponse", ">; } & ", "APMRouteCreateOptions", @@ -7373,9 +7863,9 @@ }, ">)[]; }>; } & ", "APMRouteCreateOptions", - "; \"GET /internal/apm/data_view/title\": { endpoint: \"GET /internal/apm/data_view/title\"; params?: undefined; handler: ({}: ", + "; \"GET /internal/apm/data_view/index_pattern\": { endpoint: \"GET /internal/apm/data_view/index_pattern\"; params?: undefined; handler: ({}: ", "APMRouteHandlerResources", - ") => Promise<{ apmDataViewTitle: string; }>; } & ", + ") => Promise<{ apmDataViewIndexPattern: string; }>; } & ", "APMRouteCreateOptions", "; \"POST /internal/apm/data_view/static\": { endpoint: \"POST /internal/apm/data_view/static\"; params?: undefined; handler: ({}: ", "APMRouteHandlerResources", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 3054b4228c6b..4fb46bf59a2f 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 29 | 0 | 29 | 120 | +| 29 | 0 | 29 | 127 | ## Client diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 1e3faec44ddb..c7fa34332d99 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 564cc08e57cf..6c00c6e2fcc9 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index d621ec7e6c16..d9a35019cdae 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index c6297e0f08f4..2d35da686154 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 14322f9c1f0e..f0cd1b6bfd22 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.devdocs.json b/api_docs/cases.devdocs.json index 900da326f6ec..773a3d4136d1 100644 --- a/api_docs/cases.devdocs.json +++ b/api_docs/cases.devdocs.json @@ -1314,6 +1314,97 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities", + "type": "Interface", + "tags": [], + "label": "CasesCapabilities", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.CREATE_CASES_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[CREATE_CASES_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.READ_CASES_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[READ_CASES_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.UPDATE_CASES_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[UPDATE_CASES_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.DELETE_CASES_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[DELETE_CASES_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.PUSH_CASES_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[PUSH_CASES_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.CASES_CONNECTORS_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[CASES_CONNECTORS_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesCapabilities.CASES_SETTINGS_CAPABILITY", + "type": "boolean", + "tags": [], + "label": "[CASES_SETTINGS_CAPABILITY]", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.CasesPermissions", @@ -1401,6 +1492,17 @@ "path": "x-pack/plugins/cases/common/ui/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesPermissions.settings", + "type": "boolean", + "tags": [], + "label": "settings", + "description": [], + "path": "x-pack/plugins/cases/common/ui/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1457,6 +1559,20 @@ "path": "x-pack/plugins/cases/common/utils/capabilities.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesUiCapabilities.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/capabilities.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2192,6 +2308,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.CASES_SETTINGS_CAPABILITY", + "type": "string", + "tags": [], + "label": "CASES_SETTINGS_CAPABILITY", + "description": [], + "signature": [ + "\"cases_settings\"" + ], + "path": "x-pack/plugins/cases/common/constants/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.CASES_URL", diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 81ea481070a8..0f8e4245318b 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 104 | 0 | 84 | 28 | +| 115 | 0 | 95 | 28 | ## Client diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 8f10078c47f8..fc041098837e 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 1deca15b7abc..e6f45610307d 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index e2da1f02675a..e1937292a034 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 07c00eb8fa70..326da93b8a56 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 180e2a6565f3..93f47c34a7e6 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 70873f3466d2..70abd89827df 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 81ea3c2c6302..96db7e83e468 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 20737866a276..dbb7d60d9b06 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index ecaa1207437a..defda8e95fc4 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 23c814c9c8c4..588123071168 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index bab1ba8b7e7e..b970429dd0f0 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 1388e49e66ab..83c77968119a 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 04a304f93dd8..3e25d1dccdc9 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -2690,7 +2690,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>>" ], "path": "src/plugins/data/public/plugin.ts", "deprecated": false, @@ -12839,7 +12839,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>>" ], "path": "src/plugins/data/server/plugin.ts", "deprecated": false, @@ -13241,7 +13241,7 @@ "\nReturns scripted fields" ], "signature": [ - "() => { storedFields: string[]; scriptFields: Record { scriptFields: Record; docvalueFields: { field: string; format: string; }[]; runtimeFields: ", "MappingRuntimeFields", @@ -19402,7 +19402,7 @@ "\nReturns scripted fields" ], "signature": [ - "() => { storedFields: string[]; scriptFields: Record { scriptFields: Record; docvalueFields: { field: string; format: string; }[]; runtimeFields: ", "MappingRuntimeFields", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 1028805d3b13..f76cf436c0dd 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index a85420c2c721..cde7f4c1bfd4 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index bf6f39e5a7ab..ce39cd72a3b3 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -267,7 +267,7 @@ "\nCurrent session management\n{@link ISessionService}" ], "signature": [ - "{ start: () => string; save: () => Promise; clear: () => void; destroy: () => void; readonly state$: ", + "{ start: () => string; clear: () => void; save: () => Promise; destroy: () => void; readonly state$: ", "Observable", "<", { @@ -723,7 +723,7 @@ "\nCurrent session management\n{@link ISessionService}" ], "signature": [ - "{ start: () => string; save: () => Promise; clear: () => void; destroy: () => void; readonly state$: ", + "{ start: () => string; clear: () => void; save: () => Promise; destroy: () => void; readonly state$: ", "Observable", "<", { @@ -1279,7 +1279,7 @@ "label": "ISessionService", "description": [], "signature": [ - "{ start: () => string; save: () => Promise; clear: () => void; destroy: () => void; readonly state$: ", + "{ start: () => string; clear: () => void; save: () => Promise; destroy: () => void; readonly state$: ", "Observable", "<", { @@ -1480,7 +1480,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; }>" + "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -1656,9 +1656,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1716,9 +1716,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1782,9 +1782,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1834,9 +1834,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1877,9 +1877,9 @@ "SearchSessionStatusDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1929,9 +1929,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -1980,9 +1980,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2040,9 +2040,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2106,9 +2106,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2158,9 +2158,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2216,9 +2216,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2268,9 +2268,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2311,9 +2311,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2347,9 +2347,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2390,9 +2390,9 @@ "SearchSessionDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2426,9 +2426,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2469,9 +2469,9 @@ "SearchSessionStatusDependencies", ", user: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -2513,9 +2513,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 63aedbc218d5..ca3edfdc0725 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 52bcd8c7aaa6..add92244c1b7 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 02ead0b2a86e..e97396c9d81e 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 0b1241085300..bd7fbea40a7a 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index 96792d381cdf..1f7e5f674a00 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -168,7 +168,7 @@ "\nReturns scripted fields" ], "signature": [ - "() => { storedFields: string[]; scriptFields: Record { scriptFields: Record; docvalueFields: { field: string; format: string; }[]; runtimeFields: ", "MappingRuntimeFields", @@ -6573,7 +6573,7 @@ "\nReturns scripted fields" ], "signature": [ - "() => { storedFields: string[]; scriptFields: Record { scriptFields: Record; docvalueFields: { field: string; format: string; }[]; runtimeFields: ", "MappingRuntimeFields", @@ -12015,7 +12015,7 @@ "\nReturns scripted fields" ], "signature": [ - "() => { storedFields: string[]; scriptFields: Record { scriptFields: Record; docvalueFields: { field: string; format: string; }[]; runtimeFields: ", "MappingRuntimeFields", diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 399cc8f171c1..5d290e6e9fce 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 276e39cc3731..17284e178a52 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.devdocs.json b/api_docs/dataset_quality.devdocs.json index d1a6ce1df8d6..86ad32dd897c 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -5,7 +5,20 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "datasetQuality", + "id": "def-public.datasetQualityAppTitle", + "type": "string", + "tags": [], + "label": "datasetQualityAppTitle", + "description": [], + "path": "x-pack/plugins/dataset_quality/common/translations.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [], "setup": { "parentPluginId": "datasetQuality", @@ -31,7 +44,22 @@ "path": "x-pack/plugins/dataset_quality/public/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "datasetQuality", + "id": "def-public.DatasetQualityPluginStart.DatasetQuality", + "type": "CompoundType", + "tags": [], + "label": "DatasetQuality", + "description": [], + "signature": [ + "React.ComponentClass<{}, any> | React.FunctionComponent<{}>" + ], + "path": "x-pack/plugins/dataset_quality/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], "lifecycle": "start", "initialIsOpen": true } @@ -63,7 +91,129 @@ } ], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "datasetQuality", + "id": "def-common.APIClientRequestParamsOf", + "type": "Type", + "tags": [], + "label": "APIClientRequestParamsOf", + "description": [], + "signature": [ + "{ \"GET /internal/dataset_quality/data_streams/stats\": { endpoint: \"GET /internal/dataset_quality/data_streams/stats\"; params?: ", + "TypeC", + "<{ query: ", + "IntersectionC", + "<[", + "PartialC", + "<{ type: ", + "UnionC", + "<[", + "LiteralC", + "<\"logs\">, ", + "LiteralC", + "<\"metrics\">, ", + "LiteralC", + "<\"traces\">, ", + "LiteralC", + "<\"synthetics\">, ", + "LiteralC", + "<\"profiling\">]>; }>, ", + "PartialC", + "<{ datasetQuery: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", + "DatasetQualityRouteHandlerResources", + " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"profiling\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<", + "DataStreamsStatResponse", + ">; } & ", + "DatasetQualityRouteCreateOptions", + "; }[TEndpoint] extends { endpoint: any; params?: infer TRouteParamsRT | undefined; handler: ({}: any) => Promise; } & ", + "ServerRouteCreateOptions", + " ? TRouteParamsRT extends ", + { + "pluginId": "@kbn/server-route-repository", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryPluginApi", + "section": "def-common.RouteParamsRT", + "text": "RouteParamsRT" + }, + " ? ClientRequestParamsOfType : {} : never" + ], + "path": "x-pack/plugins/dataset_quality/common/rest/create_call_dataset_quality_api.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "datasetQuality", + "id": "def-common.APIReturnType", + "type": "Type", + "tags": [], + "label": "APIReturnType", + "description": [], + "signature": [ + "{ \"GET /internal/dataset_quality/data_streams/stats\": { endpoint: \"GET /internal/dataset_quality/data_streams/stats\"; params?: ", + "TypeC", + "<{ query: ", + "IntersectionC", + "<[", + "PartialC", + "<{ type: ", + "UnionC", + "<[", + "LiteralC", + "<\"logs\">, ", + "LiteralC", + "<\"metrics\">, ", + "LiteralC", + "<\"traces\">, ", + "LiteralC", + "<\"synthetics\">, ", + "LiteralC", + "<\"profiling\">]>; }>, ", + "PartialC", + "<{ datasetQuery: ", + "StringC", + "; }>]>; }> | undefined; handler: ({}: ", + "DatasetQualityRouteHandlerResources", + " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"profiling\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<", + "DataStreamsStatResponse", + ">; } & ", + "DatasetQualityRouteCreateOptions", + "; }[TEndpoint] extends { endpoint: any; params?: any; handler: ({}: any) => Promise; } & ", + "ServerRouteCreateOptions", + " ? TReturnType : never" + ], + "path": "x-pack/plugins/dataset_quality/common/rest/create_call_dataset_quality_api.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "datasetQuality", + "id": "def-common.FetchOptions", + "type": "Type", + "tags": [], + "label": "FetchOptions", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ", \"body\"> & { pathname: string; method?: string | undefined; body?: any; }" + ], + "path": "x-pack/plugins/dataset_quality/common/fetch_options.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [] } } \ No newline at end of file diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 2791eb615437..87ee21342718 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3 | 0 | 3 | 0 | +| 8 | 0 | 8 | 3 | ## Client @@ -31,8 +31,14 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux ### Start +### Consts, variables and types + + ## Common ### Interfaces +### Consts, variables and types + + diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index a89f7618fd20..39bad4443575 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -27,9 +27,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | stackAlerts, graph, infra, inputControlVis, securitySolution, savedObjects | - | | | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | +| | triggersActionsUi | - | +| | inspector, data, savedObjects, runtimeFields, indexManagement, dataViewEditor, unifiedSearch, embeddable, visualizations, controls, dashboard, licensing, savedObjectsTagging, dataViewFieldEditor, lens, security, triggersActionsUi, cases, observabilityShared, advancedSettings, exploratoryView, fleet, telemetry, maps, banners, reporting, timelines, cloudSecurityPosture, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, uptime, cloudLinks, console, dataViewManagement, eventAnnotationListing, filesManagement, uiActions, visTypeVislib | - | +| | @kbn/core, visualizations, triggersActionsUi, advancedSettings | - | | | observability, @kbn/securitysolution-data-table, securitySolution | - | | | monitoring | - | -| | inspector, data, savedObjects, runtimeFields, indexManagement, dataViewEditor, unifiedSearch, embeddable, visualizations, controls, dashboard, licensing, savedObjectsTagging, dataViewFieldEditor, lens, security, triggersActionsUi, cases, observabilityShared, advancedSettings, exploratoryView, fleet, telemetry, maps, banners, reporting, timelines, cloudSecurityPosture, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, uptime, cloudLinks, console, dataViewManagement, eventAnnotationListing, filesManagement, uiActions, visTypeVislib | - | | | alerting, discover, securitySolution | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | @@ -122,7 +124,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | canvas | - | | | canvas | - | | | spaces, savedObjectsManagement | - | -| | @kbn/core, visualizations, triggersActionsUi, advancedSettings | - | | | reporting | - | | | @kbn/reporting-export-types-pdf, reporting | - | | | @kbn/core-elasticsearch-server-internal, @kbn/core-plugins-server-internal, observabilityOnboarding, console | - | @@ -135,7 +136,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-lifecycle-browser-mocks, @kbn/core, @kbn/core-plugins-browser-internal | - | | | @kbn/core | - | | | @kbn/core-plugins-server-internal | - | -| | security, aiops, licenseManagement, ml, profiling, apm, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | 8.8.0 | +| | security, aiops, licenseManagement, ml, observability, profiling, apm, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | 8.8.0 | | | spaces, security, actions, alerting, aiops, ml, remoteClusters, graph, indexLifecycleManagement, mapsEms, osquery, securitySolution, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | apm, fleet, security, securitySolution | 8.8.0 | | | apm, fleet, security, securitySolution | 8.8.0 | @@ -164,6 +165,8 @@ Safe to remove. | Deprecated API | Plugin Id | | ---------------|------------| | | alerting | +| | alerting | +| | alerting | | | data | | | data | | | data | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 93ec1d6ddeb5..da07e444ea69 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -1136,7 +1136,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts#:~:text=alertFactory), [custom_threshold_executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts#:~:text=alertFactory), [executor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.test.ts#:~:text=alertFactory) | - | +| | [custom_threshold_executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts#:~:text=alertFactory), [executor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts#:~:text=alertFactory), [executor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.test.ts#:~:text=alertFactory) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/public/plugin.ts#:~:text=license%24) | 8.8.0 | | | [render_cell_value.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx#:~:text=DeprecatedCellValueElementProps), [render_cell_value.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx#:~:text=DeprecatedCellValueElementProps) | - | @@ -1333,7 +1334,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 15 more | 8.8.0 | | | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures) | 8.8.0 | | | [account_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/account_management/account_management_app.tsx#:~:text=toMountPoint), [account_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/account_management/account_management_app.tsx#:~:text=toMountPoint), [session_expiration_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/session/session_expiration_toast.tsx#:~:text=toMountPoint), [session_expiration_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/session/session_expiration_toast.tsx#:~:text=toMountPoint) | - | -| | [access_agreement_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx#:~:text=KibanaThemeProvider), [access_agreement_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx#:~:text=KibanaThemeProvider), [access_agreement_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx#:~:text=KibanaThemeProvider), [logged_out_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx#:~:text=KibanaThemeProvider), [logged_out_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx#:~:text=KibanaThemeProvider), [logged_out_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx#:~:text=KibanaThemeProvider), [login_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/login/login_page.tsx#:~:text=KibanaThemeProvider), [login_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/login/login_page.tsx#:~:text=KibanaThemeProvider), [login_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/login/login_page.tsx#:~:text=KibanaThemeProvider), [overwritten_session_page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx#:~:text=KibanaThemeProvider)+ 20 more | - | +| | [api_keys_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx#:~:text=KibanaThemeProvider), [api_keys_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx#:~:text=KibanaThemeProvider), [api_keys_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx#:~:text=KibanaThemeProvider), [users_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/users/users_management_app.tsx#:~:text=KibanaThemeProvider), [users_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/users/users_management_app.tsx#:~:text=KibanaThemeProvider), [users_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/users/users_management_app.tsx#:~:text=KibanaThemeProvider), [roles_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/roles_management_app.tsx#:~:text=KibanaThemeProvider), [roles_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/roles_management_app.tsx#:~:text=KibanaThemeProvider), [roles_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/roles/roles_management_app.tsx#:~:text=KibanaThemeProvider), [role_mappings_management_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx#:~:text=KibanaThemeProvider)+ 20 more | - | | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/plugin.tsx#:~:text=license%24) | 8.8.0 | | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | @@ -1372,10 +1373,10 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | | | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject) | - | | | [timelines.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts#:~:text=convertToMultiNamespaceTypeVersion), [notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts#:~:text=convertToMultiNamespaceTypeVersion), [pinned_events.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts#:~:text=convertToMultiNamespaceTypeVersion), [legacy_saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | -| | [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [trusted_app_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [trusted_app_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [receiver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [receiver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [policy_hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [policy_hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID)+ 37 more | - | +| | [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [trusted_app_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [trusted_app_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [policy_hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [policy_hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_ID)+ 35 more | - | | | [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_NAME), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_NAME), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_NAME), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_NAME) | - | | | [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/trusted_apps/constants.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/index.ts#:~:text=ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION) | - | -| | [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [event_filter_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/event_filter_validator.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [event_filter_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/event_filter_validator.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [security_lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID)+ 35 more | - | +| | [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [event_filter_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/event_filter_validator.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [event_filter_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/event_filter_validator.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_ID)+ 33 more | - | | | [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_NAME) | - | | | [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION), [create_event_filters.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts#:~:text=ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION) | - | | | [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [lists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [manifest_manager.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [host_isolation_exceptions_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/host_isolation_exceptions_validator.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [host_isolation_exceptions_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/host_isolation_exceptions_validator.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/constants.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID), [constants.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/constants.ts#:~:text=ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID)+ 19 more | - | @@ -1488,6 +1489,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| +| | [tooltip_content.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/tooltip_content.tsx#:~:text=MaintenanceWindow), [tooltip_content.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/tooltip_content.tsx#:~:text=MaintenanceWindow), [cell.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx#:~:text=MaintenanceWindow), [cell.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx#:~:text=MaintenanceWindow), [cell.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx#:~:text=MaintenanceWindow), [cell.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/maintenance_windows/cell.tsx#:~:text=MaintenanceWindow), [bulk_get_maintenance_windows.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts#:~:text=MaintenanceWindow), [bulk_get_maintenance_windows.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts#:~:text=MaintenanceWindow), [bulk_get_maintenance_windows.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts#:~:text=MaintenanceWindow), [bulk_get_maintenance_windows.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/bulk_get_maintenance_windows.ts#:~:text=MaintenanceWindow)+ 11 more | - | | | [use_bulk_edit_response.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx#:~:text=toMountPoint), [use_bulk_edit_response.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx#:~:text=toMountPoint), [use_bulk_edit_response.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_response.tsx#:~:text=toMountPoint), [use_bulk_operation_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx#:~:text=toMountPoint), [use_bulk_operation_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx#:~:text=toMountPoint), [use_bulk_operation_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_operation_toast.tsx#:~:text=toMountPoint), [rule_add.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx#:~:text=toMountPoint), [rule_add.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx#:~:text=toMountPoint), [rule_edit.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx#:~:text=toMountPoint), [rule_edit.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx#:~:text=toMountPoint)+ 6 more | - | | | [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/app.tsx#:~:text=KibanaThemeProvider), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/app.tsx#:~:text=KibanaThemeProvider), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/app.tsx#:~:text=KibanaThemeProvider), [connectors_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx#:~:text=KibanaThemeProvider), [connectors_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx#:~:text=KibanaThemeProvider), [connectors_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/connectors_app.tsx#:~:text=KibanaThemeProvider), [test_utils.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx#:~:text=KibanaThemeProvider), [test_utils.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx#:~:text=KibanaThemeProvider), [test_utils.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/test_utils.tsx#:~:text=KibanaThemeProvider) | - | | | [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute), [rule_reducer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_reducer.ts#:~:text=SavedObjectAttribute) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 90dde6624eb2..3689103ebf77 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -124,6 +124,14 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ +## @elastic/obs-ux-management-team + +| Plugin | Deprecated API | Reference location(s) | Remove By | +| --------|-------|-----------|-----------| +| observability | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability/public/plugin.ts#:~:text=license%24) | 8.8.0 | + + + ## @elastic/platform-deployment-management | Plugin | Deprecated API | Reference location(s) | Remove By | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 6f5d7e3396c4..39156240d11d 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 307409fec37c..5b01be8304df 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -993,6 +993,21 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "discover", + "id": "def-public.FlyoutCustomization.size", + "type": "CompoundType", + "tags": [], + "label": "size", + "description": [], + "signature": [ + "Property", + ".Width | undefined" + ], + "path": "src/plugins/discover/public/customizations/customization_types/flyout_customization.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "discover", "id": "def-public.FlyoutCustomization.title", diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 71b2e1cea2a0..ee530771bc84 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 133 | 0 | 90 | 20 | +| 134 | 0 | 91 | 20 | ## Client diff --git a/api_docs/discover_enhanced.devdocs.json b/api_docs/discover_enhanced.devdocs.json index 2a08df38909f..f0194c72301a 100644 --- a/api_docs/discover_enhanced.devdocs.json +++ b/api_docs/discover_enhanced.devdocs.json @@ -639,15 +639,15 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -663,15 +663,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; }" + ") => void; }" ], "path": "x-pack/plugins/discover_enhanced/public/plugin.ts", "deprecated": false, @@ -760,15 +760,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -784,17 +786,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 9df5fae9e631..e574d63bacfe 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index fbb6be3ad8e2..073cf2bf462a 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index dd27d3fabe5a..0a83c178d471 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index b898e64c67d2..426bbd6909c6 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -7675,15 +7675,15 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -7699,15 +7699,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; }" + ") => void; }" ], "path": "src/plugins/embeddable/public/plugin.tsx", "deprecated": false, @@ -7735,15 +7735,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -7759,17 +7761,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index bfad9f63f482..0e4d97b02805 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index b0a5975752c7..cf3d5bd39d1d 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 69551457934c..4379f2bd3055 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index d5d1d961a6c1..dc6ba9bd4ee5 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 6a1598ef21c8..b5f3883774d1 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index c8c74aa4937a..f0dc0ff59a56 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index f5b2d014ce50..1d4abf2adc10 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 4209dbd4c24b..5157f01a6569 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.devdocs.json b/api_docs/exploratory_view.devdocs.json index 299ed7b02041..0e55c2772676 100644 --- a/api_docs/exploratory_view.devdocs.json +++ b/api_docs/exploratory_view.devdocs.json @@ -1532,7 +1532,7 @@ "label": "defaultSeriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/types.ts", "deprecated": false, diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 8f195a5c2420..1205013dfecf 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 39711a534055..379277590c7e 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index b4436f848d99..02239f4875bb 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index ff81db920e83..f6844f370c27 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 84b62bccb1a4..71b20928f4d5 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 490307858c68..26d7d341c276 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 03703f1840aa..e0f6202736d6 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 05fa7dd8d18e..33d8ba84a827 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index fc41ff6fb20d..0b3360e73598 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index b0dcd2bb7eb3..ed938dcab43e 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index 3287beca87e4..069206eeff30 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.devdocs.json b/api_docs/expression_shape.devdocs.json index 8e3a2a1d04c5..3c6d97d7ce0f 100644 --- a/api_docs/expression_shape.devdocs.json +++ b/api_docs/expression_shape.devdocs.json @@ -635,7 +635,7 @@ "label": "strokeLinecap", "description": [], "signature": [ - "\"butt\" | \"round\" | \"square\" | \"inherit\" | undefined" + "\"inherit\" | \"butt\" | \"round\" | \"square\" | undefined" ], "path": "src/plugins/expression_shape/public/components/reusable/types.tsx", "deprecated": false, @@ -677,7 +677,7 @@ "label": "strokeLinejoin", "description": [], "signature": [ - "\"round\" | \"inherit\" | \"miter\" | \"bevel\" | undefined" + "\"inherit\" | \"round\" | \"miter\" | \"bevel\" | undefined" ], "path": "src/plugins/expression_shape/public/components/reusable/types.tsx", "deprecated": false, diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 46bbdf399e6c..4cb20fe12c2d 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 5a302e8a3727..b2ea5e4c3722 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.devdocs.json b/api_docs/expression_x_y.devdocs.json index 557d8749fb6d..8f9e4a2d6e27 100644 --- a/api_docs/expression_x_y.devdocs.json +++ b/api_docs/expression_x_y.devdocs.json @@ -576,7 +576,7 @@ "label": "seriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\"" + "\"area\" | \"line\" | \"bar\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, @@ -3340,7 +3340,7 @@ "label": "SeriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\"" + "\"area\" | \"line\" | \"bar\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 776e9939050e..21ffcbf7617f 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index b22b81fce29c..147e417c0ce6 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -3802,7 +3802,7 @@ "id": "def-public.ExpressionRenderHandler.Unnamed.$2", "type": "Object", "tags": [], - "label": "{\n onRenderError,\n renderMode,\n syncColors,\n syncTooltips,\n syncCursor,\n interactive,\n hasCompatibleActions = async () => false,\n getCompatibleCellValueActions = async () => [],\n executionContext,\n shouldShowLegendAction,\n }", + "label": "{\n onRenderError,\n renderMode,\n syncColors,\n syncTooltips,\n syncCursor,\n interactive,\n hasCompatibleActions = async () => false,\n getCompatibleCellValueActions = async () => [],\n executionContext,\n }", "description": [], "signature": [ "ExpressionRenderHandlerParams" @@ -7350,38 +7350,6 @@ } ], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-public.ExecutionContext.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-public.ExecutionContext.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -11012,38 +10980,6 @@ "path": "src/plugins/expressions/public/types/index.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "expressions", - "id": "def-public.IExpressionLoaderParams.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/public/types/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-public.IExpressionLoaderParams.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/public/types/index.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -11426,38 +11362,6 @@ "trackAdoption": false, "children": [], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-public.IInterpreterRenderHandlers.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-public.IInterpreterRenderHandlers.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -11796,43 +11700,11 @@ "label": "padding", "description": [], "signature": [ - "\"m\" | \"s\" | \"xs\" | \"l\" | \"xl\" | undefined" + "\"m\" | \"s\" | \"l\" | \"xs\" | \"xl\" | undefined" ], "path": "src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "expressions", - "id": "def-public.ReactExpressionRendererProps.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-public.ReactExpressionRendererProps.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -18885,38 +18757,6 @@ } ], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-server.ExecutionContext.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-server.ExecutionContext.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -21566,38 +21406,6 @@ "trackAdoption": false, "children": [], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-server.IInterpreterRenderHandlers.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-server.IInterpreterRenderHandlers.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -31016,38 +30824,6 @@ } ], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-common.ExecutionContext.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-common.ExecutionContext.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/execution/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -35922,38 +35698,6 @@ "trackAdoption": false, "children": [], "returnComment": [] - }, - { - "parentPluginId": "expressions", - "id": "def-common.IInterpreterRenderHandlers.shouldShowLegendAction", - "type": "Function", - "tags": [], - "label": "shouldShowLegendAction", - "description": [], - "signature": [ - "((actionId: string) => boolean) | undefined" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "expressions", - "id": "def-common.IInterpreterRenderHandlers.shouldShowLegendAction.$1", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/expressions/common/expression_renderers/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] } ], "initialIsOpen": false @@ -38220,7 +37964,7 @@ "\nMode of the expression render environment.\nThis value can be set from a consumer embedding an expression renderer and is accessible\nfrom within the active render function as part of the handlers.\nThe following modes are supported:\n* view (default): The chart is rendered in a container with the main purpose of viewing the chart (e.g. in a container like dashboard or canvas)\n* preview: The chart is rendered in very restricted space (below 100px width and height) and should only show a rough outline\n* edit: The chart is rendered within an editor and configuration elements within the chart should be displayed" ], "signature": [ - "\"edit\" | \"preview\" | \"view\"" + "\"edit\" | \"view\" | \"preview\"" ], "path": "src/plugins/expressions/common/expression_renderers/types.ts", "deprecated": false, diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 0a5f31956155..e8b9c806171f 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2224 | 17 | 1765 | 5 | +| 2208 | 17 | 1749 | 5 | ## Client diff --git a/api_docs/features.devdocs.json b/api_docs/features.devdocs.json index 3f329d7f351b..27e89ae753ed 100644 --- a/api_docs/features.devdocs.json +++ b/api_docs/features.devdocs.json @@ -56,7 +56,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -64,7 +64,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -202,7 +202,7 @@ "label": "privileges", "description": [], "signature": [ - "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" + "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -255,7 +255,7 @@ "label": "reserved", "description": [], "signature": [ - "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" + "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -441,7 +441,7 @@ "\nIf your feature requires access to specific owners of cases (aka plugins that have created cases), then specify your access needs here. The values here should\nbe unique identifiers for the owners of cases you want access to." ], "signature": [ - "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; } | undefined" + "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; } | undefined" ], "path": "x-pack/plugins/features/common/feature_kibana_privileges.ts", "deprecated": false, @@ -1264,7 +1264,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -1272,7 +1272,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -1410,7 +1410,7 @@ "label": "privileges", "description": [], "signature": [ - "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" + "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -1463,7 +1463,7 @@ "label": "reserved", "description": [], "signature": [ - "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" + "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -1828,7 +1828,7 @@ "\nIf your feature requires access to specific owners of cases (aka plugins that have created cases), then specify your access needs here. The values here should\nbe unique identifiers for the owners of cases you want access to." ], "signature": [ - "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; } | undefined" + "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; } | undefined" ], "path": "x-pack/plugins/features/common/feature_kibana_privileges.ts", "deprecated": false, @@ -2961,7 +2961,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", + "Readonly<{ id: string; name: string; description?: string | undefined; category: Readonly<{ id: string; label: string; ariaLabel?: string | undefined; order?: number | undefined; euiIconType?: string | undefined; }>; order?: number | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; privileges: Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null; subFeatures?: readonly Readonly<{ name: string; requireAllSpaces?: boolean | undefined; privilegesTooltip?: string | undefined; privilegeGroups: readonly Readonly<{ groupType: ", { "pluginId": "features", "scope": "common", @@ -2969,7 +2969,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -3107,7 +3107,7 @@ "label": "privileges", "description": [], "signature": [ - "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" + "Readonly<{ all: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; read: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }> | null" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -3160,7 +3160,7 @@ "label": "reserved", "description": [], "signature": [ - "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" + "Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -3233,7 +3233,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }>" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, @@ -3270,7 +3270,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, @@ -3314,7 +3314,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"read\" | \"all\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; }> | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; ui: readonly string[]; catalogue?: readonly string[] | undefined; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; description?: string | undefined; }" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, @@ -3658,7 +3658,7 @@ "\nIf your feature requires access to specific owners of cases (aka plugins that have created cases), then specify your access needs here. The values here should\nbe unique identifiers for the owners of cases you want access to." ], "signature": [ - "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; } | undefined" + "{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; } | undefined" ], "path": "x-pack/plugins/features/common/feature_kibana_privileges.ts", "deprecated": false, diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 3d43ce341fbc..6332c7151516 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 8d3ee144d054..127e5339cf4e 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 97d7ebfb2f5b..5e2d7ef9c551 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index f2663b244e34..13d982803765 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index db553dcf2263..0cd387a49185 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 6aedc7943b64..a57d03da5d59 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -7146,9 +7146,9 @@ }, ", options?: { spaceId?: string | undefined; id?: string | undefined; user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -7303,9 +7303,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -7569,9 +7569,9 @@ "NewPackagePolicyWithId", "[], options?: { user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -7685,9 +7685,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -7779,9 +7779,9 @@ }, "[], options?: { user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -7893,9 +7893,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8382,9 +8382,9 @@ }, ", options?: { user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8500,9 +8500,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8586,9 +8586,9 @@ }, ", ids: string[], options?: { user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8699,9 +8699,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8814,9 +8814,9 @@ }, ", ids: string[], options?: { user?: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -8919,9 +8919,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -20639,6 +20639,21 @@ "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.Installation.latest_install_failed_attempts", + "type": "Array", + "tags": [], + "label": "latest_install_failed_attempts", + "description": [], + "signature": [ + "InstallFailedAttempt", + "[] | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/epm.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -23426,7 +23441,7 @@ "label": "[RegistryVarsEntryKeys.type]", "description": [], "signature": [ - "\"string\" | \"text\" | \"integer\" | \"select\" | \"bool\" | \"password\" | \"yaml\" | \"textarea\"" + "\"string\" | \"text\" | \"integer\" | \"select\" | \"textarea\" | \"bool\" | \"password\" | \"yaml\"" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 98c3b0c71954..ecd23ae20378 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1212 | 3 | 1094 | 46 | +| 1213 | 3 | 1095 | 47 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 9bbc2d194bf1..d91a3b8c9f2e 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 4daaac8bc910..040c14cda6a1 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.devdocs.json b/api_docs/home.devdocs.json index 4de7593782f6..964cceb399ba 100644 --- a/api_docs/home.devdocs.json +++ b/api_docs/home.devdocs.json @@ -1766,6 +1766,26 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "home", + "id": "def-server.TutorialContext.staticAssets", + "type": "Object", + "tags": [], + "label": "staticAssets", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + } + ], + "path": "src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "home", "id": "def-server.TutorialContext.Unnamed", @@ -1911,7 +1931,9 @@ "label": "SampleDatasetProvider", "description": [], "signature": [ - "() => ", + "(context: ", + "SampleDatasetProviderContext", + ") => ", { "pluginId": "@kbn/utility-types", "scope": "common", @@ -1925,7 +1947,22 @@ "deprecated": false, "trackAdoption": false, "returnComment": [], - "children": [], + "children": [ + { + "parentPluginId": "home", + "id": "def-server.SampleDatasetProvider.$1", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "SampleDatasetProviderContext" + ], + "path": "src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], "initialIsOpen": false }, { diff --git a/api_docs/home.mdx b/api_docs/home.mdx index f015c61e918c..223771a20a5d 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 149 | 0 | 109 | 0 | +| 151 | 0 | 111 | 1 | ## Client diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 8b37c7c3f558..d967cf6eba18 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index d728f1d5e164..e47e74a62b3e 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index d99952c4838c..b92a3addae84 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.devdocs.json b/api_docs/infra.devdocs.json index 6329b376e20c..7c1db61528e4 100644 --- a/api_docs/infra.devdocs.json +++ b/api_docs/infra.devdocs.json @@ -358,7 +358,7 @@ "label": "featureFlags", "description": [], "signature": [ - "{ customThresholdAlertsEnabled: boolean; logsUIEnabled: boolean; metricsExplorerEnabled: boolean; osqueryEnabled: boolean; inventoryThresholdAlertRuleEnabled: boolean; metricThresholdAlertRuleEnabled: boolean; logThresholdAlertRuleEnabled: boolean; alertsAndRulesDropdownEnabled: boolean; }" + "{ customThresholdAlertsEnabled: boolean; logsUIEnabled: boolean; metricsExplorerEnabled: boolean; osqueryEnabled: boolean; inventoryThresholdAlertRuleEnabled: boolean; metricThresholdAlertRuleEnabled: boolean; logThresholdAlertRuleEnabled: boolean; alertsAndRulesDropdownEnabled: boolean; profilingEnabled: boolean; }" ], "path": "x-pack/plugins/infra/common/plugin_config_types.ts", "deprecated": false, diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 19401203c7f5..dee6ecf9d103 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 0cc16e89bd7d..f5bef4a39476 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 63d7438c8904..a2473733d0d5 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 189b6610ee65..dd26be524aa3 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index aabb76d630a7..483eac15ecbd 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.devdocs.json b/api_docs/kbn_aiops_utils.devdocs.json index 4ab34fcaf1db..b733fd1318ca 100644 --- a/api_docs/kbn_aiops_utils.devdocs.json +++ b/api_docs/kbn_aiops_utils.devdocs.json @@ -336,12 +336,10 @@ "parentPluginId": "@kbn/aiops-utils", "id": "def-common.WindowParameters.baselineMin", "type": "number", - "tags": [ - "type" - ], + "tags": [], "label": "baselineMin", "description": [ - "\nBaseline minimum value" + "Baseline minimum value" ], "path": "x-pack/packages/ml/aiops_utils/window_parameters.ts", "deprecated": false, @@ -351,12 +349,10 @@ "parentPluginId": "@kbn/aiops-utils", "id": "def-common.WindowParameters.baselineMax", "type": "number", - "tags": [ - "type" - ], + "tags": [], "label": "baselineMax", "description": [ - "\nBaseline maximum value" + "Baseline maximum value" ], "path": "x-pack/packages/ml/aiops_utils/window_parameters.ts", "deprecated": false, @@ -366,12 +362,10 @@ "parentPluginId": "@kbn/aiops-utils", "id": "def-common.WindowParameters.deviationMin", "type": "number", - "tags": [ - "type" - ], + "tags": [], "label": "deviationMin", "description": [ - "\nDeviation minimum value" + "Deviation minimum value" ], "path": "x-pack/packages/ml/aiops_utils/window_parameters.ts", "deprecated": false, @@ -381,12 +375,10 @@ "parentPluginId": "@kbn/aiops-utils", "id": "def-common.WindowParameters.deviationMax", "type": "number", - "tags": [ - "type" - ], + "tags": [], "label": "deviationMax", "description": [ - "\nDeviation maximum value" + "Deviation maximum value" ], "path": "x-pack/packages/ml/aiops_utils/window_parameters.ts", "deprecated": false, diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 23e0ca70b44c..d5f0261697f7 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 76f8c964865d..3f61167dd6d0 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index c5357a067846..47d0dc67f62d 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.devdocs.json b/api_docs/kbn_alerts_as_data_utils.devdocs.json index 8f3c9ec250b0..a98501eb12e6 100644 --- a/api_docs/kbn_alerts_as_data_utils.devdocs.json +++ b/api_docs/kbn_alerts_as_data_utils.devdocs.json @@ -196,7 +196,7 @@ "label": "AADAlert", "description": [], "signature": [ - "({ '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }) | ({} & { 'agent.name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'error.grouping_name'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; labels?: unknown; 'processor.event'?: string | undefined; 'service.environment'?: string | undefined; 'service.language.name'?: string | undefined; 'service.name'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'slo.id'?: string | undefined; 'slo.instanceId'?: string | undefined; 'slo.revision'?: string | number | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'agent.name'?: string | undefined; 'anomaly.bucket_span.minutes'?: string | undefined; 'anomaly.start'?: string | number | undefined; 'error.message'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'monitor.id'?: string | undefined; 'monitor.name'?: string | undefined; 'monitor.type'?: string | undefined; 'observer.geo.name'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.x509.issuer.common_name'?: string | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.subject.common_name'?: string | undefined; 'url.full'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({ '@timestamp': string | number; 'kibana.alert.ancestors': { depth: string | number; id: string; index: string; type: string; }[]; 'kibana.alert.depth': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.original_event.action': string; 'kibana.alert.original_event.category': string[]; 'kibana.alert.original_event.created': string | number; 'kibana.alert.original_event.dataset': string; 'kibana.alert.original_event.id': string; 'kibana.alert.original_event.ingested': string | number; 'kibana.alert.original_event.kind': string; 'kibana.alert.original_event.module': string; 'kibana.alert.original_event.original': string; 'kibana.alert.original_event.outcome': string; 'kibana.alert.original_event.provider': string; 'kibana.alert.original_event.sequence': string | number; 'kibana.alert.original_event.type': string[]; 'kibana.alert.original_time': string | number; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.false_positives': string[]; 'kibana.alert.rule.max_signals': (string | number)[]; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.threat.framework': string; 'kibana.alert.rule.threat.tactic.id': string; 'kibana.alert.rule.threat.tactic.name': string; 'kibana.alert.rule.threat.tactic.reference': string; 'kibana.alert.rule.threat.technique.id': string; 'kibana.alert.rule.threat.technique.name': string; 'kibana.alert.rule.threat.technique.reference': string; 'kibana.alert.rule.threat.technique.subtechnique.id': string; 'kibana.alert.rule.threat.technique.subtechnique.name': string; 'kibana.alert.rule.threat.technique.subtechnique.reference': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'ecs.version'?: string | undefined; 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.ancestors.rule'?: string | undefined; 'kibana.alert.building_block_type'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.group.id'?: string | undefined; 'kibana.alert.group.index'?: number | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.new_terms'?: string[] | undefined; 'kibana.alert.original_event.agent_id_status'?: string | undefined; 'kibana.alert.original_event.code'?: string | undefined; 'kibana.alert.original_event.duration'?: string | undefined; 'kibana.alert.original_event.end'?: string | number | undefined; 'kibana.alert.original_event.hash'?: string | undefined; 'kibana.alert.original_event.reason'?: string | undefined; 'kibana.alert.original_event.reference'?: string | undefined; 'kibana.alert.original_event.risk_score'?: number | undefined; 'kibana.alert.original_event.risk_score_norm'?: number | undefined; 'kibana.alert.original_event.severity'?: string | number | undefined; 'kibana.alert.original_event.start'?: string | number | undefined; 'kibana.alert.original_event.timezone'?: string | undefined; 'kibana.alert.original_event.url'?: string | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.building_block_type'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.immutable'?: string[] | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.rule.timeline_id'?: string[] | undefined; 'kibana.alert.rule.timeline_title'?: string[] | undefined; 'kibana.alert.rule.timestamp_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.threshold_result.cardinality'?: unknown; 'kibana.alert.threshold_result.count'?: string | number | undefined; 'kibana.alert.threshold_result.from'?: string | number | undefined; 'kibana.alert.threshold_result.terms'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.alert.workflow_user'?: string | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({ 'kibana.alert.job_id': string; } & { 'kibana.alert.anomaly_score'?: number | undefined; 'kibana.alert.anomaly_timestamp'?: string | number | undefined; 'kibana.alert.is_interim'?: boolean | undefined; 'kibana.alert.top_influencers'?: { influencer_field_name?: string | undefined; influencer_field_value?: string | undefined; influencer_score?: number | undefined; initial_influencer_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; timestamp?: string | number | undefined; }[] | undefined; 'kibana.alert.top_records'?: { actual?: number | undefined; by_field_name?: string | undefined; by_field_value?: string | undefined; detector_index?: number | undefined; field_name?: string | undefined; function?: string | undefined; initial_record_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; over_field_name?: string | undefined; over_field_value?: string | undefined; partition_field_name?: string | undefined; partition_field_value?: string | undefined; record_score?: number | undefined; timestamp?: string | number | undefined; typical?: number | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; })" + "({ '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }) | ({} & { 'agent.name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'error.grouping_name'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; labels?: unknown; 'processor.event'?: string | undefined; 'service.environment'?: string | undefined; 'service.language.name'?: string | undefined; 'service.name'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'slo.id'?: string | undefined; 'slo.instanceId'?: string | undefined; 'slo.revision'?: string | number | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({} & { 'agent.name'?: string | undefined; 'anomaly.bucket_span.minutes'?: string | undefined; 'anomaly.start'?: string | number | undefined; 'error.message'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'monitor.id'?: string | undefined; 'monitor.name'?: string | undefined; 'monitor.type'?: string | undefined; 'observer.geo.name'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.x509.issuer.common_name'?: string | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.subject.common_name'?: string | undefined; 'url.full'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({ '@timestamp': string | number; 'kibana.alert.ancestors': { depth: string | number; id: string; index: string; type: string; }[]; 'kibana.alert.depth': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.original_event.action': string; 'kibana.alert.original_event.category': string[]; 'kibana.alert.original_event.created': string | number; 'kibana.alert.original_event.dataset': string; 'kibana.alert.original_event.id': string; 'kibana.alert.original_event.ingested': string | number; 'kibana.alert.original_event.kind': string; 'kibana.alert.original_event.module': string; 'kibana.alert.original_event.original': string; 'kibana.alert.original_event.outcome': string; 'kibana.alert.original_event.provider': string; 'kibana.alert.original_event.sequence': string | number; 'kibana.alert.original_event.type': string[]; 'kibana.alert.original_time': string | number; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.false_positives': string[]; 'kibana.alert.rule.max_signals': (string | number)[]; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.threat.framework': string; 'kibana.alert.rule.threat.tactic.id': string; 'kibana.alert.rule.threat.tactic.name': string; 'kibana.alert.rule.threat.tactic.reference': string; 'kibana.alert.rule.threat.technique.id': string; 'kibana.alert.rule.threat.technique.name': string; 'kibana.alert.rule.threat.technique.reference': string; 'kibana.alert.rule.threat.technique.subtechnique.id': string; 'kibana.alert.rule.threat.technique.subtechnique.name': string; 'kibana.alert.rule.threat.technique.subtechnique.reference': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'ecs.version'?: string | undefined; 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.ancestors.rule'?: string | undefined; 'kibana.alert.building_block_type'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.group.id'?: string | undefined; 'kibana.alert.group.index'?: number | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.new_terms'?: string[] | undefined; 'kibana.alert.original_event.agent_id_status'?: string | undefined; 'kibana.alert.original_event.code'?: string | undefined; 'kibana.alert.original_event.duration'?: string | undefined; 'kibana.alert.original_event.end'?: string | number | undefined; 'kibana.alert.original_event.hash'?: string | undefined; 'kibana.alert.original_event.reason'?: string | undefined; 'kibana.alert.original_event.reference'?: string | undefined; 'kibana.alert.original_event.risk_score'?: number | undefined; 'kibana.alert.original_event.risk_score_norm'?: number | undefined; 'kibana.alert.original_event.severity'?: string | number | undefined; 'kibana.alert.original_event.start'?: string | number | undefined; 'kibana.alert.original_event.timezone'?: string | undefined; 'kibana.alert.original_event.url'?: string | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.building_block_type'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.immutable'?: string[] | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.rule.timeline_id'?: string[] | undefined; 'kibana.alert.rule.timeline_title'?: string[] | undefined; 'kibana.alert.rule.timestamp_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.threshold_result.cardinality'?: unknown; 'kibana.alert.threshold_result.count'?: string | number | undefined; 'kibana.alert.threshold_result.from'?: string | number | undefined; 'kibana.alert.threshold_result.terms'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.alert.workflow_user'?: string | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }) | ({ 'kibana.alert.job_id': string; } & { 'kibana.alert.anomaly_score'?: number | undefined; 'kibana.alert.anomaly_timestamp'?: string | number | undefined; 'kibana.alert.is_interim'?: boolean | undefined; 'kibana.alert.top_influencers'?: { influencer_field_name?: string | undefined; influencer_field_value?: string | undefined; influencer_score?: number | undefined; initial_influencer_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; timestamp?: string | number | undefined; }[] | undefined; 'kibana.alert.top_records'?: { actual?: number | undefined; by_field_name?: string | undefined; by_field_value?: string | undefined; detector_index?: number | undefined; field_name?: string | undefined; function?: string | undefined; initial_record_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; over_field_name?: string | undefined; over_field_value?: string | undefined; partition_field_name?: string | undefined; partition_field_value?: string | undefined; record_score?: number | undefined; timestamp?: string | number | undefined; typical?: number | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; })" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/index.ts", "deprecated": false, @@ -211,7 +211,7 @@ "label": "Alert", "description": [], "signature": [ - "{ '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" + "{ '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/alert_schema.ts", "deprecated": false, @@ -241,7 +241,15 @@ "label": "AlertFieldMap", "description": [], "signature": [ - "{ readonly \"kibana.alert.action_group\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.case_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.duration.us\": { readonly type: \"long\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.end\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping_history\": { readonly type: \"boolean\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.maintenance_window_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.instance.id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.last_detected\": { readonly type: \"date\"; readonly required: false; readonly array: false; }; readonly \"kibana.alert.reason\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.category\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.consumer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.execution.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.name\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.producer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.revision\": { readonly type: \"long\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.rule.rule_type_id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.status\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"event.action\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"event.kind\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.space_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: true; }; readonly tags: { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"@timestamp\": { readonly type: \"date\"; readonly required: true; readonly array: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }" + "{ readonly \"kibana.alert.action_group\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.case_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.duration.us\": { readonly type: \"long\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.end\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping_history\": { readonly type: \"boolean\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.maintenance_window_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.instance.id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.last_detected\": { readonly type: \"date\"; readonly required: false; readonly array: false; }; readonly \"kibana.alert.reason\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; readonly multi_fields: ", + { + "pluginId": "@kbn/alerts-as-data-utils", + "scope": "common", + "docId": "kibKbnAlertsAsDataUtilsPluginApi", + "section": "def-common.MultiField", + "text": "MultiField" + }, + "[]; }; readonly \"kibana.alert.rule.category\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.consumer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.execution.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.name\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.producer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.revision\": { readonly type: \"long\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.rule.rule_type_id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.status\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.workflow_assignee_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"event.action\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"event.kind\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.space_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: true; }; readonly tags: { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"@timestamp\": { readonly type: \"date\"; readonly required: true; readonly array: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }" ], "path": "packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts", "deprecated": false, @@ -307,7 +315,7 @@ "label": "MlAnomalyDetectionAlert", "description": [], "signature": [ - "{ 'kibana.alert.job_id': string; } & { 'kibana.alert.anomaly_score'?: number | undefined; 'kibana.alert.anomaly_timestamp'?: string | number | undefined; 'kibana.alert.is_interim'?: boolean | undefined; 'kibana.alert.top_influencers'?: { influencer_field_name?: string | undefined; influencer_field_value?: string | undefined; influencer_score?: number | undefined; initial_influencer_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; timestamp?: string | number | undefined; }[] | undefined; 'kibana.alert.top_records'?: { actual?: number | undefined; by_field_name?: string | undefined; by_field_value?: string | undefined; detector_index?: number | undefined; field_name?: string | undefined; function?: string | undefined; initial_record_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; over_field_name?: string | undefined; over_field_value?: string | undefined; partition_field_name?: string | undefined; partition_field_value?: string | undefined; record_score?: number | undefined; timestamp?: string | number | undefined; typical?: number | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" + "{ 'kibana.alert.job_id': string; } & { 'kibana.alert.anomaly_score'?: number | undefined; 'kibana.alert.anomaly_timestamp'?: string | number | undefined; 'kibana.alert.is_interim'?: boolean | undefined; 'kibana.alert.top_influencers'?: { influencer_field_name?: string | undefined; influencer_field_value?: string | undefined; influencer_score?: number | undefined; initial_influencer_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; timestamp?: string | number | undefined; }[] | undefined; 'kibana.alert.top_records'?: { actual?: number | undefined; by_field_name?: string | undefined; by_field_value?: string | undefined; detector_index?: number | undefined; field_name?: string | undefined; function?: string | undefined; initial_record_score?: number | undefined; is_interim?: boolean | undefined; job_id?: string | undefined; over_field_name?: string | undefined; over_field_value?: string | undefined; partition_field_name?: string | undefined; partition_field_value?: string | undefined; record_score?: number | undefined; timestamp?: string | number | undefined; typical?: number | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/ml_anomaly_detection_schema.ts", "deprecated": false, @@ -322,7 +330,7 @@ "label": "ObservabilityApmAlert", "description": [], "signature": [ - "{} & { 'agent.name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'error.grouping_name'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; labels?: unknown; 'processor.event'?: string | undefined; 'service.environment'?: string | undefined; 'service.language.name'?: string | undefined; 'service.name'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{} & { 'agent.name'?: string | undefined; 'error.grouping_key'?: string | undefined; 'error.grouping_name'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; labels?: unknown; 'processor.event'?: string | undefined; 'service.environment'?: string | undefined; 'service.language.name'?: string | undefined; 'service.name'?: string | undefined; 'transaction.name'?: string | undefined; 'transaction.type'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_apm_schema.ts", "deprecated": false, @@ -337,7 +345,7 @@ "label": "ObservabilityLogsAlert", "description": [], "signature": [ - "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_logs_schema.ts", "deprecated": false, @@ -352,7 +360,7 @@ "label": "ObservabilityMetricsAlert", "description": [], "signature": [ - "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_metrics_schema.ts", "deprecated": false, @@ -367,7 +375,7 @@ "label": "ObservabilitySloAlert", "description": [], "signature": [ - "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'slo.id'?: string | undefined; 'slo.instanceId'?: string | undefined; 'slo.revision'?: string | number | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{} & { 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'slo.id'?: string | undefined; 'slo.instanceId'?: string | undefined; 'slo.revision'?: string | number | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_slo_schema.ts", "deprecated": false, @@ -382,7 +390,7 @@ "label": "ObservabilityUptimeAlert", "description": [], "signature": [ - "{} & { 'agent.name'?: string | undefined; 'anomaly.bucket_span.minutes'?: string | undefined; 'anomaly.start'?: string | number | undefined; 'error.message'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'monitor.id'?: string | undefined; 'monitor.name'?: string | undefined; 'monitor.type'?: string | undefined; 'observer.geo.name'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.x509.issuer.common_name'?: string | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.subject.common_name'?: string | undefined; 'url.full'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{} & { 'agent.name'?: string | undefined; 'anomaly.bucket_span.minutes'?: string | undefined; 'anomaly.start'?: string | number | undefined; 'error.message'?: string | undefined; 'kibana.alert.context'?: unknown; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | number | undefined; 'kibana.alert.evaluation.values'?: (string | number)[] | undefined; 'kibana.alert.group'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'monitor.id'?: string | undefined; 'monitor.name'?: string | undefined; 'monitor.type'?: string | undefined; 'observer.geo.name'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.x509.issuer.common_name'?: string | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.subject.common_name'?: string | undefined; 'url.full'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_uptime_schema.ts", "deprecated": false, @@ -397,7 +405,7 @@ "label": "SecurityAlert", "description": [], "signature": [ - "{ '@timestamp': string | number; 'kibana.alert.ancestors': { depth: string | number; id: string; index: string; type: string; }[]; 'kibana.alert.depth': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.original_event.action': string; 'kibana.alert.original_event.category': string[]; 'kibana.alert.original_event.created': string | number; 'kibana.alert.original_event.dataset': string; 'kibana.alert.original_event.id': string; 'kibana.alert.original_event.ingested': string | number; 'kibana.alert.original_event.kind': string; 'kibana.alert.original_event.module': string; 'kibana.alert.original_event.original': string; 'kibana.alert.original_event.outcome': string; 'kibana.alert.original_event.provider': string; 'kibana.alert.original_event.sequence': string | number; 'kibana.alert.original_event.type': string[]; 'kibana.alert.original_time': string | number; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.false_positives': string[]; 'kibana.alert.rule.max_signals': (string | number)[]; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.threat.framework': string; 'kibana.alert.rule.threat.tactic.id': string; 'kibana.alert.rule.threat.tactic.name': string; 'kibana.alert.rule.threat.tactic.reference': string; 'kibana.alert.rule.threat.technique.id': string; 'kibana.alert.rule.threat.technique.name': string; 'kibana.alert.rule.threat.technique.reference': string; 'kibana.alert.rule.threat.technique.subtechnique.id': string; 'kibana.alert.rule.threat.technique.subtechnique.name': string; 'kibana.alert.rule.threat.technique.subtechnique.reference': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'ecs.version'?: string | undefined; 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.ancestors.rule'?: string | undefined; 'kibana.alert.building_block_type'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.group.id'?: string | undefined; 'kibana.alert.group.index'?: number | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.new_terms'?: string[] | undefined; 'kibana.alert.original_event.agent_id_status'?: string | undefined; 'kibana.alert.original_event.code'?: string | undefined; 'kibana.alert.original_event.duration'?: string | undefined; 'kibana.alert.original_event.end'?: string | number | undefined; 'kibana.alert.original_event.hash'?: string | undefined; 'kibana.alert.original_event.reason'?: string | undefined; 'kibana.alert.original_event.reference'?: string | undefined; 'kibana.alert.original_event.risk_score'?: number | undefined; 'kibana.alert.original_event.risk_score_norm'?: number | undefined; 'kibana.alert.original_event.severity'?: string | number | undefined; 'kibana.alert.original_event.start'?: string | number | undefined; 'kibana.alert.original_event.timezone'?: string | undefined; 'kibana.alert.original_event.url'?: string | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.building_block_type'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.immutable'?: string[] | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.rule.timeline_id'?: string[] | undefined; 'kibana.alert.rule.timeline_title'?: string[] | undefined; 'kibana.alert.rule.timestamp_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.threshold_result.cardinality'?: unknown; 'kibana.alert.threshold_result.count'?: string | number | undefined; 'kibana.alert.threshold_result.from'?: string | number | undefined; 'kibana.alert.threshold_result.terms'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.alert.workflow_user'?: string | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.trigger'?: unknown; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" + "{ '@timestamp': string | number; 'kibana.alert.ancestors': { depth: string | number; id: string; index: string; type: string; }[]; 'kibana.alert.depth': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.original_event.action': string; 'kibana.alert.original_event.category': string[]; 'kibana.alert.original_event.created': string | number; 'kibana.alert.original_event.dataset': string; 'kibana.alert.original_event.id': string; 'kibana.alert.original_event.ingested': string | number; 'kibana.alert.original_event.kind': string; 'kibana.alert.original_event.module': string; 'kibana.alert.original_event.original': string; 'kibana.alert.original_event.outcome': string; 'kibana.alert.original_event.provider': string; 'kibana.alert.original_event.sequence': string | number; 'kibana.alert.original_event.type': string[]; 'kibana.alert.original_time': string | number; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.false_positives': string[]; 'kibana.alert.rule.max_signals': (string | number)[]; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.threat.framework': string; 'kibana.alert.rule.threat.tactic.id': string; 'kibana.alert.rule.threat.tactic.name': string; 'kibana.alert.rule.threat.tactic.reference': string; 'kibana.alert.rule.threat.technique.id': string; 'kibana.alert.rule.threat.technique.name': string; 'kibana.alert.rule.threat.technique.reference': string; 'kibana.alert.rule.threat.technique.subtechnique.id': string; 'kibana.alert.rule.threat.technique.subtechnique.name': string; 'kibana.alert.rule.threat.technique.subtechnique.reference': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'ecs.version'?: string | undefined; 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.ancestors.rule'?: string | undefined; 'kibana.alert.building_block_type'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.group.id'?: string | undefined; 'kibana.alert.group.index'?: number | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.new_terms'?: string[] | undefined; 'kibana.alert.original_event.agent_id_status'?: string | undefined; 'kibana.alert.original_event.code'?: string | undefined; 'kibana.alert.original_event.duration'?: string | undefined; 'kibana.alert.original_event.end'?: string | number | undefined; 'kibana.alert.original_event.hash'?: string | undefined; 'kibana.alert.original_event.reason'?: string | undefined; 'kibana.alert.original_event.reference'?: string | undefined; 'kibana.alert.original_event.risk_score'?: number | undefined; 'kibana.alert.original_event.risk_score_norm'?: number | undefined; 'kibana.alert.original_event.severity'?: string | number | undefined; 'kibana.alert.original_event.start'?: string | number | undefined; 'kibana.alert.original_event.timezone'?: string | undefined; 'kibana.alert.original_event.url'?: string | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.building_block_type'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.immutable'?: string[] | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.rule.timeline_id'?: string[] | undefined; 'kibana.alert.rule.timeline_title'?: string[] | undefined; 'kibana.alert.rule.timestamp_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.threshold_result.cardinality'?: unknown; 'kibana.alert.threshold_result.count'?: string | number | undefined; 'kibana.alert.threshold_result.from'?: string | number | undefined; 'kibana.alert.threshold_result.terms'?: { field?: string | undefined; value?: string | undefined; }[] | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.alert.workflow_user'?: string | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; } & {} & { 'ecs.version'?: string | undefined; 'kibana.alert.risk_score'?: number | undefined; 'kibana.alert.rule.author'?: string | undefined; 'kibana.alert.rule.created_at'?: string | number | undefined; 'kibana.alert.rule.created_by'?: string | undefined; 'kibana.alert.rule.description'?: string | undefined; 'kibana.alert.rule.enabled'?: string | undefined; 'kibana.alert.rule.from'?: string | undefined; 'kibana.alert.rule.interval'?: string | undefined; 'kibana.alert.rule.license'?: string | undefined; 'kibana.alert.rule.note'?: string | undefined; 'kibana.alert.rule.references'?: string[] | undefined; 'kibana.alert.rule.rule_id'?: string | undefined; 'kibana.alert.rule.rule_name_override'?: string | undefined; 'kibana.alert.rule.to'?: string | undefined; 'kibana.alert.rule.type'?: string | undefined; 'kibana.alert.rule.updated_at'?: string | number | undefined; 'kibana.alert.rule.updated_by'?: string | undefined; 'kibana.alert.rule.version'?: string | undefined; 'kibana.alert.severity'?: string | undefined; 'kibana.alert.suppression.docs_count'?: string | number | undefined; 'kibana.alert.suppression.end'?: string | number | undefined; 'kibana.alert.suppression.start'?: string | number | undefined; 'kibana.alert.suppression.terms.field'?: string[] | undefined; 'kibana.alert.suppression.terms.value'?: string[] | undefined; 'kibana.alert.system_status'?: string | undefined; 'kibana.alert.workflow_reason'?: string | undefined; 'kibana.alert.workflow_user'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/security_schema.ts", "deprecated": false, @@ -412,7 +420,7 @@ "label": "StackAlert", "description": [], "signature": [ - "{} & { 'kibana.alert.evaluation.conditions'?: string | undefined; 'kibana.alert.evaluation.value'?: string | undefined; 'kibana.alert.title'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" + "{} & { 'kibana.alert.evaluation.conditions'?: string | undefined; 'kibana.alert.evaluation.value'?: string | undefined; 'kibana.alert.title'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts", "deprecated": false, @@ -429,7 +437,15 @@ "label": "alertFieldMap", "description": [], "signature": [ - "{ readonly \"kibana.alert.action_group\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.case_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.duration.us\": { readonly type: \"long\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.end\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping_history\": { readonly type: \"boolean\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.maintenance_window_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.instance.id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.last_detected\": { readonly type: \"date\"; readonly required: false; readonly array: false; }; readonly \"kibana.alert.reason\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.category\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.consumer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.execution.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.name\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.producer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.revision\": { readonly type: \"long\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.rule.rule_type_id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.status\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"event.action\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"event.kind\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.space_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: true; }; readonly tags: { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"@timestamp\": { readonly type: \"date\"; readonly required: true; readonly array: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }" + "{ readonly \"kibana.alert.action_group\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.case_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.duration.us\": { readonly type: \"long\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.end\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping\": { readonly type: \"boolean\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.flapping_history\": { readonly type: \"boolean\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.maintenance_window_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.instance.id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.last_detected\": { readonly type: \"date\"; readonly required: false; readonly array: false; }; readonly \"kibana.alert.reason\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; readonly multi_fields: ", + { + "pluginId": "@kbn/alerts-as-data-utils", + "scope": "common", + "docId": "kibKbnAlertsAsDataUtilsPluginApi", + "section": "def-common.MultiField", + "text": "MultiField" + }, + "[]; }; readonly \"kibana.alert.rule.category\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.consumer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.execution.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.rule.name\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.parameters\": { readonly array: false; readonly type: \"flattened\"; readonly ignore_above: 4096; readonly required: false; }; readonly \"kibana.alert.rule.producer\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.revision\": { readonly type: \"long\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.rule.rule_type_id\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.rule.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.start\": { readonly type: \"date\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.status\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.time_range\": { readonly type: \"date_range\"; readonly format: \"epoch_millis||strict_date_optional_time\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.url\": { readonly type: \"keyword\"; readonly array: false; readonly index: false; readonly required: false; readonly ignore_above: 2048; }; readonly \"kibana.alert.uuid\": { readonly type: \"keyword\"; readonly array: false; readonly required: true; }; readonly \"kibana.alert.workflow_status\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.alert.workflow_tags\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"kibana.alert.workflow_assignee_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"event.action\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"event.kind\": { readonly type: \"keyword\"; readonly array: false; readonly required: false; }; readonly \"kibana.space_ids\": { readonly type: \"keyword\"; readonly array: true; readonly required: true; }; readonly tags: { readonly type: \"keyword\"; readonly array: true; readonly required: false; }; readonly \"@timestamp\": { readonly type: \"date\"; readonly required: true; readonly array: false; }; readonly \"kibana.version\": { readonly type: \"version\"; readonly array: false; readonly required: false; }; }" ], "path": "packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts", "deprecated": false, diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 14d1758ac4e2..21418fa381dc 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index fe156ca3268c..34511c4a074e 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 41da2e03a3d1..6800d7cb3212 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.devdocs.json b/api_docs/kbn_analytics_client.devdocs.json index 49f322df02d0..d695962d56d1 100644 --- a/api_docs/kbn_analytics_client.devdocs.json +++ b/api_docs/kbn_analytics_client.devdocs.json @@ -718,14 +718,6 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/analytics/analytics_service.ts" }, - { - "plugin": "@kbn/subscription-tracking", - "path": "packages/kbn-subscription-tracking/src/use_go_to_subscription.ts" - }, - { - "plugin": "@kbn/subscription-tracking", - "path": "packages/kbn-subscription-tracking/src/use_impression.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" @@ -796,15 +788,15 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" }, { "plugin": "securitySolution", @@ -872,19 +864,19 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" }, { "plugin": "@kbn/core-analytics-browser-mocks", @@ -1360,6 +1352,10 @@ "deprecated": false, "trackAdoption": true, "references": [ + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" + }, { "plugin": "@kbn/core-application-browser-internal", "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.ts" @@ -1392,10 +1388,6 @@ "plugin": "@kbn/core-analytics-browser-internal", "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" }, - { - "plugin": "@kbn/core-execution-context-browser-internal", - "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" - }, { "plugin": "@kbn/core-chrome-browser-internal", "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.ts" diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 05b22ea25bd4..83b5a6c96f26 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index f1cf88e92bba..21d1bf51067e 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 409d8363c898..897ca49e5b8a 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 92ee042360f6..917fe87fc205 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 609bfbb645ca..7c1581f2b0d2 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.devdocs.json b/api_docs/kbn_analytics_shippers_fullstory.devdocs.json index 7a55836c7d02..5878e65af7ef 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.devdocs.json +++ b/api_docs/kbn_analytics_shippers_fullstory.devdocs.json @@ -288,7 +288,7 @@ "tags": [], "label": "shutdown", "description": [ - "\nShuts down the shipper.\nIt doesn't really do anything inside because this shipper doesn't hold any internal queues." + "\nShuts down the shipper." ], "signature": [ "() => void" @@ -350,6 +350,20 @@ "path": "packages/analytics/shippers/fullstory/src/fullstory_shipper.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/analytics-shippers-fullstory", + "id": "def-common.FullStoryShipperConfig.pageVarsDebounceTimeMs", + "type": "number", + "tags": [], + "label": "pageVarsDebounceTimeMs", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/analytics/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index c0222701054b..286e6fae32b5 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 21 | 0 | 0 | 0 | +| 22 | 0 | 1 | 0 | ## Common diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 73674f838d05..6862b45e3d44 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index d6f27633bf48..b06286f034b9 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.devdocs.json b/api_docs/kbn_apm_synthtrace.devdocs.json index 721b44855b3c..c591fc9fd253 100644 --- a/api_docs/kbn_apm_synthtrace.devdocs.json +++ b/api_docs/kbn_apm_synthtrace.devdocs.json @@ -430,6 +430,77 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.LogsSynthtraceEsClient", + "type": "Class", + "tags": [], + "label": "LogsSynthtraceEsClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/apm-synthtrace", + "scope": "server", + "docId": "kibKbnApmSynthtracePluginApi", + "section": "def-server.LogsSynthtraceEsClient", + "text": "LogsSynthtraceEsClient" + }, + " extends ", + "SynthtraceEsClient", + "<", + { + "pluginId": "@kbn/apm-synthtrace-client", + "scope": "common", + "docId": "kibKbnApmSynthtraceClientPluginApi", + "section": "def-common.LogDocument", + "text": "LogDocument" + }, + ">" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/logs/logs_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.LogsSynthtraceEsClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/logs/logs_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.LogsSynthtraceEsClient.Unnamed.$1", + "type": "CompoundType", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ client: ", + "default", + "; logger: ", + "Logger", + "; } & ", + "LogsSynthtraceEsClientOptions" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/logs/logs_synthtrace_es_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/apm-synthtrace", "id": "def-server.MonitoringSynthtraceEsClient", diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 8a707c835f0f..91001dbdcf6f 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 31 | 0 | 31 | 7 | +| 34 | 0 | 34 | 8 | ## Server diff --git a/api_docs/kbn_apm_synthtrace_client.devdocs.json b/api_docs/kbn_apm_synthtrace_client.devdocs.json index fed87d820592..c3d0a4f306d8 100644 --- a/api_docs/kbn_apm_synthtrace_client.devdocs.json +++ b/api_docs/kbn_apm_synthtrace_client.devdocs.json @@ -723,6 +723,62 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.Instance.crash", + "type": "Function", + "tags": [], + "label": "crash", + "description": [], + "signature": [ + "({ message, type }: { message: string; type?: string | undefined; }) => ", + "ApmError" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.Instance.crash.$1", + "type": "Object", + "tags": [], + "label": "{ message, type }", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.Instance.crash.$1.message", + "type": "string", + "tags": [], + "label": "message", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.Instance.crash.$1.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.Instance.error", @@ -2542,6 +2598,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.LogDocument", + "type": "Type", + "tags": [], + "label": "LogDocument", + "description": [], + "signature": [ + "{ '@timestamp'?: number | undefined; } & Partial<{ 'input.type': string; 'log.file.path'?: string | undefined; 'service.name'?: string | undefined; 'data_stream.namespace': string; 'data_stream.type': string; 'data_stream.dataset': string; message?: string | undefined; 'event.dataset': string; 'log.level'?: string | undefined; 'host.name'?: string | undefined; 'trace.id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.instance.id'?: string | undefined; }>" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.MonitoringDocument", @@ -2866,6 +2937,36 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.log", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.log.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => Log" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.monitoring", diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 312a88198bc4..b53f9c57870c 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 181 | 0 | 181 | 27 | +| 188 | 0 | 188 | 27 | ## Common diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 7af7f1cef044..2597e6fca314 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index e89aa154d812..82063d8bb591 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.devdocs.json b/api_docs/kbn_calculate_auto.devdocs.json new file mode 100644 index 000000000000..486f642e16b2 --- /dev/null +++ b/api_docs/kbn_calculate_auto.devdocs.json @@ -0,0 +1,168 @@ +{ + "id": "@kbn/calculate-auto", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto", + "type": "Object", + "tags": [], + "label": "calculateAuto", + "description": [], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.near", + "type": "Function", + "tags": [], + "label": "near", + "description": [], + "signature": [ + "(buckets: number, duration: moment.Duration) => moment.Duration | undefined" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.near.$1", + "type": "number", + "tags": [], + "label": "buckets", + "description": [], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.near.$2", + "type": "Object", + "tags": [], + "label": "duration", + "description": [], + "signature": [ + "moment.Duration" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.lessThan", + "type": "Function", + "tags": [], + "label": "lessThan", + "description": [], + "signature": [ + "(buckets: number, duration: moment.Duration) => moment.Duration | undefined" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.lessThan.$1", + "type": "number", + "tags": [], + "label": "buckets", + "description": [], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.lessThan.$2", + "type": "Object", + "tags": [], + "label": "duration", + "description": [], + "signature": [ + "moment.Duration" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.atLeast", + "type": "Function", + "tags": [], + "label": "atLeast", + "description": [], + "signature": [ + "(buckets: number, duration: moment.Duration) => moment.Duration | undefined" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.atLeast.$1", + "type": "number", + "tags": [], + "label": "buckets", + "description": [], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/calculate-auto", + "id": "def-common.calculateAuto.atLeast.$2", + "type": "Object", + "tags": [], + "label": "duration", + "description": [], + "signature": [ + "moment.Duration" + ], + "path": "packages/kbn-calculate-auto/src/calculate_auto.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "initialIsOpen": false + } + ] + } +} \ No newline at end of file diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx new file mode 100644 index 000000000000..474ffea95f4d --- /dev/null +++ b/api_docs/kbn_calculate_auto.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCalculateAutoPluginApi +slug: /kibana-dev-docs/api/kbn-calculate-auto +title: "@kbn/calculate-auto" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/calculate-auto plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] +--- +import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; + + + +Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 10 | 0 | 10 | 0 | + +## Common + +### Objects + + diff --git a/api_docs/kbn_calculate_width_from_char_count.devdocs.json b/api_docs/kbn_calculate_width_from_char_count.devdocs.json new file mode 100644 index 000000000000..fb146897c3e5 --- /dev/null +++ b/api_docs/kbn_calculate_width_from_char_count.devdocs.json @@ -0,0 +1,147 @@ +{ + "id": "@kbn/calculate-width-from-char-count", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromCharCount", + "type": "Function", + "tags": [], + "label": "calculateWidthFromCharCount", + "description": [], + "signature": [ + "(labelLength: number, overridesPanelWidths: Partial<", + "LIMITS", + "> | undefined) => number" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromCharCount.$1", + "type": "number", + "tags": [], + "label": "labelLength", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromCharCount.$2", + "type": "Object", + "tags": [], + "label": "overridesPanelWidths", + "description": [], + "signature": [ + "Partial<", + "LIMITS", + "> | undefined" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromEntries", + "type": "Function", + "tags": [], + "label": "calculateWidthFromEntries", + "description": [], + "signature": [ + "(entries: string[] | Record[], labelKeys: string[] | undefined, overridesPanelWidths: Partial<", + "LIMITS", + "> | undefined) => number" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromEntries.$1", + "type": "CompoundType", + "tags": [], + "label": "entries", + "description": [], + "signature": [ + "string[] | Record[]" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromEntries.$2", + "type": "Array", + "tags": [], + "label": "labelKeys", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/calculate-width-from-char-count", + "id": "def-common.calculateWidthFromEntries.$3", + "type": "Object", + "tags": [], + "label": "overridesPanelWidths", + "description": [], + "signature": [ + "Partial<", + "LIMITS", + "> | undefined" + ], + "path": "packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx new file mode 100644 index 000000000000..6b9679a6ef7c --- /dev/null +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCalculateWidthFromCharCountPluginApi +slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count +title: "@kbn/calculate-width-from-char-count" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/calculate-width-from-char-count plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] +--- +import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; + + + +Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 7 | 0 | 7 | 1 | + +## Common + +### Functions + + diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 5f522e29787b..aacd3edc02bb 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.devdocs.json b/api_docs/kbn_cell_actions.devdocs.json index dcc406e62c1d..ffa6f3f322ab 100644 --- a/api_docs/kbn_cell_actions.devdocs.json +++ b/api_docs/kbn_cell_actions.devdocs.json @@ -1309,36 +1309,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/cell-actions", - "id": "def-common.COPY_CELL_ACTION_TYPE", - "type": "string", - "tags": [], - "label": "COPY_CELL_ACTION_TYPE", - "description": [], - "signature": [ - "\"cellAction-copy\"" - ], - "path": "packages/kbn-cell-actions/src/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/cell-actions", - "id": "def-common.FILTER_CELL_ACTION_TYPE", - "type": "string", - "tags": [], - "label": "FILTER_CELL_ACTION_TYPE", - "description": [], - "signature": [ - "\"cellAction-filter\"" - ], - "path": "packages/kbn-cell-actions/src/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/cell-actions", "id": "def-common.UseDataGridColumnsCellActions", diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 3fa31abc0ff2..466a30ce182f 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-explore](https://github.com/orgs/elast | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 62 | 1 | 44 | 3 | +| 60 | 1 | 42 | 3 | ## Common diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 2af9ff7332b8..146249122e5b 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 3eeaf3cd311c..cf08aa876dea 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 7462733fc884..5fd9b4eb4164 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 3de480ed2195..999f34e02150 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 04e7240b39f8..356c8c8639d2 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 106c7c3e03f4..96a68ce7e01d 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 4acc329f7b74..11f2ad00fdd4 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index b278289fb313..aeff02c815da 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 8a9bde089c70..78de00822204 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.devdocs.json b/api_docs/kbn_config_mocks.devdocs.json index 29e17d650004..c470bc5513b2 100644 --- a/api_docs/kbn_config_mocks.devdocs.json +++ b/api_docs/kbn_config_mocks.devdocs.json @@ -310,7 +310,7 @@ }, "[]][], [], unknown>; atPath: jest.MockInstance<", "Observable", - ", [path: ", + ", [", { "pluginId": "@kbn/config", "scope": "common", @@ -318,7 +318,7 @@ "section": "def-common.ConfigPath", "text": "ConfigPath" }, - "], unknown>; atPathSync: jest.MockInstance; atPathSync: jest.MockInstance; }> | undefined>; attributes: ", + "; statusCode: number; }> | undefined>; attributes: ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -4021,7 +4021,7 @@ "section": "def-common.Type", "text": "Type" }, - "; }> | undefined; namespaces?: string[] | undefined; createdAt?: string | undefined; updatedAt?: string | undefined; version?: string | undefined; originId?: string | undefined; } & { type: string; id: string; references: Readonly<{ name?: string | undefined; } & { type: string; id: string; }>[]; attributes: Readonly<{ [x: string]: any; } & {}>; }> | undefined>" + "; statusCode: number; }> | undefined; namespaces?: string[] | undefined; createdAt?: string | undefined; updatedAt?: string | undefined; version?: string | undefined; originId?: string | undefined; } & { type: string; id: string; references: Readonly<{ name?: string | undefined; } & { type: string; id: string; }>[]; attributes: Readonly<{ [x: string]: any; } & {}>; }> | undefined>" ], "path": "packages/kbn-content-management-utils/src/schema.ts", "deprecated": false, diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 7e84e380d6e1..9916bf6d8461 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index fda7f80ae2ea..335dc3b71f3d 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 96fc078ccc24..c1db889667fe 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 39b7d6ab11ef..96d8972cad4b 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index b71dcc4c4afd..eb04d818c7ff 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index f3658c59f301..7f9cd09d4837 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 1ff31f38bea3..c5292af76310 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index ffdcb671242e..9645aababe89 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index b81dc0db543f..e10155a5c418 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index 728714013ec7..7e7b89839e18 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 5807d0ccae70..1293bcd0faa2 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.devdocs.json b/api_docs/kbn_core_apps_browser_internal.devdocs.json index d8938c10403b..6d8e18656bdf 100644 --- a/api_docs/kbn_core_apps_browser_internal.devdocs.json +++ b/api_docs/kbn_core_apps_browser_internal.devdocs.json @@ -203,18 +203,22 @@ { "parentPluginId": "@kbn/core-apps-browser-internal", "id": "def-common.CoreAppsServiceSetupDeps.http", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "http", "description": [], "signature": [ + "Omit<", { "pluginId": "@kbn/core-http-browser", "scope": "common", "docId": "kibKbnCoreHttpBrowserPluginApi", "section": "def-common.HttpSetup", "text": "HttpSetup" - } + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" ], "path": "packages/core/apps/core-apps-browser-internal/src/core_app.ts", "deprecated": false, @@ -305,18 +309,22 @@ { "parentPluginId": "@kbn/core-apps-browser-internal", "id": "def-common.CoreAppsServiceStartDeps.http", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "http", "description": [], "signature": [ + "Omit<", { "pluginId": "@kbn/core-http-browser", "scope": "common", "docId": "kibKbnCoreHttpBrowserPluginApi", "section": "def-common.HttpSetup", "text": "HttpSetup" - } + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" ], "path": "packages/core/apps/core-apps-browser-internal/src/core_app.ts", "deprecated": false, diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index dc71b26849f4..52ec1703ee5f 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 0ee803e0744e..1473007d5f3a 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index eaabeb2aba8e..a0f6a03cf86c 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index c3cf9ff8c65f..76856442afdd 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 2025c1859d30..f26d71a8db90 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 46b5ea914831..3c0a74347fc2 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index c2956651186b..57d6ef6fe0b6 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 00dafd0d77c0..3f95820be392 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 5d371de09c55..3fa945f28dfc 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index f1378e9adc70..0c4add8335c9 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 42b48847c1dc..49bf88cf2820 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index 26bfd6ef40f0..84be089b4863 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -1596,15 +1596,12 @@ { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.ChromeProjectNavigationNode.path", - "type": "Array", + "type": "string", "tags": [], "label": "path", "description": [ "Path in the tree of the node" ], - "signature": [ - "string[]" - ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, "trackAdoption": false @@ -1657,12 +1654,30 @@ }, { "parentPluginId": "@kbn/core-chrome-browser", - "id": "def-common.ChromeProjectNavigationNode.isActive", + "id": "def-common.ChromeProjectNavigationNode.renderItem", + "type": "Function", + "tags": [], + "label": "renderItem", + "description": [ + "\nHandler to render the node item with custom JSX. This handler is added to render the `children` of\nthe Navigation.Item component when React components are used to declare the navigation tree." + ], + "signature": [ + "(() => React.ReactNode) | undefined" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeProjectNavigationNode.isElasticInternalLink", "type": "CompoundType", "tags": [], - "label": "isActive", + "label": "isElasticInternalLink", "description": [ - "\nFlag to indicate if the node is currently active." + "\nFlag to indicate if the node is an \"external\" cloud link" ], "signature": [ "boolean | undefined" @@ -3226,7 +3241,7 @@ "label": "EuiThemeSize", "description": [], "signature": [ - "\"m\" | \"s\" | \"xs\" | \"l\" | \"xl\" | \"xxl\"" + "\"m\" | \"s\" | \"l\" | \"xs\" | \"xl\" | \"xxl\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 8db90e89076f..1fb6548873b6 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 165 | 0 | 70 | 0 | +| 166 | 0 | 70 | 0 | ## Common diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 8218a43de3ef..c4cca5d2d65e 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 9ee0774c8ef8..20fdad8baaef 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 5f619525c811..7e760dca6e9a 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 8e2b103fd6d0..ef878a985ac1 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 92a3b393312a..b4b48a6de5af 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index 98d7ccc849ff..18764df0878c 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 6d596de7ccd1..1385d258e096 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index cd145170012d..2ba7351c9954 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index b3c56d63cce1..96db32a2b5ed 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 1c85a8bf3ba7..8a56282b62ff 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.devdocs.json b/api_docs/kbn_core_deprecations_browser_internal.devdocs.json index 57e6318b3165..0e0e8b0e1498 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.devdocs.json +++ b/api_docs/kbn_core_deprecations_browser_internal.devdocs.json @@ -75,11 +75,11 @@ "signature": [ "({ http }: { http: ", { - "pluginId": "@kbn/core-http-browser", + "pluginId": "@kbn/core-http-browser-internal", "scope": "common", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-common.HttpSetup", - "text": "HttpSetup" + "docId": "kibKbnCoreHttpBrowserInternalPluginApi", + "section": "def-common.InternalHttpStart", + "text": "InternalHttpStart" }, "; }) => ", { @@ -108,18 +108,22 @@ { "parentPluginId": "@kbn/core-deprecations-browser-internal", "id": "def-common.DeprecationsService.start.$1.http", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "http", "description": [], "signature": [ + "Omit<", { "pluginId": "@kbn/core-http-browser", "scope": "common", "docId": "kibKbnCoreHttpBrowserPluginApi", "section": "def-common.HttpSetup", "text": "HttpSetup" - } + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" ], "path": "packages/core/deprecations/core-deprecations-browser-internal/src/deprecations_service.ts", "deprecated": false, diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index bb1e47e81995..5180546efc52 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index 5b7ed830d6a5..8718d916c983 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 1516f640f69d..0b729f55e511 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index 939aa1d4781e..2f34435c2c7f 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index b8ec0277deff..737f6d9dc49d 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 0d897a649adc..315ee3f5cae1 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index bdaaf1d44fcc..8722a8222a0f 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index cdd5e7c326e8..cc76224dab26 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index a2fb261fc8f0..7e0edff8146d 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 729b38e60a5c..5c4e7e7835e2 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index ad7f55b1e5bf..eda119983c01 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 14c49dcb61f0..6ca9e67232c3 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 7ba891710461..a78853de484c 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index cb8834354b9e..de4d6f6cb956 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 8e11f3f668e0..9aa3eee0d27f 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index fd28961e92c3..cee8515c5cc9 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 53dbc7f73645..cd3adbe92e0b 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 0f90f7b33c80..8b086366abb3 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 7b896d781639..3ab40cdffad7 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 825f0f87bd7e..22a1a8fed8b8 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 6e813d506614..a34a4faa4575 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 4645c255a61e..a293461e1cb3 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 8d717516e1ee..4171b6820fb9 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 4cc7ac4de5ed..43fb7c0faf13 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 2b7657a91f4b..512ffa17124a 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 03cd6e56b12a..2474497d581d 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.devdocs.json b/api_docs/kbn_core_http_browser.devdocs.json index 5c9408cb3343..dbd5f96eea8c 100644 --- a/api_docs/kbn_core_http_browser.devdocs.json +++ b/api_docs/kbn_core_http_browser.devdocs.json @@ -1340,6 +1340,28 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-http-browser", + "id": "def-common.HttpSetup.staticAssets", + "type": "Object", + "tags": [], + "label": "staticAssets", + "description": [ + "\nAPIs for creating hrefs to static assets.\nSee {@link IStaticAssets}" + ], + "signature": [ + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + } + ], + "path": "packages/core/http/core-http-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-browser", "id": "def-common.HttpSetup.anonymousPaths", @@ -1868,6 +1890,19 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-http-browser", + "id": "def-common.IBasePath.assetsHrefBase", + "type": "string", + "tags": [], + "label": "assetsHrefBase", + "description": [ + "\nHref (hypertext reference) intended to be used as the base for constructing\nother hrefs to static assets." + ], + "path": "packages/core/http/core-http-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-browser", "id": "def-common.IBasePath.publicBaseUrl", @@ -2153,6 +2188,56 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-http-browser", + "id": "def-common.IStaticAssets", + "type": "Interface", + "tags": [], + "label": "IStaticAssets", + "description": [ + "\nAPIs for creating hrefs to static assets.\n" + ], + "path": "packages/core/http/core-http-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-browser", + "id": "def-common.IStaticAssets.getPluginAssetHref", + "type": "Function", + "tags": [], + "label": "getPluginAssetHref", + "description": [ + "\nGets the full href to the current plugin's asset,\ngiven its path relative to the plugin's `public/assets` folder.\n" + ], + "signature": [ + "(assetPath: string) => string" + ], + "path": "packages/core/http/core-http-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-browser", + "id": "def-common.IStaticAssets.getPluginAssetHref.$1", + "type": "string", + "tags": [], + "label": "assetPath", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/http/core-http-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-http-browser", "id": "def-common.ResponseErrorBody", diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index c6a24b662171..60058d638440 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 111 | 4 | 36 | 0 | +| 116 | 4 | 37 | 0 | ## Common diff --git a/api_docs/kbn_core_http_browser_internal.devdocs.json b/api_docs/kbn_core_http_browser_internal.devdocs.json index 1bc1f355c68f..1d5f1e532d6c 100644 --- a/api_docs/kbn_core_http_browser_internal.devdocs.json +++ b/api_docs/kbn_core_http_browser_internal.devdocs.json @@ -46,6 +46,42 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.serverBasePath", + "type": "string", + "tags": [], + "label": "serverBasePath", + "description": [], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.assetsHrefBase", + "type": "string", + "tags": [], + "label": "assetsHrefBase", + "description": [], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.publicBaseUrl", + "type": "string", + "tags": [], + "label": "publicBaseUrl", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-browser-internal", "id": "def-common.BasePath.Unnamed", @@ -63,47 +99,68 @@ { "parentPluginId": "@kbn/core-http-browser-internal", "id": "def-common.BasePath.Unnamed.$1", - "type": "string", - "tags": [], - "label": "basePath", - "description": [], - "signature": [ - "string" - ], - "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/core-http-browser-internal", - "id": "def-common.BasePath.Unnamed.$2", - "type": "string", + "type": "Object", "tags": [], - "label": "serverBasePath", + "label": "{\n basePath,\n serverBasePath,\n assetsHrefBase,\n publicBaseUrl,\n }", "description": [], - "signature": [ - "string" - ], "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/core-http-browser-internal", - "id": "def-common.BasePath.Unnamed.$3", - "type": "string", - "tags": [], - "label": "publicBaseUrl", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false + "children": [ + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.Unnamed.$1.basePath", + "type": "string", + "tags": [], + "label": "basePath", + "description": [], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.Unnamed.$1.serverBasePath", + "type": "string", + "tags": [], + "label": "serverBasePath", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.Unnamed.$1.assetsHrefBase", + "type": "string", + "tags": [], + "label": "assetsHrefBase", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.BasePath.Unnamed.$1.publicBaseUrl", + "type": "string", + "tags": [], + "label": "publicBaseUrl", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/http/core-http-browser-internal/src/base_path.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "returnComment": [] @@ -195,7 +252,58 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.InternalHttpSetup", + "type": "Type", + "tags": [], + "label": "InternalHttpSetup", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" + ], + "path": "packages/core/http/core-http-browser-internal/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-http-browser-internal", + "id": "def-common.InternalHttpStart", + "type": "Type", + "tags": [], + "label": "InternalHttpStart", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" + ], + "path": "packages/core/http/core-http-browser-internal/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [] } } \ No newline at end of file diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 09c5e377e2b7..40a5bda3dc39 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 10 | 0 | 10 | 1 | +| 17 | 0 | 17 | 2 | ## Common ### Classes +### Consts, variables and types + + diff --git a/api_docs/kbn_core_http_browser_mocks.devdocs.json b/api_docs/kbn_core_http_browser_mocks.devdocs.json index 39526d744321..9829c4677a1b 100644 --- a/api_docs/kbn_core_http_browser_mocks.devdocs.json +++ b/api_docs/kbn_core_http_browser_mocks.devdocs.json @@ -140,6 +140,14 @@ "section": "def-common.IBasePath", "text": "IBasePath" }, + "; staticAssets: ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + }, "; anonymousPaths: ", { "pluginId": "@kbn/core-http-browser", @@ -401,7 +409,7 @@ "label": "createBasePath", "description": [], "signature": [ - "({ publicBaseUrl, serverBasePath, }?: { publicBaseUrl?: string | undefined; serverBasePath?: string | undefined; }) => jest.Mocked<", + "({ publicBaseUrl, serverBasePath, assetsHrefBase, }?: { publicBaseUrl?: string | undefined; serverBasePath?: string | undefined; assetsHrefBase?: string | undefined; }) => jest.Mocked<", { "pluginId": "@kbn/core-http-browser", "scope": "common", @@ -424,7 +432,7 @@ "label": "__0", "description": [], "signature": [ - "{ publicBaseUrl?: string | undefined; serverBasePath?: string | undefined; }" + "{ publicBaseUrl?: string | undefined; serverBasePath?: string | undefined; assetsHrefBase?: string | undefined; }" ], "path": "packages/core/http/core-http-browser-mocks/src/base_path.mock.ts", "deprecated": false, diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 96a2ad090c40..b7f7f4c8f881 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 8d8a41aa64a5..5501d1fbed1c 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index c35ce23823fe..942c09444617 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 4e8df4469890..078d3a60d13b 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index d47c318a0707..19e24f38ad4b 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 6ab812b7ed9a..11583abf59f4 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 2d55704c31c0..c19cf5d0697b 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index d5848e3bb43b..e8d0cb2ada22 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 49d307af713e..4c074c60e331 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index de83f6891154..62154ca25157 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -1829,6 +1829,28 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.HttpServiceSetup.staticAssets", + "type": "Object", + "tags": [], + "label": "staticAssets", + "description": [ + "\nAPIs for creating hrefs to static assets.\nSee {@link IStaticAssets}" + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + } + ], + "path": "packages/core/http/core-http-server/src/http_contract.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-common.HttpServiceSetup.csp", @@ -2009,6 +2031,28 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.HttpServiceStart.staticAssets", + "type": "Object", + "tags": [], + "label": "staticAssets", + "description": [ + "\nAPIs for creating hrefs to static assets.\nSee {@link IStaticAssets}" + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + } + ], + "path": "packages/core/http/core-http-server/src/http_contract.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-common.HttpServiceStart.auth", @@ -3688,6 +3732,10 @@ "plugin": "assetManager", "path": "x-pack/plugins/asset_manager/server/routes/assets/containers.ts" }, + { + "plugin": "assetManager", + "path": "x-pack/plugins/asset_manager/server/routes/assets/pods.ts" + }, { "plugin": "banners", "path": "x-pack/plugins/banners/server/routes/info.ts" @@ -3996,6 +4044,10 @@ "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts" }, + { + "plugin": "enterpriseSearch", + "path": "x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts" + }, { "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/server/routes/enterprise_search/mapping.ts" @@ -5806,6 +5858,10 @@ "plugin": "@kbn/core-ui-settings-server-internal", "path": "packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/set.ts" }, + { + "plugin": "@kbn/core-ui-settings-server-internal", + "path": "packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/validate.ts" + }, { "plugin": "@kbn/core-capabilities-server-internal", "path": "packages/core/capabilities/core-capabilities-server-internal/src/routes/resolve_capabilities.ts" @@ -9639,6 +9695,56 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.IStaticAssets", + "type": "Interface", + "tags": [], + "label": "IStaticAssets", + "description": [ + "\nAPIs for creating hrefs to static assets.\n" + ], + "path": "packages/core/http/core-http-server/src/static_assets.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.IStaticAssets.getPluginAssetHref", + "type": "Function", + "tags": [], + "label": "getPluginAssetHref", + "description": [ + "\nGets the full href to the current plugin's asset,\ngiven its path relative to the plugin's `public/assets` folder.\n" + ], + "signature": [ + "(assetPath: string) => string" + ], + "path": "packages/core/http/core-http-server/src/static_assets.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.IStaticAssets.getPluginAssetHref.$1", + "type": "string", + "tags": [], + "label": "assetPath", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/http/core-http-server/src/static_assets.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-common.KibanaErrorResponseFactory", @@ -13505,43 +13611,59 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/telemetry/telemetry_detection_rules_preview_route.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_alerts_index_exists_route.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts" + "path": "x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts" + "path": "x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/telemetry/telemetry_detection_rules_preview_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_alerts_index_exists_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/status.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/privileges.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts" + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timeline/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/get_timelines/index.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/resolve_timeline/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/get_draft_timelines/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts" }, { "plugin": "securitySolution", @@ -13621,27 +13743,27 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts" + "path": "x-pack/plugins/transform/server/routes/api/audit_messages/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms_nodes.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_nodes/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_all/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_single/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_stats_all/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_stats_single/register_route.ts" }, { "plugin": "uptime", @@ -14016,7 +14138,7 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts" }, { "plugin": "uptime", @@ -14761,14 +14883,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/indices/delete_indices_route.ts" @@ -14799,27 +14913,47 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/init.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/export_timelines/index.ts" }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.ts" + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/draft_timelines/clean_draft_timelines/index.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts" }, { "plugin": "securitySolution", @@ -14871,39 +15005,39 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/field_histograms.ts" + "path": "x-pack/plugins/transform/server/routes/api/field_histograms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_update/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/reauthorize_transforms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/reset_transforms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/transforms_preview/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/start_transforms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/stop_transforms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/delete_transforms/register_route.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" + "path": "x-pack/plugins/transform/server/routes/api/schedule_now_transforms/register_route.ts" }, { "plugin": "controls", @@ -15299,6 +15433,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/delete_index_route.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts" @@ -15309,7 +15447,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts" + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts" }, { "plugin": "synthetics", diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 69ec0d058df7..85ef3b31c2fa 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 449 | 1 | 178 | 0 | +| 454 | 1 | 179 | 0 | ## Common diff --git a/api_docs/kbn_core_http_server_internal.devdocs.json b/api_docs/kbn_core_http_server_internal.devdocs.json index 73de455f5bff..777bf0f988ab 100644 --- a/api_docs/kbn_core_http_server_internal.devdocs.json +++ b/api_docs/kbn_core_http_server_internal.devdocs.json @@ -693,17 +693,9 @@ "label": "setup", "description": [], "signature": [ - "(config: ", - { - "pluginId": "@kbn/core-http-server-internal", - "scope": "common", - "docId": "kibKbnCoreHttpServerInternalPluginApi", - "section": "def-common.HttpConfig", - "text": "HttpConfig" - }, - ", executionContext?: ", - "IExecutionContext", - " | undefined) => Promise<", + "({ config$, executionContext, }: ", + "HttpServerSetupOptions", + ") => Promise<", "HttpServerSetup", ">" ], @@ -716,37 +708,15 @@ "id": "def-common.HttpServer.setup.$1", "type": "Object", "tags": [], - "label": "config", + "label": "{\n config$,\n executionContext,\n }", "description": [], "signature": [ - { - "pluginId": "@kbn/core-http-server-internal", - "scope": "common", - "docId": "kibKbnCoreHttpServerInternalPluginApi", - "section": "def-common.HttpConfig", - "text": "HttpConfig" - } + "HttpServerSetupOptions" ], "path": "packages/core/http/core-http-server-internal/src/http_server.ts", "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "@kbn/core-http-server-internal", - "id": "def-common.HttpServer.setup.$2", - "type": "Object", - "tags": [], - "label": "executionContext", - "description": [], - "signature": [ - "IExecutionContext", - " | undefined" - ], - "path": "packages/core/http/core-http-server-internal/src/http_server.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false } ], "returnComment": [] diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index c73351b576d2..21474a022295 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 59 | 0 | 53 | 7 | +| 58 | 0 | 52 | 9 | ## Common diff --git a/api_docs/kbn_core_http_server_mocks.devdocs.json b/api_docs/kbn_core_http_server_mocks.devdocs.json index 2c0ed686470b..7451177dbb1b 100644 --- a/api_docs/kbn_core_http_server_mocks.devdocs.json +++ b/api_docs/kbn_core_http_server_mocks.devdocs.json @@ -252,6 +252,14 @@ "section": "def-common.ICspConfig", "text": "ICspConfig" }, + "; staticAssets: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + }, "; registerRouteHandlerContext: jest.MockInstance<", { "pluginId": "@kbn/core-http-server", @@ -340,7 +348,7 @@ "section": "def-common.HttpServiceSetup", "text": "HttpServiceSetup" }, - ", \"createRouter\" | \"basePath\"> & { basePath: BasePathMocked; createRouter: jest.MockedFunction<() => ", + ", \"createRouter\" | \"basePath\"> & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked; createRouter: jest.MockedFunction<() => ", { "pluginId": "@kbn/core-http-router-server-mocks", "scope": "common", @@ -371,6 +379,14 @@ "section": "def-common.IBasePath", "text": "IBasePath" }, + "; staticAssets: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.IStaticAssets", + "text": "IStaticAssets" + }, "; auth: ", { "pluginId": "@kbn/core-http-server", @@ -395,7 +411,7 @@ "section": "def-common.HttpServiceStart", "text": "HttpServiceStart" }, - " & { basePath: BasePathMocked; }" + " & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked; }" ], "path": "packages/core/http/core-http-server-mocks/src/http_service.mock.ts", "deprecated": false, @@ -486,7 +502,7 @@ }, ">) => void], unknown>; } & Omit<", "InternalHttpServicePreboot", - ", \"basePath\" | \"staticAssets\"> & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked; }" + ", \"basePath\" | \"staticAssets\"> & { basePath: BasePathMocked; staticAssets: InternalStaticAssetsMocked; }" ], "path": "packages/core/http/core-http-server-mocks/src/http_service.mock.ts", "deprecated": false, @@ -625,7 +641,7 @@ }, ">], unknown>; } & Omit<", "InternalHttpServiceSetup", - ", \"createRouter\" | \"basePath\" | \"auth\" | \"staticAssets\" | \"authRequestHeaders\"> & { auth: AuthMocked; basePath: BasePathMocked; staticAssets: StaticAssetsMocked; createRouter: jest.MockedFunction<(path: string) => ", + ", \"createRouter\" | \"basePath\" | \"auth\" | \"staticAssets\" | \"authRequestHeaders\"> & { auth: AuthMocked; basePath: BasePathMocked; staticAssets: InternalStaticAssetsMocked; createRouter: jest.MockedFunction<(path: string) => ", { "pluginId": "@kbn/core-http-router-server-mocks", "scope": "common", @@ -656,7 +672,9 @@ "label": "InternalHttpServiceStartMock", "description": [], "signature": [ - "{ isListening: jest.MockInstance; basePath: ", + "{ staticAssets: ", + "InternalStaticAssets", + "; isListening: jest.MockInstance; basePath: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -682,7 +700,7 @@ }, ", [], unknown>; } & ", "InternalHttpServiceStart", - " & { basePath: BasePathMocked; }" + " & { basePath: BasePathMocked; staticAssets: InternalStaticAssetsMocked; }" ], "path": "packages/core/http/core-http-server-mocks/src/http_service.mock.ts", "deprecated": false, diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index e70fdddbe69f..d9ea394c66c4 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 9305b77d9d69..7ede0b0ed6f7 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 8e30a9928bc7..e209633d7d06 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index d88e0e3a32c0..5e034e94209f 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 67a0105427b1..b2babcce6ebe 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 27634b6d7d8e..ec8deb475767 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 8e96dd1593f0..b59ac239b833 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index dd835c6f2488..9706b88bb978 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 855e4b70b098..bfde53ea03fc 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 3ff751bc15f5..a1f8fd845e13 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 9a3054fca09e..f42cea2cd6b0 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 35bf496984fd..dcdaadf0585d 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index 698f2f3105d2..d39b04773a34 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index a328d5c73083..d534709fe42b 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index c77747874f4e..e895a0391ea6 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 96261df56bc8..4f809d0889a4 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 1a5bd3676d53..5946eae11e89 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 700a2f044466..dc841c02462e 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 21fffacb7a02..56be27869b36 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 9d50d48dd9b9..eed045e3fe19 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.devdocs.json b/api_docs/kbn_core_metrics_server.devdocs.json index edbaa1a24d19..1d18b5552b80 100644 --- a/api_docs/kbn_core_metrics_server.devdocs.json +++ b/api_docs/kbn_core_metrics_server.devdocs.json @@ -705,6 +705,22 @@ "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-common.OpsOsMetrics.cgroup_memory", + "type": "Object", + "tags": [], + "label": "cgroup_memory", + "description": [ + "memory cgroup metrics, undefined when not running in cgroup v2" + ], + "signature": [ + "{ current_in_bytes: number; swap_current_in_bytes: number; } | undefined" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -745,7 +761,7 @@ "process memory usage" ], "signature": [ - "{ heap: { total_in_bytes: number; used_in_bytes: number; size_limit: number; }; resident_set_size_in_bytes: number; }" + "{ heap: { total_in_bytes: number; used_in_bytes: number; size_limit: number; }; resident_set_size_in_bytes: number; external_in_bytes: number; array_buffers_in_bytes: number; }" ], "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", "deprecated": false, diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 90d40160bdd6..5375fda7633d 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 55 | 0 | 8 | 0 | +| 56 | 0 | 8 | 0 | ## Common diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index fcb251894033..049cc6b2e881 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 648476b471d7..95646579652c 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index d64bea6e8ceb..0f15cf9c026c 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 64fb1e71ad52..5f46c7fbe3ef 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 70776e7f0171..82caf7d87800 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 326e2fd1a347..67d8b9a7b763 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 4c274ad81587..de1d4131c7ba 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index f224b2f42c61..3d22504a6138 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 295f91227722..e84167e6d54a 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 970addfac64d..11e170148f04 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index a46d760d3698..5ffd06746cfe 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 74169fb6b52f..7b40114216d2 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 0ac7db1caa86..d5390443bebd 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 0f12ec12987f..fbfa5b59b5a9 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 3cc884220fde..b9c34930deb1 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index ba98fb28ee93..b910004c98df 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 8dd6ec1f0070..b3c605341739 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 2e161fa2396e..f4caa0c664f9 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 76b4ce950ac3..a7a0ce0069c5 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 4da0a4add6f7..3abef0e0d562 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 611f8deaddb6..f921c5298453 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 24702fd09bd5..dfe95d0558d6 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index be52019337cf..5dc7a09960b9 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 30381c53066b..918fa69414ee 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index b8d9b047e9fc..0211581495e6 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.devdocs.json b/api_docs/kbn_core_saved_objects_api_server.devdocs.json index 143bed79f4d0..51dfc7d58878 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -3901,6 +3901,22 @@ "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-api-server", + "id": "def-common.SavedObjectsBulkUpdateOptions.migrationVersionCompatibility", + "type": "CompoundType", + "tags": [], + "label": "migrationVersionCompatibility", + "description": [ + "{@link SavedObjectsRawDocParseOptions.migrationVersionCompatibility}" + ], + "signature": [ + "\"raw\" | \"compatible\" | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -5063,7 +5079,7 @@ "tags": [], "label": "bulkUpdate", "description": [ - "\nBulk Updates multiple SavedObject at once\n" + "\nBulk Updates multiple SavedObject at once\n\nThe savedObjects `bulkUpdate` API will update documents client-side and then reindex the updated documents.\nThese update operations are done in-memory, and cause memory constraint issues when\nupdating many objects with large `json` blobs stored in some fields. As such, we recommend against using\n`bulkUpdate` for savedObjects that:\n- use arrays (as these tend to be large objects)\n- store large `json` blobs in some fields\n" ], "signature": [ "(objects: ", diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 80903bbc0c71..d2c55604e908 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 352 | 1 | 5 | 2 | +| 353 | 1 | 5 | 2 | ## Common diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 735f71ed7095..f5d304891fc3 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json index bfdf4b5b8d48..ff317f16d9a6 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json +++ b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json @@ -652,6 +652,99 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getFieldListFromTypeMapping", + "type": "Function", + "tags": [], + "label": "getFieldListFromTypeMapping", + "description": [ + "\nReturn the list of fields present in the provided mappings.\nNote that fields only containing properties are still considered fields by this function.\n" + ], + "signature": [ + "(typeMappings: ", + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsTypeMappingDefinition", + "text": "SavedObjectsTypeMappingDefinition" + }, + ") => string[]" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getFieldListFromTypeMapping.$1", + "type": "Object", + "tags": [], + "label": "typeMappings", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsTypeMappingDefinition", + "text": "SavedObjectsTypeMappingDefinition" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getFieldListMapFromMappingDefinitions", + "type": "Function", + "tags": [], + "label": "getFieldListMapFromMappingDefinitions", + "description": [ + "\nReturn the list of fields present in each individual type mappings present in the definition." + ], + "signature": [ + "(mappings: ", + "SavedObjectsTypeMappingDefinitions", + ") => ", + { + "pluginId": "@kbn/core-saved-objects-base-server-internal", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsBaseServerInternalPluginApi", + "section": "def-common.FieldListMap", + "text": "FieldListMap" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getFieldListMapFromMappingDefinitions.$1", + "type": "Object", + "tags": [], + "label": "mappings", + "description": [], + "signature": [ + "SavedObjectsTypeMappingDefinitions" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-saved-objects-base-server-internal", "id": "def-common.getIndexForType", @@ -1072,6 +1165,111 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getVersionAddedFields", + "type": "Function", + "tags": [], + "label": "getVersionAddedFields", + "description": [ + "\nReturn the list of fields, sorted, that were introduced in the given version." + ], + "signature": [ + "(version: ", + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsModelVersion", + "text": "SavedObjectsModelVersion" + }, + ") => string[]" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getVersionAddedFields.$1", + "type": "Object", + "tags": [], + "label": "version", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsModelVersion", + "text": "SavedObjectsModelVersion" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getVersionAddedMappings", + "type": "Function", + "tags": [], + "label": "getVersionAddedMappings", + "description": [ + "\nReturn the mappings that were introduced in the given version.\nIf multiple 'mappings_addition' changes are present for the version,\nthey will be deep-merged." + ], + "signature": [ + "(version: ", + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsModelVersion", + "text": "SavedObjectsModelVersion" + }, + ") => ", + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsMappingProperties", + "text": "SavedObjectsMappingProperties" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.getVersionAddedMappings.$1", + "type": "Object", + "tags": [], + "label": "version", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsServerPluginApi", + "section": "def-common.SavedObjectsModelVersion", + "text": "SavedObjectsModelVersion" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-saved-objects-base-server-internal", "id": "def-common.getVirtualVersionMap", @@ -1512,6 +1710,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-common.FieldListMap", + "type": "Type", + "tags": [], + "label": "FieldListMap", + "description": [], + "signature": [ + "{ [x: string]: string[]; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-saved-objects-base-server-internal", "id": "def-common.globalSwitchToModelVersionAt", diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index 5a4cfdbcabdf..1afb9cba18af 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 89 | 0 | 61 | 10 | +| 98 | 0 | 66 | 10 | ## Common diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index edb1dda31a9f..d2bf6f3d7a6e 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 3c2235d8b525..1917df479b6d 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.devdocs.json b/api_docs/kbn_core_saved_objects_browser_internal.devdocs.json index 1510b6de8527..59b17ac34b72 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.devdocs.json +++ b/api_docs/kbn_core_saved_objects_browser_internal.devdocs.json @@ -99,11 +99,11 @@ "signature": [ "({ http }: { http: ", { - "pluginId": "@kbn/core-http-browser", + "pluginId": "@kbn/core-http-browser-internal", "scope": "common", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-common.HttpSetup", - "text": "HttpSetup" + "docId": "kibKbnCoreHttpBrowserInternalPluginApi", + "section": "def-common.InternalHttpStart", + "text": "InternalHttpStart" }, "; }) => Promise<", { @@ -133,18 +133,22 @@ { "parentPluginId": "@kbn/core-saved-objects-browser-internal", "id": "def-common.SavedObjectsService.start.$1.http", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "http", "description": [], "signature": [ + "Omit<", { "pluginId": "@kbn/core-http-browser", "scope": "common", "docId": "kibKbnCoreHttpBrowserPluginApi", "section": "def-common.HttpSetup", "text": "HttpSetup" - } + }, + ", \"staticAssets\"> & { staticAssets: ", + "InternalStaticAssets", + "; }" ], "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_service.ts", "deprecated": false, diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index e92be68f2c60..8271e12a3f3e 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 444409eceaf9..1d619a3d39bf 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 9c58104676a7..4ee7b263fb32 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 17fa146e01bf..ad6040ea177e 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index cb1c421f7336..3967e93445e7 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index c6a2df2bdfb8..d5c0f8bd54d1 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index ba4476ba7697..165afecebc55 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 00ce80eec7f7..28d148f80234 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 094fb5682e9e..1ed72850d864 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 4b3b2779f911..9d30e9ea83c6 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index c564ca08a048..2ff16c7dfd4e 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 6721891c631a..ff3ab917921f 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index af18c864dafd..9d8fd78dd60d 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 25887ac55df6..600a3c04d866 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index abd13b6e9436..aaace8064005 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 93a8f6300d55..dade55c2d86d 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 7fd05afebd09..69595f1d9718 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.devdocs.json b/api_docs/kbn_core_test_helpers_http_setup_browser.devdocs.json index 5d94094ad202..745890bc7512 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.devdocs.json +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.devdocs.json @@ -49,11 +49,11 @@ }, ">; http: ", { - "pluginId": "@kbn/core-http-browser", + "pluginId": "@kbn/core-http-browser-internal", "scope": "common", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-common.HttpSetup", - "text": "HttpSetup" + "docId": "kibKbnCoreHttpBrowserInternalPluginApi", + "section": "def-common.InternalHttpSetup", + "text": "InternalHttpSetup" }, "; }" ], @@ -123,7 +123,7 @@ "label": "injectedMetadata", "description": [], "signature": [ - "{ getBasePath: jest.MockInstance; getServerBasePath: jest.MockInstance; getPublicBaseUrl: jest.MockInstance; getKibanaBuildNumber: jest.MockInstance; getKibanaBranch: jest.MockInstance; getKibanaVersion: jest.MockInstance; getCspConfig: jest.MockInstance<{ warnLegacyBrowsers: boolean; }, [], unknown>; getExternalUrlConfig: jest.MockInstance<{ policy: ", + "{ getBasePath: jest.MockInstance; getServerBasePath: jest.MockInstance; getPublicBaseUrl: jest.MockInstance; getAssetsHrefBase: jest.MockInstance; getKibanaBuildNumber: jest.MockInstance; getKibanaBranch: jest.MockInstance; getKibanaVersion: jest.MockInstance; getCspConfig: jest.MockInstance<{ warnLegacyBrowsers: boolean; }, [], unknown>; getExternalUrlConfig: jest.MockInstance<{ policy: ", "InjectedMetadataExternalUrlPolicy", "[]; }, [], unknown>; getTheme: jest.MockInstance<{ darkMode: boolean; version: \"v8\"; }, [], unknown>; getElasticsearchInfo: jest.MockInstance<", "InjectedMetadataClusterInfo", diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 4b3175e69134..0218063d79b3 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index c0efbacdd0bb..4d48cc42037f 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index fcfabc7d2b9d..78143beb68cd 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 0761d79e0d95..4e3f7feb7474 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 8743138f0298..35e3a33be8d9 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 444d0a84a8df..36241f3d1263 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index adc8eb15e68e..df9139092a68 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.devdocs.json b/api_docs/kbn_core_ui_settings_browser.devdocs.json index 4804d0fac6da..db4b4e223d17 100644 --- a/api_docs/kbn_core_ui_settings_browser.devdocs.json +++ b/api_docs/kbn_core_ui_settings_browser.devdocs.json @@ -425,6 +425,57 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-ui-settings-browser", + "id": "def-common.IUiSettingsClient.validateValue", + "type": "Function", + "tags": [], + "label": "validateValue", + "description": [ + "\nValidates a uiSettings value and returns a ValueValidation object." + ], + "signature": [ + "(key: string, value: any) => Promise<", + "ValueValidation", + ">" + ], + "path": "packages/core/ui-settings/core-ui-settings-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-ui-settings-browser", + "id": "def-common.IUiSettingsClient.validateValue.$1", + "type": "string", + "tags": [], + "label": "key", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/ui-settings/core-ui-settings-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-ui-settings-browser", + "id": "def-common.IUiSettingsClient.validateValue.$2", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/ui-settings/core-ui-settings-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index fc5b8e1a44ae..ad160742896c 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 30 | 1 | 18 | 0 | +| 33 | 2 | 20 | 1 | ## Common diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 4717d5b705d3..ddb62a195b42 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 0132060ef647..f98fcfb75177 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 051290535f75..3e8ba6a3f29f 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.devdocs.json b/api_docs/kbn_core_ui_settings_server.devdocs.json index 9db8a89dd3d1..37732beadfc9 100644 --- a/api_docs/kbn_core_ui_settings_server.devdocs.json +++ b/api_docs/kbn_core_ui_settings_server.devdocs.json @@ -355,6 +355,55 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-ui-settings-server", + "id": "def-common.IUiSettingsClient.validate", + "type": "Function", + "tags": [], + "label": "validate", + "description": [ + "\nValidates the uiSettings value and returns a ValueValidation object." + ], + "signature": [ + "(key: string, value: unknown) => Promise" + ], + "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-ui-settings-server", + "id": "def-common.IUiSettingsClient.validate.$1", + "type": "string", + "tags": [], + "label": "key", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-ui-settings-server", + "id": "def-common.IUiSettingsClient.validate.$2", + "type": "Unknown", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index b226da910d71..1985861f971c 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 34 | 1 | 17 | 0 | +| 37 | 1 | 19 | 0 | ## Common diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index a07743c906bb..18201db74a55 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index 9d05216df57f..cb9969311169 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index a7250b634820..0ebdad712141 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 776bb1b3e2a7..d2690c744b30 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 8382c5d6b080..c781143000d9 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index 6c39b8b24267..7098c8191e12 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index c68e453848d8..352614d7023f 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index 09c71e11eb18..d923a1d5f09c 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 8fd8b457f272..b56a887e4720 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index b741fd434c65..7cd9451f9b32 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.devdocs.json b/api_docs/kbn_custom_icons.devdocs.json new file mode 100644 index 000000000000..7bf78ecff15a --- /dev/null +++ b/api_docs/kbn_custom_icons.devdocs.json @@ -0,0 +1,369 @@ +{ + "id": "@kbn/custom-icons", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.AgentIcon", + "type": "Function", + "tags": [], + "label": "AgentIcon", + "description": [], + "signature": [ + "({ agentName, size = 'l', ...props }: ", + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.AgentIconProps", + "text": "AgentIconProps" + }, + ") => JSX.Element" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.AgentIcon.$1", + "type": "Object", + "tags": [], + "label": "{ agentName, size = 'l', ...props }", + "description": [], + "signature": [ + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.AgentIconProps", + "text": "AgentIconProps" + } + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.CloudProviderIcon", + "type": "Function", + "tags": [], + "label": "CloudProviderIcon", + "description": [], + "signature": [ + "({ cloudProvider, ...props }: ", + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.CloudProviderIconProps", + "text": "CloudProviderIconProps" + }, + ") => JSX.Element" + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.CloudProviderIcon.$1", + "type": "Object", + "tags": [], + "label": "{ cloudProvider, ...props }", + "description": [], + "signature": [ + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.CloudProviderIconProps", + "text": "CloudProviderIconProps" + } + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getAgentIcon", + "type": "Function", + "tags": [], + "label": "getAgentIcon", + "description": [], + "signature": [ + "(agentName: string | undefined, isDarkMode: boolean) => string" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getAgentIcon.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getAgentIcon.$2", + "type": "boolean", + "tags": [], + "label": "isDarkMode", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getCloudProviderIcon", + "type": "Function", + "tags": [], + "label": "getCloudProviderIcon", + "description": [], + "signature": [ + "(cloudProvider: ", + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.CloudProvider", + "text": "CloudProvider" + }, + ") => \"cloudSunny\" | \"logoAWS\" | \"logoAzure\" | \"logoGCP\"" + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getCloudProviderIcon.$1", + "type": "CompoundType", + "tags": [], + "label": "cloudProvider", + "description": [], + "signature": [ + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.CloudProvider", + "text": "CloudProvider" + } + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getServerlessIcon", + "type": "Function", + "tags": [], + "label": "getServerlessIcon", + "description": [], + "signature": [ + "(serverlessType: ", + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.ServerlessType", + "text": "ServerlessType" + }, + " | undefined) => string" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/get_serverless_icon.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.getServerlessIcon.$1", + "type": "CompoundType", + "tags": [], + "label": "serverlessType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.ServerlessType", + "text": "ServerlessType" + }, + " | undefined" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/get_serverless_icon.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.AgentIconProps", + "type": "Interface", + "tags": [], + "label": "AgentIconProps", + "description": [], + "signature": [ + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.AgentIconProps", + "text": "AgentIconProps" + }, + " extends Omit<", + "EuiIconProps", + ", \"type\">" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.AgentIconProps.agentName", + "type": "CompoundType", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.AgentName", + "text": "AgentName" + }, + " | undefined" + ], + "path": "packages/kbn-custom-icons/src/components/agent_icon/index.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.CloudProviderIconProps", + "type": "Interface", + "tags": [], + "label": "CloudProviderIconProps", + "description": [], + "signature": [ + { + "pluginId": "@kbn/custom-icons", + "scope": "common", + "docId": "kibKbnCustomIconsPluginApi", + "section": "def-common.CloudProviderIconProps", + "text": "CloudProviderIconProps" + }, + " extends Omit<", + "EuiIconProps", + ", \"type\">" + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.CloudProviderIconProps.cloudProvider", + "type": "CompoundType", + "tags": [], + "label": "cloudProvider", + "description": [], + "signature": [ + "\"aws\" | \"azure\" | \"gcp\" | \"unknownProvider\" | null | undefined" + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/custom-icons", + "id": "def-common.CloudProvider", + "type": "Type", + "tags": [], + "label": "CloudProvider", + "description": [], + "signature": [ + "\"aws\" | \"azure\" | \"gcp\" | \"unknownProvider\" | null | undefined" + ], + "path": "packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx new file mode 100644 index 000000000000..cc890c817d87 --- /dev/null +++ b/api_docs/kbn_custom_icons.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCustomIconsPluginApi +slug: /kibana-dev-docs/api/kbn-custom-icons +title: "@kbn/custom-icons" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/custom-icons plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] +--- +import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; + + + +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 16 | 0 | 16 | 0 | + +## Common + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 67837181e54f..d08e34e6934b 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 8e67ef43452c..38c76b3dcb51 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index e95124d51e3d..ae3226c5b573 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 8e4ae3ecdfd0..eeba1fddd825 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 882b9fda4cf3..9e012d56b2d7 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index 4adaa6eeec30..885aba392375 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index c575cbfbda21..3893cf9d575e 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.devdocs.json b/api_docs/kbn_deeplinks_ml.devdocs.json index 8ba46143a88f..15449e28dcf5 100644 --- a/api_docs/kbn_deeplinks_ml.devdocs.json +++ b/api_docs/kbn_deeplinks_ml.devdocs.json @@ -45,7 +45,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"ml\" | \"ml:nodes\" | \"ml:notifications\" | \"ml:overview\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:singleMetricViewer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:logRateAnalysis\" | \"ml:logPatternAnalysis\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:memoryUsage\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\"" + "\"ml\" | \"ml:nodes\" | \"ml:notifications\" | \"ml:overview\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:memoryUsage\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:singleMetricViewer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:logRateAnalysis\" | \"ml:logPatternAnalysis\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\"" ], "path": "packages/deeplinks/ml/deep_links.ts", "deprecated": false, @@ -60,7 +60,7 @@ "label": "LinkId", "description": [], "signature": [ - "\"nodes\" | \"notifications\" | \"overview\" | \"settings\" | \"dataVisualizer\" | \"anomalyDetection\" | \"anomalyExplorer\" | \"singleMetricViewer\" | \"dataDrift\" | \"dataFrameAnalytics\" | \"resultExplorer\" | \"analyticsMap\" | \"aiOps\" | \"logRateAnalysis\" | \"logPatternAnalysis\" | \"changePointDetections\" | \"modelManagement\" | \"nodesOverview\" | \"memoryUsage\" | \"fileUpload\" | \"indexDataVisualizer\" | \"calendarSettings\" | \"filterListsSettings\"" + "\"nodes\" | \"notifications\" | \"overview\" | \"settings\" | \"dataVisualizer\" | \"memoryUsage\" | \"anomalyDetection\" | \"anomalyExplorer\" | \"singleMetricViewer\" | \"dataDrift\" | \"dataFrameAnalytics\" | \"resultExplorer\" | \"analyticsMap\" | \"aiOps\" | \"logRateAnalysis\" | \"logPatternAnalysis\" | \"changePointDetections\" | \"modelManagement\" | \"nodesOverview\" | \"fileUpload\" | \"indexDataVisualizer\" | \"calendarSettings\" | \"filterListsSettings\"" ], "path": "packages/deeplinks/ml/deep_links.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 279a828cbe84..c15c8f967fd1 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 07c06bd01fe2..55facfed51b9 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index bd5117564cbe..8c9fa951b36c 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 1cda3dfdf6cc..ea6871cb3c6c 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 3878c6f84ee5..8fc90f4e8100 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 0e79c5c0b93c..02f3ef7d0172 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 2910fa34db36..d24a30dfa895 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 63b6d26c64f3..9d8a95e4d845 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 3bbf3fa4b50a..e54692037088 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index c8c3a0bbee67..b9065b120376 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index c2796e378be5..2bb69c8bc912 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index c6fd7cf2abb1..187d6ce7aff1 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 4c91d4cbee50..41c974966b0d 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -300,7 +300,7 @@ "label": "enterpriseSearch", "description": [], "signature": [ - "{ readonly aiSearchDoc: string; readonly aiSearchHelp: string; readonly apiKeys: string; readonly behavioralAnalytics: string; readonly behavioralAnalyticsCORS: string; readonly behavioralAnalyticsEvents: string; readonly buildConnector: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsAzureBlobStorage: string; readonly connectorsBox: string; readonly connectorsClients: string; readonly connectorsConfluence: string; readonly connectorsContentExtraction: string; readonly connectorsDropbox: string; readonly connectorsGithub: string; readonly connectorsGoogleCloudStorage: string; readonly connectorsGoogleDrive: string; readonly connectorsGmail: string; readonly connectorsJira: string; readonly connectorsMicrosoftSQL: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsNative: string; readonly connectorsNetworkDrive: string; readonly connectorsOneDrive: string; readonly connectorsOracle: string; readonly connectorsOutlook: string; readonly connectorsPostgreSQL: string; readonly connectorsS3: string; readonly connectorsSalesforce: string; readonly connectorsServiceNow: string; readonly connectorsSharepoint: string; readonly connectorsSharepointOnline: string; readonly connectorsTeams: string; readonly connectorsSlack: string; readonly connectorsZoom: string; readonly crawlerExtractionRules: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly elser: string; readonly engines: string; readonly indexApi: string; readonly ingestionApis: string; readonly ingestPipelines: string; readonly knnSearch: string; readonly knnSearchCombine: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly machineLearningStart: string; readonly mailService: string; readonly mlDocumentEnrichment: string; readonly mlDocumentEnrichmentUpdateMappings: string; readonly searchApplicationsTemplates: string; readonly searchApplicationsSearchApi: string; readonly searchApplications: string; readonly searchApplicationsSearch: string; readonly searchLabs: string; readonly searchLabsRepo: string; readonly searchTemplates: string; readonly start: string; readonly supportedNlpModels: string; readonly syncRules: string; readonly trainedModels: string; readonly textEmbedding: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" + "{ readonly aiSearchDoc: string; readonly aiSearchHelp: string; readonly apiKeys: string; readonly behavioralAnalytics: string; readonly behavioralAnalyticsCORS: string; readonly behavioralAnalyticsEvents: string; readonly buildConnector: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsAzureBlobStorage: string; readonly connectorsBox: string; readonly connectorsClients: string; readonly connectorsConfluence: string; readonly connectorsContentExtraction: string; readonly connectorsDropbox: string; readonly connectorsGithub: string; readonly connectorsGoogleCloudStorage: string; readonly connectorsGoogleDrive: string; readonly connectorsGmail: string; readonly connectorsJira: string; readonly connectorsMicrosoftSQL: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsNative: string; readonly connectorsNetworkDrive: string; readonly connectorsOneDrive: string; readonly connectorsOracle: string; readonly connectorsOutlook: string; readonly connectorsPostgreSQL: string; readonly connectorsS3: string; readonly connectorsSalesforce: string; readonly connectorsServiceNow: string; readonly connectorsSharepoint: string; readonly connectorsSharepointOnline: string; readonly connectorsTeams: string; readonly connectorsSlack: string; readonly connectorsZoom: string; readonly crawlerExtractionRules: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly elser: string; readonly engines: string; readonly indexApi: string; readonly ingestionApis: string; readonly ingestPipelines: string; readonly knnSearch: string; readonly knnSearchCombine: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly machineLearningStart: string; readonly mailService: string; readonly mlDocumentEnrichment: string; readonly searchApplicationsTemplates: string; readonly searchApplicationsSearchApi: string; readonly searchApplications: string; readonly searchApplicationsSearch: string; readonly searchLabs: string; readonly searchLabsRepo: string; readonly searchTemplates: string; readonly start: string; readonly supportedNlpModels: string; readonly syncRules: string; readonly trainedModels: string; readonly textEmbedding: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -546,7 +546,7 @@ "label": "securitySolution", "description": [], "signature": [ - "{ readonly artifactControl: string; readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly endpointArtifacts: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly packageActionTroubleshooting: { es_connection: string; }; readonly threatIntelInt: string; readonly responseActions: string; readonly configureEndpointIntegrationPolicy: string; readonly exceptions: { value_lists: string; }; readonly privileges: string; readonly manageDetectionRules: string; readonly createEsqlRuleType: string; }" + "{ readonly artifactControl: string; readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly endpointArtifacts: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly packageActionTroubleshooting: { es_connection: string; }; readonly threatIntelInt: string; readonly responseActions: string; readonly configureEndpointIntegrationPolicy: string; readonly exceptions: { value_lists: string; }; readonly privileges: string; readonly manageDetectionRules: string; readonly createEsqlRuleType: string; readonly entityAnalytics: { readonly riskScorePrerequisites: string; readonly hostRiskScore: string; readonly userRiskScore: string; readonly entityRiskScoring: string; }; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -840,7 +840,7 @@ "label": "fleet", "description": [], "signature": [ - "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; }" + "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; readonly policySecrets: string; readonly remoteESOoutput: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -868,7 +868,7 @@ "label": "clients", "description": [], "signature": [ - "{ readonly guide: string; readonly goConnecting: string; readonly goGettingStarted: string; readonly goIndex: string; readonly goOverview: string; readonly javaBasicAuthentication: string; readonly javaIndex: string; readonly javaInstallation: string; readonly javaIntroduction: string; readonly javaRestLow: string; readonly jsAdvancedConfig: string; readonly jsApiReference: string; readonly jsBasicConfig: string; readonly jsClientConnecting: string; readonly jsIntro: string; readonly netGuide: string; readonly netIntroduction: string; readonly netNest: string; readonly netSingleNode: string; readonly phpConfiguration: string; readonly phpConnecting: string; readonly phpGuide: string; readonly phpInstallation: string; readonly phpOverview: string; readonly pythonAuthentication: string; readonly pythonConfig: string; readonly pythonConnecting: string; readonly pythonGuide: string; readonly pythonOverview: string; readonly rubyAuthentication: string; readonly rubyAdvancedConfig: string; readonly rubyBasicConfig: string; readonly rubyExamples: string; readonly rubyOverview: string; readonly rustGuide: string; readonly rustOverview: string; }" + "{ readonly guide: string; readonly goConnecting: string; readonly goGettingStarted: string; readonly goIndex: string; readonly goOverview: string; readonly javaBasicAuthentication: string; readonly javaIndex: string; readonly javaInstallation: string; readonly javaIntroduction: string; readonly javaRestLow: string; readonly jsAdvancedConfig: string; readonly jsApiReference: string; readonly jsBasicConfig: string; readonly jsClientConnecting: string; readonly jsIntro: string; readonly netGuide: string; readonly netIntroduction: string; readonly netNest: string; readonly netSingleNode: string; readonly phpConfiguration: string; readonly phpConnecting: string; readonly phpGuide: string; readonly phpInstallation: string; readonly phpOverview: string; readonly pythonAuthentication: string; readonly pythonConfig: string; readonly pythonConnecting: string; readonly pythonGuide: string; readonly pythonOverview: string; readonly rubyAuthentication: string; readonly rubyAdvancedConfig: string; readonly rubyBasicConfig: string; readonly rubyExamples: string; readonly rubyOverview: string; readonly rustGuide: string; readonly rustOverview: string; readonly eland: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 956715f22011..059a56478b37 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 93ddee1f4b73..9a735b7b98d3 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index cfca9512a500..094f9334b03b 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index e5ea9774fd2f..964079b5c3fe 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 026ece1775d5..ec177903298f 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index e1eb83ecca66..955b73872af5 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.devdocs.json b/api_docs/kbn_elastic_agent_utils.devdocs.json new file mode 100644 index 000000000000..66197d89c54b --- /dev/null +++ b/api_docs/kbn_elastic_agent_utils.devdocs.json @@ -0,0 +1,631 @@ +{ + "id": "@kbn/elastic-agent-utils", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAndroidAgentName", + "type": "Function", + "tags": [], + "label": "isAndroidAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAndroidAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAWSLambdaAgentName", + "type": "Function", + "tags": [], + "label": "isAWSLambdaAgentName", + "description": [], + "signature": [ + "(serverlessType: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAWSLambdaAgentName.$1", + "type": "string", + "tags": [], + "label": "serverlessType", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAzureFunctionsAgentName", + "type": "Function", + "tags": [], + "label": "isAzureFunctionsAgentName", + "description": [], + "signature": [ + "(serverlessType: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isAzureFunctionsAgentName.$1", + "type": "string", + "tags": [], + "label": "serverlessType", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isIosAgentName", + "type": "Function", + "tags": [], + "label": "isIosAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isIosAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isJavaAgentName", + "type": "Function", + "tags": [], + "label": "isJavaAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isJavaAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isJRubyAgentName", + "type": "Function", + "tags": [], + "label": "isJRubyAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined, runtimeName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isJRubyAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isJRubyAgentName.$2", + "type": "string", + "tags": [], + "label": "runtimeName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isMobileAgentName", + "type": "Function", + "tags": [], + "label": "isMobileAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isMobileAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isOpenTelemetryAgentName", + "type": "Function", + "tags": [], + "label": "isOpenTelemetryAgentName", + "description": [], + "signature": [ + "(agentName: string) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isOpenTelemetryAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isRumAgentName", + "type": "Function", + "tags": [], + "label": "isRumAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isRumAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isRumOrMobileAgentName", + "type": "Function", + "tags": [], + "label": "isRumOrMobileAgentName", + "description": [], + "signature": [ + "(agentName: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isRumOrMobileAgentName.$1", + "type": "string", + "tags": [], + "label": "agentName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isServerlessAgentName", + "type": "Function", + "tags": [], + "label": "isServerlessAgentName", + "description": [], + "signature": [ + "(serverlessType: string | undefined) => boolean" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.isServerlessAgentName.$1", + "type": "string", + "tags": [], + "label": "serverlessType", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_guards.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.AGENT_NAMES", + "type": "Array", + "tags": [], + "label": "AGENT_NAMES", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.AgentName", + "text": "AgentName" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.AgentName", + "type": "Type", + "tags": [], + "label": "AgentName", + "description": [], + "signature": [ + "\"java\" | \"ruby\" | \"go\" | \"dotnet\" | \"php\" | \"otlp\" | \"android/java\" | \"iOS/swift\" | \"rum-js\" | \"js-base\" | \"opentelemetry/webjs\" | \"opentelemetry/java\" | \"nodejs\" | \"python\" | \"opentelemetry/cpp\" | \"opentelemetry/dotnet\" | \"opentelemetry/erlang\" | \"opentelemetry/go\" | \"opentelemetry/nodejs\" | \"opentelemetry/php\" | \"opentelemetry/python\" | \"opentelemetry/ruby\" | \"opentelemetry/rust\" | \"opentelemetry/swift\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.ELASTIC_AGENT_NAMES", + "type": "Array", + "tags": [], + "label": "ELASTIC_AGENT_NAMES", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.ElasticAgentName", + "text": "ElasticAgentName" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.ElasticAgentName", + "type": "Type", + "tags": [], + "label": "ElasticAgentName", + "description": [ + "\nWe cannot mark these arrays as const and derive their type\nbecause we need to be able to assign them as mutable entities for ES queries." + ], + "signature": [ + "\"java\" | \"ruby\" | \"go\" | \"dotnet\" | \"php\" | \"android/java\" | \"iOS/swift\" | \"rum-js\" | \"js-base\" | \"nodejs\" | \"python\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.JAVA_AGENT_NAMES", + "type": "Array", + "tags": [], + "label": "JAVA_AGENT_NAMES", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.JavaAgentName", + "text": "JavaAgentName" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.JavaAgentName", + "type": "Type", + "tags": [], + "label": "JavaAgentName", + "description": [], + "signature": [ + "\"java\" | \"opentelemetry/java\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.OPEN_TELEMETRY_AGENT_NAMES", + "type": "Array", + "tags": [], + "label": "OPEN_TELEMETRY_AGENT_NAMES", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.OpenTelemetryAgentName", + "text": "OpenTelemetryAgentName" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.OpenTelemetryAgentName", + "type": "Type", + "tags": [], + "label": "OpenTelemetryAgentName", + "description": [], + "signature": [ + "\"otlp\" | \"opentelemetry/webjs\" | \"opentelemetry/java\" | \"opentelemetry/cpp\" | \"opentelemetry/dotnet\" | \"opentelemetry/erlang\" | \"opentelemetry/go\" | \"opentelemetry/nodejs\" | \"opentelemetry/php\" | \"opentelemetry/python\" | \"opentelemetry/ruby\" | \"opentelemetry/rust\" | \"opentelemetry/swift\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.RUM_AGENT_NAMES", + "type": "Array", + "tags": [], + "label": "RUM_AGENT_NAMES", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.RumAgentName", + "text": "RumAgentName" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.RumAgentName", + "type": "Type", + "tags": [], + "label": "RumAgentName", + "description": [], + "signature": [ + "\"rum-js\" | \"js-base\" | \"opentelemetry/webjs\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.SERVERLESS_TYPE", + "type": "Array", + "tags": [], + "label": "SERVERLESS_TYPE", + "description": [], + "signature": [ + { + "pluginId": "@kbn/elastic-agent-utils", + "scope": "common", + "docId": "kibKbnElasticAgentUtilsPluginApi", + "section": "def-common.ServerlessType", + "text": "ServerlessType" + }, + "[]" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-agent-utils", + "id": "def-common.ServerlessType", + "type": "Type", + "tags": [], + "label": "ServerlessType", + "description": [], + "signature": [ + "\"aws.lambda\" | \"azure.functions\"" + ], + "path": "packages/kbn-elastic-agent-utils/src/agent_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx new file mode 100644 index 000000000000..73ee22a52987 --- /dev/null +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnElasticAgentUtilsPluginApi +slug: /kibana-dev-docs/api/kbn-elastic-agent-utils +title: "@kbn/elastic-agent-utils" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/elastic-agent-utils plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] +--- +import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; + + + +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 35 | 0 | 34 | 0 | + +## Common + +### Functions + + +### Consts, variables and types + + diff --git a/api_docs/kbn_elastic_assistant.devdocs.json b/api_docs/kbn_elastic_assistant.devdocs.json index d308ab08ff13..160c43608057 100644 --- a/api_docs/kbn_elastic_assistant.devdocs.json +++ b/api_docs/kbn_elastic_assistant.devdocs.json @@ -1023,6 +1023,20 @@ "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/elastic-assistant", + "id": "def-public.Message.traceData", + "type": "Object", + "tags": [], + "label": "traceData", + "description": [], + "signature": [ + "{ transactionId: string; traceId: string; } | undefined" + ], + "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 5cde4c3ad25e..2eacd75d16c5 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 96 | 0 | 76 | 6 | +| 97 | 0 | 77 | 6 | ## Client diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 19e005519406..a4f94e88fe20 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index feca9bd4bdf1..8583d84ac918 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 9abe569c9e6b..8207a2e27e24 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.devdocs.json b/api_docs/kbn_es_query.devdocs.json index 2da8cfc35d41..2ae012946a9c 100644 --- a/api_docs/kbn_es_query.devdocs.json +++ b/api_docs/kbn_es_query.devdocs.json @@ -1616,6 +1616,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.cleanupESQLQueryForLensSuggestions", + "type": "Function", + "tags": [], + "label": "cleanupESQLQueryForLensSuggestions", + "description": [], + "signature": [ + "(esql: string | undefined) => string" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.cleanupESQLQueryForLensSuggestions.$1", + "type": "string", + "tags": [], + "label": "esql", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.compareFilters", diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index a20beb160dc9..1e4d41227111 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 259 | 1 | 199 | 15 | +| 261 | 1 | 201 | 15 | ## Common diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 5845573fb4ae..e2f492a1caa8 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 366cdec67c8c..ccf424f73bdc 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index e0d7211513df..15d3c6479bdb 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 03d1d494ef0a..eca8e85c4c4c 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.devdocs.json b/api_docs/kbn_expandable_flyout.devdocs.json index 3bf8bc5f0903..261654cf26f1 100644 --- a/api_docs/kbn_expandable_flyout.devdocs.json +++ b/api_docs/kbn_expandable_flyout.devdocs.json @@ -29,7 +29,7 @@ "\nExpandable flyout UI React component.\nDisplays 3 sections (right, left, preview) depending on the panels in the context.\n\nThe behavior expects that the left and preview sections should only be displayed is a right section\nis already rendered." ], "signature": [ - "{ ({ registeredPanels, handleOnFlyoutClosed, ...flyoutProps }: React.PropsWithChildren<", + "{ ({ registeredPanels, ...flyoutProps }: React.PropsWithChildren<", { "pluginId": "@kbn/expandable-flyout", "scope": "common", @@ -48,7 +48,7 @@ "id": "def-common.ExpandableFlyout.$1", "type": "CompoundType", "tags": [], - "label": "{\n registeredPanels,\n handleOnFlyoutClosed,\n ...flyoutProps\n}", + "label": "{\n registeredPanels,\n ...flyoutProps\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -77,41 +77,32 @@ "tags": [], "label": "ExpandableFlyoutProvider", "description": [ - "\nWrap your plugin with this context for the ExpandableFlyout React component." + "\nWrap your plugin with this context for the ExpandableFlyout React component.\nStorage property allows you to specify how the flyout state works internally.\nWith \"url\", it will be persisted into url and thus allow for deep linking & will survive webpage reloads.\n\"memory\" is based on useReducer hook. The state is saved internally to the package. which means it will not be\npersisted when sharing url or reloading browser pages." ], "signature": [ - "React.ForwardRefExoticComponent<", - "ExpandableFlyoutProviderProps", - " & React.RefAttributes<", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.ExpandableFlyoutApi", - "text": "ExpandableFlyoutApi" - }, - ">>" + "({ children, storage, }: React.PropsWithChildren>) => JSX.Element" ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", + "path": "packages/kbn-expandable-flyout/src/provider.tsx", "deprecated": false, "trackAdoption": false, - "returnComment": [], "children": [ { "parentPluginId": "@kbn/expandable-flyout", "id": "def-common.ExpandableFlyoutProvider.$1", - "type": "Uncategorized", + "type": "CompoundType", "tags": [], - "label": "props", + "label": "{\n children,\n storage = 'url',\n}", "description": [], "signature": [ - "P" + "React.PropsWithChildren>" ], - "path": "node_modules/@types/react/index.d.ts", + "path": "packages/kbn-expandable-flyout/src/provider.tsx", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "isRequired": true } ], + "returnComment": [], "initialIsOpen": false }, { @@ -125,13 +116,7 @@ ], "signature": [ "() => ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.ExpandableFlyoutContext", - "text": "ExpandableFlyoutContext" - } + "ExpandableFlyoutContextValue" ], "path": "packages/kbn-expandable-flyout/src/context.tsx", "deprecated": false, @@ -142,389 +127,6 @@ } ], "interfaces": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext", - "type": "Interface", - "tags": [], - "label": "ExpandableFlyoutContext", - "description": [], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.panels", - "type": "Object", - "tags": [], - "label": "panels", - "description": [ - "\nRight, left and preview panels" - ], - "signature": [ - "State" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openFlyout", - "type": "Function", - "tags": [], - "label": "openFlyout", - "description": [ - "\nOpen the flyout with left, right and/or preview panels" - ], - "signature": [ - "(panels: { left?: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined; right?: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined; preview?: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined; }) => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openFlyout.$1", - "type": "Object", - "tags": [], - "label": "panels", - "description": [], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openFlyout.$1.left", - "type": "Object", - "tags": [], - "label": "left", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openFlyout.$1.right", - "type": "Object", - "tags": [], - "label": "right", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openFlyout.$1.preview", - "type": "Object", - "tags": [], - "label": "preview", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - " | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openRightPanel", - "type": "Function", - "tags": [], - "label": "openRightPanel", - "description": [ - "\nReplaces the current right panel with a new one" - ], - "signature": [ - "(panel: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - ") => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openRightPanel.$1", - "type": "Object", - "tags": [], - "label": "panel", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - } - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openLeftPanel", - "type": "Function", - "tags": [], - "label": "openLeftPanel", - "description": [ - "\nReplaces the current left panel with a new one" - ], - "signature": [ - "(panel: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - ") => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openLeftPanel.$1", - "type": "Object", - "tags": [], - "label": "panel", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - } - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openPreviewPanel", - "type": "Function", - "tags": [], - "label": "openPreviewPanel", - "description": [ - "\nAdd a new preview panel to the list of current preview panels" - ], - "signature": [ - "(panel: ", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - }, - ") => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.openPreviewPanel.$1", - "type": "Object", - "tags": [], - "label": "panel", - "description": [], - "signature": [ - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.FlyoutPanelProps", - "text": "FlyoutPanelProps" - } - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.closeRightPanel", - "type": "Function", - "tags": [], - "label": "closeRightPanel", - "description": [ - "\nCloses right panel" - ], - "signature": [ - "() => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.closeLeftPanel", - "type": "Function", - "tags": [], - "label": "closeLeftPanel", - "description": [ - "\nCloses left panel" - ], - "signature": [ - "() => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.closePreviewPanel", - "type": "Function", - "tags": [], - "label": "closePreviewPanel", - "description": [ - "\nCloses all preview panels" - ], - "signature": [ - "() => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.previousPreviewPanel", - "type": "Function", - "tags": [], - "label": "previousPreviewPanel", - "description": [ - "\nGo back to previous preview panel" - ], - "signature": [ - "() => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutContext.closeFlyout", - "type": "Function", - "tags": [], - "label": "closeFlyout", - "description": [ - "\nClose all panels and closes flyout" - ], - "signature": [ - "() => void" - ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/expandable-flyout", "id": "def-common.ExpandableFlyoutProps", @@ -564,24 +166,6 @@ "path": "packages/kbn-expandable-flyout/src/index.tsx", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutProps.handleOnFlyoutClosed", - "type": "Function", - "tags": [], - "label": "handleOnFlyoutClosed", - "description": [ - "\nPropagate out EuiFlyout onClose event" - ], - "signature": [ - "(() => void) | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/index.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] } ], "initialIsOpen": false @@ -716,25 +300,15 @@ "misc": [ { "parentPluginId": "@kbn/expandable-flyout", - "id": "def-common.ExpandableFlyoutApi", - "type": "Type", + "id": "def-common.EXPANDABLE_FLYOUT_URL_KEY", + "type": "string", "tags": [], - "label": "ExpandableFlyoutApi", + "label": "EXPANDABLE_FLYOUT_URL_KEY", "description": [], "signature": [ - "Pick<", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.ExpandableFlyoutContext", - "text": "ExpandableFlyoutContext" - }, - ", \"openFlyout\"> & { getState: () => ", - "State", - "; }" + "\"eventFlyout\"" ], - "path": "packages/kbn-expandable-flyout/src/context.tsx", + "path": "packages/kbn-expandable-flyout/src/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -750,13 +324,7 @@ "description": [], "signature": [ "React.Context<", - { - "pluginId": "@kbn/expandable-flyout", - "scope": "common", - "docId": "kibKbnExpandableFlyoutPluginApi", - "section": "def-common.ExpandableFlyoutContext", - "text": "ExpandableFlyoutContext" - }, + "ExpandableFlyoutContextValue", " | undefined>" ], "path": "packages/kbn-expandable-flyout/src/context.tsx", diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index bca15df2c67b..7ee24eb82212 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 0 | 14 | 3 | +| 17 | 0 | 7 | 2 | ## Common diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 8ee2498fdb00..308abe1b857d 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index aab8071d09c5..dd27a06e19ff 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index b3e0721d84b8..2153369350e3 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index c6390d89bfda..f2a266a195ff 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 27ce99c92bc3..881b97c419c5 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 2a12d265387b..a597f2401d05 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 15f0991bf7e3..a76d608e40ac 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index f67f4d9cfb89..b7371c244b9f 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 68b6bf281411..236f4591bd41 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 3e1243046ba4..200a01719943 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 9d521afacf7d..506486665d26 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 481cb6766e77..a89d7799d985 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 62b7c2f31e44..6a165f61c528 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index eff401f76683..67affc398d1c 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 4822e06ba5a9..9f2d71500bb1 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 173a7796634d..3ee9dc068a1a 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 9ca66fdfeead..dd2e6c31ac27 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index e94ffcf8e779..c7e085a29cc6 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 4255f14ce211..fb888a734eb7 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index f058d33c6cfe..d8deb6fd704c 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 98094849fd80..79254480e6b5 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 656670cab4d4..d573ea7d787a 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index c2a9ffbf0997..f47a40aa9465 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.devdocs.json b/api_docs/kbn_language_documentation_popover.devdocs.json index efc5a267ed84..d15c3a47f0f0 100644 --- a/api_docs/kbn_language_documentation_popover.devdocs.json +++ b/api_docs/kbn_language_documentation_popover.devdocs.json @@ -27,7 +27,7 @@ "label": "LanguageDocumentationPopover", "description": [], "signature": [ - "React.NamedExoticComponent & { readonly type: ({ language, sections, buttonProps }: DocumentationPopoverProps) => JSX.Element; }" + "React.NamedExoticComponent & { readonly type: ({ language, sections, buttonProps, searchInDescription, }: DocumentationPopoverProps) => JSX.Element; }" ], "path": "packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx", "deprecated": false, @@ -59,7 +59,7 @@ "label": "LanguageDocumentationPopoverContent", "description": [], "signature": [ - "React.NamedExoticComponent & { readonly type: ({ language, sections }: DocumentationProps) => JSX.Element; }" + "React.NamedExoticComponent & { readonly type: ({ language, sections, searchInDescription }: DocumentationProps) => JSX.Element; }" ], "path": "packages/kbn-language-documentation-popover/src/components/documentation_content.tsx", "deprecated": false, diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index e05ea9131bfd..4cad41d5d9e3 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.devdocs.json b/api_docs/kbn_lens_embeddable_utils.devdocs.json index 3bc9508b445d..0e057402df29 100644 --- a/api_docs/kbn_lens_embeddable_utils.devdocs.json +++ b/api_docs/kbn_lens_embeddable_utils.devdocs.json @@ -1,10 +1,26 @@ { "id": "@kbn/lens-embeddable-utils", "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { "classes": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn", + "id": "def-common.FormulaColumn", "type": "Class", "tags": [], "label": "FormulaColumn", @@ -12,17 +28,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.FormulaColumn", + "section": "def-common.FormulaColumn", "text": "FormulaColumn" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartColumn", + "section": "def-common.ChartColumn", "text": "ChartColumn" } ], @@ -32,7 +48,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.Unnamed", + "id": "def-common.FormulaColumn.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -46,7 +62,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.Unnamed.$1", + "id": "def-common.FormulaColumn.Unnamed.$1", "type": "CompoundType", "tags": [], "label": "valueConfig", @@ -54,9 +70,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.FormulaValueConfig", + "section": "def-common.FormulaValueConfig", "text": "FormulaValueConfig" } ], @@ -70,7 +86,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getValueConfig", + "id": "def-common.FormulaColumn.getValueConfig", "type": "Function", "tags": [], "label": "getValueConfig", @@ -79,9 +95,9 @@ "() => ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.FormulaValueConfig", + "section": "def-common.FormulaValueConfig", "text": "FormulaValueConfig" } ], @@ -93,7 +109,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getData", + "id": "def-common.FormulaColumn.getData", "type": "Function", "tags": [], "label": "getData", @@ -138,7 +154,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getData.$1", + "id": "def-common.FormulaColumn.getData.$1", "type": "string", "tags": [], "label": "id", @@ -153,7 +169,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getData.$2", + "id": "def-common.FormulaColumn.getData.$2", "type": "Object", "tags": [], "label": "baseLayer", @@ -174,7 +190,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getData.$3", + "id": "def-common.FormulaColumn.getData.$3", "type": "Object", "tags": [], "label": "dataView", @@ -195,7 +211,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaColumn.getData.$4", + "id": "def-common.FormulaColumn.getData.$4", "type": "Object", "tags": [], "label": "formulaAPI", @@ -222,7 +238,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributesBuilder", + "id": "def-common.LensAttributesBuilder", "type": "Class", "tags": [], "label": "LensAttributesBuilder", @@ -230,17 +246,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.LensAttributesBuilder", + "section": "def-common.LensAttributesBuilder", "text": "LensAttributesBuilder" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.VisualizationAttributesBuilder", + "section": "def-common.VisualizationAttributesBuilder", "text": "VisualizationAttributesBuilder" } ], @@ -250,7 +266,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributesBuilder.Unnamed", + "id": "def-common.LensAttributesBuilder.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -264,7 +280,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributesBuilder.Unnamed.$1", + "id": "def-common.LensAttributesBuilder.Unnamed.$1", "type": "Object", "tags": [], "label": "lens", @@ -275,7 +291,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributesBuilder.Unnamed.$1.visualization", + "id": "def-common.LensAttributesBuilder.Unnamed.$1.visualization", "type": "Uncategorized", "tags": [], "label": "visualization", @@ -294,7 +310,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributesBuilder.build", + "id": "def-common.LensAttributesBuilder.build", "type": "Function", "tags": [], "label": "build", @@ -363,7 +379,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart", + "id": "def-common.MetricChart", "type": "Class", "tags": [], "label": "MetricChart", @@ -371,17 +387,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.MetricChart", + "section": "def-common.MetricChart", "text": "MetricChart" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.Chart", + "section": "def-common.Chart", "text": "Chart" }, "<", @@ -400,7 +416,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.Unnamed", + "id": "def-common.MetricChart.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -414,7 +430,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.Unnamed.$1", + "id": "def-common.MetricChart.Unnamed.$1", "type": "Object", "tags": [], "label": "chartConfig", @@ -422,17 +438,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartConfig", + "section": "def-common.ChartConfig", "text": "ChartConfig" }, "<", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "<", @@ -455,7 +471,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getVisualizationType", + "id": "def-common.MetricChart.getVisualizationType", "type": "Function", "tags": [], "label": "getVisualizationType", @@ -471,7 +487,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getLayers", + "id": "def-common.MetricChart.getLayers", "type": "Function", "tags": [], "label": "getLayers", @@ -495,7 +511,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getVisualizationState", + "id": "def-common.MetricChart.getVisualizationState", "type": "Function", "tags": [], "label": "getVisualizationState", @@ -518,7 +534,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getReferences", + "id": "def-common.MetricChart.getReferences", "type": "Function", "tags": [], "label": "getReferences", @@ -542,7 +558,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getDataViews", + "id": "def-common.MetricChart.getDataViews", "type": "Function", "tags": [], "label": "getDataViews", @@ -566,7 +582,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricChart.getTitle", + "id": "def-common.MetricChart.getTitle", "type": "Function", "tags": [], "label": "getTitle", @@ -585,7 +601,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer", + "id": "def-common.MetricLayer", "type": "Class", "tags": [], "label": "MetricLayer", @@ -593,17 +609,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.MetricLayer", + "section": "def-common.MetricLayer", "text": "MetricLayer" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "<", @@ -622,7 +638,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.Unnamed", + "id": "def-common.MetricLayer.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -636,7 +652,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.Unnamed.$1", + "id": "def-common.MetricLayer.Unnamed.$1", "type": "Object", "tags": [], "label": "layerConfig", @@ -644,9 +660,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.MetricLayerConfig", + "section": "def-common.MetricLayerConfig", "text": "MetricLayerConfig" } ], @@ -660,7 +676,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayer", + "id": "def-common.MetricLayer.getLayer", "type": "Function", "tags": [], "label": "getLayer", @@ -698,7 +714,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayer.$1", + "id": "def-common.MetricLayer.getLayer.$1", "type": "string", "tags": [], "label": "layerId", @@ -713,7 +729,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayer.$2", + "id": "def-common.MetricLayer.getLayer.$2", "type": "string", "tags": [], "label": "accessorId", @@ -728,7 +744,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayer.$3", + "id": "def-common.MetricLayer.getLayer.$3", "type": "Object", "tags": [], "label": "chartDataView", @@ -749,7 +765,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayer.$4", + "id": "def-common.MetricLayer.getLayer.$4", "type": "Object", "tags": [], "label": "formulaAPI", @@ -773,7 +789,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getReference", + "id": "def-common.MetricLayer.getReference", "type": "Function", "tags": [], "label": "getReference", @@ -803,7 +819,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getReference.$1", + "id": "def-common.MetricLayer.getReference.$1", "type": "string", "tags": [], "label": "layerId", @@ -818,7 +834,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getReference.$2", + "id": "def-common.MetricLayer.getReference.$2", "type": "Object", "tags": [], "label": "chartDataView", @@ -842,7 +858,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayerConfig", + "id": "def-common.MetricLayer.getLayerConfig", "type": "Function", "tags": [], "label": "getLayerConfig", @@ -863,7 +879,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayerConfig.$1", + "id": "def-common.MetricLayer.getLayerConfig.$1", "type": "string", "tags": [], "label": "layerId", @@ -878,7 +894,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getLayerConfig.$2", + "id": "def-common.MetricLayer.getLayerConfig.$2", "type": "string", "tags": [], "label": "accessorId", @@ -896,7 +912,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getName", + "id": "def-common.MetricLayer.getName", "type": "Function", "tags": [], "label": "getName", @@ -912,7 +928,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayer.getDataView", + "id": "def-common.MetricLayer.getDataView", "type": "Function", "tags": [], "label": "getDataView", @@ -939,7 +955,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn", + "id": "def-common.StaticColumn", "type": "Class", "tags": [], "label": "StaticColumn", @@ -947,17 +963,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticColumn", + "section": "def-common.StaticColumn", "text": "StaticColumn" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticChartColumn", + "section": "def-common.StaticChartColumn", "text": "StaticChartColumn" } ], @@ -967,7 +983,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.Unnamed", + "id": "def-common.StaticColumn.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -981,7 +997,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.Unnamed.$1", + "id": "def-common.StaticColumn.Unnamed.$1", "type": "CompoundType", "tags": [], "label": "valueConfig", @@ -989,9 +1005,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticValueConfig", + "section": "def-common.StaticValueConfig", "text": "StaticValueConfig" } ], @@ -1005,7 +1021,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.getValueConfig", + "id": "def-common.StaticColumn.getValueConfig", "type": "Function", "tags": [], "label": "getValueConfig", @@ -1014,9 +1030,9 @@ "() => ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticValueConfig", + "section": "def-common.StaticValueConfig", "text": "StaticValueConfig" } ], @@ -1028,7 +1044,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.getData", + "id": "def-common.StaticColumn.getData", "type": "Function", "tags": [], "label": "getData", @@ -1057,7 +1073,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.getData.$1", + "id": "def-common.StaticColumn.getData.$1", "type": "string", "tags": [], "label": "id", @@ -1072,7 +1088,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticColumn.getData.$2", + "id": "def-common.StaticColumn.getData.$2", "type": "Object", "tags": [], "label": "baseLayer", @@ -1099,7 +1115,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart", + "id": "def-common.XYChart", "type": "Class", "tags": [], "label": "XYChart", @@ -1107,17 +1123,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYChart", + "section": "def-common.XYChart", "text": "XYChart" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.Chart", + "section": "def-common.Chart", "text": "Chart" }, "<", @@ -1136,7 +1152,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.Unnamed", + "id": "def-common.XYChart.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -1150,7 +1166,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.Unnamed.$1", + "id": "def-common.XYChart.Unnamed.$1", "type": "CompoundType", "tags": [], "label": "chartConfig", @@ -1158,17 +1174,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartConfig", + "section": "def-common.ChartConfig", "text": "ChartConfig" }, "<", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "<", @@ -1182,9 +1198,9 @@ ">[]> & { visualOptions?: ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYVisualOptions", + "section": "def-common.XYVisualOptions", "text": "XYVisualOptions" }, " | undefined; }" @@ -1199,7 +1215,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getVisualizationType", + "id": "def-common.XYChart.getVisualizationType", "type": "Function", "tags": [], "label": "getVisualizationType", @@ -1215,7 +1231,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getLayers", + "id": "def-common.XYChart.getLayers", "type": "Function", "tags": [], "label": "getLayers", @@ -1239,7 +1255,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getVisualizationState", + "id": "def-common.XYChart.getVisualizationState", "type": "Function", "tags": [], "label": "getVisualizationState", @@ -1262,7 +1278,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getReferences", + "id": "def-common.XYChart.getReferences", "type": "Function", "tags": [], "label": "getReferences", @@ -1286,7 +1302,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getDataViews", + "id": "def-common.XYChart.getDataViews", "type": "Function", "tags": [], "label": "getDataViews", @@ -1310,7 +1326,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYChart.getTitle", + "id": "def-common.XYChart.getTitle", "type": "Function", "tags": [], "label": "getTitle", @@ -1329,7 +1345,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer", + "id": "def-common.XYDataLayer", "type": "Class", "tags": [], "label": "XYDataLayer", @@ -1337,17 +1353,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYDataLayer", + "section": "def-common.XYDataLayer", "text": "XYDataLayer" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "<", @@ -1366,7 +1382,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.Unnamed", + "id": "def-common.XYDataLayer.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -1380,7 +1396,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.Unnamed.$1", + "id": "def-common.XYDataLayer.Unnamed.$1", "type": "Object", "tags": [], "label": "layerConfig", @@ -1388,10 +1404,10 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYLayerConfig", - "text": "XYLayerConfig" + "section": "def-common.XYDataLayerConfig", + "text": "XYDataLayerConfig" } ], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts", @@ -1404,7 +1420,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getName", + "id": "def-common.XYDataLayer.getName", "type": "Function", "tags": [], "label": "getName", @@ -1420,7 +1436,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getBaseLayer", + "id": "def-common.XYDataLayer.getBaseLayer", "type": "Function", "tags": [], "label": "getBaseLayer", @@ -1437,9 +1453,9 @@ ", options: ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYLayerOptions", + "section": "def-common.XYLayerOptions", "text": "XYLayerOptions" }, ") => { [x: string]: ", @@ -1466,7 +1482,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getBaseLayer.$1", + "id": "def-common.XYDataLayer.getBaseLayer.$1", "type": "Object", "tags": [], "label": "dataView", @@ -1487,7 +1503,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getBaseLayer.$2", + "id": "def-common.XYDataLayer.getBaseLayer.$2", "type": "Object", "tags": [], "label": "options", @@ -1495,9 +1511,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYLayerOptions", + "section": "def-common.XYLayerOptions", "text": "XYLayerOptions" } ], @@ -1511,7 +1527,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayer", + "id": "def-common.XYDataLayer.getLayer", "type": "Function", "tags": [], "label": "getLayer", @@ -1549,7 +1565,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayer.$1", + "id": "def-common.XYDataLayer.getLayer.$1", "type": "string", "tags": [], "label": "layerId", @@ -1564,7 +1580,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayer.$2", + "id": "def-common.XYDataLayer.getLayer.$2", "type": "string", "tags": [], "label": "accessorId", @@ -1579,7 +1595,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayer.$3", + "id": "def-common.XYDataLayer.getLayer.$3", "type": "Object", "tags": [], "label": "chartDataView", @@ -1600,7 +1616,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayer.$4", + "id": "def-common.XYDataLayer.getLayer.$4", "type": "Object", "tags": [], "label": "formulaAPI", @@ -1624,7 +1640,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getReference", + "id": "def-common.XYDataLayer.getReference", "type": "Function", "tags": [], "label": "getReference", @@ -1654,7 +1670,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getReference.$1", + "id": "def-common.XYDataLayer.getReference.$1", "type": "string", "tags": [], "label": "layerId", @@ -1669,7 +1685,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getReference.$2", + "id": "def-common.XYDataLayer.getReference.$2", "type": "Object", "tags": [], "label": "chartDataView", @@ -1693,7 +1709,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayerConfig", + "id": "def-common.XYDataLayer.getLayerConfig", "type": "Function", "tags": [], "label": "getLayerConfig", @@ -1714,7 +1730,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayerConfig.$1", + "id": "def-common.XYDataLayer.getLayerConfig.$1", "type": "string", "tags": [], "label": "layerId", @@ -1729,7 +1745,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getLayerConfig.$2", + "id": "def-common.XYDataLayer.getLayerConfig.$2", "type": "string", "tags": [], "label": "accessorId", @@ -1747,7 +1763,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYDataLayer.getDataView", + "id": "def-common.XYDataLayer.getDataView", "type": "Function", "tags": [], "label": "getDataView", @@ -1774,7 +1790,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer", + "id": "def-common.XYReferenceLinesLayer", "type": "Class", "tags": [], "label": "XYReferenceLinesLayer", @@ -1782,17 +1798,17 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYReferenceLinesLayer", + "section": "def-common.XYReferenceLinesLayer", "text": "XYReferenceLinesLayer" }, " implements ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "<", @@ -1811,7 +1827,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.Unnamed", + "id": "def-common.XYReferenceLinesLayer.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -1825,7 +1841,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.Unnamed.$1", + "id": "def-common.XYReferenceLinesLayer.Unnamed.$1", "type": "Object", "tags": [], "label": "layerConfig", @@ -1833,9 +1849,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYReferenceLinesLayerConfig", + "section": "def-common.XYReferenceLinesLayerConfig", "text": "XYReferenceLinesLayerConfig" } ], @@ -1849,7 +1865,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getName", + "id": "def-common.XYReferenceLinesLayer.getName", "type": "Function", "tags": [], "label": "getName", @@ -1865,7 +1881,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayer", + "id": "def-common.XYReferenceLinesLayer.getLayer", "type": "Function", "tags": [], "label": "getLayer", @@ -1887,7 +1903,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayer.$1", + "id": "def-common.XYReferenceLinesLayer.getLayer.$1", "type": "string", "tags": [], "label": "layerId", @@ -1902,7 +1918,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayer.$2", + "id": "def-common.XYReferenceLinesLayer.getLayer.$2", "type": "string", "tags": [], "label": "accessorId", @@ -1920,7 +1936,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getReference", + "id": "def-common.XYReferenceLinesLayer.getReference", "type": "Function", "tags": [], "label": "getReference", @@ -1950,7 +1966,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getReference.$1", + "id": "def-common.XYReferenceLinesLayer.getReference.$1", "type": "string", "tags": [], "label": "layerId", @@ -1965,7 +1981,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getReference.$2", + "id": "def-common.XYReferenceLinesLayer.getReference.$2", "type": "Object", "tags": [], "label": "chartDataView", @@ -1989,7 +2005,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayerConfig", + "id": "def-common.XYReferenceLinesLayer.getLayerConfig", "type": "Function", "tags": [], "label": "getLayerConfig", @@ -2010,7 +2026,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayerConfig.$1", + "id": "def-common.XYReferenceLinesLayer.getLayerConfig.$1", "type": "string", "tags": [], "label": "layerId", @@ -2025,7 +2041,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getLayerConfig.$2", + "id": "def-common.XYReferenceLinesLayer.getLayerConfig.$2", "type": "string", "tags": [], "label": "accessorId", @@ -2043,7 +2059,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayer.getDataView", + "id": "def-common.XYReferenceLinesLayer.getDataView", "type": "Function", "tags": [], "label": "getDataView", @@ -2073,7 +2089,7 @@ "interfaces": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.BaseChartColumn", + "id": "def-common.BaseChartColumn", "type": "Interface", "tags": [], "label": "BaseChartColumn", @@ -2081,9 +2097,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.BaseChartColumn", + "section": "def-common.BaseChartColumn", "text": "BaseChartColumn" }, "" @@ -2094,7 +2110,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.BaseChartColumn.getValueConfig", + "id": "def-common.BaseChartColumn.getValueConfig", "type": "Function", "tags": [], "label": "getValueConfig", @@ -2113,7 +2129,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart", + "id": "def-common.Chart", "type": "Interface", "tags": [], "label": "Chart", @@ -2121,9 +2137,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.Chart", + "section": "def-common.Chart", "text": "Chart" }, "" @@ -2134,7 +2150,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getTitle", + "id": "def-common.Chart.getTitle", "type": "Function", "tags": [], "label": "getTitle", @@ -2150,7 +2166,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getVisualizationType", + "id": "def-common.Chart.getVisualizationType", "type": "Function", "tags": [], "label": "getVisualizationType", @@ -2166,7 +2182,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getLayers", + "id": "def-common.Chart.getLayers", "type": "Function", "tags": [], "label": "getLayers", @@ -2190,7 +2206,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getVisualizationState", + "id": "def-common.Chart.getVisualizationState", "type": "Function", "tags": [], "label": "getVisualizationState", @@ -2206,7 +2222,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getReferences", + "id": "def-common.Chart.getReferences", "type": "Function", "tags": [], "label": "getReferences", @@ -2230,7 +2246,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.Chart.getDataViews", + "id": "def-common.Chart.getDataViews", "type": "Function", "tags": [], "label": "getDataViews", @@ -2257,7 +2273,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn", + "id": "def-common.ChartColumn", "type": "Interface", "tags": [], "label": "ChartColumn", @@ -2265,25 +2281,25 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartColumn", + "section": "def-common.ChartColumn", "text": "ChartColumn" }, " extends ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.BaseChartColumn", + "section": "def-common.BaseChartColumn", "text": "BaseChartColumn" }, "<", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.FormulaValueConfig", + "section": "def-common.FormulaValueConfig", "text": "FormulaValueConfig" }, ">" @@ -2294,7 +2310,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn.getData", + "id": "def-common.ChartColumn.getData", "type": "Function", "tags": [], "label": "getData", @@ -2339,7 +2355,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn.getData.$1", + "id": "def-common.ChartColumn.getData.$1", "type": "string", "tags": [], "label": "id", @@ -2354,7 +2370,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn.getData.$2", + "id": "def-common.ChartColumn.getData.$2", "type": "Object", "tags": [], "label": "baseLayer", @@ -2375,7 +2391,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn.getData.$3", + "id": "def-common.ChartColumn.getData.$3", "type": "Object", "tags": [], "label": "dataView", @@ -2396,7 +2412,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartColumn.getData.$4", + "id": "def-common.ChartColumn.getData.$4", "type": "Object", "tags": [], "label": "formulaAPI", @@ -2423,7 +2439,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartConfig", + "id": "def-common.ChartConfig", "type": "Interface", "tags": [], "label": "ChartConfig", @@ -2431,9 +2447,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartConfig", + "section": "def-common.ChartConfig", "text": "ChartConfig" }, "" @@ -2444,7 +2460,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartConfig.formulaAPI", + "id": "def-common.ChartConfig.formulaAPI", "type": "Object", "tags": [], "label": "formulaAPI", @@ -2464,7 +2480,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartConfig.dataView", + "id": "def-common.ChartConfig.dataView", "type": "Object", "tags": [], "label": "dataView", @@ -2484,7 +2500,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartConfig.layers", + "id": "def-common.ChartConfig.layers", "type": "Uncategorized", "tags": [], "label": "layers", @@ -2498,7 +2514,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartConfig.title", + "id": "def-common.ChartConfig.title", "type": "string", "tags": [], "label": "title", @@ -2515,7 +2531,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer", + "id": "def-common.ChartLayer", "type": "Interface", "tags": [], "label": "ChartLayer", @@ -2523,9 +2539,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.ChartLayer", + "section": "def-common.ChartLayer", "text": "ChartLayer" }, "" @@ -2536,7 +2552,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getName", + "id": "def-common.ChartLayer.getName", "type": "Function", "tags": [], "label": "getName", @@ -2552,7 +2568,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayer", + "id": "def-common.ChartLayer.getLayer", "type": "Function", "tags": [], "label": "getLayer", @@ -2590,7 +2606,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayer.$1", + "id": "def-common.ChartLayer.getLayer.$1", "type": "string", "tags": [], "label": "layerId", @@ -2605,7 +2621,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayer.$2", + "id": "def-common.ChartLayer.getLayer.$2", "type": "string", "tags": [], "label": "accessorId", @@ -2620,7 +2636,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayer.$3", + "id": "def-common.ChartLayer.getLayer.$3", "type": "Object", "tags": [], "label": "dataView", @@ -2641,7 +2657,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayer.$4", + "id": "def-common.ChartLayer.getLayer.$4", "type": "Object", "tags": [], "label": "formulaAPI", @@ -2665,7 +2681,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getReference", + "id": "def-common.ChartLayer.getReference", "type": "Function", "tags": [], "label": "getReference", @@ -2695,7 +2711,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getReference.$1", + "id": "def-common.ChartLayer.getReference.$1", "type": "string", "tags": [], "label": "layerId", @@ -2710,7 +2726,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getReference.$2", + "id": "def-common.ChartLayer.getReference.$2", "type": "Object", "tags": [], "label": "dataView", @@ -2734,7 +2750,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayerConfig", + "id": "def-common.ChartLayer.getLayerConfig", "type": "Function", "tags": [], "label": "getLayerConfig", @@ -2748,7 +2764,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayerConfig.$1", + "id": "def-common.ChartLayer.getLayerConfig.$1", "type": "string", "tags": [], "label": "layerId", @@ -2763,7 +2779,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getLayerConfig.$2", + "id": "def-common.ChartLayer.getLayerConfig.$2", "type": "string", "tags": [], "label": "acessorId", @@ -2781,7 +2797,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.ChartLayer.getDataView", + "id": "def-common.ChartLayer.getDataView", "type": "Function", "tags": [], "label": "getDataView", @@ -2808,7 +2824,65 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerConfig", + "id": "def-common.MetricChartModel", + "type": "Interface", + "tags": [], + "label": "MetricChartModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.MetricChartModel", + "text": "MetricChartModel" + }, + " extends ChartModelBase" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.MetricChartModel.visualizationType", + "type": "string", + "tags": [], + "label": "visualizationType", + "description": [], + "signature": [ + "\"lnsMetric\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.MetricChartModel.layers", + "type": "Object", + "tags": [], + "label": "layers", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.MetricLayerConfig", + "text": "MetricLayerConfig" + } + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.MetricLayerConfig", "type": "Interface", "tags": [], "label": "MetricLayerConfig", @@ -2819,7 +2893,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerConfig.data", + "id": "def-common.MetricLayerConfig.data", "type": "CompoundType", "tags": [], "label": "data", @@ -2843,7 +2917,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerConfig.options", + "id": "def-common.MetricLayerConfig.options", "type": "Object", "tags": [], "label": "options", @@ -2851,9 +2925,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.MetricLayerOptions", + "section": "def-common.MetricLayerOptions", "text": "MetricLayerOptions" }, " | undefined" @@ -2864,7 +2938,21 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerConfig.dataView", + "id": "def-common.MetricLayerConfig.layerType", + "type": "string", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"metricTrendline\" | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/metric_layer.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.MetricLayerConfig.dataView", "type": "Object", "tags": [], "label": "dataView", @@ -2890,7 +2978,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerOptions", + "id": "def-common.MetricLayerOptions", "type": "Interface", "tags": [], "label": "MetricLayerOptions", @@ -2901,7 +2989,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerOptions.backgroundColor", + "id": "def-common.MetricLayerOptions.backgroundColor", "type": "string", "tags": [], "label": "backgroundColor", @@ -2915,7 +3003,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerOptions.showTitle", + "id": "def-common.MetricLayerOptions.showTitle", "type": "CompoundType", "tags": [], "label": "showTitle", @@ -2929,7 +3017,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerOptions.showTrendLine", + "id": "def-common.MetricLayerOptions.showTrendLine", "type": "CompoundType", "tags": [], "label": "showTrendLine", @@ -2943,7 +3031,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.MetricLayerOptions.subtitle", + "id": "def-common.MetricLayerOptions.subtitle", "type": "string", "tags": [], "label": "subtitle", @@ -2960,7 +3048,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticChartColumn", + "id": "def-common.StaticChartColumn", "type": "Interface", "tags": [], "label": "StaticChartColumn", @@ -2968,25 +3056,25 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticChartColumn", + "section": "def-common.StaticChartColumn", "text": "StaticChartColumn" }, " extends ", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.BaseChartColumn", + "section": "def-common.BaseChartColumn", "text": "BaseChartColumn" }, "<", { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticValueConfig", + "section": "def-common.StaticValueConfig", "text": "StaticValueConfig" }, ">" @@ -2997,7 +3085,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticChartColumn.getData", + "id": "def-common.StaticChartColumn.getData", "type": "Function", "tags": [], "label": "getData", @@ -3026,7 +3114,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticChartColumn.getData.$1", + "id": "def-common.StaticChartColumn.getData.$1", "type": "string", "tags": [], "label": "id", @@ -3041,7 +3129,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticChartColumn.getData.$2", + "id": "def-common.StaticChartColumn.getData.$2", "type": "Object", "tags": [], "label": "baseLayer", @@ -3068,7 +3156,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.VisualizationAttributesBuilder", + "id": "def-common.VisualizationAttributesBuilder", "type": "Interface", "tags": [], "label": "VisualizationAttributesBuilder", @@ -3079,7 +3167,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.VisualizationAttributesBuilder.build", + "id": "def-common.VisualizationAttributesBuilder.build", "type": "Function", "tags": [], "label": "build", @@ -3148,10 +3236,90 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerConfig", + "id": "def-common.XYChartModel", "type": "Interface", "tags": [], - "label": "XYLayerConfig", + "label": "XYChartModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYChartModel", + "text": "XYChartModel" + }, + " extends ChartModelBase" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYChartModel.visualOptions", + "type": "Object", + "tags": [], + "label": "visualOptions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYVisualOptions", + "text": "XYVisualOptions" + }, + " | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYChartModel.visualizationType", + "type": "string", + "tags": [], + "label": "visualizationType", + "description": [], + "signature": [ + "\"lnsXY\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYChartModel.layers", + "type": "Array", + "tags": [], + "label": "layers", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYLayerConfig", + "text": "XYLayerConfig" + }, + "[]" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYDataLayerConfig", + "type": "Interface", + "tags": [], + "label": "XYDataLayerConfig", "description": [], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts", "deprecated": false, @@ -3159,7 +3327,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerConfig.data", + "id": "def-common.XYDataLayerConfig.data", "type": "Array", "tags": [], "label": "data", @@ -3167,9 +3335,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.FormulaValueConfig", + "section": "def-common.FormulaValueConfig", "text": "FormulaValueConfig" }, "[]" @@ -3180,7 +3348,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerConfig.options", + "id": "def-common.XYDataLayerConfig.options", "type": "Object", "tags": [], "label": "options", @@ -3188,9 +3356,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.XYLayerOptions", + "section": "def-common.XYLayerOptions", "text": "XYLayerOptions" }, " | undefined" @@ -3201,7 +3369,21 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerConfig.dataView", + "id": "def-common.XYDataLayerConfig.layerType", + "type": "string", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"data\" | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYDataLayerConfig.dataView", "type": "Object", "tags": [], "label": "dataView", @@ -3227,7 +3409,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerOptions", + "id": "def-common.XYLayerOptions", "type": "Interface", "tags": [], "label": "XYLayerOptions", @@ -3238,7 +3420,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerOptions.breakdown", + "id": "def-common.XYLayerOptions.breakdown", "type": "Object", "tags": [], "label": "breakdown", @@ -3252,7 +3434,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerOptions.buckets", + "id": "def-common.XYLayerOptions.buckets", "type": "Object", "tags": [], "label": "buckets", @@ -3266,7 +3448,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYLayerOptions.seriesType", + "id": "def-common.XYLayerOptions.seriesType", "type": "CompoundType", "tags": [], "label": "seriesType", @@ -3290,7 +3472,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayerConfig", + "id": "def-common.XYReferenceLinesLayerConfig", "type": "Interface", "tags": [], "label": "XYReferenceLinesLayerConfig", @@ -3301,7 +3483,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayerConfig.data", + "id": "def-common.XYReferenceLinesLayerConfig.data", "type": "Array", "tags": [], "label": "data", @@ -3309,9 +3491,9 @@ "signature": [ { "pluginId": "@kbn/lens-embeddable-utils", - "scope": "public", + "scope": "common", "docId": "kibKbnLensEmbeddableUtilsPluginApi", - "section": "def-public.StaticValueConfig", + "section": "def-common.StaticValueConfig", "text": "StaticValueConfig" }, "[]" @@ -3322,7 +3504,21 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYReferenceLinesLayerConfig.dataView", + "id": "def-common.XYReferenceLinesLayerConfig.layerType", + "type": "string", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"referenceLine\" | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_reference_lines_layer.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYReferenceLinesLayerConfig.dataView", "type": "Object", "tags": [], "label": "dataView", @@ -3348,7 +3544,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYVisualOptions", + "id": "def-common.XYVisualOptions", "type": "Interface", "tags": [], "label": "XYVisualOptions", @@ -3359,7 +3555,7 @@ "children": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYVisualOptions.lineInterpolation", + "id": "def-common.XYVisualOptions.lineInterpolation", "type": "CompoundType", "tags": [], "label": "lineInterpolation", @@ -3380,7 +3576,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYVisualOptions.missingValues", + "id": "def-common.XYVisualOptions.missingValues", "type": "CompoundType", "tags": [], "label": "missingValues", @@ -3401,7 +3597,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYVisualOptions.endValues", + "id": "def-common.XYVisualOptions.endValues", "type": "CompoundType", "tags": [], "label": "endValues", @@ -3422,7 +3618,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.XYVisualOptions.showDottedLine", + "id": "def-common.XYVisualOptions.showDottedLine", "type": "CompoundType", "tags": [], "label": "showDottedLine", @@ -3433,6 +3629,90 @@ "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYVisualOptions.valueLabels", + "type": "CompoundType", + "tags": [], + "label": "valueLabels", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.ValueLabelMode", + "text": "ValueLabelMode" + }, + " | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYVisualOptions.axisTitlesVisibilitySettings", + "type": "Object", + "tags": [], + "label": "axisTitlesVisibilitySettings", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.AxesSettingsConfig", + "text": "AxesSettingsConfig" + }, + " | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYVisualOptions.legend", + "type": "Object", + "tags": [], + "label": "legend", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.LegendConfig", + "text": "LegendConfig" + }, + " | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYVisualOptions.yLeftExtent", + "type": "Object", + "tags": [], + "label": "yLeftExtent", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfig", + "text": "AxisExtentConfig" + }, + " | undefined" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -3442,7 +3722,51 @@ "misc": [ { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.FormulaValueConfig", + "id": "def-common.ChartModel", + "type": "Type", + "tags": [], + "label": "ChartModel", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYChartModel", + "text": "XYChartModel" + }, + " | ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.MetricChartModel", + "text": "MetricChartModel" + } + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.ChartTypes", + "type": "Type", + "tags": [], + "label": "ChartTypes", + "description": [], + "signature": [ + "\"lnsXY\" | \"lnsMetric\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.FormulaValueConfig", "type": "Type", "tags": [], "label": "FormulaValueConfig", @@ -3467,7 +3791,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensAttributes", + "id": "def-common.LensAttributes", "type": "Type", "tags": [], "label": "LensAttributes", @@ -3532,7 +3856,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensLayerConfig", + "id": "def-common.LensLayerConfig", "type": "Type", "tags": [], "label": "LensLayerConfig", @@ -3561,7 +3885,7 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.LensVisualizationState", + "id": "def-common.LensVisualizationState", "type": "Type", "tags": [], "label": "LensVisualizationState", @@ -3590,7 +3914,37 @@ }, { "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-public.StaticValueConfig", + "id": "def-common.METRIC_ID", + "type": "string", + "tags": [], + "label": "METRIC_ID", + "description": [], + "signature": [ + "\"lnsMetric\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.METRIC_TREND_LINE_ID", + "type": "string", + "tags": [], + "label": "METRIC_TREND_LINE_ID", + "description": [], + "signature": [ + "\"metricTrendline\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.StaticValueConfig", "type": "Type", "tags": [], "label": "StaticValueConfig", @@ -3606,30 +3960,111 @@ }, " | undefined; reducedTimeRange?: string | undefined; timeScale?: ", "TimeScaleUnit", - " | undefined; format?: { id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined; }, \"formula\"> & { color?: string | undefined; value: string; }" + " | undefined; format?: { id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined; }, \"formula\"> & { color?: string | undefined; fill?: ", + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.FillStyle", + "text": "FillStyle" + }, + " | undefined; value: string; }" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.VisualizationTypes", + "type": "Type", + "tags": [], + "label": "VisualizationTypes", + "description": [], + "signature": [ + "\"lnsXY\" | \"lnsMetric\"" ], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XY_DATA_ID", + "type": "string", + "tags": [], + "label": "XY_DATA_ID", + "description": [], + "signature": [ + "\"data\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XY_ID", + "type": "string", + "tags": [], + "label": "XY_ID", + "description": [], + "signature": [ + "\"lnsXY\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XY_REFERENCE_LINE_ID", + "type": "string", + "tags": [], + "label": "XY_REFERENCE_LINE_ID", + "description": [], + "signature": [ + "\"referenceLine\"" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.XYLayerConfig", + "type": "Type", + "tags": [], + "label": "XYLayerConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYDataLayerConfig", + "text": "XYDataLayerConfig" + }, + " | ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.XYReferenceLinesLayerConfig", + "text": "XYReferenceLinesLayerConfig" + } + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] } } \ No newline at end of file diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index aa1233ffc36b..245cb51b174d 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; @@ -21,16 +21,16 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 158 | 0 | 155 | 0 | +| 181 | 0 | 178 | 0 | -## Client +## Common ### Classes - + ### Interfaces - + ### Consts, variables and types - + diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index bb27e52d7b24..473059eb685b 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index f0706e42dd29..93cd53b65679 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 8cbb1448f6f9..24b093aa0381 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index f509a205739f..3855522490a4 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index dff4e250a665..11438009d88b 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index 0300ff570e0d..20149cbf9fbb 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.devdocs.json b/api_docs/kbn_management_settings_components_field_input.devdocs.json index 06eb3024d269..6dc83478cd1b 100644 --- a/api_docs/kbn_management_settings_components_field_input.devdocs.json +++ b/api_docs/kbn_management_settings_components_field_input.devdocs.json @@ -117,6 +117,28 @@ "path": "packages/kbn-management/settings/components/field_input/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/management-settings-components-field-input", + "id": "def-common.FieldInputKibanaDependencies.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + "{ client: ", + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "common", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-common.IUiSettingsClient", + "text": "IUiSettingsClient" + }, + "; }" + ], + "path": "packages/kbn-management/settings/components/field_input/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -311,6 +333,55 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/management-settings-components-field-input", + "id": "def-common.FieldInputServices.validateChange", + "type": "Function", + "tags": [], + "label": "validateChange", + "description": [], + "signature": [ + "(key: string, value: any) => Promise<", + "ValueValidation", + ">" + ], + "path": "packages/kbn-management/settings/components/field_input/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/management-settings-components-field-input", + "id": "def-common.FieldInputServices.validateChange.$1", + "type": "string", + "tags": [], + "label": "key", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-management/settings/components/field_input/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/management-settings-components-field-input", + "id": "def-common.FieldInputServices.validateChange.$2", + "type": "Any", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-management/settings/components/field_input/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 996684cf890a..96a81ef93ade 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/platform-deployment-management](https://github.com/orgs/elasti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 20 | 0 | 5 | 0 | +| 24 | 1 | 9 | 0 | ## Common diff --git a/api_docs/kbn_management_settings_components_field_row.devdocs.json b/api_docs/kbn_management_settings_components_field_row.devdocs.json index 57ee28447a32..052a3e23ff50 100644 --- a/api_docs/kbn_management_settings_components_field_row.devdocs.json +++ b/api_docs/kbn_management_settings_components_field_row.devdocs.json @@ -80,7 +80,7 @@ "\nKibana-specific Provider that maps Kibana plugins and services to a {@link FieldRowProvider}." ], "signature": [ - "({ children, docLinks, notifications, }: React.PropsWithChildren<", + "({ children, docLinks, notifications, settings, }: React.PropsWithChildren<", { "pluginId": "@kbn/management-settings-components-field-row", "scope": "common", @@ -99,7 +99,7 @@ "id": "def-common.FieldRowKibanaProvider.$1", "type": "CompoundType", "tags": [], - "label": "{\n children,\n docLinks,\n notifications,\n}", + "label": "{\n children,\n docLinks,\n notifications,\n settings,\n}", "description": [], "signature": [ "React.PropsWithChildren<", diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index b7d9c63d46c7..82402e33795e 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 7b6d4111710b..b7c6d9f4d3ce 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index cd4c29c89a5e..1965a8a12667 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 3c40ac2affa6..bd928608544d 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index d3b0e6f85de4..43ffcc8181c6 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index e1707d5e5c4e..a56af6111049 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index d6c1d9205dfb..d46cdbea97d0 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 88eef8bd3746..4ec6de5ed69c 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.devdocs.json b/api_docs/kbn_mapbox_gl.devdocs.json index 18b71846c478..838e1f65579c 100644 --- a/api_docs/kbn_mapbox_gl.devdocs.json +++ b/api_docs/kbn_mapbox_gl.devdocs.json @@ -9009,7 +9009,7 @@ "label": "sourceDataType", "description": [], "signature": [ - "\"content\" | \"visibility\" | \"metadata\" | \"idle\"" + "\"content\" | \"metadata\" | \"visibility\" | \"idle\"" ], "path": "node_modules/maplibre-gl/dist/maplibre-gl.d.ts", "deprecated": false, diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 36922e692545..778bc1c3e703 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index c39dc03e509a..cb919d7e6726 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index a69c8cd6b562..4a5f66dea2cc 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index e779cc108399..950977bddced 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index ed4d9fefe747..01a67bc5692a 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index f160234bd3f7..81451f08c9d3 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.devdocs.json b/api_docs/kbn_ml_data_frame_analytics_utils.devdocs.json index c306defc55a5..2a2427105676 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.devdocs.json +++ b/api_docs/kbn_ml_data_frame_analytics_utils.devdocs.json @@ -2417,7 +2417,7 @@ "\nUnion type of JOB_MAP_NODE_TYPES" ], "signature": [ - "\"index\" | \"transform\" | \"analytics\" | \"trainedModel\" | \"ingestPipeline\"" + "\"index\" | \"transform\" | \"analytics\" | \"analytics-job-missing\" | \"trainedModel\" | \"ingestPipeline\"" ], "path": "x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts", "deprecated": false, @@ -2742,7 +2742,7 @@ "\nCustom enum for job map node types for the DFA map view" ], "signature": [ - "{ readonly ANALYTICS: \"analytics\"; readonly TRANSFORM: \"transform\"; readonly INDEX: \"index\"; readonly TRAINED_MODEL: \"trainedModel\"; readonly INGEST_PIPELINE: \"ingestPipeline\"; }" + "{ readonly ANALYTICS: \"analytics\"; readonly ANALYTICS_JOB_MISSING: \"analytics-job-missing\"; readonly TRANSFORM: \"transform\"; readonly INDEX: \"index\"; readonly TRAINED_MODEL: \"trainedModel\"; readonly INGEST_PIPELINE: \"ingestPipeline\"; }" ], "path": "x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts", "deprecated": false, diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 5a0f3fdffe95..6d1398f4ca71 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.devdocs.json b/api_docs/kbn_ml_data_grid.devdocs.json index 0e63c9f639c1..14fcad6d9b0a 100644 --- a/api_docs/kbn_ml_data_grid.devdocs.json +++ b/api_docs/kbn_ml_data_grid.devdocs.json @@ -347,10 +347,10 @@ }, { "parentPluginId": "@kbn/ml-data-grid", - "id": "def-common.getFieldsFromKibanaIndexPattern", + "id": "def-common.getFieldsFromKibanaDataView", "type": "Function", "tags": [], - "label": "getFieldsFromKibanaIndexPattern", + "label": "getFieldsFromKibanaDataView", "description": [ "\nRetrieves fields from a Kibana data view." ], @@ -371,7 +371,7 @@ "children": [ { "parentPluginId": "@kbn/ml-data-grid", - "id": "def-common.getFieldsFromKibanaIndexPattern.$1", + "id": "def-common.getFieldsFromKibanaDataView.$1", "type": "Object", "tags": [], "label": "dataView", @@ -2489,12 +2489,12 @@ }, { "parentPluginId": "@kbn/ml-data-grid", - "id": "def-common.UseIndexDataReturnType.indexPatternFields", + "id": "def-common.UseIndexDataReturnType.dataViewFields", "type": "Array", "tags": [], - "label": "indexPatternFields", + "label": "dataViewFields", "description": [ - "\nOptional index pattern fields." + "\nOptional data view fields." ], "signature": [ "string[] | undefined" diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index e0ca15fc4d75..6afb33bca916 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index fa09cdc394da..b2eec263ed36 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index cc6eb09ac8d3..3411da52c894 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index abb315ecc6a9..8a4857f1edd1 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 16e23cfc25c4..f800ea2462b8 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index 9bd7dd87854a..b9bdf21363fd 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 8d467f203c2b..451d0bd7cde3 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 0f87482f4ae3..22e19fc73ef5 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index c22ed444a384..3d91b2556be0 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 0b2a5c31fae6..361c186ecaf4 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 0867d6b273f7..81518d97f06d 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index de86a37513a8..a43358511404 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 2aea55e5a1e6..0c47bf9f7a44 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 0b2babc59f20..a52ac4141059 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 1a286951d586..2fada14cd384 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 0459040752e4..3a972441e599 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.devdocs.json b/api_docs/kbn_ml_trained_models_utils.devdocs.json index d2bb275d5a25..f0cfb869a14f 100644 --- a/api_docs/kbn_ml_trained_models_utils.devdocs.json +++ b/api_docs/kbn_ml_trained_models_utils.devdocs.json @@ -22,10 +22,10 @@ "interfaces": [ { "parentPluginId": "@kbn/ml-trained-models-utils", - "id": "def-common.GetElserOptions", + "id": "def-common.GetModelDownloadConfigOptions", "type": "Interface", "tags": [], - "label": "GetElserOptions", + "label": "GetModelDownloadConfigOptions", "description": [], "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", "deprecated": false, @@ -33,7 +33,7 @@ "children": [ { "parentPluginId": "@kbn/ml-trained-models-utils", - "id": "def-common.GetElserOptions.version", + "id": "def-common.GetModelDownloadConfigOptions.version", "type": "CompoundType", "tags": [], "label": "version", @@ -69,10 +69,15 @@ { "parentPluginId": "@kbn/ml-trained-models-utils", "id": "def-common.ModelDefinition.modelName", - "type": "string", + "type": "CompoundType", "tags": [], "label": "modelName", - "description": [], + "description": [ + "\nModel name, e.g. elser" + ], + "signature": [ + "\"elser\" | \"e5\"" + ], "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", "deprecated": false, "trackAdoption": false @@ -94,7 +99,9 @@ "type": "Uncategorized", "tags": [], "label": "config", - "description": [], + "description": [ + "\nDefault PUT model configuration" + ], "signature": [ "object" ], @@ -182,6 +189,34 @@ "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.license", + "type": "string", + "tags": [], + "label": "license", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ModelDefinition.type", + "type": "Object", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -261,6 +296,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/ml-trained-models-utils", + "id": "def-common.ElasticCuratedModelName", + "type": "Type", + "tags": [], + "label": "ElasticCuratedModelName", + "description": [], + "signature": [ + "\"elser\" | \"e5\"" + ], + "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/ml-trained-models-utils", "id": "def-common.ElasticModelId", @@ -314,7 +364,6 @@ "label": "ModelDefinitionResponse", "description": [], "signature": [ - "Omit<", { "pluginId": "@kbn/ml-trained-models-utils", "scope": "common", @@ -322,7 +371,7 @@ "section": "def-common.ModelDefinition", "text": "ModelDefinition" }, - ", \"modelName\"> & { name: string; }" + " & { model_id: string; }" ], "path": "x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts", "deprecated": false, diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 0a09588940bd..31cbb1b0a3cf 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 29 | 0 | 29 | 0 | +| 32 | 0 | 30 | 0 | ## Common diff --git a/api_docs/kbn_ml_ui_actions.devdocs.json b/api_docs/kbn_ml_ui_actions.devdocs.json new file mode 100644 index 000000000000..6fe15ef82553 --- /dev/null +++ b/api_docs/kbn_ml_ui_actions.devdocs.json @@ -0,0 +1,298 @@ +{ + "id": "@kbn/ml-ui-actions", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CategorizeFieldContext", + "type": "Interface", + "tags": [], + "label": "CategorizeFieldContext", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CategorizeFieldContext.field", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewField", + "text": "DataViewField" + } + ], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CategorizeFieldContext.dataView", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CategorizeFieldContext.originatingApp", + "type": "string", + "tags": [], + "label": "originatingApp", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CategorizeFieldContext.additionalFilter", + "type": "Object", + "tags": [], + "label": "additionalFilter", + "description": [], + "signature": [ + "{ from: number; to: number; field?: { name: string; value: string; } | undefined; } | undefined" + ], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CreateCategorizationADJobContext", + "type": "Interface", + "tags": [], + "label": "CreateCategorizationADJobContext", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CreateCategorizationADJobContext.field", + "type": "Object", + "tags": [], + "label": "field", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewField", + "text": "DataViewField" + } + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CreateCategorizationADJobContext.dataView", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CreateCategorizationADJobContext.query", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "QueryDslQueryContainer" + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CreateCategorizationADJobContext.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + "{ from: string; to: string; mode?: \"absolute\" | \"relative\" | undefined; }" + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.ACTION_CATEGORIZE_FIELD", + "type": "string", + "tags": [], + "label": "ACTION_CATEGORIZE_FIELD", + "description": [], + "signature": [ + "\"ACTION_CATEGORIZE_FIELD\"" + ], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CATEGORIZE_FIELD_TRIGGER", + "type": "string", + "tags": [], + "label": "CATEGORIZE_FIELD_TRIGGER", + "description": [], + "signature": [ + "\"CATEGORIZE_FIELD_TRIGGER\"" + ], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION", + "type": "string", + "tags": [], + "label": "CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION", + "description": [], + "signature": [ + "\"createMLADCategorizationJobAction\"" + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER", + "type": "string", + "tags": [], + "label": "CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER", + "description": [], + "signature": [ + "\"CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER\"" + ], + "path": "x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.categorizeFieldTrigger", + "type": "Object", + "tags": [], + "label": "categorizeFieldTrigger", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.categorizeFieldTrigger.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.categorizeFieldTrigger.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-ui-actions", + "id": "def-common.categorizeFieldTrigger.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ] + } +} \ No newline at end of file diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx new file mode 100644 index 000000000000..c865df74fff3 --- /dev/null +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnMlUiActionsPluginApi +slug: /kibana-dev-docs/api/kbn-ml-ui-actions +title: "@kbn/ml-ui-actions" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/ml-ui-actions plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] +--- +import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; + + + +Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 18 | 0 | 18 | 0 | + +## Common + +### Objects + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 17b5193dbc83..e7c0e0c3f1ff 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index f8ef704a8ff1..13ba695d0eb7 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 56e5bbb6482f..116e0fb3717c 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.devdocs.json b/api_docs/kbn_observability_alert_details.devdocs.json index 29dfc1bbc379..dc03a42a119e 100644 --- a/api_docs/kbn_observability_alert_details.devdocs.json +++ b/api_docs/kbn_observability_alert_details.devdocs.json @@ -151,55 +151,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/observability-alert-details", - "id": "def-common.getPaddedAlertTimeRange", - "type": "Function", - "tags": [], - "label": "getPaddedAlertTimeRange", - "description": [], - "signature": [ - "(alertStart: string, alertEnd?: string | undefined) => ", - "TimeRange" - ], - "path": "x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/observability-alert-details", - "id": "def-common.getPaddedAlertTimeRange.$1", - "type": "string", - "tags": [], - "label": "alertStart", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/observability-alert-details", - "id": "def-common.getPaddedAlertTimeRange.$2", - "type": "string", - "tags": [], - "label": "alertEnd", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/observability-alert-details", "id": "def-common.useAlertsHistory", diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index ccda394924ff..d86970c1e189 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 13 | 0 | 13 | 3 | +| 10 | 0 | 10 | 2 | ## Common diff --git a/api_docs/kbn_observability_alerting_test_data.devdocs.json b/api_docs/kbn_observability_alerting_test_data.devdocs.json index 96da803aa4b6..d75f51f28846 100644 --- a/api_docs/kbn_observability_alerting_test_data.devdocs.json +++ b/api_docs/kbn_observability_alerting_test_data.devdocs.json @@ -434,7 +434,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; filter: string; aggType: ", "Aggregators", @@ -597,7 +597,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; filter: string; aggType: ", "Aggregators", @@ -774,7 +774,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; filter: string; aggType: ", "Aggregators", @@ -937,7 +937,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; field: string; aggType: ", "Aggregators", @@ -1100,7 +1100,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; field: string; aggType: ", "Aggregators", @@ -1277,7 +1277,7 @@ "label": "criteria", "description": [], "signature": [ - "{ aggType: string; comparator: ", + "{ comparator: ", "Comparator", "; threshold: number[]; timeSize: number; timeUnit: string; metrics: { name: string; field: string; aggType: ", "Aggregators", diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 596f990e31fa..7c0da03a2097 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.devdocs.json b/api_docs/kbn_observability_get_padded_alert_time_range_util.devdocs.json new file mode 100644 index 000000000000..932169e8a5c2 --- /dev/null +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.devdocs.json @@ -0,0 +1,77 @@ +{ + "id": "@kbn/observability-get-padded-alert-time-range-util", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/observability-get-padded-alert-time-range-util", + "id": "def-common.getPaddedAlertTimeRange", + "type": "Function", + "tags": [], + "label": "getPaddedAlertTimeRange", + "description": [], + "signature": [ + "(alertStart: string, alertEnd?: string | undefined) => ", + "TimeRange" + ], + "path": "x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/observability-get-padded-alert-time-range-util", + "id": "def-common.getPaddedAlertTimeRange.$1", + "type": "string", + "tags": [], + "label": "alertStart", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/observability-get-padded-alert-time-range-util", + "id": "def-common.getPaddedAlertTimeRange.$2", + "type": "string", + "tags": [], + "label": "alertEnd", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx new file mode 100644 index 000000000000..2fb4e6a3b67e --- /dev/null +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnObservabilityGetPaddedAlertTimeRangeUtilPluginApi +slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util +title: "@kbn/observability-get-padded-alert-time-range-util" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] +--- +import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; + + + +Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 3 | 1 | + +## Common + +### Functions + + diff --git a/api_docs/kbn_openapi_bundler.devdocs.json b/api_docs/kbn_openapi_bundler.devdocs.json new file mode 100644 index 000000000000..bfb8dad96559 --- /dev/null +++ b/api_docs/kbn_openapi_bundler.devdocs.json @@ -0,0 +1,123 @@ +{ + "id": "@kbn/openapi-bundler", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.bundle", + "type": "Function", + "tags": [], + "label": "bundle", + "description": [], + "signature": [ + "(config: ", + { + "pluginId": "@kbn/openapi-bundler", + "scope": "common", + "docId": "kibKbnOpenapiBundlerPluginApi", + "section": "def-common.BundlerConfig", + "text": "BundlerConfig" + }, + ") => Promise" + ], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.bundle.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [], + "signature": [ + { + "pluginId": "@kbn/openapi-bundler", + "scope": "common", + "docId": "kibKbnOpenapiBundlerPluginApi", + "section": "def-common.BundlerConfig", + "text": "BundlerConfig" + } + ], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.BundlerConfig", + "type": "Interface", + "tags": [], + "label": "BundlerConfig", + "description": [], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.BundlerConfig.rootDir", + "type": "string", + "tags": [], + "label": "rootDir", + "description": [], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.BundlerConfig.sourceGlob", + "type": "string", + "tags": [], + "label": "sourceGlob", + "description": [], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/openapi-bundler", + "id": "def-common.BundlerConfig.outputFilePath", + "type": "string", + "tags": [], + "label": "outputFilePath", + "description": [], + "path": "packages/kbn-openapi-bundler/src/openapi_bundler.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx new file mode 100644 index 000000000000..fdc2e8165818 --- /dev/null +++ b/api_docs/kbn_openapi_bundler.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnOpenapiBundlerPluginApi +slug: /kibana-dev-docs/api/kbn-openapi-bundler +title: "@kbn/openapi-bundler" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/openapi-bundler plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] +--- +import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; + + + +Contact [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 6 | 0 | 6 | 0 | + +## Common + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index a38da4be5304..d0830f3769f9 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 9f6322c9f087..e991a61b7e74 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 7763f9b79e4e..a8ee017c88e1 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index df617bbac03d..14f22924ee3b 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.devdocs.json b/api_docs/kbn_panel_loader.devdocs.json new file mode 100644 index 000000000000..5282b2609136 --- /dev/null +++ b/api_docs/kbn_panel_loader.devdocs.json @@ -0,0 +1,87 @@ +{ + "id": "@kbn/panel-loader", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/panel-loader", + "id": "def-public.PanelLoader", + "type": "Function", + "tags": [], + "label": "PanelLoader", + "description": [], + "signature": [ + "(props: { showShadow?: boolean | undefined; dataTestSubj?: string | undefined; }) => JSX.Element" + ], + "path": "packages/kbn-panel-loader/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/panel-loader", + "id": "def-public.PanelLoader.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "packages/kbn-panel-loader/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/panel-loader", + "id": "def-public.PanelLoader.$1.showShadow", + "type": "CompoundType", + "tags": [], + "label": "showShadow", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-panel-loader/index.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/panel-loader", + "id": "def-public.PanelLoader.$1.dataTestSubj", + "type": "string", + "tags": [], + "label": "dataTestSubj", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-panel-loader/index.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx new file mode 100644 index 000000000000..222c91aff3a4 --- /dev/null +++ b/api_docs/kbn_panel_loader.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnPanelLoaderPluginApi +slug: /kibana-dev-docs/api/kbn-panel-loader +title: "@kbn/panel-loader" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/panel-loader plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] +--- +import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; + + + +Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 4 | 0 | 4 | 0 | + +## Client + +### Functions + + diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 4556ae39a65e..c0eda21c5564 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 14421a7c8062..d141544904b6 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index ec8306b1fd83..f5fb78766e63 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.devdocs.json b/api_docs/kbn_profiling_utils.devdocs.json index 597124dd7517..e07794efc29b 100644 --- a/api_docs/kbn_profiling_utils.devdocs.json +++ b/api_docs/kbn_profiling_utils.devdocs.json @@ -21,267 +21,29 @@ "functions": [ { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createBaseFlameGraph", + "id": "def-common.convertTonsToKgs", "type": "Function", "tags": [], - "label": "createBaseFlameGraph", - "description": [ - "\ncreateBaseFlameGraph encapsulates the tree representation into a serialized form." - ], + "label": "convertTonsToKgs", + "description": [], "signature": [ - "(tree: ", - { - "pluginId": "@kbn/profiling-utils", - "scope": "common", - "docId": "kibKbnProfilingUtilsPluginApi", - "section": "def-common.CalleeTree", - "text": "CalleeTree" - }, - ", samplingRate: number, totalSeconds: number) => ", - { - "pluginId": "@kbn/profiling-utils", - "scope": "common", - "docId": "kibKbnProfilingUtilsPluginApi", - "section": "def-common.BaseFlameGraph", - "text": "BaseFlameGraph" - } + "(value: number) => number" ], - "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "path": "packages/kbn-profiling-utils/common/utils.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createBaseFlameGraph.$1", - "type": "Object", - "tags": [], - "label": "tree", - "description": [ - "CalleeTree" - ], - "signature": [ - { - "pluginId": "@kbn/profiling-utils", - "scope": "common", - "docId": "kibKbnProfilingUtilsPluginApi", - "section": "def-common.CalleeTree", - "text": "CalleeTree" - } - ], - "path": "packages/kbn-profiling-utils/common/flamegraph.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createBaseFlameGraph.$2", + "id": "def-common.convertTonsToKgs.$1", "type": "number", "tags": [], - "label": "samplingRate", - "description": [ - "number" - ], - "signature": [ - "number" - ], - "path": "packages/kbn-profiling-utils/common/flamegraph.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createBaseFlameGraph.$3", - "type": "number", - "tags": [], - "label": "totalSeconds", - "description": [ - "number" - ], - "signature": [ - "number" - ], - "path": "packages/kbn-profiling-utils/common/flamegraph.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [ - "BaseFlameGraph" - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree", - "type": "Function", - "tags": [], - "label": "createCalleeTree", - "description": [ - "\nCreate a callee tree" - ], - "signature": [ - "(events: Map, stackTraces: Map, stackFrames: Map, executables: Map, totalFrames: number, samplingRate: number) => ", - { - "pluginId": "@kbn/profiling-utils", - "scope": "common", - "docId": "kibKbnProfilingUtilsPluginApi", - "section": "def-common.CalleeTree", - "text": "CalleeTree" - } - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$1", - "type": "Object", - "tags": [], - "label": "events", - "description": [ - "Map" - ], - "signature": [ - "Map" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$2", - "type": "Object", - "tags": [], - "label": "stackTraces", - "description": [ - "Map" - ], - "signature": [ - "Map" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$3", - "type": "Object", - "tags": [], - "label": "stackFrames", - "description": [ - "Map" - ], - "signature": [ - "Map" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$4", - "type": "Object", - "tags": [], - "label": "executables", - "description": [ - "Map" - ], - "signature": [ - "Map" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$5", - "type": "number", - "tags": [], - "label": "totalFrames", - "description": [ - "number" - ], - "signature": [ - "number" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.createCalleeTree.$6", - "type": "number", - "tags": [], - "label": "samplingRate", - "description": [ - "number" - ], + "label": "value", + "description": [], "signature": [ "number" ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/utils.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1449,267 +1211,113 @@ "trackAdoption": false }, { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.BaseFlameGraph.SelfCPU", - "type": "number", - "tags": [], - "label": "SelfCPU", - "description": [], - "path": "packages/kbn-profiling-utils/common/flamegraph.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree", - "type": "Interface", - "tags": [], - "label": "CalleeTree", - "description": [ - "\nCallee tree" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.Size", - "type": "number", - "tags": [], - "label": "Size", - "description": [ - "size" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.Edges", - "type": "Array", - "tags": [], - "label": "Edges", - "description": [ - "edges" - ], - "signature": [ - "Map[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.FileID", - "type": "Array", - "tags": [], - "label": "FileID", - "description": [ - "file ids" - ], - "signature": [ - "string[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.FrameType", - "type": "Array", - "tags": [], - "label": "FrameType", - "description": [ - "frame types" - ], - "signature": [ - "number[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.Inline", - "type": "Array", - "tags": [], - "label": "Inline", - "description": [ - "inlines" - ], - "signature": [ - "boolean[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.ExeFilename", - "type": "Array", - "tags": [], - "label": "ExeFilename", - "description": [ - "executable file names" - ], - "signature": [ - "string[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.AddressOrLine", - "type": "Array", - "tags": [], - "label": "AddressOrLine", - "description": [ - "address or lines" - ], - "signature": [ - "number[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.FunctionName", - "type": "Array", - "tags": [], - "label": "FunctionName", - "description": [ - "function names" - ], - "signature": [ - "string[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.BaseFlameGraph.SelfCPU", + "type": "number", + "tags": [], + "label": "SelfCPU", + "description": [], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.FunctionOffset", + "id": "def-common.BaseFlameGraph.AnnualCO2TonsExclusive", "type": "Array", "tags": [], - "label": "FunctionOffset", - "description": [ - "function offsets" - ], + "label": "AnnualCO2TonsExclusive", + "description": [], "signature": [ "number[]" ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.SourceFilename", + "id": "def-common.BaseFlameGraph.AnnualCO2TonsInclusive", "type": "Array", "tags": [], - "label": "SourceFilename", - "description": [ - "source file names" - ], + "label": "AnnualCO2TonsInclusive", + "description": [], "signature": [ - "string[]" + "number[]" ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.SourceLine", + "id": "def-common.BaseFlameGraph.AnnualCostsUSDInclusive", "type": "Array", "tags": [], - "label": "SourceLine", - "description": [ - "source lines" - ], + "label": "AnnualCostsUSDInclusive", + "description": [], "signature": [ "number[]" ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.CountInclusive", + "id": "def-common.BaseFlameGraph.AnnualCostsUSDExclusive", "type": "Array", "tags": [], - "label": "CountInclusive", - "description": [ - "total cpu" - ], + "label": "AnnualCostsUSDExclusive", + "description": [], "signature": [ "number[]" ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.CountExclusive", - "type": "Array", + "id": "def-common.BaseFlameGraph.SelfAnnualCO2Tons", + "type": "number", "tags": [], - "label": "CountExclusive", - "description": [ - "self cpu" - ], - "signature": [ - "number[]" - ], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "label": "SelfAnnualCO2Tons", + "description": [], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.TotalSamples", + "id": "def-common.BaseFlameGraph.TotalAnnualCO2Tons", "type": "number", "tags": [], - "label": "TotalSamples", + "label": "TotalAnnualCO2Tons", "description": [], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.TotalCPU", + "id": "def-common.BaseFlameGraph.SelfAnnualCostsUSD", "type": "number", "tags": [], - "label": "TotalCPU", + "label": "SelfAnnualCostsUSD", "description": [], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "@kbn/profiling-utils", - "id": "def-common.CalleeTree.SelfCPU", + "id": "def-common.BaseFlameGraph.TotalAnnualCostsUSD", "type": "number", "tags": [], - "label": "SelfCPU", + "label": "TotalAnnualCostsUSD", "description": [], - "path": "packages/kbn-profiling-utils/common/callee.ts", + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false } @@ -1863,14 +1471,15 @@ "section": "def-common.ElasticFlameGraph", "text": "ElasticFlameGraph" }, - " extends ", + " extends Omit<", { "pluginId": "@kbn/profiling-utils", "scope": "common", "docId": "kibKbnProfilingUtilsPluginApi", "section": "def-common.BaseFlameGraph", "text": "BaseFlameGraph" - } + }, + ", \"AnnualCO2TonsExclusive\" | \"AnnualCO2TonsInclusive\" | \"SelfAnnualCO2Tons\" | \"TotalAnnualCO2Tons\" | \"AnnualCostsUSDInclusive\" | \"AnnualCostsUSDExclusive\">" ], "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, @@ -1907,6 +1516,84 @@ "path": "packages/kbn-profiling-utils/common/flamegraph.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.SelfAnnualCO2KgsItems", + "type": "Array", + "tags": [], + "label": "SelfAnnualCO2KgsItems", + "description": [], + "signature": [ + "number[]" + ], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.TotalAnnualCO2KgsItems", + "type": "Array", + "tags": [], + "label": "TotalAnnualCO2KgsItems", + "description": [], + "signature": [ + "number[]" + ], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.SelfAnnualCostsUSDItems", + "type": "Array", + "tags": [], + "label": "SelfAnnualCostsUSDItems", + "description": [], + "signature": [ + "number[]" + ], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.TotalAnnualCostsUSDItems", + "type": "Array", + "tags": [], + "label": "TotalAnnualCostsUSDItems", + "description": [], + "signature": [ + "number[]" + ], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.SelfAnnualCO2Kgs", + "type": "number", + "tags": [], + "label": "SelfAnnualCO2Kgs", + "description": [], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.ElasticFlameGraph.TotalAnnualCO2Kgs", + "type": "number", + "tags": [], + "label": "TotalAnnualCO2Kgs", + "description": [], + "path": "packages/kbn-profiling-utils/common/flamegraph.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2459,6 +2146,39 @@ "path": "packages/kbn-profiling-utils/common/profiling.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.StackTrace.selfAnnualCO2Kgs", + "type": "number", + "tags": [], + "label": "selfAnnualCO2Kgs", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.StackTrace.selfAnnualCostUSD", + "type": "number", + "tags": [], + "label": "selfAnnualCostUSD", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.StackTrace.Count", + "type": "number", + "tags": [], + "label": "Count", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2637,6 +2357,28 @@ "path": "packages/kbn-profiling-utils/common/functions.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.TopNFunctions.totalAnnualCO2Kgs", + "type": "number", + "tags": [], + "label": "totalAnnualCO2Kgs", + "description": [], + "path": "packages/kbn-profiling-utils/common/functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.TopNFunctions.totalAnnualCostUSD", + "type": "number", + "tags": [], + "label": "totalAnnualCostUSD", + "description": [], + "path": "packages/kbn-profiling-utils/common/functions.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2699,6 +2441,18 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.TopNComparisonFunctionSortField", + "type": "Enum", + "tags": [], + "label": "TopNComparisonFunctionSortField", + "description": [], + "path": "packages/kbn-profiling-utils/common/functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/profiling-utils", "id": "def-common.TopNFunctionSortField", @@ -2986,10 +2740,119 @@ "path": "packages/kbn-profiling-utils/common/profiling.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.emptyStackTrace.selfAnnualCO2Kgs", + "type": "number", + "tags": [], + "label": "selfAnnualCO2Kgs", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.emptyStackTrace.selfAnnualCostUSD", + "type": "number", + "tags": [], + "label": "selfAnnualCostUSD", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.emptyStackTrace.Count", + "type": "number", + "tags": [], + "label": "Count", + "description": [], + "path": "packages/kbn-profiling-utils/common/profiling.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/profiling-utils", + "id": "def-common.topNComparisonFunctionSortFieldRt", + "type": "Object", + "tags": [], + "label": "topNComparisonFunctionSortFieldRt", + "description": [], + "signature": [ + "UnionC", + "<[", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonRank>, ", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonFrame>, ", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonSamples>, ", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonSelfCPU>, ", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonTotalCPU>, ", + "LiteralC", + "<", + { + "pluginId": "@kbn/profiling-utils", + "scope": "common", + "docId": "kibKbnProfilingUtilsPluginApi", + "section": "def-common.TopNComparisonFunctionSortField", + "text": "TopNComparisonFunctionSortField" + }, + ".ComparisonDiff>]>" + ], + "path": "packages/kbn-profiling-utils/common/functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/profiling-utils", "id": "def-common.topNFunctionSortFieldRt", diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 86badc0e585e..4923c3c61c93 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 171 | 0 | 28 | 0 | +| 169 | 0 | 51 | 0 | ## Common diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 67a8c86aaf8b..a0be0db7cf90 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 2575b407c76e..4c1cde63e916 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index b0afe199e9ad..eef67c84e4aa 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 36e77747123b..ff3bf4535581 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index a87316950a55..121af830f9aa 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 172ff21e7a51..c20119cad219 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index b0eb24de3190..c6d17d9ef2d5 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index b72b1e56e37a..a601f321f51e 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index dc8ae220028e..cbb2021aa2c4 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index b70dc4ee827a..1e12c79a8e92 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index bc0a310b96c7..8ac0fcc4b910 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 04502f0b603d..edd12948f48c 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index cbabbb3542a2..f7160a00036f 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index e59358e3bcaf..144e84dfe2c7 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 19723d89f587..9c71af420d0d 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 6112c4f0bfc3..9ecb739d27e4 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index e80e700bd2cf..c96ff0a71e78 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index 086d6edf5d3a..990ff14d4825 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 33f9aecbbc29..7a57ab76671d 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index c67ab41fcf43..1defc8451f0f 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 6861b7b78972..2a7dbbad485b 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index d3e6352855a0..118d99a043a7 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index a99eafa2538e..de8b56a04c2e 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index e7cf47e62c84..fd40bcd39699 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index c93ae4816084..a6df33c34234 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.devdocs.json b/api_docs/kbn_rule_data_utils.devdocs.json index 249759a3164f..0f5c00269876 100644 --- a/api_docs/kbn_rule_data_utils.devdocs.json +++ b/api_docs/kbn_rule_data_utils.devdocs.json @@ -1361,6 +1361,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/rule-data-utils", + "id": "def-common.ALERT_WORKFLOW_ASSIGNEE_IDS", + "type": "string", + "tags": [], + "label": "ALERT_WORKFLOW_ASSIGNEE_IDS", + "description": [], + "signature": [ + "\"kibana.alert.workflow_assignee_ids\"" + ], + "path": "packages/kbn-rule-data-utils/src/default_alerts_as_data.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/rule-data-utils", "id": "def-common.ALERT_WORKFLOW_REASON", @@ -1474,7 +1489,7 @@ "label": "DefaultAlertFieldName", "description": [], "signature": [ - "\"@timestamp\" | \"kibana\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.producer\" | \"kibana.alert.rule.revision\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.status\" | \"kibana.alert.uuid\" | \"kibana.space_ids\" | \"kibana.alert.action_group\" | \"kibana.alert.case_ids\" | \"kibana.alert.duration.us\" | \"kibana.alert.end\" | \"kibana.alert.flapping\" | \"kibana.alert.flapping_history\" | \"kibana.alert.last_detected\" | \"kibana.alert.maintenance_window_ids\" | \"kibana.alert.reason\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.tags\" | \"kibana.alert.start\" | \"kibana.alert.time_range\" | \"kibana.alert.url\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_tags\" | \"kibana.version\" | \"kibana.alert\" | \"kibana.alert.rule\"" + "\"@timestamp\" | \"kibana\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.producer\" | \"kibana.alert.rule.revision\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.status\" | \"kibana.alert.uuid\" | \"kibana.space_ids\" | \"kibana.alert.action_group\" | \"kibana.alert.case_ids\" | \"kibana.alert.duration.us\" | \"kibana.alert.end\" | \"kibana.alert.flapping\" | \"kibana.alert.flapping_history\" | \"kibana.alert.last_detected\" | \"kibana.alert.maintenance_window_ids\" | \"kibana.alert.reason\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.tags\" | \"kibana.alert.start\" | \"kibana.alert.time_range\" | \"kibana.alert.url\" | \"kibana.alert.workflow_assignee_ids\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_tags\" | \"kibana.version\" | \"kibana.alert\" | \"kibana.alert.rule\"" ], "path": "packages/kbn-rule-data-utils/src/default_alerts_as_data.ts", "deprecated": false, @@ -1699,7 +1714,7 @@ "label": "TechnicalRuleDataFieldName", "description": [], "signature": [ - "\"@timestamp\" | \"event.action\" | \"tags\" | \"kibana\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.producer\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.status\" | \"kibana.alert.uuid\" | \"kibana.space_ids\" | \"event.kind\" | \"kibana.alert.action_group\" | \"kibana.alert.case_ids\" | \"kibana.alert.duration.us\" | \"kibana.alert.end\" | \"kibana.alert.flapping\" | \"kibana.alert.maintenance_window_ids\" | \"kibana.alert.reason\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.tags\" | \"kibana.alert.start\" | \"kibana.alert.time_range\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_tags\" | \"kibana.version\" | \"kibana.alert.context\" | \"kibana.alert.evaluation.threshold\" | \"kibana.alert.evaluation.value\" | \"kibana.alert.evaluation.values\" | \"kibana.alert.group\" | \"ecs.version\" | \"kibana.alert.risk_score\" | \"kibana.alert.rule.author\" | \"kibana.alert.rule.created_at\" | \"kibana.alert.rule.created_by\" | \"kibana.alert.rule.description\" | \"kibana.alert.rule.enabled\" | \"kibana.alert.rule.from\" | \"kibana.alert.rule.interval\" | \"kibana.alert.rule.license\" | \"kibana.alert.rule.note\" | \"kibana.alert.rule.references\" | \"kibana.alert.rule.rule_id\" | \"kibana.alert.rule.rule_name_override\" | \"kibana.alert.rule.to\" | \"kibana.alert.rule.type\" | \"kibana.alert.rule.updated_at\" | \"kibana.alert.rule.updated_by\" | \"kibana.alert.rule.version\" | \"kibana.alert.severity\" | \"kibana.alert.suppression.docs_count\" | \"kibana.alert.suppression.end\" | \"kibana.alert.suppression.start\" | \"kibana.alert.suppression.terms.field\" | \"kibana.alert.suppression.terms.value\" | \"kibana.alert.system_status\" | \"kibana.alert.workflow_reason\" | \"kibana.alert.workflow_user\" | \"event.module\" | \"kibana.alert.rule.threat.framework\" | \"kibana.alert.rule.threat.tactic.id\" | \"kibana.alert.rule.threat.tactic.name\" | \"kibana.alert.rule.threat.tactic.reference\" | \"kibana.alert.rule.threat.technique.id\" | \"kibana.alert.rule.threat.technique.name\" | \"kibana.alert.rule.threat.technique.reference\" | \"kibana.alert.rule.threat.technique.subtechnique.id\" | \"kibana.alert.rule.threat.technique.subtechnique.name\" | \"kibana.alert.rule.threat.technique.subtechnique.reference\" | \"kibana.alert.building_block_type\" | \"kibana.alert\" | \"kibana.alert.rule\" | \"kibana.alert.suppression.terms\" | \"kibana.alert.group.field\" | \"kibana.alert.group.value\" | \"kibana.alert.rule.exceptions_list\" | \"kibana.alert.rule.namespace\"" + "\"@timestamp\" | \"event.action\" | \"tags\" | \"kibana\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.producer\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.status\" | \"kibana.alert.uuid\" | \"kibana.space_ids\" | \"event.kind\" | \"kibana.alert.action_group\" | \"kibana.alert.case_ids\" | \"kibana.alert.duration.us\" | \"kibana.alert.end\" | \"kibana.alert.flapping\" | \"kibana.alert.maintenance_window_ids\" | \"kibana.alert.reason\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.tags\" | \"kibana.alert.start\" | \"kibana.alert.time_range\" | \"kibana.alert.workflow_assignee_ids\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_tags\" | \"kibana.version\" | \"kibana.alert.context\" | \"kibana.alert.evaluation.threshold\" | \"kibana.alert.evaluation.value\" | \"kibana.alert.evaluation.values\" | \"kibana.alert.group\" | \"ecs.version\" | \"kibana.alert.risk_score\" | \"kibana.alert.rule.author\" | \"kibana.alert.rule.created_at\" | \"kibana.alert.rule.created_by\" | \"kibana.alert.rule.description\" | \"kibana.alert.rule.enabled\" | \"kibana.alert.rule.from\" | \"kibana.alert.rule.interval\" | \"kibana.alert.rule.license\" | \"kibana.alert.rule.note\" | \"kibana.alert.rule.references\" | \"kibana.alert.rule.rule_id\" | \"kibana.alert.rule.rule_name_override\" | \"kibana.alert.rule.to\" | \"kibana.alert.rule.type\" | \"kibana.alert.rule.updated_at\" | \"kibana.alert.rule.updated_by\" | \"kibana.alert.rule.version\" | \"kibana.alert.severity\" | \"kibana.alert.suppression.docs_count\" | \"kibana.alert.suppression.end\" | \"kibana.alert.suppression.start\" | \"kibana.alert.suppression.terms.field\" | \"kibana.alert.suppression.terms.value\" | \"kibana.alert.system_status\" | \"kibana.alert.workflow_reason\" | \"kibana.alert.workflow_user\" | \"event.module\" | \"kibana.alert.rule.threat.framework\" | \"kibana.alert.rule.threat.tactic.id\" | \"kibana.alert.rule.threat.tactic.name\" | \"kibana.alert.rule.threat.tactic.reference\" | \"kibana.alert.rule.threat.technique.id\" | \"kibana.alert.rule.threat.technique.name\" | \"kibana.alert.rule.threat.technique.reference\" | \"kibana.alert.rule.threat.technique.subtechnique.id\" | \"kibana.alert.rule.threat.technique.subtechnique.name\" | \"kibana.alert.rule.threat.technique.subtechnique.reference\" | \"kibana.alert.building_block_type\" | \"kibana.alert\" | \"kibana.alert.rule\" | \"kibana.alert.suppression.terms\" | \"kibana.alert.group.field\" | \"kibana.alert.group.value\" | \"kibana.alert.rule.exceptions_list\" | \"kibana.alert.rule.namespace\"" ], "path": "packages/kbn-rule-data-utils/src/technical_field_names.ts", "deprecated": false, diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index d542afec010c..32d8ab1e5dd3 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detections-response](https://github.com/orgs/elastic/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 116 | 0 | 113 | 0 | +| 117 | 0 | 114 | 0 | ## Common diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 3c377155867d..3a720c15700e 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.devdocs.json b/api_docs/kbn_search_api_panels.devdocs.json index 8558d593d429..8013e6c49470 100644 --- a/api_docs/kbn_search_api_panels.devdocs.json +++ b/api_docs/kbn_search_api_panels.devdocs.json @@ -279,7 +279,7 @@ "label": "IngestData", "description": [], "signature": [ - "({ codeSnippet, selectedLanguage, setSelectedLanguage, docLinks, assetBasePath, application, sharePlugin, languages, consoleRequest, }: React.PropsWithChildren) => JSX.Element" + "({ codeSnippet, selectedLanguage, setSelectedLanguage, docLinks, assetBasePath, application, sharePlugin, languages, consoleRequest, additionalIngestionPanel, }: React.PropsWithChildren) => JSX.Element" ], "path": "packages/kbn-search-api-panels/components/ingest_data.tsx", "deprecated": false, @@ -290,7 +290,7 @@ "id": "def-common.IngestData.$1", "type": "CompoundType", "tags": [], - "label": "{\n codeSnippet,\n selectedLanguage,\n setSelectedLanguage,\n docLinks,\n assetBasePath,\n application,\n sharePlugin,\n languages,\n consoleRequest,\n}", + "label": "{\n codeSnippet,\n selectedLanguage,\n setSelectedLanguage,\n docLinks,\n assetBasePath,\n application,\n sharePlugin,\n languages,\n consoleRequest,\n additionalIngestionPanel,\n}", "description": [], "signature": [ "React.PropsWithChildren" @@ -306,29 +306,29 @@ }, { "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.InstallClientPanel", + "id": "def-common.IngestionsPanel", "type": "Function", "tags": [], - "label": "InstallClientPanel", + "label": "IngestionsPanel", "description": [], "signature": [ - "({ codeSnippet, consoleRequest, language, languages, setSelectedLanguage, assetBasePath, application, sharePlugin, isPanelLeft, overviewPanelProps, }: React.PropsWithChildren) => JSX.Element" + "({ additionalIngestionPanel, docLinks, assetBasePath, }: React.PropsWithChildren) => JSX.Element" ], - "path": "packages/kbn-search-api-panels/components/install_client.tsx", + "path": "packages/kbn-search-api-panels/components/ingestions_panel.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.InstallClientPanel.$1", + "id": "def-common.IngestionsPanel.$1", "type": "CompoundType", "tags": [], - "label": "{\n codeSnippet,\n consoleRequest,\n language,\n languages,\n setSelectedLanguage,\n assetBasePath,\n application,\n sharePlugin,\n isPanelLeft = true,\n overviewPanelProps,\n}", + "label": "{\n additionalIngestionPanel,\n docLinks,\n assetBasePath,\n}", "description": [], "signature": [ - "React.PropsWithChildren" + "React.PropsWithChildren" ], - "path": "packages/kbn-search-api-panels/components/install_client.tsx", + "path": "packages/kbn-search-api-panels/components/ingestions_panel.tsx", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -339,45 +339,29 @@ }, { "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.IntegrationsPanel", + "id": "def-common.InstallClientPanel", "type": "Function", "tags": [], - "label": "IntegrationsPanel", + "label": "InstallClientPanel", "description": [], "signature": [ - "({ docLinks, assetBasePath, }: React.PropsWithChildren<", - { - "pluginId": "@kbn/search-api-panels", - "scope": "common", - "docId": "kibKbnSearchApiPanelsPluginApi", - "section": "def-common.IntegrationsPanelProps", - "text": "IntegrationsPanelProps" - }, - ">) => JSX.Element" + "({ codeSnippet, consoleRequest, language, languages, setSelectedLanguage, assetBasePath, application, sharePlugin, isPanelLeft, overviewPanelProps, }: React.PropsWithChildren) => JSX.Element" ], - "path": "packages/kbn-search-api-panels/components/integrations_panel.tsx", + "path": "packages/kbn-search-api-panels/components/install_client.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.IntegrationsPanel.$1", + "id": "def-common.InstallClientPanel.$1", "type": "CompoundType", "tags": [], - "label": "{\n docLinks,\n assetBasePath,\n}", + "label": "{\n codeSnippet,\n consoleRequest,\n language,\n languages,\n setSelectedLanguage,\n assetBasePath,\n application,\n sharePlugin,\n isPanelLeft = true,\n overviewPanelProps,\n}", "description": [], "signature": [ - "React.PropsWithChildren<", - { - "pluginId": "@kbn/search-api-panels", - "scope": "common", - "docId": "kibKbnSearchApiPanelsPluginApi", - "section": "def-common.IntegrationsPanelProps", - "text": "IntegrationsPanelProps" - }, - ">" + "React.PropsWithChildren" ], - "path": "packages/kbn-search-api-panels/components/integrations_panel.tsx", + "path": "packages/kbn-search-api-panels/components/install_client.tsx", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -599,45 +583,6 @@ } ], "interfaces": [ - { - "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.IntegrationsPanelProps", - "type": "Interface", - "tags": [], - "label": "IntegrationsPanelProps", - "description": [], - "path": "packages/kbn-search-api-panels/components/integrations_panel.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.IntegrationsPanelProps.docLinks", - "type": "Object", - "tags": [], - "label": "docLinks", - "description": [], - "signature": [ - "{ beats: string; connectors: string; logstash: string; }" - ], - "path": "packages/kbn-search-api-panels/components/integrations_panel.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/search-api-panels", - "id": "def-common.IntegrationsPanelProps.assetBasePath", - "type": "string", - "tags": [], - "label": "assetBasePath", - "description": [], - "path": "packages/kbn-search-api-panels/components/integrations_panel.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/search-api-panels", "id": "def-common.LanguageDefinition", @@ -1166,9 +1111,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index d9f68be0e350..0455517b821b 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 69 | 0 | 69 | 0 | +| 66 | 0 | 66 | 0 | ## Common diff --git a/api_docs/kbn_search_connectors.devdocs.json b/api_docs/kbn_search_connectors.devdocs.json index a97bdea22a81..1ad9805ec749 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -25598,6 +25598,2271 @@ } ] }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle", + "type": "Object", + "tags": [], + "label": "oracle", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration", + "type": "Object", + "tags": [], + "label": "configuration", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host", + "type": "Object", + "tags": [], + "label": "host", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.host.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port", + "type": "Object", + "tags": [], + "label": "port", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".NUMERIC" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".INTEGER" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.port.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username", + "type": "Object", + "tags": [], + "label": "username", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.username.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password", + "type": "Object", + "tags": [], + "label": "password", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.password.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database", + "type": "Object", + "tags": [], + "label": "database", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.database.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables", + "type": "Object", + "tags": [], + "label": "tables", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTAREA" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".LIST" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.tables.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size", + "type": "Object", + "tags": [], + "label": "fetch_size", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.default_value", + "type": "number", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".NUMERIC" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".INTEGER" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.fetch_size.value", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count", + "type": "Object", + "tags": [], + "label": "retry_count", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.default_value", + "type": "number", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".NUMERIC" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".INTEGER" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.retry_count.value", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol", + "type": "Object", + "tags": [], + "label": "oracle_protocol", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".DROPDOWN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ label: string; value: string; }[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_protocol.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home", + "type": "Object", + "tags": [], + "label": "oracle_home", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.oracle_home.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path", + "type": "Object", + "tags": [], + "label": "wallet_configuration_path", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.default_value", + "type": "string", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.configuration.wallet_configuration_path.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features", + "type": "Object", + "tags": [], + "label": "features", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES", + "type": "Object", + "tags": [], + "label": "[FeatureName.SYNC_RULES]", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.advanced", + "type": "Object", + "tags": [], + "label": "advanced", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.advanced.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.basic", + "type": "Object", + "tags": [], + "label": "basic", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.basic.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.serviceType", + "type": "string", + "tags": [], + "label": "serviceType", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql", diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index c76aff70b345..60e3511e1a73 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2211 | 0 | 2211 | 0 | +| 2375 | 0 | 2375 | 0 | ## Common diff --git a/api_docs/kbn_search_response_warnings.devdocs.json b/api_docs/kbn_search_response_warnings.devdocs.json index ec2406fc599d..e17c541ee974 100644 --- a/api_docs/kbn_search_response_warnings.devdocs.json +++ b/api_docs/kbn_search_response_warnings.devdocs.json @@ -19,6 +19,78 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.getWarningsDescription", + "type": "Function", + "tags": [], + "label": "getWarningsDescription", + "description": [], + "signature": [ + "(warnings: ", + "SearchResponseIncompleteWarning", + "[]) => string" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.getWarningsDescription.$1", + "type": "Array", + "tags": [], + "label": "warnings", + "description": [], + "signature": [ + "SearchResponseIncompleteWarning", + "[]" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.getWarningsTitle", + "type": "Function", + "tags": [], + "label": "getWarningsTitle", + "description": [], + "signature": [ + "(warnings: ", + "SearchResponseIncompleteWarning", + "[]) => string" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.getWarningsTitle.$1", + "type": "Array", + "tags": [], + "label": "warnings", + "description": [], + "signature": [ + "SearchResponseIncompleteWarning", + "[]" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-response-warnings", "id": "def-common.hasUnsupportedDownsampledAggregationFailure", @@ -185,6 +257,39 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.ViewDetailsPopover", + "type": "Function", + "tags": [], + "label": "ViewDetailsPopover", + "description": [], + "signature": [ + "(props: Props) => JSX.Element | null" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.ViewDetailsPopover.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "Props" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [], diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 945b2ae3e699..84266532fe55 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 14 | 0 | 12 | 1 | +| 20 | 0 | 18 | 1 | ## Common diff --git a/api_docs/kbn_security_plugin_types_common.devdocs.json b/api_docs/kbn_security_plugin_types_common.devdocs.json new file mode 100644 index 000000000000..711bd3fec69e --- /dev/null +++ b/api_docs/kbn_security_plugin_types_common.devdocs.json @@ -0,0 +1,1370 @@ +{ + "id": "@kbn/security-plugin-types-common", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser", + "type": "Interface", + "tags": [], + "label": "AuthenticatedUser", + "description": [ + "\nRepresents the currently authenticated user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.User", + "text": "User" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.authentication_realm", + "type": "Object", + "tags": [], + "label": "authentication_realm", + "description": [ + "\nThe name and type of the Realm that has authenticated the user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserRealm", + "text": "UserRealm" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.lookup_realm", + "type": "Object", + "tags": [], + "label": "lookup_realm", + "description": [ + "\nThe name and type of the Realm where the user information were retrieved from." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserRealm", + "text": "UserRealm" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.authentication_provider", + "type": "Object", + "tags": [], + "label": "authentication_provider", + "description": [ + "\nThe authentication provider that used to authenticate user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticationProvider", + "text": "AuthenticationProvider" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.authentication_type", + "type": "string", + "tags": [], + "label": "authentication_type", + "description": [ + "\nThe AuthenticationType used by ES to authenticate the user.\n" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.elastic_cloud_user", + "type": "boolean", + "tags": [], + "label": "elastic_cloud_user", + "description": [ + "\nIndicates whether user is authenticated via Elastic Cloud built-in SAML realm." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticatedUser.profile_uid", + "type": "string", + "tags": [], + "label": "profile_uid", + "description": [ + "\nUser profile ID of this user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticationProvider", + "type": "Interface", + "tags": [], + "label": "AuthenticationProvider", + "description": [ + "\nType and name tuple to identify provider used to authenticate user." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticationProvider.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "\nType of the Kibana authentication provider." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.AuthenticationProvider.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nName of the Kibana authentication provider (arbitrary string)." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.FeaturesPrivileges", + "type": "Interface", + "tags": [], + "label": "FeaturesPrivileges", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.FeaturesPrivileges.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[featureId: string]: string[]", + "description": [], + "signature": [ + "[featureId: string]: string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role", + "type": "Interface", + "tags": [], + "label": "Role", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [], + "signature": [ + "{ cluster: string[]; indices: ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleIndexPrivilege", + "text": "RoleIndexPrivilege" + }, + "[]; remote_indices?: ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleRemoteIndexPrivilege", + "text": "RoleRemoteIndexPrivilege" + }, + "[] | undefined; run_as: string[]; }" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role.kibana", + "type": "Array", + "tags": [], + "label": "kibana", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleKibanaPrivilege", + "text": "RoleKibanaPrivilege" + }, + "[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [], + "signature": [ + "{ [anyKey: string]: any; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role.transient_metadata", + "type": "Object", + "tags": [], + "label": "transient_metadata", + "description": [], + "signature": [ + "{ [anyKey: string]: any; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role._transform_error", + "type": "Array", + "tags": [], + "label": "_transform_error", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.Role._unrecognized_applications", + "type": "Array", + "tags": [], + "label": "_unrecognized_applications", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleIndexPrivilege", + "type": "Interface", + "tags": [], + "label": "RoleIndexPrivilege", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleIndexPrivilege.names", + "type": "Array", + "tags": [], + "label": "names", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleIndexPrivilege.privileges", + "type": "Array", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleIndexPrivilege.field_security", + "type": "Object", + "tags": [], + "label": "field_security", + "description": [], + "signature": [ + "{ grant?: string[] | undefined; except?: string[] | undefined; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleIndexPrivilege.query", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleKibanaPrivilege", + "type": "Interface", + "tags": [], + "label": "RoleKibanaPrivilege", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleKibanaPrivilege.spaces", + "type": "Array", + "tags": [], + "label": "spaces", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleKibanaPrivilege.base", + "type": "Array", + "tags": [], + "label": "base", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleKibanaPrivilege.feature", + "type": "Object", + "tags": [], + "label": "feature", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.FeaturesPrivileges", + "text": "FeaturesPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleKibanaPrivilege._reserved", + "type": "Array", + "tags": [], + "label": "_reserved", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleRemoteIndexPrivilege", + "type": "Interface", + "tags": [], + "label": "RoleRemoteIndexPrivilege", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleRemoteIndexPrivilege", + "text": "RoleRemoteIndexPrivilege" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleIndexPrivilege", + "text": "RoleIndexPrivilege" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.RoleRemoteIndexPrivilege.clusters", + "type": "Array", + "tags": [], + "label": "clusters", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense", + "type": "Interface", + "tags": [], + "label": "SecurityLicense", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.isLicenseAvailable", + "type": "Function", + "tags": [], + "label": "isLicenseAvailable", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.isEnabled", + "type": "Function", + "tags": [], + "label": "isEnabled", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.getFeatures", + "type": "Function", + "tags": [], + "label": "getFeatures", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.SecurityLicenseFeatures", + "text": "SecurityLicenseFeatures" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.hasAtLeast", + "type": "Function", + "tags": [], + "label": "hasAtLeast", + "description": [], + "signature": [ + "(licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.hasAtLeast.$1", + "type": "CompoundType", + "tags": [], + "label": "licenseType", + "description": [], + "signature": [ + "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicense.features$", + "type": "Object", + "tags": [], + "label": "features$", + "description": [], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.SecurityLicenseFeatures", + "text": "SecurityLicenseFeatures" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures", + "type": "Interface", + "tags": [], + "label": "SecurityLicenseFeatures", + "description": [ + "\nDescribes Security plugin features that depend on license." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.showLogin", + "type": "boolean", + "tags": [], + "label": "showLogin", + "description": [ + "\nIndicates whether we show login page or skip it." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowLogin", + "type": "boolean", + "tags": [], + "label": "allowLogin", + "description": [ + "\nIndicates whether we allow login or disable it on the login page." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.showLinks", + "type": "boolean", + "tags": [], + "label": "showLinks", + "description": [ + "\nIndicates whether we show security links throughout the kibana app." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.showRoleMappingsManagement", + "type": "boolean", + "tags": [], + "label": "showRoleMappingsManagement", + "description": [ + "\nIndicates whether we show the Role Mappings UI." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowAccessAgreement", + "type": "boolean", + "tags": [], + "label": "allowAccessAgreement", + "description": [ + "\nIndicates whether we allow users to access agreement UI and acknowledge it." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowAuditLogging", + "type": "boolean", + "tags": [], + "label": "allowAuditLogging", + "description": [ + "\nIndicates whether we allow logging of audit events." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowRoleDocumentLevelSecurity", + "type": "boolean", + "tags": [], + "label": "allowRoleDocumentLevelSecurity", + "description": [ + "\nIndicates whether we allow users to define document level security in roles." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowRoleFieldLevelSecurity", + "type": "boolean", + "tags": [], + "label": "allowRoleFieldLevelSecurity", + "description": [ + "\nIndicates whether we allow users to define field level security in roles." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowRoleRemoteIndexPrivileges", + "type": "boolean", + "tags": [], + "label": "allowRoleRemoteIndexPrivileges", + "description": [ + "\nIndicates whether we allow users to define remote index privileges in roles." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowRbac", + "type": "boolean", + "tags": [], + "label": "allowRbac", + "description": [ + "\nIndicates whether we allow Role-based access control (RBAC)." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowSubFeaturePrivileges", + "type": "boolean", + "tags": [], + "label": "allowSubFeaturePrivileges", + "description": [ + "\nIndicates whether we allow sub-feature privileges." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.allowUserProfileCollaboration", + "type": "boolean", + "tags": [], + "label": "allowUserProfileCollaboration", + "description": [ + "\nIndicates whether we allow user profile collaboration features (suggest and privileges checks APIs)." + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.SecurityLicenseFeatures.layout", + "type": "CompoundType", + "tags": [], + "label": "layout", + "description": [ + "\nDescribes the layout of the login form if it's displayed." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.LoginLayout", + "text": "LoginLayout" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User", + "type": "Interface", + "tags": [], + "label": "User", + "description": [ + "\nA set of fields describing Kibana user." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.email", + "type": "string", + "tags": [], + "label": "email", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.full_name", + "type": "string", + "tags": [], + "label": "full_name", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.roles", + "type": "Object", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.User.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [], + "signature": [ + "{ _reserved: boolean; _deprecated?: boolean | undefined; _deprecated_reason?: string | undefined; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfile", + "type": "Interface", + "tags": [], + "label": "UserProfile", + "description": [ + "\nIMPORTANT:\n\nThe types in this file are duplicated at\n`packages/kbn-user-profile-components/src/user_profile.ts`\n\nWhen making changes please ensure to keep both files in sync.\n\nDescribes basic properties stored in user profile." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfile.uid", + "type": "string", + "tags": [], + "label": "uid", + "description": [ + "\nUnique ID for of the user profile." + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfile.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nIndicates whether user profile is enabled or not." + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfile.user", + "type": "Object", + "tags": [], + "label": "user", + "description": [ + "\nInformation about the user that owns profile." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileUserInfo", + "text": "UserProfileUserInfo" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfile.data", + "type": "Object", + "tags": [], + "label": "data", + "description": [ + "\nUser specific data associated with the profile." + ], + "signature": [ + "{ [P in keyof D]?: D[P] | undefined; }" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfo", + "type": "Interface", + "tags": [], + "label": "UserProfileUserInfo", + "description": [ + "\nBasic user information returned in user profile." + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfo.username", + "type": "string", + "tags": [], + "label": "username", + "description": [ + "\nUsername of the user." + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfo.email", + "type": "string", + "tags": [], + "label": "email", + "description": [ + "\nOptional email of the user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfo.full_name", + "type": "string", + "tags": [], + "label": "full_name", + "description": [ + "\nOptional full name of the user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfoWithSecurity", + "type": "Interface", + "tags": [], + "label": "UserProfileUserInfoWithSecurity", + "description": [ + "\nExtended user information returned in user profile (both basic and security related properties)." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileUserInfoWithSecurity", + "text": "UserProfileUserInfoWithSecurity" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileUserInfo", + "text": "UserProfileUserInfo" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfoWithSecurity.roles", + "type": "Object", + "tags": [], + "label": "roles", + "description": [ + "\nList of the user roles." + ], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfoWithSecurity.realm_name", + "type": "string", + "tags": [], + "label": "realm_name", + "description": [ + "\nName of the Elasticsearch security realm that was used to authenticate user." + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileUserInfoWithSecurity.realm_domain", + "type": "string", + "tags": [], + "label": "realm_domain", + "description": [ + "\nOptional name of the security domain that Elasticsearch security realm that was\nused to authenticate user resides in (if any)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileWithSecurity", + "type": "Interface", + "tags": [], + "label": "UserProfileWithSecurity", + "description": [ + "\nDescribes all properties stored in user profile (both basic and security related properties)." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileWithSecurity", + "text": "UserProfileWithSecurity" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileWithSecurity.user", + "type": "Object", + "tags": [], + "label": "user", + "description": [ + "\nInformation about the user that owns profile." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileUserInfoWithSecurity", + "text": "UserProfileUserInfoWithSecurity" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileWithSecurity.labels", + "type": "Uncategorized", + "tags": [], + "label": "labels", + "description": [ + "\nUser specific _searchable_ labels associated with the profile. Note that labels are considered\nsecurity related field since it's going to be used to store user's space ID." + ], + "signature": [ + "L" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserRealm", + "type": "Interface", + "tags": [], + "label": "UserRealm", + "description": [ + "\nAn Elasticsearch realm that was used to resolve and authenticate the user." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserRealm.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nArbitrary name of the security realm." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserRealm.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "\nType of the security realm (file, native, saml etc.)." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.LoginLayout", + "type": "Type", + "tags": [], + "label": "LoginLayout", + "description": [ + "\nRepresents types of login form layouts." + ], + "signature": [ + "\"form\" | \"error-es-unavailable\" | \"error-xpack-unavailable\"" + ], + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileData", + "type": "Type", + "tags": [], + "label": "UserProfileData", + "description": [ + "\nPlaceholder for data stored in user profile." + ], + "signature": [ + "{ [x: string]: unknown; }" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-common", + "id": "def-common.UserProfileLabels", + "type": "Type", + "tags": [], + "label": "UserProfileLabels", + "description": [ + "\nType of the user profile labels structure (currently" + ], + "signature": [ + "{ [x: string]: string; }" + ], + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx new file mode 100644 index 000000000000..646601081ee9 --- /dev/null +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnSecurityPluginTypesCommonPluginApi +slug: /kibana-dev-docs/api/kbn-security-plugin-types-common +title: "@kbn/security-plugin-types-common" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/security-plugin-types-common plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] +--- +import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; + + + +Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 82 | 0 | 35 | 0 | + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_security_plugin_types_public.devdocs.json b/api_docs/kbn_security_plugin_types_public.devdocs.json new file mode 100644 index 000000000000..e37a5f5d8482 --- /dev/null +++ b/api_docs/kbn_security_plugin_types_public.devdocs.json @@ -0,0 +1,939 @@ +{ + "id": "@kbn/security-plugin-types-public", + "client": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.AuthenticationServiceSetup", + "type": "Interface", + "tags": [], + "label": "AuthenticationServiceSetup", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.AuthenticationServiceSetup.getCurrentUser", + "type": "Function", + "tags": [], + "label": "getCurrentUser", + "description": [ + "\nReturns currently authenticated user and throws if current user isn't authenticated." + ], + "signature": [ + "() => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.AuthenticationServiceSetup.areAPIKeysEnabled", + "type": "Function", + "tags": [], + "label": "areAPIKeysEnabled", + "description": [ + "\nDetermines if API Keys are currently enabled." + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.GetUserProfileResponse", + "type": "Interface", + "tags": [], + "label": "GetUserProfileResponse", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.GetUserProfileResponse", + "text": "GetUserProfileResponse" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileWithSecurity", + "text": "UserProfileWithSecurity" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.GetUserProfileResponse.user", + "type": "CompoundType", + "tags": [], + "label": "user", + "description": [ + "\nInformation about the currently authenticated user that owns the profile." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileUserInfoWithSecurity", + "text": "UserProfileUserInfoWithSecurity" + }, + " & Pick<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + ", \"authentication_provider\">" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityNavControlServiceStart", + "type": "Interface", + "tags": [], + "label": "SecurityNavControlServiceStart", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityNavControlServiceStart.getUserMenuLinks$", + "type": "Function", + "tags": [], + "label": "getUserMenuLinks$", + "description": [ + "\nReturns an Observable of the array of user menu links (the links that show up under the user's Avatar in the UI) registered by other plugins" + ], + "signature": [ + "() => ", + "Observable", + "<", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserMenuLink", + "text": "UserMenuLink" + }, + "[]>" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityNavControlServiceStart.addUserMenuLinks", + "type": "Function", + "tags": [], + "label": "addUserMenuLinks", + "description": [ + "\nRegisters the provided user menu links to be displayed in the user menu (the links that show up under the user's Avatar in the UI)." + ], + "signature": [ + "(newUserMenuLink: ", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserMenuLink", + "text": "UserMenuLink" + }, + "[]) => void" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityNavControlServiceStart.addUserMenuLinks.$1", + "type": "Array", + "tags": [], + "label": "newUserMenuLink", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserMenuLink", + "text": "UserMenuLink" + }, + "[]" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginSetup", + "type": "Interface", + "tags": [], + "label": "SecurityPluginSetup", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginSetup.authc", + "type": "Object", + "tags": [], + "label": "authc", + "description": [ + "\nExposes authentication information about the currently logged in user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.AuthenticationServiceSetup", + "text": "AuthenticationServiceSetup" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginSetup.license", + "type": "Object", + "tags": [], + "label": "license", + "description": [ + "\nExposes information about the available security features under the current license." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.SecurityLicense", + "text": "SecurityLicense" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginStart", + "type": "Interface", + "tags": [], + "label": "SecurityPluginStart", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginStart.navControlService", + "type": "Object", + "tags": [], + "label": "navControlService", + "description": [ + "\nExposes the ability to add custom links to the dropdown menu in the top right, where the user's Avatar is." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityNavControlServiceStart", + "text": "SecurityNavControlServiceStart" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginStart.authc", + "type": "Object", + "tags": [], + "label": "authc", + "description": [ + "\nExposes authentication information about the currently logged in user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.AuthenticationServiceSetup", + "text": "AuthenticationServiceSetup" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.SecurityPluginStart.userProfiles", + "type": "Object", + "tags": [], + "label": "userProfiles", + "description": [ + "\nA set of methods to work with Kibana user profiles." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileAPIClient", + "text": "UserProfileAPIClient" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink", + "type": "Interface", + "tags": [], + "label": "UserMenuLink", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.iconType", + "type": "CompoundType", + "tags": [], + "label": "iconType", + "description": [], + "signature": [ + "string | React.ComponentType<{}>" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.href", + "type": "string", + "tags": [], + "label": "href", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.setAsProfile", + "type": "CompoundType", + "tags": [], + "label": "setAsProfile", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserMenuLink.content", + "type": "CompoundType", + "tags": [], + "label": "content", + "description": [ + "Render a custom ReactNode instead of the default " + ], + "signature": [ + "boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient", + "type": "Interface", + "tags": [], + "label": "UserProfileAPIClient", + "description": [], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.userProfile$", + "type": "Object", + "tags": [], + "label": "userProfile$", + "description": [], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileData", + "text": "UserProfileData" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.getCurrent", + "type": "Function", + "tags": [], + "label": "getCurrent", + "description": [ + "\nRetrieves the user profile of the current user. If the profile isn't available, e.g. for the anonymous users or\nusers authenticated via authenticating proxies, the `null` value is returned." + ], + "signature": [ + "(params?: ", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileGetCurrentParams", + "text": "UserProfileGetCurrentParams" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.GetUserProfileResponse", + "text": "GetUserProfileResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.getCurrent.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Get current user profile operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileGetCurrentParams", + "text": "UserProfileGetCurrentParams" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.bulkGet", + "type": "Function", + "tags": [], + "label": "bulkGet", + "description": [ + "\nRetrieves multiple user profiles by their identifiers." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileBulkGetParams", + "text": "UserProfileBulkGetParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "[]>" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.bulkGet.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Bulk get operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileBulkGetParams", + "text": "UserProfileBulkGetParams" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.suggest", + "type": "Function", + "tags": [], + "label": "suggest", + "description": [ + "\nSuggests multiple user profiles by search criteria.\n\nNote: This endpoint is not provided out-of-the-box by the platform. You need to expose your own\nversion within your app. An example of how to do this can be found in:\n`examples/user_profile_examples/server/plugin.ts`\n" + ], + "signature": [ + "(path: string, params: ", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileSuggestParams", + "text": "UserProfileSuggestParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "[]>" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.suggest.$1", + "type": "string", + "tags": [], + "label": "path", + "description": [ + "Path to your app's suggest endpoint." + ], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.suggest.$2", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Suggest operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.UserProfileSuggestParams", + "text": "UserProfileSuggestParams" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nUpdates user profile data of the current user." + ], + "signature": [ + "(data: D) => Promise" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileAPIClient.update.$1", + "type": "Uncategorized", + "tags": [], + "label": "data", + "description": [ + "Application data to be written (merged with existing data)." + ], + "signature": [ + "D" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileBulkGetParams", + "type": "Interface", + "tags": [], + "label": "UserProfileBulkGetParams", + "description": [ + "\nParameters for the bulk get API." + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileBulkGetParams.uids", + "type": "Object", + "tags": [], + "label": "uids", + "description": [ + "\nList of user profile identifiers." + ], + "signature": [ + "Set" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileBulkGetParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, suggest API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileGetCurrentParams", + "type": "Interface", + "tags": [], + "label": "UserProfileGetCurrentParams", + "description": [ + "\nParameters for the get user profile for the current user API." + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileGetCurrentParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, get API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileSuggestParams", + "type": "Interface", + "tags": [], + "label": "UserProfileSuggestParams", + "description": [ + "\nParameters for the suggest API." + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileSuggestParams.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nQuery string used to match name-related fields in user profiles. The following fields are treated as\nname-related: username, full_name and email." + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileSuggestParams.size", + "type": "number", + "tags": [], + "label": "size", + "description": [ + "\nDesired number of suggestions to return. The default value is 10." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.UserProfileSuggestParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, suggest API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/security-plugin-types-public", + "id": "def-public.AuthenticationServiceStart", + "type": "Type", + "tags": [], + "label": "AuthenticationServiceStart", + "description": [ + "\nStart has the same contract as Setup for now." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.AuthenticationServiceSetup", + "text": "AuthenticationServiceSetup" + } + ], + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx new file mode 100644 index 000000000000..27567be32b4d --- /dev/null +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnSecurityPluginTypesPublicPluginApi +slug: /kibana-dev-docs/api/kbn-security-plugin-types-public +title: "@kbn/security-plugin-types-public" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/security-plugin-types-public plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] +--- +import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; + + + +Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 44 | 0 | 14 | 0 | + +## Client + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_security_plugin_types_server.devdocs.json b/api_docs/kbn_security_plugin_types_server.devdocs.json new file mode 100644 index 000000000000..c6d441e7a04a --- /dev/null +++ b/api_docs/kbn_security_plugin_types_server.devdocs.json @@ -0,0 +1,4401 @@ +{ + "id": "@kbn/security-plugin-types-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.getKibanaRoleSchema", + "type": "Function", + "tags": [], + "label": "getKibanaRoleSchema", + "description": [ + "\nKibana specific portion of the role definition. It's represented as a list of base and/or\nfeature Kibana privileges. None of the entries should apply to the same spaces." + ], + "signature": [ + "(getBasePrivilegeNames: () => { global: string[]; space: string[]; }) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined; } & { spaces: string[] | \"*\"[]; }>[]>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.getKibanaRoleSchema.$1", + "type": "Function", + "tags": [], + "label": "getBasePrivilegeNames", + "description": [], + "signature": [ + "() => { global: string[]; space: string[]; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.getRestApiKeyWithKibanaPrivilegesSchema", + "type": "Function", + "tags": [], + "label": "getRestApiKeyWithKibanaPrivilegesSchema", + "description": [], + "signature": [ + "(getBasePrivilegeNames: () => { global: string[]; space: string[]; }) => ExtendedObjectType<{ type: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<\"rest\" | undefined>; name: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; expiration: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; role_descriptors: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ">>; metadata: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined>; }, { role_descriptors: null; kibana_role_descriptors: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>>; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.getRestApiKeyWithKibanaPrivilegesSchema.$1", + "type": "Function", + "tags": [], + "label": "getBasePrivilegeNames", + "description": [], + "signature": [ + "() => { global: string[]; space: string[]; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions", + "type": "Interface", + "tags": [], + "label": "Actions", + "description": [ + "Actions are used to create the \"actions\" that are associated with Elasticsearch's\napplication privileges, and are used to perform the authorization checks implemented\nby the various `checkPrivilegesWithRequest` derivatives." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.api", + "type": "Object", + "tags": [], + "label": "api", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ApiActions", + "text": "ApiActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.app", + "type": "Object", + "tags": [], + "label": "app", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AppActions", + "text": "AppActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.cases", + "type": "Object", + "tags": [], + "label": "cases", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CasesActions", + "text": "CasesActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.login", + "type": "string", + "tags": [], + "label": "login", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.savedObject", + "type": "Object", + "tags": [], + "label": "savedObject", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SavedObjectActions", + "text": "SavedObjectActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.alerting", + "type": "Object", + "tags": [], + "label": "alerting", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AlertingActions", + "text": "AlertingActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.space", + "type": "Object", + "tags": [], + "label": "space", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SpaceActions", + "text": "SpaceActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.Actions.ui", + "type": "Object", + "tags": [], + "label": "ui", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UIActions", + "text": "UIActions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions", + "type": "Interface", + "tags": [], + "label": "AlertingActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(ruleTypeId: string, consumer: string, alertingEntity: string, operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions.get.$1", + "type": "string", + "tags": [], + "label": "ruleTypeId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions.get.$2", + "type": "string", + "tags": [], + "label": "consumer", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions.get.$3", + "type": "string", + "tags": [], + "label": "alertingEntity", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AlertingActions.get.$4", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ApiActions", + "type": "Interface", + "tags": [], + "label": "ApiActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ApiActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ApiActions.get.$1", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys", + "type": "Interface", + "tags": [], + "label": "APIKeys", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.areAPIKeysEnabled", + "type": "Function", + "tags": [], + "label": "areAPIKeysEnabled", + "description": [ + "\nDetermines if API Keys are enabled in Elasticsearch." + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.areCrossClusterAPIKeysEnabled", + "type": "Function", + "tags": [], + "label": "areCrossClusterAPIKeysEnabled", + "description": [ + "\nDetermines if Cross-Cluster API Keys are enabled in Elasticsearch." + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [ + "\nTries to create an API key for the current user.\n\nReturns newly created API key or `null` if API keys are disabled.\n\nUser needs `manage_api_key` privilege to create REST API keys and `manage_security` for Cross-Cluster API keys.\n" + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ", createParams: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CreateAPIKeyParams", + "text": "CreateAPIKeyParams" + }, + ") => Promise<", + "SecurityCreateApiKeyResponse", + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.create.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "Request instance." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.create.$2", + "type": "CompoundType", + "tags": [], + "label": "createParams", + "description": [ + "The params to create an API key" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CreateAPIKeyParams", + "text": "CreateAPIKeyParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.grantAsInternalUser", + "type": "Function", + "tags": [], + "label": "grantAsInternalUser", + "description": [ + "\nTries to grant an API key for the current user." + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ", createParams: Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }>) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.GrantAPIKeyResult", + "text": "GrantAPIKeyResult" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.grantAsInternalUser.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "Request instance." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.grantAsInternalUser.$2", + "type": "CompoundType", + "tags": [], + "label": "createParams", + "description": [ + "Create operation parameters." + ], + "signature": [ + "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.validate", + "type": "Function", + "tags": [], + "label": "validate", + "description": [ + "\nTries to validate an API key." + ], + "signature": [ + "(apiKeyPrams: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ValidateAPIKeyParams", + "text": "ValidateAPIKeyParams" + }, + ") => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.validate.$1", + "type": "Object", + "tags": [], + "label": "apiKeyPrams", + "description": [ + "ValidateAPIKeyParams." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ValidateAPIKeyParams", + "text": "ValidateAPIKeyParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.invalidate", + "type": "Function", + "tags": [], + "label": "invalidate", + "description": [ + "\nTries to invalidate an API keys." + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ", params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeyResult", + "text": "InvalidateAPIKeyResult" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.invalidate.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "Request instance." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.invalidate.$2", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "The params to invalidate an API keys." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.invalidateAsInternalUser", + "type": "Function", + "tags": [], + "label": "invalidateAsInternalUser", + "description": [ + "\nTries to invalidate the API keys by using the internal user." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeyResult", + "text": "InvalidateAPIKeyResult" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.APIKeys.invalidateAsInternalUser.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "The params to invalidate the API keys." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AppActions", + "type": "Interface", + "tags": [], + "label": "AppActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AppActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AppActions.get.$1", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditEvent", + "type": "Interface", + "tags": [], + "label": "AuditEvent", + "description": [ + "\nAudit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.12/index.html\n\nIf you add additional fields to the schema ensure you update the Kibana Filebeat module:\nhttps://github.com/elastic/beats/tree/master/filebeat/module/kibana\n" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " extends ", + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.LogMeta", + "text": "LogMeta" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditEvent.message", + "type": "string", + "tags": [], + "label": "message", + "description": [ + "\nLog message" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditEvent.kibana", + "type": "Object", + "tags": [], + "label": "kibana", + "description": [ + "\nKibana specific fields" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditKibana", + "text": "AuditKibana" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditEvent.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [ + "\nFields describing an HTTP request" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditHttp", + "text": "AuditHttp" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditHttp", + "type": "Interface", + "tags": [], + "label": "AuditHttp", + "description": [ + "\nAudit http schema using ECS format" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditHttp", + "text": "AuditHttp" + }, + " extends ", + { + "pluginId": "@kbn/ecs", + "scope": "common", + "docId": "kibKbnEcsPluginApi", + "section": "def-common.EcsHttp", + "text": "EcsHttp" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditHttp.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "\nHTTP request details" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditRequest", + "text": "AuditRequest" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana", + "type": "Interface", + "tags": [], + "label": "AuditKibana", + "description": [ + "\nAudit kibana schema using ECS format" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.space_id", + "type": "string", + "tags": [], + "label": "space_id", + "description": [ + "\nThe ID of the space associated with this event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.session_id", + "type": "string", + "tags": [], + "label": "session_id", + "description": [ + "\nThe ID of the user session associated with this event. Each login attempt\nresults in a unique session id." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.saved_object", + "type": "Object", + "tags": [], + "label": "saved_object", + "description": [ + "\nSaved object that was created, changed, deleted or accessed as part of this event." + ], + "signature": [ + "{ type: string; id: string; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.authentication_provider", + "type": "string", + "tags": [], + "label": "authentication_provider", + "description": [ + "\nName of authentication provider associated with a login event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.authentication_type", + "type": "string", + "tags": [], + "label": "authentication_type", + "description": [ + "\nType of authentication provider associated with a login event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.authentication_realm", + "type": "string", + "tags": [], + "label": "authentication_realm", + "description": [ + "\nName of Elasticsearch realm that has authenticated the user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.lookup_realm", + "type": "string", + "tags": [], + "label": "lookup_realm", + "description": [ + "\nName of Elasticsearch realm where the user details were retrieved from." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.add_to_spaces", + "type": "Object", + "tags": [], + "label": "add_to_spaces", + "description": [ + "\nSet of space IDs that a saved object was shared to." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.delete_from_spaces", + "type": "Object", + "tags": [], + "label": "delete_from_spaces", + "description": [ + "\nSet of space IDs that a saved object was removed from." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.unauthorized_spaces", + "type": "Object", + "tags": [], + "label": "unauthorized_spaces", + "description": [ + "\nSet of space IDs that are not authorized for an action." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditKibana.unauthorized_types", + "type": "Object", + "tags": [], + "label": "unauthorized_types", + "description": [ + "\nSet of types that are not authorized for an action." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditLogger", + "type": "Interface", + "tags": [], + "label": "AuditLogger", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditLogger.log", + "type": "Function", + "tags": [], + "label": "log", + "description": [ + "\nLogs an {@link AuditEvent} and automatically adds meta data about the\ncurrent user, space and correlation id.\n\nGuidelines around what events should be logged and how they should be\nstructured can be found in: `/x-pack/plugins/security/README.md`\n" + ], + "signature": [ + "(event: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " | undefined) => void" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditLogger.log.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditLogger.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nIndicates whether audit logging is enabled or not.\n\nUseful for skipping resource-intense operations that don't need to be performed when audit\nlogging is disabled." + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditRequest", + "type": "Interface", + "tags": [], + "label": "AuditRequest", + "description": [ + "\nAudit request schema using ECS format" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditRequest", + "text": "AuditRequest" + }, + " extends { body?: { bytes?: number | undefined; content?: string | undefined; } | undefined; bytes?: number | undefined; id?: string | undefined; method?: string | undefined; mime_type?: string | undefined; referrer?: string | undefined; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditRequest.headers", + "type": "Object", + "tags": [], + "label": "headers", + "description": [ + "\nHTTP request headers" + ], + "signature": [ + "{ 'x-forwarded-for'?: string | undefined; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditServiceSetup", + "type": "Interface", + "tags": [], + "label": "AuditServiceSetup", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditServiceSetup.asScoped", + "type": "Function", + "tags": [], + "label": "asScoped", + "description": [ + "\nCreates an {@link AuditLogger} scoped to the current request.\n\nThis audit logger logs events with all required user and session info and should be used for\nall user-initiated actions.\n" + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditLogger", + "text": "AuditLogger" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditServiceSetup.asScoped.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuditServiceSetup.withoutRequest", + "type": "Object", + "tags": [], + "label": "withoutRequest", + "description": [ + "\n{@link AuditLogger} for background tasks only.\n\nThis audit logger logs events without any user or session info and should never be used to log\nuser-initiated actions.\n" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditLogger", + "text": "AuditLogger" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthenticationServiceStart", + "type": "Interface", + "tags": [], + "label": "AuthenticationServiceStart", + "description": [ + "\nAuthentication services available on the security plugin's start contract." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthenticationServiceStart.apiKeys", + "type": "Object", + "tags": [], + "label": "apiKeys", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.APIKeys", + "text": "APIKeys" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthenticationServiceStart.getCurrentUser", + "type": "Function", + "tags": [], + "label": "getCurrentUser", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " | null" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthenticationServiceStart.getCurrentUser.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationMode", + "type": "Interface", + "tags": [], + "label": "AuthorizationMode", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationMode.useRbacForRequest", + "type": "Function", + "tags": [], + "label": "useRbacForRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => boolean" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationMode.useRbacForRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup", + "type": "Interface", + "tags": [], + "label": "AuthorizationServiceSetup", + "description": [ + "\nAuthorization services available on the setup contract of the security plugin." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [ + "\nActions are used to create the \"actions\" that are associated with Elasticsearch's\napplication privileges, and are used to perform the authorization checks implemented\nby the various `checkPrivilegesWithRequest` derivatives." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.Actions", + "text": "Actions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesWithRequest", + "type": "Function", + "tags": [], + "label": "checkPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivileges", + "text": "CheckPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesDynamicallyWithRequest", + "type": "Function", + "tags": [], + "label": "checkPrivilegesDynamicallyWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesDynamically", + "text": "CheckPrivilegesDynamically" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesDynamicallyWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkSavedObjectsPrivilegesWithRequest", + "type": "Function", + "tags": [], + "label": "checkSavedObjectsPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckSavedObjectsPrivileges", + "text": "CheckSavedObjectsPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.checkSavedObjectsPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.AuthorizationServiceSetup.mode", + "type": "Object", + "tags": [], + "label": "mode", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuthorizationMode", + "text": "AuthorizationMode" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CasesActions", + "type": "Interface", + "tags": [], + "label": "CasesActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CasesActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(owner: string, operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CasesActions.get.$1", + "type": "string", + "tags": [], + "label": "owner", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CasesActions.get.$2", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges", + "type": "Interface", + "tags": [], + "label": "CheckPrivileges", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpace", + "type": "Function", + "tags": [], + "label": "atSpace", + "description": [], + "signature": [ + "(spaceId: string, privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpace.$1", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpace.$2", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpace.$3", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpaces", + "type": "Function", + "tags": [], + "label": "atSpaces", + "description": [], + "signature": [ + "(spaceIds: string[], privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpaces.$1", + "type": "Array", + "tags": [], + "label": "spaceIds", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpaces.$2", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.atSpaces.$3", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.globally", + "type": "Function", + "tags": [], + "label": "globally", + "description": [], + "signature": [ + "(privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.globally.$1", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivileges.globally.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesOptions", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesOptions", + "description": [ + "\nOptions to influce the privilege checks." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesOptions.requireLoginAction", + "type": "CompoundType", + "tags": [], + "label": "requireLoginAction", + "description": [ + "\nWhether or not the `login` action should be required (default: true).\nSetting this to false is not advised except for special circumstances, when you do not require\nthe request to belong to a user capable of logging into Kibana." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesPayload", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesPayload", + "description": [ + "\nPrivileges that can be checked for the Kibana users." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesPayload.kibana", + "type": "CompoundType", + "tags": [], + "label": "kibana", + "description": [ + "\nA list of the Kibana specific privileges (usually generated with `security.authz.actions.*.get(...)`)." + ], + "signature": [ + "string | string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesPayload.elasticsearch", + "type": "Object", + "tags": [], + "label": "elasticsearch", + "description": [ + "\nA set of the Elasticsearch cluster and index privileges." + ], + "signature": [ + "{ cluster: string[]; index: Record; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesResponse", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesResponse", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesResponse.hasAllRequested", + "type": "boolean", + "tags": [], + "label": "hasAllRequested", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesResponse.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesResponse.privileges", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + "{ kibana: { resource?: string | undefined; privilege: string; authorized: boolean; }[]; elasticsearch: { cluster: { privilege: string; authorized: boolean; }[]; index: { [indexName: string]: { privilege: string; authorized: boolean; }[]; }; }; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivileges", + "type": "Interface", + "tags": [], + "label": "CheckUserProfilesPrivileges", + "description": [ + "\nAn interface to check users profiles privileges in a specific context (only a single-space context is supported at\nthe moment)." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivileges.atSpace", + "type": "Function", + "tags": [], + "label": "atSpace", + "description": [], + "signature": [ + "(spaceId: string, privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesPayload", + "text": "CheckUserProfilesPrivilegesPayload" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesResponse", + "text": "CheckUserProfilesPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivileges.atSpace.$1", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivileges.atSpace.$2", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesPayload", + "text": "CheckUserProfilesPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivilegesPayload", + "type": "Interface", + "tags": [], + "label": "CheckUserProfilesPrivilegesPayload", + "description": [ + "\nPrivileges that can be checked for the users profiles (only Kibana specific privileges are supported at the moment)." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivilegesPayload.kibana", + "type": "Array", + "tags": [], + "label": "kibana", + "description": [ + "\nA list of the Kibana specific privileges (usually generated with `security.authz.actions.*.get(...)`)." + ], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivilegesResponse", + "type": "Interface", + "tags": [], + "label": "CheckUserProfilesPrivilegesResponse", + "description": [ + "\nResponse of the check privileges operation for the users profiles." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivilegesResponse.hasPrivilegeUids", + "type": "Array", + "tags": [], + "label": "hasPrivilegeUids", + "description": [ + "\nThe subset of the requested profile IDs of the users that have all the requested privileges." + ], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckUserProfilesPrivilegesResponse.errors", + "type": "Object", + "tags": [], + "label": "errors", + "description": [ + "\nAn errors object that may be returned from ES that contains a `count` of UIDs that have errors in the `details` property.\n\nEach entry in `details` will contain an error `type`, e.g 'resource_not_found_exception', and a `reason` message, e.g. 'profile document not found'" + ], + "signature": [ + "{ count: number; details: Record; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.GrantAPIKeyResult", + "type": "Interface", + "tags": [], + "label": "GrantAPIKeyResult", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.GrantAPIKeyResult.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique id for this API key" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.GrantAPIKeyResult.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nName for this API key" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.GrantAPIKeyResult.api_key", + "type": "string", + "tags": [], + "label": "api_key", + "description": [ + "\nGenerated API key" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse", + "type": "Interface", + "tags": [], + "label": "HasPrivilegesResponse", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse.has_all_requested", + "type": "boolean", + "tags": [], + "label": "has_all_requested", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse.application", + "type": "Object", + "tags": [], + "label": "application", + "description": [], + "signature": [ + "{ [applicationName: string]: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.HasPrivilegesResponseApplication", + "text": "HasPrivilegesResponseApplication" + }, + "; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse.cluster", + "type": "Object", + "tags": [], + "label": "cluster", + "description": [], + "signature": [ + "{ [privilegeName: string]: boolean; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponse.index", + "type": "Object", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "{ [indexName: string]: { [privilegeName: string]: boolean; }; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponseApplication", + "type": "Interface", + "tags": [], + "label": "HasPrivilegesResponseApplication", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.HasPrivilegesResponseApplication.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[resource: string]: { [privilegeName: string]: boolean; }", + "description": [], + "signature": [ + "[resource: string]: { [privilegeName: string]: boolean; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeyResult", + "type": "Interface", + "tags": [], + "label": "InvalidateAPIKeyResult", + "description": [ + "\nThe return value when invalidating an API key in Elasticsearch." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeyResult.invalidated_api_keys", + "type": "Array", + "tags": [], + "label": "invalidated_api_keys", + "description": [ + "\nThe IDs of the API keys that were invalidated as part of the request." + ], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeyResult.previously_invalidated_api_keys", + "type": "Array", + "tags": [], + "label": "previously_invalidated_api_keys", + "description": [ + "\nThe IDs of the API keys that were already invalidated." + ], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeyResult.error_count", + "type": "number", + "tags": [], + "label": "error_count", + "description": [ + "\nThe number of errors that were encountered when invalidating the API keys." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeyResult.error_details", + "type": "Array", + "tags": [], + "label": "error_details", + "description": [ + "\nDetails about these errors. This field is not present in the response when error_count is 0." + ], + "signature": [ + "{ type?: string | undefined; reason?: string | undefined; caused_by?: { type?: string | undefined; reason?: string | undefined; } | undefined; }[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeysParams", + "type": "Interface", + "tags": [], + "label": "InvalidateAPIKeysParams", + "description": [ + "\nRepresents the params for invalidating multiple API keys" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.InvalidateAPIKeysParams.ids", + "type": "Array", + "tags": [], + "label": "ids", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsRolesByFeatureIdRequest", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest.context", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-deprecations-server", + "scope": "common", + "docId": "kibKbnCoreDeprecationsServerPluginApi", + "section": "def-common.GetDeprecationsContext", + "text": "GetDeprecationsContext" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest.featureId", + "type": "string", + "tags": [], + "label": "featureId", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsRolesByFeatureIdResponse", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse.roles", + "type": "Array", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.Role", + "text": "Role" + }, + "[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse.errors", + "type": "Array", + "tags": [], + "label": "errors", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-deprecations-common", + "scope": "common", + "docId": "kibKbnCoreDeprecationsCommonPluginApi", + "section": "def-common.DeprecationsDetails", + "text": "DeprecationsDetails" + }, + "[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsService", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsService", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsService.getKibanaRolesByFeatureId", + "type": "Function", + "tags": [], + "label": "getKibanaRolesByFeatureId", + "description": [], + "signature": [ + "(args: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "text": "PrivilegeDeprecationsRolesByFeatureIdRequest" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse", + "text": "PrivilegeDeprecationsRolesByFeatureIdResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.PrivilegeDeprecationsService.getKibanaRolesByFeatureId.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "text": "PrivilegeDeprecationsRolesByFeatureIdRequest" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SavedObjectActions", + "type": "Interface", + "tags": [], + "label": "SavedObjectActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SavedObjectActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(type: string, operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SavedObjectActions.get.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SavedObjectActions.get.$2", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginSetup", + "type": "Interface", + "tags": [], + "label": "SecurityPluginSetup", + "description": [ + "\nDescribes public Security plugin contract returned at the `setup` stage." + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginSetup.license", + "type": "Object", + "tags": [], + "label": "license", + "description": [ + "\nExposes information about the available security features under the current license." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.SecurityLicense", + "text": "SecurityLicense" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginSetup.audit", + "type": "Object", + "tags": [], + "label": "audit", + "description": [ + "\nExposes services for audit logging." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditServiceSetup", + "text": "AuditServiceSetup" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginSetup.privilegeDeprecationsService", + "type": "Object", + "tags": [], + "label": "privilegeDeprecationsService", + "description": [ + "\nExposes services to access kibana roles per feature id with the GetDeprecationsContext" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsService", + "text": "PrivilegeDeprecationsService" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginStart", + "type": "Interface", + "tags": [], + "label": "SecurityPluginStart", + "description": [ + "\nDescribes public Security plugin contract returned at the `start` stage." + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginStart.authc", + "type": "Object", + "tags": [], + "label": "authc", + "description": [ + "\nAuthentication services to confirm the user is who they say they are." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuthenticationServiceStart", + "text": "AuthenticationServiceStart" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginStart.authz", + "type": "Object", + "tags": [], + "label": "authz", + "description": [ + "\nAuthorization services to manage and access the permissions a particular user has." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuthorizationServiceSetup", + "text": "AuthorizationServiceSetup" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SecurityPluginStart.userProfiles", + "type": "Object", + "tags": [], + "label": "userProfiles", + "description": [ + "\nUser profiles services to retrieve user profiles." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileServiceStart", + "text": "UserProfileServiceStart" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SpaceActions", + "type": "Interface", + "tags": [], + "label": "SpaceActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.SpaceActions.manage", + "type": "string", + "tags": [], + "label": "manage", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UIActions", + "type": "Interface", + "tags": [], + "label": "UIActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UIActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(featureId: keyof ", + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + }, + ", ...uiCapabilityParts: string[]) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UIActions.get.$1", + "type": "CompoundType", + "tags": [], + "label": "featureId", + "description": [], + "signature": [ + "keyof ", + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UIActions.get.$2", + "type": "Array", + "tags": [], + "label": "uiCapabilityParts", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileBulkGetParams", + "type": "Interface", + "tags": [], + "label": "UserProfileBulkGetParams", + "description": [ + "\nParameters for the bulk get API." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileBulkGetParams.uids", + "type": "Object", + "tags": [], + "label": "uids", + "description": [ + "\nList of user profile identifiers." + ], + "signature": [ + "Set" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileBulkGetParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, suggest API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileGetCurrentParams", + "type": "Interface", + "tags": [], + "label": "UserProfileGetCurrentParams", + "description": [ + "\nParameters for the get user profile for the current user API." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileGetCurrentParams.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "\nUser request instance to get user profile for." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileGetCurrentParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, get API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileRequiredPrivileges", + "type": "Interface", + "tags": [], + "label": "UserProfileRequiredPrivileges", + "description": [ + "\nThe set of privileges that users associated with the suggested user profile should have for a specified space id." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileRequiredPrivileges.spaceId", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [ + "\nThe id of the Kibana Space." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileRequiredPrivileges.privileges", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [ + "\nThe set of the Kibana specific application privileges." + ], + "signature": [ + "{ kibana: string[]; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart", + "type": "Interface", + "tags": [], + "label": "UserProfileServiceStart", + "description": [ + "\nA set of methods to work with Kibana user profiles." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.getCurrent", + "type": "Function", + "tags": [], + "label": "getCurrent", + "description": [ + "\nRetrieves a user profile for the current user extracted from the specified request. If the profile isn't available,\ne.g. for the anonymous users or users authenticated via authenticating proxies, the `null` value is returned." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileGetCurrentParams", + "text": "UserProfileGetCurrentParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfileWithSecurity", + "text": "UserProfileWithSecurity" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.getCurrent.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Get current user profile operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileGetCurrentParams", + "text": "UserProfileGetCurrentParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.bulkGet", + "type": "Function", + "tags": [], + "label": "bulkGet", + "description": [ + "\nRetrieves multiple user profiles by their identifiers." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileBulkGetParams", + "text": "UserProfileBulkGetParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "[]>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.bulkGet.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Bulk get operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileBulkGetParams", + "text": "UserProfileBulkGetParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.suggest", + "type": "Function", + "tags": [], + "label": "suggest", + "description": [ + "\nSuggests multiple user profiles by search criteria." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileSuggestParams", + "text": "UserProfileSuggestParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "[]>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileServiceStart.suggest.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Suggest operation parameters." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileSuggestParams", + "text": "UserProfileSuggestParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams", + "type": "Interface", + "tags": [], + "label": "UserProfileSuggestParams", + "description": [ + "\nParameters for the suggest API." + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nQuery string used to match name-related fields in user profiles. The following fields are treated as\nname-related: username, full_name and email." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams.hint", + "type": "Object", + "tags": [], + "label": "hint", + "description": [ + "\nExtra search criteria to improve relevance of the suggestion result. A profile matching the\nspecified hint is ranked higher in the response. But not-matching the hint does not exclude a\nprofile from the response as long as it matches the `name` field query." + ], + "signature": [ + "{ uids: string[]; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams.size", + "type": "number", + "tags": [], + "label": "size", + "description": [ + "\nDesired number of suggestion to return. The default value is 10." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams.dataPath", + "type": "string", + "tags": [], + "label": "dataPath", + "description": [ + "\nBy default, suggest API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.UserProfileSuggestParams.requiredPrivileges", + "type": "Object", + "tags": [], + "label": "requiredPrivileges", + "description": [ + "\nThe set of the privileges that users associated with the suggested user profile should have in the specified space.\nIf not specified, privileges check isn't performed and all matched profiles are returned irrespective to the\nprivileges of the associated users." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileRequiredPrivileges", + "text": "UserProfileRequiredPrivileges" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ValidateAPIKeyParams", + "type": "Interface", + "tags": [], + "label": "ValidateAPIKeyParams", + "description": [ + "\nRepresents the parameters for validating API Key credentials." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ValidateAPIKeyParams.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique id for this API key" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ValidateAPIKeyParams.api_key", + "type": "string", + "tags": [], + "label": "api_key", + "description": [ + "\nGenerated API Key (secret)" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesDynamically", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesDynamically", + "description": [], + "signature": [ + "(privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesDynamically.$1", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesDynamically.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesDynamicallyWithRequest", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesDynamicallyWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesDynamically", + "text": "CheckPrivilegesDynamically" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesDynamicallyWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesWithRequest", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivileges", + "text": "CheckPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckSavedObjectsPrivileges", + "type": "Type", + "tags": [], + "label": "CheckSavedObjectsPrivileges", + "description": [], + "signature": [ + "(actions: string | string[], namespaceOrNamespaces?: string | (string | undefined)[] | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckSavedObjectsPrivileges.$1", + "type": "CompoundType", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckSavedObjectsPrivileges.$2", + "type": "CompoundType", + "tags": [], + "label": "namespaceOrNamespaces", + "description": [], + "signature": [ + "string | (string | undefined)[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckSavedObjectsPrivilegesWithRequest", + "type": "Type", + "tags": [], + "label": "CheckSavedObjectsPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckSavedObjectsPrivileges", + "text": "CheckSavedObjectsPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CheckSavedObjectsPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CreateAPIKeyParams", + "type": "Type", + "tags": [], + "label": "CreateAPIKeyParams", + "description": [], + "signature": [ + "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CreateAPIKeyResult", + "type": "Type", + "tags": [], + "label": "CreateAPIKeyResult", + "description": [ + "\nResponse of Kibana Create API key endpoint." + ], + "signature": [ + "SecurityCreateApiKeyResponse" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CreateCrossClusterAPIKeyParams", + "type": "Type", + "tags": [], + "label": "CreateCrossClusterAPIKeyParams", + "description": [], + "signature": [ + "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CreateRestAPIKeyParams", + "type": "Type", + "tags": [], + "label": "CreateRestAPIKeyParams", + "description": [], + "signature": [ + "{ readonly type?: \"rest\" | undefined; readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly name: string; readonly role_descriptors: Record>; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.CreateRestAPIKeyWithKibanaPrivilegesParams", + "type": "Type", + "tags": [], + "label": "CreateRestAPIKeyWithKibanaPrivilegesParams", + "description": [], + "signature": [ + "{ readonly type?: \"rest\" | undefined; readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly name: string; readonly kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.ElasticsearchPrivilegesType", + "type": "Type", + "tags": [], + "label": "ElasticsearchPrivilegesType", + "description": [], + "signature": [ + "{ readonly cluster?: string[] | undefined; readonly indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; readonly remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; readonly run_as?: string[] | undefined; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.GLOBAL_RESOURCE", + "type": "string", + "tags": [], + "label": "GLOBAL_RESOURCE", + "description": [], + "signature": [ + "\"*\"" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.KibanaPrivilegesType", + "type": "Type", + "tags": [], + "label": "KibanaPrivilegesType", + "description": [], + "signature": [ + "Readonly<{ base?: string[] | undefined; feature?: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.crossClusterApiKeySchema", + "type": "Object", + "tags": [], + "label": "crossClusterApiKeySchema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "; name: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; expiration: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; role_descriptors: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ">>; metadata: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined>; }, { type: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<\"cross_cluster\">; role_descriptors: null; access: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "<{ search: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "[] | undefined>; replication: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "[] | undefined>; }>; }>>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.elasticsearchRoleSchema", + "type": "Object", + "tags": [], + "label": "elasticsearchRoleSchema", + "description": [ + "\nElasticsearch specific portion of the role definition.\nSee more details at https://www.elastic.co/guide/en/elasticsearch/reference/master/security-api.html#security-role-apis." + ], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "<{ cluster: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; indices: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined>; remote_indices: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined>; run_as: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-plugin-types-server", + "id": "def-server.restApiKeySchema", + "type": "Object", + "tags": [], + "label": "restApiKeySchema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "<{ type: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<\"rest\" | undefined>; name: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; expiration: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; role_descriptors: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ">>; metadata: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " | undefined>; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx new file mode 100644 index 000000000000..4a0569a3060d --- /dev/null +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -0,0 +1,39 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnSecurityPluginTypesServerPluginApi +slug: /kibana-dev-docs/api/kbn-security-plugin-types-server +title: "@kbn/security-plugin-types-server" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/security-plugin-types-server plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] +--- +import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; + + + +Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 213 | 0 | 114 | 0 | + +## Server + +### Objects + + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_security_solution_features.devdocs.json b/api_docs/kbn_security_solution_features.devdocs.json index efeb01d3237a..ec6f97556d3c 100644 --- a/api_docs/kbn_security_solution_features.devdocs.json +++ b/api_docs/kbn_security_solution_features.devdocs.json @@ -418,7 +418,7 @@ "section": "def-common.RecursivePartial", "text": "RecursivePartial" }, - "<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; } | undefined>; disabled?: ", + "<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; settings?: readonly string[] | undefined; } | undefined>; disabled?: ", { "pluginId": "@kbn/utility-types", "scope": "common", diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index acfe12918e43..8633c25ce1a2 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 83314b028e90..4582e589ff1d 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 954e8635746a..334a94d8cc05 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 8314689fb672..8182ba2cceff 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 9a5e450d64ca..25c48ad90978 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.devdocs.json b/api_docs/kbn_securitysolution_data_table.devdocs.json index 7bdb8cf37086..b003dd04c9e8 100644 --- a/api_docs/kbn_securitysolution_data_table.devdocs.json +++ b/api_docs/kbn_securitysolution_data_table.devdocs.json @@ -1864,6 +1864,14 @@ "section": "def-common.TableEntityType", "text": "TableEntityType" }, + "; \"risk-inputs\": ", + { + "pluginId": "@kbn/securitysolution-data-table", + "scope": "common", + "docId": "kibKbnSecuritysolutionDataTablePluginApi", + "section": "def-common.TableEntityType", + "text": "TableEntityType" + }, "; }" ], "path": "x-pack/packages/security-solution/data_table/common/types/data_table/index.ts", diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index a47ddc3626be..d3121fb78f0f 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 37d81e7a893d..9eebf988ead4 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 2139e894450e..a6de2f73d9f7 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json index 09a5e5bbddaf..43eab9a3b501 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.devdocs.json +++ b/api_docs/kbn_securitysolution_exception_list_components.devdocs.json @@ -834,7 +834,7 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"section\" | \"circle\" | \"code\" | \"line\" | \"area\" | \"animate\" | \"view\" | \"var\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"br\" | \"clipPath\" | \"textarea\" | \"abbr\" | \"address\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"button\" | \"caption\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"aside\" | \"audio\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"html\" | \"i\" | \"iframe\" | \"img\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"section\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"line\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, @@ -848,7 +848,7 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"section\" | \"circle\" | \"code\" | \"line\" | \"area\" | \"animate\" | \"view\" | \"var\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"br\" | \"clipPath\" | \"textarea\" | \"abbr\" | \"address\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"button\" | \"caption\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"aside\" | \"audio\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"html\" | \"i\" | \"iframe\" | \"img\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"section\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"line\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/meta/index.tsx", "deprecated": false, @@ -987,7 +987,7 @@ "label": "securityLinkAnchorComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"section\" | \"circle\" | \"code\" | \"line\" | \"area\" | \"animate\" | \"view\" | \"var\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"br\" | \"clipPath\" | \"textarea\" | \"abbr\" | \"address\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"button\" | \"caption\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"aside\" | \"audio\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"html\" | \"i\" | \"iframe\" | \"img\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"section\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"line\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, @@ -1001,7 +1001,7 @@ "label": "formattedDateComponent", "description": [], "signature": [ - "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"section\" | \"circle\" | \"code\" | \"line\" | \"area\" | \"animate\" | \"view\" | \"var\" | \"html\" | \"a\" | \"img\" | \"audio\" | \"br\" | \"clipPath\" | \"textarea\" | \"abbr\" | \"address\" | \"aside\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"button\" | \"caption\" | \"cite\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"i\" | \"iframe\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"video\" | \"wbr\" | \"webview\" | \"animateMotion\" | \"animateTransform\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\"" + "\"symbol\" | \"object\" | \"big\" | \"link\" | \"small\" | \"sub\" | \"sup\" | \"source\" | \"desc\" | \"filter\" | \"text\" | \"map\" | \"head\" | React.ComponentType | \"slot\" | \"style\" | \"title\" | \"meta\" | \"data\" | \"pattern\" | \"summary\" | \"template\" | \"span\" | \"main\" | \"path\" | \"form\" | \"body\" | \"q\" | \"label\" | \"progress\" | \"legend\" | \"article\" | \"image\" | \"menu\" | \"stop\" | \"base\" | \"s\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"canvas\" | \"svg\" | \"select\" | \"output\" | \"script\" | \"time\" | \"mask\" | \"input\" | \"a\" | \"abbr\" | \"address\" | \"area\" | \"aside\" | \"audio\" | \"b\" | \"bdi\" | \"bdo\" | \"blockquote\" | \"br\" | \"button\" | \"caption\" | \"cite\" | \"code\" | \"col\" | \"colgroup\" | \"datalist\" | \"dd\" | \"del\" | \"details\" | \"dfn\" | \"dialog\" | \"div\" | \"dl\" | \"dt\" | \"em\" | \"embed\" | \"fieldset\" | \"figcaption\" | \"figure\" | \"footer\" | \"header\" | \"hgroup\" | \"hr\" | \"html\" | \"i\" | \"iframe\" | \"img\" | \"ins\" | \"kbd\" | \"keygen\" | \"li\" | \"mark\" | \"menuitem\" | \"meter\" | \"nav\" | \"noindex\" | \"noscript\" | \"ol\" | \"optgroup\" | \"option\" | \"param\" | \"picture\" | \"pre\" | \"rp\" | \"rt\" | \"ruby\" | \"samp\" | \"section\" | \"strong\" | \"table\" | \"tbody\" | \"td\" | \"textarea\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"track\" | \"u\" | \"ul\" | \"var\" | \"video\" | \"wbr\" | \"webview\" | \"animate\" | \"animateMotion\" | \"animateTransform\" | \"circle\" | \"clipPath\" | \"defs\" | \"ellipse\" | \"feBlend\" | \"feColorMatrix\" | \"feComponentTransfer\" | \"feComposite\" | \"feConvolveMatrix\" | \"feDiffuseLighting\" | \"feDisplacementMap\" | \"feDistantLight\" | \"feDropShadow\" | \"feFlood\" | \"feFuncA\" | \"feFuncB\" | \"feFuncG\" | \"feFuncR\" | \"feGaussianBlur\" | \"feImage\" | \"feMerge\" | \"feMergeNode\" | \"feMorphology\" | \"feOffset\" | \"fePointLight\" | \"feSpecularLighting\" | \"feSpotLight\" | \"feTile\" | \"feTurbulence\" | \"foreignObject\" | \"g\" | \"line\" | \"linearGradient\" | \"marker\" | \"metadata\" | \"mpath\" | \"polygon\" | \"polyline\" | \"radialGradient\" | \"rect\" | \"switch\" | \"textPath\" | \"tspan\" | \"use\" | \"view\"" ], "path": "packages/kbn-securitysolution-exception-list-components/src/exception_item_card/exception_item_card.tsx", "deprecated": false, diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index a60e455be190..065742882d41 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.devdocs.json b/api_docs/kbn_securitysolution_grouping.devdocs.json index 2e18758ff84b..86037516e700 100644 --- a/api_docs/kbn_securitysolution_grouping.devdocs.json +++ b/api_docs/kbn_securitysolution_grouping.devdocs.json @@ -108,7 +108,9 @@ "\nHook to configure grouping component" ], "signature": [ - "({ componentProps, defaultGroupingOptions, fields, groupingId, maxGroupingLevels, onGroupChange, onOptionsChange, tracker, }: GroupingArgs) => Grouping" + "({ componentProps, defaultGroupingOptions, fields, groupingId, maxGroupingLevels, onGroupChange, onOptionsChange, tracker, title, }: GroupingArgs) => ", + "UseGrouping", + "" ], "path": "packages/kbn-securitysolution-grouping/src/hooks/use_grouping.tsx", "deprecated": false, @@ -119,7 +121,7 @@ "id": "def-common.useGrouping.$1", "type": "Object", "tags": [], - "label": "{\n componentProps,\n defaultGroupingOptions,\n fields,\n groupingId,\n maxGroupingLevels,\n onGroupChange,\n onOptionsChange,\n tracker,\n}", + "label": "{\n componentProps,\n defaultGroupingOptions,\n fields,\n groupingId,\n maxGroupingLevels,\n onGroupChange,\n onOptionsChange,\n tracker,\n title,\n}", "description": [], "signature": [ "GroupingArgs" diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index a5f7d5a72096..a3731d0d1676 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-explore](https://github.com/orgs/elast | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 17 | 0 | 12 | 7 | +| 17 | 0 | 12 | 8 | ## Common diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 1230620c33ce..c2c1017fd6f0 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 4d7f46b3fbae..36d45f8b505d 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 72e993e17610..52276e802af4 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index b8f33bd27651..8d5237772e05 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 9358eaf1778c..b4a6a86cc3cb 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 43ff4d8d86e7..36a7e975df78 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.devdocs.json b/api_docs/kbn_securitysolution_list_constants.devdocs.json index 1c3812564f68..04c226b657fc 100644 --- a/api_docs/kbn_securitysolution_list_constants.devdocs.json +++ b/api_docs/kbn_securitysolution_list_constants.devdocs.json @@ -299,14 +299,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/event_filter_validator.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts" @@ -900,14 +892,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts" diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index da004a21dfea..f4c1742346c3 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index a89758a11264..83a075b81a77 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index ed415baa5652..b1e0f91d3f45 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 78284029c6d3..de2ae9eaf52e 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index d89bf951b890..603084890049 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.devdocs.json b/api_docs/kbn_securitysolution_utils.devdocs.json index 515eb8ddac52..50fb827a8705 100644 --- a/api_docs/kbn_securitysolution_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_utils.devdocs.json @@ -466,7 +466,7 @@ "section": "def-common.OperatingSystem", "text": "OperatingSystem" }, - "; value?: string | undefined; }) => string | undefined" + "; value: string; }) => string | undefined" ], "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", "deprecated": false, @@ -477,7 +477,7 @@ "id": "def-common.validateFilePathInput.$1", "type": "Object", "tags": [], - "label": "{\n os,\n value = '',\n}", + "label": "{\n os,\n value,\n}", "description": [], "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", "deprecated": false, @@ -510,6 +510,90 @@ "tags": [], "label": "value", "description": [], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validatePotentialWildcardInput", + "type": "Function", + "tags": [], + "label": "validatePotentialWildcardInput", + "description": [], + "signature": [ + "({ field, os, value, }: { field?: string | undefined; os: ", + { + "pluginId": "@kbn/securitysolution-utils", + "scope": "common", + "docId": "kibKbnSecuritysolutionUtilsPluginApi", + "section": "def-common.OperatingSystem", + "text": "OperatingSystem" + }, + "; value?: string | undefined; }) => string | undefined" + ], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validatePotentialWildcardInput.$1", + "type": "Object", + "tags": [], + "label": "{\n field = '',\n os,\n value = '',\n}", + "description": [], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validatePotentialWildcardInput.$1.field", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validatePotentialWildcardInput.$1.os", + "type": "Enum", + "tags": [], + "label": "os", + "description": [], + "signature": [ + { + "pluginId": "@kbn/securitysolution-utils", + "scope": "common", + "docId": "kibKbnSecuritysolutionUtilsPluginApi", + "section": "def-common.OperatingSystem", + "text": "OperatingSystem" + } + ], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validatePotentialWildcardInput.$1.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], "signature": [ "string | undefined" ], @@ -522,6 +606,39 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validateWildcardInput", + "type": "Function", + "tags": [], + "label": "validateWildcardInput", + "description": [], + "signature": [ + "(value?: string | undefined) => string | undefined" + ], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.validateWildcardInput.$1", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [], @@ -624,18 +741,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-utils", - "id": "def-common.FILENAME_WILDCARD_WARNING", - "type": "string", - "tags": [], - "label": "FILENAME_WILDCARD_WARNING", - "description": [], - "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-utils", "id": "def-common.FILEPATH_WARNING", @@ -677,6 +782,18 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.WILDCARD_WARNING", + "type": "string", + "tags": [], + "label": "WILDCARD_WARNING", + "description": [], + "path": "packages/kbn-securitysolution-utils/src/path_validations/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index f1ca29e4324d..1159cc7f4f09 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detection-engine](https://github.com/orgs/elastic/tea | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 37 | 0 | 32 | 0 | +| 44 | 0 | 39 | 0 | ## Common diff --git a/api_docs/kbn_server_http_tools.devdocs.json b/api_docs/kbn_server_http_tools.devdocs.json index ace0c332ca51..768f9868081a 100644 --- a/api_docs/kbn_server_http_tools.devdocs.json +++ b/api_docs/kbn_server_http_tools.devdocs.json @@ -177,6 +177,52 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.SslConfig.isEqualTo", + "type": "Function", + "tags": [], + "label": "isEqualTo", + "description": [], + "signature": [ + "(otherConfig: ", + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.SslConfig", + "text": "SslConfig" + }, + ") => boolean" + ], + "path": "packages/kbn-server-http-tools/src/ssl/ssl_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.SslConfig.isEqualTo.$1", + "type": "Object", + "tags": [], + "label": "otherConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.SslConfig", + "text": "SslConfig" + } + ], + "path": "packages/kbn-server-http-tools/src/ssl/ssl_config.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false @@ -492,6 +538,125 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.getServerTLSOptions", + "type": "Function", + "tags": [], + "label": "getServerTLSOptions", + "description": [ + "\nConverts Kibana `SslConfig` into `TLSOptions` that are accepted by the Hapi server,\nand by https.Server.setSecureContext()" + ], + "signature": [ + "(ssl: ", + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.ISslConfig", + "text": "ISslConfig" + }, + ") => ", + "ServerOptions", + " | undefined" + ], + "path": "packages/kbn-server-http-tools/src/get_server_options.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.getServerTLSOptions.$1", + "type": "Object", + "tags": [], + "label": "ssl", + "description": [], + "signature": [ + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.ISslConfig", + "text": "ISslConfig" + } + ], + "path": "packages/kbn-server-http-tools/src/get_server_options.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.setTlsConfig", + "type": "Function", + "tags": [], + "label": "setTlsConfig", + "description": [], + "signature": [ + "(hapiServer: ", + "Server", + ", sslConfig: ", + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.ISslConfig", + "text": "ISslConfig" + }, + ") => void" + ], + "path": "packages/kbn-server-http-tools/src/set_tls_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.setTlsConfig.$1", + "type": "Object", + "tags": [], + "label": "hapiServer", + "description": [], + "signature": [ + "Server" + ], + "path": "packages/kbn-server-http-tools/src/set_tls_config.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.setTlsConfig.$2", + "type": "Object", + "tags": [], + "label": "sslConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.ISslConfig", + "text": "ISslConfig" + } + ], + "path": "packages/kbn-server-http-tools/src/set_tls_config.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [ diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 39dd797375d7..02377baa1d82 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 54 | 0 | 51 | 1 | +| 61 | 0 | 57 | 1 | ## Common diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 50fecfe29e16..2a0558f0f8ba 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 6dceb8358359..c2e898a336d8 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 9cfec6403190..268e80bf84bd 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 63f0b32b0f2f..7793adc7365a 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 27dd6e08fe45..2c704d3ffd45 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 7f594a11d155..1274f6e948cc 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index b50171c4b28f..753c928f7211 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 30112dfacaec..7b787536540b 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 0ad6bb9cae25..ecb28dbafc7a 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 4f62db815bb1..1849b6cc23ca 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 9af0278eb636..a9ffc86d61cf 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.devdocs.json b/api_docs/kbn_shared_ux_card_no_data.devdocs.json index 30043835cff5..e5df01115951 100644 --- a/api_docs/kbn_shared_ux_card_no_data.devdocs.json +++ b/api_docs/kbn_shared_ux_card_no_data.devdocs.json @@ -148,7 +148,7 @@ "signature": [ "Partial> & { button?: React.ReactNode; onClick?: React.MouseEventHandler | undefined; description?: React.ReactNode; category?: string | undefined; canAccessFleet?: boolean | undefined; }" + ", \"description\" | \"onClick\" | \"isDisabled\" | \"button\" | \"layout\">> & { button?: React.ReactNode; onClick?: React.MouseEventHandler | undefined; description?: React.ReactNode; category?: string | undefined; canAccessFleet?: boolean | undefined; }" ], "path": "packages/shared-ux/card/no_data/types/index.d.ts", "deprecated": false, @@ -186,7 +186,7 @@ "signature": [ "Partial> & { button?: React.ReactNode; onClick?: React.MouseEventHandler | undefined; description?: React.ReactNode; category?: string | undefined; canAccessFleet?: boolean | undefined; }" + ", \"description\" | \"onClick\" | \"isDisabled\" | \"button\" | \"layout\">> & { button?: React.ReactNode; onClick?: React.MouseEventHandler | undefined; description?: React.ReactNode; category?: string | undefined; canAccessFleet?: boolean | undefined; }" ], "path": "packages/shared-ux/card/no_data/types/index.d.ts", "deprecated": false, diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 2597afee40c8..747ba8e7b618 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 42e8b367cc01..f8edfd8b243a 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json index 41742443ed3b..76adf1537f4c 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json +++ b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json @@ -1,38 +1,22 @@ { "id": "@kbn/shared-ux-chrome-navigation", "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { "classes": [], "functions": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.DefaultNavigation", + "id": "def-public.DefaultNavigation", "type": "Function", "tags": [], "label": "DefaultNavigation", "description": [], "signature": [ - "({ projectNavigationTree, navigationTree, dataTestSubj, panelContentProvider, }: React.PropsWithChildren<", + "React.FunctionComponent<", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.ProjectNavigationDefinition", + "section": "def-public.ProjectNavigationDefinition", "text": "ProjectNavigationDefinition" }, "<", @@ -43,50 +27,47 @@ "section": "def-common.AppDeepLinkId", "text": "AppDeepLinkId" }, - ", string, string> & Props>) => JSX.Element" + ", string, string> & Props>" ], "path": "packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx", "deprecated": false, "trackAdoption": false, + "returnComment": [], "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.DefaultNavigation.$1", + "id": "def-public.DefaultNavigation.$1", "type": "CompoundType", "tags": [], - "label": "{\n projectNavigationTree,\n navigationTree,\n dataTestSubj,\n panelContentProvider,\n}", + "label": "props", "description": [], "signature": [ - "React.PropsWithChildren<", - { - "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", - "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.ProjectNavigationDefinition", - "text": "ProjectNavigationDefinition" - }, - "<", - { - "pluginId": "@kbn/core-chrome-browser", - "scope": "common", - "docId": "kibKbnCoreChromeBrowserPluginApi", - "section": "def-common.AppDeepLinkId", - "text": "AppDeepLinkId" - }, - ", string, string> & Props>" + "P & { children?: React.ReactNode; }" ], - "path": "packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx", + "path": "node_modules/@types/react/index.d.ts", "deprecated": false, - "trackAdoption": false, - "isRequired": true + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/shared-ux-chrome-navigation", + "id": "def-public.DefaultNavigation.$2", + "type": "Any", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false } ], - "returnComment": [], "initialIsOpen": false }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -107,7 +88,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "string", "tags": [], "label": "preset", @@ -126,7 +107,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -147,7 +128,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "string", "tags": [], "label": "preset", @@ -166,7 +147,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -187,7 +168,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "string", "tags": [], "label": "preset", @@ -206,7 +187,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -227,7 +208,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "string", "tags": [], "label": "preset", @@ -246,7 +227,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -292,7 +273,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "string", "tags": [], "label": "preset", @@ -311,7 +292,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets", + "id": "def-public.getPresets", "type": "Function", "tags": [], "label": "getPresets", @@ -320,9 +301,9 @@ "(preset: \"all\" | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationGroupPreset", + "section": "def-public.NavigationGroupPreset", "text": "NavigationGroupPreset" }, ") => ", @@ -397,7 +378,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.getPresets.$1", + "id": "def-public.getPresets.$1", "type": "CompoundType", "tags": [], "label": "preset", @@ -406,9 +387,9 @@ "\"all\" | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationGroupPreset", + "section": "def-public.NavigationGroupPreset", "text": "NavigationGroupPreset" } ], @@ -423,7 +404,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.Navigation", + "id": "def-public.Navigation", "type": "Function", "tags": [], "label": "Navigation", @@ -437,7 +418,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.Navigation.$1", + "id": "def-public.Navigation.$1", "type": "Object", "tags": [], "label": "{\n children,\n panelContentProvider,\n unstyled = false,\n dataTestSubj,\n}", @@ -456,7 +437,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationKibanaProvider", + "id": "def-public.NavigationKibanaProvider", "type": "Function", "tags": [], "label": "NavigationKibanaProvider", @@ -474,7 +455,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationKibanaProvider.$1", + "id": "def-public.NavigationKibanaProvider.$1", "type": "CompoundType", "tags": [], "label": "{\n children,\n ...dependencies\n}", @@ -495,7 +476,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationProvider", + "id": "def-public.NavigationProvider", "type": "Function", "tags": [], "label": "NavigationProvider", @@ -506,9 +487,9 @@ "({ children, ...services }: React.PropsWithChildren<", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationServices", + "section": "def-public.NavigationServices", "text": "NavigationServices" }, ">) => JSX.Element" @@ -519,7 +500,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationProvider.$1", + "id": "def-public.NavigationProvider.$1", "type": "CompoundType", "tags": [], "label": "{ children, ...services }", @@ -528,9 +509,9 @@ "React.PropsWithChildren<", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationServices", + "section": "def-public.NavigationServices", "text": "NavigationServices" }, ">" @@ -548,7 +529,7 @@ "interfaces": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.GroupDefinition", + "id": "def-public.GroupDefinition", "type": "Interface", "tags": [], "label": "GroupDefinition", @@ -556,9 +537,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.GroupDefinition", + "section": "def-public.GroupDefinition", "text": "GroupDefinition" }, " extends Omit<", @@ -577,7 +558,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.GroupDefinition.type", + "id": "def-public.GroupDefinition.type", "type": "string", "tags": [], "label": "type", @@ -591,7 +572,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.GroupDefinition.children", + "id": "def-public.GroupDefinition.children", "type": "Array", "tags": [], "label": "children", @@ -615,7 +596,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ItemDefinition", + "id": "def-public.ItemDefinition", "type": "Interface", "tags": [], "label": "ItemDefinition", @@ -623,9 +604,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.ItemDefinition", + "section": "def-public.ItemDefinition", "text": "ItemDefinition" }, " extends Omit<", @@ -644,7 +625,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ItemDefinition.type", + "id": "def-public.ItemDefinition.type", "type": "string", "tags": [], "label": "type", @@ -661,7 +642,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices", + "id": "def-public.NavigationServices", "type": "Interface", "tags": [], "label": "NavigationServices", @@ -674,7 +655,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.basePath", + "id": "def-public.NavigationServices.basePath", "type": "Object", "tags": [], "label": "basePath", @@ -688,7 +669,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.recentlyAccessed$", + "id": "def-public.NavigationServices.recentlyAccessed$", "type": "Object", "tags": [], "label": "recentlyAccessed$", @@ -705,14 +686,14 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.navLinks$", + "id": "def-public.NavigationServices.deepLinks$", "type": "Object", "tags": [], - "label": "navLinks$", + "label": "deepLinks$", "description": [], "signature": [ "Observable", - "" + ">>>" ], "path": "packages/shared-ux/chrome/navigation/types/index.ts", "deprecated": false, @@ -728,7 +709,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.navIsOpen", + "id": "def-public.NavigationServices.navIsOpen", "type": "boolean", "tags": [], "label": "navIsOpen", @@ -739,7 +720,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.navigateToUrl", + "id": "def-public.NavigationServices.navigateToUrl", "type": "Function", "tags": [], "label": "navigateToUrl", @@ -762,7 +743,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.navigateToUrl.$1", + "id": "def-public.NavigationServices.navigateToUrl.$1", "type": "string", "tags": [], "label": "url", @@ -773,7 +754,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.navigateToUrl.$2", + "id": "def-public.NavigationServices.navigateToUrl.$2", "type": "Object", "tags": [], "label": "options", @@ -796,7 +777,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.onProjectNavigationChange", + "id": "def-public.NavigationServices.onProjectNavigationChange", "type": "Function", "tags": [], "label": "onProjectNavigationChange", @@ -818,7 +799,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.onProjectNavigationChange.$1", + "id": "def-public.NavigationServices.onProjectNavigationChange.$1", "type": "Object", "tags": [], "label": "chromeProjectNavigation", @@ -842,7 +823,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.activeNodes$", + "id": "def-public.NavigationServices.activeNodes$", "type": "Object", "tags": [], "label": "activeNodes$", @@ -865,7 +846,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.cloudLinks", + "id": "def-public.NavigationServices.cloudLinks", "type": "Object", "tags": [], "label": "cloudLinks", @@ -887,7 +868,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationServices.isSideNavCollapsed", + "id": "def-public.NavigationServices.isSideNavCollapsed", "type": "boolean", "tags": [], "label": "isSideNavCollapsed", @@ -901,7 +882,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationTreeDefinition", + "id": "def-public.NavigationTreeDefinition", "type": "Interface", "tags": [], "label": "NavigationTreeDefinition", @@ -909,9 +890,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationTreeDefinition", + "section": "def-public.NavigationTreeDefinition", "text": "NavigationTreeDefinition" }, "" @@ -922,7 +903,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationTreeDefinition.body", + "id": "def-public.NavigationTreeDefinition.body", "type": "Array", "tags": [], "label": "body", @@ -932,9 +913,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.RootNavigationItemDefinition", + "section": "def-public.RootNavigationItemDefinition", "text": "RootNavigationItemDefinition" }, "[] | undefined" @@ -945,7 +926,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationTreeDefinition.footer", + "id": "def-public.NavigationTreeDefinition.footer", "type": "Array", "tags": [], "label": "footer", @@ -955,9 +936,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.RootNavigationItemDefinition", + "section": "def-public.RootNavigationItemDefinition", "text": "RootNavigationItemDefinition" }, "[] | undefined" @@ -971,7 +952,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelComponentProps", + "id": "def-public.PanelComponentProps", "type": "Interface", "tags": [], "label": "PanelComponentProps", @@ -982,7 +963,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelComponentProps.closePanel", + "id": "def-public.PanelComponentProps.closePanel", "type": "Function", "tags": [], "label": "closePanel", @@ -1000,7 +981,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelComponentProps.selectedNode", + "id": "def-public.PanelComponentProps.selectedNode", "type": "CompoundType", "tags": [], "label": "selectedNode", @@ -1024,7 +1005,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelComponentProps.activeNodes", + "id": "def-public.PanelComponentProps.activeNodes", "type": "Array", "tags": [], "label": "activeNodes", @@ -1050,7 +1031,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelContent", + "id": "def-public.PanelContent", "type": "Interface", "tags": [], "label": "PanelContent", @@ -1061,7 +1042,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelContent.title", + "id": "def-public.PanelContent.title", "type": "CompoundType", "tags": [], "label": "title", @@ -1075,7 +1056,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PanelContent.content", + "id": "def-public.PanelContent.content", "type": "CompoundType", "tags": [], "label": "content", @@ -1084,9 +1065,9 @@ "React.ComponentType<", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.PanelComponentProps", + "section": "def-public.PanelComponentProps", "text": "PanelComponentProps" }, "> | undefined" @@ -1100,7 +1081,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PresetDefinition", + "id": "def-public.PresetDefinition", "type": "Interface", "tags": [], "label": "PresetDefinition", @@ -1108,17 +1089,17 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.PresetDefinition", + "section": "def-public.PresetDefinition", "text": "PresetDefinition" }, " extends Omit<", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.GroupDefinition", + "section": "def-public.GroupDefinition", "text": "GroupDefinition" }, ", \"type\" | \"children\">" @@ -1129,7 +1110,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PresetDefinition.type", + "id": "def-public.PresetDefinition.type", "type": "string", "tags": [], "label": "type", @@ -1143,7 +1124,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.PresetDefinition.preset", + "id": "def-public.PresetDefinition.preset", "type": "CompoundType", "tags": [], "label": "preset", @@ -1160,7 +1141,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ProjectNavigationDefinition", + "id": "def-public.ProjectNavigationDefinition", "type": "Interface", "tags": [], "label": "ProjectNavigationDefinition", @@ -1168,9 +1149,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.ProjectNavigationDefinition", + "section": "def-public.ProjectNavigationDefinition", "text": "ProjectNavigationDefinition" }, "" @@ -1181,7 +1162,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ProjectNavigationDefinition.projectNavigationTree", + "id": "def-public.ProjectNavigationDefinition.projectNavigationTree", "type": "Array", "tags": [], "label": "projectNavigationTree", @@ -1198,7 +1179,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ProjectNavigationDefinition.navigationTree", + "id": "def-public.ProjectNavigationDefinition.navigationTree", "type": "Object", "tags": [], "label": "navigationTree", @@ -1208,9 +1189,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.NavigationTreeDefinition", + "section": "def-public.NavigationTreeDefinition", "text": "NavigationTreeDefinition" }, " | undefined" @@ -1224,7 +1205,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.RecentlyAccessedDefinition", + "id": "def-public.RecentlyAccessedDefinition", "type": "Interface", "tags": [], "label": "RecentlyAccessedDefinition", @@ -1232,9 +1213,9 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.RecentlyAccessedDefinition", + "section": "def-public.RecentlyAccessedDefinition", "text": "RecentlyAccessedDefinition" }, " extends ", @@ -1246,7 +1227,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.RecentlyAccessedDefinition.type", + "id": "def-public.RecentlyAccessedDefinition.type", "type": "string", "tags": [], "label": "type", @@ -1266,7 +1247,7 @@ "misc": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ContentProvider", + "id": "def-public.ContentProvider", "type": "Type", "tags": [], "label": "ContentProvider", @@ -1275,9 +1256,9 @@ "(nodeId: string) => void | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.PanelContent", + "section": "def-public.PanelContent", "text": "PanelContent" } ], @@ -1288,7 +1269,7 @@ "children": [ { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.ContentProvider.$1", + "id": "def-public.ContentProvider.$1", "type": "string", "tags": [], "label": "nodeId", @@ -1302,7 +1283,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.NavigationGroupPreset", + "id": "def-public.NavigationGroupPreset", "type": "Type", "tags": [], "label": "NavigationGroupPreset", @@ -1319,7 +1300,7 @@ }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.RootNavigationItemDefinition", + "id": "def-public.RootNavigationItemDefinition", "type": "Type", "tags": [], "label": "RootNavigationItemDefinition", @@ -1327,33 +1308,33 @@ "signature": [ { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.RecentlyAccessedDefinition", + "section": "def-public.RecentlyAccessedDefinition", "text": "RecentlyAccessedDefinition" }, " | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.GroupDefinition", + "section": "def-public.GroupDefinition", "text": "GroupDefinition" }, " | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.PresetDefinition", + "section": "def-public.PresetDefinition", "text": "PresetDefinition" }, " | ", { "pluginId": "@kbn/shared-ux-chrome-navigation", - "scope": "common", + "scope": "public", "docId": "kibKbnSharedUxChromeNavigationPluginApi", - "section": "def-common.ItemDefinition", + "section": "def-public.ItemDefinition", "text": "ItemDefinition" }, "" @@ -1365,5 +1346,21 @@ } ], "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] } } \ No newline at end of file diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 5bd9ca718f0d..43f79e050dee 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; @@ -21,16 +21,16 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 60 | 0 | 49 | 5 | +| 61 | 0 | 48 | 5 | -## Common +## Client ### Functions - + ### Interfaces - + ### Consts, variables and types - + diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index d8e841f557be..a7f5393cd7ad 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index fc319ba7b172..461d925c0d36 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index 5d16acbe371a..8a6ee39c69bb 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 98e21161e49a..627c7c44620b 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 132f52fb52ad..6fec8ef12fb0 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 3cb96a8c84b4..a804aef69899 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index ba5b55fe70c1..fc980d50c509 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 36937770ff19..5aca717befbe 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 538be5651a65..b1379cd231b9 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.devdocs.json b/api_docs/kbn_shared_ux_link_redirect_app.devdocs.json index ae8568c37433..aa7633649473 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.devdocs.json +++ b/api_docs/kbn_shared_ux_link_redirect_app.devdocs.json @@ -29,7 +29,9 @@ "\nA service-enabled component that provides Kibana-specific functionality to the `RedirectAppLinks`\npure component.\n" ], "signature": [ - "({ children }: { children?: React.ReactNode; }) => JSX.Element" + "({ children, ...props }: React.PropsWithChildren>) => JSX.Element" ], "path": "packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx", "deprecated": false, @@ -38,12 +40,14 @@ { "parentPluginId": "@kbn/shared-ux-link-redirect-app", "id": "def-common.RedirectAppLinks.$1", - "type": "Object", + "type": "CompoundType", "tags": [], - "label": "{ children }", + "label": "{\n children,\n ...props\n}", "description": [], "signature": [ - "{ children?: React.ReactNode; }" + "React.PropsWithChildren>" ], "path": "packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx", "deprecated": false, @@ -64,7 +68,7 @@ "\nUtility component that will intercept click events on children anchor (``) elements to call\n`navigateToUrl` with the link's href. This will trigger SPA friendly navigation when the link points\nto a valid Kibana app.\n" ], "signature": [ - "({ children, navigateToUrl, currentAppId, }: React.PropsWithChildren<", + "({ children, navigateToUrl, currentAppId, ...containerProps }: React.PropsWithChildren<", "RedirectAppLinksComponentProps", ">) => JSX.Element" ], @@ -77,7 +81,7 @@ "id": "def-common.RedirectAppLinks.$1", "type": "CompoundType", "tags": [], - "label": "{\n children,\n navigateToUrl,\n currentAppId,\n}", + "label": "{\n children,\n navigateToUrl,\n currentAppId,\n ...containerProps\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -317,9 +321,11 @@ "Props for the `RedirectAppLinks` component." ], "signature": [ + "(", "RedirectAppLinksKibanaDependencies", " | ", - "RedirectAppLinksServices" + "RedirectAppLinksServices", + ") & React.ClassAttributes & React.HTMLAttributes" ], "path": "packages/shared-ux/link/redirect_app/types/index.d.ts", "deprecated": false, diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 9b9e16d37e10..c16ae996ed2a 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 1c9aed917722..9765d64f069f 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 8b9880d8e2c3..4dacc3f61887 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 4148f5aa9bb7..98450c763cb3 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index ce9445910503..63d28372775c 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 0f0e2b524936..4b1ee5a6e0ab 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index dfb064bb8f27..45e9ffa9e893 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 3fcba2e9a7d1..aeb11a27ce2c 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 914f0dfe2e92..ef51e4900b82 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 2014e9f28239..1209443cb4f7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 24fb883d80c3..684b77547796 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 05879319e3bd..36b9fe71d1bc 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 3a5f7a3ff9ac..abfedc972ccd 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 7e3bff9e8e1f..739beabd40e5 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 7790de025448..2908280a3ce1 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index bf7585494008..06ae9e797f3c 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 65a4f10bb716..b4419dc39789 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 2746bdc980ce..6866494b0de3 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 3968d04cd795..ed47e1644c7c 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 5478a5d9d8c6..b08f50c36a3e 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 0e019d281ec0..3d69a21a00ae 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index eb9dc7a26549..bf42a39d135b 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index b900f7872543..8251e9e76eaf 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.devdocs.json b/api_docs/kbn_slo_schema.devdocs.json index e11a54eb98d6..4e8b55b423af 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -398,115 +398,7 @@ "initialIsOpen": false } ], - "interfaces": [ - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Paginated", - "type": "Interface", - "tags": [], - "label": "Paginated", - "description": [], - "signature": [ - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Paginated", - "text": "Paginated" - }, - "" - ], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Paginated.total", - "type": "number", - "tags": [], - "label": "total", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Paginated.page", - "type": "number", - "tags": [], - "label": "page", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Paginated.perPage", - "type": "number", - "tags": [], - "label": "perPage", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Paginated.results", - "type": "Array", - "tags": [], - "label": "results", - "description": [], - "signature": [ - "T[]" - ], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Pagination", - "type": "Interface", - "tags": [], - "label": "Pagination", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Pagination.page", - "type": "number", - "tags": [], - "label": "page", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.Pagination.perPage", - "type": "number", - "tags": [], - "label": "perPage", - "description": [], - "path": "x-pack/packages/kbn-slo-schema/src/models/pagination.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - } - ], + "interfaces": [], "enums": [ { "parentPluginId": "@kbn/slo-schema", @@ -729,28 +621,17 @@ }, { "parentPluginId": "@kbn/slo-schema", - "id": "def-common.FindSLODefinitionsParams", + "id": "def-common.FindSloDefinitionsResponse", "type": "Type", - "tags": [], - "label": "FindSLODefinitionsParams", - "description": [], - "signature": [ - "{ search?: string | undefined; includeOutdatedOnly?: boolean | undefined; page?: string | undefined; perPage?: string | undefined; }" + "tags": [ + "private" + ], + "label": "FindSloDefinitionsResponse", + "description": [ + "\nThe response type for /internal/observability/slo/_definitions\n" ], - "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.FindSLODefinitionsResponse", - "type": "Type", - "tags": [], - "label": "FindSLODefinitionsResponse", - "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; })[]; }" + "({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; })[]" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -780,7 +661,7 @@ "label": "FindSLOResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }" + "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -795,7 +676,7 @@ "label": "GetPreviewDataParams", "description": [], "signature": [ - "{ indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; }" + "{ indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; range: { start: number; end: number; }; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -810,7 +691,7 @@ "label": "GetPreviewDataResponse", "description": [], "signature": [ - "{ date: string; sliValue: number; }[]" + "({ date: string; sliValue: number; } & { events?: { good: number; bad: number; total: number; } | undefined; })[]" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -870,7 +751,7 @@ "label": "GetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -982,36 +863,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.ResetSLOParams", - "type": "Type", - "tags": [], - "label": "ResetSLOParams", - "description": [], - "signature": [ - "{ id: string; }" - ], - "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.ResetSLOResponse", - "type": "Type", - "tags": [], - "label": "ResetSLOResponse", - "description": [], - "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }" - ], - "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/slo-schema", "id": "def-common.SLOResponse", @@ -1020,7 +871,7 @@ "label": "SLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1035,7 +886,7 @@ "label": "SLOWithSummaryResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1195,7 +1046,7 @@ "label": "UpdateSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -2094,21 +1945,19 @@ "parentPluginId": "@kbn/slo-schema", "id": "def-common.findSloDefinitionsParamsSchema", "type": "Object", - "tags": [], + "tags": [ + "private" + ], "label": "findSloDefinitionsParamsSchema", - "description": [], + "description": [ + "\nThe query params schema for /internal/observability/slo/_definitions\n" + ], "signature": [ - "PartialC", + "TypeC", "<{ query: ", - "PartialC", + "TypeC", "<{ search: ", "StringC", - "; includeOutdatedOnly: ", - "Type", - "; page: ", - "StringC", - "; perPage: ", - "StringC", "; }>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", @@ -2120,18 +1969,14 @@ "parentPluginId": "@kbn/slo-schema", "id": "def-common.findSloDefinitionsResponseSchema", "type": "Object", - "tags": [], + "tags": [ + "private" + ], "label": "findSloDefinitionsResponseSchema", - "description": [], + "description": [ + "\nThe response schema for /internal/observability/slo/_definitions\n" + ], "signature": [ - "TypeC", - "<{ page: ", - "NumberC", - "; perPage: ", - "NumberC", - "; total: ", - "NumberC", - "; results: ", "ArrayC", "<", "IntersectionC", @@ -2569,9 +2414,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", @@ -2579,7 +2422,7 @@ "LiteralC", "<\"*\">, ", "StringC", - "]>; }>]>>; }>" + "]>; }>]>>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -3081,9 +2924,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", @@ -3465,7 +3306,13 @@ "PartialC", "<{ filter: ", "StringC", - "; }>]>; }>]>; }>; }>" + "; }>]>; }>]>; range: ", + "TypeC", + "<{ start: ", + "NumberC", + "; end: ", + "NumberC", + "; }>; }>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -3482,12 +3329,24 @@ "signature": [ "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ date: ", "Type", "; sliValue: ", "NumberC", - "; }>>" + "; }>, ", + "PartialC", + "<{ events: ", + "TypeC", + "<{ good: ", + "NumberC", + "; bad: ", + "NumberC", + "; total: ", + "NumberC", + "; }>; }>]>>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -4083,9 +3942,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", @@ -5022,12 +4879,24 @@ "label": "previewDataSchema", "description": [], "signature": [ + "IntersectionC", + "<[", "TypeC", "<{ date: ", "Type", "; sliValue: ", "NumberC", - "; }>" + "; }>, ", + "PartialC", + "<{ events: ", + "TypeC", + "<{ good: ", + "NumberC", + "; bad: ", + "NumberC", + "; total: ", + "NumberC", + "; }>; }>]>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/common.ts", "deprecated": false, @@ -5036,536 +4905,56 @@ }, { "parentPluginId": "@kbn/slo-schema", - "id": "def-common.resetSLOParamsSchema", + "id": "def-common.rollingTimeWindowSchema", "type": "Object", "tags": [], - "label": "resetSLOParamsSchema", + "label": "rollingTimeWindowSchema", "description": [], "signature": [ "TypeC", - "<{ path: ", - "TypeC", - "<{ id: ", - "StringC", - "; }>; }>" + "<{ duration: ", + "Type", + "<", + { + "pluginId": "@kbn/slo-schema", + "scope": "common", + "docId": "kibKbnSloSchemaPluginApi", + "section": "def-common.Duration", + "text": "Duration" + }, + ", string, unknown>; type: ", + "LiteralC", + "<\"rolling\">; }>" ], - "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", + "path": "x-pack/packages/kbn-slo-schema/src/schema/time_window.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/slo-schema", - "id": "def-common.resetSLOResponseSchema", + "id": "def-common.rollingTimeWindowTypeSchema", "type": "Object", "tags": [], - "label": "resetSLOResponseSchema", + "label": "rollingTimeWindowTypeSchema", "description": [], "signature": [ - "IntersectionC", - "<[", - "TypeC", - "<{ id: ", - "StringC", - "; name: ", - "StringC", - "; description: ", - "StringC", - "; indicator: ", - "UnionC", - "<[", - "TypeC", - "<{ type: ", "LiteralC", - "<\"sli.apm.transactionDuration\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ environment: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; service: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; transactionType: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; transactionName: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; threshold: ", - "NumberC", - "; index: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>, ", - "TypeC", - "<{ type: ", - "LiteralC", - "<\"sli.apm.transactionErrorRate\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ environment: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; service: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; transactionType: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; transactionName: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; index: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>, ", - "TypeC", - "<{ type: ", - "LiteralC", - "<\"sli.kql.custom\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ index: ", - "StringC", - "; good: ", - "StringC", - "; total: ", - "StringC", - "; timestampField: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>, ", - "TypeC", - "<{ type: ", - "LiteralC", - "<\"sli.metric.custom\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ index: ", - "StringC", - "; good: ", - "TypeC", - "<{ metrics: ", - "ArrayC", - "<", - "UnionC", - "<[", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"sum\">; field: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"doc_count\">; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>]>>; equation: ", - "StringC", - "; }>; total: ", - "TypeC", - "<{ metrics: ", - "ArrayC", - "<", - "UnionC", - "<[", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"sum\">; field: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"doc_count\">; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>]>>; equation: ", - "StringC", - "; }>; timestampField: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>, ", - "TypeC", - "<{ type: ", - "LiteralC", - "<\"sli.metric.timeslice\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ index: ", - "StringC", - "; metric: ", - "TypeC", - "<{ metrics: ", - "ArrayC", - "<", - "UnionC", - "<[", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "KeyofC", - "<{ avg: boolean; max: boolean; min: boolean; sum: boolean; cardinality: boolean; last_value: boolean; std_deviation: boolean; }>; field: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"doc_count\">; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ name: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"percentile\">; field: ", - "StringC", - "; percentile: ", - "NumberC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>]>>; equation: ", - "StringC", - "; threshold: ", - "NumberC", - "; comparator: ", - "KeyofC", - "<{ GT: string; GTE: string; LT: string; LTE: string; }>; }>; timestampField: ", - "StringC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>, ", - "TypeC", - "<{ type: ", - "LiteralC", - "<\"sli.histogram.custom\">; params: ", - "IntersectionC", - "<[", - "TypeC", - "<{ index: ", - "StringC", - "; timestampField: ", - "StringC", - "; good: ", - "UnionC", - "<[", - "IntersectionC", - "<[", - "TypeC", - "<{ field: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"value_count\">; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ field: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"range\">; from: ", - "NumberC", - "; to: ", - "NumberC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>]>; total: ", - "UnionC", - "<[", - "IntersectionC", - "<[", - "TypeC", - "<{ field: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"value_count\">; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ field: ", - "StringC", - "; aggregation: ", - "LiteralC", - "<\"range\">; from: ", - "NumberC", - "; to: ", - "NumberC", - "; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>]>; }>, ", - "PartialC", - "<{ filter: ", - "StringC", - "; }>]>; }>]>; timeWindow: ", - "UnionC", - "<[", - "TypeC", - "<{ duration: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; type: ", - "LiteralC", - "<\"rolling\">; }>, ", - "TypeC", - "<{ duration: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; type: ", - "LiteralC", - "<\"calendarAligned\">; }>]>; budgetingMethod: ", - "UnionC", - "<[", - "LiteralC", - "<\"occurrences\">, ", - "LiteralC", - "<\"timeslices\">]>; objective: ", - "IntersectionC", - "<[", - "TypeC", - "<{ target: ", - "NumberC", - "; }>, ", - "PartialC", - "<{ timesliceTarget: ", - "NumberC", - "; timesliceWindow: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; }>]>; revision: ", - "NumberC", - "; settings: ", - "TypeC", - "<{ syncDelay: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; frequency: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; }>; enabled: ", - "BooleanC", - "; tags: ", - "ArrayC", - "<", - "StringC", - ">; groupBy: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; createdAt: ", - "Type", - "; updatedAt: ", - "Type", - "; version: ", - "NumberC", - "; }>, ", - "PartialC", - "<{ instanceId: ", - "UnionC", - "<[", - "LiteralC", - "<\"*\">, ", - "StringC", - "]>; }>]>" - ], - "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.rollingTimeWindowSchema", - "type": "Object", - "tags": [], - "label": "rollingTimeWindowSchema", - "description": [], - "signature": [ - "TypeC", - "<{ duration: ", - "Type", - "<", - { - "pluginId": "@kbn/slo-schema", - "scope": "common", - "docId": "kibKbnSloSchemaPluginApi", - "section": "def-common.Duration", - "text": "Duration" - }, - ", string, unknown>; type: ", - "LiteralC", - "<\"rolling\">; }>" - ], - "path": "x-pack/packages/kbn-slo-schema/src/schema/time_window.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.rollingTimeWindowTypeSchema", - "type": "Object", - "tags": [], - "label": "rollingTimeWindowTypeSchema", - "description": [], - "signature": [ - "LiteralC", - "<\"rolling\">" - ], - "path": "x-pack/packages/kbn-slo-schema/src/schema/time_window.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/slo-schema", - "id": "def-common.settingsSchema", - "type": "Object", - "tags": [], - "label": "settingsSchema", - "description": [], - "signature": [ + "<\"rolling\">" + ], + "path": "x-pack/packages/kbn-slo-schema/src/schema/time_window.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/slo-schema", + "id": "def-common.settingsSchema", + "type": "Object", + "tags": [], + "label": "settingsSchema", + "description": [], + "signature": [ "TypeC", "<{ syncDelay: ", "Type", @@ -6052,9 +5441,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", @@ -6510,9 +5897,7 @@ "LiteralC", "<\"*\">, ", "StringC", - "]>; version: ", - "NumberC", - "; }>" + "]>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/slo.ts", "deprecated": false, @@ -6964,9 +6349,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", @@ -7450,9 +6833,7 @@ "LiteralC", "<\"*\">, ", "StringC", - "]>; version: ", - "NumberC", - "; }>, ", + "]>; }>, ", "TypeC", "<{ summary: ", "TypeC", @@ -8850,9 +8231,7 @@ "Type", "; updatedAt: ", "Type", - "; version: ", - "NumberC", - "; }>, ", + "; }>, ", "PartialC", "<{ instanceId: ", "UnionC", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 7c42b258ebde..1dfa2a23dc98 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 144 | 0 | 144 | 0 | +| 131 | 0 | 128 | 0 | ## Common @@ -34,9 +34,6 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ ### Classes -### Interfaces - - ### Enums diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 7fee4e17d1c9..96739960e93f 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 23e06f334a20..ebc335c3d0ed 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index cd6b795dc72c..15f88dd1350d 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index c6d366d7393e..68f14d2e0e76 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_subscription_tracking.devdocs.json b/api_docs/kbn_subscription_tracking.devdocs.json deleted file mode 100644 index ea9cdb7f0716..000000000000 --- a/api_docs/kbn_subscription_tracking.devdocs.json +++ /dev/null @@ -1,519 +0,0 @@ -{ - "id": "@kbn/subscription-tracking", - "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.registerEvents", - "type": "Function", - "tags": [], - "label": "registerEvents", - "description": [ - "\nRegisters the subscription-specific event types" - ], - "signature": [ - "(analyticsClient: Pick<", - { - "pluginId": "@kbn/analytics-client", - "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", - "section": "def-common.IAnalyticsClient", - "text": "IAnalyticsClient" - }, - ", \"registerEventType\">) => void" - ], - "path": "packages/kbn-subscription-tracking/src/services.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.registerEvents.$1", - "type": "Object", - "tags": [], - "label": "analyticsClient", - "description": [], - "signature": [ - "Pick<", - { - "pluginId": "@kbn/analytics-client", - "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", - "section": "def-common.IAnalyticsClient", - "text": "IAnalyticsClient" - }, - ", \"registerEventType\">" - ], - "path": "packages/kbn-subscription-tracking/src/services.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButton", - "type": "Function", - "tags": [], - "label": "SubscriptionButton", - "description": [ - "\nWrapper around `EuiButton` that provides subscription events" - ], - "signature": [ - "({\n subscriptionContext,\n children,\n ...restProps\n}: ", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionButtonProps", - "text": "SubscriptionButtonProps" - }, - ") => JSX.Element" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButton.$1", - "type": "CompoundType", - "tags": [], - "label": "{\n subscriptionContext,\n children,\n ...restProps\n}", - "description": [], - "signature": [ - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionButtonProps", - "text": "SubscriptionButtonProps" - } - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButtonEmpty", - "type": "Function", - "tags": [], - "label": "SubscriptionButtonEmpty", - "description": [ - "\nWrapper around `EuiButtonEmpty` that provides subscription events" - ], - "signature": [ - "({\n subscriptionContext,\n children,\n ...restProps\n}: ", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionButtonEmptyProps", - "text": "SubscriptionButtonEmptyProps" - }, - ") => JSX.Element" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButtonEmpty.$1", - "type": "CompoundType", - "tags": [], - "label": "{\n subscriptionContext,\n children,\n ...restProps\n}", - "description": [], - "signature": [ - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionButtonEmptyProps", - "text": "SubscriptionButtonEmptyProps" - } - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionLink", - "type": "Function", - "tags": [], - "label": "SubscriptionLink", - "description": [ - "\nWrapper around `EuiLink` that provides subscription events" - ], - "signature": [ - "({\n subscriptionContext,\n children,\n ...restProps\n}: ", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionLinkProps", - "text": "SubscriptionLinkProps" - }, - ") => JSX.Element" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionLink.$1", - "type": "CompoundType", - "tags": [], - "label": "{\n subscriptionContext,\n children,\n ...restProps\n}", - "description": [], - "signature": [ - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.SubscriptionLinkProps", - "text": "SubscriptionLinkProps" - } - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionTrackingProvider", - "type": "Function", - "tags": [], - "label": "SubscriptionTrackingProvider", - "description": [ - "\nExternal services provider" - ], - "signature": [ - "({ children, ...services }: React.PropsWithChildren<", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.Services", - "text": "Services" - }, - ">) => JSX.Element" - ], - "path": "packages/kbn-subscription-tracking/src/services.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionTrackingProvider.$1", - "type": "CompoundType", - "tags": [], - "label": "{ children, ...services }", - "description": [], - "signature": [ - "React.PropsWithChildren<", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.Services", - "text": "Services" - }, - ">" - ], - "path": "packages/kbn-subscription-tracking/src/services.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - } - ], - "interfaces": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services", - "type": "Interface", - "tags": [], - "label": "Services", - "description": [], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services.navigateToApp", - "type": "Function", - "tags": [], - "label": "navigateToApp", - "description": [], - "signature": [ - "(app: string, options: { path: string; }) => void" - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services.navigateToApp.$1", - "type": "string", - "tags": [], - "label": "app", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services.navigateToApp.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services.navigateToApp.$2.path", - "type": "string", - "tags": [], - "label": "path", - "description": [], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.Services.analyticsClient", - "type": "Object", - "tags": [], - "label": "analyticsClient", - "description": [], - "signature": [ - "{ reportEvent: (eventType: string, eventData: EventTypeData) => void; }" - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionContextData", - "type": "Interface", - "tags": [], - "label": "SubscriptionContextData", - "description": [ - "\nA piece of metadata which consists of an identifier of the advertised feature and\nthe `source` (e.g. location) of the subscription element." - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionContextData.source", - "type": "CompoundType", - "tags": [], - "label": "source", - "description": [ - "\nA human-readable identifier describing the location of the beginning of the\nsubscription flow.\nLocation identifiers are prefixed with a solution identifier, e.g. `security__`\n" - ], - "signature": [ - "`observability__${string}` | `security__${string}`" - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionContextData.feature", - "type": "string", - "tags": [], - "label": "feature", - "description": [ - "\nA human-readable identifier describing the feature that is being promoted.\n" - ], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - } - ], - "enums": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.EVENT_NAMES", - "type": "Enum", - "tags": [], - "label": "EVENT_NAMES", - "description": [], - "path": "packages/kbn-subscription-tracking/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], - "misc": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButtonEmptyProps", - "type": "Type", - "tags": [], - "label": "SubscriptionButtonEmptyProps", - "description": [], - "signature": [ - "((", - "DisambiguateSet", - " & ", - "CommonEuiButtonEmptyProps", - " & { onClick?: React.MouseEventHandler | undefined; } & React.ButtonHTMLAttributes) | (", - "DisambiguateSet", - "<", - "EuiButtonEmptyPropsForButton", - ", EuiButtonEmptyPropsForAnchor> & ", - "CommonEuiButtonEmptyProps", - " & { href?: string | undefined; onClick?: React.MouseEventHandler | undefined; } & React.AnchorHTMLAttributes)) & CommonProps" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionButtonProps", - "type": "Type", - "tags": [], - "label": "SubscriptionButtonProps", - "description": [], - "signature": [ - "EuiButtonProps", - " & CommonProps" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionLinkProps", - "type": "Type", - "tags": [], - "label": "SubscriptionLinkProps", - "description": [], - "signature": [ - "((", - "DisambiguateSet", - "<", - "EuiLinkButtonProps", - ", ", - "EuiLinkAnchorProps", - "> & ", - "EuiLinkAnchorProps", - ") | (", - "DisambiguateSet", - "<", - "EuiLinkAnchorProps", - ", ", - "EuiLinkButtonProps", - "> & ", - "EuiLinkButtonProps", - ")) & CommonProps" - ], - "path": "packages/kbn-subscription-tracking/src/subscription_elements.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], - "objects": [ - { - "parentPluginId": "@kbn/subscription-tracking", - "id": "def-common.SubscriptionTrackingContext", - "type": "Object", - "tags": [], - "label": "SubscriptionTrackingContext", - "description": [], - "signature": [ - "React.Context<", - { - "pluginId": "@kbn/subscription-tracking", - "scope": "common", - "docId": "kibKbnSubscriptionTrackingPluginApi", - "section": "def-common.Services", - "text": "Services" - }, - " | null>" - ], - "path": "packages/kbn-subscription-tracking/src/services.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ] - } -} \ No newline at end of file diff --git a/api_docs/kbn_subscription_tracking.mdx b/api_docs/kbn_subscription_tracking.mdx deleted file mode 100644 index ab44c4c5278c..000000000000 --- a/api_docs/kbn_subscription_tracking.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -#### -#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. -#### Reach out in #docs-engineering for more info. -#### -id: kibKbnSubscriptionTrackingPluginApi -slug: /kibana-dev-docs/api/kbn-subscription-tracking -title: "@kbn/subscription-tracking" -image: https://source.unsplash.com/400x175/?github -description: API docs for the @kbn/subscription-tracking plugin -date: 2023-11-16 -tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/subscription-tracking'] ---- -import kbnSubscriptionTrackingObj from './kbn_subscription_tracking.devdocs.json'; - - - -Contact [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) for questions regarding this plugin. - -**Code health stats** - -| Public API count | Any count | Items lacking comments | Missing exports | -|-------------------|-----------|------------------------|-----------------| -| 24 | 0 | 16 | 0 | - -## Common - -### Objects - - -### Functions - - -### Interfaces - - -### Enums - - -### Consts, variables and types - - diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 0945a0e2d111..8e8b696ac749 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index 67c1c7a4a48c..68147342a7a5 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -3136,7 +3136,7 @@ "signature": [ "Pick<", "ServerlessOptions", - ", \"host\" | \"tag\" | \"image\" | \"resources\"> | undefined" + ", \"host\" | \"tag\" | \"image\" | \"resources\" | \"kibanaUrl\"> | undefined" ], "path": "packages/kbn-test/src/es/test_es_cluster.ts", "deprecated": false, diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 69bba2fc1f84..bf6dfa6ff284 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 2901e719fe49..e67eca3beeb7 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 1764322c812e..ed7cd68c8555 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.devdocs.json b/api_docs/kbn_text_based_editor.devdocs.json index 252a6537ae63..69205611cafd 100644 --- a/api_docs/kbn_text_based_editor.devdocs.json +++ b/api_docs/kbn_text_based_editor.devdocs.json @@ -192,7 +192,9 @@ "type": "CompoundType", "tags": [], "label": "query", - "description": [], + "description": [ + "The aggregate type query" + ], "signature": [ "{ sql: string; } | { esql: string; }" ], @@ -206,7 +208,9 @@ "type": "Function", "tags": [], "label": "onTextLangQueryChange", - "description": [], + "description": [ + "Callback running everytime the query changes" + ], "signature": [ "(query: ", { @@ -252,14 +256,47 @@ "type": "Function", "tags": [], "label": "onTextLangQuerySubmit", - "description": [], + "description": [ + "Callback running when the user submits the query" + ], "signature": [ - "() => void" + "(query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined) => void" ], "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "@kbn/text-based-editor", + "id": "def-public.TextBasedLanguagesEditorProps.onTextLangQuerySubmit.$1", + "type": "CompoundType", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], "returnComment": [] }, { @@ -268,7 +305,9 @@ "type": "Function", "tags": [], "label": "expandCodeEditor", - "description": [], + "description": [ + "Can be used to expand/minimize the editor" + ], "signature": [ "(status: boolean) => void" ], @@ -300,7 +339,9 @@ "type": "boolean", "tags": [], "label": "isCodeEditorExpanded", - "description": [], + "description": [ + "If it is true, the editor initializes with height EDITOR_INITIAL_HEIGHT_EXPANDED" + ], "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false @@ -311,7 +352,9 @@ "type": "CompoundType", "tags": [], "label": "detectTimestamp", - "description": [], + "description": [ + "If it is true, the editor displays the message @timestamp found\nThe text based queries are relying on adhoc dataviews which\ncan have an @timestamp timefield or nothing" + ], "signature": [ "boolean | undefined" ], @@ -325,7 +368,9 @@ "type": "Array", "tags": [], "label": "errors", - "description": [], + "description": [ + "Array of errors" + ], "signature": [ "Error[] | undefined" ], @@ -339,7 +384,9 @@ "type": "string", "tags": [], "label": "warning", - "description": [], + "description": [ + "Warning string as it comes from ES" + ], "signature": [ "string | undefined" ], @@ -353,7 +400,9 @@ "type": "CompoundType", "tags": [], "label": "isDisabled", - "description": [], + "description": [ + "Disables the editor" + ], "signature": [ "boolean | undefined" ], @@ -367,7 +416,9 @@ "type": "CompoundType", "tags": [], "label": "isDarkMode", - "description": [], + "description": [ + "Indicator if the editor is on dark mode" + ], "signature": [ "boolean | undefined" ], @@ -395,7 +446,9 @@ "type": "CompoundType", "tags": [], "label": "hideMinimizeButton", - "description": [], + "description": [ + "If true it hides the minimize button and the user can't return to the minimized version\nUseful when the application doesn't want to give this capability" + ], "signature": [ "boolean | undefined" ], @@ -409,7 +462,41 @@ "type": "CompoundType", "tags": [], "label": "hideRunQueryText", - "description": [], + "description": [ + "Hide the Run query information which appears on the footer" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/text-based-editor", + "id": "def-public.TextBasedLanguagesEditorProps.editorIsInline", + "type": "CompoundType", + "tags": [], + "label": "editorIsInline", + "description": [ + "This is used for applications (such as the inline editing flyout in dashboards)\nwhich want to add the editor without being part of the Unified search component\nIt renders a submit query button inside the editor" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/text-based-editor", + "id": "def-public.TextBasedLanguagesEditorProps.disableSubmitAction", + "type": "CompoundType", + "tags": [], + "label": "disableSubmitAction", + "description": [ + "Disables the submit query action" + ], "signature": [ "boolean | undefined" ], diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index e53078298866..a63795c1f1b3 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 22 | 0 | 21 | 0 | +| 25 | 0 | 10 | 0 | ## Client diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 8658e8c3dd4a..e5c86dfdbf34 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 9ced7a66855b..3a58eb72d0a4 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 77bdb5f91fd4..1e9f0f6a0a34 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.devdocs.json b/api_docs/kbn_ui_actions_browser.devdocs.json index 7a589d952a59..aabb32029e0d 100644 --- a/api_docs/kbn_ui_actions_browser.devdocs.json +++ b/api_docs/kbn_ui_actions_browser.devdocs.json @@ -438,21 +438,6 @@ ], "enums": [], "misc": [ - { - "parentPluginId": "@kbn/ui-actions-browser", - "id": "def-common.CATEGORIZE_FIELD_TRIGGER", - "type": "string", - "tags": [], - "label": "CATEGORIZE_FIELD_TRIGGER", - "description": [], - "signature": [ - "\"CATEGORIZE_FIELD_TRIGGER\"" - ], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/ui-actions-browser", "id": "def-common.PresentableGrouping", @@ -522,53 +507,6 @@ } ], "objects": [ - { - "parentPluginId": "@kbn/ui-actions-browser", - "id": "def-common.categorizeFieldTrigger", - "type": "Object", - "tags": [], - "label": "categorizeFieldTrigger", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/ui-actions-browser", - "id": "def-common.categorizeFieldTrigger.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/ui-actions-browser", - "id": "def-common.categorizeFieldTrigger.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/ui-actions-browser", - "id": "def-common.categorizeFieldTrigger.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/ui-actions-browser", "id": "def-common.defaultTrigger", diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 1274bf25fa9c..bc2e6612e1e1 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 49 | 0 | 35 | 0 | +| 44 | 0 | 30 | 0 | ## Common diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index e9f159428e46..30a944415ad5 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 04a49d734708..f349de02b8a8 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 6becec7972d2..7dd298c9e4ed 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 8cf7199ed233..ad20b1bf88db 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index 20244ca1fb58..35da28a598da 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -4171,15 +4171,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -4195,17 +4197,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 81aa7a60b9cf..3ec92235d5a8 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 6c364636d653..e15ae9c48121 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_url_state.devdocs.json b/api_docs/kbn_url_state.devdocs.json index e7659b142aa8..aebb4ed9e001 100644 --- a/api_docs/kbn_url_state.devdocs.json +++ b/api_docs/kbn_url_state.devdocs.json @@ -21,67 +21,50 @@ "functions": [ { "parentPluginId": "@kbn/url-state", - "id": "def-common.useSyncToUrl", + "id": "def-common.useUrlState", "type": "Function", "tags": [], - "label": "useSyncToUrl", + "label": "useUrlState", "description": [ - "\nSync any object with browser query string using @knb/rison" + "\nThis hook stores state in the URL, but with a namespace to avoid collisions with other values in the URL.\nIt also batches updates to the URL to avoid excessive history entries.\nWith it, you can store state in the URL and have it persist across page refreshes.\nThe state is stored in the URL as a Rison encoded object.\n\nExample: when called like this `const [value, setValue] = useUrlState('myNamespace', 'myKey');`\nthe state will be stored in the URL like this: `?myNamespace=(myKey:!n)`\n\nState is not cleared from the URL when the hook is unmounted and this is by design.\nIf you want it to be cleared, you can do it manually by calling `setValue(undefined)`.\n" ], "signature": [ - "(key: string, restore: (data: TValueToSerialize) => void, cleanupOnHistoryNavigation?: boolean) => (valueToSerialize?: TValueToSerialize | undefined) => void" + "(urlNamespace: string, key: string) => readonly [T | undefined, (updatedValue: T | undefined) => void]" ], - "path": "packages/kbn-url-state/use_sync_to_url.ts", + "path": "packages/kbn-url-state/index.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/url-state", - "id": "def-common.useSyncToUrl.$1", + "id": "def-common.useUrlState.$1", "type": "string", "tags": [], - "label": "key", + "label": "urlNamespace", "description": [ - "query string param to use" + "actual top level query param key" ], "signature": [ "string" ], - "path": "packages/kbn-url-state/use_sync_to_url.ts", + "path": "packages/kbn-url-state/index.ts", "deprecated": false, "trackAdoption": false, "isRequired": true }, { "parentPluginId": "@kbn/url-state", - "id": "def-common.useSyncToUrl.$2", - "type": "Function", - "tags": [], - "label": "restore", - "description": [ - "use this to handle restored state" - ], - "signature": [ - "(data: TValueToSerialize) => void" - ], - "path": "packages/kbn-url-state/use_sync_to_url.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/url-state", - "id": "def-common.useSyncToUrl.$3", - "type": "boolean", + "id": "def-common.useUrlState.$2", + "type": "string", "tags": [], - "label": "cleanupOnHistoryNavigation", + "label": "key", "description": [ - "use history events to cleanup state on back / forward naviation. true by default" + "sub key of the query param" ], "signature": [ - "boolean" + "string" ], - "path": "packages/kbn-url-state/use_sync_to_url.ts", + "path": "packages/kbn-url-state/index.ts", "deprecated": false, "trackAdoption": false, "isRequired": true diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 840b0a497719..e1004fcc32b7 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 4 | 0 | 0 | 0 | +| 3 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index d786478df658..332df8eff8b6 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index f7a5f71a4cc1..9b02f9a7d772 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index e7e71b57227d..6c5e8da76e66 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index f9667564988d..91abc5f3c9bb 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.devdocs.json b/api_docs/kbn_utils.devdocs.json index c2f4eefd1be6..88821550bc55 100644 --- a/api_docs/kbn_utils.devdocs.json +++ b/api_docs/kbn_utils.devdocs.json @@ -19,6 +19,23 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "@kbn/utils", + "id": "def-common.buildDataPaths", + "type": "Function", + "tags": [], + "label": "buildDataPaths", + "description": [], + "signature": [ + "() => string[]" + ], + "path": "packages/kbn-utils/src/path/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/utils", "id": "def-common.concatStreamProviders", diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index bb87f0b1f130..b3aa7e6e1885 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 24 | 0 | 14 | 0 | +| 25 | 0 | 15 | 0 | ## Common diff --git a/api_docs/kbn_visualization_ui_components.devdocs.json b/api_docs/kbn_visualization_ui_components.devdocs.json index bd1f417ecd32..7390e6b1b8d4 100644 --- a/api_docs/kbn_visualization_ui_components.devdocs.json +++ b/api_docs/kbn_visualization_ui_components.devdocs.json @@ -716,7 +716,7 @@ "label": "FieldPicker", "description": [], "signature": [ - "({\n selectedOptions,\n options,\n onChoose,\n onDelete,\n fieldIsInvalid,\n ['data-test-subj']: dataTestSub,\n ...rest\n}: ", + "(props: ", "FieldPickerProps", ") => JSX.Element" ], @@ -729,7 +729,7 @@ "id": "def-public.FieldPicker.$1", "type": "Object", "tags": [], - "label": "{\n selectedOptions,\n options,\n onChoose,\n onDelete,\n fieldIsInvalid,\n ['data-test-subj']: dataTestSub,\n ...rest\n}", + "label": "props", "description": [], "signature": [ "FieldPickerProps", diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 542a0bbbca63..e4a1892917c2 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index e762b217c836..5cfccffe78b8 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 7b7f033b237e..9affbf0fa3de 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index a37c31eea382..536e58c7790c 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 5e4d81d7129a..9b544eeb88eb 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 4cc2a07f5bad..06032a3c4184 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -1021,111 +1021,111 @@ }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" + "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" + "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" + "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" + "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" + "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" + "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" + "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" + "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" + "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" + "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" + "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" + "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" + "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" + "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx" + "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/users/users_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/roles/roles_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/login/login_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" }, { "plugin": "security", - "path": "x-pack/plugins/security/public/account_management/account_management_app.tsx" + "path": "x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx" }, { "plugin": "security", diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 2de9cf5fc087..ec861b3ee0f4 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index ca28b725ddd7..6b2874bc27b6 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index c95eecaf212b..2ab345b3349d 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 0808aafa7726..96eb1b3d2cc4 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -360,7 +360,7 @@ "\nGets the Lens embeddable's datasource and visualization states\nupdates the embeddable input" ], "signature": [ - "(datasourceState: unknown, visualizationState: unknown) => Promise" + "(datasourceState: unknown, visualizationState: unknown, visualizationType?: string | undefined) => Promise" ], "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", "deprecated": false, @@ -395,6 +395,67 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.updateVisualization.$3", + "type": "string", + "tags": [], + "label": "visualizationType", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.updateSuggestion", + "type": "Function", + "tags": [], + "label": "updateSuggestion", + "description": [], + "signature": [ + "(attrs: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSavedObjectAttributes", + "text": "LensSavedObjectAttributes" + }, + ") => Promise" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.updateSuggestion.$1", + "type": "Object", + "tags": [], + "label": "attrs", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSavedObjectAttributes", + "text": "LensSavedObjectAttributes" + } + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -1401,7 +1462,7 @@ "label": "seriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\"" + "\"area\" | \"line\" | \"bar\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, @@ -5131,6 +5192,20 @@ "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.datasourceId", + "type": "string", + "tags": [], + "label": "datasourceId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -5222,6 +5297,20 @@ "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.notAssignedMetrics", + "type": "CompoundType", + "tags": [], + "label": "notAssignedMetrics", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -6375,7 +6464,7 @@ "label": "getRemoveOperation", "description": [], "signature": [ - "((state: T, layerId: string) => \"remove\" | \"clear\") | undefined" + "((state: T, layerId: string) => \"clear\" | \"remove\") | undefined" ], "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, @@ -8708,7 +8797,7 @@ "label": "seriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", "deprecated": false, @@ -9035,7 +9124,7 @@ "label": "preferredSeriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", "deprecated": false, @@ -10469,7 +10558,7 @@ "label": "SeriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", "deprecated": false, diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 5f943d19e19c..8fe02d6e46f2 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 625 | 0 | 526 | 60 | +| 630 | 0 | 531 | 60 | ## Client diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 0b78839bfd9c..76b41b57cc3c 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index b15198d1460f..787d4304b192 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.devdocs.json b/api_docs/licensing.devdocs.json index 2fa21b35baeb..1004dd938427 100644 --- a/api_docs/licensing.devdocs.json +++ b/api_docs/licensing.devdocs.json @@ -822,6 +822,10 @@ "plugin": "ml", "path": "x-pack/plugins/ml/public/plugin.ts" }, + { + "plugin": "observability", + "path": "x-pack/plugins/observability/public/plugin.ts" + }, { "plugin": "profiling", "path": "x-pack/plugins/profiling/public/components/contexts/license/license_context.tsx" diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 404178eee6f7..e014be166dd1 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.devdocs.json b/api_docs/links.devdocs.json index d688e23b9f15..24744659d473 100644 --- a/api_docs/links.devdocs.json +++ b/api_docs/links.devdocs.json @@ -80,98 +80,14 @@ }, { "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.select", - "type": "Function", - "tags": [], - "label": "select", - "description": [ - "\nTODO: Keep track of the necessary state without the redux embeddable tools; it's kind of overkill here.\n Related issue: https://github.com/elastic/kibana/issues/167577" - ], - "signature": [ - "(selector: (state: ", - "LinksReduxState", - ") => Selected, equalityFn?: ((previous: Selected, next: Selected) => boolean) | undefined) => Selected" - ], - "path": "src/plugins/links/public/embeddable/links_embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.select.$1", - "type": "Function", - "tags": [], - "label": "selector", - "description": [], - "signature": [ - "(state: ReduxStateType) => Selected" - ], - "path": "src/plugins/presentation_util/public/redux_tools/types.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.select.$1.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "ReduxStateType" - ], - "path": "src/plugins/presentation_util/public/redux_tools/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.select.$2", - "type": "Function", - "tags": [], - "label": "equalityFn", - "description": [], - "signature": [ - "((previous: Selected, next: Selected) => boolean) | undefined" - ], - "path": "src/plugins/presentation_util/public/redux_tools/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.getState", - "type": "Function", - "tags": [], - "label": "getState", - "description": [], - "signature": [ - "() => ", - "LinksReduxState" - ], - "path": "src/plugins/links/public/embeddable/links_embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [] - }, - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.dispatch", + "id": "def-public.LinksEmbeddable.attributes", "type": "Object", "tags": [], - "label": "dispatch", + "label": "attributes", "description": [], "signature": [ - "{ setLoading: (payload: boolean) => void; setAttributes: (payload: ", "LinksAttributes", - ") => void; }" + " | undefined" ], "path": "src/plugins/links/public/embeddable/links_embeddable.tsx", "deprecated": false, @@ -179,37 +95,20 @@ }, { "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.onStateChange", - "type": "Function", + "id": "def-public.LinksEmbeddable.attributes$", + "type": "Object", "tags": [], - "label": "onStateChange", + "label": "attributes$", "description": [], "signature": [ - "(listener: () => void) => ", - "Unsubscribe" + "Subject", + "<", + "LinksAttributes", + ">" ], "path": "src/plugins/links/public/embeddable/links_embeddable.tsx", "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.onStateChange.$1", - "type": "Function", - "tags": [], - "label": "listener", - "description": [], - "signature": [ - "() => void" - ], - "path": "node_modules/redux/index.d.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [] - } - ] + "trackAdoption": false }, { "parentPluginId": "links", @@ -230,27 +129,6 @@ "id": "def-public.LinksEmbeddable.Unnamed.$1", "type": "Object", "tags": [], - "label": "reduxToolsPackage", - "description": [], - "signature": [ - { - "pluginId": "presentationUtil", - "scope": "public", - "docId": "kibPresentationUtilPluginApi", - "section": "def-public.ReduxToolsPackage", - "text": "ReduxToolsPackage" - } - ], - "path": "src/plugins/links/public/embeddable/links_embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.Unnamed.$2", - "type": "Object", - "tags": [], "label": "config", "description": [], "signature": [ @@ -263,7 +141,7 @@ }, { "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.Unnamed.$3", + "id": "def-public.LinksEmbeddable.Unnamed.$2", "type": "CompoundType", "tags": [], "label": "initialInput", @@ -278,7 +156,7 @@ }, { "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.Unnamed.$4", + "id": "def-public.LinksEmbeddable.Unnamed.$3", "type": "Object", "tags": [], "label": "attributeService", @@ -320,7 +198,7 @@ }, { "parentPluginId": "links", - "id": "def-public.LinksEmbeddable.Unnamed.$5", + "id": "def-public.LinksEmbeddable.Unnamed.$4", "type": "Object", "tags": [], "label": "parent", diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 6fef3a10d5d6..080b6feaed86 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 64 | 0 | 62 | 7 | +| 57 | 0 | 57 | 6 | ## Client diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 44decb607a98..078f57b14b59 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx index 105ccbfe1bf5..ee9d862794f5 100644 --- a/api_docs/log_explorer.mdx +++ b/api_docs/log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logExplorer title: "logExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logExplorer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] --- import logExplorerObj from './log_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.devdocs.json b/api_docs/logs_shared.devdocs.json index 5e35354e0187..61da0f6f1007 100644 --- a/api_docs/logs_shared.devdocs.json +++ b/api_docs/logs_shared.devdocs.json @@ -2878,15 +2878,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -2902,17 +2904,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index f84708561f3d..221750797a3b 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 4715b32b3c07..a7bbb94bfc81 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.devdocs.json b/api_docs/maps.devdocs.json index 56ef9cf8b744..96444b697240 100644 --- a/api_docs/maps.devdocs.json +++ b/api_docs/maps.devdocs.json @@ -1684,12 +1684,12 @@ { "parentPluginId": "maps", "id": "def-public.GeoJsonWithMeta.meta", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "meta", "description": [], "signature": [ - "ESSearchSourceResponseMeta", + "DataRequestMeta", " | undefined" ], "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 62a9a54b192c..93b86638ca11 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 260 | 0 | 259 | 29 | +| 260 | 0 | 259 | 28 | ## Client diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 6abe3da16aad..330f0e35bdad 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.devdocs.json b/api_docs/metrics_data_access.devdocs.json index fa981b59de28..6c3c17671881 100644 --- a/api_docs/metrics_data_access.devdocs.json +++ b/api_docs/metrics_data_access.devdocs.json @@ -550,8 +550,7 @@ "label": "findInventoryModel", "description": [], "signature": [ - "(type: \"host\" | \"container\" | \"pod\" | \"awsEC2\" | \"awsS3\" | \"awsSQS\" | \"awsRDS\") => ", - "InventoryModel" + "(type: T) => InventoryModels" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/index.ts", "deprecated": false, @@ -560,12 +559,12 @@ { "parentPluginId": "metricsDataAccess", "id": "def-common.findInventoryModel.$1", - "type": "CompoundType", + "type": "Uncategorized", "tags": [], "label": "type", "description": [], "signature": [ - "\"host\" | \"container\" | \"pod\" | \"awsEC2\" | \"awsS3\" | \"awsSQS\" | \"awsRDS\"" + "T" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/index.ts", "deprecated": false, @@ -671,7 +670,7 @@ "label": "awsEC2SnapshotMetricTypes", "description": [], "signature": [ - "(\"rx\" | \"cpu\" | \"tx\" | \"diskIOReadBytes\" | \"diskIOWriteBytes\")[]" + "(\"rx\" | \"tx\" | \"cpu\" | \"diskIOReadBytes\" | \"diskIOWriteBytes\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/aws_ec2/metrics/index.ts", "deprecated": false, @@ -686,7 +685,7 @@ "label": "awsRDSSnapshotMetricTypes", "description": [], "signature": [ - "(\"cpu\" | \"rdsConnections\" | \"rdsQueriesExecuted\" | \"rdsActiveTransactions\" | \"rdsLatency\")[]" + "(\"cpu\" | \"rdsLatency\" | \"rdsConnections\" | \"rdsQueriesExecuted\" | \"rdsActiveTransactions\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/aws_rds/metrics/index.ts", "deprecated": false, @@ -701,7 +700,7 @@ "label": "awsS3SnapshotMetricTypes", "description": [], "signature": [ - "(\"s3TotalRequests\" | \"s3NumberOfObjects\" | \"s3BucketSize\" | \"s3DownloadBytes\" | \"s3UploadBytes\")[]" + "(\"s3BucketSize\" | \"s3NumberOfObjects\" | \"s3TotalRequests\" | \"s3UploadBytes\" | \"s3DownloadBytes\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/aws_s3/metrics/index.ts", "deprecated": false, @@ -716,7 +715,7 @@ "label": "awsSQSSnapshotMetricTypes", "description": [], "signature": [ - "(\"sqsMessagesVisible\" | \"sqsMessagesDelayed\" | \"sqsMessagesSent\" | \"sqsMessagesEmpty\" | \"sqsOldestMessage\")[]" + "(\"sqsMessagesVisible\" | \"sqsMessagesDelayed\" | \"sqsMessagesEmpty\" | \"sqsMessagesSent\" | \"sqsOldestMessage\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/aws_sqs/metrics/index.ts", "deprecated": false, @@ -731,7 +730,7 @@ "label": "containerSnapshotMetricTypes", "description": [], "signature": [ - "(\"memory\" | \"rx\" | \"cpu\" | \"tx\")[]" + "(\"memory\" | \"rx\" | \"tx\" | \"cpu\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/container/metrics/index.ts", "deprecated": false, @@ -746,7 +745,7 @@ "label": "hostSnapshotMetricTypes", "description": [], "signature": [ - "(\"memory\" | \"rx\" | \"cpu\" | \"diskLatency\" | \"diskSpaceUsage\" | \"load\" | \"memoryFree\" | \"memoryTotal\" | \"normalizedLoad1m\" | \"tx\" | \"logRate\")[]" + "(\"memory\" | \"rx\" | \"logRate\" | \"normalizedLoad1m\" | \"memoryFree\" | \"tx\" | \"cpu\" | \"diskLatency\" | \"diskSpaceUsage\" | \"load\" | \"memoryTotal\")[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/index.ts", "deprecated": false, @@ -806,8 +805,313 @@ "label": "inventoryModels", "description": [], "signature": [ + "(", + "InventoryModel", + "<", + "InventoryMetricsWithDashboards", + "<{ cpuUsage: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageIowait: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageIrq: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageNice: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageSoftirq: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageSteal: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageUser: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; cpuUsageSystem: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskIORead: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskIOWrite: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskReadThroughput: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskWriteThroughput: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskSpaceAvailability: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskSpaceAvailable: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; diskUsage: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; hostCount: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; logRate: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; normalizedLoad1m: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; load1m: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; load5m: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; load15m: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; memoryUsage: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; memoryFree: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; memoryUsed: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; memoryFreeExcludingCache: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; memoryCache: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; rx: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; tx: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.FormulaValueConfig", + "text": "FormulaValueConfig" + }, + "; }, { assetDetails: { get: ({ metricsDataView, logsDataView, }: { metricsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; logsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; }) => ", + "DashboardModel", + "; }; assetDetailsFlyout: { get: ({ metricsDataView, logsDataView, }: { metricsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; logsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; }) => ", + "DashboardModel", + "; }; hostsView: { get: ({ metricsDataView }: { metricsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; }) => ", + "DashboardModel", + "; }; kpi: { get: ({ metricsDataView, options, }: { metricsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; options?: ", + { + "pluginId": "@kbn/lens-embeddable-utils", + "scope": "common", + "docId": "kibKbnLensEmbeddableUtilsPluginApi", + "section": "def-common.MetricLayerOptions", + "text": "MetricLayerOptions" + }, + " | undefined; }) => ", + "DashboardModel", + "; }; assetDetailsKubernetesNode: { get: ({ metricsDataView }: { metricsDataView?: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + " | undefined; }) => ", + "DashboardModel", + "; }; }>> | ", "InventoryModel", - "[]" + "<", + "InventoryMetrics", + ">)[]" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/index.ts", "deprecated": false, @@ -822,7 +1126,7 @@ "label": "InventoryVisType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\"" + "\"area\" | \"line\" | \"bar\"" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/types.ts", "deprecated": false, @@ -854,9 +1158,9 @@ "label": "podSnapshotMetricTypes", "description": [], "signature": [ - "(\"memory\" | \"rx\" | \"cpu\" | \"tx\")[]" + "(\"memory\" | \"rx\" | \"tx\" | \"cpu\")[]" ], - "path": "x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/index.ts", + "path": "x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -869,7 +1173,7 @@ "label": "SnapshotMetricType", "description": [], "signature": [ - "\"count\" | \"custom\" | \"memory\" | \"rx\" | \"cpu\" | \"diskLatency\" | \"diskSpaceUsage\" | \"load\" | \"memoryFree\" | \"memoryTotal\" | \"normalizedLoad1m\" | \"tx\" | \"logRate\" | \"diskIOReadBytes\" | \"diskIOWriteBytes\" | \"s3TotalRequests\" | \"s3NumberOfObjects\" | \"s3BucketSize\" | \"s3DownloadBytes\" | \"s3UploadBytes\" | \"rdsConnections\" | \"rdsQueriesExecuted\" | \"rdsActiveTransactions\" | \"rdsLatency\" | \"sqsMessagesVisible\" | \"sqsMessagesDelayed\" | \"sqsMessagesSent\" | \"sqsMessagesEmpty\" | \"sqsOldestMessage\"" + "\"count\" | \"custom\" | \"memory\" | \"rx\" | \"logRate\" | \"normalizedLoad1m\" | \"memoryFree\" | \"tx\" | \"cpu\" | \"s3BucketSize\" | \"s3NumberOfObjects\" | \"s3TotalRequests\" | \"s3UploadBytes\" | \"s3DownloadBytes\" | \"diskLatency\" | \"diskSpaceUsage\" | \"load\" | \"memoryTotal\" | \"diskIOReadBytes\" | \"diskIOWriteBytes\" | \"rdsLatency\" | \"rdsConnections\" | \"rdsQueriesExecuted\" | \"rdsActiveTransactions\" | \"sqsMessagesVisible\" | \"sqsMessagesDelayed\" | \"sqsMessagesEmpty\" | \"sqsMessagesSent\" | \"sqsOldestMessage\"" ], "path": "x-pack/plugins/metrics_data_access/common/inventory_models/types.ts", "deprecated": false, diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index 95b742207197..1f4b428e4860 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 104 | 8 | 104 | 4 | +| 104 | 8 | 104 | 7 | ## Client diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index f3254ea9f455..46c0e7d8ec21 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -1045,7 +1045,7 @@ "label": "ML_PAGES", "description": [], "signature": [ - "{ readonly ANOMALY_DETECTION_JOBS_MANAGE: \"jobs\"; readonly ANOMALY_EXPLORER: \"explorer\"; readonly SINGLE_METRIC_VIEWER: \"timeseriesexplorer\"; readonly DATA_FRAME_ANALYTICS_JOBS_MANAGE: \"data_frame_analytics\"; readonly DATA_FRAME_ANALYTICS_SOURCE_SELECTION: \"data_frame_analytics/source_selection\"; readonly DATA_FRAME_ANALYTICS_CREATE_JOB: \"data_frame_analytics/new_job\"; readonly TRAINED_MODELS_MANAGE: \"trained_models\"; readonly DATA_DRIFT_INDEX_SELECT: \"data_drift_index_select\"; readonly DATA_DRIFT_CUSTOM: \"data_drift_custom\"; readonly DATA_DRIFT: \"data_drift\"; readonly NODES: \"nodes\"; readonly MEMORY_USAGE: \"memory_usage\"; readonly DATA_FRAME_ANALYTICS_EXPLORATION: \"data_frame_analytics/exploration\"; readonly DATA_FRAME_ANALYTICS_MAP: \"data_frame_analytics/map\"; readonly DATA_VISUALIZER: \"datavisualizer\"; readonly DATA_VISUALIZER_INDEX_SELECT: \"datavisualizer_index_select\"; readonly DATA_VISUALIZER_FILE: \"filedatavisualizer\"; readonly DATA_VISUALIZER_INDEX_VIEWER: \"jobs/new_job/datavisualizer\"; readonly ANOMALY_DETECTION_CREATE_JOB: \"jobs/new_job\"; readonly ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER: \"jobs/new_job/recognize\"; readonly ANOMALY_DETECTION_CREATE_JOB_SINGLE_METRIC: \"jobs/new_job/single_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_MULTI_METRIC: \"jobs/new_job/multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_MULTI_METRIC: \"jobs/new_job/convert_to_multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_ADVANCED: \"jobs/new_job/advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_POPULATION: \"jobs/new_job/population\"; readonly ANOMALY_DETECTION_CREATE_JOB_CATEGORIZATION: \"jobs/new_job/categorization\"; readonly ANOMALY_DETECTION_CREATE_JOB_RARE: \"jobs/new_job/rare\"; readonly ANOMALY_DETECTION_CREATE_JOB_GEO: \"jobs/new_job/geo\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_ADVANCED: \"jobs/new_job/convert_to_advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: \"jobs/new_job/step/job_type\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: \"jobs/new_job/step/index_or_search\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: \"jobs/new_job/from_lens\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_MAP: \"jobs/new_job/from_map\"; readonly ANOMALY_DETECTION_MODULES_VIEW_OR_CREATE: \"modules/check_view_or_create\"; readonly SETTINGS: \"settings\"; readonly CALENDARS_MANAGE: \"settings/calendars_list\"; readonly CALENDARS_NEW: \"settings/calendars_list/new_calendar\"; readonly CALENDARS_EDIT: \"settings/calendars_list/edit_calendar\"; readonly FILTER_LISTS_MANAGE: \"settings/filter_lists\"; readonly FILTER_LISTS_NEW: \"settings/filter_lists/new_filter_list\"; readonly FILTER_LISTS_EDIT: \"settings/filter_lists/edit_filter_list\"; readonly OVERVIEW: \"overview\"; readonly NOTIFICATIONS: \"notifications\"; readonly AIOPS: \"aiops\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES: \"aiops/explain_log_rate_spikes\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT: \"aiops/explain_log_rate_spikes_index_select\"; readonly AIOPS_LOG_RATE_ANALYSIS: \"aiops/log_rate_analysis\"; readonly AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT: \"aiops/log_rate_analysis_index_select\"; readonly AIOPS_LOG_CATEGORIZATION: \"aiops/log_categorization\"; readonly AIOPS_LOG_CATEGORIZATION_INDEX_SELECT: \"aiops/log_categorization_index_select\"; readonly AIOPS_CHANGE_POINT_DETECTION: \"aiops/change_point_detection\"; readonly AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT: \"aiops/change_point_detection_index_select\"; }" + "{ readonly ANOMALY_DETECTION_JOBS_MANAGE: \"jobs\"; readonly ANOMALY_EXPLORER: \"explorer\"; readonly SINGLE_METRIC_VIEWER: \"timeseriesexplorer\"; readonly DATA_FRAME_ANALYTICS_JOBS_MANAGE: \"data_frame_analytics\"; readonly DATA_FRAME_ANALYTICS_SOURCE_SELECTION: \"data_frame_analytics/source_selection\"; readonly DATA_FRAME_ANALYTICS_CREATE_JOB: \"data_frame_analytics/new_job\"; readonly TRAINED_MODELS_MANAGE: \"trained_models\"; readonly DATA_DRIFT_INDEX_SELECT: \"data_drift_index_select\"; readonly DATA_DRIFT_CUSTOM: \"data_drift_custom\"; readonly DATA_DRIFT: \"data_drift\"; readonly NODES: \"nodes\"; readonly MEMORY_USAGE: \"memory_usage\"; readonly DATA_FRAME_ANALYTICS_EXPLORATION: \"data_frame_analytics/exploration\"; readonly DATA_FRAME_ANALYTICS_MAP: \"data_frame_analytics/map\"; readonly DATA_VISUALIZER: \"datavisualizer\"; readonly DATA_VISUALIZER_INDEX_SELECT: \"datavisualizer_index_select\"; readonly DATA_VISUALIZER_FILE: \"filedatavisualizer\"; readonly DATA_VISUALIZER_INDEX_VIEWER: \"jobs/new_job/datavisualizer\"; readonly ANOMALY_DETECTION_CREATE_JOB: \"jobs/new_job\"; readonly ANOMALY_DETECTION_CREATE_JOB_RECOGNIZER: \"jobs/new_job/recognize\"; readonly ANOMALY_DETECTION_CREATE_JOB_SINGLE_METRIC: \"jobs/new_job/single_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_MULTI_METRIC: \"jobs/new_job/multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_MULTI_METRIC: \"jobs/new_job/convert_to_multi_metric\"; readonly ANOMALY_DETECTION_CREATE_JOB_ADVANCED: \"jobs/new_job/advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_POPULATION: \"jobs/new_job/population\"; readonly ANOMALY_DETECTION_CREATE_JOB_CATEGORIZATION: \"jobs/new_job/categorization\"; readonly ANOMALY_DETECTION_CREATE_JOB_RARE: \"jobs/new_job/rare\"; readonly ANOMALY_DETECTION_CREATE_JOB_GEO: \"jobs/new_job/geo\"; readonly ANOMALY_DETECTION_CREATE_JOB_CONVERT_TO_ADVANCED: \"jobs/new_job/convert_to_advanced\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: \"jobs/new_job/step/job_type\"; readonly ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: \"jobs/new_job/step/index_or_search\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: \"jobs/new_job/from_lens\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS: \"jobs/new_job/from_pattern_analysis\"; readonly ANOMALY_DETECTION_CREATE_JOB_FROM_MAP: \"jobs/new_job/from_map\"; readonly ANOMALY_DETECTION_MODULES_VIEW_OR_CREATE: \"modules/check_view_or_create\"; readonly SETTINGS: \"settings\"; readonly CALENDARS_MANAGE: \"settings/calendars_list\"; readonly CALENDARS_NEW: \"settings/calendars_list/new_calendar\"; readonly CALENDARS_EDIT: \"settings/calendars_list/edit_calendar\"; readonly FILTER_LISTS_MANAGE: \"settings/filter_lists\"; readonly FILTER_LISTS_NEW: \"settings/filter_lists/new_filter_list\"; readonly FILTER_LISTS_EDIT: \"settings/filter_lists/edit_filter_list\"; readonly OVERVIEW: \"overview\"; readonly NOTIFICATIONS: \"notifications\"; readonly AIOPS: \"aiops\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES: \"aiops/explain_log_rate_spikes\"; readonly AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT: \"aiops/explain_log_rate_spikes_index_select\"; readonly AIOPS_LOG_RATE_ANALYSIS: \"aiops/log_rate_analysis\"; readonly AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT: \"aiops/log_rate_analysis_index_select\"; readonly AIOPS_LOG_CATEGORIZATION: \"aiops/log_categorization\"; readonly AIOPS_LOG_CATEGORIZATION_INDEX_SELECT: \"aiops/log_categorization_index_select\"; readonly AIOPS_CHANGE_POINT_DETECTION: \"aiops/change_point_detection\"; readonly AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT: \"aiops/change_point_detection_index_select\"; }" ], "path": "x-pack/plugins/ml/common/constants/locator.ts", "deprecated": false, @@ -1907,8 +1907,32 @@ "pluginId": "@kbn/ml-trained-models-utils", "scope": "common", "docId": "kibKbnMlTrainedModelsUtilsPluginApi", - "section": "def-common.GetElserOptions", - "text": "GetElserOptions" + "section": "def-common.GetModelDownloadConfigOptions", + "text": "GetModelDownloadConfigOptions" + }, + " | undefined): Promise<", + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.ModelDefinitionResponse", + "text": "ModelDefinitionResponse" + }, + ">; getCuratedModelConfig(modelName: ", + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.ElasticCuratedModelName", + "text": "ElasticCuratedModelName" + }, + ", options?: ", + { + "pluginId": "@kbn/ml-trained-models-utils", + "scope": "common", + "docId": "kibKbnMlTrainedModelsUtilsPluginApi", + "section": "def-common.GetModelDownloadConfigOptions", + "text": "GetModelDownloadConfigOptions" }, " | undefined): Promise<", { diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index c1ad326590a8..e4e11888af67 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.devdocs.json b/api_docs/mock_idp_plugin.devdocs.json new file mode 100644 index 000000000000..9c7b5bd1558d --- /dev/null +++ b/api_docs/mock_idp_plugin.devdocs.json @@ -0,0 +1,410 @@ +{ + "id": "mockIdpPlugin", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createMockIdpMetadata", + "type": "Function", + "tags": [], + "label": "createMockIdpMetadata", + "description": [ + "\nCreates XML metadata for our mock identity provider.\n\nThis can be saved to file and used to configure Elasticsearch SAML realm.\n" + ], + "signature": [ + "(kibanaUrl: string) => Promise" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createMockIdpMetadata.$1", + "type": "string", + "tags": [], + "label": "kibanaUrl", + "description": [ + "Fully qualified URL where Kibana is hosted (including base path)" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse", + "type": "Function", + "tags": [], + "label": "createSAMLResponse", + "description": [ + "\nCreates a SAML response that can be passed directly to the Kibana ACS endpoint to authenticate a user.\n" + ], + "signature": [ + "(options: { kibanaUrl: string; authnRequestId?: string | undefined; username: string; fullname?: string | undefined; email?: string | undefined; roles: string[]; }) => Promise" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.kibanaUrl", + "type": "string", + "tags": [], + "label": "kibanaUrl", + "description": [ + "Fully qualified URL where Kibana is hosted (including base path)" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.authnRequestId", + "type": "string", + "tags": [], + "label": "authnRequestId", + "description": [ + "ID from SAML authentication request" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.fullname", + "type": "string", + "tags": [], + "label": "fullname", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.email", + "type": "string", + "tags": [], + "label": "email", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.createSAMLResponse.$1.roles", + "type": "Array", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.ensureSAMLRoleMapping", + "type": "Function", + "tags": [], + "label": "ensureSAMLRoleMapping", + "description": [ + "\nCreates the role mapping required for developers to authenticate using SAML." + ], + "signature": [ + "(client: ", + "default", + ") => Promise" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.ensureSAMLRoleMapping.$1", + "type": "Object", + "tags": [], + "label": "client", + "description": [], + "signature": [ + "default" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.parseSAMLAuthnRequest", + "type": "Function", + "tags": [], + "label": "parseSAMLAuthnRequest", + "description": [], + "signature": [ + "(samlRequest: string) => Promise<{ AssertionConsumerServiceURL: string; Destination: string; ID: string; IssueInstant: string; }>" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.parseSAMLAuthnRequest.$1", + "type": "string", + "tags": [], + "label": "samlRequest", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ATTRIBUTE_EMAIL", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_EMAIL", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/email\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ATTRIBUTE_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_NAME", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/name\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ATTRIBUTE_PRINCIPAL", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_PRINCIPAL", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/principal\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ATTRIBUTE_ROLES", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_ROLES", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/roles\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ENTITY_ID", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ENTITY_ID", + "description": [], + "signature": [ + "\"urn:mock-idp\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_LOGIN_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_LOGIN_PATH", + "description": [], + "signature": [ + "\"/mock_idp/login\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_LOGOUT_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_LOGOUT_PATH", + "description": [], + "signature": [ + "\"/mock_idp/logout\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_METADATA_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_METADATA_PATH", + "description": [], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_PLUGIN_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_PLUGIN_PATH", + "description": [], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_REALM_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_REALM_NAME", + "description": [], + "signature": [ + "\"mock-idp\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "mockIdpPlugin", + "id": "def-common.MOCK_IDP_ROLE_MAPPING_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ROLE_MAPPING_NAME", + "description": [], + "signature": [ + "\"mock-idp-mapping\"" + ], + "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx new file mode 100644 index 000000000000..4f07ed3493e6 --- /dev/null +++ b/api_docs/mock_idp_plugin.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibMockIdpPluginPluginApi +slug: /kibana-dev-docs/api/mockIdpPlugin +title: "mockIdpPlugin" +image: https://source.unsplash.com/400x175/?github +description: API docs for the mockIdpPlugin plugin +date: 2023-12-04 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] +--- +import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; + + + +Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 25 | 0 | 19 | 0 | + +## Common + +### Functions + + +### Consts, variables and types + + diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 4b2a335daee9..abe0d57c2c9a 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 14d4b44e3f52..f33ff03a4d20 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 8e5fe7c5e044..e383d134318c 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 3af33a3c7fac..6965bc6e5039 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 81ef92527b9f..22a1ab949d9f 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index d46bcbbda45c..7e168a46b94f 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index f0d4f0c019ba..6cbeaf65fbaf 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -784,7 +784,7 @@ }, " | undefined; list: () => string[]; }; selectedAlertId?: string | undefined; } & ", "CommonProps", - " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | keyof React.HTMLAttributes | \"css\"> & { ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject | null | undefined; }, \"type\" | \"prefix\" | \"key\" | \"id\" | \"defaultValue\" | \"security\" | \"children\" | \"ref\" | \"onChange\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"title\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"color\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDown\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClick\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"data-test-subj\" | \"css\" | \"paddingSize\" | \"size\" | \"onClose\" | \"as\" | \"maxWidth\" | \"ownFocus\" | \"hideCloseButton\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"pushAnimation\" | \"focusTrapProps\" | \"includeFixedHeadersInFocusTrap\">, \"type\" | \"prefix\" | \"key\" | \"id\" | \"defaultValue\" | \"security\" | \"alert\" | \"children\" | \"onChange\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"title\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"color\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDown\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClick\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"data-test-subj\" | \"css\" | \"alerts\" | \"paddingSize\" | \"size\" | \"onClose\" | \"as\" | \"maxWidth\" | \"ownFocus\" | \"hideCloseButton\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"pushAnimation\" | \"focusTrapProps\" | \"includeFixedHeadersInFocusTrap\" | \"isInApp\" | \"observabilityRuleTypeRegistry\" | \"selectedAlertId\"> & { ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject | null | undefined; }> & { readonly _result: ({ alert, alerts, isInApp, observabilityRuleTypeRegistry, onClose, selectedAlertId, }: AlertsFlyoutProps) => JSX.Element | null; }" + " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | keyof React.HTMLAttributes | \"css\"> & { ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject | null | undefined; }, \"type\" | \"prefix\" | \"key\" | \"id\" | \"defaultValue\" | \"security\" | \"children\" | \"ref\" | \"onChange\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"title\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"color\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDown\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClick\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"data-test-subj\" | \"css\" | \"paddingSize\" | \"size\" | \"onClose\" | \"maxWidth\" | \"ownFocus\" | \"hideCloseButton\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"pushAnimation\" | \"focusTrapProps\" | \"includeFixedHeadersInFocusTrap\" | \"as\">, \"type\" | \"prefix\" | \"key\" | \"id\" | \"defaultValue\" | \"security\" | \"alert\" | \"children\" | \"onChange\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"className\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"hidden\" | \"lang\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"title\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"color\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onError\" | \"onErrorCapture\" | \"onKeyDown\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClick\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"data-test-subj\" | \"css\" | \"alerts\" | \"paddingSize\" | \"size\" | \"onClose\" | \"maxWidth\" | \"ownFocus\" | \"hideCloseButton\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"pushAnimation\" | \"focusTrapProps\" | \"includeFixedHeadersInFocusTrap\" | \"as\" | \"isInApp\" | \"observabilityRuleTypeRegistry\" | \"selectedAlertId\"> & { ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject | null | undefined; }> & { readonly _result: ({ alert, alerts, isInApp, observabilityRuleTypeRegistry, onClose, selectedAlertId, }: AlertsFlyoutProps) => JSX.Element | null; }" ], "path": "x-pack/plugins/observability/public/index.ts", "deprecated": false, @@ -2636,6 +2636,26 @@ "path": "x-pack/plugins/observability/public/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-public.ObservabilityPublicPluginsSetup.licensing", + "type": "Object", + "tags": [], + "label": "licensing", + "description": [], + "signature": [ + { + "pluginId": "licensing", + "scope": "public", + "docId": "kibLicensingPluginApi", + "section": "def-public.LicensingPluginSetup", + "text": "LicensingPluginSetup" + } + ], + "path": "x-pack/plugins/observability/public/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -3339,11 +3359,19 @@ "label": "format", "description": [], "signature": [ - "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", - ", denominator: number | undefined, fallbackResult?: string) => string; }; }) => { reason: string; link?: string | undefined; }" + ", denominator: number | undefined, fallbackResult?: string) => string; }; }) => { reason: string; link?: string | undefined; hasBasePath?: boolean | undefined; }" ], "path": "x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts", "deprecated": false, @@ -3358,7 +3386,15 @@ "label": "options", "description": [], "signature": [ - "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -3566,7 +3602,15 @@ "label": "fields", "description": [], "signature": [ - "OutputOf> & OutputOf> & TAdditionalMetaFields" + "OutputOf> & OutputOf> & TAdditionalMetaFields" ], "path": "x-pack/plugins/observability/public/typings/alerts.ts", "deprecated": false, @@ -3629,6 +3673,20 @@ "path": "x-pack/plugins/observability/public/typings/alerts.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-public.TopAlert.hasBasePath", + "type": "CompoundType", + "tags": [], + "label": "hasBasePath", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability/public/typings/alerts.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4366,11 +4424,19 @@ "label": "ObservabilityRuleTypeFormatter", "description": [], "signature": [ - "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", - ", denominator: number | undefined, fallbackResult?: string) => string; }; }) => { reason: string; link?: string | undefined; }" + ", denominator: number | undefined, fallbackResult?: string) => string; }; }) => { reason: string; link?: string | undefined; hasBasePath?: boolean | undefined; }" ], "path": "x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts", "deprecated": false, @@ -4385,7 +4451,15 @@ "label": "options", "description": [], "signature": [ - "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -8156,29 +8230,7 @@ "label": "ObservabilityAPIReturnType", "description": [], "signature": [ - "{ \"POST /api/observability/slos/{id}/_reset 2023-10-31\": { endpoint: \"POST /api/observability/slos/{id}/_reset 2023-10-31\"; params?: ", - "TypeC", - "<{ path: ", - "TypeC", - "<{ id: ", - "StringC", - "; }>; }> | undefined; handler: ({}: ", - { - "pluginId": "observability", - "scope": "server", - "docId": "kibObservabilityPluginApi", - "section": "def-server.ObservabilityRouteHandlerResources", - "text": "ObservabilityRouteHandlerResources" - }, - " & { params: { path: { id: string; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }>; } & ", - { - "pluginId": "observability", - "scope": "server", - "docId": "kibObservabilityPluginApi", - "section": "def-server.ObservabilityRouteCreateOptions", - "text": "ObservabilityRouteCreateOptions" - }, - "; \"GET /internal/observability/slos/{id}/_instances\": { endpoint: \"GET /internal/observability/slos/{id}/_instances\"; params?: ", + "{ \"GET /internal/observability/slos/{id}/_instances\": { endpoint: \"GET /internal/observability/slos/{id}/_instances\"; params?: ", "TypeC", "<{ path: ", "TypeC", @@ -8534,7 +8586,13 @@ "PartialC", "<{ filter: ", "StringC", - "; }>]>; }>]>; }>; }> | undefined; handler: ({}: ", + "; }>]>; }>]>; range: ", + "TypeC", + "<{ start: ", + "NumberC", + "; end: ", + "NumberC", + "; }>; }>; }> | undefined; handler: ({}: ", { "pluginId": "observability", "scope": "server", @@ -8542,7 +8600,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params: { body: { indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; }; }; }) => Promise<{ date: string; sliValue: number; }[]>; } & ", + " & { params: { body: { indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; range: { start: number; end: number; }; }; }; }) => Promise<({ date: string; sliValue: number; } & { events?: { good: number; bad: number; total: number; } | undefined; })[]>; } & ", { "pluginId": "observability", "scope": "server", @@ -9104,7 +9162,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | undefined; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }>; } & ", + " | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | undefined; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -9138,7 +9196,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params: { path: { id: string; }; } & { query?: { instanceId?: string | undefined; } | undefined; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }>; } & ", + " & { params: { path: { id: string; }; } & { query?: { instanceId?: string | undefined; } | undefined; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -9180,7 +9238,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params?: { query?: { kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }>; } & ", + " & { params?: { query?: { kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -9188,18 +9246,12 @@ "section": "def-server.ObservabilityRouteCreateOptions", "text": "ObservabilityRouteCreateOptions" }, - "; \"GET /api/observability/slos/_definitions 2023-10-31\": { endpoint: \"GET /api/observability/slos/_definitions 2023-10-31\"; params?: ", - "PartialC", + "; \"GET /internal/observability/slos/_definitions\": { endpoint: \"GET /internal/observability/slos/_definitions\"; params?: ", + "TypeC", "<{ query: ", - "PartialC", + "TypeC", "<{ search: ", "StringC", - "; includeOutdatedOnly: ", - "Type", - "; page: ", - "StringC", - "; perPage: ", - "StringC", "; }>; }> | undefined; handler: ({}: ", { "pluginId": "observability", @@ -9208,7 +9260,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params?: { query?: { search?: string | undefined; includeOutdatedOnly?: boolean | undefined; page?: string | undefined; perPage?: string | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; })[]; }>; } & ", + " & { params: { query: { search: string; }; }; }) => Promise<({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; })[]>; } & ", { "pluginId": "observability", "scope": "server", @@ -9888,29 +9940,7 @@ "label": "ObservabilityServerRouteRepository", "description": [], "signature": [ - "{ \"POST /api/observability/slos/{id}/_reset 2023-10-31\": { endpoint: \"POST /api/observability/slos/{id}/_reset 2023-10-31\"; params?: ", - "TypeC", - "<{ path: ", - "TypeC", - "<{ id: ", - "StringC", - "; }>; }> | undefined; handler: ({}: ", - { - "pluginId": "observability", - "scope": "server", - "docId": "kibObservabilityPluginApi", - "section": "def-server.ObservabilityRouteHandlerResources", - "text": "ObservabilityRouteHandlerResources" - }, - " & { params: { path: { id: string; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }>; } & ", - { - "pluginId": "observability", - "scope": "server", - "docId": "kibObservabilityPluginApi", - "section": "def-server.ObservabilityRouteCreateOptions", - "text": "ObservabilityRouteCreateOptions" - }, - "; \"GET /internal/observability/slos/{id}/_instances\": { endpoint: \"GET /internal/observability/slos/{id}/_instances\"; params?: ", + "{ \"GET /internal/observability/slos/{id}/_instances\": { endpoint: \"GET /internal/observability/slos/{id}/_instances\"; params?: ", "TypeC", "<{ path: ", "TypeC", @@ -10266,7 +10296,13 @@ "PartialC", "<{ filter: ", "StringC", - "; }>]>; }>]>; }>; }> | undefined; handler: ({}: ", + "; }>]>; }>]>; range: ", + "TypeC", + "<{ start: ", + "NumberC", + "; end: ", + "NumberC", + "; }>; }>; }> | undefined; handler: ({}: ", { "pluginId": "observability", "scope": "server", @@ -10274,7 +10310,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params: { body: { indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; }; }; }) => Promise<{ date: string; sliValue: number; }[]>; } & ", + " & { params: { body: { indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; range: { start: number; end: number; }; }; }; }) => Promise<({ date: string; sliValue: number; } & { events?: { good: number; bad: number; total: number; } | undefined; })[]>; } & ", { "pluginId": "observability", "scope": "server", @@ -10836,7 +10872,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | undefined; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; }>; } & ", + " | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | undefined; }; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -10870,7 +10906,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params: { path: { id: string; }; } & { query?: { instanceId?: string | undefined; } | undefined; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }>; } & ", + " & { params: { path: { id: string; }; } & { query?: { instanceId?: string | undefined; } | undefined; }; }) => Promise<{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -10912,7 +10948,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params?: { query?: { kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }>; } & ", + " & { params?: { query?: { kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }; })[]; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -10920,18 +10956,12 @@ "section": "def-server.ObservabilityRouteCreateOptions", "text": "ObservabilityRouteCreateOptions" }, - "; \"GET /api/observability/slos/_definitions 2023-10-31\": { endpoint: \"GET /api/observability/slos/_definitions 2023-10-31\"; params?: ", - "PartialC", + "; \"GET /internal/observability/slos/_definitions\": { endpoint: \"GET /internal/observability/slos/_definitions\"; params?: ", + "TypeC", "<{ query: ", - "PartialC", + "TypeC", "<{ search: ", "StringC", - "; includeOutdatedOnly: ", - "Type", - "; page: ", - "StringC", - "; perPage: ", - "StringC", "; }>; }> | undefined; handler: ({}: ", { "pluginId": "observability", @@ -10940,7 +10970,7 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - " & { params?: { query?: { search?: string | undefined; includeOutdatedOnly?: boolean | undefined; page?: string | undefined; perPage?: string | undefined; } | undefined; } | undefined; }) => Promise<{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; version: number; } & { instanceId?: string | undefined; })[]; }>; } & ", + " & { params: { query: { search: string; }; }; }) => Promise<({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string; total: string; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | undefined; }); } & { filter?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; revision: number; settings: { syncDelay: string; frequency: string; }; enabled: boolean; tags: string[]; groupBy: string; createdAt: string; updatedAt: string; } & { instanceId?: string | undefined; })[]>; } & ", { "pluginId": "observability", "scope": "server", @@ -13842,10 +13872,10 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingUseLegacyFlamegraphAPI", + "id": "def-server.uiSettings.profilingPervCPUWattX86", "type": "Object", "tags": [], - "label": "[profilingUseLegacyFlamegraphAPI]", + "label": "[profilingPervCPUWattX86]", "description": [], "path": "x-pack/plugins/observability/server/ui_settings.ts", "deprecated": false, @@ -13853,7 +13883,7 @@ "children": [ { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingUseLegacyFlamegraphAPI.category", + "id": "def-server.uiSettings.profilingPervCPUWattX86.category", "type": "Array", "tags": [], "label": "category", @@ -13867,7 +13897,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingUseLegacyFlamegraphAPI.name", + "id": "def-server.uiSettings.profilingPervCPUWattX86.name", "type": "string", "tags": [], "label": "name", @@ -13878,21 +13908,29 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingUseLegacyFlamegraphAPI.value", - "type": "boolean", + "id": "def-server.uiSettings.profilingPervCPUWattX86.value", + "type": "number", "tags": [], "label": "value", "description": [], - "signature": [ - "false" - ], "path": "x-pack/plugins/observability/server/ui_settings.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingUseLegacyFlamegraphAPI.schema", + "id": "def-server.uiSettings.profilingPervCPUWattX86.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingPervCPUWattX86.schema", "type": "Object", "tags": [], "label": "schema", @@ -13905,7 +13943,21 @@ "section": "def-common.Type", "text": "Type" }, - "" + "" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingPervCPUWattX86.requiresPageReload", + "type": "boolean", + "tags": [], + "label": "requiresPageReload", + "description": [], + "signature": [ + "true" ], "path": "x-pack/plugins/observability/server/ui_settings.ts", "deprecated": false, @@ -13915,10 +13967,10 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt", + "id": "def-server.uiSettings.profilingPervCPUWattArm64", "type": "Object", "tags": [], - "label": "[profilingPerCoreWatt]", + "label": "[profilingPervCPUWattArm64]", "description": [], "path": "x-pack/plugins/observability/server/ui_settings.ts", "deprecated": false, @@ -13926,7 +13978,7 @@ "children": [ { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.category", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.category", "type": "Array", "tags": [], "label": "category", @@ -13940,7 +13992,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.name", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.name", "type": "string", "tags": [], "label": "name", @@ -13951,7 +14003,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.value", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.value", "type": "number", "tags": [], "label": "value", @@ -13962,7 +14014,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.description", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.description", "type": "string", "tags": [], "label": "description", @@ -13973,7 +14025,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.schema", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.schema", "type": "Object", "tags": [], "label": "schema", @@ -13994,7 +14046,7 @@ }, { "parentPluginId": "observability", - "id": "def-server.uiSettings.profilingPerCoreWatt.requiresPageReload", + "id": "def-server.uiSettings.profilingPervCPUWattArm64.requiresPageReload", "type": "boolean", "tags": [], "label": "requiresPageReload", @@ -14197,6 +14249,269 @@ "trackAdoption": false } ] + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingUseLegacyCo2Calculation", + "type": "Object", + "tags": [], + "label": "[profilingUseLegacyCo2Calculation]", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingUseLegacyCo2Calculation.category", + "type": "Array", + "tags": [], + "label": "category", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingUseLegacyCo2Calculation.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingUseLegacyCo2Calculation.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "false" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingUseLegacyCo2Calculation.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate", + "type": "Object", + "tags": [], + "label": "[profilingAWSCostDiscountRate]", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.category", + "type": "Array", + "tags": [], + "label": "category", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.value", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.requiresPageReload", + "type": "boolean", + "tags": [], + "label": "requiresPageReload", + "description": [], + "signature": [ + "true" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingAWSCostDiscountRate.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour", + "type": "Object", + "tags": [], + "label": "[profilingCostPervCPUPerHour]", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.category", + "type": "Array", + "tags": [], + "label": "category", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.value", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.profilingCostPervCPUPerHour.requiresPageReload", + "type": "boolean", + "tags": [], + "label": "requiresPageReload", + "description": [], + "signature": [ + "true" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "initialIsOpen": false @@ -15591,6 +15906,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-common.profilingAWSCostDiscountRate", + "type": "string", + "tags": [], + "label": "profilingAWSCostDiscountRate", + "description": [], + "signature": [ + "\"observability:profilingAWSCostDiscountRate\"" + ], + "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-common.profilingCo2PerKWH", @@ -15606,6 +15936,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-common.profilingCostPervCPUPerHour", + "type": "string", + "tags": [], + "label": "profilingCostPervCPUPerHour", + "description": [], + "signature": [ + "\"observability:profilingCostPervCPUPerHour\"" + ], + "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-common.profilingDatacenterPUE", @@ -15623,13 +15968,28 @@ }, { "parentPluginId": "observability", - "id": "def-common.profilingPerCoreWatt", + "id": "def-common.profilingPervCPUWattArm64", + "type": "string", + "tags": [], + "label": "profilingPervCPUWattArm64", + "description": [], + "signature": [ + "\"observability:profilingPervCPUWattArm64\"" + ], + "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observability", + "id": "def-common.profilingPervCPUWattX86", "type": "string", "tags": [], - "label": "profilingPerCoreWatt", + "label": "profilingPervCPUWattX86", "description": [], "signature": [ - "\"observability:profilingPerCoreWatt\"" + "\"observability:profilingPerVCPUWattX86\"" ], "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", "deprecated": false, @@ -15638,13 +15998,13 @@ }, { "parentPluginId": "observability", - "id": "def-common.profilingUseLegacyFlamegraphAPI", + "id": "def-common.profilingUseLegacyCo2Calculation", "type": "string", "tags": [], - "label": "profilingUseLegacyFlamegraphAPI", + "label": "profilingUseLegacyCo2Calculation", "description": [], "signature": [ - "\"observability:profilingUseLegacyFlamegraphAPI\"" + "\"observability:profilingUseLegacyCo2Calculation\"" ], "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", "deprecated": false, diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 0c57a24e4c44..fa52f21ac3ff 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 580 | 2 | 571 | 17 | +| 606 | 2 | 597 | 17 | ## Client diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index 29b5cec0de50..73bbb37b5f0d 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -19,7 +19,7 @@ "section": "def-common.Message", "text": "Message" }, - "[]; title: string; } & ", + "[]; title: string; dataTestSubj?: string | undefined; } & ", { "pluginId": "@kbn/shared-ux-utility", "scope": "common", @@ -415,7 +415,15 @@ "Type", "; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", - " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", + " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"GET /internal/observability_ai_assistant/functions/kb_status\": { endpoint: \"GET /internal/observability_ai_assistant/functions/kb_status\"; params?: undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", @@ -814,7 +822,15 @@ "Type", "; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", - " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", + " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"GET /internal/observability_ai_assistant/functions/kb_status\": { endpoint: \"GET /internal/observability_ai_assistant/functions/kb_status\"; params?: undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", @@ -1319,7 +1335,15 @@ "Type", "; }>]>; }> | undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", - " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", + " & { params: { body: { featureIds: string[]; start: string; end: string; } & { filter?: string | undefined; includeRecovered?: boolean | undefined; }; }; }) => Promise<{ content: { total: number; alerts: OutputOf>[]; }; }>; } & ", "ObservabilityAIAssistantRouteCreateOptions", "; \"GET /internal/observability_ai_assistant/functions/kb_status\": { endpoint: \"GET /internal/observability_ai_assistant/functions/kb_status\"; params?: undefined; handler: ({}: ", "ObservabilityAIAssistantRouteHandlerResources", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index dca8e221f5e7..fe29a445cda2 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_log_explorer.mdx b/api_docs/observability_log_explorer.mdx index a49295da03a0..c8caa6f6a29e 100644 --- a/api_docs/observability_log_explorer.mdx +++ b/api_docs/observability_log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogExplorer title: "observabilityLogExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogExplorer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogExplorer'] --- import observabilityLogExplorerObj from './observability_log_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 7d96d1aca7a9..3ccf4f4ae914 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.devdocs.json b/api_docs/observability_shared.devdocs.json index e8ab113a22cf..66888b1e6a82 100644 --- a/api_docs/observability_shared.devdocs.json +++ b/api_docs/observability_shared.devdocs.json @@ -315,6 +315,23 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.allCasesPermissions", + "type": "Function", + "tags": [], + "label": "allCasesPermissions", + "description": [], + "signature": [ + "() => { all: boolean; create: boolean; read: boolean; update: boolean; delete: boolean; push: boolean; connectors: boolean; settings: boolean; }" + ], + "path": "x-pack/plugins/observability_shared/public/utils/cases_permissions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "observabilityShared", "id": "def-public.createEsParams", @@ -414,6 +431,53 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBar", + "type": "Function", + "tags": [], + "label": "EmbeddableProfilingSearchBar", + "description": [], + "signature": [ + "(props: ", + { + "pluginId": "observabilityShared", + "scope": "public", + "docId": "kibObservabilitySharedPluginApi", + "section": "def-public.EmbeddableProfilingSearchBarProps", + "text": "EmbeddableProfilingSearchBarProps" + }, + ") => JSX.Element" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBar.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + { + "pluginId": "observabilityShared", + "scope": "public", + "docId": "kibObservabilitySharedPluginApi", + "section": "def-public.EmbeddableProfilingSearchBarProps", + "text": "EmbeddableProfilingSearchBarProps" + } + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "observabilityShared", "id": "def-public.getContextMenuItemsFromActions", @@ -471,15 +535,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -495,17 +561,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", @@ -739,7 +803,7 @@ "label": "noCasesPermissions", "description": [], "signature": [ - "() => { all: boolean; create: boolean; read: boolean; update: boolean; delete: boolean; push: boolean; connectors: boolean; }" + "() => { all: boolean; create: boolean; read: boolean; update: boolean; delete: boolean; push: boolean; connectors: boolean; settings: boolean; }" ], "path": "x-pack/plugins/observability_shared/public/utils/cases_permissions.ts", "deprecated": false, @@ -826,7 +890,7 @@ "DisambiguateSet", ", Omit, \"href\">> & Omit, \"href\">) | (", "DisambiguateSet", - ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"xs\" | \"l\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", + ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"l\" | \"xs\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", "IconType", " | undefined; iconProps?: Omit<", "EuiIconProps", @@ -865,7 +929,7 @@ "DisambiguateSet", ", Omit, \"href\">> & Omit, \"href\">) | (", "DisambiguateSet", - ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"xs\" | \"l\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", + ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"l\" | \"xs\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", "IconType", " | undefined; iconProps?: Omit<", "EuiIconProps", @@ -896,7 +960,7 @@ "CommonProps", " & Omit, \"color\"> & { bordered?: boolean | undefined; flush?: boolean | undefined; gutterSize?: \"m\" | \"none\" | \"s\" | undefined; listItems?: ", "EuiListGroupItemProps", - "[] | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; size?: \"m\" | \"s\" | \"xs\" | \"l\" | undefined; maxWidth?: boolean | ", + "[] | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; size?: \"m\" | \"s\" | \"l\" | \"xs\" | undefined; maxWidth?: boolean | ", "Property", ".MaxWidth | undefined; showToolTips?: boolean | undefined; wrapText?: boolean | undefined; ariaLabelledby?: string | undefined; }) => JSX.Element" ], @@ -916,7 +980,7 @@ "CommonProps", " & Omit, \"color\"> & { bordered?: boolean | undefined; flush?: boolean | undefined; gutterSize?: \"m\" | \"none\" | \"s\" | undefined; listItems?: ", "EuiListGroupItemProps", - "[] | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; size?: \"m\" | \"s\" | \"xs\" | \"l\" | undefined; maxWidth?: boolean | ", + "[] | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; size?: \"m\" | \"s\" | \"l\" | \"xs\" | undefined; maxWidth?: boolean | ", "Property", ".MaxWidth | undefined; showToolTips?: boolean | undefined; wrapText?: boolean | undefined; ariaLabelledby?: string | undefined; }" ], @@ -1468,30 +1532,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "observabilityShared", - "id": "def-public.useGetUserCasesPermissions", - "type": "Function", - "tags": [], - "label": "useGetUserCasesPermissions", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "cases", - "scope": "common", - "docId": "kibCasesPluginApi", - "section": "def-common.CasesPermissions", - "text": "CasesPermissions" - } - ], - "path": "x-pack/plugins/observability_shared/public/hooks/use_get_user_cases_permissions.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "observabilityShared", "id": "def-public.useInspectorContext", @@ -1912,6 +1952,138 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps", + "type": "Interface", + "tags": [], + "label": "EmbeddableProfilingSearchBarProps", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.kuery", + "type": "string", + "tags": [], + "label": "kuery", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.showDatePicker", + "type": "CompoundType", + "tags": [], + "label": "showDatePicker", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.onQuerySubmit", + "type": "Function", + "tags": [], + "label": "onQuerySubmit", + "description": [], + "signature": [ + "(params: { dateRange: { from: string; to: string; mode?: \"absolute\" | \"relative\" | undefined; }; query: string; }) => void" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.onQuerySubmit.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.onQuerySubmit.$1.dateRange", + "type": "Object", + "tags": [], + "label": "dateRange", + "description": [], + "signature": [ + "{ from: string; to: string; mode?: \"absolute\" | \"relative\" | undefined; }" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.onQuerySubmit.$1.query", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.onRefresh", + "type": "Function", + "tags": [], + "label": "onRefresh", + "description": [], + "signature": [ + "() => void" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.rangeFrom", + "type": "string", + "tags": [], + "label": "rangeFrom", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EmbeddableProfilingSearchBarProps.rangeTo", + "type": "string", + "tags": [], + "label": "rangeTo", + "description": [], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "observabilityShared", "id": "def-public.FetcherResult", @@ -2620,6 +2792,23 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observabilityShared", + "id": "def-public.EMBEDDABLE_PROFILING_SEARCH_BAR", + "type": "string", + "tags": [], + "label": "EMBEDDABLE_PROFILING_SEARCH_BAR", + "description": [ + "Profiling search bar embeddable key" + ], + "signature": [ + "\"EMBEDDABLE_PROFILING_SEARCH_BAR\"" + ], + "path": "x-pack/plugins/observability_shared/public/components/profiling/embeddables/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observabilityShared", "id": "def-public.LazyObservabilityPageTemplateProps", @@ -2895,7 +3084,7 @@ "DisambiguateSet", ", Omit, \"href\">> & Omit, \"href\">) | (", "DisambiguateSet", - ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"xs\" | \"l\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", + ", \"href\">, React.ButtonHTMLAttributes> & React.ButtonHTMLAttributes))), \"color\" | \"onClick\" | \"rel\" | \"target\"> & { size?: \"m\" | \"s\" | \"l\" | \"xs\" | undefined; color?: \"text\" | \"subdued\" | \"primary\" | undefined; label: React.ReactNode; isActive?: boolean | undefined; isDisabled?: boolean | undefined; href?: string | undefined; target?: string | undefined; rel?: string | undefined; iconType?: ", "IconType", " | undefined; iconProps?: Omit<", "EuiIconProps", diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 5b32bb8b6835..6e0f7536ef58 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 292 | 1 | 289 | 15 | +| 305 | 1 | 301 | 15 | ## Client diff --git a/api_docs/osquery.devdocs.json b/api_docs/osquery.devdocs.json index f03a3b873a0c..e2dd1f913cbf 100644 --- a/api_docs/osquery.devdocs.json +++ b/api_docs/osquery.devdocs.json @@ -301,7 +301,15 @@ "label": "createActionService", "description": [], "signature": [ - "{ create: (params: { agent_ids?: string[] | undefined; agent_all?: boolean | undefined; agent_platforms?: string[] | undefined; agent_policy_ids?: string[] | undefined; query?: string | undefined; queries?: { id: string; query: string; ecs_mapping: { [x: string]: { field?: string | undefined; value?: string | string[] | undefined; }; } | undefined; version: string | undefined; platform: string | undefined; removed: boolean | undefined; snapshot: boolean | undefined; }[] | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; ecs_mapping?: { [x: string]: { field?: string | undefined; value?: string | string[] | undefined; }; } | undefined; pack_id?: string | undefined; alert_ids?: string[] | undefined; case_ids?: string[] | undefined; event_ids?: string[] | undefined; metadata?: object | undefined; }, alertData?: OutputOf> | undefined) => Promise<{ response: { action_id: string; '@timestamp': string; expiration: string; type: string; input_type: string; alert_ids: string[] | undefined; event_ids: string[] | undefined; case_ids: string[] | undefined; agent_ids: string[] | undefined; agent_all: boolean | undefined; agent_platforms: string[] | undefined; agent_policy_ids: string[] | undefined; agents: string[]; user_id: string | undefined; metadata: object | undefined; pack_id: string | undefined; pack_name: string | undefined; pack_prebuilt: boolean | undefined; queries: ", + "{ create: (params: { agent_ids?: string[] | undefined; agent_all?: boolean | undefined; agent_platforms?: string[] | undefined; agent_policy_ids?: string[] | undefined; query?: string | undefined; queries?: { id: string; query: string; ecs_mapping: { [x: string]: { field?: string | undefined; value?: string | string[] | undefined; }; } | undefined; version: string | undefined; platform: string | undefined; removed: boolean | undefined; snapshot: boolean | undefined; }[] | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; ecs_mapping?: { [x: string]: { field?: string | undefined; value?: string | string[] | undefined; }; } | undefined; pack_id?: string | undefined; alert_ids?: string[] | undefined; case_ids?: string[] | undefined; event_ids?: string[] | undefined; metadata?: object | undefined; }, alertData?: OutputOf> | undefined) => Promise<{ response: { action_id: string; '@timestamp': string; expiration: string; type: string; input_type: string; alert_ids: string[] | undefined; event_ids: string[] | undefined; case_ids: string[] | undefined; agent_ids: string[] | undefined; agent_all: boolean | undefined; agent_platforms: string[] | undefined; agent_policy_ids: string[] | undefined; agents: string[]; user_id: string | undefined; metadata: object | undefined; pack_id: string | undefined; pack_name: string | undefined; pack_prebuilt: boolean | undefined; queries: ", "Dictionary", "[]; }; fleetActionsCount: number; }>; stop: () => void; }" ], diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 34c0045ada19..a0833a535827 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index fbebc63aaa1f..0571c9018313 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index bb621aec7465..2d7b661f0e7a 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
    public API | Number of teams | |--------------|----------|------------------------| -| 711 | 603 | 40 | +| 724 | 614 | 40 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 76352 | 233 | 65301 | 1602 | +| 77183 | 235 | 65919 | 1621 | ## Plugin Directory @@ -29,15 +29,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 269 | 0 | 263 | 31 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 17 | 1 | 15 | 2 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 69 | 1 | 4 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 810 | 1 | 779 | 50 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 120 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 70 | 1 | 4 | 1 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 813 | 1 | 782 | 51 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 127 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 9 | 0 | 9 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Asset manager plugin for entity assets (inventory, topology, etc) | 9 | 0 | 9 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 91 | 1 | 75 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 104 | 0 | 84 | 28 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 115 | 0 | 95 | 28 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 268 | 2 | 253 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 72 | 0 | 16 | 0 | | cloudChat | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 0 | 0 | 0 | 0 | @@ -62,9 +62,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 922 | 0 | 257 | 4 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 1 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin introduces the concept of dataset quality, where users can easily get an overview on the datasets they have. | 3 | 0 | 3 | 0 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin introduces the concept of dataset quality, where users can easily get an overview on the datasets they have. | 8 | 0 | 8 | 3 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 12 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 133 | 0 | 90 | 20 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 134 | 0 | 91 | 20 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Server APIs for the Elastic AI Assistant | 4 | 0 | 2 | 0 | @@ -90,13 +90,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 148 | 0 | 146 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 6 | 0 | 6 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 176 | 0 | 166 | 13 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2224 | 17 | 1765 | 5 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2208 | 17 | 1749 | 5 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 235 | 0 | 99 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Index pattern fields and ambiguous values formatters | 292 | 5 | 253 | 3 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 59 | 0 | 59 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 2 | 0 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1212 | 3 | 1094 | 46 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1213 | 3 | 1095 | 47 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -104,7 +104,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | graph | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 0 | 0 | 0 | 0 | | grokdebugger | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 58 | 0 | 57 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 149 | 0 | 109 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 151 | 0 | 111 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 3 | 0 | 3 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 215 | 0 | 210 | 4 | @@ -118,31 +118,32 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | kibanaUsageCollection | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 610 | 3 | 417 | 9 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 5 | 0 | 5 | 1 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 625 | 0 | 526 | 60 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 630 | 0 | 531 | 60 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 8 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 10 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | A dashboard panel for creating links to dashboards or external links. | 64 | 0 | 62 | 7 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | A dashboard panel for creating links to dashboards or external links. | 57 | 0 | 57 | 6 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 224 | 0 | 96 | 51 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin provides a LogExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption. | 26 | 0 | 26 | 8 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes the shared components and APIs to access and visualize logs. | 289 | 11 | 274 | 27 | | logstash | [@elastic/logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 45 | 0 | 45 | 7 | -| | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 260 | 0 | 259 | 29 | +| | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 260 | 0 | 259 | 28 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 60 | 0 | 60 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 104 | 8 | 104 | 4 | +| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 104 | 8 | 104 | 7 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 150 | 3 | 64 | 33 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 25 | 0 | 19 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 15 | 3 | 13 | 1 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 35 | 0 | 35 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 580 | 2 | 571 | 17 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 606 | 2 | 597 | 17 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 42 | 0 | 39 | 7 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 15 | 0 | 15 | 1 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 14 | 0 | 14 | 0 | -| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 292 | 1 | 289 | 15 | +| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 305 | 1 | 301 | 15 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 219 | 2 | 164 | 11 | @@ -151,7 +152,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 23 | 0 | 23 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 22 | 0 | 6 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 21 | 0 | 21 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 267 | 0 | 238 | 14 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 268 | 0 | 239 | 14 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 24 | 0 | 19 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 129 | 2 | 118 | 4 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 25 | 0 | 25 | 0 | @@ -162,8 +163,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 13 | 0 | | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 32 | 0 | 8 | 4 | | searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | -| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 270 | 0 | 87 | 3 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 175 | 0 | 106 | 35 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 401 | 0 | 196 | 2 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 179 | 0 | 110 | 36 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | ESS customizations for Security Solution. | 6 | 0 | 6 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 7 | 0 | 7 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 19 | 0 | 18 | 0 | @@ -181,15 +182,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 31 | 0 | 26 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 0 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 20 | 0 | 20 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 23 | 0 | 9 | 0 | | | [@elastic/protections-experience](https://github.com/orgs/elastic/teams/protections-experience) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 30 | 0 | 14 | 5 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 240 | 1 | 196 | 17 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [@elastic/kibana-localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 583 | 1 | 557 | 55 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 145 | 0 | 103 | 9 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 584 | 1 | 558 | 55 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 135 | 0 | 93 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 212 | 0 | 145 | 10 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 13 | 0 | 10 | 3 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 12 | 0 | 9 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 55 | 0 | 23 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 148 | 2 | 110 | 23 | | upgradeAssistant | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | @@ -211,7 +212,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the vislib visualizations. These are the classical area/line/bar, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 1 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 52 | 0 | 50 | 5 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 837 | 12 | 807 | 19 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 835 | 12 | 804 | 19 | | watcher | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | ## Package Directory @@ -231,15 +232,17 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 23 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 21 | 0 | 0 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 2 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 31 | 0 | 31 | 7 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 181 | 0 | 181 | 27 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 34 | 0 | 34 | 8 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 188 | 0 | 188 | 27 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 11 | 0 | 11 | 0 | | | [@elastic/kibana-qa](https://github.com/orgs/elastic/teams/kibana-qa) | - | 12 | 0 | 12 | 0 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 7 | 0 | 7 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 19 | 0 | 16 | 0 | -| | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 62 | 1 | 44 | 3 | +| | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 60 | 1 | 42 | 3 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 14 | 0 | 10 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 78 | 0 | 78 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 2 | 0 | @@ -277,7 +280,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 20 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 165 | 0 | 70 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 166 | 0 | 70 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | @@ -314,8 +317,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 5 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 2 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 111 | 4 | 36 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 10 | 0 | 10 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 116 | 4 | 37 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 16 | 0 | 16 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 10 | 1 | 10 | 0 | @@ -325,8 +328,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 26 | 6 | 26 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 0 | 13 | 1 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 449 | 1 | 178 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 59 | 0 | 53 | 7 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 454 | 1 | 179 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 58 | 0 | 52 | 9 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 44 | 0 | 43 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 2 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 3 | 0 | @@ -347,7 +350,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 0 | 13 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 29 | 0 | 25 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 1 | 11 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 55 | 0 | 8 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 56 | 0 | 8 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 11 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 0 | 0 | @@ -373,9 +376,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 25 | 1 | 24 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 111 | 1 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 352 | 1 | 5 | 2 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 353 | 1 | 5 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 11 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 89 | 0 | 61 | 10 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 98 | 0 | 66 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | @@ -402,11 +405,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 30 | 1 | 18 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 33 | 2 | 20 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 11 | 1 | 11 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 27 | 0 | 4 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 1 | 17 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 37 | 1 | 19 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 18 | 1 | 17 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 155 | 0 | 144 | 0 | @@ -417,6 +420,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 13 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 10 | 0 | 10 | 0 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 16 | 0 | 16 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 19 | 0 | 17 | 6 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 14 | 0 | 9 | 0 | @@ -442,16 +446,17 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 11 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 35125 | 0 | 34718 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 13 | 0 | 5 | 0 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 96 | 0 | 76 | 6 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 35 | 0 | 34 | 0 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 97 | 0 | 77 | 6 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 48 | 0 | 33 | 7 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 27 | 0 | 14 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 3 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 259 | 1 | 199 | 15 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 261 | 1 | 201 | 15 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 19 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 39 | 0 | 39 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 36 | 0 | 14 | 3 | +| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 17 | 0 | 7 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 16 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 29 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | @@ -476,14 +481,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 35 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 108 | 0 | 107 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 7 | 0 | 5 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 158 | 0 | 155 | 0 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 181 | 0 | 178 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 27 | 0 | 1 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 8 | 0 | 8 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 1 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 11 | 0 | 10 | 2 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 9 | 0 | 6 | 2 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 24 | 0 | 4 | 0 | -| | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 20 | 0 | 5 | 0 | +| | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 24 | 1 | 9 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 23 | 0 | 7 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 2 | 3 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 45 | 0 | 0 | 0 | @@ -515,20 +520,24 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 1 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 29 | 0 | 29 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 32 | 0 | 30 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 18 | 0 | 18 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 31 | 1 | 24 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 78 | 0 | 76 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 13 | 0 | 13 | 3 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 2 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 99 | 1 | 99 | 0 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 3 | 0 | 3 | 1 | +| | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 6 | 0 | 6 | 0 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 45 | 0 | 45 | 10 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 51 | 5 | 34 | 0 | | | [@elastic/security-asset-management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 66 | 0 | 66 | 0 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-performance-testing](https://github.com/orgs/elastic/teams/kibana-performance-testing) | - | 3 | 0 | 3 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 171 | 0 | 28 | 0 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 169 | 0 | 51 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 13 | 0 | 7 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 22 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 2 | 0 | @@ -554,11 +563,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. | 18 | 0 | 5 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 2 | 8 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 16 | 0 | 16 | 1 | -| | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 116 | 0 | 113 | 0 | +| | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 117 | 0 | 114 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | -| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 69 | 0 | 69 | 0 | -| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 2211 | 0 | 2211 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 14 | 0 | 12 | 1 | +| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 66 | 0 | 66 | 0 | +| | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 2375 | 0 | 2375 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 18 | 1 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 82 | 0 | 35 | 0 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 44 | 0 | 14 | 0 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 213 | 0 | 114 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 14 | 0 | 14 | 6 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 52 | 0 | 48 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 29 | 0 | 23 | 0 | @@ -568,7 +580,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 341 | 1 | 337 | 32 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 87 | 0 | 76 | 1 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 104 | 0 | 93 | 1 | -| | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 17 | 0 | 12 | 7 | +| | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 17 | 0 | 12 | 8 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 15 | 0 | 7 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 147 | 0 | 125 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 532 | 0 | 519 | 0 | @@ -580,8 +592,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 207 | 0 | 160 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 28 | 0 | 25 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 120 | 0 | 116 | 0 | -| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 37 | 0 | 32 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 54 | 0 | 51 | 1 | +| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 44 | 0 | 39 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 61 | 0 | 57 | 1 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 31 | 0 | 30 | 1 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management @elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 1 | 0 | 1 | 0 | @@ -595,7 +607,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 26 | 0 | 8 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 28 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 60 | 0 | 49 | 5 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 61 | 0 | 48 | 5 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 2 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 5 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 0 | @@ -628,33 +640,32 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 15 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 11 | 0 | 3 | 0 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 144 | 0 | 144 | 0 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 131 | 0 | 128 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 20 | 0 | 12 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 102 | 2 | 65 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 4 | 0 | 2 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 21 | 0 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 24 | 0 | 16 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 5 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 291 | 4 | 244 | 12 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 137 | 5 | 105 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 22 | 0 | 21 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 25 | 0 | 10 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 72 | 0 | 55 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 39 | 0 | 25 | 1 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 1 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 35 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 44 | 0 | 30 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 53 | 0 | 44 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 109 | 0 | 49 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 10 | 0 | 7 | 7 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 285 | 0 | 261 | 9 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 4 | 0 | 0 | 0 | +| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 3 | 0 | 0 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 2 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 80 | 1 | 21 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 16 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 24 | 0 | 14 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 25 | 0 | 15 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 154 | 0 | 151 | 3 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 12 | 0 | 12 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 2 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index ca1e4ee40d00..e23c0a769895 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 1bda61f7d601..7d69418cf6ff 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.devdocs.json b/api_docs/profiling_data_access.devdocs.json index 0e1b1fab4bee..7a8d4a6ae9eb 100644 --- a/api_docs/profiling_data_access.devdocs.json +++ b/api_docs/profiling_data_access.devdocs.json @@ -37,17 +37,9 @@ "label": "ProfilingDataAccessPluginStart", "description": [], "signature": [ - "{ services: { fetchFlamechartData: ({ esClient, rangeFromMs, rangeToMs, kuery, useLegacyFlamegraphAPI, }: ", + "{ services: { fetchFlamechartData: ({ core, esClient, rangeFromMs, rangeToMs, kuery }: ", "FetchFlamechartParams", - ") => Promise<", - { - "pluginId": "@kbn/profiling-utils", - "scope": "common", - "docId": "kibKbnProfilingUtilsPluginApi", - "section": "def-common.BaseFlameGraph", - "text": "BaseFlameGraph" - }, - ">; getStatus: ({ esClient, soClient, spaceId }: ", + ") => Promise<{ TotalSeconds: number; Size: number; Edges: number[][]; FileID: string[]; FrameType: number[]; Inline: boolean[]; ExeFilename: string[]; AddressOrLine: number[]; FunctionName: string[]; FunctionOffset: number[]; SourceFilename: string[]; SourceLine: number[]; CountInclusive: number[]; CountExclusive: number[]; SamplingRate: number; TotalSamples: number; TotalCPU: number; SelfCPU: number; AnnualCO2TonsExclusive: number[]; AnnualCO2TonsInclusive: number[]; AnnualCostsUSDInclusive: number[]; AnnualCostsUSDExclusive: number[]; SelfAnnualCO2Tons: number; TotalAnnualCO2Tons: number; SelfAnnualCostsUSD: number; TotalAnnualCostsUSD: number; }>; getStatus: ({ esClient, soClient, spaceId }: ", "HasSetupParams", ") => Promise<", { @@ -63,7 +55,7 @@ "CloudSetupStateType", " | ", "SetupStateType", - ">; fetchFunction: ({ esClient, rangeFromMs, rangeToMs, kuery, startIndex, endIndex, }: ", + ">; fetchFunction: ({ core, esClient, rangeFromMs, rangeToMs, kuery, startIndex, endIndex, }: ", "FetchFunctionsParams", ") => Promise<", { diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 81cc34b894c6..d4f71d98fe3e 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index c150917716eb..d2872cb24364 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 1a61297dc8ca..9cde2a5d0819 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 72ff87930779..2c65433cf96d 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index 6a8f4d39d685..8e1c216d59c9 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -107,7 +107,15 @@ "label": "get", "description": [], "signature": [ - "({ id, index }: GetAlertParams) => Promise> | undefined>" + "({ id, index }: GetAlertParams) => Promise> | undefined>" ], "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", "deprecated": false, @@ -403,7 +411,15 @@ "SortOptions", "[] | undefined; track_total_hits?: number | boolean | undefined; _source?: string[] | undefined; }) => Promise<", "SearchResponse", - ">, Record>, Record>>" ], @@ -626,7 +642,7 @@ "label": "getBrowserFields", "description": [], "signature": [ - "({ indices, metaFields, allowNoIndex, }: { indices: string[]; metaFields: string[]; allowNoIndex: boolean; }) => Promise<{ browserFields: ", + "({ featureIds, indices, metaFields, allowNoIndex, }: { featureIds: string[]; indices: string[]; metaFields: string[]; allowNoIndex: boolean; }) => Promise<{ browserFields: ", { "pluginId": "ruleRegistry", "scope": "common", @@ -653,12 +669,26 @@ "id": "def-server.AlertsClient.getBrowserFields.$1", "type": "Object", "tags": [], - "label": "{\n indices,\n metaFields,\n allowNoIndex,\n }", + "label": "{\n featureIds,\n indices,\n metaFields,\n allowNoIndex,\n }", "description": [], "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "ruleRegistry", + "id": "def-server.AlertsClient.getBrowserFields.$1.featureIds", + "type": "Array", + "tags": [], + "label": "featureIds", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "ruleRegistry", "id": "def-server.AlertsClient.getBrowserFields.$1.indices", @@ -1651,9 +1681,9 @@ }, ") => ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.AuditEvent", "text": "AuditEvent" } @@ -2701,7 +2731,15 @@ "signature": [ "> & OutputOf>>>(request: TSearchRequest) => Promise<", + ", TAlertDoc = Partial> & OutputOf>>>(request: TSearchRequest) => Promise<", { "pluginId": "@kbn/es-types", "scope": "common", @@ -3338,7 +3376,15 @@ "label": "getAlertByAlertUuid", "description": [], "signature": [ - "(alertUuid: string) => Promise> & OutputOf>> | null> | null" + "(alertUuid: string) => Promise> & OutputOf>> | null> | null" ], "path": "x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts", "deprecated": false, @@ -4752,7 +4798,15 @@ "label": "parseTechnicalFields", "description": [], "signature": [ - "(input: unknown, partial?: boolean) => OutputOf>" + "(input: unknown, partial?: boolean) => OutputOf>" ], "path": "x-pack/plugins/rule_registry/common/parse_technical_fields.ts", "deprecated": false, @@ -5128,7 +5182,7 @@ "label": "ParsedTechnicalFields", "description": [], "signature": [ - "{ readonly \"@timestamp\": string; readonly \"kibana.alert.rule.rule_type_id\": string; readonly \"kibana.alert.rule.consumer\": string; readonly \"kibana.alert.instance.id\": string; readonly \"kibana.alert.rule.category\": string; readonly \"kibana.alert.rule.name\": string; readonly \"kibana.alert.rule.producer\": string; readonly \"kibana.alert.rule.revision\": number; readonly \"kibana.alert.rule.uuid\": string; readonly \"kibana.alert.status\": string; readonly \"kibana.alert.uuid\": string; readonly \"kibana.space_ids\": string[]; readonly \"event.action\"?: string | undefined; readonly tags?: string[] | undefined; readonly \"kibana.alert.rule.execution.uuid\"?: string | undefined; readonly \"event.kind\"?: string | undefined; readonly \"kibana.alert.action_group\"?: string | undefined; readonly \"kibana.alert.case_ids\"?: string[] | undefined; readonly \"kibana.alert.duration.us\"?: number | undefined; readonly \"kibana.alert.end\"?: string | undefined; readonly \"kibana.alert.flapping\"?: boolean | undefined; readonly \"kibana.alert.flapping_history\"?: boolean[] | undefined; readonly \"kibana.alert.last_detected\"?: string | undefined; readonly \"kibana.alert.maintenance_window_ids\"?: string[] | undefined; readonly \"kibana.alert.reason\"?: string | undefined; readonly \"kibana.alert.rule.parameters\"?: { [key: string]: unknown; } | undefined; readonly \"kibana.alert.rule.tags\"?: string[] | undefined; readonly \"kibana.alert.start\"?: string | undefined; readonly \"kibana.alert.time_range\"?: unknown; readonly \"kibana.alert.url\"?: string | undefined; readonly \"kibana.alert.workflow_status\"?: string | undefined; readonly \"kibana.alert.workflow_tags\"?: string[] | undefined; readonly \"kibana.version\"?: string | undefined; readonly \"ecs.version\"?: string | undefined; readonly \"kibana.alert.risk_score\"?: number | undefined; readonly \"kibana.alert.rule.author\"?: string | undefined; readonly \"kibana.alert.rule.created_at\"?: string | undefined; readonly \"kibana.alert.rule.created_by\"?: string | undefined; readonly \"kibana.alert.rule.description\"?: string | undefined; readonly \"kibana.alert.rule.enabled\"?: string | undefined; readonly \"kibana.alert.rule.from\"?: string | undefined; readonly \"kibana.alert.rule.interval\"?: string | undefined; readonly \"kibana.alert.rule.license\"?: string | undefined; readonly \"kibana.alert.rule.note\"?: string | undefined; readonly \"kibana.alert.rule.references\"?: string[] | undefined; readonly \"kibana.alert.rule.rule_id\"?: string | undefined; readonly \"kibana.alert.rule.rule_name_override\"?: string | undefined; readonly \"kibana.alert.rule.to\"?: string | undefined; readonly \"kibana.alert.rule.type\"?: string | undefined; readonly \"kibana.alert.rule.updated_at\"?: string | undefined; readonly \"kibana.alert.rule.updated_by\"?: string | undefined; readonly \"kibana.alert.rule.version\"?: string | undefined; readonly \"kibana.alert.severity\"?: string | undefined; readonly \"kibana.alert.suppression.docs_count\"?: number | undefined; readonly \"kibana.alert.suppression.end\"?: string | undefined; readonly \"kibana.alert.suppression.start\"?: string | undefined; readonly \"kibana.alert.suppression.terms.field\"?: string[] | undefined; readonly \"kibana.alert.suppression.terms.value\"?: string[] | undefined; readonly \"kibana.alert.system_status\"?: string | undefined; readonly \"kibana.alert.workflow_reason\"?: string | undefined; readonly \"kibana.alert.workflow_user\"?: string | undefined; }" + "{ readonly \"@timestamp\": string; readonly \"kibana.alert.rule.rule_type_id\": string; readonly \"kibana.alert.rule.consumer\": string; readonly \"kibana.alert.instance.id\": string; readonly \"kibana.alert.rule.category\": string; readonly \"kibana.alert.rule.name\": string; readonly \"kibana.alert.rule.producer\": string; readonly \"kibana.alert.rule.revision\": number; readonly \"kibana.alert.rule.uuid\": string; readonly \"kibana.alert.status\": string; readonly \"kibana.alert.uuid\": string; readonly \"kibana.space_ids\": string[]; readonly \"event.action\"?: string | undefined; readonly tags?: string[] | undefined; readonly \"kibana.alert.rule.execution.uuid\"?: string | undefined; readonly \"event.kind\"?: string | undefined; readonly \"kibana.alert.action_group\"?: string | undefined; readonly \"kibana.alert.case_ids\"?: string[] | undefined; readonly \"kibana.alert.duration.us\"?: number | undefined; readonly \"kibana.alert.end\"?: string | undefined; readonly \"kibana.alert.flapping\"?: boolean | undefined; readonly \"kibana.alert.flapping_history\"?: boolean[] | undefined; readonly \"kibana.alert.last_detected\"?: string | undefined; readonly \"kibana.alert.maintenance_window_ids\"?: string[] | undefined; readonly \"kibana.alert.reason\"?: string | undefined; readonly \"kibana.alert.rule.parameters\"?: { [key: string]: unknown; } | undefined; readonly \"kibana.alert.rule.tags\"?: string[] | undefined; readonly \"kibana.alert.start\"?: string | undefined; readonly \"kibana.alert.time_range\"?: unknown; readonly \"kibana.alert.url\"?: string | undefined; readonly \"kibana.alert.workflow_assignee_ids\"?: string[] | undefined; readonly \"kibana.alert.workflow_status\"?: string | undefined; readonly \"kibana.alert.workflow_tags\"?: string[] | undefined; readonly \"kibana.version\"?: string | undefined; readonly \"ecs.version\"?: string | undefined; readonly \"kibana.alert.risk_score\"?: number | undefined; readonly \"kibana.alert.rule.author\"?: string | undefined; readonly \"kibana.alert.rule.created_at\"?: string | undefined; readonly \"kibana.alert.rule.created_by\"?: string | undefined; readonly \"kibana.alert.rule.description\"?: string | undefined; readonly \"kibana.alert.rule.enabled\"?: string | undefined; readonly \"kibana.alert.rule.from\"?: string | undefined; readonly \"kibana.alert.rule.interval\"?: string | undefined; readonly \"kibana.alert.rule.license\"?: string | undefined; readonly \"kibana.alert.rule.note\"?: string | undefined; readonly \"kibana.alert.rule.references\"?: string[] | undefined; readonly \"kibana.alert.rule.rule_id\"?: string | undefined; readonly \"kibana.alert.rule.rule_name_override\"?: string | undefined; readonly \"kibana.alert.rule.to\"?: string | undefined; readonly \"kibana.alert.rule.type\"?: string | undefined; readonly \"kibana.alert.rule.updated_at\"?: string | undefined; readonly \"kibana.alert.rule.updated_by\"?: string | undefined; readonly \"kibana.alert.rule.version\"?: string | undefined; readonly \"kibana.alert.severity\"?: string | undefined; readonly \"kibana.alert.suppression.docs_count\"?: number | undefined; readonly \"kibana.alert.suppression.end\"?: string | undefined; readonly \"kibana.alert.suppression.start\"?: string | undefined; readonly \"kibana.alert.suppression.terms.field\"?: string[] | undefined; readonly \"kibana.alert.suppression.terms.value\"?: string[] | undefined; readonly \"kibana.alert.system_status\"?: string | undefined; readonly \"kibana.alert.workflow_reason\"?: string | undefined; readonly \"kibana.alert.workflow_user\"?: string | undefined; }" ], "path": "x-pack/plugins/rule_registry/common/parse_technical_fields.ts", "deprecated": false, diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 418f7ce050c3..fa466b85f9f9 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 267 | 0 | 238 | 14 | +| 268 | 0 | 239 | 14 | ## Server diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index cc8bb29feeff..8dd41189a110 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index cca924baeeb7..5bc4ed69dca5 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 2f098e900ea6..92e020ae6625 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.devdocs.json b/api_docs/saved_objects_management.devdocs.json index 0c087c56c37e..112ad59aab74 100644 --- a/api_docs/saved_objects_management.devdocs.json +++ b/api_docs/saved_objects_management.devdocs.json @@ -294,7 +294,7 @@ "label": "euiColumn", "description": [], "signature": [ - "{ prefix?: string | undefined; scope?: string | undefined; id?: string | undefined; defaultValue?: string | number | readonly string[] | undefined; name: React.ReactNode; security?: string | undefined; children?: React.ReactNode; description?: string | undefined; onChange?: React.FormEventHandler | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; className?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; hidden?: boolean | undefined; lang?: string | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; title?: string | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; color?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"search\" | \"none\" | \"text\" | \"url\" | \"email\" | \"tel\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: Booleanish | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"both\" | \"inline\" | undefined; 'aria-busy'?: Booleanish | undefined; 'aria-checked'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"page\" | \"date\" | \"location\" | \"true\" | \"false\" | \"time\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: Booleanish | undefined; 'aria-dropeffect'?: \"execute\" | \"link\" | \"none\" | \"copy\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: Booleanish | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: Booleanish | undefined; 'aria-haspopup'?: boolean | \"true\" | \"false\" | \"grid\" | \"menu\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: Booleanish | undefined; 'aria-invalid'?: boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: Booleanish | undefined; 'aria-multiline'?: Booleanish | undefined; 'aria-multiselectable'?: Booleanish | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-readonly'?: Booleanish | undefined; 'aria-relevant'?: \"text\" | \"all\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: Booleanish | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: Booleanish | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onError?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDown?: React.KeyboardEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; css?: ", + "{ prefix?: string | undefined; scope?: string | undefined; id?: string | undefined; defaultValue?: string | number | readonly string[] | undefined; name: React.ReactNode; security?: string | undefined; children?: React.ReactNode; description?: string | undefined; onChange?: React.FormEventHandler | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; className?: string | undefined; contentEditable?: Booleanish | \"inherit\" | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; hidden?: boolean | undefined; lang?: string | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; title?: string | undefined; translate?: \"yes\" | \"no\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; color?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"search\" | \"none\" | \"text\" | \"url\" | \"email\" | \"tel\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: Booleanish | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"both\" | \"inline\" | undefined; 'aria-busy'?: Booleanish | undefined; 'aria-checked'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"page\" | \"date\" | \"location\" | \"true\" | \"false\" | \"time\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: Booleanish | undefined; 'aria-dropeffect'?: \"execute\" | \"link\" | \"none\" | \"copy\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: Booleanish | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: Booleanish | undefined; 'aria-haspopup'?: boolean | \"true\" | \"false\" | \"grid\" | \"menu\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: Booleanish | undefined; 'aria-invalid'?: boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: Booleanish | undefined; 'aria-multiline'?: Booleanish | undefined; 'aria-multiselectable'?: Booleanish | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-readonly'?: Booleanish | undefined; 'aria-relevant'?: \"text\" | \"all\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: Booleanish | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: Booleanish | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onError?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDown?: React.KeyboardEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; css?: ", "Interpolation", "<", "Theme", @@ -306,9 +306,9 @@ "section": "def-public.SavedObjectsManagementRecord", "text": "SavedObjectsManagementRecord" }, - "; width?: string | undefined; headers?: string | undefined; dataType?: ", - "EuiTableDataType", - " | undefined; render?: ((value: any, record: ", + "; width?: string | undefined; headers?: string | undefined; abbr?: string | undefined; footer?: string | React.ReactElement> | ((props: ", + "EuiTableFooterProps", + "<", { "pluginId": "savedObjectsManagement", "scope": "public", @@ -316,11 +316,9 @@ "section": "def-public.SavedObjectsManagementRecord", "text": "SavedObjectsManagementRecord" }, - ") => React.ReactNode) | undefined; height?: string | number | undefined; align?: ", - "HorizontalAlignment", - " | undefined; abbr?: string | undefined; footer?: string | React.ReactElement> | ((props: ", - "EuiTableFooterProps", - "<", + ">) => React.ReactNode) | undefined; dataType?: ", + "EuiTableDataType", + " | undefined; render?: ((value: any, record: ", { "pluginId": "savedObjectsManagement", "scope": "public", @@ -328,7 +326,9 @@ "section": "def-public.SavedObjectsManagementRecord", "text": "SavedObjectsManagementRecord" }, - ">) => React.ReactNode) | undefined; readOnly?: boolean | undefined; colSpan?: number | undefined; rowSpan?: number | undefined; valign?: \"top\" | \"bottom\" | \"middle\" | \"baseline\" | undefined; isExpander?: boolean | undefined; textOnly?: boolean | undefined; truncateText?: boolean | { lines: number; } | undefined; mobileOptions?: (Omit<", + ") => React.ReactNode) | undefined; height?: string | number | undefined; align?: ", + "HorizontalAlignment", + " | undefined; readOnly?: boolean | undefined; colSpan?: number | undefined; rowSpan?: number | undefined; valign?: \"top\" | \"bottom\" | \"middle\" | \"baseline\" | undefined; isExpander?: boolean | undefined; textOnly?: boolean | undefined; truncateText?: boolean | { lines: number; } | undefined; mobileOptions?: (Omit<", "EuiTableRowCellMobileOptionsShape", ", \"render\"> & { render?: ((item: ", { diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 565f6dfe7ef3..ea084f6c259e 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 0ff75ff00963..3910180aa11f 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 9639090cb165..161c05e44341 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index 4981df336cae..26e855b9be30 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 8b9513867ef4..cbb296eb15e7 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index a70c69c91dee..b406d501beec 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index f948514fa2fa..d29eac4beaa0 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -15,22 +15,22 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, " extends ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.User", "text": "User" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -45,14 +45,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserRealm", "text": "UserRealm" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -67,14 +67,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserRealm", "text": "UserRealm" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -89,14 +89,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticationProvider", "text": "AuthenticationProvider" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -109,7 +109,7 @@ "description": [ "\nThe AuthenticationType used by ES to authenticate the user.\n" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -122,7 +122,7 @@ "description": [ "\nIndicates whether user is authenticated via Elastic Cloud built-in SAML realm." ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -138,7 +138,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false } @@ -152,7 +152,7 @@ "tags": [], "label": "AuthenticationServiceSetup", "description": [], - "path": "x-pack/plugins/security/public/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -168,15 +168,15 @@ "signature": [ "() => Promise<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, ">" ], - "path": "x-pack/plugins/security/public/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -194,7 +194,7 @@ "signature": [ "() => Promise" ], - "path": "x-pack/plugins/security/public/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -223,9 +223,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" } @@ -257,9 +257,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" } @@ -278,7 +278,7 @@ "tags": [], "label": "SecurityLicense", "description": [], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -292,7 +292,7 @@ "signature": [ "() => boolean" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -308,7 +308,7 @@ "signature": [ "() => boolean" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -324,14 +324,14 @@ "signature": [ "() => ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.SecurityLicenseFeatures", "text": "SecurityLicenseFeatures" } ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -347,7 +347,7 @@ "signature": [ "(licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -361,7 +361,7 @@ "signature": [ "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -380,15 +380,15 @@ "Observable", "<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.SecurityLicenseFeatures", "text": "SecurityLicenseFeatures" }, ">" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false } @@ -404,7 +404,7 @@ "description": [ "\nDescribes Security plugin features that depend on license." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -417,7 +417,7 @@ "description": [ "\nIndicates whether we show login page or skip it." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -430,7 +430,7 @@ "description": [ "\nIndicates whether we allow login or disable it on the login page." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -443,7 +443,7 @@ "description": [ "\nIndicates whether we show security links throughout the kibana app." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -456,7 +456,7 @@ "description": [ "\nIndicates whether we show the Role Mappings UI." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -469,7 +469,7 @@ "description": [ "\nIndicates whether we allow users to access agreement UI and acknowledge it." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -482,7 +482,7 @@ "description": [ "\nIndicates whether we allow logging of audit events." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -495,7 +495,7 @@ "description": [ "\nIndicates whether we allow users to define document level security in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -508,7 +508,7 @@ "description": [ "\nIndicates whether we allow users to define field level security in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -521,7 +521,7 @@ "description": [ "\nIndicates whether we allow users to define remote index privileges in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -534,7 +534,7 @@ "description": [ "\nIndicates whether we allow Role-based access control (RBAC)." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -547,7 +547,7 @@ "description": [ "\nIndicates whether we allow sub-feature privileges." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -560,7 +560,7 @@ "description": [ "\nIndicates whether we allow user profile collaboration features (suggest and privileges checks APIs)." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -575,15 +575,15 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.LoginLayout", "text": "LoginLayout" }, " | undefined" ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false } @@ -597,7 +597,7 @@ "tags": [], "label": "SecurityNavControlServiceStart", "description": [], - "path": "x-pack/plugins/security/public/nav_control/nav_control_service.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -615,15 +615,15 @@ "Observable", "<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-public", "scope": "public", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", "section": "def-public.UserMenuLink", "text": "UserMenuLink" }, "[]>" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_service.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -641,15 +641,15 @@ "signature": [ "(newUserMenuLink: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-public", "scope": "public", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", "section": "def-public.UserMenuLink", "text": "UserMenuLink" }, "[]) => void" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_service.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -662,15 +662,15 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-public", "scope": "public", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", "section": "def-public.UserMenuLink", "text": "UserMenuLink" }, "[]" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_service.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -732,7 +732,7 @@ "tags": [], "label": "UserMenuLink", "description": [], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -743,7 +743,7 @@ "tags": [], "label": "label", "description": [], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false }, @@ -757,7 +757,7 @@ "signature": [ "string | React.ComponentType<{}>" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false }, @@ -768,7 +768,7 @@ "tags": [], "label": "href", "description": [], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false }, @@ -782,7 +782,7 @@ "signature": [ "number | undefined" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false }, @@ -796,7 +796,7 @@ "signature": [ "boolean | undefined" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false }, @@ -812,7 +812,7 @@ "signature": [ "boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined" ], - "path": "x-pack/plugins/security/public/nav_control/nav_control_component.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts", "deprecated": false, "trackAdoption": false } @@ -828,7 +828,7 @@ "description": [ "\nParameters for the bulk get API." ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -844,7 +844,7 @@ "signature": [ "Set" ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false }, @@ -860,7 +860,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false } @@ -876,7 +876,7 @@ "description": [ "\nParameters for the get user profile for the current user API." ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -889,7 +889,7 @@ "description": [ "\nBy default, get API returns user information, but does not return any user data. The optional \"dataPath\"\nparameter can be used to return personal data for this user (within `kibana` namespace only)." ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false } @@ -905,7 +905,7 @@ "description": [ "\nParameters for the suggest API." ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -918,7 +918,7 @@ "description": [ "\nQuery string used to match name-related fields in user profiles. The following fields are treated as\nname-related: username, full_name and email." ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false }, @@ -934,7 +934,7 @@ "signature": [ "number | undefined" ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false }, @@ -950,7 +950,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts", + "path": "x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts", "deprecated": false, "trackAdoption": false } @@ -988,115 +988,108 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-public", "scope": "public", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", "section": "def-public.AuthenticationServiceSetup", "text": "AuthenticationServiceSetup" } ], - "path": "x-pack/plugins/security/public/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false } ], "objects": [], - "setup": { + "start": { "parentPluginId": "security", - "id": "def-public.SecurityPluginSetup", + "id": "def-public.SecurityPluginStart", "type": "Interface", "tags": [], - "label": "SecurityPluginSetup", + "label": "SecurityPluginStart", "description": [], + "signature": [ + { + "pluginId": "security", + "scope": "public", + "docId": "kibSecurityPluginApi", + "section": "def-public.SecurityPluginStart", + "text": "SecurityPluginStart" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityPluginStart", + "text": "SecurityPluginStart" + } + ], "path": "x-pack/plugins/security/public/plugin.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-public.SecurityPluginSetup.authc", + "id": "def-public.SecurityPluginStart.uiApi", "type": "Object", - "tags": [], - "label": "authc", + "tags": [ + "deprecated" + ], + "label": "uiApi", "description": [ - "\nExposes authentication information about the currently logged in user." + "\nExposes UI components that will be loaded asynchronously." ], "signature": [ { "pluginId": "security", "scope": "public", "docId": "kibSecurityPluginApi", - "section": "def-public.AuthenticationServiceSetup", - "text": "AuthenticationServiceSetup" + "section": "def-public.UiApi", + "text": "UiApi" } ], "path": "x-pack/plugins/security/public/plugin.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-public.SecurityPluginSetup.license", - "type": "Object", - "tags": [], - "label": "license", - "description": [ - "\nExposes information about the available security features under the current license." - ], - "signature": [ + "deprecated": true, + "trackAdoption": false, + "references": [ { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.SecurityLicense", - "text": "SecurityLicense" + "plugin": "enterpriseSearch", + "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" + }, + { + "plugin": "enterpriseSearch", + "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" + }, + { + "plugin": "enterpriseSearch", + "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" + }, + { + "plugin": "enterpriseSearch", + "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" } - ], - "path": "x-pack/plugins/security/public/plugin.tsx", - "deprecated": false, - "trackAdoption": false + ] } ], - "lifecycle": "setup", + "lifecycle": "start", "initialIsOpen": true }, - "start": { + "setup": { "parentPluginId": "security", - "id": "def-public.SecurityPluginStart", + "id": "def-public.SecurityPluginSetup", "type": "Interface", "tags": [], - "label": "SecurityPluginStart", + "label": "SecurityPluginSetup", "description": [], - "path": "x-pack/plugins/security/public/plugin.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-public.SecurityPluginStart.navControlService", - "type": "Object", - "tags": [], - "label": "navControlService", - "description": [ - "\nExposes the ability to add custom links to the dropdown menu in the top right, where the user's Avatar is." - ], - "signature": [ - { - "pluginId": "security", - "scope": "public", - "docId": "kibSecurityPluginApi", - "section": "def-public.SecurityNavControlServiceStart", - "text": "SecurityNavControlServiceStart" - } - ], - "path": "x-pack/plugins/security/public/plugin.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-public.SecurityPluginStart.authc", + "id": "def-public.SecurityPluginSetup.authc", "type": "Object", "tags": [], "label": "authc", @@ -1105,167 +1098,41 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-public", "scope": "public", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", "section": "def-public.AuthenticationServiceSetup", "text": "AuthenticationServiceSetup" } ], - "path": "x-pack/plugins/security/public/plugin.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-public.SecurityPluginStart.userProfiles", + "id": "def-public.SecurityPluginSetup.license", "type": "Object", "tags": [], - "label": "userProfiles", + "label": "license", "description": [ - "\nA set of methods to work with Kibana user profiles." + "\nExposes information about the available security features under the current license." ], "signature": [ - "{ update: (data: D) => Promise; suggest: (path: string, params: ", - { - "pluginId": "security", - "scope": "public", - "docId": "kibSecurityPluginApi", - "section": "def-public.UserProfileSuggestParams", - "text": "UserProfileSuggestParams" - }, - ") => Promise<", - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.UserProfile", - "text": "UserProfile" - }, - "[]>; bulkGet: (params: ", - { - "pluginId": "security", - "scope": "public", - "docId": "kibSecurityPluginApi", - "section": "def-public.UserProfileBulkGetParams", - "text": "UserProfileBulkGetParams" - }, - ") => Promise<", - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.UserProfile", - "text": "UserProfile" - }, - "[]>; getCurrent: (params?: ", - { - "pluginId": "security", - "scope": "public", - "docId": "kibSecurityPluginApi", - "section": "def-public.UserProfileGetCurrentParams", - "text": "UserProfileGetCurrentParams" - }, - " | undefined) => Promise<", - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.GetUserProfileResponse", - "text": "GetUserProfileResponse" - }, - ">; readonly userProfile$: ", - "Observable", - "<", { - "pluginId": "@kbn/user-profile-components", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibKbnUserProfileComponentsPluginApi", - "section": "def-common.UserProfileData", - "text": "UserProfileData" - }, - " | null>; }" + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.SecurityLicense", + "text": "SecurityLicense" + } ], - "path": "x-pack/plugins/security/public/plugin.tsx", + "path": "x-pack/packages/security/plugin_types_public/src/plugin.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-public.SecurityPluginStart.uiApi", - "type": "Object", - "tags": [ - "deprecated" - ], - "label": "uiApi", - "description": [ - "\nExposes UI components that will be loaded asynchronously." - ], - "signature": [ - { - "pluginId": "security", - "scope": "public", - "docId": "kibSecurityPluginApi", - "section": "def-public.UiApi", - "text": "UiApi" - } - ], - "path": "x-pack/plugins/security/public/plugin.tsx", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "enterpriseSearch", - "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" - }, - { - "plugin": "enterpriseSearch", - "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" - }, - { - "plugin": "enterpriseSearch", - "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" - }, - { - "plugin": "enterpriseSearch", - "path": "x-pack/plugins/enterprise_search/public/applications/workplace_search/views/account_settings/account_settings.tsx" - } - ] } ], - "lifecycle": "start", + "lifecycle": "setup", "initialIsOpen": true } }, @@ -1438,338 +1305,165 @@ "interfaces": [ { "parentPluginId": "security", - "id": "def-server.AuditEvent", + "id": "def-server.Actions", "type": "Interface", "tags": [], - "label": "AuditEvent", + "label": "Actions", "description": [ - "\nAudit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.12/index.html\n\nIf you add additional fields to the schema ensure you update the Kibana Filebeat module:\nhttps://github.com/elastic/beats/tree/master/filebeat/module/kibana\n" - ], - "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditEvent", - "text": "AuditEvent" - }, - " extends ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.LogMeta", - "text": "LogMeta" - } + "Actions are used to create the \"actions\" that are associated with Elasticsearch's\napplication privileges, and are used to perform the authorization checks implemented\nby the various `checkPrivilegesWithRequest` derivatives." ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditEvent.message", - "type": "string", + "id": "def-server.Actions.api", + "type": "Object", "tags": [], - "label": "message", - "description": [ - "\nLog message" + "label": "api", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ApiActions", + "text": "ApiActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditEvent.kibana", + "id": "def-server.Actions.app", "type": "Object", "tags": [], - "label": "kibana", - "description": [ - "\nKibana specific fields" - ], + "label": "app", + "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditKibana", - "text": "AuditKibana" - }, - " | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditEvent.http", - "type": "Object", - "tags": [], - "label": "http", - "description": [ - "\nFields describing an HTTP request" - ], - "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditHttp", - "text": "AuditHttp" - }, - " | undefined" + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AppActions", + "text": "AppActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditHttp", - "type": "Interface", - "tags": [], - "label": "AuditHttp", - "description": [ - "\nAudit http schema using ECS format" - ], - "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditHttp", - "text": "AuditHttp" }, - " extends ", - { - "pluginId": "@kbn/ecs", - "scope": "common", - "docId": "kibKbnEcsPluginApi", - "section": "def-common.EcsHttp", - "text": "EcsHttp" - } - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ { "parentPluginId": "security", - "id": "def-server.AuditHttp.request", + "id": "def-server.Actions.cases", "type": "Object", "tags": [], - "label": "request", - "description": [ - "\nHTTP request details" - ], + "label": "cases", + "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditRequest", - "text": "AuditRequest" - }, - " | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana", - "type": "Interface", - "tags": [], - "label": "AuditKibana", - "description": [ - "\nAudit kibana schema using ECS format" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.space_id", - "type": "string", - "tags": [], - "label": "space_id", - "description": [ - "\nThe ID of the space associated with this event." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.session_id", - "type": "string", - "tags": [], - "label": "session_id", - "description": [ - "\nThe ID of the user session associated with this event. Each login attempt\nresults in a unique session id." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.saved_object", - "type": "Object", - "tags": [], - "label": "saved_object", - "description": [ - "\nSaved object that was created, changed, deleted or accessed as part of this event." - ], - "signature": [ - "{ type: string; id: string; } | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.authentication_provider", - "type": "string", - "tags": [], - "label": "authentication_provider", - "description": [ - "\nName of authentication provider associated with a login event." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.authentication_type", - "type": "string", - "tags": [], - "label": "authentication_type", - "description": [ - "\nType of authentication provider associated with a login event." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuditKibana.authentication_realm", - "type": "string", - "tags": [], - "label": "authentication_realm", - "description": [ - "\nName of Elasticsearch realm that has authenticated the user." - ], - "signature": [ - "string | undefined" + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CasesActions", + "text": "CasesActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditKibana.lookup_realm", + "id": "def-server.Actions.login", "type": "string", "tags": [], - "label": "lookup_realm", - "description": [ - "\nName of Elasticsearch realm where the user details were retrieved from." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "label": "login", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditKibana.add_to_spaces", + "id": "def-server.Actions.savedObject", "type": "Object", "tags": [], - "label": "add_to_spaces", - "description": [ - "\nSet of space IDs that a saved object was shared to." - ], + "label": "savedObject", + "description": [], "signature": [ - "readonly string[] | undefined" + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SavedObjectActions", + "text": "SavedObjectActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditKibana.delete_from_spaces", + "id": "def-server.Actions.alerting", "type": "Object", "tags": [], - "label": "delete_from_spaces", - "description": [ - "\nSet of space IDs that a saved object was removed from." - ], + "label": "alerting", + "description": [], "signature": [ - "readonly string[] | undefined" + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AlertingActions", + "text": "AlertingActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditKibana.unauthorized_spaces", + "id": "def-server.Actions.space", "type": "Object", "tags": [], - "label": "unauthorized_spaces", - "description": [ - "\nSet of space IDs that are not authorized for an action." - ], + "label": "space", + "description": [], "signature": [ - "readonly string[] | undefined" + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SpaceActions", + "text": "SpaceActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuditKibana.unauthorized_types", + "id": "def-server.Actions.ui", "type": "Object", "tags": [], - "label": "unauthorized_types", - "description": [ - "\nSet of types that are not authorized for an action." - ], + "label": "ui", + "description": [], "signature": [ - "readonly string[] | undefined" + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UIActions", + "text": "UIActions" + } ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts", "deprecated": false, "trackAdoption": false } @@ -1778,141 +1472,196 @@ }, { "parentPluginId": "security", - "id": "def-server.AuditLogger", + "id": "def-server.AlertingActions", "type": "Interface", "tags": [], - "label": "AuditLogger", + "label": "AlertingActions", "description": [], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditLogger.log", + "id": "def-server.AlertingActions.get", "type": "Function", "tags": [], - "label": "log", - "description": [ - "\nLogs an {@link AuditEvent} and automatically adds meta data about the\ncurrent user, space and correlation id.\n\nGuidelines around what events should be logged and how they should be\nstructured can be found in: `/x-pack/plugins/security/README.md`\n" - ], + "label": "get", + "description": [], "signature": [ - "(event: ", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditEvent", - "text": "AuditEvent" - }, - " | undefined) => void" + "(ruleTypeId: string, consumer: string, alertingEntity: string, operation: string) => string" ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditLogger.log.$1", - "type": "Object", + "id": "def-server.AlertingActions.get.$1", + "type": "string", "tags": [], - "label": "event", + "label": "ruleTypeId", "description": [], "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditEvent", - "text": "AuditEvent" - }, - " | undefined" + "string" ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", "deprecated": false, "trackAdoption": false, - "isRequired": false + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.AlertingActions.get.$2", + "type": "string", + "tags": [], + "label": "consumer", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.AlertingActions.get.$3", + "type": "string", + "tags": [], + "label": "alertingEntity", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.AlertingActions.get.$4", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] - }, - { - "parentPluginId": "security", - "id": "def-server.AuditLogger.enabled", - "type": "boolean", - "tags": [], - "label": "enabled", - "description": [ - "\nIndicates whether audit logging is enabled or not.\n\nUseful for skipping resource-intense operations that don't need to be performed when audit\nlogging is disabled." - ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false }, { "parentPluginId": "security", - "id": "def-server.AuditRequest", + "id": "def-server.ApiActions", "type": "Interface", "tags": [], - "label": "AuditRequest", - "description": [ - "\nAudit request schema using ECS format" - ], - "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditRequest", - "text": "AuditRequest" - }, - " extends { body?: { bytes?: number | undefined; content?: string | undefined; } | undefined; bytes?: number | undefined; id?: string | undefined; method?: string | undefined; mime_type?: string | undefined; referrer?: string | undefined; }" - ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "label": "ApiActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditRequest.headers", - "type": "Object", + "id": "def-server.ApiActions.get", + "type": "Function", "tags": [], - "label": "headers", - "description": [ - "\nHTTP request headers" - ], + "label": "get", + "description": [], "signature": [ - "{ 'x-forwarded-for'?: string | undefined; } | undefined" + "(operation: string) => string" ], - "path": "x-pack/plugins/security/server/audit/audit_events.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.ApiActions.get.$1", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false }, { "parentPluginId": "security", - "id": "def-server.AuditServiceSetup", + "id": "def-server.APIKeys", "type": "Interface", "tags": [], - "label": "AuditServiceSetup", + "label": "APIKeys", "description": [], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditServiceSetup.asScoped", + "id": "def-server.APIKeys.areAPIKeysEnabled", "type": "Function", "tags": [], - "label": "asScoped", + "label": "areAPIKeysEnabled", "description": [ - "\nCreates an {@link AuditLogger} scoped to the current request.\n\nThis audit logger logs events with all required user and session info and should be used for\nall user-initiated actions.\n" + "\nDetermines if API Keys are enabled in Elasticsearch." + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.areCrossClusterAPIKeysEnabled", + "type": "Function", + "tags": [], + "label": "areCrossClusterAPIKeysEnabled", + "description": [ + "\nDetermines if Cross-Cluster API Keys are enabled in Elasticsearch." + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [ + "\nTries to create an API key for the current user.\n\nReturns newly created API key or `null` if API keys are disabled.\n\nUser needs `manage_api_key` privilege to create REST API keys and `manage_security` for Cross-Cluster API keys.\n" ], "signature": [ "(request: ", @@ -1923,26 +1672,31 @@ "section": "def-common.KibanaRequest", "text": "KibanaRequest" }, - ") => ", + ", createParams: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditLogger", - "text": "AuditLogger" - } + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CreateAPIKeyParams", + "text": "CreateAPIKeyParams" + }, + ") => Promise<", + "SecurityCreateApiKeyResponse", + " | null>" ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuditServiceSetup.asScoped.$1", + "id": "def-server.APIKeys.create.$1", "type": "Object", "tags": [], "label": "request", - "description": [], + "description": [ + "Request instance." + ], "signature": [ { "pluginId": "@kbn/core-http-server", @@ -1953,7 +1707,30 @@ }, "" ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.create.$2", + "type": "CompoundType", + "tags": [], + "label": "createParams", + "description": [ + "The params to create an API key" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CreateAPIKeyParams", + "text": "CreateAPIKeyParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1963,164 +1740,1868 @@ }, { "parentPluginId": "security", - "id": "def-server.AuditServiceSetup.withoutRequest", - "type": "Object", + "id": "def-server.APIKeys.grantAsInternalUser", + "type": "Function", "tags": [], - "label": "withoutRequest", + "label": "grantAsInternalUser", "description": [ - "\n{@link AuditLogger} for background tasks only.\n\nThis audit logger logs events without any user or session info and should never be used to log\nuser-initiated actions.\n" + "\nTries to grant an API key for the current user." ], "signature": [ + "(request: ", { - "pluginId": "security", + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ", createParams: Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }>) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditLogger", - "text": "AuditLogger" - } + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.GrantAPIKeyResult", + "text": "GrantAPIKeyResult" + }, + " | null>" ], - "path": "x-pack/plugins/security/server/audit/audit_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuthenticatedUser", - "type": "Interface", - "tags": [], - "label": "AuthenticatedUser", - "description": [ - "\nRepresents the currently authenticated user." - ], - "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.AuthenticatedUser", - "text": "AuthenticatedUser" + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.APIKeys.grantAsInternalUser.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "Request instance." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.grantAsInternalUser.$2", + "type": "CompoundType", + "tags": [], + "label": "createParams", + "description": [ + "Create operation parameters." + ], + "signature": [ + "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, - " extends ", { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.User", - "text": "User" + "parentPluginId": "security", + "id": "def-server.APIKeys.validate", + "type": "Function", + "tags": [], + "label": "validate", + "description": [ + "\nTries to validate an API key." + ], + "signature": [ + "(apiKeyPrams: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ValidateAPIKeyParams", + "text": "ValidateAPIKeyParams" + }, + ") => Promise" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.APIKeys.validate.$1", + "type": "Object", + "tags": [], + "label": "apiKeyPrams", + "description": [ + "ValidateAPIKeyParams." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.ValidateAPIKeyParams", + "text": "ValidateAPIKeyParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.invalidate", + "type": "Function", + "tags": [], + "label": "invalidate", + "description": [ + "\nTries to invalidate an API keys." + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ", params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeyResult", + "text": "InvalidateAPIKeyResult" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.APIKeys.invalidate.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "Request instance." + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.invalidate.$2", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "The params to invalidate an API keys." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.APIKeys.invalidateAsInternalUser", + "type": "Function", + "tags": [], + "label": "invalidateAsInternalUser", + "description": [ + "\nTries to invalidate the API keys by using the internal user." + ], + "signature": [ + "(params: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeyResult", + "text": "InvalidateAPIKeyResult" + }, + " | null>" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.APIKeys.invalidateAsInternalUser.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "The params to invalidate the API keys." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.InvalidateAPIKeysParams", + "text": "InvalidateAPIKeysParams" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AppActions", + "type": "Interface", + "tags": [], + "label": "AppActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AppActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AppActions.get.$1", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditEvent", + "type": "Interface", + "tags": [], + "label": "AuditEvent", + "description": [ + "\nAudit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.12/index.html\n\nIf you add additional fields to the schema ensure you update the Kibana Filebeat module:\nhttps://github.com/elastic/beats/tree/master/filebeat/module/kibana\n" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " extends ", + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.LogMeta", + "text": "LogMeta" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditEvent.message", + "type": "string", + "tags": [], + "label": "message", + "description": [ + "\nLog message" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditEvent.kibana", + "type": "Object", + "tags": [], + "label": "kibana", + "description": [ + "\nKibana specific fields" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditKibana", + "text": "AuditKibana" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditEvent.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [ + "\nFields describing an HTTP request" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditHttp", + "text": "AuditHttp" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditHttp", + "type": "Interface", + "tags": [], + "label": "AuditHttp", + "description": [ + "\nAudit http schema using ECS format" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditHttp", + "text": "AuditHttp" + }, + " extends ", + { + "pluginId": "@kbn/ecs", + "scope": "common", + "docId": "kibKbnEcsPluginApi", + "section": "def-common.EcsHttp", + "text": "EcsHttp" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditHttp.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "\nHTTP request details" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditRequest", + "text": "AuditRequest" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana", + "type": "Interface", + "tags": [], + "label": "AuditKibana", + "description": [ + "\nAudit kibana schema using ECS format" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.space_id", + "type": "string", + "tags": [], + "label": "space_id", + "description": [ + "\nThe ID of the space associated with this event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.session_id", + "type": "string", + "tags": [], + "label": "session_id", + "description": [ + "\nThe ID of the user session associated with this event. Each login attempt\nresults in a unique session id." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.saved_object", + "type": "Object", + "tags": [], + "label": "saved_object", + "description": [ + "\nSaved object that was created, changed, deleted or accessed as part of this event." + ], + "signature": [ + "{ type: string; id: string; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.authentication_provider", + "type": "string", + "tags": [], + "label": "authentication_provider", + "description": [ + "\nName of authentication provider associated with a login event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.authentication_type", + "type": "string", + "tags": [], + "label": "authentication_type", + "description": [ + "\nType of authentication provider associated with a login event." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.authentication_realm", + "type": "string", + "tags": [], + "label": "authentication_realm", + "description": [ + "\nName of Elasticsearch realm that has authenticated the user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.lookup_realm", + "type": "string", + "tags": [], + "label": "lookup_realm", + "description": [ + "\nName of Elasticsearch realm where the user details were retrieved from." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.add_to_spaces", + "type": "Object", + "tags": [], + "label": "add_to_spaces", + "description": [ + "\nSet of space IDs that a saved object was shared to." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.delete_from_spaces", + "type": "Object", + "tags": [], + "label": "delete_from_spaces", + "description": [ + "\nSet of space IDs that a saved object was removed from." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.unauthorized_spaces", + "type": "Object", + "tags": [], + "label": "unauthorized_spaces", + "description": [ + "\nSet of space IDs that are not authorized for an action." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditKibana.unauthorized_types", + "type": "Object", + "tags": [], + "label": "unauthorized_types", + "description": [ + "\nSet of types that are not authorized for an action." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditLogger", + "type": "Interface", + "tags": [], + "label": "AuditLogger", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditLogger.log", + "type": "Function", + "tags": [], + "label": "log", + "description": [ + "\nLogs an {@link AuditEvent} and automatically adds meta data about the\ncurrent user, space and correlation id.\n\nGuidelines around what events should be logged and how they should be\nstructured can be found in: `/x-pack/plugins/security/README.md`\n" + ], + "signature": [ + "(event: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " | undefined) => void" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditLogger.log.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditEvent", + "text": "AuditEvent" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.AuditLogger.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nIndicates whether audit logging is enabled or not.\n\nUseful for skipping resource-intense operations that don't need to be performed when audit\nlogging is disabled." + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditRequest", + "type": "Interface", + "tags": [], + "label": "AuditRequest", + "description": [ + "\nAudit request schema using ECS format" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditRequest", + "text": "AuditRequest" + }, + " extends { body?: { bytes?: number | undefined; content?: string | undefined; } | undefined; bytes?: number | undefined; id?: string | undefined; method?: string | undefined; mime_type?: string | undefined; referrer?: string | undefined; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditRequest.headers", + "type": "Object", + "tags": [], + "label": "headers", + "description": [ + "\nHTTP request headers" + ], + "signature": [ + "{ 'x-forwarded-for'?: string | undefined; } | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuditServiceSetup", + "type": "Interface", + "tags": [], + "label": "AuditServiceSetup", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditServiceSetup.asScoped", + "type": "Function", + "tags": [], + "label": "asScoped", + "description": [ + "\nCreates an {@link AuditLogger} scoped to the current request.\n\nThis audit logger logs events with all required user and session info and should be used for\nall user-initiated actions.\n" + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditLogger", + "text": "AuditLogger" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuditServiceSetup.asScoped.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.AuditServiceSetup.withoutRequest", + "type": "Object", + "tags": [], + "label": "withoutRequest", + "description": [ + "\n{@link AuditLogger} for background tasks only.\n\nThis audit logger logs events without any user or session info and should never be used to log\nuser-initiated actions.\n" + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuditLogger", + "text": "AuditLogger" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser", + "type": "Interface", + "tags": [], + "label": "AuthenticatedUser", + "description": [ + "\nRepresents the currently authenticated user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.User", + "text": "User" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.authentication_realm", + "type": "Object", + "tags": [], + "label": "authentication_realm", + "description": [ + "\nThe name and type of the Realm that has authenticated the user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserRealm", + "text": "UserRealm" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.lookup_realm", + "type": "Object", + "tags": [], + "label": "lookup_realm", + "description": [ + "\nThe name and type of the Realm where the user information were retrieved from." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.UserRealm", + "text": "UserRealm" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.authentication_provider", + "type": "Object", + "tags": [], + "label": "authentication_provider", + "description": [ + "\nThe authentication provider that used to authenticate user." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticationProvider", + "text": "AuthenticationProvider" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.authentication_type", + "type": "string", + "tags": [], + "label": "authentication_type", + "description": [ + "\nThe AuthenticationType used by ES to authenticate the user.\n" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.elastic_cloud_user", + "type": "boolean", + "tags": [], + "label": "elastic_cloud_user", + "description": [ + "\nIndicates whether user is authenticated via Elastic Cloud built-in SAML realm." + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.profile_uid", + "type": "string", + "tags": [], + "label": "profile_uid", + "description": [ + "\nUser profile ID of this user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticationServiceStart", + "type": "Interface", + "tags": [], + "label": "AuthenticationServiceStart", + "description": [ + "\nAuthentication services available on the security plugin's start contract." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthenticationServiceStart.apiKeys", + "type": "Object", + "tags": [], + "label": "apiKeys", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.APIKeys", + "text": "APIKeys" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticationServiceStart.getCurrentUser", + "type": "Function", + "tags": [], + "label": "getCurrentUser", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " | null" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthenticationServiceStart.getCurrentUser.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationMode", + "type": "Interface", + "tags": [], + "label": "AuthorizationMode", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationMode.useRbacForRequest", + "type": "Function", + "tags": [], + "label": "useRbacForRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => boolean" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationMode.useRbacForRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/mode.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup", + "type": "Interface", + "tags": [], + "label": "AuthorizationServiceSetup", + "description": [ + "\nAuthorization services available on the setup contract of the security plugin." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [ + "\nActions are used to create the \"actions\" that are associated with Elasticsearch's\napplication privileges, and are used to perform the authorization checks implemented\nby the various `checkPrivilegesWithRequest` derivatives." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.Actions", + "text": "Actions" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesWithRequest", + "type": "Function", + "tags": [], + "label": "checkPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivileges", + "text": "CheckPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesDynamicallyWithRequest", + "type": "Function", + "tags": [], + "label": "checkPrivilegesDynamicallyWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesDynamically", + "text": "CheckPrivilegesDynamically" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkPrivilegesDynamicallyWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkSavedObjectsPrivilegesWithRequest", + "type": "Function", + "tags": [], + "label": "checkSavedObjectsPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckSavedObjectsPrivileges", + "text": "CheckSavedObjectsPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.checkSavedObjectsPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "security", + "id": "def-server.AuthorizationServiceSetup.mode", + "type": "Object", + "tags": [], + "label": "mode", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.AuthorizationMode", + "text": "AuthorizationMode" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CasesActions", + "type": "Interface", + "tags": [], + "label": "CasesActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CasesActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(owner: string, operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CasesActions.get.$1", + "type": "string", + "tags": [], + "label": "owner", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CasesActions.get.$2", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges", + "type": "Interface", + "tags": [], + "label": "CheckPrivileges", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpace", + "type": "Function", + "tags": [], + "label": "atSpace", + "description": [], + "signature": [ + "(spaceId: string, privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpace.$1", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpace.$2", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpace.$3", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpaces", + "type": "Function", + "tags": [], + "label": "atSpaces", + "description": [], + "signature": [ + "(spaceIds: string[], privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpaces.$1", + "type": "Array", + "tags": [], + "label": "spaceIds", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpaces.$2", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.atSpaces.$3", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.globally", + "type": "Function", + "tags": [], + "label": "globally", + "description": [], + "signature": [ + "(privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.globally.$1", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivileges.globally.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesOptions", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesOptions", + "description": [ + "\nOptions to influce the privilege checks." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.authentication_realm", - "type": "Object", + "id": "def-server.CheckPrivilegesOptions.requireLoginAction", + "type": "CompoundType", "tags": [], - "label": "authentication_realm", + "label": "requireLoginAction", "description": [ - "\nThe name and type of the Realm that has authenticated the user." + "\nWhether or not the `login` action should be required (default: true).\nSetting this to false is not advised except for special circumstances, when you do not require\nthe request to belong to a user capable of logging into Kibana." ], "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.UserRealm", - "text": "UserRealm" - } + "boolean | undefined" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false - }, + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesPayload", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesPayload", + "description": [ + "\nPrivileges that can be checked for the Kibana users." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.lookup_realm", - "type": "Object", + "id": "def-server.CheckPrivilegesPayload.kibana", + "type": "CompoundType", "tags": [], - "label": "lookup_realm", + "label": "kibana", "description": [ - "\nThe name and type of the Realm where the user information were retrieved from." + "\nA list of the Kibana specific privileges (usually generated with `security.authz.actions.*.get(...)`)." ], "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.UserRealm", - "text": "UserRealm" - } + "string | string[] | undefined" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.authentication_provider", + "id": "def-server.CheckPrivilegesPayload.elasticsearch", "type": "Object", "tags": [], - "label": "authentication_provider", + "label": "elasticsearch", "description": [ - "\nThe authentication provider that used to authenticate user." + "\nA set of the Elasticsearch cluster and index privileges." ], "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.AuthenticationProvider", - "text": "AuthenticationProvider" - } + "{ cluster: string[]; index: Record; } | undefined" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false - }, + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesResponse", + "type": "Interface", + "tags": [], + "label": "CheckPrivilegesResponse", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.authentication_type", - "type": "string", + "id": "def-server.CheckPrivilegesResponse.hasAllRequested", + "type": "boolean", "tags": [], - "label": "authentication_type", - "description": [ - "\nThe AuthenticationType used by ES to authenticate the user.\n" - ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "label": "hasAllRequested", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.elastic_cloud_user", - "type": "boolean", + "id": "def-server.CheckPrivilegesResponse.username", + "type": "string", "tags": [], - "label": "elastic_cloud_user", - "description": [ - "\nIndicates whether user is authenticated via Elastic Cloud built-in SAML realm." - ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "label": "username", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.AuthenticatedUser.profile_uid", - "type": "string", + "id": "def-server.CheckPrivilegesResponse.privileges", + "type": "Object", "tags": [], - "label": "profile_uid", - "description": [ - "\nUser profile ID of this user." - ], + "label": "privileges", + "description": [], "signature": [ - "string | undefined" + "{ kibana: { resource?: string | undefined; privilege: string; authorized: boolean; }[]; elasticsearch: { cluster: { privilege: string; authorized: boolean; }[]; index: { [indexName: string]: { privilege: string; authorized: boolean; }[]; }; }; }" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false } @@ -2129,213 +3610,163 @@ }, { "parentPluginId": "security", - "id": "def-server.AuthenticationServiceStart", + "id": "def-server.CheckUserProfilesPrivileges", "type": "Interface", "tags": [], - "label": "AuthenticationServiceStart", + "label": "CheckUserProfilesPrivileges", "description": [ - "\nAuthentication services available on the security plugin's start contract." + "\nAn interface to check users profiles privileges in a specific context (only a single-space context is supported at\nthe moment)." ], - "path": "x-pack/plugins/security/server/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuthenticationServiceStart.apiKeys", - "type": "Object", + "id": "def-server.CheckUserProfilesPrivileges.atSpace", + "type": "Function", "tags": [], - "label": "apiKeys", + "label": "atSpace", "description": [], "signature": [ - "{ create: (request: ", - { - "pluginId": "@kbn/core-http-server", - "scope": "common", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-common.KibanaRequest", - "text": "KibanaRequest" - }, - ", createParams: ", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.CreateAPIKeyParams", - "text": "CreateAPIKeyParams" - }, - ") => Promise<", - "SecurityCreateApiKeyResponse", - " | null>; validate: (apiKeyPrams: ", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.ValidateAPIKeyParams", - "text": "ValidateAPIKeyParams" - }, - ") => Promise; areAPIKeysEnabled: () => Promise; areCrossClusterAPIKeysEnabled: () => Promise; invalidate: (request: ", - { - "pluginId": "@kbn/core-http-server", - "scope": "common", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-common.KibanaRequest", - "text": "KibanaRequest" - }, - ", params: ", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.InvalidateAPIKeysParams", - "text": "InvalidateAPIKeysParams" - }, - ") => Promise<", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.InvalidateAPIKeyResult", - "text": "InvalidateAPIKeyResult" - }, - " | null>; grantAsInternalUser: (request: ", - { - "pluginId": "@kbn/core-http-server", - "scope": "common", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-common.KibanaRequest", - "text": "KibanaRequest" - }, - ", createParams: Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }>) => Promise<", - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.GrantAPIKeyResult", - "text": "GrantAPIKeyResult" - }, - " | null>; invalidateAsInternalUser: (params: ", + "(spaceId: string, privileges: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.InvalidateAPIKeysParams", - "text": "InvalidateAPIKeysParams" + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesPayload", + "text": "CheckUserProfilesPrivilegesPayload" }, ") => Promise<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.InvalidateAPIKeyResult", - "text": "InvalidateAPIKeyResult" - }, - " | null>; }" - ], - "path": "x-pack/plugins/security/server/authentication/authentication_service.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.AuthenticationServiceStart.getCurrentUser", - "type": "Function", - "tags": [], - "label": "getCurrentUser", - "description": [], - "signature": [ - "(request: ", - { - "pluginId": "@kbn/core-http-server", - "scope": "common", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-common.KibanaRequest", - "text": "KibanaRequest" - }, - ") => ", - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.AuthenticatedUser", - "text": "AuthenticatedUser" + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesResponse", + "text": "CheckUserProfilesPrivilegesResponse" }, - " | null" + ">" ], - "path": "x-pack/plugins/security/server/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.AuthenticationServiceStart.getCurrentUser.$1", + "id": "def-server.CheckUserProfilesPrivileges.atSpace.$1", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.CheckUserProfilesPrivileges.atSpace.$2", "type": "Object", "tags": [], - "label": "request", + "label": "privileges", "description": [], "signature": [ { - "pluginId": "@kbn/core-http-server", - "scope": "common", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-common.KibanaRequest", - "text": "KibanaRequest" - }, - "" + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckUserProfilesPrivilegesPayload", + "text": "CheckUserProfilesPrivilegesPayload" + } ], - "path": "x-pack/plugins/security/server/authentication/authentication_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false, "isRequired": true } ], - "returnComment": [] + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckUserProfilesPrivilegesPayload", + "type": "Interface", + "tags": [], + "label": "CheckUserProfilesPrivilegesPayload", + "description": [ + "\nPrivileges that can be checked for the users profiles (only Kibana specific privileges are supported at the moment)." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckUserProfilesPrivilegesPayload.kibana", + "type": "Array", + "tags": [], + "label": "kibana", + "description": [ + "\nA list of the Kibana specific privileges (usually generated with `security.authz.actions.*.get(...)`)." + ], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false }, { "parentPluginId": "security", - "id": "def-server.CheckPrivilegesPayload", + "id": "def-server.CheckUserProfilesPrivilegesResponse", "type": "Interface", "tags": [], - "label": "CheckPrivilegesPayload", + "label": "CheckUserProfilesPrivilegesResponse", "description": [ - "\nPrivileges that can be checked for the Kibana users." + "\nResponse of the check privileges operation for the users profiles." ], - "path": "x-pack/plugins/security/server/authorization/types.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.CheckPrivilegesPayload.kibana", - "type": "CompoundType", + "id": "def-server.CheckUserProfilesPrivilegesResponse.hasPrivilegeUids", + "type": "Array", "tags": [], - "label": "kibana", + "label": "hasPrivilegeUids", "description": [ - "\nA list of the Kibana specific privileges (usually generated with `security.authz.actions.*.get(...)`)." + "\nThe subset of the requested profile IDs of the users that have all the requested privileges." ], "signature": [ - "string | string[] | undefined" + "string[]" ], - "path": "x-pack/plugins/security/server/authorization/types.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.CheckPrivilegesPayload.elasticsearch", + "id": "def-server.CheckUserProfilesPrivilegesResponse.errors", "type": "Object", "tags": [], - "label": "elasticsearch", + "label": "errors", "description": [ - "\nA set of the Elasticsearch cluster and index privileges." + "\nAn errors object that may be returned from ES that contains a `count` of UIDs that have errors in the `details` property.\n\nEach entry in `details` will contain an error `type`, e.g 'resource_not_found_exception', and a `reason` message, e.g. 'profile document not found'" ], "signature": [ - "{ cluster: string[]; index: Record; } | undefined" + "{ count: number; details: Record; } | undefined" ], - "path": "x-pack/plugins/security/server/authorization/types.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false } @@ -2349,7 +3780,7 @@ "tags": [], "label": "GrantAPIKeyResult", "description": [], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2362,7 +3793,7 @@ "description": [ "\nUnique id for this API key" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false }, @@ -2375,7 +3806,7 @@ "description": [ "\nName for this API key" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false }, @@ -2388,7 +3819,7 @@ "description": [ "\nGenerated API key" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false } @@ -2404,7 +3835,7 @@ "description": [ "\nThe return value when invalidating an API key in Elasticsearch." ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2420,7 +3851,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false }, @@ -2436,7 +3867,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false }, @@ -2449,23 +3880,308 @@ "description": [ "\nThe number of errors that were encountered when invalidating the API keys." ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.InvalidateAPIKeyResult.error_details", + "type": "Array", + "tags": [], + "label": "error_details", + "description": [ + "\nDetails about these errors. This field is not present in the response when error_count is 0." + ], + "signature": [ + "{ type?: string | undefined; reason?: string | undefined; caused_by?: { type?: string | undefined; reason?: string | undefined; } | undefined; }[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.InvalidateAPIKeysParams", + "type": "Interface", + "tags": [], + "label": "InvalidateAPIKeysParams", + "description": [ + "\nRepresents the params for invalidating multiple API keys" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.InvalidateAPIKeysParams.ids", + "type": "Array", + "tags": [], + "label": "ids", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsRolesByFeatureIdRequest", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest.context", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-deprecations-server", + "scope": "common", + "docId": "kibKbnCoreDeprecationsServerPluginApi", + "section": "def-common.GetDeprecationsContext", + "text": "GetDeprecationsContext" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest.featureId", + "type": "string", + "tags": [], + "label": "featureId", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsRolesByFeatureIdResponse", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse.roles", + "type": "Array", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.Role", + "text": "Role" + }, + "[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.InvalidateAPIKeyResult.error_details", - "type": "Array", + "id": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse.errors", + "type": "Array", + "tags": [], + "label": "errors", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-deprecations-common", + "scope": "common", + "docId": "kibKbnCoreDeprecationsCommonPluginApi", + "section": "def-common.DeprecationsDetails", + "text": "DeprecationsDetails" + }, + "[] | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsService", + "type": "Interface", + "tags": [], + "label": "PrivilegeDeprecationsService", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsService.getKibanaRolesByFeatureId", + "type": "Function", + "tags": [], + "label": "getKibanaRolesByFeatureId", + "description": [], + "signature": [ + "(args: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "text": "PrivilegeDeprecationsRolesByFeatureIdRequest" + }, + ") => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdResponse", + "text": "PrivilegeDeprecationsRolesByFeatureIdResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.PrivilegeDeprecationsService.getKibanaRolesByFeatureId.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.PrivilegeDeprecationsRolesByFeatureIdRequest", + "text": "PrivilegeDeprecationsRolesByFeatureIdRequest" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.SavedObjectActions", + "type": "Interface", + "tags": [], + "label": "SavedObjectActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.SavedObjectActions.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(type: string, operation: string) => string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.SavedObjectActions.get.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.SavedObjectActions.get.$2", + "type": "string", + "tags": [], + "label": "operation", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.SpaceActions", + "type": "Interface", + "tags": [], + "label": "SpaceActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.SpaceActions.manage", + "type": "string", "tags": [], - "label": "error_details", - "description": [ - "\nDetails about these errors. This field is not present in the response when error_count is 0." - ], - "signature": [ - "{ type?: string | undefined; reason?: string | undefined; caused_by?: { type?: string | undefined; reason?: string | undefined; } | undefined; }[] | undefined" - ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "label": "manage", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts", "deprecated": false, "trackAdoption": false } @@ -2474,30 +4190,76 @@ }, { "parentPluginId": "security", - "id": "def-server.InvalidateAPIKeysParams", + "id": "def-server.UIActions", "type": "Interface", "tags": [], - "label": "InvalidateAPIKeysParams", - "description": [ - "\nRepresents the params for invalidating multiple API keys" - ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "label": "UIActions", + "description": [], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-server.InvalidateAPIKeysParams.ids", - "type": "Array", + "id": "def-server.UIActions.get", + "type": "Function", "tags": [], - "label": "ids", + "label": "get", "description": [], "signature": [ - "string[]" + "(featureId: keyof ", + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + }, + ", ...uiCapabilityParts: string[]) => string" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.UIActions.get.$1", + "type": "CompoundType", + "tags": [], + "label": "featureId", + "description": [], + "signature": [ + "keyof ", + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "security", + "id": "def-server.UIActions.get.$2", + "type": "Array", + "tags": [], + "label": "uiCapabilityParts", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false @@ -2511,7 +4273,7 @@ "description": [ "\nParameters for the bulk get API." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2527,7 +4289,7 @@ "signature": [ "Set" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2543,7 +4305,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false } @@ -2559,7 +4321,7 @@ "description": [ "\nParameters for the get user profile for the current user API." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2582,7 +4344,7 @@ }, "" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2598,7 +4360,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false } @@ -2614,7 +4376,7 @@ "description": [ "\nThe set of privileges that users associated with the suggested user profile should have for a specified space id." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2627,7 +4389,7 @@ "description": [ "\nThe id of the Kibana Space." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2643,7 +4405,7 @@ "signature": [ "{ kibana: string[]; }" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false } @@ -2659,7 +4421,7 @@ "description": [ "\nA set of methods to work with Kibana user profiles." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2675,39 +4437,39 @@ "signature": [ "(params: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileGetCurrentParams", "text": "UserProfileGetCurrentParams" }, ") => Promise<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileWithSecurity", "text": "UserProfileWithSecurity" }, " | null>" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2722,14 +4484,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileGetCurrentParams", "text": "UserProfileGetCurrentParams" } ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -2749,31 +4511,31 @@ "signature": [ "(params: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileBulkGetParams", "text": "UserProfileBulkGetParams" }, ") => Promise<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfile", "text": "UserProfile" }, "[]>" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2788,14 +4550,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileBulkGetParams", "text": "UserProfileBulkGetParams" } ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -2815,31 +4577,31 @@ "signature": [ "(params: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileSuggestParams", "text": "UserProfileSuggestParams" }, ") => Promise<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfile", "text": "UserProfile" }, "[]>" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2854,14 +4616,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileSuggestParams", "text": "UserProfileSuggestParams" } ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -2881,7 +4643,7 @@ "description": [ "\nParameters for the suggest API." ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2897,7 +4659,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2913,7 +4675,7 @@ "signature": [ "{ uids: string[]; } | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2929,7 +4691,7 @@ "signature": [ "number | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", "deprecated": false, "trackAdoption": false }, @@ -2945,30 +4707,281 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.UserProfileSuggestParams.requiredPrivileges", + "type": "Object", + "tags": [], + "label": "requiredPrivileges", + "description": [ + "\nThe set of the privileges that users associated with the suggested user profile should have in the specified space.\nIf not specified, privileges check isn't performed and all matched profiles are returned irrespective to the\nprivileges of the associated users." + ], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.UserProfileRequiredPrivileges", + "text": "UserProfileRequiredPrivileges" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.ValidateAPIKeyParams", + "type": "Interface", + "tags": [], + "label": "ValidateAPIKeyParams", + "description": [ + "\nRepresents the parameters for validating API Key credentials." + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-server.ValidateAPIKeyParams.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique id for this API key" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.ValidateAPIKeyParams.api_key", + "type": "string", + "tags": [], + "label": "api_key", + "description": [ + "\nGenerated API Key (secret)" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "security", + "id": "def-server.CasesSupportedOperations", + "type": "Type", + "tags": [], + "label": "CasesSupportedOperations", + "description": [], + "signature": [ + "\"getTags\" | \"pushCase\" | \"createCase\" | \"createComment\" | \"getCase\" | \"getComment\" | \"getReporters\" | \"getUserActions\" | \"findConfigurations\" | \"updateCase\" | \"updateComment\" | \"deleteCase\" | \"deleteComment\" | \"createConfiguration\" | \"updateConfiguration\"" + ], + "path": "x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesDynamically", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesDynamically", + "description": [], + "signature": [ + "(privileges: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + }, + ", options?: ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesDynamically.$1", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesPayload", + "text": "CheckPrivilegesPayload" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesDynamically.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesOptions", + "text": "CheckPrivilegesOptions" + }, + " | undefined" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesDynamicallyWithRequest", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesDynamicallyWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesDynamically", + "text": "CheckPrivilegesDynamically" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesDynamicallyWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts", "deprecated": false, "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.CheckPrivilegesWithRequest", + "type": "Type", + "tags": [], + "label": "CheckPrivilegesWithRequest", + "description": [], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivileges", + "text": "CheckPrivileges" + } + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ { "parentPluginId": "security", - "id": "def-server.UserProfileSuggestParams.requiredPrivileges", + "id": "def-server.CheckPrivilegesWithRequest.$1", "type": "Object", "tags": [], - "label": "requiredPrivileges", - "description": [ - "\nThe set of the privileges that users associated with the suggested user profile should have in the specified space.\nIf not specified, privileges check isn't performed and all matched profiles are returned irrespective to the\nprivileges of the associated users." - ], + "label": "request", + "description": [], "signature": [ { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.UserProfileRequiredPrivileges", - "text": "UserProfileRequiredPrivileges" + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" }, - " | undefined" + "" ], - "path": "x-pack/plugins/security/server/user_profile/user_profile_service.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts", "deprecated": false, "trackAdoption": false } @@ -2977,74 +4990,110 @@ }, { "parentPluginId": "security", - "id": "def-server.ValidateAPIKeyParams", - "type": "Interface", + "id": "def-server.CheckSavedObjectsPrivileges", + "type": "Type", "tags": [], - "label": "ValidateAPIKeyParams", - "description": [ - "\nRepresents the parameters for validating API Key credentials." + "label": "CheckSavedObjectsPrivileges", + "description": [], + "signature": [ + "(actions: string | string[], namespaceOrNamespaces?: string | (string | undefined)[] | undefined) => Promise<", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckPrivilegesResponse", + "text": "CheckPrivilegesResponse" + }, + ">" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", "deprecated": false, "trackAdoption": false, + "returnComment": [], "children": [ { "parentPluginId": "security", - "id": "def-server.ValidateAPIKeyParams.id", - "type": "string", + "id": "def-server.CheckSavedObjectsPrivileges.$1", + "type": "CompoundType", "tags": [], - "label": "id", - "description": [ - "\nUnique id for this API key" + "label": "actions", + "description": [], + "signature": [ + "string | string[]" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "security", - "id": "def-server.ValidateAPIKeyParams.api_key", - "type": "string", + "id": "def-server.CheckSavedObjectsPrivileges.$2", + "type": "CompoundType", "tags": [], - "label": "api_key", - "description": [ - "\nGenerated API Key (secret)" + "label": "namespaceOrNamespaces", + "description": [], + "signature": [ + "string | (string | undefined)[] | undefined" ], - "path": "x-pack/plugins/security/server/authentication/api_keys/api_keys.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", "deprecated": false, "trackAdoption": false } ], "initialIsOpen": false - } - ], - "enums": [], - "misc": [ - { - "parentPluginId": "security", - "id": "def-server.AuthorizationServiceSetup", - "type": "Type", - "tags": [], - "label": "AuthorizationServiceSetup", - "description": [], - "path": "x-pack/plugins/security/server/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false }, { "parentPluginId": "security", - "id": "def-server.CasesSupportedOperations", + "id": "def-server.CheckSavedObjectsPrivilegesWithRequest", "type": "Type", "tags": [], - "label": "CasesSupportedOperations", + "label": "CheckSavedObjectsPrivilegesWithRequest", "description": [], "signature": [ - "\"getTags\" | \"pushCase\" | \"createCase\" | \"createComment\" | \"createConfiguration\" | \"getCase\" | \"getComment\" | \"getReporters\" | \"getUserActions\" | \"findConfigurations\" | \"updateCase\" | \"updateComment\" | \"updateConfiguration\" | \"deleteCase\" | \"deleteComment\"" + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.CheckSavedObjectsPrivileges", + "text": "CheckSavedObjectsPrivileges" + } ], - "path": "x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", "deprecated": false, "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "security", + "id": "def-server.CheckSavedObjectsPrivilegesWithRequest.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], "initialIsOpen": false }, { @@ -3053,13 +5102,11 @@ "type": "Type", "tags": [], "label": "CreateAPIKeyParams", - "description": [ - "\nRequest body of Kibana Create API key endpoint." - ], + "description": [], "signature": [ "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" ], - "path": "x-pack/plugins/security/server/routes/api_keys/create.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3076,7 +5123,7 @@ "signature": [ "SecurityCreateApiKeyResponse" ], - "path": "x-pack/plugins/security/server/routes/api_keys/create.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3091,7 +5138,7 @@ "signature": [ "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" ], - "path": "x-pack/plugins/security/server/routes/api_keys/create.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3106,7 +5153,7 @@ "signature": [ "{ readonly type?: \"rest\" | undefined; readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly name: string; readonly role_descriptors: Record>; }" ], - "path": "x-pack/plugins/security/server/routes/api_keys/create.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3121,7 +5168,37 @@ "signature": [ "{ readonly type?: \"rest\" | undefined; readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly name: string; readonly kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }" ], - "path": "x-pack/plugins/security/server/routes/api_keys/create.ts", + "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.ElasticsearchPrivilegesType", + "type": "Type", + "tags": [], + "label": "ElasticsearchPrivilegesType", + "description": [], + "signature": [ + "{ readonly cluster?: string[] | undefined; readonly indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; readonly remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; readonly run_as?: string[] | undefined; }" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-server.KibanaPrivilegesType", + "type": "Type", + "tags": [], + "label": "KibanaPrivilegesType", + "description": [], + "signature": [ + "Readonly<{ base?: string[] | undefined; feature?: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]" + ], + "path": "x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3154,6 +5231,23 @@ "description": [ "\nDescribes public Security plugin contract returned at the `setup` stage." ], + "signature": [ + { + "pluginId": "security", + "scope": "server", + "docId": "kibSecurityPluginApi", + "section": "def-server.SecurityPluginSetup", + "text": "SecurityPluginSetup" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SecurityPluginSetup", + "text": "SecurityPluginSetup" + } + ], "path": "x-pack/plugins/security/server/plugin.ts", "deprecated": false, "trackAdoption": false, @@ -3178,9 +5272,9 @@ }, ") => ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, @@ -3259,9 +5353,9 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.AuthorizationServiceSetup", "text": "AuthorizationServiceSetup" } @@ -3307,72 +5401,6 @@ "path": "x-pack/plugins/enterprise_search/server/lib/check_access.ts" } ] - }, - { - "parentPluginId": "security", - "id": "def-server.SecurityPluginSetup.license", - "type": "Object", - "tags": [], - "label": "license", - "description": [ - "\nExposes information about the available security features under the current license." - ], - "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.SecurityLicense", - "text": "SecurityLicense" - } - ], - "path": "x-pack/plugins/security/server/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.SecurityPluginSetup.audit", - "type": "Object", - "tags": [], - "label": "audit", - "description": [ - "\nExposes services for audit logging." - ], - "signature": [ - { - "pluginId": "security", - "scope": "server", - "docId": "kibSecurityPluginApi", - "section": "def-server.AuditServiceSetup", - "text": "AuditServiceSetup" - } - ], - "path": "x-pack/plugins/security/server/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.SecurityPluginSetup.privilegeDeprecationsService", - "type": "Object", - "tags": [], - "label": "privilegeDeprecationsService", - "description": [ - "\nExposes services to access kibana roles per feature id with the GetDeprecationsContext" - ], - "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.PrivilegeDeprecationsService", - "text": "PrivilegeDeprecationsService" - } - ], - "path": "x-pack/plugins/security/server/plugin.ts", - "deprecated": false, - "trackAdoption": false } ], "lifecycle": "setup", @@ -3387,7 +5415,7 @@ "description": [ "\nDescribes public Security plugin contract returned at the `start` stage." ], - "path": "x-pack/plugins/security/server/plugin.ts", + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3402,14 +5430,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.AuthenticationServiceStart", "text": "AuthenticationServiceStart" } ], - "path": "x-pack/plugins/security/server/plugin.ts", + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", "deprecated": false, "trackAdoption": false }, @@ -3424,14 +5452,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.AuthorizationServiceSetup", "text": "AuthorizationServiceSetup" } ], - "path": "x-pack/plugins/security/server/plugin.ts", + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", "deprecated": false, "trackAdoption": false }, @@ -3446,14 +5474,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-server", "scope": "server", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", "section": "def-server.UserProfileServiceStart", "text": "UserProfileServiceStart" } ], - "path": "x-pack/plugins/security/server/plugin.ts", + "path": "x-pack/packages/security/plugin_types_server/src/plugin.ts", "deprecated": false, "trackAdoption": false } @@ -3467,47 +5495,100 @@ "functions": [ { "parentPluginId": "security", - "id": "def-common.getUserDisplayName", + "id": "def-common.getUserDisplayName", + "type": "Function", + "tags": [], + "label": "getUserDisplayName", + "description": [ + "\nDetermines the display name for the provided user information." + ], + "signature": [ + "(params: ", + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.GetUserDisplayNameParams", + "text": "GetUserDisplayNameParams" + }, + ") => string" + ], + "path": "x-pack/plugins/security/common/model/user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.getUserDisplayName.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [ + "Set of available user's name-related fields." + ], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.GetUserDisplayNameParams", + "text": "GetUserDisplayNameParams" + } + ], + "path": "x-pack/plugins/security/common/model/user.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.isRoleReserved", "type": "Function", "tags": [], - "label": "getUserDisplayName", + "label": "isRoleReserved", "description": [ - "\nDetermines the display name for the provided user information." + "\nReturns whether given role is reserved or not.\n" ], "signature": [ - "(params: ", + "(role: Partial<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.GetUserDisplayNameParams", - "text": "GetUserDisplayNameParams" + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.Role", + "text": "Role" }, - ") => string" + ">) => boolean" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/plugins/security/common/model/role.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "security", - "id": "def-common.getUserDisplayName.$1", + "id": "def-common.isRoleReserved.$1", "type": "Object", "tags": [], - "label": "params", + "label": "role", "description": [ - "Set of available user's name-related fields." + "Role as returned by roles API" ], "signature": [ + "Partial<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.GetUserDisplayNameParams", - "text": "GetUserDisplayNameParams" - } + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.Role", + "text": "Role" + }, + ">" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/plugins/security/common/model/role.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -3529,22 +5610,22 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticatedUser", "text": "AuthenticatedUser" }, " extends ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.User", "text": "User" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3559,14 +5640,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserRealm", "text": "UserRealm" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -3581,14 +5662,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserRealm", "text": "UserRealm" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -3603,14 +5684,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.AuthenticationProvider", "text": "AuthenticationProvider" } ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -3623,7 +5704,7 @@ "description": [ "\nThe AuthenticationType used by ES to authenticate the user.\n" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -3636,7 +5717,7 @@ "description": [ "\nIndicates whether user is authenticated via Elastic Cloud built-in SAML realm." ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -3652,7 +5733,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false } @@ -3668,7 +5749,7 @@ "description": [ "\nType and name tuple to identify provider used to authenticate user." ], - "path": "x-pack/plugins/security/common/model/authentication_provider.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3681,7 +5762,7 @@ "description": [ "\nType of the Kibana authentication provider." ], - "path": "x-pack/plugins/security/common/model/authentication_provider.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", "deprecated": false, "trackAdoption": false }, @@ -3694,7 +5775,108 @@ "description": [ "\nName of the Kibana authentication provider (arbitrary string)." ], - "path": "x-pack/plugins/security/common/model/authentication_provider.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.BuiltinESPrivileges", + "type": "Interface", + "tags": [], + "label": "BuiltinESPrivileges", + "description": [], + "path": "x-pack/plugins/security/common/model/builtin_es_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.BuiltinESPrivileges.cluster", + "type": "Array", + "tags": [], + "label": "cluster", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/security/common/model/builtin_es_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.BuiltinESPrivileges.index", + "type": "Array", + "tags": [], + "label": "index", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/security/common/model/builtin_es_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.EditUser", + "type": "Interface", + "tags": [], + "label": "EditUser", + "description": [], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.EditUser", + "text": "EditUser" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.User", + "text": "User" + } + ], + "path": "x-pack/plugins/security/common/model/user.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.EditUser.password", + "type": "string", + "tags": [], + "label": "password", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/common/model/user.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.EditUser.confirmPassword", + "type": "string", + "tags": [], + "label": "confirmPassword", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/common/model/user.ts", "deprecated": false, "trackAdoption": false } @@ -3708,7 +5890,7 @@ "tags": [], "label": "FeaturesPrivileges", "description": [], - "path": "x-pack/plugins/security/common/model/features_privileges.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3722,7 +5904,7 @@ "signature": [ "[featureId: string]: string[]" ], - "path": "x-pack/plugins/security/common/model/features_privileges.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts", "deprecated": false, "trackAdoption": false } @@ -3809,17 +5991,17 @@ }, " extends ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileWithSecurity", "text": "UserProfileWithSecurity" }, " Promise<", - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.PrivilegeDeprecationsRolesByFeatureIdResponse", - "text": "PrivilegeDeprecationsRolesByFeatureIdResponse" - }, - ">" + "{ [x: string]: string[]; }" ], - "path": "x-pack/plugins/security/common/model/deprecations.ts", + "path": "x-pack/plugins/security/common/model/raw_kibana_privileges.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "security", - "id": "def-common.PrivilegeDeprecationsService.getKibanaRolesByFeatureId.$1", - "type": "Object", - "tags": [], - "label": "args", - "description": [], - "signature": [ - { - "pluginId": "security", - "scope": "common", - "docId": "kibSecurityPluginApi", - "section": "def-common.PrivilegeDeprecationsRolesByFeatureIdRequest", - "text": "PrivilegeDeprecationsRolesByFeatureIdRequest" - } - ], - "path": "x-pack/plugins/security/common/model/deprecations.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RawKibanaPrivileges.features", + "type": "Object", + "tags": [], + "label": "features", + "description": [], + "signature": [ + "RawKibanaFeaturePrivileges" + ], + "path": "x-pack/plugins/security/common/model/raw_kibana_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RawKibanaPrivileges.space", + "type": "Object", + "tags": [], + "label": "space", + "description": [], + "signature": [ + "{ [x: string]: string[]; }" + ], + "path": "x-pack/plugins/security/common/model/raw_kibana_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RawKibanaPrivileges.reserved", + "type": "Object", + "tags": [], + "label": "reserved", + "description": [], + "signature": [ + "{ [x: string]: string[]; }" + ], + "path": "x-pack/plugins/security/common/model/raw_kibana_privileges.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.RestApiKey", + "type": "Interface", + "tags": [], + "label": "RestApiKey", + "description": [ + "\nInterface representing a REST API key the way it is returned by Elasticsearch GET endpoint.\n\nTODO: Remove this type when `@elastic/elasticsearch` has been updated." + ], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.RestApiKey", + "text": "RestApiKey" + }, + " extends BaseApiKey" + ], + "path": "x-pack/plugins/security/common/model/api_key.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.RestApiKey.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "\"rest\"" ], - "returnComment": [] + "path": "x-pack/plugins/security/common/model/api_key.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4039,7 +6243,7 @@ "tags": [], "label": "Role", "description": [], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4050,7 +6254,7 @@ "tags": [], "label": "name", "description": [], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4064,17 +6268,23 @@ "signature": [ "{ cluster: string[]; indices: ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.RoleIndexPrivilege", "text": "RoleIndexPrivilege" }, "[]; remote_indices?: ", - "RoleRemoteIndexPrivilege", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleRemoteIndexPrivilege", + "text": "RoleRemoteIndexPrivilege" + }, "[] | undefined; run_as: string[]; }" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4087,15 +6297,15 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.RoleKibanaPrivilege", "text": "RoleKibanaPrivilege" }, "[]" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4109,7 +6319,7 @@ "signature": [ "{ [anyKey: string]: any; } | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4123,7 +6333,7 @@ "signature": [ "{ [anyKey: string]: any; } | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4137,7 +6347,7 @@ "signature": [ "string[] | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4151,7 +6361,7 @@ "signature": [ "string[] | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false } @@ -4165,7 +6375,7 @@ "tags": [], "label": "RoleIndexPrivilege", "description": [], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4179,7 +6389,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4193,7 +6403,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4207,7 +6417,7 @@ "signature": [ "{ grant?: string[] | undefined; except?: string[] | undefined; } | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4221,7 +6431,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false } @@ -4235,7 +6445,7 @@ "tags": [], "label": "RoleKibanaPrivilege", "description": [], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4249,7 +6459,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4263,7 +6473,7 @@ "signature": [ "string[]" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4276,14 +6486,14 @@ "description": [], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.FeaturesPrivileges", "text": "FeaturesPrivileges" } ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false }, @@ -4297,7 +6507,151 @@ "signature": [ "string[] | undefined" ], - "path": "x-pack/plugins/security/common/model/role.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping", + "type": "Interface", + "tags": [], + "label": "RoleMapping", + "description": [], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.roles", + "type": "Array", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.role_templates", + "type": "Array", + "tags": [], + "label": "role_templates", + "description": [], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.RoleTemplate", + "text": "RoleTemplate" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.rules", + "type": "CompoundType", + "tags": [], + "label": "rules", + "description": [], + "signature": [ + "{} | RoleMappingRule" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleMapping.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [], + "signature": [ + "{ [x: string]: any; }" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleRemoteIndexPrivilege", + "type": "Interface", + "tags": [], + "label": "RoleRemoteIndexPrivilege", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleRemoteIndexPrivilege", + "text": "RoleRemoteIndexPrivilege" + }, + " extends ", + { + "pluginId": "@kbn/security-plugin-types-common", + "scope": "common", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", + "section": "def-common.RoleIndexPrivilege", + "text": "RoleIndexPrivilege" + } + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.RoleRemoteIndexPrivilege.clusters", + "type": "Array", + "tags": [], + "label": "clusters", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/packages/security/plugin_types_common/src/authorization/role.ts", "deprecated": false, "trackAdoption": false } @@ -4311,7 +6665,7 @@ "tags": [], "label": "SecurityLicense", "description": [], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4325,7 +6679,7 @@ "signature": [ "() => boolean" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -4341,7 +6695,7 @@ "signature": [ "() => boolean" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -4357,14 +6711,14 @@ "signature": [ "() => ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.SecurityLicenseFeatures", "text": "SecurityLicenseFeatures" } ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -4380,7 +6734,7 @@ "signature": [ "(licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4394,7 +6748,7 @@ "signature": [ "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -4413,15 +6767,15 @@ "Observable", "<", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.SecurityLicenseFeatures", "text": "SecurityLicenseFeatures" }, ">" ], - "path": "x-pack/plugins/security/common/licensing/license_service.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license.ts", "deprecated": false, "trackAdoption": false } @@ -4437,7 +6791,7 @@ "description": [ "\nDescribes Security plugin features that depend on license." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4450,7 +6804,7 @@ "description": [ "\nIndicates whether we show login page or skip it." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4463,7 +6817,7 @@ "description": [ "\nIndicates whether we allow login or disable it on the login page." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4476,7 +6830,7 @@ "description": [ "\nIndicates whether we show security links throughout the kibana app." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4489,7 +6843,7 @@ "description": [ "\nIndicates whether we show the Role Mappings UI." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4502,7 +6856,7 @@ "description": [ "\nIndicates whether we allow users to access agreement UI and acknowledge it." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4515,7 +6869,7 @@ "description": [ "\nIndicates whether we allow logging of audit events." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4528,7 +6882,7 @@ "description": [ "\nIndicates whether we allow users to define document level security in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4541,7 +6895,7 @@ "description": [ "\nIndicates whether we allow users to define field level security in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4554,7 +6908,7 @@ "description": [ "\nIndicates whether we allow users to define remote index privileges in roles." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4567,7 +6921,7 @@ "description": [ "\nIndicates whether we allow Role-based access control (RBAC)." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4580,7 +6934,7 @@ "description": [ "\nIndicates whether we allow sub-feature privileges." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4593,7 +6947,7 @@ "description": [ "\nIndicates whether we allow user profile collaboration features (suggest and privileges checks APIs)." ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", "deprecated": false, "trackAdoption": false }, @@ -4608,15 +6962,57 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.LoginLayout", "text": "LoginLayout" }, " | undefined" ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.StoredRoleTemplate", + "type": "Interface", + "tags": [], + "label": "StoredRoleTemplate", + "description": [], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "security", + "id": "def-common.StoredRoleTemplate.template", + "type": "Object", + "tags": [], + "label": "template", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.StoredRoleTemplate.format", + "type": "CompoundType", + "tags": [], + "label": "format", + "description": [], + "signature": [ + "RoleTemplateFormat | undefined" + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", "deprecated": false, "trackAdoption": false } @@ -4632,7 +7028,7 @@ "description": [ "\nA set of fields describing Kibana user." ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4643,7 +7039,7 @@ "tags": [], "label": "username", "description": [], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false }, @@ -4657,7 +7053,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false }, @@ -4671,7 +7067,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false }, @@ -4685,7 +7081,7 @@ "signature": [ "readonly string[]" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false }, @@ -4696,7 +7092,7 @@ "tags": [], "label": "enabled", "description": [], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false }, @@ -4710,7 +7106,7 @@ "signature": [ "{ _reserved: boolean; _deprecated?: boolean | undefined; _deprecated_reason?: string | undefined; } | undefined" ], - "path": "x-pack/plugins/security/common/model/user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/user.ts", "deprecated": false, "trackAdoption": false } @@ -4728,15 +7124,15 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfile", "text": "UserProfile" }, "" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4749,7 +7145,7 @@ "description": [ "\nUnique ID for of the user profile." ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4762,7 +7158,7 @@ "description": [ "\nIndicates whether user profile is enabled or not." ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4777,14 +7173,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileUserInfo", "text": "UserProfileUserInfo" } ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4800,7 +7196,7 @@ "signature": [ "{ [P in keyof D]?: D[P] | undefined; }" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false } @@ -4816,7 +7212,7 @@ "description": [ "\nBasic user information returned in user profile." ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4829,7 +7225,7 @@ "description": [ "\nUsername of the user." ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4845,7 +7241,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4861,7 +7257,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false } @@ -4879,22 +7275,22 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileUserInfoWithSecurity", "text": "UserProfileUserInfoWithSecurity" }, " extends ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileUserInfo", "text": "UserProfileUserInfo" } ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4910,7 +7306,7 @@ "signature": [ "readonly string[]" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4923,7 +7319,7 @@ "description": [ "\nName of the Elasticsearch security realm that was used to authenticate user." ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -4939,7 +7335,7 @@ "signature": [ "string | undefined" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false } @@ -4957,23 +7353,23 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileWithSecurity", "text": "UserProfileWithSecurity" }, " extends ", { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfile", "text": "UserProfile" }, "" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -4988,14 +7384,14 @@ ], "signature": [ { - "pluginId": "security", + "pluginId": "@kbn/security-plugin-types-common", "scope": "common", - "docId": "kibSecurityPluginApi", + "docId": "kibKbnSecurityPluginTypesCommonPluginApi", "section": "def-common.UserProfileUserInfoWithSecurity", "text": "UserProfileUserInfoWithSecurity" } ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false }, @@ -5011,7 +7407,7 @@ "signature": [ "L" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false } @@ -5027,7 +7423,7 @@ "description": [ "\nAn Elasticsearch realm that was used to resolve and authenticate the user." ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -5040,7 +7436,7 @@ "description": [ "\nArbitrary name of the security realm." ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false }, @@ -5053,7 +7449,7 @@ "description": [ "\nType of the security realm (file, native, saml etc.)." ], - "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "path": "x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts", "deprecated": false, "trackAdoption": false } @@ -5073,7 +7469,13 @@ "\nInterface representing an API key the way it is returned by Elasticsearch GET endpoint." ], "signature": [ - "RestApiKey", + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.RestApiKey", + "text": "RestApiKey" + }, " | ", "CrossClusterApiKey" ], @@ -5094,7 +7496,44 @@ "signature": [ "\"form\" | \"error-es-unavailable\" | \"error-xpack-unavailable\"" ], - "path": "x-pack/plugins/security/common/licensing/license_features.ts", + "path": "x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "security", + "id": "def-common.RoleTemplate", + "type": "Type", + "tags": [], + "label": "RoleTemplate", + "description": [], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.InlineRoleTemplate", + "text": "InlineRoleTemplate" + }, + " | ", + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.StoredRoleTemplate", + "text": "StoredRoleTemplate" + }, + " | ", + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.InvalidRoleTemplate", + "text": "InvalidRoleTemplate" + } + ], + "path": "x-pack/plugins/security/common/model/role_mapping.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -5111,7 +7550,7 @@ "signature": [ "{ [x: string]: unknown; }" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -5128,7 +7567,7 @@ "signature": [ "{ [x: string]: string; }" ], - "path": "x-pack/plugins/security/common/model/user_profile.ts", + "path": "x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/security.mdx b/api_docs/security.mdx index febe88375ef3..51917c8afdbe 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 270 | 0 | 87 | 3 | +| 401 | 0 | 196 | 2 | ## Client diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 391640559497..f1940d505763 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -114,7 +114,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/plugin.tsx", "deprecated": false, @@ -507,7 +507,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | undefined" + "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -587,7 +587,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | undefined" + "\"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"assistantModelEvaluation\" | \"newUserDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1746,6 +1746,27 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "securitySolution", + "id": "def-public.TimelineModel.savedSearch", + "type": "CompoundType", + "tags": [], + "label": "savedSearch", + "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "common", + "docId": "kibSavedSearchPluginApi", + "section": "def-common.SavedSearch", + "text": "SavedSearch" + }, + " | null" + ], + "path": "x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "securitySolution", "id": "def-public.TimelineModel.isDiscoverSavedSearchLoaded", @@ -1760,6 +1781,17 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "securitySolution", + "id": "def-public.TimelineModel.isDataProviderVisible", + "type": "boolean", + "tags": [], + "label": "isDataProviderVisible", + "description": [], + "path": "x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "securitySolution", "id": "def-public.TimelineModel.changed", @@ -1820,7 +1852,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -1972,9 +2004,7 @@ "label": "setComponents", "description": [], "signature": [ - "(components: Partial>>) => void" + "(components: Partial<{ GetStarted: React.ComponentType<{}>; DashboardsLandingCallout: React.ComponentType<{}>; }>) => void" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -1989,7 +2019,7 @@ "label": "components", "description": [], "signature": [ - "{ getStarted?: React.ComponentType<{}> | undefined; dashboardsLandingCallout?: React.ComponentType<{}> | undefined; }" + "{ GetStarted?: React.ComponentType<{}> | undefined; DashboardsLandingCallout?: React.ComponentType<{}> | undefined; }" ], "path": "x-pack/plugins/security_solution/public/contract_components.ts", "deprecated": false, @@ -2803,6 +2833,40 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-server.SecuritySolutionApiRequestHandlerContext.getRiskScoreDataClient", + "type": "Function", + "tags": [], + "label": "getRiskScoreDataClient", + "description": [], + "signature": [ + "() => ", + "RiskScoreDataClient" + ], + "path": "x-pack/plugins/security_solution/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-server.SecuritySolutionApiRequestHandlerContext.getAssetCriticalityDataClient", + "type": "Function", + "tags": [], + "label": "getAssetCriticalityDataClient", + "description": [], + "signature": [ + "() => ", + "AssetCriticalityDataClient" + ], + "path": "x-pack/plugins/security_solution/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false @@ -2818,7 +2882,7 @@ "label": "ConfigType", "description": [], "signature": [ - "Omit; }>, \"offeringSettings\"> & { experimentalFeatures: ", + "Omit; }>, \"offeringSettings\"> & { experimentalFeatures: ", { "pluginId": "securitySolution", "scope": "common", @@ -2828,7 +2892,7 @@ }, "; settings: ", "ConfigSettings", - "; }" + "; enableUiSettingsValidations: boolean; }" ], "path": "x-pack/plugins/security_solution/server/config.ts", "deprecated": false, @@ -2893,7 +2957,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3039,7 +3103,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3088,7 +3152,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index bc3ffdf38091..4b87aa97a8f4 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 175 | 0 | 106 | 35 | +| 179 | 0 | 110 | 36 | ## Client diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index b58dafce91a1..608f46ae7c4e 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index cf9ec5b91aab..5403e6c7393f 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index fe1cd09d3cf8..865fc1b6d110 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 0ae7995397c1..c128063c134d 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index fe91d628cb1a..a24121171860 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index ac01cb776457..ddee464eeaeb 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 49683b402acb..e4a5411cd5ff 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 324c3f8ade86..7bbd97384c68 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 948e23e6a61b..51558790e3a8 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 7207b47ea96d..36fca1fd3e92 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 80b732da8644..65f96d06fafe 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 602903ef9f6c..5e91a3a350d8 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 55899b0789d2..306709d7859d 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 48423b3cd511..94997b06461b 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 91c2294ff166..0d4223d4c5c1 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index e4514a6fffd5..0069a4f1abdd 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.devdocs.json b/api_docs/text_based_languages.devdocs.json index c44e1664a3fe..bfbd1ef629c7 100644 --- a/api_docs/text_based_languages.devdocs.json +++ b/api_docs/text_based_languages.devdocs.json @@ -69,7 +69,9 @@ "type": "CompoundType", "tags": [], "label": "query", - "description": [], + "description": [ + "The aggregate type query" + ], "signature": [ "{ sql: string; } | { esql: string; }" ], @@ -83,7 +85,9 @@ "type": "Function", "tags": [], "label": "onTextLangQueryChange", - "description": [], + "description": [ + "Callback running everytime the query changes" + ], "signature": [ "(query: ", { @@ -129,14 +133,47 @@ "type": "Function", "tags": [], "label": "onTextLangQuerySubmit", - "description": [], + "description": [ + "Callback running when the user submits the query" + ], "signature": [ - "() => void" + "(query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined) => void" ], "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "textBasedLanguages", + "id": "def-public.TextBasedLanguagesEditorProps.onTextLangQuerySubmit.$1", + "type": "CompoundType", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], "returnComment": [] }, { @@ -145,7 +182,9 @@ "type": "Function", "tags": [], "label": "expandCodeEditor", - "description": [], + "description": [ + "Can be used to expand/minimize the editor" + ], "signature": [ "(status: boolean) => void" ], @@ -177,7 +216,9 @@ "type": "boolean", "tags": [], "label": "isCodeEditorExpanded", - "description": [], + "description": [ + "If it is true, the editor initializes with height EDITOR_INITIAL_HEIGHT_EXPANDED" + ], "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false @@ -188,7 +229,9 @@ "type": "CompoundType", "tags": [], "label": "detectTimestamp", - "description": [], + "description": [ + "If it is true, the editor displays the message @timestamp found\nThe text based queries are relying on adhoc dataviews which\ncan have an @timestamp timefield or nothing" + ], "signature": [ "boolean | undefined" ], @@ -202,7 +245,9 @@ "type": "Array", "tags": [], "label": "errors", - "description": [], + "description": [ + "Array of errors" + ], "signature": [ "Error[] | undefined" ], @@ -216,7 +261,9 @@ "type": "string", "tags": [], "label": "warning", - "description": [], + "description": [ + "Warning string as it comes from ES" + ], "signature": [ "string | undefined" ], @@ -230,7 +277,9 @@ "type": "CompoundType", "tags": [], "label": "isDisabled", - "description": [], + "description": [ + "Disables the editor" + ], "signature": [ "boolean | undefined" ], @@ -244,7 +293,9 @@ "type": "CompoundType", "tags": [], "label": "isDarkMode", - "description": [], + "description": [ + "Indicator if the editor is on dark mode" + ], "signature": [ "boolean | undefined" ], @@ -272,7 +323,9 @@ "type": "CompoundType", "tags": [], "label": "hideMinimizeButton", - "description": [], + "description": [ + "If true it hides the minimize button and the user can't return to the minimized version\nUseful when the application doesn't want to give this capability" + ], "signature": [ "boolean | undefined" ], @@ -286,7 +339,41 @@ "type": "CompoundType", "tags": [], "label": "hideRunQueryText", - "description": [], + "description": [ + "Hide the Run query information which appears on the footer" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "textBasedLanguages", + "id": "def-public.TextBasedLanguagesEditorProps.editorIsInline", + "type": "CompoundType", + "tags": [], + "label": "editorIsInline", + "description": [ + "This is used for applications (such as the inline editing flyout in dashboards)\nwhich want to add the editor without being part of the Unified search component\nIt renders a submit query button inside the editor" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "textBasedLanguages", + "id": "def-public.TextBasedLanguagesEditorProps.disableSubmitAction", + "type": "CompoundType", + "tags": [], + "label": "disableSubmitAction", + "description": [ + "Disables the submit query action" + ], "signature": [ "boolean | undefined" ], diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 80ea2fd4442f..1e7446d9197f 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 20 | 0 | 20 | 0 | +| 23 | 0 | 9 | 0 | ## Client diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 4d11d75097c8..b1882af7b3b3 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 7708843c1ad3..095c597217be 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 1f9ef01d6f13..29f6f2a5599c 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index a21b1f53aa70..a7e724324a49 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -2387,6 +2387,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.ActionParamsProps.selectedActionGroupId", + "type": "string", + "tags": [], + "label": "selectedActionGroupId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "triggersActionsUi", "id": "def-public.ActionParamsProps.showEmailSubjectAndMessage", @@ -2993,7 +3007,7 @@ "description": [], "signature": [ "BasicFields", - " & { \"@timestamp\"?: string[] | undefined; \"event.action\"?: string[] | undefined; tags?: string[] | undefined; kibana?: string[] | undefined; \"kibana.alert.rule.rule_type_id\"?: string[] | undefined; \"kibana.alert.rule.consumer\"?: string[] | undefined; \"kibana.alert.rule.execution.uuid\"?: string[] | undefined; \"kibana.alert.instance.id\"?: string[] | undefined; \"kibana.alert.rule.category\"?: string[] | undefined; \"kibana.alert.rule.name\"?: string[] | undefined; \"kibana.alert.rule.producer\"?: string[] | undefined; \"kibana.alert.rule.uuid\"?: string[] | undefined; \"kibana.alert.status\"?: string[] | undefined; \"kibana.alert.uuid\"?: string[] | undefined; \"kibana.space_ids\"?: string[] | undefined; \"event.kind\"?: string[] | undefined; \"kibana.alert.action_group\"?: string[] | undefined; \"kibana.alert.case_ids\"?: string[] | undefined; \"kibana.alert.duration.us\"?: string[] | undefined; \"kibana.alert.end\"?: string[] | undefined; \"kibana.alert.flapping\"?: string[] | undefined; \"kibana.alert.maintenance_window_ids\"?: string[] | undefined; \"kibana.alert.reason\"?: string[] | undefined; \"kibana.alert.rule.parameters\"?: string[] | undefined; \"kibana.alert.rule.tags\"?: string[] | undefined; \"kibana.alert.start\"?: string[] | undefined; \"kibana.alert.time_range\"?: string[] | undefined; \"kibana.alert.workflow_status\"?: string[] | undefined; \"kibana.alert.workflow_tags\"?: string[] | undefined; \"kibana.version\"?: string[] | undefined; \"kibana.alert.context\"?: string[] | undefined; \"kibana.alert.evaluation.threshold\"?: string[] | undefined; \"kibana.alert.evaluation.value\"?: string[] | undefined; \"kibana.alert.evaluation.values\"?: string[] | undefined; \"kibana.alert.group\"?: string[] | undefined; \"ecs.version\"?: string[] | undefined; \"kibana.alert.risk_score\"?: string[] | undefined; \"kibana.alert.rule.author\"?: string[] | undefined; \"kibana.alert.rule.created_at\"?: string[] | undefined; \"kibana.alert.rule.created_by\"?: string[] | undefined; \"kibana.alert.rule.description\"?: string[] | undefined; \"kibana.alert.rule.enabled\"?: string[] | undefined; \"kibana.alert.rule.from\"?: string[] | undefined; \"kibana.alert.rule.interval\"?: string[] | undefined; \"kibana.alert.rule.license\"?: string[] | undefined; \"kibana.alert.rule.note\"?: string[] | undefined; \"kibana.alert.rule.references\"?: string[] | undefined; \"kibana.alert.rule.rule_id\"?: string[] | undefined; \"kibana.alert.rule.rule_name_override\"?: string[] | undefined; \"kibana.alert.rule.to\"?: string[] | undefined; \"kibana.alert.rule.type\"?: string[] | undefined; \"kibana.alert.rule.updated_at\"?: string[] | undefined; \"kibana.alert.rule.updated_by\"?: string[] | undefined; \"kibana.alert.rule.version\"?: string[] | undefined; \"kibana.alert.severity\"?: string[] | undefined; \"kibana.alert.suppression.docs_count\"?: string[] | undefined; \"kibana.alert.suppression.end\"?: string[] | undefined; \"kibana.alert.suppression.start\"?: string[] | undefined; \"kibana.alert.suppression.terms.field\"?: string[] | undefined; \"kibana.alert.suppression.terms.value\"?: string[] | undefined; \"kibana.alert.system_status\"?: string[] | undefined; \"kibana.alert.workflow_reason\"?: string[] | undefined; \"kibana.alert.workflow_user\"?: string[] | undefined; \"event.module\"?: string[] | undefined; \"kibana.alert.rule.threat.framework\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.id\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.name\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.reference\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.id\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.name\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.reference\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.id\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.name\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.reference\"?: string[] | undefined; \"kibana.alert.building_block_type\"?: string[] | undefined; \"kibana.alert\"?: string[] | undefined; \"kibana.alert.rule\"?: string[] | undefined; \"kibana.alert.suppression.terms\"?: string[] | undefined; \"kibana.alert.group.field\"?: string[] | undefined; \"kibana.alert.group.value\"?: string[] | undefined; \"kibana.alert.rule.exceptions_list\"?: string[] | undefined; \"kibana.alert.rule.namespace\"?: string[] | undefined; } & { [x: string]: unknown[]; }" + " & { \"@timestamp\"?: string[] | undefined; \"event.action\"?: string[] | undefined; tags?: string[] | undefined; kibana?: string[] | undefined; \"kibana.alert.rule.rule_type_id\"?: string[] | undefined; \"kibana.alert.rule.consumer\"?: string[] | undefined; \"kibana.alert.rule.execution.uuid\"?: string[] | undefined; \"kibana.alert.instance.id\"?: string[] | undefined; \"kibana.alert.rule.category\"?: string[] | undefined; \"kibana.alert.rule.name\"?: string[] | undefined; \"kibana.alert.rule.producer\"?: string[] | undefined; \"kibana.alert.rule.uuid\"?: string[] | undefined; \"kibana.alert.status\"?: string[] | undefined; \"kibana.alert.uuid\"?: string[] | undefined; \"kibana.space_ids\"?: string[] | undefined; \"event.kind\"?: string[] | undefined; \"kibana.alert.action_group\"?: string[] | undefined; \"kibana.alert.case_ids\"?: string[] | undefined; \"kibana.alert.duration.us\"?: string[] | undefined; \"kibana.alert.end\"?: string[] | undefined; \"kibana.alert.flapping\"?: string[] | undefined; \"kibana.alert.maintenance_window_ids\"?: string[] | undefined; \"kibana.alert.reason\"?: string[] | undefined; \"kibana.alert.rule.parameters\"?: string[] | undefined; \"kibana.alert.rule.tags\"?: string[] | undefined; \"kibana.alert.start\"?: string[] | undefined; \"kibana.alert.time_range\"?: string[] | undefined; \"kibana.alert.workflow_assignee_ids\"?: string[] | undefined; \"kibana.alert.workflow_status\"?: string[] | undefined; \"kibana.alert.workflow_tags\"?: string[] | undefined; \"kibana.version\"?: string[] | undefined; \"kibana.alert.context\"?: string[] | undefined; \"kibana.alert.evaluation.threshold\"?: string[] | undefined; \"kibana.alert.evaluation.value\"?: string[] | undefined; \"kibana.alert.evaluation.values\"?: string[] | undefined; \"kibana.alert.group\"?: string[] | undefined; \"ecs.version\"?: string[] | undefined; \"kibana.alert.risk_score\"?: string[] | undefined; \"kibana.alert.rule.author\"?: string[] | undefined; \"kibana.alert.rule.created_at\"?: string[] | undefined; \"kibana.alert.rule.created_by\"?: string[] | undefined; \"kibana.alert.rule.description\"?: string[] | undefined; \"kibana.alert.rule.enabled\"?: string[] | undefined; \"kibana.alert.rule.from\"?: string[] | undefined; \"kibana.alert.rule.interval\"?: string[] | undefined; \"kibana.alert.rule.license\"?: string[] | undefined; \"kibana.alert.rule.note\"?: string[] | undefined; \"kibana.alert.rule.references\"?: string[] | undefined; \"kibana.alert.rule.rule_id\"?: string[] | undefined; \"kibana.alert.rule.rule_name_override\"?: string[] | undefined; \"kibana.alert.rule.to\"?: string[] | undefined; \"kibana.alert.rule.type\"?: string[] | undefined; \"kibana.alert.rule.updated_at\"?: string[] | undefined; \"kibana.alert.rule.updated_by\"?: string[] | undefined; \"kibana.alert.rule.version\"?: string[] | undefined; \"kibana.alert.severity\"?: string[] | undefined; \"kibana.alert.suppression.docs_count\"?: string[] | undefined; \"kibana.alert.suppression.end\"?: string[] | undefined; \"kibana.alert.suppression.start\"?: string[] | undefined; \"kibana.alert.suppression.terms.field\"?: string[] | undefined; \"kibana.alert.suppression.terms.value\"?: string[] | undefined; \"kibana.alert.system_status\"?: string[] | undefined; \"kibana.alert.workflow_reason\"?: string[] | undefined; \"kibana.alert.workflow_user\"?: string[] | undefined; \"event.module\"?: string[] | undefined; \"kibana.alert.rule.threat.framework\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.id\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.name\"?: string[] | undefined; \"kibana.alert.rule.threat.tactic.reference\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.id\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.name\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.reference\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.id\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.name\"?: string[] | undefined; \"kibana.alert.rule.threat.technique.subtechnique.reference\"?: string[] | undefined; \"kibana.alert.building_block_type\"?: string[] | undefined; \"kibana.alert\"?: string[] | undefined; \"kibana.alert.rule\"?: string[] | undefined; \"kibana.alert.suppression.terms\"?: string[] | undefined; \"kibana.alert.group.field\"?: string[] | undefined; \"kibana.alert.group.value\"?: string[] | undefined; \"kibana.alert.rule.exceptions_list\"?: string[] | undefined; \"kibana.alert.rule.namespace\"?: string[] | undefined; } & { [x: string]: unknown[]; }" ], "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "deprecated": false, @@ -6316,7 +6330,7 @@ "label": "GetRenderCellValue", "description": [], "signature": [ - "({ setFlyoutAlert, }: { setFlyoutAlert?: ((data: unknown) => void) | undefined; }) => (props: unknown) => React.ReactNode" + "({ setFlyoutAlert, context, }: { setFlyoutAlert?: ((data: unknown) => void) | undefined; context?: T | undefined; }) => (props: unknown) => React.ReactNode" ], "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "deprecated": false, @@ -6331,7 +6345,7 @@ "label": "__0", "description": [], "signature": [ - "{ setFlyoutAlert?: ((data: unknown) => void) | undefined; }" + "{ setFlyoutAlert?: ((data: unknown) => void) | undefined; context?: T | undefined; }" ], "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "deprecated": false, diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 8076002044f8..90ba1896980c 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 583 | 1 | 557 | 55 | +| 584 | 1 | 558 | 55 | ## Client diff --git a/api_docs/ui_actions.devdocs.json b/api_docs/ui_actions.devdocs.json index fc3e6efa4a21..bf583998fc74 100644 --- a/api_docs/ui_actions.devdocs.json +++ b/api_docs/ui_actions.devdocs.json @@ -1634,71 +1634,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "uiActions", - "id": "def-public.CategorizeFieldContext", - "type": "Interface", - "tags": [], - "label": "CategorizeFieldContext", - "description": [], - "path": "src/plugins/ui_actions/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "uiActions", - "id": "def-public.CategorizeFieldContext.field", - "type": "Object", - "tags": [], - "label": "field", - "description": [], - "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataViewField", - "text": "DataViewField" - } - ], - "path": "src/plugins/ui_actions/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "uiActions", - "id": "def-public.CategorizeFieldContext.dataView", - "type": "Object", - "tags": [], - "label": "dataView", - "description": [], - "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataView", - "text": "DataView" - } - ], - "path": "src/plugins/ui_actions/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "uiActions", - "id": "def-public.CategorizeFieldContext.originatingApp", - "type": "string", - "tags": [], - "label": "originatingApp", - "description": [], - "path": "src/plugins/ui_actions/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "uiActions", "id": "def-public.Presentable", @@ -2300,21 +2235,6 @@ ], "enums": [], "misc": [ - { - "parentPluginId": "uiActions", - "id": "def-public.ACTION_CATEGORIZE_FIELD", - "type": "string", - "tags": [], - "label": "ACTION_CATEGORIZE_FIELD", - "description": [], - "signature": [ - "\"ACTION_CATEGORIZE_FIELD\"" - ], - "path": "src/plugins/ui_actions/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "uiActions", "id": "def-public.ACTION_VISUALIZE_FIELD", @@ -2384,21 +2304,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "uiActions", - "id": "def-public.CATEGORIZE_FIELD_TRIGGER", - "type": "string", - "tags": [], - "label": "CATEGORIZE_FIELD_TRIGGER", - "description": [], - "signature": [ - "\"CATEGORIZE_FIELD_TRIGGER\"" - ], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "uiActions", "id": "def-public.PresentableGrouping", @@ -2468,53 +2373,6 @@ } ], "objects": [ - { - "parentPluginId": "uiActions", - "id": "def-public.categorizeFieldTrigger", - "type": "Object", - "tags": [], - "label": "categorizeFieldTrigger", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "uiActions", - "id": "def-public.categorizeFieldTrigger.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "uiActions", - "id": "def-public.categorizeFieldTrigger.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "uiActions", - "id": "def-public.categorizeFieldTrigger.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "uiActions", "id": "def-public.rowClickTrigger", @@ -2665,15 +2523,15 @@ "label": "UiActionsSetup", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -2689,15 +2547,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; }" + ") => void; }" ], "path": "src/plugins/ui_actions/public/plugin.ts", "deprecated": false, @@ -2713,15 +2571,17 @@ "label": "UiActionsStart", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -2737,17 +2597,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 1c8f3f5e8344..0008b069fc49 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 145 | 0 | 103 | 9 | +| 135 | 0 | 93 | 9 | ## Client diff --git a/api_docs/ui_actions_enhanced.devdocs.json b/api_docs/ui_actions_enhanced.devdocs.json index 774898421d86..83c71b1e3e65 100644 --- a/api_docs/ui_actions_enhanced.devdocs.json +++ b/api_docs/ui_actions_enhanced.devdocs.json @@ -3311,7 +3311,7 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + "{ readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -3327,7 +3327,7 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly getActionFactory: (actionFactoryId: string) => ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly getActionFactory: (actionFactoryId: string) => ", { "pluginId": "uiActionsEnhanced", "scope": "public", diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index bc7c3d55f0c6..c7178ca22c3a 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.devdocs.json b/api_docs/unified_doc_viewer.devdocs.json index 3a98a829b9e6..28e674ad5844 100644 --- a/api_docs/unified_doc_viewer.devdocs.json +++ b/api_docs/unified_doc_viewer.devdocs.json @@ -133,24 +133,6 @@ ], "returnComment": [], "initialIsOpen": false - }, - { - "parentPluginId": "unifiedDocViewer", - "id": "def-public.useUnifiedDocViewerServices", - "type": "Function", - "tags": [], - "label": "useUnifiedDocViewerServices", - "description": [], - "signature": [ - "() => ", - "UnifiedDocViewerServices" - ], - "path": "src/plugins/unified_doc_viewer/public/hooks/use_doc_viewer_services.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [], - "initialIsOpen": false } ], "interfaces": [], diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index dff22e1edd0b..7639e6095069 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 13 | 0 | 10 | 3 | +| 12 | 0 | 9 | 2 | ## Client diff --git a/api_docs/unified_histogram.devdocs.json b/api_docs/unified_histogram.devdocs.json index 8cf2ef256b1a..23dd7f92c406 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -632,15 +632,17 @@ "label": "uiActions", "description": [], "signature": [ - "{ readonly addTriggerAction: (triggerId: string, action: ", + "{ readonly registerTrigger: (trigger: ", { - "pluginId": "uiActions", - "scope": "public", - "docId": "kibUiActionsPluginApi", - "section": "def-public.ActionDefinition", - "text": "ActionDefinition" + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" }, - ") => void; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly registerAction: (definition: ", + ") => void; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", { "pluginId": "uiActions", "scope": "public", @@ -656,17 +658,15 @@ "section": "def-public.Action", "text": "Action" }, - "; readonly registerTrigger: (trigger: ", + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", { - "pluginId": "@kbn/ui-actions-browser", - "scope": "common", - "docId": "kibKbnUiActionsBrowserPluginApi", - "section": "def-common.Trigger", - "text": "Trigger" + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" }, - ") => void; readonly unregisterAction: (actionId: string) => void; readonly getTrigger: (triggerId: string) => ", - "TriggerContract", - "; readonly hasAction: (actionId: string) => boolean; readonly getAction: (id: string) => ", + ") => void; readonly getAction: (id: string) => ", { "pluginId": "uiActions", "scope": "public", diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 1b8cde068313..014dd12dcaf8 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index 09a1feea1cee..0d5e841aaada 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -635,7 +635,7 @@ }, "[] | undefined; refreshInterval?: number | undefined; iconType?: ", "IconType", - " | undefined; showQueryInput?: boolean | undefined; dataTestSubj?: string | undefined; showSaveQuery?: boolean | undefined; customSubmitButton?: React.ReactNode; dataViewPickerOverride?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; filtersForSuggestions?: ", + " | undefined; dataTestSubj?: string | undefined; showSaveQuery?: boolean | undefined; customSubmitButton?: React.ReactNode; dataViewPickerOverride?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showQueryInput?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; filtersForSuggestions?: ", { "pluginId": "@kbn/es-query", "scope": "common", diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index dd540663bb60..ac49393b5a9c 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 996c7f5528dc..04d77c062703 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 814bcd995e63..2603cc3a18aa 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 9f93b59207c1..fc6bdfd5e665 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index fb864ad03798..6be4168b8a2b 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 8098cf149e57..e70ed2a46772 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 40877abcb634..ada3c86c1f72 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 0d4725984ca1..45303239244f 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 7857b49c7ecd..4c9212b3f611 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index c1307ba118b0..2870d38dd28f 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 37333abc730d..80b79a73d1f5 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index cb39b15983e1..4e2657f2c3c3 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 882aaf0a79f7..6d708a34a972 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index d1fa982b691c..12a5148f7fee 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 7084cbc94b13..a183b2f8c8c0 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 44036f275579..6a556f0816fb 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index b9e6229c9486..13897de83762 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -4423,22 +4423,16 @@ "children": [ { "parentPluginId": "visualizations", - "id": "def-public.VisTypeAlias.aliasPath", - "type": "string", - "tags": [], - "label": "aliasPath", - "description": [], - "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "visualizations", - "id": "def-public.VisTypeAlias.aliasApp", - "type": "string", + "id": "def-public.VisTypeAlias.alias", + "type": "Object", "tags": [], - "label": "aliasApp", - "description": [], + "label": "alias", + "description": [ + "\nProvide `alias` when your visualization has a dedicated app for creation.\nTODO: Provide a generic callback to create visualizations inline." + ], + "signature": [ + "{ app: string; path: string; } | undefined" + ], "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", "deprecated": false, "trackAdoption": false @@ -5874,31 +5868,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "visualizations", - "id": "def-public.VisualizationListItem.editUrl", - "type": "string", - "tags": [], - "label": "editUrl", - "description": [], - "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "visualizations", - "id": "def-public.VisualizationListItem.editApp", - "type": "string", - "tags": [], - "label": "editApp", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "visualizations", "id": "def-public.VisualizationListItem.error", @@ -6055,6 +6024,20 @@ "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationListItem.editor", + "type": "CompoundType", + "tags": [], + "label": "editor", + "description": [], + "signature": [ + "{ editUrl: string; editApp?: string | undefined; } | { onEdit: (savedObjectId: string) => Promise; }" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -13422,7 +13405,7 @@ "label": "seriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "src/plugins/visualizations/common/convert_to_lens/types/configurations.ts", "deprecated": false, @@ -15513,7 +15496,7 @@ "label": "SeriesType", "description": [], "signature": [ - "\"bar\" | \"line\" | \"area\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], "path": "src/plugins/visualizations/common/convert_to_lens/types/configurations.ts", "deprecated": false, diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index ce10e1dd34ed..5d193810ac70 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2023-11-16 +date: 2023-12-04 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 837 | 12 | 807 | 19 | +| 835 | 12 | 804 | 19 | ## Client diff --git a/catalog-info.yaml b/catalog-info.yaml index e7aa12000448..3e23a7e20cce 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -56,15 +56,7 @@ spec: teams: kibana-operations: access_level: MANAGE_BUILD_AND_READ - appex-qa: - access_level: BUILD_AND_READ - security-engineering-productivity: - access_level: BUILD_AND_READ - fleet: - access_level: BUILD_AND_READ - kibana-tech-leads: - access_level: BUILD_AND_READ - kibana-core: + kibana-release-operators: access_level: BUILD_AND_READ cloud-tooling: access_level: BUILD_AND_READ @@ -162,3 +154,31 @@ spec: access_level: MANAGE_BUILD_AND_READ everyone: access_level: READ_ONLY +--- +# yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json +apiVersion: backstage.io/v1alpha1 +kind: Resource +metadata: + name: buildkite-pipeline-kibana-kme-test +spec: + implementation: + apiVersion: buildkite.elastic.dev/v1 + kind: Pipeline + metadata: + description: Temporary pipeline for testing Kibana KME work + name: kibana-kme-test + spec: + pipeline_file: .buildkite/scripts/pipelines/pull_request/pipeline.sh + provider_settings: + build_branches: false + build_pull_requests: true + publish_commit_status: false + trigger_mode: none + repository: elastic/kibana + teams: + kibana_operations: + access_level: MANAGE_BUILD_AND_READ + everyone: + access_level: READ_ONLY + owner: group:kibana-operations + type: buildkite-pipeline diff --git a/config/serverless.es.yml b/config/serverless.es.yml index 8a81fbe5f48a..e724eb5207ed 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -9,10 +9,7 @@ xpack.observabilityLogExplorer.enabled: false xpack.observability.enabled: false xpack.securitySolution.enabled: false xpack.serverless.observability.enabled: false -xpack.uptime.enabled: false -xpack.legacy_uptime.enabled: false enterpriseSearch.enabled: false -monitoring.ui.enabled: false xpack.fleet.enabled: false ## Cloud settings diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index 68f340fb64c0..86b3aabadbe5 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -5,8 +5,6 @@ enterpriseSearch.enabled: false xpack.cloudSecurityPosture.enabled: false xpack.infra.enabled: true xpack.securitySolution.enabled: false -xpack.uptime.enabled: false -xpack.legacy_uptime.enabled: false ## Cloud settings xpack.cloud.serverless.project_type: observability diff --git a/config/serverless.security.yml b/config/serverless.security.yml index 7f749afc7626..f47d3b02a1bf 100644 --- a/config/serverless.security.yml +++ b/config/serverless.security.yml @@ -6,8 +6,6 @@ xpack.apm.enabled: false xpack.infra.enabled: false xpack.observabilityLogExplorer.enabled: false xpack.observability.enabled: false -xpack.uptime.enabled: false -xpack.legacy_uptime.enabled: false ## Cloud settings xpack.cloud.serverless.project_type: security diff --git a/config/serverless.yml b/config/serverless.yml index 3731caddd583..30aa06ab8f05 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -150,6 +150,14 @@ xpack.reporting.queue.pollInterval: 3m xpack.reporting.roles.enabled: false xpack.reporting.statefulSettings.enabled: false - # Disabled Observability plugins xpack.ux.enabled: false +xpack.monitoring.enabled: false +xpack.uptime.enabled: false +xpack.legacy_uptime.enabled: false +monitoring.ui.enabled: false + +## Enable uiSettings validations +xpack.securitySolution.enableUiSettingsValidations: true +data.enableUiSettingsValidations: true +discover.enableUiSettingsValidations: true diff --git a/docs/api/alerting/enable_rule.asciidoc b/docs/api/alerting/enable_rule.asciidoc index f51f6c929533..ba04d0147944 100644 --- a/docs/api/alerting/enable_rule.asciidoc +++ b/docs/api/alerting/enable_rule.asciidoc @@ -6,8 +6,6 @@ Enable a rule. -WARNING: This API supports <> only. - [NOTE] ==== For the most up-to-date API details, refer to the diff --git a/docs/apm/how-to-guides.asciidoc b/docs/apm/how-to-guides.asciidoc index 1f1670a12e6f..fe7d6626a077 100644 --- a/docs/apm/how-to-guides.asciidoc +++ b/docs/apm/how-to-guides.asciidoc @@ -13,6 +13,7 @@ Learn how to perform common APM app tasks. * <> * <> * <> +* <> * <> * <> * <> @@ -35,6 +36,8 @@ include::agent-explorer.asciidoc[] include::machine-learning.asciidoc[] +include::mobile-session-explorer.asciidoc[] + include::lambda.asciidoc[] include::advanced-queries.asciidoc[] diff --git a/docs/apm/images/mobile-session-error-details.png b/docs/apm/images/mobile-session-error-details.png new file mode 100644 index 000000000000..41c0bf509514 Binary files /dev/null and b/docs/apm/images/mobile-session-error-details.png differ diff --git a/docs/apm/images/mobile-session-explorer-apm.png b/docs/apm/images/mobile-session-explorer-apm.png new file mode 100644 index 000000000000..55fbc857901f Binary files /dev/null and b/docs/apm/images/mobile-session-explorer-apm.png differ diff --git a/docs/apm/images/mobile-session-explorer-nav.png b/docs/apm/images/mobile-session-explorer-nav.png new file mode 100644 index 000000000000..d208f4091201 Binary files /dev/null and b/docs/apm/images/mobile-session-explorer-nav.png differ diff --git a/docs/apm/images/mobile-session-filter-discover.png b/docs/apm/images/mobile-session-filter-discover.png new file mode 100644 index 000000000000..989284ba2aea Binary files /dev/null and b/docs/apm/images/mobile-session-filter-discover.png differ diff --git a/docs/apm/mobile-errors.asciidoc b/docs/apm/mobile-errors.asciidoc new file mode 100644 index 000000000000..df4e4f380b0c --- /dev/null +++ b/docs/apm/mobile-errors.asciidoc @@ -0,0 +1,36 @@ +[role="xpack"] +[[mobile-errors-crashes]] +=== Mobile errors and crashes + +TIP: {apm-guide-ref}/data-model-errors.html[Errors] are groups of exceptions with a similar exception or log message. + +The *Errors & Crashes* overview provides a high-level view of errors and crashes that APM mobile agents catch, +or that users manually report with APM agent APIs. Errors and crashes are separated into two tabs for easy differentiation. +Like errors are grouped together to make it easy to quickly see which errors are affecting your services, +and to take actions to rectify them. + + + + + +[role="screenshot"] +image::apm/images/mobile-errors-overview.png[Mobile Errors overview] + +Selecting an error group ID or error message brings you to the *Error group*. + +[role="screenshot"] +image::apm/images/mobile-error-group.png[Mobile Error group] + +The error group details page visualizes the number of error occurrences over time and compared to a recent time range. +This allows you to quickly determine if the error rate is changing or remaining constant. +You'll also see the "most affected" chart which can be oriented to 'by device' or 'by app version'. + +Further down, you'll see an Error sample. +The error shown is always the most recent to occur. +The sample includes the exception message, culprit, stack trace where the error occurred (when available), +and additional contextual information to help debug the issue--all of which can be copied with the click of a button. + +In some cases, you might also see a Transaction sample ID. +This feature allows you to make a connection between the errors and transactions, +by linking you to the specific transaction where the error occurred. +This allows you to see the whole trace, including which services the request went through. diff --git a/docs/apm/mobile-service.asciidoc b/docs/apm/mobile-service.asciidoc index aca4e4e65981..774d4592dd67 100644 --- a/docs/apm/mobile-service.asciidoc +++ b/docs/apm/mobile-service.asciidoc @@ -9,7 +9,7 @@ to make data-driven decisions about how to improve your user experience. For example, see: -* Crash Rate (Crashes per minute) -- coming soon +* Crash Rate (Crashes per session) * Slowest App load time -- coming soon * Number of sessions * Number of HTTP requests @@ -28,6 +28,8 @@ of their mobile application environment and the impact of backend errors and bot Understand the impact of slow application load times and variations in application crash rate on user traffic (coming soon). Visualize session and HTTP trends, and see where your users are located--enabling you to optimize your infrastructure deployment and routing topology. +Note: due to the way crash rate is calculated (crashes per session) it is possible to have greater than 100% rate, due to fact that a session may contain multiple crashes. + [role="screenshot"] image::apm/images/mobile-location.png[mobile service overview centered on location map] diff --git a/docs/apm/mobile-session-explorer.asciidoc b/docs/apm/mobile-session-explorer.asciidoc new file mode 100644 index 000000000000..92d4e4dc1fe8 --- /dev/null +++ b/docs/apm/mobile-session-explorer.asciidoc @@ -0,0 +1,43 @@ +[role="xpack] +[[mobile-session-explorer]] +=== Exploring mobile sessions with Discover +Elastic Mobile APM provides session tracking by attaching a `session.id`, a guid, to every span and event. +This allows for the recall of the activities of a specific user during a specific period of time. The best way recall +these data points is using the xref:document-explorer[Discover document explorer]. This guide will explain how to do that. + +=== Viewing sessions with Discover + +The first step is to find the relevant `session.id`. In this example, we'll walk through investigating a crash. +Since all events and spans have `session.id` attributes, a crash is no different. + +The steps to follow are: + +* copy the `session.id` from the relevant document. +* Open the Discover page. +* Select the appropriate data view (use `APM` to search all datastreams) +* set filter to the copied `session.id` + +Here we can see the `session.id` guid in the metadata viewer in the error detail view: +[role="screenshot"] +image::images/mobile-session-error-details.png[Example of session.id in error details] + +Copy this value and open the Discover page: + +[role="screenshot"] +image::images/mobile-session-explorer-nav.png[Example view of navigation to Discover] + + +set the data view. `APM` selected in the example: + +[role="screenshot"] +image::images/mobile-session-explorer-apm.png[Example view of Explorer selecting APM data view] + +filter using the `session.id`: `session.id: ""`: + +[role="screenshot"] +image::images/mobile-session-filter-discover.png[Filter Explor using session.id] + +explore all the documents associated with that session id including crashes, lifecycle events, network requests, errors, and other custom events! + + + diff --git a/docs/developer/contributing/development-accessibility-tests.asciidoc b/docs/developer/contributing/development-accessibility-tests.asciidoc index 2fe2682a3e36..491c16b8a82d 100644 --- a/docs/developer/contributing/development-accessibility-tests.asciidoc +++ b/docs/developer/contributing/development-accessibility-tests.asciidoc @@ -68,7 +68,7 @@ node scripts/functional_test_runner.js --config test/accessibility/config.ts ----------- To run the x-pack tests, swap the config file out for -`x-pack/test/accessibility/config.ts`. +`x-pack/test/accessibility/apps/{group1,group2,group3}/config.ts`. The testing is done using https://github.com/dequelabs/axe-core[axe]. You can run the same thing that runs CI using browser plugins: diff --git a/docs/developer/contributing/interpreting-ci-failures.asciidoc b/docs/developer/contributing/interpreting-ci-failures.asciidoc index 7708c866c3a8..976b3aded365 100644 --- a/docs/developer/contributing/interpreting-ci-failures.asciidoc +++ b/docs/developer/contributing/interpreting-ci-failures.asciidoc @@ -33,7 +33,7 @@ image::images/test_results.png[Buildkite build screenshot] Looking at the failure, we first look at the Error and stack trace. In the example below, this test failed to find an element within the timeout; `Error: retry.try timeout: TimeoutError: Waiting for element to be located By(css selector, [data-test-subj="createSpace"])` -We know the test file from the stack trace was on line 50 of `test/accessibility/apps/spaces.ts` (this test and the stack trace context is kibana/x-pack/ so the file is https://github.com/elastic/kibana/blob/main/x-pack/test/accessibility/apps/spaces.ts#L50). +We know the test file from the stack trace was on line 50 of `test/accessibility/apps/spaces.ts` (this test and the stack trace context is kibana/x-pack/ so the file is https://github.com/elastic/kibana/blob/main/x-pack/test/accessibility/apps/group1/spaces.ts#L50). The function to click on the element was called from a page object method in `test/functional/page_objects/space_selector_page.ts` https://github.com/elastic/kibana/blob/main/x-pack/test/functional/page_objects/space_selector_page.ts#L58 diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index df3f4c8ec855..cb233fc8c10c 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -672,7 +672,7 @@ Elastic. |This plugin allows for other plugins to add data to Kibana stack monitoring documents. -|{kib-repo}blob/{branch}/x-pack/plugins/notifications/README.md[notifications] +|{kib-repo}blob/{branch}/x-pack/plugins/notifications/README.mdx[notifications] |The Notifications plugin provides a set of services to help Solutions and plugins send notifications to users. diff --git a/docs/management/connectors/action-types/pagerduty.asciidoc b/docs/management/connectors/action-types/pagerduty.asciidoc index 0a7cf2b584d1..29b68d6ff3ed 100644 --- a/docs/management/connectors/action-types/pagerduty.asciidoc +++ b/docs/management/connectors/action-types/pagerduty.asciidoc @@ -31,9 +31,15 @@ image::management/connectors/images/pagerduty-connector.png[PagerDuty connector] PagerDuty connectors have the following configuration properties: -Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. -API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is added to the allowed hosts. -Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. +API URL:: +An optional PagerDuty event URL. +Defaults to `https://events.pagerduty.com/v2/enqueue`. +If you are using the <> setting, make sure the hostname is added to the allowed hosts. +Integration key:: +A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. +Name:: +The name of the connector. +The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. [float] [[pagerduty-action-configuration]] @@ -80,17 +86,39 @@ image::management/connectors/images/pagerduty-trigger-test.png[PagerDuty params This action has the following properties: -Severity:: The perceived severity of on the affected system. This can be one of `Critical`, `Error`, `Warning` or `Info`(default). -Event action:: One of `Trigger` (default), `Resolve`, or `Acknowledge`. See https://v2.developer.pagerduty.com/docs/events-api-v2#event-action[event action] for more details. -Dedup Key:: All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution. This value is optional, and if not set, defaults to `:`. The maximum length is 255 characters. See https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication[alert deduplication] for details. +Class:: +An optional value indicating the class/type of the event, for example `ping failure` or `cpu load`. +Component:: +An optional value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. +Custom details:: +An optional set of additional details to add to the event. +DedupKey:: +All actions sharing this key will be associated with the same PagerDuty alert. +This value is used to correlate trigger and resolution. +This value is optional, and if not set, defaults to `:`. +The maximum length is 255 characters. See https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication[alert deduplication] for details. + By default, when you create rules that use the PagerDuty connector, the de-duplication key is used to create a new PagerDuty incident for each alert and reuse the incident when a recovered alert reactivates. -Timestamp:: An optional https://v2.developer.pagerduty.com/v2/docs/types#datetime[ISO-8601 format date-time], indicating the time the event was detected or generated. -Component:: An optional value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. -Group:: An optional value indicating the logical grouping of components of a service, for example `app-stack`. -Source:: An optional value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the {kib} saved object id of the action. -Summary:: An optional text summary of the event, defaults to `No summary provided`. The maximum length is 1024 characters. -Class:: An optional value indicating the class/type of the event, for example `ping failure` or `cpu load`. +Event action:: +One of `Trigger` (default), `Resolve`, or `Acknowledge`. +See https://v2.developer.pagerduty.com/docs/events-api-v2#event-action[event action] for more details. +Group:: +An optional value indicating the logical grouping of components of a service, for example `app-stack`. +Links:: +An optional list of links to add to the event. +You must provide a URL and plain text description for each link. +Severity:: +The perceived severity of on the affected system. +This can be one of `Critical`, `Error`, `Warning` or `Info`(default). +Source:: +An optional value indicating the affected system, preferably a hostname or fully qualified domain name. +Defaults to the {kib} saved object id of the action. +Summary:: +An optional text summary of the event, defaults to `No summary provided`. +The maximum length is 1024 characters. +Timestamp:: +An optional https://v2.developer.pagerduty.com/v2/docs/types#datetime[ISO-8601 format date-time], indicating the time the event was detected or generated. + For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. diff --git a/docs/management/connectors/images/pagerduty-connector.png b/docs/management/connectors/images/pagerduty-connector.png index 6613c1321f6b..f3d7fd0c69e4 100644 Binary files a/docs/management/connectors/images/pagerduty-connector.png and b/docs/management/connectors/images/pagerduty-connector.png differ diff --git a/docs/management/connectors/images/pagerduty-trigger-test.png b/docs/management/connectors/images/pagerduty-trigger-test.png index b12f599b58bf..3504e4683d33 100644 Binary files a/docs/management/connectors/images/pagerduty-trigger-test.png and b/docs/management/connectors/images/pagerduty-trigger-test.png differ diff --git a/docs/maps/connect-to-ems.asciidoc b/docs/maps/connect-to-ems.asciidoc index 8db34ee3f61b..8fac6a6d95c1 100644 --- a/docs/maps/connect-to-ems.asciidoc +++ b/docs/maps/connect-to-ems.asciidoc @@ -3,17 +3,58 @@ :ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8 :ems-docker-image: {ems-docker-repo}:{version} +:ems-headers-url: https://deployment-host https://www.elastic.co/elastic-maps-service[Elastic Maps Service (EMS)] is a service that hosts tile layers and vector shapes of administrative boundaries. If you are using Kibana's out-of-the-box settings, Maps is already configured to use EMS. +[float] +=== Domains + EMS requests are made to the following domains: -* tiles.maps.elastic.co -* vector.maps.elastic.co +* Tile Service: `tiles.maps.elastic.co` +* File Service: `vector.maps.elastic.co` + +[float] +=== Headers + +Find below examples of the request and response headers from Kibana and a minimal `curl` request example showing the response headers sent by each service. + +WARNING: These headers may change without further notice at anytime and are shared for reference. + +[float] +==== EMS Tile Service + +The EMS Tile Service provides basemaps in three different styles as the default background for Maps visualizations. The basemaps use https://www.openstreetmap.org/about[OpenStreetMap] data following the https://openmaptiles.org/[OpenMapTiles] schema and can be explored at https://maps.elastic.co[maps.elastic.co]. + +Headers for the Tile Service JSON manifest describing the basemaps available. + +include::headers/tile-json.asciidoc[] + +Headers for a vector tile asset in _protobuffer_ format from the Tile Service. + +include::headers/tile-pbf.asciidoc[] + +Headers for an sprite image asset from the Tile Service + +include::headers/tile-png.asciidoc[] + + +[float] +==== EMS File Service + +EMS File Service provides the administrative boundaries used for <> as static assets in GeoJSON or TopoJSON formats and can be explored at https://maps.elastic.co[maps.elastic.co]. + +Headers for the File Service JSON manifest that declares all the datasets available. + +include::headers/file-json.asciidoc[] + +Headers for a sample Dataset from the File Service in TopoJSON format. + +include::headers/file-data.asciidoc[] -Maps makes requests directly from the browser to EMS. [float] === Disable Elastic Maps Service diff --git a/docs/maps/headers/file-data.asciidoc b/docs/maps/headers/file-data.asciidoc new file mode 100644 index 000000000000..62b47ed714d0 --- /dev/null +++ b/docs/maps/headers/file-data.asciidoc @@ -0,0 +1,131 @@ + +++++ +
    +
    + + + +
    +
    +++++ +[%collapsible] +==== +[source,bash,subs="attributes"] +---------------------------------- +curl -I 'https://vector.maps.elastic.co/files/world_countries_v7.topo.json?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version={version}' \ +-H 'User-Agent: curl/7.81.0' \ +-H 'Accept: */*' \ +-H 'Accept-Encoding: gzip, deflate, br' +---------------------------------- + +Server response + +[source,regex] +---------------------------------- +HTTP/2 200 +x-guploader-uploadid: ABPtcPpmMffchVgfHIr-SSC00WORo145oV-1q0asjqRvjLV_7cIgyfLRfofXV-BG7huMYABFypblcgdgXRBARhpo2c88ow +x-goog-generation: 1689593325442971 +x-goog-metageneration: 1 +x-goog-stored-content-encoding: gzip +x-goog-stored-content-length: 587241 +content-encoding: gzip +x-goog-hash: crc32c=OcROeg== +x-goog-hash: md5=8KKIwD6wbKa3YYXTnnFcZw== +x-goog-storage-class: MULTI_REGIONAL +accept-ranges: bytes +content-length: 587241 +access-control-allow-origin: * +access-control-expose-headers: Authorization, Content-Length, Content-Type, Date, Server, Transfer-Encoding, X-GUploader-UploadID, X-Google-Trace, accept, elastic-api-version, kbn-name, kbn-version, origin +server: UploadServer +date: Tue, 21 Nov 2023 14:22:16 GMT +expires: Tue, 21 Nov 2023 15:22:16 GMT +cache-control: public, max-age=3600,no-transform +age: 2202 +last-modified: Mon, 17 Jul 2023 11:28:45 GMT +etag: "f0a288c03eb06ca6b76185d39e715c67" +content-type: application/json +alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 +---------------------------------- +==== +++++ +
    + + +
    +++++ diff --git a/docs/maps/headers/file-json.asciidoc b/docs/maps/headers/file-json.asciidoc new file mode 100644 index 000000000000..8e08508da14f --- /dev/null +++ b/docs/maps/headers/file-json.asciidoc @@ -0,0 +1,132 @@ + +++++ +
    +
    + + + +
    +
    +++++ +[%collapsible] +==== +[source,bash,subs="attributes"] +---------------------------------- +curl -I 'https://vector.maps.elastic.co/v{minor-version}/manifest?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version={version}' \ +-H 'User-Agent: curl/7.81.0' \ +-H 'Accept: */*' \ +-H 'Accept-Encoding: gzip, deflate, br' +---------------------------------- + +Server response + +[source,regex] +---------------------------------- +HTTP/2 200 +x-guploader-uploadid: ABPtcPp_BvMdBDO5jVlutETVHmvpOachwjilw4AkIKwMrOQJ4exR9Eln4g0LkW3V_LLSEpvjYLtUtFmO0Uwr61XXUhoP_A +x-goog-generation: 1689593295246576 +x-goog-metageneration: 1 +x-goog-stored-content-encoding: gzip +x-goog-stored-content-length: 108029 +content-encoding: gzip +x-goog-hash: crc32c=T5gVpw== +x-goog-hash: md5=6F8KWV8VTdx8FsN2iFehow== +x-goog-storage-class: MULTI_REGIONAL +accept-ranges: bytes +content-length: 108029 +access-control-allow-origin: * +access-control-expose-headers: Authorization, Content-Length, Content-Type, Date, Server, Transfer-Encoding, X-GUploader-UploadID, X-Google-Trace, accept, elastic-api-version, kbn-name, kbn-version, origin +server: UploadServer +date: Tue, 21 Nov 2023 14:25:07 GMT +expires: Tue, 21 Nov 2023 15:25:07 GMT +cache-control: public, max-age=3600,no-transform +age: 2170 +last-modified: Mon, 17 Jul 2023 11:28:15 GMT +etag: "e85f0a595f154ddc7c16c3768857a1a3" +content-type: application/json +alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 +---------------------------------- +==== +++++ +
    + + +
    +++++ diff --git a/docs/maps/headers/tile-json.asciidoc b/docs/maps/headers/tile-json.asciidoc new file mode 100644 index 000000000000..b34e82dcab3c --- /dev/null +++ b/docs/maps/headers/tile-json.asciidoc @@ -0,0 +1,120 @@ + +++++ +
    +
    + + + +
    +
    +++++ +[%collapsible] +==== +[source,bash,subs="attributes"] +---------------------------------- +curl -I 'https://tiles.maps.elastic.co/v{minor-version}/manifest?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version={version}' \ +-H 'User-Agent: curl/7.81.0' \ +-H 'Accept: */*' \ +-H 'Accept-Encoding: gzip, deflate, br' +---------------------------------- + +Server response + +[source,regex] +---------------------------------- +HTTP/2 200 +server: BaseHTTP/0.6 Python/3.11.4 +date: Mon, 20 Nov 2023 15:08:46 GMT +content-type: application/json; charset=utf-8 +elastic-api-version: 2023-10-31 +access-control-allow-origin: * +access-control-allow-methods: GET, OPTIONS, HEAD +access-control-allow-headers: Origin, Accept, Content-Type, kbn-version, elastic-api-version +access-control-expose-headers: etag +content-encoding: gzip +vary: Accept-Encoding +x-varnish: 844076 5416505 +accept-ranges: bytes +varnish-age: 85285 +cache-control: private, max-age=86400 +via: 1.1 varnish (Varnish/7.0), 1.1 google +alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 +---------------------------------- +==== +++++ +
    + + +
    +++++ diff --git a/docs/maps/headers/tile-pbf.asciidoc b/docs/maps/headers/tile-pbf.asciidoc new file mode 100644 index 000000000000..52215a714cda --- /dev/null +++ b/docs/maps/headers/tile-pbf.asciidoc @@ -0,0 +1,121 @@ + +++++ +
    +
    + + + +
    +
    +++++ +[%collapsible] +==== +[source,bash,subs="attributes"] +---------------------------------- +$ curl -I 'https://tiles.maps.elastic.co/data/v3/1/1/0.pbf?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version={version}' \ +-H 'User-Agent: curl/7.81.0' \ +-H 'Accept: */*' \ +-H 'Accept-Encoding: gzip, deflate, br' +---------------------------------- + +Server response + +[source,regex] +---------------------------------- +HTTP/2 200 +content-encoding: gzip +content-length: 144075 +access-control-allow-origin: * +access-control-allow-methods: GET, OPTIONS, HEAD +access-control-allow-headers: Origin, Accept, Content-Type, kbn-version, elastic-api-version +access-control-expose-headers: etag +x-varnish: 3269455 5976667 +accept-ranges: bytes +varnish-age: 9045 +via: 1.1 varnish (Varnish/7.0), 1.1 google +date: Mon, 20 Nov 2023 15:08:19 GMT +age: 78827 +last-modified: Thu, 16 Sep 2021 17:14:41 GMT +etag: W/"232cb-zYEfNgd8rzHusLotRFzgRDSDDGA" +content-type: application/x-protobuf +vary: Accept-Encoding +cache-control: public,max-age=3600 +alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 +---------------------------------- +==== +++++ +
    + + +
    +++++ diff --git a/docs/maps/headers/tile-png.asciidoc b/docs/maps/headers/tile-png.asciidoc new file mode 100644 index 000000000000..9d972b1ce8c0 --- /dev/null +++ b/docs/maps/headers/tile-png.asciidoc @@ -0,0 +1,117 @@ + +++++ +
    +
    + + + +
    +
    +++++ +[%collapsible] +==== +[source,bash] +---------------------------------- +curl -I 'https://tiles.maps.elastic.co/styles/osm-bright-desaturated/sprite.png' \ +-H 'User-Agent: curl/7.81.0' \ +-H 'Accept: image/avif,image/webp,*/*' \ +-H 'Accept-Encoding: gzip, deflate, br' +---------------------------------- + +Server response + +[source,regex] +---------------------------------- +HTTP/2 200 +content-length: 17181 +access-control-allow-origin: * +access-control-allow-methods: GET, OPTIONS, HEAD +access-control-allow-headers: Origin, Accept, Content-Type, kbn-version, elastic-api-version +access-control-expose-headers: etag +x-varnish: 8769943 4865354 +accept-ranges: bytes +varnish-age: 250 +via: 1.1 varnish (Varnish/7.0), 1.1 google +date: Tue, 21 Nov 2023 14:44:36 GMT +age: 592 +etag: W/"431d-/dqE/W5Q3FqkHikyDQtCuQqAdlY" +content-type: image/png +cache-control: public,max-age=3600 +alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 +---------------------------------- +==== +++++ +
    + + +
    +++++ diff --git a/docs/setup/configuring-reporting.asciidoc b/docs/setup/configuring-reporting.asciidoc index 903f6fdfb5af..d8ff9e1b202b 100644 --- a/docs/setup/configuring-reporting.asciidoc +++ b/docs/setup/configuring-reporting.asciidoc @@ -113,7 +113,7 @@ Granting the privilege to generate reports also grants the user the privilege to ==== Grant access with the role API With <> enabled in Reporting, you can also use the {ref}/security-api-put-role.html[role API] to grant access to the {report-features}, using *All* privileges, or sub-feature privileges. -NOTE: this [API request](https://www.elastic.co/guide/en/kibana/current/role-management-api-put.html) needs to be executed against the Kibana API endpoint +NOTE: This link:https://www.elastic.co/guide/en/kibana/current/role-management-api-put.html[API request] needs to be executed against the link:https://www.elastic.co/guide/en/kibana/current/api.html[Kibana API endpoint]. [source, sh] --------------------------------------------------------------- POST :/api/_security/role/custom_reporting_user @@ -229,3 +229,5 @@ For more information, see {ref}/notification-settings.html#ssl-notification-sett . Add one or more users who have access to the {report-features}. + Once you've enabled SSL for {kib}, all requests to the reporting endpoints must include valid credentials. + +For more information on sharing reports, direct links, and more, refer to <>. diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc index fef9ae71a085..da4784f7ea36 100644 --- a/docs/setup/connect-to-elasticsearch.asciidoc +++ b/docs/setup/connect-to-elasticsearch.asciidoc @@ -54,9 +54,9 @@ Details for each programming language library that Elastic provides are in the https://www.elastic.co/guide/en/elasticsearch/client/index.html[{es} Client documentation]. If you are running {kib} on our hosted {es} Service, -click *Endpoints* on the *Integrations* view +click *Connection details* on the *Integrations* view to verify your {es} endpoint and Cloud ID, and create API keys for integration. -Alternatively, the *Endpoints* are also accessible through the top bar help menu. +Alternatively, the *Connection details* are also accessible through the top bar help menu. [float] === Add sample data diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 9d38b5162f12..37bb26ae53a3 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -323,12 +323,12 @@ run {kib} in different modes. Valid options are `background_tasks` and `ui`, or `*` to select all roles. *Default: `*`* `notifications.connectors.default.email`:: -Specifies the name of the connector that is used to send email notifications. -In {ecloud}, the default value is `elastic-cloud-email`. + Choose the default email connector for user notifications. As of `8.6.0`, {kib} is shipping with a new notification mechanism that will send email notifications for various user actions, e.g. assigning a _Case_ to a user. To enable notifications, an email connector must be <> in the system via `kibana.yml`, and the notifications plugin must be configured to point to the ID of that connector. [[path-data]] `path.data`:: -The path where {kib} stores persistent data -not saved in {es}. *Default: `data`* +The path where {kib} stores persistent data not saved in {es}. +Can be a relative or absolute path. +Relative paths are resolved starting from the installation directory. *Default: `data`* `pid.file`:: Specifies the path where {kib} creates the process ID file. diff --git a/docs/user/alerting/images/es-query-rule-conditions.png b/docs/user/alerting/images/es-query-rule-conditions.png index c9572afc3dc2..b2a4aeba332d 100644 Binary files a/docs/user/alerting/images/es-query-rule-conditions.png and b/docs/user/alerting/images/es-query-rule-conditions.png differ diff --git a/docs/user/alerting/images/rule-types-es-query-conditions.png b/docs/user/alerting/images/rule-types-es-query-conditions.png index 47eed98caf5e..786d17236886 100644 Binary files a/docs/user/alerting/images/rule-types-es-query-conditions.png and b/docs/user/alerting/images/rule-types-es-query-conditions.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-conditions.png b/docs/user/alerting/images/rule-types-index-threshold-conditions.png index 9aac7bd26c3c..5c540a079048 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-conditions.png and b/docs/user/alerting/images/rule-types-index-threshold-conditions.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-example-aggregation.png b/docs/user/alerting/images/rule-types-index-threshold-example-aggregation.png index 68b21a62d8a9..5367d05be86b 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-example-aggregation.png and b/docs/user/alerting/images/rule-types-index-threshold-example-aggregation.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-example-grouping.png b/docs/user/alerting/images/rule-types-index-threshold-example-grouping.png index aaed0acfbf86..1f6a6003353e 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-example-grouping.png and b/docs/user/alerting/images/rule-types-index-threshold-example-grouping.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-example-index.png b/docs/user/alerting/images/rule-types-index-threshold-example-index.png index 29a9c9520d69..4899bd33dc3c 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-example-index.png and b/docs/user/alerting/images/rule-types-index-threshold-example-index.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-example-threshold.png b/docs/user/alerting/images/rule-types-index-threshold-example-threshold.png index 5a1bc35bd22c..1f8ebc120f00 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-example-threshold.png and b/docs/user/alerting/images/rule-types-index-threshold-example-threshold.png differ diff --git a/docs/user/alerting/images/rule-types-index-threshold-select.png b/docs/user/alerting/images/rule-types-index-threshold-select.png index 3a00f5da6aa1..98866694e6e3 100644 Binary files a/docs/user/alerting/images/rule-types-index-threshold-select.png and b/docs/user/alerting/images/rule-types-index-threshold-select.png differ diff --git a/docs/user/alerting/rule-types/index-threshold.asciidoc b/docs/user/alerting/rule-types/index-threshold.asciidoc index 9945b58df8bb..867dbf4ddb30 100644 --- a/docs/user/alerting/rule-types/index-threshold.asciidoc +++ b/docs/user/alerting/rule-types/index-threshold.asciidoc @@ -15,21 +15,37 @@ In *{stack-manage-app}* > *{rules-ui}*, click *Create rule*, fill in the name an [float] === Define the conditions +When you create an index threshold rule, you must define the conditions for the rule to detect. For example: + [role="screenshot"] image::user/alerting/images/rule-types-index-threshold-conditions.png[Defining index threshold rule conditions in {kib}] // NOTE: This is an autogenerated screenshot. Do not edit it directly. -When you create an index threshold rule, you must define the conditions for the rule to detect. For example: +1. Specify the indices to query and a time field that will be used for the time window. + +2. In the `WHEN` clause, specify how to calculate the value that is compared to the threshold. +The value is calculated by aggregating a numeric field in a time window. +The aggregation options are: count, average, sum, min, and max. +When using count the document count is used and an aggregation field is not necessary. + +3. In the `OVER` or `GROUPED OVER` clause, specify whether the aggregation is applied over all documents or split into groups using a grouping field. +If grouping is used, an alert will be created for each group when it exceeds the threshold. +To limit the number of alerts on high cardinality fields, you must specify the number of groups to check against the threshold. +Only the top groups are checked. + +4. Choose a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). +The result of the aggregation is compared to this threshold. + +5. In the `FOR THE LAST` clause, specify a time window. +It determines how far back to search for documents and uses the time field set in the index clause. + +6. Optionally add a KQL expression to further refine the conditions that the rule detects. -Select an index:: -Index::: Specify the indices to query and a time field that will be used for the time window. -When::: Specify how to calculate the value that is compared to the threshold. The value is calculated by aggregating a numeric field in a time window. The aggregation options are: `count`, `average`, `sum`, `min`, and `max`. When using `count` the document count is used and an aggregation field is not necessary. -Over/Grouped Over::: Specify whether the aggregation is applied over all documents or split into groups using a grouping field. If grouping is used, an <> will be created for each group when it exceeds the threshold. To limit the number of alerts on high cardinality fields, you must specify the number of groups to check against the threshold. Only the top groups are checked. -Define the condition:: -This section defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The result of the aggregation is compared to this threshold. -It also defines a time window, which determines how far back to search for documents, using the time field set in the index clause. Generally this value should be a value higher than the check interval to avoid gaps in detection. +7. Set the check interval, which defines how often to evaluate the rule conditions. +Generally this value should be set to a value that is smaller than the time window, to avoid gaps in detection. -If data is available and all clauses have been defined, a preview chart will render the threshold value and display a line chart showing the value for the last 30 intervals. This can provide an indication of recent values and their proximity to the threshold, and help you tune the clauses. +If data is available and all clauses have been defined, a preview chart will render the threshold value and display a line chart showing the value for the last 30 intervals. +This can provide an indication of recent values and their proximity to the threshold, and help you tune the clauses. [float] [[actions-index-threshold]] @@ -116,7 +132,7 @@ image::user/alerting/images/rule-types-index-threshold-example-aggregation.png[C image::user/alerting/images/rule-types-index-threshold-example-grouping.png[Choosing the groups] // NOTE: This is an autogenerated screenshot. Do not edit it directly. -.. Define the condition. To trigger the rule when any of the top four sites exceeds 420,000 bytes over a 24 hour period, select `is above` and enter `420000`. Then click *For the last*, enter `24`, and select `hours`. +.. To trigger the rule when any of the top four sites exceeds 420,000 bytes over a 24 hour period, select `is above` and enter `420000`. Then click *For the last*, enter `24`, and select `hours`. + [role="screenshot"] image::user/alerting/images/rule-types-index-threshold-example-threshold.png[Setting the threshold] @@ -129,7 +145,7 @@ image::user/alerting/images/rule-types-index-threshold-example-threshold.png[Set image::user/alerting/images/rule-types-index-threshold-example-preview.png[Setting the check interval] // NOTE: This is an autogenerated screenshot. Do not edit it directly. -The preview chart will render showing the 24 hour sum of bytes at 4 hours intervals (the _check interval_) for the past 120 hours (the last 30 intervals). +The preview chart will render showing the 24 hour sum of bytes at 4 hours intervals for the past 120 hours (the last 30 intervals). -- .. Change the time window and observe the effect it has on the chart. Compare a 24 window to a 12 hour window. Notice the variability in the sum of bytes, due to different traffic levels during the day compared to at night. This variability would result in noisy rules, so the 24 hour window is better. The preview chart can help you find the right values for your rule. diff --git a/docs/user/dashboard/images/dashboard_links_panel.png b/docs/user/dashboard/images/dashboard_links_panel.png index f6334f4df29f..23b37879378e 100644 Binary files a/docs/user/dashboard/images/dashboard_links_panel.png and b/docs/user/dashboard/images/dashboard_links_panel.png differ diff --git a/docs/user/plugins.asciidoc b/docs/user/plugins.asciidoc index 0bf407ac1ff9..8dc3d8b6e9e0 100644 --- a/docs/user/plugins.asciidoc +++ b/docs/user/plugins.asciidoc @@ -81,7 +81,6 @@ Use it to create, edit and embed visualizations, and also to search inside an em * https://github.com/sw-jung/kibana_markdown_doc_view[Markdown Doc View] (sw-jung) - A plugin for custom doc view using markdown+handlebars template. * https://github.com/datasweet-fr/kibana-datasweet-formula[Datasweet Formula] (datasweet) - enables calculated metric on any standard Kibana visualization. -* https://github.com/pjhampton/kibana-prometheus-exporter[Prometheus Exporter] - exports the Kibana metrics in the prometheus format NOTE: To add your plugin to this page, open a {kib-repo}tree/{branch}/docs/plugins/known-plugins.asciidoc[pull request]. @@ -183,4 +182,4 @@ you must specify the path to that configuration file each time you use the `bin/ 0:: Success 64:: Unknown command or incorrect option parameter 74:: I/O error -70:: Other error +70:: Other error \ No newline at end of file diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index 8d53018dec57..676fb430b9c6 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -31,6 +31,8 @@ You access the options from the *Share* menu in the toolbar. The sharing options NOTE: For Elastic Cloud deployments, {kib} instances require a minimum of 2GB RAM to generate PDF or PNG reports. To change {kib} sizing, {ess-console}[edit the deployment]. +For more information on how to configure reporting in {kib}, refer to <> + [float] [[manually-generate-reports]] == Create reports diff --git a/nav-kibana-dev.docnav.json b/nav-kibana-dev.docnav.json index c85c804cdfda..56517c4136f7 100644 --- a/nav-kibana-dev.docnav.json +++ b/nav-kibana-dev.docnav.json @@ -425,6 +425,9 @@ { "id": "kibNewsfeedPluginApi" }, + { + "id": "kibNotificationsPluginApi" + }, { "id": "kibObservabilityPluginApi" }, diff --git a/package.json b/package.json index a14a06c2e188..08dc4ceee7a3 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.9.1-canary.1", "@elastic/ems-client": "8.5.1", - "@elastic/eui": "90.0.0", + "@elastic/eui": "90.0.1", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", @@ -166,6 +166,8 @@ "@kbn/banners-plugin": "link:x-pack/plugins/banners", "@kbn/bfetch-explorer-plugin": "link:examples/bfetch_explorer", "@kbn/bfetch-plugin": "link:src/plugins/bfetch", + "@kbn/calculate-auto": "link:packages/kbn-calculate-auto", + "@kbn/calculate-width-from-char-count": "link:packages/kbn-calculate-width-from-char-count", "@kbn/canvas-plugin": "link:x-pack/plugins/canvas", "@kbn/cases-api-integration-test-plugin": "link:x-pack/test/cases_api_integration/common/plugins/cases", "@kbn/cases-components": "link:packages/kbn-cases-components", @@ -352,6 +354,7 @@ "@kbn/crypto": "link:packages/kbn-crypto", "@kbn/crypto-browser": "link:packages/kbn-crypto-browser", "@kbn/custom-branding-plugin": "link:x-pack/plugins/custom_branding", + "@kbn/custom-icons": "link:packages/kbn-custom-icons", "@kbn/custom-integrations": "link:packages/kbn-custom-integrations", "@kbn/custom-integrations-plugin": "link:src/plugins/custom_integrations", "@kbn/dashboard-enhanced-plugin": "link:x-pack/plugins/dashboard_enhanced", @@ -389,6 +392,7 @@ "@kbn/ecs": "link:packages/kbn-ecs", "@kbn/ecs-data-quality-dashboard": "link:x-pack/packages/security-solution/ecs_data_quality_dashboard", "@kbn/ecs-data-quality-dashboard-plugin": "link:x-pack/plugins/ecs_data_quality_dashboard", + "@kbn/elastic-agent-utils": "link:packages/kbn-elastic-agent-utils", "@kbn/elastic-assistant": "link:x-pack/packages/kbn-elastic-assistant", "@kbn/elastic-assistant-plugin": "link:x-pack/plugins/elastic_assistant", "@kbn/elasticsearch-client-plugin": "link:test/plugin_functional/plugins/elasticsearch_client_plugin", @@ -532,8 +536,10 @@ "@kbn/ml-anomaly-utils": "link:x-pack/packages/ml/anomaly_utils", "@kbn/ml-category-validator": "link:x-pack/packages/ml/category_validator", "@kbn/ml-chi2test": "link:x-pack/packages/ml/chi2test", + "@kbn/ml-creation-wizard-utils": "link:x-pack/packages/ml/creation_wizard_utils", "@kbn/ml-data-frame-analytics-utils": "link:x-pack/packages/ml/data_frame_analytics_utils", "@kbn/ml-data-grid": "link:x-pack/packages/ml/data_grid", + "@kbn/ml-data-view-utils": "link:x-pack/packages/ml/data_view_utils", "@kbn/ml-date-picker": "link:x-pack/packages/ml/date_picker", "@kbn/ml-date-utils": "link:x-pack/packages/ml/date_utils", "@kbn/ml-error-utils": "link:x-pack/packages/ml/error_utils", @@ -552,6 +558,7 @@ "@kbn/ml-runtime-field-utils": "link:x-pack/packages/ml/runtime_field_utils", "@kbn/ml-string-hash": "link:x-pack/packages/ml/string_hash", "@kbn/ml-trained-models-utils": "link:x-pack/packages/ml/trained_models_utils", + "@kbn/ml-ui-actions": "link:x-pack/packages/ml/ui_actions", "@kbn/ml-url-state": "link:x-pack/packages/ml/url_state", "@kbn/monaco": "link:packages/kbn-monaco", "@kbn/monitoring-collection-plugin": "link:x-pack/plugins/monitoring_collection", @@ -566,6 +573,7 @@ "@kbn/observability-alert-details": "link:x-pack/packages/observability/alert_details", "@kbn/observability-alerting-test-data": "link:x-pack/packages/observability/alerting_test_data", "@kbn/observability-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/observability", + "@kbn/observability-get-padded-alert-time-range-util": "link:x-pack/packages/observability/get_padded_alert_time_range_util", "@kbn/observability-log-explorer-plugin": "link:x-pack/plugins/observability_log_explorer", "@kbn/observability-onboarding-plugin": "link:x-pack/plugins/observability_onboarding", "@kbn/observability-plugin": "link:x-pack/plugins/observability", @@ -576,6 +584,7 @@ "@kbn/osquery-plugin": "link:x-pack/plugins/osquery", "@kbn/paertial-results-example-plugin": "link:examples/partial_results_example", "@kbn/painless-lab-plugin": "link:x-pack/plugins/painless_lab", + "@kbn/panel-loader": "link:packages/kbn-panel-loader", "@kbn/portable-dashboards-example": "link:examples/portable_dashboards_example", "@kbn/preboot-example-plugin": "link:examples/preboot_example", "@kbn/presentation-util-plugin": "link:src/plugins/presentation_util", @@ -642,6 +651,9 @@ "@kbn/search-response-warnings": "link:packages/kbn-search-response-warnings", "@kbn/searchprofiler-plugin": "link:x-pack/plugins/searchprofiler", "@kbn/security-plugin": "link:x-pack/plugins/security", + "@kbn/security-plugin-types-common": "link:x-pack/packages/security/plugin_types_common", + "@kbn/security-plugin-types-public": "link:x-pack/packages/security/plugin_types_public", + "@kbn/security-plugin-types-server": "link:x-pack/packages/security/plugin_types_server", "@kbn/security-solution-ess": "link:x-pack/plugins/security_solution_ess", "@kbn/security-solution-features": "link:x-pack/packages/security-solution/features", "@kbn/security-solution-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/security_solution", @@ -746,7 +758,6 @@ "@kbn/status-plugin-a-plugin": "link:test/server_integration/plugins/status_plugin_a", "@kbn/status-plugin-b-plugin": "link:test/server_integration/plugins/status_plugin_b", "@kbn/std": "link:packages/kbn-std", - "@kbn/subscription-tracking": "link:packages/kbn-subscription-tracking", "@kbn/synthetics-plugin": "link:x-pack/plugins/synthetics", "@kbn/task-manager-fixture-plugin": "link:x-pack/test/alerting_api_integration/common/plugins/task_manager_fixture", "@kbn/task-manager-performance-plugin": "link:x-pack/test/plugin_api_perf/plugins/task_manager_performance", @@ -841,6 +852,8 @@ "@opentelemetry/semantic-conventions": "^1.4.0", "@reduxjs/toolkit": "1.7.2", "@slack/webhook": "^5.0.4", + "@smithy/eventstream-codec": "^2.0.12", + "@smithy/util-utf8": "^2.0.0", "@tanstack/react-query": "^4.29.12", "@tanstack/react-query-devtools": "^4.29.12", "@turf/along": "6.0.1", @@ -900,7 +913,7 @@ "deep-freeze-strict": "^1.1.1", "deepmerge": "^4.2.2", "del": "^6.1.0", - "elastic-apm-node": "^4.1.0", + "elastic-apm-node": "^4.2.0", "email-addresses": "^5.0.0", "execa": "^5.1.1", "expiry-js": "0.1.7", @@ -919,7 +932,7 @@ "getos": "^3.1.0", "globby": "^11.1.0", "gpt-tokenizer": "^2.1.2", - "handlebars": "4.7.7", + "handlebars": "4.7.8", "he": "^1.2.0", "history": "^4.9.0", "hjson": "3.2.1", @@ -950,7 +963,8 @@ "jsonwebtoken": "^9.0.0", "jsts": "^1.6.2", "kea": "^2.6.0", - "langchain": "^0.0.151", + "langchain": "^0.0.186", + "langsmith": "^0.0.48", "launchdarkly-js-client-sdk": "^3.1.4", "launchdarkly-node-server-sdk": "^7.0.3", "load-json-file": "^6.2.0", @@ -1002,7 +1016,7 @@ "query-string": "^6.13.2", "rbush": "^3.0.1", "re-resizable": "^6.9.9", - "re2": "1.20.1", + "re2": "1.20.9", "react": "^17.0.2", "react-ace": "^7.0.5", "react-color": "^2.13.8", @@ -1232,6 +1246,8 @@ "@kbn/managed-vscode-config": "link:packages/kbn-managed-vscode-config", "@kbn/managed-vscode-config-cli": "link:packages/kbn-managed-vscode-config-cli", "@kbn/management-storybook-config": "link:packages/kbn-management/storybook/config", + "@kbn/mock-idp-plugin": "link:packages/kbn-mock-idp-plugin", + "@kbn/openapi-bundler": "link:packages/kbn-openapi-bundler", "@kbn/openapi-generator": "link:packages/kbn-openapi-generator", "@kbn/optimizer": "link:packages/kbn-optimizer", "@kbn/optimizer-webpack-helpers": "link:packages/kbn-optimizer-webpack-helpers", @@ -1303,7 +1319,7 @@ "@types/byte-size": "^8.1.0", "@types/chance": "^1.0.0", "@types/chroma-js": "^2.1.0", - "@types/chromedriver": "^81.0.2", + "@types/chromedriver": "^81.0.5", "@types/classnames": "^2.2.9", "@types/color": "^3.0.3", "@types/cytoscape": "^3.14.0", @@ -1410,7 +1426,7 @@ "@types/redux-logger": "^3.0.8", "@types/resolve": "^1.20.1", "@types/seedrandom": ">=2.0.0 <4.0.0", - "@types/selenium-webdriver": "^4.1.13", + "@types/selenium-webdriver": "^4.1.20", "@types/semver": "^7", "@types/set-value": "^2.0.0", "@types/sharp": "^0.30.4", @@ -1464,7 +1480,7 @@ "blob-polyfill": "^7.0.20220408", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^119.0.0", + "chromedriver": "^119.0.1", "clean-webpack-plugin": "^3.0.0", "cli-table3": "^0.6.1", "copy-webpack-plugin": "^6.0.2", @@ -1513,7 +1529,7 @@ "file-loader": "^4.2.0", "find-cypress-specs": "^1.35.1", "form-data": "^4.0.0", - "geckodriver": "^4.0.0", + "geckodriver": "^4.2.1", "gulp-brotli": "^3.0.0", "gulp-postcss": "^9.0.1", "gulp-sourcemaps": "2.6.5", @@ -1588,7 +1604,7 @@ "resolve": "^1.22.0", "rxjs-marbles": "^7.0.1", "sass-loader": "^10.4.1", - "selenium-webdriver": "^4.9.1", + "selenium-webdriver": "^4.15.0", "simple-git": "^3.16.0", "sinon": "^7.4.2", "sort-package-json": "^1.53.1", diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts b/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts index fadd1ffee2ae..7608606c3939 100644 --- a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts +++ b/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import * as RxJS from 'rxjs'; import type { FullStoryApi } from './types'; export const fullStoryApiMock: jest.Mocked = { @@ -22,3 +23,10 @@ jest.doMock('./load_snippet', () => { loadSnippet: () => fullStoryApiMock, }; }); + +jest.doMock('rxjs', () => { + return { + ...RxJS, + debounceTime: () => RxJS.identity, + }; +}); diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts b/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts index 4e874b405add..88f53fd7f837 100644 --- a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts +++ b/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts @@ -28,6 +28,10 @@ describe('FullStoryShipper', () => { ); }); + afterEach(() => { + fullstoryShipper.shutdown(); + }); + describe('extendContext', () => { describe('FS.identify', () => { test('calls `identify` when the userId is provided', () => { @@ -119,6 +123,21 @@ describe('FullStoryShipper', () => { labels: { serverless_str: 'test' }, }); }); + + test('emits once only if nothing changes', () => { + const context = { + userId: 'test-user-id', + version: '1.2.3', + cloudId: 'test-es-org-id', + labels: { serverless: 'test' }, + foo: 'bar', + }; + fullstoryShipper.extendContext(context); + fullstoryShipper.extendContext(context); + expect(fullStoryApiMock.setVars).toHaveBeenCalledTimes(1); + fullstoryShipper.extendContext(context); + expect(fullStoryApiMock.setVars).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts b/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts index bcb95ae38f1f..a4ad730f87b2 100644 --- a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts +++ b/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts @@ -12,6 +12,7 @@ import type { Event, IShipper, } from '@kbn/analytics-client'; +import { Subject, distinct, debounceTime, map, filter, Subscription } from 'rxjs'; import { get, has } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; import type { FullStoryApi } from './types'; @@ -55,8 +56,18 @@ export interface FullStoryShipperConfig extends FullStorySnippetConfig { * If this setting is provided, it'll only send the event types specified in this list. */ eventTypesAllowlist?: string[]; + pageVarsDebounceTimeMs?: number; } +interface FullStoryUserVars { + userId?: string; + isElasticCloudUser?: boolean; + cloudIsElasticStaffOwned?: boolean; + cloudTrialEndDate?: string; +} + +type FullStoryPageContext = Pick; + /** * FullStory shipper. */ @@ -67,6 +78,9 @@ export class FullStoryShipper implements IShipper { private readonly fullStoryApi: FullStoryApi; private lastUserId: string | undefined; private readonly eventTypesAllowlist?: string[]; + private readonly pageContext$ = new Subject(); + private readonly userContext$ = new Subject(); + private readonly subscriptions = new Subscription(); /** * Creates a new instance of the FullStoryShipper. @@ -77,9 +91,54 @@ export class FullStoryShipper implements IShipper { config: FullStoryShipperConfig, private readonly initContext: AnalyticsClientInitContext ) { - const { eventTypesAllowlist, ...snippetConfig } = config; + const { eventTypesAllowlist, pageVarsDebounceTimeMs = 500, ...snippetConfig } = config; this.fullStoryApi = loadSnippet(snippetConfig); this.eventTypesAllowlist = eventTypesAllowlist; + + this.subscriptions.add( + this.userContext$ + .pipe( + distinct(({ userId, isElasticCloudUser, cloudIsElasticStaffOwned, cloudTrialEndDate }) => + [userId, isElasticCloudUser, cloudIsElasticStaffOwned, cloudTrialEndDate].join('-') + ) + ) + .subscribe((userVars) => this.updateUserVars(userVars)) + ); + + this.subscriptions.add( + this.pageContext$ + .pipe( + map((newContext) => { + // Cherry-picking fields because FS limits the number of fields that can be sent. + // > Note: You can capture up to 20 unique page properties (exclusive of pageName) for any given page + // > and up to 500 unique page properties across all pages. + // https://help.fullstory.com/hc/en-us/articles/1500004101581-FS-setVars-API-Sending-custom-page-data-to-FullStory + return PAGE_VARS_KEYS.reduce((acc, key) => { + if (has(newContext, key)) { + set(acc, key, get(newContext, key)); + } + return acc; + }, {} as Partial & Record); + }), + filter((pageVars) => Object.keys(pageVars).length > 0), + // Wait for anything to actually change. + distinct((pageVars) => { + const sortedKeys = Object.keys(pageVars).sort(); + return sortedKeys.map((key) => pageVars[key]).join('-'); + }), + // We need some debounce time to ensure everything is updated before calling FS because some properties cannot be changed twice for the same URL. + debounceTime(pageVarsDebounceTimeMs) + ) + .subscribe((pageVars) => { + this.initContext.logger.debug( + `Calling FS.setVars with context ${JSON.stringify(pageVars)}` + ); + this.fullStoryApi.setVars('page', { + ...formatPayload(pageVars), + ...(pageVars.version ? getParsedVersion(pageVars.version) : {}), + }); + }) + ); } /** @@ -89,57 +148,11 @@ export class FullStoryShipper implements IShipper { public extendContext(newContext: EventContext): void { this.initContext.logger.debug(`Received context ${JSON.stringify(newContext)}`); - // FullStory requires different APIs for different type of contexts. - const { - userId, - isElasticCloudUser, - cloudIsElasticStaffOwned, - cloudTrialEndDate, - ...nonUserContext - } = newContext; - - // Call it only when the userId changes - if (userId && userId !== this.lastUserId) { - this.initContext.logger.debug(`Calling FS.identify with userId ${userId}`); - // We need to call the API for every new userId (restarting the session). - this.fullStoryApi.identify(userId); - this.lastUserId = userId; - } - - // User-level context - if ( - typeof isElasticCloudUser === 'boolean' || - typeof cloudIsElasticStaffOwned === 'boolean' || - cloudTrialEndDate - ) { - const userVars = { - isElasticCloudUser, - cloudIsElasticStaffOwned, - cloudTrialEndDate, - }; - this.initContext.logger.debug(`Calling FS.setUserVars with ${JSON.stringify(userVars)}`); - this.fullStoryApi.setUserVars(formatPayload(userVars)); - } - - // Cherry-picking fields because FS limits the number of fields that can be sent. - // > Note: You can capture up to 20 unique page properties (exclusive of pageName) for any given page - // > and up to 500 unique page properties across all pages. - // https://help.fullstory.com/hc/en-us/articles/1500004101581-FS-setVars-API-Sending-custom-page-data-to-FullStory - const pageVars = PAGE_VARS_KEYS.reduce((acc, key) => { - if (has(nonUserContext, key)) { - set(acc, key, get(nonUserContext, key)); - } - return acc; - }, {} as Partial> & Record); - + // FullStory requires different APIs for different type of contexts: + // User-level context. + this.userContext$.next(newContext); // Event-level context. At the moment, only the scope `page` is supported by FullStory for webapps. - if (Object.keys(pageVars).length) { - this.initContext.logger.debug(`Calling FS.setVars with context ${JSON.stringify(pageVars)}`); - this.fullStoryApi.setVars('page', { - ...formatPayload(pageVars), - ...(pageVars.version ? getParsedVersion(pageVars.version) : {}), - }); - } + this.pageContext$.next(newContext); } /** @@ -184,9 +197,38 @@ export class FullStoryShipper implements IShipper { /** * Shuts down the shipper. - * It doesn't really do anything inside because this shipper doesn't hold any internal queues. */ public shutdown() { - // No need to do anything here for now. + this.subscriptions.unsubscribe(); + } + + private updateUserVars({ + userId, + isElasticCloudUser, + cloudIsElasticStaffOwned, + cloudTrialEndDate, + }: FullStoryUserVars) { + // Call it only when the userId changes + if (userId && userId !== this.lastUserId) { + this.initContext.logger.debug(`Calling FS.identify with userId ${userId}`); + // We need to call the API for every new userId (restarting the session). + this.fullStoryApi.identify(userId); + this.lastUserId = userId; + } + + // User-level context + if ( + typeof isElasticCloudUser === 'boolean' || + typeof cloudIsElasticStaffOwned === 'boolean' || + cloudTrialEndDate + ) { + const userVars = { + isElasticCloudUser, + cloudIsElasticStaffOwned, + cloudTrialEndDate, + }; + this.initContext.logger.debug(`Calling FS.setUserVars with ${JSON.stringify(userVars)}`); + this.fullStoryApi.setUserVars(formatPayload(userVars)); + } } } diff --git a/packages/cloud/deployment_details/deployment_details_modal.tsx b/packages/cloud/deployment_details/deployment_details_modal.tsx index c715b2d830c8..4064d289bf68 100644 --- a/packages/cloud/deployment_details/deployment_details_modal.tsx +++ b/packages/cloud/deployment_details/deployment_details_modal.tsx @@ -38,8 +38,8 @@ export const DeploymentDetailsModal: FC = ({ closeModal }) => { > - {i18n.translate('cloud.deploymentDetails.helpMenuLinks.endpoints', { - defaultMessage: 'Endpoints', + {i18n.translate('cloud.deploymentDetails.helpMenuLinks.connectionDetails', { + defaultMessage: 'Connection details', })} diff --git a/packages/content-management/table_list_view_table/src/components/item_details.tsx b/packages/content-management/table_list_view_table/src/components/item_details.tsx index 0b2f52b21690..6c14c9c52021 100644 --- a/packages/content-management/table_list_view_table/src/components/item_details.tsx +++ b/packages/content-management/table_list_view_table/src/components/item_details.tsx @@ -57,7 +57,7 @@ export function ItemDetails({ ); const onClickTitleHandler = useMemo(() => { - if (!onClickTitle) { + if (!onClickTitle || getDetailViewLink?.(item)) { return undefined; } @@ -65,7 +65,7 @@ export function ItemDetails({ e.preventDefault(); onClickTitle(item); }) as React.MouseEventHandler; - }, [item, onClickTitle]); + }, [item, onClickTitle, getDetailViewLink]); const renderTitle = useCallback(() => { const href = getDetailViewLink ? getDetailViewLink(item) : undefined; @@ -79,7 +79,7 @@ export function ItemDetails({ {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index ccf6ef791d8d..f7de8935ea94 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -289,12 +289,6 @@ function TableListViewTableComp({ ); } - if (getDetailViewLink && onClickTitle) { - throw new Error( - `[TableListView] Either "getDetailViewLink" or "onClickTitle" can be provided. Not both.` - ); - } - if (contentEditor.isReadonly === false && contentEditor.onSave === undefined) { throw new Error( `[TableListView] A value for [contentEditor.onSave()] must be provided when [contentEditor.isReadonly] is false.` diff --git a/packages/core/application/core-application-browser-internal/src/application_service.tsx b/packages/core/application/core-application-browser-internal/src/application_service.tsx index d54b71b91f11..8e5f2643929e 100644 --- a/packages/core/application/core-application-browser-internal/src/application_service.tsx +++ b/packages/core/application/core-application-browser-internal/src/application_service.tsx @@ -13,7 +13,7 @@ import { createBrowserHistory, History } from 'history'; import type { PluginOpaqueId } from '@kbn/core-base-common'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpSetup, InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { Capabilities } from '@kbn/core-capabilities-common'; import type { MountPoint } from '@kbn/core-mount-utils-browser'; import type { OverlayStart } from '@kbn/core-overlays-browser'; @@ -46,7 +46,7 @@ import { import { registerAnalyticsContextProvider } from './register_analytics_context_provider'; export interface SetupDeps { - http: HttpSetup; + http: InternalHttpSetup; analytics: AnalyticsServiceSetup; history?: History; /** Used to redirect to external urls */ @@ -54,7 +54,7 @@ export interface SetupDeps { } export interface StartDeps { - http: HttpStart; + http: InternalHttpStart; analytics: AnalyticsServiceStart; theme: ThemeServiceStart; overlays: OverlayStart; diff --git a/packages/core/application/core-application-browser-internal/src/utils/parse_app_url.test.ts b/packages/core/application/core-application-browser-internal/src/utils/parse_app_url.test.ts index 7bc5752a72b1..0126acd36e45 100644 --- a/packages/core/application/core-application-browser-internal/src/utils/parse_app_url.test.ts +++ b/packages/core/application/core-application-browser-internal/src/utils/parse_app_url.test.ts @@ -30,7 +30,7 @@ describe('parseAppUrl', () => { beforeEach(() => { apps = new Map(); - basePath = new BasePath('/base-path'); + basePath = new BasePath({ basePath: '/base-path' }); createApp({ id: 'foo', diff --git a/packages/core/apps/core-apps-browser-internal/src/core_app.ts b/packages/core/apps/core-apps-browser-internal/src/core_app.ts index e8a61de40bea..c6a8583a1493 100644 --- a/packages/core/apps/core-apps-browser-internal/src/core_app.ts +++ b/packages/core/apps/core-apps-browser-internal/src/core_app.ts @@ -10,7 +10,7 @@ import type { UnregisterCallback } from 'history'; import type { CoreContext } from '@kbn/core-base-browser-internal'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; -import type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpSetup, InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import type { NotificationsSetup, NotificationsStart } from '@kbn/core-notifications-browser'; import { AppNavLinkStatus, type AppMountParameters } from '@kbn/core-application-browser'; @@ -27,7 +27,7 @@ import { renderApp as renderStatusApp } from './status'; export interface CoreAppsServiceSetupDeps { application: InternalApplicationSetup; - http: HttpSetup; + http: InternalHttpSetup; injectedMetadata: InternalInjectedMetadataSetup; notifications: NotificationsSetup; } @@ -35,7 +35,7 @@ export interface CoreAppsServiceSetupDeps { export interface CoreAppsServiceStartDeps { application: InternalApplicationStart; docLinks: DocLinksStart; - http: HttpStart; + http: InternalHttpStart; notifications: NotificationsStart; uiSettings: IUiSettingsClient; } diff --git a/packages/core/apps/core-apps-browser-internal/src/errors/error_application.test.ts b/packages/core/apps/core-apps-browser-internal/src/errors/error_application.test.ts index 5ca92bc3904f..65f7a437631b 100644 --- a/packages/core/apps/core-apps-browser-internal/src/errors/error_application.test.ts +++ b/packages/core/apps/core-apps-browser-internal/src/errors/error_application.test.ts @@ -22,7 +22,7 @@ describe('renderApp', () => { let unmount: () => void; beforeEach(() => { - basePath = new BasePath(); + basePath = new BasePath({ basePath: '' }); element = document.createElement('div'); history = createMemoryHistory(); unmount = renderApp( diff --git a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx index 0d2e678963d8..f125d0323980 100644 --- a/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx +++ b/packages/core/apps/core-apps-browser-internal/src/errors/public_base_url.tsx @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { NotificationsStart } from '@kbn/core-notifications-browser'; import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; @@ -21,7 +21,7 @@ export const MISSING_CONFIG_STORAGE_KEY = `core.warnings.publicBaseUrlMissingDis interface Deps { docLinks: DocLinksStart; - http: HttpStart; + http: InternalHttpStart; notifications: NotificationsStart; // Exposed for easier testing storage?: Storage; diff --git a/packages/core/apps/core-apps-browser-internal/src/errors/url_overflow.test.ts b/packages/core/apps/core-apps-browser-internal/src/errors/url_overflow.test.ts index bdf8bdf0abc6..dae718c75afc 100644 --- a/packages/core/apps/core-apps-browser-internal/src/errors/url_overflow.test.ts +++ b/packages/core/apps/core-apps-browser-internal/src/errors/url_overflow.test.ts @@ -27,7 +27,7 @@ describe('url overflow detection', () => { let unlisten: any; beforeEach(() => { - basePath = new BasePath('/test-123'); + basePath = new BasePath({ basePath: '/test-123' }); history = createMemoryHistory(); toasts = notificationServiceMock.createStartContract().toasts; uiSettings = uiSettingsServiceMock.createStartContract(); diff --git a/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.test.ts b/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.test.ts index 45b466225c37..ed6cc186313f 100644 --- a/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.test.ts +++ b/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.test.ts @@ -76,6 +76,8 @@ const mockedResponse: StatusResponse = { total_in_bytes: 0, }, resident_set_size_in_bytes: 1, + array_buffers_in_bytes: 1, + external_in_bytes: 1, }, event_loop_delay: 1, event_loop_delay_histogram: mocked.createHistogram(), @@ -96,6 +98,8 @@ const mockedResponse: StatusResponse = { total_in_bytes: 0, }, resident_set_size_in_bytes: 1, + array_buffers_in_bytes: 1, + external_in_bytes: 1, }, event_loop_delay: 1, event_loop_delay_histogram: mocked.createHistogram(), diff --git a/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts b/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts index 6672786c72a1..7338db04716c 100644 --- a/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts +++ b/packages/core/apps/core-apps-browser-internal/src/status/lib/load_status.ts @@ -189,7 +189,7 @@ export async function loadStatus({ http, notifications, }: { - http: HttpSetup; + http: Pick; notifications: NotificationsSetup; }) { let response: StatusResponse; diff --git a/packages/core/apps/core-apps-browser-internal/src/status/render_app.tsx b/packages/core/apps/core-apps-browser-internal/src/status/render_app.tsx index 4578ff0f347d..a2af773a239a 100644 --- a/packages/core/apps/core-apps-browser-internal/src/status/render_app.tsx +++ b/packages/core/apps/core-apps-browser-internal/src/status/render_app.tsx @@ -10,13 +10,13 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { I18nProvider } from '@kbn/i18n-react'; import { CoreThemeProvider } from '@kbn/core-theme-browser-internal'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { NotificationsSetup } from '@kbn/core-notifications-browser'; import type { AppMountParameters } from '@kbn/core-application-browser'; import { StatusApp } from './status_app'; interface Deps { - http: HttpSetup; + http: InternalHttpSetup; notifications: NotificationsSetup; } diff --git a/packages/core/apps/core-apps-browser-internal/src/status/status_app.tsx b/packages/core/apps/core-apps-browser-internal/src/status/status_app.tsx index 43e388ad170a..88ae96bd3359 100644 --- a/packages/core/apps/core-apps-browser-internal/src/status/status_app.tsx +++ b/packages/core/apps/core-apps-browser-internal/src/status/status_app.tsx @@ -10,13 +10,13 @@ import React, { Component } from 'react'; import { EuiLoadingSpinner, EuiText, EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { NotificationsSetup } from '@kbn/core-notifications-browser'; import { loadStatus, type ProcessedServerResponse } from './lib'; import { MetricTiles, ServerStatus, StatusSection, VersionHeader } from './components'; interface StatusAppProps { - http: HttpSetup; + http: InternalHttpSetup; notifications: NotificationsSetup; } diff --git a/packages/core/capabilities/core-capabilities-browser-internal/src/capabilities_service.tsx b/packages/core/capabilities/core-capabilities-browser-internal/src/capabilities_service.tsx index 746911117e5a..0751225af531 100644 --- a/packages/core/capabilities/core-capabilities-browser-internal/src/capabilities_service.tsx +++ b/packages/core/capabilities/core-capabilities-browser-internal/src/capabilities_service.tsx @@ -8,12 +8,12 @@ import type { RecursiveReadonly } from '@kbn/utility-types'; import { deepFreeze } from '@kbn/std'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { Capabilities } from '@kbn/core-capabilities-common'; interface StartDeps { appIds: string[]; - http: HttpStart; + http: InternalHttpStart; } /** @internal */ diff --git a/packages/core/capabilities/core-capabilities-browser-internal/tsconfig.json b/packages/core/capabilities/core-capabilities-browser-internal/tsconfig.json index 258f96a51d15..ca9379c02486 100644 --- a/packages/core/capabilities/core-capabilities-browser-internal/tsconfig.json +++ b/packages/core/capabilities/core-capabilities-browser-internal/tsconfig.json @@ -14,9 +14,9 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/std", - "@kbn/core-http-browser", "@kbn/core-http-browser-mocks", - "@kbn/core-capabilities-common" + "@kbn/core-capabilities-common", + "@kbn/core-http-browser-internal" ], "exclude": [ "target/**/*", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index eaa30238cde8..e7f1ecbd29ac 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -16,7 +16,7 @@ import useObservable from 'react-use/lib/useObservable'; import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal'; import type { AnalyticsServiceSetup } from '@kbn/core-analytics-browser'; import { type DocLinksStart } from '@kbn/core-doc-links-browser'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; import type { NotificationsStart } from '@kbn/core-notifications-browser'; import type { InternalApplicationStart } from '@kbn/core-application-browser-internal'; @@ -63,7 +63,7 @@ export interface SetupDeps { export interface StartDeps { application: InternalApplicationStart; docLinks: DocLinksStart; - http: HttpStart; + http: InternalHttpStart; injectedMetadata: InternalInjectedMetadataStart; notifications: NotificationsStart; customBranding: CustomBrandingStart; diff --git a/packages/core/chrome/core-chrome-browser-internal/src/nav_links/nav_links_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/nav_links/nav_links_service.ts index e55e8cd0307a..08466a1f35fb 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/nav_links/nav_links_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/nav_links/nav_links_service.ts @@ -9,7 +9,8 @@ import { sortBy } from 'lodash'; import { BehaviorSubject, ReplaySubject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import type { HttpStart, IBasePath } from '@kbn/core-http-browser'; +import type { IBasePath } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { PublicAppDeepLinkInfo, PublicAppInfo } from '@kbn/core-application-browser'; import type { InternalApplicationStart } from '@kbn/core-application-browser-internal'; import type { ChromeNavLinks } from '@kbn/core-chrome-browser'; @@ -18,7 +19,7 @@ import { toNavLink } from './to_nav_link'; interface StartDeps { application: InternalApplicationStart; - http: HttpStart; + http: InternalHttpStart; } export class NavLinksService { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx index 8bd690fba8a7..089613939c83 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx @@ -100,6 +100,8 @@ function buildRootCrumb({ i18n.translate('core.ui.primaryNav.cloud.projectLabel', { defaultMessage: 'Project', }), + // increase the max-width of the root breadcrumb to not truncate too soon + style: { maxWidth: '320px' }, popoverContent: ( { { id: 'root', title: 'Root', - path: ['root'], + path: 'root', breadcrumbStatus: 'hidden' as 'hidden', children: [ { id: 'subNav', - path: ['root', 'subNav'], + path: 'root.subNav', title: '', // intentionally empty to skip rendering children: [ { id: 'navItem1', title: 'Nav Item 1', - path: ['root', 'subNav', 'navItem1'], + path: 'root.subNav.navItem1', deepLink: { id: 'navItem1', title: 'Nav Item 1', @@ -114,6 +114,9 @@ describe('breadcrumbs', () => { "popoverProps": Object { "panelPaddingSize": "none", }, + "style": Object { + "maxWidth": "320px", + }, "text": "Project", }, Object { @@ -176,6 +179,9 @@ describe('breadcrumbs', () => { "popoverProps": Object { "panelPaddingSize": "none", }, + "style": Object { + "maxWidth": "320px", + }, "text": "Project", }, Object { @@ -232,6 +238,9 @@ describe('breadcrumbs', () => { "popoverProps": Object { "panelPaddingSize": "none", }, + "style": Object { + "maxWidth": "320px", + }, "text": "Project", }, Object { @@ -309,12 +318,12 @@ describe('getActiveNodes$()', () => { { id: 'root', title: 'Root', - path: ['root'], + path: 'root', children: [ { id: 'item1', title: 'Item 1', - path: ['root', 'item1'], + path: 'root.item1', deepLink: { id: 'item1', title: 'Item 1', @@ -335,14 +344,12 @@ describe('getActiveNodes$()', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item1', title: 'Item 1', - isActive: true, - path: ['root', 'item1'], + path: 'root.item1', deepLink: { id: 'item1', title: 'Item 1', @@ -366,12 +373,12 @@ describe('getActiveNodes$()', () => { { id: 'root', title: 'Root', - path: ['root'], + path: 'root', children: [ { id: 'item1', title: 'Item 1', - path: ['root', 'item1'], + path: 'root.item1', getIsActive: () => true, }, ], @@ -386,14 +393,12 @@ describe('getActiveNodes$()', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item1', title: 'Item 1', - isActive: true, - path: ['root', 'item1'], + path: 'root.item1', getIsActive: expect.any(Function), }, ], diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index 38766a026cdc..7a8f5b89db65 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -16,7 +16,7 @@ import { ChromeSetProjectBreadcrumbsParams, ChromeProjectNavigationNode, } from '@kbn/core-chrome-browser'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { BehaviorSubject, Observable, @@ -37,7 +37,7 @@ import { buildBreadcrumbs } from './breadcrumbs'; interface StartDeps { application: InternalApplicationStart; navLinks: ChromeNavLinks; - http: HttpStart; + http: InternalHttpStart; chromeBreadcrumbs$: Observable; } @@ -59,7 +59,7 @@ export class ProjectNavigationService { }>({ breadcrumbs: [], params: { absolute: false } }); private readonly stop$ = new ReplaySubject(1); private application?: InternalApplicationStart; - private http?: HttpStart; + private http?: InternalHttpStart; private unlistenHistory?: () => void; public start({ application, navLinks, http, chromeBreadcrumbs$ }: StartDeps) { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts index 93abfd5d5a1f..a207162e060c 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.test.ts @@ -23,27 +23,27 @@ describe('flattenNav', () => { { id: 'root', title: 'Root', - path: ['root'], + path: 'root', children: [ { id: 'item1', title: 'Item 1', - path: ['root', 'item1'], + path: 'root.item1', }, { id: 'item2', title: 'Item 2', - path: ['root', 'item2'], + path: 'root.item2', }, { id: 'group1', title: 'Group 1', - path: ['root', 'group1'], + path: 'root.group1', children: [ { id: 'item3', title: 'Item 3', - path: ['root', 'group1', 'item3'], + path: 'root.group1.item3', }, ], }, @@ -55,27 +55,27 @@ describe('flattenNav', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][0]': { id: 'item1', title: 'Item 1', - path: ['root', 'item1'], + path: 'root.item1', }, '[0][1]': { id: 'item2', title: 'Item 2', - path: ['root', 'item2'], + path: 'root.item2', }, '[0][2]': { id: 'group1', title: 'Group 1', - path: ['root', 'group1'], + path: 'root.group1', }, '[0][2][0]': { id: 'item3', title: 'Item 3', - path: ['root', 'group1', 'item3'], + path: 'root.group1.item3', }, }; @@ -89,18 +89,18 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][0]': { id: 'group1', title: 'Group 1', - path: ['root', 'group1'], + path: 'root.group1', }, '[0][0][0]': { id: 'item1', title: 'Item 1', deepLink: getDeepLink('item1', 'item1'), - path: ['root', 'group1', 'item1'], + path: 'root.group1.item1', }, }; @@ -109,21 +109,18 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'group1', title: 'Group 1', - isActive: true, - path: ['root', 'group1'], + path: 'root.group1', }, { id: 'item1', title: 'Item 1', - isActive: true, deepLink: getDeepLink('item1', 'item1'), - path: ['root', 'group1', 'item1'], + path: 'root.group1.item1', }, ], ]); @@ -134,35 +131,35 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][0]': { id: 'group1', title: 'Group 1', deepLink: getDeepLink('group1', 'group1'), - path: ['root', 'group1'], + path: 'root.group1', }, '[0][0][0]': { id: 'group1A', title: 'Group 1A', - path: ['root', 'group1', 'group1A'], + path: 'root.group1.group1A', }, '[0][0][0][0]': { id: 'item1', title: 'Item 1', deepLink: getDeepLink('item1', 'item1'), - path: ['root', 'group1', 'group1A', 'item1'], + path: 'root.group1.group1A.item1', }, '[0][1]': { id: 'group2', title: 'Group 2', - path: ['root', 'group2'], + path: 'root.group2', }, '[0][1][0]': { id: 'item2', title: 'Item 2', deepLink: getDeepLink('item1', 'item1'), // Same link as above, should match both - path: ['root', 'group2', 'item2'], + path: 'root.group2.item2', }, }; @@ -172,49 +169,42 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'group1', title: 'Group 1', - isActive: true, deepLink: getDeepLink('group1', 'group1'), - path: ['root', 'group1'], + path: 'root.group1', }, { id: 'group1A', title: 'Group 1A', - isActive: true, - path: ['root', 'group1', 'group1A'], + path: 'root.group1.group1A', }, { id: 'item1', title: 'Item 1', - isActive: true, deepLink: getDeepLink('item1', 'item1'), - path: ['root', 'group1', 'group1A', 'item1'], + path: 'root.group1.group1A.item1', }, ], [ { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'group2', title: 'Group 2', - isActive: true, - path: ['root', 'group2'], + path: 'root.group2', }, { id: 'item2', title: 'Item 2', - isActive: true, deepLink: getDeepLink('item1', 'item1'), - path: ['root', 'group2', 'item2'], + path: 'root.group2.item2', }, ], ]); @@ -225,13 +215,13 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][1]': { id: 'item1', title: 'Item 1', deepLink: getDeepLink('item1', `item1#/foo/bar`), - path: ['root', 'item1'], + path: 'root.item1', }, }; @@ -240,15 +230,13 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item1', title: 'Item 1', - isActive: true, deepLink: getDeepLink('item1', `item1#/foo/bar`), - path: ['root', 'item1'], + path: 'root.item1', }, ], ]); @@ -260,7 +248,7 @@ describe('findActiveNodes', () => { id: 'root', title: 'Root', deepLink: getDeepLink('root', `root`), - path: ['root'], + path: 'root', }, }; @@ -269,9 +257,8 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, deepLink: getDeepLink('root', `root`), - path: ['root'], + path: 'root', }, ], ]); @@ -282,19 +269,19 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][1]': { id: 'item1', title: 'Item 1', deepLink: getDeepLink('item1', `item1#/foo`), - path: ['root', 'item1'], + path: 'root.item1', }, '[0][2]': { id: 'item2', title: 'Item 2', deepLink: getDeepLink('item2', `item1#/foo/bar`), // Should match this one - path: ['root', 'item2'], + path: 'root.item2', }, }; @@ -303,15 +290,13 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item2', title: 'Item 2', - isActive: true, deepLink: getDeepLink('item2', `item1#/foo/bar`), - path: ['root', 'item2'], + path: 'root.item2', }, ], ]); @@ -322,13 +307,13 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][1]': { id: 'item1', title: 'Item 1', deepLink: getDeepLink('item1', `appRoot`), - path: ['root', 'item1'], + path: 'root.item1', }, }; @@ -337,15 +322,13 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item1', title: 'Item 1', - isActive: true, deepLink: getDeepLink('item1', `appRoot`), - path: ['root', 'item1'], + path: 'root.item1', }, ], ]; @@ -362,19 +345,19 @@ describe('findActiveNodes', () => { '[0]': { id: 'root', title: 'Root', - path: ['root'], + path: 'root', }, '[0][1]': { id: 'item1', title: 'Item 1', - path: ['root', 'item1'], + path: 'root.item1', getIsActive: ({ location }) => location.pathname.startsWith('/foo'), // Should match }, '[0][2]': { id: 'item2', title: 'Item 2', deepLink: getDeepLink('item2', 'item2'), // Should match - path: ['root', 'item2'], + path: 'root.item2', }, }; @@ -393,30 +376,26 @@ describe('findActiveNodes', () => { { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item1', title: 'Item 1', - isActive: true, getIsActive: expect.any(Function), - path: ['root', 'item1'], + path: 'root.item1', }, ], [ { id: 'root', title: 'Root', - isActive: true, - path: ['root'], + path: 'root', }, { id: 'item2', title: 'Item 2', - isActive: true, deepLink: getDeepLink('item2', 'item2'), - path: ['root', 'item2'], + path: 'root.item2', }, ], ]); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index 48158025414c..63f7f8e612c2 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -114,7 +114,6 @@ export const findActiveNodes = ( const activeNodeFromKey = (key: string): ChromeProjectNavigationNode => ({ ...navTree[key], - isActive: true, }); Object.entries(navTree).forEach(([key, node]) => { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/recently_accessed/recently_accessed_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/recently_accessed/recently_accessed_service.ts index 414f0c796d1b..ec9a04ab5551 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/recently_accessed/recently_accessed_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/recently_accessed/recently_accessed_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem, @@ -15,7 +15,7 @@ import { PersistedLog } from './persisted_log'; import { createLogKey } from './create_log_key'; interface StartDeps { - http: HttpSetup; + http: InternalHttpStart; } /** @internal */ diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index c5c82c88c852..416ce39bbf9b 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -733,6 +733,7 @@ exports[`CollapsibleNav renders the default nav 1`] = ` } basePath={ BasePath { + "assetsHrefBase": "/test", "basePath": "/test", "get": [Function], "prepend": [Function], @@ -918,6 +919,7 @@ exports[`CollapsibleNav renders the default nav 2`] = ` } basePath={ BasePath { + "assetsHrefBase": "/test", "basePath": "/test", "get": [Function], "prepend": [Function], diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx index 4ce22ba727e1..0d453290ba3c 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/breadcrumbs.tsx @@ -43,5 +43,18 @@ export function Breadcrumbs({ breadcrumbs$ }: Props) { }; }); - return ; + return ( + + ); } diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index 30fe35be0b55..80f108c8be78 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -62,6 +62,17 @@ const getHeaderCss = ({ size }: EuiThemeComputed) => ({ top: 2px; `, }, + leftHeaderSection: css` + // needed to enable breadcrumbs truncation + min-width: 0; + flex-shrink: 1; + `, + breadcrumbsSectionItem: css` + min-width: 0; // needed to enable breadcrumbs truncation + `, + redirectAppLinksContainer: css` + min-width: 0; // needed to enable breadcrumbs truncation + `, }); type HeaderCss = ReturnType; @@ -181,7 +192,7 @@ export const ProjectHeader = ({
    - + {children} @@ -196,8 +207,11 @@ export const ProjectHeader = ({ /> - - + + diff --git a/packages/core/chrome/core-chrome-browser-internal/tsconfig.json b/packages/core/chrome/core-chrome-browser-internal/tsconfig.json index 020324c1f67b..ed460a196566 100644 --- a/packages/core/chrome/core-chrome-browser-internal/tsconfig.json +++ b/packages/core/chrome/core-chrome-browser-internal/tsconfig.json @@ -43,6 +43,7 @@ "@kbn/core-analytics-browser", "@kbn/shared-ux-router", "@kbn/shared-ux-link-redirect-app", + "@kbn/core-http-browser-internal", ], "exclude": [ "target/**/*", diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index b879cf6f716d..a43e8cbee8a9 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -169,7 +169,7 @@ export interface ChromeProjectNavigationNode extends NodeDefinitionBase { /** Optional title. If not provided and a "link" is provided the title will be the Deep link title */ title: string; /** Path in the tree of the node */ - path: string[]; + path: string; /** App id or deeplink id */ deepLink?: ChromeNavLink; /** @@ -178,9 +178,14 @@ export interface ChromeProjectNavigationNode extends NodeDefinitionBase { */ children?: ChromeProjectNavigationNode[]; /** - * Flag to indicate if the node is currently active. + * Handler to render the node item with custom JSX. This handler is added to render the `children` of + * the Navigation.Item component when React components are used to declare the navigation tree. */ - isActive?: boolean; + renderItem?: () => React.ReactNode; + /** + * Flag to indicate if the node is an "external" cloud link + */ + isElasticInternalLink?: boolean; } /** @public */ diff --git a/packages/core/deprecations/core-deprecations-browser-internal/src/deprecations_service.ts b/packages/core/deprecations/core-deprecations-browser-internal/src/deprecations_service.ts index edaf5f7f27be..6dd78c8525f5 100644 --- a/packages/core/deprecations/core-deprecations-browser-internal/src/deprecations_service.ts +++ b/packages/core/deprecations/core-deprecations-browser-internal/src/deprecations_service.ts @@ -8,13 +8,13 @@ import type { CoreService } from '@kbn/core-base-browser-internal'; import type { DeprecationsServiceStart } from '@kbn/core-deprecations-browser'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { DeprecationsClient } from './deprecations_client'; export class DeprecationsService implements CoreService { public setup(): void {} - public start({ http }: { http: HttpStart }): DeprecationsServiceStart { + public start({ http }: { http: InternalHttpStart }): DeprecationsServiceStart { const deprecationsClient = new DeprecationsClient({ http }); return { diff --git a/packages/core/deprecations/core-deprecations-browser-internal/tsconfig.json b/packages/core/deprecations/core-deprecations-browser-internal/tsconfig.json index 8c7dde1c84e0..38fda3fdccf4 100644 --- a/packages/core/deprecations/core-deprecations-browser-internal/tsconfig.json +++ b/packages/core/deprecations/core-deprecations-browser-internal/tsconfig.json @@ -16,7 +16,8 @@ "@kbn/core-http-browser", "@kbn/core-http-browser-mocks", "@kbn/core-deprecations-common", - "@kbn/core-deprecations-browser" + "@kbn/core-deprecations-browser", + "@kbn/core-http-browser-internal" ], "exclude": [ "target/**/*", diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts index 45d88445df41..039f1ff8ccb8 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts @@ -40,7 +40,7 @@ test('set correct defaults', () => { "idleSocketTimeout": "PT1M", "ignoreVersionMismatch": false, "maxIdleSockets": 256, - "maxSockets": Infinity, + "maxSockets": 800, "password": undefined, "pingTimeout": "PT30S", "requestHeadersWhitelist": Array [ diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts index b1a4712a7949..d7f426ec28e5 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts @@ -40,7 +40,7 @@ export const configSchema = schema.object({ hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })], { defaultValue: 'http://localhost:9200', }), - maxSockets: schema.number({ defaultValue: Infinity, min: 1 }), + maxSockets: schema.number({ defaultValue: 800, min: 1 }), maxIdleSockets: schema.number({ defaultValue: 256, min: 1 }), idleSocketTimeout: schema.duration({ defaultValue: '60s' }), compression: schema.boolean({ defaultValue: false }), diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/ensure_es_version.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/ensure_es_version.test.ts index dccb2722309c..ec22185a2962 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/ensure_es_version.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/ensure_es_version.test.ts @@ -42,6 +42,12 @@ describe('mapNodesVersionCompatibility', () => { return { nodes: { 'node-without-http': { version, ip: 'ip' } } } as any; } + it('returns isCompatible=false with a single node with non-SemVer-compliant version', async () => { + const nodesInfo = createNodes('615c621a8416c444941dc97b142a0122d5c878d0'); + const result = await mapNodesVersionCompatibility(nodesInfo, KIBANA_VERSION, false); + expect(result.isCompatible).toBe(false); + }); + it('returns isCompatible=true with a single node that matches', async () => { const nodesInfo = createNodes('5.1.0'); const result = await mapNodesVersionCompatibility(nodesInfo, KIBANA_VERSION, false); diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.test.ts index 3aa93435982d..867b843c1aae 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.test.ts @@ -22,6 +22,12 @@ describe('plugins/elasticsearch', () => { it('when majors are equal, but ES minor is less than Kibana minor', () => { expect(esVersionCompatibleWithKibana('1.0.0', '1.1.0')).toBe(false); }); + + it('ES is not SemVer-compliant', () => { + expect( + esVersionCompatibleWithKibana('615c621a8416c444941dc97b142a0122d5c878d0', '1.1.0') + ).toBe(false); + }); }); describe('returns true', () => { diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.ts index accf4edc0226..8732d0df2fb4 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/version_check/es_kibana_version_compatability.ts @@ -14,6 +14,10 @@ import semver, { coerce } from 'semver'; * 2. Older versions of ES won't work with newer versions of Kibana. */ export function esVersionCompatibleWithKibana(esVersion: string, kibanaVersion: string) { + if (!semver.valid(esVersion)) { + return false; + } + const esVersionNumbers = { major: semver.major(esVersion), minor: semver.minor(esVersion), diff --git a/packages/core/http/core-http-browser-internal/index.ts b/packages/core/http/core-http-browser-internal/index.ts index 3baa45b8bcdf..0b747b6261eb 100644 --- a/packages/core/http/core-http-browser-internal/index.ts +++ b/packages/core/http/core-http-browser-internal/index.ts @@ -8,3 +8,4 @@ export { BasePath } from './src/base_path'; export { HttpService } from './src/http_service'; +export type { InternalHttpSetup, InternalHttpStart } from './src/types'; diff --git a/packages/core/http/core-http-browser-internal/src/anonymous_paths_service.test.ts b/packages/core/http/core-http-browser-internal/src/anonymous_paths_service.test.ts index dff9c4719fef..181641700d4d 100644 --- a/packages/core/http/core-http-browser-internal/src/anonymous_paths_service.test.ts +++ b/packages/core/http/core-http-browser-internal/src/anonymous_paths_service.test.ts @@ -12,13 +12,13 @@ import { BasePath } from './base_path'; describe('#setup()', () => { describe('#register', () => { it(`allows paths that don't start with /`, () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('bar'); }); it(`allows paths that end with '/'`, () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar/'); }); @@ -26,70 +26,70 @@ describe('#setup()', () => { describe('#isAnonymous', () => { it('returns true for registered paths', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true); }); it('returns true for paths registered with a trailing slash, but call "isAnonymous" with no trailing slash', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar/'); expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true); }); it('returns true for paths registered without a trailing slash, but call "isAnonymous" with a trailing slash', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/foo/bar/')).toBe(true); }); it('returns true for paths registered without a starting slash', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('bar'); expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true); }); it('returns true for paths registered with a starting slash', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true); }); it('when there is no basePath and calling "isAnonymous" without a starting slash, returns true for paths registered with a starting slash', () => { - const basePath = new BasePath('/'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('bar')).toBe(true); }); it('when there is no basePath and calling "isAnonymous" with a starting slash, returns true for paths registered with a starting slash', () => { - const basePath = new BasePath('/'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/bar')).toBe(true); }); it('returns true for paths whose capitalization is different', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/BAR'); expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true); }); it('returns false for other paths', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/foo/foo')).toBe(false); }); it('returns false for sub-paths of registered paths', () => { - const basePath = new BasePath('/foo'); + const basePath = new BasePath({ basePath: '/foo' }); const anonymousPaths = new AnonymousPathsService().setup({ basePath }); anonymousPaths.register('/bar'); expect(anonymousPaths.isAnonymous('/foo/bar/baz')).toBe(false); diff --git a/packages/core/http/core-http-browser-internal/src/base_path.test.ts b/packages/core/http/core-http-browser-internal/src/base_path.test.ts index cfca537c0f5b..ebf70c48d79c 100644 --- a/packages/core/http/core-http-browser-internal/src/base_path.test.ts +++ b/packages/core/http/core-http-browser-internal/src/base_path.test.ts @@ -10,35 +10,31 @@ import { BasePath } from './base_path'; describe('BasePath', () => { describe('#get()', () => { - it('returns an empty string if no basePath not provided', () => { - expect(new BasePath().get()).toBe(''); - }); - it('returns basePath value if provided', () => { - expect(new BasePath('/foo').get()).toBe('/foo'); + expect(new BasePath({ basePath: '/foo' }).get()).toBe('/foo'); }); describe('#prepend()', () => { it('adds the base path to the path if it is relative and starts with a slash', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.prepend('/a/b')).toBe('/foo/bar/a/b'); }); it('leaves the query string and hash of path unchanged', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.prepend('/a/b?x=y#c/d/e')).toBe('/foo/bar/a/b?x=y#c/d/e'); }); it('returns the path unchanged if it does not start with a slash', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.prepend('a/b')).toBe('a/b'); }); it('returns the path unchanged it it has a hostname', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.prepend('http://localhost:5601/a/b')).toBe('http://localhost:5601/a/b'); }); @@ -46,19 +42,19 @@ describe('BasePath', () => { describe('#remove()', () => { it('removes the basePath if relative path starts with it', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.remove('/foo/bar/a/b')).toBe('/a/b'); }); it('leaves query string and hash intact', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.remove('/foo/bar/a/b?c=y#1234')).toBe('/a/b?c=y#1234'); }); it('ignores urls with hostnames', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.remove('http://localhost:5601/foo/bar/a/b')).toBe( 'http://localhost:5601/foo/bar/a/b' @@ -66,13 +62,13 @@ describe('BasePath', () => { }); it('returns slash if path is just basePath', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.remove('/foo/bar')).toBe('/'); }); it('returns full path if basePath is not its own segment', () => { - const basePath = new BasePath('/foo/bar'); + const basePath = new BasePath({ basePath: '/foo/bar' }); expect(basePath.remove('/foo/barhop')).toBe('/foo/barhop'); }); @@ -81,20 +77,39 @@ describe('BasePath', () => { describe('serverBasePath', () => { it('defaults to basePath', () => { - expect(new BasePath('/foo/bar').serverBasePath).toEqual('/foo/bar'); + expect(new BasePath({ basePath: '/foo/bar' }).serverBasePath).toEqual('/foo/bar'); }); it('returns value when passed into constructor', () => { - expect(new BasePath('/foo/bar', '/foo').serverBasePath).toEqual('/foo'); + expect(new BasePath({ basePath: '/foo/bar', serverBasePath: '/foo' }).serverBasePath).toEqual( + '/foo' + ); }); }); describe('publicBaseUrl', () => { it('returns value passed into construtor', () => { - expect(new BasePath('/foo/bar', '/foo').publicBaseUrl).toEqual(undefined); - expect(new BasePath('/foo/bar', '/foo', 'http://myhost.com/foo').publicBaseUrl).toEqual( - 'http://myhost.com/foo' + expect(new BasePath({ basePath: '/foo/bar' }).publicBaseUrl).toEqual(undefined); + expect( + new BasePath({ basePath: '/foo/bar', publicBaseUrl: 'http://myhost.com/foo' }).publicBaseUrl + ).toEqual('http://myhost.com/foo'); + }); + }); + + describe('assetsHrefBase', () => { + it('default to the serverBasePath if unspecified', () => { + expect(new BasePath({ basePath: '/foo/bar', serverBasePath: '/foo' }).assetsHrefBase).toEqual( + '/foo' ); }); + it('returns the correct value when explicitly set', () => { + expect( + new BasePath({ + basePath: '/foo/bar', + serverBasePath: '/foo', + assetsHrefBase: 'http://cdn/foo', + }).assetsHrefBase + ).toEqual('http://cdn/foo'); + }); }); }); diff --git a/packages/core/http/core-http-browser-internal/src/base_path.ts b/packages/core/http/core-http-browser-internal/src/base_path.ts index 63fb8917421e..4eaa71f8290d 100644 --- a/packages/core/http/core-http-browser-internal/src/base_path.ts +++ b/packages/core/http/core-http-browser-internal/src/base_path.ts @@ -10,18 +10,36 @@ import { IBasePath } from '@kbn/core-http-browser'; import { modifyUrl } from '@kbn/std'; export class BasePath implements IBasePath { - constructor( - private readonly basePath: string = '', - public readonly serverBasePath: string = basePath, - public readonly publicBaseUrl?: string - ) {} + private readonly basePath: string; + public readonly serverBasePath: string; + public readonly assetsHrefBase: string; + public readonly publicBaseUrl?: string; + + constructor({ + basePath, + serverBasePath, + assetsHrefBase, + publicBaseUrl, + }: { + basePath: string; + serverBasePath?: string; + assetsHrefBase?: string; + publicBaseUrl?: string; + }) { + this.basePath = basePath; + this.serverBasePath = serverBasePath ?? this.basePath; + this.assetsHrefBase = assetsHrefBase ?? this.serverBasePath; + this.publicBaseUrl = publicBaseUrl; + } public get = () => { return this.basePath; }; public prepend = (path: string): string => { - if (!this.basePath) return path; + if (!this.basePath) { + return path; + } return modifyUrl(path, (parts) => { if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) { parts.pathname = `${this.basePath}${parts.pathname}`; diff --git a/packages/core/http/core-http-browser-internal/src/fetch.test.ts b/packages/core/http/core-http-browser-internal/src/fetch.test.ts index b46a34f768b6..d4f37a6601b6 100644 --- a/packages/core/http/core-http-browser-internal/src/fetch.test.ts +++ b/packages/core/http/core-http-browser-internal/src/fetch.test.ts @@ -27,7 +27,7 @@ const BASE_PATH = 'http://localhost/myBase'; describe('Fetch', () => { const executionContextMock = executionContextServiceMock.createSetupContract(); const fetchInstance = new Fetch({ - basePath: new BasePath(BASE_PATH), + basePath: new BasePath({ basePath: BASE_PATH }), kibanaVersion: 'VERSION', buildNumber: 1234, executionContext: executionContextMock, diff --git a/packages/core/http/core-http-browser-internal/src/http_service.ts b/packages/core/http/core-http-browser-internal/src/http_service.ts index d097dc7a14c9..a054ca3a7c11 100644 --- a/packages/core/http/core-http-browser-internal/src/http_service.ts +++ b/packages/core/http/core-http-browser-internal/src/http_service.ts @@ -10,8 +10,9 @@ import type { CoreService } from '@kbn/core-base-browser-internal'; import type { ExecutionContextSetup } from '@kbn/core-execution-context-browser'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; import type { FatalErrorsSetup } from '@kbn/core-fatal-errors-browser'; -import type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpSetup, InternalHttpStart } from './types'; import { BasePath } from './base_path'; +import { StaticAssets } from './static_assets'; import { AnonymousPathsService } from './anonymous_paths_service'; import { LoadingCountService } from './loading_count_service'; import { Fetch } from './fetch'; @@ -24,19 +25,23 @@ interface HttpDeps { } /** @internal */ -export class HttpService implements CoreService { +export class HttpService implements CoreService { private readonly anonymousPaths = new AnonymousPathsService(); private readonly loadingCount = new LoadingCountService(); - private service?: HttpSetup; + private service?: InternalHttpSetup; - public setup({ injectedMetadata, fatalErrors, executionContext }: HttpDeps): HttpSetup { + public setup({ injectedMetadata, fatalErrors, executionContext }: HttpDeps): InternalHttpSetup { const kibanaVersion = injectedMetadata.getKibanaVersion(); const buildNumber = injectedMetadata.getKibanaBuildNumber(); - const basePath = new BasePath( - injectedMetadata.getBasePath(), - injectedMetadata.getServerBasePath(), - injectedMetadata.getPublicBaseUrl() - ); + const basePath = new BasePath({ + basePath: injectedMetadata.getBasePath(), + serverBasePath: injectedMetadata.getServerBasePath(), + publicBaseUrl: injectedMetadata.getPublicBaseUrl(), + assetsHrefBase: injectedMetadata.getAssetsHrefBase(), + }); + const staticAssets = new StaticAssets({ + assetsHrefBase: injectedMetadata.getAssetsHrefBase(), + }); const fetchService = new Fetch({ basePath, kibanaVersion, buildNumber, executionContext }); const loadingCount = this.loadingCount.setup({ fatalErrors }); @@ -44,6 +49,7 @@ export class HttpService implements CoreService { this.service = { basePath, + staticAssets, anonymousPaths: this.anonymousPaths.setup({ basePath }), externalUrl: new ExternalUrlService().setup({ injectedMetadata, location: window.location }), intercept: fetchService.intercept.bind(fetchService), diff --git a/packages/core/http/core-http-browser-internal/src/static_assets.test.ts b/packages/core/http/core-http-browser-internal/src/static_assets.test.ts new file mode 100644 index 000000000000..c9083e2fd017 --- /dev/null +++ b/packages/core/http/core-http-browser-internal/src/static_assets.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { StaticAssets } from './static_assets'; + +describe('StaticAssets', () => { + describe('#getPluginAssetHref()', () => { + it('returns the expected value when the base is a path', () => { + const staticAssets = new StaticAssets({ assetsHrefBase: '/base-path' }); + expect(staticAssets.getPluginAssetHref('foo', 'path/to/img.gif')).toEqual( + '/base-path/plugins/foo/assets/path/to/img.gif' + ); + }); + + it('returns the expected value when the base is a full url', () => { + const staticAssets = new StaticAssets({ assetsHrefBase: 'http://cdn/cdn-base-path' }); + expect(staticAssets.getPluginAssetHref('bar', 'path/to/img.gif')).toEqual( + 'http://cdn/cdn-base-path/plugins/bar/assets/path/to/img.gif' + ); + }); + + it('removes leading slash from the', () => { + const staticAssets = new StaticAssets({ assetsHrefBase: '/base-path' }); + expect(staticAssets.getPluginAssetHref('dolly', '/path/for/something.svg')).toEqual( + '/base-path/plugins/dolly/assets/path/for/something.svg' + ); + }); + }); +}); diff --git a/packages/core/http/core-http-browser-internal/src/static_assets.ts b/packages/core/http/core-http-browser-internal/src/static_assets.ts new file mode 100644 index 000000000000..02218e3d375d --- /dev/null +++ b/packages/core/http/core-http-browser-internal/src/static_assets.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { InternalStaticAssets } from './types'; + +export class StaticAssets implements InternalStaticAssets { + public readonly assetsHrefBase: string; + + constructor({ assetsHrefBase }: { assetsHrefBase: string }) { + this.assetsHrefBase = assetsHrefBase.endsWith('/') + ? assetsHrefBase.slice(0, -1) + : assetsHrefBase; + } + + getPluginAssetHref(pluginName: string, assetPath: string): string { + if (assetPath.startsWith('/')) { + assetPath = assetPath.slice(1); + } + return `${this.assetsHrefBase}/plugins/${pluginName}/assets/${assetPath}`; + } +} diff --git a/packages/core/http/core-http-browser-internal/src/types.ts b/packages/core/http/core-http-browser-internal/src/types.ts new file mode 100644 index 000000000000..83e47ff0b726 --- /dev/null +++ b/packages/core/http/core-http-browser-internal/src/types.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; + +export type InternalHttpSetup = Omit & { + staticAssets: InternalStaticAssets; +}; + +export type InternalHttpStart = Omit & { + staticAssets: InternalStaticAssets; +}; + +export interface InternalStaticAssets { + getPluginAssetHref(pluginId: string, assetPath: string): string; +} diff --git a/packages/core/http/core-http-browser-mocks/src/base_path.mock.ts b/packages/core/http/core-http-browser-mocks/src/base_path.mock.ts index 9d36d4e33c10..ad27677dd41f 100644 --- a/packages/core/http/core-http-browser-mocks/src/base_path.mock.ts +++ b/packages/core/http/core-http-browser-mocks/src/base_path.mock.ts @@ -11,13 +11,15 @@ import type { IBasePath } from '@kbn/core-http-browser'; const createBasePathMock = ({ publicBaseUrl = '/', serverBasePath = '/', -}: { publicBaseUrl?: string; serverBasePath?: string } = {}) => { + assetsHrefBase = '/', +}: { publicBaseUrl?: string; serverBasePath?: string; assetsHrefBase?: string } = {}) => { const mock: jest.Mocked = { prepend: jest.fn(), get: jest.fn(), remove: jest.fn(), publicBaseUrl, serverBasePath, + assetsHrefBase, }; return mock; diff --git a/packages/core/http/core-http-browser-mocks/src/http_service.mock.ts b/packages/core/http/core-http-browser-mocks/src/http_service.mock.ts index 553e09875ae9..45b445b39fad 100644 --- a/packages/core/http/core-http-browser-mocks/src/http_service.mock.ts +++ b/packages/core/http/core-http-browser-mocks/src/http_service.mock.ts @@ -29,7 +29,10 @@ const createServiceMock = ({ patch: jest.fn(), delete: jest.fn(), options: jest.fn(), - basePath: new BasePath(basePath, undefined, publicBaseUrl), + basePath: new BasePath({ + basePath, + publicBaseUrl, + }), anonymousPaths: { register: jest.fn(), isAnonymous: jest.fn(), @@ -38,6 +41,9 @@ const createServiceMock = ({ isInternalUrl: jest.fn(), validateUrl: jest.fn(), }, + staticAssets: { + getPluginAssetHref: jest.fn(), + }, addLoadingCountSource: jest.fn(), getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)), intercept: jest.fn(), diff --git a/packages/core/http/core-http-browser/index.ts b/packages/core/http/core-http-browser/index.ts index 5f733d720c17..de1e201132d3 100644 --- a/packages/core/http/core-http-browser/index.ts +++ b/packages/core/http/core-http-browser/index.ts @@ -12,6 +12,7 @@ export type { IBasePath, IExternalUrl, IAnonymousPaths, + IStaticAssets, HttpHeadersInit, HttpRequestInit, HttpFetchQuery, diff --git a/packages/core/http/core-http-browser/src/types.ts b/packages/core/http/core-http-browser/src/types.ts index e9b3d2ecdd66..5d270d77afc2 100644 --- a/packages/core/http/core-http-browser/src/types.ts +++ b/packages/core/http/core-http-browser/src/types.ts @@ -19,6 +19,12 @@ export interface HttpSetup { */ basePath: IBasePath; + /** + * APIs for creating hrefs to static assets. + * See {@link IStaticAssets} + */ + staticAssets: IStaticAssets; + /** * APIs for denoting certain paths for not requiring authentication */ @@ -96,6 +102,12 @@ export interface IBasePath { */ readonly serverBasePath: string; + /** + * Href (hypertext reference) intended to be used as the base for constructing + * other hrefs to static assets. + */ + readonly assetsHrefBase: string; + /** * The server's publicly exposed base URL, if configured. Includes protocol, host, port (optional) and the * {@link IBasePath.serverBasePath}. @@ -105,6 +117,7 @@ export interface IBasePath { */ readonly publicBaseUrl?: string; } + /** * APIs for working with external URLs. * @@ -130,6 +143,25 @@ export interface IExternalUrl { validateUrl(relativeOrAbsoluteUrl: string): URL | null; } +/** + * APIs for creating hrefs to static assets. + * + * @public + */ +export interface IStaticAssets { + /** + * Gets the full href to the current plugin's asset, + * given its path relative to the plugin's `public/assets` folder. + * + * @example + * ```ts + * // I want to retrieve the href for the asset stored under `my_plugin/public/assets/some_folder/asset.png`: + * const assetHref = core.http.statisAssets.getPluginAssetHref('some_folder/asset.png'); + * ``` + */ + getPluginAssetHref(assetPath: string): string; +} + /** * APIs for denoting paths as not requiring authentication */ @@ -318,10 +350,13 @@ export interface HttpHandler { path: string, options: HttpFetchOptions & { asResponse: true } ): Promise>; + (options: HttpFetchOptionsWithPath & { asResponse: true }): Promise< HttpResponse >; + (path: string, options?: HttpFetchOptions): Promise; + (options: HttpFetchOptionsWithPath): Promise; } @@ -368,6 +403,7 @@ export interface HttpInterceptorResponseError extends HttpResponse { request: Readonly; error: Error | IHttpFetchError; } + /** @public */ export interface HttpInterceptorRequestError { fetchOptions: Readonly; @@ -429,6 +465,7 @@ export interface HttpInterceptor { export interface IHttpInterceptController { /** Whether or not this chain has been halted. */ halted: boolean; + /** Halt the request Promise chain and do not process further interceptors or response handlers. */ halt(): void; } diff --git a/packages/core/http/core-http-server-internal/src/http_config.ts b/packages/core/http/core-http-server-internal/src/http_config.ts index 201770eba269..eba98e725e80 100644 --- a/packages/core/http/core-http-server-internal/src/http_config.ts +++ b/packages/core/http/core-http-server-internal/src/http_config.ts @@ -178,9 +178,10 @@ const configSchema = schema.object( versioned: schema.object({ /** - * Which handler resolution algo to use: "newest" or "oldest". + * Which handler resolution algo to use for public routes: "newest" or "oldest". * - * @note in development we have an additional option "none" which is also the default. + * @note Internal routes always require a version to be specified. + * @note in development we have an additional option "none" which is also the default in dev. * This prevents any fallbacks and requires that a version specified. * Useful for ensuring that a given client always specifies a version. */ diff --git a/packages/core/http/core-http-server-internal/src/http_server.test.mocks.ts b/packages/core/http/core-http-server-internal/src/http_server.test.mocks.ts new file mode 100644 index 000000000000..6b0eadee96f3 --- /dev/null +++ b/packages/core/http/core-http-server-internal/src/http_server.test.mocks.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const setTlsConfigMock = jest.fn(); + +jest.doMock('@kbn/server-http-tools', () => { + const actual = jest.requireActual('@kbn/server-http-tools'); + return { + ...actual, + setTlsConfig: setTlsConfigMock, + createServer: jest.fn(actual.createServer), + }; +}); diff --git a/packages/core/http/core-http-server-internal/src/http_server.test.ts b/packages/core/http/core-http-server-internal/src/http_server.test.ts index f188d7a06552..d50156df94ed 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.test.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.test.ts @@ -6,20 +6,12 @@ * Side Public License, v 1. */ -jest.mock('@kbn/server-http-tools', () => { - const module = jest.requireActual('@kbn/server-http-tools'); - return { - ...module, - createServer: jest.fn(module.createServer), - }; -}); - +import { setTlsConfigMock } from './http_server.test.mocks'; import { Server } from 'http'; import { rm, mkdtemp, readFile, writeFile } from 'fs/promises'; import supertest from 'supertest'; import { omit } from 'lodash'; import { join } from 'path'; - import { ByteSizeValue, schema } from '@kbn/config-schema'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import type { @@ -37,7 +29,7 @@ import { HttpServer } from './http_server'; import { Readable } from 'stream'; import { KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; import moment from 'moment'; -import { of } from 'rxjs'; +import { of, Observable, BehaviorSubject } from 'rxjs'; const routerOptions: RouterOptions = { isDev: false, @@ -52,8 +44,12 @@ const cookieOptions = { }; let server: HttpServer; + let config: HttpConfig; +let config$: Observable; + let configWithSSL: HttpConfig; +let configWithSSL$: Observable; const loggingService = loggingSystemMock.create(); const logger = loggingService.get(); @@ -82,8 +78,10 @@ beforeEach(() => { cors: { enabled: false, }, + cdn: {}, shutdownTimeout: moment.duration(500, 'ms'), } as any; + config$ = of(config); configWithSSL = { ...config, @@ -96,6 +94,7 @@ beforeEach(() => { redirectHttpFromPort: config.port + 1, }, } as HttpConfig; + configWithSSL$ = of(configWithSSL); server = new HttpServer(loggingService, 'tests', of(config.shutdownTimeout)); }); @@ -108,7 +107,7 @@ afterEach(async () => { test('log listening address after started', async () => { expect(server.isListening()).toBe(false); - await server.setup(config); + await server.setup({ config$ }); await server.start(); expect(server.isListening()).toBe(true); @@ -124,7 +123,7 @@ test('log listening address after started', async () => { test('log listening address after started when configured with BasePath and rewriteBasePath = false', async () => { expect(server.isListening()).toBe(false); - await server.setup({ ...config, basePath: '/bar', rewriteBasePath: false }); + await server.setup({ config$: of({ ...config, basePath: '/bar', rewriteBasePath: false }) }); await server.start(); expect(server.isListening()).toBe(true); @@ -140,7 +139,7 @@ test('log listening address after started when configured with BasePath and rewr test('log listening address after started when configured with BasePath and rewriteBasePath = true', async () => { expect(server.isListening()).toBe(false); - await server.setup({ ...config, basePath: '/bar', rewriteBasePath: true }); + await server.setup({ config$: of({ ...config, basePath: '/bar', rewriteBasePath: true }) }); await server.start(); expect(server.isListening()).toBe(true); @@ -156,7 +155,7 @@ test('log listening address after started when configured with BasePath and rewr test('does not allow router registration after server is listening', async () => { expect(server.isListening()).toBe(false); - const { registerRouter } = await server.setup(config); + const { registerRouter } = await server.setup({ config$ }); const router1 = new Router('/foo', logger, enhanceWithContext, routerOptions); expect(() => registerRouter(router1)).not.toThrowError(); @@ -174,7 +173,7 @@ test('does not allow router registration after server is listening', async () => test('allows router registration after server is listening via `registerRouterAfterListening`', async () => { expect(server.isListening()).toBe(false); - const { registerRouterAfterListening } = await server.setup(config); + const { registerRouterAfterListening } = await server.setup({ config$ }); const router1 = new Router('/foo', logger, enhanceWithContext, routerOptions); expect(() => registerRouterAfterListening(router1)).not.toThrowError(); @@ -204,7 +203,7 @@ test('valid params', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -234,7 +233,7 @@ test('invalid params', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -269,7 +268,7 @@ test('valid query', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -299,7 +298,7 @@ test('invalid query', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -334,7 +333,7 @@ test('valid body', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -372,7 +371,7 @@ test('valid body with validate function', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -415,7 +414,7 @@ test('not inline validation - specifying params', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -458,7 +457,7 @@ test('not inline validation - specifying validation handler', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -508,7 +507,7 @@ test('not inline handler - KibanaRequest', async () => { handler ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -557,7 +556,7 @@ test('not inline handler - RequestHandler', async () => { handler ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -591,7 +590,7 @@ test('invalid body', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -626,7 +625,7 @@ test('handles putting', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -657,7 +656,7 @@ test('handles deleting', async () => { } ); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); registerRouter(router); await server.start(); @@ -687,7 +686,9 @@ describe('with `basepath: /bar` and `rewriteBasePath: false`', () => { res.ok({ body: 'value:/foo' }) ); - const { registerRouter, server: innerServer } = await server.setup(configWithBasePath); + const { registerRouter, server: innerServer } = await server.setup({ + config$: of(configWithBasePath), + }); registerRouter(router); await server.start(); @@ -742,7 +743,9 @@ describe('with `basepath: /bar` and `rewriteBasePath: true`', () => { res.ok({ body: 'value:/foo' }) ); - const { registerRouter, server: innerServer } = await server.setup(configWithBasePath); + const { registerRouter, server: innerServer } = await server.setup({ + config$: of(configWithBasePath), + }); registerRouter(router); await server.start(); @@ -789,7 +792,7 @@ test('with defined `redirectHttpFromPort`', async () => { const router = new Router('/', logger, enhanceWithContext, routerOptions); router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'value:/' })); - const { registerRouter } = await server.setup(configWithSSL); + const { registerRouter } = await server.setup({ config$: configWithSSL$ }); registerRouter(router); await server.start(); @@ -800,7 +803,7 @@ test('returns server and connection options on start', async () => { ...config, port: 12345, }; - const { server: innerServer } = await server.setup(configWithPort); + const { server: innerServer } = await server.setup({ config$: of(configWithPort) }); expect(innerServer).toBeDefined(); expect(innerServer).toBe((server as any).server); @@ -814,7 +817,7 @@ test('throws an error if starts without set up', async () => { test('allows attaching metadata to attach meta-data tag strings to a route', async () => { const tags = ['my:tag']; - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.get({ path: '/with-tags', validate: false, options: { tags } }, (context, req, res) => @@ -833,7 +836,7 @@ test('allows attaching metadata to attach meta-data tag strings to a route', asy test('allows declaring route access to flag a route as public or internal', async () => { const access = 'internal'; - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.get({ path: '/with-access', validate: false, options: { access } }, (context, req, res) => @@ -851,7 +854,7 @@ test('allows declaring route access to flag a route as public or internal', asyn }); test(`sets access flag to 'internal' if not defined`, async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.get({ path: '/internal/foo', validate: false }, (context, req, res) => @@ -882,7 +885,7 @@ test(`sets access flag to 'internal' if not defined`, async () => { }); test('exposes route details of incoming request to a route handler', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: req.route })); @@ -906,7 +909,9 @@ test('exposes route details of incoming request to a route handler', async () => describe('conditional compression', () => { async function setupServer(innerConfig: HttpConfig) { - const { registerRouter, server: innerServer } = await server.setup(innerConfig); + const { registerRouter, server: innerServer } = await server.setup({ + config$: of(innerConfig), + }); const router = new Router('', logger, enhanceWithContext, routerOptions); // we need the large body here so that compression would normally be used const largeRequest = { @@ -1011,8 +1016,10 @@ describe('conditional compression', () => { describe('response headers', () => { test('allows to configure "keep-alive" header', async () => { const { registerRouter, server: innerServer } = await server.setup({ - ...config, - keepaliveTimeout: 100_000, + config$: of({ + ...config, + keepaliveTimeout: 100_000, + }), }); const router = new Router('', logger, enhanceWithContext, routerOptions); @@ -1030,7 +1037,7 @@ describe('response headers', () => { }); test('default headers', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: req.route })); @@ -1052,7 +1059,7 @@ describe('response headers', () => { }); test('exposes route details of incoming request to a route handler (POST + payload options)', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1092,7 +1099,7 @@ test('exposes route details of incoming request to a route handler (POST + paylo describe('body options', () => { test('should reject the request because the Content-Type in the request is not valid', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1114,7 +1121,7 @@ describe('body options', () => { }); test('should reject the request because the payload is too large', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1136,7 +1143,7 @@ describe('body options', () => { }); test('should not parse the content in the request', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1165,7 +1172,7 @@ describe('body options', () => { describe('timeout options', () => { describe('payload timeout', () => { test('POST routes set the payload timeout', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1199,7 +1206,7 @@ describe('timeout options', () => { }); test('DELETE routes set the payload timeout', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.delete( @@ -1232,7 +1239,7 @@ describe('timeout options', () => { }); test('PUT routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.put( @@ -1265,7 +1272,7 @@ describe('timeout options', () => { }); test('PATCH routes set the payload timeout and automatically adjusts the idle socket timeout', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.patch( @@ -1301,8 +1308,10 @@ describe('timeout options', () => { describe('idleSocket timeout', () => { test('uses server socket timeout when not specified in the route', async () => { const { registerRouter, server: innerServer } = await server.setup({ - ...config, - socketTimeout: 11000, + config$: of({ + ...config, + socketTimeout: 11000, + }), }); const router = new Router('', logger, enhanceWithContext, routerOptions); @@ -1334,8 +1343,10 @@ describe('timeout options', () => { test('sets the socket timeout when specified in the route', async () => { const { registerRouter, server: innerServer } = await server.setup({ - ...config, - socketTimeout: 11000, + config$: of({ + ...config, + socketTimeout: 11000, + }), }); const router = new Router('', logger, enhanceWithContext, routerOptions); @@ -1367,7 +1378,7 @@ describe('timeout options', () => { }); test('idleSocket timeout can be smaller than the payload timeout', async () => { - const { registerRouter } = await server.setup(config); + const { registerRouter } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.post( @@ -1394,7 +1405,7 @@ describe('timeout options', () => { }); test('should return a stream in the body', async () => { - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$ }); const router = new Router('', logger, enhanceWithContext, routerOptions); router.put( @@ -1420,8 +1431,10 @@ test('should return a stream in the body', async () => { test('closes sockets on timeout', async () => { const { registerRouter, server: innerServer } = await server.setup({ - ...config, - socketTimeout: 1000, + config$: of({ + ...config, + socketTimeout: 1000, + }), }); const router = new Router('', logger, enhanceWithContext, routerOptions); @@ -1445,14 +1458,14 @@ test('closes sockets on timeout', async () => { describe('setup contract', () => { describe('#createSessionStorage', () => { test('creates session storage factory', async () => { - const { createCookieSessionStorageFactory } = await server.setup(config); + const { createCookieSessionStorageFactory } = await server.setup({ config$ }); const sessionStorageFactory = await createCookieSessionStorageFactory(cookieOptions); expect(sessionStorageFactory.asScoped).toBeDefined(); }); test('creates session storage factory only once', async () => { - const { createCookieSessionStorageFactory } = await server.setup(config); + const { createCookieSessionStorageFactory } = await server.setup({ config$ }); const create = async () => await createCookieSessionStorageFactory(cookieOptions); await create(); @@ -1460,7 +1473,7 @@ describe('setup contract', () => { }); test('does not throw if called after stop', async () => { - const { createCookieSessionStorageFactory } = await server.setup(config); + const { createCookieSessionStorageFactory } = await server.setup({ config$ }); await server.stop(); expect(() => { createCookieSessionStorageFactory(cookieOptions); @@ -1470,7 +1483,7 @@ describe('setup contract', () => { describe('#getServerInfo', () => { test('returns correct information', async () => { - let { getServerInfo } = await server.setup(config); + let { getServerInfo } = await server.setup({ config$ }); expect(getServerInfo()).toEqual({ hostname: '127.0.0.1', @@ -1480,10 +1493,12 @@ describe('setup contract', () => { }); ({ getServerInfo } = await server.setup({ - ...config, - port: 12345, - name: 'custom-name', - host: 'localhost', + config$: of({ + ...config, + port: 12345, + name: 'custom-name', + host: 'localhost', + }), })); expect(getServerInfo()).toEqual({ @@ -1495,7 +1510,7 @@ describe('setup contract', () => { }); test('returns correct protocol when ssl is enabled', async () => { - const { getServerInfo } = await server.setup(configWithSSL); + const { getServerInfo } = await server.setup({ config$: configWithSSL$ }); expect(getServerInfo().protocol).toEqual('https'); }); @@ -1516,7 +1531,7 @@ describe('setup contract', () => { }); test('registers routes with expected options', async () => { - const { registerStaticDir } = await server.setup(config); + const { registerStaticDir } = await server.setup({ config$ }); expect(createServer).toHaveBeenCalledTimes(1); const [{ value: myServer }] = (createServer as jest.Mock).mock.results; jest.spyOn(myServer, 'route'); @@ -1539,7 +1554,7 @@ describe('setup contract', () => { }); test('does not throw if called after stop', async () => { - const { registerStaticDir } = await server.setup(config); + const { registerStaticDir } = await server.setup({ config$ }); await server.stop(); expect(() => { registerStaticDir('/path1/{path*}', '/path/to/resource'); @@ -1547,7 +1562,7 @@ describe('setup contract', () => { }); test('returns correct headers for static assets', async () => { - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', assetFolder); @@ -1561,7 +1576,7 @@ describe('setup contract', () => { }); test('returns compressed version if present', async () => { - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', assetFolder); @@ -1577,7 +1592,7 @@ describe('setup contract', () => { }); test('returns uncompressed version if compressed asset is not available', async () => { - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', assetFolder); @@ -1593,7 +1608,7 @@ describe('setup contract', () => { }); test('returns a 304 if etag value matches', async () => { - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', assetFolder); @@ -1612,7 +1627,7 @@ describe('setup contract', () => { }); test('serves content if etag values does not match', async () => { - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', assetFolder); @@ -1627,7 +1642,7 @@ describe('setup contract', () => { test('dynamically updates depending on the content of the file', async () => { const tempFile = join(tempDir, 'some_file.json'); - const { registerStaticDir, server: innerServer } = await server.setup(config); + const { registerStaticDir, server: innerServer } = await server.setup({ config$ }); registerStaticDir('/static/{path*}', tempDir); await server.start(); @@ -1654,7 +1669,7 @@ describe('setup contract', () => { describe('#registerOnPreRouting', () => { test('does not throw if called after stop', async () => { - const { registerOnPreRouting } = await server.setup(config); + const { registerOnPreRouting } = await server.setup({ config$ }); await server.stop(); expect(() => { registerOnPreRouting((req, res) => res.unauthorized()); @@ -1664,7 +1679,7 @@ describe('setup contract', () => { describe('#registerOnPreAuth', () => { test('does not throw if called after stop', async () => { - const { registerOnPreAuth } = await server.setup(config); + const { registerOnPreAuth } = await server.setup({ config$ }); await server.stop(); expect(() => { registerOnPreAuth((req, res) => res.unauthorized()); @@ -1674,7 +1689,7 @@ describe('setup contract', () => { describe('#registerOnPostAuth', () => { test('does not throw if called after stop', async () => { - const { registerOnPostAuth } = await server.setup(config); + const { registerOnPostAuth } = await server.setup({ config$ }); await server.stop(); expect(() => { registerOnPostAuth((req, res) => res.unauthorized()); @@ -1684,7 +1699,7 @@ describe('setup contract', () => { describe('#registerOnPreResponse', () => { test('does not throw if called after stop', async () => { - const { registerOnPreResponse } = await server.setup(config); + const { registerOnPreResponse } = await server.setup({ config$ }); await server.stop(); expect(() => { registerOnPreResponse((req, res, t) => t.next()); @@ -1694,7 +1709,7 @@ describe('setup contract', () => { describe('#registerAuth', () => { test('does not throw if called after stop', async () => { - const { registerAuth } = await server.setup(config); + const { registerAuth } = await server.setup({ config$ }); await server.stop(); expect(() => { registerAuth((req, res) => res.unauthorized()); @@ -1702,3 +1717,52 @@ describe('setup contract', () => { }); }); }); + +describe('configuration change', () => { + it('logs a warning in case of incompatible config change', async () => { + const configSubject = new BehaviorSubject(configWithSSL); + + await server.setup({ config$: configSubject }); + await server.start(); + + const nextConfig = { + ...configWithSSL, + ssl: { + ...configWithSSL.ssl, + getSecureOptions: () => 0, + enabled: false, + }, + } as HttpConfig; + + configSubject.next(nextConfig); + + expect(loggingService.get().warn).toHaveBeenCalledWith( + 'Incompatible TLS config change detected - TLS cannot be toggled without a full server reboot.' + ); + }); + + it('calls setTlsConfig and logs an info message when config changes', async () => { + const configSubject = new BehaviorSubject(configWithSSL); + + const { server: innerServer } = await server.setup({ config$: configSubject }); + await server.start(); + + const nextConfig = { + ...configWithSSL, + ssl: { + ...configWithSSL.ssl, + isEqualTo: () => false, + getSecureOptions: () => 0, + }, + } as HttpConfig; + + configSubject.next(nextConfig); + + expect(setTlsConfigMock).toHaveBeenCalledTimes(1); + expect(setTlsConfigMock).toHaveBeenCalledWith(innerServer, nextConfig.ssl); + + expect(loggingService.get().info).toHaveBeenCalledWith( + 'TLS configuration change detected - reloading TLS configuration.' + ); + }); +}); diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index c8a6f55e0a55..1361c64bb67c 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -14,12 +14,13 @@ import { createServer, getListenerOptions, getServerOptions, + setTlsConfig, getRequestId, } from '@kbn/server-http-tools'; import type { Duration } from 'moment'; -import { firstValueFrom, Observable } from 'rxjs'; -import { take } from 'rxjs/operators'; +import { firstValueFrom, Observable, Subscription } from 'rxjs'; +import { take, pairwise } from 'rxjs/operators'; import apm from 'elastic-apm-node'; // @ts-expect-error no type definition import Brok from 'brok'; @@ -58,7 +59,7 @@ import { AuthStateStorage } from './auth_state_storage'; import { AuthHeadersStorage } from './auth_headers_storage'; import { BasePath } from './base_path_service'; import { getEcsResponseLog } from './logging'; -import { StaticAssets, type IStaticAssets } from './static_assets'; +import { StaticAssets, type InternalStaticAssets } from './static_assets'; /** * Adds ELU timings for the executed function to the current's context transaction @@ -136,7 +137,7 @@ export interface HttpServerSetup { * @note Static assets may be served over CDN */ registerStaticDir: (path: string, dirPath: string) => void; - staticAssets: IStaticAssets; + staticAssets: InternalStaticAssets; basePath: HttpServiceSetup['basePath']; csp: HttpServiceSetup['csp']; createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory']; @@ -160,9 +161,15 @@ export type LifecycleRegistrar = Pick< | 'registerOnPreResponse' >; +export interface HttpServerSetupOptions { + config$: Observable; + executionContext?: InternalExecutionContextSetup; +} + export class HttpServer { private server?: Server; private config?: HttpConfig; + private subscriptions: Subscription[] = []; private registeredRouters = new Set(); private authRegistered = false; private cookieSessionStorageCreated = false; @@ -209,13 +216,16 @@ export class HttpServer { } } - public async setup( - config: HttpConfig, - executionContext?: InternalExecutionContextSetup - ): Promise { + public async setup({ + config$, + executionContext, + }: HttpServerSetupOptions): Promise { + const config = await firstValueFrom(config$); + this.config = config; + const serverOptions = getServerOptions(config); const listenerOptions = getListenerOptions(config); - this.config = config; + this.server = createServer(serverOptions, listenerOptions); await this.server.register([HapiStaticFiles]); if (config.compression.brotli.enabled) { @@ -227,6 +237,29 @@ export class HttpServer { }); } + // only hot-reloading TLS config - don't need to subscribe if TLS is initially disabled, + // given we can't hot-switch from/to enabled/disabled. + if (config.ssl.enabled) { + const configSubscription = config$ + .pipe(pairwise()) + .subscribe(([{ ssl: prevSslConfig }, { ssl: newSslConfig }]) => { + if (prevSslConfig.enabled !== newSslConfig.enabled) { + this.log.warn( + 'Incompatible TLS config change detected - TLS cannot be toggled without a full server reboot.' + ); + return; + } + + const sameConfig = newSslConfig.isEqualTo(prevSslConfig); + + if (!sameConfig) { + this.log.info('TLS configuration change detected - reloading TLS configuration.'); + setTlsConfig(this.server!, newSslConfig); + } + }); + this.subscriptions.push(configSubscription); + } + // It's important to have setupRequestStateAssignment call the very first, otherwise context passing will be broken. // That's the only reason why context initialization exists in this method. this.setupRequestStateAssignment(config, executionContext); diff --git a/packages/core/http/core-http-server-internal/src/http_service.ts b/packages/core/http/core-http-server-internal/src/http_service.ts index 96e9c8a85ba8..b09e7e84fef2 100644 --- a/packages/core/http/core-http-server-internal/src/http_service.ts +++ b/packages/core/http/core-http-server-internal/src/http_service.ts @@ -71,7 +71,7 @@ export class HttpService this.env = env; this.log = logger.get('http'); this.config$ = combineLatest([ - configService.atPath(httpConfig.path), + configService.atPath(httpConfig.path, { ignoreUnchanged: false }), configService.atPath(cspConfig.path), configService.atPath(externalUrlConfig.path), ]).pipe(map(([http, csp, externalUrl]) => new HttpConfig(http, csp, externalUrl))); @@ -85,7 +85,9 @@ export class HttpService this.log.debug('setting up preboot server'); const config = await firstValueFrom(this.config$); - const prebootSetup = await this.prebootServer.setup(config); + const prebootSetup = await this.prebootServer.setup({ + config$: this.config$, + }); prebootSetup.server.route({ path: '/{p*}', method: '*', @@ -157,10 +159,10 @@ export class HttpService const config = await firstValueFrom(this.config$); - const { registerRouter, ...serverContract } = await this.httpServer.setup( - config, - deps.executionContext - ); + const { registerRouter, ...serverContract } = await this.httpServer.setup({ + config$: this.config$, + executionContext: deps.executionContext, + }); registerCoreHandlers(serverContract, config, this.env, this.log); @@ -199,7 +201,7 @@ export class HttpService // the `plugin` and `legacy` services. public getStartContract(): InternalHttpServiceStart { return { - ...pick(this.internalSetup!, ['auth', 'basePath', 'getServerInfo']), + ...pick(this.internalSetup!, ['auth', 'basePath', 'getServerInfo', 'staticAssets']), isListening: () => this.httpServer.isListening(), }; } diff --git a/packages/core/http/core-http-server-internal/src/static_assets.test.ts b/packages/core/http/core-http-server-internal/src/static_assets.test.ts index d80ec6aaf6ed..0b1acd4e73fd 100644 --- a/packages/core/http/core-http-server-internal/src/static_assets.test.ts +++ b/packages/core/http/core-http-server-internal/src/static_assets.test.ts @@ -14,18 +14,48 @@ describe('StaticAssets', () => { let basePath: BasePath; let cdnConfig: CdnConfig; let staticAssets: StaticAssets; + beforeEach(() => { - basePath = new BasePath('/test'); - cdnConfig = CdnConfig.from(); - staticAssets = new StaticAssets(basePath, cdnConfig); + basePath = new BasePath('/base-path'); }); - it('provides fallsback to server base path', () => { - expect(staticAssets.getHrefBase()).toEqual('/test'); + + describe('#getHrefBase()', () => { + it('provides fallback to server base path', () => { + cdnConfig = CdnConfig.from(); + staticAssets = new StaticAssets(basePath, cdnConfig); + expect(staticAssets.getHrefBase()).toEqual('/base-path'); + }); + + it('provides the correct HREF given a CDN is configured', () => { + cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' }); + staticAssets = new StaticAssets(basePath, cdnConfig); + expect(staticAssets.getHrefBase()).toEqual('https://cdn.example.com/test'); + }); }); - it('provides the correct HREF given a CDN is configured', () => { - cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' }); - staticAssets = new StaticAssets(basePath, cdnConfig); - expect(staticAssets.getHrefBase()).toEqual('https://cdn.example.com/test'); + describe('#getPluginAssetHref()', () => { + it('returns the expected value when CDN config is not set', () => { + cdnConfig = CdnConfig.from(); + staticAssets = new StaticAssets(basePath, cdnConfig); + expect(staticAssets.getPluginAssetHref('foo', 'path/to/img.gif')).toEqual( + '/base-path/plugins/foo/assets/path/to/img.gif' + ); + }); + + it('returns the expected value when CDN config is set', () => { + cdnConfig = CdnConfig.from({ url: 'https://cdn.example.com/test' }); + staticAssets = new StaticAssets(basePath, cdnConfig); + expect(staticAssets.getPluginAssetHref('bar', 'path/to/img.gif')).toEqual( + 'https://cdn.example.com/test/plugins/bar/assets/path/to/img.gif' + ); + }); + + it('removes leading slash from the', () => { + cdnConfig = CdnConfig.from(); + staticAssets = new StaticAssets(basePath, cdnConfig); + expect(staticAssets.getPluginAssetHref('dolly', '/path/for/something.svg')).toEqual( + '/base-path/plugins/dolly/assets/path/for/something.svg' + ); + }); }); }); diff --git a/packages/core/http/core-http-server-internal/src/static_assets.ts b/packages/core/http/core-http-server-internal/src/static_assets.ts index b4e7a529fe94..4dfe46d8d31a 100644 --- a/packages/core/http/core-http-server-internal/src/static_assets.ts +++ b/packages/core/http/core-http-server-internal/src/static_assets.ts @@ -9,20 +9,31 @@ import type { BasePath } from './base_path_service'; import { CdnConfig } from './cdn'; -export interface IStaticAssets { +export interface InternalStaticAssets { getHrefBase(): string; + getPluginAssetHref(pluginName: string, assetPath: string): string; } -export class StaticAssets implements IStaticAssets { - constructor(private readonly basePath: BasePath, private readonly cdnConfig: CdnConfig) {} +export class StaticAssets implements InternalStaticAssets { + private readonly assetsHrefBase: string; + + constructor(basePath: BasePath, cdnConfig: CdnConfig) { + const hrefToUse = cdnConfig.baseHref ?? basePath.serverBasePath; + this.assetsHrefBase = hrefToUse.endsWith('/') ? hrefToUse.slice(0, -1) : hrefToUse; + } + /** * Returns a href (hypertext reference) intended to be used as the base for constructing * other hrefs to static assets. */ getHrefBase(): string { - if (this.cdnConfig.baseHref) { - return this.cdnConfig.baseHref; + return this.assetsHrefBase; + } + + getPluginAssetHref(pluginName: string, assetPath: string): string { + if (assetPath.startsWith('/')) { + assetPath = assetPath.slice(1); } - return this.basePath.serverBasePath; + return `${this.assetsHrefBase}/plugins/${pluginName}/assets/${assetPath}`; } } diff --git a/packages/core/http/core-http-server-internal/src/types.ts b/packages/core/http/core-http-server-internal/src/types.ts index 0acbb0d0508d..72dde630e03d 100644 --- a/packages/core/http/core-http-server-internal/src/types.ts +++ b/packages/core/http/core-http-server-internal/src/types.ts @@ -16,8 +16,9 @@ import type { HttpServiceSetup, HttpServiceStart, } from '@kbn/core-http-server'; -import { HttpServerSetup } from './http_server'; -import { ExternalUrlConfig } from './external_url'; +import type { HttpServerSetup } from './http_server'; +import type { ExternalUrlConfig } from './external_url'; +import type { InternalStaticAssets } from './static_assets'; /** @internal */ export interface InternalHttpServicePreboot @@ -43,10 +44,10 @@ export interface InternalHttpServicePreboot /** @internal */ export interface InternalHttpServiceSetup - extends Omit { + extends Omit { auth: HttpServerSetup['auth']; server: HttpServerSetup['server']; - staticAssets: HttpServerSetup['staticAssets']; + staticAssets: InternalStaticAssets; externalUrl: ExternalUrlConfig; createRouter: ( path: string, @@ -66,7 +67,8 @@ export interface InternalHttpServiceSetup } /** @internal */ -export interface InternalHttpServiceStart extends HttpServiceStart { +export interface InternalHttpServiceStart extends Omit { + staticAssets: InternalStaticAssets; /** Indicates if the http server is listening on the configured port */ isListening: () => boolean; } diff --git a/packages/core/http/core-http-server-mocks/src/http_service.mock.ts b/packages/core/http/core-http-server-mocks/src/http_service.mock.ts index ad7e310f5a2d..f8ecfadfeb87 100644 --- a/packages/core/http/core-http-server-mocks/src/http_service.mock.ts +++ b/packages/core/http/core-http-server-mocks/src/http_service.mock.ts @@ -20,6 +20,7 @@ import type { HttpServicePreboot, HttpServiceSetup, HttpServiceStart, + IStaticAssets, } from '@kbn/core-http-server'; import { AuthStatus } from '@kbn/core-http-server'; import { mockRouter, RouterMock } from '@kbn/core-http-router-server-mocks'; @@ -34,17 +35,19 @@ import type { import { sessionStorageMock } from './cookie_session_storage.mocks'; type BasePathMocked = jest.Mocked; -type StaticAssetsMocked = jest.Mocked; +type InternalStaticAssetsMocked = jest.Mocked; +type StaticAssetsMocked = jest.Mocked; type AuthMocked = jest.Mocked; export type HttpServicePrebootMock = jest.Mocked; export type InternalHttpServicePrebootMock = jest.Mocked< Omit -> & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked }; +> & { basePath: BasePathMocked; staticAssets: InternalStaticAssetsMocked }; export type HttpServiceSetupMock< ContextType extends RequestHandlerContextBase = RequestHandlerContextBase > = jest.Mocked, 'basePath' | 'createRouter'>> & { basePath: BasePathMocked; + staticAssets: StaticAssetsMocked; createRouter: jest.MockedFunction<() => RouterMock>; }; export type InternalHttpServiceSetupMock = jest.Mocked< @@ -55,15 +58,17 @@ export type InternalHttpServiceSetupMock = jest.Mocked< > & { auth: AuthMocked; basePath: BasePathMocked; - staticAssets: StaticAssetsMocked; + staticAssets: InternalStaticAssetsMocked; createRouter: jest.MockedFunction<(path: string) => RouterMock>; authRequestHeaders: jest.Mocked; }; export type HttpServiceStartMock = jest.Mocked & { basePath: BasePathMocked; + staticAssets: StaticAssetsMocked; }; export type InternalHttpServiceStartMock = jest.Mocked & { basePath: BasePathMocked; + staticAssets: InternalStaticAssetsMocked; }; const createBasePathMock = ( @@ -78,11 +83,12 @@ const createBasePathMock = ( remove: jest.fn(), }); -const createStaticAssetsMock = ( +const createInternalStaticAssetsMock = ( basePath: BasePathMocked, cdnUrl: undefined | string = undefined -): StaticAssetsMocked => ({ +): InternalStaticAssetsMocked => ({ getHrefBase: jest.fn(() => cdnUrl ?? basePath.serverBasePath), + getPluginAssetHref: jest.fn().mockReturnValue(cdnUrl ?? basePath.serverBasePath), }); const createAuthMock = () => { @@ -106,6 +112,7 @@ const createAuthHeaderStorageMock = () => { interface CreateMockArgs { cdnUrl?: string; } + const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { const basePath = createBasePathMock(); const mock: InternalHttpServicePrebootMock = { @@ -113,7 +120,7 @@ const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { registerRouteHandlerContext: jest.fn(), registerStaticDir: jest.fn(), basePath, - staticAssets: createStaticAssetsMock(basePath, args.cdnUrl), + staticAssets: createInternalStaticAssetsMock(basePath, args.cdnUrl), csp: CspConfig.DEFAULT, externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), @@ -144,6 +151,7 @@ const createPrebootContractMock = () => { }; const createInternalSetupContractMock = () => { + const basePath = createBasePathMock(); const mock: InternalHttpServiceSetupMock = { // we can mock other hapi server methods when we need it server: { @@ -164,9 +172,9 @@ const createInternalSetupContractMock = () => { registerOnPreResponse: jest.fn(), createRouter: jest.fn().mockImplementation(() => mockRouter.create({})), registerStaticDir: jest.fn(), - basePath: createBasePathMock(), + basePath, csp: CspConfig.DEFAULT, - staticAssets: { getHrefBase: jest.fn(() => mock.basePath.serverBasePath) }, + staticAssets: createInternalStaticAssetsMock(basePath), externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), authRequestHeaders: createAuthHeaderStorageMock(), @@ -202,6 +210,9 @@ const createSetupContractMock = < createRouter: jest.fn(), registerRouteHandlerContext: jest.fn(), getServerInfo: internalMock.getServerInfo, + staticAssets: { + getPluginAssetHref: jest.fn().mockImplementation((assetPath: string) => assetPath), + }, }; mock.createRouter.mockImplementation(() => internalMock.createRouter('')); @@ -214,14 +225,19 @@ const createStartContractMock = () => { auth: createAuthMock(), basePath: createBasePathMock(), getServerInfo: jest.fn(), + staticAssets: { + getPluginAssetHref: jest.fn().mockImplementation((assetPath: string) => assetPath), + }, }; return mock; }; const createInternalStartContractMock = () => { + const basePath = createBasePathMock(); const mock: InternalHttpServiceStartMock = { ...createStartContractMock(), + staticAssets: createInternalStaticAssetsMock(basePath), isListening: jest.fn(), }; diff --git a/packages/core/http/core-http-server/index.ts b/packages/core/http/core-http-server/index.ts index 94eefba610a4..9a28a7be5033 100644 --- a/packages/core/http/core-http-server/index.ts +++ b/packages/core/http/core-http-server/index.ts @@ -142,3 +142,5 @@ export type { VersionedRouteRegistrar, VersionedRouter, } from './src/versioning'; + +export type { IStaticAssets } from './src/static_assets'; diff --git a/packages/core/http/core-http-server/src/http_contract.ts b/packages/core/http/core-http-server/src/http_contract.ts index 753b7b8cf006..8ac34b26a386 100644 --- a/packages/core/http/core-http-server/src/http_contract.ts +++ b/packages/core/http/core-http-server/src/http_contract.ts @@ -20,6 +20,7 @@ import type { OnPreRoutingHandler, } from './lifecycle'; import type { IBasePath } from './base_path'; +import type { IStaticAssets } from './static_assets'; import type { ICspConfig } from './csp'; import type { GetAuthState, IsAuthenticated } from './auth_state'; import type { SessionStorageCookieOptions, SessionStorageFactory } from './session_storage'; @@ -287,6 +288,12 @@ export interface HttpServiceSetup< */ basePath: IBasePath; + /** + * APIs for creating hrefs to static assets. + * See {@link IStaticAssets} + */ + staticAssets: IStaticAssets; + /** * The CSP config used for Kibana. */ @@ -361,6 +368,12 @@ export interface HttpServiceStart { */ basePath: IBasePath; + /** + * APIs for creating hrefs to static assets. + * See {@link IStaticAssets} + */ + staticAssets: IStaticAssets; + /** * Auth status. * See {@link HttpAuth} diff --git a/packages/core/http/core-http-server/src/static_assets.ts b/packages/core/http/core-http-server/src/static_assets.ts new file mode 100644 index 000000000000..c0cc8597d154 --- /dev/null +++ b/packages/core/http/core-http-server/src/static_assets.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * APIs for creating hrefs to static assets. + * + * @public + */ +export interface IStaticAssets { + /** + * Gets the full href to the current plugin's asset, + * given its path relative to the plugin's `public/assets` folder. + * + * @example + * ```ts + * // I want to retrieve the href for the asset stored under `my_plugin/public/assets/some_folder/asset.png`: + * const assetHref = core.http.statisAssets.getPluginAssetHref('some_folder/asset.png'); + * ``` + */ + getPluginAssetHref(assetPath: string): string; +} diff --git a/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/injected_metadata_service.ts b/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/injected_metadata_service.ts index ca818f9f79dc..a50de7ca3f5e 100644 --- a/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/injected_metadata_service.ts +++ b/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/injected_metadata_service.ts @@ -48,6 +48,10 @@ export class InjectedMetadataService { return this.state.publicBaseUrl; }, + getAssetsHrefBase: () => { + return this.state.assetsHrefBase; + }, + getAnonymousStatusPage: () => { return this.state.anonymousStatusPage; }, diff --git a/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/types.ts b/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/types.ts index 67c9c6ff4d66..3b996e68e50b 100644 --- a/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/types.ts +++ b/packages/core/injected-metadata/core-injected-metadata-browser-internal/src/types.ts @@ -29,6 +29,7 @@ export interface InternalInjectedMetadataSetup { getBasePath: () => string; getServerBasePath: () => string; getPublicBaseUrl: () => string | undefined; + getAssetsHrefBase: () => string; getKibanaBuildNumber: () => number; getKibanaBranch: () => string; getKibanaVersion: () => string; diff --git a/packages/core/injected-metadata/core-injected-metadata-browser-mocks/src/injected_metadata_service.mock.ts b/packages/core/injected-metadata/core-injected-metadata-browser-mocks/src/injected_metadata_service.mock.ts index 98f1f8c65c37..3d76d48cbdb9 100644 --- a/packages/core/injected-metadata/core-injected-metadata-browser-mocks/src/injected_metadata_service.mock.ts +++ b/packages/core/injected-metadata/core-injected-metadata-browser-mocks/src/injected_metadata_service.mock.ts @@ -16,6 +16,7 @@ const createSetupContractMock = () => { const setupContract: jest.Mocked = { getBasePath: jest.fn(), getServerBasePath: jest.fn(), + getAssetsHrefBase: jest.fn(), getPublicBaseUrl: jest.fn(), getKibanaVersion: jest.fn(), getKibanaBranch: jest.fn(), @@ -31,6 +32,9 @@ const createSetupContractMock = () => { getKibanaBuildNumber: jest.fn(), getCustomBranding: jest.fn(), }; + setupContract.getBasePath.mockReturnValue('/base-path'); + setupContract.getServerBasePath.mockReturnValue('/server-base-path'); + setupContract.getAssetsHrefBase.mockReturnValue('/assets-base-path'); setupContract.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true }); setupContract.getExternalUrlConfig.mockReturnValue({ policy: [] }); setupContract.getKibanaVersion.mockReturnValue('kibanaVersion'); diff --git a/packages/core/injected-metadata/core-injected-metadata-common-internal/src/types.ts b/packages/core/injected-metadata/core-injected-metadata-common-internal/src/types.ts index 944ec94554b2..dd9d6bced5c9 100644 --- a/packages/core/injected-metadata/core-injected-metadata-common-internal/src/types.ts +++ b/packages/core/injected-metadata/core-injected-metadata-common-internal/src/types.ts @@ -42,6 +42,7 @@ export interface InjectedMetadata { basePath: string; serverBasePath: string; publicBaseUrl?: string; + assetsHrefBase: string; clusterInfo: InjectedMetadataClusterInfo; env: { mode: EnvironmentMode; diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts index 9ef51b986458..396c83408242 100644 --- a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts @@ -9,10 +9,12 @@ import type { CoreSetup } from '@kbn/core-lifecycle-browser'; import type { InternalApplicationSetup } from '@kbn/core-application-browser-internal'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; /** @internal */ export interface InternalCoreSetup - extends Omit { + extends Omit { application: InternalApplicationSetup; injectedMetadata: InternalInjectedMetadataSetup; + http: InternalHttpSetup; } diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts index f6b20626cd56..1806f52b8292 100644 --- a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts @@ -9,9 +9,11 @@ import type { CoreStart } from '@kbn/core-lifecycle-browser'; import type { InternalApplicationStart } from '@kbn/core-application-browser-internal'; import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; /** @internal */ -export interface InternalCoreStart extends Omit { +export interface InternalCoreStart extends Omit { application: InternalApplicationStart; injectedMetadata: InternalInjectedMetadataStart; + http: InternalHttpStart; } diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json b/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json index 5f6dcff8fd67..7d5c7fd5c06f 100644 --- a/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json @@ -14,7 +14,8 @@ "kbn_references": [ "@kbn/core-lifecycle-browser", "@kbn/core-application-browser-internal", - "@kbn/core-injected-metadata-browser-internal" + "@kbn/core-injected-metadata-browser-internal", + "@kbn/core-http-browser-internal" ], "exclude": [ "target/**/*", diff --git a/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap b/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap index 01ffd79b0b87..d283fc1400c7 100644 --- a/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap +++ b/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap @@ -25,6 +25,7 @@ Object { "message": "buffered trace message", "process": Object { "pid": Any, + "uptime": 10, }, } `; @@ -42,6 +43,7 @@ Object { "message": "buffered info message", "process": Object { "pid": Any, + "uptime": 10, }, "some": "value", } @@ -60,6 +62,7 @@ Object { "message": "buffered fatal message", "process": Object { "pid": Any, + "uptime": 10, }, } `; @@ -77,6 +80,7 @@ Object { "message": "buffered info message", "process": Object { "pid": Any, + "uptime": 10, }, "some": "value", } @@ -95,6 +99,7 @@ Object { "message": "some new info message", "process": Object { "pid": Any, + "uptime": 10, }, } `; diff --git a/packages/core/logging/core-logging-server-internal/src/layouts/__snapshots__/json_layout.test.ts.snap b/packages/core/logging/core-logging-server-internal/src/layouts/__snapshots__/json_layout.test.ts.snap index 0809dbffce67..da1c1b4c4f8b 100644 --- a/packages/core/logging/core-logging-server-internal/src/layouts/__snapshots__/json_layout.test.ts.snap +++ b/packages/core/logging/core-logging-server-internal/src/layouts/__snapshots__/json_layout.test.ts.snap @@ -15,6 +15,7 @@ Object { "message": "message-1", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -29,6 +30,7 @@ Object { "message": "message-2", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -43,6 +45,7 @@ Object { "message": "message-3", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -57,6 +60,7 @@ Object { "message": "message-4", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -71,6 +75,7 @@ Object { "message": "message-5", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -85,6 +90,7 @@ Object { "message": "message-6", "process": Object { "pid": 5355, + "uptime": 10, }, } `; @@ -99,6 +105,7 @@ Object { "message": "message-6", "process": Object { "pid": 5355, + "uptime": 10, }, "span": Object { "id": "spanId-1", diff --git a/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.test.ts b/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.test.ts index 60b415b1b2a2..8d16ce8a576f 100644 --- a/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.test.ts +++ b/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.test.ts @@ -10,6 +10,8 @@ import { EcsVersion } from '@kbn/ecs'; import { LogLevel, LogRecord } from '@kbn/logging'; import { JsonLayout } from './json_layout'; +jest.spyOn(process, 'uptime').mockReturnValue(10); + const timestamp = new Date(Date.UTC(2012, 1, 1, 14, 30, 22, 11)); const records: LogRecord[] = [ { @@ -121,6 +123,7 @@ test('`format()` correctly formats record with meta-data', () => { }, process: { pid: 5355, + uptime: 10, }, }); }); @@ -169,6 +172,7 @@ test('`format()` correctly formats error record with meta-data', () => { }, process: { pid: 5355, + uptime: 10, }, }); }); @@ -202,6 +206,7 @@ test('format() meta can merge override logs', () => { }, process: { pid: 3, + uptime: 10, }, }); }); @@ -232,6 +237,7 @@ test('format() meta can not override message', () => { }, process: { pid: 3, + uptime: 10, }, }); }); @@ -262,6 +268,7 @@ test('format() meta can not override ecs version', () => { }, process: { pid: 3, + uptime: 10, }, }); }); @@ -295,6 +302,7 @@ test('format() meta can not override logger or level', () => { }, process: { pid: 3, + uptime: 10, }, }); }); @@ -325,6 +333,7 @@ test('format() meta can not override timestamp', () => { }, process: { pid: 3, + uptime: 10, }, }); }); @@ -359,6 +368,7 @@ test('format() meta can not override tracing properties', () => { }, process: { pid: 3, + uptime: 10, }, span: { id: 'span_override' }, trace: { id: 'trace_override' }, @@ -404,6 +414,7 @@ test('format() meta.toJSON() is used if own property', () => { }, process: { pid: 3, + uptime: 10, }, server: { address: 'localhost', @@ -448,6 +459,7 @@ test('format() meta.toJSON() is used if present on prototype', () => { }, process: { pid: 3, + uptime: 10, }, foo: 'bar', }); diff --git a/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.ts b/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.ts index 43b906fa8407..59921b0f4b7f 100644 --- a/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.ts +++ b/packages/core/logging/core-logging-server-internal/src/layouts/json_layout.ts @@ -53,6 +53,7 @@ export class JsonLayout implements Layout { }, process: { pid: record.pid, + uptime: process.uptime(), }, span: spanId ? { id: spanId } : undefined, trace: traceId ? { id: traceId } : undefined, diff --git a/packages/core/logging/core-logging-server-internal/src/logging_system.test.ts b/packages/core/logging/core-logging-server-internal/src/logging_system.test.ts index 81eb539a618f..76fe93d1e614 100644 --- a/packages/core/logging/core-logging-server-internal/src/logging_system.test.ts +++ b/packages/core/logging/core-logging-server-internal/src/logging_system.test.ts @@ -23,6 +23,7 @@ let system: LoggingSystem; beforeEach(() => { mockConsoleLog = jest.spyOn(global.console, 'log').mockReturnValue(undefined); jest.spyOn(global, 'Date').mockImplementation(() => timestamp); + jest.spyOn(process, 'uptime').mockReturnValue(10); system = new LoggingSystem(); }); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.test.ts index 4ac8870de505..ee85fd9b755b 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.test.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.test.ts @@ -93,10 +93,7 @@ describe('OsCgroupMetricsCollector', () => { await collector.collect(); expect(gatherV2CgroupMetrics).toHaveBeenCalledTimes(1); - expect(gatherV2CgroupMetrics).toHaveBeenCalledWith({ - cpuAcctPath: '/groupname', - cpuPath: '/groupname', - }); + expect(gatherV2CgroupMetrics).toHaveBeenCalledWith('/groupname'); expect(gatherV1CgroupMetrics).toHaveBeenCalledTimes(0); }); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.ts index b336bff923b2..cea83674faa9 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/cgroup.ts @@ -42,9 +42,13 @@ export class OsCgroupMetricsCollector implements MetricsCollector { if (this.hasPaths()) return; - const { data: cgroups, v2 } = await gatherInfo(); - this.isCgroup2 = v2; - this.cpuPath = this.options.cpuPath || cgroups[GROUP_CPU]; - this.cpuAcctPath = this.options.cpuAcctPath || cgroups[GROUP_CPUACCT]; + const result = await gatherInfo(); + this.isCgroup2 = result.v2; + if (result.v2) { + this.cpuPath = result.path; + this.cpuAcctPath = result.path; + } else { + this.cpuPath = this.options.cpuPath || result.data[GROUP_CPU]; + this.cpuAcctPath = this.options.cpuAcctPath || result.data[GROUP_CPUACCT]; + } // prevents undefined cgroup paths this.noCgroupPresent = Boolean(!this.cpuPath || !this.cpuAcctPath); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.test.ts index bf86907e656d..8324091eaced 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.test.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.test.ts @@ -17,11 +17,14 @@ describe('gatherInfo', () => { '/proc/self/cgroup': `0:controller:/path 1:controller2,controller3:/otherpath`, }); - const { data } = await gatherInfo(); - expect(data).toEqual({ - controller: '/path', - controller2: '/otherpath', - controller3: '/otherpath', + const result = await gatherInfo(); + expect(result).toEqual({ + v2: false, + data: { + controller: '/path', + controller2: '/otherpath', + controller3: '/otherpath', + }, }); }); @@ -30,7 +33,7 @@ describe('gatherInfo', () => { '/proc/self/cgroup': `0:controller:/path 1:controller2,controller3:/otherpath`, }); - await expect(gatherInfo()).resolves.toMatchObject({ v2: false }); + expect(await gatherInfo()).toMatchObject({ v2: false }); mockFs({ '/proc/self/cgroup': ` @@ -38,7 +41,7 @@ describe('gatherInfo', () => { `, }); - await expect(gatherInfo()).resolves.toMatchObject({ v2: true }); + expect(await gatherInfo()).toMatchObject({ v2: true }); }); test('missing cgroup file', async () => { diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.ts index 7e490a577ff0..0afbceb85d96 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/gather_info.ts @@ -7,8 +7,6 @@ */ import fs from 'fs/promises'; -import { GROUP_CPU, GROUP_CPUACCT } from './constants'; - const CONTROL_GROUP_RE = new RegExp('\\d+:([^:]+):(/.*)'); const CONTROLLER_SEPARATOR_RE = ','; const PROC_SELF_CGROUP_FILE = '/proc/self/cgroup'; @@ -27,10 +25,15 @@ async function readProcSelf(): Promise { return data.split(/\n/).filter((line) => line.trim().length > 0); } -interface Result { - data: Record; - v2: boolean; -} +type Result = + | { + v2: true; + path: string; + } + | { + v2: false; + data: Record; + }; export async function gatherInfo(): Promise { const lines = await readProcSelf(); @@ -39,11 +42,8 @@ export async function gatherInfo(): Promise { // eslint-disable-next-line prettier/prettier const [/* '0' */, /* '' */, path] = lines[0].trim().split(':'); return { - data: { - [GROUP_CPU]: path, - [GROUP_CPUACCT]: path, - }, v2: true, + path, }; } diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/types.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/types.ts index 84b03e3ba151..133de91efb37 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/types.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/types.ts @@ -8,4 +8,4 @@ import type { OpsOsMetrics } from '@kbn/core-metrics-server'; -export type OsCgroupMetrics = Pick; +export type OsCgroupMetrics = Pick; diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.test.ts index 96c720fe9a63..17f781a401ec 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.test.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.test.ts @@ -22,10 +22,17 @@ system_usec 125968 nr_periods 123 nr_throttled 1 throttled_usec 123123`, + '/sys/fs/cgroup/memory.current': '9000', + '/sys/fs/cgroup/memory.swap.current': '42', }); - expect(await gatherV2CgroupMetrics({ cpuAcctPath: '/', cpuPath: '/' })).toMatchInlineSnapshot(` + const metrics = await gatherV2CgroupMetrics('/'); + expect(metrics).toMatchInlineSnapshot(` Object { + "cgroup_memory": Object { + "current_in_bytes": 9000, + "swap_current_in_bytes": 42, + }, "cpu": Object { "cfs_period_micros": 100000, "cfs_quota_micros": -1, @@ -54,11 +61,17 @@ system_usec 125968 nr_periods 123 nr_throttled 1 throttled_usec 123123`, + '/sys/fs/cgroup/mypath/memory.current': '9876', + '/sys/fs/cgroup/mypath/memory.swap.current': '132645', }); - expect(await gatherV2CgroupMetrics({ cpuAcctPath: '/mypath', cpuPath: '/mypath' })) - .toMatchInlineSnapshot(` + const metrics = await gatherV2CgroupMetrics('/mypath'); + expect(metrics).toMatchInlineSnapshot(` Object { + "cgroup_memory": Object { + "current_in_bytes": 9876, + "swap_current_in_bytes": 132645, + }, "cpu": Object { "cfs_period_micros": 100000, "cfs_quota_micros": 111, diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.ts index ac7fba7cfaf4..3d5d1f563d28 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/cgroup/v2.ts @@ -13,37 +13,60 @@ import type { OsCgroupMetrics } from './types'; const PROC_CGROUP2_DIR = '/sys/fs/cgroup'; const CPU_STATS_FILE = 'cpu.stat'; const CPU_MAX_FILE = 'cpu.max'; +const MEMORY_CURRENT_FILE = 'memory.current'; +const MEMORY_SWAP_CURRENT_FILE = 'memory.swap.current'; -interface Arg { - cpuPath: string; - cpuAcctPath: string; -} +const getCGroupFilePath = (group: string, fileName: string): string => { + return joinPath(PROC_CGROUP2_DIR, group, fileName); +}; -export async function gatherV2CgroupMetrics(arg: Arg): Promise { - const [{ usage_nanos: usageNanos, ...stat }, cpuMax] = await Promise.all([ - readCPUStat(arg.cpuPath), - readCPUMax(arg.cpuPath), - ]); +export async function gatherV2CgroupMetrics(group: string): Promise { + const [{ usage_nanos: usageNanos, ...stat }, cpuMax, memoryCurrent, swapCurrent] = + await Promise.all([ + readCPUStat(group), + readCPUMax(group), + readMemoryCurrent(group), + readSwapCurrent(group), + ]); return { cpu: { ...cpuMax, - control_group: arg.cpuPath, + control_group: group, stat, }, cpuacct: { - control_group: arg.cpuPath, + control_group: group, usage_nanos: usageNanos, }, + cgroup_memory: { + current_in_bytes: memoryCurrent, + swap_current_in_bytes: swapCurrent, + }, }; } + interface CPUMax { cfs_period_micros: number; cfs_quota_micros: number; } +async function readMemoryCurrent(group: string): Promise { + const rawMemoryCurrent = (await fs.readFile(getCGroupFilePath(group, MEMORY_CURRENT_FILE))) + .toString() + .trim(); + return parseInt(rawMemoryCurrent, 10); +} + +async function readSwapCurrent(group: string): Promise { + const rawMemoryCurrent = (await fs.readFile(getCGroupFilePath(group, MEMORY_SWAP_CURRENT_FILE))) + .toString() + .trim(); + return parseInt(rawMemoryCurrent, 10); +} + async function readCPUMax(group: string): Promise { - const [quota, period] = (await fs.readFile(joinPath(PROC_CGROUP2_DIR, group, CPU_MAX_FILE))) + const [quota, period] = (await fs.readFile(getCGroupFilePath(group, CPU_MAX_FILE))) .toString() .trim() .split(/\s+/); @@ -62,7 +85,7 @@ async function readCPUStat(group: string): Promise { time_throttled_nanos: -1, usage_nanos: -1, }; - return (await fs.readFile(joinPath(PROC_CGROUP2_DIR, group, CPU_STATS_FILE))) + return (await fs.readFile(getCGroupFilePath(group, CPU_STATS_FILE))) .toString() .split(/\n/) .reduce((acc, line) => { diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/mocks_internal.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/mocks_internal.ts index 812b2c89ff8d..d8659d702d0c 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/mocks_internal.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/mocks_internal.ts @@ -37,6 +37,8 @@ function createMockOpsProcessMetrics(): OpsProcessMetrics { memory: { heap: { total_in_bytes: 1, used_in_bytes: 1, size_limit: 1 }, resident_set_size_in_bytes: 1, + array_buffers_in_bytes: 1, + external_in_bytes: 1, }, event_loop_delay: 1, event_loop_delay_histogram: histogram, diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/process.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/process.test.ts index dbb667aeeb04..4bad8e24b322 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/process.test.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/process.test.ts @@ -61,12 +61,15 @@ describe('ProcessMetricsCollector', () => { const heapUsed = 4688; const heapSizeLimit = 5788; const rss = 5865; + const external = 9001; + const arrayBuffers = 42; + jest.spyOn(process, 'memoryUsage').mockImplementation(() => ({ rss, heapTotal, heapUsed, - external: 0, - arrayBuffers: 0, + external, + arrayBuffers, })); jest.spyOn(v8, 'getHeapStatistics').mockImplementation( @@ -83,6 +86,8 @@ describe('ProcessMetricsCollector', () => { expect(metrics[0].memory.heap.used_in_bytes).toEqual(heapUsed); expect(metrics[0].memory.heap.size_limit).toEqual(heapSizeLimit); expect(metrics[0].memory.resident_set_size_in_bytes).toEqual(rss); + expect(metrics[0].memory.external_in_bytes).toEqual(external); + expect(metrics[0].memory.array_buffers_in_bytes).toEqual(arrayBuffers); }); }); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/process.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/process.ts index 399da1ad9c29..3e35eaa108ea 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/src/process.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/process.ts @@ -38,6 +38,8 @@ export class ProcessMetricsCollector implements MetricsCollector): OpsMetrics { ...testMetrics, }; } + const testMetrics = { process: { - memory: { heap: { used_in_bytes: 100 } }, + memory: { + heap: { used_in_bytes: 100, total_in_bytes: 200, size_limit: 300 }, + resident_set_size_in_bytes: 400, + external_in_bytes: 500, + array_buffers_in_bytes: 600, + }, uptime_in_millis: 1500, event_loop_delay: 50, event_loop_delay_histogram: { percentiles: { '50': 50, '75': 75, '95': 95, '99': 99 } }, @@ -127,9 +133,14 @@ describe('getEcsOpsMetricsLog', () => { "utilization": 0.6365329598160299, }, "memory": Object { + "arrayBuffersInBytes": 600, + "externalInBytes": 500, "heap": Object { + "sizeLimit": 300, + "totalInBytes": 200, "usedInBytes": 100, }, + "residentSetSizeInBytes": 400, }, "uptime": 1, }, diff --git a/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.ts b/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.ts index 78e4482b7a35..e3fffbdeb043 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.ts @@ -86,7 +86,12 @@ export function getEcsOpsMetricsLog(metrics: OpsMetrics) { memory: { heap: { usedInBytes: processMemoryUsedInBytes, + totalInBytes: process?.memory?.heap.total_in_bytes, + sizeLimit: process?.memory?.heap.size_limit, }, + residentSetSizeInBytes: process?.memory?.resident_set_size_in_bytes, + externalInBytes: process?.memory?.external_in_bytes, + arrayBuffersInBytes: process?.memory?.array_buffers_in_bytes, }, eventLoopDelay: eventLoopDelayVal, eventLoopDelayHistogram: eventLoopDelayHistVals, diff --git a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts index 45b3ae49a1f5..176ad9c7fa4c 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts @@ -216,9 +216,14 @@ describe('MetricsService', () => { "eventLoopDelayHistogram": undefined, "eventLoopUtilization": undefined, "memory": Object { + "arrayBuffersInBytes": undefined, + "externalInBytes": undefined, "heap": Object { + "sizeLimit": undefined, + "totalInBytes": undefined, "usedInBytes": undefined, }, + "residentSetSizeInBytes": undefined, }, "uptime": undefined, }, diff --git a/packages/core/metrics/core-metrics-server/src/metrics.ts b/packages/core/metrics/core-metrics-server/src/metrics.ts index 6f903cd66a24..615998e600a2 100644 --- a/packages/core/metrics/core-metrics-server/src/metrics.ts +++ b/packages/core/metrics/core-metrics-server/src/metrics.ts @@ -82,6 +82,10 @@ export interface OpsProcessMetrics { }; /** node rss */ resident_set_size_in_bytes: number; + /** memory usage of C++ objects bound to JavaScript objects managed by V8 */ + external_in_bytes: number; + /** memory allocated for array buffers. This is also included in the external value*/ + array_buffers_in_bytes: number; }; /** mean event loop delay since last collection*/ event_loop_delay: number; @@ -153,6 +157,14 @@ export interface OpsOsMetrics { time_throttled_nanos: number; }; }; + + /** memory cgroup metrics, undefined when not running in cgroup v2 */ + cgroup_memory?: { + /** The total amount of memory currently being used by the cgroup and its descendants. */ + current_in_bytes: number; + /** The total amount of swap currently being used by the cgroup and its descendants. */ + swap_current_in_bytes: number; + }; } /** diff --git a/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts index 604eb8609375..94ada11ac5b2 100644 --- a/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts @@ -82,7 +82,13 @@ export function createPluginSetupContext< customBranding: deps.customBranding, fatalErrors: deps.fatalErrors, executionContext: deps.executionContext, - http: deps.http, + http: { + ...deps.http, + staticAssets: { + getPluginAssetHref: (assetPath: string) => + deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath), + }, + }, notifications: deps.notifications, uiSettings: deps.uiSettings, settings: deps.settings, @@ -133,7 +139,13 @@ export function createPluginStartContext< customBranding: deps.customBranding, docLinks: deps.docLinks, executionContext: deps.executionContext, - http: deps.http, + http: { + ...deps.http, + staticAssets: { + getPluginAssetHref: (assetPath: string) => + deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath), + }, + }, chrome: omit(deps.chrome, 'getComponent'), i18n: deps.i18n, notifications: deps.notifications, diff --git a/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts index 00c056a20d87..c1c612d38720 100644 --- a/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts @@ -104,6 +104,10 @@ describe('PluginsService', () => { application: expect.any(Object), plugins: expect.any(Object), getStartServices: expect.any(Function), + http: { + ...mockSetupDeps.http, + staticAssets: expect.any(Object), + }, }; // @ts-expect-error this file was not being type checked properly in the past, error is legit mockStartDeps = { @@ -128,6 +132,10 @@ describe('PluginsService', () => { application: expect.any(Object), plugins: expect.any(Object), chrome: omit(mockStartDeps.chrome, 'getComponent'), + http: { + ...mockStartDeps.http, + staticAssets: expect.any(Object), + }, }; // Reset these for each test. diff --git a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts index 8d493e78aae8..c3ed7f6a433b 100644 --- a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts @@ -235,6 +235,10 @@ export function createPluginSetupContext({ registerOnPostAuth: deps.http.registerOnPostAuth, registerOnPreResponse: deps.http.registerOnPreResponse, basePath: deps.http.basePath, + staticAssets: { + getPluginAssetHref: (assetPath: string) => + deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath), + }, csp: deps.http.csp, getServerInfo: deps.http.getServerInfo, }, @@ -324,6 +328,10 @@ export function createPluginStartContext({ auth: deps.http.auth, basePath: deps.http.basePath, getServerInfo: deps.http.getServerInfo, + staticAssets: { + getPluginAssetHref: (assetPath: string) => + deps.http.staticAssets.getPluginAssetHref(plugin.name, assetPath), + }, }, savedObjects: { getScopedClient: deps.savedObjects.getScopedClient, diff --git a/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap b/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap index d444959de3c9..535624e4a832 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap +++ b/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap @@ -3,6 +3,7 @@ exports[`RenderingService preboot() render() renders "core" CDN url injected 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "http://foo.bar:1773", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -70,6 +71,7 @@ Object { exports[`RenderingService preboot() render() renders "core" page 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -133,6 +135,7 @@ Object { exports[`RenderingService preboot() render() renders "core" page driven by settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -200,6 +203,7 @@ Object { exports[`RenderingService preboot() render() renders "core" page for blank basepath 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "", "branch": Any, "buildNumber": Any, @@ -263,6 +267,7 @@ Object { exports[`RenderingService preboot() render() renders "core" page for unauthenticated requests 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -326,6 +331,7 @@ Object { exports[`RenderingService preboot() render() renders "core" page with global settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -393,6 +399,7 @@ Object { exports[`RenderingService preboot() render() renders "core" with excluded global user settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -456,6 +463,7 @@ Object { exports[`RenderingService preboot() render() renders "core" with excluded user settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -519,6 +527,7 @@ Object { exports[`RenderingService setup() render() renders "core" CDN url injected 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -591,6 +600,7 @@ Object { exports[`RenderingService setup() render() renders "core" page 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -654,6 +664,7 @@ Object { exports[`RenderingService setup() render() renders "core" page driven by settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -726,6 +737,7 @@ Object { exports[`RenderingService setup() render() renders "core" page for blank basepath 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "", "branch": Any, "buildNumber": Any, @@ -794,6 +806,7 @@ Object { exports[`RenderingService setup() render() renders "core" page for unauthenticated requests 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -857,6 +870,7 @@ Object { exports[`RenderingService setup() render() renders "core" page with global settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -929,6 +943,7 @@ Object { exports[`RenderingService setup() render() renders "core" with excluded global user settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, @@ -997,6 +1012,7 @@ Object { exports[`RenderingService setup() render() renders "core" with excluded user settings 1`] = ` Object { "anonymousStatusPage": false, + "assetsHrefBase": "/mock-server-basepath", "basePath": "/mock-server-basepath", "branch": Any, "buildNumber": Any, diff --git a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx index 1791f55e563b..f5bb1f5fa115 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx +++ b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx @@ -209,6 +209,7 @@ export class RenderingService { basePath, serverBasePath, publicBaseUrl, + assetsHrefBase: staticAssetsHrefBase, env, clusterInfo, anonymousStatusPage: status?.isStatusPageAnonymous() ?? false, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.test.ts new file mode 100644 index 000000000000..3faeee08048e --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.test.ts @@ -0,0 +1,1048 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* eslint-disable @typescript-eslint/no-shadow */ + +import { + pointInTimeFinderMock, + mockGetBulkOperationError, + mockGetCurrentTime, + mockPreflightCheckForCreate, + mockGetSearchDsl, +} from '../repository.test.mock'; + +import type { Payload } from '@hapi/boom'; + +import type { SavedObjectsBulkCreateObject } from '@kbn/core-saved-objects-api-server'; +import { + type SavedObjectsRawDoc, + type SavedObjectUnsanitizedDoc, + type SavedObjectReference, +} from '@kbn/core-saved-objects-server'; +import { ALL_NAMESPACES_STRING } from '@kbn/core-saved-objects-utils-server'; +import { SavedObjectsRepository } from '../repository'; +import { loggerMock } from '@kbn/logging-mocks'; +import { SavedObjectsSerializer } from '@kbn/core-saved-objects-base-server-internal'; +import { kibanaMigratorMock } from '../../mocks'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; + +import { + CUSTOM_INDEX_TYPE, + NAMESPACE_AGNOSTIC_TYPE, + MULTI_NAMESPACE_TYPE, + MULTI_NAMESPACE_ISOLATED_TYPE, + HIDDEN_TYPE, + mockVersionProps, + mockTimestampFields, + mockTimestamp, + mappings, + mockVersion, + createRegistry, + createDocumentMigrator, + createSpySerializer, + bulkCreateSuccess, + getMockBulkCreateResponse, + expectErrorResult, + expectErrorInvalidType, + expectErrorConflict, + expectError, + createBadRequestErrorPayload, + expectCreateResult, + mockTimestampFieldsWithCreated, +} from '../../test_helpers/repository.test.common'; + +// BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository +// so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient. + +interface ExpectedErrorResult { + type: string; + id: string; + error: Record; +} + +describe('SavedObjectsRepository', () => { + let client: ReturnType; + let repository: SavedObjectsRepository; + let migrator: ReturnType; + let logger: ReturnType; + let serializer: jest.Mocked; + + const registry = createRegistry(); + const documentMigrator = createDocumentMigrator(registry); + + const expectSuccess = ({ type, id }: { type: string; id: string }) => { + // @ts-expect-error TS is not aware of the extension + return expect.toBeDocumentWithoutError(type, id); + }; + + const expectMigrationArgs = (args: unknown, contains = true, n = 1) => { + const obj = contains ? expect.objectContaining(args) : expect.not.objectContaining(args); + expect(migrator.migrateDocument).toHaveBeenNthCalledWith( + n, + obj, + expect.objectContaining({ + allowDowngrade: expect.any(Boolean), + }) + ); + }; + + beforeEach(() => { + pointInTimeFinderMock.mockClear(); + client = elasticsearchClientMock.createElasticsearchClient(); + migrator = kibanaMigratorMock.create(); + documentMigrator.prepareMigrations(); + migrator.migrateDocument = jest.fn().mockImplementation(documentMigrator.migrate); + migrator.runMigrations = jest.fn().mockResolvedValue([{ status: 'skipped' }]); + logger = loggerMock.create(); + + // create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation + serializer = createSpySerializer(registry); + + const allTypes = registry.getAllTypes().map((type) => type.name); + const allowedTypes = [...new Set(allTypes.filter((type) => !registry.isHidden(type)))]; + + // @ts-expect-error must use the private constructor to use the mocked serializer + repository = new SavedObjectsRepository({ + index: '.kibana-test', + mappings, + client, + migrator, + typeRegistry: registry, + serializer, + allowedTypes, + logger, + }); + + mockGetCurrentTime.mockReturnValue(mockTimestamp); + mockGetSearchDsl.mockClear(); + }); + + // Setup migration mock for creating an object + const mockMigrationVersion = { foo: '2.3.4' }; + const mockMigrateDocument = (doc: SavedObjectUnsanitizedDoc) => ({ + ...doc, + attributes: { + ...doc.attributes, + ...(doc.attributes?.title && { title: `${doc.attributes.title}!!` }), + }, + migrationVersion: mockMigrationVersion, + managed: doc.managed ?? false, + references: [{ name: 'search_0', type: 'search', id: '123' }], + }); + + describe('#bulkCreate', () => { + beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return Promise.resolve(objects.map(({ type, id }) => ({ type, id }))); // respond with no errors by default + }); + }); + + const obj1 = { + type: 'config', + id: '6.0.0-alpha1', + attributes: { title: 'Test One' }, + references: [{ name: 'ref_0', type: 'test', id: '1' }], + managed: false, + }; + const obj2 = { + type: 'index-pattern', + id: 'logstash-*', + attributes: { title: 'Test Two' }, + references: [{ name: 'ref_0', type: 'test', id: '2' }], + managed: false, + }; + const namespace = 'foo-namespace'; + + // bulk create calls have two objects for each source -- the action, and the source + const expectClientCallArgsAction = ( + objects: Array<{ type: string; id?: string; if_primary_term?: string; if_seq_no?: string }>, + { + method, + _index = expect.any(String), + getId = () => expect.any(String), + }: { method: string; _index?: string; getId?: (type: string, id?: string) => string } + ) => { + const body = []; + for (const { type, id, if_primary_term: ifPrimaryTerm, if_seq_no: ifSeqNo } of objects) { + body.push({ + [method]: { + _index, + _id: getId(type, id), + ...(ifPrimaryTerm && ifSeqNo + ? { if_primary_term: expect.any(Number), if_seq_no: expect.any(Number) } + : {}), + }, + }); + body.push(expect.any(Object)); + } + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }; + + const expectObjArgs = ( + { + type, + attributes, + references, + }: { type: string; attributes: unknown; references?: SavedObjectReference[] }, + overrides: Record = {} + ) => [ + expect.any(Object), + expect.objectContaining({ + [type]: attributes, + references, + type, + ...overrides, + ...mockTimestampFields, + }), + ]; + describe('client calls', () => { + it(`should use the ES bulk action by default`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expect(client.bulk).toHaveBeenCalledTimes(1); + }); + + it(`should use the preflightCheckForCreate action before bulk action for any types that are multi-namespace, when id is defined`, async () => { + const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; + await bulkCreateSuccess(client, repository, objects); + expect(client.bulk).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { + type: MULTI_NAMESPACE_ISOLATED_TYPE, + id: obj2.id, + overwrite: false, + namespaces: ['default'], + }, + ], + }) + ); + }); + + it(`should use the ES create method if ID is undefined and overwrite=true`, async () => { + const objects = [obj1, obj2].map((obj) => ({ ...obj, id: undefined })); + await bulkCreateSuccess(client, repository, objects, { overwrite: true }); + expectClientCallArgsAction(objects, { method: 'create' }); + }); + + it(`should use the ES create method if ID is undefined and overwrite=false`, async () => { + const objects = [obj1, obj2].map((obj) => ({ ...obj, id: undefined })); + await bulkCreateSuccess(client, repository, objects); + expectClientCallArgsAction(objects, { method: 'create' }); + }); + + it(`should use the ES index method if ID is defined and overwrite=true`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { overwrite: true }); + expectClientCallArgsAction([obj1, obj2], { method: 'index' }); + }); + + it(`should use the ES index method with version if ID and version are defined and overwrite=true`, async () => { + await bulkCreateSuccess( + client, + repository, + [ + { + ...obj1, + version: mockVersion, + }, + obj2, + ], + { overwrite: true } + ); + + const obj1WithSeq = { + ...obj1, + managed: obj1.managed, + if_seq_no: mockVersionProps._seq_no, + if_primary_term: mockVersionProps._primary_term, + }; + + expectClientCallArgsAction([obj1WithSeq, obj2], { method: 'index' }); + }); + + it(`should use the ES create method if ID is defined and overwrite=false`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expectClientCallArgsAction([obj1, obj2], { method: 'create' }); + }); + + it(`should use the ES index method if ID is defined, overwrite=true and managed=true in a document`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { + overwrite: true, + managed: true, + }); + expectClientCallArgsAction([obj1, obj2], { method: 'index' }); + }); + + it(`should use the ES create method if ID is defined, overwrite=false and managed=true in a document`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { managed: true }); + expectClientCallArgsAction([obj1, obj2], { method: 'create' }); + }); + + it(`formats the ES request`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + // this test only ensures that the client accepts the managed field in a document + it(`formats the ES request with managed=true in a document`, async () => { + const obj1WithManagedTrue = { ...obj1, managed: true }; + const obj2WithManagedTrue = { ...obj2, managed: true }; + await bulkCreateSuccess(client, repository, [obj1WithManagedTrue, obj2WithManagedTrue]); + const body = [...expectObjArgs(obj1WithManagedTrue), ...expectObjArgs(obj2WithManagedTrue)]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + describe('originId', () => { + it(`returns error if originId is set for non-multi-namespace type`, async () => { + const result = await repository.bulkCreate([ + { ...obj1, originId: 'some-originId' }, + { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE, originId: 'some-originId' }, + ]); + expect(result.saved_objects).toEqual([ + expect.objectContaining({ id: obj1.id, type: obj1.type, error: expect.anything() }), + expect.objectContaining({ + id: obj2.id, + type: NAMESPACE_AGNOSTIC_TYPE, + error: expect.anything(), + }), + ]); + expect(client.bulk).not.toHaveBeenCalled(); + }); + + it(`defaults to no originId`, async () => { + const objects = [ + { ...obj1, type: MULTI_NAMESPACE_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, + ]; + + await bulkCreateSuccess(client, repository, objects); + const expected = expect.not.objectContaining({ originId: expect.anything() }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + describe('with existing originId', () => { + beforeEach(() => { + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + const existingDocument = { + _source: { originId: 'existing-originId' }, + } as SavedObjectsRawDoc; + return Promise.resolve( + objects.map(({ type, id }) => ({ type, id, existingDocument })) + ); + }); + }); + + it(`accepts custom originId for multi-namespace type`, async () => { + // The preflight result has `existing-originId`, but that is discarded + const objects = [ + { ...obj1, type: MULTI_NAMESPACE_TYPE, originId: 'some-originId' }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE, originId: 'some-originId' }, + ]; + await bulkCreateSuccess(client, repository, objects); + const expected = expect.objectContaining({ originId: 'some-originId' }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + it(`accepts undefined originId`, async () => { + // The preflight result has `existing-originId`, but that is discarded + const objects = [ + { ...obj1, type: MULTI_NAMESPACE_TYPE, originId: undefined }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE, originId: undefined }, + ]; + await bulkCreateSuccess(client, repository, objects); + const expected = expect.not.objectContaining({ originId: expect.anything() }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + it(`preserves existing originId if originId option is not set`, async () => { + const objects = [ + { ...obj1, type: MULTI_NAMESPACE_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, + ]; + await bulkCreateSuccess(client, repository, objects); + const expected = expect.objectContaining({ originId: 'existing-originId' }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + }); + }); + + it(`adds namespace to request body for any types that are single-namespace`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); + const expected = expect.objectContaining({ namespace }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + // this only ensures we don't override any other options + it(`adds managed=false to request body if declared for any types that are single-namespace`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace, managed: false }); + const expected = expect.objectContaining({ namespace, managed: false }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + // this only ensures we don't override any other options + it(`adds managed=true to request body if declared for any types that are single-namespace`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace, managed: true }); + const expected = expect.objectContaining({ namespace, managed: true }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + it(`normalizes options.namespace from 'default' to undefined`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace: 'default' }); + const expected = expect.not.objectContaining({ namespace: 'default' }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + it(`doesn't add namespace to request body for any types that are not single-namespace`, async () => { + const objects = [ + { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, + ]; + await bulkCreateSuccess(client, repository, objects, { namespace }); + const expected = expect.not.objectContaining({ namespace: expect.anything() }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + }); + + it(`adds namespaces to request body for any types that are multi-namespace`, async () => { + const test = async (namespace?: string) => { + const objects = [obj1, obj2].map((x) => ({ ...x, type: MULTI_NAMESPACE_ISOLATED_TYPE })); + const [o1, o2] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + { type: o1.type, id: o1.id! }, // first object does not have an existing document to overwrite + { + type: o2.type, + id: o2.id!, + existingDocument: { _id: o2.id!, _source: { namespaces: ['*'], type: o2.type } }, // second object does have an existing document to overwrite + }, + ]); + await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); + const expected1 = expect.objectContaining({ namespaces: [namespace ?? 'default'] }); + const expected2 = expect.objectContaining({ namespaces: ['*'] }); + const body = [expect.any(Object), expected1, expect.any(Object), expected2]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + client.bulk.mockClear(); + mockPreflightCheckForCreate.mockReset(); + }; + await test(undefined); + await test(namespace); + }); + + it(`adds initialNamespaces instead of namespace`, async () => { + const test = async (namespace?: string) => { + const ns2 = 'bar-namespace'; + const ns3 = 'baz-namespace'; + const objects = [ + { ...obj1, type: 'dashboard', initialNamespaces: [ns2] }, + { ...obj1, type: MULTI_NAMESPACE_ISOLATED_TYPE, initialNamespaces: [ns2] }, + { ...obj1, type: MULTI_NAMESPACE_TYPE, initialNamespaces: [ns2, ns3] }, + ]; + const [o1, o2, o3] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + // first object does not get passed in to preflightCheckForCreate at all + { type: o2.type, id: o2.id! }, // second object does not have an existing document to overwrite + { + type: o3.type, + id: o3.id!, + existingDocument: { + _id: o3.id!, + _source: { type: o3.type, namespaces: [namespace ?? 'default', 'something-else'] }, // third object does have an existing document to overwrite + }, + }, + ]); + await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); + const body = [ + { index: expect.objectContaining({ _id: `${ns2}:dashboard:${o1.id}` }) }, + expect.objectContaining({ namespace: ns2 }), + { + index: expect.objectContaining({ + _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${o2.id}`, + }), + }, + expect.objectContaining({ namespaces: [ns2] }), + { index: expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${o3.id}` }) }, + expect.objectContaining({ namespaces: [ns2, ns3] }), + ]; + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + // assert that the initialNamespaces fields were passed into preflightCheckForCreate instead of the current namespace + { type: o2.type, id: o2.id, overwrite: true, namespaces: o2.initialNamespaces }, + { type: o3.type, id: o3.id, overwrite: true, namespaces: o3.initialNamespaces }, + ], + }) + ); + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + client.bulk.mockClear(); + mockPreflightCheckForCreate.mockReset(); + }; + await test(undefined); + await test(namespace); + }); + + it(`normalizes initialNamespaces from 'default' to undefined`, async () => { + const test = async (namespace?: string) => { + const objects = [{ ...obj1, type: 'dashboard', initialNamespaces: ['default'] }]; + await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); + const body = [ + { index: expect.objectContaining({ _id: `dashboard:${obj1.id}` }) }, + expect.not.objectContaining({ namespace: 'default' }), + ]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + client.bulk.mockClear(); + }; + await test(undefined); + await test(namespace); + }); + + it(`doesn't add namespaces to request body for any types that are not multi-namespace`, async () => { + const test = async (namespace?: string) => { + const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }]; + await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); + const expected = expect.not.objectContaining({ namespaces: expect.anything() }); + const body = [expect.any(Object), expected, expect.any(Object), expected]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + client.bulk.mockClear(); + }; + await test(undefined); + await test(namespace); + }); + + it(`defaults to a refresh setting of wait_for`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ refresh: 'wait_for' }), + expect.anything() + ); + }); + + it(`should use default index`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expectClientCallArgsAction([obj1, obj2], { + method: 'create', + _index: '.kibana-test_8.0.0-testing', + }); + }); + + it(`should use custom index`, async () => { + await bulkCreateSuccess( + client, + repository, + [obj1, obj2].map((x) => ({ ...x, type: CUSTOM_INDEX_TYPE })) + ); + expectClientCallArgsAction([obj1, obj2], { + method: 'create', + _index: 'custom_8.0.0-testing', + }); + }); + + it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { + const getId = (type: string, id: string = '') => `${namespace}:${type}:${id}`; // test that the raw document ID equals this (e.g., has a namespace prefix) + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); + expectClientCallArgsAction([obj1, obj2], { method: 'create', getId }); + }); + + it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { + const getId = (type: string, id: string = '') => `${type}:${id}`; // test that the raw document ID equals this (e.g., does not have a namespace prefix) + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expectClientCallArgsAction([obj1, obj2], { method: 'create', getId }); + }); + + it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => { + const getId = (type: string, id: string = '') => `${type}:${id}`; // test that the raw document ID equals this (e.g., does not have a namespace prefix) + const objects = [ + { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, + ]; + await bulkCreateSuccess(client, repository, objects, { namespace }); + expectClientCallArgsAction(objects, { method: 'create', getId }); + }); + }); + + describe('errors', () => { + afterEach(() => { + mockGetBulkOperationError.mockReset(); + }); + + const obj3 = { + type: 'dashboard', + id: 'three', + attributes: { title: 'Test Three' }, + references: [{ name: 'ref_0', type: 'test', id: '2' }], + }; + + const bulkCreateError = async ( + obj: SavedObjectsBulkCreateObject, + isBulkError: boolean | undefined, + expectedErrorResult: ExpectedErrorResult + ) => { + let response; + if (isBulkError) { + // mock the bulk error for only the second object + mockGetBulkOperationError.mockReturnValueOnce(undefined); + mockGetBulkOperationError.mockReturnValueOnce(expectedErrorResult.error as Payload); + response = getMockBulkCreateResponse([obj1, obj, obj2]); + } else { + response = getMockBulkCreateResponse([obj1, obj2]); + } + client.bulk.mockResponseOnce(response); + + const objects = [obj1, obj, obj2]; + const result = await repository.bulkCreate(objects); + expect(client.bulk).toHaveBeenCalled(); + const objCall = isBulkError ? expectObjArgs(obj) : []; + const body = [...expectObjArgs(obj1), ...objCall, ...expectObjArgs(obj2)]; + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body }), + expect.anything() + ); + expect(result).toEqual({ + saved_objects: [expectSuccess(obj1), expectedErrorResult, expectSuccess(obj2)], + }); + }; + + it(`throws when options.namespace is '*'`, async () => { + await expect( + repository.bulkCreate([obj3], { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestErrorPayload('"options.namespace" cannot be "*"')); + }); + + it(`returns error when initialNamespaces is used with a space-agnostic object`, async () => { + const obj = { ...obj3, type: NAMESPACE_AGNOSTIC_TYPE, initialNamespaces: [] }; + await bulkCreateError( + obj, + undefined, + expectErrorResult( + obj, + createBadRequestErrorPayload( + '"initialNamespaces" cannot be used on space-agnostic types' + ) + ) + ); + }); + + it(`returns error when initialNamespaces is empty`, async () => { + const obj = { ...obj3, type: MULTI_NAMESPACE_TYPE, initialNamespaces: [] }; + await bulkCreateError( + obj, + undefined, + expectErrorResult( + obj, + createBadRequestErrorPayload('"initialNamespaces" must be a non-empty array of strings') + ) + ); + }); + + it(`returns error when initialNamespaces is used with a space-isolated object and does not specify a single space`, async () => { + const doTest = async (objType: string, initialNamespaces: string[]) => { + const obj = { ...obj3, type: objType, initialNamespaces }; + await bulkCreateError( + obj, + undefined, + expectErrorResult( + obj, + createBadRequestErrorPayload( + '"initialNamespaces" can only specify a single space when used with space-isolated types' + ) + ) + ); + }; + await doTest('dashboard', ['spacex', 'spacey']); + await doTest('dashboard', ['*']); + await doTest(MULTI_NAMESPACE_ISOLATED_TYPE, ['spacex', 'spacey']); + await doTest(MULTI_NAMESPACE_ISOLATED_TYPE, ['*']); + }); + + it(`returns error when type is invalid`, async () => { + const obj = { ...obj3, type: 'unknownType' }; + await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); + }); + + it(`returns error when type is hidden`, async () => { + const obj = { ...obj3, type: HIDDEN_TYPE }; + await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); + }); + + it(`returns error when there is a conflict from preflightCheckForCreate`, async () => { + const objects = [ + // only the second, third, and fourth objects are passed to preflightCheckForCreate and result in errors + obj1, + { ...obj1, type: MULTI_NAMESPACE_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_TYPE }, + { ...obj3, type: MULTI_NAMESPACE_TYPE }, + obj2, + ]; + const [o1, o2, o3, o4, o5] = objects; + mockPreflightCheckForCreate.mockResolvedValueOnce([ + // first and last objects do not get passed in to preflightCheckForCreate at all + { type: o2.type, id: o2.id!, error: { type: 'conflict' } }, + { + type: o3.type, + id: o3.id!, + error: { type: 'unresolvableConflict', metadata: { isNotOverwritable: true } }, + }, + { + type: o4.type, + id: o4.id!, + error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['foo'] } }, + }, + ]); + const bulkResponse = getMockBulkCreateResponse([o1, o5]); + client.bulk.mockResponseOnce(bulkResponse); + + const options = { overwrite: true }; + const result = await repository.bulkCreate(objects, options); + expect(mockPreflightCheckForCreate).toHaveBeenCalled(); + expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( + expect.objectContaining({ + objects: [ + { type: o2.type, id: o2.id, overwrite: true, namespaces: ['default'] }, + { type: o3.type, id: o3.id, overwrite: true, namespaces: ['default'] }, + { type: o4.type, id: o4.id, overwrite: true, namespaces: ['default'] }, + ], + }) + ); + expect(client.bulk).toHaveBeenCalled(); + expect(client.bulk).toHaveBeenCalledWith( + expect.objectContaining({ body: [...expectObjArgs(o1), ...expectObjArgs(o5)] }), + expect.anything() + ); + expect(result).toEqual({ + saved_objects: [ + expectSuccess(o1), + expectErrorConflict(o2), + expectErrorConflict(o3, { metadata: { isNotOverwritable: true } }), + expectErrorConflict(o4, { metadata: { spacesWithConflictingAliases: ['foo'] } }), + expectSuccess(o5), + ], + }); + }); + + it(`returns bulk error`, async () => { + const expectedErrorResult = { + type: obj3.type, + id: obj3.id, + error: { error: 'Oh no, a bulk error!' }, + }; + await bulkCreateError(obj3, true, expectedErrorResult); + }); + + it(`returns errors for any bulk objects with invalid schemas`, async () => { + const response = getMockBulkCreateResponse([obj3]); + client.bulk.mockResponseOnce(response); + + const result = await repository.bulkCreate([ + obj3, + // @ts-expect-error - Title should be a string and is intentionally malformed for testing + { ...obj3, id: 'three-again', attributes: { title: 123 } }, + ]); + expect(client.bulk).toHaveBeenCalledTimes(1); // only called once for the valid object + expect(result.saved_objects).toEqual([ + expect.objectContaining(obj3), + expect.objectContaining({ + error: new Error( + '[attributes.title]: expected value of type [string] but got [number]: Bad Request' + ), + id: 'three-again', + type: 'dashboard', + }), + ]); + }); + }); + + describe('migration', () => { + it(`migrates the docs and serializes the migrated docs`, async () => { + migrator.migrateDocument.mockImplementation(mockMigrateDocument); + const modifiedObj1 = { ...obj1, coreMigrationVersion: '8.0.0' }; + await bulkCreateSuccess(client, repository, [modifiedObj1, obj2]); + const docs = [modifiedObj1, obj2].map((x) => ({ ...x, ...mockTimestampFieldsWithCreated })); + expectMigrationArgs(docs[0], true, 1); + expectMigrationArgs(docs[1], true, 2); + + const migratedDocs = docs.map((x) => migrator.migrateDocument(x)); + expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(1, migratedDocs[0]); + expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(2, migratedDocs[1]); + }); + + it(`adds namespace to body when providing namespace for single-namespace type`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); + expectMigrationArgs({ namespace }, true, 1); + expectMigrationArgs({ namespace }, true, 2); + }); + + it(`doesn't add namespace to body when providing no namespace for single-namespace type`, async () => { + await bulkCreateSuccess(client, repository, [obj1, obj2]); + expectMigrationArgs({ namespace: expect.anything() }, false, 1); + expectMigrationArgs({ namespace: expect.anything() }, false, 2); + }); + + it(`doesn't add namespace to body when not using single-namespace type`, async () => { + const objects = [ + { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, + { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, + ]; + await bulkCreateSuccess(client, repository, objects, { namespace }); + expectMigrationArgs({ namespace: expect.anything() }, false, 1); + expectMigrationArgs({ namespace: expect.anything() }, false, 2); + }); + + it(`adds namespaces to body when providing namespace for multi-namespace type`, async () => { + const objects = [obj1, obj2].map((obj) => ({ + ...obj, + type: MULTI_NAMESPACE_ISOLATED_TYPE, + })); + await bulkCreateSuccess(client, repository, objects, { namespace }); + expectMigrationArgs({ namespaces: [namespace] }, true, 1); + expectMigrationArgs({ namespaces: [namespace] }, true, 2); + }); + + it(`adds default namespaces to body when providing no namespace for multi-namespace type`, async () => { + const objects = [obj1, obj2].map((obj) => ({ + ...obj, + type: MULTI_NAMESPACE_ISOLATED_TYPE, + })); + await bulkCreateSuccess(client, repository, objects); + expectMigrationArgs({ namespaces: ['default'] }, true, 1); + expectMigrationArgs({ namespaces: ['default'] }, true, 2); + }); + + it(`doesn't add namespaces to body when not using multi-namespace type`, async () => { + const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }]; + await bulkCreateSuccess(client, repository, objects); + expectMigrationArgs({ namespaces: expect.anything() }, false, 1); + expectMigrationArgs({ namespaces: expect.anything() }, false, 2); + }); + }); + + describe('returns', () => { + it(`formats the ES response`, async () => { + const result = await bulkCreateSuccess(client, repository, [obj1, obj2]); + expect(result).toEqual({ + saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), + }); + }); + + it.todo(`should return objects in the same order regardless of type`); + + it(`handles a mix of successful creates and errors`, async () => { + const obj = { + type: 'unknownType', + id: 'three', + attributes: {}, + }; + const objects = [obj1, obj, obj2]; + const response = getMockBulkCreateResponse([obj1, obj2]); + client.bulk.mockResponseOnce(response); + const result = await repository.bulkCreate(objects); + expect(client.bulk).toHaveBeenCalledTimes(1); + expect(result).toEqual({ + saved_objects: [expectCreateResult(obj1), expectError(obj), expectCreateResult(obj2)], + }); + }); + + it(`a deserialized saved object`, async () => { + // Test for fix to https://github.com/elastic/kibana/issues/65088 where + // we returned raw ID's when an object without an id was created. + const namespace = 'myspace'; + // FIXME: this test is based on a gigantic hack to have the bulk operation return the source + // of the document when it actually does not, forcing to cast to any as BulkResponse + // does not contains _source + const response = getMockBulkCreateResponse([obj1, obj2], namespace) as any; + client.bulk.mockResponseOnce(response); + + // Bulk create one object with id unspecified, and one with id specified + const result = await repository.bulkCreate([{ ...obj1, id: undefined }, obj2], { + namespace, + }); + + // Assert that both raw docs from the ES response are deserialized + expect(serializer.rawToSavedObject).toHaveBeenNthCalledWith( + 1, + { + ...response.items[0].create, + _source: { + ...response.items[0].create._source, + namespaces: response.items[0].create._source.namespaces, + coreMigrationVersion: expect.any(String), + typeMigrationVersion: '1.1.1', + }, + _id: expect.stringMatching( + /^myspace:config:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/ + ), + }, + expect.any(Object) + ); + expect(serializer.rawToSavedObject).toHaveBeenNthCalledWith( + 2, + { + ...response.items[1].create, + _source: { + ...response.items[1].create._source, + namespaces: response.items[1].create._source.namespaces, + coreMigrationVersion: expect.any(String), + typeMigrationVersion: '1.1.1', + }, + }, + expect.any(Object) + ); + + // Assert that ID's are deserialized to remove the type and namespace + expect(result.saved_objects[0].id).toEqual( + expect.stringMatching(/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/) + ); + expect(result.saved_objects[1].id).toEqual(obj2.id); + + // Assert that managed is not changed + expect(result.saved_objects[0].managed).toBeFalsy(); + expect(result.saved_objects[1].managed).toEqual(obj2.managed); + }); + + it(`sets managed=false if not already set`, async () => { + const obj1WithoutManaged = { + type: 'config', + id: '6.0.0-alpha1', + attributes: { title: 'Test One' }, + references: [{ name: 'ref_0', type: 'test', id: '1' }], + }; + const obj2WithoutManaged = { + type: 'index-pattern', + id: 'logstash-*', + attributes: { title: 'Test Two' }, + references: [{ name: 'ref_0', type: 'test', id: '2' }], + }; + const result = await bulkCreateSuccess(client, repository, [ + obj1WithoutManaged, + obj2WithoutManaged, + ]); + expect(result).toEqual({ + saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), + }); + }); + + it(`sets managed=false only on documents without managed already set`, async () => { + const objWithoutManaged = { + type: 'config', + id: '6.0.0-alpha1', + attributes: { title: 'Test One' }, + references: [{ name: 'ref_0', type: 'test', id: '1' }], + }; + const result = await bulkCreateSuccess(client, repository, [objWithoutManaged, obj2]); + expect(result).toEqual({ + saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), + }); + }); + + it(`sets managed=true if provided as an override`, async () => { + const obj1WithoutManaged = { + type: 'config', + id: '6.0.0-alpha1', + attributes: { title: 'Test One' }, + references: [{ name: 'ref_0', type: 'test', id: '1' }], + }; + const obj2WithoutManaged = { + type: 'index-pattern', + id: 'logstash-*', + attributes: { title: 'Test Two' }, + references: [{ name: 'ref_0', type: 'test', id: '2' }], + }; + const result = await bulkCreateSuccess( + client, + repository, + [obj1WithoutManaged, obj2WithoutManaged], + { managed: true } + ); + expect(result).toEqual({ + saved_objects: [ + { ...obj1WithoutManaged, managed: true }, + { ...obj2WithoutManaged, managed: true }, + ].map((x) => expectCreateResult(x)), + }); + }); + + it(`sets managed=false if provided as an override`, async () => { + const obj1WithoutManaged = { + type: 'config', + id: '6.0.0-alpha1', + attributes: { title: 'Test One' }, + references: [{ name: 'ref_0', type: 'test', id: '1' }], + }; + const obj2WithoutManaged = { + type: 'index-pattern', + id: 'logstash-*', + attributes: { title: 'Test Two' }, + references: [{ name: 'ref_0', type: 'test', id: '2' }], + }; + const result = await bulkCreateSuccess( + client, + repository, + [obj1WithoutManaged, obj2WithoutManaged], + { managed: false } + ); + expect(result).toEqual({ + saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), + }); + }); + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.test.ts index d24c11f19069..60deaa64e3e6 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.test.ts @@ -75,6 +75,17 @@ describe('SavedObjectsRepository', () => { return expect.toBeDocumentWithoutError(type, id); }; + const expectMigrationArgs = (args: unknown, contains = true, n = 1) => { + const obj = contains ? expect.objectContaining(args) : expect.not.objectContaining(args); + expect(migrator.migrateDocument).toHaveBeenNthCalledWith( + n, + obj, + expect.objectContaining({ + allowDowngrade: expect.any(Boolean), + }) + ); + }; + beforeEach(() => { pointInTimeFinderMock.mockClear(); client = elasticsearchClientMock.createElasticsearchClient(); @@ -121,7 +132,7 @@ describe('SavedObjectsRepository', () => { const originId = 'some-origin-id'; const namespace = 'foo-namespace'; - // bulk create calls have two objects for each source -- the action, and the source + // bulk index calls have two objects for each source -- the action, and the source const expectClientCallArgsAction = ( objects: TypeIdTuple[], { @@ -153,14 +164,26 @@ describe('SavedObjectsRepository', () => { ); }; - const expectObjArgs = ({ type, attributes }: { type: string; attributes: unknown }) => [ - expect.any(Object), + const expectObjArgs = ( { - doc: expect.objectContaining({ - [type]: attributes, - ...mockTimestampFields, - }), + type, + attributes, + references, + }: { + type: string; + attributes: unknown; + references?: SavedObjectReference[]; }, + overrides: Record = {} + ) => [ + expect.any(Object), + expect.objectContaining({ + [type]: attributes, + references, + type, + ...overrides, + ...mockTimestampFields, + }), ]; describe('client calls', () => { @@ -169,13 +192,14 @@ describe('SavedObjectsRepository', () => { expect(client.bulk).toHaveBeenCalled(); }); - it(`should use the ES mget action before bulk action for any types that are multi-namespace`, async () => { + it(`should use the ES mget action before bulk action for any types that are valid`, async () => { const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; await bulkUpdateSuccess(client, repository, registry, objects); expect(client.bulk).toHaveBeenCalled(); expect(client.mget).toHaveBeenCalled(); const docs = [ + expect.objectContaining({ _id: `${obj1.type}:${obj1.id}` }), expect.objectContaining({ _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${obj2.id}` }), ]; expect(client.mget).toHaveBeenCalledWith( @@ -186,21 +210,14 @@ describe('SavedObjectsRepository', () => { it(`formats the ES request`, async () => { await bulkUpdateSuccess(client, repository, registry, [obj1, obj2]); - const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); + // expect client.bulk call args should include the whole doc + expectClientCallArgsAction([obj1, obj2], { method: 'index' }); }); it(`formats the ES request for any types that are multi-namespace`, async () => { const _obj2 = { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }; await bulkUpdateSuccess(client, repository, registry, [obj1, _obj2]); - const body = [...expectObjArgs(obj1), ...expectObjArgs(_obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); + expectClientCallArgsAction([obj1, _obj2], { method: 'index' }); }); it(`doesnt call Elasticsearch if there are no valid objects to update`, async () => { @@ -211,8 +228,10 @@ describe('SavedObjectsRepository', () => { it(`defaults to no references`, async () => { await bulkUpdateSuccess(client, repository, registry, [obj1, obj2]); - const expected = { doc: expect.not.objectContaining({ references: expect.anything() }) }; - const body = [expect.any(Object), expected, expect.any(Object), expected]; + const body = [ + ...expectObjArgs({ ...obj1, references: [] }), + ...expectObjArgs({ ...obj2, references: [] }), + ]; expect(client.bulk).toHaveBeenCalledWith( expect.objectContaining({ body }), expect.anything() @@ -223,13 +242,16 @@ describe('SavedObjectsRepository', () => { const test = async (references: SavedObjectReference[]) => { const objects = [obj1, obj2].map((obj) => ({ ...obj, references })); await bulkUpdateSuccess(client, repository, registry, objects); - const expected = { doc: expect.objectContaining({ references }) }; - const body = [expect.any(Object), expected, expect.any(Object), expected]; + const body = [ + ...expectObjArgs({ ...obj1, references }), + ...expectObjArgs({ ...obj2, references }), + ]; expect(client.bulk).toHaveBeenCalledWith( expect.objectContaining({ body }), expect.anything() ); client.bulk.mockClear(); + client.mget.mockClear(); }; await test(references); await test([{ type: 'type', id: 'id', name: 'some ref' }]); @@ -238,15 +260,18 @@ describe('SavedObjectsRepository', () => { it(`doesn't accept custom references if not an array`, async () => { const test = async (references: unknown) => { - const objects = [obj1, obj2]; // .map((obj) => ({ ...obj })); + const objects = [obj1, obj2]; await bulkUpdateSuccess(client, repository, registry, objects); - const expected = { doc: expect.not.objectContaining({ references: expect.anything() }) }; - const body = [expect.any(Object), expected, expect.any(Object), expected]; + const body = [ + ...expectObjArgs({ ...obj1, references: expect.not.arrayContaining([references]) }), + ...expectObjArgs({ ...obj2, references: expect.not.arrayContaining([references]) }), + ]; expect(client.bulk).toHaveBeenCalledWith( expect.objectContaining({ body }), expect.anything() ); client.bulk.mockClear(); + client.mget.mockClear(); }; await test('string'); await test(123); @@ -265,7 +290,7 @@ describe('SavedObjectsRepository', () => { it(`defaults to no version for types that are not multi-namespace`, async () => { const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }]; await bulkUpdateSuccess(client, repository, registry, objects); - expectClientCallArgsAction(objects, { method: 'update' }); + expectClientCallArgsAction(objects, { method: 'index' }); }); it(`accepts version`, async () => { @@ -277,13 +302,13 @@ describe('SavedObjectsRepository', () => { ]; await bulkUpdateSuccess(client, repository, registry, objects); const overrides = { if_seq_no: 100, if_primary_term: 200 }; - expectClientCallArgsAction(objects, { method: 'update', overrides }); + expectClientCallArgsAction(objects, { method: 'index', overrides }); }); it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { const getId = (type: string, id: string) => `${namespace}:${type}:${id}`; // test that the raw document ID equals this (e.g., has a namespace prefix) await bulkUpdateSuccess(client, repository, registry, [obj1, obj2], { namespace }); - expectClientCallArgsAction([obj1, obj2], { method: 'update', getId }); + expectClientCallArgsAction([obj1, obj2], { method: 'index', getId }); jest.clearAllMocks(); // test again with object namespace string that supersedes the operation's namespace ID @@ -291,13 +316,13 @@ describe('SavedObjectsRepository', () => { { ...obj1, namespace }, { ...obj2, namespace }, ]); - expectClientCallArgsAction([obj1, obj2], { method: 'update', getId }); + expectClientCallArgsAction([obj1, obj2], { method: 'index', getId }); }); it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { const getId = (type: string, id: string) => `${type}:${id}`; // test that the raw document ID equals this (e.g., does not have a namespace prefix) await bulkUpdateSuccess(client, repository, registry, [obj1, obj2]); - expectClientCallArgsAction([obj1, obj2], { method: 'update', getId }); + expectClientCallArgsAction([obj1, obj2], { method: 'index', getId }); jest.clearAllMocks(); // test again with object namespace string that supersedes the operation's namespace ID @@ -311,7 +336,7 @@ describe('SavedObjectsRepository', () => { ], { namespace } ); - expectClientCallArgsAction([obj1, obj2], { method: 'update', getId }); + expectClientCallArgsAction([obj1, obj2], { method: 'index', getId }); }); it(`normalizes options.namespace from 'default' to undefined`, async () => { @@ -319,7 +344,7 @@ describe('SavedObjectsRepository', () => { await bulkUpdateSuccess(client, repository, registry, [obj1, obj2], { namespace: 'default', }); - expectClientCallArgsAction([obj1, obj2], { method: 'update', getId }); + expectClientCallArgsAction([obj1, obj2], { method: 'index', getId }); }); it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => { @@ -328,18 +353,20 @@ describe('SavedObjectsRepository', () => { const _obj2 = { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }; await bulkUpdateSuccess(client, repository, registry, [_obj1], { namespace }); - expectClientCallArgsAction([_obj1], { method: 'update', getId }); + expectClientCallArgsAction([_obj1], { method: 'index', getId }); client.bulk.mockClear(); + client.mget.mockClear(); await bulkUpdateSuccess(client, repository, registry, [_obj2], { namespace }); - expectClientCallArgsAction([_obj2], { method: 'update', getId }); + expectClientCallArgsAction([_obj2], { method: 'index', getId }); jest.clearAllMocks(); // test again with object namespace string that supersedes the operation's namespace ID await bulkUpdateSuccess(client, repository, registry, [{ ..._obj1, namespace }]); - expectClientCallArgsAction([_obj1], { method: 'update', getId }); + expectClientCallArgsAction([_obj1], { method: 'index', getId }); client.bulk.mockClear(); + client.mget.mockClear(); await bulkUpdateSuccess(client, repository, registry, [{ ..._obj2, namespace }]); - expectClientCallArgsAction([_obj2], { method: 'update', getId }); + expectClientCallArgsAction([_obj2], { method: 'index', getId }); }); }); @@ -359,51 +386,71 @@ describe('SavedObjectsRepository', () => { isBulkError: boolean, expectedErrorResult: ExpectedErrorResult ) => { - const objects = [obj1, obj, obj2]; - const mockResponse = getMockBulkUpdateResponse(registry, objects); + const objects = [obj1, obj2, obj]; + + const mockedMgetResponse = getMockMgetResponse(registry, [obj1, obj2, obj]); + client.bulk.mockClear(); + client.mget.mockClear(); + client.mget.mockResponseOnce(mockedMgetResponse); + + const mockBulkIndexResponse = getMockBulkUpdateResponse(registry, objects); if (isBulkError) { - // mock the bulk error for only the second object + // mock the bulk error for only the third object + mockGetBulkOperationError.mockReturnValueOnce(undefined); mockGetBulkOperationError.mockReturnValueOnce(undefined); mockGetBulkOperationError.mockReturnValueOnce(expectedErrorResult.error as Payload); } - client.bulk.mockResponseOnce(mockResponse); + client.bulk.mockResponseOnce(mockBulkIndexResponse); const result = await repository.bulkUpdate(objects); + + expect(client.mget).toHaveBeenCalled(); expect(client.bulk).toHaveBeenCalled(); - const objCall = isBulkError ? expectObjArgs(obj) : []; - const body = [...expectObjArgs(obj1), ...objCall, ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); + + const expectClientCallObjects = isBulkError ? [obj1, obj2, obj] : [obj1, obj2]; + expectClientCallArgsAction(expectClientCallObjects, { method: 'index' }); + expect(result).toEqual({ - saved_objects: [expectSuccess(obj1), expectedErrorResult, expectSuccess(obj2)], + saved_objects: [expectSuccess(obj1), expectSuccess(obj2), expectedErrorResult], }); }; const bulkUpdateMultiError = async ( - [obj1, _obj, obj2]: SavedObjectsBulkUpdateObject[], + [obj1, obj2, _obj]: SavedObjectsBulkUpdateObject[], options: SavedObjectsBulkUpdateOptions | undefined, mgetResponse: estypes.MgetResponse, mgetOptions?: { statusCode?: number } ) => { + client.bulk.mockClear(); + client.mget.mockClear(); + // we only need to mock the response once. A 404 status code will apply to the response for all client.mget.mockResponseOnce(mgetResponse, { statusCode: mgetOptions?.statusCode }); - const bulkResponse = getMockBulkUpdateResponse(registry, [obj1, obj2], { namespace }); - client.bulk.mockResponseOnce(bulkResponse); + const mockBulkIndexResponse = getMockBulkUpdateResponse(registry, [obj1, obj2], { + namespace, + }); + client.bulk.mockResponseOnce(mockBulkIndexResponse); + + const result = await repository.bulkUpdate([obj1, obj2, _obj], options); - const result = await repository.bulkUpdate([obj1, _obj, obj2], options); - expect(client.bulk).toHaveBeenCalled(); expect(client.mget).toHaveBeenCalled(); - const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - - expect(result).toEqual({ - saved_objects: [expectSuccess(obj1), expectErrorNotFound(_obj), expectSuccess(obj2)], - }); + if (mgetOptions?.statusCode === 404) { + expect(client.bulk).not.toHaveBeenCalled(); + expect(result).toEqual({ + saved_objects: [ + expectErrorNotFound(obj1), + expectErrorNotFound(obj2), + expectErrorNotFound(_obj), + ], + }); + } else { + expect(client.bulk).toHaveBeenCalled(); + expectClientCallArgsAction([obj1, obj2], { method: 'index' }); + + expect(result).toEqual({ + saved_objects: [expectSuccess(obj1), expectSuccess(obj2), expectErrorNotFound(_obj)], + }); + } }; it(`throws when options.namespace is '*'`, async () => { @@ -433,22 +480,22 @@ describe('SavedObjectsRepository', () => { it(`returns error when ES is unable to find the document (mget)`, async () => { const _obj = { ...obj, type: MULTI_NAMESPACE_ISOLATED_TYPE, found: false }; - const mgetResponse = getMockMgetResponse(registry, [_obj]); - await bulkUpdateMultiError([obj1, _obj, obj2], undefined, mgetResponse); + const mgetResponse = getMockMgetResponse(registry, [obj1, obj2, _obj]); + await bulkUpdateMultiError([obj1, obj2, _obj], undefined, mgetResponse); }); it(`returns error when ES is unable to find the index (mget)`, async () => { const _obj = { ...obj, type: MULTI_NAMESPACE_ISOLATED_TYPE }; - const mgetResponse = getMockMgetResponse(registry, [_obj]); - await bulkUpdateMultiError([obj1, _obj, obj2], { namespace }, mgetResponse, { + const mgetResponse = getMockMgetResponse(registry, [obj1, obj2, _obj]); + await bulkUpdateMultiError([obj1, obj2, _obj], { namespace }, mgetResponse, { statusCode: 404, }); }); it(`returns error when there is a conflict with an existing multi-namespace saved object (mget)`, async () => { const _obj = { ...obj, type: MULTI_NAMESPACE_ISOLATED_TYPE }; - const mgetResponse = getMockMgetResponse(registry, [_obj], 'bar-namespace'); - await bulkUpdateMultiError([obj1, _obj, obj2], { namespace }, mgetResponse); + const mgetResponse = getMockMgetResponse(registry, [obj1, obj2, _obj], 'bar-namespace'); + await bulkUpdateMultiError([obj1, obj2, _obj], { namespace }, mgetResponse); }); it(`returns bulk error`, async () => { @@ -460,6 +507,52 @@ describe('SavedObjectsRepository', () => { await bulkUpdateError(obj, true, expectedErrorResult); }); }); + describe('migration', () => { + it('migrates the fetched documents from Mget', async () => { + const modifiedObj2 = { ...obj2, coreMigrationVersion: '8.0.0' }; + const objects = [modifiedObj2]; + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + + await bulkUpdateSuccess(client, repository, registry, objects); + expect(migrator.migrateDocument).toHaveBeenCalledTimes(2); + expectMigrationArgs({ + id: modifiedObj2.id, + type: modifiedObj2.type, + }); + }); + + it('migrates namespace agnostic and multinamespace object documents', async () => { + const modifiedObj2 = { + ...obj2, + coreMigrationVersion: '8.0.0', + type: MULTI_NAMESPACE_ISOLATED_TYPE, + namespace: 'default', + }; + const modifiedObj1 = { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }; + const objects = [modifiedObj2, modifiedObj1]; + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + + await bulkUpdateSuccess(client, repository, registry, objects, { namespace }); + + expect(migrator.migrateDocument).toHaveBeenCalledTimes(4); + expectMigrationArgs( + { + id: modifiedObj2.id, + type: modifiedObj2.type, + }, + true, + 1 + ); + expectMigrationArgs( + { + id: modifiedObj1.id, + type: modifiedObj1.type, + }, + true, + 2 + ); + }); + }); describe('returns', () => { it(`formats the ES response`, async () => { @@ -483,14 +576,24 @@ describe('SavedObjectsRepository', () => { id: 'three', attributes: {}, }; - const objects = [obj1, obj, obj2]; - const mockResponse = getMockBulkUpdateResponse(registry, objects); - client.bulk.mockResponseOnce(mockResponse); + const objects = [obj1, obj2, obj]; + const mockedMgetResponse = getMockMgetResponse(registry, [obj1, obj2, obj]); + client.bulk.mockClear(); + client.mget.mockClear(); + client.mget.mockResponseOnce(mockedMgetResponse); + const mockBulkIndexResponse = getMockBulkUpdateResponse(registry, objects); + client.bulk.mockResponseOnce(mockBulkIndexResponse); const result = await repository.bulkUpdate(objects); - expect(client.bulk).toHaveBeenCalledTimes(1); + + expect(client.mget).toHaveBeenCalled(); + expect(client.bulk).toHaveBeenCalled(); + + const expectClientCallObjects = [obj1, obj2]; + expectClientCallArgsAction(expectClientCallObjects, { method: 'index' }); + expect(result).toEqual({ - saved_objects: [expectUpdateResult(obj1), expectError(obj), expectUpdateResult(obj2)], + saved_objects: [expectUpdateResult(obj1), expectUpdateResult(obj2), expectError(obj)], }); }); @@ -515,14 +618,25 @@ describe('SavedObjectsRepository', () => { id: 'three', attributes: {}, }; - const result = await bulkUpdateSuccess( - client, - repository, - registry, - [obj1, obj], - {}, - originId - ); + client.bulk.mockClear(); + client.mget.mockClear(); + const objects = [ + { ...obj1, originId }, + { ...obj, originId }, + ]; + const mockedMgetResponse = getMockMgetResponse(registry, objects); + + client.mget.mockResponseOnce(mockedMgetResponse); + + const mockBulkIndexResponse = getMockBulkUpdateResponse(registry, objects, {}, originId); + client.bulk.mockResponseOnce(mockBulkIndexResponse); + const result = await repository.bulkUpdate(objects); + + expect(client.mget).toHaveBeenCalled(); + expect(client.bulk).toHaveBeenCalled(); + + const expectClientCallObjects = objects; + expectClientCallArgsAction(expectClientCallObjects, { method: 'index' }); expect(result).toEqual({ saved_objects: [ expect.objectContaining({ originId }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.ts index b9c0f10a9021..9c119ff86e7d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_update.ts @@ -14,6 +14,8 @@ import { DecoratedError, AuthorizeUpdateObject, SavedObjectsRawDoc, + SavedObjectsRawDocSource, + SavedObjectSanitizedDoc, } from '@kbn/core-saved-objects-server'; import { ALL_NAMESPACES_STRING, SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server'; import { encodeVersion } from '@kbn/core-saved-objects-base-server-internal'; @@ -35,6 +37,8 @@ import { isLeft, isRight, rawDocExistsInNamespace, + getSavedObjectFromSource, + mergeForUpdate, } from './utils'; import { ApiExecutionContext } from './types'; @@ -43,32 +47,51 @@ export interface PerformUpdateParams { options: SavedObjectsBulkUpdateOptions; } +type DocumentToSave = Record; +type ExpectedBulkGetResult = Either< + { type: string; id: string; error: Payload }, + { + type: string; + id: string; + version?: string; + documentToSave: DocumentToSave; + objectNamespace?: string; + esRequestIndex: number; + migrationVersionCompatibility?: 'raw' | 'compatible'; + } +>; + +type ExpectedBulkUpdateResult = Either< + { type: string; id: string; error: Payload }, + { + type: string; + id: string; + namespaces?: string[]; + documentToSave: DocumentToSave; + esRequestIndex: number; + rawMigratedUpdatedDoc: SavedObjectsRawDoc; + } +>; + export const performBulkUpdate = async ( { objects, options }: PerformUpdateParams, { registry, helpers, allowedTypes, client, serializer, extensions = {} }: ApiExecutionContext ): Promise> => { - const { common: commonHelper, encryption: encryptionHelper } = helpers; + const { + common: commonHelper, + encryption: encryptionHelper, + migration: migrationHelper, + } = helpers; const { securityExtension } = extensions; - + const { migrationVersionCompatibility } = options; const namespace = commonHelper.getCurrentNamespace(options.namespace); const time = getCurrentTime(); let bulkGetRequestIndexCounter = 0; - type DocumentToSave = Record; - type ExpectedBulkGetResult = Either< - { type: string; id: string; error: Payload }, - { - type: string; - id: string; - version?: string; - documentToSave: DocumentToSave; - objectNamespace?: string; - esRequestIndex?: number; - } - >; const expectedBulkGetResults = objects.map((object) => { const { type, id, attributes, references, version, namespace: objectNamespace } = object; let error: DecoratedError | undefined; + if (!allowedTypes.includes(type)) { error = SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); } else { @@ -91,21 +114,19 @@ export const performBulkUpdate = async ( ...(Array.isArray(references) && { references }), }; - const requiresNamespacesCheck = registry.isMultiNamespace(object.type); - return right({ type, id, version, documentToSave, objectNamespace, - ...(requiresNamespacesCheck && { esRequestIndex: bulkGetRequestIndexCounter++ }), + esRequestIndex: bulkGetRequestIndexCounter++, + migrationVersionCompatibility, }); }); const validObjects = expectedBulkGetResults.filter(isRight); if (validObjects.length === 0) { - // We only have error results; return early to avoid potentially trying authZ checks for 0 types which would result in an exception. return { // Technically the returned array should only contain SavedObject results, but for errors this is not true (we cast to 'any' below) saved_objects: expectedBulkGetResults.map>( @@ -117,20 +138,25 @@ export const performBulkUpdate = async ( // `objectNamespace` is a namespace string, while `namespace` is a namespace ID. // The object namespace string, if defined, will supersede the operation's namespace ID. const namespaceString = SavedObjectsUtils.namespaceIdToString(namespace); + const getNamespaceId = (objectNamespace?: string) => objectNamespace !== undefined ? SavedObjectsUtils.namespaceStringToId(objectNamespace) : namespace; + const getNamespaceString = (objectNamespace?: string) => objectNamespace ?? namespaceString; - const bulkGetDocs = validObjects - .filter(({ value }) => value.esRequestIndex !== undefined) - .map(({ value: { type, id, objectNamespace } }) => ({ - _id: serializer.generateRawId(getNamespaceId(objectNamespace), type, id), - _index: commonHelper.getIndexForType(type), - _source: ['type', 'namespaces'], - })); + + const bulkGetDocs = validObjects.map(({ value: { type, id, objectNamespace } }) => ({ + _id: serializer.generateRawId(getNamespaceId(objectNamespace), type, id), + _index: commonHelper.getIndexForType(type), + _source: true, + })); + const bulkGetResponse = bulkGetDocs.length - ? await client.mget({ body: { docs: bulkGetDocs } }, { ignore: [404], meta: true }) + ? await client.mget( + { body: { docs: bulkGetDocs } }, + { ignore: [404], meta: true } + ) : undefined; // fail fast if we can't verify a 404 response is from Elasticsearch if ( @@ -145,14 +171,24 @@ export const performBulkUpdate = async ( const authObjects: AuthorizeUpdateObject[] = validObjects.map((element) => { const { type, id, objectNamespace, esRequestIndex: index } = element.value; - const preflightResult = index !== undefined ? bulkGetResponse?.body.docs[index] : undefined; - return { - type, - id, - objectNamespace, - // @ts-expect-error MultiGetHit._source is optional - existingNamespaces: preflightResult?._source?.namespaces ?? [], - }; + const preflightResult = bulkGetResponse!.body.docs[index]; + + if (registry.isMultiNamespace(type)) { + return { + type, + id, + objectNamespace, + // @ts-expect-error MultiGetHit._source is optional + existingNamespaces: preflightResult._source?.namespaces ?? [], + }; + } else { + return { + type, + id, + objectNamespace, + existingNamespaces: [], + }; + } }); const authorizationResult = await securityExtension?.authorizeBulkUpdate({ @@ -162,16 +198,7 @@ export const performBulkUpdate = async ( let bulkUpdateRequestIndexCounter = 0; const bulkUpdateParams: object[] = []; - type ExpectedBulkUpdateResult = Either< - { type: string; id: string; error: Payload }, - { - type: string; - id: string; - namespaces: string[]; - documentToSave: DocumentToSave; - esRequestIndex: number; - } - >; + const expectedBulkUpdateResults = await Promise.all( expectedBulkGetResults.map>(async (expectedBulkGetResult) => { if (isLeft(expectedBulkGetResult)) { @@ -181,67 +208,105 @@ export const performBulkUpdate = async ( const { esRequestIndex, id, type, version, documentToSave, objectNamespace } = expectedBulkGetResult.value; - let namespaces; - let versionProperties; - if (esRequestIndex !== undefined) { - const indexFound = bulkGetResponse?.statusCode !== 404; - const actualResult = indexFound ? bulkGetResponse?.body.docs[esRequestIndex] : undefined; - const docFound = indexFound && isMgetDoc(actualResult) && actualResult.found; - if ( - !docFound || + let namespaces: string[] | undefined; + const versionProperties = getExpectedVersionProperties(version); + const indexFound = bulkGetResponse?.statusCode !== 404; + const actualResult = indexFound ? bulkGetResponse?.body.docs[esRequestIndex] : undefined; + const docFound = indexFound && isMgetDoc(actualResult) && actualResult.found; + const isMultiNS = registry.isMultiNamespace(type); + + if ( + !docFound || + (isMultiNS && !rawDocExistsInNamespace( registry, actualResult as SavedObjectsRawDoc, getNamespaceId(objectNamespace) - ) - ) { - return left({ - id, - type, - error: errorContent(SavedObjectsErrorHelpers.createGenericNotFoundError(type, id)), - }); - } + )) + ) { + return left({ + id, + type, + error: errorContent(SavedObjectsErrorHelpers.createGenericNotFoundError(type, id)), + }); + } + + if (isMultiNS) { // @ts-expect-error MultiGetHit is incorrectly missing _id, _source namespaces = actualResult!._source.namespaces ?? [ // @ts-expect-error MultiGetHit is incorrectly missing _id, _source SavedObjectsUtils.namespaceIdToString(actualResult!._source.namespace), ]; - versionProperties = getExpectedVersionProperties(version); - } else { - if (registry.isSingleNamespace(type)) { - // if `objectNamespace` is undefined, fall back to `options.namespace` - namespaces = [getNamespaceString(objectNamespace)]; - } - versionProperties = getExpectedVersionProperties(version); + } else if (registry.isSingleNamespace(type)) { + // if `objectNamespace` is undefined, fall back to `options.namespace` + namespaces = [getNamespaceString(objectNamespace)]; + } + + const document = getSavedObjectFromSource( + registry, + type, + id, + actualResult as SavedObjectsRawDoc, + { migrationVersionCompatibility } + ); + + let migrated: SavedObject; + try { + migrated = migrationHelper.migrateStorageDocument(document) as SavedObject; + } catch (migrateStorageDocError) { + throw SavedObjectsErrorHelpers.decorateGeneralError( + migrateStorageDocError, + 'Failed to migrate document to the latest version.' + ); } + const typeDefinition = registry.getType(type)!; + const updatedAttributes = mergeForUpdate({ + targetAttributes: { + ...migrated!.attributes, + }, + updatedAttributes: await encryptionHelper.optionallyEncryptAttributes( + type, + id, + objectNamespace || namespace, + documentToSave[type] + ), + typeMappings: typeDefinition.mappings, + }); + + const migratedUpdatedSavedObjectDoc = migrationHelper.migrateInputDocument({ + ...migrated!, + id, + type, + namespace, + namespaces, + attributes: updatedAttributes, + updated_at: time, + ...(Array.isArray(documentToSave.references) && { references: documentToSave.references }), + }); + const updatedMigratedDocumentToSave = serializer.savedObjectToRaw( + migratedUpdatedSavedObjectDoc as SavedObjectSanitizedDoc + ); + const expectedResult = { type, id, namespaces, esRequestIndex: bulkUpdateRequestIndexCounter++, documentToSave: expectedBulkGetResult.value.documentToSave, + rawMigratedUpdatedDoc: updatedMigratedDocumentToSave, + migrationVersionCompatibility, }; bulkUpdateParams.push( { - update: { + index: { _id: serializer.generateRawId(getNamespaceId(objectNamespace), type, id), _index: commonHelper.getIndexForType(type), ...versionProperties, }, }, - { - doc: { - ...documentToSave, - [type]: await encryptionHelper.optionallyEncryptAttributes( - type, - id, - objectNamespace || namespace, - documentToSave[type] - ), - }, - } + updatedMigratedDocumentToSave._source ); return right(expectedResult); @@ -264,7 +329,8 @@ export const performBulkUpdate = async ( return expectedResult.value as any; } - const { type, id, namespaces, documentToSave, esRequestIndex } = expectedResult.value; + const { type, id, namespaces, documentToSave, esRequestIndex, rawMigratedUpdatedDoc } = + expectedResult.value; const response = bulkUpdateResponse?.items[esRequestIndex] ?? {}; const rawResponse = Object.values(response)[0] as any; @@ -273,14 +339,12 @@ export const performBulkUpdate = async ( return { type, id, error }; } - // When a bulk update operation is completed, any fields specified in `_sourceIncludes` will be found in the "get" value of the - // returned object. We need to retrieve the `originId` if it exists so we can return it to the consumer. - const { _seq_no: seqNo, _primary_term: primaryTerm, get } = rawResponse; + const { _seq_no: seqNo, _primary_term: primaryTerm } = rawResponse; // eslint-disable-next-line @typescript-eslint/naming-convention const { [type]: attributes, references, updated_at } = documentToSave; - const { originId } = get._source; + const { originId } = rawMigratedUpdatedDoc._source; return { id, type, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts index fd9c587502d7..61f9cb4cfdb2 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts @@ -106,7 +106,7 @@ export const executeUpdate = async ( preflightDocResult, }); - const existingNamespaces = preflightDocNSResult?.savedObjectNamespaces ?? []; + const existingNamespaces = preflightDocNSResult.savedObjectNamespaces ?? []; const authorizationResult = await securityExtension?.authorizeUpdate({ namespace, object: { type, id, existingNamespaces }, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.test.ts index a2b4121cebad..79e04bae320c 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.test.ts @@ -235,6 +235,81 @@ describe('createPointInTimeFinder()', () => { ); }); + test('does not yield empty first page', async () => { + repository.openPointInTimeForType.mockResolvedValueOnce({ + id: 'abc123', + }); + repository.find.mockResolvedValueOnce({ + total: 2, + saved_objects: [], + pit_id: 'abc123', + per_page: 2, + page: 0, + }); + + const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { + type: ['visualization'], + search: 'foo*', + }; + + const internalOptions = {}; + const finder = new PointInTimeFinder(findOptions, { + logger, + client: repository, + internalOptions, + }); + + const hits: SavedObjectsFindResult[] = []; + let pageCount = 0; + for await (const result of finder.find()) { + hits.push(...result.saved_objects); + pageCount++; + } + + expect(pageCount).toEqual(0); + expect(hits.length).toEqual(0); + }); + + test('yields empty first page if aggregations are used', async () => { + repository.openPointInTimeForType.mockResolvedValueOnce({ + id: 'abc123', + }); + repository.find.mockResolvedValueOnce({ + total: 2, + saved_objects: [], + pit_id: 'abc123', + per_page: 2, + page: 0, + }); + + const findOptions: SavedObjectsCreatePointInTimeFinderOptions = { + type: ['visualization'], + search: 'foo*', + aggs: { + some: { + avg: { field: 'fo' }, + }, + }, + }; + + const internalOptions = {}; + const finder = new PointInTimeFinder(findOptions, { + logger, + client: repository, + internalOptions, + }); + + const hits: SavedObjectsFindResult[] = []; + let pageCount = 0; + for await (const result of finder.find()) { + hits.push(...result.saved_objects); + pageCount++; + } + + expect(pageCount).toEqual(1); + expect(hits.length).toEqual(0); + }); + test('still applies the defaults in the mandatory fields even when `undefined` is explicitly provided', async () => { repository.openPointInTimeForType.mockResolvedValueOnce({ id: 'abc123', diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.ts index 524b57189400..7a2c124a0e86 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/point_in_time_finder.ts @@ -93,7 +93,12 @@ export class PointInTimeFinder await this.close(); } - yield results; + // do not yield first page if empty, unless there are aggregations + // (in which case we always want to return at least one page) + if (lastResultsCount > 0 || this.#findOptions.aggs) { + yield results; + } + // We've reached the end when there are fewer hits than our perPage size, // or when `close()` has been called. } while (this.#open && lastResultsCount >= this.#findOptions.perPage!); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts index 29983177adc9..82a7d2930f8d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts @@ -696,26 +696,23 @@ describe('SavedObjectsRepository Spaces Extension', () => { expect.objectContaining({ body: expect.arrayContaining([ expect.objectContaining({ - update: expect.objectContaining({ + index: expect.objectContaining({ _id: `${ currentSpace.expectedNamespace ? `${currentSpace.expectedNamespace}:` : '' }${obj1.type}:${obj1.id}`, }), }), expect.objectContaining({ - doc: expect.objectContaining({ - config: obj1.attributes, - }), + config: obj1.attributes, }), + expect.objectContaining({ - update: expect.objectContaining({ + index: expect.objectContaining({ _id: `${obj2.type}:${obj2.id}`, }), }), expect.objectContaining({ - doc: expect.objectContaining({ - multiNamespaceType: obj2.attributes, - }), + multiNamespaceType: obj2.attributes, }), ]), }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts index 1084ad3e5896..3547d653e3de 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts @@ -32,7 +32,6 @@ import type { SavedObjectsIncrementCounterOptions, SavedObjectsCreatePointInTimeFinderDependencies, SavedObjectsCreatePointInTimeFinderOptions, - SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, SavedObjectsCreateOptions, SavedObjectsDeleteOptions, @@ -86,13 +85,10 @@ import { getMockMgetResponse, type TypeIdTuple, createSpySerializer, - bulkCreateSuccess, - getMockBulkCreateResponse, bulkGet, expectErrorResult, expectErrorInvalidType, expectErrorNotFound, - expectErrorConflict, expectError, generateIndexPatternSearchResults, findSuccess, @@ -105,7 +101,6 @@ import { createUnsupportedTypeErrorPayload, createConflictErrorPayload, createGenericNotFoundErrorPayload, - expectCreateResult, mockTimestampFieldsWithCreated, getMockEsBulkDeleteResponse, bulkDeleteSuccess, @@ -193,917 +188,6 @@ describe('SavedObjectsRepository', () => { references: [{ name: 'search_0', type: 'search', id: '123' }], }); - describe('#bulkCreate', () => { - beforeEach(() => { - mockPreflightCheckForCreate.mockReset(); - mockPreflightCheckForCreate.mockImplementation(({ objects }) => { - return Promise.resolve(objects.map(({ type, id }) => ({ type, id }))); // respond with no errors by default - }); - }); - - const obj1 = { - type: 'config', - id: '6.0.0-alpha1', - attributes: { title: 'Test One' }, - references: [{ name: 'ref_0', type: 'test', id: '1' }], - managed: false, - }; - const obj2 = { - type: 'index-pattern', - id: 'logstash-*', - attributes: { title: 'Test Two' }, - references: [{ name: 'ref_0', type: 'test', id: '2' }], - managed: false, - }; - const namespace = 'foo-namespace'; - - // bulk create calls have two objects for each source -- the action, and the source - const expectClientCallArgsAction = ( - objects: Array<{ type: string; id?: string; if_primary_term?: string; if_seq_no?: string }>, - { - method, - _index = expect.any(String), - getId = () => expect.any(String), - }: { method: string; _index?: string; getId?: (type: string, id?: string) => string } - ) => { - const body = []; - for (const { type, id, if_primary_term: ifPrimaryTerm, if_seq_no: ifSeqNo } of objects) { - body.push({ - [method]: { - _index, - _id: getId(type, id), - ...(ifPrimaryTerm && ifSeqNo - ? { if_primary_term: expect.any(Number), if_seq_no: expect.any(Number) } - : {}), - }, - }); - body.push(expect.any(Object)); - } - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }; - - const expectObjArgs = ( - { - type, - attributes, - references, - }: { type: string; attributes: unknown; references?: SavedObjectReference[] }, - overrides: Record = {} - ) => [ - expect.any(Object), - expect.objectContaining({ - [type]: attributes, - references, - type, - ...overrides, - ...mockTimestampFields, - }), - ]; - describe('client calls', () => { - it(`should use the ES bulk action by default`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expect(client.bulk).toHaveBeenCalledTimes(1); - }); - - it(`should use the preflightCheckForCreate action before bulk action for any types that are multi-namespace, when id is defined`, async () => { - const objects = [obj1, { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }]; - await bulkCreateSuccess(client, repository, objects); - expect(client.bulk).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( - expect.objectContaining({ - objects: [ - { - type: MULTI_NAMESPACE_ISOLATED_TYPE, - id: obj2.id, - overwrite: false, - namespaces: ['default'], - }, - ], - }) - ); - }); - - it(`should use the ES create method if ID is undefined and overwrite=true`, async () => { - const objects = [obj1, obj2].map((obj) => ({ ...obj, id: undefined })); - await bulkCreateSuccess(client, repository, objects, { overwrite: true }); - expectClientCallArgsAction(objects, { method: 'create' }); - }); - - it(`should use the ES create method if ID is undefined and overwrite=false`, async () => { - const objects = [obj1, obj2].map((obj) => ({ ...obj, id: undefined })); - await bulkCreateSuccess(client, repository, objects); - expectClientCallArgsAction(objects, { method: 'create' }); - }); - - it(`should use the ES index method if ID is defined and overwrite=true`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { overwrite: true }); - expectClientCallArgsAction([obj1, obj2], { method: 'index' }); - }); - - it(`should use the ES index method with version if ID and version are defined and overwrite=true`, async () => { - await bulkCreateSuccess( - client, - repository, - [ - { - ...obj1, - version: mockVersion, - }, - obj2, - ], - { overwrite: true } - ); - - const obj1WithSeq = { - ...obj1, - managed: obj1.managed, - if_seq_no: mockVersionProps._seq_no, - if_primary_term: mockVersionProps._primary_term, - }; - - expectClientCallArgsAction([obj1WithSeq, obj2], { method: 'index' }); - }); - - it(`should use the ES create method if ID is defined and overwrite=false`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expectClientCallArgsAction([obj1, obj2], { method: 'create' }); - }); - - it(`should use the ES index method if ID is defined, overwrite=true and managed=true in a document`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { - overwrite: true, - managed: true, - }); - expectClientCallArgsAction([obj1, obj2], { method: 'index' }); - }); - - it(`should use the ES create method if ID is defined, overwrite=false and managed=true in a document`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { managed: true }); - expectClientCallArgsAction([obj1, obj2], { method: 'create' }); - }); - - it(`formats the ES request`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - const body = [...expectObjArgs(obj1), ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - // this test only ensures that the client accepts the managed field in a document - it(`formats the ES request with managed=true in a document`, async () => { - const obj1WithManagedTrue = { ...obj1, managed: true }; - const obj2WithManagedTrue = { ...obj2, managed: true }; - await bulkCreateSuccess(client, repository, [obj1WithManagedTrue, obj2WithManagedTrue]); - const body = [...expectObjArgs(obj1WithManagedTrue), ...expectObjArgs(obj2WithManagedTrue)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - describe('originId', () => { - it(`returns error if originId is set for non-multi-namespace type`, async () => { - const result = await repository.bulkCreate([ - { ...obj1, originId: 'some-originId' }, - { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE, originId: 'some-originId' }, - ]); - expect(result.saved_objects).toEqual([ - expect.objectContaining({ id: obj1.id, type: obj1.type, error: expect.anything() }), - expect.objectContaining({ - id: obj2.id, - type: NAMESPACE_AGNOSTIC_TYPE, - error: expect.anything(), - }), - ]); - expect(client.bulk).not.toHaveBeenCalled(); - }); - - it(`defaults to no originId`, async () => { - const objects = [ - { ...obj1, type: MULTI_NAMESPACE_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, - ]; - - await bulkCreateSuccess(client, repository, objects); - const expected = expect.not.objectContaining({ originId: expect.anything() }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - describe('with existing originId', () => { - beforeEach(() => { - mockPreflightCheckForCreate.mockImplementation(({ objects }) => { - const existingDocument = { - _source: { originId: 'existing-originId' }, - } as SavedObjectsRawDoc; - return Promise.resolve( - objects.map(({ type, id }) => ({ type, id, existingDocument })) - ); - }); - }); - - it(`accepts custom originId for multi-namespace type`, async () => { - // The preflight result has `existing-originId`, but that is discarded - const objects = [ - { ...obj1, type: MULTI_NAMESPACE_TYPE, originId: 'some-originId' }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE, originId: 'some-originId' }, - ]; - await bulkCreateSuccess(client, repository, objects); - const expected = expect.objectContaining({ originId: 'some-originId' }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - it(`accepts undefined originId`, async () => { - // The preflight result has `existing-originId`, but that is discarded - const objects = [ - { ...obj1, type: MULTI_NAMESPACE_TYPE, originId: undefined }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE, originId: undefined }, - ]; - await bulkCreateSuccess(client, repository, objects); - const expected = expect.not.objectContaining({ originId: expect.anything() }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - it(`preserves existing originId if originId option is not set`, async () => { - const objects = [ - { ...obj1, type: MULTI_NAMESPACE_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, - ]; - await bulkCreateSuccess(client, repository, objects); - const expected = expect.objectContaining({ originId: 'existing-originId' }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - }); - }); - - it(`adds namespace to request body for any types that are single-namespace`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); - const expected = expect.objectContaining({ namespace }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - // this only ensures we don't override any other options - it(`adds managed=false to request body if declared for any types that are single-namespace`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace, managed: false }); - const expected = expect.objectContaining({ namespace, managed: false }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - // this only ensures we don't override any other options - it(`adds managed=true to request body if declared for any types that are single-namespace`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace, managed: true }); - const expected = expect.objectContaining({ namespace, managed: true }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - it(`normalizes options.namespace from 'default' to undefined`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace: 'default' }); - const expected = expect.not.objectContaining({ namespace: 'default' }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - it(`doesn't add namespace to request body for any types that are not single-namespace`, async () => { - const objects = [ - { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, - ]; - await bulkCreateSuccess(client, repository, objects, { namespace }); - const expected = expect.not.objectContaining({ namespace: expect.anything() }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - }); - - it(`adds namespaces to request body for any types that are multi-namespace`, async () => { - const test = async (namespace?: string) => { - const objects = [obj1, obj2].map((x) => ({ ...x, type: MULTI_NAMESPACE_ISOLATED_TYPE })); - const [o1, o2] = objects; - mockPreflightCheckForCreate.mockResolvedValueOnce([ - { type: o1.type, id: o1.id! }, // first object does not have an existing document to overwrite - { - type: o2.type, - id: o2.id!, - existingDocument: { _id: o2.id!, _source: { namespaces: ['*'], type: o2.type } }, // second object does have an existing document to overwrite - }, - ]); - await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); - const expected1 = expect.objectContaining({ namespaces: [namespace ?? 'default'] }); - const expected2 = expect.objectContaining({ namespaces: ['*'] }); - const body = [expect.any(Object), expected1, expect.any(Object), expected2]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - client.bulk.mockClear(); - mockPreflightCheckForCreate.mockReset(); - }; - await test(undefined); - await test(namespace); - }); - - it(`adds initialNamespaces instead of namespace`, async () => { - const test = async (namespace?: string) => { - const ns2 = 'bar-namespace'; - const ns3 = 'baz-namespace'; - const objects = [ - { ...obj1, type: 'dashboard', initialNamespaces: [ns2] }, - { ...obj1, type: MULTI_NAMESPACE_ISOLATED_TYPE, initialNamespaces: [ns2] }, - { ...obj1, type: MULTI_NAMESPACE_TYPE, initialNamespaces: [ns2, ns3] }, - ]; - const [o1, o2, o3] = objects; - mockPreflightCheckForCreate.mockResolvedValueOnce([ - // first object does not get passed in to preflightCheckForCreate at all - { type: o2.type, id: o2.id! }, // second object does not have an existing document to overwrite - { - type: o3.type, - id: o3.id!, - existingDocument: { - _id: o3.id!, - _source: { type: o3.type, namespaces: [namespace ?? 'default', 'something-else'] }, // third object does have an existing document to overwrite - }, - }, - ]); - await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); - const body = [ - { index: expect.objectContaining({ _id: `${ns2}:dashboard:${o1.id}` }) }, - expect.objectContaining({ namespace: ns2 }), - { - index: expect.objectContaining({ - _id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${o2.id}`, - }), - }, - expect.objectContaining({ namespaces: [ns2] }), - { index: expect.objectContaining({ _id: `${MULTI_NAMESPACE_TYPE}:${o3.id}` }) }, - expect.objectContaining({ namespaces: [ns2, ns3] }), - ]; - expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( - expect.objectContaining({ - objects: [ - // assert that the initialNamespaces fields were passed into preflightCheckForCreate instead of the current namespace - { type: o2.type, id: o2.id, overwrite: true, namespaces: o2.initialNamespaces }, - { type: o3.type, id: o3.id, overwrite: true, namespaces: o3.initialNamespaces }, - ], - }) - ); - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - client.bulk.mockClear(); - mockPreflightCheckForCreate.mockReset(); - }; - await test(undefined); - await test(namespace); - }); - - it(`normalizes initialNamespaces from 'default' to undefined`, async () => { - const test = async (namespace?: string) => { - const objects = [{ ...obj1, type: 'dashboard', initialNamespaces: ['default'] }]; - await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); - const body = [ - { index: expect.objectContaining({ _id: `dashboard:${obj1.id}` }) }, - expect.not.objectContaining({ namespace: 'default' }), - ]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - client.bulk.mockClear(); - }; - await test(undefined); - await test(namespace); - }); - - it(`doesn't add namespaces to request body for any types that are not multi-namespace`, async () => { - const test = async (namespace?: string) => { - const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }]; - await bulkCreateSuccess(client, repository, objects, { namespace, overwrite: true }); - const expected = expect.not.objectContaining({ namespaces: expect.anything() }); - const body = [expect.any(Object), expected, expect.any(Object), expected]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - client.bulk.mockClear(); - }; - await test(undefined); - await test(namespace); - }); - - it(`defaults to a refresh setting of wait_for`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ refresh: 'wait_for' }), - expect.anything() - ); - }); - - it(`should use default index`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expectClientCallArgsAction([obj1, obj2], { - method: 'create', - _index: '.kibana-test_8.0.0-testing', - }); - }); - - it(`should use custom index`, async () => { - await bulkCreateSuccess( - client, - repository, - [obj1, obj2].map((x) => ({ ...x, type: CUSTOM_INDEX_TYPE })) - ); - expectClientCallArgsAction([obj1, obj2], { - method: 'create', - _index: 'custom_8.0.0-testing', - }); - }); - - it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { - const getId = (type: string, id: string = '') => `${namespace}:${type}:${id}`; // test that the raw document ID equals this (e.g., has a namespace prefix) - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); - expectClientCallArgsAction([obj1, obj2], { method: 'create', getId }); - }); - - it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { - const getId = (type: string, id: string = '') => `${type}:${id}`; // test that the raw document ID equals this (e.g., does not have a namespace prefix) - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expectClientCallArgsAction([obj1, obj2], { method: 'create', getId }); - }); - - it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => { - const getId = (type: string, id: string = '') => `${type}:${id}`; // test that the raw document ID equals this (e.g., does not have a namespace prefix) - const objects = [ - { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, - ]; - await bulkCreateSuccess(client, repository, objects, { namespace }); - expectClientCallArgsAction(objects, { method: 'create', getId }); - }); - }); - - describe('errors', () => { - afterEach(() => { - mockGetBulkOperationError.mockReset(); - }); - - const obj3 = { - type: 'dashboard', - id: 'three', - attributes: { title: 'Test Three' }, - references: [{ name: 'ref_0', type: 'test', id: '2' }], - }; - - const bulkCreateError = async ( - obj: SavedObjectsBulkCreateObject, - isBulkError: boolean | undefined, - expectedErrorResult: ExpectedErrorResult - ) => { - let response; - if (isBulkError) { - // mock the bulk error for only the second object - mockGetBulkOperationError.mockReturnValueOnce(undefined); - mockGetBulkOperationError.mockReturnValueOnce(expectedErrorResult.error as Payload); - response = getMockBulkCreateResponse([obj1, obj, obj2]); - } else { - response = getMockBulkCreateResponse([obj1, obj2]); - } - client.bulk.mockResponseOnce(response); - - const objects = [obj1, obj, obj2]; - const result = await repository.bulkCreate(objects); - expect(client.bulk).toHaveBeenCalled(); - const objCall = isBulkError ? expectObjArgs(obj) : []; - const body = [...expectObjArgs(obj1), ...objCall, ...expectObjArgs(obj2)]; - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body }), - expect.anything() - ); - expect(result).toEqual({ - saved_objects: [expectSuccess(obj1), expectedErrorResult, expectSuccess(obj2)], - }); - }; - - it(`throws when options.namespace is '*'`, async () => { - await expect( - repository.bulkCreate([obj3], { namespace: ALL_NAMESPACES_STRING }) - ).rejects.toThrowError(createBadRequestErrorPayload('"options.namespace" cannot be "*"')); - }); - - it(`returns error when initialNamespaces is used with a space-agnostic object`, async () => { - const obj = { ...obj3, type: NAMESPACE_AGNOSTIC_TYPE, initialNamespaces: [] }; - await bulkCreateError( - obj, - undefined, - expectErrorResult( - obj, - createBadRequestErrorPayload( - '"initialNamespaces" cannot be used on space-agnostic types' - ) - ) - ); - }); - - it(`returns error when initialNamespaces is empty`, async () => { - const obj = { ...obj3, type: MULTI_NAMESPACE_TYPE, initialNamespaces: [] }; - await bulkCreateError( - obj, - undefined, - expectErrorResult( - obj, - createBadRequestErrorPayload('"initialNamespaces" must be a non-empty array of strings') - ) - ); - }); - - it(`returns error when initialNamespaces is used with a space-isolated object and does not specify a single space`, async () => { - const doTest = async (objType: string, initialNamespaces: string[]) => { - const obj = { ...obj3, type: objType, initialNamespaces }; - await bulkCreateError( - obj, - undefined, - expectErrorResult( - obj, - createBadRequestErrorPayload( - '"initialNamespaces" can only specify a single space when used with space-isolated types' - ) - ) - ); - }; - await doTest('dashboard', ['spacex', 'spacey']); - await doTest('dashboard', ['*']); - await doTest(MULTI_NAMESPACE_ISOLATED_TYPE, ['spacex', 'spacey']); - await doTest(MULTI_NAMESPACE_ISOLATED_TYPE, ['*']); - }); - - it(`returns error when type is invalid`, async () => { - const obj = { ...obj3, type: 'unknownType' }; - await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); - }); - - it(`returns error when type is hidden`, async () => { - const obj = { ...obj3, type: HIDDEN_TYPE }; - await bulkCreateError(obj, undefined, expectErrorInvalidType(obj)); - }); - - it(`returns error when there is a conflict from preflightCheckForCreate`, async () => { - const objects = [ - // only the second, third, and fourth objects are passed to preflightCheckForCreate and result in errors - obj1, - { ...obj1, type: MULTI_NAMESPACE_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_TYPE }, - { ...obj3, type: MULTI_NAMESPACE_TYPE }, - obj2, - ]; - const [o1, o2, o3, o4, o5] = objects; - mockPreflightCheckForCreate.mockResolvedValueOnce([ - // first and last objects do not get passed in to preflightCheckForCreate at all - { type: o2.type, id: o2.id!, error: { type: 'conflict' } }, - { - type: o3.type, - id: o3.id!, - error: { type: 'unresolvableConflict', metadata: { isNotOverwritable: true } }, - }, - { - type: o4.type, - id: o4.id!, - error: { type: 'aliasConflict', metadata: { spacesWithConflictingAliases: ['foo'] } }, - }, - ]); - const bulkResponse = getMockBulkCreateResponse([o1, o5]); - client.bulk.mockResponseOnce(bulkResponse); - - const options = { overwrite: true }; - const result = await repository.bulkCreate(objects, options); - expect(mockPreflightCheckForCreate).toHaveBeenCalled(); - expect(mockPreflightCheckForCreate).toHaveBeenCalledWith( - expect.objectContaining({ - objects: [ - { type: o2.type, id: o2.id, overwrite: true, namespaces: ['default'] }, - { type: o3.type, id: o3.id, overwrite: true, namespaces: ['default'] }, - { type: o4.type, id: o4.id, overwrite: true, namespaces: ['default'] }, - ], - }) - ); - expect(client.bulk).toHaveBeenCalled(); - expect(client.bulk).toHaveBeenCalledWith( - expect.objectContaining({ body: [...expectObjArgs(o1), ...expectObjArgs(o5)] }), - expect.anything() - ); - expect(result).toEqual({ - saved_objects: [ - expectSuccess(o1), - expectErrorConflict(o2), - expectErrorConflict(o3, { metadata: { isNotOverwritable: true } }), - expectErrorConflict(o4, { metadata: { spacesWithConflictingAliases: ['foo'] } }), - expectSuccess(o5), - ], - }); - }); - - it(`returns bulk error`, async () => { - const expectedErrorResult = { - type: obj3.type, - id: obj3.id, - error: { error: 'Oh no, a bulk error!' }, - }; - await bulkCreateError(obj3, true, expectedErrorResult); - }); - - it(`returns errors for any bulk objects with invalid schemas`, async () => { - const response = getMockBulkCreateResponse([obj3]); - client.bulk.mockResponseOnce(response); - - const result = await repository.bulkCreate([ - obj3, - // @ts-expect-error - Title should be a string and is intentionally malformed for testing - { ...obj3, id: 'three-again', attributes: { title: 123 } }, - ]); - expect(client.bulk).toHaveBeenCalledTimes(1); // only called once for the valid object - expect(result.saved_objects).toEqual([ - expect.objectContaining(obj3), - expect.objectContaining({ - error: new Error( - '[attributes.title]: expected value of type [string] but got [number]: Bad Request' - ), - id: 'three-again', - type: 'dashboard', - }), - ]); - }); - }); - - describe('migration', () => { - it(`migrates the docs and serializes the migrated docs`, async () => { - migrator.migrateDocument.mockImplementation(mockMigrateDocument); - const modifiedObj1 = { ...obj1, coreMigrationVersion: '8.0.0' }; - await bulkCreateSuccess(client, repository, [modifiedObj1, obj2]); - const docs = [modifiedObj1, obj2].map((x) => ({ ...x, ...mockTimestampFieldsWithCreated })); - expectMigrationArgs(docs[0], true, 1); - expectMigrationArgs(docs[1], true, 2); - - const migratedDocs = docs.map((x) => migrator.migrateDocument(x)); - expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(1, migratedDocs[0]); - expect(serializer.savedObjectToRaw).toHaveBeenNthCalledWith(2, migratedDocs[1]); - }); - - it(`adds namespace to body when providing namespace for single-namespace type`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2], { namespace }); - expectMigrationArgs({ namespace }, true, 1); - expectMigrationArgs({ namespace }, true, 2); - }); - - it(`doesn't add namespace to body when providing no namespace for single-namespace type`, async () => { - await bulkCreateSuccess(client, repository, [obj1, obj2]); - expectMigrationArgs({ namespace: expect.anything() }, false, 1); - expectMigrationArgs({ namespace: expect.anything() }, false, 2); - }); - - it(`doesn't add namespace to body when not using single-namespace type`, async () => { - const objects = [ - { ...obj1, type: NAMESPACE_AGNOSTIC_TYPE }, - { ...obj2, type: MULTI_NAMESPACE_ISOLATED_TYPE }, - ]; - await bulkCreateSuccess(client, repository, objects, { namespace }); - expectMigrationArgs({ namespace: expect.anything() }, false, 1); - expectMigrationArgs({ namespace: expect.anything() }, false, 2); - }); - - it(`adds namespaces to body when providing namespace for multi-namespace type`, async () => { - const objects = [obj1, obj2].map((obj) => ({ - ...obj, - type: MULTI_NAMESPACE_ISOLATED_TYPE, - })); - await bulkCreateSuccess(client, repository, objects, { namespace }); - expectMigrationArgs({ namespaces: [namespace] }, true, 1); - expectMigrationArgs({ namespaces: [namespace] }, true, 2); - }); - - it(`adds default namespaces to body when providing no namespace for multi-namespace type`, async () => { - const objects = [obj1, obj2].map((obj) => ({ - ...obj, - type: MULTI_NAMESPACE_ISOLATED_TYPE, - })); - await bulkCreateSuccess(client, repository, objects); - expectMigrationArgs({ namespaces: ['default'] }, true, 1); - expectMigrationArgs({ namespaces: ['default'] }, true, 2); - }); - - it(`doesn't add namespaces to body when not using multi-namespace type`, async () => { - const objects = [obj1, { ...obj2, type: NAMESPACE_AGNOSTIC_TYPE }]; - await bulkCreateSuccess(client, repository, objects); - expectMigrationArgs({ namespaces: expect.anything() }, false, 1); - expectMigrationArgs({ namespaces: expect.anything() }, false, 2); - }); - }); - - describe('returns', () => { - it(`formats the ES response`, async () => { - const result = await bulkCreateSuccess(client, repository, [obj1, obj2]); - expect(result).toEqual({ - saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), - }); - }); - - it.todo(`should return objects in the same order regardless of type`); - - it(`handles a mix of successful creates and errors`, async () => { - const obj = { - type: 'unknownType', - id: 'three', - attributes: {}, - }; - const objects = [obj1, obj, obj2]; - const response = getMockBulkCreateResponse([obj1, obj2]); - client.bulk.mockResponseOnce(response); - const result = await repository.bulkCreate(objects); - expect(client.bulk).toHaveBeenCalledTimes(1); - expect(result).toEqual({ - saved_objects: [expectCreateResult(obj1), expectError(obj), expectCreateResult(obj2)], - }); - }); - - it(`a deserialized saved object`, async () => { - // Test for fix to https://github.com/elastic/kibana/issues/65088 where - // we returned raw ID's when an object without an id was created. - const namespace = 'myspace'; - // FIXME: this test is based on a gigantic hack to have the bulk operation return the source - // of the document when it actually does not, forcing to cast to any as BulkResponse - // does not contains _source - const response = getMockBulkCreateResponse([obj1, obj2], namespace) as any; - client.bulk.mockResponseOnce(response); - - // Bulk create one object with id unspecified, and one with id specified - const result = await repository.bulkCreate([{ ...obj1, id: undefined }, obj2], { - namespace, - }); - - // Assert that both raw docs from the ES response are deserialized - expect(serializer.rawToSavedObject).toHaveBeenNthCalledWith( - 1, - { - ...response.items[0].create, - _source: { - ...response.items[0].create._source, - namespaces: response.items[0].create._source.namespaces, - coreMigrationVersion: expect.any(String), - typeMigrationVersion: '1.1.1', - }, - _id: expect.stringMatching( - /^myspace:config:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/ - ), - }, - expect.any(Object) - ); - expect(serializer.rawToSavedObject).toHaveBeenNthCalledWith( - 2, - { - ...response.items[1].create, - _source: { - ...response.items[1].create._source, - namespaces: response.items[1].create._source.namespaces, - coreMigrationVersion: expect.any(String), - typeMigrationVersion: '1.1.1', - }, - }, - expect.any(Object) - ); - - // Assert that ID's are deserialized to remove the type and namespace - expect(result.saved_objects[0].id).toEqual( - expect.stringMatching(/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/) - ); - expect(result.saved_objects[1].id).toEqual(obj2.id); - - // Assert that managed is not changed - expect(result.saved_objects[0].managed).toBeFalsy(); - expect(result.saved_objects[1].managed).toEqual(obj2.managed); - }); - - it(`sets managed=false if not already set`, async () => { - const obj1WithoutManaged = { - type: 'config', - id: '6.0.0-alpha1', - attributes: { title: 'Test One' }, - references: [{ name: 'ref_0', type: 'test', id: '1' }], - }; - const obj2WithoutManaged = { - type: 'index-pattern', - id: 'logstash-*', - attributes: { title: 'Test Two' }, - references: [{ name: 'ref_0', type: 'test', id: '2' }], - }; - const result = await bulkCreateSuccess(client, repository, [ - obj1WithoutManaged, - obj2WithoutManaged, - ]); - expect(result).toEqual({ - saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), - }); - }); - - it(`sets managed=false only on documents without managed already set`, async () => { - const objWithoutManaged = { - type: 'config', - id: '6.0.0-alpha1', - attributes: { title: 'Test One' }, - references: [{ name: 'ref_0', type: 'test', id: '1' }], - }; - const result = await bulkCreateSuccess(client, repository, [objWithoutManaged, obj2]); - expect(result).toEqual({ - saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), - }); - }); - - it(`sets managed=true if provided as an override`, async () => { - const obj1WithoutManaged = { - type: 'config', - id: '6.0.0-alpha1', - attributes: { title: 'Test One' }, - references: [{ name: 'ref_0', type: 'test', id: '1' }], - }; - const obj2WithoutManaged = { - type: 'index-pattern', - id: 'logstash-*', - attributes: { title: 'Test Two' }, - references: [{ name: 'ref_0', type: 'test', id: '2' }], - }; - const result = await bulkCreateSuccess( - client, - repository, - [obj1WithoutManaged, obj2WithoutManaged], - { managed: true } - ); - expect(result).toEqual({ - saved_objects: [ - { ...obj1WithoutManaged, managed: true }, - { ...obj2WithoutManaged, managed: true }, - ].map((x) => expectCreateResult(x)), - }); - }); - - it(`sets managed=false if provided as an override`, async () => { - const obj1WithoutManaged = { - type: 'config', - id: '6.0.0-alpha1', - attributes: { title: 'Test One' }, - references: [{ name: 'ref_0', type: 'test', id: '1' }], - }; - const obj2WithoutManaged = { - type: 'index-pattern', - id: 'logstash-*', - attributes: { title: 'Test Two' }, - references: [{ name: 'ref_0', type: 'test', id: '2' }], - }; - const result = await bulkCreateSuccess( - client, - repository, - [obj1WithoutManaged, obj2WithoutManaged], - { managed: false } - ); - expect(result).toEqual({ - saved_objects: [obj1, obj2].map((x) => expectCreateResult(x)), - }); - }); - }); - }); - describe('#bulkGet', () => { const obj1: SavedObject = { type: 'config', diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts index 29c00e9d41ac..d3a31a905de5 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts @@ -469,7 +469,9 @@ export const getMockGetResponse = ( export const getMockMgetResponse = ( registry: SavedObjectTypeRegistry, - objects: Array, + objects: Array< + TypeIdTuple & { found?: boolean; initialNamespaces?: string[]; originId?: string } + >, namespace?: string ) => ({ @@ -649,10 +651,10 @@ export const getMockBulkUpdateResponse = ( objects: TypeIdTuple[], options?: SavedObjectsBulkUpdateOptions, originId?: string -) => - ({ +) => { + return { items: objects.map(({ type, id }) => ({ - update: { + index: { _id: `${ registry.isSingleNamespace(type) && options?.namespace ? `${options?.namespace}:` : '' }${type}:${id}`, @@ -667,7 +669,8 @@ export const getMockBulkUpdateResponse = ( result: 'updated', }, })), - } as estypes.BulkResponse); + } as estypes.BulkResponse; +}; export const bulkUpdateSuccess = async ( client: ElasticsearchClientMock, @@ -678,19 +681,26 @@ export const bulkUpdateSuccess = async ( originId?: string, multiNamespaceSpace?: string // the space for multi namespace objects returned by mock mget (this is only needed for space ext testing) ) => { - const multiNamespaceObjects = objects.filter(({ type }) => registry.isMultiNamespace(type)); - if (multiNamespaceObjects?.length) { - const response = getMockMgetResponse( - registry, - multiNamespaceObjects, - multiNamespaceSpace ?? options?.namespace - ); - client.mget.mockResponseOnce(response); + let mockedMgetResponse; + const validObjects = objects.filter(({ type }) => registry.getType(type) !== undefined); + const multiNamespaceObjects = validObjects.filter(({ type }) => registry.isMultiNamespace(type)); + + if (validObjects?.length) { + if (multiNamespaceObjects.length > 0) { + mockedMgetResponse = getMockMgetResponse( + registry, + validObjects, + multiNamespaceSpace ?? options?.namespace + ); + } else { + mockedMgetResponse = getMockMgetResponse(registry, validObjects); + } + client.mget.mockResponseOnce(mockedMgetResponse); } const response = getMockBulkUpdateResponse(registry, objects, options, originId); client.bulk.mockResponseOnce(response); const result = await repository.bulkUpdate(objects, options); - expect(client.mget).toHaveBeenCalledTimes(multiNamespaceObjects?.length ? 1 : 0); + expect(client.mget).toHaveBeenCalledTimes(validObjects?.length ? 1 : 0); return result; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts index 6d10aee397b2..49bc8d769a1d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/bulk_update.ts @@ -39,6 +39,8 @@ export interface SavedObjectsBulkUpdateObject export interface SavedObjectsBulkUpdateOptions extends SavedObjectsBaseOptions { /** The Elasticsearch Refresh setting for this operation */ refresh?: MutatingOperationRefreshSetting; + /** {@link SavedObjectsRawDocParseOptions.migrationVersionCompatibility} */ + migrationVersionCompatibility?: 'compatible' | 'raw'; } /** diff --git a/packages/core/saved-objects/core-saved-objects-api-server/src/saved_objects_client.ts b/packages/core/saved-objects/core-saved-objects-api-server/src/saved_objects_client.ts index 532c2dc58d99..1d2d7225f5d8 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server/src/saved_objects_client.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server/src/saved_objects_client.ts @@ -276,6 +276,13 @@ export interface SavedObjectsClientContract { /** * Bulk Updates multiple SavedObject at once * + * The savedObjects `bulkUpdate` API will update documents client-side and then reindex the updated documents. + * These update operations are done in-memory, and cause memory constraint issues when + * updating many objects with large `json` blobs stored in some fields. As such, we recommend against using + * `bulkUpdate` for savedObjects that: + * - use arrays (as these tend to be large objects) + * - store large `json` blobs in some fields + * * @param objects - array of objects to update (contains ID, type, attributes, and optional namespace) * @param options {@link SavedObjectsBulkUpdateOptions} - options for the bulkUpdate operation * @returns the {@link SavedObjectsBulkUpdateResponse} diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts index eea0966433f0..2a3535f19207 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts @@ -42,7 +42,14 @@ export type { MigrationStatus, MigrateDocumentOptions, } from './src/migration'; -export { parseObjectKey, getObjectKey, getIndexForType } from './src/utils'; +export { + parseObjectKey, + getObjectKey, + getIndexForType, + getFieldListFromTypeMapping, + getFieldListMapFromMappingDefinitions, + type FieldListMap, +} from './src/utils'; export { modelVersionVirtualMajor, globalSwitchToModelVersionAt, @@ -68,4 +75,6 @@ export { buildModelVersionTransformFn, aggregateMappingAdditions, convertModelVersionBackwardConversionSchema, + getVersionAddedMappings, + getVersionAddedFields, } from './src/model_version'; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/index.ts index 350ab86ca298..3c189977731e 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/index.ts @@ -37,3 +37,4 @@ export { getModelVersionDelta } from './get_version_delta'; export { buildModelVersionTransformFn } from './build_transform_fn'; export { aggregateMappingAdditions } from './aggregate_model_changes'; export { convertModelVersionBackwardConversionSchema } from './backward_conversion_schema'; +export { getVersionAddedFields, getVersionAddedMappings } from './version_mapping_changes'; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.test.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.test.ts new file mode 100644 index 000000000000..00946f4dc1eb --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { + SavedObjectsModelVersion, + SavedObjectsModelChange, +} from '@kbn/core-saved-objects-server'; +import { getVersionAddedMappings, getVersionAddedFields } from './version_mapping_changes'; + +const createVersion = (changes: SavedObjectsModelChange[]): SavedObjectsModelVersion => { + return { + changes, + }; +}; + +describe('getVersionAddedMappings', () => { + it('returns empty mappings when the version has no changes', () => { + const version = createVersion([]); + expect(getVersionAddedMappings(version)).toEqual({}); + }); + + it('returns empty mappings when the version has no `mappings_addition` changes', () => { + const version = createVersion([ + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + ]); + expect(getVersionAddedMappings(version)).toEqual({}); + }); + + it(`returns the change's mappings when the version has a single 'mappings_addition' changes`, () => { + const version = createVersion([ + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + { + type: 'mappings_addition', + addedMappings: { + nested: { + properties: { + foo: { type: 'text' }, + }, + }, + }, + }, + ]); + expect(getVersionAddedMappings(version)).toEqual({ + nested: { + properties: { + foo: { type: 'text' }, + }, + }, + }); + }); + + it(`merges the mappings when the version has multiple 'mappings_addition' changes`, () => { + const version = createVersion([ + { + type: 'mappings_addition', + addedMappings: { + top: { type: 'text' }, + nested: { + properties: { + bar: { type: 'text' }, + }, + }, + }, + }, + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + { + type: 'mappings_addition', + addedMappings: { + nested: { + properties: { + foo: { type: 'text' }, + }, + }, + }, + }, + ]); + expect(getVersionAddedMappings(version)).toEqual({ + top: { type: 'text' }, + nested: { + properties: { + foo: { type: 'text' }, + bar: { type: 'text' }, + }, + }, + }); + }); +}); + +describe('getVersionAddedFields', () => { + it('returns empty mappings when the version has no changes', () => { + const version = createVersion([]); + expect(getVersionAddedFields(version)).toEqual([]); + }); + + it('returns empty mappings when the version has no `mappings_addition` changes', () => { + const version = createVersion([ + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + ]); + expect(getVersionAddedFields(version)).toEqual([]); + }); + + it(`returns the change's mappings when the version has a single 'mappings_addition' changes`, () => { + const version = createVersion([ + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + { + type: 'mappings_addition', + addedMappings: { + nested: { + properties: { + foo: { type: 'text' }, + }, + }, + }, + }, + ]); + expect(getVersionAddedFields(version)).toEqual(['nested', 'nested.foo']); + }); + + it(`merges the mappings when the version has multiple 'mappings_addition' changes`, () => { + const version = createVersion([ + { + type: 'mappings_addition', + addedMappings: { + top: { type: 'text' }, + nested: { + properties: { + bar: { type: 'text' }, + }, + }, + }, + }, + { + type: 'data_backfill', + backfillFn: jest.fn(), + }, + { + type: 'mappings_addition', + addedMappings: { + nested: { + properties: { + foo: { type: 'text' }, + }, + }, + }, + }, + ]); + expect(getVersionAddedFields(version)).toEqual(['nested', 'nested.bar', 'nested.foo', 'top']); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts new file mode 100644 index 000000000000..adbbf74ae79c --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/model_version/version_mapping_changes.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { merge } from 'lodash'; +import type { + SavedObjectsMappingProperties, + SavedObjectsModelVersion, + SavedObjectsModelMappingsAdditionChange, +} from '@kbn/core-saved-objects-server'; +import { getFieldListFromTypeMapping } from '../utils/get_field_list'; + +/** + * Return the mappings that were introduced in the given version. + * If multiple 'mappings_addition' changes are present for the version, + * they will be deep-merged. + */ +export const getVersionAddedMappings = ( + version: SavedObjectsModelVersion +): SavedObjectsMappingProperties => { + const mappingChanges = version.changes.filter( + (change) => change.type === 'mappings_addition' + ) as SavedObjectsModelMappingsAdditionChange[]; + return merge({}, ...mappingChanges.map((change) => change.addedMappings)); +}; + +/** + * Return the list of fields, sorted, that were introduced in the given version. + */ +export const getVersionAddedFields = (version: SavedObjectsModelVersion): string[] => { + const addedMappings = getVersionAddedMappings(version); + return getFieldListFromTypeMapping({ properties: addedMappings }); +}; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.test.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.test.ts new file mode 100644 index 000000000000..ef1a8e1e0164 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SavedObjectsTypeMappingDefinition } from '@kbn/core-saved-objects-server'; +import { getFieldListFromTypeMapping } from './get_field_list'; + +describe('getFieldListFromTypeMapping', () => { + it('returns an empty list for empty mappings', () => { + const mappings: SavedObjectsTypeMappingDefinition = { + properties: {}, + }; + expect(getFieldListFromTypeMapping(mappings)).toEqual([]); + }); + + it('returns the correct list for top level fields', () => { + const mappings: SavedObjectsTypeMappingDefinition = { + properties: { + foo: { type: 'text' }, + bar: { type: 'text' }, + }, + }; + expect(getFieldListFromTypeMapping(mappings)).toEqual(['bar', 'foo']); + }); + + it('returns the correct list for deep fields', () => { + const mappings: SavedObjectsTypeMappingDefinition = { + properties: { + foo: { + properties: { + hello: { type: 'text' }, + dolly: { type: 'text' }, + }, + }, + bar: { type: 'text' }, + }, + }; + expect(getFieldListFromTypeMapping(mappings)).toEqual(['bar', 'foo', 'foo.dolly', 'foo.hello']); + }); + + it('returns the correct list for any depth', () => { + const mappings: SavedObjectsTypeMappingDefinition = { + properties: { + foo: { + properties: { + hello: { type: 'text' }, + dolly: { + properties: { + far: { type: 'text' }, + }, + }, + }, + }, + bar: { type: 'text' }, + }, + }; + expect(getFieldListFromTypeMapping(mappings)).toEqual([ + 'bar', + 'foo', + 'foo.dolly', + 'foo.dolly.far', + 'foo.hello', + ]); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts new file mode 100644 index 000000000000..8a33d42d7cb0 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/get_field_list.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { MappingProperty as EsMappingProperty } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { + SavedObjectsTypeMappingDefinition, + SavedObjectsFieldMapping, +} from '@kbn/core-saved-objects-server'; +import type { SavedObjectsTypeMappingDefinitions } from '../mappings'; + +export type FieldListMap = Record; + +/** + * Return the list of fields present in each individual type mappings present in the definition. + */ +export const getFieldListMapFromMappingDefinitions = ( + mappings: SavedObjectsTypeMappingDefinitions +): FieldListMap => { + return Object.entries(mappings).reduce((memo, [typeName, typeMappings]) => { + memo[typeName] = getFieldListFromTypeMapping(typeMappings); + return memo; + }, {}); +}; + +type AnyFieldMapping = SavedObjectsFieldMapping | EsMappingProperty; + +interface QueueItem { + fieldPath: string[]; + fieldDef: AnyFieldMapping; +} + +/** + * Return the list of fields present in the provided mappings. + * Note that fields only containing properties are still considered fields by this function. + * + * @example + * ``` + * getFieldListFromTypeMapping({ + * properties: { + * foo: { + * properties: { + * hello: { type: 'text' }, + * dolly: { type: 'text' }, + * }, + * }, + * }, + * }); + * // ['foo', 'foo.dolly', 'foo.hello'] + * ``` + */ +export const getFieldListFromTypeMapping = ( + typeMappings: SavedObjectsTypeMappingDefinition +): string[] => { + const fieldList: string[] = []; + const queue: QueueItem[] = []; + + Object.entries(typeMappings.properties).forEach(([fieldName, fieldDef]) => { + queue.push({ + fieldPath: [fieldName], + fieldDef, + }); + }); + + while (queue.length > 0) { + const item = queue.pop()!; + fieldList.push(item.fieldPath.join('.')); + if ('properties' in item.fieldDef) { + Object.entries(item.fieldDef.properties ?? {}).forEach(([fieldName, fieldDef]) => { + queue.push({ + fieldPath: [...item.fieldPath, fieldName], + fieldDef, + }); + }); + } + } + + return fieldList.sort(); +}; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/index.ts index 8db62a4c5228..374b39abe9ed 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/utils/index.ts @@ -8,3 +8,8 @@ export { getObjectKey, parseObjectKey } from './object_key'; export { getIndexForType } from './get_index_for_type'; +export { + getFieldListFromTypeMapping, + getFieldListMapFromMappingDefinitions, + type FieldListMap, +} from './get_field_list'; diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts index 0493652b1192..a5e112ca2aa7 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts @@ -7,7 +7,8 @@ */ import { pick, throttle, cloneDeep } from 'lodash'; -import type { HttpSetup, HttpFetchOptions } from '@kbn/core-http-browser'; +import type { HttpFetchOptions } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { SavedObject, SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common'; import type { SavedObjectsBulkResolveResponse as SavedObjectsBulkResolveResponseServer, @@ -106,7 +107,7 @@ const getObjectsToResolve = (queue: BatchResolveQueueEntry[]) => { * @deprecated See https://github.com/elastic/kibana/issues/149098 */ export class SavedObjectsClient implements SavedObjectsClientContract { - private http: HttpSetup; + private http: InternalHttpSetup; private batchGetQueue: BatchGetQueueEntry[]; private batchResolveQueue: BatchResolveQueueEntry[]; @@ -180,7 +181,7 @@ export class SavedObjectsClient implements SavedObjectsClientContract { ); /** @internal */ - constructor(http: HttpSetup) { + constructor(http: InternalHttpSetup) { this.http = http; this.batchGetQueue = []; this.batchResolveQueue = []; diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_service.ts b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_service.ts index 7cef8a1c3905..f806dc6b69ef 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_service.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_service.ts @@ -7,7 +7,7 @@ */ import type { CoreService } from '@kbn/core-base-browser-internal'; -import type { HttpStart } from '@kbn/core-http-browser'; +import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import type { SavedObjectsStart } from '@kbn/core-saved-objects-browser'; import { SavedObjectsClient } from './saved_objects_client'; @@ -17,7 +17,7 @@ import { SavedObjectsClient } from './saved_objects_client'; export class SavedObjectsService implements CoreService { public async setup() {} - public async start({ http }: { http: HttpStart }): Promise { + public async start({ http }: { http: InternalHttpStart }): Promise { return { client: new SavedObjectsClient(http) }; } diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/tsconfig.json b/packages/core/saved-objects/core-saved-objects-browser-internal/tsconfig.json index a29dbf58b411..d9b414c39220 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/tsconfig.json +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/tsconfig.json @@ -19,6 +19,7 @@ "@kbn/core-saved-objects-api-server", "@kbn/core-saved-objects-api-browser", "@kbn/core-http-browser-mocks", + "@kbn/core-http-browser-internal", ], "exclude": [ "target/**/*", diff --git a/packages/core/saved-objects/core-saved-objects-server/docs/model_versions.md b/packages/core/saved-objects/core-saved-objects-server/docs/model_versions.md index 0177c85f484c..31229e5eebc9 100644 --- a/packages/core/saved-objects/core-saved-objects-server/docs/model_versions.md +++ b/packages/core/saved-objects/core-saved-objects-server/docs/model_versions.md @@ -1040,76 +1040,13 @@ to the `fields` option **were already present in the prior model version**. Othe during upgrades, where newly introduced or backfilled fields may not necessarily appear in the documents returned from the `search` API when the option is used. -### Using `bulkUpdate` with dynamically backfilled fields + (*note*: both the previous and next version of Kibana must follow this rule then) -(Note: this same limitation used to exist for the `update` method but has been [fixed](https://github.com/elastic/kibana/issues/165434). So while they're similar this limitation is only relevant for the `bulkUpdate` method) +### Using `bulkUpdate` for fields with large `json` blobs -The savedObjects `bulkUpdate` API is effectively a partial update (using Elasticsearch's `_update` under the hood), -allowing API consumers to only specify the subset of fields they want to update to new values, without having to -provide the full list of attributes (the unchanged ones). We're also not changing the `version` of the document -during updates, even when the instance performing the operation doesn't know about the current model version -of the document (e.g an old node during an upgrade). - -If this was fine before zero downtime upgrades, there is an edge case in serverless when this API is used -to update fields that are the "source" of another field's backfill that can potentially lead to data becoming inconsistent. - -For example, imagine that: - -1. In model version 1, we have some `index (number)` field. - -2. In model version 2, we introduce a `odd (boolean)` field that is backfilled with the following function: - -```ts -let change: SavedObjectsModelDataBackfillChange = { - type: 'data_backfill', - backfillFn: (doc, ctx) => { - return { attributes: { odd: doc.attributes.index % 2 === 1 } }; - }, -}; -``` - -3. During the cohabitation period (upgrade), an instance of the new version of Kibana creates a document - -E.g with the following attributes: - -```ts -const newDocAttributes = { - index: 12, - odd: false, -} -``` - -4. Then an instance of the old version of Kibana updates the `index` field of this document - -Which could occur either while being still in the cohabitation period, or in case of rollback: - -```ts -savedObjectClient.bulkUpdate({ - objects: [{ - type: 'type', - id: 'id', - attributes: { - index: 11 - } - }] -}); -``` - -We will then be in a situation where our data is **inconsistent**, as the value of the `odd` field wasn't recomputed: - -```json -{ - index: 11, - odd: false, -} -``` - -The long term solution for that is implementing [backward-compatible updates](https://github.com/elastic/kibana/issues/165434), however -this won't be done for the MVP, so the workaround for now is to avoid situations where this edge case can occur. - -It can be avoided by either: - -1. Not having backfill functions depending on the value of the existing fields (*recommended*) - -2. Not performing update operations impacting fields that are used as "source" for backfill functions - (*note*: both the previous and next version of Kibana must follow this rule then) \ No newline at end of file +The savedObjects `bulkUpdate` API will update documents client-side and then reindex the updated documents. +These update operations are done in-memory, and cause memory constraint issues when +updating many objects with large `json` blobs stored in some fields. As such, we recommend against using +`bulkUpdate` for savedObjects that: +- use arrays (as these tend to be large objects) +- store large `json` blobs in some fields diff --git a/packages/core/saved-objects/docs/openapi/bundled.json b/packages/core/saved-objects/docs/openapi/bundled.json index dd6b95fa959b..4382ee9b62d9 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.json +++ b/packages/core/saved-objects/docs/openapi/bundled.json @@ -757,7 +757,7 @@ "post": { "summary": "Resolve errors from the Import objects API.", "operationId": "resolveImportErrors", - "description": "To resolve errors, you can: \n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "To resolve errors, you can:\n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", "tags": [ "saved objects" ], @@ -1210,7 +1210,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "examples": { diff --git a/packages/core/saved-objects/docs/openapi/bundled.yaml b/packages/core/saved-objects/docs/openapi/bundled.yaml index 3e07633a5107..a12e326ccdbe 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled.yaml @@ -208,7 +208,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -239,7 +239,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -798,7 +798,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' examples: key_rotation_response: summary: Encryption key rotation using default parameters. diff --git a/packages/core/saved-objects/docs/openapi/entrypoint.yaml b/packages/core/saved-objects/docs/openapi/entrypoint.yaml index cfb8a93210a5..b4e58a6ef217 100644 --- a/packages/core/saved-objects/docs/openapi/entrypoint.yaml +++ b/packages/core/saved-objects/docs/openapi/entrypoint.yaml @@ -49,7 +49,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - - apiKeyAuth: [] \ No newline at end of file + - apiKeyAuth: [] diff --git a/packages/core/status/core-status-server-internal/src/plugins_status.test.ts b/packages/core/status/core-status-server-internal/src/plugins_status.test.ts index d1d35ade5615..ed14eee45229 100644 --- a/packages/core/status/core-status-server-internal/src/plugins_status.test.ts +++ b/packages/core/status/core-status-server-internal/src/plugins_status.test.ts @@ -41,7 +41,7 @@ describe('PluginStatusService', () => { pluginDependencies, }); - service.blockNewRegistrations(); + service.start(); expect(() => { service.set( 'a', @@ -365,6 +365,8 @@ describe('PluginStatusService', () => { const pluginA$ = new ReplaySubject(1); service.set('a', pluginA$); + service.start(); // the plugin emission timeout starts counting when we call pluginsStatus.start() + // the first emission happens right after core$ services emit const firstEmission = firstValueFrom(service.getAll$().pipe(skip(1))); diff --git a/packages/core/status/core-status-server-internal/src/plugins_status.ts b/packages/core/status/core-status-server-internal/src/plugins_status.ts index 8d20eff18927..7de22e23cc97 100644 --- a/packages/core/status/core-status-server-internal/src/plugins_status.ts +++ b/packages/core/status/core-status-server-internal/src/plugins_status.ts @@ -6,15 +6,22 @@ * Side Public License, v 1. */ -import { BehaviorSubject, type Observable, ReplaySubject, type Subscription } from 'rxjs'; +import { + BehaviorSubject, + merge, + Observable, + ReplaySubject, + Subject, + type Subscription, +} from 'rxjs'; import { map, distinctUntilChanged, filter, - timeout, - startWith, tap, debounceTime, + takeUntil, + delay, } from 'rxjs/operators'; import { sortBy } from 'lodash'; import { isDeepStrictEqual } from 'util'; @@ -62,6 +69,7 @@ export class PluginsStatusService { private pluginData: PluginData; private rootPlugins: PluginName[]; // root plugins are those that do not have any dependencies private orderedPluginNames: PluginName[]; + private start$ = new Subject(); private pluginData$ = new ReplaySubject(1); private pluginStatus: PluginsStatus = {}; private pluginStatus$ = new BehaviorSubject(this.pluginStatus); @@ -110,26 +118,21 @@ export class PluginsStatusService { // delete any derived statuses calculated before the custom status Observable was registered delete this.pluginStatus[plugin]; - const statusChanged$ = status$.pipe(distinctUntilChanged()); + const firstEmissionTimeout$ = this.start$.pipe( + delay(this.statusTimeoutMs), + map(() => ({ + level: ServiceStatusLevels.unavailable, + summary: `Status check timed out after ${ + this.statusTimeoutMs < 1000 + ? `${this.statusTimeoutMs}ms` + : `${this.statusTimeoutMs / 1000}s` + }`, + })), + takeUntil(status$) + ); - this.reportedStatusSubscriptions[plugin] = statusChanged$ - .pipe( - // Set a timeout for externally-defined status Observables - timeout({ - first: this.statusTimeoutMs, - with: () => - statusChanged$.pipe( - startWith({ - level: ServiceStatusLevels.unavailable, - summary: `Status check timed out after ${ - this.statusTimeoutMs < 1000 - ? `${this.statusTimeoutMs}ms` - : `${this.statusTimeoutMs / 1000}s` - }`, - }) - ), - }) - ) + this.reportedStatusSubscriptions[plugin] = merge(firstEmissionTimeout$, status$) + .pipe(distinctUntilChanged()) .subscribe((status) => { const { levelChanged, summaryChanged } = this.updatePluginReportedStatus(plugin, status); @@ -143,11 +146,11 @@ export class PluginsStatusService { }); } - /** - * Prevent plugins from registering status Observables - */ - public blockNewRegistrations() { + public start() { + // Prevent plugins from registering status Observables this.newRegistrationsAllowed = false; + this.start$.next(); + this.start$.complete(); } /** diff --git a/packages/core/status/core-status-server-internal/src/status_service.ts b/packages/core/status/core-status-server-internal/src/status_service.ts index 0d1a53615da5..f33621e101a7 100644 --- a/packages/core/status/core-status-server-internal/src/status_service.ts +++ b/packages/core/status/core-status-server-internal/src/status_service.ts @@ -179,7 +179,7 @@ export class StatusService implements CoreService { if (!this.pluginsStatus || !this.overall$) { throw new Error(`StatusService#setup must be called before #start`); } - this.pluginsStatus.blockNewRegistrations(); + this.pluginsStatus.start(); this.logStatusChanges(); } diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/__snapshots__/ui_settings_api.test.ts.snap b/packages/core/ui-settings/core-ui-settings-browser-internal/src/__snapshots__/ui_settings_api.test.ts.snap index b80765e3536c..eb5eb00c04ee 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/__snapshots__/ui_settings_api.test.ts.snap +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/__snapshots__/ui_settings_api.test.ts.snap @@ -253,3 +253,26 @@ Array [ ], ] `; + +exports[`#validate rejects on 301 1`] = `"Moved Permanently"`; + +exports[`#validate rejects on 404 response 1`] = `"Request failed with status code: 404"`; + +exports[`#validate rejects on 500 1`] = `"Request failed with status code: 500"`; + +exports[`#validate sends a validation request: validation request 1`] = ` +Array [ + Array [ + "/foo/bar/internal/kibana/settings/foo/validate", + Object { + "headers": Object { + "accept": "application/json", + "content-type": "application/json", + "kbn-version": "kibanaVersion", + "x-elastic-internal-origin": "Kibana", + }, + "method": "POST", + }, + ], +] +`; diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/settings_service.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/settings_service.ts index edda603644fa..202f8ceb1206 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/settings_service.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/settings_service.ts @@ -9,14 +9,14 @@ import { Subject } from 'rxjs'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { SettingsStart, SettingsSetup } from '@kbn/core-ui-settings-browser'; import { UiSettingsApi } from './ui_settings_api'; import { UiSettingsClient } from './ui_settings_client'; import { UiSettingsGlobalClient } from './ui_settings_global_client'; export interface SettingsServiceDeps { - http: HttpSetup; + http: InternalHttpSetup; injectedMetadata: InternalInjectedMetadataSetup; } diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.test.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.test.ts index 9fbbb4045583..992e2230988d 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.test.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.test.ts @@ -345,3 +345,45 @@ describe('#stop', () => { await batchSetPromise; }); }); + +describe('#validate', () => { + it('sends a validation request', async () => { + fetchMock.mock('*', { + body: { errorMessage: 'Test validation error message.' }, + }); + + const { uiSettingsApi } = setup(); + await uiSettingsApi.validate('foo', 'bar'); + expect(fetchMock.calls()).toMatchSnapshot('validation request'); + }); + + it('rejects on 404 response', async () => { + fetchMock.mock('*', { + status: 404, + body: 'not found', + }); + + const { uiSettingsApi } = setup(); + await expect(uiSettingsApi.validate('foo', 'bar')).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('rejects on 301', async () => { + fetchMock.mock('*', { + status: 301, + body: 'redirect', + }); + + const { uiSettingsApi } = setup(); + await expect(uiSettingsApi.validate('foo', 'bar')).rejects.toThrowErrorMatchingSnapshot(); + }); + + it('rejects on 500', async () => { + fetchMock.mock('*', { + status: 500, + body: 'redirect', + }); + + const { uiSettingsApi } = setup(); + await expect(uiSettingsApi.validate('foo', 'bar')).rejects.toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.ts index c96232b9f9b4..c26d2369d4e0 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_api.ts @@ -7,7 +7,7 @@ */ import { BehaviorSubject } from 'rxjs'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { UiSettingsState } from '@kbn/core-ui-settings-browser'; import { UiSettingsScope } from '@kbn/core-ui-settings-common'; @@ -16,6 +16,11 @@ export interface UiSettingsApiResponse { settings: UiSettingsState; } +export interface ValidationApiResponse { + valid: boolean; + errorMessage?: string; +} + interface Changes { values: { [key: string]: any; @@ -37,7 +42,7 @@ export class UiSettingsApi { private readonly loadingCount$ = new BehaviorSubject(0); - constructor(private readonly http: HttpSetup) {} + constructor(private readonly http: InternalHttpSetup) {} /** * Adds a key+value that will be sent to the server ASAP. If a request is @@ -94,6 +99,15 @@ export class UiSettingsApi { }); } + /** + * Sends a validation request to the server for the provided key+value pair. + */ + public async validate(key: string, value: any): Promise { + return await this.sendRequest('POST', `/internal/kibana/settings/${key}/validate`, { + value, + }); + } + /** * Gets an observable that notifies subscribers of the current number of active requests */ diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client.test.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client.test.ts index 8e8a4af6aa00..58da98f91e10 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client.test.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client.test.ts @@ -10,6 +10,9 @@ import { Subject } from 'rxjs'; import { materialize, take, toArray } from 'rxjs/operators'; import { UiSettingsClient } from './ui_settings_client'; +import { ValidationApiResponse } from './ui_settings_api'; + +const TEST_VALIDATION_ERROR_MESSAGE = 'Test validation message.'; let done$: Subject; @@ -22,6 +25,12 @@ function setup(options: { defaults?: any; initialSettings?: any } = {}) { const batchSetGlobal = jest.fn(() => ({ settings: {}, })); + const validate = jest.fn( + (): ValidationApiResponse => ({ + valid: false, + errorMessage: TEST_VALIDATION_ERROR_MESSAGE, + }) + ); done$ = new Subject(); const client = new UiSettingsClient({ defaults, @@ -29,11 +38,12 @@ function setup(options: { defaults?: any; initialSettings?: any } = {}) { api: { batchSet, batchSetGlobal, + validate, } as any, done$, }); - return { client, batchSet, batchSetGlobal }; + return { client, batchSet, batchSetGlobal, validate }; } afterEach(() => { @@ -283,3 +293,27 @@ describe('#getUpdate$', () => { expect(onComplete).toHaveBeenCalled(); }); }); + +describe('#validateValue', () => { + it('resolves to a ValueValidation', async () => { + const { client } = setup(); + + await expect(client.validateValue('foo', 'bar')).resolves.toMatchObject({ + successfulValidation: true, + valid: false, + errorMessage: TEST_VALIDATION_ERROR_MESSAGE, + }); + }); + + it('resolves to a ValueValidation on failure', async () => { + const { client, validate } = setup(); + + validate.mockImplementation(() => { + throw new Error('Error in request'); + }); + + await expect(client.validateValue('foo', 'bar')).resolves.toMatchObject({ + successfulValidation: false, + }); + }); +}); diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts index 65a3c44861ed..cccb0f85bb0d 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_client_common.ts @@ -128,6 +128,19 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r return this.updateErrors$.asObservable(); } + async validateValue(key: string, value: unknown) { + try { + const resp = await this.api.validate(key, value); + const isValid = resp.valid; + return isValid + ? { successfulValidation: true, valid: true } + : { successfulValidation: true, valid: false, errorMessage: resp.errorMessage }; + } catch (error) { + this.updateErrors$.next(error); + return { successfulValidation: false }; + } + } + protected assertUpdateAllowed(key: string) { if (this.isOverridden(key)) { throw new Error( diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_service.ts b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_service.ts index c531d18aded1..5827919f21ad 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_service.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/src/ui_settings_service.ts @@ -9,14 +9,14 @@ import { Subject } from 'rxjs'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import type { InternalHttpSetup } from '@kbn/core-http-browser-internal'; import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { UiSettingsApi } from './ui_settings_api'; import { UiSettingsClient } from './ui_settings_client'; export interface UiSettingsServiceDeps { - http: HttpSetup; + http: InternalHttpSetup; injectedMetadata: InternalInjectedMetadataSetup; } diff --git a/packages/core/ui-settings/core-ui-settings-browser-internal/tsconfig.json b/packages/core/ui-settings/core-ui-settings-browser-internal/tsconfig.json index 0beed2d6ddfb..bcedc9db9175 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-internal/tsconfig.json +++ b/packages/core/ui-settings/core-ui-settings-browser-internal/tsconfig.json @@ -12,12 +12,12 @@ ], "kbn_references": [ "@kbn/core-test-helpers-http-setup-browser", - "@kbn/core-http-browser", "@kbn/core-ui-settings-browser", "@kbn/core-ui-settings-common", "@kbn/core-http-browser-mocks", "@kbn/core-injected-metadata-browser-mocks", "@kbn/core-injected-metadata-browser-internal", + "@kbn/core-http-browser-internal", ], "exclude": [ "target/**/*", diff --git a/packages/core/ui-settings/core-ui-settings-browser-mocks/src/client.mock.ts b/packages/core/ui-settings/core-ui-settings-browser-mocks/src/client.mock.ts index 0f7c9a6bd0ad..93ca7d065b0f 100644 --- a/packages/core/ui-settings/core-ui-settings-browser-mocks/src/client.mock.ts +++ b/packages/core/ui-settings/core-ui-settings-browser-mocks/src/client.mock.ts @@ -22,6 +22,7 @@ export const clientMock = () => { isOverridden: jest.fn(), getUpdate$: jest.fn(), getUpdateErrors$: jest.fn(), + validateValue: jest.fn(), }; mock.get$.mockReturnValue(new Subject()); mock.getUpdate$.mockReturnValue(new Subject()); diff --git a/packages/core/ui-settings/core-ui-settings-browser/src/types.ts b/packages/core/ui-settings/core-ui-settings-browser/src/types.ts index 1227df230926..6927506a5338 100644 --- a/packages/core/ui-settings/core-ui-settings-browser/src/types.ts +++ b/packages/core/ui-settings/core-ui-settings-browser/src/types.ts @@ -16,6 +16,12 @@ export interface UiSettingsState { [key: string]: PublicUiSettingsParams & UserProvidedValues; } +export interface ValueValidation { + successfulValidation: boolean; + valid?: boolean; + errorMessage?: string; +} + /** * Client-side client that provides access to the advanced settings stored in elasticsearch. * The settings provide control over the behavior of the Kibana application. @@ -100,6 +106,11 @@ export interface IUiSettingsClient { * the settings, containing the actual Error class. */ getUpdateErrors$: () => Observable; + + /** + * Validates a uiSettings value and returns a ValueValidation object. + */ + validateValue: (key: string, value: any) => Promise; } /** @public */ diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts index 2d6e2d93a431..90205f8afa64 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts @@ -10,6 +10,7 @@ import { omit } from 'lodash'; import type { Logger } from '@kbn/logging'; import type { UiSettingsParams, UserProvidedValues } from '@kbn/core-ui-settings-common'; import type { IUiSettingsClient } from '@kbn/core-ui-settings-server'; +import { ValidationBadValueError, ValidationSettingNotFoundError } from '../ui_settings_errors'; export interface BaseUiSettingsDefaultsClientOptions { overrides?: Record; @@ -72,6 +73,24 @@ export abstract class BaseUiSettingsClient implements IUiSettingsClient { return !!definition?.sensitive; } + async validate(key: string, value: unknown) { + if (!value) { + throw new ValidationBadValueError(); + } + const definition = this.defaults[key]; + if (!definition) { + throw new ValidationSettingNotFoundError(key); + } + if (definition.schema) { + try { + definition.schema.validate(value); + } catch (error) { + return { valid: false, errorMessage: error.message }; + } + } + return { valid: true }; + } + protected validateKey(key: string, value: unknown) { const definition = this.defaults[key]; if (value === null || definition === undefined) return; diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_client.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_client.test.ts index b00517d259a4..7baa7afad9b2 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_client.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_client.test.ts @@ -13,7 +13,11 @@ import { mockCreateOrUpgradeSavedConfig } from './ui_settings_client.test.mock'; import { SavedObjectsClient } from '@kbn/core-saved-objects-api-server-internal'; import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; import { UiSettingsClient } from './ui_settings_client'; -import { CannotOverrideError } from '../ui_settings_errors'; +import { + CannotOverrideError, + ValidationBadValueError, + ValidationSettingNotFoundError, +} from '../ui_settings_errors'; const logger = loggingSystemMock.create().get(); @@ -732,6 +736,48 @@ describe('ui settings', () => { }); }); + describe('#validate()', () => { + it('returns a correct validation response for an existing setting key and an invalid value', async () => { + const defaults = { foo: { schema: schema.number() } }; + const { uiSettings } = setup({ defaults }); + + expect(await uiSettings.validate('foo', 'testValue')).toMatchObject({ + valid: false, + errorMessage: 'expected value of type [number] but got [string]', + }); + }); + + it('returns a correct validation response for an existing setting key and a valid value', async () => { + const defaults = { foo: { schema: schema.number() } }; + const { uiSettings } = setup({ defaults }); + + expect(await uiSettings.validate('foo', 5)).toMatchObject({ valid: true }); + }); + + it('throws for a non-existing setting key', async () => { + const { uiSettings } = setup(); + + try { + await uiSettings.validate('bar', 5); + } catch (error) { + expect(error).toBeInstanceOf(ValidationSettingNotFoundError); + expect(error.message).toBe('Setting with a key [bar] does not exist.'); + } + }); + + it('throws for a null value', async () => { + const defaults = { foo: { schema: schema.number() } }; + const { uiSettings } = setup({ defaults }); + + try { + await uiSettings.validate('foo', null); + } catch (error) { + expect(error).toBeInstanceOf(ValidationBadValueError); + expect(error.message).toBe('No value was specified.'); + } + }); + }); + describe('caching', () => { describe('read operations cache user config', () => { beforeEach(() => { diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/index.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/index.ts index e15ded76ab6b..dccadb6c02f6 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/index.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/index.ts @@ -11,10 +11,12 @@ import { registerInternalDeleteRoute } from './delete'; import { registerInternalGetRoute } from './get'; import { registerInternalSetManyRoute } from './set_many'; import { registerInternalSetRoute } from './set'; +import { registerInternalValidateRoute } from './validate'; export function registerInternalRoutes(router: InternalUiSettingsRouter) { registerInternalGetRoute(router); registerInternalDeleteRoute(router); registerInternalSetRoute(router); registerInternalSetManyRoute(router); + registerInternalValidateRoute(router); } diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/validate.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/validate.ts new file mode 100644 index 000000000000..83f119c658a8 --- /dev/null +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/routes/internal/validate.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; +import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-server'; +import { ValidationBadValueError, ValidationSettingNotFoundError } from '../../ui_settings_errors'; +import type { + InternalUiSettingsRequestHandlerContext, + InternalUiSettingsRouter, +} from '../../internal_types'; + +export function registerInternalValidateRoute(router: InternalUiSettingsRouter) { + const validateFromRequest = async ( + uiSettingsClient: IUiSettingsClient, + context: InternalUiSettingsRequestHandlerContext, + request: KibanaRequest< + Readonly<{} & { key: string }>, + unknown, + Readonly<{ value?: any } & {}>, + 'post' + >, + response: KibanaResponseFactory + ) => { + try { + const { key } = request.params; + const { value } = request.body; + + const { valid, errorMessage } = await uiSettingsClient.validate(key, value); + + return response.ok({ + body: { + valid, + errorMessage, + }, + }); + } catch (error) { + if (error instanceof ValidationSettingNotFoundError) { + return response.notFound({ body: error }); + } + + if (error instanceof ValidationBadValueError) { + return response.badRequest({ body: error }); + } + + throw error; + } + }; + router.post( + { + path: '/internal/kibana/settings/{key}/validate', + validate: { + params: schema.object({ + key: schema.string(), + }), + body: schema.object({ + value: schema.any(), + }), + }, + options: { access: 'internal' }, + }, + async (context, request, response) => { + const uiSettingsClient = (await context.core).uiSettings.client; + return await validateFromRequest(uiSettingsClient, context, request, response); + } + ); +} diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_errors.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_errors.ts index 755ed6447c5e..93cec94bc71a 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_errors.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_errors.ts @@ -27,3 +27,15 @@ export class SettingNotRegisteredError extends Error { ); } } + +export class ValidationSettingNotFoundError extends Error { + constructor(key: string) { + super(`Setting with a key [${key}] does not exist.`); + } +} + +export class ValidationBadValueError extends Error { + constructor() { + super('No value was specified.'); + } +} diff --git a/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts b/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts index 280d75319a8b..7149da0d517b 100644 --- a/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts +++ b/packages/core/ui-settings/core-ui-settings-server-mocks/src/ui_settings_service.mock.ts @@ -27,6 +27,7 @@ const createClientMock = () => { removeMany: jest.fn(), isOverridden: jest.fn(), isSensitive: jest.fn(), + validate: jest.fn(), }; mocked.get.mockResolvedValue(false); mocked.getAll.mockResolvedValue({}); diff --git a/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts b/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts index 9a297109002d..d4b16ae6ffe1 100644 --- a/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts +++ b/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts @@ -8,6 +8,11 @@ import type { UserProvidedValues, UiSettingsParams } from '@kbn/core-ui-settings-common'; +interface ValueValidation { + valid: boolean; + errorMessage?: string; +} + /** * Server-side client that provides access to the advanced settings stored in elasticsearch. * The settings provide control over the behavior of the Kibana application. @@ -57,4 +62,8 @@ export interface IUiSettingsClient { * Shows whether the uiSetting is a sensitive value. Used by telemetry to not send sensitive values. */ isSensitive: (key: string) => boolean; + /** + * Validates the uiSettings value and returns a ValueValidation object. + */ + validate: (key: string, value: unknown) => Promise; } diff --git a/packages/home/sample_data_card/src/sample_data_card.tsx b/packages/home/sample_data_card/src/sample_data_card.tsx index a8da0a7494da..a952431c5097 100644 --- a/packages/home/sample_data_card/src/sample_data_card.tsx +++ b/packages/home/sample_data_card/src/sample_data_card.tsx @@ -6,11 +6,10 @@ * Side Public License, v 1. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { useEuiTheme } from '@elastic/eui'; import type { SampleDataSet } from '@kbn/home-sample-data-types'; -import { useServices } from './services'; import { SampleDataCard as Component, Props as ComponentProps } from './sample_data_card.component'; /** @@ -27,12 +26,10 @@ export interface Props extends Pick { * function. */ export const SampleDataCard = ({ sampleDataSet, onStatusChange }: Props) => { - const { addBasePath } = useServices(); const { colorMode } = useEuiTheme(); const { darkPreviewImagePath, previewImagePath } = sampleDataSet; - const path = + const imagePath = colorMode === 'DARK' && darkPreviewImagePath ? darkPreviewImagePath : previewImagePath; - const imagePath = useMemo(() => addBasePath(path), [addBasePath, path]); return ; }; diff --git a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts index f22e902bbbea..07ada8b7c06b 100644 --- a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts +++ b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts @@ -32,6 +32,7 @@ import { ALERT_TIME_RANGE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, SPACE_IDS, @@ -41,6 +42,7 @@ import { EVENT_KIND, TAGS, } from '@kbn/rule-data-utils'; +import { MultiField } from './types'; export const alertFieldMap = { [ALERT_ACTION_GROUP]: { @@ -92,6 +94,13 @@ export const alertFieldMap = { type: 'keyword', array: false, required: false, + multi_fields: [ + { + flat_name: `${ALERT_REASON}.text`, + name: 'text', + type: 'match_only_text', + }, + ] as MultiField[], }, [ALERT_RULE_CATEGORY]: { type: 'keyword', @@ -182,6 +191,11 @@ export const alertFieldMap = { array: true, required: false, }, + [ALERT_WORKFLOW_ASSIGNEE_IDS]: { + type: 'keyword', + array: true, + required: false, + }, [EVENT_ACTION]: { type: 'keyword', array: false, diff --git a/packages/kbn-alerts-as-data-utils/src/field_maps/ecs_field_map.ts b/packages/kbn-alerts-as-data-utils/src/field_maps/ecs_field_map.ts index 3704edee7270..8aea9ca56e02 100644 --- a/packages/kbn-alerts-as-data-utils/src/field_maps/ecs_field_map.ts +++ b/packages/kbn-alerts-as-data-utils/src/field_maps/ecs_field_map.ts @@ -11,9 +11,64 @@ import { EcsMetadata, FieldMap } from './types'; const EXCLUDED_TYPES = ['constant_keyword']; +// ECS fields that have reached Stage 2 in the RFC process +// are included in the generated Yaml but are still considered +// experimental. Some are correctly marked as beta but most are +// not. + +// More about the RFC stages here: https://elastic.github.io/ecs/stages.html + +// The following RFCS are currently in stage 2: +// https://github.com/elastic/ecs/blob/main/rfcs/text/0027-faas-fields.md +// https://github.com/elastic/ecs/blob/main/rfcs/text/0035-tty-output.md +// https://github.com/elastic/ecs/blob/main/rfcs/text/0037-host-metrics.md +// https://github.com/elastic/ecs/blob/main/rfcs/text/0040-volume-device.md + +// Fields from these RFCs that are not already in the ECS component template +// as of 8.11 are manually identified as experimental below. +// The next time this list is updated, we should check the above list of RFCs to +// see if any have moved to Stage 3 and remove them from the list and check if +// there are any new stage 2 RFCs with fields we should exclude as experimental. + +const EXPERIMENTAL_FIELDS = [ + 'faas.trigger', // this was previously mapped as nested but changed to object + 'faas.trigger.request_id', + 'faas.trigger.type', + 'host.cpu.system.norm.pct', + 'host.cpu.user.norm.pct', + 'host.fsstats.total_size.total', + 'host.fsstats.total_size.used', + 'host.fsstats.total_size.used.pct', + 'host.load.norm.1', + 'host.load.norm.5', + 'host.load.norm.15', + 'host.memory.actual.used.bytes', + 'host.memory.actual.used.pct', + 'host.memory.total', + 'process.io.bytes', + 'volume.bus_type', + 'volume.default_access', + 'volume.device_name', + 'volume.device_type', + 'volume.dos_name', + 'volume.file_system_type', + 'volume.mount_name', + 'volume.nt_name', + 'volume.product_id', + 'volume.product_name', + 'volume.removable', + 'volume.serial_number', + 'volume.size', + 'volume.vendor_id', + 'volume.vendor_name', + 'volume.writable', +]; + export const ecsFieldMap: FieldMap = Object.fromEntries( Object.entries(EcsFlat) - .filter(([_, value]) => !EXCLUDED_TYPES.includes(value.type)) + .filter( + ([key, value]) => !EXCLUDED_TYPES.includes(value.type) && !EXPERIMENTAL_FIELDS.includes(key) + ) .map(([key, _]) => { const value: EcsMetadata = EcsFlat[key as keyof typeof EcsFlat]; return [ diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/alert_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/alert_schema.ts index ac143adf5f5d..5625460f269b 100644 --- a/packages/kbn-alerts-as-data-utils/src/schemas/generated/alert_schema.ts +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/alert_schema.ts @@ -98,6 +98,7 @@ const AlertOptional = rt.partial({ 'kibana.alert.start': schemaDate, 'kibana.alert.time_range': schemaDateRange, 'kibana.alert.url': schemaString, + 'kibana.alert.workflow_assignee_ids': schemaStringArray, 'kibana.alert.workflow_status': schemaString, 'kibana.alert.workflow_tags': schemaStringArray, 'kibana.version': schemaString, diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/ecs_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/ecs_schema.ts index a3d3ef6f0a8a..b3bc0eb16172 100644 --- a/packages/kbn-alerts-as-data-utils/src/schemas/generated/ecs_schema.ts +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/ecs_schema.ts @@ -308,7 +308,6 @@ const EcsOptional = rt.partial({ 'faas.execution': schemaString, 'faas.id': schemaString, 'faas.name': schemaString, - 'faas.trigger': schemaUnknown, 'faas.version': schemaString, 'file.accessed': schemaDate, 'file.attributes': schemaStringArray, diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/security_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/security_schema.ts index f8648bfa4218..a0af087b70c9 100644 --- a/packages/kbn-alerts-as-data-utils/src/schemas/generated/security_schema.ts +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/security_schema.ts @@ -193,6 +193,7 @@ const SecurityAlertOptional = rt.partial({ ), 'kibana.alert.time_range': schemaDateRange, 'kibana.alert.url': schemaString, + 'kibana.alert.workflow_assignee_ids': schemaStringArray, 'kibana.alert.workflow_reason': schemaString, 'kibana.alert.workflow_status': schemaString, 'kibana.alert.workflow_tags': schemaStringArray, diff --git a/packages/kbn-alerts-as-data-utils/src/search/security/fields.ts b/packages/kbn-alerts-as-data-utils/src/search/security/fields.ts index b3be5cbb62a1..34da32b0eaa5 100644 --- a/packages/kbn-alerts-as-data-utils/src/search/security/fields.ts +++ b/packages/kbn-alerts-as-data-utils/src/search/security/fields.ts @@ -11,6 +11,7 @@ import { ALERT_RISK_SCORE, ALERT_SEVERITY, ALERT_RULE_PARAMETERS, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_TAGS, } from '@kbn/rule-data-utils'; @@ -46,6 +47,7 @@ export const ALERT_EVENTS_FIELDS = [ ALERT_RULE_CONSUMER, '@timestamp', 'kibana.alert.ancestors.index', + ALERT_WORKFLOW_ASSIGNEE_IDS, 'kibana.alert.workflow_status', ALERT_WORKFLOW_TAGS, 'kibana.alert.group.id', diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts index bedae100bc93..3dd5ec30933c 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts @@ -64,6 +64,14 @@ export class Instance extends Entity { }); } + crash({ message, type }: { message: string; type?: string }) { + return new ApmError({ + ...this.fields, + 'error.type': 'crash', + 'error.exception': [{ message, ...(type ? { type } : {}) }], + 'error.grouping_name': getErrorGroupingKey(message), + }); + } error({ message, type }: { message: string; type?: string }) { return new ApmError({ ...this.fields, diff --git a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts index 8a1476cd5827..3453bee1d736 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts @@ -22,6 +22,7 @@ export type LogDocument = Fields & 'log.level'?: string; 'host.name'?: string; 'trace.id'?: string; + 'agent.id'?: string; 'agent.name'?: string; 'orchestrator.cluster.name'?: string; 'orchestrator.cluster.id'?: string; diff --git a/packages/kbn-apm-synthtrace/src/cli/run_synthtrace.ts b/packages/kbn-apm-synthtrace/src/cli/run_synthtrace.ts index d792dc35f037..08fab85b04c0 100644 --- a/packages/kbn-apm-synthtrace/src/cli/run_synthtrace.ts +++ b/packages/kbn-apm-synthtrace/src/cli/run_synthtrace.ts @@ -52,10 +52,6 @@ function options(y: Argv) { number: true, default: 1, }) - .option('versionOverride', { - describe: 'Package/observer version override', - string: true, - }) .option('logLevel', { describe: 'Log level', default: 'info', @@ -66,6 +62,10 @@ function options(y: Argv) { return arg as Record | undefined; }, }) + .option('assume-package-version', { + describe: 'Assumes passed package version to avoid calling Fleet API to install', + string: true, + }) .showHelpOnFail(false); } diff --git a/packages/kbn-apm-synthtrace/src/cli/utils/bootstrap.ts b/packages/kbn-apm-synthtrace/src/cli/utils/bootstrap.ts index be0bd7ff6168..df436fa8984e 100644 --- a/packages/kbn-apm-synthtrace/src/cli/utils/bootstrap.ts +++ b/packages/kbn-apm-synthtrace/src/cli/utils/bootstrap.ts @@ -16,6 +16,8 @@ import { RunOptions } from './parse_run_cli_flags'; export async function bootstrap(runOptions: RunOptions) { const logger = createLogger(runOptions.logLevel); + let version = runOptions['assume-package-version']; + const { kibanaUrl, esUrl } = await getServiceUrls({ ...runOptions, logger }); const kibanaClient = getKibanaClient({ @@ -23,9 +25,14 @@ export async function bootstrap(runOptions: RunOptions) { logger, }); - const latestPackageVersion = await kibanaClient.fetchLatestApmPackageVersion(); + if (!version) { + version = await kibanaClient.fetchLatestApmPackageVersion(); + await kibanaClient.installApmPackage(version); + } else if (version === 'latest') { + version = await kibanaClient.fetchLatestApmPackageVersion(); + } - const version = runOptions.versionOverride || latestPackageVersion; + logger.info(`Using package version: ${version}`); const apmEsClient = getApmEsClient({ target: esUrl, @@ -40,8 +47,6 @@ export async function bootstrap(runOptions: RunOptions) { concurrency: runOptions.concurrency, }); - await kibanaClient.installApmPackage(latestPackageVersion); - if (runOptions.clean) { await apmEsClient.clean(); await logsEsClient.clean(); diff --git a/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts b/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts index 64abc36c0560..3f13cae5e039 100644 --- a/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts +++ b/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts @@ -36,6 +36,7 @@ async function discoverAuth(parsedTarget: Url) { async function getKibanaUrl({ target, logger }: { target: string; logger: Logger }) { try { + const isCI = process.env.CI?.toLowerCase() === 'true'; logger.debug(`Checking Kibana URL ${target} for a redirect`); const unredirectedResponse = await fetch(target, { @@ -69,7 +70,16 @@ async function getKibanaUrl({ target, logger }: { target: string; logger: Logger ); } - logger.info(`Discovered kibana running at: ${discoveredKibanaUrlWithAuth}`); + const discoveredKibanaUrlWithoutAuth = format({ + ...parsedDiscoveredUrl, + auth: undefined, + }); + + logger.info( + `Discovered kibana running at: ${ + isCI ? discoveredKibanaUrlWithoutAuth : discoveredKibanaUrlWithAuth + }` + ); return discoveredKibanaUrlWithAuth.replace(/\/$/, ''); } catch (error) { diff --git a/packages/kbn-apm-synthtrace/src/cli/utils/parse_run_cli_flags.ts b/packages/kbn-apm-synthtrace/src/cli/utils/parse_run_cli_flags.ts index 57426902d7b6..fe047f7ebfc8 100644 --- a/packages/kbn-apm-synthtrace/src/cli/utils/parse_run_cli_flags.ts +++ b/packages/kbn-apm-synthtrace/src/cli/utils/parse_run_cli_flags.ts @@ -38,7 +38,10 @@ function getParsedFile(flags: RunCliFlags) { } export function parseRunCliFlags(flags: RunCliFlags) { - const { logLevel } = flags; + const { logLevel, target } = flags; + if (target?.includes('.kb.')) { + throw new Error(`Target URL seems to be a Kibana URL, please provide Elasticsearch URL`); + } const parsedFile = getParsedFile(flags); let parsedLogLevel = LogLevel.info; @@ -69,7 +72,8 @@ export function parseRunCliFlags(flags: RunCliFlags) { 'kibana', 'concurrency', 'versionOverride', - 'clean' + 'clean', + 'assume-package-version' ), logLevel: parsedLogLevel, file: parsedFile, diff --git a/packages/kbn-apm-synthtrace/src/scenarios/trace_with_orphan_items.ts b/packages/kbn-apm-synthtrace/src/scenarios/trace_with_orphan_items.ts new file mode 100644 index 000000000000..ca853f9e7354 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/trace_with_orphan_items.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { apm, ApmFields, httpExitSpan, Serializable } from '@kbn/apm-synthtrace-client'; +import { Readable } from 'stream'; +import { Scenario } from '../cli/scenario'; + +import { RunOptions } from '../cli/utils/parse_run_cli_flags'; +import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment'; +import { withClient } from '../lib/utils/with_client'; + +const ENVIRONMENT = getSynthtraceEnvironment(__filename); + +const scenario: Scenario = async (runOptions: RunOptions) => { + return { + generate: ({ range, clients: { apmEsClient } }) => { + const transactionName = 'trace with orphans'; + const successfulTimestamps = range.interval('1s').rate(3); + + const synthRum = apm + .service({ name: 'synth-rum', environment: ENVIRONMENT, agentName: 'rum-js' }) + .instance('my-instance'); + const synthNode = apm + .service({ name: 'synth-node', environment: ENVIRONMENT, agentName: 'nodejs' }) + .instance('my-instance'); + const synthGo = apm + .service({ name: 'synth-go', environment: ENVIRONMENT, agentName: 'go' }) + .instance('my-instance'); + + const traces = successfulTimestamps.generator((timestamp) => { + // synth-rum + return synthGo + .transaction({ transactionName }) + .duration(400) + .timestamp(timestamp) + .children( + // synth-rum -> synth-node + synthRum + .span( + httpExitSpan({ + spanName: 'GET /api/products/top', + destinationUrl: 'http://synth-node:3000', + }) + ) + .duration(300) + .timestamp(timestamp) + .children( + synthRum + .transaction({ transactionName: 'Child Transaction' }) + .timestamp(timestamp) + .duration(200) + .children( + synthGo + .span({ spanName: 'custom_operation', spanType: 'custom' }) + .timestamp(timestamp) + .duration(100) + .success() + ), + // synth-node + synthNode + .transaction({ transactionName: 'Initial transaction in synth-node' }) + .duration(300) + .timestamp(timestamp) + .children( + synthNode + // synth-node -> synth-go + .span( + httpExitSpan({ + spanName: 'GET synth-go:3000', + destinationUrl: 'http://synth-go:3000', + }) + ) + .timestamp(timestamp) + .duration(400) + + .children( + // synth-go + synthGo + .transaction({ transactionName: 'Child Transaction' }) + .timestamp(timestamp) + .duration(200) + .children( + synthGo + .span({ spanName: 'custom_operation', spanType: 'custom' }) + .timestamp(timestamp) + .duration(100) + .success(), + synthGo + .span({ spanName: 'custom_new_operation', spanType: 'custom' }) + .timestamp(timestamp) + .duration(100) + .success() + ) + ) + ) + ) + ); + }); + + const successfulTraceEvents = Array.from( + successfulTimestamps.generator((timestamp) => + synthNode + .transaction({ transactionName: 'successful trace' }) + .timestamp(timestamp) + .duration(1000) + .success() + .children( + synthNode + .span({ + spanName: 'GET apm-*/_search', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .duration(1000) + .success() + .destination('elasticsearch') + .timestamp(timestamp), + synthNode + .span({ spanName: 'custom_operation', spanType: 'custom' }) + .duration(100) + .success() + .timestamp(timestamp) + ) + ) + ); + + const unserialized = Array.from(traces); + + const serialized = unserialized + .flatMap((event) => event.serialize()) + .filter((trace) => trace['transaction.name'] !== 'Child Transaction'); + + const unserializedChanged = serialized.map((event) => ({ + fields: event, + serialize: () => { + return [event]; + }, + })) as Array>; + + return withClient( + apmEsClient, + Readable.from([...unserializedChanged, ...successfulTraceEvents]) + ); + }, + }; +}; + +export default scenario; diff --git a/packages/kbn-axe-config/index.ts b/packages/kbn-axe-config/index.ts index 7f7340873372..74cfa52939d8 100644 --- a/packages/kbn-axe-config/index.ts +++ b/packages/kbn-axe-config/index.ts @@ -26,21 +26,11 @@ export const AXE_CONFIG = { id: 'aria-roles', selector: '[data-test-subj="comboBoxSearchInput"] *', }, - { - // EUI bug: https://github.com/elastic/eui/issues/4474 - id: 'aria-required-parent', - selector: '[class=*"euiDataGridRowCell"][role="gridcell"]', - }, { // 3rd-party library; button has aria-describedby id: 'button-name', selector: '[data-rbd-drag-handle-draggable-id]', }, - { - // EUI bug: https://github.com/elastic/eui/issues/4536 - id: 'duplicate-id', - selector: '.euiSuperDatePicker *', - }, ], }; diff --git a/packages/kbn-calculate-auto/README.md b/packages/kbn-calculate-auto/README.md new file mode 100644 index 000000000000..4964f65ef181 --- /dev/null +++ b/packages/kbn-calculate-auto/README.md @@ -0,0 +1,3 @@ +# @kbn/calculate-auto + +Empty package generated by @kbn/generate diff --git a/packages/kbn-calculate-auto/index.ts b/packages/kbn-calculate-auto/index.ts new file mode 100644 index 000000000000..fb114b4bb315 --- /dev/null +++ b/packages/kbn-calculate-auto/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { calculateAuto } from './src/calculate_auto'; diff --git a/packages/kbn-calculate-auto/jest.config.js b/packages/kbn-calculate-auto/jest.config.js new file mode 100644 index 000000000000..fa25db97a3a4 --- /dev/null +++ b/packages/kbn-calculate-auto/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-calculate-auto'], +}; diff --git a/packages/kbn-calculate-auto/kibana.jsonc b/packages/kbn-calculate-auto/kibana.jsonc new file mode 100644 index 000000000000..2ce6c776f1a6 --- /dev/null +++ b/packages/kbn-calculate-auto/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/calculate-auto", + "owner": "@elastic/obs-ux-management-team" +} diff --git a/packages/kbn-calculate-auto/package.json b/packages/kbn-calculate-auto/package.json new file mode 100644 index 000000000000..71de96101c61 --- /dev/null +++ b/packages/kbn-calculate-auto/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/calculate-auto", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-calculate-auto/src/calculate_auto.test.ts b/packages/kbn-calculate-auto/src/calculate_auto.test.ts new file mode 100644 index 000000000000..1ef166bae4fc --- /dev/null +++ b/packages/kbn-calculate-auto/src/calculate_auto.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { calculateAuto } from './calculate_auto'; +import moment, { isDuration } from 'moment'; + +describe('calculateAuto.near(bucket, duration)', () => { + it('should calculate the bucket size for 15 minutes', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(15, 'minutes')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asSeconds()).toBe(10); + }); + it('should calculate the bucket size for an hour', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'hour')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asSeconds()).toBe(30); + }); + it('should calculate the bucket size for a day', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'day')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asMinutes()).toBe(10); + }); +}); diff --git a/packages/kbn-calculate-auto/src/calculate_auto.ts b/packages/kbn-calculate-auto/src/calculate_auto.ts new file mode 100644 index 000000000000..a955765ff15f --- /dev/null +++ b/packages/kbn-calculate-auto/src/calculate_auto.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import moment, { isDuration, Duration } from 'moment'; +const d = moment.duration; + +const roundingRules = [ + [d(500, 'ms'), d(100, 'ms')], + [d(5, 'second'), d(1, 'second')], + [d(7.5, 'second'), d(5, 'second')], + [d(15, 'second'), d(10, 'second')], + [d(45, 'second'), d(30, 'second')], + [d(3, 'minute'), d(1, 'minute')], + [d(9, 'minute'), d(5, 'minute')], + [d(20, 'minute'), d(10, 'minute')], + [d(45, 'minute'), d(30, 'minute')], + [d(2, 'hour'), d(1, 'hour')], + [d(6, 'hour'), d(3, 'hour')], + [d(24, 'hour'), d(12, 'hour')], + [d(1, 'week'), d(1, 'd')], + [d(3, 'week'), d(1, 'week')], + [d(1, 'year'), d(1, 'month')], + [d(Infinity, 'year'), d(1, 'year')], +]; + +const reverseRoundingRules = [...roundingRules].reverse(); +type CheckFunction = (bound: Duration, interval: Duration, target: number) => Duration | undefined; + +function findRule(rules: Duration[][], check: CheckFunction, last?: boolean) { + function pickInterval(buckets: number, duration: Duration) { + const target = duration.asMilliseconds() / buckets; + let lastResult = null; + + for (const [end, start] of rules) { + const result = check(end, start, target); + + if (result == null) { + if (!last) continue; + if (lastResult) return lastResult; + break; + } + + if (!last) return result; + lastResult = result; + } + + // fallback to just a number of milliseconds, ensure ms is >= 1 + const ms = Math.max(Math.floor(target), 1); + return moment.duration(ms, 'ms'); + } + + return (buckets: number, duration: Duration) => { + const interval = pickInterval(buckets, duration); + if (isDuration(interval)) return interval; + }; +} + +export const calculateAuto = { + near: findRule( + reverseRoundingRules, + function near(bound, interval, target) { + if (isDuration(bound) && bound.asMilliseconds() > target) return interval; + }, + true + ), + lessThan: findRule( + reverseRoundingRules, + function lessThan(_bound: Duration, interval: Duration, target: number) { + if (interval.asMilliseconds() < target) return interval; + } + ), + atLeast: findRule( + reverseRoundingRules, + function atLeast(_bound: Duration, interval: Duration, target: number) { + if (interval.asMilliseconds() <= target) return interval; + } + ), +}; diff --git a/packages/kbn-calculate-auto/tsconfig.json b/packages/kbn-calculate-auto/tsconfig.json new file mode 100644 index 000000000000..2f9ddddbeea2 --- /dev/null +++ b/packages/kbn-calculate-auto/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/packages/kbn-calculate-width-from-char-count/.storybook/main.js b/packages/kbn-calculate-width-from-char-count/.storybook/main.js new file mode 100644 index 000000000000..8dc3c5d1518f --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/.storybook/main.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/packages/kbn-calculate-width-from-char-count/README.md b/packages/kbn-calculate-width-from-char-count/README.md new file mode 100644 index 000000000000..13581e81bd9e --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/README.md @@ -0,0 +1,3 @@ +# @kbn/calculate-width-from-char-count + +This package contains a function that calculates the approximate width of the component from a text length. diff --git a/packages/kbn-calculate-width-from-char-count/index.ts b/packages/kbn-calculate-width-from-char-count/index.ts new file mode 100644 index 000000000000..de0577ee3ed8 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './src'; diff --git a/packages/kbn-calculate-width-from-char-count/jest.config.js b/packages/kbn-calculate-width-from-char-count/jest.config.js new file mode 100644 index 000000000000..0538847bfc82 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-calculate-width-from-char-count'], +}; diff --git a/packages/kbn-calculate-width-from-char-count/kibana.jsonc b/packages/kbn-calculate-width-from-char-count/kibana.jsonc new file mode 100644 index 000000000000..216b12ddeac8 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/calculate-width-from-char-count", + "owner": "@elastic/kibana-visualizations" +} diff --git a/packages/kbn-calculate-width-from-char-count/package.json b/packages/kbn-calculate-width-from-char-count/package.json new file mode 100644 index 000000000000..dd8182452f0e --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/calculate-width-from-char-count", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "sideEffects": false +} \ No newline at end of file diff --git a/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.test.ts b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.test.ts new file mode 100644 index 000000000000..1dbe25306b63 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { calculateWidthFromCharCount, MAX_WIDTH } from './calculate_width_from_char_count'; + +describe('calculateWidthFromCharCount', () => { + it('should return minimum width if char count is smaller than minWidth', () => { + expect(calculateWidthFromCharCount(10, { minWidth: 300 })).toBe(300); + }); + it('should return calculated width', () => { + expect(calculateWidthFromCharCount(30)).toBe(30 * 7 + 116); + }); + it('should return maximum width if char count is bigger than maxWidth', () => { + expect(calculateWidthFromCharCount(1000)).toBe(MAX_WIDTH); + }); +}); diff --git a/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts new file mode 100644 index 000000000000..c79307473c7e --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_char_count.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface LIMITS { + paddingsWidth: number; + minWidth?: number; + avCharWidth: number; + maxWidth: number; +} + +export const MAX_WIDTH = 550; +const PADDINGS_WIDTH = 116; +const AVERAGE_CHAR_WIDTH = 7; + +const defaultPanelWidths: LIMITS = { + maxWidth: MAX_WIDTH, + avCharWidth: AVERAGE_CHAR_WIDTH, + paddingsWidth: PADDINGS_WIDTH, +}; + +export function calculateWidthFromCharCount( + labelLength: number, + overridesPanelWidths?: Partial +) { + const { maxWidth, avCharWidth, paddingsWidth, minWidth } = { + ...defaultPanelWidths, + ...overridesPanelWidths, + }; + const widthForCharCount = paddingsWidth + labelLength * avCharWidth; + + if (minWidth && widthForCharCount < minWidth) { + return minWidth; + } + + return Math.min(widthForCharCount, maxWidth); +} diff --git a/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.test.ts b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.test.ts new file mode 100644 index 000000000000..6e740defdce9 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { calculateWidthFromEntries } from './calculate_width_from_entries'; +import { MAX_WIDTH } from './calculate_width_from_char_count'; +import faker from 'faker'; + +const generateLabel = (length: number) => faker.random.alpha({ count: length }); + +const generateObjectWithLabelOfLength = (length: number, propOverrides?: Record) => ({ + label: generateLabel(length), + ...propOverrides, +}); + +describe('calculateWidthFromEntries', () => { + it('calculates width for array of strings', () => { + const shortLabels = [10, 20].map(generateLabel); + expect(calculateWidthFromEntries(shortLabels)).toBe(256); + + const mediumLabels = [50, 55, 10, 20].map(generateLabel); + expect(calculateWidthFromEntries(mediumLabels)).toBe(501); + + const longLabels = [80, 90, 10].map(generateLabel); + expect(calculateWidthFromEntries(longLabels)).toBe(MAX_WIDTH); + }); + + it('calculates width for array of objects with keys', () => { + const shortLabels = [10, 20].map((v) => generateObjectWithLabelOfLength(v)); + expect(calculateWidthFromEntries(shortLabels, ['label'])).toBe(256); + + const mediumLabels = [50, 55, 10, 20].map((v) => generateObjectWithLabelOfLength(v)); + expect(calculateWidthFromEntries(mediumLabels, ['label'])).toBe(501); + + const longLabels = [80, 90, 10].map((v) => generateObjectWithLabelOfLength(v)); + expect(calculateWidthFromEntries(longLabels, ['label'])).toBe(MAX_WIDTH); + }); + it('calculates width for array of objects for fallback keys', () => { + const shortLabels = [10, 20].map((v) => + generateObjectWithLabelOfLength(v, { label: undefined, name: generateLabel(v) }) + ); + expect(calculateWidthFromEntries(shortLabels, ['id', 'label', 'name'])).toBe(256); + + const mediumLabels = [50, 55, 10, 20].map((v) => + generateObjectWithLabelOfLength(v, { label: undefined, name: generateLabel(v) }) + ); + expect(calculateWidthFromEntries(mediumLabels, ['id', 'label', 'name'])).toBe(501); + }); +}); diff --git a/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts new file mode 100644 index 000000000000..4a6795c8ea07 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/src/calculate_width_from_entries.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { LIMITS, calculateWidthFromCharCount } from './calculate_width_from_char_count'; + +type GenericObject> = T; + +const getMaxLabelLengthForObjects = ( + entries: GenericObject[], + labelKeys: Array +) => + entries.reduce((acc, curr) => { + const labelKey = labelKeys.find((key) => curr[key]); + if (!labelKey) { + return acc; + } + const labelLength = curr[labelKey].length; + return acc > labelLength ? acc : labelLength; + }, 0); + +const getMaxLabelLengthForStrings = (arr: string[]) => + arr.reduce((acc, curr) => (acc > curr.length ? acc : curr.length), 0); + +export function calculateWidthFromEntries( + entries: GenericObject[] | string[], + labelKeys?: Array, + overridesPanelWidths?: Partial +) { + const maxLabelLength = labelKeys + ? getMaxLabelLengthForObjects(entries as GenericObject[], labelKeys) + : getMaxLabelLengthForStrings(entries as string[]); + + return calculateWidthFromCharCount(maxLabelLength, overridesPanelWidths); +} diff --git a/packages/kbn-calculate-width-from-char-count/src/index.ts b/packages/kbn-calculate-width-from-char-count/src/index.ts new file mode 100644 index 000000000000..33fcddecf740 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/src/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { calculateWidthFromCharCount } from './calculate_width_from_char_count'; + +export { calculateWidthFromEntries } from './calculate_width_from_entries'; diff --git a/packages/kbn-calculate-width-from-char-count/tsconfig.json b/packages/kbn-calculate-width-from-char-count/tsconfig.json new file mode 100644 index 000000000000..ea0a30fa7517 --- /dev/null +++ b/packages/kbn-calculate-width-from-char-count/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + ], + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "kbn_references": [], + "exclude": [ + "target/**/*", + ] +} diff --git a/packages/kbn-cell-actions/constants.ts b/packages/kbn-cell-actions/constants.ts new file mode 100644 index 000000000000..c78869a471cb --- /dev/null +++ b/packages/kbn-cell-actions/constants.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './src/constants'; diff --git a/packages/kbn-cell-actions/src/index.ts b/packages/kbn-cell-actions/src/index.ts index dfd1d83937c0..4e478baec441 100644 --- a/packages/kbn-cell-actions/src/index.ts +++ b/packages/kbn-cell-actions/src/index.ts @@ -20,7 +20,7 @@ export type { export type { UseDataGridColumnsCellActions, UseDataGridColumnsCellActionsProps } from './hooks'; // Constants -export { CellActionsMode, FILTER_CELL_ACTION_TYPE, COPY_CELL_ACTION_TYPE } from './constants'; +export { CellActionsMode } from './constants'; // Components and hooks export { CellActionsProvider } from './context'; diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json new file mode 100644 index 000000000000..ad25525f1930 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -0,0 +1,970 @@ +{ + "core-usage-stats": [], + "legacy-url-alias": [ + "disabled", + "resolveCounter", + "sourceId", + "targetId", + "targetNamespace", + "targetType" + ], + "config": [ + "buildNum" + ], + "config-global": [ + "buildNum" + ], + "url": [ + "accessDate", + "createDate", + "slug" + ], + "usage-counters": [ + "domainId" + ], + "task": [ + "attempts", + "enabled", + "ownerId", + "retryAt", + "runAt", + "schedule", + "schedule.interval", + "scheduledAt", + "scope", + "status", + "taskType" + ], + "guided-onboarding-guide-state": [ + "guideId", + "isActive" + ], + "guided-onboarding-plugin-state": [], + "ui-metric": [ + "count" + ], + "application_usage_totals": [], + "application_usage_daily": [ + "timestamp" + ], + "event_loop_delays_daily": [ + "lastUpdatedAt" + ], + "index-pattern": [ + "name", + "title", + "type" + ], + "sample-data-telemetry": [ + "installCount", + "unInstallCount" + ], + "space": [ + "name" + ], + "spaces-usage-stats": [], + "exception-list-agnostic": [ + "_tags", + "comments", + "comments.comment", + "comments.created_at", + "comments.created_by", + "comments.id", + "comments.updated_at", + "comments.updated_by", + "created_at", + "created_by", + "description", + "entries", + "entries.entries", + "entries.entries.field", + "entries.entries.operator", + "entries.entries.type", + "entries.entries.value", + "entries.field", + "entries.list", + "entries.list.id", + "entries.list.type", + "entries.operator", + "entries.type", + "entries.value", + "expire_time", + "immutable", + "item_id", + "list_id", + "list_type", + "meta", + "name", + "os_types", + "tags", + "tie_breaker_id", + "type", + "updated_by", + "version" + ], + "exception-list": [ + "_tags", + "comments", + "comments.comment", + "comments.created_at", + "comments.created_by", + "comments.id", + "comments.updated_at", + "comments.updated_by", + "created_at", + "created_by", + "description", + "entries", + "entries.entries", + "entries.entries.field", + "entries.entries.operator", + "entries.entries.type", + "entries.entries.value", + "entries.field", + "entries.list", + "entries.list.id", + "entries.list.type", + "entries.operator", + "entries.type", + "entries.value", + "expire_time", + "immutable", + "item_id", + "list_id", + "list_type", + "meta", + "name", + "os_types", + "tags", + "tie_breaker_id", + "type", + "updated_by", + "version" + ], + "telemetry": [], + "file": [ + "FileKind", + "Meta", + "Status", + "Updated", + "created", + "extension", + "hash", + "mime_type", + "name", + "size", + "user" + ], + "fileShare": [ + "created", + "name", + "token", + "valid_until" + ], + "action": [ + "actionTypeId", + "name" + ], + "action_task_params": [], + "connector_token": [ + "connectorId", + "tokenType" + ], + "query": [ + "description", + "title" + ], + "kql-telemetry": [], + "search-session": [ + "created", + "realmName", + "realmType", + "sessionId", + "username" + ], + "search-telemetry": [], + "file-upload-usage-collection-telemetry": [ + "file_upload", + "file_upload.index_creation_count" + ], + "apm-indices": [], + "tag": [ + "color", + "description", + "name" + ], + "alert": [ + "actions", + "actions.actionRef", + "actions.actionTypeId", + "actions.group", + "alertTypeId", + "consumer", + "createdAt", + "createdBy", + "enabled", + "executionStatus", + "executionStatus.error", + "executionStatus.error.message", + "executionStatus.error.reason", + "executionStatus.lastDuration", + "executionStatus.lastExecutionDate", + "executionStatus.numberOfTriggeredActions", + "executionStatus.status", + "executionStatus.warning", + "executionStatus.warning.message", + "executionStatus.warning.reason", + "lastRun", + "lastRun.alertsCount", + "lastRun.alertsCount.active", + "lastRun.alertsCount.ignored", + "lastRun.alertsCount.new", + "lastRun.alertsCount.recovered", + "lastRun.outcome", + "lastRun.outcomeOrder", + "legacyId", + "mapped_params", + "mapped_params.risk_score", + "mapped_params.severity", + "monitoring", + "monitoring.run", + "monitoring.run.calculated_metrics", + "monitoring.run.calculated_metrics.p50", + "monitoring.run.calculated_metrics.p95", + "monitoring.run.calculated_metrics.p99", + "monitoring.run.calculated_metrics.success_ratio", + "monitoring.run.last_run", + "monitoring.run.last_run.metrics", + "monitoring.run.last_run.metrics.duration", + "monitoring.run.last_run.metrics.gap_duration_s", + "monitoring.run.last_run.metrics.total_alerts_created", + "monitoring.run.last_run.metrics.total_alerts_detected", + "monitoring.run.last_run.metrics.total_indexing_duration_ms", + "monitoring.run.last_run.metrics.total_search_duration_ms", + "monitoring.run.last_run.timestamp", + "muteAll", + "mutedInstanceIds", + "name", + "notifyWhen", + "params", + "revision", + "running", + "schedule", + "schedule.interval", + "scheduledTaskId", + "snoozeSchedule", + "snoozeSchedule.duration", + "snoozeSchedule.id", + "snoozeSchedule.skipRecurrences", + "tags", + "throttle", + "updatedAt", + "updatedBy" + ], + "api_key_pending_invalidation": [ + "apiKeyId", + "createdAt" + ], + "rules-settings": [ + "flapping" + ], + "maintenance-window": [ + "enabled", + "events" + ], + "graph-workspace": [ + "description", + "kibanaSavedObjectMeta", + "kibanaSavedObjectMeta.searchSourceJSON", + "legacyIndexPatternRef", + "numLinks", + "numVertices", + "title", + "version", + "wsState" + ], + "search": [ + "description", + "title" + ], + "visualization": [ + "description", + "kibanaSavedObjectMeta", + "title", + "version" + ], + "canvas-element": [ + "@created", + "@timestamp", + "content", + "help", + "image", + "name" + ], + "canvas-workpad": [ + "@created", + "@timestamp", + "name" + ], + "canvas-workpad-template": [ + "help", + "name", + "tags", + "template_key" + ], + "event-annotation-group": [ + "description", + "title" + ], + "dashboard": [ + "controlGroupInput", + "controlGroupInput.chainingSystem", + "controlGroupInput.controlStyle", + "controlGroupInput.ignoreParentSettingsJSON", + "controlGroupInput.panelsJSON", + "description", + "hits", + "kibanaSavedObjectMeta", + "kibanaSavedObjectMeta.searchSourceJSON", + "optionsJSON", + "panelsJSON", + "refreshInterval", + "refreshInterval.display", + "refreshInterval.pause", + "refreshInterval.section", + "refreshInterval.value", + "timeFrom", + "timeRestore", + "timeTo", + "title", + "version" + ], + "links": [ + "description", + "links", + "title" + ], + "lens": [ + "description", + "state", + "title", + "visualizationType" + ], + "lens-ui-telemetry": [ + "count", + "date", + "name", + "type" + ], + "map": [ + "bounds", + "description", + "layerListJSON", + "mapStateJSON", + "title", + "uiStateJSON", + "version" + ], + "cases-comments": [ + "actions", + "actions.type", + "alertId", + "comment", + "created_at", + "created_by", + "created_by.username", + "externalReferenceAttachmentTypeId", + "owner", + "persistableStateAttachmentTypeId", + "pushed_at", + "type", + "updated_at" + ], + "cases-configure": [ + "closure_type", + "created_at", + "owner" + ], + "cases-connector-mappings": [ + "owner" + ], + "cases": [ + "assignees", + "assignees.uid", + "category", + "closed_at", + "closed_by", + "closed_by.email", + "closed_by.full_name", + "closed_by.profile_uid", + "closed_by.username", + "connector", + "connector.fields", + "connector.fields.key", + "connector.fields.value", + "connector.name", + "connector.type", + "created_at", + "created_by", + "created_by.email", + "created_by.full_name", + "created_by.profile_uid", + "created_by.username", + "customFields", + "customFields.key", + "customFields.type", + "customFields.value", + "description", + "duration", + "external_service", + "external_service.connector_name", + "external_service.external_id", + "external_service.external_title", + "external_service.external_url", + "external_service.pushed_at", + "external_service.pushed_by", + "external_service.pushed_by.email", + "external_service.pushed_by.full_name", + "external_service.pushed_by.profile_uid", + "external_service.pushed_by.username", + "owner", + "settings", + "settings.syncAlerts", + "severity", + "status", + "tags", + "title", + "total_alerts", + "total_comments", + "updated_at", + "updated_by", + "updated_by.email", + "updated_by.full_name", + "updated_by.profile_uid", + "updated_by.username" + ], + "cases-user-actions": [ + "action", + "created_at", + "created_by", + "created_by.username", + "owner", + "payload", + "payload.assignees", + "payload.assignees.uid", + "payload.comment", + "payload.comment.externalReferenceAttachmentTypeId", + "payload.comment.persistableStateAttachmentTypeId", + "payload.comment.type", + "payload.connector", + "payload.connector.type", + "type" + ], + "cases-telemetry": [], + "infrastructure-monitoring-log-view": [ + "name" + ], + "metrics-data-source": [], + "ingest_manager_settings": [ + "fleet_server_hosts", + "has_seen_add_data_notice", + "prerelease_integrations_enabled", + "secret_storage_requirements_met" + ], + "ingest-agent-policies": [ + "agent_features", + "agent_features.enabled", + "agent_features.name", + "data_output_id", + "description", + "download_source_id", + "fleet_server_host_id", + "inactivity_timeout", + "is_default", + "is_default_fleet_server", + "is_managed", + "is_preconfigured", + "is_protected", + "keep_monitoring_alive", + "monitoring_enabled", + "monitoring_output_id", + "name", + "namespace", + "overrides", + "revision", + "schema_version", + "status", + "unenroll_timeout", + "updated_at", + "updated_by" + ], + "ingest-outputs": [ + "allow_edit", + "auth_type", + "broker_ack_reliability", + "broker_buffer_size", + "broker_timeout", + "ca_sha256", + "ca_trusted_fingerprint", + "channel_buffer_size", + "client_id", + "compression", + "compression_level", + "config", + "config_yaml", + "connection_type", + "hash", + "hash.hash", + "hash.random", + "headers", + "headers.key", + "headers.value", + "hosts", + "is_default", + "is_default_monitoring", + "is_preconfigured", + "key", + "name", + "output_id", + "partition", + "password", + "proxy_id", + "random", + "random.group_events", + "required_acks", + "round_robin", + "round_robin.group_events", + "sasl", + "sasl.mechanism", + "secrets", + "secrets.password", + "secrets.password.id", + "secrets.service_token", + "secrets.service_token.id", + "secrets.ssl", + "secrets.ssl.key", + "secrets.ssl.key.id", + "service_token", + "shipper", + "ssl", + "timeout", + "topics", + "topics.topic", + "topics.when", + "topics.when.condition", + "topics.when.type", + "type", + "username", + "version" + ], + "ingest-package-policies": [ + "created_at", + "created_by", + "description", + "elasticsearch", + "enabled", + "inputs", + "is_managed", + "name", + "namespace", + "package", + "package.name", + "package.title", + "package.version", + "policy_id", + "revision", + "secret_references", + "secret_references.id", + "updated_at", + "updated_by", + "vars" + ], + "epm-packages": [ + "es_index_patterns", + "experimental_data_stream_features", + "experimental_data_stream_features.data_stream", + "experimental_data_stream_features.features", + "experimental_data_stream_features.features.synthetic_source", + "experimental_data_stream_features.features.tsdb", + "install_format_schema_version", + "install_source", + "install_started_at", + "install_status", + "install_version", + "installed_es", + "installed_es.deferred", + "installed_es.id", + "installed_es.type", + "installed_es.version", + "installed_kibana", + "installed_kibana_space_id", + "internal", + "keep_policies_up_to_date", + "latest_install_failed_attempts", + "name", + "package_assets", + "verification_key_id", + "verification_status", + "version" + ], + "epm-packages-assets": [ + "asset_path", + "data_base64", + "data_utf8", + "install_source", + "media_type", + "package_name", + "package_version" + ], + "fleet-preconfiguration-deletion-record": [ + "id" + ], + "ingest-download-sources": [ + "host", + "is_default", + "name", + "proxy_id", + "source_id" + ], + "fleet-fleet-server-host": [ + "host_urls", + "is_default", + "is_preconfigured", + "name", + "proxy_id" + ], + "fleet-proxy": [ + "certificate", + "certificate_authorities", + "certificate_key", + "is_preconfigured", + "name", + "proxy_headers", + "url" + ], + "fleet-message-signing-keys": [], + "fleet-uninstall-tokens": [ + "policy_id", + "token_plain" + ], + "osquery-manager-usage-metric": [ + "count", + "errors" + ], + "osquery-saved-query": [ + "created_at", + "created_by", + "description", + "ecs_mapping", + "id", + "interval", + "platform", + "query", + "timeout", + "updated_at", + "updated_by", + "version" + ], + "osquery-pack": [ + "created_at", + "created_by", + "description", + "enabled", + "name", + "queries", + "queries.ecs_mapping", + "queries.id", + "queries.interval", + "queries.platform", + "queries.query", + "queries.timeout", + "queries.version", + "shards", + "updated_at", + "updated_by", + "version" + ], + "osquery-pack-asset": [ + "description", + "name", + "queries", + "queries.ecs_mapping", + "queries.id", + "queries.interval", + "queries.platform", + "queries.query", + "queries.timeout", + "queries.version", + "shards", + "version" + ], + "csp-rule-template": [ + "metadata", + "metadata.benchmark", + "metadata.benchmark.id", + "metadata.benchmark.name", + "metadata.benchmark.posture_type", + "metadata.benchmark.rule_number", + "metadata.benchmark.version", + "metadata.id", + "metadata.name", + "metadata.section", + "metadata.version" + ], + "slo": [ + "budgetingMethod", + "description", + "enabled", + "id", + "indicator", + "indicator.params", + "indicator.type", + "name", + "tags" + ], + "threshold-explorer-view": [], + "observability-onboarding-state": [ + "progress", + "state", + "type" + ], + "ml-job": [ + "datafeed_id", + "job_id", + "type" + ], + "ml-trained-model": [ + "job", + "job.create_time", + "job.job_id", + "model_id" + ], + "ml-module": [ + "datafeeds", + "defaultIndexPattern", + "description", + "id", + "jobs", + "logo", + "query", + "tags", + "title", + "type" + ], + "uptime-dynamic-settings": [], + "synthetics-privates-locations": [], + "synthetics-monitor": [ + "alert", + "alert.status", + "alert.status.enabled", + "alert.tls", + "alert.tls.enabled", + "custom_heartbeat_id", + "enabled", + "hash", + "hosts", + "id", + "journey_id", + "locations", + "locations.id", + "locations.label", + "name", + "origin", + "project_id", + "schedule", + "schedule.number", + "tags", + "throttling", + "throttling.label", + "type", + "urls" + ], + "uptime-synthetics-api-key": [ + "apiKey" + ], + "synthetics-param": [], + "infrastructure-ui-source": [], + "inventory-view": [], + "metrics-explorer-view": [], + "upgrade-assistant-reindex-operation": [ + "indexName", + "status" + ], + "upgrade-assistant-ml-upgrade-operation": [ + "snapshotId" + ], + "monitoring-telemetry": [ + "reportedClusterUuids" + ], + "enterprise_search_telemetry": [], + "app_search_telemetry": [], + "workplace_search_telemetry": [], + "siem-ui-timeline-note": [ + "created", + "createdBy", + "eventId", + "note", + "updated", + "updatedBy" + ], + "siem-ui-timeline-pinned-event": [ + "created", + "createdBy", + "eventId", + "updated", + "updatedBy" + ], + "siem-detection-engine-rule-actions": [ + "actions", + "actions.actionRef", + "actions.action_type_id", + "actions.group", + "actions.id", + "actions.params", + "alertThrottle", + "ruleAlertId", + "ruleThrottle" + ], + "security-rule": [ + "rule_id", + "version" + ], + "siem-ui-timeline": [ + "columns", + "columns.aggregatable", + "columns.category", + "columns.columnHeaderType", + "columns.description", + "columns.example", + "columns.id", + "columns.indexes", + "columns.name", + "columns.placeholder", + "columns.searchable", + "columns.type", + "created", + "createdBy", + "dataProviders", + "dataProviders.and", + "dataProviders.and.enabled", + "dataProviders.and.excluded", + "dataProviders.and.id", + "dataProviders.and.kqlQuery", + "dataProviders.and.name", + "dataProviders.and.queryMatch", + "dataProviders.and.queryMatch.displayField", + "dataProviders.and.queryMatch.displayValue", + "dataProviders.and.queryMatch.field", + "dataProviders.and.queryMatch.operator", + "dataProviders.and.queryMatch.value", + "dataProviders.and.type", + "dataProviders.enabled", + "dataProviders.excluded", + "dataProviders.id", + "dataProviders.kqlQuery", + "dataProviders.name", + "dataProviders.queryMatch", + "dataProviders.queryMatch.displayField", + "dataProviders.queryMatch.displayValue", + "dataProviders.queryMatch.field", + "dataProviders.queryMatch.operator", + "dataProviders.queryMatch.value", + "dataProviders.type", + "dateRange", + "dateRange.end", + "dateRange.start", + "description", + "eqlOptions", + "eqlOptions.eventCategoryField", + "eqlOptions.query", + "eqlOptions.size", + "eqlOptions.tiebreakerField", + "eqlOptions.timestampField", + "eventType", + "excludedRowRendererIds", + "favorite", + "favorite.favoriteDate", + "favorite.fullName", + "favorite.keySearch", + "favorite.userName", + "filters", + "filters.exists", + "filters.match_all", + "filters.meta", + "filters.meta.alias", + "filters.meta.controlledBy", + "filters.meta.disabled", + "filters.meta.field", + "filters.meta.formattedValue", + "filters.meta.index", + "filters.meta.key", + "filters.meta.negate", + "filters.meta.params", + "filters.meta.relation", + "filters.meta.type", + "filters.meta.value", + "filters.missing", + "filters.query", + "filters.range", + "filters.script", + "indexNames", + "kqlMode", + "kqlQuery", + "kqlQuery.filterQuery", + "kqlQuery.filterQuery.kuery", + "kqlQuery.filterQuery.kuery.expression", + "kqlQuery.filterQuery.kuery.kind", + "kqlQuery.filterQuery.serializedQuery", + "savedSearchId", + "sort", + "sort.columnId", + "sort.columnType", + "sort.sortDirection", + "status", + "templateTimelineId", + "templateTimelineVersion", + "timelineType", + "title", + "updated", + "updatedBy" + ], + "endpoint:user-artifact-manifest": [ + "artifacts", + "schemaVersion" + ], + "security-solution-signals-migration": [ + "sourceIndex", + "updated", + "version" + ], + "risk-engine-configuration": [ + "dataViewId", + "enabled", + "filter", + "identifierType", + "interval", + "pageSize", + "range", + "range.end", + "range.start" + ], + "policy-settings-protection-updates-note": [ + "note" + ], + "apm-telemetry": [], + "apm-server-schema": [ + "schemaJson" + ], + "apm-service-group": [ + "color", + "description", + "groupName", + "kuery" + ], + "apm-custom-dashboards": [ + "dashboardSavedObjectId", + "kuery", + "serviceEnvironmentFilterEnabled", + "serviceNameFilterEnabled" + ] +} diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index af8fae6214ff..fcc8422c4586 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -1844,6 +1844,14 @@ } } } + }, + "service_token": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + } + } } } } @@ -1959,6 +1967,10 @@ } } }, + "latest_install_failed_attempts": { + "type": "object", + "enabled": false + }, "installed_kibana": { "dynamic": false, "properties": {} @@ -2363,9 +2375,6 @@ }, "tags": { "type": "keyword" - }, - "version": { - "type": "long" } } }, diff --git a/packages/kbn-check-mappings-update-cli/src/check_additive_only_change.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/check_additive_only_change.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/check_additive_only_change.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/check_additive_only_change.ts diff --git a/packages/kbn-check-mappings-update-cli/src/check_additve_only_change.test.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/check_additve_only_change.test.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/check_additve_only_change.test.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/check_additve_only_change.test.ts diff --git a/packages/kbn-check-mappings-update-cli/src/check_incompatible_mappings.test.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/check_incompatible_mappings.test.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/check_incompatible_mappings.test.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/check_incompatible_mappings.test.ts diff --git a/packages/kbn-check-mappings-update-cli/src/check_incompatible_mappings.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/check_incompatible_mappings.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/check_incompatible_mappings.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/check_incompatible_mappings.ts diff --git a/packages/kbn-check-mappings-update-cli/src/current_mappings.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/current_mappings.ts similarity index 97% rename from packages/kbn-check-mappings-update-cli/src/current_mappings.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/current_mappings.ts index c7e7dac4763a..5632f3c479d1 100644 --- a/packages/kbn-check-mappings-update-cli/src/current_mappings.ts +++ b/packages/kbn-check-mappings-update-cli/src/compatibility/current_mappings.ts @@ -11,7 +11,7 @@ import Path from 'path'; import type { SavedObjectsTypeMappingDefinitions } from '@kbn/core-saved-objects-base-server-internal'; -export const CURRENT_MAPPINGS_FILE = Path.resolve(__dirname, '../current_mappings.json'); +export const CURRENT_MAPPINGS_FILE = Path.resolve(__dirname, '../../current_mappings.json'); export async function readCurrentMappings(): Promise { let currentMappingsJson; diff --git a/packages/kbn-check-mappings-update-cli/src/extract_mappings_from_plugins.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/extract_mappings_from_plugins.ts similarity index 90% rename from packages/kbn-check-mappings-update-cli/src/extract_mappings_from_plugins.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/extract_mappings_from_plugins.ts index 2c2884b44633..420febc93c3b 100644 --- a/packages/kbn-check-mappings-update-cli/src/extract_mappings_from_plugins.ts +++ b/packages/kbn-check-mappings-update-cli/src/compatibility/extract_mappings_from_plugins.ts @@ -8,7 +8,6 @@ import ChildProcess from 'child_process'; import { Readable } from 'stream'; - import * as Rx from 'rxjs'; import { REPO_ROOT } from '@kbn/repo-info'; @@ -18,19 +17,13 @@ import type { SavedObjectsTypeMappingDefinitions } from '@kbn/core-saved-objects import type { Result } from './extract_mappings_from_plugins_worker'; -function routeToLog(readable: Readable, log: SomeDevLog, level: 'debug' | 'error') { - return observeLines(readable).pipe( - Rx.tap((line) => { - log[level](line); - }), - Rx.ignoreElements() - ); -} - /** * Run a worker process that starts the core with all plugins enabled and sends back the - * saved object mappings for all plugins. We run this in a child process so that we can - * harvest logs and feed them into the logger when debugging. + * saved object mappings for all plugins. + * + * We run this in a child process to make it easier to kill the kibana instance once done + * (dodges issues with open handles), and so that we can harvest logs and feed them into + * the logger when debugging. */ export async function extractMappingsFromPlugins( log: SomeDevLog @@ -78,3 +71,12 @@ export async function extractMappingsFromPlugins( return mappings; } + +function routeToLog(readable: Readable, log: SomeDevLog, level: 'debug' | 'error') { + return observeLines(readable).pipe( + Rx.tap((line) => { + log[level](line); + }), + Rx.ignoreElements() + ); +} diff --git a/packages/kbn-check-mappings-update-cli/src/extract_mappings_from_plugins_worker.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/extract_mappings_from_plugins_worker.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/extract_mappings_from_plugins_worker.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/extract_mappings_from_plugins_worker.ts diff --git a/packages/kbn-check-mappings-update-cli/src/compatibility/index.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/index.ts new file mode 100644 index 000000000000..88869c8e449f --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/compatibility/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { runMappingsCompatibilityChecks } from './run_mappings_compatibility_check'; diff --git a/packages/kbn-check-mappings-update-cli/src/mocks.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/mocks.ts similarity index 100% rename from packages/kbn-check-mappings-update-cli/src/mocks.ts rename to packages/kbn-check-mappings-update-cli/src/compatibility/mocks.ts diff --git a/packages/kbn-check-mappings-update-cli/src/compatibility/run_mappings_compatibility_check.ts b/packages/kbn-check-mappings-update-cli/src/compatibility/run_mappings_compatibility_check.ts new file mode 100644 index 000000000000..38c339dd43e5 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/compatibility/run_mappings_compatibility_check.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import deepEqual from 'fast-deep-equal'; +import { ToolingLog } from '@kbn/tooling-log'; +import { CleanupTask } from '@kbn/dev-cli-runner'; +import { createTestEsCluster } from '@kbn/test'; +import { extractMappingsFromPlugins } from './extract_mappings_from_plugins'; +import { checkAdditiveOnlyChange } from './check_additive_only_change'; +import { checkIncompatibleMappings } from './check_incompatible_mappings'; +import { readCurrentMappings, updateCurrentMappings } from './current_mappings'; + +export const runMappingsCompatibilityChecks = async ({ + fix, + verify, + log, + addCleanupTask, +}: { + fix: boolean; + verify: boolean; + log: ToolingLog; + addCleanupTask: (task: CleanupTask) => void; +}) => { + /** + * Algorithm for checking compatible mappings. Should work in CI or local + * dev environment. + * 1. Extract mappings from code as JSON object + * 2. Check if extracted mappings is different from current_mappings.json, current_mappings.json stores + * the mappings from upstream and is commited to each branch + * 3. Start a fresh ES node + * 4. Upload current_mappings.json to ES node + * 5. Upload extracted mappings.json to ES node + * 6. Check result of response to step 5, if bad response the mappings are incompatible + * 7. If good response, write extracted mappings to current_mappings.json + */ + + log.info('Extracting mappings from plugins'); + const extractedMappings = await log.indent(4, async () => { + return await extractMappingsFromPlugins(log); + }); + + const currentMappings = await readCurrentMappings(); + const isMappingChanged = !deepEqual(currentMappings, extractedMappings); + + if (!isMappingChanged) { + log.success('Mappings are unchanged.'); + return; + } + + if (verify) { + log.info('Checking if any mappings have been removed'); + await log.indent(4, async () => { + return checkAdditiveOnlyChange(log, currentMappings, extractedMappings); + }); + + log.info('Starting es...'); + const esClient = await log.indent(4, async () => { + const cluster = createTestEsCluster({ log }); + await cluster.start(); + addCleanupTask(() => cluster.cleanup()); + return cluster.getClient(); + }); + + log.info(`Checking if mappings are compatible`); + await log.indent(4, async () => { + await checkIncompatibleMappings({ + log, + esClient, + currentMappings, + nextMappings: extractedMappings, + }); + }); + } + + if (fix) { + await updateCurrentMappings(extractedMappings); + log.warning( + `Updated extracted mappings in current_mappings.json file, please commit the changes if desired.` + ); + } else { + log.warning( + `The extracted mappings do not match the current_mappings.json file, run with --fix to update.` + ); + } +}; diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/compare_type_field_lists.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/compare_type_field_lists.ts new file mode 100644 index 000000000000..b0eb2a6fd013 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/compare_type_field_lists.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { difference } from 'lodash'; + +export interface CompareResult { + error: boolean; + fieldsToAdd: string[]; + registeredFields: string[]; + missingFromModelVersion: string[]; + missingFromDefinition: string[]; +} + +export const compareFieldLists = ({ + currentFields, + registeredFields = [], + modelVersionFields = [], +}: { + currentFields: string[] | undefined; + registeredFields: string[] | undefined; + modelVersionFields: string[] | undefined; +}): CompareResult => { + // type not present in the file, so it was just added. + // in that case we just update the file to add all the registered fields. + if (!currentFields) { + return { + error: false, + registeredFields, + fieldsToAdd: registeredFields, + missingFromModelVersion: [], + missingFromDefinition: [], + }; + } + + // we search all registered/mv fields not already in the file + const registeredFieldsNotInCurrent = difference(registeredFields, currentFields); + const modelVersionFieldsNotInCurrent = difference(modelVersionFields, currentFields); + + // then we search for registered fields not in model versions, and the opposite + const registeredFieldsNotInModelVersions = difference( + registeredFieldsNotInCurrent, + modelVersionFieldsNotInCurrent + ); + const modelVersionFieldsNotRegistered = difference( + modelVersionFieldsNotInCurrent, + registeredFieldsNotInCurrent + ); + + // if any non-file field is present only in mapping definition or in model version, then there's an error on the type + const anyFieldMissing = + registeredFieldsNotInModelVersions.length > 0 || modelVersionFieldsNotRegistered.length > 0; + + return { + error: anyFieldMissing, + registeredFields, + fieldsToAdd: registeredFieldsNotInCurrent, + missingFromModelVersion: registeredFieldsNotInModelVersions, + missingFromDefinition: modelVersionFieldsNotRegistered, + }; +}; diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/current_fields.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/current_fields.ts new file mode 100644 index 000000000000..0029f4f40142 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/current_fields.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { readFile, writeFile } from 'fs/promises'; +import Path from 'path'; +import { FieldListMap } from '@kbn/core-saved-objects-base-server-internal'; + +const CURRENT_FIELDS_FILE_PATH = Path.resolve(__dirname, '../../current_fields.json'); + +export const readCurrentFields = async (): Promise => { + try { + const fileContent = await readFile(CURRENT_FIELDS_FILE_PATH, 'utf-8'); + return JSON.parse(fileContent); + } catch (error) { + if (error.code === 'ENOENT') { + return {}; + } + throw error; + } +}; + +export const writeCurrentFields = async (fieldMap: FieldListMap) => { + await writeFile(CURRENT_FIELDS_FILE_PATH, JSON.stringify(fieldMap, null, 2) + '\n', 'utf-8'); +}; diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins.ts new file mode 100644 index 000000000000..118559f63e31 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import ChildProcess from 'child_process'; +import { Readable } from 'stream'; +import * as Rx from 'rxjs'; +import { REPO_ROOT } from '@kbn/repo-info'; +import { SomeDevLog } from '@kbn/some-dev-log'; +import { observeLines } from '@kbn/stdio-dev-helpers'; +import type { Result } from './extract_field_lists_from_plugins_worker'; + +/** + * Run a worker process that starts the core with all plugins enabled and sends back the + * registered fields for all plugins. + * + * We run this in a child process to make it easier to kill the kibana instance once done + * (dodges issues with open handles), and so that we can harvest logs and feed them into + * the logger when debugging. + */ +export async function extractFieldListsFromPlugins(log: SomeDevLog): Promise { + log.info('Loading core with all plugins enabled so that we can get all savedObject mappings...'); + + const fork = ChildProcess.fork(require.resolve('./extract_field_lists_from_plugins_worker.ts'), { + execArgv: ['--require=@kbn/babel-register/install'], + cwd: REPO_ROOT, + stdio: ['ignore', 'pipe', 'pipe', 'ipc'], + }); + + const result = await Rx.firstValueFrom( + Rx.merge( + // the actual value we are interested in + Rx.fromEvent(fork, 'message'), + + // worker logs are written to the logger, but dropped from the stream + routeToLog(fork.stdout!, log, 'debug'), + routeToLog(fork.stderr!, log, 'error'), + + // if an error occurs running the worker throw it into the stream + Rx.fromEvent(fork, 'error').pipe( + Rx.map((err) => { + throw err; + }) + ) + ).pipe( + Rx.takeUntil(Rx.fromEvent(fork, 'exit')), + Rx.map((results) => { + const [outcome] = results as [Result]; + log.debug('message received from worker', outcome); + fork.kill('SIGILL'); + return outcome; + }), + Rx.defaultIfEmpty(undefined) + ) + ); + + if (!result) { + throw new Error('worker exited without sending mappings'); + } + + return result; +} + +function routeToLog(readable: Readable, log: SomeDevLog, level: 'debug' | 'error') { + return observeLines(readable).pipe( + Rx.tap((line) => { + log[level](line); + }), + Rx.ignoreElements() + ); +} diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins_worker.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins_worker.ts new file mode 100644 index 000000000000..7402e82e467c --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/extract_field_lists_from_plugins_worker.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createRootWithCorePlugins } from '@kbn/core-test-helpers-kbn-server'; +import { set } from '@kbn/safer-lodash-set'; +import { PLUGIN_SYSTEM_ENABLE_ALL_PLUGINS_CONFIG_PATH } from '@kbn/core-plugins-server-internal/src/constants'; +import { + FieldListMap, + getFieldListMapFromMappingDefinitions, + SavedObjectsTypeMappingDefinitions, +} from '@kbn/core-saved-objects-base-server-internal'; +import { getFieldListMapFromModelVersions } from './get_field_list_from_model_version'; + +export interface Result { + fieldsFromRegisteredTypes: FieldListMap; + fieldsFromModelVersions: FieldListMap; +} + +(async () => { + if (!process.send) { + throw new Error('worker must be run in a node.js fork'); + } + + const settings = { + logging: { + loggers: [{ name: 'root', level: 'info', appenders: ['console'] }], + }, + migrations: { skip: true }, + elasticsearch: { skipStartupConnectionCheck: true }, + }; + + set(settings, PLUGIN_SYSTEM_ENABLE_ALL_PLUGINS_CONFIG_PATH, true); + + const root = createRootWithCorePlugins(settings, { + basePath: false, + cache: false, + dev: true, + disableOptimizer: true, + silent: false, + dist: false, + oss: false, + runExamples: false, + watch: false, + }); + + await root.preboot(); + const { savedObjects } = await root.setup(); + const typeRegistry = savedObjects.getTypeRegistry(); + + const registeredTypes = typeRegistry.getAllTypes(); + const registeredMappings = registeredTypes.reduce( + (memo, type) => { + memo[type.name] = type.mappings; + return memo; + }, + {} + ); + + const fieldsFromRegisteredTypes = getFieldListMapFromMappingDefinitions(registeredMappings); + const fieldsFromModelVersions = getFieldListMapFromModelVersions(registeredTypes); + + const result: Result = { + fieldsFromRegisteredTypes, + fieldsFromModelVersions, + }; + process.send(result); +})().catch((error) => { + process.stderr.write(`UNHANDLED ERROR: ${error.stack}`); + process.exit(1); +}); diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/get_field_list_from_model_version.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/get_field_list_from_model_version.ts new file mode 100644 index 000000000000..278d950dcd3f --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/get_field_list_from_model_version.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SavedObjectsType } from '@kbn/core-saved-objects-server'; +import { FieldListMap, getVersionAddedFields } from '@kbn/core-saved-objects-base-server-internal'; + +const getModelVersionAddedFieldsForType = (typeDef: SavedObjectsType): string[] => { + const addedFieldSet = new Set(); + const versions = + typeof typeDef.modelVersions === 'function' + ? typeDef.modelVersions() + : typeDef.modelVersions ?? {}; + Object.values(versions).forEach((version) => { + const addedFields = getVersionAddedFields(version); + addedFields.forEach((field) => addedFieldSet.add(field)); + }); + return [...addedFieldSet].sort(); +}; + +export const getFieldListMapFromModelVersions = (types: SavedObjectsType[]): FieldListMap => { + return types.reduce((memo, type) => { + memo[type.name] = getModelVersionAddedFieldsForType(type); + return memo; + }, {}); +}; diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/index.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/index.ts new file mode 100644 index 000000000000..1b63ee3d0713 --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { runModelVersionMappingAdditionsChecks } from './run_versions_mapping_additions_check'; diff --git a/packages/kbn-check-mappings-update-cli/src/mappings_additions/run_versions_mapping_additions_check.ts b/packages/kbn-check-mappings-update-cli/src/mappings_additions/run_versions_mapping_additions_check.ts new file mode 100644 index 000000000000..b4bcc332f2dc --- /dev/null +++ b/packages/kbn-check-mappings-update-cli/src/mappings_additions/run_versions_mapping_additions_check.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog } from '@kbn/tooling-log'; +import { createFailError } from '@kbn/dev-cli-errors'; +import { FieldListMap } from '@kbn/core-saved-objects-base-server-internal'; +import { compareFieldLists, type CompareResult } from './compare_type_field_lists'; +import { readCurrentFields, writeCurrentFields } from './current_fields'; +import { extractFieldListsFromPlugins } from './extract_field_lists_from_plugins'; + +export const runModelVersionMappingAdditionsChecks = async ({ + fix, + override, + verify, + log, +}: { + fix: boolean; + override: boolean; + verify: boolean; + log: ToolingLog; +}) => { + log.info('Generating field lists from registry and file'); + const { fieldsFromRegisteredTypes, fieldsFromModelVersions } = await extractFieldListsFromPlugins( + log + ); + const currentFields = await readCurrentFields(); + + const allTypeNames = [ + ...new Set([ + ...Object.keys(fieldsFromRegisteredTypes), + ...Object.keys(currentFields), + ...Object.keys(fieldsFromModelVersions), + ]), + ]; + + log.info('Generating field delta'); + const results = allTypeNames.reduce>((memo, typeName) => { + memo[typeName] = compareFieldLists({ + registeredFields: fieldsFromRegisteredTypes[typeName], + currentFields: currentFields[typeName], + modelVersionFields: fieldsFromModelVersions[typeName], + }); + return memo; + }, {}); + + const hasError = Object.values(results).some((result) => result.error); + if (hasError) { + const errorMessage = getErrorMessage(results); + if (verify) { + throw createFailError(errorMessage + `\nUse --override --no-verify`); + } else { + log.warning(errorMessage); + } + } + + if (fix || override) { + log.info(`Updating field file with override: ${override}`); + const updatedFields = updateCurrentFields(currentFields, results, override); + await writeCurrentFields(updatedFields); + } +}; + +const getErrorMessage = (results: Record): string => { + const errors = Object.entries(results) + .filter(([_, result]) => result.error) + .reduce((memo, [typeName, result]) => { + if (result.missingFromDefinition.length) { + memo.push( + `- ${typeName}: found mappings from model version not present in mappings definition: ${result.missingFromDefinition.join( + ',' + )}` + ); + } + if (result.missingFromModelVersion.length) { + memo.push( + `- ${typeName}: found mappings from root definition not present in any model version: ${result.missingFromModelVersion.join( + ',' + )}` + ); + } + return memo; + }, []); + + return `Found issues in savedObjects mappings:\n${errors.join('\n')}`; +}; + +const updateCurrentFields = ( + currentFields: FieldListMap, + results: Record, + override: boolean +): FieldListMap => { + // mutating the field lists is fine + const updatedFields = override ? {} : { ...currentFields }; + Object.entries(results).forEach(([typeName, typeResult]) => { + if (override) { + updatedFields[typeName] = [...typeResult.registeredFields].sort(); + } else { + if (!typeResult.error) { + updatedFields[typeName] = [ + ...new Set([...(updatedFields[typeName] || []), ...typeResult.fieldsToAdd]), + ].sort(); + } + } + }); + return updatedFields; +}; diff --git a/packages/kbn-check-mappings-update-cli/src/run_check_mappings_update_cli.ts b/packages/kbn-check-mappings-update-cli/src/run_check_mappings_update_cli.ts index b1674211d61f..8ccc757324f9 100644 --- a/packages/kbn-check-mappings-update-cli/src/run_check_mappings_update_cli.ts +++ b/packages/kbn-check-mappings-update-cli/src/run_check_mappings_update_cli.ts @@ -6,95 +6,46 @@ * Side Public License, v 1. */ -import deepEqual from 'fast-deep-equal'; import { run } from '@kbn/dev-cli-runner'; -import { createTestEsCluster } from '@kbn/test'; - -import { extractMappingsFromPlugins } from './extract_mappings_from_plugins'; - -import { checkAdditiveOnlyChange } from './check_additive_only_change'; -import { checkIncompatibleMappings } from './check_incompatible_mappings'; -import { readCurrentMappings, updateCurrentMappings } from './current_mappings'; +import { runMappingsCompatibilityChecks } from './compatibility'; +import { runModelVersionMappingAdditionsChecks } from './mappings_additions'; run( async ({ log, flagsReader, addCleanupTask }) => { const fix = flagsReader.boolean('fix'); const verify = flagsReader.boolean('verify'); + const override = flagsReader.boolean('override'); + const task = flagsReader.string('task'); - /** - * Algorithm for checking compatible mappings. Should work in CI or local - * dev environment. - * 1. Extract mappings from code as JSON object - * 2. Check if extracted mappings is different from current_mappings.json, current_mappings.json stores - * the mappings from upstream and is commited to each branch - * 3. Start a fresh ES node - * 4. Upload current_mappings.json to ES node - * 5. Upload extracted mappings.json to ES node - * 6. Check result of response to step 5, if bad response the mappings are incompatible - * 7. If good response, write extracted mappings to current_mappings.json - */ - - log.info('Extracting mappings from plugins'); - const extractedMappings = await log.indent(4, async () => { - return await extractMappingsFromPlugins(log); - }); - - const currentMappings = await readCurrentMappings(); - const isMappingChanged = !deepEqual(currentMappings, extractedMappings); - - if (!isMappingChanged) { - log.success('Mappings are unchanged.'); - return; - } - - if (verify) { - log.info('Checking if any mappings have been removed'); + if (!task || task === 'mapping-addition') { + log.info('Running model version mapping addition checks'); await log.indent(4, async () => { - return checkAdditiveOnlyChange(log, currentMappings, extractedMappings); + await runModelVersionMappingAdditionsChecks({ fix, override, verify, log }); }); - - log.info('Starting es...'); - const esClient = await log.indent(4, async () => { - const cluster = createTestEsCluster({ log }); - await cluster.start(); - addCleanupTask(() => cluster.cleanup()); - return cluster.getClient(); - }); - - log.info(`Checking if mappings are compatible`); + } + if (!task || task === 'compatibility') { + log.info('Running mapping compatibility checks'); await log.indent(4, async () => { - await checkIncompatibleMappings({ - log, - esClient, - currentMappings, - nextMappings: extractedMappings, - }); + await runMappingsCompatibilityChecks({ fix, verify, log, addCleanupTask }); }); } - - if (fix) { - await updateCurrentMappings(extractedMappings); - log.warning( - `Updated extracted mappings in current_mappings.json file, please commit the changes if desired.` - ); - } else { - log.warning( - `The extracted mappings do not match the current_mappings.json file, run with --fix to update.` - ); - } }, { description: ` - Determine if the current SavedObject mappings in the source code can be applied to the current mappings from upstream. + Determine if the changes performed to the savedObjects mappings are following our standards `, flags: { - boolean: ['fix', 'verify'], + boolean: ['fix', 'override', 'verify'], + string: ['task'], default: { verify: true, + mappings: true, }, help: ` --fix If the current mappings differ from the mappings in the file, update the current_mappings.json file + --override If the current mappings differ from the mappings in the file, update the current_mappings.json file --no-verify Don't run any validation, just update the current_mappings.json file. + --task Specify which task(s) to run (compatibility | mapping-addition) `, }, } diff --git a/packages/kbn-check-mappings-update-cli/tsconfig.json b/packages/kbn-check-mappings-update-cli/tsconfig.json index 1439669b1e1d..48973be21d21 100644 --- a/packages/kbn-check-mappings-update-cli/tsconfig.json +++ b/packages/kbn-check-mappings-update-cli/tsconfig.json @@ -26,5 +26,7 @@ "@kbn/test", "@kbn/core-elasticsearch-client-server-mocks", "@kbn/safer-lodash-set", + "@kbn/tooling-log", + "@kbn/core-saved-objects-server", ] } diff --git a/packages/kbn-config/src/config_service.test.ts b/packages/kbn-config/src/config_service.test.ts index 434534f6d888..b03d407c2fcc 100644 --- a/packages/kbn-config/src/config_service.test.ts +++ b/packages/kbn-config/src/config_service.test.ts @@ -131,6 +131,23 @@ test("does not push new configs when reloading if config at path hasn't changed" expect(valuesReceived).toEqual(['value']); }); +test("does push new configs when reloading when config at path hasn't changed if ignoreUnchanged is false", async () => { + const rawConfig$ = new BehaviorSubject>({ key: 'value' }); + const rawConfigProvider = createRawConfigServiceMock({ rawConfig$ }); + + const configService = new ConfigService(rawConfigProvider, defaultEnv, logger); + await configService.setSchema('key', schema.string()); + + const valuesReceived: any[] = []; + configService.atPath('key', { ignoreUnchanged: false }).subscribe((value) => { + valuesReceived.push(value); + }); + + rawConfig$.next({ key: 'value' }); + + expect(valuesReceived).toEqual(['value', 'value']); +}); + test('pushes new config when reloading and config at path has changed', async () => { const rawConfig$ = new BehaviorSubject>({ key: 'value' }); const rawConfigProvider = createRawConfigServiceMock({ rawConfig$ }); diff --git a/packages/kbn-config/src/config_service.ts b/packages/kbn-config/src/config_service.ts index 0026876f70b4..e1c4ccfb55fb 100644 --- a/packages/kbn-config/src/config_service.ts +++ b/packages/kbn-config/src/config_service.ts @@ -10,7 +10,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { SchemaTypeError, Type, ValidationError } from '@kbn/config-schema'; import { cloneDeep, isEqual, merge } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; -import { BehaviorSubject, combineLatest, firstValueFrom, Observable } from 'rxjs'; +import { BehaviorSubject, combineLatest, firstValueFrom, Observable, identity } from 'rxjs'; import { distinctUntilChanged, first, map, shareReplay, tap } from 'rxjs/operators'; import { Logger, LoggerFactory } from '@kbn/logging'; import { getDocLinks, DocLinks } from '@kbn/doc-links'; @@ -159,9 +159,13 @@ export class ConfigService { * against its registered schema. * * @param path - The path to the desired subset of the config. + * @param ignoreUnchanged - If true (default), will not emit if the config at path did not change. */ - public atPath(path: ConfigPath) { - return this.getValidatedConfigAtPath$(path) as Observable; + public atPath( + path: ConfigPath, + { ignoreUnchanged = true }: { ignoreUnchanged?: boolean } = {} + ) { + return this.getValidatedConfigAtPath$(path, { ignoreUnchanged }) as Observable; } /** @@ -310,10 +314,13 @@ export class ConfigService { ); } - private getValidatedConfigAtPath$(path: ConfigPath) { + private getValidatedConfigAtPath$( + path: ConfigPath, + { ignoreUnchanged = true }: { ignoreUnchanged?: boolean } = {} + ) { return this.config$.pipe( map((config) => config.get(path)), - distinctUntilChanged(isEqual), + ignoreUnchanged ? distinctUntilChanged(isEqual) : identity, map((config) => this.validateAtPath(path, config)) ); } diff --git a/packages/kbn-custom-icons/.storybook/main.js b/packages/kbn-custom-icons/.storybook/main.js new file mode 100644 index 000000000000..8dc3c5d1518f --- /dev/null +++ b/packages/kbn-custom-icons/.storybook/main.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/packages/kbn-custom-icons/README.md b/packages/kbn-custom-icons/README.md new file mode 100644 index 000000000000..ec48e8b8558c --- /dev/null +++ b/packages/kbn-custom-icons/README.md @@ -0,0 +1,29 @@ +# @kbn/custom-icons + +A utility package, `@kbn/custom-icons`, that provides components for rendering icons related to Elastic Agents, Cloud Providers and more. + +## Components + +### `` + +```jsx + +``` + +This component renders an icon corresponding to the specified Elastic Agent name (`agentName`). + +#### Props + +- **`agentName`**: The name of the Elastic Agent for which the icon should be rendered. + +### `` + +```jsx + +``` + +This component renders an icon associated with the specified Cloud Provider (`cloudProvider`). + +#### Props + +- **`cloudProvider`**: The name of the Cloud Provider for which the icon should be rendered. diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/android.svg b/packages/kbn-custom-icons/assets/android.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/android.svg rename to packages/kbn-custom-icons/assets/android.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/cpp.svg b/packages/kbn-custom-icons/assets/cpp.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/cpp.svg rename to packages/kbn-custom-icons/assets/cpp.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/cpp_dark.svg b/packages/kbn-custom-icons/assets/cpp_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/cpp_dark.svg rename to packages/kbn-custom-icons/assets/cpp_dark.svg diff --git a/packages/kbn-custom-icons/assets/default.svg b/packages/kbn-custom-icons/assets/default.svg new file mode 100644 index 000000000000..08bc5331e083 --- /dev/null +++ b/packages/kbn-custom-icons/assets/default.svg @@ -0,0 +1,3 @@ + + + diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/dot_net.svg b/packages/kbn-custom-icons/assets/dot_net.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/dot_net.svg rename to packages/kbn-custom-icons/assets/dot_net.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/erlang.svg b/packages/kbn-custom-icons/assets/erlang.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/erlang.svg rename to packages/kbn-custom-icons/assets/erlang.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/erlang_dark.svg b/packages/kbn-custom-icons/assets/erlang_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/erlang_dark.svg rename to packages/kbn-custom-icons/assets/erlang_dark.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/functions.svg b/packages/kbn-custom-icons/assets/functions.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/functions.svg rename to packages/kbn-custom-icons/assets/functions.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/go.svg b/packages/kbn-custom-icons/assets/go.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/go.svg rename to packages/kbn-custom-icons/assets/go.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/ios.svg b/packages/kbn-custom-icons/assets/ios.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/ios.svg rename to packages/kbn-custom-icons/assets/ios.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/ios_dark.svg b/packages/kbn-custom-icons/assets/ios_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/ios_dark.svg rename to packages/kbn-custom-icons/assets/ios_dark.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/java.svg b/packages/kbn-custom-icons/assets/java.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/java.svg rename to packages/kbn-custom-icons/assets/java.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/lambda.svg b/packages/kbn-custom-icons/assets/lambda.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/lambda.svg rename to packages/kbn-custom-icons/assets/lambda.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/nodejs.svg b/packages/kbn-custom-icons/assets/nodejs.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/nodejs.svg rename to packages/kbn-custom-icons/assets/nodejs.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/ocaml.svg b/packages/kbn-custom-icons/assets/ocaml.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/ocaml.svg rename to packages/kbn-custom-icons/assets/ocaml.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/opentelemetry.svg b/packages/kbn-custom-icons/assets/opentelemetry.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/opentelemetry.svg rename to packages/kbn-custom-icons/assets/opentelemetry.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/otel_default.svg b/packages/kbn-custom-icons/assets/otel_default.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/otel_default.svg rename to packages/kbn-custom-icons/assets/otel_default.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/php.svg b/packages/kbn-custom-icons/assets/php.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/php.svg rename to packages/kbn-custom-icons/assets/php.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/php_dark.svg b/packages/kbn-custom-icons/assets/php_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/php_dark.svg rename to packages/kbn-custom-icons/assets/php_dark.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/python.svg b/packages/kbn-custom-icons/assets/python.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/python.svg rename to packages/kbn-custom-icons/assets/python.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/ruby.svg b/packages/kbn-custom-icons/assets/ruby.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/ruby.svg rename to packages/kbn-custom-icons/assets/ruby.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/rumjs.svg b/packages/kbn-custom-icons/assets/rumjs.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/rumjs.svg rename to packages/kbn-custom-icons/assets/rumjs.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/rumjs_dark.svg b/packages/kbn-custom-icons/assets/rumjs_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/rumjs_dark.svg rename to packages/kbn-custom-icons/assets/rumjs_dark.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/rust.svg b/packages/kbn-custom-icons/assets/rust.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/rust.svg rename to packages/kbn-custom-icons/assets/rust.svg diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/icons/rust_dark.svg b/packages/kbn-custom-icons/assets/rust_dark.svg similarity index 100% rename from x-pack/plugins/apm/public/components/shared/agent_icon/icons/rust_dark.svg rename to packages/kbn-custom-icons/assets/rust_dark.svg diff --git a/packages/kbn-custom-icons/index.ts b/packages/kbn-custom-icons/index.ts new file mode 100644 index 000000000000..d6bc468b6652 --- /dev/null +++ b/packages/kbn-custom-icons/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export { getAgentIcon } from './src/components/agent_icon/get_agent_icon'; +export { getServerlessIcon } from './src/components/agent_icon/get_serverless_icon'; +export { AgentIcon } from './src/components/agent_icon'; +export type { AgentIconProps } from './src/components/agent_icon'; + +export { getCloudProviderIcon } from './src/components/cloud_provider_icon/get_cloud_provider_icon'; +export type { CloudProvider } from './src/components/cloud_provider_icon/get_cloud_provider_icon'; +export { CloudProviderIcon } from './src/components/cloud_provider_icon'; +export type { CloudProviderIconProps } from './src/components/cloud_provider_icon'; diff --git a/packages/kbn-custom-icons/jest.config.js b/packages/kbn-custom-icons/jest.config.js new file mode 100644 index 000000000000..518564ce1dbb --- /dev/null +++ b/packages/kbn-custom-icons/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-custom-icons'], +}; diff --git a/packages/kbn-custom-icons/kibana.jsonc b/packages/kbn-custom-icons/kibana.jsonc new file mode 100644 index 000000000000..7bd9eaa57e87 --- /dev/null +++ b/packages/kbn-custom-icons/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/custom-icons", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/packages/kbn-custom-icons/package.json b/packages/kbn-custom-icons/package.json new file mode 100644 index 000000000000..d6952600c0af --- /dev/null +++ b/packages/kbn-custom-icons/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/custom-icons", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "sideEffects": false +} \ No newline at end of file diff --git a/packages/kbn-custom-icons/src/components/agent_icon/agent_icon.stories.tsx b/packages/kbn-custom-icons/src/components/agent_icon/agent_icon.stories.tsx new file mode 100644 index 000000000000..45ba59137a6c --- /dev/null +++ b/packages/kbn-custom-icons/src/components/agent_icon/agent_icon.stories.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiImage, EuiToolTip } from '@elastic/eui'; +import type { Story } from '@storybook/react'; +import React from 'react'; +import { AGENT_NAMES } from '@kbn/elastic-agent-utils'; +import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { getAgentIcon } from './get_agent_icon'; +import { AgentIcon } from '.'; + +export default { + title: 'Custom Icons/AgentIcon', + component: AgentIcon, +}; + +export const List: Story = () => { + return ( + + + {AGENT_NAMES.map((agentName) => { + return ( + + + + + } + title={agentName} + description={ + + + + } + /> + + ); + })} + + + ); +}; diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.test.ts b/packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.test.ts similarity index 86% rename from x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.test.ts rename to packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.test.ts index aac5fc19ca37..58dff1afb109 100644 --- a/x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.test.ts +++ b/packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.test.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { getAgentIconKey } from './get_agent_icon'; diff --git a/packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts b/packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts new file mode 100644 index 000000000000..7c37f1a86a05 --- /dev/null +++ b/packages/kbn-custom-icons/src/components/agent_icon/get_agent_icon.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { + isAndroidAgentName, + isIosAgentName, + isJavaAgentName, + isRumAgentName, + OpenTelemetryAgentName, + OPEN_TELEMETRY_AGENT_NAMES, +} from '@kbn/elastic-agent-utils'; +import defaultIcon from '../../../assets/default.svg'; +import cppIcon from '../../../assets/cpp.svg'; +import darkCppIcon from '../../../assets/cpp_dark.svg'; +import dotNetIcon from '../../../assets/dot_net.svg'; +import erlangIcon from '../../../assets/erlang.svg'; +import darkErlangIcon from '../../../assets/erlang_dark.svg'; +import goIcon from '../../../assets/go.svg'; +import iosIcon from '../../../assets/ios.svg'; +import darkIosIcon from '../../../assets/ios_dark.svg'; +import javaIcon from '../../../assets/java.svg'; +import nodeJsIcon from '../../../assets/nodejs.svg'; +import ocamlIcon from '../../../assets/ocaml.svg'; +import openTelemetryIcon from '../../../assets/otel_default.svg'; +import phpIcon from '../../../assets/php.svg'; +import pythonIcon from '../../../assets/python.svg'; +import rubyIcon from '../../../assets/ruby.svg'; +import rumJsIcon from '../../../assets/rumjs.svg'; +import darkPhpIcon from '../../../assets/php_dark.svg'; +import darkRumJsIcon from '../../../assets/rumjs_dark.svg'; +import rustIcon from '../../../assets/rust.svg'; +import darkRustIcon from '../../../assets/rust_dark.svg'; +import androidIcon from '../../../assets/android.svg'; + +const agentIcons: { [key: string]: string } = { + cpp: cppIcon, + dotnet: dotNetIcon, + erlang: erlangIcon, + go: goIcon, + ios: iosIcon, + java: javaIcon, + nodejs: nodeJsIcon, + ocaml: ocamlIcon, + opentelemetry: openTelemetryIcon, + php: phpIcon, + python: pythonIcon, + ruby: rubyIcon, + rum: rumJsIcon, + rust: rustIcon, + android: androidIcon, +}; + +const darkAgentIcons: { [key: string]: string } = { + ...agentIcons, + cpp: darkCppIcon, + erlang: darkErlangIcon, + ios: darkIosIcon, + php: darkPhpIcon, + rum: darkRumJsIcon, + rust: darkRustIcon, +}; + +// This only needs to be exported for testing purposes, since we stub the SVG +// import values in test. +export function getAgentIconKey(agentName: string) { + // Ignore case + const lowercasedAgentName = agentName.toLowerCase(); + + // RUM agent names + if (isRumAgentName(lowercasedAgentName)) { + return 'rum'; + } + + // Java agent names + if (isJavaAgentName(lowercasedAgentName)) { + return 'java'; + } + + if (isIosAgentName(lowercasedAgentName)) { + return 'ios'; + } + + if (isAndroidAgentName(lowercasedAgentName)) { + return 'android'; + } + + // Remove "opentelemetry/" prefix + const agentNameWithoutPrefix = lowercasedAgentName.replace(/^opentelemetry\//, ''); + + if (Object.keys(agentIcons).includes(agentNameWithoutPrefix)) { + return agentNameWithoutPrefix; + } + + // OpenTelemetry-only agents + if (OPEN_TELEMETRY_AGENT_NAMES.includes(lowercasedAgentName as OpenTelemetryAgentName)) { + return 'opentelemetry'; + } +} + +export function getAgentIcon(agentName: string | undefined, isDarkMode: boolean = false) { + const key = agentName && getAgentIconKey(agentName); + if (!key) { + return defaultIcon; + } + return (isDarkMode ? darkAgentIcons[key] : agentIcons[key]) ?? defaultIcon; +} diff --git a/packages/kbn-custom-icons/src/components/agent_icon/get_serverless_icon.ts b/packages/kbn-custom-icons/src/components/agent_icon/get_serverless_icon.ts new file mode 100644 index 000000000000..26268d3c7dce --- /dev/null +++ b/packages/kbn-custom-icons/src/components/agent_icon/get_serverless_icon.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { ServerlessType } from '@kbn/elastic-agent-utils'; +import defaultIcon from '../../../assets/default.svg'; +import lambdaIcon from '../../../assets/lambda.svg'; +import azureFunctionsIcon from '../../../assets/functions.svg'; + +const serverlessIcons: Record = { + 'aws.lambda': lambdaIcon, + 'azure.functions': azureFunctionsIcon, +} as const; + +export function getServerlessIcon(serverlessType?: ServerlessType) { + if (!serverlessType) { + return defaultIcon; + } + return serverlessIcons[serverlessType] ?? defaultIcon; +} diff --git a/packages/kbn-custom-icons/src/components/agent_icon/index.tsx b/packages/kbn-custom-icons/src/components/agent_icon/index.tsx new file mode 100644 index 000000000000..bd34aa7f3a32 --- /dev/null +++ b/packages/kbn-custom-icons/src/components/agent_icon/index.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiIcon, EuiIconProps, useEuiTheme } from '@elastic/eui'; +import { AgentName } from '@kbn/elastic-agent-utils'; +import { getAgentIcon } from './get_agent_icon'; + +export interface AgentIconProps extends Omit { + agentName?: AgentName; +} + +export function AgentIcon({ agentName, size = 'l', ...props }: AgentIconProps) { + const theme = useEuiTheme(); + const icon = getAgentIcon(agentName, theme.colorMode === 'DARK'); + + return ; +} diff --git a/packages/kbn-custom-icons/src/components/cloud_provider_icon/cloud_provider_icon.stories.tsx b/packages/kbn-custom-icons/src/components/cloud_provider_icon/cloud_provider_icon.stories.tsx new file mode 100644 index 000000000000..e84e865fb55f --- /dev/null +++ b/packages/kbn-custom-icons/src/components/cloud_provider_icon/cloud_provider_icon.stories.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import type { Story } from '@storybook/react'; +import React from 'react'; +import { CloudProviderIcon } from '.'; +import { CloudProvider } from './get_cloud_provider_icon'; + +export default { + title: 'Custom Icons/CloudProviderIcon', + component: CloudProviderIcon, +}; + +const providers: CloudProvider[] = ['gcp', 'aws', 'azure', 'unknownProvider']; + +export const List: Story = () => { + return ( + + {providers.map((cloudProvider) => { + return ( + + + + + } + /> + + ); + })} + + ); +}; diff --git a/packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts b/packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts new file mode 100644 index 000000000000..7c4bcd2ec3f7 --- /dev/null +++ b/packages/kbn-custom-icons/src/components/cloud_provider_icon/get_cloud_provider_icon.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +const CLOUD_PROVIDER_ICONS = { + gcp: 'logoGCP', + aws: 'logoAWS', + azure: 'logoAzure', + unknownProvider: 'cloudSunny', +} as const; + +export type CloudProvider = keyof typeof CLOUD_PROVIDER_ICONS | null | undefined; + +export function getCloudProviderIcon(cloudProvider?: CloudProvider) { + if (cloudProvider === undefined || cloudProvider === null) { + return CLOUD_PROVIDER_ICONS.unknownProvider; + } + + return CLOUD_PROVIDER_ICONS[cloudProvider]; +} diff --git a/packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx b/packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx new file mode 100644 index 000000000000..bf90704e4f64 --- /dev/null +++ b/packages/kbn-custom-icons/src/components/cloud_provider_icon/index.tsx @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiIcon, EuiIconProps } from '@elastic/eui'; +import { CloudProvider, getCloudProviderIcon } from './get_cloud_provider_icon'; + +export interface CloudProviderIconProps extends Omit { + cloudProvider?: CloudProvider; +} + +export function CloudProviderIcon({ cloudProvider, ...props }: CloudProviderIconProps) { + const computedProps: Pick = { + type: getCloudProviderIcon(cloudProvider), + }; + + if (cloudProvider) computedProps.title = cloudProvider; + + return ; +} diff --git a/packages/kbn-custom-icons/tsconfig.json b/packages/kbn-custom-icons/tsconfig.json new file mode 100644 index 000000000000..5cd845d4948c --- /dev/null +++ b/packages/kbn-custom-icons/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@kbn/ambient-ui-types" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/elastic-agent-utils", + "@kbn/kibana-react-plugin" + ] +} diff --git a/packages/kbn-discover-utils/src/__mocks__/data_view.ts b/packages/kbn-discover-utils/src/__mocks__/data_view.ts index 66e2803cdd23..b7a365c8b674 100644 --- a/packages/kbn-discover-utils/src/__mocks__/data_view.ts +++ b/packages/kbn-discover-utils/src/__mocks__/data_view.ts @@ -108,7 +108,7 @@ export const buildDataViewMock = ({ fields: dataViewFields, type: 'default', getName: () => name, - getComputedFields: () => ({ docvalueFields: [], scriptFields: {}, storedFields: ['*'] }), + getComputedFields: () => ({ docvalueFields: [], scriptFields: {} }), getSourceFiltering: () => ({}), getIndexPattern: () => `${name}-title`, getFieldByName: jest.fn((fieldName: string) => dataViewFields.getByName(fieldName)), diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 9e0d380c2f01..dca7c0871f08 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -187,7 +187,6 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { machineLearningStart: `${ELASTICSEARCH_DOCS}nlp-example.html`, mailService: `${ENTERPRISE_SEARCH_DOCS}mailer-configuration.html`, mlDocumentEnrichment: `${ELASTICSEARCH_DOCS}ingest-pipeline-search-inference.html`, - mlDocumentEnrichmentUpdateMappings: `${ELASTICSEARCH_DOCS}ingest-pipeline-search-inference.html#ingest-pipeline-search-inference-update-mapping`, searchApplicationsTemplates: `${ELASTICSEARCH_DOCS}search-application-api.html`, searchApplicationsSearchApi: `${ELASTICSEARCH_DOCS}search-application-security.html`, searchApplications: `${ELASTICSEARCH_DOCS}search-application-overview.html`, @@ -459,6 +458,12 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { privileges: `${SECURITY_SOLUTION_DOCS}endpoint-management-req.html`, manageDetectionRules: `${SECURITY_SOLUTION_DOCS}rules-ui-management.html`, createEsqlRuleType: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#create-esql-rule`, + entityAnalytics: { + riskScorePrerequisites: `${SECURITY_SOLUTION_DOCS}ers-requirements.html`, + hostRiskScore: `${SECURITY_SOLUTION_DOCS}host-risk-score.html`, + userRiskScore: `${SECURITY_SOLUTION_DOCS}user-risk-score.html`, + entityRiskScoring: `${SECURITY_SOLUTION_DOCS}advanced-entity-analytics-overview.html#entity-risk-scoring`, + }, }, query: { eql: `${ELASTICSEARCH_DOCS}eql.html`, @@ -518,6 +523,8 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { trainedModels: `${MACHINE_LEARNING_DOCS}ml-trained-models.html`, startTrainedModelsDeployment: `${MACHINE_LEARNING_DOCS}ml-nlp-deploy-model.html`, nlpElser: `${MACHINE_LEARNING_DOCS}ml-nlp-elser.html`, + nlpE5: `${MACHINE_LEARNING_DOCS}ml-nlp-e5.html`, + nlpImportModel: `${MACHINE_LEARNING_DOCS}ml-nlp-import-model.html`, }, transforms: { guide: `${ELASTICSEARCH_DOCS}transforms.html`, @@ -769,6 +776,8 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { uninstallAgent: `${SECURITY_SOLUTION_DOCS}uninstall-agent.html`, installAndUninstallIntegrationAssets: `${FLEET_DOCS}install-uninstall-integration-assets.html`, elasticAgentInputConfiguration: `${FLEET_DOCS}elastic-agent-input-configuration.html`, + policySecrets: `${FLEET_DOCS}agent-policy.html#agent-policy-secret-values`, + remoteESOoutput: `${FLEET_DOCS}monitor-elastic-agent.html#external-elasticsearch-monitoring`, }, ecs: { guide: `${ELASTIC_WEBSITE_URL}guide/en/ecs/current/index.html`, @@ -811,6 +820,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { rubyOverview: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/client/ruby-api/${DOC_LINK_VERSION}/ruby_client.html`, rustGuide: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/client/rust-api/${DOC_LINK_VERSION}/index.html`, rustOverview: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/client/rust-api/${DOC_LINK_VERSION}/overview.html`, + eland: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/client/eland/${DOC_LINK_VERSION}/index.html`, }, endpoints: { troubleshooting: `${SECURITY_SOLUTION_DOCS}ts-management.html#ts-endpoints`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 37974c9244b7..85d540cb70ca 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -168,7 +168,6 @@ export interface DocLinks { readonly machineLearningStart: string; readonly mailService: string; readonly mlDocumentEnrichment: string; - readonly mlDocumentEnrichmentUpdateMappings: string; readonly searchApplicationsTemplates: string; readonly searchApplicationsSearchApi: string; readonly searchApplications: string; @@ -350,6 +349,12 @@ export interface DocLinks { readonly privileges: string; readonly manageDetectionRules: string; readonly createEsqlRuleType: string; + readonly entityAnalytics: { + readonly riskScorePrerequisites: string; + readonly hostRiskScore: string; + readonly userRiskScore: string; + readonly entityRiskScoring: string; + }; }; readonly query: { readonly eql: string; @@ -527,6 +532,8 @@ export interface DocLinks { uninstallAgent: string; installAndUninstallIntegrationAssets: string; elasticAgentInputConfiguration: string; + policySecrets: string; + remoteESOoutput: string; }>; readonly ecs: { readonly guide: string; @@ -568,6 +575,7 @@ export interface DocLinks { readonly rubyOverview: string; readonly rustGuide: string; readonly rustOverview: string; + readonly eland: string; }; readonly endpoints: { readonly troubleshooting: string; diff --git a/packages/kbn-elastic-agent-utils/README.md b/packages/kbn-elastic-agent-utils/README.md new file mode 100644 index 000000000000..f5b99bf1b159 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/README.md @@ -0,0 +1,141 @@ +# @kbn/elastic-agent-utils + +A utility package providing functions for working with Elastic Agents. This package focuses on agent names used in various contexts, such as OpenTelemetry, Java, Rum (Real User Monitoring), Mobile, JRuby, and Serverless environments. + +## Functions + +- **`isOpenTelemetryAgentName`** + + ```typescript + export function isOpenTelemetryAgentName(agentName: string): agentName is OpenTelemetryAgentName; + ``` + + Check if the provided agent name is part of the OpenTelemetry agents. + +- **`isJavaAgentName`** + + ```typescript + export function isJavaAgentName(agentName?: string): agentName is JavaAgentName; + ``` + + Check if the provided agent name is part of the Java agents. + +- **`isRumAgentName`** + + ```typescript + export function isRumAgentName(agentName?: string): agentName is RumAgentName; + ``` + + Check if the provided agent name is part of the Rum (Real User Monitoring) agents. + +- **`isMobileAgentName`** + + ```typescript + export function isMobileAgentName(agentName?: string): boolean; + ``` + + Check if the provided agent name is either an iOS or Android agent. + +- **`isRumOrMobileAgentName`** + + ```typescript + export function isRumOrMobileAgentName(agentName?: string): boolean; + ``` + + Check if the provided agent name is either a Rum agent or a Mobile agent. + +- **`isIosAgentName`** + + ```typescript + export function isIosAgentName(agentName?: string): boolean; + ``` + + Check if the provided agent name is "ios/swift." + +- **`isAndroidAgentName`** + + ```typescript + export function isAndroidAgentName(agentName?: string): boolean; + ``` + + Check if the provided agent name is "android/java." + +- **`isJRubyAgentName`** + + ```typescript + export function isJRubyAgentName(agentName?: string, runtimeName?: string): boolean; + ``` + + Check if the provided agent name is "ruby" and the runtime name is "jruby." + +- **`isServerlessAgentName`** + + ```typescript + export function isServerlessAgentName(serverlessType?: string): serverlessType is ServerlessType; + ``` + + Check if the provided serverless type is part of the supported Serverless environments. + +- **`isAWSLambdaAgentName`** + + ```typescript + export function isAWSLambdaAgentName(serverlessType?: string): serverlessType is ServerlessType; + ``` + + Check if the provided serverless type is "aws.lambda." + +- **`isAzureFunctionsAgentName`** + + ```typescript + export function isAzureFunctionsAgentName( + serverlessType?: string + ): serverlessType is ServerlessType; + ``` + + Check if the provided serverless type is "azure.functions." + +## Additional Exports + +The `@kbn/elastic-agent-utils` package also exports several constants and types for commonly used agent names. These exports can be utilized for broader categorizations and validations within your Elastic Agent projects. + +### Agent Names Constants + +- **`ELASTIC_AGENT_NAMES`** + + An array of Elastic Agent names, including various programming languages and platforms. + +- **`OPEN_TELEMETRY_AGENT_NAMES`** + + An array of OpenTelemetry agent names, covering different languages and platforms supporting OpenTelemetry. + +- **`JAVA_AGENT_NAMES`** + + An array of Java agent names, including both generic Java and OpenTelemetry Java agents. + +- **`RUM_AGENT_NAMES`** + + An array of Real User Monitoring (RUM) agent names, encompassing both base JavaScript and specific RUM agents. + +- **`SERVERLESS_TYPE`** + + An array of supported Serverless types, including AWS Lambda and Azure Functions. + +### Agent Name Types + +- **`ElasticAgentName`** +- **`OpenTelemetryAgentName`** +- **`JavaAgentName`** +- **`RumAgentName`** +- **`ServerlessType`** + + These types represent the available agent name categories, providing TypeScript type safety for agent name usage. + +### Combined Agent Names + +- **`AgentName`** + + A union type combining all agent name categories. + +- **`AGENT_NAMES`** + + An array containing all available agent names from the combined categories. diff --git a/packages/kbn-elastic-agent-utils/index.ts b/packages/kbn-elastic-agent-utils/index.ts new file mode 100644 index 000000000000..62e7a6cd5968 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/index.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export { + isOpenTelemetryAgentName, + isJavaAgentName, + isRumAgentName, + isMobileAgentName, + isRumOrMobileAgentName, + isIosAgentName, + isAndroidAgentName, + isJRubyAgentName, + isServerlessAgentName, + isAWSLambdaAgentName, + isAzureFunctionsAgentName, +} from './src/agent_guards'; + +export { + ELASTIC_AGENT_NAMES, + OPEN_TELEMETRY_AGENT_NAMES, + JAVA_AGENT_NAMES, + RUM_AGENT_NAMES, + SERVERLESS_TYPE, + AGENT_NAMES, +} from './src/agent_names'; + +export type { + ElasticAgentName, + OpenTelemetryAgentName, + JavaAgentName, + RumAgentName, + ServerlessType, + AgentName, +} from './src/agent_names'; diff --git a/packages/kbn-elastic-agent-utils/jest.config.js b/packages/kbn-elastic-agent-utils/jest.config.js new file mode 100644 index 000000000000..787036bd78da --- /dev/null +++ b/packages/kbn-elastic-agent-utils/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-elastic-agent-utils'], +}; diff --git a/packages/kbn-elastic-agent-utils/kibana.jsonc b/packages/kbn-elastic-agent-utils/kibana.jsonc new file mode 100644 index 000000000000..cf8dc4c03f59 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/elastic-agent-utils", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/packages/kbn-elastic-agent-utils/package.json b/packages/kbn-elastic-agent-utils/package.json new file mode 100644 index 000000000000..df029eb7db2d --- /dev/null +++ b/packages/kbn-elastic-agent-utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/elastic-agent-utils", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-elastic-agent-utils/src/agent_guards.test.ts b/packages/kbn-elastic-agent-utils/src/agent_guards.test.ts new file mode 100644 index 000000000000..0de2ea225ce8 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/src/agent_guards.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + isAndroidAgentName, + isAWSLambdaAgentName, + isAzureFunctionsAgentName, + isIosAgentName, + isJavaAgentName, + isJRubyAgentName, + isMobileAgentName, + isOpenTelemetryAgentName, + isRumAgentName, + isRumOrMobileAgentName, + isServerlessAgentName, +} from './agent_guards'; + +describe('Agents guards', () => { + it('isOpenTelemetryAgentName should guard if the passed agent is an OpenTelemetry one.', () => { + expect(isOpenTelemetryAgentName('otlp')).toBe(true); + expect(isOpenTelemetryAgentName('not-an-agent')).toBe(false); + }); + + it('isJavaAgentName should guard if the passed agent is an Java one.', () => { + expect(isJavaAgentName('java')).toBe(true); + expect(isJavaAgentName('not-an-agent')).toBe(false); + }); + + it('isRumAgentName should guard if the passed agent is an Rum one.', () => { + expect(isRumAgentName('rum-js')).toBe(true); + expect(isRumAgentName('not-an-agent')).toBe(false); + }); + + it('isMobileAgentName should guard if the passed agent is an Mobile one.', () => { + expect(isMobileAgentName('ios/swift')).toBe(true); + expect(isMobileAgentName('android/java')).toBe(true); + expect(isMobileAgentName('not-an-agent')).toBe(false); + }); + + it('isRumOrMobileAgentName should guard if the passed agent is an RumOrMobile one.', () => { + expect(isRumOrMobileAgentName('ios/swift')).toBe(true); + expect(isRumOrMobileAgentName('android/java')).toBe(true); + expect(isRumOrMobileAgentName('rum-js')).toBe(true); + expect(isRumOrMobileAgentName('not-an-agent')).toBe(false); + }); + + it('isIosAgentName should guard if the passed agent is an Ios one.', () => { + expect(isIosAgentName('ios/swift')).toBe(true); + expect(isIosAgentName('not-an-agent')).toBe(false); + }); + + it('isAndroidAgentName should guard if the passed agent is an Android one.', () => { + expect(isAndroidAgentName('android/java')).toBe(true); + expect(isAndroidAgentName('not-an-agent')).toBe(false); + }); + + it('isJRubyAgentName should guard if the passed agent is an JRuby one.', () => { + expect(isJRubyAgentName('ruby', 'jruby')).toBe(true); + expect(isJRubyAgentName('ruby')).toBe(false); + expect(isJRubyAgentName('not-an-agent')).toBe(false); + }); + + it('isServerlessAgentName should guard if the passed agent is an Serverless one.', () => { + expect(isServerlessAgentName('aws.lambda')).toBe(true); + expect(isServerlessAgentName('azure.functions')).toBe(true); + expect(isServerlessAgentName('not-an-agent')).toBe(false); + }); + + it('isAWSLambdaAgentName should guard if the passed agent is an AWSLambda one.', () => { + expect(isAWSLambdaAgentName('aws.lambda')).toBe(true); + expect(isAWSLambdaAgentName('not-an-agent')).toBe(false); + }); + + it('isAzureFunctionsAgentName should guard if the passed agent is an AzureFunctions one.', () => { + expect(isAzureFunctionsAgentName('azure.functions')).toBe(true); + expect(isAzureFunctionsAgentName('not-an-agent')).toBe(false); + }); +}); diff --git a/packages/kbn-elastic-agent-utils/src/agent_guards.ts b/packages/kbn-elastic-agent-utils/src/agent_guards.ts new file mode 100644 index 000000000000..6997cbd81c42 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/src/agent_guards.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { JAVA_AGENT_NAMES, OPEN_TELEMETRY_AGENT_NAMES, RUM_AGENT_NAMES } from './agent_names'; + +import type { + JavaAgentName, + OpenTelemetryAgentName, + RumAgentName, + ServerlessType, +} from './agent_names'; + +export function isOpenTelemetryAgentName(agentName: string): agentName is OpenTelemetryAgentName { + return OPEN_TELEMETRY_AGENT_NAMES.includes(agentName as OpenTelemetryAgentName); +} + +export function isJavaAgentName(agentName?: string): agentName is JavaAgentName { + return JAVA_AGENT_NAMES.includes(agentName! as JavaAgentName); +} + +export function isRumAgentName(agentName?: string): agentName is RumAgentName { + return RUM_AGENT_NAMES.includes(agentName! as RumAgentName); +} + +export function isMobileAgentName(agentName?: string) { + return isIosAgentName(agentName) || isAndroidAgentName(agentName); +} + +export function isRumOrMobileAgentName(agentName?: string) { + return isRumAgentName(agentName) || isMobileAgentName(agentName); +} + +export function isIosAgentName(agentName?: string) { + return agentName?.toLowerCase() === 'ios/swift'; +} + +export function isAndroidAgentName(agentName?: string) { + const lowercased = agentName && agentName.toLowerCase(); + return lowercased === 'android/java'; +} + +export function isJRubyAgentName(agentName?: string, runtimeName?: string) { + return agentName === 'ruby' && runtimeName?.toLowerCase() === 'jruby'; +} + +export function isServerlessAgentName(serverlessType?: string): serverlessType is ServerlessType { + return isAWSLambdaAgentName(serverlessType) || isAzureFunctionsAgentName(serverlessType); +} + +export function isAWSLambdaAgentName(serverlessType?: string): serverlessType is ServerlessType { + return serverlessType === 'aws.lambda'; +} + +export function isAzureFunctionsAgentName( + serverlessType?: string +): serverlessType is ServerlessType { + return serverlessType === 'azure.functions'; +} diff --git a/packages/kbn-elastic-agent-utils/src/agent_names.ts b/packages/kbn-elastic-agent-utils/src/agent_names.ts new file mode 100644 index 000000000000..f29160699a24 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/src/agent_names.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * We cannot mark these arrays as const and derive their type + * because we need to be able to assign them as mutable entities for ES queries. + */ +export type ElasticAgentName = + | 'dotnet' + | 'go' + | 'iOS/swift' + | 'java' + | 'js-base' + | 'nodejs' + | 'php' + | 'python' + | 'ruby' + | 'rum-js' + | 'android/java'; +export const ELASTIC_AGENT_NAMES: ElasticAgentName[] = [ + 'dotnet', + 'go', + 'iOS/swift', + 'java', + 'js-base', + 'nodejs', + 'php', + 'python', + 'ruby', + 'rum-js', + 'android/java', +]; + +export type OpenTelemetryAgentName = + | 'otlp' + | 'opentelemetry/cpp' + | 'opentelemetry/dotnet' + | 'opentelemetry/erlang' + | 'opentelemetry/go' + | 'opentelemetry/java' + | 'opentelemetry/nodejs' + | 'opentelemetry/php' + | 'opentelemetry/python' + | 'opentelemetry/ruby' + | 'opentelemetry/rust' + | 'opentelemetry/swift' + | 'opentelemetry/webjs'; +export const OPEN_TELEMETRY_AGENT_NAMES: OpenTelemetryAgentName[] = [ + 'otlp', + 'opentelemetry/cpp', + 'opentelemetry/dotnet', + 'opentelemetry/erlang', + 'opentelemetry/go', + 'opentelemetry/java', + 'opentelemetry/nodejs', + 'opentelemetry/php', + 'opentelemetry/python', + 'opentelemetry/ruby', + 'opentelemetry/rust', + 'opentelemetry/swift', + 'opentelemetry/webjs', +]; + +export type JavaAgentName = 'java' | 'opentelemetry/java'; +export const JAVA_AGENT_NAMES: JavaAgentName[] = ['java', 'opentelemetry/java']; + +export type RumAgentName = 'js-base' | 'rum-js' | 'opentelemetry/webjs'; +export const RUM_AGENT_NAMES: RumAgentName[] = ['js-base', 'rum-js', 'opentelemetry/webjs']; + +export type ServerlessType = 'aws.lambda' | 'azure.functions'; +export const SERVERLESS_TYPE: ServerlessType[] = ['aws.lambda', 'azure.functions']; + +export type AgentName = ElasticAgentName | OpenTelemetryAgentName | JavaAgentName | RumAgentName; +export const AGENT_NAMES: AgentName[] = [ + ...ELASTIC_AGENT_NAMES, + ...OPEN_TELEMETRY_AGENT_NAMES, + ...JAVA_AGENT_NAMES, + ...RUM_AGENT_NAMES, +]; diff --git a/packages/kbn-elastic-agent-utils/tsconfig.json b/packages/kbn-elastic-agent-utils/tsconfig.json new file mode 100644 index 000000000000..975454477180 --- /dev/null +++ b/packages/kbn-elastic-agent-utils/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "target/**/*" + ] +} diff --git a/packages/kbn-es-query/index.ts b/packages/kbn-es-query/index.ts index a14724fc3a74..ac0a078e34d9 100644 --- a/packages/kbn-es-query/index.ts +++ b/packages/kbn-es-query/index.ts @@ -56,6 +56,7 @@ export { getIndexPatternFromSQLQuery, getIndexPatternFromESQLQuery, getLanguageDisplayName, + cleanupESQLQueryForLensSuggestions, } from './src/es_query'; export { diff --git a/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts b/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts index ca98864aab44..504e6a5c93d4 100644 --- a/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts +++ b/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts @@ -12,6 +12,7 @@ import { getAggregateQueryMode, getIndexPatternFromSQLQuery, getIndexPatternFromESQLQuery, + cleanupESQLQueryForLensSuggestions, } from './es_aggregate_query'; describe('sql query helpers', () => { @@ -115,4 +116,18 @@ describe('sql query helpers', () => { expect(idxPattern9).toBe('foo-1, foo-2'); }); }); + + describe('cleanupESQLQueryForLensSuggestions', () => { + it('should not remove anything if a drop command is not present', () => { + expect(cleanupESQLQueryForLensSuggestions('from a | eval b = 1')).toBe('from a | eval b = 1'); + }); + + it('should remove multiple drop statement if present', () => { + expect( + cleanupESQLQueryForLensSuggestions( + 'from a | drop @timestamp | drop a | drop b | keep c | drop d' + ) + ).toBe('from a | keep c '); + }); + }); }); diff --git a/packages/kbn-es-query/src/es_query/es_aggregate_query.ts b/packages/kbn-es-query/src/es_query/es_aggregate_query.ts index 27a5e790569c..f74650589636 100644 --- a/packages/kbn-es-query/src/es_query/es_aggregate_query.ts +++ b/packages/kbn-es-query/src/es_query/es_aggregate_query.ts @@ -66,3 +66,8 @@ export function getIndexPatternFromESQLQuery(esql?: string): string { } return ''; } + +export function cleanupESQLQueryForLensSuggestions(esql?: string): string { + const pipes = (esql || '').split('|'); + return pipes.filter((statement) => !/DROP\s/i.test(statement)).join('|'); +} diff --git a/packages/kbn-es-query/src/es_query/index.ts b/packages/kbn-es-query/src/es_query/index.ts index 22141a52e93f..18009145a432 100644 --- a/packages/kbn-es-query/src/es_query/index.ts +++ b/packages/kbn-es-query/src/es_query/index.ts @@ -20,6 +20,7 @@ export { getIndexPatternFromSQLQuery, getLanguageDisplayName, getIndexPatternFromESQLQuery, + cleanupESQLQueryForLensSuggestions, } from './es_aggregate_query'; export { fromCombinedFilter } from './from_combined_filter'; export type { diff --git a/packages/kbn-es/src/cli_commands/serverless.ts b/packages/kbn-es/src/cli_commands/serverless.ts index 87a573a8810d..0743cf2e7b5b 100644 --- a/packages/kbn-es/src/cli_commands/serverless.ts +++ b/packages/kbn-es/src/cli_commands/serverless.ts @@ -38,6 +38,7 @@ export const serverless: Command = { --host Publish ES docker container on additional host IP --port The port to bind to on 127.0.0.1 [default: ${DEFAULT_PORT}] --ssl Enable HTTP SSL on the ES cluster + --kibanaUrl Fully qualified URL where Kibana is hosted (including base path). [default: https://localhost:5601/] --skipTeardown If this process exits, leave the ES cluster running in the background --waitForReady Wait for the ES cluster to be ready to serve requests --resources Overrides resources under ES 'config/' directory, which are by default @@ -73,7 +74,7 @@ export const serverless: Command = { files: 'F', }, - string: ['tag', 'image', 'basePath', 'resources', 'host'], + string: ['tag', 'image', 'basePath', 'resources', 'host', 'kibanaUrl'], boolean: ['clean', 'ssl', 'kill', 'background', 'skipTeardown', 'waitForReady'], default: defaults, diff --git a/packages/kbn-es/src/paths.ts b/packages/kbn-es/src/paths.ts index d9b4be41aa15..4da444857338 100644 --- a/packages/kbn-es/src/paths.ts +++ b/packages/kbn-es/src/paths.ts @@ -8,6 +8,7 @@ import Os from 'os'; import { resolve } from 'path'; +import { REPO_ROOT } from '@kbn/repo-info'; function maybeUseBat(bin: string) { return Os.platform().startsWith('win') ? `${bin}.bat` : bin; @@ -51,6 +52,8 @@ export const SERVERLESS_SECRETS_SSL_PATH = resolve( export const SERVERLESS_JWKS_PATH = resolve(__dirname, './serverless_resources/jwks.json'); +export const SERVERLESS_IDP_METADATA_PATH = resolve(REPO_ROOT, '.es', 'idp_metadata.xml'); + export const SERVERLESS_RESOURCES_PATHS = [ SERVERLESS_OPERATOR_USERS_PATH, SERVERLESS_ROLE_MAPPING_PATH, diff --git a/packages/kbn-es/src/serverless_resources/roles.yml b/packages/kbn-es/src/serverless_resources/roles.yml index 5f968ece56e3..a98652d5b931 100644 --- a/packages/kbn-es/src/serverless_resources/roles.yml +++ b/packages/kbn-es/src/serverless_resources/roles.yml @@ -210,6 +210,7 @@ t3_analyst: privileges: - read - write + - maintenance - names: - .lists* - .items* @@ -263,12 +264,16 @@ threat_intelligence_analyst: - endgame-* - filebeat-* - logs-* - - .lists* - - .items* - packetbeat-* - winlogbeat-* privileges: - read + - names: + - .lists* + - .items* + privileges: + - read + - write - names: - .alerts-security* - .siem-signals-* @@ -287,8 +292,7 @@ threat_intelligence_analyst: - application: "kibana-.kibana" privileges: - feature_ml.read - - feature_siem.read - - feature_siem.read_alerts + - feature_siem.all - feature_siem.endpoint_list_read - feature_siem.blocklist_all - feature_securitySolutionCases.all @@ -573,12 +577,12 @@ endpoint_operations_analyst: privileges: - read - write + - maintenance applications: - application: "kibana-.kibana" privileges: - feature_ml.read - feature_siem.all - - feature_siem.read_alerts - feature_siem.policy_management_all - feature_siem.endpoint_list_all - feature_siem.trusted_applications_all @@ -623,11 +627,15 @@ endpoint_policy_manager: - logs-* - packetbeat-* - winlogbeat-* + - risk-score.risk-score-* + privileges: + - read + - names: - .lists* - .items* - - risk-score.risk-score-* privileges: - read + - write - names: - .alerts-security* - .siem-signals-* diff --git a/packages/kbn-es/src/serverless_resources/security_roles.json b/packages/kbn-es/src/serverless_resources/security_roles.json index 5ac286a41c16..c4a06751e19b 100644 --- a/packages/kbn-es/src/serverless_resources/security_roles.json +++ b/packages/kbn-es/src/serverless_resources/security_roles.json @@ -107,7 +107,7 @@ }, { "names": [".alerts-security*", ".siem-signals-*"], - "privileges": ["read", "write"] + "privileges": ["read", "write", "maintenance"] }, { "names": [".lists*", ".items*"], diff --git a/packages/kbn-es/src/utils/docker.test.ts b/packages/kbn-es/src/utils/docker.test.ts index 2d71a4e628e1..b574447a2050 100644 --- a/packages/kbn-es/src/utils/docker.test.ts +++ b/packages/kbn-es/src/utils/docker.test.ts @@ -32,15 +32,17 @@ import { ServerlessOptions, } from './docker'; import { ToolingLog, ToolingLogCollectingWriter } from '@kbn/tooling-log'; -import { ES_P12_PATH } from '@kbn/dev-utils'; +import { CA_CERT_PATH, ES_P12_PATH } from '@kbn/dev-utils'; import { SERVERLESS_CONFIG_PATH, SERVERLESS_RESOURCES_PATHS, SERVERLESS_SECRETS_PATH, SERVERLESS_JWKS_PATH, + SERVERLESS_IDP_METADATA_PATH, } from '../paths'; import * as waitClusterUtil from './wait_until_cluster_ready'; import * as waitForSecurityIndexUtil from './wait_for_security_index'; +import * as mockIdpPluginUtil from '@kbn/mock-idp-plugin/common'; jest.mock('execa'); const execa = jest.requireMock('execa'); @@ -58,6 +60,8 @@ jest.mock('./wait_for_security_index', () => ({ waitForSecurityIndex: jest.fn(), })); +jest.mock('@kbn/mock-idp-plugin/common'); + const log = new ToolingLog(); const logWriter = new ToolingLogCollectingWriter(); log.setWriters([logWriter]); @@ -69,6 +73,8 @@ const serverlessObjectStorePath = `${baseEsPath}/${serverlessDir}`; const waitUntilClusterReadyMock = jest.spyOn(waitClusterUtil, 'waitUntilClusterReady'); const waitForSecurityIndexMock = jest.spyOn(waitForSecurityIndexUtil, 'waitForSecurityIndex'); +const ensureSAMLRoleMappingMock = jest.spyOn(mockIdpPluginUtil, 'ensureSAMLRoleMapping'); +const createMockIdpMetadataMock = jest.spyOn(mockIdpPluginUtil, 'createMockIdpMetadata'); beforeEach(() => { jest.resetAllMocks(); @@ -423,6 +429,66 @@ describe('resolveEsArgs()', () => { ] `); }); + + test('should add SAML realm args when kibanaUrl and SSL are passed', () => { + const esArgs = resolveEsArgs([], { + ssl: true, + kibanaUrl: 'https://localhost:5601/', + }); + + expect(esArgs).toHaveLength(26); + expect(esArgs).toMatchInlineSnapshot(` + Array [ + "--env", + "xpack.security.http.ssl.enabled=true", + "--env", + "xpack.security.http.ssl.keystore.path=/usr/share/elasticsearch/config/certs/elasticsearch.p12", + "--env", + "xpack.security.http.ssl.verification_mode=certificate", + "--env", + "xpack.security.authc.realms.saml.mock-idp.order=0", + "--env", + "xpack.security.authc.realms.saml.mock-idp.idp.metadata.path=/usr/share/elasticsearch/config/secrets/idp_metadata.xml", + "--env", + "xpack.security.authc.realms.saml.mock-idp.idp.entity_id=urn:mock-idp", + "--env", + "xpack.security.authc.realms.saml.mock-idp.sp.entity_id=https://localhost:5601", + "--env", + "xpack.security.authc.realms.saml.mock-idp.sp.acs=https://localhost:5601/api/security/saml/callback", + "--env", + "xpack.security.authc.realms.saml.mock-idp.sp.logout=https://localhost:5601/logout", + "--env", + "xpack.security.authc.realms.saml.mock-idp.attributes.principal=http://saml.elastic-cloud.com/attributes/principal", + "--env", + "xpack.security.authc.realms.saml.mock-idp.attributes.groups=http://saml.elastic-cloud.com/attributes/roles", + "--env", + "xpack.security.authc.realms.saml.mock-idp.attributes.name=http://saml.elastic-cloud.com/attributes/email", + "--env", + "xpack.security.authc.realms.saml.mock-idp.attributes.mail=http://saml.elastic-cloud.com/attributes/name", + ] + `); + }); + + test('should not add SAML realm args when security is disabled', () => { + const esArgs = resolveEsArgs([['xpack.security.enabled', 'false']], { + ssl: true, + kibanaUrl: 'https://localhost:5601/', + }); + + expect(esArgs).toHaveLength(8); + expect(esArgs).toMatchInlineSnapshot(` + Array [ + "--env", + "xpack.security.enabled=false", + "--env", + "xpack.security.http.ssl.enabled=true", + "--env", + "xpack.security.http.ssl.keystore.path=/usr/share/elasticsearch/config/certs/elasticsearch.p12", + "--env", + "xpack.security.http.ssl.verification_mode=certificate", + ] + `); + }); }); describe('setupServerlessVolumes()', () => { @@ -463,21 +529,29 @@ describe('setupServerlessVolumes()', () => { expect(existsSync(`${serverlessObjectStorePath}/cluster_state/lease`)).toBe(false); }); - test('should add SSL volumes when ssl is passed', async () => { + test('should add SSL and IDP metadata volumes when ssl and kibanaUrl are passed', async () => { mockFs(existingObjectStore); + createMockIdpMetadataMock.mockResolvedValue(''); - const volumeCmd = await setupServerlessVolumes(log, { basePath: baseEsPath, ssl: true }); + const volumeCmd = await setupServerlessVolumes(log, { + basePath: baseEsPath, + ssl: true, + kibanaUrl: 'https://localhost:5603/', + }); + + expect(createMockIdpMetadataMock).toHaveBeenCalledTimes(1); + expect(createMockIdpMetadataMock).toHaveBeenCalledWith('https://localhost:5603/'); const requiredPaths = [ `${baseEsPath}:/objectstore:z`, + SERVERLESS_IDP_METADATA_PATH, ES_P12_PATH, ...SERVERLESS_RESOURCES_PATHS, ]; const pathsNotIncludedInCmd = requiredPaths.filter( (path) => !volumeCmd.some((cmd) => cmd.includes(path)) ); - - expect(volumeCmd).toHaveLength(20); + expect(volumeCmd).toHaveLength(22); expect(pathsNotIncludedInCmd).toEqual([]); }); @@ -543,6 +617,7 @@ describe('runServerlessEsNode()', () => { describe('runServerlessCluster()', () => { test('should start 3 serverless nodes', async () => { + waitUntilClusterReadyMock.mockResolvedValue(); mockFs({ [baseEsPath]: {}, }); @@ -567,7 +642,27 @@ describe('runServerlessCluster()', () => { expect(waitUntilClusterReadyMock.mock.calls[0][0].readyTimeout).toEqual(undefined); }); + test(`should create SAML role mapping when ssl and kibanaUrl are passed`, async () => { + waitUntilClusterReadyMock.mockResolvedValue(); + mockFs({ + [CA_CERT_PATH]: '', + [baseEsPath]: {}, + }); + execa.mockImplementation(() => Promise.resolve({ stdout: '' })); + createMockIdpMetadataMock.mockResolvedValue(''); + + await runServerlessCluster(log, { + basePath: baseEsPath, + waitForReady: true, + ssl: true, + kibanaUrl: 'https://localhost:5601/', + }); + + expect(ensureSAMLRoleMappingMock).toHaveBeenCalledTimes(1); + }); + test(`should wait for the security index`, async () => { + waitUntilClusterReadyMock.mockResolvedValue(); waitForSecurityIndexMock.mockResolvedValue(); mockFs({ [baseEsPath]: {}, @@ -580,6 +675,7 @@ describe('runServerlessCluster()', () => { }); test(`should not wait for the security index when security is disabled`, async () => { + waitUntilClusterReadyMock.mockResolvedValue(); mockFs({ [baseEsPath]: {}, }); diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index 1c89339e1a56..73e5e1fc7728 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -14,12 +14,17 @@ import { Client, ClientOptions, HttpConnection } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/tooling-log'; import { kibanaPackageJson as pkg, REPO_ROOT } from '@kbn/repo-info'; +import { CA_CERT_PATH, ES_P12_PASSWORD, ES_P12_PATH } from '@kbn/dev-utils'; import { - CA_CERT_PATH, - ES_P12_PASSWORD, - ES_P12_PATH, - kibanaDevServiceAccount, -} from '@kbn/dev-utils'; + MOCK_IDP_REALM_NAME, + MOCK_IDP_ENTITY_ID, + MOCK_IDP_ATTRIBUTE_PRINCIPAL, + MOCK_IDP_ATTRIBUTE_ROLES, + MOCK_IDP_ATTRIBUTE_EMAIL, + MOCK_IDP_ATTRIBUTE_NAME, + ensureSAMLRoleMapping, + createMockIdpMetadata, +} from '@kbn/mock-idp-plugin/common'; import { waitForSecurityIndex } from './wait_for_security_index'; import { createCliError } from '../errors'; @@ -28,6 +33,7 @@ import { SERVERLESS_RESOURCES_PATHS, SERVERLESS_SECRETS_PATH, SERVERLESS_JWKS_PATH, + SERVERLESS_IDP_METADATA_PATH, SERVERLESS_CONFIG_PATH, SERVERLESS_FILES_PATH, SERVERLESS_SECRETS_SSL_PATH, @@ -69,6 +75,8 @@ export interface ServerlessOptions extends EsClusterExecOptions, BaseOptions { background?: boolean; /** Wait for the ES cluster to be ready to serve requests */ waitForReady?: boolean; + /** Fully qualified URL where Kibana is hosted (including base path) */ + kibanaUrl?: string; /** * Resource file(s) to overwrite * (see list of files that can be overwritten under `packages/kbn-es/src/serverless_resources/users`) @@ -460,6 +468,54 @@ export function resolveEsArgs( esArgs.set('ELASTIC_PASSWORD', password); } + // Configure mock identify provider (ES only supports SAML when running in SSL mode) + if ( + ssl && + 'kibanaUrl' in options && + options.kibanaUrl && + esArgs.get('xpack.security.enabled') !== 'false' + ) { + const trimTrailingSlash = (url: string) => (url.endsWith('/') ? url.slice(0, -1) : url); + + esArgs.set(`xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.order`, '0'); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.idp.metadata.path`, + `${SERVERLESS_CONFIG_PATH}secrets/idp_metadata.xml` + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.idp.entity_id`, + MOCK_IDP_ENTITY_ID + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.sp.entity_id`, + trimTrailingSlash(options.kibanaUrl) + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.sp.acs`, + `${trimTrailingSlash(options.kibanaUrl)}/api/security/saml/callback` + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.sp.logout`, + `${trimTrailingSlash(options.kibanaUrl)}/logout` + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.attributes.principal`, + MOCK_IDP_ATTRIBUTE_PRINCIPAL + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.attributes.groups`, + MOCK_IDP_ATTRIBUTE_ROLES + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.attributes.name`, + MOCK_IDP_ATTRIBUTE_EMAIL + ); + esArgs.set( + `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.attributes.mail`, + MOCK_IDP_ATTRIBUTE_NAME + ); + } + return Array.from(esArgs).flatMap((e) => ['--env', e.join('=')]); } @@ -480,7 +536,7 @@ export function getDockerFileMountPath(hostPath: string) { * Setup local volumes for Serverless ES */ export async function setupServerlessVolumes(log: ToolingLog, options: ServerlessOptions) { - const { basePath, clean, ssl, files, resources } = options; + const { basePath, clean, ssl, kibanaUrl, files, resources } = options; const objectStorePath = resolve(basePath, 'stateless'); log.info(chalk.bold(`Checking for local serverless ES object store at ${objectStorePath}`)); @@ -551,6 +607,16 @@ export async function setupServerlessVolumes(log: ToolingLog, options: Serverles ); } + // Create and add meta data for mock identity provider + if (ssl && kibanaUrl) { + const metadata = await createMockIdpMetadata(kibanaUrl); + await Fsp.writeFile(SERVERLESS_IDP_METADATA_PATH, metadata); + volumeCmds.push( + '--volume', + `${SERVERLESS_IDP_METADATA_PATH}:${SERVERLESS_CONFIG_PATH}secrets/idp_metadata.xml:z` + ); + } + volumeCmds.push( ...getESp12Volume(), ...serverlessResources, @@ -559,7 +625,6 @@ export async function setupServerlessVolumes(log: ToolingLog, options: Serverles `${ ssl ? SERVERLESS_SECRETS_SSL_PATH : SERVERLESS_SECRETS_PATH }:${SERVERLESS_CONFIG_PATH}secrets/secrets.json:z`, - '--volume', `${SERVERLESS_JWKS_PATH}:${SERVERLESS_CONFIG_PATH}secrets/jwks.json:z` ); @@ -661,33 +726,52 @@ export async function runServerlessCluster(log: ToolingLog, options: ServerlessO process.on('SIGINT', () => teardownServerlessClusterSync(log, options)); } + const esNodeUrl = `${options.ssl ? 'https' : 'http'}://${portCmd[1].substring( + 0, + portCmd[1].lastIndexOf(':') + )}`; + + const client = getESClient({ + node: esNodeUrl, + auth: { + username: ELASTIC_SERVERLESS_SUPERUSER, + password: ELASTIC_SERVERLESS_SUPERUSER_PASSWORD, + }, + ...(options.ssl + ? { + tls: { + ca: [fs.readFileSync(CA_CERT_PATH)], + // NOTE: Even though we've added ca into the tls options, we are using 127.0.0.1 instead of localhost + // for the ip which is not validated. As such we are getting the error + // Hostname/IP does not match certificate's altnames: IP: 127.0.0.1 is not in the cert's list: + // To work around that we are overriding the function checkServerIdentity too + checkServerIdentity: () => { + return undefined; + }, + }, + } + : {}), + }); + + const readyPromise = waitUntilClusterReady({ client, expectedStatus: 'green', log }).then( + async () => { + if (!options.ssl || !options.kibanaUrl) { + return; + } + + await ensureSAMLRoleMapping(client); + + log.success( + `Created role mapping for mock identity provider. You can now login using ${chalk.bold.cyan( + MOCK_IDP_REALM_NAME + )} realm` + ); + } + ); + if (options.waitForReady) { log.info('Waiting until ES is ready to serve requests...'); - - const esNodeUrl = `${options.ssl ? 'https' : 'http'}://${portCmd[1].substring( - 0, - portCmd[1].lastIndexOf(':') - )}`; - - const client = getESClient({ - node: esNodeUrl, - auth: { bearer: kibanaDevServiceAccount.token }, - ...(options.ssl - ? { - tls: { - ca: [fs.readFileSync(CA_CERT_PATH)], - // NOTE: Even though we've added ca into the tls options, we are using 127.0.0.1 instead of localhost - // for the ip which is not validated. As such we are getting the error - // Hostname/IP does not match certificate's altnames: IP: 127.0.0.1 is not in the cert's list: - // To work around that we are overriding the function checkServerIdentity too - checkServerIdentity: () => { - return undefined; - }, - }, - } - : {}), - }); - await waitUntilClusterReady({ client, expectedStatus: 'green', log }); + await readyPromise; if (!options.esArgs || !options.esArgs.includes('xpack.security.enabled=false')) { // If security is not disabled, make sure the security index exists before running the test to avoid flakiness await waitForSecurityIndex({ client, log }); diff --git a/packages/kbn-es/tsconfig.json b/packages/kbn-es/tsconfig.json index 75059c2ef69c..b40ca3382556 100644 --- a/packages/kbn-es/tsconfig.json +++ b/packages/kbn-es/tsconfig.json @@ -3,13 +3,20 @@ "compilerOptions": { "outDir": "target/types" }, - "include": ["**/*.ts", "**/*.js", "**/*.json"], - "exclude": ["target/**/*"], + "include": [ + "**/*.ts", + "**/*.js", + "**/*.json" + ], + "exclude": [ + "target/**/*" + ], "kbn_references": [ "@kbn/tooling-log", "@kbn/dev-utils", "@kbn/dev-proc-runner", "@kbn/ci-stats-reporter", + "@kbn/mock-idp-plugin", "@kbn/jest-serializers", "@kbn/repo-info" ] diff --git a/packages/kbn-eslint-plugin-i18n/README.mdx b/packages/kbn-eslint-plugin-i18n/README.mdx index 174457477e81..6b836eb8bb52 100644 --- a/packages/kbn-eslint-plugin-i18n/README.mdx +++ b/packages/kbn-eslint-plugin-i18n/README.mdx @@ -6,22 +6,88 @@ description: Custom ESLint rules to support translations in the Kibana repositor tags: ['kibana', 'dev', 'contributor', 'operations', 'eslint', 'i18n'] --- -`@kbn/eslint-plugin-i18n` is an ESLint plugin providing custom rules for validating JSXCode in the Kibana repo to make sure they are translated. +# Summary -Note: At the moment these rules only work for apps that are inside `/x-pack/plugins`. -If you want to enable this rule on code that is outside of this path, adjust `/helpers/get_i18n_identifier_from_file_path.ts`. +`@kbn/eslint-plugin-i18n` is an ESLint plugin providing custom ESLint rules to help validating code in the Kibana repo in the area of translations. + +The aim of this package is to help engineers type less and have a nicer experience. + +If a rule does not behave as you expect or you have an idea of how these rules can be improved, please reach out to the Observability Knowledge Team or the Kibana Operations team. + +# Rules ## `@kbn/i18n/strings_should_be_translated_with_i18n` -This rule warns engineers to translate their strings by using i18n.translate from the '@kbn/i18n' package. It provides an autofix that takes into account the context of the translatable string in the JSX tree to generate a translation ID. -It kicks in on JSXText elements and specific JSXAttributes (`label` and `aria-label`) which expect a translated value. +This rule warns engineers to translate their strings by using `i18n.translate` from the `@kbn/i18n` package. + +It provides an autofix that takes into account the context of the translatable string in the JSX tree to generate a translation ID. + +This rule kicks in on: + +- JSXText elements; +- specific JSXAttributes (`label` and `aria-label`) which expect a translated value. + +### Example + +This code: + +``` +// Filename: /x-pack/plugins/observability/public/my_component.tsx + +import React from 'react'; +import { EuiText } from '@elastic/eui'; + +function MyComponent() { + return ( + You know, for search + ) +} +``` + +will be autofixed with: + +``` +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiText } from '@elastic/eui'; + +function MyComponent() { + return ( + + {i18n.translate('xpack.observability.myComponent.textLabel', { defaultMessage: 'You know, for search' } )} + + ) +} +``` + +If `i18n` has not been imported yet, the autofix will automatically add the import statement as well. + +### Exemptions and exceptions + +A JSXText element or JSXAttribute `label` or `aria-label` of which the value is: + +- wrapped in a `EuiCode` or `EuiBetaBadge` component, +- made up of non alpha characters such as `!@#$%^&*(){}` or numbers, +- wrapped in three backticks, + +are exempt from this rule. + +If this rule kicks in on a string value that you don't like, you can escape it by wrapping the string inside a JSXExpression: `{'my escaped value'}`. + +--- ## `@kbn/i18n/strings_should_be_translated_with_formatted_message` -This rule warns engineers to translate their strings by using `` from the '@kbn/i18n-react' package. It provides an autofix that takes into account the context of the translatable string in the JSX tree and to generate a translation ID. -It kicks in on JSXText elements and specific JSXAttributes (`label` and `aria-label`) which expect a translated value. +This rule warns engineers to translate their strings by using `` from the `@kbn/i18n-react` package. + +It provides an autofix that takes into account the context of the translatable string in the JSX tree and to generate a translation ID. + +This rule kicks in on: -## Exemptions and exceptions +- JSXText elements; +- specific JSXAttributes (`label` and `aria-label`) which expect a translated value. + +### Exemptions and exceptions A JSXText element or JSXAttribute `label` or `aria-label` of which the value is: @@ -32,3 +98,52 @@ A JSXText element or JSXAttribute `label` or `aria-label` of which the value is: are exempt from this rule. If this rule kicks in on a string value that you don't like, you can escape it by wrapping the string inside a JSXExpression: `{'my escaped value'}`. + +--- + +## `@kbn/i18n/i18n_translate_should_start_with_the_right_id` + +This rule checks every instance of `i18n.translate()` if the first parameter passed: + +1. has a string value, +2. if the parameter starts with the correct i18n app identifier for the file. + +It checks the repo for the `i18nrc.json` and `/x-pack/i18nrc.json` files and determines what the right i18n identifier should be. + +If the parameter is missing or does not start with the right i18n identifier, it can autofix the parameter. + +This rule is useful when defining translated values in plain functions (non-JSX), but it works in JSX as well. + +### Example + +This code: + +``` +// Filename: /x-pack/plugins/observability/public/my_function.ts + +function myFunction() { + const translations = [ + { + id: 'copy'; + label: i18n.translate() + } + ] +} +``` + +will be autofixed with: + +``` +import { i18n } from '@kbn/i18n'; + +function myFunction() { + const translations = [ + { + id: 'copy'; + label: i18n.translate('xpack.observability.myFunction.', { defaultMessage: '' }) + } + ] +} +``` + +If `i18n` has not been imported yet, the autofix will automatically add the import statement as well. diff --git a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.test.ts b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.test.ts index 6e01b89b2356..cea9fa1c333d 100644 --- a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.test.ts +++ b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.test.ts @@ -11,17 +11,15 @@ import { getI18nIdentifierFromFilePath } from './get_i18n_identifier_from_file_p const SYSTEMPATH = 'systemPath'; const testMap = [ - ['x-pack/plugins/observability/foo/bar/baz/header_actions.tsx', 'xpack.observability'], - ['x-pack/plugins/apm/public/components/app/correlations/correlations_table.tsx', 'xpack.apm'], - ['x-pack/plugins/cases/public/components/foo.tsx', 'xpack.cases'], + ['x-pack/plugins/observability/public/header_actions.tsx', 'xpack.observability'], + ['x-pack/plugins/apm/common/components/app/correlations/correlations_table.tsx', 'xpack.apm'], + ['x-pack/plugins/cases/server/components/foo.tsx', 'xpack.cases'], [ 'x-pack/plugins/synthetics/public/apps/synthetics/components/alerts/toggle_alert_flyout_button.tsx', 'xpack.synthetics', ], - [ - 'packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx', - 'app_not_found_in_i18nrc', - ], + ['src/plugins/vis_types/gauge/public/editor/collections.ts', 'visTypeGauge'], + ['packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx', 'alertsUIShared'], ]; describe('Get i18n Identifier for file', () => { diff --git a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.ts b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.ts index d23a42f4ebcf..7b39d119ee84 100644 --- a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.ts +++ b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_identifier_from_file_path.ts @@ -14,18 +14,38 @@ export function getI18nIdentifierFromFilePath(fileName: string, cwd: string) { const { dir } = parse(fileName); const relativePathToFile = dir.replace(cwd, ''); - const relativePathArray = relativePathToFile.split('/'); + // We need to match the path of the file that is being worked in with the path + // that is noted in the values inside the i18nrc.json object. + // These values differ depending on which i18nrc.json object you look at (there are multiple) + // so we need to account for both notations. + const relativePathArray = relativePathToFile.includes('src') + ? relativePathToFile.split('/').slice(1) + : relativePathToFile.split('/').slice(2); - const path = `${relativePathArray[2]}/${relativePathArray[3]}`; + const pluginNameIndex = relativePathArray.findIndex( + (el) => el === 'public' || el === 'server' || el === 'common' + ); + + const path = relativePathArray.slice(0, pluginNameIndex).join('/'); const xpackRC = resolve(join(__dirname, '../../../'), 'x-pack/.i18nrc.json'); + const rootRC = resolve(join(__dirname, '../../../'), '.i18nrc.json'); + + const xpackI18nrcFile = fs.readFileSync(xpackRC, 'utf8'); + const xpackI18nrc = JSON.parse(xpackI18nrcFile); + + const rootI18nrcFile = fs.readFileSync(rootRC, 'utf8'); + const rootI18nrc = JSON.parse(rootI18nrcFile); + + const allPaths = { ...xpackI18nrc.paths, ...rootI18nrc.paths }; - const i18nrcFile = fs.readFileSync(xpackRC, 'utf8'); - const i18nrc = JSON.parse(i18nrcFile); + if (Object.keys(allPaths).length === 0) return 'could_not_find_i18nrc'; - return i18nrc && i18nrc.paths - ? findKey(i18nrc.paths, (v) => - Array.isArray(v) ? v.find((e) => e === path) : typeof v === 'string' && v === path - ) ?? 'app_not_found_in_i18nrc' - : 'could_not_find_i18nrc'; + return ( + findKey(allPaths, (value) => + Array.isArray(value) + ? value.find((el) => el === path) + : typeof value === 'string' && value === path + ) ?? 'app_not_found_in_i18nrc' + ); } diff --git a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_import_fixer.ts b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_import_fixer.ts index cf3a7330f758..7b81c0f7a6b8 100644 --- a/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_import_fixer.ts +++ b/packages/kbn-eslint-plugin-i18n/helpers/get_i18n_import_fixer.ts @@ -10,10 +10,10 @@ import { SourceCode } from 'eslint'; export function getI18nImportFixer({ sourceCode, - mode, + translationFunction, }: { sourceCode: SourceCode; - mode: 'i18n.translate' | 'FormattedMessage'; + translationFunction: 'i18n.translate' | 'FormattedMessage'; }) { let existingI18nImportLineIndex = -1; let i18nImportLineToBeAdded = ''; @@ -27,7 +27,7 @@ export function getI18nImportFixer({ * * */ - if (mode === 'i18n.translate') { + if (translationFunction === 'i18n.translate') { existingI18nImportLineIndex = sourceCode.lines.findIndex((l) => l.includes("from '@kbn/i18n'")); const i18nImportLineInSource = sourceCode.lines[existingI18nImportLineIndex]; @@ -46,7 +46,7 @@ export function getI18nImportFixer({ } } - if (mode === 'FormattedMessage') { + if (translationFunction === 'FormattedMessage') { existingI18nImportLineIndex = sourceCode.lines.findIndex((l) => l.includes("from '@kbn/i18n-react'") ); @@ -83,21 +83,27 @@ export function getI18nImportFixer({ return { i18nImportLine: i18nImportLineToBeAdded, rangeToAddI18nImportLine: [start, end] as [number, number], - mode: 'replace', + replaceMode: 'replace', }; } // If the file doesn't have an import line for the translation package yet, we need to add it. // Pretty safe bet to add it underneath the import line for React. - const lineIndex = sourceCode.lines.findIndex((l) => l.includes("from 'react'")); + let lineIndex = sourceCode.lines.findIndex((l) => l.includes("from 'react'") || l.includes('*/')); + + if (lineIndex === -1) { + lineIndex = 0; + } + const targetLine = sourceCode.lines[lineIndex]; + // `getIndexFromLoc` is 0-based, so we need to add 1 to the line index. const start = sourceCode.getIndexFromLoc({ line: lineIndex + 1, column: 0 }); const end = start + targetLine.length; return { i18nImportLine: i18nImportLineToBeAdded, rangeToAddI18nImportLine: [start, end] as [number, number], - mode: 'insert', + replaceMode: 'insert', }; } diff --git a/packages/kbn-eslint-plugin-i18n/index.ts b/packages/kbn-eslint-plugin-i18n/index.ts index be5661cf46de..dd99785204c3 100644 --- a/packages/kbn-eslint-plugin-i18n/index.ts +++ b/packages/kbn-eslint-plugin-i18n/index.ts @@ -8,6 +8,7 @@ import { StringsShouldBeTranslatedWithI18n } from './rules/strings_should_be_translated_with_i18n'; import { StringsShouldBeTranslatedWithFormattedMessage } from './rules/strings_should_be_translated_with_formatted_message'; +import { I18nTranslateShouldStartWithTheRightId } from './rules/i18n_translate_should_start_with_the_right_id'; /** * Custom ESLint rules, add `'@kbn/eslint-plugin-i18n'` to your eslint config to use them @@ -17,4 +18,5 @@ export const rules = { strings_should_be_translated_with_i18n: StringsShouldBeTranslatedWithI18n, strings_should_be_translated_with_formatted_message: StringsShouldBeTranslatedWithFormattedMessage, + i18n_translate_should_start_with_the_right_id: I18nTranslateShouldStartWithTheRightId, }; diff --git a/packages/kbn-eslint-plugin-i18n/kibana.jsonc b/packages/kbn-eslint-plugin-i18n/kibana.jsonc index 72e051941db6..b234cc835ed3 100644 --- a/packages/kbn-eslint-plugin-i18n/kibana.jsonc +++ b/packages/kbn-eslint-plugin-i18n/kibana.jsonc @@ -1,6 +1,6 @@ { "type": "shared-common", "id": "@kbn/eslint-plugin-i18n", - "owner": "@elastic/obs-knowledge-team", + "owner": ["@elastic/obs-knowledge-team", "@elastic/kibana-operations"], "devOnly": true } diff --git a/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.test.ts b/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.test.ts new file mode 100644 index 000000000000..49bdb03a4f47 --- /dev/null +++ b/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.test.ts @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { RuleTester } from 'eslint'; +import { + I18nTranslateShouldStartWithTheRightId, + RULE_WARNING_MESSAGE, +} from './i18n_translate_should_start_with_the_right_id'; + +const tsTester = [ + '@typescript-eslint/parser', + new RuleTester({ + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { + sourceType: 'module', + ecmaVersion: 2018, + ecmaFeatures: { + jsx: true, + }, + }, + }), +] as const; + +const babelTester = [ + '@babel/eslint-parser', + new RuleTester({ + parser: require.resolve('@babel/eslint-parser'), + parserOptions: { + sourceType: 'module', + ecmaVersion: 2018, + requireConfigFile: false, + babelOptions: { + presets: ['@kbn/babel-preset/node_preset'], + }, + }, + }), +] as const; + +const invalid: RuleTester.InvalidTestCase[] = [ + { + name: 'When a string literal is passed to i18n.translate, it should start with the correct i18n identifier.', + filename: '/x-pack/plugins/observability/public/test_component.ts', + code: ` +import { i18n } from '@kbn/i18n'; + +function TestComponent() { + const foo = i18n.translate('foo'); +}`, + errors: [ + { + line: 5, + message: RULE_WARNING_MESSAGE, + }, + ], + output: ` +import { i18n } from '@kbn/i18n'; + +function TestComponent() { + const foo = i18n.translate('xpack.observability.testComponent.', { defaultMessage: '' }); +}`, + }, + { + name: 'When no string literal is passed to i18n.translate, it should start with the correct i18n identifier.', + filename: '/x-pack/plugins/observability/public/test_component.ts', + code: ` +import { i18n } from '@kbn/i18n'; + +function TestComponent() { + const foo = i18n.translate(); +}`, + errors: [ + { + line: 5, + message: RULE_WARNING_MESSAGE, + }, + ], + output: ` +import { i18n } from '@kbn/i18n'; + +function TestComponent() { + const foo = i18n.translate('xpack.observability.testComponent.', { defaultMessage: '' }); +}`, + }, + { + name: 'When i18n is not imported yet, the rule should add it.', + filename: '/x-pack/plugins/observability/public/test_component.ts', + code: ` +function TestComponent() { + const foo = i18n.translate(); +}`, + errors: [ + { + line: 3, + message: RULE_WARNING_MESSAGE, + }, + ], + output: ` +import { i18n } from '@kbn/i18n'; +function TestComponent() { + const foo = i18n.translate('xpack.observability.testComponent.', { defaultMessage: '' }); +}`, + }, +]; + +const valid: RuleTester.ValidTestCase[] = [ + { + name: invalid[0].name, + filename: invalid[0].filename, + code: invalid[0].output as string, + }, + { + name: invalid[1].name, + filename: invalid[1].filename, + code: invalid[1].output as string, + }, +]; + +for (const [name, tester] of [tsTester, babelTester]) { + describe(name, () => { + tester.run( + '@kbn/i18n_translate_should_start_with_the_right_id', + I18nTranslateShouldStartWithTheRightId, + { + valid, + invalid, + } + ); + }); +} diff --git a/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.ts b/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.ts new file mode 100644 index 000000000000..d6510ba588a4 --- /dev/null +++ b/packages/kbn-eslint-plugin-i18n/rules/i18n_translate_should_start_with_the_right_id.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { TSESTree } from '@typescript-eslint/typescript-estree'; +import type { Rule } from 'eslint'; +import { getI18nIdentifierFromFilePath } from '../helpers/get_i18n_identifier_from_file_path'; +import { getFunctionName } from '../helpers/get_function_name'; +import { getI18nImportFixer } from '../helpers/get_i18n_import_fixer'; +import { isTruthy } from '../helpers/utils'; + +export const RULE_WARNING_MESSAGE = + 'First parameter passed to i18n.translate should start with the correct i18n identifier for this file. Correct it or use the autofix suggestion.'; + +export const I18nTranslateShouldStartWithTheRightId: Rule.RuleModule = { + meta: { + type: 'suggestion', + fixable: 'code', + }, + create(context) { + const { cwd, filename, getScope, sourceCode, report } = context; + + return { + CallExpression: (node: TSESTree.CallExpression) => { + const { callee } = node; + + if ( + !callee || + !('object' in callee) || + !('property' in callee) || + !('name' in callee.object) || + !('name' in callee.property) || + callee.object.name !== 'i18n' || + callee.property.name !== 'translate' + ) + return; + + const identifier = + Array.isArray(node.arguments) && + node.arguments.length && + 'value' in node.arguments[0] && + typeof node.arguments[0].value === 'string' && + node.arguments[0].value; + + const i18nAppId = getI18nIdentifierFromFilePath(filename, cwd); + const functionDeclaration = getScope().block as TSESTree.FunctionDeclaration; + const functionName = getFunctionName(functionDeclaration); + + // Check if i18n has already been imported into the file + const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, replaceMode } = + getI18nImportFixer({ + sourceCode, + translationFunction: 'i18n.translate', + }); + + if (!identifier || (identifier && !identifier.startsWith(`${i18nAppId}.`))) { + report({ + node: node as any, + message: RULE_WARNING_MESSAGE, + fix(fixer) { + return [ + fixer.replaceTextRange( + node.range, + `i18n.translate('${i18nAppId}.${functionName}.', { defaultMessage: '' })` + ), + !hasI18nImportLine && rangeToAddI18nImportLine + ? replaceMode === 'replace' + ? fixer.replaceTextRange(rangeToAddI18nImportLine, i18nImportLine) + : fixer.insertTextAfterRange(rangeToAddI18nImportLine, `\n${i18nImportLine}`) + : null, + ].filter(isTruthy); + }, + }); + } + }, + } as Rule.RuleListener; + }, +}; diff --git a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.test.ts b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.test.ts index 009fac255fc6..6faf6732f901 100644 --- a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.test.ts +++ b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.test.ts @@ -7,7 +7,10 @@ */ import { RuleTester } from 'eslint'; -import { StringsShouldBeTranslatedWithFormattedMessage } from './strings_should_be_translated_with_formatted_message'; +import { + StringsShouldBeTranslatedWithFormattedMessage, + RULE_WARNING_MESSAGE, +} from './strings_should_be_translated_with_formatted_message'; const tsTester = [ '@typescript-eslint/parser', @@ -41,7 +44,7 @@ const babelTester = [ const invalid: RuleTester.InvalidTestCase[] = [ { name: 'A JSX element with a string literal should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -53,7 +56,7 @@ function TestComponent() { errors: [ { line: 6, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -64,7 +67,7 @@ function TestComponent() { return (
    ) @@ -72,7 +75,7 @@ function TestComponent() { }, { name: 'A JSX element with a string literal that are inside an Eui component should take the component name of the parent into account', - filename: 'x-pack/plugins/observability/public/another_component.tsx', + filename: '/x-pack/plugins/observability/public/another_component.tsx', code: ` import React from 'react'; @@ -90,7 +93,7 @@ function AnotherComponent() { errors: [ { line: 9, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -104,7 +107,7 @@ function AnotherComponent() { @@ -115,7 +118,7 @@ function AnotherComponent() { }, { name: 'When no import of the translation module is present, the import line should be added', - filename: 'x-pack/plugins/observability/public/yet_another_component.tsx', + filename: '/x-pack/plugins/observability/public/yet_another_component.tsx', code: ` import React from 'react'; @@ -129,7 +132,7 @@ function YetAnotherComponent() { errors: [ { line: 7, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -141,7 +144,7 @@ function YetAnotherComponent() {
    @@ -150,7 +153,7 @@ function YetAnotherComponent() { }, { name: 'Import lines without the necessary translation module should be updated to include i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { SomeOtherModule } from '@kbn/i18n-react'; @@ -163,7 +166,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -172,13 +175,13 @@ import { SomeOtherModule, FormattedMessage } from '@kbn/i18n-react'; function TestComponent() { return ( - } /> + } /> ) }`, }, { name: 'JSX elements that have a label or aria-label prop with a string value should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -191,7 +194,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -200,13 +203,13 @@ import { FormattedMessage } from '@kbn/i18n-react'; function TestComponent() { return ( - } /> + } /> ) }`, }, { name: 'JSX elements that have a label or aria-label prop with a JSXExpression value that is a string should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -219,7 +222,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with . Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -228,7 +231,7 @@ function TestComponent() { function TestComponent() { return ( - } /> + } /> ) }`, }, @@ -237,7 +240,7 @@ function TestComponent() { const valid: RuleTester.ValidTestCase[] = [ { name: 'A JSXText element inside a EuiCode component should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -249,7 +252,7 @@ function TestComponent() { }, { name: 'A JSXText element that contains anything other than alpha characters should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -261,7 +264,7 @@ function TestComponent() { }, { name: 'A JSXText element that is wrapped in three backticks (markdown) should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; diff --git a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.ts b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.ts index 77b591895103..ea96cf313d1b 100644 --- a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.ts +++ b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_formatted_message.ts @@ -14,6 +14,8 @@ import { getFunctionName } from '../helpers/get_function_name'; import { getI18nImportFixer } from '../helpers/get_i18n_import_fixer'; import { cleanString, isTruthy } from '../helpers/utils'; +export const RULE_WARNING_MESSAGE = + 'Strings should be translated with . Use the autofix suggestion or add your own.'; export const StringsShouldBeTranslatedWithFormattedMessage: Rule.RuleModule = { meta: { type: 'suggestion', @@ -44,17 +46,16 @@ export const StringsShouldBeTranslatedWithFormattedMessage: Rule.RuleModule = { const translationIdSuggestion = `${i18nAppId}.${functionName}.${intent}`; // 'xpack.observability.overview.logs.loadMoreLabel' // Check if i18n has already been imported into the file - const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, mode } = + const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, replaceMode } = getI18nImportFixer({ sourceCode, - mode: 'FormattedMessage', + translationFunction: 'FormattedMessage', }); // Show warning to developer and offer autofix suggestion report({ node: node as any, - message: - 'Strings should be translated with . Use the autofix suggestion or add your own.', + message: RULE_WARNING_MESSAGE, fix(fixer) { return [ fixer.replaceText( @@ -65,7 +66,7 @@ export const StringsShouldBeTranslatedWithFormattedMessage: Rule.RuleModule = { />` ), !hasI18nImportLine && rangeToAddI18nImportLine - ? mode === 'replace' + ? replaceMode === 'replace' ? fixer.replaceTextRange(rangeToAddI18nImportLine, i18nImportLine) : fixer.insertTextAfterRange(rangeToAddI18nImportLine, `\n${i18nImportLine}`) : null, @@ -106,17 +107,16 @@ export const StringsShouldBeTranslatedWithFormattedMessage: Rule.RuleModule = { const translationIdSuggestion = `${i18nAppId}.${functionName}.${intent}`; // 'xpack.observability.overview.logs.loadMoreLabel' // Check if i18n has already been imported into the file. - const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, mode } = + const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, replaceMode } = getI18nImportFixer({ sourceCode, - mode: 'FormattedMessage', + translationFunction: 'FormattedMessage', }); // Show warning to developer and offer autofix suggestion report({ node: node as any, - message: - 'Strings should be translated with . Use the autofix suggestion or add your own.', + message: RULE_WARNING_MESSAGE, fix(fixer) { return [ fixer.replaceTextRange( @@ -124,7 +124,7 @@ export const StringsShouldBeTranslatedWithFormattedMessage: Rule.RuleModule = { `{}` ), !hasI18nImportLine && rangeToAddI18nImportLine - ? mode === 'replace' + ? replaceMode === 'replace' ? fixer.replaceTextRange(rangeToAddI18nImportLine, i18nImportLine) : fixer.insertTextAfterRange(rangeToAddI18nImportLine, `\n${i18nImportLine}`) : null, diff --git a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.test.ts b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.test.ts index f470ed885682..3142d368b076 100644 --- a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.test.ts +++ b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.test.ts @@ -7,7 +7,10 @@ */ import { RuleTester } from 'eslint'; -import { StringsShouldBeTranslatedWithI18n } from './strings_should_be_translated_with_i18n'; +import { + StringsShouldBeTranslatedWithI18n, + RULE_WARNING_MESSAGE, +} from './strings_should_be_translated_with_i18n'; const tsTester = [ '@typescript-eslint/parser', @@ -41,7 +44,7 @@ const babelTester = [ const invalid: RuleTester.InvalidTestCase[] = [ { name: 'A JSX element with a string literal should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -53,7 +56,7 @@ function TestComponent() { errors: [ { line: 6, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -62,13 +65,13 @@ import { i18n } from '@kbn/i18n'; function TestComponent() { return ( -
    {i18n.translate('app_not_found_in_i18nrc.testComponent.div.thisIsATestLabel', { defaultMessage: 'This is a test' })}
    +
    {i18n.translate('xpack.observability.testComponent.div.thisIsATestLabel', { defaultMessage: 'This is a test' })}
    ) }`, }, { name: 'A JSX element with a string literal that are inside an Eui component should take the component name of the parent into account', - filename: 'x-pack/plugins/observability/public/another_component.tsx', + filename: '/x-pack/plugins/observability/public/another_component.tsx', code: ` import React from 'react'; @@ -86,7 +89,7 @@ function AnotherComponent() { errors: [ { line: 9, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -98,7 +101,7 @@ function AnotherComponent() { - {i18n.translate('app_not_found_in_i18nrc.anotherComponent.thisIsATestButtonLabel', { defaultMessage: 'This is a test' })} + {i18n.translate('xpack.observability.anotherComponent.thisIsATestButtonLabel', { defaultMessage: 'This is a test' })} @@ -107,7 +110,7 @@ function AnotherComponent() { }, { name: 'When no import of the translation module is present, the import line should be added', - filename: 'x-pack/plugins/observability/public/yet_another_component.tsx', + filename: '/x-pack/plugins/observability/public/yet_another_component.tsx', code: ` import React from 'react'; @@ -121,7 +124,7 @@ function YetAnotherComponent() { errors: [ { line: 7, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -131,14 +134,14 @@ import { i18n } from '@kbn/i18n'; function YetAnotherComponent() { return (
    - {i18n.translate('app_not_found_in_i18nrc.yetAnotherComponent.selectMeSelectLabel', { defaultMessage: 'Select me' })} + {i18n.translate('xpack.observability.yetAnotherComponent.selectMeSelectLabel', { defaultMessage: 'Select me' })}
    ) }`, }, { name: 'Import lines without the necessary translation module should be updated to include i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { SomeOtherModule } from '@kbn/i18n'; @@ -151,7 +154,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -160,13 +163,13 @@ import { SomeOtherModule, i18n } from '@kbn/i18n'; function TestComponent() { return ( - + ) }`, }, { name: 'JSX elements that have a label or aria-label prop with a string value should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { i18n } from '@kbn/i18n'; @@ -179,7 +182,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -188,13 +191,13 @@ import { i18n } from '@kbn/i18n'; function TestComponent() { return ( - + ) }`, }, { name: 'JSX elements that have a label or aria-label prop with a JSXExpression value that is a string should be translated with i18n', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; import { i18n } from '@kbn/i18n'; @@ -207,7 +210,7 @@ function TestComponent() { errors: [ { line: 7, - message: `Strings should be translated with i18n. Use the autofix suggestion or add your own.`, + message: RULE_WARNING_MESSAGE, }, ], output: ` @@ -216,7 +219,7 @@ import { i18n } from '@kbn/i18n'; function TestComponent() { return ( - + ) }`, }, @@ -225,7 +228,7 @@ function TestComponent() { const valid: RuleTester.ValidTestCase[] = [ { name: 'A JSXText element inside a EuiCode component should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -237,7 +240,7 @@ function TestComponent() { }, { name: 'A JSXText element that contains anything other than alpha characters should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; @@ -249,7 +252,7 @@ function TestComponent() { }, { name: 'A JSXText element that is wrapped in three backticks (markdown) should not be translated', - filename: 'x-pack/plugins/observability/public/test_component.tsx', + filename: '/x-pack/plugins/observability/public/test_component.tsx', code: ` import React from 'react'; diff --git a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.ts b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.ts index fea04d33d555..ec1630de115e 100644 --- a/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.ts +++ b/packages/kbn-eslint-plugin-i18n/rules/strings_should_be_translated_with_i18n.ts @@ -14,6 +14,9 @@ import { getFunctionName } from '../helpers/get_function_name'; import { getI18nImportFixer } from '../helpers/get_i18n_import_fixer'; import { cleanString, isTruthy } from '../helpers/utils'; +export const RULE_WARNING_MESSAGE = + 'Strings should be translated with i18n. Use the autofix suggestion or add your own.'; + export const StringsShouldBeTranslatedWithI18n: Rule.RuleModule = { meta: { type: 'suggestion', @@ -44,17 +47,16 @@ export const StringsShouldBeTranslatedWithI18n: Rule.RuleModule = { const translationIdSuggestion = `${i18nAppId}.${functionName}.${intent}`; // 'xpack.observability.overview.logs.loadMoreLabel' // Check if i18n has already been imported into the file - const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, mode } = + const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, replaceMode } = getI18nImportFixer({ sourceCode, - mode: 'i18n.translate', + translationFunction: 'i18n.translate', }); // Show warning to developer and offer autofix suggestion report({ node: node as any, - message: - 'Strings should be translated with i18n. Use the autofix suggestion or add your own.', + message: RULE_WARNING_MESSAGE, fix(fixer) { return [ fixer.replaceText( @@ -62,7 +64,7 @@ export const StringsShouldBeTranslatedWithI18n: Rule.RuleModule = { `${whiteSpaces}{i18n.translate('${translationIdSuggestion}', { defaultMessage: '${value}' })}` ), !hasI18nImportLine && rangeToAddI18nImportLine - ? mode === 'replace' + ? replaceMode === 'replace' ? fixer.replaceTextRange(rangeToAddI18nImportLine, i18nImportLine) : fixer.insertTextAfterRange(rangeToAddI18nImportLine, `\n${i18nImportLine}`) : null, @@ -103,17 +105,16 @@ export const StringsShouldBeTranslatedWithI18n: Rule.RuleModule = { const translationIdSuggestion = `${i18nAppId}.${functionName}.${intent}`; // 'xpack.observability.overview.logs.loadMoreLabel' // Check if i18n has already been imported into the file. - const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, mode } = + const { hasI18nImportLine, i18nImportLine, rangeToAddI18nImportLine, replaceMode } = getI18nImportFixer({ sourceCode, - mode: 'i18n.translate', + translationFunction: 'i18n.translate', }); // Show warning to developer and offer autofix suggestion report({ node: node as any, - message: - 'Strings should be translated with i18n. Use the autofix suggestion or add your own.', + message: RULE_WARNING_MESSAGE, fix(fixer) { return [ fixer.replaceTextRange( @@ -121,7 +122,7 @@ export const StringsShouldBeTranslatedWithI18n: Rule.RuleModule = { `{i18n.translate('${translationIdSuggestion}', { defaultMessage: '${val}' })}` ), !hasI18nImportLine && rangeToAddI18nImportLine - ? mode === 'replace' + ? replaceMode === 'replace' ? fixer.replaceTextRange(rangeToAddI18nImportLine, i18nImportLine) : fixer.insertTextAfterRange(rangeToAddI18nImportLine, `\n${i18nImportLine}`) : null, diff --git a/packages/kbn-expandable-flyout/README.md b/packages/kbn-expandable-flyout/README.md index 63a6f9483ead..d5428bd7e4fc 100644 --- a/packages/kbn-expandable-flyout/README.md +++ b/packages/kbn-expandable-flyout/README.md @@ -16,8 +16,12 @@ The flyout is composed of 3 sections: The expandable-flyout package is designed to render a single flyout for an entire plugin. While displaying multiple flyouts might be feasible, it will be a bit complicated, and we recommend instead to build multiple panels, with each their own context to manage their data (for example, take a look at the Security Solution [setup](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/flyout)). The expandable-flyout is making some strict UI design decisions: -- when in collapsed mode (i.e. when only the right/preview section is open), the flyout's width is fixed to the EUI `s` size -- when in expanded mode (i.e. when the left section is opened), the flyout's width is fixed to the EUI `l` size. Internally the right, left and preview sections' widths are set to a hardcoded percentage (40%, 60$ and 40% respectively) +- when in collapsed mode (i.e. when only the right/preview section is open), the flyout's width linearly grows from its minimum value of 380px to its maximum value of 750px +- when in expanded mode (i.e. when the left section is opened), the flyout's width changes depending on the browser's width: + - if the window is smaller than 1600px, the flyout takes the entire browser window (minus 48px of padding on the left) + - for windows bigger than 1600px, the flyout's width is 80% of the entire browser window (with a max width of 1500px for the left section, and 750px for the right section) + +> While the expandable-flyout will work on very small screens, having both the right and left sections visible at the same time will not be a good experience to the user. We recommend only showing the right panel, and therefore handling this situation when you build your panels by considering hiding the actions that could open the left panel (like the expand details button in the [FlyoutNavigation](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx)). ## Package API @@ -54,6 +58,12 @@ Then use the [React UI component](https://github.com/elastic/kibana/tree/main/pa ``` _where `myPanels` is a list of all the panels that can be rendered in the flyout_ +## State persistence + +The expandable flyout offers 2 ways of managing its state: +- the default behavior saves the state of the flyout in the url. This allows the flyout to be automatically reopened when users refresh the browser page, or when users share a url +- the second way (done by setting the `storage` prop to `memory`) stores the state of the flyout in memory. This means that the flyout will not be reopened when users refresh the browser page, or when users share a url + ## Terminology diff --git a/packages/kbn-expandable-flyout/index.ts b/packages/kbn-expandable-flyout/index.ts index 5a9094d6dbac..6de82033af04 100644 --- a/packages/kbn-expandable-flyout/index.ts +++ b/packages/kbn-expandable-flyout/index.ts @@ -7,13 +7,12 @@ */ export { ExpandableFlyout } from './src'; -export { - ExpandableFlyoutProvider, - useExpandableFlyoutContext, - type ExpandableFlyoutContext, -} from './src/context'; -export type { ExpandableFlyoutApi } from './src/context'; +export { useExpandableFlyoutContext, type ExpandableFlyoutContext } from './src/context'; + +export { ExpandableFlyoutProvider } from './src/provider'; export type { ExpandableFlyoutProps } from './src'; export type { FlyoutPanelProps, PanelPath } from './src/types'; + +export { EXPANDABLE_FLYOUT_URL_KEY } from './src/constants'; diff --git a/packages/kbn-expandable-flyout/src/components/left_section.tsx b/packages/kbn-expandable-flyout/src/components/left_section.tsx index 1d2a4a7eeaba..37cc0564d22e 100644 --- a/packages/kbn-expandable-flyout/src/components/left_section.tsx +++ b/packages/kbn-expandable-flyout/src/components/left_section.tsx @@ -26,7 +26,7 @@ interface LeftSectionProps { */ export const LeftSection: React.FC = ({ component, width }: LeftSectionProps) => { const style = useMemo( - () => ({ height: '100%', width: `${width * 100}%` }), + () => ({ height: '100%', width: `${width}px` }), [width] ); return ( diff --git a/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx b/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx index f365c8f29962..69bdd7050e64 100644 --- a/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx +++ b/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx @@ -8,15 +8,16 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { PreviewSection } from './preview_section'; +import { PreviewBanner, PreviewSection } from './preview_section'; import { PREVIEW_SECTION_BACK_BUTTON_TEST_ID, PREVIEW_SECTION_CLOSE_BUTTON_TEST_ID, + PREVIEW_SECTION_TEST_ID, } from './test_ids'; -import { ExpandableFlyoutContext } from '../context'; +import { ExpandableFlyoutContext, ExpandableFlyoutContextValue } from '../context'; describe('PreviewSection', () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: {}, left: {}, @@ -26,16 +27,17 @@ describe('PreviewSection', () => { }, ], }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; + + const component =
    {'component'}
    ; + const left = 500; it('should render close button in header', () => { - const component =
    {'component'}
    ; - const width = 500; const showBackButton = false; const { getByTestId } = render( - + ); @@ -43,16 +45,43 @@ describe('PreviewSection', () => { }); it('should render back button in header', () => { - const component =
    {'component'}
    ; - const width = 500; const showBackButton = true; const { getByTestId } = render( - + ); expect(getByTestId(PREVIEW_SECTION_BACK_BUTTON_TEST_ID)).toBeInTheDocument(); }); + + it('should render banner', () => { + const showBackButton = false; + const title = 'test'; + const banner: PreviewBanner = { + title, + backgroundColor: 'primary', + textColor: 'red', + }; + + const { getByTestId, getByText } = render( + + + + ); + + expect(getByTestId(`${PREVIEW_SECTION_TEST_ID}BannerPanel`)).toHaveClass( + `euiPanel--${banner.backgroundColor}` + ); + expect(getByTestId(`${PREVIEW_SECTION_TEST_ID}BannerText`)).toHaveStyle( + `color: ${banner.textColor}` + ); + expect(getByText(title)).toBeInTheDocument(); + }); }); diff --git a/packages/kbn-expandable-flyout/src/components/preview_section.tsx b/packages/kbn-expandable-flyout/src/components/preview_section.tsx index 1cc2243d6584..ae96bdb7ce18 100644 --- a/packages/kbn-expandable-flyout/src/components/preview_section.tsx +++ b/packages/kbn-expandable-flyout/src/components/preview_section.tsx @@ -65,9 +65,9 @@ interface PreviewSectionProps { */ component: React.ReactElement; /** - * Width used when rendering the panel + * Left position used when rendering the panel */ - width: number; + leftPosition: number; /** * Display the back button in the header */ @@ -85,12 +85,13 @@ interface PreviewSectionProps { export const PreviewSection: React.FC = ({ component, showBackButton, - width, + leftPosition, banner, }: PreviewSectionProps) => { const { euiTheme } = useEuiTheme(); const { closePreviewPanel, previousPreviewPanel } = useExpandableFlyoutContext(); - const left = `${(1 - width) * 100}%`; + + const left = leftPosition + 4; const closeButton = ( @@ -103,7 +104,7 @@ export const PreviewSection: React.FC = ({ ); const header = showBackButton ? ( - + = ({ {closeButton} ) : ( - {closeButton} + + {closeButton} + ); return (
    {isPreviewBanner(banner) && ( - - + + {banner.title} diff --git a/packages/kbn-expandable-flyout/src/components/right_section.tsx b/packages/kbn-expandable-flyout/src/components/right_section.tsx index 6e7e94dc1404..ae6cad5c7e9f 100644 --- a/packages/kbn-expandable-flyout/src/components/right_section.tsx +++ b/packages/kbn-expandable-flyout/src/components/right_section.tsx @@ -29,7 +29,7 @@ export const RightSection: React.FC = ({ width, }: RightSectionProps) => { const style = useMemo( - () => ({ height: '100%', width: `${width * 100}%` }), + () => ({ height: '100%', width: `${width}px` }), [width] ); diff --git a/packages/kbn-expandable-flyout/src/constants.ts b/packages/kbn-expandable-flyout/src/constants.ts new file mode 100644 index 000000000000..4ee20ebb8e8f --- /dev/null +++ b/packages/kbn-expandable-flyout/src/constants.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const EXPANDABLE_FLYOUT_URL_KEY = 'eventFlyout' as const; diff --git a/packages/kbn-expandable-flyout/src/context.tsx b/packages/kbn-expandable-flyout/src/context.tsx index 9738c2a4c867..6deb5d2bede3 100644 --- a/packages/kbn-expandable-flyout/src/context.tsx +++ b/packages/kbn-expandable-flyout/src/context.tsx @@ -6,202 +6,19 @@ * Side Public License, v 1. */ -import React, { - createContext, - useCallback, - useContext, - useEffect, - useImperativeHandle, - useMemo, - useReducer, -} from 'react'; -import { ActionType } from './actions'; -import { reducer, State } from './reducer'; -import type { FlyoutPanelProps } from './types'; -import { initialState } from './reducer'; +import { createContext, useContext } from 'react'; +import { type ExpandableFlyoutContextValue } from './types'; -export interface ExpandableFlyoutContext { - /** - * Right, left and preview panels - */ - panels: State; - /** - * Open the flyout with left, right and/or preview panels - */ - openFlyout: (panels: { - left?: FlyoutPanelProps; - right?: FlyoutPanelProps; - preview?: FlyoutPanelProps; - }) => void; - /** - * Replaces the current right panel with a new one - */ - openRightPanel: (panel: FlyoutPanelProps) => void; - /** - * Replaces the current left panel with a new one - */ - openLeftPanel: (panel: FlyoutPanelProps) => void; - /** - * Add a new preview panel to the list of current preview panels - */ - openPreviewPanel: (panel: FlyoutPanelProps) => void; - /** - * Closes right panel - */ - closeRightPanel: () => void; - /** - * Closes left panel - */ - closeLeftPanel: () => void; - /** - * Closes all preview panels - */ - closePreviewPanel: () => void; - /** - * Go back to previous preview panel - */ - previousPreviewPanel: () => void; - /** - * Close all panels and closes flyout - */ - closeFlyout: () => void; -} +export type { ExpandableFlyoutContextValue }; -export const ExpandableFlyoutContext = createContext( +export const ExpandableFlyoutContext = createContext( undefined ); -export type ExpandableFlyoutApi = Pick & { - getState: () => State; -}; - -export interface ExpandableFlyoutProviderProps { - /** - * React children - */ - children: React.ReactNode; - /** - * Triggered whenever flyout state changes. You can use it to store it's state somewhere for instance. - */ - onChanges?: (state: State) => void; - /** - * Triggered whenever flyout is closed. This is independent from the onChanges above. - */ - onClosePanels?: () => void; -} - -/** - * Wrap your plugin with this context for the ExpandableFlyout React component. - */ -export const ExpandableFlyoutProvider = React.forwardRef< - ExpandableFlyoutApi, - ExpandableFlyoutProviderProps ->(({ children, onChanges = () => {}, onClosePanels = () => {} }, ref) => { - const [state, dispatch] = useReducer(reducer, initialState); - - useEffect(() => { - const closed = !state.right; - if (closed) { - // manual close is singalled via separate callback - return; - } - - onChanges(state); - }, [state, onChanges]); - - const openPanels = useCallback( - ({ - right, - left, - preview, - }: { - right?: FlyoutPanelProps; - left?: FlyoutPanelProps; - preview?: FlyoutPanelProps; - }) => dispatch({ type: ActionType.openFlyout, payload: { left, right, preview } }), - [dispatch] - ); - - const openRightPanel = useCallback( - (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openRightPanel, payload: panel }), - [] - ); - - const openLeftPanel = useCallback( - (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openLeftPanel, payload: panel }), - [] - ); - - const openPreviewPanel = useCallback( - (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openPreviewPanel, payload: panel }), - [] - ); - - const closeRightPanel = useCallback(() => dispatch({ type: ActionType.closeRightPanel }), []); - - const closeLeftPanel = useCallback(() => dispatch({ type: ActionType.closeLeftPanel }), []); - - const closePreviewPanel = useCallback(() => dispatch({ type: ActionType.closePreviewPanel }), []); - - const previousPreviewPanel = useCallback( - () => dispatch({ type: ActionType.previousPreviewPanel }), - [] - ); - - const closePanels = useCallback(() => { - dispatch({ type: ActionType.closeFlyout }); - onClosePanels(); - }, [onClosePanels]); - - useImperativeHandle( - ref, - () => { - return { - openFlyout: openPanels, - getState: () => state, - }; - }, - [openPanels, state] - ); - - const contextValue = useMemo( - () => ({ - panels: state, - openFlyout: openPanels, - openRightPanel, - openLeftPanel, - openPreviewPanel, - closeRightPanel, - closeLeftPanel, - closePreviewPanel, - closeFlyout: closePanels, - previousPreviewPanel, - }), - [ - state, - openPanels, - openRightPanel, - openLeftPanel, - openPreviewPanel, - closeRightPanel, - closeLeftPanel, - closePreviewPanel, - closePanels, - previousPreviewPanel, - ] - ); - - return ( - - {children} - - ); -}); - /** * Retrieve context's properties */ -export const useExpandableFlyoutContext = (): ExpandableFlyoutContext => { +export const useExpandableFlyoutContext = (): ExpandableFlyoutContextValue => { const contextValue = useContext(ExpandableFlyoutContext); if (!contextValue) { diff --git a/packages/kbn-expandable-flyout/src/context/memory_state_provider.tsx b/packages/kbn-expandable-flyout/src/context/memory_state_provider.tsx new file mode 100644 index 000000000000..f70ae9dbbe8d --- /dev/null +++ b/packages/kbn-expandable-flyout/src/context/memory_state_provider.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC, PropsWithChildren, useCallback, useMemo, useReducer } from 'react'; +import { ActionType } from '../actions'; +import { reducer } from '../reducer'; +import type { ExpandableFlyoutContextValue, FlyoutPanelProps } from '../types'; +import { initialState } from '../reducer'; +import { ExpandableFlyoutContext } from '../context'; + +/** + * In-memory state provider for the expandable flyout, for cases when we don't want changes to be persisted + * in the url. + */ +export const MemoryStateProvider: FC> = ({ children }) => { + const [state, dispatch] = useReducer(reducer, initialState); + + const openPanels = useCallback( + ({ + right, + left, + preview, + }: { + right?: FlyoutPanelProps; + left?: FlyoutPanelProps; + preview?: FlyoutPanelProps; + }) => dispatch({ type: ActionType.openFlyout, payload: { left, right, preview } }), + [dispatch] + ); + + const openRightPanel = useCallback( + (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openRightPanel, payload: panel }), + [] + ); + + const openLeftPanel = useCallback( + (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openLeftPanel, payload: panel }), + [] + ); + + const openPreviewPanel = useCallback( + (panel: FlyoutPanelProps) => dispatch({ type: ActionType.openPreviewPanel, payload: panel }), + [] + ); + + const closeRightPanel = useCallback(() => dispatch({ type: ActionType.closeRightPanel }), []); + + const closeLeftPanel = useCallback(() => dispatch({ type: ActionType.closeLeftPanel }), []); + + const closePreviewPanel = useCallback(() => dispatch({ type: ActionType.closePreviewPanel }), []); + + const previousPreviewPanel = useCallback( + () => dispatch({ type: ActionType.previousPreviewPanel }), + [] + ); + + const closePanels = useCallback(() => { + dispatch({ type: ActionType.closeFlyout }); + }, []); + + const contextValue: ExpandableFlyoutContextValue = useMemo( + () => ({ + panels: state, + openFlyout: openPanels, + openRightPanel, + openLeftPanel, + openPreviewPanel, + closeRightPanel, + closeLeftPanel, + closePreviewPanel, + closeFlyout: closePanels, + previousPreviewPanel, + }), + [ + state, + openPanels, + openRightPanel, + openLeftPanel, + openPreviewPanel, + closeRightPanel, + closeLeftPanel, + closePreviewPanel, + closePanels, + previousPreviewPanel, + ] + ); + + return ( + + {children} + + ); +}; diff --git a/packages/kbn-expandable-flyout/src/context/url_state_provider.tsx b/packages/kbn-expandable-flyout/src/context/url_state_provider.tsx new file mode 100644 index 000000000000..e6f81e23d2fb --- /dev/null +++ b/packages/kbn-expandable-flyout/src/context/url_state_provider.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC, PropsWithChildren, useCallback, useMemo } from 'react'; +import { FlyoutPanelProps, ExpandableFlyoutContextValue } from '../types'; +import { useRightPanel } from '../hooks/use_right_panel'; +import { useLeftPanel } from '../hooks/use_left_panel'; +import { usePreviewPanel } from '../hooks/use_preview_panel'; +import { ExpandableFlyoutContext } from '../context'; +import { State } from '../reducer'; + +/** + * Private component that manages flyout state with url query params + */ +export const UrlStateProvider: FC> = ({ children }) => { + const { setRightPanelState, rightPanelState } = useRightPanel(); + const { setLeftPanelState, leftPanelState } = useLeftPanel(); + const { previewState, setPreviewState } = usePreviewPanel(); + + const panels: State = useMemo( + () => ({ + left: leftPanelState, + right: rightPanelState, + preview: previewState || [], + }), + [leftPanelState, previewState, rightPanelState] + ); + + const openPanels = useCallback( + ({ + right, + left, + preview, + }: { + right?: FlyoutPanelProps; + left?: FlyoutPanelProps; + preview?: FlyoutPanelProps; + }) => { + setRightPanelState(right); + setLeftPanelState(left); + setPreviewState(preview ? [preview] : []); + }, + [setRightPanelState, setLeftPanelState, setPreviewState] + ); + + const openRightPanel = useCallback( + (panel: FlyoutPanelProps) => { + setRightPanelState(panel); + }, + [setRightPanelState] + ); + + const openLeftPanel = useCallback( + (panel: FlyoutPanelProps) => setLeftPanelState(panel), + [setLeftPanelState] + ); + + const openPreviewPanel = useCallback( + (panel: FlyoutPanelProps) => setPreviewState([...(previewState ?? []), panel]), + [previewState, setPreviewState] + ); + + const closeRightPanel = useCallback(() => setRightPanelState(undefined), [setRightPanelState]); + + const closeLeftPanel = useCallback(() => setLeftPanelState(undefined), [setLeftPanelState]); + + const closePreviewPanel = useCallback(() => setPreviewState([]), [setPreviewState]); + + const previousPreviewPanel = useCallback( + () => setPreviewState(previewState?.slice(0, previewState.length - 1)), + [previewState, setPreviewState] + ); + + const closePanels = useCallback(() => { + setRightPanelState(undefined); + setLeftPanelState(undefined); + setPreviewState([]); + }, [setRightPanelState, setLeftPanelState, setPreviewState]); + + const contextValue: ExpandableFlyoutContextValue = useMemo( + () => ({ + panels, + openFlyout: openPanels, + openRightPanel, + openLeftPanel, + openPreviewPanel, + closeRightPanel, + closeLeftPanel, + closePreviewPanel, + closeFlyout: closePanels, + previousPreviewPanel, + }), + [ + panels, + openPanels, + openRightPanel, + openLeftPanel, + openPreviewPanel, + closeRightPanel, + closeLeftPanel, + closePreviewPanel, + closePanels, + previousPreviewPanel, + ] + ); + + return ( + + {children} + + ); +}; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_left_panel.ts b/packages/kbn-expandable-flyout/src/hooks/use_left_panel.ts new file mode 100644 index 000000000000..2a3e4212a06f --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_left_panel.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useUrlState } from '@kbn/url-state'; +import { EXPANDABLE_FLYOUT_URL_KEY } from '../constants'; +import { FlyoutPanelProps } from '../types'; + +/** + * This hook stores state in the URL + */ +export const useLeftPanel = () => { + const [leftPanelState, setLeftPanelState] = useUrlState( + EXPANDABLE_FLYOUT_URL_KEY, + 'leftPanel' + ); + + return { leftPanelState, setLeftPanelState } as const; +}; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_preview_panel.ts b/packages/kbn-expandable-flyout/src/hooks/use_preview_panel.ts new file mode 100644 index 000000000000..5e9cfddb93ba --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_preview_panel.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useUrlState } from '@kbn/url-state'; +import { EXPANDABLE_FLYOUT_URL_KEY } from '../constants'; +import { FlyoutPanelProps } from '../types'; + +/** + * This hook stores state in the URL + */ +export const usePreviewPanel = () => { + const [previewState, setPreviewState] = useUrlState( + EXPANDABLE_FLYOUT_URL_KEY, + 'preview' + ); + + return { previewState, setPreviewState } as const; +}; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_right_panel.ts b/packages/kbn-expandable-flyout/src/hooks/use_right_panel.ts new file mode 100644 index 000000000000..2bce75d65f23 --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_right_panel.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useUrlState } from '@kbn/url-state'; +import { EXPANDABLE_FLYOUT_URL_KEY } from '../constants'; +import { FlyoutPanelProps } from '../types'; + +/** + * This hook stores state in the URL + */ +export const useRightPanel = () => { + const [rightPanelState, setRightPanelState] = useUrlState( + EXPANDABLE_FLYOUT_URL_KEY, + 'rightPanel' + ); + + return { rightPanelState, setRightPanelState } as const; +}; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.test.ts b/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.test.ts new file mode 100644 index 000000000000..cc8f7e0f283e --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.test.ts @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import type { RenderHookResult } from '@testing-library/react-hooks'; +import type { UserSectionsSizesParams, UserSectionsSizesResult } from './use_sections_sizes'; +import { useSectionSizes } from './use_sections_sizes'; + +describe('useSectionSizes', () => { + let hookResult: RenderHookResult; + + describe('Right section', () => { + it('should return 0 for right section if it is hidden', () => { + const initialProps = { + windowWidth: 350, + showRight: false, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 0, + leftSectionWidth: 0, + flyoutWidth: '0px', + previewSectionLeft: 0, + }); + }); + + it('should return the window width for right section size for tiny screen', () => { + const initialProps = { + windowWidth: 350, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 350, + leftSectionWidth: 0, + flyoutWidth: '350px', + previewSectionLeft: 0, + }); + }); + + it('should return 380 for right section size for medium screen', () => { + const initialProps = { + windowWidth: 600, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 0, + flyoutWidth: '380px', + previewSectionLeft: 0, + }); + }); + + it('should return 500 for right section size for large screen', () => { + const initialProps = { + windowWidth: 1300, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current.rightSectionWidth).toBeGreaterThan(420); + expect(hookResult.result.current.rightSectionWidth).toBeLessThan(750); + expect(hookResult.result.current.leftSectionWidth).toEqual(0); + expect(hookResult.result.current.flyoutWidth).toEqual( + `${hookResult.result.current.rightSectionWidth}px` + ); + expect(hookResult.result.current.previewSectionLeft).toEqual(0); + }); + + it('should return 750 for right section size for very large screen', () => { + const initialProps = { + windowWidth: 2500, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 750, + leftSectionWidth: 0, + flyoutWidth: '750px', + previewSectionLeft: 0, + }); + }); + }); + + describe('Left section', () => { + it('should return 0 for left section if it is hidden', () => { + const initialProps = { + windowWidth: 500, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 0, + flyoutWidth: '380px', + previewSectionLeft: 0, + }); + }); + + it('should return the remaining for left section', () => { + const initialProps = { + windowWidth: 500, + showRight: true, + showLeft: true, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 72, + flyoutWidth: '452px', + previewSectionLeft: 0, + }); + }); + + it('should return 80% of remaining for left section', () => { + const initialProps = { + windowWidth: 2500, + showRight: true, + showLeft: true, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current.rightSectionWidth).toEqual(750); + expect(hookResult.result.current.leftSectionWidth).toEqual((2500 - 750) * 0.8); + expect(hookResult.result.current.flyoutWidth).toEqual( + `${ + hookResult.result.current.rightSectionWidth + hookResult.result.current.leftSectionWidth + }px` + ); + expect(hookResult.result.current.previewSectionLeft).toEqual(0); + }); + + it('should return max out at 1500px for really big screens', () => { + const initialProps = { + windowWidth: 2700, + showRight: true, + showLeft: true, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current.rightSectionWidth).toEqual(750); + expect(hookResult.result.current.leftSectionWidth).toEqual(1500); + expect(hookResult.result.current.flyoutWidth).toEqual( + `${ + hookResult.result.current.rightSectionWidth + hookResult.result.current.leftSectionWidth + }px` + ); + expect(hookResult.result.current.previewSectionLeft).toEqual(0); + }); + }); + + describe('Preview section', () => { + it('should return the 0 for preview section if it is hidden', () => { + const initialProps = { + windowWidth: 600, + showRight: true, + showLeft: false, + showPreview: false, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 0, + flyoutWidth: '380px', + previewSectionLeft: 0, + }); + }); + + it('should return the 0 for preview section when left section is hidden', () => { + const initialProps = { + windowWidth: 600, + showRight: true, + showLeft: false, + showPreview: true, + }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 0, + flyoutWidth: '380px', + previewSectionLeft: 0, + }); + }); + + it('should return for preview section when left section is visible', () => { + const initialProps = { windowWidth: 600, showRight: true, showLeft: true, showPreview: true }; + hookResult = renderHook((props: UserSectionsSizesParams) => useSectionSizes(props), { + initialProps, + }); + + expect(hookResult.result.current).toEqual({ + rightSectionWidth: 380, + leftSectionWidth: 172, + flyoutWidth: '552px', + previewSectionLeft: 172, + }); + }); + }); +}); diff --git a/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.ts b/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.ts new file mode 100644 index 000000000000..94b10cde6e1c --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_sections_sizes.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +const RIGHT_SECTION_MIN_WIDTH = 380; +const MIN_RESOLUTION_BREAKPOINT = 992; +const RIGHT_SECTION_MAX_WIDTH = 750; +const MAX_RESOLUTION_BREAKPOINT = 1920; + +const LEFT_SECTION_MAX_WIDTH = 1500; + +const FULL_WIDTH_BREAKPOINT = 1600; +const FULL_WIDTH_PADDING = 48; + +export interface UserSectionsSizesParams { + /** + * The width of the browser window + */ + windowWidth: number; + /** + * True if the right section is visible, false otherwise + */ + showRight: boolean; + /** + * True if the left section is visible, false otherwise + */ + showLeft: boolean; + /** + * True if the preview section is visible, false otherwise + */ + showPreview: boolean; +} + +export interface UserSectionsSizesResult { + /** + * Width of the right section in pixels + */ + rightSectionWidth: number; + /** + * Width of the left section in pixels + */ + leftSectionWidth: number; + /** + * Width of the flyout in pixels + */ + flyoutWidth: string; + /** + * Left position of the preview section in pixels + */ + previewSectionLeft: number; +} + +/** + * Hook that calculate the different width for the sections of the flyout and the flyout itself + */ +export const useSectionSizes = ({ + windowWidth, + showRight, + showLeft, + showPreview, +}: UserSectionsSizesParams): UserSectionsSizesResult => { + let rightSectionWidth: number = 0; + if (showRight) { + if (windowWidth < MIN_RESOLUTION_BREAKPOINT) { + // the right section's width will grow from 380px (at 992px resolution) while handling tiny screens by not going smaller than the window width + rightSectionWidth = Math.min(RIGHT_SECTION_MIN_WIDTH, windowWidth); + } else { + const ratioWidth = + (RIGHT_SECTION_MAX_WIDTH - RIGHT_SECTION_MIN_WIDTH) * + ((windowWidth - MIN_RESOLUTION_BREAKPOINT) / + (MAX_RESOLUTION_BREAKPOINT - MIN_RESOLUTION_BREAKPOINT)); + + // the right section's width will grow to 750px (at 1920px resolution) and will never go bigger than 750px in higher resolutions + rightSectionWidth = Math.min(RIGHT_SECTION_MIN_WIDTH + ratioWidth, RIGHT_SECTION_MAX_WIDTH); + } + } + + let leftSectionWidth: number = 0; + if (showLeft) { + // the left section's width will be nearly the remaining space for resolution lower than 1600px + if (windowWidth <= FULL_WIDTH_BREAKPOINT) { + leftSectionWidth = windowWidth - rightSectionWidth - FULL_WIDTH_PADDING; + } else { + // the left section's width will be taking 80% of the remaining space for resolution higher than 1600px, while never going bigger than 1500px + leftSectionWidth = Math.min( + ((windowWidth - rightSectionWidth) * 80) / 100, + LEFT_SECTION_MAX_WIDTH + ); + } + } + + const flyoutWidth: string = + showRight && showLeft ? `${rightSectionWidth + leftSectionWidth}px` : `${rightSectionWidth}px`; + + // preview section's width should only be similar to the right section. + // Though because the preview is rendered with an absolute position in the flyout, we calculate its left position instead of the width + let previewSectionLeft: number = 0; + if (showPreview) { + // the preview section starts where the left section ends + previewSectionLeft = leftSectionWidth; + } + + return { + rightSectionWidth, + leftSectionWidth, + flyoutWidth, + previewSectionLeft, + }; +}; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_window_size.test.ts b/packages/kbn-expandable-flyout/src/hooks/use_window_size.test.ts new file mode 100644 index 000000000000..cb9f44d36e2f --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_window_size.test.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useWindowSize } from './use_window_size'; + +describe('useWindowSize', () => { + it('should return the window size', () => { + const hookResult = renderHook(() => useWindowSize()); + expect(hookResult.result.current).toEqual(1024); + }); +}); diff --git a/packages/kbn-expandable-flyout/src/hooks/use_window_size.ts b/packages/kbn-expandable-flyout/src/hooks/use_window_size.ts new file mode 100644 index 000000000000..0d773ad02c1c --- /dev/null +++ b/packages/kbn-expandable-flyout/src/hooks/use_window_size.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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useLayoutEffect, useState } from 'react'; + +/** + * Hook that returns the browser window width + */ +export const useWindowSize = (): number => { + const [width, setWidth] = useState(0); + useLayoutEffect(() => { + function updateSize() { + setWidth(window.innerWidth); + } + window.addEventListener('resize', updateSize); + updateSize(); + return () => window.removeEventListener('resize', updateSize); + }, []); + return width; +}; diff --git a/packages/kbn-expandable-flyout/src/index.stories.tsx b/packages/kbn-expandable-flyout/src/index.stories.tsx index 2bbc26c3363f..615621bf9a57 100644 --- a/packages/kbn-expandable-flyout/src/index.stories.tsx +++ b/packages/kbn-expandable-flyout/src/index.stories.tsx @@ -19,7 +19,7 @@ import { EuiTitle, } from '@elastic/eui'; import { ExpandableFlyout } from '.'; -import { ExpandableFlyoutContext } from './context'; +import { ExpandableFlyoutContext, ExpandableFlyoutContextValue } from './context'; export default { component: ExpandableFlyout, @@ -100,7 +100,7 @@ const registeredPanels = [ ]; export const Right: Story = () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: { id: 'right', @@ -109,7 +109,7 @@ export const Right: Story = () => { preview: [], }, closeFlyout: () => window.alert('closeFlyout api'), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; return ( @@ -119,7 +119,7 @@ export const Right: Story = () => { }; export const Left: Story = () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: { id: 'right', @@ -130,7 +130,7 @@ export const Left: Story = () => { preview: [], }, closeFlyout: () => window.alert('closeFlyout api'), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; return ( @@ -140,7 +140,7 @@ export const Left: Story = () => { }; export const Preview: Story = () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: { id: 'right', @@ -156,7 +156,7 @@ export const Preview: Story = () => { }, closePreviewPanel: () => window.alert('closePreviewPanel api'), closeFlyout: () => window.alert('closeFlyout api'), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; return ( @@ -166,7 +166,7 @@ export const Preview: Story = () => { }; export const MultiplePreviews: Story = () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: { id: 'right', @@ -186,7 +186,7 @@ export const MultiplePreviews: Story = () => { closePreviewPanel: () => window.alert('closePreviewPanel api'), previousPreviewPanel: () => window.alert('previousPreviewPanel api'), closeFlyout: () => window.alert('closeFlyout api'), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; return ( diff --git a/packages/kbn-expandable-flyout/src/index.test.tsx b/packages/kbn-expandable-flyout/src/index.test.tsx index c6da99ad0177..46ae2dce508f 100644 --- a/packages/kbn-expandable-flyout/src/index.test.tsx +++ b/packages/kbn-expandable-flyout/src/index.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { Panel } from './types'; +import { ExpandableFlyoutContextValue, Panel } from './types'; import { ExpandableFlyout } from '.'; import { LEFT_SECTION_TEST_ID, @@ -26,13 +26,13 @@ describe('ExpandableFlyout', () => { ]; it(`shouldn't render flyout if no panels`, () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: undefined, left: undefined, preview: [], }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const result = render( @@ -44,7 +44,7 @@ describe('ExpandableFlyout', () => { }); it('should render right section', () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: { id: 'key', @@ -52,7 +52,7 @@ describe('ExpandableFlyout', () => { left: {}, preview: [], }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId } = render( @@ -64,7 +64,7 @@ describe('ExpandableFlyout', () => { }); it('should render left section', () => { - const context: ExpandableFlyoutContext = { + const context = { panels: { right: {}, left: { @@ -72,7 +72,7 @@ describe('ExpandableFlyout', () => { }, preview: [], }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId } = render( @@ -84,7 +84,7 @@ describe('ExpandableFlyout', () => { }); it('should render preview section', () => { - const context: ExpandableFlyoutContext = { + const context: ExpandableFlyoutContextValue = { panels: { right: {}, left: {}, @@ -94,7 +94,7 @@ describe('ExpandableFlyout', () => { }, ], }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId } = render( diff --git a/packages/kbn-expandable-flyout/src/index.tsx b/packages/kbn-expandable-flyout/src/index.tsx index d5a1bff46439..e7f6c3fcafb2 100644 --- a/packages/kbn-expandable-flyout/src/index.tsx +++ b/packages/kbn-expandable-flyout/src/index.tsx @@ -6,9 +6,11 @@ * Side Public License, v 1. */ -import React, { useCallback, useMemo } from 'react'; -import type { EuiFlyoutProps } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { EuiFlyoutProps } from '@elastic/eui'; import { EuiFlexGroup, EuiFlyout } from '@elastic/eui'; +import { useSectionSizes } from './hooks/use_sections_sizes'; +import { useWindowSize } from './hooks/use_window_size'; import { useExpandableFlyoutContext } from './context'; import { PreviewSection } from './components/preview_section'; import { RightSection } from './components/right_section'; @@ -16,19 +18,15 @@ import type { FlyoutPanelProps, Panel } from './types'; import { LeftSection } from './components/left_section'; import { isPreviewBanner } from './components/preview_section'; +const flyoutInnerStyles = { height: '100%' }; + export interface ExpandableFlyoutProps extends Omit { /** * List of all registered panels available for render */ registeredPanels: Panel[]; - /** - * Propagate out EuiFlyout onClose event - */ - handleOnFlyoutClosed?: () => void; } -const flyoutInnerStyles = { height: '100%' }; - /** * Expandable flyout UI React component. * Displays 3 sections (right, left, preview) depending on the panels in the context. @@ -38,16 +36,13 @@ const flyoutInnerStyles = { height: '100%' }; */ export const ExpandableFlyout: React.FC = ({ registeredPanels, - handleOnFlyoutClosed, ...flyoutProps }) => { - const { panels, closeFlyout } = useExpandableFlyoutContext(); - const { left, right, preview } = panels; + const windowWidth = useWindowSize(); + + const { closeFlyout, panels } = useExpandableFlyoutContext(); - const onClose = useCallback(() => { - if (handleOnFlyoutClosed) handleOnFlyoutClosed(); - closeFlyout(); - }, [closeFlyout, handleOnFlyoutClosed]); + const { left, right, preview } = panels; const leftSection = useMemo( () => registeredPanels.find((panel) => panel.key === left?.id), @@ -65,38 +60,44 @@ export const ExpandableFlyout: React.FC = ({ ? mostRecentPreview?.params?.banner : undefined; - const showBackButton = preview && preview.length > 1; + const showBackButton = !!preview && preview.length > 1; const previewSection = useMemo( () => registeredPanels.find((panel) => panel.key === mostRecentPreview?.id), [mostRecentPreview, registeredPanels] ); - const hideFlyout = !left && !right && !preview.length; + const showRight = rightSection != null && right != null; + const showLeft = leftSection != null && left != null; + const showPreview = previewSection != null && preview != null; + const { rightSectionWidth, leftSectionWidth, flyoutWidth, previewSectionLeft } = useSectionSizes({ + windowWidth, + showRight, + showLeft, + showPreview, + }); + + const hideFlyout = !left && !right && !preview?.length; if (hideFlyout) { return null; } - const flyoutWidth: string = leftSection && rightSection ? 'l' : 's'; - const rightSectionWidth: number = leftSection ? 0.4 : 1; - const leftSectionWidth: number = 0.6; - const previewSectionWidth: number = leftSection ? 0.4 : 1; - return ( - + - {leftSection && left ? ( + {showLeft ? ( ) : null} - {rightSection && right ? ( + {showRight ? ( = ({ ) : null} - {previewSection && preview ? ( + {showPreview ? ( ) : null} diff --git a/packages/kbn-expandable-flyout/src/provider.tsx b/packages/kbn-expandable-flyout/src/provider.tsx new file mode 100644 index 000000000000..a5acc25c13b7 --- /dev/null +++ b/packages/kbn-expandable-flyout/src/provider.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { FC, PropsWithChildren } from 'react'; +import { UrlStateProvider } from './context/url_state_provider'; +import { MemoryStateProvider } from './context/memory_state_provider'; + +interface ExpandableFlyoutProviderProps { + /** + * This allows the user to choose how the flyout storage is handled. + * Url storage syncs current values straight to the browser query string. + */ + storage?: 'url' | 'memory'; +} + +/** + * Wrap your plugin with this context for the ExpandableFlyout React component. + * Storage property allows you to specify how the flyout state works internally. + * With "url", it will be persisted into url and thus allow for deep linking & will survive webpage reloads. + * "memory" is based on useReducer hook. The state is saved internally to the package. which means it will not be + * persisted when sharing url or reloading browser pages. + */ +export const ExpandableFlyoutProvider: FC> = ({ + children, + storage = 'url', +}) => { + if (storage === 'memory') { + return {children}; + } + + return {children}; +}; diff --git a/packages/kbn-expandable-flyout/src/types.ts b/packages/kbn-expandable-flyout/src/types.ts index bfe64c459908..92c4af79024b 100644 --- a/packages/kbn-expandable-flyout/src/types.ts +++ b/packages/kbn-expandable-flyout/src/types.ts @@ -7,6 +7,55 @@ */ import React from 'react'; +import { State } from './reducer'; + +export interface ExpandableFlyoutContextValue { + /** + * Right, left and preview panels + */ + panels: State; + + /** + * Open the flyout with left, right and/or preview panels + */ + openFlyout: (panels: { + left?: FlyoutPanelProps; + right?: FlyoutPanelProps; + preview?: FlyoutPanelProps; + }) => void; + /** + * Replaces the current right panel with a new one + */ + openRightPanel: (panel: FlyoutPanelProps) => void; + /** + * Replaces the current left panel with a new one + */ + openLeftPanel: (panel: FlyoutPanelProps) => void; + /** + * Add a new preview panel to the list of current preview panels + */ + openPreviewPanel: (panel: FlyoutPanelProps) => void; + /** + * Closes right panel + */ + closeRightPanel: () => void; + /** + * Closes left panel + */ + closeLeftPanel: () => void; + /** + * Closes all preview panels + */ + closePreviewPanel: () => void; + /** + * Go back to previous preview panel + */ + previousPreviewPanel: () => void; + /** + * Close all panels and closes flyout + */ + closeFlyout: () => void; +} export interface PanelPath { /** diff --git a/packages/kbn-expandable-flyout/tsconfig.json b/packages/kbn-expandable-flyout/tsconfig.json index d1755389bcdd..9a5dcbaf0304 100644 --- a/packages/kbn-expandable-flyout/tsconfig.json +++ b/packages/kbn-expandable-flyout/tsconfig.json @@ -19,6 +19,7 @@ "target/**/*" ], "kbn_references": [ - "@kbn/i18n" + "@kbn/i18n", + "@kbn/url-state" ] } diff --git a/packages/kbn-generate-csv/src/__snapshots__/generate_csv.test.ts.snap b/packages/kbn-generate-csv/src/__snapshots__/generate_csv.test.ts.snap index da0f6a456064..e38a7427e98d 100644 --- a/packages/kbn-generate-csv/src/__snapshots__/generate_csv.test.ts.snap +++ b/packages/kbn-generate-csv/src/__snapshots__/generate_csv.test.ts.snap @@ -66,6 +66,77 @@ exports[`CsvGenerator formulas escapes formula values in a header, doesn't warn `; exports[`CsvGenerator keeps order of the columns during the scroll 1`] = ` +Array [ + Array [ + "Requesting PIT for: [logstash-*]...", + ], + Array [ + "Opened PIT ID: oju9fs3698s3[39 bytes]", + ], + Array [ + "Executing search request with PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received total hits: 3. Accuracy: unknown.", + ], + Array [ + "Result details: {\\"rawResponse\\":{\\"took\\":1,\\"timed_out\\":false,\\"_shards\\":{\\"total\\":1,\\"successful\\":1,\\"failed\\":0,\\"skipped\\":0},\\"hits\\":{\\"total\\":3,\\"max_score\\":0},\\"pit_id\\":\\"oju9fs3698s3[39 bytes]\\"}}", + ], + Array [ + "Received PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received search_after: [undefined]", + ], + Array [ + "Building CSV header row", + ], + Array [ + "Building 1 CSV data rows", + ], + Array [ + "Executing search request with PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received total hits: 3. Accuracy: unknown.", + ], + Array [ + "Result details: {\\"rawResponse\\":{\\"took\\":1,\\"timed_out\\":false,\\"_shards\\":{\\"total\\":1,\\"successful\\":1,\\"failed\\":0,\\"skipped\\":0},\\"hits\\":{\\"total\\":3,\\"max_score\\":0},\\"pit_id\\":\\"oju9fs3698s3[39 bytes]\\"}}", + ], + Array [ + "Received PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received search_after: [undefined]", + ], + Array [ + "Building 1 CSV data rows", + ], + Array [ + "Executing search request with PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received total hits: 3. Accuracy: unknown.", + ], + Array [ + "Result details: {\\"rawResponse\\":{\\"took\\":1,\\"timed_out\\":false,\\"_shards\\":{\\"total\\":1,\\"successful\\":1,\\"failed\\":0,\\"skipped\\":0},\\"hits\\":{\\"total\\":3,\\"max_score\\":0},\\"pit_id\\":\\"oju9fs3698s3[39 bytes]\\"}}", + ], + Array [ + "Received PIT ID: [oju9fs3698s3[39 bytes]]", + ], + Array [ + "Received search_after: [undefined]", + ], + Array [ + "Building 1 CSV data rows", + ], + Array [ + "Closing PIT oju9fs3698s3[39 bytes]", + ], +] +`; + +exports[`CsvGenerator keeps order of the columns during the scroll 2`] = ` "\\"_id\\",\\"_index\\",\\"_score\\",a,b \\"'-\\",\\"'-\\",\\"'-\\",a1,b1 \\"'-\\",\\"'-\\",\\"'-\\",\\"'-\\",b2 diff --git a/packages/kbn-generate-csv/src/generate_csv.test.ts b/packages/kbn-generate-csv/src/generate_csv.test.ts index 22857f37afda..22269054a61d 100644 --- a/packages/kbn-generate-csv/src/generate_csv.test.ts +++ b/packages/kbn-generate-csv/src/generate_csv.test.ts @@ -393,6 +393,8 @@ describe('CsvGenerator', () => { }) ); + const debugLogSpy = jest.spyOn(mockLogger, 'debug'); + const generateCsv = new CsvGenerator( createMockJob({ searchSource: {}, columns: [] }), mockConfig, @@ -411,6 +413,8 @@ describe('CsvGenerator', () => { ); await generateCsv.generateData(); + expect(debugLogSpy.mock.calls).toMatchSnapshot(); + expect(content).toMatchSnapshot(); }); @@ -896,6 +900,82 @@ describe('CsvGenerator', () => { `); }); + describe('debug logging', () => { + it('logs the the total hits relation if relation is provided', async () => { + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + took: 1, + timed_out: false, + pit_id: mockPitId, + _shards: { total: 1, successful: 1, failed: 0, skipped: 0 }, + hits: { hits: [], total: { relation: 'eq', value: 12345 }, max_score: 0 }, + }, + }) + ); + + const debugLogSpy = jest.spyOn(mockLogger, 'debug'); + + const generateCsv = new CsvGenerator( + createMockJob({ columns: ['date', 'ip', 'message'] }), + mockConfig, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, + new CancellationToken(), + mockLogger, + stream + ); + + await generateCsv.generateData(); + + expect(debugLogSpy).toHaveBeenCalledWith('Received total hits: 12345. Accuracy: eq.'); + }); + + it('logs the the total hits relation as "unknown" if relation is not provided', async () => { + mockDataClient.search = jest.fn().mockImplementation(() => + Rx.of({ + rawResponse: { + took: 1, + timed_out: false, + pit_id: mockPitId, + _shards: { total: 1, successful: 1, failed: 0, skipped: 0 }, + hits: { hits: [], total: 12345, max_score: 0 }, + }, + }) + ); + + const debugLogSpy = jest.spyOn(mockLogger, 'debug'); + + const generateCsv = new CsvGenerator( + createMockJob({ columns: ['date', 'ip', 'message'] }), + mockConfig, + { + es: mockEsClient, + data: mockDataClient, + uiSettings: uiSettingsClient, + }, + { + searchSourceStart: mockSearchSourceService, + fieldFormatsRegistry: mockFieldFormatsRegistry, + }, + new CancellationToken(), + mockLogger, + stream + ); + + await generateCsv.generateData(); + + expect(debugLogSpy).toHaveBeenCalledWith('Received total hits: 12345. Accuracy: unknown.'); + }); + }); + it('will return partial data if the scroll or search fails', async () => { mockDataClient.search = jest.fn().mockImplementation(() => { throw new esErrors.ResponseError({ diff --git a/packages/kbn-generate-csv/src/generate_csv.ts b/packages/kbn-generate-csv/src/generate_csv.ts index 59e69e9989c8..22e2916bf6fd 100644 --- a/packages/kbn-generate-csv/src/generate_csv.ts +++ b/packages/kbn-generate-csv/src/generate_csv.ts @@ -11,7 +11,11 @@ import type { Writable } from 'stream'; import { errors as esErrors, estypes } from '@elastic/elasticsearch'; import type { IScopedClusterClient, IUiSettingsClient, Logger } from '@kbn/core/server'; -import type { ISearchSource, ISearchStartSearchSource } from '@kbn/data-plugin/common'; +import type { + IKibanaSearchResponse, + ISearchSource, + ISearchStartSearchSource, +} from '@kbn/data-plugin/common'; import { ES_SEARCH_STRATEGY, cellHasFormulas, tabifyDocs } from '@kbn/data-plugin/common'; import type { IScopedSearchClient } from '@kbn/data-plugin/server'; import type { Datatable } from '@kbn/expressions-plugin/server'; @@ -94,6 +98,38 @@ export class CsvGenerator { return pitId; } + /** + * @param clientDetails: Details from the data.search client + * @param results: Raw data from ES + */ + private logResults( + clientDetails: Omit, 'rawResponse'>, + results: estypes.SearchResponse + ) { + const { hits: resultsHits, ...headerWithPit } = results; + const { hits, ...hitsMeta } = resultsHits; + const trackedTotal = resultsHits.total as estypes.SearchTotalHits; + const currentTotal = trackedTotal?.value ?? resultsHits.total; + + const totalAccuracy = trackedTotal?.relation ?? 'unknown'; + this.logger.debug(`Received total hits: ${currentTotal}. Accuracy: ${totalAccuracy}.`); + + // reconstruct the data.search response (w/out the data) for logging + const { pit_id: newPitId, ...header } = headerWithPit; + const logInfo = { + ...clientDetails, + rawResponse: { + ...header, + hits: hitsMeta, + pit_id: `${this.formatPit(newPitId)}`, + }, + }; + this.logger.debug(`Result details: ${JSON.stringify(logInfo)}`); + + // use the most recently received id for the next search request + this.logger.debug(`Received PIT ID: [${this.formatPit(results.pit_id)}]`); + } + private async doSearch( searchSource: ISearchSource, settings: CsvExportSettings, @@ -117,25 +153,20 @@ export class CsvGenerator { throw new Error('Could not retrieve the search body!'); } - const searchParams = { - params: { - body: searchBody, - }, - }; - - let results: estypes.SearchResponse | undefined; + const searchParams = { params: { body: searchBody } }; + let results: estypes.SearchResponse; try { - results = ( - await lastValueFrom( - this.clients.data.search(searchParams, { - strategy: ES_SEARCH_STRATEGY, - transport: { - maxRetries: 0, // retrying reporting jobs is handled in the task manager scheduling logic - requestTimeout: scrollSettings.duration, - }, - }) - ) - ).rawResponse; + const { rawResponse, ...rawDetails } = await lastValueFrom( + this.clients.data.search(searchParams, { + strategy: ES_SEARCH_STRATEGY, + transport: { + maxRetries: 0, // retrying reporting jobs is handled in the task manager scheduling logic + requestTimeout: settings.scroll.duration, + }, + }) + ); + results = rawResponse; + this.logResults(rawDetails, rawResponse); } catch (err) { this.logger.error(`CSV export search error: ${err}`); throw err; @@ -327,7 +358,6 @@ export class CsvGenerator { let first = true; let currentRecord = -1; let totalRecords: number | undefined; - let totalRelation = 'eq'; let searchAfter: estypes.SortResults | undefined; let pitId = await this.openPointInTime(indexPatternTitle, settings); @@ -360,47 +390,31 @@ export class CsvGenerator { searchSource.setField('pit', { id: pitId, keep_alive: settings.scroll.duration }); const results = await this.doSearch(searchSource, settings, searchAfter); - - const { hits } = results; - if (first && hits.total != null) { - if (typeof hits.total === 'number') { - totalRecords = hits.total; - } else { - totalRecords = hits.total?.value; - totalRelation = hits.total?.relation ?? 'unknown'; - } - this.logger.info(`Total hits ${totalRelation} ${totalRecords}.`); - } - if (!results) { this.logger.warn(`Search results are undefined!`); break; } - const { - hits: { hits: _hits, ...hitsMeta }, - ...headerWithPit - } = results; + const { hits: resultsHits } = results; + const { hits, total } = resultsHits; + const trackedTotal = total as estypes.SearchTotalHits; + const currentTotal = trackedTotal?.value ?? total; - const { pit_id: newPitId, ...header } = headerWithPit; - - const logInfo = { - header: { pit_id: `${this.formatPit(newPitId)}`, ...header }, - hitsMeta, - }; - this.logger.debug(`Results metadata: ${JSON.stringify(logInfo)}`); + if (first) { + // export stops when totalRecords have been accumulated (or the results have run out) + totalRecords = currentTotal; + } // use the most recently received id for the next search request - this.logger.debug(`Received PIT ID: [${this.formatPit(results.pit_id)}]`); pitId = results.pit_id ?? pitId; // Update last sort results for next query. PIT is used, so the sort results // automatically include _shard_doc as a tiebreaker - searchAfter = hits.hits[hits.hits.length - 1]?.sort as estypes.SortResults | undefined; + searchAfter = hits[hits.length - 1]?.sort as estypes.SortResults | undefined; this.logger.debug(`Received search_after: [${searchAfter}]`); // check for shard failures, log them and add a warning if found - const { _shards: shards } = header; + const { _shards: shards } = results; if (shards.failures) { shards.failures.forEach(({ reason }) => { warnings.push(`Shard failure: ${JSON.stringify(reason)}`); @@ -499,6 +513,9 @@ export class CsvGenerator { }; } + /** + * Method to avoid logging the entire PIT: it could be megabytes long + */ private formatPit(pitId: string | undefined) { const byteSize = pitId ? Buffer.byteLength(pitId, 'utf-8') : 0; return pitId?.substring(0, 12) + `[${byteSize} bytes]`; diff --git a/packages/kbn-handlebars/__snapshots__/index.test.ts.snap b/packages/kbn-handlebars/__snapshots__/index.test.ts.snap index b9a8c27e4591..d25a455699fd 100644 --- a/packages/kbn-handlebars/__snapshots__/index.test.ts.snap +++ b/packages/kbn-handlebars/__snapshots__/index.test.ts.snap @@ -42,7 +42,7 @@ HandlebarsEnvironment { "isFunction": [Function], "toString": [Function], }, - "VERSION": "4.7.7", + "VERSION": "4.7.8", "VM": Object { "__esModule": true, "checkRevision": [Function], diff --git a/packages/kbn-handlebars/scripts/check_for_upstream_updates.sh b/packages/kbn-handlebars/scripts/check_for_upstream_updates.sh index 73f7376ab431..7f2bf784f863 100755 --- a/packages/kbn-handlebars/scripts/check_for_upstream_updates.sh +++ b/packages/kbn-handlebars/scripts/check_for_upstream_updates.sh @@ -34,7 +34,7 @@ else echo " our local versions of these files (located in" echo " 'packages/kbn-handlebars/src/spec')." echo - echo " https://github.com/handlebars-lang/handlebars.js/compare/$hash...4.x" + echo " https://github.com/handlebars-lang/handlebars.js/compare/$expected_hash...4.x" echo echo " 2. Execute the following script and commit the updated '$HASH_FILE'" echo " file including any changes you made to our own spec files." diff --git a/packages/kbn-handlebars/src/spec/.upstream_git_hash b/packages/kbn-handlebars/src/spec/.upstream_git_hash index 5a6b183166d4..0d4d453a0c5c 100644 --- a/packages/kbn-handlebars/src/spec/.upstream_git_hash +++ b/packages/kbn-handlebars/src/spec/.upstream_git_hash @@ -1 +1 @@ -c65c6cce3f626e4896a9d59250f0908be695adae \ No newline at end of file +eab1d141cb4a1d93375d7380ed070aa1f576a2c9 \ No newline at end of file diff --git a/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx b/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx index 6d91cc403795..e0d7e3c28dbe 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx +++ b/packages/kbn-language-documentation-popover/src/components/documentation_content.test.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { mountWithIntl, findTestSubject } from '@kbn/test-jest-helpers'; import { act } from 'react-dom/test-utils'; +import { Markdown } from '@kbn/kibana-react-plugin/public'; import { LanguageDocumentationPopoverContent } from './documentation_content'; describe('###Documentation popover content', () => { @@ -24,11 +25,11 @@ describe('###Documentation popover content', () => { items: [ { label: 'Section two item 1', - description: Section 2 item 1 description, + description: , }, { label: 'Section two item 2', - description: Section 2 item 2 description, + description: , }, ], }, @@ -52,7 +53,7 @@ describe('###Documentation popover content', () => { }); }); - test('Documentation component should list all sections that match the search input', () => { + test('Documentation component should list all sections that match the search input when title matches', () => { const component = mountWithIntl( ); @@ -69,4 +70,25 @@ describe('###Documentation popover content', () => { expect(sectionsLabels.length).toBe(1); expect(sectionsLabels.text()).toEqual('Section one'); }); + + test('Documentation component should list all sections that match the search input when description matches', () => { + const component = mountWithIntl( + + ); + const searchBox = component.find('[data-test-subj="language-documentation-navigation-search"]'); + act(() => { + searchBox.at(0).prop('onChange')!({ + target: { value: 'item 2 description' }, + } as React.ChangeEvent); + }); + + component.update(); + + const sectionsLabels = findTestSubject(component, 'language-documentation-navigation-title'); + expect(sectionsLabels.length).toBe(1); + }); }); diff --git a/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx b/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx index b7c2e800bbaf..0f24e233a4f2 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx +++ b/packages/kbn-language-documentation-popover/src/components/documentation_content.tsx @@ -20,6 +20,7 @@ import { EuiHighlight, EuiSpacer, } from '@elastic/eui'; +import { elementToString } from '../utils/element_to_string'; import './documentation.scss'; @@ -35,9 +36,11 @@ export interface LanguageDocumentationSections { interface DocumentationProps { language: string; sections?: LanguageDocumentationSections; + // if sets to true, allows searching in the markdown description + searchInDescription?: boolean; } -function DocumentationContent({ language, sections }: DocumentationProps) { +function DocumentationContent({ language, sections, searchInDescription }: DocumentationProps) { const [selectedSection, setSelectedSection] = useState(); const scrollTargets = useRef>({}); @@ -55,7 +58,13 @@ function DocumentationContent({ language, sections }: DocumentationProps) { .map((group) => { const items = group.items.filter((helpItem) => { return ( - !normalizedSearchText || helpItem.label.toLocaleLowerCase().includes(normalizedSearchText) + !normalizedSearchText || + helpItem.label.toLocaleLowerCase().includes(normalizedSearchText) || + // Converting the JSX element to a string first + (searchInDescription && + elementToString(helpItem.description) + ?.toLocaleLowerCase() + .includes(normalizedSearchText)) ); }); return { ...group, items }; diff --git a/packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx b/packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx index 8ff16737337a..db66d69d7173 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx +++ b/packages/kbn-language-documentation-popover/src/components/documentation_popover.tsx @@ -17,9 +17,15 @@ interface DocumentationPopoverProps { language: string; sections?: LanguageDocumentationSections; buttonProps?: Omit; + searchInDescription?: boolean; } -function DocumentationPopover({ language, sections, buttonProps }: DocumentationPopoverProps) { +function DocumentationPopover({ + language, + sections, + buttonProps, + searchInDescription, +}: DocumentationPopoverProps) { const [isHelpOpen, setIsHelpOpen] = useState(false); const toggleDocumentationPopover = useCallback(() => { @@ -50,7 +56,11 @@ function DocumentationPopover({ language, sections, buttonProps }: Documentation } > - + ); } diff --git a/packages/kbn-language-documentation-popover/src/utils/element_to_string.test.tsx b/packages/kbn-language-documentation-popover/src/utils/element_to_string.test.tsx new file mode 100644 index 000000000000..42ca61cca472 --- /dev/null +++ b/packages/kbn-language-documentation-popover/src/utils/element_to_string.test.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React from 'react'; +import { Markdown } from '@kbn/kibana-react-plugin/public'; +import { elementToString } from './element_to_string'; + +describe('elementToString', () => { + test('Should return empty string if no element is given', () => { + const text = elementToString(undefined); + expect(text).toEqual(''); + }); + + test('Should return empty string if no markdown is passed', () => { + const text = elementToString(Meow); + expect(text).toEqual(''); + }); + + test('Should convert to string if markdown is passed', () => { + const text = elementToString(); + expect(text).toEqual('## Markdown goes here '); + }); + + test('Should convert to string if children with markdown are passed', () => { + const text = elementToString( + <> +

    Meow

    + + + ); + expect(text).toEqual('## Markdown goes here '); + }); +}); diff --git a/packages/kbn-language-documentation-popover/src/utils/element_to_string.ts b/packages/kbn-language-documentation-popover/src/utils/element_to_string.ts new file mode 100644 index 000000000000..f13bb652f662 --- /dev/null +++ b/packages/kbn-language-documentation-popover/src/utils/element_to_string.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React, { isValidElement } from 'react'; + +function nonNullable(v: T): v is NonNullable { + return v != null; +} + +/** + * Gets the JSX.Element as the input. It returns the markdown as string. + * If the children are not markdown it will return an empty string. + */ +export function elementToString(element?: JSX.Element): string { + if (!element) { + return ''; + } + const props = element.props; + if (props && 'markdown' in props) { + return String(props.markdown); + } else if (props && 'children' in props && Array.isArray(props.children)) { + return props.children.reduce((text: string, child: React.ReactNode): string => { + const validChildren = React.Children.toArray(child).filter(nonNullable); + if (isValidElement(child) && validChildren.length > 0) { + return text.concat(elementToString(child)); + } + return text; + }, ''); + } + return ''; +} diff --git a/packages/kbn-language-documentation-popover/tsconfig.json b/packages/kbn-language-documentation-popover/tsconfig.json index 82710b41d10b..a0c043b8a15e 100644 --- a/packages/kbn-language-documentation-popover/tsconfig.json +++ b/packages/kbn-language-documentation-popover/tsconfig.json @@ -14,6 +14,7 @@ "kbn_references": [ "@kbn/i18n", "@kbn/test-jest-helpers", + "@kbn/kibana-react-plugin", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/types.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/types.ts index 428f6aacce13..68d632db2f03 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/types.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/types.ts @@ -18,6 +18,7 @@ import type { XYLayerConfig, FillStyle, } from '@kbn/lens-plugin/public'; + export type LensAttributes = TypedLensByValueInput['attributes']; // Attributes @@ -61,7 +62,6 @@ export interface ChartLayer { getDataView(): DataView | undefined; } -// Chart export interface Chart { getTitle(): string; getVisualizationType(): string; @@ -70,6 +70,8 @@ export interface Chart { getReferences(): SavedObjectReference[]; getDataViews(): DataView[]; } + +// Chart export interface ChartConfig< TLayer extends ChartLayer | Array> > { @@ -91,3 +93,5 @@ export type StaticValueConfig = Omit & { fill?: FillStyle; value: string; }; + +export type VisualizationTypes = 'lnsXY' | 'lnsMetric'; diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts new file mode 100644 index 000000000000..f2d6a056c09d --- /dev/null +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/constants.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const XY_ID = 'lnsXY'; +export const METRIC_ID = 'lnsMetric'; + +export const METRIC_TREND_LINE_ID = 'metricTrendline'; +export const XY_REFERENCE_LINE_ID = 'referenceLine'; +export const XY_DATA_ID = 'data'; diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts index 7927ff37b2f1..ffafd8983fe5 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/index.ts @@ -5,8 +5,37 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import type { DataView } from '@kbn/data-views-plugin/common'; +import { + METRIC_ID, + XY_ID, + METRIC_TREND_LINE_ID, + XY_DATA_ID, + XY_REFERENCE_LINE_ID, +} from './constants'; +import type { XYVisualOptions } from './xy_chart'; +import type { MetricLayerConfig, XYDataLayerConfig, XYReferenceLinesLayerConfig } from './layers'; export { XYChart, type XYVisualOptions } from './xy_chart'; export { MetricChart } from './metric_chart'; - export * from './layers'; +export type XYLayerConfig = XYDataLayerConfig | XYReferenceLinesLayerConfig; + +interface ChartModelBase { + id: string; + title?: string; + dataView?: DataView; +} +export interface XYChartModel extends ChartModelBase { + visualOptions?: XYVisualOptions; + visualizationType: typeof XY_ID; + layers: XYLayerConfig[]; +} +export interface MetricChartModel extends ChartModelBase { + visualizationType: typeof METRIC_ID; + layers: MetricLayerConfig; +} + +export type ChartModel = XYChartModel | MetricChartModel; +export type ChartTypes = typeof XY_ID | typeof METRIC_ID; +export { METRIC_ID, XY_ID, METRIC_TREND_LINE_ID, XY_DATA_ID, XY_REFERENCE_LINE_ID }; diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/index.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/index.ts index a9680c27b764..2620d7639f5f 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/index.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/index.ts @@ -7,7 +7,7 @@ */ export { MetricLayer, type MetricLayerOptions, type MetricLayerConfig } from './metric_layer'; -export { XYDataLayer, type XYLayerOptions, type XYLayerConfig } from './xy_data_layer'; +export { XYDataLayer, type XYLayerOptions, type XYDataLayerConfig } from './xy_data_layer'; export { XYReferenceLinesLayer, type XYReferenceLinesLayerConfig, diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/metric_layer.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/metric_layer.ts index 0a98f31aec15..a78191ffb82a 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/metric_layer.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/metric_layer.ts @@ -16,6 +16,7 @@ import type { } from '@kbn/lens-plugin/public'; import type { ChartColumn, ChartLayer, FormulaValueConfig } from '../../types'; import { getDefaultReferences, getHistogramColumn } from '../../utils'; +import { METRIC_TREND_LINE_ID } from '../constants'; import { FormulaColumn } from './columns/formula'; const HISTOGRAM_COLUMN_NAME = 'x_date_histogram'; @@ -30,6 +31,7 @@ export interface MetricLayerOptions { export interface MetricLayerConfig { data: FormulaValueConfig; options?: MetricLayerOptions; + layerType?: typeof METRIC_TREND_LINE_ID; /** * It is possible to define a specific dataView for the layer. It will override the global chart one **/ @@ -38,8 +40,13 @@ export interface MetricLayerConfig { export class MetricLayer implements ChartLayer { private column: ChartColumn; - constructor(private layerConfig: MetricLayerConfig) { + private layerConfig: MetricLayerConfig; + constructor(layerConfig: MetricLayerConfig) { this.column = new FormulaColumn(layerConfig.data); + this.layerConfig = { + ...layerConfig, + layerType: layerConfig.layerType ?? 'metricTrendline', + }; } getLayer( diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts index f4845a5c93ab..d42a00e96348 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_data_layer.ts @@ -12,7 +12,7 @@ import type { FormulaPublicApi, FormBasedPersistedState, PersistedIndexPatternLayer, - XYDataLayerConfig, + XYDataLayerConfig as LensXYDataLayerConfig, SeriesType, TermsIndexPatternColumn, DateHistogramIndexPatternColumn, @@ -26,6 +26,7 @@ import { type TopValuesColumnParams, type DateHistogramColumnParams, } from '../../utils'; +import { XY_DATA_ID } from '../constants'; import { FormulaColumn } from './columns/formula'; const BREAKDOWN_COLUMN_NAME = 'aggs_breakdown'; @@ -50,22 +51,25 @@ export interface XYLayerOptions { seriesType?: SeriesType; } -export interface XYLayerConfig { +export interface XYDataLayerConfig { data: FormulaValueConfig[]; options?: XYLayerOptions; + layerType?: typeof XY_DATA_ID; + /** * It is possible to define a specific dataView for the layer. It will override the global chart one **/ dataView?: DataView; } -export class XYDataLayer implements ChartLayer { +export class XYDataLayer implements ChartLayer { private column: ChartColumn[]; - private layerConfig: XYLayerConfig; - constructor(layerConfig: XYLayerConfig) { + private layerConfig: XYDataLayerConfig; + constructor(layerConfig: XYDataLayerConfig) { this.column = layerConfig.data.map((dataItem) => new FormulaColumn(dataItem)); this.layerConfig = { ...layerConfig, + layerType: layerConfig.layerType ?? 'data', options: { ...layerConfig.options, buckets: { @@ -151,7 +155,7 @@ export class XYDataLayer implements ChartLayer { return getDefaultReferences(this.layerConfig.dataView ?? chartDataView, layerId); } - getLayerConfig(layerId: string, accessorId: string): XYDataLayerConfig { + getLayerConfig(layerId: string, accessorId: string): LensXYDataLayerConfig { return { layerId, seriesType: this.layerConfig.options?.seriesType ?? 'line', diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_reference_lines_layer.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_reference_lines_layer.ts index 2a105c10677a..bc2132f17918 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_reference_lines_layer.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/layers/xy_reference_lines_layer.ts @@ -15,10 +15,12 @@ import type { } from '@kbn/lens-plugin/public'; import type { ChartLayer, StaticValueConfig, StaticChartColumn } from '../../types'; import { getDefaultReferences } from '../../utils'; +import { XY_REFERENCE_LINE_ID } from '../constants'; import { StaticColumn } from './columns/static'; export interface XYReferenceLinesLayerConfig { data: StaticValueConfig[]; + layerType?: typeof XY_REFERENCE_LINE_ID; /** * It is possible to define a specific dataView for the layer. It will override the global chart one **/ @@ -27,8 +29,13 @@ export interface XYReferenceLinesLayerConfig { export class XYReferenceLinesLayer implements ChartLayer { private column: StaticChartColumn[]; - constructor(private layerConfig: XYReferenceLinesLayerConfig) { + private layerConfig: XYReferenceLinesLayerConfig; + constructor(layerConfig: XYReferenceLinesLayerConfig) { this.column = layerConfig.data.map((p) => new StaticColumn(p)); + this.layerConfig = { + ...layerConfig, + layerType: layerConfig.layerType ?? 'referenceLine', + }; } getName(): string | undefined { diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/metric_chart.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/metric_chart.ts index 9c3f5bf3afe9..02b44c061878 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/metric_chart.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/metric_chart.ts @@ -11,6 +11,7 @@ import type { SavedObjectReference } from '@kbn/core/server'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { Chart, ChartConfig, ChartLayer } from '../types'; import { DEFAULT_LAYER_ID } from '../utils'; +import { METRIC_ID } from './constants'; const ACCESSOR = 'metric_formula_accessor'; @@ -18,7 +19,7 @@ export class MetricChart implements Chart { constructor(private chartConfig: ChartConfig>) {} getVisualizationType(): string { - return 'lnsMetric'; + return METRIC_ID; } getLayers(): FormBasedPersistedState['layers'] { diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts index 6e0390ffe9e1..e0b42c2dcfbf 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts @@ -7,7 +7,9 @@ */ import type { + AxisExtentConfig, FormBasedPersistedState, + LegendConfig, XYArgs, XYLayerConfig, XYState, @@ -17,6 +19,7 @@ import type { SavedObjectReference } from '@kbn/core/server'; import { AxesSettingsConfig } from '@kbn/visualizations-plugin/common'; import type { Chart, ChartConfig, ChartLayer } from '../types'; import { DEFAULT_LAYER_ID } from '../utils'; +import { XY_ID } from './constants'; const ACCESSOR = 'formula_accessor'; @@ -28,6 +31,8 @@ export interface XYVisualOptions { showDottedLine?: boolean; valueLabels?: XYArgs['valueLabels']; axisTitlesVisibilitySettings?: AxesSettingsConfig; + legend?: LegendConfig; + yLeftExtent?: AxisExtentConfig; } export class XYChart implements Chart { @@ -39,7 +44,7 @@ export class XYChart implements Chart { ) {} getVisualizationType(): string { - return 'lnsXY'; + return XY_ID; } private get layers() { @@ -79,12 +84,23 @@ export class XYChart implements Chart { }), ], }), + legend: this.chartConfig.visualOptions?.legend ?? { + isVisible: false, + position: 'right', + showSingleSeries: false, + }, fittingFunction: this.chartConfig.visualOptions?.missingValues ?? 'None', endValue: this.chartConfig.visualOptions?.endValues, curveType: this.chartConfig.visualOptions?.lineInterpolation, emphasizeFitting: !this.chartConfig.visualOptions?.showDottedLine, valueLabels: this.chartConfig.visualOptions?.valueLabels, - axisTitlesVisibilitySettings: this.chartConfig.visualOptions?.axisTitlesVisibilitySettings, + axisTitlesVisibilitySettings: this.chartConfig.visualOptions + ?.axisTitlesVisibilitySettings ?? { + x: false, + yLeft: false, + yRight: true, + }, + yLeftExtent: this.chartConfig.visualOptions?.yLeftExtent, }; } @@ -117,11 +133,6 @@ export const getXYVisualizationState = ( }, valueLabels: 'show', yLeftScale: 'linear', - axisTitlesVisibilitySettings: { - x: false, - yLeft: false, - yRight: true, - }, tickLabelsVisibilitySettings: { x: true, yLeft: true, diff --git a/packages/kbn-lens-embeddable-utils/index.ts b/packages/kbn-lens-embeddable-utils/index.ts index ddd5744f230b..ffe9d4e87d78 100644 --- a/packages/kbn-lens-embeddable-utils/index.ts +++ b/packages/kbn-lens-embeddable-utils/index.ts @@ -12,9 +12,14 @@ export type { MetricLayerOptions, MetricLayerConfig, XYLayerOptions, - XYLayerConfig, + XYDataLayerConfig, XYReferenceLinesLayerConfig, XYVisualOptions, + XYLayerConfig, + ChartTypes, + ChartModel, + XYChartModel, + MetricChartModel, } from './attribute_builder/visualization_types'; export { @@ -25,6 +30,11 @@ export { XYChart, XYDataLayer, XYReferenceLinesLayer, + METRIC_ID, + METRIC_TREND_LINE_ID, + XY_ID, + XY_DATA_ID, + XY_REFERENCE_LINE_ID, } from './attribute_builder/visualization_types'; export { LensAttributesBuilder } from './attribute_builder/lens_attributes_builder'; diff --git a/packages/kbn-lens-embeddable-utils/kibana.jsonc b/packages/kbn-lens-embeddable-utils/kibana.jsonc index 9dc67508d99e..4f8fd44b1ea6 100644 --- a/packages/kbn-lens-embeddable-utils/kibana.jsonc +++ b/packages/kbn-lens-embeddable-utils/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-browser", + "type": "shared-common", "id": "@kbn/lens-embeddable-utils", "owner": "@elastic/obs-ux-infra_services-team" } diff --git a/packages/kbn-management/settings/application/__stories__/application.stories.tsx b/packages/kbn-management/settings/application/__stories__/application.stories.tsx index b7742e8eca54..efc27f7f8300 100644 --- a/packages/kbn-management/settings/application/__stories__/application.stories.tsx +++ b/packages/kbn-management/settings/application/__stories__/application.stories.tsx @@ -40,6 +40,13 @@ export const SettingsApplication: Story = () => { showReloadPagePrompt={action('showReloadPagePrompt')} subscribeToUpdates={() => new Subscription()} addUrlToHistory={action('addUrlToHistory')} + validateChange={async (key, value) => { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} > diff --git a/packages/kbn-management/settings/application/services.tsx b/packages/kbn-management/settings/application/services.tsx index 09ce0780b06d..d64657525d35 100644 --- a/packages/kbn-management/settings/application/services.tsx +++ b/packages/kbn-management/settings/application/services.tsx @@ -32,7 +32,10 @@ export type SettingsApplicationServices = Services & FormServices; export interface KibanaDependencies { settings: { - client: Pick; + client: Pick< + IUiSettingsClient, + 'getAll' | 'isCustom' | 'isOverridden' | 'getUpdate$' | 'validateValue' + >; }; history: ScopedHistory; } @@ -52,6 +55,7 @@ export const SettingsApplicationProvider: FC = ({ const { saveChanges, showError, + validateChange, showReloadPagePrompt, links, showDanger, @@ -72,7 +76,9 @@ export const SettingsApplicationProvider: FC = ({ addUrlToHistory, }} > - + {children} diff --git a/packages/kbn-management/settings/components/field_category/__stories__/categories.stories.tsx b/packages/kbn-management/settings/components/field_category/__stories__/categories.stories.tsx index 1a9fb03b2753..8185310c71a0 100644 --- a/packages/kbn-management/settings/components/field_category/__stories__/categories.stories.tsx +++ b/packages/kbn-management/settings/components/field_category/__stories__/categories.stories.tsx @@ -53,6 +53,13 @@ export const Categories: Story = (params) => { { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} > { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} {...{ isSavingEnabled, onFieldChange }} > diff --git a/packages/kbn-management/settings/components/field_category/__stories__/use_category_story.tsx b/packages/kbn-management/settings/components/field_category/__stories__/use_category_story.tsx index a04e2aa93177..fe65004f551c 100644 --- a/packages/kbn-management/settings/components/field_category/__stories__/use_category_story.tsx +++ b/packages/kbn-management/settings/components/field_category/__stories__/use_category_story.tsx @@ -59,8 +59,13 @@ export const useCategoryStory = ({ isFiltered, isSavingEnabled }: Params) => { setUnsavedChanges((changes) => ({ ...changes, [id]: change })); }; - // This is only needed for when a search query is present - const categoryCounts = {}; + const categoryCounts = Object.keys(categorizedFields).reduce( + (acc, category) => ({ + ...acc, + [category]: categorizedFields[category].count, + }), + {} + ); return { onClearQuery, diff --git a/packages/kbn-management/settings/components/field_input/__stories__/common.tsx b/packages/kbn-management/settings/components/field_input/__stories__/common.tsx index 39daed80f40b..0bdd569b9974 100644 --- a/packages/kbn-management/settings/components/field_input/__stories__/common.tsx +++ b/packages/kbn-management/settings/components/field_input/__stories__/common.tsx @@ -75,7 +75,16 @@ export const getStory = (title: string, description: string) => }, decorators: [ (Story) => ( - + { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} + > diff --git a/packages/kbn-management/settings/components/field_input/input/array_input.test.tsx b/packages/kbn-management/settings/components/field_input/input/array_input.test.tsx index c954035e9c63..ee0d7cb5e723 100644 --- a/packages/kbn-management/settings/components/field_input/input/array_input.test.tsx +++ b/packages/kbn-management/settings/components/field_input/input/array_input.test.tsx @@ -6,8 +6,7 @@ * Side Public License, v 1. */ import React from 'react'; -import { act, fireEvent, render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { ArrayInput } from './array_input'; import { TEST_SUBJ_PREFIX_FIELD } from '.'; @@ -60,34 +59,17 @@ describe('ArrayInput', () => { expect(screen.getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`)).toHaveValue('foo, bar, baz'); }); - it('formats array when blurred', () => { + it('calls the onInputChange prop when the value changes', async () => { render(wrap()); const input = screen.getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); - fireEvent.focus(input); - userEvent.type(input, ',baz'); - expect(input).toHaveValue('foo, bar,baz'); - input.blur(); - expect(input).toHaveValue('foo, bar, baz'); - }); - - it('only calls onInputChange when blurred ', () => { - render(wrap()); - const input = screen.getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); - - fireEvent.focus(input); - userEvent.type(input, ',baz'); + fireEvent.change(input, { target: { value: 'foo, bar,baz' } }); - expect(input).toHaveValue('foo, bar,baz'); - expect(defaultProps.onInputChange).not.toHaveBeenCalled(); - - act(() => { - input.blur(); - }); - - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'array', - unsavedValue: ['foo', 'bar', 'baz'], - }); + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ + type: 'array', + unsavedValue: ['foo', 'bar', 'baz'], + }) + ); }); it('disables the input when isDisabled prop is true', () => { diff --git a/packages/kbn-management/settings/components/field_input/input/array_input.tsx b/packages/kbn-management/settings/components/field_input/input/array_input.tsx index f2ce42051eb0..0dc9b8ddc406 100644 --- a/packages/kbn-management/settings/components/field_input/input/array_input.tsx +++ b/packages/kbn-management/settings/components/field_input/input/array_input.tsx @@ -6,12 +6,14 @@ * Side Public License, v 1. */ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiFieldText, EuiFieldTextProps } from '@elastic/eui'; import { getFieldInputValue } from '@kbn/management-settings-utilities'; import { useUpdate } from '@kbn/management-settings-utilities'; +import { debounce } from 'lodash'; +import { useServices } from '../services'; import { InputProps } from '../types'; import { TEST_SUBJ_PREFIX_FIELD } from '.'; @@ -33,29 +35,45 @@ export const ArrayInput = ({ }: ArrayInputProps) => { const [inputValue] = getFieldInputValue(field, unsavedChange) || []; const [value, setValue] = useState(inputValue?.join(', ')); + const { validateChange } = useServices(); + const onUpdate = useUpdate({ onInputChange, field }); + + const updateValue = useCallback( + async (newValue: string, onUpdateFn) => { + const parsedValue = newValue + .replace(REGEX, ',') + .split(',') + .filter((v) => v !== ''); + const validationResponse = await validateChange(field.id, parsedValue); + if (validationResponse.successfulValidation && !validationResponse.valid) { + onUpdateFn({ + type: field.type, + unsavedValue: parsedValue, + isInvalid: !validationResponse.valid, + error: validationResponse.errorMessage, + }); + } else { + onUpdateFn({ type: field.type, unsavedValue: parsedValue }); + } + }, + [validateChange, field.id, field.type] + ); + + const debouncedUpdateValue = useMemo(() => { + // Trigger update 1000 ms after the user stopped typing to reduce validation requests to the server + return debounce(updateValue, 1000); + }, [updateValue]); - const onChange: EuiFieldTextProps['onChange'] = (event) => { + const onChange: EuiFieldTextProps['onChange'] = async (event) => { const newValue = event.target.value; setValue(newValue); + await debouncedUpdateValue(newValue, onUpdate); }; - const onUpdate = useUpdate({ onInputChange, field }); - useEffect(() => { setValue(inputValue?.join(', ')); }, [inputValue]); - // In the past, each keypress would invoke the `onChange` callback. This - // is likely wasteful, so we've switched it to `onBlur` instead. - const onBlur = (event: React.ChangeEvent) => { - const blurValue = event.target.value - .replace(REGEX, ',') - .split(',') - .filter((v) => v !== ''); - onUpdate({ type: field.type, unsavedValue: blurValue }); - setValue(blurValue.join(', ')); - }; - const { id, name, ariaAttributes } = field; const { ariaLabel, ariaDescribedBy } = ariaAttributes; @@ -66,7 +84,7 @@ export const ArrayInput = ({ disabled={!isSavingEnabled} aria-label={ariaLabel} aria-describedby={ariaDescribedBy} - {...{ name, onBlur, onChange, value }} + {...{ name, onChange, value }} /> ); }; diff --git a/packages/kbn-management/settings/components/field_input/input/code_editor_input.tsx b/packages/kbn-management/settings/components/field_input/input/code_editor_input.tsx index 5b9d90154d08..cbf53979efa8 100644 --- a/packages/kbn-management/settings/components/field_input/input/code_editor_input.tsx +++ b/packages/kbn-management/settings/components/field_input/input/code_editor_input.tsx @@ -6,13 +6,13 @@ * Side Public License, v 1. */ -import React from 'react'; - -import { i18n } from '@kbn/i18n'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { SettingType } from '@kbn/management-settings-types'; import { getFieldInputValue, useUpdate } from '@kbn/management-settings-utilities'; +import { debounce } from 'lodash'; +import { useServices } from '../services'; import { CodeEditor, CodeEditorProps } from '../code_editor'; import type { InputProps } from '../types'; import { TEST_SUBJ_PREFIX_FIELD } from '.'; @@ -45,39 +45,48 @@ export const CodeEditorInput = ({ defaultValue, onInputChange, }: CodeEditorInputProps) => { + // @ts-expect-error + const [inputValue] = getFieldInputValue(field, unsavedChange); + const [value, setValue] = useState(inputValue); + const { validateChange } = useServices(); const onUpdate = useUpdate({ onInputChange, field }); - const onChange: CodeEditorProps['onChange'] = (inputValue) => { - let newUnsavedValue; - let errorParams = {}; - - switch (type) { - case 'json': - const isJsonArray = Array.isArray(JSON.parse(defaultValue || '{}')); - newUnsavedValue = inputValue || (isJsonArray ? '[]' : '{}'); + const updateValue = useCallback( + async (newValue: string, onUpdateFn) => { + const isJsonArray = Array.isArray(JSON.parse(defaultValue || '{}')); + const parsedValue = newValue || (isJsonArray ? '[]' : '{}'); + const validationResponse = await validateChange(field.id, parsedValue); + if (validationResponse.successfulValidation && !validationResponse.valid) { + onUpdateFn({ + type: field.type, + unsavedValue: newValue, + isInvalid: !validationResponse.valid, + error: validationResponse.errorMessage, + }); + } else { + onUpdateFn({ type: field.type, unsavedValue: newValue }); + } + }, + [validateChange, field.id, field.type, defaultValue] + ); - try { - JSON.parse(newUnsavedValue); - } catch (e) { - errorParams = { - error: i18n.translate('management.settings.field.codeEditorSyntaxErrorMessage', { - defaultMessage: 'Invalid JSON syntax', - }), - isInvalid: true, - }; - } - break; - default: - newUnsavedValue = inputValue; - } + const debouncedUpdateValue = useMemo(() => { + // Trigger update 1000 ms after the user stopped typing to reduce validation requests to the server + return debounce(updateValue, 1000); + }, [updateValue]); - onUpdate({ type: field.type, unsavedValue: inputValue, ...errorParams }); + const onChange: CodeEditorProps['onChange'] = async (newValue) => { + // @ts-expect-error + setValue(newValue); + await debouncedUpdateValue(newValue, onUpdate); }; + useEffect(() => { + setValue(inputValue); + }, [inputValue]); + const { id, ariaAttributes } = field; const { ariaLabel, ariaDescribedBy } = ariaAttributes; - // @ts-expect-error - const [value] = getFieldInputValue(field, unsavedChange); return (
    diff --git a/packages/kbn-management/settings/components/field_input/input/json_editor_input.test.tsx b/packages/kbn-management/settings/components/field_input/input/json_editor_input.test.tsx index 800a807f8103..ecc132dad8c8 100644 --- a/packages/kbn-management/settings/components/field_input/input/json_editor_input.test.tsx +++ b/packages/kbn-management/settings/components/field_input/input/json_editor_input.test.tsx @@ -16,6 +16,7 @@ import { CodeEditorProps } from '../code_editor'; const name = 'Some json field'; const id = 'some:json:field'; const initialValue = '{"foo":"bar"}'; +import { wrap } from '../mocks'; jest.mock('../code_editor', () => ({ CodeEditor: ({ value, onChange }: CodeEditorProps) => ( @@ -55,51 +56,46 @@ describe('JsonEditorInput', () => { }); it('renders without errors', () => { - const { container } = render(); + const { container } = render(wrap()); expect(container).toBeInTheDocument(); }); it('renders the value prop', () => { - const { getByTestId } = render(); + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); expect(input).toHaveValue(initialValue); }); - it('calls the onInputChange prop when the object value changes', () => { - const { getByTestId } = render(); + it('calls the onInputChange prop when the object value changes', async () => { + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '{"bar":"foo"}' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'json', - unsavedValue: '{"bar":"foo"}', - }); + + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ + type: 'json', + unsavedValue: '{"bar":"foo"}', + }) + ); }); - it('calls the onInputChange prop when the object value changes with no value', () => { - const { getByTestId } = render(); + it('calls the onInputChange prop when the object value changes with no value', async () => { + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ type: 'json', unsavedValue: '' }); - }); - it('calls the onInputChange prop with an error when the object value changes to invalid JSON', () => { - const { getByTestId } = render(); - const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); - fireEvent.change(input, { target: { value: '{"bar" "foo"}' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'json', - unsavedValue: '{"bar" "foo"}', - error: 'Invalid JSON syntax', - isInvalid: true, - }); + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ type: 'json', unsavedValue: '' }) + ); }); - it('calls the onInputChange prop when the array value changes', () => { + it('calls the onInputChange prop when the array value changes', async () => { const props = { ...defaultProps, defaultValue: '["bar", "foo"]', value: undefined }; - const { getByTestId } = render(); + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '["foo", "bar", "baz"]' } }); - waitFor(() => + + await waitFor(() => expect(defaultProps.onInputChange).toHaveBeenCalledWith({ type: 'json', unsavedValue: '["foo", "bar", "baz"]', @@ -107,28 +103,18 @@ describe('JsonEditorInput', () => { ); }); - it('calls the onInputChange prop when the array value changes with no value', () => { + it('calls the onInputChange prop when the array value changes with no value', async () => { const props = { ...defaultProps, defaultValue: '["bar", "foo"]', value: '["bar", "foo"]', }; - const { getByTestId } = render(); + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ type: 'json', unsavedValue: '' }); - }); - it('calls the onInputChange prop with an array when the array value changes to invalid JSON', () => { - const props = { ...defaultProps, defaultValue: '["bar", "foo"]', value: undefined }; - const { getByTestId } = render(); - const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); - fireEvent.change(input, { target: { value: '["bar", "foo" | "baz"]' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'json', - unsavedValue: '["bar", "foo" | "baz"]', - error: 'Invalid JSON syntax', - isInvalid: true, - }); + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ type: 'json', unsavedValue: '' }) + ); }); }); diff --git a/packages/kbn-management/settings/components/field_input/input/markdown_editor_input.test.tsx b/packages/kbn-management/settings/components/field_input/input/markdown_editor_input.test.tsx index 291585e5f149..f26e59e43efb 100644 --- a/packages/kbn-management/settings/components/field_input/input/markdown_editor_input.test.tsx +++ b/packages/kbn-management/settings/components/field_input/input/markdown_editor_input.test.tsx @@ -7,11 +7,12 @@ */ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render, fireEvent, waitFor } from '@testing-library/react'; import { CodeEditorInput, CodeEditorInputProps } from './code_editor_input'; import { TEST_SUBJ_PREFIX_FIELD } from '.'; import { CodeEditorProps } from '../code_editor'; +import { wrap } from '../mocks'; const name = 'Some markdown field'; const id = 'some:markdown:field'; @@ -55,23 +56,26 @@ describe('MarkdownEditorInput', () => { }); it('renders without errors', () => { - const { container } = render(); + const { container } = render(wrap()); expect(container).toBeInTheDocument(); }); it('renders the value prop', () => { - const { getByTestId } = render(); + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); expect(input).toHaveValue(initialValue); }); - it('calls the onInputChange prop when the value changes', () => { - const { getByTestId } = render(); + it('calls the onInputChange prop when the value changes', async () => { + const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '# New Markdown Title' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'markdown', - unsavedValue: '# New Markdown Title', - }); + + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ + type: 'markdown', + unsavedValue: '# New Markdown Title', + }) + ); }); }); diff --git a/packages/kbn-management/settings/components/field_input/input/number_input.test.tsx b/packages/kbn-management/settings/components/field_input/input/number_input.test.tsx index fa228a48b721..968982759a1d 100644 --- a/packages/kbn-management/settings/components/field_input/input/number_input.test.tsx +++ b/packages/kbn-management/settings/components/field_input/input/number_input.test.tsx @@ -65,14 +65,17 @@ describe('NumberInput', () => { expect(input).toHaveValue(4321); }); - it('calls the onInputChange prop when the value changes', () => { + it('calls the onInputChange prop when the value changes', async () => { const { getByTestId } = render(wrap()); const input = getByTestId(`${TEST_SUBJ_PREFIX_FIELD}-${id}`); fireEvent.change(input, { target: { value: '54321' } }); - expect(defaultProps.onInputChange).toHaveBeenCalledWith({ - type: 'number', - unsavedValue: 54321, - }); + + await waitFor(() => + expect(defaultProps.onInputChange).toHaveBeenCalledWith({ + type: 'number', + unsavedValue: 54321, + }) + ); }); it('disables the input when isDisabled prop is true', () => { diff --git a/packages/kbn-management/settings/components/field_input/input/number_input.tsx b/packages/kbn-management/settings/components/field_input/input/number_input.tsx index a1929593e3cb..8a29429eff59 100644 --- a/packages/kbn-management/settings/components/field_input/input/number_input.tsx +++ b/packages/kbn-management/settings/components/field_input/input/number_input.tsx @@ -6,13 +6,15 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiFieldNumber, EuiFieldNumberProps } from '@elastic/eui'; import { getFieldInputValue, useUpdate } from '@kbn/management-settings-utilities'; +import { debounce } from 'lodash'; import { InputProps } from '../types'; import { TEST_SUBJ_PREFIX_FIELD } from '.'; +import { useServices } from '../services'; /** * Props for a {@link NumberInput} component. @@ -28,18 +30,45 @@ export const NumberInput = ({ isSavingEnabled, onInputChange, }: NumberInputProps) => { - const onChange: EuiFieldNumberProps['onChange'] = (event) => { - const inputValue = Number(event.target.value); - onUpdate({ type: field.type, unsavedValue: inputValue }); + const [inputValue] = getFieldInputValue(field, unsavedChange) || undefined; + const [value, setValue] = useState(inputValue); + const { validateChange } = useServices(); + const onUpdate = useUpdate({ onInputChange, field }); + + const updateValue = useCallback( + async (newValue: number, onUpdateFn) => { + const validationResponse = await validateChange(field.id, newValue); + if (validationResponse.successfulValidation && !validationResponse.valid) { + onUpdateFn({ + type: field.type, + unsavedValue: newValue, + isInvalid: !validationResponse.valid, + error: validationResponse.errorMessage, + }); + } else { + onUpdateFn({ type: field.type, unsavedValue: newValue }); + } + }, + [validateChange, field.id, field.type] + ); + + const debouncedUpdateValue = useMemo(() => { + // Trigger update 500 ms after the user stopped typing to reduce validation requests to the server + return debounce(updateValue, 500); + }, [updateValue]); + + const onChange: EuiFieldNumberProps['onChange'] = async (event) => { + const newValue = Number(event.target.value); + setValue(newValue); + await debouncedUpdateValue(newValue, onUpdate); }; - const onUpdate = useUpdate({ onInputChange, field }); + useEffect(() => { + setValue(inputValue); + }, [inputValue]); const { id, name, ariaAttributes } = field; const { ariaLabel, ariaDescribedBy } = ariaAttributes; - const [rawValue] = getFieldInputValue(field, unsavedChange); - - const value = rawValue === null ? undefined : rawValue; return ( { export const createFieldInputServicesMock = (): FieldInputServices => ({ showDanger: jest.fn(), + validateChange: async () => { + return { successfulValidation: true, valid: true }; + }, }); export const TestWrapper = ({ diff --git a/packages/kbn-management/settings/components/field_input/services.tsx b/packages/kbn-management/settings/components/field_input/services.tsx index 95a6474f89b5..d19278268b2a 100644 --- a/packages/kbn-management/settings/components/field_input/services.tsx +++ b/packages/kbn-management/settings/components/field_input/services.tsx @@ -17,9 +17,13 @@ const FieldInputContext = React.createContext(null); export const FieldInputProvider: FC = ({ children, ...services }) => { // Typescript types are widened to accept more than what is needed. Take only what is necessary // so the context remains clean. - const { showDanger } = services; + const { showDanger, validateChange } = services; - return {children}; + return ( + + {children} + + ); }; /** @@ -28,11 +32,15 @@ export const FieldInputProvider: FC = ({ children, ...servic export const FieldInputKibanaProvider: FC = ({ children, notifications: { toasts }, + settings: { client }, }) => { return ( toasts.addDanger(message), + validateChange: async (key, value) => { + return await client.validateValue(key, value); + }, }} > {children} diff --git a/packages/kbn-management/settings/components/field_input/tsconfig.json b/packages/kbn-management/settings/components/field_input/tsconfig.json index bc47a21a3d75..bb4c6b4aa57d 100644 --- a/packages/kbn-management/settings/components/field_input/tsconfig.json +++ b/packages/kbn-management/settings/components/field_input/tsconfig.json @@ -29,5 +29,6 @@ "@kbn/core-theme-browser-mocks", "@kbn/core-i18n-browser", "@kbn/core-analytics-browser-mocks", + "@kbn/core-ui-settings-browser", ] } diff --git a/packages/kbn-management/settings/components/field_input/types.ts b/packages/kbn-management/settings/components/field_input/types.ts index e1c2ce1a70df..f6eed155a189 100644 --- a/packages/kbn-management/settings/components/field_input/types.ts +++ b/packages/kbn-management/settings/components/field_input/types.ts @@ -13,6 +13,8 @@ import { UnsavedFieldChange, } from '@kbn/management-settings-types'; import { ToastsStart } from '@kbn/core-notifications-browser'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import { ValueValidation } from '@kbn/core-ui-settings-browser/src/types'; /** * Contextual services used by a {@link FieldInput} component. @@ -23,6 +25,7 @@ export interface FieldInputServices { * @param value The message to display. */ showDanger: (value: string) => void; + validateChange: (key: string, value: any) => Promise; } /** @@ -34,6 +37,9 @@ export interface FieldInputKibanaDependencies { notifications: { toasts: Pick; }; + settings: { + client: IUiSettingsClient; + }; } /** diff --git a/packages/kbn-management/settings/components/field_row/__stories__/common.tsx b/packages/kbn-management/settings/components/field_row/__stories__/common.tsx index e8c51d075c21..5b20b5fcf24b 100644 --- a/packages/kbn-management/settings/components/field_row/__stories__/common.tsx +++ b/packages/kbn-management/settings/components/field_row/__stories__/common.tsx @@ -78,6 +78,13 @@ export const getStory = ( { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} > diff --git a/packages/kbn-management/settings/components/field_row/services.tsx b/packages/kbn-management/settings/components/field_row/services.tsx index 10963041837e..6350b7f7cd10 100644 --- a/packages/kbn-management/settings/components/field_row/services.tsx +++ b/packages/kbn-management/settings/components/field_row/services.tsx @@ -29,11 +29,11 @@ export interface FieldRowProviderProps extends FieldRowServices { export const FieldRowProvider = ({ children, ...services }: FieldRowProviderProps) => { // Typescript types are widened to accept more than what is needed. Take only what is necessary // so the context remains clean. - const { links, showDanger } = services; + const { links, showDanger, validateChange } = services; return ( - {children} + {children} ); }; @@ -45,6 +45,7 @@ export const FieldRowKibanaProvider: FC = ({ children, docLinks, notifications, + settings, }) => { return ( = ({ links: docLinks.links.management, }} > - {children} + + {children} + ); }; diff --git a/packages/kbn-management/settings/components/form/services.tsx b/packages/kbn-management/settings/components/form/services.tsx index e0a48807b351..39aac8b4ecb0 100644 --- a/packages/kbn-management/settings/components/form/services.tsx +++ b/packages/kbn-management/settings/components/form/services.tsx @@ -56,7 +56,7 @@ export const FormKibanaProvider: FC = ({ children, ...de return ( - + {children} diff --git a/packages/kbn-management/settings/components/form/storybook/form.stories.tsx b/packages/kbn-management/settings/components/form/storybook/form.stories.tsx index dce99b908d65..d239c862a631 100644 --- a/packages/kbn-management/settings/components/form/storybook/form.stories.tsx +++ b/packages/kbn-management/settings/components/form/storybook/form.stories.tsx @@ -12,6 +12,7 @@ import { FieldDefinition } from '@kbn/management-settings-types'; import { getFieldDefinitions } from '@kbn/management-settings-field-definition'; import { getSettingsMock } from '@kbn/management-settings-utilities/mocks/settings.mock'; +import { categorizeFields } from '@kbn/management-settings-utilities'; import { uiSettingsClientMock } from '../mocks'; import { Form as Component } from '../form'; import { FormProvider } from '../services'; @@ -37,6 +38,13 @@ export default { saveChanges={action('saveChanges')} showError={action('showError')} showReloadPagePrompt={action('showReloadPagePrompt')} + validateChange={async (key, value) => { + action(`validateChange`)({ + key, + value, + }); + return { successfulValidation: true, valid: true }; + }} > @@ -62,8 +70,16 @@ export const Form = ({ isSavingEnabled, requirePageReload }: FormStoryProps) => uiSettingsClientMock ); - // This is only needed for when a search query is present - const categoryCounts = {}; + const categorizedFields = categorizeFields(fields); + + const categoryCounts = Object.keys(categorizedFields).reduce( + (acc, category) => ({ + ...acc, + [category]: categorizedFields[category].count, + }), + {} + ); + const onClearQuery = () => {}; return ; diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index 31db42d321d2..c176890334dc 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -167,6 +167,9 @@ export const SECURITY_SOLUTION_DEFAULT_ALERT_TAGS_KEY = 'securitySolution:alertT /** This Kibana Advanced Setting allows users to enable/disable the Expandable Flyout */ export const SECURITY_SOLUTION_ENABLE_EXPANDABLE_FLYOUT_SETTING = 'securitySolution:enableExpandableFlyout' as const; +/** This Kibana Advanced Setting allows users to enable/disable querying cold and frozen data tiers in analyzer */ +export const SECURITY_SOLUTION_EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER = + 'securitySolution:excludeColdAndFrozenTiersInAnalyzer' as const; // Timelion settings export const TIMELION_ES_DEFAULT_INDEX_ID = 'timelion:es.default_index'; diff --git a/packages/kbn-mock-idp-plugin/common/constants.ts b/packages/kbn-mock-idp-plugin/common/constants.ts new file mode 100644 index 000000000000..6fb547558757 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/common/constants.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { resolve } from 'path'; + +export const MOCK_IDP_PLUGIN_PATH = resolve(__dirname, '..'); +export const MOCK_IDP_METADATA_PATH = resolve(MOCK_IDP_PLUGIN_PATH, 'metadata.xml'); + +export const MOCK_IDP_LOGIN_PATH = '/mock_idp/login'; +export const MOCK_IDP_LOGOUT_PATH = '/mock_idp/logout'; + +export const MOCK_IDP_REALM_NAME = 'mock-idp'; +export const MOCK_IDP_ENTITY_ID = 'urn:mock-idp'; // Must match `entityID` in `metadata.xml` +export const MOCK_IDP_ROLE_MAPPING_NAME = 'mock-idp-mapping'; + +export const MOCK_IDP_ATTRIBUTE_PRINCIPAL = 'http://saml.elastic-cloud.com/attributes/principal'; +export const MOCK_IDP_ATTRIBUTE_ROLES = 'http://saml.elastic-cloud.com/attributes/roles'; +export const MOCK_IDP_ATTRIBUTE_EMAIL = 'http://saml.elastic-cloud.com/attributes/email'; +export const MOCK_IDP_ATTRIBUTE_NAME = 'http://saml.elastic-cloud.com/attributes/name'; diff --git a/packages/kbn-mock-idp-plugin/common/index.ts b/packages/kbn-mock-idp-plugin/common/index.ts new file mode 100644 index 000000000000..aaaffc15f10f --- /dev/null +++ b/packages/kbn-mock-idp-plugin/common/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { + MOCK_IDP_PLUGIN_PATH, + MOCK_IDP_METADATA_PATH, + MOCK_IDP_LOGIN_PATH, + MOCK_IDP_LOGOUT_PATH, + MOCK_IDP_REALM_NAME, + MOCK_IDP_ENTITY_ID, + MOCK_IDP_ROLE_MAPPING_NAME, + MOCK_IDP_ATTRIBUTE_PRINCIPAL, + MOCK_IDP_ATTRIBUTE_ROLES, + MOCK_IDP_ATTRIBUTE_EMAIL, + MOCK_IDP_ATTRIBUTE_NAME, +} from './constants'; +export { + createMockIdpMetadata, + createSAMLResponse, + ensureSAMLRoleMapping, + parseSAMLAuthnRequest, +} from './utils'; diff --git a/packages/kbn-mock-idp-plugin/common/utils.ts b/packages/kbn-mock-idp-plugin/common/utils.ts new file mode 100644 index 000000000000..5d55fbc56568 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/common/utils.ts @@ -0,0 +1,231 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Client } from '@elastic/elasticsearch'; +import { SignedXml } from 'xml-crypto'; +import { KBN_KEY_PATH, KBN_CERT_PATH } from '@kbn/dev-utils'; +import { readFile } from 'fs/promises'; +import zlib from 'zlib'; +import { promisify } from 'util'; +import { parseString } from 'xml2js'; +import { X509Certificate } from 'crypto'; + +import { + MOCK_IDP_REALM_NAME, + MOCK_IDP_ENTITY_ID, + MOCK_IDP_ROLE_MAPPING_NAME, + MOCK_IDP_ATTRIBUTE_PRINCIPAL, + MOCK_IDP_ATTRIBUTE_ROLES, + MOCK_IDP_ATTRIBUTE_EMAIL, + MOCK_IDP_ATTRIBUTE_NAME, + MOCK_IDP_LOGIN_PATH, + MOCK_IDP_LOGOUT_PATH, +} from './constants'; + +const inflateRawAsync = promisify(zlib.inflateRaw); +const parseStringAsync = promisify(parseString); + +/** + * Creates XML metadata for our mock identity provider. + * + * This can be saved to file and used to configure Elasticsearch SAML realm. + * + * @param kibanaUrl Fully qualified URL where Kibana is hosted (including base path) + */ +export async function createMockIdpMetadata(kibanaUrl: string) { + const signingKey = await readFile(KBN_CERT_PATH); + const cert = new X509Certificate(signingKey); + const trimTrailingSlash = (url: string) => (url.endsWith('/') ? url.slice(0, -1) : url); + + return ` + + + + + + ${cert.raw.toString('base64')} + + + + + + + + + + `; +} + +/** + * Creates a SAML response that can be passed directly to the Kibana ACS endpoint to authenticate a user. + * + * @example Create a SAML response. + * + * ```ts + * const samlResponse = await createSAMLResponse({ + * username: '1234567890', + * email: 'mail@elastic.co', + * fullname: 'Test User', + * roles: ['t1_analyst', 'editor'], + * }) + * ``` + * + * @example Authenticate user with SAML response. + * + * ```ts + * fetch('/api/security/saml/callback', { + * method: 'POST', + * body: JSON.stringify({ SAMLResponse: samlResponse }), + * redirect: 'manual' + * }) + * ``` + */ +export async function createSAMLResponse(options: { + /** Fully qualified URL where Kibana is hosted (including base path) */ + kibanaUrl: string; + /** ID from SAML authentication request */ + authnRequestId?: string; + username: string; + fullname?: string; + email?: string; + roles: string[]; +}) { + const issueInstant = new Date().toISOString(); + const notOnOrAfter = new Date(Date.now() + 3600 * 1000).toISOString(); + + const samlAssertionTemplateXML = ` + + ${MOCK_IDP_ENTITY_ID} + + _643ec1b3f5673583b9f9a1e9e73a36daa2a3748f + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + ${options.username} + + + ${options.roles + .map( + (role) => `${role}` + ) + .join('')} + + ${ + options.email + ? ` + ${options.email} + ` + : '' + } + ${ + options.fullname + ? ` + ${options.fullname} + ` + : '' + } + + + `; + + const signature = new SignedXml(); + signature.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + signature.signingKey = await readFile(KBN_KEY_PATH); + + // Adds a reference to a `Assertion` xml element and an array of transform algorithms to be used during signing. + signature.addReference( + `//*[local-name(.)='Assertion']`, + [ + 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', + 'http://www.w3.org/2001/10/xml-exc-c14n#', + ], + 'http://www.w3.org/2001/04/xmlenc#sha256' + ); + + signature.computeSignature(samlAssertionTemplateXML, { + location: { reference: `//*[local-name(.)='Issuer']`, action: 'after' }, + }); + + const value = await Buffer.from( + ` + + ${MOCK_IDP_ENTITY_ID} + + + ${signature.getSignedXml()} + + ` + ).toString('base64'); + + return value; +} + +/** + * Creates the role mapping required for developers to authenticate using SAML. + */ +export async function ensureSAMLRoleMapping(client: Client) { + return client.transport.request({ + method: 'PUT', + path: `/_security/role_mapping/${MOCK_IDP_ROLE_MAPPING_NAME}`, + body: { + enabled: true, + role_templates: [ + { + template: '{"source":"{{#tojson}}groups{{/tojson}}"}', + format: 'json', + }, + ], + rules: { + all: [ + { + field: { + 'realm.name': MOCK_IDP_REALM_NAME, + }, + }, + ], + }, + }, + }); +} + +interface SAMLAuthnRequest { + 'saml2p:AuthnRequest': { + $: { + AssertionConsumerServiceURL: string; + Destination: string; + ID: string; + IssueInstant: string; + }; + }; +} + +export async function parseSAMLAuthnRequest(samlRequest: string) { + const inflatedSAMLRequest = (await inflateRawAsync(Buffer.from(samlRequest, 'base64'))) as Buffer; + const parsedSAMLRequest = (await parseStringAsync( + inflatedSAMLRequest.toString() + )) as SAMLAuthnRequest; + return parsedSAMLRequest['saml2p:AuthnRequest'].$; +} diff --git a/packages/kbn-mock-idp-plugin/kibana.jsonc b/packages/kbn-mock-idp-plugin/kibana.jsonc new file mode 100644 index 000000000000..929d7b9b990d --- /dev/null +++ b/packages/kbn-mock-idp-plugin/kibana.jsonc @@ -0,0 +1,11 @@ +{ + "type": "plugin", + "id": "@kbn/mock-idp-plugin", + "owner": "@elastic/kibana-security", + "devOnly": true, + "plugin": { + "id": "mockIdpPlugin", + "server": true, + "browser": false + } +} \ No newline at end of file diff --git a/packages/kbn-mock-idp-plugin/package.json b/packages/kbn-mock-idp-plugin/package.json new file mode 100644 index 000000000000..456a2cfa5ce3 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/mock-idp-plugin", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-mock-idp-plugin/server/index.ts b/packages/kbn-mock-idp-plugin/server/index.ts new file mode 100644 index 000000000000..db807851d456 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/server/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { plugin } from './plugin'; diff --git a/packages/kbn-mock-idp-plugin/server/plugin.ts b/packages/kbn-mock-idp-plugin/server/plugin.ts new file mode 100644 index 000000000000..20c115d80cf2 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/server/plugin.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { PluginInitializer, Plugin } from '@kbn/core-plugins-server'; +import { schema } from '@kbn/config-schema'; + +import { + MOCK_IDP_LOGIN_PATH, + MOCK_IDP_LOGOUT_PATH, + createSAMLResponse, + parseSAMLAuthnRequest, +} from '../common'; + +export const plugin: PluginInitializer = async (): Promise => ({ + setup(core) { + core.http.resources.register( + { + path: MOCK_IDP_LOGIN_PATH, + validate: { + query: schema.object({ + SAMLRequest: schema.string(), + }), + }, + options: { authRequired: false }, + }, + async (context, request, response) => { + let samlRequest: Awaited>; + try { + samlRequest = await parseSAMLAuthnRequest(request.query.SAMLRequest); + } catch (error) { + return response.badRequest({ + body: '[request query.SAMLRequest]: value is not valid SAMLRequest.', + }); + } + + const userRoles: Array<[string, string]> = [ + ['system_indices_superuser', 'system_indices_superuser'], + ['t1_analyst', 't1_analyst'], + ['t2_analyst', 't2_analyst'], + ['t3_analyst', 't3_analyst'], + ['threat_intelligence_analyst', 'threat_intelligence_analyst'], + ['rule_author', 'rule_author'], + ['soc_manager', 'soc_manager'], + ['detections_admin', 'detections_admin'], + ['platform_engineer', 'platform_engineer'], + ['endpoint_operations_analyst', 'endpoint_operations_analyst'], + ['endpoint_policy_manager', 'endpoint_policy_manager'], + ]; + + const samlResponses = await Promise.all( + userRoles.map(([username, role]) => + createSAMLResponse({ + authnRequestId: samlRequest.ID, + kibanaUrl: samlRequest.AssertionConsumerServiceURL, + username, + roles: [role], + }) + ) + ); + + return response.renderHtml({ + body: ` + + Mock Identity Provider + + +

    Mock Identity Provider

    +
    +

    Pick a role:

    +
      + ${userRoles + .map( + ([username], i) => + ` +
    • + +
    • + ` + ) + .join('')} +
    + + + `, + }); + } + ); + + core.http.resources.register( + { + path: `${MOCK_IDP_LOGIN_PATH}/submit.js`, + validate: false, + options: { authRequired: false }, + }, + (context, request, response) => { + return response.renderJs({ body: 'document.getElementById("loginForm").submit();' }); + } + ); + + core.http.resources.register( + { + path: MOCK_IDP_LOGOUT_PATH, + validate: false, + options: { authRequired: false }, + }, + async (context, request, response) => { + return response.redirected({ headers: { location: '/' } }); + } + ); + }, + start() {}, + stop() {}, +}); diff --git a/packages/kbn-mock-idp-plugin/tsconfig.json b/packages/kbn-mock-idp-plugin/tsconfig.json new file mode 100644 index 000000000000..1420a34208f1 --- /dev/null +++ b/packages/kbn-mock-idp-plugin/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/core-plugins-server", + "@kbn/config-schema", + "@kbn/dev-utils" + ] +} diff --git a/packages/kbn-openapi-bundler/README.md b/packages/kbn-openapi-bundler/README.md new file mode 100644 index 000000000000..4a82cb9c2033 --- /dev/null +++ b/packages/kbn-openapi-bundler/README.md @@ -0,0 +1,493 @@ +# OpenAPI Specs Bundler for Kibana + +`@kbn/openapi-bundler` is a tool for transforming multiple OpenAPI specification files (source specs) into a single bundled specification file (target spec). +This can be used for API docs generation purposes. This approach allows you to: + +- Abstract away the knowledge of where you keep your OpenAPI specs, how many specs there are, and how to find them. The Docs team should only know where a single file is located - the bundle. +- Omit internal API endpoints from the bundle. +- Omit API endpoints that are hidden behind a feature flag and haven't been released yet. +- Omit parts of schemas that are hidden behind a feature flag (e.g. a new property added to an existing response schema). +- Omit custom OpenAPI attributes from the bundle, such as `x-codegen-enabled`, `x-internal`, and `x-modify` (see below). +- Transform the target schema according to the custom OpenAPI attributes, such as `x-modify`. +- Resolve references and inline some of them for better readability. The bundled file contains only local references and paths. + +## Getting started + +To let this package help you with bundling your OpenAPI specifications you should have OpenAPI specification describing your API endpoint request and response schemas along with common types used in your API. Refer [@kbn/openapi-generator](../kbn-openapi-generator/README.md) and [OpenAPI 3.0.3](https://swagger.io/specification/v3/) (support for [OpenAPI 3.1.0](https://swagger.io/specification/) is planned to be added soon) for more details. + +Following recommendations provided in `@kbn/openapi-generator` you should have OpenAPI specs defined under a common folder something like `my-plugin/common/api`. + +Currently package supports only programmatic API. As the next step you need to create a JavaScript script file like below and put it to `my-plugin/scripts/openapi` + +```ts +require('../../../../../src/setup_node_env'); +const { bundle } = require('@kbn/openapi-bundler'); +const { resolve } = require('path'); + +// define ROOT as `my-plugin` instead of `my-plugin/scripts/openapi` +// pay attention to this constant when your script's location is different +const ROOT = resolve(__dirname, '../..'); + +bundle({ + rootDir: ROOT, // Root path e.g. plugin root directory + sourceGlob: './**/*.schema.yaml', // Glob pattern to find OpenAPI specification files + outputFilePath: './target/openapi/my-plugin.bundled.schema.yaml', // +}); +``` + +And add a script entry to your `package.json` file + +```json +{ + "author": "Elastic", + ... + "scripts": { + ... + "openapi:bundle": "node scripts/openapi/bundle" + } +} +``` + +Finally you should be able to run OpenAPI bundler via + +```bash +yarn openapi:bundle +``` + +This command will produce a bundled file `my-plugin/target/openapi/my-plugin.bundled.schema.yaml` containing +all specs matching `./**/*.schema.yaml` glob pattern. + +Here's an example how your source schemas can look like and the expected result + +- `example1.schema.yaml` + +```yaml +openapi: 3.0.3 +info: + title: My endpoint + version: '2023-10-31' + +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +- `example2.schema.yaml` + +```yaml +openapi: 3.0.3 +info: + title: My endpoint + version: '2023-10-31' + +paths: + /api/path/to/endpoint: + post: + x-internal: true + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +And the target spec will look like + +```yaml +openapi: 3.0.3 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + post: + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +components: + schemas: {} +``` + +## Supported custom (`x-` prefixed) properties + +OpenAPI specification allows to define custom properties. They can be used to describe extra functionality that is not covered by the standard OpenAPI Specification. We currently support the following custom properties + +- [x-internal](#x-internal) - marks source spec nodes the bundler must NOT include in the target spec +- [x-modify](#x-modify) - marks nodes to be modified by the bundler +- [x-inline](#x-inline) - marks reference nodes to be inlined when bundled + +### `x-internal` + +Marks source spec nodes the bundler must NOT include in the target spec. + +**Supported values**: `true` + +When bundler encounters a node with `x-internal: true` it doesn't include this node into the target spec. It's useful when it's necessary to hide some chunk of OpenAPI spec because functionality supporting it is hidden under a feature flag or the chunk is just for internal use. + +#### Examples + +The following spec defines an API endpoint `/api/path/to/endpoint` accepting `GET` and `POST` requests. It has `x-internal: true` defined in `post` section meaning it won't be included in the target spec. + +```yaml +openapi: 3.0.3 +info: + title: My endpoint + version: '2023-10-31' + +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + post: + x-internal: true + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +The target spec will look like + +```yaml +openapi: 3.0.3 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +`x-internal: true` can also be defined next to a reference. + +```yaml +openapi: 3.0.3 +info: + title: My endpoint + version: '2023-10-31' + +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + post: + $ref: '#/components/schemas/MyPostEndpointResponse' + x-internal: true + +components: + schemas: + MyPostEndpointResponse: + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +The target spec will look like + +```yaml +openapi: 3.0.3 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + get: + operationId: MyGetEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +### `x-modify` + +Marks nodes to be modified by the bundler. + +**Supported values**: `partial` or `required` + +Value `partial` leads to removing `required` property making params under `properties` optional. Value `required` leads to adding or extending `required` property by adding all param names under `properties`. + +#### Examples + +The following spec has `x-modify: partial` at `schema` section. It makes params optional for a PATCH request. + +```yaml +openapi: 3.0.0 +info: + title: My endpoint + version: '2023-10-31' +paths: + /api/path/to/endpoint: + patch: + operationId: MyPatchEndpoint + requestBody: + required: true + content: + application/json: + schema: + x-modify: partial + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number + required: + - param1 + - param2 +``` + +The target spec will look like + +```yaml +openapi: 3.0.0 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + patch: + operationId: MyPatchEndpoint + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number +``` + +The following spec has `x-modify: required` at `schema` section. It makes params optional for a PATCH request. + +```yaml +openapi: 3.0.0 +info: + title: My endpoint + version: '2023-10-31' +paths: + /api/path/to/endpoint: + put: + operationId: MyPutEndpoint + requestBody: + required: true + content: + application/json: + schema: + x-modify: required + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number +``` + +The target spec will look like + +```yaml +openapi: 3.0.0 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + patch: + operationId: MyPatchEndpoint + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number + required: + - param1 + - param2 +``` + +`x-modify` can also be defined next to a reference. + +```yaml +openapi: 3.0.0 +info: + title: My endpoint + version: '2023-10-31' +paths: + /api/path/to/endpoint: + patch: + operationId: MyPatchEndpoint + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PatchProps' + x-modify: partial + +components: + schemas: + PatchProps: + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number + required: + - param1 + - param2 +``` + +The target spec will look like + +```yaml +openapi: 3.0.0 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + patch: + operationId: MyPatchEndpoint + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + param1: + type: string + enum: [val1, val2, val3] + param2: + type: number +``` + +### `x-inline` + +Marks reference nodes to be inlined when bundled. + +**Supported values**: `true` + +`x-inline: true` can be specified at a reference node itself (a node with `$ref` key) or at a node `$ref` resolves to. When bundler encounters such a node it assigns (copies keys via `Object.assign()`) the latter node (a node`$ref` resolves to) to the first node (a node with `$ref` key). This way target won't have referenced component in `components` as well. + +#### Examples + +The following spec defines an API endpoint `/api/path/to/endpoint` accepting `POST` request. It has `x-inline: true` specified in `post` section meaning reference `#/components/schemas/MyPostEndpointResponse` will be inlined in the target spec. + +```yaml +openapi: 3.0.3 +info: + title: My endpoint + version: '2023-10-31' + +paths: + /api/path/to/endpoint: + post: + $ref: '#/components/schemas/MyPostEndpointResponse' + x-inline: true + +components: + schemas: + MyPostEndpointResponse: + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` + +The target spec will look like + +```yaml +openapi: 3.0.3 +info: + title: Bundled specs file. See individual paths.verb.tags for details + version: not applicable +paths: + /api/path/to/endpoint: + post: + operationId: MyPostEndpoint + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object +``` diff --git a/packages/kbn-openapi-bundler/index.ts b/packages/kbn-openapi-bundler/index.ts new file mode 100644 index 000000000000..badd58def955 --- /dev/null +++ b/packages/kbn-openapi-bundler/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './src/openapi_bundler'; diff --git a/packages/kbn-openapi-bundler/jest.config.js b/packages/kbn-openapi-bundler/jest.config.js new file mode 100644 index 000000000000..a1a964777331 --- /dev/null +++ b/packages/kbn-openapi-bundler/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-openapi-bundler'], +}; diff --git a/packages/kbn-openapi-bundler/kibana.jsonc b/packages/kbn-openapi-bundler/kibana.jsonc new file mode 100644 index 000000000000..0434322591cc --- /dev/null +++ b/packages/kbn-openapi-bundler/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "devOnly": true, + "id": "@kbn/openapi-bundler", + "owner": "@elastic/security-detection-rule-management", + "type": "shared-common" +} diff --git a/packages/kbn-openapi-bundler/package.json b/packages/kbn-openapi-bundler/package.json new file mode 100644 index 000000000000..83d92beb71aa --- /dev/null +++ b/packages/kbn-openapi-bundler/package.json @@ -0,0 +1,7 @@ +{ + "description": "OpenAPI specs bundler for Kibana", + "license": "SSPL-1.0 OR Elastic License 2.0", + "name": "@kbn/openapi-bundler", + "private": true, + "version": "1.0.0" +} diff --git a/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/expected.yaml new file mode 100644 index 000000000000..d8eb6a8b66c6 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/expected.yaml @@ -0,0 +1,40 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/ConflictTestSchema' + +spec2.schema.yaml: + openapi: 3.0.3 + info: + title: Another test endpoint + version: '2023-10-31' + paths: + /api/another_api: + put: + operationId: AnotherTestEndpointPut + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/ConflictTestSchema' + +shared_components.schema.yaml: + components: + schemas: + ConflictTestSchema: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec1.schema.yaml new file mode 100644 index 000000000000..a44cd371ba32 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec1.schema.yaml @@ -0,0 +1,21 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/ConflictTestSchema' + +components: + schemas: + ConflictTestSchema: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec2.schema.yaml new file mode 100644 index 000000000000..4a5670f8ae5f --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/conflicting_but_equal_refs_in_different_specs/spec2.schema.yaml @@ -0,0 +1,21 @@ +openapi: 3.0.3 +info: + title: Another test endpoint + version: '2023-10-31' +paths: + /api/another_api: + put: + operationId: AnotherTestEndpointPut + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/ConflictTestSchema' + +components: + schemas: + ConflictTestSchema: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec1.schema.yaml new file mode 100644 index 000000000000..765811b78a61 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec1.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/ConflictTestSchema' + +components: + schemas: + ConflictTestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec2.schema.yaml new file mode 100644 index 000000000000..4a5670f8ae5f --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/conflicting_refs_in_different_specs/spec2.schema.yaml @@ -0,0 +1,21 @@ +openapi: 3.0.3 +info: + title: Another test endpoint + version: '2023-10-31' +paths: + /api/another_api: + put: + operationId: AnotherTestEndpointPut + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/ConflictTestSchema' + +components: + schemas: + ConflictTestSchema: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/expected.yaml new file mode 100644 index 000000000000..0b916b7b17ac --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/expected.yaml @@ -0,0 +1,44 @@ +version1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + +version2.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-11-11' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + field2: + type: string + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version1.schema.yaml new file mode 100644 index 000000000000..5b7f6a8718fc --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version1.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer diff --git a/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version2.schema.yaml new file mode 100644 index 000000000000..4492f449ba2f --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_endpoint_versions/version2.schema.yaml @@ -0,0 +1,20 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-11-11' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + field2: + type: string diff --git a/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/expected.yaml new file mode 100644 index 000000000000..3aa6c7051ebc --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/expected.yaml @@ -0,0 +1,42 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + +spec2.schema.yaml: + openapi: 3.1.0 + info: + title: Test endpoint POST + version: '2023-10-31' + paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field2: + type: string + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec1.schema.yaml new file mode 100644 index 000000000000..5b7f6a8718fc --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec1.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer diff --git a/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec2.schema.yaml new file mode 100644 index 000000000000..e437e40e6698 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/different_openapi_versions/spec2.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.1.0 +info: + title: Test endpoint POST + version: '2023-10-31' +paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field2: + type: string diff --git a/packages/kbn-openapi-bundler/src/__test__/inline_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/inline_ref/expected.yaml new file mode 100644 index 000000000000..270886caa051 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/inline_ref/expected.yaml @@ -0,0 +1,50 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + anyOf: + - type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + - $ref: './shared_components.schema.yaml#/components/schemas/TestSchema2' + - $ref: './shared_components.schema.yaml#/components/schemas/TestSchema3' + +shared_components.schema.yaml: + components: + schemas: + TestSchema2: + x-inline: false + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + + TestSchema3: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/inline_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/inline_ref/spec.schema.yaml new file mode 100644 index 000000000000..f5cdb2694a5c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/inline_ref/spec.schema.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/TestSchema1' + - $ref: '#/components/schemas/TestSchema2' + - $ref: '#/components/schemas/TestSchema3' + +components: + schemas: + TestSchema1: + x-inline: true + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + + TestSchema2: + x-inline: false + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + + TestSchema3: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/expected.yaml new file mode 100644 index 000000000000..fa679d0c3f8c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/expected.yaml @@ -0,0 +1,26 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/spec.schema.yaml new file mode 100644 index 000000000000..9646051aab90 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_partial_node/spec.schema.yaml @@ -0,0 +1,26 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + x-modify: partial + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + required: + - field1 + - field2 diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/expected.yaml new file mode 100644 index 000000000000..fa679d0c3f8c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/expected.yaml @@ -0,0 +1,26 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/spec.schema.yaml new file mode 100644 index 000000000000..547bb4cd913b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_partial_ref/spec.schema.yaml @@ -0,0 +1,31 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/TestSchema' + x-modify: partial + +components: + schemas: + TestSchema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + required: + - field1 + - field2 diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_required_node/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_required_node/expected.yaml new file mode 100644 index 000000000000..3b075e3cf803 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_required_node/expected.yaml @@ -0,0 +1,29 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + required: + - field1 + - field2 + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_required_node/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_required_node/spec.schema.yaml new file mode 100644 index 000000000000..68d478ea8caa --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_required_node/spec.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + x-modify: required + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/expected.yaml new file mode 100644 index 000000000000..3b075e3cf803 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/expected.yaml @@ -0,0 +1,29 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + required: + - field1 + - field2 + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/spec.schema.yaml new file mode 100644 index 000000000000..0f02e3e905e2 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/modify_required_ref/spec.schema.yaml @@ -0,0 +1,28 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/TestSchema' + x-modify: required + +components: + schemas: + TestSchema: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/common.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/common.schema.yaml new file mode 100644 index 000000000000..6e0ec47b773c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/common.schema.yaml @@ -0,0 +1,21 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: {} + +components: + schemas: + CircularTestSchema: + type: string + data: + items: + $ref: '#/components/schemas/AnotherCircularTestSchema' + + AnotherCircularTestSchema: + anyof: + - $ref: '#/components/schemas/CircularTestSchema' + - type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/expected.yaml new file mode 100644 index 000000000000..cce50159ca39 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/expected.yaml @@ -0,0 +1,50 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/CircularTestSchema' + +spec2.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint POST + version: '2023-10-31' + paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/CircularTestSchema' + +shared_components.schema.yaml: + components: + schemas: + CircularTestSchema: + type: string + data: + items: + $ref: '#/components/schemas/AnotherCircularTestSchema' + + AnotherCircularTestSchema: + anyof: + - $ref: '#/components/schemas/CircularTestSchema' + - type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec1.schema.yaml new file mode 100644 index 000000000000..2e64f53087f8 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec1.schema.yaml @@ -0,0 +1,15 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/CircularTestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec2.schema.yaml new file mode 100644 index 000000000000..92ebc5f4468e --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_ref_specs/spec2.schema.yaml @@ -0,0 +1,15 @@ +openapi: 3.0.3 +info: + title: Test endpoint POST + version: '2023-10-31' +paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/CircularTestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_spec/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_spec/expected.yaml new file mode 100644 index 000000000000..b5bb0cffb639 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_spec/expected.yaml @@ -0,0 +1,27 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: &ref0 + type: object + properties: + - name: field1 + required: false + schema: *ref0 + - field2: + required: false + schema: + type: string + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/recursive_spec/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/recursive_spec/spec.schema.yaml new file mode 100644 index 000000000000..f9e3d8b2c590 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/recursive_spec/spec.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: &ref0 + type: object + properties: + - name: field1 + required: false + schema: *ref0 + - field2: + required: false + schema: + type: string diff --git a/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/expected.yaml new file mode 100644 index 000000000000..2b75720a069b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/expected.yaml @@ -0,0 +1,24 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/CircularTestSchema' + +shared_components.schema.yaml: + components: + schemas: + CircularTestSchema: + type: string + data: + $ref: '#/components/schemas/CircularTestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/spec.schema.yaml new file mode 100644 index 000000000000..d90a11781845 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/self_recursive_ref/spec.schema.yaml @@ -0,0 +1,22 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/CircularTestSchema' + +components: + schemas: + CircularTestSchema: + type: string + data: + $ref: '#/components/schemas/CircularTestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/skip_internal/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/skip_internal/expected.yaml new file mode 100644 index 000000000000..d8f6d6cb474b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/skip_internal/expected.yaml @@ -0,0 +1,31 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + anyOf: + - $ref: './shared_components.schema.yaml#/components/schemas/TestSchema1' + - type: object + +shared_components.schema.yaml: + components: + schemas: + TestSchema1: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/skip_internal/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/skip_internal/spec.schema.yaml new file mode 100644 index 000000000000..1d172978a424 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/skip_internal/spec.schema.yaml @@ -0,0 +1,57 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/TestSchema1' + - $ref: '#/components/schemas/TestSchema2' + x-internal: true + - type: object + properties: + x-internal: true + field1: + $ref: '#/components/schemas/TestSchema3' + +components: + schemas: + TestSchema1: + # x-internal is not supported here + # x-internal: true + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + + TestSchema2: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 + + TestSchema3: + type: object + properties: + field1: + type: string + enum: [value1] + field2: + type: integer + minimum: 1 diff --git a/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/expected.yaml new file mode 100644 index 000000000000..3015eb607287 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/expected.yaml @@ -0,0 +1,22 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec1.schema.yaml new file mode 100644 index 000000000000..5b7f6a8718fc --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec1.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer diff --git a/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec2.schema.yaml new file mode 100644 index 000000000000..5a53977b6910 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/skip_internal_endpoint/spec2.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint POST + version: '2023-10-31' +paths: + /internal/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field2: + type: string diff --git a/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/common.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/common.schema.yaml new file mode 100644 index 000000000000..b710c4e8b114 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/common.schema.yaml @@ -0,0 +1,13 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: {} + +components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/expected.yaml new file mode 100644 index 000000000000..48c9045d62ce --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/expected.yaml @@ -0,0 +1,25 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/TestSchema' + +shared_components.schema.yaml: + components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/spec.schema.yaml new file mode 100644 index 000000000000..b1d910fa5e96 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/spec_with_external_ref/spec.schema.yaml @@ -0,0 +1,15 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/TestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/expected.yaml new file mode 100644 index 000000000000..48c9045d62ce --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/expected.yaml @@ -0,0 +1,25 @@ +spec.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/TestSchema' + +shared_components.schema.yaml: + components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/spec.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/spec.schema.yaml new file mode 100644 index 000000000000..2339d5eb7aa5 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/spec_with_local_ref/spec.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/TestSchema' + +components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/expected.yaml new file mode 100644 index 000000000000..dbe9fdb445e8 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/expected.yaml @@ -0,0 +1,42 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer + +spec2.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint POST + version: '2023-10-31' + paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field2: + type: string + +shared_components.schema.yaml: + components: {} diff --git a/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec1.schema.yaml new file mode 100644 index 000000000000..5b7f6a8718fc --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec1.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field1: + type: integer diff --git a/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec2.schema.yaml new file mode 100644 index 000000000000..c3ba67e0b46e --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_simple_specs/spec2.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Test endpoint POST + version: '2023-10-31' +paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + field2: + type: string diff --git a/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/common.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/common.schema.yaml new file mode 100644 index 000000000000..b710c4e8b114 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/common.schema.yaml @@ -0,0 +1,13 @@ +openapi: 3.0.3 +info: + title: Test endpoint + version: '2023-10-31' +paths: {} + +components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/expected.yaml b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/expected.yaml new file mode 100644 index 000000000000..d3040ae511b2 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/expected.yaml @@ -0,0 +1,42 @@ +spec1.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint GET + version: '2023-10-31' + paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/TestSchema' + +spec2.schema.yaml: + openapi: 3.0.3 + info: + title: Test endpoint POST + version: '2023-10-31' + paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './shared_components.schema.yaml#/components/schemas/TestSchema' + +shared_components.schema.yaml: + components: + schemas: + TestSchema: + type: string + enum: + - value1 + - value2 diff --git a/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec1.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec1.schema.yaml new file mode 100644 index 000000000000..c08570d69311 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec1.schema.yaml @@ -0,0 +1,15 @@ +openapi: 3.0.3 +info: + title: Test endpoint GET + version: '2023-10-31' +paths: + /api/some_api: + get: + operationId: TestEndpointGet + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/TestSchema' diff --git a/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec2.schema.yaml b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec2.schema.yaml new file mode 100644 index 000000000000..9dec5566875b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/__test__/two_specs_with_external_ref/spec2.schema.yaml @@ -0,0 +1,15 @@ +openapi: 3.0.3 +info: + title: Test endpoint POST + version: '2023-10-31' +paths: + /api/some_api: + post: + operationId: TestEndpointPost + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/TestSchema' diff --git a/packages/kbn-openapi-bundler/src/bundler/__mocks__/ref_resolver.ts b/packages/kbn-openapi-bundler/src/bundler/__mocks__/ref_resolver.ts new file mode 100644 index 000000000000..69fd3f5a41af --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/__mocks__/ref_resolver.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const RefResolver = jest.fn().mockImplementation(() => ({ + resolveRef: jest.fn(), + resolveDocument: jest.fn(), +})); diff --git a/packages/kbn-openapi-bundler/src/bundler/bundle_document.ts b/packages/kbn-openapi-bundler/src/bundler/bundle_document.ts new file mode 100644 index 000000000000..1f6884a87f67 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/bundle_document.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isAbsolute } from 'path'; +import { RefResolver } from './ref_resolver'; +import { processDocument } from './process_document'; +import { BundleRefProcessor } from './document_processors/bundle_refs'; +import { createSkipNodeWithInternalPropProcessor } from './document_processors/skip_node_with_internal_prop'; +import { createModifyPartialProcessor } from './document_processors/modify_partial'; +import { createSkipInternalPathProcessor } from './document_processors/skip_internal_path'; +import { ResolvedDocument, ResolvedRef } from './types'; +import { createRemovePropsProcessor } from './document_processors/remove_props'; +import { createModifyRequiredProcessor } from './document_processors/modify_required'; +import { X_CODEGEN_ENABLED, X_INLINE, X_INTERNAL, X_MODIFY } from './known_custom_props'; +import { RemoveUnusedComponentsProcessor } from './document_processors/remove_unused_components'; +import { isPlainObjectType } from '../utils/is_plain_object_type'; + +export class SkipException extends Error { + constructor(public documentPath: string, message: string) { + super(message); + } +} + +export interface BundledDocument extends ResolvedDocument { + bundledRefs: ResolvedRef[]; +} + +/** + * Bundles document into one file and performs appropriate document modifications. + * + * Bundling assumes external references defined via `$ref` are included into the result document. + * Some of the references get inlined. + * + * Document modification includes the following + * - skips nodes with `x-internal: true` property + * - skips paths started with `/internal` + * - modifies nodes having `x-modify` + * + * @param absoluteDocumentPath document's absolute path + * @returns bundled document + */ +export async function bundleDocument(absoluteDocumentPath: string): Promise { + if (!isAbsolute(absoluteDocumentPath)) { + throw new Error( + `bundleDocument expects an absolute document path but got "${absoluteDocumentPath}"` + ); + } + + const refResolver = new RefResolver(); + const resolvedDocument = await refResolver.resolveDocument(absoluteDocumentPath); + + if (!hasPaths(resolvedDocument.document as MaybeObjectWithPaths)) { + // Specs without paths defined are usually considered as shared. Such specs have `components` defined + // and referenced by the specs with paths defined. In this case the shared specs have been + // handled already and must be skipped. + // + // An additional case when it's a rogue spec. Rogue specs are skipped as well as they don't contribute + // to the API endpoints. + throw new SkipException(resolvedDocument.absolutePath, 'Document has no paths defined'); + } + + const bundleRefsProcessor = new BundleRefProcessor(X_INLINE); + const removeUnusedComponentsProcessor = new RemoveUnusedComponentsProcessor(); + + await processDocument(resolvedDocument, refResolver, [ + createSkipNodeWithInternalPropProcessor(X_INTERNAL), + createSkipInternalPathProcessor('/internal'), + createModifyPartialProcessor(), + createModifyRequiredProcessor(), + createRemovePropsProcessor([X_MODIFY, X_CODEGEN_ENABLED]), + bundleRefsProcessor, + removeUnusedComponentsProcessor, + ]); + + if (isPlainObjectType(resolvedDocument.document.components)) { + removeUnusedComponentsProcessor.removeUnusedComponents(resolvedDocument.document.components); + } + + // If document.paths were removed by processors skip the document + if (!hasPaths(resolvedDocument.document as MaybeObjectWithPaths)) { + throw new SkipException( + resolvedDocument.absolutePath, + 'Document has no paths after processing the document' + ); + } + + return { ...resolvedDocument, bundledRefs: bundleRefsProcessor.getBundledRefs() }; +} + +interface MaybeObjectWithPaths { + paths?: unknown; +} + +function hasPaths(document: MaybeObjectWithPaths): boolean { + return ( + typeof document.paths === 'object' && + document.paths !== null && + Object.keys(document.paths).length > 0 + ); +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/bundle_refs.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/bundle_refs.ts new file mode 100644 index 000000000000..4064e92a7b80 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/bundle_refs.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Document, ResolvedRef, TraverseDocumentContext, RefNode } from '../types'; +import { hasProp } from '../../utils/has_prop'; +import { isChildContext } from '../is_child_context'; +import { inlineRef } from './utils/inline_ref'; +import { insertRefByPointer } from '../../utils/insert_by_json_pointer'; + +/** + * Node processor to bundle and conditionally dereference document references. + * + * Bundling means all external references like `../../some_file.schema.yaml#/components/schemas/SomeSchema` saved + * to the result document under corresponding path `components` -> `schemas` -> `SomeSchema` and `$ref` property's + * values is updated to `#/components/schemas/SomeSchema`. + * + * Conditional dereference means inlining references when `inliningPredicate()` returns `true`. If `inliningPredicate` + * is not passed only bundling happens. + */ +export class BundleRefProcessor { + private refs: ResolvedRef[] = []; + + constructor(private inliningPropName: string) {} + + ref(node: RefNode, resolvedRef: ResolvedRef, context: TraverseDocumentContext): void { + if (!resolvedRef.pointer.startsWith('/components/schemas')) { + throw new Error(`$ref pointer must start with "/components/schemas"`); + } + + if ( + hasProp(node, this.inliningPropName, true) || + hasProp(resolvedRef.refNode, this.inliningPropName, true) + ) { + inlineRef(node, resolvedRef); + + delete node[this.inliningPropName]; + } else { + const rootDocument = this.extractRootDocument(context); + + if (!rootDocument.components) { + rootDocument.components = {}; + } + + node.$ref = this.saveComponent( + resolvedRef, + rootDocument.components as Record + ); + this.refs.push(resolvedRef); + } + } + + getBundledRefs(): ResolvedRef[] { + return this.refs; + } + + private saveComponent(ref: ResolvedRef, components: Record): string { + insertRefByPointer(ref.pointer, ref.refNode, components); + + return `#${ref.pointer}`; + } + + private extractRootDocument(context: TraverseDocumentContext): Document { + while (isChildContext(context)) { + context = context.parentContext; + } + + return context.resolvedDocument.document; + } +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_partial.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_partial.ts new file mode 100644 index 000000000000..13c876b7579c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_partial.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DocumentNodeProcessor } from '../types'; +import { hasProp } from '../../utils/has_prop'; +import { inlineRef } from './utils/inline_ref'; +import { X_MODIFY } from '../known_custom_props'; + +/** + * Creates a node processor to modify a node by removing `required` property when + * `x-modify: partial` property is presented in the node. + */ +export function createModifyPartialProcessor(): DocumentNodeProcessor { + return { + ref(node, resolvedRef) { + if (!hasProp(node, X_MODIFY, 'partial')) { + return; + } + + // Inline the ref node because we are gonna modify it + inlineRef(node, resolvedRef); + + delete node.required; + }, + leave(node) { + if (!hasProp(node, X_MODIFY, 'partial')) { + return; + } + + delete node.required; + }, + }; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_required.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_required.ts new file mode 100644 index 000000000000..14a9ac2ea25c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/modify_required.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import chalk from 'chalk'; +import { logger } from '../../logger'; +import { isPlainObjectType } from '../../utils/is_plain_object_type'; +import { DocumentNodeProcessor } from '../types'; +import { hasProp } from '../../utils/has_prop'; +import { X_MODIFY } from '../known_custom_props'; +import { inlineRef } from './utils/inline_ref'; + +/** + * Creates a node processor to modify a node by add or extending `required` property + * when `x-modify: required` property is presented in the node. + */ +export function createModifyRequiredProcessor(): DocumentNodeProcessor { + return { + ref(node, resolvedRef) { + if (!hasProp(node, X_MODIFY, 'required')) { + return; + } + + if (!hasProp(resolvedRef.refNode, 'properties')) { + logger.warning( + `Unable to apply ${chalk.blueBright(X_MODIFY)} to ${chalk.cyan( + resolvedRef.pointer + )} because ${chalk.blueBright('properties')} property was not found` + ); + return; + } + + if (!isPlainObjectType(resolvedRef.refNode.properties)) { + logger.warning( + `Unable to apply ${chalk.blueBright(X_MODIFY)} to ${chalk.cyan( + resolvedRef.pointer + )} because ${chalk.blueBright('properties')} property was not an object` + ); + return; + } + + // Inline the ref node because we are gonna modify it + inlineRef(node, resolvedRef); + + node.required = Object.keys(resolvedRef.refNode.properties); + }, + leave(node) { + if (!hasProp(node, X_MODIFY, 'required')) { + return; + } + + if (!hasProp(node, 'properties')) { + logger.warning( + `Unable to apply ${chalk.blueBright(X_MODIFY)} to ${chalk.cyan( + node + )} because ${chalk.blueBright('properties')} property was not found` + ); + return; + } + + if (!isPlainObjectType(node.properties)) { + logger.warning( + `Unable to apply ${chalk.blueBright(X_MODIFY)} to ${chalk.cyan( + node + )} because ${chalk.blueBright('properties')} property was not an object` + ); + return; + } + + node.required = Object.keys(node.properties); + }, + }; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_props.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_props.ts new file mode 100644 index 000000000000..616d9db11f55 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_props.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObjectType } from '../../utils/is_plain_object_type'; +import { DocumentNodeProcessor } from '../types'; + +/** + * Creates a node processor to remove specified by `propNames` properties. + */ +export function createRemovePropsProcessor(propNames: string[]): DocumentNodeProcessor { + return { + leave(node) { + if (!isPlainObjectType(node)) { + return; + } + + for (const propName of propNames) { + if (!node[propName]) { + continue; + } + + delete node[propName]; + } + }, + }; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_unused_components.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_unused_components.ts new file mode 100644 index 000000000000..1f5053d4667f --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/remove_unused_components.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { hasProp } from '../../utils/has_prop'; +import { isPlainObjectType } from '../../utils/is_plain_object_type'; +import { PlainObjectNode, ResolvedRef } from '../types'; + +/** + * Helps to remove unused components. + * + * To achieve it requires including in document processors list to collect encountered refs + * and then `removeUnusedComponents()` should be invoked after document processing to perform + * actual unused components deletion. + */ +export class RemoveUnusedComponentsProcessor { + private refs = new Set(); + + ref(node: unknown, resolvedRef: ResolvedRef): void { + // If the reference has been inlined by one of the previous processors skip it + if (!hasProp(node, '$ref')) { + return; + } + + this.refs.add(resolvedRef.pointer); + } + + removeUnusedComponents(components: PlainObjectNode): void { + if (!isPlainObjectType(components.schemas)) { + return; + } + + for (const schema of Object.keys(components.schemas)) { + if (!this.refs.has(`/components/schemas/${schema}`)) { + delete components.schemas[schema]; + } + } + } +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_internal_path.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_internal_path.ts new file mode 100644 index 000000000000..42769eab7a68 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_internal_path.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DocumentNodeProcessor } from '../types'; + +/** + * Creates a node processor to skip paths starting with `/internal` and omit them from the result document. + */ +export function createSkipInternalPathProcessor(skipPathPrefix: string): DocumentNodeProcessor { + return { + enter(_, context) { + if (typeof context.parentKey === 'number') { + return false; + } + + return context.parentKey.startsWith(skipPathPrefix); + }, + }; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_node_with_internal_prop.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_node_with_internal_prop.ts new file mode 100644 index 000000000000..4931036bcd1b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/skip_node_with_internal_prop.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DocumentNodeProcessor } from '../types'; + +/** + * Creates a node processor to skip nodes having provided `skipProperty` property + * and omit them from the result document. + */ +export function createSkipNodeWithInternalPropProcessor( + skipProperty: string +): DocumentNodeProcessor { + return { + enter: (node) => skipProperty in node, + }; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/types.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/types.ts new file mode 100644 index 000000000000..60fd512c3cf5 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/types.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface InlinableRefNode { + $ref?: string; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/document_processors/utils/inline_ref.ts b/packages/kbn-openapi-bundler/src/bundler/document_processors/utils/inline_ref.ts new file mode 100644 index 000000000000..3106bf9cbc95 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/document_processors/utils/inline_ref.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { cloneDeep } from 'lodash'; +import { DocumentNode, ResolvedRef } from '../../types'; +import { InlinableRefNode } from '../types'; + +export function inlineRef(node: DocumentNode, resolvedRef: ResolvedRef): void { + // Make sure unwanted side effects don't happen when child nodes are processed + const deepClone = cloneDeep(resolvedRef.refNode); + + Object.assign(node, deepClone); + + delete (node as InlinableRefNode).$ref; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/is_child_context.ts b/packages/kbn-openapi-bundler/src/bundler/is_child_context.ts new file mode 100644 index 000000000000..f3fe4dde915c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/is_child_context.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { TraverseChildDocumentContext, TraverseDocumentContext } from './types'; + +export function isChildContext( + context: TraverseDocumentContext +): context is TraverseChildDocumentContext { + return 'parentContext' in context; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/known_custom_props.ts b/packages/kbn-openapi-bundler/src/bundler/known_custom_props.ts new file mode 100644 index 000000000000..4a1832a62bce --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/known_custom_props.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * `x-internal: true` marks nodes the bundler must NOT include in the result bundled document. Any other values are ignored. + */ +export const X_INTERNAL = 'x-internal'; + +/** + * `x-internal: true` marks reference nodes the bundler must inline in the result bundled document. + */ +export const X_INLINE = 'x-inline'; + +/** + * `x-modify` marks nodes to be modified by the bundler. `partial` and `required` values are supported. + * + * - `partial` leads to removing `required` property making params under `properties` optional + * - `required` leads to adding or extending `required` property by adding all param names under `properties` + */ +export const X_MODIFY = 'x-modify'; + +/** + * `x-codegen-enabled` is used by the code generator package `@kbn/openapi-generator` and shouldn't be included + * in result bundled document. + */ +export const X_CODEGEN_ENABLED = 'x-codegen-enabled'; diff --git a/packages/kbn-openapi-bundler/src/bundler/merge_documents.ts b/packages/kbn-openapi-bundler/src/bundler/merge_documents.ts new file mode 100644 index 000000000000..e27253cefc1c --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/merge_documents.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import deepEqual from 'fast-deep-equal'; +import { basename, dirname, join } from 'path'; +import chalk from 'chalk'; +import { parseRef } from '../utils/parse_ref'; +import { insertRefByPointer } from '../utils/insert_by_json_pointer'; +import { DocumentNodeProcessor, PlainObjectNode, ResolvedDocument, ResolvedRef } from './types'; +import { BundledDocument } from './bundle_document'; +import { processDocument } from './process_document'; + +type MergedDocuments = Record; + +type MergedResult = Record; + +const SHARED_COMPONENTS_FILE_NAME = 'shared_components.schema.yaml'; + +export async function mergeDocuments(bundledDocuments: BundledDocument[]): Promise { + const mergedDocuments: MergedDocuments = {}; + const componentsMap = new Map(); + + for (const bundledDocument of bundledDocuments) { + mergeRefsToMap(bundledDocument.bundledRefs, componentsMap); + + delete bundledDocument.document.components; + + await setRefsFileName(bundledDocument, SHARED_COMPONENTS_FILE_NAME); + mergeDocument(bundledDocument, mergedDocuments); + } + + const result: MergedResult = {}; + + for (const fileName of Object.keys(mergedDocuments)) { + result[fileName] = mergedDocuments[fileName].document; + } + + result[SHARED_COMPONENTS_FILE_NAME] = { + components: componentsMapToComponents(componentsMap), + }; + + return result; +} + +function mergeDocument(resolvedDocument: ResolvedDocument, mergeResult: MergedDocuments): void { + const fileName = basename(resolvedDocument.absolutePath); + + if (!mergeResult[fileName]) { + mergeResult[fileName] = resolvedDocument; + return; + } + + const nonConflictFileName = generateNonConflictingFilePath( + resolvedDocument.absolutePath, + mergeResult + ); + + mergeResult[nonConflictFileName] = resolvedDocument; +} + +function generateNonConflictingFilePath( + documentAbsolutePath: string, + mergeResult: MergedDocuments +): string { + let pathToDocument = dirname(documentAbsolutePath); + let suggestedName = basename(documentAbsolutePath); + + while (mergeResult[suggestedName]) { + suggestedName = `${basename(pathToDocument)}_${suggestedName}`; + pathToDocument = join(pathToDocument, '..'); + } + + return suggestedName; +} + +function mergeRefsToMap(bundledRefs: ResolvedRef[], componentsMap: Map): void { + for (const bundledRef of bundledRefs) { + const existingRef = componentsMap.get(bundledRef.pointer); + + if (!existingRef) { + componentsMap.set(bundledRef.pointer, bundledRef); + continue; + } + + if (deepEqual(existingRef.refNode, bundledRef.refNode)) { + continue; + } + + throw new Error( + `❌ Unable to bundle documents due to conflicts in references. Schema ${chalk.yellow( + bundledRef.pointer + )} is defined in ${chalk.blue(existingRef.absolutePath)} and in ${chalk.magenta( + bundledRef.absolutePath + )} but has not matching definitions.` + ); + } +} + +function componentsMapToComponents( + componentsMap: Map +): Record { + const result: Record = {}; + + for (const resolvedRef of componentsMap.values()) { + insertRefByPointer(resolvedRef.pointer, resolvedRef.refNode, result); + } + + return result; +} + +async function setRefsFileName( + resolvedDocument: ResolvedDocument, + fileName: string +): Promise { + // We don't need to follow references + const stubRefResolver = { + resolveRef: async (refDocumentAbsolutePath: string, pointer: string): Promise => ({ + absolutePath: refDocumentAbsolutePath, + pointer, + document: resolvedDocument.document, + refNode: {}, + }), + resolveDocument: async (): Promise => ({ + absolutePath: '', + document: resolvedDocument.document, + }), + }; + const setRefFileProcessor: DocumentNodeProcessor = { + ref: (node) => { + const { pointer } = parseRef(node.$ref); + + node.$ref = `./${fileName}#${pointer}`; + }, + }; + + await processDocument(resolvedDocument, stubRefResolver, [setRefFileProcessor]); +} diff --git a/packages/kbn-openapi-bundler/src/bundler/process_document.test.ts b/packages/kbn-openapi-bundler/src/bundler/process_document.test.ts new file mode 100644 index 000000000000..d78a4ce515b6 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/process_document.test.ts @@ -0,0 +1,224 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { processDocument } from './process_document'; +import { RefResolver } from './ref_resolver'; +import { Document, DocumentNodeProcessor } from './types'; + +jest.mock('./ref_resolver'); + +describe('processDocument', () => { + it('invokes processors in the provided order', async () => { + const resolvedDocument = { + absolutePath: '/path/to/document', + document: {} as Document, + }; + const calls: string[] = []; + const processor1 = { + leave() { + calls.push('processor1'); + }, + }; + const processor2 = { + leave() { + calls.push('processor2'); + }, + }; + + processDocument(resolvedDocument, new RefResolver(), [processor1, processor2]); + + expect(calls).toEqual(['processor1', 'processor2']); + }); + + it('invokes callbacks in expected order (enter -> ref -> leave)', async () => { + const document = { + id: 'root', + t1: { + id: 't1', + $ref: '#/TestRef', + }, + }; + const calls: string[] = []; + const refResolver = new RefResolver(); + const processor: DocumentNodeProcessor = { + enter(node) { + calls.push(`enter - ${(node as NodeWithId).id}`); + return false; + }, + ref(node) { + calls.push(`ref - ${(node as NodeWithId).id}`); + }, + leave(node) { + calls.push(`leave - ${(node as NodeWithId).id}`); + }, + }; + + const refNode = { + id: 'TestRef', + bar: 'foo', + }; + + (refResolver.resolveRef as jest.Mock).mockResolvedValue({ + absolutePath: '/path/to/document', + document: { + TestRef: refNode, + }, + refNode, + pointer: '/TestRef', + }); + + await processDocument( + { + absolutePath: '/path/to/document', + document: document as unknown as Document, + }, + refResolver, + [processor] + ); + + expect(calls).toEqual([ + 'enter - root', + 'enter - t1', + 'enter - TestRef', + 'leave - TestRef', + 'ref - t1', + 'leave - t1', + 'leave - root', + ]); + }); + + it('removes a node after "enter" callback returned true', async () => { + const nodeToRemove = { + id: 't2', + foo: 'bar', + }; + const document = { + t1: { + id: 't1', + }, + t2: nodeToRemove, + }; + const removeNodeProcessor: DocumentNodeProcessor = { + enter(node) { + return node === nodeToRemove; + }, + }; + + await processDocument( + { + absolutePath: '/path/to/document', + document: document as unknown as Document, + }, + new RefResolver(), + [removeNodeProcessor] + ); + + expect(document).toEqual({ + t1: { + id: 't1', + }, + }); + }); + + it('handles recursive documents', async () => { + const nodeA: Record = { + foo: 'bar', + }; + const nodeB: Record = { + bar: ' foo', + }; + + nodeA.circular = nodeB; + nodeB.circular = nodeA; + + const document = { + nodeA, + nodeB, + }; + + await processDocument( + { + absolutePath: '/path/to/document', + document: document as unknown as Document, + }, + new RefResolver(), + [] + ); + + expect(document).toBeDefined(); + }); + + it('handles self-recursive references', async () => { + const document = { + node: { + $ref: '#/TestComponentCircular', + }, + TestComponentCircular: { + $ref: '#/TestComponentCircular', + }, + }; + const refResolver = new RefResolver(); + + (refResolver.resolveRef as jest.Mock).mockResolvedValue({ + absolutePath: '/path/to/document', + document, + refNode: { + $ref: '#/TestComponentCircular', + }, + pointer: '/TestComponentCircular', + }); + + await processDocument( + { + absolutePath: '/path/to/document', + document: document as unknown as Document, + }, + refResolver, + [] + ); + + expect(document).toBeDefined(); + }); + + it('handles recursive references', async () => { + const document: Record = { + node: { + $ref: '#/TestComponentCircular', + }, + TestComponentCircular: { + $ref: '#/AnotherTestComponentCircular', + }, + AnotherTestComponentCircular: { + $ref: '#/TestComponentCircular', + }, + }; + const refResolver = new RefResolver(); + + (refResolver.resolveRef as jest.Mock).mockImplementation((_, pointer) => ({ + absolutePath: '/path/to/document', + document, + refNode: document[pointer.slice(1)], + pointer, + })); + + await processDocument( + { + absolutePath: '/path/to/document', + document: document as unknown as Document, + }, + refResolver, + [] + ); + + expect(document).toBeDefined(); + }); +}); + +interface NodeWithId { + id?: string; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/process_document.ts b/packages/kbn-openapi-bundler/src/bundler/process_document.ts new file mode 100644 index 000000000000..1efe64b87b4e --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/process_document.ts @@ -0,0 +1,203 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { dirname } from 'path'; +import { isPlainObject } from 'lodash'; +import { IRefResolver } from './ref_resolver'; +import { + DocumentNode, + ResolvedDocument, + TraverseDocumentContext, + ResolvedRef, + DocumentNodeProcessor, + RefNode, + PlainObjectNode, +} from './types'; +import { parseRef } from '../utils/parse_ref'; +import { toAbsolutePath } from '../utils/to_absolute_path'; +import { isPlainObjectType } from '../utils/is_plain_object_type'; +import { isChildContext } from './is_child_context'; + +interface TraverseItem { + node: DocumentNode; + context: TraverseDocumentContext; + /** + * Keeps track of visited nodes to be able to detect circular references + */ + visitedDocumentNodes: Set; + parentNode: DocumentNode; + parentKey: string | number; + resolvedRef?: ResolvedRef; +} + +export async function processDocument( + resolvedDocument: ResolvedDocument, + refResolver: IRefResolver, + processors: DocumentNodeProcessor[] +): Promise { + const nodesToVisit: TraverseItem[] = [ + { + node: resolvedDocument.document, + context: { + resolvedDocument, + }, + visitedDocumentNodes: new Set(), + parentNode: resolvedDocument.document, + parentKey: '', + }, + ]; + const postOrderTraversalStack: TraverseItem[] = []; + + while (nodesToVisit.length > 0) { + const traverseItem = nodesToVisit.pop() as TraverseItem; + + if (!isTraversableNode(traverseItem.node)) { + continue; + } + + if (traverseItem.visitedDocumentNodes.has(traverseItem.node)) { + // Circular reference in the current document detected + continue; + } + + traverseItem.visitedDocumentNodes.add(traverseItem.node); + + if (shouldSkipNode(traverseItem, processors)) { + removeNode(traverseItem); + continue; + } + + postOrderTraversalStack.push(traverseItem); + + if (isRefNode(traverseItem.node)) { + const currentDocument = isChildContext(traverseItem.context) + ? traverseItem.context.resolvedRef + : traverseItem.context.resolvedDocument; + const { path, pointer } = parseRef(traverseItem.node.$ref); + const refAbsolutePath = path + ? toAbsolutePath(path, dirname(currentDocument.absolutePath)) + : currentDocument.absolutePath; + const absoluteRef = `${refAbsolutePath}#${pointer}`; + + if (isCircularRef(absoluteRef, traverseItem.context)) { + continue; + } + + const resolvedRef = await refResolver.resolveRef(refAbsolutePath, pointer); + const childContext = { + resolvedRef, + parentContext: traverseItem.context, + followedRef: absoluteRef, + }; + + traverseItem.resolvedRef = resolvedRef; + + nodesToVisit.push({ + node: resolvedRef.refNode, + context: childContext, + visitedDocumentNodes: new Set(), + parentNode: traverseItem.parentNode, + parentKey: traverseItem.parentKey, + }); + + continue; + } + + if (Array.isArray(traverseItem.node)) { + for (let i = 0; i < traverseItem.node.length; ++i) { + const nodeItem = traverseItem.node[i]; + + nodesToVisit.push({ + node: nodeItem as DocumentNode, + context: traverseItem.context, + visitedDocumentNodes: traverseItem.visitedDocumentNodes, + parentNode: traverseItem.node, + parentKey: i, + }); + } + } + + if (isPlainObjectType(traverseItem.node)) { + for (const key of Object.keys(traverseItem.node)) { + const value = traverseItem.node[key]; + + nodesToVisit.push({ + node: value as DocumentNode, + context: traverseItem.context, + visitedDocumentNodes: traverseItem.visitedDocumentNodes, + parentNode: traverseItem.node, + parentKey: key, + }); + } + } + } + + for (let i = postOrderTraversalStack.length - 1; i >= 0; --i) { + const traverseItem = postOrderTraversalStack[i]; + + for (const processor of processors) { + // If ref has been inlined by one of the processors it's not a ref node anymore + // so we can skip the following processors + if (isRefNode(traverseItem.node) && traverseItem.resolvedRef) { + processor.ref?.( + traverseItem.node as RefNode, + traverseItem.resolvedRef, + traverseItem.context + ); + } + + processor.leave?.(traverseItem.node, traverseItem.context); + } + } +} + +function isTraversableNode(maybeTraversableNode: unknown): boolean { + // We need to process only objects and arrays. Scalars pass through as is. + return typeof maybeTraversableNode === 'object' && maybeTraversableNode !== null; +} + +export function isRefNode(node: DocumentNode): node is { $ref: string } { + return isPlainObject(node) && '$ref' in node; +} + +function shouldSkipNode(traverseItem: TraverseItem, processors: DocumentNodeProcessor[]): boolean { + return processors?.some((p) => + p.enter?.(traverseItem.node, { + ...traverseItem.context, + parentNode: traverseItem.parentNode, + parentKey: traverseItem.parentKey, + }) + ); +} + +function removeNode(traverseItem: TraverseItem): void { + if (Array.isArray(traverseItem.parentNode) && typeof traverseItem.parentKey === 'number') { + traverseItem.parentNode.splice(traverseItem.parentKey, 1); + return; + } + + delete (traverseItem.parentNode as PlainObjectNode)[traverseItem.parentKey]; +} + +function isCircularRef(absoluteRef: string, context: TraverseDocumentContext): boolean { + let nextContext: TraverseDocumentContext | undefined = context; + + if (!isChildContext(nextContext)) { + return false; + } + + do { + if (nextContext.followedRef === absoluteRef) { + return true; + } + + nextContext = nextContext.parentContext; + } while (nextContext); + + return false; +} diff --git a/packages/kbn-openapi-bundler/src/bundler/ref_resolver.ts b/packages/kbn-openapi-bundler/src/bundler/ref_resolver.ts new file mode 100644 index 000000000000..92b17c19c1b6 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/ref_resolver.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import path from 'path'; +import { extractByJsonPointer } from '../utils/extract_by_json_pointer'; +import { readYamlDocument } from '../utils/read_yaml_document'; +import { ResolvedDocument, ResolvedRef } from './types'; + +export interface IRefResolver { + resolveRef(refDocumentAbsolutePath: string, pointer: string): Promise; + resolveDocument(documentAbsolutePath: string): Promise; +} + +export class RefResolver implements IRefResolver { + private documentsCache = new Map(); + + async resolveRef(refDocumentAbsolutePath: string, pointer: string): Promise { + const resolvedRefDocument = await this.resolveDocument(refDocumentAbsolutePath); + const refNode = extractByJsonPointer(resolvedRefDocument.document, pointer); + const resolvedRef = { + absolutePath: refDocumentAbsolutePath, + pointer, + document: resolvedRefDocument.document, + refNode, + }; + + return resolvedRef; + } + + async resolveDocument(documentAbsolutePath: string): Promise { + if (!path.isAbsolute(documentAbsolutePath)) { + throw new Error( + `resolveDocument requires absolute document path, provided path "${documentAbsolutePath}" is not absolute` + ); + } + + const cachedDocument = this.documentsCache.get(documentAbsolutePath); + + if (cachedDocument) { + return cachedDocument; + } + + try { + const document = await readYamlDocument(documentAbsolutePath); + const resolvedRef = { + absolutePath: documentAbsolutePath, + document, + }; + + this.documentsCache.set(documentAbsolutePath, resolvedRef); + + return resolvedRef; + } catch (e) { + throw new Error(`Unable to resolve document "${documentAbsolutePath}"`, { cause: e }); + } + } +} diff --git a/packages/kbn-openapi-bundler/src/bundler/types.ts b/packages/kbn-openapi-bundler/src/bundler/types.ts new file mode 100644 index 000000000000..06aa533c9122 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/bundler/types.ts @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * A plain object node not containing `$ref` property + */ +export type PlainObjectNode = Record; + +/** + * An array node + */ +export type ArrayNode = unknown[]; + +/** + * A ref node containing `$ref` property besides the others + */ +export interface RefNode extends PlainObjectNode { + $ref: string; +} + +/** + * An abstract OpenAPI entry node. Content besides $ref isn't important. + */ +export type DocumentNode = PlainObjectNode | ArrayNode | RefNode; + +/** + * Document abstraction. We don't mind OpenAPI `3.0` and `3.1` differences. + */ +export type Document = Record; + +export interface ResolvedDocument { + /** + * Document's absolute path + */ + absolutePath: string; + /** + * Document's root + */ + document: Document; +} + +export interface ResolvedRef extends ResolvedDocument { + /** + * Parsed pointer without leading hash symbol (e.g. `/components/schemas/MySchema`) + */ + pointer: string; + + /** + * Resolved ref's node pointer points to + */ + refNode: DocumentNode; +} + +export interface TraverseRootDocumentContext { + /** + * Root document + */ + resolvedDocument: ResolvedDocument; + + parentContext?: undefined; + followedRef?: undefined; +} + +export interface TraverseChildDocumentContext { + /** + * Current document after resolving $ref property + */ + resolvedRef: ResolvedRef; + + /** + * Context of the parent document the current one in `document` field was referenced via $ref. Empty if it's the root document. + */ + parentContext: TraverseDocumentContext; + + /** + * Reference used to resolve the current document + */ + followedRef: string; +} + +/** + * Traverse context storing additional information related to the currently traversed node + */ +export type TraverseDocumentContext = TraverseRootDocumentContext | TraverseChildDocumentContext; + +export type TraverseDocumentEntryContext = TraverseDocumentContext & { + parentNode: DocumentNode; + parentKey: string | number; +}; + +/** + * Entry processor controls when a node should be omitted from the result document. + * + * When result is `true` - omit the node. + */ +export type EntryProcessorFn = ( + node: Readonly, + context: TraverseDocumentEntryContext +) => boolean; + +export type LeaveProcessorFn = (node: DocumentNode, context: TraverseDocumentContext) => void; + +export type RefProcessorFn = ( + node: RefNode, + resolvedRef: ResolvedRef, + context: TraverseDocumentContext +) => void; + +/** + * Document or document node processor gives flexibility in modifying OpenAPI specs and/or collect some metrics. + * For convenience it defined handlers invoked upon action or specific node type. + * + * Currently the following node types supported + * + * - ref - Callback function is invoked upon leaving ref node (a node having `$ref` key) + * + * and the following actions + * + * - enter - Callback function is invoked upon entering any type of node element including ref nodes. It doesn't allow + * to modify node's content but provides an ability to remove the element by returning `true`. + * + * - leave - Callback function is invoked upon leaving any type of node. It give an opportunity to modify the document like + * dereference refs or remove unwanted properties. + */ +export interface DocumentNodeProcessor { + enter?: EntryProcessorFn; + leave?: LeaveProcessorFn; + ref?: RefProcessorFn; +} diff --git a/packages/kbn-openapi-bundler/src/logger.ts b/packages/kbn-openapi-bundler/src/logger.ts new file mode 100644 index 000000000000..de3779fff887 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/logger.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog } from '@kbn/tooling-log'; + +export const logger = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); diff --git a/packages/kbn-openapi-bundler/src/openapi_bundler.test.ts b/packages/kbn-openapi-bundler/src/openapi_bundler.test.ts new file mode 100644 index 000000000000..eaed80727dee --- /dev/null +++ b/packages/kbn-openapi-bundler/src/openapi_bundler.test.ts @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { existsSync, rmSync } from 'fs'; +import { basename, join } from 'path'; +import { bundle } from './openapi_bundler'; +import { readYamlDocument } from './utils/read_yaml_document'; + +const rootPath = join(__dirname, '__test__'); +const targetAbsoluteFilePath = join(rootPath, 'bundled.yaml'); + +describe('OpenAPI Bundler', () => { + afterEach(() => { + removeTargetFile(); + }); + + it('bundles two simple specs', async () => { + await bundleFolder('two_simple_specs'); + await expectBundleToMatchFile('two_simple_specs', 'expected.yaml'); + }); + + it('bundles one file with a local reference', async () => { + await bundleFolder('spec_with_local_ref'); + await expectBundleToMatchFile('spec_with_local_ref', 'expected.yaml'); + }); + + it('bundles one file with an external reference', async () => { + await bundleFolder('spec_with_external_ref'); + await expectBundleToMatchFile('spec_with_external_ref', 'expected.yaml'); + }); + + it('bundles files with external references', async () => { + await bundleFolder('two_specs_with_external_ref'); + await expectBundleToMatchFile('two_specs_with_external_ref', 'expected.yaml'); + }); + + // Fails because `writeYamlDocument()` has `noRefs: true` setting + // it('bundles recursive spec', async () => { + // await bundleFolder('recursive_spec'); + // await expectBundleToMatchFile('recursive_spec', 'expected.yaml'); + // }); + + it('bundles specs with recursive references', async () => { + await bundleFolder('recursive_ref_specs'); + await expectBundleToMatchFile('recursive_ref_specs', 'expected.yaml'); + }); + + it('bundles spec with a self-recursive reference', async () => { + await bundleFolder('self_recursive_ref'); + await expectBundleToMatchFile('self_recursive_ref', 'expected.yaml'); + }); + + it('bundles one endpoint with different versions', async () => { + await bundleFolder('different_endpoint_versions'); + await expectBundleToMatchFile('different_endpoint_versions', 'expected.yaml'); + }); + + it('bundles spec with different OpenAPI versions', async () => { + await bundleFolder('different_openapi_versions'); + await expectBundleToMatchFile('different_openapi_versions', 'expected.yaml'); + }); + + it('bundles conflicting but equal references', async () => { + await bundleFolder('conflicting_but_equal_refs_in_different_specs'); + await expectBundleToMatchFile('conflicting_but_equal_refs_in_different_specs', 'expected.yaml'); + }); + + it('fails to bundle conflicting references encountered in separate specs', async () => { + await expectBundlingError( + 'conflicting_refs_in_different_specs', + /\/components\/schemas\/ConflictTestSchema/ + ); + }); + + describe('x-modify', () => { + it('makes properties in an object node partial', async () => { + await bundleFolder('modify_partial_node'); + await expectBundleToMatchFile('modify_partial_node', 'expected.yaml'); + }); + + it('makes properties in a referenced object node partial', async () => { + await bundleFolder('modify_partial_ref'); + await expectBundleToMatchFile('modify_partial_ref', 'expected.yaml'); + }); + + it('makes properties in an object node required', async () => { + await bundleFolder('modify_required_node'); + await expectBundleToMatchFile('modify_required_node', 'expected.yaml'); + }); + + it('makes properties in a referenced object node required', async () => { + await bundleFolder('modify_required_ref'); + await expectBundleToMatchFile('modify_required_ref', 'expected.yaml'); + }); + }); + + describe('x-inline', () => { + it('inlines a reference', async () => { + await bundleFolder('inline_ref'); + await expectBundleToMatchFile('inline_ref', 'expected.yaml'); + }); + }); + + describe('skip internal', () => { + it('skips nodes with x-internal property', async () => { + await bundleFolder('skip_internal'); + await expectBundleToMatchFile('skip_internal', 'expected.yaml'); + }); + + it('skips endpoints starting with /internal', async () => { + await bundleFolder('skip_internal_endpoint'); + await expectBundleToMatchFile('skip_internal_endpoint', 'expected.yaml'); + }); + }); +}); + +async function bundleFolder(folderName: string): Promise { + await expect( + bundle({ + rootDir: join(rootPath, folderName), + sourceGlob: '*.schema.yaml', + outputFilePath: join('..', basename(targetAbsoluteFilePath)), + }) + ).resolves.toBeUndefined(); +} + +async function expectBundlingError( + folderName: string, + error: string | RegExp | jest.Constructable | Error | undefined +): Promise { + return await expect( + bundle({ + rootDir: join(rootPath, folderName), + sourceGlob: '*.schema.yaml', + outputFilePath: join('..', basename(targetAbsoluteFilePath)), + }) + ).rejects.toThrowError(error); +} + +async function expectBundleToMatchFile( + folderName: string, + expectedFileName: string +): Promise { + expect(existsSync(targetAbsoluteFilePath)).toBeTruthy(); + + const bundledSpec = await readYamlDocument(targetAbsoluteFilePath); + const expectedAbsoluteFilePath = join(rootPath, folderName, expectedFileName); + const expectedSpec = await readYamlDocument(expectedAbsoluteFilePath); + + expect(bundledSpec).toEqual(expectedSpec); +} + +function removeTargetFile(): void { + if (existsSync(targetAbsoluteFilePath)) { + rmSync(targetAbsoluteFilePath, { force: true }); + } +} diff --git a/packages/kbn-openapi-bundler/src/openapi_bundler.ts b/packages/kbn-openapi-bundler/src/openapi_bundler.ts new file mode 100644 index 000000000000..451b0ff700ba --- /dev/null +++ b/packages/kbn-openapi-bundler/src/openapi_bundler.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import chalk from 'chalk'; +import globby from 'globby'; +import { basename, dirname, join, resolve } from 'path'; +import { BundledDocument, bundleDocument, SkipException } from './bundler/bundle_document'; +import { mergeDocuments } from './bundler/merge_documents'; +import { removeFilesByGlob } from './utils/remove_files_by_glob'; +import { logger } from './logger'; +import { writeYamlDocument } from './utils/write_yaml_document'; + +export interface BundlerConfig { + rootDir: string; + sourceGlob: string; + outputFilePath: string; +} + +export const bundle = async (config: BundlerConfig) => { + const { + rootDir, + sourceGlob, + outputFilePath: relativeOutputFilePath = 'target/openapi/bundled.schema.yaml', + } = config; + + logger.debug(chalk.bold(`Bundling API route schemas`)); + logger.debug(chalk.bold(`Working directory: ${chalk.underline(rootDir)}`)); + logger.debug(`👀 Searching for source files`); + + const outputFilePath = join(rootDir, relativeOutputFilePath); + const sourceFilesGlob = resolve(rootDir, sourceGlob); + const schemaFilePaths = await globby([sourceFilesGlob]); + + logger.info(`🕵️‍♀️ Found ${schemaFilePaths.length} schemas`); + logSchemas(schemaFilePaths); + + logger.info(`🧹 Cleaning up any previously generated artifacts`); + await removeFilesByGlob(dirname(outputFilePath), basename(outputFilePath)); + + logger.debug(`Processing schemas...`); + + const resolvedDocuments = await Promise.all( + schemaFilePaths.map(async (schemaFilePath) => { + try { + const resolvedDocument = await bundleDocument(schemaFilePath); + + logger.debug(`Processed ${chalk.bold(basename(schemaFilePath))}`); + + return resolvedDocument; + } catch (e) { + if (e instanceof SkipException) { + logger.info(`Skipped ${chalk.bold(e.documentPath)}: ${e.message}`); + return; + } + + throw e; + } + }) + ); + + const processedDocuments = filterOutSkippedDocuments(resolvedDocuments); + + logger.success(`Processed ${processedDocuments.length} schemas`); + + const resultDocument = await mergeDocuments(processedDocuments); + + try { + await writeYamlDocument(outputFilePath, resultDocument); + + logger.success(`📖 Wrote all bundled OpenAPI specs to ${chalk.bold(outputFilePath)}`); + } catch (e) { + logger.error(`Unable to save bundled document to ${chalk.bold(outputFilePath)}: ${e.message}`); + } +}; + +function logSchemas(schemaFilePaths: string[]): void { + for (const filePath of schemaFilePaths) { + logger.debug(`Found OpenAPI spec ${chalk.bold(filePath)}`); + } +} + +function filterOutSkippedDocuments( + documents: Array +): BundledDocument[] { + const processedDocuments: BundledDocument[] = []; + + for (const document of documents) { + if (!document) { + continue; + } + + processedDocuments.push(document); + } + + return processedDocuments; +} diff --git a/packages/kbn-openapi-bundler/src/utils/extract_by_json_pointer.ts b/packages/kbn-openapi-bundler/src/utils/extract_by_json_pointer.ts new file mode 100644 index 000000000000..15507ac938ae --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/extract_by_json_pointer.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObjectType } from './is_plain_object_type'; + +/** + * Extract a node from a document using a provided [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901). + * + * JSON Pointer is the second part in [JSON Reference](https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03). + * For example an object `{ $ref: "./some-file.yaml#/components/schemas/MySchema"}` is a reference node. + * Where `/components/schemas/MySchema` is a JSON pointer. `./some-file.yaml` is a document reference. + * Yaml shares the same JSON reference standard and basically can be considered just as a different + * JS Object serialization format. See OpenAPI [Using $ref](https://swagger.io/docs/specification/using-ref/) for more information. + * + * @param document a document containing node to resolve by using the pointer + * @param pointer a JSON Pointer + * @returns resolved document node + */ +export function extractByJsonPointer(document: unknown, pointer: string): Record { + if (!pointer.startsWith('/')) { + throw new Error('$ref pointer must start with a leading slash'); + } + + if (!isPlainObjectType(document)) { + throw new Error('document must be an object'); + } + + let target = document; + + for (const segment of pointer.slice(1).split('/')) { + const nextTarget = target[segment]; + + if (!isPlainObjectType(nextTarget)) { + throw new Error(`JSON Pointer "${pointer}" is not found in "${JSON.stringify(document)}"`); + } + + target = nextTarget; + } + + return target; +} diff --git a/packages/kbn-openapi-bundler/src/utils/has_prop.ts b/packages/kbn-openapi-bundler/src/utils/has_prop.ts new file mode 100644 index 000000000000..aa38041b8178 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/has_prop.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObjectType } from './is_plain_object_type'; + +export function hasProp( + node: unknown, + propName: Property, + propValue?: Value +): node is { [key in Property]: Value } & Record { + if (!isPlainObjectType(node) || !(propName in node)) { + return false; + } + + return propValue ? node[propName] === propValue : Boolean(node[propName]); +} diff --git a/packages/kbn-openapi-bundler/src/utils/insert_by_json_pointer.ts b/packages/kbn-openapi-bundler/src/utils/insert_by_json_pointer.ts new file mode 100644 index 000000000000..8538102305ed --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/insert_by_json_pointer.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** + * Inserts `data` into the location specified by pointer in the `document`. + * + * @param pointer [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) + * @param data An object to insert + * @param document A document to insert to + */ +export function insertRefByPointer( + pointer: string, + data: unknown, + document: Record +): void { + const segments = pointer.split('/').slice(2); + let target = document; + + while (segments.length > 0) { + const segment = segments.shift() as string; + + if (!target[segment]) { + target[segment] = {}; + } + + target = target[segment] as Record; + } + + Object.assign(target, data); +} diff --git a/packages/kbn-openapi-bundler/src/utils/is_plain_object_type.ts b/packages/kbn-openapi-bundler/src/utils/is_plain_object_type.ts new file mode 100644 index 000000000000..5807bae63f28 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/is_plain_object_type.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObject } from 'lodash'; + +export function isPlainObjectType(maybeObj: unknown): maybeObj is Record { + return isPlainObject(maybeObj); +} diff --git a/packages/kbn-openapi-bundler/src/utils/parse_ref.ts b/packages/kbn-openapi-bundler/src/utils/parse_ref.ts new file mode 100644 index 000000000000..fd23bf0d9277 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/parse_ref.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface ParsedRef { + path: string; + pointer: string; +} + +/** + * Parses [JSON Reference](https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03) + * + * @param ref JSON Reference + * @returns file path and JSON pointer + */ +export function parseRef(ref: string): ParsedRef { + const [filePath, pointer] = ref.split('#'); + + if (!pointer) { + throw new Error(`Unable to parse $ref "${ref}"`); + } + + return { + path: filePath, + pointer, + }; +} diff --git a/packages/kbn-openapi-bundler/src/utils/read_yaml_document.ts b/packages/kbn-openapi-bundler/src/utils/read_yaml_document.ts new file mode 100644 index 000000000000..c8cbae710c1b --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/read_yaml_document.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { load } from 'js-yaml'; + +export async function readYamlDocument(filePath: string): Promise> { + // Typing load's result to Record is optimistic as we can't be sure + // there is object inside a yaml file. We don't have this validation layer so far + // but using JSON Schemas here should mitigate this problem. + return load(await fs.readFile(filePath, { encoding: 'utf8' })); +} diff --git a/packages/kbn-openapi-bundler/src/utils/remove_files_by_glob.ts b/packages/kbn-openapi-bundler/src/utils/remove_files_by_glob.ts new file mode 100644 index 000000000000..db8ed245914a --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/remove_files_by_glob.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import globby from 'globby'; +import { resolve } from 'path'; + +/** + * Removes any files matching glob pattern from the target directory + * + * @param path target directory + * @param globPattern files pattern to remove + */ +export async function removeFilesByGlob(path: string, globPattern: string): Promise { + const filesToRemove = await globby([resolve(path, globPattern)]); + + await Promise.all(filesToRemove.map((fileName) => fs.unlink(fileName))); +} diff --git a/packages/kbn-openapi-bundler/src/utils/to_absolute_path.ts b/packages/kbn-openapi-bundler/src/utils/to_absolute_path.ts new file mode 100644 index 000000000000..db63feae1295 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/to_absolute_path.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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { join, isAbsolute } from 'path'; + +/** + * Transforms a path to absolute path. If an absolute path passed to the function it's returned without + * changes. Base path is current working directory by default. + * + * @param maybeAbsolutePath a path to be transformed into absolute path + * @param baseDirPath a path from root to the folder maybeAbsolutePath is relative to + * @returns absolute path + */ +export function toAbsolutePath(maybeAbsolutePath: string, baseDirPath: string): string { + if (isAbsolute(maybeAbsolutePath)) { + return maybeAbsolutePath; + } + + return join(baseDirPath, maybeAbsolutePath); +} diff --git a/packages/kbn-openapi-bundler/src/utils/write_yaml_document.ts b/packages/kbn-openapi-bundler/src/utils/write_yaml_document.ts new file mode 100644 index 000000000000..bdcd783e1a21 --- /dev/null +++ b/packages/kbn-openapi-bundler/src/utils/write_yaml_document.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs/promises'; +import { dump } from 'js-yaml'; +import { dirname } from 'path'; + +export async function writeYamlDocument(filePath: string, document: unknown): Promise { + try { + const yaml = dump(document, { noRefs: true }); + + await fs.mkdir(dirname(filePath), { recursive: true }); + await fs.writeFile(filePath, yaml); + } catch (e) { + throw new Error(`Unable to write bundled yaml: ${e.message}`, { cause: e }); + } +} diff --git a/packages/kbn-openapi-bundler/tsconfig.json b/packages/kbn-openapi-bundler/tsconfig.json new file mode 100644 index 000000000000..79d0eba0851b --- /dev/null +++ b/packages/kbn-openapi-bundler/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": ["@kbn/tooling-log"] +} diff --git a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts index 72c6b50d1266..3b4b5fa9202f 100644 --- a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts +++ b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts @@ -47,4 +47,7 @@ export function registerHelpers(handlebarsInstance: typeof Handlebars) { handlebarsInstance.registerHelper('isUnknown', (val: object) => { return !('type' in val || '$ref' in val || 'anyOf' in val || 'oneOf' in val || 'allOf' in val); }); + handlebarsInstance.registerHelper('startsWithSpecialChar', (val: string) => { + return /^[^a-zA-Z0-9]/.test(val); + }); } diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars index 9a5312cf88f5..29d4453da4d7 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars @@ -12,7 +12,6 @@ {{~#if (defined default)}}.default({{{toJSON default}}}){{/if~}} {{~#if (eq x-modify "partial")}}.partial(){{/if~}} {{~#if (eq x-modify "required")}}.required(){{/if~}} - {{~#if (eq x-modify "requiredOptional")}}.transform(requiredOptional){{/if~}} {{~/if~}} {{~#if allOf~}} @@ -20,26 +19,34 @@ {{~#if @first~}} {{> zod_schema_item }} {{~else~}} - .and({{> zod_schema_item }}) + .merge({{> zod_schema_item }}) {{~/if~}} {{~/each~}} {{~/if~}} {{~#if anyOf~}} - z.union([ - {{~#each anyOf~}} + {{#if discriminator}} + z.discriminatedUnion('{{discriminator.propertyName}}', [ + {{else}} + z.union([ + {{/if}} + {{~#each anyOf~}} {{~> zod_schema_item ~}}, - {{~/each~}} + {{~/each~}} ]) {{~#if nullable}}.nullable(){{/if~}} {{~#if (eq requiredBool false)}}.optional(){{/if~}} {{~/if~}} {{~#if oneOf~}} - z.union([ - {{~#each oneOf~}} + {{#if discriminator}} + z.discriminatedUnion('{{discriminator.propertyName}}', [ + {{else}} + z.union([ + {{/if}} + {{~#each oneOf~}} {{~> zod_schema_item ~}}, - {{~/each~}} + {{~/each~}} ]) {{~#if nullable}}.nullable(){{/if~}} {{~#if (eq requiredBool false)}}.optional(){{/if~}} @@ -80,7 +87,11 @@ z.unknown() * {{{description}}} */ {{/if}} - {{@key}}: {{> zod_schema_item requiredBool=(includes ../required @key)}}, + {{#if (startsWithSpecialChar @key)}} + '{{@key}}': {{> zod_schema_item requiredBool=(includes ../required @key)}}, + {{else}} + {{@key}}: {{> zod_schema_item requiredBool=(includes ../required @key)}}, + {{/if}} {{/each}} }) {{~#if (eq additionalProperties false)}}.strict(){{/if~}} @@ -93,7 +104,6 @@ z.unknown() {{~/if~}} {{~#if (eq x-modify "partial")}}.partial(){{/if~}} {{~#if (eq x-modify "required")}}.required(){{/if~}} - {{~#if (eq x-modify "requiredOptional")}}.transform(requiredOptional){{/if~}} {{~/inline~}} {{~#*inline "type_string"~}} diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index e79e6b4fa8be..976b423fc50f 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -63,7 +63,7 @@ pageLoadAssetSize: files: 22673 filesManagement: 18683 fileUpload: 25664 - fleet: 158438 + fleet: 174609 globalSearch: 29696 globalSearchBar: 50403 globalSearchProviders: 25554 @@ -95,7 +95,7 @@ pageLoadAssetSize: management: 46112 maps: 90000 mapsEms: 26072 - metricsDataAccess: 60000 + metricsDataAccess: 73287 ml: 82187 monitoring: 80000 navigation: 37269 diff --git a/packages/kbn-panel-loader/README.md b/packages/kbn-panel-loader/README.md new file mode 100644 index 000000000000..5b14fa96c6c4 --- /dev/null +++ b/packages/kbn-panel-loader/README.md @@ -0,0 +1,3 @@ +# @kbn/panel-loader + +Contains a generic loader which should be used to indicate that a chart is loading diff --git a/packages/kbn-panel-loader/index.tsx b/packages/kbn-panel-loader/index.tsx new file mode 100644 index 000000000000..ad4e8751910f --- /dev/null +++ b/packages/kbn-panel-loader/index.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiLoadingChart, EuiPanel } from '@elastic/eui'; + +export const PanelLoader = (props: { showShadow?: boolean; dataTestSubj?: string }) => { + return ( + + + + ); +}; diff --git a/packages/kbn-panel-loader/jest.config.js b/packages/kbn-panel-loader/jest.config.js new file mode 100644 index 000000000000..e8cfab95a073 --- /dev/null +++ b/packages/kbn-panel-loader/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-panel-loader'], +}; diff --git a/packages/kbn-panel-loader/kibana.jsonc b/packages/kbn-panel-loader/kibana.jsonc new file mode 100644 index 000000000000..5fc518a8983c --- /dev/null +++ b/packages/kbn-panel-loader/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/panel-loader", + "owner": "@elastic/kibana-presentation" +} diff --git a/packages/kbn-panel-loader/package.json b/packages/kbn-panel-loader/package.json new file mode 100644 index 000000000000..94394420475b --- /dev/null +++ b/packages/kbn-panel-loader/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/panel-loader", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-panel-loader/tsconfig.json b/packages/kbn-panel-loader/tsconfig.json new file mode 100644 index 000000000000..f885e788791b --- /dev/null +++ b/packages/kbn-panel-loader/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/packages/kbn-profiling-utils/common/__fixtures__/README.md b/packages/kbn-profiling-utils/common/__fixtures__/README.md deleted file mode 100644 index 1a26bca59066..000000000000 --- a/packages/kbn-profiling-utils/common/__fixtures__/README.md +++ /dev/null @@ -1,17 +0,0 @@ -The stacktrace fixtures in this directory are originally from Elasticsearch's -`POST /_profiling/stacktraces` endpoint. They were subsequently filtered -through the `shrink_stacktrace_response.js` command in `x-pack/plugins/profiling/scripts/` -to reduce the size without losing sampling fidelity (see the script for further -details). - -The naming convention for each stacktrace fixture follows this pattern: - -``` -stacktraces_{seconds}s_{upsampling rate}x.json -``` - -where `seconds` is the time span of the original query and `upsampling rate` is -the reciprocal of the sampling rate returned from the original query. - -To add a new stacktrace fixture to the test suite, update `stacktraces.ts` -appropriately. \ No newline at end of file diff --git a/packages/kbn-profiling-utils/common/__fixtures__/base_flamegraph.ts b/packages/kbn-profiling-utils/common/__fixtures__/base_flamegraph.ts new file mode 100644 index 000000000000..ce4aa885d354 --- /dev/null +++ b/packages/kbn-profiling-utils/common/__fixtures__/base_flamegraph.ts @@ -0,0 +1,298 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { BaseFlameGraph } from '../flamegraph'; + +export const baseFlamegraph: BaseFlameGraph = { + Edges: [ + [1], + [2], + [3], + [4], + [5], + [6], + [7], + [8], + [9], + [10], + [11], + [12], + [13], + [14], + [15], + [16], + [17], + [18], + [19], + [20], + [21], + [22], + [23], + [24], + [25], + [26], + [27], + [28], + [29], + [30], + [31], + [32], + [33], + [34], + [], + ], + FileID: [ + '', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + ], + FrameType: [ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, + ], + Inline: [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + ], + ExeFilename: [ + '', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + ], + AddressOrLine: [ + 0, 43443520, 67880745, 67881145, 53704110, 53704665, 53696841, 53697537, 53700683, 53696841, + 52492674, 67626923, 67629380, 67630226, 51515812, 51512445, 51522994, 44606453, 43747101, + 43699300, 43538916, 43547623, 42994898, 42994925, 14680216, 14356875, 3732840, 3732678, 3721714, + 3719260, 3936007, 3897721, 4081162, 4458225, 1712873, + ], + FunctionName: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'entry_SYSCALL_64_after_hwframe', + 'do_syscall_64', + '__x64_sys_read', + 'ksys_read', + 'vfs_read', + 'new_sync_read', + 'seq_read_iter', + 'm_show', + 'show_mountinfo', + 'kernfs_sop_show_path', + 'cgroup_show_path', + ], + FunctionOffset: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + SourceFilename: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + SourceLine: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + CountInclusive: [ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, + ], + CountExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, + ], + AnnualCO2TonsInclusive: [ + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + ], + AnnualCO2TonsExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0.0013627551116480942, + ], + AnnualCostsUSDInclusive: [ + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + ], + AnnualCostsUSDExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 61.30240940376492, + ], + Size: 35, + SamplingRate: 1, + SelfCPU: 7, + SelfAnnualCO2Tons: 0.0013627551116480942, + TotalAnnualCO2Tons: 0.04769642890768329, + SelfAnnualCostsUSD: 61.30240940376492, + TotalAnnualCostsUSD: 2145.5843291317715, + TotalCPU: 245, + TotalSamples: 7, + TotalSeconds: 4.980000019073486, +}; diff --git a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces.ts b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces.ts index 105132ec1594..90f97e87d8bf 100644 --- a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces.ts +++ b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces.ts @@ -8,18 +8,166 @@ import { StackTraceResponse } from '../stack_traces'; -import stackTraces1x from './stacktraces_60s_1x.json'; -import stackTraces5x from './stacktraces_3600s_5x.json'; -import stackTraces125x from './stacktraces_86400s_125x.json'; -import stackTraces625x from './stacktraces_604800s_625x.json'; - -export const stackTraceFixtures: Array<{ - response: StackTraceResponse; - seconds: number; - upsampledBy: number; -}> = [ - { response: stackTraces1x, seconds: 60, upsampledBy: 1 }, - { response: stackTraces5x, seconds: 3600, upsampledBy: 5 }, - { response: stackTraces125x, seconds: 86400, upsampledBy: 125 }, - { response: stackTraces625x, seconds: 604800, upsampledBy: 625 }, -]; +export const stacktraces: StackTraceResponse = { + stack_traces: { + ['c2TovSbgCECd_RtKHxMtyQ']: { + address_or_lines: [ + 43443520, 67880745, 67881145, 53704110, 53704665, 53696841, 53697537, 53700683, 53696841, + 52492674, 67626923, 67629380, 67630226, 51515812, 51512445, 51522994, 44606453, 43747101, + 43699300, 43538916, 43547623, 42994898, 42994925, 14680216, 14356875, 3732840, 3732678, + 3721714, 3719260, 3936007, 3897721, 4081162, 4458225, 1712873, + ], + file_ids: [ + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + ], + frame_ids: [ + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACluVA', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAAEC8cp', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAAEC8i5', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM3Wu', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM3fZ', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM1lJ', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM1wB', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM2hL', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADM1lJ', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADIPmC', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAAEB-er', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAAEB_FE', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAAEB_SS', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADEhGk', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADEgR9', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAADEi2y', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACqKP1', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACm4cd', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACmsxk', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACmFnk', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACmHvn', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACkAzS', + 'fwIcP8qXDOl7k0VhWU8z9QAAAAACkAzt', + '5JfXt00O17Yra2Rwh8HT8QAAAAAA4ACY', + '5JfXt00O17Yra2Rwh8HT8QAAAAAA2xGL', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOPVo', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOPTG', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOMny', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOMBc', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAPA8H', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAO3l5', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAPkYK', + '5JfXt00O17Yra2Rwh8HT8QAAAAAARAbx', + '5JfXt00O17Yra2Rwh8HT8QAAAAAAGiLp', + ], + type_ids: [ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, + ], + annual_co2_tons: 0.0013627551116480942, + annual_costs_usd: 61.30240940376492, + count: 7, + }, + }, + stack_frames: { + '5JfXt00O17Yra2Rwh8HT8QAAAAAAO3l5': { + file_name: [], + function_name: ['m_show'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAA4ACY': { + file_name: [], + function_name: ['entry_SYSCALL_64_after_hwframe'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAARAbx': { + file_name: [], + function_name: ['kernfs_sop_show_path'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOMBc': { + file_name: [], + function_name: ['new_sync_read'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAPA8H': { + file_name: [], + function_name: ['seq_read_iter'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOPVo': { + file_name: [], + function_name: ['__x64_sys_read'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAPkYK': { + file_name: [], + function_name: ['show_mountinfo'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAGiLp': { + file_name: [], + function_name: ['cgroup_show_path'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOMny': { + file_name: [], + function_name: ['vfs_read'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAAOPTG': { + file_name: [], + function_name: ['ksys_read'], + function_offset: [], + line_number: [], + }, + '5JfXt00O17Yra2Rwh8HT8QAAAAAA2xGL': { + file_name: [], + function_name: ['do_syscall_64'], + function_offset: [], + line_number: [], + }, + }, + executables: { '5JfXt00O17Yra2Rwh8HT8Q': 'vmlinux', fwIcP8qXDOl7k0VhWU8z9Q: 'metricbeat' }, + stack_trace_events: { ['c2TovSbgCECd_RtKHxMtyQ']: 7 }, + total_frames: 34, + sampling_rate: 1, +}; diff --git a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_3600s_5x.json b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_3600s_5x.json deleted file mode 100644 index cad5ac24c7a7..000000000000 --- a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_3600s_5x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"-njmbjRUBOZR5EgXpUQdRw":42,"ztDY3GPoIfO7CjHQxmyZ-Q":115,"Y8CwPu4zFwOz0m86XYzkGw":256,"QiwsJA6NJ0Q3f2M4DT-dxA":1192,"9_06LL00QkYIeiFNCWu0XQ":1033,"GApi1ybrprUZdnGMiSfUPA":675,"QpRRwD9tRNNrUmJ_2oOuSg":385,"43tbk4XHS6h_eSSkozr2lQ":480,"nORl1I4BGh3mzZiFR21ijQ":342,"ONNtRKFUjSc8lLm64B4nVQ":604,"IgUYn71JvS5hV0IssAqJCA":415,"u31aX9a6CI2OuomWQHSx1Q":486,"ZBYtP3yTV5OAbePvOl3arg":500,"ztbi9NfSFBK5AxpIlylSew":478,"-s21TvA-EsTWbfCutQG83Q":402,"APcbPjShNMH1PkL1e22JYg":381,"sGdKDAzt2D3ZK2brqGj4vQ":551,"hecRkAhRG62NML7wI512zA":225,"yqosCJmye4YNNxuB2s8zdQ":181,"JEl8c8qrwRMDRhl_VlTpFQ":234,"TFvQpP8OVc3AdHSKmIUBAA":218,"eUMH9Wf36CVzdkAZsN9itA":242,"57NvBalQc9mIcBwC1lPObg":229,"qaTBBEzEjIyGmsWUYfCBpA":189,"y7Mdo_ee9-4XsWhpA4MB0g":271,"vODIlh-kDOyM2hWSJhdfpA":235,"QKuCwkwTUdmVpouD1TSb6g":167,"zQ3yVnMIXoz1yUFx6SaSlA":146,"PfGJvpI_t-0Eiwgl8k31BA":148,"P-lVr6eiwDBuO8eZBdsdMQ":144,"KxQngfXsErVAsVuASxix6w":138,"NDxOvbKIocbTk6FkHrLlqQ":107,"2GP6bCEH-XkrLdH6ox0E3Q":95,"NYEjWS7muJ8dsj9z5lNehg":52,"Nr5XZDDmb-nXg0BzTFzdFA":44,"JVvUxIunvr6V68Rt99rK9w":38,"tagsGmBta7BnDHBzEbH9eQ":28,"CjP83pplY09FGl9PBMeqCg":13,"SQ6jhz-Ee7WHXLMOHOsDcQ":18,"eM1ATYEKUIN4nyPylmr13A":20,"9vNu8RjYClbqhYYGUiWI7A":12,"CU-T9AvnxmWd1TTRjgV01Q":17,"hoJT-ObO7MDFTgt9UeFJfg":9,"us5XzJaFA8Y8a8Jhq7VWzQ":34,"tWPDa1sBMePW-YFiahrHBA":9,"KKjaO47Ew4fmVCY-lBFkLg":6,"zxyQebekMWvnWWEuWSzR9Q":8,"UI-7Z494NKAWuv1FuNlxoQ":4,"6yHX0lcyWmly8MshBzd78Q":7,"uEL43HtanLRCO2rLB4ttzQ":3,"mXgK2ekWZ4qH-uHB8QaLtA":7,"1twYzjHR6hCfJqQLvJ81XA":5,"f-LRF9Sfj675yc68DOXczw":2,"p24lyWOwFjGMsQaWybQUMA":1,"KHat1RLkyP8wPwwR1uD04A":4,"B-OQjwP7KzSb4f6cXUL1bA":2,"kOWftL0Ttias8Z1isZi9oA":4,"JzGylmBPluUmIML9XnagKw":3,"tTw0tfSnPtZhbcyzyVHHpg":2,"E_F-N51BcZ4iQ9oPaHFKXw":2,"d04G8ZHV3kYQ0ekQBw1VYQ":3,"I-DofAMUQgh7q14tBJcZlA":3,"tGGi0acvAmmxOR5DbuF3dg":4,"Ws9TqFMz-kHv_-7zrBFdKw":3,"nBHRVpYV5wUL_UAb5ff6Zg":1,"vfw5EN0FEHQCAj0w-N2avQ":1,"lyeLQDjWsQDYEJbcY4aFJA":3,"cqzgaW0F-6gZ8uHz_Pf3hQ":1,"b89Eo7vMfG4HsPSBVvjiKQ":5,"5_-zAnLDYAi4FySmVgS6iw":2,"zOI_cRK31hVrh4Typ0-Fxg":5,"4U9ayDnwvWmqJPhn_AOKew":8,"Jt6CexOHLEwUl4IeTgASBQ":4,"8Rif7kuKG2cfhEYF2fJXmA":4,"cCjn5miDmyezrnBAe2jDww":12,"f8AFYpSQOpjCNbhqUuR3Rg":9,"dGMvgpGXk-ajX6PRi92qdg":9,"OxrG9ZVAzX9GwGtxUtIQNg":3,"QoW8uF5K3OBNL2DXI66leA":9,"zV-93oQDbZK9zB7UMAcCmw":5,"9CQVJEfCfL1rSnUaxlAfqg":3,"mGGvLNOYB74ofk9FRrMxxQ":2,"pnLCuJVNeqGwwFeJQIrkPw":2,"R77Zz6fBvENVXyt4GVb9dQ":1,"tgL-t2GJJjItpLjnwjc4zQ":1,"XNCSlgkv_bOXDIYn6zwekw":5,"jPN_jNGPJguImYjakYlBcA":1,"4K-SlZ4j8NjsVBpqyPj2dw":1,"W8IRlEZMfFJdYSgUQXDnMg":2,"qytuJG9brvKSB9NJCHV9fQ":1,"b116myovN7_XXb1AVLPH0g":1,"dNwgDmnCM1dIIF5EZm4ZgA":1,"KEdXtWOmrUdpIHsjndtg_A":1,"V2K_ZjA6rol7KyINtV45_A":1},"stack_traces":{"-njmbjRUBOZR5EgXpUQdRw":{"address_or_lines":[1277056],"file_ids":["G68hjsyagwq6LpWrMjDdng"],"frame_ids":["G68hjsyagwq6LpWrMjDdngAAAAAAE3yA"],"type_ids":[3]},"ztDY3GPoIfO7CjHQxmyZ-Q":{"address_or_lines":[4643458,4456960],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtqC","B8JRxL079xbhqQBqGvksAgAAAAAARAIA"],"type_ids":[3,3]},"Y8CwPu4zFwOz0m86XYzkGw":{"address_or_lines":[4597989,4390116,4390542],"file_ids":["6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w"],"frame_ids":["6kzBY4yj-1Fh1NCTZA3z0wAAAAAARijl","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQvzk","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQv6O"],"type_ids":[3,3,3]},"QiwsJA6NJ0Q3f2M4DT-dxA":{"address_or_lines":[4597989,4307812,4320019,4321918],"file_ids":["6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w"],"frame_ids":["6kzBY4yj-1Fh1NCTZA3z0wAAAAAARijl","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQbtk","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQesT","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQfJ-"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"GApi1ybrprUZdnGMiSfUPA":{"address_or_lines":[18434496,18109958,18105083,18107109,18183090,18183229],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABFFYG","j8DVIOTu7Btj9lgFefJ84AAAAAABFEL7","j8DVIOTu7Btj9lgFefJ84AAAAAABFErl","j8DVIOTu7Btj9lgFefJ84AAAAAABFXOy","j8DVIOTu7Btj9lgFefJ84AAAAAABFXQ9"],"type_ids":[3,3,3,3,3,3]},"QpRRwD9tRNNrUmJ_2oOuSg":{"address_or_lines":[4644672,40444780,40465086,40468873,40476239,4250662,4249714],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARt9A","B56YkhsK1JwqD-8F8sjS3AAAAAACaSNs","B56YkhsK1JwqD-8F8sjS3AAAAAACaXK-","B56YkhsK1JwqD-8F8sjS3AAAAAACaYGJ","B56YkhsK1JwqD-8F8sjS3AAAAAACaZ5P","B56YkhsK1JwqD-8F8sjS3AAAAAAAQNwm","B56YkhsK1JwqD-8F8sjS3AAAAAAAQNhy"],"type_ids":[3,3,3,3,3,3,3]},"43tbk4XHS6h_eSSkozr2lQ":{"address_or_lines":[18515232,22597677,22574090,22556393,22530363,22106663,22101077,22107662],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHQK","v6HIzNa4K6G4nRP9032RIAAAAAABWC7p","v6HIzNa4K6G4nRP9032RIAAAAAABV8k7","v6HIzNa4K6G4nRP9032RIAAAAAABUVIn","v6HIzNa4K6G4nRP9032RIAAAAAABUTxV","v6HIzNa4K6G4nRP9032RIAAAAAABUVYO"],"type_ids":[3,3,3,3,3,3,3,3]},"nORl1I4BGh3mzZiFR21ijQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271908,4256166,4255110,4288975,4287865],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qfk","FWZ9q3TQKZZok58ua1HDsgAAAAAAQPGm","FWZ9q3TQKZZok58ua1HDsgAAAAAAQO2G","FWZ9q3TQKZZok58ua1HDsgAAAAAAQXHP","FWZ9q3TQKZZok58ua1HDsgAAAAAAQW15"],"type_ids":[3,3,3,3,3,3,3,3,3]},"ONNtRKFUjSc8lLm64B4nVQ":{"address_or_lines":[4641312,7081613,7060969,4425906,7064267,7057968,6093476,6025643,4305623,4278829],"file_ids":["gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w"],"frame_ids":["gNW12BepH17pXwK-ZuYt3wAAAAAARtIg","gNW12BepH17pXwK-ZuYt3wAAAAAAbA6N","gNW12BepH17pXwK-ZuYt3wAAAAAAa73p","gNW12BepH17pXwK-ZuYt3wAAAAAAQ4iy","gNW12BepH17pXwK-ZuYt3wAAAAAAa8rL","gNW12BepH17pXwK-ZuYt3wAAAAAAa7Iw","gNW12BepH17pXwK-ZuYt3wAAAAAAXPqk","gNW12BepH17pXwK-ZuYt3wAAAAAAW_Gr","gNW12BepH17pXwK-ZuYt3wAAAAAAQbLX","gNW12BepH17pXwK-ZuYt3wAAAAAAQUot"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"IgUYn71JvS5hV0IssAqJCA":{"address_or_lines":[4636100,4452920,4453106,4487396,4487396,4651100,10485923,16743,1136873,1113241,4849252],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARr3E","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ_I4","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ_Ly","B56YkhsK1JwqD-8F8sjS3AAAAAAARHjk","B56YkhsK1JwqD-8F8sjS3AAAAAAARHjk","B56YkhsK1JwqD-8F8sjS3AAAAAAARvhc","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEVjp","piWSMQrh4r040D0BPNaJvwAAAAAAEPyZ","piWSMQrh4r040D0BPNaJvwAAAAAASf5k"],"type_ids":[3,3,3,3,3,3,4,4,4,4,4]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"ZBYtP3yTV5OAbePvOl3arg":{"address_or_lines":[4636226,4469356,4468068,4466980,4460377,4459271,4243432,4415957,4652642,10485923,16743,1221731,1219038],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARr5C","B56YkhsK1JwqD-8F8sjS3AAAAAAARDJs","B56YkhsK1JwqD-8F8sjS3AAAAAAARC1k","B56YkhsK1JwqD-8F8sjS3AAAAAAARCkk","B56YkhsK1JwqD-8F8sjS3AAAAAAARA9Z","B56YkhsK1JwqD-8F8sjS3AAAAAAARAsH","B56YkhsK1JwqD-8F8sjS3AAAAAAAQL_o","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ2HV","B56YkhsK1JwqD-8F8sjS3AAAAAAARv5i","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEpne"],"type_ids":[3,3,3,3,3,3,3,3,3,4,4,4,4]},"ztbi9NfSFBK5AxpIlylSew":{"address_or_lines":[4594466,4444524,4443160,4438546,4391572,4609107,10485923,16807,2756288,2755416,2744627,2792698,4867725,4855327],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARhsi","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ9Fs","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ8wY","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ7oS","kajOqZqz7V1y0BdYQLFQrwAAAAAAQwKU","kajOqZqz7V1y0BdYQLFQrwAAAAAARlRT","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAKpz6","A2oiHVwisByxRn5RDT4LjAAAAAAASkaN","A2oiHVwisByxRn5RDT4LjAAAAAAAShYf"],"type_ids":[3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"APcbPjShNMH1PkL1e22JYg":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54546893,54560984,44458726,43610833,43327941,43735894],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFHN","MNBJ5seVz_ocW6tcr1HSmwAAAAADQIjY","MNBJ5seVz_ocW6tcr1HSmwAAAAACpmLm","MNBJ5seVz_ocW6tcr1HSmwAAAAACmXLR","MNBJ5seVz_ocW6tcr1HSmwAAAAAClSHF","MNBJ5seVz_ocW6tcr1HSmwAAAAACm1tW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"sGdKDAzt2D3ZK2brqGj4vQ":{"address_or_lines":[4652224,22354871,22382638,22364302,56672751,58471189,58268669,58227812,58241853,31197476,7372151,7373114,7373997,4536145,4264900,4265340,4655641],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYMHv","-pk6w5puGcp-wKnQ61BZzQAAAAADfDMV","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH13","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIE6","-pk6w5puGcp-wKnQ61BZzQAAAAAAcISt","-pk6w5puGcp-wKnQ61BZzQAAAAAARTdR","-pk6w5puGcp-wKnQ61BZzQAAAAAAQRPE","-pk6w5puGcp-wKnQ61BZzQAAAAAAQRV8","-pk6w5puGcp-wKnQ61BZzQAAAAAARwoZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"yqosCJmye4YNNxuB2s8zdQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961653,27949894,18928855],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqk1","v6HIzNa4K6G4nRP9032RIAAAAAABqntG","v6HIzNa4K6G4nRP9032RIAAAAAABINTX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"JEl8c8qrwRMDRhl_VlTpFQ":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59181690,58121321,58026161,58173220,58175116,7294148,7295421,7297245,7300762,7297188,7304836,7297413,7309604,7298328,5114154],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwp6","B8JRxL079xbhqQBqGvksAgAAAAADdtxp","B8JRxL079xbhqQBqGvksAgAAAAADdWix","B8JRxL079xbhqQBqGvksAgAAAAADd6ck","B8JRxL079xbhqQBqGvksAgAAAAADd66M","B8JRxL079xbhqQBqGvksAgAAAAAAb0zE","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1mF","B8JRxL079xbhqQBqGvksAgAAAAAAb4kk","B8JRxL079xbhqQBqGvksAgAAAAAAb10Y","B8JRxL079xbhqQBqGvksAgAAAAAATgkq"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"TFvQpP8OVc3AdHSKmIUBAA":{"address_or_lines":[4652224,22357367,22385134,22366798,57092143,58893857,58677085,58641545,58657509,31313785,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7306724,5132868,4625639,4289536],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZygv","B8JRxL079xbhqQBqGvksAgAAAAADgqYh","B8JRxL079xbhqQBqGvksAgAAAAADf1dd","B8JRxL079xbhqQBqGvksAgAAAAADfsyJ","B8JRxL079xbhqQBqGvksAgAAAAADfwrl","B8JRxL079xbhqQBqGvksAgAAAAAB3c95","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb33k","B8JRxL079xbhqQBqGvksAgAAAAAATlJE","B8JRxL079xbhqQBqGvksAgAAAAAARpTn","B8JRxL079xbhqQBqGvksAgAAAAAAQXQA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"eUMH9Wf36CVzdkAZsN9itA":{"address_or_lines":[32443680,43151402,43152149,43153397,41329281,41441892,41443480,41222389,41225442,41240900,40679166,40714972,40707458,40707880,40710748,40690621,40679204,40688196,40679204,40688166,40644014,41210644],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7w0g","QvG8QEGAld88D676NL_Y2QAAAAACknAq","QvG8QEGAld88D676NL_Y2QAAAAACknMV","QvG8QEGAld88D676NL_Y2QAAAAACknf1","QvG8QEGAld88D676NL_Y2QAAAAACdqKB","QvG8QEGAld88D676NL_Y2QAAAAACeFpk","QvG8QEGAld88D676NL_Y2QAAAAACeGCY","QvG8QEGAld88D676NL_Y2QAAAAACdQD1","QvG8QEGAld88D676NL_Y2QAAAAACdQzi","QvG8QEGAld88D676NL_Y2QAAAAACdUlE","QvG8QEGAld88D676NL_Y2QAAAAACbLb-","QvG8QEGAld88D676NL_Y2QAAAAACbULc","QvG8QEGAld88D676NL_Y2QAAAAACbSWC","QvG8QEGAld88D676NL_Y2QAAAAACbSco","QvG8QEGAld88D676NL_Y2QAAAAACbTJc","QvG8QEGAld88D676NL_Y2QAAAAACbOO9","QvG8QEGAld88D676NL_Y2QAAAAACbLck","QvG8QEGAld88D676NL_Y2QAAAAACbNpE","QvG8QEGAld88D676NL_Y2QAAAAACbLck","QvG8QEGAld88D676NL_Y2QAAAAACbNom","QvG8QEGAld88D676NL_Y2QAAAAACbC2u","QvG8QEGAld88D676NL_Y2QAAAAACdNMU"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"57NvBalQc9mIcBwC1lPObg":{"address_or_lines":[4652224,31040261,31054565,31056612,31058888,31450411,30791748,25539462,25519688,25480413,25483943,25484196,4951332,4960527,4959954,4897957,4893996,4627954,4660663,10485923,16807,3103640,3100879],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAAB2aMF","B8JRxL079xbhqQBqGvksAgAAAAAB2drl","B8JRxL079xbhqQBqGvksAgAAAAAB2eLk","B8JRxL079xbhqQBqGvksAgAAAAAB2evI","B8JRxL079xbhqQBqGvksAgAAAAAB3-Ur","B8JRxL079xbhqQBqGvksAgAAAAAB1dhE","B8JRxL079xbhqQBqGvksAgAAAAABhbOG","B8JRxL079xbhqQBqGvksAgAAAAABhWZI","B8JRxL079xbhqQBqGvksAgAAAAABhMzd","B8JRxL079xbhqQBqGvksAgAAAAABhNqn","B8JRxL079xbhqQBqGvksAgAAAAABhNuk","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7EP","B8JRxL079xbhqQBqGvksAgAAAAAAS67S","B8JRxL079xbhqQBqGvksAgAAAAAASryl","B8JRxL079xbhqQBqGvksAgAAAAAASq0s","B8JRxL079xbhqQBqGvksAgAAAAAARp3y","B8JRxL079xbhqQBqGvksAgAAAAAARx23","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAL1uY","A2oiHVwisByxRn5RDT4LjAAAAAAAL1DP"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"qaTBBEzEjIyGmsWUYfCBpA":{"address_or_lines":[4652224,31040261,31054565,31056612,31058888,31450411,30791748,25539462,25520823,25502704,25503492,25480821,25481061,4953508,4960780,4898318,4893650,4898160,4745321,4757831,4219698,4219725,10485923,16755],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAAB2aMF","B8JRxL079xbhqQBqGvksAgAAAAAB2drl","B8JRxL079xbhqQBqGvksAgAAAAAB2eLk","B8JRxL079xbhqQBqGvksAgAAAAAB2evI","B8JRxL079xbhqQBqGvksAgAAAAAB3-Ur","B8JRxL079xbhqQBqGvksAgAAAAAB1dhE","B8JRxL079xbhqQBqGvksAgAAAAABhbOG","B8JRxL079xbhqQBqGvksAgAAAAABhWq3","B8JRxL079xbhqQBqGvksAgAAAAABhSPw","B8JRxL079xbhqQBqGvksAgAAAAABhScE","B8JRxL079xbhqQBqGvksAgAAAAABhM51","B8JRxL079xbhqQBqGvksAgAAAAABhM9l","B8JRxL079xbhqQBqGvksAgAAAAAAS5Wk","B8JRxL079xbhqQBqGvksAgAAAAAAS7IM","B8JRxL079xbhqQBqGvksAgAAAAAASr4O","B8JRxL079xbhqQBqGvksAgAAAAAASqvS","B8JRxL079xbhqQBqGvksAgAAAAAASr1w","B8JRxL079xbhqQBqGvksAgAAAAAASGhp","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"y7Mdo_ee9-4XsWhpA4MB0g":{"address_or_lines":[4652224,58223725,10400868,10401064,10401333,10401661,58236869,58227432,58120068,58163344,58184537,58041720,57725674,57726188,57066632,22280836,22281116,22396783,22397566,22398116,5362852,5363370,4271546,4264588,4299069],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAADeGxt","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrRk","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrUo","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrY1","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrd9","6auiCMWq5cA-hAbqSYvdQQAAAAADeJ_F","6auiCMWq5cA-hAbqSYvdQQAAAAADeHro","6auiCMWq5cA-hAbqSYvdQQAAAAADdteE","6auiCMWq5cA-hAbqSYvdQQAAAAADd4CQ","6auiCMWq5cA-hAbqSYvdQQAAAAADd9NZ","6auiCMWq5cA-hAbqSYvdQQAAAAADdaV4","6auiCMWq5cA-hAbqSYvdQQAAAAADcNLq","6auiCMWq5cA-hAbqSYvdQQAAAAADcNTs","6auiCMWq5cA-hAbqSYvdQQAAAAADZsSI","6auiCMWq5cA-hAbqSYvdQQAAAAABU_qE","6auiCMWq5cA-hAbqSYvdQQAAAAABU_uc","6auiCMWq5cA-hAbqSYvdQQAAAAABVb9v","6auiCMWq5cA-hAbqSYvdQQAAAAABVcJ-","6auiCMWq5cA-hAbqSYvdQQAAAAABVcSk","6auiCMWq5cA-hAbqSYvdQQAAAAAAUdSk","6auiCMWq5cA-hAbqSYvdQQAAAAAAUdaq","6auiCMWq5cA-hAbqSYvdQQAAAAAAQS26","6auiCMWq5cA-hAbqSYvdQQAAAAAAQRKM","6auiCMWq5cA-hAbqSYvdQQAAAAAAQZk9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"vODIlh-kDOyM2hWSJhdfpA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19976893,19927481,19928567,19983876,19943049,19984068,19944276,19984260,19945213,19982696,19937907,19982884,19142858],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNK9","v6HIzNa4K6G4nRP9032RIAAAAAABMBG5","v6HIzNa4K6G4nRP9032RIAAAAAABMBX3","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMO-E","v6HIzNa4K6G4nRP9032RIAAAAAABMFb9","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMOok","v6HIzNa4K6G4nRP9032RIAAAAAABJBjK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"QKuCwkwTUdmVpouD1TSb6g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858562,18659470],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwSC","j8DVIOTu7Btj9lgFefJ84AAAAAABHLiO"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"zQ3yVnMIXoz1yUFx6SaSlA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528467,54488242,54489352,54492882,44042020,44050554,43824563,43838109,43282962,43282989,10485923,16807,2741196,2827770,2817934],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQAnT","MNBJ5seVz_ocW6tcr1HSmwAAAAADP2yy","MNBJ5seVz_ocW6tcr1HSmwAAAAADP3EI","MNBJ5seVz_ocW6tcr1HSmwAAAAADP37S","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAck","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCh6","MNBJ5seVz_ocW6tcr1HSmwAAAAACnLWz","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOqd","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv-O"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"PfGJvpI_t-0Eiwgl8k31BA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708921,24712242,24698684,24696100,20084020,20086666,20084847,20085083,18040582,18049603],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQc5","j8DVIOTu7Btj9lgFefJ84AAAAAABeRQy","j8DVIOTu7Btj9lgFefJ84AAAAAABeN88","j8DVIOTu7Btj9lgFefJ84AAAAAABeNUk","j8DVIOTu7Btj9lgFefJ84AAAAAABMnU0","j8DVIOTu7Btj9lgFefJ84AAAAAABMn-K","j8DVIOTu7Btj9lgFefJ84AAAAAABMnhv","j8DVIOTu7Btj9lgFefJ84AAAAAABMnlb","j8DVIOTu7Btj9lgFefJ84AAAAAABE0cG","j8DVIOTu7Btj9lgFefJ84AAAAAABE2pD"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"P-lVr6eiwDBuO8eZBdsdMQ":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528745,54499864,54500494,54477482,44044054,44044293,44044676,44051020,43988398,43982642,43988240,43826825,43837959,43282962,43282989,10485923,16755],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQArp","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5oY","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5yO","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA8W","MNBJ5seVz_ocW6tcr1HSmwAAAAACoBAF","MNBJ5seVz_ocW6tcr1HSmwAAAAACoBGE","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCpM","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzWu","MNBJ5seVz_ocW6tcr1HSmwAAAAACnx8y","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzUQ","MNBJ5seVz_ocW6tcr1HSmwAAAAACnL6J","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"KxQngfXsErVAsVuASxix6w":{"address_or_lines":[4652224,11645454,31861537,31858282,31847101,59040776,58304471,58312462,31457395,31076505,31042101,31058818,31448215,30842852,30845380,30848778,30847620,4952886,4953125,4953508,4960780,4898318,4893650,4898125,4628233,4660663,10485923,16807,3104019,8528279,936364],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAAsbIO","6auiCMWq5cA-hAbqSYvdQQAAAAAB5ish","6auiCMWq5cA-hAbqSYvdQQAAAAAB5h5q","6auiCMWq5cA-hAbqSYvdQQAAAAAB5fK9","6auiCMWq5cA-hAbqSYvdQQAAAAADhOQI","6auiCMWq5cA-hAbqSYvdQQAAAAADeafX","6auiCMWq5cA-hAbqSYvdQQAAAAADeccO","6auiCMWq5cA-hAbqSYvdQQAAAAAB4ABz","6auiCMWq5cA-hAbqSYvdQQAAAAAB2jCZ","6auiCMWq5cA-hAbqSYvdQQAAAAAB2ao1","6auiCMWq5cA-hAbqSYvdQQAAAAAB2euC","6auiCMWq5cA-hAbqSYvdQQAAAAAB39yX","6auiCMWq5cA-hAbqSYvdQQAAAAAB1p_k","6auiCMWq5cA-hAbqSYvdQQAAAAAB1qnE","6auiCMWq5cA-hAbqSYvdQQAAAAAB1rcK","6auiCMWq5cA-hAbqSYvdQQAAAAAB1rKE","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5M2","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5Ql","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5Wk","6auiCMWq5cA-hAbqSYvdQQAAAAAAS7IM","6auiCMWq5cA-hAbqSYvdQQAAAAAASr4O","6auiCMWq5cA-hAbqSYvdQQAAAAAASqvS","6auiCMWq5cA-hAbqSYvdQQAAAAAASr1N","6auiCMWq5cA-hAbqSYvdQQAAAAAARp8J","6auiCMWq5cA-hAbqSYvdQQAAAAAARx23","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAL10T","ew01Dk0sWZctP-VaEpavqQAAAAAAgiGX","ew01Dk0sWZctP-VaEpavqQAAAAAADkms"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"NDxOvbKIocbTk6FkHrLlqQ":{"address_or_lines":[4652224,58222957,10400868,10401064,10401333,10401661,58236101,58226664,58119300,58162576,58183769,58040952,57724906,57725420,57065864,22280836,22281206,22412958,22408242,22413668,22416921,22341332,22109092,22108612,11325304,11325700,10718668,11154818,57469092,57466065,4552751,4263429],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADeGlt","B8JRxL079xbhqQBqGvksAgAAAAAAnrRk","B8JRxL079xbhqQBqGvksAgAAAAAAnrUo","B8JRxL079xbhqQBqGvksAgAAAAAAnrY1","B8JRxL079xbhqQBqGvksAgAAAAAAnrd9","B8JRxL079xbhqQBqGvksAgAAAAADeJzF","B8JRxL079xbhqQBqGvksAgAAAAADeHfo","B8JRxL079xbhqQBqGvksAgAAAAADdtSE","B8JRxL079xbhqQBqGvksAgAAAAADd32Q","B8JRxL079xbhqQBqGvksAgAAAAADd9BZ","B8JRxL079xbhqQBqGvksAgAAAAADdaJ4","B8JRxL079xbhqQBqGvksAgAAAAADcM_q","B8JRxL079xbhqQBqGvksAgAAAAADcNHs","B8JRxL079xbhqQBqGvksAgAAAAADZsGI","B8JRxL079xbhqQBqGvksAgAAAAABU_qE","B8JRxL079xbhqQBqGvksAgAAAAABU_v2","B8JRxL079xbhqQBqGvksAgAAAAABVf6e","B8JRxL079xbhqQBqGvksAgAAAAABVewy","B8JRxL079xbhqQBqGvksAgAAAAABVgFk","B8JRxL079xbhqQBqGvksAgAAAAABVg4Z","B8JRxL079xbhqQBqGvksAgAAAAABVObU","B8JRxL079xbhqQBqGvksAgAAAAABUVuk","B8JRxL079xbhqQBqGvksAgAAAAABUVnE","B8JRxL079xbhqQBqGvksAgAAAAAArM94","B8JRxL079xbhqQBqGvksAgAAAAAArNEE","B8JRxL079xbhqQBqGvksAgAAAAAAo43M","B8JRxL079xbhqQBqGvksAgAAAAAAqjWC","B8JRxL079xbhqQBqGvksAgAAAAADbOik","B8JRxL079xbhqQBqGvksAgAAAAADbNzR","B8JRxL079xbhqQBqGvksAgAAAAAARXgv","B8JRxL079xbhqQBqGvksAgAAAAAAQQ4F"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"2GP6bCEH-XkrLdH6ox0E3Q":{"address_or_lines":[4623648,7066994,7068484,7069849,7058446,10002970,10005676,10124500,9016547,11291366,9016547,24500423,24494926,9016547,10689293,10690744,9016547,24494153,24444068,9016547,24526481,9016547,12769368,12762703,6837766,6838366,6839304,5651373,5585348,5510696,4903076,4768780,4778619],"file_ids":["JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA"],"frame_ids":["JsObMPhfT_zO2Q_B1cPLxAAAAAAARo0g","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9Vy","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9tE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-CZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa7QO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKIa","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKys","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmnzU","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAArErm","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABddjH","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcNO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoxsN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoyC4","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcBJ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdPyk","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdj6R","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwthY","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwr5P","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFYG","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFhe","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFwI","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVjut","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVTnE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVBYo","JsObMPhfT_zO2Q_B1cPLxAAAAAAAStCk","JsObMPhfT_zO2Q_B1cPLxAAAAAAASMQM","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOp7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"NYEjWS7muJ8dsj9z5lNehg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19908516,19901477,19920683,18932457,18907996,18882195],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL_cr","v6HIzNa4K6G4nRP9032RIAAAAAABIOLp","v6HIzNa4K6G4nRP9032RIAAAAAABIINc","v6HIzNa4K6G4nRP9032RIAAAAAABIB6T"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Nr5XZDDmb-nXg0BzTFzdFA":{"address_or_lines":[4652224,22354871,22382638,22364302,56669071,58509234,58268669,58227812,58241853,31197553,31197973,31304315,4873273,4873930,4883062,4875761,4874468,8925121,8860356,8860667,8476967,4872825,5688954,8906989,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16890,16350,1408382],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYLOP","-pk6w5puGcp-wKnQ61BZzQAAAAADfMey","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Alx","-pk6w5puGcp-wKnQ61BZzQAAAAAB3AsV","-pk6w5puGcp-wKnQ61BZzQAAAAAB3ap7","-pk6w5puGcp-wKnQ61BZzQAAAAAASlw5","-pk6w5puGcp-wKnQ61BZzQAAAAAASl7K","-pk6w5puGcp-wKnQ61BZzQAAAAAASoJ2","-pk6w5puGcp-wKnQ61BZzQAAAAAASmXx","-pk6w5puGcp-wKnQ61BZzQAAAAAASmDk","-pk6w5puGcp-wKnQ61BZzQAAAAAAiC_B","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzLE","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzP7","-pk6w5puGcp-wKnQ61BZzQAAAAAAgVkn","-pk6w5puGcp-wKnQ61BZzQAAAAAASlp5","-pk6w5puGcp-wKnQ61BZzQAAAAAAVs56","-pk6w5puGcp-wKnQ61BZzQAAAAAAh-jt","-pk6w5puGcp-wKnQ61BZzQAAAAAAVUwE","-pk6w5puGcp-wKnQ61BZzQAAAAAAVATI","-pk6w5puGcp-wKnQ61BZzQAAAAAASsLk","-pk6w5puGcp-wKnQ61BZzQAAAAAASHZk","-pk6w5puGcp-wKnQ61BZzQAAAAAASJlH","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEH6","piWSMQrh4r040D0BPNaJvwAAAAAAAD_e","piWSMQrh4r040D0BPNaJvwAAAAAAFX1-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"JVvUxIunvr6V68Rt99rK9w":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19045737,19044484,19054298,18859716,18879913,10485923,16807,2741196,2827770,2817385,2759858,2758809,2558430,2672376],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8bE","v6HIzNa4K6G4nRP9032RIAAAAAABIBWp","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv1p","A2oiHVwisByxRn5RDT4LjAAAAAAAKhyy","A2oiHVwisByxRn5RDT4LjAAAAAAAKhiZ","A2oiHVwisByxRn5RDT4LjAAAAAAAJwne","A2oiHVwisByxRn5RDT4LjAAAAAAAKMb4"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"tagsGmBta7BnDHBzEbH9eQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927445,6732427,882422,8542429],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePaV","ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL","ew01Dk0sWZctP-VaEpavqQAAAAAADXb2","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"CjP83pplY09FGl9PBMeqCg":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895829,22487599,22488317,19128052,22462004,19128023,19127329,22526546,19673252,19587368,18920557,18789740,18799034,10485923,16743,2752800,2752044,2741274,6650246,6650090,7860129,6674998,6706857,2411027,2395208],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5YV","j8DVIOTu7Btj9lgFefJ84AAAAAABVyIv","j8DVIOTu7Btj9lgFefJ84AAAAAABVyT9","j8DVIOTu7Btj9lgFefJ84AAAAAABI970","j8DVIOTu7Btj9lgFefJ84AAAAAABVr40","j8DVIOTu7Btj9lgFefJ84AAAAAABI97X","j8DVIOTu7Btj9lgFefJ84AAAAAABI9wh","j8DVIOTu7Btj9lgFefJ84AAAAAABV7pS","j8DVIOTu7Btj9lgFefJ84AAAAAABLDCk","j8DVIOTu7Btj9lgFefJ84AAAAAABKuEo","j8DVIOTu7Btj9lgFefJ84AAAAAABILRt","j8DVIOTu7Btj9lgFefJ84AAAAAABHrVs","j8DVIOTu7Btj9lgFefJ84AAAAAABHtm6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjq","piWSMQrh4r040D0BPNaJvwAAAAAAd--h","piWSMQrh4r040D0BPNaJvwAAAAAAZdo2","piWSMQrh4r040D0BPNaJvwAAAAAAZlap","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIxI"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"SQ6jhz-Ee7WHXLMOHOsDcQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,6715099,4221812],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAZnbb","ew01Dk0sWZctP-VaEpavqQAAAAAAQGt0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"eM1ATYEKUIN4nyPylmr13A":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440021,7478164],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYaV","ew01Dk0sWZctP-VaEpavqQAAAAAAchuU"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"9vNu8RjYClbqhYYGUiWI7A":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,51380,55074,37132,20242,23612,47200,14250,1480561,1970211,1481652,1480953,2600004,1079669,52860,1480561,1970211,1481652,1480953,2600004,1079483,6166,60608,20250,65302,10604,14228,1479868,2600004,1079483,29728,14228,1479868,2600004,1069332,47952],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","DxQN3aM1Ddn1lUwovx75wQ","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0","U4Le8nh-beog_B7jq7uTIAAAAAAAANci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFw8","W8AFtEsepzrJ6AasHrCttwAAAAAAALhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAM58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","kSaNXrGzSS3BnDNNWezzMAAAAAAAABgW","ne8F__HPIVgxgycJADVSzAAAAAAAAOzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAE8a","O_h7elJSxPO7SiCsftYRZgAAAAAAAP8W","DxQN3aM1Ddn1lUwovx75wQAAAAAAACls","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAHQg","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEFEU","--q8cwZVXbHL2zOM_p3RlQAAAAAAALtQ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,1,1,3,3,3,1]},"CU-T9AvnxmWd1TTRjgV01Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7508830,6761766,2559050],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe","9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m","9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"hoJT-ObO7MDFTgt9UeFJfg":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2822585,3001783,2924437,3111967,3095700,156159,136664,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317318,469350,452199,518055,511351],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxG5","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3wf","-p9BlJh9JZMPPNjY_j92ngAAAAAALzyU","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhXY","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBnG","huWyXZbCBWCe2ZtK9BiokQAAAAAABylm","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB813"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"us5XzJaFA8Y8a8Jhq7VWzQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797926,6797556,2726254,449444],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0","ew01Dk0sWZctP-VaEpavqQAAAAAAKZlu","ew01Dk0sWZctP-VaEpavqQAAAAAABtuk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"tWPDa1sBMePW-YFiahrHBA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10489481,12583132,6878809,6871998,6871380,7366427,7371724,7390232,7379824,6863646,7218707,7217709,6862495,13713],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","5OhlekN4HU3KaqhG_GtinA"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J","9LzzIocepYcOjnUsLlgOjgAAAAAAwADc","9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ","9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-","9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU","9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb","9LzzIocepYcOjnUsLlgOjgAAAAAAcHvM","9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY","9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw","9LzzIocepYcOjnUsLlgOjgAAAAAAaLse","9LzzIocepYcOjnUsLlgOjgAAAAAAbiYT","9LzzIocepYcOjnUsLlgOjgAAAAAAbiIt","9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf","5OhlekN4HU3KaqhG_GtinAAAAAAAADWR"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"KKjaO47Ew4fmVCY-lBFkLg":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317297,1335062,1334886,452199,517552],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBmx","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF5m","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-Ww"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"zxyQebekMWvnWWEuWSzR9Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265873,31266293,31372635,4873273,4873930,4883062,4875761,4874468,8927681,8862916,8863227,8479623,4872825,5688954,8909549,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7925524,6772762,6770749,6770671,7937674,6744271,7917830,882422,8541549],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RRR","B8JRxL079xbhqQBqGvksAgAAAAAB3RX1","B8JRxL079xbhqQBqGvksAgAAAAAB3rVb","B8JRxL079xbhqQBqGvksAgAAAAAASlw5","B8JRxL079xbhqQBqGvksAgAAAAAASl7K","B8JRxL079xbhqQBqGvksAgAAAAAASoJ2","B8JRxL079xbhqQBqGvksAgAAAAAASmXx","B8JRxL079xbhqQBqGvksAgAAAAAASmDk","B8JRxL079xbhqQBqGvksAgAAAAAAiDnB","B8JRxL079xbhqQBqGvksAgAAAAAAhzzE","B8JRxL079xbhqQBqGvksAgAAAAAAhz37","B8JRxL079xbhqQBqGvksAgAAAAAAgWOH","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAh_Lt","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeO8U","A2oiHVwisByxRn5RDT4LjAAAAAAAZ1ga","A2oiHVwisByxRn5RDT4LjAAAAAAAZ1A9","A2oiHVwisByxRn5RDT4LjAAAAAAAZ0_v","A2oiHVwisByxRn5RDT4LjAAAAAAAeR6K","A2oiHVwisByxRn5RDT4LjAAAAAAAZujP","A2oiHVwisByxRn5RDT4LjAAAAAAAeNEG","A2oiHVwisByxRn5RDT4LjAAAAAAADXb2","A2oiHVwisByxRn5RDT4LjAAAAAAAglVt"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"UI-7Z494NKAWuv1FuNlxoQ":{"address_or_lines":[4652224,59049454,56939078,10401064,10401333,10401661,56939173,56937529,56937108,38310942,29802677,29803353,29746360,8752265,4268420,4265510,4264588,4297532,10488398,10493154,585663,12583132,6882905,21536,6881628,6877992,6877443,6876950,7370944,7369391,7367054,7370328,7370195,7369770,7552115,7547124,7496717,7491196,7486785,7507864,7393057,7394424,7384016,6867742,7222899,7221901,6866591,13650],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","R3YNZBiWt7Z3ZpFfTh6XyQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","R3YNZBiWt7Z3ZpFfTh6XyQ"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADhQXu","B8JRxL079xbhqQBqGvksAgAAAAADZNJG","B8JRxL079xbhqQBqGvksAgAAAAAAnrUo","B8JRxL079xbhqQBqGvksAgAAAAAAnrY1","B8JRxL079xbhqQBqGvksAgAAAAAAnrd9","B8JRxL079xbhqQBqGvksAgAAAAADZNKl","B8JRxL079xbhqQBqGvksAgAAAAADZMw5","B8JRxL079xbhqQBqGvksAgAAAAADZMqU","B8JRxL079xbhqQBqGvksAgAAAAACSJQe","B8JRxL079xbhqQBqGvksAgAAAAABxsC1","B8JRxL079xbhqQBqGvksAgAAAAABxsNZ","B8JRxL079xbhqQBqGvksAgAAAAABxeS4","B8JRxL079xbhqQBqGvksAgAAAAAAhYyJ","B8JRxL079xbhqQBqGvksAgAAAAAAQSGE","B8JRxL079xbhqQBqGvksAgAAAAAAQRYm","B8JRxL079xbhqQBqGvksAgAAAAAAQRKM","B8JRxL079xbhqQBqGvksAgAAAAAAQZM8","A2oiHVwisByxRn5RDT4LjAAAAAAAoApO","A2oiHVwisByxRn5RDT4LjAAAAAAAoBzi","A2oiHVwisByxRn5RDT4LjAAAAAAACO-_","A2oiHVwisByxRn5RDT4LjAAAAAAAwADc","A2oiHVwisByxRn5RDT4LjAAAAAAAaQZZ","R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAAFQg","A2oiHVwisByxRn5RDT4LjAAAAAAAaQFc","A2oiHVwisByxRn5RDT4LjAAAAAAAaPMo","A2oiHVwisByxRn5RDT4LjAAAAAAAaPED","A2oiHVwisByxRn5RDT4LjAAAAAAAaO8W","A2oiHVwisByxRn5RDT4LjAAAAAAAcHjA","A2oiHVwisByxRn5RDT4LjAAAAAAAcHKv","A2oiHVwisByxRn5RDT4LjAAAAAAAcGmO","A2oiHVwisByxRn5RDT4LjAAAAAAAcHZY","A2oiHVwisByxRn5RDT4LjAAAAAAAcHXT","A2oiHVwisByxRn5RDT4LjAAAAAAAcHQq","A2oiHVwisByxRn5RDT4LjAAAAAAAczxz","A2oiHVwisByxRn5RDT4LjAAAAAAAcyj0","A2oiHVwisByxRn5RDT4LjAAAAAAAcmQN","A2oiHVwisByxRn5RDT4LjAAAAAAAck58","A2oiHVwisByxRn5RDT4LjAAAAAAAcj1B","A2oiHVwisByxRn5RDT4LjAAAAAAAco-Y","A2oiHVwisByxRn5RDT4LjAAAAAAAcM8h","A2oiHVwisByxRn5RDT4LjAAAAAAAcNR4","A2oiHVwisByxRn5RDT4LjAAAAAAAcKvQ","A2oiHVwisByxRn5RDT4LjAAAAAAAaMse","A2oiHVwisByxRn5RDT4LjAAAAAAAbjZz","A2oiHVwisByxRn5RDT4LjAAAAAAAbjKN","A2oiHVwisByxRn5RDT4LjAAAAAAAaMaf","R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAADVS"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"6yHX0lcyWmly8MshBzd78Q":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,3132,30816,59306,1480561,1970211,1481652,1480953,2600004,1079483,36350,56142,27276,48820,6316,1479960,1494280,2600004,1079483,31058,15346,1479960,2600004,1079483,44156,54044,53948,63380,1479868,2600004,1079483,8496,63380,1479868,2600004,1056891,26970,28876,2143205,2040020],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","3FRCbvQLPuJyn2B-2wELGw","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAAw8","W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","EFJHOn-GACfHXgae-R1yDAAAAAAAAI3-","GdaBUD9IUEkKxIBryNqV2wAAAAAAANtO","QU8QLoFK6ojrywKrBFfTzAAAAAAAAGqM","V558DAsp4yi8bwa8eYwk5QAAAAAAAL60","tuTnMBfyc9UiPsI0QyvErAAAAAAAABis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAKx8","-9oyoP4Jj2iRkwEezqId-gAAAAAAANMc","3FRCbvQLPuJyn2B-2wELGwAAAAAAANK8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAACEw","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECB7","--q8cwZVXbHL2zOM_p3RlQAAAAAAAGla","yaTrLhUSIq2WitrTHLBy3QAAAAAAAHDM","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAILPl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHyDU"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3]},"uEL43HtanLRCO2rLB4ttzQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,64358,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,11986,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,51652,2573747,2594708,1091475,13186,2790352,1482889,1482415,2595076,1069851,33394,1493754,2595076,1049998,50014,45950,2995046,2994923,3072326,3072096,3066615,1917744],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8EY5iPD5-FtlXFBTyb6lkw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","dCCKy6JoX0PADOFic8hRNQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","7RLN3PNgotUSmdQVMRTSvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","43vJVfBcAahhLMzDSC-H0g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","RRFdsCrJw1U2erb6qtrrzQ","_zH-ed4x-42m0B4z2RmcdQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","dCCKy6JoX0PADOFic8hRNQAAAAAAAC7S","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","7RLN3PNgotUSmdQVMRTSvAAAAAAAAMnE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","43vJVfBcAahhLMzDSC-H0gAAAAAAADOC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFMb","ik6PIX946fW_erE7uBJlVQAAAAAAAIJy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsr6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAWO","RRFdsCrJw1U2erb6qtrrzQAAAAAAAMNe","_zH-ed4x-42m0B4z2RmcdQAAAAAAALN-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALbNm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALbLr","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsr3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUMw"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,1,1,3,3,3,3,3,3]},"mXgK2ekWZ4qH-uHB8QaLtA":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,824,116,12,8,54,12,46,22,1091612,1804498,665668,663668,1112453,1232178,833111,2265137,2264574,2258679],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","IlUL618nbeW5Kz4uyGZLrQ","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","7aaw2O1Vn7-6eR8XuUWQZQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4","IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu","7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAG4jS","G68hjsyagwq6LpWrMjDdngAAAAAACihE","G68hjsyagwq6LpWrMjDdngAAAAAACiB0","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEs0y","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInb3"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"1twYzjHR6hCfJqQLvJ81XA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,50892,43744,57354,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1075570,17430,40768,26744,7590,63980,23014,47110,19666,47110,34306,44426,44426,44426,44426,44426,44426,44426,44334,47110,46588,46966,1670488,3072326,3072096,3066777,1745028],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","O_h7elJSxPO7SiCsftYRZg","ZLTqiSLOmv4Ej_7d8yKLmw","qLiwuFhv6DIyQ0OgaSMXCg","ka2IKJhpWbD6PA3J3v624w","e8Lb_MV93AH-OkvHPPDitg","ka2IKJhpWbD6PA3J3v624w","1vivUE5hL65442lQ9a_ylg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","ka2IKJhpWbD6PA3J3v624w","fCsVLBj60GK9Hf8VtnMcgA","ka2IKJhpWbD6PA3J3v624w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAMbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGly","kSaNXrGzSS3BnDNNWezzMAAAAAAAAEQW","ne8F__HPIVgxgycJADVSzAAAAAAAAJ9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAAGh4","O_h7elJSxPO7SiCsftYRZgAAAAAAAB2m","ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAPns","qLiwuFhv6DIyQ0OgaSMXCgAAAAAAAFnm","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","e8Lb_MV93AH-OkvHPPDitgAAAAAAAEzS","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","1vivUE5hL65442lQ9a_ylgAAAAAAAIYC","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK0u","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","fCsVLBj60GK9Hf8VtnMcgAAAAAAAALX8","ka2IKJhpWbD6PA3J3v624wAAAAAAALd2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGX1Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsuZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGqCE"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3]},"f-LRF9Sfj675yc68DOXczw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,56302,2790352,1482889,1482415,2595076,1079144,25326,27384,368,1760,1481694,1828960,2573747,2594708,1091475,16910,2790352,1482889,1482415,2595076,1079144,25326,27384,368,1760,1481694,1828960,2573747,2594708,1073425,16424,24340,2572553,2928589,1108138,1105869,1310238,1245752,1200236,1192099,1183786,1104144,1103499,2268402,1775000,1761295,1048342],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","cfc92_adXFZraMPGbgbcDg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","WLefmNR3IpykzCX3WWNnMw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","IvJrzqPEgeoowZySdwFq3w","vkeP2ntYyoFN0A16x9eliw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","cfc92_adXFZraMPGbgbcDgAAAAAAANvu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","WLefmNR3IpykzCX3WWNnMwAAAAAAAEIO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","IvJrzqPEgeoowZySdwFq3wAAAAAAAEAo","vkeP2ntYyoFN0A16x9eliwAAAAAAAF8U","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0EJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALK_N","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEOiq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEN_N","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAE_4e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEwI4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAElBs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEjCj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEhAq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAENkQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAENaL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_8W"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"p24lyWOwFjGMsQaWybQUMA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,36384,21728,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959028,1099442],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MXHCWLuAJw7Gg6T7hdrPHA","ecHSwk0KAG7gFkiYdAgIZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAI4g","ecHSwk0KAG7gFkiYdAgIZwAAAAAAAFTg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeR0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEMay"],"type_ids":[3,3,3,3,3,3,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3]},"KHat1RLkyP8wPwwR1uD04A":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,40,38,174,104,68,80,38,174,104,68,60,38,174,104,68,382,38,174,104,68,24,38,174,104,68,28,38,174,104,68,0,1090933,1814182,788459,788130,1197048,1243240,1238413,1212345,1033898,429638],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","0cqvso24v07beLsmyC0nMw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","3WU6MO1xF7O0NmrHFj4y4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","x617yDiAG2Sqq3cLDkX4aA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZTmztUywGW_uHXPqWVr76w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZPAF8mJO2n0azNbxzkJ2rA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","0cqvso24v07beLsmyC0nMwAAAAAAAABQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","3WU6MO1xF7O0NmrHFj4y4AAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","x617yDiAG2Sqq3cLDkX4aAAAAAAAAAF-","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZTmztUywGW_uHXPqWVr76wAAAAAAAAAY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZPAF8mJO2n0azNbxzkJ2rAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvho","G68hjsyagwq6LpWrMjDdngAAAAAAEuWN","G68hjsyagwq6LpWrMjDdngAAAAAAEn-5","G68hjsyagwq6LpWrMjDdngAAAAAAD8aq","G68hjsyagwq6LpWrMjDdngAAAAAABo5G"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"B-OQjwP7KzSb4f6cXUL1bA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,3616,42208,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,50288,64358,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986405,1946637,1538878,2269465,2268402,1774938,1011120],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MXHCWLuAJw7Gg6T7hdrPHA","ecHSwk0KAG7gFkiYdAgIZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAA4g","ecHSwk0KAG7gFkiYdAgIZwAAAAAAAKTg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAMRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbQN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF3s-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIqEZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxVa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD22w"],"type_ids":[3,3,3,3,3,3,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"kOWftL0Ttias8Z1isZi9oA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,58710,61916,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,12482,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,49534,2790352,1482889,1482415,2595076,1097615,37614,39672,12656,17976,49494,2722496,3251876,3237020,1748920],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SOSrvCNmbstVFKAcqHNCvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAADDC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","SOSrvCNmbstVFKAcqHNCvAAAAAAAAMF-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEL-P","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKYrA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMZ6k","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWSc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGq-4"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3]},"JzGylmBPluUmIML9XnagKw":{"address_or_lines":[2599636,1079669,2228,5922,53516,36626,36806,45836,18932,13860,58864,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,56398,58456,31408,16708,2578675,2599636,1091600,36298,2795776,1483241,1482767,2600004,1074397,56398,58456,31408,16708,2578675,2599636,1091600,46582,2795776,1483241,1482767,2600004,1073803,56398,58456,31408,16492,49494,45794,2852079,2851771,2849353,2846190,2849353,2846190,2847233,2838792],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SD7uzoegJjRT3jYNpuQ5wQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAI_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAALMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAI3K","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SD7uzoegJjRT3jYNpuQ5wQAAAAAAALX2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3IB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK1EI"],"type_ids":[3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3]},"tTw0tfSnPtZhbcyzyVHHpg":{"address_or_lines":[4622976,4423302,48950246,48930003,48929418,48931768,15219528,15219797,15220198,48932134,15224283,15224488,15224631,15220795,15220538,48932900,48934534,48924362,21171091,15443915,15441240,6695879,6686586,6688471,15292865,6927608,7025423,9353786,9296758,9312446,9317924,5671585,9381613,9295438,6263620,6258992,6257863,6068365,6003908,5935528,5054445,4702860,4711258,10485923,16743,2752800,2752044,2741274,6650246,6650083,7384662,7382442,7451553,7447772,7441688,7327025,7328392,7317984,6802313,6799580,6799223,6797958],"file_ids":["-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-SVIyCZG9IbFKK-fe2Wh4gAAAAAARoqA","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAQ36G","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6uvm","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6pzT","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6pqK","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qO4","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6DtI","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6DxV","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6D3m","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qUm","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E3b","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E6o","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E83","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6EA7","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6D86","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qgk","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6q6G","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6obK","-SVIyCZG9IbFKK-fe2Wh4gAAAAABQwuT","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA66fL","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA651Y","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZivH","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZgd6","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZg7X","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6VnB","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAabT4","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAazMP","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjro6","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjdt2","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjhi-","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAji4k","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAVoqh","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjybt","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjdZO","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX5NE","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX4Ew","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX3zH","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAXJiN","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAW5zE","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAWpGo","-SVIyCZG9IbFKK-fe2Wh4gAAAAAATR_t","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAR8KM","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAR-Na","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjj","piWSMQrh4r040D0BPNaJvwAAAAAAcK5W","piWSMQrh4r040D0BPNaJvwAAAAAAcKWq","piWSMQrh4r040D0BPNaJvwAAAAAAcbOh","piWSMQrh4r040D0BPNaJvwAAAAAAcaTc","piWSMQrh4r040D0BPNaJvwAAAAAAcY0Y","piWSMQrh4r040D0BPNaJvwAAAAAAb80x","piWSMQrh4r040D0BPNaJvwAAAAAAb9KI","piWSMQrh4r040D0BPNaJvwAAAAAAb6ng","piWSMQrh4r040D0BPNaJvwAAAAAAZ8uJ","piWSMQrh4r040D0BPNaJvwAAAAAAZ8Dc","piWSMQrh4r040D0BPNaJvwAAAAAAZ793","piWSMQrh4r040D0BPNaJvwAAAAAAZ7qG"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"E_F-N51BcZ4iQ9oPaHFKXw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,400,38,174,104,68,20,38,174,104,68,88,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044780,2041460,1171829,2265239,2264574,2258463,1015963,2256180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","c-eM3dWacIPzBmA_7-OWBw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","w9AQfBE7-1YeE4mOMirPBg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAGQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","c-eM3dWacIPzBmA_7-OWBwAAAAAAAAAU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","w9AQfBE7-1YeE4mOMirPBgAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNs","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAD4Cb","G68hjsyagwq6LpWrMjDdngAAAAAAIm00"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"d04G8ZHV3kYQ0ekQBw1VYQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,62806,476,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17614,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,41518,2790352,1482889,1482415,2595076,1076587,25326,27384,368,1592,16726,55682,2846655,2846347,2843929,2840766,2843929,2840766,2843929,2840692,1912597,3072400],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uo8E5My6tupMEt-pfV-uhA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAETO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1h0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHS8V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuGQ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"I-DofAMUQgh7q14tBJcZlA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,30412,43744,6426,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1062336,60522,1844695,1847563,1481567,2595076,1079485,19388,48282,27404,1479608,1493928,2595076,1079485,63084,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,5750,41842,34364,63380,1479516,2595076,1079485,14544,63380,1479516,2595076,1056995,11370,55184,2188039,2032414,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABka","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAOxq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAEu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAALya","un9fLDZOLvDMO52ltZtuegAAAAAAAGsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAPZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAABZ2","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAADjQ","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECDj","--q8cwZVXbHL2zOM_p3RlQAAAAAAACxq","yaTrLhUSIq2WitrTHLBy3QAAAAAAANeQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIWMH","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHwMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3,3]},"tGGi0acvAmmxOR5DbuF3dg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,49488,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,20126,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,12078,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1079144,65228,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079144,28888,1480209,1827586,1940195,1986405,1946664,1775467,1749899,1745572,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","r1l-BTVp1g6dSvPPoOY_cg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAE6e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAC8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAP7M","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","r1l-BTVp1g6dSvPPoOY_cgAAAAAAAHDY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbQo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxdr","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGrOL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGqKk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"Ws9TqFMz-kHv_-7zrBFdKw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,188,38,174,104,68,60,38,174,104,68,98,38,174,104,68,8,38,174,104,68,36,38,174,104,14,32,166,1090933,19429,41240,50286],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","IcegEVkl4JzbMBhUeMqp0Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","tz0ps4QDYR1clO_q5ziJUQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M0gS5SrmklEEjlV4jbSIBA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","k5C4r96b77lEZ_fHFwCYkQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","tz0ps4QDYR1clO_q5ziJUQAAAAAAAABi","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M0gS5SrmklEEjlV4jbSIBAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","k5C4r96b77lEZ_fHFwCYkQAAAAAAAAAk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMRu"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"nBHRVpYV5wUL_UAb5ff6Zg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,33826,49772,35602,22316,60128,28682,1480209,1969795,1481300,1480601,2595076,1079144,51020,1480209,1969795,1481300,1480601,2595076,1062336,53402,1844695,1847563,1481567,2595076,1079485,35772,40874,43788,1479608,1493928,2595076,1079485,13932,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,1990,41842,34364,63380,1479516,2595076,1079485,8256,63380,1479516,2595076,1073749,4896,39178,32948,3149429,3144768,1903783,1765444,1761295,1048797],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","wXOyVgf5_nNg6CUH5kFBbg","zEgDK4qMawUAQZjg5YHyww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAFcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAOrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAHAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAMdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAANCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAJ-q","un9fLDZOLvDMO52ltZtuegAAAAAAAKsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAADZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAAAfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAACBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAABMg","wXOyVgf5_nNg6CUH5kFBbgAAAAAAAJkK","zEgDK4qMawUAQZjg5YHywwAAAAAAAIC0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMA51","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL_xA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHQyn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGvBE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEADd"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,1,3,3,3,3,3,3]},"vfw5EN0FEHQCAj0w-N2avQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,5462,8668,3444,60212,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,24902,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,21798,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,62098,2789627,1482889,1482415,2595076,1073425,9228,2567913,1848405,1837592,1848017,2712905,2221838,2208668,2039344],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","780bLUPADqfQ3x1T5lnVOg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","X0TUmWpd8saA6nnPGQi3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAACHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAAOs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAGFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","780bLUPADqfQ3x1T5lnVOgAAAAAAAFUm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","X0TUmWpd8saA6nnPGQi3nQAAAAAAAPKS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","Npep8JfxWDWZ3roJSD7jPgAAAAAAACQM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDLR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKWVJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIecO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIbOc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHx4w"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3]},"lyeLQDjWsQDYEJbcY4aFJA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,51380,55074,37132,20242,15420,47200,6058,1480561,1970211,1481652,1480953,2600004,1079669,52860,1480561,1970211,1481652,1480953,2600004,1062448,62522,1845095,1847963,1481919,2600004,1079483,44204,61562,19788,1479960,1494280,2600004,1079483,22700,1479960,1494280,2600004,1079483,31058,15346,1479960,2600004,1079483,54374,42194,5116,30612,1479868,2600004,1079483,16608,30612,1479868,2600004,1074397,28580,3123760,766784,10485923,16807,2741468,2828042,2817657,2760130,2759130,4216293],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","-T5rZCijT5TDJjmoEi8Kxg","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","xLxcEbwnZ5oNrk99ZsxcSQ","Z_CHd3Zjsh2cWE2NSdbiNQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0","U4Le8nh-beog_B7jq7uTIAAAAAAAANci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S","grZNsSElR5ITq8H2yHCNSwAAAAAAADw8","W8AFtEsepzrJ6AasHrCttwAAAAAAALhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAM58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEDYw","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPQ6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCdn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDKb","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAKys","MYrgKQIxdDhr1gdpucfc-QAAAAAAAPB6","un9fLDZOLvDMO52ltZtuegAAAAAAAE1M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","tuTnMBfyc9UiPsI0QyvErAAAAAAAAFis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","rTFMSHhLRlj86vHPR06zoQAAAAAAANRm","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKTS","-T5rZCijT5TDJjmoEi8KxgAAAAAAABP8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEDg","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","--q8cwZVXbHL2zOM_p3RlQAAAAAAAG-k","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAL6ow","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7NA","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc","ew01Dk0sWZctP-VaEpavqQAAAAAAKycK","ew01Dk0sWZctP-VaEpavqQAAAAAAKv55","ew01Dk0sWZctP-VaEpavqQAAAAAAKh3C","ew01Dk0sWZctP-VaEpavqQAAAAAAKhna","ew01Dk0sWZctP-VaEpavqQAAAAAAQFXl"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,4,4,4,4,4,4,4,4]},"cqzgaW0F-6gZ8uHz_Pf3hQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,188,38,174,104,68,60,38,174,104,68,86,38,174,104,68,4,38,174,104,68,0,38,174,104,68,0,714,34,1115045,1179023,833111,2265137,2264574,2261229,1175338],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","IcegEVkl4JzbMBhUeMqp0Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","tz0ps4QDYR1clO_q5ziJUQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","O2RGJIowquMzuET0HYQ6aQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","Ht79I_xqXv3bOgaClTNQ4w","T8-enlAkCZXqinPHW4B8sw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","tz0ps4QDYR1clO_q5ziJUQAAAAAAAABW","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","O2RGJIowquMzuET0HYQ6aQAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","Ht79I_xqXv3bOgaClTNQ4wAAAAAAAALK","T8-enlAkCZXqinPHW4B8swAAAAAAAAAi","G68hjsyagwq6LpWrMjDdngAAAAAAEQOl","G68hjsyagwq6LpWrMjDdngAAAAAAEf2P","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAIoDt","G68hjsyagwq6LpWrMjDdngAAAAAAEe8q"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3]},"b89Eo7vMfG4HsPSBVvjiKQ":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,31334,49372,51700,46628,9712,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1091600,32150,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1091600,7938,2795051,1483241,1482767,2600004,1079483,28112,42150,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1079669,40672,1482046,1829360,2586325,1480953,1480561,1940968,1986911,1983192],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","3HhVgGD2yvuFLpoZq7RfKw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fDiQPd_MeGeyY9ZBOSU1Gg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAHpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAMDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAMn0","xwuAPHgc12-8PZB3i-320gAAAAAAALYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAH2W","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAB8C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAG3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","fDiQPd_MeGeyY9ZBOSU1GgAAAAAAAJ7g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkLY"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3]},"5_-zAnLDYAi4FySmVgS6iw":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,61666,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,9122,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,8610,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,11838,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,61238,1481694,1828960,2581297,2595076,1072525,49410,1646337,3072295,1865241,10489950,422647],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","b-3iFnlA7BmzAxDEzxShdA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8jcOoolAg5RmmHop7NqzWQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2LABj1asXFICsosP2OrbVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N1ZmsCOKFJHNThnHfFYo6Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAAPDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAACOi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","b-3iFnlA7BmzAxDEzxShdAAAAAAAACGi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8jcOoolAg5RmmHop7NqzWQAAAAAAAC4-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","2LABj1asXFICsosP2OrbVQAAAAAAAO82","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF2N","N1ZmsCOKFJHNThnHfFYo6QAAAAAAAMEC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGR8B","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnL3"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,4,4]},"zOI_cRK31hVrh4Typ0-Fxg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,16720,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,60990,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,44846,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,40354,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,48884,1481694,1828960,2581397,1480601,1480209,1940568,1986405,1948474,1768216,1756070,1865241,10490014,423063,2283967,2281647,2098628,2098378,8541549],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-gDCCFjiBc58_iqAxti3Kw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAO4-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAJ2i","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","-gDCCFjiBc58_iqAxti3KwAAAAAAAL70","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbs6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGvsY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGsum","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAItCv","A2oiHVwisByxRn5RDT4LjAAAAAAAIAXE","A2oiHVwisByxRn5RDT4LjAAAAAAAIATK","A2oiHVwisByxRn5RDT4LjAAAAAAAglVt"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"4U9ayDnwvWmqJPhn_AOKew":{"address_or_lines":[38782,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,50350,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,10266,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,31478,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,4998,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959065,1765336,1761295,1048381],"file_ids":["GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","d4jl580PLMUwu5s3I4wcXg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","tKago5vqLnwIkezk_wTBpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rpq4cV1KPyFZcnKfWjKdZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uFElJcsK9my-kA6ZYzT1uw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["GP7h96O0_ppGVtc-UpQQIQAAAAAAAJd-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","d4jl580PLMUwu5s3I4wcXgAAAAAAAMSu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","tKago5vqLnwIkezk_wTBpQAAAAAAACga","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","rpq4cV1KPyFZcnKfWjKdZwAAAAAAAHr2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uFElJcsK9my-kA6ZYzT1uwAAAAAAABOG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_89"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3]},"Jt6CexOHLEwUl4IeTgASBQ":{"address_or_lines":[2795051,1483241,1482767,2600004,1079483,64976,13478,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,57670,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,51706,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,59680,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1079669,0,1482046,1829360,2586325,1481195,1480561,1940968,1917658,1481652,1480953,2600004,1079483,41394,1480124,1827986,1940595,1986911,1983184],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yp8MidCGMe4czbl-NigsYQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2noK4QoWxdzASRHkjOFwVA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yO-OCNRiISNdCb_iVi4E_w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","mBpjyQvq6ftE7Wm1BUpcFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAP3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAADSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yp8MidCGMe4czbl-NigsYQAAAAAAAOFG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2noK4QoWxdzASRHkjOFwVAAAAAAAAMn6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yO-OCNRiISNdCb_iVi4E_wAAAAAAAOkg","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpnr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAKGy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpW8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkLQ"],"type_ids":[3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3]},"8Rif7kuKG2cfhEYF2fJXmA":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,18066,2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,53890,2789627,1482889,1482415,2595076,1073425,41996,2567913,1848405,1837592,1847724,1483518,1482415,2595076,1079144,6526,35438,63996,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,48638,2790352,1482889,1482415,2595076,1079485,45806,47864,20848,32520,56166,1479516,1828960,2573747,2594708,1091475,0,2789548,1848405,1837592,1848026,1002720],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","bcwppGWOjTWw86zVNJE_Jg","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NiCfOMPggzUjx-usqlmxvg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","Vot4T3F5OpUj8rbXhgpMDg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEaS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAANKC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","Npep8JfxWDWZ3roJSD7jPgAAAAAAAKQM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDGs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","bcwppGWOjTWw86zVNJE_JgAAAAAAABl-","TBeSzkyqIwKL8td602zDjAAAAAAAAIpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAAPn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NiCfOMPggzUjx-usqlmxvgAAAAAAAL3-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","Vot4T3F5OpUj8rbXhgpMDgAAAAAAAH8I","eV_m28NnKeeTL60KO2H3SAAAAAAAANtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpCs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDLa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD0zg"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3]},"cCjn5miDmyezrnBAe2jDww":{"address_or_lines":[1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,46938,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,15022,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,57678,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,1870,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1079669,19486,1482046,1829360,2586325,1480953,1480561,1940968,1986928],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","5nuRo5ZVtij8bTLlri7QXA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","hi5mlwAHRj-Yl1GNV_UEZQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uSWUCgHgLPG4OFtPdUp0rg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","-BjW54fwMksXBor9R-YN9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","wuSmWRANn3Cl-syjEtxMoQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","5nuRo5ZVtij8bTLlri7QXAAAAAAAALda","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","hi5mlwAHRj-Yl1GNV_UEZQAAAAAAADqu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAOFO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","-BjW54fwMksXBor9R-YN9wAAAAAAAAdO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","wuSmWRANn3Cl-syjEtxMoQAAAAAAAEwe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFw"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"f8AFYpSQOpjCNbhqUuR3Rg":{"address_or_lines":[2578675,2599636,1091600,13686,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,50302,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,31414,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,43062,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,38710,2795776,1483241,1482767,2600004,1079483,31822,33880,6648,14264,54464,42150,1479868,1829983,2783616,2800188,3063028,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,37650],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rEbhXoMLMee0rf6bwU9RPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","pv4wAezdMMO0SVuGgaEMTgAAAAAAADV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAMR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAHq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAKg2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","rEbhXoMLMee0rf6bwU9RPwAAAAAAAJc2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABn4","0S3htaCNkzxOYeavDR1GTQAAAAAAADe4","rBzW547V0L_mH4nnWK1FUQAAAAAAANTA","eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKnmA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKro8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALrz0","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJMS"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"dGMvgpGXk-ajX6PRi92qdg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,17442,33388,19218,62806,476,52596,11060,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,16746,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,23102,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,13424,27494,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1592,33110,55262,3227220,1488310,1480209,1940568,3236384],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","z1-LQiSwGmfJHZm7Q223fQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAM10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAEFq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","z1-LQiSwGmfJHZm7Q223fQAAAAAAAFo-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANfe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMT5U","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFrW2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWIg"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3]},"OxrG9ZVAzX9GwGtxUtIQNg":{"address_or_lines":[51762,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,64822,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,45750,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,58410,2795776,1483241,1482767,2600004,1073803,40014,42072,15024,49260,33110,13026,2852079,2851771,2849353,2846190,2849353,2846190,2849408,2846190,2848321,2268450,1775400,1761695,1048471],"file_ids":["xDXQtI2vA5YySwpx7QFiwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fSQ747oLNh0c0zFQjsVRWg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yp8MidCGMe4czbl-NigsYQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2noK4QoWxdzASRHkjOFwVA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xDXQtI2vA5YySwpx7QFiwAAAAAAAAMoy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fSQ747oLNh0c0zFQjsVRWgAAAAAAAP02","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yp8MidCGMe4czbl-NigsYQAAAAAAALK2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2noK4QoWxdzASRHkjOFwVAAAAAAAAOQq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3qA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3ZB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIp0i","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGxco","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGuGf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAD_-X"],"type_ids":[1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"QoW8uF5K3OBNL2DXI66leA":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,44118,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,32266,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,0,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959065,1765320],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Z-J8GEZK5aE8XNQ-3sO-Fg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","H-OlnUNurKAlPjkWfV0hTg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","Z-J8GEZK5aE8XNQ-3sO-FgAAAAAAAKxW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","H-OlnUNurKAlPjkWfV0hTgAAAAAAAH4K","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_I"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3]},"zV-93oQDbZK9zB7UMAcCmw":{"address_or_lines":[1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,38166,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,63374,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,12690,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1062336,11500,1844695,1837592,1847724,1483518,1482415,2595076,1079144,40398,15390,8700,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1079485,41710,43252,52070,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1072909,41710,43768,16752,18098,34934,1898256],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","pv4wAezdMMO0SVuGgaEMTg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","qns5vQ3LMi6QrIMOgD_TwQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J_Lkq1OzUHxWQhnTgF6FwA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","hrIwGgdEFsOBluJKOOs8Zg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","jhRfowFriqBKJWhZSTe7kg","B0e_Spx899MeGx2KSvzzow","v1UMuiFodNtdRCNi4iF0Rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","yzJdtc2TQHpJ_IY5QdUQKA","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","pv4wAezdMMO0SVuGgaEMTgAAAAAAAJUW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAPeO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAADGS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","hrIwGgdEFsOBluJKOOs8ZgAAAAAAACzs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDGs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","jhRfowFriqBKJWhZSTe7kgAAAAAAAJ3O","B0e_Spx899MeGx2KSvzzowAAAAAAADwe","v1UMuiFodNtdRCNi4iF0RgAAAAAAACH8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAMtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF8N","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEay","yzJdtc2TQHpJ_IY5QdUQKAAAAAAAAIh2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHPcQ"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,3]},"9CQVJEfCfL1rSnUaxlAfqg":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,2830,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,16862,2789627,1482889,1482415,2595076,1079485,9328,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,7050,1481694,1828960,2581297,2595076,1079144,21502,39750,29852,29250,6740,37336,26240,24712,1480209,1940568,1934986,1933934,3072096,3066615,1918105,1787434,3064390],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","q_M8ZB6aihtZKYZfHGkluQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MAFaasFcVIeoQsejXrnp0w","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","zpgqltXEgKujOhJUj-jAhg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAAEHe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","q_M8ZB6aihtZKYZfHGkluQAAAAAAABuK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","MAFaasFcVIeoQsejXrnp0wAAAAAAAFP-","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAGaA","zpgqltXEgKujOhJUj-jAhgAAAAAAAGCI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHYaK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHYJu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsr3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG0Yq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsJG"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"mGGvLNOYB74ofk9FRrMxxQ":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,17196,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,38014,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,62622,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1073803,35918,37976,10928,49260,33110,13026,2852079,2851771,2849353,2846190,2849443,2846638,1439925,1865540],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ihsoi5zicXHpPrWRA9bTnA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","HbU9j_4D3UaJfjASj-JljA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","awUBhCYYZvWyN4rrVw-u5A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","ihsoi5zicXHpPrWRA9bTnAAAAAAAAEMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","HbU9j_4D3UaJfjASj-JljAAAAAAAAJR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","awUBhCYYZvWyN4rrVw-u5AAAAAAAAPSe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3qj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHdE"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3]},"pnLCuJVNeqGwwFeJQIrkPw":{"address_or_lines":[2795776,1483241,1482767,2600004,1079483,52302,53844,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079483,52302,53844,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1091600,63066,2795051,1483241,1482767,2600004,1079483,48592,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1091600,62622,2795051,1483241,1482767,2600004,1079483,48592,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1079669,27496,1482046,1829360,2586325,1480953,1480561,1940968,1986911,1982943],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","akZOzI9XwsEixvkTDGeDPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","d1LNRHMzWQ5PvB10hYiN3g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PmkUsVBZlaSEgaFwCOKZlg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","akZOzI9XwsEixvkTDGeDPwAAAAAAAPZa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","d1LNRHMzWQ5PvB10hYiN3gAAAAAAAPSe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","PmkUsVBZlaSEgaFwCOKZlgAAAAAAAGto","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkHf"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3]},"R77Zz6fBvENVXyt4GVb9dQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,94,6,108,36,24,4,28,693765,935741],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","4xH83ZXxs_KV95Ur8Z59WQ","PWlQ4X4jsNu5q7FFJqlo_Q","LSxiso_u1cO_pWDBw25Egg","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAABe","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAk","4xH83ZXxs_KV95Ur8Z59WQAAAAAAAAAY","PWlQ4X4jsNu5q7FFJqlo_QAAAAAAAAAE","LSxiso_u1cO_pWDBw25EggAAAAAAAAAc","G68hjsyagwq6LpWrMjDdngAAAAAACpYF","G68hjsyagwq6LpWrMjDdngAAAAAADkc9"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"tgL-t2GJJjItpLjnwjc4zQ":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,40902,49932,35316,46628,9712,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,40322,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,6862,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,45714,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20588,33110,49802,19187,41240,51007],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","f3fxdcTCg7rbloZ6VtA0_Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAJ_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAAMMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAIn0","xwuAPHgc12-8PZB3i-320gAAAAAAALYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAJ2C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAABrO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","f3fxdcTCg7rbloZ6VtA0_QAAAAAAALKS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMc_"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"XNCSlgkv_bOXDIYn6zwekw":{"address_or_lines":[2578675,2599636,1091600,10822,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1091600,40982,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1091600,6678,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1074067,39072,35338,13252,2577481,2934013,1108250,1105981,1310350,1245864,1200348,1190613,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165561,1146206,1245475,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165783,1162744,1226823,1225457,1224431,1198830,1177316,1176308,1173405,1172510,1172373,1102592],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uU7rISh8R_xr6YYB3RgLuA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","vQQdLrWHLywJs9twt3EH2Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PUIH740KQXWx70DXM4ZvgQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","dsOcslker2-lnNTIC5yERA","zUlsQG278t98_u2KV_JLSQ","vkeP2ntYyoFN0A16x9eliw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uU7rISh8R_xr6YYB3RgLuAAAAAAAACpG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","vQQdLrWHLywJs9twt3EH2QAAAAAAAKAW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","PUIH740KQXWx70DXM4ZvgQAAAAAAABoW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGOT","dsOcslker2-lnNTIC5yERAAAAAAAAJig","zUlsQG278t98_u2KV_JLSQAAAAAAAIoK","vkeP2ntYyoFN0A16x9eliwAAAAAAADPE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1RJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALMT9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOA9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAE_6O","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwKo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAElDc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEirV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEX1e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwEj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcnX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEb34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErhH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErLx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEq7v","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeQe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeOV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAENMA"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"jPN_jNGPJguImYjakYlBcA":{"address_or_lines":[19534,21592,60080,53572,2578675,2599636,1091600,12394,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,53572,2578675,2599636,1091600,39546,2795776,1483241,1482767,2600004,1079669,19534,21418,26368,41208,8202,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,34238,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,53572,2578675,2599636,1091600,33554,2795776,1483241,1482767,2600004,1073803,19534,21592,60080,53356,33110,17122,2852079,2851771,2849353,2846190,2849353,2846190,2849353,2846190,2845695,2033924,2033070,1865524],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAADBq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAJp6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4","h0l-9tGi18mC40qpcJbyDwAAAAAAACAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAIW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAIMS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2v_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHwkE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHwWu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHc0"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"4K-SlZ4j8NjsVBpqyPj2dw":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,6714,2790352,1482889,1482415,2595076,1079144,29422,31306,36256,31544,18122,5412,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,54286,19054,47612,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,60034,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,64446,2790352,1482889,1482415,2595076,1079485,29422,31480,4280,11896,52064,39782,1479516,1829583,2778192,2794764,3057572,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,37750],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zo4mnjDJ1PlZka7jS9k2BA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAABo6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO","TBeSzkyqIwKL8td602zDjAAAAAAAAEpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J3wpF3Lf_vPkis4aNGKFbwAAAAAAAOqC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPu-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABC4","0S3htaCNkzxOYeavDR1GTQAAAAAAAC54","rBzW547V0L_mH4nnWK1FUQAAAAAAAMtg","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKmRQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKqUM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALqek","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJN2"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"W8IRlEZMfFJdYSgUQXDnMg":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,72,38,174,104,68,88,38,174,104,68,124,38,38,10,38,174,104,68,72,38,174,104,68,120,38,174,104,68,276,6,108,20,50,50,2970,50,2970,50,1360,24,788130,1197115,1222867,1212996,1212720],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qkYSh95E1urNTie_gKbr7w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","V8ldXm9NGXsJ182jEHEsUw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xVaa0cBWNcFeS-8zFezQgA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","UBINlIxj95Sa_x2_k5IddA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gRRk0W_9P4SGZLXFJ5KU8Q","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","cbxfeE2AkqKne6oKUxdB6g","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","iLW1ehST1pGQ3S8RoqM9Qg","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qkYSh95E1urNTie_gKbr7wAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAEU","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU","cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAVQ","iLW1ehST1pGQ3S8RoqM9QgAAAAAAAAAY","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAEqjT","G68hjsyagwq6LpWrMjDdngAAAAAAEoJE","G68hjsyagwq6LpWrMjDdngAAAAAAEoEw"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3]},"qytuJG9brvKSB9NJCHV9fQ":{"address_or_lines":[1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,45506,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,10626,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,54118,2795776,1483241,1482767,2600004,1073803,23630,25688,64176,53356,16726,17122,2852079,2851771,2849353,2846190,2849353,2846190,2849762,2846638,1439925,1865641,10490014,423063,2284223,2281903,2098884,2098647,2097658],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","9NWoah56eYULAP_zGE9Puw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IKrIDHd5n47PpDQsRXxvvg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oG7568kMJujZxPJfj7VMjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","9NWoah56eYULAP_zGE9PuwAAAAAAALHC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","IKrIDHd5n47PpDQsRXxvvgAAAAAAACmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","oG7568kMJujZxPJfj7VMjAAAAAAAANNm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3vi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHep","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnSX","ew01Dk0sWZctP-VaEpavqQAAAAAAItq_","ew01Dk0sWZctP-VaEpavqQAAAAAAItGv","ew01Dk0sWZctP-VaEpavqQAAAAAAIAbE","ew01Dk0sWZctP-VaEpavqQAAAAAAIAXX","ew01Dk0sWZctP-VaEpavqQAAAAAAIAH6"],"type_ids":[3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"b116myovN7_XXb1AVLPH0g":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,21010,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,32886,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52386,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1097633,38284,39750,58524,57922,35412,472,59182,472,59182,472,59182,472,59182,472,55416,2915906,959782,10485923,16807,2315878,2315735,2315122,2305825,2551628],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAFIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAIB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAMyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEL-h","MsEmysGbXhMvgdbwhcZDCgAAAAAAAJWM","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAOSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAOJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAIpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAANh4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALH5C","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADqUm","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAI1Zm","A2oiHVwisByxRn5RDT4LjAAAAAAAI1XX","A2oiHVwisByxRn5RDT4LjAAAAAAAI1Ny","A2oiHVwisByxRn5RDT4LjAAAAAAAIy8h","A2oiHVwisByxRn5RDT4LjAAAAAAAJu9M"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,4,4,4,4,4,4,4]},"dNwgDmnCM1dIIF5EZm4ZgA":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,132,38,174,104,68,16,38,38,10,38,174,104,68,4,38,174,104,68,8,38,38,10,38,38,10,38,174,104,68,16,140,10,38,174,104,68,20,140,10,38,174,104,68,92,1090933,1814182,788459,788130,1197048,1243240,1238413,1212345,1033898,428752],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iwnHqwtnoHjA-XW01rxhpw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","53nvYhJfd2eJh-qREaeFBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zwRZ32H5_95LpRJHzXkqVA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","JJab8JrsPDK66yfOtCG3zQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1XUiDryPjyncBxkTlbVecg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OIy8IFqaTWz5UoN3FSH-wQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iwnHqwtnoHjA-XW01rxhpwAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","53nvYhJfd2eJh-qREaeFBQAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zwRZ32H5_95LpRJHzXkqVAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","JJab8JrsPDK66yfOtCG3zQAAAAAAAAAQ","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1XUiDryPjyncBxkTlbVecgAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OIy8IFqaTWz5UoN3FSH-wQAAAAAAAABc","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvho","G68hjsyagwq6LpWrMjDdngAAAAAAEuWN","G68hjsyagwq6LpWrMjDdngAAAAAAEn-5","G68hjsyagwq6LpWrMjDdngAAAAAAD8aq","G68hjsyagwq6LpWrMjDdngAAAAAABorQ"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"KEdXtWOmrUdpIHsjndtg_A":{"address_or_lines":[13038,15096,53616,1756,2573747,2594708,1091475,37514,2789627,1482889,1482415,2595076,1079485,9328,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,33834,2790352,1482889,1482415,2595076,1079144,13038,14922,19872,15160,1738,54564,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,37902,2670,31228,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,20530,2790352,1482889,1482415,2595076,1076587,13038,15096,53616,1592,16726,2434,2846655,2846347,2843929,2840766,2843929,2840766,2844278,2841214,1439429,1865241,10489950,423063,2283967,2281306,2510155,2414579,2398792,2385273,8471622],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAJKK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAIQq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAE2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAADs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAAbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAANUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAAJQO","TBeSzkyqIwKL8td602zDjAAAAAAAAApu","NH3zvSjFAfTSy6bEocpNyQAAAAAAAHn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J3wpF3Lf_vPkis4aNGKFbwAAAAAAAFAy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAAmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Z2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a","A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L","A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz","A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI","A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5","A2oiHVwisByxRn5RDT4LjAAAAAAAgURG"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"V2K_ZjA6rol7KyINtV45_A":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,178,1090933,1814182,788459,788130,1197048,1243204,1201241,1245991,1245236,1171829,2265239,2264574,2258463,922614,2256180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAACy","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvhE","G68hjsyagwq6LpWrMjDdngAAAAAAElRZ","G68hjsyagwq6LpWrMjDdngAAAAAAEwMn","G68hjsyagwq6LpWrMjDdngAAAAAAEwA0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAADhP2","G68hjsyagwq6LpWrMjDdngAAAAAAIm00"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEVjp":{"file_name":[],"function_name":["__x64_sys_nanosleep"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEPyZ":{"file_name":[],"function_name":["get_timespec64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAASf5k":{"file_name":[],"function_name":["_copy_from_user"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEqRj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEpne":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKpz6":{"file_name":[],"function_name":["pipe_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAASkaN":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAShYf":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAL1uY":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAL1DP":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv-O":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL10T":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgiGX":{"file_name":[],"function_name":["__mutex_lock.isra.7"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADkms":{"file_name":[],"function_name":["mutex_spin_on_owner"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEH6":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAD_e":{"file_name":[],"function_name":["syscall_slow_exit_work"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAFX1-":{"file_name":[],"function_name":["__audit_syscall_exit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv1p":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKhyy":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKhiZ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJwne":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKMb4":{"file_name":[],"function_name":["memcg_kmem_get_cache"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg38":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKePq":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePaV":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL":{"file_name":[],"function_name":["sock_def_readable"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgljd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgEg":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKf4s":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdQa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd--h":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZdo2":{"file_name":[],"function_name":["sock_alloc_send_pskb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlap":{"file_name":[],"function_name":["alloc_skb_with_frags"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJMoT":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIxI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnbb":{"file_name":[],"function_name":["sock_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQGt0":{"file_name":[],"function_name":["security_socket_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYaV":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAchuU":{"file_name":[],"function_name":["tcp_rcv_space_adjust"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAANci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAALhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAM58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABgW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAOzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAE8a":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAP8W":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"DxQN3aM1Ddn1lUwovx75wQAAAAAAACls":{"file_name":["client.py"],"function_name":["_load_service_endpoints_ruleset"],"function_offset":[1],"line_number":[193]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAHQg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAALtQ":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK":{"file_name":[],"function_name":["kmem_cache_alloc_node"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_connect"],"function_offset":[],"line_number":[345]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhXY":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_get_server_certificate"],"function_offset":[],"line_number":[1234]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[266]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_ex_d2i"],"function_offset":[],"line_number":[235]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBnG":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[380]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABylm":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/objects/obj_lib.c"],"function_name":["OBJ_dup"],"function_offset":[],"line_number":[83]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/mem.c"],"function_name":["CRYPTO_malloc"],"function_offset":[],"line_number":[346]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3068]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB813":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["_int_malloc"],"function_offset":[],"line_number":[3995]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKZlu":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABtuk":{"file_name":[],"function_name":["__virt_addr_valid"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J":{"file_name":[],"function_name":["do_softirq_own_stack"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-":{"file_name":[],"function_name":["process_backlog"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU":{"file_name":[],"function_name":["__netif_receive_skb_one_core"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb":{"file_name":[],"function_name":["ip_rcv"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcHvM":{"file_name":[],"function_name":["ip_forward"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLse":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbiYT":{"file_name":[],"function_name":["__qdisc_run"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbiIt":{"file_name":[],"function_name":["sch_direct_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"5OhlekN4HU3KaqhG_GtinAAAAAAAADWR":{"file_name":[],"function_name":["ena_start_xmit"],"function_offset":[],"line_number":[]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBmx":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[377]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_item_new"],"function_offset":[],"line_number":[76]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF5m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["asn1_item_ex_combine_new"],"function_offset":[],"line_number":[179]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-Ww":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3031]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeO8U":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ1ga":{"file_name":[],"function_name":["consume_skb"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ1A9":{"file_name":[],"function_name":["skb_release_all"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ0_v":{"file_name":[],"function_name":["skb_release_head_state"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeR6K":{"file_name":[],"function_name":["unix_destruct_scm"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZujP":{"file_name":[],"function_name":["sock_wfree"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeNEG":{"file_name":[],"function_name":["unix_write_space"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAglVt":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoApO":{"file_name":[],"function_name":["ret_from_intr"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBzi":{"file_name":[],"function_name":["do_IRQ"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACO-_":{"file_name":[],"function_name":["irq_exit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaQZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAAFQg":{"file_name":[],"function_name":["ena_io_poll"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaQFc":{"file_name":[],"function_name":["napi_complete_done"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaPMo":{"file_name":[],"function_name":["gro_normal_list.part.132"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaPED":{"file_name":[],"function_name":["netif_receive_skb_list_internal"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaO8W":{"file_name":[],"function_name":["__netif_receive_skb_list_core"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHjA":{"file_name":[],"function_name":["ip_list_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHKv":{"file_name":[],"function_name":["ip_sublist_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcGmO":{"file_name":[],"function_name":["ip_sublist_rcv_finish"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHZY":{"file_name":[],"function_name":["ip_local_deliver"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHXT":{"file_name":[],"function_name":["ip_local_deliver_finish"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHQq":{"file_name":[],"function_name":["ip_protocol_deliver_rcu"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAczxz":{"file_name":[],"function_name":["tcp_v4_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcyj0":{"file_name":[],"function_name":["tcp_v4_do_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcmQN":{"file_name":[],"function_name":["tcp_rcv_state_process"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAck58":{"file_name":[],"function_name":["tcp_data_queue"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcj1B":{"file_name":[],"function_name":["tcp_fin"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAco-Y":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcM8h":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcNR4":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcKvQ":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaMse":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAbjZz":{"file_name":[],"function_name":["__qdisc_run"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAbjKN":{"file_name":[],"function_name":["sch_direct_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaMaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAADVS":{"file_name":[],"function_name":["ena_start_xmit"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAJci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAAw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAI3-":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAANtO":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAAGqM":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAL60":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAABis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAKx8":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAANMc":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"3FRCbvQLPuJyn2B-2wELGwAAAAAAANK8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[527]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAACEw":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAGla":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAHDM":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAC7S":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"7RLN3PNgotUSmdQVMRTSvAAAAAAAAMnE":{"file_name":["_bootstrap.py"],"function_name":["exec_module"],"function_offset":[5],"line_number":[982]},"43vJVfBcAahhLMzDSC-H0gAAAAAAADOC":{"file_name":["util.py"],"function_name":[""],"function_offset":[266],"line_number":[267]},"ik6PIX946fW_erE7uBJlVQAAAAAAAIJy":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"RRFdsCrJw1U2erb6qtrrzQAAAAAAAMNe":{"file_name":["_bootstrap.py"],"function_name":["__enter__"],"function_offset":[2],"line_number":[171]},"_zH-ed4x-42m0B4z2RmcdQAAAAAAALN-":{"file_name":["_bootstrap.py"],"function_name":["_get_module_lock"],"function_offset":[34],"line_number":[213]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4":{"file_name":["application.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0":{"file_name":["application.py"],"function_name":["Application"],"function_offset":[91],"line_number":[206]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[18],"line_number":[155]},"7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW":{"file_name":["typing.py"],"function_name":["_type_convert"],"function_offset":[4],"line_number":[132]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAMbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAEQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAJ9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAAGh4":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAB2m":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAPns":{"file_name":["client.py"],"function_name":["_get_client_args"],"function_offset":[15],"line_number":[295]},"qLiwuFhv6DIyQ0OgaSMXCgAAAAAAAFnm":{"file_name":["args.py"],"function_name":["get_client_args"],"function_offset":[72],"line_number":[118]},"ka2IKJhpWbD6PA3J3v624wAAAAAAALgG":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"e8Lb_MV93AH-OkvHPPDitgAAAAAAAEzS":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[6],"line_number":[344]},"1vivUE5hL65442lQ9a_ylgAAAAAAAIYC":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[8],"line_number":[486]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK0u":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fCsVLBj60GK9Hf8VtnMcgAAAAAAAALX8":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[5],"line_number":[35]},"ka2IKJhpWbD6PA3J3v624wAAAAAAALd2":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"cfc92_adXFZraMPGbgbcDgAAAAAAANvu":{"file_name":["pyi_rth_inspect.py"],"function_name":[""],"function_offset":[43],"line_number":[44]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"WLefmNR3IpykzCX3WWNnMwAAAAAAAEIO":{"file_name":["inspect.py"],"function_name":[""],"function_offset":[1707],"line_number":[1708]},"IvJrzqPEgeoowZySdwFq3wAAAAAAAEAo":{"file_name":["dis.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"vkeP2ntYyoFN0A16x9eliwAAAAAAAF8U":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAI4g":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":[""],"function_offset":[13],"line_number":[14]},"ecHSwk0KAG7gFkiYdAgIZwAAAAAAAFTg":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":["_pyi_rth_multiprocessing"],"function_offset":[94],"line_number":[107]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAo":{"file_name":["client.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"0cqvso24v07beLsmyC0nMwAAAAAAAABQ":{"file_name":["args.py"],"function_name":[""],"function_offset":[15],"line_number":[28]},"3WU6MO1xF7O0NmrHFj4y4AAAAAAAAAA8":{"file_name":["regions.py"],"function_name":[""],"function_offset":[12],"line_number":[25]},"x617yDiAG2Sqq3cLDkX4aAAAAAAAAAF-":{"file_name":["auth.py"],"function_name":[""],"function_offset":[660],"line_number":[674]},"ZTmztUywGW_uHXPqWVr76wAAAAAAAAAY":{"file_name":["auth.py"],"function_name":[""],"function_offset":[3],"line_number":[17]},"ZPAF8mJO2n0azNbxzkJ2rAAAAAAAAAAc":{"file_name":["auth.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAA4g":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":[""],"function_offset":[13],"line_number":[14]},"ecHSwk0KAG7gFkiYdAgIZwAAAAAAAKTg":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":["_pyi_rth_multiprocessing"],"function_offset":[94],"line_number":[107]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAMRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAPtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAGs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAADDC":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"SOSrvCNmbstVFKAcqHNCvAAAAAAAAMF-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[89],"line_number":[90]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAI_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAALMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAANxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAI3K":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"SD7uzoegJjRT3jYNpuQ5wQAAAAAAALX2":{"file_name":["configure.py"],"function_name":[""],"function_offset":[56],"line_number":[57]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAEBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjj":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcK5W":{"file_name":[],"function_name":["tcp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcKWq":{"file_name":[],"function_name":["tcp_sendmsg_locked"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcbOh":{"file_name":[],"function_name":["__tcp_push_pending_frames"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcaTc":{"file_name":[],"function_name":["tcp_write_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcY0Y":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb80x":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb9KI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb6ng":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ8uJ":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ8Dc":{"file_name":[],"function_name":["validate_xmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ793":{"file_name":[],"function_name":["netif_skb_features"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ7qG":{"file_name":[],"function_name":["skb_network_protocol"],"function_offset":[],"line_number":[]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAGQ":{"file_name":["application.py"],"function_name":[""],"function_offset":[58],"line_number":[59]},"c-eM3dWacIPzBmA_7-OWBwAAAAAAAAAU":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"w9AQfBE7-1YeE4mOMirPBgAAAAAAAABY":{"file_name":["basic.py"],"function_name":[""],"function_offset":[13],"line_number":[15]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAETO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABka":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAOxq":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAEu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAALya":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAGsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAPZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAABZ2":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAIY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAADjQ":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAACxq":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAANeQ":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAE6e":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAC8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAP7M":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"r1l-BTVp1g6dSvPPoOY_cgAAAAAAAHDY":{"file_name":["typing.py"],"function_name":["__new__"],"function_offset":[55],"line_number":[2965]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[32],"line_number":[33]},"IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8":{"file_name":["auto_suggest.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"tz0ps4QDYR1clO_q5ziJUQAAAAAAAABi":{"file_name":["document.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"M0gS5SrmklEEjlV4jbSIBAAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"k5C4r96b77lEZ_fHFwCYkQAAAAAAAAAk":{"file_name":["app.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[16],"line_number":[302]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAOrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAHAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAMdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAANCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAJ-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAKsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAADZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAAfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAACBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAABMg":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"wXOyVgf5_nNg6CUH5kFBbgAAAAAAAJkK":{"file_name":["loaders.py"],"function_name":[""],"function_offset":[0],"line_number":[273]},"zEgDK4qMawUAQZjg5YHywwAAAAAAAIC0":{"file_name":["genericpath.py"],"function_name":["isdir"],"function_offset":[6],"line_number":[45]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAACHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAOs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAADLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAANFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAGFG":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAFUm":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"X0TUmWpd8saA6nnPGQi3nQAAAAAAAPKS":{"file_name":["addsteps.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAACQM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAPQ6":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAKys":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAPB6":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAE1M":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAAFis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"rTFMSHhLRlj86vHPR06zoQAAAAAAANRm":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKTS":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"-T5rZCijT5TDJjmoEi8KxgAAAAAAABP8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[533]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAEDg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAG-k":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKycK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKv55":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKh3C":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhna":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQFXl":{"file_name":[],"function_name":["security_file_alloc"],"function_offset":[],"line_number":[]},"tz0ps4QDYR1clO_q5ziJUQAAAAAAAABW":{"file_name":["document.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"O2RGJIowquMzuET0HYQ6aQAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"Ht79I_xqXv3bOgaClTNQ4wAAAAAAAALK":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[131],"line_number":[310]},"T8-enlAkCZXqinPHW4B8swAAAAAAAAAi":{"file_name":["enum.py"],"function_name":["__setattr__"],"function_offset":[11],"line_number":[473]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAMDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAMn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAALYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAH2W":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAB8C":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAG3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"fDiQPd_MeGeyY9ZBOSU1GgAAAAAAAJ7g":{"file_name":["hashes.py"],"function_name":[""],"function_offset":[245],"line_number":[246]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAAPDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAACOi":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"b-3iFnlA7BmzAxDEzxShdAAAAAAAACGi":{"file_name":["config.py"],"function_name":[""],"function_offset":[24],"line_number":[25]},"8jcOoolAg5RmmHop7NqzWQAAAAAAAC4-":{"file_name":["endpoint.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"2LABj1asXFICsosP2OrbVQAAAAAAAO82":{"file_name":["hooks.py"],"function_name":["httpchecksum"],"function_offset":[67],"line_number":[68]},"N1ZmsCOKFJHNThnHfFYo6QAAAAAAAMEC":{"file_name":["hooks.py"],"function_name":["HierarchicalEmitter"],"function_offset":[155],"line_number":[321]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe":{"file_name":[],"function_name":["page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnL3":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAO4-":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAJ2i":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"-gDCCFjiBc58_iqAxti3KwAAAAAAAL70":{"file_name":["argparse.py"],"function_name":[""],"function_offset":[817],"line_number":[818]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItCv":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIAXE":{"file_name":[],"function_name":["__lru_cache_add"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIATK":{"file_name":[],"function_name":["pagevec_lru_move_fn"],"function_offset":[],"line_number":[]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAJd-":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"d4jl580PLMUwu5s3I4wcXgAAAAAAAMSu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"tKago5vqLnwIkezk_wTBpQAAAAAAACga":{"file_name":["package.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"rpq4cV1KPyFZcnKfWjKdZwAAAAAAAHr2":{"file_name":["s3uploader.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"uFElJcsK9my-kA6ZYzT1uwAAAAAAABOG":{"file_name":["manager.py"],"function_name":[""],"function_offset":[46],"line_number":[47]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAP3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"yp8MidCGMe4czbl-NigsYQAAAAAAAOFG":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAAMn6":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"yO-OCNRiISNdCb_iVi4E_wAAAAAAAOkg":{"file_name":["shutil.py"],"function_name":[""],"function_offset":[2003],"line_number":[2004]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAKGy":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"ik6PIX946fW_erE7uBJlVQAAAAAAALLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEaS":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"OlTvyWQFXjOweJcs3kiGygAAAAAAANKC":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAKQM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"bcwppGWOjTWw86zVNJE_JgAAAAAAABl-":{"file_name":["six.py"],"function_name":["__get__"],"function_offset":[9],"line_number":[104]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAPn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"NiCfOMPggzUjx-usqlmxvgAAAAAAAL3-":{"file_name":["queue.py"],"function_name":[""],"function_offset":[62],"line_number":[63]},"Vot4T3F5OpUj8rbXhgpMDgAAAAAAAH8I":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[4],"line_number":[938]},"eV_m28NnKeeTL60KO2H3SAAAAAAAANtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"5nuRo5ZVtij8bTLlri7QXAAAAAAAALda":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[29],"line_number":[30]},"hi5mlwAHRj-Yl1GNV_UEZQAAAAAAADqu":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[30],"line_number":[31]},"uSWUCgHgLPG4OFtPdUp0rgAAAAAAAOFO":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"-BjW54fwMksXBor9R-YN9wAAAAAAAAdO":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[575],"line_number":[576]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAALSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wuSmWRANn3Cl-syjEtxMoQAAAAAAAEwe":{"file_name":["ec.py"],"function_name":[""],"function_offset":[339],"line_number":[340]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAADV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAMR-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAHq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAKg2":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"rEbhXoMLMee0rf6bwU9RPwAAAAAAAJc2":{"file_name":["hashlib.py"],"function_name":[""],"function_offset":[300],"line_number":[301]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABn4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAADe4":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAANTA":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["__dlopen"],"function_offset":[],"line_number":[87]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlerror.c"],"function_name":["_dlerror_run"],"function_offset":[],"line_number":[163]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-error-skeleton.c"],"function_name":["__GI__dl_catch_error"],"function_offset":[],"line_number":[198]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["dlopen_doit"],"function_offset":[],"line_number":[66]},"3nN3bymnZ8E42aLEtgglmAAAAAAAASmo":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["_dl_open"],"function_offset":[],"line_number":[649]},"3nN3bymnZ8E42aLEtgglmAAAAAAAATA-":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[424]},"3nN3bymnZ8E42aLEtgglmAAAAAAAALbA":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-reloc.c"],"function_name":["_dl_relocate_object"],"function_offset":[],"line_number":[160]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["_dl_lookup_symbol_x"],"function_offset":[],"line_number":[833]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJMS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x"],"function_offset":[],"line_number":[413]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAM10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAEFq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"z1-LQiSwGmfJHZm7Q223fQAAAAAAAFo-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANfe":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"xDXQtI2vA5YySwpx7QFiwAAAAAAAAMoy":{"file_name":["popen_forkserver.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fSQ747oLNh0c0zFQjsVRWgAAAAAAAP02":{"file_name":["forkserver.py"],"function_name":[""],"function_offset":[80],"line_number":[81]},"yp8MidCGMe4czbl-NigsYQAAAAAAALK2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAAOQq":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"Z-J8GEZK5aE8XNQ-3sO-FgAAAAAAAKxW":{"file_name":["adaptive.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"H-OlnUNurKAlPjkWfV0hTgAAAAAAAH4K":{"file_name":["standard.py"],"function_name":[""],"function_offset":[279],"line_number":[280]},"ik6PIX946fW_erE7uBJlVQAAAAAAAKLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAAJUW":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAPeO":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAADGS":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"hrIwGgdEFsOBluJKOOs8ZgAAAAAAACzs":{"file_name":["docstringparser.py"],"function_name":[""],"function_offset":[172],"line_number":[173]},"jhRfowFriqBKJWhZSTe7kgAAAAAAAJ3O":{"file_name":["six.py"],"function_name":["__get__"],"function_offset":[9],"line_number":[100]},"B0e_Spx899MeGx2KSvzzowAAAAAAADwe":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[115]},"v1UMuiFodNtdRCNi4iF0RgAAAAAAACH8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[83]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEay":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"yzJdtc2TQHpJ_IY5QdUQKAAAAAAAAIh2":{"file_name":["posixpath.py"],"function_name":["dirname"],"function_offset":[8],"line_number":[158]},"VuJFonCXevADcEDW6NVbKgAAAAAAAGsG":{"file_name":["devcommands.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAAEHe":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"q_M8ZB6aihtZKYZfHGkluQAAAAAAABuK":{"file_name":["core.py"],"function_name":[""],"function_offset":[331],"line_number":[332]},"MAFaasFcVIeoQsejXrnp0wAAAAAAAFP-":{"file_name":["core.py"],"function_name":["TemplateStep"],"function_offset":[40],"line_number":[240]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAGaA":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zpgqltXEgKujOhJUj-jAhgAAAAAAAGCI":{"file_name":["_parser.py"],"function_name":["__getitem__"],"function_offset":[3],"line_number":[165]},"ihsoi5zicXHpPrWRA9bTnAAAAAAAAEMs":{"file_name":["base_events.py"],"function_name":[""],"function_offset":[190],"line_number":[191]},"HbU9j_4D3UaJfjASj-JljAAAAAAAAJR-":{"file_name":["staggered.py"],"function_name":[""],"function_offset":[1],"line_number":[2]},"awUBhCYYZvWyN4rrVw-u5AAAAAAAAPSe":{"file_name":["locks.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"akZOzI9XwsEixvkTDGeDPwAAAAAAAPZa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"d1LNRHMzWQ5PvB10hYiN3gAAAAAAAPSe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"PmkUsVBZlaSEgaFwCOKZlgAAAAAAAGto":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[166],"line_number":[167]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAABe":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[28],"line_number":[33]},"VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG":{"file_name":["re.py"],"function_name":["compile"],"function_offset":[2],"line_number":[252]},"SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs":{"file_name":["re.py"],"function_name":["_compile"],"function_offset":[15],"line_number":[304]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAk":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[9],"line_number":[768]},"4xH83ZXxs_KV95Ur8Z59WQAAAAAAAAAY":{"file_name":["sre_compile.py"],"function_name":["_code"],"function_offset":[6],"line_number":[604]},"PWlQ4X4jsNu5q7FFJqlo_QAAAAAAAAAE":{"file_name":["sre_compile.py"],"function_name":["_compile_info"],"function_offset":[4],"line_number":[540]},"LSxiso_u1cO_pWDBw25EggAAAAAAAAAc":{"file_name":["sre_parse.py"],"function_name":["getwidth"],"function_offset":[5],"line_number":[179]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJ_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAMMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAIn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAJ2C":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAABrO":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"f3fxdcTCg7rbloZ6VtA0_QAAAAAAALKS":{"file_name":["hbase.py"],"function_name":[""],"function_offset":[96],"line_number":[97]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"uU7rISh8R_xr6YYB3RgLuAAAAAAAACpG":{"file_name":["s3.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"vQQdLrWHLywJs9twt3EH2QAAAAAAAKAW":{"file_name":["subcommands.py"],"function_name":[""],"function_offset":[833],"line_number":[834]},"PUIH740KQXWx70DXM4ZvgQAAAAAAABoW":{"file_name":["s3handler.py"],"function_name":[""],"function_offset":[273],"line_number":[274]},"dsOcslker2-lnNTIC5yERAAAAAAAAJig":{"file_name":["results.py"],"function_name":[""],"function_offset":[550],"line_number":[551]},"zUlsQG278t98_u2KV_JLSQAAAAAAAIoK":{"file_name":["results.py"],"function_name":["_create_new_result_cls"],"function_offset":[10],"line_number":[48]},"vkeP2ntYyoFN0A16x9eliwAAAAAAADPE":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAADBq":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAJp6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAACAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAIMS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAABo6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAAOqC":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPu-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[780],"line_number":[781]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABC4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAAC54":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAAMtg":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJN2":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x"],"function_offset":[],"line_number":[420]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"qkYSh95E1urNTie_gKbr7wAAAAAAAABY":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8":{"file_name":["connection.py"],"function_name":[""],"function_offset":[14],"line_number":[15]},"xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAEU":{"file_name":["url.py"],"function_name":[""],"function_offset":[61],"line_number":[62]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[5],"line_number":[764]},"cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["parse"],"function_offset":[11],"line_number":[948]},"aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["_parse_sub"],"function_offset":[8],"line_number":[443]},"MebnOxK5WOhP29sl19JefwAAAAAAAAua":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[341],"line_number":[834]},"MebnOxK5WOhP29sl19JefwAAAAAAAAVQ":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[171],"line_number":[664]},"iLW1ehST1pGQ3S8RoqM9QgAAAAAAAAAY":{"file_name":["sre_parse.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[166]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"9NWoah56eYULAP_zGE9PuwAAAAAAALHC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[101],"line_number":[102]},"IKrIDHd5n47PpDQsRXxvvgAAAAAAACmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[81],"line_number":[82]},"oG7568kMJujZxPJfj7VMjAAAAAAAANNm":{"file_name":["frontend.py"],"function_name":[""],"function_offset":[390],"line_number":[391]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAItq_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAItGv":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAbE":{"file_name":[],"function_name":["__lru_cache_add"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAXX":{"file_name":[],"function_name":["pagevec_lru_move_fn"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAH6":{"file_name":[],"function_name":["release_pages"],"function_offset":[],"line_number":[]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAFIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAIB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAMyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAJWM":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAOSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAOJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAIpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAANh4":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1Zm":{"file_name":[],"function_name":["__x64_sys_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1XX":{"file_name":[],"function_name":["__vm_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1Ny":{"file_name":[],"function_name":["__do_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIy8h":{"file_name":[],"function_name":["remove_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJu9M":{"file_name":[],"function_name":["kmem_cache_free"],"function_offset":[],"line_number":[]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACE":{"file_name":["compat.py"],"function_name":[""],"function_offset":[15],"line_number":[29]},"iwnHqwtnoHjA-XW01rxhpwAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[16]},"53nvYhJfd2eJh-qREaeFBQAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[7]},"zwRZ32H5_95LpRJHzXkqVAAAAAAAAAAI":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[7],"line_number":[10]},"JJab8JrsPDK66yfOtCG3zQAAAAAAAAAQ":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"1XUiDryPjyncBxkTlbVecgAAAAAAAAAU":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"OIy8IFqaTWz5UoN3FSH-wQAAAAAAAABc":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[37],"line_number":[41]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAJKK":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAIQq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAE2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAADs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAAbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAANUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAJQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAApu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAHn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAAFAy":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAAmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5":{"file_name":[],"function_name":["prep_new_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgURG":{"file_name":[],"function_name":["clear_page_erms"],"function_offset":[],"line_number":[]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAACy":{"file_name":["errors.py"],"function_name":[""],"function_offset":[45],"line_number":[50]}},"executables":{"G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","B8JRxL079xbhqQBqGvksAg":"kubelet","6kzBY4yj-1Fh1NCTZA3z0w":"aws-k8s-agent","j8DVIOTu7Btj9lgFefJ84A":"dockerd","B56YkhsK1JwqD-8F8sjS3A":"prometheus","v6HIzNa4K6G4nRP9032RIA":"dockerd","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","gNW12BepH17pXwK-ZuYt3w":"node_exporter","piWSMQrh4r040D0BPNaJvw":"vmlinux","kajOqZqz7V1y0BdYQLFQrw":"containerd-shim-runc-v2","A2oiHVwisByxRn5RDT4LjA":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","QvG8QEGAld88D676NL_Y2Q":"filebeat","6auiCMWq5cA-hAbqSYvdQQ":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","JsObMPhfT_zO2Q_B1cPLxA":"coredns","SbPwzb_Kog2bWn8uc7xhDQ":"aws","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","9LzzIocepYcOjnUsLlgOjg":"vmlinux","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","9HZ7GQCC6G9fZlRD7aGzXQ":"libssl.so.1.0.2k","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k","5OhlekN4HU3KaqhG_GtinA":"ena","R3YNZBiWt7Z3ZpFfTh6XyQ":"ena","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","-SVIyCZG9IbFKK-fe2Wh4g":"cluster-autoscaler","EX9l-cE0x8X9W8uz4iKUfw":"zlib.cpython-39-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","PVZV2uq5ZRt-FFaczL10BA":"libdl-2.26.so","3nN3bymnZ8E42aLEtgglmA":"ld-2.26.so","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so"},"total_frames":172380,"sampling_rate":0.2} diff --git a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_604800s_625x.json b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_604800s_625x.json deleted file mode 100644 index 75ad39e9298d..000000000000 --- a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_604800s_625x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"oxpVfjjIF44Ceg6SK1UUdQ":43,"JTDxAdxqnTYIS6qzFXvK3g":100,"5tZzmji29IcMEbLCg170Tw":294,"0CNUMdOdpmKJxWeUmvWvXg":1343,"9_06LL00QkYIeiFNCWu0XQ":1109,"OtKh8npcfHhiQ7ynFMPOeQ":622,"TCJ8_VmEK5hAZOYdmPHyug":487,"OCdksb_5DbnTD8RB0r1Hmw":460,"2Ov4wSepfExdnFvsJSSjog":411,"668oRSTLMVtOeHPjJ80fWg":574,"VmRA1Zd-R_saxzv9stOlrw":519,"u31aX9a6CI2OuomWQHSx1Q":614,"oHTQoPZFXrc9eFjCRWW_BA":570,"tIRMz0rwuOf8rRZlytIuAQ":481,"-s21TvA-EsTWbfCutQG83Q":528,"LuHRiiYB6iq-QXoGUFYVXA":457,"5oh0023XVeE3U9ZP60NzUA":505,"hecRkAhRG62NML7wI512zA":286,"P-5EQ3lfGgit0Oj6qTKYqw":210,"fRxnoZgNqB73ndCJkUzrxg":263,"iww2NcKTwMO4dUHXUrsfKA":297,"dP8WPiIXitz7dopr2cbyrg":302,"c84Ph1EEsEpt9KFMdSQvtA":307,"DkjcsUWzUMWlzGIG7vWPLA":251,"O7XAt57p5nvwpgeB2KrNbw":312,"Oam9nmQfwQpA_10YTKZCkg":255,"gM71DK9QAb25Em9dhlNNXA":231,"VoyVx3eKZvx3I7o9LV75WA":180,"6MfMhGSHuQ0CLUxktz5OVg":175,"9pWzAEbyffmwRrKvRecyaQ":174,"DK4Iffrk3v05Awun60ygow":152,"4r_hCJ268ciweOwgH0Qwzw":129,"VC42Hg55_L_IfaF_actjIw":104,"7l18-g5emVzljYbZzZJDRA":62,"PkHiro08_uzuUWpeantpNA":42,"9EcGjMrQwznPlnAdDi9Lxw":38,"tagsGmBta7BnDHBzEbH9eQ":27,"euPXE4-KNZJD0T6j_TMfYw":24,"cL14TWzNnz1qK2PUYdE9bg":20,"9wXZUZEeGMQm83C5yXCZ2g":15,"bz1cYNqu8MBH2xCXTMEiAg":16,"fCScXsJaisrZL_JXgS4qQg":33,"V-MDb_Yh073ps9Vw4ypmDQ":17,"wAujHiFN47_oNUI63d6EtA":26,"zMMsPlSW5HOq5bsuVRh3KA":6,"pLdowTKUS5KSwivHyl5AgA":10,"_ef-NJahpYK_FzFC-KdtYQ":11,"omG-i9KffSi3YT8q0rYOiw":3,"XiONbb-veQ1sAuFD6_Fv0A":12,"krdohOL0KiVMtm4q-6fmjg":8,"N2LqhupgLi4T_B9D7JaDDQ":6,"7TvODt8WtQ5KXTmYPsDI3A":5,"u1L6jqeUaTNx1a2aJ9yFwA":2,"8uzy4VW9n0Z8KokUdeadfg":2,"EeUwhr9vbcywMBkIYZRfCw":3,"x443zjuudYI-A7cRu2DIGg":3,"rrrvnakD3SpJqProBGqoCQ":3,"sDfHX0MKzztQSqC8kl_-sg":2,"WmwSnxyphedkasVyGbhNdg":3,"NU5so_CJJJwGJM_hiEcxgQ":1,"A9B6bwuKQl9pC0MIYqtAgg":1,"X86DUuQ7tHAxGBaWu4tZLg":4,"T3fWxJzHMwU-oUs7rgXCcg":2,"vq75CDVua5N-eDXnfyZYMA":2,"oKVObqTWF9QIjxgKf8UkTw":6,"DaDdc6eLo0hc-QxL2XQh5Q":3,"YRZbUV2DChD6dl3Y2xjF8g":1,"EnsO3_jc7LnLdUHQbwkxMg":1,"V2XOOBv96QfYXHIIY7_OLA":6,"FTJM3wsT8Kc-UaiIK2yDMQ":4,"ivbgd9hswtvZ7aTts7HESw":3,"yXsgvY1JyekwdCV5rJdspg":7,"_TjN4epIphuKUiHZJZdqxQ":3,"ZQdwkmvvmLjNzNpTA4PPhw":8,"ssC7MBcE9kfM3yTim7UrNQ":12,"-yH5iqJp4uVN6clNHuFusA":7,"SrSwvDbs2pmPg3SRfXJBCA":13,"n5nFiHsDS01AKuzFKvQXdA":4,"XbtNNAnLtuHwAR-P2ynwqA":4,"Rr1Z3cNxrq9AQiD8wZZ1dA":9,"gESQTq4qRn3wnW-FPfxOfA":7,"CSpdzACT53hVs5DyKY8X5A":5,"AlH3zgnqwh5sdMMzX8AXxg":6,"ysEqok7gFOl9eLMLBwFm1g":3,"7B48NKNivOFEka6-8dK3Qg":1,"OC533YmmMZSw8TjJz41YiQ":1,"X6-W250nbzzPy4NasjncWg":1,"gi6S4ODPtJ-ERYxlMd4WHA":2,"EGm59IOxpyqZq7sEwgZb1g":1,"y7cw8NxReMWOs4KtDlMCFA":1,"L1ZLG1mjktr2Zy0xiQnH0w":1},"stack_traces":{"oxpVfjjIF44Ceg6SK1UUdQ":{"address_or_lines":[2357],"file_ids":["edNJ10OjHiWc5nzuTQdvig"],"frame_ids":["edNJ10OjHiWc5nzuTQdvigAAAAAAAAk1"],"type_ids":[3]},"JTDxAdxqnTYIS6qzFXvK3g":{"address_or_lines":[4636840,4373888],"file_ids":["LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g"],"frame_ids":["LvhLWomlc0dSPYzQ8C620gAAAAAARsCo","LvhLWomlc0dSPYzQ8C620gAAAAAAQr2A"],"type_ids":[3,3]},"5tZzmji29IcMEbLCg170Tw":{"address_or_lines":[18425733,18110445,18122515],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGSeF","j8DVIOTu7Btj9lgFefJ84AAAAAABFFft","j8DVIOTu7Btj9lgFefJ84AAAAAABFIcT"],"type_ids":[3,3,3]},"0CNUMdOdpmKJxWeUmvWvXg":{"address_or_lines":[32434917,32101228,32115955,32118104],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6gzz","QvG8QEGAld88D676NL_Y2QAAAAAB6hVY"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"OtKh8npcfHhiQ7ynFMPOeQ":{"address_or_lines":[4643458,4477392,4476996,4475762,4469018,4457110],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtqC","B8JRxL079xbhqQBqGvksAgAAAAAARFHQ","B8JRxL079xbhqQBqGvksAgAAAAAARFBE","B8JRxL079xbhqQBqGvksAgAAAAAAREty","B8JRxL079xbhqQBqGvksAgAAAAAARDEa","B8JRxL079xbhqQBqGvksAgAAAAAARAKW"],"type_ids":[3,3,3,3,3,3]},"TCJ8_VmEK5hAZOYdmPHyug":{"address_or_lines":[4652224,11517676,25223155,25230084,11538500,11501274,4847689],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAAAr77s","wfA2BgwfDNXUWsxkJ083RwAAAAABgN_z","wfA2BgwfDNXUWsxkJ083RwAAAAABgPsE","wfA2BgwfDNXUWsxkJ083RwAAAAAAsBBE","wfA2BgwfDNXUWsxkJ083RwAAAAAAr37a","wfA2BgwfDNXUWsxkJ083RwAAAAAASfhJ"],"type_ids":[3,3,3,3,3,3,3]},"OCdksb_5DbnTD8RB0r1Hmw":{"address_or_lines":[18515232,25399653,25432667,25428452,25361060,18103588,18097915,18123257],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABg5Fl","v6HIzNa4K6G4nRP9032RIAAAAAABhBJb","v6HIzNa4K6G4nRP9032RIAAAAAABhAHk","v6HIzNa4K6G4nRP9032RIAAAAAABgvqk","v6HIzNa4K6G4nRP9032RIAAAAAABFD0k","v6HIzNa4K6G4nRP9032RIAAAAAABFCb7","v6HIzNa4K6G4nRP9032RIAAAAAABFIn5"],"type_ids":[3,3,3,3,3,3,3,3]},"2Ov4wSepfExdnFvsJSSjog":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504548,5043327],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQck","FWZ9q3TQKZZok58ua1HDsgAAAAAATPR_"],"type_ids":[3,3,3,3,3,3,3,3,3]},"668oRSTLMVtOeHPjJ80fWg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9506710,10521925,4547584],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQ-W","FWZ9q3TQKZZok58ua1HDsgAAAAAAoI1F","FWZ9q3TQKZZok58ua1HDsgAAAAAARWQA"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"VmRA1Zd-R_saxzv9stOlrw":{"address_or_lines":[4650848,9850853,9880398,9883181,9807044,9827268,9781937,9782483,9784009,9784300,9829781],"file_ids":["QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg"],"frame_ids":["QaIvzvU8UoclQMd_OMt-PgAAAAAARvdg","QaIvzvU8UoclQMd_OMt-PgAAAAAAlk_l","QaIvzvU8UoclQMd_OMt-PgAAAAAAlsNO","QaIvzvU8UoclQMd_OMt-PgAAAAAAls4t","QaIvzvU8UoclQMd_OMt-PgAAAAAAlaTE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlfPE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUKx","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUTT","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUrJ","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUvs","QaIvzvU8UoclQMd_OMt-PgAAAAAAlf2V"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"oHTQoPZFXrc9eFjCRWW_BA":{"address_or_lines":[4646312,4475111,4248744,4416245,4662882,10485923,16807,1222099,1219772,1208264,769619,768516,8542429],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAAREjn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQNSo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ2L1","FWZ9q3TQKZZok58ua1HDsgAAAAAARyZi","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEpy8","ew01Dk0sWZctP-VaEpavqQAAAAAAEm_I","ew01Dk0sWZctP-VaEpavqQAAAAAAC75T","ew01Dk0sWZctP-VaEpavqQAAAAAAC7oE","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,4,4,4,4,4,4,4,4]},"tIRMz0rwuOf8rRZlytIuAQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10734948,4245427,4255110,4288384],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo81k","FWZ9q3TQKZZok58ua1HDsgAAAAAAQMez","FWZ9q3TQKZZok58ua1HDsgAAAAAAQO2G","FWZ9q3TQKZZok58ua1HDsgAAAAAAQW-A"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"LuHRiiYB6iq-QXoGUFYVXA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41428636,40303236,22534565,19333914,19319593],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCac","v6HIzNa4K6G4nRP9032RIAAAAAACZvqE","v6HIzNa4K6G4nRP9032RIAAAAAABV9ml","v6HIzNa4K6G4nRP9032RIAAAAAABJwMa","v6HIzNa4K6G4nRP9032RIAAAAAABJssp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"5oh0023XVeE3U9ZP60NzUA":{"address_or_lines":[4610335,4610076,4612877,4490724,4492388,4499312,4241704,4392309,4610754,10485923,16807,1221667,1219340,1207832,769603,768500,8537181],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARlkf","kajOqZqz7V1y0BdYQLFQrwAAAAAARlgc","kajOqZqz7V1y0BdYQLFQrwAAAAAARmMN","kajOqZqz7V1y0BdYQLFQrwAAAAAARIXk","kajOqZqz7V1y0BdYQLFQrwAAAAAARIxk","kajOqZqz7V1y0BdYQLFQrwAAAAAARKdw","kajOqZqz7V1y0BdYQLFQrwAAAAAAQLko","kajOqZqz7V1y0BdYQLFQrwAAAAAAQwV1","kajOqZqz7V1y0BdYQLFQrwAAAAAARlrC","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAEqQj","9LzzIocepYcOjnUsLlgOjgAAAAAAEpsM","9LzzIocepYcOjnUsLlgOjgAAAAAAEm4Y","9LzzIocepYcOjnUsLlgOjgAAAAAAC75D","9LzzIocepYcOjnUsLlgOjgAAAAAAC7n0","9LzzIocepYcOjnUsLlgOjgAAAAAAgkRd"],"type_ids":[3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"P-5EQ3lfGgit0Oj6qTKYqw":{"address_or_lines":[43732576,69263145,69263545,54339630,54340167,54179273,54179969,54177426,50376971,50377819,50384113,50377819,43742470,43723999,43620502,43619092,43672236,43616946,43623742],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIN8p","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIOC5","MNBJ5seVz_ocW6tcr1HSmwAAAAADPSgu","MNBJ5seVz_ocW6tcr1HSmwAAAAADPSpH","MNBJ5seVz_ocW6tcr1HSmwAAAAADOrXJ","MNBJ5seVz_ocW6tcr1HSmwAAAAADOriB","MNBJ5seVz_ocW6tcr1HSmwAAAAADOq6S","MNBJ5seVz_ocW6tcr1HSmwAAAAADALEL","MNBJ5seVz_ocW6tcr1HSmwAAAAADALRb","MNBJ5seVz_ocW6tcr1HSmwAAAAADAMzx","MNBJ5seVz_ocW6tcr1HSmwAAAAADALRb","MNBJ5seVz_ocW6tcr1HSmwAAAAACm3UG","MNBJ5seVz_ocW6tcr1HSmwAAAAACmyzf","MNBJ5seVz_ocW6tcr1HSmwAAAAACmZiW","MNBJ5seVz_ocW6tcr1HSmwAAAAACmZMU","MNBJ5seVz_ocW6tcr1HSmwAAAAACmmKs","MNBJ5seVz_ocW6tcr1HSmwAAAAACmYqy","MNBJ5seVz_ocW6tcr1HSmwAAAAACmaU-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"fRxnoZgNqB73ndCJkUzrxg":{"address_or_lines":[4652224,22354871,22382638,22364302,56669071,58509234,58268669,58227812,58241853,31197476,7372432,7294909,7296733,7300250,7296676,7304324,7296733,7300250,7296901,7319678],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYLOP","-pk6w5puGcp-wKnQ61BZzQAAAAADfMey","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH6Q","-pk6w5puGcp-wKnQ61BZzQAAAAAAb0-9","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1bd","-pk6w5puGcp-wKnQ61BZzQAAAAAAb2Sa","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1ak","-pk6w5puGcp-wKnQ61BZzQAAAAAAb3SE","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1bd","-pk6w5puGcp-wKnQ61BZzQAAAAAAb2Sa","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1eF","-pk6w5puGcp-wKnQ61BZzQAAAAAAb7B-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"iww2NcKTwMO4dUHXUrsfKA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528745,54499864,54500494,54477482,44043537,44060985,43329158,43326819],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQArp","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5oY","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5yO","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA0R","MNBJ5seVz_ocW6tcr1HSmwAAAAACoFE5","MNBJ5seVz_ocW6tcr1HSmwAAAAAClSaG","MNBJ5seVz_ocW6tcr1HSmwAAAAAClR1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"dP8WPiIXitz7dopr2cbyrg":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709512,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16807,2741196,2827770,2817684,2805156,3383048,8438368],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEI","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7A6","B8JRxL079xbhqQBqGvksAgAAAAAASFtz","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k","A2oiHVwisByxRn5RDT4LjAAAAAAAM58I","A2oiHVwisByxRn5RDT4LjAAAAAAAgMJg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"c84Ph1EEsEpt9KFMdSQvtA":{"address_or_lines":[152249,135481,144741,190122,831754,827742,928935,925466,103752,102294,97206,439344,486674,922914,10485923,16807,2756288,2755416,2924693,3066448,4344,2925966,8437662],"file_ids":["w5zBqPf1_9mIVEf-Rn7EdA","Z_CHd3Zjsh2cWE2NSdbiNQ","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","LHNvPtcKBt87cCBX8aTNhQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAlK5","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAjVl","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAuaq","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADLEK","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADKFe","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADiyn","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADh8a","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAXu2","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAABrQw","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB20S","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADhUi","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAALKCV","A2oiHVwisByxRn5RDT4LjAAAAAAALspQ","LHNvPtcKBt87cCBX8aTNhQAAAAAAABD4","A2oiHVwisByxRn5RDT4LjAAAAAAALKWO","A2oiHVwisByxRn5RDT4LjAAAAAAAgL-e"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"DkjcsUWzUMWlzGIG7vWPLA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54556506,44024036,44026008,44007166,43828228,43837959,43282962,43282989,10485923,16807,2845749,2845580,2841596,3335577,3325166,699747],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHda","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8Dk","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8iY","MNBJ5seVz_ocW6tcr1HSmwAAAAACn37-","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1","A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ","A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu","A2oiHVwisByxRn5RDT4LjAAAAAAACq1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"O7XAt57p5nvwpgeB2KrNbw":{"address_or_lines":[12540096,19004791,19032250,19014236,19907031,31278974,31279321,31305795,31279321,31290406,31279321,31317002,19907351,21668882,21654434,21097575,20766142,16277099,16285669,16307614,16278212,12403428,12120854,12121189,12544111],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAv1jA","67s2TwiMngM0yin5Y8pvEgAAAAABIf13","67s2TwiMngM0yin5Y8pvEgAAAAABImi6","67s2TwiMngM0yin5Y8pvEgAAAAABIiJc","67s2TwiMngM0yin5Y8pvEgAAAAABL8HX","67s2TwiMngM0yin5Y8pvEgAAAAAB3Ud-","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3bBD","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3XQm","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3dwK","67s2TwiMngM0yin5Y8pvEgAAAAABL8MX","67s2TwiMngM0yin5Y8pvEgAAAAABSqQS","67s2TwiMngM0yin5Y8pvEgAAAAABSmui","67s2TwiMngM0yin5Y8pvEgAAAAABQexn","67s2TwiMngM0yin5Y8pvEgAAAAABPN2-","67s2TwiMngM0yin5Y8pvEgAAAAAA-F5r","67s2TwiMngM0yin5Y8pvEgAAAAAA-H_l","67s2TwiMngM0yin5Y8pvEgAAAAAA-NWe","67s2TwiMngM0yin5Y8pvEgAAAAAA-GLE","67s2TwiMngM0yin5Y8pvEgAAAAAAvULk","67s2TwiMngM0yin5Y8pvEgAAAAAAuPMW","67s2TwiMngM0yin5Y8pvEgAAAAAAuPRl","67s2TwiMngM0yin5Y8pvEgAAAAAAv2hv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Oam9nmQfwQpA_10YTKZCkg":{"address_or_lines":[4652224,58596086,58544235,10401064,10401333,10401661,58561029,58544882,58545860,58550052,58558939,56502167,58377199,58374713,5176491,5212551,5201562,5198538,12589080,12593882,12537260,12591620,12402541,12450679,4552007,4551401],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAADfhr2","wfA2BgwfDNXUWsxkJ083RwAAAAADfVBr","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrUo","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrY1","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrd9","wfA2BgwfDNXUWsxkJ083RwAAAAADfZIF","wfA2BgwfDNXUWsxkJ083RwAAAAADfVLy","wfA2BgwfDNXUWsxkJ083RwAAAAADfVbE","wfA2BgwfDNXUWsxkJ083RwAAAAADfWck","wfA2BgwfDNXUWsxkJ083RwAAAAADfYnb","wfA2BgwfDNXUWsxkJ083RwAAAAADXieX","wfA2BgwfDNXUWsxkJ083RwAAAAADesPv","wfA2BgwfDNXUWsxkJ083RwAAAAADero5","wfA2BgwfDNXUWsxkJ083RwAAAAAATvyr","wfA2BgwfDNXUWsxkJ083RwAAAAAAT4mH","wfA2BgwfDNXUWsxkJ083RwAAAAAAT16a","wfA2BgwfDNXUWsxkJ083RwAAAAAAT1LK","wfA2BgwfDNXUWsxkJ083RwAAAAAAwBgY","wfA2BgwfDNXUWsxkJ083RwAAAAAAwCra","wfA2BgwfDNXUWsxkJ083RwAAAAAAv02s","wfA2BgwfDNXUWsxkJ083RwAAAAAAwCIE","wfA2BgwfDNXUWsxkJ083RwAAAAAAvT9t","wfA2BgwfDNXUWsxkJ083RwAAAAAAvft3","wfA2BgwfDNXUWsxkJ083RwAAAAAARXVH","wfA2BgwfDNXUWsxkJ083RwAAAAAARXLp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"gM71DK9QAb25Em9dhlNNXA":{"address_or_lines":[4602912,7755816,7756100,7759920,7760733,7744869,8376791,8749164,8618561,8132341,8137261,8133828,8067381,8671283,5977431,5085785,5087348,4663256,4670457,4680028,4694485,10485923,16807,2795169,2795020,2794811,2794363],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARjwg","kajOqZqz7V1y0BdYQLFQrwAAAAAAdlgo","kajOqZqz7V1y0BdYQLFQrwAAAAAAdllE","kajOqZqz7V1y0BdYQLFQrwAAAAAAdmgw","kajOqZqz7V1y0BdYQLFQrwAAAAAAdmtd","kajOqZqz7V1y0BdYQLFQrwAAAAAAdi1l","kajOqZqz7V1y0BdYQLFQrwAAAAAAf9HX","kajOqZqz7V1y0BdYQLFQrwAAAAAAhYBs","kajOqZqz7V1y0BdYQLFQrwAAAAAAg4JB","kajOqZqz7V1y0BdYQLFQrwAAAAAAfBb1","kajOqZqz7V1y0BdYQLFQrwAAAAAAfCot","kajOqZqz7V1y0BdYQLFQrwAAAAAAfBzE","kajOqZqz7V1y0BdYQLFQrwAAAAAAexk1","kajOqZqz7V1y0BdYQLFQrwAAAAAAhFAz","kajOqZqz7V1y0BdYQLFQrwAAAAAAWzVX","kajOqZqz7V1y0BdYQLFQrwAAAAAATZpZ","kajOqZqz7V1y0BdYQLFQrwAAAAAATaB0","kajOqZqz7V1y0BdYQLFQrwAAAAAARyfY","kajOqZqz7V1y0BdYQLFQrwAAAAAAR0P5","kajOqZqz7V1y0BdYQLFQrwAAAAAAR2lc","kajOqZqz7V1y0BdYQLFQrwAAAAAAR6HV","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKqah","9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM","9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7","9LzzIocepYcOjnUsLlgOjgAAAAAAKqN7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4]},"VoyVx3eKZvx3I7o9LV75WA":{"address_or_lines":[4652224,22354373,22356417,22043891,9840916,9838765,4872825,5688954,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7924288,7914841,6798266,6797590,6797444,2726038],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVRnF","B8JRxL079xbhqQBqGvksAgAAAAABVSHB","B8JRxL079xbhqQBqGvksAgAAAAABUFzz","B8JRxL079xbhqQBqGvksAgAAAAAAlikU","B8JRxL079xbhqQBqGvksAgAAAAAAliCt","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA","A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE","A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"6MfMhGSHuQ0CLUxktz5OVg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19907431,18154044,18082996],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8Nn","v6HIzNa4K6G4nRP9032RIAAAAAABFQI8","v6HIzNa4K6G4nRP9032RIAAAAAABE-y0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"9pWzAEbyffmwRrKvRecyaQ":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858041,18647118,18648496,18406502,18049625],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwJ5","j8DVIOTu7Btj9lgFefJ84AAAAAABHIhO","j8DVIOTu7Btj9lgFefJ84AAAAAABHI2w","j8DVIOTu7Btj9lgFefJ84AAAAAABGNxm","j8DVIOTu7Btj9lgFefJ84AAAAAABE2pZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"DK4Iffrk3v05Awun60ygow":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41460538,41453510,39933561,34157889,34191237,32888264,25716990,34278084,34202797,25717430,25848062,25843154,25848772,25852175,25783796,25513444,25512912,32939143,32929768,24984119,18131287],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeKM6","v6HIzNa4K6G4nRP9032RIAAAAAACeIfG","v6HIzNa4K6G4nRP9032RIAAAAAACYVZ5","v6HIzNa4K6G4nRP9032RIAAAAAACCTVB","v6HIzNa4K6G4nRP9032RIAAAAAACCbeF","v6HIzNa4K6G4nRP9032RIAAAAAAB9dXI","v6HIzNa4K6G4nRP9032RIAAAAAABiGj-","v6HIzNa4K6G4nRP9032RIAAAAAACCwrE","v6HIzNa4K6G4nRP9032RIAAAAAACCeSt","v6HIzNa4K6G4nRP9032RIAAAAAABiGq2","v6HIzNa4K6G4nRP9032RIAAAAAABimj-","v6HIzNa4K6G4nRP9032RIAAAAAABilXS","v6HIzNa4K6G4nRP9032RIAAAAAABimvE","v6HIzNa4K6G4nRP9032RIAAAAAABinkP","v6HIzNa4K6G4nRP9032RIAAAAAABiW30","v6HIzNa4K6G4nRP9032RIAAAAAABhU3k","v6HIzNa4K6G4nRP9032RIAAAAAABhUvQ","v6HIzNa4K6G4nRP9032RIAAAAAAB9pyH","v6HIzNa4K6G4nRP9032RIAAAAAAB9nfo","v6HIzNa4K6G4nRP9032RIAAAAAABfTo3","v6HIzNa4K6G4nRP9032RIAAAAAABFKlX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"4r_hCJ268ciweOwgH0Qwzw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756169,2891746,2888851],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg5J","A2oiHVwisByxRn5RDT4LjAAAAAAALB_i","A2oiHVwisByxRn5RDT4LjAAAAAAALBST"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"VC42Hg55_L_IfaF_actjIw":{"address_or_lines":[4652224,30971941,30986245,30988292,30990568,31382091,30723428,25540326,25548827,25550707,25503568,25504356,25481468,25481277,25484807,25485060,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813708,2804875,2803431,2801020,2796664,2900191,2900031],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAAB2Jgl","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NAF","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NgE","-pk6w5puGcp-wKnQ61BZzQAAAAAB2ODo","-pk6w5puGcp-wKnQ61BZzQAAAAAB3tpL","-pk6w5puGcp-wKnQ61BZzQAAAAAB1M1k","-pk6w5puGcp-wKnQ61BZzQAAAAABhbbm","-pk6w5puGcp-wKnQ61BZzQAAAAABhdgb","-pk6w5puGcp-wKnQ61BZzQAAAAABhd9z","-pk6w5puGcp-wKnQ61BZzQAAAAABhSdQ","-pk6w5puGcp-wKnQ61BZzQAAAAABhSpk","-pk6w5puGcp-wKnQ61BZzQAAAAABhND8","-pk6w5puGcp-wKnQ61BZzQAAAAABhNA9","-pk6w5puGcp-wKnQ61BZzQAAAAABhN4H","-pk6w5puGcp-wKnQ61BZzQAAAAABhN8E","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyL","piWSMQrh4r040D0BPNaJvwAAAAAAKsbn","piWSMQrh4r040D0BPNaJvwAAAAAAKr18","piWSMQrh4r040D0BPNaJvwAAAAAAKqx4","piWSMQrh4r040D0BPNaJvwAAAAAALEDf","piWSMQrh4r040D0BPNaJvwAAAAAALEA_"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"7l18-g5emVzljYbZzZJDRA":{"address_or_lines":[4652224,57367531,57370109,31789066,31776683,58631656,57895320,57890805,57903406,31388307,31007417,30973013,30989730,30933387,30773764,30777712,30779690,30778532,4952297,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813708,2804913,2798877,3355670,8461220],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAADa1vr","-pk6w5puGcp-wKnQ61BZzQAAAAADa2X9","-pk6w5puGcp-wKnQ61BZzQAAAAAB5RAK","-pk6w5puGcp-wKnQ61BZzQAAAAAB5N-r","-pk6w5puGcp-wKnQ61BZzQAAAAADfqXo","-pk6w5puGcp-wKnQ61BZzQAAAAADc2mY","-pk6w5puGcp-wKnQ61BZzQAAAAADc1f1","-pk6w5puGcp-wKnQ61BZzQAAAAADc4ku","-pk6w5puGcp-wKnQ61BZzQAAAAAB3vKT","-pk6w5puGcp-wKnQ61BZzQAAAAAB2SK5","-pk6w5puGcp-wKnQ61BZzQAAAAAB2JxV","-pk6w5puGcp-wKnQ61BZzQAAAAAB2N2i","-pk6w5puGcp-wKnQ61BZzQAAAAAB2AGL","-pk6w5puGcp-wKnQ61BZzQAAAAAB1ZIE","-pk6w5puGcp-wKnQ61BZzQAAAAAB1aFw","-pk6w5puGcp-wKnQ61BZzQAAAAAB1akq","-pk6w5puGcp-wKnQ61BZzQAAAAAB1aSk","-pk6w5puGcp-wKnQ61BZzQAAAAAAS5Dp","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyx","piWSMQrh4r040D0BPNaJvwAAAAAAKrUd","piWSMQrh4r040D0BPNaJvwAAAAAAMzQW","piWSMQrh4r040D0BPNaJvwAAAAAAgRuk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"PkHiro08_uzuUWpeantpNA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927405,7924037],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePZt","ew01Dk0sWZctP-VaEpavqQAAAAAAeOlF"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"9EcGjMrQwznPlnAdDi9Lxw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19908516,19901309,19904117,19988362,19897796,19899069,19901309,19904677,19901380,19901069],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7Z1","v6HIzNa4K6G4nRP9032RIAAAAAABMP-K","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6vE","v6HIzNa4K6G4nRP9032RIAAAAAABL6qN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"tagsGmBta7BnDHBzEbH9eQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927445,6732427,882422,8542429],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePaV","ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL","ew01Dk0sWZctP-VaEpavqQAAAAAADXb2","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"euPXE4-KNZJD0T6j_TMfYw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,7046,2795776,1483241,1482767,2600004,1074397,11342,13400,51888,12612,2578675,2599636,1091600,7744,52134,33264,2795776,1483241,1482767,2600004,1073803,11342,13400,51888,12396,16726,41698,2852079,2851771,2850043,1501120,1495723],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lLD39yzd4Cg8F13tcGpzGQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","dCCKy6JoX0PADOFic8hRNQ","9w9lF96vJW7ZhBoZ8ETsBw","xUQuo4OgBaS_Le-fdAwt8A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lLD39yzd4Cg8F13tcGpzGQAAAAAAABuG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAACxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","dCCKy6JoX0PADOFic8hRNQAAAAAAAB5A","9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAMum","xUQuo4OgBaS_Le-fdAwt8AAAAAAAAIHw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAACxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAKLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3z7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFufA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFtKr"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3]},"cL14TWzNnz1qK2PUYdE9bg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791289,24794610,24781052,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756560,2755688,2744899,3827767,3827522,2050302,4868077,4855697,8473771],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekj5","v6HIzNa4K6G4nRP9032RIAAAAAABelXy","v6HIzNa4K6G4nRP9032RIAAAAAABeiD8","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3","ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC","ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-","ew01Dk0sWZctP-VaEpavqQAAAAAASkft","ew01Dk0sWZctP-VaEpavqQAAAAAASheR","ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"9wXZUZEeGMQm83C5yXCZ2g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696049,18965430,18965669,18966052,18973868,18911086,18905330,18910928,18783663,18799034,10485923,16900,15534,703491,2755412,3875596,3765212,3542694,3677893],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNTx","j8DVIOTu7Btj9lgFefJ84AAAAAABIWO2","j8DVIOTu7Btj9lgFefJ84AAAAAABIWSl","j8DVIOTu7Btj9lgFefJ84AAAAAABIWYk","j8DVIOTu7Btj9lgFefJ84AAAAAABIYSs","j8DVIOTu7Btj9lgFefJ84AAAAAABII9u","j8DVIOTu7Btj9lgFefJ84AAAAAABIHjy","j8DVIOTu7Btj9lgFefJ84AAAAAABII7Q","j8DVIOTu7Btj9lgFefJ84AAAAAABHp2v","j8DVIOTu7Btj9lgFefJ84AAAAAABHtm6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEIE","piWSMQrh4r040D0BPNaJvwAAAAAAADyu","piWSMQrh4r040D0BPNaJvwAAAAAACrwD","piWSMQrh4r040D0BPNaJvwAAAAAAKgtU","piWSMQrh4r040D0BPNaJvwAAAAAAOyMM","piWSMQrh4r040D0BPNaJvwAAAAAAOXPc","piWSMQrh4r040D0BPNaJvwAAAAAANg6m","piWSMQrh4r040D0BPNaJvwAAAAAAOB7F"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"bz1cYNqu8MBH2xCXTMEiAg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7507990,7549300],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpAW","ew01Dk0sWZctP-VaEpavqQAAAAAAczF0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"fCScXsJaisrZL_JXgS4qQg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7436960,6766701,6769642,2098164],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg","9LzzIocepYcOjnUsLlgOjgAAAAAAZ0Bt","9LzzIocepYcOjnUsLlgOjgAAAAAAZ0vq","9LzzIocepYcOjnUsLlgOjgAAAAAAIAP0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"V-MDb_Yh073ps9Vw4ypmDQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797702,6797556,2726148],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7mG","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0","ew01Dk0sWZctP-VaEpavqQAAAAAAKZkE"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"wAujHiFN47_oNUI63d6EtA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7513502,6765905,6759805,2574033,2218596],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe","ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R","ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9","ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR","ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"zMMsPlSW5HOq5bsuVRh3KA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2822585,3001783,2924437,3111967,3095700,156159,136830,285452,1430646,1449979,1447865,1447752,1446446,1188192,1188137,220151,219438,219438,219438,219438,219438,219425,219589,1446206],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","huWyXZbCBWCe2ZtK9BiokQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxG5","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3wf","-p9BlJh9JZMPPNjY_j92ngAAAAAALzyU","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhZ-","9HZ7GQCC6G9fZlRD7aGzXQAAAAAABFsM","huWyXZbCBWCe2ZtK9BiokQAAAAAAFdR2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFh_7","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhe5","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhdI","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhIu","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiFg","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiEp","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1v3","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1kh","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1nF","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhE-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"pLdowTKUS5KSwivHyl5AgA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317790,1316548,1337360,1338921,1188023],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBue","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBbE","huWyXZbCBWCe2ZtK9BiokQAAAAAAFGgQ","huWyXZbCBWCe2ZtK9BiokQAAAAAAFG4p","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiC3"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"_ef-NJahpYK_FzFC-KdtYQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,29942,33148,3444,27444,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1072174,33518,35576,8560,17976,49494,22596,3272936,3254825,1481992,1534257,3238809,3051716,67008,10485923,16807,2756288,2755416,2744627,3827463,3827218,2049230,2042319,2040147,2469374],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","eOfhJQFIxbIEScd007tROw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAAIF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFwu","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAFhE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMfDo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMaop","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp0I","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF2kx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWuZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALpDE","eOfhJQFIxbIEScd007tROwAAAAAAAQXA","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAOmcH","A2oiHVwisByxRn5RDT4LjAAAAAAAOmYS","A2oiHVwisByxRn5RDT4LjAAAAAAAH0TO","A2oiHVwisByxRn5RDT4LjAAAAAAAHynP","A2oiHVwisByxRn5RDT4LjAAAAAAAHyFT","A2oiHVwisByxRn5RDT4LjAAAAAAAJa3-"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"omG-i9KffSi3YT8q0rYOiw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6869315,6866863,2620,6841654,6841533],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","6miIyyucTZf5zXHCk7PT1g","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD","ew01Dk0sWZctP-VaEpavqQAAAAAAaMev","6miIyyucTZf5zXHCk7PT1gAAAAAAAAo8","ew01Dk0sWZctP-VaEpavqQAAAAAAaGU2","ew01Dk0sWZctP-VaEpavqQAAAAAAaGS9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"XiONbb-veQ1sAuFD6_Fv0A":{"address_or_lines":[48,38,174,104,68,200,38,174,104,68,60,38,174,104,68,92,38,174,104,68,4,38,174,104,10,10,38,174,104,68,20,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044807,2041460,1171829,2265239,2264574,2258601,1016100],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5sij7Z672VAK_gGoPDPJBg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","PCeTYI0HN2oKNST6e1IaQQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","U4FmFVJMlNKhF1hVl3Xj1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","JR7ekk9KGQJKKPohpdwCLQ","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rpRn_rYC3CgtEgBAUrkZZg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAADI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5sij7Z672VAK_gGoPDPJBgAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","PCeTYI0HN2oKNST6e1IaQQAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","U4FmFVJMlNKhF1hVl3Xj1AAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","JR7ekk9KGQJKKPohpdwCLQAAAAAAAAAK","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rpRn_rYC3CgtEgBAUrkZZgAAAAAAAAAU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzOH","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInap","G68hjsyagwq6LpWrMjDdngAAAAAAD4Ek"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"krdohOL0KiVMtm4q-6fmjg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,5836,10976,12298,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,37910,8000,46852,32076,49840,40252,33434,32730,43978,37948,30428,26428,19370,1480209,1940645,1970099,1481300,1480695,2595076,1079144,20016,37192,1480141,1913750],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","okehWevKsEA4q6dk779jgw","-IuadWGT89NVzIyF_Emodw","XXJY7v4esGWnaxtMW3FA0g","FbrXdcA4j750RyQ3q9JXMw","pL34QuyxyP6XYzGDBMK_5w","IoAk4kM-M4DsDPp7ia5QXw","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","fB79lJck2X90l-j7VqPR-Q","gbMheDI1NZ3NY96J0seddg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GquRfhZBLBKr9rIBPuH3nA","_DA_LSFNMjbu9L2Dcselpw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE","okehWevKsEA4q6dk779jgwAAAAAAAH1M","-IuadWGT89NVzIyF_EmodwAAAAAAAMKw","XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08","FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa","pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a","IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK","uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc","fB79lJck2X90l-j7VqPR-QAAAAAAAGc8","gbMheDI1NZ3NY96J0seddgAAAAAAAEuq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpf3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w","_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpXN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHTOW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,3,3]},"N2LqhupgLi4T_B9D7JaDDQ":{"address_or_lines":[4623648,7066994,7068484,7069849,7058446,10002970,10005676,10124500,9016547,11291366,9016547,24500423,24494926,9016547,10689293,10690744,9016547,24494153,24444068,9016547,24526481,9016547,12769612,10684953,24495408,10128820,7327937,7071629,7072042,7142576,5627718,5631637,5512164,4910105,4760761,4777496,4778618,10485923,16743,6659981,6654519,6650911,6650061,8052504,7525822,7331115,7324128,6674998,6706722,6700261,2539310],"file_ids":["JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["JsObMPhfT_zO2Q_B1cPLxAAAAAAARo0g","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9Vy","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9tE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-CZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa7QO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKIa","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKys","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmnzU","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAArErm","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABddjH","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcNO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoxsN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoyC4","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcBJ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdPyk","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdj6R","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwtlM","JsObMPhfT_zO2Q_B1cPLxAAAAAAAowoZ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcUw","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmo20","JsObMPhfT_zO2Q_B1cPLxAAAAAAAb9DB","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-eN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-kq","JsObMPhfT_zO2Q_B1cPLxAAAAAAAbPyw","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVd9G","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVe6V","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVBvk","JsObMPhfT_zO2Q_B1cPLxAAAAAAASuwZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAASKS5","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOYY","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOp6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAZZ-N","piWSMQrh4r040D0BPNaJvwAAAAAAZYo3","piWSMQrh4r040D0BPNaJvwAAAAAAZXwf","piWSMQrh4r040D0BPNaJvwAAAAAAZXjN","piWSMQrh4r040D0BPNaJvwAAAAAAet8Y","piWSMQrh4r040D0BPNaJvwAAAAAActW-","piWSMQrh4r040D0BPNaJvwAAAAAAb90r","piWSMQrh4r040D0BPNaJvwAAAAAAb8Hg","piWSMQrh4r040D0BPNaJvwAAAAAAZdo2","piWSMQrh4r040D0BPNaJvwAAAAAAZlYi","piWSMQrh4r040D0BPNaJvwAAAAAAZjzl","piWSMQrh4r040D0BPNaJvwAAAAAAJr8u"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"7TvODt8WtQ5KXTmYPsDI3A":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,54988,10976,61450,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,21526,8000,30022,59542,29542,18986,21536,54462,53814,11024,12030,61026,21014,45460,42632,1480209,3459845,1479516,2595076,1050939,23882,1371605,2194798,2100556,2032414,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","cBO14nNDW8EW0oaZDaZipw","C64RiOp1JIPwHLB_iHDa0A","xvApUwdY2y4sFaZRNrMv5g","vsalcPHh9qLgsdKtk190IA","QsuqlohtoJfpo6vQ6tHa2A","8ep9l3WIVYErRiHtmAdvew","nPWpQrEmCn54Ou0__aZyJA","-xcELApECIipEESUIWed9w","L_saUsdri-UdXCut6Tdtng","uHLoBslr3h6S7ooNeXzEbw","p19NBQ2pky4eRJM7tgeenw","55ABUc9FqQ0uj-yn-sTq2A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1msFlmxT18lYvJkx-hfGPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAANbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAPAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAFQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAAHVG","cBO14nNDW8EW0oaZDaZipwAAAAAAAOiW","C64RiOp1JIPwHLB_iHDa0AAAAAAAAHNm","xvApUwdY2y4sFaZRNrMv5gAAAAAAAEoq","vsalcPHh9qLgsdKtk190IAAAAAAAAFQg","QsuqlohtoJfpo6vQ6tHa2AAAAAAAANS-","8ep9l3WIVYErRiHtmAdvewAAAAAAANI2","nPWpQrEmCn54Ou0__aZyJAAAAAAAACsQ","-xcELApECIipEESUIWed9wAAAAAAAC7-","L_saUsdri-UdXCut6TdtngAAAAAAAO5i","uHLoBslr3h6S7ooNeXzEbwAAAAAAAFIW","p19NBQ2pky4eRJM7tgeenwAAAAAAALGU","55ABUc9FqQ0uj-yn-sTq2AAAAAAAAKaI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANMsF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAk7","1msFlmxT18lYvJkx-hfGPgAAAAAAAF1K","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFO3V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIX1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIA1M","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHwMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3]},"u1L6jqeUaTNx1a2aJ9yFwA":{"address_or_lines":[74,6,18,8,18,80,24,4,84,38,174,104,68,128,38,174,104,68,64,38,174,104,68,84,38,174,104,68,100,140,10,38,174,104,68,60,38,174,104,14,32,38,32,786829,1090933,2561389,794630,788130,1197115,2578326,1109790,1111453,1034624],"file_ids":["a5aMcPOeWx28QSVng73nBQ","inI9W0bfekFTCpu0ceKTHg","RPwdw40HEBL87wRkKV2ozw","pT2bgvKv3bKR6LMAYtKFRw","Rsr7q4vCSh2ppRtyNkwZAA","cKQfWSgZRgu_1Goz5QGSHw","T2fhmP8acUvRZslK7YRDPw","lrxXzNEmAlflj7bCNDjxdA","SMoSw8cr-PdrIATvljOPrQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xaCec3W8F6xlvd_EISI7vw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GYpj0RgmHJTfD-_w_Fx69w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","b78FoZPzgl20nGrU0Zu24g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5ZxW56RI3EOJxqCWjdkdHg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","7l7IlhF_Z6_Ribw1CW945Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","imaY9TOf2pKX0_q1vRTskQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAABK","inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG","RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS","pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI","Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS","cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ","T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY","lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE","SMoSw8cr-PdrIATvljOPrQAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xaCec3W8F6xlvd_EISI7vwAAAAAAAACA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GYpj0RgmHJTfD-_w_Fx69wAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","b78FoZPzgl20nGrU0Zu24gAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5ZxW56RI3EOJxqCWjdkdHgAAAAAAAABk","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","7l7IlhF_Z6_Ribw1CW945QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAAm","imaY9TOf2pKX0_q1vRTskQAAAAAAAAAg","G68hjsyagwq6LpWrMjDdngAAAAAADAGN","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAJxVt","G68hjsyagwq6LpWrMjDdngAAAAAADCAG","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAJ1eW","G68hjsyagwq6LpWrMjDdngAAAAAAEO8e","G68hjsyagwq6LpWrMjDdngAAAAAAEPWd","G68hjsyagwq6LpWrMjDdngAAAAAAD8mA"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"8uzy4VW9n0Z8KokUdeadfg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,14028,27360,55578,1480209,1969795,1481300,1480601,2595076,1079485,18126,36558,2460,42724,46700,1479608,1493928,2595076,1079485,30578,15346,1479608,2595076,1079485,57180,32508,1276,30612,1479516,2595076,1079485,63696,30612,1479516,2595076,1073749,60436,3118304,766784,10485923,16807,2741196,2827770,2817684,2804657,2869654],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","Kq9d0b1CBVEQZUtuJtmlJg","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAADbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAANka","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","EFJHOn-GACfHXgae-R1yDAAAAAAAAEbO","GdaBUD9IUEkKxIBryNqV2wAAAAAAAI7O","QU8QLoFK6ojrywKrBFfTzAAAAAAAAAmc","V558DAsp4yi8bwa8eYwk5QAAAAAAAKbk","grikUXlisBLUbeL_OWixIwAAAAAAALZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAN9c","-9oyoP4Jj2iRkwEezqId-gAAAAAAAH78","Kq9d0b1CBVEQZUtuJtmlJgAAAAAAAAT8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAPjQ","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAAOwU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL5Tg","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7NA","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKsux","A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,4,4,4,4,4,4,4]},"EeUwhr9vbcywMBkIYZRfCw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,46796,43744,53258,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1079144,13334,40862,834,1480209,1969795,1481300,1480601,2595076,1069341,58136,12466,1587508,1079485,50582,26272,1479608,1493928,2595076,1079211,60348,34084,42798,54954,4836,40660,62188,43850,13372,5488,20256,1924997],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","wpss7yv4AvkSwbtctTl0JA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SLUxdgyFrTF3l4NU1VRO_w","ZOgaFnYiv38tVz-8Hafu3w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","u1Za6xFXDX1Ys5Qeh_gy9Q","uq4_q8agTQ0rkhJvygJ3QA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","pK0zxAMiW-X23QjQRVzm5w","OP7EiuTwTtWCf_B7a-Zpig","WyVrojmISSgbkYAxEOnpQw","JdWBEAqhrU7LJg0YDuYO0w","cwZEcJVCN5Q4BJdAS3o8fw","iLNvi1vqLkBP_ehg4QlqeA","guXM5tmjJlv0Ehde0y1DFw","avBEfFKeFSrhKf93SLNe0Q","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","aAagm2yDcrnYaqBPCwyu8Q","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAALbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAANAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAADQW","ne8F__HPIVgxgycJADVSzAAAAAAAAJ-e","wpss7yv4AvkSwbtctTl0JAAAAAAAAANC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFEd","SLUxdgyFrTF3l4NU1VRO_wAAAAAAAOMY","ZOgaFnYiv38tVz-8Hafu3wAAAAAAADCy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGDk0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","u1Za6xFXDX1Ys5Qeh_gy9QAAAAAAAMWW","uq4_q8agTQ0rkhJvygJ3QAAAAAAAAGag","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHer","pK0zxAMiW-X23QjQRVzm5wAAAAAAAOu8","OP7EiuTwTtWCf_B7a-ZpigAAAAAAAIUk","WyVrojmISSgbkYAxEOnpQwAAAAAAAKcu","JdWBEAqhrU7LJg0YDuYO0wAAAAAAANaq","cwZEcJVCN5Q4BJdAS3o8fwAAAAAAABLk","iLNvi1vqLkBP_ehg4QlqeAAAAAAAAJ7U","guXM5tmjJlv0Ehde0y1DFwAAAAAAAPLs","avBEfFKeFSrhKf93SLNe0QAAAAAAAKtK","uHLoBslr3h6S7ooNeXzEbwAAAAAAADQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAABVw","aAagm2yDcrnYaqBPCwyu8QAAAAAAAE8g","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHV-F"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,1,1,3,3,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,3]},"x443zjuudYI-A7cRu2DIGg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,49094,58124,2548,13860,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28996,2578675,2599636,1091600,48574,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28996,2578675,2599636,1091600,63674,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28780,342,57994,19187,38198,48990],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lpUCR1NQj5NOLBg7mvzlqg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAL_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAAOMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAL2-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lpUCR1NQj5NOLBg7mvzlqgAAAAAAAPi6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAOKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAJU2","jaBVtokSUzfS97d-XKjijgAAAAAAAL9e"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"rrrvnakD3SpJqProBGqoCQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,1270,4476,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,19382,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,60558,2790352,1482889,1482415,2595076,1079144,8942,10826,15776,45470,57908,19178,5946,1481694,1535004,2095808],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","08DBZKRu4nC_Oi_uT40UHw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","n74P5OxFm1hAo5ZWtgcKHQ","zXbqXCWr0lCbi_b24hNBRQ","AOM_-6oRTyAxK8W79Wo5aQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAAT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAABF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAEu2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","08DBZKRu4nC_Oi_uT40UHwAAAAAAAOyO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAD2g","n74P5OxFm1hAo5ZWtgcKHQAAAAAAALGe","zXbqXCWr0lCbi_b24hNBRQAAAAAAAOI0","AOM_-6oRTyAxK8W79Wo5aQAAAAAAAErq","yaTrLhUSIq2WitrTHLBy3QAAAAAAABc6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF2wc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAH_rA"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3]},"sDfHX0MKzztQSqC8kl_-sg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,16720,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,52894,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,44846,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,32258,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50744,16726,2346,19187,41240,50359],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAM6e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAH4C","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAAkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMS3"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"WmwSnxyphedkasVyGbhNdg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,23142,41180,18932,30244,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,29418,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,58990,2795776,1483241,1482767,2600004,1073803,3150,5208,43696,4204,342,33506,2852079,2851771,2849353,2846190,2846190,2845732],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","l97YFeEKpeLfa-lEAZVNcA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAAHYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2wk"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"NU5so_CJJJwGJM_hiEcxgQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,4,38,174,104,68,16,38,174,104,68,256,140,10,38,174,104,68,0,12,8,28,12,8,54,12,120,1169291,1109342,1109180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZBnr-5IlLVGCdkX_lTNKmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RDOEyok4432cuMjL10_tug","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","25JFhMXA0rvP5hfyUpf34w","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RDOEyok4432cuMjL10_tugAAAAAAAAEA","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","25JFhMXA0rvP5hfyUpf34wAAAAAAAAAc","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAB4","G68hjsyagwq6LpWrMjDdngAAAAAAEdeL","G68hjsyagwq6LpWrMjDdngAAAAAAEO1e","G68hjsyagwq6LpWrMjDdngAAAAAAEOy8"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3]},"A9B6bwuKQl9pC0MIYqtAgg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,37276,30816,26538,1480561,1970211,1481652,1480953,2600004,1079669,36476,1480561,1970211,1481652,1480953,2600004,1079669,13542,44224,26138,5558,16780,64790,18774,36466,18774,17314,43978,43978,43978,43978,43978,43978,43978,43886,18774,13462,1480561,1940968,1917658,1481652,1480953,2600004,1079669,27396,1480561,1827986,1940595,1909209,1934862,3077552,3072233,1745406,3070488],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","ZLTqiSLOmv4Ej_7d8yKLmw","v_WV3HQYVe0q1Ob-1gtx1A","ka2IKJhpWbD6PA3J3v624w","e8Lb_MV93AH-OkvHPPDitg","ka2IKJhpWbD6PA3J3v624w","1vivUE5hL65442lQ9a_ylg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","ka2IKJhpWbD6PA3J3v624w","fCsVLBj60GK9Hf8VtnMcgA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","54xjnvwS2UtwpSVJMemggA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAJGc","W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAGeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAI58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","kSaNXrGzSS3BnDNNWezzMAAAAAAAADTm","ne8F__HPIVgxgycJADVSzAAAAAAAAKzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAGYa","O_h7elJSxPO7SiCsftYRZgAAAAAAABW2","ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAEGM","v_WV3HQYVe0q1Ob-1gtx1AAAAAAAAP0W","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","e8Lb_MV93AH-OkvHPPDitgAAAAAAAI5y","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","1vivUE5hL65442lQ9a_ylgAAAAAAAEOi","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKtu","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","fCsVLBj60GK9Hf8VtnMcgAAAAAAAADSW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","54xjnvwS2UtwpSVJMemggAAAAAAAAGsE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHSHZ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHYYO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvWw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALuDp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGqH-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALtoY"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"X86DUuQ7tHAxGBaWu4tZLg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,19046,37084,2548,13860,26096,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,64610,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,39726,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,0,2794972,1848805,1837992,1848417,2718329,2222078,2208786],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqXc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHAuo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDRh","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKXp5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIef-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIbQS"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"T3fWxJzHMwU-oUs7rgXCcg":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,172,669638,1091944,956540,2223054,995645,1276144],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","okgAOHfDrcA806m5xh4DMA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","okgAOHfDrcA806m5xh4DMAAAAAAAAACs","G68hjsyagwq6LpWrMjDdngAAAAAACjfG","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAADph8","G68hjsyagwq6LpWrMjDdngAAAAAAIevO","G68hjsyagwq6LpWrMjDdngAAAAAADzE9","G68hjsyagwq6LpWrMjDdngAAAAAAE3jw"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3]},"vq75CDVua5N-eDXnfyZYMA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,620,51986,58710,61916,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,12034,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,38490,2790352,1482889,1482415,2595076,1076587,49902,51960,24944,34360,342,51586,2846655,2846347,2843929,2840766,2843954,2840766,2842897,2268402,1775000,1761295,1048455],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","aRRT4_vBG9Q4nqyirWo5FA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAC8C","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","aRRT4_vBG9Q4nqyirWo5FAAAAAAAAJZa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Uy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2ER","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_-H"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3]},"oKVObqTWF9QIjxgKf8UkTw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,51328,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,50170,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,13752,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41068,49494,4746,19187,41141,49404],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","08Dc0vnMK9C_nl7yQB6ZKQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zuPG_tF81PcJTwjfBwKlDg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKC1","jaBVtokSUzfS97d-XKjijgAAAAAAAMD8"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"DaDdc6eLo0hc-QxL2XQh5Q":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,336,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,28326,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,51274,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,43126,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,0,2790352,1482889,1482415,2595076,1071215,49902,51786,56736,43360,44552,32102],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ZyAwfhB8pqBFv6xiDVdvPQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","9alsKcnSosScCQ3ntwGT5w","xAINw9zPBhJlledr3DAcGA","xVweU0pD8q051c2YgF4PTw"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAG6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAAMhK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ZyAwfhB8pqBFv6xiDVdvPQAAAAAAAKh2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFhv","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAN2g","9alsKcnSosScCQ3ntwGT5wAAAAAAAKlg","xAINw9zPBhJlledr3DAcGAAAAAAAAK4I","xVweU0pD8q051c2YgF4PTwAAAAAAAH1m"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1]},"YRZbUV2DChD6dl3Y2xjF8g":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,38230,41436,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,57358,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,33966,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,59370,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,17976,49494,31018,19187,41240,50308],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","d4jl580PLMUwu5s3I4wcXg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","tKago5vqLnwIkezk_wTBpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAJVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAOAO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","d4jl580PLMUwu5s3I4wcXgAAAAAAAISu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","tKago5vqLnwIkezk_wTBpQAAAAAAAOfq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSE"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"EnsO3_jc7LnLdUHQbwkxMg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,336,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,24230,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,47162,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,37090,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,41914,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34360,342,39210,19187,41240,51115],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAF6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAALg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAAJDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAAKO6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAJkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMer"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"V2XOOBv96QfYXHIIY7_OLA":{"address_or_lines":[3150,5208,43696,12612,2578675,2599636,1091600,42546,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,12274,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,15838,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,37594,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1079669,12698,1482046,1829360,2586225,2600004,1054235,21784,1973936,2600004,1051035,60416,55140,1372101,2194686,2080131],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Gp9aOxUrrpSVBx4-ftlTOA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","y9R94bQUxts02WzRWfV7xg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uI6css-d8SGQRK6a_Ntl-A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SlnkBp0IIJFLHVOe4KbxwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7wBb3xHP1JZHNBpMGh4EdA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","u3fGdgL6eAYjYSRbRUri0g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aG0mH34tM6si5c1l397JVQ","GC-VoGaqaEobPzimayHQTQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAKYy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","y9R94bQUxts02WzRWfV7xgAAAAAAAC_y","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uI6css-d8SGQRK6a_Ntl-AAAAAAAAD3e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SlnkBp0IIJFLHVOe4KbxwQAAAAAAAJLa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","7wBb3xHP1JZHNBpMGh4EdAAAAAAAADGa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEBYb","u3fGdgL6eAYjYSRbRUri0gAAAAAAAFUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHh6w","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEAmb","aG0mH34tM6si5c1l397JVQAAAAAAAOwA","GC-VoGaqaEobPzimayHQTQAAAAAAANdk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFO_F","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIXz-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAH72D"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,1,1,3,3,3]},"FTJM3wsT8Kc-UaiIK2yDMQ":{"address_or_lines":[33018,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,32502,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,6654,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,9126,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,27090,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1079144,39334,1481694,1828960,2581397,1480843,1480209,1940568,1917230,1844695,1996687],"file_ids":["PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","UfGck3qA2qF0xFB5gpY4Hg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","G9ShE3ODivDEFyHVdsnZ_g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","6AsJ0dA2BUqaic-ScDJBMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fr52ZDCgnkPZlzTNdLTQ5w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uqoEOAkLp1toolLH0q5LVw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["PmhxUKv5sePRxhCBONca8gAAAAAAAID6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","UfGck3qA2qF0xFB5gpY4HgAAAAAAAH72","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","G9ShE3ODivDEFyHVdsnZ_gAAAAAAABn-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","6AsJ0dA2BUqaic-ScDJBMAAAAAAAACOm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fr52ZDCgnkPZlzTNdLTQ5wAAAAAAAGnS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","uqoEOAkLp1toolLH0q5LVwAAAAAAAJmm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUEu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHneP"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3]},"ivbgd9hswtvZ7aTts7HESw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,49488,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,40502,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,9946,2790352,1482889,1482415,2595076,1079485,8942,11000,49520,61192,19302,1479516,1828960,2573747,2594708,1091475,51250,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1079144,0,1481694,1828960,2581297,2595076,1087128,0,23366,42140,41576,9542,41540,41016,39548,3072796],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","WjtMXFj0eujpoknR_rynvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","Vot4T3F5OpUj8rbXhgpMDg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EPS0ql6FPdCQLe9KByvDQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAJ42","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","WjtMXFj0eujpoknR_rynvAAAAAAAACba","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","Vot4T3F5OpUj8rbXhgpMDgAAAAAAAO8I","eV_m28NnKeeTL60KO2H3SAAAAAAAAEtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","EPS0ql6FPdCQLe9KByvDQAAAAAAAAMgy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEJaY","_____________________wAAAAAAAAAA","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAKSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAKJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG","E2b-mzlh_8261-JxcySn-AAAAAAAAKJE","E2b-mzlh_8261-JxcySn-AAAAAAAAKA4","E2b-mzlh_8261-JxcySn-AAAAAAAAJp8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuMc"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,1,3]},"yXsgvY1JyekwdCV5rJdspg":{"address_or_lines":[2573747,2594708,1091475,43746,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,51994,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,18382,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,10738,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1079144,0,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079485,46582,1479772,1827586,1940195,1986447,1982493,1959065,1765336,1761295,1048494],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XVsKc4e32xXUv-3uv2s-8Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uPGvGNXBf1JXGeeDSsmGQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAAKri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAMsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAAEfO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XVsKc4e32xXUv-3uv2s-8QAAAAAAACny","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","uPGvGNXBf1JXGeeDSsmGQAAAAAAAALX2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_-u"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"_TjN4epIphuKUiHZJZdqxQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,38,10,38,174,104,68,30,56,382,1034444],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OwrnTUowquMzuETYoP67yQ","HmAocvtnsxREZJIec2I5gw","KHDki7BxJPyjGLtvY8M5lQ","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OwrnTUowquMzuETYoP67yQAAAAAAAAAe","HmAocvtnsxREZJIec2I5gwAAAAAAAAA4","KHDki7BxJPyjGLtvY8M5lQAAAAAAAAF-","G68hjsyagwq6LpWrMjDdngAAAAAAD8jM"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3]},"ZQdwkmvvmLjNzNpTA4PPhw":{"address_or_lines":[25326,27384,368,1756,2573747,2594708,1091475,48726,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,64878,2789627,1482889,1482415,2595076,1079485,21616,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,51982,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,58138,2790352,1482889,1482415,2595076,1067375,25326,27210,32160,46288],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XlQ19HBD_RNa2r3QWOR-nA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","it1vvnZdXdzy0fFROnaaOQ"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAL5W","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XlQ19HBD_RNa2r3QWOR-nAAAAAAAAP1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAMsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAAOMa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEElv","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAH2g","it1vvnZdXdzy0fFROnaaOQAAAAAAALTQ"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1]},"ssC7MBcE9kfM3yTim7UrNQ":{"address_or_lines":[4846,6904,45424,50908,2573747,2594708,1091475,58102,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,48494,2789627,1482889,1482415,2595076,1079485,1136,15206,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,2830,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,4586,2790352,1482889,1482415,2595076,1067395,4846,6904,45240,53006,54142],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XlQ19HBD_RNa2r3QWOR-nA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","gZooqVYiItnHim-lK4feOg"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAOL2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XlQ19HBD_RNa2r3QWOR-nAAAAAAAAL1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAARw","eV_m28NnKeeTL60KO2H3SAAAAAAAADtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAABHq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEEmD","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALC4","0S3htaCNkzxOYeavDR1GTQAAAAAAAM8O","gZooqVYiItnHim-lK4feOgAAAAAAANN-"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1]},"-yH5iqJp4uVN6clNHuFusA":{"address_or_lines":[2578675,2599636,1091600,5350,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,6974,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,5866,2795776,1483241,1482767,2600004,1079483,3150,4692,13478,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,58134,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,10246,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12396,342,41610,19187,41240,50663],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","UfGck3qA2qF0xFB5gpY4Hg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","G9ShE3ODivDEFyHVdsnZ_g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","6AsJ0dA2BUqaic-ScDJBMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","VY0EiAO0DxwLRTE4PfFhdw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","A8AozG5gQfEN24i4IE7w5w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","UfGck3qA2qF0xFB5gpY4HgAAAAAAABTm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","G9ShE3ODivDEFyHVdsnZ_gAAAAAAABs-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","6AsJ0dA2BUqaic-ScDJBMAAAAAAAABbq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABJU","eV_m28NnKeeTL60KO2H3SAAAAAAAADSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","VY0EiAO0DxwLRTE4PfFhdwAAAAAAAOMW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","A8AozG5gQfEN24i4IE7w5wAAAAAAACgG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAKKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMXn"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"SrSwvDbs2pmPg3SRfXJBCA":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11318,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,15678,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,250,2790352,1482889,1482415,2595076,1076587,29422,31480,4464,17976,33110,51586,2846655,2846347,2843929,2840766,2843907,2841214,1439462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NGbZlnLCqeq3LFq89r_SpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PmhxUKv5sePRxhCBONca8gAAAAAAAAD6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbm"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3]},"n5nFiHsDS01AKuzFKvQXdA":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,302,38,174,104,68,382,120,38,258,658,1111840,1034048],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OPpnYj88CDOiKneikdGPHA","ZJjPF65K8mBuISvhCfKfBg","xLxhp_367a_SbgOYuEJjlw","QHotkhNTqx5C4Kjd2F2_6w","Ht79I_xqXv3bOgaClTNQ4w","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAEu","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OPpnYj88CDOiKneikdGPHAAAAAAAAAF-","ZJjPF65K8mBuISvhCfKfBgAAAAAAAAB4","xLxhp_367a_SbgOYuEJjlwAAAAAAAAAm","QHotkhNTqx5C4Kjd2F2_6wAAAAAAAAEC","Ht79I_xqXv3bOgaClTNQ4wAAAAAAAAKS","G68hjsyagwq6LpWrMjDdngAAAAAAEPcg","G68hjsyagwq6LpWrMjDdngAAAAAAD8dA"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"XbtNNAnLtuHwAR-P2ynwqA":{"address_or_lines":[1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,46454,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,17534,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,64182,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,22670,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1079669,35024,1482046,1829360,2586325,1480953,1480561,1940968,1986869,1946031,1991239,1990411,1912997,3078008,3077552,3072071,1641674,3069796],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aD-GPAkaW-Swis8ybNgyMQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","pv4wAezdMMO0SVuGgaEMTgAAAAAAALV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAER-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAPq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAFiO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","aD-GPAkaW-Swis8ybNgyMQAAAAAAAIjQ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlE1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHbGv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHmJH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHl8L","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHTCl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvd4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvWw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALuBH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGQzK","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALtdk"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Rr1Z3cNxrq9AQiD8wZZ1dA":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,9150,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52246,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,48350,2789627,1482889,1482415,2595076,1079485,21616,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1079144,37050,1481694,1828960,2581297,2595076,1079144,2994,1480209,1940645,1970099,1481300,1480601,2595076,1067831,41714,39750,33948,33384,25926,33098,33348,34466,32098,39462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","HENgRXYeEs7mDD8Gk_MNmg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fFS0upy5lIaT99RhlTN5LQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lSdGU4igLMOpLhL_6XP15w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","QAp_Nt6XUeNsCXnAUgW7Xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","20O937106XMbOD0LQR4SPw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","HENgRXYeEs7mDD8Gk_MNmgAAAAAAACO-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fFS0upy5lIaT99RhlTN5LQAAAAAAAMwW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","lSdGU4igLMOpLhL_6XP15wAAAAAAALze","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","20O937106XMbOD0LQR4SPwAAAAAAAAuy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEEs3","gPzb0fXoBe1225fbKepMRAAAAAAAAKLy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAISc","_lF8o5tJDcePvza_IYtgSQAAAAAAAIJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAAGVG","E2b-mzlh_8261-JxcySn-AAAAAAAAIFK","E2b-mzlh_8261-JxcySn-AAAAAAAAIJE","E2b-mzlh_8261-JxcySn-AAAAAAAAIai","E2b-mzlh_8261-JxcySn-AAAAAAAAH1i","JrU1PwRIxl_8SXdnTESnogAAAAAAAJom"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1]},"gESQTq4qRn3wnW-FPfxOfA":{"address_or_lines":[2790352,1482889,1482415,2595076,1079485,62190,63732,7014,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,43746,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,2842,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,48542,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1050939,4144,1371605,1977020,2595076,1079485,8954,1479772,3459845,1479516,2595076,1072525,58674,1646337,3072295,1865241,10490014,423063,2283967,2281306,2510155,2414579,2398792,2385273,8471624],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lTFhQHSZwvS4-s94KVv5mA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","IcJVDEq52FRv22q0yHVMaw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","BDtQyw375W96A0PA_Z7SDQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0","eV_m28NnKeeTL60KO2H3SAAAAAAAABtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAAKri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAAsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAAL2e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAk7","lTFhQHSZwvS4-s94KVv5mAAAAAAAABAw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFO3V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHiq8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","IcJVDEq52FRv22q0yHVMawAAAAAAACL6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANMsF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF2N","BDtQyw375W96A0PA_Z7SDQAAAAAAAOUy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGR8B","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a","A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L","A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz","A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI","A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5","A2oiHVwisByxRn5RDT4LjAAAAAAAgURI"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,1,3,3,3,3,3,1,3,3,3,4,4,4,4,4,4,4,4,4]},"CSpdzACT53hVs5DyKY8X5A":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,13654,16860,52596,11060,58864,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,36842,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,30778,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,47130,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,51886,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1592,33110,6110,3227324,1844695,1847563,1702665,1680736,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","skFt9oVHBFfMDC1On4IJhg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","g5zhfSuJlGbmNqPl5Qb2wg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","UoMth5MLnZ-vUHeTplwEvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAADVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAEHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAM10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAI_q","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","skFt9oVHBFfMDC1On4IJhgAAAAAAAHg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","g5zhfSuJlGbmNqPl5Qb2wgAAAAAAALga","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","UoMth5MLnZ-vUHeTplwEvAAAAAAAAMqu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABfe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMT68","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGfsJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGaVg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"AlH3zgnqwh5sdMMzX8AXxg":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52130,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,61558,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17970,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1066158,3868,39750,21660,21058,64084,29144,22318,29144,18030,1840882,1970521,2595076,1049850,1910],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Gxt7_MN7XgUOe9547JcHVQ"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAMui","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAT6","Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,1]},"ysEqok7gFOl9eLMLBwFm1g":{"address_or_lines":[29422,31480,4464,18140,2573747,2594708,1091475,64774,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,18042,2789627,1482889,1482415,2595076,1079485,25712,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,2618,2790352,1482889,1482415,2595076,1079144,29422,31306,36256,31544,18122,5412,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,54286,19054,47612,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1073749,55752,56134,25756,25504,3350479,3072521,1865128],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XkOSW26Xa6_lkqHv5givKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XkOSW26Xa6_lkqHv5givKgAAAAAAAP0G","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEZ6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAAo6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO","TBeSzkyqIwKL8td602zDjAAAAAAAAEpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","J3wpF3Lf_vPkis4aNGKFbwAAAAAAANnI","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAGSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAGOg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMx_P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuIJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,3,3,3]},"7B48NKNivOFEka6-8dK3Qg":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,8722,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,20598,2790352,1482889,1482415,2595076,1079485,33518,35060,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,41538,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,40098,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1074318,25764,6982,46236,45634,23124,53720,46894,53720,46894,53720,46894,53720,47420,41028,1347096],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","zpgqltXEgKujOhJUj-jAhg","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAACIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAAKJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGSO","MsEmysGbXhMvgdbwhcZDCgAAAAAAAGSk","jtp3NDFNJGnK6sK5oOFo8QAAAAAAABtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc","_lF8o5tJDcePvza_IYtgSQAAAAAAALJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALk8","zpgqltXEgKujOhJUj-jAhgAAAAAAAKBE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFI4Y"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3]},"OC533YmmMZSw8TjJz41YiQ":{"address_or_lines":[19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,27150,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,42322,2795776,1483241,1482767,2600004,1079483,19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079483,19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,30298,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,32876,16726,62090,20547,1659254,1860268],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","6GGFIt18C0VByIn0h-PdeQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SA64oIT_DC3uHXf7ZjFqkw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","akZOzI9XwsEixvkTDGeDPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","6GGFIt18C0VByIn0h-PdeQAAAAAAAGoO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SA64oIT_DC3uHXf7ZjFqkwAAAAAAAKVS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","akZOzI9XwsEixvkTDGeDPwAAAAAAAHZa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAPKK","ASi9f26ltguiwFajNwOaZwAAAAAAAFBD","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGVF2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHGKs"],"type_ids":[1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"X6-W250nbzzPy4NasjncWg":{"address_or_lines":[23630,25514,30464,8440,12298,26148,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,38814,1470,22780,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,51026,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,47386,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,19506,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1073803,23630,25688,64176,108,16726,29410,2852079,2851771,2849353,2846190,2849331,2846638,1439925,1865566,1029925,10490014,422731,937148],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","AtF9VdLKnFQvB9H1lsFPjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Pf1McBfrZjVj1CxRZBq6Yw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAHcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAACD4","h0l-9tGi18mC40qpcJbyDwAAAAAAADAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAGYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAAJee","TBeSzkyqIwKL8td602zDjAAAAAAAAAW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAFj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAMdS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","AtF9VdLKnFQvB9H1lsFPjAAAAAAAALka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Pf1McBfrZjVj1CxRZBq6YwAAAAAAAEwy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3oz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHde","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAD7cl","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnNL","ew01Dk0sWZctP-VaEpavqQAAAAAADky8"],"type_ids":[1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,4,4,4]},"gi6S4ODPtJ-ERYxlMd4WHA":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1091600,55462,2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1091600,63874,2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1074067,0,29636,2577481,2934013,1108250,1105981,1310350,1245864,1200348,1190613,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165561,1146206,1245475,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165783,1162744,1226823,1225457,1224431,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165323,1165909],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","vkeP2ntYyoFN0A16x9eliw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAANim","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAPmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGOT","_____________________wAAAAAAAAAA","vkeP2ntYyoFN0A16x9eliwAAAAAAAHPE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1RJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALMT9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOA9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAE_6O","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwKo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAElDc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEirV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEX1e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwEj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcnX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEb34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErhH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErLx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEq7v","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcgL","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcpV"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"EGm59IOxpyqZq7sEwgZb1g":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,36,38,174,104,68,16,140,10,38,174,104,68,48,1992440,1112453,1098694,1112047],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","H5LY_MytOVgyAawi8TymCg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","kUJz0cDHgh-y1O5Hi8equA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","H5LY_MytOVgyAawi8TymCgAAAAAAAAAQ","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","kUJz0cDHgh-y1O5Hi8equAAAAAAAAAAw","G68hjsyagwq6LpWrMjDdngAAAAAAHmb4","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEMPG","G68hjsyagwq6LpWrMjDdngAAAAAAEPfv"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"y7cw8NxReMWOs4KtDlMCFA":{"address_or_lines":[40014,41898,46848,24824,28682,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,17854,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,11362,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,14618,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,22130,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079669,40014,42072,15024,28780,33110,57790,1480561,1827950,3236393,1482344,1535086,3273255,1482344,1535086,3245980,67155,10485923,16964,15598,703171,2759460,3901948,3791884,3567755],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","AtF9VdLKnFQvB9H1lsFPjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Pf1McBfrZjVj1CxRZBq6Yw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","eOfhJQFIxbIEScd007tROw","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAALcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAGD4","h0l-9tGi18mC40qpcJbyDwAAAAAAAHAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAEW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAACxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","AtF9VdLKnFQvB9H1lsFPjAAAAAAAADka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Pf1McBfrZjVj1CxRZBq6YwAAAAAAAFZy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAOG-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-Ru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMWIp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp5o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAF2xu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMfIn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp5o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAF2xu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMYec","eOfhJQFIxbIEScd007tROwAAAAAAAQZT","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEJE","ew01Dk0sWZctP-VaEpavqQAAAAAAADzu","ew01Dk0sWZctP-VaEpavqQAAAAAACrrD","ew01Dk0sWZctP-VaEpavqQAAAAAAKhsk","ew01Dk0sWZctP-VaEpavqQAAAAAAO4n8","ew01Dk0sWZctP-VaEpavqQAAAAAAOdwM","ew01Dk0sWZctP-VaEpavqQAAAAAANnCL"],"type_ids":[1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"L1ZLG1mjktr2Zy0xiQnH0w":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,178,1090933,1814182,788459,788130,1197048,1243204,1201241,1245991,1245236,1171829,2265239,2264574,2258463,1169067],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAACy","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvhE","G68hjsyagwq6LpWrMjDdngAAAAAAElRZ","G68hjsyagwq6LpWrMjDdngAAAAAAEwMn","G68hjsyagwq6LpWrMjDdngAAAAAAEwA0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAEdar"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEpy8":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEm_I":{"file_name":[],"function_name":["futex_wake"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAC75T":{"file_name":[],"function_name":["wake_up_q"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAC7oE":{"file_name":[],"function_name":["try_to_wake_up"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgljd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEqQj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEpsM":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEm4Y":{"file_name":[],"function_name":["futex_wake"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAC75D":{"file_name":[],"function_name":["wake_up_q"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAC7n0":{"file_name":[],"function_name":["try_to_wake_up"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAgkRd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAM58I":{"file_name":[],"function_name":["kernfs_dop_revalidate"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgMJg":{"file_name":[],"function_name":["strcmp"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI":{"file_name":["libmount/src/tab_parse.c"],"function_name":["__mnt_table_parse_mtab"],"function_offset":[],"line_number":[1102]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W":{"file_name":["libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_file"],"function_offset":[],"line_number":[707]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAXu2":{"file_name":["libmount/src/tab_parse.c","libmount/src/tab_parse.c","/usr/include/bits/stdio.h"],"function_name":["mnt_table_parse_stream","mnt_table_parse_next","getline"],"function_offset":[],"line_number":[643,453,117]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAABrQw":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/libio/iogetdelim.c"],"function_name":["_IO_getdelim"],"function_offset":[],"line_number":[114]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB20S":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/libio/fileops.c"],"function_name":["_IO_new_file_underflow"],"function_offset":[],"line_number":[584]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALKCV":{"file_name":[],"function_name":["seq_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALspQ":{"file_name":[],"function_name":["show_mountinfo"],"function_offset":[],"line_number":[]},"LHNvPtcKBt87cCBX8aTNhQAAAAAAABD4":{"file_name":[],"function_name":["ovl_show_options"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALKWO":{"file_name":[],"function_name":["seq_escape"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgL-e":{"file_name":[],"function_name":["strlen"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1":{"file_name":[],"function_name":["__x64_sys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM":{"file_name":[],"function_name":["ksys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8":{"file_name":[],"function_name":["iterate_dir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ":{"file_name":[],"function_name":["proc_pid_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu":{"file_name":[],"function_name":["next_tgid"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACq1j":{"file_name":[],"function_name":["pid_nr_ns"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqah":{"file_name":[],"function_name":["__x64_sys_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM":{"file_name":[],"function_name":["do_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7":{"file_name":[],"function_name":["__do_pipe_flags"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqN7":{"file_name":[],"function_name":["create_pipe_files"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ":{"file_name":[],"function_name":["unix_stream_read_actor"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg5J":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALB_i":{"file_name":[],"function_name":["__fdget_pos"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALBST":{"file_name":[],"function_name":["__fget_light"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu8M":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyL":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKr18":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKqx4":{"file_name":[],"function_name":["follow_managed"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAALEDf":{"file_name":[],"function_name":["lookup_mnt"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAALEA_":{"file_name":[],"function_name":["__lookup_mnt"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyx":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKrUd":{"file_name":[],"function_name":["inode_permission"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAMzQW":{"file_name":[],"function_name":["kernfs_iop_permission"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAgRuk":{"file_name":[],"function_name":["mutex_lock"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg38":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKePq":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePZt":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAeOlF":{"file_name":[],"function_name":["maybe_add_creds"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePaV":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL":{"file_name":[],"function_name":["sock_def_readable"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"lLD39yzd4Cg8F13tcGpzGQAAAAAAABuG":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"LEy-wm0GIvRoYVAga55HiwAAAAAAACxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAB5A":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAMum":{"file_name":["functools.py"],"function_name":["register"],"function_offset":[50],"line_number":[902]},"xUQuo4OgBaS_Le-fdAwt8AAAAAAAAIHw":{"file_name":["functools.py"],"function_name":["_is_union_type"],"function_offset":[2],"line_number":[843]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAKLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkft":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASheR":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr":{"file_name":[],"function_name":["copy_user_generic_string"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEIE":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAADyu":{"file_name":[],"function_name":["exit_to_usermode_loop"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACrwD":{"file_name":[],"function_name":["task_work_run"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgtU":{"file_name":[],"function_name":["__fput"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOyMM":{"file_name":[],"function_name":["xfs_release"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOXPc":{"file_name":[],"function_name":["xfs_free_eofblocks"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAANg6m":{"file_name":[],"function_name":["xfs_bmapi_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOB7F":{"file_name":[],"function_name":["xfs_iext_lookup_extent"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpAW":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAczF0":{"file_name":[],"function_name":["tcp_v4_send_check"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZ0Bt":{"file_name":[],"function_name":["__kfree_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZ0vq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAIAP0":{"file_name":[],"function_name":["__put_page"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7mG":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKZkE":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9":{"file_name":[],"function_name":["__kmalloc_reserve.isra.57"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR":{"file_name":[],"function_name":["__kmalloc_node_track_caller"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk":{"file_name":[],"function_name":["kmalloc_slab"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_connect"],"function_offset":[],"line_number":[345]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhZ-":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_get_server_certificate"],"function_offset":[],"line_number":[1255]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAABFsM":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/ssl_cert.c"],"function_name":["ssl_verify_cert_chain"],"function_offset":[],"line_number":[759]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFdR2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_vfy.c"],"function_name":["X509_verify_cert"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFh_7":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_STORE_CTX_get1_issuer"],"function_offset":[],"line_number":[617]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhe5":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_STORE_get_by_subject"],"function_offset":[],"line_number":[306]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhdI":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_OBJECT_retrieve_by_subject"],"function_offset":[],"line_number":[480]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhIu":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["x509_object_idx_cnt"],"function_offset":[],"line_number":[454]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiFg":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["internal_find"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiEp":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["sk_sort"],"function_offset":[],"line_number":[374]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1v3":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["__GI___qsort_r","msort_with_tmp"],"function_offset":[],"line_number":[297,45]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp","msort_with_tmp"],"function_offset":[],"line_number":[53,159]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1kh":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp","msort_with_tmp"],"function_offset":[],"line_number":[54,159]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1nF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp"],"function_offset":[],"line_number":[83]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhE-":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["x509_object_cmp"],"function_offset":[],"line_number":[168]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[266]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_ex_d2i"],"function_offset":[],"line_number":[235]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBue":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[390]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBbE":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["i2d_name_canon"],"function_offset":[],"line_number":[508]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFGgQ":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_enc.c"],"function_name":["ASN1_item_ex_i2d"],"function_offset":[],"line_number":[148]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFG4p":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_enc.c"],"function_name":["asn1_template_ex_i2d"],"function_offset":[],"line_number":[360]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiC3":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["sk_num"],"function_offset":[],"line_number":[344]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAIF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAGs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAFhE":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOmcH":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOmYS":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAH0TO":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAHynP":{"file_name":[],"function_name":["pagecache_get_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAHyFT":{"file_name":[],"function_name":["find_get_entry"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJa3-":{"file_name":[],"function_name":["PageHuge"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMev":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"6miIyyucTZf5zXHCk7PT1gAAAAAAAAo8":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaGU2":{"file_name":[],"function_name":["netif_rx"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaGS9":{"file_name":[],"function_name":["netif_rx_internal"],"function_offset":[],"line_number":[]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAADI":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[22],"line_number":[35]},"5sij7Z672VAK_gGoPDPJBgAAAAAAAAA8":{"file_name":["formatter.py"],"function_name":[""],"function_offset":[6],"line_number":[19]},"PCeTYI0HN2oKNST6e1IaQQAAAAAAAABc":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[50],"line_number":[51]},"U4FmFVJMlNKhF1hVl3Xj1AAAAAAAAAAE":{"file_name":["cyaml.py"],"function_name":[""],"function_offset":[0],"line_number":[3]},"JR7ekk9KGQJKKPohpdwCLQAAAAAAAAAK":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[2],"line_number":[1181]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"rpRn_rYC3CgtEgBAUrkZZgAAAAAAAAAU":{"file_name":["error.py"],"function_name":[""],"function_offset":[3],"line_number":[6]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAACrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAB9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"okehWevKsEA4q6dk779jgwAAAAAAAH1M":{"file_name":["session.py"],"function_name":["get_credentials"],"function_offset":[12],"line_number":[445]},"-IuadWGT89NVzIyF_EmodwAAAAAAAMKw":{"file_name":["credentials.py"],"function_name":["load_credentials"],"function_offset":[18],"line_number":[1953]},"XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08":{"file_name":["credentials.py"],"function_name":["load"],"function_offset":[18],"line_number":[1009]},"FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa":{"file_name":["utils.py"],"function_name":["retrieve_iam_role_credentials"],"function_offset":[30],"line_number":[517]},"pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a":{"file_name":["utils.py"],"function_name":["_get_iam_role"],"function_offset":[1],"line_number":[524]},"IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK":{"file_name":["utils.py"],"function_name":["_get_request"],"function_offset":[32],"line_number":[435]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"fB79lJck2X90l-j7VqPR-QAAAAAAAGc8":{"file_name":["connectionpool.py"],"function_name":["_make_request"],"function_offset":[116],"line_number":[494]},"gbMheDI1NZ3NY96J0seddgAAAAAAAEuq":{"file_name":["client.py"],"function_name":["getresponse"],"function_offset":[58],"line_number":[1389]},"GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w":{"file_name":["client.py"],"function_name":["__init__"],"function_offset":[28],"line_number":[276]},"_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI":{"file_name":["socket.py"],"function_name":["makefile"],"function_offset":[40],"line_number":[343]},"piWSMQrh4r040D0BPNaJvwAAAAAAZZ-N":{"file_name":[],"function_name":["__sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZYo3":{"file_name":[],"function_name":["___sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXwf":{"file_name":[],"function_name":["____sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjN":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAet8Y":{"file_name":[],"function_name":["udpv6_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAActW-":{"file_name":[],"function_name":["udp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb90r":{"file_name":[],"function_name":["ip_make_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb8Hg":{"file_name":[],"function_name":["__ip_append_data.isra.50"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZdo2":{"file_name":[],"function_name":["sock_alloc_send_pskb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlYi":{"file_name":[],"function_name":["alloc_skb_with_frags"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZjzl":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJr8u":{"file_name":[],"function_name":["__ksize"],"function_offset":[],"line_number":[]},"grZNsSElR5ITq8H2yHCNSwAAAAAAANbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAPAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAFQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAAHVG":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"cBO14nNDW8EW0oaZDaZipwAAAAAAAOiW":{"file_name":["session.py"],"function_name":["_resolve_region_name"],"function_offset":[20],"line_number":[876]},"C64RiOp1JIPwHLB_iHDa0AAAAAAAAHNm":{"file_name":["session.py"],"function_name":["get_config_variable"],"function_offset":[4],"line_number":[253]},"xvApUwdY2y4sFaZRNrMv5gAAAAAAAEoq":{"file_name":["configprovider.py"],"function_name":["get_config_variable"],"function_offset":[19],"line_number":[316]},"vsalcPHh9qLgsdKtk190IAAAAAAAAFQg":{"file_name":["configprovider.py"],"function_name":["provide"],"function_offset":[11],"line_number":[416]},"QsuqlohtoJfpo6vQ6tHa2AAAAAAAANS-":{"file_name":["utils.py"],"function_name":["provide"],"function_offset":[3],"line_number":[116]},"8ep9l3WIVYErRiHtmAdvewAAAAAAANI2":{"file_name":["utils.py"],"function_name":["_get_instance_metadata_region"],"function_offset":[3],"line_number":[121]},"nPWpQrEmCn54Ou0__aZyJAAAAAAAACsQ":{"file_name":["utils.py"],"function_name":["retrieve_region"],"function_offset":[19],"line_number":[172]},"-xcELApECIipEESUIWed9wAAAAAAAC7-":{"file_name":["utils.py"],"function_name":["_get_region"],"function_offset":[9],"line_number":[185]},"L_saUsdri-UdXCut6TdtngAAAAAAAO5i":{"file_name":["utils.py"],"function_name":["_fetch_metadata_token"],"function_offset":[28],"line_number":[400]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAFIW":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"p19NBQ2pky4eRJM7tgeenwAAAAAAALGU":{"file_name":["httpsession.py"],"function_name":["proxy_url_for"],"function_offset":[6],"line_number":[222]},"55ABUc9FqQ0uj-yn-sTq2AAAAAAAAKaI":{"file_name":["parse.py"],"function_name":["urlparse"],"function_offset":[28],"line_number":[393]},"1msFlmxT18lYvJkx-hfGPgAAAAAAAF1K":{"file_name":["parse.py"],"function_name":["urlsplit"],"function_offset":[49],"line_number":[481]},"a5aMcPOeWx28QSVng73nBQAAAAAAAABK":{"file_name":["aws"],"function_name":[""],"function_offset":[13],"line_number":[27]},"inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[2],"line_number":[166]},"Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[3],"line_number":[185]},"cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[8],"line_number":[97]},"T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[23],"line_number":[48]},"lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[1],"line_number":[62]},"SMoSw8cr-PdrIATvljOPrQAAAAAAAABU":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[8],"line_number":[76]},"xaCec3W8F6xlvd_EISI7vwAAAAAAAACA":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[16],"line_number":[29]},"GYpj0RgmHJTfD-_w_Fx69wAAAAAAAABA":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[7],"line_number":[20]},"b78FoZPzgl20nGrU0Zu24gAAAAAAAABU":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[22]},"5ZxW56RI3EOJxqCWjdkdHgAAAAAAAABk":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[12],"line_number":[17]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"7l7IlhF_Z6_Ribw1CW945QAAAAAAAAA8":{"file_name":["ec.py"],"function_name":[""],"function_offset":[8],"line_number":[13]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAAm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[5],"line_number":[291]},"imaY9TOf2pKX0_q1vRTskQAAAAAAAAAg":{"file_name":["pyimod01_archive.py"],"function_name":["__enter__"],"function_offset":[8],"line_number":[87]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAANka":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAEbO":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAAI7O":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAAAmc":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAKbk":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"grikUXlisBLUbeL_OWixIwAAAAAAALZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAN9c":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAAH78":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"Kq9d0b1CBVEQZUtuJtmlJgAAAAAAAAT8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[526]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAPjQ":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAOwU":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKsux":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAALbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAANAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAADQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAJ-e":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"wpss7yv4AvkSwbtctTl0JAAAAAAAAANC":{"file_name":["clidriver.py"],"function_name":["_display_response"],"function_offset":[7],"line_number":[952]},"SLUxdgyFrTF3l4NU1VRO_wAAAAAAAOMY":{"file_name":["formatter.py"],"function_name":["__call__"],"function_offset":[23],"line_number":[91]},"ZOgaFnYiv38tVz-8Hafu3wAAAAAAADCy":{"file_name":["paginate.py"],"function_name":["build_full_result"],"function_offset":[43],"line_number":[487]},"u1Za6xFXDX1Ys5Qeh_gy9QAAAAAAAMWW":{"file_name":["paginate.py"],"function_name":["__iter__"],"function_offset":[16],"line_number":[251]},"uq4_q8agTQ0rkhJvygJ3QAAAAAAAAGag":{"file_name":["paginate.py"],"function_name":["_make_request"],"function_offset":[1],"line_number":[329]},"pK0zxAMiW-X23QjQRVzm5wAAAAAAAOu8":{"file_name":["client.py"],"function_name":["_api_call"],"function_offset":[4],"line_number":[337]},"OP7EiuTwTtWCf_B7a-ZpigAAAAAAAIUk":{"file_name":["client.py"],"function_name":["_make_api_call"],"function_offset":[58],"line_number":[699]},"WyVrojmISSgbkYAxEOnpQwAAAAAAAKcu":{"file_name":["client.py"],"function_name":["_make_request"],"function_offset":[3],"line_number":[704]},"JdWBEAqhrU7LJg0YDuYO0wAAAAAAANaq":{"file_name":["endpoint.py"],"function_name":["make_request"],"function_offset":[3],"line_number":[101]},"cwZEcJVCN5Q4BJdAS3o8fwAAAAAAABLk":{"file_name":["endpoint.py"],"function_name":["_send_request"],"function_offset":[28],"line_number":[157]},"iLNvi1vqLkBP_ehg4QlqeAAAAAAAAJ7U":{"file_name":["endpoint.py"],"function_name":["_get_response"],"function_offset":[18],"line_number":[177]},"guXM5tmjJlv0Ehde0y1DFwAAAAAAAPLs":{"file_name":["endpoint.py"],"function_name":["_do_get_response"],"function_offset":[48],"line_number":[232]},"avBEfFKeFSrhKf93SLNe0QAAAAAAAKtK":{"file_name":["endpoint.py"],"function_name":["_send"],"function_offset":[1],"line_number":[271]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAADQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAABVw":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"aAagm2yDcrnYaqBPCwyu8QAAAAAAAE8g":{"file_name":["awsrequest.py"],"function_name":["copy"],"function_offset":[1],"line_number":[605]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAL_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAOMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAL2-":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"lpUCR1NQj5NOLBg7mvzlqgAAAAAAAPi6":{"file_name":["generatecliskeleton.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAOKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAAT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAABF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAACLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAEu2":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"08DBZKRu4nC_Oi_uT40UHwAAAAAAAOyO":{"file_name":["codecommit.py"],"function_name":[""],"function_offset":[156],"line_number":[157]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAD2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"n74P5OxFm1hAo5ZWtgcKHQAAAAAAALGe":{"file_name":["__init__.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[93]},"zXbqXCWr0lCbi_b24hNBRQAAAAAAAOI0":{"file_name":["pyimod02_importers.py"],"function_name":["find_spec"],"function_offset":[87],"line_number":[302]},"AOM_-6oRTyAxK8W79Wo5aQAAAAAAAErq":{"file_name":["pyimod02_importers.py"],"function_name":["get_filename"],"function_offset":[12],"line_number":[212]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAABc6":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"ik6PIX946fW_erE7uBJlVQAAAAAAABLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAM6e":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAH4C":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAAkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAFci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAHYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE":{"file_name":["application.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAAAQ":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"RDOEyok4432cuMjL10_tugAAAAAAAAEA":{"file_name":["base_events.py"],"function_name":[""],"function_offset":[44],"line_number":[45]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"25JFhMXA0rvP5hfyUpf34wAAAAAAAAAc":{"file_name":["typing.py"],"function_name":["Optional"],"function_offset":[7],"line_number":[479]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAB4":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[24],"line_number":[161]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAJci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAGeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAI58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAADTm":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAKzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAGYa":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAABW2":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAEGM":{"file_name":["client.py"],"function_name":["_get_client_args"],"function_offset":[15],"line_number":[295]},"v_WV3HQYVe0q1Ob-1gtx1AAAAAAAAP0W":{"file_name":["args.py"],"function_name":["get_client_args"],"function_offset":[72],"line_number":[118]},"ka2IKJhpWbD6PA3J3v624wAAAAAAAElW":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"e8Lb_MV93AH-OkvHPPDitgAAAAAAAI5y":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[6],"line_number":[344]},"1vivUE5hL65442lQ9a_ylgAAAAAAAEOi":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[8],"line_number":[486]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKtu":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fCsVLBj60GK9Hf8VtnMcgAAAAAAAADSW":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[5],"line_number":[35]},"54xjnvwS2UtwpSVJMemggAAAAAAAAGsE":{"file_name":[""],"function_name":[""],"function_offset":[0],"line_number":[1]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"qordvIiilnF7CmkWCAd7eAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"okgAOHfDrcA806m5xh4DMAAAAAAAAACs":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAAMLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAC8C":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"aRRT4_vBG9Q4nqyirWo5FAAAAAAAAJZa":{"file_name":["codedeploy.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4":{"file_name":["abc.py"],"function_name":[""],"function_offset":[267],"line_number":[268]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAG6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAAMhK":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"ZyAwfhB8pqBFv6xiDVdvPQAAAAAAAKh2":{"file_name":["credentials.py"],"function_name":[""],"function_offset":[553],"line_number":[554]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAN2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"9alsKcnSosScCQ3ntwGT5wAAAAAAAKlg":{"file_name":["_bootstrap_external.py"],"function_name":["find_spec"],"function_offset":[22],"line_number":[1518]},"xAINw9zPBhJlledr3DAcGAAAAAAAAK4I":{"file_name":["_bootstrap_external.py"],"function_name":["_get_spec"],"function_offset":[29],"line_number":[1493]},"xVweU0pD8q051c2YgF4PTwAAAAAAAH1m":{"file_name":["_bootstrap_external.py"],"function_name":["find_spec"],"function_offset":[43],"line_number":[1647]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAOAO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"d4jl580PLMUwu5s3I4wcXgAAAAAAAISu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"tKago5vqLnwIkezk_wTBpQAAAAAAAOfq":{"file_name":["package.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAF6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAALg6":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAAJDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAAKO6":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAJkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAKYy":{"file_name":["auth.py"],"function_name":[""],"function_offset":[603],"line_number":[604]},"y9R94bQUxts02WzRWfV7xgAAAAAAAC_y":{"file_name":["auth.py"],"function_name":[""],"function_offset":[316],"line_number":[317]},"uI6css-d8SGQRK6a_Ntl-AAAAAAAAD3e":{"file_name":["auth.py"],"function_name":[""],"function_offset":[336],"line_number":[337]},"SlnkBp0IIJFLHVOe4KbxwQAAAAAAAJLa":{"file_name":["http.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"7wBb3xHP1JZHNBpMGh4EdAAAAAAAADGa":{"file_name":["io.py"],"function_name":[""],"function_offset":[408],"line_number":[409]},"u3fGdgL6eAYjYSRbRUri0gAAAAAAAFUY":{"file_name":["io.py"],"function_name":["SocketDomain"],"function_offset":[3],"line_number":[194]},"aG0mH34tM6si5c1l397JVQAAAAAAAOwA":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[93],"line_number":[457]},"GC-VoGaqaEobPzimayHQTQAAAAAAANdk":{"file_name":["enum.py"],"function_name":["_is_sunder"],"function_offset":[4],"line_number":[62]},"PmhxUKv5sePRxhCBONca8gAAAAAAAID6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"ik6PIX946fW_erE7uBJlVQAAAAAAAPLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"UfGck3qA2qF0xFB5gpY4HgAAAAAAAH72":{"file_name":["base.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"G9ShE3ODivDEFyHVdsnZ_gAAAAAAABn-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"6AsJ0dA2BUqaic-ScDJBMAAAAAAAACOm":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"fr52ZDCgnkPZlzTNdLTQ5wAAAAAAAGnS":{"file_name":["base.py"],"function_name":[""],"function_offset":[167],"line_number":[168]},"uqoEOAkLp1toolLH0q5LVwAAAAAAAJmm":{"file_name":["mouse_events.py"],"function_name":[""],"function_offset":[63],"line_number":[64]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAJ42":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"WjtMXFj0eujpoknR_rynvAAAAAAAACba":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[800],"line_number":[801]},"Vot4T3F5OpUj8rbXhgpMDgAAAAAAAO8I":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[4],"line_number":[938]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAEtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"EPS0ql6FPdCQLe9KByvDQAAAAAAAAMgy":{"file_name":["traceback.py"],"function_name":[""],"function_offset":[328],"line_number":[329]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAKSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAKJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAAKJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAKA4":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAJp8":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"V6gUZHzBRISi-Z25klK5DQAAAAAAAKri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"zWNEoAKVTnnzSns045VKhwAAAAAAAMsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAAEfO":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"XVsKc4e32xXUv-3uv2s-8QAAAAAAACny":{"file_name":["defaults.py"],"function_name":["emacs_state"],"function_offset":[32],"line_number":[33]},"uPGvGNXBf1JXGeeDSsmGQAAAAAAAALX2":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[194],"line_number":[679]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"OwrnTUowquMzuETYoP67yQAAAAAAAAAe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[4],"line_number":[5]},"HmAocvtnsxREZJIec2I5gwAAAAAAAAA4":{"file_name":["__init__.py"],"function_name":["HTTPStatus"],"function_offset":[41],"line_number":[46]},"KHDki7BxJPyjGLtvY8M5lQAAAAAAAAF-":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[64],"line_number":[152]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAL5W":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"XlQ19HBD_RNa2r3QWOR-nAAAAAAAAP1u":{"file_name":["commands.py"],"function_name":[""],"function_offset":[127],"line_number":[128]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VuJFonCXevADcEDW6NVbKgAAAAAAAGsG":{"file_name":["devcommands.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAMsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAAOMa":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAH2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"it1vvnZdXdzy0fFROnaaOQAAAAAAALTQ":{"file_name":["_bootstrap.py"],"function_name":["find_spec"],"function_offset":[28],"line_number":[950]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAOL2":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"XlQ19HBD_RNa2r3QWOR-nAAAAAAAAL1u":{"file_name":["commands.py"],"function_name":[""],"function_offset":[127],"line_number":[128]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAARw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAABHq":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALC4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAAM8O":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"gZooqVYiItnHim-lK4feOgAAAAAAANN-":{"file_name":["_bootstrap.py"],"function_name":["_init_module_attrs"],"function_offset":[70],"line_number":[563]},"UfGck3qA2qF0xFB5gpY4HgAAAAAAABTm":{"file_name":["base.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"G9ShE3ODivDEFyHVdsnZ_gAAAAAAABs-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"6AsJ0dA2BUqaic-ScDJBMAAAAAAAABbq":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VY0EiAO0DxwLRTE4PfFhdwAAAAAAAOMW":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"A8AozG5gQfEN24i4IE7w5wAAAAAAACgG":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[21],"line_number":[22]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAKKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"V6gUZHzBRISi-Z25klK5DQAAAAAAACri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"zWNEoAKVTnnzSns045VKhwAAAAAAAIsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"PmhxUKv5sePRxhCBONca8gAAAAAAAAD6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAEu":{"file_name":["client.py"],"function_name":[""],"function_offset":[1396],"line_number":[1397]},"OPpnYj88CDOiKneikdGPHAAAAAAAAAF-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[138],"line_number":[142]},"ZJjPF65K8mBuISvhCfKfBgAAAAAAAAB4":{"file_name":["enum.py"],"function_name":["_convert_"],"function_offset":[27],"line_number":[555]},"xLxhp_367a_SbgOYuEJjlwAAAAAAAAAm":{"file_name":["enum.py"],"function_name":["__call__"],"function_offset":[28],"line_number":[386]},"QHotkhNTqx5C4Kjd2F2_6wAAAAAAAAEC":{"file_name":["enum.py"],"function_name":["_create_"],"function_offset":[35],"line_number":[510]},"Ht79I_xqXv3bOgaClTNQ4wAAAAAAAAKS":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[122],"line_number":[301]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAALV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAER-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAPq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAFiO":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"aD-GPAkaW-Swis8ybNgyMQAAAAAAAIjQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[455],"line_number":[456]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAACO-":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAAMwW":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAALze":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAAuy":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAKLy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAISc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAIJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAAGVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIFK":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIai":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAH1i":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAAJom":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAABtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"zWNEoAKVTnnzSns045VKhwAAAAAAAAsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAAL2e":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"lTFhQHSZwvS4-s94KVv5mAAAAAAAABAw":{"file_name":["renderer.py"],"function_name":[""],"function_offset":[85],"line_number":[86]},"IcJVDEq52FRv22q0yHVMawAAAAAAACL6":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[6],"line_number":[351]},"BDtQyw375W96A0PA_Z7SDQAAAAAAAOUy":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[7],"line_number":[1557]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5":{"file_name":[],"function_name":["prep_new_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgURI":{"file_name":[],"function_name":["clear_page_erms"],"function_offset":[],"line_number":[]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAEHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAM10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAI_q":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"skFt9oVHBFfMDC1On4IJhgAAAAAAAHg6":{"file_name":["ddb.py"],"function_name":[""],"function_offset":[26],"line_number":[27]},"g5zhfSuJlGbmNqPl5Qb2wgAAAAAAALga":{"file_name":["subcommands.py"],"function_name":[""],"function_offset":[64],"line_number":[65]},"UoMth5MLnZ-vUHeTplwEvAAAAAAAAMqu":{"file_name":["params.py"],"function_name":[""],"function_offset":[226],"line_number":[227]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABfe":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAMui":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2":{"file_name":["_parser.py"],"function_name":["__len__"],"function_offset":[1],"line_number":[159]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAP0G":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEZ6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAAo6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAANnI":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAGSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAGOg":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OlTvyWQFXjOweJcs3kiGygAAAAAAACIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAAKJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAGSk":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAABtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALk8":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zpgqltXEgKujOhJUj-jAhgAAAAAAAKBE":{"file_name":["_parser.py"],"function_name":["__getitem__"],"function_offset":[3],"line_number":[165]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"6GGFIt18C0VByIn0h-PdeQAAAAAAAGoO":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"SA64oIT_DC3uHXf7ZjFqkwAAAAAAAKVS":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[48],"line_number":[49]},"akZOzI9XwsEixvkTDGeDPwAAAAAAAHZa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAPKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAHcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAACD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAADAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAGYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAJee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAAW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAFj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAMdS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"AtF9VdLKnFQvB9H1lsFPjAAAAAAAALka":{"file_name":["parser.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"Pf1McBfrZjVj1CxRZBq6YwAAAAAAAEwy":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[443],"line_number":[444]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnNL":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADky8":{"file_name":[],"function_name":["down_read_trylock"],"function_offset":[],"line_number":[]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"XkOSW26Xa6_lkqHv5givKgAAAAAAANim":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAPmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"vkeP2ntYyoFN0A16x9eliwAAAAAAAHPE":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAk":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[22],"line_number":[27]},"H5LY_MytOVgyAawi8TymCgAAAAAAAAAQ":{"file_name":["_policybase.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"kUJz0cDHgh-y1O5Hi8equAAAAAAAAAAw":{"file_name":["header.py"],"function_name":[""],"function_offset":[14],"line_number":[19]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAALcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAGD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAHAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fj70ljef7nDHOqVJGSIoEQAAAAAAACxi":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"AtF9VdLKnFQvB9H1lsFPjAAAAAAAADka":{"file_name":["parser.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"Pf1McBfrZjVj1CxRZBq6YwAAAAAAAFZy":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[443],"line_number":[444]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAOG-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEJE":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAADzu":{"file_name":[],"function_name":["exit_to_usermode_loop"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACrrD":{"file_name":[],"function_name":["task_work_run"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhsk":{"file_name":[],"function_name":["__fput"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAO4n8":{"file_name":[],"function_name":["xfs_release"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOdwM":{"file_name":[],"function_name":["xfs_free_eofblocks"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAANnCL":{"file_name":[],"function_name":["xfs_bmapi_read"],"function_offset":[],"line_number":[]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAACy":{"file_name":["errors.py"],"function_name":[""],"function_offset":[45],"line_number":[50]}},"executables":{"edNJ10OjHiWc5nzuTQdvig":"linux-vdso.so.1","LvhLWomlc0dSPYzQ8C620g":"controller","j8DVIOTu7Btj9lgFefJ84A":"dockerd","QvG8QEGAld88D676NL_Y2Q":"filebeat","B8JRxL079xbhqQBqGvksAg":"kubelet","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","v6HIzNa4K6G4nRP9032RIA":"dockerd","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","QaIvzvU8UoclQMd_OMt-Pg":"elastic-operator","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","kajOqZqz7V1y0BdYQLFQrw":"containerd-shim-runc-v2","9LzzIocepYcOjnUsLlgOjg":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","A2oiHVwisByxRn5RDT4LjA":"vmlinux","w5zBqPf1_9mIVEf-Rn7EdA":"systemd","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","OTWX4UsOVMrSIF5cD4zUzg":"libmount.so.1.1.0","LHNvPtcKBt87cCBX8aTNhQ":"overlay","67s2TwiMngM0yin5Y8pvEg":"containerd","piWSMQrh4r040D0BPNaJvw":"vmlinux","SbPwzb_Kog2bWn8uc7xhDQ":"aws","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","9HZ7GQCC6G9fZlRD7aGzXQ":"libssl.so.1.0.2k","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","6miIyyucTZf5zXHCk7PT1g":"veth","G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","JsObMPhfT_zO2Q_B1cPLxA":"coredns","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","dGWvVtQJJ5wuqNyQVpi8lA":"zlib.cpython-311-x86_64-linux-gnu.so"},"total_frames":198526,"sampling_rate":0.0016000000000000003} diff --git a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_60s_1x.json b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_60s_1x.json deleted file mode 100644 index 8a5c1acf7f93..000000000000 --- a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_60s_1x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"YdDJxgmO4Qwjr0AEbbpw5g":3,"ARUlXLnccHmzguHUjXRt-A":7,"fsUmzqifyqwKCmzKO1INZQ":24,"z_Kbu_3KsKjzL49rf-CSTA":94,"RpSSZ069-ac11a4PUFolMA":101,"H4U5LLhN4L_4fDVbcrz30A":57,"8jSwzubV-3-vgAsXwII0kA":26,"43tbk4XHS6h_eSSkozr2lQ":33,"1Hf53oSb-zH-2QD2FYxgyA":27,"ER-x6xVv257WtFQAI5qb9g":47,"Hr1OSWigQhS4BD9n1H0fVw":40,"g1qDjUCVlmghGHVDrjeDvw":44,"XU0AYWfaWEgxn6HS3Npe0Q":42,"Xi_OuuwxmtjxVLfRnOKl-w":43,"j3pRZrJva_6zVfPpTrRgMQ":34,"B0rzVoKcdftibP3e40EU_g":39,"jHWwY4al2R105ljWitJf8Q":51,"JFrKrVm1b8YVyjTALHwFPQ":17,"UkNqUaLVbzZ-0N4mRSSfPA":7,"EH1ElzcXDEuDqu7McdrBdQ":17,"VyF1fKBkXgRmNRnKNEu8Fw":23,"naNkvUaKAyxw8L7AmrJp_A":25,"INCPC3idrKxHgrRrb5yK7w":18,"4-XWrzbKLiMzMN29SCKUhA":18,"oazzZOrFVKPzoEMEINIH2g":14,"bgW4z1P_qeyGZ-BNg-EtzA":21,"_7muG2H-TTX5D3mi3LROgw":17,"nKCqWW03DZONEM_Nq2LvwQ":6,"08TjeY9jNFfBuPDWZvzcGA":16,"41gF_giRSTRZMXWPVpvLYA":10,"CCCw9Z7XCAUBXfzhCKjvyQ":12,"RK2MfkyDuA83Ote1DRpnig":9,"E9YrFLZE6ytYTLr5nOdeqA":8,"OaI2ikXPfU9oPJVr7qHqRA":6,"BeervgrHDOwHnECUdx-R1Q":1,"_E7kI3XeP50ndUGgLwozRw":1,"PiAbunsxsTWIrlVv5AJCxQ":2,"gcylfs4yiiRtiY_AHc1fkQ":2,"2J6chKI2om9Kbvwi1SgqlA":1,"YX2R7C2iz4FGt5q5Tnk6TA":1,"--7TGRswVMtk5qWYdGBDUw":1,"iVZ81pgajC_4cYBykPWgBg":1,"dg33Fg5TLDtB9bOuPSPREA":1},"stack_traces":{"YdDJxgmO4Qwjr0AEbbpw5g":{"address_or_lines":[2371],"file_ids":["Ij7mO1SCteAnvtNe95RpEg"],"frame_ids":["Ij7mO1SCteAnvtNe95RpEgAAAAAAAAlD"],"type_ids":[3]},"ARUlXLnccHmzguHUjXRt-A":{"address_or_lines":[4651602,2352],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","Ij7mO1SCteAnvtNe95RpEg"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARvpS","Ij7mO1SCteAnvtNe95RpEgAAAAAAAAkw"],"type_ids":[3,3]},"fsUmzqifyqwKCmzKO1INZQ":{"address_or_lines":[32434917,32101228,32118123],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6hVr"],"type_ids":[3,3,3]},"z_Kbu_3KsKjzL49rf-CSTA":{"address_or_lines":[4646312,4318297,4332979,4334816],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQeRZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAQh2z","FWZ9q3TQKZZok58ua1HDsgAAAAAAQiTg"],"type_ids":[3,3,3,3]},"RpSSZ069-ac11a4PUFolMA":{"address_or_lines":[4646178,4471372,4470064,4464366,4415263],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuUi","FWZ9q3TQKZZok58ua1HDsgAAAAAARDpM","FWZ9q3TQKZZok58ua1HDsgAAAAAARDUw","FWZ9q3TQKZZok58ua1HDsgAAAAAARB7u","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ18f"],"type_ids":[3,3,3,3,3]},"H4U5LLhN4L_4fDVbcrz30A":{"address_or_lines":[12531204,12361900,12360536,12355924,12307483,12548548],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAvzYE","67s2TwiMngM0yin5Y8pvEgAAAAAAvKCs","67s2TwiMngM0yin5Y8pvEgAAAAAAvJtY","67s2TwiMngM0yin5Y8pvEgAAAAAAvIlU","67s2TwiMngM0yin5Y8pvEgAAAAAAu8wb","67s2TwiMngM0yin5Y8pvEgAAAAAAv3nE"],"type_ids":[3,3,3,3,3,3]},"8jSwzubV-3-vgAsXwII0kA":{"address_or_lines":[4635624,4317996,4333118,4324708,4325572,4330137,4587439],"file_ids":["-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw"],"frame_ids":["-1kQFVGzdQWpzLSZ9TRmnwAAAAAARrvo","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQeMs","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQh4-","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQf1k","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQgDE","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQhKZ","-1kQFVGzdQWpzLSZ9TRmnwAAAAAARf-v"],"type_ids":[3,3,3,3,3,3,3]},"43tbk4XHS6h_eSSkozr2lQ":{"address_or_lines":[18515232,22597677,22574090,22556393,22530363,22106663,22101077,22107662],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHQK","v6HIzNa4K6G4nRP9032RIAAAAAABWC7p","v6HIzNa4K6G4nRP9032RIAAAAAABV8k7","v6HIzNa4K6G4nRP9032RIAAAAAABUVIn","v6HIzNa4K6G4nRP9032RIAAAAAABUTxV","v6HIzNa4K6G4nRP9032RIAAAAAABUVYO"],"type_ids":[3,3,3,3,3,3,3,3]},"1Hf53oSb-zH-2QD2FYxgyA":{"address_or_lines":[4636706,4469836,4468509,4463096,4465892,4469227,4567193,4567640,5020934],"file_ids":["LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g"],"frame_ids":["LvhLWomlc0dSPYzQ8C620gAAAAAARsAi","LvhLWomlc0dSPYzQ8C620gAAAAAARDRM","LvhLWomlc0dSPYzQ8C620gAAAAAARC8d","LvhLWomlc0dSPYzQ8C620gAAAAAARBn4","LvhLWomlc0dSPYzQ8C620gAAAAAARCTk","LvhLWomlc0dSPYzQ8C620gAAAAAARDHr","LvhLWomlc0dSPYzQ8C620gAAAAAARbCZ","LvhLWomlc0dSPYzQ8C620gAAAAAARbJY","LvhLWomlc0dSPYzQ8C620gAAAAAATJ0G"],"type_ids":[3,3,3,3,3,3,3,3,3]},"ER-x6xVv257WtFQAI5qb9g":{"address_or_lines":[4643592,4325284,4340382,4331972,4332836,4337401,4594856,4566419,4563908,4561911],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjqe","B8JRxL079xbhqQBqGvksAgAAAAAAQhnE","B8JRxL079xbhqQBqGvksAgAAAAAAQh0k","B8JRxL079xbhqQBqGvksAgAAAAAAQi75","B8JRxL079xbhqQBqGvksAgAAAAAARhyo","B8JRxL079xbhqQBqGvksAgAAAAAARa2T","B8JRxL079xbhqQBqGvksAgAAAAAARaPE","B8JRxL079xbhqQBqGvksAgAAAAAARZv3"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"Hr1OSWigQhS4BD9n1H0fVw":{"address_or_lines":[4646178,4471372,4470064,4464366,4415320,4209576,4209709,10485923,16807,3096172,3095028],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuUi","FWZ9q3TQKZZok58ua1HDsgAAAAAARDpM","FWZ9q3TQKZZok58ua1HDsgAAAAAARDUw","FWZ9q3TQKZZok58ua1HDsgAAAAAARB7u","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ19Y","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDuo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAALz5s","ew01Dk0sWZctP-VaEpavqQAAAAAALzn0"],"type_ids":[3,3,3,3,3,3,3,4,4,4,4]},"g1qDjUCVlmghGHVDrjeDvw":{"address_or_lines":[18425604,18258924,18257560,18253668,18248332,18043494,18206037,18442402,10485923,16743,1221731,1219041],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGScE","j8DVIOTu7Btj9lgFefJ84AAAAAABFpvs","j8DVIOTu7Btj9lgFefJ84AAAAAABFpaY","j8DVIOTu7Btj9lgFefJ84AAAAAABFodk","j8DVIOTu7Btj9lgFefJ84AAAAAABFnKM","j8DVIOTu7Btj9lgFefJ84AAAAAABE1Jm","j8DVIOTu7Btj9lgFefJ84AAAAAABFc1V","j8DVIOTu7Btj9lgFefJ84AAAAAABGWii","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEpnh"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4]},"XU0AYWfaWEgxn6HS3Npe0Q":{"address_or_lines":[18506340,18339660,18338296,18334404,18329068,18124198,18286773,18523138,10485923,16807,1222099,1220257,1210315],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGmJk","v6HIzNa4K6G4nRP9032RIAAAAAABF9dM","v6HIzNa4K6G4nRP9032RIAAAAAABF9H4","v6HIzNa4K6G4nRP9032RIAAAAAABF8LE","v6HIzNa4K6G4nRP9032RIAAAAAABF63s","v6HIzNa4K6G4nRP9032RIAAAAAABFI2m","v6HIzNa4K6G4nRP9032RIAAAAAABFwi1","v6HIzNa4K6G4nRP9032RIAAAAAABGqQC","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h","ew01Dk0sWZctP-VaEpavqQAAAAAAEnfL"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4]},"Xi_OuuwxmtjxVLfRnOKl-w":{"address_or_lines":[4643332,4460312,4460498,4495428,4495848,4496542,4426254,4658837,10485923,16807,633597,633524,633342,631364],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARtoE","6auiCMWq5cA-hAbqSYvdQQAAAAAARA8Y","6auiCMWq5cA-hAbqSYvdQQAAAAAARA_S","6auiCMWq5cA-hAbqSYvdQQAAAAAARJhE","6auiCMWq5cA-hAbqSYvdQQAAAAAARJno","6auiCMWq5cA-hAbqSYvdQQAAAAAARJye","6auiCMWq5cA-hAbqSYvdQQAAAAAAQ4oO","6auiCMWq5cA-hAbqSYvdQQAAAAAARxaV","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAACar9","ew01Dk0sWZctP-VaEpavqQAAAAAACaq0","ew01Dk0sWZctP-VaEpavqQAAAAAACan-","ew01Dk0sWZctP-VaEpavqQAAAAAACaJE"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4,4]},"j3pRZrJva_6zVfPpTrRgMQ":{"address_or_lines":[4435309,4435559,4470649,4243696,4243480,4398678,4639074,10485923,16807,1222099,1220257,1210438,1210021,1207727,1205915],"file_ids":["gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["gfRL5jyxmWedM28UI08hFQAAAAAAQ61t","gfRL5jyxmWedM28UI08hFQAAAAAAQ65n","gfRL5jyxmWedM28UI08hFQAAAAAARDd5","gfRL5jyxmWedM28UI08hFQAAAAAAQMDw","gfRL5jyxmWedM28UI08hFQAAAAAAQMAY","gfRL5jyxmWedM28UI08hFQAAAAAAQx5W","gfRL5jyxmWedM28UI08hFQAAAAAARsli","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h","ew01Dk0sWZctP-VaEpavqQAAAAAAEnhG","ew01Dk0sWZctP-VaEpavqQAAAAAAEnal","ew01Dk0sWZctP-VaEpavqQAAAAAAEm2v","ew01Dk0sWZctP-VaEpavqQAAAAAAEmab"],"type_ids":[3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"B0rzVoKcdftibP3e40EU_g":{"address_or_lines":[4594276,4428280,4428466,4462056,4242611,4242276,4392174,4610690,10485923,16743,1221731,1219889,1210331,1133072,1132968,8474365],"file_ids":["1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["1QjX8mEQC0-5qYXzadOESAAAAAAARhpk","1QjX8mEQC0-5qYXzadOESAAAAAAAQ5H4","1QjX8mEQC0-5qYXzadOESAAAAAAAQ5Ky","1QjX8mEQC0-5qYXzadOESAAAAAAARBXo","1QjX8mEQC0-5qYXzadOESAAAAAAAQLyz","1QjX8mEQC0-5qYXzadOESAAAAAAAQLtk","1QjX8mEQC0-5qYXzadOESAAAAAAAQwTu","1QjX8mEQC0-5qYXzadOESAAAAAAARlqC","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEp0x","piWSMQrh4r040D0BPNaJvwAAAAAAEnfb","piWSMQrh4r040D0BPNaJvwAAAAAAEUoQ","piWSMQrh4r040D0BPNaJvwAAAAAAEUmo","piWSMQrh4r040D0BPNaJvwAAAAAAgU79"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"jHWwY4al2R105ljWitJf8Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584294],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj6m"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"JFrKrVm1b8YVyjTALHwFPQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000312,40003155,27960932,18154776,18503217],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYls4","v6HIzNa4K6G4nRP9032RIAAAAAACYmZT","v6HIzNa4K6G4nRP9032RIAAAAAABqqZk","v6HIzNa4K6G4nRP9032RIAAAAAABFQUY","v6HIzNa4K6G4nRP9032RIAAAAAABGlYx"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"UkNqUaLVbzZ-0N4mRSSfPA":{"address_or_lines":[4652224,31039781,31054085,31056132,31058408,31449931,30791268,25539462,25547885,25549299,25502704,25503492,25480821,25481061,4953508,4960780,4898318,4893650,4898126],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAAB2aEl","wfA2BgwfDNXUWsxkJ083RwAAAAAB2dkF","wfA2BgwfDNXUWsxkJ083RwAAAAAB2eEE","wfA2BgwfDNXUWsxkJ083RwAAAAAB2eno","wfA2BgwfDNXUWsxkJ083RwAAAAAB3-NL","wfA2BgwfDNXUWsxkJ083RwAAAAAB1dZk","wfA2BgwfDNXUWsxkJ083RwAAAAABhbOG","wfA2BgwfDNXUWsxkJ083RwAAAAABhdRt","wfA2BgwfDNXUWsxkJ083RwAAAAABhdnz","wfA2BgwfDNXUWsxkJ083RwAAAAABhSPw","wfA2BgwfDNXUWsxkJ083RwAAAAABhScE","wfA2BgwfDNXUWsxkJ083RwAAAAABhM51","wfA2BgwfDNXUWsxkJ083RwAAAAABhM9l","wfA2BgwfDNXUWsxkJ083RwAAAAAAS5Wk","wfA2BgwfDNXUWsxkJ083RwAAAAAAS7IM","wfA2BgwfDNXUWsxkJ083RwAAAAAASr4O","wfA2BgwfDNXUWsxkJ083RwAAAAAASqvS","wfA2BgwfDNXUWsxkJ083RwAAAAAASr1O"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"EH1ElzcXDEuDqu7McdrBdQ":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297413,7309604,7297924,5094553],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1mF","B8JRxL079xbhqQBqGvksAgAAAAAAb4kk","B8JRxL079xbhqQBqGvksAgAAAAAAb1uE","B8JRxL079xbhqQBqGvksAgAAAAAATbyZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"VyF1fKBkXgRmNRnKNEu8Fw":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709512,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16807,2741196,2827770,2817684,2805156,3382963],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEI","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7A6","B8JRxL079xbhqQBqGvksAgAAAAAASFtz","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k","A2oiHVwisByxRn5RDT4LjAAAAAAAM56z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"naNkvUaKAyxw8L7AmrJp_A":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602139,24420574,24417550,19100458,18003551],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8Xgb","j8DVIOTu7Btj9lgFefJ84AAAAAABdKDe","j8DVIOTu7Btj9lgFefJ84AAAAAABdJUO","j8DVIOTu7Btj9lgFefJ84AAAAAABI3Mq","j8DVIOTu7Btj9lgFefJ84AAAAAABErZf"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"INCPC3idrKxHgrRrb5yK7w":{"address_or_lines":[4652224,22357367,22385134,22366798,57079599,58878037,58675517,58634660,58648701,31265316,7372944,7295421,7297245,7300762,7297188,7304836,7297245,7300762,7297188,7304836,7297413,7310803,7320503],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAABVSV3","wfA2BgwfDNXUWsxkJ083RwAAAAABVZHu","wfA2BgwfDNXUWsxkJ083RwAAAAABVUpO","wfA2BgwfDNXUWsxkJ083RwAAAAADZvcv","wfA2BgwfDNXUWsxkJ083RwAAAAADgmhV","wfA2BgwfDNXUWsxkJ083RwAAAAADf1E9","wfA2BgwfDNXUWsxkJ083RwAAAAADfrGk","wfA2BgwfDNXUWsxkJ083RwAAAAADfuh9","wfA2BgwfDNXUWsxkJ083RwAAAAAB3RIk","wfA2BgwfDNXUWsxkJ083RwAAAAAAcICQ","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1G9","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1jd","wfA2BgwfDNXUWsxkJ083RwAAAAAAb2aa","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1ik","wfA2BgwfDNXUWsxkJ083RwAAAAAAb3aE","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1jd","wfA2BgwfDNXUWsxkJ083RwAAAAAAb2aa","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1ik","wfA2BgwfDNXUWsxkJ083RwAAAAAAb3aE","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1mF","wfA2BgwfDNXUWsxkJ083RwAAAAAAb43T","wfA2BgwfDNXUWsxkJ083RwAAAAAAb7O3"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"4-XWrzbKLiMzMN29SCKUhA":{"address_or_lines":[4652224,31041029,31055333,31057380,31059656,31451286,31449907,25120346,25115948,4970003,4971223,4754617,4757981,4219698,4219725,10485923,16807,2777344,2775602,2826949,2809805,2807527,2804929,2869997],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAB2aYF","6auiCMWq5cA-hAbqSYvdQQAAAAAB2d3l","6auiCMWq5cA-hAbqSYvdQQAAAAAB2eXk","6auiCMWq5cA-hAbqSYvdQQAAAAAB2e7I","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-iW","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-Mz","6auiCMWq5cA-hAbqSYvdQQAAAAABf05a","6auiCMWq5cA-hAbqSYvdQQAAAAABfz0s","6auiCMWq5cA-hAbqSYvdQQAAAAAAS9YT","6auiCMWq5cA-hAbqSYvdQQAAAAAAS9rX","6auiCMWq5cA-hAbqSYvdQQAAAAAASIy5","6auiCMWq5cA-hAbqSYvdQQAAAAAASJnd","6auiCMWq5cA-hAbqSYvdQQAAAAAAQGMy","6auiCMWq5cA-hAbqSYvdQQAAAAAAQGNN","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKmEA","ew01Dk0sWZctP-VaEpavqQAAAAAAKloy","ew01Dk0sWZctP-VaEpavqQAAAAAAKyLF","ew01Dk0sWZctP-VaEpavqQAAAAAAKt_N","ew01Dk0sWZctP-VaEpavqQAAAAAAKtbn","ew01Dk0sWZctP-VaEpavqQAAAAAAKszB","ew01Dk0sWZctP-VaEpavqQAAAAAAK8rt"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"oazzZOrFVKPzoEMEINIH2g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696100,20084005,20770646,20784592],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNUk","j8DVIOTu7Btj9lgFefJ84AAAAAABMnUl","j8DVIOTu7Btj9lgFefJ84AAAAAABPO9W","j8DVIOTu7Btj9lgFefJ84AAAAAABPSXQ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"bgW4z1P_qeyGZ-BNg-EtzA":{"address_or_lines":[43732576,54345578,54346325,54347573,52524033,52636324,52637912,52417621,52420674,52436132,51874398,51910204,51902690,51903112,51905980,51885853,51874436,51883428,51874436,51883428,51874436,51883398,51839246,52405829,52404692,44450492],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAADPT9q","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUJV","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUc1","MNBJ5seVz_ocW6tcr1HSmwAAAAADIXQB","MNBJ5seVz_ocW6tcr1HSmwAAAAADIyqk","MNBJ5seVz_ocW6tcr1HSmwAAAAADIzDY","MNBJ5seVz_ocW6tcr1HSmwAAAAADH9RV","MNBJ5seVz_ocW6tcr1HSmwAAAAADH-BC","MNBJ5seVz_ocW6tcr1HSmwAAAAADIByk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4pe","MNBJ5seVz_ocW6tcr1HSmwAAAAADGBY8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_ji","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_qI","MNBJ5seVz_ocW6tcr1HSmwAAAAADGAW8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF7cd","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62k","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62k","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62G","MNBJ5seVz_ocW6tcr1HSmwAAAAADFwEO","MNBJ5seVz_ocW6tcr1HSmwAAAAADH6ZF","MNBJ5seVz_ocW6tcr1HSmwAAAAADH6HU","MNBJ5seVz_ocW6tcr1HSmwAAAAACpkK8"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"_7muG2H-TTX5D3mi3LROgw":{"address_or_lines":[4652224,31041029,31055333,31057380,31059656,31451179,30792516,25540230,25548731,25550840,25503472,25504260,25481372,25481181,25484711,25484964,4951332,4960527,4959954,4897957,4893996,4627954,4660663,10485923,16807,3103928,3101167],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAB2aYF","6auiCMWq5cA-hAbqSYvdQQAAAAAB2d3l","6auiCMWq5cA-hAbqSYvdQQAAAAAB2eXk","6auiCMWq5cA-hAbqSYvdQQAAAAAB2e7I","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-gr","6auiCMWq5cA-hAbqSYvdQQAAAAAB1dtE","6auiCMWq5cA-hAbqSYvdQQAAAAABhbaG","6auiCMWq5cA-hAbqSYvdQQAAAAABhde7","6auiCMWq5cA-hAbqSYvdQQAAAAABhd_4","6auiCMWq5cA-hAbqSYvdQQAAAAABhSbw","6auiCMWq5cA-hAbqSYvdQQAAAAABhSoE","6auiCMWq5cA-hAbqSYvdQQAAAAABhNCc","6auiCMWq5cA-hAbqSYvdQQAAAAABhM_d","6auiCMWq5cA-hAbqSYvdQQAAAAABhN2n","6auiCMWq5cA-hAbqSYvdQQAAAAABhN6k","6auiCMWq5cA-hAbqSYvdQQAAAAAAS40k","6auiCMWq5cA-hAbqSYvdQQAAAAAAS7EP","6auiCMWq5cA-hAbqSYvdQQAAAAAAS67S","6auiCMWq5cA-hAbqSYvdQQAAAAAASryl","6auiCMWq5cA-hAbqSYvdQQAAAAAASq0s","6auiCMWq5cA-hAbqSYvdQQAAAAAARp3y","6auiCMWq5cA-hAbqSYvdQQAAAAAARx23","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAL1y4","ew01Dk0sWZctP-VaEpavqQAAAAAAL1Hv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"nKCqWW03DZONEM_Nq2LvwQ":{"address_or_lines":[12540096,19004791,19032250,19014236,19907031,31278974,31279321,31305795,31279321,31290406,31279321,31317002,19907351,21668882,21654220,21663244,21662923,16321295,16318241,16372475,15847297,16321906,16318704,15818442,15818729,12152742,12151794,12187561],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAv1jA","67s2TwiMngM0yin5Y8pvEgAAAAABIf13","67s2TwiMngM0yin5Y8pvEgAAAAABImi6","67s2TwiMngM0yin5Y8pvEgAAAAABIiJc","67s2TwiMngM0yin5Y8pvEgAAAAABL8HX","67s2TwiMngM0yin5Y8pvEgAAAAAB3Ud-","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3bBD","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3XQm","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3dwK","67s2TwiMngM0yin5Y8pvEgAAAAABL8MX","67s2TwiMngM0yin5Y8pvEgAAAAABSqQS","67s2TwiMngM0yin5Y8pvEgAAAAABSmrM","67s2TwiMngM0yin5Y8pvEgAAAAABSo4M","67s2TwiMngM0yin5Y8pvEgAAAAABSozL","67s2TwiMngM0yin5Y8pvEgAAAAAA-QsP","67s2TwiMngM0yin5Y8pvEgAAAAAA-P8h","67s2TwiMngM0yin5Y8pvEgAAAAAA-dL7","67s2TwiMngM0yin5Y8pvEgAAAAAA8c-B","67s2TwiMngM0yin5Y8pvEgAAAAAA-Q1y","67s2TwiMngM0yin5Y8pvEgAAAAAA-QDw","67s2TwiMngM0yin5Y8pvEgAAAAAA8V7K","67s2TwiMngM0yin5Y8pvEgAAAAAA8V_p","67s2TwiMngM0yin5Y8pvEgAAAAAAuW-m","67s2TwiMngM0yin5Y8pvEgAAAAAAuWvy","67s2TwiMngM0yin5Y8pvEgAAAAAAufep"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"08TjeY9jNFfBuPDWZvzcGA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708845,24702901,19816356,19817629,19819812,19827076,19819869,19823237,19819812,19819076],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbt","j8DVIOTu7Btj9lgFefJ84AAAAAABeO-1","j8DVIOTu7Btj9lgFefJ84AAAAAABLl-k","j8DVIOTu7Btj9lgFefJ84AAAAAABLmSd","j8DVIOTu7Btj9lgFefJ84AAAAAABLm0k","j8DVIOTu7Btj9lgFefJ84AAAAAABLomE","j8DVIOTu7Btj9lgFefJ84AAAAAABLm1d","j8DVIOTu7Btj9lgFefJ84AAAAAABLnqF","j8DVIOTu7Btj9lgFefJ84AAAAAABLm0k","j8DVIOTu7Btj9lgFefJ84AAAAAABLmpE"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"41gF_giRSTRZMXWPVpvLYA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19907099,19901069],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8Ib","v6HIzNa4K6G4nRP9032RIAAAAAABL6qN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"CCCw9Z7XCAUBXfzhCKjvyQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778468,20166836,20169482,20167663,20167859,19086136,19109575,19098127,19092114,19079610],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehbk","v6HIzNa4K6G4nRP9032RIAAAAAABM7i0","v6HIzNa4K6G4nRP9032RIAAAAAABM8MK","v6HIzNa4K6G4nRP9032RIAAAAAABM7vv","v6HIzNa4K6G4nRP9032RIAAAAAABM7yz","v6HIzNa4K6G4nRP9032RIAAAAAABIzs4","v6HIzNa4K6G4nRP9032RIAAAAAABI5bH","v6HIzNa4K6G4nRP9032RIAAAAAABI2oP","v6HIzNa4K6G4nRP9032RIAAAAAABI1KS","v6HIzNa4K6G4nRP9032RIAAAAAABIyG6"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"RK2MfkyDuA83Ote1DRpnig":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19908516,19901309,19904677,19901477,19914228,19923006],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL930","v6HIzNa4K6G4nRP9032RIAAAAAABMAA-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"E9YrFLZE6ytYTLr5nOdeqA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16755],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"OaI2ikXPfU9oPJVr7qHqRA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19045737,19044484,19054298,18859716,18879913,10485923,16807,2741468,2828042,2818852,4377977,4376240],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8bE","v6HIzNa4K6G4nRP9032RIAAAAAABIBWp","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc","ew01Dk0sWZctP-VaEpavqQAAAAAAKycK","ew01Dk0sWZctP-VaEpavqQAAAAAAKwMk","ew01Dk0sWZctP-VaEpavqQAAAAAAQs15","ew01Dk0sWZctP-VaEpavqQAAAAAAQsaw"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"BeervgrHDOwHnECUdx-R1Q":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528188,54495447,54497074,54477482,44043465,44042020,44050767,44050194,43988037,43983308,43704594,43741015,10485923,16807,3103112,3099892,3094686,3393841,3393734,3091863,2557902,2671840],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQAi8","MNBJ5seVz_ocW6tcr1HSmwAAAAADP4jX","MNBJ5seVz_ocW6tcr1HSmwAAAAADP48y","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAzJ","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAck","MNBJ5seVz_ocW6tcr1HSmwAAAAACoClP","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCcS","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzRF","MNBJ5seVz_ocW6tcr1HSmwAAAAACnyHM","MNBJ5seVz_ocW6tcr1HSmwAAAAACmuES","MNBJ5seVz_ocW6tcr1HSmwAAAAACm29X","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAL1mI","9LzzIocepYcOjnUsLlgOjgAAAAAAL0z0","9LzzIocepYcOjnUsLlgOjgAAAAAALzie","9LzzIocepYcOjnUsLlgOjgAAAAAAM8kx","9LzzIocepYcOjnUsLlgOjgAAAAAAM8jG","9LzzIocepYcOjnUsLlgOjgAAAAAALy2X","9LzzIocepYcOjnUsLlgOjgAAAAAAJwfO","9LzzIocepYcOjnUsLlgOjgAAAAAAKMTg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"_E7kI3XeP50ndUGgLwozRw":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696049,18964841,18963588,18973402,18778948,18799145,10485923,16743,2737420,2823946,2813708,2804875,2803431,2800833,2865890],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNTx","j8DVIOTu7Btj9lgFefJ84AAAAAABIWFp","j8DVIOTu7Btj9lgFefJ84AAAAAABIVyE","j8DVIOTu7Btj9lgFefJ84AAAAAABIYLa","j8DVIOTu7Btj9lgFefJ84AAAAAABHotE","j8DVIOTu7Btj9lgFefJ84AAAAAABHtop","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyL","piWSMQrh4r040D0BPNaJvwAAAAAAKsbn","piWSMQrh4r040D0BPNaJvwAAAAAAKrzB","piWSMQrh4r040D0BPNaJvwAAAAAAK7ri"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"PiAbunsxsTWIrlVv5AJCxQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7441528],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYx4"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"gcylfs4yiiRtiY_AHc1fkQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508562],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpJS"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"2J6chKI2om9Kbvwi1SgqlA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7441584,6770797,6773738,2395067],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYyw","ew01Dk0sWZctP-VaEpavqQAAAAAAZ1Bt","ew01Dk0sWZctP-VaEpavqQAAAAAAZ1vq","ew01Dk0sWZctP-VaEpavqQAAAAAAJIu7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"YX2R7C2iz4FGt5q5Tnk6TA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858248,18713630,18723524,18720816,19859472,18001099,10488398,10493154,585983,12583132,6817209,21184,6815932,6812296,6811747,6811254,7304819,7302120],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","_3bHXKBtA1BrvZVdhZK3vg","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwNI","j8DVIOTu7Btj9lgFefJ84AAAAAABHYwe","j8DVIOTu7Btj9lgFefJ84AAAAAABHbLE","j8DVIOTu7Btj9lgFefJ84AAAAAABHagw","j8DVIOTu7Btj9lgFefJ84AAAAAABLwgQ","j8DVIOTu7Btj9lgFefJ84AAAAAABEqzL","piWSMQrh4r040D0BPNaJvwAAAAAAoApO","piWSMQrh4r040D0BPNaJvwAAAAAAoBzi","piWSMQrh4r040D0BPNaJvwAAAAAACPD_","piWSMQrh4r040D0BPNaJvwAAAAAAwADc","piWSMQrh4r040D0BPNaJvwAAAAAAaAW5","_3bHXKBtA1BrvZVdhZK3vgAAAAAAAFLA","piWSMQrh4r040D0BPNaJvwAAAAAAaAC8","piWSMQrh4r040D0BPNaJvwAAAAAAZ_KI","piWSMQrh4r040D0BPNaJvwAAAAAAZ_Bj","piWSMQrh4r040D0BPNaJvwAAAAAAZ-52","piWSMQrh4r040D0BPNaJvwAAAAAAb3Zz","piWSMQrh4r040D0BPNaJvwAAAAAAb2vo"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"--7TGRswVMtk5qWYdGBDUw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797926,4866621,4855697,8473771],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm","ew01Dk0sWZctP-VaEpavqQAAAAAASkI9","ew01Dk0sWZctP-VaEpavqQAAAAAASheR","ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"iVZ81pgajC_4cYBykPWgBg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6869315,6866863,2643],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","6miIyyucTZf5zXHCk7PT1g"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD","ew01Dk0sWZctP-VaEpavqQAAAAAAaMev","6miIyyucTZf5zXHCk7PT1gAAAAAAAApT"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"dg33Fg5TLDtB9bOuPSPREA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1345741,1348060,1347558,1345954,1343030,1342299,1335062,1334604,1334212,452199,518055,509958],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFImi","huWyXZbCBWCe2ZtK9BiokQAAAAAAFH42","huWyXZbCBWCe2ZtK9BiokQAAAAAAFHtb","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF1M","huWyXZbCBWCe2ZtK9BiokQAAAAAAFFvE","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB8gG"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAALz5s":{"file_name":[],"function_name":["__x64_sys_epoll_pwait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAALzn0":{"file_name":[],"function_name":["do_epoll_wait"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEqRj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEpnh":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnfL":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACar9":{"file_name":[],"function_name":["__x64_sys_tgkill"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACaq0":{"file_name":[],"function_name":["do_tkill"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACan-":{"file_name":[],"function_name":["do_send_specific"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACaJE":{"file_name":[],"function_name":["do_send_sig_info"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnhG":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnal":{"file_name":[],"function_name":["futex_wait_setup"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEm2v":{"file_name":[],"function_name":["get_futex_key"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEmab":{"file_name":[],"function_name":["get_futex_key_refs.isra.8"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEp0x":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEnfb":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEUoQ":{"file_name":[],"function_name":["hrtimer_cancel"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEUmo":{"file_name":[],"function_name":["hrtimer_try_to_cancel"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAgU79":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAM56z":{"file_name":[],"function_name":["kernfs_dop_revalidate"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKmEA":{"file_name":[],"function_name":["__do_sys_newfstatat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKloy":{"file_name":[],"function_name":["vfs_statx"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKyLF":{"file_name":[],"function_name":["filename_lookup"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKt_N":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKtbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKszB":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAK8rt":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL1y4":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL1Hv":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEFz":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKycK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKwMk":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQs15":{"file_name":[],"function_name":["ima_file_check"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQsaw":{"file_name":[],"function_name":["process_measurement"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAL1mI":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAL0z0":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAALzie":{"file_name":[],"function_name":["ep_item_poll.isra.15"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAM8kx":{"file_name":[],"function_name":["kernfs_fop_poll"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAM8jG":{"file_name":[],"function_name":["kernfs_generic_poll"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAALy2X":{"file_name":[],"function_name":["ep_ptable_queue_proc"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwfO":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKMTg":{"file_name":[],"function_name":["memcg_kmem_get_cache"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu8M":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyL":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKrzB":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAK7ri":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYx4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpJS":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYyw":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ1Bt":{"file_name":[],"function_name":["__kfree_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ1vq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJIu7":{"file_name":[],"function_name":["free_unref_page"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoApO":{"file_name":[],"function_name":["ret_from_intr"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoBzi":{"file_name":[],"function_name":["do_IRQ"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACPD_":{"file_name":[],"function_name":["irq_exit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAaAW5":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"_3bHXKBtA1BrvZVdhZK3vgAAAAAAAFLA":{"file_name":[],"function_name":["ena_io_poll"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAaAC8":{"file_name":[],"function_name":["napi_complete_done"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ_KI":{"file_name":[],"function_name":["gro_normal_list.part.131"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ_Bj":{"file_name":[],"function_name":["netif_receive_skb_list_internal"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ-52":{"file_name":[],"function_name":["__netif_receive_skb_list_core"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb3Zz":{"file_name":[],"function_name":["ip_list_rcv"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb2vo":{"file_name":[],"function_name":["ip_rcv_core.isra.17"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkI9":{"file_name":[],"function_name":["_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASheR":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr":{"file_name":[],"function_name":["copy_user_generic_string"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMev":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"6miIyyucTZf5zXHCk7PT1gAAAAAAAApT":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFImi":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFH42":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_d2i_ex_primitive"],"function_offset":[],"line_number":[874]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFHtb":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_ex_c2i"],"function_offset":[],"line_number":[903]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_item_new"],"function_offset":[],"line_number":[76]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF1M":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["asn1_item_ex_combine_new"],"function_offset":[],"line_number":[136]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFFvE":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_primitive_new"],"function_offset":[],"line_number":[342]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/mem.c"],"function_name":["CRYPTO_malloc"],"function_offset":[],"line_number":[346]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3068]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB8gG":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["_int_malloc"],"function_offset":[],"line_number":[3584]}},"executables":{"Ij7mO1SCteAnvtNe95RpEg":"linux-vdso.so.1","B56YkhsK1JwqD-8F8sjS3A":"prometheus","QvG8QEGAld88D676NL_Y2Q":"filebeat","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","67s2TwiMngM0yin5Y8pvEg":"containerd","-1kQFVGzdQWpzLSZ9TRmnw":"kube-state-metrics","v6HIzNa4K6G4nRP9032RIA":"dockerd","LvhLWomlc0dSPYzQ8C620g":"controller","B8JRxL079xbhqQBqGvksAg":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","j8DVIOTu7Btj9lgFefJ84A":"dockerd","piWSMQrh4r040D0BPNaJvw":"vmlinux","6auiCMWq5cA-hAbqSYvdQQ":"kubelet","gfRL5jyxmWedM28UI08hFQ":"snapshot-controller","1QjX8mEQC0-5qYXzadOESA":"containerd-shim-runc-v2","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","A2oiHVwisByxRn5RDT4LjA":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","9LzzIocepYcOjnUsLlgOjg":"vmlinux","_3bHXKBtA1BrvZVdhZK3vg":"ena","6miIyyucTZf5zXHCk7PT1g":"veth","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k"},"total_frames":13116,"sampling_rate":1} diff --git a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_86400s_125x.json b/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_86400s_125x.json deleted file mode 100644 index 35bdfd788368..000000000000 --- a/packages/kbn-profiling-utils/common/__fixtures__/stacktraces_86400s_125x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"clTcDPwSeibw16tpSQPVxA":38,"1sIZ88dgfmQewwimPWuaWw":80,"2gFeSnOvAhz1aSRiNEVnjQ":213,"0CNUMdOdpmKJxWeUmvWvXg":1062,"9_06LL00QkYIeiFNCWu0XQ":919,"StwAKCpFAmfI3NKtrFQDVg":494,"Jd0qjF7XxnghG2_AZCQTFA":408,"1Ez9iBhqi5bXK2tpNXVjRA":380,"2Ov4wSepfExdnFvsJSSjog":281,"DALs1IxJ3oi7BZ8FFjuM_Q":418,"VmRA1Zd-R_saxzv9stOlrw":364,"u31aX9a6CI2OuomWQHSx1Q":397,"7zatBTElj7KkoApkBS7dzw":438,"ErI-d7HGvspCKDUrR8E64A":371,"-s21TvA-EsTWbfCutQG83Q":373,"kryT_w4Id2yAnU578aXk1w":330,"AsgowTLQhiAbue_lxpHIHw":373,"hecRkAhRG62NML7wI512zA":230,"woPu0Q2DCHU5xpBNJFRNGw":179,"-t2pi-xr8qjFCfIHra96OA":203,"qbtMiMC37gp-mMp0u-WgYw":238,"ZZck2mgLZGHuLiBDFerx6w":244,"af-YU39AX7WoGwE66OjkRg":197,"DkjcsUWzUMWlzGIG7vWPLA":201,"9sZZ-MQWzCV4c64gJJBU6Q":261,"rQhVFvlTg_4aQXNpF_LGMQ":213,"-t0hOBsBrsbJ-S8NPXUTmg":175,"VoyVx3eKZvx3I7o9LV75WA":148,"SwXYsounAV_Jw1AjJobr2g":120,"Z84n0-wX6U6-iVSLGr0n7A":130,"PPkg_Kb06KioYNLVH5MUSw":114,"lMQPlrvTe5c5NiwvC7JXZg":102,"0BFlivqqa58juwW6lzxBVg":70,"cKHQmDxYocbgoxaTvYj6SA":53,"KnJHmq-Dv1WTEbftpdA5Zg":39,"2-DAEecFvG7qyB6YjY5nOg":38,"Ocoebh9gAlmO1k7rQilo0w":23,"XyR38J9TfiJQyusyqjnL0Q":12,"9s4s_y43ZAfUdYXm930H4A":9,"LeV2oAqU4BVeWoabuoh-cw":10,"2gcYNFzbFyKxWn73M5202w":12,"CU-T9AvnxmWd1TTRjgV01Q":27,"nnsc9UkL_oA5SAi5cs_ZPg":9,"wAujHiFN47_oNUI63d6EtA":15,"ia-QZTf1AEqK7KEggAUJSw":12,"YxsKA4n0U7pKfHmrePpfjA":2,"mqliNf10_gB69yQo7_zlzg":9,"24tLFB3hY9xz1zbZCjaBXA":1,"MLSOPRH6z6HuctKh5rsAnA":4,"krdohOL0KiVMtm4q-6fmjg":2,"FtHYpmBv9BwyjtHQeYFcCw":2,"FuFG7sSEAg94nZpDT4nzlA":3,"chida0TNeXOPGVvI0kALCQ":4,"UDWRHwtQcuK3KYw4Lj118w":3,"wQhKHV5i9LyZbGr1o38TMA":1,"TtsX1UxF45-CxViHFwbKJw":1,"iu7dYG1YyobzAXC7AJADOw":1,"WmwSnxyphedkasVyGbhNdg":2,"YWZby9VC56JtR6BAaYHEoA":1,"Hi8HEHDniMkBvPgm-_IXdg":2,"X86DUuQ7tHAxGBaWu4tZLg":3,"Tx8lhCcOjrVLOl1hWK6aBw":1,"oKVObqTWF9QIjxgKf8UkTw":3,"rsb7cL4OAenBHrp0F_Wcgg":2,"mWVVBnqMHfG9pWtaZUm47Q":1,"r1nqJ9JqsZyOKqlpBmuvLg":1,"5MDEZjYH98Woy4iHbcvgDg":1,"WYRZ4mSdJHjsW8s2yoKnfA":1,"C4ItszXjQjtRADEg560AUw":6,"8IBqDIuSolkkEHIjO_CfMw":5,"T2hqeT_yirkauwcO1cGJEw":4,"OIXgOJgQPE-F5rS7DPPzZA":2,"i0e78nPZCZ2CbzzLMEOcMw":4,"34DMF2kw8Djh_MjcdchMzw":6,"XG9tjujXJl2nWpbHppoRMA":6,"SrSwvDbs2pmPg3SRfXJBCA":8,"bcNRMcXtTRgNPl4vy6M5KQ":8,"XmiUdMqa5OViUnHQ_LS4Uw":3,"3odHGojcaqq4ImPnmLLSzw":6,"bRKRM4i4-XY2LCfN18mOow":8,"W936jUeelyxTrQQ2V9mn-w":3,"AlH3zgnqwh5sdMMzX8AXxg":3,"YHwQa4NMDpWa9cokfF0xqw":1,"AlRn0MJA_RCD0pN2OpIRZA":4,"inhNt-Ftru1dLAPaXB98Gw":2,"qaaAfLAUIerA8yhApFJRYQ":2,"cj3H8UtNXHeFFvSKCpbt_Q":1,"XT5dbBR70HCMmAkhladaCQ":1,"Kfnso_5TQwyEGb1cfr-n5A":1,"O3_UY4IxBGbcnXlHSqWz_w":2},"stack_traces":{"clTcDPwSeibw16tpSQPVxA":{"address_or_lines":[4646313],"file_ids":["FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWp"],"type_ids":[3]},"1sIZ88dgfmQewwimPWuaWw":{"address_or_lines":[4660883,2469],"file_ids":["B8JRxL079xbhqQBqGvksAg","edNJ10OjHiWc5nzuTQdvig"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARx6T","edNJ10OjHiWc5nzuTQdvigAAAAAAAAml"],"type_ids":[3,3]},"2gFeSnOvAhz1aSRiNEVnjQ":{"address_or_lines":[10486356,710610,1071113],"file_ids":["piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["piWSMQrh4r040D0BPNaJvwAAAAAAoAJU","piWSMQrh4r040D0BPNaJvwAAAAAACtfS","piWSMQrh4r040D0BPNaJvwAAAAAAEFgJ"],"type_ids":[4,4,4]},"0CNUMdOdpmKJxWeUmvWvXg":{"address_or_lines":[32434917,32101228,32115955,32118104],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6gzz","QvG8QEGAld88D676NL_Y2QAAAAAB6hVY"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"StwAKCpFAmfI3NKtrFQDVg":{"address_or_lines":[4646312,4600750,4594821,4561903,4559144,4562383],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAARjOu","FWZ9q3TQKZZok58ua1HDsgAAAAAARhyF","FWZ9q3TQKZZok58ua1HDsgAAAAAARZvv","FWZ9q3TQKZZok58ua1HDsgAAAAAARZEo","FWZ9q3TQKZZok58ua1HDsgAAAAAARZ3P"],"type_ids":[3,3,3,3,3,3]},"Jd0qjF7XxnghG2_AZCQTFA":{"address_or_lines":[43723813,43390308,43405438,43397462,43398148,43406419,43408369],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACmywl","MNBJ5seVz_ocW6tcr1HSmwAAAAAClhVk","MNBJ5seVz_ocW6tcr1HSmwAAAAACllB-","MNBJ5seVz_ocW6tcr1HSmwAAAAACljFW","MNBJ5seVz_ocW6tcr1HSmwAAAAACljQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACllRT","MNBJ5seVz_ocW6tcr1HSmwAAAAACllvx"],"type_ids":[3,3,3,3,3,3,3]},"1Ez9iBhqi5bXK2tpNXVjRA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9497568],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkOvg"],"type_ids":[3,3,3,3,3,3,3,3]},"2Ov4wSepfExdnFvsJSSjog":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504548,5043327],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQck","FWZ9q3TQKZZok58ua1HDsgAAAAAATPR_"],"type_ids":[3,3,3,3,3,3,3,3,3]},"DALs1IxJ3oi7BZ8FFjuM_Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504218,4890989,4889187],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQXa","FWZ9q3TQKZZok58ua1HDsgAAAAAASqFt","FWZ9q3TQKZZok58ua1HDsgAAAAAASppj"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"VmRA1Zd-R_saxzv9stOlrw":{"address_or_lines":[4650848,9850853,9880398,9883181,9807044,9827268,9781937,9782483,9784009,9784300,9829781],"file_ids":["QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg"],"frame_ids":["QaIvzvU8UoclQMd_OMt-PgAAAAAARvdg","QaIvzvU8UoclQMd_OMt-PgAAAAAAlk_l","QaIvzvU8UoclQMd_OMt-PgAAAAAAlsNO","QaIvzvU8UoclQMd_OMt-PgAAAAAAls4t","QaIvzvU8UoclQMd_OMt-PgAAAAAAlaTE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlfPE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUKx","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUTT","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUrJ","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUvs","QaIvzvU8UoclQMd_OMt-PgAAAAAAlf2V"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"7zatBTElj7KkoApkBS7dzw":{"address_or_lines":[32443680,58256816,58381230,58319266,58327970,58359946,58318775,58321276,58323254,58419093,58425670,32747421,32699470],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7w0g","QvG8QEGAld88D676NL_Y2QAAAAADeO2w","QvG8QEGAld88D676NL_Y2QAAAAADetOu","QvG8QEGAld88D676NL_Y2QAAAAADeeGi","QvG8QEGAld88D676NL_Y2QAAAAADegOi","QvG8QEGAld88D676NL_Y2QAAAAADeoCK","QvG8QEGAld88D676NL_Y2QAAAAADed-3","QvG8QEGAld88D676NL_Y2QAAAAADeel8","QvG8QEGAld88D676NL_Y2QAAAAADefE2","QvG8QEGAld88D676NL_Y2QAAAAADe2eV","QvG8QEGAld88D676NL_Y2QAAAAADe4FG","QvG8QEGAld88D676NL_Y2QAAAAAB86-d","QvG8QEGAld88D676NL_Y2QAAAAAB8vRO"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3]},"ErI-d7HGvspCKDUrR8E64A":{"address_or_lines":[152249,135481,144741,190122,831754,827742,928935,925466,103752,102294,100426,61069,75059,73332],"file_ids":["w5zBqPf1_9mIVEf-Rn7EdA","Z_CHd3Zjsh2cWE2NSdbiNQ","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg"],"frame_ids":["w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAlK5","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAjVl","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAuaq","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADLEK","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADKFe","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADiyn","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADh8a","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAYhK","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAO6N","OTWX4UsOVMrSIF5cD4zUzgAAAAAAASUz","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAR50"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"kryT_w4Id2yAnU578aXk1w":{"address_or_lines":[4652224,22357367,22385134,22366798,57089650,58932906,58679635,58644118,58665750,31406998,7372944,7295421,7297188,7304836,7297245,5131680],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZx5y","B8JRxL079xbhqQBqGvksAgAAAAADgz6q","B8JRxL079xbhqQBqGvksAgAAAAADf2FT","B8JRxL079xbhqQBqGvksAgAAAAADftaW","B8JRxL079xbhqQBqGvksAgAAAAADfysW","B8JRxL079xbhqQBqGvksAgAAAAAB3zuW","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAATk2g"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"AsgowTLQhiAbue_lxpHIHw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41460538,41453510,39934947,37247976,34247181,33672088,18131287],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeKM6","v6HIzNa4K6G4nRP9032RIAAAAAACeIfG","v6HIzNa4K6G4nRP9032RIAAAAAACYVvj","v6HIzNa4K6G4nRP9032RIAAAAAACOFvo","v6HIzNa4K6G4nRP9032RIAAAAAACCpIN","v6HIzNa4K6G4nRP9032RIAAAAAACAcuY","v6HIzNa4K6G4nRP9032RIAAAAAABFKlX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"woPu0Q2DCHU5xpBNJFRNGw":{"address_or_lines":[43732576,54345578,54346325,54347573,52524033,52636324,52637912,52417621,52420674,52436132,51874398,51910204,51902690,51903112,51905980,51885853,51874212,51875084,44164621],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAADPT9q","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUJV","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUc1","MNBJ5seVz_ocW6tcr1HSmwAAAAADIXQB","MNBJ5seVz_ocW6tcr1HSmwAAAAADIyqk","MNBJ5seVz_ocW6tcr1HSmwAAAAADIzDY","MNBJ5seVz_ocW6tcr1HSmwAAAAADH9RV","MNBJ5seVz_ocW6tcr1HSmwAAAAADH-BC","MNBJ5seVz_ocW6tcr1HSmwAAAAADIByk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4pe","MNBJ5seVz_ocW6tcr1HSmwAAAAADGBY8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_ji","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_qI","MNBJ5seVz_ocW6tcr1HSmwAAAAADGAW8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF7cd","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4mk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF40M","MNBJ5seVz_ocW6tcr1HSmwAAAAACoeYN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-t2pi-xr8qjFCfIHra96OA":{"address_or_lines":[4620832,23557195,23527051,9749435,9749637,9750553,9750935,9746779,9746522,23527477,23529910,23522407,10849724,10839125,10834845,10836246,10842317,4508401,4247613,4282212],"file_ids":["hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg"],"frame_ids":["hc6JHMKlLXjOZcU9MGxvfgAAAAAARoIg","hc6JHMKlLXjOZcU9MGxvfgAAAAABZ3RL","hc6JHMKlLXjOZcU9MGxvfgAAAAABZv6L","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMO7","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMSF","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMgZ","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMmX","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlLlb","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlLha","hc6JHMKlLXjOZcU9MGxvfgAAAAABZwA1","hc6JHMKlLXjOZcU9MGxvfgAAAAABZwm2","hc6JHMKlLXjOZcU9MGxvfgAAAAABZuxn","hc6JHMKlLXjOZcU9MGxvfgAAAAAApY28","hc6JHMKlLXjOZcU9MGxvfgAAAAAApWRV","hc6JHMKlLXjOZcU9MGxvfgAAAAAApVOd","hc6JHMKlLXjOZcU9MGxvfgAAAAAApVkW","hc6JHMKlLXjOZcU9MGxvfgAAAAAApXDN","hc6JHMKlLXjOZcU9MGxvfgAAAAAARMrx","hc6JHMKlLXjOZcU9MGxvfgAAAAAAQNA9","hc6JHMKlLXjOZcU9MGxvfgAAAAAAQVdk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"qbtMiMC37gp-mMp0u-WgYw":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7305194,5143289,5150220,5146267],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3fq","B8JRxL079xbhqQBqGvksAgAAAAAATnr5","B8JRxL079xbhqQBqGvksAgAAAAAATpYM","B8JRxL079xbhqQBqGvksAgAAAAAAToab"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"ZZck2mgLZGHuLiBDFerx6w":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7304836,7297188,7304836,7297188,7303473],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3Ex"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"af-YU39AX7WoGwE66OjkRg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961306,27960060,27907285,27885784,27888182,18793031,27888361],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqfa","v6HIzNa4K6G4nRP9032RIAAAAAABqqL8","v6HIzNa4K6G4nRP9032RIAAAAAABqdTV","v6HIzNa4K6G4nRP9032RIAAAAAABqYDY","v6HIzNa4K6G4nRP9032RIAAAAAABqYo2","v6HIzNa4K6G4nRP9032RIAAAAAABHsJH","v6HIzNa4K6G4nRP9032RIAAAAAABqYrp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"DkjcsUWzUMWlzGIG7vWPLA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54556506,44024036,44026008,44007166,43828228,43837959,43282962,43282989,10485923,16807,2845749,2845580,2841596,3335577,3325166,699747],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHda","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8Dk","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8iY","MNBJ5seVz_ocW6tcr1HSmwAAAAACn37-","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1","A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ","A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu","A2oiHVwisByxRn5RDT4LjAAAAAAACq1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"9sZZ-MQWzCV4c64gJJBU6Q":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709540,4933796,4937114,4970099,4971610,4754617,4757981,4219698,4219725,10485923,16807,2777072,2775330,2826677,2809572,2808699,2807483,2863936],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEk","B8JRxL079xbhqQBqGvksAgAAAAAAS0ik","B8JRxL079xbhqQBqGvksAgAAAAAAS1Wa","B8JRxL079xbhqQBqGvksAgAAAAAAS9Zz","B8JRxL079xbhqQBqGvksAgAAAAAAS9xa","B8JRxL079xbhqQBqGvksAgAAAAAASIy5","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKl_w","A2oiHVwisByxRn5RDT4LjAAAAAAAKlki","A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1","A2oiHVwisByxRn5RDT4LjAAAAAAAKt7k","A2oiHVwisByxRn5RDT4LjAAAAAAAKtt7","A2oiHVwisByxRn5RDT4LjAAAAAAAKta7","A2oiHVwisByxRn5RDT4LjAAAAAAAK7NA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"rQhVFvlTg_4aQXNpF_LGMQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41428732,20150746,19897796,19899069,19901252,19906953,20160590,19897796,19899069,19901252,19910358,18737412,18488391,18154825,18129756],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCb8","v6HIzNa4K6G4nRP9032RIAAAAAABM3na","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8GJ","v6HIzNa4K6G4nRP9032RIAAAAAABM6BO","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL87W","v6HIzNa4K6G4nRP9032RIAAAAAABHekE","v6HIzNa4K6G4nRP9032RIAAAAAABGhxH","v6HIzNa4K6G4nRP9032RIAAAAAABFQVJ","v6HIzNa4K6G4nRP9032RIAAAAAABFKNc"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-t0hOBsBrsbJ-S8NPXUTmg":{"address_or_lines":[4652224,22033901,21942103,21951046,9844260,9839268,22072132,22072395,5590500,5508424,4907789,4749540,4757831,4219698,4219725,10485923,16807,2756576,2755820,2745050,6715782,6715626,7926696,6795731,4869416,4855393,8472925],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABUDXt","B8JRxL079xbhqQBqGvksAgAAAAABTs9X","B8JRxL079xbhqQBqGvksAgAAAAABTvJG","B8JRxL079xbhqQBqGvksAgAAAAAAljYk","B8JRxL079xbhqQBqGvksAgAAAAAAliKk","B8JRxL079xbhqQBqGvksAgAAAAABUMtE","B8JRxL079xbhqQBqGvksAgAAAAABUMxL","B8JRxL079xbhqQBqGvksAgAAAAAAVU3k","B8JRxL079xbhqQBqGvksAgAAAAAAVA1I","B8JRxL079xbhqQBqGvksAgAAAAAASuMN","B8JRxL079xbhqQBqGvksAgAAAAAASHjk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg_g","A2oiHVwisByxRn5RDT4LjAAAAAAAKgzs","A2oiHVwisByxRn5RDT4LjAAAAAAAKeLa","A2oiHVwisByxRn5RDT4LjAAAAAAAZnmG","A2oiHVwisByxRn5RDT4LjAAAAAAAZnjq","A2oiHVwisByxRn5RDT4LjAAAAAAAePOo","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7HT","A2oiHVwisByxRn5RDT4LjAAAAAAASk0o","A2oiHVwisByxRn5RDT4LjAAAAAAAShZh","A2oiHVwisByxRn5RDT4LjAAAAAAAgUld"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"VoyVx3eKZvx3I7o9LV75WA":{"address_or_lines":[4652224,22354373,22356417,22043891,9840916,9838765,4872825,5688954,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7924288,7914841,6798266,6797590,6797444,2726038],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVRnF","B8JRxL079xbhqQBqGvksAgAAAAABVSHB","B8JRxL079xbhqQBqGvksAgAAAAABUFzz","B8JRxL079xbhqQBqGvksAgAAAAAAlikU","B8JRxL079xbhqQBqGvksAgAAAAAAliCt","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA","A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE","A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"SwXYsounAV_Jw1AjJobr2g":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791289,24794610,24781052,24778417,19045737,19044484,19054298,18859588,18399464,18130636],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekj5","v6HIzNa4K6G4nRP9032RIAAAAAABelXy","v6HIzNa4K6G4nRP9032RIAAAAAABeiD8","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8ZE","v6HIzNa4K6G4nRP9032RIAAAAAABGMDo","v6HIzNa4K6G4nRP9032RIAAAAAABFKbM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Z84n0-wX6U6-iVSLGr0n7A":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19907213,19923168],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8KN","v6HIzNa4K6G4nRP9032RIAAAAAABMADg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"PPkg_Kb06KioYNLVH5MUSw":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54547559,54558277,54570436,44043866,44037437,43989636,43829252,43837959,43282962,43282989,10485923,16807,2756288,2755416,2924231,3319181,3316454,2921821,2921711,8455053,8481479],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFRn","MNBJ5seVz_ocW6tcr1HSmwAAAAADQH5F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQK3E","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA5a","MNBJ5seVz_ocW6tcr1HSmwAAAAACn_U9","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzqE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMgE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAALJ7H","A2oiHVwisByxRn5RDT4LjAAAAAAAMqWN","A2oiHVwisByxRn5RDT4LjAAAAAAAMprm","A2oiHVwisByxRn5RDT4LjAAAAAAALJVd","A2oiHVwisByxRn5RDT4LjAAAAAAALJTv","A2oiHVwisByxRn5RDT4LjAAAAAAAgQON","A2oiHVwisByxRn5RDT4LjAAAAAAAgWrH"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"lMQPlrvTe5c5NiwvC7JXZg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19976893,19927481,19928567,19983876,19943049,19984068,19944276,19984260,19945213,19982696,19937907,19983876,19943049,19984068,19944276,19982696,19937907,19935862,19142858],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNK9","v6HIzNa4K6G4nRP9032RIAAAAAABMBG5","v6HIzNa4K6G4nRP9032RIAAAAAABMBX3","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMO-E","v6HIzNa4K6G4nRP9032RIAAAAAABMFb9","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMDJ2","v6HIzNa4K6G4nRP9032RIAAAAAABJBjK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"0BFlivqqa58juwW6lzxBVg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19908516,19901477,19920683,18932457,18903037],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL_cr","v6HIzNa4K6G4nRP9032RIAAAAAABIOLp","v6HIzNa4K6G4nRP9032RIAAAAAABIG_9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"cKHQmDxYocbgoxaTvYj6SA":{"address_or_lines":[4652224,58814799,10400775,10401064,10401333,10401661,58829797,58814910,58812516,58789549,58791347,58770754,58772726,13824541,13825258,13823212,13823370,4964628,4731769,4742286,4757722,4219698,4219725,10485923,16807,2795169,2795020,2794811,2794650,2760034,2759532,2759330,2758281,2557765],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAADgXFP","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrQH","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrUo","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrY1","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrd9","wfA2BgwfDNXUWsxkJ083RwAAAAADgavl","wfA2BgwfDNXUWsxkJ083RwAAAAADgXG-","wfA2BgwfDNXUWsxkJ083RwAAAAADgWhk","wfA2BgwfDNXUWsxkJ083RwAAAAADgQ6t","wfA2BgwfDNXUWsxkJ083RwAAAAADgRWz","wfA2BgwfDNXUWsxkJ083RwAAAAADgMVC","wfA2BgwfDNXUWsxkJ083RwAAAAADgMz2","wfA2BgwfDNXUWsxkJ083RwAAAAAA0vId","wfA2BgwfDNXUWsxkJ083RwAAAAAA0vTq","wfA2BgwfDNXUWsxkJ083RwAAAAAA0uzs","wfA2BgwfDNXUWsxkJ083RwAAAAAA0u2K","wfA2BgwfDNXUWsxkJ083RwAAAAAAS8EU","wfA2BgwfDNXUWsxkJ083RwAAAAAASDN5","wfA2BgwfDNXUWsxkJ083RwAAAAAASFyO","wfA2BgwfDNXUWsxkJ083RwAAAAAASJja","wfA2BgwfDNXUWsxkJ083RwAAAAAAQGMy","wfA2BgwfDNXUWsxkJ083RwAAAAAAQGNN","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKqah","9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM","9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7","9LzzIocepYcOjnUsLlgOjgAAAAAAKqSa","9LzzIocepYcOjnUsLlgOjgAAAAAAKh1i","9LzzIocepYcOjnUsLlgOjgAAAAAAKhts","9LzzIocepYcOjnUsLlgOjgAAAAAAKhqi","9LzzIocepYcOjnUsLlgOjgAAAAAAKhaJ","9LzzIocepYcOjnUsLlgOjgAAAAAAJwdF"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"KnJHmq-Dv1WTEbftpdA5Zg":{"address_or_lines":[4652224,30971941,30986245,30988292,30990568,30935955,30723428,25540326,25548591,25550478,25503568,25504356,25481468,25481277,25484807,25485060,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813561,2756082,2755033,2554964,2554477,2553932,2551218,2411027,2394415],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAAB2Jgl","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NAF","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NgE","-pk6w5puGcp-wKnQ61BZzQAAAAAB2ODo","-pk6w5puGcp-wKnQ61BZzQAAAAAB2AuT","-pk6w5puGcp-wKnQ61BZzQAAAAAB1M1k","-pk6w5puGcp-wKnQ61BZzQAAAAABhbbm","-pk6w5puGcp-wKnQ61BZzQAAAAABhdcv","-pk6w5puGcp-wKnQ61BZzQAAAAABhd6O","-pk6w5puGcp-wKnQ61BZzQAAAAABhSdQ","-pk6w5puGcp-wKnQ61BZzQAAAAABhSpk","-pk6w5puGcp-wKnQ61BZzQAAAAABhND8","-pk6w5puGcp-wKnQ61BZzQAAAAABhNA9","-pk6w5puGcp-wKnQ61BZzQAAAAABhN4H","-pk6w5puGcp-wKnQ61BZzQAAAAABhN8E","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu55","piWSMQrh4r040D0BPNaJvwAAAAAAKg3y","piWSMQrh4r040D0BPNaJvwAAAAAAKgnZ","piWSMQrh4r040D0BPNaJvwAAAAAAJvxU","piWSMQrh4r040D0BPNaJvwAAAAAAJvpt","piWSMQrh4r040D0BPNaJvwAAAAAAJvhM","piWSMQrh4r040D0BPNaJvwAAAAAAJu2y","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIkv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"2-DAEecFvG7qyB6YjY5nOg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755650,4215846],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxC","ew01Dk0sWZctP-VaEpavqQAAAAAAQFQm"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"Ocoebh9gAlmO1k7rQilo0w":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756560,2755688,2744899,3827767,3827522,2050302,4868077,4855663],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3","ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC","ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-","ew01Dk0sWZctP-VaEpavqQAAAAAASkft","ew01Dk0sWZctP-VaEpavqQAAAAAAShdv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"XyR38J9TfiJQyusyqjnL0Q":{"address_or_lines":[4652224,22354871,22382638,22364302,56672751,58471189,58268669,58227812,58241853,31197476,7372151,7373114,7374151,8925121,8860356,8860667,8477214,5688773,8906989,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16743,2752512,2751640,2740851,6649793,7859650,7859044,6707098,6708074,2391221,2381065],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYMHv","-pk6w5puGcp-wKnQ61BZzQAAAAADfDMV","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH13","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIE6","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIVH","-pk6w5puGcp-wKnQ61BZzQAAAAAAiC_B","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzLE","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzP7","-pk6w5puGcp-wKnQ61BZzQAAAAAAgVoe","-pk6w5puGcp-wKnQ61BZzQAAAAAAVs3F","-pk6w5puGcp-wKnQ61BZzQAAAAAAh-jt","-pk6w5puGcp-wKnQ61BZzQAAAAAAVUwE","-pk6w5puGcp-wKnQ61BZzQAAAAAAVATI","-pk6w5puGcp-wKnQ61BZzQAAAAAASsLk","-pk6w5puGcp-wKnQ61BZzQAAAAAASHZk","-pk6w5puGcp-wKnQ61BZzQAAAAAASJlH","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgAA","piWSMQrh4r040D0BPNaJvwAAAAAAKfyY","piWSMQrh4r040D0BPNaJvwAAAAAAKdJz","piWSMQrh4r040D0BPNaJvwAAAAAAZXfB","piWSMQrh4r040D0BPNaJvwAAAAAAd-3C","piWSMQrh4r040D0BPNaJvwAAAAAAd-tk","piWSMQrh4r040D0BPNaJvwAAAAAAZlea","piWSMQrh4r040D0BPNaJvwAAAAAAZltq","piWSMQrh4r040D0BPNaJvwAAAAAAJHy1","piWSMQrh4r040D0BPNaJvwAAAAAAJFUJ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"9s4s_y43ZAfUdYXm930H4A":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,6711003,4219907],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAZmbb","9LzzIocepYcOjnUsLlgOjgAAAAAAQGQD"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"LeV2oAqU4BVeWoabuoh-cw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7503313],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcn3R"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"2gcYNFzbFyKxWn73M5202w":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7436960,2551475,2548988],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg","9LzzIocepYcOjnUsLlgOjgAAAAAAJu6z","9LzzIocepYcOjnUsLlgOjgAAAAAAJuT8"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"CU-T9AvnxmWd1TTRjgV01Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7508830,6761766,2559050],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe","9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m","9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"nnsc9UkL_oA5SAi5cs_ZPg":{"address_or_lines":[4195929,135481,1080531,1010960,1006705,1002538,905832,905294,893117,905294,893117,905294,895510,893117,905294,893117,905294,893117,905294,893117,905294,887126,310194,449006,905294,893117,905294,885107,310194,633609,646930,310194,366119,310194,448792,905294,895510,876495,513798,506886,539471,539386,531635],"file_ids":["YsKzCJ9e4eZnuT00vj7Pcw","Z_CHd3Zjsh2cWE2NSdbiNQ","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw"],"frame_ids":["YsKzCJ9e4eZnuT00vj7PcwAAAAAAQAZZ","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","N4ILulabOfF5MnyRJbvDXwAAAAAAEHzT","N4ILulabOfF5MnyRJbvDXwAAAAAAD20Q","N4ILulabOfF5MnyRJbvDXwAAAAAAD1xx","N4ILulabOfF5MnyRJbvDXwAAAAAAD0wq","N4ILulabOfF5MnyRJbvDXwAAAAAADdJo","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaoW","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADYlW","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABtnu","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADYFz","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAACasJ","N4ILulabOfF5MnyRJbvDXwAAAAAACd8S","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABZYn","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABtkY","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaoW","N4ILulabOfF5MnyRJbvDXwAAAAAADV_P","N4ILulabOfF5MnyRJbvDXwAAAAAAB9cG","N4ILulabOfF5MnyRJbvDXwAAAAAAB7wG","N4ILulabOfF5MnyRJbvDXwAAAAAACDtP","N4ILulabOfF5MnyRJbvDXwAAAAAACDr6","N4ILulabOfF5MnyRJbvDXwAAAAAACByz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"wAujHiFN47_oNUI63d6EtA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7513502,6765905,6759805,2574033,2218596],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe","ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R","ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9","ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR","ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"ia-QZTf1AEqK7KEggAUJSw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6868281,6866019],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaM05","ew01Dk0sWZctP-VaEpavqQAAAAAAaMRj"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"YxsKA4n0U7pKfHmrePpfjA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10489481,12583132,6878809,6871998,6871380,7366427,7363873,7362975,7354531,7354154,7352952,7752506,7093274,7753394,7707617],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J","9LzzIocepYcOjnUsLlgOjgAAAAAAwADc","9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ","9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-","9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU","9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb","9LzzIocepYcOjnUsLlgOjgAAAAAAcF0h","9LzzIocepYcOjnUsLlgOjgAAAAAAcFmf","9LzzIocepYcOjnUsLlgOjgAAAAAAcDij","9LzzIocepYcOjnUsLlgOjgAAAAAAcDcq","9LzzIocepYcOjnUsLlgOjgAAAAAAcDJ4","9LzzIocepYcOjnUsLlgOjgAAAAAAdks6","9LzzIocepYcOjnUsLlgOjgAAAAAAbDwa","9LzzIocepYcOjnUsLlgOjgAAAAAAdk6y","9LzzIocepYcOjnUsLlgOjgAAAAAAdZvh"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"mqliNf10_gB69yQo7_zlzg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,48188,14432,38826,1480561,1970211,1481652,1480953,2600004,1079483,19966,39758,10892,28340,55468,1479960,1494280,2600004,1079483,63826,64498,1479960,2600004,1079483,60540,21276,37564,30612,1479868,2600004,1079483,54304,30612,1479868,2600004,1066627,7128,57352],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","3FRCbvQLPuJyn2B-2wELGw","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAALw8","W8AFtEsepzrJ6AasHrCttwAAAAAAADhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","EFJHOn-GACfHXgae-R1yDAAAAAAAAE3-","GdaBUD9IUEkKxIBryNqV2wAAAAAAAJtO","QU8QLoFK6ojrywKrBFfTzAAAAAAAACqM","V558DAsp4yi8bwa8eYwk5QAAAAAAAG60","tuTnMBfyc9UiPsI0QyvErAAAAAAAANis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAOx8","-9oyoP4Jj2iRkwEezqId-gAAAAAAAFMc","3FRCbvQLPuJyn2B-2wELGwAAAAAAAJK8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAANQg","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEEaD","--q8cwZVXbHL2zOM_p3RlQAAAAAAABvY","yaTrLhUSIq2WitrTHLBy3QAAAAAAAOAI"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1]},"24tLFB3hY9xz1zbZCjaBXA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7503672,7388865,7390232,7379824,6864947,6862495,2596,6843125,7212243],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","aUXpdArtZf510BJKvwiFDw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcn84","9LzzIocepYcOjnUsLlgOjgAAAAAAcL7B","9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY","9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw","9LzzIocepYcOjnUsLlgOjgAAAAAAaMAz","9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf","aUXpdArtZf510BJKvwiFDwAAAAAAAAok","9LzzIocepYcOjnUsLlgOjgAAAAAAaGr1","9LzzIocepYcOjnUsLlgOjgAAAAAAbgzT"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"MLSOPRH6z6HuctKh5rsAnA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,29084,63584,18346,1480561,1970211,1481652,1480953,2600004,1079669,3708,1480561,1970211,1481652,1480953,2600004,1079669,5350,11456,17946,62630,26608,28264,8452,1480561,1941045,1970515,1481652,1481047,2600004,1058958,26942,1844654,1847116,1788409,1758317,1865641,10490014,422731,937166],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","_s_-RvH9Io2qUzM6f5JLGg","8UGQaqEhTX9IIJEQCXnRsQ","jn4X0YIYIsTeszwLEaje9g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","TesF2I_BvQoOuJH9P_M2mA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAHGc","W8AFtEsepzrJ6AasHrCttwAAAAAAAPhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAEeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAA58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","kSaNXrGzSS3BnDNNWezzMAAAAAAAABTm","ne8F__HPIVgxgycJADVSzAAAAAAAACzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAEYa","O_h7elJSxPO7SiCsftYRZgAAAAAAAPSm","_s_-RvH9Io2qUzM6f5JLGgAAAAAAAGfw","8UGQaqEhTX9IIJEQCXnRsQAAAAAAAG5o","jn4X0YIYIsTeszwLEaje9gAAAAAAACEE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ41","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhFT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFplX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECiO","TesF2I_BvQoOuJH9P_M2mAAAAAAAAGk-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCWu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHC9M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG0n5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGtRt","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHep","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnNL","ew01Dk0sWZctP-VaEpavqQAAAAAADkzO"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,3,3,3,3,3,4,4,4]},"krdohOL0KiVMtm4q-6fmjg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,5836,10976,12298,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,37910,8000,46852,32076,49840,40252,33434,32730,43978,37948,30428,26428,19370,1480209,1940645,1970099,1481300,1480695,2595076,1079144,20016,37192,1480141,1913750],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","okehWevKsEA4q6dk779jgw","-IuadWGT89NVzIyF_Emodw","XXJY7v4esGWnaxtMW3FA0g","FbrXdcA4j750RyQ3q9JXMw","pL34QuyxyP6XYzGDBMK_5w","IoAk4kM-M4DsDPp7ia5QXw","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","fB79lJck2X90l-j7VqPR-Q","gbMheDI1NZ3NY96J0seddg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GquRfhZBLBKr9rIBPuH3nA","_DA_LSFNMjbu9L2Dcselpw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE","okehWevKsEA4q6dk779jgwAAAAAAAH1M","-IuadWGT89NVzIyF_EmodwAAAAAAAMKw","XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08","FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa","pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a","IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK","uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc","fB79lJck2X90l-j7VqPR-QAAAAAAAGc8","gbMheDI1NZ3NY96J0seddgAAAAAAAEuq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpf3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w","_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpXN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHTOW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,3,3]},"FtHYpmBv9BwyjtHQeYFcCw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,64358,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,61360,18470,16624,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1079144,14936,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1076587,6244,3453440,1376741,1877279,3072226],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8EY5iPD5-FtlXFBTyb6lkw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","dCCKy6JoX0PADOFic8hRNQ","9w9lF96vJW7ZhBoZ8ETsBw","xUQuo4OgBaS_Le-fdAwt8A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zkPjzY2Et3KehkHOcSphkA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mBpjyQvq6ftE7Wm1BUpcFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","dCCKy6JoX0PADOFic8hRNQAAAAAAAO-w","9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAEgm","xUQuo4OgBaS_Le-fdAwt8AAAAAAAAEDw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","zkPjzY2Et3KehkHOcSphkAAAAAAAADpY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAABhk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANLIA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFQHl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHKUf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuDi"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3]},"FuFG7sSEAg94nZpDT4nzlA":{"address_or_lines":[4623936,24755503,6980046,23231210,6980046,23264536,6980046,23232004,23232150,6980046,23230455,6980046,23232004,23232150,6980046,23230455,6980046,23272795,6980046,23232004,23232150,6980046,24742300,6980046,23230455,6980046,23269877,22973163,22972451,22973163,22972451,22964890,22884541,11721444,11715672,11715835,11715578,22884850,22966101,22967654,19588556,8970856,8920596,9005417,9007845,7887684,7888285,7889956,7894532,7945899,4658568,4210208],"file_ids":["pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g"],"frame_ids":["pRLjmMO0U8sO4DFopfFU5gAAAAAARo5A","pRLjmMO0U8sO4DFopfFU5gAAAAABeb0v","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnrq","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYv0Y","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYx1b","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABeYmc","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYxH1","pRLjmMO0U8sO4DFopfFU5gAAAAABXorr","pRLjmMO0U8sO4DFopfFU5gAAAAABXogj","pRLjmMO0U8sO4DFopfFU5gAAAAABXorr","pRLjmMO0U8sO4DFopfFU5gAAAAABXogj","pRLjmMO0U8sO4DFopfFU5gAAAAABXmqa","pRLjmMO0U8sO4DFopfFU5gAAAAABXTC9","pRLjmMO0U8sO4DFopfFU5gAAAAAAstrk","pRLjmMO0U8sO4DFopfFU5gAAAAAAssRY","pRLjmMO0U8sO4DFopfFU5gAAAAAAssT7","pRLjmMO0U8sO4DFopfFU5gAAAAAAssP6","pRLjmMO0U8sO4DFopfFU5gAAAAABXTHy","pRLjmMO0U8sO4DFopfFU5gAAAAABXm9V","pRLjmMO0U8sO4DFopfFU5gAAAAABXnVm","pRLjmMO0U8sO4DFopfFU5gAAAAABKuXM","pRLjmMO0U8sO4DFopfFU5gAAAAAAiOJo","pRLjmMO0U8sO4DFopfFU5gAAAAAAiB4U","pRLjmMO0U8sO4DFopfFU5gAAAAAAiWlp","pRLjmMO0U8sO4DFopfFU5gAAAAAAiXLl","pRLjmMO0U8sO4DFopfFU5gAAAAAAeFtE","pRLjmMO0U8sO4DFopfFU5gAAAAAAeF2d","pRLjmMO0U8sO4DFopfFU5gAAAAAAeGQk","pRLjmMO0U8sO4DFopfFU5gAAAAAAeHYE","pRLjmMO0U8sO4DFopfFU5gAAAAAAeT6r","pRLjmMO0U8sO4DFopfFU5gAAAAAARxWI","pRLjmMO0U8sO4DFopfFU5gAAAAAAQD4g"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"chida0TNeXOPGVvI0kALCQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,824,116,12,8,54,12,46,22,1091612,1804498,665668,663668,1112453,1232178,833111,2265137,2264574,2258601,1016110,2256845],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","IlUL618nbeW5Kz4uyGZLrQ","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","7aaw2O1Vn7-6eR8XuUWQZQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4","IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu","7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAG4jS","G68hjsyagwq6LpWrMjDdngAAAAAACihE","G68hjsyagwq6LpWrMjDdngAAAAAACiB0","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEs0y","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInap","G68hjsyagwq6LpWrMjDdngAAAAAAD4Eu","G68hjsyagwq6LpWrMjDdngAAAAAAIm_N"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"UDWRHwtQcuK3KYw4Lj118w":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,30038,33244,3444,11060,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,49806,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,61514,2790352,1482889,1482415,2595076,1057495,58094,59978,64928,29086,21086],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SD7uzoegJjRT3jYNpuQ5wQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","n74P5OxFm1hAo5ZWtgcKHQ","zXbqXCWr0lCbi_b24hNBRQ"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAIHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAMKO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","SD7uzoegJjRT3jYNpuQ5wQAAAAAAAPBK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECLX","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAP2g","n74P5OxFm1hAo5ZWtgcKHQAAAAAAAHGe","zXbqXCWr0lCbi_b24hNBRQAAAAAAAFJe"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1]},"wQhKHV5i9LyZbGr1o38TMA":{"address_or_lines":[4631744,4426728,23175065,22765086,22101979,22101626,22103238,19925815,19926028,19930622,22109732,19929162,22109403,22104583,22092442,20383549,20126576,20124268,7004126,6995902,6997458,19974869,19979184,7254420,7366379,8869213,8813007,8830631,8835818,5761274,8899923,8811367,6480793,6476612,6475553,6139725,6059982,5083307,5091601,4714216,4721177,4729434,10485923,16743,2752800,2752044,2741274,6650246,6650083,7384662,7382442,7451553,7447772,7440959,7439791],"file_ids":["-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-V-5ede56KMAXhjFbz84SwAAAAAARqzA","-V-5ede56KMAXhjFbz84SwAAAAAAQ4vo","-V-5ede56KMAXhjFbz84SwAAAAABYZ-Z","-V-5ede56KMAXhjFbz84SwAAAAABW14e","-V-5ede56KMAXhjFbz84SwAAAAABUT_b","-V-5ede56KMAXhjFbz84SwAAAAABUT56","-V-5ede56KMAXhjFbz84SwAAAAABUUTG","-V-5ede56KMAXhjFbz84SwAAAAABMAs3","-V-5ede56KMAXhjFbz84SwAAAAABMAwM","-V-5ede56KMAXhjFbz84SwAAAAABMB3-","-V-5ede56KMAXhjFbz84SwAAAAABUV4k","-V-5ede56KMAXhjFbz84SwAAAAABMBhK","-V-5ede56KMAXhjFbz84SwAAAAABUVzb","-V-5ede56KMAXhjFbz84SwAAAAABUUoH","-V-5ede56KMAXhjFbz84SwAAAAABURqa","-V-5ede56KMAXhjFbz84SwAAAAABNwc9","-V-5ede56KMAXhjFbz84SwAAAAABMxtw","-V-5ede56KMAXhjFbz84SwAAAAABMxJs","-V-5ede56KMAXhjFbz84SwAAAAAAat_e","-V-5ede56KMAXhjFbz84SwAAAAAAar--","-V-5ede56KMAXhjFbz84SwAAAAAAasXS","-V-5ede56KMAXhjFbz84SwAAAAABMMrV","-V-5ede56KMAXhjFbz84SwAAAAABMNuw","-V-5ede56KMAXhjFbz84SwAAAAAAbrGU","-V-5ede56KMAXhjFbz84SwAAAAAAcGbr","-V-5ede56KMAXhjFbz84SwAAAAAAh1Vd","-V-5ede56KMAXhjFbz84SwAAAAAAhnnP","-V-5ede56KMAXhjFbz84SwAAAAAAhr6n","-V-5ede56KMAXhjFbz84SwAAAAAAhtLq","-V-5ede56KMAXhjFbz84SwAAAAAAV-j6","-V-5ede56KMAXhjFbz84SwAAAAAAh81T","-V-5ede56KMAXhjFbz84SwAAAAAAhnNn","-V-5ede56KMAXhjFbz84SwAAAAAAYuOZ","-V-5ede56KMAXhjFbz84SwAAAAAAYtNE","-V-5ede56KMAXhjFbz84SwAAAAAAYs8h","-V-5ede56KMAXhjFbz84SwAAAAAAXa9N","-V-5ede56KMAXhjFbz84SwAAAAAAXHfO","-V-5ede56KMAXhjFbz84SwAAAAAATZCr","-V-5ede56KMAXhjFbz84SwAAAAAATbER","-V-5ede56KMAXhjFbz84SwAAAAAAR-7o","-V-5ede56KMAXhjFbz84SwAAAAAASAoZ","-V-5ede56KMAXhjFbz84SwAAAAAASCpa","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjj","piWSMQrh4r040D0BPNaJvwAAAAAAcK5W","piWSMQrh4r040D0BPNaJvwAAAAAAcKWq","piWSMQrh4r040D0BPNaJvwAAAAAAcbOh","piWSMQrh4r040D0BPNaJvwAAAAAAcaTc","piWSMQrh4r040D0BPNaJvwAAAAAAcYo_","piWSMQrh4r040D0BPNaJvwAAAAAAcYWv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"TtsX1UxF45-CxViHFwbKJw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,33388,19218,34134,37340,19828,11060,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,53982,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,41518,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,26922,19187,41240,50343],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uo8E5My6tupMEt-pfV-uhA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAIVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAANLe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAGkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSn"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"iu7dYG1YyobzAXC7AJADOw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,4,38,174,104,68,88,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044755,2041537,2044780,2041460,1171829,2265239,2264574,2258463,1179954],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZBnr-5IlLVGCdkX_lTNKmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNs","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAEgEy"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"WmwSnxyphedkasVyGbhNdg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,23142,41180,18932,30244,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,29418,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,58990,2795776,1483241,1482767,2600004,1073803,3150,5208,43696,4204,342,33506,2852079,2851771,2849353,2846190,2846190,2845732],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","l97YFeEKpeLfa-lEAZVNcA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAAHYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2wk"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"YWZby9VC56JtR6BAaYHEoA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,16796,14432,6058,1480561,1970211,1481652,1480953,2600004,1079669,20092,1480561,1970211,1481652,1480953,2600004,1062448,57610,1845095,1847963,1481919,2600004,1079483,60588,38154,52556,1479960,1494280,2600004,1079483,55468,1479960,1494280,2600004,1079483,14674,64498,1479960,2600004,1079483,48678,25810,37884,46996,1479868,2600004,1079483,7536,46996,1479868,2600004,1049946,29322],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","-T5rZCijT5TDJjmoEi8Kxg","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEGc","W8AFtEsepzrJ6AasHrCttwAAAAAAADhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAE58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEDYw","kSaNXrGzSS3BnDNNWezzMAAAAAAAAOEK","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCdn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDKb","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAOys","MYrgKQIxdDhr1gdpucfc-QAAAAAAAJUK","un9fLDZOLvDMO52ltZtuegAAAAAAAM1M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","tuTnMBfyc9UiPsI0QyvErAAAAAAAANis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAADlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","rTFMSHhLRlj86vHPR06zoQAAAAAAAL4m","oArGmvsy3VNtTf_V9EHNeQAAAAAAAGTS","-T5rZCijT5TDJjmoEi8KxgAAAAAAAJP8","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAB1w","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEAVa","--q8cwZVXbHL2zOM_p3RlQAAAAAAAHKK"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1]},"Hi8HEHDniMkBvPgm-_IXdg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,50422,53628,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,3426,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,5270,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1055190,28766,23366,29852,29250,6740,37336,23068],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ynoRUNDFNh_CC1ViETMulA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fxzD8soKl4etJ4L6nJl81g","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAMT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAANF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAA1i","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ynoRUNDFNh_CC1ViETMulAAAAAAAABSW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEBnW","fxzD8soKl4etJ4L6nJl81gAAAAAAAHBe","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFoc"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1]},"X86DUuQ7tHAxGBaWu4tZLg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,19046,37084,2548,13860,26096,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,64610,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,39726,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,0,2794972,1848805,1837992,1848417,2718329,2222078,2208786],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqXc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHAuo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDRh","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKXp5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIef-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIbQS"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"Tx8lhCcOjrVLOl1hWK6aBw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,38700,43744,45066,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1062336,4250,1844695,1847563,1481567,2595076,1079485,3004,57258,27404,1479608,1493928,2595076,1079485,63084,1479608,1493928,2595076,1079485,14194,64498,1479608,2595076,1079485,18374,41842,34364,14228,1479516,2595076,1079485,24640,14228,1479516,2595076,1087128,21352,26392,2571436,1909209],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAJcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAALAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAABCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAN-q","un9fLDZOLvDMO52ltZtuegAAAAAAAGsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAPZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAADdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAAEfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAGBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEJaY","--q8cwZVXbHL2zOM_p3RlQAAAAAAAFNo","yaTrLhUSIq2WitrTHLBy3QAAAAAAAGcY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJzys","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHSHZ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3]},"oKVObqTWF9QIjxgKf8UkTw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,51328,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,50170,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,13752,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41068,49494,4746,19187,41141,49404],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","08Dc0vnMK9C_nl7yQB6ZKQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zuPG_tF81PcJTwjfBwKlDg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKC1","jaBVtokSUzfS97d-XKjijgAAAAAAAMD8"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"rsb7cL4OAenBHrp0F_Wcgg":{"address_or_lines":[30070,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,1150,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,47798,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,18886,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1074397,51858,2586225,2600004,1055835,28542,1975041,2600004,1079669,52004,1480561,1940968,1917658,1481652,1480953,2600004,1057290,36296,2944663],"file_ids":["pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BuJIbGFo3xNyZaTAXvW1Ag","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","L9BMhx_jo5vrPGr_NYlXCQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pZhbjLL2hYCcec5rSvEEGw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kkqG_q7yucIGLE7ky-QX9A","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["pv4wAezdMMO0SVuGgaEMTgAAAAAAAHV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAAR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAALq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAEnG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","BuJIbGFo3xNyZaTAXvW1AgAAAAAAAMqS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEBxb","L9BMhx_jo5vrPGr_NYlXCQAAAAAAAG9-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHiMB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","pZhbjLL2hYCcec5rSvEEGwAAAAAAAMsk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECIK","kkqG_q7yucIGLE7ky-QX9AAAAAAAAI3I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALO6X"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,1,3,3,3,1,3,3,3,3,3,3,3,1,3]},"mWVVBnqMHfG9pWtaZUm47Q":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,1058,33388,19218,58614,61820,19828,11060,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11498,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,56810,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,31598,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,51498,19187,41240,50348],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3HhVgGD2yvuFLpoZq7RfKw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uSWUCgHgLPG4OFtPdUp0rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAACzq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAN3q","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSs"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"r1nqJ9JqsZyOKqlpBmuvLg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,30508,27360,36874,1480209,1969795,1481300,1480601,2595076,1079144,18252,1480209,1969795,1481300,1480601,2595076,1062336,61594,1844695,1847563,1481567,2595076,1079485,3004,49066,11020,1479608,1493928,2595076,1079485,46700,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,10182,25458,17980,63380,1479516,2595076,1079485,16448,63380,1479516,2595076,1073749,13188,3118087,767068,768138,10485923,16807,2845274,2841596,3817899,3815886,3627192],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAEdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q","un9fLDZOLvDMO52ltZtuegAAAAAAACsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAALZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAACfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAGNy","7v-k2b21f_Xuf-3329jFywAAAAAAAEY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAADOE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL5QH","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7Rc","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7iK","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2pa","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAOkGr","A2oiHVwisByxRn5RDT4LjAAAAAAAOjnO","A2oiHVwisByxRn5RDT4LjAAAAAAAN1i4"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,3,4,4,4,4,4,4,4]},"5MDEZjYH98Woy4iHbcvgDg":{"address_or_lines":[2573747,2594708,1091475,65190,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,22586,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,12514,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,25530,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,37170,2790352,1482889,1482415,2595076,1079144,58108,1481694,1493928,2595076,1080441,8392,15128,1480209,1827586,3439453,2746712,2738096],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","s6flibJ32CsA8wnq-j6RkQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3EA5Wz2lIIw6eu5uv4gkTw","hjYcB64xHdoySaNOZ8xYqg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAP6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAAFg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAADDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAAGO6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","s6flibJ32CsA8wnq-j6RkQAAAAAAAJEy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAOL8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHx5","3EA5Wz2lIIw6eu5uv4gkTwAAAAAAACDI","hjYcB64xHdoySaNOZ8xYqgAAAAAAADsY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANHtd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKelY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKcew"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,1,1,3,3,3,3,3]},"WYRZ4mSdJHjsW8s2yoKnfA":{"address_or_lines":[1858,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,30594,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,34158,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1079144,56186,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079485,9718,1479772,1827586,1940195,1986609,1483518,1482415,1493679,2595076,1073425,15208,2566502,1844254,1972704,2595076,1071886,41592,1850963,1844695,1917599,1539319,3072295,1865140],"file_ids":["Gp9aOxUrrpSVBx4-ftlTOA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","y9R94bQUxts02WzRWfV7xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uI6css-d8SGQRK6a_Ntl-A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SlnkBp0IIJFLHVOe4KbxwQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uPGvGNXBf1JXGeeDSsmGQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmtIuZrIdDPbhY30JCQRww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yos2k6ZH69vZXiBQV3d7cQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAAdC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","y9R94bQUxts02WzRWfV7xgAAAAAAAHeC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uI6css-d8SGQRK6a_Ntl-AAAAAAAAIVu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","SlnkBp0IIJFLHVOe4KbxwQAAAAAAANt6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","uPGvGNXBf1JXGeeDSsmGQAAAAAAAACX2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHlAx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsqv","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","PmtIuZrIdDPbhY30JCQRwwAAAAAAADto","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJylm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCQe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhng","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFsO","yos2k6ZH69vZXiBQV3d7cQAAAAAAAKJ4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHD5T","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUKf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF3z3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHW0"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3]},"C4ItszXjQjtRADEg560AUw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,30508,10976,36874,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1062336,61594,1844695,1847563,1481567,2595076,1079485,35772,49066,60172,1479608,1493928,2595076,1079485,30316,1479608,1493928,2595076,1079485,30578,15346,1479608,2595076,1079485,10678,9074,1596,46996,1479516,2595076,1079485,16448,46996,1479516,2595076,1073749,13088,6410,24756,3150002,920932,10485923,16807,2776792,2775330,2826677,2809533,2807255,2804657,2869654],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","wXOyVgf5_nNg6CUH5kFBbg","zEgDK4qMawUAQZjg5YHyww","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q","un9fLDZOLvDMO52ltZtuegAAAAAAAOsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAHZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAACm2","oArGmvsy3VNtTf_V9EHNeQAAAAAAACNy","7v-k2b21f_Xuf-3329jFywAAAAAAAAY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAADMg","wXOyVgf5_nNg6CUH5kFBbgAAAAAAABkK","zEgDK4qMawUAQZjg5YHywwAAAAAAAGC0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMBCy","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADg1k","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKl7Y","A2oiHVwisByxRn5RDT4LjAAAAAAAKlki","A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1","A2oiHVwisByxRn5RDT4LjAAAAAAAKt69","A2oiHVwisByxRn5RDT4LjAAAAAAAKtXX","A2oiHVwisByxRn5RDT4LjAAAAAAAKsux","A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,1,3,3,4,4,4,4,4,4,4,4,4]},"8IBqDIuSolkkEHIjO_CfMw":{"address_or_lines":[1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,57338,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,46806,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,4702,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,25478,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1079144,57700,1481694,1828960,2580566,1480601,1493679,2595076,1052274,37402,1973088,2595076,1059438,7162],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VY0EiAO0DxwLRTE4PfFhdw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2AkHKX3hFovQqnWGTZG4BA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","JEYMXKhPKBKP90oNIKO6Ww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Fq3uvTWKo9OreZfu-LOYYQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","f2CfX6aaJGZ4Su3cCY2vCQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yxUFWTEZsQP-FeNV2RKnFQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Q2lceMFM0t8w5Hdokg8e8A"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VY0EiAO0DxwLRTE4PfFhdwAAAAAAAN_6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2AkHKX3hFovQqnWGTZG4BAAAAAAAALbW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","JEYMXKhPKBKP90oNIKO6WwAAAAAAABJe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","Fq3uvTWKo9OreZfu-LOYYQAAAAAAAGOG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","f2CfX6aaJGZ4Su3cCY2vCQAAAAAAAOFk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2BW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsqv","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEA5y","yxUFWTEZsQP-FeNV2RKnFQAAAAAAAJIa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhtg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECpu","Q2lceMFM0t8w5Hdokg8e8AAAAAAAABv6"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,1,3,3,3,1]},"T2hqeT_yirkauwcO1cGJEw":{"address_or_lines":[74,6,18,8,18,80,24,4,84,38,174,104,68,116,38,174,104,68,4,38,174,104,68,96,38,174,104,68,60,38,38,10,38,174,104,68,124,38,174,104,68,124,38,174,104,68,100,140,10,38,174,104,68,76,38,174,34,24,10,10,786829,1091612,1986900,1997206,2238455,4240,5748,1213299,4101,76200,1213299,77535,52678,1213299,52081,33630,106222],"file_ids":["a5aMcPOeWx28QSVng73nBQ","inI9W0bfekFTCpu0ceKTHg","RPwdw40HEBL87wRkKV2ozw","pT2bgvKv3bKR6LMAYtKFRw","Rsr7q4vCSh2ppRtyNkwZAA","cKQfWSgZRgu_1Goz5QGSHw","T2fhmP8acUvRZslK7YRDPw","lrxXzNEmAlflj7bCNDjxdA","SMoSw8cr-PdrIATvljOPrQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xaCec3W8F6xlvd_EISI7vw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","QCNrAtEDVSYrGKsToy3LYA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ocuGLNOciiOP6W8cfH2-qw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bjI4Jot-SXYwqfMr0sl7Xg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjBJSIgrJ7WBnrV9WxdKEQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9-_Y7FNFlkawnHBUI4HVnA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","suQJt7m9qyZP3i8d45HwBQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5w2Emmm2pdiPFBnzFSNcKg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","1bzyoH1Mbbzc-oKA3fR-7Q","BXKFYOU6E7YaW5MDpfBf8w","zP58DjIs7uq1cghmzykyNA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAABK","inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG","RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS","pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI","Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS","cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ","T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY","lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE","SMoSw8cr-PdrIATvljOPrQAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xaCec3W8F6xlvd_EISI7vwAAAAAAAAB0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","QCNrAtEDVSYrGKsToy3LYAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ocuGLNOciiOP6W8cfH2-qwAAAAAAAABg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bjI4Jot-SXYwqfMr0sl7XgAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjBJSIgrJ7WBnrV9WxdKEQAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9-_Y7FNFlkawnHBUI4HVnAAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","suQJt7m9qyZP3i8d45HwBQAAAAAAAABk","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5w2Emmm2pdiPFBnzFSNcKgAAAAAAAABM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAAAi","1bzyoH1Mbbzc-oKA3fR-7QAAAAAAAAAY","BXKFYOU6E7YaW5MDpfBf8wAAAAAAAAAK","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","G68hjsyagwq6LpWrMjDdngAAAAAADAGN","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAHlFU","G68hjsyagwq6LpWrMjDdngAAAAAAHnmW","G68hjsyagwq6LpWrMjDdngAAAAAAIif3","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAAS7f","3nN3bymnZ8E42aLEtgglmAAAAAAAAM3G","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAAMtx","3nN3bymnZ8E42aLEtgglmAAAAAAAAINe","3nN3bymnZ8E42aLEtgglmAAAAAAAAZ7u"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"OIXgOJgQPE-F5rS7DPPzZA":{"address_or_lines":[2795776,1483241,1482767,2600004,1079483,23630,25172,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1091600,20658,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1091600,0,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1079669,0,1482046,1829360,2586225,2600004,1079669,36060,1482046,1829360,2586325,1481195,1480561,1940968,1917658,1481652,1480953,2600004,1079483,61874,1480124,1827986,1940595,1989057,1480953,1494106,2600004,1073803,20418,2569666],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","93AmMdBRQTTNSFcMQ_Ywdg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","29RxCcCS3qayH8Wz47EBXQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","mBpjyQvq6ftE7Wm1BUpcFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IWme5rHQfgYd-9YstXSeGA","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","93AmMdBRQTTNSFcMQ_YwdgAAAAAAAFCy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","29RxCcCS3qayH8Wz47EBXQAAAAAAAIzc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpnr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAPGy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpW8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlnB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFsxa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","IWme5rHQfgYd-9YstXSeGAAAAAAAAE_C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJzXC"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,1,3]},"i0e78nPZCZ2CbzzLMEOcMw":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,38,10,38,38,10,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044733,2042086,2025366,954962],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzM9","G68hjsyagwq6LpWrMjDdngAAAAAAHyjm","G68hjsyagwq6LpWrMjDdngAAAAAAHueW","G68hjsyagwq6LpWrMjDdngAAAAAADpJS"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"34DMF2kw8Djh_MjcdchMzw":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,34914,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,7430,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,3230,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,61846,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1079669,38686,1482046,1829360,2586225,2600004,1079669,15794,56134,43516,45442,36964,61672,47980,1480561,1940984,1479155],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","y4VaggFtn5eGbiM4h45zCg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aovhV1VhdNHhPwAmk_rOhg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","px3SfTg4DYOeiT_Yemty2w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","opI8K6Q9RBhmYCrRVwNTgA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cVEUVwL4zVVcM9r_4PTCXA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GGxNFCJdZtgXLG8zgUfn_Q","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","y4VaggFtn5eGbiM4h45zCgAAAAAAAIhi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","aovhV1VhdNHhPwAmk_rOhgAAAAAAAB0G","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","px3SfTg4DYOeiT_Yemty2wAAAAAAAAye","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","opI8K6Q9RBhmYCrRVwNTgAAAAAAAAPGW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","cVEUVwL4zVVcM9r_4PTCXAAAAAAAAJce","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","GGxNFCJdZtgXLG8zgUfn_QAAAAAAAD2y","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAKn8","_lF8o5tJDcePvza_IYtgSQAAAAAAALGC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAJBk","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAPDo","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALts","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpHz"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3]},"XG9tjujXJl2nWpbHppoRMA":{"address_or_lines":[2573747,2594708,1091475,39286,2790352,1482889,1482415,2595076,1079485,29422,30964,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10138,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,58142,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,47402,19187,41240,50602],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ZVYMRqiL5oPAMqs8XcON8Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1y9WuJpjgBMcQb3shY5phQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ZVYMRqiL5oPAMqs8XcON8QAAAAAAAJl2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACea","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1y9WuJpjgBMcQb3shY5phQAAAAAAAOMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMWq"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"SrSwvDbs2pmPg3SRfXJBCA":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11318,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,15678,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,250,2790352,1482889,1482415,2595076,1076587,29422,31480,4464,17976,33110,51586,2846655,2846347,2843929,2840766,2843907,2841214,1439462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NGbZlnLCqeq3LFq89r_SpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PmhxUKv5sePRxhCBONca8gAAAAAAAAD6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbm"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3]},"bcNRMcXtTRgNPl4vy6M5KQ":{"address_or_lines":[2573747,2594708,1091475,48050,2789627,1482889,1482415,2595076,1079485,29808,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,47414,2789627,1482889,1482415,2595076,1079485,29808,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,21414,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,12682,2790352,1482889,1482415,2595076,1076587,33518,35576,8560,17976,49494,55682,2846655,2846347,2843929,2840766,2843929,2840766,2843954,2840766,2841312],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xDXQtI2vA5YySwpx7QFiwA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fSQ747oLNh0c0zFQjsVRWg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yp8MidCGMe4czbl-NigsYQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2noK4QoWxdzASRHkjOFwVA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","xDXQtI2vA5YySwpx7QFiwAAAAAAAALuy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fSQ747oLNh0c0zFQjsVRWgAAAAAAALk2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","yp8MidCGMe4czbl-NigsYQAAAAAAAFOm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2noK4QoWxdzASRHkjOFwVAAAAAAAADGK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Uy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1rg"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"XmiUdMqa5OViUnHQ_LS4Uw":{"address_or_lines":[61654,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,61890,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,27010,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,2254,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,108,49494,29322,19187,41240,50348],"file_ids":["mfGJjedIJMvFXgX3QuTMfQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","9NWoah56eYULAP_zGE9Puw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IKrIDHd5n47PpDQsRXxvvg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oG7568kMJujZxPJfj7VMjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["mfGJjedIJMvFXgX3QuTMfQAAAAAAAPDW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","9NWoah56eYULAP_zGE9PuwAAAAAAAPHC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","IKrIDHd5n47PpDQsRXxvvgAAAAAAAGmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","oG7568kMJujZxPJfj7VMjAAAAAAAAAjO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSs"],"type_ids":[1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"3odHGojcaqq4ImPnmLLSzw":{"address_or_lines":[1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,43246,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,17846,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,13950,2795051,1483241,1482767,2600004,1079483,60880,9382,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1079669,4762,1482046,1829360,2586225,2600004,1079669,34130,1480561,1941045,1970515,1481652,1480953,2600004,1069341,25906,23366,39420,41384,9542,10212,11330,8962,13084,1693331,1865533],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","HENgRXYeEs7mDD8Gk_MNmg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fFS0upy5lIaT99RhlTN5LQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lSdGU4igLMOpLhL_6XP15w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","QAp_Nt6XUeNsCXnAUgW7Xg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","20O937106XMbOD0LQR4SPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","HENgRXYeEs7mDD8Gk_MNmgAAAAAAAKju","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fFS0upy5lIaT99RhlTN5LQAAAAAAAEW2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lSdGU4igLMOpLhL_6XP15wAAAAAAADZ-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAO3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAACSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAABKa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","20O937106XMbOD0LQR4SPwAAAAAAAIVS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ41","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhFT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEFEd","gPzb0fXoBe1225fbKepMRAAAAAAAAGUy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAJn8","_lF8o5tJDcePvza_IYtgSQAAAAAAAKGo","OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG","E2b-mzlh_8261-JxcySn-AAAAAAAACfk","E2b-mzlh_8261-JxcySn-AAAAAAAACxC","E2b-mzlh_8261-JxcySn-AAAAAAAACMC","JrU1PwRIxl_8SXdnTESnogAAAAAAADMc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGdaT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHc9"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3]},"bRKRM4i4-XY2LCfN18mOow":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,32078,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,9638,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,5742,2789627,1482889,1482415,2595076,1079485,25712,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1079144,37050,1481694,1828960,2581297,2595076,1079144,25922,1480209,1940645,1970099,1481300,1480601,2595076,1052274,41714,56134,54428,53864,42310,53828,54946,52578,59942,1429990,1365958,1365461],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","HENgRXYeEs7mDD8Gk_MNmg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fFS0upy5lIaT99RhlTN5LQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lSdGU4igLMOpLhL_6XP15w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","QAp_Nt6XUeNsCXnAUgW7Xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","20O937106XMbOD0LQR4SPw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","HENgRXYeEs7mDD8Gk_MNmgAAAAAAAH1O","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fFS0upy5lIaT99RhlTN5LQAAAAAAACWm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","lSdGU4igLMOpLhL_6XP15wAAAAAAABZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","20O937106XMbOD0LQR4SPwAAAAAAAGVC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEA5y","gPzb0fXoBe1225fbKepMRAAAAAAAAKLy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAANSc","_lF8o5tJDcePvza_IYtgSQAAAAAAANJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAAKVG","E2b-mzlh_8261-JxcySn-AAAAAAAANJE","E2b-mzlh_8261-JxcySn-AAAAAAAANai","E2b-mzlh_8261-JxcySn-AAAAAAAAM1i","JrU1PwRIxl_8SXdnTESnogAAAAAAAOom","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFdHm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFNfG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFNXV"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3]},"W936jUeelyxTrQQ2V9mn-w":{"address_or_lines":[1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,59834,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,60574,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,64656,2790352,1482889,1482415,2595076,1079485,13038,14580,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,42430,2790352,1482889,1482415,2595076,1076587,13038,15096,53616,1592,16726,47490,2846655,2846347,2843929,2840766,2843929,2840766,2843929,2840766,2840766,2842897,2268402,1775000,1761295,1048381],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWCVT22bUHN0NWIQIBSuKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zj3hc8VBXxWxcbGVwJZYLA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EHb2BWbkIivImSAfaUtw-A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-7Nhzq0bVRejx7IVqpbbZQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWCVT22bUHN0NWIQIBSuKgAAAAAAAOm6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zj3hc8VBXxWxcbGVwJZYLAAAAAAAAOye","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","EHb2BWbkIivImSAfaUtw-AAAAAAAAPyQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","-7Nhzq0bVRejx7IVqpbbZQAAAAAAAKW-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2ER","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_89"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"AlH3zgnqwh5sdMMzX8AXxg":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52130,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,61558,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17970,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1066158,3868,39750,21660,21058,64084,29144,22318,29144,18030,1840882,1970521,2595076,1049850,1910],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Gxt7_MN7XgUOe9547JcHVQ"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAMui","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAT6","Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,1]},"YHwQa4NMDpWa9cokfF0xqw":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,35162,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,62314,2795776,1483241,1482767,2600004,1079669,19534,21418,26368,41208,8202,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,34238,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,55698,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4204,33110,33418,19187,41240,50763],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAIla","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAPNq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4","h0l-9tGi18mC40qpcJbyDwAAAAAAACAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAIW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAANmS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAIKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMZL"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"AlRn0MJA_RCD0pN2OpIRZA":{"address_or_lines":[1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,11962,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,59882,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,31598,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,28926,2789627,1482889,1482415,2595076,1079485,13424,27494,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1076587,17134,19192,57712,1592,33110,51586,2846655,2846347,2843929,2840766,2843929,2840766,2843907,2841214,1439429,1865241,10489950,423063,2283967,2281521,8542303],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3HhVgGD2yvuFLpoZq7RfKw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uSWUCgHgLPG4OFtPdUp0rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-BjW54fwMksXBor9R-YN9w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAC66","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAOnq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","-BjW54fwMksXBor9R-YN9wAAAAAAAHD-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAItAx","A2oiHVwisByxRn5RDT4LjAAAAAAAglhf"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"inhNt-Ftru1dLAPaXB98Gw":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,8722,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,20598,2790352,1482889,1482415,2595076,1079485,62190,63732,7014,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,25154,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,40098,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1066158,25996,23366,46236,45634,23124,53720,46894,53720,46894,53720,46894,53720,42606,1840882,1970521,2594999,2587827],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAACIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0","eV_m28NnKeeTL60KO2H3SAAAAAAAABtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAAGJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAGWM","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc","_lF8o5tJDcePvza_IYtgSQAAAAAAALJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAKZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5i3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ3yz"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"qaaAfLAUIerA8yhApFJRYQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,72,38,174,104,68,88,38,174,104,68,124,38,38,10,38,174,104,68,72,38,174,104,68,120,38,174,104,68,354,6,108,20,50,50,2970,50,2970,50,2970,50,684,1109029,956192],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qkYSh95E1urNTie_gKbr7w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","V8ldXm9NGXsJ182jEHEsUw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xVaa0cBWNcFeS-8zFezQgA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","UBINlIxj95Sa_x2_k5IddA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gRRk0W_9P4SGZLXFJ5KU8Q","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","cbxfeE2AkqKne6oKUxdB6g","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qkYSh95E1urNTie_gKbr7wAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAFi","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU","cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAKs","G68hjsyagwq6LpWrMjDdngAAAAAAEOwl","G68hjsyagwq6LpWrMjDdngAAAAAADpcg"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"cj3H8UtNXHeFFvSKCpbt_Q":{"address_or_lines":[1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,58218,2795776,1483241,1482767,2600004,1079669,7246,9130,14080,57592,61450,9764,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,22430,50622,6396,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,51602,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,62974,2795776,1483241,1482767,2600004,1079483,7246,9304,47608,55224,29888,17574,1479868,1829983,2783616,2800188,3063028,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,38821],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zo4mnjDJ1PlZka7jS9k2BA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAONq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAADcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAOD4","h0l-9tGi18mC40qpcJbyDwAAAAAAAPAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAACYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAAFee","TBeSzkyqIwKL8td602zDjAAAAAAAAMW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAABj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAMmS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPX-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALn4","0S3htaCNkzxOYeavDR1GTQAAAAAAANe4","rBzW547V0L_mH4nnWK1FUQAAAAAAAHTA","eV_m28NnKeeTL60KO2H3SAAAAAAAAESm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKnmA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKro8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALrz0","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJel"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"XT5dbBR70HCMmAkhladaCQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,44,38,38,10,38,174,104,68,4,38,174,104,68,40,38,174,104,68,68,38,38,10,38,174,104,68,4,38,174,104,14,32,166,1090933,19429,42789,49059],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ED3bhsHkhBwZ5ynmMnkPRA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","cZ-wyq9rmPl5QnqP0Smp6Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GLV-c6bk0E-nhaaCp6u20w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","c_1Yb4rio2EAH6C9SFwQog","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","O4ILxZswquMzuET9RRf5QA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GLV-c6bk0E-nhaaCp6u20wAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","c_1Yb4rio2EAH6C9SFwQogAAAAAAAABE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","O4ILxZswquMzuET9RRf5QAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKcl","jaBVtokSUzfS97d-XKjijgAAAAAAAL-j"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"Kfnso_5TQwyEGb1cfr-n5A":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,44,38,38,10,38,174,104,68,4,38,174,104,68,64,38,174,104,68,40,38,174,104,68,48,38,174,104,14,32,166,1090933,19429,41240,51098,10490014,423687,2280415,2277754,2506475,2411027,2395201],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ED3bhsHkhBwZ5ynmMnkPRA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","cZ-wyq9rmPl5QnqP0Smp6Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GLV-c6bk0E-nhaaCp6u20w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rJZ4aC9w8bMvzrC0ApyIjg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","TC9v9fO0nTP4oypYCgB_1Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GLV-c6bk0E-nhaaCp6u20wAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rJZ4aC9w8bMvzrC0ApyIjgAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","TC9v9fO0nTP4oypYCgB_1QAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMea","piWSMQrh4r040D0BPNaJvwAAAAAAoBCe","piWSMQrh4r040D0BPNaJvwAAAAAABncH","piWSMQrh4r040D0BPNaJvwAAAAAAIsvf","piWSMQrh4r040D0BPNaJvwAAAAAAIsF6","piWSMQrh4r040D0BPNaJvwAAAAAAJj7r","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIxB"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,4,4,4,4,4,4,4]},"O3_UY4IxBGbcnXlHSqWz_w":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,210,1090933,1814182,788459,788130,1197048,1243927,788130,1197115,1198576,1948785,1941513],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAADS","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvsX","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAEknw","G68hjsyagwq6LpWrMjDdngAAAAAAHbxx","G68hjsyagwq6LpWrMjDdngAAAAAAHaAJ"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"piWSMQrh4r040D0BPNaJvwAAAAAAoAJU":{"file_name":[],"function_name":["ret_from_fork"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACtfS":{"file_name":[],"function_name":["kthread"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEFgJ":{"file_name":[],"function_name":["rcu_gp_kthread"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI":{"file_name":["libmount/src/tab_parse.c"],"function_name":["__mnt_table_parse_mtab"],"function_offset":[],"line_number":[1102]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W":{"file_name":["libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_file"],"function_offset":[],"line_number":[707]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAYhK":{"file_name":["libmount/src/tab_parse.c","libmount/src/tab_parse.c","libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_stream","mnt_table_parse_next","mnt_parse_mountinfo_line"],"function_offset":[],"line_number":[643,506,215]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAO6N":{"file_name":["libmount/src/fs.c","libmount/src/fs.c"],"function_name":["mnt_fs_strdup_options","merge_optstr"],"function_offset":[],"line_number":[751,715]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAASUz":{"file_name":["libmount/src/optstr.c"],"function_name":["mnt_optstr_remove_option"],"function_offset":[],"line_number":[490]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAR50":{"file_name":["libmount/src/optstr.c"],"function_name":["mnt_optstr_locate_option"],"function_offset":[],"line_number":[122]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1":{"file_name":[],"function_name":["__x64_sys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM":{"file_name":[],"function_name":["ksys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8":{"file_name":[],"function_name":["iterate_dir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ":{"file_name":[],"function_name":["proc_pid_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu":{"file_name":[],"function_name":["next_tgid"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACq1j":{"file_name":[],"function_name":["pid_nr_ns"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKl_w":{"file_name":[],"function_name":["__do_sys_newfstatat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKlki":{"file_name":[],"function_name":["vfs_statx"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1":{"file_name":[],"function_name":["filename_lookup"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKt7k":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKtt7":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKta7":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK7NA":{"file_name":[],"function_name":["dput"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg_g":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgzs":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeLa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePOo":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7HT":{"file_name":[],"function_name":["skb_copy_datagram_from_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAASk0o":{"file_name":[],"function_name":["copy_page_from_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAShZh":{"file_name":[],"function_name":["copyin"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgUld":{"file_name":[],"function_name":["copy_user_enhanced_fast_string"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ":{"file_name":[],"function_name":["unix_stream_read_actor"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJ7H":{"file_name":[],"function_name":["seq_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMqWN":{"file_name":[],"function_name":["proc_single_show"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMprm":{"file_name":[],"function_name":["proc_pid_limits"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJVd":{"file_name":[],"function_name":["seq_printf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJTv":{"file_name":[],"function_name":["seq_vprintf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgQON":{"file_name":[],"function_name":["vsnprintf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgWrH":{"file_name":[],"function_name":["memcpy_erms"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqah":{"file_name":[],"function_name":["__x64_sys_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM":{"file_name":[],"function_name":["do_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7":{"file_name":[],"function_name":["__do_pipe_flags"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqSa":{"file_name":[],"function_name":["create_pipe_files"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKh1i":{"file_name":[],"function_name":["alloc_file_clone"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhts":{"file_name":[],"function_name":["alloc_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhqi":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhaJ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwdF":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu55":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKg3y":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgnZ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvxU":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvpt":{"file_name":[],"function_name":["__slab_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvhM":{"file_name":[],"function_name":["___slab_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJu2y":{"file_name":[],"function_name":["new_slab"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJMoT":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIkv":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxC":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQFQm":{"file_name":[],"function_name":["security_file_permission"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkft":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAShdv":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgAA":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKfyY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdJz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd-3C":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd-tk":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlea":{"file_name":[],"function_name":["consume_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZltq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJHy1":{"file_name":[],"function_name":["free_unref_page"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJFUJ":{"file_name":[],"function_name":["free_unref_page_prepare.part.71"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmbb":{"file_name":[],"function_name":["sock_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAQGQD":{"file_name":[],"function_name":["security_socket_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcn3R":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJu6z":{"file_name":[],"function_name":["kmem_cache_free"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJuT8":{"file_name":[],"function_name":["__slab_free"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK":{"file_name":[],"function_name":["kmem_cache_alloc_node"],"function_offset":[],"line_number":[]},"N4ILulabOfF5MnyRJbvDXwAAAAAAEHzT":{"file_name":["/usr/src/debug/Python-2.7.18/Modules/main.c"],"function_name":["Py_Main"],"function_offset":[],"line_number":[645]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD20Q":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["PyRun_SimpleFileExFlags"],"function_offset":[],"line_number":[957]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD1xx":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["PyRun_FileExFlags"],"function_offset":[],"line_number":[1371]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD0wq":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["run_mod"],"function_offset":[],"line_number":[1385]},"N4ILulabOfF5MnyRJbvDXwAAAAAADdJo":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalCode"],"function_offset":[],"line_number":[691]},"N4ILulabOfF5MnyRJbvDXwAAAAAADdBO":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalCodeEx"],"function_offset":[],"line_number":[3685]},"N4ILulabOfF5MnyRJbvDXwAAAAAADaC9":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","fast_function"],"function_offset":[],"line_number":[3087,4473,4548]},"N4ILulabOfF5MnyRJbvDXwAAAAAADaoW":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","fast_function"],"function_offset":[],"line_number":[3087,4473,4538]},"N4ILulabOfF5MnyRJbvDXwAAAAAADYlW":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","ext_do_call"],"function_offset":[],"line_number":[3126,4767]},"N4ILulabOfF5MnyRJbvDXwAAAAAABLuy":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/abstract.c"],"function_name":["PyObject_Call"],"function_offset":[],"line_number":[2544]},"N4ILulabOfF5MnyRJbvDXwAAAAAABtnu":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/funcobject.c"],"function_name":["function_call"],"function_offset":[],"line_number":[523]},"N4ILulabOfF5MnyRJbvDXwAAAAAADYFz":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","do_call"],"function_offset":[],"line_number":[3087,4475,4670]},"N4ILulabOfF5MnyRJbvDXwAAAAAACasJ":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/typeobject.c"],"function_name":["type_call"],"function_offset":[],"line_number":[765]},"N4ILulabOfF5MnyRJbvDXwAAAAAACd8S":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/typeobject.c"],"function_name":["slot_tp_init"],"function_offset":[],"line_number":[5869]},"N4ILulabOfF5MnyRJbvDXwAAAAAABZYn":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/classobject.c"],"function_name":["instancemethod_call"],"function_offset":[],"line_number":[2600]},"N4ILulabOfF5MnyRJbvDXwAAAAAABtkY":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/funcobject.c"],"function_name":["function_call"],"function_offset":[],"line_number":[523]},"N4ILulabOfF5MnyRJbvDXwAAAAAADV_P":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx"],"function_offset":[],"line_number":[1629]},"N4ILulabOfF5MnyRJbvDXwAAAAAAB9cG":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/dictobject.c"],"function_name":["dict_subscript"],"function_offset":[],"line_number":[1261]},"N4ILulabOfF5MnyRJbvDXwAAAAAAB7wG":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/dictobject.c"],"function_name":["lookdict"],"function_offset":[],"line_number":[351]},"N4ILulabOfF5MnyRJbvDXwAAAAAACDtP":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["PyObject_RichCompareBool"],"function_offset":[],"line_number":[1009]},"N4ILulabOfF5MnyRJbvDXwAAAAAACDr6":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c","/usr/src/debug/Python-2.7.18/Objects/object.c","/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["PyObject_RichCompare","do_richcmp","try_3way_to_rich_compare"],"function_offset":[],"line_number":[987,940,921]},"N4ILulabOfF5MnyRJbvDXwAAAAAACByz":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["convert_3way_to_object"],"function_offset":[],"line_number":[881]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9":{"file_name":[],"function_name":["__kmalloc_reserve.isra.57"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR":{"file_name":[],"function_name":["__kmalloc_node_track_caller"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk":{"file_name":[],"function_name":["kmalloc_slab"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaM05":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMRj":{"file_name":[],"function_name":["validate_xmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J":{"file_name":[],"function_name":["do_softirq_own_stack"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-":{"file_name":[],"function_name":["process_backlog"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU":{"file_name":[],"function_name":["__netif_receive_skb_one_core"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb":{"file_name":[],"function_name":["ip_rcv"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcF0h":{"file_name":[],"function_name":["ip_rcv_finish"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcFmf":{"file_name":[],"function_name":["ip_rcv_finish_core.isra.16"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDij":{"file_name":[],"function_name":["ip_route_input_noref"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDcq":{"file_name":[],"function_name":["ip_route_input_rcu"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDJ4":{"file_name":[],"function_name":["ip_route_input_slow"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdks6":{"file_name":[],"function_name":["__fib_lookup"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbDwa":{"file_name":[],"function_name":["fib_rules_lookup"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdk6y":{"file_name":[],"function_name":["fib4_rule_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdZvh":{"file_name":[],"function_name":["fib_table_lookup"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAFci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAALw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAADhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAE3-":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAAJtO":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAACqM":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAG60":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAANis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAOx8":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAAFMc":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"3FRCbvQLPuJyn2B-2wELGwAAAAAAAJK8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[527]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAANQg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAABvY":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAOAI":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcn84":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcL7B":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaMAz":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"aUXpdArtZf510BJKvwiFDwAAAAAAAAok":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaGr1":{"file_name":[],"function_name":["__dev_forward_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbgzT":{"file_name":[],"function_name":["eth_type_trans"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAPhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAEeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAA58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABTm":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAACzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAEYa":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAPSm":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"_s_-RvH9Io2qUzM6f5JLGgAAAAAAAGfw":{"file_name":["client.py"],"function_name":["_create_client_class"],"function_offset":[12],"line_number":[160]},"8UGQaqEhTX9IIJEQCXnRsQAAAAAAAG5o":{"file_name":["client.py"],"function_name":["_create_methods"],"function_offset":[5],"line_number":[319]},"jn4X0YIYIsTeszwLEaje9gAAAAAAACEE":{"file_name":["client.py"],"function_name":["_create_api_method"],"function_offset":[25],"line_number":[356]},"TesF2I_BvQoOuJH9P_M2mAAAAAAAAGk-":{"file_name":["docstring.py"],"function_name":["__init__"],"function_offset":[9],"line_number":[36]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnNL":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADkzO":{"file_name":[],"function_name":["down_read_trylock"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAACrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAB9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"okehWevKsEA4q6dk779jgwAAAAAAAH1M":{"file_name":["session.py"],"function_name":["get_credentials"],"function_offset":[12],"line_number":[445]},"-IuadWGT89NVzIyF_EmodwAAAAAAAMKw":{"file_name":["credentials.py"],"function_name":["load_credentials"],"function_offset":[18],"line_number":[1953]},"XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08":{"file_name":["credentials.py"],"function_name":["load"],"function_offset":[18],"line_number":[1009]},"FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa":{"file_name":["utils.py"],"function_name":["retrieve_iam_role_credentials"],"function_offset":[30],"line_number":[517]},"pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a":{"file_name":["utils.py"],"function_name":["_get_iam_role"],"function_offset":[1],"line_number":[524]},"IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK":{"file_name":["utils.py"],"function_name":["_get_request"],"function_offset":[32],"line_number":[435]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"fB79lJck2X90l-j7VqPR-QAAAAAAAGc8":{"file_name":["connectionpool.py"],"function_name":["_make_request"],"function_offset":[116],"line_number":[494]},"gbMheDI1NZ3NY96J0seddgAAAAAAAEuq":{"file_name":["client.py"],"function_name":["getresponse"],"function_offset":[58],"line_number":[1389]},"GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w":{"file_name":["client.py"],"function_name":["__init__"],"function_offset":[28],"line_number":[276]},"_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI":{"file_name":["socket.py"],"function_name":["makefile"],"function_offset":[40],"line_number":[343]},"8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAO-w":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAEgm":{"file_name":["functools.py"],"function_name":["register"],"function_offset":[50],"line_number":[902]},"xUQuo4OgBaS_Le-fdAwt8AAAAAAAAEDw":{"file_name":["functools.py"],"function_name":["_is_union_type"],"function_offset":[2],"line_number":[843]},"zkPjzY2Et3KehkHOcSphkAAAAAAAADpY":{"file_name":["typing.py"],"function_name":[""],"function_offset":[2084],"line_number":[2085]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAABhk":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4":{"file_name":["application.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0":{"file_name":["application.py"],"function_name":["Application"],"function_offset":[91],"line_number":[206]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[18],"line_number":[155]},"7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW":{"file_name":["typing.py"],"function_name":["_type_convert"],"function_offset":[4],"line_number":[132]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAIHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAMKO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"SD7uzoegJjRT3jYNpuQ5wQAAAAAAAPBK":{"file_name":["configure.py"],"function_name":[""],"function_offset":[56],"line_number":[57]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAP2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"n74P5OxFm1hAo5ZWtgcKHQAAAAAAAHGe":{"file_name":["__init__.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[93]},"zXbqXCWr0lCbi_b24hNBRQAAAAAAAFJe":{"file_name":["pyimod02_importers.py"],"function_name":["find_spec"],"function_offset":[87],"line_number":[302]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgEg":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKf4s":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdQa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjj":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcK5W":{"file_name":[],"function_name":["tcp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcKWq":{"file_name":[],"function_name":["tcp_sendmsg_locked"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcbOh":{"file_name":[],"function_name":["__tcp_push_pending_frames"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcaTc":{"file_name":[],"function_name":["tcp_write_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcYo_":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcYWv":{"file_name":[],"function_name":["__tcp_select_window"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAIVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAANLe":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAGkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE":{"file_name":["application.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAABY":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAHYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAE58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAOEK":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAOys":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAJUK":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAM1M":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAADlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAL4m":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAGTS":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"-T5rZCijT5TDJjmoEi8KxgAAAAAAAJP8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[533]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAB1w":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAHKK":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAMT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAANF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAA1i":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"ynoRUNDFNh_CC1ViETMulAAAAAAAABSW":{"file_name":["subscribe.py"],"function_name":[""],"function_offset":[150],"line_number":[151]},"fxzD8soKl4etJ4L6nJl81gAAAAAAAHBe":{"file_name":["utils.py"],"function_name":[""],"function_offset":[584],"line_number":[585]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFoc":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAALAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAN-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAGsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAPZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAADdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAEfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAIY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAGBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAFNo":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAGcY":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4":{"file_name":["abc.py"],"function_name":[""],"function_offset":[267],"line_number":[268]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAAHV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"LEy-wm0GIvRoYVAga55HiwAAAAAAALxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAAR-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAALq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAEnG":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"BuJIbGFo3xNyZaTAXvW1AgAAAAAAAMqS":{"file_name":["datetime.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"L9BMhx_jo5vrPGr_NYlXCQAAAAAAAG9-":{"file_name":["datetime.py"],"function_name":["timezone"],"function_offset":[97],"line_number":[2394]},"pZhbjLL2hYCcec5rSvEEGwAAAAAAAMsk":{"file_name":["datetime.py"],"function_name":["__neg__"],"function_offset":[3],"line_number":[768]},"kkqG_q7yucIGLE7ky-QX9AAAAAAAAI3I":{"file_name":["datetime.py"],"function_name":["__new__"],"function_offset":[99],"line_number":[691]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAACzq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAN3q":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAEdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAACsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAALZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAACfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAGNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAEY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAADOE":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7Rc":{"file_name":["../sysdeps/posix/readdir.c"],"function_name":["__readdir"],"function_offset":[],"line_number":[65]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2pa":{"file_name":[],"function_name":["__x64_sys_getdents"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOkGr":{"file_name":[],"function_name":["xfs_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOjnO":{"file_name":[],"function_name":["xfs_dir2_sf_getdents.isra.9"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAN1i4":{"file_name":[],"function_name":["xfs_dir2_sf_get_parent_ino"],"function_offset":[],"line_number":[]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAP6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAAFg6":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAADDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAAGO6":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"s6flibJ32CsA8wnq-j6RkQAAAAAAAJEy":{"file_name":["regions.py"],"function_name":[""],"function_offset":[139],"line_number":[140]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOL8":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"3EA5Wz2lIIw6eu5uv4gkTwAAAAAAACDI":{"file_name":["_bootstrap.py"],"function_name":["__exit__"],"function_offset":[1],"line_number":[174]},"hjYcB64xHdoySaNOZ8xYqgAAAAAAADsY":{"file_name":["_bootstrap.py"],"function_name":["release"],"function_offset":[2],"line_number":[127]},"Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAAdC":{"file_name":["auth.py"],"function_name":[""],"function_offset":[603],"line_number":[604]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"y9R94bQUxts02WzRWfV7xgAAAAAAAHeC":{"file_name":["auth.py"],"function_name":[""],"function_offset":[316],"line_number":[317]},"uI6css-d8SGQRK6a_Ntl-AAAAAAAAIVu":{"file_name":["auth.py"],"function_name":[""],"function_offset":[336],"line_number":[337]},"SlnkBp0IIJFLHVOe4KbxwQAAAAAAANt6":{"file_name":["http.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"uPGvGNXBf1JXGeeDSsmGQAAAAAAAACX2":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[194],"line_number":[679]},"PmtIuZrIdDPbhY30JCQRwwAAAAAAADto":{"file_name":["enum.py"],"function_name":["__set_name__"],"function_offset":[96],"line_number":[333]},"yos2k6ZH69vZXiBQV3d7cQAAAAAAAKJ4":{"file_name":["enum.py"],"function_name":["__setattr__"],"function_offset":[11],"line_number":[839]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"un9fLDZOLvDMO52ltZtuegAAAAAAAOsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAHZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAACm2":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAACNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAAY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAADMg":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"wXOyVgf5_nNg6CUH5kFBbgAAAAAAABkK":{"file_name":["loaders.py"],"function_name":[""],"function_offset":[0],"line_number":[273]},"zEgDK4qMawUAQZjg5YHywwAAAAAAAGC0":{"file_name":["genericpath.py"],"function_name":["isdir"],"function_offset":[6],"line_number":[45]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKl7Y":{"file_name":[],"function_name":["__do_sys_newstat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKt69":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKtXX":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKsux":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"VY0EiAO0DxwLRTE4PfFhdwAAAAAAAN_6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"2AkHKX3hFovQqnWGTZG4BAAAAAAAALbW":{"file_name":["base.py"],"function_name":[""],"function_offset":[44],"line_number":[45]},"JEYMXKhPKBKP90oNIKO6WwAAAAAAABJe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"Fq3uvTWKo9OreZfu-LOYYQAAAAAAAGOG":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[2553],"line_number":[2554]},"f2CfX6aaJGZ4Su3cCY2vCQAAAAAAAOFk":{"file_name":["style.py"],"function_name":[""],"function_offset":[506],"line_number":[507]},"yxUFWTEZsQP-FeNV2RKnFQAAAAAAAJIa":{"file_name":["enum.py"],"function_name":["__prepare__"],"function_offset":[13],"line_number":[483]},"Q2lceMFM0t8w5Hdokg8e8AAAAAAAABv6":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[93],"line_number":[446]},"a5aMcPOeWx28QSVng73nBQAAAAAAAABK":{"file_name":["aws"],"function_name":[""],"function_offset":[13],"line_number":[27]},"inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[2],"line_number":[166]},"Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[3],"line_number":[185]},"cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[8],"line_number":[97]},"T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[23],"line_number":[48]},"lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[1],"line_number":[62]},"SMoSw8cr-PdrIATvljOPrQAAAAAAAABU":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[8],"line_number":[76]},"xaCec3W8F6xlvd_EISI7vwAAAAAAAAB0":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[15],"line_number":[28]},"QCNrAtEDVSYrGKsToy3LYAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"ocuGLNOciiOP6W8cfH2-qwAAAAAAAABg":{"file_name":["package.py"],"function_name":[""],"function_offset":[12],"line_number":[26]},"bjI4Jot-SXYwqfMr0sl7XgAAAAAAAAA8":{"file_name":["s3uploader.py"],"function_name":[""],"function_offset":[8],"line_number":[22]},"zjBJSIgrJ7WBnrV9WxdKEQAAAAAAAAB8":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[130],"line_number":[143]},"9-_Y7FNFlkawnHBUI4HVnAAAAAAAAAB8":{"file_name":["compat.py"],"function_name":[""],"function_offset":[81],"line_number":[94]},"suQJt7m9qyZP3i8d45HwBQAAAAAAAABk":{"file_name":["managers.py"],"function_name":[""],"function_offset":[18],"line_number":[29]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"5w2Emmm2pdiPFBnzFSNcKgAAAAAAAABM":{"file_name":["connection.py"],"function_name":[""],"function_offset":[11],"line_number":[21]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAAAi":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[7],"line_number":[666]},"1bzyoH1Mbbzc-oKA3fR-7QAAAAAAAAAY":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[7],"line_number":[565]},"BXKFYOU6E7YaW5MDpfBf8wAAAAAAAAAK":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[2],"line_number":[1173]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["__dlopen"],"function_offset":[],"line_number":[87]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlerror.c"],"function_name":["_dlerror_run"],"function_offset":[],"line_number":[163]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-error-skeleton.c"],"function_name":["__GI__dl_catch_error"],"function_offset":[],"line_number":[198]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["dlopen_doit"],"function_offset":[],"line_number":[66]},"3nN3bymnZ8E42aLEtgglmAAAAAAAASmo":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["_dl_open"],"function_offset":[],"line_number":[649]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAS7f":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[269]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAM3G":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-deps.c"],"function_name":["_dl_map_object_deps"],"function_offset":[],"line_number":[253]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAMtx":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-deps.c"],"function_name":["openaux"],"function_offset":[],"line_number":[64]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAINe":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-load.c"],"function_name":["_dl_map_object"],"function_offset":[],"line_number":[1943]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"93AmMdBRQTTNSFcMQ_YwdgAAAAAAAFCy":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"29RxCcCS3qayH8Wz47EBXQAAAAAAAIzc":{"file_name":["_adapters.py"],"function_name":["CompatibilityFiles"],"function_offset":[81],"line_number":[123]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAPGy":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"IWme5rHQfgYd-9YstXSeGAAAAAAAAE_C":{"file_name":["typing.py"],"function_name":["__init_subclass__"],"function_offset":[57],"line_number":[2092]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"y4VaggFtn5eGbiM4h45zCgAAAAAAAIhi":{"file_name":["formatter.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"aovhV1VhdNHhPwAmk_rOhgAAAAAAAB0G":{"file_name":["table.py"],"function_name":[""],"function_offset":[189],"line_number":[190]},"px3SfTg4DYOeiT_Yemty2wAAAAAAAAye":{"file_name":["."],"function_name":["utils"],"function_offset":[5],"line_number":[6]},"opI8K6Q9RBhmYCrRVwNTgAAAAAAAAPGW":{"file_name":["initialise.py"],"function_name":[""],"function_offset":[120],"line_number":[121]},"cVEUVwL4zVVcM9r_4PTCXAAAAAAAAJce":{"file_name":["ansitowin32.py"],"function_name":[""],"function_offset":[71],"line_number":[72]},"GGxNFCJdZtgXLG8zgUfn_QAAAAAAAD2y":{"file_name":["ansitowin32.py"],"function_name":["AnsiToWin32"],"function_offset":[182],"line_number":[254]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAKn8":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALGC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAJBk":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAPDo":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALts":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"ZVYMRqiL5oPAMqs8XcON8QAAAAAAAJl2":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[58],"line_number":[59]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"V6gUZHzBRISi-Z25klK5DQAAAAAAACri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"zWNEoAKVTnnzSns045VKhwAAAAAAAIsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACea":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"1y9WuJpjgBMcQb3shY5phQAAAAAAAOMe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[45],"line_number":[46]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"PmhxUKv5sePRxhCBONca8gAAAAAAAAD6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"xDXQtI2vA5YySwpx7QFiwAAAAAAAALuy":{"file_name":["popen_forkserver.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"fSQ747oLNh0c0zFQjsVRWgAAAAAAALk2":{"file_name":["forkserver.py"],"function_name":[""],"function_offset":[80],"line_number":[81]},"yp8MidCGMe4czbl-NigsYQAAAAAAAFOm":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAADGK":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"mfGJjedIJMvFXgX3QuTMfQAAAAAAAPDW":{"file_name":["core.py"],"function_name":[""],"function_offset":[275],"line_number":[276]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAALSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"9NWoah56eYULAP_zGE9PuwAAAAAAAPHC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[101],"line_number":[102]},"IKrIDHd5n47PpDQsRXxvvgAAAAAAAGmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[81],"line_number":[82]},"oG7568kMJujZxPJfj7VMjAAAAAAAAAjO":{"file_name":["frontend.py"],"function_name":[""],"function_offset":[390],"line_number":[391]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAAKju":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAAEW2":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAADZ-":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAO3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAACSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAABKa":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAIVS":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAGUy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAJn8":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAKGo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAACfk":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAACxC":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAACMC":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAADMc":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAAH1O":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAACWm":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAABZu":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAGVC":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAKLy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAANSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAANJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAAKVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAANJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAANai":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAM1i":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAAOom":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"ik6PIX946fW_erE7uBJlVQAAAAAAADLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAANFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"zWCVT22bUHN0NWIQIBSuKgAAAAAAAOm6":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[32],"line_number":[33]},"zj3hc8VBXxWxcbGVwJZYLAAAAAAAAOye":{"file_name":["basic.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"EHb2BWbkIivImSAfaUtw-AAAAAAAAPyQ":{"file_name":["named_commands.py"],"function_name":[""],"function_offset":[586],"line_number":[587]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"-7Nhzq0bVRejx7IVqpbbZQAAAAAAAKW-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[96],"line_number":[97]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAMui":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2":{"file_name":["_parser.py"],"function_name":["__len__"],"function_offset":[1],"line_number":[159]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAIla":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAPNq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAACAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAANmS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAIKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAC66":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAOnq":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"-BjW54fwMksXBor9R-YN9wAAAAAAAHD-":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[575],"line_number":[576]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe":{"file_name":[],"function_name":["page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItAx":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAglhf":{"file_name":[],"function_name":["_raw_spin_lock"],"function_offset":[],"line_number":[]},"ik6PIX946fW_erE7uBJlVQAAAAAAAPLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"OlTvyWQFXjOweJcs3kiGygAAAAAAACIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAABtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAAGJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAGWM":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAKZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"qkYSh95E1urNTie_gKbr7wAAAAAAAABY":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8":{"file_name":["connection.py"],"function_name":[""],"function_offset":[14],"line_number":[15]},"xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAFi":{"file_name":["url.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG":{"file_name":["re.py"],"function_name":["compile"],"function_offset":[2],"line_number":[252]},"SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs":{"file_name":["re.py"],"function_name":["_compile"],"function_offset":[15],"line_number":[304]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[5],"line_number":[764]},"cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["parse"],"function_offset":[11],"line_number":[948]},"aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["_parse_sub"],"function_offset":[8],"line_number":[443]},"MebnOxK5WOhP29sl19JefwAAAAAAAAua":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[341],"line_number":[834]},"MebnOxK5WOhP29sl19JefwAAAAAAAAKs":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[98],"line_number":[591]},"LEy-wm0GIvRoYVAga55HiwAAAAAAABxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAONq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAACOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAADcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAOD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAPAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAACYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAFee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAMW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAABj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAMmS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPX-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[780],"line_number":[781]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALn4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAANe4":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAAHTA":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAESm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"3nN3bymnZ8E42aLEtgglmAAAAAAAATA-":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[424]},"3nN3bymnZ8E42aLEtgglmAAAAAAAALbA":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-reloc.c"],"function_name":["_dl_relocate_object"],"function_offset":[],"line_number":[160]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["_dl_lookup_symbol_x"],"function_offset":[],"line_number":[833]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJel":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x","do_lookup_unique","enter_unique_sym"],"function_offset":[],"line_number":[544,322,197]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"qordvIiilnF7CmkWCAd7eAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[3],"line_number":[4]},"cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"GLV-c6bk0E-nhaaCp6u20wAAAAAAAAAo":{"file_name":["base.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"c_1Yb4rio2EAH6C9SFwQogAAAAAAAABE":{"file_name":["cursor_shapes.py"],"function_name":[""],"function_offset":[5],"line_number":[6]},"O4ILxZswquMzuET9RRf5QAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[16],"line_number":[302]},"GLV-c6bk0E-nhaaCp6u20wAAAAAAAABA":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"rJZ4aC9w8bMvzrC0ApyIjgAAAAAAAAAo":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"TC9v9fO0nTP4oypYCgB_1QAAAAAAAAAw":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"piWSMQrh4r040D0BPNaJvwAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAABncH":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAIsvf":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAIsF6":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJj7r":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIxB":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAADS":{"file_name":["errors.py"],"function_name":[""],"function_offset":[51],"line_number":[56]}},"executables":{"FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","B8JRxL079xbhqQBqGvksAg":"kubelet","edNJ10OjHiWc5nzuTQdvig":"linux-vdso.so.1","piWSMQrh4r040D0BPNaJvw":"vmlinux","QvG8QEGAld88D676NL_Y2Q":"filebeat","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","QaIvzvU8UoclQMd_OMt-Pg":"elastic-operator","w5zBqPf1_9mIVEf-Rn7EdA":"systemd","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","OTWX4UsOVMrSIF5cD4zUzg":"libmount.so.1.1.0","v6HIzNa4K6G4nRP9032RIA":"dockerd","hc6JHMKlLXjOZcU9MGxvfg":"kube-proxy","A2oiHVwisByxRn5RDT4LjA":"vmlinux","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","9LzzIocepYcOjnUsLlgOjg":"vmlinux","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","YsKzCJ9e4eZnuT00vj7Pcw":"python2.7","N4ILulabOfF5MnyRJbvDXw":"libpython2.7.so.1.0","SbPwzb_Kog2bWn8uc7xhDQ":"aws","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","aUXpdArtZf510BJKvwiFDw":"veth","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","pRLjmMO0U8sO4DFopfFU5g":"metrics-server","G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","-V-5ede56KMAXhjFbz84Sw":"csi-provisioner","dGWvVtQJJ5wuqNyQVpi8lA":"zlib.cpython-311-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so","PVZV2uq5ZRt-FFaczL10BA":"libdl-2.26.so","3nN3bymnZ8E42aLEtgglmA":"ld-2.26.so","EX9l-cE0x8X9W8uz4iKUfw":"zlib.cpython-39-x86_64-linux-gnu.so"},"total_frames":150718,"sampling_rate":0.008000000000000002} diff --git a/packages/kbn-profiling-utils/common/callee.test.ts b/packages/kbn-profiling-utils/common/callee.test.ts deleted file mode 100644 index 431f914bd6a1..000000000000 --- a/packages/kbn-profiling-utils/common/callee.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { sum } from 'lodash'; - -import { createCalleeTree } from './callee'; -import { decodeStackTraceResponse } from './stack_traces'; -import { stackTraceFixtures } from './__fixtures__/stacktraces'; - -describe('Callee operations', () => { - stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { - const { events, stackTraces, stackFrames, executables, totalFrames, samplingRate } = - decodeStackTraceResponse(response); - const tree = createCalleeTree( - events, - stackTraces, - stackFrames, - executables, - totalFrames, - samplingRate - ); - - describe(`stacktraces from ${seconds} seconds and upsampled by ${upsampledBy}`, () => { - test('inclusive count of root to be less than or equal total sampled stacktraces', () => { - const totalAdjustedSamples = Math.ceil(sum([...events.values()]) / samplingRate); - expect(tree.CountInclusive[0]).toBeLessThanOrEqual(totalAdjustedSamples); - }); - - test('inclusive count for each node should be greater than or equal to its children', () => { - const allGreaterThanOrEqual = tree.Edges.map( - (children, i) => - tree.CountInclusive[i] >= sum([...children.values()].map((j) => tree.CountInclusive[j])) - ); - expect(allGreaterThanOrEqual).toBeTruthy(); - }); - - test('exclusive count of root is zero', () => { - expect(tree.CountExclusive[0]).toEqual(0); - }); - - test('tree de-duplicates sibling nodes', () => { - expect(tree.Size).toBeLessThan(totalFrames); - }); - }); - }); -}); diff --git a/packages/kbn-profiling-utils/common/callee.ts b/packages/kbn-profiling-utils/common/callee.ts deleted file mode 100644 index 63152d91de3f..000000000000 --- a/packages/kbn-profiling-utils/common/callee.ts +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { sum } from 'lodash'; -import { createFrameGroupID, FrameGroupID } from './frame_group'; -import { - emptyExecutable, - emptyStackFrame, - emptyStackTrace, - Executable, - FileID, - StackFrame, - StackFrameID, - StackTrace, - StackTraceID, -} from './profiling'; - -type NodeID = number; - -/** - * Callee tree - */ -export interface CalleeTree { - /** size */ - Size: number; - /** edges */ - Edges: Array>; - /** file ids */ - FileID: string[]; - /** frame types */ - FrameType: number[]; - /** inlines */ - Inline: boolean[]; - /** executable file names */ - ExeFilename: string[]; - /** address or lines */ - AddressOrLine: number[]; - /** function names */ - FunctionName: string[]; - /** function offsets */ - FunctionOffset: number[]; - /** source file names */ - SourceFilename: string[]; - /** source lines */ - SourceLine: number[]; - /** total cpu */ - CountInclusive: number[]; - /** self cpu */ - CountExclusive: number[]; - TotalSamples: number; - TotalCPU: number; - SelfCPU: number; -} - -/** - * Create a callee tree - * @param events Map - * @param stackTraces Map - * @param stackFrames Map - * @param executables Map - * @param totalFrames number - * @param samplingRate number - * @returns - */ -export function createCalleeTree( - events: Map, - stackTraces: Map, - stackFrames: Map, - executables: Map, - totalFrames: number, - samplingRate: number -): CalleeTree { - const tree: CalleeTree = { - Size: 1, - Edges: new Array(totalFrames), - FileID: new Array(totalFrames), - FrameType: new Array(totalFrames), - Inline: new Array(totalFrames), - ExeFilename: new Array(totalFrames), - AddressOrLine: new Array(totalFrames), - FunctionName: new Array(totalFrames), - FunctionOffset: new Array(totalFrames), - SourceFilename: new Array(totalFrames), - SourceLine: new Array(totalFrames), - CountInclusive: new Array(totalFrames), - CountExclusive: new Array(totalFrames), - TotalSamples: 0, - SelfCPU: 0, - TotalCPU: 0, - }; - - // The inverse of the sampling rate is the number with which to multiply the number of - // samples to get an estimate of the actual number of samples the backend received. - const scalingFactor = 1.0 / samplingRate; - let totalSamples = 0; - tree.Edges[0] = new Map(); - - tree.FileID[0] = ''; - tree.FrameType[0] = 0; - tree.Inline[0] = false; - tree.ExeFilename[0] = ''; - tree.AddressOrLine[0] = 0; - tree.FunctionName[0] = ''; - tree.FunctionOffset[0] = 0; - tree.SourceFilename[0] = ''; - tree.SourceLine[0] = 0; - - tree.CountInclusive[0] = 0; - tree.CountExclusive[0] = 0; - - const sortedStackTraceIDs = new Array(); - for (const trace of stackTraces.keys()) { - sortedStackTraceIDs.push(trace); - } - sortedStackTraceIDs.sort((t1, t2) => { - return t1.localeCompare(t2); - }); - - // Walk through all traces. Increment the count of the root by the count of - // that trace. Walk "down" the trace (through the callees) and add the count - // of the trace to each callee. - - for (const stackTraceID of sortedStackTraceIDs) { - // The slice of frames is ordered so that the leaf function is at the - // highest index. - - // It is possible that we do not have a stacktrace for an event, - // e.g. when stopping the host agent or on network errors. - const stackTrace = stackTraces.get(stackTraceID) ?? emptyStackTrace; - const lenStackTrace = stackTrace.FrameIDs.length; - const samples = Math.floor((events.get(stackTraceID) ?? 0) * scalingFactor); - totalSamples += samples; - let currentNode = 0; - - // Increment the count by the number of samples observed, multiplied with the inverse of the - // samplingrate (this essentially means scaling up the total samples). It would incur - tree.CountInclusive[currentNode] += samples; - tree.CountExclusive[currentNode] = 0; - - for (let i = 0; i < lenStackTrace; i++) { - const frameID = stackTrace.FrameIDs[i]; - const fileID = stackTrace.FileIDs[i]; - const addressOrLine = stackTrace.AddressOrLines[i]; - const frame = stackFrames.get(frameID) ?? emptyStackFrame; - const executable = executables.get(fileID) ?? emptyExecutable; - - const frameGroupID = createFrameGroupID( - fileID, - addressOrLine, - executable.FileName, - frame.FileName, - frame.FunctionName - ); - - let node = tree.Edges[currentNode].get(frameGroupID); - - if (node === undefined) { - node = tree.Size; - - tree.FileID[node] = fileID; - tree.FrameType[node] = stackTrace.Types[i]; - tree.ExeFilename[node] = executable.FileName; - tree.AddressOrLine[node] = addressOrLine; - tree.FunctionName[node] = frame.FunctionName; - tree.FunctionOffset[node] = frame.FunctionOffset; - tree.SourceLine[node] = frame.LineNumber; - tree.SourceFilename[node] = frame.FileName; - tree.Inline[node] = frame.Inline; - tree.CountInclusive[node] = samples; - tree.CountExclusive[node] = 0; - - tree.Edges[currentNode].set(frameGroupID, node); - tree.Edges[node] = new Map(); - - tree.Size++; - } else { - tree.CountInclusive[node] += samples; - } - - if (i === lenStackTrace - 1) { - // Leaf frame: sum up counts for exclusive CPU. - tree.CountExclusive[node] += samples; - } - currentNode = node; - } - } - const sumSelfCPU = sum(tree.CountExclusive); - const sumTotalCPU = sum(tree.CountInclusive); - - return { - ...tree, - TotalSamples: totalSamples, - SelfCPU: sumSelfCPU, - TotalCPU: sumTotalCPU, - }; -} diff --git a/packages/kbn-profiling-utils/common/flamegraph.test.ts b/packages/kbn-profiling-utils/common/flamegraph.test.ts index cc6b3cca6992..676c253b9e6b 100644 --- a/packages/kbn-profiling-utils/common/flamegraph.test.ts +++ b/packages/kbn-profiling-utils/common/flamegraph.test.ts @@ -6,49 +6,32 @@ * Side Public License, v 1. */ -import { createCalleeTree } from './callee'; -import { createBaseFlameGraph, createFlameGraph } from './flamegraph'; -import { decodeStackTraceResponse } from './stack_traces'; -import { stackTraceFixtures } from './__fixtures__/stacktraces'; - -describe('Flamegraph operations', () => { - stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { - const { events, stackTraces, stackFrames, executables, totalFrames, samplingRate } = - decodeStackTraceResponse(response); - const tree = createCalleeTree( - events, - stackTraces, - stackFrames, - executables, - totalFrames, - samplingRate - ); - const baseFlamegraph = createBaseFlameGraph(tree, samplingRate, seconds); - const flamegraph = createFlameGraph(baseFlamegraph); - - describe(`stacktraces from ${seconds} seconds and upsampled by ${upsampledBy}`, () => { - test('base flamegraph has non-zero total seconds', () => { - expect(baseFlamegraph.TotalSeconds).toEqual(seconds); - }); - - test('base flamegraph has one more node than the number of edges', () => { - const numEdges = baseFlamegraph.Edges.flatMap((edge) => edge).length; - - expect(numEdges).toEqual(baseFlamegraph.Size - 1); - }); - - test('all flamegraph IDs are the same non-zero length', () => { - // 16 is the length of a 64-bit FNV-1a hash encoded to a hex string - const allSameLengthIDs = flamegraph.ID.every((id) => id.length === 16); - - expect(allSameLengthIDs).toBeTruthy(); - }); - - test('all flamegraph labels are non-empty', () => { - const allNonEmptyLabels = flamegraph.Label.every((id) => id.length > 0); - - expect(allNonEmptyLabels).toBeTruthy(); - }); - }); +import { createFlameGraph } from './flamegraph'; +import { baseFlamegraph } from './__fixtures__/base_flamegraph'; + +describe('Flamegraph', () => { + const flamegraph = createFlameGraph(baseFlamegraph); + + it('base flamegraph has non-zero total seconds', () => { + expect(baseFlamegraph.TotalSeconds).toEqual(4.980000019073486); + }); + + it('base flamegraph has one more node than the number of edges', () => { + const numEdges = baseFlamegraph.Edges.flatMap((edge) => edge).length; + + expect(numEdges).toEqual(baseFlamegraph.Size - 1); + }); + + it('all flamegraph IDs are the same non-zero length', () => { + // 16 is the length of a 64-bit FNV-1a hash encoded to a hex string + const allSameLengthIDs = flamegraph.ID.every((id) => id.length === 16); + + expect(allSameLengthIDs).toBeTruthy(); + }); + + it('all flamegraph labels are non-empty', () => { + const allNonEmptyLabels = flamegraph.Label.every((id) => id.length > 0); + + expect(allNonEmptyLabels).toBeTruthy(); }); }); diff --git a/packages/kbn-profiling-utils/common/flamegraph.ts b/packages/kbn-profiling-utils/common/flamegraph.ts index 0961e02bfd1a..407a83b4d350 100644 --- a/packages/kbn-profiling-utils/common/flamegraph.ts +++ b/packages/kbn-profiling-utils/common/flamegraph.ts @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import { CalleeTree } from './callee'; import { createFrameGroupID } from './frame_group'; import { fnv1a64 } from './hash'; import { createStackFrameMetadata, getCalleeLabel } from './profiling'; +import { convertTonsToKgs } from './utils'; /** * Base Flamegraph @@ -48,63 +48,37 @@ export interface BaseFlameGraph { TotalSamples: number; TotalCPU: number; SelfCPU: number; -} - -/** - * createBaseFlameGraph encapsulates the tree representation into a serialized form. - * @param tree CalleeTree - * @param samplingRate number - * @param totalSeconds number - * @returns BaseFlameGraph - */ -export function createBaseFlameGraph( - tree: CalleeTree, - samplingRate: number, - totalSeconds: number -): BaseFlameGraph { - const graph: BaseFlameGraph = { - Size: tree.Size, - SamplingRate: samplingRate, - Edges: new Array(tree.Size), - - FileID: tree.FileID.slice(0, tree.Size), - FrameType: tree.FrameType.slice(0, tree.Size), - Inline: tree.Inline.slice(0, tree.Size), - ExeFilename: tree.ExeFilename.slice(0, tree.Size), - AddressOrLine: tree.AddressOrLine.slice(0, tree.Size), - FunctionName: tree.FunctionName.slice(0, tree.Size), - FunctionOffset: tree.FunctionOffset.slice(0, tree.Size), - SourceFilename: tree.SourceFilename.slice(0, tree.Size), - SourceLine: tree.SourceLine.slice(0, tree.Size), - - CountInclusive: tree.CountInclusive.slice(0, tree.Size), - CountExclusive: tree.CountExclusive.slice(0, tree.Size), - - TotalSeconds: totalSeconds, - TotalSamples: tree.TotalSamples, - SelfCPU: tree.SelfCPU, - TotalCPU: tree.TotalCPU, - }; - - for (let i = 0; i < tree.Size; i++) { - let j = 0; - const nodes = new Array(tree.Edges[i].size); - for (const [, n] of tree.Edges[i]) { - nodes[j] = n; - j++; - } - graph.Edges[i] = nodes; - } - - return graph; + AnnualCO2TonsExclusive: number[]; + AnnualCO2TonsInclusive: number[]; + AnnualCostsUSDInclusive: number[]; + AnnualCostsUSDExclusive: number[]; + SelfAnnualCO2Tons: number; + TotalAnnualCO2Tons: number; + SelfAnnualCostsUSD: number; + TotalAnnualCostsUSD: number; } /** Elasticsearch flamegraph */ -export interface ElasticFlameGraph extends BaseFlameGraph { +export interface ElasticFlameGraph + extends Omit< + BaseFlameGraph, + | 'AnnualCO2TonsExclusive' + | 'AnnualCO2TonsInclusive' + | 'SelfAnnualCO2Tons' + | 'TotalAnnualCO2Tons' + | 'AnnualCostsUSDInclusive' + | 'AnnualCostsUSDExclusive' + > { /** ID */ ID: string[]; /** Label */ Label: string[]; + SelfAnnualCO2KgsItems: number[]; + TotalAnnualCO2KgsItems: number[]; + SelfAnnualCostsUSDItems: number[]; + TotalAnnualCostsUSDItems: number[]; + SelfAnnualCO2Kgs: number; + TotalAnnualCO2Kgs: number; } /** @@ -141,6 +115,14 @@ export function createFlameGraph(base: BaseFlameGraph): ElasticFlameGraph { TotalSamples: base.TotalSamples, SelfCPU: base.SelfCPU, TotalCPU: base.TotalCPU, + SelfAnnualCO2KgsItems: base.AnnualCO2TonsExclusive.map(convertTonsToKgs), + TotalAnnualCO2KgsItems: base.AnnualCO2TonsInclusive.map(convertTonsToKgs), + SelfAnnualCostsUSDItems: base.AnnualCostsUSDExclusive, + TotalAnnualCostsUSDItems: base.AnnualCostsUSDInclusive, + SelfAnnualCO2Kgs: convertTonsToKgs(base.SelfAnnualCO2Tons), + TotalAnnualCO2Kgs: convertTonsToKgs(base.TotalAnnualCO2Tons), + SelfAnnualCostsUSD: base.SelfAnnualCostsUSD, + TotalAnnualCostsUSD: base.TotalAnnualCostsUSD, }; const rootFrameGroupID = createFrameGroupID( diff --git a/packages/kbn-profiling-utils/common/functions.test.ts b/packages/kbn-profiling-utils/common/functions.test.ts index d5facff78d13..d7d59d26abf7 100644 --- a/packages/kbn-profiling-utils/common/functions.test.ts +++ b/packages/kbn-profiling-utils/common/functions.test.ts @@ -9,49 +9,44 @@ import { sum } from 'lodash'; import { createTopNFunctions } from './functions'; import { decodeStackTraceResponse } from '..'; -import { stackTraceFixtures } from './__fixtures__/stacktraces'; +import { stacktraces } from './__fixtures__/stacktraces'; describe('TopN function operations', () => { - stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { - const { events, stackTraces, stackFrames, executables, samplingRate } = - decodeStackTraceResponse(response); - - describe(`stacktraces upsampled by ${upsampledBy}`, () => { - const maxTopN = 5; - const topNFunctions = createTopNFunctions({ - events, - stackTraces, - stackFrames, - executables, - startIndex: 0, - endIndex: maxTopN, - samplingRate, - }); - const exclusiveCounts = topNFunctions.TopN.map((value) => value.CountExclusive); + const { events, stackTraces, stackFrames, executables, samplingRate } = + decodeStackTraceResponse(stacktraces); + const maxTopN = 5; + const topNFunctions = createTopNFunctions({ + events, + stackTraces, + stackFrames, + executables, + startIndex: 0, + endIndex: maxTopN, + samplingRate, + }); + const exclusiveCounts = topNFunctions.TopN.map((value) => value.CountExclusive); - test('samples are less than or equal to original upsampled samples', () => { - const totalUpsampledSamples = Math.ceil(sum([...events.values()]) / samplingRate); - expect(topNFunctions.TotalCount).toBeLessThanOrEqual(totalUpsampledSamples); - }); + it('samples are less than or equal to original upsampled samples', () => { + const totalUpsampledSamples = Math.ceil(sum([...events.values()]) / samplingRate); + expect(topNFunctions.TotalCount).toBeLessThanOrEqual(totalUpsampledSamples); + }); - test('number of functions is equal to maximum', () => { - expect(topNFunctions.TopN.length).toEqual(maxTopN); - }); + it('number of functions is equal to maximum', () => { + expect(topNFunctions.TopN.length).toEqual(maxTopN); + }); - test('all exclusive counts are numeric', () => { - expect(typeof exclusiveCounts[0]).toBe('number'); - expect(typeof exclusiveCounts[1]).toBe('number'); - expect(typeof exclusiveCounts[2]).toBe('number'); - expect(typeof exclusiveCounts[3]).toBe('number'); - expect(typeof exclusiveCounts[4]).toBe('number'); - }); + it('all exclusive counts are numeric', () => { + expect(typeof exclusiveCounts[0]).toBe('number'); + expect(typeof exclusiveCounts[1]).toBe('number'); + expect(typeof exclusiveCounts[2]).toBe('number'); + expect(typeof exclusiveCounts[3]).toBe('number'); + expect(typeof exclusiveCounts[4]).toBe('number'); + }); - test('exclusive counts are sorted from highest to lowest', () => { - expect(exclusiveCounts[0]).toBeGreaterThanOrEqual(exclusiveCounts[1]); - expect(exclusiveCounts[1]).toBeGreaterThanOrEqual(exclusiveCounts[2]); - expect(exclusiveCounts[2]).toBeGreaterThanOrEqual(exclusiveCounts[3]); - expect(exclusiveCounts[3]).toBeGreaterThanOrEqual(exclusiveCounts[4]); - }); - }); + it('exclusive counts are sorted from highest to lowest', () => { + expect(exclusiveCounts[0]).toBeGreaterThanOrEqual(exclusiveCounts[1]); + expect(exclusiveCounts[1]).toBeGreaterThanOrEqual(exclusiveCounts[2]); + expect(exclusiveCounts[2]).toBeGreaterThanOrEqual(exclusiveCounts[3]); + expect(exclusiveCounts[3]).toBeGreaterThanOrEqual(exclusiveCounts[4]); }); }); diff --git a/packages/kbn-profiling-utils/common/functions.ts b/packages/kbn-profiling-utils/common/functions.ts index 47bf0a310007..5d1a225693ca 100644 --- a/packages/kbn-profiling-utils/common/functions.ts +++ b/packages/kbn-profiling-utils/common/functions.ts @@ -30,11 +30,21 @@ interface TopNFunctionAndFrameGroup { FrameGroupID: FrameGroupID; CountExclusive: number; CountInclusive: number; + selfAnnualCO2kgs: number; + selfAnnualCostUSD: number; + totalAnnualCO2kgs: number; + totalAnnualCostUSD: number; } type TopNFunction = Pick< TopNFunctionAndFrameGroup, - 'Frame' | 'CountExclusive' | 'CountInclusive' + | 'Frame' + | 'CountExclusive' + | 'CountInclusive' + | 'selfAnnualCO2kgs' + | 'selfAnnualCostUSD' + | 'totalAnnualCO2kgs' + | 'totalAnnualCostUSD' > & { Id: string; Rank: number; @@ -46,6 +56,8 @@ export interface TopNFunctions { SamplingRate: number; selfCPU: number; totalCPU: number; + totalAnnualCO2Kgs: number; + totalAnnualCostUSD: number; } export function createTopNFunctions({ @@ -84,6 +96,9 @@ export function createTopNFunctions({ // It is possible that we do not have a stacktrace for an event, // e.g. when stopping the host agent or on network errors. const stackTrace = stackTraces.get(stackTraceID) ?? emptyStackTrace; + const selfAnnualCO2kgs = stackTrace.selfAnnualCO2Kgs; + const selfAnnualCostUSD = stackTrace.selfAnnualCostUSD; + const lenStackTrace = stackTrace.FrameIDs.length; for (let i = 0; i < lenStackTrace; i++) { @@ -122,6 +137,10 @@ export function createTopNFunctions({ FrameGroupID: frameGroupID, CountExclusive: 0, CountInclusive: 0, + selfAnnualCO2kgs: 0, + totalAnnualCO2kgs: 0, + selfAnnualCostUSD: 0, + totalAnnualCostUSD: 0, }; topNFunctions.set(frameGroupID, topNFunction); @@ -130,11 +149,15 @@ export function createTopNFunctions({ if (!uniqueFrameGroupsPerEvent.has(frameGroupID)) { uniqueFrameGroupsPerEvent.add(frameGroupID); topNFunction.CountInclusive += scaledCount; + topNFunction.totalAnnualCO2kgs += selfAnnualCO2kgs; + topNFunction.totalAnnualCostUSD += selfAnnualCostUSD; } if (i === lenStackTrace - 1) { // Leaf frame: sum up counts for exclusive CPU. topNFunction.CountExclusive += scaledCount; + topNFunction.selfAnnualCO2kgs += selfAnnualCO2kgs; + topNFunction.selfAnnualCostUSD += selfAnnualCostUSD; } } } @@ -161,21 +184,29 @@ export function createTopNFunctions({ endIndex = topN.length; } - const framesAndCountsAndIds = topN.slice(startIndex, endIndex).map((frameAndCount, i) => { - const countExclusive = frameAndCount.CountExclusive; - const countInclusive = frameAndCount.CountInclusive; + const framesAndCountsAndIds = topN + .slice(startIndex, endIndex) + .map((frameAndCount, i): TopNFunction => { + const countExclusive = frameAndCount.CountExclusive; + const countInclusive = frameAndCount.CountInclusive; - return { - Rank: i + 1, - Frame: frameAndCount.Frame, - CountExclusive: countExclusive, - CountInclusive: countInclusive, - Id: frameAndCount.FrameGroupID, - }; - }); + return { + Rank: i + 1, + Frame: frameAndCount.Frame, + CountExclusive: countExclusive, + CountInclusive: countInclusive, + Id: frameAndCount.FrameGroupID, + selfAnnualCO2kgs: frameAndCount.selfAnnualCO2kgs, + selfAnnualCostUSD: frameAndCount.selfAnnualCostUSD, + totalAnnualCO2kgs: frameAndCount.totalAnnualCO2kgs, + totalAnnualCostUSD: frameAndCount.totalAnnualCostUSD, + }; + }); const sumSelfCPU = sumBy(framesAndCountsAndIds, 'CountExclusive'); const sumTotalCPU = sumBy(framesAndCountsAndIds, 'CountInclusive'); + const totalAnnualCO2Kgs = sumBy(framesAndCountsAndIds, 'totalAnnualCO2kgs'); + const totalAnnualCostUSD = sumBy(framesAndCountsAndIds, 'totalAnnualCostUSD'); return { TotalCount: totalCount, @@ -183,6 +214,8 @@ export function createTopNFunctions({ SamplingRate: samplingRate, selfCPU: sumSelfCPU, totalCPU: sumTotalCPU, + totalAnnualCO2Kgs, + totalAnnualCostUSD, }; } @@ -207,3 +240,21 @@ export const topNFunctionSortFieldRt = t.union([ t.literal(TopNFunctionSortField.AnnualizedCo2), t.literal(TopNFunctionSortField.AnnualizedDollarCost), ]); + +export enum TopNComparisonFunctionSortField { + ComparisonRank = 'comparison_rank', + ComparisonFrame = 'comparison_frame', + ComparisonSamples = 'comparison_samples', + ComparisonSelfCPU = 'comparison_selfCPU', + ComparisonTotalCPU = 'comparison_totalCPU', + ComparisonDiff = 'comparison_diff', +} + +export const topNComparisonFunctionSortFieldRt = t.union([ + t.literal(TopNComparisonFunctionSortField.ComparisonRank), + t.literal(TopNComparisonFunctionSortField.ComparisonFrame), + t.literal(TopNComparisonFunctionSortField.ComparisonSamples), + t.literal(TopNComparisonFunctionSortField.ComparisonSelfCPU), + t.literal(TopNComparisonFunctionSortField.ComparisonTotalCPU), + t.literal(TopNComparisonFunctionSortField.ComparisonDiff), +]); diff --git a/packages/kbn-profiling-utils/common/profiling.ts b/packages/kbn-profiling-utils/common/profiling.ts index a8786224b223..c7e8e6a89b76 100644 --- a/packages/kbn-profiling-utils/common/profiling.ts +++ b/packages/kbn-profiling-utils/common/profiling.ts @@ -74,6 +74,9 @@ export interface StackTrace { AddressOrLines: number[]; /** types */ Types: number[]; + selfAnnualCO2Kgs: number; + selfAnnualCostUSD: number; + Count: number; } /** * Empty stack trace @@ -87,6 +90,9 @@ export const emptyStackTrace: StackTrace = { AddressOrLines: [], /** Types */ Types: [], + selfAnnualCO2Kgs: 0, + selfAnnualCostUSD: 0, + Count: 0, }; /** Stack frame */ diff --git a/packages/kbn-profiling-utils/common/stack_traces.test.ts b/packages/kbn-profiling-utils/common/stack_traces.test.ts index 832ebe7bb66b..9f7076f133d0 100644 --- a/packages/kbn-profiling-utils/common/stack_traces.test.ts +++ b/packages/kbn-profiling-utils/common/stack_traces.test.ts @@ -58,6 +58,9 @@ describe('Stack trace response operations', () => { frame_ids: ['abc123', 'def456'], address_or_lines: [123, 456], type_ids: [0, 1], + count: 3, + annual_co2_tons: 1, + annual_costs_usd: 1, }, }, stack_frames: { @@ -92,6 +95,9 @@ describe('Stack trace response operations', () => { FrameIDs: ['abc123', makeFrameID('def456', 0), makeFrameID('def456', 1)], AddressOrLines: [123, 456, 456], Types: [0, 1, 1], + Count: 3, + selfAnnualCO2Kgs: 1, + selfAnnualCostUSD: 1, }, ], ]), @@ -165,6 +171,9 @@ describe('Stack trace response operations', () => { frame_ids: ['abc123'], address_or_lines: [123], type_ids: [0], + count: 3, + annual_co2_tons: 1, + annual_costs_usd: 1, }, }, stack_frames: { @@ -191,6 +200,9 @@ describe('Stack trace response operations', () => { FrameIDs: ['abc123'], AddressOrLines: [123], Types: [0], + Count: 3, + selfAnnualCO2Kgs: 1, + selfAnnualCostUSD: 1, }, ], ]), diff --git a/packages/kbn-profiling-utils/common/stack_traces.ts b/packages/kbn-profiling-utils/common/stack_traces.ts index f7893c66c5e2..be8ffe8a32f8 100644 --- a/packages/kbn-profiling-utils/common/stack_traces.ts +++ b/packages/kbn-profiling-utils/common/stack_traces.ts @@ -15,6 +15,7 @@ import { StackTrace, StackTraceID, } from './profiling'; +import { convertTonsToKgs } from './utils'; /** Profiling status response */ export interface ProfilingStatusResponse { @@ -42,6 +43,9 @@ export interface ProfilingStackTrace { ['frame_ids']: string[]; ['address_or_lines']: number[]; ['type_ids']: number[]; + ['annual_co2_tons']: number; + ['annual_costs_usd']: number; + count: number; } interface ProfilingStackTraces { @@ -140,7 +144,10 @@ const createInlineTrace = ( FileIDs: fileIDs, AddressOrLines: addressOrLines, Types: typeIDs, - } as StackTrace; + selfAnnualCO2Kgs: convertTonsToKgs(trace.annual_co2_tons), + selfAnnualCostUSD: trace.annual_costs_usd, + Count: trace.count, + }; }; /** diff --git a/packages/kbn-profiling-utils/common/utils.ts b/packages/kbn-profiling-utils/common/utils.ts new file mode 100644 index 000000000000..a5407df005a4 --- /dev/null +++ b/packages/kbn-profiling-utils/common/utils.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export const convertTonsToKgs = (value: number) => value * 1000; diff --git a/packages/kbn-profiling-utils/index.ts b/packages/kbn-profiling-utils/index.ts index 38ab8d11be23..502253b1aef1 100644 --- a/packages/kbn-profiling-utils/index.ts +++ b/packages/kbn-profiling-utils/index.ts @@ -7,8 +7,7 @@ */ export { decodeStackTraceResponse } from './common/stack_traces'; -export { createBaseFlameGraph, createFlameGraph } from './common/flamegraph'; -export { createCalleeTree } from './common/callee'; +export { createFlameGraph } from './common/flamegraph'; export { ProfilingESField } from './common/elasticsearch'; export { groupStackFrameMetadataByStackTrace, @@ -30,9 +29,11 @@ export { createTopNFunctions, TopNFunctionSortField, topNFunctionSortFieldRt, + TopNComparisonFunctionSortField, + topNComparisonFunctionSortFieldRt, } from './common/functions'; +export { convertTonsToKgs } from './common/utils'; -export type { CalleeTree } from './common/callee'; export type { ProfilingStatusResponse, StackTraceResponse, diff --git a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts index d1aec24a9b26..7c0827147813 100644 --- a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts +++ b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts @@ -70,6 +70,9 @@ const ALERT_WORKFLOW_STATUS = `${ALERT_NAMESPACE}.workflow_status` as const; // kibana.alert.workflow_tags - user workflow alert tags const ALERT_WORKFLOW_TAGS = `${ALERT_NAMESPACE}.workflow_tags` as const; +// kibana.alert.workflow_assignee_ids - user workflow alert assignees +const ALERT_WORKFLOW_ASSIGNEE_IDS = `${ALERT_NAMESPACE}.workflow_assignee_ids` as const; + // kibana.alert.rule.category - rule type name for rule that generated this alert const ALERT_RULE_CATEGORY = `${ALERT_RULE_NAMESPACE}.category` as const; @@ -135,6 +138,7 @@ const fields = { ALERT_TIME_RANGE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, SPACE_IDS, @@ -174,6 +178,7 @@ export { ALERT_TIME_RANGE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, SPACE_IDS, diff --git a/packages/kbn-rule-data-utils/src/technical_field_names.ts b/packages/kbn-rule-data-utils/src/technical_field_names.ts index b387ab67750d..951766977f05 100644 --- a/packages/kbn-rule-data-utils/src/technical_field_names.ts +++ b/packages/kbn-rule-data-utils/src/technical_field_names.ts @@ -32,6 +32,7 @@ import { ALERT_STATUS, ALERT_TIME_RANGE, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, SPACE_IDS, @@ -174,6 +175,7 @@ const fields = { ALERT_STATUS, ALERT_SYSTEM_STATUS, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_REASON, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, diff --git a/packages/kbn-search-api-panels/components/ingest_data.tsx b/packages/kbn-search-api-panels/components/ingest_data.tsx index 0b0e11b13618..f8ba59d29bf3 100644 --- a/packages/kbn-search-api-panels/components/ingest_data.tsx +++ b/packages/kbn-search-api-panels/components/ingest_data.tsx @@ -6,25 +6,22 @@ * Side Public License, v 1. */ -import React, { useState } from 'react'; +import React from 'react'; -import { EuiCheckableCard, EuiFormFieldset, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { ApplicationStart } from '@kbn/core-application-browser'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import { CodeBox } from './code_box'; import { LanguageDefinition } from '../types'; import { OverviewPanel } from './overview_panel'; -import { IntegrationsPanel } from './integrations_panel'; - +import { IngestionsPanel } from './ingestions_panel'; interface IngestDataProps { codeSnippet: string; selectedLanguage: LanguageDefinition; setSelectedLanguage: (language: LanguageDefinition) => void; docLinks: { beats: string; - connectors: string; - integrations: string; logstash: string; }; assetBasePath: string; @@ -32,6 +29,7 @@ interface IngestDataProps { sharePlugin: SharePluginStart; languages: LanguageDefinition[]; consoleRequest?: string; + additionalIngestionPanel?: React.ReactNode; } export const IngestData: React.FC = ({ @@ -44,115 +42,45 @@ export const IngestData: React.FC = ({ sharePlugin, languages, consoleRequest, + additionalIngestionPanel, }) => { - const [selectedIngestMethod, setSelectedIngestMethod] = useState< - 'ingestViaApi' | 'ingestViaIntegration' - >('ingestViaApi'); return ( - ) : ( - - ) + } - links={[ - ...(selectedLanguage.apiReference - ? [ - { - href: selectedLanguage.apiReference, - label: i18n.translate('searchApiPanels.welcomeBanner.ingestData.clientDocLink', { - defaultMessage: '{languageName} API reference', - values: { languageName: selectedLanguage.name }, - }), - }, - ] - : []), - { - href: docLinks.integrations, - label: i18n.translate('searchApiPanels.welcomeBanner.ingestData.integrationsLink', { - defaultMessage: 'About Integrations', - }), - }, - ]} + links={[]} title={i18n.translate('searchApiPanels.welcomeBanner.ingestData.title', { defaultMessage: 'Ingest data', })} > - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.ingestApiLabel', { - defaultMessage: 'Ingest via API', - })} -

    - - } - value="ingestViaApi" - checked={selectedIngestMethod === 'ingestViaApi'} - onChange={() => setSelectedIngestMethod('ingestViaApi')} - > - - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.ingestApiDescription', { - defaultMessage: - 'The most flexible way to index data, enabling full control over your customization and optimization options.', - })} - -
    - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.ingestIntegrationLabel', { - defaultMessage: 'Ingest via integration', - })} -

    - - } - value="ingestViaIntegration" - checked={selectedIngestMethod === 'ingestViaIntegration'} - onChange={() => setSelectedIngestMethod('ingestViaIntegration')} - > - - {i18n.translate( - 'searchApiPanels.welcomeBanner.ingestData.ingestIntegrationDescription', - { - defaultMessage: - 'Specialized ingestion tools optimized for transforming data and shipping it to Elasticsearch.', - } - )} - -
    -
    + +

    + {i18n.translate('searchApiPanels.welcomeBanner.ingestData.alternativeOptions', { + defaultMessage: 'Alternative ingestion options', + })} +

    +
    + + +
    ); }; diff --git a/packages/kbn-search-api-panels/components/ingestions_panel.tsx b/packages/kbn-search-api-panels/components/ingestions_panel.tsx new file mode 100644 index 000000000000..ef9a0ef95ad0 --- /dev/null +++ b/packages/kbn-search-api-panels/components/ingestions_panel.tsx @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer, EuiText, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { GithubLink } from './github_link'; + +interface IngestionPanelProps { + additionalIngestionPanel?: React.ReactNode; + docLinks: { beats: string; logstash: string }; + assetBasePath: string; +} + +export const IngestionsPanel: React.FC = ({ + additionalIngestionPanel, + docLinks, + assetBasePath, +}) => { + const panels = [ + { + description: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDescription', + { + defaultMessage: + 'General-purpose data processing pipeline for Elasticsearch. Use Logstash to extract and transform data from a variety of inputs and outputs.', + } + ), + title: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashTitle', + { + defaultMessage: 'Logstash', + } + ), + links: [ + { + href: docLinks.logstash, + label: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDocumentationLabel', + { + defaultMessage: 'Documentation', + } + ), + }, + { + href: 'https://github.com/elastic/logstash', + isGithubLink: true, + label: 'logstash', + }, + ], + }, + { + description: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDescription', + { + defaultMessage: + 'Lightweight, single-purpose data shippers for Elasticsearch. Use Beats to send operational data from your servers.', + } + ), + title: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsTitle', + { + defaultMessage: 'Beats', + } + ), + links: [ + { + href: docLinks.beats, + label: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDocumentationLabel', + { + defaultMessage: 'Documentation', + } + ), + }, + { + href: 'https://github.com/elastic/beats', + isGithubLink: true, + label: 'beats', + }, + ], + }, + ]; + return ( + <> + {additionalIngestionPanel} + {panels.map(({ title, description, links }, panelIndex) => ( + + + +
    {title}
    +
    + + +

    {description}

    +
    +
    + {links && links.length > 0 && ( + <> + + {links.map(({ label, href, isGithubLink }, linksIndex) => ( + + {isGithubLink ? ( + + ) : ( + + {label} + + )} + + ))} + + + + )} +
    + ))} + + ); +}; diff --git a/packages/kbn-search-api-panels/components/integrations_panel.tsx b/packages/kbn-search-api-panels/components/integrations_panel.tsx deleted file mode 100644 index 3f6005f26ceb..000000000000 --- a/packages/kbn-search-api-panels/components/integrations_panel.tsx +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; - -import { - EuiThemeProvider, - EuiPanel, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiTitle, - EuiSpacer, - EuiText, - EuiLink, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { LEARN_MORE_LABEL } from '../constants'; -import { GithubLink } from './github_link'; - -export interface IntegrationsPanelProps { - docLinks: { beats: string; connectors: string; logstash: string }; - assetBasePath: string; -} - -export const IntegrationsPanel: React.FC = ({ - docLinks, - assetBasePath, -}) => { - return ( - - - - - - - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.logstashTitle', { - defaultMessage: 'Logstash', - })} -

    -
    - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.logstashDescription', { - defaultMessage: - 'Add data to your data stream or index to make it searchable. Choose an ingestion method that fits your application and workflow.', - })} -

    -
    - - - - - - {LEARN_MORE_LABEL} - - - - - - - -
    -
    - - - - - - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.beatsTitle', { - defaultMessage: 'Beats', - })} -

    -
    - - - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.beatsDescription', { - defaultMessage: - 'Lightweight, single-purpose data shippers for Elasticsearch. Use Beats to send operational data from your servers.', - })} - - - - - - - {LEARN_MORE_LABEL} - - - - - - - -
    -
    - - - - - - - -

    - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsTitle', { - defaultMessage: 'Connector clients', - })} -

    -
    - - - {i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsDescription', { - defaultMessage: - 'Specialized integrations for syncing data from third-party sources to Elasticsearch. Use Elastic connectors to sync content from a range of databases and object stores.', - })} - - - - - - - {LEARN_MORE_LABEL} - - - - - - - -
    -
    -
    -
    - ); -}; diff --git a/packages/kbn-search-api-panels/index.tsx b/packages/kbn-search-api-panels/index.tsx index 059aaf184ebf..513cc0fda807 100644 --- a/packages/kbn-search-api-panels/index.tsx +++ b/packages/kbn-search-api-panels/index.tsx @@ -14,7 +14,7 @@ import { AuthenticatedUser } from '@kbn/security-plugin/common'; export * from './components/code_box'; export * from './components/github_link'; export * from './components/ingest_data'; -export * from './components/integrations_panel'; +export * from './components/ingestions_panel'; export * from './components/language_client_panel'; export * from './components/overview_panel'; export * from './components/select_client'; @@ -54,18 +54,18 @@ export const WelcomeBanner: React.FC = ({ {Boolean(user) && ( - +

    {user ? i18n.translate('searchApiPanels.welcomeBanner.header.greeting.customTitle', { - defaultMessage: 'Hi {name}!', + defaultMessage: '👋 Hi {name}!', values: { name: user.full_name || user.username }, }) : i18n.translate('searchApiPanels.welcomeBanner.header.greeting.defaultTitle', { - defaultMessage: 'Hi!', + defaultMessage: '👋 Hi', })}

    -
    +
    )} diff --git a/packages/kbn-search-connectors/types/native_connectors.ts b/packages/kbn-search-connectors/types/native_connectors.ts index d815c40eb435..e29f1ebbf8a8 100644 --- a/packages/kbn-search-connectors/types/native_connectors.ts +++ b/packages/kbn-search-connectors/types/native_connectors.ts @@ -2040,6 +2040,243 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record ({ @@ -368,7 +368,7 @@ describe('AutocompleteFieldWildcardComponent', () => { placeholder="Placeholder text" selectedField={getField('file.path.text')} selectedValue="invalid path" - warning={FILENAME_WILDCARD_WARNING} + warning={WILDCARD_WARNING} /> ); @@ -384,7 +384,7 @@ describe('AutocompleteFieldWildcardComponent', () => { const helpText = wrapper .find('[data-test-subj="valuesAutocompleteWildcardLabel"] div.euiFormHelpText') .at(0); - expect(helpText.text()).toEqual(FILENAME_WILDCARD_WARNING); + expect(helpText.text()).toEqual(WILDCARD_WARNING); expect(helpText.find('.euiToolTipAnchor')).toBeTruthy(); }); test('should show the warning helper text if the new value contains spaces when change', async () => { @@ -412,7 +412,7 @@ describe('AutocompleteFieldWildcardComponent', () => { placeholder="Placeholder text" selectedField={getField('file.path.text')} selectedValue="invalid path" - warning={FILENAME_WILDCARD_WARNING} + warning={WILDCARD_WARNING} /> ); diff --git a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx index 3595b96d7e42..954b14a8ea24 100644 --- a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx @@ -223,6 +223,7 @@ describe('operator', () => { { label: 'is one of' }, { label: 'is not one of' }, { label: 'matches' }, + { label: 'does not match' }, ]); }); diff --git a/packages/kbn-securitysolution-ecs/src/signal/index.ts b/packages/kbn-securitysolution-ecs/src/signal/index.ts index 679ab70264d2..623d6a3e96a6 100644 --- a/packages/kbn-securitysolution-ecs/src/signal/index.ts +++ b/packages/kbn-securitysolution-ecs/src/signal/index.ts @@ -24,6 +24,7 @@ export type SignalEcsAAD = Exclude & { building_block_type?: string[]; workflow_status?: string[]; workflow_tags?: string[]; + workflow_assignee_ids?: string[]; suppression?: { docs_count: string[]; }; diff --git a/packages/kbn-securitysolution-grouping/src/components/group_selector/index.test.tsx b/packages/kbn-securitysolution-grouping/src/components/group_selector/index.test.tsx index 2172390f41e8..9f09e3b26ea4 100644 --- a/packages/kbn-securitysolution-grouping/src/components/group_selector/index.test.tsx +++ b/packages/kbn-securitysolution-grouping/src/components/group_selector/index.test.tsx @@ -124,4 +124,52 @@ describe('group selector', () => { ); expect(getByTestId('group-selector-dropdown').title).toEqual('Rule name, Host name'); }); + describe('when maxGroupingLevels is 1', () => { + it('Presents single option selector label when dropdown is clicked', () => { + const { getByTestId } = render( + + ); + fireEvent.click(getByTestId('group-selector-dropdown')); + expect(getByTestId('contextMenuPanelTitle').textContent).toMatch(/select grouping/i); + }); + it('Does not disable any options when maxGroupingLevels is 1 and one option is selected', () => { + const groupSelected = ['kibana.alert.rule.name']; + + const { getByTestId } = render( + + ); + + fireEvent.click(getByTestId('group-selector-dropdown')); + + [...testProps.options, { key: 'custom', label: 'Custom field' }].forEach((o) => { + expect(getByTestId(`panel-${o.key}`)).not.toHaveAttribute('disabled'); + }); + }); + }); + describe('when maxGroupingLevels is greater than 1', () => { + it('Presents select up to "X" groupings when dropdown is clicked', () => { + const { getByTestId } = render( + + ); + fireEvent.click(getByTestId('group-selector-dropdown')); + expect(getByTestId('contextMenuPanelTitle').textContent).toMatch(/select up to 3 groupings/i); + }); + it('Disables non-selected options when maxGroupingLevels is greater than 1 and the selects items reaches the maxGroupingLevels', () => { + const groupSelected = ['kibana.alert.rule.name', 'user.name']; + + const { getByTestId } = render( + + ); + + fireEvent.click(getByTestId('group-selector-dropdown')); + + [...testProps.options, { key: 'custom', label: 'Custom field' }].forEach((o) => { + if (groupSelected.includes(o.key) || o.key === 'none') { + expect(getByTestId(`panel-${o.key}`)).not.toHaveAttribute('disabled'); + } else { + expect(getByTestId(`panel-${o.key}`)).toHaveAttribute('disabled'); + } + }); + }); + }); }); diff --git a/packages/kbn-securitysolution-grouping/src/components/group_selector/index.tsx b/packages/kbn-securitysolution-grouping/src/components/group_selector/index.tsx index 3fa82f7f8af2..ffec5db36206 100644 --- a/packages/kbn-securitysolution-grouping/src/components/group_selector/index.tsx +++ b/packages/kbn-securitysolution-grouping/src/components/group_selector/index.tsx @@ -43,11 +43,21 @@ const GroupSelectorComponent = ({ [groupsSelected] ); - const panels: EuiContextMenuPanelDescriptor[] = useMemo( - () => [ + const panels: EuiContextMenuPanelDescriptor[] = useMemo(() => { + const isOptionDisabled = (key?: string) => { + // Do not disable when maxGroupingLevels is 1 to allow toggling between groups + if (maxGroupingLevels === 1) { + return false; + } + // Disable all non selected options when the maxGroupingLevels is reached + return groupsSelected.length === maxGroupingLevels && (key ? !isGroupSelected(key) : true); + }; + + return [ { id: 'firstPanel', - title: i18n.SELECT_FIELD(maxGroupingLevels), + title: + maxGroupingLevels === 1 ? i18n.SELECT_SINGLE_FIELD : i18n.SELECT_FIELD(maxGroupingLevels), items: [ { 'data-test-subj': 'panel-none', @@ -57,7 +67,7 @@ const GroupSelectorComponent = ({ }, ...options.map((o) => ({ 'data-test-subj': `panel-${o.key}`, - disabled: groupsSelected.length === maxGroupingLevels && !isGroupSelected(o.key), + disabled: isOptionDisabled(o.key), name: o.label, onClick: () => onGroupChange(o.key), icon: isGroupSelected(o.key) ? 'check' : 'empty', @@ -66,7 +76,7 @@ const GroupSelectorComponent = ({ 'data-test-subj': `panel-custom`, name: i18n.CUSTOM_FIELD, icon: 'empty', - disabled: groupsSelected.length === maxGroupingLevels, + disabled: isOptionDisabled(), panel: 'customPanel', hasPanel: true, }, @@ -87,9 +97,8 @@ const GroupSelectorComponent = ({ /> ), }, - ], - [fields, groupsSelected.length, isGroupSelected, maxGroupingLevels, onGroupChange, options] - ); + ]; + }, [fields, groupsSelected.length, isGroupSelected, maxGroupingLevels, onGroupChange, options]); const selectedOptions = useMemo( () => options.filter((groupOption) => isGroupSelected(groupOption.key)), [isGroupSelected, options] diff --git a/packages/kbn-securitysolution-grouping/src/components/grouping.test.tsx b/packages/kbn-securitysolution-grouping/src/components/grouping.test.tsx index 2b581ed774d5..0cf16ae4c821 100644 --- a/packages/kbn-securitysolution-grouping/src/components/grouping.test.tsx +++ b/packages/kbn-securitysolution-grouping/src/components/grouping.test.tsx @@ -136,4 +136,53 @@ describe('grouping container', () => { expect(renderChildComponent).toHaveBeenCalledWith(getNullGroupFilter('host.name')); }); + + it('Renders groupPanelRenderer when provided', () => { + const groupPanelRenderer = jest.fn(); + render( + + + + ); + + expect(groupPanelRenderer).toHaveBeenNthCalledWith( + 1, + 'host.name', + testProps.data.groupByFields.buckets[0], + undefined, + false + ); + + expect(groupPanelRenderer).toHaveBeenNthCalledWith( + 2, + 'host.name', + testProps.data.groupByFields.buckets[1], + undefined, + false + ); + + expect(groupPanelRenderer).toHaveBeenNthCalledWith( + 3, + 'host.name', + testProps.data.groupByFields.buckets[2], + 'The selected group by field, host.name, is missing a value for this group of events.', + false + ); + }); + it('Renders groupPanelRenderer when provided with isLoading attribute', () => { + const groupPanelRenderer = jest.fn(); + render( + + + + ); + + expect(groupPanelRenderer).toHaveBeenNthCalledWith( + 1, + 'host.name', + testProps.data.groupByFields.buckets[0], + undefined, + true + ); + }); }); diff --git a/packages/kbn-securitysolution-grouping/src/components/grouping.tsx b/packages/kbn-securitysolution-grouping/src/components/grouping.tsx index aab42a0804e4..5ae1037d9edb 100644 --- a/packages/kbn-securitysolution-grouping/src/components/grouping.tsx +++ b/packages/kbn-securitysolution-grouping/src/components/grouping.tsx @@ -128,7 +128,7 @@ const GroupingComponent = ({ groupBucket={groupBucket} groupPanelRenderer={ groupPanelRenderer && - groupPanelRenderer(selectedGroup, groupBucket, nullGroupMessage) + groupPanelRenderer(selectedGroup, groupBucket, nullGroupMessage, isLoading) } isLoading={isLoading} onToggleGroup={(isOpen) => { diff --git a/packages/kbn-securitysolution-grouping/src/components/translations.ts b/packages/kbn-securitysolution-grouping/src/components/translations.ts index c2e0f13e325a..de5337db904d 100644 --- a/packages/kbn-securitysolution-grouping/src/components/translations.ts +++ b/packages/kbn-securitysolution-grouping/src/components/translations.ts @@ -32,6 +32,10 @@ export const SELECT_FIELD = (groupingLevelsCount: number) => defaultMessage: 'Select up to {groupingLevelsCount} groupings', }); +export const SELECT_SINGLE_FIELD = i18n.translate('grouping.groupBySingleField', { + defaultMessage: 'Select grouping', +}); + export const NONE = i18n.translate('grouping.noneGroupByOptionName', { defaultMessage: 'None', }); diff --git a/packages/kbn-securitysolution-grouping/src/components/types.ts b/packages/kbn-securitysolution-grouping/src/components/types.ts index 6987a09c083f..43a9af13372f 100644 --- a/packages/kbn-securitysolution-grouping/src/components/types.ts +++ b/packages/kbn-securitysolution-grouping/src/components/types.ts @@ -76,7 +76,8 @@ export type GroupStatsRenderer = ( export type GroupPanelRenderer = ( selectedGroup: string, fieldBucket: RawBucket, - nullGroupMessage?: string + nullGroupMessage?: string, + isLoading?: boolean ) => JSX.Element | undefined; export type OnGroupToggle = (params: { diff --git a/packages/kbn-securitysolution-grouping/src/containers/query/types.ts b/packages/kbn-securitysolution-grouping/src/containers/query/types.ts index b208aef1e840..69a284ecf7a5 100644 --- a/packages/kbn-securitysolution-grouping/src/containers/query/types.ts +++ b/packages/kbn-securitysolution-grouping/src/containers/query/types.ts @@ -19,11 +19,11 @@ type RunTimeMappings = | Record & { type: RuntimePrimitiveTypes }> | undefined; -interface BoolAgg { +export interface BoolAgg { bool: BoolQuery; } -interface RangeAgg { +export interface RangeAgg { range: { '@timestamp': { gte: string; lte: string } }; } diff --git a/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.test.tsx b/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.test.tsx index 36fe9badac55..e6221c677b9d 100644 --- a/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.test.tsx +++ b/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.test.tsx @@ -157,6 +157,34 @@ describe('Group Selector Hooks', () => { }); }); + it('On group change when maxGroupingLevels is 1, remove previously selected group', () => { + const testGroup = { + [groupingId]: { + ...defaultGroup, + options: defaultGroupingOptions, + activeGroups: ['host.name'], + }, + }; + const { result } = renderHook((props) => useGetGroupSelector(props), { + initialProps: { + ...defaultArgs, + maxGroupingLevels: 1, + groupingState: { + groupById: testGroup, + }, + }, + }); + act(() => result.current.props.onGroupChange('user.name')); + + expect(dispatch).toHaveBeenCalledWith({ + payload: { + id: groupingId, + activeGroups: ['user.name'], + }, + type: ActionType.updateActiveGroups, + }); + }); + it('On group change, resets active page, sets active group, and leaves options alone', () => { const testGroup = { [groupingId]: { diff --git a/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.tsx b/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.tsx index d50809c99fb3..d3e518a48fe5 100644 --- a/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.tsx +++ b/packages/kbn-securitysolution-grouping/src/hooks/use_get_group_selector.tsx @@ -30,6 +30,7 @@ export interface UseGetGroupSelectorArgs { event: string | string[], count?: number | undefined ) => void; + title?: string; } interface UseGetGroupSelectorStateless @@ -84,6 +85,7 @@ export const useGetGroupSelector = ({ onGroupChange, onOptionsChange, tracker, + title, }: UseGetGroupSelectorArgs) => { const { activeGroups: selectedGroups, options } = groupByIdSelector({ groups: groupingState }, groupingId) ?? defaultGroup; @@ -110,20 +112,25 @@ export const useGetGroupSelector = ({ const onChange = useCallback( (groupSelection: string) => { - if (selectedGroups.find((selected) => selected === groupSelection)) { - const groups = selectedGroups.filter((selectedGroup) => selectedGroup !== groupSelection); - if (groups.length === 0) { - setSelectedGroups(['none']); - } else { - setSelectedGroups(groups); + // Simulate a toggle behavior when maxGroupingLevels is 1 + if (maxGroupingLevels === 1) { + setSelectedGroups([groupSelection]); + } else { + if (selectedGroups.find((selected) => selected === groupSelection)) { + const groups = selectedGroups.filter((selectedGroup) => selectedGroup !== groupSelection); + if (groups.length === 0) { + setSelectedGroups(['none']); + } else { + setSelectedGroups(groups); + } + return; } - return; - } - const newSelectedGroups = isNoneGroup([groupSelection]) - ? [groupSelection] - : [...selectedGroups.filter((selectedGroup) => selectedGroup !== 'none'), groupSelection]; - setSelectedGroups(newSelectedGroups); + const newSelectedGroups = isNoneGroup([groupSelection]) + ? [groupSelection] + : [...selectedGroups.filter((selectedGroup) => selectedGroup !== 'none'), groupSelection]; + setSelectedGroups(newSelectedGroups); + } // built-in telemetry: UI-counter tracker?.( @@ -133,7 +140,7 @@ export const useGetGroupSelector = ({ onGroupChange?.({ tableId: groupingId, groupByField: groupSelection }); }, - [groupingId, onGroupChange, selectedGroups, setSelectedGroups, tracker] + [groupingId, maxGroupingLevels, onGroupChange, selectedGroups, setSelectedGroups, tracker] ); useEffect(() => { @@ -184,6 +191,7 @@ export const useGetGroupSelector = ({ fields, maxGroupingLevels, options, + title, }} /> ); diff --git a/packages/kbn-securitysolution-grouping/src/hooks/use_grouping.tsx b/packages/kbn-securitysolution-grouping/src/hooks/use_grouping.tsx index a744fc6c4ff7..3ff2232acbd7 100644 --- a/packages/kbn-securitysolution-grouping/src/hooks/use_grouping.tsx +++ b/packages/kbn-securitysolution-grouping/src/hooks/use_grouping.tsx @@ -19,7 +19,7 @@ import { Grouping as GroupingComponent } from '../components/grouping'; /** Interface for grouping object where T is the `GroupingAggregation` * @interface GroupingArgs */ -interface Grouping { +export interface UseGrouping { getGrouping: (props: DynamicGroupingProps) => React.ReactElement; groupSelector: React.ReactElement; selectedGroups: string[]; @@ -72,6 +72,7 @@ interface GroupingArgs { event: string | string[], count?: number | undefined ) => void; + title?: string; } /** @@ -85,6 +86,7 @@ interface GroupingArgs { * @param onGroupChange callback executed when selected group is changed, used for tracking * @param onOptionsChange callback executed when grouping options are changed, used for consumer grouping selector * @param tracker telemetry handler + * @param title of the grouping selector component * @returns {@link Grouping} the grouping constructor { getGrouping, groupSelector, pagination, selectedGroups } */ export const useGrouping = ({ @@ -96,7 +98,8 @@ export const useGrouping = ({ onGroupChange, onOptionsChange, tracker, -}: GroupingArgs): Grouping => { + title, +}: GroupingArgs): UseGrouping => { const [groupingState, dispatch] = useReducer(groupsReducerWithStorage, initialState); const { activeGroups: selectedGroups } = useMemo( () => groupByIdSelector({ groups: groupingState }, groupingId) ?? defaultGroup, @@ -125,6 +128,7 @@ export const useGrouping = ({ onGroupChange, onOptionsChange, tracker, + title, }); const getGrouping = useCallback( diff --git a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts b/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts index f9caa6387e35..c236cacad6a2 100644 --- a/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/autocomplete_operators/index.ts @@ -109,6 +109,7 @@ export const EVENT_FILTERS_OPERATORS: OperatorOption[] = [ isOneOfOperator, isNotOneOfOperator, matchesOperator, + doesNotMatchOperator, ]; /* diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts index 5bb84816b160..f877683caec1 100644 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts +++ b/packages/kbn-securitysolution-utils/src/path_validations/index.test.ts @@ -11,11 +11,43 @@ import { hasSimpleExecutableName, OperatingSystem, ConditionEntryField, + validatePotentialWildcardInput, validateFilePathInput, - FILENAME_WILDCARD_WARNING, + validateWildcardInput, + WILDCARD_WARNING, FILEPATH_WARNING, } from '.'; +describe('validatePotentialWildcardInput', () => { + it('warns on wildcard when field is file.path.text', () => { + expect( + validatePotentialWildcardInput({ + field: 'file.path.text', + os: OperatingSystem.WINDOWS, + value: 'c:\\path*.exe', + }) + ).toEqual(WILDCARD_WARNING); + }); + it('warns on wildcard when field is not file.path.text', () => { + expect( + validatePotentialWildcardInput({ + field: 'event.category', + os: OperatingSystem.WINDOWS, + value: 'some*value', + }) + ).toEqual(WILDCARD_WARNING); + }); +}); + +describe('validateWildcardInput', () => { + it('warns on wildcard for fields that are not file paths', () => { + expect(validateWildcardInput('*')).toEqual(WILDCARD_WARNING); + }); + it('does not warn if no wildcard', () => { + expect(validateWildcardInput('non-wildcard')).toEqual(undefined); + }); +}); + describe('validateFilePathInput', () => { describe('windows', () => { const os = OperatingSystem.WINDOWS; @@ -36,15 +68,13 @@ describe('validateFilePathInput', () => { }); it('warns on wildcard in file name at the end of the path', () => { - expect(validateFilePathInput({ os, value: 'c:\\path*.exe' })).toEqual( - FILENAME_WILDCARD_WARNING - ); + expect(validateFilePathInput({ os, value: 'c:\\path*.exe' })).toEqual(WILDCARD_WARNING); expect( validateFilePathInput({ os, value: 'C:\\Windows\\*\\FILENAME.EXE-*.gz', }) - ).toEqual(FILENAME_WILDCARD_WARNING); + ).toEqual(WILDCARD_WARNING); }); it('warns on unix paths or non-windows paths', () => { @@ -65,20 +95,23 @@ describe('validateFilePathInput', () => { : OperatingSystem.LINUX; it('does not warn on valid filenames', () => { - expect(validateFilePathInput({ os, value: '/opt/*/FILENAME.EXE-1231205124.gz' })).not.toEqual( - FILENAME_WILDCARD_WARNING - ); + expect( + validateFilePathInput({ + os, + value: '/opt/*/FILENAME.EXE-1231205124.gz', + }) + ).not.toEqual(WILDCARD_WARNING); expect( validateFilePathInput({ os, value: "/opt/*/test$ as2@13---12!@#A,DS.#$^&$!#~ 'as'd.华语.txt", }) - ).not.toEqual(FILENAME_WILDCARD_WARNING); + ).not.toEqual(WILDCARD_WARNING); }); it('warns on wildcard in file name at the end of the path', () => { - expect(validateFilePathInput({ os, value: '/opt/bin*' })).toEqual(FILENAME_WILDCARD_WARNING); + expect(validateFilePathInput({ os, value: '/opt/bin*' })).toEqual(WILDCARD_WARNING); expect(validateFilePathInput({ os, value: '/opt/FILENAME.EXE-*.gz' })).toEqual( - FILENAME_WILDCARD_WARNING + WILDCARD_WARNING ); }); diff --git a/packages/kbn-securitysolution-utils/src/path_validations/index.ts b/packages/kbn-securitysolution-utils/src/path_validations/index.ts index ac7c17426e72..b2ae2d9fbceb 100644 --- a/packages/kbn-securitysolution-utils/src/path_validations/index.ts +++ b/packages/kbn-securitysolution-utils/src/path_validations/index.ts @@ -8,8 +8,8 @@ import { i18n } from '@kbn/i18n'; -export const FILENAME_WILDCARD_WARNING = i18n.translate('utils.filename.wildcardWarning', { - defaultMessage: `Using wildcards in file paths can impact Endpoint performance`, +export const WILDCARD_WARNING = i18n.translate('utils.wildcardWarning', { + defaultMessage: `Using wildcards can impact Endpoint performance`, }); export const FILEPATH_WARNING = i18n.translate('utils.filename.pathWarning', { @@ -52,39 +52,60 @@ export enum OperatingSystem { export type EntryTypes = 'match' | 'wildcard' | 'match_any'; export type TrustedAppEntryTypes = Extract; -export const validateFilePathInput = ({ +export const validatePotentialWildcardInput = ({ + field = '', os, value = '', }: { + field?: string; os: OperatingSystem; value?: string; }): string | undefined => { const textInput = value.trim(); + if (field === 'file.path.text') { + return validateFilePathInput({ os, value: textInput }); + } + return validateWildcardInput(textInput); +}; + +export const validateFilePathInput = ({ + os, + value, +}: { + os: OperatingSystem; + value: string; +}): string | undefined => { const isValidFilePath = isPathValid({ os, field: 'file.path.text', type: 'wildcard', - value: textInput, + value, }); const hasSimpleFileName = hasSimpleExecutableName({ os, type: 'wildcard', - value: textInput, + value, }); - if (!textInput.length) { + if (!value.length) { return FILEPATH_WARNING; } if (isValidFilePath) { if (hasSimpleFileName !== undefined && !hasSimpleFileName) { - return FILENAME_WILDCARD_WARNING; + return WILDCARD_WARNING; } } else { return FILEPATH_WARNING; } }; +export const validateWildcardInput = (value?: string): string | undefined => { + if (/[*?]/.test(value ?? '')) { + return WILDCARD_WARNING; + } +}; + export const hasSimpleExecutableName = ({ os, type, diff --git a/packages/kbn-server-http-tools/index.ts b/packages/kbn-server-http-tools/index.ts index 3e172297bf6c..a572cc6ab083 100644 --- a/packages/kbn-server-http-tools/index.ts +++ b/packages/kbn-server-http-tools/index.ts @@ -10,6 +10,7 @@ export type { IHttpConfig, ISslConfig, ICorsConfig } from './src/types'; export { createServer } from './src/create_server'; export { defaultValidationErrorHandler } from './src/default_validation_error_handler'; export { getListenerOptions } from './src/get_listener_options'; -export { getServerOptions } from './src/get_server_options'; +export { getServerOptions, getServerTLSOptions } from './src/get_server_options'; export { getRequestId } from './src/get_request_id'; +export { setTlsConfig } from './src/set_tls_config'; export { sslSchema, SslConfig } from './src/ssl'; diff --git a/packages/kbn-server-http-tools/src/get_server_options.ts b/packages/kbn-server-http-tools/src/get_server_options.ts index ade90a0e0d3f..5cac081fdd14 100644 --- a/packages/kbn-server-http-tools/src/get_server_options.ts +++ b/packages/kbn-server-http-tools/src/get_server_options.ts @@ -9,7 +9,7 @@ import { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; import { ServerOptions as TLSOptions } from 'https'; import { defaultValidationErrorHandler } from './default_validation_error_handler'; -import { IHttpConfig } from './types'; +import { IHttpConfig, ISslConfig } from './types'; const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; @@ -50,26 +50,31 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = }, }; - if (configureTLS && config.ssl.enabled) { - const ssl = config.ssl; - - // TODO: Hapi types have a typo in `tls` property type definition: `https.RequestOptions` is used instead of - // `https.ServerOptions`, and `honorCipherOrder` isn't presented in `https.RequestOptions`. - const tlsOptions: TLSOptions = { - ca: ssl.certificateAuthorities, - cert: ssl.certificate, - ciphers: config.ssl.cipherSuites?.join(':'), - // We use the server's cipher order rather than the client's to prevent the BEAST attack. - honorCipherOrder: true, - key: ssl.key, - passphrase: ssl.keyPassphrase, - secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, - requestCert: ssl.requestCert, - rejectUnauthorized: ssl.rejectUnauthorized, - }; - - options.tls = tlsOptions; + if (configureTLS) { + options.tls = getServerTLSOptions(config.ssl); } return options; } + +/** + * Converts Kibana `SslConfig` into `TLSOptions` that are accepted by the Hapi server, + * and by https.Server.setSecureContext() + */ +export function getServerTLSOptions(ssl: ISslConfig): TLSOptions | undefined { + if (!ssl.enabled) { + return undefined; + } + return { + ca: ssl.certificateAuthorities, + cert: ssl.certificate, + ciphers: ssl.cipherSuites?.join(':'), + // We use the server's cipher order rather than the client's to prevent the BEAST attack. + honorCipherOrder: true, + key: ssl.key, + passphrase: ssl.keyPassphrase, + secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, + requestCert: ssl.requestCert, + rejectUnauthorized: ssl.rejectUnauthorized, + }; +} diff --git a/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts b/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts new file mode 100644 index 000000000000..4b93301b334e --- /dev/null +++ b/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const getServerTLSOptionsMock = jest.fn(); + +jest.doMock('./get_server_options', () => { + const actual = jest.requireActual('./get_server_options'); + return { + ...actual, + getServerTLSOptions: getServerTLSOptionsMock, + }; +}); diff --git a/packages/kbn-server-http-tools/src/set_tls_config.test.ts b/packages/kbn-server-http-tools/src/set_tls_config.test.ts new file mode 100644 index 000000000000..ea3e61c13944 --- /dev/null +++ b/packages/kbn-server-http-tools/src/set_tls_config.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { getServerTLSOptionsMock } from './set_tls_config.test.mocks'; +import { Server } from '@hapi/hapi'; +import type { ISslConfig } from './types'; +import { setTlsConfig } from './set_tls_config'; + +describe('setTlsConfig', () => { + beforeEach(() => { + getServerTLSOptionsMock.mockReset(); + getServerTLSOptionsMock.mockReturnValue({}); + }); + + it('throws when called for a non-TLS server', () => { + const server = new Server({}); + const config: ISslConfig = { enabled: true }; + expect(() => setTlsConfig(server, config)).toThrowErrorMatchingInlineSnapshot( + `"tried to set TLS config on a non-TLS http server"` + ); + }); + + it('calls `getServerTLSOptions` with the correct parameters', () => { + const server = new Server({}); + // easiest way to shim a tls.Server + (server.listener as any).setSecureContext = jest.fn(); + const config: ISslConfig = { enabled: true }; + + setTlsConfig(server, config); + + expect(getServerTLSOptionsMock).toHaveBeenCalledTimes(1); + expect(getServerTLSOptionsMock).toHaveBeenCalledWith(config); + }); + + it('throws when called for a disabled SSL config', () => { + const server = new Server({}); + // easiest way to shim a tls.Server + (server.listener as any).setSecureContext = jest.fn(); + const config: ISslConfig = { enabled: false }; + + getServerTLSOptionsMock.mockReturnValue(undefined); + + expect(() => setTlsConfig(server, config)).toThrowErrorMatchingInlineSnapshot( + `"tried to apply a disabled SSL config"` + ); + }); + + it('calls `setSecureContext` on the underlying server', () => { + const server = new Server({}); + // easiest way to shim a tls.Server + const setSecureContextMock = jest.fn(); + (server.listener as any).setSecureContext = setSecureContextMock; + const config: ISslConfig = { enabled: true }; + + const tlsConfig = { someTlsConfig: true }; + getServerTLSOptionsMock.mockReturnValue(tlsConfig); + + setTlsConfig(server, config); + + expect(setSecureContextMock).toHaveBeenCalledTimes(1); + expect(setSecureContextMock).toHaveBeenCalledWith(tlsConfig); + }); +}); diff --git a/packages/kbn-server-http-tools/src/set_tls_config.ts b/packages/kbn-server-http-tools/src/set_tls_config.ts new file mode 100644 index 000000000000..1f2e1d70fa12 --- /dev/null +++ b/packages/kbn-server-http-tools/src/set_tls_config.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { Server as HapiServer } from '@hapi/hapi'; +import type { Server as HttpServer } from 'http'; +import type { Server as TlsServer } from 'https'; +import type { ISslConfig } from './types'; +import { getServerTLSOptions } from './get_server_options'; + +function isServerTLS(server: HttpServer): server is TlsServer { + return 'setSecureContext' in server; +} + +export const setTlsConfig = (hapiServer: HapiServer, sslConfig: ISslConfig) => { + const server = hapiServer.listener; + if (!isServerTLS(server)) { + throw new Error('tried to set TLS config on a non-TLS http server'); + } + const tlsOptions = getServerTLSOptions(sslConfig); + if (!tlsOptions) { + throw new Error('tried to apply a disabled SSL config'); + } + server.setSecureContext(tlsOptions); +}; diff --git a/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts index 112fcd8a449f..c6f701ef67a1 100644 --- a/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.test.ts @@ -164,6 +164,79 @@ describe('#SslConfig', () => { expect(configValue.certificate).toEqual('content-of-another-path'); }); }); + + describe('isEqualTo()', () => { + const createEnabledConfig = (obj: any) => + createConfig({ + enabled: true, + key: 'same-key', + certificate: 'same-cert', + ...obj, + }); + + it('compares `enabled`', () => { + const reference = createConfig({ enabled: true, key: 'same-key', certificate: 'same-cert' }); + const same = createConfig({ enabled: true, key: 'same-key', certificate: 'same-cert' }); + const different = createConfig({ enabled: false, key: 'same-key', certificate: 'same-cert' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `key`', () => { + const reference = createEnabledConfig({ key: 'keyA', certificate: 'same-cert' }); + const same = createEnabledConfig({ key: 'keyA', certificate: 'same-cert' }); + const different = createEnabledConfig({ key: 'keyB', certificate: 'same-cert' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `keyPassphrase`', () => { + const reference = createEnabledConfig({ keyPassphrase: 'passA' }); + const same = createEnabledConfig({ keyPassphrase: 'passA' }); + const different = createEnabledConfig({ keyPassphrase: 'passB' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `certificate`', () => { + const reference = createEnabledConfig({ key: 'same-key', certificate: 'cert-a' }); + const same = createEnabledConfig({ key: 'same-key', certificate: 'cert-a' }); + const different = createEnabledConfig({ key: 'same-key', certificate: 'cert-b' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `cipherSuites`', () => { + const reference = createEnabledConfig({ cipherSuites: ['A', 'B'] }); + const same = createEnabledConfig({ cipherSuites: ['A', 'B'] }); + const different = createEnabledConfig({ cipherSuites: ['A', 'C'] }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `supportedProtocols`', () => { + const reference = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.2'] }); + const same = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.2'] }); + const different = createEnabledConfig({ supportedProtocols: ['TLSv1.1', 'TLSv1.3'] }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + + it('compares `clientAuthentication`', () => { + const reference = createEnabledConfig({ clientAuthentication: 'none' }); + const same = createEnabledConfig({ clientAuthentication: 'none' }); + const different = createEnabledConfig({ clientAuthentication: 'required' }); + + expect(reference.isEqualTo(same)).toBe(true); + expect(reference.isEqualTo(different)).toBe(false); + }); + }); }); describe('#sslSchema', () => { diff --git a/packages/kbn-server-http-tools/src/ssl/ssl_config.ts b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts index 53d3616a09a7..a5d43064baa6 100644 --- a/packages/kbn-server-http-tools/src/ssl/ssl_config.ts +++ b/packages/kbn-server-http-tools/src/ssl/ssl_config.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { isEqual } from 'lodash'; import { schema, TypeOf } from '@kbn/config-schema'; import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { constants as cryptoConstants } from 'crypto'; @@ -161,6 +162,13 @@ export class SslConfig { : secureOptions | secureOption; // eslint-disable-line no-bitwise }, 0); } + + public isEqualTo(otherConfig: SslConfig) { + if (this === otherConfig) { + return true; + } + return isEqual(this, otherConfig); + } } const readFile = (file: string) => readFileSync(file, 'utf8'); diff --git a/packages/kbn-subscription-tracking/README.md b/packages/kbn-subscription-tracking/README.md deleted file mode 100644 index 4f8459398088..000000000000 --- a/packages/kbn-subscription-tracking/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# @kbn/subscription-tracking - -This package leverages the `@kbn/analytics-client` package to send dedicated subscription tracking events. - -It provides a set of React components that automatically track `impression` and `click` events. Consumers of those components need to specify a `subscription context` that gives more details on the type of feature that is advertised and the location of the upsell. - -```typescript -import { SubscriptionLink } from '@kbn/subscription-tracking'; -import type { SubscriptionContext } from '@kbn/subscription-tracking'; - -const subscriptionContext: SubscriptionContext = { - feature: 'threat-intelligence', - source: 'security__threat-intelligence', -}; - -export const Paywall = () => { - return ( -
    - - Upgrade to Platinum to get this feature - -
    - ); -}; -``` - -The example above uses a `SubscriptionLink` which is a wrapper of `EuiLink` . So it behaves just like a normal link. Alternatively, upsells can also use a `SubscriptionButton` or `SubscriptionButtonEmpty` which wrap `EuiButton` and `EuiButtonEmpty` respectively. - -When the link is mounted, it will send off an `impression` event with the given `subscriptionContext`. That piece of metadata consists of an identifier of the advertised feature (in this case `threat-intelligence`) and the `source` (aka location) of the impression (in this case the `threat-intelligence` page in the `security` solution). `source` follows the following format: `{solution-identifier}__location-identifier`. - -There are no special rules for how to name these identifiers but it's good practise to make sure that `feature` has the same value for all upsells advertising the same feature (e.g. use enums for features to prevent spelling mistakes). - -Upon interaction with the upsell link/button, a special `click` event is sent, which, again, contains the same subscription context. - -If you want to use the `subscription-tracking` elements in your app, you have to set up a `SubscriptionTrackingProvider` in your plugin setup and register the tracking events on startup. Have a look at https://github.com/elastic/kibana/pull/143910 for an example of an integration. diff --git a/packages/kbn-subscription-tracking/index.ts b/packages/kbn-subscription-tracking/index.ts deleted file mode 100644 index de17c595918d..000000000000 --- a/packages/kbn-subscription-tracking/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export * from './src/subscription_elements'; - -export { - SubscriptionTrackingContext, - SubscriptionTrackingProvider, - registerEvents, -} from './src/services'; - -export * from './types'; diff --git a/packages/kbn-subscription-tracking/jest.config.js b/packages/kbn-subscription-tracking/jest.config.js deleted file mode 100644 index edc1839850da..000000000000 --- a/packages/kbn-subscription-tracking/jest.config.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../..', - roots: ['/packages/kbn-subscription-tracking'], -}; diff --git a/packages/kbn-subscription-tracking/kibana.jsonc b/packages/kbn-subscription-tracking/kibana.jsonc deleted file mode 100644 index e165baebfa76..000000000000 --- a/packages/kbn-subscription-tracking/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/subscription-tracking", - "owner": "@elastic/security-threat-hunting-investigations" -} diff --git a/packages/kbn-subscription-tracking/mocks.tsx b/packages/kbn-subscription-tracking/mocks.tsx deleted file mode 100644 index b918f9bba282..000000000000 --- a/packages/kbn-subscription-tracking/mocks.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { FC } from 'react'; -import { analyticsClientMock } from '@kbn/analytics-client/src/mocks'; - -import { SubscriptionTrackingProvider } from './src/services'; - -const analyticsClientMockInst = analyticsClientMock.create(); - -/** - * Mock for the external services provider. Only use in tests! - */ -export const MockSubscriptionTrackingProvider: FC = ({ children }) => { - return ( - - {children} - - ); -}; diff --git a/packages/kbn-subscription-tracking/package.json b/packages/kbn-subscription-tracking/package.json deleted file mode 100644 index e9dd11b56c81..000000000000 --- a/packages/kbn-subscription-tracking/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "@kbn/subscription-tracking", - "private": true, - "version": "1.0.0", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/packages/kbn-subscription-tracking/src/helpers.test.ts b/packages/kbn-subscription-tracking/src/helpers.test.ts deleted file mode 100644 index fa000567d35d..000000000000 --- a/packages/kbn-subscription-tracking/src/helpers.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { isValidContext } from './helpers'; - -describe('tracking', () => { - describe('isValidLocation', () => { - it('identifies correct contexts', () => { - expect( - isValidContext({ - feature: 'test', - source: 'security__test', - }) - ).toBeTruthy(); - }); - - it('identifies incorrect contexts', () => { - expect( - isValidContext({ - feature: '', - source: 'security__', - }) - ).toBeFalsy(); - - expect( - isValidContext({ - feature: 'test', - source: 'security__', - }) - ).toBeFalsy(); - - expect( - isValidContext({ - feature: '', - source: 'security__test', - }) - ).toBeFalsy(); - }); - }); -}); diff --git a/packages/kbn-subscription-tracking/src/helpers.ts b/packages/kbn-subscription-tracking/src/helpers.ts deleted file mode 100644 index 251c0d1c0411..000000000000 --- a/packages/kbn-subscription-tracking/src/helpers.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { SubscriptionContextData } from '../types'; - -const sourceStringRegEx = /^(\w[\w\-_]*)__(\w[\w\-_]*)$/; -export function isValidContext(context: SubscriptionContextData): boolean { - return context.feature.length > 0 && sourceStringRegEx.test(context.source); -} diff --git a/packages/kbn-subscription-tracking/src/services.tsx b/packages/kbn-subscription-tracking/src/services.tsx deleted file mode 100644 index 857bd0b0dcd8..000000000000 --- a/packages/kbn-subscription-tracking/src/services.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { FC, useContext } from 'react'; -import type { AnalyticsClient, EventTypeOpts } from '@kbn/analytics-client'; -import { EVENT_NAMES, Services, SubscriptionContextData } from '../types'; - -export const SubscriptionTrackingContext = React.createContext(null); - -/** - * External services provider - */ -export const SubscriptionTrackingProvider: FC = ({ children, ...services }) => { - return ( - - {children} - - ); -}; - -/** - * React hook for accessing pre-wired services. - */ -export function useServices() { - const context = useContext(SubscriptionTrackingContext); - - if (!context) { - throw new Error( - 'SubscriptionTrackingContext is missing. Ensure your component or React root is wrapped with SubscriptionTrackingProvider.' - ); - } - - return context; -} - -const subscriptionContextSchema: EventTypeOpts['schema'] = { - source: { - type: 'keyword', - _meta: { - description: - 'A human-readable identifier describing the location of the beginning of the subscription flow', - }, - }, - feature: { - type: 'keyword', - _meta: { - description: 'A human-readable identifier describing the feature that is being promoted', - }, - }, -}; - -/** - * Registers the subscription-specific event types - */ -export function registerEvents(analyticsClient: Pick) { - analyticsClient.registerEventType({ - eventType: EVENT_NAMES.IMPRESSION, - schema: subscriptionContextSchema, - }); - - analyticsClient.registerEventType({ - eventType: EVENT_NAMES.CLICK, - schema: subscriptionContextSchema, - }); -} diff --git a/packages/kbn-subscription-tracking/src/subscription_elements.test.tsx b/packages/kbn-subscription-tracking/src/subscription_elements.test.tsx deleted file mode 100644 index 1795bbf42dd0..000000000000 --- a/packages/kbn-subscription-tracking/src/subscription_elements.test.tsx +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import { - SubscriptionLink, - SubscriptionButton, - SubscriptionButtonEmpty, -} from './subscription_elements'; -import { SubscriptionTrackingProvider } from './services'; -import { EVENT_NAMES, Services, SubscriptionContextData } from '../types'; -import { coolDownTimeMs, resetCoolDown } from './use_impression'; - -const testServices: Services = { - navigateToApp: jest.fn(), - analyticsClient: { - reportEvent: jest.fn(), - registerEventType: jest.fn(), - } as any, -}; -const testContext: SubscriptionContextData = { feature: 'test', source: 'security__test' }; - -const WithProviders: React.FC = ({ children }) => ( - - {children} - -); - -const renderWithProviders = (children: React.ReactElement) => - render(children, { wrapper: WithProviders }); - -const reset = () => { - jest.resetAllMocks(); - resetCoolDown(); -}; - -describe('SubscriptionElements', () => { - beforeAll(() => { - jest.useFakeTimers(); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - [SubscriptionButton, SubscriptionLink, SubscriptionButtonEmpty].forEach((SubscriptionElement) => { - describe(SubscriptionElement.name, () => { - beforeEach(reset); - - it('renders the children correctly', () => { - renderWithProviders( - Hello - ); - expect(screen.getByText('Hello')).toBeTruthy(); - }); - - it('fires an impression event when rendered', () => { - renderWithProviders(); - expect(testServices.analyticsClient.reportEvent).toHaveBeenCalledWith( - EVENT_NAMES.IMPRESSION, - testContext - ); - }); - - it('fires an impression event when rendered (but only once)', () => { - const { unmount } = renderWithProviders( - - ); - expect(testServices.analyticsClient.reportEvent).toHaveBeenCalledTimes(1); - unmount(); - - // does not create an impression again when remounted - const { unmount: unmountAgain } = renderWithProviders( - - ); - unmountAgain(); - expect(testServices.analyticsClient.reportEvent).toHaveBeenCalledTimes(1); - - // only creates anew impression when the cooldown time has passed - jest.setSystemTime(Date.now() + coolDownTimeMs); - renderWithProviders(); - expect(testServices.analyticsClient.reportEvent).toHaveBeenCalledTimes(2); - }); - - it('tracks a click when clicked and navigates to page', () => { - renderWithProviders( - hello - ); - - screen.getByText('hello').click(); - expect(testServices.analyticsClient.reportEvent).toHaveBeenCalledWith( - EVENT_NAMES.CLICK, - testContext - ); - expect(testServices.navigateToApp).toHaveBeenCalled(); - }); - }); - }); -}); diff --git a/packages/kbn-subscription-tracking/src/subscription_elements.tsx b/packages/kbn-subscription-tracking/src/subscription_elements.tsx deleted file mode 100644 index f29c58d8a0a4..000000000000 --- a/packages/kbn-subscription-tracking/src/subscription_elements.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { EuiLink, EuiButton, EuiButtonEmpty } from '@elastic/eui'; -import type { EuiLinkProps, EuiButtonEmptyProps, EuiButtonProps } from '@elastic/eui'; -import { useGoToSubscription } from './use_go_to_subscription'; -import { useImpression } from './use_impression'; -import type { SubscriptionContextData } from '../types'; - -interface CommonProps { - /** The context information for this subscription element */ - subscriptionContext: SubscriptionContextData; -} - -export type SubscriptionLinkProps = EuiLinkProps & CommonProps; - -/** - * Wrapper around `EuiLink` that provides subscription events - */ -export function SubscriptionLink({ - subscriptionContext, - children, - ...restProps -}: SubscriptionLinkProps) { - const goToSubscription = useGoToSubscription({ subscriptionContext }); - useImpression(subscriptionContext); - - return ( - - {children} - - ); -} - -export type SubscriptionButtonProps = EuiButtonProps & CommonProps; - -/** - * Wrapper around `EuiButton` that provides subscription events - */ -export function SubscriptionButton({ - subscriptionContext, - children, - ...restProps -}: SubscriptionButtonProps) { - const goToSubscription = useGoToSubscription({ subscriptionContext }); - useImpression(subscriptionContext); - - return ( - - {children} - - ); -} - -export type SubscriptionButtonEmptyProps = EuiButtonEmptyProps & CommonProps; - -/** - * Wrapper around `EuiButtonEmpty` that provides subscription events - */ -export function SubscriptionButtonEmpty({ - subscriptionContext, - children, - ...restProps -}: SubscriptionButtonEmptyProps) { - const goToSubscription = useGoToSubscription({ subscriptionContext }); - useImpression(subscriptionContext); - - return ( - - {children} - - ); -} diff --git a/packages/kbn-subscription-tracking/src/use_go_to_subscription.ts b/packages/kbn-subscription-tracking/src/use_go_to_subscription.ts deleted file mode 100644 index 6c93fb27ee9b..000000000000 --- a/packages/kbn-subscription-tracking/src/use_go_to_subscription.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -import { useCallback } from 'react'; -import { isValidContext } from './helpers'; -import { useServices } from './services'; -import { EVENT_NAMES, SubscriptionContextData } from '../types'; - -interface Options { - subscriptionContext: SubscriptionContextData; -} - -/** - * Provides a navigation function that navigates to the subscription - * management page. When the function executes, a click event with the - * given context is emitted. - */ -export const useGoToSubscription = ({ subscriptionContext }: Options) => { - const { navigateToApp, analyticsClient } = useServices(); - const goToSubscription = useCallback(() => { - if (isValidContext(subscriptionContext)) { - analyticsClient.reportEvent(EVENT_NAMES.CLICK, subscriptionContext); - } else { - // eslint-disable-next-line no-console - console.error('The provided subscription context is invalid', subscriptionContext); - } - navigateToApp('management', { path: 'stack/license_management' }); - }, [analyticsClient, navigateToApp, subscriptionContext]); - - return goToSubscription; -}; diff --git a/packages/kbn-subscription-tracking/src/use_impression.ts b/packages/kbn-subscription-tracking/src/use_impression.ts deleted file mode 100644 index eb8aa4c2e0ec..000000000000 --- a/packages/kbn-subscription-tracking/src/use_impression.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { useEffect } from 'react'; -import { isValidContext } from './helpers'; -import { useServices } from './services'; -import { EVENT_NAMES, SubscriptionContextData } from '../types'; - -/** - * Sends an impression event with the given context. - * - * Note: impression events are throttled and will not fire more - * often than once every 30 seconds. - */ -export const useImpression = (context: SubscriptionContextData) => { - const { analyticsClient } = useServices(); - - useEffect(() => { - if (!isValidContext(context)) { - // eslint-disable-next-line no-console - console.error('The provided subscription context is invalid', context); - return; - } - if (!isCoolingDown(context)) { - analyticsClient.reportEvent(EVENT_NAMES.IMPRESSION, context); - coolDown(context); - } - }, [analyticsClient, context]); -}; - -/** - * Impressions from the same context should not fire more than once every 30 seconds. - * This prevents logging too many impressions in case a page is reloaded often or - * if the user is navigating back and forth rapidly. - */ -export const coolDownTimeMs = 30 * 1000; -let impressionCooldown = new WeakMap(); - -function isCoolingDown(context: SubscriptionContextData) { - const previousLog = impressionCooldown.get(context); - - // we logged before and we are in the cooldown period - return previousLog && Date.now() - previousLog < coolDownTimeMs; -} - -function coolDown(context: SubscriptionContextData) { - impressionCooldown.set(context, Date.now()); -} - -export function resetCoolDown() { - impressionCooldown = new WeakMap(); -} diff --git a/packages/kbn-subscription-tracking/tsconfig.json b/packages/kbn-subscription-tracking/tsconfig.json deleted file mode 100644 index 677e9db998bb..000000000000 --- a/packages/kbn-subscription-tracking/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": ["jest", "node", "react"] - }, - "include": ["**/*.ts", "**/*.tsx"], - "exclude": ["target/**/*"], - "kbn_references": ["@kbn/analytics-client"] -} diff --git a/packages/kbn-subscription-tracking/types.ts b/packages/kbn-subscription-tracking/types.ts deleted file mode 100644 index a2adf0c6d90c..000000000000 --- a/packages/kbn-subscription-tracking/types.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -import type { AnalyticsClient } from '@kbn/analytics-client'; - -enum SolutionIdentifier { - observability = 'observability', - security = 'security', -} -type LocationString = string; -type SourceIdentifier = `${SolutionIdentifier}__${LocationString}`; -/** - * A piece of metadata which consists of an identifier of the advertised feature and - * the `source` (e.g. location) of the subscription element. - */ -export interface SubscriptionContextData { - /** - * A human-readable identifier describing the location of the beginning of the - * subscription flow. - * Location identifiers are prefixed with a solution identifier, e.g. `security__` - * - * @example "security__host-overview" - the user is looking at an upsell button - * on the host overview page in the security solution - */ - source: SourceIdentifier; - - /** - * A human-readable identifier describing the feature that is being promoted. - * - * @example "alerts-by-process-ancestry" - */ - feature: string; -} - -export interface Services { - navigateToApp: (app: string, options: { path: string }) => void; - analyticsClient: Pick; -} - -export enum EVENT_NAMES { - CLICK = 'subscription__upsell__click', - IMPRESSION = 'subscription__upsell__impression', -} diff --git a/packages/kbn-test/src/es/test_es_cluster.ts b/packages/kbn-test/src/es/test_es_cluster.ts index 461ad2b6f0df..84c2da1e52f8 100644 --- a/packages/kbn-test/src/es/test_es_cluster.ts +++ b/packages/kbn-test/src/es/test_es_cluster.ts @@ -71,7 +71,10 @@ export interface CreateTestEsClusterOptions { */ esArgs?: string[]; esFrom?: string; - esServerlessOptions?: Pick; + esServerlessOptions?: Pick< + ServerlessOptions, + 'image' | 'tag' | 'resources' | 'host' | 'kibanaUrl' + >; esJavaOpts?: string; /** * License to run your cluster under. Keep in mind that a `trial` license @@ -242,10 +245,7 @@ export function createTestEsCluster< await firstNode.runServerless({ basePath, esArgs: customEsArgs, - image: esServerlessOptions?.image, - tag: esServerlessOptions?.tag, - host: esServerlessOptions?.host, - resources: esServerlessOptions?.resources, + ...esServerlessOptions, port, clean: true, background: true, diff --git a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts index 742f729745d2..4f01321b8239 100644 --- a/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts +++ b/packages/kbn-test/src/functional_tests/lib/run_elasticsearch.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import Url from 'url'; import { resolve } from 'path'; import type { ToolingLog } from '@kbn/tooling-log'; import getPort from 'get-port'; @@ -160,7 +161,18 @@ async function startEsNode({ return cluster; } -function getESServerlessOptions(esServerlessImageFromArg: string | undefined, config: Config) { +interface EsServerlessOptions { + host?: string; + resources: string[]; + kibanaUrl: string; + tag?: string; + image?: string; +} + +function getESServerlessOptions( + esServerlessImageFromArg: string | undefined, + config: Config +): EsServerlessOptions { const esServerlessImageUrlOrTag = esServerlessImageFromArg || esTestConfig.getESServerlessImage() || @@ -172,24 +184,24 @@ function getESServerlessOptions(esServerlessImageFromArg: string | undefined, co const serverlessHost: string | undefined = config.has('esServerlessOptions.host') && config.get('esServerlessOptions.host'); + const commonOptions = { + host: serverlessHost, + resources: serverlessResources, + kibanaUrl: Url.format({ + protocol: config.get('servers.kibana.protocol'), + hostname: config.get('servers.kibana.hostname'), + port: config.get('servers.kibana.port'), + }), + }; + if (esServerlessImageUrlOrTag) { - if (esServerlessImageUrlOrTag.includes(':')) { - return { - resources: serverlessResources, - image: esServerlessImageUrlOrTag, - host: serverlessHost, - }; - } else { - return { - resources: serverlessResources, - tag: esServerlessImageUrlOrTag, - host: serverlessHost, - }; - } + return { + ...commonOptions, + ...(esServerlessImageUrlOrTag.includes(':') + ? { image: esServerlessImageUrlOrTag } + : { tag: esServerlessImageUrlOrTag }), + }; } - return { - resources: serverlessResources, - host: serverlessHost, - }; + return commonOptions; } diff --git a/packages/kbn-test/src/jest/mocks/apm_agent_mock.ts b/packages/kbn-test/src/jest/mocks/apm_agent_mock.ts index 17bb9f190646..d44770d2f209 100644 --- a/packages/kbn-test/src/jest/mocks/apm_agent_mock.ts +++ b/packages/kbn-test/src/jest/mocks/apm_agent_mock.ts @@ -38,6 +38,9 @@ const agent: jest.Mocked = { start: jest.fn().mockImplementation(() => agent), isStarted: jest.fn().mockReturnValue(false), getServiceName: jest.fn().mockReturnValue('mock-service'), + getServiceVersion: jest.fn().mockReturnValue('1.0'), + getServiceEnvironment: jest.fn().mockReturnValue('env'), + getServiceNodeName: jest.fn().mockReturnValue('mock-node-name'), setFramework: jest.fn(), addPatch: jest.fn(), removePatch: jest.fn(), diff --git a/packages/kbn-text-based-editor/src/editor_footer.tsx b/packages/kbn-text-based-editor/src/editor_footer.tsx index 5070e2d5789e..6bc663713a8d 100644 --- a/packages/kbn-text-based-editor/src/editor_footer.tsx +++ b/packages/kbn-text-based-editor/src/editor_footer.tsx @@ -19,6 +19,9 @@ import { EuiPopoverTitle, EuiDescriptionList, EuiDescriptionListDescription, + EuiButton, + useEuiTheme, + EuiLink, } from '@elastic/eui'; import { Interpolation, Theme, css } from '@emotion/react'; import { css as classNameCss } from '@emotion/css'; @@ -27,6 +30,7 @@ import type { MonacoError } from './helpers'; const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0; const COMMAND_KEY = isMac ? '⌘' : '^'; +const FEEDBACK_LINK = 'https://ela.st/esql-feedback'; const getConstsByType = (type: 'error' | 'warning', count: number) => { if (type === 'error') { @@ -54,18 +58,51 @@ const getConstsByType = (type: 'error' | 'warning', count: number) => { } }; +export function SubmitFeedbackComponent({ isSpaceReduced }: { isSpaceReduced?: boolean }) { + const { euiTheme } = useEuiTheme(); + return ( + <> + + + + + + {isSpaceReduced + ? i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.feedback', { + defaultMessage: 'Feedback', + }) + : i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.submitFeedback', { + defaultMessage: 'Submit feedback', + })} + + + + ); +} + export function ErrorsWarningsPopover({ isPopoverOpen, items, type, setIsPopoverOpen, onErrorClick, + isSpaceReduced, }: { isPopoverOpen: boolean; items: MonacoError[]; type: 'error' | 'warning'; setIsPopoverOpen: (flag: boolean) => void; onErrorClick: (error: MonacoError) => void; + isSpaceReduced?: boolean; }) { const strings = getConstsByType(type, items.length); return ( @@ -90,7 +127,7 @@ export function ErrorsWarningsPopover({ setIsPopoverOpen(!isPopoverOpen); }} > -

    {strings.message}

    +

    {isSpaceReduced ? items.length : strings.message}

    } ownFocus={false} @@ -151,8 +188,11 @@ interface EditorFooterProps { warning?: MonacoError[]; detectTimestamp: boolean; onErrorClick: (error: MonacoError) => void; - refreshErrors: () => void; + runQuery: () => void; hideRunQueryText?: boolean; + disableSubmitAction?: boolean; + editorIsInline?: boolean; + isSpaceReduced?: boolean; } export const EditorFooter = memo(function EditorFooter({ @@ -162,10 +202,15 @@ export const EditorFooter = memo(function EditorFooter({ warning, detectTimestamp, onErrorClick, - refreshErrors, + runQuery, hideRunQueryText, + disableSubmitAction, + editorIsInline, + isSpaceReduced, }: EditorFooterProps) { + const { euiTheme } = useEuiTheme(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); + return ( + + +

    + {i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.lineCount', { + defaultMessage: '{count} {count, plural, one {line} other {lines}}', + values: { count: lines }, + })} +

    +
    +
    + {/* If there is no space and no @timestamp detected hide the information */} + {(detectTimestamp || !isSpaceReduced) && ( + + + + +

    + {isSpaceReduced + ? '@timestamp' + : detectTimestamp + ? i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.timestampDetected', + { + defaultMessage: '@timestamp found', + } + ) + : i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected', + { + defaultMessage: '@timestamp not found', + } + )} +

    +
    +
    +
    +
    + )} {errors && errors.length > 0 && ( )} {warning && warning.length > 0 && ( @@ -192,49 +276,15 @@ export const EditorFooter = memo(function EditorFooter({ type="warning" setIsPopoverOpen={setIsPopoverOpen} onErrorClick={onErrorClick} + isSpaceReduced={isSpaceReduced} /> )} - - -

    - {i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.lineCount', { - defaultMessage: '{count} {count, plural, one {line} other {lines}}', - values: { count: lines }, - })} -

    -
    -
    - - - - - - - -

    - {detectTimestamp - ? i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.timestampDetected', - { - defaultMessage: '@timestamp detected', - } - ) - : i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected', - { - defaultMessage: '@timestamp not detected', - } - )} -

    -
    -
    -
    -
    {!hideRunQueryText && ( +

    @@ -255,6 +305,63 @@ export const EditorFooter = memo(function EditorFooter({ )} + {Boolean(editorIsInline) && ( + <> + + + + + + + + {isSpaceReduced + ? i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.run', { + defaultMessage: 'Run', + }) + : i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.runQuery', + { + defaultMessage: 'Run query', + } + )} + + + + {COMMAND_KEY}⏎ + + + + + + + + + )} ); }); diff --git a/packages/kbn-text-based-editor/src/resizable_button.tsx b/packages/kbn-text-based-editor/src/resizable_button.tsx index fb4ee944bc2f..5a52d67780ca 100644 --- a/packages/kbn-text-based-editor/src/resizable_button.tsx +++ b/packages/kbn-text-based-editor/src/resizable_button.tsx @@ -13,11 +13,13 @@ import { css } from '@emotion/react'; export function ResizableButton({ onMouseDownResizeHandler, onKeyDownResizeHandler, + editorIsInline, }: { onMouseDownResizeHandler: ( mouseDownEvent: React.MouseEvent | React.TouchEvent ) => void; onKeyDownResizeHandler: (keyDownEvernt: React.KeyboardEvent) => void; + editorIsInline?: boolean; }) { return ( { let position = isCompactFocused ? ('absolute' as 'absolute') : ('relative' as 'relative'); // cast string to type 'relative' | 'absolute' if (isCodeEditorExpanded) { @@ -33,7 +34,9 @@ export const textBasedLanguagedEditorStyles = ( zIndex: isCompactFocused ? 4 : 0, height: `${editorHeight}px`, border: isCompactFocused ? euiTheme.border.thin : 'none', - borderTopLeftRadius: isCodeEditorExpanded ? 0 : '6px', + borderLeft: editorIsInline || !isCompactFocused ? 'none' : euiTheme.border.thin, + borderRight: editorIsInline || !isCompactFocused ? 'none' : euiTheme.border.thin, + borderTopLeftRadius: isCodeEditorExpanded ? 0 : euiTheme.border.radius.medium, borderBottom: isCodeEditorExpanded ? 'none' : isCompactFocused @@ -45,8 +48,8 @@ export const textBasedLanguagedEditorStyles = ( width: isCodeEditorExpanded ? '100%' : `calc(100% - ${hasReference ? 80 : 40}px)`, alignItems: isCompactFocused ? 'flex-start' : 'center', border: !isCompactFocused ? euiTheme.border.thin : 'none', - borderTopLeftRadius: '6px', - borderBottomLeftRadius: '6px', + borderTopLeftRadius: euiTheme.border.radius.medium, + borderBottomLeftRadius: euiTheme.border.radius.medium, borderBottomWidth: hasErrors ? '2px' : '1px', borderBottomColor: hasErrors ? euiTheme.colors.danger : euiTheme.colors.lightShade, }, @@ -66,6 +69,8 @@ export const textBasedLanguagedEditorStyles = ( }, bottomContainer: { border: euiTheme.border.thin, + borderLeft: editorIsInline ? 'none' : euiTheme.border.thin, + borderRight: editorIsInline ? 'none' : euiTheme.border.thin, borderTop: isCodeEditorExpanded && !isCodeEditorExpandedFocused ? hasErrors @@ -75,29 +80,29 @@ export const textBasedLanguagedEditorStyles = ( backgroundColor: euiTheme.colors.lightestShade, paddingLeft: euiTheme.size.base, paddingRight: euiTheme.size.base, - paddingTop: euiTheme.size.xs, - paddingBottom: euiTheme.size.xs, + paddingTop: editorIsInline ? euiTheme.size.s : euiTheme.size.xs, + paddingBottom: editorIsInline ? euiTheme.size.s : euiTheme.size.xs, width: 'calc(100% + 2px)', position: 'relative' as 'relative', // cast string to type 'relative', marginTop: 0, marginLeft: 0, marginBottom: 0, - borderBottomLeftRadius: '6px', - borderBottomRightRadius: '6px', + borderBottomLeftRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, + borderBottomRightRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, }, topContainer: { - border: euiTheme.border.thin, - borderTopLeftRadius: '6px', - borderTopRightRadius: '6px', + border: editorIsInline ? 'none' : euiTheme.border.thin, + borderTopLeftRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, + borderTopRightRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, backgroundColor: euiTheme.colors.lightestShade, paddingLeft: euiTheme.size.base, paddingRight: euiTheme.size.base, - paddingTop: euiTheme.size.xs, - paddingBottom: euiTheme.size.xs, + paddingTop: editorIsInline ? euiTheme.size.s : euiTheme.size.xs, + paddingBottom: editorIsInline ? euiTheme.size.s : euiTheme.size.xs, width: 'calc(100% + 2px)', position: 'relative' as 'relative', // cast string to type 'relative', marginLeft: 0, - marginTop: euiTheme.size.s, + marginTop: editorIsInline ? 0 : euiTheme.size.s, }, dragResizeContainer: { width: '100%', diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx index 0be4c38eed74..0f9ed5c6cb9c 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx @@ -69,46 +69,49 @@ describe('TextBasedLanguagesEditor', () => { }; }); it('should render the editor component', async () => { - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); - expect(component.find('[data-test-subj="TextBasedLangEditor"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); + expect(component.find('[data-test-subj="TextBasedLangEditor"]').length).not.toBe(0); }); it('should render the lines badge for the inline mode by default', async () => { - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-lines-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-lines-badge"]').length + ).not.toBe(0); }); - it('should render the date info with no @timestamp detected', async () => { + it('should render the date info with no @timestamp found', async () => { const newProps = { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() - ).toStrictEqual('@timestamp not detected'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() + ).toStrictEqual('@timestamp not found'); }); - it('should render the date info with @timestamp detected if detectTimestamp is true', async () => { + it('should render the feedback link', async () => { + const newProps = { + ...props, + isCodeEditorExpanded: true, + }; + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-feedback-link"]').length).not.toBe( + 0 + ); + }); + + it('should render the date info with @timestamp found if detectTimestamp is true', async () => { const newProps = { ...props, isCodeEditorExpanded: true, detectTimestamp: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() - ).toStrictEqual('@timestamp detected'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-date-info"]').at(0).text() + ).toStrictEqual('@timestamp found'); }); it('should render the errors badge for the inline mode by default if errors are provides', async () => { @@ -116,12 +119,10 @@ describe('TextBasedLanguagesEditor', () => { ...props, errors: [new Error('error1')], }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-errors-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-errors-badge"]').length + ).not.toBe(0); }); it('should render the warnings badge for the inline mode by default if warning are provides', async () => { @@ -129,12 +130,10 @@ describe('TextBasedLanguagesEditor', () => { ...props, warning: 'Line 1: 20: Warning', }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-warning-badge"]').length - ).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect( + component.find('[data-test-subj="TextBasedLangEditor-inline-warning-badge"]').length + ).not.toBe(0); }); it('should render the correct buttons for the inline code editor mode', async () => { @@ -156,11 +155,9 @@ describe('TextBasedLanguagesEditor', () => { ...props, expandCodeEditor: expandCodeEditorSpy, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - findTestSubject(component, 'TextBasedLangEditor-expand').simulate('click'); - expect(expandCodeEditorSpy).toHaveBeenCalled(); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + findTestSubject(component, 'TextBasedLangEditor-expand').simulate('click'); + expect(expandCodeEditorSpy).toHaveBeenCalled(); }); it('should render the correct buttons for the expanded code editor mode', async () => { @@ -211,11 +208,9 @@ describe('TextBasedLanguagesEditor', () => { isCodeEditorExpanded: true, expandCodeEditor: expandCodeEditorSpy, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - findTestSubject(component, 'TextBasedLangEditor-minimize').simulate('click'); - expect(expandCodeEditorSpy).toHaveBeenCalled(); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + findTestSubject(component, 'TextBasedLangEditor-minimize').simulate('click'); + expect(expandCodeEditorSpy).toHaveBeenCalled(); }); it('should render the resize for the expanded code editor mode', async () => { @@ -223,10 +218,8 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-resize"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-resize"]').length).not.toBe(0); }); it('should render the footer for the expanded code editor mode', async () => { @@ -234,13 +227,11 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-footer"]').length).not.toBe(0); - expect( - component.find('[data-test-subj="TextBasedLangEditor-footer-lines"]').at(0).text() - ).toBe('1 line'); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-footer"]').length).not.toBe(0); + expect(component.find('[data-test-subj="TextBasedLangEditor-footer-lines"]').at(0).text()).toBe( + '1 line' + ); }); it('should render the run query text', async () => { @@ -248,10 +239,8 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).not.toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).not.toBe(0); }); it('should not render the run query text if the hideRunQueryText prop is set to true', async () => { @@ -260,9 +249,25 @@ describe('TextBasedLanguagesEditor', () => { isCodeEditorExpanded: true, hideRunQueryText: true, }; - await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); - expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); - }); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); + }); + + it('should render correctly if editorIsInline prop is set to true', async () => { + const onTextLangQuerySubmit = jest.fn(); + const newProps = { + ...props, + isCodeEditorExpanded: true, + hideRunQueryText: true, + editorIsInline: true, + onTextLangQuerySubmit, + }; + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + expect(component.find('[data-test-subj="TextBasedLangEditor-run-query"]').length).toBe(0); + expect( + component.find('[data-test-subj="TextBasedLangEditor-run-query-button"]').length + ).not.toBe(1); + findTestSubject(component, 'TextBasedLangEditor-run-query-button').simulate('click'); + expect(onTextLangQuerySubmit).toHaveBeenCalled(); }); }); diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 312d08cadf0c..9d175ef86ecf 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -65,19 +65,43 @@ import { fetchFieldsFromESQL } from './fetch_fields_from_esql'; import './overwrite.scss'; export interface TextBasedLanguagesEditorProps { + /** The aggregate type query */ query: AggregateQuery; + /** Callback running everytime the query changes */ onTextLangQueryChange: (query: AggregateQuery) => void; - onTextLangQuerySubmit: () => void; + /** Callback running when the user submits the query */ + onTextLangQuerySubmit: (query?: AggregateQuery) => void; + /** Can be used to expand/minimize the editor */ expandCodeEditor: (status: boolean) => void; + /** If it is true, the editor initializes with height EDITOR_INITIAL_HEIGHT_EXPANDED */ isCodeEditorExpanded: boolean; + /** If it is true, the editor displays the message @timestamp found + * The text based queries are relying on adhoc dataviews which + * can have an @timestamp timefield or nothing + */ detectTimestamp?: boolean; + /** Array of errors */ errors?: Error[]; + /** Warning string as it comes from ES */ warning?: string; + /** Disables the editor */ isDisabled?: boolean; + /** Indicator if the editor is on dark mode */ isDarkMode?: boolean; dataTestSubj?: string; + /** If true it hides the minimize button and the user can't return to the minimized version + * Useful when the application doesn't want to give this capability + */ hideMinimizeButton?: boolean; + /** Hide the Run query information which appears on the footer*/ hideRunQueryText?: boolean; + /** This is used for applications (such as the inline editing flyout in dashboards) + * which want to add the editor without being part of the Unified search component + * It renders a submit query button inside the editor + */ + editorIsInline?: boolean; + /** Disables the submit query action*/ + disableSubmitAction?: boolean; } interface TextBasedEditorDeps { @@ -94,6 +118,9 @@ const EDITOR_ONE_LINER_UNUSED_SPACE_WITH_ERRORS = 220; const KEYCODE_ARROW_UP = 38; const KEYCODE_ARROW_DOWN = 40; +// for editor width smaller than this value we want to start hiding some text +const BREAKPOINT_WIDTH = 540; + const languageId = (language: string) => { switch (language) { case 'esql': { @@ -125,6 +152,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ isDarkMode, hideMinimizeButton, hideRunQueryText, + editorIsInline, + disableSubmitAction, dataTestSubj, }: TextBasedLanguagesEditorProps) { const { euiTheme } = useEuiTheme(); @@ -137,6 +166,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const [editorHeight, setEditorHeight] = useState( isCodeEditorExpanded ? EDITOR_INITIAL_HEIGHT_EXPANDED : EDITOR_INITIAL_HEIGHT ); + const [isSpaceReduced, setIsSpaceReduced] = useState(false); const [showLineNumbers, setShowLineNumbers] = useState(isCodeEditorExpanded); const [isCompactFocused, setIsCompactFocused] = useState(isCodeEditorExpanded); const [isCodeEditorExpandedFocused, setIsCodeEditorExpandedFocused] = useState(false); @@ -166,7 +196,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ Boolean(errors?.length), Boolean(warning), isCodeEditorExpandedFocused, - Boolean(documentationSections) + Boolean(documentationSections), + Boolean(editorIsInline) ); const isDark = isDarkMode; const editorModel = useRef(); @@ -216,6 +247,11 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ [editorHeight] ); + const onQuerySubmit = useCallback(() => { + const currentValue = editor1.current?.getValue(); + onTextLangQuerySubmit({ [language]: currentValue } as AggregateQuery); + }, [language, onTextLangQuerySubmit]); + const restoreInitialMode = () => { setIsCodeEditorExpandedFocused(false); if (isCodeEditorExpanded) return; @@ -355,6 +391,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ }, [code, isCodeEditorExpanded, isWordWrapped]); const onResize = ({ width }: { width: number }) => { + setIsSpaceReduced(Boolean(editorIsInline && width < BREAKPOINT_WIDTH)); calculateVisibleCode(width); if (editor1.current) { editor1.current.layout({ width, height: editorHeight }); @@ -514,6 +551,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ { expandCodeEditor(false); updateLinesFromModel = false; @@ -582,8 +621,10 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ )}

    @@ -782,6 +826,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ language={ String(language) === 'esql' ? 'ES|QL' : String(language).toUpperCase() } + searchInDescription sections={documentationSections} buttonProps={{ display: 'empty', @@ -816,15 +861,19 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ errors={editorErrors} warning={editorWarning} onErrorClick={onErrorClick} - refreshErrors={onTextLangQuerySubmit} + runQuery={onQuerySubmit} detectTimestamp={detectTimestamp} hideRunQueryText={hideRunQueryText} + editorIsInline={editorIsInline} + disableSubmitAction={disableSubmitAction} + isSpaceReduced={isSpaceReduced} /> )} {isCodeEditorExpanded && ( )} diff --git a/packages/kbn-ui-actions-browser/index.ts b/packages/kbn-ui-actions-browser/index.ts index 9662013cf99e..076b77680826 100644 --- a/packages/kbn-ui-actions-browser/index.ts +++ b/packages/kbn-ui-actions-browser/index.ts @@ -15,7 +15,5 @@ export { visualizeGeoFieldTrigger, ROW_CLICK_TRIGGER, rowClickTrigger, - CATEGORIZE_FIELD_TRIGGER, - categorizeFieldTrigger, defaultTrigger, } from './src/triggers'; diff --git a/packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts b/packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts deleted file mode 100644 index a332a21acb43..000000000000 --- a/packages/kbn-ui-actions-browser/src/triggers/categorize_field_trigger.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { Trigger } from './trigger'; - -export const CATEGORIZE_FIELD_TRIGGER = 'CATEGORIZE_FIELD_TRIGGER'; -export const categorizeFieldTrigger: Trigger = { - id: CATEGORIZE_FIELD_TRIGGER, - title: 'Run pattern analysis', - description: 'Triggered when user wants to run pattern analysis on a field.', -}; diff --git a/packages/kbn-ui-actions-browser/src/triggers/index.ts b/packages/kbn-ui-actions-browser/src/triggers/index.ts index 433a9cd6dff4..091305791d85 100644 --- a/packages/kbn-ui-actions-browser/src/triggers/index.ts +++ b/packages/kbn-ui-actions-browser/src/triggers/index.ts @@ -11,4 +11,3 @@ export * from './row_click_trigger'; export * from './default_trigger'; export * from './visualize_field_trigger'; export * from './visualize_geo_field_trigger'; -export * from './categorize_field_trigger'; diff --git a/packages/kbn-unified-data-table/__mocks__/data_view_without_timefield.ts b/packages/kbn-unified-data-table/__mocks__/data_view_without_timefield.ts new file mode 100644 index 000000000000..cc07103a5448 --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/data_view_without_timefield.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; + +const fields = [ + { + name: '_index', + type: 'string', + scripted: false, + filterable: true, + }, + { + name: 'timestamp', + displayName: 'timestamp', + type: 'date', + scripted: false, + filterable: true, + aggregatable: true, + sortable: true, + }, + { + name: 'message', + displayName: 'message', + type: 'string', + scripted: false, + filterable: false, + }, + { + name: 'extension', + displayName: 'extension', + type: 'string', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'scripted', + displayName: 'scripted', + type: 'number', + scripted: true, + filterable: false, + }, +] as DataView['fields']; + +export const dataViewWithoutTimefieldMock = buildDataViewMock({ + name: 'index-pattern-without-timefield', + fields, + timeFieldName: undefined, +}); diff --git a/packages/kbn-unified-data-table/src/components/data_table.test.tsx b/packages/kbn-unified-data-table/src/components/data_table.test.tsx index 0d5f858bd357..f898c4707717 100644 --- a/packages/kbn-unified-data-table/src/components/data_table.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.test.tsx @@ -300,6 +300,54 @@ describe('UnifiedDataTable', () => { } `); }); + + it('should apply sorting', async () => { + const component = await getComponent({ + ...getProps(), + sort: [['message', 'desc']], + columns: ['message'], + }); + + expect(component.find(EuiDataGrid).prop('sorting')).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "direction": "desc", + "id": "message", + }, + ], + "onSort": [Function], + } + `); + }); + + it('should not apply unknown sorting', async () => { + const component = await getComponent({ + ...getProps(), + sort: [ + ['bytes', 'desc'], + ['unknown', 'asc'], + ['message', 'desc'], + ], + columns: ['bytes', 'message'], + }); + + expect(component.find(EuiDataGrid).prop('sorting')).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "direction": "desc", + "id": "bytes", + }, + Object { + "direction": "desc", + "id": "message", + }, + ], + "onSort": [Function], + } + `); + }); }); describe('display settings', () => { diff --git a/packages/kbn-unified-data-table/src/components/data_table.tsx b/packages/kbn-unified-data-table/src/components/data_table.tsx index 4ce88e52e6c8..5e9168f62946 100644 --- a/packages/kbn-unified-data-table/src/components/data_table.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.tsx @@ -56,7 +56,12 @@ import { getDisplayedColumns } from '../utils/columns'; import { convertValueToString } from '../utils/convert_value_to_string'; import { getRowsPerPageOptions } from '../utils/rows_per_page'; import { getRenderCellValueFn } from '../utils/get_render_cell_value'; -import { getEuiGridColumns, getLeadControlColumns, getVisibleColumns } from './data_table_columns'; +import { + getEuiGridColumns, + getLeadControlColumns, + getVisibleColumns, + hasSourceTimeFieldValue, +} from './data_table_columns'; import { UnifiedDataTableContext } from '../table_context'; import { getSchemaDetectors } from './data_table_schema'; import { DataTableDocumentToolbarBtn } from './data_table_document_selection'; @@ -533,25 +538,6 @@ export const UnifiedDataTable = ({ ); }, [currentPageSize, setPagination]); - /** - * Sorting - */ - const sortingColumns = useMemo(() => sort.map(([id, direction]) => ({ id, direction })), [sort]); - - const [inmemorySortingColumns, setInmemorySortingColumns] = useState([]); - const onTableSort = useCallback( - (sortingColumnsData) => { - if (isSortEnabled) { - if (isPlainRecord) { - setInmemorySortingColumns(sortingColumnsData); - } else if (onSort) { - onSort(sortingColumnsData.map(({ id, direction }: SortObj) => [id, direction])); - } - } - }, - [onSort, isSortEnabled, isPlainRecord, setInmemorySortingColumns] - ); - const shouldShowFieldHandler = useMemo(() => { const dataViewFields = dataView.fields.getAll().map((fld) => fld.name); return getShouldShowFieldHandler(dataViewFields, dataView, showMultiFields); @@ -617,9 +603,15 @@ export const UnifiedDataTable = ({ [dataView, onFieldEdited, services.dataViewFieldEditor] ); + const shouldShowTimeField = useMemo( + () => + hasSourceTimeFieldValue(displayedColumns, dataView, columnTypes, showTimeCol, isPlainRecord), + [dataView, displayedColumns, isPlainRecord, showTimeCol, columnTypes] + ); + const visibleColumns = useMemo( - () => getVisibleColumns(displayedColumns, dataView, showTimeCol), - [dataView, displayedColumns, showTimeCol] + () => getVisibleColumns(displayedColumns, dataView, shouldShowTimeField), + [dataView, displayedColumns, shouldShowTimeField] ); const getCellValue = useCallback( @@ -709,6 +701,32 @@ export const UnifiedDataTable = ({ }), [visibleColumns, hideTimeColumn, onSetColumns] ); + + /** + * Sorting + */ + const sortingColumns = useMemo( + () => + sort + .map(([id, direction]) => ({ id, direction })) + .filter(({ id }) => visibleColumns.includes(id)), + [sort, visibleColumns] + ); + + const [inmemorySortingColumns, setInmemorySortingColumns] = useState([]); + const onTableSort = useCallback( + (sortingColumnsData) => { + if (isSortEnabled) { + if (isPlainRecord) { + setInmemorySortingColumns(sortingColumnsData); + } else if (onSort) { + onSort(sortingColumnsData.map(({ id, direction }: SortObj) => [id, direction])); + } + } + }, + [onSort, isSortEnabled, isPlainRecord, setInmemorySortingColumns] + ); + const sorting = useMemo(() => { if (isSortEnabled) { return { diff --git a/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx index 38cbdb5aeb63..e1d7082353e1 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx @@ -7,8 +7,14 @@ */ import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { getEuiGridColumns, getVisibleColumns } from './data_table_columns'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import { + getEuiGridColumns, + getVisibleColumns, + hasSourceTimeFieldValue, +} from './data_table_columns'; import { dataViewWithTimefieldMock } from '../../__mocks__/data_view_with_timefield'; +import { dataViewWithoutTimefieldMock } from '../../__mocks__/data_view_without_timefield'; import { dataTableContextMock } from '../../__mocks__/table_context'; import { servicesMock } from '../../__mocks__/services'; @@ -110,6 +116,133 @@ describe('Data table columns', function () { }); }); + describe('hasSourceTimeFieldValue', () => { + function buildColumnTypes(dataView: DataView) { + const columnTypes: Record = {}; + for (const field of dataView.fields) { + columnTypes[field.name] = ''; + } + return columnTypes; + } + + describe('dataView with timeField', () => { + it('should forward showTimeCol if no _source columns is passed', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['extension', 'message'], + dataViewWithTimefieldMock, + buildColumnTypes(dataViewWithTimefieldMock), + showTimeCol, + false + ) + ).toBe(showTimeCol); + } + }); + + it('should forward showTimeCol if no _source columns is passed, text-based datasource', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['extension', 'message'], + dataViewWithTimefieldMock, + buildColumnTypes(dataViewWithTimefieldMock), + showTimeCol, + true + ) + ).toBe(showTimeCol); + } + }); + + it('should forward showTimeCol if _source column is passed', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['_source'], + dataViewWithTimefieldMock, + buildColumnTypes(dataViewWithTimefieldMock), + showTimeCol, + false + ) + ).toBe(showTimeCol); + } + }); + + it('should return true if _source column is passed, text-based datasource', () => { + // ... | DROP @timestamp test case + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['_source'], + dataViewWithTimefieldMock, + buildColumnTypes(dataViewWithTimefieldMock), + showTimeCol, + true + ) + ).toBe(true); + } + }); + }); + + describe('dataView without timeField', () => { + it('should forward showTimeCol if no _source columns is passed', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['extension', 'message'], + dataViewWithoutTimefieldMock, + buildColumnTypes(dataViewWithoutTimefieldMock), + showTimeCol, + false + ) + ).toBe(showTimeCol); + } + }); + + it('should forward showTimeCol if no _source columns is passed, text-based datasource', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['extension', 'message'], + dataViewWithoutTimefieldMock, + buildColumnTypes(dataViewWithoutTimefieldMock), + showTimeCol, + true + ) + ).toBe(showTimeCol); + } + }); + + it('should forward showTimeCol if _source column is passed', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['_source'], + dataViewWithoutTimefieldMock, + buildColumnTypes(dataViewWithoutTimefieldMock), + showTimeCol, + false + ) + ).toBe(showTimeCol); + } + }); + + it('should return false if _source column is passed, text-based datasource', () => { + for (const showTimeCol of [true, false]) { + expect( + hasSourceTimeFieldValue( + ['_source'], + dataViewWithoutTimefieldMock, + buildColumnTypes(dataViewWithoutTimefieldMock), + showTimeCol, + true + ) + ).toBe(showTimeCol); + } + }); + }); + }); + describe('column tokens', () => { it('returns eui grid columns with tokens', async () => { const actual = getEuiGridColumns({ diff --git a/packages/kbn-unified-data-table/src/components/data_table_columns.tsx b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx index 274b1148df4e..f7a3d41bf330 100644 --- a/packages/kbn-unified-data-table/src/components/data_table_columns.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx @@ -267,6 +267,20 @@ export function getEuiGridColumns({ ); } +export function hasSourceTimeFieldValue( + columns: string[], + dataView: DataView, + columnTypes: DataTableColumnTypes | undefined, + showTimeCol: boolean, + isPlainRecord: boolean +) { + const timeFieldName = dataView.timeFieldName; + if (!isPlainRecord || !columns.includes('_source') || !timeFieldName || !columnTypes) { + return showTimeCol; + } + return timeFieldName in columnTypes; +} + export function getVisibleColumns(columns: string[], dataView: DataView, showTimeCol: boolean) { const timeFieldName = dataView.timeFieldName; diff --git a/packages/kbn-unified-doc-viewer/src/services/types.ts b/packages/kbn-unified-doc-viewer/src/services/types.ts index 071704e0559a..25493db97d09 100644 --- a/packages/kbn-unified-doc-viewer/src/services/types.ts +++ b/packages/kbn-unified-doc-viewer/src/services/types.ts @@ -36,6 +36,7 @@ export interface DocViewRenderProps { columnTypes?: Record; query?: Query | AggregateQuery; textBasedHits?: DataTableRecord[]; + hideActionsColumn?: boolean; filter?: DocViewFilterFn; onAddColumn?: (columnName: string) => void; onRemoveColumn?: (columnName: string) => void; diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts b/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts index afeb34e6572a..007a88b2c7f9 100644 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts +++ b/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import type { UiActionsStart, CategorizeFieldContext } from '@kbn/ui-actions-plugin/public'; -import { CATEGORIZE_FIELD_TRIGGER } from '@kbn/ui-actions-browser/src/triggers'; +import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { CATEGORIZE_FIELD_TRIGGER, type CategorizeFieldContext } from '@kbn/ml-ui-actions'; import type { DataViewField, DataView } from '@kbn/data-views-plugin/public'; async function getCompatibleActions( diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx b/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx index 4e0d00b4549c..45569b344337 100644 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx +++ b/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx @@ -14,9 +14,12 @@ import { stubLogstashDataView as dataView } from '@kbn/data-views-plugin/common/ import { ActionInternal } from '@kbn/ui-actions-plugin/public'; import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { getFieldCategorizeButton } from './field_categorize_button'; -import { ACTION_CATEGORIZE_FIELD, CategorizeFieldContext } from '@kbn/ui-actions-plugin/public'; +import { + CATEGORIZE_FIELD_TRIGGER, + ACTION_CATEGORIZE_FIELD, + type CategorizeFieldContext, +} from '@kbn/ml-ui-actions'; import { TriggerContract } from '@kbn/ui-actions-plugin/public/triggers'; -import { CATEGORIZE_FIELD_TRIGGER } from '@kbn/ui-actions-browser'; const ORIGINATING_APP = 'test'; const mockExecuteAction = jest.fn(); diff --git a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx index 4f5b71384b32..929627537bbb 100755 --- a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx +++ b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx @@ -270,7 +270,7 @@ const FieldStatsComponent: React.FC = ({ const [showingHistogram, setShowingHistogram] = useState(histogramDefault); if (isLoading) { - return ; + return ; } if (!dataView) { diff --git a/packages/kbn-unified-field-list/tsconfig.json b/packages/kbn-unified-field-list/tsconfig.json index 27cbb23cf3d7..eeca808e1bee 100644 --- a/packages/kbn-unified-field-list/tsconfig.json +++ b/packages/kbn-unified-field-list/tsconfig.json @@ -31,6 +31,7 @@ "@kbn/ebt-tools", "@kbn/shared-ux-button-toolbar", "@kbn/field-utils", + "@kbn/ml-ui-actions", ], "exclude": ["target/**/*"] } diff --git a/packages/kbn-url-state/README.md b/packages/kbn-url-state/README.md index e7b131e3743d..3549936888f9 100644 --- a/packages/kbn-url-state/README.md +++ b/packages/kbn-url-state/README.md @@ -1,45 +1,33 @@ # @kbn/url-state - utils for syncing state to URL -This package provides: +This package provides a React hook called `useUrlState` that can be used to synchronize state to the URL. This can be useful when you want to make a portion of state shareable. -- a React hook called `useSyncToUrl` that can be used to synchronize state to the URL. This can be useful when you want to make a portion of state shareable. - -## useSyncToUrl - -The `useSyncToUrl` hook takes three arguments: - -``` -key (string): The key to use in the URL to store the state. -restore (function): A function that is called with the deserialized value from the URL. You should use this function to update your state based on the value from the URL. -cleanupOnHistoryNavigation (optional boolean, default: true): If true, the hook will clear the URL state when the user navigates using the browser's history API. -``` +The state is grouped under a namespace, to avoid collisions. See the example url below for how it would look like. ### Example usage: ``` import React, { useState } from 'react'; -import { useSyncToUrl } from '@kbn/url-state'; +import { useUrlState } from '@kbn/url-state'; function MyComponent() { - const [count, setCount] = useState(0); - - useSyncToUrl('count', (value) => { - setCount(value); - }); + const [name, setName] = useUrlState('namespace','name'); const handleClick = () => { - setCount((prevCount) => prevCount + 1); + setName('John Doe') }; return (
    -

    Count: {count}

    - +

    Name: {name}

    +
    ); } ``` -In this example, the count state is synced to the URL using the `useSyncToUrl` hook. -Whenever the count state changes, the hook will update the URL with the new value. -When the user copies the updated url or refreshes the page, `restore` function will be called to update the count state. \ No newline at end of file +The resulting URL will look like this: + +``` +http://localhost:5601/?namespace=(name:John%20Doe) +``` diff --git a/packages/kbn-url-state/index.test.ts b/packages/kbn-url-state/index.test.ts index e2a85e58902f..7e646a387d24 100644 --- a/packages/kbn-url-state/index.test.ts +++ b/packages/kbn-url-state/index.test.ts @@ -7,8 +7,7 @@ */ import { renderHook, act } from '@testing-library/react-hooks'; -import { useSyncToUrl } from '.'; -import { encode } from '@kbn/rison'; +import { useUrlState } from '.'; describe('useSyncToUrl', () => { let originalLocation: Location; @@ -28,95 +27,70 @@ describe('useSyncToUrl', () => { window.history = { ...originalHistory, replaceState: jest.fn(), + pushState: jest.fn(), }; + + jest.useFakeTimers(); }); afterEach(() => { window.location = originalLocation; window.history = originalHistory; + jest.useRealTimers(); }); - it('should restore the value from the query string on mount', () => { - const key = 'testKey'; - const restoredValue = { test: 'value' }; - const encodedValue = encode(restoredValue); - const restore = jest.fn(); - - window.location.search = `?${key}=${encodedValue}`; - - renderHook(() => useSyncToUrl(key, restore)); - - expect(restore).toHaveBeenCalledWith(restoredValue); - }); - - it('should sync the value to the query string', () => { - const key = 'testKey'; - const valueToSerialize = { test: 'value' }; + it('should update the URL when the state changes', () => { + window.location.hash = '#should_be_there'; - const { result } = renderHook(() => useSyncToUrl(key, jest.fn())); + const { result } = renderHook(() => useUrlState('namespace', 'test')); act(() => { - result.current(valueToSerialize); + result.current[1]('foo'); + jest.runAllTimers(); }); - expect(window.history.replaceState).toHaveBeenCalledWith( - { path: expect.any(String) }, + expect(window.history.pushState).toHaveBeenCalledWith( + {}, '', - '/?testKey=%28test%3Avalue%29' + '#should_be_there?namespace=(test:foo)' ); }); - it('should should not alter the location hash', () => { - const key = 'testKey'; - const valueToSerialize = { test: 'value' }; + it('should remove the key from the namespace after undefined is passed (state clear mechanism)', () => { window.location.hash = '#should_be_there'; - const { result } = renderHook(() => useSyncToUrl(key, jest.fn())); + const { result } = renderHook(() => useUrlState('namespace', 'test')); act(() => { - result.current(valueToSerialize); + result.current[1](undefined); + jest.runAllTimers(); }); - expect(window.history.replaceState).toHaveBeenCalledWith( - { path: expect.any(String) }, - '', - '/#should_be_there?testKey=%28test%3Avalue%29' - ); + expect(window.history.pushState).toHaveBeenCalledWith({}, '', '#should_be_there?namespace=()'); }); - it('should clear the value from the query string on unmount', () => { - const key = 'testKey'; - - // Location should have a key to clear - window.location.search = `?${key}=${encode({ test: 'value' })}`; - - const { unmount } = renderHook(() => useSyncToUrl(key, jest.fn())); + it('should restore the value from the query string on mount', () => { + window.location.search = `?namespace=(test:foo)`; - act(() => { - unmount(); - }); + const { + result: { current: state }, + } = renderHook(() => useUrlState('namespace', 'test')); - expect(window.history.replaceState).toHaveBeenCalledWith( - { path: expect.any(String) }, - '', - expect.any(String) - ); + expect(state[0]).toEqual('foo'); }); - it('should clear the value from the query string when history back or forward is pressed', () => { - const key = 'testKey'; - const restore = jest.fn(); + it('should return updated state on browser navigation', () => { + window.location.search = '?namespace=(test:foo)'; - // Location should have a key to clear - window.location.search = `?${key}=${encode({ test: 'value' })}`; + const { result } = renderHook(() => useUrlState('namespace', 'test')); - renderHook(() => useSyncToUrl(key, restore, true)); + expect(result.current[0]).toEqual('foo'); act(() => { - window.dispatchEvent(new Event('popstate')); + window.location.search = '?namespace=(test:bar)'; + window.dispatchEvent(new CustomEvent('popstate')); }); - expect(window.history.replaceState).toHaveBeenCalledTimes(1); - expect(window.history.replaceState).toHaveBeenCalledWith({ path: expect.any(String) }, '', '/'); + expect(result.current[0]).toEqual('bar'); }); }); diff --git a/packages/kbn-url-state/index.ts b/packages/kbn-url-state/index.ts index 73568222fb4c..d165d75e1f95 100644 --- a/packages/kbn-url-state/index.ts +++ b/packages/kbn-url-state/index.ts @@ -6,4 +6,118 @@ * Side Public License, v 1. */ -export { useSyncToUrl } from './use_sync_to_url'; +import { useCallback, useEffect, useState } from 'react'; +import { encode, decode, RisonValue } from '@kbn/rison'; +import { stringify, parse } from 'query-string'; + +interface StateCache { + namespaces: Record>; + timeoutHandle: number; +} + +/** + * Temporary cache for state stored in the URL. This will be serialized to the URL + * in a single batched update to avoid excessive history entries. + */ +const cache: StateCache = { + namespaces: {}, + timeoutHandle: 0, +}; + +const CUSTOM_URL_EVENT = 'url:update' as const; + +// This is a list of events that can trigger a render. +const URL_CHANGE_EVENTS: string[] = ['popstate', CUSTOM_URL_EVENT]; + +/** + * This hook stores state in the URL, but with a namespace to avoid collisions with other values in the URL. + * It also batches updates to the URL to avoid excessive history entries. + * With it, you can store state in the URL and have it persist across page refreshes. + * The state is stored in the URL as a Rison encoded object. + * + * Example: when called like this `const [value, setValue] = useUrlState('myNamespace', 'myKey');` + * the state will be stored in the URL like this: `?myNamespace=(myKey:!n)` + * + * State is not cleared from the URL when the hook is unmounted and this is by design. + * If you want it to be cleared, you can do it manually by calling `setValue(undefined)`. + * + * @param urlNamespace actual top level query param key + * @param key sub key of the query param + */ +export const useUrlState = (urlNamespace: string, key: string) => { + if (!cache.namespaces[urlNamespace]) { + cache.namespaces[urlNamespace] = {}; + } + + const [internalValue, setInternalValue] = useState(undefined); + + useEffect(() => { + // This listener is called on browser navigation or on custom event. + // It updates the LOCAL state, allowing dependent components to re-render. + const listener = () => { + const searchParams = new URLSearchParams(window.location.search); + const param = searchParams.get(urlNamespace); + + const decodedState = param ? decode(param) : ({} as Record); + const decodedValue = (decodedState as Record | undefined)?.[key]; + cache.namespaces[urlNamespace][key] = decodedValue; + setInternalValue(decodedValue as unknown as T); + }; + + listener(); + + URL_CHANGE_EVENTS.forEach((event) => window.addEventListener(event, listener)); + + return () => URL_CHANGE_EVENTS.forEach((event) => window.removeEventListener(event, listener)); + }, [key, urlNamespace]); + + const setValue = useCallback( + (updatedValue: T | undefined) => { + const currentValue = cache.namespaces[urlNamespace][key]; + + const canSpread = + typeof updatedValue === 'object' && + typeof currentValue === 'object' && + !Array.isArray(updatedValue) && + !Array.isArray(currentValue); + + cache.namespaces[urlNamespace][key] = canSpread + ? ({ ...currentValue, ...updatedValue } as unknown as T) + : (updatedValue as unknown as T); + + // This batches updates to the URL state to avoid excessive history entries + if (cache.timeoutHandle) { + window.clearTimeout(cache.timeoutHandle); + } + + // The push state call is delayed to make sure that multiple calls to setValue + // within a short period of time are batched together. + cache.timeoutHandle = window.setTimeout(() => { + const searchParams = parse(location.search); + + for (const ns in cache.namespaces) { + if (!Object.prototype.hasOwnProperty.call(cache.namespaces, ns)) { + continue; + } + searchParams[ns] = encode(cache.namespaces[ns]); + } + + const newSearch = stringify(searchParams, { encode: false }); + + if (window.location.search === newSearch) { + return; + } + + const newUrl = `${window.location.hash}?${newSearch}`; + + window.history.pushState({}, '', newUrl); + // This custom event is used to notify other instances + // of this hook that the URL has changed. + window.dispatchEvent(new Event(CUSTOM_URL_EVENT)); + }, 0); + }, + [key, urlNamespace] + ); + + return [internalValue, setValue] as const; +}; diff --git a/packages/kbn-url-state/use_sync_to_url.ts b/packages/kbn-url-state/use_sync_to_url.ts deleted file mode 100644 index e6f1531980f7..000000000000 --- a/packages/kbn-url-state/use_sync_to_url.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { useCallback, useEffect } from 'react'; -import { encode, decode } from '@kbn/rison'; - -// https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event -const POPSTATE_EVENT = 'popstate' as const; - -/** - * Sync any object with browser query string using @knb/rison - * @param key query string param to use - * @param restore use this to handle restored state - * @param cleanupOnHistoryNavigation use history events to cleanup state on back / forward naviation. true by default - */ -export const useSyncToUrl = ( - key: string, - restore: (data: TValueToSerialize) => void, - cleanupOnHistoryNavigation = true -) => { - useEffect(() => { - const params = new URLSearchParams(window.location.search); - const param = params.get(key); - - if (!param) { - return; - } - - const decodedQuery = decode(param); - - if (!decodedQuery) { - return; - } - - // Only restore the value if it is not falsy - restore(decodedQuery as unknown as TValueToSerialize); - }, [key, restore]); - - /** - * Synces value with the url state, under specified key. If payload is undefined, the value will be removed from the query string althogether. - */ - const syncValueToQueryString = useCallback( - (valueToSerialize?: TValueToSerialize) => { - const searchParams = new URLSearchParams(window.location.search); - - if (valueToSerialize) { - const serializedPayload = encode(valueToSerialize); - searchParams.set(key, serializedPayload); - } else { - searchParams.delete(key); - } - - const stringifiedSearchParams = searchParams.toString(); - const newSearch = stringifiedSearchParams.length > 0 ? `?${stringifiedSearchParams}` : ''; - - if (window.location.search === newSearch) { - return; - } - - // Update query string without unnecessary re-render - const newUrl = `${window.location.pathname}${window.location.hash}${newSearch}`; - window.history.replaceState({ path: newUrl }, '', newUrl); - }, - [key] - ); - - // Clear remove state from the url on unmount / when history back or forward is pressed - useEffect(() => { - const clearState = () => { - syncValueToQueryString(undefined); - }; - - if (cleanupOnHistoryNavigation) { - window.addEventListener(POPSTATE_EVENT, clearState); - } - - return () => { - clearState(); - - if (cleanupOnHistoryNavigation) { - window.removeEventListener(POPSTATE_EVENT, clearState); - } - }; - }, [cleanupOnHistoryNavigation, syncValueToQueryString]); - - return syncValueToQueryString; -}; diff --git a/packages/kbn-utils/src/path/index.test.ts b/packages/kbn-utils/src/path/index.test.ts index 608f3cb2cfeb..163dfbef598d 100644 --- a/packages/kbn-utils/src/path/index.test.ts +++ b/packages/kbn-utils/src/path/index.test.ts @@ -6,8 +6,10 @@ * Side Public License, v 1. */ +import { join } from 'path'; import { accessSync, constants } from 'fs'; -import { getConfigPath, getDataPath, getLogsPath, getConfigDirectory } from '.'; +import { rm, mkdtemp, writeFile } from 'fs/promises'; +import { getConfigPath, getDataPath, getLogsPath, getConfigDirectory, buildDataPaths } from '.'; import { REPO_ROOT } from '@kbn/repo-info'; expect.addSnapshotSerializer( @@ -46,3 +48,97 @@ describe('Default path finder', () => { expect(() => accessSync(configPath, constants.R_OK)).not.toThrow(); }); }); + +describe('Custom data path finder', () => { + const originalArgv = process.argv; + + beforeEach(() => { + process.argv = originalArgv; + }); + + it('ignores the path.data flag when no value is provided', () => { + process.argv = ['--foo', 'bar', '--path.data', '--baz', 'xyz']; + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data, + "/var/lib/kibana", + ] + `); + }); + + describe('overrides path.data when provided as command line argument', () => { + it('with absolute path', () => { + process.argv = ['--foo', 'bar', '--path.data', '/some/data/path', '--baz', 'xyz']; + + /* + * Test buildDataPaths since getDataPath returns the first valid directory and + * custom paths do not exist in environment. Custom directories are built during env init. + */ + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + "/some/data/path", + /data, + "/var/lib/kibana", + ] + `); + }); + + it('with relative path', () => { + process.argv = ['--foo', 'bar', '--path.data', 'data2', '--baz', 'xyz']; + + /* + * Test buildDataPaths since getDataPath returns the first valid directory and + * custom paths do not exist in environment. Custom directories are built during env init. + */ + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data2, + /data, + "/var/lib/kibana", + ] + `); + }); + }); + + describe('overrides path.data when provided by kibana.yml', () => { + let tempDir: string; + let tempConfigFile: string; + + beforeAll(async () => { + tempDir = await mkdtemp('config-test'); + tempConfigFile = join(tempDir, 'kibana.yml'); + }); + + afterAll(async () => { + await rm(tempDir, { recursive: true }); + delete process.env.KBN_PATH_CONF; + }); + + it('with absolute path', async () => { + process.env.KBN_PATH_CONF = tempDir; + await writeFile(tempConfigFile, `path.data: /path/from/yml`); + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + "/path/from/yml", + /data, + "/var/lib/kibana", + ] + `); + }); + + it('with relative path', async () => { + process.env.KBN_PATH_CONF = tempDir; + await writeFile(tempConfigFile, `path.data: data2`); + + expect(buildDataPaths()).toMatchInlineSnapshot(` + Array [ + /data2, + /data, + "/var/lib/kibana", + ] + `); + }); + }); +}); diff --git a/packages/kbn-utils/src/path/index.ts b/packages/kbn-utils/src/path/index.ts index 63ca454dd04f..caeaa9a493f1 100644 --- a/packages/kbn-utils/src/path/index.ts +++ b/packages/kbn-utils/src/path/index.ts @@ -6,18 +6,22 @@ * Side Public License, v 1. */ -import { join } from 'path'; +import { join, resolve } from 'path'; import { accessSync, constants } from 'fs'; import { TypeOf, schema } from '@kbn/config-schema'; import { REPO_ROOT } from '@kbn/repo-info'; +import { getConfigFromFiles } from '@kbn/config'; +import getopts from 'getopts'; const isString = (v: any): v is string => typeof v === 'string'; -const CONFIG_PATHS = [ - process.env.KBN_PATH_CONF && join(process.env.KBN_PATH_CONF, 'kibana.yml'), - join(REPO_ROOT, 'config/kibana.yml'), - '/etc/kibana/kibana.yml', -].filter(isString); +const buildConfigPaths = () => { + return [ + process.env.KBN_PATH_CONF && resolve(process.env.KBN_PATH_CONF, 'kibana.yml'), + join(REPO_ROOT, 'config/kibana.yml'), + '/etc/kibana/kibana.yml', + ].filter(isString); +}; const CONFIG_DIRECTORIES = [ process.env.KBN_PATH_CONF, @@ -25,8 +29,6 @@ const CONFIG_DIRECTORIES = [ '/etc/kibana', ].filter(isString); -const DATA_PATHS = [join(REPO_ROOT, 'data'), '/var/lib/kibana'].filter(isString); - const LOGS_PATHS = [join(REPO_ROOT, 'logs'), '/var/log/kibana'].filter(isString); function findFile(paths: string[]) { @@ -41,11 +43,29 @@ function findFile(paths: string[]) { return availablePath || paths[0]; } +export const buildDataPaths = (): string[] => { + const configDataPath = getConfigFromFiles([getConfigPath()]).path?.data; + const argv = process.argv.slice(2); + const options = getopts(argv, { + string: ['pathData'], + alias: { + pathData: 'path.data', + }, + }); + + return [ + !!options.pathData && resolve(REPO_ROOT, options.pathData), + configDataPath && resolve(REPO_ROOT, configDataPath), + join(REPO_ROOT, 'data'), + '/var/lib/kibana', + ].filter(isString); +}; + /** * Get the path of kibana.yml * @internal */ -export const getConfigPath = () => findFile(CONFIG_PATHS); +export const getConfigPath = () => findFile(buildConfigPaths()); /** * Get the directory containing configuration files @@ -57,7 +77,7 @@ export const getConfigDirectory = () => findFile(CONFIG_DIRECTORIES); * Get the directory containing runtime data * @internal */ -export const getDataPath = () => findFile(DATA_PATHS); +export const getDataPath = () => findFile(buildDataPaths()); /** * Get the directory containing logs diff --git a/packages/kbn-utils/tsconfig.json b/packages/kbn-utils/tsconfig.json index 6baa222ef8c3..f6e7fb408bfa 100644 --- a/packages/kbn-utils/tsconfig.json +++ b/packages/kbn-utils/tsconfig.json @@ -13,6 +13,7 @@ "kbn_references": [ "@kbn/config-schema", "@kbn/repo-info", + "@kbn/config", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-visualization-ui-components/components/field_picker/field_picker.test.tsx b/packages/kbn-visualization-ui-components/components/field_picker/field_picker.test.tsx new file mode 100644 index 000000000000..1b821dd44bc9 --- /dev/null +++ b/packages/kbn-visualization-ui-components/components/field_picker/field_picker.test.tsx @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { FieldPicker, FieldPickerProps } from './field_picker'; +import { render, screen } from '@testing-library/react'; +import faker from 'faker'; +import userEvent from '@testing-library/user-event'; +import { DataType, FieldOptionValue } from './types'; + +const generateFieldWithLabelOfLength = (length: number) => ({ + label: faker.random.alpha({ count: length }), + value: { + type: 'field' as const, + field: faker.random.alpha({ count: length }), + dataType: 'date' as DataType, + operationType: 'count', + }, + exists: true, + compatible: 1, +}); + +const generateProps = (customField = generateFieldWithLabelOfLength(20)) => + ({ + selectedOptions: [ + { + label: 'Category', + value: { + type: 'field' as const, + field: 'category.keyword', + dataType: 'keyword' as DataType, + operationType: 'count', + }, + }, + ], + options: [ + { + label: 'nested options', + exists: true, + compatible: 1, + value: generateFieldWithLabelOfLength(20), + options: [ + generateFieldWithLabelOfLength(20), + customField, + generateFieldWithLabelOfLength(20), + ], + }, + ], + onChoose: jest.fn(), + fieldIsInvalid: false, + } as unknown as FieldPickerProps); + +describe('field picker', () => { + const renderFieldPicker = (customField = generateFieldWithLabelOfLength(20)) => { + const props = generateProps(customField); + const rtlRender = render(); + return { + openCombobox: () => userEvent.click(screen.getByLabelText(/open list of options/i)), + ...rtlRender, + }; + }; + + it('should render minimum width dropdown list if all labels are short', async () => { + const { openCombobox } = renderFieldPicker(); + openCombobox(); + const popover = screen.getByRole('dialog'); + expect(popover).toHaveStyle('inline-size: 256px'); + }); + + it('should render calculated width dropdown list if the longest label is longer than min width', async () => { + const { openCombobox } = renderFieldPicker(generateFieldWithLabelOfLength(50)); + openCombobox(); + + const popover = screen.getByRole('dialog'); + expect(popover).toHaveStyle('inline-size: 466px'); + }); + + it('should render maximum width dropdown list if the longest label is longer than max width', async () => { + const { openCombobox } = renderFieldPicker(generateFieldWithLabelOfLength(80)); + openCombobox(); + const popover = screen.getByRole('dialog'); + expect(popover).toHaveStyle('inline-size: 550px'); + }); +}); diff --git a/packages/kbn-visualization-ui-components/components/field_picker/field_picker.tsx b/packages/kbn-visualization-ui-components/components/field_picker/field_picker.tsx index 5b6022d5cb45..237b7c85cd8f 100644 --- a/packages/kbn-visualization-ui-components/components/field_picker/field_picker.tsx +++ b/packages/kbn-visualization-ui-components/components/field_picker/field_picker.tsx @@ -9,9 +9,10 @@ import './field_picker.scss'; import React from 'react'; import { i18n } from '@kbn/i18n'; +import classNames from 'classnames'; import { EuiComboBox, EuiComboBoxProps } from '@elastic/eui'; import { FieldIcon } from '@kbn/field-utils/src/components/field_icon'; -import classNames from 'classnames'; +import { calculateWidthFromCharCount } from '@kbn/calculate-width-from-char-count'; import type { FieldOptionValue, FieldOption } from './types'; export interface FieldPickerProps @@ -27,23 +28,26 @@ export interface FieldPickerProps const MIDDLE_TRUNCATION_PROPS = { truncation: 'middle' as const }; const SINGLE_SELECTION_AS_TEXT_PROPS = { asPlainText: true }; -export function FieldPicker({ - selectedOptions, - options, - onChoose, - onDelete, - fieldIsInvalid, - ['data-test-subj']: dataTestSub, - ...rest -}: FieldPickerProps) { - let theLongestLabel = ''; +export function FieldPicker( + props: FieldPickerProps +) { + const { + selectedOptions, + options, + onChoose, + onDelete, + fieldIsInvalid, + ['data-test-subj']: dataTestSub, + ...rest + } = props; + let maxLabelLength = 0; const styledOptions = options?.map(({ compatible, exists, ...otherAttr }) => { if (otherAttr.options) { return { ...otherAttr, options: otherAttr.options.map(({ exists: fieldOptionExists, ...fieldOption }) => { - if (fieldOption.label.length > theLongestLabel.length) { - theLongestLabel = fieldOption.label; + if (fieldOption.label.length > maxLabelLength) { + maxLabelLength = fieldOption.label.length; } return { ...fieldOption, @@ -75,7 +79,6 @@ export function FieldPicker({ }; }); - const panelMinWidth = getPanelMinWidth(theLongestLabel.length); return ( ({ selectedOptions={selectedOptions} singleSelection={SINGLE_SELECTION_AS_TEXT_PROPS} truncationProps={MIDDLE_TRUNCATION_PROPS} - inputPopoverProps={{ panelMinWidth }} + inputPopoverProps={{ + panelMinWidth: calculateWidthFromCharCount(maxLabelLength), + anchorPosition: 'downRight', + }} onChange={(choices) => { if (choices.length === 0) { onDelete?.(); @@ -102,20 +108,3 @@ export function FieldPicker({ /> ); } - -const MINIMUM_POPOVER_WIDTH = 300; -const MINIMUM_POPOVER_WIDTH_CHAR_COUNT = 28; -const AVERAGE_CHAR_WIDTH = 7; -const MAXIMUM_POPOVER_WIDTH_CHAR_COUNT = 60; -const MAXIMUM_POPOVER_WIDTH = 550; // fitting 60 characters - -function getPanelMinWidth(labelLength: number) { - if (labelLength > MAXIMUM_POPOVER_WIDTH_CHAR_COUNT) { - return MAXIMUM_POPOVER_WIDTH; - } - if (labelLength > MINIMUM_POPOVER_WIDTH_CHAR_COUNT) { - const overflownChars = labelLength - MINIMUM_POPOVER_WIDTH_CHAR_COUNT; - return MINIMUM_POPOVER_WIDTH + overflownChars * AVERAGE_CHAR_WIDTH; - } - return MINIMUM_POPOVER_WIDTH; -} diff --git a/packages/kbn-visualization-ui-components/tsconfig.json b/packages/kbn-visualization-ui-components/tsconfig.json index 78f0b8a4b111..a9d6627828dc 100644 --- a/packages/kbn-visualization-ui-components/tsconfig.json +++ b/packages/kbn-visualization-ui-components/tsconfig.json @@ -31,5 +31,6 @@ "@kbn/coloring", "@kbn/field-formats-plugin", "@kbn/field-utils", + "@kbn/calculate-width-from-char-count" ], } diff --git a/packages/shared-ux/chrome/navigation/__jest__/__snapshots__/project_navigation.test.tsx.snap b/packages/shared-ux/chrome/navigation/__jest__/__snapshots__/project_navigation.test.tsx.snap index 65ed8b80aa8a..d8a1b5d6eacc 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/__snapshots__/project_navigation.test.tsx.snap +++ b/packages/shared-ux/chrome/navigation/__jest__/__snapshots__/project_navigation.test.tsx.snap @@ -5,21 +5,15 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": undefined, "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.item1", "sideNavStatus": "visible", "title": "Item 1", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "", "href": "", @@ -27,19 +21,14 @@ Array [ "title": "Title from deeplink!", "url": "", }, - "href": undefined, + "href": "", "id": "item2", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item2", - ], + "isElasticInternalLink": false, + "path": "group1.item2", "sideNavStatus": "visible", "title": "Title from deeplink!", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "", "href": "", @@ -47,14 +36,10 @@ Array [ "title": "Title from deeplink!", "url": "", }, - "href": undefined, + "href": "", "id": "item3", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item3", - ], + "isElasticInternalLink": false, + "path": "group1.item3", "sideNavStatus": "visible", "title": "Deeplink title overriden", }, @@ -62,11 +47,8 @@ Array [ "deepLink": undefined, "href": undefined, "id": "group1", - "isActive": false, - "isGroup": true, - "path": Array [ - "group1", - ], + "isElasticInternalLink": false, + "path": "group1", "sideNavStatus": "visible", "title": "Group 1", "type": "navGroup", @@ -74,7 +56,6 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/discover", @@ -82,19 +63,14 @@ Array [ "title": "Deeplink discover", "url": "/mocked/discover", }, - "href": undefined, + "href": "/mocked/discover", "id": "discover", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:analytics", - "discover", - ], + "isElasticInternalLink": false, + "path": "rootNav:analytics.discover", "sideNavStatus": "visible", "title": "Deeplink discover", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/dashboards", @@ -102,19 +78,14 @@ Array [ "title": "Deeplink dashboards", "url": "/mocked/dashboards", }, - "href": undefined, + "href": "/mocked/dashboards", "id": "dashboards", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:analytics", - "dashboards", - ], + "isElasticInternalLink": false, + "path": "rootNav:analytics.dashboards", "sideNavStatus": "visible", "title": "Deeplink dashboards", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/visualize", @@ -122,14 +93,10 @@ Array [ "title": "Deeplink visualize", "url": "/mocked/visualize", }, - "href": undefined, + "href": "/mocked/visualize", "id": "visualize", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:analytics", - "visualize", - ], + "isElasticInternalLink": false, + "path": "rootNav:analytics.visualize", "sideNavStatus": "visible", "title": "Deeplink visualize", }, @@ -138,11 +105,8 @@ Array [ "href": undefined, "icon": "stats", "id": "rootNav:analytics", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:analytics", - ], + "isElasticInternalLink": false, + "path": "rootNav:analytics", "renderAs": "accordion", "sideNavStatus": "visible", "title": "Data exploration", @@ -151,7 +115,6 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:overview", @@ -159,19 +122,14 @@ Array [ "title": "Deeplink ml:overview", "url": "/mocked/ml:overview", }, - "href": undefined, + "href": "/mocked/ml:overview", "id": "ml:overview", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:overview", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:overview", "sideNavStatus": "visible", "title": "Deeplink ml:overview", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:notifications", @@ -179,19 +137,14 @@ Array [ "title": "Deeplink ml:notifications", "url": "/mocked/ml:notifications", }, - "href": undefined, + "href": "/mocked/ml:notifications", "id": "ml:notifications", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:notifications", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:notifications", "sideNavStatus": "visible", "title": "Deeplink ml:notifications", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:memoryUsage", @@ -199,14 +152,10 @@ Array [ "title": "Deeplink ml:memoryUsage", "url": "/mocked/ml:memoryUsage", }, - "href": undefined, + "href": "/mocked/ml:memoryUsage", "id": "ml:memoryUsage", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:memoryUsage", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:memoryUsage", "sideNavStatus": "visible", "title": "Deeplink ml:memoryUsage", }, @@ -214,7 +163,6 @@ Array [ "children": Array [ Object { "breadcrumbStatus": "hidden", - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:anomalyDetection", @@ -222,20 +170,14 @@ Array [ "title": "Deeplink ml:anomalyDetection", "url": "/mocked/ml:anomalyDetection", }, - "href": undefined, + "href": "/mocked/ml:anomalyDetection", "id": "ml:anomalyDetection", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:anomalyDetection", - "ml:anomalyDetection", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:anomalyDetection.ml:anomalyDetection", "sideNavStatus": "visible", "title": "Jobs", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:anomalyExplorer", @@ -243,20 +185,14 @@ Array [ "title": "Deeplink ml:anomalyExplorer", "url": "/mocked/ml:anomalyExplorer", }, - "href": undefined, + "href": "/mocked/ml:anomalyExplorer", "id": "ml:anomalyExplorer", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:anomalyDetection", - "ml:anomalyExplorer", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:anomalyDetection.ml:anomalyExplorer", "sideNavStatus": "visible", "title": "Deeplink ml:anomalyExplorer", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:singleMetricViewer", @@ -264,20 +200,14 @@ Array [ "title": "Deeplink ml:singleMetricViewer", "url": "/mocked/ml:singleMetricViewer", }, - "href": undefined, + "href": "/mocked/ml:singleMetricViewer", "id": "ml:singleMetricViewer", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:anomalyDetection", - "ml:singleMetricViewer", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:anomalyDetection.ml:singleMetricViewer", "sideNavStatus": "visible", "title": "Deeplink ml:singleMetricViewer", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:settings", @@ -285,15 +215,10 @@ Array [ "title": "Deeplink ml:settings", "url": "/mocked/ml:settings", }, - "href": undefined, + "href": "/mocked/ml:settings", "id": "ml:settings", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:anomalyDetection", - "ml:settings", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:anomalyDetection.ml:settings", "sideNavStatus": "visible", "title": "Deeplink ml:settings", }, @@ -305,14 +230,10 @@ Array [ "title": "Deeplink ml:anomalyDetection", "url": "/mocked/ml:anomalyDetection", }, - "href": undefined, + "href": "/mocked/ml:anomalyDetection", "id": "ml:anomalyDetection", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - "ml:anomalyDetection", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:anomalyDetection", "renderAs": "accordion", "sideNavStatus": "visible", "title": "Anomaly Detection", @@ -321,7 +242,6 @@ Array [ "children": Array [ Object { "breadcrumbStatus": "hidden", - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:dataFrameAnalytics", @@ -329,20 +249,14 @@ Array [ "title": "Deeplink ml:dataFrameAnalytics", "url": "/mocked/ml:dataFrameAnalytics", }, - "href": undefined, + "href": "/mocked/ml:dataFrameAnalytics", "id": "ml:dataFrameAnalytics", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:dataFrameAnalytics", - "ml:dataFrameAnalytics", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:dataFrameAnalytics.ml:dataFrameAnalytics", "sideNavStatus": "visible", "title": "Jobs", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:resultExplorer", @@ -350,20 +264,14 @@ Array [ "title": "Deeplink ml:resultExplorer", "url": "/mocked/ml:resultExplorer", }, - "href": undefined, + "href": "/mocked/ml:resultExplorer", "id": "ml:resultExplorer", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:dataFrameAnalytics", - "ml:resultExplorer", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:dataFrameAnalytics.ml:resultExplorer", "sideNavStatus": "visible", "title": "Deeplink ml:resultExplorer", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:analyticsMap", @@ -371,15 +279,10 @@ Array [ "title": "Deeplink ml:analyticsMap", "url": "/mocked/ml:analyticsMap", }, - "href": undefined, + "href": "/mocked/ml:analyticsMap", "id": "ml:analyticsMap", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "ml:dataFrameAnalytics", - "ml:analyticsMap", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:dataFrameAnalytics.ml:analyticsMap", "sideNavStatus": "visible", "title": "Deeplink ml:analyticsMap", }, @@ -391,14 +294,10 @@ Array [ "title": "Deeplink ml:dataFrameAnalytics", "url": "/mocked/ml:dataFrameAnalytics", }, - "href": undefined, + "href": "/mocked/ml:dataFrameAnalytics", "id": "ml:dataFrameAnalytics", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - "ml:dataFrameAnalytics", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.ml:dataFrameAnalytics", "renderAs": "accordion", "sideNavStatus": "visible", "title": "Data Frame Analytics", @@ -406,7 +305,6 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:nodesOverview", @@ -414,20 +312,14 @@ Array [ "title": "Deeplink ml:nodesOverview", "url": "/mocked/ml:nodesOverview", }, - "href": undefined, + "href": "/mocked/ml:nodesOverview", "id": "ml:nodesOverview", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "model_management", - "ml:nodesOverview", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.model_management.ml:nodesOverview", "sideNavStatus": "visible", "title": "Deeplink ml:nodesOverview", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:nodes", @@ -435,15 +327,10 @@ Array [ "title": "Deeplink ml:nodes", "url": "/mocked/ml:nodes", }, - "href": undefined, + "href": "/mocked/ml:nodes", "id": "ml:nodes", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "model_management", - "ml:nodes", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.model_management.ml:nodes", "sideNavStatus": "visible", "title": "Deeplink ml:nodes", }, @@ -451,12 +338,8 @@ Array [ "deepLink": undefined, "href": undefined, "id": "model_management", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - "model_management", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.model_management", "renderAs": "accordion", "sideNavStatus": "visible", "title": "Model Management", @@ -464,7 +347,6 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:fileUpload", @@ -472,20 +354,14 @@ Array [ "title": "Deeplink ml:fileUpload", "url": "/mocked/ml:fileUpload", }, - "href": undefined, + "href": "/mocked/ml:fileUpload", "id": "ml:fileUpload", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "data_visualizer", - "ml:fileUpload", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.data_visualizer.ml:fileUpload", "sideNavStatus": "visible", "title": "File", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:indexDataVisualizer", @@ -494,20 +370,14 @@ Array [ "url": "/mocked/ml:indexDataVisualizer", }, "getIsActive": [Function], - "href": undefined, + "href": "/mocked/ml:indexDataVisualizer", "id": "ml:indexDataVisualizer", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "data_visualizer", - "ml:indexDataVisualizer", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.data_visualizer.ml:indexDataVisualizer", "sideNavStatus": "visible", "title": "Data view", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:dataDrift", @@ -516,15 +386,10 @@ Array [ "url": "/mocked/ml:dataDrift", }, "getIsActive": [Function], - "href": undefined, + "href": "/mocked/ml:dataDrift", "id": "ml:dataDrift", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "data_visualizer", - "ml:dataDrift", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.data_visualizer.ml:dataDrift", "sideNavStatus": "visible", "title": "Data drift", }, @@ -532,12 +397,8 @@ Array [ "deepLink": undefined, "href": undefined, "id": "data_visualizer", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - "data_visualizer", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.data_visualizer", "renderAs": "accordion", "sideNavStatus": "visible", "title": "Data Visualizer", @@ -545,7 +406,6 @@ Array [ Object { "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:logRateAnalysis", @@ -554,20 +414,14 @@ Array [ "url": "/mocked/ml:logRateAnalysis", }, "getIsActive": [Function], - "href": undefined, + "href": "/mocked/ml:logRateAnalysis", "id": "ml:logRateAnalysis", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "aiops_labs", - "ml:logRateAnalysis", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.aiops_labs.ml:logRateAnalysis", "sideNavStatus": "visible", "title": "Deeplink ml:logRateAnalysis", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:logPatternAnalysis", @@ -576,20 +430,14 @@ Array [ "url": "/mocked/ml:logPatternAnalysis", }, "getIsActive": [Function], - "href": undefined, + "href": "/mocked/ml:logPatternAnalysis", "id": "ml:logPatternAnalysis", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "aiops_labs", - "ml:logPatternAnalysis", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.aiops_labs.ml:logPatternAnalysis", "sideNavStatus": "visible", "title": "Deeplink ml:logPatternAnalysis", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/ml:changePointDetections", @@ -598,15 +446,10 @@ Array [ "url": "/mocked/ml:changePointDetections", }, "getIsActive": [Function], - "href": undefined, + "href": "/mocked/ml:changePointDetections", "id": "ml:changePointDetections", - "isActive": false, - "isGroup": false, - "path": Array [ - "rootNav:ml", - "aiops_labs", - "ml:changePointDetections", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.aiops_labs.ml:changePointDetections", "sideNavStatus": "visible", "title": "Deeplink ml:changePointDetections", }, @@ -614,12 +457,8 @@ Array [ "deepLink": undefined, "href": undefined, "id": "aiops_labs", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - "aiops_labs", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml.aiops_labs", "renderAs": "accordion", "sideNavStatus": "visible", "title": "AIOps labs", @@ -629,17 +468,13 @@ Array [ "href": undefined, "icon": "machineLearningApp", "id": "rootNav:ml", - "isActive": false, - "isGroup": true, - "path": Array [ - "rootNav:ml", - ], + "isElasticInternalLink": false, + "path": "rootNav:ml", "sideNavStatus": "visible", "title": "Machine Learning", "type": "navGroup", }, Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/dev_tools", @@ -647,14 +482,11 @@ Array [ "title": "Deeplink dev_tools", "url": "/mocked/dev_tools", }, - "href": undefined, + "href": "/mocked/dev_tools", "icon": "editorCodeBlock", "id": "devTools", - "isActive": false, - "isGroup": false, - "path": Array [ - "devTools", - ], + "isElasticInternalLink": false, + "path": "devTools", "sideNavStatus": "visible", "title": "Developer tools", "type": "navItem", @@ -663,7 +495,6 @@ Array [ "breadcrumbStatus": "hidden", "children": Array [ Object { - "children": undefined, "deepLink": Object { "baseUrl": "/mocked", "href": "http://mocked/management", @@ -671,42 +502,28 @@ Array [ "title": "Deeplink management", "url": "/mocked/management", }, - "href": undefined, + "href": "/mocked/management", "id": "management", - "isActive": false, - "isGroup": false, - "path": Array [ - "project_settings_project_nav", - "management", - ], + "isElasticInternalLink": false, + "path": "project_settings_project_nav.management", "sideNavStatus": "visible", "title": "Management", }, Object { - "children": undefined, "deepLink": undefined, "href": "https://cloud.elastic.co/deployments/123456789/security/users", "id": "cloudLinkUserAndRoles", - "isActive": false, - "isGroup": false, - "path": Array [ - "project_settings_project_nav", - "cloudLinkUserAndRoles", - ], + "isElasticInternalLink": true, + "path": "project_settings_project_nav.cloudLinkUserAndRoles", "sideNavStatus": "visible", "title": "Mock Users & Roles", }, Object { - "children": undefined, "deepLink": undefined, "href": "https://cloud.elastic.co/account/billing", "id": "cloudLinkBilling", - "isActive": false, - "isGroup": false, - "path": Array [ - "project_settings_project_nav", - "cloudLinkBilling", - ], + "isElasticInternalLink": true, + "path": "project_settings_project_nav.cloudLinkBilling", "sideNavStatus": "visible", "title": "Mock Billing & Subscriptions", }, @@ -715,11 +532,8 @@ Array [ "href": undefined, "icon": "gear", "id": "project_settings_project_nav", - "isActive": false, - "isGroup": true, - "path": Array [ - "project_settings_project_nav", - ], + "isElasticInternalLink": false, + "path": "project_settings_project_nav", "sideNavStatus": "visible", "title": "Project settings", "type": "navGroup", diff --git a/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx index a0c35ace442e..5a82d4ccd509 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/active_node.test.tsx @@ -8,36 +8,35 @@ import './setup_jest_mocks'; import React from 'react'; import { type RenderResult, act } from '@testing-library/react'; -import { type Observable, of, BehaviorSubject } from 'rxjs'; +import { of, BehaviorSubject } from 'rxjs'; import type { - ChromeNavLink, ChromeProjectNavigation, ChromeProjectNavigationNode, } from '@kbn/core-chrome-browser'; import { Navigation } from '../src/ui/components/navigation'; import type { RootNavigationItemDefinition } from '../src/ui/types'; - +import { NavigationServices } from '../types'; import { renderNavigation, errorHandler, TestType } from './utils'; describe('Active node', () => { test('should set the active node', async () => { - const navLinks$: Observable = of([ - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + item1: { id: 'item1', title: 'Item 1', baseUrl: '', url: '', href: '', }, - { + item2: { id: 'item2', title: 'Item 2', baseUrl: '', url: '', href: '', }, - ]); + }); let activeNodes$: BehaviorSubject; @@ -47,12 +46,12 @@ describe('Active node', () => { { id: 'group1', title: 'Group 1', - path: ['group1'], + path: 'group1', }, { id: 'item1', title: 'Item 1', - path: ['group1', 'item1'], + path: 'group1.item1', }, ], ]); @@ -75,12 +74,12 @@ describe('Active node', () => { { id: 'group1', title: 'Group 1', - path: ['group1'], + path: 'group1', }, { id: 'item2', title: 'Item 2', - path: ['group1', 'item2'], + path: 'group1.item2', }, ], ]); @@ -112,7 +111,7 @@ describe('Active node', () => { const renderResult = renderNavigation({ navTreeDef: { body: navigationBody }, - services: { navLinks$, activeNodes$: getActiveNodes$() }, + services: { deepLinks$, activeNodes$: getActiveNodes$() }, }); await runTests('treeDef', renderResult); @@ -131,7 +130,7 @@ describe('Active node', () => { ), - services: { navLinks$, activeNodes$: getActiveNodes$() }, + services: { deepLinks$, activeNodes$: getActiveNodes$() }, }); await runTests('uiComponents', renderResult); @@ -139,15 +138,15 @@ describe('Active node', () => { }); test('should override the URL location to set the active node', async () => { - const navLinks$: Observable = of([ - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + item1: { id: 'item1', title: 'Item 1', baseUrl: '', url: '', href: '', }, - ]); + }); let activeNodes$: BehaviorSubject; @@ -197,7 +196,7 @@ describe('Active node', () => { const renderResult = renderNavigation({ navTreeDef: { body: navigationBody }, - services: { navLinks$, activeNodes$: getActiveNodes$() }, + services: { deepLinks$, activeNodes$: getActiveNodes$() }, onProjectNavigationChange, }); @@ -223,7 +222,7 @@ describe('Active node', () => { ), onProjectNavigationChange, - services: { navLinks$, activeNodes$: getActiveNodes$() }, + services: { deepLinks$, activeNodes$: getActiveNodes$() }, }); await runTests('uiComponents', renderResult); diff --git a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx index df8246df69d5..653af835b6c9 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx @@ -8,13 +8,12 @@ import './setup_jest_mocks'; import React from 'react'; import { type RenderResult } from '@testing-library/react'; -import { type Observable, of } from 'rxjs'; +import { of } from 'rxjs'; import type { ChromeNavLink } from '@kbn/core-chrome-browser'; import { navLinksMock } from '../mocks/src/navlinks'; import { Navigation } from '../src/ui/components/navigation'; import type { RootNavigationItemDefinition } from '../src/ui/types'; - import { getMockFn, renderNavigation, @@ -23,6 +22,7 @@ import { type ProjectNavigationChangeListener, } from './utils'; import { getServicesMock } from '../mocks/src/jest'; +import { NavigationServices } from '../types'; const { cloudLinks: mockCloudLinks } = getServicesMock(); @@ -110,65 +110,42 @@ describe('builds navigation tree', () => { Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.item1", "sideNavStatus": "visible", "title": "Item 1", }, Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item2", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item2", - ], + "isElasticInternalLink": false, + "path": "group1.item2", "sideNavStatus": "visible", "title": "Item 2", }, Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "group1A", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.item1", "sideNavStatus": "visible", "title": "Group 1A Item 1", }, Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "group1A", - "group1A_1", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.group1A_1.item1", "sideNavStatus": "visible", "title": "Group 1A_1 Item 1", }, @@ -176,38 +153,28 @@ describe('builds navigation tree', () => { "deepLink": undefined, "href": undefined, "id": "group1A_1", - "isActive": false, - "isGroup": true, - "path": Array [ - "group1", - "group1A", - "group1A_1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.group1A_1", "sideNavStatus": "visible", "title": "Group1A_1", }, ], "deepLink": undefined, + "defaultIsCollapsed": false, "href": undefined, "id": "group1A", - "isActive": true, - "isGroup": true, - "path": Array [ - "group1", - "group1A", - ], + "isElasticInternalLink": false, + "path": "group1.group1A", "sideNavStatus": "visible", "title": "Group1A", }, ], "deepLink": undefined, + "defaultIsCollapsed": false, "href": undefined, "id": "group1", - "isActive": true, - "isGroup": true, - "path": Array [ - "group1", - ], + "isElasticInternalLink": false, + "path": "group1", "sideNavStatus": "visible", "title": "", "type": "navGroup", @@ -246,65 +213,42 @@ describe('builds navigation tree', () => { Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.item1", "sideNavStatus": "visible", "title": "Item 1", }, Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item2", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "item2", - ], + "isElasticInternalLink": false, + "path": "group1.item2", "sideNavStatus": "visible", "title": "Item 2", }, Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "group1A", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.item1", "sideNavStatus": "visible", "title": "Group 1A Item 1", }, Object { "children": Array [ Object { - "children": undefined, "deepLink": undefined, "href": "https://foo", "id": "item1", - "isActive": false, - "isGroup": false, - "path": Array [ - "group1", - "group1A", - "group1A_1", - "item1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.group1A_1.item1", "sideNavStatus": "visible", "title": "Group 1A_1 Item 1", }, @@ -312,13 +256,8 @@ describe('builds navigation tree', () => { "deepLink": undefined, "href": undefined, "id": "group1A_1", - "isActive": false, - "isGroup": true, - "path": Array [ - "group1", - "group1A", - "group1A_1", - ], + "isElasticInternalLink": false, + "path": "group1.group1A.group1A_1", "sideNavStatus": "visible", "title": "Group1A_1", }, @@ -326,24 +265,18 @@ describe('builds navigation tree', () => { "deepLink": undefined, "href": undefined, "id": "group1A", - "isActive": false, - "isGroup": true, - "path": Array [ - "group1", - "group1A", - ], + "isElasticInternalLink": false, + "path": "group1.group1A", "sideNavStatus": "visible", "title": "Group1A", }, ], "deepLink": undefined, + "defaultIsCollapsed": false, "href": undefined, "id": "group1", - "isActive": true, - "isGroup": true, - "path": Array [ - "group1", - ], + "isElasticInternalLink": false, + "path": "group1", "sideNavStatus": "visible", "title": "", }, @@ -353,16 +286,19 @@ describe('builds navigation tree', () => { }); test('should read the title from deeplink, prop or React children', async () => { - const navLinks$: Observable = of([ - ...navLinksMock, - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + ...navLinksMock.reduce>((acc, navLink) => { + acc[navLink.id] = navLink; + return acc; + }, {}), + item1: { id: 'item1', title: 'Title from deeplink', baseUrl: '', url: '', href: '', }, - ]); + }); const onProjectNavigationChange = getMockFn(); @@ -425,7 +361,7 @@ describe('builds navigation tree', () => { const renderResult = renderNavigation({ navTreeDef: { body: navigationBody }, - services: { navLinks$ }, + services: { deepLinks$ }, onProjectNavigationChange, }); @@ -454,7 +390,7 @@ describe('builds navigation tree', () => { ), - services: { navLinks$ }, + services: { deepLinks$ }, onProjectNavigationChange, }); @@ -466,15 +402,15 @@ describe('builds navigation tree', () => { }); test('should not render the group if it does not have children AND no href or deeplink', async () => { - const navLinks$: Observable = of([ - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + item1: { id: 'item1', title: 'Title from deeplink', baseUrl: '', url: '', href: '', }, - ]); + }); const onProjectNavigationChange = getMockFn(); const runTests = (type: TestType, { queryByTestId }: RenderResult) => { @@ -523,7 +459,7 @@ describe('builds navigation tree', () => { const renderResult = renderNavigation({ navTreeDef: { body: navigationBody }, - services: { navLinks$ }, + services: { deepLinks$ }, onProjectNavigationChange, }); @@ -548,7 +484,7 @@ describe('builds navigation tree', () => { ), - services: { navLinks$ }, + services: { deepLinks$ }, onProjectNavigationChange, }); @@ -663,11 +599,7 @@ describe('builds navigation tree', () => { const renderResult = renderNavigation({ navigationElement: ( - - - - - + ), services: { recentlyAccessed$ }, @@ -688,28 +620,28 @@ describe('builds navigation tree', () => { { const userAndRolesLink = await findByTestId(/nav-item-group1.cloudLink1/); - expect(userAndRolesLink.textContent).toBe('Mock Users & RolesExternal link'); + expect(userAndRolesLink.textContent).toBe('Mock Users & Roles'); const href = userAndRolesLink.getAttribute('href'); expect(href).toBe(stripLastChar(mockCloudLinks.userAndRoles?.href)); } { const performanceLink = await findByTestId(/nav-item-group1.cloudLink2/); - expect(performanceLink.textContent).toBe('Mock PerformanceExternal link'); + expect(performanceLink.textContent).toBe('Mock Performance'); const href = performanceLink.getAttribute('href'); expect(href).toBe(stripLastChar(mockCloudLinks.performance?.href)); } { const billingLink = await findByTestId(/nav-item-group1.cloudLink3/); - expect(billingLink.textContent).toBe('Mock Billing & SubscriptionsExternal link'); + expect(billingLink.textContent).toBe('Mock Billing & Subscriptions'); const href = billingLink.getAttribute('href'); expect(href).toBe(stripLastChar(mockCloudLinks.billingAndSub?.href)); } { const deploymentLink = await findByTestId(/nav-item-group1.cloudLink4/); - expect(deploymentLink.textContent).toBe('Mock DeploymentExternal link'); + expect(deploymentLink.textContent).toBe('Mock Deployment'); const href = deploymentLink.getAttribute('href'); expect(href).toBe(stripLastChar(mockCloudLinks.deployment?.href)); } diff --git a/packages/shared-ux/chrome/navigation/__jest__/links.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/links.test.tsx index 56da3d4494c8..c52f56e3075d 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/links.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/links.test.tsx @@ -8,12 +8,11 @@ import './setup_jest_mocks'; import React from 'react'; import { type RenderResult } from '@testing-library/react'; -import { type Observable, of } from 'rxjs'; -import type { ChromeNavLink } from '@kbn/core-chrome-browser'; +import { of } from 'rxjs'; import { Navigation } from '../src/ui/components/navigation'; import type { RootNavigationItemDefinition } from '../src/ui/types'; - +import { NavigationServices } from '../types'; import { getMockFn, renderNavigation, @@ -27,15 +26,15 @@ describe('Links', () => { const onProjectNavigationChange = getMockFn(); const unknownLinkId = 'unknown'; - const navLinks$: Observable = of([ - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + item1: { id: 'item1', title: 'Title from deeplink', baseUrl: '', url: '', href: '', }, - ]); + }); const runTests = async (type: TestType, { findByTestId, queryByTestId }: RenderResult) => { try { @@ -84,7 +83,7 @@ describe('Links', () => { const renderResult = renderNavigation({ navTreeDef: { body: navigationBody }, onProjectNavigationChange, - services: { navLinks$ }, + services: { deepLinks$ }, }); await runTests('treeDef', renderResult); @@ -108,7 +107,7 @@ describe('Links', () => { ), onProjectNavigationChange, - services: { navLinks$ }, + services: { deepLinks$ }, }); await runTests('uiComponents', renderResult); diff --git a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx index 40641eb31d2d..e588ed384c11 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/panel.test.tsx @@ -13,7 +13,7 @@ import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import { Navigation } from '../src/ui/components/navigation'; import type { RootNavigationItemDefinition } from '../src/ui/types'; - +import { PanelContentProvider } from '../src/ui'; import { renderNavigation, errorHandler, @@ -21,7 +21,6 @@ import { getMockFn, ProjectNavigationChangeListener, } from './utils'; -import { PanelContentProvider } from '../src/ui'; describe('Panel', () => { test('should render group as panel opener', async () => { @@ -187,7 +186,7 @@ describe('Panel', () => { const [path0 = []] = activeNodes; return (
    -

    {selectedNode.id}

    +

    {selectedNode.path}

      {path0.map((node) => (
    • {node.id}
    • @@ -207,12 +206,12 @@ describe('Panel', () => { { id: 'activeGroup1', title: 'Group 1', - path: ['activeGroup1'], + path: 'activeGroup1', }, { id: 'activeItem1', title: 'Item 1', - path: ['activeGroup1', 'activeItem1'], + path: 'activeGroup1.activeItem1', }, ], ]); diff --git a/packages/shared-ux/chrome/navigation/__jest__/project_navigation.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/project_navigation.test.tsx index 7b47c466b838..a707d1e84b19 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/project_navigation.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/project_navigation.test.tsx @@ -6,12 +6,12 @@ * Side Public License, v 1. */ import './setup_jest_mocks'; -import { type Observable, of } from 'rxjs'; +import { of } from 'rxjs'; import type { ChromeNavLink } from '@kbn/core-chrome-browser'; import { navLinksMock } from '../mocks/src/navlinks'; +import { NavigationServices } from '../types'; import type { ProjectNavigationTreeDefinition } from '../src/ui/types'; - import { getMockFn, renderNavigation, type ProjectNavigationChangeListener } from './utils'; describe('Default navigation', () => { @@ -22,16 +22,19 @@ describe('Default navigation', () => { */ test('builds the full navigation tree when only the project is provided', async () => { const onProjectNavigationChange = getMockFn(); - const navLinks$: Observable = of([ - ...navLinksMock, - { + const deepLinks$: NavigationServices['deepLinks$'] = of({ + ...navLinksMock.reduce>((acc, navLink) => { + acc[navLink.id] = navLink; + return acc; + }, {}), + item2: { id: 'item2', title: 'Title from deeplink!', baseUrl: '', url: '', href: '', }, - ]); + }); const projectNavigationTree: ProjectNavigationTreeDefinition = [ { @@ -62,7 +65,7 @@ describe('Default navigation', () => { renderNavigation({ projectNavigationTree, onProjectNavigationChange, - services: { navLinks$ }, + services: { deepLinks$ }, }); expect(onProjectNavigationChange).toHaveBeenCalled(); diff --git a/packages/shared-ux/chrome/navigation/kibana.jsonc b/packages/shared-ux/chrome/navigation/kibana.jsonc index 74cd1ccea325..60bfed4d5796 100644 --- a/packages/shared-ux/chrome/navigation/kibana.jsonc +++ b/packages/shared-ux/chrome/navigation/kibana.jsonc @@ -1,5 +1,5 @@ { - "type": "shared-common", + "type": "shared-browser", "id": "@kbn/shared-ux-chrome-navigation", "owner": "@elastic/appex-sharedux" } diff --git a/packages/shared-ux/chrome/navigation/mocks/src/jest.ts b/packages/shared-ux/chrome/navigation/mocks/src/jest.ts index 9ae6c2b2a695..750b3faada7b 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/jest.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/jest.ts @@ -13,18 +13,25 @@ import { navLinksMock } from './navlinks'; const activeNodes: ChromeProjectNavigationNode[][] = []; +const defaultDeepLinks = { + ...navLinksMock.reduce>((acc, navLink) => { + acc[navLink.id] = navLink; + return acc; + }, {}), +}; + export const getServicesMock = ({ - navLinks = navLinksMock, -}: { navLinks?: ChromeNavLink[] } = {}): NavigationServices => { + deepLinks = defaultDeepLinks, +}: { deepLinks?: Readonly> } = {}): NavigationServices => { const navigateToUrl = jest.fn().mockResolvedValue(undefined); const basePath = { prepend: jest.fn((path: string) => `/base${path}`) }; const recentlyAccessed$ = new BehaviorSubject([]); - const navLinks$ = new BehaviorSubject(navLinks); + const deepLinks$ = new BehaviorSubject(deepLinks); return { basePath, recentlyAccessed$, - navLinks$, + deepLinks$, navIsOpen: true, navigateToUrl, onProjectNavigationChange: jest.fn(), diff --git a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts index df1416ec0f79..7a7d0e5fbe3e 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts @@ -14,7 +14,7 @@ import { NavigationServices } from '../../types'; type Arguments = NavigationServices; export type Params = Pick< Arguments, - 'navIsOpen' | 'recentlyAccessed$' | 'activeNodes$' | 'navLinks$' | 'onProjectNavigationChange' + 'navIsOpen' | 'recentlyAccessed$' | 'activeNodes$' | 'deepLinks$' | 'onProjectNavigationChange' >; export class StorybookMock extends AbstractStorybookMock<{}, NavigationServices> { @@ -41,7 +41,7 @@ export class StorybookMock extends AbstractStorybookMock<{}, NavigationServices> basePath: { prepend: (suffix: string) => `/basepath${suffix}` }, navigateToUrl, recentlyAccessed$: params.recentlyAccessed$ ?? new BehaviorSubject([]), - navLinks$: params.navLinks$ ?? new BehaviorSubject([]), + deepLinks$: params.deepLinks$ ?? new BehaviorSubject({}), onProjectNavigationChange: params.onProjectNavigationChange ?? (() => undefined), activeNodes$: params.activeNodes$ ?? new BehaviorSubject([]), isSideNavCollapsed: true, diff --git a/packages/shared-ux/chrome/navigation/src/cloud_links.tsx b/packages/shared-ux/chrome/navigation/src/cloud_links.tsx index ce9d9e5990aa..b900daa340b4 100644 --- a/packages/shared-ux/chrome/navigation/src/cloud_links.tsx +++ b/packages/shared-ux/chrome/navigation/src/cloud_links.tsx @@ -7,7 +7,6 @@ */ import { i18n } from '@kbn/i18n'; import type { CloudLinkId } from '@kbn/core-chrome-browser'; -import type { CloudStart } from '@kbn/cloud-plugin/public'; export interface CloudLink { title: string; @@ -18,7 +17,12 @@ export type CloudLinks = { [id in CloudLinkId]?: CloudLink; }; -export const getCloudLinks = (cloud: CloudStart): CloudLinks => { +export const getCloudLinks = (cloud: { + billingUrl?: string; + deploymentUrl?: string; + performanceUrl?: string; + usersAndRolesUrl?: string; +}): CloudLinks => { const { billingUrl, deploymentUrl, performanceUrl, usersAndRolesUrl } = cloud; const links: CloudLinks = {}; diff --git a/packages/shared-ux/chrome/navigation/src/navnode_utils.ts b/packages/shared-ux/chrome/navigation/src/navnode_utils.ts new file mode 100644 index 000000000000..561950959d08 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/navnode_utils.ts @@ -0,0 +1,173 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { + AppDeepLinkId, + ChromeNavLink, + ChromeProjectNavigationNode, + CloudLinkId, + SideNavNodeStatus, +} from '@kbn/core-chrome-browser'; + +import type { CloudLinks } from './cloud_links'; +import type { NodeProps } from './ui/types'; +import { getNavigationNodeHref, getNavigationNodeId, isAbsoluteLink } from './utils'; + +/** + * We don't have currently a way to know if a user has access to a Cloud section. + * TODO: This function will have to be revisited once we have an API from Cloud to know the user + * permissions. + */ +function hasUserAccessToCloudLink(): boolean { + return true; +} + +function getNodeStatus( + { + link, + deepLink, + cloudLink, + sideNavStatus, + }: { + link?: string; + deepLink?: ChromeNavLink; + cloudLink?: CloudLinkId; + sideNavStatus?: SideNavNodeStatus; + }, + { cloudLinks }: { cloudLinks: CloudLinks } +): SideNavNodeStatus | 'remove' { + if (link && !deepLink) { + // If a link is provided, but no deepLink is found, don't render anything + return 'remove'; + } + + if (cloudLink) { + if (!cloudLinks[cloudLink]) { + // Invalid cloudLinkId or link url has not been set in kibana.yml + return 'remove'; + } + if (!hasUserAccessToCloudLink()) return 'remove'; + } + + if (deepLink && deepLink.hidden) return 'hidden'; + + return sideNavStatus ?? 'visible'; +} + +function getTitleForNode< + LinkId extends AppDeepLinkId = AppDeepLinkId, + Id extends string = string, + ChildrenId extends string = Id +>( + navNode: NodeProps, + { deepLink, cloudLinks }: { deepLink?: ChromeNavLink; cloudLinks: CloudLinks } +): string { + const { children } = navNode; + if (navNode.title) { + return navNode.title; + } + + if (typeof children === 'string') { + return children; + } + + if (deepLink?.title) { + return deepLink.title; + } + + if (navNode.cloudLink) { + return cloudLinks[navNode.cloudLink]?.title ?? ''; + } + + return ''; +} + +function validateNodeProps< + LinkId extends AppDeepLinkId = AppDeepLinkId, + Id extends string = string, + ChildrenId extends string = Id +>({ id, link, href, cloudLink, renderAs }: NodeProps) { + if (link && cloudLink) { + throw new Error( + `[Chrome navigation] Error in node [${id}]. Only one of "link" or "cloudLink" can be provided.` + ); + } + if (href && cloudLink) { + throw new Error( + `[Chrome navigation] Error in node [${id}]. Only one of "href" or "cloudLink" can be provided.` + ); + } + if (renderAs === 'panelOpener' && !link) { + throw new Error( + `[Chrome navigation] Error in node [${id}]. If renderAs is set to "panelOpener", a "link" must also be provided.` + ); + } + if (renderAs === 'item' && !link) { + throw new Error( + `[Chrome navigation] Error in node [${id}]. If renderAs is set to "item", a "link" must also be provided.` + ); + } +} + +export const initNavNode = < + LinkId extends AppDeepLinkId = AppDeepLinkId, + Id extends string = string, + ChildrenId extends string = Id +>( + node: NodeProps, + { cloudLinks, deepLinks }: { cloudLinks: CloudLinks; deepLinks: Record } +): ChromeProjectNavigationNode | null => { + validateNodeProps(node); + + const { + cloudLink, + link, + parentNodePath, + rootIndex = 0, + treeDepth = 0, + index = 0, + children, + ...navNodeFromProps + } = node; + const deepLink = link !== undefined ? deepLinks[link] : undefined; + const sideNavStatus = getNodeStatus( + { + link, + deepLink, + cloudLink, + sideNavStatus: navNodeFromProps.sideNavStatus, + }, + { cloudLinks } + ); + if (sideNavStatus === 'remove') { + return null; + } + + const id = getNavigationNodeId(node, () => `node-${rootIndex}-${treeDepth}-${index}`) as Id; + const title = getTitleForNode(node, { deepLink, cloudLinks }); + const isElasticInternalLink = cloudLink != null; + const href = isElasticInternalLink ? cloudLinks[cloudLink]?.href : node.href; + const path = parentNodePath ? `${parentNodePath}.${id}` : id; + + if (href && !isAbsoluteLink(href)) { + throw new Error(`href must be an absolute URL. Node id [${id}].`); + } + + const navNode: ChromeProjectNavigationNode = { + ...navNodeFromProps, + id, + href: getNavigationNodeHref({ href, deepLink }), + path, + title, + deepLink, + isElasticInternalLink, + sideNavStatus, + }; + + return navNode; +}; diff --git a/packages/shared-ux/chrome/navigation/src/services.tsx b/packages/shared-ux/chrome/navigation/src/services.tsx index f77a288160a3..54e45ede100e 100644 --- a/packages/shared-ux/chrome/navigation/src/services.tsx +++ b/packages/shared-ux/chrome/navigation/src/services.tsx @@ -8,6 +8,9 @@ import React, { FC, useContext, useMemo } from 'react'; import useObservable from 'react-use/lib/useObservable'; +import { map } from 'rxjs'; +import type { ChromeNavLink } from '@kbn/core-chrome-browser'; + import { NavigationKibanaDependencies, NavigationServices } from '../types'; import { CloudLink, CloudLinks, getCloudLinks } from './cloud_links'; @@ -61,17 +64,31 @@ export const NavigationKibanaProvider: FC = ({ const { chrome, http } = core; const { basePath } = http; const { navigateToUrl } = core.application; + const { billingUrl, deploymentUrl, performanceUrl, usersAndRolesUrl } = cloud; - const cloudLinks: CloudLinks = useMemo( - () => (cloud ? parseCloudURLs(getCloudLinks(cloud)) : {}), - [cloud] - ); + const cloudLinks: CloudLinks = useMemo(() => { + return parseCloudURLs( + getCloudLinks({ billingUrl, deploymentUrl, performanceUrl, usersAndRolesUrl }) + ); + }, [billingUrl, deploymentUrl, performanceUrl, usersAndRolesUrl]); const isSideNavCollapsed = useObservable(chrome.getIsSideNavCollapsed$(), true); + const navLinks$ = useMemo(() => chrome.navLinks.getNavLinks$(), [chrome.navLinks]); + const deepLinks$ = useMemo(() => { + return navLinks$.pipe( + map((navLinks) => { + return navLinks.reduce((acc, navLink) => { + acc[navLink.id] = navLink; + return acc; + }, {} as Record); + }) + ); + }, [navLinks$]); + const value: NavigationServices = { basePath, recentlyAccessed$: chrome.recentlyAccessed.get$(), - navLinks$: chrome.navLinks.getNavLinks$(), + deepLinks$, navigateToUrl, navIsOpen: true, onProjectNavigationChange: serverless.setNavigation, diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation.tsx index 8f74abee6a11..d56495b810f4 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation.tsx @@ -8,19 +8,18 @@ import React, { createContext, - useState, useCallback, ReactNode, useMemo, - useEffect, useContext, useRef, + Children, } from 'react'; import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; -import useDebounce from 'react-use/lib/useDebounce'; import useObservable from 'react-use/lib/useObservable'; import { useNavigation as useNavigationServices } from '../../services'; +import { getChildType } from '../../utils'; import { RegisterFunction, UnRegisterFunction } from '../types'; import { NavigationFooter } from './navigation_footer'; import { NavigationGroup } from './navigation_group'; @@ -31,17 +30,12 @@ import { PanelProvider, type ContentProvider } from './panel'; interface Context { register: RegisterFunction; - updateFooterChildren: (children: ReactNode) => void; unstyled: boolean; activeNodes: ChromeProjectNavigationNode[][]; } const NavigationContext = createContext({ - register: () => ({ - unregister: () => {}, - path: [], - }), - updateFooterChildren: () => {}, + register: () => () => {}, unstyled: false, activeNodes: [], }); @@ -77,83 +71,105 @@ export function Navigation({ const idx = useRef(0); const activeNodes = useObservable(activeNodes$, []); - const [navigationItems, setNavigationItems] = useState< - Record - >({}); - const [debouncedNavigationItems, setDebouncedNavigationItems] = useState< - Record - >({}); - const [footerChildren, setFooterChildren] = useState(null); - - const unregister: UnRegisterFunction = useCallback((id: string) => { - setNavigationItems((prevItems) => { - const updatedItems = { ...prevItems }; - delete updatedItems[id]; - return updatedItems; + const navigationItemsRef = useRef>({}); + + const onNavigationItemsChange = useCallback(() => { + const navigationTree = Object.values(navigationItemsRef.current).sort((a, b) => { + const aOrder = orderChildrenRef.current[a.id]; + const bOrder = orderChildrenRef.current[b.id]; + return aOrder - bOrder; }); - }, []); + + // This will update the navigation tree in the Chrome service (calling the serverless.setNavigation()) + onProjectNavigationChange({ navigationTree }); + }, [onProjectNavigationChange]); + + const unregister = useCallback( + (id: string) => { + const updatedItems = { ...navigationItemsRef.current }; + delete updatedItems[id]; + navigationItemsRef.current = updatedItems; + + onNavigationItemsChange(); + }, + [onNavigationItemsChange] + ); const register = useCallback( - (navNode) => { + (navNode, order): UnRegisterFunction => { if (orderChildrenRef.current[navNode.id] === undefined) { - orderChildrenRef.current[navNode.id] = idx.current++; + orderChildrenRef.current[navNode.id] = order ?? idx.current++; } - setNavigationItems((prevItems) => { - return { - ...prevItems, - [navNode.id]: navNode, - }; - }); + const updatedRef = { ...navigationItemsRef.current, [navNode.id]: navNode }; + navigationItemsRef.current = updatedRef; + + onNavigationItemsChange(); - return { - unregister, - path: [navNode.id], - }; + return () => unregister(navNode.id); }, - [unregister] + [unregister, onNavigationItemsChange] ); const contextValue = useMemo( () => ({ register, - updateFooterChildren: setFooterChildren, unstyled, activeNodes, }), [register, unstyled, activeNodes] ); - useDebounce( - () => { - setDebouncedNavigationItems(navigationItems); - }, - 100, - [navigationItems] - ); + const childrenParsed = useMemo(() => { + let footerChildren: ReactNode; + let rootIndex = 0; + + const parseChildren = (_children: ReactNode, wrapperComponent = '') => { + const parsed: ReactNode[] = []; + Children.forEach(_children, (child, i) => { + if (!React.isValidElement(child)) { + return; + } + + const childType = getChildType(child); + if (childType === 'unknown' && unstyled === false) { + throw new Error( + `${wrapperComponent} only accepts , and as children. Received ${child.type}` + ); + } + + if (childType === 'footer') { + if (footerChildren) { + throw new Error('Only one is allowed'); + } + footerChildren = parseChildren(child.props.children, ''); + return; + } + + // We add a "rootIndex" prop to each child to keep track of the order of the children + // and correctly set the order of nodes in the navigation tree independently of when a + // node register itself (it could be after a deepLink is being activated). + parsed.push({ ...child, props: { ...child.props, rootIndex } }); + rootIndex += 1; + }); - useEffect(() => { - const navigationTree = Object.values(debouncedNavigationItems).sort((a, b) => { - const aOrder = orderChildrenRef.current[a.id]; - const bOrder = orderChildrenRef.current[b.id]; - return aOrder - bOrder; - }); + return parsed; + }; - // This will update the navigation tree in the Chrome service (calling the serverless.setNavigation()) - onProjectNavigationChange({ - navigationTree, - }); - }, [debouncedNavigationItems, onProjectNavigationChange]); + const bodyChildren: ReactNode[] = parseChildren(children); + + return { body: bodyChildren, footer: footerChildren }; + }, [children, unstyled]); return ( - {children} + {childrenParsed.body} diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_footer.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_footer.tsx index d4b78c1e9305..083e8e66ee55 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_footer.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_footer.tsx @@ -6,23 +6,14 @@ * Side Public License, v 1. */ -import React, { useEffect } from 'react'; -import { useNavigation } from './navigation'; +import { type FC } from 'react'; export interface Props { - children?: React.ReactNode; + children?: JSX.Element[]; } -function NavigationFooterComp({ children }: Props) { - const { updateFooterChildren } = useNavigation(); - - useEffect(() => { - if (children) { - updateFooterChildren(children); - } - }, [children, updateFooterChildren]); - +// Note: this component is only used to detect which children are part of the body and which +// are part of the footer. See the "childrenParsed" value of the component. +export const NavigationFooter: FC = () => { return null; -} - -export const NavigationFooter = React.memo(NavigationFooterComp); +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx index 2f3ecbd381b4..11beb966963a 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx @@ -6,31 +6,98 @@ * Side Public License, v 1. */ -import React, { createContext, useCallback, useMemo, useContext } from 'react'; -import type { AppDeepLinkId, ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; +import React, { useMemo, Children, ReactNode, useEffect, useRef } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import deepEqual from 'react-fast-compare'; +import type { + AppDeepLinkId, + ChromeProjectNavigationNode, + ChromeNavLink, +} from '@kbn/core-chrome-browser'; import { useNavigation as useNavigationServices } from '../../services'; -import { useInitNavNode } from '../hooks'; -import type { NodeProps, NodePropsEnhanced, RegisterFunction } from '../types'; +import type { NodeProps } from '../types'; import { NavigationSectionUI } from './navigation_section_ui'; import { useNavigation } from './navigation'; import { NavigationBucket, type Props as NavigationBucketProps } from './navigation_bucket'; +import { generateUniqueNodeId, getChildType } from '../../utils'; +import { initNavNode } from '../../navnode_utils'; +import { CloudLinks } from '../../cloud_links'; + +/** + * Handler to convert the JSX children of the NavigationGroup to the ChromeProjectNavigationNode + * interface. We do that by parsing the children with the React.Children func, read their prop + * and initiate the node objects. + */ +const jsxChildrenToNavigationNode = ( + { + parentNodePath, + jsxChildren, + rootIndex, + treeDepth, + }: { parentNodePath: string; jsxChildren?: ReactNode; rootIndex: number; treeDepth: number }, + { cloudLinks, deepLinks }: { cloudLinks: CloudLinks; deepLinks: Record } +): ChromeProjectNavigationNode[] | undefined => { + if (!jsxChildren) return undefined; + + const navigationNodes: ChromeProjectNavigationNode[] = []; + + Children.forEach(jsxChildren, (child, index) => { + if (!React.isValidElement(child)) { + return; + } + const title = + typeof child.props.children === 'string' ? child.props.children : child.props.title; + const childNode = initNavNode( + { ...child.props, title, rootIndex, treeDepth, index, parentNodePath }, + { cloudLinks, deepLinks } + ); -interface Context { - register: RegisterFunction; -} + if (!childNode) return; + + const childType = getChildType(child); + + if (childType !== 'group') { + if (childType === 'item') { + if (child.props.children && typeof child.props.children !== 'string') { + // Render the node item + childNode.renderItem = () => child.props.children; + } + navigationNodes.push(childNode); + } else { + // This is a custom JSX node, render it "as is" in the nav. + navigationNodes.push({ + id: generateUniqueNodeId(), + title: '', + path: '', + renderItem: () => child, + }); + } + return; + } -export const NavigationGroupContext = createContext(undefined); + if (child.props?.children) { + navigationNodes.push({ + ...childNode, + // Recursively add all the children of the group + children: jsxChildrenToNavigationNode( + { + parentNodePath: childNode.path, + jsxChildren: child.props.children, + rootIndex, + treeDepth: treeDepth + 1, + }, + { cloudLinks, deepLinks } + ), + }); + return; + } -export function useNavigationGroup( - throwIfNotFound: T = true as T -): T extends true ? Context : Context | undefined { - const context = useContext(NavigationGroupContext); - if (!context && throwIfNotFound) { - throw new Error('useNavigationGroup must be used within a NavigationGroup provider'); - } - return context as T extends true ? Context : Context | undefined; -} + navigationNodes.push(childNode); + }); + + return navigationNodes.length > 0 ? navigationNodes : undefined; +}; export interface Props< LinkId extends AppDeepLinkId = AppDeepLinkId, @@ -45,82 +112,60 @@ function NavigationGroupInternalComp< Id extends string = string, ChildrenId extends string = Id >(props: Props) { - const { cloudLinks } = useNavigationServices(); - const navigationContext = useNavigation(); - - const { children, node } = useMemo(() => { - const { children: _children, defaultIsCollapsed, ...rest } = props; - const nodeEnhanced: Omit, 'children'> = { - ...rest, - isActive: defaultIsCollapsed !== undefined ? defaultIsCollapsed === false : undefined, - isGroup: true, - }; - return { - children: _children, - node: nodeEnhanced, - }; - }, [props]); - - const { navNode, registerChildNode, path, childrenNodes } = useInitNavNode(node, { cloudLinks }); + const { cloudLinks, deepLinks$ } = useNavigationServices(); + const { register } = useNavigation(); + const deepLinks = useObservable(deepLinks$, {}); + const { rootIndex = 0 } = props; - // We add to the nav node the children that have mounted and registered themselves. - // Those children render in the UI inside the NavigationSectionUI -> EuiCollapsibleNavItem -> items - const navNodeWithChildren = useMemo(() => { - if (!navNode) return null; + const navNodeRef = useRef(); + const childrenNodesRef = useRef(); - const hasChildren = Object.keys(childrenNodes).length > 0; - const withChildren: ChromeProjectNavigationNode = { - ...navNode, - children: hasChildren ? Object.values(childrenNodes) : undefined, - }; + const navNode = useMemo(() => { + const _navNode = initNavNode(props, { cloudLinks, deepLinks }); - return withChildren; - }, [navNode, childrenNodes]); + if (!_navNode) return null; - const unstyled = props.unstyled ?? navigationContext.unstyled; + const childrenNodes = jsxChildrenToNavigationNode( + { parentNodePath: _navNode.path, jsxChildren: props.children, rootIndex, treeDepth: 1 }, + { cloudLinks, deepLinks } + ); - const renderContent = useCallback(() => { - if (!path || !navNodeWithChildren) { - return null; + const childrenChanged = deepEqual(childrenNodes, childrenNodesRef.current) === false; + if (childrenChanged) { + childrenNodesRef.current = childrenNodes; } - if (navNodeWithChildren.sideNavStatus === 'hidden') return null; + const nextValue = { + ..._navNode, + children: childrenNodesRef.current, + }; - if (unstyled) { - // No UI for unstyled groups - return children; + const hasChanged = deepEqual(nextValue, navNodeRef.current) === false; + if (hasChanged) { + navNodeRef.current = nextValue; } - // We will only render the component for root groups. The nested group - // are handled by the EuiCollapsibleNavItem component through its "items" prop. - const isRootLevel = path && path.length === 1; + if (navNodeRef.current === undefined) { + // Adding this check for TS purpose, it should never be undefined. + throw new Error('Navnode ref is undefined.'); + } - return ( - <> - {isRootLevel && } - {/* We render the children so they mount and can **register** themselves but - visually they don't appear here in the DOM. They are rendered inside the - "items" prop (see ) */} - {children} - - ); - }, [navNodeWithChildren, path, children, unstyled]); + return navNodeRef.current; + }, [props, cloudLinks, deepLinks, rootIndex]); - const contextValue = useMemo(() => { - return { - register: registerChildNode, - }; - }, [registerChildNode]); + /** Register when mounting and whenever the internal nav node changes */ + useEffect(() => { + if (navNode) { + return register(navNode, rootIndex); + } + return undefined; + }, [register, navNode, rootIndex]); - if (!navNode) { + if (!navNode || navNode.sideNavStatus === 'hidden') { return null; } - return ( - - {renderContent()} - - ); + return ; } function NavigationGroupComp< diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx index dae8cef6f4ee..068f12d7ccd9 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx @@ -6,16 +6,18 @@ * Side Public License, v 1. */ -import React, { Fragment, useEffect, useMemo } from 'react'; +import React, { Fragment, useEffect, useMemo, useRef } from 'react'; import type { AppDeepLinkId, ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import { EuiCollapsibleNavItem } from '@elastic/eui'; import classNames from 'classnames'; +import deepEqual from 'react-fast-compare'; +import useObservable from 'react-use/lib/useObservable'; import { useNavigation as useNavigationServices } from '../../services'; -import { useInitNavNode } from '../hooks'; -import type { NodeProps, NodePropsEnhanced } from '../types'; +import type { NodeProps } from '../types'; import { useNavigation } from './navigation'; -import { getNavigationNodeHref } from '../../utils'; +import { isActiveFromUrl } from '../../utils'; +import { initNavNode } from '../../navnode_utils'; export interface Props< LinkId extends AppDeepLinkId = AppDeepLinkId, @@ -30,31 +32,55 @@ function NavigationItemComp< Id extends string = string, ChildrenId extends string = Id >(props: Props) { - const { cloudLinks, navigateToUrl } = useNavigationServices(); - const navigationContext = useNavigation(); - const navNodeRef = React.useRef(null); + const { cloudLinks, navigateToUrl, deepLinks$ } = useNavigationServices(); + const { unstyled: unstyledFromContext, register, activeNodes } = useNavigation(); + const deepLinks = useObservable(deepLinks$, {}); + const navNodeRef = useRef(); + const { rootIndex, appendHorizontalRule } = props; const { children, node } = useMemo(() => { const { children: _children, ...rest } = props; - const nodeEnhanced: Omit, 'children'> = { - ...rest, - isGroup: false, - }; + if (typeof _children === 'string') { - nodeEnhanced.title = nodeEnhanced.title ?? _children; + rest.title = rest.title ?? _children; } + return { children: _children, - node: nodeEnhanced, + node: rest, }; }, [props]); - const unstyled = props.unstyled ?? navigationContext.unstyled; + const unstyled = props.unstyled ?? unstyledFromContext; + + const navNode = useMemo(() => { + const _navNode = initNavNode(node, { cloudLinks, deepLinks }); + if (!_navNode) return null; + + const hasChanged = deepEqual(_navNode, navNodeRef.current) === false; + if (hasChanged) { + navNodeRef.current = _navNode; + } + + if (navNodeRef.current === undefined) { + // Adding this check for TS purpose, it should never be undefined. + throw new Error('Navnode ref is undefined.'); + } - const { navNode } = useInitNavNode(node, { cloudLinks }); + return navNodeRef.current; + }, [node, cloudLinks, deepLinks]); + + if (navNode && appendHorizontalRule) { + throw new Error( + `[Chrome navigation] Error in node [${navNode.id}]. "appendHorizontalRule" can only be added for group with children.` + ); + } useEffect(() => { - navNodeRef.current = navNode; - }, [navNode]); + if (navNode) { + return register(navNode, rootIndex); + } + return undefined; + }, [register, navNode, rootIndex]); if (!navNode) { return null; @@ -71,40 +97,34 @@ function NavigationItemComp< return {navNode.title}; } - const isRootLevel = navNode.path.length === 1; - - if (isRootLevel) { - const href = getNavigationNodeHref(navNode); - const dataTestSubj = classNames(`nav-item`, { - [`nav-item-deepLinkId-${navNode.deepLink?.id}`]: !!navNode.deepLink, - [`nav-item-isActive`]: navNode.isActive, - }); - - return ( - { - e.preventDefault(); - e.stopPropagation(); - if (href) { - navigateToUrl(href); - } - }, - }} - /> - ); - } + const isActive = isActiveFromUrl(navNode.path, activeNodes); + + const { href } = navNode; + const dataTestSubj = classNames(`nav-item`, { + [`nav-item-deepLinkId-${navNode.deepLink?.id}`]: !!navNode.deepLink, + [`nav-item-isActive`]: isActive, + }); - // We don't render anything in the UI for non root item as those register themselves on the parent (Group) - // updating its "childrenNodes" state which are then converted to "items" for the EuiCollapsibleNavItem component. - return null; + return ( + { + e.preventDefault(); + e.stopPropagation(); + if (href) { + navigateToUrl(href); + } + }, + }} + /> + ); } export const NavigationItem = React.memo(NavigationItemComp) as typeof NavigationItemComp; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx index eb12759eb09d..8e4475a979a0 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx @@ -23,9 +23,9 @@ import { } from '@elastic/eui'; import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import type { NavigateToUrlFn } from '../../../types/internal'; -import { nodePathToString } from '../../utils'; import { useNavigation as useServices } from '../../services'; import { usePanel } from './panel'; +import { isActiveFromUrl } from '../../utils'; const getStyles = (euiTheme: EuiThemeComputed<{}>) => css` * { @@ -47,17 +47,19 @@ const getStyles = (euiTheme: EuiThemeComputed<{}>) => css` interface Props { item: ChromeProjectNavigationNode; navigateToUrl: NavigateToUrlFn; + activeNodes: ChromeProjectNavigationNode[][]; } -export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl }: Props) => { +export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl, activeNodes }: Props) => { const { euiTheme } = useEuiTheme(); const { open: openPanel, close: closePanel, selectedNode } = usePanel(); const { isSideNavCollapsed } = useServices(); - const { title, deepLink, isActive, children } = item; - const id = nodePathToString(item); + const { title, deepLink, children } = item; + const { id, path } = item; const href = deepLink?.url ?? item.href; const isNotMobile = useIsWithinMinBreakpoint('s'); const isIconVisible = isNotMobile && !isSideNavCollapsed && !!children && children.length > 0; + const isActive = isActiveFromUrl(item.path, activeNodes); const itemClassNames = classNames( 'sideNavItem', @@ -65,12 +67,12 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl }: Prop getStyles(euiTheme) ); - const dataTestSubj = classNames(`nav-item`, `nav-item-${id}`, { + const dataTestSubj = classNames(`nav-item`, `nav-item-${path}`, { [`nav-item-deepLinkId-${deepLink?.id}`]: !!deepLink, [`nav-item-id-${id}`]: id, [`nav-item-isActive`]: isActive, }); - const buttonDataTestSubj = classNames(`panelOpener`, `panelOpener-${id}`, { + const buttonDataTestSubj = classNames(`panelOpener`, `panelOpener-${path}`, { [`panelOpener-deepLinkId-${deepLink?.id}`]: !!deepLink, }); @@ -113,7 +115,7 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl }: Prop {isIconVisible && ( Boolean(navNod const itemIsVisible = (item: ChromeProjectNavigationNode) => { if (item.sideNavStatus === 'hidden') return false; + if (item.renderItem) return true; + if (nodeHasLink(item)) { return true; } @@ -61,8 +66,8 @@ const getRenderAs = (navNode: ChromeProjectNavigationNode): RenderAs => { }; const getTestSubj = (navNode: ChromeProjectNavigationNode, isActive = false): string => { - const { id, deepLink } = navNode; - return classnames(`nav-item`, `nav-item-${id}`, { + const { id, path, deepLink } = navNode; + return classnames(`nav-item`, `nav-item-${path}`, { [`nav-item-deepLinkId-${deepLink?.id}`]: !!deepLink, [`nav-item-id-${id}`]: id, [`nav-item-isActive`]: isActive, @@ -79,9 +84,7 @@ const filterChildren = ( const serializeNavNode = (navNode: ChromeProjectNavigationNode) => { const serialized: ChromeProjectNavigationNode = { ...navNode, - id: nodePathToString(navNode), children: filterChildren(navNode.children), - href: getNavigationNodeHref(navNode), }; serialized.renderAs = getRenderAs(serialized); @@ -130,7 +133,7 @@ const renderBlockTitle: ( const renderGroup = ( navGroup: ChromeProjectNavigationNode, - groupItems: Array, + groupItems: Array, { spaceBefore = DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS }: { spaceBefore?: EuiThemeSize | null } = {} ): Required['items'] => { let itemPrepend: EuiCollapsibleNavItemProps | EuiCollapsibleNavSubItemProps | null = null; @@ -163,31 +166,35 @@ const nodeToEuiCollapsibleNavProps = ( closePanel, isSideNavCollapsed, treeDepth, - itemsState, + itemsAccordionState, + activeNodes, }: { navigateToUrl: NavigateToUrlFn; openPanel: PanelContext['open']; closePanel: PanelContext['close']; isSideNavCollapsed: boolean; treeDepth: number; - itemsState: AccordionItemsState; + itemsAccordionState: AccordionItemsState; + activeNodes: ChromeProjectNavigationNode[][]; } ): { - items: Array; + items: Array; isVisible: boolean; } => { const { navNode, isItem, hasChildren, hasLink } = serializeNavNode(_navNode); + const isActive = isActiveFromUrl(navNode.path, activeNodes); - const { id, title, href, icon, renderAs, isActive, spaceBefore: _spaceBefore } = navNode; - const isExternal = Boolean(href) && isAbsoluteLink(href!); + const { id, path, href, renderAs } = navNode; + const isExternal = Boolean(href) && !navNode.isElasticInternalLink && isAbsoluteLink(href!); const isAccordion = hasChildren && !isItem; - const isAccordionExpanded = (itemsState[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED) === false; + const isAccordionExpanded = + (itemsAccordionState[path]?.isCollapsed ?? DEFAULT_IS_COLLAPSED) === false; const isSelected = isAccordion && isAccordionExpanded ? false : isActive; const dataTestSubj = getTestSubj(navNode, isSelected); - let spaceBefore = _spaceBefore; + let spaceBefore = navNode.spaceBefore; if (spaceBefore === undefined && treeDepth === 1 && hasChildren) { // For groups at level 1 that don't have a space specified we default to add a "m" // space. For all other groups, unless specified, there is no vertical space. @@ -195,9 +202,15 @@ const nodeToEuiCollapsibleNavProps = ( } if (renderAs === 'panelOpener') { - const items: EuiCollapsibleNavSubItemProps[] = [ + const items: EuiCollapsibleNavSubItemPropsEnhanced[] = [ { - renderItem: () => , + renderItem: () => ( + + ), }, ]; if (spaceBefore) { @@ -227,7 +240,8 @@ const nodeToEuiCollapsibleNavProps = ( closePanel, isSideNavCollapsed, treeDepth: treeDepth + 1, - itemsState, + itemsAccordionState, + activeNodes, }) ) .filter(({ isVisible }) => isVisible) @@ -264,17 +278,30 @@ const nodeToEuiCollapsibleNavProps = ( // Render as an accordion or a link (handled by EUI) depending if // "items" is undefined or not. If it is undefined --> a link, otherwise an // accordion is rendered. - const items: Array = [ + if (navNode.renderItem) { + return { + items: [ + { + renderItem: navNode.renderItem, + }, + ], + isVisible: true, + }; + } + + const items: Array = [ + // @ts-ignore - TODO { id, - title, + path, isSelected, linkProps, onClick, href, + icon: navNode.icon, + title: navNode.title, items: subItems, ['data-test-subj']: dataTestSubj, - icon, iconProps: { size: treeDepth === 0 ? 'm' : 's' }, }, ]; @@ -317,19 +344,22 @@ interface Props { navNode: ChromeProjectNavigationNode; } -export const NavigationSectionUI: FC = ({ navNode }) => { +export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) => { + const { activeNodes } = useNavigation(); const { navigateToUrl, isSideNavCollapsed } = useServices(); + + const { navNode } = useMemo(() => serializeNavNode(_navNode), [_navNode]); const { open: openPanel, close: closePanel } = usePanel(); const navNodesById = useMemo(() => { const byId = { - [nodePathToString(navNode)]: navNode, + [navNode.path]: navNode, }; const parse = (navNodes?: ChromeProjectNavigationNode[]) => { if (!navNodes) return; navNodes.forEach((childNode) => { - byId[nodePathToString(childNode)] = childNode; + byId[childNode.path] = childNode; parse(childNode.children); }); }; @@ -338,13 +368,21 @@ export const NavigationSectionUI: FC = ({ navNode }) => { return byId; }, [navNode]); - const [itemsState, setItemsState] = useState(() => { + const [itemsAccordionState, setItemsAccordionState] = useState(() => { return Object.entries(navNodesById).reduce((acc, [_id, node]) => { if (node.children) { + let isCollapsed = DEFAULT_IS_COLLAPSED; + let doCollapseFromActiveState = true; + + if (node.defaultIsCollapsed !== undefined) { + isCollapsed = node.defaultIsCollapsed; + doCollapseFromActiveState = false; + } + acc[_id] = { - isCollapsed: !node.isActive ?? DEFAULT_IS_COLLAPSED, + isCollapsed, isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, - doCollapseFromActiveState: true, + doCollapseFromActiveState, }; } return acc; @@ -354,7 +392,8 @@ export const NavigationSectionUI: FC = ({ navNode }) => { const [subItems, setSubItems] = useState(); const toggleAccordion = useCallback((id: string) => { - setItemsState((prev) => { + setItemsAccordionState((prev) => { + // if (prev[id]?.isCollapsed === undefined) return prev; const prevValue = prev[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; return { ...prev, @@ -367,13 +406,15 @@ export const NavigationSectionUI: FC = ({ navNode }) => { }); }, []); - const setAccordionProps = useCallback( + const getAccordionProps = useCallback( ( id: string, _accordionProps?: Partial ): Partial | undefined => { - const isCollapsed = itemsState[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; - const isCollapsible = itemsState[id]?.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE; + const isCollapsed = itemsAccordionState[id]?.isCollapsed; + const isCollapsible = itemsAccordionState[id]?.isCollapsible; + + if (isCollapsed === undefined) return _accordionProps; // No state set yet let forceState: EuiAccordionProps['forceState'] = isCollapsed ? 'closed' : 'open'; if (!isCollapsible) forceState = 'open'; // Allways open if the accordion is not collapsible @@ -394,7 +435,7 @@ export const NavigationSectionUI: FC = ({ navNode }) => { return updated; }, - [itemsState, toggleAccordion] + [itemsAccordionState, toggleAccordion] ); const { items, isVisible } = useMemo(() => { @@ -404,9 +445,18 @@ export const NavigationSectionUI: FC = ({ navNode }) => { closePanel, isSideNavCollapsed, treeDepth: 0, - itemsState, + itemsAccordionState, + activeNodes, }); - }, [closePanel, isSideNavCollapsed, navNode, navigateToUrl, openPanel, itemsState]); + }, [ + navNode, + navigateToUrl, + openPanel, + closePanel, + isSideNavCollapsed, + itemsAccordionState, + activeNodes, + ]); const [props] = items; const { items: accordionItems } = props; @@ -416,58 +466,87 @@ export const NavigationSectionUI: FC = ({ navNode }) => { } /** - * Effect to set our internal state of each of the accordions (isCollapsed) based on the - * "isActive" state of the navNode. + * Effect to set the internal state of each of the accordions (isCollapsed) based on the + * "isActive" state of the navNode or if its path matches the URL location */ useEffect(() => { - setItemsState((prev) => { - return Object.entries(navNodesById).reduce((acc, [_id, node]) => { - if (node.children && (!prev[_id] || prev[_id].doCollapseFromActiveState)) { - acc[_id] = { - isCollapsed: !node.isActive ?? DEFAULT_IS_COLLAPSED, - isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, - doCollapseFromActiveState: true, - }; - } - return acc; - }, prev); + setItemsAccordionState((prev) => { + return Object.entries(navNodesById).reduce( + (acc, [_id, node]) => { + const prevState = prev[_id]; + + if ( + node.children && + node.renderAs !== 'item' && + (!prevState || prevState.doCollapseFromActiveState === true) + ) { + let nextIsActive = false; + let doCollapseFromActiveState = true; + + if (!prevState && node.defaultIsCollapsed !== undefined) { + nextIsActive = !node.defaultIsCollapsed; + doCollapseFromActiveState = false; + } else { + if (prevState?.doCollapseFromActiveState !== false) { + nextIsActive = isActiveFromUrl(node.path, activeNodes); + } else if (nextIsActive === undefined) { + nextIsActive = !DEFAULT_IS_COLLAPSED; + } + } + + acc[_id] = { + ...prevState, + isCollapsed: !nextIsActive, + isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, + doCollapseFromActiveState, + }; + } + return acc; + }, + { ...prev } + ); }); - }, [navNodesById]); + }, [navNodesById, activeNodes]); useEffect(() => { // Serializer to add recursively the accordionProps to each of the items // that will control its "open"/"closed" state + handler to toggle the state. const serializeAccordionItems = ( - _items?: EuiCollapsibleNavSubItemProps[] + _items?: EuiCollapsibleNavSubItemPropsEnhanced[] ): EuiCollapsibleNavSubItemProps[] | undefined => { if (!_items) return; - return _items.map((item: EuiCollapsibleNavSubItemProps) => { + return _items.map((item) => { if (item.renderItem) { return item; } + // @ts-ignore - TODO const parsed: EuiCollapsibleNavSubItemProps = { ...item, items: serializeAccordionItems(item.items), - accordionProps: setAccordionProps(item.id!, item.accordionProps), + accordionProps: + item.items !== undefined + ? getAccordionProps(item.path ?? item.id!, item.accordionProps) + : undefined, }; return parsed; }); }; setSubItems(serializeAccordionItems(accordionItems)); - }, [accordionItems, setAccordionProps]); + }, [accordionItems, getAccordionProps]); if (!isVisible) { return null; } return ( + // @ts-ignore - TODO ); -}; +}); diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/context.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/panel/context.tsx index f9720a38a665..7eee3515c49c 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/context.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/context.tsx @@ -9,7 +9,6 @@ import React, { type FC, useCallback, useContext, useMemo, useState, ReactNode } from 'react'; import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; -import { nodePathToString } from '../../../utils'; import { DefaultContent } from './default_content'; import { ContentProvider, PanelNavNode } from './types'; @@ -54,7 +53,7 @@ export const PanelProvider: FC = ({ children, contentProvider, activeNode return null; } - const provided = contentProvider?.(nodePathToString(selectedNode)); + const provided = contentProvider?.(selectedNode.path); if (!provided) { return ; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/default_content.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/panel/default_content.tsx index a678bad3aeae..e3a45c760225 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/default_content.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/default_content.tsx @@ -39,7 +39,7 @@ function serializeChildren(node: PanelNavNode): ChromeProjectNavigationNode[] | { id: 'root', title: '', - path: [...node.path, 'root'], + path: `${node.path}.root`, children: [...node.children], }, ]; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx index ca118249d123..ff7982417626 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx @@ -38,7 +38,9 @@ export const NavigationPanel: FC = () => { ({ target }: Event) => { // Only close if we are not clicking on the currently selected nav node if ( - !(target as HTMLButtonElement).dataset.testSubj?.includes(`panelOpener-${selectedNode?.id}`) + !(target as HTMLButtonElement).dataset.testSubj?.includes( + `panelOpener-${selectedNode?.path}` + ) ) { close(); } diff --git a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx index f423ba98d04a..e7d20a812d58 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx @@ -8,9 +8,8 @@ import React, { FC, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import type { AppDeepLinkId, NodeDefinition } from '@kbn/core-chrome-browser'; +import type { NodeDefinition } from '@kbn/core-chrome-browser'; -import { getNavigationNodeId } from '../utils'; import { Navigation } from './components'; import type { GroupDefinition, @@ -116,55 +115,12 @@ const getDefaultNavigationTree = ( }; }; -/** - * Serialize a navigation node. Currently this handler only adds an autogenerated id if it's missing - * - * @param item The navigation node - * @returns The navigation node serialized - */ -function serializeNode< - T extends { - id?: string; - link?: LinkId; - children?: Array<{ id?: string; link?: LinkId }>; - }, - LinkId extends AppDeepLinkId = AppDeepLinkId ->(item: T, depth: number, index: number): T & { id: string } { - const id = getNavigationNodeId(item, () => `node-${depth}-${index}`); - const children = item.children?.map((_item, i) => serializeNode(_item, depth + 1, i)); - - return { - ...item, - id, - children, - }; -} - -const serializeNavigationTree = (navTree: NavigationTreeDefinition): NavigationTreeDefinition => { - const serialized: NavigationTreeDefinition = { ...navTree }; - - const serialize = (item: RootNavigationItemDefinition, index: number) => { - if (item.type === 'recentlyAccessed') return item; - return serializeNode(item, 0, index); - }; - - if (navTree.body) { - serialized.body = navTree.body.map(serialize); - } - - if (navTree.footer) { - serialized.footer = navTree.footer.map(serialize); - } - - return serialized; -}; - interface Props { dataTestSubj?: string; panelContentProvider?: ContentProvider; } -export const DefaultNavigation: FC = ({ +const DefaultNavigationComp: FC = ({ projectNavigationTree, navigationTree, dataTestSubj, @@ -174,14 +130,6 @@ export const DefaultNavigation: FC = ({ throw new Error('One of navigationTree or projectNavigationTree must be defined'); } - const navigationDefinition = useMemo(() => { - const definition = !navigationTree - ? getDefaultNavigationTree(projectNavigationTree!) - : navigationTree; - - return serializeNavigationTree(definition); - }, [navigationTree, projectNavigationTree]); - const renderNodes = useCallback( (nodes: Array = []) => { return nodes.map((navNode, i) => { @@ -194,28 +142,35 @@ export const DefaultNavigation: FC = ({ } if (isGroupDefinition(navNode)) { + // Recursively build the tree return ( - - {/* Recursively build the tree */} + {renderNodes(navNode.children)} ); } - return ; + return ; }); }, [] ); + const definitionToJSX = useMemo(() => { + const definition = !navigationTree + ? getDefaultNavigationTree(projectNavigationTree!) + : navigationTree; + + const { body, footer } = definition; + return { body: renderNodes(body), footer: Boolean(footer) ? renderNodes(footer) : null }; + }, [navigationTree, projectNavigationTree, renderNodes]); + return ( - <> - {renderNodes(navigationDefinition.body)} - {navigationDefinition.footer && ( - {renderNodes(navigationDefinition.footer)} - )} - + {definitionToJSX.body} + {definitionToJSX.footer && {definitionToJSX.footer}} ); }; + +export const DefaultNavigation = React.memo(DefaultNavigationComp) as typeof DefaultNavigationComp; diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts deleted file mode 100644 index 631ad5f590ce..000000000000 --- a/packages/shared-ux/chrome/navigation/src/ui/hooks/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export { useInitNavNode } from './use_init_navnode'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts deleted file mode 100644 index f8d56bc78526..000000000000 --- a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import useObservable from 'react-use/lib/useObservable'; -import type { - AppDeepLinkId, - ChromeNavLink, - ChromeProjectNavigationNode, - CloudLinkId, - SideNavNodeStatus, -} from '@kbn/core-chrome-browser'; -import { CloudLinks } from '../../cloud_links'; - -import { useNavigation as useNavigationServices } from '../../services'; -import { getNavigationNodeId, isAbsoluteLink } from '../../utils'; -import { useNavigation } from '../components/navigation'; -import { NodePropsEnhanced, RegisterFunction, UnRegisterFunction } from '../types'; -import { useRegisterTreeNode } from './use_register_tree_node'; - -/** - * We don't have currently a way to know if a user has access to a Cloud section. - * TODO: This function will have to be revisited once we have an API from Cloud to know the user - * permissions. - */ -function hasUserAccessToCloudLink(): boolean { - return true; -} - -function getNodeStatus( - { - link, - deepLink, - cloudLink, - sideNavStatus, - }: { - link?: string; - deepLink?: ChromeNavLink; - cloudLink?: CloudLinkId; - sideNavStatus?: SideNavNodeStatus; - }, - { cloudLinks }: { cloudLinks: CloudLinks } -): SideNavNodeStatus | 'remove' { - if (link && !deepLink) { - // If a link is provided, but no deepLink is found, don't render anything - return 'remove'; - } - - if (cloudLink) { - if (!cloudLinks[cloudLink]) { - // Invalid cloudLinkId or link url has not been set in kibana.yml - return 'remove'; - } - if (!hasUserAccessToCloudLink()) return 'remove'; - } - - if (deepLink && deepLink.hidden) return 'hidden'; - - return sideNavStatus ?? 'visible'; -} - -function getTitleForNode< - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id ->( - navNode: NodePropsEnhanced, - { deepLink, cloudLinks }: { deepLink?: ChromeNavLink; cloudLinks: CloudLinks } -): string { - const { children } = navNode; - if (navNode.title) { - return navNode.title; - } - - if (typeof children === 'string') { - return children; - } - - if (deepLink?.title) { - return deepLink.title; - } - - if (navNode.cloudLink) { - return cloudLinks[navNode.cloudLink]?.title ?? ''; - } - - return ''; -} - -function validateNodeProps< - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id ->({ - id, - link, - href, - cloudLink, - renderAs, - appendHorizontalRule, - isGroup, -}: Omit, 'children'>) { - if (link && cloudLink) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. Only one of "link" or "cloudLink" can be provided.` - ); - } - if (href && cloudLink) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. Only one of "href" or "cloudLink" can be provided.` - ); - } - if (renderAs === 'panelOpener' && !link) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. If renderAs is set to "panelOpener", a "link" must also be provided.` - ); - } - if (renderAs === 'item' && !link) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. If renderAs is set to "item", a "link" must also be provided.` - ); - } - if (appendHorizontalRule && !isGroup) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. "appendHorizontalRule" can only be added for group with children.` - ); - } -} - -function createInternalNavNode< - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id ->( - id: string, - _navNode: NodePropsEnhanced, - deepLinks: Readonly, - path: string[] | null, - isActive: boolean, - { cloudLinks }: { cloudLinks: CloudLinks } -): ChromeProjectNavigationNode | null { - validateNodeProps(_navNode); - - const { children, link, cloudLink, ...navNode } = _navNode; - const deepLink = deepLinks.find((dl) => dl.id === link); - const sideNavStatus = getNodeStatus( - { - link, - deepLink, - cloudLink, - sideNavStatus: navNode.sideNavStatus, - }, - { cloudLinks } - ); - const title = getTitleForNode(_navNode, { deepLink, cloudLinks }); - const href = cloudLink ? cloudLinks[cloudLink]?.href : _navNode.href; - - if (href && !isAbsoluteLink(href)) { - throw new Error(`href must be an absolute URL. Node id [${id}].`); - } - - if (sideNavStatus === 'remove') { - return null; - } - - return { - ...navNode, - id, - path: path ?? [], - title: title ?? '', - deepLink, - href, - isActive, - sideNavStatus, - }; -} - -function isSamePath(pathA: string[] | null, pathB: string[] | null) { - if (pathA === null || pathB === null) { - return false; - } - const pathAToString = pathA.join('.'); - const pathBToString = pathB.join('.'); - return pathAToString === pathBToString; -} - -export const useInitNavNode = < - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id ->( - node: Omit, 'children'>, - { cloudLinks }: { cloudLinks: CloudLinks } -) => { - const { isActive: isActiveControlled } = node; - - /** - * Map of children nodes - */ - const [childrenNodes, setChildrenNodes] = useState>( - {} - ); - - const isMounted = useRef(false); - - /** - * Reference to the unregister function - */ - const unregisterRef = useRef(); - - /** - * Map to keep track of the order of the children when they mount. - * This allows us to keep in sync the nav tree sent to the Chrome service - * with the order of the DOM elements - */ - const orderChildrenRef = useRef>({}); - - /** - * Index to keep track of the order of the children when they mount. - */ - const idx = useRef(0); - - /** - * The current node path, including all of its parents. We'll use it to match it against - * the list of active routes based on current URL location (passed by the Chrome service) - */ - const [nodePath, setNodePath] = useState(null); - const [isActiveState, setIsActive] = useState(false); - const isActive = isActiveControlled ?? isActiveState; - - const { navLinks$ } = useNavigationServices(); - const deepLinks = useObservable(navLinks$, []); - const { register: registerNodeOnParent } = useRegisterTreeNode(); - const { activeNodes } = useNavigation(); - - const id = getNavigationNodeId(node); - - const internalNavNode = useMemo( - () => createInternalNavNode(id, node, deepLinks, nodePath, isActive, { cloudLinks }), - [node, id, deepLinks, nodePath, isActive, cloudLinks] - ); - - // Register the node on the parent whenever its properties change or whenever - // a child node is registered. - const register = useCallback(() => { - if (!internalNavNode) { - return; - } - - const children = Object.values(childrenNodes).sort((a, b) => { - const aOrder = orderChildrenRef.current[a.id]; - const bOrder = orderChildrenRef.current[b.id]; - return aOrder - bOrder; - }); - - const { unregister, path } = registerNodeOnParent({ - ...internalNavNode, - children: children.length ? children : undefined, - }); - - setNodePath((prev) => { - if (!isSamePath(prev, path)) { - return path; - } - return prev; - }); - - unregisterRef.current = unregister; - }, [internalNavNode, childrenNodes, registerNodeOnParent]); - - // Un-register from the parent. This will happen when the node is unmounted or if the deeplink - // is not active anymore. - const unregister = useCallback(() => { - if (unregisterRef.current) { - unregisterRef.current(id); - unregisterRef.current = undefined; - } - }, [id]); - - const registerChildNode = useCallback( - (childNode) => { - if (orderChildrenRef.current[childNode.id] === undefined) { - orderChildrenRef.current[childNode.id] = idx.current++; - } - - const childPath = nodePath ? [...nodePath, childNode.id] : []; - - setChildrenNodes((prev) => { - return { - ...prev, - [childNode.id]: { - ...childNode, - path: childPath, - }, - }; - }); - - return { - unregister: (childId: string) => { - setChildrenNodes((prev) => { - const updatedItems = { ...prev }; - delete updatedItems[childId]; - return updatedItems; - }); - }, - path: childPath, - }; - }, - [nodePath] - ); - - useEffect(() => { - const updatedIsActive = activeNodes.reduce((acc, nodesBranch) => { - return acc === true ? acc : nodesBranch.some((_node) => isSamePath(_node.path, nodePath)); - }, false); - - setIsActive(updatedIsActive); - }, [activeNodes, nodePath]); - - /** Register when mounting and whenever the internal nav node changes */ - useEffect(() => { - if (!isMounted.current) { - return; - } - - if (internalNavNode) { - register(); - } else { - unregister(); - } - }, [unregister, register, internalNavNode]); - - /** Unregister when unmounting */ - useEffect(() => { - isMounted.current = true; - return () => { - isMounted.current = false; - unregister(); - }; - }, [unregister]); - - return useMemo( - () => ({ - navNode: internalNavNode, - path: nodePath, - registerChildNode, - childrenNodes, - }), - [internalNavNode, registerChildNode, nodePath, childrenNodes] - ); -}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_register_tree_node.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_register_tree_node.ts deleted file mode 100644 index 5ad690b2de2e..000000000000 --- a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_register_tree_node.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { useMemo } from 'react'; - -import { useNavigation } from '../components/navigation'; -import { useNavigationGroup } from '../components/navigation_group'; - -/** - * Helper hook that will proxy the correct "register" handler. - * It first tries to the closest parent group, if not found it will use the root register. - */ -export const useRegisterTreeNode = () => { - const root = useNavigation(); - const group = useNavigationGroup(false); - const register = group ? group.register : root.register; - - return useMemo( - () => ({ - register, - }), - [register] - ); -}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index be749a5cac9b..def69d3c9df5 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -7,26 +7,22 @@ */ import { action } from '@storybook/addon-actions'; -import { useState as useStateStorybook } from '@storybook/addons'; import { ComponentMeta } from '@storybook/react'; import React, { EventHandler, FC, MouseEvent, useState, useEffect } from 'react'; -import { BehaviorSubject, of } from 'rxjs'; +import { of } from 'rxjs'; import { EuiButton, EuiCollapsibleNavBeta, EuiCollapsibleNavBetaProps, - EuiFlexGroup, - EuiFlexItem, EuiHeader, EuiHeaderSection, EuiLink, EuiPageTemplate, EuiText, - EuiTitle, } from '@elastic/eui'; -import type { ChromeNavLink, ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; +import type { ChromeNavLink } from '@kbn/core-chrome-browser'; import { NavigationStorybookMock, navLinksMock } from '../../mocks'; import mdx from '../../README.mdx'; import type { NavigationServices } from '../../types'; @@ -34,7 +30,7 @@ import { NavigationProvider } from '../services'; import { Navigation } from './components'; import { DefaultNavigation } from './default_navigation'; import { getPresets } from './nav_tree_presets'; -import type { GroupDefinition, ProjectNavigationDefinition } from './types'; +import type { ProjectNavigationDefinition } from './types'; import { ContentProvider } from './components/panel'; const storybookMock = new NavigationStorybookMock(); @@ -127,6 +123,13 @@ const deepLinks: ChromeNavLink[] = [ createDeepLink('group:settings.tracing'), ]; +const deepLinks$ = of({ + ...[...navLinksMock, ...deepLinks].reduce>((acc, navLink) => { + acc[navLink.id] = navLink; + return acc; + }, {}), +}); + const simpleNavigationDefinition: ProjectNavigationDefinition = { projectNavigationTree: [ { @@ -182,7 +185,7 @@ const simpleNavigationDefinition: ProjectNavigationDefinition = { export const SimpleObjectDefinition = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -330,7 +333,7 @@ const groupExamplesDefinition: ProjectNavigationDefinition = { export const GroupsExamples = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -342,9 +345,11 @@ export const GroupsExamples = (args: NavigationServices) => { return ( - - - + {({ isCollapsed }) => ( + + + + )} ); }; @@ -401,6 +406,7 @@ const navigationDefinition: ProjectNavigationDefinition = { { id: 'group:settings-2', title: 'Settings as nav Item', + link: 'item1', renderAs: 'item', // Render just like any other item, even if it has children children: [ { @@ -520,6 +526,7 @@ const navigationDefinition: ProjectNavigationDefinition = { id: 'test_all_hidden', title: 'Test group render as Item', renderAs: 'item', + link: 'item1', children: [ { id: 'test.item1', @@ -576,7 +583,7 @@ const navigationDefinition: ProjectNavigationDefinition = { export const ComplexObjectDefinition = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -891,6 +898,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition = { { title: 'Group renders as "item" (2)', id: 'group2.renderAsItem', + link: 'item1', renderAs: 'item', children: [ { @@ -945,6 +953,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition = { children: [ { id: 'group2-B', + link: 'item1', title: 'Group renders as "item" (3)', renderAs: 'item', // This group renders as a normal item children: [ @@ -978,6 +987,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition = { }, { title: 'Yet another group as item', + link: 'item1', renderAs: 'item', children: [ { @@ -1076,7 +1086,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition = { export const ObjectDefinitionWithPanel = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -1100,10 +1110,69 @@ export const ObjectDefinitionWithPanel = (args: NavigationServices) => { ); }; +export const WithUIComponentsTiny = (args: NavigationServices) => { + const services = storybookMock.getServices({ + ...args, + deepLinks$, + onProjectNavigationChange: (updated) => { + action('Update chrome navigation')(JSON.stringify(updated, null, 2)); + }, + recentlyAccessed$: of([ + { label: 'This is an example', link: '/app/example/39859', id: '39850' }, + { label: 'Another example', link: '/app/example/5235', id: '5235' }, + ]), + }); + + return ( + + {({ isCollapsed }) => ( + + + + + id="item1" link="item1" /> + + + id="item2" link="item1" title="YEAH!!" icon="launch" /> + + + + + + + + + + + + + + + )} + + ); +}; + export const WithUIComponents = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -1127,7 +1196,7 @@ export const WithUIComponents = (args: NavigationServices) => { defaultIsCollapsed={false} > id="item1" link="item1" /> - + {/* {(navNode) => { return (
      @@ -1135,7 +1204,7 @@ export const WithUIComponents = (args: NavigationServices) => {
      ); }} -
      +
      */}
      Title in ReactNode @@ -1224,7 +1293,7 @@ export const WithUIComponents = (args: NavigationServices) => { export const MinimalUI = (args: NavigationServices) => { const services = storybookMock.getServices({ ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), + deepLinks$, onProjectNavigationChange: (updated) => { action('Update chrome navigation')(JSON.stringify(updated, null, 2)); }, @@ -1272,230 +1341,6 @@ export const MinimalUI = (args: NavigationServices) => { ); }; -export const CreativeUI = (args: NavigationServices) => { - const services = storybookMock.getServices({ - ...args, - navLinks$: of([...navLinksMock, ...deepLinks]), - onProjectNavigationChange: (updated) => { - action('Update chrome navigation')(JSON.stringify(updated, null, 2)); - }, - recentlyAccessed$: of([ - { label: 'This is an example', link: '/app/example/39859', id: '39850' }, - { label: 'Another example', link: '/app/example/5235', id: '5235' }, - ]), - }); - - return ( - - - - - - - - -

      Hello!

      -
      - - - - -

      - As you can see there is really no limit in what UI you can create! -
      -

      -

      - Have fun! -

      -
      - - -
      -
      -
      -
      -
      -
      - ); -}; - -export const UpdatingState = (args: NavigationServices) => { - const simpleGroupDef: GroupDefinition = { - type: 'navGroup', - id: 'observability_project_nav', - title: 'Observability', - icon: 'logoObservability', - children: [ - { - id: 'aiops', - title: 'AIOps', - icon: 'branch', - children: [ - { - title: 'Anomaly detection', - id: 'ml:anomalyDetection', - link: 'ml:anomalyDetection', - }, - { - title: 'Log Rate Analysis', - id: 'ml:logRateAnalysis', - link: 'ml:logRateAnalysis', - }, - { - title: 'Change Point Detections', - link: 'ml:changePointDetections', - id: 'ml:changePointDetections', - }, - { - title: 'Job Notifications', - link: 'ml:notifications', - id: 'ml:notifications', - }, - ], - }, - { - id: 'project_settings_project_nav', - title: 'Project settings', - icon: 'gear', - children: [ - { id: 'management', link: 'management' }, - { id: 'integrations', link: 'integrations' }, - { id: 'fleet', link: 'fleet' }, - ], - }, - ], - }; - const firstSection = simpleGroupDef.children![0]; - const firstSectionFirstChild = firstSection.children![0]; - const secondSection = simpleGroupDef.children![1]; - const secondSectionFirstChild = secondSection.children![0]; - - const activeNodeSets: ChromeProjectNavigationNode[][][] = [ - [ - [ - { - ...simpleGroupDef, - path: [simpleGroupDef.id], - } as unknown as ChromeProjectNavigationNode, - { - ...firstSection, - path: [simpleGroupDef.id, firstSection.id], - } as unknown as ChromeProjectNavigationNode, - { - ...firstSectionFirstChild, - path: [simpleGroupDef.id, firstSection.id, firstSectionFirstChild.id], - } as unknown as ChromeProjectNavigationNode, - ], - ], - [ - [ - { - ...simpleGroupDef, - path: [simpleGroupDef.id], - } as unknown as ChromeProjectNavigationNode, - { - ...secondSection, - path: [simpleGroupDef.id, secondSection.id], - } as unknown as ChromeProjectNavigationNode, - { - ...secondSectionFirstChild, - path: [simpleGroupDef.id, secondSection.id, secondSectionFirstChild.id], - } as unknown as ChromeProjectNavigationNode, - ], - ], - ]; - - // use state to track which element of activeNodeSets is active - const [activeNodeIndex, setActiveNodeIndex] = useStateStorybook(0); - const changeActiveNode = () => { - const value = (activeNodeIndex + 1) % 2; // toggle between 0 and 1 - setActiveNodeIndex(value); - }; - - const activeNodes$ = new BehaviorSubject([]); - activeNodes$.next(activeNodeSets[activeNodeIndex]); - - const services = storybookMock.getServices({ - ...args, - activeNodes$, - navLinks$: of([...navLinksMock, ...deepLinks]), - onProjectNavigationChange: (updated) => { - action('Update chrome navigation')(JSON.stringify(updated, null, 2)); - }, - }); - - return ( - - - - - - ); -}; - export default { title: 'Chrome/Navigation', description: 'Navigation container to render items for cross-app linking', diff --git a/packages/shared-ux/chrome/navigation/src/ui/types.ts b/packages/shared-ux/chrome/navigation/src/ui/types.ts index 9051cc3747bf..768155ced305 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/types.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/types.ts @@ -30,26 +30,15 @@ export interface NodeProps< * Children of the node. For Navigation.Item (only) it allows a function to be set. * This function will receive the ChromeProjectNavigationNode object */ - children?: ((navNode: ChromeProjectNavigationNode) => ReactNode) | ReactNode; -} - -/** - * @internal - * - * Internally we enhance the Props passed to the Navigation.Item component. - */ -export interface NodePropsEnhanced< - LinkId extends AppDeepLinkId = AppDeepLinkId, - Id extends string = string, - ChildrenId extends string = Id -> extends NodeProps { - /** - * Forces the node to be active. This is used to force a collapisble nav group to be open - * even if the URL does not match any of the nodes in the group. - */ - isActive?: boolean; - /** Flag to indicate if the navigation node is a group or not */ - isGroup: boolean; + children?: ReactNode; + /** @internal - Prop internally controlled, don't use it. */ + parentNodePath?: string; + /** @internal - Prop internally controlled, don't use it. */ + rootIndex?: number; + /** @internal - Prop internally controlled, don't use it. */ + treeDepth?: number; + /** @internal - Prop internally controlled, don't use it. */ + index?: number; } /** The preset that can be pass to the NavigationBucket component */ @@ -181,16 +170,14 @@ export interface ProjectNavigationDefinition< * * Function to unregister a navigation node from its parent. */ -export type UnRegisterFunction = (id: string) => void; +export type UnRegisterFunction = () => void; /** * @internal * * A function to register a navigation node on its parent. */ -export type RegisterFunction = (navNode: ChromeProjectNavigationNode) => { - /** The function to unregister the node. */ - unregister: UnRegisterFunction; - /** The full path of the node in the navigation tree. */ - path: string[]; -}; +export type RegisterFunction = ( + navNode: ChromeProjectNavigationNode, + order?: number +) => UnRegisterFunction; diff --git a/packages/shared-ux/chrome/navigation/src/utils.ts b/packages/shared-ux/chrome/navigation/src/utils.ts index 8322fe797590..efbf3c0e2a42 100644 --- a/packages/shared-ux/chrome/navigation/src/utils.ts +++ b/packages/shared-ux/chrome/navigation/src/utils.ts @@ -6,11 +6,16 @@ * Side Public License, v 1. */ +import React, { type ReactNode } from 'react'; import type { ChromeProjectNavigationNode, NodeDefinition } from '@kbn/core-chrome-browser'; +import { NavigationFooter } from './ui/components/navigation_footer'; +import { NavigationGroup } from './ui/components/navigation_group'; +import { NavigationItem } from './ui/components/navigation_item'; +import { RecentlyAccessed } from './ui/components/recently_accessed'; let uniqueId = 0; -function generateUniqueNodeId() { +export function generateUniqueNodeId() { const id = `node${uniqueId++}`; return id; } @@ -19,15 +24,6 @@ export function isAbsoluteLink(link: string) { return link.startsWith('http://') || link.startsWith('https://'); } -export function nodePathToString( - node?: T -): T extends { path?: string[]; id: string } ? string : undefined { - if (!node) return undefined as T extends { path?: string[]; id: string } ? string : undefined; - return (node.path ? node.path.join('.') : node.id) as T extends { path?: string[]; id: string } - ? string - : undefined; -} - export function isGroupNode({ children }: Pick) { return children !== undefined; } @@ -50,3 +46,37 @@ export function getNavigationNodeHref({ }: Pick): string | undefined { return deepLink?.url ?? href; } + +function isSamePath(pathA: string | null, pathB: string | null) { + if (pathA === null || pathB === null) { + return false; + } + return pathA === pathB; +} + +export function isActiveFromUrl(nodePath: string, activeNodes: ChromeProjectNavigationNode[][]) { + return activeNodes.reduce((acc, nodesBranch) => { + return acc === true ? acc : nodesBranch.some((branch) => isSamePath(branch.path, nodePath)); + }, false); +} + +type ChildType = 'item' | 'group' | 'recentlyAccessed' | 'footer' | 'unknown'; + +export const getChildType = (child: ReactNode): ChildType => { + if (!React.isValidElement(child)) { + return 'unknown'; + } + + switch (child.type) { + case NavigationItem: + return 'item'; + case NavigationGroup: + return 'group'; + case RecentlyAccessed: + return 'recentlyAccessed'; + case NavigationFooter: + return 'footer'; + default: + return 'unknown'; + } +}; diff --git a/packages/shared-ux/chrome/navigation/types/index.ts b/packages/shared-ux/chrome/navigation/types/index.ts index e162e395362a..43ff4083ba41 100644 --- a/packages/shared-ux/chrome/navigation/types/index.ts +++ b/packages/shared-ux/chrome/navigation/types/index.ts @@ -24,7 +24,7 @@ import type { CloudLinks } from '../src/cloud_links'; export interface NavigationServices { basePath: BasePathService; recentlyAccessed$: Observable; - navLinks$: Observable>; + deepLinks$: Observable>>; navIsOpen: boolean; navigateToUrl: NavigateToUrlFn; onProjectNavigationChange: (chromeProjectNavigation: ChromeProjectNavigation) => void; diff --git a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.component.tsx b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.component.tsx index 96e80af24651..3705b5885f1a 100644 --- a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.component.tsx +++ b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.component.tsx @@ -29,6 +29,7 @@ export const RedirectAppLinks: FC = ({ children, navigateToUrl, currentAppId, + ...containerProps }) => { const containerRef = useRef(null); @@ -50,6 +51,7 @@ export const RedirectAppLinks: FC = ({ ref={containerRef} css={redirectAppLinksStyles} data-test-subj="kbnRedirectAppLink" + {...containerProps} > {children}
      diff --git a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx index 9a069881b212..da227ab023cb 100644 --- a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx +++ b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.container.tsx @@ -7,6 +7,7 @@ */ import React, { FC } from 'react'; +import type { RedirectAppLinksComponentProps } from '@kbn/shared-ux-link-redirect-app-types'; import { useServices } from './services'; import { RedirectAppLinks as Component } from './redirect_app_links.component'; @@ -22,6 +23,11 @@ import { RedirectAppLinks as Component } from './redirect_app_links.component'; * * ``` */ -export const RedirectAppLinks: FC<{}> = ({ children }) => ( - {children} +export const RedirectAppLinks: FC> = ({ + children, + ...props +}) => ( + + {children} + ); diff --git a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.tsx b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.tsx index 2909dcdbda17..89d8a61531e9 100644 --- a/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.tsx +++ b/packages/shared-ux/link/redirect_app/impl/src/redirect_app_links.tsx @@ -25,10 +25,11 @@ const isKibanaContract = (services: any): services is RedirectAppLinksKibanaDepe * with which consumers can wrap their components or solutions. */ export const RedirectAppLinks: FC = ({ children, ...props }) => { - const container = {children}; - if (isKibanaContract(props)) { - const { coreStart } = props; + const { coreStart, ...containerProps } = props; + const container = ( + {children} + ); return ( {container} @@ -36,7 +37,10 @@ export const RedirectAppLinks: FC = ({ children, ...props ); } - const { navigateToUrl, currentAppId } = props; + const { navigateToUrl, currentAppId, ...containerProps } = props; + const container = ( + {children} + ); return ( {container} diff --git a/packages/shared-ux/link/redirect_app/types/index.d.ts b/packages/shared-ux/link/redirect_app/types/index.d.ts index 186e86af8943..01899edea65d 100644 --- a/packages/shared-ux/link/redirect_app/types/index.d.ts +++ b/packages/shared-ux/link/redirect_app/types/index.d.ts @@ -32,7 +32,11 @@ export interface RedirectAppLinksKibanaDependencies { } /** Props for the `RedirectAppLinks` component. */ -export type RedirectAppLinksProps = RedirectAppLinksServices | RedirectAppLinksKibanaDependencies; +export type RedirectAppLinksProps = ( + | RedirectAppLinksServices + | RedirectAppLinksKibanaDependencies +) & + DetailedHTMLProps, HTMLDivElement>; /** Props for the `RedirectAppLinksComponent`. */ export interface RedirectAppLinksComponentProps diff --git a/preinstall_check.js b/preinstall_check.js index d6d0cdf1ffb4..59a4cfd2aa4a 100644 --- a/preinstall_check.js +++ b/preinstall_check.js @@ -10,7 +10,7 @@ const isUsingNpm = process.env.npm_config_git !== undefined; if (isUsingNpm) { - throw `Use Yarn instead of npm, see Kibana's contributing guidelines`; + throw new Error(`Use Yarn instead of npm, see Kibana's contributing guidelines`); } // The value of the `npm_config_argv` env for each command: diff --git a/renovate.json b/renovate.json index e4c1e0672c78..4a725ce80a5f 100644 --- a/renovate.json +++ b/renovate.json @@ -458,11 +458,37 @@ "matchPackagePatterns": [ "^@storybook" ], + "excludePackageNames": [ + "@storybook/testing-react" + ], "labels": [ "Team:Operations", - "release_note:skip" + "release_note:skip", + "ci:build-storybooks", + "backport:skip" ], - "enabled": true + "enabled": true, + "allowedVersions": "<7.0" + }, + { + "groupName": "@storybook/testing-react", + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "matchPackageNames": [ + "@storybook/testing-react" + ], + "labels": [ + "Team:Operations", + "release_note:skip", + "ci:build-storybooks", + "backport:skip" + ], + "enabled": true, + "allowedVersions": "<2.0" }, { "groupName": "react-query", @@ -647,4 +673,4 @@ "enabled": true } ] -} +} \ No newline at end of file diff --git a/scripts/es.js b/scripts/es.js index 1fcd221c9790..1cee27b7685b 100644 --- a/scripts/es.js +++ b/scripts/es.js @@ -20,6 +20,7 @@ kbnEs 'source-path': resolve(__dirname, '../../elasticsearch'), 'base-path': resolve(__dirname, '../.es'), ssl: false, + kibanaUrl: 'https://localhost:5601/', }) .catch(function (e) { console.error(e); diff --git a/src/cli/serve/integration_tests/invalid_config.test.ts b/src/cli/serve/integration_tests/invalid_config.test.ts index 32414fe7f89f..ba9ee113ee76 100644 --- a/src/cli/serve/integration_tests/invalid_config.test.ts +++ b/src/cli/serve/integration_tests/invalid_config.test.ts @@ -41,7 +41,7 @@ describe('cli invalid config support', () => { .split('\n') .filter(Boolean) .map((line) => JSON.parse(line) as LogEntry) - .filter((line) => line.log.level === 'FATAL'); + .filter((line) => line.log?.level === 'FATAL'); } catch (e) { throw new Error( `error parsing log output:\n\n${e.stack}\n\nstdout: \n${stdout}\n\nstderr:\n${stderr}` diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 911eecd45a9f..75a18378f56b 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -109,6 +109,38 @@ export function applyConfigOverrides(rawConfig, opts, extraCliOptions) { if (opts.dev) { if (opts.serverless) { setServerlessKibanaDevServiceAccountIfPossible(get, set, opts); + + // Load mock identity provider plugin and configure realm if supported (ES only supports SAML when run with SSL) + if (opts.ssl && canRequire('@kbn/mock-idp-plugin/common')) { + // Ensure the plugin is loaded in dynamically to exclude from production build + const { + MOCK_IDP_PLUGIN_PATH, + MOCK_IDP_REALM_NAME, + } = require('@kbn/mock-idp-plugin/common'); + + if (has('server.basePath')) { + console.log( + `Custom base path is not supported when running in Serverless, it will be removed.` + ); + _.unset(rawConfig, 'server.basePath'); + } + + set('plugins.paths', _.compact([].concat(get('plugins.paths'), MOCK_IDP_PLUGIN_PATH))); + set(`xpack.security.authc.providers.saml.${MOCK_IDP_REALM_NAME}`, { + order: Number.MAX_SAFE_INTEGER, + realm: MOCK_IDP_REALM_NAME, + icon: 'user', + description: 'Continue as Test User', + hint: 'Allows testing serverless user roles', + }); + // Add basic realm since defaults won't be applied when a provider has been configured + if (!has('xpack.security.authc.providers.basic')) { + set('xpack.security.authc.providers.basic.basic', { + order: 0, + enabled: true, + }); + } + } } if (!has('elasticsearch.serviceAccountToken') && opts.devCredentials !== false) { @@ -274,7 +306,9 @@ export default function (program) { // We can tell users they only have to run with `yarn start --run-examples` to get those // local links to work. Similar to what we do for "View in Console" links in our // elastic.co links. - basePath: opts.runExamples ? false : !!opts.basePath, + // We also want to run without base path when running in serverless mode so that Elasticsearch can + // connect to Kibana's mock identity provider. + basePath: opts.runExamples || isServerlessMode ? false : !!opts.basePath, optimize: !!opts.optimize, disableOptimizer: !opts.optimizer, oss: !!opts.oss, diff --git a/src/cli/tsconfig.json b/src/cli/tsconfig.json index ebbbc19f75c7..3b3c0854975d 100644 --- a/src/cli/tsconfig.json +++ b/src/cli/tsconfig.json @@ -17,6 +17,7 @@ "@kbn/config", "@kbn/dev-utils", "@kbn/apm-config-loader", + "@kbn/mock-idp-plugin", ], "exclude": [ "target/**/*", diff --git a/src/core/public/index.ts b/src/core/public/index.ts index b874a937257b..6b29603dd63f 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -187,6 +187,7 @@ export type { HttpResponse, HttpHandler, IBasePath, + IStaticAssets, IAnonymousPaths, IExternalUrl, IHttpInterceptController, diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 30562d389ac4..3e63315e6d8f 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -184,6 +184,7 @@ export type { ICspConfig, IExternalUrlConfig, IBasePath, + IStaticAssets, SessionStorage, SessionStorageCookieOptions, SessionCookieValidationResult, diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 2bc127bcadcf..43920d3bbbe2 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -57,7 +57,7 @@ describe('checking migration metadata changes on all registered SO types', () => Object { "action": "cc93fe2c0c76e57c2568c63170e05daea897c136", "action_task_params": "96e27e7f4e8273ffcd87060221e2b75e81912dd5", - "alert": "dc710bc17dfc98a9a703d388569abccce5f8bf07", + "alert": "3a67d3f1db80af36bd57aaea47ecfef87e43c58f", "api_key_pending_invalidation": "1399e87ca37b3d3a65d269c924eda70726cfe886", "apm-custom-dashboards": "b67128f78160c288bd7efe25b2da6e2afd5e82fc", "apm-indices": "8a2d68d415a4b542b26b0d292034a28ffac6fed4", @@ -84,7 +84,7 @@ describe('checking migration metadata changes on all registered SO types', () => "dashboard": "0611794ce10d25a36da0770c91376c575e92e8f2", "endpoint:user-artifact-manifest": "1c3533161811a58772e30cdc77bac4631da3ef2b", "enterprise_search_telemetry": "9ac912e1417fc8681e0cd383775382117c9e3d3d", - "epm-packages": "2449bb565f987eff70b1b39578bb17e90c404c6e", + "epm-packages": "c23d3d00c051a08817335dba26f542b64b18a56a", "epm-packages-assets": "7a3e58efd9a14191d0d1a00b8aaed30a145fd0b1", "event-annotation-group": "715ba867d8c68f3c9438052210ea1c30a9362582", "event_loop_delays_daily": "01b967e8e043801357503de09199dfa3853bab88", @@ -106,7 +106,7 @@ describe('checking migration metadata changes on all registered SO types', () => "infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4", "ingest-agent-policies": "7633e578f60c074f8267bc50ec4763845e431437", "ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d", - "ingest-outputs": "8546f1123ec30dcbd6f238f72729c5f1656a4d9b", + "ingest-outputs": "20bd44ce6016079c3b28f1b2bc241e7715be48f8", "ingest-package-policies": "f4c2767e852b700a8b82678925b86bac08958b43", "ingest_manager_settings": "64955ef1b7a9ffa894d4bb9cf863b5602bfa6885", "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", @@ -142,7 +142,7 @@ describe('checking migration metadata changes on all registered SO types', () => "siem-ui-timeline": "d3de8ff3617be8f2a799d66b1471b9be6124bf40", "siem-ui-timeline-note": "0a32fb776907f596bedca292b8c646496ae9c57b", "siem-ui-timeline-pinned-event": "082daa3ce647b33873f6abccf340bdfa32057c8d", - "slo": "9a9995e4572de1839651c43b5fc4dc8276bb5815", + "slo": "2048ab6791df2e1ae0936f29c20765cb8d2fcfaa", "space": "8de4ec513e9bbc6b2f1d635161d850be7747d38e", "spaces-usage-stats": "3abca98713c52af8b30300e386c7779b3025a20e", "synthetics-monitor": "33ddc4b8979f378edf58bcc7ba13c5c5b572f42d", diff --git a/src/core/server/integration_tests/elasticsearch/error_logging.test.ts b/src/core/server/integration_tests/elasticsearch/error_logging.test.ts index 8cd4f5ae4113..f8deaa41ee86 100644 --- a/src/core/server/integration_tests/elasticsearch/error_logging.test.ts +++ b/src/core/server/integration_tests/elasticsearch/error_logging.test.ts @@ -86,6 +86,7 @@ describe('Error logging', () => { name: 'ResponseError', process: { pid: expect.any(Number), + uptime: expect.any(Number), }, }); } diff --git a/src/core/server/integration_tests/http/http_server.test.ts b/src/core/server/integration_tests/http/http_server.test.ts index f65a5b59487b..b901f7f85cb6 100644 --- a/src/core/server/integration_tests/http/http_server.test.ts +++ b/src/core/server/integration_tests/http/http_server.test.ts @@ -36,6 +36,7 @@ describe('Http server', () => { allowFromAnyIp: true, ipAllowlist: [], }, + cdn: {}, cors: { enabled: false, }, @@ -51,7 +52,7 @@ describe('Http server', () => { beforeEach(async () => { shutdownTimeout = config.shutdownTimeout.asMilliseconds(); - const { registerRouter, server: innerServer } = await server.setup(config); + const { registerRouter, server: innerServer } = await server.setup({ config$: of(config) }); innerServerListener = innerServer.listener; const router = new Router('', logger, enhanceWithContext, { diff --git a/src/core/server/integration_tests/http/router.test.ts b/src/core/server/integration_tests/http/router.test.ts index 1e5b28413451..f66cab0a07f5 100644 --- a/src/core/server/integration_tests/http/router.test.ts +++ b/src/core/server/integration_tests/http/router.test.ts @@ -408,7 +408,7 @@ describe('Options', () => { }); describe('idleSocket', () => { - it.skip('should timeout if payload sending has too long of an idle period', async () => { + it('should timeout if payload sending has too long of an idle period', async () => { const { server: innerServer, createRouter } = await server.setup(setupDeps); const router = createRouter('/'); @@ -420,7 +420,7 @@ describe('Options', () => { body: { accepts: ['application/json'], }, - timeout: { idleSocket: 10 }, + timeout: { idleSocket: 5 }, }, }, async (context, req, res) => { diff --git a/src/core/server/integration_tests/http/set_tls_config.test.ts b/src/core/server/integration_tests/http/set_tls_config.test.ts new file mode 100644 index 000000000000..6c198d820670 --- /dev/null +++ b/src/core/server/integration_tests/http/set_tls_config.test.ts @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import supertest from 'supertest'; +import { KBN_CERT_PATH, KBN_KEY_PATH, ES_KEY_PATH, ES_CERT_PATH } from '@kbn/dev-utils'; +import { + createServer, + getListenerOptions, + getServerOptions, + setTlsConfig, +} from '@kbn/server-http-tools'; +import { + HttpConfig, + config as httpConfig, + cspConfig, + externalUrlConfig, +} from '@kbn/core-http-server-internal'; +import { flattenCertificateChain, fetchPeerCertificate, isServerTLS } from './tls_utils'; + +describe('setTlsConfig', () => { + const CSP_CONFIG = cspConfig.schema.validate({}); + const EXTERNAL_URL_CONFIG = externalUrlConfig.schema.validate({}); + + beforeAll(() => { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + }); + + it('replaces the TLS configuration on the HAPI server', async () => { + const rawHttpConfig = httpConfig.schema.validate({ + name: 'kibana', + host: '127.0.0.1', + port: 10002, + ssl: { + enabled: true, + certificate: KBN_CERT_PATH, + key: KBN_KEY_PATH, + cipherSuites: ['TLS_AES_256_GCM_SHA384'], + redirectHttpFromPort: 10003, + }, + shutdownTimeout: '1s', + }); + const firstConfig = new HttpConfig(rawHttpConfig, CSP_CONFIG, EXTERNAL_URL_CONFIG); + + const serverOptions = getServerOptions(firstConfig); + const listenerOptions = getListenerOptions(firstConfig); + const server = createServer(serverOptions, listenerOptions); + + server.route({ + method: 'GET', + path: '/', + handler: (request, toolkit) => { + return toolkit.response('ok'); + }, + }); + + await server.start(); + + const listener = server.listener; + + // force TS to understand what we're working with. + if (!isServerTLS(listener)) { + throw new Error('Server should be a TLS server'); + } + + const certificate = await fetchPeerCertificate(firstConfig.host, firstConfig.port); + const certificateChain = flattenCertificateChain(certificate); + + expect(isServerTLS(listener)).toEqual(true); + expect(certificateChain.length).toEqual(1); + expect(certificateChain[0].subject.CN).toEqual('kibana'); + + await supertest(listener).get('/').expect(200); + + const secondRawConfig = httpConfig.schema.validate({ + name: 'kibana', + host: '127.0.0.1', + port: 10002, + ssl: { + enabled: true, + certificate: ES_CERT_PATH, + key: ES_KEY_PATH, + cipherSuites: ['TLS_AES_256_GCM_SHA384'], + redirectHttpFromPort: 10003, + }, + shutdownTimeout: '1s', + }); + + const secondConfig = new HttpConfig(secondRawConfig, CSP_CONFIG, EXTERNAL_URL_CONFIG); + + setTlsConfig(server, secondConfig.ssl); + + const secondCertificate = await fetchPeerCertificate(firstConfig.host, firstConfig.port); + const secondCertificateChain = flattenCertificateChain(secondCertificate); + + expect(secondCertificateChain.length).toEqual(1); + expect(secondCertificateChain[0].subject.CN).toEqual('elasticsearch'); + + await supertest(listener).get('/').expect(200); + + await server.stop(); + }); +}); diff --git a/src/core/server/integration_tests/http/tls_config_reload.test.ts b/src/core/server/integration_tests/http/tls_config_reload.test.ts new file mode 100644 index 000000000000..b0c8f6abf5e5 --- /dev/null +++ b/src/core/server/integration_tests/http/tls_config_reload.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import supertest from 'supertest'; +import { duration } from 'moment'; +import { BehaviorSubject, of } from 'rxjs'; +import { KBN_CERT_PATH, KBN_KEY_PATH, ES_KEY_PATH, ES_CERT_PATH } from '@kbn/dev-utils'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { Router } from '@kbn/core-http-router-server-internal'; +import { + HttpServer, + HttpConfig, + config as httpConfig, + cspConfig, + externalUrlConfig, +} from '@kbn/core-http-server-internal'; +import { isServerTLS, flattenCertificateChain, fetchPeerCertificate } from './tls_utils'; + +const CSP_CONFIG = cspConfig.schema.validate({}); +const EXTERNAL_URL_CONFIG = externalUrlConfig.schema.validate({}); +const enhanceWithContext = (fn: (...args: any[]) => any) => fn.bind(null, {}); + +describe('HttpServer - TLS config', () => { + let server: HttpServer; + let logger: ReturnType; + + beforeAll(() => { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + }); + + beforeEach(() => { + const loggingService = loggingSystemMock.create(); + logger = loggingSystemMock.createLogger(); + server = new HttpServer(loggingService, 'tests', of(duration('1s'))); + }); + + it('supports dynamic reloading of the TLS configuration', async () => { + const rawHttpConfig = httpConfig.schema.validate({ + name: 'kibana', + host: '127.0.0.1', + port: 10002, + ssl: { + enabled: true, + certificate: KBN_CERT_PATH, + key: KBN_KEY_PATH, + cipherSuites: ['TLS_AES_256_GCM_SHA384'], + redirectHttpFromPort: 10003, + }, + shutdownTimeout: '1s', + }); + const firstConfig = new HttpConfig(rawHttpConfig, CSP_CONFIG, EXTERNAL_URL_CONFIG); + + const config$ = new BehaviorSubject(firstConfig); + + const { server: innerServer, registerRouter } = await server.setup({ config$ }); + const listener = innerServer.listener; + + const router = new Router('', logger, enhanceWithContext, { + isDev: false, + versionedRouteResolution: 'oldest', + }); + router.get( + { + path: '/', + validate: false, + }, + async (ctx, req, res) => { + return res.ok({ + body: 'ok', + }); + } + ); + registerRouter(router); + + await server.start(); + + // force TS to understand what we're working with. + if (!isServerTLS(listener)) { + throw new Error('Server should be a TLS server'); + } + + const certificate = await fetchPeerCertificate(firstConfig.host, firstConfig.port); + const certificateChain = flattenCertificateChain(certificate); + + expect(certificateChain.length).toEqual(1); + expect(certificateChain[0].subject.CN).toEqual('kibana'); + + await supertest(listener).get('/').expect(200); + + const secondRawConfig = httpConfig.schema.validate({ + name: 'kibana', + host: '127.0.0.1', + port: 10002, + ssl: { + enabled: true, + certificate: ES_CERT_PATH, + key: ES_KEY_PATH, + cipherSuites: ['TLS_AES_256_GCM_SHA384'], + redirectHttpFromPort: 10003, + }, + shutdownTimeout: '1s', + }); + + const secondConfig = new HttpConfig(secondRawConfig, CSP_CONFIG, EXTERNAL_URL_CONFIG); + config$.next(secondConfig); + + const secondCertificate = await fetchPeerCertificate(firstConfig.host, firstConfig.port); + const secondCertificateChain = flattenCertificateChain(secondCertificate); + + expect(secondCertificateChain.length).toEqual(1); + expect(secondCertificateChain[0].subject.CN).toEqual('elasticsearch'); + + await supertest(listener).get('/').expect(200); + + await server.stop(); + }); +}); diff --git a/src/core/server/integration_tests/http/tls_utils.ts b/src/core/server/integration_tests/http/tls_utils.ts new file mode 100644 index 000000000000..e565a61ae5dc --- /dev/null +++ b/src/core/server/integration_tests/http/tls_utils.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Server as NodeHttpServer } from 'http'; +import { Server as NodeTlsServer } from 'https'; +import tls from 'tls'; + +export function isServerTLS(server: NodeHttpServer): server is NodeTlsServer { + return 'setSecureContext' in server; +} + +export const fetchPeerCertificate = (host: string, port: number) => { + return new Promise((resolve, reject) => { + const socket = tls.connect({ host, port: Number(port), rejectUnauthorized: false }); + socket.once('secureConnect', () => { + const cert = socket.getPeerCertificate(true); + socket.destroy(); + resolve(cert); + }); + socket.once('error', reject); + }); +}; + +export const flattenCertificateChain = ( + cert: tls.DetailedPeerCertificate, + accumulator: tls.DetailedPeerCertificate[] = [] +) => { + accumulator.push(cert); + if (cert.issuerCertificate && cert.fingerprint256 !== cert.issuerCertificate.fingerprint256) { + flattenCertificateChain(cert.issuerCertificate, accumulator); + } + return accumulator; +}; diff --git a/src/core/server/integration_tests/saved_objects/service/lib/bulk_update.test.ts b/src/core/server/integration_tests/saved_objects/service/lib/bulk_update.test.ts new file mode 100644 index 000000000000..dc620f87ea55 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/service/lib/bulk_update.test.ts @@ -0,0 +1,234 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import fs from 'fs/promises'; +import { pick } from 'lodash'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { SavedObjectsType, SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { type TestElasticsearchUtils } from '@kbn/core-test-helpers-kbn-server'; +import '../../migrations/jest_matchers'; +import { + getKibanaMigratorTestKit, + startElasticsearch, +} from '../../migrations/kibana_migrator_test_kit'; +import { delay } from '../../migrations/test_utils'; +import { getBaseMigratorParams } from '../../migrations/fixtures/zdt_base.fixtures'; + +export const logFilePath = Path.join(__dirname, 'bulk_update.test.log'); + +describe('SOR - bulk_update API', () => { + let esServer: TestElasticsearchUtils['es']; + + beforeAll(async () => { + await fs.unlink(logFilePath).catch(() => {}); + esServer = await startElasticsearch(); + }); + + const getType = (version: 'v1' | 'v2'): SavedObjectsType => { + const versionMap: SavedObjectsModelVersionMap = { + 1: { + changes: [], + schemas: { + forwardCompatibility: (attributes) => { + return pick(attributes, 'count'); + }, + }, + }, + }; + + if (version === 'v2') { + versionMap[2] = { + changes: [ + { + type: 'data_backfill', + backfillFn: (document) => { + return { attributes: { even: document.attributes.count % 2 === 0 } }; + }, + }, + ], + }; + } + + return { + name: 'my-test-type', + hidden: false, + namespaceType: 'agnostic', + mappings: { + dynamic: false, + properties: { + count: { type: 'integer' }, + ...(version === 'v2' ? { even: { type: 'boolean' } } : {}), + }, + }, + management: { + importableAndExportable: true, + }, + switchToModelVersionAt: '8.10.0', + modelVersions: versionMap, + }; + }; + + const getOtherType = (version: 'v1' | 'v2'): SavedObjectsType => { + const versionOtherMap: SavedObjectsModelVersionMap = { + 1: { + changes: [], + schemas: { + forwardCompatibility: (attributes) => { + return pick(attributes, 'sum'); + }, + }, + }, + }; + + if (version === 'v2') { + versionOtherMap[2] = { + changes: [ + { + type: 'data_backfill', + backfillFn: (document) => { + return { attributes: { isodd: document.attributes.sum % 2 !== 0 } }; + }, + }, + ], + }; + } + + return { + name: 'my-other-test-type', + hidden: false, + namespaceType: 'agnostic', + mappings: { + dynamic: false, + properties: { + sum: { type: 'integer' }, + ...(version === 'v2' ? { isodd: { type: 'boolean' } } : {}), + }, + }, + management: { + importableAndExportable: true, + }, + switchToModelVersionAt: '8.10.0', + modelVersions: versionOtherMap, + }; + }; + afterAll(async () => { + await esServer?.stop(); + await delay(10); + }); + + const setup = async () => { + const { runMigrations: runMigrationV1, savedObjectsRepository: repositoryV1 } = + await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + types: [getType('v1'), getOtherType('v1')], + }); + await runMigrationV1(); + + const { + runMigrations: runMigrationV2, + savedObjectsRepository: repositoryV2, + client: esClient, + } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + types: [getType('v2'), getOtherType('v2')], + }); + await runMigrationV2(); + + return { repositoryV1, repositoryV2, esClient }; + }; + + it('supports updates between older and newer versions', async () => { + const { repositoryV1, repositoryV2, esClient } = await setup(); + + await repositoryV1.create('my-test-type', { count: 12 }, { id: 'my-id' }); + await repositoryV1.create('my-other-test-type', { sum: 24 }, { id: 'my-other-id' }); + + let repoV2Docs = await repositoryV2.bulkGet([ + { type: 'my-test-type', id: 'my-id' }, + { type: 'my-other-test-type', id: 'my-other-id' }, + ]); + const [doc, otherDoc] = repoV2Docs.saved_objects; + + expect(doc.attributes).toEqual({ + count: 12, + even: true, + }); + expect(otherDoc.attributes).toEqual({ + sum: 24, + isodd: false, + }); + + await repositoryV2.bulkUpdate([ + { type: 'my-test-type', id: doc.id, attributes: { count: 11, even: false } }, + // @ts-expect-error cannot assign to partial + { type: 'my-other-test-type', id: otherDoc.id, attributes: { sum: 23, isodd: true } }, + ]); + + const repoV1Docs = await repositoryV1.bulkGet([ + { type: 'my-test-type', id: 'my-id' }, + { type: 'my-other-test-type', id: 'my-other-id' }, + ]); + const [doc1, otherDoc1] = repoV1Docs.saved_objects; + + expect(doc1.attributes).toEqual({ + count: 11, + }); + expect(otherDoc1.attributes).toEqual({ + sum: 23, + }); + + await repositoryV1.bulkUpdate([ + { type: 'my-test-type', id: doc1.id, attributes: { count: 14 } }, + // @ts-expect-error cannot assign to partial + { type: 'my-other-test-type', id: otherDoc1.id, attributes: { sum: 24 } }, + ]); + + repoV2Docs = await repositoryV2.bulkGet([ + { type: 'my-test-type', id: 'my-id' }, + { type: 'my-other-test-type', id: 'my-other-id' }, + ]); + const [doc2, otherDoc2] = repoV2Docs.saved_objects; + + expect(doc2.attributes).toEqual({ + count: 14, + even: true, + }); + expect(otherDoc2.attributes).toEqual({ + sum: 24, + isodd: false, + }); + + const rawDoc = await fetchDoc(esClient, 'my-test-type', 'my-id'); + expect(rawDoc._source).toEqual( + expect.objectContaining({ + typeMigrationVersion: '10.1.0', + 'my-test-type': { + count: 14, + }, + }) + ); + + const otherRawDoc = await fetchDoc(esClient, 'my-other-test-type', 'my-other-id'); + expect(otherRawDoc._source).toEqual( + expect.objectContaining({ + typeMigrationVersion: '10.1.0', + 'my-other-test-type': { + sum: 24, + }, + }) + ); + }); + + const fetchDoc = async (client: ElasticsearchClient, type: string, id: string) => { + return await client.get({ + index: '.kibana', + id: `${type}:${id}`, + }); + }; +}); diff --git a/src/core/server/integration_tests/ui_settings/routes.test.ts b/src/core/server/integration_tests/ui_settings/routes.test.ts index 6999731947d8..078946a7a9ab 100644 --- a/src/core/server/integration_tests/ui_settings/routes.test.ts +++ b/src/core/server/integration_tests/ui_settings/routes.test.ts @@ -156,6 +156,47 @@ describe('ui settings service', () => { }); }); + describe('validate', () => { + it('returns correct validation error message for invalid value', async () => { + const response = await request + .post(root, '/internal/kibana/settings/custom/validate') + .send({ value: 100 }) + .expect(200); + + expect(response.body).toMatchObject({ + valid: false, + errorMessage: 'expected value of type [string] but got [number]', + }); + }); + + it('returns no validation error message for valid value', async () => { + const response = await request + .post(root, '/internal/kibana/settings/custom/validate') + .send({ value: 'test' }) + .expect(200); + + expect(response.body).toMatchObject({ valid: true }); + }); + + it('returns a 404 for non-existing key', async () => { + const response = await request + .post(root, '/internal/kibana/settings/test/validate') + .send({ value: 'test' }) + .expect(404); + + expect(response.body.message).toBe('Setting with a key [test] does not exist.'); + }); + + it('returns a 400 for a null value', async () => { + const response = await request + .post(root, '/internal/kibana/settings/test/validate') + .send({ value: null }) + .expect(400); + + expect(response.body.message).toBe('No value was specified.'); + }); + }); + describe('global', () => { describe('set', () => { it('validates value', async () => { diff --git a/src/core/tsconfig.json b/src/core/tsconfig.json index 88cac5132132..78219114a51d 100644 --- a/src/core/tsconfig.json +++ b/src/core/tsconfig.json @@ -155,6 +155,8 @@ "@kbn/core-test-helpers-model-versions", "@kbn/core-plugins-contracts-browser", "@kbn/core-plugins-contracts-server", + "@kbn/dev-utils", + "@kbn/server-http-tools", ], "exclude": [ "target/**/*", diff --git a/src/dev/build/lib/config.ts b/src/dev/build/lib/config.ts index a33540ce00c5..a27592e3f642 100644 --- a/src/dev/build/lib/config.ts +++ b/src/dev/build/lib/config.ts @@ -251,6 +251,6 @@ export class Config { } getDistPluginsFromRepo() { - return getPackages(this.repoRoot).filter(this.pluginFilter); + return getPackages(this.repoRoot).filter((p) => !p.isDevOnly() && this.pluginFilter(p)); } } diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 05b7133519a8..3aa057ac1bd3 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -402,6 +402,7 @@ kibana_vars=( xpack.securitySolution.packagerTaskInterval xpack.securitySolution.prebuiltRulesPackageVersion xpack.spaces.maxSpaces + xpack.task_manager.claim_strategy xpack.task_manager.max_attempts xpack.task_manager.max_workers xpack.task_manager.monitored_aggregated_stats_refresh_rate diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.ts b/src/dev/build/tasks/os_packages/docker_generator/run.ts index f9da19183d86..eb7a03a9e933 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/run.ts @@ -45,7 +45,7 @@ export async function runDockerGenerator( let imageFlavor = ''; if (flags.baseImage === 'ubi8') imageFlavor += `-ubi8`; - if (flags.baseImage === 'ubi9') imageFlavor += `-ubi9`; + if (flags.baseImage === 'ubi9') imageFlavor += `-ubi`; if (flags.ironbank) imageFlavor += '-ironbank'; if (flags.cloud) imageFlavor += '-cloud'; if (flags.serverless) imageFlavor += '-serverless'; diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile index 7fbba7d72ea7..5fe1a6695d06 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile @@ -3,7 +3,7 @@ # Extract Kibana and make various file manipulations. ################################################################################ ARG BASE_REGISTRY=registry1.dso.mil -ARG BASE_IMAGE=redhat/ubi/ubi9 +ARG BASE_IMAGE=ironbank/redhat/ubi/ubi9 ARG BASE_TAG=9.3 FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as prep_files diff --git a/src/dev/build/tasks/package_json/create_package_json_tasks.ts b/src/dev/build/tasks/package_json/create_package_json_tasks.ts index d5f4ee94e049..fae14c14e3db 100644 --- a/src/dev/build/tasks/package_json/create_package_json_tasks.ts +++ b/src/dev/build/tasks/package_json/create_package_json_tasks.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { PluginPackage } from '@kbn/repo-packages'; import { findUsedDependencies } from './find_used_dependencies'; import { read, write, Task } from '../../lib'; @@ -13,7 +14,7 @@ export const CreatePackageJson: Task = { description: 'Creating build-ready version of package.json', async run(config, log, build) { - const plugins = config.getDistPluginsFromRepo(); + const plugins = config.getDistPluginsFromRepo() as PluginPackage[]; const distPkgIds = new Set(config.getDistPackagesFromRepo().map((p) => p.id)); const pkg = config.getKibanaPkg(); diff --git a/src/dev/build/tasks/patch_native_modules_task.ts b/src/dev/build/tasks/patch_native_modules_task.ts index 24ab98d13220..d36fe4eca01e 100644 --- a/src/dev/build/tasks/patch_native_modules_task.ts +++ b/src/dev/build/tasks/patch_native_modules_task.ts @@ -42,13 +42,13 @@ const packages: Package[] = [ { // Tip: use `scripts/download_re2.sh` to download binary artifacts from GitHub name: 're2', - version: '1.20.1', + version: '1.20.9', destinationPath: 'node_modules/re2/build/Release/re2.node', extractMethod: 'gunzip', archives: { 'linux-x64': { - url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.1/linux-x64-108.gz', - sha256: 'e14f274f73ede22f170bfe9e57a0645ebf7ed320042a27361fa158bc239a5563', + url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.9/linux-x64-108.gz', + sha256: '136b6cf61b54bf610071a950400518add65d44a4923f11ef658769df1a037f0b', }, // Linux ARM builds are currently done manually as Github Actions used in upstream project // do not natively support an Linux ARM target. @@ -63,20 +63,20 @@ const packages: Package[] = [ // * capture the sha256 with: `shasum -a 256 linux-arm64-*` // * upload the `linux-arm64-*.gz` artifact to the `yarn-prebuilt-artifacts` bucket in GCS using the correct version number 'linux-arm64': { - url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.1/linux-arm64-108.gz', - sha256: 'cbdf3f75a331c601ac0bd34715814d0a1fd17612c6d6b5269f176d46044defd5', + url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.9/linux-arm64-108.gz', + sha256: '311822ac689bd49a534ecf400b4732a288ad218f711b0e593e41dd3a6b739d97', }, 'darwin-x64': { - url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.1/darwin-x64-108.gz', - sha256: 'f88c09e98f152ac15c593b3b923b7fbe28d448cfde5986da40c34461bede5a09', + url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.9/darwin-x64-108.gz', + sha256: '215b6ffb1e5d124439a7dbdd09e4ed1263e065839354a6ad67091ce00d14ee9b', }, 'darwin-arm64': { - url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.1/darwin-arm64-108.gz', - sha256: '80700aecbe63052149aba721449a8ce30c24d884e414025124bb4602efe708be', + url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.9/darwin-arm64-108.gz', + sha256: '0a8bc28150c9efd04f3b52ac214cc7898bde1b8e1f8e6900ae711b03665ff657', }, 'win32-x64': { - url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.1/win32-x64-108.gz', - sha256: 'cadc4713907f3ad1de45f470810ec8e13e08f32c1a1e45e5d5ab5e9d7fcb9763', + url: 'https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache/node-re2/uhop/node-re2/releases/download/1.20.9/win32-x64-108.gz', + sha256: '117872144e4a2bb61611aacc51ac9fd24e494c209cf63366f236099a662316eb', }, }, }, diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index 1680edb446e3..efd8f22dc0c9 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -85,7 +85,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.1': ['Elastic License 2.0'], - '@elastic/eui@90.0.0': ['SSPL-1.0 OR Elastic License 2.0'], + '@elastic/eui@90.0.1': ['SSPL-1.0 OR Elastic License 2.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary }; diff --git a/src/dev/so_migration/compare_snapshots.ts b/src/dev/so_migration/compare_snapshots.ts index 3f5563c18913..9eecf621c13e 100644 --- a/src/dev/so_migration/compare_snapshots.ts +++ b/src/dev/so_migration/compare_snapshots.ts @@ -45,7 +45,7 @@ async function compareSnapshots({ log.info( `Snapshots compared: ${from} <=> ${to}. ` + - `${result.hasChanges ? 'No changes' : 'Changed: ' + result.changed.join(', ')}` + `${result.hasChanges ? 'Changed: ' + result.changed.join(', ') : 'No changes'}` ); if (outputPath) { diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index a43fd71d0004..88d8c04b4233 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -15,13 +15,13 @@ export const storybookAliases = { canvas: 'x-pack/plugins/canvas/storybook', cases: 'packages/kbn-cases-components/.storybook', cell_actions: 'packages/kbn-cell-actions/.storybook', - ci_composite: '.ci/.storybook', cloud_chat: 'x-pack/plugins/cloud_integrations/cloud_chat/.storybook', coloring: 'packages/kbn-coloring/.storybook', language_documentation_popover: 'packages/kbn-language-documentation-popover/.storybook', chart_icons: 'packages/kbn-chart-icons/.storybook', content_management_examples: 'examples/content_management_examples/.storybook', controls: 'src/plugins/controls/storybook', + custom_icons: 'packages/kbn-custom-icons/.storybook', custom_integrations: 'src/plugins/custom_integrations/storybook', dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook', dashboard: 'src/plugins/dashboard/.storybook', diff --git a/src/plugins/advanced_settings/public/management_app/settings.test.tsx b/src/plugins/advanced_settings/public/management_app/settings.test.tsx index f51eec4e97bb..a98b29922af1 100644 --- a/src/plugins/advanced_settings/public/management_app/settings.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/settings.test.tsx @@ -201,6 +201,8 @@ function mockConfig() { }, }; }, + validateValue: (key: string, value: any) => + Promise.resolve({ successfulValidation: true, valid: true }), }; return { core: { diff --git a/src/plugins/advanced_settings/public/management_app/settings_helper.test.ts b/src/plugins/advanced_settings/public/management_app/settings_helper.test.ts index 7f745db9b786..e4aaab4bb305 100644 --- a/src/plugins/advanced_settings/public/management_app/settings_helper.test.ts +++ b/src/plugins/advanced_settings/public/management_app/settings_helper.test.ts @@ -129,6 +129,8 @@ describe('Settings Helper', () => { ...imageSetting, }; }, + validateValue: (key: string, value: any) => + Promise.resolve({ successfulValidation: true, valid: true }), }; it('mapConfig', () => { diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/ui_settings.ts b/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/ui_settings.ts index 1585133e3b8d..490d2c931b44 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/ui_settings.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/__mocks__/ui_settings.ts @@ -28,4 +28,6 @@ export const uiSettings: IUiSettingsClient = { getAll: (): Readonly> => { return {}; }, + validateValue: (key: string, value: any) => + Promise.resolve({ successfulValidation: true, valid: true }), }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts index 0beca2e79de8..7b139df576d6 100755 --- a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts @@ -47,6 +47,7 @@ export interface MultiFilterEvent { export interface CellValueAction { id: string; + type?: string; iconType: string; displayName: string; execute: (data: CellValueContext['data']) => void; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx index 778c2003de4f..b734e1b07a0c 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx @@ -14,10 +14,15 @@ import { LegendAction, SeriesIdentifier, useLegendAction } from '@elastic/charts import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Datatable } from '@kbn/expressions-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { FILTER_CELL_ACTION_TYPE } from '@kbn/cell-actions/constants'; import { PartitionVisParams } from '../../common/types'; -import { ColumnCellValueActions, FilterEvent } from '../types'; +import { CellValueAction, ColumnCellValueActions, FilterEvent } from '../types'; import { getSeriesValueColumnIndex, getFilterPopoverTitle } from './filter_helpers'; +const hasFilterCellAction = (actions: CellValueAction[]) => { + return actions.some(({ type }) => type === FILTER_CELL_ACTION_TYPE); +}; + export const getLegendActions = ( canFilter: ( data: FilterEvent | null, @@ -58,9 +63,10 @@ export const getLegendActions = ( pieSeries.key ); - const panelItems: EuiContextMenuPanelDescriptor['items'] = []; + const compatibleCellActions = columnCellValueActions[columnIndex] ?? []; - if (isFilterable && filterData) { + const panelItems: EuiContextMenuPanelDescriptor['items'] = []; + if (!hasFilterCellAction(compatibleCellActions) && isFilterable && filterData) { panelItems.push( { name: i18n.translate('expressionPartitionVis.legend.filterForValueButtonAriaLabel', { @@ -87,20 +93,18 @@ export const getLegendActions = ( ); } - if (columnCellValueActions[columnIndex]) { - const columnMeta = visData.columns[columnIndex].meta; - columnCellValueActions[columnIndex].forEach((action) => { - panelItems.push({ - name: action.displayName, - 'data-test-subj': `legend-${title}-${action.id}`, - icon: , - onClick: () => { - action.execute([{ columnMeta, value: pieSeries.key }]); - setPopoverOpen(false); - }, - }); + const columnMeta = visData.columns[columnIndex].meta; + compatibleCellActions.forEach((action) => { + panelItems.push({ + name: action.displayName, + 'data-test-subj': `legend-${title}-${action.id}`, + icon: , + onClick: () => { + action.execute([{ columnMeta, value: pieSeries.key }]); + setPopoverOpen(false); + }, }); - } + }); if (panelItems.length === 0) { return null; diff --git a/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json b/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json index bfb4774a1676..59b7893879ce 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json +++ b/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json @@ -29,6 +29,7 @@ "@kbn/analytics", "@kbn/chart-icons", "@kbn/chart-expressions-common", + "@kbn/cell-actions", ], "exclude": [ "target/**/*", diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.test.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.test.ts index 78eb7c54ebf8..eae70ea54f0c 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.test.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.test.ts @@ -10,7 +10,6 @@ import { layeredXyVisFunction } from '.'; import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks'; import { sampleArgs, sampleExtendedLayer } from '../__mocks__'; import { XY_VIS } from '../constants'; -import { shouldShowLegendActionDefault } from '../helpers/visualization'; describe('layeredXyVis', () => { test('it renders with the specified data and args', async () => { @@ -31,7 +30,6 @@ describe('layeredXyVis', () => { syncTooltips: false, syncCursor: true, canNavigateToLens: false, - shouldShowLegendAction: shouldShowLegendActionDefault, }, }); }); diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts index 5a1a79ef984f..cf1325f09bf2 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts @@ -18,7 +18,6 @@ import { validateAxes, } from './validate'; import { appendLayerIds, getDataLayers } from '../helpers'; -import { shouldShowLegendActionDefault } from '../helpers/visualization'; export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers) => { const layers = appendLayerIds(args.layers ?? [], 'layers'); @@ -67,7 +66,6 @@ export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers) syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false, syncCursor: handlers?.isSyncCursorEnabled?.() ?? true, overrides: handlers.variables?.overrides as XYRender['value']['overrides'], - shouldShowLegendAction: handlers?.shouldShowLegendAction ?? shouldShowLegendActionDefault, }, }; }; diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts index e0c825597d32..9a71ec92d7a5 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis.test.ts @@ -10,7 +10,6 @@ import { xyVisFunction } from '.'; import { createMockExecutionContext } from '@kbn/expressions-plugin/common/mocks'; import { sampleArgs, sampleLayer } from '../__mocks__'; import { XY_VIS } from '../constants'; -import { shouldShowLegendActionDefault } from '../helpers/visualization'; describe('xyVis', () => { test('it renders with the specified data and args', async () => { @@ -43,7 +42,6 @@ describe('xyVis', () => { syncColors: false, syncTooltips: false, syncCursor: true, - shouldShowLegendAction: shouldShowLegendActionDefault, }, }); }); @@ -354,7 +352,6 @@ describe('xyVis', () => { syncColors: false, syncTooltips: false, syncCursor: true, - shouldShowLegendAction: shouldShowLegendActionDefault, }, }); }); @@ -404,7 +401,6 @@ describe('xyVis', () => { syncTooltips: false, syncCursor: true, overrides, - shouldShowLegendAction: shouldShowLegendActionDefault, }, }); }); diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts index 1eb4357e57c8..03df575b3c65 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts @@ -30,7 +30,6 @@ import { validateAxes, } from './validate'; import { logDatatable } from '../utils'; -import { shouldShowLegendActionDefault } from '../helpers/visualization'; const createDataLayer = (args: XYArgs, table: Datatable): DataLayerConfigResult => { const accessors = getAccessors(args, table); @@ -140,7 +139,6 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => { syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false, syncCursor: handlers?.isSyncCursorEnabled?.() ?? true, overrides: handlers.variables?.overrides as XYRender['value']['overrides'], - shouldShowLegendAction: handlers?.shouldShowLegendAction ?? shouldShowLegendActionDefault, }, }; }; diff --git a/src/plugins/chart_expressions/expression_xy/common/helpers/visualization.ts b/src/plugins/chart_expressions/expression_xy/common/helpers/visualization.ts index 8f740c2578d7..66d4c11a9f7a 100644 --- a/src/plugins/chart_expressions/expression_xy/common/helpers/visualization.ts +++ b/src/plugins/chart_expressions/expression_xy/common/helpers/visualization.ts @@ -19,5 +19,3 @@ export function isTimeChart(layers: CommonXYDataLayerConfigResult[]) { (!l.xScaleType || l.xScaleType === XScaleTypes.TIME) ); } - -export const shouldShowLegendActionDefault = () => true; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx index 47e36adab06f..1398fc64357c 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.test.tsx @@ -203,8 +203,7 @@ describe('getLegendAction', function () { formattedColumns: {}, }, }, - {}, - () => true + {} ); let wrapper: ReactWrapper; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx index 2ae2c21b8c0d..f5b00f696d04 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx @@ -28,7 +28,6 @@ export const getLegendAction = ( fieldFormats: LayersFieldFormats, formattedDatatables: DatatablesWithFormatInfo, titles: LayersAccessorsTitles, - shouldShowLegendAction?: (actionId: string) => boolean, singleTable?: boolean ): LegendAction => React.memo(({ series: [xySeries] }) => { @@ -110,7 +109,6 @@ export const getLegendAction = ( } onFilter={filterHandler} legendCellValueActions={legendCellValueActions} - shouldShowLegendAction={shouldShowLegendAction} /> ); }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action_popover.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action_popover.tsx index aa2db4c4eb47..268a7051bd4c 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action_popover.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action_popover.tsx @@ -8,16 +8,14 @@ import React, { useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiContextMenuPanelDescriptor, - EuiIcon, - EuiPopover, - EuiContextMenu, - EuiContextMenuPanelItemDescriptor, -} from '@elastic/eui'; +import { FILTER_CELL_ACTION_TYPE } from '@kbn/cell-actions/constants'; +import { EuiContextMenuPanelDescriptor, EuiIcon, EuiPopover, EuiContextMenu } from '@elastic/eui'; import { useLegendAction } from '@elastic/charts'; import type { CellValueAction } from '../types'; -import { shouldShowLegendActionDefault } from '../../common/helpers/visualization'; + +const hasFilterCellAction = (actions: CellValueAction[]) => { + return actions.some(({ type }) => type === FILTER_CELL_ACTION_TYPE); +}; export type LegendCellValueActions = Array< Omit & { execute: () => void } @@ -36,20 +34,18 @@ export interface LegendActionPopoverProps { * Compatible actions to be added to the popover actions */ legendCellValueActions?: LegendCellValueActions; - shouldShowLegendAction?: (actionId: string) => boolean; } export const LegendActionPopover: React.FunctionComponent = ({ label, onFilter, legendCellValueActions = [], - shouldShowLegendAction = shouldShowLegendActionDefault, }) => { const [popoverOpen, setPopoverOpen] = useState(false); const [ref, onClose] = useLegendAction(); const panels: EuiContextMenuPanelDescriptor[] = useMemo(() => { - const defaultActions = [ + const defaultFilterActions = [ { id: 'filterIn', displayName: i18n.translate('expressionXY.legend.filterForValueButtonAriaLabel', { @@ -76,22 +72,21 @@ export const LegendActionPopover: React.FunctionComponent((acc, action) => { - if (shouldShowLegendAction(action.id)) { - acc.push({ - name: action.displayName, - 'data-test-subj': `legend-${label}-${action.id}`, - icon: , - onClick: () => { - action.execute(); - setPopoverOpen(false); - }, - }); - } - return acc; - }, []); + const allActions = [ + ...(!hasFilterCellAction(legendCellValueActions) ? defaultFilterActions : []), + ...legendCellValueActions, + ]; + + const legendCellValueActionPanelItems = allActions.map((action) => ({ + name: action.displayName, + 'data-test-subj': `legend-${label}-${action.id}`, + icon: , + onClick: () => { + action.execute(); + setPopoverOpen(false); + }, + })); + return [ { id: 'main', @@ -99,7 +94,7 @@ export const LegendActionPopover: React.FunctionComponent & { renderComplete: () => void; uiState?: PersistedState; timeFormat: string; - shouldShowLegendAction?: (actionId: string) => boolean; }; function nonNullable(v: T): v is NonNullable { @@ -208,7 +207,6 @@ export function XYChart({ uiState, timeFormat, overrides, - shouldShowLegendAction, }: XYChartRenderProps) { const { legend, @@ -841,7 +839,6 @@ export function XYChart({ fieldFormats, formattedDatatables, titles, - shouldShowLegendAction, singleTable ) : undefined diff --git a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx index 401af740375b..c2561191deb9 100644 --- a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx @@ -277,7 +277,6 @@ export const getXyChartRenderer = ({ syncCursor={config.syncCursor} uiState={handlers.uiState as PersistedState} renderComplete={renderComplete} - shouldShowLegendAction={handlers.shouldShowLegendAction} />
    diff --git a/src/plugins/chart_expressions/expression_xy/public/types.ts b/src/plugins/chart_expressions/expression_xy/public/types.ts index 733dba9400bf..14aa84768efe 100755 --- a/src/plugins/chart_expressions/expression_xy/public/types.ts +++ b/src/plugins/chart_expressions/expression_xy/public/types.ts @@ -120,6 +120,7 @@ export interface VisualizationType { export interface CellValueAction { id: string; + type?: string; iconType: string; displayName: string; execute: (data: CellValueContext['data']) => void; diff --git a/src/plugins/chart_expressions/expression_xy/tsconfig.json b/src/plugins/chart_expressions/expression_xy/tsconfig.json index 901b7eb0568c..a0e7e207f92c 100644 --- a/src/plugins/chart_expressions/expression_xy/tsconfig.json +++ b/src/plugins/chart_expressions/expression_xy/tsconfig.json @@ -34,6 +34,7 @@ "@kbn/event-annotation-common", "@kbn/visualization-ui-components", "@kbn/es-query", + "@kbn/cell-actions", ], "exclude": [ "target/**/*", diff --git a/src/plugins/console/public/lib/autocomplete/autocomplete.ts b/src/plugins/console/public/lib/autocomplete/autocomplete.ts index ec543a1663d9..c6b425697abc 100644 --- a/src/plugins/console/public/lib/autocomplete/autocomplete.ts +++ b/src/plugins/console/public/lib/autocomplete/autocomplete.ts @@ -983,32 +983,33 @@ export default function ({ context.urlTokenPath = ret.urlTokenPath; const components = getTopLevelUrlCompleteComponents(context.method); - const { tokenPath, predicate } = (() => { - const lastUrlTokenPath = - Array.isArray(context.urlTokenPath) && context.urlTokenPath.length !== 0 - ? context.urlTokenPath[context.urlTokenPath.length - 1] - : null; - // Checking the last chunk of path like 'c,d,' of 'GET /a/b/c,d,' - if ( - Array.isArray(lastUrlTokenPath) && - // true if neither c nor d equals to every ConstantComponent's name (such as _search) - !_.find( - components, - (c) => c instanceof ConstantComponent && _.find(lastUrlTokenPath, (p) => c.name === p) - ) - ) { - // will simulate autocomplete on 'GET /a/b/' with a filter by index - return { - tokenPath: context.urlTokenPath?.slice(0, -1), - predicate: (term: ReturnType[0]) => term.meta === 'index', - }; - } else { - // will do nothing special - return { tokenPath: context.urlTokenPath, predicate: () => true }; + let urlTokenPath = context.urlTokenPath; + let predicate: (term: ReturnType[0]) => boolean = () => true; + + const tokenIter = createTokenIterator({ editor, position: pos }); + const currentTokenType = tokenIter.getCurrentToken()?.type; + const previousTokenType = tokenIter.stepBackward()?.type; + if (!Array.isArray(urlTokenPath)) { + // skip checks for url.comma + } else if (previousTokenType === 'url.comma' && currentTokenType === 'url.comma') { + predicate = () => false; // two consecutive commas empty the autocomplete + } else if ( + (previousTokenType === 'url.part' && currentTokenType === 'url.comma') || + (previousTokenType === 'url.slash' && currentTokenType === 'url.comma') || + (previousTokenType === 'url.comma' && currentTokenType === 'url.part') + ) { + const lastUrlTokenPath = _.last(urlTokenPath) || []; // ['c', 'd'] from 'GET /a/b/c,d,' + const constantComponents = _.filter(components, (c) => c instanceof ConstantComponent); + const constantComponentNames = _.map(constantComponents, 'name'); + + // check if neither 'c' nor 'd' is a constant component name such as '_search' + if (_.every(lastUrlTokenPath, (token) => !_.includes(constantComponentNames, token))) { + urlTokenPath = urlTokenPath.slice(0, -1); // drop the last 'c,d,' part from the url path + predicate = (term) => term.meta === 'index'; // limit the autocomplete to indices only } - })(); + } - populateContext(tokenPath, context, editor, true, components); + populateContext(urlTokenPath, context, editor, true, components); context.autoCompleteSet = _.filter( addMetaToTermsList(context.autoCompleteSet!, 'endpoint'), predicate diff --git a/src/plugins/console/public/lib/autocomplete/body_completer.js b/src/plugins/console/public/lib/autocomplete/body_completer.js index 9759eb9b629d..d9355db85f4d 100644 --- a/src/plugins/console/public/lib/autocomplete/body_completer.js +++ b/src/plugins/console/public/lib/autocomplete/body_completer.js @@ -266,7 +266,7 @@ function compileCondition(description, compiledObject) { return new RegExp(description.lines_regex, 'm').test(lines); }, compiledObject); } else { - throw 'unknown condition type - got: ' + JSON.stringify(description); + throw new Error(`unknown condition type - got: ${JSON.stringify(description)}`); } } diff --git a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts index 969f06f8d994..cbcfb724798d 100644 --- a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts +++ b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.test.ts @@ -103,6 +103,10 @@ describe('looksLikeTypingIn', () => { { preamble: 'GET _cat/indices?s=index&exp', autocomplete: 'and_wildcards', input: '=' }, { preamble: 'GET _cat/indices?v&', autocomplete: 'expand_wildcards', input: '=' }, { preamble: 'GET _cat/indices?v&exp', autocomplete: 'and_wildcards', input: '=' }, + // autocomplete skips one iteration of token evaluation if user types in every letter + { preamble: 'GET .kibana', autocomplete: '/', input: '_' }, // token '/' may not be evaluated + { preamble: 'GET .kibana', autocomplete: ',', input: '.' }, // token ',' may not be evaluated + { preamble: 'GET .kibana', autocomplete: '?', input: 'k' }, // token '?' may not be evaluated ]; for (const c of cases) { const name = diff --git a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts index a679aa2eda11..44dbb99025c7 100644 --- a/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts +++ b/src/plugins/console/public/lib/autocomplete/looks_like_typing_in.ts @@ -11,6 +11,7 @@ import type { CoreEditor, Position, Token } from '../../types'; enum Move { ForwardOneCharacter = 1, ForwardOneToken, // the column position may jump to the next token by autocomplete + ForwardTwoTokens, // the column position could jump two tokens due to autocomplete } const knownTypingInTokenTypes = new Map>>([ @@ -43,6 +44,10 @@ const knownTypingInTokenTypes = new Map>>([ ['whitespace', new Set(['url.comma', 'url.questionmark', 'url.slash'])], ]), ], + [ + Move.ForwardTwoTokens, + new Map>([['url.part', new Set(['url.param', 'url.part'])]]), + ], ]); const getOneCharacterNextOnTheRight = (pos: Position, coreEditor: CoreEditor): string => { @@ -75,14 +80,16 @@ export const looksLikeTypingIn = ( currentToken.value.length === 1 && getOneCharacterNextOnTheRight(currentToken.position, coreEditor) === '' ) { - const move = + const moves = lastEvaluatedToken.position.column + 1 === currentToken.position.column - ? Move.ForwardOneCharacter - : Move.ForwardOneToken; - const tokenTypesPairs = knownTypingInTokenTypes.get(move) ?? new Map>(); - const currentTokenTypes = tokenTypesPairs.get(lastEvaluatedToken.type) ?? new Set(); - if (currentTokenTypes.has(currentToken.type)) { - return true; + ? [Move.ForwardOneCharacter] + : [Move.ForwardOneToken, Move.ForwardTwoTokens]; + for (const move of moves) { + const tokenTypesPairs = knownTypingInTokenTypes.get(move) ?? new Map>(); + const currentTokenTypes = tokenTypesPairs.get(lastEvaluatedToken.type) ?? new Set(); + if (currentTokenTypes.has(currentToken.type)) { + return true; + } } } diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx index ea1bea52c83d..1ff789ab6120 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx @@ -41,6 +41,7 @@ import { useDashboardOutcomeValidation } from './hooks/use_dashboard_outcome_val import { loadDashboardHistoryLocationState } from './locator/load_dashboard_history_location_state'; import type { DashboardCreationOptions } from '../dashboard_container/embeddable/dashboard_container_factory'; import { DashboardTopNav } from '../dashboard_top_nav'; +import { DashboardTabTitleSetter } from './tab_title_setter/dashboard_tab_title_setter'; export interface DashboardAppProps { history: History; @@ -200,15 +201,17 @@ export function DashboardApp({ {!showNoDataPage && ( <> {dashboardAPI && ( - + <> + + + )} {getLegacyConflictWarning?.()} - { + const { + chrome: { docTitle: chromeDocTitle }, + } = pluginServices.getServices(); + const title = dashboardContainer.select((state) => state.explicitInput.title); + const lastSavedId = dashboardContainer.select((state) => state.componentState.lastSavedId); + + /** + * Set chrome tab title when dashboard's title changes + */ + useEffect(() => { + /** We do not want the tab title to include the "Editing" prefix, so always send in view mode */ + chromeDocTitle.change(getDashboardTitle(title, ViewMode.VIEW, !lastSavedId)); + }, [title, chromeDocTitle, lastSavedId]); + + return null; +}; diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx index 0190bbaefa00..6afdf1429663 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx @@ -54,12 +54,14 @@ export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean } trackUiMetric(METRIC_TYPE.CLICK, `${visType.name}:create`); } - if ('aliasPath' in visType) { - appId = visType.aliasApp; - path = visType.aliasPath; - } else { + if (!('alias' in visType)) { + // this visualization is not an alias appId = 'visualize'; path = `#/create?type=${encodeURIComponent(visType.name)}`; + } else if (visType.alias && 'path' in visType.alias) { + // this visualization **is** an alias, and it has an app to redirect to for creation + appId = visType.alias.app; + path = visType.alias.path; } } else { appId = 'visualize'; diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx index d2b6470650ca..18f26704221a 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx @@ -104,10 +104,11 @@ export const EditorMenu = ({ createNewVisType, createNewEmbeddable, isDisabled } const promotedVisTypes = getSortedVisTypesByGroup(VisGroups.PROMOTED); const aggsBasedVisTypes = getSortedVisTypesByGroup(VisGroups.AGGBASED); const toolVisTypes = getSortedVisTypesByGroup(VisGroups.TOOLS); - const visTypeAliases = getVisTypeAliases().sort( - ({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => + const visTypeAliases = getVisTypeAliases() + .sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => a === b ? 0 : a ? -1 : 1 - ); + ) + .filter(({ disableCreate }: VisTypeAlias) => !disableCreate); const factories = unwrappedEmbeddableFactories.filter( ({ isEditable, factory: { type, canCreateNew, isContainerType } }) => diff --git a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx index 8767b5abe356..de7d79d456b9 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx @@ -10,21 +10,21 @@ import React, { useCallback, useMemo } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { - EuiText, - EuiImage, EuiButton, - EuiFlexItem, - EuiFlexGroup, EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiImage, EuiPageTemplate, + EuiText, } from '@elastic/eui'; import { METRIC_TYPE } from '@kbn/analytics'; import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { DASHBOARD_UI_METRIC_ID } from '../../../dashboard_constants'; import { pluginServices } from '../../../services/plugin_services'; -import { emptyScreenStrings } from '../../_dashboard_container_strings'; import { useDashboardContainer } from '../../embeddable/dashboard_container'; -import { DASHBOARD_UI_METRIC_ID } from '../../../dashboard_constants'; +import { emptyScreenStrings } from '../../_dashboard_container_strings'; export function DashboardEmptyScreen() { const { @@ -53,7 +53,7 @@ export function DashboardEmptyScreen() { const originatingApp = embeddableAppContext?.currentAppId; const goToLens = useCallback(() => { - if (!lensAlias || !lensAlias.aliasPath) return; + if (!lensAlias || !lensAlias.alias) return; const trackUiMetric = usageCollection.reportUiCounter?.bind( usageCollection, DASHBOARD_UI_METRIC_ID @@ -62,8 +62,8 @@ export function DashboardEmptyScreen() { if (trackUiMetric) { trackUiMetric(METRIC_TYPE.CLICK, `${lensAlias.name}:create`); } - getStateTransfer().navigateToEditor(lensAlias.aliasApp, { - path: lensAlias.aliasPath, + getStateTransfer().navigateToEditor(lensAlias.alias.app, { + path: lensAlias.alias.path, state: { originatingApp, originatingPath, diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index 9eb12379741a..083d47ee4e69 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -108,6 +108,7 @@ export const Item = React.forwardRef( key={type} index={index} showBadges={true} + showShadow={true} showNotifications={true} onPanelStatusChange={onPanelStatusChange} embeddable={() => container.untilEmbeddableLoaded(id)} diff --git a/src/plugins/data/common/search/expressions/esql.ts b/src/plugins/data/common/search/expressions/esql.ts index ec30a92bae99..ca6096c8160d 100644 --- a/src/plugins/data/common/search/expressions/esql.ts +++ b/src/plugins/data/common/search/expressions/esql.ts @@ -31,7 +31,10 @@ type Output = Observable; interface Arguments { query: string; - timezone?: string; + // TODO: time_zone support was temporarily removed from ES|QL, + // we will need to add it back in once it is supported again. + // https://github.com/elastic/elasticsearch/pull/102767 + // timezone?: string; timeField?: string; locale?: string; } @@ -67,10 +70,6 @@ function normalizeType(type: string): DatatableColumnType { } } -function sanitize(value: string) { - return value.replace(/[\(\)]/g, '_'); -} - function extractTypeAndReason(attributes: any): { type?: string; reason?: string } { if (['type', 'reason'].every((prop) => prop in attributes)) { return attributes; @@ -82,7 +81,10 @@ function extractTypeAndReason(attributes: any): { type?: string; reason?: string } interface ESQLSearchParams { - time_zone?: string; + // TODO: time_zone support was temporarily removed from ES|QL, + // we will need to add it back in once it is supported again. + // https://github.com/elastic/elasticsearch/pull/102767 + // time_zone?: string; query: string; filter?: unknown; locale?: string; @@ -112,15 +114,15 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { defaultMessage: 'An ES|QL query.', }), }, - timezone: { - aliases: ['tz'], - types: ['string'], - default: 'UTC', - help: i18n.translate('data.search.esql.timezone.help', { - defaultMessage: - 'The timezone to use for date operations. Valid ISO8601 formats and UTC offsets both work.', - }), - }, + // timezone: { + // aliases: ['tz'], + // types: ['string'], + // default: 'UTC', + // help: i18n.translate('data.search.esql.timezone.help', { + // defaultMessage: + // 'The timezone to use for date operations. Valid ISO8601 formats and UTC offsets both work.', + // }), + // }, timeField: { aliases: ['timeField'], types: ['string'], @@ -138,7 +140,7 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { }, fn( input, - { query, timezone, timeField, locale }, + { query, /* timezone, */ timeField, locale }, { abortSignal, inspectorAdapters, getKibanaRequest } ) { return defer(() => @@ -157,7 +159,7 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { switchMap(({ search, uiSettings }) => { const params: ESQLSearchParams = { query, - time_zone: timezone, + // time_zone: timezone, locale, }; if (input) { @@ -249,8 +251,8 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { map(({ rawResponse: body, warning }) => { const columns = body.columns?.map(({ name, type }) => ({ - id: sanitize(name), - name: sanitize(name), + id: name, + name, meta: { type: normalizeType(type) }, })) ?? []; const columnNames = columns.map(({ name }) => name); diff --git a/src/plugins/data/common/search/search_source/search_source.test.ts b/src/plugins/data/common/search/search_source/search_source.test.ts index 4dfd9aea3b6d..64ae2f3b2ec0 100644 --- a/src/plugins/data/common/search/search_source/search_source.test.ts +++ b/src/plugins/data/common/search/search_source/search_source.test.ts @@ -281,7 +281,6 @@ describe('SearchSource', () => { searchSource.setField('index', { ...indexPattern, getComputedFields: () => ({ - storedFields: ['hello'], scriptFields: { world: {} }, docvalueFields: ['@timestamp'], runtimeFields, @@ -289,7 +288,7 @@ describe('SearchSource', () => { } as unknown as DataView); const request = searchSource.getSearchRequestBody(); - expect(request.stored_fields).toEqual(['hello']); + expect(request.stored_fields).toEqual(['*']); expect(request.script_fields).toEqual({ world: {} }); expect(request.fields).toEqual(['@timestamp']); expect(request.runtime_mappings).toEqual(runtimeFields); diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 19d39c7772fb..6fc47ac12643 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -779,12 +779,11 @@ export class SearchSource { const metaFields = getConfig(UI_SETTINGS.META_FIELDS) ?? []; // get some special field types from the index pattern - const { docvalueFields, scriptFields, storedFields, runtimeFields } = index + const { docvalueFields, scriptFields, runtimeFields } = index ? index.getComputedFields() : { docvalueFields: [], scriptFields: {}, - storedFields: ['*'], runtimeFields: {}, }; const fieldListProvided = !!body.fields; @@ -798,7 +797,7 @@ export class SearchSource { ...scriptFields, } : {}; - body.stored_fields = storedFields; + body.stored_fields = ['*']; body.runtime_mappings = runtimeFields || {}; // apply source filters from index pattern if specified by the user diff --git a/src/plugins/data/config.ts b/src/plugins/data/config.ts index 03cd77653bec..b6adfdede246 100644 --- a/src/plugins/data/config.ts +++ b/src/plugins/data/config.ts @@ -86,6 +86,10 @@ export const searchConfigSchema = schema.object({ export const configSchema = schema.object({ search: searchConfigSchema, + /** + * Turns on/off limit validations for the registered uiSettings. + */ + enableUiSettingsValidations: schema.boolean({ defaultValue: false }), }); export type ConfigSchema = TypeOf; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 1b2b0c3c78ca..dfe88a12026b 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -74,9 +74,11 @@ export class DataServerPlugin private readonly kqlTelemetryService: KqlTelemetryService; private readonly queryService = new QueryService(); private readonly logger: Logger; + private readonly config: ConfigSchema; constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get('data'); + this.config = initializerContext.config.get(); this.searchService = new SearchService(initializerContext, this.logger); this.scriptsService = new ScriptsService(); this.kqlTelemetryService = new KqlTelemetryService(initializerContext); @@ -90,7 +92,7 @@ export class DataServerPlugin const querySetup = this.queryService.setup(core); this.kqlTelemetryService.setup(core, { usageCollection }); - core.uiSettings.register(getUiSettings(core.docLinks)); + core.uiSettings.register(getUiSettings(core.docLinks, this.config.enableUiSettingsValidations)); const searchSetup = this.searchService.setup(core, { bfetch, diff --git a/src/plugins/data/server/search/session/session_service.test.ts b/src/plugins/data/server/search/session/session_service.test.ts index 3f79049fa966..481fabcfa423 100644 --- a/src/plugins/data/server/search/session/session_service.test.ts +++ b/src/plugins/data/server/search/session/session_service.test.ts @@ -18,7 +18,7 @@ import { createRequestHash } from './utils'; import moment from 'moment'; import { coreMock } from '@kbn/core/server/mocks'; import { ConfigSchema } from '../../../config'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index 3ed2a86fb053..7b386e864fbc 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -32,7 +32,8 @@ const requestPreferenceOptionLabels = { }; export function getUiSettings( - docLinks: DocLinksServiceSetup + docLinks: DocLinksServiceSetup, + enableValidations: boolean ): Record> { return { [UI_SETTINGS.META_FIELDS]: { @@ -463,13 +464,22 @@ export function getUiSettings( '', }, }), - schema: schema.arrayOf( - schema.object({ - from: schema.string(), - to: schema.string(), - display: schema.string(), - }) - ), + schema: enableValidations + ? schema.arrayOf( + schema.object({ + from: schema.string(), + to: schema.string(), + display: schema.string(), + }), + { maxSize: 10 } + ) + : schema.arrayOf( + schema.object({ + from: schema.string(), + to: schema.string(), + display: schema.string(), + }) + ), }, [UI_SETTINGS.FILTERS_PINNED_BY_DEFAULT]: { name: i18n.translate('data.advancedSettings.pinFiltersTitle', { diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx index 71ff8ce38636..7ce1c9ccbc66 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -30,6 +30,7 @@ import { } from '@kbn/saved-objects-management-plugin/public'; import { pickBy } from 'lodash'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; +import type * as CSS from 'csstype'; import { IndexPatternManagmentContext } from '../../types'; import { Tabs } from './tabs'; import { IndexHeader } from './index_header'; @@ -37,8 +38,9 @@ import { getTags } from '../utils'; import { removeDataView, RemoveDataViewProps } from './remove_data_view'; import { APP_STATE_STORAGE_KEY } from './edit_index_pattern_state_container'; -const codeStyle = { +const codeStyle: CSS.Properties = { marginLeft: '8px', + overflowWrap: 'anywhere', }; export interface EditIndexPatternProps extends RouteComponentProps { diff --git a/src/plugins/data_views/common/data_views/data_view.test.ts b/src/plugins/data_views/common/data_views/data_view.test.ts index 18ab045d81dd..15a229832a48 100644 --- a/src/plugins/data_views/common/data_views/data_view.test.ts +++ b/src/plugins/data_views/common/data_views/data_view.test.ts @@ -136,10 +136,6 @@ describe('IndexPattern', () => { expect(indexPattern.getComputedFields).toBeInstanceOf(Function); }); - test('should request all stored fields', () => { - expect(indexPattern.getComputedFields().storedFields).toContain('*'); - }); - test('should request date fields as docvalue_fields', () => { const { docvalueFields } = indexPattern.getComputedFields(); const docValueFieldNames = docvalueFields.map((field) => field.field); diff --git a/src/plugins/data_views/common/data_views/data_view.ts b/src/plugins/data_views/common/data_views/data_view.ts index f47d4c0fb217..d60d0b4c1172 100644 --- a/src/plugins/data_views/common/data_views/data_view.ts +++ b/src/plugins/data_views/common/data_views/data_view.ts @@ -85,7 +85,6 @@ export class DataView extends AbstractDataView implements DataViewBase { const scriptFields: Record = {}; if (!this.fields) { return { - storedFields: ['*'], scriptFields, docvalueFields: [] as Array<{ field: string; format: string }>, runtimeFields: {}, @@ -117,7 +116,6 @@ export class DataView extends AbstractDataView implements DataViewBase { const runtimeFields = this.getRuntimeMappings(); return { - storedFields: ['*'], scriptFields, docvalueFields, runtimeFields, diff --git a/src/plugins/data_views/docs/openapi/bundled.json b/src/plugins/data_views/docs/openapi/bundled.json index d661e0a7cbaa..e4f7e9856e2b 100644 --- a/src/plugins/data_views/docs/openapi/bundled.json +++ b/src/plugins/data_views/docs/openapi/bundled.json @@ -740,7 +740,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "examples": { diff --git a/src/plugins/data_views/docs/openapi/bundled.yaml b/src/plugins/data_views/docs/openapi/bundled.yaml index c6e52614b66e..65ffd986ade7 100644 --- a/src/plugins/data_views/docs/openapi/bundled.yaml +++ b/src/plugins/data_views/docs/openapi/bundled.yaml @@ -474,7 +474,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' examples: get_data_views_response: summary: The get all data views API returns a list of data views. diff --git a/src/plugins/data_views/docs/openapi/entrypoint.yaml b/src/plugins/data_views/docs/openapi/entrypoint.yaml index 991d0e32154a..697fd554dae8 100644 --- a/src/plugins/data_views/docs/openapi/entrypoint.yaml +++ b/src/plugins/data_views/docs/openapi/entrypoint.yaml @@ -52,7 +52,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - apiKeyAuth: [] diff --git a/src/plugins/data_views/public/data_views/data_views_api_client.test.ts b/src/plugins/data_views/public/data_views/data_views_api_client.test.ts index 90a208650a96..f36776153ee3 100644 --- a/src/plugins/data_views/public/data_views/data_views_api_client.test.ts +++ b/src/plugins/data_views/public/data_views/data_views_api_client.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { HttpSetup } from '@kbn/core/public'; import { http } from './data_views_api_client.test.mock'; import { DataViewsApiClient } from './data_views_api_client'; import { FIELDS_FOR_WILDCARD_PATH as expectedPath } from '../../common/constants'; @@ -16,7 +17,7 @@ describe('IndexPatternsApiClient', () => { beforeEach(() => { fetchSpy = jest.spyOn(http, 'fetch').mockImplementation(() => Promise.resolve({})); - indexPatternsApiClient = new DataViewsApiClient(http); + indexPatternsApiClient = new DataViewsApiClient(http as HttpSetup); }); test('uses the right URI to fetch fields for wildcard', async function () { diff --git a/src/plugins/discover/public/application/context/context_app_content.tsx b/src/plugins/discover/public/application/context/context_app_content.tsx index 098f789be1a6..84d2126f1549 100644 --- a/src/plugins/discover/public/application/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.tsx @@ -151,7 +151,7 @@ export function ContextAppContent({ return ( - {interceptedWarnings.length && ( + {Boolean(interceptedWarnings.length) && ( <> diff --git a/src/plugins/discover/public/application/doc/components/doc.test.tsx b/src/plugins/discover/public/application/doc/components/doc.test.tsx index 56eac62b0318..79a1be2cf175 100644 --- a/src/plugins/discover/public/application/doc/components/doc.test.tsx +++ b/src/plugins/discover/public/application/doc/components/doc.test.tsx @@ -18,6 +18,7 @@ import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { setUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/plugin'; import { mockUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/__mocks__'; +import type { UnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/types'; const mockSearchApi = jest.fn(); @@ -68,7 +69,14 @@ async function mountDoc(update = false) { locator: { getUrl: jest.fn(() => Promise.resolve('mock-url')) }, chrome: { setBreadcrumbs: jest.fn() }, }; - setUnifiedDocViewerServices(mockUnifiedDocViewerServices); + setUnifiedDocViewerServices({ + ...mockUnifiedDocViewerServices, + data: { + search: { + search: mockSearchApi, + }, + }, + } as unknown as UnifiedDocViewerServices); await act(async () => { comp = mountWithIntl( diff --git a/src/plugins/discover/public/application/doc/components/doc.tsx b/src/plugins/discover/public/application/doc/components/doc.tsx index 5bf79863ecfb..c604abcdd74d 100644 --- a/src/plugins/discover/public/application/doc/components/doc.tsx +++ b/src/plugins/discover/public/application/doc/components/doc.tsx @@ -119,7 +119,7 @@ export function Doc(props: DocProps) { {reqState === ElasticRequestState.Found && hit !== null && dataView && (
    - +
    )} diff --git a/src/plugins/discover/public/application/main/utils/resolve_data_view.ts b/src/plugins/discover/public/application/main/utils/resolve_data_view.ts index fc6a1ae9d166..761fb9764c82 100644 --- a/src/plugins/discover/public/application/main/utils/resolve_data_view.ts +++ b/src/plugins/discover/public/application/main/utils/resolve_data_view.ts @@ -70,7 +70,7 @@ export async function loadDataView({ let fetchedDataView: DataView | null = null; // try to fetch adhoc data view first try { - fetchedDataView = fetchId ? await dataViews.get(fetchId, false, true) : null; + fetchedDataView = fetchId ? await dataViews.get(fetchId) : null; if (fetchedDataView && !fetchedDataView.isPersisted()) { return { list: dataViewList || [], diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx index 19cf02b43585..421792ca8cb6 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx @@ -195,11 +195,13 @@ export function DiscoverGridFlyout({ }); const flyoutTitle = flyoutCustomization?.title ?? defaultFlyoutTitle; + const flyoutSize = flyoutCustomization?.size ?? 'm'; + return ( { @@ -162,6 +162,38 @@ describe('getSharingData', () => { ]); }); + test('getSearchSource supports nested fields', async () => { + const index = buildDataViewMock({ + name: 'the-data-view', + timeFieldName: 'cool-timefield', + fields: [ + ...dataViewMock.fields, + { + name: 'cool-field-2.field', + type: 'keyword', + subType: { + nested: { + path: 'cool-field-2.field.path', + }, + }, + }, + ] as DataView['fields'], + }); + const searchSourceMock = createSearchSourceMock({ index }); + const { getSearchSource } = await getSharingData( + searchSourceMock, + { + columns: ['cool-field-1', 'cool-field-2'], + }, + services + ); + expect(getSearchSource({}).fields).toStrictEqual([ + { field: 'cool-timefield', include_unmapped: 'true' }, + { field: 'cool-field-1', include_unmapped: 'true' }, + { field: 'cool-field-2.*', include_unmapped: 'true' }, + ]); + }); + test('fields have prepended timeField', async () => { const index = { ...dataViewMock } as DataView; index.timeFieldName = 'cool-timefield'; diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index 0e243385272c..9e3b2b236946 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -17,6 +17,7 @@ import type { Filter } from '@kbn/es-query'; import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public'; import { DOC_HIDE_TIME_COLUMN_SETTING, + isNestedFieldParent, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, } from '@kbn/discover-utils'; @@ -113,7 +114,17 @@ export async function getSharingData( if (useFieldsApi) { searchSource.removeField('fieldsFromSource'); const fields = columns.length - ? columns.map((field) => ({ field, include_unmapped: 'true' })) + ? columns.map((column) => { + let field = column; + + // If this column is a nested field, add a wildcard to the field name in order to fetch + // all leaf fields for the report, since the fields API doesn't support nested field roots + if (isNestedFieldParent(column, index)) { + field = `${column}.*`; + } + + return { field, include_unmapped: 'true' }; + }) : [{ field: '*', include_unmapped: 'true' }]; searchSource.setField('fields', fields); diff --git a/src/plugins/discover/server/config.ts b/src/plugins/discover/server/config.ts new file mode 100644 index 000000000000..5813ce2d5049 --- /dev/null +++ b/src/plugins/discover/server/config.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginConfigDescriptor } from '@kbn/core-plugins-server'; + +const configSchema = schema.object({ + enableUiSettingsValidations: schema.boolean({ defaultValue: false }), +}); + +export type ConfigSchema = TypeOf; + +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; diff --git a/src/plugins/discover/server/index.ts b/src/plugins/discover/server/index.ts index 1b5a9b5080da..4ec924a25859 100644 --- a/src/plugins/discover/server/index.ts +++ b/src/plugins/discover/server/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { KibanaRequest } from '@kbn/core/server'; +import { KibanaRequest, PluginInitializerContext } from '@kbn/core/server'; import { DataPluginStart } from '@kbn/data-plugin/server/plugin'; import { ColumnsFromLocatorFn, SearchSourceFromLocatorFn, TitleFromLocatorFn } from './locator'; @@ -28,7 +28,9 @@ export interface DiscoverServerPluginStart { locator: DiscoverServerPluginLocatorService; } -export const plugin = async () => { +export { config } from './config'; + +export const plugin = async (context: PluginInitializerContext) => { const { DiscoverServerPlugin } = await import('./plugin'); - return new DiscoverServerPlugin(); + return new DiscoverServerPlugin(context); }; diff --git a/src/plugins/discover/server/plugin.ts b/src/plugins/discover/server/plugin.ts index b12833edf67a..dc7761b2ba20 100644 --- a/src/plugins/discover/server/plugin.ts +++ b/src/plugins/discover/server/plugin.ts @@ -12,6 +12,7 @@ import type { EmbeddableSetup } from '@kbn/embeddable-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common'; import type { SharePluginSetup } from '@kbn/share-plugin/server'; +import { PluginInitializerContext } from '@kbn/core/server'; import type { DiscoverServerPluginStart, DiscoverServerPluginStartDeps } from '.'; import { DiscoverAppLocatorDefinition } from '../common/locator'; import { capabilitiesProvider } from './capabilities_provider'; @@ -19,10 +20,17 @@ import { createSearchEmbeddableFactory } from './embeddable'; import { initializeLocatorServices } from './locator'; import { registerSampleData } from './sample_data'; import { getUiSettings } from './ui_settings'; +import { ConfigSchema } from './config'; export class DiscoverServerPlugin implements Plugin { + private readonly config: ConfigSchema; + + constructor(initializerContext: PluginInitializerContext) { + this.config = initializerContext.config.get(); + } + public setup( core: CoreSetup, plugins: { @@ -33,7 +41,7 @@ export class DiscoverServerPlugin } ) { core.capabilities.registerProvider(capabilitiesProvider); - core.uiSettings.register(getUiSettings(core.docLinks)); + core.uiSettings.register(getUiSettings(core.docLinks, this.config.enableUiSettingsValidations)); if (plugins.home) { registerSampleData(plugins.home.sampleData); diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index d6bbbd0eed9f..806ae826bf3a 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -38,8 +38,12 @@ const technicalPreviewLabel = i18n.translate('discover.advancedSettings.technica defaultMessage: 'technical preview', }); -export const getUiSettings: (docLinks: DocLinksServiceSetup) => Record = ( - docLinks: DocLinksServiceSetup +export const getUiSettings: ( + docLinks: DocLinksServiceSetup, + enableValidations: boolean +) => Record = ( + docLinks: DocLinksServiceSetup, + enableValidations: boolean ) => ({ [DEFAULT_COLUMNS_SETTING]: { name: i18n.translate('discover.advancedSettings.defaultColumnsTitle', { @@ -51,7 +55,9 @@ export const getUiSettings: (docLinks: DocLinksServiceSetup) => Record { - return ( - - - - ); -}; diff --git a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx index 93279e311b06..2c9a30431218 100644 --- a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx @@ -12,9 +12,8 @@ import { distinct, map } from 'rxjs'; import React, { ReactNode, useEffect, useMemo, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, htmlIdGenerator } from '@elastic/eui'; -import { isPromise } from '@kbn/std'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; - +import { PanelLoader } from '@kbn/panel-loader'; import { EditPanelAction, RemovePanelAction, @@ -51,6 +50,7 @@ const getEventStatus = (output: EmbeddableOutput): EmbeddablePhase => { export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { const { hideHeader, showShadow, embeddable, hideInspector, onPanelStatusChange } = panelProps; const [node, setNode] = useState(); + const [initialLoadComplete, setInitialLoadComplete] = useState(false); const embeddableRoot: React.RefObject = useMemo(() => React.createRef(), []); const headerId = useMemo(() => htmlIdGenerator()(), []); @@ -129,6 +129,11 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { * Select state from the embeddable */ const loading = useSelectFromEmbeddableOutput('loading', embeddable); + + if (loading === false && !initialLoadComplete) { + setInitialLoadComplete(true); + } + const viewMode = useSelectFromEmbeddableInput('viewMode', embeddable); /** @@ -136,21 +141,30 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { */ useEffect(() => { if (!embeddableRoot.current) return; - const nextNode = embeddable.render(embeddableRoot.current) ?? undefined; - if (isPromise(nextNode)) { - nextNode.then((resolved) => setNode(resolved)); - } else { + + let cancelled = false; + + const render = async (root: HTMLDivElement) => { + const nextNode = (await embeddable.render(root)) ?? undefined; + + if (cancelled) return; + setNode(nextNode); - } + }; + + render(embeddableRoot.current); + const errorSubscription = embeddable.getOutput$().subscribe({ next: (output) => { setOutputError(output.error); }, error: (error) => setOutputError(error), }); + return () => { embeddable?.destroy(); errorSubscription?.unsubscribe(); + cancelled = true; }; }, [embeddable, embeddableRoot]); @@ -207,7 +221,13 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { )} -
    + {!initialLoadComplete && } +
    {node}
    diff --git a/src/plugins/embeddable/public/embeddable_panel/index.tsx b/src/plugins/embeddable/public/embeddable_panel/index.tsx index 9e29d49cbfd5..7c8c87d25598 100644 --- a/src/plugins/embeddable/public/embeddable_panel/index.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/index.tsx @@ -8,16 +8,19 @@ import React from 'react'; +import { PanelLoader } from '@kbn/panel-loader'; import { EmbeddablePanelProps } from './types'; import { useEmbeddablePanel } from './use_embeddable_panel'; -import { EmbeddableLoadingIndicator } from './embeddable_loading_indicator'; /** * Loads and renders an embeddable. */ export const EmbeddablePanel = (props: EmbeddablePanelProps) => { const result = useEmbeddablePanel({ embeddable: props.embeddable }); - if (!result) return ; + if (!result) + return ( + + ); const { embeddable, ...passThroughProps } = props; return ; }; diff --git a/src/plugins/embeddable/tsconfig.json b/src/plugins/embeddable/tsconfig.json index 9055c59c2d84..8239fba0d0d1 100644 --- a/src/plugins/embeddable/tsconfig.json +++ b/src/plugins/embeddable/tsconfig.json @@ -34,6 +34,7 @@ "@kbn/react-kibana-mount", "@kbn/unified-search-plugin", "@kbn/data-views-plugin", + "@kbn/panel-loader", ], "exclude": ["target/**/*"] } diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index eed9628444cc..dddc50328594 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -84,8 +84,6 @@ export interface ExecutionContext< * Logs datatable. */ logDatatable?(name: string, datatable: Datatable): void; - - shouldShowLegendAction?: (actionId: string) => boolean; } /** diff --git a/src/plugins/expressions/common/expression_renderers/types.ts b/src/plugins/expressions/common/expression_renderers/types.ts index e75e0af849ed..7dae307aa6c0 100644 --- a/src/plugins/expressions/common/expression_renderers/types.ts +++ b/src/plugins/expressions/common/expression_renderers/types.ts @@ -105,5 +105,4 @@ export interface IInterpreterRenderHandlers { uiState?: unknown; getExecutionContext(): KibanaExecutionContext | undefined; - shouldShowLegendAction?: (actionId: string) => boolean; } diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index c3d7b1fb9920..f10b8db1f128 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -63,7 +63,6 @@ export class ExpressionLoader { hasCompatibleActions: params?.hasCompatibleActions, getCompatibleCellValueActions: params?.getCompatibleCellValueActions, executionContext: params?.executionContext, - shouldShowLegendAction: params?.shouldShowLegendAction, }); this.render$ = this.renderHandler.render$; this.update$ = this.renderHandler.update$; diff --git a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx index 7c299e1bc724..43723ecc0698 100644 --- a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx @@ -8,7 +8,8 @@ import React, { useRef } from 'react'; import classNames from 'classnames'; -import { EuiLoadingChart, EuiProgress, useEuiTheme } from '@elastic/eui'; +import { PanelLoader } from '@kbn/panel-loader'; +import { EuiProgress, useEuiTheme } from '@elastic/eui'; import { ExpressionRenderError } from '../types'; import type { ExpressionRendererParams } from './use_expression_renderer'; import { useExpressionRenderer } from './use_expression_renderer'; @@ -24,7 +25,6 @@ export interface ReactExpressionRendererProps error?: ExpressionRenderError | null ) => React.ReactElement | React.ReactElement[]; padding?: 'xs' | 's' | 'm' | 'l' | 'xl'; - shouldShowLegendAction?: (actionId: string) => boolean; } export type ReactExpressionRendererType = React.ComponentType; @@ -57,7 +57,7 @@ export function ReactExpressionRenderer({ return (
    - {isEmpty && } + {isEmpty && } {isLoading && ( )} diff --git a/src/plugins/expressions/public/react_expression_renderer_wrapper.tsx b/src/plugins/expressions/public/react_expression_renderer_wrapper.tsx index fe0bfcc42d60..57e2951c1244 100644 --- a/src/plugins/expressions/public/react_expression_renderer_wrapper.tsx +++ b/src/plugins/expressions/public/react_expression_renderer_wrapper.tsx @@ -7,7 +7,7 @@ */ import React, { lazy, Suspense } from 'react'; -import { EuiLoadingSpinner } from '@elastic/eui'; +import { PanelLoader } from '@kbn/panel-loader'; import type { ReactExpressionRendererProps } from './react_expression_renderer'; const ReactExpressionRendererComponent = lazy(async () => { @@ -17,7 +17,7 @@ const ReactExpressionRendererComponent = lazy(async () => { }); export const ReactExpressionRenderer = (props: ReactExpressionRendererProps) => ( - }> + }> ); diff --git a/src/plugins/expressions/public/render.ts b/src/plugins/expressions/public/render.ts index 6bb9c4d0836b..a7b919625b8d 100644 --- a/src/plugins/expressions/public/render.ts +++ b/src/plugins/expressions/public/render.ts @@ -36,7 +36,6 @@ export interface ExpressionRenderHandlerParams { hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise; getCompatibleCellValueActions?: (data: object[]) => Promise; executionContext?: KibanaExecutionContext; - shouldShowLegendAction?: (actionId: string) => boolean; } type UpdateValue = IInterpreterRenderUpdateParams; @@ -67,7 +66,6 @@ export class ExpressionRenderHandler { hasCompatibleActions = async () => false, getCompatibleCellValueActions = async () => [], executionContext, - shouldShowLegendAction, }: ExpressionRenderHandlerParams = {} ) { this.element = element; @@ -120,9 +118,6 @@ export class ExpressionRenderHandler { }, hasCompatibleActions, getCompatibleCellValueActions, - shouldShowLegendAction: (actionId: string) => { - return shouldShowLegendAction?.(actionId) ?? true; - }, }; } diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index a96c0629ce8a..870b44e9bc02 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -67,7 +67,6 @@ export interface IExpressionLoaderParams { * By default, it equals 1000. */ throttle?: number; - shouldShowLegendAction?: (actionId: string) => boolean; } export interface ExpressionRenderError extends Error { diff --git a/src/plugins/expressions/tsconfig.json b/src/plugins/expressions/tsconfig.json index 1f1128ae6ab1..94f1d7852da3 100644 --- a/src/plugins/expressions/tsconfig.json +++ b/src/plugins/expressions/tsconfig.json @@ -16,6 +16,7 @@ "@kbn/std", "@kbn/core-execution-context-common", "@kbn/tinymath", + "@kbn/panel-loader", ], "exclude": [ "target/**/*", diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts index e995510c99fe..f68036496914 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import { i18n } from '@kbn/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; -import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types'; +import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types'; const ecommerceName = i18n.translate('home.sampleData.ecommerceSpecTitle', { defaultMessage: 'Sample eCommerce orders', @@ -19,14 +19,17 @@ const ecommerceDescription = i18n.translate('home.sampleData.ecommerceSpecDescri defaultMessage: 'Sample data, visualizations, and dashboards for tracking eCommerce orders.', }); -export const ecommerceSpecProvider = function (): SampleDatasetSchema { +export const ecommerceSpecProvider: SampleDatasetProvider = ({ staticAssets }) => { return { id: 'ecommerce', name: ecommerceName, description: ecommerceDescription, - previewImagePath: '/plugins/home/assets/sample_data_resources/ecommerce/dashboard.webp', - darkPreviewImagePath: - '/plugins/home/assets/sample_data_resources/ecommerce/dashboard_dark.webp', + previewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/ecommerce/dashboard.webp' + ), + darkPreviewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/ecommerce/dashboard_dark.webp' + ), overviewDashboard: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', defaultIndex: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', savedObjects: getSavedObjects(), @@ -41,6 +44,6 @@ export const ecommerceSpecProvider = function (): SampleDatasetSchema { }, ], status: 'not_installed', - iconPath: '/plugins/home/assets/sample_data_resources/ecommerce/icon.svg', + iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/ecommerce/icon.svg'), }; }; diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts index 691ac8334cbc..7481f4cd5072 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import { i18n } from '@kbn/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; -import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types'; +import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types'; const flightsName = i18n.translate('home.sampleData.flightsSpecTitle', { defaultMessage: 'Sample flight data', @@ -19,13 +19,17 @@ const flightsDescription = i18n.translate('home.sampleData.flightsSpecDescriptio defaultMessage: 'Sample data, visualizations, and dashboards for monitoring flight routes.', }); -export const flightsSpecProvider = function (): SampleDatasetSchema { +export const flightsSpecProvider: SampleDatasetProvider = ({ staticAssets }) => { return { id: 'flights', name: flightsName, description: flightsDescription, - previewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard.webp', - darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/flights/dashboard_dark.webp', + previewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/flights/dashboard.webp' + ), + darkPreviewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/flights/dashboard_dark.webp' + ), overviewDashboard: '7adfa750-4c81-11e8-b3d7-01146121b73d', defaultIndex: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', savedObjects: getSavedObjects(), @@ -40,6 +44,6 @@ export const flightsSpecProvider = function (): SampleDatasetSchema { }, ], status: 'not_installed', - iconPath: '/plugins/home/assets/sample_data_resources/flights/icon.svg', + iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/flights/icon.svg'), }; }; diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts index 219b7ea2cc9d..6f001e85c615 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import { i18n } from '@kbn/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; -import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types'; +import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types'; const logsName = i18n.translate('home.sampleData.logsSpecTitle', { defaultMessage: 'Sample web logs', @@ -20,13 +20,15 @@ const logsDescription = i18n.translate('home.sampleData.logsSpecDescription', { }); export const GLOBE_ICON_PATH = '/plugins/home/assets/sample_data_resources/logs/icon.svg'; -export const logsSpecProvider = function (): SampleDatasetSchema { +export const logsSpecProvider: SampleDatasetProvider = ({ staticAssets }) => { return { id: 'logs', name: logsName, description: logsDescription, - previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.webp', - darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.webp', + previewImagePath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/dashboard.webp'), + darkPreviewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/logs/dashboard_dark.webp' + ), overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b', defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0b247', savedObjects: getSavedObjects(), @@ -42,6 +44,6 @@ export const logsSpecProvider = function (): SampleDatasetSchema { }, ], status: 'not_installed', - iconPath: GLOBE_ICON_PATH, + iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/icon.svg'), }; }; diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/index.ts b/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/index.ts index bfc4ec455419..39dc153eb2b1 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/index.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import { i18n } from '@kbn/i18n'; import { getSavedObjects } from './saved_objects'; import { fieldMappings } from './field_mappings'; -import { SampleDatasetSchema } from '../../lib/sample_dataset_registry_types'; +import { SampleDatasetProvider } from '../../lib/sample_dataset_registry_types'; const logsName = i18n.translate('home.sampleData.logsTsdbSpecTitle', { defaultMessage: 'Sample web logs (TSDB)', @@ -20,7 +20,7 @@ const logsDescription = i18n.translate('home.sampleData.logsTsdbSpecDescription' }); export const GLOBE_ICON_PATH = '/plugins/home/assets/sample_data_resources/logs/icon.svg'; -export const logsTSDBSpecProvider = function (): SampleDatasetSchema { +export const logsTSDBSpecProvider: SampleDatasetProvider = ({ staticAssets }) => { const startDate = new Date(); const endDate = new Date(); startDate.setMonth(startDate.getMonth() - 1); @@ -29,8 +29,10 @@ export const logsTSDBSpecProvider = function (): SampleDatasetSchema { id: 'logstsdb', name: logsName, description: logsDescription, - previewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard.webp', - darkPreviewImagePath: '/plugins/home/assets/sample_data_resources/logs/dashboard_dark.webp', + previewImagePath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/dashboard.webp'), + darkPreviewImagePath: staticAssets.getPluginAssetHref( + '/sample_data_resources/logs/dashboard_dark.webp' + ), overviewDashboard: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef8f5b', defaultIndex: '90943e30-9a47-11e8-b64d-95841ca0c247', savedObjects: getSavedObjects(), @@ -53,6 +55,6 @@ export const logsTSDBSpecProvider = function (): SampleDatasetSchema { }, ], status: 'not_installed', - iconPath: GLOBE_ICON_PATH, + iconPath: staticAssets.getPluginAssetHref('/sample_data_resources/logs/icon.svg'), }; }; diff --git a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts index 9b1212e13b02..eb248cc4d407 100644 --- a/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts +++ b/src/plugins/home/server/services/sample_data/lib/sample_dataset_registry_types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { IStaticAssets } from '@kbn/core/server'; import type { SampleDatasetSchema } from './sample_dataset_schema'; export type { SampleDatasetSchema, DataIndexSchema } from './sample_dataset_schema'; @@ -27,7 +28,11 @@ export enum EmbeddableTypes { SEARCH_EMBEDDABLE_TYPE = 'search', VISUALIZE_EMBEDDABLE_TYPE = 'visualization', } -export type SampleDatasetProvider = () => SampleDatasetSchema; + +export interface SampleDatasetProviderContext { + staticAssets: IStaticAssets; +} +export type SampleDatasetProvider = (context: SampleDatasetProviderContext) => SampleDatasetSchema; /** This type is used to identify an object in a sample dataset. */ export interface SampleObject { diff --git a/src/plugins/home/server/services/sample_data/sample_data_registry.ts b/src/plugins/home/server/services/sample_data/sample_data_registry.ts index 47ddc122f82c..1f96cbe20def 100644 --- a/src/plugins/home/server/services/sample_data/sample_data_registry.ts +++ b/src/plugins/home/server/services/sample_data/sample_data_registry.ts @@ -15,6 +15,7 @@ import { SampleDatasetSchema, SampleDatasetDashboardPanel, AppLinkData, + SampleDatasetProviderContext, } from './lib/sample_dataset_registry_types'; import { sampleDataSchema } from './lib/sample_dataset_schema'; @@ -34,11 +35,15 @@ export class SampleDataRegistry { private readonly sampleDatasets: SampleDatasetSchema[] = []; private readonly appLinksMap = new Map(); + private sampleDataProviderContext?: SampleDatasetProviderContext; private registerSampleDataSet(specProvider: SampleDatasetProvider) { + if (!this.sampleDataProviderContext) { + throw new Error('#registerSampleDataSet called before #setup'); + } let value: SampleDatasetSchema; try { - value = sampleDataSchema.validate(specProvider()); + value = sampleDataSchema.validate(specProvider(this.sampleDataProviderContext)); } catch (error) { throw new Error(`Unable to register sample dataset spec because it's invalid. ${error}`); } @@ -83,6 +88,10 @@ export class SampleDataRegistry { createInstallRoute(router, this.sampleDatasets, logger, usageTracker, core.analytics); createUninstallRoute(router, this.sampleDatasets, logger, usageTracker, core.analytics); + this.sampleDataProviderContext = { + staticAssets: core.http.staticAssets, + }; + this.registerSampleDataSet(flightsSpecProvider); this.registerSampleDataSet(logsSpecProvider); this.registerSampleDataSet(ecommerceSpecProvider); diff --git a/src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts b/src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts index f0746764f464..dd625c608671 100644 --- a/src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts +++ b/src/plugins/home/server/services/tutorials/lib/tutorials_registry_types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { KibanaRequest } from '@kbn/core/server'; +import type { KibanaRequest, IStaticAssets } from '@kbn/core/server'; import type { TutorialSchema } from './tutorial_schema'; export { TutorialsCategory } from '../../../../common/constants'; @@ -25,6 +25,7 @@ export type Platform = 'WINDOWS' | 'OSX' | 'DEB' | 'RPM'; export interface TutorialContext { kibanaBranch: string; + staticAssets: IStaticAssets; [key: string]: unknown; } export type TutorialProvider = (context: TutorialContext) => TutorialSchema; diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts index 5a8c6dc55bda..c8d9fa9d27ae 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.test.ts @@ -166,10 +166,9 @@ describe('TutorialsRegistry', () => { describe('start', () => { test('exposes proper contract', () => { - const start = new TutorialsRegistry(mockInitContext).start( - coreMock.createStart(), - mockCustomIntegrationsPluginSetup - ); + const registry = new TutorialsRegistry(mockInitContext); + registry.setup(mockCoreSetup, mockCustomIntegrationsPluginSetup); + const start = registry.start(coreMock.createStart(), mockCustomIntegrationsPluginSetup); expect(start).toBeDefined(); }); }); diff --git a/src/plugins/home/server/services/tutorials/tutorials_registry.ts b/src/plugins/home/server/services/tutorials/tutorials_registry.ts index 0ef800f63228..eb3c6e931ff6 100644 --- a/src/plugins/home/server/services/tutorials/tutorials_registry.ts +++ b/src/plugins/home/server/services/tutorials/tutorials_registry.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/server'; +import { CoreSetup, CoreStart, PluginInitializerContext, IStaticAssets } from '@kbn/core/server'; import { CustomIntegrationsPluginSetup } from '@kbn/custom-integrations-plugin/server'; import { IntegrationCategory } from '@kbn/custom-integrations-plugin/common'; import { @@ -71,10 +71,13 @@ function registerBeatsTutorialsWithCustomIntegrations( export class TutorialsRegistry { private tutorialProviders: TutorialProvider[] = []; // pre-register all the tutorials we know we want in here private readonly scopedTutorialContextFactories: TutorialContextFactory[] = []; + private staticAssets!: IStaticAssets; constructor(private readonly initContext: PluginInitializerContext) {} public setup(core: CoreSetup, customIntegrations?: CustomIntegrationsPluginSetup) { + this.staticAssets = core.http.staticAssets; + const router = core.http.createRouter(); router.get( { path: '/api/kibana/home/tutorials', validate: false }, @@ -143,7 +146,10 @@ export class TutorialsRegistry { } private get baseTutorialContext(): TutorialContext { - return { kibanaBranch: this.initContext.env.packageInfo.branch }; + return { + kibanaBranch: this.initContext.env.packageInfo.branch, + staticAssets: this.staticAssets, + }; } } diff --git a/src/plugins/home/server/tutorials/activemq_logs/index.ts b/src/plugins/home/server/tutorials/activemq_logs/index.ts index af1a79e445fd..b152d760bd60 100644 --- a/src/plugins/home/server/tutorials/activemq_logs/index.ts +++ b/src/plugins/home/server/tutorials/activemq_logs/index.ts @@ -38,7 +38,7 @@ export function activemqLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-activemq.html', }, }), - euiIconType: '/plugins/home/assets/logos/activemq.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/activemq.svg'), artifacts: { dashboards: [ { @@ -54,7 +54,7 @@ export function activemqLogsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/activemq_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/activemq_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/activemq_metrics/index.ts b/src/plugins/home/server/tutorials/activemq_metrics/index.ts index c5c68ba0fe0e..a255a85fa696 100644 --- a/src/plugins/home/server/tutorials/activemq_metrics/index.ts +++ b/src/plugins/home/server/tutorials/activemq_metrics/index.ts @@ -38,7 +38,7 @@ export function activemqMetricsSpecProvider(context: TutorialContext): TutorialS learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-activemq.html', }, }), - euiIconType: '/plugins/home/assets/logos/activemq.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/activemq.svg'), isBeta: true, artifacts: { application: { diff --git a/src/plugins/home/server/tutorials/apache_logs/index.ts b/src/plugins/home/server/tutorials/apache_logs/index.ts index 2d729daefdc6..3bd77f587f09 100644 --- a/src/plugins/home/server/tutorials/apache_logs/index.ts +++ b/src/plugins/home/server/tutorials/apache_logs/index.ts @@ -55,7 +55,7 @@ export function apacheLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/apache_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/apache_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/apache_metrics/index.ts b/src/plugins/home/server/tutorials/apache_metrics/index.ts index 114483f7414d..a02140189050 100644 --- a/src/plugins/home/server/tutorials/apache_metrics/index.ts +++ b/src/plugins/home/server/tutorials/apache_metrics/index.ts @@ -54,7 +54,7 @@ export function apacheMetricsSpecProvider(context: TutorialContext): TutorialSch }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/apache_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/apache_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/auditbeat/index.ts b/src/plugins/home/server/tutorials/auditbeat/index.ts index e31539857878..fe9928ff368b 100644 --- a/src/plugins/home/server/tutorials/auditbeat/index.ts +++ b/src/plugins/home/server/tutorials/auditbeat/index.ts @@ -54,7 +54,7 @@ processes, users, logins, sockets information, file accesses, and more. \ }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/auditbeat/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/auditbeat/screenshot.webp'), onPrem: onPremInstructions(platforms, context), elasticCloud: cloudInstructions(platforms, context), onPremElasticCloud: onPremCloudInstructions(platforms, context), diff --git a/src/plugins/home/server/tutorials/auditd_logs/index.ts b/src/plugins/home/server/tutorials/auditd_logs/index.ts index 383eb46d83a7..438e847efe33 100644 --- a/src/plugins/home/server/tutorials/auditd_logs/index.ts +++ b/src/plugins/home/server/tutorials/auditd_logs/index.ts @@ -39,7 +39,7 @@ export function auditdLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-auditd.html', }, }), - euiIconType: '/plugins/home/assets/logos/linux.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/linux.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function auditdLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/auditd_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/auditd_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/aws_logs/index.ts b/src/plugins/home/server/tutorials/aws_logs/index.ts index dd20d8d282f1..e8c178c040ad 100644 --- a/src/plugins/home/server/tutorials/aws_logs/index.ts +++ b/src/plugins/home/server/tutorials/aws_logs/index.ts @@ -55,7 +55,7 @@ export function awsLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/aws_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/aws_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/aws_metrics/index.ts b/src/plugins/home/server/tutorials/aws_metrics/index.ts index cdc4a3970b42..d5bf865b7902 100644 --- a/src/plugins/home/server/tutorials/aws_metrics/index.ts +++ b/src/plugins/home/server/tutorials/aws_metrics/index.ts @@ -56,7 +56,7 @@ export function awsMetricsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/aws_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/aws_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/azure_logs/index.ts b/src/plugins/home/server/tutorials/azure_logs/index.ts index 8efa2cea888e..62f75a3eb053 100644 --- a/src/plugins/home/server/tutorials/azure_logs/index.ts +++ b/src/plugins/home/server/tutorials/azure_logs/index.ts @@ -56,7 +56,7 @@ export function azureLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/azure_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/azure_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/azure_metrics/index.ts b/src/plugins/home/server/tutorials/azure_metrics/index.ts index 32f9840b9ed6..59492f6704ac 100644 --- a/src/plugins/home/server/tutorials/azure_metrics/index.ts +++ b/src/plugins/home/server/tutorials/azure_metrics/index.ts @@ -55,7 +55,7 @@ export function azureMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/azure_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/azure_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/barracuda_logs/index.ts b/src/plugins/home/server/tutorials/barracuda_logs/index.ts index 70daca5656a6..d91b77495dca 100644 --- a/src/plugins/home/server/tutorials/barracuda_logs/index.ts +++ b/src/plugins/home/server/tutorials/barracuda_logs/index.ts @@ -40,7 +40,7 @@ export function barracudaLogsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-barracuda.html', }, }), - euiIconType: '/plugins/home/assets/logos/barracuda.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/barracuda.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/checkpoint_logs/index.ts b/src/plugins/home/server/tutorials/checkpoint_logs/index.ts index 3fa333c21839..bd7457f0157f 100644 --- a/src/plugins/home/server/tutorials/checkpoint_logs/index.ts +++ b/src/plugins/home/server/tutorials/checkpoint_logs/index.ts @@ -39,7 +39,7 @@ export function checkpointLogsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-checkpoint.html', }, }), - euiIconType: '/plugins/home/assets/logos/checkpoint.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/checkpoint.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/cisco_logs/index.ts b/src/plugins/home/server/tutorials/cisco_logs/index.ts index 098819c14297..c125c283702d 100644 --- a/src/plugins/home/server/tutorials/cisco_logs/index.ts +++ b/src/plugins/home/server/tutorials/cisco_logs/index.ts @@ -39,7 +39,7 @@ export function ciscoLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-cisco.html', }, }), - euiIconType: '/plugins/home/assets/logos/cisco.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/cisco.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function ciscoLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/cisco_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/cisco_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/cockroachdb_metrics/index.ts b/src/plugins/home/server/tutorials/cockroachdb_metrics/index.ts index 1d5cbd95d67f..14c1d2c1b9c1 100644 --- a/src/plugins/home/server/tutorials/cockroachdb_metrics/index.ts +++ b/src/plugins/home/server/tutorials/cockroachdb_metrics/index.ts @@ -38,7 +38,7 @@ export function cockroachdbMetricsSpecProvider(context: TutorialContext): Tutori learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-cockroachdb.html', }, }), - euiIconType: '/plugins/home/assets/logos/cockroachdb.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/cockroachdb.svg'), artifacts: { dashboards: [ { @@ -57,7 +57,9 @@ export function cockroachdbMetricsSpecProvider(context: TutorialContext): Tutori }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/cockroachdb_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref( + '/cockroachdb_metrics/screenshot.webp' + ), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/consul_metrics/index.ts b/src/plugins/home/server/tutorials/consul_metrics/index.ts index bc1d1b6f1d1e..64b7cb80e881 100644 --- a/src/plugins/home/server/tutorials/consul_metrics/index.ts +++ b/src/plugins/home/server/tutorials/consul_metrics/index.ts @@ -38,7 +38,7 @@ export function consulMetricsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-consul.html', }, }), - euiIconType: '/plugins/home/assets/logos/consul.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/consul.svg'), artifacts: { dashboards: [ { @@ -54,7 +54,7 @@ export function consulMetricsSpecProvider(context: TutorialContext): TutorialSch }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/consul_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/consul_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/coredns_logs/index.ts b/src/plugins/home/server/tutorials/coredns_logs/index.ts index fedea213c008..a740144e0740 100644 --- a/src/plugins/home/server/tutorials/coredns_logs/index.ts +++ b/src/plugins/home/server/tutorials/coredns_logs/index.ts @@ -39,7 +39,7 @@ export function corednsLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-coredns.html', }, }), - euiIconType: '/plugins/home/assets/logos/coredns.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/coredns.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function corednsLogsSpecProvider(context: TutorialContext): TutorialSchem }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/coredns_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/coredns_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/coredns_metrics/index.ts b/src/plugins/home/server/tutorials/coredns_metrics/index.ts index b3e5de7fb58a..82f1205971aa 100644 --- a/src/plugins/home/server/tutorials/coredns_metrics/index.ts +++ b/src/plugins/home/server/tutorials/coredns_metrics/index.ts @@ -38,7 +38,7 @@ export function corednsMetricsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-coredns.html', }, }), - euiIconType: '/plugins/home/assets/logos/coredns.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/coredns.svg'), artifacts: { application: { label: i18n.translate('home.tutorials.corednsMetrics.artifacts.application.label', { @@ -52,7 +52,7 @@ export function corednsMetricsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/coredns_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/coredns_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/couchdb_metrics/index.ts b/src/plugins/home/server/tutorials/couchdb_metrics/index.ts index 59f8431fe6a0..c63d9a045f59 100644 --- a/src/plugins/home/server/tutorials/couchdb_metrics/index.ts +++ b/src/plugins/home/server/tutorials/couchdb_metrics/index.ts @@ -38,7 +38,7 @@ export function couchdbMetricsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-couchdb.html', }, }), - euiIconType: '/plugins/home/assets/logos/couchdb.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/couchdb.svg'), artifacts: { dashboards: [ { @@ -57,7 +57,7 @@ export function couchdbMetricsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/couchdb_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/couchdb_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/crowdstrike_logs/index.ts b/src/plugins/home/server/tutorials/crowdstrike_logs/index.ts index f55d84e7b58c..566624d8252b 100644 --- a/src/plugins/home/server/tutorials/crowdstrike_logs/index.ts +++ b/src/plugins/home/server/tutorials/crowdstrike_logs/index.ts @@ -43,7 +43,7 @@ export function crowdstrikeLogsSpecProvider(context: TutorialContext): TutorialS learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-crowdstrike.html', }, }), - euiIconType: '/plugins/home/assets/logos/crowdstrike.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/crowdstrike.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/cylance_logs/index.ts b/src/plugins/home/server/tutorials/cylance_logs/index.ts index 805391dc4d36..e1781fa69df5 100644 --- a/src/plugins/home/server/tutorials/cylance_logs/index.ts +++ b/src/plugins/home/server/tutorials/cylance_logs/index.ts @@ -39,7 +39,7 @@ export function cylanceLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-cylance.html', }, }), - euiIconType: '/plugins/home/assets/logos/cylance.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/cylance.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/docker_metrics/index.ts b/src/plugins/home/server/tutorials/docker_metrics/index.ts index 180723079acb..6f683c7eb9b7 100644 --- a/src/plugins/home/server/tutorials/docker_metrics/index.ts +++ b/src/plugins/home/server/tutorials/docker_metrics/index.ts @@ -54,7 +54,7 @@ export function dockerMetricsSpecProvider(context: TutorialContext): TutorialSch }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/docker_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/docker_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/elasticsearch_logs/index.ts b/src/plugins/home/server/tutorials/elasticsearch_logs/index.ts index bdcc65ead418..1763a434d490 100644 --- a/src/plugins/home/server/tutorials/elasticsearch_logs/index.ts +++ b/src/plugins/home/server/tutorials/elasticsearch_logs/index.ts @@ -54,7 +54,9 @@ export function elasticsearchLogsSpecProvider(context: TutorialContext): Tutoria }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/elasticsearch_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref( + '/elasticsearch_logs/screenshot.webp' + ), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/envoyproxy_logs/index.ts b/src/plugins/home/server/tutorials/envoyproxy_logs/index.ts index 06f0587e1021..aa071297ed97 100644 --- a/src/plugins/home/server/tutorials/envoyproxy_logs/index.ts +++ b/src/plugins/home/server/tutorials/envoyproxy_logs/index.ts @@ -39,7 +39,7 @@ export function envoyproxyLogsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-envoyproxy.html', }, }), - euiIconType: '/plugins/home/assets/logos/envoyproxy.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/envoyproxy.svg'), artifacts: { dashboards: [ { @@ -58,7 +58,7 @@ export function envoyproxyLogsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/envoyproxy_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/envoyproxy_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/envoyproxy_metrics/index.ts b/src/plugins/home/server/tutorials/envoyproxy_metrics/index.ts index 03bc5d13baf9..8c4396ff90ba 100644 --- a/src/plugins/home/server/tutorials/envoyproxy_metrics/index.ts +++ b/src/plugins/home/server/tutorials/envoyproxy_metrics/index.ts @@ -38,7 +38,7 @@ export function envoyproxyMetricsSpecProvider(context: TutorialContext): Tutoria learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-envoyproxy.html', }, }), - euiIconType: '/plugins/home/assets/logos/envoyproxy.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/envoyproxy.svg'), artifacts: { dashboards: [], exportedFields: { diff --git a/src/plugins/home/server/tutorials/f5_logs/index.ts b/src/plugins/home/server/tutorials/f5_logs/index.ts index ae596b52a538..e79018c6b58e 100644 --- a/src/plugins/home/server/tutorials/f5_logs/index.ts +++ b/src/plugins/home/server/tutorials/f5_logs/index.ts @@ -39,7 +39,7 @@ export function f5LogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-f5.html', }, }), - euiIconType: '/plugins/home/assets/logos/f5.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/f5.svg'), artifacts: { dashboards: [], application: { @@ -53,7 +53,7 @@ export function f5LogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/f5_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/f5_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/fortinet_logs/index.ts b/src/plugins/home/server/tutorials/fortinet_logs/index.ts index 32338480fb00..4128f7460b90 100644 --- a/src/plugins/home/server/tutorials/fortinet_logs/index.ts +++ b/src/plugins/home/server/tutorials/fortinet_logs/index.ts @@ -39,7 +39,7 @@ export function fortinetLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-fortinet.html', }, }), - euiIconType: '/plugins/home/assets/logos/fortinet.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/fortinet.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/gcp_logs/index.ts b/src/plugins/home/server/tutorials/gcp_logs/index.ts index 6c33ac1fbaa0..bc0fa1de8184 100644 --- a/src/plugins/home/server/tutorials/gcp_logs/index.ts +++ b/src/plugins/home/server/tutorials/gcp_logs/index.ts @@ -57,7 +57,7 @@ export function gcpLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/gcp_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/gcp_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/gcp_metrics/index.ts b/src/plugins/home/server/tutorials/gcp_metrics/index.ts index 649fd54dbde5..4b9fc9c23e79 100644 --- a/src/plugins/home/server/tutorials/gcp_metrics/index.ts +++ b/src/plugins/home/server/tutorials/gcp_metrics/index.ts @@ -55,7 +55,7 @@ export function gcpMetricsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/gcp_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/gcp_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/haproxy_logs/index.ts b/src/plugins/home/server/tutorials/haproxy_logs/index.ts index 6d83b9c54499..4cfa85570d8f 100644 --- a/src/plugins/home/server/tutorials/haproxy_logs/index.ts +++ b/src/plugins/home/server/tutorials/haproxy_logs/index.ts @@ -55,7 +55,7 @@ export function haproxyLogsSpecProvider(context: TutorialContext): TutorialSchem }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/haproxy_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/haproxy_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/ibmmq_logs/index.ts b/src/plugins/home/server/tutorials/ibmmq_logs/index.ts index fd3327a555b4..0ca37ece3584 100644 --- a/src/plugins/home/server/tutorials/ibmmq_logs/index.ts +++ b/src/plugins/home/server/tutorials/ibmmq_logs/index.ts @@ -38,7 +38,7 @@ export function ibmmqLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-ibmmq.html', }, }), - euiIconType: '/plugins/home/assets/logos/ibmmq.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/ibmmq.svg'), artifacts: { dashboards: [ { @@ -54,7 +54,7 @@ export function ibmmqLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/ibmmq_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/ibmmq_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/ibmmq_metrics/index.ts b/src/plugins/home/server/tutorials/ibmmq_metrics/index.ts index 6b81919ce281..b6411f1b0bff 100644 --- a/src/plugins/home/server/tutorials/ibmmq_metrics/index.ts +++ b/src/plugins/home/server/tutorials/ibmmq_metrics/index.ts @@ -38,7 +38,7 @@ export function ibmmqMetricsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-ibmmq.html', }, }), - euiIconType: '/plugins/home/assets/logos/ibmmq.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/ibmmq.svg'), isBeta: true, artifacts: { application: { @@ -53,7 +53,7 @@ export function ibmmqMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/ibmmq_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/ibmmq_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/icinga_logs/index.ts b/src/plugins/home/server/tutorials/icinga_logs/index.ts index b8d51b1a1809..c1cf30854342 100644 --- a/src/plugins/home/server/tutorials/icinga_logs/index.ts +++ b/src/plugins/home/server/tutorials/icinga_logs/index.ts @@ -39,7 +39,7 @@ export function icingaLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-icinga.html', }, }), - euiIconType: '/plugins/home/assets/logos/icinga.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/icinga.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function icingaLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/icinga_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/icinga_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/iis_logs/index.ts b/src/plugins/home/server/tutorials/iis_logs/index.ts index 1b7af958d4f9..1ce2657b5092 100644 --- a/src/plugins/home/server/tutorials/iis_logs/index.ts +++ b/src/plugins/home/server/tutorials/iis_logs/index.ts @@ -40,7 +40,7 @@ export function iisLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-iis.html', }, }), - euiIconType: '/plugins/home/assets/logos/iis.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/iis.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ export function iisLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/iis_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/iis_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/iis_metrics/index.ts b/src/plugins/home/server/tutorials/iis_metrics/index.ts index 68f167c7be04..052b90c0719b 100644 --- a/src/plugins/home/server/tutorials/iis_metrics/index.ts +++ b/src/plugins/home/server/tutorials/iis_metrics/index.ts @@ -39,7 +39,7 @@ export function iisMetricsSpecProvider(context: TutorialContext): TutorialSchema }, }), isBeta: true, - euiIconType: '/plugins/home/assets/logos/iis.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/iis.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function iisMetricsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/iis_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/iis_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/infoblox_logs/index.ts b/src/plugins/home/server/tutorials/infoblox_logs/index.ts index ad82d25993dc..f86ccbf0084b 100644 --- a/src/plugins/home/server/tutorials/infoblox_logs/index.ts +++ b/src/plugins/home/server/tutorials/infoblox_logs/index.ts @@ -39,7 +39,7 @@ export function infobloxLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-infoblox.html', }, }), - euiIconType: '/plugins/home/assets/logos/infoblox.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/infoblox.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/iptables_logs/index.ts b/src/plugins/home/server/tutorials/iptables_logs/index.ts index 082b0a239714..856a8b033148 100644 --- a/src/plugins/home/server/tutorials/iptables_logs/index.ts +++ b/src/plugins/home/server/tutorials/iptables_logs/index.ts @@ -42,7 +42,7 @@ export function iptablesLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-iptables.html', }, }), - euiIconType: '/plugins/home/assets/logos/linux.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/linux.svg'), artifacts: { dashboards: [ { @@ -58,7 +58,7 @@ export function iptablesLogsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/iptables_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/iptables_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/juniper_logs/index.ts b/src/plugins/home/server/tutorials/juniper_logs/index.ts index a6d34d1e8447..04d2e708aeab 100644 --- a/src/plugins/home/server/tutorials/juniper_logs/index.ts +++ b/src/plugins/home/server/tutorials/juniper_logs/index.ts @@ -39,7 +39,7 @@ export function juniperLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-juniper.html', }, }), - euiIconType: '/plugins/home/assets/logos/juniper.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/juniper.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/kafka_logs/index.ts b/src/plugins/home/server/tutorials/kafka_logs/index.ts index cb78ffbaeaea..a4918995965c 100644 --- a/src/plugins/home/server/tutorials/kafka_logs/index.ts +++ b/src/plugins/home/server/tutorials/kafka_logs/index.ts @@ -55,7 +55,7 @@ export function kafkaLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/kafka_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/kafka_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/kubernetes_metrics/index.ts b/src/plugins/home/server/tutorials/kubernetes_metrics/index.ts index bb40e88e7541..6db2731349e2 100644 --- a/src/plugins/home/server/tutorials/kubernetes_metrics/index.ts +++ b/src/plugins/home/server/tutorials/kubernetes_metrics/index.ts @@ -57,7 +57,9 @@ export function kubernetesMetricsSpecProvider(context: TutorialContext): Tutoria }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/kubernetes_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref( + '/kubernetes_metrics/screenshot.webp' + ), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/microsoft_logs/index.ts b/src/plugins/home/server/tutorials/microsoft_logs/index.ts index fc8926df0842..bc7eb73f6062 100644 --- a/src/plugins/home/server/tutorials/microsoft_logs/index.ts +++ b/src/plugins/home/server/tutorials/microsoft_logs/index.ts @@ -39,7 +39,7 @@ export function microsoftLogsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-microsoft.html', }, }), - euiIconType: '/plugins/home/assets/logos/microsoft.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/microsoft.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function microsoftLogsSpecProvider(context: TutorialContext): TutorialSch }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/microsoft_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/microsoft_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/misp_logs/index.ts b/src/plugins/home/server/tutorials/misp_logs/index.ts index 7cb31f8db3a4..3fcd6f35faae 100644 --- a/src/plugins/home/server/tutorials/misp_logs/index.ts +++ b/src/plugins/home/server/tutorials/misp_logs/index.ts @@ -39,7 +39,7 @@ export function mispLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-misp.html', }, }), - euiIconType: '/plugins/home/assets/logos/misp.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/misp.svg'), artifacts: { dashboards: [ { @@ -55,7 +55,7 @@ export function mispLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/misp_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/misp_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/mongodb_logs/index.ts b/src/plugins/home/server/tutorials/mongodb_logs/index.ts index 3f2618d15c84..4cd48e2af715 100644 --- a/src/plugins/home/server/tutorials/mongodb_logs/index.ts +++ b/src/plugins/home/server/tutorials/mongodb_logs/index.ts @@ -55,7 +55,7 @@ export function mongodbLogsSpecProvider(context: TutorialContext): TutorialSchem }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/mongodb_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/mongodb_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/mongodb_metrics/index.ts b/src/plugins/home/server/tutorials/mongodb_metrics/index.ts index c4b56cef60d1..441ede88c5c3 100644 --- a/src/plugins/home/server/tutorials/mongodb_metrics/index.ts +++ b/src/plugins/home/server/tutorials/mongodb_metrics/index.ts @@ -57,7 +57,7 @@ export function mongodbMetricsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/mongodb_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/mongodb_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/mssql_logs/index.ts b/src/plugins/home/server/tutorials/mssql_logs/index.ts index 2add9281860b..ab8363afd25b 100644 --- a/src/plugins/home/server/tutorials/mssql_logs/index.ts +++ b/src/plugins/home/server/tutorials/mssql_logs/index.ts @@ -39,7 +39,7 @@ export function mssqlLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-mssql.html', }, }), - euiIconType: '/plugins/home/assets/logos/microsoft.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/microsoft.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/mssql_metrics/index.ts b/src/plugins/home/server/tutorials/mssql_metrics/index.ts index 5dd6bca41a81..33091b6b0450 100644 --- a/src/plugins/home/server/tutorials/mssql_metrics/index.ts +++ b/src/plugins/home/server/tutorials/mssql_metrics/index.ts @@ -38,7 +38,7 @@ export function mssqlMetricsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-mssql.html', }, }), - euiIconType: '/plugins/home/assets/logos/mssql.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/mssql.svg'), isBeta: false, artifacts: { dashboards: [ @@ -55,7 +55,7 @@ export function mssqlMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/mssql_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/mssql_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/munin_metrics/index.ts b/src/plugins/home/server/tutorials/munin_metrics/index.ts index 1e3e091ab0b8..aa9ba8e72ddd 100644 --- a/src/plugins/home/server/tutorials/munin_metrics/index.ts +++ b/src/plugins/home/server/tutorials/munin_metrics/index.ts @@ -26,7 +26,7 @@ export function muninMetricsSpecProvider(context: TutorialContext): TutorialSche defaultMessage: 'Munin Metrics', }), moduleName, - euiIconType: '/plugins/home/assets/logos/munin.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/munin.svg'), isBeta: true, category: TutorialsCategory.METRICS, shortDescription: i18n.translate('home.tutorials.muninMetrics.shortDescription', { diff --git a/src/plugins/home/server/tutorials/mysql_logs/index.ts b/src/plugins/home/server/tutorials/mysql_logs/index.ts index 5ca657283d51..776926d9bd74 100644 --- a/src/plugins/home/server/tutorials/mysql_logs/index.ts +++ b/src/plugins/home/server/tutorials/mysql_logs/index.ts @@ -55,7 +55,7 @@ export function mysqlLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/mysql_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/mysql_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/mysql_metrics/index.ts b/src/plugins/home/server/tutorials/mysql_metrics/index.ts index 8710fb70a4e2..61f6d936f88e 100644 --- a/src/plugins/home/server/tutorials/mysql_metrics/index.ts +++ b/src/plugins/home/server/tutorials/mysql_metrics/index.ts @@ -54,7 +54,7 @@ export function mysqlMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/mysql_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/mysql_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/nats_logs/index.ts b/src/plugins/home/server/tutorials/nats_logs/index.ts index d72a6df5e710..2695edaf9938 100644 --- a/src/plugins/home/server/tutorials/nats_logs/index.ts +++ b/src/plugins/home/server/tutorials/nats_logs/index.ts @@ -40,7 +40,7 @@ export function natsLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-nats.html', }, }), - euiIconType: '/plugins/home/assets/logos/nats.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/nats.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ export function natsLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/nats_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/nats_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/nats_metrics/index.ts b/src/plugins/home/server/tutorials/nats_metrics/index.ts index 1aab107a6121..e9226331b5ec 100644 --- a/src/plugins/home/server/tutorials/nats_metrics/index.ts +++ b/src/plugins/home/server/tutorials/nats_metrics/index.ts @@ -38,7 +38,7 @@ export function natsMetricsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-nats.html', }, }), - euiIconType: '/plugins/home/assets/logos/nats.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/nats.svg'), artifacts: { dashboards: [ { @@ -54,7 +54,7 @@ export function natsMetricsSpecProvider(context: TutorialContext): TutorialSchem }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/nats_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/nats_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/netscout_logs/index.ts b/src/plugins/home/server/tutorials/netscout_logs/index.ts index 9418a787be5d..64e7fb351fff 100644 --- a/src/plugins/home/server/tutorials/netscout_logs/index.ts +++ b/src/plugins/home/server/tutorials/netscout_logs/index.ts @@ -39,7 +39,7 @@ export function netscoutLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-netscout.html', }, }), - euiIconType: '/plugins/home/assets/logos/netscout.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/netscout.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/nginx_logs/index.ts b/src/plugins/home/server/tutorials/nginx_logs/index.ts index 451d1b8acbab..5a08a6ebcddf 100644 --- a/src/plugins/home/server/tutorials/nginx_logs/index.ts +++ b/src/plugins/home/server/tutorials/nginx_logs/index.ts @@ -55,7 +55,7 @@ export function nginxLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/nginx_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/nginx_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/nginx_metrics/index.ts b/src/plugins/home/server/tutorials/nginx_metrics/index.ts index 9441f59bbe56..d133af96d03e 100644 --- a/src/plugins/home/server/tutorials/nginx_metrics/index.ts +++ b/src/plugins/home/server/tutorials/nginx_metrics/index.ts @@ -59,7 +59,7 @@ which must be enabled in your Nginx installation. \ }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/nginx_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/nginx_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/o365_logs/index.ts b/src/plugins/home/server/tutorials/o365_logs/index.ts index c3cecbef3250..87dd8e7dcf24 100644 --- a/src/plugins/home/server/tutorials/o365_logs/index.ts +++ b/src/plugins/home/server/tutorials/o365_logs/index.ts @@ -42,7 +42,7 @@ export function o365LogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-o365.html', }, }), - euiIconType: '/plugins/home/assets/logos/o365.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/o365.svg'), artifacts: { dashboards: [ { @@ -58,7 +58,7 @@ export function o365LogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/o365_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/o365_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/okta_logs/index.ts b/src/plugins/home/server/tutorials/okta_logs/index.ts index c3929cff0909..4e4206ce9531 100644 --- a/src/plugins/home/server/tutorials/okta_logs/index.ts +++ b/src/plugins/home/server/tutorials/okta_logs/index.ts @@ -40,7 +40,7 @@ export function oktaLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-okta.html', }, }), - euiIconType: '/plugins/home/assets/logos/okta.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/okta.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ export function oktaLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/okta_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/okta_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/openmetrics_metrics/index.ts b/src/plugins/home/server/tutorials/openmetrics_metrics/index.ts index 9c0f6e89b6fa..56db28fb0e9e 100644 --- a/src/plugins/home/server/tutorials/openmetrics_metrics/index.ts +++ b/src/plugins/home/server/tutorials/openmetrics_metrics/index.ts @@ -39,7 +39,7 @@ export function openmetricsMetricsSpecProvider(context: TutorialContext): Tutori learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-openmetrics.html', }, }), - euiIconType: '/plugins/home/assets/logos/openmetrics.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/openmetrics.svg'), artifacts: { dashboards: [], exportedFields: { diff --git a/src/plugins/home/server/tutorials/oracle_metrics/index.ts b/src/plugins/home/server/tutorials/oracle_metrics/index.ts index 14f8dd0c3977..71cdedc6bb3b 100644 --- a/src/plugins/home/server/tutorials/oracle_metrics/index.ts +++ b/src/plugins/home/server/tutorials/oracle_metrics/index.ts @@ -40,7 +40,7 @@ export function oracleMetricsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-' + moduleName + '.html', }, }), - euiIconType: '/plugins/home/assets/logos/oracle.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/oracle.svg'), artifacts: { application: { label: i18n.translate('home.tutorials.oracleMetrics.artifacts.application.label', { diff --git a/src/plugins/home/server/tutorials/osquery_logs/index.ts b/src/plugins/home/server/tutorials/osquery_logs/index.ts index 8bf4ba94e949..e73eb7e544df 100644 --- a/src/plugins/home/server/tutorials/osquery_logs/index.ts +++ b/src/plugins/home/server/tutorials/osquery_logs/index.ts @@ -43,7 +43,7 @@ export function osqueryLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-osquery.html', }, }), - euiIconType: '/plugins/home/assets/logos/osquery.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/osquery.svg'), artifacts: { dashboards: [ { diff --git a/src/plugins/home/server/tutorials/panw_logs/index.ts b/src/plugins/home/server/tutorials/panw_logs/index.ts index 1279b0ebaf5a..2aa4d6ebb6f2 100644 --- a/src/plugins/home/server/tutorials/panw_logs/index.ts +++ b/src/plugins/home/server/tutorials/panw_logs/index.ts @@ -42,7 +42,7 @@ export function panwLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-panw.html', }, }), - euiIconType: '/plugins/home/assets/logos/paloalto.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/paloalto.svg'), artifacts: { dashboards: [ { @@ -58,7 +58,7 @@ export function panwLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/panw_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/panw_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/postgresql_logs/index.ts b/src/plugins/home/server/tutorials/postgresql_logs/index.ts index 0338d33d9851..2f8d6acc10f9 100644 --- a/src/plugins/home/server/tutorials/postgresql_logs/index.ts +++ b/src/plugins/home/server/tutorials/postgresql_logs/index.ts @@ -58,7 +58,7 @@ export function postgresqlLogsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/postgresql_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/postgresql_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/rabbitmq_logs/index.ts b/src/plugins/home/server/tutorials/rabbitmq_logs/index.ts index 49ca87b1fbaa..5cfa4d9a7fed 100644 --- a/src/plugins/home/server/tutorials/rabbitmq_logs/index.ts +++ b/src/plugins/home/server/tutorials/rabbitmq_logs/index.ts @@ -39,7 +39,7 @@ export function rabbitmqLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-rabbitmq.html', }, }), - euiIconType: '/plugins/home/assets/logos/rabbitmq.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/rabbitmq.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/rabbitmq_metrics/index.ts b/src/plugins/home/server/tutorials/rabbitmq_metrics/index.ts index 49b4abb6bf83..c3c955e4658a 100644 --- a/src/plugins/home/server/tutorials/rabbitmq_metrics/index.ts +++ b/src/plugins/home/server/tutorials/rabbitmq_metrics/index.ts @@ -58,7 +58,7 @@ export function rabbitmqMetricsSpecProvider(context: TutorialContext): TutorialS }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/rabbitmq_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/rabbitmq_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/radware_logs/index.ts b/src/plugins/home/server/tutorials/radware_logs/index.ts index 4abd897c0aff..607fe2fa6014 100644 --- a/src/plugins/home/server/tutorials/radware_logs/index.ts +++ b/src/plugins/home/server/tutorials/radware_logs/index.ts @@ -39,7 +39,7 @@ export function radwareLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-radware.html', }, }), - euiIconType: '/plugins/home/assets/logos/radware.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/radware.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/redis_logs/index.ts b/src/plugins/home/server/tutorials/redis_logs/index.ts index f0110b1e4f36..5a278706f753 100644 --- a/src/plugins/home/server/tutorials/redis_logs/index.ts +++ b/src/plugins/home/server/tutorials/redis_logs/index.ts @@ -61,7 +61,7 @@ Note that the `slowlog` fileset is experimental. \ }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/redis_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/redis_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/redis_metrics/index.ts b/src/plugins/home/server/tutorials/redis_metrics/index.ts index 1b541226ca24..bef4dcf6b077 100644 --- a/src/plugins/home/server/tutorials/redis_metrics/index.ts +++ b/src/plugins/home/server/tutorials/redis_metrics/index.ts @@ -54,7 +54,7 @@ export function redisMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/redis_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/redis_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/redisenterprise_metrics/index.ts b/src/plugins/home/server/tutorials/redisenterprise_metrics/index.ts index 608ce867727d..fd1c26f4da16 100644 --- a/src/plugins/home/server/tutorials/redisenterprise_metrics/index.ts +++ b/src/plugins/home/server/tutorials/redisenterprise_metrics/index.ts @@ -53,7 +53,9 @@ export function redisenterpriseMetricsSpecProvider(context: TutorialContext): Tu }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/redisenterprise_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref( + '/redisenterprise_metrics/screenshot.webp' + ), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/santa_logs/index.ts b/src/plugins/home/server/tutorials/santa_logs/index.ts index eda644458ba3..292c1b20c41d 100644 --- a/src/plugins/home/server/tutorials/santa_logs/index.ts +++ b/src/plugins/home/server/tutorials/santa_logs/index.ts @@ -56,7 +56,7 @@ export function santaLogsSpecProvider(context: TutorialContext): TutorialSchema }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/santa_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/santa_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/sonicwall_logs/index.ts b/src/plugins/home/server/tutorials/sonicwall_logs/index.ts index 5e88eb03d75d..00995b6767ab 100644 --- a/src/plugins/home/server/tutorials/sonicwall_logs/index.ts +++ b/src/plugins/home/server/tutorials/sonicwall_logs/index.ts @@ -39,7 +39,7 @@ export function sonicwallLogsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-sonicwall.html', }, }), - euiIconType: '/plugins/home/assets/logos/sonicwall.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/sonicwall.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/sophos_logs/index.ts b/src/plugins/home/server/tutorials/sophos_logs/index.ts index a504ae2a3080..5f43d0bccaf5 100644 --- a/src/plugins/home/server/tutorials/sophos_logs/index.ts +++ b/src/plugins/home/server/tutorials/sophos_logs/index.ts @@ -39,7 +39,7 @@ export function sophosLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-sophos.html', }, }), - euiIconType: '/plugins/home/assets/logos/sophos.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/sophos.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/stan_metrics/index.ts b/src/plugins/home/server/tutorials/stan_metrics/index.ts index ca0be2097af1..c83b405e2058 100644 --- a/src/plugins/home/server/tutorials/stan_metrics/index.ts +++ b/src/plugins/home/server/tutorials/stan_metrics/index.ts @@ -38,7 +38,7 @@ export function stanMetricsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-stan.html', }, }), - euiIconType: '/plugins/home/assets/logos/stan.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/stan.svg'), artifacts: { dashboards: [ { @@ -54,7 +54,7 @@ export function stanMetricsSpecProvider(context: TutorialContext): TutorialSchem }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/stan_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/stan_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/statsd_metrics/index.ts b/src/plugins/home/server/tutorials/statsd_metrics/index.ts index a7c8a27aa7af..695c890bb449 100644 --- a/src/plugins/home/server/tutorials/statsd_metrics/index.ts +++ b/src/plugins/home/server/tutorials/statsd_metrics/index.ts @@ -35,7 +35,7 @@ export function statsdMetricsSpecProvider(context: TutorialContext): TutorialSch learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-statsd.html', }, }), - euiIconType: '/plugins/home/assets/logos/statsd.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/statsd.svg'), artifacts: { dashboards: [], exportedFields: { diff --git a/src/plugins/home/server/tutorials/suricata_logs/index.ts b/src/plugins/home/server/tutorials/suricata_logs/index.ts index dfff18cd8f19..aa8a24a843c6 100644 --- a/src/plugins/home/server/tutorials/suricata_logs/index.ts +++ b/src/plugins/home/server/tutorials/suricata_logs/index.ts @@ -40,7 +40,7 @@ export function suricataLogsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-suricata.html', }, }), - euiIconType: '/plugins/home/assets/logos/suricata.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/suricata.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ export function suricataLogsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/suricata_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/suricata_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/system_metrics/index.ts b/src/plugins/home/server/tutorials/system_metrics/index.ts index b9d607c9fc59..1db7e1e33533 100644 --- a/src/plugins/home/server/tutorials/system_metrics/index.ts +++ b/src/plugins/home/server/tutorials/system_metrics/index.ts @@ -40,7 +40,7 @@ It collects system wide statistics and statistics per process and filesystem. \ learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-system.html', }, }), - euiIconType: '/plugins/home/assets/logos/system.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/system.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ It collects system wide statistics and statistics per process and filesystem. \ }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/system_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/system_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/tomcat_logs/index.ts b/src/plugins/home/server/tutorials/tomcat_logs/index.ts index 99198f835402..6694f54428c9 100644 --- a/src/plugins/home/server/tutorials/tomcat_logs/index.ts +++ b/src/plugins/home/server/tutorials/tomcat_logs/index.ts @@ -39,7 +39,7 @@ export function tomcatLogsSpecProvider(context: TutorialContext): TutorialSchema learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-tomcat.html', }, }), - euiIconType: '/plugins/home/assets/logos/tomcat.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/tomcat.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/home/server/tutorials/traefik_logs/index.ts b/src/plugins/home/server/tutorials/traefik_logs/index.ts index 7c096f68aabf..13a1c448c876 100644 --- a/src/plugins/home/server/tutorials/traefik_logs/index.ts +++ b/src/plugins/home/server/tutorials/traefik_logs/index.ts @@ -39,7 +39,7 @@ export function traefikLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-traefik.html', }, }), - euiIconType: '/plugins/home/assets/logos/traefik.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/traefik.svg'), artifacts: { dashboards: [ { diff --git a/src/plugins/home/server/tutorials/traefik_metrics/index.ts b/src/plugins/home/server/tutorials/traefik_metrics/index.ts index 1bba0718fbd9..daa83e051bd2 100644 --- a/src/plugins/home/server/tutorials/traefik_metrics/index.ts +++ b/src/plugins/home/server/tutorials/traefik_metrics/index.ts @@ -35,7 +35,7 @@ export function traefikMetricsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-traefik.html', }, }), - euiIconType: '/plugins/home/assets/logos/traefik.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/traefik.svg'), artifacts: { dashboards: [], exportedFields: { diff --git a/src/plugins/home/server/tutorials/uptime_monitors/index.ts b/src/plugins/home/server/tutorials/uptime_monitors/index.ts index 86b3e99e1105..653cf939108b 100644 --- a/src/plugins/home/server/tutorials/uptime_monitors/index.ts +++ b/src/plugins/home/server/tutorials/uptime_monitors/index.ts @@ -53,7 +53,7 @@ export function uptimeMonitorsSpecProvider(context: TutorialContext): TutorialSc }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/uptime_monitors/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/uptime_monitors/screenshot.webp'), onPrem: onPremInstructions([], context), elasticCloud: cloudInstructions(context), onPremElasticCloud: onPremCloudInstructions(context), diff --git a/src/plugins/home/server/tutorials/uwsgi_metrics/index.ts b/src/plugins/home/server/tutorials/uwsgi_metrics/index.ts index 4fb6725255e0..fedc37523baa 100644 --- a/src/plugins/home/server/tutorials/uwsgi_metrics/index.ts +++ b/src/plugins/home/server/tutorials/uwsgi_metrics/index.ts @@ -38,7 +38,7 @@ export function uwsgiMetricsSpecProvider(context: TutorialContext): TutorialSche learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-uwsgi.html', }, }), - euiIconType: '/plugins/home/assets/logos/uwsgi.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/uwsgi.svg'), isBeta: false, artifacts: { dashboards: [ @@ -55,7 +55,7 @@ export function uwsgiMetricsSpecProvider(context: TutorialContext): TutorialSche }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/uwsgi_metrics/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/uwsgi_metrics/screenshot.webp'), onPrem: onPremInstructions(moduleName, context), elasticCloud: cloudInstructions(moduleName, context), onPremElasticCloud: onPremCloudInstructions(moduleName, context), diff --git a/src/plugins/home/server/tutorials/vsphere_metrics/index.ts b/src/plugins/home/server/tutorials/vsphere_metrics/index.ts index 946da1b884a8..66359772a14c 100644 --- a/src/plugins/home/server/tutorials/vsphere_metrics/index.ts +++ b/src/plugins/home/server/tutorials/vsphere_metrics/index.ts @@ -38,7 +38,7 @@ export function vSphereMetricsSpecProvider(context: TutorialContext): TutorialSc learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-vsphere.html', }, }), - euiIconType: '/plugins/home/assets/logos/vsphere.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/vsphere.svg'), isBeta: true, artifacts: { application: { diff --git a/src/plugins/home/server/tutorials/zeek_logs/index.ts b/src/plugins/home/server/tutorials/zeek_logs/index.ts index 387f1041f497..1460fb6acf9b 100644 --- a/src/plugins/home/server/tutorials/zeek_logs/index.ts +++ b/src/plugins/home/server/tutorials/zeek_logs/index.ts @@ -40,7 +40,7 @@ export function zeekLogsSpecProvider(context: TutorialContext): TutorialSchema { learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-zeek.html', }, }), - euiIconType: '/plugins/home/assets/logos/zeek.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/zeek.svg'), artifacts: { dashboards: [ { @@ -56,7 +56,7 @@ export function zeekLogsSpecProvider(context: TutorialContext): TutorialSchema { }, }, completionTimeMinutes: 10, - previewImagePath: '/plugins/home/assets/zeek_logs/screenshot.webp', + previewImagePath: context.staticAssets.getPluginAssetHref('/zeek_logs/screenshot.webp'), onPrem: onPremInstructions(moduleName, platforms, context), elasticCloud: cloudInstructions(moduleName, platforms, context), onPremElasticCloud: onPremCloudInstructions(moduleName, platforms, context), diff --git a/src/plugins/home/server/tutorials/zookeeper_metrics/index.ts b/src/plugins/home/server/tutorials/zookeeper_metrics/index.ts index dd65f61a78b3..2479650a5198 100644 --- a/src/plugins/home/server/tutorials/zookeeper_metrics/index.ts +++ b/src/plugins/home/server/tutorials/zookeeper_metrics/index.ts @@ -26,7 +26,7 @@ export function zookeeperMetricsSpecProvider(context: TutorialContext): Tutorial defaultMessage: 'Zookeeper Metrics', }), moduleName, - euiIconType: '/plugins/home/assets/logos/zookeeper.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/zookeeper.svg'), isBeta: false, category: TutorialsCategory.METRICS, shortDescription: i18n.translate('home.tutorials.zookeeperMetrics.shortDescription', { diff --git a/src/plugins/home/server/tutorials/zscaler_logs/index.ts b/src/plugins/home/server/tutorials/zscaler_logs/index.ts index 316590c74fd7..47be9df4cdf5 100644 --- a/src/plugins/home/server/tutorials/zscaler_logs/index.ts +++ b/src/plugins/home/server/tutorials/zscaler_logs/index.ts @@ -39,7 +39,7 @@ export function zscalerLogsSpecProvider(context: TutorialContext): TutorialSchem learnMoreLink: '{config.docs.beats.filebeat}/filebeat-module-zscaler.html', }, }), - euiIconType: '/plugins/home/assets/logos/zscaler.svg', + euiIconType: context.staticAssets.getPluginAssetHref('/logos/zscaler.svg'), artifacts: { dashboards: [], application: { diff --git a/src/plugins/image_embeddable/public/image_editor/configure_image.tsx b/src/plugins/image_embeddable/public/image_editor/configure_image.tsx index 416a35f61870..357f3ff46785 100644 --- a/src/plugins/image_embeddable/public/image_editor/configure_image.tsx +++ b/src/plugins/image_embeddable/public/image_editor/configure_image.tsx @@ -11,7 +11,7 @@ import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { FilesContext } from '@kbn/shared-ux-file-context'; import { skip, take, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { ImageConfig } from '../types'; import { ImageEditorFlyout } from './image_editor_flyout'; import { ImageViewerContext } from '../image_viewer'; diff --git a/src/plugins/image_embeddable/public/image_editor/image_editor_flyout.tsx b/src/plugins/image_embeddable/public/image_editor/image_editor_flyout.tsx index 795418438492..c8d5f9b9636f 100644 --- a/src/plugins/image_embeddable/public/image_editor/image_editor_flyout.tsx +++ b/src/plugins/image_embeddable/public/image_editor/image_editor_flyout.tsx @@ -34,7 +34,7 @@ import { FileUpload } from '@kbn/shared-ux-file-upload'; import { FilePicker } from '@kbn/shared-ux-file-picker'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { FileImageMetadata, imageEmbeddableFileKind } from '../imports'; import { ImageConfig } from '../types'; import { ImageViewer } from '../image_viewer/image_viewer'; // use eager version to avoid flickering diff --git a/src/plugins/image_embeddable/public/image_embeddable/image_embeddable_factory.tsx b/src/plugins/image_embeddable/public/image_embeddable/image_embeddable_factory.tsx index ae2b2a4406fa..c824b7b50765 100644 --- a/src/plugins/image_embeddable/public/image_embeddable/image_embeddable_factory.tsx +++ b/src/plugins/image_embeddable/public/image_embeddable/image_embeddable_factory.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { IExternalUrl } from '@kbn/core-http-browser'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { IContainer, EmbeddableInput, diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/__snapshots__/clusters_view.test.tsx.snap b/src/plugins/inspector/public/views/requests/components/details/clusters_view/__snapshots__/clusters_view.test.tsx.snap deleted file mode 100644 index 0186e1c71343..000000000000 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/__snapshots__/clusters_view.test.tsx.snap +++ /dev/null @@ -1,96 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`render should render local and remote cluster details from _clusters 1`] = ` - - - - - -`; - -exports[`render should render local cluster details from _shards 1`] = ` - - - - -`; diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_health/cluster_health.tsx b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_health/cluster_health.tsx index 4e4e57f5284c..af066c3fac71 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_health/cluster_health.tsx +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_health/cluster_health.tsx @@ -8,15 +8,21 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiHealth, EuiText } from '@elastic/eui'; +import { EuiHealth, EuiText, EuiTextProps } from '@elastic/eui'; import { HEALTH_HEX_CODES } from './gradient'; interface Props { count?: number; status: string; + textProps?: EuiTextProps; } -export function ClusterHealth({ count, status }: Props) { +const defaultTextProps: EuiTextProps = { + size: 'xs', + color: 'subdued', +}; + +export function ClusterHealth({ count, status, textProps = defaultTextProps }: Props) { if (typeof count === 'number' && count === 0) { return null; } @@ -48,9 +54,7 @@ export function ClusterHealth({ count, status }: Props) { const label = typeof count === 'number' ? `${count} ${statusLabel}` : statusLabel; return ( - - {label} - + {label} ); } diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.test.tsx b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.test.tsx new file mode 100644 index 000000000000..19c269886041 --- /dev/null +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.test.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import type { ClusterDetails } from '@kbn/es-types'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { ClustersTable } from './clusters_table'; + +describe('ClustersTable', () => { + describe('sorting', () => { + const clusters = { + remote1: { + status: 'successful', + took: 50, + } as unknown as ClusterDetails, + remote2: { + status: 'skipped', + took: 1000, + } as unknown as ClusterDetails, + remote3: { + status: 'failed', + took: 90, + } as unknown as ClusterDetails, + }; + + test('should render rows in native order', () => { + render(); + const tableRows = screen.getAllByRole('row'); + expect(tableRows.length).toBe(4); // 1 header row, 3 data rows + expect(tableRows[1]).toHaveTextContent('Nameremote1StatussuccessfulResponse time50ms'); + expect(tableRows[2]).toHaveTextContent('Nameremote2StatusskippedResponse time1000ms'); + expect(tableRows[3]).toHaveTextContent('Nameremote3StatusfailedResponse time90ms'); + }); + + test('should sort by response time', () => { + render(); + const button = screen.getByRole('button', { + name: 'Response time', + }); + fireEvent.click(button); + const tableRowsAsc = screen.getAllByRole('row'); + expect(tableRowsAsc.length).toBe(4); // 1 header row, 3 data rows + expect(tableRowsAsc[1]).toHaveTextContent('Nameremote1StatussuccessfulResponse time50ms'); + expect(tableRowsAsc[2]).toHaveTextContent('Nameremote3StatusfailedResponse time90ms'); + expect(tableRowsAsc[3]).toHaveTextContent('Nameremote2StatusskippedResponse time1000ms'); + + fireEvent.click(button); + const tableRowsDesc = screen.getAllByRole('row'); + expect(tableRowsDesc.length).toBe(4); // 1 header row, 3 data rows + expect(tableRowsDesc[1]).toHaveTextContent('Nameremote2StatusskippedResponse time1000ms'); + expect(tableRowsDesc[2]).toHaveTextContent('Nameremote3StatusfailedResponse time90ms'); + expect(tableRowsDesc[3]).toHaveTextContent('Nameremote1StatussuccessfulResponse time50ms'); + }); + }); +}); diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.tsx b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.tsx index c9fea1a470f4..03de4a0b999f 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.tsx +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/clusters_table.tsx @@ -6,10 +6,17 @@ * Side Public License, v 1. */ -import React, { useState, ReactNode } from 'react'; +import React, { useMemo, useState, ReactNode } from 'react'; import type { ClusterDetails } from '@kbn/es-types'; import { i18n } from '@kbn/i18n'; -import { EuiBasicTable, type EuiBasicTableColumn, EuiButtonIcon, EuiText } from '@elastic/eui'; +import { + Comparators, + EuiBasicTable, + type EuiBasicTableColumn, + EuiButtonIcon, + EuiText, + Criteria, +} from '@elastic/eui'; import { ClusterView } from './cluster_view'; import { ClusterHealth } from '../clusters_health'; import { LOCAL_CLUSTER_KEY } from '../local_cluster'; @@ -21,7 +28,7 @@ function getInitialExpandedRow(clusters: Record) { : {}; } -interface ClusterColumn { +interface ClusterItem { name: string; status: string; responseTime?: number; @@ -35,6 +42,8 @@ export function ClustersTable({ clusters }: Props) { const [expandedRows, setExpandedRows] = useState>( getInitialExpandedRow(clusters) ); + const [sortField, setSortField] = useState(); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); const toggleDetails = (name: string) => { const nextExpandedRows = { ...expandedRows }; @@ -46,7 +55,17 @@ export function ClustersTable({ clusters }: Props) { setExpandedRows(nextExpandedRows); }; - const columns: Array> = [ + const items = useMemo(() => { + return Object.keys(clusters).map((key) => { + return { + name: key, + status: clusters[key].status, + responseTime: clusters[key].took, + }; + }); + }, [clusters]); + + const columns: Array> = [ { field: 'name', name: i18n.translate('inspector.requests.clusters.table.nameLabel', { @@ -78,6 +97,7 @@ export function ClustersTable({ clusters }: Props) { ); }, + sortable: items.length > 1, width: '60%', }, { @@ -88,6 +108,7 @@ export function ClustersTable({ clusters }: Props) { render: (status: string) => { return ; }, + sortable: items.length > 1, }, { align: 'right' as 'right', @@ -105,22 +126,38 @@ export function ClustersTable({ clusters }: Props) { : null} ), + sortable: items.length > 1, }, ]; return ( { - return { - name: key, - status: clusters[key].status, - responseTime: clusters[key].took, - }; - })} + items={ + sortField + ? items.sort(Comparators.property(sortField, Comparators.default(sortDirection))) + : items + } isExpandable={true} itemIdToExpandedRowMap={expandedRows} itemId="name" columns={columns} + sorting={{ + sort: sortField + ? { + field: sortField, + direction: sortDirection, + } + : undefined, + }} + onChange={({ sort }: Criteria) => { + if (sort) { + setSortField(sort.field); + setSortDirection(sort.direction); + } + }} + noItemsMessage={i18n.translate('inspector.requests.clusters.table.noItemsFound', { + defaultMessage: 'No clusters found', + })} /> ); } diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.test.tsx b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.test.tsx index 971c3bad5bef..7fd1edf1ecc0 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.test.tsx +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; +import { render, screen, fireEvent } from '@testing-library/react'; import { ClustersView } from './clusters_view'; import { Request } from '../../../../../../common/adapters/request/types'; @@ -51,26 +51,33 @@ describe('shouldShow', () => { }); describe('render', () => { - test('should render local cluster details from _shards', () => { - const request = { - response: { - json: { - rawResponse: { - _shards: { - total: 2, - successful: 2, - skipped: 0, - failed: 0, + describe('single cluster', () => { + test('should display table and not display search bar and health bar', () => { + const request = { + response: { + json: { + rawResponse: { + _shards: { + total: 2, + successful: 2, + skipped: 0, + failed: 0, + }, }, }, }, - }, - } as unknown as Request; - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + } as unknown as Request; + render(); + const table = screen.getByRole('table'); + expect(table).not.toBeNull(); + const searchbar = screen.queryByRole('searchbox'); + expect(searchbar).toBeNull(); + const healthbar = screen.queryByText('2 clusters'); + expect(healthbar).toBeNull(); + }); }); - test('should render local and remote cluster details from _clusters', () => { + describe('multiple clusters', () => { const request = { response: { json: { @@ -110,7 +117,35 @@ describe('render', () => { }, }, } as unknown as Request; - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + + test('should display table, search bar, and health bar', () => { + render(); + const table = screen.getByRole('table'); + expect(table).not.toBeNull(); + const searchbar = screen.getByRole('searchbox'); + expect(searchbar).not.toBeNull(); + const healthbar = screen.getByText('2 clusters'); + expect(healthbar).not.toBeNull(); + }); + + test('should filter table and health bar', () => { + render(); + const searchbar = screen.getByRole('searchbox'); + fireEvent.change(searchbar, { target: { value: 'remot' } }); + const tableRows = screen.getAllByRole('row'); + expect(tableRows.length).toBe(2); // table header and matching table row + const healthbar = screen.getByText('1 cluster'); + expect(healthbar).not.toBeNull(); + }); + + test('should display search bar when there are no matches for search', () => { + render(); + const searchbar = screen.getByRole('searchbox'); + fireEvent.change(searchbar, { target: { value: 'nevergonafindme' } }); + const notFoundRow = screen.getByRole('row', { name: 'No clusters found' }); + expect(notFoundRow).not.toBeNull(); + const searchbarAfterSearch = screen.getByRole('searchbox'); + expect(searchbarAfterSearch).not.toBeNull(); + }); }); }); diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.tsx b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.tsx index 8a96847832dc..c14822d93561 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.tsx +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_view.tsx @@ -8,45 +8,100 @@ import React, { Component } from 'react'; import { estypes } from '@elastic/elasticsearch'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiSearchBar, type EuiSearchBarOnChangeArgs, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import type { ClusterDetails } from '@kbn/es-types'; import { Request } from '../../../../../../common/adapters/request/types'; import type { DetailViewProps } from '../types'; -import { getLocalClusterDetails, LOCAL_CLUSTER_KEY } from './local_cluster'; -import { ClustersHealth } from './clusters_health'; +import { ClusterHealth, ClustersHealth } from './clusters_health'; import { ClustersTable } from './clusters_table'; +import { findClusters } from './find_clusters'; -export class ClustersView extends Component { +interface State { + clusters: Record; + showSearchAndStatusBar: boolean; +} + +export class ClustersView extends Component { static shouldShow = (request: Request) => Boolean( (request.response?.json as { rawResponse?: estypes.SearchResponse })?.rawResponse?._shards || (request.response?.json as { rawResponse?: estypes.SearchResponse })?.rawResponse?._clusters ); - render() { - const rawResponse = ( - this.props.request.response?.json as { rawResponse?: estypes.SearchResponse } - )?.rawResponse; - if (!rawResponse) { - return null; - } + constructor(props: DetailViewProps) { + super(props); + const clusters = findClusters(this.props.request); + this.state = { + clusters, + showSearchAndStatusBar: Object.keys(clusters).length > 1, + }; + } - const clusters = rawResponse._clusters - ? ( - rawResponse._clusters as estypes.ClusterStatistics & { - details: Record; - } - ).details - : { - [LOCAL_CLUSTER_KEY]: getLocalClusterDetails(rawResponse), - }; + _onSearchChange = ({ query, error }: EuiSearchBarOnChangeArgs) => { + if (!error) { + this.setState({ clusters: findClusters(this.props.request, query) }); + } + }; - return this.props.request.response?.json ? ( + render() { + return ( <> - {Object.keys(clusters).length > 1 ? : null} - + {this.state.showSearchAndStatusBar ? ( + <> + + ), + }, + { + value: 'partial', + view: ( + + ), + }, + { + value: 'skipped', + view: ( + + ), + }, + { + value: 'failed', + view: ( + + ), + }, + ], + }, + ]} + onChange={this._onSearchChange} + /> + + + + ) : null} + - ) : null; + ); } } diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.test.ts b/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.test.ts new file mode 100644 index 000000000000..79cc378d8912 --- /dev/null +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.test.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiSearchBar } from '@elastic/eui'; +import { findClusters } from './find_clusters'; +import { LOCAL_CLUSTER_KEY } from './local_cluster'; +import { Request } from '../../../../../../common/adapters/request/types'; + +const request = { + response: { + json: { + rawResponse: { + _clusters: { + details: { + [LOCAL_CLUSTER_KEY]: { + status: 'successful', + took: 50, + }, + remote1: { + status: 'skipped', + took: 1000, + }, + remote2: { + status: 'failed', + took: 90, + }, + }, + }, + }, + }, + }, +} as unknown as Request; + +describe('findClusters', () => { + test('should return all clusters when query is not provided', () => { + const clusters = findClusters(request); + expect(Object.keys(clusters)).toEqual([LOCAL_CLUSTER_KEY, 'remote1', 'remote2']); + }); + + test('should filter clusters by cluster name', () => { + const clusters = findClusters(request, EuiSearchBar.Query.parse('remo')); + expect(Object.keys(clusters)).toEqual(['remote1', 'remote2']); + }); + + test('should filter clusters by cluster name and status', () => { + const clusters = findClusters( + request, + EuiSearchBar.Query.parse('remo status:(successful or skipped)') + ); + expect(Object.keys(clusters)).toEqual(['remote1']); + }); + + test('should filter by multiple status values', () => { + const clusters = findClusters( + request, + EuiSearchBar.Query.parse('status:(successful or skipped)') + ); + expect(Object.keys(clusters)).toEqual([LOCAL_CLUSTER_KEY, 'remote1']); + }); +}); diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.ts b/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.ts new file mode 100644 index 000000000000..8b62cf20d1b4 --- /dev/null +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/find_clusters.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { estypes } from '@elastic/elasticsearch'; +import type { ClusterDetails } from '@kbn/es-types'; +import { EuiSearchBar, type Query } from '@elastic/eui'; +import { Request } from '../../../../../../common/adapters/request/types'; +import { getLocalClusterDetails, LOCAL_CLUSTER_KEY } from './local_cluster'; + +export function findClusters(request: Request, query?: Query): Record { + const rawResponse = (request.response?.json as { rawResponse?: estypes.SearchResponse }) + ?.rawResponse; + if (!rawResponse) { + return {}; + } + + const clusters = rawResponse._clusters + ? ( + rawResponse._clusters as estypes.ClusterStatistics & { + details: Record; + } + ).details + : { + [LOCAL_CLUSTER_KEY]: getLocalClusterDetails(rawResponse), + }; + + if (!query) { + return clusters; + } + + const clusterItems = Object.keys(clusters).map((key) => { + return { + name: key, + status: clusters[key].status, + }; + }); + + const narrowedClusterItems = EuiSearchBar.Query.execute(query, clusterItems, { + defaultFields: ['name'], + }); + + const narrowedClusers: Record = {}; + narrowedClusterItems.forEach(({ name }) => { + narrowedClusers[name] = clusters[name]; + }); + return narrowedClusers; +} diff --git a/src/plugins/inspector/public/views/requests/components/request_details.tsx b/src/plugins/inspector/public/views/requests/components/request_details.tsx index 7677cca66b36..cbe7c035afc8 100644 --- a/src/plugins/inspector/public/views/requests/components/request_details.tsx +++ b/src/plugins/inspector/public/views/requests/components/request_details.tsx @@ -96,7 +96,7 @@ export function RequestDetails(props: Props) { ))} - + ) : null; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 0862d6ece004..537b7739bcc0 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -114,6 +114,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'securitySolution:excludeColdAndFrozenTiersInAnalyzer': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'securitySolution:enableCcsWarning': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, @@ -553,7 +557,11 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'observability:profilingPerCoreWatt': { + 'observability:profilingPerVCPUWattX86': { + type: 'integer', + _meta: { description: 'Non-default value of setting.' }, + }, + 'observability:profilingPervCPUWattArm64': { type: 'integer', _meta: { description: 'Non-default value of setting.' }, }, @@ -589,8 +597,16 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'observability:profilingUseLegacyFlamegraphAPI': { + 'observability:profilingUseLegacyCo2Calculation': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'observability:profilingCostPervCPUPerHour': { + type: 'integer', + _meta: { description: 'Non-default value of setting.' }, + }, + 'observability:profilingAWSCostDiscountRate': { + type: 'integer', + _meta: { description: 'Non-default value of setting.' }, + }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 3499471e0d5a..273864af2bb4 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -64,6 +64,7 @@ export interface UsageStats { 'securitySolution:refreshIntervalDefaults': string; 'securitySolution:enableNewsFeed': boolean; 'securitySolution:enableExpandableFlyout': boolean; + 'securitySolution:excludeColdAndFrozenTiersInAnalyzer': boolean; 'securitySolution:enableCcsWarning': boolean; 'search:includeFrozen': boolean; 'courier:maxConcurrentShardRequests': number; @@ -154,8 +155,11 @@ export interface UsageStats { 'securitySolution:enableGroupedNav': boolean; 'securitySolution:showRelatedIntegrations': boolean; 'visualization:visualize:legacyGaugeChartsLibrary': boolean; - 'observability:profilingUseLegacyFlamegraphAPI': boolean; - 'observability:profilingPerCoreWatt': number; + 'observability:profilingPerVCPUWattX86': number; + 'observability:profilingPervCPUWattArm64': number; 'observability:profilingCo2PerKWH': number; 'observability:profilingDatacenterPUE': number; + 'observability:profilingUseLegacyCo2Calculation': boolean; + 'observability:profilingCostPervCPUPerHour': number; + 'observability:profilingAWSCostDiscountRate': number; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/__snapshots__/ops_stats_collector.test.ts.snap b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/__snapshots__/ops_stats_collector.test.ts.snap index 5f4aabf57995..8464a88dfce5 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/__snapshots__/ops_stats_collector.test.ts.snap +++ b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/__snapshots__/ops_stats_collector.test.ts.snap @@ -32,6 +32,8 @@ Object { "utilization": 1, }, "memory": Object { + "array_buffers_in_bytes": 1, + "external_in_bytes": 1, "heap": Object { "size_limit": 1, "total_in_bytes": 1, @@ -51,6 +53,8 @@ Object { "utilization": 1, }, "memory": Object { + "array_buffers_in_bytes": 1, + "external_in_bytes": 1, "heap": Object { "size_limit": 1, "total_in_bytes": 1, diff --git a/src/plugins/links/common/persistable_state/references.ts b/src/plugins/links/common/persistable_state/references.ts index 1410cdc53d23..3c527465a286 100644 --- a/src/plugins/links/common/persistable_state/references.ts +++ b/src/plugins/links/common/persistable_state/references.ts @@ -7,6 +7,7 @@ */ import { Reference } from '@kbn/content-management-utils'; +import { omit } from 'lodash'; import { DASHBOARD_LINK_TYPE, LinksAttributes } from '../content_management'; export function extractReferences({ @@ -22,23 +23,24 @@ export function extractReferences({ const { links } = attributes; const extractedReferences: Reference[] = []; - links.forEach((link) => { + + const newLinks = links.map((link) => { if (link.type === DASHBOARD_LINK_TYPE && link.destination) { const refName = `link_${link.id}_dashboard`; - link.destinationRefName = refName; extractedReferences.push({ name: refName, type: 'dashboard', id: link.destination, }); - delete link.destination; + return { ...omit(link, 'destination'), destinationRefName: refName }; } + return link; }); return { attributes: { ...attributes, - links, + links: newLinks, }, references: references.concat(extractedReferences), }; diff --git a/src/plugins/links/kibana.jsonc b/src/plugins/links/kibana.jsonc index 5f0796d55b43..a058db8a03ce 100644 --- a/src/plugins/links/kibana.jsonc +++ b/src/plugins/links/kibana.jsonc @@ -12,11 +12,12 @@ "dashboard", "embeddable", "kibanaReact", + "kibanaUtils", "presentationUtil", "uiActionsEnhanced", - "kibanaUtils" + "visualizations" ], - "optionalPlugins": ["triggersActionsUi"], + "optionalPlugins": ["triggersActionsUi", "usageCollection"], "requiredBundles": ["savedObjects"] } } diff --git a/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx b/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx index 5ff2bacaf49f..30977b593238 100644 --- a/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx +++ b/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx @@ -7,24 +7,31 @@ */ import classNames from 'classnames'; -import useAsync from 'react-use/lib/useAsync'; import React, { useEffect, useMemo, useState } from 'react'; +import useAsync from 'react-use/lib/useAsync'; import useObservable from 'react-use/lib/useObservable'; -import { - DashboardDrilldownOptions, - DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS, -} from '@kbn/presentation-util-plugin/public'; import { EuiButtonEmpty, EuiListGroupItem } from '@elastic/eui'; -import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; +import { METRIC_TYPE } from '@kbn/analytics'; import { DashboardLocatorParams, getDashboardLocatorParamsFromEmbeddable, } from '@kbn/dashboard-plugin/public'; +import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; +import { + DashboardDrilldownOptions, + DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS, +} from '@kbn/presentation-util-plugin/public'; -import { LINKS_VERTICAL_LAYOUT, LinksLayoutType, Link } from '../../../common/content_management'; +import { + DASHBOARD_LINK_TYPE, + Link, + LinksLayoutType, + LINKS_VERTICAL_LAYOUT, +} from '../../../common/content_management'; +import { trackUiMetric } from '../../services/kibana_services'; +import { useLinks } from '../links_hooks'; import { DashboardLinkStrings } from './dashboard_link_strings'; -import { useLinks } from '../../embeddable/links_embeddable'; import { fetchDashboard } from './dashboard_link_tools'; export const DashboardLinkComponent = ({ @@ -97,9 +104,9 @@ export const DashboardLinkComponent = ({ /** * Dashboard-to-dashboard navigation */ - const { loading: loadingOnClickProps, value: onClickProps } = useAsync(async () => { + const onClickProps = useMemo(() => { /** If the link points to the current dashboard, then there should be no `onClick` or `href` prop */ - if (link.destination === parentDashboardId) return; + if (!link.destination || link.destination === parentDashboardId) return; const linkOptions = { ...DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS, @@ -118,6 +125,8 @@ export const DashboardLinkComponent = ({ return { href, onClick: async (event: React.MouseEvent) => { + trackUiMetric?.(METRIC_TYPE.CLICK, `${DASHBOARD_LINK_TYPE}:click`); + /** * If the link is being opened via a modified click, then we should use the default `href` navigation behaviour * by passing all the dashboard state via the URL - this will keep behaviour consistent across all browsers. @@ -132,26 +141,19 @@ export const DashboardLinkComponent = ({ if (linkOptions.openInNewTab) { window.open(href, '_blank'); } else { - locator.navigate(params); + await locator.navigate(params); } }, }; - }, [link]); + }, [link, dashboardContainer.locator, linksEmbeddable, parentDashboardId]); useEffect(() => { - if (loadingDestinationDashboard || loadingOnClickProps) { + if (loadingDestinationDashboard) { onLoading(); } else { onRender(); } - }, [ - link, - linksEmbeddable, - loadingDestinationDashboard, - loadingOnClickProps, - onLoading, - onRender, - ]); + }, [link, linksEmbeddable, loadingDestinationDashboard, onLoading, onRender]); const id = `dashboardLink--${link.id}`; @@ -178,7 +180,7 @@ export const DashboardLinkComponent = ({ }} iconType={error ? 'warning' : undefined} iconProps={{ className: 'dashboardLinkIcon' }} - isDisabled={Boolean(error) || loadingOnClickProps} + isDisabled={Boolean(error)} className={classNames('linksPanelLink', { linkCurrent: link.destination === parentDashboardId, dashboardLinkError: Boolean(error), diff --git a/src/plugins/links/public/components/editor/links_editor.tsx b/src/plugins/links/public/components/editor/links_editor.tsx index 0fb22efaf850..12e48e5aa463 100644 --- a/src/plugins/links/public/components/editor/links_editor.tsx +++ b/src/plugins/links/public/components/editor/links_editor.tsx @@ -7,41 +7,42 @@ */ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import useMountedState from 'react-use/lib/useMountedState'; import { - EuiForm, EuiBadge, - EuiTitle, EuiButton, - EuiSwitch, - EuiFormRow, - EuiToolTip, - EuiFlexItem, - EuiFlexGroup, - EuiDroppable, - EuiDraggable, - EuiFlyoutBody, EuiButtonEmpty, EuiButtonGroup, - EuiFlyoutFooter, - EuiFlyoutHeader, + EuiButtonGroupOptionProps, EuiDragDropContext, euiDragDropReorder, - EuiButtonGroupOptionProps, + EuiDraggable, + EuiDroppable, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiForm, + EuiFormRow, + EuiSwitch, + EuiTitle, + EuiToolTip, } from '@elastic/eui'; import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; -import { LinksLayoutInfo } from '../../embeddable/types'; import { Link, LinksLayoutType, LINKS_HORIZONTAL_LAYOUT, LINKS_VERTICAL_LAYOUT, } from '../../../common/content_management'; +import { memoizedGetOrderedLinkList } from '../../editor/links_editor_tools'; +import { openLinkEditorFlyout } from '../../editor/open_link_editor_flyout'; +import { LinksLayoutInfo } from '../../embeddable/types'; import { coreServices } from '../../services/kibana_services'; import { LinksStrings } from '../links_strings'; -import { openLinkEditorFlyout } from '../../editor/open_link_editor_flyout'; -import { memoizedGetOrderedLinkList } from '../../editor/links_editor_tools'; import { LinksEditorEmptyPrompt } from './links_editor_empty_prompt'; import { LinksEditorSingleLink } from './links_editor_single_link'; @@ -80,6 +81,7 @@ const LinksEditor = ({ isByReference: boolean; }) => { const toasts = coreServices.notifications.toasts; + const isMounted = useMountedState(); const editLinkFlyoutRef = useRef(null); const [currentLayout, setCurrentLayout] = useState( @@ -294,7 +296,9 @@ const LinksEditor = ({ }); }) .finally(() => { - setIsSaving(false); + if (isMounted()) { + setIsSaving(false); + } }); } else { onAddToDashboard(orderedLinks, currentLayout); diff --git a/src/plugins/links/public/components/external_link/external_link_component.tsx b/src/plugins/links/public/components/external_link/external_link_component.tsx index ac409cfbac4c..4af95c83cc32 100644 --- a/src/plugins/links/public/components/external_link/external_link_component.tsx +++ b/src/plugins/links/public/components/external_link/external_link_component.tsx @@ -9,15 +9,21 @@ import React, { useMemo, useState } from 'react'; import useMount from 'react-use/lib/useMount'; +import { EuiListGroupItem } from '@elastic/eui'; +import { METRIC_TYPE } from '@kbn/analytics'; import { - UrlDrilldownOptions, DEFAULT_URL_DRILLDOWN_OPTIONS, + UrlDrilldownOptions, } from '@kbn/ui-actions-enhanced-plugin/public'; -import { EuiListGroupItem } from '@elastic/eui'; +import { + EXTERNAL_LINK_TYPE, + Link, + LinksLayoutType, + LINKS_VERTICAL_LAYOUT, +} from '../../../common/content_management'; +import { coreServices, trackUiMetric } from '../../services/kibana_services'; import { validateUrl } from './external_link_tools'; -import { coreServices } from '../../services/kibana_services'; -import { Link, LinksLayoutType, LINKS_VERTICAL_LAYOUT } from '../../../common/content_management'; export const ExternalLinkComponent = ({ link, @@ -78,6 +84,8 @@ export const ExternalLinkComponent = ({ onClick={async (event) => { if (!destination) return; + trackUiMetric?.(METRIC_TYPE.CLICK, `${EXTERNAL_LINK_TYPE}:click`); + /** Only use `navigateToUrl` if we **aren't** opening in a new window/tab; otherwise, just use default href handling */ const modifiedClick = event.ctrlKey || event.metaKey || event.shiftKey; if (!modifiedClick) { diff --git a/src/plugins/links/public/components/links_component.tsx b/src/plugins/links/public/components/links_component.tsx index c72c0db04fd5..0da40365abad 100644 --- a/src/plugins/links/public/components/links_component.tsx +++ b/src/plugins/links/public/components/links_component.tsx @@ -6,29 +6,28 @@ * Side Public License, v 1. */ +import { EuiListGroup, EuiPanel } from '@elastic/eui'; import React, { useEffect, useMemo } from 'react'; import useMap from 'react-use/lib/useMap'; -import { EuiListGroup, EuiPanel } from '@elastic/eui'; -import { useLinks } from '../embeddable/links_embeddable'; -import { ExternalLinkComponent } from './external_link/external_link_component'; -import { DashboardLinkComponent } from './dashboard_link/dashboard_link_component'; -import { memoizedGetOrderedLinkList } from '../editor/links_editor_tools'; import { DASHBOARD_LINK_TYPE, LINKS_HORIZONTAL_LAYOUT, LINKS_VERTICAL_LAYOUT, } from '../../common/content_management'; +import { memoizedGetOrderedLinkList } from '../editor/links_editor_tools'; +import { DashboardLinkComponent } from './dashboard_link/dashboard_link_component'; +import { ExternalLinkComponent } from './external_link/external_link_component'; import './links_component.scss'; +import { useLinks, useLinksAttributes } from './links_hooks'; export const LinksComponent = () => { const linksEmbeddable = useLinks(); - const links = linksEmbeddable.select((state) => state.componentState.links); - const layout = linksEmbeddable.select((state) => state.componentState.layout); + const linksAttributes = useLinksAttributes(); const [linksLoading, { set: setLinkIsLoading }] = useMap( Object.fromEntries( - (links ?? []).map((link) => { + (linksAttributes?.links ?? []).map((link) => { return [link.id, true]; }) ) @@ -43,12 +42,12 @@ export const LinksComponent = () => { }, [linksLoading, linksEmbeddable]); const orderedLinks = useMemo(() => { - if (!links) return []; - return memoizedGetOrderedLinkList(links); - }, [links]); + if (!linksAttributes?.links) return []; + return memoizedGetOrderedLinkList(linksAttributes?.links); + }, [linksAttributes]); const linkItems: { [id: string]: { id: string; content: JSX.Element } } = useMemo(() => { - return (links ?? []).reduce((prev, currentLink) => { + return (linksAttributes?.links ?? []).reduce((prev, currentLink) => { return { ...prev, [currentLink.id]: { @@ -58,7 +57,7 @@ export const LinksComponent = () => { setLinkIsLoading(currentLink.id, true)} onRender={() => setLinkIsLoading(currentLink.id, false)} /> @@ -66,26 +65,26 @@ export const LinksComponent = () => { setLinkIsLoading(currentLink.id, false)} /> ), }, }; }, {}); - }, [links, layout, setLinkIsLoading]); + }, [linksAttributes?.links, linksAttributes?.layout, setLinkIsLoading]); return ( {orderedLinks.map((link) => linkItems[link.id].content)} diff --git a/src/plugins/links/public/components/links_hooks.tsx b/src/plugins/links/public/components/links_hooks.tsx new file mode 100644 index 000000000000..aa33c9d0f3ac --- /dev/null +++ b/src/plugins/links/public/components/links_hooks.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useContext, useEffect, useState } from 'react'; + +import { LinksAttributes } from '../../common/content_management'; +import { LinksContext, LinksEmbeddable } from '../embeddable/links_embeddable'; + +export const useLinks = (): LinksEmbeddable => { + const linksEmbeddable = useContext(LinksContext); + if (linksEmbeddable == null) { + throw new Error('useLinks must be used inside LinksContext.'); + } + return linksEmbeddable!; +}; + +export const useLinksAttributes = (): LinksAttributes | undefined => { + const linksEmbeddable = useLinks(); + const [attributes, setAttributes] = useState( + linksEmbeddable.attributes + ); + + useEffect(() => { + const attributesSubscription = linksEmbeddable.attributes$.subscribe((newAttributes) => { + setAttributes(newAttributes); + }); + return () => { + attributesSubscription.unsubscribe(); + }; + }, [linksEmbeddable.attributes$]); + + return attributes; +}; diff --git a/src/plugins/links/public/content_management/links_content_management_client.ts b/src/plugins/links/public/content_management/links_content_management_client.ts index 777fd8731d69..586b5aff5efb 100644 --- a/src/plugins/links/public/content_management/links_content_management_client.ts +++ b/src/plugins/links/public/content_management/links_content_management_client.ts @@ -7,8 +7,9 @@ */ import type { SearchQuery } from '@kbn/content-management-plugin/common'; +import { SerializableAttributes, VisualizationClient } from '@kbn/visualizations-plugin/public'; +import { CONTENT_ID as contentTypeId, CONTENT_ID } from '../../common'; import type { LinksCrudTypes } from '../../common/content_management'; -import { CONTENT_ID as contentTypeId } from '../../common'; import { contentManagement } from '../services/kibana_services'; const get = async (id: string) => { @@ -65,3 +66,9 @@ export const linksClient = { delete: deleteLinks, search, }; + +export function getLinksClient< + Attr extends SerializableAttributes = SerializableAttributes +>(): VisualizationClient { + return linksClient as unknown as VisualizationClient; +} diff --git a/src/plugins/links/public/editor/open_editor_flyout.tsx b/src/plugins/links/public/editor/open_editor_flyout.tsx index 1c722a484eb1..d47b178d5ff9 100644 --- a/src/plugins/links/public/editor/open_editor_flyout.tsx +++ b/src/plugins/links/public/editor/open_editor_flyout.tsx @@ -7,18 +7,20 @@ */ import React from 'react'; +import { skip, take } from 'rxjs/operators'; -import { withSuspense } from '@kbn/shared-ux-utility'; -import { toMountPoint } from '@kbn/react-kibana-mount'; import { EuiLoadingSpinner, EuiPanel } from '@elastic/eui'; -import { tracksOverlays } from '@kbn/embeddable-plugin/public'; import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; +import { tracksOverlays } from '@kbn/embeddable-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { withSuspense } from '@kbn/shared-ux-utility'; -import { LinksInput, LinksByReferenceInput, LinksEditorFlyoutReturn } from '../embeddable/types'; -import { coreServices } from '../services/kibana_services'; -import { runSaveToLibrary } from '../content_management/save_to_library'; +import { OverlayRef } from '@kbn/core-mount-utils-browser'; import { Link, LinksLayoutType } from '../../common/content_management'; +import { runSaveToLibrary } from '../content_management/save_to_library'; +import { LinksByReferenceInput, LinksEditorFlyoutReturn, LinksInput } from '../embeddable/types'; import { getLinksAttributeService } from '../services/attribute_service'; +import { coreServices } from '../services/kibana_services'; const LazyLinksEditor = React.lazy(() => import('../components/editor/links_editor')); @@ -40,7 +42,8 @@ export async function openEditorFlyout( const { attributes } = await attributeService.unwrapAttributes(initialInput); const isByReference = attributeService.inputIsRefType(initialInput); const initialLinks = attributes?.links; - const overlayTracker = tracksOverlays(parentDashboard) ? parentDashboard : undefined; + const overlayTracker = + parentDashboard && tracksOverlays(parentDashboard) ? parentDashboard : undefined; if (!initialLinks) { /** @@ -55,6 +58,22 @@ export async function openEditorFlyout( } return new Promise((resolve, reject) => { + const closeEditorFlyout = (editorFlyout: OverlayRef) => { + if (overlayTracker) { + overlayTracker.clearOverlays(); + } else { + editorFlyout.close(); + } + }; + + /** + * Close the flyout whenever the app changes - this handles cases for when the flyout is open outside of the + * Dashboard app (`overlayTracker` is not available) + */ + coreServices.application.currentAppId$.pipe(skip(1), take(1)).subscribe(() => { + if (!overlayTracker) editorFlyout.close(); + }); + const onSaveToLibrary = async (newLinks: Link[], newLayout: LinksLayoutType) => { const newAttributes = { ...attributes, @@ -74,7 +93,7 @@ export async function openEditorFlyout( attributes: newAttributes, }); parentDashboard?.reload(); - if (overlayTracker) overlayTracker.clearOverlays(); + closeEditorFlyout(editorFlyout); }; const onAddToDashboard = (newLinks: Link[], newLayout: LinksLayoutType) => { @@ -94,12 +113,12 @@ export async function openEditorFlyout( attributes: newAttributes, }); parentDashboard?.reload(); - if (overlayTracker) overlayTracker.clearOverlays(); + closeEditorFlyout(editorFlyout); }; const onCancel = () => { reject(); - if (overlayTracker) overlayTracker.clearOverlays(); + closeEditorFlyout(editorFlyout); }; const editorFlyout = coreServices.overlays.openFlyout( @@ -125,6 +144,8 @@ export async function openEditorFlyout( } ); - if (overlayTracker) overlayTracker.openOverlay(editorFlyout); + if (overlayTracker) { + overlayTracker.openOverlay(editorFlyout); + } }); } diff --git a/src/plugins/links/public/embeddable/links_embeddable.tsx b/src/plugins/links/public/embeddable/links_embeddable.tsx index 032b0099ed45..d803b9df9e8c 100644 --- a/src/plugins/links/public/embeddable/links_embeddable.tsx +++ b/src/plugins/links/public/embeddable/links_embeddable.tsx @@ -6,37 +6,25 @@ * Side Public License, v 1. */ -import React, { createContext, useContext } from 'react'; -import { unmountComponentAtNode } from 'react-dom'; -import { Subscription, distinctUntilChanged, skip, switchMap } from 'rxjs'; import deepEqual from 'fast-deep-equal'; +import React, { createContext } from 'react'; +import { unmountComponentAtNode } from 'react-dom'; +import { distinctUntilChanged, skip, Subject, Subscription, switchMap } from 'rxjs'; +import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; import { AttributeService, Embeddable, ReferenceOrValueEmbeddable, SavedObjectEmbeddableInput, } from '@kbn/embeddable-plugin/public'; -import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; -import { ReduxEmbeddableTools, ReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; -import { linksReducers } from './links_reducers'; -import { LinksByReferenceInput, LinksByValueInput, LinksReduxState } from './types'; -import { LinksComponent } from '../components/links_component'; -import { LinksInput, LinksOutput } from './types'; -import { LinksAttributes } from '../../common/content_management'; import { CONTENT_ID } from '../../common'; +import { LinksAttributes } from '../../common/content_management'; +import { LinksComponent } from '../components/links_component'; +import { LinksByReferenceInput, LinksByValueInput, LinksInput, LinksOutput } from './types'; export const LinksContext = createContext(null); -export const useLinks = (): LinksEmbeddable => { - const linksEmbeddable = useContext(LinksContext); - if (linksEmbeddable == null) { - throw new Error('useLinks must be used inside LinksContext.'); - } - return linksEmbeddable!; -}; - -type LinksReduxEmbeddableTools = ReduxEmbeddableTools; export interface LinksConfig { editable: boolean; @@ -53,20 +41,10 @@ export class LinksEmbeddable private isDestroyed?: boolean; private subscriptions: Subscription = new Subscription(); - // state management - /** - * TODO: Keep track of the necessary state without the redux embeddable tools; it's kind of overkill here. - * Related issue: https://github.com/elastic/kibana/issues/167577 - */ - public select: LinksReduxEmbeddableTools['select']; - public getState: LinksReduxEmbeddableTools['getState']; - public dispatch: LinksReduxEmbeddableTools['dispatch']; - public onStateChange: LinksReduxEmbeddableTools['onStateChange']; - - private cleanupStateTools: () => void; + public attributes?: LinksAttributes; + public attributes$ = new Subject(); constructor( - reduxToolsPackage: ReduxToolsPackage, config: LinksConfig, initialInput: LinksInput, private attributeService: AttributeService, @@ -81,29 +59,11 @@ export class LinksEmbeddable parent ); - /** Build redux embeddable tools */ - const reduxEmbeddableTools = reduxToolsPackage.createReduxEmbeddableTools< - LinksReduxState, - typeof linksReducers - >({ - embeddable: this, - reducers: linksReducers, - initialComponentState: { - title: '', - }, - }); - - this.select = reduxEmbeddableTools.select; - this.getState = reduxEmbeddableTools.getState; - this.dispatch = reduxEmbeddableTools.dispatch; - this.cleanupStateTools = reduxEmbeddableTools.cleanup; - this.onStateChange = reduxEmbeddableTools.onStateChange; - this.initializeSavedLinks() .then(() => this.setInitializationFinished()) .catch((e: Error) => this.onFatalError(e)); - // By-value panels should update the componentState when input changes + // By-value panels should update the links attributes when input changes this.subscriptions.add( this.getInput$() .pipe( @@ -113,25 +73,28 @@ export class LinksEmbeddable ) .subscribe() ); + + // Keep attributes in sync with subject value so it can be used in output + this.subscriptions.add( + this.attributes$.pipe(distinctUntilChanged(deepEqual)).subscribe((attributes) => { + this.attributes = attributes; + }) + ); } private async initializeSavedLinks() { const { attributes } = await this.attributeService.unwrapAttributes(this.getInput()); - if (this.isDestroyed) return; - - this.dispatch.setAttributes(attributes); - + this.attributes$.next(attributes); await this.initializeOutput(); } private async initializeOutput() { - const attributes = this.getState().componentState; const { title, description } = this.getInput(); this.updateOutput({ - defaultTitle: attributes.title, - defaultDescription: attributes.description, - title: title ?? attributes.title, - description: description ?? attributes.description, + defaultTitle: this.attributes?.title, + defaultDescription: this.attributes?.description, + title: title ?? this.attributes?.title, + description: description ?? this.attributes?.description, }); } @@ -162,7 +125,7 @@ export class LinksEmbeddable public async reload() { if (this.isDestroyed) return; - // By-reference embeddable panels are reloaded when changed, so update the componentState + // By-reference embeddable panels are reloaded when changed, so update the attributes this.initializeSavedLinks(); if (this.domNode) { this.render(this.domNode); @@ -173,7 +136,6 @@ export class LinksEmbeddable this.isDestroyed = true; super.destroy(); this.subscriptions.unsubscribe(); - this.cleanupStateTools(); if (this.domNode) { unmountComponentAtNode(this.domNode); } diff --git a/src/plugins/links/public/embeddable/links_embeddable_factory.ts b/src/plugins/links/public/embeddable/links_embeddable_factory.ts index e0502d34a742..e1446aff316a 100644 --- a/src/plugins/links/public/embeddable/links_embeddable_factory.ts +++ b/src/plugins/links/public/embeddable/links_embeddable_factory.ts @@ -6,34 +6,33 @@ * Side Public License, v 1. */ +import { DASHBOARD_GRID_COLUMN_COUNT } from '@kbn/dashboard-plugin/public'; +import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; +import { IProvidesPanelPlacementSettings } from '@kbn/dashboard-plugin/public/dashboard_container/component/panel_placement/types'; +import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; import { EmbeddableFactory, EmbeddableFactoryDefinition, ErrorEmbeddable, } from '@kbn/embeddable-plugin/public'; import { - MigrateFunctionsObject, GetMigrationFunctionObjectFn, + MigrateFunctionsObject, } from '@kbn/kibana-utils-plugin/common'; -import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; -import { DASHBOARD_GRID_COLUMN_COUNT } from '@kbn/dashboard-plugin/public'; import { UiActionsPresentableGrouping } from '@kbn/ui-actions-plugin/public'; -import { lazyLoadReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; -import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; -import { IProvidesPanelPlacementSettings } from '@kbn/dashboard-plugin/public/dashboard_container/component/panel_placement/types'; +import { APP_ICON, APP_NAME, CONTENT_ID } from '../../common'; +import { LinksAttributes } from '../../common/content_management'; +import { extract, inject } from '../../common/embeddable'; +import { LinksStrings } from '../components/links_strings'; +import { getLinksAttributeService } from '../services/attribute_service'; import { coreServices, presentationUtil, untilPluginStartServicesReady, } from '../services/kibana_services'; -import { extract, inject } from '../../common/embeddable'; import type { LinksEmbeddable } from './links_embeddable'; -import { LinksStrings } from '../components/links_strings'; -import { APP_ICON, APP_NAME, CONTENT_ID } from '../../common'; -import { LinksAttributes } from '../../common/content_management'; -import { getLinksAttributeService } from '../services/attribute_service'; -import { LinksInput, LinksByReferenceInput, LinksEditorFlyoutReturn } from './types'; +import { LinksByReferenceInput, LinksEditorFlyoutReturn, LinksInput } from './types'; export type LinksFactory = EmbeddableFactory; @@ -111,12 +110,10 @@ export class LinksFactoryDefinition public async create(initialInput: LinksInput, parent: DashboardContainer) { await untilPluginStartServicesReady(); - const reduxEmbeddablePackage = await lazyLoadReduxToolsPackage(); const { LinksEmbeddable } = await import('./links_embeddable'); const editable = await this.isEditable(); return new LinksEmbeddable( - reduxEmbeddablePackage, { editable }, { ...getDefaultLinksInput(), ...initialInput }, getLinksAttributeService(), @@ -128,8 +125,6 @@ export class LinksFactoryDefinition initialInput: LinksInput, parent?: DashboardContainer ): Promise { - if (!parent) return { newInput: {} }; - const { openEditorFlyout } = await import('../editor/open_editor_flyout'); const { newInput, attributes } = await openEditorFlyout( diff --git a/src/plugins/links/public/embeddable/links_reducers.ts b/src/plugins/links/public/embeddable/links_reducers.ts deleted file mode 100644 index 659b19058adb..000000000000 --- a/src/plugins/links/public/embeddable/links_reducers.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { WritableDraft } from 'immer/dist/types/types-external'; - -import { PayloadAction } from '@reduxjs/toolkit'; - -import { LinksReduxState } from './types'; -import { LinksAttributes } from '../../common/content_management'; - -export const linksReducers = { - setLoading: (state: WritableDraft, action: PayloadAction) => { - state.output.loading = action.payload; - }, - - setAttributes: ( - state: WritableDraft, - action: PayloadAction - ) => { - state.componentState = { ...action.payload }; - }, -}; diff --git a/src/plugins/links/public/plugin.ts b/src/plugins/links/public/plugin.ts index 7927de88b80e..f72f45d4c6a2 100644 --- a/src/plugins/links/public/plugin.ts +++ b/src/plugins/links/public/plugin.ts @@ -6,22 +6,29 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { ContentManagementPublicSetup, ContentManagementPublicStart, } from '@kbn/content-management-plugin/public'; +import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { DashboardStart } from '@kbn/dashboard-plugin/public'; +import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import { VisualizationsSetup } from '@kbn/visualizations-plugin/public'; -import { APP_NAME } from '../common'; +import { APP_ICON, APP_NAME, CONTENT_ID, LATEST_VERSION } from '../common'; +import { LinksCrudTypes } from '../common/content_management'; +import { LinksStrings } from './components/links_strings'; +import { getLinksClient } from './content_management/links_content_management_client'; import { LinksFactoryDefinition } from './embeddable'; -import { CONTENT_ID, LATEST_VERSION } from '../common'; +import { LinksByReferenceInput } from './embeddable/types'; import { setKibanaServices } from './services/kibana_services'; export interface LinksSetupDependencies { embeddable: EmbeddableSetup; + visualizations: VisualizationsSetup; contentManagement: ContentManagementPublicSetup; } @@ -30,6 +37,7 @@ export interface LinksStartDependencies { dashboard: DashboardStart; presentationUtil: PresentationUtilPluginStart; contentManagement: ContentManagementPublicStart; + usageCollection?: UsageCollectionStart; } export class LinksPlugin @@ -39,7 +47,9 @@ export class LinksPlugin public setup(core: CoreSetup, plugins: LinksSetupDependencies) { core.getStartServices().then(([_, deps]) => { - plugins.embeddable.registerEmbeddableFactory(CONTENT_ID, new LinksFactoryDefinition()); + const linksFactory = new LinksFactoryDefinition(); + + plugins.embeddable.registerEmbeddableFactory(CONTENT_ID, linksFactory); plugins.contentManagement.registry.register({ id: CONTENT_ID, @@ -48,6 +58,53 @@ export class LinksPlugin }, name: APP_NAME, }); + + const getExplicitInput = async ({ + savedObjectId, + parent, + }: { + savedObjectId?: string; + parent?: DashboardContainer; + }) => { + try { + await linksFactory.getExplicitInput({ savedObjectId } as LinksByReferenceInput, parent); + } catch { + // swallow any errors - this just means that the user cancelled editing + } + return; + }; + + plugins.visualizations.registerAlias({ + disableCreate: true, // do not allow creation through visualization listing page + name: CONTENT_ID, + title: APP_NAME, + icon: APP_ICON, + description: LinksStrings.getDescription(), + stage: 'experimental', + appExtensions: { + visualizations: { + docTypes: [CONTENT_ID], + searchFields: ['title^3'], + client: getLinksClient, + toListItem(linkItem: LinksCrudTypes['Item']) { + const { id, type, updatedAt, attributes } = linkItem; + const { title, description } = attributes; + + return { + id, + title, + editor: { onEdit: (savedObjectId: string) => getExplicitInput({ savedObjectId }) }, + description, + updatedAt, + icon: APP_ICON, + typeTitle: APP_NAME, + stage: 'experimental', + savedObjectType: type, + }; + }, + }, + }, + }); }); } diff --git a/src/plugins/links/public/services/kibana_services.ts b/src/plugins/links/public/services/kibana_services.ts index 76acd242f757..7536c1226279 100644 --- a/src/plugins/links/public/services/kibana_services.ts +++ b/src/plugins/links/public/services/kibana_services.ts @@ -8,12 +8,13 @@ import { BehaviorSubject } from 'rxjs'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { CoreStart } from '@kbn/core/public'; import { DashboardStart } from '@kbn/dashboard-plugin/public'; import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { CONTENT_ID } from '../../common'; import { LinksStartDependencies } from '../plugin'; export let coreServices: CoreStart; @@ -21,6 +22,11 @@ export let dashboardServices: DashboardStart; export let embeddableService: EmbeddableStart; export let presentationUtil: PresentationUtilPluginStart; export let contentManagement: ContentManagementPublicStart; +export let trackUiMetric: ( + type: string, + eventNames: string | string[], + count?: number +) => void | undefined; const servicesReady$ = new BehaviorSubject(false); @@ -42,6 +48,8 @@ export const setKibanaServices = (kibanaCore: CoreStart, deps: LinksStartDepende embeddableService = deps.embeddable; presentationUtil = deps.presentationUtil; contentManagement = deps.contentManagement; + if (deps.usageCollection) + trackUiMetric = deps.usageCollection.reportUiCounter.bind(deps.usageCollection, CONTENT_ID); servicesReady$.next(true); }; diff --git a/src/plugins/links/tsconfig.json b/src/plugins/links/tsconfig.json index e9814f4e107e..f839243325d0 100644 --- a/src/plugins/links/tsconfig.json +++ b/src/plugins/links/tsconfig.json @@ -26,7 +26,11 @@ "@kbn/logging", "@kbn/core-plugins-server", "@kbn/react-kibana-mount", - "@kbn/react-kibana-context-theme" + "@kbn/react-kibana-context-theme", + "@kbn/analytics", + "@kbn/usage-collection-plugin", + "@kbn/visualizations-plugin", + "@kbn/core-mount-utils-browser" ], "exclude": ["target/**/*"] } diff --git a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx index 1804a2fcf204..267131c33058 100644 --- a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx +++ b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx @@ -9,6 +9,7 @@ import React, { useState } from 'react'; import { EuiSelectable, EuiInputPopover, EuiSelectableProps } from '@elastic/eui'; import { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import { ToolbarButton, ToolbarButtonProps } from '@kbn/shared-ux-button-toolbar'; @@ -67,6 +68,7 @@ export function DataViewPicker({ isOpen={isPopoverOpen} input={createTrigger()} closePopover={() => setPopoverIsOpen(false)} + panelMinWidth={calculateWidthFromEntries(dataViews, ['name', 'id'])} panelProps={{ 'data-test-subj': 'data-view-picker-popover', }} @@ -98,6 +100,9 @@ export function DataViewPicker({ compressed: true, ...(selectableProps ? selectableProps.searchProps : undefined), }} + listProps={{ + truncationProps: { truncation: 'middle' }, + }} > {(list, search) => ( <> diff --git a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx index d5789284b413..ef14a6c88dcb 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx +++ b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx @@ -141,6 +141,7 @@ export const FieldPicker = ({ isVirtualized: true, showIcons: false, bordered: true, + truncationProps: { truncation: 'middle' }, }} height="full" > diff --git a/src/plugins/presentation_util/tsconfig.json b/src/plugins/presentation_util/tsconfig.json index e17fd6cc5a75..4076319587e1 100644 --- a/src/plugins/presentation_util/tsconfig.json +++ b/src/plugins/presentation_util/tsconfig.json @@ -31,7 +31,8 @@ "@kbn/ui-actions-plugin", "@kbn/saved-objects-finder-plugin", "@kbn/content-management-plugin", - "@kbn/shared-ux-button-toolbar" + "@kbn/shared-ux-button-toolbar", + "@kbn/calculate-width-from-char-count" ], "exclude": ["target/**/*"] } diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap index a04790ca6af2..538755e8d677 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/object_view/__snapshots__/saved_object_view.test.tsx.snap @@ -17,6 +17,7 @@ exports[`SavedObjectEdition should render normally 1`] = ` "isOverridden": [MockFunction], "remove": [MockFunction], "set": [MockFunction], + "validateValue": [MockFunction], }, "globalClient": Object { "get": [MockFunction], @@ -30,6 +31,7 @@ exports[`SavedObjectEdition should render normally 1`] = ` "isOverridden": [MockFunction], "remove": [MockFunction], "set": [MockFunction], + "validateValue": [MockFunction], }, }, "theme": Object { @@ -49,6 +51,7 @@ exports[`SavedObjectEdition should render normally 1`] = ` "isOverridden": [MockFunction], "remove": [MockFunction], "set": [MockFunction], + "validateValue": [MockFunction], }, } } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 1a2fdf031a9d..92bae41b22e5 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -188,6 +188,7 @@ exports[`SavedObjectsTable should render normally 1`] = ` } basePath={ BasePath { + "assetsHrefBase": "", "basePath": "", "get": [Function], "prepend": [Function], diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap index 7d4ed131f6ea..03ba5cf5d9ea 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap @@ -174,6 +174,7 @@ exports[`Flyout conflicts should allow conflict resolution 2`] = ` "register": [MockFunction], }, "basePath": BasePath { + "assetsHrefBase": "", "basePath": "", "get": [Function], "prepend": [Function], @@ -195,6 +196,9 @@ exports[`Flyout conflicts should allow conflict resolution 2`] = ` "patch": [MockFunction], "post": [MockFunction], "put": [MockFunction], + "staticAssets": Object { + "getPluginAssetHref": [MockFunction], + }, }, "state": Object { "conflictingRecord": undefined, @@ -401,6 +405,7 @@ exports[`Flyout summary should display summary when import is complete 1`] = ` allowedTypes={Array []} basePath={ BasePath { + "assetsHrefBase": "", "basePath": "", "get": [Function], "prepend": [Function], diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 0854944f3940..8c2a7b13d52c 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -9356,6 +9356,12 @@ "description": "Non-default value of setting." } }, + "securitySolution:excludeColdAndFrozenTiersInAnalyzer": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "securitySolution:enableCcsWarning": { "type": "boolean", "_meta": { @@ -10019,7 +10025,13 @@ "description": "Non-default value of setting." } }, - "observability:profilingPerCoreWatt": { + "observability:profilingPerVCPUWattX86": { + "type": "integer", + "_meta": { + "description": "Non-default value of setting." + } + }, + "observability:profilingPervCPUWattArm64": { "type": "integer", "_meta": { "description": "Non-default value of setting." @@ -10073,11 +10085,23 @@ "description": "Non-default value of setting." } }, - "observability:profilingUseLegacyFlamegraphAPI": { + "observability:profilingUseLegacyCo2Calculation": { "type": "boolean", "_meta": { "description": "Non-default value of setting." } + }, + "observability:profilingCostPervCPUPerHour": { + "type": "integer", + "_meta": { + "description": "Non-default value of setting." + } + }, + "observability:profilingAWSCostDiscountRate": { + "type": "integer", + "_meta": { + "description": "Non-default value of setting." + } } } }, diff --git a/src/plugins/telemetry/server/fetcher.test.ts b/src/plugins/telemetry/server/fetcher.test.ts index e1da374dc723..5a61de1a0d83 100644 --- a/src/plugins/telemetry/server/fetcher.test.ts +++ b/src/plugins/telemetry/server/fetcher.test.ts @@ -195,6 +195,61 @@ describe('FetcherTask', () => { }) ); + test( + 'Retries when `getCurrentConfigs` rejects', + fakeSchedulers(async (advance) => { + expect(fetcherTask['isOnline$'].value).toBe(false); + getCurrentConfigs.mockRejectedValueOnce(new Error('SomeError')).mockResolvedValue({ + telemetryOptIn: true, + telemetrySendUsageFrom: 'server', + failureCount: 0, + telemetryUrl: 'test-url', + }); + fetchMock.mockResolvedValue({}); + + const subscription = fetcherTask['validateConnectivity'](); + + // need to advance / await twice for retry + advance(5 * 60 * 1000); + await new Promise((resolve) => process.nextTick(resolve)); // Wait for the initial promise to fulfill + advance(1 * 60 * 1000); + await new Promise((resolve) => process.nextTick(resolve)); // Wait for the retry promise to fulfill + + expect(getCurrentConfigs).toHaveBeenCalledTimes(2); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(updateReportFailure).toHaveBeenCalledTimes(0); + expect(fetcherTask['isOnline$'].value).toBe(true); + + subscription.unsubscribe(); + }) + ); + + test( + 'logs a message when retries are exceeded', + fakeSchedulers(async (advance) => { + expect(fetcherTask['isOnline$'].value).toBe(false); + getCurrentConfigs.mockRejectedValue(new Error('SomeError')); + + const subscription = fetcherTask['validateConnectivity'](); + + const wait = async () => { + advance(5 * 60 * 1000); + await new Promise((resolve) => process.nextTick(resolve)); // Wait for the initial promise to fulfill + }; + + for (let i = 0; i < 7; i++) { + await wait(); + } + + expect(fetcherTask['logger'].error).toBeCalledTimes(1); + expect(fetcherTask['logger'].error).toHaveBeenCalledWith( + `Cannot get the current config: SomeError` + ); + + subscription.unsubscribe(); + }) + ); + test( 'Should not retry if it hit the max number of failures for this version', fakeSchedulers(async (advance) => { diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index a79e04355177..756c9f49ded6 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -18,6 +18,10 @@ import { Subscription, takeUntil, timer, + catchError, + defer, + EMPTY, + retry, } from 'rxjs'; import fetch from 'node-fetch'; import type { TelemetryCollectionManagerPluginStart } from '@kbn/telemetry-collection-manager-plugin/server'; @@ -105,7 +109,25 @@ export class FetcherTask { // Skip any further processing if already online filter(() => !this.isOnline$.value), // Fetch current state and configs - exhaustMap(async () => await this.getCurrentConfigs()), + exhaustMap(() => { + return defer(() => { + return this.getCurrentConfigs(); + }).pipe( + // exp-backoff retries in case of errors fetching the config + retry({ + count: 5, + delay: (error, retryIndex) => { + const retryDelay = 1000 * Math.min(Math.pow(2, retryIndex + 2), 64); // 5 retries -> 8s, 16s, 32s, 64s, 64s + return timer(retryDelay); + }, + }), + // shallow errors if all retry failed, next time tick will continue the emission + catchError((err) => { + this.logger.error(`Cannot get the current config: ${err.message}`); + return EMPTY; + }) + ); + }), // Skip if opted-out, or should only send from the browser filter( ({ telemetryOptIn, telemetrySendUsageFrom }) => diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap index 515add8c29dd..430cf538779b 100644 --- a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap @@ -281,6 +281,7 @@ exports[`TelemetryManagementSectionComponent renders null because allowChangingO "register": [MockFunction], }, "basePath": BasePath { + "assetsHrefBase": "", "basePath": "", "get": [Function], "prepend": [Function], @@ -302,6 +303,9 @@ exports[`TelemetryManagementSectionComponent renders null because allowChangingO "patch": [MockFunction], "post": [MockFunction], "put": [MockFunction], + "staticAssets": Object { + "getPluginAssetHref": [MockFunction], + }, }, "isScreenshotMode": false, "notifications": Object { diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index ede7098b7e91..d996b6b4e2cd 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -31,14 +31,11 @@ export { visualizeGeoFieldTrigger, ROW_CLICK_TRIGGER, rowClickTrigger, - CATEGORIZE_FIELD_TRIGGER, - categorizeFieldTrigger, } from '@kbn/ui-actions-browser/src/triggers'; -export type { VisualizeFieldContext, CategorizeFieldContext } from './types'; +export type { VisualizeFieldContext } from './types'; export { ACTION_VISUALIZE_FIELD, ACTION_VISUALIZE_GEO_FIELD, ACTION_VISUALIZE_LENS_FIELD, - ACTION_CATEGORIZE_FIELD, } from './types'; export type { ActionExecutionContext, ActionExecutionMeta, ActionMenuItemProps } from './actions'; diff --git a/src/plugins/ui_actions/public/plugin.ts b/src/plugins/ui_actions/public/plugin.ts index 52629aa3f572..16060d4bf343 100644 --- a/src/plugins/ui_actions/public/plugin.ts +++ b/src/plugins/ui_actions/public/plugin.ts @@ -9,7 +9,6 @@ import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { PublicMethodsOf } from '@kbn/utility-types'; import { - categorizeFieldTrigger, rowClickTrigger, visualizeFieldTrigger, visualizeGeoFieldTrigger, @@ -39,7 +38,6 @@ export class UiActionsPlugin implements Plugin { this.service.registerTrigger(rowClickTrigger); this.service.registerTrigger(visualizeFieldTrigger); this.service.registerTrigger(visualizeGeoFieldTrigger); - this.service.registerTrigger(categorizeFieldTrigger); return this.service; } diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 6d689f6776d9..c66ea2b1769b 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -7,7 +7,7 @@ */ import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import type { AggregateQuery } from '@kbn/es-query'; -import type { DataViewField, DataViewSpec, DataView } from '@kbn/data-views-plugin/public'; +import type { DataViewSpec } from '@kbn/data-views-plugin/public'; import { ActionInternal } from './actions/action_internal'; import { TriggerInternal } from './triggers/trigger_internal'; @@ -24,13 +24,6 @@ export interface VisualizeFieldContext { query?: AggregateQuery; } -export interface CategorizeFieldContext { - field: DataViewField; - dataView: DataView; - originatingApp: string; -} - export const ACTION_VISUALIZE_FIELD = 'ACTION_VISUALIZE_FIELD'; export const ACTION_VISUALIZE_GEO_FIELD = 'ACTION_VISUALIZE_GEO_FIELD'; export const ACTION_VISUALIZE_LENS_FIELD = 'ACTION_VISUALIZE_LENS_FIELD'; -export const ACTION_CATEGORIZE_FIELD = 'ACTION_CATEGORIZE_FIELD'; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer/doc_viewer.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer/doc_viewer.tsx index beb9a032d8c8..929ef2aa1b0c 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer/doc_viewer.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer/doc_viewer.tsx @@ -7,16 +7,11 @@ */ import React from 'react'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; import { DocViewer } from '@kbn/unified-doc-viewer'; import { getUnifiedDocViewerServices } from '../../plugin'; export function UnifiedDocViewer(props: DocViewRenderProps) { - const services = getUnifiedDocViewerServices(); - return ( - - - - ); + const { unifiedDocViewer } = getUnifiedDocViewerServices(); + return ; } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx index fc8f7498f6ef..6c6ae2852e05 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx @@ -12,13 +12,13 @@ import { getHeight } from './get_height'; describe('getHeight', () => { Object.defineProperty(window, 'innerHeight', { writable: true, configurable: true, value: 500 }); - const getMonacoMock = (lineCount: number) => { + const getMonacoMock = (lineCount: number, top: number = 200) => { return { getDomNode: jest.fn(() => { return { getBoundingClientRect: jest.fn(() => { return { - top: 200, + top, }; }), }; @@ -29,10 +29,17 @@ describe('getHeight', () => { } as unknown as monaco.editor.IStandaloneCodeEditor; }; test('when using document explorer, returning the available height in the flyout', () => { + const monacoMock = getMonacoMock(500, 0); + + const height = getHeight(monacoMock, true); + expect(height).toBe(475); + }); + + test('when using document explorer, returning the available height in the flyout has a minimun guarenteed height', () => { const monacoMock = getMonacoMock(500); const height = getHeight(monacoMock, true); - expect(height).toBe(275); + expect(height).toBe(400); }); test('when using classic table, its displayed inline without scrolling', () => { diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx index 0dcabc8ae951..dbab289018a6 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import { monaco } from '@kbn/monaco'; -import { MARGIN_BOTTOM, MAX_LINES_CLASSIC_TABLE } from './source'; +import { MARGIN_BOTTOM, MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExplorer: boolean) { const editorElement = editor?.getDomNode(); @@ -28,5 +28,5 @@ export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExp lineCount > MAX_LINES_CLASSIC_TABLE ? MAX_LINES_CLASSIC_TABLE : lineCount; result = editor.getTopForLineNumber(displayedLineCount + 1) + lineHeight; } - return result > 0 ? result : 0; + return Math.max(result, MIN_HEIGHT); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.test.tsx index 02f31a2e4f46..a9c8ae7d55b1 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.test.tsx @@ -7,25 +7,20 @@ */ import React from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { DocViewerSource } from './source'; import * as hooks from '../../hooks/use_es_doc_search'; import * as useUiSettingHook from '@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting'; import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; import { JsonCodeEditorCommon } from '../json_code_editor'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { buildDataTableRecord } from '@kbn/discover-utils'; -import { of } from 'rxjs'; +import { setUnifiedDocViewerServices } from '../../plugin'; +import type { UnifiedDocViewerServices } from '../../types'; const mockDataView = { getComputedFields: () => [], } as never; -const getMock = jest.fn(() => Promise.resolve(mockDataView)); -const mockDataViewService = { - get: getMock, -} as unknown as DataView; -const services = { +setUnifiedDocViewerServices({ uiSettings: { get: (key: string) => { if (key === 'discover:useNewFieldsApi') { @@ -33,29 +28,21 @@ const services = { } }, }, - data: { - dataViewService: mockDataViewService, - }, - theme: { - theme$: of({ darkMode: false }), - }, -}; +} as UnifiedDocViewerServices); describe('Source Viewer component', () => { test('renders loading state', () => { jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [0, null, () => {}]); const comp = mountWithIntl( - - {}} - /> - + {}} + /> ); const loadingIndicator = comp.find(EuiLoadingSpinner); expect(loadingIndicator).not.toBe(null); @@ -65,16 +52,14 @@ describe('Source Viewer component', () => { jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [3, null, () => {}]); const comp = mountWithIntl( - - {}} - /> - + {}} + /> ); const errorPrompt = comp.find(EuiEmptyPrompt); expect(errorPrompt.length).toBe(1); @@ -105,16 +90,14 @@ describe('Source Viewer component', () => { return false; }); const comp = mountWithIntl( - - {}} - /> - + {}} + /> ); const jsonCodeEditor = comp.find(JsonCodeEditorCommon); expect(jsonCodeEditor).not.toBe(null); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 26c771e405be..189cbd2b5be4 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -16,7 +16,8 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { ElasticRequestState } from '@kbn/unified-doc-viewer'; import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; -import { useEsDocSearch, useUnifiedDocViewerServices } from '../../hooks'; +import { getUnifiedDocViewerServices } from '../../plugin'; +import { useEsDocSearch } from '../../hooks'; import { getHeight } from './get_height'; import { JSONCodeEditorCommonMemoized } from '../json_code_editor'; @@ -36,6 +37,8 @@ interface SourceViewerProps { export const MAX_LINES_CLASSIC_TABLE = 500; // Displayed margin of the code editor to the window bottom when rendered in the document explorer flyout export const MARGIN_BOTTOM = 25; +// Minimum height for the source content to guarantee minimum space when the flyout is scrollable. +export const MIN_HEIGHT = 400; export const DocViewerSource = ({ id, @@ -49,7 +52,7 @@ export const DocViewerSource = ({ const [editor, setEditor] = useState(); const [editorHeight, setEditorHeight] = useState(); const [jsonValue, setJsonValue] = useState(''); - const { uiSettings } = useUnifiedDocViewerServices(); + const { uiSettings } = getUnifiedDocViewerServices(); const useNewFieldsApi = !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE); const useDocExplorer = !uiSettings.get(DOC_TABLE_LEGACY); const [requestState, hit] = useEsDocSearch({ diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx index 3a614ef71ad5..26ad6bad42ff 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx @@ -12,9 +12,9 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { DocViewerLegacyTable } from './table'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { buildDataTableRecord } from '@kbn/discover-utils'; -import type { UnifiedDocViewerServices } from '../../../hooks'; +import { setUnifiedDocViewerServices } from '../../../plugin'; +import type { UnifiedDocViewerServices } from '../../../types'; const services = { uiSettings: { @@ -77,11 +77,8 @@ const mountComponent = ( props: DocViewRenderProps, overrides?: Partial ) => { - return mountWithIntl( - - {' '} - - ); + setUnifiedDocViewerServices({ ...services, ...overrides } as UnifiedDocViewerServices); + return mountWithIntl(); }; describe('DocViewTable at Discover', () => { @@ -248,6 +245,7 @@ describe('DocViewTable at Discover Doc', () => { const props = { hit, dataView, + hideActionsColumn: true, }; const component = mountComponent(props); const foundLength = findTestSubject(component, 'addInclusiveFilterButton').length; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx index 531fafa408ec..310c8653bbee 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx @@ -18,24 +18,25 @@ import { isNestedFieldParent, } from '@kbn/discover-utils'; import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { useUnifiedDocViewerServices } from '../../../hooks'; +import { getUnifiedDocViewerServices } from '../../../plugin'; import { ACTIONS_COLUMN, MAIN_COLUMNS } from './table_columns'; export const DocViewerLegacyTable = ({ columns, hit, dataView, + hideActionsColumn, filter, onAddColumn, onRemoveColumn, }: DocViewRenderProps) => { - const { fieldFormats, uiSettings } = useUnifiedDocViewerServices(); + const { fieldFormats, uiSettings } = getUnifiedDocViewerServices(); const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS), [uiSettings]); const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]); const tableColumns = useMemo(() => { - return filter ? [ACTIONS_COLUMN, ...MAIN_COLUMNS] : MAIN_COLUMNS; - }, [filter]); + return !hideActionsColumn ? [ACTIONS_COLUMN, ...MAIN_COLUMNS] : MAIN_COLUMNS; + }, [hideActionsColumn]); const onToggleColumn = useCallback( (field: string) => { if (!onRemoveColumn || !onAddColumn || !columns) { diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx index 4499a4419074..2a202513340b 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx @@ -36,11 +36,11 @@ export const TableActions = ({ return (
    onFilter(fieldMapping, flattenedField, '+')} /> onFilter(fieldMapping, flattenedField, '-')} /> onToggleColumn(field)} /> onFilter('_exists_', field, '+')} scripted={fieldMapping && fieldMapping.scripted} /> diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx index 5a53f8a8eee5..5c6cbc6d8065 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx @@ -41,7 +41,7 @@ import { import { fieldNameWildcardMatcher, getFieldSearchMatchingHighlight } from '@kbn/field-utils'; import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; import { FieldName } from '@kbn/unified-doc-viewer'; -import { useUnifiedDocViewerServices } from '../../hooks'; +import { getUnifiedDocViewerServices } from '../../plugin'; import { TableFieldValue } from './table_cell_value'; import { TableActions } from './table_cell_actions'; @@ -109,16 +109,16 @@ export const DocViewerTable = ({ columnTypes, hit, dataView, + hideActionsColumn, filter, onAddColumn, onRemoveColumn, }: DocViewRenderProps) => { const showActionsInsideTableCell = useIsWithinBreakpoints(['xl'], true); - const { fieldFormats, storage, uiSettings } = useUnifiedDocViewerServices(); + const { fieldFormats, storage, uiSettings } = getUnifiedDocViewerServices(); const showMultiFields = uiSettings.get(SHOW_MULTIFIELDS); const currentDataViewId = dataView.id!; - const isSingleDocView = !filter; const [searchText, setSearchText] = useState(getSearchText(storage)); const [pinnedFields, setPinnedFields] = useState( @@ -283,7 +283,7 @@ export const DocViewerTable = ({ ); const headers = [ - !isSingleDocView && ( + !hideActionsColumn && ( { return ( - {!isSingleDocView && ( + {!hideActionsColumn && ( { + it('should render the panels correctly for undefined onFilter function', () => { + render( + + ); + expect(screen.getByTestId('addFilterForValueButton-message')).toBeDisabled(); + expect(screen.getByTestId('addFilterOutValueButton-message')).toBeDisabled(); + expect(screen.getByTestId('addExistsFilterButton-message')).toBeDisabled(); + expect(screen.getByTestId('toggleColumnButton-message')).not.toBeDisabled(); + expect(screen.getByTestId('togglePinFilterButton-message')).not.toBeDisabled(); + }); + + it('should render the panels correctly for defined onFilter function', () => { + render( + + ); + expect(screen.getByTestId('addFilterForValueButton-message')).not.toBeDisabled(); + expect(screen.getByTestId('addFilterOutValueButton-message')).not.toBeDisabled(); + expect(screen.getByTestId('addExistsFilterButton-message')).not.toBeDisabled(); + expect(screen.getByTestId('toggleColumnButton-message')).not.toBeDisabled(); + expect(screen.getByTestId('togglePinFilterButton-message')).not.toBeDisabled(); + }); +}); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx index 8b9a35e07131..0ebef67a7c76 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx @@ -25,7 +25,7 @@ interface TableActionsProps { pinned: boolean; flattenedField: unknown; fieldMapping?: DataViewField; - onFilter: DocViewFilterFn; + onFilter?: DocViewFilterFn; onToggleColumn: (field: string) => void; ignoredValue: boolean; onTogglePinned: (field: string) => void; @@ -51,7 +51,8 @@ export const TableActions = ({ }); // Filters pair - const filtersPairDisabled = !fieldMapping || !fieldMapping.filterable || ignoredValue; + const filtersPairDisabled = + !fieldMapping || !fieldMapping.filterable || ignoredValue || !onFilter; const filterAddLabel = i18n.translate( 'unifiedDocViewer.docViews.table.filterForValueButtonTooltip', { @@ -88,7 +89,7 @@ export const TableActions = ({ 'unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel', { defaultMessage: 'Filter for field present' } ); - const filtersExistsDisabled = !fieldMapping || !fieldMapping.filterable; + const filtersExistsDisabled = !fieldMapping || !fieldMapping.filterable || !onFilter; const filtersExistsToolTip = (filtersExistsDisabled && (fieldMapping && fieldMapping.scripted @@ -156,7 +157,9 @@ export const TableActions = ({ icon: 'plusInCircle', disabled: filtersPairDisabled, 'data-test-subj': `addFilterForValueButton-${field}`, - onClick: onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '+')), + onClick: onFilter + ? onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '+')) + : undefined, }, { name: filterOutLabel, @@ -164,7 +167,10 @@ export const TableActions = ({ toolTipContent: filtersPairToolTip, icon: 'minusInCircle', disabled: filtersPairDisabled, - onClick: onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '-')), + 'data-test-subj': `addFilterOutValueButton-${field}`, + onClick: onFilter + ? onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '-')) + : undefined, }, { name: filterExistsLabel, @@ -173,7 +179,7 @@ export const TableActions = ({ icon: 'filter', disabled: filtersExistsDisabled, 'data-test-subj': `addExistsFilterButton-${field}`, - onClick: onClickAction(onFilter.bind({}, '_exists_', field, '+')), + onClick: onFilter ? onClickAction(onFilter.bind({}, '_exists_', field, '+')) : undefined, }, { name: toggleColumnsLabel, @@ -186,6 +192,7 @@ export const TableActions = ({ name: pinnedLabel, 'aria-label': pinnedAriaLabel, icon: pinnedIconType, + 'data-test-subj': `togglePinFilterButton-${field}`, onClick: onClickAction(togglePinned), }, ], diff --git a/src/plugins/unified_doc_viewer/public/hooks/index.ts b/src/plugins/unified_doc_viewer/public/hooks/index.ts index 547032ce4415..382c8d4de305 100644 --- a/src/plugins/unified_doc_viewer/public/hooks/index.ts +++ b/src/plugins/unified_doc_viewer/public/hooks/index.ts @@ -6,5 +6,4 @@ * Side Public License, v 1. */ -export * from './use_doc_viewer_services'; export * from './use_es_doc_search'; diff --git a/src/plugins/unified_doc_viewer/public/hooks/use_doc_viewer_services.ts b/src/plugins/unified_doc_viewer/public/hooks/use_doc_viewer_services.ts deleted file mode 100644 index 4287e87ea6aa..000000000000 --- a/src/plugins/unified_doc_viewer/public/hooks/use_doc_viewer_services.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { Storage } from '@kbn/kibana-utils-plugin/public'; -import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { UnifiedDocViewerStart } from '../plugin'; - -export interface UnifiedDocViewerServices { - analytics: AnalyticsServiceStart; - data: DataPublicPluginStart; - fieldFormats: FieldFormatsStart; - storage: Storage; - uiSettings: IUiSettingsClient; - unifiedDocViewer: UnifiedDocViewerStart; -} - -export function useUnifiedDocViewerServices(): UnifiedDocViewerServices { - const { services } = useKibana(); - const { analytics, data, fieldFormats, storage, uiSettings, unifiedDocViewer } = services; - return { analytics, data, fieldFormats, storage, uiSettings, unifiedDocViewer }; -} diff --git a/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.test.tsx b/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.test.tsx index cee1cf509e13..b0beac94ab4f 100644 --- a/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.test.tsx +++ b/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.test.tsx @@ -15,12 +15,12 @@ import { SEARCH_FIELDS_FROM_SOURCE as mockSearchFieldsFromSource, buildDataTableRecord, } from '@kbn/discover-utils'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import React from 'react'; +import { setUnifiedDocViewerServices } from '../plugin'; +import { UnifiedDocViewerServices } from '../types'; const index = 'test-index'; const mockSearchResult = new Subject(); -const services = { +setUnifiedDocViewerServices({ data: { search: { search: jest.fn(() => { @@ -35,12 +35,12 @@ const services = { } }, }, -}; +} as unknown as UnifiedDocViewerServices); describe('Test of helper / hook', () => { test('buildSearchBody given useNewFieldsApi is false', () => { const dataView = { - getComputedFields: () => ({ storedFields: [], scriptFields: [], docvalueFields: [] }), + getComputedFields: () => ({ scriptFields: [], docvalueFields: [] }), } as unknown as DataView; const actual = buildSearchBody('1', index, dataView, false); expect(actual).toMatchInlineSnapshot(` @@ -67,7 +67,9 @@ describe('Test of helper / hook', () => { }, }, "script_fields": Array [], - "stored_fields": Array [], + "stored_fields": Array [ + "*", + ], "version": true, }, } @@ -76,7 +78,7 @@ describe('Test of helper / hook', () => { test('buildSearchBody useNewFieldsApi is true', () => { const dataView = { - getComputedFields: () => ({ storedFields: [], scriptFields: [], docvalueFields: [] }), + getComputedFields: () => ({ scriptFields: [], docvalueFields: [] }), } as unknown as DataView; const actual = buildSearchBody('1', index, dataView, true); expect(actual).toMatchInlineSnapshot(` @@ -108,7 +110,9 @@ describe('Test of helper / hook', () => { }, "runtime_mappings": Object {}, "script_fields": Array [], - "stored_fields": Array [], + "stored_fields": Array [ + "*", + ], "version": true, }, } @@ -117,7 +121,7 @@ describe('Test of helper / hook', () => { test('buildSearchBody with requestSource', () => { const dataView = { - getComputedFields: () => ({ storedFields: [], scriptFields: [], docvalueFields: [] }), + getComputedFields: () => ({ scriptFields: [], docvalueFields: [] }), } as unknown as DataView; const actual = buildSearchBody('1', index, dataView, true, true); expect(actual).toMatchInlineSnapshot(` @@ -150,7 +154,9 @@ describe('Test of helper / hook', () => { }, "runtime_mappings": Object {}, "script_fields": Array [], - "stored_fields": Array [], + "stored_fields": Array [ + "*", + ], "version": true, }, } @@ -160,7 +166,6 @@ describe('Test of helper / hook', () => { test('buildSearchBody with runtime fields', () => { const dataView = { getComputedFields: () => ({ - storedFields: [], scriptFields: [], docvalueFields: [], runtimeFields: { @@ -210,7 +215,9 @@ describe('Test of helper / hook', () => { }, }, "script_fields": Array [], - "stored_fields": Array [], + "stored_fields": Array [ + "*", + ], "version": true, }, } @@ -230,9 +237,6 @@ describe('Test of helper / hook', () => { const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), { initialProps: props, - wrapper: ({ children }) => ( - {children} - ), }); expect(hook.result.current.slice(0, 2)).toEqual([ElasticRequestState.Loading, null]); @@ -254,9 +258,6 @@ describe('Test of helper / hook', () => { const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), { initialProps: props, - wrapper: ({ children }) => ( - {children} - ), }); await act(async () => { @@ -308,9 +309,6 @@ describe('Test of helper / hook', () => { const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), { initialProps: props, - wrapper: ({ children }) => ( - {children} - ), }); expect(hook.result.current.slice(0, 2)).toEqual([ diff --git a/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts b/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts index d215306d6f7e..ef236e4a9118 100644 --- a/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts +++ b/src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts @@ -14,7 +14,7 @@ import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { SEARCH_FIELDS_FROM_SOURCE, buildDataTableRecord } from '@kbn/discover-utils'; import { ElasticRequestState } from '@kbn/unified-doc-viewer'; -import { useUnifiedDocViewerServices } from './use_doc_viewer_services'; +import { getUnifiedDocViewerServices } from '../plugin'; type RequestBody = Pick; @@ -53,7 +53,7 @@ export function useEsDocSearch({ }: EsDocSearchProps): [ElasticRequestState, DataTableRecord | null, () => void] { const [status, setStatus] = useState(ElasticRequestState.Loading); const [hit, setHit] = useState(null); - const { data, uiSettings, analytics } = useUnifiedDocViewerServices(); + const { data, uiSettings, analytics } = getUnifiedDocViewerServices(); const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]); const requestData = useCallback(async () => { @@ -131,7 +131,7 @@ export function buildSearchBody( filter: [{ ids: { values: [id] } }, { term: { _index: index } }], }, }, - stored_fields: computedFields.storedFields, + stored_fields: ['*'], script_fields: computedFields.scriptFields, version: true, }, diff --git a/src/plugins/unified_doc_viewer/public/index.tsx b/src/plugins/unified_doc_viewer/public/index.tsx index d08de9dcaa0e..ffe5c3f16d78 100644 --- a/src/plugins/unified_doc_viewer/public/index.tsx +++ b/src/plugins/unified_doc_viewer/public/index.tsx @@ -34,6 +34,6 @@ export const UnifiedDocViewer = withSuspense( ); -export { useEsDocSearch, useUnifiedDocViewerServices } from './hooks'; +export { useEsDocSearch } from './hooks'; export const plugin = () => new UnifiedDocViewerPublicPlugin(); diff --git a/src/plugins/unified_doc_viewer/public/plugin.tsx b/src/plugins/unified_doc_viewer/public/plugin.tsx index 018e6ffadd31..a79ae9e44d0c 100644 --- a/src/plugins/unified_doc_viewer/public/plugin.tsx +++ b/src/plugins/unified_doc_viewer/public/plugin.tsx @@ -16,7 +16,7 @@ import { createGetterSetter, Storage } from '@kbn/kibana-utils-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { CoreStart } from '@kbn/core/public'; -import { type UnifiedDocViewerServices, useUnifiedDocViewerServices } from './hooks'; +import type { UnifiedDocViewerServices } from './types'; export const [getUnifiedDocViewerServices, setUnifiedDocViewerServices] = createGetterSetter('UnifiedDocViewerServices'); @@ -50,8 +50,7 @@ export class UnifiedDocViewerPublicPlugin }), order: 10, component: (props) => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { uiSettings } = useUnifiedDocViewerServices(); + const { uiSettings } = getUnifiedDocViewerServices(); const DocView = uiSettings.get(DOC_TABLE_LEGACY) ? DocViewerLegacyTable : DocViewerTable; return ( diff --git a/src/plugins/unified_doc_viewer/public/types.ts b/src/plugins/unified_doc_viewer/public/types.ts index d9ec40eedfff..5a89a6037bec 100644 --- a/src/plugins/unified_doc_viewer/public/types.ts +++ b/src/plugins/unified_doc_viewer/public/types.ts @@ -7,5 +7,21 @@ */ export type { JsonCodeEditorProps } from './components'; -export type { EsDocSearchProps, UnifiedDocViewerServices } from './hooks'; +export type { EsDocSearchProps } from './hooks'; export type { UnifiedDocViewerSetup, UnifiedDocViewerStart } from './plugin'; + +import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { Storage } from '@kbn/kibana-utils-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import type { UnifiedDocViewerStart } from './plugin'; + +export interface UnifiedDocViewerServices { + analytics: AnalyticsServiceStart; + data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; + storage: Storage; + uiSettings: IUiSettingsClient; + unifiedDocViewer: UnifiedDocViewerStart; +} diff --git a/src/plugins/unified_histogram/public/__mocks__/data_view.ts b/src/plugins/unified_histogram/public/__mocks__/data_view.ts index 34043e8348c4..ffc429c1aa88 100644 --- a/src/plugins/unified_histogram/public/__mocks__/data_view.ts +++ b/src/plugins/unified_histogram/public/__mocks__/data_view.ts @@ -91,7 +91,7 @@ export const buildDataViewMock = ({ metaFields: ['_index', '_score'], fields: dataViewFields, getName: () => name, - getComputedFields: () => ({ docvalueFields: [], scriptFields: {}, storedFields: ['*'] }), + getComputedFields: () => ({ docvalueFields: [], scriptFields: {} }), getSourceFiltering: () => ({}), getFieldByName: jest.fn((fieldName: string) => dataViewFields.getByName(fieldName)), timeFieldName: timeFieldName || '', diff --git a/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx b/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx index e3e4059ad3cf..77e00e157d62 100644 --- a/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx +++ b/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx @@ -9,6 +9,7 @@ import { EuiComboBox, EuiComboBoxOptionOption, EuiToolTip, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import { i18n } from '@kbn/i18n'; import React, { useCallback, useState } from 'react'; import { UnifiedHistogramBreakdownContext } from '../types'; @@ -59,11 +60,10 @@ export const BreakdownFieldSelector = ({ const breakdownCss = css` width: 100%; max-width: ${euiTheme.base * 22}px; - &:focus-within { - max-width: ${euiTheme.base * 30}px; - } `; + const panelMinWidth = calculateWidthFromEntries(fieldOptions, ['label']); + return ( ; isOnHistogramMode?: boolean; + histogramQuery?: AggregateQuery; isChartLoading?: boolean; onResetChartHeight?: () => void; onChartHiddenChange?: (chartHidden: boolean) => void; @@ -115,6 +116,7 @@ export function Chart({ lensAdapters, lensEmbeddableOutput$, isOnHistogramMode, + histogramQuery, isChartLoading, onResetChartHeight, onChartHiddenChange, @@ -216,7 +218,7 @@ export function Chart({ getLensAttributes({ title: chart?.title, filters, - query, + query: histogramQuery ?? query, dataView, timeInterval: chart?.timeInterval, breakdownField: breakdown?.field, @@ -230,6 +232,7 @@ export function Chart({ dataView, filters, query, + histogramQuery, ] ); diff --git a/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx b/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx index 486ea7da7987..5ed329f251a9 100644 --- a/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx +++ b/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx @@ -68,6 +68,7 @@ export function ChartConfigPanel({ updatePanelState={updateSuggestion} lensAdapters={lensAdapters} output$={lensEmbeddableOutput$} + displayFlyoutHeader closeFlyout={() => { setIsFlyoutVisible(false); }} diff --git a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.test.ts b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.test.ts index d891c62df351..119356af6f63 100644 --- a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.test.ts +++ b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.test.ts @@ -38,6 +38,7 @@ describe('useLensSuggestions', () => { allSuggestions: [], currentSuggestion: undefined, isOnHistogramMode: false, + histogramQuery: undefined, suggestionUnsupported: false, }); }); @@ -66,6 +67,7 @@ describe('useLensSuggestions', () => { allSuggestions: allSuggestionsMock, currentSuggestion: allSuggestionsMock[0], isOnHistogramMode: false, + histogramQuery: undefined, suggestionUnsupported: false, }); }); @@ -94,6 +96,7 @@ describe('useLensSuggestions', () => { allSuggestions: [], currentSuggestion: undefined, isOnHistogramMode: false, + histogramQuery: undefined, suggestionUnsupported: true, }); }); @@ -133,10 +136,52 @@ describe('useLensSuggestions', () => { allSuggestions: [], currentSuggestion: allSuggestionsMock[0], isOnHistogramMode: true, + histogramQuery: { + esql: 'from the-data-view | limit 100 | EVAL timestamp=DATE_TRUNC(30 minute, @timestamp) | stats rows = count(*) by timestamp | rename timestamp as `@timestamp every 30 minute`', + }, suggestionUnsupported: false, }); }); + test('should return histogramSuggestion even if the ESQL query contains a DROP @timestamp statement', async () => { + const firstMockReturn = undefined; + const secondMockReturn = allSuggestionsMock; + const lensSuggestionsApi = jest + .fn() + .mockReturnValueOnce(firstMockReturn) // will return to firstMockReturn object firstly + .mockReturnValueOnce(secondMockReturn); // will return to secondMockReturn object secondly + + renderHook(() => { + return useLensSuggestions({ + dataView: dataViewMock, + query: { esql: 'from the-data-view | DROP @timestamp | limit 100' }, + isPlainRecord: true, + columns: [ + { + id: 'var0', + name: 'var0', + meta: { + type: 'number', + }, + }, + ], + data: dataMock, + lensSuggestionsApi, + timeRange: { + from: '2023-09-03T08:00:00.000Z', + to: '2023-09-04T08:56:28.274Z', + }, + }); + }); + expect(lensSuggestionsApi).toHaveBeenLastCalledWith( + expect.objectContaining({ + query: { esql: expect.stringMatching('from the-data-view | limit 100 ') }, + }), + expect.anything(), + ['lnsDatatable'] + ); + }); + test('should not return histogramSuggestion if no suggestions returned by the api and transformational commands', async () => { const firstMockReturn = undefined; const secondMockReturn = allSuggestionsMock; @@ -172,6 +217,7 @@ describe('useLensSuggestions', () => { allSuggestions: [], currentSuggestion: undefined, isOnHistogramMode: false, + histogramQuery: undefined, suggestionUnsupported: true, }); }); diff --git a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts index 514c32cefcb8..063e1b7ef89a 100644 --- a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts +++ b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts @@ -11,6 +11,7 @@ import { AggregateQuery, isOfAggregateQueryType, getAggregateQueryMode, + cleanupESQLQueryForLensSuggestions, Query, TimeRange, } from '@kbn/es-query'; @@ -61,7 +62,7 @@ export const useLensSuggestions = ({ const [allSuggestions, setAllSuggestions] = useState(suggestions.allSuggestions); const currentSuggestion = originalSuggestion ?? suggestions.firstSuggestion; const suggestionDeps = useRef(getSuggestionDeps({ dataView, query, columns })); - + const histogramQuery = useRef(); const histogramSuggestion = useMemo(() => { if ( !currentSuggestion && @@ -85,8 +86,8 @@ export const useLensSuggestions = ({ const interval = computeInterval(timeRange, data); const language = getAggregateQueryMode(query); - const histogramQuery = `${query[language]} - | EVAL timestamp=DATE_TRUNC(${interval}, ${dataView.timeFieldName}) | stats rows = count(*) by timestamp | rename timestamp as \`${dataView.timeFieldName} every ${interval}\``; + const safeQuery = cleanupESQLQueryForLensSuggestions(query[language]); + const esqlQuery = `${safeQuery} | EVAL timestamp=DATE_TRUNC(${interval}, ${dataView.timeFieldName}) | stats rows = count(*) by timestamp | rename timestamp as \`${dataView.timeFieldName} every ${interval}\``; const context = { dataViewSpec: dataView?.toSpec(), fieldName: '', @@ -107,15 +108,16 @@ export const useLensSuggestions = ({ }, ] as DatatableColumn[], query: { - esql: histogramQuery, + esql: esqlQuery, }, }; const sug = lensSuggestionsApi(context, dataView, ['lnsDatatable']) ?? []; if (sug.length) { + histogramQuery.current = { esql: esqlQuery }; return sug[0]; } - return undefined; } + histogramQuery.current = undefined; return undefined; }, [currentSuggestion, dataView, query, timeRange, data, lensSuggestionsApi]); @@ -142,6 +144,7 @@ export const useLensSuggestions = ({ currentSuggestion: histogramSuggestion ?? currentSuggestion, suggestionUnsupported: !currentSuggestion && !histogramSuggestion && isPlainRecord, isOnHistogramMode: Boolean(histogramSuggestion), + histogramQuery: histogramQuery.current ? histogramQuery.current : undefined, }; }; diff --git a/src/plugins/unified_histogram/public/layout/layout.tsx b/src/plugins/unified_histogram/public/layout/layout.tsx index d923ea3031a5..17eaf65fcde5 100644 --- a/src/plugins/unified_histogram/public/layout/layout.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.tsx @@ -215,18 +215,23 @@ export const UnifiedHistogramLayout = ({ children, withDefaultActions, }: UnifiedHistogramLayoutProps) => { - const { allSuggestions, currentSuggestion, suggestionUnsupported, isOnHistogramMode } = - useLensSuggestions({ - dataView, - query, - originalSuggestion, - isPlainRecord, - columns, - timeRange, - data: services.data, - lensSuggestionsApi, - onSuggestionChange, - }); + const { + allSuggestions, + currentSuggestion, + suggestionUnsupported, + isOnHistogramMode, + histogramQuery, + } = useLensSuggestions({ + dataView, + query, + originalSuggestion, + isPlainRecord, + columns, + timeRange, + data: services.data, + lensSuggestionsApi, + onSuggestionChange, + }); const chart = suggestionUnsupported ? undefined : originalChart; const [topPanelNode] = useState(() => @@ -302,6 +307,7 @@ export const UnifiedHistogramLayout = ({ lensAdapters={lensAdapters} lensEmbeddableOutput$={lensEmbeddableOutput$} isOnHistogramMode={isOnHistogramMode} + histogramQuery={histogramQuery} withDefaultActions={withDefaultActions} /> diff --git a/src/plugins/unified_histogram/tsconfig.json b/src/plugins/unified_histogram/tsconfig.json index b8337379679c..e381b7ee3cf0 100644 --- a/src/plugins/unified_histogram/tsconfig.json +++ b/src/plugins/unified_histogram/tsconfig.json @@ -26,6 +26,7 @@ "@kbn/visualizations-plugin", "@kbn/discover-utils", "@kbn/resizable-layout", + "@kbn/calculate-width-from-char-count", ], "exclude": [ "target/**/*", diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.styles.ts b/src/plugins/unified_search/public/dataview_picker/change_dataview.styles.ts index 1c505752d392..a2332648da3e 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.styles.ts +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.styles.ts @@ -6,15 +6,24 @@ * Side Public License, v 1. */ -export const DATA_VIEW_POPOVER_CONTENT_WIDTH = 280; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; +import { DataViewListItemEnhanced } from './dataview_list'; -export const changeDataViewStyles = ({ fullWidth }: { fullWidth?: boolean }) => { +const MIN_WIDTH = 300; + +export const changeDataViewStyles = ({ + fullWidth, + dataViewsList, +}: { + fullWidth?: boolean; + dataViewsList: DataViewListItemEnhanced[]; +}) => { return { trigger: { - maxWidth: fullWidth ? undefined : DATA_VIEW_POPOVER_CONTENT_WIDTH, + maxWidth: fullWidth ? undefined : MIN_WIDTH, }, popoverContent: { - width: DATA_VIEW_POPOVER_CONTENT_WIDTH, + width: calculateWidthFromEntries(dataViewsList, ['name', 'id'], { minWidth: MIN_WIDTH }), }, }; }; diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx index e1565f1ff6b0..9076bcb37c7d 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx @@ -96,7 +96,9 @@ export function ChangeDataView({ const { application, data, storage, dataViews, dataViewEditor, appName, usageCollection } = kibana.services; const reportUiCounter = usageCollection?.reportUiCounter.bind(usageCollection, appName); - const styles = changeDataViewStyles({ fullWidth: trigger.fullWidth }); + + const styles = changeDataViewStyles({ fullWidth: trigger.fullWidth, dataViewsList }); + const [isTextLangTransitionModalDismissed, setIsTextLangTransitionModalDismissed] = useState(() => Boolean(storage.get(TEXT_LANG_TRANSITION_MODAL_KEY)) ); @@ -215,7 +217,7 @@ export function ChangeDataView({ })} ) : ( - + ), ); @@ -336,13 +338,23 @@ export function ChangeDataView({ if (textBasedLanguages?.length) { panelItems.push( , - + onTextBasedSubmit({ esql: `from ${trigger.title} | limit 10` })} data-test-subj="select-text-based-language-panel" + contentProps={{ + css: { + justifyContent: 'flex-start', + paddingLeft: '26px', + }, + }} > {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTryLabel', { defaultMessage: 'Try ES|QL', diff --git a/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx b/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx index ec231d577e11..a42a91510abe 100644 --- a/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx +++ b/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx @@ -23,6 +23,7 @@ import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { SortingService } from './sorting_service'; +import { MIDDLE_TRUNCATION_PROPS } from '../filter_bar/filter_editor/lib/helpers'; const strings = { sortOrder: { @@ -120,6 +121,10 @@ export function DataViewsList({ checked?: 'on' | 'off' | undefined; }> {...selectableProps} + listProps={{ + truncationProps: MIDDLE_TRUNCATION_PROPS, + ...(selectableProps?.listProps ? selectableProps.listProps : undefined), + }} data-test-subj="indexPattern-switcher" searchable singleSelection="always" diff --git a/src/plugins/unified_search/public/dataview_picker/mocks/dataview.ts b/src/plugins/unified_search/public/dataview_picker/mocks/dataview.ts index 699ad5fcd4d9..7b8c1318fae8 100644 --- a/src/plugins/unified_search/public/dataview_picker/mocks/dataview.ts +++ b/src/plugins/unified_search/public/dataview_picker/mocks/dataview.ts @@ -100,7 +100,7 @@ export const buildDataViewMock = ({ fields: dataViewFields, type: 'default', getName: () => name, - getComputedFields: () => ({ docvalueFields: [], scriptFields: {}, storedFields: ['*'] }), + getComputedFields: () => ({ docvalueFields: [], scriptFields: {} }), getSourceFiltering: () => ({}), getIndexPattern: () => `${name}-title`, getFieldByName: jest.fn((fieldName: string) => dataViewFields.getByName(fieldName)), diff --git a/src/plugins/unified_search/public/filter_bar/filter_bar.tsx b/src/plugins/unified_search/public/filter_bar/filter_bar.tsx index 769d6bfcaf48..a9c53d9f8912 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_bar.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_bar.tsx @@ -55,6 +55,8 @@ const FilterBarUI = React.memo(function FilterBarUI(props: Props) { gutterSize="none" // We use `gap` in the styles instead for better truncation of badges alignItems="center" tabIndex={-1} + data-test-subj="filter-items-group" + className={`filter-items-group ${props.className ?? ''}`} > {props.prepend} { onChange={this.onLocalFilterChange} disabled={!selectedDataView} suggestionsAbstraction={this.props.suggestionsAbstraction} + filtersCount={this.props.filtersCount} />
    diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_suggestor.tsx index f25ce0cb28ca..3f542be18d9f 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_suggestor.tsx @@ -71,6 +71,7 @@ export class PhraseSuggestorUI extends React.Com } protected onSearchChange = (value: string | number | boolean) => { + this.setState({ isLoading: true }); this.updateSuggestions(`${value}`); }; diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_value_input.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_value_input.tsx index 62648ae50d26..9328ecfa66c5 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_value_input.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/phrase_value_input.tsx @@ -10,6 +10,7 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n-react'; import { uniq } from 'lodash'; import React from 'react'; import { withKibana } from '@kbn/kibana-react-plugin/public'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; import { ValueInputType } from './value_input_type'; @@ -26,7 +27,6 @@ interface PhraseValueInputProps extends PhraseSuggestorProps { } class PhraseValueInputUI extends PhraseSuggestorUI { - comboBoxWrapperRef = React.createRef(); inputRef: HTMLInputElement | null = null; public render() { @@ -54,46 +54,44 @@ class PhraseValueInputUI extends PhraseSuggestorUI { } private renderWithSuggestions() { - const { suggestions } = this.state; + const { suggestions, isLoading } = this.state; const { value, intl, onChange, fullWidth } = this.props; // there are cases when the value is a number, this would cause an exception const valueAsStr = String(value); const options = value ? uniq([valueAsStr, ...suggestions]) : suggestions; + const panelMinWidth = calculateWidthFromEntries(options); return ( -
    - { - this.inputRef = ref; - }} - isDisabled={this.props.disabled} - fullWidth={fullWidth} - compressed={this.props.compressed} - placeholder={intl.formatMessage({ - id: 'unifiedSearch.filter.filterEditor.valueSelectPlaceholder', - defaultMessage: 'Select a value', - })} - aria-label={intl.formatMessage({ - id: 'unifiedSearch.filter.filterEditor.valueSelectPlaceholder', - defaultMessage: 'Select a value', - })} - options={options} - getLabel={(option) => option} - selectedOptions={value ? [valueAsStr] : []} - onChange={([newValue = '']) => { - onChange(newValue); - setTimeout(() => { - // Note: requires a tick skip to correctly blur element focus - this.inputRef?.blur(); - }); - }} - onSearchChange={this.onSearchChange} - onCreateOption={onChange} - isClearable={false} - data-test-subj="filterParamsComboBox phraseParamsComboxBox" - singleSelection={SINGLE_SELECTION_AS_TEXT_PROPS} - truncationProps={MIDDLE_TRUNCATION_PROPS} - /> -
    + { + this.inputRef = ref; + }} + isDisabled={this.props.disabled} + fullWidth={fullWidth} + compressed={this.props.compressed} + placeholder={intl.formatMessage({ + id: 'unifiedSearch.filter.filterEditor.valueSelectPlaceholder', + defaultMessage: 'Select a value', + })} + aria-label={intl.formatMessage({ + id: 'unifiedSearch.filter.filterEditor.valueSelectPlaceholder', + defaultMessage: 'Select a value', + })} + options={options} + getLabel={(option) => option} + selectedOptions={value ? [valueAsStr] : []} + onChange={([newValue = '']) => { + onChange(newValue); + }} + onSearchChange={this.onSearchChange} + onCreateOption={onChange} + isClearable={false} + data-test-subj="filterParamsComboBox phraseParamsComboxBox" + singleSelection={SINGLE_SELECTION_AS_TEXT_PROPS} + truncationProps={MIDDLE_TRUNCATION_PROPS} + inputPopoverProps={{ panelMinWidth, anchorPosition: 'downRight' }} + /> ); } } diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/phrases_values_input.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/phrases_values_input.tsx index 513dad144582..30fd03fb3d9c 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/phrases_values_input.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/phrases_values_input.tsx @@ -11,6 +11,7 @@ import { uniq } from 'lodash'; import React from 'react'; import { withKibana } from '@kbn/kibana-react-plugin/public'; import { withEuiTheme, WithEuiThemeProps } from '@elastic/eui'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; import { phrasesValuesComboboxCss } from './phrases_values_input.styles'; @@ -28,43 +29,42 @@ interface Props { export type PhrasesValuesInputProps = Props & PhraseSuggestorProps & WithEuiThemeProps; class PhrasesValuesInputUI extends PhraseSuggestorUI { - comboBoxWrapperRef = React.createRef(); - public render() { - const { suggestions } = this.state; + const { suggestions, isLoading } = this.state; const { values, intl, onChange, fullWidth, onParamsUpdate, compressed, disabled } = this.props; const options = values ? uniq([...values, ...suggestions]) : suggestions; - + const panelMinWidth = calculateWidthFromEntries(options); return ( -
    - option} - selectedOptions={values || []} - onSearchChange={this.onSearchChange} - onCreateOption={(option: string) => { - onParamsUpdate(option.trim()); - }} - className={phrasesValuesComboboxCss(this.props.theme)} - onChange={onChange} - isClearable={false} - data-test-subj="filterParamsComboBox phrasesParamsComboxBox" - isDisabled={disabled} - truncationProps={MIDDLE_TRUNCATION_PROPS} - /> -
    + option} + selectedOptions={values || []} + onSearchChange={this.onSearchChange} + onCreateOption={(option: string) => { + onParamsUpdate(option.trim()); + }} + className={phrasesValuesComboboxCss(this.props.theme)} + onChange={onChange} + isClearable={false} + data-test-subj="filterParamsComboBox phrasesParamsComboxBox" + isDisabled={disabled} + truncationProps={MIDDLE_TRUNCATION_PROPS} + inputPopoverProps={{ panelMinWidth, anchorPosition: 'downRight' }} + /> ); } } diff --git a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx index d14891c5fc3f..d29529f59a3c 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx @@ -61,6 +61,7 @@ export interface FilterItemProps extends WithCloseFilterEditorConfirmModalProps filtersForSuggestions?: Filter[]; readOnly?: boolean; suggestionsAbstraction?: SuggestionsAbstraction; + filtersCount?: number; } type FilterPopoverProps = HTMLAttributes & EuiPopoverProps; @@ -398,6 +399,7 @@ function FilterItemComponent(props: FilterItemProps) { filtersForSuggestions={props.filtersForSuggestions} suggestionsAbstraction={props.suggestionsAbstraction} docLinks={docLinks} + filtersCount={props.filtersCount} />
    , ]} diff --git a/src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx b/src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx index 841f4915e78b..f0e558f75ba7 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx @@ -83,6 +83,7 @@ const FilterItemsUI = React.memo(function FilterItemsUI(props: FilterItemsProps) filtersForSuggestions={props.filtersForSuggestions} readOnly={readOnly} suggestionsAbstraction={props.suggestionsAbstraction} + filtersCount={props.filters.length} /> )); diff --git a/src/plugins/unified_search/public/filters_builder/filter_group.tsx b/src/plugins/unified_search/public/filters_builder/filter_group.tsx index 73813e512a22..98daa1146e5c 100644 --- a/src/plugins/unified_search/public/filters_builder/filter_group.tsx +++ b/src/plugins/unified_search/public/filters_builder/filter_group.tsx @@ -44,6 +44,7 @@ export interface FilterGroupProps { /** @internal used for recursive rendering **/ renderedLevel?: number; reverseBackground?: boolean; + filtersCount?: number; } /** @internal **/ @@ -75,6 +76,7 @@ export const FilterGroup = ({ path, reverseBackground = false, renderedLevel = 0, + filtersCount, }: FilterGroupProps) => { const { globalParams: { maxDepth, hideOr }, @@ -128,6 +130,7 @@ export const FilterGroup = ({ color={color} index={index} renderedLevel={renderedLevel} + filtersCount={filtersCount} /> diff --git a/src/plugins/unified_search/public/filters_builder/filter_item/field_input.tsx b/src/plugins/unified_search/public/filters_builder/filter_item/field_input.tsx index 540226caef52..cc87c3de7893 100644 --- a/src/plugins/unified_search/public/filters_builder/filter_item/field_input.tsx +++ b/src/plugins/unified_search/public/filters_builder/filter_item/field_input.tsx @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import { FieldIcon } from '@kbn/react-field'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import { useGeneratedHtmlId, EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; import { getFilterableFields } from '../../filter_bar/filter_editor'; import { FiltersBuilderContextType } from '../context'; @@ -36,7 +37,6 @@ export function FieldInput({ field, dataView, onHandleField }: FieldInputProps) const { disabled, suggestionsAbstraction } = useContext(FiltersBuilderContextType); const fields = dataView ? getFilterableFields(dataView) : []; const id = useGeneratedHtmlId({ prefix: 'fieldInput' }); - const comboBoxWrapperRef = useRef(null); const inputRef = useRef(null); const onFieldChange = useCallback( @@ -72,40 +72,30 @@ export function FieldInput({ field, dataView, onHandleField }: FieldInputProps) ({ label }) => fields[optionFields.findIndex((optionField) => optionField.label === label)] ); onFieldChange(newValues); - - setTimeout(() => { - // Note: requires a tick skip to correctly blur element focus - inputRef?.current?.blur(); - }); }; - const handleFocus: React.FocusEventHandler = () => { - // Force focus on input due to https://github.com/elastic/eui/issues/7170 - inputRef?.current?.focus(); - }; + const panelMinWidth = calculateWidthFromEntries(euiOptions, ['label']); return ( -
    - { - inputRef.current = ref; - }} - options={euiOptions} - selectedOptions={selectedEuiOptions} - onChange={onComboBoxChange} - isDisabled={disabled} - placeholder={strings.getFieldSelectPlaceholderLabel()} - sortMatchesBy="startsWith" - aria-label={strings.getFieldSelectPlaceholderLabel()} - isClearable={false} - compressed - fullWidth - onFocus={handleFocus} - data-test-subj="filterFieldSuggestionList" - singleSelection={SINGLE_SELECTION_AS_TEXT_PROPS} - truncationProps={MIDDLE_TRUNCATION_PROPS} - /> -
    + { + inputRef.current = ref; + }} + options={euiOptions} + selectedOptions={selectedEuiOptions} + onChange={onComboBoxChange} + isDisabled={disabled} + placeholder={strings.getFieldSelectPlaceholderLabel()} + sortMatchesBy="startsWith" + aria-label={strings.getFieldSelectPlaceholderLabel()} + isClearable={false} + compressed + fullWidth + data-test-subj="filterFieldSuggestionList" + singleSelection={SINGLE_SELECTION_AS_TEXT_PROPS} + truncationProps={MIDDLE_TRUNCATION_PROPS} + inputPopoverProps={{ panelMinWidth }} + /> ); } diff --git a/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.styles.ts b/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.styles.ts index 6ec0ac9ab705..78c4952aa69b 100644 --- a/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.styles.ts +++ b/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.styles.ts @@ -26,9 +26,6 @@ export const fieldAndParamCss = (euiTheme: EuiThemeComputed) => css` .euiFormRow { max-width: 800px; } - &:focus-within { - flex-grow: 4; - } `; export const operationCss = (euiTheme: EuiThemeComputed) => css` diff --git a/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.tsx b/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.tsx index 7bc1f875fcd5..97ea1f364b9d 100644 --- a/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.tsx +++ b/src/plugins/unified_search/public/filters_builder/filter_item/filter_item.tsx @@ -24,6 +24,7 @@ import { buildEmptyFilter, getFilterParams, BooleanRelation } from '@kbn/es-quer import { DataViewField } from '@kbn/data-views-plugin/common'; import { cx } from '@emotion/css'; +import { css } from '@emotion/react'; import { FieldInput } from './field_input'; import { OperatorInput } from './operator_input'; import { ParamsEditor } from './params_editor'; @@ -71,6 +72,7 @@ export interface FilterItemProps { /** @internal used for recursive rendering **/ renderedLevel: number; reverseBackground: boolean; + filtersCount?: number; } const isMaxFilterNesting = (path: string) => { @@ -89,6 +91,7 @@ export function FilterItem({ index, renderedLevel, draggable = true, + filtersCount = 1, }: FilterItemProps) { const { dispatch, @@ -253,6 +256,15 @@ export function FilterItem({ className={cx({ [cursorOrCss]: dropTarget === path && !hideOr, })} + css={ + // With a single filter there's a disabled cursor set at dragging level + // so we need to revert such css directive for the rest of the editor row + filtersCount === 1 + ? css` + cursor: auto; + ` + : undefined + } > -
    +
    - +
    diff --git a/src/plugins/unified_search/public/index_pattern_select/index_pattern_select.tsx b/src/plugins/unified_search/public/index_pattern_select/index_pattern_select.tsx index f7148db93ce1..d8517eedba4e 100644 --- a/src/plugins/unified_search/public/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/unified_search/public/index_pattern_select/index_pattern_select.tsx @@ -11,7 +11,9 @@ import React, { Component } from 'react'; import { Required } from '@kbn/utility-types'; import { EuiComboBox, EuiComboBoxProps } from '@elastic/eui'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import type { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { MIDDLE_TRUNCATION_PROPS } from '../filter_bar/filter_editor/lib/helpers'; export type IndexPatternSelectProps = Required< Omit, 'onSearchChange' | 'options' | 'selectedOptions' | 'onChange'>, @@ -28,7 +30,7 @@ export type IndexPatternSelectInternalProps = IndexPatternSelectProps & { interface IndexPatternSelectState { isLoading: boolean; - options: []; + options: Array<{ value: string; label: string }>; selectedIndexPattern: { value: string; label: string } | undefined; searchValue: string | undefined; } @@ -147,6 +149,8 @@ export default class IndexPatternSelect extends Component ); } diff --git a/src/plugins/unified_search/tsconfig.json b/src/plugins/unified_search/tsconfig.json index f83de4ff80fc..0412bbc4c8c9 100644 --- a/src/plugins/unified_search/tsconfig.json +++ b/src/plugins/unified_search/tsconfig.json @@ -42,6 +42,7 @@ "@kbn/core-doc-links-browser", "@kbn/core-lifecycle-browser", "@kbn/ml-string-hash", + "@kbn/calculate-width-from-char-count" ], "exclude": [ "target/**/*", diff --git a/src/plugins/usage_collection/common/types/stats/core_metrics.ts b/src/plugins/usage_collection/common/types/stats/core_metrics.ts index 64e5ef34155d..5bc2023afc04 100644 --- a/src/plugins/usage_collection/common/types/stats/core_metrics.ts +++ b/src/plugins/usage_collection/common/types/stats/core_metrics.ts @@ -89,6 +89,10 @@ export interface OpsProcessMetrics { }; /** node rss */ resident_set_size_in_bytes: number; + /** memory usage of C++ objects bound to JavaScript objects managed by V8 */ + external_in_bytes: number; + /** memory allocated for array buffers. This is also included in the external value*/ + array_buffers_in_bytes: number; }; /** mean event loop delay since last collection*/ event_loop_delay: number; @@ -159,6 +163,14 @@ export interface OpsOsMetrics { time_throttled_nanos: number; }; }; + + /** memory cgroup metrics, undefined when not running in cgroup v2 */ + cgroup_memory?: { + /** The total amount of memory currently being used by the cgroup and its descendants. */ + current_in_bytes: number; + /** The total amount of swap currently being used by the cgroup and its descendants. */ + swap_current_in_bytes: number; + }; } /** diff --git a/src/plugins/usage_collection/server/collector/collector_set.test.ts b/src/plugins/usage_collection/server/collector/collector_set.test.ts index 56b4e55eccfc..43e063b95333 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.test.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.test.ts @@ -237,6 +237,16 @@ describe('CollectorSet', () => { }, uptime_in_millis: 137844000, }, + process: { + heap: { + total_in_bytes: 1, + used_in_bytes: 2, + size_limit: 3, + }, + resident_set_size_in_bytes: 4, + array_buffers_in_bytes: 5, + external_in_bytes: 6, + }, daysOfTheWeek: ['monday', 'tuesday', 'wednesday'], }; @@ -247,6 +257,16 @@ describe('CollectorSet', () => { memory: { free_bytes: 458280960, total_bytes: 17179869184, used_bytes: 16721588224 }, uptime_ms: 137844000, }, + process: { + heap: { + total_bytes: 1, + used_bytes: 2, + size_limit: 3, + }, + resident_set_size_bytes: 4, + array_buffers_bytes: 5, + external_bytes: 6, + }, days_of_the_week: ['monday', 'tuesday', 'wednesday'], }); }); diff --git a/src/plugins/visualizations/public/utils/saved_visualize_utils.test.ts b/src/plugins/visualizations/public/utils/saved_visualize_utils.test.ts index 01475fe483c8..54de776faa62 100644 --- a/src/plugins/visualizations/public/utils/saved_visualize_utils.test.ts +++ b/src/plugins/visualizations/public/utils/saved_visualize_utils.test.ts @@ -504,11 +504,13 @@ describe('saved_visualize_utils', () => { { id: 'wat', image: undefined, + editor: { + editUrl: '/edit/wat', + }, readOnly: false, references: undefined, icon: undefined, savedObjectType: 'visualization', - editUrl: '/edit/wat', type: 'test', typeName: 'test', typeTitle: undefined, diff --git a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts index 9232504e026d..85932c09729c 100644 --- a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts +++ b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts @@ -73,7 +73,7 @@ export function mapHitSource( references: SavedObjectReference[]; url: string; savedObjectType?: string; - editUrl?: string; + editor?: { editUrl?: string }; updatedAt?: string; type?: BaseVisType; icon?: BaseVisType['icon']; @@ -108,7 +108,7 @@ export function mapHitSource( newAttributes.icon = newAttributes.type?.icon; newAttributes.image = newAttributes.type?.image; newAttributes.typeTitle = newAttributes.type?.title; - newAttributes.editUrl = `/edit/${id}`; + newAttributes.editor = { editUrl: `/edit/${id}` }; newAttributes.readOnly = Boolean(visTypes.get(typeName as string)?.disableEdit); return newAttributes; @@ -168,7 +168,6 @@ export async function findListItems( return acc; }, acc); }, {} as { [visType: string]: VisualizationsAppExtension }); - const searchOption = (field: string, ...defaults: string[]) => _(extensions).map(field).concat(defaults).compact().flatten().uniq().value() as string[]; diff --git a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts index 2a46b28f06dd..617f0386f618 100644 --- a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts +++ b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts @@ -19,8 +19,6 @@ import { BaseVisType } from './base_vis_type'; export type VisualizationStage = 'experimental' | 'beta' | 'production'; export interface VisualizationListItem { - editUrl: string; - editApp?: string; error?: string; icon: string; id: string; @@ -32,6 +30,9 @@ export interface VisualizationListItem { typeTitle: string; image?: string; type?: BaseVisType | string; + editor: + | { editUrl: string; editApp?: string } + | { onEdit: (savedObjectId: string) => Promise }; } export interface SerializableAttributes { @@ -86,8 +87,14 @@ export interface VisualizationsAppExtension { } export interface VisTypeAlias { - aliasPath: string; - aliasApp: string; + /** + * Provide `alias` when your visualization has a dedicated app for creation. + * TODO: Provide a generic callback to create visualizations inline. + */ + alias?: { + app: string; + path: string; + }; name: string; title: string; icon: string; diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.scss b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.scss index 7fe4fe05ab26..48df3fc67388 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.scss +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.scss @@ -11,7 +11,7 @@ .visListingTable__experimentalIcon { width: $euiSizeL; - vertical-align: baseline; + vertical-align: middle; padding: 0 $euiSizeS; margin-left: $euiSizeS; } diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx index d4beb45c4e24..d1de28ac7379 100644 --- a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx +++ b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx @@ -36,6 +36,7 @@ import { TableListViewProps, } from '@kbn/content-management-table-list-view'; import { TableListViewTable } from '@kbn/content-management-table-list-view-table'; + import { findListItems } from '../../utils/saved_visualize_utils'; import { updateBasicSoAttributes } from '../../utils/saved_objects_utils/update_basic_attributes'; import { checkForDuplicateTitle } from '../../utils/saved_objects_utils/check_for_duplicate_title'; @@ -49,17 +50,17 @@ import { getNoItemsMessage, getCustomColumn } from '../utils'; import { getVisualizeListItemLink } from '../utils/get_visualize_list_item_link'; import type { VisualizationStage } from '../../vis_types/vis_type_alias_registry'; -interface VisualizeUserContent extends VisualizationListItem, UserContentCommonSchema { - type: string; - attributes: { - title: string; - description?: string; - editApp: string; - editUrl: string; - readOnly: boolean; - error?: string; +type VisualizeUserContent = VisualizationListItem & + UserContentCommonSchema & { + type: string; + attributes: { + id: string; + title: string; + description?: string; + readOnly: boolean; + error?: string; + }; }; -} const toTableListViewSavedObject = (savedObject: Record): VisualizeUserContent => { return { @@ -67,19 +68,17 @@ const toTableListViewSavedObject = (savedObject: Record): Visua updatedAt: savedObject.updatedAt as string, references: savedObject.references as Array<{ id: string; type: string; name: string }>, type: savedObject.savedObjectType as string, - editUrl: savedObject.editUrl as string, - editApp: savedObject.editApp as string, icon: savedObject.icon as string, stage: savedObject.stage as VisualizationStage, savedObjectType: savedObject.savedObjectType as string, typeTitle: savedObject.typeTitle as string, title: (savedObject.title as string) ?? '', error: (savedObject.error as string) ?? '', + editor: savedObject.editor as any, attributes: { + id: savedObject.id as string, title: (savedObject.title as string) ?? '', description: savedObject.description as string, - editApp: savedObject.editApp as string, - editUrl: savedObject.editUrl as string, readOnly: savedObject.readOnly as boolean, error: savedObject.error as string, }, @@ -120,7 +119,13 @@ const useTableListViewProps = ( }, [closeNewVisModal]); const editItem = useCallback( - ({ attributes: { editUrl, editApp } }: VisualizeUserContent) => { + async ({ attributes: { id }, editor }: VisualizeUserContent) => { + if (!('editApp' in editor || 'editUrl' in editor)) { + await editor.onEdit(id); + return; + } + + const { editApp, editUrl } = editor; if (editApp) { application.navigateToApp(editApp, { path: editUrl }); return; @@ -383,10 +388,19 @@ export const VisualizeListing = () => { entityNamePlural={i18n.translate('visualizations.listing.table.entityNamePlural', { defaultMessage: 'visualizations', })} - getDetailViewLink={({ attributes: { editApp, editUrl, error, readOnly } }) => - readOnly + onClickTitle={(item) => { + tableViewProps.editItem?.(item); + }} + getDetailViewLink={({ editor, attributes: { error, readOnly } }) => + readOnly || (editor && 'onEdit' in editor) ? undefined - : getVisualizeListItemLink(application, kbnUrlStateStorage, editApp, editUrl, error) + : getVisualizeListItemLink( + application, + kbnUrlStateStorage, + editor.editApp, + editor.editUrl, + error + ) } tableCaption={visualizeLibraryTitle} {...tableViewProps} diff --git a/src/plugins/visualizations/public/visualize_app/utils/get_visualize_list_item_link.ts b/src/plugins/visualizations/public/visualize_app/utils/get_visualize_list_item_link.ts index 524ccbad44f8..5c1a5b1ee3eb 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/get_visualize_list_item_link.ts +++ b/src/plugins/visualizations/public/visualize_app/utils/get_visualize_list_item_link.ts @@ -17,10 +17,10 @@ export const getVisualizeListItemLink = ( application: ApplicationStart, kbnUrlStateStorage: IKbnUrlStateStorage, editApp: string | undefined, - editUrl: string, + editUrl: string | undefined, error: string | undefined = undefined ) => { - if (error) { + if (error || (!editApp && !editUrl)) { return undefined; } diff --git a/src/plugins/visualizations/public/wizard/group_selection/group_selection.test.tsx b/src/plugins/visualizations/public/wizard/group_selection/group_selection.test.tsx index e1e9cec25e15..a9a21446e06a 100644 --- a/src/plugins/visualizations/public/wizard/group_selection/group_selection.test.tsx +++ b/src/plugins/visualizations/public/wizard/group_selection/group_selection.test.tsx @@ -37,8 +37,10 @@ describe('GroupSelection', () => { { name: 'visWithAliasUrl', title: 'Vis with alias Url', - aliasApp: 'aliasApp', - aliasPath: '#/aliasApp', + alias: { + app: 'aliasApp', + path: '#/aliasApp', + }, description: 'Vis with alias Url', stage: 'production', group: VisGroups.PROMOTED, @@ -49,8 +51,10 @@ describe('GroupSelection', () => { description: 'Vis alias with promotion', stage: 'production', group: VisGroups.PROMOTED, - aliasApp: 'anotherApp', - aliasPath: '#/anotherUrl', + alias: { + app: 'anotherApp', + path: '#/anotherUrl', + }, promotion: true, } as unknown, ] as BaseVisType[]; diff --git a/src/plugins/visualizations/public/wizard/group_selection/group_selection.tsx b/src/plugins/visualizations/public/wizard/group_selection/group_selection.tsx index dc8aaa03161b..3bcdff18c47a 100644 --- a/src/plugins/visualizations/public/wizard/group_selection/group_selection.tsx +++ b/src/plugins/visualizations/public/wizard/group_selection/group_selection.tsx @@ -200,7 +200,7 @@ const VisGroup = ({ visType, onVisTypeSelected }: VisCardProps) => { } onClick={onClick} data-test-subj={`visType-${visType.name}`} - data-vis-stage={!('aliasPath' in visType) ? visType.stage : 'alias'} + data-vis-stage={!('alias' in visType) ? visType.stage : 'alias'} aria-label={`visType-${visType.name}`} description={ <> diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx index 907c989c7bb4..0db5f66cc5c9 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx @@ -47,8 +47,10 @@ describe('NewVisModal', () => { title: 'Vis with alias Url', stage: 'production', group: VisGroups.PROMOTED, - aliasApp: 'otherApp', - aliasPath: '#/aliasUrl', + alias: { + app: 'otherApp', + path: '#/aliasUrl', + }, }, { name: 'visWithSearch', @@ -181,7 +183,7 @@ describe('NewVisModal', () => { ); }); - it('closes and redirects properly if visualization with aliasPath and originatingApp in props', () => { + it('closes and redirects properly if visualization with alias.path and originatingApp in props', () => { const onClose = jest.fn(); const navigateToApp = jest.fn(); const stateTransfer = embeddablePluginMock.createStartContract().getStateTransfer(); diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx index ac1f89e73700..b1e5de321526 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx @@ -119,7 +119,7 @@ class NewVisModal extends React.Component { - if (!('aliasPath' in visType) && visType.requiresSearch && visType.options.showIndexSelection) { + if ('visConfig' in visType && visType.requiresSearch && visType.options.showIndexSelection) { this.setState({ showSearchVisModal: true, visType, @@ -143,10 +143,12 @@ class NewVisModal extends React.Component { let originalTitles: string[] = []; + const checkDashboardTitle = async (expectedTitle: string) => { + expect(await browser.getTitle()).to.equal(`${expectedTitle} - Elastic`); + await retry.try(async () => { + const breadcrumb = await globalNav.getLastBreadcrumb(); + expect(breadcrumb).to.equal(`Editing ${expectedTitle}`); + }); + }; + before(async () => { await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load( @@ -60,13 +69,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should update the title of the dashboard', async () => { + await checkDashboardTitle('few panels'); + const newTitle = 'My awesome dashboard!!1'; await PageObjects.dashboard.openSettingsFlyout(); await dashboardSettings.setCustomPanelTitle(newTitle); await dashboardSettings.clickApplyButton(); - await retry.try(async () => { - expect((await globalNav.getLastBreadcrumb()) === newTitle); - }); + + await checkDashboardTitle(newTitle); }); it('should disable quick save when the settings are open', async () => { @@ -106,9 +116,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardSettings.expectDuplicateTitleWarningDisplayed(); }); await dashboardSettings.clickApplyButton(); - await retry.try(async () => { - expect((await globalNav.getLastBreadcrumb()) === newTitle); - }); + + await checkDashboardTitle(newTitle); }); }); } diff --git a/test/functional/apps/dashboard_elements/links/links_create_edit.ts b/test/functional/apps/dashboard_elements/links/links_create_edit.ts index 4a6e94c656ba..e0abfffbad18 100644 --- a/test/functional/apps/dashboard_elements/links/links_create_edit.ts +++ b/test/functional/apps/dashboard_elements/links/links_create_edit.ts @@ -78,18 +78,33 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.clickDiscardChanges(); }); - it('can create a new by-value links panel', async () => { - await dashboardAddPanel.clickEditorMenuButton(); - await dashboardAddPanel.clickAddNewEmbeddableLink('links'); - await dashboardLinks.setLayout('horizontal'); - await createSomeLinks(); - await dashboardLinks.toggleSaveByReference(false); - await dashboardLinks.clickPanelEditorSaveButton(); - await testSubjects.exists('addObjectToDashboardSuccess'); - - expect(await testSubjects.existOrFail('links--component')); - expect(await dashboardLinks.getNumberOfLinksInPanel()).to.equal(4); - await dashboard.clickDiscardChanges(); + describe('by-value links panel', async () => { + it('can create a new by-value links panel', async () => { + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAddNewEmbeddableLink('links'); + await dashboardLinks.setLayout('horizontal'); + await createSomeLinks(); + await dashboardLinks.toggleSaveByReference(false); + await dashboardLinks.clickPanelEditorSaveButton(); + await testSubjects.exists('addObjectToDashboardSuccess'); + + expect(await testSubjects.existOrFail('links--component')); + expect(await dashboardLinks.getNumberOfLinksInPanel()).to.equal(4); + }); + + it('can save by-value links panel to the library', async () => { + /** Navigate away to test non-extensible input */ + await dashboard.gotoDashboardLandingPage(); + await dashboard.clickUnsavedChangesContinueEditing(DASHBOARD_NAME); + + await dashboard.waitForRenderComplete(); + await dashboardPanelActions.saveToLibrary('Some more links'); + await testSubjects.existOrFail('addPanelToLibrarySuccess'); + }); + + after(async () => { + await dashboard.clickDiscardChanges(); + }); }); }); diff --git a/test/functional/apps/discover/ccs_compatibility/_search_errors.ts b/test/functional/apps/discover/ccs_compatibility/_search_errors.ts new file mode 100644 index 000000000000..da2d2b556734 --- /dev/null +++ b/test/functional/apps/discover/ccs_compatibility/_search_errors.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const config = getService('config'); + const filterBar = getService('filterBar'); + const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); + + const isCcsTest = config.get('esTestCluster.ccs'); + const archiveDirectory = isCcsTest + ? 'test/functional/fixtures/kbn_archiver/ccs/discover.json' + : 'test/functional/fixtures/kbn_archiver/discover.json'; + const esNode = isCcsTest + ? getService('remoteEsArchiver' as 'esArchiver') + : getService('esArchiver'); + + const defaultIndex = isCcsTest ? 'ftr-remote:logstash-*' : 'logstash-*'; + + describe('discover search errors', () => { + before(async () => { + await kibanaServer.importExport.load(archiveDirectory); + await esNode.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + after(async () => { + await kibanaServer.importExport.unload(archiveDirectory); + await esNode.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + it('exception on single shard shows warning and results', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern(defaultIndex); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await retry.try(async () => { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('14,004'); + }); + await filterBar.addDslFilter(` + { + "query": { + "error_query": { + "indices": [ + { + "name": "${defaultIndex.slice(0, defaultIndex.length - 1)}2015.09.20", + "error_type": "exception", + "message": "'Watch out!'" + } + ] + } + } + }`); + + // Ensure documents are still returned for the successful shards + await retry.try(async function tryingForTime() { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('9,247'); + }); + + // Ensure a warning is shown + await testSubjects.exists('searchResponseWarningsCallout'); + }); + + it('exception on all shards shows error', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern(defaultIndex); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await retry.try(async () => { + const hitCount = await PageObjects.discover.getHitCount(); + expect(hitCount).to.be('14,004'); + }); + await filterBar.addDslFilter(` + { + "query": { + "error_query": { + "indices": [ + { + "name": "${defaultIndex}", + "error_type": "exception", + "message": "'Watch out!'" + } + ] + } + } + }`); + + // Ensure an error is shown + await testSubjects.exists('searchResponseWarningsEmptyPrompt'); + }); + }); +} diff --git a/test/functional/apps/discover/ccs_compatibility/index.ts b/test/functional/apps/discover/ccs_compatibility/index.ts index 1204ce9daadb..4f932c399383 100644 --- a/test/functional/apps/discover/ccs_compatibility/index.ts +++ b/test/functional/apps/discover/ccs_compatibility/index.ts @@ -22,5 +22,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_data_view_editor')); loadTestFile(require.resolve('./_saved_queries')); + loadTestFile(require.resolve('./_search_errors')); }); } diff --git a/test/functional/apps/discover/group1/_url_state.ts b/test/functional/apps/discover/group1/_url_state.ts index 49957519cdc5..027e767e8fe3 100644 --- a/test/functional/apps/discover/group1/_url_state.ts +++ b/test/functional/apps/discover/group1/_url_state.ts @@ -107,7 +107,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { "to:'2015-09-23T18:31:44.000Z'))&_a=(columns:!(),filters:!(),index:'logstash-*'," + "interval:auto,query:(language:kuery,query:''),sort:!(!('@timestamp',desc)))" ); - await appsMenu.clickLink('Discover'); + await appsMenu.clickLink('Discover', { category: 'kibana' }); await PageObjects.header.waitUntilLoadingHasFinished(); expect(await filterBar.hasFilter('extension.raw', '', undefined, true)).to.be(true); expect(await filterBar.isFilterPinned('extension.raw')).to.be(true); diff --git a/test/functional/apps/home/_navigation.ts b/test/functional/apps/home/_navigation.ts index 016cead53f0c..1d0aeeea6a0d 100644 --- a/test/functional/apps/home/_navigation.ts +++ b/test/functional/apps/home/_navigation.ts @@ -36,13 +36,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const homeUrl = await browser.getCurrentUrl(); // Navigate to discover app - await appsMenu.clickLink('Discover'); + await appsMenu.clickLink('Discover', { category: 'kibana' }); const discoverUrl = await browser.getCurrentUrl(); await PageObjects.timePicker.setDefaultAbsoluteRange(); const modifiedTimeDiscoverUrl = await browser.getCurrentUrl(); // Navigate to dashboard app - await appsMenu.clickLink('Dashboard'); + await appsMenu.clickLink('Dashboard', { category: 'kibana' }); // Navigating back to discover await browser.goBack(); diff --git a/test/functional/fixtures/es_archiver/many_fields/mappings.json b/test/functional/fixtures/es_archiver/many_fields/mappings.json index 491085676c16..8fb5e73b4d04 100644 --- a/test/functional/fixtures/es_archiver/many_fields/mappings.json +++ b/test/functional/fixtures/es_archiver/many_fields/mappings.json @@ -38103,6 +38103,7 @@ "limit" : "50000" } }, + "auto_expand_replicas": "0-1", "number_of_shards" : "1", "number_of_replicas" : "0" } diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index e41d1583341d..d17c12d8269d 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -27,6 +27,7 @@ interface SaveDashboardOptions { } export class DashboardPageObject extends FtrService { + private readonly comboBox = this.ctx.getService('comboBox'); private readonly config = this.ctx.getService('config'); private readonly log = this.ctx.getService('log'); private readonly find = this.ctx.getService('find'); @@ -555,9 +556,9 @@ export class DashboardPageObject extends FtrService { } public async selectDashboardTags(tagNames: string[]) { - await this.testSubjects.click('savedObjectTagSelector'); + const tagsComboBox = await this.testSubjects.find('savedObjectTagSelector'); for (const tagName of tagNames) { - await this.testSubjects.click(`tagSelectorOption-${tagName.replace(' ', '_')}`); + await this.comboBox.setElement(tagsComboBox, tagName); } await this.testSubjects.click('savedObjectTitle'); } diff --git a/test/functional/services/apps_menu.ts b/test/functional/services/apps_menu.ts index 0f6316647788..0dddddd35e77 100644 --- a/test/functional/services/apps_menu.ts +++ b/test/functional/services/apps_menu.ts @@ -116,23 +116,55 @@ export class AppsMenuService extends FtrService { category, }: { closeCollapsibleNav?: boolean; category?: string } = {} ) { - try { + await this.waitUntilLoadingHasFinished(); + + await this.ctx.getService('retry').try(async () => { this.log.debug(`click "${name}" app link`); - await this.openCollapsibleNav(); - let nav; - if (typeof category === 'string') { - nav = await this.testSubjects.find(`collapsibleNavGroup-${category}`); - } else { - nav = await this.testSubjects.find('collapsibleNav'); - } - const link = await nav.findByPartialLinkText(name); - await link.click(); - if (closeCollapsibleNav) { - await this.closeCollapsibleNav(); + try { + await this.openCollapsibleNav(); + let nav; + if (typeof category === 'string') { + // we can search within a specific section of the side nav + nav = await this.testSubjects.find(`collapsibleNavGroup-${category}`); + const link = await nav.findByPartialLinkText(name); + await link.click(); + } else { + // we need to search our app link in the whole side nav + // first, we get all the links, along with their inner text + const allLinks = await this.testSubjects.findAll('collapsibleNavAppLink'); + const allLinksTexts = await Promise.all( + allLinks.map((link) => link.getVisibleText().then((text) => ({ link, text }))) + ); + + // then, filter out those that don't have a matching text + const matchingLinks = allLinksTexts.filter(({ text }) => text.includes(name)); + if (matchingLinks.length === 0) { + this.log.debug( + `Found ${allLinks.length} links on the side nav: ${allLinksTexts.map( + ({ text }) => text + )}` + ); + throw new Error( + `Could not find the '${name}' application on the side nav (${allLinks.length} links found)` + ); + } else if (matchingLinks.length > 1) { + throw new Error( + `Multiple apps exist in the side nav with the specified name: '${name}'. Consider using the "category" parameter to disambiguate` + ); + } + + this.log.debug(`Found "${name}" app link on the side nav!`); + // if we click on a stale element (e.g. re-rendered) it'll throw an Error and we will retry + await matchingLinks.pop()!.link.click(); + } + + if (closeCollapsibleNav) { + await this.closeCollapsibleNav(); + } + } finally { + // Intentionally empty } - } finally { - // Intentionally empty - } + }); } } diff --git a/test/functional/services/filter_bar.ts b/test/functional/services/filter_bar.ts index 22fa4ff0b5e5..eb9aae45621e 100644 --- a/test/functional/services/filter_bar.ts +++ b/test/functional/services/filter_bar.ts @@ -65,6 +65,7 @@ type Filter = FilterLeaf | FilterNode; export class FilterBarService extends FtrService { private readonly comboBox = this.ctx.getService('comboBox'); + private readonly monacoEditor = this.ctx.getService('monacoEditor'); private readonly testSubjects = this.ctx.getService('testSubjects'); private readonly common = this.ctx.getPageObject('common'); private readonly header = this.ctx.getPageObject('header'); @@ -315,6 +316,19 @@ export class FilterBarService extends FtrService { await this.addFilterAndSelectDataView(null, filter); } + public async addDslFilter(value: string) { + await this.testSubjects.click('addFilter'); + await this.testSubjects.click('editQueryDSL'); + await this.monacoEditor.waitCodeEditorReady('addFilterPopover'); + await this.monacoEditor.setCodeEditorValue(value); + await this.testSubjects.scrollIntoView('saveFilter'); + await this.testSubjects.clickWhenNotDisabled('saveFilter'); + await this.retry.try(async () => { + await this.testSubjects.waitForDeleted('saveFilter'); + }); + await this.header.waitUntilLoadingHasFinished(); + } + /** * Activates filter editing * @param key field name diff --git a/test/functional/services/flyout.ts b/test/functional/services/flyout.ts index 71c4f13556eb..de1592a74c95 100644 --- a/test/functional/services/flyout.ts +++ b/test/functional/services/flyout.ts @@ -36,12 +36,23 @@ export class FlyoutService extends FtrService { if (!flyoutElements.length) { return true; } + let expectedFlyoutCount = 0; for (let i = 0; i < flyoutElements.length; i++) { - const closeBtn = await flyoutElements[i].findByCssSelector('[aria-label*="Close"]'); - await closeBtn.click(); + const closeBtnExists = await this.find.descendantExistsByCssSelector( + '[aria-label*="Close"]', + flyoutElements[i] + ); + if (closeBtnExists) { + const closeBtn = await flyoutElements[i].findByCssSelector('[aria-label*="Close"]'); + await closeBtn.click(); + } else { + // If it doesn't have a close button, it can't + // be closed, so ignore it in the count check + expectedFlyoutCount++; + } } flyoutElements = await this.find.allByCssSelector('.euiFlyout', 500); - return flyoutElements.length === 0; + return flyoutElements.length === expectedFlyoutCount; }); } } diff --git a/test/plugin_functional/plugins/core_plugin_route_timeouts/server/plugin.ts b/test/plugin_functional/plugins/core_plugin_route_timeouts/server/plugin.ts index fce258c1b8b0..5ecdc0a03dd0 100644 --- a/test/plugin_functional/plugins/core_plugin_route_timeouts/server/plugin.ts +++ b/test/plugin_functional/plugins/core_plugin_route_timeouts/server/plugin.ts @@ -53,7 +53,7 @@ export class CorePluginRouteTimeoutsPlugin implements Plugin { body: { accepts: ['application/json'], }, - timeout: { idleSocket: 10 }, + timeout: { idleSocket: 5 }, }, path: '/short_idle_socket_timeout', validate: { diff --git a/test/plugin_functional/test_suites/core/route.ts b/test/plugin_functional/test_suites/core/route.ts index 13bd4190d32f..597189dd5faf 100644 --- a/test/plugin_functional/test_suites/core/route.ts +++ b/test/plugin_functional/test_suites/core/route.ts @@ -7,14 +7,13 @@ */ import expect from '@kbn/expect'; -import { Test } from 'supertest'; -import { PluginFunctionalProviderContext } from '../../services'; +import type { Test } from 'supertest'; +import type { PluginFunctionalProviderContext } from '../../services'; export default function ({ getService }: PluginFunctionalProviderContext) { const supertest = getService('supertest'); - // FLAKY: https://github.com/elastic/kibana/issues/75440 - describe.skip('route', function () { + describe('route', function () { describe('timeouts', function () { const writeBodyCharAtATime = (request: Test, body: string, interval: number) => { return new Promise((resolve, reject) => { @@ -45,7 +44,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { .set('Transfer-Encoding', 'chunked') .set('kbn-xsrf', 'true'); - const result = writeBodyCharAtATime(request, '{"foo":"bar"}', 10); + const result = writeBodyCharAtATime(request, '{"foo":"bar"}', 20); await result.then( (res) => { @@ -65,7 +64,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { .set('Transfer-Encoding', 'chunked') .set('kbn-xsrf', 'true'); - const result = writeBodyCharAtATime(request, '{"foo":"bar"}', 10); + const result = writeBodyCharAtATime(request, '{"foo":"bar"}', 20); await result.then( (res) => { @@ -107,7 +106,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { .set('Transfer-Encoding', 'chunked') .set('kbn-xsrf', 'true'); - const result = writeBodyCharAtATime(request, '{"responseDelay":0}', 10); + const result = writeBodyCharAtATime(request, '{"responseDelay":0}', 20); await result.then( (res) => { @@ -119,44 +118,23 @@ export default function ({ getService }: PluginFunctionalProviderContext) { ); }); - it('should timeout if servers response is too slow', async function () { - // start the request - const request = supertest + it('should timeout if servers response is too slow', async () => { + await supertest .post('/short_idle_socket_timeout') + .send({ responseDelay: 100 }) .set('Content-Type', 'application/json') - .set('Transfer-Encoding', 'chunked') - .set('kbn-xsrf', 'true'); - - const result = writeBodyCharAtATime(request, '{"responseDelay":100}', 0); - - await result.then( - (res) => { - expect(res).to.be(undefined); - }, - (err) => { - expect(err.message).to.be('socket hang up'); - } - ); + .set('kbn-xsrf', 'true') + .then(() => expect('to throw').to.be('but it did NOT')) + .catch((error) => expect(error.message).to.be('socket hang up')); }); - it('should not timeout if servers response is fast enough', async function () { - // start the request - const request = supertest + it('should not timeout if servers response is fast enough', async () => { + await supertest .post('/longer_idle_socket_timeout') + .send({ responseDelay: 100 }) .set('Content-Type', 'application/json') - .set('Transfer-Encoding', 'chunked') - .set('kbn-xsrf', 'true'); - - const result = writeBodyCharAtATime(request, '{"responseDelay":100}', 0); - - await result.then( - (res) => { - expect(res).to.have.property('statusCode', 200); - }, - (err) => { - expect(err).to.be(undefined); - } - ); + .set('kbn-xsrf', 'true') + .expect(200); }); }); }); diff --git a/test/plugin_functional/test_suites/core_plugins/applications.ts b/test/plugin_functional/test_suites/core_plugins/applications.ts index 862cb6acfb6d..d33000bfa70c 100644 --- a/test/plugin_functional/test_suites/core_plugins/applications.ts +++ b/test/plugin_functional/test_suites/core_plugins/applications.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { PluginFunctionalProviderContext } from '../../services'; +import type { PluginFunctionalProviderContext } from '../../services'; export default function ({ getService, getPageObject }: PluginFunctionalProviderContext) { const common = getPageObject('common'); @@ -17,10 +17,24 @@ export default function ({ getService, getPageObject }: PluginFunctionalProvider const find = getService('find'); const deployment = getService('deployment'); const esArchiver = getService('esArchiver'); + const log = getService('log'); + + const clickAppLink = async (app: string) => { + const appLink = `fooNav${app}`; + if (!(await testSubjects.exists(appLink))) { + log.debug(`App ${app} not found on side nav`); + } + await testSubjects.click(appLink); + }; const loadingScreenNotShown = async () => expect(await testSubjects.exists('kbnLoadingMessage')).to.be(false); + const checkAppVisible = async (app: string) => { + const appContainer = `fooApp${app}`; + await testSubjects.existOrFail(appContainer); + }; + const getAppWrapperHeight = async () => { const wrapper = await find.byClassName('kbnAppWrapper'); return (await wrapper.getSize()).height; @@ -29,8 +43,7 @@ export default function ({ getService, getPageObject }: PluginFunctionalProvider const navigateTo = async (path: string) => await browser.navigateTo(`${deployment.getHostPort()}${path}`); - // FLAKY: https://github.com/elastic/kibana/issues/53356 - describe.skip('ui applications', function describeIndexTests() { + describe('ui applications', function describeIndexTests() { before(async () => { await esArchiver.emptyKibanaIndex(); await common.navigateToApp('foo'); @@ -38,48 +51,48 @@ export default function ({ getService, getPageObject }: PluginFunctionalProvider }); it('starts on home page', async () => { - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); }); it('redirects and renders correctly regardless of trailing slash', async () => { await navigateTo(`/app/foo`); await browser.waitForUrlToBe('/app/foo/home'); - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); await navigateTo(`/app/foo/`); await browser.waitForUrlToBe('/app/foo/home'); - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); }); it('navigates to its own pages', async () => { // Go to page A - await testSubjects.click('fooNavPageA'); + await clickAppLink('PageA'); await browser.waitForUrlToBe('/app/foo/page-a'); await loadingScreenNotShown(); - await testSubjects.existOrFail('fooAppPageA'); + await checkAppVisible('PageA'); // Go to home page - await testSubjects.click('fooNavHome'); + await clickAppLink('Home'); await browser.waitForUrlToBe('/app/foo/home'); await loadingScreenNotShown(); - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); }); it('can use the back button to navigate within an app', async () => { await browser.goBack(); await browser.waitForUrlToBe('/app/foo/page-a'); await loadingScreenNotShown(); - await testSubjects.existOrFail('fooAppPageA'); + await checkAppVisible('PageA'); }); it('navigates to app root when navlink is clicked', async () => { - await appsMenu.clickLink('Foo', { category: 'kibana' }); + await appsMenu.clickLink('Foo'); await browser.waitForUrlToBe('/app/foo/home'); await loadingScreenNotShown(); - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); }); it('navigates to other apps', async () => { - await testSubjects.click('fooNavBarPageB'); + await clickAppLink('BarPageB'); await loadingScreenNotShown(); await testSubjects.existOrFail('barAppPageB'); await browser.waitForUrlToBe('/app/bar/page-b?query=here'); @@ -94,7 +107,7 @@ export default function ({ getService, getPageObject }: PluginFunctionalProvider await browser.goBack(); await browser.waitForUrlToBe('/app/foo/home'); await loadingScreenNotShown(); - await testSubjects.existOrFail('fooAppHome'); + await checkAppVisible('Home'); }); it('chromeless applications are not visible in apps list', async () => { diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 1a168e8fe73e..8b248c5bccc6 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -238,6 +238,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.cloud_integrations.full_story.org_id (any)', // No PII. Just the list of event types we want to forward to FullStory. 'xpack.cloud_integrations.full_story.eventTypesAllowlist (array)', + 'xpack.cloud_integrations.full_story.pageVarsDebounceTime (duration)', 'xpack.cloud_integrations.gain_sight.org_id (any)', 'xpack.cloud.id (string)', 'xpack.cloud.organization_url (string)', @@ -282,6 +283,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.infra.featureFlags.logThresholdAlertRuleEnabled (any)', 'xpack.infra.featureFlags.logsUIEnabled (any)', 'xpack.infra.featureFlags.alertsAndRulesDropdownEnabled (any)', + 'xpack.infra.featureFlags.profilingEnabled (any)', 'xpack.license_management.ui.enabled (boolean)', 'xpack.maps.preserveDrawingBuffer (boolean)', diff --git a/tsconfig.base.json b/tsconfig.base.json index a92c90b6aeb3..4ed3f86eef5a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -102,6 +102,10 @@ "@kbn/bfetch-explorer-plugin/*": ["examples/bfetch_explorer/*"], "@kbn/bfetch-plugin": ["src/plugins/bfetch"], "@kbn/bfetch-plugin/*": ["src/plugins/bfetch/*"], + "@kbn/calculate-auto": ["packages/kbn-calculate-auto"], + "@kbn/calculate-auto/*": ["packages/kbn-calculate-auto/*"], + "@kbn/calculate-width-from-char-count": ["packages/kbn-calculate-width-from-char-count"], + "@kbn/calculate-width-from-char-count/*": ["packages/kbn-calculate-width-from-char-count/*"], "@kbn/canvas-plugin": ["x-pack/plugins/canvas"], "@kbn/canvas-plugin/*": ["x-pack/plugins/canvas/*"], "@kbn/cases-api-integration-test-plugin": ["x-pack/test/cases_api_integration/common/plugins/cases"], @@ -596,6 +600,8 @@ "@kbn/crypto-browser/*": ["packages/kbn-crypto-browser/*"], "@kbn/custom-branding-plugin": ["x-pack/plugins/custom_branding"], "@kbn/custom-branding-plugin/*": ["x-pack/plugins/custom_branding/*"], + "@kbn/custom-icons": ["packages/kbn-custom-icons"], + "@kbn/custom-icons/*": ["packages/kbn-custom-icons/*"], "@kbn/custom-integrations": ["packages/kbn-custom-integrations"], "@kbn/custom-integrations/*": ["packages/kbn-custom-integrations/*"], "@kbn/custom-integrations-plugin": ["src/plugins/custom_integrations"], @@ -682,6 +688,8 @@ "@kbn/ecs-data-quality-dashboard/*": ["x-pack/packages/security-solution/ecs_data_quality_dashboard/*"], "@kbn/ecs-data-quality-dashboard-plugin": ["x-pack/plugins/ecs_data_quality_dashboard"], "@kbn/ecs-data-quality-dashboard-plugin/*": ["x-pack/plugins/ecs_data_quality_dashboard/*"], + "@kbn/elastic-agent-utils": ["packages/kbn-elastic-agent-utils"], + "@kbn/elastic-agent-utils/*": ["packages/kbn-elastic-agent-utils/*"], "@kbn/elastic-assistant": ["x-pack/packages/kbn-elastic-assistant"], "@kbn/elastic-assistant/*": ["x-pack/packages/kbn-elastic-assistant/*"], "@kbn/elastic-assistant-plugin": ["x-pack/plugins/elastic_assistant"], @@ -1020,10 +1028,14 @@ "@kbn/ml-category-validator/*": ["x-pack/packages/ml/category_validator/*"], "@kbn/ml-chi2test": ["x-pack/packages/ml/chi2test"], "@kbn/ml-chi2test/*": ["x-pack/packages/ml/chi2test/*"], + "@kbn/ml-creation-wizard-utils": ["x-pack/packages/ml/creation_wizard_utils"], + "@kbn/ml-creation-wizard-utils/*": ["x-pack/packages/ml/creation_wizard_utils/*"], "@kbn/ml-data-frame-analytics-utils": ["x-pack/packages/ml/data_frame_analytics_utils"], "@kbn/ml-data-frame-analytics-utils/*": ["x-pack/packages/ml/data_frame_analytics_utils/*"], "@kbn/ml-data-grid": ["x-pack/packages/ml/data_grid"], "@kbn/ml-data-grid/*": ["x-pack/packages/ml/data_grid/*"], + "@kbn/ml-data-view-utils": ["x-pack/packages/ml/data_view_utils"], + "@kbn/ml-data-view-utils/*": ["x-pack/packages/ml/data_view_utils/*"], "@kbn/ml-date-picker": ["x-pack/packages/ml/date_picker"], "@kbn/ml-date-picker/*": ["x-pack/packages/ml/date_picker/*"], "@kbn/ml-date-utils": ["x-pack/packages/ml/date_utils"], @@ -1060,8 +1072,12 @@ "@kbn/ml-string-hash/*": ["x-pack/packages/ml/string_hash/*"], "@kbn/ml-trained-models-utils": ["x-pack/packages/ml/trained_models_utils"], "@kbn/ml-trained-models-utils/*": ["x-pack/packages/ml/trained_models_utils/*"], + "@kbn/ml-ui-actions": ["x-pack/packages/ml/ui_actions"], + "@kbn/ml-ui-actions/*": ["x-pack/packages/ml/ui_actions/*"], "@kbn/ml-url-state": ["x-pack/packages/ml/url_state"], "@kbn/ml-url-state/*": ["x-pack/packages/ml/url_state/*"], + "@kbn/mock-idp-plugin": ["packages/kbn-mock-idp-plugin"], + "@kbn/mock-idp-plugin/*": ["packages/kbn-mock-idp-plugin/*"], "@kbn/monaco": ["packages/kbn-monaco"], "@kbn/monaco/*": ["packages/kbn-monaco/*"], "@kbn/monitoring-collection-plugin": ["x-pack/plugins/monitoring_collection"], @@ -1088,6 +1104,8 @@ "@kbn/observability-alerting-test-data/*": ["x-pack/packages/observability/alerting_test_data/*"], "@kbn/observability-fixtures-plugin": ["x-pack/test/cases_api_integration/common/plugins/observability"], "@kbn/observability-fixtures-plugin/*": ["x-pack/test/cases_api_integration/common/plugins/observability/*"], + "@kbn/observability-get-padded-alert-time-range-util": ["x-pack/packages/observability/get_padded_alert_time_range_util"], + "@kbn/observability-get-padded-alert-time-range-util/*": ["x-pack/packages/observability/get_padded_alert_time_range_util/*"], "@kbn/observability-log-explorer-plugin": ["x-pack/plugins/observability_log_explorer"], "@kbn/observability-log-explorer-plugin/*": ["x-pack/plugins/observability_log_explorer/*"], "@kbn/observability-onboarding-plugin": ["x-pack/plugins/observability_onboarding"], @@ -1100,6 +1118,8 @@ "@kbn/oidc-provider-plugin/*": ["x-pack/test/security_api_integration/plugins/oidc_provider/*"], "@kbn/open-telemetry-instrumented-plugin": ["test/common/plugins/otel_metrics"], "@kbn/open-telemetry-instrumented-plugin/*": ["test/common/plugins/otel_metrics/*"], + "@kbn/openapi-bundler": ["packages/kbn-openapi-bundler"], + "@kbn/openapi-bundler/*": ["packages/kbn-openapi-bundler/*"], "@kbn/openapi-generator": ["packages/kbn-openapi-generator"], "@kbn/openapi-generator/*": ["packages/kbn-openapi-generator/*"], "@kbn/optimizer": ["packages/kbn-optimizer"], @@ -1114,6 +1134,8 @@ "@kbn/paertial-results-example-plugin/*": ["examples/partial_results_example/*"], "@kbn/painless-lab-plugin": ["x-pack/plugins/painless_lab"], "@kbn/painless-lab-plugin/*": ["x-pack/plugins/painless_lab/*"], + "@kbn/panel-loader": ["packages/kbn-panel-loader"], + "@kbn/panel-loader/*": ["packages/kbn-panel-loader/*"], "@kbn/peggy": ["packages/kbn-peggy"], "@kbn/peggy/*": ["packages/kbn-peggy/*"], "@kbn/peggy-loader": ["packages/kbn-peggy-loader"], @@ -1270,6 +1292,12 @@ "@kbn/security-api-integration-helpers/*": ["x-pack/test/security_api_integration/packages/helpers/*"], "@kbn/security-plugin": ["x-pack/plugins/security"], "@kbn/security-plugin/*": ["x-pack/plugins/security/*"], + "@kbn/security-plugin-types-common": ["x-pack/packages/security/plugin_types_common"], + "@kbn/security-plugin-types-common/*": ["x-pack/packages/security/plugin_types_common/*"], + "@kbn/security-plugin-types-public": ["x-pack/packages/security/plugin_types_public"], + "@kbn/security-plugin-types-public/*": ["x-pack/packages/security/plugin_types_public/*"], + "@kbn/security-plugin-types-server": ["x-pack/packages/security/plugin_types_server"], + "@kbn/security-plugin-types-server/*": ["x-pack/packages/security/plugin_types_server/*"], "@kbn/security-solution-ess": ["x-pack/plugins/security_solution_ess"], "@kbn/security-solution-ess/*": ["x-pack/plugins/security_solution_ess/*"], "@kbn/security-solution-features": ["x-pack/packages/security-solution/features"], @@ -1490,8 +1518,6 @@ "@kbn/stdio-dev-helpers/*": ["packages/kbn-stdio-dev-helpers/*"], "@kbn/storybook": ["packages/kbn-storybook"], "@kbn/storybook/*": ["packages/kbn-storybook/*"], - "@kbn/subscription-tracking": ["packages/kbn-subscription-tracking"], - "@kbn/subscription-tracking/*": ["packages/kbn-subscription-tracking/*"], "@kbn/synthetics-plugin": ["x-pack/plugins/synthetics"], "@kbn/synthetics-plugin/*": ["x-pack/plugins/synthetics/*"], "@kbn/task-manager-fixture-plugin": ["x-pack/test/alerting_api_integration/common/plugins/task_manager_fixture"], @@ -1670,9 +1696,7 @@ "@kbn/zod-helpers/*": ["packages/kbn-zod-helpers/*"], // END AUTOMATED PACKAGE LISTING // Allows for importing from `kibana` package for the exported types. - "@emotion/core": [ - "typings/@emotion" - ], + "@emotion/core": ["typings/@emotion"] }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", @@ -1743,6 +1767,6 @@ "@kbn/ambient-ui-types", "@kbn/ambient-common-types", "@kbn/ambient-storybook-types" - ], + ] } } diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index bb14c06a53e3..3a6b3bc95a81 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -55,10 +55,13 @@ "xpack.metricsData": "plugins/metrics_data_access", "xpack.ml": [ "packages/ml/anomaly_utils", + "packages/ml/creation_wizard_utils", "packages/ml/data_grid", + "packages/ml/data_view_utils", "packages/ml/date_picker", "packages/ml/trained_models_utils", "packages/ml/category_validator", + "packages/ml/ui_actions", "plugins/ml" ], "xpack.monitoring": ["plugins/monitoring"], diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx index b1d9145a9e61..c38983df5a6c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.test.tsx @@ -75,19 +75,20 @@ describe('API tests', () => { expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { - body: '{"params":{"subActionParams":{"model":"gpt-4","messages":[{"role":"user","content":"This is a test"}],"n":1,"stop":null,"temperature":0.2},"subAction":"invokeAI"},"assistantLangChain":false}', - headers: { 'Content-Type': 'application/json' }, + body: '{"params":{"subActionParams":{"model":"gpt-4","messages":[{"role":"user","content":"This is a test"}],"n":1,"stop":null,"temperature":0.2},"subAction":"invokeStream"},"assistantLangChain":false}', method: 'POST', + asResponse: true, + rawResponse: true, signal: undefined, } ); }); - it('returns API_ERROR when the response status is not ok', async () => { + it('returns API_ERROR when the response status is error and langchain is on', async () => { (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'error' }); const testProps: FetchConnectorExecuteAction = { - assistantLangChain: false, + assistantLangChain: true, http: mockHttp, messages, apiConfig, @@ -98,10 +99,50 @@ describe('API tests', () => { expect(result).toEqual({ response: API_ERROR, isStream: false, isError: true }); }); + it('returns API_ERROR when the response status is error, langchain is off, and response is not a reader', async () => { + (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'error' }); + + const testProps: FetchConnectorExecuteAction = { + assistantLangChain: false, + http: mockHttp, + messages, + apiConfig, + }; + + const result = await fetchConnectorExecuteAction(testProps); + + expect(result).toEqual({ + response: `${API_ERROR}\n\nCould not get reader from response`, + isStream: false, + isError: true, + }); + }); + + it('returns API_ERROR when the response is error, langchain is off, and response is a reader', async () => { + const mockReader = jest.fn(); + (mockHttp.fetch as jest.Mock).mockRejectedValue({ + response: { body: { getReader: jest.fn().mockImplementation(() => mockReader) } }, + }); + const testProps: FetchConnectorExecuteAction = { + assistantLangChain: false, + http: mockHttp, + messages, + apiConfig, + }; + + const result = await fetchConnectorExecuteAction(testProps); + + expect(result).toEqual({ + response: mockReader, + isStream: true, + isError: true, + }); + }); + it('returns API_ERROR when there are no choices', async () => { (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'ok', data: '' }); const testProps: FetchConnectorExecuteAction = { - assistantLangChain: false, + assistantLangChain: true, http: mockHttp, messages, apiConfig, @@ -278,6 +319,9 @@ describe('API tests', () => { evalParams: { agents: ['not', 'alphabetical'], dataset: '{}', + datasetName: 'Test Dataset', + projectName: 'Test Project Name', + runName: 'Test Run Name', evalModel: ['not', 'alphabetical'], evalPrompt: 'evalPrompt', evaluationType: ['not', 'alphabetical'], @@ -295,9 +339,12 @@ describe('API tests', () => { query: { models: 'alphabetical,not', agents: 'alphabetical,not', + datasetName: 'Test Dataset', evaluationType: 'alphabetical,not', evalModel: 'alphabetical,not', outputIndex: 'outputIndex', + projectName: 'Test Project Name', + runName: 'Test Run Name', }, signal: undefined, }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx index 69e6d39d85e1..a0263bc21b2d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx @@ -26,6 +26,10 @@ export interface FetchConnectorExecuteResponse { response: string | ReadableStreamDefaultReader; isError: boolean; isStream: boolean; + traceData?: { + transactionId: string; + traceId: string; + }; } export const fetchConnectorExecuteAction = async ({ @@ -54,17 +58,16 @@ export const fetchConnectorExecuteAction = async ({ messages: outboundMessages, }; - // TODO: Remove in part 2 of streaming work for security solution + // TODO: Remove in part 3 of streaming work for security solution // tracked here: https://github.com/elastic/security-team/issues/7363 - // My "Feature Flag", turn to false before merging - // In part 2 I will make enhancements to invokeAI to make it work with both openA, but to keep it to a Security Soltuion only review on this PR, - // I'm calling the stream action directly - const isStream = !assistantLangChain && false; + // In part 3 I will make enhancements to langchain to introduce streaming + // Once implemented, invokeAI can be removed + const isStream = !assistantLangChain; const requestBody = isStream ? { params: { subActionParams: body, - subAction: 'stream', + subAction: 'invokeStream', }, assistantLangChain, } @@ -105,7 +108,7 @@ export const fetchConnectorExecuteAction = async ({ }; } - // TODO: Remove in part 2 of streaming work for security solution + // TODO: Remove in part 3 of streaming work for security solution // tracked here: https://github.com/elastic/security-team/issues/7363 // This is a temporary code to support the non-streaming API const response = await http.fetch<{ @@ -113,6 +116,10 @@ export const fetchConnectorExecuteAction = async ({ status: string; data: string; service_message?: string; + trace_data?: { + transaction_id: string; + trace_id: string; + }; }>(`/internal/elastic_assistant/actions/connector/${apiConfig?.connectorId}/_execute`, { method: 'POST', body: JSON.stringify(requestBody), @@ -134,16 +141,36 @@ export const fetchConnectorExecuteAction = async ({ isStream: false, }; } + + // Only add traceData if it exists in the response + const traceData = + response.trace_data?.trace_id != null && response.trace_data?.transaction_id != null + ? { + traceId: response.trace_data?.trace_id, + transactionId: response.trace_data?.transaction_id, + } + : undefined; + return { response: assistantLangChain ? getFormattedMessageContent(response.data) : response.data, isError: false, isStream: false, + traceData, }; } catch (error) { + const reader = error?.response?.body?.getReader(); + + if (!reader) { + return { + response: `${API_ERROR}\n\n${error?.body?.message ?? error?.message}`, + isError: true, + isStream: false, + }; + } return { - response: `${API_ERROR}\n\n${error?.body?.message ?? error?.message}`, + response: reader, + isStream: true, isError: true, - isStream: false, }; } }; @@ -273,6 +300,7 @@ export interface PostEvaluationParams { } export interface PostEvaluationResponse { + evaluationId: string; success: boolean; } @@ -294,11 +322,14 @@ export const postEvaluation = async ({ try { const path = `/internal/elastic_assistant/evaluate`; const query = { - models: evalParams?.models.sort()?.join(','), agents: evalParams?.agents.sort()?.join(','), + datasetName: evalParams?.datasetName, evaluationType: evalParams?.evaluationType.sort()?.join(','), evalModel: evalParams?.evalModel.sort()?.join(','), outputIndex: evalParams?.outputIndex, + models: evalParams?.models.sort()?.join(','), + projectName: evalParams?.projectName, + runName: evalParams?.runName, }; const response = await http.fetch(path, { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts index 61001d95e8a3..fa9617d00a6e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts @@ -22,6 +22,7 @@ export const getMessageFromRawResponse = (rawResponse: FetchConnectorExecuteResp : { content: response as string }), timestamp: dateTimeString, isError, + traceData: rawResponse.traceData, }; } else { return { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx index ab8d79454b0e..f4fe4d7f8a40 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx @@ -7,6 +7,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { + EuiAccordion, euiPaletteComplementary, EuiFormRow, EuiTitle, @@ -17,12 +18,14 @@ import { EuiButton, EuiComboBoxOptionOption, EuiTextArea, + EuiTextColor, EuiFieldText, EuiFlexItem, EuiFlexGroup, EuiLink, } from '@elastic/eui'; +import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import * as i18n from './translations'; import { useAssistantContext } from '../../../assistant_context'; @@ -30,6 +33,8 @@ import { useLoadConnectors } from '../../../connectorland/use_load_connectors'; import { getActionTypeTitle, getGenAiConfig } from '../../../connectorland/helpers'; import { PRECONFIGURED_CONNECTOR } from '../../../connectorland/translations'; import { usePerformEvaluation } from './use_perform_evaluation'; +import { getApmLink, getDiscoverLink } from './utils'; +import { PostEvaluationResponse } from '../../api'; /** * See AGENT_EXECUTOR_MAP in `x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts` @@ -41,6 +46,7 @@ const DEFAULT_EVAL_TYPES_OPTIONS = [ { label: 'esql-validator', disabled: true }, { label: 'custom', disabled: true }, ]; +const DEFAULT_OUTPUT_INDEX = '.kibana-elastic-ai-assistant-evaluation-results'; interface Props { onEvaluationSettingsChange?: () => void; @@ -52,10 +58,93 @@ interface Props { export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSettingsChange }) => { const { actionTypeRegistry, basePath, http } = useAssistantContext(); const { data: connectors } = useLoadConnectors({ http }); - const { mutate: performEvaluation, isLoading: isPerformingEvaluation } = usePerformEvaluation({ + const { + data: evalResponse, + mutate: performEvaluation, + isLoading: isPerformingEvaluation, + } = usePerformEvaluation({ http, }); + // Run Details + // Project Name + const [projectName, setProjectName] = useState(); + const onProjectNameChange = useCallback( + (e) => { + setProjectName(e.target.value); + }, + [setProjectName] + ); + // Run Name + const [runName, setRunName] = useState(); + const onRunNameChange = useCallback( + (e) => { + setRunName(e.target.value); + }, + [setRunName] + ); + // Local Output Index + const [outputIndex, setOutputIndex] = useState(DEFAULT_OUTPUT_INDEX); + const onOutputIndexChange = useCallback( + (e) => { + setOutputIndex(e.target.value); + }, + [setOutputIndex] + ); + // Dataset + const [useLangSmithDataset, setUseLangSmithDataset] = useState(true); + const datasetToggleButton = useMemo(() => { + return ( + + {i18n.EVALUATOR_DATASET_LABEL} + {' ('} + setUseLangSmithDataset(true)} + > + {i18n.LANGSMITH_DATASET_LABEL} + + {' / '} + setUseLangSmithDataset(false)} + > + {i18n.CUSTOM_DATASET_LABEL} + + {')'} + + ); + }, [useLangSmithDataset]); + const [datasetName, setDatasetName] = useState(); + const onDatasetNameChange = useCallback( + (e) => { + setDatasetName(e.target.value); + }, + [setDatasetName] + ); + const sampleDataset = [ + { + input: + 'As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, and really make sure you check your knowledge really well on all the functions I am asking for. check it multiple times if you need to. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema. Ensure the answers are formatted in a way which is easily copyable.\n\n' + + 'Write an ESQL query for detecting cryptomining activity on an AWS EC2 instance.', + reference: + 'FROM metrics-apm*\n| WHERE metricset.name == ""transaction"" AND metricset.interval == ""1m""\n| EVAL bucket = AUTO_BUCKET(transaction.duration.histogram, 50, , )\n| STATS avg_duration = AVG(transaction.duration.histogram) BY bucket', + }, + ]; + const [datasetText, setDatasetText] = useState(JSON.stringify(sampleDataset, null, 2)); + const onDatasetTextChange = useCallback( + (e) => { + setDatasetText(e.target.value); + }, + [setDatasetText] + ); + + // Predictions // Connectors / Models const [selectedModelOptions, setSelectedModelOptions] = useState< Array> @@ -109,6 +198,7 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet return DEFAULT_AGENTS.map((label) => ({ label })); }, []); + // Evaluation // Evaluation Type const [selectedEvaluationType, setSelectedEvaluationType] = useState< Array> @@ -146,15 +236,6 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet [setSelectedEvaluatorModelOptions] ); - // Output Index - const [outputIndex, setOutputIndex] = useState('.kibana-elastic-ai-assistant-evaluation-results'); - const onOutputIndexChange = useCallback( - (e) => { - setOutputIndex(e.target.value); - }, - [setOutputIndex] - ); - // Eval Prompt const sampleEvalPrompt: string = `For the below input: \n\n{{input}} \n\na prediction: \n\n{{prediction}} \n\nwas made. How's it stack up against this reference: \n\n{{reference}} \n\nReturn output in a succinct sentence ranking on a simple grading rubric focused on correctness.`; const [evalPrompt, setEvalPrompt] = useState(sampleEvalPrompt); @@ -165,55 +246,88 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet [setEvalPrompt] ); - // Dataset - const sampleDataset = [ - { - input: - 'I want to see a query for metrics-apm*, filtering on metricset.name:transaction and metricset.interval:1m, showing the average duration (via transaction.duration.histogram), in 50 buckets. Only return the ESQL query, and do not wrap in a codeblock.', - reference: - 'FROM metrics-apm*\n| WHERE metricset.name == ""transaction"" AND metricset.interval == ""1m""\n| EVAL bucket = AUTO_BUCKET(transaction.duration.histogram, 50, , )\n| STATS avg_duration = AVG(transaction.duration.histogram) BY bucket', - }, - ]; - const [datasetText, setDatasetText] = useState(JSON.stringify(sampleDataset, null, 2)); - const onDatasetTextChange = useCallback( - (e) => { - setDatasetText(e.target.value); - }, - [setDatasetText] - ); - + // Required fields by eval API const isPerformEvaluationDisabled = selectedModelOptions.length === 0 || selectedAgentOptions.length === 0 || - selectedEvaluatorModelOptions.length === 0 || - selectedEvaluationType.length === 0 || - datasetText.length === 0 || outputIndex.length === 0; // Perform Evaluation Button - const handlePerformEvaluation = useCallback(() => { + const handlePerformEvaluation = useCallback(async () => { const evalParams = { models: selectedModelOptions.flatMap((option) => option.key ?? []), agents: selectedAgentOptions.map((option) => option.label), - dataset: datasetText, + dataset: useLangSmithDataset ? undefined : datasetText, + datasetName: useLangSmithDataset ? datasetName : undefined, evalModel: selectedEvaluatorModelOptions.flatMap((option) => option.key ?? []), evalPrompt, evaluationType: selectedEvaluationType.map((option) => option.label), outputIndex, + projectName, + runName, }; performEvaluation(evalParams); }, [ + datasetName, datasetText, evalPrompt, outputIndex, performEvaluation, + projectName, + runName, selectedAgentOptions, selectedEvaluationType, selectedEvaluatorModelOptions, selectedModelOptions, + useLangSmithDataset, ]); - const discoverLink = `${basePath}/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-7d%2Fd,to:now))&_a=(columns:!('@timestamp',evaluationId,totalAgents,totalInput,totalRequests,input,reference,prediction,evaluation.value,evaluation.reasoning,predictionResponse.value.connector_id),filters:!(),grid:(columns:('@timestamp':(width:212),evaluationId:(width:285),totalAgents:(width:111),totalInput:(width:98),totalRequests:(width:121))),index:'6d9ba861-a76b-4d31-90f4-dfb8f01b78bd',interval:auto,query:(esql:'from%20.kibana-elastic-ai-assistant-evaluation-results%20%0A%7C%20keep%20@timestamp,%20evaluationId,%20totalAgents,%20totalInput,%20totalRequests,%20input,%20reference,%20prediction,%20evaluation.value,%20evaluation.reasoning,%20predictionResponse.value.connector_id%0A%7C%20sort%20@timestamp%20desc%0A%7C%20limit%20100%0A%0A%0A'),sort:!(!('@timestamp',desc)))`; + const discoverLink = useMemo( + () => getDiscoverLink(basePath, (evalResponse as PostEvaluationResponse)?.evaluationId ?? ''), + [basePath, evalResponse] + ); + + const apmLink = useMemo( + () => getApmLink(basePath, (evalResponse as PostEvaluationResponse)?.evaluationId ?? ''), + [basePath, evalResponse] + ); + + const getSection = (title: string, description: string) => ( +
    + + + +

    {title}

    +
    +
    +
    + + +

    + {description} +

    +
    +
    + ); + + const runDetailsSection = useMemo( + () => getSection(i18n.RUN_DETAILS_TITLE, i18n.RUN_DETAILS_DESCRIPTION), + [] + ); + const predictionDetailsSection = useMemo( + () => getSection(i18n.PREDICTION_DETAILS_TITLE, i18n.PREDICTION_DETAILS_DESCRIPTION), + [] + ); + const evalDetailsSection = useMemo( + () => getSection(i18n.EVALUATION_DETAILS_TITLE, i18n.EVALUATION_DETAILS_DESCRIPTION), + [] + ); + + const buttonCss = css` + &:hover { + text-decoration: none; + } + `; return ( <> @@ -223,113 +337,193 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet {i18n.SETTINGS_DESCRIPTION} - - - - - - - - - - + + + + + + + + + + + + + {useLangSmithDataset ? ( + + ) : ( + + )} + + + + + + + {/* Prediction Details*/} + - - + + + - + + + + + {/* Evaluation Details*/} + - - + + + - - - + + + - - - - - - - - + helpText={i18n.EVALUATION_PROMPT_DESCRIPTION} + > + + + - = React.memo(({ onEvaluationSet {i18n.EVALUATOR_FUN_FACT_DISCOVER_LINK} ), + apm: ( + + {i18n.EVALUATOR_FUN_FACT_APM_LINK} + + ), }} /> - ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts index d0299cb7d513..305090d76678 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts @@ -17,7 +17,93 @@ export const SETTINGS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.settingsDescription', { defaultMessage: - 'Not-so-secret dev UI for evaluating sample datasets against models/agents/more...', + 'Run predictions and evaluations against test data sets using different models (connectors), agents, and evaluation schemes.', + } +); + +export const RUN_DETAILS_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runDetailsTitle', + { + defaultMessage: '🏃 Run Details', + } +); + +export const RUN_DETAILS_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runDetailsDescription', + { + defaultMessage: 'Configure test run details like project, run name, dataset, and output index', + } +); + +export const PREDICTION_DETAILS_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.predictionDetailsTitle', + { + defaultMessage: '🔮 Predictions', + } +); + +export const PREDICTION_DETAILS_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.predictionDetailsDescription', + { + defaultMessage: + 'Choose models (connectors) and corresponding agents the dataset should run against', + } +); + +export const EVALUATION_DETAILS_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationDetailsTitle', + { + defaultMessage: '🧮 Evaluation (Optional)', + } +); + +export const EVALUATION_DETAILS_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationDetailsDescription', + { + defaultMessage: + 'Evaluate prediction results using a specific model (connector) and evaluation criterion', + } +); + +export const PROJECT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectLabel', + { + defaultMessage: 'Project', + } +); + +export const PROJECT_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectDescription', + { + defaultMessage: 'LangSmith project to write results to', + } +); + +export const PROJECT_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectPlaceholder', + { + defaultMessage: '8.12 Testing', + } +); + +export const RUN_NAME_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameLabel', + { + defaultMessage: 'Run name', + } +); + +export const RUN_NAME_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameDescription', + { + defaultMessage: 'Name for this specific test run', + } +); + +export const RUN_NAME_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNamePlaceholder', + { + defaultMessage: '8.12 ESQL Query Generation', } ); @@ -114,11 +200,39 @@ export const EVALUATOR_DATASET_LABEL = i18n.translate( } ); -export const EVALUATOR_DATASET_DESCRIPTION = i18n.translate( - 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetDescription', +export const LANGSMITH_DATASET_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetLabel', + { + defaultMessage: 'LangSmith', + } +); + +export const LANGSMITH_DATASET_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetDescription', + { + defaultMessage: 'Name of dataset hosted on LangSmith to evaluate', + } +); + +export const LANGSMITH_DATASET_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetPlaceholder', + { + defaultMessage: 'ESQL Query Generation', + } +); + +export const CUSTOM_DATASET_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetLabel', + { + defaultMessage: 'Custom', + } +); + +export const CUSTOM_DATASET_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetDescription', { defaultMessage: - 'Sample data set to evaluate. Array of objects with "input" and "references" properties', + 'Custom dataset to evaluate. Array of objects with "input" and "references" properties', } ); @@ -132,6 +246,12 @@ export const PERFORM_EVALUATION = i18n.translate( export const EVALUATOR_FUN_FACT_DISCOVER_LINK = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactDiscoverLinkText', { - defaultMessage: 'click here', + defaultMessage: 'Discover', + } +); +export const EVALUATOR_FUN_FACT_APM_LINK = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactApmLinkText', + { + defaultMessage: 'APM', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/use_perform_evaluation.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/use_perform_evaluation.tsx index ac194d9c0225..158f7159310a 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/use_perform_evaluation.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/use_perform_evaluation.tsx @@ -20,12 +20,15 @@ export interface UsePerformEvaluationParams { export interface PerformEvaluationParams { agents: string[]; - dataset: string; + dataset: string | undefined; + datasetName: string | undefined; evalModel: string[]; evalPrompt: string; evaluationType: string[]; models: string[]; outputIndex: string; + projectName: string | undefined; + runName: string | undefined; } /** diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/utils.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/utils.tsx new file mode 100644 index 000000000000..ae35db921b07 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/utils.tsx @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Link to Discover for viewing an evaluation + * + * @param basePath + * @param evaluationId + */ +export const getDiscoverLink = (basePath: string, evaluationId: string) => { + return `${basePath}/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-1y%2Fd,to:now))&_a=(columns:!(evaluationId,runName,totalAgents,totalInput,totalRequests,input,reference,prediction,evaluation.value,evaluation.reasoning,connectorName,connectorName.keyword,evaluation.__run.runId,evaluation.__run.runId.keyword,evaluation.score,evaluationEnd,evaluationId.keyword,evaluationStart,input.keyword,inputExampleId,inputExampleId.keyword,evaluationDuration,prediction.keyword,predictionResponse.reason.sendToLLM,predictionResponse.status,ConnectorId,predictionResponse.value.data,predictionResponse.value.data.keyword,predictionResponse.value.status,predictionResponse.value.trace_data.trace_id,predictionResponse.value.trace_data.trace_id.keyword,predictionResponse.value.trace_data.transaction_id,predictionResponse.value.trace_data.transaction_id.keyword,reference.keyword,runName.keyword),filters:!(),grid:(columns:('@timestamp':(width:212),ConnectorId:(width:133),connectorName:(width:181),connectorName.keyword:(width:229),evaluation.__run.runId:(width:282),evaluation.__run.runId.keyword:(width:245),evaluation.reasoning:(width:336),evaluation.reasoning.keyword:(width:232),evaluation.score:(width:209),evaluation.value:(width:156),evaluationDuration:(width:174),evaluationEnd:(width:151),evaluationId:(width:130),evaluationId.keyword:(width:186),evaluationStart:(width:202),input:(width:347),input.keyword:(width:458),prediction:(width:264),prediction.keyword:(width:313),predictionResponse.value.connector_id:(width:294),predictionResponse.value.trace_data.trace_id:(width:278),predictionResponse.value.trace_data.transaction_id.keyword:(width:177),reference:(width:305),reference.keyword:(width:219),runName:(width:405),totalAgents:(width:125),totalInput:(width:111),totalRequests:(width:138))),hideChart:!t,index:ce1b41cb-6298-4612-a33c-ba85b3c18ec7,interval:auto,query:(esql:'from%20.kibana-elastic-ai-assistant-evaluation-results%20%0A%7C%20keep%20@timestamp,%20evaluationId,%20runName,%20totalAgents,%20totalInput,%20totalRequests,%20input,%20reference,%20prediction,%20evaluation.value,%20evaluation.reasoning,%20connectorName,%20*%0A%7C%20drop%20evaluation.reasoning.keyword%0A%7C%20rename%20predictionResponse.value.connector_id%20as%20ConnectorId%0A%7C%20where%20evaluationId%20%3D%3D%20%22${evaluationId}%22%0A%7C%20sort%20@timestamp%20desc%0A%7C%20limit%20100%0A%0A%0A'),rowHeight:15,sort:!(!('@timestamp',desc)))`; +}; + +/** + * Link to APM Trace Explorer for viewing an evaluation + * @param basePath + * @param evaluationId + */ +export const getApmLink = (basePath: string, evaluationId: string) => { + return `${basePath}/app/apm/traces/explorer/waterfall?comparisonEnabled=false&detailTab=timeline&environment=ENVIRONMENT_ALL&kuery=&query=%22labels.evaluationId%22:%20%22${evaluationId}%22&rangeFrom=now-1y&rangeTo=now&showCriticalPath=false&traceId=451662121b1f5e6c44084ad7415b9409&transactionId=5f1392fa04766025&type=kql&waterfallItemId=`; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx index f9ade4b9abc1..d4d2d1672b2c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx @@ -20,6 +20,10 @@ export interface Message { timestamp: string; isError?: boolean; presentation?: MessagePresentation; + traceData?: { + transactionId: string; + traceId: string; + }; } export interface ConversationTheme { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/new_chat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/new_chat/index.tsx index 3f6b7afc14c7..3fd798f38c4b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/new_chat/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/new_chat/index.tsx @@ -21,10 +21,13 @@ export type Props = Omit & { iconType?: string | null; /** Optionally specify a well known ID, or default to a UUID */ promptContextId?: string; + /** Optionally specify color of empty button */ + color?: 'text' | 'accent' | 'primary' | 'success' | 'warning' | 'danger'; }; const NewChatComponent: React.FC = ({ category, + color = 'primary', children = i18n.NEW_CHAT, conversationId, description, @@ -58,11 +61,11 @@ const NewChatComponent: React.FC = ({ return useMemo( () => ( - + {children} ), - [children, icon, showOverlay] + [children, icon, showOverlay, color] ); }; diff --git a/x-pack/packages/kbn-slo-schema/index.ts b/x-pack/packages/kbn-slo-schema/index.ts index 98b183d391bb..3d9e295055a6 100644 --- a/x-pack/packages/kbn-slo-schema/index.ts +++ b/x-pack/packages/kbn-slo-schema/index.ts @@ -8,4 +8,3 @@ export * from './src/schema'; export * from './src/rest_specs'; export * from './src/models/duration'; -export * from './src/models/pagination'; diff --git a/x-pack/packages/kbn-slo-schema/src/models/pagination.ts b/x-pack/packages/kbn-slo-schema/src/models/pagination.ts deleted file mode 100644 index 815c30f71d4c..000000000000 --- a/x-pack/packages/kbn-slo-schema/src/models/pagination.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -export interface Paginated { - total: number; - page: number; - perPage: number; - results: T[]; -} - -export interface Pagination { - page: number; - perPage: number; -} diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts index 1251e49b56af..54e463adc210 100644 --- a/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts +++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts @@ -6,7 +6,6 @@ */ import * as t from 'io-ts'; -import { toBooleanRt } from '@kbn/io-ts-utils'; import { allOrAnyString, apmTransactionDurationIndicatorSchema, @@ -61,6 +60,10 @@ const createSLOResponseSchema = t.type({ const getPreviewDataParamsSchema = t.type({ body: t.type({ indicator: indicatorSchema, + range: t.type({ + start: t.number, + end: t.number, + }), }), }); @@ -106,7 +109,6 @@ const sloResponseSchema = t.intersection([ groupBy: allOrAnyString, createdAt: dateType, updatedAt: dateType, - version: t.number, }), t.partial({ instanceId: allOrAnyString, @@ -155,12 +157,6 @@ const manageSLOParamsSchema = t.type({ path: t.type({ id: sloIdSchema }), }); -const resetSLOParamsSchema = t.type({ - path: t.type({ id: sloIdSchema }), -}); - -const resetSLOResponseSchema = sloResponseSchema; - const updateSLOResponseSchema = sloResponseSchema; const findSLOResponseSchema = t.type({ @@ -186,21 +182,23 @@ const fetchHistoricalSummaryResponseSchema = t.array( }) ); -const findSloDefinitionsParamsSchema = t.partial({ - query: t.partial({ +/** + * The query params schema for /internal/observability/slo/_definitions + * + * @private + */ +const findSloDefinitionsParamsSchema = t.type({ + query: t.type({ search: t.string, - includeOutdatedOnly: toBooleanRt, - page: t.string, - perPage: t.string, }), }); -const findSloDefinitionsResponseSchema = t.type({ - page: t.number, - perPage: t.number, - total: t.number, - results: t.array(sloResponseSchema), -}); +/** + * The response schema for /internal/observability/slo/_definitions + * + * @private + */ +const findSloDefinitionsResponseSchema = t.array(sloResponseSchema); const getSLOBurnRatesResponseSchema = t.type({ burnRates: t.array( @@ -246,9 +244,6 @@ type GetSLOResponse = t.OutputOf; type ManageSLOParams = t.TypeOf; -type ResetSLOParams = t.TypeOf; -type ResetSLOResponse = t.OutputOf; - type UpdateSLOInput = t.OutputOf; type UpdateSLOParams = t.TypeOf; type UpdateSLOResponse = t.OutputOf; @@ -263,8 +258,12 @@ type FetchHistoricalSummaryParams = t.TypeOf; type HistoricalSummaryResponse = t.OutputOf; -type FindSLODefinitionsParams = t.TypeOf; -type FindSLODefinitionsResponse = t.OutputOf; +/** + * The response type for /internal/observability/slo/_definitions + * + * @private + */ +type FindSloDefinitionsResponse = t.OutputOf; type GetPreviewDataParams = t.TypeOf; type GetPreviewDataResponse = t.OutputOf; @@ -301,8 +300,6 @@ export { findSloDefinitionsParamsSchema, findSloDefinitionsResponseSchema, manageSLOParamsSchema, - resetSLOParamsSchema, - resetSLOResponseSchema, sloResponseSchema, sloWithSummaryResponseSchema, updateSLOParamsSchema, @@ -328,11 +325,8 @@ export type { FetchHistoricalSummaryParams, FetchHistoricalSummaryResponse, HistoricalSummaryResponse, - FindSLODefinitionsParams, - FindSLODefinitionsResponse, + FindSloDefinitionsResponse, ManageSLOParams, - ResetSLOParams, - ResetSLOResponse, SLOResponse, SLOWithSummaryResponse, UpdateSLOInput, diff --git a/x-pack/packages/kbn-slo-schema/src/schema/common.ts b/x-pack/packages/kbn-slo-schema/src/schema/common.ts index 166f3eab34a9..55e597e759d6 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/common.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/common.ts @@ -50,10 +50,19 @@ const historicalSummarySchema = t.intersection([ summarySchema, ]); -const previewDataSchema = t.type({ - date: dateType, - sliValue: t.number, -}); +const previewDataSchema = t.intersection([ + t.type({ + date: dateType, + sliValue: t.number, + }), + t.partial({ + events: t.type({ + good: t.number, + bad: t.number, + total: t.number, + }), + }), +]); const dateRangeSchema = t.type({ from: dateType, to: dateType }); diff --git a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts index 27e8a9e998f7..29df82010710 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts @@ -50,7 +50,6 @@ const sloSchema = t.type({ createdAt: dateType, updatedAt: dateType, groupBy: allOrAnyString, - version: t.number, }); const sloWithSummarySchema = t.intersection([sloSchema, t.type({ summary: summarySchema })]); diff --git a/x-pack/packages/kbn-slo-schema/tsconfig.json b/x-pack/packages/kbn-slo-schema/tsconfig.json index bc9fd2fdede8..3c94d9a902af 100644 --- a/x-pack/packages/kbn-slo-schema/tsconfig.json +++ b/x-pack/packages/kbn-slo-schema/tsconfig.json @@ -11,8 +11,7 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/std", - "@kbn/io-ts-utils" + "@kbn/std" ], "exclude": [ "target/**/*", diff --git a/x-pack/packages/ml/aiops_utils/window_parameters.ts b/x-pack/packages/ml/aiops_utils/window_parameters.ts index 806d224defdf..91ecee5f841a 100644 --- a/x-pack/packages/ml/aiops_utils/window_parameters.ts +++ b/x-pack/packages/ml/aiops_utils/window_parameters.ts @@ -15,25 +15,13 @@ import { isPopulatedObject } from '@kbn/ml-is-populated-object'; * @typedef {WindowParameters} */ export interface WindowParameters { - /** - * Baseline minimum value - * @type {number} - */ + /** Baseline minimum value */ baselineMin: number; - /** - * Baseline maximum value - * @type {number} - */ + /** Baseline maximum value */ baselineMax: number; - /** - * Deviation minimum value - * @type {number} - */ + /** Deviation minimum value */ deviationMin: number; - /** - * Deviation maximum value - * @type {number} - */ + /** Deviation maximum value */ deviationMax: number; } diff --git a/x-pack/packages/ml/creation_wizard_utils/README.md b/x-pack/packages/ml/creation_wizard_utils/README.md new file mode 100644 index 000000000000..b638cc6f85ca --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/README.md @@ -0,0 +1,3 @@ +# @kbn/ml-creation-wizard-utils + +Utilities and components shared across creation wizards in plugins owned by the @elastic/ml-ui team. diff --git a/x-pack/packages/ml/creation_wizard_utils/components/destination_index_form.tsx b/x-pack/packages/ml/creation_wizard_utils/components/destination_index_form.tsx new file mode 100644 index 000000000000..057969112a61 --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/components/destination_index_form.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiFieldText, EuiFormRow, EuiLink } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { UseIdAsIndexNameSwitch } from './use_id_as_index_name_switch'; + +interface DestinationIndexFormProps { + createIndexLink: string; + destinationIndex: string; + destinationIndexNameEmpty: boolean; + destinationIndexNameExists: boolean; + destinationIndexNameValid: boolean; + destIndexSameAsId: boolean; + fullWidth?: boolean; + indexNameExistsMessage: string; + isJobCreated: boolean; + onDestinationIndexChange: (d: string) => void; + setDestIndexSameAsId: (d: boolean) => void; + switchLabel: string; +} + +export const DestinationIndexForm: FC = ({ + createIndexLink, + destinationIndex, + destinationIndexNameEmpty, + destinationIndexNameExists, + destinationIndexNameValid, + destIndexSameAsId, + fullWidth = true, + indexNameExistsMessage, + isJobCreated, + onDestinationIndexChange, + setDestIndexSameAsId, + switchLabel, +}) => ( + <> + + + + {destIndexSameAsId === false && ( + + {i18n.translate('xpack.ml.creationWizardUtils.destinationIndexInvalidError', { + defaultMessage: 'Invalid destination index name.', + })} +
    + + {i18n.translate('xpack.ml.creationWizardUtils.destinationIndexInvalidErrorLink', { + defaultMessage: 'Learn more about index name limitations.', + })} + + , + ] + } + > + onDestinationIndexChange(e.target.value)} + aria-label={i18n.translate( + 'xpack.ml.creationWizardUtils.destinationIndexInputAriaLabel', + { + defaultMessage: 'Choose a unique destination index name.', + } + )} + isInvalid={!destinationIndexNameEmpty && !destinationIndexNameValid} + data-test-subj="mlCreationWizardUtilsDestinationIndexInput" + /> +
    + )} + +); diff --git a/x-pack/packages/ml/creation_wizard_utils/components/use_id_as_index_name_switch.tsx b/x-pack/packages/ml/creation_wizard_utils/components/use_id_as_index_name_switch.tsx new file mode 100644 index 000000000000..1191ffec5501 --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/components/use_id_as_index_name_switch.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiSwitch } from '@elastic/eui'; + +interface UseIdAsIndexNameSwitchProps { + destIndexSameAsId: boolean; + isJobCreated: boolean; + setDestIndexSameAsId: (d: boolean) => void; + label: string; +} + +export const UseIdAsIndexNameSwitch: FC = ({ + destIndexSameAsId, + isJobCreated, + setDestIndexSameAsId, + label, +}) => ( + setDestIndexSameAsId(!destIndexSameAsId)} + data-test-subj="mlCreationWizardUtilsJobIdAsDestIndexNameSwitch" + /> +); diff --git a/x-pack/packages/ml/creation_wizard_utils/jest.config.js b/x-pack/packages/ml/creation_wizard_utils/jest.config.js new file mode 100644 index 000000000000..04abfa6eec19 --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/creation_wizard_utils'], +}; diff --git a/x-pack/packages/ml/creation_wizard_utils/kibana.jsonc b/x-pack/packages/ml/creation_wizard_utils/kibana.jsonc new file mode 100644 index 000000000000..158d81188350 --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/ml-creation-wizard-utils", + "owner": "@elastic/ml-ui" +} diff --git a/x-pack/packages/ml/creation_wizard_utils/package.json b/x-pack/packages/ml/creation_wizard_utils/package.json new file mode 100644 index 000000000000..c48eab9641bd --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ml-creation-wizard-utils", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/ml/creation_wizard_utils/tsconfig.json b/x-pack/packages/ml/creation_wizard_utils/tsconfig.json new file mode 100644 index 000000000000..df10dcf5b4b5 --- /dev/null +++ b/x-pack/packages/ml/creation_wizard_utils/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/i18n", + ] +} diff --git a/x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts b/x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts index 16c07a57e2c9..3b2e540730fa 100644 --- a/x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts +++ b/x-pack/packages/ml/data_frame_analytics_utils/src/constants.ts @@ -36,6 +36,7 @@ export const DEFAULT_RESULTS_FIELD = 'ml'; */ export const JOB_MAP_NODE_TYPES = { ANALYTICS: 'analytics', + ANALYTICS_JOB_MISSING: 'analytics-job-missing', TRANSFORM: 'transform', INDEX: 'index', TRAINED_MODEL: 'trainedModel', diff --git a/x-pack/packages/ml/data_grid/index.ts b/x-pack/packages/ml/data_grid/index.ts index 129feadb00ca..49468ce79c51 100644 --- a/x-pack/packages/ml/data_grid/index.ts +++ b/x-pack/packages/ml/data_grid/index.ts @@ -10,7 +10,7 @@ export { getDataGridSchemaFromESFieldType, getDataGridSchemaFromKibanaFieldType, getFeatureImportance, - getFieldsFromKibanaIndexPattern, + getFieldsFromKibanaDataView, getNestedOrEscapedVal, getProcessedFields, getTopClasses, diff --git a/x-pack/packages/ml/data_grid/lib/common.ts b/x-pack/packages/ml/data_grid/lib/common.ts index 3b6e8dc4dad6..84dc4591d9a1 100644 --- a/x-pack/packages/ml/data_grid/lib/common.ts +++ b/x-pack/packages/ml/data_grid/lib/common.ts @@ -83,7 +83,7 @@ export const euiDataGridToolbarSettings = { * @param {DataView} dataView - The Kibana data view. * @returns {string[]} - The array of field names from the data view. */ -export const getFieldsFromKibanaIndexPattern = (dataView: DataView): string[] => { +export const getFieldsFromKibanaDataView = (dataView: DataView): string[] => { const allFields = dataView.fields.map((f) => f.name); const dataViewFields: string[] = allFields.filter((f) => { if (dataView.metaFields.includes(f)) { diff --git a/x-pack/packages/ml/data_grid/lib/types.ts b/x-pack/packages/ml/data_grid/lib/types.ts index 2c1ab284d1c2..2d8ed5319237 100644 --- a/x-pack/packages/ml/data_grid/lib/types.ts +++ b/x-pack/packages/ml/data_grid/lib/types.ts @@ -158,9 +158,9 @@ export interface UseIndexDataReturnType */ renderCellValue: RenderCellValue; /** - * Optional index pattern fields. + * Optional data view fields. */ - indexPatternFields?: string[]; + dataViewFields?: string[]; /** * Optional time range. */ diff --git a/x-pack/packages/ml/data_view_utils/README.md b/x-pack/packages/ml/data_view_utils/README.md new file mode 100644 index 000000000000..33b0a8bae4f8 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/README.md @@ -0,0 +1,3 @@ +# @kbn/ml-data-view-utils + +Utilities for handling data views in plugins owned by the @elastic/ml-ui team. diff --git a/x-pack/packages/ml/data_view_utils/actions/create.ts b/x-pack/packages/ml/data_view_utils/actions/create.ts new file mode 100644 index 000000000000..56d6acbeb0d2 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/actions/create.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataViewsService, RuntimeField } from '@kbn/data-views-plugin/common'; + +import type { CreateDataViewApiResponseSchema } from '../types/api_create_response_schema'; + +interface CreateDataViewFnOptions { + dataViewsService: DataViewsService; + dataViewName: string; + runtimeMappings: Record; + timeFieldName?: string; + errorFallbackId: string; +} + +export const createDataViewFn = async ({ + dataViewsService, + dataViewName, + runtimeMappings, + timeFieldName, + // A fall back id to be able to track the response + // because in case of an error we don't get a data view id. + errorFallbackId, +}: CreateDataViewFnOptions): Promise => { + const response: CreateDataViewApiResponseSchema = { + dataViewsCreated: [], + dataViewsErrors: [], + }; + + try { + const dataViewsResp = await dataViewsService.createAndSave( + { + title: dataViewName, + timeFieldName, + runtimeFieldMap: runtimeMappings, + allowNoIndex: true, + }, + false, + true + ); + + if (dataViewsResp.id) { + response.dataViewsCreated = [{ id: dataViewsResp.id }]; + } + } catch (error) { + response.dataViewsErrors = [{ id: errorFallbackId, error }]; + } + + return response; +}; diff --git a/x-pack/packages/ml/data_view_utils/actions/data_view_handler.ts b/x-pack/packages/ml/data_view_utils/actions/data_view_handler.ts new file mode 100644 index 000000000000..97ec5cbf9766 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/actions/data_view_handler.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataViewsService } from '@kbn/data-views-plugin/common'; + +export class DataViewHandler { + constructor(private dataViewService: DataViewsService) {} + // returns a id based on an data view name + async getDataViewId(indexName: string) { + const dv = (await this.dataViewService.find(indexName)).find( + ({ title }) => title === indexName + ); + return dv?.id; + } + + async deleteDataViewById(dataViewId: string) { + return await this.dataViewService.delete(dataViewId); + } +} diff --git a/x-pack/packages/ml/data_view_utils/actions/delete.ts b/x-pack/packages/ml/data_view_utils/actions/delete.ts new file mode 100644 index 000000000000..3ae6429d3c12 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/actions/delete.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataViewsService } from '@kbn/data-views-plugin/common'; + +import type { DeleteDataViewApiResponseSchema } from '../types/api_delete_response_schema'; + +import { DataViewHandler } from './data_view_handler'; + +async function getDataViewId(dataViewsService: DataViewsService, patternName: string) { + const iph = new DataViewHandler(dataViewsService); + return await iph.getDataViewId(patternName); +} + +async function deleteDestDataViewById(dataViewsService: DataViewsService, dataViewId: string) { + const iph = new DataViewHandler(dataViewsService); + return await iph.deleteDataViewById(dataViewId); +} + +interface DeleteDataViewFnOptions { + dataViewsService: DataViewsService; + dataViewName: string; +} + +export const deleteDataViewFn = async ({ + dataViewsService, + dataViewName, +}: DeleteDataViewFnOptions): Promise => { + const response: DeleteDataViewApiResponseSchema = { + success: false, + }; + + try { + const dataViewId = await getDataViewId(dataViewsService, dataViewName); + if (dataViewId) { + await deleteDestDataViewById(dataViewsService, dataViewId); + } + response.success = true; + } catch (deleteDestDataViewError) { + response.error = deleteDestDataViewError; + } + + return response; +}; diff --git a/x-pack/packages/ml/data_view_utils/components/create_data_view_form_row.tsx b/x-pack/packages/ml/data_view_utils/components/create_data_view_form_row.tsx new file mode 100644 index 000000000000..b252fc028b52 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/components/create_data_view_form_row.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiFormRow, EuiText } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { CreateDataViewSwitch } from './create_data_view_switch'; +import { CreateDataViewTimeField } from './create_data_view_time_field'; + +interface CreateDataViewFormProps { + canCreateDataView: boolean; + createDataView: boolean; + dataViewTitleExists: boolean; + setCreateDataView: (d: boolean) => void; + dataViewAvailableTimeFields: string[]; + dataViewTimeField: string | undefined; + onTimeFieldChanged: (e: React.ChangeEvent) => void; +} + +export const CreateDataViewForm: FC = ({ + canCreateDataView, + createDataView, + dataViewTitleExists, + setCreateDataView, + dataViewAvailableTimeFields, + dataViewTimeField, + onTimeFieldChanged, +}) => ( + <> + + {i18n.translate('xpack.ml.dataViewUtils.dataViewPermissionWarning', { + defaultMessage: 'You need permission to create data views.', + })} + , + ] + : []), + ...(createDataView && dataViewTitleExists + ? [ + i18n.translate('xpack.ml.dataViewUtils.dataViewTitleError', { + defaultMessage: 'A data view with this title already exists.', + }), + ] + : []), + ]} + > + + + {createDataView && !dataViewTitleExists && dataViewAvailableTimeFields.length > 0 && ( + + )} + +); diff --git a/x-pack/packages/ml/data_view_utils/components/create_data_view_switch.tsx b/x-pack/packages/ml/data_view_utils/components/create_data_view_switch.tsx new file mode 100644 index 000000000000..9cef002fa974 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/components/create_data_view_switch.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiSwitch } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +interface CreateDataViewSwitchProps { + canCreateDataView: boolean; + createDataView: boolean; + setCreateDataView: (d: boolean) => void; +} + +export const CreateDataViewSwitch: FC = ({ + canCreateDataView, + createDataView, + setCreateDataView, +}) => ( + setCreateDataView(!createDataView)} + data-test-subj="mlCreateDataViewSwitch" + /> +); diff --git a/x-pack/packages/ml/data_view_utils/components/create_data_view_time_field.tsx b/x-pack/packages/ml/data_view_utils/components/create_data_view_time_field.tsx new file mode 100644 index 000000000000..c86056ffa69c --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/components/create_data_view_time_field.tsx @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; + +interface CreateDataViewTimeFieldProps { + dataViewAvailableTimeFields: string[]; + dataViewTimeField: string | undefined; + onTimeFieldChanged: (e: React.ChangeEvent) => void; +} + +export const CreateDataViewTimeField: FC = ({ + dataViewAvailableTimeFields, + dataViewTimeField, + onTimeFieldChanged, +}) => { + const noTimeFieldLabel = i18n.translate('xpack.ml.dataViewUtils.noTimeFieldOptionLabel', { + defaultMessage: "I don't want to use the time field option", + }); + + const noTimeFieldOption = { + text: noTimeFieldLabel, + value: undefined, + }; + + const disabledDividerOption = { + disabled: true, + text: '───', + value: '', + }; + + return ( + + } + helpText={ + + } + > + ({ text })), + disabledDividerOption, + noTimeFieldOption, + ]} + value={dataViewTimeField} + onChange={onTimeFieldChanged} + data-test-subj="mlDataViewTimeFieldSelect" + /> + + ); +}; diff --git a/x-pack/packages/ml/data_view_utils/jest.config.js b/x-pack/packages/ml/data_view_utils/jest.config.js new file mode 100644 index 000000000000..783a52cc9f53 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/data_view_utils'], +}; diff --git a/x-pack/packages/ml/data_view_utils/kibana.jsonc b/x-pack/packages/ml/data_view_utils/kibana.jsonc new file mode 100644 index 000000000000..41251d1f7cbc --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/ml-data-view-utils", + "owner": "@elastic/ml-ui" +} diff --git a/x-pack/packages/ml/data_view_utils/package.json b/x-pack/packages/ml/data_view_utils/package.json new file mode 100644 index 000000000000..c7bbac173415 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ml-data-view-utils", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/ml/data_view_utils/schemas/api_create_query_schema.ts b/x-pack/packages/ml/data_view_utils/schemas/api_create_query_schema.ts new file mode 100644 index 000000000000..b0884b1a65f5 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/schemas/api_create_query_schema.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, type TypeOf } from '@kbn/config-schema'; + +export const dataViewCreateQuerySchema = schema.object({ + createDataView: schema.boolean({ defaultValue: false }), + timeFieldName: schema.maybe(schema.string()), +}); + +export type DataViewCreateQuerySchema = TypeOf; diff --git a/x-pack/packages/ml/data_view_utils/tsconfig.json b/x-pack/packages/ml/data_view_utils/tsconfig.json new file mode 100644 index 000000000000..957b027bc2f2 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/data-views-plugin", + "@kbn/config-schema", + "@kbn/ml-error-utils", + "@kbn/i18n", + "@kbn/i18n-react", + ] +} diff --git a/x-pack/packages/ml/data_view_utils/types/api_create_response_schema.ts b/x-pack/packages/ml/data_view_utils/types/api_create_response_schema.ts new file mode 100644 index 000000000000..5b752cd89e57 --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/types/api_create_response_schema.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +interface DataViewCreated { + id: string; +} + +interface DataViewError { + id: string; + error: any; +} + +export interface CreateDataViewApiResponseSchema { + dataViewsCreated: DataViewCreated[]; + dataViewsErrors: DataViewError[]; +} diff --git a/x-pack/packages/ml/data_view_utils/types/api_delete_response_schema.ts b/x-pack/packages/ml/data_view_utils/types/api_delete_response_schema.ts new file mode 100644 index 000000000000..2d1ee4ee0abd --- /dev/null +++ b/x-pack/packages/ml/data_view_utils/types/api_delete_response_schema.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import Boom from '@hapi/boom'; + +import { EsErrorBody } from '@kbn/ml-error-utils'; + +/** + * Interface for data view API response for deletion status + */ +export interface DeleteDataViewApiResponseSchema { + /** + * Success + */ + success: boolean; + /** + * Optional error + */ + error?: EsErrorBody | Boom.Boom; +} diff --git a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx index 5b2a9d880c1b..cb890172bbdd 100644 --- a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx +++ b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx @@ -7,7 +7,7 @@ import React, { FC, useCallback, useMemo, useState } from 'react'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { EuiButton, diff --git a/x-pack/packages/ml/date_picker/src/services/full_time_range_selector_service.ts b/x-pack/packages/ml/date_picker/src/services/full_time_range_selector_service.ts index cfd363e8b53c..c4cdd23995ae 100644 --- a/x-pack/packages/ml/date_picker/src/services/full_time_range_selector_service.ts +++ b/x-pack/packages/ml/date_picker/src/services/full_time_range_selector_service.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import type { TimefilterContract } from '@kbn/data-plugin/public'; import dateMath from '@kbn/datemath'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { i18n } from '@kbn/i18n'; import type { ToastsStart, HttpStart } from '@kbn/core/public'; import type { DataView } from '@kbn/data-views-plugin/public'; diff --git a/x-pack/packages/ml/date_picker/src/services/time_field_range.ts b/x-pack/packages/ml/date_picker/src/services/time_field_range.ts index 07a5fb3de355..92d71f582a1e 100644 --- a/x-pack/packages/ml/date_picker/src/services/time_field_range.ts +++ b/x-pack/packages/ml/date_picker/src/services/time_field_range.ts @@ -6,7 +6,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import type { HttpStart } from '@kbn/core/public'; diff --git a/x-pack/packages/ml/query_utils/src/add_exclude_frozen_to_query.ts b/x-pack/packages/ml/query_utils/src/add_exclude_frozen_to_query.ts index 716254603496..3148e93bed02 100644 --- a/x-pack/packages/ml/query_utils/src/add_exclude_frozen_to_query.ts +++ b/x-pack/packages/ml/query_utils/src/add_exclude_frozen_to_query.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { cloneDeep } from 'lodash'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; diff --git a/x-pack/packages/ml/trained_models_utils/index.ts b/x-pack/packages/ml/trained_models_utils/index.ts index 0ae43c5ef401..b9ad2e2ae4d4 100644 --- a/x-pack/packages/ml/trained_models_utils/index.ts +++ b/x-pack/packages/ml/trained_models_utils/index.ts @@ -19,7 +19,8 @@ export { type ModelDefinition, type ModelDefinitionResponse, type ElserVersion, - type GetElserOptions, + type GetModelDownloadConfigOptions, + type ElasticCuratedModelName, ELSER_ID_V1, ELASTIC_MODEL_TAG, ELASTIC_MODEL_TYPE, diff --git a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts index 82258f4ef987..10e6618672f4 100644 --- a/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts +++ b/x-pack/packages/ml/trained_models_utils/src/constants/trained_models.ts @@ -61,6 +61,7 @@ export const ELASTIC_MODEL_DEFINITIONS: Record = Object description: i18n.translate('xpack.ml.trainedModels.modelsList.elserDescription', { defaultMessage: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)', }), + type: ['elastic', 'pytorch', 'text_expansion'], }, '.elser_model_2': { modelName: 'elser', @@ -74,6 +75,7 @@ export const ELASTIC_MODEL_DEFINITIONS: Record = Object description: i18n.translate('xpack.ml.trainedModels.modelsList.elserV2Description', { defaultMessage: 'Elastic Learned Sparse EncodeR v2', }), + type: ['elastic', 'pytorch', 'text_expansion'], }, '.elser_model_2_linux-x86_64': { modelName: 'elser', @@ -88,12 +90,53 @@ export const ELASTIC_MODEL_DEFINITIONS: Record = Object description: i18n.translate('xpack.ml.trainedModels.modelsList.elserV2x86Description', { defaultMessage: 'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64', }), + type: ['elastic', 'pytorch', 'text_expansion'], + }, + '.multilingual-e5-small': { + modelName: 'e5', + version: 1, + default: true, + config: { + input: { + field_names: ['text_field'], + }, + }, + description: i18n.translate('xpack.ml.trainedModels.modelsList.e5v1Description', { + defaultMessage: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + }), + license: 'MIT', + type: ['pytorch', 'text_embedding'], + }, + '.multilingual-e5-small_linux-x86_64': { + modelName: 'e5', + version: 1, + os: 'Linux', + arch: 'amd64', + config: { + input: { + field_names: ['text_field'], + }, + }, + description: i18n.translate('xpack.ml.trainedModels.modelsList.e5v1x86Description', { + defaultMessage: + 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + }), + license: 'MIT', + type: ['pytorch', 'text_embedding'], }, } as const); +export type ElasticCuratedModelName = 'elser' | 'e5'; + export interface ModelDefinition { - modelName: string; + /** + * Model name, e.g. elser + */ + modelName: ElasticCuratedModelName; version: number; + /** + * Default PUT model configuration + */ config: object; description: string; os?: string; @@ -101,10 +144,15 @@ export interface ModelDefinition { default?: boolean; recommended?: boolean; hidden?: boolean; + license?: string; + type?: readonly string[]; } -export type ModelDefinitionResponse = Omit & { - name: string; +export type ModelDefinitionResponse = ModelDefinition & { + /** + * Complete model id, e.g. .elser_model_2_linux-x86_64 + */ + model_id: string; }; export type ElasticModelId = keyof typeof ELASTIC_MODEL_DEFINITIONS; @@ -120,6 +168,6 @@ export type ModelState = typeof MODEL_STATE[keyof typeof MODEL_STATE] | null; export type ElserVersion = 1 | 2; -export interface GetElserOptions { +export interface GetModelDownloadConfigOptions { version?: ElserVersion; } diff --git a/x-pack/packages/ml/ui_actions/README.md b/x-pack/packages/ml/ui_actions/README.md new file mode 100644 index 000000000000..a9cba4a278c8 --- /dev/null +++ b/x-pack/packages/ml/ui_actions/README.md @@ -0,0 +1,3 @@ +# @kbn/ml-ui-actions + +Empty package generated by @kbn/generate diff --git a/x-pack/packages/ml/ui_actions/index.ts b/x-pack/packages/ml/ui_actions/index.ts new file mode 100644 index 000000000000..7a82ca6d68d9 --- /dev/null +++ b/x-pack/packages/ml/ui_actions/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION, + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER, + type CreateCategorizationADJobContext, +} from './src/ml/ui_actions'; + +export { + ACTION_CATEGORIZE_FIELD, + CATEGORIZE_FIELD_TRIGGER, + categorizeFieldTrigger, + type CategorizeFieldContext, +} from './src/aiops/ui_actions'; diff --git a/x-pack/packages/ml/ui_actions/jest.config.js b/x-pack/packages/ml/ui_actions/jest.config.js new file mode 100644 index 000000000000..8efadb42705f --- /dev/null +++ b/x-pack/packages/ml/ui_actions/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/ui_actions'], +}; diff --git a/x-pack/packages/ml/ui_actions/kibana.jsonc b/x-pack/packages/ml/ui_actions/kibana.jsonc new file mode 100644 index 000000000000..999f955bc2e4 --- /dev/null +++ b/x-pack/packages/ml/ui_actions/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/ml-ui-actions", + "owner": "@elastic/ml-ui" +} diff --git a/x-pack/packages/ml/ui_actions/package.json b/x-pack/packages/ml/ui_actions/package.json new file mode 100644 index 000000000000..a3d77f4701c6 --- /dev/null +++ b/x-pack/packages/ml/ui_actions/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ml-ui-actions", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts b/x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts new file mode 100644 index 000000000000..b5e9ca07031b --- /dev/null +++ b/x-pack/packages/ml/ui_actions/src/aiops/ui_actions.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; +import type { Trigger } from '@kbn/ui-actions-plugin/public'; + +export interface CategorizeFieldContext { + field: DataViewField; + dataView: DataView; + originatingApp: string; + additionalFilter?: { + from: number; + to: number; + field?: { name: string; value: string }; + }; +} + +export const ACTION_CATEGORIZE_FIELD = 'ACTION_CATEGORIZE_FIELD'; + +export const CATEGORIZE_FIELD_TRIGGER = 'CATEGORIZE_FIELD_TRIGGER'; +export const categorizeFieldTrigger: Trigger = { + id: CATEGORIZE_FIELD_TRIGGER, + title: i18n.translate('xpack.ml.actions.runPatternAnalysis.title', { + defaultMessage: 'Run pattern analysis', + }), + description: i18n.translate('xpack.ml.actions.runPatternAnalysis.description', { + defaultMessage: 'Triggered when user wants to run pattern analysis on a field.', + }), +}; diff --git a/x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts b/x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts new file mode 100644 index 000000000000..cf36e3ff01ce --- /dev/null +++ b/x-pack/packages/ml/ui_actions/src/ml/ui_actions.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import type { TimeRange } from '@kbn/es-query'; + +export interface CreateCategorizationADJobContext { + field: DataViewField; + dataView: DataView; + query: QueryDslQueryContainer; + timeRange: TimeRange; +} + +export const CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION = 'createMLADCategorizationJobAction'; + +export const CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER = + 'CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER'; diff --git a/x-pack/packages/ml/ui_actions/tsconfig.json b/x-pack/packages/ml/ui_actions/tsconfig.json new file mode 100644 index 000000000000..ca3f66082b5c --- /dev/null +++ b/x-pack/packages/ml/ui_actions/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/data-views-plugin", + "@kbn/es-query", + "@kbn/ui-actions-plugin", + "@kbn/i18n", + ] +} diff --git a/x-pack/packages/observability/alert_details/index.ts b/x-pack/packages/observability/alert_details/index.ts index 6f0200e9bf72..b90173ddf136 100644 --- a/x-pack/packages/observability/alert_details/index.ts +++ b/x-pack/packages/observability/alert_details/index.ts @@ -9,5 +9,4 @@ export { AlertAnnotation } from './src/components/alert_annotation'; export { AlertActiveTimeRangeAnnotation } from './src/components/alert_active_time_range_annotation'; export { AlertThresholdTimeRangeRect } from './src/components/alert_threshold_time_range_rect'; export { AlertThresholdAnnotation } from './src/components/alert_threshold_annotation'; -export { getPaddedAlertTimeRange } from './src/helpers/get_padded_alert_time_range'; export { useAlertsHistory } from './src/hooks/use_alerts_history'; diff --git a/x-pack/packages/observability/alert_details/package.json b/x-pack/packages/observability/alert_details/package.json index 3baee7af3443..2764095b1074 100644 --- a/x-pack/packages/observability/alert_details/package.json +++ b/x-pack/packages/observability/alert_details/package.json @@ -1,7 +1,6 @@ { "name": "@kbn/observability-alert-details", "descriptio": "Helper and components related to alert details", - "author": "Actionable Observability", "private": true, "version": "1.0.0", "license": "Elastic License 2.0" diff --git a/x-pack/packages/observability/alerting_test_data/src/create_custom_threshold_rule.ts b/x-pack/packages/observability/alerting_test_data/src/create_custom_threshold_rule.ts index 9c7e1fb6acdb..7ad732af3694 100644 --- a/x-pack/packages/observability/alerting_test_data/src/create_custom_threshold_rule.ts +++ b/x-pack/packages/observability/alerting_test_data/src/create_custom_threshold_rule.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -39,7 +38,6 @@ export const createCustomThresholdRule = async ( params: { criteria: ruleParams.params?.criteria || [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [1], timeSize: 1, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count.ts index c2515cfe1615..be2f2e344d7a 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario1 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.LT, threshold: [100], timeSize: 1, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_groupby.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_groupby.ts index 68786ea4a06d..fe8e2cfa01d3 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_groupby.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_groupby.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario2 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.LT, threshold: [40], timeSize: 1, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_nodata.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_nodata.ts index 97585a66b838..bbb4d4e1c255 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_nodata.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_log_count_nodata.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario3 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.LT, threshold: [5], timeSize: 1, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg.ts index 0feec99ca5a4..dcf6048915eb 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario4 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [80], timeSize: 1, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_groupby.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_groupby.ts index a36bb4af2544..b42006a33a65 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_groupby.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_groupby.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario5 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [80], timeSize: 5, diff --git a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_nodata.ts b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_nodata.ts index 16639c7749ca..9bea0a00eb71 100644 --- a/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_nodata.ts +++ b/x-pack/packages/observability/alerting_test_data/src/scenarios/custom_threshold_metric_avg_nodata.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -23,7 +22,6 @@ export const scenario6 = { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.LT, threshold: [1], timeSize: 1, diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/README.md b/x-pack/packages/observability/get_padded_alert_time_range_util/README.md new file mode 100644 index 000000000000..049cd022eb92 --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/README.md @@ -0,0 +1,3 @@ +# @kbn/get-padded-alert-time-range-util + +A utility to get padded alert time range based on alert's start and end time \ No newline at end of file diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/index.ts b/x-pack/packages/observability/get_padded_alert_time_range_util/index.ts new file mode 100644 index 000000000000..ea4c87b42729 --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getPaddedAlertTimeRange } from './src/get_padded_alert_time_range'; diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/jest.config.js b/x-pack/packages/observability/get_padded_alert_time_range_util/jest.config.js new file mode 100644 index 000000000000..2e476b09b3c4 --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/observability/get_padded_alert_time_range_util'], +}; diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/kibana.jsonc b/x-pack/packages/observability/get_padded_alert_time_range_util/kibana.jsonc new file mode 100644 index 000000000000..30797d6915c4 --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/observability-get-padded-alert-time-range-util", + "owner": "@elastic/obs-ux-management-team" +} diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/package.json b/x-pack/packages/observability/get_padded_alert_time_range_util/package.json new file mode 100644 index 000000000000..055cae3211ce --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/observability-get-padded-alert-time-range-util", + "descriptio": "An util to get padded alert time range", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.test.ts b/x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.test.ts similarity index 100% rename from x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.test.ts rename to x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.test.ts diff --git a/x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.ts b/x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.ts similarity index 100% rename from x-pack/packages/observability/alert_details/src/helpers/get_padded_alert_time_range.ts rename to x-pack/packages/observability/get_padded_alert_time_range_util/src/get_padded_alert_time_range.ts diff --git a/x-pack/packages/observability/get_padded_alert_time_range_util/tsconfig.json b/x-pack/packages/observability/get_padded_alert_time_range_util/tsconfig.json new file mode 100644 index 000000000000..0d78dace105e --- /dev/null +++ b/x-pack/packages/observability/get_padded_alert_time_range_util/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/x-pack/packages/security-solution/data_table/common/types/data_table/index.ts b/x-pack/packages/security-solution/data_table/common/types/data_table/index.ts index f86b3ecc98ee..e9625d39f269 100644 --- a/x-pack/packages/security-solution/data_table/common/types/data_table/index.ts +++ b/x-pack/packages/security-solution/data_table/common/types/data_table/index.ts @@ -31,6 +31,8 @@ export enum TableId { kubernetesPageSessions = 'kubernetes-page-sessions', alertsOnCasePage = 'alerts-case-page', alertsRiskInputs = 'alerts-risk-inputs', + // New version of `alertsRiskInputs` designed to support multiple kinds of risk inputs + riskInputs = 'risk-inputs', } export enum TableEntityType { @@ -52,6 +54,7 @@ export const tableEntity: Record = { [TableId.hostsPageSessions]: TableEntityType.session, [TableId.kubernetesPageSessions]: TableEntityType.session, [TableId.alertsRiskInputs]: TableEntityType.alert, + [TableId.riskInputs]: TableEntityType.alert, } as const; const TableIdLiteralRt = runtimeTypes.union([ diff --git a/x-pack/packages/security-solution/data_table/store/data_table/reducer.ts b/x-pack/packages/security-solution/data_table/store/data_table/reducer.ts index f65292a2919e..1ad08a933250 100644 --- a/x-pack/packages/security-solution/data_table/store/data_table/reducer.ts +++ b/x-pack/packages/security-solution/data_table/store/data_table/reducer.ts @@ -95,7 +95,7 @@ export const dataTableReducer = reducerWithInitialState(initialDataTableState) [action.id]: { ...state.tableById[action.id], expandedDetail: { - ...state.tableById[action.id].expandedDetail, + ...state.tableById[action.id]?.expandedDetail, ...updateTableDetailsPanel(action), }, }, diff --git a/x-pack/packages/security-solution/features/src/app_features_keys.ts b/x-pack/packages/security-solution/features/src/app_features_keys.ts index ab54c64cf899..ed8923cdb229 100644 --- a/x-pack/packages/security-solution/features/src/app_features_keys.ts +++ b/x-pack/packages/security-solution/features/src/app_features_keys.ts @@ -99,6 +99,7 @@ export enum SecuritySubFeatureId { /** Sub-features IDs for Cases */ export enum CasesSubFeatureId { deleteCases = 'deleteCasesSubFeature', + casesSettings = 'casesSettingsSubFeature', } /** Sub-features IDs for Security Assistant */ diff --git a/x-pack/packages/security-solution/features/src/cases/kibana_sub_features.ts b/x-pack/packages/security-solution/features/src/cases/kibana_sub_features.ts index 3cbdb3f0e912..1f49d01f979d 100644 --- a/x-pack/packages/security-solution/features/src/cases/kibana_sub_features.ts +++ b/x-pack/packages/security-solution/features/src/cases/kibana_sub_features.ts @@ -17,6 +17,7 @@ import type { CasesFeatureParams } from './types'; */ export const getCasesBaseKibanaSubFeatureIds = (): CasesSubFeatureId[] => [ CasesSubFeatureId.deleteCases, + CasesSubFeatureId.casesSettings, ]; /** @@ -60,7 +61,42 @@ export const getCasesSubFeaturesMap = ({ ], }; + const casesSettingsCasesSubFeature: SubFeatureConfig = { + name: i18n.translate( + 'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureName', + { + defaultMessage: 'Case Settings', + } + ), + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cases_settings', + name: i18n.translate( + 'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureDetails', + { + defaultMessage: 'Edit Case Settings', + } + ), + includeIn: 'all', + savedObject: { + all: [...savedObjects.files], + read: [...savedObjects.files], + }, + cases: { + settings: [APP_ID], + }, + ui: uiCapabilities.settings, + }, + ], + }, + ], + }; + return new Map([ [CasesSubFeatureId.deleteCases, deleteCasesSubFeature], + [CasesSubFeatureId.casesSettings, casesSettingsCasesSubFeature], ]); }; diff --git a/x-pack/packages/security-solution/upselling/messages/index.tsx b/x-pack/packages/security-solution/upselling/messages/index.tsx index 633f44d21b77..4933ff36cfa1 100644 --- a/x-pack/packages/security-solution/upselling/messages/index.tsx +++ b/x-pack/packages/security-solution/upselling/messages/index.tsx @@ -14,3 +14,11 @@ export const UPGRADE_INVESTIGATION_GUIDE = (requiredLicense: string) => requiredLicense, }, }); + +export const UPGRADE_ALERT_ASSIGNMENTS = (requiredLicense: string) => + i18n.translate('securitySolutionPackages.alertAssignments.upsell', { + defaultMessage: 'Upgrade to {requiredLicense} to make use of alert assignments', + values: { + requiredLicense, + }, + }); diff --git a/x-pack/packages/security-solution/upselling/service/types.ts b/x-pack/packages/security-solution/upselling/service/types.ts index d14f39ac9796..fdb66b27d97f 100644 --- a/x-pack/packages/security-solution/upselling/service/types.ts +++ b/x-pack/packages/security-solution/upselling/service/types.ts @@ -17,4 +17,4 @@ export type UpsellingSectionId = | 'osquery_automated_response_actions' | 'ruleDetailsEndpointExceptions'; -export type UpsellingMessageId = 'investigation_guide'; +export type UpsellingMessageId = 'investigation_guide' | 'alert_assignments'; diff --git a/x-pack/packages/security/plugin_types_common/README.md b/x-pack/packages/security/plugin_types_common/README.md new file mode 100644 index 000000000000..eb7fbaa4a316 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/README.md @@ -0,0 +1,4 @@ +# @kbn/security-plugin-types-common + +Contains type definitions for the Kibana Security plugin (common). + diff --git a/x-pack/packages/security/plugin_types_common/index.ts b/x-pack/packages/security/plugin_types_common/index.ts new file mode 100644 index 000000000000..c5771f698280 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + AuthenticatedUser, + UserRealm, + User, + AuthenticationProvider, +} from './src/authentication'; +export type { + Role, + RoleIndexPrivilege, + RoleKibanaPrivilege, + RoleRemoteIndexPrivilege, + FeaturesPrivileges, +} from './src/authorization'; +export type { SecurityLicense, SecurityLicenseFeatures, LoginLayout } from './src/licensing'; +export type { + UserProfileUserInfo, + UserProfileData, + UserProfileLabels, + UserProfile, + UserProfileWithSecurity, + UserProfileUserInfoWithSecurity, +} from './src/user_profile'; diff --git a/x-pack/packages/security/plugin_types_common/kibana.jsonc b/x-pack/packages/security/plugin_types_common/kibana.jsonc new file mode 100644 index 000000000000..714eb0f564cd --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/security-plugin-types-common", + "owner": "@elastic/kibana-security" +} diff --git a/x-pack/packages/security/plugin_types_common/package.json b/x-pack/packages/security/plugin_types_common/package.json new file mode 100644 index 000000000000..d28f1c03614d --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/security-plugin-types-common", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts b/x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts new file mode 100644 index 000000000000..ef58d6798297 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authentication/authenticated_user.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AuthenticationProvider } from './authentication_provider'; +import type { User } from './user'; + +/** + * An Elasticsearch realm that was used to resolve and authenticate the user. + */ +export interface UserRealm { + /** + * Arbitrary name of the security realm. + */ + name: string; + + /** + * Type of the security realm (file, native, saml etc.). + */ + type: string; +} + +/** + * Represents the currently authenticated user. + */ +export interface AuthenticatedUser extends User { + /** + * The name and type of the Realm that has authenticated the user. + */ + authentication_realm: UserRealm; + + /** + * The name and type of the Realm where the user information were retrieved from. + */ + lookup_realm: UserRealm; + + /** + * The authentication provider that used to authenticate user. + */ + authentication_provider: AuthenticationProvider; + + /** + * The AuthenticationType used by ES to authenticate the user. + * + * @example "realm" | "api_key" | "token" | "anonymous" | "internal" + */ + authentication_type: string; + + /** + * Indicates whether user is authenticated via Elastic Cloud built-in SAML realm. + */ + elastic_cloud_user: boolean; + + /** + * User profile ID of this user. + */ + profile_uid?: string; +} diff --git a/x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts b/x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts new file mode 100644 index 000000000000..92ec64d83db2 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authentication/authentication_provider.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Type and name tuple to identify provider used to authenticate user. + */ +export interface AuthenticationProvider { + /** + * Type of the Kibana authentication provider. + */ + type: string; + /** + * Name of the Kibana authentication provider (arbitrary string). + */ + name: string; +} diff --git a/x-pack/packages/security/plugin_types_common/src/authentication/index.ts b/x-pack/packages/security/plugin_types_common/src/authentication/index.ts new file mode 100644 index 000000000000..26b9873068c0 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authentication/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { AuthenticatedUser, UserRealm } from './authenticated_user'; +export type { User } from './user'; +export type { AuthenticationProvider } from './authentication_provider'; diff --git a/x-pack/packages/security/plugin_types_common/src/authentication/user.ts b/x-pack/packages/security/plugin_types_common/src/authentication/user.ts new file mode 100644 index 000000000000..17cd7cd100ca --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authentication/user.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * A set of fields describing Kibana user. + */ +export interface User { + username: string; + email?: string; + full_name?: string; + roles: readonly string[]; + enabled: boolean; + metadata?: { + _reserved: boolean; + _deprecated?: boolean; + _deprecated_reason?: string; + }; +} diff --git a/x-pack/plugins/security/common/model/features_privileges.ts b/x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts similarity index 100% rename from x-pack/plugins/security/common/model/features_privileges.ts rename to x-pack/packages/security/plugin_types_common/src/authorization/features_privileges.ts diff --git a/x-pack/packages/security/plugin_types_common/src/authorization/index.ts b/x-pack/packages/security/plugin_types_common/src/authorization/index.ts new file mode 100644 index 000000000000..29cb395ccfe4 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authorization/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { FeaturesPrivileges } from './features_privileges'; +export type { + Role, + RoleKibanaPrivilege, + RoleIndexPrivilege, + RoleRemoteIndexPrivilege, +} from './role'; diff --git a/x-pack/packages/security/plugin_types_common/src/authorization/role.ts b/x-pack/packages/security/plugin_types_common/src/authorization/role.ts new file mode 100644 index 000000000000..12fc0a85ff7a --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/authorization/role.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FeaturesPrivileges } from './features_privileges'; + +export interface RoleIndexPrivilege { + names: string[]; + privileges: string[]; + field_security?: { + grant?: string[]; + except?: string[]; + }; + query?: string; +} + +export interface RoleRemoteIndexPrivilege extends RoleIndexPrivilege { + clusters: string[]; +} + +export interface RoleKibanaPrivilege { + spaces: string[]; + base: string[]; + feature: FeaturesPrivileges; + _reserved?: string[]; +} + +export interface Role { + name: string; + elasticsearch: { + cluster: string[]; + indices: RoleIndexPrivilege[]; + remote_indices?: RoleRemoteIndexPrivilege[]; + run_as: string[]; + }; + kibana: RoleKibanaPrivilege[]; + metadata?: { + [anyKey: string]: any; + }; + transient_metadata?: { + [anyKey: string]: any; + }; + _transform_error?: string[]; + _unrecognized_applications?: string[]; +} diff --git a/x-pack/packages/security/plugin_types_common/src/licensing/index.ts b/x-pack/packages/security/plugin_types_common/src/licensing/index.ts new file mode 100644 index 000000000000..6fab9a2338fc --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/licensing/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { SecurityLicense } from './license'; +export type { LoginLayout, SecurityLicenseFeatures } from './license_features'; diff --git a/x-pack/packages/security/plugin_types_common/src/licensing/license.ts b/x-pack/packages/security/plugin_types_common/src/licensing/license.ts new file mode 100644 index 000000000000..041d76c0e874 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/licensing/license.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Observable } from 'rxjs'; + +import type { LicenseType } from '@kbn/licensing-plugin/common/types'; + +import type { SecurityLicenseFeatures } from './license_features'; + +export interface SecurityLicense { + isLicenseAvailable(): boolean; + isEnabled(): boolean; + getFeatures(): SecurityLicenseFeatures; + hasAtLeast(licenseType: LicenseType): boolean | undefined; + features$: Observable; +} diff --git a/x-pack/plugins/security/common/licensing/license_features.ts b/x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts similarity index 100% rename from x-pack/plugins/security/common/licensing/license_features.ts rename to x-pack/packages/security/plugin_types_common/src/licensing/license_features.ts diff --git a/x-pack/packages/security/plugin_types_common/src/user_profile/index.ts b/x-pack/packages/security/plugin_types_common/src/user_profile/index.ts new file mode 100644 index 000000000000..bffb7939c2fc --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/user_profile/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + UserProfileUserInfo, + UserProfileData, + UserProfileLabels, + UserProfileUserInfoWithSecurity, + UserProfile, + UserProfileWithSecurity, +} from './user_profile'; diff --git a/x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts b/x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts new file mode 100644 index 000000000000..13743974afea --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/src/user_profile/user_profile.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * IMPORTANT: + * + * The types in this file are duplicated at + * `packages/kbn-user-profile-components/src/user_profile.ts` + * + * When making changes please ensure to keep both files in sync. + */ + +/** + * Describes basic properties stored in user profile. + */ +export interface UserProfile { + /** + * Unique ID for of the user profile. + */ + uid: string; + + /** + * Indicates whether user profile is enabled or not. + */ + enabled: boolean; + + /** + * Information about the user that owns profile. + */ + user: UserProfileUserInfo; + + /** + * User specific data associated with the profile. + */ + data: Partial; +} + +/** + * Basic user information returned in user profile. + */ +export interface UserProfileUserInfo { + /** + * Username of the user. + */ + username: string; + /** + * Optional email of the user. + */ + email?: string; + /** + * Optional full name of the user. + */ + full_name?: string; +} + +/** + * Placeholder for data stored in user profile. + */ +export type UserProfileData = Record; + +/** + * Type of the user profile labels structure (currently + */ +export type UserProfileLabels = Record; + +/** + * Extended user information returned in user profile (both basic and security related properties). + */ +export interface UserProfileUserInfoWithSecurity extends UserProfileUserInfo { + /** + * List of the user roles. + */ + roles: readonly string[]; + /** + * Name of the Elasticsearch security realm that was used to authenticate user. + */ + realm_name: string; + /** + * Optional name of the security domain that Elasticsearch security realm that was + * used to authenticate user resides in (if any). + */ + realm_domain?: string; +} + +/** + * Describes all properties stored in user profile (both basic and security related properties). + */ +export interface UserProfileWithSecurity< + D extends UserProfileData = UserProfileData, + L extends UserProfileLabels = UserProfileLabels +> extends UserProfile { + /** + * Information about the user that owns profile. + */ + user: UserProfileUserInfoWithSecurity; + + /** + * User specific _searchable_ labels associated with the profile. Note that labels are considered + * security related field since it's going to be used to store user's space ID. + */ + labels: L; +} diff --git a/x-pack/packages/security/plugin_types_common/tsconfig.json b/x-pack/packages/security/plugin_types_common/tsconfig.json new file mode 100644 index 000000000000..74be218f1ec2 --- /dev/null +++ b/x-pack/packages/security/plugin_types_common/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/licensing-plugin" + ] +} diff --git a/x-pack/packages/security/plugin_types_public/README.md b/x-pack/packages/security/plugin_types_public/README.md new file mode 100644 index 000000000000..fdc0481d60b6 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/README.md @@ -0,0 +1,4 @@ +# @kbn/security-plugin-types-public + +Contains type definitions for the Kibana Security plugin (public). + diff --git a/x-pack/packages/security/plugin_types_public/index.ts b/x-pack/packages/security/plugin_types_public/index.ts new file mode 100644 index 000000000000..fc129909743e --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { AuthenticationServiceStart, AuthenticationServiceSetup } from './src/authentication'; +export type { UserMenuLink, SecurityNavControlServiceStart } from './src/nav_control'; +export type { SecurityPluginSetup, SecurityPluginStart } from './src/plugin'; +export type { + GetUserProfileResponse, + UserProfileGetCurrentParams, + UserProfileBulkGetParams, + UserProfileSuggestParams, + UserProfileAPIClient, +} from './src/user_profile'; diff --git a/x-pack/packages/security/plugin_types_public/kibana.jsonc b/x-pack/packages/security/plugin_types_public/kibana.jsonc new file mode 100644 index 000000000000..f4fbe8fe8ea7 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/security-plugin-types-public", + "owner": "@elastic/kibana-security" +} diff --git a/x-pack/packages/security/plugin_types_public/package.json b/x-pack/packages/security/plugin_types_public/package.json new file mode 100644 index 000000000000..58e244244058 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/security-plugin-types-public", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts b/x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.ts new file mode 100644 index 000000000000..a8fa8a6a64d2 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/authentication/authentication_service.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AuthenticatedUser } from '@kbn/security-plugin-types-common'; + +export interface AuthenticationServiceSetup { + /** + * Returns currently authenticated user and throws if current user isn't authenticated. + */ + getCurrentUser: () => Promise; + + /** + * Determines if API Keys are currently enabled. + */ + areAPIKeysEnabled: () => Promise; +} + +/** + * Start has the same contract as Setup for now. + */ +export type AuthenticationServiceStart = AuthenticationServiceSetup; diff --git a/x-pack/packages/security/plugin_types_public/src/authentication/index.ts b/x-pack/packages/security/plugin_types_public/src/authentication/index.ts new file mode 100644 index 000000000000..55a977e551e2 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/authentication/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + AuthenticationServiceSetup, + AuthenticationServiceStart, +} from './authentication_service'; diff --git a/x-pack/packages/security/plugin_types_public/src/nav_control/index.ts b/x-pack/packages/security/plugin_types_public/src/nav_control/index.ts new file mode 100644 index 000000000000..3250ac3c3ca7 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/nav_control/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { UserMenuLink, SecurityNavControlServiceStart } from './nav_control_service'; diff --git a/x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts b/x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts new file mode 100644 index 000000000000..39982a753127 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/nav_control/nav_control_service.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IconType } from '@elastic/eui'; +import type { ReactNode } from 'react'; +import type { Observable } from 'rxjs'; + +export interface UserMenuLink { + label: string; + iconType: IconType; + href: string; + order?: number; + setAsProfile?: boolean; + /** Render a custom ReactNode instead of the default */ + content?: ReactNode; +} + +export interface SecurityNavControlServiceStart { + /** + * Returns an Observable of the array of user menu links (the links that show up under the user's Avatar in the UI) registered by other plugins + */ + getUserMenuLinks$: () => Observable; + + /** + * Registers the provided user menu links to be displayed in the user menu (the links that show up under the user's Avatar in the UI). + */ + addUserMenuLinks: (newUserMenuLink: UserMenuLink[]) => void; +} diff --git a/x-pack/packages/security/plugin_types_public/src/plugin.ts b/x-pack/packages/security/plugin_types_public/src/plugin.ts new file mode 100644 index 000000000000..28c5822a2e13 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/plugin.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SecurityLicense } from '@kbn/security-plugin-types-common'; +import type { AuthenticationServiceSetup, AuthenticationServiceStart } from './authentication'; +import type { SecurityNavControlServiceStart } from './nav_control'; +import type { UserProfileAPIClient } from './user_profile'; + +export interface SecurityPluginSetup { + /** + * Exposes authentication information about the currently logged in user. + */ + authc: AuthenticationServiceSetup; + /** + * Exposes information about the available security features under the current license. + */ + license: SecurityLicense; +} + +export interface SecurityPluginStart { + /** + * Exposes the ability to add custom links to the dropdown menu in the top right, where the user's Avatar is. + */ + navControlService: SecurityNavControlServiceStart; + /** + * Exposes authentication information about the currently logged in user. + */ + authc: AuthenticationServiceStart; + /** + * A set of methods to work with Kibana user profiles. + */ + userProfiles: UserProfileAPIClient; +} diff --git a/x-pack/packages/security/plugin_types_public/src/user_profile/index.ts b/x-pack/packages/security/plugin_types_public/src/user_profile/index.ts new file mode 100644 index 000000000000..8840a7cee272 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/user_profile/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + GetUserProfileResponse, + UserProfileAPIClient, + UserProfileGetCurrentParams, + UserProfileBulkGetParams, + UserProfileSuggestParams, +} from './user_profile_api_client'; diff --git a/x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts b/x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts new file mode 100644 index 000000000000..090d5d5b0fcf --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/src/user_profile/user_profile_api_client.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + UserProfileData, + AuthenticatedUser, + UserProfileWithSecurity, + UserProfile, +} from '@kbn/security-plugin-types-common'; +import type { Observable } from 'rxjs'; + +export interface UserProfileAPIClient { + readonly userProfile$: Observable; + /** + * Retrieves the user profile of the current user. If the profile isn't available, e.g. for the anonymous users or + * users authenticated via authenticating proxies, the `null` value is returned. + * @param [params] Get current user profile operation parameters. + * @param params.dataPath By default `getCurrent()` returns user information, but does not return any user data. The + * optional "dataPath" parameter can be used to return personal data for this user. + */ + getCurrent( + params?: UserProfileGetCurrentParams + ): Promise>; + + /** + * Retrieves multiple user profiles by their identifiers. + * @param params Bulk get operation parameters. + * @param params.uids List of user profile identifiers. + * @param params.dataPath By default Elasticsearch returns user information, but does not return any user data. The + * optional "dataPath" parameter can be used to return personal data for the requested user profiles. + */ + bulkGet( + params: UserProfileBulkGetParams + ): Promise>>; + + /** + * Suggests multiple user profiles by search criteria. + * + * Note: This endpoint is not provided out-of-the-box by the platform. You need to expose your own + * version within your app. An example of how to do this can be found in: + * `examples/user_profile_examples/server/plugin.ts` + * + * @param path Path to your app's suggest endpoint. + * @param params Suggest operation parameters. + * @param params.name Query string used to match name-related fields in user profiles. The + * following fields are treated as name-related: username, full_name and email. + * @param params.size Desired number of suggestions to return. The default value is 10. + * @param params.dataPath By default, suggest API returns user information, but does not return + * any user data. The optional "dataPath" parameter can be used to return personal data for this + * user (within `kibana` namespace only). + */ + suggest( + path: string, + params: UserProfileSuggestParams + ): Promise>>; + + /** + * Updates user profile data of the current user. + * @param data Application data to be written (merged with existing data). + */ + update(data: D): Promise; +} + +/** + * Parameters for the get user profile for the current user API. + */ +export interface UserProfileGetCurrentParams { + /** + * By default, get API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath: string; +} + +export interface GetUserProfileResponse + extends UserProfileWithSecurity { + /** + * Information about the currently authenticated user that owns the profile. + */ + user: UserProfileWithSecurity['user'] & Pick; +} + +/** + * Parameters for the bulk get API. + */ +export interface UserProfileBulkGetParams { + /** + * List of user profile identifiers. + */ + uids: Set; + + /** + * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath?: string; +} + +/** + * Parameters for the suggest API. + */ +export interface UserProfileSuggestParams { + /** + * Query string used to match name-related fields in user profiles. The following fields are treated as + * name-related: username, full_name and email. + */ + name: string; + + /** + * Desired number of suggestions to return. The default value is 10. + */ + size?: number; + + /** + * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath?: string; +} diff --git a/x-pack/packages/security/plugin_types_public/tsconfig.json b/x-pack/packages/security/plugin_types_public/tsconfig.json new file mode 100644 index 000000000000..23e34902d2c1 --- /dev/null +++ b/x-pack/packages/security/plugin_types_public/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/security-plugin-types-common" + ] +} diff --git a/x-pack/packages/security/plugin_types_server/README.md b/x-pack/packages/security/plugin_types_server/README.md new file mode 100644 index 000000000000..91ac1d3b2d18 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/README.md @@ -0,0 +1,4 @@ +# @kbn/security-plugin-types-server + +Contains type definitions for the Kibana Security plugin (server). + diff --git a/x-pack/packages/security/plugin_types_server/index.ts b/x-pack/packages/security/plugin_types_server/index.ts new file mode 100644 index 000000000000..2d697dd0187a --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/index.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + AuditEvent, + AuditHttp, + AuditKibana, + AuditRequest, + AuditServiceSetup, + AuditLogger, +} from './src/audit'; +export type { + CreateAPIKeyParams, + CreateAPIKeyResult, + CreateRestAPIKeyParams, + GrantAPIKeyResult, + InvalidateAPIKeysParams, + ValidateAPIKeyParams, + CreateRestAPIKeyWithKibanaPrivilegesParams, + CreateCrossClusterAPIKeyParams, + InvalidateAPIKeyResult, + APIKeys, + AuthenticationServiceStart, +} from './src/authentication'; +export type { + PrivilegeDeprecationsService, + PrivilegeDeprecationsRolesByFeatureIdResponse, + PrivilegeDeprecationsRolesByFeatureIdRequest, + CheckPrivilegesResponse, + CheckPrivilegesWithRequest, + CheckSavedObjectsPrivilegesWithRequest, + CheckPrivilegesDynamicallyWithRequest, + KibanaPrivilegesType, + SavedObjectActions, + UIActions, + CheckPrivilegesPayload, + CheckSavedObjectsPrivileges, + HasPrivilegesResponse, + HasPrivilegesResponseApplication, + SpaceActions, + Actions, + CheckPrivilegesOptions, + CheckUserProfilesPrivilegesPayload, + CheckUserProfilesPrivilegesResponse, + ElasticsearchPrivilegesType, + CasesActions, + CheckPrivileges, + AlertingActions, + AppActions, + ApiActions, + CheckPrivilegesDynamically, + CheckUserProfilesPrivileges, + AuthorizationMode, + AuthorizationServiceSetup, +} from './src/authorization'; +export type { SecurityPluginSetup, SecurityPluginStart } from './src/plugin'; +export type { + UserProfileServiceStart, + UserProfileSuggestParams, + UserProfileGetCurrentParams, + UserProfileBulkGetParams, + UserProfileRequiredPrivileges, +} from './src/user_profile'; + +export { + restApiKeySchema, + getRestApiKeyWithKibanaPrivilegesSchema, + crossClusterApiKeySchema, +} from './src/authentication'; +export { GLOBAL_RESOURCE, elasticsearchRoleSchema, getKibanaRoleSchema } from './src/authorization'; diff --git a/x-pack/packages/security/plugin_types_server/kibana.jsonc b/x-pack/packages/security/plugin_types_server/kibana.jsonc new file mode 100644 index 000000000000..e4f4a074f6e7 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-server", + "id": "@kbn/security-plugin-types-server", + "owner": "@elastic/kibana-security" +} diff --git a/x-pack/packages/security/plugin_types_server/package.json b/x-pack/packages/security/plugin_types_server/package.json new file mode 100644 index 000000000000..da6a8b5eb0b0 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/security-plugin-types-server", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts b/x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts new file mode 100644 index 000000000000..f071a3edcd82 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/audit/audit_events.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LogMeta } from '@kbn/core/server'; + +/** + * Audit kibana schema using ECS format + */ +export interface AuditKibana { + /** + * The ID of the space associated with this event. + */ + space_id?: string; + /** + * The ID of the user session associated with this event. Each login attempt + * results in a unique session id. + */ + session_id?: string; + /** + * Saved object that was created, changed, deleted or accessed as part of this event. + */ + saved_object?: { + type: string; + id: string; + }; + /** + * Name of authentication provider associated with a login event. + */ + authentication_provider?: string; + /** + * Type of authentication provider associated with a login event. + */ + authentication_type?: string; + /** + * Name of Elasticsearch realm that has authenticated the user. + */ + authentication_realm?: string; + /** + * Name of Elasticsearch realm where the user details were retrieved from. + */ + lookup_realm?: string; + /** + * Set of space IDs that a saved object was shared to. + */ + add_to_spaces?: readonly string[]; + /** + * Set of space IDs that a saved object was removed from. + */ + delete_from_spaces?: readonly string[]; + /** + * Set of space IDs that are not authorized for an action. + */ + unauthorized_spaces?: readonly string[]; + /** + * Set of types that are not authorized for an action. + */ + unauthorized_types?: readonly string[]; +} + +type EcsHttp = Required['http']; +type EcsRequest = Required['request']; + +/** + * Audit request schema using ECS format + */ +export interface AuditRequest extends EcsRequest { + /** + * HTTP request headers + */ + headers?: { + 'x-forwarded-for'?: string; + }; +} + +/** + * Audit http schema using ECS format + */ +export interface AuditHttp extends EcsHttp { + /** + * HTTP request details + */ + request?: AuditRequest; +} + +/** + * Audit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.12/index.html + * + * If you add additional fields to the schema ensure you update the Kibana Filebeat module: + * https://github.com/elastic/beats/tree/master/filebeat/module/kibana + * + * @public + */ +export interface AuditEvent extends LogMeta { + /** + * Log message + */ + message: string; + + /** + * Kibana specific fields + */ + kibana?: AuditKibana; + + /** + * Fields describing an HTTP request + */ + http?: AuditHttp; +} diff --git a/x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts b/x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts new file mode 100644 index 000000000000..4670de3aa8d3 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/audit/audit_logger.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AuditEvent } from './audit_events'; + +export interface AuditLogger { + /** + * Logs an {@link AuditEvent} and automatically adds meta data about the + * current user, space and correlation id. + * + * Guidelines around what events should be logged and how they should be + * structured can be found in: `/x-pack/plugins/security/README.md` + * + * @example + * ```typescript + * const auditLogger = securitySetup.audit.asScoped(request); + * auditLogger.log({ + * message: 'User is updating dashboard [id=123]', + * event: { + * action: 'saved_object_update', + * outcome: 'unknown' + * }, + * kibana: { + * saved_object: { type: 'dashboard', id: '123' } + * }, + * }); + * ``` + */ + log: (event: AuditEvent | undefined) => void; + + /** + * Indicates whether audit logging is enabled or not. + * + * Useful for skipping resource-intense operations that don't need to be performed when audit + * logging is disabled. + */ + readonly enabled: boolean; +} diff --git a/x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts b/x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts new file mode 100644 index 000000000000..88b25b5181a4 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/audit/audit_service.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; + +import type { AuditLogger } from './audit_logger'; + +export interface AuditServiceSetup { + /** + * Creates an {@link AuditLogger} scoped to the current request. + * + * This audit logger logs events with all required user and session info and should be used for + * all user-initiated actions. + * + * @example + * ```typescript + * const auditLogger = securitySetup.audit.asScoped(request); + * auditLogger.log(event); + * ``` + */ + asScoped: (request: KibanaRequest) => AuditLogger; + + /** + * {@link AuditLogger} for background tasks only. + * + * This audit logger logs events without any user or session info and should never be used to log + * user-initiated actions. + * + * @example + * ```typescript + * securitySetup.audit.withoutRequest.log(event); + * ``` + */ + withoutRequest: AuditLogger; +} diff --git a/x-pack/packages/security/plugin_types_server/src/audit/index.ts b/x-pack/packages/security/plugin_types_server/src/audit/index.ts new file mode 100644 index 000000000000..0111172cd409 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/audit/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { AuditServiceSetup } from './audit_service'; +export type { AuditEvent, AuditHttp, AuditKibana, AuditRequest } from './audit_events'; +export type { AuditLogger } from './audit_logger'; diff --git a/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts new file mode 100644 index 000000000000..1cbf13a4ad45 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts @@ -0,0 +1,201 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { estypes } from '@elastic/elasticsearch'; + +import type { KibanaRequest } from '@kbn/core/server'; +import { schema, TypeOf } from '@kbn/config-schema'; +import { getKibanaRoleSchema, elasticsearchRoleSchema } from '../../authorization'; + +export interface APIKeys { + /** + * Determines if API Keys are enabled in Elasticsearch. + */ + areAPIKeysEnabled(): Promise; + + /** + * Determines if Cross-Cluster API Keys are enabled in Elasticsearch. + */ + areCrossClusterAPIKeysEnabled(): Promise; + + /** + * Tries to create an API key for the current user. + * + * Returns newly created API key or `null` if API keys are disabled. + * + * User needs `manage_api_key` privilege to create REST API keys and `manage_security` for Cross-Cluster API keys. + * + * @param request Request instance. + * @param createParams The params to create an API key + */ + create( + request: KibanaRequest, + createParams: CreateAPIKeyParams + ): Promise; + + /** + * Tries to grant an API key for the current user. + * @param request Request instance. + * @param createParams Create operation parameters. + */ + grantAsInternalUser( + request: KibanaRequest, + createParams: CreateRestAPIKeyParams | CreateRestAPIKeyWithKibanaPrivilegesParams + ): Promise; + + /** + * Tries to validate an API key. + * @param apiKeyPrams ValidateAPIKeyParams. + */ + validate(apiKeyPrams: ValidateAPIKeyParams): Promise; + + /** + * Tries to invalidate an API keys. + * @param request Request instance. + * @param params The params to invalidate an API keys. + */ + invalidate( + request: KibanaRequest, + params: InvalidateAPIKeysParams + ): Promise; + + /** + * Tries to invalidate the API keys by using the internal user. + * @param params The params to invalidate the API keys. + */ + invalidateAsInternalUser(params: InvalidateAPIKeysParams): Promise; +} + +export type CreateAPIKeyParams = + | CreateRestAPIKeyParams + | CreateRestAPIKeyWithKibanaPrivilegesParams + | CreateCrossClusterAPIKeyParams; + +/** + * Response of Kibana Create API key endpoint. + */ +export type CreateAPIKeyResult = estypes.SecurityCreateApiKeyResponse; + +export type CreateRestAPIKeyParams = TypeOf; +export type CreateRestAPIKeyWithKibanaPrivilegesParams = TypeOf< + ReturnType +>; +export type CreateCrossClusterAPIKeyParams = TypeOf; + +export interface GrantAPIKeyResult { + /** + * Unique id for this API key + */ + id: string; + /** + * Name for this API key + */ + name: string; + /** + * Generated API key + */ + api_key: string; +} + +/** + * Represents the parameters for validating API Key credentials. + */ +export interface ValidateAPIKeyParams { + /** + * Unique id for this API key + */ + id: string; + + /** + * Generated API Key (secret) + */ + api_key: string; +} + +/** + * Represents the params for invalidating multiple API keys + */ +export interface InvalidateAPIKeysParams { + ids: string[]; +} + +/** + * The return value when invalidating an API key in Elasticsearch. + */ +export interface InvalidateAPIKeyResult { + /** + * The IDs of the API keys that were invalidated as part of the request. + */ + invalidated_api_keys: string[]; + /** + * The IDs of the API keys that were already invalidated. + */ + previously_invalidated_api_keys: string[]; + /** + * The number of errors that were encountered when invalidating the API keys. + */ + error_count: number; + /** + * Details about these errors. This field is not present in the response when error_count is 0. + */ + error_details?: Array<{ + type?: string; + reason?: string; + caused_by?: { + type?: string; + reason?: string; + }; + }>; +} + +export const restApiKeySchema = schema.object({ + type: schema.maybe(schema.literal('rest')), + name: schema.string(), + expiration: schema.maybe(schema.string()), + role_descriptors: schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' }), { + defaultValue: {}, + }), + metadata: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}); + +export const getRestApiKeyWithKibanaPrivilegesSchema = ( + getBasePrivilegeNames: Parameters[0] +) => + restApiKeySchema.extends({ + role_descriptors: null, + kibana_role_descriptors: schema.recordOf( + schema.string(), + schema.object({ + elasticsearch: elasticsearchRoleSchema.extends({}, { unknowns: 'allow' }), + kibana: getKibanaRoleSchema(getBasePrivilegeNames), + }) + ), + }); + +export const crossClusterApiKeySchema = restApiKeySchema.extends({ + type: schema.literal('cross_cluster'), + role_descriptors: null, + access: schema.object( + { + search: schema.maybe( + schema.arrayOf( + schema.object({ + names: schema.arrayOf(schema.string()), + }) + ) + ), + replication: schema.maybe( + schema.arrayOf( + schema.object({ + names: schema.arrayOf(schema.string()), + }) + ) + ), + }, + { unknowns: 'allow' } + ), +}); diff --git a/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/index.ts b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/index.ts new file mode 100644 index 000000000000..dbad1344d1d2 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + CreateAPIKeyParams, + CreateAPIKeyResult, + InvalidateAPIKeyResult, + InvalidateAPIKeysParams, + ValidateAPIKeyParams, + CreateRestAPIKeyParams, + CreateRestAPIKeyWithKibanaPrivilegesParams, + CreateCrossClusterAPIKeyParams, + GrantAPIKeyResult, + APIKeys, +} from './api_keys'; +export { + crossClusterApiKeySchema, + getRestApiKeyWithKibanaPrivilegesSchema, + restApiKeySchema, +} from './api_keys'; diff --git a/x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts b/x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts new file mode 100644 index 000000000000..5dc8827786a4 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authentication/authentication_service.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; +import type { AuthenticatedUser } from '@kbn/security-plugin-types-common'; + +import type { APIKeys } from './api_keys'; + +/** + * Authentication services available on the security plugin's start contract. + */ +export interface AuthenticationServiceStart { + apiKeys: APIKeys; + getCurrentUser: (request: KibanaRequest) => AuthenticatedUser | null; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authentication/index.ts b/x-pack/packages/security/plugin_types_server/src/authentication/index.ts new file mode 100644 index 000000000000..04e4a820fb4d --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authentication/index.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + CreateAPIKeyParams, + CreateAPIKeyResult, + CreateRestAPIKeyParams, + CreateRestAPIKeyWithKibanaPrivilegesParams, + CreateCrossClusterAPIKeyParams, + InvalidateAPIKeyResult, + InvalidateAPIKeysParams, + ValidateAPIKeyParams, + APIKeys, + GrantAPIKeyResult, +} from './api_keys'; +export type { AuthenticationServiceStart } from './authentication_service'; +export { + restApiKeySchema, + getRestApiKeyWithKibanaPrivilegesSchema, + crossClusterApiKeySchema, +} from './api_keys'; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts new file mode 100644 index 000000000000..e1ad16afa5d3 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/actions.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AlertingActions } from './alerting'; +import type { ApiActions } from './api'; +import type { AppActions } from './app'; +import type { CasesActions } from './cases'; +import type { SavedObjectActions } from './saved_object'; +import type { SpaceActions } from './space'; +import type { UIActions } from './ui'; + +/** Actions are used to create the "actions" that are associated with Elasticsearch's + * application privileges, and are used to perform the authorization checks implemented + * by the various `checkPrivilegesWithRequest` derivatives. + */ +export interface Actions { + readonly api: ApiActions; + readonly app: AppActions; + readonly cases: CasesActions; + readonly login: string; + readonly savedObject: SavedObjectActions; + readonly alerting: AlertingActions; + readonly space: SpaceActions; + readonly ui: UIActions; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts new file mode 100644 index 000000000000..fe27a15d1ec0 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/alerting.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface AlertingActions { + get(ruleTypeId: string, consumer: string, alertingEntity: string, operation: string): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts new file mode 100644 index 000000000000..30a1328ce563 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/api.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface ApiActions { + get(operation: string): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts new file mode 100644 index 000000000000..38125e45bdfe --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/app.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface AppActions { + get(operation: string): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts new file mode 100644 index 000000000000..974c106f14d1 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/cases.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface CasesActions { + get(owner: string, operation: string): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/index.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/index.ts new file mode 100644 index 000000000000..6b3993423015 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { Actions } from './actions'; +export type { AlertingActions } from './alerting'; +export type { ApiActions } from './api'; +export type { AppActions } from './app'; +export type { CasesActions } from './cases'; +export type { SavedObjectActions } from './saved_object'; +export type { SpaceActions } from './space'; +export type { UIActions } from './ui'; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts new file mode 100644 index 000000000000..329feb596704 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/saved_object.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface SavedObjectActions { + get(type: string, operation: string): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts new file mode 100644 index 000000000000..fb23efaa084b --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/space.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface SpaceActions { + manage: string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts b/x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts new file mode 100644 index 000000000000..176248553898 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/actions/ui.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Capabilities as UICapabilities } from '@kbn/core/server'; + +export interface UIActions { + get(featureId: keyof UICapabilities, ...uiCapabilityParts: string[]): string; +} diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts b/x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts new file mode 100644 index 000000000000..82fa3d3fcce5 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/authorization_service.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Actions } from './actions'; +import type { CheckPrivilegesWithRequest } from './check_privileges'; +import type { CheckPrivilegesDynamicallyWithRequest } from './check_privileges_dynamically'; +import type { CheckSavedObjectsPrivilegesWithRequest } from './check_saved_objects_privileges'; +import type { AuthorizationMode } from './mode'; + +/** + * Authorization services available on the setup contract of the security plugin. + */ +export interface AuthorizationServiceSetup { + /** + * Actions are used to create the "actions" that are associated with Elasticsearch's + * application privileges, and are used to perform the authorization checks implemented + * by the various `checkPrivilegesWithRequest` derivatives. + */ + actions: Actions; + checkPrivilegesWithRequest: CheckPrivilegesWithRequest; + checkPrivilegesDynamicallyWithRequest: CheckPrivilegesDynamicallyWithRequest; + checkSavedObjectsPrivilegesWithRequest: CheckSavedObjectsPrivilegesWithRequest; + mode: AuthorizationMode; +} diff --git a/x-pack/plugins/security/server/authorization/types.ts b/x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts similarity index 100% rename from x-pack/plugins/security/server/authorization/types.ts rename to x-pack/packages/security/plugin_types_server/src/authorization/check_privileges.ts diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts b/x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts new file mode 100644 index 000000000000..f9663dddc64d --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/check_privileges_dynamically.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; +import type { + CheckPrivilegesPayload, + CheckPrivilegesOptions, + CheckPrivilegesResponse, +} from './check_privileges'; + +export type CheckPrivilegesDynamically = ( + privileges: CheckPrivilegesPayload, + options?: CheckPrivilegesOptions +) => Promise; + +export type CheckPrivilegesDynamicallyWithRequest = ( + request: KibanaRequest +) => CheckPrivilegesDynamically; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts b/x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts new file mode 100644 index 000000000000..4b42723c8328 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/check_saved_objects_privileges.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; +import type { CheckPrivilegesResponse } from './check_privileges'; + +export type CheckSavedObjectsPrivilegesWithRequest = ( + request: KibanaRequest +) => CheckSavedObjectsPrivileges; + +export type CheckSavedObjectsPrivileges = ( + actions: string | string[], + namespaceOrNamespaces?: string | Array +) => Promise; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/constants.ts b/x-pack/packages/security/plugin_types_server/src/authorization/constants.ts new file mode 100644 index 000000000000..cd2d7d300255 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const GLOBAL_RESOURCE = '*'; diff --git a/x-pack/plugins/security/common/model/deprecations.ts b/x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts similarity index 92% rename from x-pack/plugins/security/common/model/deprecations.ts rename to x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts index 3fa9bd401981..68cc61067e3c 100644 --- a/x-pack/plugins/security/common/model/deprecations.ts +++ b/x-pack/packages/security/plugin_types_server/src/authorization/deprecations.ts @@ -7,7 +7,7 @@ import type { DeprecationsDetails, GetDeprecationsContext } from '@kbn/core/server'; -import type { Role } from './role'; +import type { Role } from '@kbn/security-plugin-types-common'; export interface PrivilegeDeprecationsRolesByFeatureIdResponse { roles?: Role[]; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/index.ts b/x-pack/packages/security/plugin_types_server/src/authorization/index.ts new file mode 100644 index 000000000000..54364d7817f3 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/index.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + Actions, + ApiActions, + AppActions, + AlertingActions, + CasesActions, + SavedObjectActions, + SpaceActions, + UIActions, +} from './actions'; +export type { AuthorizationServiceSetup } from './authorization_service'; +export type { + CheckPrivilegesOptions, + CheckPrivilegesResponse, + CheckPrivilegesWithRequest, + CheckPrivilegesPayload, + CheckPrivileges, + HasPrivilegesResponse, + HasPrivilegesResponseApplication, + CheckUserProfilesPrivilegesPayload, + CheckUserProfilesPrivilegesResponse, + CheckUserProfilesPrivileges, +} from './check_privileges'; +export type { + CheckPrivilegesDynamically, + CheckPrivilegesDynamicallyWithRequest, +} from './check_privileges_dynamically'; +export type { + CheckSavedObjectsPrivileges, + CheckSavedObjectsPrivilegesWithRequest, +} from './check_saved_objects_privileges'; +export type { + PrivilegeDeprecationsService, + PrivilegeDeprecationsRolesByFeatureIdRequest, + PrivilegeDeprecationsRolesByFeatureIdResponse, +} from './deprecations'; +export type { AuthorizationMode } from './mode'; +export type { ElasticsearchPrivilegesType, KibanaPrivilegesType } from './role_schema'; + +export { GLOBAL_RESOURCE } from './constants'; +export { elasticsearchRoleSchema, getKibanaRoleSchema } from './role_schema'; diff --git a/x-pack/packages/security/plugin_types_server/src/authorization/mode.ts b/x-pack/packages/security/plugin_types_server/src/authorization/mode.ts new file mode 100644 index 000000000000..242b5524a937 --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/authorization/mode.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; + +export interface AuthorizationMode { + useRbacForRequest(request: KibanaRequest): boolean; +} diff --git a/x-pack/plugins/security/server/lib/role_schema.ts b/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts similarity index 99% rename from x-pack/plugins/security/server/lib/role_schema.ts rename to x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts index fe59a1f740b4..ea7f89692790 100644 --- a/x-pack/plugins/security/server/lib/role_schema.ts +++ b/x-pack/packages/security/plugin_types_server/src/authorization/role_schema.ts @@ -9,7 +9,7 @@ import _ from 'lodash'; import type { TypeOf } from '@kbn/config-schema'; import { schema } from '@kbn/config-schema'; -import { GLOBAL_RESOURCE } from '../../common/constants'; +import { GLOBAL_RESOURCE } from './constants'; /** * Elasticsearch specific portion of the role definition. diff --git a/x-pack/packages/security/plugin_types_server/src/plugin.ts b/x-pack/packages/security/plugin_types_server/src/plugin.ts new file mode 100644 index 000000000000..d3ee046c2d0c --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/plugin.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SecurityLicense } from '@kbn/security-plugin-types-common'; +import type { AuditServiceSetup } from './audit'; +import type { PrivilegeDeprecationsService, AuthorizationServiceSetup } from './authorization'; +import type { AuthenticationServiceStart } from './authentication'; +import type { UserProfileServiceStart } from './user_profile'; + +/** + * Describes public Security plugin contract returned at the `setup` stage. + */ +export interface SecurityPluginSetup { + /** + * Exposes information about the available security features under the current license. + */ + license: SecurityLicense; + /** + * Exposes services for audit logging. + */ + audit: AuditServiceSetup; + /** + * Exposes services to access kibana roles per feature id with the GetDeprecationsContext + */ + privilegeDeprecationsService: PrivilegeDeprecationsService; +} + +/** + * Describes public Security plugin contract returned at the `start` stage. + */ +export interface SecurityPluginStart { + /** + * Authentication services to confirm the user is who they say they are. + */ + authc: AuthenticationServiceStart; + /** + * Authorization services to manage and access the permissions a particular user has. + */ + authz: AuthorizationServiceSetup; + /** + * User profiles services to retrieve user profiles. + */ + userProfiles: UserProfileServiceStart; +} diff --git a/x-pack/packages/security/plugin_types_server/src/user_profile/index.ts b/x-pack/packages/security/plugin_types_server/src/user_profile/index.ts new file mode 100644 index 000000000000..15be67e7601f --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/user_profile/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { + UserProfileServiceStart, + UserProfileSuggestParams, + UserProfileBulkGetParams, + UserProfileRequiredPrivileges, + UserProfileGetCurrentParams, +} from './user_profile_service'; diff --git a/x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts b/x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts new file mode 100644 index 000000000000..ab68b973139e --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/src/user_profile/user_profile_service.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; +import type { + UserProfileData, + UserProfileLabels, + UserProfileWithSecurity, + UserProfile, +} from '@kbn/security-plugin-types-common'; + +/** + * A set of methods to work with Kibana user profiles. + */ +export interface UserProfileServiceStart { + /** + * Retrieves a user profile for the current user extracted from the specified request. If the profile isn't available, + * e.g. for the anonymous users or users authenticated via authenticating proxies, the `null` value is returned. + * @param params Get current user profile operation parameters. + * @param params.request User request instance to get user profile for. + * @param params.dataPath By default Elasticsearch returns user information, but does not return any user data. The + * optional "dataPath" parameter can be used to return personal data for the requested user profiles. + */ + getCurrent( + params: UserProfileGetCurrentParams + ): Promise | null>; + + /** + * Retrieves multiple user profiles by their identifiers. + * @param params Bulk get operation parameters. + * @param params.uids List of user profile identifiers. + * @param params.dataPath By default Elasticsearch returns user information, but does not return any user data. The + * optional "dataPath" parameter can be used to return personal data for the requested user profiles. + */ + bulkGet( + params: UserProfileBulkGetParams + ): Promise>>; + + /** + * Suggests multiple user profiles by search criteria. + * @param params Suggest operation parameters. + * @param params.name Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email. + * @param params.size Desired number of suggestion to return. The default value is 10. + * @param params.dataPath By default, suggest API returns user information, but does not return any user data. The optional "dataPath" parameter can be used to return personal data for this user (within `kibana` namespace only). + * @param params.requiredPrivileges The set of the privileges that users associated with the suggested user profile should have in the specified space. If not specified, privileges check isn't performed and all matched profiles are returned irrespective to the privileges of the associated users. + */ + suggest( + params: UserProfileSuggestParams + ): Promise>>; +} + +/** + * The set of privileges that users associated with the suggested user profile should have for a specified space id. + */ +export interface UserProfileRequiredPrivileges { + /** + * The id of the Kibana Space. + */ + spaceId: string; + + /** + * The set of the Kibana specific application privileges. + */ + privileges: { kibana: string[] }; +} + +/** + * Parameters for the get user profile for the current user API. + */ +export interface UserProfileGetCurrentParams { + /** + * User request instance to get user profile for. + */ + request: KibanaRequest; + + /** + * By default, get API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath?: string; +} + +/** + * Parameters for the bulk get API. + */ +export interface UserProfileBulkGetParams { + /** + * List of user profile identifiers. + */ + uids: Set; + + /** + * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath?: string; +} + +/** + * Parameters for the suggest API. + */ +export interface UserProfileSuggestParams { + /** + * Query string used to match name-related fields in user profiles. The following fields are treated as + * name-related: username, full_name and email. + */ + name?: string; + + /** + * Extra search criteria to improve relevance of the suggestion result. A profile matching the + * specified hint is ranked higher in the response. But not-matching the hint does not exclude a + * profile from the response as long as it matches the `name` field query. + */ + hint?: { + /** + * A list of Profile UIDs to match against. + */ + uids: string[]; + }; + + /** + * Desired number of suggestion to return. The default value is 10. + */ + size?: number; + + /** + * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" + * parameter can be used to return personal data for this user (within `kibana` namespace only). + */ + dataPath?: string; + + /** + * The set of the privileges that users associated with the suggested user profile should have in the specified space. + * If not specified, privileges check isn't performed and all matched profiles are returned irrespective to the + * privileges of the associated users. + */ + requiredPrivileges?: UserProfileRequiredPrivileges; +} diff --git a/x-pack/packages/security/plugin_types_server/tsconfig.json b/x-pack/packages/security/plugin_types_server/tsconfig.json new file mode 100644 index 000000000000..1883d50f328e --- /dev/null +++ b/x-pack/packages/security/plugin_types_server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/config-schema", + "@kbn/core", + "@kbn/security-plugin-types-common", + ] +} diff --git a/x-pack/plugins/actions/docs/openapi/README.md b/x-pack/plugins/actions/docs/openapi/README.md index 2bce08f0b1a4..210bb719eb91 100644 --- a/x-pack/plugins/actions/docs/openapi/README.md +++ b/x-pack/plugins/actions/docs/openapi/README.md @@ -1,6 +1,6 @@ # OpenAPI (Experimental) -The current self-contained spec file is [as JSON](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/cases/common/openapi/bundled.json) or [as YAML](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/cases/common/openapi/bundled.yaml) and can be used for online tools like those found at https://openapi.tools/. +The current self-contained spec file is [as JSON](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/cases/common/openapi/bundled.json) or [as YAML](https://raw.githubusercontent.com/elastic/kibana/master/x-pack/plugins/cases/common/openapi/bundled.yaml) and can be used for online tools like those found at https://openapi.tools/. This spec is experimental and may be incomplete or change later. A guide about the openApi specification can be found at [https://swagger.io/docs/specification/about/](https://swagger.io/docs/specification/about/). diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index 2f8bbf898efe..a2debc66a17a 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -1,9 +1,9 @@ { - "openapi": "3.0.1", + "openapi": "3.1.0", "info": { "title": "Connectors", "description": "OpenAPI schema for Connectors endpoints", - "version": "0.1", + "version": "0.2", "contact": { "name": "Connectors Team" }, @@ -178,7 +178,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } } ], @@ -303,6 +305,9 @@ "runJiraConnectorRequest": { "$ref": "#/components/examples/run_jira_connector_request" }, + "runPagerDutyConnectorRequest": { + "$ref": "#/components/examples/run_pagerduty_connector_request" + }, "runServerLogConnectorRequest": { "$ref": "#/components/examples/run_server_log_connector_request" }, @@ -368,6 +373,9 @@ "runJiraConnectorResponse": { "$ref": "#/components/examples/run_jira_connector_response" }, + "runPagerDutyConnectorResponse": { + "$ref": "#/components/examples/run_pagerduty_connector_response" + }, "runServerLogConnectorResponse": { "$ref": "#/components/examples/run_server_log_connector_response" }, @@ -451,34 +459,46 @@ "enabled": { "type": "boolean", "description": "Indicates whether the connector type is enabled in Kibana.", - "example": true + "examples": [ + true + ] }, "enabled_in_config": { "type": "boolean", "description": "Indicates whether the connector type is enabled in the Kibana configuration file.", - "example": true + "examples": [ + true + ] }, "enabled_in_license": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "example": true + "examples": [ + true + ] }, "id": { "$ref": "#/components/schemas/connector_types" }, "is_system_action_type": { "type": "boolean", - "example": false + "examples": [ + false + ] }, "minimum_license_required": { "type": "string", "description": "The license that is required to use the connector type.", - "example": "basic" + "examples": [ + "basic" + ] }, "name": { "type": "string", "description": "The name of the connector type.", - "example": "Index" + "examples": [ + "Index" + ] }, "supported_feature_ids": { "type": "array", @@ -486,10 +506,12 @@ "items": { "$ref": "#/components/schemas/features" }, - "example": [ - "alerting", - "cases", - "siem" + "examples": [ + [ + "alerting", + "cases", + "siem" + ] ] } } @@ -671,7 +693,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } } ], @@ -841,17 +865,23 @@ "enabled": { "type": "boolean", "description": "Indicates whether the connector type is enabled in Kibana.", - "example": true + "examples": [ + true + ] }, "enabled_in_config": { "type": "boolean", "description": "Indicates whether the connector type is enabled in the Kibana `.yml` file.", - "example": true + "examples": [ + true + ] }, "enabled_in_license": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "example": true + "examples": [ + true + ] }, "id": { "$ref": "#/components/schemas/connector_types" @@ -859,12 +889,16 @@ "minimum_license_required": { "type": "string", "description": "The license that is required to use the connector type.", - "example": "basic" + "examples": [ + "basic" + ] }, "name": { "type": "string", "description": "The name of the connector type.", - "example": "Index" + "examples": [ + "Index" + ] }, "supported_feature_ids": { "type": "array", @@ -872,10 +906,12 @@ "items": { "$ref": "#/components/schemas/features" }, - "example": [ - "alerting", - "uptime", - "siem" + "examples": [ + [ + "alerting", + "uptime", + "siem" + ] ] } } @@ -1243,7 +1279,9 @@ "enabledInLicense": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "example": true + "examples": [ + true + ] }, "id": { "type": "string", @@ -1362,7 +1400,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "parameters": { @@ -1382,7 +1421,9 @@ "required": true, "schema": { "type": "string", - "example": "df770e30-8b8b-11ed-a780-3b746c987a81" + "examples": [ + "df770e30-8b8b-11ed-a780-3b746c987a81" + ] } }, "space_id": { @@ -1392,7 +1433,9 @@ "required": true, "schema": { "type": "string", - "example": "default" + "examples": [ + "default" + ] } }, "action_id": { @@ -1402,7 +1445,9 @@ "required": true, "schema": { "type": "string", - "example": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad" + "examples": [ + "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad" + ] } } }, @@ -1465,12 +1510,16 @@ "enum": [ ".bedrock" ], - "example": ".bedrock" + "examples": [ + ".bedrock" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_bedrock" @@ -1495,11 +1544,13 @@ "createCommentJson": { "type": "string", "description": "A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "example": { - "body": { - "[object Object]": null + "examples": [ + { + "body": { + "[object Object]": null + } } - } + ] }, "createCommentMethod": { "type": "string", @@ -1514,24 +1565,28 @@ "createCommentUrl": { "type": "string", "description": "The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment" + ] }, "createIncidentJson": { "type": "string", "description": "A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "example": { - "fields": { - "summary": { - "[object Object]": null - }, - "description": { - "[object Object]": null - }, - "labels": { - "[object Object]": null + "examples": [ + { + "fields": { + "summary": { + "[object Object]": null + }, + "description": { + "[object Object]": null + }, + "labels": { + "[object Object]": null + } } } - } + ] }, "createIncidentMethod": { "type": "string", @@ -1558,7 +1613,9 @@ "getIncidentUrl": { "type": "string", "description": "The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}" + ] }, "hasAuth": { "type": "boolean", @@ -1572,19 +1629,21 @@ "updateIncidentJson": { "type": "string", "description": "The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "example": { - "fields": { - "summary": { - "[object Object]": null - }, - "description": { - "[object Object]": null - }, - "labels": { - "[object Object]": null + "examples": [ + { + "fields": { + "summary": { + "[object Object]": null + }, + "description": { + "[object Object]": null + }, + "labels": { + "[object Object]": null + } } } - } + ] }, "updateIncidentMethod": { "type": "string", @@ -1599,12 +1658,16 @@ "updateIncidentUrl": { "type": "string", "description": "The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}}" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}}" + ] }, "viewIncidentUrl": { "type": "string", "description": "The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL.\n", - "example": "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" + "examples": [ + "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" + ] } } }, @@ -1641,12 +1704,16 @@ "enum": [ ".cases-webhook" ], - "example": ".cases-webhook" + "examples": [ + ".cases-webhook" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -1701,12 +1768,16 @@ "enum": [ ".d3security" ], - "example": ".d3security" + "examples": [ + ".d3security" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_d3security" @@ -1723,8 +1794,10 @@ "properties": { "clientId": { "description": "The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "from": { "description": "The from address for all emails sent by the connector. It must be specified in `user@host-name` format.\n", @@ -1740,8 +1813,10 @@ "type": "string" }, "oauthTokenUrl": { - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "port": { "description": "The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", @@ -1765,8 +1840,10 @@ }, "tenantId": { "description": "The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -1809,12 +1886,16 @@ "enum": [ ".email" ], - "example": ".email" + "examples": [ + ".email" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_email" @@ -1905,12 +1986,16 @@ "enum": [ ".gen-ai" ], - "example": ".gen-ai" + "examples": [ + ".gen-ai" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_genai" @@ -1928,8 +2013,10 @@ "executionTimeField": { "description": "A field that indicates when the document was indexed.", "default": null, - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "index": { "description": "The Elasticsearch index to be written to.", @@ -1961,12 +2048,16 @@ "enum": [ ".index" ], - "example": ".index" + "examples": [ + ".index" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] } } }, @@ -2028,12 +2119,16 @@ "enum": [ ".jira" ], - "example": ".jira" + "examples": [ + ".jira" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_jira" @@ -2088,12 +2183,16 @@ "enum": [ ".opsgenie" ], - "example": ".opsgenie" + "examples": [ + ".opsgenie" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_opsgenie" @@ -2107,9 +2206,13 @@ "properties": { "apiUrl": { "description": "The PagerDuty event URL.", - "type": "string", - "nullable": true, - "example": "https://events.pagerduty.com/v2/enqueue" + "type": [ + "string", + "null" + ], + "examples": [ + "https://events.pagerduty.com/v2/enqueue" + ] } } }, @@ -2147,12 +2250,16 @@ "enum": [ ".pagerduty" ], - "example": ".pagerduty" + "examples": [ + ".pagerduty" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_pagerduty" @@ -2214,7 +2321,9 @@ "connector_type_id": { "description": "The type of connector.", "type": "string", - "example": ".resilient", + "examples": [ + ".resilient" + ], "enum": [ ".resilient" ] @@ -2222,7 +2331,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_resilient" @@ -2244,12 +2355,16 @@ "enum": [ ".server-log" ], - "example": ".server-log" + "examples": [ + ".server-log" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] } } }, @@ -2336,12 +2451,16 @@ "enum": [ ".servicenow" ], - "example": ".servicenow" + "examples": [ + ".servicenow" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -2399,12 +2518,16 @@ "enum": [ ".servicenow-itom" ], - "example": ".servicenow-itom" + "examples": [ + ".servicenow-itom" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -2431,12 +2554,16 @@ "enum": [ ".servicenow-sir" ], - "example": ".servicenow-sir" + "examples": [ + ".servicenow-sir" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -2473,12 +2600,16 @@ "enum": [ ".slack_api" ], - "example": ".slack_api" + "examples": [ + ".slack_api" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_api" @@ -2515,12 +2646,16 @@ "enum": [ ".slack" ], - "example": ".slack" + "examples": [ + ".slack" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_webhook" @@ -2797,12 +2932,16 @@ "enum": [ ".swimlane" ], - "example": ".swimlane" + "examples": [ + ".swimlane" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -2839,12 +2978,16 @@ "enum": [ ".teams" ], - "example": ".teams" + "examples": [ + ".teams" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_teams" @@ -2904,12 +3047,16 @@ "enum": [ ".tines" ], - "example": ".tines" + "examples": [ + ".tines" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_tines" @@ -2964,12 +3111,16 @@ "enum": [ ".torq" ], - "example": ".torq" + "examples": [ + ".torq" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_torq" @@ -3007,8 +3158,10 @@ "description": "If `true`, a user name and password must be provided for login type authentication.\n" }, "headers": { - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "description": "A set of key-value pairs sent as headers with the request." }, "method": { @@ -3083,12 +3236,16 @@ "enum": [ ".webhook" ], - "example": ".webhook" + "examples": [ + ".webhook" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_webhook" @@ -3102,8 +3259,10 @@ "properties": { "configUrl": { "description": "The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "usesBasic": { "description": "Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`).", @@ -3151,12 +3310,16 @@ "enum": [ ".xmatters" ], - "example": ".xmatters" + "examples": [ + ".xmatters" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_xmatters" @@ -3241,22 +3404,30 @@ "is_deprecated": { "type": "boolean", "description": "Indicates whether the connector type is deprecated.", - "example": false + "examples": [ + false + ] }, "is_missing_secrets": { "type": "boolean", "description": "Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.", - "example": false + "examples": [ + false + ] }, "is_preconfigured": { "type": "boolean", "description": "Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. \n", - "example": false + "examples": [ + false + ] }, "is_system_action": { "type": "boolean", "description": "Indicates whether the connector is used for system actions.", - "example": false + "examples": [ + false + ] }, "connector_response_properties_bedrock": { "title": "Connector response properties for an Amazon Bedrock connector", @@ -3305,7 +3476,9 @@ "referenced_by_count": { "type": "integer", "description": "Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API.\n", - "example": 2 + "examples": [ + 2 + ] }, "connector_response_properties_cases_webhook": { "title": "Connector request properties for a Webhook - Case Management connector", @@ -3687,8 +3860,10 @@ ], "properties": { "config": { - "type": "object", - "nullable": true + "type": [ + "object", + "null" + ] }, "connector_type_id": { "type": "string", @@ -4328,7 +4503,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -4581,7 +4758,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -4758,6 +4937,30 @@ } ] }, + "run_connector_params_acknowledge_resolve_pagerduty": { + "title": "PagerDuty connector parameters", + "description": "Test an action that acknowledges or resolves a PagerDuty alert.", + "type": "object", + "required": [ + "dedupKey", + "eventAction" + ], + "properties": { + "dedupKey": { + "description": "The deduplication key for the PagerDuty alert.", + "type": "string", + "maxLength": 255 + }, + "eventAction": { + "description": "The type of event.", + "type": "string", + "enum": [ + "acknowledge", + "resolve" + ] + } + } + }, "run_connector_params_documents": { "title": "Index connector parameters", "description": "Test an action that indexes a document into Elasticsearch.", @@ -4862,6 +5065,95 @@ } } }, + "run_connector_params_trigger_pagerduty": { + "title": "PagerDuty connector parameters", + "description": "Test an action that triggers a PagerDuty alert.", + "type": "object", + "required": [ + "eventAction" + ], + "properties": { + "class": { + "description": "The class or type of the event.", + "type": "string", + "examples": [ + "cpu load" + ] + }, + "component": { + "description": "The component of the source machine that is responsible for the event.", + "type": "string", + "examples": [ + "eth0" + ] + }, + "customDetails": { + "description": "Additional details to add to the event.", + "type": "object" + }, + "dedupKey": { + "description": "All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution.\n", + "type": "string", + "maxLength": 255 + }, + "eventAction": { + "description": "The type of event.", + "type": "string", + "enum": [ + "trigger" + ] + }, + "group": { + "description": "The logical grouping of components of a service.", + "type": "string", + "examples": [ + "app-stack" + ] + }, + "links": { + "description": "A list of links to add to the event.", + "type": "array", + "items": { + "type": "object", + "properties": { + "href": { + "description": "The URL for the link.", + "type": "string" + }, + "text": { + "description": "A plain text description of the purpose of the link.", + "type": "string" + } + } + } + }, + "severity": { + "description": "The severity of the event on the affected system.", + "type": "string", + "enum": [ + "critical", + "error", + "info", + "warning" + ], + "default": "info" + }, + "source": { + "description": "The affected system, such as a hostname or fully qualified domain name. Defaults to the Kibana saved object id of the action.\n", + "type": "string" + }, + "summary": { + "description": "A summery of the event.", + "type": "string", + "maxLength": 1024 + }, + "timestamp": { + "description": "An ISO-8601 timestamp that indicates when the event was detected or generated.", + "type": "string", + "format": "date-time" + } + } + }, "run_connector_subaction_addevent": { "title": "The addEvent subaction", "type": "object", @@ -5012,10 +5304,12 @@ "type": "object", "description": "The custom properties of the alert.", "additionalProperties": true, - "example": { - "key1": "value1", - "key2": "value2" - } + "examples": [ + { + "key1": "value1", + "key2": "value2" + } + ] }, "entity": { "type": "string", @@ -5147,7 +5441,9 @@ "id": { "type": "string", "description": "The Jira issue type identifier.", - "example": 10024 + "examples": [ + 10024 + ] } } } @@ -5229,7 +5525,9 @@ "externalId": { "type": "string", "description": "The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier.", - "example": 71778 + "examples": [ + 71778 + ] } } } @@ -5259,7 +5557,9 @@ "id": { "type": "string", "description": "The Jira issue identifier.", - "example": 71778 + "examples": [ + 71778 + ] } } } @@ -5509,6 +5809,9 @@ "properties": { "params": { "oneOf": [ + { + "$ref": "#/components/schemas/run_connector_params_acknowledge_resolve_pagerduty" + }, { "$ref": "#/components/schemas/run_connector_params_documents" }, @@ -5518,6 +5821,9 @@ { "$ref": "#/components/schemas/run_connector_params_message_serverlog" }, + { + "$ref": "#/components/schemas/run_connector_params_trigger_pagerduty" + }, { "title": "Subaction parameters", "description": "Test an action that involves a subaction.", @@ -5603,7 +5909,9 @@ ".webhook", ".xmatters" ], - "example": ".server-log" + "examples": [ + ".server-log" + ] }, "action_response_properties": { "title": "Action response properties", @@ -5838,6 +6146,24 @@ } } }, + "run_pagerduty_connector_request": { + "summary": "Run a PagerDuty connector to trigger an alert.", + "value": { + "params": { + "eventAction": "trigger", + "summary": "A brief event summary", + "links": [ + { + "href": "http://example.com/pagerduty", + "text": "An example link" + } + ], + "customDetails": { + "my_data_1": "test data" + } + } + } + }, "run_server_log_connector_request": { "summary": "Run a server log connector.", "value": { @@ -5974,6 +6300,18 @@ "status": "ok" } }, + "run_pagerduty_connector_response": { + "summary": "Response from running a PagerDuty connector.", + "value": { + "connector_id": "45de9f70-954f-4608-b12a-db7cf808e49d", + "data": { + "dedup_key": "5115e138b26b484a81eaea779faa6016", + "message": "Event processed", + "status": "success" + }, + "status": "ok" + } + }, "run_server_log_connector_response": { "summary": "Response from running a server log connector.", "value": { @@ -6176,7 +6514,9 @@ "properties": { "error": { "type": "string", - "example": "Unauthorized", + "examples": [ + "Unauthorized" + ], "enum": [ "Unauthorized" ] @@ -6186,7 +6526,9 @@ }, "statusCode": { "type": "integer", - "example": 401, + "examples": [ + 401 + ], "enum": [ 401 ] @@ -6206,18 +6548,24 @@ "properties": { "error": { "type": "string", - "example": "Not Found", + "examples": [ + "Not Found" + ], "enum": [ "Not Found" ] }, "message": { "type": "string", - "example": "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + "examples": [ + "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + ] }, "statusCode": { "type": "integer", - "example": 404, + "examples": [ + 404 + ], "enum": [ 404 ] diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index 481d0f0a7ec4..50856a35f939 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Connectors description: OpenAPI schema for Connectors endpoints - version: '0.1' + version: '0.2' contact: name: Connectors Team license: @@ -109,7 +109,8 @@ paths: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -185,6 +186,8 @@ paths: $ref: '#/components/examples/run_index_connector_request' runJiraConnectorRequest: $ref: '#/components/examples/run_jira_connector_request' + runPagerDutyConnectorRequest: + $ref: '#/components/examples/run_pagerduty_connector_request' runServerLogConnectorRequest: $ref: '#/components/examples/run_server_log_connector_request' runServiceNowITOMConnectorRequest: @@ -227,6 +230,8 @@ paths: $ref: '#/components/examples/run_index_connector_response' runJiraConnectorResponse: $ref: '#/components/examples/run_jira_connector_response' + runPagerDutyConnectorResponse: + $ref: '#/components/examples/run_pagerduty_connector_response' runServerLogConnectorResponse: $ref: '#/components/examples/run_server_log_connector_response' runServiceNowITOMConnectorResponse: @@ -282,37 +287,43 @@ paths: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - example: true + examples: + - true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana configuration file. - example: true + examples: + - true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: $ref: '#/components/schemas/connector_types' is_system_action_type: type: boolean - example: false + examples: + - false minimum_license_required: type: string description: The license that is required to use the connector type. - example: basic + examples: + - basic name: type: string description: The name of the connector type. - example: Index + examples: + - Index supported_feature_ids: type: array description: The features that are supported by the connector type. items: $ref: '#/components/schemas/features' - example: - - alerting - - cases - - siem + examples: + - - alerting + - cases + - siem examples: getConnectorTypesServerlessResponse: $ref: '#/components/examples/get_connector_types_generativeai_response' @@ -421,7 +432,8 @@ paths: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -530,34 +542,39 @@ paths: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - example: true + examples: + - true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana `.yml` file. - example: true + examples: + - true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: $ref: '#/components/schemas/connector_types' minimum_license_required: type: string description: The license that is required to use the connector type. - example: basic + examples: + - basic name: type: string description: The name of the connector type. - example: Index + examples: + - Index supported_feature_ids: type: array description: The Kibana features that are supported by the connector type. items: $ref: '#/components/schemas/features' - example: - - alerting - - uptime - - siem + examples: + - - alerting + - uptime + - siem examples: getConnectorTypesResponse: $ref: '#/components/examples/get_connector_types_response' @@ -789,7 +806,8 @@ paths: enabledInLicense: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: type: string description: The unique identifier for the connector type. @@ -859,7 +877,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -875,7 +894,8 @@ components: required: true schema: type: string - example: df770e30-8b8b-11ed-a780-3b746c987a81 + examples: + - df770e30-8b8b-11ed-a780-3b746c987a81 space_id: in: path name: spaceId @@ -883,7 +903,8 @@ components: required: true schema: type: string - example: default + examples: + - default action_id: in: path name: actionId @@ -891,7 +912,8 @@ components: required: true schema: type: string - example: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + examples: + - c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad schemas: config_properties_bedrock: title: Connector request properties for an Amazon Bedrock connector @@ -939,11 +961,13 @@ components: description: The type of connector. enum: - .bedrock - example: .bedrock + examples: + - .bedrock name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_bedrock' config_properties_cases_webhook: @@ -964,9 +988,9 @@ components: type: string description: | A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: - body: - '[object Object]': null + examples: + - body: + '[object Object]': null createCommentMethod: type: string description: | @@ -980,19 +1004,20 @@ components: type: string description: | The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: | A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: - fields: - summary: - '[object Object]': null - description: - '[object Object]': null - labels: - '[object Object]': null + examples: + - fields: + summary: + '[object Object]': null + description: + '[object Object]': null + labels: + '[object Object]': null createIncidentMethod: type: string description: | @@ -1016,7 +1041,8 @@ components: type: string description: | The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -1029,14 +1055,14 @@ components: type: string description: | The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: - fields: - summary: - '[object Object]': null - description: - '[object Object]': null - labels: - '[object Object]': null + examples: + - fields: + summary: + '[object Object]': null + description: + '[object Object]': null + labels: + '[object Object]': null updateIncidentMethod: type: string description: | @@ -1050,12 +1076,14 @@ components: type: string description: | The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: | The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + examples: + - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} secrets_properties_cases_webhook: title: Connector secrets properties for Webhook - Case Management connector type: object @@ -1083,11 +1111,13 @@ components: description: The type of connector. enum: - .cases-webhook - example: .cases-webhook + examples: + - .cases-webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' config_properties_d3security: @@ -1129,11 +1159,13 @@ components: description: The type of connector. enum: - .d3security - example: .d3security + examples: + - .d3security name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_d3security' config_properties_email: @@ -1146,8 +1178,9 @@ components: clientId: description: | The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true + type: + - string + - 'null' from: description: | The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -1162,8 +1195,9 @@ components: The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. type: string oauthTokenUrl: - type: string - nullable: true + type: + - string + - 'null' port: description: | The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. @@ -1186,8 +1220,9 @@ components: tenantId: description: | The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true + type: + - string + - 'null' secrets_properties_email: title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. @@ -1223,11 +1258,13 @@ components: description: The type of connector. enum: - .email - example: .email + examples: + - .email name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_email' config_properties_genai: @@ -1291,11 +1328,13 @@ components: description: The type of connector. enum: - .gen-ai - example: .gen-ai + examples: + - .gen-ai name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_genai' config_properties_index: @@ -1308,8 +1347,9 @@ components: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: string - nullable: true + type: + - string + - 'null' index: description: The Elasticsearch index to be written to. type: string @@ -1334,11 +1374,13 @@ components: description: The type of connector. enum: - .index - example: .index + examples: + - .index name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector config_properties_jira: title: Connector request properties for a Jira connector required: @@ -1384,11 +1426,13 @@ components: description: The type of connector. enum: - .jira - example: .jira + examples: + - .jira name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_jira' config_properties_opsgenie: @@ -1429,11 +1473,13 @@ components: description: The type of connector. enum: - .opsgenie - example: .opsgenie + examples: + - .opsgenie name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_opsgenie' config_properties_pagerduty: @@ -1443,9 +1489,11 @@ components: properties: apiUrl: description: The PagerDuty event URL. - type: string - nullable: true - example: https://events.pagerduty.com/v2/enqueue + type: + - string + - 'null' + examples: + - https://events.pagerduty.com/v2/enqueue secrets_properties_pagerduty: title: Connector secrets properties for a PagerDuty connector description: Defines secrets for connectors when type is `.pagerduty`. @@ -1475,11 +1523,13 @@ components: description: The type of connector. enum: - .pagerduty - example: .pagerduty + examples: + - .pagerduty name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_pagerduty' config_properties_resilient: @@ -1525,13 +1575,15 @@ components: connector_type_id: description: The type of connector. type: string - example: .resilient + examples: + - .resilient enum: - .resilient name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_resilient' create_connector_request_serverlog: @@ -1547,11 +1599,13 @@ components: description: The type of connector. enum: - .server-log - example: .server-log + examples: + - .server-log name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector config_properties_servicenow: title: Connector request properties for a ServiceNow ITSM connector required: @@ -1622,11 +1676,13 @@ components: description: The type of connector. enum: - .servicenow - example: .servicenow + examples: + - .servicenow name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' config_properties_servicenow_itom: @@ -1674,11 +1730,13 @@ components: description: The type of connector. enum: - .servicenow-itom - example: .servicenow-itom + examples: + - .servicenow-itom name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_sir: @@ -1699,11 +1757,13 @@ components: description: The type of connector. enum: - .servicenow-sir - example: .servicenow-sir + examples: + - .servicenow-sir name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' secrets_properties_slack_api: @@ -1730,11 +1790,13 @@ components: description: The type of connector. enum: - .slack_api - example: .slack_api + examples: + - .slack_api name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_api' secrets_properties_slack_webhook: @@ -1761,11 +1823,13 @@ components: description: The type of connector. enum: - .slack - example: .slack + examples: + - .slack name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_webhook' config_properties_swimlane: @@ -1974,11 +2038,13 @@ components: description: The type of connector. enum: - .swimlane - example: .swimlane + examples: + - .swimlane name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' secrets_properties_teams: @@ -2006,11 +2072,13 @@ components: description: The type of connector. enum: - .teams - example: .teams + examples: + - .teams name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_teams' config_properties_tines: @@ -2056,11 +2124,13 @@ components: description: The type of connector. enum: - .tines - example: .tines + examples: + - .tines name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_tines' config_properties_torq: @@ -2101,11 +2171,13 @@ components: description: The type of connector. enum: - .torq - example: .torq + examples: + - .torq name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_torq' config_properties_webhook: @@ -2137,8 +2209,9 @@ components: description: | If `true`, a user name and password must be provided for login type authentication. headers: - type: object - nullable: true + type: + - object + - 'null' description: A set of key-value pairs sent as headers with the request. method: type: string @@ -2201,11 +2274,13 @@ components: description: The type of connector. enum: - .webhook - example: .webhook + examples: + - .webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_webhook' config_properties_xmatters: @@ -2216,8 +2291,9 @@ components: configUrl: description: | The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: string - nullable: true + type: + - string + - 'null' usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean @@ -2257,11 +2333,13 @@ components: description: The type of connector. enum: - .xmatters - example: .xmatters + examples: + - .xmatters name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_xmatters' create_connector_request: @@ -2295,20 +2373,24 @@ components: is_deprecated: type: boolean description: Indicates whether the connector type is deprecated. - example: false + examples: + - false is_missing_secrets: type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. - example: false + examples: + - false is_preconfigured: type: boolean description: | Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. - example: false + examples: + - false is_system_action: type: boolean description: Indicates whether the connector is used for system actions. - example: false + examples: + - false connector_response_properties_bedrock: title: Connector response properties for an Amazon Bedrock connector type: object @@ -2345,7 +2427,8 @@ components: type: integer description: | Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. - example: 2 + examples: + - 2 connector_response_properties_cases_webhook: title: Connector request properties for a Webhook - Case Management connector type: object @@ -2621,8 +2704,9 @@ components: - name properties: config: - type: object - nullable: true + type: + - object + - 'null' connector_type_id: type: string description: The type of connector. @@ -3056,7 +3140,8 @@ components: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' update_connector_request_d3security: @@ -3236,7 +3321,8 @@ components: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' update_connector_request_teams: @@ -3336,6 +3422,24 @@ components: - $ref: '#/components/schemas/update_connector_request_torq' - $ref: '#/components/schemas/update_connector_request_webhook' - $ref: '#/components/schemas/update_connector_request_xmatters' + run_connector_params_acknowledge_resolve_pagerduty: + title: PagerDuty connector parameters + description: Test an action that acknowledges or resolves a PagerDuty alert. + type: object + required: + - dedupKey + - eventAction + properties: + dedupKey: + description: The deduplication key for the PagerDuty alert. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - acknowledge + - resolve run_connector_params_documents: title: Index connector parameters description: Test an action that indexes a document into Elasticsearch. @@ -3413,6 +3517,74 @@ components: message: type: string description: The message for server log connectors. + run_connector_params_trigger_pagerduty: + title: PagerDuty connector parameters + description: Test an action that triggers a PagerDuty alert. + type: object + required: + - eventAction + properties: + class: + description: The class or type of the event. + type: string + examples: + - cpu load + component: + description: The component of the source machine that is responsible for the event. + type: string + examples: + - eth0 + customDetails: + description: Additional details to add to the event. + type: object + dedupKey: + description: | + All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - trigger + group: + description: The logical grouping of components of a service. + type: string + examples: + - app-stack + links: + description: A list of links to add to the event. + type: array + items: + type: object + properties: + href: + description: The URL for the link. + type: string + text: + description: A plain text description of the purpose of the link. + type: string + severity: + description: The severity of the event on the affected system. + type: string + enum: + - critical + - error + - info + - warning + default: info + source: + description: | + The affected system, such as a hostname or fully qualified domain name. Defaults to the Kibana saved object id of the action. + type: string + summary: + description: A summery of the event. + type: string + maxLength: 1024 + timestamp: + description: An ISO-8601 timestamp that indicates when the event was detected or generated. + type: string + format: date-time run_connector_subaction_addevent: title: The addEvent subaction type: object @@ -3525,9 +3697,9 @@ components: type: object description: The custom properties of the alert. additionalProperties: true - example: - key1: value1 - key2: value2 + examples: + - key1: value1 + key2: value2 entity: type: string description: The domain of the alert. For example, the application or server name. @@ -3625,7 +3797,8 @@ components: id: type: string description: The Jira issue type identifier. - example: 10024 + examples: + - 10024 run_connector_subaction_getchoices: title: The getChoices subaction type: object @@ -3683,7 +3856,8 @@ components: externalId: type: string description: The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier. - example: 71778 + examples: + - 71778 run_connector_subaction_issue: title: The issue subaction type: object @@ -3704,7 +3878,8 @@ components: id: type: string description: The Jira issue identifier. - example: 71778 + examples: + - 71778 run_connector_subaction_issues: title: The issues subaction type: object @@ -3877,9 +4052,11 @@ components: properties: params: oneOf: + - $ref: '#/components/schemas/run_connector_params_acknowledge_resolve_pagerduty' - $ref: '#/components/schemas/run_connector_params_documents' - $ref: '#/components/schemas/run_connector_params_message_email' - $ref: '#/components/schemas/run_connector_params_message_serverlog' + - $ref: '#/components/schemas/run_connector_params_trigger_pagerduty' - title: Subaction parameters description: Test an action that involves a subaction. oneOf: @@ -3933,7 +4110,8 @@ components: - .torq - .webhook - .xmatters - example: .server-log + examples: + - .server-log action_response_properties: title: Action response properties description: The properties vary depending on the action type. @@ -4110,6 +4288,17 @@ components: value: params: subAction: issueTypes + run_pagerduty_connector_request: + summary: Run a PagerDuty connector to trigger an alert. + value: + params: + eventAction: trigger + summary: A brief event summary + links: + - href: http://example.com/pagerduty + text: An example link + customDetails: + my_data_1: test data run_server_log_connector_request: summary: Run a server log connector. value: @@ -4201,6 +4390,15 @@ components: - id: 10000 name: Epic status: ok + run_pagerduty_connector_response: + summary: Response from running a PagerDuty connector. + value: + connector_id: 45de9f70-954f-4608-b12a-db7cf808e49d + data: + dedup_key: 5115e138b26b484a81eaea779faa6016 + message: Event processed + status: success + status: ok run_server_log_connector_response: summary: Response from running a server log connector. value: @@ -4347,14 +4545,16 @@ components: properties: error: type: string - example: Unauthorized + examples: + - Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 enum: - 401 '404': @@ -4367,15 +4567,18 @@ components: properties: error: type: string - example: Not Found + examples: + - Not Found enum: - Not Found message: type: string - example: Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found + examples: + - Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found statusCode: type: integer - example: 404 + examples: + - 404 enum: - 404 200_actions: diff --git a/x-pack/plugins/actions/docs/openapi/bundled_serverless.json b/x-pack/plugins/actions/docs/openapi/bundled_serverless.json index dadcc4cc0876..769fdf2d258e 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled_serverless.json +++ b/x-pack/plugins/actions/docs/openapi/bundled_serverless.json @@ -1,9 +1,9 @@ { - "openapi": "3.0.1", + "openapi": "3.1.0", "info": { "title": "Connectors", "description": "OpenAPI schema for connectors in Serverless projects", - "version": "0.1", + "version": "0.2", "contact": { "name": "Connectors Team" }, @@ -180,7 +180,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } } ], @@ -336,34 +338,46 @@ "enabled": { "type": "boolean", "description": "Indicates whether the connector type is enabled in Kibana.", - "example": true + "examples": [ + true + ] }, "enabled_in_config": { "type": "boolean", "description": "Indicates whether the connector type is enabled in the Kibana configuration file.", - "example": true + "examples": [ + true + ] }, "enabled_in_license": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "example": true + "examples": [ + true + ] }, "id": { "$ref": "#/components/schemas/connector_types" }, "is_system_action_type": { "type": "boolean", - "example": false + "examples": [ + false + ] }, "minimum_license_required": { "type": "string", "description": "The license that is required to use the connector type.", - "example": "basic" + "examples": [ + "basic" + ] }, "name": { "type": "string", "description": "The name of the connector type.", - "example": "Index" + "examples": [ + "Index" + ] }, "supported_feature_ids": { "type": "array", @@ -371,10 +385,12 @@ "items": { "$ref": "#/components/schemas/features" }, - "example": [ - "alerting", - "cases", - "siem" + "examples": [ + [ + "alerting", + "cases", + "siem" + ] ] } } @@ -400,7 +416,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "parameters": { @@ -420,7 +437,9 @@ "required": true, "schema": { "type": "string", - "example": "df770e30-8b8b-11ed-a780-3b746c987a81" + "examples": [ + "df770e30-8b8b-11ed-a780-3b746c987a81" + ] } } }, @@ -483,12 +502,16 @@ "enum": [ ".bedrock" ], - "example": ".bedrock" + "examples": [ + ".bedrock" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_bedrock" @@ -513,11 +536,13 @@ "createCommentJson": { "type": "string", "description": "A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "example": { - "body": { - "[object Object]": null + "examples": [ + { + "body": { + "[object Object]": null + } } - } + ] }, "createCommentMethod": { "type": "string", @@ -532,24 +557,28 @@ "createCommentUrl": { "type": "string", "description": "The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment" + ] }, "createIncidentJson": { "type": "string", "description": "A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "example": { - "fields": { - "summary": { - "[object Object]": null - }, - "description": { - "[object Object]": null - }, - "labels": { - "[object Object]": null + "examples": [ + { + "fields": { + "summary": { + "[object Object]": null + }, + "description": { + "[object Object]": null + }, + "labels": { + "[object Object]": null + } } } - } + ] }, "createIncidentMethod": { "type": "string", @@ -576,7 +605,9 @@ "getIncidentUrl": { "type": "string", "description": "The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}" + ] }, "hasAuth": { "type": "boolean", @@ -590,19 +621,21 @@ "updateIncidentJson": { "type": "string", "description": "The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "example": { - "fields": { - "summary": { - "[object Object]": null - }, - "description": { - "[object Object]": null - }, - "labels": { - "[object Object]": null + "examples": [ + { + "fields": { + "summary": { + "[object Object]": null + }, + "description": { + "[object Object]": null + }, + "labels": { + "[object Object]": null + } } } - } + ] }, "updateIncidentMethod": { "type": "string", @@ -617,12 +650,16 @@ "updateIncidentUrl": { "type": "string", "description": "The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts.\n", - "example": "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}}" + "examples": [ + "https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}}" + ] }, "viewIncidentUrl": { "type": "string", "description": "The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL.\n", - "example": "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" + "examples": [ + "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" + ] } } }, @@ -659,12 +696,16 @@ "enum": [ ".cases-webhook" ], - "example": ".cases-webhook" + "examples": [ + ".cases-webhook" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -719,12 +760,16 @@ "enum": [ ".d3security" ], - "example": ".d3security" + "examples": [ + ".d3security" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_d3security" @@ -741,8 +786,10 @@ "properties": { "clientId": { "description": "The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "from": { "description": "The from address for all emails sent by the connector. It must be specified in `user@host-name` format.\n", @@ -758,8 +805,10 @@ "type": "string" }, "oauthTokenUrl": { - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "port": { "description": "The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", @@ -783,8 +832,10 @@ }, "tenantId": { "description": "The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -827,12 +878,16 @@ "enum": [ ".email" ], - "example": ".email" + "examples": [ + ".email" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_email" @@ -923,12 +978,16 @@ "enum": [ ".gen-ai" ], - "example": ".gen-ai" + "examples": [ + ".gen-ai" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_genai" @@ -946,8 +1005,10 @@ "executionTimeField": { "description": "A field that indicates when the document was indexed.", "default": null, - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "index": { "description": "The Elasticsearch index to be written to.", @@ -979,12 +1040,16 @@ "enum": [ ".index" ], - "example": ".index" + "examples": [ + ".index" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] } } }, @@ -1046,12 +1111,16 @@ "enum": [ ".jira" ], - "example": ".jira" + "examples": [ + ".jira" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_jira" @@ -1106,12 +1175,16 @@ "enum": [ ".opsgenie" ], - "example": ".opsgenie" + "examples": [ + ".opsgenie" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_opsgenie" @@ -1125,9 +1198,13 @@ "properties": { "apiUrl": { "description": "The PagerDuty event URL.", - "type": "string", - "nullable": true, - "example": "https://events.pagerduty.com/v2/enqueue" + "type": [ + "string", + "null" + ], + "examples": [ + "https://events.pagerduty.com/v2/enqueue" + ] } } }, @@ -1165,12 +1242,16 @@ "enum": [ ".pagerduty" ], - "example": ".pagerduty" + "examples": [ + ".pagerduty" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_pagerduty" @@ -1232,7 +1313,9 @@ "connector_type_id": { "description": "The type of connector.", "type": "string", - "example": ".resilient", + "examples": [ + ".resilient" + ], "enum": [ ".resilient" ] @@ -1240,7 +1323,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_resilient" @@ -1262,12 +1347,16 @@ "enum": [ ".server-log" ], - "example": ".server-log" + "examples": [ + ".server-log" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] } } }, @@ -1354,12 +1443,16 @@ "enum": [ ".servicenow" ], - "example": ".servicenow" + "examples": [ + ".servicenow" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -1417,12 +1510,16 @@ "enum": [ ".servicenow-itom" ], - "example": ".servicenow-itom" + "examples": [ + ".servicenow-itom" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -1449,12 +1546,16 @@ "enum": [ ".servicenow-sir" ], - "example": ".servicenow-sir" + "examples": [ + ".servicenow-sir" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -1491,12 +1592,16 @@ "enum": [ ".slack_api" ], - "example": ".slack_api" + "examples": [ + ".slack_api" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_api" @@ -1533,12 +1638,16 @@ "enum": [ ".slack" ], - "example": ".slack" + "examples": [ + ".slack" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_webhook" @@ -1815,12 +1924,16 @@ "enum": [ ".swimlane" ], - "example": ".swimlane" + "examples": [ + ".swimlane" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -1857,12 +1970,16 @@ "enum": [ ".teams" ], - "example": ".teams" + "examples": [ + ".teams" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_teams" @@ -1922,12 +2039,16 @@ "enum": [ ".tines" ], - "example": ".tines" + "examples": [ + ".tines" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_tines" @@ -1982,12 +2103,16 @@ "enum": [ ".torq" ], - "example": ".torq" + "examples": [ + ".torq" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_torq" @@ -2025,8 +2150,10 @@ "description": "If `true`, a user name and password must be provided for login type authentication.\n" }, "headers": { - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "description": "A set of key-value pairs sent as headers with the request." }, "method": { @@ -2101,12 +2228,16 @@ "enum": [ ".webhook" ], - "example": ".webhook" + "examples": [ + ".webhook" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_webhook" @@ -2120,8 +2251,10 @@ "properties": { "configUrl": { "description": "The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`.\n", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "usesBasic": { "description": "Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`).", @@ -2169,12 +2302,16 @@ "enum": [ ".xmatters" ], - "example": ".xmatters" + "examples": [ + ".xmatters" + ] }, "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_xmatters" @@ -2259,22 +2396,30 @@ "is_deprecated": { "type": "boolean", "description": "Indicates whether the connector type is deprecated.", - "example": false + "examples": [ + false + ] }, "is_missing_secrets": { "type": "boolean", "description": "Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.", - "example": false + "examples": [ + false + ] }, "is_preconfigured": { "type": "boolean", "description": "Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. \n", - "example": false + "examples": [ + false + ] }, "is_system_action": { "type": "boolean", "description": "Indicates whether the connector is used for system actions.", - "example": false + "examples": [ + false + ] }, "connector_response_properties_bedrock": { "title": "Connector response properties for an Amazon Bedrock connector", @@ -2323,7 +2468,9 @@ "referenced_by_count": { "type": "integer", "description": "Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API.\n", - "example": 2 + "examples": [ + 2 + ] }, "connector_response_properties_cases_webhook": { "title": "Connector request properties for a Webhook - Case Management connector", @@ -2705,8 +2852,10 @@ ], "properties": { "config": { - "type": "object", - "nullable": true + "type": [ + "object", + "null" + ] }, "connector_type_id": { "type": "string", @@ -3346,7 +3495,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -3599,7 +3750,9 @@ "name": { "type": "string", "description": "The display name for the connector.", - "example": "my-connector" + "examples": [ + "my-connector" + ] }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -3815,7 +3968,9 @@ ".webhook", ".xmatters" ], - "example": ".server-log" + "examples": [ + ".server-log" + ] } }, "examples": { @@ -4048,7 +4203,9 @@ "properties": { "error": { "type": "string", - "example": "Unauthorized", + "examples": [ + "Unauthorized" + ], "enum": [ "Unauthorized" ] @@ -4058,7 +4215,9 @@ }, "statusCode": { "type": "integer", - "example": 401, + "examples": [ + 401 + ], "enum": [ 401 ] @@ -4078,18 +4237,24 @@ "properties": { "error": { "type": "string", - "example": "Not Found", + "examples": [ + "Not Found" + ], "enum": [ "Not Found" ] }, "message": { "type": "string", - "example": "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + "examples": [ + "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + ] }, "statusCode": { "type": "integer", - "example": 404, + "examples": [ + 404 + ], "enum": [ 404 ] diff --git a/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml b/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml index fbe684c35fe4..15a9dfb0be29 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Connectors description: OpenAPI schema for connectors in Serverless projects - version: '0.1' + version: '0.2' contact: name: Connectors Team license: @@ -111,7 +111,8 @@ paths: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -210,37 +211,43 @@ paths: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - example: true + examples: + - true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana configuration file. - example: true + examples: + - true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: $ref: '#/components/schemas/connector_types' is_system_action_type: type: boolean - example: false + examples: + - false minimum_license_required: type: string description: The license that is required to use the connector type. - example: basic + examples: + - basic name: type: string description: The name of the connector type. - example: Index + examples: + - Index supported_feature_ids: type: array description: The features that are supported by the connector type. items: $ref: '#/components/schemas/features' - example: - - alerting - - cases - - siem + examples: + - - alerting + - cases + - siem examples: getConnectorTypesServerlessResponse: $ref: '#/components/examples/get_connector_types_generativeai_response' @@ -251,7 +258,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -267,7 +275,8 @@ components: required: true schema: type: string - example: df770e30-8b8b-11ed-a780-3b746c987a81 + examples: + - df770e30-8b8b-11ed-a780-3b746c987a81 schemas: config_properties_bedrock: title: Connector request properties for an Amazon Bedrock connector @@ -315,11 +324,13 @@ components: description: The type of connector. enum: - .bedrock - example: .bedrock + examples: + - .bedrock name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_bedrock' config_properties_cases_webhook: @@ -340,9 +351,9 @@ components: type: string description: | A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: - body: - '[object Object]': null + examples: + - body: + '[object Object]': null createCommentMethod: type: string description: | @@ -356,19 +367,20 @@ components: type: string description: | The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: | A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: - fields: - summary: - '[object Object]': null - description: - '[object Object]': null - labels: - '[object Object]': null + examples: + - fields: + summary: + '[object Object]': null + description: + '[object Object]': null + labels: + '[object Object]': null createIncidentMethod: type: string description: | @@ -392,7 +404,8 @@ components: type: string description: | The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -405,14 +418,14 @@ components: type: string description: | The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: - fields: - summary: - '[object Object]': null - description: - '[object Object]': null - labels: - '[object Object]': null + examples: + - fields: + summary: + '[object Object]': null + description: + '[object Object]': null + labels: + '[object Object]': null updateIncidentMethod: type: string description: | @@ -426,12 +439,14 @@ components: type: string description: | The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: | The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + examples: + - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} secrets_properties_cases_webhook: title: Connector secrets properties for Webhook - Case Management connector type: object @@ -459,11 +474,13 @@ components: description: The type of connector. enum: - .cases-webhook - example: .cases-webhook + examples: + - .cases-webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' config_properties_d3security: @@ -505,11 +522,13 @@ components: description: The type of connector. enum: - .d3security - example: .d3security + examples: + - .d3security name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_d3security' config_properties_email: @@ -522,8 +541,9 @@ components: clientId: description: | The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true + type: + - string + - 'null' from: description: | The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -538,8 +558,9 @@ components: The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. type: string oauthTokenUrl: - type: string - nullable: true + type: + - string + - 'null' port: description: | The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. @@ -562,8 +583,9 @@ components: tenantId: description: | The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true + type: + - string + - 'null' secrets_properties_email: title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. @@ -599,11 +621,13 @@ components: description: The type of connector. enum: - .email - example: .email + examples: + - .email name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_email' config_properties_genai: @@ -667,11 +691,13 @@ components: description: The type of connector. enum: - .gen-ai - example: .gen-ai + examples: + - .gen-ai name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_genai' config_properties_index: @@ -684,8 +710,9 @@ components: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: string - nullable: true + type: + - string + - 'null' index: description: The Elasticsearch index to be written to. type: string @@ -710,11 +737,13 @@ components: description: The type of connector. enum: - .index - example: .index + examples: + - .index name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector config_properties_jira: title: Connector request properties for a Jira connector required: @@ -760,11 +789,13 @@ components: description: The type of connector. enum: - .jira - example: .jira + examples: + - .jira name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_jira' config_properties_opsgenie: @@ -805,11 +836,13 @@ components: description: The type of connector. enum: - .opsgenie - example: .opsgenie + examples: + - .opsgenie name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_opsgenie' config_properties_pagerduty: @@ -819,9 +852,11 @@ components: properties: apiUrl: description: The PagerDuty event URL. - type: string - nullable: true - example: https://events.pagerduty.com/v2/enqueue + type: + - string + - 'null' + examples: + - https://events.pagerduty.com/v2/enqueue secrets_properties_pagerduty: title: Connector secrets properties for a PagerDuty connector description: Defines secrets for connectors when type is `.pagerduty`. @@ -851,11 +886,13 @@ components: description: The type of connector. enum: - .pagerduty - example: .pagerduty + examples: + - .pagerduty name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_pagerduty' config_properties_resilient: @@ -901,13 +938,15 @@ components: connector_type_id: description: The type of connector. type: string - example: .resilient + examples: + - .resilient enum: - .resilient name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_resilient' create_connector_request_serverlog: @@ -923,11 +962,13 @@ components: description: The type of connector. enum: - .server-log - example: .server-log + examples: + - .server-log name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector config_properties_servicenow: title: Connector request properties for a ServiceNow ITSM connector required: @@ -998,11 +1039,13 @@ components: description: The type of connector. enum: - .servicenow - example: .servicenow + examples: + - .servicenow name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' config_properties_servicenow_itom: @@ -1050,11 +1093,13 @@ components: description: The type of connector. enum: - .servicenow-itom - example: .servicenow-itom + examples: + - .servicenow-itom name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_sir: @@ -1075,11 +1120,13 @@ components: description: The type of connector. enum: - .servicenow-sir - example: .servicenow-sir + examples: + - .servicenow-sir name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' secrets_properties_slack_api: @@ -1106,11 +1153,13 @@ components: description: The type of connector. enum: - .slack_api - example: .slack_api + examples: + - .slack_api name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_api' secrets_properties_slack_webhook: @@ -1137,11 +1186,13 @@ components: description: The type of connector. enum: - .slack - example: .slack + examples: + - .slack name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_webhook' config_properties_swimlane: @@ -1350,11 +1401,13 @@ components: description: The type of connector. enum: - .swimlane - example: .swimlane + examples: + - .swimlane name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' secrets_properties_teams: @@ -1382,11 +1435,13 @@ components: description: The type of connector. enum: - .teams - example: .teams + examples: + - .teams name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_teams' config_properties_tines: @@ -1432,11 +1487,13 @@ components: description: The type of connector. enum: - .tines - example: .tines + examples: + - .tines name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_tines' config_properties_torq: @@ -1477,11 +1534,13 @@ components: description: The type of connector. enum: - .torq - example: .torq + examples: + - .torq name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_torq' config_properties_webhook: @@ -1513,8 +1572,9 @@ components: description: | If `true`, a user name and password must be provided for login type authentication. headers: - type: object - nullable: true + type: + - object + - 'null' description: A set of key-value pairs sent as headers with the request. method: type: string @@ -1577,11 +1637,13 @@ components: description: The type of connector. enum: - .webhook - example: .webhook + examples: + - .webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_webhook' config_properties_xmatters: @@ -1592,8 +1654,9 @@ components: configUrl: description: | The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: string - nullable: true + type: + - string + - 'null' usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean @@ -1633,11 +1696,13 @@ components: description: The type of connector. enum: - .xmatters - example: .xmatters + examples: + - .xmatters name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_xmatters' create_connector_request: @@ -1671,20 +1736,24 @@ components: is_deprecated: type: boolean description: Indicates whether the connector type is deprecated. - example: false + examples: + - false is_missing_secrets: type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. - example: false + examples: + - false is_preconfigured: type: boolean description: | Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. - example: false + examples: + - false is_system_action: type: boolean description: Indicates whether the connector is used for system actions. - example: false + examples: + - false connector_response_properties_bedrock: title: Connector response properties for an Amazon Bedrock connector type: object @@ -1721,7 +1790,8 @@ components: type: integer description: | Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. - example: 2 + examples: + - 2 connector_response_properties_cases_webhook: title: Connector request properties for a Webhook - Case Management connector type: object @@ -1997,8 +2067,9 @@ components: - name properties: config: - type: object - nullable: true + type: + - object + - 'null' connector_type_id: type: string description: The type of connector. @@ -2432,7 +2503,8 @@ components: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' update_connector_request_d3security: @@ -2612,7 +2684,8 @@ components: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' update_connector_request_teams: @@ -2749,7 +2822,8 @@ components: - .torq - .webhook - .xmatters - example: .server-log + examples: + - .server-log examples: create_email_connector_request: summary: Create an email connector. @@ -2932,14 +3006,16 @@ components: properties: error: type: string - example: Unauthorized + examples: + - Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 enum: - 401 '404': @@ -2952,14 +3028,17 @@ components: properties: error: type: string - example: Not Found + examples: + - Not Found enum: - Not Found message: type: string - example: Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found + examples: + - Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found statusCode: type: integer - example: 404 + examples: + - 404 enum: - 404 diff --git a/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_request.yaml b/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_request.yaml new file mode 100644 index 000000000000..8124aac245ec --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_request.yaml @@ -0,0 +1,10 @@ +summary: Run a PagerDuty connector to trigger an alert. +value: + params: + eventAction: trigger + summary: A brief event summary + links: + - href: http://example.com/pagerduty + text: An example link + customDetails: + my_data_1: test data \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_response.yaml b/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_response.yaml new file mode 100644 index 000000000000..81e941ce52a4 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/examples/run_pagerduty_connector_response.yaml @@ -0,0 +1,8 @@ +summary: Response from running a PagerDuty connector. +value: + connector_id: 45de9f70-954f-4608-b12a-db7cf808e49d + data: + dedup_key: 5115e138b26b484a81eaea779faa6016 + message: Event processed + status: success + status: ok \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml index 3ee0b642c9de..acbc6ab5acd6 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the action. required: true schema: type: string - example: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + examples: + - c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml index d98c2cec803f..fdf1487e626a 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the connector. required: true schema: type: string - example: df770e30-8b8b-11ed-a780-3b746c987a81 + examples: + - df770e30-8b8b-11ed-a780-3b746c987a81 diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml index 0a9fba457e3e..45787e844cae 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the space. If `/s/` and the identifier are omitte required: true schema: type: string - example: default + examples: + - default diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml index 263623dd1fb4..4f8890737ff4 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml @@ -6,10 +6,13 @@ content: properties: error: type: string - example: Bad Request + examples: + - Bad Request message: type: string - example: "error validating action type config: [index]: expected value of type [string] but got [undefined]" + examples: + - "error validating action type config: [index]: expected value of type [string] but got [undefined]" statusCode: type: integer - example: 400 \ No newline at end of file + examples: + - 400 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml index ff5cbfd4c276..78b77b3ab5f4 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml @@ -7,13 +7,15 @@ content: properties: error: type: string - example: Unauthorized + examples: + - Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 enum: - 401 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml index 56964c6015c8..d4cf816f5903 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml @@ -7,14 +7,17 @@ content: properties: error: type: string - example: Not Found + examples: + - Not Found enum: - Not Found message: type: string - example: "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + examples: + - "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" statusCode: type: integer - example: 404 + examples: + - 404 enum: - 404 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml index 43945fbb241a..81c94bd3e880 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml @@ -22,7 +22,8 @@ properties: connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: {"body": {{{case.comment}}}} + examples: + - {"body": {{{case.comment}}}} createCommentMethod: type: string description: > @@ -40,7 +41,8 @@ properties: You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: > @@ -52,7 +54,8 @@ properties: connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: {"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}} + examples: + - {"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}} createIncidentMethod: type: string description: > @@ -86,7 +89,8 @@ properties: variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -107,7 +111,8 @@ properties: connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - example: {"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}} + examples: + - {"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}} updateIncidentMethod: type: string description: > @@ -124,12 +129,14 @@ properties: The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - example: https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} + examples: + - https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: > The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + examples: + - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml index 6d3618e2bba2..202f4022a6fb 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml @@ -8,8 +8,9 @@ properties: description: > The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true + type: + - "string" + - "null" from: description: > The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -27,8 +28,9 @@ properties: type: string oauthTokenUrl: # description: TBD - type: string - nullable: true + type: + - "string" + - "null" port: description: > The port to connect to on the service provider. @@ -55,5 +57,6 @@ properties: description: > The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: string - nullable: true \ No newline at end of file + type: + - "string" + - "null" \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml index 6c335b166d20..f6d3af59b493 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml @@ -7,8 +7,9 @@ properties: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: string - nullable: true + type: + - "string" + - "null" index: description: The Elasticsearch index to be written to. type: string diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml index 562557f548ec..bfbec7b46190 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml @@ -4,6 +4,8 @@ type: object properties: apiUrl: description: The PagerDuty event URL. - type: string - nullable: true - example: https://events.pagerduty.com/v2/enqueue \ No newline at end of file + type: + - "string" + - "null" + examples: + - https://events.pagerduty.com/v2/enqueue \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml index fe45366eca26..601d41066657 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml @@ -27,8 +27,9 @@ properties: description: > If `true`, a user name and password must be provided for login type authentication. headers: - type: object - nullable: true + type: + - "object" + - "null" description: A set of key-value pairs sent as headers with the request. method: type: string diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml index 350e96f3aa63..3393c11ecd90 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml @@ -6,8 +6,9 @@ properties: description: > The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: string - nullable: true + type: + - "string" + - "null" usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml index a397e668102a..da741478864b 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml @@ -8,8 +8,9 @@ required: - name properties: config: - type: object - nullable: true + type: + - "object" + - "null" connector_type_id: type: string description: The type of connector. diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml index 5d0bc42ab831..dff10fcc778d 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml @@ -24,4 +24,5 @@ enum: - .torq - .webhook - .xmatters -example: .server-log \ No newline at end of file +examples: + - .server-log \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml index 2acc21bfbfac..e8feecb0051c 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml @@ -14,10 +14,12 @@ properties: description: The type of connector. enum: - .bedrock - example: .bedrock + examples: + - .bedrock name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_bedrock.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml index bcbe840c0351..0cd030d74080 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml @@ -15,10 +15,12 @@ properties: description: The type of connector. enum: - .cases-webhook - example: .cases-webhook + examples: + - .cases-webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_cases_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml index 39cdda80b7dd..6b5389cc80f3 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml @@ -15,10 +15,12 @@ properties: description: The type of connector. enum: - .d3security - example: .d3security + examples: + - .d3security name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_d3security.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml index 89f0b79c4e74..1f1c6c079770 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml @@ -18,10 +18,12 @@ properties: description: The type of connector. enum: - .email - example: .email + examples: + - .email name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_email.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml index 95d65bdb8091..725f842f9109 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .gen-ai - example: .gen-ai + examples: + - .gen-ai name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_genai.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml index 26d6e118c1fe..ad8e9be9a41d 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml @@ -13,8 +13,10 @@ properties: description: The type of connector. enum: - .index - example: .index + examples: + - .index name: type: string description: The display name for the connector. - example: my-connector \ No newline at end of file + examples: + - my-connector \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml index 5b6077e875b2..95ccaa5b2ec6 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml @@ -14,10 +14,12 @@ properties: description: The type of connector. enum: - .jira - example: .jira + examples: + - .jira name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_jira.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml index 6de1296dac43..51c29f5cdd8f 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml @@ -14,10 +14,12 @@ properties: description: The type of connector. enum: - .opsgenie - example: .opsgenie + examples: + - .opsgenie name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_opsgenie.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml index 498488299afd..66ffc61d30f3 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .pagerduty - example: .pagerduty + examples: + - .pagerduty name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_pagerduty.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml index c3f766625b7d..60467336c0d9 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml @@ -12,12 +12,14 @@ properties: connector_type_id: description: The type of connector. type: string - example: .resilient + examples: + - .resilient enum: - .resilient name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_resilient.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml index eac0a0d65b69..0cb85403663c 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml @@ -10,8 +10,10 @@ properties: description: The type of connector. enum: - .server-log - example: .server-log + examples: + - .server-log name: type: string description: The display name for the connector. - example: my-connector \ No newline at end of file + examples: + - my-connector \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml index e03303dcada4..b0f35483cc39 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .servicenow - example: .servicenow + examples: + - .servicenow name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml index 70a4c05c9652..bfbeb231ca7d 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .servicenow-itom - example: .servicenow-itom + examples: + - .servicenow-itom name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml index 4d247c456f3e..37519eb63f27 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .servicenow-sir - example: .servicenow-sir + examples: + - .servicenow-sir name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml index a16ba7416e7b..07dbadbef989 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml @@ -11,10 +11,12 @@ properties: description: The type of connector. enum: - .slack_api - example: .slack_api + examples: + - .slack_api name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_slack_api.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml index 1c046cc3f000..3e884daa6e3b 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml @@ -11,10 +11,12 @@ properties: description: The type of connector. enum: - .slack - example: .slack + examples: + - .slack name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_slack_webhook.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml index 3de4f5ecbcce..633438a721ee 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml @@ -14,10 +14,12 @@ properties: description: The type of connector. enum: - .swimlane - example: .swimlane + examples: + - .swimlane name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_swimlane.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml index 5e0d449bf554..787f057c09ce 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml @@ -11,10 +11,12 @@ properties: description: The type of connector. enum: - .teams - example: .teams + examples: + - .teams name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_teams.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml index 224c3e03c436..c5333c8acc47 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml @@ -15,10 +15,12 @@ properties: description: The type of connector. enum: - .tines - example: .tines + examples: + - .tines name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_tines.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml index 934f9c9c1b39..a4ab3cc92aa0 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml @@ -15,10 +15,12 @@ properties: description: The type of connector. enum: - .torq - example: .torq + examples: + - .torq name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_torq.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml index e0ead115d48d..30e9663da8d9 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml @@ -15,10 +15,12 @@ properties: description: The type of connector. enum: - .webhook - example: .webhook + examples: + - .webhook name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml index 13213d39561b..753888b16ae5 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml @@ -16,10 +16,12 @@ properties: description: The type of connector. enum: - .xmatters - example: .xmatters + examples: + - .xmatters name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_xmatters.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml index 75fb1efe2f58..ac0a26102eed 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml @@ -1,3 +1,4 @@ type: boolean description: Indicates whether the connector type is deprecated. -example: false \ No newline at end of file +examples: + - false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml index cad03a44f862..a7ad3f9542b3 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml @@ -1,3 +1,4 @@ type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. -example: false \ No newline at end of file +examples: + - false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml index e38741c83718..d3f711c22939 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml @@ -2,4 +2,5 @@ type: boolean description: > Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. -example: false \ No newline at end of file +examples: + - false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml index fd0dd06ef5ff..5a78f4676646 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml @@ -1,3 +1,4 @@ type: boolean description: Indicates whether the connector is used for system actions. -example: false \ No newline at end of file +examples: + - false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml index 61579fa3dc6c..0a65bf9a854f 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml @@ -3,4 +3,5 @@ description: > Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. -example: 2 \ No newline at end of file +examples: + - 2 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_acknowledge_resolve_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_acknowledge_resolve_pagerduty.yaml new file mode 100644 index 000000000000..d5e9087cdb7b --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_acknowledge_resolve_pagerduty.yaml @@ -0,0 +1,17 @@ +title: PagerDuty connector parameters +description: Test an action that acknowledges or resolves a PagerDuty alert. +type: object +required: + - dedupKey + - eventAction +properties: + dedupKey: + description: The deduplication key for the PagerDuty alert. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - acknowledge + - resolve \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml new file mode 100644 index 000000000000..75a59af15626 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml @@ -0,0 +1,69 @@ +title: PagerDuty connector parameters +description: Test an action that triggers a PagerDuty alert. +type: object +required: + - eventAction +properties: + class: + description: The class or type of the event. + type: string + examples: + - cpu load + component: + description: The component of the source machine that is responsible for the event. + type: string + examples: + - eth0 + customDetails: + description: Additional details to add to the event. + type: object + dedupKey: + description: > + All actions sharing this key will be associated with the same PagerDuty alert. + This value is used to correlate trigger and resolution. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - trigger + group: + description: The logical grouping of components of a service. + type: string + examples: + - app-stack + links: + description: A list of links to add to the event. + type: array + items: + type: object + properties: + href: + description: The URL for the link. + type: string + text: + description: A plain text description of the purpose of the link. + type: string + severity: + description: The severity of the event on the affected system. + type: string + enum: + - critical + - error + - info + - warning + default: info + source: + description: > + The affected system, such as a hostname or fully qualified domain name. + Defaults to the Kibana saved object id of the action. + type: string + summary: + description: A summery of the event. + type: string + maxLength: 1024 + timestamp: + description: An ISO-8601 timestamp that indicates when the event was detected or generated. + type: string + format: date-time \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_request.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_request.yaml index 7602693cebe5..13b0623a01ab 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_request.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_request.yaml @@ -6,9 +6,11 @@ required: properties: params: oneOf: + - $ref: 'run_connector_params_acknowledge_resolve_pagerduty.yaml' - $ref: 'run_connector_params_documents.yaml' - $ref: 'run_connector_params_message_email.yaml' - $ref: 'run_connector_params_message_serverlog.yaml' + - $ref: 'run_connector_params_trigger_pagerduty.yaml' - title: Subaction parameters description: Test an action that involves a subaction. oneOf: diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml index e739a9ed6c91..a53560951361 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml @@ -30,7 +30,8 @@ properties: type: object description: The custom properties of the alert. additionalProperties: true - example: {"key1":"value1","key2":"value2"} + examples: + - {"key1":"value1","key2":"value2"} entity: type: string description: The domain of the alert. For example, the application or server name. diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml index e8c8869e7d68..6c39957c29fc 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml @@ -18,5 +18,6 @@ properties: id: type: string description: The Jira issue type identifier. - example: 10024 + examples: + - 10024 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml index 666c0257f68b..7a16f3d9f829 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml @@ -18,4 +18,5 @@ properties: externalId: type: string description: The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier. - example: 71778 + examples: + - 71778 diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml index 56ee923b4006..3743e7fa90bd 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml @@ -17,4 +17,5 @@ properties: id: type: string description: The Jira issue identifier. - example: 71778 \ No newline at end of file + examples: + - 71778 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml index 66250b31a94e..9201a1b1e1d7 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml @@ -9,6 +9,7 @@ properties: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_cases_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml index 81321351b74e..771625841a04 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml @@ -10,6 +10,7 @@ properties: name: type: string description: The display name for the connector. - example: my-connector + examples: + - my-connector secrets: $ref: 'secrets_properties_swimlane.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/entrypoint.yaml b/x-pack/plugins/actions/docs/openapi/entrypoint.yaml index bdbf408de3e1..d082d91a2a4e 100644 --- a/x-pack/plugins/actions/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/actions/docs/openapi/entrypoint.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Connectors description: OpenAPI schema for Connectors endpoints - version: '0.1' + version: '0.2' contact: name: Connectors Team license: @@ -51,7 +51,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - apiKeyAuth: [] diff --git a/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml b/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml index 3503221c4e30..4780a65da652 100644 --- a/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml +++ b/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Connectors description: OpenAPI schema for connectors in Serverless projects - version: '0.1' + version: '0.2' contact: name: Connectors Team license: @@ -30,6 +30,7 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - apiKeyAuth: [] diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml index e4b8e1c46864..6464b9592436 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml @@ -51,7 +51,8 @@ post: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml index 577a57fbb5d9..a276f30292da 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml @@ -23,6 +23,8 @@ post: $ref: '../components/examples/run_index_connector_request.yaml' runJiraConnectorRequest: $ref: '../components/examples/run_jira_connector_request.yaml' + runPagerDutyConnectorRequest: + $ref: '../components/examples/run_pagerduty_connector_request.yaml' runServerLogConnectorRequest: $ref: '../components/examples/run_server_log_connector_request.yaml' runServiceNowITOMConnectorRequest: @@ -65,6 +67,8 @@ post: $ref: '../components/examples/run_index_connector_response.yaml' runJiraConnectorResponse: $ref: '../components/examples/run_jira_connector_response.yaml' + runPagerDutyConnectorResponse: + $ref: '../components/examples/run_pagerduty_connector_response.yaml' runServerLogConnectorResponse: $ref: '../components/examples/run_server_log_connector_response.yaml' runServiceNowITOMConnectorResponse: diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml index 530fed05e304..94dbb727eea4 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml @@ -24,37 +24,41 @@ get: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - example: true + examples: + - true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana configuration file. - example: true + examples: + - true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: $ref: '../components/schemas/connector_types.yaml' is_system_action_type: type: boolean - example: false + examples: + - false minimum_license_required: type: string description: The license that is required to use the connector type. - example: basic + examples: + - basic name: type: string description: The name of the connector type. - example: Index + examples: + - Index supported_feature_ids: type: array description: The features that are supported by the connector type. items: $ref: '../components/schemas/features.yaml' - example: - - alerting - - cases - - siem + examples: + - [alerting, cases, siem] examples: getConnectorTypesServerlessResponse: $ref: '../components/examples/get_connector_types_generativeai_response.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml index 1d014404a643..27351f0954ee 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml @@ -59,7 +59,8 @@ post: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml index 86ef1cd5460f..9a0fababdf16 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml @@ -27,34 +27,37 @@ get: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - example: true + examples: + - true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana `.yml` file. - example: true + examples: + - true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: $ref: '../components/schemas/connector_types.yaml' minimum_license_required: type: string description: The license that is required to use the connector type. - example: basic + examples: + - basic name: type: string description: The name of the connector type. - example: Index + examples: + - Index supported_feature_ids: type: array description: The Kibana features that are supported by the connector type. items: $ref: '../components/schemas/features.yaml' - example: - - alerting - - uptime - - siem + examples: + - [alerting, uptime, siem] examples: getConnectorTypesResponse: $ref: '../components/examples/get_connector_types_response.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml index edda7d4aca31..6bc2b9e5e53a 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml @@ -28,7 +28,8 @@ get: enabledInLicense: type: boolean description: Indicates whether the connector is enabled in the license. - example: true + examples: + - true id: type: string description: The unique identifier for the connector type. diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 9b2fd5e987f6..9e277b908432 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -22,6 +22,7 @@ import { import { securityMock } from '@kbn/security-plugin/server/mocks'; import { finished } from 'stream/promises'; import { PassThrough } from 'stream'; +import { SecurityConnectorFeatureId } from '../../common'; const actionExecutor = new ActionExecutor({ isESOCanEncrypt: true }); const services = actionsMock.createServices(); @@ -839,6 +840,44 @@ test('successfully authorize system actions', async () => { }); }); +test('Execute of SentinelOne sub-actions require create privilege', async () => { + const actionType: jest.Mocked = { + id: '.sentinelone', + name: 'sentinelone', + minimumLicenseRequired: 'enterprise', + supportedFeatureIds: [SecurityConnectorFeatureId], + validate: { + config: { schema: schema.any() }, + secrets: { schema: schema.any() }, + params: { schema: schema.any() }, + }, + executor: jest.fn(), + }; + const actionSavedObject = { + id: '1', + type: 'action', + attributes: { + name: '1', + actionTypeId: '.sentinelone', + config: { + bar: true, + }, + secrets: { + baz: true, + }, + isMissingSecrets: false, + }, + references: [], + }; + + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject); + actionTypeRegistry.get.mockReturnValueOnce(actionType); + + await actionExecutor.execute({ ...executeParams, actionId: 'sentinel-one-connector-authz' }); + + expect(authorizationMock.ensureAuthorized).toHaveBeenCalledWith({ operation: 'create' }); +}); + test('pass the params to the actionTypeRegistry when authorizing system actions', async () => { const actionType: jest.Mocked = { id: '.cases', diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 9cd70d4c7bf9..fd1d8f92a048 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -8,12 +8,13 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { Logger, KibanaRequest } from '@kbn/core/server'; import { cloneDeep } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { withSpan } from '@kbn/apm-utils'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import { SpacesServiceStart } from '@kbn/spaces-plugin/server'; import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; -import { PassThrough, Readable } from 'stream'; +import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; import { validateParams, validateConfig, @@ -38,7 +39,6 @@ import { RelatedSavedObjects } from './related_saved_objects'; import { createActionEventLogRecordObject } from './create_action_event_log_record_object'; import { ActionExecutionError, ActionExecutionErrorReason } from './errors/action_execution_error'; import type { ActionsAuthorization } from '../authorization/actions_authorization'; -import { getTokenCountFromOpenAIStream } from './get_token_count_from_openai_stream'; // 1,000,000 nanoseconds in 1 millisecond const Millis2Nanos = 1000 * 1000; @@ -328,55 +328,33 @@ export class ActionExecutor { eventLogger.logEvent(event); } - // start openai extension - // add event.kibana.action.execution.openai to event log when OpenAI Connector is executed - if (result.status === 'ok' && actionTypeId === '.gen-ai') { - const data = result.data as unknown as { - usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number }; - }; - event.kibana = event.kibana || {}; - event.kibana.action = event.kibana.action || {}; - event.kibana = { - ...event.kibana, - action: { - ...event.kibana.action, - execution: { - ...event.kibana.action.execution, - gen_ai: { - usage: { - total_tokens: data.usage?.total_tokens, - prompt_tokens: data.usage?.prompt_tokens, - completion_tokens: data.usage?.completion_tokens, - }, - }, - }, - }, - }; - - if (result.data instanceof Readable) { - getTokenCountFromOpenAIStream({ - responseStream: result.data.pipe(new PassThrough()), - body: (validatedParams as { subActionParams: { body: string } }).subActionParams.body, + // start genai extension + if (result.status === 'ok' && shouldTrackGenAiToken(actionTypeId)) { + getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }) + .then((tokenTracking) => { + if (tokenTracking != null) { + set(event, 'kibana.action.execution.gen_ai.usage', { + total_tokens: tokenTracking.total_tokens, + prompt_tokens: tokenTracking.prompt_tokens, + completion_tokens: tokenTracking.completion_tokens, + }); + } }) - .then(({ total, prompt, completion }) => { - event.kibana!.action!.execution!.gen_ai!.usage = { - total_tokens: total, - prompt_tokens: prompt, - completion_tokens: completion, - }; - }) - .catch((err) => { - logger.error('Failed to calculate tokens from streaming response'); - logger.error(err); - }) - .finally(() => { - completeEventLogging(); - }); - - return resultWithoutError; - } + .catch((err) => { + logger.error('Failed to calculate tokens from streaming response'); + logger.error(err); + }) + .finally(() => { + completeEventLogging(); + }); + return resultWithoutError; } - // end openai extension + // end genai extension completeEventLogging(); @@ -589,6 +567,14 @@ const ensureAuthorizedToExecute = async ({ await authorization.ensureAuthorized({ operation: 'execute', additionalPrivileges }); } + + // SentinelOne sub-actions require that a user have `all` privilege to Actions and Connectors. + // This is a temporary solution until a more robust RBAC approach can be implemented for sub-actions + if (actionTypeId === '.sentinelone') { + await authorization.ensureAuthorized({ + operation: 'create', + }); + } } catch (error) { throw new ActionExecutionError(error.message, ActionExecutionErrorReason.Authorization, { actionId, diff --git a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts new file mode 100644 index 000000000000..888a00cd5ff4 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; +import { loggerMock } from '@kbn/logging-mocks'; +import { getTokenCountFromBedrockInvoke } from './get_token_count_from_bedrock_invoke'; +import { getTokenCountFromInvokeStream } from './get_token_count_from_invoke_stream'; +import { IncomingMessage } from 'http'; +import { Socket } from 'net'; + +jest.mock('./get_token_count_from_bedrock_invoke'); +jest.mock('./get_token_count_from_invoke_stream'); + +const logger = loggerMock.create(); + +describe('getGenAiTokenTracking', () => { + let mockGetTokenCountFromBedrockInvoke: jest.Mock; + let mockGetTokenCountFromInvokeStream: jest.Mock; + beforeEach(() => { + mockGetTokenCountFromBedrockInvoke = ( + getTokenCountFromBedrockInvoke as jest.Mock + ).mockResolvedValueOnce({ + total: 100, + prompt: 50, + completion: 50, + }); + mockGetTokenCountFromInvokeStream = ( + getTokenCountFromInvokeStream as jest.Mock + ).mockResolvedValueOnce({ + total: 100, + prompt: 50, + completion: 50, + }); + }); + it('should return the total, prompt, and completion token counts when given a valid OpenAI response', async () => { + const actionTypeId = '.gen-ai'; + + const result = { + actionId: '123', + status: 'ok' as const, + data: { + usage: { + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }, + }, + }; + const validatedParams = {}; + + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toEqual({ + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }); + expect(logger.error).not.toHaveBeenCalled(); + }); + + it('should return the total, prompt, and completion token counts when given a valid Bedrock response for run/test subactions', async () => { + const actionTypeId = '.bedrock'; + + const result = { + actionId: '123', + status: 'ok' as const, + data: { + completion: 'Sample completion', + }, + }; + const validatedParams = { + subAction: 'run', + subActionParams: { + body: 'Sample body', + }, + }; + + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toEqual({ + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }); + expect(logger.error).not.toHaveBeenCalled(); + expect(mockGetTokenCountFromBedrockInvoke).toHaveBeenCalledWith({ + response: 'Sample completion', + body: 'Sample body', + }); + }); + + it('should return the total, prompt, and completion token counts when given a valid Bedrock response for invokeAI subaction', async () => { + const actionTypeId = '.bedrock'; + + const result = { + actionId: '123', + status: 'ok' as const, + data: { + message: 'Sample completion', + }, + }; + const validatedParams = { + subAction: 'invokeAI', + subActionParams: { + messages: [ + { + role: 'user', + content: 'Sample message', + }, + ], + }, + }; + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toEqual({ + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }); + expect(logger.error).not.toHaveBeenCalled(); + expect(mockGetTokenCountFromBedrockInvoke).toHaveBeenCalledWith({ + response: 'Sample completion', + body: '{"prompt":"Sample message"}', + }); + }); + + it('should return the total, prompt, and completion token counts when given a valid OpenAI streamed response', async () => { + const mockReader = new IncomingMessage(new Socket()); + const actionTypeId = '.gen-ai'; + const result = { + actionId: '123', + status: 'ok' as const, + data: mockReader, + }; + const validatedParams = { + subAction: 'invokeStream', + subActionParams: { + messages: [ + { + role: 'user', + content: 'Sample message', + }, + ], + }, + }; + + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toEqual({ + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }); + expect(logger.error).not.toHaveBeenCalled(); + + expect(JSON.stringify(mockGetTokenCountFromInvokeStream.mock.calls[0][0].body)).toStrictEqual( + JSON.stringify({ + messages: [ + { + role: 'user', + content: 'Sample message', + }, + ], + }) + ); + }); + + it('should return null when given an invalid OpenAI response', async () => { + const actionTypeId = '.gen-ai'; + const result = { + actionId: '123', + status: 'ok' as const, + data: {}, + }; + const validatedParams = {}; + + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toBeNull(); + expect(logger.error).toHaveBeenCalled(); + }); + + describe('shouldTrackGenAiToken', () => { + it('should be true with OpenAI action', () => { + expect(shouldTrackGenAiToken('.gen-ai')).toEqual(true); + }); + it('should be true with bedrock action', () => { + expect(shouldTrackGenAiToken('.bedrock')).toEqual(true); + }); + it('should be false with any other action', () => { + expect(shouldTrackGenAiToken('.jira')).toEqual(false); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts new file mode 100644 index 000000000000..78dfe3ecb172 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PassThrough, Readable } from 'stream'; +import { Logger } from '@kbn/logging'; +import { getTokenCountFromBedrockInvoke } from './get_token_count_from_bedrock_invoke'; +import { ActionTypeExecutorRawResult } from '../../common'; +import { getTokenCountFromOpenAIStream } from './get_token_count_from_openai_stream'; +import { getTokenCountFromInvokeStream, InvokeBody } from './get_token_count_from_invoke_stream'; + +interface OwnProps { + actionTypeId: string; + logger: Logger; + result: ActionTypeExecutorRawResult; + validatedParams: Record; +} +/* + * Calculates the total, prompt, and completion token counts from different types of responses. + * It handles both streamed and non-streamed responses from OpenAI and Bedrock. + * It returns null if it cannot calculate the token counts. + * @param actionTypeId the action type id + * @param logger the logger + * @param result the result from the action executor + * @param validatedParams the validated params from the action executor + */ +export const getGenAiTokenTracking = async ({ + actionTypeId, + logger, + result, + validatedParams, +}: OwnProps): Promise<{ + total_tokens: number; + prompt_tokens: number; + completion_tokens: number; +} | null> => { + // this is a streamed OpenAI or Bedrock response, using the subAction invokeStream to stream the response as a simple string + if (validatedParams.subAction === 'invokeStream' && result.data instanceof Readable) { + try { + const { total, prompt, completion } = await getTokenCountFromInvokeStream({ + responseStream: result.data.pipe(new PassThrough()), + actionTypeId, + body: (validatedParams as { subActionParams: InvokeBody }).subActionParams, + logger, + }); + return { + total_tokens: total, + prompt_tokens: prompt, + completion_tokens: completion, + }; + } catch (e) { + logger.error('Failed to calculate tokens from Invoke Stream subaction streaming response'); + logger.error(e); + } + } + + // this is a streamed OpenAI response, which did not use the subAction invokeStream + if (actionTypeId === '.gen-ai' && result.data instanceof Readable) { + try { + const { total, prompt, completion } = await getTokenCountFromOpenAIStream({ + responseStream: result.data.pipe(new PassThrough()), + body: (validatedParams as { subActionParams: { body: string } }).subActionParams.body, + logger, + }); + return { + total_tokens: total, + prompt_tokens: prompt, + completion_tokens: completion, + }; + } catch (e) { + logger.error('Failed to calculate tokens from streaming response'); + logger.error(e); + } + } + + // this is a non-streamed OpenAI response, which comes with the usage object + if (actionTypeId === '.gen-ai') { + const data = result.data as unknown as { + usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number }; + }; + if (data.usage == null) { + logger.error('Response did not contain usage object'); + return null; + } + return { + total_tokens: data.usage?.total_tokens ?? 0, + prompt_tokens: data.usage?.prompt_tokens ?? 0, + completion_tokens: data.usage?.completion_tokens ?? 0, + }; + } + + // this is a non-streamed Bedrock response + if ( + actionTypeId === '.bedrock' && + (validatedParams.subAction === 'run' || validatedParams.subAction === 'test') + ) { + try { + const { total, prompt, completion } = await getTokenCountFromBedrockInvoke({ + response: ( + result.data as unknown as { + completion: string; + } + ).completion, + body: (validatedParams as { subActionParams: { body: string } }).subActionParams.body, + }); + + return { + total_tokens: total, + prompt_tokens: prompt, + completion_tokens: completion, + }; + } catch (e) { + logger.error('Failed to calculate tokens from Bedrock invoke response'); + logger.error(e); + } + } + + // this is a non-streamed Bedrock response used by security solution + if (actionTypeId === '.bedrock' && validatedParams.subAction === 'invokeAI') { + try { + const { total, prompt, completion } = await getTokenCountFromBedrockInvoke({ + response: ( + result.data as unknown as { + message: string; + } + ).message, + body: JSON.stringify({ + prompt: (validatedParams as { subActionParams: { messages: Array<{ content: string }> } }) + .subActionParams.messages[0].content, + }), + }); + + return { + total_tokens: total, + prompt_tokens: prompt, + completion_tokens: completion, + }; + } catch (e) { + logger.error('Failed to calculate tokens from Bedrock invoke response'); + logger.error(e); + } + } + return null; +}; + +export const shouldTrackGenAiToken = (actionTypeId: string) => + actionTypeId === '.gen-ai' || actionTypeId === '.bedrock'; diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.test.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.test.ts new file mode 100644 index 000000000000..efb0c2cd0eaf --- /dev/null +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.test.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getTokenCountFromBedrockInvoke } from './get_token_count_from_bedrock_invoke'; + +describe('getTokenCountFromBedrockInvoke', () => { + const body = JSON.stringify({ + prompt: `\n\nAssistant: This is a system message\n\nHuman: This is a user message\n\nAssistant:`, + }); + + const PROMPT_TOKEN_COUNT = 27; + const COMPLETION_TOKEN_COUNT = 4; + + it('counts the prompt tokens', async () => { + const tokens = await getTokenCountFromBedrockInvoke({ + response: 'This is a response', + body, + }); + expect(tokens.prompt).toBe(PROMPT_TOKEN_COUNT); + expect(tokens.completion).toBe(COMPLETION_TOKEN_COUNT); + expect(tokens.total).toBe(PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.ts new file mode 100644 index 000000000000..26e320200830 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_bedrock_invoke.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { encode } from 'gpt-tokenizer'; + +export interface InvokeBody { + prompt: string; +} + +/** + * Takes the Bedrock `run` and `test` sub action response and the request prompt as inputs. + * Uses gpt-tokenizer encoding to calculate the number of tokens in the prompt and completion. + * Returns an object containing the total, prompt, and completion token counts. + * @param response (string) - the response completion from the `run` or `test` sub action + * @param body - the stringified request prompt + */ +export async function getTokenCountFromBedrockInvoke({ + response, + body, +}: { + response: string; + body: string; +}): Promise<{ + total: number; + prompt: number; + completion: number; +}> { + const chatCompletionRequest = JSON.parse(body) as InvokeBody; + + // per https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb + const tokensFromMessages = encode(`<|start|>${chatCompletionRequest.prompt}<|end|>`).length; + + const promptTokens = tokensFromMessages; + + const completionTokens = encode(response).length; + + return { + prompt: promptTokens, + completion: completionTokens, + total: promptTokens + completionTokens, + }; +} diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts new file mode 100644 index 000000000000..2d8f86b88172 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Transform } from 'stream'; +import { getTokenCountFromInvokeStream } from './get_token_count_from_invoke_stream'; +import { loggerMock } from '@kbn/logging-mocks'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; + +function createStreamMock() { + const transform: Transform = new Transform({}); + + return { + write: (data: unknown) => { + transform.push(data); + }, + fail: () => { + transform.emit('error', new Error('Stream failed')); + transform.end(); + }, + transform, + complete: () => { + transform.end(); + }, + }; +} +const logger = loggerMock.create(); +describe('getTokenCountFromInvokeStream', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + let stream: ReturnType; + const body = { + messages: [ + { + role: 'system', + content: 'This is a system message', + }, + { + role: 'user', + content: 'This is a user message', + }, + ], + }; + + const chunk = { + object: 'chat.completion.chunk', + choices: [ + { + delta: { + content: 'Single.', + }, + }, + ], + }; + + const PROMPT_TOKEN_COUNT = 34; + const COMPLETION_TOKEN_COUNT = 2; + describe('OpenAI stream', () => { + beforeEach(() => { + stream = createStreamMock(); + stream.write(`data: ${JSON.stringify(chunk)}`); + }); + + it('counts the prompt + completion tokens for OpenAI response', async () => { + stream.complete(); + const tokens = await getTokenCountFromInvokeStream({ + responseStream: stream.transform, + body, + logger, + actionTypeId: '.gen-ai', + }); + expect(tokens.prompt).toBe(PROMPT_TOKEN_COUNT); + expect(tokens.completion).toBe(COMPLETION_TOKEN_COUNT); + expect(tokens.total).toBe(PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT); + }); + it('resolves the promise with the correct prompt tokens', async () => { + const tokenPromise = getTokenCountFromInvokeStream({ + responseStream: stream.transform, + body, + logger, + actionTypeId: '.gen-ai', + }); + + stream.fail(); + + await expect(tokenPromise).resolves.toEqual({ + prompt: PROMPT_TOKEN_COUNT, + total: PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT, + completion: COMPLETION_TOKEN_COUNT, + }); + expect(logger.error).toHaveBeenCalled(); + }); + }); + describe('Bedrock stream', () => { + beforeEach(() => { + stream = createStreamMock(); + stream.write(encodeBedrockResponse('Simple.')); + }); + + it('counts the prompt + completion tokens for OpenAI response', async () => { + stream.complete(); + const tokens = await getTokenCountFromInvokeStream({ + responseStream: stream.transform, + body, + logger, + actionTypeId: '.bedrock', + }); + expect(tokens.prompt).toBe(PROMPT_TOKEN_COUNT); + expect(tokens.completion).toBe(COMPLETION_TOKEN_COUNT); + expect(tokens.total).toBe(PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT); + }); + it('resolves the promise with the correct prompt tokens', async () => { + const tokenPromise = getTokenCountFromInvokeStream({ + responseStream: stream.transform, + body, + logger, + actionTypeId: '.bedrock', + }); + + stream.fail(); + + await expect(tokenPromise).resolves.toEqual({ + prompt: PROMPT_TOKEN_COUNT, + total: PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT, + completion: COMPLETION_TOKEN_COUNT, + }); + expect(logger.error).toHaveBeenCalled(); + }); + }); +}); + +function encodeBedrockResponse(completion: string) { + return new EventStreamCodec(toUtf8, fromUtf8).encode({ + headers: {}, + body: Uint8Array.from( + Buffer.from( + JSON.stringify({ + bytes: Buffer.from(JSON.stringify({ completion })).toString('base64'), + }) + ) + ), + }); +} diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts new file mode 100644 index 000000000000..dfb4bae69f8c --- /dev/null +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts @@ -0,0 +1,197 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from '@kbn/logging'; +import { encode } from 'gpt-tokenizer'; +import { Readable } from 'stream'; +import { finished } from 'stream/promises'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; + +export interface InvokeBody { + messages: Array<{ + role: string; + content: string; + }>; +} + +/** + * Takes the OpenAI and Bedrock `invokeStream` sub action response stream and the request messages array as inputs. + * Uses gpt-tokenizer encoding to calculate the number of tokens in the prompt and completion parts of the response stream + * Returns an object containing the total, prompt, and completion token counts. + * @param responseStream the response stream from the `invokeStream` sub action + * @param body the request messages array + * @param logger the logger + */ +export async function getTokenCountFromInvokeStream({ + actionTypeId, + responseStream, + body, + logger, +}: { + actionTypeId: string; + responseStream: Readable; + body: InvokeBody; + logger: Logger; +}): Promise<{ + total: number; + prompt: number; + completion: number; +}> { + const chatCompletionRequest = body; + + // per https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb + const promptTokens = encode( + chatCompletionRequest.messages + .map((msg) => `<|start|>${msg.role}\n${msg.content}<|end|>`) + .join('\n') + ).length; + + const parser = actionTypeId === '.bedrock' ? parseBedrockStream : parseOpenAIStream; + const parsedResponse = await parser(responseStream, logger); + + const completionTokens = encode(parsedResponse).length; + return { + prompt: promptTokens, + completion: completionTokens, + total: promptTokens + completionTokens, + }; +} + +type StreamParser = (responseStream: Readable, logger: Logger) => Promise; + +const parseBedrockStream: StreamParser = async (responseStream, logger) => { + const responseBuffer: Uint8Array[] = []; + responseStream.on('data', (chunk) => { + // special encoding for bedrock, do not attempt to convert to string + responseBuffer.push(chunk); + }); + try { + await finished(responseStream); + } catch (e) { + logger.error('An error occurred while calculating streaming response tokens'); + } + return parseBedrockBuffer(responseBuffer); +}; + +const parseOpenAIStream: StreamParser = async (responseStream, logger) => { + let responseBody: string = ''; + responseStream.on('data', (chunk) => { + // no special encoding, can safely use toString and append to responseBody + responseBody += chunk.toString(); + }); + try { + await finished(responseStream); + } catch (e) { + logger.error('An error occurred while calculating streaming response tokens'); + } + return parseOpenAIResponse(responseBody); +}; + +/** + * Parses a Bedrock buffer from an array of chunks. + * + * @param {Uint8Array[]} chunks - Array of Uint8Array chunks to be parsed. + * @returns {string} - Parsed string from the Bedrock buffer. + */ +const parseBedrockBuffer = (chunks: Uint8Array[]): string => { + // Initialize an empty Uint8Array to store the concatenated buffer. + let bedrockBuffer: Uint8Array = new Uint8Array(0); + + // Map through each chunk to process the Bedrock buffer. + return chunks + .map((chunk) => { + // Concatenate the current chunk to the existing buffer. + bedrockBuffer = concatChunks(bedrockBuffer, chunk); + // Get the length of the next message in the buffer. + let messageLength = getMessageLength(bedrockBuffer); + // Initialize an array to store fully formed message chunks. + const buildChunks = []; + // Process the buffer until no complete messages are left. + while (bedrockBuffer.byteLength > 0 && bedrockBuffer.byteLength >= messageLength) { + // Extract a chunk of the specified length from the buffer. + const extractedChunk = bedrockBuffer.slice(0, messageLength); + // Add the extracted chunk to the array of fully formed message chunks. + buildChunks.push(extractedChunk); + // Remove the processed chunk from the buffer. + bedrockBuffer = bedrockBuffer.slice(messageLength); + // Get the length of the next message in the updated buffer. + messageLength = getMessageLength(bedrockBuffer); + } + + const awsDecoder = new EventStreamCodec(toUtf8, fromUtf8); + + // Decode and parse each message chunk, extracting the 'completion' property. + return buildChunks + .map((bChunk) => { + const event = awsDecoder.decode(bChunk); + const body = JSON.parse( + Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString() + ); + return body.completion; + }) + .join(''); + }) + .join(''); +}; + +/** + * Concatenates two Uint8Array buffers. + * + * @param {Uint8Array} a - First buffer. + * @param {Uint8Array} b - Second buffer. + * @returns {Uint8Array} - Concatenated buffer. + */ +function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array { + const newBuffer = new Uint8Array(a.length + b.length); + // Copy the contents of the first buffer to the new buffer. + newBuffer.set(a); + // Copy the contents of the second buffer to the new buffer starting from the end of the first buffer. + newBuffer.set(b, a.length); + return newBuffer; +} + +/** + * Gets the length of the next message from the buffer. + * + * @param {Uint8Array} buffer - Buffer containing the message. + * @returns {number} - Length of the next message. + */ +function getMessageLength(buffer: Uint8Array): number { + // If the buffer is empty, return 0. + if (buffer.byteLength === 0) return 0; + // Create a DataView to read the Uint32 value at the beginning of the buffer. + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + // Read and return the Uint32 value (message length). + return view.getUint32(0, false); +} + +const parseOpenAIResponse = (responseBody: string) => + responseBody + .split('\n') + .filter((line) => { + return line.startsWith('data: ') && !line.endsWith('[DONE]'); + }) + .map((line) => { + return JSON.parse(line.replace('data: ', '')); + }) + .filter( + ( + line + ): line is { + choices: Array<{ + delta: { content?: string; function_call?: { name?: string; arguments: string } }; + }>; + } => { + return 'object' in line && line.object === 'chat.completion.chunk'; + } + ) + .reduce((prev, line) => { + const msg = line.choices[0].delta!; + prev += msg.content || ''; + return prev; + }, ''); diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.test.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.test.ts index 080b7cb5f972..cc81706fc257 100644 --- a/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.test.ts +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.test.ts @@ -6,6 +6,7 @@ */ import { Transform } from 'stream'; import { getTokenCountFromOpenAIStream } from './get_token_count_from_openai_stream'; +import { loggerMock } from '@kbn/logging-mocks'; interface StreamMock { write: (data: string) => void; @@ -32,6 +33,7 @@ function createStreamMock(): StreamMock { }; } +const logger = loggerMock.create(); describe('getTokenCountFromOpenAIStream', () => { let tokens: Awaited>; let stream: StreamMock; @@ -77,6 +79,7 @@ describe('getTokenCountFromOpenAIStream', () => { beforeEach(async () => { tokens = await getTokenCountFromOpenAIStream({ responseStream: stream.transform, + logger, body: JSON.stringify(body), }); }); @@ -92,6 +95,7 @@ describe('getTokenCountFromOpenAIStream', () => { beforeEach(async () => { tokens = await getTokenCountFromOpenAIStream({ responseStream: stream.transform, + logger, body: JSON.stringify({ ...body, functions: [ @@ -123,6 +127,7 @@ describe('getTokenCountFromOpenAIStream', () => { it('resolves the promise with the correct prompt tokens', async () => { const tokenPromise = getTokenCountFromOpenAIStream({ responseStream: stream.transform, + logger, body: JSON.stringify(body), }); @@ -133,6 +138,7 @@ describe('getTokenCountFromOpenAIStream', () => { total: PROMPT_TOKEN_COUNT + COMPLETION_TOKEN_COUNT, completion: COMPLETION_TOKEN_COUNT, }); + expect(logger.error).toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.ts index 74c89f716171..0091faca468e 100644 --- a/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.ts +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_openai_stream.ts @@ -10,13 +10,16 @@ import { isEmpty, omitBy } from 'lodash'; import { Readable } from 'stream'; import { finished } from 'stream/promises'; import { CreateChatCompletionRequest } from 'openai'; +import { Logger } from '@kbn/logging'; export async function getTokenCountFromOpenAIStream({ responseStream, body, + logger, }: { responseStream: Readable; body: string; + logger: Logger; }): Promise<{ total: number; prompt: number; @@ -65,8 +68,8 @@ export async function getTokenCountFromOpenAIStream({ try { await finished(responseStream); - } catch { - // no need to handle this explicitly + } catch (e) { + logger.error('An error occurred while calculating streaming response tokens'); } const response = responseBody diff --git a/x-pack/plugins/actions/tsconfig.json b/x-pack/plugins/actions/tsconfig.json index 3beeddef429b..ea8096271d69 100644 --- a/x-pack/plugins/actions/tsconfig.json +++ b/x-pack/plugins/actions/tsconfig.json @@ -43,7 +43,7 @@ "@kbn/core-saved-objects-api-server-mocks", "@kbn/core-elasticsearch-server-mocks", "@kbn/core-logging-server-mocks", - "@kbn/serverless" + "@kbn/serverless", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms.ts b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms.ts new file mode 100644 index 000000000000..c597a18e2f05 --- /dev/null +++ b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SignificantItem } from '@kbn/ml-agg-utils'; + +// Named topTerms since all these items are of type `keyword`. +export const topTerms: SignificantItem[] = [ + { + bg_count: 0, + doc_count: 5102, + fieldName: 'version', + fieldValue: 'v1.0.0', + key: 'version:v1.0.0', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 2272, + fieldName: 'response_code', + fieldValue: '500', + key: 'response_code:500', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 2197, + fieldName: 'url', + fieldValue: 'home.php', + key: 'url:home.php', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1981, + fieldName: 'user', + fieldValue: 'Peter', + key: 'user:Peter', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1773, + fieldName: 'user', + fieldValue: 'Paul', + key: 'user:Paul', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1574, + fieldName: 'url', + fieldValue: 'login.php', + key: 'url:login.php', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1569, + fieldName: 'response_code', + fieldValue: '404', + key: 'response_code:404', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1348, + fieldName: 'user', + fieldValue: 'Mary', + key: 'user:Mary', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1331, + fieldName: 'url', + fieldValue: 'user.php', + key: 'url:user.php', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, + { + bg_count: 0, + doc_count: 1261, + fieldName: 'response_code', + fieldValue: '200', + key: 'response_code:200', + normalizedScore: 0, + pValue: 1, + score: 0, + total_bg_count: 0, + total_doc_count: 0, + type: 'keyword', + }, +]; diff --git a/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms_groups.ts b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms_groups.ts new file mode 100644 index 000000000000..582fded59d7b --- /dev/null +++ b/x-pack/plugins/aiops/common/__mocks__/artificial_logs/top_terms_groups.ts @@ -0,0 +1,1086 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SignificantItemGroup } from '@kbn/ml-agg-utils'; + +export const topTermsGroups: SignificantItemGroup[] = [ + { + id: '1921491265', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 1097, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 602, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 602, + pValue: 1, + }, + { + id: '1354434627', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 1097, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 495, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 495, + pValue: 1, + }, + { + id: '1539462188', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 787, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 411, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 411, + pValue: 1, + }, + { + id: '1553868016', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 787, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 376, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 376, + pValue: 1, + }, + { + id: '3400778144', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 473, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 318, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 318, + pValue: 1, + }, + { + id: '2753923470', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 627, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 318, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 318, + pValue: 1, + }, + { + id: '611881711', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 420, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 317, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 317, + pValue: 1, + }, + { + id: '1605132418', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 523, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 317, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 317, + pValue: 1, + }, + { + id: '1389551523', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 368, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 316, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 316, + pValue: 1, + }, + { + id: '1156337696', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 419, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 316, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 316, + pValue: 1, + }, + { + id: '3582406482', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 627, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 190, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 190, + pValue: 1, + }, + { + id: '1758796965', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 388, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 190, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 190, + pValue: 1, + }, + { + id: '943892302', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 523, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 127, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 127, + pValue: 1, + }, + { + id: '3952579328', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 627, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 119, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 119, + pValue: 1, + }, + { + id: '1573710542', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 388, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 119, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 119, + pValue: 1, + }, + { + id: '1384949010', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 473, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 95, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 95, + pValue: 1, + }, + { + id: '3945828984', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 523, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 79, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 79, + pValue: 1, + }, + { + id: '3487185726', + group: [ + { + key: 'response_code:500', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '500', + docCount: 2272, + pValue: 1, + duplicate: 7, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 2272, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 388, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Peter', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Peter', + docCount: 79, + pValue: 1, + duplicate: 7, + }, + ], + docCount: 79, + pValue: 1, + }, + { + id: '113295987', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 420, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 63, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 63, + pValue: 1, + }, + { + id: '2896531546', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 419, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 63, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 63, + pValue: 1, + }, + { + id: '2376883532', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:home.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'home.php', + docCount: 473, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 60, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 60, + pValue: 1, + }, + { + id: '3927320460', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:user.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'user.php', + docCount: 420, + pValue: 1, + duplicate: 9, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 40, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 40, + pValue: 1, + }, + { + id: '769745306', + group: [ + { + key: 'response_code:404', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '404', + docCount: 1569, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1569, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 419, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 40, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 40, + pValue: 1, + }, + { + id: '2532116164', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 368, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Paul', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Paul', + docCount: 32, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 32, + pValue: 1, + }, + { + id: '1953946181', + group: [ + { + key: 'response_code:200', + type: 'keyword', + fieldName: 'response_code', + fieldValue: '200', + docCount: 1261, + pValue: 1, + duplicate: 9, + }, + { + key: 'version:v1.0.0', + type: 'keyword', + fieldName: 'version', + fieldValue: 'v1.0.0', + docCount: 1261, + pValue: 1, + duplicate: 25, + }, + { + key: 'url:login.php', + type: 'keyword', + fieldName: 'url', + fieldValue: 'login.php', + docCount: 368, + pValue: 1, + duplicate: 8, + }, + { + key: 'user:Mary', + type: 'keyword', + fieldName: 'user', + fieldValue: 'Mary', + docCount: 20, + pValue: 1, + duplicate: 9, + }, + ], + docCount: 20, + pValue: 1, + }, +]; diff --git a/x-pack/plugins/aiops/common/api/log_rate_analysis/actions.ts b/x-pack/plugins/aiops/common/api/log_rate_analysis/actions.ts index bd3afd3152ae..2348b32c32f8 100644 --- a/x-pack/plugins/aiops/common/api/log_rate_analysis/actions.ts +++ b/x-pack/plugins/aiops/common/api/log_rate_analysis/actions.ts @@ -36,6 +36,7 @@ export const API_ACTION_NAME = { RESET_ALL: 'reset_all', RESET_ERRORS: 'reset_errors', RESET_GROUPS: 'reset_groups', + SET_ZERO_DOCS_FALLBACK: 'set_zero_docs_fallback', UPDATE_LOADING_STATE: 'update_loading_state', } as const; export type ApiActionName = typeof API_ACTION_NAME[keyof typeof API_ACTION_NAME]; @@ -210,6 +211,20 @@ export function updateLoadingStateAction( }; } +interface ApiActionSetZeroDocsFallback { + type: typeof API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK; + payload: boolean; +} + +export function setZeroDocsFallback( + payload: ApiActionSetZeroDocsFallback['payload'] +): ApiActionSetZeroDocsFallback { + return { + type: API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK, + payload, + }; +} + export type AiopsLogRateAnalysisApiAction = | ApiActionAddSignificantItems | ApiActionAddSignificantItemsGroup @@ -220,4 +235,5 @@ export type AiopsLogRateAnalysisApiAction = | ApiActionResetAll | ApiActionResetErrors | ApiActionResetGroups - | ApiActionUpdateLoadingState; + | ApiActionUpdateLoadingState + | ApiActionSetZeroDocsFallback; diff --git a/x-pack/plugins/aiops/common/api/stream_reducer.test.ts b/x-pack/plugins/aiops/common/api/stream_reducer.test.ts index f3dd6cce856c..5344d2448463 100644 --- a/x-pack/plugins/aiops/common/api/stream_reducer.test.ts +++ b/x-pack/plugins/aiops/common/api/stream_reducer.test.ts @@ -31,6 +31,7 @@ describe('streamReducer', () => { significantItems: [], significantItemsGroups: [], errors: [], + zeroDocsFallback: false, }); }); diff --git a/x-pack/plugins/aiops/common/api/stream_reducer.ts b/x-pack/plugins/aiops/common/api/stream_reducer.ts index 05d3fce52c22..06da4d3d250a 100644 --- a/x-pack/plugins/aiops/common/api/stream_reducer.ts +++ b/x-pack/plugins/aiops/common/api/stream_reducer.ts @@ -18,6 +18,7 @@ interface StreamState { loadingState: string; remainingFieldCandidates?: string[]; groupsMissing?: boolean; + zeroDocsFallback: boolean; } export const initialState: StreamState = { @@ -27,6 +28,7 @@ export const initialState: StreamState = { errors: [], loaded: 0, loadingState: '', + zeroDocsFallback: false, }; export function streamReducer( @@ -72,6 +74,8 @@ export function streamReducer( return initialState; case API_ACTION_NAME.UPDATE_LOADING_STATE: return { ...state, ...action.payload }; + case API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK: + return { ...state, zeroDocsFallback: action.payload }; default: return state; } diff --git a/x-pack/plugins/aiops/public/application/url_state/common.ts b/x-pack/plugins/aiops/public/application/url_state/common.ts new file mode 100644 index 000000000000..8ca9ec848150 --- /dev/null +++ b/x-pack/plugins/aiops/public/application/url_state/common.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import type { Filter, Query } from '@kbn/es-query'; + +import { SEARCH_QUERY_LANGUAGE, type SearchQueryLanguage } from '@kbn/ml-query-utils'; + +const defaultSearchQuery = { + match_all: {}, +}; + +export interface AiOpsPageUrlState { + pageKey: 'AIOPS_INDEX_VIEWER'; + pageUrlState: AiOpsIndexBasedAppState; +} + +export interface AiOpsIndexBasedAppState { + searchString?: Query['query']; + searchQuery?: estypes.QueryDslQueryContainer; + searchQueryLanguage: SearchQueryLanguage; + filters?: Filter[]; +} + +export type AiOpsFullIndexBasedAppState = Required; + +export const getDefaultAiOpsListState = ( + overrides?: Partial +): AiOpsFullIndexBasedAppState => ({ + searchString: '', + searchQuery: defaultSearchQuery, + searchQueryLanguage: SEARCH_QUERY_LANGUAGE.KUERY, + filters: [], + ...overrides, +}); diff --git a/x-pack/plugins/aiops/public/application/url_state/log_pattern_analysis.ts b/x-pack/plugins/aiops/public/application/url_state/log_pattern_analysis.ts new file mode 100644 index 000000000000..7ea9e1a398e4 --- /dev/null +++ b/x-pack/plugins/aiops/public/application/url_state/log_pattern_analysis.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getDefaultAiOpsListState, type AiOpsFullIndexBasedAppState } from './common'; + +export interface LogCategorizationPageUrlState { + pageKey: 'logCategorization'; + pageUrlState: LogCategorizationAppState; +} + +export interface LogCategorizationAppState extends AiOpsFullIndexBasedAppState { + field: string | undefined; +} + +export const getDefaultLogCategorizationAppState = ( + overrides?: Partial +): LogCategorizationAppState => { + return { + field: undefined, + ...getDefaultAiOpsListState(overrides), + }; +}; diff --git a/x-pack/plugins/aiops/public/application/url_state/log_rate_analysis.ts b/x-pack/plugins/aiops/public/application/url_state/log_rate_analysis.ts new file mode 100644 index 000000000000..f7691bc2b9d7 --- /dev/null +++ b/x-pack/plugins/aiops/public/application/url_state/log_rate_analysis.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { WindowParameters } from '@kbn/aiops-utils'; + +import { getDefaultAiOpsListState, type AiOpsFullIndexBasedAppState } from './common'; + +export interface LogRateAnalysisPageUrlState { + pageKey: 'logRateAnalysis'; + pageUrlState: LogRateAnalysisAppState; +} +/** + * To avoid long urls, we store the window parameters in the url state not with + * their full parameters names but with abbrevations. `windowParametersToAppState` and + * `appStateToWindowParameters` are used to transform the data structure. + */ +export interface LogRateAnalysisAppState extends AiOpsFullIndexBasedAppState { + /** Window parameters */ + wp?: { + /** Baseline minimum value */ + bMin: number; + /** Baseline maximum value */ + bMax: number; + /** Deviation minimum value */ + dMin: number; + /** Deviation maximum value */ + dMax: number; + }; +} + +/** + * Transforms a full window parameters object to the abbreviated url state version. + */ +export const windowParametersToAppState = (wp?: WindowParameters): LogRateAnalysisAppState['wp'] => + wp && { + bMin: wp.baselineMin, + bMax: wp.baselineMax, + dMin: wp.deviationMin, + dMax: wp.deviationMax, + }; + +/** + * Transforms an abbreviated url state version of window parameters to its full version. + */ +export const appStateToWindowParameters = ( + wp: LogRateAnalysisAppState['wp'] +): WindowParameters | undefined => + wp && { + baselineMin: wp.bMin, + baselineMax: wp.bMax, + deviationMin: wp.dMin, + deviationMax: wp.dMax, + }; + +export const getDefaultLogRateAnalysisAppState = ( + overrides?: Partial +): LogRateAnalysisAppState => { + return { + wp: undefined, + ...getDefaultAiOpsListState(overrides), + }; +}; diff --git a/x-pack/plugins/aiops/public/application/utils/url_state.ts b/x-pack/plugins/aiops/public/application/utils/url_state.ts deleted file mode 100644 index 22a32a3d610e..000000000000 --- a/x-pack/plugins/aiops/public/application/utils/url_state.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -import type { Filter, Query } from '@kbn/es-query'; - -import { SEARCH_QUERY_LANGUAGE, type SearchQueryLanguage } from '@kbn/ml-query-utils'; - -const defaultSearchQuery = { - match_all: {}, -}; - -export interface AiOpsPageUrlState { - pageKey: 'AIOPS_INDEX_VIEWER'; - pageUrlState: AiOpsIndexBasedAppState; -} - -export interface AiOpsIndexBasedAppState { - searchString?: Query['query']; - searchQuery?: estypes.QueryDslQueryContainer; - searchQueryLanguage: SearchQueryLanguage; - filters?: Filter[]; -} - -export type AiOpsFullIndexBasedAppState = Required; - -export const getDefaultAiOpsListState = ( - overrides?: Partial -): AiOpsFullIndexBasedAppState => ({ - searchString: '', - searchQuery: defaultSearchQuery, - searchQueryLanguage: SEARCH_QUERY_LANGUAGE.KUERY, - filters: [], - ...overrides, -}); - -export interface LogCategorizationPageUrlState { - pageKey: 'logCategorization'; - pageUrlState: LogCategorizationAppState; -} - -export interface LogCategorizationAppState extends AiOpsFullIndexBasedAppState { - field: string | undefined; -} - -export const getDefaultLogCategorizationAppState = ( - overrides?: Partial -): LogCategorizationAppState => { - return { - field: undefined, - ...getDefaultAiOpsListState(overrides), - }; -}; diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/no_change_points_warning.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/no_change_points_warning.tsx index 0f5303725e51..ce15116d968c 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/no_change_points_warning.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/no_change_points_warning.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import React, { type FC } from 'react'; +import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiEmptyPrompt } from '@elastic/eui'; -export const NoChangePointsWarning: FC = () => { +export const NoChangePointsWarning = (props: { onRenderComplete?: () => void }) => { + props.onRenderComplete?.(); + return ( +export const createCategorizeFieldAction = (coreStart: CoreStart, plugins: AiopsPluginStartDeps) => createAction({ type: ACTION_CATEGORIZE_FIELD, id: ACTION_CATEGORIZE_FIELD, getDisplayName: () => i18n.translate('xpack.aiops.categorizeFieldAction.displayName', { - defaultMessage: 'Categorize field', + defaultMessage: 'Pattern analysis', }), isCompatible: async ({ field }: CategorizeFieldContext) => { return field.esTypes?.includes('text') === true; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 3796af67f8cd..05cca08d2222 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -30,7 +30,7 @@ import type { } from '../../../../common/api/log_categorization/types'; import { useEuiTheme } from '../../../hooks/use_eui_theme'; -import type { LogCategorizationAppState } from '../../../application/utils/url_state'; +import type { LogCategorizationAppState } from '../../../application/url_state/log_pattern_analysis'; import { MiniHistogram } from '../../mini_histogram'; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx b/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx new file mode 100644 index 000000000000..66458c511d98 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; + +import moment from 'moment'; +import { EuiButtonEmpty } from '@elastic/eui'; +import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER, + type CreateCategorizationADJobContext, +} from '@kbn/ml-ui-actions'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; + +interface Props { + dataView: DataView; + field: DataViewField; + query: QueryDslQueryContainer; + earliest: number | undefined; + latest: number | undefined; +} + +export const CreateCategorizationJobButton: FC = ({ + dataView, + field, + query, + earliest, + latest, +}) => { + const { + uiActions, + application: { capabilities }, + } = useAiopsAppContext(); + + const createADJob = () => { + if (uiActions === undefined) { + return; + } + + const triggerOptions: CreateCategorizationADJobContext = { + dataView, + field, + query, + timeRange: { from: moment(earliest).toISOString(), to: moment(latest).toISOString() }, + }; + uiActions.getTrigger(CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER).exec(triggerOptions); + }; + + if (uiActions === undefined || capabilities.ml.canCreateJob === false) { + return null; + } + + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/index.ts b/x-pack/plugins/aiops/public/components/log_categorization/index.ts index 550add880274..ace01d4f0338 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/index.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/index.ts @@ -7,7 +7,7 @@ export type { LogCategorizationAppStateProps } from './log_categorization_app_state'; import { LogCategorizationAppState } from './log_categorization_app_state'; -export { categorizeFieldAction } from './categorize_field_actions'; +export { createCategorizeFieldAction } from './categorize_field_actions'; // required for dynamic import using React.lazy() // eslint-disable-next-line import/no-default-export diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx index a5262393e0ee..1f3eda09132e 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx @@ -29,7 +29,7 @@ import type { Category, SparkLinesPerCategory } from '../../../common/api/log_ca import { type LogCategorizationPageUrlState, getDefaultLogCategorizationAppState, -} from '../../application/utils/url_state'; +} from '../../application/url_state/log_pattern_analysis'; import { createMergedEsQuery } from '../../application/utils/search_utils'; import { useData } from '../../hooks/use_data'; import { useSearch } from '../../hooks/use_search'; @@ -44,6 +44,7 @@ import { TechnicalPreviewBadge } from './technical_preview_badge'; import { LoadingCategorization } from './loading_categorization'; import { useValidateFieldRequest } from './use_validate_category_field'; import { FieldValidationCallout } from './category_validation_callout'; +import { CreateCategorizationJobButton } from './create_categorization_job'; export interface LogCategorizationPageProps { dataView: DataView; @@ -261,17 +262,21 @@ export const LogCategorizationFlyout: FC = ({ + - {loading === true ? : null} - - {loading === false && data !== null && data.categories.length > 0 ? ( void; + /** Optional callback that exposes current window parameters */ + onWindowParametersChange?: (wp?: WindowParameters) => void; /** Identifier to indicate the plugin utilizing the component */ embeddingOrigin: string; } @@ -78,6 +92,7 @@ export const LogRateAnalysisContent: FC = ({ barColorOverride, barHighlightColorOverride, onAnalysisCompleted, + onWindowParametersChange, embeddingOrigin, }) => { const [windowParameters, setWindowParameters] = useState(); @@ -93,6 +108,35 @@ export const LogRateAnalysisContent: FC = ({ setIsBrushCleared(windowParameters === undefined); }, [windowParameters]); + // Window parameters stored in the url state use this components + // `initialAnalysisStart` prop to set the initial params restore from url state. + // To avoid a loop with window parameters being passed around on load, + // the following ref and useEffect are used to check wether it's safe to call + // the `onWindowParametersChange` callback. + const windowParametersTouched = useRef(false); + useEffect(() => { + // Don't continue if window parameters were not touched yet. + // Because they can be reset to `undefined` at a later stage again when a user + // clears the selections, we cannot rely solely on checking if they are + // `undefined`, we need the additional ref to update on the first change. + if (!windowParametersTouched.current && windowParameters === undefined) { + return; + } + + windowParametersTouched.current = true; + + if (onWindowParametersChange) { + onWindowParametersChange(windowParameters); + } + }, [onWindowParametersChange, windowParameters]); + + // Checks if `esSearchQuery` is the default empty query passed on from the search bar + // and if that's the case fall back to a simpler match all query. + const searchQuery = useMemo( + () => (isEqual(esSearchQuery, DEFAULT_SEARCH_BAR_QUERY) ? DEFAULT_SEARCH_QUERY : esSearchQuery), + [esSearchQuery] + ); + const { currentSelectedSignificantItem, currentSelectedGroup, @@ -105,7 +149,7 @@ export const LogRateAnalysisContent: FC = ({ const { documentStats, earliest, latest } = useData( dataView, 'log_rate_analysis', - esSearchQuery, + searchQuery, setGlobalState, currentSelectedSignificantItem, currentSelectedGroup, @@ -170,7 +214,7 @@ export const LogRateAnalysisContent: FC = ({ stickyHistogram={stickyHistogram} onReset={clearSelection} sampleProbability={sampleProbability} - searchQuery={esSearchQuery} + searchQuery={searchQuery} windowParameters={windowParameters} barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx index b3c9f256fb2e..4931503b7366 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx @@ -6,22 +6,26 @@ */ import React, { useCallback, useEffect, useState, FC } from 'react'; +import { isEqual } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { EuiFlexGroup, EuiFlexItem, EuiPageBody, EuiPageSection, EuiSpacer } from '@elastic/eui'; import { Filter, FilterStateStore, Query } from '@kbn/es-query'; import { useUrlState, usePageUrlState } from '@kbn/ml-url-state'; - import type { SearchQueryLanguage } from '@kbn/ml-query-utils'; +import type { WindowParameters } from '@kbn/aiops-utils'; + import { useDataSource } from '../../hooks/use_data_source'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { useData } from '../../hooks/use_data'; import { useSearch } from '../../hooks/use_search'; import { - getDefaultAiOpsListState, - type AiOpsPageUrlState, -} from '../../application/utils/url_state'; + getDefaultLogRateAnalysisAppState, + appStateToWindowParameters, + windowParametersToAppState, + type LogRateAnalysisPageUrlState, +} from '../../application/url_state/log_rate_analysis'; import { AIOPS_TELEMETRY_ID } from '../../../common/constants'; import { SearchPanel } from '../search_panel'; @@ -40,9 +44,9 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { const { currentSelectedSignificantItem, currentSelectedGroup } = useLogRateAnalysisResultsTableRowContext(); - const [aiopsListState, setAiopsListState] = usePageUrlState( - 'AIOPS_INDEX_VIEWER', - getDefaultAiOpsListState() + const [stateFromUrl, setUrlState] = usePageUrlState( + 'logRateAnalysis', + getDefaultLogRateAnalysisAppState() ); const [globalState, setGlobalState] = useUrlState('_g'); @@ -67,20 +71,20 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { setSelectedSavedSearch(null); } - setAiopsListState({ - ...aiopsListState, + setUrlState({ + ...stateFromUrl, searchQuery: searchParams.searchQuery, searchString: searchParams.searchString, searchQueryLanguage: searchParams.queryLanguage, filters: searchParams.filters, }); }, - [selectedSavedSearch, aiopsListState, setAiopsListState] + [selectedSavedSearch, stateFromUrl, setUrlState] ); const { searchQueryLanguage, searchString, searchQuery } = useSearch( { dataView, savedSearch }, - aiopsListState + stateFromUrl ); const { timefilter } = useData( @@ -132,6 +136,14 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { }); }, [dataService, searchQueryLanguage, searchString]); + const onWindowParametersHandler = (wp?: WindowParameters) => { + if (!isEqual(wp, stateFromUrl.wp)) { + setUrlState({ + wp: windowParametersToAppState(wp), + }); + } + }; + return ( @@ -148,11 +160,13 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { /> diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx index 457419c8b050..121c19be2ddb 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx @@ -46,6 +46,7 @@ import { import { useLogRateAnalysisResultsTableRowContext } from '../log_rate_analysis_results_table/log_rate_analysis_results_table_row_provider'; import { FieldFilterPopover } from './field_filter_popover'; +import { LogRateAnalysisTypeCallOut } from './log_rate_analysis_type_callout'; const groupResultsMessage = i18n.translate( 'xpack.aiops.logRateAnalysis.resultsTable.groupedSwitchLabel.groupResults', @@ -209,7 +210,8 @@ export const LogRateAnalysisResults: FC = ({ { [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin } ); - const { significantItems } = data; + const { significantItems, zeroDocsFallback } = data; + useEffect( () => setUniqueFieldNames(uniq(significantItems.map((d) => d.fieldName)).sort()), [significantItems] @@ -362,37 +364,13 @@ export const LogRateAnalysisResults: FC = ({ /> - {showLogRateAnalysisResultsTable && ( + {showLogRateAnalysisResultsTable && currentAnalysisType !== undefined && ( <> - - {currentAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE - ? i18n.translate('xpack.aiops.analysis.analysisTypeSpikeCallOutTitle', { - defaultMessage: 'Analysis type: Log rate spike', - }) - : i18n.translate('xpack.aiops.analysis.analysisTypeDipCallOutTitle', { - defaultMessage: 'Analysis type: Log rate dip', - })} - - } - color="primary" - iconType="pin" - size="s" - > - - {currentAnalysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE - ? i18n.translate('xpack.aiops.analysis.analysisTypeSpikeCallOutContent', { - defaultMessage: - 'The median log rate in the selected deviation time range is higher than the baseline. Therefore, the analysis results table shows statistically significant items within the deviation time range that are contributors to the spike. The "doc count" column refers to the amount of documents in the deviation time range.', - }) - : i18n.translate('xpack.aiops.analysis.analysisTypeDipCallOutContent', { - defaultMessage: - 'The median log rate in the selected deviation time range is lower than the baseline. Therefore, the analysis results table shows statistically significant items within the baseline time range that are less in number or missing within the deviation time range. The "doc count" column refers to the amount of documents in the baseline time range.', - })} - - + )} @@ -490,6 +468,7 @@ export const LogRateAnalysisResults: FC = ({ searchQuery={searchQuery} barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} + zeroDocsFallback={zeroDocsFallback} /> ) : null} {showLogRateAnalysisResultsTable && !groupResults ? ( @@ -501,6 +480,7 @@ export const LogRateAnalysisResults: FC = ({ searchQuery={searchQuery} barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} + zeroDocsFallback={zeroDocsFallback} /> ) : null}
    diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_type_callout.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_type_callout.tsx new file mode 100644 index 000000000000..2760a27c3d22 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_type_callout.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiCallOut, EuiText } from '@elastic/eui'; + +import { LOG_RATE_ANALYSIS_TYPE, type LogRateAnalysisType } from '@kbn/aiops-utils'; +import { i18n } from '@kbn/i18n'; + +interface LogRateAnalysisTypeCallOutProps { + analysisType: LogRateAnalysisType; + zeroDocsFallback: boolean; +} + +export const LogRateAnalysisTypeCallOut: FC = ({ + analysisType, + zeroDocsFallback, +}) => { + let callOutTitle: string; + let callOutText: string; + + if (!zeroDocsFallback && analysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE) { + callOutTitle = i18n.translate('xpack.aiops.analysis.analysisTypeSpikeCallOutTitle', { + defaultMessage: 'Analysis type: Log rate spike', + }); + callOutText = i18n.translate('xpack.aiops.analysis.analysisTypeSpikeCallOutContent', { + defaultMessage: + 'The median log rate in the selected deviation time range is higher than the baseline. Therefore, the analysis results table shows statistically significant items within the deviation time range that are contributors to the spike. The "doc count" column refers to the amount of documents in the deviation time range.', + }); + } else if (!zeroDocsFallback && analysisType === LOG_RATE_ANALYSIS_TYPE.DIP) { + callOutTitle = i18n.translate('xpack.aiops.analysis.analysisTypeDipCallOutTitle', { + defaultMessage: 'Analysis type: Log rate dip', + }); + callOutText = i18n.translate('xpack.aiops.analysis.analysisTypeDipCallOutContent', { + defaultMessage: + 'The median log rate in the selected deviation time range is lower than the baseline. Therefore, the analysis results table shows statistically significant items within the baseline time range that are less in number or missing within the deviation time range. The "doc count" column refers to the amount of documents in the baseline time range.', + }); + } else if (zeroDocsFallback && analysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE) { + callOutTitle = i18n.translate('xpack.aiops.analysis.analysisTypeSpikeFallbackCallOutTitle', { + defaultMessage: 'Analysis type: Top items for deviation time range', + }); + callOutText = i18n.translate('xpack.aiops.analysis.analysisTypeSpikeCallOutContentFallback', { + defaultMessage: + 'The baseline time range does not contain any documents. Therefore the results show top log message categories and field values for the deviation time range.', + }); + } else if (zeroDocsFallback && analysisType === LOG_RATE_ANALYSIS_TYPE.DIP) { + callOutTitle = i18n.translate('xpack.aiops.analysis.analysisTypeDipFallbackCallOutTitle', { + defaultMessage: 'Analysis type: Top items for baseline time range', + }); + callOutText = i18n.translate('xpack.aiops.analysis.analysisTypeDipCallOutContentFallback', { + defaultMessage: + 'The deviation time range does not contain any documents. Therefore the results show top log message categories and field values for the baseline time range.', + }); + } else { + return null; + } + + return ( + {callOutTitle}} + color="primary" + iconType="pin" + size="s" + > + {callOutText} + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx index d8845145f1ac..b0b4d699919b 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx @@ -51,7 +51,9 @@ const NOT_AVAILABLE = '--'; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; const DEFAULT_SORT_FIELD = 'pValue'; +const DEFAULT_SORT_FIELD_ZERO_DOCS_FALLBACK = 'doc_count'; const DEFAULT_SORT_DIRECTION = 'asc'; +const DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK = 'desc'; const TRUNCATE_TEXT_LINES = 3; @@ -66,6 +68,7 @@ interface LogRateAnalysisResultsTableProps { barColorOverride?: string; /** Optional color override for the highlighted bar color for charts */ barHighlightColorOverride?: string; + zeroDocsFallback?: boolean; } export const LogRateAnalysisResultsTable: FC = ({ @@ -77,6 +80,7 @@ export const LogRateAnalysisResultsTable: FC = timeRangeMs, barColorOverride, barHighlightColorOverride, + zeroDocsFallback = false, }) => { const euiTheme = useEuiTheme(); const primaryBackgroundColor = useEuiBackgroundColor('primary'); @@ -93,8 +97,12 @@ export const LogRateAnalysisResultsTable: FC = const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); - const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); - const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(DEFAULT_SORT_DIRECTION); + const [sortField, setSortField] = useState( + zeroDocsFallback ? DEFAULT_SORT_FIELD_ZERO_DOCS_FALLBACK : DEFAULT_SORT_FIELD + ); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>( + zeroDocsFallback ? DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK : DEFAULT_SORT_DIRECTION + ); const { data, uiSettings, fieldFormats, charts } = useAiopsAppContext(); @@ -236,7 +244,10 @@ export const LogRateAnalysisResultsTable: FC = sortable: true, valign: 'middle', }, - { + ]; + + if (!zeroDocsFallback) { + columns.push({ 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnPValue', width: NARROW_COLUMN_WIDTH, field: 'pValue', @@ -260,8 +271,9 @@ export const LogRateAnalysisResultsTable: FC = render: (pValue: number | null) => pValue?.toPrecision(3) ?? NOT_AVAILABLE, sortable: true, valign: 'middle', - }, - { + }); + + columns.push({ 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnImpact', width: NARROW_COLUMN_WIDTH, field: 'pValue', @@ -291,21 +303,22 @@ export const LogRateAnalysisResultsTable: FC = }, sortable: true, valign: 'middle', - }, - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnAction', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.actionsColumnName', { - defaultMessage: 'Actions', - }), - actions: [ - ...(viewInDiscoverAction ? [viewInDiscoverAction] : []), - ...(viewInLogPatternAnalysisAction ? [viewInLogPatternAnalysisAction] : []), - copyToClipBoardAction, - ], - width: ACTIONS_COLUMN_WIDTH, - valign: 'middle', - }, - ]; + }); + } + + columns.push({ + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnAction', + name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.actionsColumnName', { + defaultMessage: 'Actions', + }), + actions: [ + ...(viewInDiscoverAction ? [viewInDiscoverAction] : []), + ...(viewInLogPatternAnalysisAction ? [viewInLogPatternAnalysisAction] : []), + copyToClipBoardAction, + ], + width: ACTIONS_COLUMN_WIDTH, + valign: 'middle', + }); if (isExpandedRow === true) { columns.unshift({ diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx index f6961e49c2c7..957385780cea 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx @@ -50,7 +50,9 @@ const MAX_GROUP_BADGES = 5; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; const DEFAULT_SORT_FIELD = 'pValue'; +const DEFAULT_SORT_FIELD_ZERO_DOCS_FALLBACK = 'docCount'; const DEFAULT_SORT_DIRECTION = 'asc'; +const DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK = 'desc'; interface LogRateAnalysisResultsTableProps { significantItems: SignificantItem[]; @@ -63,6 +65,7 @@ interface LogRateAnalysisResultsTableProps { barColorOverride?: string; /** Optional color override for the highlighted bar color for charts */ barHighlightColorOverride?: string; + zeroDocsFallback?: boolean; } export const LogRateAnalysisResultsGroupsTable: FC = ({ @@ -74,11 +77,16 @@ export const LogRateAnalysisResultsGroupsTable: FC { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); - const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); - const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(DEFAULT_SORT_DIRECTION); + const [sortField, setSortField] = useState<'docCount' | 'pValue'>( + zeroDocsFallback ? DEFAULT_SORT_FIELD_ZERO_DOCS_FALLBACK : DEFAULT_SORT_FIELD + ); + const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>( + zeroDocsFallback ? DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK : DEFAULT_SORT_DIRECTION + ); const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState>( {} ); @@ -297,7 +305,10 @@ export const LogRateAnalysisResultsGroupsTable: FC pValue?.toPrecision(3) ?? NOT_AVAILABLE, sortable: true, valign: 'top', - }, - { + }); + + columns.push({ 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnImpact', width: NARROW_COLUMN_WIDTH, field: 'pValue', @@ -355,21 +367,22 @@ export const LogRateAnalysisResultsGroupsTable: FC { if (tableSettings.page) { diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx index cbfff714d66f..0392f28184b8 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx @@ -243,7 +243,7 @@ export const ChartGridEmbeddableWrapper: FC< ) : emptyState ? ( emptyState ) : ( - + )}
    ); diff --git a/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts b/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts index 5714ae5283fb..c1903f6bba8a 100644 --- a/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts +++ b/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts @@ -33,6 +33,7 @@ import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/ import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { CasesUiStart } from '@kbn/cases-plugin/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; +import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; /** * AIOps App Dependencies to be provided via React context. @@ -97,6 +98,10 @@ export interface AiopsAppDependencies { * Used to create lens embeddables. */ lens: LensPublicStart; + /** + * UI actions. + */ + uiActions?: UiActionsStart; /** * Internationalisation service */ diff --git a/x-pack/plugins/aiops/public/hooks/use_search.ts b/x-pack/plugins/aiops/public/hooks/use_search.ts index 609beb6774bc..8c62db36289f 100644 --- a/x-pack/plugins/aiops/public/hooks/use_search.ts +++ b/x-pack/plugins/aiops/public/hooks/use_search.ts @@ -11,7 +11,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import { getEsQueryFromSavedSearch } from '../application/utils/search_utils'; -import type { AiOpsIndexBasedAppState } from '../application/utils/url_state'; +import type { AiOpsIndexBasedAppState } from '../application/url_state/common'; import { useAiopsAppContext } from './use_aiops_app_context'; export const useSearch = ( diff --git a/x-pack/plugins/aiops/public/plugin.tsx b/x-pack/plugins/aiops/public/plugin.tsx index c896ccc7d5b3..12a7f659135a 100755 --- a/x-pack/plugins/aiops/public/plugin.tsx +++ b/x-pack/plugins/aiops/public/plugin.tsx @@ -25,49 +25,38 @@ export class AiopsPlugin core: AiopsCoreSetup, { embeddable, cases, licensing, uiActions }: AiopsPluginSetupDeps ) { - firstValueFrom(licensing.license$).then(async (license) => { - if (license.hasAtLeast('platinum')) { - if (embeddable) { - const { registerEmbeddable } = await import('./embeddable/register_embeddable'); - registerEmbeddable(core, embeddable); - } + Promise.all([ + firstValueFrom(licensing.license$), + import('./embeddable/register_embeddable'), + import('./ui_actions'), + import('./cases/register_change_point_charts_attachment'), + core.getStartServices(), + ]).then( + ([ + license, + { registerEmbeddable }, + { registerAiopsUiActions }, + { registerChangePointChartsAttachment }, + [coreStart, pluginStart], + ]) => { + if (license.hasAtLeast('platinum')) { + if (embeddable) { + registerEmbeddable(core, embeddable); + } - if (uiActions) { - const { registerAiopsUiActions } = await import('./ui_actions'); - registerAiopsUiActions(uiActions, core); - } + if (uiActions) { + registerAiopsUiActions(uiActions, coreStart, pluginStart); + } - if (cases) { - const [coreStart, pluginStart] = await core.getStartServices(); - const { registerChangePointChartsAttachment } = await import( - './cases/register_change_point_charts_attachment' - ); - registerChangePointChartsAttachment(cases, coreStart, pluginStart); + if (cases) { + registerChangePointChartsAttachment(cases, coreStart, pluginStart); + } } } - }); + ); } public start(core: CoreStart, plugins: AiopsPluginStartDeps): AiopsPluginStart { - // importing async to keep the aiops plugin size to a minimum - Promise.all([ - import('@kbn/ui-actions-plugin/public'), - import('./components/log_categorization'), - firstValueFrom(plugins.licensing.license$), - ]).then(([uiActionsImports, { categorizeFieldAction }, license]) => { - if (license.hasAtLeast('platinum')) { - const { ACTION_CATEGORIZE_FIELD, CATEGORIZE_FIELD_TRIGGER } = uiActionsImports; - if (plugins.uiActions.hasAction(ACTION_CATEGORIZE_FIELD)) { - plugins.uiActions.unregisterAction(ACTION_CATEGORIZE_FIELD); - } - - plugins.uiActions.addTriggerAction( - CATEGORIZE_FIELD_TRIGGER, - categorizeFieldAction(core, plugins) - ); - } - }); - return { EmbeddableChangePointChart: getEmbeddableChangePointChart(core, plugins), }; diff --git a/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx b/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx index ae50937921f3..d9401f6064cb 100644 --- a/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx +++ b/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx @@ -8,14 +8,16 @@ import type { UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; import { i18n } from '@kbn/i18n'; import { ViewMode } from '@kbn/embeddable-plugin/common'; +import type { CoreStart } from '@kbn/core/public'; import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; import type { EditChangePointChartsPanelContext } from '../embeddable/types'; -import type { AiopsCoreSetup } from '../plugin'; +import type { AiopsPluginStartDeps } from '../types'; export const EDIT_CHANGE_POINT_CHARTS_ACTION = 'editChangePointChartsPanelAction'; export function createEditChangePointChartsPanelAction( - getStartServices: AiopsCoreSetup['getStartServices'] + coreStart: CoreStart, + pluginStart: AiopsPluginStartDeps ): UiActionsActionDefinition { return { id: 'edit-change-point-charts', @@ -32,8 +34,6 @@ export function createEditChangePointChartsPanelAction( throw new Error('Not possible to execute an action without the embeddable context'); } - const [coreStart, pluginStart] = await getStartServices(); - try { const { resolveEmbeddableChangePointUserInput } = await import( '../embeddable/handle_explicit_input' diff --git a/x-pack/plugins/aiops/public/ui_actions/index.ts b/x-pack/plugins/aiops/public/ui_actions/index.ts index cd00842c662c..14e1879027ff 100644 --- a/x-pack/plugins/aiops/public/ui_actions/index.ts +++ b/x-pack/plugins/aiops/public/ui_actions/index.ts @@ -7,16 +7,33 @@ import type { UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import { + categorizeFieldTrigger, + CATEGORIZE_FIELD_TRIGGER, +} from '@kbn/ml-ui-actions/src/aiops/ui_actions'; + +import type { CoreStart } from '@kbn/core/public'; +import type { AiopsPluginStartDeps } from '../types'; import { createEditChangePointChartsPanelAction } from './edit_change_point_charts_panel'; -import type { AiopsCoreSetup } from '../plugin'; +import { createCategorizeFieldAction } from '../components/log_categorization'; -export function registerAiopsUiActions(uiActions: UiActionsSetup, core: AiopsCoreSetup) { +export function registerAiopsUiActions( + uiActions: UiActionsSetup, + coreStart: CoreStart, + pluginStart: AiopsPluginStartDeps +) { // Initialize actions const editChangePointChartPanelAction = createEditChangePointChartsPanelAction( - core.getStartServices + coreStart, + pluginStart + ); + // // Register actions and triggers + uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, editChangePointChartPanelAction); + + uiActions.registerTrigger(categorizeFieldTrigger); + + uiActions.addTriggerAction( + CATEGORIZE_FIELD_TRIGGER, + createCategorizeFieldAction(coreStart, pluginStart) ); - // Register actions - uiActions.registerAction(editChangePointChartPanelAction); - // Assign and register triggers - uiActions.attachAction(CONTEXT_MENU_TRIGGER, editChangePointChartPanelAction.id); } diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts index 6ae2a07055ae..3c6ea4d022bb 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts @@ -7,7 +7,10 @@ import { i18n } from '@kbn/i18n'; -import { updateLoadingStateAction } from '../../../../common/api/log_rate_analysis/actions'; +import { + updateLoadingStateAction, + setZeroDocsFallback, +} from '../../../../common/api/log_rate_analysis/actions'; import type { AiopsLogRateAnalysisApiVersion as ApiVersion } from '../../../../common/api/log_rate_analysis/schema'; import { isRequestAbortedError } from '../../../lib/is_request_aborted_error'; @@ -36,6 +39,7 @@ export const indexInfoHandlerFactory = const textFieldCandidates: string[] = []; let totalDocCount = 0; + let zeroDocsFallback = false; if (!requestBody.overrides?.remainingFieldCandidates) { logDebugMessage('Fetch index information.'); @@ -63,7 +67,8 @@ export const indexInfoHandlerFactory = fieldCandidates.push(...indexInfo.fieldCandidates); fieldCandidatesCount = fieldCandidates.length; textFieldCandidates.push(...indexInfo.textFieldCandidates); - totalDocCount = indexInfo.totalDocCount; + totalDocCount = indexInfo.deviationTotalDocCount; + zeroDocsFallback = indexInfo.zeroDocsFallback; } catch (e) { if (!isRequestAbortedError(e)) { logger.error(`Failed to fetch index information, got: \n${e.toString()}`); @@ -96,6 +101,8 @@ export const indexInfoHandlerFactory = }) ); + responseStream.push(setZeroDocsFallback(zeroDocsFallback)); + if (fieldCandidatesCount === 0) { responseStream.endWithUpdatedLoadingState(); } else if (stateHandler.shouldStop()) { @@ -105,5 +112,5 @@ export const indexInfoHandlerFactory = } } - return { fieldCandidates, textFieldCandidates }; + return { fieldCandidates, textFieldCandidates, zeroDocsFallback }; }; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/top_items_handler.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/top_items_handler.ts new file mode 100644 index 000000000000..10f0b19f0792 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/top_items_handler.ts @@ -0,0 +1,212 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { queue } from 'async'; + +import { SIGNIFICANT_ITEM_TYPE, type SignificantItem } from '@kbn/ml-agg-utils'; +import { i18n } from '@kbn/i18n'; + +import { + addSignificantItemsAction, + updateLoadingStateAction, +} from '../../../../common/api/log_rate_analysis/actions'; + +import { isRequestAbortedError } from '../../../lib/is_request_aborted_error'; + +import { fetchTopCategories } from '../queries/fetch_top_categories'; +import { fetchTopTerms } from '../queries/fetch_top_terms'; + +import type { + AiopsLogRateAnalysisSchema, + AiopsLogRateAnalysisApiVersion as ApiVersion, +} from '../../../../common/api/log_rate_analysis/schema'; + +import { + LOADED_FIELD_CANDIDATES, + MAX_CONCURRENT_QUERIES, + PROGRESS_STEP_P_VALUES, +} from '../response_stream_utils/constants'; +import type { ResponseStreamFetchOptions } from '../response_stream_factory'; + +export const topItemsHandlerFactory = + ({ + abortSignal, + client, + logDebugMessage, + logger, + requestBody, + responseStream, + stateHandler, + version, + }: ResponseStreamFetchOptions) => + async ({ + fieldCandidates, + textFieldCandidates, + }: { + fieldCandidates: string[]; + textFieldCandidates: string[]; + }) => { + let fieldCandidatesCount = fieldCandidates.length; + + // This will store the combined count of detected log patterns and keywords + let fieldValuePairsCount = 0; + + const topCategories: SignificantItem[] = []; + + if (version === '1') { + topCategories.push( + ...((requestBody as AiopsLogRateAnalysisSchema<'1'>).overrides?.significantTerms?.filter( + (d) => d.type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN + ) ?? []) + ); + } + + if (version === '2') { + topCategories.push( + ...((requestBody as AiopsLogRateAnalysisSchema<'2'>).overrides?.significantItems?.filter( + (d) => d.type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN + ) ?? []) + ); + } + + // Get categories of text fields + if (textFieldCandidates.length > 0) { + topCategories.push( + ...(await fetchTopCategories( + client, + requestBody, + textFieldCandidates, + logger, + stateHandler.sampleProbability(), + responseStream.pushError, + abortSignal + )) + ); + + if (topCategories.length > 0) { + responseStream.push(addSignificantItemsAction(topCategories, version)); + } + } + + const topTerms: SignificantItem[] = []; + + if (version === '1') { + topTerms.push( + ...((requestBody as AiopsLogRateAnalysisSchema<'1'>).overrides?.significantTerms?.filter( + (d) => d.type === SIGNIFICANT_ITEM_TYPE.KEYWORD + ) ?? []) + ); + } + + if (version === '2') { + topTerms.push( + ...((requestBody as AiopsLogRateAnalysisSchema<'2'>).overrides?.significantItems?.filter( + (d) => d.type === SIGNIFICANT_ITEM_TYPE.KEYWORD + ) ?? []) + ); + } + + const fieldsToSample = new Set(); + + let remainingFieldCandidates: string[]; + let loadingStepSizeTopTerms = PROGRESS_STEP_P_VALUES; + + if (requestBody.overrides?.remainingFieldCandidates) { + fieldCandidates.push(...requestBody.overrides?.remainingFieldCandidates); + remainingFieldCandidates = requestBody.overrides?.remainingFieldCandidates; + fieldCandidatesCount = fieldCandidates.length; + loadingStepSizeTopTerms = + LOADED_FIELD_CANDIDATES + + PROGRESS_STEP_P_VALUES - + (requestBody.overrides?.loaded ?? PROGRESS_STEP_P_VALUES); + } else { + remainingFieldCandidates = fieldCandidates; + } + + logDebugMessage('Fetch p-values.'); + + const topTermsQueue = queue(async function (fieldCandidate: string) { + stateHandler.loaded((1 / fieldCandidatesCount) * loadingStepSizeTopTerms, false); + + let fetchedTopTerms: Awaited>; + + try { + fetchedTopTerms = await fetchTopTerms( + client, + requestBody, + [fieldCandidate], + logger, + stateHandler.sampleProbability(), + responseStream.pushError, + abortSignal + ); + } catch (e) { + if (!isRequestAbortedError(e)) { + logger.error(`Failed to fetch p-values for '${fieldCandidate}', got: \n${e.toString()}`); + responseStream.pushError(`Failed to fetch p-values for '${fieldCandidate}'.`); + } + return; + } + + remainingFieldCandidates = remainingFieldCandidates.filter((d) => d !== fieldCandidate); + + if (fetchedTopTerms.length > 0) { + fetchedTopTerms.forEach((d) => { + fieldsToSample.add(d.fieldName); + }); + topTerms.push(...fetchedTopTerms); + + responseStream.push(addSignificantItemsAction(fetchedTopTerms, version)); + } + + responseStream.push( + updateLoadingStateAction({ + ccsWarning: false, + loaded: stateHandler.loaded(), + loadingState: i18n.translate( + 'xpack.aiops.logRateAnalysis.loadingState.identifiedFieldValuePairs', + { + defaultMessage: + 'Identified {fieldValuePairsCount, plural, one {# significant field/value pair} other {# significant field/value pairs}}.', + values: { + fieldValuePairsCount, + }, + } + ), + remainingFieldCandidates, + }) + ); + }, MAX_CONCURRENT_QUERIES); + + topTermsQueue.push(fieldCandidates, (err) => { + if (err) { + logger.error(`Failed to fetch p-values.', got: \n${err.toString()}`); + responseStream.pushError(`Failed to fetch p-values.`); + topTermsQueue.kill(); + responseStream.end(); + } else if (stateHandler.shouldStop()) { + logDebugMessage('shouldStop fetching p-values.'); + topTermsQueue.kill(); + responseStream.end(); + } + }); + await topTermsQueue.drain(); + + fieldValuePairsCount = topCategories.length + topTerms.length; + + if (fieldValuePairsCount === 0) { + logDebugMessage('Stopping analysis, did not find any categories or terms.'); + responseStream.endWithUpdatedLoadingState(); + return; + } + + return { + fieldValuePairsCount, + significantCategories: topCategories, + significantTerms: topTerms, + }; + }; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_match_all.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_match_all.ts new file mode 100644 index 000000000000..a81ba523caa4 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_match_all.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const paramsMock = { + index: 'the-index', + timeFieldName: 'the-time-field-name', + start: 0, + end: 50, + baselineMin: 10, + baselineMax: 20, + deviationMin: 30, + deviationMax: 40, + includeFrozen: false, + searchQuery: '{ "match_all": {} }', +}; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_search_query.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_search_query.ts new file mode 100644 index 000000000000..dd0ac8058540 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/params_search_query.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AiopsLogRateAnalysisSchema } from '../../../../../common/api/log_rate_analysis/schema'; + +import { paramsMock } from './params_match_all'; +import { searchQueryMock } from './search_query'; + +export const paramsSearchQueryMock: AiopsLogRateAnalysisSchema = { + ...paramsMock, + searchQuery: searchQueryMock, +}; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/search_query.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/search_query.ts new file mode 100644 index 000000000000..58be3bf37271 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/__mocks__/search_query.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// This is the format that gets passed on from the Kibana search bar. +export const searchQueryMock = JSON.stringify({ + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts new file mode 100644 index 000000000000..d38dd57c0afd --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; + +import { paramsMock } from './__mocks__/params_match_all'; +import { getBaselineOrDeviationFilter, getCategoryRequest } from './fetch_categories'; + +describe('getBaselineOrDeviationFilter', () => { + it('returns a filter that matches both baseline and deviation time range', () => { + const baselineOrDeviationFilter = getBaselineOrDeviationFilter(paramsMock); + + expect(baselineOrDeviationFilter).toEqual({ + bool: { + should: [ + { + range: { + 'the-time-field-name': { gte: 10, lte: 20, format: 'epoch_millis' }, + }, + }, + { + range: { + 'the-time-field-name': { gte: 30, lte: 40, format: 'epoch_millis' }, + }, + }, + ], + }, + }); + }); +}); + +describe('getCategoryRequest', () => { + it('returns the category request', () => { + const randomSamplerWrapper = createRandomSamplerWrapper({ + probability: 0.1, + seed: 1234, + }); + + const query = getCategoryRequest(paramsMock, 'the-field-name', randomSamplerWrapper); + + // Because the time range filter is covered by the should clauses that cover both + // baseline (10,20) and deviation (30,40), we expect that there is no other + // time range filter whatsoever, for example for start/end (0,50). + expect(query).toEqual({ + index: 'the-index', + size: 0, + body: { + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + range: { + 'the-time-field-name': { + gte: 10, + lte: 20, + format: 'epoch_millis', + }, + }, + }, + { + range: { + 'the-time-field-name': { + gte: 30, + lte: 40, + format: 'epoch_millis', + }, + }, + }, + ], + }, + }, + ], + }, + }, + aggs: { + sample: { + random_sampler: { probability: 0.1, seed: 1234 }, + aggs: { + categories: { + categorize_text: { field: 'the-field-name', size: 1000 }, + aggs: { + hit: { + top_hits: { size: 1, sort: ['the-time-field-name'], _source: 'the-field-name' }, + }, + }, + }, + }, + }, + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts index e70255ababff..703242b7e9a6 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts @@ -28,30 +28,67 @@ import { isRequestAbortedError } from '../../../lib/is_request_aborted_error'; import { getQueryWithParams } from './get_query_with_params'; +// Filter that includes docs from both the baseline and deviation time range. +export const getBaselineOrDeviationFilter = ( + params: AiopsLogRateAnalysisSchema +): estypes.QueryDslQueryContainer => { + return { + bool: { + should: [ + { + range: { + [params.timeFieldName]: { + gte: params.baselineMin, + lte: params.baselineMax, + format: 'epoch_millis', + }, + }, + }, + { + range: { + [params.timeFieldName]: { + gte: params.deviationMin, + lte: params.deviationMax, + format: 'epoch_millis', + }, + }, + }, + ], + }, + }; +}; + export const getCategoryRequest = ( params: AiopsLogRateAnalysisSchema, fieldName: string, - from: number | undefined, - to: number | undefined, - filter: estypes.QueryDslQueryContainer, { wrap }: RandomSamplerWrapper ): estypes.SearchRequest => { const { index, timeFieldName } = params; + const query = getQueryWithParams({ params, - termFilters: undefined, - filter, + // We're skipping the overall range query here since this + // is covered by the filter which will match docs in both baseline + // and deviation time range via `getBaselineOrDeviationFilter`. + skipRangeQuery: true, + filter: getBaselineOrDeviationFilter(params), }); + const { params: request } = createCategoryRequest( index, fieldName, timeFieldName, - from, - to, + undefined, + undefined, query, wrap ); + // In this case we're only interested in the aggregation which + // `createCategoryRequest` returns, so we're re-applying the original + // query we create via `getQueryWithParams` here. + request.body.query = query; + return request; }; @@ -64,9 +101,6 @@ export const fetchCategories = async ( esClient: ElasticsearchClient, params: AiopsLogRateAnalysisSchema, fieldNames: string[], - from: number | undefined, - to: number | undefined, - filter: estypes.QueryDslQueryContainer, logger: Logger, // The default value of 1 means no sampling will be used sampleProbability: number = 1, @@ -82,7 +116,7 @@ export const fetchCategories = async ( const settledPromises = await Promise.allSettled( fieldNames.map((fieldName) => { - const request = getCategoryRequest(params, fieldName, from, to, filter, randomSamplerWrapper); + const request = getCategoryRequest(params, fieldName, randomSamplerWrapper); return esClient.search(request, { signal: abortSignal, maxRetries: 0, diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts new file mode 100644 index 000000000000..b3fa6ff5f31a --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { paramsMock } from './__mocks__/params_match_all'; + +import { getCategoryCountRequest, getCategoryCountMSearchRequest } from './fetch_category_counts'; + +describe('getCategoryCountRequest', () => { + it('returns the category count request', () => { + const category = { + key: 'runTask ended no files to process', + count: 667, + examples: ['[runTask()] ended: no files to process'], + }; + + const query = getCategoryCountRequest( + paramsMock, + 'the-field-name', + category, + paramsMock.baselineMin, + paramsMock.baselineMax + ); + + expect(query).toEqual({ + index: 'the-index', + body: { + query: { + bool: { + filter: [ + { range: { 'the-time-field-name': { gte: 10, lte: 20, format: 'epoch_millis' } } }, + { + bool: { + should: [ + { + match: { + 'the-field-name': { + auto_generate_synonyms_phrase_query: false, + fuzziness: 0, + operator: 'and', + query: 'runTask ended no files to process', + }, + }, + }, + ], + }, + }, + ], + }, + }, + size: 0, + track_total_hits: true, + }, + }); + }); +}); + +describe('getCategoryCountMSearchRequest', () => { + it('returns the request body for the msearch request', () => { + const categories = [ + { + key: 'SLO summary transforms installed and started', + count: 500, + examples: ['SLO summary transforms installed and started'], + }, + { key: 'Trusted Apps', count: 500, examples: ['Trusted Apps: '] }, + ]; + + const query = getCategoryCountMSearchRequest( + paramsMock, + 'the-field-name', + categories, + paramsMock.baselineMin, + paramsMock.baselineMax + ); + + expect(query).toEqual([ + { index: 'the-index' }, + { + query: { + bool: { + filter: [ + { range: { 'the-time-field-name': { gte: 10, lte: 20, format: 'epoch_millis' } } }, + { + bool: { + should: [ + { + match: { + 'the-field-name': { + auto_generate_synonyms_phrase_query: false, + fuzziness: 0, + operator: 'and', + query: 'SLO summary transforms installed and started', + }, + }, + }, + ], + }, + }, + ], + }, + }, + size: 0, + track_total_hits: true, + }, + { index: 'the-index' }, + { + query: { + bool: { + filter: [ + { range: { 'the-time-field-name': { gte: 10, lte: 20, format: 'epoch_millis' } } }, + { + bool: { + should: [ + { + match: { + 'the-field-name': { + auto_generate_synonyms_phrase_query: false, + fuzziness: 0, + operator: 'and', + query: 'Trusted Apps', + }, + }, + }, + ], + }, + }, + ], + }, + }, + size: 0, + track_total_hits: true, + }, + ]); + }); +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.ts index 608734ae0e19..555d49b46dc1 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.ts @@ -33,24 +33,18 @@ export const getCategoryCountRequest = ( ): estypes.SearchRequest => { const { index } = params; - const query = getQueryWithParams({ - params, - }); - const categoryQuery = getCategoryQuery(fieldName, [category]); - if (Array.isArray(query.bool?.filter)) { - query.bool?.filter?.push(categoryQuery); - query.bool?.filter?.push({ - range: { - [params.timeFieldName]: { - gte: from, - lte: to, - format: 'epoch_millis', - }, - }, - }); - } + const query = getQueryWithParams({ + // This will override the original start/end params if + // the optional from/to args are provided. + params: { + ...params, + ...(from ? { start: from } : {}), + ...(to ? { end: to } : {}), + }, + filter: categoryQuery, + }); return { index, @@ -62,6 +56,19 @@ export const getCategoryCountRequest = ( }; }; +export const getCategoryCountMSearchRequest = ( + params: AiopsLogRateAnalysisSchema, + fieldName: string, + categories: FetchCategoriesResponse['categories'], + from: number | undefined, + to: number | undefined +): estypes.MsearchRequestItem[] => + categories.flatMap((category) => [ + { index: params.index }, + getCategoryCountRequest(params, fieldName, category, from, to) + .body as estypes.MsearchMultisearchBody, + ]); + export const fetchCategoryCounts = async ( esClient: ElasticsearchClient, params: AiopsLogRateAnalysisSchema, @@ -75,11 +82,13 @@ export const fetchCategoryCounts = async ( ): Promise => { const updatedCategories = cloneDeep(categories); - const searches = categories.categories.flatMap((category) => [ - { index: params.index }, - getCategoryCountRequest(params, fieldName, category, from, to) - .body as estypes.MsearchMultisearchBody, - ]); + const searches = getCategoryCountMSearchRequest( + params, + fieldName, + categories.categories, + from, + to + ); let mSearchresponse; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.test.ts index db14c30caebd..38377a9e0d32 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.test.ts @@ -9,63 +9,11 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from '@kbn/core/server'; -import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; +import { paramsSearchQueryMock } from './__mocks__/params_search_query'; -import { fetchIndexInfo, getRandomDocsRequest } from './fetch_index_info'; - -const params: AiopsLogRateAnalysisSchema = { - index: 'the-index', - timeFieldName: 'the-time-field-name', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - includeFrozen: false, - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', -}; +import { fetchIndexInfo } from './fetch_index_info'; describe('fetch_index_info', () => { - describe('getRandomDocsRequest', () => { - it('returns the most basic request body for a sample of random documents', () => { - const req = getRandomDocsRequest(params); - - expect(req).toEqual({ - body: { - _source: false, - fields: ['*'], - query: { - function_score: { - query: { - bool: { - filter: [ - { bool: { filter: [], must: [{ match_all: {} }], must_not: [] } }, - { - range: { - 'the-time-field-name': { - format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, - }, - }, - }, - ], - }, - }, - random_score: {}, - }, - }, - size: 1000, - track_total_hits: true, - }, - index: params.index, - ignore_throttled: undefined, - ignore_unavailable: true, - }); - }); - }); - describe('fetchFieldCandidates', () => { it('returns field candidates and total hits', async () => { const esClientFieldCapsMock = jest.fn(() => ({ @@ -105,12 +53,14 @@ describe('fetch_index_info', () => { search: esClientSearchMock, } as unknown as ElasticsearchClient; - const { totalDocCount, fieldCandidates } = await fetchIndexInfo(esClientMock, params); + const { baselineTotalDocCount, deviationTotalDocCount, fieldCandidates } = + await fetchIndexInfo(esClientMock, paramsSearchQueryMock); expect(fieldCandidates).toEqual(['myIpFieldName', 'myKeywordFieldName']); - expect(totalDocCount).toEqual(5000000); + expect(baselineTotalDocCount).toEqual(5000000); + expect(deviationTotalDocCount).toEqual(5000000); expect(esClientFieldCapsMock).toHaveBeenCalledTimes(1); - expect(esClientSearchMock).toHaveBeenCalledTimes(1); + expect(esClientSearchMock).toHaveBeenCalledTimes(2); }); }); }); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.ts index 595e21215943..fd7975aac1b6 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_index_info.ts @@ -12,14 +12,12 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; -import { getQueryWithParams } from './get_query_with_params'; -import { getRequestBase } from './get_request_base'; +import { getRandomDocsRequest } from './get_random_docs_request'; +import { getTotalDocCountRequest } from './get_total_doc_count_request'; // TODO Consolidate with duplicate `fetchPValues` in // `x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts` -const POPULATED_DOC_COUNT_SAMPLE_SIZE = 1000; - const SUPPORTED_ES_FIELD_TYPES = [ ES_FIELD_TYPES.KEYWORD, ES_FIELD_TYPES.IP, @@ -28,30 +26,12 @@ const SUPPORTED_ES_FIELD_TYPES = [ const SUPPORTED_ES_FIELD_TYPES_TEXT = [ES_FIELD_TYPES.TEXT, ES_FIELD_TYPES.MATCH_ONLY_TEXT]; -export const getRandomDocsRequest = ( - params: AiopsLogRateAnalysisSchema -): estypes.SearchRequest => ({ - ...getRequestBase(params), - body: { - fields: ['*'], - _source: false, - query: { - function_score: { - query: getQueryWithParams({ params }), - // @ts-ignore - random_score: {}, - }, - }, - size: POPULATED_DOC_COUNT_SAMPLE_SIZE, - // Used to determine sample probability for follow up queries - track_total_hits: true, - }, -}); - interface IndexInfo { fieldCandidates: string[]; textFieldCandidates: string[]; - totalDocCount: number; + baselineTotalDocCount: number; + deviationTotalDocCount: number; + zeroDocsFallback: boolean; } export const fetchIndexInfo = async ( @@ -95,15 +75,24 @@ export const fetchIndexInfo = async ( allFieldNames.push(key); }); + // Get the total doc count for the baseline time range + const respBaselineTotalDocCount = await esClient.search( + getTotalDocCountRequest({ ...params, start: params.baselineMin, end: params.baselineMax }), + { + signal: abortSignal, + maxRetries: 0, + } + ); + // Only the deviation window will be used to identify field candidates and sample probability based on total doc count. - const resp = await esClient.search( + const respDeviationRandomDocs = await esClient.search( getRandomDocsRequest({ ...params, start: params.deviationMin, end: params.deviationMax }), { signal: abortSignal, maxRetries: 0, } ); - const sampledDocs = resp.hits.hits.map((d) => d.fields ?? {}); + const sampledDocs = respDeviationRandomDocs.hits.hits.map((d) => d.fields ?? {}); const textFieldCandidatesOverridesWithKeywordPostfix = textFieldCandidatesOverrides.map( (d) => `${d}.keyword` @@ -127,11 +116,16 @@ export const fetchIndexInfo = async ( } }); - const totalDocCount = (resp.hits.total as estypes.SearchTotalHits).value; + const baselineTotalDocCount = (respBaselineTotalDocCount.hits.total as estypes.SearchTotalHits) + .value; + const deviationTotalDocCount = (respDeviationRandomDocs.hits.total as estypes.SearchTotalHits) + .value; return { fieldCandidates: [...finalFieldCandidates], textFieldCandidates: [...finalTextFieldCandidates], - totalDocCount, + baselineTotalDocCount, + deviationTotalDocCount, + zeroDocsFallback: baselineTotalDocCount === 0 || deviationTotalDocCount === 0, }; }; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_significant_categories.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_significant_categories.ts index 49617a1661ba..2284622dc808 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_significant_categories.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_significant_categories.ts @@ -42,39 +42,10 @@ export const fetchSignificantCategories = async ( emitError: (m: string) => void, abortSignal?: AbortSignal ) => { - // Filter that includes docs from both the baseline and deviation time range. - const baselineOrDeviationFilter = { - bool: { - should: [ - { - range: { - [params.timeFieldName]: { - gte: params.baselineMin, - lte: params.baselineMax, - format: 'epoch_millis', - }, - }, - }, - { - range: { - [params.timeFieldName]: { - gte: params.deviationMin, - lte: params.deviationMax, - format: 'epoch_millis', - }, - }, - }, - ], - }, - }; - const categoriesOverall = await fetchCategories( esClient, params, fieldNames, - undefined, - undefined, - baselineOrDeviationFilter, logger, sampleProbability, emitError, diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_categories.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_categories.ts new file mode 100644 index 000000000000..2933e5d3e414 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_categories.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { uniq } from 'lodash'; + +import { ElasticsearchClient } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; +import { type SignificantItem, SIGNIFICANT_ITEM_TYPE } from '@kbn/ml-agg-utils'; + +import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; + +import { fetchCategories } from './fetch_categories'; + +export const fetchTopCategories = async ( + esClient: ElasticsearchClient, + params: AiopsLogRateAnalysisSchema, + fieldNames: string[], + logger: Logger, + // The default value of 1 means no sampling will be used + sampleProbability: number = 1, + emitError: (m: string) => void, + abortSignal?: AbortSignal +) => { + const categoriesOverall = await fetchCategories( + esClient, + params, + fieldNames, + logger, + sampleProbability, + emitError, + abortSignal + ); + + if (categoriesOverall.length !== fieldNames.length) return []; + + const topCategories: SignificantItem[] = []; + + // Using for...of to allow `await` within the loop. + for (const [i, fieldName] of fieldNames.entries()) { + if (categoriesOverall[i].categories.length === 0) { + continue; + } + + // Get all unique keys + const allKeys: string[] = uniq(categoriesOverall[i].categories.map((cd) => cd.key)); + + allKeys.forEach((key) => { + const categoryData = categoriesOverall[i].categories.find((c) => c.key === key); + + topCategories.push({ + key, + fieldName, + fieldValue: categoryData?.examples[0] ?? '', + doc_count: categoryData?.count ?? 0, + bg_count: 0, + total_doc_count: 0, + total_bg_count: 0, + score: 0, + pValue: 1, + normalizedScore: 0, + type: SIGNIFICANT_ITEM_TYPE.LOG_PATTERN, + }); + }); + } + + return topCategories; +}; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_terms.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_terms.ts new file mode 100644 index 000000000000..d1b800724913 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_top_terms.ts @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { uniqBy } from 'lodash'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { ElasticsearchClient } from '@kbn/core/server'; + +import type { Logger } from '@kbn/logging'; +import { type SignificantItem, SIGNIFICANT_ITEM_TYPE } from '@kbn/ml-agg-utils'; +import { + createRandomSamplerWrapper, + type RandomSamplerWrapper, +} from '@kbn/ml-random-sampler-utils'; + +import { RANDOM_SAMPLER_SEED } from '../../../../common/constants'; +import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; + +import { isRequestAbortedError } from '../../../lib/is_request_aborted_error'; + +import { getQueryWithParams } from './get_query_with_params'; +import { getRequestBase } from './get_request_base'; + +// TODO Consolidate with duplicate `fetchDurationFieldCandidates` in +// `x-pack/plugins/apm/server/routes/correlations/queries/fetch_failed_events_correlation_p_values.ts` + +export const getTopTermRequest = ( + params: AiopsLogRateAnalysisSchema, + fieldName: string, + { wrap }: RandomSamplerWrapper +): estypes.SearchRequest => { + const query = getQueryWithParams({ + params, + }); + + const timeFieldName = params.timeFieldName ?? '@timestamp'; + + let filter: estypes.QueryDslQueryContainer[] = []; + + if (query.bool && Array.isArray(query.bool.filter)) { + filter = query.bool.filter.filter((d) => Object.keys(d)[0] !== 'range'); + + query.bool.filter = [ + ...filter, + { + range: { + [timeFieldName]: { + gte: params.deviationMin, + lt: params.deviationMax, + format: 'epoch_millis', + }, + }, + }, + ]; + } + + const termAgg: Record<'log_rate_top_terms', estypes.AggregationsAggregationContainer> = { + log_rate_top_terms: { + terms: { + field: fieldName, + size: 10, + }, + }, + }; + + const body = { + query, + size: 0, + aggs: wrap(termAgg), + }; + + return { + ...getRequestBase(params), + body, + }; +}; + +interface Aggs extends estypes.AggregationsLongTermsAggregate { + buckets: estypes.AggregationsLongTermsBucket[]; +} + +export const fetchTopTerms = async ( + esClient: ElasticsearchClient, + params: AiopsLogRateAnalysisSchema, + fieldNames: string[], + logger: Logger, + // The default value of 1 means no sampling will be used + sampleProbability: number = 1, + emitError: (m: string) => void, + abortSignal?: AbortSignal +): Promise => { + const randomSamplerWrapper = createRandomSamplerWrapper({ + probability: sampleProbability, + seed: RANDOM_SAMPLER_SEED, + }); + + const result: SignificantItem[] = []; + + const settledPromises = await Promise.allSettled( + fieldNames.map((fieldName) => + esClient.search(getTopTermRequest(params, fieldName, randomSamplerWrapper), { + signal: abortSignal, + maxRetries: 0, + }) + ) + ); + + function reportError(fieldName: string, error: unknown) { + if (!isRequestAbortedError(error)) { + logger.error( + `Failed to fetch term aggregation for fieldName "${fieldName}", got: \n${JSON.stringify( + error, + null, + 2 + )}` + ); + emitError(`Failed to fetch term aggregation for fieldName "${fieldName}".`); + } + } + + for (const [index, settledPromise] of settledPromises.entries()) { + const fieldName = fieldNames[index]; + + if (settledPromise.status === 'rejected') { + reportError(fieldName, settledPromise.reason); + // Still continue the analysis even if individual p-value queries fail. + continue; + } + + const resp = settledPromise.value; + + if (resp.aggregations === undefined) { + reportError(fieldName, resp); + // Still continue the analysis even if individual p-value queries fail. + continue; + } + + const overallResult = ( + randomSamplerWrapper.unwrap(resp.aggregations) as Record<'log_rate_top_terms', Aggs> + ).log_rate_top_terms; + + for (const bucket of overallResult.buckets) { + result.push({ + key: `${fieldName}:${String(bucket.key)}`, + type: SIGNIFICANT_ITEM_TYPE.KEYWORD, + fieldName, + fieldValue: String(bucket.key), + doc_count: bucket.doc_count, + bg_count: 0, + total_doc_count: 0, + total_bg_count: 0, + score: 0, + pValue: 1, + normalizedScore: 0, + }); + } + } + + return uniqBy(result, (d) => `${d.fieldName},${d.fieldValue}`); +}; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.test.ts deleted file mode 100644 index c34d81fa91bd..000000000000 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getFilters } from './get_filters'; - -describe('getFilters', () => { - it('returns an empty array with no timeFieldName and searchQuery supplied', () => { - const filters = getFilters({ - index: 'the-index', - timeFieldName: '', - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - }); - expect(filters).toEqual([]); - }); - - it('returns a range filter when timeFieldName is supplied', () => { - const filters = getFilters({ - index: 'the-index', - timeFieldName: 'the-time-field-name', - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - }); - expect(filters).toEqual([ - { - range: { - 'the-time-field-name': { - format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, - }, - }, - }, - ]); - }); -}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.ts deleted file mode 100644 index e910d2e99744..000000000000 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_filters.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -import type { ESFilter } from '@kbn/es-types'; - -import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; - -export function rangeQuery( - start?: number, - end?: number, - field = '@timestamp' -): estypes.QueryDslQueryContainer[] { - return [ - { - range: { - [field]: { - gte: start, - lte: end, - format: 'epoch_millis', - }, - }, - }, - ]; -} - -export function getFilters({ start, end, timeFieldName }: AiopsLogRateAnalysisSchema): ESFilter[] { - const filters: ESFilter[] = []; - - if (timeFieldName !== '') { - filters.push(...rangeQuery(start, end, timeFieldName)); - } - - return filters; -} diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_histogram_query.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_histogram_query.test.ts index 95113d39f41c..39af620dd266 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_histogram_query.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_histogram_query.test.ts @@ -5,34 +5,30 @@ * 2.0. */ -import { getHistogramQuery } from './get_histogram_query'; +import { paramsSearchQueryMock } from './__mocks__/params_search_query'; -const paramsMock = { - index: 'the-index', - timeFieldName: 'the-time-field-name', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - includeFrozen: false, - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', -}; +import { getHistogramQuery } from './get_histogram_query'; describe('getHistogramQuery', () => { it('returns histogram query without additional filters', () => { - const query = getHistogramQuery(paramsMock); + const query = getHistogramQuery(paramsSearchQueryMock); expect(query).toEqual({ bool: { filter: [ - { bool: { filter: [], must: [{ match_all: {} }], must_not: [] } }, + { + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, + }, { range: { 'the-time-field-name': { format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, + gte: 0, + lte: 50, }, }, }, @@ -42,7 +38,7 @@ describe('getHistogramQuery', () => { }); it('returns histogram query with additional filters', () => { - const query = getHistogramQuery(paramsMock, [ + const query = getHistogramQuery(paramsSearchQueryMock, [ { term: { ['the-filter-fieldName']: 'the-filter-fieldValue' }, }, @@ -50,7 +46,14 @@ describe('getHistogramQuery', () => { expect(query).toEqual({ bool: { filter: [ - { bool: { filter: [], must: [{ match_all: {} }], must_not: [] } }, + { + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, + }, { term: { 'the-filter-fieldName': 'the-filter-fieldValue', @@ -60,8 +63,8 @@ describe('getHistogramQuery', () => { range: { 'the-time-field-name': { format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, + gte: 0, + lte: 50, }, }, }, diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.test.ts index aa600065fd22..cd43e031e916 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.test.ts @@ -5,34 +5,33 @@ * 2.0. */ +import { paramsMock } from './__mocks__/params_match_all'; +import { paramsSearchQueryMock } from './__mocks__/params_search_query'; + import { getQueryWithParams } from './get_query_with_params'; describe('getQueryWithParams', () => { it('returns the most basic query filtering', () => { const query = getQueryWithParams({ - params: { - index: 'the-index', - timeFieldName: 'the-time-field-name', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - includeFrozen: false, - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - }, + params: paramsSearchQueryMock, }); expect(query).toEqual({ bool: { filter: [ - { bool: { filter: [], must: [{ match_all: {} }], must_not: [] } }, + { + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, + }, { range: { 'the-time-field-name': { format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, + gte: 0, + lte: 50, }, }, }, @@ -43,18 +42,7 @@ describe('getQueryWithParams', () => { it('returns a query considering a custom field/value pair', () => { const query = getQueryWithParams({ - params: { - index: 'the-index', - timeFieldName: 'the-time-field-name', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - includeFrozen: false, - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - }, + params: paramsSearchQueryMock, termFilters: [ { fieldName: 'actualFieldName', @@ -65,13 +53,20 @@ describe('getQueryWithParams', () => { expect(query).toEqual({ bool: { filter: [ - { bool: { filter: [], must: [{ match_all: {} }], must_not: [] } }, + { + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, + }, { range: { 'the-time-field-name': { format: 'epoch_millis', - gte: 1577836800000, - lte: 1609459200000, + gte: 0, + lte: 50, }, }, }, @@ -84,4 +79,25 @@ describe('getQueryWithParams', () => { }, }); }); + + it("should not add `searchQuery` if it's just a match_all query", () => { + const query = getQueryWithParams({ + params: paramsMock, + }); + expect(query).toEqual({ + bool: { + filter: [ + { + range: { + 'the-time-field-name': { + format: 'epoch_millis', + gte: 0, + lte: 50, + }, + }, + }, + ], + }, + }); + }); }); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.ts index b7e2e2619316..80d67fe73fa8 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_query_with_params.ts @@ -11,7 +11,7 @@ import type { FieldValuePair } from '@kbn/ml-agg-utils'; import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; -import { getFilters } from './get_filters'; +import { getRangeQuery } from './get_range_query'; export const getTermsQuery = ({ fieldName, fieldValue }: FieldValuePair) => { return { term: { [fieldName]: fieldValue } }; @@ -21,21 +21,30 @@ interface QueryParams { params: AiopsLogRateAnalysisSchema<'2'>; termFilters?: FieldValuePair[]; filter?: estypes.QueryDslQueryContainer; + skipRangeQuery?: boolean; } export const getQueryWithParams = ({ params, termFilters, filter, + skipRangeQuery = false, }: QueryParams): estypes.QueryDslQueryContainer => { const searchQuery = JSON.parse(params.searchQuery) as estypes.QueryDslQueryContainer; return { bool: { filter: [ - searchQuery, - ...getFilters(params), + // Add `searchQuery` if it's not a `match_all` query + ...(searchQuery.match_all === undefined ? [searchQuery] : []), + + // Add a range query based on `start/end` for the `timeFieldName`, check for skip flag. + ...(!skipRangeQuery ? [getRangeQuery(params.start, params.end, params.timeFieldName)] : []), + + // Add optional term filters ...(Array.isArray(termFilters) ? termFilters.map(getTermsQuery) : []), + + // Add other optional filters ...(filter ? [filter] : []), - ] as estypes.QueryDslQueryContainer[], + ], }, }; }; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.test.ts new file mode 100644 index 000000000000..6e68c789142c --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { paramsSearchQueryMock } from './__mocks__/params_search_query'; + +import { getRandomDocsRequest } from './get_random_docs_request'; + +describe('getRandomDocsRequest', () => { + it('returns the most basic request body for a sample of random documents', () => { + const req = getRandomDocsRequest(paramsSearchQueryMock); + + expect(req).toEqual({ + body: { + _source: false, + fields: ['*'], + query: { + function_score: { + query: { + bool: { + filter: [ + { + bool: { + filter: [], + minimum_should_match: 1, + must_not: [], + should: [{ term: { 'the-term': { value: 'the-value' } } }], + }, + }, + { + range: { + 'the-time-field-name': { + format: 'epoch_millis', + gte: 0, + lte: 50, + }, + }, + }, + ], + }, + }, + random_score: {}, + }, + }, + size: 1000, + track_total_hits: true, + }, + index: paramsSearchQueryMock.index, + ignore_throttled: undefined, + ignore_unavailable: true, + }); + }); +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.ts new file mode 100644 index 000000000000..7c1abdfd5266 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_random_docs_request.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; + +import { getQueryWithParams } from './get_query_with_params'; +import { getRequestBase } from './get_request_base'; + +const POPULATED_DOC_COUNT_SAMPLE_SIZE = 1000; + +export const getRandomDocsRequest = ( + params: AiopsLogRateAnalysisSchema +): estypes.SearchRequest => ({ + ...getRequestBase(params), + body: { + fields: ['*'], + _source: false, + query: { + function_score: { + query: getQueryWithParams({ params }), + // @ts-ignore + random_score: {}, + }, + }, + size: POPULATED_DOC_COUNT_SAMPLE_SIZE, + // Used to determine sample probability for follow up queries + track_total_hits: true, + }, +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.test.ts new file mode 100644 index 000000000000..8d232df5d2c2 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.test.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getRangeQuery } from './get_range_query'; + +describe('getRangeQuery', () => { + it('returns a range filter with default time field', () => { + const query = getRangeQuery(0, 50); + expect(query).toEqual({ + range: { + '@timestamp': { + gte: 0, + lte: 50, + format: 'epoch_millis', + }, + }, + }); + }); + + it('returns a range filter with a custom time field', () => { + const query = getRangeQuery(0, 50, 'the-time-field'); + expect(query).toEqual({ + range: { + 'the-time-field': { + gte: 0, + lte: 50, + format: 'epoch_millis', + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.ts new file mode 100644 index 000000000000..ca9ae7a299ee --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_range_query.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export function getRangeQuery( + start?: number, + end?: number, + field = '@timestamp' +): estypes.QueryDslQueryContainer { + return { + range: { + [field]: { + gte: start, + lte: end, + format: 'epoch_millis', + }, + }, + }; +} diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_request_base.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_request_base.test.ts index ee21cb985f5d..33797e219fd3 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_request_base.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_request_base.test.ts @@ -5,36 +5,20 @@ * 2.0. */ +import { paramsMock } from './__mocks__/params_match_all'; + import { getRequestBase } from './get_request_base'; describe('getRequestBase', () => { it('defaults to not setting `ignore_throttled`', () => { - const requestBase = getRequestBase({ - index: 'the-index', - timeFieldName: 'the-time-field-name', - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, - }); + const requestBase = getRequestBase(paramsMock); expect(requestBase.ignore_throttled).toEqual(undefined); }); it('adds `ignore_throttled=false` when `includeFrozen=true`', () => { const requestBase = getRequestBase({ - index: 'the-index', - timeFieldName: 'the-time-field-name', + ...paramsMock, includeFrozen: true, - searchQuery: '{"bool":{"filter":[],"must":[{"match_all":{}}],"must_not":[]}}', - start: 1577836800000, - end: 1609459200000, - baselineMin: 10, - baselineMax: 20, - deviationMin: 30, - deviationMax: 40, }); expect(requestBase.ignore_throttled).toEqual(false); }); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_total_doc_count_request.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_total_doc_count_request.ts new file mode 100644 index 000000000000..e9b0fc853535 --- /dev/null +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_total_doc_count_request.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import type { AiopsLogRateAnalysisSchema } from '../../../../common/api/log_rate_analysis/schema'; + +import { getQueryWithParams } from './get_query_with_params'; +import { getRequestBase } from './get_request_base'; + +export const getTotalDocCountRequest = ( + params: AiopsLogRateAnalysisSchema +): estypes.SearchRequest => ({ + ...getRequestBase(params), + body: { + fields: ['*'], + _source: false, + query: getQueryWithParams({ params }), + size: 0, + track_total_hits: true, + }, +}); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/response_stream_factory.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/response_stream_factory.ts index f54c2e93dd29..0dce9c7cf34d 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/response_stream_factory.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/response_stream_factory.ts @@ -22,6 +22,7 @@ import { groupingHandlerFactory } from './analysis_handlers/grouping_handler'; import { histogramHandlerFactory } from './analysis_handlers/histogram_handler'; import { overridesHandlerFactory } from './analysis_handlers/overrides_handler'; import { significantItemsHandlerFactory } from './analysis_handlers/significant_items_handler'; +import { topItemsHandlerFactory } from './analysis_handlers/top_items_handler'; import { overallHistogramHandlerFactory } from './analysis_handlers/overall_histogram_handler'; import { logDebugMessageFactory, @@ -131,6 +132,7 @@ export const responseStreamFactory = (options: ResponseStr overallHistogramHandler: overallHistogramHandlerFactory(streamFetchOptions), overridesHandler: overridesHandlerFactory(streamFetchOptions), significantItemsHandler: significantItemsHandlerFactory(streamFetchOptions), + topItemsHandler: topItemsHandlerFactory(streamFetchOptions), }, responseWithHeaders, }; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/route_handler_factory.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/route_handler_factory.ts index 3c1bcde38ebd..e0a9b9c3e980 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/route_handler_factory.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/route_handler_factory.ts @@ -92,7 +92,9 @@ export function routeHandlerFactory( } // Step 2: Significant categories and terms - const significantItemsObj = await analysis.significantItemsHandler(indexInfo); + const significantItemsObj = indexInfo.zeroDocsFallback + ? await analysis.topItemsHandler(indexInfo) + : await analysis.significantItemsHandler(indexInfo); if (!significantItemsObj) { return; diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 66d996fe0b00..4e2e4bfc8a19 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -23,7 +23,6 @@ "@kbn/data-views-plugin", "@kbn/datemath", "@kbn/es-query", - "@kbn/es-types", "@kbn/field-formats-plugin", "@kbn/field-types", "@kbn/i18n-react", @@ -66,6 +65,7 @@ "@kbn/ml-chi2test", "@kbn/usage-collection-plugin", "@kbn/analytics", + "@kbn/ml-ui-actions", "@kbn/core-http-server", ], "exclude": [ diff --git a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts index e58b795863e4..24aa552f6a1e 100644 --- a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts +++ b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts @@ -242,6 +242,11 @@ describe('mappingFromFieldMap', () => { }, reason: { type: 'keyword', + fields: { + text: { + type: 'match_only_text', + }, + }, }, rule: { properties: { @@ -306,6 +311,9 @@ describe('mappingFromFieldMap', () => { workflow_tags: { type: 'keyword', }, + workflow_assignee_ids: { + type: 'keyword', + }, }, }, space_ids: { diff --git a/x-pack/plugins/alerting/common/constants/plugin.ts b/x-pack/plugins/alerting/common/constants/plugin.ts new file mode 100644 index 000000000000..e8136f257d46 --- /dev/null +++ b/x-pack/plugins/alerting/common/constants/plugin.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LicenseType } from '@kbn/licensing-plugin/server'; + +export const PLUGIN = { + ID: 'alerting', + MINIMUM_LICENSE_REQUIRED: 'basic' as LicenseType, // TODO: supposed to be changed up on requirements + // all plugins seem to use getI18nName with any + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getI18nName: (i18n: any): string => + i18n.translate('xpack.alerting.appName', { + defaultMessage: 'Alerting', + }), +}; diff --git a/x-pack/plugins/alerting/common/disabled_action_groups.ts b/x-pack/plugins/alerting/common/disabled_action_groups.ts index 352fbb03524a..b6b603c10c0f 100644 --- a/x-pack/plugins/alerting/common/disabled_action_groups.ts +++ b/x-pack/plugins/alerting/common/disabled_action_groups.ts @@ -8,7 +8,7 @@ import { RecoveredActionGroup } from './builtin_action_groups'; const DisabledActionGroupsByActionType: Record = { - [RecoveredActionGroup.id]: ['.jira', '.servicenow', '.resilient'], + [RecoveredActionGroup.id]: ['.jira', '.resilient'], }; export const DisabledActionTypeIdsForActionGroup: Map = new Map( diff --git a/x-pack/plugins/alerting/common/maintenance_window.ts b/x-pack/plugins/alerting/common/maintenance_window.ts index 1f5bffea7708..8b7646670cc7 100644 --- a/x-pack/plugins/alerting/common/maintenance_window.ts +++ b/x-pack/plugins/alerting/common/maintenance_window.ts @@ -14,6 +14,13 @@ export enum MaintenanceWindowStatus { Archived = 'archived', } +export const filterStateStore = { + APP_STATE: 'appState', + GLOBAL_STATE: 'globalState', +} as const; + +export type FilterStateStore = typeof filterStateStore[keyof typeof filterStateStore]; + export interface MaintenanceWindowModificationMetadata { createdBy: string | null; updatedBy: string | null; @@ -26,6 +33,23 @@ export interface DateRange { lte: string; } +export interface ScopeQueryFilter { + query?: Record; + meta: Record; + $state?: { + store: FilterStateStore; + }; +} + +export interface ScopedQueryAttributes { + kql: string; + filters: ScopeQueryFilter[]; + dsl?: string; +} + +/** + * @deprecated Use the data/maintenance_window types instead + */ export interface MaintenanceWindowSOProperties { title: string; enabled: boolean; @@ -34,11 +58,18 @@ export interface MaintenanceWindowSOProperties { events: DateRange[]; rRule: RRuleParams; categoryIds?: string[] | null; + scopedQuery?: ScopedQueryAttributes | null; } +/** + * @deprecated Use the data/maintenance_window types instead + */ export type MaintenanceWindowSOAttributes = MaintenanceWindowSOProperties & MaintenanceWindowModificationMetadata; +/** + * @deprecated Use the application/maintenance_window types instead + */ export type MaintenanceWindow = MaintenanceWindowSOAttributes & { status: MaintenanceWindowStatus; eventStartTime: string | null; diff --git a/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/latest.ts b/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/latest.ts new file mode 100644 index 000000000000..6c32b4867cc0 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/latest.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { filterStateStore } from './v1'; +export type { FilterStateStore } from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/v1.ts b/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/v1.ts new file mode 100644 index 000000000000..bce6890c22f2 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/alerts_filter_query/constants/v1.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filterStateStore = { + APP_STATE: 'appState', + GLOBAL_STATE: 'globalState', +} as const; + +export type FilterStateStore = typeof filterStateStore[keyof typeof filterStateStore]; diff --git a/x-pack/plugins/alerting/common/routes/alerts_filter_query/index.ts b/x-pack/plugins/alerting/common/routes/alerts_filter_query/index.ts new file mode 100644 index 000000000000..093299dbe66f --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/alerts_filter_query/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { filterStateStore } from './constants/latest'; +export type { FilterStateStore } from './constants/latest'; +export { alertsFilterQuerySchema } from './schemas/latest'; + +export { filterStateStore as filterStateStoreV1 } from './constants/v1'; +export type { FilterStateStore as FilterStateStoreV1 } from './constants/v1'; +export { alertsFilterQuerySchema as alertsFilterQuerySchemaV1 } from './schemas/v1'; diff --git a/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/latest.ts b/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/latest.ts new file mode 100644 index 000000000000..b9ae85bd590c --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/latest.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { alertsFilterQuerySchema } from './v1'; diff --git a/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/v1.ts new file mode 100644 index 000000000000..08614efb96b7 --- /dev/null +++ b/x-pack/plugins/alerting/common/routes/alerts_filter_query/schemas/v1.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { filterStateStore } from '..'; + +export const alertsFilterQuerySchema = schema.object({ + kql: schema.string(), + filters: schema.arrayOf( + schema.object({ + query: schema.maybe(schema.recordOf(schema.string(), schema.any())), + meta: schema.recordOf(schema.string(), schema.any()), + $state: schema.maybe( + schema.object({ + store: schema.oneOf([ + schema.literal(filterStateStore.APP_STATE), + schema.literal(filterStateStore.GLOBAL_STATE), + ]), + }) + ), + }) + ), + dsl: schema.maybe(schema.string()), +}); diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/create/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/create/schemas/v1.ts index f10eb420963e..a715bd13f2f7 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/create/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/create/schemas/v1.ts @@ -8,10 +8,12 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowCategoryIdsSchemaV1 } from '../../../shared'; import { rRuleRequestSchemaV1 } from '../../../../r_rule'; +import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; export const createBodySchema = schema.object({ title: schema.string(), duration: schema.number(), r_rule: rRuleRequestSchemaV1, category_ids: maintenanceWindowCategoryIdsSchemaV1, + scoped_query: schema.maybe(schema.nullable(alertsFilterQuerySchemaV1)), }); diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/update/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/update/schemas/v1.ts index 970cd3442457..ac61048d760a 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/apis/update/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/apis/update/schemas/v1.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowCategoryIdsSchemaV1 } from '../../../shared'; import { rRuleRequestSchemaV1 } from '../../../../r_rule'; +import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; export const updateParamsSchema = schema.object({ id: schema.string(), @@ -19,4 +20,5 @@ export const updateBodySchema = schema.object({ duration: schema.maybe(schema.number()), r_rule: schema.maybe(rRuleRequestSchemaV1), category_ids: maintenanceWindowCategoryIdsSchemaV1, + scoped_query: schema.maybe(schema.nullable(alertsFilterQuerySchemaV1)), }); diff --git a/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts index 410a1dc1e439..648b2b806978 100644 --- a/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/maintenance_window/response/schemas/v1.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowStatusV1 } from '..'; import { maintenanceWindowCategoryIdsSchemaV1 } from '../../shared'; import { rRuleResponseSchemaV1 } from '../../../r_rule'; +import { alertsFilterQuerySchemaV1 } from '../../../alerts_filter_query'; export const maintenanceWindowEventSchema = schema.object({ gte: schema.string(), @@ -36,4 +37,5 @@ export const maintenanceWindowResponseSchema = schema.object({ schema.literal(maintenanceWindowStatusV1.ARCHIVED), ]), category_ids: maintenanceWindowCategoryIdsSchemaV1, + scoped_query: schema.maybe(schema.nullable(alertsFilterQuerySchemaV1)), }); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts index 751f2e8c3878..30a294d5c052 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { validateDurationV1, validateHoursV1, validateTimezoneV1 } from '../../../validation'; import { notifyWhenSchemaV1 } from '../../../response'; -import { filterStateStore } from '../../../common/constants/v1'; +import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; export const actionFrequencySchema = schema.object({ summary: schema.boolean(), @@ -17,26 +17,7 @@ export const actionFrequencySchema = schema.object({ }); export const actionAlertsFilterSchema = schema.object({ - query: schema.maybe( - schema.object({ - kql: schema.string(), - filters: schema.arrayOf( - schema.object({ - query: schema.maybe(schema.recordOf(schema.string(), schema.any())), - meta: schema.recordOf(schema.string(), schema.any()), - $state: schema.maybe( - schema.object({ - store: schema.oneOf([ - schema.literal(filterStateStore.APP_STATE), - schema.literal(filterStateStore.GLOBAL_STATE), - ]), - }) - ), - }) - ), - dsl: schema.maybe(schema.string()), - }) - ), + query: schema.maybe(alertsFilterQuerySchemaV1), timeframe: schema.maybe( schema.object({ days: schema.arrayOf( diff --git a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts index 0e043aa21766..1c7b202f5906 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts @@ -7,13 +7,13 @@ import { schema } from '@kbn/config-schema'; import { rRuleResponseSchemaV1 } from '../../../r_rule'; +import { alertsFilterQuerySchemaV1 } from '../../../alerts_filter_query'; import { ruleNotifyWhen as ruleNotifyWhenV1, ruleExecutionStatusValues as ruleExecutionStatusValuesV1, ruleExecutionStatusErrorReason as ruleExecutionStatusErrorReasonV1, ruleExecutionStatusWarningReason as ruleExecutionStatusWarningReasonV1, ruleLastRunOutcomeValues as ruleLastRunOutcomeValuesV1, - filterStateStore as filterStateStoreV1, } from '../../common/constants/v1'; import { validateNotifyWhenV1 } from '../../validation'; @@ -41,25 +41,7 @@ const actionFrequencySchema = schema.object({ }); const actionAlertsFilterSchema = schema.object({ - query: schema.maybe( - schema.object({ - kql: schema.string(), - filters: schema.arrayOf( - schema.object({ - query: schema.maybe(schema.recordOf(schema.string(), schema.any())), - meta: schema.recordOf(schema.string(), schema.any()), - $state: schema.maybe( - schema.object({ - store: schema.oneOf([ - schema.literal(filterStateStoreV1.APP_STATE), - schema.literal(filterStateStoreV1.GLOBAL_STATE), - ]), - }) - ), - }) - ), - }) - ), + query: schema.maybe(alertsFilterQuerySchemaV1), timeframe: schema.maybe( schema.object({ days: schema.arrayOf( diff --git a/x-pack/plugins/alerting/docs/openapi/bundled.json b/x-pack/plugins/alerting/docs/openapi/bundled.json index 6e09c658ae40..8688c79a8122 100644 --- a/x-pack/plugins/alerting/docs/openapi/bundled.json +++ b/x-pack/plugins/alerting/docs/openapi/bundled.json @@ -1,9 +1,9 @@ { - "openapi": "3.0.1", + "openapi": "3.1.0", "info": { "title": "Alerting", "description": "OpenAPI schema for alerting endpoints", - "version": "0.1", + "version": "0.2", "contact": { "name": "Alerting Team" }, @@ -239,7 +239,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } } ], @@ -496,9 +498,11 @@ "description": "The default operator to use for the simple_query_string.", "schema": { "type": "string", - "default": "OR" - }, - "example": "OR" + "default": "OR", + "examples": [ + "AND" + ] + } }, { "name": "fields", @@ -541,9 +545,11 @@ "description": "The page number to return.", "schema": { "type": "integer", - "default": 1 - }, - "example": 1 + "default": 1, + "examples": [ + 1 + ] + } }, { "name": "per_page", @@ -551,16 +557,21 @@ "description": "The number of rules to return per page.", "schema": { "type": "integer", - "default": 20 - }, - "example": 20 + "default": 20, + "examples": [ + 20 + ] + } }, { "name": "search", "in": "query", "description": "An Elasticsearch simple_query_string query that filters the objects in the response.", "schema": { - "type": "string" + "type": "string", + "examples": [ + "threshold +-test*" + ] } }, { @@ -570,7 +581,10 @@ "schema": { "oneOf": [ { - "type": "string" + "type": "string", + "examples": [ + "name" + ] }, { "type": "array", @@ -599,9 +613,11 @@ "asc", "desc" ], - "default": "desc" - }, - "example": "asc" + "default": "desc", + "examples": [ + "asc" + ] + } } ], "responses": { @@ -684,7 +700,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -694,7 +712,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } }, @@ -704,7 +724,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -714,7 +736,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } }, @@ -724,7 +748,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -734,7 +760,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } } @@ -743,12 +771,16 @@ "has_permanent_encryption_key": { "type": "boolean", "description": "If `false`, the encrypted saved object plugin does not have a permanent encryption key.", - "example": true + "examples": [ + true + ] }, "is_sufficiently_secure": { "type": "boolean", "description": "If `false`, security is enabled but TLS is not.", - "example": true + "examples": [ + true + ] } } }, @@ -1030,7 +1062,9 @@ "minimum_license_required": { "description": "The subscriptions required to use the rule type.", "type": "string", - "example": "basic" + "examples": [ + "basic" + ] }, "name": { "description": "The descriptive name of the rule type.", @@ -1039,7 +1073,9 @@ "producer": { "description": "An identifier for the application that produces this rule type.", "type": "string", - "example": "stackAlerts" + "examples": [ + "stackAlerts" + ] }, "recovery_action_group": { "description": "An action group to use when an alert goes from an active state to an inactive one.", @@ -1055,7 +1091,9 @@ }, "rule_task_timeout": { "type": "string", - "example": "5m" + "examples": [ + "5m" + ] } } } @@ -1290,7 +1328,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1329,7 +1369,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1375,7 +1417,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } }, { @@ -1464,7 +1508,9 @@ "interval": { "type": "string", "description": "The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute.", - "example": "10s" + "examples": [ + "10s" + ] } } }, @@ -1529,7 +1575,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1601,7 +1649,9 @@ "interval": { "type": "string", "description": "The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute.", - "example": "1d" + "examples": [ + "1d" + ] } } }, @@ -1668,7 +1718,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1712,7 +1764,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1756,7 +1810,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1800,7 +1856,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } } ], @@ -1840,9 +1898,11 @@ "description": "The default operator to use for the `simple_query_string`.", "schema": { "type": "string", - "default": "OR" - }, - "example": "OR" + "default": "OR", + "examples": [ + "OR" + ] + } }, { "name": "fields", @@ -1885,9 +1945,11 @@ "description": "The page number to return.", "schema": { "type": "integer", - "default": 1 - }, - "example": 1 + "default": 1, + "examples": [ + 1 + ] + } }, { "name": "per_page", @@ -1895,9 +1957,11 @@ "description": "The number of alerts to return per page.", "schema": { "type": "integer", - "default": 20 - }, - "example": 20 + "default": 20, + "examples": [ + 20 + ] + } }, { "name": "search", @@ -1943,9 +2007,11 @@ "asc", "desc" ], - "default": "desc" - }, - "example": "asc" + "default": "desc", + "examples": [ + "asc" + ] + } } ], "responses": { @@ -2021,7 +2087,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -2031,7 +2099,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } }, @@ -2041,7 +2111,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -2051,7 +2123,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } }, @@ -2061,7 +2135,9 @@ "properties": { "status": { "type": "string", - "example": "ok", + "examples": [ + "ok" + ], "enum": [ "error", "ok", @@ -2071,7 +2147,9 @@ "timestamp": { "type": "string", "format": "date-time", - "example": "2023-01-13T01:28:00.280Z" + "examples": [ + "2023-01-13T01:28:00.280Z" + ] } } } @@ -2080,12 +2158,16 @@ "hasPermanentEncryptionKey": { "type": "boolean", "description": "If `false`, the encrypted saved object plugin does not have a permanent encryption key.", - "example": true + "examples": [ + true + ] }, "isSufficientlySecure": { "type": "boolean", "description": "If `false`, security is enabled but TLS is not.", - "example": true + "examples": [ + true + ] } } } @@ -2278,7 +2360,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } }, { @@ -2288,7 +2372,9 @@ "required": true, "schema": { "type": "string", - "example": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2" + "examples": [ + "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2" + ] } } ], @@ -2332,7 +2418,9 @@ "required": true, "schema": { "type": "string", - "example": "41893910-6bca-11eb-9e0d-85d233e3ee35" + "examples": [ + "41893910-6bca-11eb-9e0d-85d233e3ee35" + ] } }, { @@ -2342,7 +2430,9 @@ "required": true, "schema": { "type": "string", - "example": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2" + "examples": [ + "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2" + ] } } ], @@ -2373,7 +2463,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "parameters": { @@ -2393,7 +2484,9 @@ "required": true, "schema": { "type": "string", - "example": "default" + "examples": [ + "default" + ] } }, "rule_id": { @@ -2403,7 +2496,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } }, "alert_id": { @@ -2413,7 +2508,9 @@ "required": true, "schema": { "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + "examples": [ + "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + ] } } }, @@ -2426,8 +2523,10 @@ "type": "object", "properties": { "alias": { - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "controlledBy": { "type": "string" @@ -2480,19 +2579,27 @@ "onActiveAlert", "onThrottleInterval" ], - "example": "onActiveAlert" + "examples": [ + "onActiveAlert" + ] }, "throttle": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if `notify_when` is set to `onThrottleInterval`. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.\n", - "nullable": true, "default": null, - "example": "10m" + "examples": [ + "10m" + ] }, "actions": { - "type": "array", + "type": [ + "array", + "null" + ], "default": [], - "nullable": true, "items": { "type": "object", "required": [ @@ -2532,12 +2639,14 @@ "items": { "type": "integer" }, - "example": [ - 1, - 2, - 3, - 4, - 5 + "examples": [ + [ + 1, + 2, + 3, + 4, + 5 + ] ] }, "hours": { @@ -2547,19 +2656,25 @@ "end": { "type": "string", "description": "The end of the time frame in 24-hour notation (`hh:mm`).", - "example": "17:00" + "examples": [ + "17:00" + ] }, "start": { "type": "string", "description": "The start of the time frame in 24-hour notation (`hh:mm`).", - "example": "08:00" + "examples": [ + "08:00" + ] } } }, "timezone": { "type": "string", "description": "The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended.\n", - "example": "Europe/Madrid" + "examples": [ + "Europe/Madrid" + ] } } } @@ -2568,7 +2683,9 @@ "connector_type_id": { "type": "string", "description": "The type of connector. This property appears in responses but cannot be set in requests.", - "example": ".server-log", + "examples": [ + ".server-log" + ], "readOnly": true }, "frequency": { @@ -2594,12 +2711,16 @@ "group": { "type": "string", "description": "The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`.\n", - "example": "default" + "examples": [ + "default" + ] }, "id": { "type": "string", "description": "The identifier for the connector saved object.", - "example": "9dca3e00-74f5-11ed-9801-35303b735aef" + "examples": [ + "9dca3e00-74f5-11ed-9801-35303b735aef" + ] }, "params": { "type": "object", @@ -2609,7 +2730,9 @@ "uuid": { "type": "string", "description": "A universally unique identifier (UUID) for the action.", - "example": "1c7a1280-f28c-4e06-96b2-e4e5f05d1d61" + "examples": [ + "1c7a1280-f28c-4e06-96b2-e4e5f05d1d61" + ] } } } @@ -2632,7 +2755,9 @@ "properties": { "interval": { "type": "string", - "example": "1m" + "examples": [ + "1m" + ] } } }, @@ -3210,7 +3335,9 @@ "timewindowsize": { "description": "The size of the time window (in `timeWindowUnit` units), which determines how far back to search for documents. Generally it should be a value higher than the rule check interval to avoid gaps in detection.\n", "type": "integer", - "example": 5 + "examples": [ + 5 + ] }, "timewindowunit": { "description": "The type of units for the time window: seconds, minutes, hours, or days.\n", @@ -3221,7 +3348,9 @@ "h", "d" ], - "example": "m" + "examples": [ + "m" + ] }, "size": { "description": "The number of documents to pass to the configured actions when the threshold condition is met.\n", @@ -3247,7 +3376,9 @@ "type": "array", "items": { "type": "integer", - "example": 4000 + "examples": [ + 4000 + ] } }, "thresholdcomparator": { @@ -3261,7 +3392,9 @@ "between", "notBetween" ], - "example": ">" + "examples": [ + ">" + ] }, "params_es_query_rule": { "oneOf": [ @@ -3309,12 +3442,16 @@ "enum": [ "esqlQuery" ], - "example": "esqlQuery" + "examples": [ + "esqlQuery" + ] }, "size": { "type": "integer", "description": "When `searchType` is `esqlQuery`, this property is required but it does not affect the rule behavior.\n", - "example": 0 + "examples": [ + 0 + ] }, "termSize": { "$ref": "#/components/schemas/termsize" @@ -3334,7 +3471,9 @@ "enum": [ ">" ], - "example": ">" + "examples": [ + ">" + ] }, "timeField": { "$ref": "#/components/schemas/timefield" @@ -3400,7 +3539,9 @@ "properties": { "language": { "type": "string", - "example": "kuery" + "examples": [ + "kuery" + ] }, "query": { "type": "string" @@ -3415,7 +3556,9 @@ "enum": [ "searchSource" ], - "example": "searchSource" + "examples": [ + "searchSource" + ] }, "size": { "$ref": "#/components/schemas/size" @@ -3493,7 +3636,9 @@ "esQuery" ], "default": "esQuery", - "example": "esQuery" + "examples": [ + "esQuery" + ] }, "size": { "$ref": "#/components/schemas/size" @@ -6318,58 +6463,82 @@ "api_key_created_by_user": { "type": "boolean", "description": "Indicates whether the API key that is associated with the rule was created by the user.", - "example": false + "examples": [ + false + ] }, "api_key_owner": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "The owner of the API key that is associated with the rule and used to run background tasks.\n", - "nullable": true, - "example": "elastic" + "examples": [ + "elastic" + ] }, "consumer": { "type": "string", "description": "The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.", - "example": "alerts" + "examples": [ + "alerts" + ] }, "created_at": { "type": "string", "description": "The date and time that the rule was created.", "format": "date-time", - "example": "2022-12-05T23:36:58.284Z" + "examples": [ + "2022-12-05T23:36:58.284Z" + ] }, "created_by": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "The identifier for the user that created the rule.", - "nullable": true, - "example": "elastic" + "examples": [ + "elastic" + ] }, "enabled": { "type": "boolean", "description": "Indicates whether the rule is currently enabled.", - "example": true + "examples": [ + true + ] }, "execution_status": { "type": "object", "properties": { "last_duration": { "type": "integer", - "example": 55 + "examples": [ + 55 + ] }, "last_execution_date": { "type": "string", "format": "date-time", - "example": "2022-12-06T00:13:43.890Z" + "examples": [ + "2022-12-06T00:13:43.890Z" + ] }, "status": { "type": "string", - "example": "ok" + "examples": [ + "ok" + ] } } }, "id": { "type": "string", "description": "The identifier for the rule.", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" + "examples": [ + "b530fed0-74f5-11ed-9801-35303b735aef" + ] }, "last_run": { "type": "object", @@ -6393,51 +6562,71 @@ }, "outcome": { "type": "string", - "example": "succeeded" + "examples": [ + "succeeded" + ] }, "outcome_msg": { - "type": "array", + "type": [ + "array", + "null" + ], "items": { "type": "string" - }, - "nullable": true + } }, "outcome_order": { "type": "integer" }, "warning": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] } } }, "muted_alert_ids": { - "type": "array", - "nullable": true, + "type": [ + "array", + "null" + ], "items": { "type": "string" } }, "mute_all": { "type": "boolean", - "example": false + "examples": [ + false + ] }, "name": { "type": "string", "description": "The name of the rule.", - "example": "cluster_health_rule" + "examples": [ + "cluster_health_rule" + ] }, "next_run": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-12-06T00:14:43.818Z" + "examples": [ + "2022-12-06T00:14:43.818Z" + ] }, "notify_when": { - "type": "string", - "description": "Indicates how often alerts generate actions.", - "nullable": true + "type": [ + "string", + "null" + ], + "description": "Indicates how often alerts generate actions." }, "params": { "type": "object", @@ -6451,7 +6640,9 @@ "rule_type_id": { "type": "string", "description": "The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`.\n", - "example": "monitoring_alert_cluster_health" + "examples": [ + "monitoring_alert_cluster_health" + ] }, "running": { "type": "boolean", @@ -6462,7 +6653,9 @@ }, "scheduled_task_id": { "type": "string", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" + "examples": [ + "b530fed0-74f5-11ed-9801-35303b735aef" + ] }, "tags": { "$ref": "#/components/schemas/tags" @@ -6473,13 +6666,19 @@ "updated_at": { "type": "string", "description": "The date and time that the rule was updated most recently.", - "example": "2022-12-05T23:36:58.284Z" + "examples": [ + "2022-12-05T23:36:58.284Z" + ] }, "updated_by": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "The identifier for the user that updated this rule most recently.", - "nullable": true, - "example": "elastic" + "examples": [ + "elastic" + ] } } }, @@ -6489,7 +6688,9 @@ "properties": { "error": { "type": "string", - "example": "Unauthorized", + "examples": [ + "Unauthorized" + ], "enum": [ "Unauthorized" ] @@ -6499,7 +6700,9 @@ }, "statusCode": { "type": "integer", - "example": 401, + "examples": [ + 401 + ], "enum": [ 401 ] @@ -6511,18 +6714,24 @@ "properties": { "error": { "type": "string", - "example": "Not Found", + "examples": [ + "Not Found" + ], "enum": [ "Not Found" ] }, "message": { "type": "string", - "example": "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" + "examples": [ + "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" + ] }, "statusCode": { "type": "integer", - "example": 404, + "examples": [ + 404 + ], "enum": [ 404 ] @@ -6545,7 +6754,9 @@ "name": { "type": "string", "description": "The name of the rule.", - "example": "cluster_health_rule" + "examples": [ + "cluster_health_rule" + ] }, "notify_when": { "$ref": "#/components/schemas/notify_when" @@ -6604,28 +6815,40 @@ }, "alertTypeId": { "type": "string", - "example": ".index-threshold" + "examples": [ + ".index-threshold" + ] }, "apiKeyOwner": { - "type": "string", - "nullable": true, - "example": "elastic" + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] }, "createdAt": { "type": "string", "description": "The date and time that the alert was created.", "format": "date-time", - "example": "2022-12-05T23:36:58.284Z" + "examples": [ + "2022-12-05T23:36:58.284Z" + ] }, "createdBy": { "type": "string", "description": "The identifier for the user that created the alert.", - "example": "elastic" + "examples": [ + "elastic" + ] }, "enabled": { "type": "boolean", "description": "Indicates whether the alert is currently enabled.", - "example": true + "examples": [ + true + ] }, "executionStatus": { "type": "object", @@ -6633,26 +6856,36 @@ "lastExecutionDate": { "type": "string", "format": "date-time", - "example": "2022-12-06T00:13:43.890Z" + "examples": [ + "2022-12-06T00:13:43.890Z" + ] }, "status": { "type": "string", - "example": "ok" + "examples": [ + "ok" + ] } } }, "id": { "type": "string", "description": "The identifier for the alert.", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" + "examples": [ + "b530fed0-74f5-11ed-9801-35303b735aef" + ] }, "muteAll": { "type": "boolean", - "example": false + "examples": [ + false + ] }, "mutedInstanceIds": { - "type": "array", - "nullable": true, + "type": [ + "array", + "null" + ], "items": { "type": "string" } @@ -6660,11 +6893,15 @@ "name": { "type": "string", "description": "The name of the alert.", - "example": "my alert" + "examples": [ + "my alert" + ] }, "notifyWhen": { "type": "string", - "example": "onActionGroupChange" + "examples": [ + "onActionGroupChange" + ] }, "params": { "type": "object", @@ -6680,7 +6917,9 @@ }, "scheduledTaskId": { "type": "string", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" + "examples": [ + "b530fed0-74f5-11ed-9801-35303b735aef" + ] }, "tags": { "type": "array", @@ -6689,18 +6928,26 @@ } }, "throttle": { - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "updatedAt": { "type": "string", - "example": "2022-12-05T23:36:58.284Z" + "examples": [ + "2022-12-05T23:36:58.284Z" + ] }, "updatedBy": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "The identifier for the user that updated this alert most recently.", - "nullable": true, - "example": "elastic" + "examples": [ + "elastic" + ] } } } diff --git a/x-pack/plugins/alerting/docs/openapi/bundled.yaml b/x-pack/plugins/alerting/docs/openapi/bundled.yaml index 424326e12c8f..83fec9274220 100644 --- a/x-pack/plugins/alerting/docs/openapi/bundled.yaml +++ b/x-pack/plugins/alerting/docs/openapi/bundled.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Alerting description: OpenAPI schema for alerting endpoints - version: '0.1' + version: '0.2' contact: name: Alerting Team license: @@ -147,7 +147,8 @@ paths: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -303,7 +304,8 @@ paths: schema: type: string default: OR - example: OR + examples: + - AND - name: fields in: query description: The fields to return in the `attributes` key of the response. @@ -333,25 +335,31 @@ paths: schema: type: integer default: 1 - example: 1 + examples: + - 1 - name: per_page in: query description: The number of rules to return per page. schema: type: integer default: 20 - example: 20 + examples: + - 20 - name: search in: query description: An Elasticsearch simple_query_string query that filters the objects in the response. schema: type: string + examples: + - threshold +-test* - name: search_fields in: query description: The fields to perform the simple_query_string parsed query against. schema: oneOf: - type: string + examples: + - name - type: array items: type: string @@ -370,7 +378,8 @@ paths: - asc - desc default: desc - example: asc + examples: + - asc responses: '200': description: Indicates a successful call. @@ -429,7 +438,8 @@ paths: properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -437,14 +447,16 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' execution_health: type: object description: The timestamp and status of the rule run. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -452,14 +464,16 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' read_health: type: object description: The timestamp and status of the rule reading events. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -467,15 +481,18 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' has_permanent_encryption_key: type: boolean description: If `false`, the encrypted saved object plugin does not have a permanent encryption key. - example: true + examples: + - true is_sufficiently_secure: type: boolean description: If `false`, security is enabled but TLS is not. - example: true + examples: + - true examples: getAlertingHealthResponse: $ref: '#/components/examples/get_health_response' @@ -662,14 +679,16 @@ paths: minimum_license_required: description: The subscriptions required to use the rule type. type: string - example: basic + examples: + - basic name: description: The descriptive name of the rule type. type: string producer: description: An identifier for the application that produces this rule type. type: string - example: stackAlerts + examples: + - stackAlerts recovery_action_group: description: An action group to use when an alert goes from an active state to an inactive one. type: object @@ -680,7 +699,8 @@ paths: type: string rule_task_timeout: type: string - example: 5m + examples: + - 5m examples: getRuleTypesResponse: $ref: '#/components/examples/get_rule_types_response' @@ -814,7 +834,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -839,7 +860,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '200': description: Indicates a successful call. @@ -868,7 +890,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - $ref: '#/components/parameters/space_id' requestBody: required: true @@ -939,7 +962,8 @@ paths: interval: type: string description: The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute. - example: 10s + examples: + - 10s tags: type: array items: @@ -978,7 +1002,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 requestBody: required: true content: @@ -1037,7 +1062,8 @@ paths: interval: type: string description: The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute. - example: 1d + examples: + - 1d tags: type: array items: @@ -1077,7 +1103,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -1104,7 +1131,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -1131,7 +1159,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -1158,7 +1187,8 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -1185,7 +1215,8 @@ paths: schema: type: string default: OR - example: OR + examples: + - OR - name: fields in: query description: The fields to return in the `attributes` key of the response. @@ -1215,14 +1246,16 @@ paths: schema: type: integer default: 1 - example: 1 + examples: + - 1 - name: per_page in: query description: The number of alerts to return per page. schema: type: integer default: 20 - example: 20 + examples: + - 20 - name: search in: query description: An Elasticsearch `simple_query_string` query that filters the alerts in the response. @@ -1252,7 +1285,8 @@ paths: - asc - desc default: desc - example: asc + examples: + - asc responses: '200': description: Indicates a successful call. @@ -1306,7 +1340,8 @@ paths: properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -1314,14 +1349,16 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' executionHealth: type: object description: The timestamp and status of the alert execution. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -1329,14 +1366,16 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' readHealth: type: object description: The timestamp and status of the alert reading events. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -1344,15 +1383,18 @@ paths: timestamp: type: string format: date-time - example: '2023-01-13T01:28:00.280Z' + examples: + - '2023-01-13T01:28:00.280Z' hasPermanentEncryptionKey: type: boolean description: If `false`, the encrypted saved object plugin does not have a permanent encryption key. - example: true + examples: + - true isSufficientlySecure: type: boolean description: If `false`, security is enabled but TLS is not. - example: true + examples: + - true '401': description: Authorization information is missing or invalid. content: @@ -1478,14 +1520,16 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - in: path name: alertInstanceId description: An identifier for the alert instance. required: true schema: type: string - example: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + examples: + - dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 responses: '204': description: Indicates a successful call. @@ -1512,14 +1556,16 @@ paths: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - in: path name: alertInstanceId description: An identifier for the alert instance. required: true schema: type: string - example: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + examples: + - dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 responses: '204': description: Indicates a successful call. @@ -1537,7 +1583,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -1553,7 +1600,8 @@ components: required: true schema: type: string - example: default + examples: + - default rule_id: in: path name: ruleId @@ -1561,7 +1609,8 @@ components: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 alert_id: in: path name: alertId @@ -1569,7 +1618,8 @@ components: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 schemas: filter: type: object @@ -1579,8 +1629,9 @@ components: type: object properties: alias: - type: string - nullable: true + type: + - string + - 'null' controlledBy: type: string disabled: @@ -1615,18 +1666,22 @@ components: - onActionGroupChange - onActiveAlert - onThrottleInterval - example: onActiveAlert + examples: + - onActiveAlert throttle: - type: string + type: + - string + - 'null' description: | The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if `notify_when` is set to `onThrottleInterval`. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values. - nullable: true default: null - example: 10m + examples: + - 10m actions: - type: array + type: + - array + - 'null' default: [] - nullable: true items: type: object required: @@ -1661,12 +1716,12 @@ components: description: Defines the days of the week that the action can run, represented as an array of numbers. For example, `1` represents Monday. An empty array is equivalent to specifying all the days of the week. items: type: integer - example: - - 1 - - 2 - - 3 - - 4 - - 5 + examples: + - - 1 + - 2 + - 3 + - 4 + - 5 hours: type: object description: | @@ -1675,20 +1730,24 @@ components: end: type: string description: The end of the time frame in 24-hour notation (`hh:mm`). - example: '17:00' + examples: + - '17:00' start: type: string description: The start of the time frame in 24-hour notation (`hh:mm`). - example: '08:00' + examples: + - '08:00' timezone: type: string description: | The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended. - example: Europe/Madrid + examples: + - Europe/Madrid connector_type_id: type: string description: The type of connector. This property appears in responses but cannot be set in requests. - example: .server-log + examples: + - .server-log readOnly: true frequency: type: object @@ -1709,11 +1768,13 @@ components: type: string description: | The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`. - example: default + examples: + - default id: type: string description: The identifier for the connector saved object. - example: 9dca3e00-74f5-11ed-9801-35303b735aef + examples: + - 9dca3e00-74f5-11ed-9801-35303b735aef params: type: object description: The parameters for the action, which are sent to the connector. The `params` are handled as Mustache templates and passed a default set of context. @@ -1721,7 +1782,8 @@ components: uuid: type: string description: A universally unique identifier (UUID) for the action. - example: 1c7a1280-f28c-4e06-96b2-e4e5f05d1d61 + examples: + - 1c7a1280-f28c-4e06-96b2-e4e5f05d1d61 consumer: type: string description: | @@ -1739,7 +1801,8 @@ components: properties: interval: type: string - example: 1m + examples: + - 1m tags: type: array description: The tags for the rule. @@ -2170,7 +2233,8 @@ components: description: | The size of the time window (in `timeWindowUnit` units), which determines how far back to search for documents. Generally it should be a value higher than the rule check interval to avoid gaps in detection. type: integer - example: 5 + examples: + - 5 timewindowunit: description: | The type of units for the time window: seconds, minutes, hours, or days. @@ -2180,7 +2244,8 @@ components: - m - h - d - example: m + examples: + - m size: description: | The number of documents to pass to the configured actions when the threshold condition is met. @@ -2200,7 +2265,8 @@ components: type: array items: type: integer - example: 4000 + examples: + - 4000 thresholdcomparator: description: The comparison function for the threshold. For example, "is above", "is above or equals", "is below", "is below or equals", "is between", and "is not between". type: string @@ -2211,7 +2277,8 @@ components: - <= - between - notBetween - example: '>' + examples: + - '>' params_es_query_rule: oneOf: - type: object @@ -2248,12 +2315,14 @@ components: type: string enum: - esqlQuery - example: esqlQuery + examples: + - esqlQuery size: type: integer description: | When `searchType` is `esqlQuery`, this property is required but it does not affect the rule behavior. - example: 0 + examples: + - 0 termSize: $ref: '#/components/schemas/termsize' threshold: @@ -2270,7 +2339,8 @@ components: The comparison function for the threshold. When `searchType` is `esqlQuery`, this property is required and must be set to ">". Since the `threshold` value must be `0`, the result is that an alert occurs whenever the query returns results. enum: - '>' - example: '>' + examples: + - '>' timeField: $ref: '#/components/schemas/timefield' timeWindowSize: @@ -2315,7 +2385,8 @@ components: properties: language: type: string - example: kuery + examples: + - kuery query: type: string searchType: @@ -2323,7 +2394,8 @@ components: type: string enum: - searchSource - example: searchSource + examples: + - searchSource size: $ref: '#/components/schemas/size' termField: @@ -2375,7 +2447,8 @@ components: enum: - esQuery default: esQuery - example: esQuery + examples: + - esQuery size: $ref: '#/components/schemas/size' termField: @@ -4357,48 +4430,60 @@ components: api_key_created_by_user: type: boolean description: Indicates whether the API key that is associated with the rule was created by the user. - example: false + examples: + - false api_key_owner: - type: string + type: + - string + - 'null' description: | The owner of the API key that is associated with the rule and used to run background tasks. - nullable: true - example: elastic + examples: + - elastic consumer: type: string description: The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. - example: alerts + examples: + - alerts created_at: type: string description: The date and time that the rule was created. format: date-time - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' created_by: - type: string + type: + - string + - 'null' description: The identifier for the user that created the rule. - nullable: true - example: elastic + examples: + - elastic enabled: type: boolean description: Indicates whether the rule is currently enabled. - example: true + examples: + - true execution_status: type: object properties: last_duration: type: integer - example: 55 + examples: + - 55 last_execution_date: type: string format: date-time - example: '2022-12-06T00:13:43.890Z' + examples: + - '2022-12-06T00:13:43.890Z' status: type: string - example: ok + examples: + - ok id: type: string description: The identifier for the rule. - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef last_run: type: object properties: @@ -4415,39 +4500,49 @@ components: type: integer outcome: type: string - example: succeeded + examples: + - succeeded outcome_msg: - type: array + type: + - array + - 'null' items: type: string - nullable: true outcome_order: type: integer warning: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null muted_alert_ids: - type: array - nullable: true + type: + - array + - 'null' items: type: string mute_all: type: boolean - example: false + examples: + - false name: type: string description: The name of the rule. - example: cluster_health_rule + examples: + - cluster_health_rule next_run: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-12-06T00:14:43.818Z' + examples: + - '2022-12-06T00:14:43.818Z' notify_when: - type: string + type: + - string + - 'null' description: Indicates how often alerts generate actions. - nullable: true params: type: object description: The parameters for the rule. @@ -4459,7 +4554,8 @@ components: type: string description: | The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. - example: monitoring_alert_cluster_health + examples: + - monitoring_alert_cluster_health running: type: boolean description: Indicates whether the rule is running. @@ -4467,7 +4563,8 @@ components: $ref: '#/components/schemas/schedule' scheduled_task_id: type: string - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef tags: $ref: '#/components/schemas/tags' throttle: @@ -4475,26 +4572,31 @@ components: updated_at: type: string description: The date and time that the rule was updated most recently. - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' updated_by: - type: string + type: + - string + - 'null' description: The identifier for the user that updated this rule most recently. - nullable: true - example: elastic + examples: + - elastic 401_response: type: object title: Unsuccessful rule API response properties: error: type: string - example: Unauthorized + examples: + - Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 enum: - 401 404_response: @@ -4502,15 +4604,18 @@ components: properties: error: type: string - example: Not Found + examples: + - Not Found enum: - Not Found message: type: string - example: Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found + examples: + - Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found statusCode: type: integer - example: 404 + examples: + - 404 enum: - 404 update_rule_request: @@ -4528,7 +4633,8 @@ components: name: type: string description: The name of the rule. - example: cluster_health_rule + examples: + - cluster_health_rule notify_when: $ref: '#/components/schemas/notify_when' params: @@ -4569,53 +4675,66 @@ components: type: object alertTypeId: type: string - example: .index-threshold + examples: + - .index-threshold apiKeyOwner: - type: string - nullable: true - example: elastic + type: + - string + - 'null' + examples: + - elastic createdAt: type: string description: The date and time that the alert was created. format: date-time - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' createdBy: type: string description: The identifier for the user that created the alert. - example: elastic + examples: + - elastic enabled: type: boolean description: Indicates whether the alert is currently enabled. - example: true + examples: + - true executionStatus: type: object properties: lastExecutionDate: type: string format: date-time - example: '2022-12-06T00:13:43.890Z' + examples: + - '2022-12-06T00:13:43.890Z' status: type: string - example: ok + examples: + - ok id: type: string description: The identifier for the alert. - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef muteAll: type: boolean - example: false + examples: + - false mutedInstanceIds: - type: array - nullable: true + type: + - array + - 'null' items: type: string name: type: string description: The name of the alert. - example: my alert + examples: + - my alert notifyWhen: type: string - example: onActionGroupChange + examples: + - onActionGroupChange params: type: object additionalProperties: true @@ -4626,22 +4745,27 @@ components: type: string scheduledTaskId: type: string - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef tags: type: array items: type: string throttle: - type: string - nullable: true + type: + - string + - 'null' updatedAt: type: string - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' updatedBy: - type: string + type: + - string + - 'null' description: The identifier for the user that updated this alert most recently. - nullable: true - example: elastic + examples: + - elastic examples: create_es_query_esql_rule_request: summary: Create an Elasticsearch query rule that uses Elasticsearch Query Language (ES|QL). diff --git a/x-pack/plugins/alerting/docs/openapi/components/parameters/alert_id.yaml b/x-pack/plugins/alerting/docs/openapi/components/parameters/alert_id.yaml index 27427e1ec675..3ae77530b04d 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/parameters/alert_id.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/parameters/alert_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the alert. The identifier is generated by the rul required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 \ No newline at end of file + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/parameters/rule_id.yaml b/x-pack/plugins/alerting/docs/openapi/components/parameters/rule_id.yaml index 4b5d14e20735..18cadc0e5d7e 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/parameters/rule_id.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/parameters/rule_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the rule. required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 \ No newline at end of file + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/parameters/space_id.yaml b/x-pack/plugins/alerting/docs/openapi/components/parameters/space_id.yaml index 0a9fba457e3e..45787e844cae 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/parameters/space_id.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/parameters/space_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the space. If `/s/` and the identifier are omitte required: true schema: type: string - example: default + examples: + - default diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/401_response.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/401_response.yaml index c6044998f864..ed5e2a823bc0 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/401_response.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/401_response.yaml @@ -3,13 +3,15 @@ title: Unsuccessful rule API response properties: error: type: string - example: Unauthorized + examples: + - Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 enum: - 401 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/404_response.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/404_response.yaml index 1b8a118703ec..875307d5a389 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/404_response.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/404_response.yaml @@ -2,14 +2,17 @@ type: object properties: error: type: string - example: Not Found + examples: + - Not Found enum: - Not Found message: type: string - example: "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" + examples: + - "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" statusCode: type: integer - example: 404 + examples: + - 404 enum: - 404 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/actions.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/actions.yaml index ee11bead0135..4297900d7a95 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/actions.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/actions.yaml @@ -1,6 +1,7 @@ -type: array +type: + - "array" + - "null" default: [] -nullable: true items: type: object required: @@ -37,7 +38,8 @@ items: description: Defines the days of the week that the action can run, represented as an array of numbers. For example, `1` represents Monday. An empty array is equivalent to specifying all the days of the week. items: type: integer - example: [1,2,3,4,5] + examples: + - [1,2,3,4,5] hours: type: object description: > @@ -47,21 +49,25 @@ items: end: type: string description: The end of the time frame in 24-hour notation (`hh:mm`). - example: 17:00 + examples: + - 17:00 start: type: string description: The start of the time frame in 24-hour notation (`hh:mm`). - example: 08:00 + examples: + - 08:00 timezone: type: string description: > The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended. - example: Europe/Madrid + examples: + - Europe/Madrid connector_type_id: type: string description: The type of connector. This property appears in responses but cannot be set in requests. - example: .server-log + examples: + - .server-log readOnly: true frequency: type: object @@ -87,11 +93,13 @@ items: The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`. - example: default + examples: + - default id: type: string description: The identifier for the connector saved object. - example: 9dca3e00-74f5-11ed-9801-35303b735aef + examples: + - 9dca3e00-74f5-11ed-9801-35303b735aef params: type: object description: The parameters for the action, which are sent to the connector. The `params` are handled as Mustache templates and passed a default set of context. @@ -99,4 +107,5 @@ items: uuid: type: string description: A universally unique identifier (UUID) for the action. - example: 1c7a1280-f28c-4e06-96b2-e4e5f05d1d61 + examples: + - 1c7a1280-f28c-4e06-96b2-e4e5f05d1d61 diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/alert_response_properties.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/alert_response_properties.yaml index 06fa627311e7..744e4ead6c94 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/alert_response_properties.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/alert_response_properties.yaml @@ -7,53 +7,66 @@ properties: type: object alertTypeId: type: string - example: ".index-threshold" + examples: + - ".index-threshold" apiKeyOwner: - type: string - nullable: true - example: elastic + type: + - "string" + - "null" + examples: + - elastic createdAt: type: string description: The date and time that the alert was created. format: date-time - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' createdBy: type: string description: The identifier for the user that created the alert. - example: elastic + examples: + - elastic enabled: type: boolean description: Indicates whether the alert is currently enabled. - example: true + examples: + - true executionStatus: type: object properties: lastExecutionDate: type: string format: date-time - example: '2022-12-06T00:13:43.890Z' + examples: + - '2022-12-06T00:13:43.890Z' status: type: string - example: ok + examples: + - ok id: type: string description: The identifier for the alert. - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef muteAll: type: boolean - example: false + examples: + - false mutedInstanceIds: - type: array - nullable: true + type: + - "array" + - "null" items: type: string name: type: string description: The name of the alert. - example: my alert + examples: + - my alert notifyWhen: type: string - example: onActionGroupChange + examples: + - onActionGroupChange params: type: object additionalProperties: true @@ -64,19 +77,24 @@ properties: type: string scheduledTaskId: type: string - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef tags: type: array items: type: string throttle: - type: string - nullable: true + type: + - "string" + - "null" updatedAt: type: string - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' updatedBy: - type: string + type: + - "string" + - "null" description: The identifier for the user that updated this alert most recently. - nullable: true - example: elastic \ No newline at end of file + examples: + - elastic \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/filter.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/filter.yaml index cb6a77c21568..ba8507f87f05 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/filter.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/filter.yaml @@ -5,8 +5,9 @@ properties: type: object properties: alias: - type: string - nullable: true + type: + - "string" + - "null" controlledBy: type: string disabled: diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/notify_when.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/notify_when.yaml index 0dcd244fc33e..bb68967b6f5c 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/notify_when.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/notify_when.yaml @@ -8,4 +8,5 @@ enum: - onActionGroupChange - onActiveAlert - onThrottleInterval -example: onActiveAlert \ No newline at end of file +examples: + - onActiveAlert \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/params_es_query_rule.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/params_es_query_rule.yaml index 99b6a6f393a3..f51cbce979ab 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/params_es_query_rule.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/params_es_query_rule.yaml @@ -35,12 +35,14 @@ oneOf: type: string enum: - esqlQuery - example: esqlQuery + examples: + - esqlQuery size: type: integer description: > When `searchType` is `esqlQuery`, this property is required but it does not affect the rule behavior. - example: 0 + examples: + - 0 termSize: $ref: 'termsize.yaml' threshold: @@ -60,7 +62,8 @@ oneOf: Since the `threshold` value must be `0`, the result is that an alert occurs whenever the query returns results. enum: - ">" - example: ">" + examples: + - ">" timeField: $ref: 'timefield.yaml' timeWindowSize: @@ -105,7 +108,8 @@ oneOf: properties: language: type: string - example: kuery + examples: + - kuery query: type: string searchType: @@ -113,7 +117,8 @@ oneOf: type: string enum: - searchSource - example: searchSource + examples: + - searchSource size: $ref: 'size.yaml' termField: @@ -165,7 +170,8 @@ oneOf: enum: - esQuery default: esQuery - example: esQuery + examples: + - esQuery size: $ref: 'size.yaml' termField: diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/rule_response_properties.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/rule_response_properties.yaml index 13f62ba63e22..51310c87b6c5 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/rule_response_properties.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/rule_response_properties.yaml @@ -25,48 +25,60 @@ properties: api_key_created_by_user: type: boolean description: Indicates whether the API key that is associated with the rule was created by the user. - example: false + examples: + - false api_key_owner: - type: string + type: + - "string" + - "null" description: > The owner of the API key that is associated with the rule and used to run background tasks. - nullable: true - example: elastic + examples: + - elastic consumer: type: string description: The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. - example: alerts + examples: + - alerts created_at: type: string description: The date and time that the rule was created. format: date-time - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' created_by: - type: string + type: + - "string" + - "null" description: The identifier for the user that created the rule. - nullable: true - example: elastic + examples: + - elastic enabled: type: boolean description: Indicates whether the rule is currently enabled. - example: true + examples: + - true execution_status: type: object properties: last_duration: type: integer - example: 55 + examples: + - 55 last_execution_date: type: string format: date-time - example: '2022-12-06T00:13:43.890Z' + examples: + - '2022-12-06T00:13:43.890Z' status: type: string - example: ok + examples: + - ok id: type: string description: The identifier for the rule. - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef last_run: type: object properties: @@ -83,39 +95,49 @@ properties: type: integer outcome: type: string - example: succeeded + examples: + - succeeded outcome_msg: - type: array + type: + - "array" + - "null" items: type: string - nullable: true outcome_order: type: integer warning: - type: string - nullable: true - example: null + type: + - "string" + - "null" + examples: + - null muted_alert_ids: - type: array - nullable: true + type: + - "array" + - "null" items: type: string mute_all: type: boolean - example: false + examples: + - false name: type: string description: The name of the rule. - example: cluster_health_rule + examples: + - cluster_health_rule next_run: - type: string + type: + - "string" + - "null" format: date-time - nullable: true - example: '2022-12-06T00:14:43.818Z' + examples: + - '2022-12-06T00:14:43.818Z' notify_when: - type: string + type: + - "string" + - "null" description: Indicates how often alerts generate actions. - nullable: true params: type: object description: The parameters for the rule. @@ -127,7 +149,8 @@ properties: type: string description: > The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. - example: monitoring_alert_cluster_health + examples: + - monitoring_alert_cluster_health running: type: boolean description: Indicates whether the rule is running. @@ -135,7 +158,8 @@ properties: $ref: 'schedule.yaml' scheduled_task_id: type: string - example: b530fed0-74f5-11ed-9801-35303b735aef + examples: + - b530fed0-74f5-11ed-9801-35303b735aef tags: $ref: 'tags.yaml' throttle: @@ -143,9 +167,12 @@ properties: updated_at: type: string description: The date and time that the rule was updated most recently. - example: '2022-12-05T23:36:58.284Z' + examples: + - '2022-12-05T23:36:58.284Z' updated_by: - type: string + type: + - "string" + - "null" description: The identifier for the user that updated this rule most recently. - nullable: true - example: elastic \ No newline at end of file + examples: + - elastic \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/schedule.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/schedule.yaml index 57ddf84ceb41..75e98d9a8d19 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/schedule.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/schedule.yaml @@ -3,4 +3,5 @@ description: The check interval, which specifies how frequently the rule conditi properties: interval: type: string - example: 1m \ No newline at end of file + examples: + - 1m \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/threshold.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/threshold.yaml index 4d646f637522..7060ecf4e91a 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/threshold.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/threshold.yaml @@ -4,4 +4,5 @@ description: > type: array items: type: integer - example: 4000 \ No newline at end of file + examples: + - 4000 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/thresholdcomparator.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/thresholdcomparator.yaml index 3459365ee0a1..dd39d4c0bdc3 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/thresholdcomparator.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/thresholdcomparator.yaml @@ -7,4 +7,5 @@ enum: - "<=" - between - notBetween -example: ">" \ No newline at end of file +examples: + - ">" \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/throttle.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/throttle.yaml index 19d8e621cdaf..f45573dac8ab 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/throttle.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/throttle.yaml @@ -1,9 +1,11 @@ -type: string +type: + - "string" + - "null" description: > The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if `notify_when` is set to `onThrottleInterval`. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values. -nullable: true default: null -example: 10m \ No newline at end of file +examples: + - 10m \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowsize.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowsize.yaml index 7271f62f8dac..137ae56a9167 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowsize.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowsize.yaml @@ -2,4 +2,5 @@ description: > The size of the time window (in `timeWindowUnit` units), which determines how far back to search for documents. Generally it should be a value higher than the rule check interval to avoid gaps in detection. type: integer -example: 5 \ No newline at end of file +examples: + - 5 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowunit.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowunit.yaml index c0f2d458ae0e..bc2cbf1bd3e1 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowunit.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/timewindowunit.yaml @@ -6,4 +6,5 @@ enum: - m - h - d -example: "m" \ No newline at end of file +examples: + - "m" \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/update_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/update_rule_request.yaml index 58b6049aa107..63293f76ca71 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/update_rule_request.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/update_rule_request.yaml @@ -12,7 +12,8 @@ properties: name: type: string description: The name of the rule. - example: cluster_health_rule + examples: + - cluster_health_rule notify_when: $ref: 'notify_when.yaml' params: diff --git a/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml b/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml index 5b3d70e78069..39c46ca8513f 100644 --- a/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Alerting description: OpenAPI schema for alerting endpoints - version: '0.1' + version: '0.2' contact: name: Alerting Team license: @@ -68,7 +68,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - apiKeyAuth: [] diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@_health.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@_health.yaml index 5b856e24ca99..25ae1cb0b9fc 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@_health.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@_health.yaml @@ -28,7 +28,8 @@ get: properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -36,14 +37,16 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" execution_health: type: object description: The timestamp and status of the rule run. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -51,14 +54,16 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" read_health: type: object description: The timestamp and status of the rule reading events. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -66,15 +71,18 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" has_permanent_encryption_key: type: boolean description: If `false`, the encrypted saved object plugin does not have a permanent encryption key. - example: true + examples: + - true is_sufficiently_secure: type: boolean description: If `false`, security is enabled but TLS is not. - example: true + examples: + - true examples: getAlertingHealthResponse: $ref: '../components/examples/get_health_response.yaml' diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml index a4d624110014..96c5973c570c 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml @@ -90,7 +90,8 @@ post: required: true schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + examples: + - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule_types.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule_types.yaml index 1dba3e085e2b..41ec2aeadbe3 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule_types.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule_types.yaml @@ -186,14 +186,16 @@ get: minimum_license_required: description: The subscriptions required to use the rule type. type: string - example: basic + examples: + - basic name: description: The descriptive name of the rule type. type: string producer: description: An identifier for the application that produces this rule type. type: string - example: stackAlerts + examples: + - stackAlerts recovery_action_group: description: An action group to use when an alert goes from an active state to an inactive one. type: object @@ -204,7 +206,8 @@ get: type: string rule_task_timeout: type: string - example: 5m + examples: + - 5m examples: getRuleTypesResponse: $ref: '../components/examples/get_rule_types_response.yaml' diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rules@_find.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rules@_find.yaml index f512a0660f18..7f5417eec10c 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rules@_find.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rules@_find.yaml @@ -19,7 +19,8 @@ get: schema: type: string default: OR - example: OR + examples: + - AND - name: fields in: query description: The fields to return in the `attributes` key of the response. @@ -53,25 +54,31 @@ get: schema: type: integer default: 1 - example: 1 + examples: + - 1 - name: per_page in: query description: The number of rules to return per page. schema: type: integer default: 20 - example: 20 + examples: + - 20 - name: search in: query description: An Elasticsearch simple_query_string query that filters the objects in the response. schema: type: string + examples: + - threshold +-test* - name: search_fields in: query description: The fields to perform the simple_query_string parsed query against. schema: oneOf: - type: string + examples: + - name - type: array items: type: string @@ -91,7 +98,8 @@ get: - asc - desc default: desc - example: asc + examples: + - asc responses: '200': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_find.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_find.yaml index 32dcbbf218a3..2cc8acdf5c5a 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_find.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_find.yaml @@ -17,7 +17,8 @@ get: schema: type: string default: OR - example: OR + examples: + - OR - name: fields in: query description: The fields to return in the `attributes` key of the response. @@ -51,14 +52,16 @@ get: schema: type: integer default: 1 - example: 1 + examples: + - 1 - name: per_page in: query description: The number of alerts to return per page. schema: type: integer default: 20 - example: 20 + examples: + - 20 - name: search in: query description: An Elasticsearch `simple_query_string` query that filters the alerts in the response. @@ -89,7 +92,8 @@ get: - asc - desc default: desc - example: asc + examples: + - asc responses: '200': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_health.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_health.yaml index eba22ac1b409..593977bd384d 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_health.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@_health.yaml @@ -26,7 +26,8 @@ get: properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -34,14 +35,16 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" executionHealth: type: object description: The timestamp and status of the alert execution. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -49,14 +52,16 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" readHealth: type: object description: The timestamp and status of the alert reading events. properties: status: type: string - example: ok + examples: + - ok enum: - error - ok @@ -64,15 +69,18 @@ get: timestamp: type: string format: date-time - example: "2023-01-13T01:28:00.280Z" + examples: + - "2023-01-13T01:28:00.280Z" hasPermanentEncryptionKey: type: boolean description: If `false`, the encrypted saved object plugin does not have a permanent encryption key. - example: true + examples: + - true isSufficientlySecure: type: boolean description: If `false`, security is enabled but TLS is not. - example: true + examples: + - true '401': description: Authorization information is missing or invalid. content: diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}.yaml index 4af612fc150c..48a1b12984b4 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}.yaml @@ -16,7 +16,8 @@ delete: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. @@ -42,7 +43,8 @@ get: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '200': description: Indicates a successful call. @@ -72,7 +74,8 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - $ref: '../components/parameters/space_id.yaml' requestBody: required: true @@ -146,7 +149,8 @@ post: interval: type: string description: The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute. - example: "10s" + examples: + - "10s" tags: type: array items: @@ -189,7 +193,8 @@ put: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 requestBody: required: true content: @@ -251,7 +256,8 @@ put: interval: type: string description: The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute. - example: "1d" + examples: + - "1d" tags: type: array items: diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_disable.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_disable.yaml index 62fc4de90cae..a383c71ed0ea 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_disable.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_disable.yaml @@ -14,7 +14,8 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_enable.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_enable.yaml index 85ede004c189..19b782ea3ccc 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_enable.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_enable.yaml @@ -14,7 +14,8 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_mute_all.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_mute_all.yaml index 6507cf6da6a1..64c28317025a 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_mute_all.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_mute_all.yaml @@ -14,7 +14,8 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_unmute_all.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_unmute_all.yaml index 17c48dae2677..63fa1d2aa50f 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_unmute_all.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@_unmute_all.yaml @@ -14,7 +14,8 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_mute.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_mute.yaml index 439445aa29a8..0f2620aff6a1 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_mute.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_mute.yaml @@ -14,14 +14,16 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - in: path name: alertInstanceId description: An identifier for the alert instance. required: true schema: type: string - example: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + examples: + - dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_unmute.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_unmute.yaml index 3a7fe8dc1d31..7b1b6abeab39 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_unmute.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerts@alert@{alertid}@alert_instance@{alertinstanceid}@_unmute.yaml @@ -14,14 +14,16 @@ post: required: true schema: type: string - example: 41893910-6bca-11eb-9e0d-85d233e3ee35 + examples: + - 41893910-6bca-11eb-9e0d-85d233e3ee35 - in: path name: alertInstanceId description: An identifier for the alert instance. required: true schema: type: string - example: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + examples: + - dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 responses: '204': description: Indicates a successful call. diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 9526f87e260d..86fe855152a9 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -1133,6 +1133,22 @@ describe('Alerts Client', () => { }, }, }, + { + index: { + _index: '.internal.alerts-test.alerts-default-000001', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'. Preview of field's value: 'we don't want this field value to be echoed'", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, { index: { _index: '.internal.alerts-test.alerts-default-000002', @@ -1164,7 +1180,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalled(); expect(logger.error).toHaveBeenCalledWith( - `Error writing alerts: 1 successful, 0 conflicts, 1 errors: Validation Failed: 1: index is missing;2: type is missing;` + `Error writing alerts: 1 successful, 0 conflicts, 2 errors: Validation Failed: 1: index is missing;2: type is missing;; failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'.` ); }); diff --git a/x-pack/plugins/alerting/server/alerts_client/index.ts b/x-pack/plugins/alerting/server/alerts_client/index.ts index 442f8935650f..a1c0a309e0dc 100644 --- a/x-pack/plugins/alerting/server/alerts_client/index.ts +++ b/x-pack/plugins/alerting/server/alerts_client/index.ts @@ -8,3 +8,4 @@ export { type LegacyAlertsClientParams, LegacyAlertsClient } from './legacy_alerts_client'; export { AlertsClient } from './alerts_client'; export type { AlertRuleData } from './types'; +export { sanitizeBulkErrorResponse } from './lib'; diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/alert_conflict_resolver.ts b/x-pack/plugins/alerting/server/alerts_client/lib/alert_conflict_resolver.ts index 3c5ce6e25a1a..383d8dbb103f 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/alert_conflict_resolver.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/alert_conflict_resolver.ts @@ -23,6 +23,7 @@ import { } from '@kbn/rule-data-utils'; import { zip, get } from 'lodash'; +import { sanitizeBulkErrorResponse } from '../..'; // these fields are the one's we'll refresh from the fresh mget'd docs const REFRESH_FIELDS_ALWAYS = [ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, ALERT_CASE_IDS]; @@ -269,8 +270,9 @@ interface ResponseStatsResult { // generate a summary of the original bulk request attempt, for logging function getResponseStats(bulkResponse: BulkResponse): ResponseStatsResult { + const sanitizedResponse = sanitizeBulkErrorResponse(bulkResponse) as BulkResponse; const stats: ResponseStatsResult = { success: 0, conflicts: 0, errors: 0, messages: [] }; - for (const item of bulkResponse.items) { + for (const item of sanitizedResponse.items) { const op = item.create || item.index || item.update || item.delete; if (op?.error) { if (op?.status === 409 && op === item.index) { diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/index.ts b/x-pack/plugins/alerting/server/alerts_client/lib/index.ts index 7225e87056e4..6e40e918a8b2 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/index.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/index.ts @@ -16,3 +16,4 @@ export { getContinualAlertsQuery, } from './get_summarized_alerts_query'; export { expandFlattenedAlert } from './format_alert'; +export { sanitizeBulkErrorResponse } from './sanitize_bulk_response'; diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.test.ts b/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.test.ts new file mode 100644 index 000000000000..533bb5b554ae --- /dev/null +++ b/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.test.ts @@ -0,0 +1,244 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { TransportResult } from '@elastic/elasticsearch'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { sanitizeBulkErrorResponse } from './sanitize_bulk_response'; + +// Using https://www.elastic.co/guide/en/elasticsearch/reference/8.11/docs-bulk.html +describe('sanitizeBulkErrorResponse', () => { + test('should not modify success response', () => { + const responseBody = { + errors: false, + took: 1, + items: [ + { + index: { + _index: 'test', + _id: '1', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 0, + _primary_term: 1, + }, + }, + { + delete: { + _index: 'test', + _id: '2', + _version: 1, + result: 'not_found', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 404, + _seq_no: 1, + _primary_term: 2, + }, + }, + { + create: { + _index: 'test', + _id: '3', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + { + update: { + _index: 'test', + _id: '1', + _version: 2, + result: 'updated', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 200, + _seq_no: 3, + _primary_term: 4, + }, + }, + ], + }; + const transportResponseBody = wrapResponseBody(responseBody); + + expect(sanitizeBulkErrorResponse(responseBody)).toEqual(responseBody); + expect(sanitizeBulkErrorResponse(transportResponseBody)).toEqual(transportResponseBody); + }); + + test('should not modify error response without field preview', () => { + const responseBody = { + took: 486, + errors: true, + items: [ + { + update: { + _index: 'index1', + _id: '5', + status: 404, + error: { + type: 'document_missing_exception', + reason: '[5]: document missing', + index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', + shard: '0', + index: 'index1', + }, + }, + }, + { + delete: { + _index: 'index1', + _id: '6', + status: 404, + error: { + type: 'document_missing_exception', + reason: '[6]: document missing', + index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', + shard: '0', + index: 'index1', + }, + }, + }, + { + create: { + _index: 'test', + _id: '3', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + ], + }; + const transportResponseBody = wrapResponseBody(responseBody); + + expect(sanitizeBulkErrorResponse(responseBody)).toEqual(responseBody); + expect(sanitizeBulkErrorResponse(transportResponseBody)).toEqual(transportResponseBody); + }); + + test('should sanitize error response with field preview', () => { + const responseBody = { + took: 486, + errors: true, + items: [ + { + update: { + _index: 'index1', + _id: '5', + status: 404, + error: { + type: 'document_missing_exception', + reason: '[5]: document missing', + index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', + shard: '0', + index: 'index1', + }, + }, + }, + { + update: { + _index: 'index1', + _id: '6', + status: 404, + error: { + type: 'document_missing_exception', + reason: '[6]: document missing', + index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', + shard: '0', + index: 'index1', + }, + }, + }, + { + create: { + _index: 'index1', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'. Preview of field's value: 'we don't want this field value to be echoed'", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, + ], + }; + const transportResponseBody = wrapResponseBody(responseBody); + + expect(sanitizeBulkErrorResponse(responseBody)).toEqual({ + ...responseBody, + items: [ + responseBody.items[0], + responseBody.items[1], + { + create: { + _index: 'index1', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'.", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, + ], + }); + expect(sanitizeBulkErrorResponse(transportResponseBody)).toEqual({ + ...transportResponseBody, + body: { + ...transportResponseBody.body, + items: [ + transportResponseBody.body.items[0], + transportResponseBody.body.items[1], + { + create: { + _index: 'index1', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'.", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, + ], + }, + }); + }); +}); + +function wrapResponseBody( + body: estypes.BulkResponse, + statusCode: number = 200 +): TransportResult { + return { + body, + statusCode, + headers: {}, + warnings: null, + // @ts-expect-error + meta: {}, + }; +} diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.ts b/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.ts new file mode 100644 index 000000000000..2b6d9f6e3c2c --- /dev/null +++ b/x-pack/plugins/alerting/server/alerts_client/lib/sanitize_bulk_response.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { cloneDeep } from 'lodash'; +import { TransportResult } from '@elastic/elasticsearch'; +import { get } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export const sanitizeBulkErrorResponse = ( + response: TransportResult | estypes.BulkResponse +): TransportResult | estypes.BulkResponse => { + const clonedResponse = cloneDeep(response); + const isTransportResponse = !!(response as TransportResult).body; + + const responseToUse: estypes.BulkResponse = isTransportResponse + ? (clonedResponse as TransportResult).body + : (clonedResponse as estypes.BulkResponse); + + if (responseToUse.errors) { + (responseToUse.items ?? []).forEach( + (item: Partial>) => { + for (const [_, responseItem] of Object.entries(item)) { + const reason: string = get(responseItem, 'error.reason'); + const redactIndex = reason ? reason.indexOf(`Preview of field's value:`) : -1; + if (redactIndex > 1) { + set(responseItem, 'error.reason', reason.substring(0, redactIndex - 1)); + } + } + } + ); + } + + return clonedResponse; +}; diff --git a/x-pack/plugins/alerting/server/application/alerts_filter_query/constants.ts b/x-pack/plugins/alerting/server/application/alerts_filter_query/constants.ts new file mode 100644 index 000000000000..bce6890c22f2 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/alerts_filter_query/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filterStateStore = { + APP_STATE: 'appState', + GLOBAL_STATE: 'globalState', +} as const; + +export type FilterStateStore = typeof filterStateStore[keyof typeof filterStateStore]; diff --git a/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/alerts_filter_query_schemas.ts b/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/alerts_filter_query_schemas.ts new file mode 100644 index 000000000000..bf5a24b6e439 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/alerts_filter_query_schemas.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { filterStateStore } from '../constants'; + +export const alertsFilterQuerySchema = schema.object({ + kql: schema.string(), + filters: schema.arrayOf( + schema.object({ + query: schema.maybe(schema.recordOf(schema.string(), schema.any())), + meta: schema.recordOf(schema.string(), schema.any()), + $state: schema.maybe( + schema.object({ + store: schema.oneOf([ + schema.literal(filterStateStore.APP_STATE), + schema.literal(filterStateStore.GLOBAL_STATE), + ]), + }) + ), + }) + ), + dsl: schema.maybe(schema.string()), +}); diff --git a/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/index.ts b/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/index.ts new file mode 100644 index 000000000000..5042e3e8265a --- /dev/null +++ b/x-pack/plugins/alerting/server/application/alerts_filter_query/schemas/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { alertsFilterQuerySchema } from './alerts_filter_query_schemas'; diff --git a/x-pack/plugins/alerting/server/application/alerts_filter_query/types/alerts_filter_query.ts b/x-pack/plugins/alerting/server/application/alerts_filter_query/types/alerts_filter_query.ts new file mode 100644 index 000000000000..926d27e89fa9 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/alerts_filter_query/types/alerts_filter_query.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { alertsFilterQuerySchema } from '../schemas/alerts_filter_query_schemas'; + +export type AlertsFilterQuery = TypeOf; diff --git a/x-pack/plugins/alerting/server/application/alerts_filter_query/types/index.ts b/x-pack/plugins/alerting/server/application/alerts_filter_query/types/index.ts new file mode 100644 index 000000000000..2553fd000590 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/alerts_filter_query/types/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { AlertsFilterQuery } from './alerts_filter_query'; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/constants.ts b/x-pack/plugins/alerting/server/application/maintenance_window/constants.ts index caa1616d10a7..4b5920d64558 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/constants.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/constants.ts @@ -13,8 +13,12 @@ export const maintenanceWindowStatus = { } as const; export const maintenanceWindowCategoryIdTypes = { - KIBANA: 'kibana', OBSERVABILITY: 'observability', SECURITY_SOLUTION: 'securitySolution', MANAGEMENT: 'management', } as const; + +export const filterStateStore = { + APP_STATE: 'appState', + GLOBAL_STATE: 'globalState', +} as const; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/lib/generate_maintenance_window_events.ts b/x-pack/plugins/alerting/server/application/maintenance_window/lib/generate_maintenance_window_events.ts index 99f8e99f3f5e..78227dab5864 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/lib/generate_maintenance_window_events.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/lib/generate_maintenance_window_events.ts @@ -8,7 +8,8 @@ import _ from 'lodash'; import moment from 'moment-timezone'; import { RRule, Weekday } from '@kbn/rrule'; -import { RRuleParams, MaintenanceWindowSOAttributes, DateRange } from '../../../../common'; +import { RRuleParams, DateRange } from '../../../../common'; +import { MaintenanceWindow } from '../types'; export interface GenerateMaintenanceWindowEventsParams { rRule: RRuleParams; @@ -58,7 +59,7 @@ export const shouldRegenerateEvents = ({ rRule, duration, }: { - maintenanceWindow: MaintenanceWindowSOAttributes; + maintenanceWindow: MaintenanceWindow; rRule?: RRuleParams; duration?: number; }): boolean => { diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.test.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.test.ts index 1de657bdfd6e..af04b62bfc7d 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.test.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.test.ts @@ -133,6 +133,124 @@ describe('MaintenanceWindowClient - create', () => { ); }); + it('should create maintenance window with scoped query', async () => { + jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z')); + + const mockMaintenanceWindow = getMockMaintenanceWindow({ + expirationDate: moment(new Date()).tz('UTC').add(1, 'year').toISOString(), + }); + + savedObjectsClient.create.mockResolvedValueOnce({ + attributes: mockMaintenanceWindow, + version: '123', + id: 'test-id', + } as unknown as SavedObject); + + await createMaintenanceWindow(mockContext, { + data: { + title: mockMaintenanceWindow.title, + duration: mockMaintenanceWindow.duration, + rRule: mockMaintenanceWindow.rRule as CreateMaintenanceWindowParams['data']['rRule'], + categoryIds: ['observability', 'securitySolution'], + scopedQuery: { + kql: "_id: '1234'", + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'kibana.alert.action_group', + field: 'kibana.alert.action_group', + params: { + query: 'test', + }, + type: 'phrase', + }, + $state: { + store: 'appState', + }, + query: { + match_phrase: { + 'kibana.alert.action_group': 'test', + }, + }, + }, + ], + }, + }, + }); + + expect(savedObjectsClient.create).toHaveBeenLastCalledWith( + MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, + expect.objectContaining({ + title: mockMaintenanceWindow.title, + duration: mockMaintenanceWindow.duration, + rRule: mockMaintenanceWindow.rRule, + enabled: true, + expirationDate: moment(new Date()).tz('UTC').add(1, 'year').toISOString(), + categoryIds: ['observability', 'securitySolution'], + ...updatedMetadata, + }), + { + id: expect.any(String), + } + ); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.kql + ).toEqual(`_id: '1234'`); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.filters[0] + ).toEqual({ + $state: { store: 'appState' }, + meta: { + alias: null, + disabled: false, + field: 'kibana.alert.action_group', + key: 'kibana.alert.action_group', + negate: false, + params: { query: 'test' }, + type: 'phrase', + }, + query: { match_phrase: { 'kibana.alert.action_group': 'test' } }, + }); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.dsl + ).toMatchInlineSnapshot( + `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"_id\\":\\"'1234'\\"}}],\\"minimum_should_match\\":1}},{\\"match_phrase\\":{\\"kibana.alert.action_group\\":\\"test\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` + ); + }); + + it('should throw if trying to create a maintenance window with invalid scoped query', async () => { + jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z')); + + const mockMaintenanceWindow = getMockMaintenanceWindow({ + expirationDate: moment(new Date()).tz('UTC').add(1, 'year').toISOString(), + }); + + await expect(async () => { + await createMaintenanceWindow(mockContext, { + data: { + title: mockMaintenanceWindow.title, + duration: mockMaintenanceWindow.duration, + rRule: mockMaintenanceWindow.rRule as CreateMaintenanceWindowParams['data']['rRule'], + categoryIds: ['observability', 'securitySolution'], + scopedQuery: { + kql: 'invalid: ', + filters: [], + }, + }, + }); + }).rejects.toThrowErrorMatchingInlineSnapshot(` + "Error validating create maintenance scoped query - Expected \\"(\\", \\"{\\", value, whitespace but end of input found. + invalid: + ---------^" + `); + }); + it('should throw if trying to create a maintenance window with invalid category ids', async () => { jest.useFakeTimers().setSystemTime(new Date('2023-02-26T00:00:00.000Z')); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.ts index b8fba87b2fc1..78f5e885874b 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/create_maintenance_window.ts @@ -8,6 +8,7 @@ import moment from 'moment'; import Boom from '@hapi/boom'; import { SavedObjectsUtils } from '@kbn/core/server'; +import { buildEsQuery, Filter } from '@kbn/es-query'; import { generateMaintenanceWindowEvents } from '../../lib/generate_maintenance_window_events'; import type { MaintenanceWindowClientContext } from '../../../../../common'; import type { MaintenanceWindow } from '../../types'; @@ -25,7 +26,7 @@ export async function createMaintenanceWindow( ): Promise { const { data } = params; const { savedObjectsClient, getModificationMetadata, logger } = context; - const { title, duration, rRule, categoryIds } = data; + const { title, duration, rRule, categoryIds, scopedQuery } = data; try { createMaintenanceWindowParamsSchema.validate(params); @@ -33,6 +34,25 @@ export async function createMaintenanceWindow( throw Boom.badRequest(`Error validating create maintenance window data - ${error.message}`); } + let scopedQueryWithGeneratedValue = scopedQuery; + try { + if (scopedQuery) { + const dsl = JSON.stringify( + buildEsQuery( + undefined, + [{ query: scopedQuery.kql, language: 'kuery' }], + scopedQuery.filters as Filter[] + ) + ); + scopedQueryWithGeneratedValue = { + ...scopedQuery, + dsl, + }; + } + } catch (error) { + throw Boom.badRequest(`Error validating create maintenance scoped query - ${error.message}`); + } + const id = SavedObjectsUtils.generateId(); const expirationDate = moment().utc().add(1, 'year').toISOString(); const modificationMetadata = await getModificationMetadata(); @@ -43,6 +63,7 @@ export async function createMaintenanceWindow( enabled: true, expirationDate, categoryIds, + scopedQuery: scopedQueryWithGeneratedValue, rRule: rRule as MaintenanceWindow['rRule'], duration, events, diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/schemas/create_maintenance_window_params_schema.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/schemas/create_maintenance_window_params_schema.ts index dcb9150f2385..b55a4871d0b6 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/schemas/create_maintenance_window_params_schema.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/create/schemas/create_maintenance_window_params_schema.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowCategoryIdsSchema } from '../../../schemas'; import { rRuleRequestSchema } from '../../../../r_rule/schemas'; +import { alertsFilterQuerySchema } from '../../../../alerts_filter_query/schemas'; export const createMaintenanceWindowParamsSchema = schema.object({ data: schema.object({ @@ -15,5 +16,6 @@ export const createMaintenanceWindowParamsSchema = schema.object({ duration: schema.number(), rRule: rRuleRequestSchema, categoryIds: maintenanceWindowCategoryIdsSchema, + scopedQuery: schema.maybe(schema.nullable(alertsFilterQuerySchema)), }), }); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/schemas/update_maintenance_window_params_schema.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/schemas/update_maintenance_window_params_schema.ts index 84120a5ee8c4..1aca8ab24fcd 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/schemas/update_maintenance_window_params_schema.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/schemas/update_maintenance_window_params_schema.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowCategoryIdsSchema } from '../../../schemas'; import { rRuleRequestSchema } from '../../../../r_rule/schemas'; +import { alertsFilterQuerySchema } from '../../../../alerts_filter_query/schemas'; export const updateMaintenanceWindowParamsSchema = schema.object({ id: schema.string(), @@ -17,5 +18,6 @@ export const updateMaintenanceWindowParamsSchema = schema.object({ duration: schema.maybe(schema.number()), rRule: schema.maybe(rRuleRequestSchema), categoryIds: maintenanceWindowCategoryIdsSchema, + scopedQuery: schema.maybe(schema.nullable(alertsFilterQuerySchema)), }), }); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts index 966808fed57f..4caef4eca1ba 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.test.ts @@ -207,6 +207,172 @@ describe('MaintenanceWindowClient - update', () => { ); }); + it('should update maintenance window with scoped query', async () => { + jest.useFakeTimers().setSystemTime(new Date(firstTimestamp)); + + const modifiedEvents = [ + { gte: '2023-03-26T00:00:00.000Z', lte: '2023-03-26T00:12:34.000Z' }, + { gte: '2023-04-01T23:00:00.000Z', lte: '2023-04-01T23:43:21.000Z' }, + ]; + const mockMaintenanceWindow = getMockMaintenanceWindow({ + rRule: { + tzid: 'CET', + dtstart: '2023-03-26T00:00:00.000Z', + freq: Frequency.WEEKLY, + count: 5, + } as MaintenanceWindow['rRule'], + events: modifiedEvents, + expirationDate: moment(new Date(firstTimestamp)).tz('UTC').add(2, 'week').toISOString(), + }); + + savedObjectsClient.get.mockResolvedValue({ + attributes: mockMaintenanceWindow, + version: '123', + id: 'test-id', + } as unknown as SavedObject); + + savedObjectsClient.create.mockResolvedValue({ + attributes: { + ...mockMaintenanceWindow, + ...updatedAttributes, + ...updatedMetadata, + }, + id: 'test-id', + } as unknown as SavedObject); + + await updateMaintenanceWindow(mockContext, { + id: 'test-id', + data: { + scopedQuery: { + kql: "_id: '1234'", + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'kibana.alert.action_group', + field: 'kibana.alert.action_group', + params: { + query: 'test', + }, + type: 'phrase', + }, + $state: { + store: 'appState', + }, + query: { + match_phrase: { + 'kibana.alert.action_group': 'test', + }, + }, + }, + ], + }, + }, + }); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.kql + ).toEqual(`_id: '1234'`); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.filters[0] + ).toEqual({ + $state: { store: 'appState' }, + meta: { + alias: null, + disabled: false, + field: 'kibana.alert.action_group', + key: 'kibana.alert.action_group', + negate: false, + params: { query: 'test' }, + type: 'phrase', + }, + query: { match_phrase: { 'kibana.alert.action_group': 'test' } }, + }); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery!.dsl + ).toMatchInlineSnapshot( + `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"_id\\":\\"'1234'\\"}}],\\"minimum_should_match\\":1}},{\\"match_phrase\\":{\\"kibana.alert.action_group\\":\\"test\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` + ); + }); + + it('should remove maintenance window with scoped query', async () => { + jest.useFakeTimers().setSystemTime(new Date(firstTimestamp)); + + const modifiedEvents = [ + { gte: '2023-03-26T00:00:00.000Z', lte: '2023-03-26T00:12:34.000Z' }, + { gte: '2023-04-01T23:00:00.000Z', lte: '2023-04-01T23:43:21.000Z' }, + ]; + const mockMaintenanceWindow = getMockMaintenanceWindow({ + rRule: { + tzid: 'CET', + dtstart: '2023-03-26T00:00:00.000Z', + freq: Frequency.WEEKLY, + count: 5, + } as MaintenanceWindow['rRule'], + events: modifiedEvents, + expirationDate: moment(new Date(firstTimestamp)).tz('UTC').add(2, 'week').toISOString(), + }); + + savedObjectsClient.get.mockResolvedValue({ + attributes: mockMaintenanceWindow, + version: '123', + id: 'test-id', + } as unknown as SavedObject); + + savedObjectsClient.create.mockResolvedValue({ + attributes: { + ...mockMaintenanceWindow, + ...updatedAttributes, + ...updatedMetadata, + }, + id: 'test-id', + } as unknown as SavedObject); + + await updateMaintenanceWindow(mockContext, { + id: 'test-id', + data: { + scopedQuery: null, + }, + }); + + expect( + (savedObjectsClient.create.mock.calls[0][1] as MaintenanceWindow).scopedQuery + ).toBeNull(); + }); + + it('should throw if updating a maintenance window with invalid scoped query', async () => { + jest.useFakeTimers().setSystemTime(new Date(firstTimestamp)); + const mockMaintenanceWindow = getMockMaintenanceWindow({ + expirationDate: moment(new Date(firstTimestamp)).tz('UTC').subtract(1, 'year').toISOString(), + }); + + savedObjectsClient.get.mockResolvedValueOnce({ + attributes: mockMaintenanceWindow, + version: '123', + id: 'test-id', + } as unknown as SavedObject); + + await expect(async () => { + await updateMaintenanceWindow(mockContext, { + id: 'test-id', + data: { + scopedQuery: { + kql: 'invalid: ', + filters: [], + }, + }, + }); + }).rejects.toThrowErrorMatchingInlineSnapshot(` + "Error validating update maintenance scoped query - Expected \\"(\\", \\"{\\", value, whitespace but end of input found. + invalid: + ---------^" + `); + }); + it('should throw if updating a maintenance window that has expired', async () => { jest.useFakeTimers().setSystemTime(new Date(firstTimestamp)); const mockMaintenanceWindow = getMockMaintenanceWindow({ diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts index f10381defc9b..6b7ab69cc807 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/methods/update/update_maintenance_window.ts @@ -7,6 +7,7 @@ import moment from 'moment'; import Boom from '@hapi/boom'; +import { buildEsQuery, Filter } from '@kbn/es-query'; import type { MaintenanceWindowClientContext } from '../../../../../common'; import type { MaintenanceWindow } from '../../types'; import { @@ -45,7 +46,7 @@ async function updateWithOCC( ): Promise { const { savedObjectsClient, getModificationMetadata, logger } = context; const { id, data } = params; - const { title, enabled, duration, rRule, categoryIds } = data; + const { title, enabled, duration, rRule, categoryIds, scopedQuery } = data; try { updateMaintenanceWindowParamsSchema.validate(params); @@ -53,6 +54,25 @@ async function updateWithOCC( throw Boom.badRequest(`Error validating update maintenance window data - ${error.message}`); } + let scopedQueryWithGeneratedValue = scopedQuery; + try { + if (scopedQuery) { + const dsl = JSON.stringify( + buildEsQuery( + undefined, + [{ query: scopedQuery.kql, language: 'kuery' }], + scopedQuery.filters as Filter[] + ) + ); + scopedQueryWithGeneratedValue = { + ...scopedQuery, + dsl, + }; + } + } catch (error) { + throw Boom.badRequest(`Error validating update maintenance scoped query - ${error.message}`); + } + try { const { attributes, @@ -88,6 +108,9 @@ async function updateWithOCC( ...(title ? { title } : {}), ...(rRule ? { rRule: rRule as MaintenanceWindow['rRule'] } : {}), ...(categoryIds !== undefined ? { categoryIds } : {}), + ...(scopedQueryWithGeneratedValue !== undefined + ? { scopedQuery: scopedQueryWithGeneratedValue } + : {}), ...(typeof duration === 'number' ? { duration } : {}), ...(typeof enabled === 'boolean' ? { enabled } : {}), expirationDate, diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/schemas/maintenance_window_schemas.ts b/x-pack/plugins/alerting/server/application/maintenance_window/schemas/maintenance_window_schemas.ts index 080f5b1bbe67..cf9b69454aa9 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/schemas/maintenance_window_schemas.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/schemas/maintenance_window_schemas.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import { maintenanceWindowStatus, maintenanceWindowCategoryIdTypes } from '../constants'; import { rRuleSchema } from '../../r_rule/schemas'; +import { alertsFilterQuerySchema } from '../../alerts_filter_query/schemas'; export const maintenanceWindowEventSchema = schema.object({ gte: schema.string(), @@ -47,4 +48,5 @@ export const maintenanceWindowSchema = schema.object({ schema.literal(maintenanceWindowStatus.ARCHIVED), ]), categoryIds: maintenanceWindowCategoryIdsSchema, + scopedQuery: schema.maybe(schema.nullable(alertsFilterQuerySchema)), }); diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_attributes_to_maintenance_window.ts b/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_attributes_to_maintenance_window.ts index 53996f29694f..6a2f25ce18dd 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_attributes_to_maintenance_window.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_attributes_to_maintenance_window.ts @@ -40,5 +40,6 @@ export const transformMaintenanceWindowAttributesToMaintenanceWindow = ( eventEndTime, status, ...(attributes.categoryIds !== undefined ? { categoryIds: attributes.categoryIds } : {}), + ...(attributes.scopedQuery !== undefined ? { scopedQuery: attributes.scopedQuery } : {}), }; }; diff --git a/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_to_maintenance_window_attributes.ts b/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_to_maintenance_window_attributes.ts index 35865f38aa9b..9d26443bdc07 100644 --- a/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_to_maintenance_window_attributes.ts +++ b/x-pack/plugins/alerting/server/application/maintenance_window/transforms/transform_maintenance_window_to_maintenance_window_attributes.ts @@ -25,5 +25,8 @@ export const transformMaintenanceWindowToMaintenanceWindowAttributes = ( ...(maintenanceWindow.categoryIds !== undefined ? { categoryIds: maintenanceWindow.categoryIds } : {}), + ...(maintenanceWindow.scopedQuery !== undefined + ? { scopedQuery: maintenanceWindow.scopedQuery } + : {}), }; }; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index 294945ad8203..996f67448c7f 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -489,7 +489,7 @@ async function updateRuleAttributesAndParamsInMemory( context, operations, rule: ruleDomain, - ruleActions, + ruleActions: ruleActions as RuleDomain['actions'], // TODO (http-versioning) Remove this cast once we fix injectReferencesIntoActions ruleType, }); diff --git a/x-pack/plugins/alerting/server/application/rule/schemas/action_schemas.ts b/x-pack/plugins/alerting/server/application/rule/schemas/action_schemas.ts index 579f41adb042..7cbadb619908 100644 --- a/x-pack/plugins/alerting/server/application/rule/schemas/action_schemas.ts +++ b/x-pack/plugins/alerting/server/application/rule/schemas/action_schemas.ts @@ -7,31 +7,10 @@ import { schema } from '@kbn/config-schema'; import { notifyWhenSchema } from './notify_when_schema'; -import { filterStateStore } from '../constants'; +import { alertsFilterQuerySchema } from '../../alerts_filter_query/schemas'; export const actionParamsSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); -const actionAlertsFilterQueryFiltersSchema = schema.arrayOf( - schema.object({ - query: schema.maybe(schema.recordOf(schema.string(), schema.any())), - meta: schema.recordOf(schema.string(), schema.any()), - $state: schema.maybe( - schema.object({ - store: schema.oneOf([ - schema.literal(filterStateStore.APP_STATE), - schema.literal(filterStateStore.GLOBAL_STATE), - ]), - }) - ), - }) -); - -const actionDomainAlertsFilterQuerySchema = schema.object({ - kql: schema.string(), - filters: actionAlertsFilterQueryFiltersSchema, - dsl: schema.maybe(schema.string()), -}); - const actionAlertsFilterTimeFrameSchema = schema.object({ days: schema.arrayOf( schema.oneOf([ @@ -52,7 +31,7 @@ const actionAlertsFilterTimeFrameSchema = schema.object({ }); const actionDomainAlertsFilterSchema = schema.object({ - query: schema.maybe(actionDomainAlertsFilterQuerySchema), + query: schema.maybe(alertsFilterQuerySchema), timeframe: schema.maybe(actionAlertsFilterTimeFrameSchema), }); @@ -76,17 +55,8 @@ export const actionDomainSchema = schema.object({ useAlertDataAsTemplate: schema.maybe(schema.boolean()), }); -/** - * Sanitized (non-domain) action schema, returned by rules clients for other solutions - */ -const actionAlertsFilterQuerySchema = schema.object({ - kql: schema.string(), - filters: actionAlertsFilterQueryFiltersSchema, - dsl: schema.maybe(schema.string()), -}); - export const actionAlertsFilterSchema = schema.object({ - query: schema.maybe(actionAlertsFilterQuerySchema), + query: schema.maybe(alertsFilterQuerySchema), timeframe: schema.maybe(actionAlertsFilterTimeFrameSchema), }); diff --git a/x-pack/plugins/alerting/server/constants/plugin.ts b/x-pack/plugins/alerting/server/constants/plugin.ts deleted file mode 100644 index 05fd33ebf8dd..000000000000 --- a/x-pack/plugins/alerting/server/constants/plugin.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { LicenseType } from '@kbn/licensing-plugin/server'; - -export const PLUGIN = { - ID: 'alerting', - MINIMUM_LICENSE_REQUIRED: 'basic' as LicenseType, // TODO: supposed to be changed up on requirements - // all plugins seem to use getI18nName with any - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getI18nName: (i18n: any): string => - i18n.translate('xpack.alerting.appName', { - defaultMessage: 'Alerting', - }), -}; diff --git a/x-pack/plugins/alerting/server/data/alerts_filter_query/constants.ts b/x-pack/plugins/alerting/server/data/alerts_filter_query/constants.ts new file mode 100644 index 000000000000..bce6890c22f2 --- /dev/null +++ b/x-pack/plugins/alerting/server/data/alerts_filter_query/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filterStateStore = { + APP_STATE: 'appState', + GLOBAL_STATE: 'globalState', +} as const; + +export type FilterStateStore = typeof filterStateStore[keyof typeof filterStateStore]; diff --git a/x-pack/plugins/alerting/server/data/alerts_filter_query/types/alerts_filter_query_attributes.ts b/x-pack/plugins/alerting/server/data/alerts_filter_query/types/alerts_filter_query_attributes.ts new file mode 100644 index 000000000000..f740d8070abf --- /dev/null +++ b/x-pack/plugins/alerting/server/data/alerts_filter_query/types/alerts_filter_query_attributes.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FilterStateStore } from '../constants'; + +export interface AlertsFilterAttributes { + query?: Record; + meta: Record; + $state?: { + store: FilterStateStore; + }; +} + +export interface AlertsFilterQueryAttributes { + kql: string; + filters: AlertsFilterAttributes[]; + dsl?: string; +} diff --git a/x-pack/plugins/alerting/server/data/alerts_filter_query/types/index.ts b/x-pack/plugins/alerting/server/data/alerts_filter_query/types/index.ts new file mode 100644 index 000000000000..6258f925b6e7 --- /dev/null +++ b/x-pack/plugins/alerting/server/data/alerts_filter_query/types/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type { AlertsFilterQueryAttributes } from './alerts_filter_query_attributes'; diff --git a/x-pack/plugins/alerting/server/data/maintenance_window/types/maintenance_window_attributes.ts b/x-pack/plugins/alerting/server/data/maintenance_window/types/maintenance_window_attributes.ts index 91f4e9517255..afb217abaf13 100644 --- a/x-pack/plugins/alerting/server/data/maintenance_window/types/maintenance_window_attributes.ts +++ b/x-pack/plugins/alerting/server/data/maintenance_window/types/maintenance_window_attributes.ts @@ -6,7 +6,8 @@ */ import { RRuleAttributes } from '../../r_rule/types'; -import { MaintenanceWindowCategoryIdTypes } from '../constants'; +import type { MaintenanceWindowCategoryIdTypes } from '../constants'; +import { AlertsFilterQueryAttributes } from '../../alerts_filter_query/types'; export interface MaintenanceWindowEventAttributes { gte: string; @@ -25,4 +26,5 @@ export interface MaintenanceWindowAttributes { createdAt: string; updatedAt: string; categoryIds?: MaintenanceWindowCategoryIdTypes[] | null; + scopedQuery?: AlertsFilterQueryAttributes | null; } diff --git a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts b/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts index aa8adda873cd..19a669e6bd33 100644 --- a/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts +++ b/x-pack/plugins/alerting/server/data/rule/types/rule_attributes.ts @@ -6,7 +6,6 @@ */ import type { SavedObjectAttributes } from '@kbn/core/server'; -import { Filter } from '@kbn/es-query'; import { IsoWeekday } from '../../../../common'; import { ruleNotifyWhenAttributes, @@ -16,6 +15,7 @@ import { ruleExecutionStatusWarningReasonAttributes, } from '../constants'; import { RRuleAttributes } from '../../r_rule/types'; +import { AlertsFilterQueryAttributes } from '../../alerts_filter_query/types'; export type RuleNotifyWhenAttributes = typeof ruleNotifyWhenAttributes[keyof typeof ruleNotifyWhenAttributes]; @@ -115,11 +115,7 @@ interface AlertsFilterTimeFrameAttributes { } interface AlertsFilterAttributes { - query?: { - kql: string; - filters: Filter[]; - dsl: string; - }; + query?: AlertsFilterQueryAttributes; timeframe?: AlertsFilterTimeFrameAttributes; } diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index b6962f65b4ab..13237f92b1c1 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -67,6 +67,7 @@ export { isValidAlertIndexName, InstallShutdownError, } from './alerts_service'; +export { sanitizeBulkErrorResponse } from './alerts_client'; export { getDataStreamAdapter } from './alerts_service/lib/data_stream_adapter'; export const plugin = async (initContext: PluginInitializerContext) => { diff --git a/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts b/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts index 9a8109977962..32fac87b7485 100644 --- a/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts +++ b/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts @@ -33,6 +33,7 @@ describe('createGetAlertIndicesAliasFn', () => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, + latestRuleVersion: 1, }; const registry = new RuleTypeRegistry(ruleTypeRegistryParams); registry.register({ diff --git a/x-pack/plugins/alerting/server/lib/license_state.ts b/x-pack/plugins/alerting/server/lib/license_state.ts index c774673934eb..99be775f7c3c 100644 --- a/x-pack/plugins/alerting/server/lib/license_state.ts +++ b/x-pack/plugins/alerting/server/lib/license_state.ts @@ -13,7 +13,7 @@ import { capitalize } from 'lodash'; import { Observable, Subscription } from 'rxjs'; import { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { ILicense, LicenseType } from '@kbn/licensing-plugin/common/types'; -import { PLUGIN } from '../constants/plugin'; +import { PLUGIN } from '../../common/constants/plugin'; import { getRuleTypeFeatureUsageName } from './get_rule_type_feature_usage_name'; import { RuleType, diff --git a/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts b/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts index 9f3f2d26447d..a1ec0a351729 100644 --- a/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/maintenance_window_client_factory.test.ts @@ -14,7 +14,7 @@ import { savedObjectsServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; -import { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; import { MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE } from '../common'; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 03431c2804c6..64bc8ca05281 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -77,7 +77,7 @@ import { } from './types'; import { registerAlertingUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; -import { setupSavedObjects } from './saved_objects'; +import { setupSavedObjects, getLatestRuleVersion } from './saved_objects'; import { initializeApiKeyInvalidator, scheduleApiKeyInvalidatorTask, @@ -305,6 +305,7 @@ export class AlertingPlugin { alertsService: this.alertsService, minimumScheduleInterval: this.config.rules.minimumScheduleInterval, inMemoryMetrics: this.inMemoryMetrics, + latestRuleVersion: getLatestRuleVersion(), }); this.ruleTypeRegistry = ruleTypeRegistry; diff --git a/x-pack/plugins/alerting/server/raw_rule_schema.ts b/x-pack/plugins/alerting/server/raw_rule_schema.ts deleted file mode 100644 index 4072b15b1921..000000000000 --- a/x-pack/plugins/alerting/server/raw_rule_schema.ts +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; - -const executionStatusWarningReason = schema.oneOf([ - schema.literal('maxExecutableActions'), - schema.literal('maxAlerts'), - schema.literal('maxQueuedActions'), -]); - -const executionStatusErrorReason = schema.oneOf([ - schema.literal('read'), - schema.literal('decrypt'), - schema.literal('execute'), - schema.literal('unknown'), - schema.literal('license'), - schema.literal('timeout'), - schema.literal('disabled'), - schema.literal('validate'), -]); - -const rawRuleExecutionStatusSchema = schema.object({ - status: schema.oneOf([ - schema.literal('ok'), - schema.literal('active'), - schema.literal('error'), - schema.literal('pending'), - schema.literal('unknown'), - schema.literal('warning'), - ]), - lastExecutionDate: schema.string(), - lastDuration: schema.maybe(schema.number()), - error: schema.nullable( - schema.object({ - reason: executionStatusErrorReason, - message: schema.string(), - }) - ), - warning: schema.nullable( - schema.object({ - reason: executionStatusWarningReason, - message: schema.string(), - }) - ), -}); - -const ISOWeekdaysSchema = schema.oneOf([ - schema.literal(1), - schema.literal(2), - schema.literal(3), - schema.literal(4), - schema.literal(5), - schema.literal(6), - schema.literal(7), -]); - -const rRuleSchema = schema.object({ - dtstart: schema.string(), - tzid: schema.string(), - freq: schema.maybe( - schema.oneOf([ - schema.literal(0), - schema.literal(1), - schema.literal(2), - schema.literal(3), - schema.literal(4), - schema.literal(5), - schema.literal(6), - ]) - ), - until: schema.maybe(schema.string()), - count: schema.maybe(schema.number()), - interval: schema.maybe(schema.number()), - wkst: schema.maybe( - schema.oneOf([ - schema.literal('MO'), - schema.literal('TU'), - schema.literal('WE'), - schema.literal('TH'), - schema.literal('FR'), - schema.literal('SA'), - schema.literal('SU'), - ]) - ), - byweekday: schema.maybe(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))), - bymonth: schema.maybe(schema.number()), - bysetpos: schema.maybe(schema.number()), - bymonthday: schema.maybe(schema.number()), - byyearday: schema.maybe(schema.number()), - byweekno: schema.maybe(schema.number()), - byhour: schema.maybe(schema.number()), - byminute: schema.maybe(schema.number()), - bysecond: schema.maybe(schema.number()), -}); - -const outcome = schema.oneOf([ - schema.literal('succeeded'), - schema.literal('warning'), - schema.literal('failed'), -]); - -const rawRuleLastRunSchema = schema.object({ - outcome, - outcomeOrder: schema.maybe(schema.number()), - alertsCount: schema.object({ - new: schema.maybe(schema.nullable(schema.number())), - active: schema.maybe(schema.nullable(schema.number())), - recovered: schema.maybe(schema.nullable(schema.number())), - ignored: schema.maybe(schema.nullable(schema.number())), - }), - outcomeMsg: schema.maybe(schema.nullable(schema.arrayOf(schema.string()))), - warning: schema.maybe( - schema.nullable(schema.oneOf([executionStatusErrorReason, executionStatusWarningReason])) - ), -}); - -const rawRuleMonitoringSchema = schema.object({ - run: schema.object({ - history: schema.arrayOf( - schema.object({ - success: schema.boolean(), - timestamp: schema.number(), - duration: schema.maybe(schema.number()), - outcome: schema.maybe(outcome), - }) - ), - calculated_metrics: schema.object({ - p50: schema.maybe(schema.number()), - p95: schema.maybe(schema.number()), - p99: schema.maybe(schema.number()), - success_ratio: schema.number(), - }), - last_run: schema.object({ - timestamp: schema.string(), - metrics: schema.object({ - duration: schema.maybe(schema.number()), - total_search_duration_ms: schema.maybe(schema.nullable(schema.number())), - total_indexing_duration_ms: schema.maybe(schema.nullable(schema.number())), - total_alerts_detected: schema.maybe(schema.nullable(schema.number())), - total_alerts_created: schema.maybe(schema.nullable(schema.number())), - gap_duration_s: schema.maybe(schema.nullable(schema.number())), - }), - }), - }), -}); - -const rawRuleAlertsFilterSchema = schema.object({ - query: schema.maybe( - schema.object({ - kql: schema.string(), - filters: schema.arrayOf( - schema.object({ - query: schema.maybe(schema.recordOf(schema.string(), schema.any())), - meta: schema.object({ - alias: schema.maybe(schema.nullable(schema.string())), - disabled: schema.maybe(schema.boolean()), - negate: schema.maybe(schema.boolean()), - controlledBy: schema.maybe(schema.string()), - group: schema.maybe(schema.string()), - index: schema.maybe(schema.string()), - isMultiIndex: schema.maybe(schema.boolean()), - type: schema.maybe(schema.string()), - key: schema.maybe(schema.string()), - params: schema.maybe(schema.recordOf(schema.string(), schema.any())), // better type? - value: schema.maybe(schema.string()), - }), - $state: schema.maybe( - schema.object({ - store: schema.oneOf([schema.literal('appState'), schema.literal('globalState')]), - }) - ), - }) - ), - dsl: schema.maybe(schema.string()), - }) - ), - timeframe: schema.maybe( - schema.object({ - days: schema.arrayOf(ISOWeekdaysSchema), - hours: schema.object({ - start: schema.string(), - end: schema.string(), - }), - timezone: schema.string(), - }) - ), -}); - -const rawRuleActionSchema = schema.object({ - uuid: schema.maybe(schema.string()), - group: schema.string(), - actionRef: schema.string(), - actionTypeId: schema.string(), - params: schema.recordOf(schema.string(), schema.any()), - frequency: schema.maybe( - schema.object({ - summary: schema.boolean(), - notifyWhen: schema.oneOf([ - schema.literal('onActionGroupChange'), - schema.literal('onActiveAlert'), - schema.literal('onThrottleInterval'), - ]), - throttle: schema.nullable(schema.string()), - }) - ), - alertsFilter: schema.maybe(rawRuleAlertsFilterSchema), -}); - -export const rawRuleSchema = schema.object({ - name: schema.string(), - enabled: schema.boolean(), - consumer: schema.string(), - tags: schema.arrayOf(schema.string()), - alertTypeId: schema.string(), - apiKeyOwner: schema.nullable(schema.string()), - apiKey: schema.nullable(schema.string()), - apiKeyCreatedByUser: schema.maybe(schema.nullable(schema.boolean())), - createdBy: schema.nullable(schema.string()), - updatedBy: schema.nullable(schema.string()), - updatedAt: schema.string(), - createdAt: schema.string(), - muteAll: schema.boolean(), - mutedInstanceIds: schema.arrayOf(schema.string()), - throttle: schema.maybe(schema.nullable(schema.string())), - revision: schema.number(), - running: schema.maybe(schema.nullable(schema.boolean())), - schedule: schema.object({ - interval: schema.string(), - }), - legacyId: schema.nullable(schema.string()), - scheduledTaskId: schema.maybe(schema.nullable(schema.string())), - isSnoozedUntil: schema.maybe(schema.nullable(schema.string())), - snoozeSchedule: schema.maybe( - schema.arrayOf( - schema.object({ - duration: schema.number(), - rRule: rRuleSchema, - id: schema.maybe(schema.string()), - skipRecurrences: schema.maybe(schema.arrayOf(schema.string())), - }) - ) - ), - meta: schema.maybe(schema.object({ versionApiKeyLastmodified: schema.maybe(schema.string()) })), - actions: schema.arrayOf(rawRuleActionSchema), - executionStatus: rawRuleExecutionStatusSchema, - notifyWhen: schema.maybe( - schema.nullable( - schema.oneOf([ - schema.literal('onActionGroupChange'), - schema.literal('onActiveAlert'), - schema.literal('onThrottleInterval'), - ]) - ) - ), - monitoring: schema.maybe(rawRuleMonitoringSchema), - lastRun: schema.maybe(schema.nullable(rawRuleLastRunSchema)), - nextRun: schema.maybe(schema.nullable(schema.string())), - mapped_params: schema.maybe( - schema.object({ - risk_score: schema.maybe(schema.number()), - severity: schema.maybe(schema.string()), - }) - ), - params: schema.recordOf(schema.string(), schema.any()), -}); diff --git a/x-pack/plugins/alerting/server/routes/lib/rewrite_actions.ts b/x-pack/plugins/alerting/server/routes/lib/rewrite_actions.ts index 16309485c18a..96c2275d113a 100644 --- a/x-pack/plugins/alerting/server/routes/lib/rewrite_actions.ts +++ b/x-pack/plugins/alerting/server/routes/lib/rewrite_actions.ts @@ -24,7 +24,7 @@ export const rewriteActionsReq = ( }) => { return { ...action, - useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' ? { useAlertDataForTemplate } : {}), ...(frequency ? { frequency: { @@ -49,7 +49,9 @@ export const rewriteActionsRes = (actions?: RuleAction[]) => { ({ actionTypeId, frequency, alertsFilter, useAlertDataForTemplate, ...action }) => ({ ...action, connector_type_id: actionTypeId, - use_alert_data_for_template: useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' + ? { use_alert_data_for_template: useAlertDataForTemplate } + : {}), ...(frequency ? { frequency: rewriteFrequency(frequency) } : {}), ...(alertsFilter ? { diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/create/transforms/transform_create_body/v1.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/create/transforms/transform_create_body/v1.ts index 03627c258c5e..6eaa77fc7862 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/create/transforms/transform_create_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/create/transforms/transform_create_body/v1.ts @@ -16,5 +16,6 @@ export const transformCreateBody = ( duration: createBody.duration, rRule: createBody.r_rule, categoryIds: createBody.category_ids, + scopedQuery: createBody.scoped_query, }; }; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/transforms/transform_update_body/v1.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/transforms/transform_update_body/v1.ts index 9da852bd6ebf..96c4e92d4934 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/transforms/transform_update_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/apis/update/transforms/transform_update_body/v1.ts @@ -11,12 +11,21 @@ import { UpdateMaintenanceWindowParams } from '../../../../../../application/mai export const transformUpdateBody = ( updateBody: UpdateMaintenanceWindowRequestBodyV1 ): UpdateMaintenanceWindowParams['data'] => { - const { title, enabled, duration, r_rule: rRule, category_ids: categoryIds } = updateBody; + const { + title, + enabled, + duration, + r_rule: rRule, + category_ids: categoryIds, + scoped_query: scopedQuery, + } = updateBody; + return { ...(title !== undefined ? { title } : {}), ...(enabled !== undefined ? { enabled } : {}), ...(duration !== undefined ? { duration } : {}), ...(rRule !== undefined ? { rRule } : {}), ...(categoryIds !== undefined ? { categoryIds } : {}), + ...(scopedQuery !== undefined ? { scopedQuery } : {}), }; }; diff --git a/x-pack/plugins/alerting/server/routes/maintenance_window/transforms/transform_maintenance_window_to_response/v1.ts b/x-pack/plugins/alerting/server/routes/maintenance_window/transforms/transform_maintenance_window_to_response/v1.ts index e6e0fb9a6aa4..2d21576773c2 100644 --- a/x-pack/plugins/alerting/server/routes/maintenance_window/transforms/transform_maintenance_window_to_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/maintenance_window/transforms/transform_maintenance_window_to_response/v1.ts @@ -29,5 +29,8 @@ export const transformMaintenanceWindowToResponse = ( ...(maintenanceWindow.categoryIds !== undefined ? { category_ids: maintenanceWindow.categoryIds } : {}), + ...(maintenanceWindow.scopedQuery !== undefined + ? { scoped_query: maintenanceWindow.scopedQuery } + : {}), }; }; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.test.ts index 9a77d46fb920..1b1ed454c520 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.test.ts @@ -114,7 +114,6 @@ describe('bulkEditRulesRoute', () => { foo: true, }, uuid: '123-456', - use_alert_data_for_template: false, }, ], }), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts index a12b8ee5e177..e952a72ec385 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts @@ -124,7 +124,6 @@ describe('createRuleRoute', () => { }, connector_type_id: 'test', uuid: '123-456', - use_alert_data_for_template: false, }, ], }; @@ -199,7 +198,6 @@ describe('createRuleRoute', () => { "params": Object { "foo": true, }, - "useAlertDataForTemplate": undefined, }, ], "alertTypeId": "1", @@ -316,7 +314,6 @@ describe('createRuleRoute', () => { "params": Object { "foo": true, }, - "useAlertDataForTemplate": undefined, }, ], "alertTypeId": "1", @@ -434,7 +431,6 @@ describe('createRuleRoute', () => { "params": Object { "foo": true, }, - "useAlertDataForTemplate": undefined, }, ], "alertTypeId": "1", @@ -552,7 +548,6 @@ describe('createRuleRoute', () => { "params": Object { "foo": true, }, - "useAlertDataForTemplate": undefined, }, ], "alertTypeId": "1", diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts index a9e9a25d05c9..97ff8b383e4c 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/transforms/transform_create_body/v1.ts @@ -27,7 +27,7 @@ const transformCreateBodyActions = (actions: CreateRuleActionV1[]): CreateRuleDa id: action.id, params: action.params, actionTypeId: action.actionTypeId, - useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' ? { useAlertDataForTemplate } : {}), ...(action.uuid ? { uuid: action.uuid } : {}), ...(frequency ? { diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts index 3968e0e27162..fb6799f2b5e4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts @@ -63,7 +63,9 @@ export const transformRuleToRuleResponse = ( id, params, connector_type_id: actionTypeId, - use_alert_data_for_template: useAlertDataForTemplate ?? false, + ...(typeof useAlertDataForTemplate !== 'undefined' + ? { use_alert_data_for_template: useAlertDataForTemplate } + : {}), ...(frequency ? { frequency: { diff --git a/x-pack/plugins/alerting/server/routes/update_rule.test.ts b/x-pack/plugins/alerting/server/routes/update_rule.test.ts index 87901feab64c..5a4b3a19c0d7 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule.test.ts @@ -132,7 +132,6 @@ describe('updateRuleRoute', () => { "params": Object { "baz": true, }, - "useAlertDataForTemplate": undefined, "uuid": "1234-5678", }, ], diff --git a/x-pack/plugins/alerting/server/rule_type_registry.mock.ts b/x-pack/plugins/alerting/server/rule_type_registry.mock.ts index 706484fdd92f..0aa7e5b68b40 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.mock.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.mock.ts @@ -18,6 +18,7 @@ const createRuleTypeRegistryMock = () => { list: jest.fn(), getAllTypes: jest.fn(), ensureRuleTypeEnabled: jest.fn(), + getLatestRuleVersion: jest.fn(), }; return mocked; }; diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index 8e01e7d05cbd..2059f1e7548e 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -40,6 +40,7 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, + latestRuleVersion: 1, }; }); @@ -782,6 +783,7 @@ describe('Create Lifecycle', () => { "defaultScheduleInterval": undefined, "doesSetRecoveryContext": false, "enabledInLicense": false, + "fieldsForAAD": undefined, "hasAlertsMappings": true, "hasFieldsForAAD": false, "id": "test", @@ -911,6 +913,16 @@ describe('Create Lifecycle', () => { ).toThrowErrorMatchingInlineSnapshot(`"Fail"`); }); }); + + describe('getLatestRuleVersion', () => { + test('should return the latest rule version', async () => { + const ruleTypeRegistry = new RuleTypeRegistry({ + ...ruleTypeRegistryParams, + latestRuleVersion: 5, + }); + expect(ruleTypeRegistry.getLatestRuleVersion()).toBe(5); + }); + }); }); function ruleTypeWithVariables( diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index d73d28950970..2ed57e878291 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -14,7 +14,6 @@ import { Logger } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { RunContext, TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; import { stateSchemaByVersion } from '@kbn/alerting-state-types'; -import { rawRuleSchema } from './raw_rule_schema'; import { TaskRunnerFactory } from './task_runner'; import { RuleType, @@ -40,6 +39,7 @@ import { AlertingRulesConfig } from '.'; import { AlertsService } from './alerts_service/alerts_service'; import { getRuleTypeIdValidLegacyConsumers } from './rule_type_registry_deprecated_consumers'; import { AlertingConfig } from './config'; +import { rawRuleSchemaV1 } from './saved_objects/schemas/raw_rule'; export interface ConstructorOptions { config: AlertingConfig; @@ -51,6 +51,7 @@ export interface ConstructorOptions { minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval']; inMemoryMetrics: InMemoryMetrics; alertsService: AlertsService | null; + latestRuleVersion: number; } export interface RegistryRuleType @@ -160,6 +161,7 @@ export class RuleTypeRegistry { private readonly licensing: LicensingPluginSetup; private readonly inMemoryMetrics: InMemoryMetrics; private readonly alertsService: AlertsService | null; + private readonly latestRuleVersion: number; constructor({ config, @@ -171,6 +173,7 @@ export class RuleTypeRegistry { minimumScheduleInterval, inMemoryMetrics, alertsService, + latestRuleVersion, }: ConstructorOptions) { this.config = config; this.logger = logger; @@ -181,6 +184,7 @@ export class RuleTypeRegistry { this.minimumScheduleInterval = minimumScheduleInterval; this.inMemoryMetrics = inMemoryMetrics; this.alertsService = alertsService; + this.latestRuleVersion = latestRuleVersion; } public has(id: string) { @@ -311,7 +315,7 @@ export class RuleTypeRegistry { spaceId: schema.string(), consumer: schema.maybe(schema.string()), }), - indirectParamsSchema: rawRuleSchema, + indirectParamsSchema: rawRuleSchemaV1, }, }); @@ -419,6 +423,7 @@ export class RuleTypeRegistry { name, minimumLicenseRequired ).isValid, + fieldsForAAD, hasFieldsForAAD: Boolean(fieldsForAAD), hasAlertsMappings: !!alerts, validLegacyConsumers, @@ -433,6 +438,10 @@ export class RuleTypeRegistry { public getAllTypes(): string[] { return [...this.ruleTypes.keys()]; } + + public getLatestRuleVersion() { + return this.latestRuleVersion; + } } function normalizedActionVariables(actionVariables: RuleType['actionVariables']) { diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 9f1a4acb1242..0532a48be01e 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -15,7 +15,7 @@ import { savedObjectsRepositoryMock, } from '@kbn/core/server/mocks'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; -import { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { PluginStartContract as ActionsStartContract } from '@kbn/actions-plugin/server'; import { actionsMock, actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; diff --git a/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts index bb278dbf50cd..6f713f20530e 100644 --- a/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_settings_client_factory.test.ts @@ -15,7 +15,7 @@ import { savedObjectsServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; -import { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; import { RULES_SETTINGS_SAVED_OBJECT_TYPE } from '../common'; diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index c16356193fd8..9006bf1cab1b 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -24,10 +24,12 @@ import { getImportWarnings } from './get_import_warnings'; import { isRuleExportable } from './is_rule_exportable'; import { RuleTypeRegistry } from '../rule_type_registry'; export { partiallyUpdateAlert } from './partially_update_alert'; +export { getLatestRuleVersion, getMinimumCompatibleVersion } from './rule_model_versions'; import { RULES_SETTINGS_SAVED_OBJECT_TYPE, MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, } from '../../common'; +import { ruleModelVersions } from './rule_model_versions'; // Use caution when removing items from this array! Any field which has // ever existed in the rule SO must be included in this array to prevent @@ -106,6 +108,7 @@ export function setupSavedObjects( return isRuleExportable(ruleSavedObject, ruleTypeRegistry, logger); }, }, + modelVersions: ruleModelVersions, }); savedObjects.registerType({ diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts index 442dcf0a9469..bf330be87257 100644 --- a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -37,6 +37,7 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, + latestRuleVersion: 1, }; }); diff --git a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts new file mode 100644 index 000000000000..9afcdaad8e2f --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + CustomSavedObjectsModelVersionMap, + getLatestRuleVersion, + getMinimumCompatibleVersion, +} from './rule_model_versions'; +import { schema } from '@kbn/config-schema'; +import { RawRule } from '../types'; + +describe('rule model versions', () => { + const ruleModelVersions: CustomSavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: schema.object({ + name: schema.string(), + }), + }, + isCompatibleWithPreviousVersion: (rawRule) => true, + }, + '2': { + changes: [], + schemas: { + create: schema.object({ + name: schema.string(), + }), + }, + isCompatibleWithPreviousVersion: (rawRule) => false, + }, + '3': { + changes: [], + schemas: { + create: schema.object({ + name: schema.string(), + }), + }, + isCompatibleWithPreviousVersion: (rawRule) => rawRule.name === 'test', + }, + '4': { + changes: [], + schemas: { + create: schema.object({ + name: schema.string(), + }), + }, + isCompatibleWithPreviousVersion: (rawRule) => rawRule.name === 'test', + }, + }; + + const rawRule = { name: 'test' } as RawRule; + const mismatchingRawRule = { enabled: true } as RawRule; + + describe('getMinimumCompatibleVersion', () => { + it('should return the minimum compatible version for the matching rawRule', () => { + expect(getMinimumCompatibleVersion(ruleModelVersions, 1, rawRule)).toBe(1); + expect(getMinimumCompatibleVersion(ruleModelVersions, 2, rawRule)).toBe(2); + expect(getMinimumCompatibleVersion(ruleModelVersions, 3, rawRule)).toBe(2); + expect(getMinimumCompatibleVersion(ruleModelVersions, 4, rawRule)).toBe(2); + }); + it('should return the minimum compatible version for the mismatching rawRule', () => { + expect(getMinimumCompatibleVersion(ruleModelVersions, 3, mismatchingRawRule)).toBe(3); + expect(getMinimumCompatibleVersion(ruleModelVersions, 4, mismatchingRawRule)).toBe(4); + }); + }); + + describe('getLatestRuleVersion', () => { + it('should return the latest rule model version', () => { + expect(getLatestRuleVersion()).toBe(1); + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts new file mode 100644 index 000000000000..38adc17389b2 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + SavedObjectsModelVersion, + SavedObjectsModelVersionMap, +} from '@kbn/core-saved-objects-server'; +import { RawRule } from '../types'; +import { rawRuleSchemaV1 } from './schemas/raw_rule'; + +interface CustomSavedObjectsModelVersion extends SavedObjectsModelVersion { + isCompatibleWithPreviousVersion: (param: RawRule) => boolean; +} + +export interface CustomSavedObjectsModelVersionMap extends SavedObjectsModelVersionMap { + [modelVersion: string]: CustomSavedObjectsModelVersion; +} + +export const ruleModelVersions: CustomSavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: rawRuleSchemaV1, + }, + isCompatibleWithPreviousVersion: (rawRule) => true, + }, +}; + +export const getLatestRuleVersion = () => Math.max(...Object.keys(ruleModelVersions).map(Number)); + +export function getMinimumCompatibleVersion( + modelVersions: CustomSavedObjectsModelVersionMap, + version: number, + rawRule: RawRule +): number { + if (version === 1) { + return 1; + } + + if (modelVersions[version].isCompatibleWithPreviousVersion(rawRule)) { + return getMinimumCompatibleVersion(modelVersions, version - 1, rawRule); + } + + return version; +} diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts new file mode 100644 index 000000000000..d5778bcda4a7 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { rawRuleSchema as rawRuleSchemaV1 } from './v1'; diff --git a/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v1.ts b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v1.ts new file mode 100644 index 000000000000..76c6241396dc --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/schemas/raw_rule/v1.ts @@ -0,0 +1,273 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +const executionStatusWarningReason = schema.oneOf([ + schema.literal('maxExecutableActions'), + schema.literal('maxAlerts'), + schema.literal('maxQueuedActions'), +]); + +const executionStatusErrorReason = schema.oneOf([ + schema.literal('read'), + schema.literal('decrypt'), + schema.literal('execute'), + schema.literal('unknown'), + schema.literal('license'), + schema.literal('timeout'), + schema.literal('disabled'), + schema.literal('validate'), +]); + +const rawRuleExecutionStatusSchema = schema.object({ + status: schema.oneOf([ + schema.literal('ok'), + schema.literal('active'), + schema.literal('error'), + schema.literal('pending'), + schema.literal('unknown'), + schema.literal('warning'), + ]), + lastExecutionDate: schema.string(), + lastDuration: schema.maybe(schema.number()), + error: schema.nullable( + schema.object({ + reason: executionStatusErrorReason, + message: schema.string(), + }) + ), + warning: schema.nullable( + schema.object({ + reason: executionStatusWarningReason, + message: schema.string(), + }) + ), +}); + +const ISOWeekdaysSchema = schema.oneOf([ + schema.literal(1), + schema.literal(2), + schema.literal(3), + schema.literal(4), + schema.literal(5), + schema.literal(6), + schema.literal(7), +]); + +const rRuleSchema = schema.object({ + dtstart: schema.string(), + tzid: schema.string(), + freq: schema.maybe( + schema.oneOf([ + schema.literal(0), + schema.literal(1), + schema.literal(2), + schema.literal(3), + schema.literal(4), + schema.literal(5), + schema.literal(6), + ]) + ), + until: schema.maybe(schema.string()), + count: schema.maybe(schema.number()), + interval: schema.maybe(schema.number()), + wkst: schema.maybe( + schema.oneOf([ + schema.literal('MO'), + schema.literal('TU'), + schema.literal('WE'), + schema.literal('TH'), + schema.literal('FR'), + schema.literal('SA'), + schema.literal('SU'), + ]) + ), + byweekday: schema.maybe(schema.arrayOf(schema.oneOf([schema.string(), schema.number()]))), + bymonth: schema.maybe(schema.number()), + bysetpos: schema.maybe(schema.number()), + bymonthday: schema.maybe(schema.number()), + byyearday: schema.maybe(schema.number()), + byweekno: schema.maybe(schema.number()), + byhour: schema.maybe(schema.number()), + byminute: schema.maybe(schema.number()), + bysecond: schema.maybe(schema.number()), +}); + +const outcome = schema.oneOf([ + schema.literal('succeeded'), + schema.literal('warning'), + schema.literal('failed'), +]); + +const rawRuleLastRunSchema = schema.object({ + outcome, + outcomeOrder: schema.maybe(schema.number()), + alertsCount: schema.object({ + new: schema.maybe(schema.nullable(schema.number())), + active: schema.maybe(schema.nullable(schema.number())), + recovered: schema.maybe(schema.nullable(schema.number())), + ignored: schema.maybe(schema.nullable(schema.number())), + }), + outcomeMsg: schema.maybe(schema.nullable(schema.arrayOf(schema.string()))), + warning: schema.maybe( + schema.nullable(schema.oneOf([executionStatusErrorReason, executionStatusWarningReason])) + ), +}); + +const rawRuleMonitoringSchema = schema.object({ + run: schema.object({ + history: schema.arrayOf( + schema.object({ + success: schema.boolean(), + timestamp: schema.number(), + duration: schema.maybe(schema.number()), + outcome: schema.maybe(outcome), + }) + ), + calculated_metrics: schema.object({ + p50: schema.maybe(schema.number()), + p95: schema.maybe(schema.number()), + p99: schema.maybe(schema.number()), + success_ratio: schema.number(), + }), + last_run: schema.object({ + timestamp: schema.string(), + metrics: schema.object({ + duration: schema.maybe(schema.number()), + total_search_duration_ms: schema.maybe(schema.nullable(schema.number())), + total_indexing_duration_ms: schema.maybe(schema.nullable(schema.number())), + total_alerts_detected: schema.maybe(schema.nullable(schema.number())), + total_alerts_created: schema.maybe(schema.nullable(schema.number())), + gap_duration_s: schema.maybe(schema.nullable(schema.number())), + }), + }), + }), +}); + +const rawRuleAlertsFilterSchema = schema.object({ + query: schema.maybe( + schema.object({ + kql: schema.string(), + filters: schema.arrayOf( + schema.object({ + query: schema.maybe(schema.recordOf(schema.string(), schema.any())), + meta: schema.object({ + alias: schema.maybe(schema.nullable(schema.string())), + disabled: schema.maybe(schema.boolean()), + negate: schema.maybe(schema.boolean()), + controlledBy: schema.maybe(schema.string()), + group: schema.maybe(schema.string()), + index: schema.maybe(schema.string()), + isMultiIndex: schema.maybe(schema.boolean()), + type: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + params: schema.maybe(schema.recordOf(schema.string(), schema.any())), // better type? + value: schema.maybe(schema.string()), + field: schema.maybe(schema.string()), + }), + $state: schema.maybe( + schema.object({ + store: schema.oneOf([schema.literal('appState'), schema.literal('globalState')]), + }) + ), + }) + ), + dsl: schema.maybe(schema.string()), + }) + ), + timeframe: schema.maybe( + schema.object({ + days: schema.arrayOf(ISOWeekdaysSchema), + hours: schema.object({ + start: schema.string(), + end: schema.string(), + }), + timezone: schema.string(), + }) + ), +}); + +const rawRuleActionSchema = schema.object({ + uuid: schema.maybe(schema.string()), + group: schema.string(), + actionRef: schema.string(), + actionTypeId: schema.string(), + params: schema.recordOf(schema.string(), schema.any()), + frequency: schema.maybe( + schema.object({ + summary: schema.boolean(), + notifyWhen: schema.oneOf([ + schema.literal('onActionGroupChange'), + schema.literal('onActiveAlert'), + schema.literal('onThrottleInterval'), + ]), + throttle: schema.nullable(schema.string()), + }) + ), + alertsFilter: schema.maybe(rawRuleAlertsFilterSchema), + useAlertDataForTemplate: schema.maybe(schema.boolean()), +}); + +export const rawRuleSchema = schema.object({ + name: schema.string(), + enabled: schema.boolean(), + consumer: schema.string(), + tags: schema.arrayOf(schema.string()), + alertTypeId: schema.string(), + apiKeyOwner: schema.nullable(schema.string()), + apiKey: schema.nullable(schema.string()), + apiKeyCreatedByUser: schema.maybe(schema.nullable(schema.boolean())), + createdBy: schema.nullable(schema.string()), + updatedBy: schema.nullable(schema.string()), + updatedAt: schema.string(), + createdAt: schema.string(), + muteAll: schema.boolean(), + mutedInstanceIds: schema.arrayOf(schema.string()), + throttle: schema.maybe(schema.nullable(schema.string())), + revision: schema.number(), + running: schema.maybe(schema.nullable(schema.boolean())), + schedule: schema.object({ + interval: schema.string(), + }), + legacyId: schema.nullable(schema.string()), + scheduledTaskId: schema.maybe(schema.nullable(schema.string())), + isSnoozedUntil: schema.maybe(schema.nullable(schema.string())), + snoozeSchedule: schema.maybe( + schema.arrayOf( + schema.object({ + duration: schema.number(), + rRule: rRuleSchema, + id: schema.maybe(schema.string()), + skipRecurrences: schema.maybe(schema.arrayOf(schema.string())), + }) + ) + ), + meta: schema.maybe(schema.object({ versionApiKeyLastmodified: schema.maybe(schema.string()) })), + actions: schema.arrayOf(rawRuleActionSchema), + executionStatus: rawRuleExecutionStatusSchema, + notifyWhen: schema.maybe( + schema.nullable( + schema.oneOf([ + schema.literal('onActionGroupChange'), + schema.literal('onActiveAlert'), + schema.literal('onThrottleInterval'), + ]) + ) + ), + monitoring: schema.maybe(rawRuleMonitoringSchema), + lastRun: schema.maybe(schema.nullable(rawRuleLastRunSchema)), + nextRun: schema.maybe(schema.nullable(schema.string())), + mapped_params: schema.maybe( + schema.object({ + risk_score: schema.maybe(schema.number()), + severity: schema.maybe(schema.string()), + }) + ), + params: schema.recordOf(schema.string(), schema.maybe(schema.any())), + typeVersion: schema.maybe(schema.number()), +}); diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts index d0ddc6b2f53c..dbe1da998885 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts @@ -12,7 +12,7 @@ import { PathReporter } from 'io-ts/lib/PathReporter'; import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; import { booleanRt } from '../runtime_types/boolean_rt'; import { getIntegerRt } from '../runtime_types/integer_rt'; -import { isRumOrMobileAgent } from '../../agent_name'; +import { isRumOrMobileAgentName } from '../../agent_name'; import { floatRt } from '../runtime_types/float_rt'; import { RawSettingDefinition, SettingDefinition } from './types'; import { generalSettings } from './general_settings'; @@ -106,7 +106,7 @@ export function filterByAgent(agentName?: AgentName) { // only options that apply to every agent (ignoring RUM) should be returned if (setting.excludeAgents) { - return setting.excludeAgents.every(isRumOrMobileAgent); + return setting.excludeAgents.every(isRumOrMobileAgentName); } return true; diff --git a/x-pack/plugins/apm/common/agent_name.test.ts b/x-pack/plugins/apm/common/agent_name.test.ts deleted file mode 100644 index 972ecb39fcec..000000000000 --- a/x-pack/plugins/apm/common/agent_name.test.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - isJavaAgentName, - isRumAgentName, - isIosAgentName, - isAndroidAgentName, - isMobileAgentName, - isServerlessAgent, - isAWSLambdaAgent, - isAzureFunctionsAgent, -} from './agent_name'; - -import { ServerlessType } from './serverless'; - -describe('agent name helpers', () => { - describe('isJavaAgentName', () => { - describe('when the agent name is java', () => { - it('returns true', () => { - expect(isJavaAgentName('java')).toEqual(true); - }); - }); - - describe('when the agent name is opentelemetry/java', () => { - it('returns true', () => { - expect(isJavaAgentName('opentelemetry/java')).toEqual(true); - }); - }); - - describe('when the agent name is not java', () => { - it('returns false', () => { - expect(isJavaAgentName('not java')).toEqual(false); - }); - }); - }); - - describe('isRumAgentName', () => { - describe('when the agent name is js-base', () => { - it('returns true', () => { - expect(isRumAgentName('js-base')).toEqual(true); - }); - }); - - describe('when the agent name is rum-js', () => { - it('returns true', () => { - expect(isRumAgentName('rum-js')).toEqual(true); - }); - }); - - describe('when the agent name is opentelemetry/webjs', () => { - it('returns true', () => { - expect(isRumAgentName('opentelemetry/webjs')).toEqual(true); - }); - }); - - describe('when the agent name is something else', () => { - it('returns false', () => { - expect(isRumAgentName('not rum')).toEqual(false); - }); - }); - }); - - describe('isIosAgentName', () => { - describe('when the agent name is iOS/swift', () => { - it('returns true', () => { - expect(isIosAgentName('iOS/swift')).toEqual(true); - }); - }); - - describe('when the agent name is ios/swift', () => { - it('returns true', () => { - expect(isIosAgentName('ios/swift')).toEqual(true); - }); - }); - - describe('when the agent name is opentelemetry/swift', () => { - it('returns true', () => { - expect(isIosAgentName('opentelemetry/swift')).toEqual(false); - }); - }); - - describe('when the agent name is something else', () => { - it('returns false', () => { - expect(isIosAgentName('not ios')).toEqual(false); - }); - }); - }); - - describe('isAndroidAgentName', () => { - describe('when the agent name is android/java', () => { - it('returns true', () => { - expect(isAndroidAgentName('android/java')).toEqual(true); - }); - }); - - describe('when the agent name is opentelemetry/java', () => { - it('returns false', () => { - expect(isAndroidAgentName('opentelemetry/java')).toEqual(false); - }); - }); - - describe('when the agent name is something else', () => { - it('returns false', () => { - expect(isAndroidAgentName('not android')).toEqual(false); - }); - }); - }); - - describe('isMobileAgentName', () => { - describe('when the agent name is android/java', () => { - it('returns true', () => { - expect(isMobileAgentName('android/java')).toEqual(true); - }); - }); - - describe('when the agent name is iOS/swift', () => { - it('returns true', () => { - expect(isMobileAgentName('iOS/swift')).toEqual(true); - }); - }); - - describe('when the agent name is ios/swift', () => { - it('returns true', () => { - expect(isMobileAgentName('ios/swift')).toEqual(true); - }); - }); - - describe('when the agent name is opentelemetry/swift', () => { - it('returns true', () => { - expect(isMobileAgentName('opentelemetry/swift')).toEqual(false); - }); - }); - - describe('when the agent name is opentelemetry/java', () => { - it('returns false', () => { - expect(isMobileAgentName('opentelemetry/java')).toEqual(false); - }); - }); - - describe('when the agent name is something else', () => { - it('returns false', () => { - expect(isMobileAgentName('not mobile')).toEqual(false); - }); - }); - }); - - describe('isServerlessAgent', () => { - describe('when the serverlessType is AWS_LAMBDA', () => { - it('returns true', () => { - expect(isServerlessAgent(ServerlessType.AWS_LAMBDA)).toEqual(true); - }); - }); - - describe('when the serverlessType is AZURE_FUNCTIONS', () => { - it('returns true', () => { - expect(isServerlessAgent(ServerlessType.AZURE_FUNCTIONS)).toEqual(true); - }); - }); - - describe('when the serverlessType is undefined', () => { - it('returns false', () => { - expect(isServerlessAgent(undefined)).toEqual(false); - }); - }); - }); - - describe('isAWSLambdaAgent', () => { - describe('when the serverlessType is AWS_LAMBDA', () => { - it('returns true', () => { - expect(isAWSLambdaAgent(ServerlessType.AWS_LAMBDA)).toEqual(true); - }); - }); - - describe('when the serverlessType is AZURE_FUNCTIONS', () => { - it('returns true', () => { - expect(isAWSLambdaAgent(ServerlessType.AZURE_FUNCTIONS)).toEqual(false); - }); - }); - - describe('when the serverlessType is undefined', () => { - it('returns false', () => { - expect(isAWSLambdaAgent(undefined)).toEqual(false); - }); - }); - }); - - describe('isAzureFunctionsAgent', () => { - describe('when the serverlessType is AZURE_FUNCTIONS', () => { - it('returns true', () => { - expect(isAzureFunctionsAgent(ServerlessType.AZURE_FUNCTIONS)).toEqual( - true - ); - }); - }); - - describe('when the serverlessType is AWS_LAMBDA', () => { - it('returns true', () => { - expect(isAzureFunctionsAgent(ServerlessType.AWS_LAMBDA)).toEqual(false); - }); - }); - - describe('when the serverlessType is undefined', () => { - it('returns false', () => { - expect(isAzureFunctionsAgent(undefined)).toEqual(false); - }); - }); - }); -}); diff --git a/x-pack/plugins/apm/common/agent_name.ts b/x-pack/plugins/apm/common/agent_name.ts index 7782cc044e95..608fdf497535 100644 --- a/x-pack/plugins/apm/common/agent_name.ts +++ b/x-pack/plugins/apm/common/agent_name.ts @@ -4,110 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { - AgentName, - OpenTelemetryAgentName, -} from '../typings/es_schemas/ui/fields/agent'; -import { ServerlessType } from './serverless'; - -/* - * Agent names can be any string. This list only defines the official agents - * that we might want to target specifically eg. linking to their documentation - * & telemetry reporting. Support additional agent types by appending - * definitions in mappings.json (for telemetry), the AgentName type, and the - * AGENT_NAMES array. - */ - -export const OPEN_TELEMETRY_AGENT_NAMES: AgentName[] = [ - 'otlp', - 'opentelemetry/cpp', - 'opentelemetry/dotnet', - 'opentelemetry/erlang', - 'opentelemetry/go', - 'opentelemetry/java', - 'opentelemetry/nodejs', - 'opentelemetry/php', - 'opentelemetry/python', - 'opentelemetry/ruby', - 'opentelemetry/rust', - 'opentelemetry/swift', - 'opentelemetry/webjs', -]; - -export const AGENT_NAMES: AgentName[] = [ - 'dotnet', - 'go', - 'iOS/swift', - 'java', - 'js-base', - 'nodejs', - 'php', - 'python', - 'ruby', - 'rum-js', - 'android/java', - ...OPEN_TELEMETRY_AGENT_NAMES, -]; - -export function isOpenTelemetryAgentName( - agentName: string -): agentName is OpenTelemetryAgentName { - return OPEN_TELEMETRY_AGENT_NAMES.includes(agentName as AgentName); -} - -export const JAVA_AGENT_NAMES: AgentName[] = ['java', 'opentelemetry/java']; - -export function isJavaAgentName( - agentName?: string -): agentName is 'java' | 'opentelemetry/java' { - return JAVA_AGENT_NAMES.includes(agentName! as AgentName); -} - -export const RUM_AGENT_NAMES: AgentName[] = [ - 'js-base', - 'rum-js', - 'opentelemetry/webjs', -]; - -export function isRumAgentName( - agentName?: string -): agentName is 'js-base' | 'rum-js' | 'opentelemetry/webjs' { - return RUM_AGENT_NAMES.includes(agentName! as AgentName); -} - -export function isMobileAgentName(agentName?: string) { - return isIosAgentName(agentName) || isAndroidAgentName(agentName); -} - -export function isRumOrMobileAgent(agentName?: string) { - return isRumAgentName(agentName) || isMobileAgentName(agentName); -} - -export function isIosAgentName(agentName?: string) { - const lowercased = agentName && agentName.toLowerCase(); - return lowercased === 'ios/swift'; -} - -export function isJRubyAgent(agentName?: string, runtimeName?: string) { - return agentName === 'ruby' && runtimeName?.toLowerCase() === 'jruby'; -} - -export function isServerlessAgent(serverlessType?: ServerlessType) { - return ( - isAWSLambdaAgent(serverlessType) || isAzureFunctionsAgent(serverlessType) - ); -} - -export function isAWSLambdaAgent(serverlessType?: ServerlessType) { - return serverlessType === ServerlessType.AWS_LAMBDA; -} - -export function isAzureFunctionsAgent(serverlessType?: ServerlessType) { - return serverlessType === ServerlessType.AZURE_FUNCTIONS; -} - -export function isAndroidAgentName(agentName?: string) { - const lowercased = agentName && agentName.toLowerCase(); - return lowercased === 'android/java'; -} +export { + OPEN_TELEMETRY_AGENT_NAMES, + AGENT_NAMES, + isOpenTelemetryAgentName, + JAVA_AGENT_NAMES, + isJavaAgentName, + RUM_AGENT_NAMES, + isRumAgentName, + isRumOrMobileAgentName, + isMobileAgentName, + isIosAgentName, + isJRubyAgentName, + isServerlessAgentName, + isAWSLambdaAgentName, + isAzureFunctionsAgentName, + isAndroidAgentName, +} from '@kbn/elastic-agent-utils'; diff --git a/x-pack/plugins/apm/common/data_source.ts b/x-pack/plugins/apm/common/data_source.ts index f3450fe77542..93d826147369 100644 --- a/x-pack/plugins/apm/common/data_source.ts +++ b/x-pack/plugins/apm/common/data_source.ts @@ -14,7 +14,8 @@ type AnyApmDocumentType = | ApmDocumentType.TransactionEvent | ApmDocumentType.ServiceDestinationMetric | ApmDocumentType.ServiceSummaryMetric - | ApmDocumentType.ErrorEvent; + | ApmDocumentType.ErrorEvent + | ApmDocumentType.SpanEvent; export interface ApmDataSource< TDocumentType extends AnyApmDocumentType = AnyApmDocumentType diff --git a/x-pack/plugins/apm/common/data_view_constants.ts b/x-pack/plugins/apm/common/data_view_constants.ts index b448918f8fac..c50966399ad2 100644 --- a/x-pack/plugins/apm/common/data_view_constants.ts +++ b/x-pack/plugins/apm/common/data_view_constants.ts @@ -5,5 +5,11 @@ * 2.0. */ -// value of const needs to be backwards compatible -export const APM_STATIC_DATA_VIEW_ID = 'apm_static_index_pattern_id'; +export const DO_NOT_USE_LEGACY_APM_STATIC_DATA_VIEW_ID = + 'apm_static_index_pattern_id'; + +const APM_STATIC_DATA_VIEW_ID_PREFIX = 'apm_static_data_view_id'; + +export function getDataViewId(spaceId: string) { + return `${APM_STATIC_DATA_VIEW_ID_PREFIX}_${spaceId}`; +} diff --git a/x-pack/plugins/apm/common/document_type.ts b/x-pack/plugins/apm/common/document_type.ts index 92a17c3125a9..e8a29e8d08c4 100644 --- a/x-pack/plugins/apm/common/document_type.ts +++ b/x-pack/plugins/apm/common/document_type.ts @@ -12,6 +12,7 @@ export enum ApmDocumentType { ServiceDestinationMetric = 'serviceDestinationMetric', ServiceSummaryMetric = 'serviceSummaryMetric', ErrorEvent = 'error', + SpanEvent = 'span', } export type ApmServiceTransactionDocumentType = diff --git a/x-pack/plugins/apm/common/service_inventory.ts b/x-pack/plugins/apm/common/service_inventory.ts index b3eeb1cbf8fa..f758bc083cf7 100644 --- a/x-pack/plugins/apm/common/service_inventory.ts +++ b/x-pack/plugins/apm/common/service_inventory.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AgentName } from '../typings/es_schemas/ui/fields/agent'; +import { AgentName } from '@kbn/elastic-agent-utils'; import { ServiceHealthStatus } from './service_health_status'; export interface ServiceListItem { diff --git a/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.test.ts b/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.test.ts index cacc544a3afe..cfdc451790bc 100644 --- a/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.test.ts +++ b/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.test.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { getKueryWithMobileFilters } from './get_kuery_with_mobile_filters'; +import { + getKueryWithMobileFilters, + getKueryWithMobileCrashFilter, + getKueryWithMobileErrorFilter, +} from './get_kuery_with_mobile_filters'; describe('getKueryWithMobileFilters', () => { it('should handle empty and undefined values', () => { const result = getKueryWithMobileFilters({ @@ -70,3 +74,68 @@ describe('getKueryWithMobileFilters', () => { ); }); }); + +describe('getKueryWithMobileCrashFilter', () => { + it('should handle empty and undefined values', () => { + const result = getKueryWithMobileCrashFilter({ + groupId: undefined, + kuery: '', + }); + expect(result).toBe('error.type: crash'); + }); + it('should return kuery and crash filter when groupId is empty', () => { + const result = getKueryWithMobileCrashFilter({ + groupId: undefined, + kuery: 'foo.bar: test', + }); + expect(result).toBe('foo.bar: test and error.type: crash'); + }); + it('should return crash filter and groupId when kuery is empty', () => { + const result = getKueryWithMobileCrashFilter({ + groupId: '1', + kuery: '', + }); + expect(result).toBe('error.type: crash and error.grouping_key: 1'); + }); + it('should return crash filter, groupId, and kuery in kql format', () => { + const result = getKueryWithMobileCrashFilter({ + groupId: '1', + kuery: 'foo.bar: test', + }); + expect(result).toBe( + 'foo.bar: test and error.type: crash and error.grouping_key: 1' + ); + }); +}); +describe('getKueryWithMobileErrorFilter', () => { + it('should handle empty and undefined values', () => { + const result = getKueryWithMobileErrorFilter({ + groupId: undefined, + kuery: '', + }); + expect(result).toBe('NOT error.type: crash'); + }); + it('should return kuery and error filter when groupId is empty', () => { + const result = getKueryWithMobileErrorFilter({ + kuery: 'foo.bar: test', + groupId: undefined, + }); + expect(result).toBe('foo.bar: test and NOT error.type: crash'); + }); + it('should return error filter and groupId when kuery is empty', () => { + const result = getKueryWithMobileErrorFilter({ + groupId: '1', + kuery: '', + }); + expect(result).toBe('NOT error.type: crash and error.grouping_key: 1'); + }); + it('should return error filter, groupId, and kuery in kql format', () => { + const result = getKueryWithMobileErrorFilter({ + groupId: '1', + kuery: 'foo.bar: test', + }); + expect(result).toBe( + 'foo.bar: test and NOT error.type: crash and error.grouping_key: 1' + ); + }); +}); diff --git a/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.ts b/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.ts index 19970a0b24b9..2efaf1e2e858 100644 --- a/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.ts +++ b/x-pack/plugins/apm/common/utils/get_kuery_with_mobile_filters.ts @@ -10,6 +10,8 @@ import { DEVICE_MODEL_IDENTIFIER, NETWORK_CONNECTION_TYPE, SERVICE_VERSION, + ERROR_TYPE, + ERROR_GROUP_ID, } from '../es_fields/apm'; import { fieldValuePairToKql } from './field_value_pair_to_kql'; @@ -38,3 +40,37 @@ export function getKueryWithMobileFilters({ return kueryWithFilters; } + +export function getKueryWithMobileCrashFilter({ + groupId, + kuery, +}: { + groupId: string | undefined; + kuery: string; +}) { + const kueryWithFilters = [ + kuery, + ...fieldValuePairToKql(ERROR_TYPE, 'crash'), + ...fieldValuePairToKql(ERROR_GROUP_ID, groupId), + ] + .filter(Boolean) + .join(' and '); + return kueryWithFilters; +} + +export function getKueryWithMobileErrorFilter({ + groupId, + kuery, +}: { + groupId: string | undefined; + kuery: string; +}) { + const kueryWithFilters = [ + kuery, + `NOT ${ERROR_TYPE}: crash`, + ...fieldValuePairToKql(ERROR_GROUP_ID, groupId), + ] + .filter(Boolean) + .join(' and '); + return kueryWithFilters; +} diff --git a/x-pack/plugins/apm/common/utils/kuery_utils.test.ts b/x-pack/plugins/apm/common/utils/kuery_utils.test.ts new file mode 100644 index 000000000000..556a0f4968fd --- /dev/null +++ b/x-pack/plugins/apm/common/utils/kuery_utils.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { toKueryFilterFormat, mergeKueries } from './kuery_utils'; + +describe('toKueryFilterFormat', () => { + it('returns a single value', () => { + expect(toKueryFilterFormat('key', ['foo'])).toEqual(`key : "foo"`); + }); + + it('returns multiple values default separator', () => { + expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'])).toEqual( + `key : "foo" OR key : "bar" OR key : "baz"` + ); + }); + + it('returns multiple values custom separator', () => { + expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'], 'AND')).toEqual( + `key : "foo" AND key : "bar" AND key : "baz"` + ); + }); + + it('return empty string when no hostname', () => { + expect(toKueryFilterFormat('key', [])).toEqual(''); + }); + + describe('mergeKueries', () => { + it('returns empty string when both kueries are empty', () => { + expect(mergeKueries(['', ''])).toEqual(''); + }); + + it('returns only first kuery when second is empty', () => { + expect(mergeKueries(['host.name: "foo"', ''])).toEqual( + 'host.name: "foo"' + ); + }); + + it('returns second kuery when first is empty', () => { + expect(mergeKueries(['', 'host.name: "foo"'])).toEqual( + 'host.name: "foo"' + ); + }); + + it('returns merged kueries with default separator', () => { + expect( + mergeKueries([ + 'host.name: "foo" OR host.name: "bar"', + 'process.id: "1"', + ]) + ).toEqual('host.name: "foo" OR host.name: "bar" AND process.id: "1"'); + }); + + it('uses custom separator', () => { + expect( + mergeKueries(['host.name: "foo"', 'process.id: "1"'], 'OR') + ).toEqual('host.name: "foo" OR process.id: "1"'); + }); + }); +}); diff --git a/x-pack/plugins/apm/common/utils/kuery_utils.ts b/x-pack/plugins/apm/common/utils/kuery_utils.ts new file mode 100644 index 000000000000..1caf154a0d5f --- /dev/null +++ b/x-pack/plugins/apm/common/utils/kuery_utils.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isEmpty } from 'lodash'; + +type Separator = 'OR' | 'AND'; + +export const toKueryFilterFormat = ( + key: string, + values: string[], + separator: Separator = 'OR' +) => values.map((value) => `${key} : "${value}"`).join(` ${separator} `); + +export const mergeKueries = (filters: string[], separator: Separator = 'AND') => + filters.filter((filter) => !isEmpty(filter)).join(` ${separator} `); diff --git a/x-pack/plugins/apm/common/utils/to_kuery_filter_format.test.ts b/x-pack/plugins/apm/common/utils/to_kuery_filter_format.test.ts deleted file mode 100644 index 0a1e01d8404f..000000000000 --- a/x-pack/plugins/apm/common/utils/to_kuery_filter_format.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { toKueryFilterFormat } from './to_kuery_filter_format'; - -describe('toKueryFilterFormat', () => { - it('returns a single value', () => { - expect(toKueryFilterFormat('key', ['foo'])).toEqual(`key : "foo"`); - }); - - it('returns multiple values default separator', () => { - expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'])).toEqual( - `key : "foo" OR key : "bar" OR key : "baz"` - ); - }); - - it('returns multiple values custom separator', () => { - expect(toKueryFilterFormat('key', ['foo', 'bar', 'baz'], 'AND')).toEqual( - `key : "foo" AND key : "bar" AND key : "baz"` - ); - }); - - it('return empty string when no hostname', () => { - expect(toKueryFilterFormat('key', [])).toEqual(''); - }); -}); diff --git a/x-pack/plugins/apm/common/utils/to_kuery_filter_format.ts b/x-pack/plugins/apm/common/utils/to_kuery_filter_format.ts deleted file mode 100644 index 8e3169f4d07e..000000000000 --- a/x-pack/plugins/apm/common/utils/to_kuery_filter_format.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export function toKueryFilterFormat( - key: string, - values: string[], - separator: 'OR' | 'AND' = 'OR' -) { - return values.map((value) => `${key} : "${value}"`).join(` ${separator} `); -} diff --git a/x-pack/plugins/apm/dev_docs/telemetry.md b/x-pack/plugins/apm/dev_docs/telemetry.md index e11ea3bcdec3..89293aad75a1 100644 --- a/x-pack/plugins/apm/dev_docs/telemetry.md +++ b/x-pack/plugins/apm/dev_docs/telemetry.md @@ -7,7 +7,7 @@ two types of telemetry, which we'll refer to here as "Data Telemetry" and This document will explain how they are collected and how to make changes to them. -[The telemetry repository has information about accessing the clusters](https://github.com/elastic/telemetry#kibana-access). +[The telemetry repository has information about accessing the clusters](https://github.com/elastic/telemetry#i-just-want-to-see-the-data). Telemetry data is uploaded to the "xpack-phone-home" indices. ## Data Telemetry diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx index 91fa325f4ae7..f8b14acfb364 100644 --- a/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx @@ -19,7 +19,7 @@ import { import moment from 'moment'; import React, { useEffect, useMemo } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { getPaddedAlertTimeRange } from '@kbn/observability-alert-details'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { EuiCallOut } from '@elastic/eui'; import { SERVICE_ENVIRONMENT } from '../../../../../common/es_fields/apm'; import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; diff --git a/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx b/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx index d4776c8995c4..03fcd2610f23 100644 --- a/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx +++ b/x-pack/plugins/apm/public/components/app/diagnostics/apm_documents_tab.tsx @@ -13,20 +13,23 @@ import { EuiText, EuiToolTip, } from '@elastic/eui'; -import React, { useState, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { orderBy } from 'lodash'; -import { useApmParams } from '../../../hooks/use_apm_params'; +import React, { useMemo, useState } from 'react'; import { asBigNumber, asInteger } from '../../../../common/utils/formatters'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../common/data_view_constants'; import type { ApmEvent } from '../../../../server/routes/diagnostics/bundle/get_apm_events'; -import { useDiagnosticsContext } from './context/use_diagnostics'; +import { useApmParams } from '../../../hooks/use_apm_params'; +import { useDataViewId } from '../../../hooks/use_data_view_id'; import { ApmPluginStartDeps } from '../../../plugin'; import { SearchBar } from '../../shared/search_bar/search_bar'; +import { useDiagnosticsContext } from './context/use_diagnostics'; export function DiagnosticsApmDocuments() { const { diagnosticsBundle, isImported } = useDiagnosticsContext(); const { discover } = useKibana().services; + const dataViewId = useDataViewId(); + const [sortField, setSortField] = useState('name'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); const { @@ -103,7 +106,7 @@ export function DiagnosticsApmDocuments() { language: 'kuery', query: item.kuery, }, - dataViewId: APM_STATIC_DATA_VIEW_ID, + dataViewId, timeRange: rangeTo && rangeFrom ? { @@ -123,13 +126,37 @@ export function DiagnosticsApmDocuments() { {isImported && diagnosticsBundle ? ( <> - From: {new Date(diagnosticsBundle.params.start).toISOString()} + {i18n.translate( + 'xpack.apm.diagnosticsApmDocuments.from:BadgeLabel', + { + defaultMessage: 'From: {date}', + values: { + date: new Date(diagnosticsBundle.params.start).toISOString(), + }, + } + )} - To: {new Date(diagnosticsBundle.params.end).toISOString()} + {i18n.translate('xpack.apm.diagnosticsApmDocuments.to:BadgeLabel', { + defaultMessage: 'To: {date}', + values: { + date: new Date(diagnosticsBundle.params.end).toISOString(), + }, + })} - Filter: {diagnosticsBundle?.params.kuery ?? Empty} + {i18n.translate( + 'xpack.apm.diagnosticsApmDocuments.filter:BadgeLabel', + { defaultMessage: 'Filter:' } + )} + {diagnosticsBundle?.params.kuery ?? ( + + {i18n.translate( + 'xpack.apm.diagnosticsApmDocuments.em.emptyLabel', + { defaultMessage: 'Empty' } + )} + + )} @@ -183,7 +210,13 @@ function IntervalDocCount({ - ({asBigNumber(interval.eventDocCount)} events) + {i18n.translate('xpack.apm.intervalDocCount.TextLabel', { + defaultMessage: + '({docCount} {docCount, plural, one {event} other {events}})', + values: { + docCount: asBigNumber(interval.eventDocCount), + }, + })}
    diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_detail.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_detail.tsx index 574e9db2f507..d8f500f9fb78 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_detail.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_detail.tsx @@ -34,7 +34,7 @@ import { TraceSearchType } from '../../../../../common/trace_explorer'; import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params'; -import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useAnyOfApmParams } from '../../../../hooks/use_apm_params'; import { useApmRouter } from '../../../../hooks/use_apm_router'; import { FETCH_STATUS, isPending } from '../../../../hooks/use_fetcher'; import { useTraceExplorerEnabledSetting } from '../../../../hooks/use_trace_explorer_enabled_setting'; @@ -102,7 +102,11 @@ export function ErrorSampleDetails({ const { path: { groupId }, query, - } = useApmParams('/services/{serviceName}/errors/{groupId}'); + } = useAnyOfApmParams( + '/services/{serviceName}/errors/{groupId}', + '/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}', + '/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}' + ); const { kuery } = query; diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/index.tsx index e5b13aa0df21..48cd78e6705d 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/index.tsx @@ -8,7 +8,7 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; import { useHistory } from 'react-router-dom'; import { fromQuery, toQuery } from '../../../shared/links/url_helpers'; -import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useAnyOfApmParams } from '../../../../hooks/use_apm_params'; import { FETCH_STATUS, isPending, @@ -36,7 +36,11 @@ export function ErrorSampler({ const { path: { groupId }, query, - } = useApmParams('/services/{serviceName}/errors/{groupId}'); + } = useAnyOfApmParams( + '/services/{serviceName}/errors/{groupId}', + '/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}', + '/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}' + ); const { rangeFrom, rangeTo, environment, kuery, errorId } = query; diff --git a/x-pack/plugins/apm/public/components/app/metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/index.tsx index 5f290b4d4af8..0c70b6fd48d7 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/index.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { isJavaAgentName, - isJRubyAgent, - isAWSLambdaAgent, + isJRubyAgentName, + isAWSLambdaAgentName, } from '../../../../common/agent_name'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { ServerlessMetrics } from './serverless_metrics'; @@ -20,7 +20,7 @@ import { hasDashboardFile } from './static_dashboard/helper'; export function Metrics() { const { agentName, runtimeName, serverlessType } = useApmServiceContext(); - const isAWSLambda = isAWSLambdaAgent(serverlessType); + const isAWSLambda = isAWSLambdaAgentName(serverlessType); if (isAWSLambda) { return ; @@ -44,7 +44,7 @@ export function Metrics() { if ( !isAWSLambda && - (isJavaAgentName(agentName) || isJRubyAgent(agentName, runtimeName)) + (isJavaAgentName(agentName) || isJRubyAgentName(agentName, runtimeName)) ) { return ; } diff --git a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts index a6d22ea7b6a5..780e4387b0e1 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts +++ b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/helper.ts @@ -6,7 +6,6 @@ */ import type { DashboardPanelMap } from '@kbn/dashboard-plugin/common'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../../common/data_view_constants'; import { AGENT_NAME_DASHBOARD_FILE_MAPPING, loadDashboardFile, @@ -29,7 +28,8 @@ function getDashboardFile({ agentName }: MetricsDashboardProps) { } export async function getDashboardPanelMap( - props: MetricsDashboardProps + props: MetricsDashboardProps, + dataViewId: string ): Promise { const dashboardFile = getDashboardFile(props); const panelsRawObj = !!dashboardFile @@ -42,7 +42,7 @@ export async function getDashboardPanelMap( const panelsStr: string = ( panelsRawObj.attributes.panelsJSON as string - ).replaceAll('APM_STATIC_DATA_VIEW_ID', APM_STATIC_DATA_VIEW_ID); + ).replaceAll('APM_STATIC_DATA_VIEW_ID', dataViewId); const panelsRawObjects = JSON.parse(panelsStr) as any[]; diff --git a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx index 50bda742eb37..29ebf34cca44 100644 --- a/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics/static_dashboard/index.tsx @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { controlGroupInputBuilder } from '@kbn/controls-plugin/public'; import { getDefaultControlGroupInput } from '@kbn/controls-plugin/common'; import { NotificationsStart } from '@kbn/core/public'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../../common/data_view_constants'; +import { useDataViewId } from '../../../../hooks/use_data_view_id'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, @@ -28,11 +28,11 @@ import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plug import { useApmDataView } from '../../../../hooks/use_apm_data_view'; import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; import { useApmParams } from '../../../../hooks/use_apm_params'; - import { getDashboardPanelMap, MetricsDashboardProps } from './helper'; export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { const [dashboard, setDashboard] = useState(); + const dataViewId = useDataViewId(); const { query: { environment, kuery, rangeFrom, rangeTo }, @@ -65,7 +65,7 @@ export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { return ( - getCreationOptions(dashboardProps, notifications) + getCreationOptions(dashboardProps, notifications, dataViewId) } ref={setDashboard} /> @@ -74,20 +74,21 @@ export function JsonMetricsDashboard(dashboardProps: MetricsDashboardProps) { async function getCreationOptions( dashboardProps: MetricsDashboardProps, - notifications: NotificationsStart + notifications: NotificationsStart, + dataViewId: string ): Promise { try { const builder = controlGroupInputBuilder; const controlGroupInput = getDefaultControlGroupInput(); await builder.addDataControlFromField(controlGroupInput, { - dataViewId: APM_STATIC_DATA_VIEW_ID, + dataViewId, title: 'Node name', fieldName: 'service.node.name', width: 'medium', grow: true, }); - const panels = await getDashboardPanelMap(dashboardProps); + const panels = await getDashboardPanelMap(dashboardProps, dataViewId); if (!panels) { throw new Error('Failed parsing dashboard panels.'); diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx index ffcba4d83897..99d3d8830ceb 100644 --- a/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics_details/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { isAWSLambdaAgent } from '../../../../common/agent_name'; +import { isAWSLambdaAgentName } from '../../../../common/agent_name'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { useApmParams } from '../../../hooks/use_apm_params'; import { ServerlessMetricsDetails } from './serverless_metrics_details'; @@ -17,7 +17,7 @@ export function MetricsDetails() { } = useApmParams('/services/{serviceName}/metrics/{id}'); const { serverlessType } = useApmServiceContext(); - if (isAWSLambdaAgent(serverlessType)) { + if (isAWSLambdaAgentName(serverlessType)) { return ; } diff --git a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx index 28865a8ad5f1..46f5045dc43e 100644 --- a/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/metrics_details/service_node_metrics/index.tsx @@ -22,6 +22,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import React from 'react'; +import { ApmDocumentType } from '../../../../../common/document_type'; import { getServiceNodeName, SERVICE_NODE_NAME_MISSING, @@ -33,6 +34,7 @@ import { ChartPointerEventContextProvider } from '../../../../context/chart_poin import { useApmParams } from '../../../../hooks/use_apm_params'; import { useApmRouter } from '../../../../hooks/use_apm_router'; import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { usePreferredDataSourceAndBucketSize } from '../../../../hooks/use_preferred_data_source_and_bucket_size'; import { useServiceMetricChartsFetcher } from '../../../../hooks/use_service_metric_charts_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { truncate, unit } from '../../../../utils/style'; @@ -83,9 +85,17 @@ export function ServiceNodeMetrics({ serviceNodeName }: Props) { environment, }); + const preferred = usePreferredDataSourceAndBucketSize({ + start, + end, + kuery, + type: ApmDocumentType.ServiceTransactionMetric, + numBuckets: 100, + }); + const { data: { host, containerId } = INITIAL_DATA, status } = useFetcher( (callApmApi) => { - if (start && end) { + if (start && end && preferred) { return callApmApi( 'GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata', { @@ -96,13 +106,15 @@ export function ServiceNodeMetrics({ serviceNodeName }: Props) { start, end, environment, + documentType: preferred.source.documentType, + rollupInterval: preferred.source.rollupInterval, }, }, } ); } }, - [kuery, serviceName, serviceNodeName, start, end, environment] + [kuery, serviceName, serviceNodeName, start, end, environment, preferred] ); const { docLinks } = useApmPluginContext().core; diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/index.tsx new file mode 100644 index 000000000000..a30495b703eb --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/index.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { TreemapSelect, TreemapTypes } from './treemap_select'; +import { TreemapChart } from '../../../../shared/charts/treemap_chart'; +import { useFetcher } from '../../../../../hooks/use_fetcher'; +import { + DEVICE_MODEL_IDENTIFIER, + SERVICE_VERSION, +} from '../../../../../../common/es_fields/apm'; + +const ES_FIELD_MAPPING: Record = { + [TreemapTypes.Devices]: DEVICE_MODEL_IDENTIFIER, + [TreemapTypes.Versions]: SERVICE_VERSION, +}; + +export function MobileErrorsAndCrashesTreemap({ + kuery, + serviceName, + start, + end, + environment, +}: { + kuery: string; + serviceName: string; + start: string; + end: string; + environment: string; +}) { + const [selectedTreemap, selectTreemap] = useState(TreemapTypes.Devices); + + const { data, status } = useFetcher( + (callApmApi) => { + const fieldName = ES_FIELD_MAPPING[selectedTreemap]; + if (fieldName) { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/error_terms', + { + params: { + path: { + serviceName, + }, + query: { + environment, + kuery, + start, + end, + fieldName, + size: 500, + }, + }, + } + ); + } + }, + [environment, kuery, serviceName, start, end, selectedTreemap] + ); + return ( + <> + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/treemap_select.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/treemap_select.tsx new file mode 100644 index 000000000000..498e0ef8fda7 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_errors_and_crashes_treemap/treemap_select.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiSuperSelect, + EuiText, +} from '@elastic/eui'; +import type { EuiSuperSelectOption } from '@elastic/eui'; + +export enum TreemapTypes { + Devices = 'devices', + Versions = 'versions', +} + +const options: Array> = [ + { + value: TreemapTypes.Devices, + label: i18n.translate( + 'xpack.apm.transactionOverview.treemap.dropdown.devices', + { + defaultMessage: 'Devices', + } + ), + description: i18n.translate( + 'xpack.apm.errorOverview.treemap.dropdown.devices.subtitle', + { + defaultMessage: + 'This treemap view allows for easy and faster visual way the most affected devices', + } + ), + }, + { + value: TreemapTypes.Versions, + label: i18n.translate( + 'xpack.apm.transactionOverview.treemap.versions.devices', + { + defaultMessage: 'Versions', + } + ), + description: i18n.translate( + 'xpack.apm.errorOverview.treemap.dropdown.versions.subtitle', + { + defaultMessage: + 'This treemap view allows for easy and faster visual way the most affected versions.', + } + ), + }, +].map(({ value, label, description }) => ({ + inputDisplay: label, + value, + dropdownDisplay: ( + <> + {label} + +

    {description}

    +
    + + ), +})); + +export function TreemapSelect({ + selectedTreemap, + onChange, +}: { + selectedTreemap: TreemapTypes; + onChange: (value: TreemapTypes) => void; +}) { + const currentTreemap = + options.find(({ value }) => value === selectedTreemap) ?? options[0]; + + return ( + + + +

    + {i18n.translate('xpack.apm.errorOverview.treemap.title', { + defaultMessage: 'Most affected {currentTreemap}', + values: { currentTreemap: currentTreemap.value }, + })} +

    +
    + + {i18n.translate('xpack.apm.errorOverview.treemap.subtitle', { + defaultMessage: + 'Treemap showing the total and most affected {currentTreemap}', + values: { currentTreemap: currentTreemap.value }, + })} + +
    + + + + + {i18n.translate('xpack.apm.transactionOverview.treemap.show', { + defaultMessage: 'Show', + })} + + + + + + +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_http_error_rate/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_http_error_rate/index.tsx new file mode 100644 index 000000000000..f26fe41a0eca --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_http_error_rate/index.tsx @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiPanel, + EuiTitle, + EuiIconTip, + EuiFlexItem, + EuiFlexGroup, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { getComparisonChartTheme } from '../../../../shared/time_comparison/get_comparison_chart_theme'; +import { TimeseriesChartWithContext } from '../../../../shared/charts/timeseries_chart_with_context'; + +import { useFetcher } from '../../../../../hooks/use_fetcher'; + +import { + ChartType, + getTimeSeriesColor, +} from '../../../../shared/charts/helper/get_timeseries_color'; +import { usePreviousPeriodLabel } from '../../../../../hooks/use_previous_period_text'; + +const INITIAL_STATE = { + currentPeriod: { timeseries: [] }, + previousPeriod: { timeseries: [] }, +}; + +export function HttpErrorRateChart({ + height, + kuery, + serviceName, + start, + end, + environment, + offset, + comparisonEnabled, +}: { + height: number; + kuery: string; + serviceName: string; + start: string; + end: string; + environment: string; + offset?: string; + comparisonEnabled: boolean; +}) { + const comparisonChartTheme = getComparisonChartTheme(); + const { currentPeriodColor, previousPeriodColor } = getTimeSeriesColor( + ChartType.HTTP_REQUESTS + ); + const { data = INITIAL_STATE, status } = useFetcher( + (callApmApi) => { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/error/http_error_rate', + { + params: { + path: { + serviceName, + }, + query: { + environment, + kuery, + start, + end, + offset: comparisonEnabled ? offset : undefined, + }, + }, + } + ); + }, + [environment, kuery, serviceName, start, end, offset, comparisonEnabled] + ); + + const previousPeriodLabel = usePreviousPeriodLabel(); + + const timeseries = [ + { + data: data.currentPeriod.timeseries, + type: 'linemark', + color: currentPeriodColor, + title: i18n.translate('xpack.apm.errors.httpErrorRateTitle', { + defaultMessage: 'HTTP error rate', + }), + }, + ...(comparisonEnabled + ? [ + { + data: data.previousPeriod.timeseries, + type: 'area', + color: previousPeriodColor, + title: previousPeriodLabel, + }, + ] + : []), + ]; + + return ( + + + + +

    + {i18n.translate('xpack.apm.mobile.errors.httpErrorRate', { + defaultMessage: 'HTTP Error Rate', + })} +

    +
    +
    + + + +
    + + `${y}`} + /> +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/index.tsx new file mode 100644 index 000000000000..8f53f84c19b0 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/index.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { TreemapSelect, TreemapTypes } from './treemap_select'; +import { TreemapChart } from '../../../../shared/charts/treemap_chart'; +import { useFetcher } from '../../../../../hooks/use_fetcher'; +import { + DEVICE_MODEL_IDENTIFIER, + HOST_OS_VERSION, + SERVICE_VERSION, +} from '../../../../../../common/es_fields/apm'; + +const ES_FIELD_MAPPING: Record = { + [TreemapTypes.Devices]: DEVICE_MODEL_IDENTIFIER, + [TreemapTypes.AppVersions]: SERVICE_VERSION, + [TreemapTypes.OsVersions]: HOST_OS_VERSION, +}; + +export function MobileTreemap({ + kuery, + serviceName, + start, + end, + environment, +}: { + kuery: string; + serviceName: string; + start: string; + end: string; + environment: string; +}) { + const [selectedTreemap, selectTreemap] = useState(TreemapTypes.Devices); + + const { data, status } = useFetcher( + (callApmApi) => { + const fieldName = ES_FIELD_MAPPING[selectedTreemap]; + if (fieldName) { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/terms', + { + params: { + path: { + serviceName, + }, + query: { + environment, + kuery, + start, + end, + fieldName, + size: 500, + }, + }, + } + ); + } + }, + [environment, kuery, serviceName, start, end, selectedTreemap] + ); + return ( + <> + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/treemap_select.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/treemap_select.tsx new file mode 100644 index 000000000000..b166c81b7ee1 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_most_affected/treemap_select.tsx @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiSuperSelect, + EuiText, +} from '@elastic/eui'; +import type { EuiSuperSelectOption } from '@elastic/eui'; + +export enum TreemapTypes { + OsVersions = 'osVersions', + AppVersions = 'appVersions', + Devices = 'devices', +} + +const options: Array> = [ + { + value: TreemapTypes.Devices, + label: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.dropdown.devices', + { + defaultMessage: 'Devices', + } + ), + description: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.dropdown.devices.subtitle', + { + defaultMessage: 'Treemap displaying the most affected devices.', + } + ), + }, + { + value: TreemapTypes.AppVersions, + label: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.versions.devices', + { + defaultMessage: 'App versions', + } + ), + description: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.dropdown.versions.subtitle', + { + defaultMessage: + 'Treemap displaying the most affected application versions.', + } + ), + }, + { + value: TreemapTypes.OsVersions, + label: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.dropdown.osVersions', + { + defaultMessage: 'OS versions', + } + ), + description: i18n.translate( + 'xpack.apm.mobile.errorOverview.treemap.dropdown.osVersions.subtitle', + { + defaultMessage: 'Treemap displaying the most affected OS versions.', + } + ), + }, +].map(({ value, label, description }) => ({ + inputDisplay: label, + value, + dropdownDisplay: ( + <> + {label} + +

    {description}

    +
    + + ), +})); + +export function TreemapSelect({ + selectedTreemap, + onChange, +}: { + selectedTreemap: TreemapTypes; + onChange: (value: TreemapTypes) => void; +}) { + const currentTreemap = + options.find(({ value }) => value === selectedTreemap) ?? options[0]; + + return ( + + + +

    + {i18n.translate('xpack.apm.errorsOverview.treemap.title', { + defaultMessage: 'Most affected {currentTreemap}', + values: { currentTreemap: currentTreemap.value }, + })} +

    +
    +
    + + + + + + +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_treemap/treemap_select.tsx b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_treemap/treemap_select.tsx index 6f86b5a83c30..281ea1b2c2b9 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_treemap/treemap_select.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/charts/mobile_treemap/treemap_select.tsx @@ -26,7 +26,7 @@ const options: Array> = [ label: i18n.translate( 'xpack.apm.transactionOverview.treemap.dropdown.devices', { - defaultMessage: 'Devices treemap', + defaultMessage: 'Devices', } ), description: i18n.translate( @@ -42,7 +42,7 @@ const options: Array> = [ label: i18n.translate( 'xpack.apm.transactionOverview.treemap.versions.devices', { - defaultMessage: 'Versions treemap', + defaultMessage: 'Versions', } ), description: i18n.translate( diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/crash_group_details/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/crash_group_details/index.tsx new file mode 100644 index 000000000000..4c80fe922973 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/crash_group_details/index.tsx @@ -0,0 +1,274 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useEffect } from 'react'; +import { omit } from 'lodash'; +import { useHistory } from 'react-router-dom'; +import { NOT_AVAILABLE_LABEL } from '../../../../../../common/i18n'; +import { useApmServiceContext } from '../../../../../context/apm_service/use_apm_service_context'; +import { useBreadcrumb } from '../../../../../context/breadcrumbs/use_breadcrumb'; +import { useApmParams } from '../../../../../hooks/use_apm_params'; +import { useApmRouter } from '../../../../../hooks/use_apm_router'; +import { useCrashGroupDistributionFetcher } from '../../../../../hooks/use_crash_group_distribution_fetcher'; +import { FETCH_STATUS, useFetcher } from '../../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../../hooks/use_time_range'; +import type { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; +import { ErrorSampler } from '../../../error_group_details/error_sampler'; +import { ErrorDistribution } from '../shared/distribution'; +import { ChartPointerEventContextProvider } from '../../../../../context/chart_pointer_event/chart_pointer_event_context'; +import { MobileErrorsAndCrashesTreemap } from '../../charts/mobile_errors_and_crashes_treemap'; +import { maybe } from '../../../../../../common/utils/maybe'; +import { fromQuery, toQuery } from '../../../../shared/links/url_helpers'; +import { + getKueryWithMobileCrashFilter, + getKueryWithMobileFilters, +} from '../../../../../../common/utils/get_kuery_with_mobile_filters'; + +type ErrorSamplesAPIResponse = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples'>; + +const emptyErrorSamples: ErrorSamplesAPIResponse = { + errorSampleIds: [], + occurrencesCount: 0, +}; + +function getShortGroupId(errorGroupId?: string) { + if (!errorGroupId) { + return NOT_AVAILABLE_LABEL; + } + + return errorGroupId.slice(0, 5); +} + +function CrashGroupHeader({ + groupId, + occurrencesCount, +}: { + groupId: string; + occurrencesCount?: number; +}) { + return ( + + + +

    + {i18n.translate('xpack.apm.CrashGroupDetails.CrashGroupTitle', { + defaultMessage: 'Crash group {errorGroupId}', + values: { + errorGroupId: getShortGroupId(groupId), + }, + })} +

    +
    +
    + + + {i18n.translate('xpack.apm.errorGroupDetails.occurrencesLabel', { + defaultMessage: '{occurrencesCount} occ', + values: { occurrencesCount }, + })} + + +
    + ); +} + +export function CrashGroupDetails() { + const { serviceName } = useApmServiceContext(); + + const apmRouter = useApmRouter(); + const history = useHistory(); + + const { + path: { groupId }, + query: { + rangeFrom, + rangeTo, + environment, + kuery, + serviceGroup, + comparisonEnabled, + errorId, + device, + osVersion, + appVersion, + netConnectionType, + }, + } = useApmParams( + '/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}' + ); + + const kueryWithMobileFilters = getKueryWithMobileFilters({ + device, + osVersion, + appVersion, + netConnectionType, + kuery, + }); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + useBreadcrumb( + () => ({ + title: groupId, + href: apmRouter.link( + '/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}', + { + path: { + serviceName, + groupId, + }, + query: { + rangeFrom, + rangeTo, + environment, + kuery: kueryWithMobileFilters, + serviceGroup, + comparisonEnabled, + }, + } + ), + }), + [ + apmRouter, + comparisonEnabled, + environment, + groupId, + kueryWithMobileFilters, + rangeFrom, + rangeTo, + serviceGroup, + serviceName, + ] + ); + + const kueryForTreemap = getKueryWithMobileCrashFilter({ + kuery: kueryWithMobileFilters, + groupId, + }); + + const { + data: errorSamplesData = emptyErrorSamples, + status: errorSamplesFetchStatus, + } = useFetcher( + (callApmApi) => { + if (start && end) { + return callApmApi( + 'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples', + { + params: { + path: { + serviceName, + groupId, + }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + }, + }, + } + ); + } + }, + [environment, kueryWithMobileFilters, serviceName, start, end, groupId] + ); + + const { crashDistributionData, status: crashDistributionStatus } = + useCrashGroupDistributionFetcher({ + serviceName, + groupId, + environment, + kuery: kueryWithMobileFilters, + }); + + useEffect(() => { + const selectedSample = errorSamplesData?.errorSampleIds.find( + (sample) => sample === errorId + ); + + if (errorSamplesFetchStatus === FETCH_STATUS.SUCCESS && !selectedSample) { + // selected sample was not found. select a new one: + const selectedErrorId = maybe(errorSamplesData?.errorSampleIds[0]); + + history.replace({ + ...history.location, + search: fromQuery({ + ...omit(toQuery(history.location.search), ['errorId']), + errorId: selectedErrorId, + }), + }); + } + }, [history, errorId, errorSamplesData, errorSamplesFetchStatus]); + + // If there are 0 occurrences, show only charts w. empty message + const showDetails = errorSamplesData.occurrencesCount !== 0; + + return ( + <> + + + + + + + + + + + + + + + + + + + + + {showDetails && ( + + )} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/error_group_details/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/error_group_details/index.tsx new file mode 100644 index 000000000000..eb71f5c04ea3 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/error_group_details/index.tsx @@ -0,0 +1,275 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useEffect } from 'react'; +import { omit } from 'lodash'; +import { useHistory } from 'react-router-dom'; +import { NOT_AVAILABLE_LABEL } from '../../../../../../common/i18n'; +import { useApmServiceContext } from '../../../../../context/apm_service/use_apm_service_context'; +import { useBreadcrumb } from '../../../../../context/breadcrumbs/use_breadcrumb'; +import { useApmParams } from '../../../../../hooks/use_apm_params'; +import { useApmRouter } from '../../../../../hooks/use_apm_router'; +import { useErrorGroupDistributionFetcher } from '../../../../../hooks/use_error_group_distribution_fetcher'; +import { FETCH_STATUS, useFetcher } from '../../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../../hooks/use_time_range'; +import type { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; +import { ErrorSampler } from '../../../error_group_details/error_sampler'; +import { ErrorDistribution } from '../shared/distribution'; +import { ChartPointerEventContextProvider } from '../../../../../context/chart_pointer_event/chart_pointer_event_context'; +import { MobileErrorsAndCrashesTreemap } from '../../charts/mobile_errors_and_crashes_treemap'; +import { maybe } from '../../../../../../common/utils/maybe'; +import { fromQuery, toQuery } from '../../../../shared/links/url_helpers'; +import { + getKueryWithMobileFilters, + getKueryWithMobileErrorFilter, +} from '../../../../../../common/utils/get_kuery_with_mobile_filters'; + +type ErrorSamplesAPIResponse = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples'>; + +const emptyErrorSamples: ErrorSamplesAPIResponse = { + errorSampleIds: [], + occurrencesCount: 0, +}; + +function getShortGroupId(errorGroupId?: string) { + if (!errorGroupId) { + return NOT_AVAILABLE_LABEL; + } + + return errorGroupId.slice(0, 5); +} + +function ErrorGroupHeader({ + groupId, + occurrencesCount, +}: { + groupId: string; + occurrencesCount?: number; +}) { + return ( + + + +

    + {i18n.translate('xpack.apm.errorGroupDetails.errorGroupTitle', { + defaultMessage: 'Error group {errorGroupId}', + values: { + errorGroupId: getShortGroupId(groupId), + }, + })} +

    +
    +
    + + + {i18n.translate('xpack.apm.errorGroupDetails.occurrencesLabel', { + defaultMessage: '{occurrencesCount} occ', + values: { occurrencesCount }, + })} + + +
    + ); +} + +export function ErrorGroupDetails() { + const { serviceName } = useApmServiceContext(); + + const apmRouter = useApmRouter(); + const history = useHistory(); + + const { + path: { groupId }, + query: { + rangeFrom, + rangeTo, + environment, + kuery, + serviceGroup, + comparisonEnabled, + errorId, + device, + osVersion, + appVersion, + netConnectionType, + }, + } = useApmParams( + '/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}' + ); + const kueryWithMobileFilters = getKueryWithMobileFilters({ + device, + osVersion, + appVersion, + netConnectionType, + kuery, + }); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + useBreadcrumb( + () => ({ + title: groupId, + href: apmRouter.link( + '/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}', + { + path: { + serviceName, + groupId, + }, + query: { + rangeFrom, + rangeTo, + environment, + kuery: kueryWithMobileFilters, + serviceGroup, + comparisonEnabled, + }, + } + ), + }), + [ + apmRouter, + comparisonEnabled, + environment, + groupId, + kueryWithMobileFilters, + rangeFrom, + rangeTo, + serviceGroup, + serviceName, + ] + ); + + const { + data: errorSamplesData = emptyErrorSamples, + status: errorSamplesFetchStatus, + } = useFetcher( + (callApmApi) => { + if (start && end) { + return callApmApi( + 'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples', + { + params: { + path: { + serviceName, + groupId, + }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + }, + }, + } + ); + } + }, + [environment, kueryWithMobileFilters, serviceName, start, end, groupId] + ); + + const { errorDistributionData, status: errorDistributionStatus } = + useErrorGroupDistributionFetcher({ + serviceName, + groupId, + environment, + kuery: kueryWithMobileFilters, + }); + + useEffect(() => { + const selectedSample = errorSamplesData?.errorSampleIds.find( + (sample) => sample === errorId + ); + + if (errorSamplesFetchStatus === FETCH_STATUS.SUCCESS && !selectedSample) { + // selected sample was not found. select a new one: + const selectedErrorId = maybe(errorSamplesData?.errorSampleIds[0]); + + history.replace({ + ...history.location, + search: fromQuery({ + ...omit(toQuery(history.location.search), ['errorId']), + errorId: selectedErrorId, + }), + }); + } + }, [history, errorId, errorSamplesData, errorSamplesFetchStatus]); + + // If there are 0 occurrences, show only charts w. empty message + const showDetails = errorSamplesData.occurrencesCount !== 0; + + const kueryForTreemap = getKueryWithMobileErrorFilter({ + groupId, + kuery: kueryWithMobileFilters, + }); + + return ( + <> + + + + + + + + + + + + + + + + + + + + + {showDetails && ( + + )} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.stories.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.stories.tsx new file mode 100644 index 000000000000..1fd2b4e7522b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.stories.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ComponentType } from 'react'; +import { ErrorDistribution } from '.'; +import { MockApmPluginStorybook } from '../../../../../../context/apm_plugin/mock_apm_plugin_storybook'; +import { FETCH_STATUS } from '../../../../../../hooks/use_fetcher'; + +export default { + title: 'app/ErrorGroupDetails/distribution', + component: ErrorDistribution, + decorators: [ + (Story: ComponentType) => { + return ( + + + + ); + }, + ], +}; + +export function Example() { + const distribution = { + bucketSize: 62350, + currentPeriod: [ + { x: 1624279912350, y: 6 }, + { x: 1624279974700, y: 1 }, + { x: 1624280037050, y: 2 }, + { x: 1624280099400, y: 3 }, + { x: 1624280161750, y: 13 }, + { x: 1624280224100, y: 1 }, + { x: 1624280286450, y: 2 }, + { x: 1624280348800, y: 0 }, + { x: 1624280411150, y: 4 }, + { x: 1624280473500, y: 4 }, + { x: 1624280535850, y: 1 }, + { x: 1624280598200, y: 4 }, + { x: 1624280660550, y: 0 }, + { x: 1624280722900, y: 2 }, + { x: 1624280785250, y: 3 }, + { x: 1624280847600, y: 0 }, + ], + previousPeriod: [ + { x: 1624279912350, y: 6 }, + { x: 1624279974700, y: 1 }, + { x: 1624280037050, y: 2 }, + { x: 1624280099400, y: 3 }, + { x: 1624280161750, y: 13 }, + { x: 1624280224100, y: 1 }, + { x: 1624280286450, y: 2 }, + { x: 1624280348800, y: 0 }, + { x: 1624280411150, y: 4 }, + { x: 1624280473500, y: 4 }, + { x: 1624280535850, y: 1 }, + { x: 1624280598200, y: 4 }, + { x: 1624280660550, y: 0 }, + { x: 1624280722900, y: 2 }, + { x: 1624280785250, y: 3 }, + { x: 1624280847600, y: 0 }, + ], + }; + + return ( + + ); +} + +export function EmptyState() { + return ( + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.tsx new file mode 100644 index 000000000000..78e39d3f2f8f --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_group_details/shared/distribution/index.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiTitle, EuiIconTip, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import React from 'react'; +import { TimeseriesChartWithContext } from '../../../../../shared/charts/timeseries_chart_with_context'; +import { useLegacyUrlParams } from '../../../../../../context/url_params_context/use_url_params'; +import { FETCH_STATUS } from '../../../../../../hooks/use_fetcher'; +import { usePreviousPeriodLabel } from '../../../../../../hooks/use_previous_period_text'; +import { APIReturnType } from '../../../../../../services/rest/create_call_apm_api'; +import { getComparisonChartTheme } from '../../../../../shared/time_comparison/get_comparison_chart_theme'; + +import { + ChartType, + getTimeSeriesColor, +} from '../../../../../shared/charts/helper/get_timeseries_color'; + +type ErrorDistributionAPIResponse = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/distribution'>; + +interface Props { + fetchStatus: FETCH_STATUS; + distribution?: ErrorDistributionAPIResponse; + title: string; + tip: string; + height: number; +} + +export function ErrorDistribution({ + distribution, + title, + tip, + height, + fetchStatus, +}: Props) { + const { urlParams } = useLegacyUrlParams(); + const { comparisonEnabled } = urlParams; + + const previousPeriodLabel = usePreviousPeriodLabel(); + const { currentPeriodColor, previousPeriodColor } = getTimeSeriesColor( + ChartType.ERROR_OCCURRENCES + ); + const timeseries = [ + { + data: distribution?.currentPeriod ?? [], + type: 'linemark', + color: currentPeriodColor, + title, + }, + ...(comparisonEnabled + ? [ + { + data: distribution?.previousPeriod ?? [], + type: 'area', + color: previousPeriodColor, + title: previousPeriodLabel, + }, + ] + : []), + ]; + + const comparisonChartTheme = getComparisonChartTheme(); + + return ( + <> + + + +

    {title}

    +
    +
    + + + +
    + + `${value}`} + timeseries={timeseries} + customTheme={comparisonChartTheme} + /> + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.stories.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.stories.tsx new file mode 100644 index 000000000000..993d291a7e4c --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.stories.tsx @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Meta, Story } from '@storybook/react'; +import React, { ComponentProps } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { MockApmPluginContextWrapper } from '../../../../../context/apm_plugin/mock_apm_plugin_context'; +import { MockUrlParamsContextProvider } from '../../../../../context/url_params_context/mock_url_params_context_provider'; + +import { MobileCrashGroupList } from '.'; + +type Args = ComponentProps; + +const stories: Meta = { + title: 'app/CrashGroupOverview/MobileCrashGroupList', + component: MobileCrashGroupList, + decorators: [ + (StoryComponent) => { + return ( + + + + + + + + ); + }, + ], +}; +export default stories; + +export const Example: Story = (args) => { + return ; +}; +Example.args = { + mainStatistics: [ + { + name: 'net/http: abort Handler', + occurrences: 14, + culprit: 'Main.func2', + groupId: '83a653297ec29afed264d7b60d5cda7b', + lastSeen: 1634833121434, + handled: false, + type: 'errorString', + }, + { + name: 'POST /api/orders (500)', + occurrences: 5, + culprit: 'logrusMiddleware', + groupId: '7a640436a9be648fd708703d1ac84650', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.2.24:3000->10.36.1.14:34232: write: connection reset by peer', + occurrences: 4, + culprit: 'apiHandlers.getProductCustomers', + groupId: '95ca0e312c109aa11e298bcf07f1445b', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.0.21:3000->10.36.1.252:57070: write: connection reset by peer', + occurrences: 3, + culprit: 'apiHandlers.getCustomers', + groupId: '4053d7e33d2b716c819bd96d9d6121a2', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.0.21:3000->10.36.0.88:33926: write: broken pipe', + occurrences: 2, + culprit: 'apiHandlers.getOrders', + groupId: '94f4ca8ec8c02e5318cf03f46ae4c1f3', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + ], + serviceName: 'test service', +}; + +export const EmptyState: Story = (args) => { + return ; +}; +EmptyState.args = { + mainStatistics: [], + serviceName: 'test service', +}; diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.test.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.test.tsx new file mode 100644 index 000000000000..cd1d4110e32f --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/crash_group_list.test.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render } from '@testing-library/react'; +import React from 'react'; +import * as stories from './crash_group_list.stories'; + +const { Example } = composeStories(stories); + +describe('MobileCrashGroupList', () => { + it('renders', () => { + expect(() => render()).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/index.tsx new file mode 100644 index 000000000000..2010225591fd --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crash_group_list/index.tsx @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiToolTip, RIGHT_ALIGNMENT, LEFT_ALIGNMENT } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import React, { useMemo } from 'react'; +import { NOT_AVAILABLE_LABEL } from '../../../../../../common/i18n'; +import { asInteger } from '../../../../../../common/utils/formatters'; +import { useApmParams } from '../../../../../hooks/use_apm_params'; +import { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; +import { truncate } from '../../../../../utils/style'; +import { + ChartType, + getTimeSeriesColor, +} from '../../../../shared/charts/helper/get_timeseries_color'; +import { SparkPlot } from '../../../../shared/charts/spark_plot'; +import { CrashDetailLink } from '../../../../shared/links/apm/mobile/crash_detail_link'; +import { ErrorOverviewLink } from '../../../../shared/links/apm/mobile/error_overview_link'; +import { ITableColumn, ManagedTable } from '../../../../shared/managed_table'; +import { TimestampTooltip } from '../../../../shared/timestamp_tooltip'; +import { isTimeComparison } from '../../../../shared/time_comparison/get_comparison_options'; + +const MessageAndCulpritCell = euiStyled.div` + ${truncate('100%')}; +`; + +const ErrorLink = euiStyled(ErrorOverviewLink)` + ${truncate('100%')}; +`; + +type ErrorGroupItem = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics'>['errorGroups'][0]; +type ErrorGroupDetailedStatistics = + APIReturnType<'POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics'>; + +interface Props { + mainStatistics: ErrorGroupItem[]; + serviceName: string; + detailedStatisticsLoading: boolean; + detailedStatistics: ErrorGroupDetailedStatistics; + initialSortField: string; + initialSortDirection: 'asc' | 'desc'; + comparisonEnabled?: boolean; + isLoading: boolean; +} + +function MobileCrashGroupList({ + mainStatistics, + serviceName, + detailedStatisticsLoading, + detailedStatistics, + comparisonEnabled, + initialSortField, + initialSortDirection, + isLoading, +}: Props) { + const { query } = useApmParams( + '/mobile-services/{serviceName}/errors-and-crashes' + ); + const { offset } = query; + const columns = useMemo(() => { + return [ + { + name: i18n.translate('xpack.apm.errorsTable.typeColumnLabel', { + defaultMessage: 'Type', + }), + field: 'type', + sortable: false, + render: (_, { type }) => { + return ( + + {type} + + ); + }, + }, + { + name: i18n.translate( + 'xpack.apm.crashTable.crashMessageAndCulpritColumnLabel', + { + defaultMessage: 'Crash message', + } + ), + field: 'message', + sortable: false, + width: '30%', + render: (_, item: ErrorGroupItem) => { + return ( + + + + {item.name || NOT_AVAILABLE_LABEL} + + + + ); + }, + }, + { + field: 'lastSeen', + sortable: true, + name: i18n.translate('xpack.apm.errorsTable.lastSeenColumnLabel', { + defaultMessage: 'Last seen', + }), + align: LEFT_ALIGNMENT, + render: (_, { lastSeen }) => + lastSeen ? ( + + ) : ( + NOT_AVAILABLE_LABEL + ), + }, + { + field: 'occurrences', + name: i18n.translate('xpack.apm.errorsTable.occurrencesColumnLabel', { + defaultMessage: 'Occurrences', + }), + sortable: true, + dataType: 'number', + align: RIGHT_ALIGNMENT, + render: (_, { occurrences, groupId }) => { + const currentPeriodTimeseries = + detailedStatistics?.currentPeriod?.[groupId]?.timeseries; + const previousPeriodTimeseries = + detailedStatistics?.previousPeriod?.[groupId]?.timeseries; + const { currentPeriodColor, previousPeriodColor } = + getTimeSeriesColor(ChartType.FAILED_TRANSACTION_RATE); + + return ( + + ); + }, + }, + ] as Array>; + }, [ + serviceName, + query, + detailedStatistics, + comparisonEnabled, + detailedStatisticsLoading, + offset, + ]); + return ( + + ); +} + +export { MobileCrashGroupList }; diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crashes_overview.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crashes_overview.tsx new file mode 100644 index 000000000000..9ebd3a75e44b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/crashes_overview.tsx @@ -0,0 +1,267 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { orderBy } from 'lodash'; +import { v4 as uuidv4 } from 'uuid'; +import { useTimeRange } from '../../../../hooks/use_time_range'; +import { useCrashGroupDistributionFetcher } from '../../../../hooks/use_crash_group_distribution_fetcher'; +import { MobileErrorsAndCrashesTreemap } from '../charts/mobile_errors_and_crashes_treemap'; +import { MobileCrashGroupList } from './crash_group_list'; +import { + FETCH_STATUS, + isPending, + useFetcher, +} from '../../../../hooks/use_fetcher'; +import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { ErrorDistribution } from '../errors_and_crashes_group_details/shared/distribution'; +import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; +import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options'; +import { + getKueryWithMobileCrashFilter, + getKueryWithMobileFilters, +} from '../../../../../common/utils/get_kuery_with_mobile_filters'; + +type MobileCrashGroupMainStatistics = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics'>; +type MobileCrashGroupDetailedStatistics = + APIReturnType<'POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics'>; + +const INITIAL_STATE_MAIN_STATISTICS: { + mobileCrashGroupMainStatistics: MobileCrashGroupMainStatistics['errorGroups']; + requestId?: string; + currentPageGroupIds: MobileCrashGroupMainStatistics['errorGroups']; +} = { + mobileCrashGroupMainStatistics: [], + requestId: undefined, + currentPageGroupIds: [], +}; + +const INITIAL_STATE_DETAILED_STATISTICS: MobileCrashGroupDetailedStatistics = { + currentPeriod: {}, + previousPeriod: {}, +}; + +export function MobileCrashesOverview() { + const { serviceName } = useApmServiceContext(); + + const { + query: { + environment, + kuery, + sortField = 'occurrences', + sortDirection = 'desc', + rangeFrom, + rangeTo, + offset, + comparisonEnabled, + page = 0, + pageSize = 25, + device, + osVersion, + appVersion, + netConnectionType, + }, + } = useApmParams('/mobile-services/{serviceName}/errors-and-crashes/'); + + const kueryWithMobileFilters = getKueryWithMobileFilters({ + device, + osVersion, + appVersion, + netConnectionType, + kuery, + }); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { crashDistributionData, status } = useCrashGroupDistributionFetcher({ + serviceName, + groupId: undefined, + environment, + kuery: kueryWithMobileFilters, + }); + + const { + data: crashGroupListData = INITIAL_STATE_MAIN_STATISTICS, + status: crashGroupListDataStatus, + } = useFetcher( + (callApmApi) => { + const normalizedSortDirection = sortDirection === 'asc' ? 'asc' : 'desc'; + + if (start && end) { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics', + { + params: { + path: { + serviceName, + }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + sortField, + sortDirection: normalizedSortDirection, + }, + }, + } + ).then((response) => { + const currentPageGroupIds = orderBy( + response.errorGroups, + sortField, + sortDirection + ) + .slice(page * pageSize, (page + 1) * pageSize) + .map(({ groupId }) => groupId) + .sort(); + + return { + // Everytime the main statistics is refetched, updates the requestId making the comparison API to be refetched. + requestId: uuidv4(), + mobileCrashGroupMainStatistics: response.errorGroups, + currentPageGroupIds, + }; + }); + } + }, + [ + environment, + kueryWithMobileFilters, + serviceName, + start, + end, + sortField, + sortDirection, + page, + pageSize, + ] + ); + + const { requestId, mobileCrashGroupMainStatistics, currentPageGroupIds } = + crashGroupListData; + const { + data: mobileCrashGroupDetailedStatistics = INITIAL_STATE_DETAILED_STATISTICS, + status: mobileCrashGroupDetailedStatisticsStatus, + } = useFetcher( + (callApmApi) => { + if (requestId && currentPageGroupIds.length && start && end) { + return callApmApi( + 'POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics', + { + params: { + path: { serviceName }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + numBuckets: 20, + offset: + comparisonEnabled && isTimeComparison(offset) + ? offset + : undefined, + }, + body: { + groupIds: JSON.stringify(currentPageGroupIds), + }, + }, + } + ); + } + }, + // only fetches agg results when requestId changes + // eslint-disable-next-line react-hooks/exhaustive-deps + [requestId], + { preservePreviousData: false } + ); + + const kueryForTreemap = getKueryWithMobileCrashFilter({ + kuery: kueryWithMobileFilters, + groupId: undefined, + }); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + +

    + {i18n.translate( + 'xpack.apm.serviceDetails.metrics.crashes.title', + { defaultMessage: 'Crashes' } + )} +

    +
    + + + +
    +
    +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.stories.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.stories.tsx new file mode 100644 index 000000000000..9e564a930a9a --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.stories.tsx @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Meta, Story } from '@storybook/react'; +import React, { ComponentProps } from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { MockApmPluginContextWrapper } from '../../../../../context/apm_plugin/mock_apm_plugin_context'; +import { MockUrlParamsContextProvider } from '../../../../../context/url_params_context/mock_url_params_context_provider'; + +import { MobileErrorGroupList } from '.'; + +type Args = ComponentProps; + +const stories: Meta = { + title: 'app/ErrorGroupOverview/MobileErrorGroupList', + component: MobileErrorGroupList, + decorators: [ + (StoryComponent) => { + return ( + + + + + + + + ); + }, + ], +}; +export default stories; + +export const Example: Story = (args) => { + return ; +}; +Example.args = { + mainStatistics: [ + { + name: 'net/http: abort Handler', + occurrences: 14, + culprit: 'Main.func2', + groupId: '83a653297ec29afed264d7b60d5cda7b', + lastSeen: 1634833121434, + handled: false, + type: 'errorString', + }, + { + name: 'POST /api/orders (500)', + occurrences: 5, + culprit: 'logrusMiddleware', + groupId: '7a640436a9be648fd708703d1ac84650', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.2.24:3000->10.36.1.14:34232: write: connection reset by peer', + occurrences: 4, + culprit: 'apiHandlers.getProductCustomers', + groupId: '95ca0e312c109aa11e298bcf07f1445b', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.0.21:3000->10.36.1.252:57070: write: connection reset by peer', + occurrences: 3, + culprit: 'apiHandlers.getCustomers', + groupId: '4053d7e33d2b716c819bd96d9d6121a2', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + { + name: 'write tcp 10.36.0.21:3000->10.36.0.88:33926: write: broken pipe', + occurrences: 2, + culprit: 'apiHandlers.getOrders', + groupId: '94f4ca8ec8c02e5318cf03f46ae4c1f3', + lastSeen: 1634833121434, + handled: false, + type: 'OpError', + }, + ], + serviceName: 'test service', +}; + +export const EmptyState: Story = (args) => { + return ; +}; +EmptyState.args = { + mainStatistics: [], + serviceName: 'test service', +}; diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.test.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.test.tsx new file mode 100644 index 000000000000..278825c25c68 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/error_group_list.test.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { composeStories } from '@storybook/testing-react'; +import { render } from '@testing-library/react'; +import React from 'react'; +import * as stories from './error_group_list.stories'; + +const { Example } = composeStories(stories); + +describe('ErrorGroupList', () => { + it('renders', () => { + expect(() => render()).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/index.tsx new file mode 100644 index 000000000000..e179410a5a20 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/error_group_list/index.tsx @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBadge, + EuiToolTip, + RIGHT_ALIGNMENT, + LEFT_ALIGNMENT, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import React, { useMemo } from 'react'; +import { NOT_AVAILABLE_LABEL } from '../../../../../../common/i18n'; +import { asInteger } from '../../../../../../common/utils/formatters'; +import { useApmParams } from '../../../../../hooks/use_apm_params'; +import { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; +import { truncate } from '../../../../../utils/style'; +import { + ChartType, + getTimeSeriesColor, +} from '../../../../shared/charts/helper/get_timeseries_color'; +import { SparkPlot } from '../../../../shared/charts/spark_plot'; +import { ErrorDetailLink } from '../../../../shared/links/apm/mobile/error_detail_link'; +import { ErrorOverviewLink } from '../../../../shared/links/apm/mobile/error_overview_link'; +import { ITableColumn, ManagedTable } from '../../../../shared/managed_table'; +import { TimestampTooltip } from '../../../../shared/timestamp_tooltip'; +import { isTimeComparison } from '../../../../shared/time_comparison/get_comparison_options'; + +const MessageAndCulpritCell = euiStyled.div` + ${truncate('100%')}; +`; + +const ErrorLink = euiStyled(ErrorOverviewLink)` + ${truncate('100%')}; +`; + +type ErrorGroupItem = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics'>['errorGroups'][0]; +type ErrorGroupDetailedStatistics = + APIReturnType<'POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics'>; + +interface Props { + mainStatistics: ErrorGroupItem[]; + serviceName: string; + detailedStatisticsLoading: boolean; + detailedStatistics: ErrorGroupDetailedStatistics; + initialSortField: string; + initialSortDirection: 'asc' | 'desc'; + comparisonEnabled?: boolean; + isLoading: boolean; +} + +function MobileErrorGroupList({ + mainStatistics, + serviceName, + detailedStatisticsLoading, + detailedStatistics, + comparisonEnabled, + initialSortField, + initialSortDirection, + isLoading, +}: Props) { + const { query } = useApmParams( + '/mobile-services/{serviceName}/errors-and-crashes' + ); + const { offset } = query; + const columns = useMemo(() => { + return [ + { + name: i18n.translate('xpack.apm.errorsTable.typeColumnLabel', { + defaultMessage: 'Type', + }), + field: 'type', + sortable: false, + render: (_, { type }) => { + return ( + + {type} + + ); + }, + }, + { + name: i18n.translate( + 'xpack.apm.errorsTable.errorMessageAndCulpritColumnLabel', + { + defaultMessage: 'Error message and culprit', + } + ), + field: 'message', + sortable: false, + width: '30%', + render: (_, item: ErrorGroupItem) => { + return ( + + + + {item.name || NOT_AVAILABLE_LABEL} + + + + ); + }, + }, + { + name: '', + field: 'handled', + sortable: false, + align: RIGHT_ALIGNMENT, + render: (_, { handled }) => + handled === false && ( + + {i18n.translate('xpack.apm.errorsTable.unhandledLabel', { + defaultMessage: 'Unhandled', + })} + + ), + }, + { + field: 'lastSeen', + sortable: true, + name: i18n.translate('xpack.apm.errorsTable.lastSeenColumnLabel', { + defaultMessage: 'Last seen', + }), + align: LEFT_ALIGNMENT, + render: (_, { lastSeen }) => + lastSeen ? ( + + ) : ( + NOT_AVAILABLE_LABEL + ), + }, + { + field: 'occurrences', + name: i18n.translate('xpack.apm.errorsTable.occurrencesColumnLabel', { + defaultMessage: 'Occurrences', + }), + sortable: true, + dataType: 'number', + align: RIGHT_ALIGNMENT, + render: (_, { occurrences, groupId }) => { + const currentPeriodTimeseries = + detailedStatistics?.currentPeriod?.[groupId]?.timeseries; + const previousPeriodTimeseries = + detailedStatistics?.previousPeriod?.[groupId]?.timeseries; + const { currentPeriodColor, previousPeriodColor } = + getTimeSeriesColor(ChartType.FAILED_TRANSACTION_RATE); + + return ( + + ); + }, + }, + ] as Array>; + }, [ + serviceName, + query, + detailedStatistics, + comparisonEnabled, + detailedStatisticsLoading, + offset, + ]); + return ( + + ); +} + +export { MobileErrorGroupList }; diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/errors_overview.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/errors_overview.tsx new file mode 100644 index 000000000000..56d3ee35fc32 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/errors_overview.tsx @@ -0,0 +1,275 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { orderBy } from 'lodash'; +import React from 'react'; +import { v4 as uuidv4 } from 'uuid'; +import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; +import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event/chart_pointer_event_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useErrorGroupDistributionFetcher } from '../../../../hooks/use_error_group_distribution_fetcher'; +import { + FETCH_STATUS, + isPending, + useFetcher, +} from '../../../../hooks/use_fetcher'; +import { useTimeRange } from '../../../../hooks/use_time_range'; +import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; +import { isTimeComparison } from '../../../shared/time_comparison/get_comparison_options'; +import { HttpErrorRateChart } from '../charts/mobile_http_error_rate'; +import { ErrorDistribution } from '../errors_and_crashes_group_details/shared/distribution'; +import { MobileErrorGroupList } from './error_group_list'; +import { MobileErrorsAndCrashesTreemap } from '../charts/mobile_errors_and_crashes_treemap'; +import { + getKueryWithMobileErrorFilter, + getKueryWithMobileFilters, +} from '../../../../../common/utils/get_kuery_with_mobile_filters'; + +type MobileErrorGroupMainStatistics = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics'>; +type MobileErrorGroupDetailedStatistics = + APIReturnType<'POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics'>; + +const INITIAL_STATE_MAIN_STATISTICS: { + mobileErrorGroupMainStatistics: MobileErrorGroupMainStatistics['errorGroups']; + requestId?: string; + currentPageGroupIds: MobileErrorGroupMainStatistics['errorGroups']; +} = { + mobileErrorGroupMainStatistics: [], + requestId: undefined, + currentPageGroupIds: [], +}; + +const INITIAL_STATE_DETAILED_STATISTICS: MobileErrorGroupDetailedStatistics = { + currentPeriod: {}, + previousPeriod: {}, +}; + +export function MobileErrorsOverview() { + const { serviceName } = useApmServiceContext(); + const { + query: { + environment, + kuery, + sortField = 'occurrences', + sortDirection = 'desc', + rangeFrom, + rangeTo, + offset, + comparisonEnabled, + page = 0, + pageSize = 25, + device, + osVersion, + appVersion, + netConnectionType, + }, + } = useApmParams('/mobile-services/{serviceName}/errors-and-crashes'); + const kueryWithMobileFilters = getKueryWithMobileFilters({ + device, + osVersion, + appVersion, + netConnectionType, + kuery, + }); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { errorDistributionData, status } = useErrorGroupDistributionFetcher({ + serviceName, + groupId: undefined, + environment, + kuery: kueryWithMobileFilters, + }); + const { + data: errorGroupListData = INITIAL_STATE_MAIN_STATISTICS, + status: errorGroupListDataStatus, + } = useFetcher( + (callApmApi) => { + const normalizedSortDirection = sortDirection === 'asc' ? 'asc' : 'desc'; + + if (start && end) { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics', + { + params: { + path: { + serviceName, + }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + sortField, + sortDirection: normalizedSortDirection, + }, + }, + } + ).then((response) => { + const currentPageGroupIds = orderBy( + response.errorGroups, + sortField, + sortDirection + ) + .slice(page * pageSize, (page + 1) * pageSize) + .map(({ groupId }) => groupId) + .sort(); + + return { + // Everytime the main statistics is refetched, updates the requestId making the comparison API to be refetched. + requestId: uuidv4(), + mobileErrorGroupMainStatistics: response.errorGroups, + currentPageGroupIds, + }; + }); + } + }, + [ + environment, + kueryWithMobileFilters, + serviceName, + start, + end, + sortField, + sortDirection, + page, + pageSize, + ] + ); + const { requestId, mobileErrorGroupMainStatistics, currentPageGroupIds } = + errorGroupListData; + const { + data: mobileErrorGroupDetailedStatistics = INITIAL_STATE_DETAILED_STATISTICS, + status: mobileErrorGroupDetailedStatisticsStatus, + } = useFetcher( + (callApmApi) => { + if (requestId && currentPageGroupIds.length && start && end) { + return callApmApi( + 'POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics', + { + params: { + path: { serviceName }, + query: { + environment, + kuery: kueryWithMobileFilters, + start, + end, + numBuckets: 20, + offset: + comparisonEnabled && isTimeComparison(offset) + ? offset + : undefined, + }, + body: { + groupIds: JSON.stringify(currentPageGroupIds), + }, + }, + } + ); + } + }, + // only fetches agg results when requestId changes + // eslint-disable-next-line react-hooks/exhaustive-deps + [requestId], + { preservePreviousData: false } + ); + const kueryForTreemap = getKueryWithMobileErrorFilter({ + kuery: kueryWithMobileFilters, + groupId: undefined, + }); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + {i18n.translate( + 'xpack.apm.serviceDetails.metrics.errorsList.title', + { defaultMessage: 'Errors' } + )} +

    +
    + + + +
    +
    +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/index.tsx new file mode 100644 index 000000000000..539a0efc0170 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/index.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { useHistory } from 'react-router-dom'; +import { Tabs, MobileErrorTabIds } from './tabs/tabs'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { push } from '../../../shared/links/url_helpers'; + +export function MobileErrorCrashesOverview() { + const { + query: { mobileErrorTabId = MobileErrorTabIds.ERRORS }, + } = useApmParams('/mobile-services/{serviceName}/errors-and-crashes'); + const history = useHistory(); + return ( + + + + { + push(history, { + query: { + mobileErrorTabId: nextTab, + }, + }); + }} + mobileErrorTabId={mobileErrorTabId as MobileErrorTabIds} + /> + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/tabs/tabs.tsx b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/tabs/tabs.tsx new file mode 100644 index 000000000000..8cdcd231d933 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/mobile/errors_and_crashes_overview/tabs/tabs.tsx @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiTab, EuiTabs, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { MobileErrorsOverview } from '../errors_overview'; +import { MobileCrashesOverview } from '../crashes_overview'; + +export enum MobileErrorTabIds { + ERRORS = 'errors', + CRASHES = 'crashes', +} + +const tabs = [ + { + id: MobileErrorTabIds.ERRORS, + name: i18n.translate('xpack.apm.mobile.errorsAndCrashes.errorsTab', { + defaultMessage: 'Errors', + }), + 'data-test-subj': 'apmMobileErrorsTabButton', + }, + { + id: MobileErrorTabIds.CRASHES, + name: i18n.translate('xpack.apm.mobile.errorsAndCrashes.crashesTab', { + defaultMessage: 'Crashes', + }), + append:
    , + 'data-test-subj': 'apmMobileCrashesTabButton', + }, +]; + +export function Tabs({ + mobileErrorTabId, + onTabClick, +}: { + mobileErrorTabId: MobileErrorTabIds; + onTabClick: (nextTab: MobileErrorTabIds) => void; +}) { + const selectedTabId = mobileErrorTabId; + const tabEntries = tabs.map((tab, index) => ( + { + onTabClick(tab.id); + }} + isSelected={tab.id === selectedTabId} + append={tab.append} + > + {tab.name} + + )); + + return ( + <> + {tabEntries} + + {selectedTabId === MobileErrorTabIds.ERRORS && } + {selectedTabId === MobileErrorTabIds.CRASHES && } + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/filters/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/filters/index.tsx index 01ac1451e23e..b92af98de2d6 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/filters/index.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/filters/index.tsx @@ -77,7 +77,8 @@ export function MobileFilters() { } = useAnyOfApmParams( '/mobile-services/{serviceName}/overview', '/mobile-services/{serviceName}/transactions', - '/mobile-services/{serviceName}/transactions/view' + '/mobile-services/{serviceName}/transactions/view', + '/mobile-services/{serviceName}/errors-and-crashes' ); const filters = { netConnectionType, device, osVersion, appVersion }; diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx index b046511d6ce6..f4c530b47acc 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/embedded_map.tsx @@ -23,6 +23,7 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { EuiText } from '@elastic/eui'; import type { Filter } from '@kbn/es-query'; +import { useDataViewId } from '../../../../../hooks/use_data_view_id'; import { ApmPluginStartDeps } from '../../../../../plugin'; import { getLayerList } from './map_layers/get_layer_list'; import { MapTypes } from '../../../../../../common/mobile/constants'; @@ -40,6 +41,7 @@ function EmbeddedMapComponent({ filters: Filter[]; }) { const [error, setError] = useState(); + const dataViewId = useDataViewId(); const [embeddable, setEmbeddable] = useState< MapEmbeddable | ErrorEmbeddable | undefined @@ -128,7 +130,7 @@ function EmbeddedMapComponent({ useEffect(() => { const setLayerList = async () => { if (embeddable && !isErrorEmbeddable(embeddable)) { - const layerList = await getLayerList({ selectedMap, maps }); + const layerList = await getLayerList({ selectedMap, maps, dataViewId }); await Promise.all([ embeddable.setLayerList(layerList), embeddable.reload(), @@ -137,7 +139,7 @@ function EmbeddedMapComponent({ }; setLayerList(); - }, [embeddable, selectedMap, maps]); + }, [embeddable, selectedMap, maps, dataViewId]); useEffect(() => { if (embeddable) { diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_http_requests_map_layer_list.ts b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_http_requests_map_layer_list.ts index 895462654629..728658817b27 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_http_requests_map_layer_list.ts +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_http_requests_map_layer_list.ts @@ -24,7 +24,6 @@ import { SPAN_SUBTYPE, SPAN_TYPE, } from '../../../../../../../common/es_fields/apm'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../../../../common/data_view_constants'; import { getLayerStyle, PalleteColors } from './get_map_layer_style'; import { MobileSpanSubtype, @@ -48,7 +47,10 @@ const label = i18n.translate( } ); -export async function getHttpRequestsLayerList(maps?: MapsStartApi) { +export async function getHttpRequestsLayerList( + maps: MapsStartApi | undefined, + dataViewId: string +) { const whereQuery = { language: 'kuery', query: `${PROCESSOR_EVENT}:${ProcessorEvent.span} and ${SPAN_SUBTYPE}:${MobileSpanSubtype.Http} and ${SPAN_TYPE}:${MobileSpanType.External}`, @@ -72,7 +74,7 @@ export async function getHttpRequestsLayerList(maps?: MapsStartApi) { }, ], whereQuery, - indexPatternId: APM_STATIC_DATA_VIEW_ID, + indexPatternId: dataViewId, applyGlobalQuery: true, applyGlobalTime: true, applyForceRefresh: true, @@ -114,7 +116,7 @@ export async function getHttpRequestsLayerList(maps?: MapsStartApi) { }, ], whereQuery, - indexPatternId: APM_STATIC_DATA_VIEW_ID, + indexPatternId: dataViewId, applyGlobalQuery: true, applyGlobalTime: true, applyForceRefresh: true, diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_layer_list.ts b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_layer_list.ts index 152f1874b143..d9f1d023fbf6 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_layer_list.ts +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_layer_list.ts @@ -10,19 +10,21 @@ import { getHttpRequestsLayerList } from './get_http_requests_map_layer_list'; import { getSessionMapLayerList } from './get_session_map_layer_list'; import { MapTypes } from '../../../../../../../common/mobile/constants'; -export async function getLayerList({ +export function getLayerList({ selectedMap, maps, + dataViewId, }: { selectedMap: MapTypes; - maps?: MapsStartApi; + maps: MapsStartApi | undefined; + dataViewId: string; }): Promise { switch (selectedMap) { case MapTypes.Http: - return await getHttpRequestsLayerList(maps); + return getHttpRequestsLayerList(maps, dataViewId); case MapTypes.Session: - return await getSessionMapLayerList(maps); + return getSessionMapLayerList(maps, dataViewId); default: - return await getHttpRequestsLayerList(maps); + return getHttpRequestsLayerList(maps, dataViewId); } } diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_session_map_layer_list.ts b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_session_map_layer_list.ts index a0d2b80b218f..be86b5da710a 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_session_map_layer_list.ts +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/geo_map/map_layers/get_session_map_layer_list.ts @@ -21,7 +21,6 @@ import { CLIENT_GEO_REGION_ISO_CODE, SESSION_ID, } from '../../../../../../../common/es_fields/apm'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../../../../common/data_view_constants'; import { getLayerStyle, PalleteColors } from './get_map_layer_style'; interface VectorLayerDescriptor extends BaseVectorLayerDescriptor { @@ -40,7 +39,10 @@ const label = i18n.translate( defaultMessage: 'Sessions', } ); -export async function getSessionMapLayerList(maps?: MapsStartApi) { +export async function getSessionMapLayerList( + maps: MapsStartApi | undefined, + dataViewId: string +) { const basemapLayerDescriptor = await maps?.createLayerDescriptors?.createBasemapLayerDescriptor(); @@ -59,7 +61,7 @@ export async function getSessionMapLayerList(maps?: MapsStartApi) { label, }, ], - indexPatternId: APM_STATIC_DATA_VIEW_ID, + indexPatternId: dataViewId, applyGlobalQuery: true, applyGlobalTime: true, applyForceRefresh: true, @@ -101,7 +103,7 @@ export async function getSessionMapLayerList(maps?: MapsStartApi) { label, }, ], - indexPatternId: APM_STATIC_DATA_VIEW_ID, + indexPatternId: dataViewId, applyGlobalQuery: true, applyGlobalTime: true, applyForceRefresh: true, diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx index df322ea7fe37..b4c68a14b07c 100644 --- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/index.tsx @@ -15,9 +15,7 @@ import { EuiPanel, EuiSpacer, EuiTitle, - EuiCallOut, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { AnnotationsContextProvider } from '../../../../context/annotations/annotations_context'; import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context'; @@ -111,42 +109,6 @@ export function MobileServiceOverview() { - - -

    - - {i18n.translate( - 'xpack.apm.serviceOverview.mobileCallOutLink', - { - defaultMessage: 'Give feedback', - } - )} - - ), - }} - /> -

    -
    - -
    (); const { path: { serviceName }, query: { rangeFrom, rangeTo, environment, kuery }, } = useApmParams('/services/{serviceName}/profiling'); const { isProfilingAvailable } = useProfilingPlugin(); - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { start, end, refreshTimeRange } = useTimeRange({ rangeFrom, rangeTo }); const preferred = usePreferredDataSourceAndBucketSize({ start, end, @@ -43,6 +47,7 @@ export function ProfilingOverview() { type: ApmDocumentType.TransactionMetric, numBuckets: 20, }); + const [ apmUniversalProfilingShowCallout, setAPMUniversalProfilingShowCallout, @@ -67,6 +72,7 @@ export function ProfilingOverview() { end={end} environment={environment} dataSource={preferred?.source} + kuery={kuery} /> ), @@ -87,12 +93,13 @@ export function ProfilingOverview() { startIndex={0} endIndex={10} dataSource={preferred?.source} + kuery={kuery} /> ), }, ]; - }, [end, environment, preferred?.source, serviceName, start]); + }, [end, environment, kuery, preferred?.source, serviceName, start]); if (!isProfilingAvailable) { return null; @@ -147,6 +154,22 @@ export function ProfilingOverview() { )} + { + push(history, { + query: { + kuery: next.query, + rangeFrom: next.dateRange.from, + rangeTo: next.dateRange.to, + }, + }); + }} + onRefresh={refreshTimeRange} + /> + ; + kuery: string; } export function ProfilingFlamegraph({ @@ -44,6 +48,7 @@ export function ProfilingFlamegraph({ serviceName, environment, dataSource, + kuery, }: Props) { const { profilingLocators } = useProfilingPlugin(); @@ -61,13 +66,14 @@ export function ProfilingFlamegraph({ environment, documentType: dataSource.documentType, rollupInterval: dataSource.rollupInterval, + kuery, }, }, } ); } }, - [dataSource, serviceName, start, end, environment] + [dataSource, serviceName, start, end, environment, kuery] ); const hostNamesKueryFormat = toKueryFilterFormat( @@ -86,7 +92,7 @@ export function ProfilingFlamegraph({ {i18n.translate('xpack.apm.profiling.flamegraph.link', { diff --git a/x-pack/plugins/apm/public/components/app/profiling_overview/profiling_top_functions.tsx b/x-pack/plugins/apm/public/components/app/profiling_overview/profiling_top_functions.tsx index 0c2a22504072..7b428802fbfc 100644 --- a/x-pack/plugins/apm/public/components/app/profiling_overview/profiling_top_functions.tsx +++ b/x-pack/plugins/apm/public/components/app/profiling_overview/profiling_top_functions.tsx @@ -9,13 +9,16 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { EmbeddableFunctions } from '@kbn/observability-shared-plugin/public'; import React from 'react'; +import { ApmDataSourceWithSummary } from '../../../../common/data_source'; +import { ApmDocumentType } from '../../../../common/document_type'; import { HOST_NAME } from '../../../../common/es_fields/apm'; -import { toKueryFilterFormat } from '../../../../common/utils/to_kuery_filter_format'; +import { + mergeKueries, + toKueryFilterFormat, +} from '../../../../common/utils/kuery_utils'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { useProfilingPlugin } from '../../../hooks/use_profiling_plugin'; import { HostnamesFilterWarning } from './host_names_filter_warning'; -import { ApmDataSourceWithSummary } from '../../../../common/data_source'; -import { ApmDocumentType } from '../../../../common/document_type'; interface Props { serviceName: string; @@ -27,6 +30,7 @@ interface Props { dataSource?: ApmDataSourceWithSummary< ApmDocumentType.TransactionMetric | ApmDocumentType.TransactionEvent >; + kuery: string; } export function ProfilingTopNFunctions({ @@ -37,6 +41,7 @@ export function ProfilingTopNFunctions({ startIndex, endIndex, dataSource, + kuery, }: Props) { const { profilingLocators } = useProfilingPlugin(); @@ -56,13 +61,23 @@ export function ProfilingTopNFunctions({ endIndex, documentType: dataSource.documentType, rollupInterval: dataSource.rollupInterval, + kuery, }, }, } ); } }, - [dataSource, serviceName, start, end, environment, startIndex, endIndex] + [ + dataSource, + serviceName, + start, + end, + environment, + startIndex, + endIndex, + kuery, + ] ); const hostNamesKueryFormat = toKueryFilterFormat( @@ -81,7 +96,7 @@ export function ProfilingTopNFunctions({ {i18n.translate('xpack.apm.profiling.topnFunctions.link', { diff --git a/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx b/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx index 93876d1df600..7f4f4293722d 100644 --- a/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/service_dependencies/service_dependencies_breakdown_chart.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { getVizColorForIndex } from '../../../../common/viz_colors'; import { Coordinate, TimeSeries } from '../../../../typings/timeseries'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; -import { useApmParams } from '../../../hooks/use_apm_params'; +import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { BreakdownChart } from '../../shared/charts/breakdown_chart'; @@ -22,7 +22,10 @@ export function ServiceDependenciesBreakdownChart({ const { query: { kuery, environment, rangeFrom, rangeTo }, - } = useApmParams('/services/{serviceName}/dependencies'); + } = useAnyOfApmParams( + '/services/{serviceName}/dependencies', + '/mobile-services/{serviceName}/dependencies' + ); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); diff --git a/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/service_list_preview.tsx b/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/service_list_preview.tsx index 66105c106805..39f8ba7068ab 100644 --- a/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/service_list_preview.tsx +++ b/x-pack/plugins/apm/public/components/app/service_groups/service_group_save/service_list_preview.tsx @@ -10,11 +10,11 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; +import { AgentIcon } from '@kbn/custom-icons'; import { i18n } from '@kbn/i18n'; import { orderBy } from 'lodash'; import React, { useCallback, useMemo, useState } from 'react'; import { ValuesType } from 'utility-types'; -import { AgentIcon } from '../../../shared/agent_icon'; import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; import { unit } from '../../../../utils/style'; import { EnvironmentBadge } from '../../../shared/environment_badge'; @@ -93,7 +93,7 @@ export function ServiceListPreview({ items, isLoading }: Props) { content={ - + {serviceName} diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx index 081a24ceb442..b3e36fc8bebb 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx @@ -327,6 +327,7 @@ export function ServiceList({ } = useApmParams('/services'); const { kuery } = query; + const { fallbackToTransactions } = useFallbackToTransactionsFetcher({ kuery, }); diff --git a/x-pack/plugins/apm/public/components/app/service_map/icons.ts b/x-pack/plugins/apm/public/components/app/service_map/icons.ts index 187a84cb6cca..f784a737f8d6 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/icons.ts +++ b/x-pack/plugins/apm/public/components/app/service_map/icons.ts @@ -5,13 +5,13 @@ * 2.0. */ +import { getAgentIcon } from '@kbn/custom-icons'; import cytoscape from 'cytoscape'; import { AGENT_NAME, SPAN_SUBTYPE, SPAN_TYPE, } from '../../../../common/es_fields/apm'; -import { getAgentIcon } from '../../shared/agent_icon/get_agent_icon'; import { getSpanIcon } from '../../shared/span_icon/get_span_icon'; export function iconForNode(node: cytoscape.NodeSingular) { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index 4a4e79b39c8e..55972ede6e56 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -20,7 +20,7 @@ import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { isOpenTelemetryAgentName, isRumAgentName, - isServerlessAgent, + isServerlessAgentName, } from '../../../../common/agent_name'; import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; @@ -60,7 +60,7 @@ export function ServiceOverview() { const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const isRumAgent = isRumAgentName(agentName); const isOpenTelemetryAgent = isOpenTelemetryAgentName(agentName as AgentName); - const isServerless = isServerlessAgent(serverlessType); + const isServerless = isServerlessAgentName(serverlessType); const dependenciesLink = router.link('/services/{serviceName}/dependencies', { path: { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx index fac65a448576..09b9e461ca1c 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/intance_details.tsx @@ -6,6 +6,11 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; +import { + CloudProvider, + getAgentIcon, + getCloudProviderIcon, +} from '@kbn/custom-icons'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import React from 'react'; @@ -36,10 +41,9 @@ import { import { isPending } from '../../../../hooks/use_fetcher'; import { useTheme } from '../../../../hooks/use_theme'; import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; -import { getAgentIcon } from '../../../shared/agent_icon/get_agent_icon'; import { KeyValueFilterList } from '../../../shared/key_value_filter_list'; import { pushNewItemToKueryBar } from '../../../shared/kuery_bar/utils'; -import { getCloudIcon, getContainerIcon } from '../../../shared/service_icons'; +import { getContainerIcon } from '../../../shared/service_icons'; import { useInstanceDetailsFetcher } from './use_instance_details_fetcher'; type ServiceInstanceDetails = @@ -175,7 +179,7 @@ export function InstanceDetails({ 'xpack.apm.serviceOverview.instanceTable.details.cloudTitle', { defaultMessage: 'Cloud' } )} - icon={getCloudIcon(data.cloud?.provider)} + icon={getCloudProviderIcon(data.cloud?.provider as CloudProvider)} keyValueList={cloudDetailsKeyValuePairs} onClickFilter={addKueryBarFilter} /> diff --git a/x-pack/plugins/apm/public/components/app/settings/agent_explorer/agent_list/index.tsx b/x-pack/plugins/apm/public/components/app/settings/agent_explorer/agent_list/index.tsx index 665d454c440f..10d2cec27ee1 100644 --- a/x-pack/plugins/apm/public/components/app/settings/agent_explorer/agent_list/index.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/agent_explorer/agent_list/index.tsx @@ -12,6 +12,7 @@ import { EuiIcon, EuiToolTip, } from '@elastic/eui'; +import { AgentIcon } from '@kbn/custom-icons'; import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; import React, { useMemo, useState } from 'react'; @@ -20,7 +21,6 @@ import { AgentExplorerFieldName } from '../../../../../../common/agent_explorer' import { AgentName } from '../../../../../../typings/es_schemas/ui/fields/agent'; import { useApmPluginContext } from '../../../../../context/apm_plugin/use_apm_plugin_context'; import { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; -import { AgentIcon } from '../../../../shared/agent_icon'; import { EnvironmentBadge } from '../../../../shared/environment_badge'; import { ItemsBadge } from '../../../../shared/item_badge'; import { ITableColumn, ManagedTable } from '../../../../shared/managed_table'; @@ -67,7 +67,10 @@ export function getAgentsColumns({ onAgentSelected(agent)} display={isSelected ? 'base' : 'empty'} @@ -96,7 +99,7 @@ export function getAgentsColumns({ content={ - + {serviceName} diff --git a/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx b/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx index 486a54b40009..3c314f638977 100644 --- a/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx @@ -19,12 +19,12 @@ export function TopTracesOverview() { const { query: { environment, kuery, rangeFrom, rangeTo }, } = useApmParams('/traces'); + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { fallbackToTransactions } = useFallbackToTransactionsFetcher({ kuery, }); - const { start, end } = useTimeRange({ rangeFrom, rangeTo }); - const response = useProgressiveFetcher( (callApmApi) => { if (start && end) { diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx index 1c3ea3bf7e5f..0b9a1190b1e1 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/index.tsx @@ -18,7 +18,7 @@ import { AggregatedTransactionsBadge } from '../../shared/aggregated_transaction import { TransactionCharts } from '../../shared/charts/transaction_charts'; import { replace } from '../../shared/links/url_helpers'; import { TransactionDetailsTabs } from './transaction_details_tabs'; -import { isServerlessAgent } from '../../../../common/agent_name'; +import { isServerlessAgentName } from '../../../../common/agent_name'; import { useLocalStorage } from '../../../hooks/use_local_storage'; import { SloCallout } from '../../shared/slo_callout'; @@ -63,7 +63,7 @@ export function TransactionDetails() { [apmRouter, path, query, transactionName] ); - const isServerless = isServerlessAgent(serverlessType); + const isServerless = isServerlessAgentName(serverlessType); const [sloCalloutDismissed, setSloCalloutDismissed] = useLocalStorage( 'apm.sloCalloutDismissed', false diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx index 69ed7a63b0c5..abd6aee61f40 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/index.tsx @@ -13,10 +13,11 @@ import { useCriticalPathFeatureEnabledSetting } from '../../../../../hooks/use_c import { TechnicalPreviewBadge } from '../../../../shared/technical_preview_badge'; import { Waterfall } from './waterfall'; import { - IWaterfall, + type IWaterfall, WaterfallLegendType, } from './waterfall/waterfall_helpers/waterfall_helpers'; import { WaterfallLegends } from './waterfall_legends'; +import { MissingTransactionWarning } from './waterfall/missing_transaction_warning'; interface Props { waterfallItemId?: string; @@ -38,7 +39,7 @@ export function WaterfallContainer({ if (!waterfall) { return null; } - const { legends, items } = waterfall; + const { legends, items, hasOrphanTraceItems } = waterfall; // Service colors are needed to color the dot in the error popover const serviceLegends = legends.filter( @@ -108,7 +109,19 @@ export function WaterfallContainer({ ) : null} - + + + + + {hasOrphanTraceItems ? ( + + + + ) : null} + + + {i18n.translate( + 'xpack.apm.transactionDetails.agentMissingTransactionLabel', + { + defaultMessage: 'Incomplete trace', + } + )} + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts index df028ee3c8f7..208102b415e5 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.test.ts @@ -16,6 +16,7 @@ import { IWaterfallTransaction, IWaterfallError, IWaterfallSpanOrTransaction, + getHasOrphanTraceItems, } from './waterfall_helpers'; import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_error'; import { @@ -717,4 +718,46 @@ describe('waterfall_helpers', () => { expect(getClockSkew(child, parent)).toBe(0); }); }); + + describe('getHasOrphanTraceItems', () => { + const myTransactionItem = { + processor: { event: 'transaction' }, + trace: { id: 'myTrace' }, + transaction: { + id: 'myTransactionId1', + }, + } as WaterfallTransaction; + + it('should return false if there are no orphan items', () => { + const traceItems: Array = [ + myTransactionItem, + { + processor: { event: 'span' }, + span: { + id: 'mySpanId', + }, + parent: { + id: 'myTransactionId1', + }, + } as WaterfallSpan, + ]; + expect(getHasOrphanTraceItems(traceItems)).toBe(false); + }); + + it('should return true if there are orphan items', () => { + const traceItems: Array = [ + myTransactionItem, + { + processor: { event: 'span' }, + span: { + id: 'myOrphanSpanId', + }, + parent: { + id: 'myNotExistingTransactionId1', + }, + } as WaterfallSpan, + ]; + expect(getHasOrphanTraceItems(traceItems)).toBe(true); + }); + }); }); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts index 62a3ddb434ee..b197859ff108 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers.ts @@ -48,6 +48,7 @@ export interface IWaterfall { totalErrorsCount: number; traceDocsTotal: number; maxTraceItems: number; + hasOrphanTraceItems: boolean; } interface IWaterfallItemBase { @@ -191,7 +192,7 @@ export function getClockSkew( case 'error': case 'span': return parentItem.skew; - // transaction is the inital entry in a service. Calculate skew for this, and it will be propogated to all child spans + // transaction is the initial entry in a service. Calculate skew for this, and it will be propagated to all child spans case 'transaction': { const parentStart = parentItem.doc.timestamp.us + parentItem.skew; @@ -415,6 +416,22 @@ function getErrorCountByParentId( }, {}); } +export const getHasOrphanTraceItems = ( + traceDocs: Array +) => { + const waterfallItemsIds = new Set( + traceDocs.map((doc) => + doc.processor.event === 'span' + ? (doc?.span as WaterfallSpan['span']).id + : doc?.transaction?.id + ) + ); + + return traceDocs.some( + (item) => item.parent?.id && !waterfallItemsIds.has(item.parent.id) + ); +}; + export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { const { traceItems, entryTransaction } = apiResponse; if (isEmpty(traceItems.traceDocs) || !entryTransaction) { @@ -429,6 +446,7 @@ export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { totalErrorsCount: 0, traceDocsTotal: 0, maxTraceItems: 0, + hasOrphanTraceItems: false, }; } @@ -464,6 +482,8 @@ export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { const duration = getWaterfallDuration(items); const legends = getLegends(items); + const hasOrphanTraceItems = getHasOrphanTraceItems(traceItems.traceDocs); + return { entryWaterfallTransaction, rootWaterfallTransaction, @@ -478,5 +498,6 @@ export function getWaterfall(apiResponse: TraceAPIResponse): IWaterfall { totalErrorsCount: traceItems.errorDocs.length, traceDocsTotal: traceItems.traceDocsTotal, maxTraceItems: traceItems.maxTraceItems, + hasOrphanTraceItems, }; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx index 9981533eead4..372138c1273a 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_overview/index.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; import React from 'react'; import { useHistory } from 'react-router-dom'; -import { isServerlessAgent } from '../../../../common/agent_name'; +import { isServerlessAgentName } from '../../../../common/agent_name'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { useApmParams } from '../../../hooks/use_apm_params'; import { useLocalStorage } from '../../../hooks/use_local_storage'; @@ -48,7 +48,7 @@ export function TransactionOverview() { replace(history, { query: { transactionType } }); } - const isServerless = isServerlessAgent(serverlessType); + const isServerless = isServerlessAgentName(serverlessType); const [sloCalloutDismissed, setSloCalloutDismissed] = useLocalStorage( 'apm.sloCalloutDismissed', diff --git a/x-pack/plugins/apm/public/components/fleet_integration/apm_agents/agent_instructions_accordion.tsx b/x-pack/plugins/apm/public/components/fleet_integration/apm_agents/agent_instructions_accordion.tsx index 3e4ddc36413c..237b31219c82 100644 --- a/x-pack/plugins/apm/public/components/fleet_integration/apm_agents/agent_instructions_accordion.tsx +++ b/x-pack/plugins/apm/public/components/fleet_integration/apm_agents/agent_instructions_accordion.tsx @@ -18,12 +18,12 @@ import { i18n } from '@kbn/i18n'; import React, { ComponentType } from 'react'; import styled from 'styled-components'; import { Markdown, useKibana } from '@kbn/kibana-react-plugin/public'; +import { AgentIcon } from '@kbn/custom-icons'; import { AgentRuntimeAttachmentProps, CreateAgentInstructions, } from './agent_instructions_mappings'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; -import { AgentIcon } from '../../shared/agent_icon'; import type { NewPackagePolicy, PackagePolicy, diff --git a/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx b/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx index bc22b84a056a..11a365e0d832 100644 --- a/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/mobile_service_detail/index.tsx @@ -22,6 +22,10 @@ import { MobileTransactionOverview } from '../../app/mobile/transaction_overview import { TransactionDetails } from '../../app/transaction_details'; import { RedirectToDefaultServiceRouteView } from '../service_detail/redirect_to_default_service_route_view'; import { ApmTimeRangeMetadataContextProvider } from '../../../context/time_range_metadata/time_range_metadata_context'; +import { ErrorGroupDetails } from '../../app/mobile/errors_and_crashes_group_details/error_group_details'; +import { CrashGroupDetails } from '../../app/mobile/errors_and_crashes_group_details/crash_group_details'; +import { MobileErrorCrashesOverview } from '../../app/mobile/errors_and_crashes_overview'; +import { ServiceDependencies } from '../../app/service_dependencies'; export function page({ title, @@ -178,6 +182,67 @@ export const mobileServiceDetailRoute = { }, }, }, + '/mobile-services/{serviceName}/errors-and-crashes': { + ...page({ + tabKey: 'errors-and-crashes', + title: i18n.translate('xpack.apm.views.errorsAndCrashes.title', { + defaultMessage: 'Errors & Crashes', + }), + element: , + searchBarOptions: { + showTimeComparison: true, + showMobileFilters: true, + }, + }), + params: t.partial({ + query: t.partial({ + page: toNumberRt, + pageSize: toNumberRt, + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + mobileErrorTabId: t.string, + device: t.string, + osVersion: t.string, + appVersion: t.string, + netConnectionType: t.string, + }), + }), + children: { + '/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}': + { + element: , + params: t.type({ + path: t.type({ + groupId: t.string, + }), + query: t.partial({ errorId: t.string }), + }), + }, + '/mobile-services/{serviceName}/errors-and-crashes/': { + element: , + }, + '/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}': + { + element: , + params: t.type({ + path: t.type({ + groupId: t.string, + }), + query: t.partial({ errorId: t.string }), + }), + }, + }, + }, + '/mobile-services/{serviceName}/dependencies': page({ + element: , + tabKey: 'dependencies', + title: i18n.translate('xpack.apm.views.dependencies.title', { + defaultMessage: 'Dependencies', + }), + searchBarOptions: { + showTimeComparison: true, + }, + }), '/mobile-services/{serviceName}/service-map': page({ tabKey: 'service-map', title: i18n.translate('xpack.apm.views.serviceMap.title', { diff --git a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx index 56deaaa2e6d6..f2601e392b27 100644 --- a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx @@ -371,9 +371,7 @@ export const serviceDetailRoute = { }), element: , searchBarOptions: { - showTimeComparison: false, - showTransactionTypeSelector: false, - showQueryInput: false, + hidden: true, }, }), }, diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index b5261eb55826..fa5e43980ce1 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -24,10 +24,10 @@ import { useHistory } from 'react-router-dom'; import { isMobileAgentName, isRumAgentName, - isAWSLambdaAgent, - isAzureFunctionsAgent, - isServerlessAgent, - isRumOrMobileAgent, + isAWSLambdaAgentName, + isAzureFunctionsAgentName, + isServerlessAgentName, + isRumOrMobileAgentName, } from '../../../../../common/agent_name'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { ApmServiceContextProvider } from '../../../../context/apm_service/apm_service_context'; @@ -185,13 +185,13 @@ export function isMetricsTabHidden({ serverlessType?: ServerlessType; isAwsLambdaEnabled?: boolean; }) { - if (isAWSLambdaAgent(serverlessType)) { + if (isAWSLambdaAgentName(serverlessType)) { return !isAwsLambdaEnabled; } return ( !agentName || isRumAgentName(agentName) || - isAzureFunctionsAgent(serverlessType) + isAzureFunctionsAgentName(serverlessType) ); } @@ -207,7 +207,7 @@ export function isInfraTabHidden({ return ( !agentName || isRumAgentName(agentName) || - isServerlessAgent(serverlessType) || + isServerlessAgentName(serverlessType) || !isInfraTabAvailable ); } @@ -320,7 +320,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.serviceDetails.metricsTabLabel', { defaultMessage: 'Metrics', }), - append: isServerlessAgent(serverlessType) && ( + append: isServerlessAgentName(serverlessType) && ( ), hidden: isMetricsTabHidden({ @@ -364,13 +364,13 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.home.serviceLogsTabLabel', { defaultMessage: 'Logs', }), - append: isServerlessAgent(serverlessType) && ( + append: isServerlessAgentName(serverlessType) && ( ), hidden: !agentName || isRumAgentName(agentName) || - isAzureFunctionsAgent(serverlessType), + isAzureFunctionsAgentName(serverlessType), }, { key: 'alerts', @@ -408,8 +408,8 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { }), hidden: !isProfilingAvailable || - isRumOrMobileAgent(agentName) || - isAWSLambdaAgent(serverlessType), + isRumOrMobileAgentName(agentName) || + isAWSLambdaAgentName(serverlessType), append: ( {i18n.translate('xpack.apm.universalProfiling.newLabel', { diff --git a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx index acddb4677bf0..3c9bde66ff3a 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/mobile_service_template/index.tsx @@ -24,13 +24,18 @@ import { useTimeRange } from '../../../../hooks/use_time_range'; import { getAlertingCapabilities } from '../../../alerting/utils/get_alerting_capabilities'; import { MobileSearchBar } from '../../../app/mobile/search_bar'; import { ServiceIcons } from '../../../shared/service_icons'; -import { BetaBadge } from '../../../shared/beta_badge'; import { TechnicalPreviewBadge } from '../../../shared/technical_preview_badge'; import { ApmMainTemplate } from '../apm_main_template'; import { AnalyzeDataButton } from '../apm_service_template/analyze_data_button'; type Tab = NonNullable[0] & { - key: 'overview' | 'transactions' | 'service-map' | 'alerts'; + key: + | 'overview' + | 'transactions' + | 'dependencies' + | 'errors-and-crashes' + | 'service-map' + | 'alerts'; hidden?: boolean; }; @@ -122,9 +127,6 @@ function TemplateWithContext({ end={end} /> - - - @@ -190,6 +192,26 @@ function useTabs({ selectedTabKey }: { selectedTabKey: Tab['key'] }) { } ), }, + { + key: 'dependencies', + href: router.link('/mobile-services/{serviceName}/dependencies', { + path: { serviceName }, + query, + }), + label: i18n.translate('xpack.apm.serviceDetails.dependenciesTabLabel', { + defaultMessage: 'Dependencies', + }), + }, + { + key: 'errors-and-crashes', + href: router.link('/mobile-services/{serviceName}/errors-and-crashes', { + path: { serviceName }, + query, + }), + label: i18n.translate('xpack.apm.serviceDetails.mobileErrorsTabLabel', { + defaultMessage: 'Errors & Crashes', + }), + }, { key: 'service-map', href: router.link('/mobile-services/{serviceName}/service-map', { diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx b/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx deleted file mode 100644 index be4dad7f1642..000000000000 --- a/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiCard, - EuiFlexGroup, - EuiFlexItem, - EuiImage, - EuiToolTip, -} from '@elastic/eui'; -import type { Story } from '@storybook/react'; -import React from 'react'; -import { AGENT_NAMES } from '../../../../common/agent_name'; -import { getAgentIcon } from './get_agent_icon'; -import { AgentIcon } from '.'; -import { MockApmPluginStorybook } from '../../../context/apm_plugin/mock_apm_plugin_storybook'; - -export default { - title: 'shared/AgentIcon', - component: AgentIcon, -}; - -export const List: Story = () => { - return ( - - - {AGENT_NAMES.map((agentName) => { - return ( - - -

    - - - -

    - - } - title={agentName} - description={ -
    - - - -
    - } - /> -
    - ); - })} -
    -
    - ); -}; diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.ts b/x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.ts deleted file mode 100644 index 04bc276dcfa6..000000000000 --- a/x-pack/plugins/apm/public/components/shared/agent_icon/get_agent_icon.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - isIosAgentName, - isRumAgentName, - isJavaAgentName, - isAndroidAgentName, - OPEN_TELEMETRY_AGENT_NAMES, -} from '../../../../common/agent_name'; -import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; -import defaultIcon from '../span_icon/icons/default.svg'; -import cppIcon from './icons/cpp.svg'; -import darkCppIcon from './icons/cpp_dark.svg'; -import dotNetIcon from './icons/dot_net.svg'; -import erlangIcon from './icons/erlang.svg'; -import darkErlangIcon from './icons/erlang_dark.svg'; -import goIcon from './icons/go.svg'; -import iosIcon from './icons/ios.svg'; -import darkIosIcon from './icons/ios_dark.svg'; -import javaIcon from './icons/java.svg'; -import nodeJsIcon from './icons/nodejs.svg'; -import ocamlIcon from './icons/ocaml.svg'; -import openTelemetryIcon from './icons/otel_default.svg'; -import phpIcon from './icons/php.svg'; -import pythonIcon from './icons/python.svg'; -import rubyIcon from './icons/ruby.svg'; -import rumJsIcon from './icons/rumjs.svg'; -import darkPhpIcon from './icons/php_dark.svg'; -import darkRumJsIcon from './icons/rumjs_dark.svg'; -import rustIcon from './icons/rust.svg'; -import darkRustIcon from './icons/rust_dark.svg'; -import androidIcon from './icons/android.svg'; - -const agentIcons: { [key: string]: string } = { - cpp: cppIcon, - dotnet: dotNetIcon, - erlang: erlangIcon, - go: goIcon, - ios: iosIcon, - java: javaIcon, - nodejs: nodeJsIcon, - ocaml: ocamlIcon, - opentelemetry: openTelemetryIcon, - php: phpIcon, - python: pythonIcon, - ruby: rubyIcon, - rum: rumJsIcon, - rust: rustIcon, - android: androidIcon, -}; - -const darkAgentIcons: { [key: string]: string } = { - ...agentIcons, - cpp: darkCppIcon, - erlang: darkErlangIcon, - ios: darkIosIcon, - php: darkPhpIcon, - rum: darkRumJsIcon, - rust: darkRustIcon, -}; - -// This only needs to be exported for testing purposes, since we stub the SVG -// import values in test. -export function getAgentIconKey(agentName: string) { - // Ignore case - const lowercasedAgentName = agentName.toLowerCase(); - - // RUM agent names - if (isRumAgentName(lowercasedAgentName)) { - return 'rum'; - } - - // Java agent names - if (isJavaAgentName(lowercasedAgentName)) { - return 'java'; - } - - if (isIosAgentName(lowercasedAgentName)) { - return 'ios'; - } - - if (isAndroidAgentName(lowercasedAgentName)) { - return 'android'; - } - - // Remove "opentelemetry/" prefix - const agentNameWithoutPrefix = lowercasedAgentName.replace( - /^opentelemetry\//, - '' - ); - - if (Object.keys(agentIcons).includes(agentNameWithoutPrefix)) { - return agentNameWithoutPrefix; - } - - // OpenTelemetry-only agents - if (OPEN_TELEMETRY_AGENT_NAMES.includes(lowercasedAgentName as AgentName)) { - return 'opentelemetry'; - } -} - -export function getAgentIcon( - agentName: string | undefined, - isDarkMode: boolean -) { - const key = agentName && getAgentIconKey(agentName); - if (!key) { - return defaultIcon; - } - return (isDarkMode ? darkAgentIcons[key] : agentIcons[key]) ?? defaultIcon; -} diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/get_serverless_icon.ts b/x-pack/plugins/apm/public/components/shared/agent_icon/get_serverless_icon.ts deleted file mode 100644 index 70af655b9f34..000000000000 --- a/x-pack/plugins/apm/public/components/shared/agent_icon/get_serverless_icon.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import defaultIcon from '../span_icon/icons/default.svg'; -import lambdaIcon from './icons/lambda.svg'; -import azureFunctionsIcon from './icons/functions.svg'; -import { ServerlessType } from '../../../../common/serverless'; - -type ServerlessIcons = Record; - -const serverlessIcons: ServerlessIcons = { - 'aws.lambda': lambdaIcon, - 'azure.functions': azureFunctionsIcon, -}; - -export function getServerlessIcon(serverlessType?: ServerlessType) { - if (!serverlessType) { - return defaultIcon; - } - return serverlessIcons[serverlessType] ?? defaultIcon; -} diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/index.tsx b/x-pack/plugins/apm/public/components/shared/agent_icon/index.tsx deleted file mode 100644 index b995e2bbe7cf..000000000000 --- a/x-pack/plugins/apm/public/components/shared/agent_icon/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiIcon, EuiIconProps } from '@elastic/eui'; -import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; -import { getAgentIcon } from './get_agent_icon'; -import { useTheme } from '../../../hooks/use_theme'; - -interface Props { - agentName?: AgentName; - size?: EuiIconProps['size']; -} - -export function AgentIcon(props: Props) { - const { agentName, size = 'l' } = props; - const theme = useTheme(); - const icon = getAgentIcon(agentName, theme.darkMode); - - return ; -} diff --git a/x-pack/plugins/apm/public/components/shared/critical_path_flamegraph/critical_path_flamegraph_tooltip.tsx b/x-pack/plugins/apm/public/components/shared/critical_path_flamegraph/critical_path_flamegraph_tooltip.tsx index e4687719cdfc..3551bffd07f0 100644 --- a/x-pack/plugins/apm/public/components/shared/critical_path_flamegraph/critical_path_flamegraph_tooltip.tsx +++ b/x-pack/plugins/apm/public/components/shared/critical_path_flamegraph/critical_path_flamegraph_tooltip.tsx @@ -14,6 +14,7 @@ import { import React from 'react'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { i18n } from '@kbn/i18n'; +import { AgentIcon } from '@kbn/custom-icons'; import type { CriticalPathResponse } from '../../../../server/routes/traces/get_aggregated_critical_path'; import { AGENT_NAME, @@ -25,7 +26,6 @@ import { TRANSACTION_TYPE, } from '../../../../common/es_fields/apm'; import { SpanIcon } from '../span_icon'; -import { AgentIcon } from '../agent_icon'; import { asPercent } from '../../../../common/utils/formatters'; export function CriticalPathFlamegraphTooltip({ @@ -86,7 +86,7 @@ export function CriticalPathFlamegraphTooltip({ - + {metadata[SERVICE_NAME]} diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/mobile/crash_detail_link.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/crash_detail_link.tsx new file mode 100644 index 000000000000..73d79529cf70 --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/crash_detail_link.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { TypeOf } from '@kbn/typed-react-router-config'; +import { EuiLink } from '@elastic/eui'; +import { mobileServiceDetailRoute } from '../../../../routing/mobile_service_detail'; +import { useApmRouter } from '../../../../../hooks/use_apm_router'; + +interface Props { + children: React.ReactNode; + title?: string; + serviceName: string; + groupId: string; + query: TypeOf< + typeof mobileServiceDetailRoute, + '/mobile-services/{serviceName}/errors-and-crashes' + >['query']; +} + +function CrashDetailLink({ serviceName, groupId, query, ...rest }: Props) { + const router = useApmRouter(); + const crashDetailsLink = router.link( + `/mobile-services/{serviceName}/errors-and-crashes/crashes/{groupId}`, + { + path: { + serviceName, + groupId, + }, + query, + } + ); + + return ( + + ); +} + +export { CrashDetailLink }; diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_detail_link.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_detail_link.tsx new file mode 100644 index 000000000000..7c77846fdaee --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_detail_link.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { TypeOf } from '@kbn/typed-react-router-config'; +import { EuiLink } from '@elastic/eui'; +import { useApmRouter } from '../../../../../hooks/use_apm_router'; +import { mobileServiceDetailRoute } from '../../../../routing/mobile_service_detail'; + +interface Props { + children: React.ReactNode; + title?: string; + serviceName: string; + groupId: string; + query: TypeOf< + typeof mobileServiceDetailRoute, + '/mobile-services/{serviceName}/errors-and-crashes' + >['query']; +} + +function ErrorDetailLink({ serviceName, groupId, query, ...rest }: Props) { + const router = useApmRouter(); + const errorDetailsLink = router.link( + `/mobile-services/{serviceName}/errors-and-crashes/errors/{groupId}`, + { + path: { + serviceName, + groupId, + }, + query, + } + ); + + return ( + + ); +} + +export { ErrorDetailLink }; diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_overview_link.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_overview_link.tsx new file mode 100644 index 000000000000..ad4f33707952 --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/links/apm/mobile/error_overview_link.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLink } from '@elastic/eui'; +import { TypeOf } from '@kbn/typed-react-router-config'; +import { useApmRouter } from '../../../../../hooks/use_apm_router'; +import { mobileServiceDetailRoute } from '../../../../routing/mobile_service_detail'; + +interface Props { + children: React.ReactNode; + title?: string; + serviceName: string; + query: TypeOf< + typeof mobileServiceDetailRoute, + '/mobile-services/{serviceName}/errors-and-crashes' + >['query']; +} + +export function ErrorOverviewLink({ serviceName, query, ...rest }: Props) { + const router = useApmRouter(); + const errorOverviewLink = router.link( + '/mobile-services/{serviceName}/errors-and-crashes', + { + path: { + serviceName, + }, + query, + } + ); + + return ( + + ); +} diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx index c3474f18d794..4cf6363811f8 100644 --- a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx @@ -6,6 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiText } from '@elastic/eui'; +import { AgentIcon } from '@kbn/custom-icons'; import { i18n } from '@kbn/i18n'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { TypeOf } from '@kbn/typed-react-router-config'; @@ -16,7 +17,6 @@ import { AgentName } from '../../../../../../typings/es_schemas/ui/fields/agent' import { useApmRouter } from '../../../../../hooks/use_apm_router'; import { truncate, unit } from '../../../../../utils/style'; import { ApmRoutes } from '../../../../routing/apm_route_config'; -import { AgentIcon } from '../../../agent_icon'; import { PopoverTooltip } from '../../../popover_tooltip'; import { TruncateWithTooltip } from '../../../truncate_with_tooltip'; import { OTHER_SERVICE_NAME, MaxGroupsMessage } from '../max_groups_message'; @@ -88,7 +88,7 @@ export function ServiceLink({ > - + {serviceName} diff --git a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx index dccce740b62d..1f066d1322eb 100644 --- a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_link.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { useLocation } from 'react-router-dom'; import rison from '@kbn/rison'; import url from 'url'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../../../common/data_view_constants'; +import { useDataViewId } from '../../../../hooks/use_data_view_id'; import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { getTimepickerRisonData } from '../rison_helpers'; @@ -37,16 +37,18 @@ export const getDiscoverHref = ({ basePath, location, query, + dataViewId, }: { basePath: IBasePath; location: Location; query: Props['query']; + dataViewId: string; }) => { const risonQuery = { _g: getTimepickerRisonData(location.search), _a: { ...query._a, - index: APM_STATIC_DATA_VIEW_ID, + index: dataViewId, }, }; @@ -62,11 +64,13 @@ export const getDiscoverHref = ({ export function DiscoverLink({ query = {}, ...rest }: Props) { const { core } = useApmPluginContext(); const location = useLocation(); + const dataViewId = useDataViewId(); const href = getDiscoverHref({ basePath: core.http.basePath, query, location, + dataViewId, }); return ; diff --git a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx index dfd14e3a172b..f4d95a87df5d 100644 --- a/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/discover_links/discover_links.integration.test.tsx @@ -35,7 +35,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:'processor.event:\\"transaction\\" AND transaction.id:\\"8b60bd32ecc6e150\\" AND trace.id:\\"8b60bd32ecc6e1506735a8b6cfcf175c\\"'))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:'processor.event:\\"transaction\\" AND transaction.id:\\"8b60bd32ecc6e150\\" AND trace.id:\\"8b60bd32ecc6e1506735a8b6cfcf175c\\"'))"` ); }); @@ -55,7 +55,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:'span.id:\\"test-span-id\\"'))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:'span.id:\\"test-span-id\\"'))"` ); }); @@ -77,7 +77,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\"'),sort:('@timestamp':desc))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\"'),sort:('@timestamp':desc))"` ); }); @@ -100,7 +100,7 @@ describe('DiscoverLinks', () => { ); expect(href).toMatchInlineSnapshot( - `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\" AND some:kuery-string'),sort:('@timestamp':desc))"` + `"/basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:'service.name:\\"service-name\\" AND error.grouping_key:\\"grouping-key\\" AND some:kuery-string'),sort:('@timestamp':desc))"` ); }); }); diff --git a/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx b/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx index a77c6b9c7c60..3ce8e3032db6 100644 --- a/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/service_icons/index.tsx @@ -7,12 +7,16 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { + CloudProvider, + getAgentIcon, + getCloudProviderIcon, + getServerlessIcon, +} from '@kbn/custom-icons'; import React, { ReactChild, useState } from 'react'; import { useTheme } from '../../../hooks/use_theme'; import { ContainerType } from '../../../../common/service_metadata'; import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; -import { getAgentIcon } from '../agent_icon/get_agent_icon'; -import { getServerlessIcon } from '../agent_icon/get_serverless_icon'; import { CloudDetails } from './cloud_details'; import { ServerlessDetails } from './serverless_details'; import { ContainerDetails } from './container_details'; @@ -21,7 +25,6 @@ import { IconPopover } from './icon_popover'; import { ServiceDetails } from './service_details'; import { ServerlessType } from '../../../../common/serverless'; import { isOpenTelemetryAgentName } from '../../../../common/agent_name'; -import openTelemetryIcon from '../agent_icon/icons/opentelemetry.svg'; interface Props { serviceName: string; @@ -30,12 +33,6 @@ interface Props { end: string; } -const cloudIcons: Record = { - gcp: 'logoGCP', - aws: 'logoAWS', - azure: 'logoAzure', -}; - function getServerlessTitle(serverlessType?: ServerlessType): string { switch (serverlessType) { case ServerlessType.AWS_LAMBDA: { @@ -56,12 +53,6 @@ function getServerlessTitle(serverlessType?: ServerlessType): string { } } -export function getCloudIcon(provider?: string) { - if (provider) { - return cloudIcons[provider]; - } -} - export function getContainerIcon(container?: ContainerType) { if (!container) { return; @@ -155,7 +146,7 @@ export function ServiceIcons({ start, end, serviceName, environment }: Props) { { key: 'opentelemetry', icon: { - type: openTelemetryIcon, + type: getAgentIcon('opentelemetry', theme.darkMode), }, isVisible: !!icons?.agentName && isOpenTelemetryAgentName(icons.agentName), @@ -197,7 +188,7 @@ export function ServiceIcons({ start, end, serviceName, environment }: Props) { { key: 'cloud', icon: { - type: getCloudIcon(icons?.cloudProvider), + type: getCloudProviderIcon(icons?.cloudProvider as CloudProvider), }, isVisible: !!icons?.cloudProvider, title: i18n.translate('xpack.apm.serviceIcons.cloud', { diff --git a/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts b/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts index 5c719d51d457..8952c7b78977 100644 --- a/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts +++ b/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { getAgentIcon } from '@kbn/custom-icons'; import { maybe } from '../../../../common/utils/maybe'; import awsIcon from './icons/aws.svg'; import cassandraIcon from './icons/cassandra.svg'; @@ -22,7 +23,6 @@ import mysqlIcon from './icons/mysql.svg'; import postgresqlIcon from './icons/postgresql.svg'; import redisIcon from './icons/redis.svg'; import websocketIcon from './icons/websocket.svg'; -import javaIcon from '../agent_icon/icons/java.svg'; import dynamodbIcon from './icons/dynamo_db.svg'; import sThreeIcon from './icons/s3.svg'; import snsIcon from './icons/sns.svg'; @@ -70,7 +70,7 @@ export const spanTypeIcons: { messaging: { azurequeue: storageQueueIcon, azureservicebus: serviceBusIcon, - jms: javaIcon, + jms: getAgentIcon('java'), kafka: kafkaIcon, sns: snsIcon, sqs: sqsIcon, diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts index fe8cb9d68fdf..7d7a720f27cf 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts @@ -77,6 +77,7 @@ describe('Transaction action menu', () => { rangeFrom: 'now-24h', rangeTo: 'now', environment: 'ENVIRONMENT_ALL', + dataViewId: 'apm_static_data_view_id_default', }) ).toEqual([ [ @@ -113,7 +114,7 @@ describe('Transaction action menu', () => { { key: 'sampleDocument', label: 'View transaction in Discover', - href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', + href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', condition: true, }, ], @@ -145,6 +146,7 @@ describe('Transaction action menu', () => { rangeFrom: 'now-24h', rangeTo: 'now', environment: 'ENVIRONMENT_ALL', + dataViewId: 'apm_static_data_view_id_default', }) ).toEqual([ [ @@ -200,7 +202,7 @@ describe('Transaction action menu', () => { { key: 'sampleDocument', label: 'View transaction in Discover', - href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', + href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', condition: true, }, ], @@ -232,6 +234,7 @@ describe('Transaction action menu', () => { rangeFrom: 'now-24h', rangeTo: 'now', environment: 'ENVIRONMENT_ALL', + dataViewId: 'apm_static_data_view_id_default', }) ).toEqual([ [ @@ -286,7 +289,7 @@ describe('Transaction action menu', () => { { key: 'sampleDocument', label: 'View transaction in Discover', - href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_index_pattern_id,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', + href: 'some-basepath/app/discover#/?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-24h,to:now))&_a=(index:apm_static_data_view_id_default,interval:auto,query:(language:kuery,query:\'processor.event:"transaction" AND transaction.id:"123" AND trace.id:"123"\'))', condition: true, }, ], diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts index a944a80a458f..b50bbd5239cc 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts @@ -55,6 +55,7 @@ export const getSections = ({ allDatasetsLocator, logsLocator, nodeLogsLocator, + dataViewId, }: { transaction?: Transaction; basePath: IBasePath; @@ -68,6 +69,7 @@ export const getSections = ({ allDatasetsLocator: LocatorPublic; logsLocator: LocatorPublic; nodeLogsLocator: LocatorPublic; + dataViewId: string; }) => { if (!transaction) return []; @@ -271,6 +273,7 @@ export const getSections = ({ basePath, query: getDiscoverQuery(transaction), location, + dataViewId, }), condition: true, }, diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx index 02664e370b9c..7895fdf7d059 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx @@ -32,6 +32,7 @@ import { NodeLogsLocatorParams, } from '@kbn/logs-shared-plugin/common'; import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public'; +import { useDataViewId } from '../../../hooks/use_data_view_id'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; @@ -138,6 +139,7 @@ function ActionMenuSections({ const { core, uiActions, share } = useApmPluginContext(); const location = useLocation(); const apmRouter = useApmRouter(); + const dataViewId = useDataViewId(); const allDatasetsLocator = share.url.locators.get( ALL_DATASETS_LOCATOR_ID @@ -173,6 +175,7 @@ function ActionMenuSections({ allDatasetsLocator, logsLocator, nodeLogsLocator, + dataViewId, }); const externalMenuItems = useAsync(() => { diff --git a/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts b/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts index 2f2d14714e51..57ad95dce2a5 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts @@ -12,11 +12,11 @@ import { useEffect, useState } from 'react'; import { ApmPluginStartDeps } from '../plugin'; import { callApmApi } from '../services/rest/create_call_apm_api'; -async function getApmDataViewTitle() { - const res = await callApmApi('GET /internal/apm/data_view/title', { +async function getApmDataViewIndexPattern() { + const res = await callApmApi('GET /internal/apm/data_view/index_pattern', { signal: null, }); - return res.apmDataViewTitle; + return res.apmDataViewIndexPattern; } export function useApmDataView() { @@ -25,11 +25,11 @@ export function useApmDataView() { useEffect(() => { async function fetchDataView() { - const title = await getApmDataViewTitle(); + const indexPattern = await getApmDataViewIndexPattern(); try { const displayError = false; return await services.dataViews.create( - { title }, + { title: indexPattern }, undefined, displayError ); diff --git a/x-pack/plugins/apm/public/hooks/use_crash_group_distribution_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_crash_group_distribution_fetcher.tsx new file mode 100644 index 000000000000..e094b2440f0b --- /dev/null +++ b/x-pack/plugins/apm/public/hooks/use_crash_group_distribution_fetcher.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { isTimeComparison } from '../components/shared/time_comparison/get_comparison_options'; +import { useAnyOfApmParams } from './use_apm_params'; +import { useFetcher } from './use_fetcher'; +import { useTimeRange } from './use_time_range'; + +export function useCrashGroupDistributionFetcher({ + serviceName, + groupId, + kuery, + environment, +}: { + serviceName: string; + groupId: string | undefined; + kuery: string; + environment: string; +}) { + const { + query: { rangeFrom, rangeTo, offset, comparisonEnabled }, + } = useAnyOfApmParams( + '/services/{serviceName}/errors', + '/mobile-services/{serviceName}/errors-and-crashes' + ); + + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + + const { data, status } = useFetcher( + (callApmApi) => { + if (start && end) { + return callApmApi( + 'GET /internal/apm/mobile-services/{serviceName}/crashes/distribution', + { + params: { + path: { serviceName }, + query: { + environment, + kuery, + start, + end, + offset: + comparisonEnabled && isTimeComparison(offset) + ? offset + : undefined, + groupId, + }, + }, + } + ); + } + }, + [ + environment, + kuery, + serviceName, + start, + end, + offset, + groupId, + comparisonEnabled, + ] + ); + + return { crashDistributionData: data, status }; +} diff --git a/x-pack/plugins/apm/public/hooks/use_current_user.ts b/x-pack/plugins/apm/public/hooks/use_current_user.ts index 0e95bb27bbb8..c700ae7bd288 100644 --- a/x-pack/plugins/apm/public/hooks/use_current_user.ts +++ b/x-pack/plugins/apm/public/hooks/use_current_user.ts @@ -7,7 +7,7 @@ import { useState, useEffect } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { ApmPluginStartDeps } from '../plugin'; export function useCurrentUser() { diff --git a/x-pack/plugins/apm/public/hooks/use_data_view_id.tsx b/x-pack/plugins/apm/public/hooks/use_data_view_id.tsx new file mode 100644 index 000000000000..3390471ff60e --- /dev/null +++ b/x-pack/plugins/apm/public/hooks/use_data_view_id.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useEffect, useState } from 'react'; +import { getDataViewId } from '../../common/data_view_constants'; +import { ApmPluginStartDeps } from '../plugin'; + +export function useDataViewId() { + const [dataViewId, setDataViewId] = useState( + getDataViewId('default') + ); + const { spaces } = useKibana().services; + + useEffect(() => { + const fetchSpaceId = async () => { + const space = await spaces?.getActiveSpace(); + setDataViewId(getDataViewId(space?.id ?? 'default')); + }; + + fetchSpaceId(); + }, [spaces]); + + return dataViewId; +} diff --git a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx index 2aa64472aa1d..bc8a2056cb41 100644 --- a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx @@ -5,7 +5,7 @@ * 2.0. */ import { isTimeComparison } from '../components/shared/time_comparison/get_comparison_options'; -import { useApmParams } from './use_apm_params'; +import { useAnyOfApmParams } from './use_apm_params'; import { useFetcher } from './use_fetcher'; import { useTimeRange } from './use_time_range'; @@ -22,7 +22,10 @@ export function useErrorGroupDistributionFetcher({ }) { const { query: { rangeFrom, rangeTo, offset, comparisonEnabled }, - } = useApmParams('/services/{serviceName}/errors'); + } = useAnyOfApmParams( + '/services/{serviceName}/errors', + '/mobile-services/{serviceName}/errors-and-crashes' + ); const { start, end } = useTimeRange({ rangeFrom, rangeTo }); diff --git a/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx index f1d30f423707..6ffebcb95f2a 100644 --- a/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_fallback_to_transactions_fetcher.tsx @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { getKueryWithMobileFilters } from '../../common/utils/get_kuery_with_mobile_filters'; import { useApmParams } from './use_apm_params'; import { useFetcher } from './use_fetcher'; @@ -33,11 +34,17 @@ export function useFallbackToTransactionsFetcher({ kuery }: { kuery: string }) { const { data = { fallbackToTransactions: false } } = useFetcher( (callApmApi) => { - return callApmApi('GET /internal/apm/fallback_to_transactions', { - params: { - query: { kuery: kueryWithFilters, start, end }, - }, - }); + if (start && end) { + return callApmApi('GET /internal/apm/fallback_to_transactions', { + params: { + query: { + kuery: kueryWithFilters, + start, + end, + }, + }, + }); + } }, [kueryWithFilters, start, end] ); diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts index fc6cfe8d3ee4..e27486c1e645 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts @@ -6,10 +6,7 @@ */ import { DeepPartial } from 'utility-types'; -import { - AgentName, - ElasticAgentName, -} from '../../../typings/es_schemas/ui/fields/agent'; +import { AgentName, ElasticAgentName } from '@kbn/elastic-agent-utils'; import { RollupInterval } from '../../../common/rollup'; export interface TimeframeMap { diff --git a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts index 346921960f92..4524d5121b78 100644 --- a/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts +++ b/x-pack/plugins/apm/server/lib/connections/get_connection_stats/get_stats.ts @@ -9,7 +9,6 @@ import { sum } from 'lodash'; import objectHash from 'object-hash'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { rangeQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values'; @@ -28,6 +27,8 @@ import { import { getBucketSize } from '../../../../common/utils/get_bucket_size'; import { EventOutcome } from '../../../../common/event_outcome'; import { NodeType } from '../../../../common/connections'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; import { excludeRumExitSpansQuery } from '../exclude_rum_exit_spans_query'; import { APMEventClient } from '../../helpers/create_es_client/create_apm_event_client'; import { getDocumentTypeFilterForServiceDestinationStatistics } from '../../helpers/spans/get_is_using_service_destination_metrics'; @@ -55,7 +56,12 @@ export const getStats = async ({ const response = await apmEventClient.search('get_connection_stats', { apm: { - events: [ProcessorEvent.metric], + sources: [ + { + documentType: ApmDocumentType.ServiceDestinationMetric, + rollupInterval: RollupInterval.OneMinute, + }, + ], }, body: { track_total_hits: true, diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/get_request_base.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/get_request_base.ts index 1046a2ad47cf..85ac6689f5df 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/get_request_base.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/get_request_base.ts @@ -57,9 +57,9 @@ export function getRequestBase(options: { if ('sources' in options.apm) { options.apm.sources.forEach((source) => { - const { getQuery } = getConfigForDocumentType(source.documentType); - if (getQuery) { - filters.push(getQuery(source.rollupInterval)); + const documentTypeConfig = getConfigForDocumentType(source.documentType); + if ('getQuery' in documentTypeConfig) { + filters.push(documentTypeConfig.getQuery(source.rollupInterval)); } }); } diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts index fcac29b1d57d..53e4c91f384f 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.ts @@ -62,13 +62,11 @@ type APMEventTermsEnumRequest = APMEventWrapper; type APMEventEqlSearchRequest = APMEventWrapper; type APMEventFieldCapsRequest = APMEventWrapper; -// These keys shoul all be `ProcessorEvent.x`, but until TypeScript 4.2 we're inlining them here. -// See https://github.com/microsoft/TypeScript/issues/37888 type TypeOfProcessorEvent = { - error: APMError; - transaction: Transaction; - span: Span; - metric: Metric; + [ProcessorEvent.error]: APMError; + [ProcessorEvent.transaction]: Transaction; + [ProcessorEvent.span]: Span; + [ProcessorEvent.metric]: Metric; }[T]; type TypedLogEventSearchResponse = @@ -77,15 +75,13 @@ type TypedLogEventSearchResponse = type TypedSearchResponse = InferSearchResponseOf< TypeOfProcessorEvent< - ValuesType< - TParams['apm'] extends { events: ProcessorEvent[] } - ? TParams['apm']['events'] - : TParams['apm'] extends { sources: ApmDataSource[] } - ? ProcessorEventOfDocumentType< - ValuesType['documentType'] - > - : never - > + TParams['apm'] extends { events: ProcessorEvent[] } + ? ValuesType + : TParams['apm'] extends { sources: ApmDataSource[] } + ? ProcessorEventOfDocumentType< + ValuesType['documentType'] + > + : never >, TParams >; diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/document_type.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/document_type.ts index a3f5ff8d5683..bcafd76b8e22 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/document_type.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/document_type.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { ApmDocumentType } from '../../../../common/document_type'; import { @@ -33,18 +32,11 @@ function getDefaultFilter( ]; } -const documentTypeConfigMap: Record< - ApmDocumentType, - { - processorEvent: ProcessorEvent; - getQuery?: (rollupInterval: RollupInterval) => QueryDslQueryContainer; - rollupIntervals: RollupInterval[]; - } -> = { +const documentTypeConfigMap = { [ApmDocumentType.ServiceTransactionMetric]: { processorEvent: ProcessorEvent.metric, - getQuery: (rollupInterval) => ({ + getQuery: (rollupInterval: RollupInterval) => ({ bool: { filter: getDefaultFilter('service_transaction', rollupInterval), }, @@ -53,7 +45,7 @@ const documentTypeConfigMap: Record< }, [ApmDocumentType.ServiceSummaryMetric]: { processorEvent: ProcessorEvent.metric, - getQuery: (rollupInterval) => ({ + getQuery: (rollupInterval: RollupInterval) => ({ bool: { filter: getDefaultFilter('service_summary', rollupInterval), }, @@ -62,7 +54,7 @@ const documentTypeConfigMap: Record< }, [ApmDocumentType.TransactionMetric]: { processorEvent: ProcessorEvent.metric, - getQuery: (rollupInterval) => ({ + getQuery: (rollupInterval: RollupInterval) => ({ bool: { filter: rollupInterval === RollupInterval.OneMinute @@ -79,7 +71,7 @@ const documentTypeConfigMap: Record< [ApmDocumentType.ServiceDestinationMetric]: { processorEvent: ProcessorEvent.metric, rollupIntervals: defaultRollupIntervals, - getQuery: (rollupInterval) => ({ + getQuery: (rollupInterval: RollupInterval) => ({ bool: { filter: rollupInterval === RollupInterval.OneMinute @@ -92,7 +84,11 @@ const documentTypeConfigMap: Record< processorEvent: ProcessorEvent.error, rollupIntervals: [RollupInterval.None], }, -}; + [ApmDocumentType.SpanEvent]: { + processorEvent: ProcessorEvent.span, + rollupIntervals: [RollupInterval.None], + }, +} as const; type DocumentTypeConfigOf = typeof documentTypeConfigMap[TApmDocumentType]; diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap index 325ce29af118..192df5cc8eb3 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/__snapshots__/get_is_using_transaction_events.test.ts.snap @@ -96,8 +96,11 @@ Array [ "get_has_transactions", Object { "apm": Object { - "events": Array [ - "transaction", + "sources": Array [ + Object { + "documentType": "transactionEvent", + "rollupInterval": "none", + }, ], }, "body": Object { diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts index 20832c70d007..0ba5fb5f92af 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/get_is_using_transaction_events.ts @@ -6,10 +6,11 @@ */ import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { getSearchTransactionsEvents } from '.'; import { APMEventClient } from '../create_es_client/create_apm_event_client'; import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; import { APMConfig } from '../../..'; export async function getIsUsingTransactionEvents({ @@ -63,7 +64,12 @@ async function getHasTransactions({ }) { const response = await apmEventClient.search('get_has_transactions', { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: 1, diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 525b2c5e2cbc..07010d5f8dc5 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -11,7 +11,6 @@ import { Logger, Plugin, PluginInitializerContext, - SavedObjectsClient, } from '@kbn/core/server'; import { isEmpty, mapValues } from 'lodash'; import { Dataset } from '@kbn/rule-registry-plugin/server'; @@ -50,7 +49,6 @@ import { scheduleSourceMapMigration } from './routes/source_maps/schedule_source import { createApmSourceMapIndexTemplate } from './routes/source_maps/create_apm_source_map_index_template'; import { addApiKeysToEveryPackagePolicyIfMissing } from './routes/fleet/api_keys/add_api_keys_to_policies_if_missing'; import { apmTutorialCustomIntegration } from '../common/tutorial/tutorials'; -import { APM_STATIC_DATA_VIEW_ID } from '../common/data_view_constants'; export class APMPlugin implements @@ -123,26 +121,6 @@ export class APMPlugin ], }); - // ensure that the APM data view is globally available - getCoreStart() - .then(async (coreStart) => { - const soClient = new SavedObjectsClient( - coreStart.savedObjects.createInternalRepository() - ); - - await soClient.updateObjectsSpaces( - [{ id: APM_STATIC_DATA_VIEW_ID, type: 'index-pattern' }], - ['*'], - [] - ); - }) - .catch((e) => { - this.logger?.error( - 'Failed to make APM data view available globally', - e - ); - }); - const resourcePlugins = mapValues(plugins, (value, key) => { return { setup: value, diff --git a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts index f4e6c1aaa98d..dbe306999571 100644 --- a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts @@ -165,7 +165,6 @@ export function registerRoutes({ _inspect: inspectableEsQueriesMap.get(request), } : { ...data }; - if (!options.disableTelemetry && telemetryUsageCounter) { telemetryUsageCounter.incrementCounter({ counterName: `${method.toUpperCase()} ${pathname}`, diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts index 714f97b1a480..c3c1d7f124a5 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts @@ -5,20 +5,22 @@ * 2.0. */ -import { createStaticDataView } from './create_static_data_view'; -import * as HistoricalAgentData from '../historical_data/has_historical_agent_data'; +import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; +import { Logger } from '@kbn/core/server'; import { DataViewsService } from '@kbn/data-views-plugin/common'; -import { APMCore } from '../typings'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; -import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; import { APMRouteHandlerResources } from '../apm_routes/register_apm_server_routes'; +import * as HistoricalAgentData from '../historical_data/has_historical_agent_data'; +import { APMCore } from '../typings'; +import { createStaticDataView } from './create_static_data_view'; function getMockedDataViewService(existingDataViewTitle: string) { return { get: jest.fn(() => ({ - title: existingDataViewTitle, + getIndexPattern: () => existingDataViewTitle, })), createAndSave: jest.fn(), + delete: () => {}, } as unknown as DataViewsService; } @@ -36,6 +38,10 @@ const coreMock = { }, } as unknown as APMCore; +const logger = { + info: jest.fn, +} as unknown as Logger; + const apmEventClientMock = { search: jest.fn(), indices: { @@ -55,6 +61,8 @@ describe('createStaticDataView', () => { config: { autoCreateApmDataView: false }, } as APMRouteHandlerResources, dataViewService, + spaceId: 'default', + logger, }); expect(dataViewService.createAndSave).not.toHaveBeenCalled(); }); @@ -73,6 +81,8 @@ describe('createStaticDataView', () => { config: { autoCreateApmDataView: false }, } as APMRouteHandlerResources, dataViewService, + spaceId: 'default', + logger, }); expect(dataViewService.createAndSave).not.toHaveBeenCalled(); }); @@ -92,6 +102,8 @@ describe('createStaticDataView', () => { config: { autoCreateApmDataView: true }, } as APMRouteHandlerResources, dataViewService, + spaceId: 'default', + logger, }); expect(dataViewService.createAndSave).toHaveBeenCalled(); @@ -114,6 +126,8 @@ describe('createStaticDataView', () => { config: { autoCreateApmDataView: true }, } as APMRouteHandlerResources, dataViewService, + spaceId: 'default', + logger, }); expect(dataViewService.get).toHaveBeenCalled(); @@ -143,6 +157,8 @@ describe('createStaticDataView', () => { config: { autoCreateApmDataView: true }, } as APMRouteHandlerResources, dataViewService, + spaceId: 'default', + logger, }); expect(dataViewService.get).toHaveBeenCalled(); diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts index 715a568eaf6b..5f2cf097f3e2 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts @@ -5,18 +5,21 @@ * 2.0. */ -import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { Logger, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DataView, DataViewsService } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; +import { + DO_NOT_USE_LEGACY_APM_STATIC_DATA_VIEW_ID, + getDataViewId, +} from '../../../common/data_view_constants'; import { TRACE_ID, TRANSACTION_ID, TRANSACTION_DURATION, } from '../../../common/es_fields/apm'; -import { APM_STATIC_DATA_VIEW_ID } from '../../../common/data_view_constants'; import { hasHistoricalAgentData } from '../historical_data/has_historical_agent_data'; import { withApmSpan } from '../../utils/with_apm_span'; -import { getApmDataViewTitle } from './get_apm_data_view_title'; +import { getApmDataViewIndexPattern } from './get_apm_data_view_index_pattern'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { APMRouteHandlerResources } from '../apm_routes/register_apm_server_routes'; @@ -29,12 +32,18 @@ export async function createStaticDataView({ dataViewService, resources, apmEventClient, + spaceId, + logger, }: { dataViewService: DataViewsService; resources: APMRouteHandlerResources; apmEventClient: APMEventClient; + spaceId: string; + logger: Logger; }): CreateDataViewResponse { const { config } = resources; + const dataViewId = getDataViewId(spaceId); + logger.info(`create static data view ${dataViewId}`); return withApmSpan('create_static_data_view', async () => { // don't auto-create APM data view if it's been disabled via the config @@ -61,10 +70,13 @@ export async function createStaticDataView({ }; } - const apmDataViewTitle = getApmDataViewTitle(apmEventClient.indices); + const apmDataViewIndexPattern = getApmDataViewIndexPattern( + apmEventClient.indices + ); const shouldCreateOrUpdate = await getShouldCreateOrUpdate({ - apmDataViewTitle, + apmDataViewIndexPattern, dataViewService, + dataViewId, }); if (!shouldCreateOrUpdate) { @@ -72,52 +84,48 @@ export async function createStaticDataView({ created: false, reason: i18n.translate( 'xpack.apm.dataView.alreadyExistsInActiveSpace', - { defaultMessage: 'Dataview already exists in the active space' } + { + defaultMessage: + 'Dataview already exists in the active space and does not need to be updated', + } ), }; } - return await withApmSpan('create_data_view', async () => { - try { - const dataView = await createAndSaveStaticDataView({ - dataViewService, - apmDataViewTitle, - }); - - await addDataViewToAllSpaces(resources); - - return { created: true, dataView }; - } catch (e) { - // if the data view (saved object) already exists a conflict error (code: 409) will be thrown - if (SavedObjectsErrorHelpers.isConflictError(e)) { - return { - created: false, - reason: i18n.translate( - 'xpack.apm.dataView.alreadyExistsInAnotherSpace', - { - defaultMessage: - 'Dataview already exists in another space but is not made available in this space', - } - ), - }; - } + // delete legacy global data view + + const dataView = await createAndSaveStaticDataView({ + dataViewService, + apmDataViewIndexPattern, + dataViewId, + }); + + try { + await dataViewService.delete(DO_NOT_USE_LEGACY_APM_STATIC_DATA_VIEW_ID); + } catch (e) { + // swallow error if caused by the data view (saved object) not existing + if (!SavedObjectsErrorHelpers.isNotFoundError(e)) { throw e; } - }); + } + + return { created: true, dataView }; }); } // only create data view if it doesn't exist or was changed async function getShouldCreateOrUpdate({ dataViewService, - apmDataViewTitle, + apmDataViewIndexPattern, + dataViewId, }: { dataViewService: DataViewsService; - apmDataViewTitle: string; + apmDataViewIndexPattern: string; + dataViewId: string; }) { try { - const existingDataView = await dataViewService.get(APM_STATIC_DATA_VIEW_ID); - return existingDataView.title !== apmDataViewTitle; + const existingDataView = await dataViewService.get(dataViewId); + return existingDataView.getIndexPattern() !== apmDataViewIndexPattern; } catch (e) { // ignore exception if the data view (saved object) is not found if (SavedObjectsErrorHelpers.isNotFoundError(e)) { @@ -128,32 +136,21 @@ async function getShouldCreateOrUpdate({ } } -async function addDataViewToAllSpaces(resources: APMRouteHandlerResources) { - const { request, core } = resources; - const startServices = await core.start(); - const scopedClient = startServices.savedObjects.getScopedClient(request); - - // make data view available across all spaces - return scopedClient.updateObjectsSpaces( - [{ id: APM_STATIC_DATA_VIEW_ID, type: 'index-pattern' }], - ['*'], - [] - ); -} - function createAndSaveStaticDataView({ dataViewService, - apmDataViewTitle, + apmDataViewIndexPattern, + dataViewId, }: { dataViewService: DataViewsService; - apmDataViewTitle: string; + apmDataViewIndexPattern: string; + dataViewId: string; }) { return dataViewService.createAndSave( { allowNoIndex: true, - id: APM_STATIC_DATA_VIEW_ID, + id: dataViewId, name: 'APM', - title: apmDataViewTitle, + title: apmDataViewIndexPattern, timeFieldName: '@timestamp', // link to APM from Discover diff --git a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.test.ts b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.test.ts new file mode 100644 index 000000000000..e7a0ee915c8c --- /dev/null +++ b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; +import { getApmDataViewIndexPattern } from './get_apm_data_view_index_pattern'; + +describe('getApmDataViewIndexPattern', () => { + it('returns a data view index pattern by combining existing indices', () => { + const indexPattern = getApmDataViewIndexPattern({ + transaction: 'apm-*-transaction-*', + span: 'apm-*-span-*', + error: 'apm-*-error-*', + metric: 'apm-*-metrics-*', + } as APMIndices); + expect(indexPattern).toBe( + 'apm-*-transaction-*,apm-*-span-*,apm-*-error-*,apm-*-metrics-*' + ); + }); + + it('removes duplicates', () => { + const title = getApmDataViewIndexPattern({ + transaction: 'apm-*', + span: 'apm-*', + error: 'apm-*', + metric: 'apm-*', + } as APMIndices); + expect(title).toBe('apm-*'); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.ts b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.ts new file mode 100644 index 000000000000..b5c3fa0f73d2 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_index_pattern.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { uniq } from 'lodash'; +import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; + +export function getApmDataViewIndexPattern(apmIndices: APMIndices) { + return uniq([ + apmIndices.transaction, + apmIndices.span, + apmIndices.error, + apmIndices.metric, + ]).join(','); +} diff --git a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.test.ts b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.test.ts deleted file mode 100644 index a8dc25e49300..000000000000 --- a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; -import { getApmDataViewTitle } from './get_apm_data_view_title'; - -describe('getApmDataViewTitle', () => { - it('returns a data view title by combining existing indicies', () => { - const title = getApmDataViewTitle({ - transaction: 'apm-*-transaction-*', - span: 'apm-*-span-*', - error: 'apm-*-error-*', - metric: 'apm-*-metrics-*', - } as APMIndices); - expect(title).toBe( - 'apm-*-transaction-*,apm-*-span-*,apm-*-error-*,apm-*-metrics-*' - ); - }); - - it('removes duplicates', () => { - const title = getApmDataViewTitle({ - transaction: 'apm-*', - span: 'apm-*', - error: 'apm-*', - metric: 'apm-*', - } as APMIndices); - expect(title).toBe('apm-*'); - }); -}); diff --git a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.ts b/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.ts deleted file mode 100644 index 3061a1ac1571..000000000000 --- a/x-pack/plugins/apm/server/routes/data_view/get_apm_data_view_title.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { uniq } from 'lodash'; -import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; - -export function getApmDataViewTitle(apmIndices: APMIndices) { - return uniq([ - apmIndices.transaction, - apmIndices.span, - apmIndices.error, - apmIndices.metric, - ]).join(','); -} diff --git a/x-pack/plugins/apm/server/routes/data_view/route.ts b/x-pack/plugins/apm/server/routes/data_view/route.ts index 388884c4f576..429b74c99e63 100644 --- a/x-pack/plugins/apm/server/routes/data_view/route.ts +++ b/x-pack/plugins/apm/server/routes/data_view/route.ts @@ -5,22 +5,32 @@ * 2.0. */ +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { CreateDataViewResponse, createStaticDataView, } from './create_static_data_view'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; -import { getApmDataViewTitle } from './get_apm_data_view_title'; +import { getApmDataViewIndexPattern } from './get_apm_data_view_index_pattern'; import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; const staticDataViewRoute = createApmServerRoute({ endpoint: 'POST /internal/apm/data_view/static', options: { tags: ['access:apm'] }, handler: async (resources): CreateDataViewResponse => { - const { context, plugins, request } = resources; + const { context, plugins, request, logger } = resources; const apmEventClient = await getApmEventClient(resources); const coreContext = await context.core; + // get name of selected (name)space + const spacesStart = await plugins.spaces?.start(); + const spaceId = + spacesStart?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; + + if (!spaceId) { + throw new Error('No spaceId found'); + } + const dataViewStart = await plugins.dataViews.start(); const dataViewService = await dataViewStart.dataViewsServiceFactory( coreContext.savedObjects.client, @@ -33,6 +43,8 @@ const staticDataViewRoute = createApmServerRoute({ dataViewService, resources, apmEventClient, + spaceId, + logger, }); return res; @@ -40,13 +52,15 @@ const staticDataViewRoute = createApmServerRoute({ }); const dataViewTitleRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/data_view/title', + endpoint: 'GET /internal/apm/data_view/index_pattern', options: { tags: ['access:apm'] }, - handler: async ({ getApmIndices }): Promise<{ apmDataViewTitle: string }> => { + handler: async ({ + getApmIndices, + }): Promise<{ apmDataViewIndexPattern: string }> => { const apmIndicies = await getApmIndices(); - const apmDataViewTitle = getApmDataViewTitle(apmIndicies); + const apmDataViewIndexPattern = getApmDataViewIndexPattern(apmIndicies); - return { apmDataViewTitle }; + return { apmDataViewIndexPattern }; }, }); diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/get_buckets.test.ts.snap b/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/get_buckets.test.ts.snap index 54705647dc6a..7d8d396a01de 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/get_buckets.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/get_buckets.test.ts.snap @@ -6,8 +6,11 @@ Array [ "get_error_distribution_buckets", Object { "apm": Object { - "events": Array [ - "error", + "sources": Array [ + Object { + "documentType": "error", + "rollupInterval": "none", + }, ], }, "body": Object { @@ -47,6 +50,11 @@ Array [ }, }, ], + "must_not": Object { + "term": Object { + "error.type": "crash", + }, + }, }, }, "size": 0, diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/queries.test.ts.snap index a3127ee28c0b..3ef42dc70bce 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/errors/distribution/__snapshots__/queries.test.ts.snap @@ -3,8 +3,11 @@ exports[`error distribution queries fetches an error distribution 1`] = ` Object { "apm": Object { - "events": Array [ - "error", + "sources": Array [ + Object { + "documentType": "error", + "rollupInterval": "none", + }, ], }, "body": Object { @@ -39,6 +42,11 @@ Object { }, }, ], + "must_not": Object { + "term": Object { + "error.type": "crash", + }, + }, }, }, "size": 0, @@ -50,8 +58,11 @@ Object { exports[`error distribution queries fetches an error distribution with a group id 1`] = ` Object { "apm": Object { - "events": Array [ - "error", + "sources": Array [ + Object { + "documentType": "error", + "rollupInterval": "none", + }, ], }, "body": Object { @@ -91,6 +102,11 @@ Object { }, }, ], + "must_not": Object { + "term": Object { + "error.type": "crash", + }, + }, }, }, "size": 0, diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts index 4a3fc6d969cd..a8994fd4ec2c 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.test.ts @@ -6,7 +6,8 @@ */ import { getBuckets } from './get_buckets'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; describe('get buckets', () => { let clientSpy: jest.Mock; @@ -42,6 +43,11 @@ describe('get buckets', () => { it('should limit query results to error documents', () => { const query = clientSpy.mock.calls[0][1]; - expect(query.apm.events).toEqual([ProcessorEvent.error]); + expect(query.apm.sources).toEqual([ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ]); }); }); diff --git a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts index 72e9b1c1b2d5..b0e6835ba921 100644 --- a/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/routes/errors/distribution/get_buckets.ts @@ -10,8 +10,9 @@ import { kqlQuery, termQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { ApmDocumentType } from '../../../../common/document_type'; import { ERROR_GROUP_ID, SERVICE_NAME } from '../../../../common/es_fields/apm'; +import { RollupInterval } from '../../../../common/rollup'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; @@ -36,13 +37,21 @@ export async function getBuckets({ }) { const params = { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, size: 0, query: { bool: { + must_not: { + term: { 'error.type': 'crash' }, + }, filter: [ { term: { [SERVICE_NAME]: serviceName } }, ...rangeQuery(start, end), diff --git a/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts b/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts index 31695c0a127d..41f49959aa70 100644 --- a/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts +++ b/x-pack/plugins/apm/server/routes/errors/erroneous_transactions/get_top_erroneous_transactions.ts @@ -17,7 +17,6 @@ import { kqlQuery, termQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { keyBy } from 'lodash'; import { ERROR_GROUP_ID, @@ -28,6 +27,8 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { getBucketSize } from '../../../../common/utils/get_bucket_size'; import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; async function getTopErroneousTransactions({ @@ -65,7 +66,12 @@ async function getTopErroneousTransactions({ const res = await apmEventClient.search('get_top_erroneous_transactions', { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, @@ -112,17 +118,19 @@ async function getTopErroneousTransactions({ return ( res.aggregations?.top_five_transactions.buckets.map( - ({ key, doc_count: docCount, sample, timeseries }) => ({ - transactionName: key as string, - transactionType: sample.hits.hits[0]._source.transaction?.type, - occurrences: docCount, - timeseries: timeseries.buckets.map((timeseriesBucket) => { - return { - x: timeseriesBucket.key + offsetInMs, - y: timeseriesBucket.doc_count, - }; - }), - }) + ({ key, doc_count: docCount, sample, timeseries }) => { + return { + transactionName: key as string, + transactionType: sample.hits.hits[0]._source.transaction?.type, + occurrences: docCount, + timeseries: timeseries.buckets.map((timeseriesBucket) => { + return { + x: timeseriesBucket.key + offsetInMs, + y: timeseriesBucket.doc_count, + }; + }), + }; + } ) ?? [] ); } diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts index cf799a47f7dc..182fe0a1cdd8 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts @@ -11,7 +11,6 @@ import { rangeQuery, termQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { ERROR_CULPRIT, ERROR_EXC_HANDLED, @@ -26,6 +25,8 @@ import { import { environmentQuery } from '../../../../common/utils/environment_query'; import { getErrorName } from '../../../lib/helpers/get_error_name'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; export type ErrorGroupMainStatisticsResponse = Array<{ groupId: string; @@ -75,7 +76,12 @@ export async function getErrorGroupMainStatistics({ 'get_error_group_main_statistics', { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, @@ -128,16 +134,19 @@ export async function getErrorGroupMainStatistics({ ); return ( - response.aggregations?.error_groups.buckets.map((bucket) => ({ - groupId: bucket.key as string, - name: getErrorName(bucket.sample.hits.hits[0]._source), - lastSeen: new Date( - bucket.sample.hits.hits[0]?._source['@timestamp'] - ).getTime(), - occurrences: bucket.doc_count, - culprit: bucket.sample.hits.hits[0]?._source.error.culprit, - handled: bucket.sample.hits.hits[0]?._source.error.exception?.[0].handled, - type: bucket.sample.hits.hits[0]?._source.error.exception?.[0].type, - })) ?? [] + response.aggregations?.error_groups.buckets.map((bucket) => { + return { + groupId: bucket.key as string, + name: getErrorName(bucket.sample.hits.hits[0]._source), + lastSeen: new Date( + bucket.sample.hits.hits[0]._source['@timestamp'] + ).getTime(), + occurrences: bucket.doc_count, + culprit: bucket.sample.hits.hits[0]._source.error.culprit, + handled: + bucket.sample.hits.hits[0]._source.error.exception?.[0].handled, + type: bucket.sample.hits.hits[0]._source.error.exception?.[0].type, + }; + }) ?? [] ); } diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample_ids.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample_ids.ts index 2796ec590ad4..0a154d3ad13f 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample_ids.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_group_sample_ids.ts @@ -6,7 +6,6 @@ */ import { rangeQuery, kqlQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; import { ERROR_GROUP_ID, @@ -16,6 +15,8 @@ import { } from '../../../../common/es_fields/apm'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; const ERROR_SAMPLES_SIZE = 10000; @@ -41,9 +42,14 @@ export async function getErrorGroupSampleIds({ start: number; end: number; }): Promise { - const params = { + const resp = await apmEventClient.search('get_error_group_sample_ids', { apm: { - events: [ProcessorEvent.error as const], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: ERROR_SAMPLES_SIZE, @@ -66,13 +72,11 @@ export async function getErrorGroupSampleIds({ { '@timestamp': { order: 'desc' } }, // sort by timestamp to get the most recent error ] as const), }, - }; - - const resp = await apmEventClient.search( - 'get_error_group_sample_ids', - params - ); - const errorSampleIds = resp.hits.hits.map((item) => item._source.error.id); + }); + const errorSampleIds = resp.hits.hits.map((item) => { + const source = item._source; + return source.error.id; + }); return { errorSampleIds, diff --git a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts index cb11c0154be6..348949d3ecca 100644 --- a/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts +++ b/x-pack/plugins/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts @@ -6,9 +6,10 @@ */ import { rangeQuery, kqlQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { ERROR_ID, SERVICE_NAME } from '../../../../common/es_fields/apm'; import { environmentQuery } from '../../../../common/utils/environment_query'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { getTransaction } from '../../transactions/get_transaction'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; @@ -38,7 +39,12 @@ export async function getErrorSampleDetails({ }): Promise { const params = { apm: { - events: [ProcessorEvent.error as const], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent as const, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts index 8deb85264e01..b6ea22e03d50 100644 --- a/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts +++ b/x-pack/plugins/apm/server/routes/metrics/serverless/get_serverless_summary.ts @@ -10,6 +10,7 @@ import { kqlQuery, rangeQuery, } from '@kbn/observability-plugin/server'; +import { ApmDocumentType } from '../../../../common/document_type'; import { FAAS_BILLED_DURATION, FAAS_DURATION, @@ -20,6 +21,7 @@ import { METRIC_SYSTEM_TOTAL_MEMORY, SERVICE_NAME, } from '../../../../common/es_fields/apm'; +import { RollupInterval } from '../../../../common/rollup'; import { environmentQuery } from '../../../../common/utils/environment_query'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; import { computeUsageAvgScript } from './get_compute_usage_chart'; @@ -52,7 +54,12 @@ async function getServerlessTransactionThroughput({ }) { const params = { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: true, diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/get_buckets.test.ts.snap b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/get_buckets.test.ts.snap new file mode 100644 index 000000000000..5c8b2ed593e9 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/get_buckets.test.ts.snap @@ -0,0 +1,63 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`get buckets should make the correct query 1`] = ` +Array [ + Array [ + "get_error_distribution_buckets", + Object { + "apm": Object { + "events": Array [ + "error", + ], + }, + "body": Object { + "aggs": Object { + "distribution": Object { + "histogram": Object { + "extended_bounds": Object { + "max": 1528977600000, + "min": 1528113600000, + }, + "field": "@timestamp", + "interval": 10, + "min_doc_count": 0, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "error.type": "crash", + }, + }, + Object { + "term": Object { + "service.name": "myServiceName", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, + Object { + "term": Object { + "service.environment": "prod", + }, + }, + ], + }, + }, + "size": 0, + "track_total_hits": false, + }, + }, + ], +] +`; diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/queries.test.ts.snap new file mode 100644 index 000000000000..447ac8b73633 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/__snapshots__/queries.test.ts.snap @@ -0,0 +1,110 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`error distribution queries fetches an error distribution 1`] = ` +Object { + "apm": Object { + "events": Array [ + "error", + ], + }, + "body": Object { + "aggs": Object { + "distribution": Object { + "histogram": Object { + "extended_bounds": Object { + "max": 50000, + "min": 0, + }, + "field": "@timestamp", + "interval": 3333, + "min_doc_count": 0, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "error.type": "crash", + }, + }, + Object { + "term": Object { + "service.name": "serviceName", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 0, + "lte": 50000, + }, + }, + }, + ], + }, + }, + "size": 0, + "track_total_hits": false, + }, +} +`; + +exports[`error distribution queries fetches an error distribution with a group id 1`] = ` +Object { + "apm": Object { + "events": Array [ + "error", + ], + }, + "body": Object { + "aggs": Object { + "distribution": Object { + "histogram": Object { + "extended_bounds": Object { + "max": 50000, + "min": 0, + }, + "field": "@timestamp", + "interval": 3333, + "min_doc_count": 0, + }, + }, + }, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "term": Object { + "error.type": "crash", + }, + }, + Object { + "term": Object { + "service.name": "serviceName", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 0, + "lte": 50000, + }, + }, + }, + Object { + "term": Object { + "error.grouping_key": "foo", + }, + }, + ], + }, + }, + "size": 0, + "track_total_hits": false, + }, +} +`; diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.test.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.test.ts new file mode 100644 index 000000000000..4a3fc6d969cd --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getBuckets } from './get_buckets'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; + +describe('get buckets', () => { + let clientSpy: jest.Mock; + + beforeEach(async () => { + clientSpy = jest.fn().mockResolvedValueOnce({ + hits: { + total: 100, + }, + aggregations: { + distribution: { + buckets: [], + }, + }, + }); + + await getBuckets({ + environment: 'prod', + serviceName: 'myServiceName', + bucketSize: 10, + kuery: '', + apmEventClient: { + search: clientSpy, + } as any, + start: 1528113600000, + end: 1528977600000, + }); + }); + + it('should make the correct query', () => { + expect(clientSpy.mock.calls).toMatchSnapshot(); + }); + + it('should limit query results to error documents', () => { + const query = clientSpy.mock.calls[0][1]; + expect(query.apm.events).toEqual([ProcessorEvent.error]); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.ts new file mode 100644 index 000000000000..8fe2ec16c2d4 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_buckets.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + rangeQuery, + kqlQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + ERROR_GROUP_ID, + SERVICE_NAME, + ERROR_TYPE, +} from '../../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; + +export async function getBuckets({ + environment, + kuery, + serviceName, + groupId, + bucketSize, + apmEventClient, + start, + end, +}: { + environment: string; + kuery: string; + serviceName: string; + groupId?: string; + bucketSize: number; + apmEventClient: APMEventClient; + start: number; + end: number; +}) { + const params = { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(ERROR_TYPE, 'crash'), + ...termQuery(SERVICE_NAME, serviceName), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ...termQuery(ERROR_GROUP_ID, groupId), + ], + }, + }, + aggs: { + distribution: { + histogram: { + field: '@timestamp', + min_doc_count: 0, + interval: bucketSize, + extended_bounds: { + min: start, + max: end, + }, + }, + }, + }, + }, + }; + + const resp = await apmEventClient.search( + 'get_error_distribution_buckets', + params + ); + + const buckets = (resp.aggregations?.distribution.buckets || []).map( + (bucket) => ({ + x: bucket.key, + y: bucket.doc_count, + }) + ); + return { buckets }; +} diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_distribution.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_distribution.ts new file mode 100644 index 000000000000..1599ea3c8e87 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/get_distribution.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { offsetPreviousPeriodCoordinates } from '../../../../../common/utils/offset_previous_period_coordinate'; +import { BUCKET_TARGET_COUNT } from '../../../transactions/constants'; +import { getBuckets } from './get_buckets'; +import { getOffsetInMs } from '../../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; +import { Maybe } from '../../../../../typings/common'; + +function getBucketSize({ start, end }: { start: number; end: number }) { + return Math.floor((end - start) / BUCKET_TARGET_COUNT); +} + +export interface CrashDistributionResponse { + currentPeriod: Array<{ x: number; y: number }>; + previousPeriod: Array<{ + x: number; + y: Maybe; + }>; + bucketSize: number; +} + +export async function getCrashDistribution({ + environment, + kuery, + serviceName, + groupId, + apmEventClient, + start, + end, + offset, +}: { + environment: string; + kuery: string; + serviceName: string; + groupId?: string; + apmEventClient: APMEventClient; + start: number; + end: number; + offset?: string; +}): Promise { + const { startWithOffset, endWithOffset } = getOffsetInMs({ + start, + end, + offset, + }); + + const bucketSize = getBucketSize({ + start: startWithOffset, + end: endWithOffset, + }); + + const commonProps = { + environment, + kuery, + serviceName, + groupId, + apmEventClient, + bucketSize, + }; + const currentPeriodPromise = getBuckets({ + ...commonProps, + start, + end, + }); + + const previousPeriodPromise = offset + ? getBuckets({ + ...commonProps, + start: startWithOffset, + end: endWithOffset, + }) + : { buckets: [], bucketSize: null }; + + const [currentPeriod, previousPeriod] = await Promise.all([ + currentPeriodPromise, + previousPeriodPromise, + ]); + + return { + currentPeriod: currentPeriod.buckets, + previousPeriod: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: currentPeriod.buckets, + previousPeriodTimeseries: previousPeriod.buckets, + }), + bucketSize, + }; +} diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/queries.test.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/queries.test.ts new file mode 100644 index 000000000000..70232a66abb4 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/distribution/queries.test.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getCrashDistribution } from './get_distribution'; +import { + SearchParamsMock, + inspectSearchParams, +} from '../../../../utils/test_helpers'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; + +describe('error distribution queries', () => { + let mock: SearchParamsMock; + + afterEach(() => { + mock.teardown(); + }); + + it('fetches an error distribution', async () => { + mock = await inspectSearchParams(({ mockApmEventClient }) => + getCrashDistribution({ + serviceName: 'serviceName', + apmEventClient: mockApmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 50000, + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); + + it('fetches an error distribution with a group id', async () => { + mock = await inspectSearchParams(({ mockApmEventClient }) => + getCrashDistribution({ + serviceName: 'serviceName', + groupId: 'foo', + apmEventClient: mockApmEventClient, + environment: ENVIRONMENT_ALL.value, + kuery: '', + start: 0, + end: 50000, + }) + ); + + expect(mock.params).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/get_crash_groups/get_crash_group_main_statistics.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/get_crash_groups/get_crash_group_main_statistics.ts new file mode 100644 index 000000000000..2bb38c63b3b5 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/get_crash_groups/get_crash_group_main_statistics.ts @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AggregationsAggregateOrder } from '@elastic/elasticsearch/lib/api/types'; +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + ERROR_CULPRIT, + ERROR_TYPE, + ERROR_EXC_HANDLED, + ERROR_EXC_MESSAGE, + ERROR_EXC_TYPE, + ERROR_GROUP_ID, + ERROR_LOG_MESSAGE, + SERVICE_NAME, + TRANSACTION_NAME, + TRANSACTION_TYPE, +} from '../../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../../common/utils/environment_query'; +import { getErrorName } from '../../../../lib/helpers/get_error_name'; +import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; + +export type MobileCrashGroupMainStatisticsResponse = Array<{ + groupId: string; + name: string; + lastSeen: number; + occurrences: number; + culprit: string | undefined; + handled: boolean | undefined; + type: string | undefined; +}>; + +export async function getMobileCrashGroupMainStatistics({ + kuery, + serviceName, + apmEventClient, + environment, + sortField, + sortDirection = 'desc', + start, + end, + maxNumberOfErrorGroups = 500, + transactionName, + transactionType, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + environment: string; + sortField?: string; + sortDirection?: 'asc' | 'desc'; + start: number; + end: number; + maxNumberOfErrorGroups?: number; + transactionName?: string; + transactionType?: string; +}): Promise { + // sort buckets by last occurrence of error + const sortByLatestOccurrence = sortField === 'lastSeen'; + + const maxTimestampAggKey = 'max_timestamp'; + + const order: AggregationsAggregateOrder = sortByLatestOccurrence + ? { [maxTimestampAggKey]: sortDirection } + : { _count: sortDirection }; + + const response = await apmEventClient.search( + 'get_crash_group_main_statistics', + { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(SERVICE_NAME, serviceName), + ...termQuery(TRANSACTION_NAME, transactionName), + ...termQuery(TRANSACTION_TYPE, transactionType), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...termQuery(ERROR_TYPE, 'crash'), + ...kqlQuery(kuery), + ], + }, + }, + aggs: { + crash_groups: { + terms: { + field: ERROR_GROUP_ID, + size: maxNumberOfErrorGroups, + order, + }, + aggs: { + sample: { + top_hits: { + size: 1, + _source: [ + ERROR_LOG_MESSAGE, + ERROR_EXC_MESSAGE, + ERROR_EXC_HANDLED, + ERROR_EXC_TYPE, + ERROR_CULPRIT, + ERROR_GROUP_ID, + '@timestamp', + ], + sort: { + '@timestamp': 'desc', + }, + }, + }, + ...(sortByLatestOccurrence + ? { [maxTimestampAggKey]: { max: { field: '@timestamp' } } } + : {}), + }, + }, + }, + }, + } + ); + + return ( + response.aggregations?.crash_groups.buckets.map((bucket) => ({ + groupId: bucket.key as string, + name: getErrorName(bucket.sample.hits.hits[0]._source), + lastSeen: new Date( + bucket.sample.hits.hits[0]?._source['@timestamp'] + ).getTime(), + occurrences: bucket.doc_count, + culprit: bucket.sample.hits.hits[0]?._source.error.culprit, + handled: bucket.sample.hits.hits[0]?._source.error.exception?.[0].handled, + type: bucket.sample.hits.hits[0]?._source.error.exception?.[0].type, + })) ?? [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/get_mobile_crash_group_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/get_mobile_crash_group_detailed_statistics.ts new file mode 100644 index 000000000000..71f6a9ef152e --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/get_mobile_crash_group_detailed_statistics.ts @@ -0,0 +1,199 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { keyBy } from 'lodash'; +import { + rangeQuery, + kqlQuery, + termQuery, + termsQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; +import { Coordinate } from '../../../../typings/timeseries'; +import { + ERROR_GROUP_ID, + ERROR_TYPE, + SERVICE_NAME, +} from '../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { getBucketSize } from '../../../../common/utils/get_bucket_size'; +import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +interface CrashGroupDetailedStat { + groupId: string; + timeseries: Coordinate[]; +} + +export async function getMobileCrashesGroupDetailedStatistics({ + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + environment, + start, + end, + offset, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + numBuckets: number; + groupIds: string[]; + environment: string; + start: number; + end: number; + offset?: string; +}): Promise { + const { startWithOffset, endWithOffset } = getOffsetInMs({ + start, + end, + offset, + }); + + const { intervalString } = getBucketSize({ + start: startWithOffset, + end: endWithOffset, + numBuckets, + }); + + const timeseriesResponse = await apmEventClient.search( + 'get_service_error_group_detailed_statistics', + { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termsQuery(ERROR_GROUP_ID, ...groupIds), + ...termsQuery(ERROR_TYPE, 'crash'), + ...termQuery(SERVICE_NAME, serviceName), + ...rangeQuery(startWithOffset, endWithOffset), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ], + }, + }, + aggs: { + error_groups: { + terms: { + field: ERROR_GROUP_ID, + size: 500, + }, + aggs: { + timeseries: { + date_histogram: { + field: '@timestamp', + fixed_interval: intervalString, + min_doc_count: 0, + extended_bounds: { + min: startWithOffset, + max: endWithOffset, + }, + }, + }, + }, + }, + }, + }, + } + ); + + if (!timeseriesResponse.aggregations) { + return []; + } + + return timeseriesResponse.aggregations.error_groups.buckets.map((bucket) => { + const groupId = bucket.key as string; + return { + groupId, + timeseries: bucket.timeseries.buckets.map((timeseriesBucket) => { + return { + x: timeseriesBucket.key, + y: timeseriesBucket.doc_count, + }; + }), + }; + }); +} + +export interface MobileCrashesGroupPeriodsResponse { + currentPeriod: Record; + previousPeriod: Record; +} + +export async function getMobileCrashesGroupPeriods({ + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + environment, + start, + end, + offset, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + numBuckets: number; + groupIds: string[]; + environment: string; + start: number; + end: number; + offset?: string; +}): Promise { + const commonProps = { + environment, + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + }; + + const currentPeriodPromise = getMobileCrashesGroupDetailedStatistics({ + ...commonProps, + start, + end, + }); + + const previousPeriodPromise = offset + ? getMobileCrashesGroupDetailedStatistics({ + ...commonProps, + start, + end, + offset, + }) + : []; + + const [currentPeriod, previousPeriod] = await Promise.all([ + currentPeriodPromise, + previousPeriodPromise, + ]); + + const firstCurrentPeriod = currentPeriod?.[0]; + + return { + currentPeriod: keyBy(currentPeriod, 'groupId'), + previousPeriod: keyBy( + previousPeriod.map((crashRateGroup) => ({ + ...crashRateGroup, + timeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: firstCurrentPeriod?.timeseries, + previousPeriodTimeseries: crashRateGroup.timeseries, + }), + })), + 'groupId' + ), + }; +} diff --git a/x-pack/plugins/apm/server/routes/mobile/crashes/route.ts b/x-pack/plugins/apm/server/routes/mobile/crashes/route.ts new file mode 100644 index 000000000000..75eeaf3b5ddc --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/crashes/route.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import * as t from 'io-ts'; +import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; +import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; +import { environmentRt, kueryRt, rangeRt } from '../../default_api_types'; +import { offsetRt } from '../../../../common/comparison_rt'; +import { + getMobileCrashGroupMainStatistics, + MobileCrashGroupMainStatisticsResponse, +} from './get_crash_groups/get_crash_group_main_statistics'; +import { + MobileCrashesGroupPeriodsResponse, + getMobileCrashesGroupPeriods, +} from './get_mobile_crash_group_detailed_statistics'; +import { + CrashDistributionResponse, + getCrashDistribution, +} from './distribution/get_distribution'; + +const mobileCrashDistributionRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/mobile-services/{serviceName}/crashes/distribution', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + t.partial({ + groupId: t.string, + }), + environmentRt, + kueryRt, + rangeRt, + offsetRt, + ]), + }), + options: { tags: ['access:apm'] }, + handler: async (resources): Promise => { + const apmEventClient = await getApmEventClient(resources); + const { params } = resources; + const { serviceName } = params.path; + const { environment, kuery, groupId, start, end, offset } = params.query; + return getCrashDistribution({ + environment, + kuery, + serviceName, + groupId, + apmEventClient, + start, + end, + offset, + }); + }, +}); + +const mobileCrashMainStatisticsRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + t.partial({ + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + }), + environmentRt, + kueryRt, + rangeRt, + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ errorGroups: MobileCrashGroupMainStatisticsResponse }> => { + const { params } = resources; + const apmEventClient = await getApmEventClient(resources); + const { serviceName } = params.path; + const { environment, kuery, sortField, sortDirection, start, end } = + params.query; + + const errorGroups = await getMobileCrashGroupMainStatistics({ + environment, + kuery, + serviceName, + sortField, + sortDirection, + apmEventClient, + start, + end, + }); + + return { errorGroups }; + }, +}); + +const mobileCrashDetailedStatisticsRoute = createApmServerRoute({ + endpoint: + 'POST /internal/apm/mobile-services/{serviceName}/crashes/groups/detailed_statistics', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + environmentRt, + kueryRt, + rangeRt, + offsetRt, + t.type({ + numBuckets: toNumberRt, + }), + ]), + body: t.type({ groupIds: jsonRt.pipe(t.array(t.string)) }), + }), + options: { tags: ['access:apm'] }, + handler: async (resources): Promise => { + const apmEventClient = await getApmEventClient(resources); + const { params } = resources; + + const { + path: { serviceName }, + query: { environment, kuery, numBuckets, start, end, offset }, + body: { groupIds }, + } = params; + + return getMobileCrashesGroupPeriods({ + environment, + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + start, + end, + offset, + }); + }, +}); + +export const mobileCrashRoutes = { + ...mobileCrashDetailedStatisticsRoute, + ...mobileCrashMainStatisticsRoute, + ...mobileCrashDistributionRoute, +}; diff --git a/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_detailed_statistics.ts b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_detailed_statistics.ts new file mode 100644 index 000000000000..ef7ce97ff9d7 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_detailed_statistics.ts @@ -0,0 +1,197 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { keyBy } from 'lodash'; +import { + rangeQuery, + kqlQuery, + termQuery, + termsQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; +import { Coordinate } from '../../../../typings/timeseries'; +import { ERROR_GROUP_ID, SERVICE_NAME } from '../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { getBucketSize } from '../../../../common/utils/get_bucket_size'; +import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +interface ErrorGroupDetailedStat { + groupId: string; + timeseries: Coordinate[]; +} + +export async function getMobileErrorGroupDetailedStatistics({ + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + environment, + start, + end, + offset, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + numBuckets: number; + groupIds: string[]; + environment: string; + start: number; + end: number; + offset?: string; +}): Promise { + const { startWithOffset, endWithOffset } = getOffsetInMs({ + start, + end, + offset, + }); + + const { intervalString } = getBucketSize({ + start: startWithOffset, + end: endWithOffset, + numBuckets, + }); + + const timeseriesResponse = await apmEventClient.search( + 'get_service_error_group_detailed_statistics', + { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termsQuery(ERROR_GROUP_ID, ...groupIds), + ...termQuery(SERVICE_NAME, serviceName), + ...rangeQuery(startWithOffset, endWithOffset), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ], + must_not: { + term: { 'error.type': 'crash' }, + }, + }, + }, + aggs: { + error_groups: { + terms: { + field: ERROR_GROUP_ID, + size: 500, + }, + aggs: { + timeseries: { + date_histogram: { + field: '@timestamp', + fixed_interval: intervalString, + min_doc_count: 0, + extended_bounds: { + min: startWithOffset, + max: endWithOffset, + }, + }, + }, + }, + }, + }, + }, + } + ); + + if (!timeseriesResponse.aggregations) { + return []; + } + + return timeseriesResponse.aggregations.error_groups.buckets.map((bucket) => { + const groupId = bucket.key as string; + return { + groupId, + timeseries: bucket.timeseries.buckets.map((timeseriesBucket) => { + return { + x: timeseriesBucket.key, + y: timeseriesBucket.doc_count, + }; + }), + }; + }); +} + +export interface MobileErrorGroupPeriodsResponse { + currentPeriod: Record; + previousPeriod: Record; +} + +export async function getMobileErrorGroupPeriods({ + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + environment, + start, + end, + offset, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + numBuckets: number; + groupIds: string[]; + environment: string; + start: number; + end: number; + offset?: string; +}): Promise { + const commonProps = { + environment, + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + }; + + const currentPeriodPromise = getMobileErrorGroupDetailedStatistics({ + ...commonProps, + start, + end, + }); + + const previousPeriodPromise = offset + ? getMobileErrorGroupDetailedStatistics({ + ...commonProps, + start, + end, + offset, + }) + : []; + + const [currentPeriod, previousPeriod] = await Promise.all([ + currentPeriodPromise, + previousPeriodPromise, + ]); + + const firstCurrentPeriod = currentPeriod?.[0]; + + return { + currentPeriod: keyBy(currentPeriod, 'groupId'), + previousPeriod: keyBy( + previousPeriod.map((errorRateGroup) => ({ + ...errorRateGroup, + timeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: firstCurrentPeriod?.timeseries, + previousPeriodTimeseries: errorRateGroup.timeseries, + }), + })), + 'groupId' + ), + }; +} diff --git a/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_main_statistics.ts b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_main_statistics.ts new file mode 100644 index 000000000000..483ff2341d18 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_error_group_main_statistics.ts @@ -0,0 +1,146 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AggregationsAggregateOrder } from '@elastic/elasticsearch/lib/api/types'; +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + ERROR_CULPRIT, + ERROR_EXC_HANDLED, + ERROR_EXC_MESSAGE, + ERROR_EXC_TYPE, + ERROR_GROUP_ID, + ERROR_LOG_MESSAGE, + SERVICE_NAME, + TRANSACTION_NAME, + TRANSACTION_TYPE, +} from '../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { getErrorName } from '../../../lib/helpers/get_error_name'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +export type MobileErrorGroupMainStatisticsResponse = Array<{ + groupId: string; + name: string; + lastSeen: number; + occurrences: number; + culprit: string | undefined; + handled: boolean | undefined; + type: string | undefined; +}>; + +export async function getMobileErrorGroupMainStatistics({ + kuery, + serviceName, + apmEventClient, + environment, + sortField, + sortDirection = 'desc', + start, + end, + maxNumberOfErrorGroups = 500, + transactionName, + transactionType, +}: { + kuery: string; + serviceName: string; + apmEventClient: APMEventClient; + environment: string; + sortField?: string; + sortDirection?: 'asc' | 'desc'; + start: number; + end: number; + maxNumberOfErrorGroups?: number; + transactionName?: string; + transactionType?: string; +}): Promise { + // sort buckets by last occurrence of error + const sortByLatestOccurrence = sortField === 'lastSeen'; + + const maxTimestampAggKey = 'max_timestamp'; + + const order: AggregationsAggregateOrder = sortByLatestOccurrence + ? { [maxTimestampAggKey]: sortDirection } + : { _count: sortDirection }; + + const response = await apmEventClient.search( + 'get_error_group_main_statistics', + { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + must_not: { + term: { 'error.type': 'crash' }, + }, + filter: [ + ...termQuery(SERVICE_NAME, serviceName), + ...termQuery(TRANSACTION_NAME, transactionName), + ...termQuery(TRANSACTION_TYPE, transactionType), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ], + }, + }, + aggs: { + error_groups: { + terms: { + field: ERROR_GROUP_ID, + size: maxNumberOfErrorGroups, + order, + }, + aggs: { + sample: { + top_hits: { + size: 1, + _source: [ + ERROR_LOG_MESSAGE, + ERROR_EXC_MESSAGE, + ERROR_EXC_HANDLED, + ERROR_EXC_TYPE, + ERROR_CULPRIT, + ERROR_GROUP_ID, + '@timestamp', + ], + sort: { + '@timestamp': 'desc', + }, + }, + }, + ...(sortByLatestOccurrence + ? { [maxTimestampAggKey]: { max: { field: '@timestamp' } } } + : {}), + }, + }, + }, + }, + } + ); + + return ( + response.aggregations?.error_groups.buckets.map((bucket) => ({ + groupId: bucket.key as string, + name: getErrorName(bucket.sample.hits.hits[0]._source), + lastSeen: new Date( + bucket.sample.hits.hits[0]?._source['@timestamp'] + ).getTime(), + occurrences: bucket.doc_count, + culprit: bucket.sample.hits.hits[0]?._source.error.culprit, + handled: bucket.sample.hits.hits[0]?._source.error.exception?.[0].handled, + type: bucket.sample.hits.hits[0]?._source.error.exception?.[0].type, + })) ?? [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_errors_terms_by_field.ts b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_errors_terms_by_field.ts new file mode 100644 index 000000000000..96cb9bde697a --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_errors_terms_by_field.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + termQuery, + kqlQuery, + rangeQuery, +} from '@kbn/observability-plugin/server'; +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { SERVICE_NAME } from '../../../../common/es_fields/apm'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; + +export type MobileErrorTermsByFieldResponse = Array<{ + label: string; + count: number; +}>; + +export async function getMobileErrorsTermsByField({ + kuery, + apmEventClient, + serviceName, + environment, + start, + end, + size, + fieldName, +}: { + kuery: string; + apmEventClient: APMEventClient; + serviceName: string; + environment: string; + start: number; + end: number; + size: number; + fieldName: string; +}): Promise { + const response = await apmEventClient.search( + `get_mobile_terms_by_${fieldName}`, + { + apm: { + events: [ProcessorEvent.error], + }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(SERVICE_NAME, serviceName), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...kqlQuery(kuery), + ], + }, + }, + aggs: { + terms: { + terms: { + field: fieldName, + size, + }, + }, + }, + }, + } + ); + + return ( + response.aggregations?.terms?.buckets?.map(({ key, doc_count: count }) => ({ + label: key as string, + count, + })) ?? [] + ); +} diff --git a/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_http_errors.ts b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_http_errors.ts new file mode 100644 index 000000000000..ffd719e8462b --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/errors/get_mobile_http_errors.ts @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { + kqlQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; +import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { getOffsetInMs } from '../../../../common/utils/get_offset_in_ms'; +import { environmentQuery } from '../../../../common/utils/environment_query'; +import { + SERVICE_NAME, + HTTP_RESPONSE_STATUS_CODE, +} from '../../../../common/es_fields/apm'; +import { offsetPreviousPeriodCoordinates } from '../../../../common/utils/offset_previous_period_coordinate'; +import { Coordinate } from '../../../../typings/timeseries'; +import { BUCKET_TARGET_COUNT } from '../../transactions/constants'; + +interface Props { + apmEventClient: APMEventClient; + serviceName: string; + environment: string; + start: number; + end: number; + kuery: string; + offset?: string; +} + +function getBucketSize({ start, end }: { start: number; end: number }) { + return Math.floor((end - start) / BUCKET_TARGET_COUNT); +} + +export interface MobileHttpErrorsTimeseries { + currentPeriod: { timeseries: Coordinate[] }; + previousPeriod: { timeseries: Coordinate[] }; +} +async function getMobileHttpErrorsTimeseries({ + kuery, + apmEventClient, + serviceName, + environment, + start, + end, +}: Props) { + const bucketSize = getBucketSize({ + start, + end, + }); + const response = await apmEventClient.search('get_mobile_http_errors', { + apm: { events: [ProcessorEvent.error] }, + body: { + track_total_hits: false, + size: 0, + query: { + bool: { + filter: [ + ...termQuery(SERVICE_NAME, serviceName), + ...environmentQuery(environment), + ...rangeQuery(start, end), + ...rangeQuery(400, 599, HTTP_RESPONSE_STATUS_CODE), + ...kqlQuery(kuery), + ], + must_not: { + term: { 'error.type': 'crash' }, + }, + }, + }, + aggs: { + timeseries: { + histogram: { + field: '@timestamp', + min_doc_count: 0, + interval: bucketSize, + extended_bounds: { + min: start, + max: end, + }, + }, + }, + }, + }, + }); + + const timeseries = (response?.aggregations?.timeseries.buckets || []).map( + (bucket) => ({ + x: bucket.key, + y: bucket.doc_count, + }) + ); + return { timeseries }; +} + +export async function getMobileHttpErrors({ + kuery, + apmEventClient, + serviceName, + environment, + start, + end, + offset, +}: Props): Promise { + const options = { + serviceName, + apmEventClient, + kuery, + environment, + }; + const { startWithOffset, endWithOffset } = getOffsetInMs({ + start, + end, + offset, + }); + + const currentPeriodPromise = getMobileHttpErrorsTimeseries({ + ...options, + start, + end, + }); + const previousPeriodPromise = offset + ? getMobileHttpErrorsTimeseries({ + ...options, + start: startWithOffset, + end: endWithOffset, + }) + : { timeseries: [] as Coordinate[] }; + const [currentPeriod, previousPeriod] = await Promise.all([ + currentPeriodPromise, + previousPeriodPromise, + ]); + return { + currentPeriod, + previousPeriod: { + timeseries: offsetPreviousPeriodCoordinates({ + currentPeriodTimeseries: currentPeriod.timeseries, + previousPeriodTimeseries: previousPeriod.timeseries, + }), + }, + }; +} diff --git a/x-pack/plugins/apm/server/routes/mobile/errors/route.ts b/x-pack/plugins/apm/server/routes/mobile/errors/route.ts new file mode 100644 index 000000000000..9a0182891a86 --- /dev/null +++ b/x-pack/plugins/apm/server/routes/mobile/errors/route.ts @@ -0,0 +1,197 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; +import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; +import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; +import { environmentRt, kueryRt, rangeRt } from '../../default_api_types'; +import { offsetRt } from '../../../../common/comparison_rt'; +import { + getMobileErrorGroupPeriods, + MobileErrorGroupPeriodsResponse, +} from './get_mobile_error_group_detailed_statistics'; +import { + MobileErrorGroupMainStatisticsResponse, + getMobileErrorGroupMainStatistics, +} from './get_mobile_error_group_main_statistics'; +import { + getMobileErrorsTermsByField, + MobileErrorTermsByFieldResponse, +} from './get_mobile_errors_terms_by_field'; +import { + MobileHttpErrorsTimeseries, + getMobileHttpErrors, +} from './get_mobile_http_errors'; + +const mobileMobileHttpRatesRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/mobile-services/{serviceName}/error/http_error_rate', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([environmentRt, kueryRt, rangeRt, offsetRt]), + }), + options: { tags: ['access:apm'] }, + handler: async (resources): Promise => { + const apmEventClient = await getApmEventClient(resources); + const { params } = resources; + const { serviceName } = params.path; + const { kuery, environment, start, end, offset } = params.query; + const response = await getMobileHttpErrors({ + kuery, + environment, + start, + end, + serviceName, + apmEventClient, + offset, + }); + + return { ...response }; + }, +}); + +const mobileErrorsDetailedStatisticsRoute = createApmServerRoute({ + endpoint: + 'POST /internal/apm/mobile-services/{serviceName}/errors/groups/detailed_statistics', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + environmentRt, + kueryRt, + rangeRt, + offsetRt, + t.type({ + numBuckets: toNumberRt, + }), + ]), + body: t.type({ groupIds: jsonRt.pipe(t.array(t.string)) }), + }), + options: { tags: ['access:apm'] }, + handler: async (resources): Promise => { + const apmEventClient = await getApmEventClient(resources); + const { params } = resources; + + const { + path: { serviceName }, + query: { environment, kuery, numBuckets, start, end, offset }, + body: { groupIds }, + } = params; + + return getMobileErrorGroupPeriods({ + environment, + kuery, + serviceName, + apmEventClient, + numBuckets, + groupIds, + start, + end, + offset, + }); + }, +}); + +const mobileErrorTermsByFieldRoute = createApmServerRoute({ + endpoint: 'GET /internal/apm/mobile-services/{serviceName}/error_terms', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + kueryRt, + rangeRt, + environmentRt, + t.type({ + size: toNumberRt, + fieldName: t.string, + }), + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ + terms: MobileErrorTermsByFieldResponse; + }> => { + const apmEventClient = await getApmEventClient(resources); + const { params } = resources; + const { serviceName } = params.path; + const { kuery, environment, start, end, size, fieldName } = params.query; + const terms = await getMobileErrorsTermsByField({ + kuery, + environment, + start, + end, + serviceName, + apmEventClient, + fieldName, + size, + }); + + return { terms }; + }, +}); + +const mobileErrorsMainStatisticsRoute = createApmServerRoute({ + endpoint: + 'GET /internal/apm/mobile-services/{serviceName}/errors/groups/main_statistics', + params: t.type({ + path: t.type({ + serviceName: t.string, + }), + query: t.intersection([ + t.partial({ + sortField: t.string, + sortDirection: t.union([t.literal('asc'), t.literal('desc')]), + }), + environmentRt, + kueryRt, + rangeRt, + ]), + }), + options: { tags: ['access:apm'] }, + handler: async ( + resources + ): Promise<{ errorGroups: MobileErrorGroupMainStatisticsResponse }> => { + const { params } = resources; + const apmEventClient = await getApmEventClient(resources); + const { serviceName } = params.path; + const { environment, kuery, sortField, sortDirection, start, end } = + params.query; + + const errorGroups = await getMobileErrorGroupMainStatistics({ + environment, + kuery, + serviceName, + sortField, + sortDirection, + apmEventClient, + start, + end, + }); + + return { errorGroups }; + }, +}); + +export const mobileErrorRoutes = { + ...mobileMobileHttpRatesRoute, + ...mobileErrorsMainStatisticsRoute, + ...mobileErrorsDetailedStatisticsRoute, + ...mobileErrorTermsByFieldRoute, +}; diff --git a/x-pack/plugins/apm/server/routes/mobile/get_device_os_app.ts b/x-pack/plugins/apm/server/routes/mobile/get_device_os_app.ts index e2194b994b02..80fae958b6c5 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_device_os_app.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_device_os_app.ts @@ -10,7 +10,6 @@ import { kqlQuery, rangeQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { DEVICE_MODEL_IDENTIFIER, HOST_OS_VERSION, @@ -19,6 +18,8 @@ import { TRANSACTION_TYPE, } from '../../../common/es_fields/apm'; import { environmentQuery } from '../../../common/utils/environment_query'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getDeviceOSApp({ @@ -42,7 +43,12 @@ export async function getDeviceOSApp({ }) { return await apmEventClient.search('get_mobile_device_os_app', { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_crash_rate.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_crash_rate.ts index bf498bf70460..e60d0ff15c62 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_mobile_crash_rate.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_crash_rate.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { kqlQuery, rangeQuery, @@ -23,6 +22,8 @@ import { import { environmentQuery } from '../../../common/utils/environment_query'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; export interface CrashRateTimeseries { currentPeriod: { timeseries: Coordinate[]; value: Maybe }; @@ -70,7 +71,12 @@ async function getMobileCrashTimeseries({ const response = await apmEventClient.search('get_mobile_crash_rate', { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_crashes_by_location.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_crashes_by_location.ts index 855ae8fb35d0..e91214af444b 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_mobile_crashes_by_location.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_crashes_by_location.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { kqlQuery, rangeQuery, @@ -16,6 +15,8 @@ import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_ev import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { getBucketSize } from '../../../common/utils/get_bucket_size'; import { environmentQuery } from '../../../common/utils/environment_query'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; interface Props { kuery: string; @@ -64,7 +65,12 @@ export async function getCrashesByLocation({ }; const response = await apmEventClient.search('get_mobile_location_crashes', { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions.ts index e3ccd83c20bf..9168101ebc40 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { kqlQuery, rangeQuery, @@ -23,6 +22,8 @@ import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_ev import { getBucketSize } from '../../../common/utils/get_bucket_size'; import { Coordinate } from '../../../typings/timeseries'; import { Maybe } from '../../../typings/common'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; export interface SessionsTimeseries { currentPeriod: { timeseries: Coordinate[]; value: Maybe }; @@ -70,7 +71,12 @@ async function getSessionTimeseries({ const response = await apmEventClient.search('get_mobile_sessions', { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions_by_location.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions_by_location.ts index 95ad146f585f..7543d097d888 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions_by_location.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_sessions_by_location.ts @@ -10,12 +10,13 @@ import { kqlQuery, rangeQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { SERVICE_NAME, SESSION_ID } from '../../../common/es_fields/apm'; import { environmentQuery } from '../../../common/utils/environment_query'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms'; import { getBucketSize } from '../../../common/utils/get_bucket_size'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; interface Props { kuery: string; @@ -65,7 +66,12 @@ export async function getSessionsByLocation({ const response = await apmEventClient.search('get_mobile_location_sessions', { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/get_nct.ts b/x-pack/plugins/apm/server/routes/mobile/get_nct.ts index 829f40962f84..f84701ecfb29 100644 --- a/x-pack/plugins/apm/server/routes/mobile/get_nct.ts +++ b/x-pack/plugins/apm/server/routes/mobile/get_nct.ts @@ -10,12 +10,13 @@ import { kqlQuery, rangeQuery, } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { NETWORK_CONNECTION_TYPE, SERVICE_NAME, } from '../../../common/es_fields/apm'; import { environmentQuery } from '../../../common/utils/environment_query'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; export async function getNCT({ @@ -38,7 +39,12 @@ export async function getNCT({ }) { return await apmEventClient.search('get_mobile_nct', { apm: { - events: [ProcessorEvent.span], + sources: [ + { + documentType: ApmDocumentType.SpanEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/mobile/route.ts b/x-pack/plugins/apm/server/routes/mobile/route.ts index e57352b9df3a..b7bc7d68787b 100644 --- a/x-pack/plugins/apm/server/routes/mobile/route.ts +++ b/x-pack/plugins/apm/server/routes/mobile/route.ts @@ -39,6 +39,8 @@ import { getMobileMostUsedCharts, MobileMostUsedChartResponse, } from './get_mobile_most_used_charts'; +import { mobileErrorRoutes } from './errors/route'; +import { mobileCrashRoutes } from './crashes/route'; const mobileFiltersRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/services/{serviceName}/mobile/filters', @@ -306,7 +308,6 @@ const mobileTermsByFieldRoute = createApmServerRoute({ const { params } = resources; const { serviceName } = params.path; const { kuery, environment, start, end, size, fieldName } = params.query; - const terms = await getMobileTermsByField({ kuery, environment, @@ -401,6 +402,8 @@ const mobileDetailedStatisticsByField = createApmServerRoute({ }); export const mobileRouteRepository = { + ...mobileErrorRoutes, + ...mobileCrashRoutes, ...mobileFiltersRoute, ...mobileChartsRoute, ...sessionsChartRoute, diff --git a/x-pack/plugins/apm/server/routes/profiling/route.ts b/x-pack/plugins/apm/server/routes/profiling/route.ts index 9d5853c28833..0421cb994124 100644 --- a/x-pack/plugins/apm/server/routes/profiling/route.ts +++ b/x-pack/plugins/apm/server/routes/profiling/route.ts @@ -8,13 +8,16 @@ import { toNumberRt } from '@kbn/io-ts-utils'; import type { BaseFlameGraph, TopNFunctions } from '@kbn/profiling-utils'; import * as t from 'io-ts'; -import { profilingUseLegacyFlamegraphAPI } from '@kbn/observability-plugin/common'; import { HOST_NAME } from '../../../common/es_fields/apm'; -import { toKueryFilterFormat } from '../../../common/utils/to_kuery_filter_format'; +import { + mergeKueries, + toKueryFilterFormat, +} from '../../../common/utils/kuery_utils'; import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, + kueryRt, rangeRt, serviceTransactionDataSourceRt, } from '../default_api_types'; @@ -28,6 +31,7 @@ const profilingFlamegraphRoute = createApmServerRoute({ rangeRt, environmentRt, serviceTransactionDataSourceRt, + kueryRt, ]), }), options: { tags: ['access:apm'] }, @@ -37,18 +41,15 @@ const profilingFlamegraphRoute = createApmServerRoute({ { flamegraph: BaseFlameGraph; hostNames: string[] } | undefined > => { const { context, plugins, params } = resources; - const useLegacyFlamegraphAPI = await ( - await context.core - ).uiSettings.client.get(profilingUseLegacyFlamegraphAPI); - + const core = await context.core; const [esClient, apmEventClient, profilingDataAccessStart] = await Promise.all([ - (await context.core).elasticsearch.client, + core.elasticsearch.client, await getApmEventClient(resources), await plugins.profilingDataAccess?.start(), ]); if (profilingDataAccessStart) { - const { start, end, environment, documentType, rollupInterval } = + const { start, end, environment, documentType, rollupInterval, kuery } = params.query; const { serviceName } = params.path; @@ -68,11 +69,14 @@ const profilingFlamegraphRoute = createApmServerRoute({ const flamegraph = await profilingDataAccessStart?.services.fetchFlamechartData({ + core, esClient: esClient.asCurrentUser, rangeFromMs: start, rangeToMs: end, - kuery: toKueryFilterFormat(HOST_NAME, serviceHostNames), - useLegacyFlamegraphAPI, + kuery: mergeKueries([ + `(${toKueryFilterFormat(HOST_NAME, serviceHostNames)})`, + kuery, + ]), }); return { flamegraph, hostNames: serviceHostNames }; @@ -91,6 +95,7 @@ const profilingFunctionsRoute = createApmServerRoute({ environmentRt, serviceTransactionDataSourceRt, t.type({ startIndex: toNumberRt, endIndex: toNumberRt }), + kueryRt, ]), }), options: { tags: ['access:apm'] }, @@ -98,9 +103,10 @@ const profilingFunctionsRoute = createApmServerRoute({ resources ): Promise<{ functions: TopNFunctions; hostNames: string[] } | undefined> => { const { context, plugins, params } = resources; + const core = await context.core; const [esClient, apmEventClient, profilingDataAccessStart] = await Promise.all([ - (await context.core).elasticsearch.client, + core.elasticsearch.client, await getApmEventClient(resources), await plugins.profilingDataAccess?.start(), ]); @@ -113,6 +119,7 @@ const profilingFunctionsRoute = createApmServerRoute({ endIndex, documentType, rollupInterval, + kuery, } = params.query; const { serviceName } = params.path; @@ -131,10 +138,14 @@ const profilingFunctionsRoute = createApmServerRoute({ } const functions = await profilingDataAccessStart?.services.fetchFunction({ + core, esClient: esClient.asCurrentUser, rangeFromMs: start, rangeToMs: end, - kuery: toKueryFilterFormat(HOST_NAME, serviceHostNames), + kuery: mergeKueries([ + `(${toKueryFilterFormat(HOST_NAME, serviceHostNames)})`, + kuery, + ]), startIndex, endIndex, }); diff --git a/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts b/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts index e327bf1e7cdb..033e34308478 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_node_metadata.ts @@ -6,7 +6,6 @@ */ import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { HOST_NAME, CONTAINER_ID } from '../../../common/es_fields/apm'; import { NOT_AVAILABLE_LABEL } from '../../../common/i18n'; import { SERVICE_NAME, SERVICE_NODE_NAME } from '../../../common/es_fields/apm'; @@ -15,6 +14,8 @@ import { serviceNodeNameQuery, } from '../../../common/utils/environment_query'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import { ApmServiceTransactionDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; export interface ServiceNodeMetadataResponse { host: string | number; @@ -29,6 +30,8 @@ export async function getServiceNodeMetadata({ start, end, environment, + documentType, + rollupInterval, }: { kuery: string; serviceName: string; @@ -37,10 +40,17 @@ export async function getServiceNodeMetadata({ start: number; end: number; environment: string; + documentType: ApmServiceTransactionDocumentType; + rollupInterval: RollupInterval; }): Promise { const params = { apm: { - events: [ProcessorEvent.metric], + sources: [ + { + documentType, + rollupInterval, + }, + ], }, body: { track_total_hits: false, @@ -78,14 +88,14 @@ export async function getServiceNodeMetadata({ }, }; - const response = await apmEventClient.search( + const { aggregations } = await apmEventClient.search( 'get_service_node_metadata', params ); return { - host: response.aggregations?.host.buckets[0]?.key || NOT_AVAILABLE_LABEL, + host: aggregations?.host.buckets[0]?.key || NOT_AVAILABLE_LABEL, containerId: - response.aggregations?.containerId.buckets[0]?.key || NOT_AVAILABLE_LABEL, + aggregations?.containerId.buckets[0]?.key || NOT_AVAILABLE_LABEL, }; } diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 24dc79ea668b..0a51a3e88379 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -368,14 +368,20 @@ const serviceNodeMetadataRoute = createApmServerRoute({ serviceName: t.string, serviceNodeName: t.string, }), - query: t.intersection([kueryRt, rangeRt, environmentRt]), + query: t.intersection([ + kueryRt, + rangeRt, + environmentRt, + serviceTransactionDataSourceRt, + ]), }), options: { tags: ['access:apm'] }, handler: async (resources): Promise => { const apmEventClient = await getApmEventClient(resources); const { params } = resources; const { serviceName, serviceNodeName } = params.path; - const { kuery, start, end, environment } = params.query; + const { kuery, start, end, environment, documentType, rollupInterval } = + params.query; return getServiceNodeMetadata({ kuery, @@ -385,6 +391,8 @@ const serviceNodeMetadataRoute = createApmServerRoute({ start, end, environment, + documentType, + rollupInterval, }); }, }); diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link/__snapshots__/get_transaction.test.ts.snap b/x-pack/plugins/apm/server/routes/settings/custom_link/__snapshots__/get_transaction.test.ts.snap index 3a738243cf5c..ea8d4318f4c5 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link/__snapshots__/get_transaction.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/settings/custom_link/__snapshots__/get_transaction.test.ts.snap @@ -3,8 +3,11 @@ exports[`custom link get transaction fetches with all filter 1`] = ` Object { "apm": Object { - "events": Array [ - "transaction", + "sources": Array [ + Object { + "documentType": "transactionEvent", + "rollupInterval": "none", + }, ], }, "body": Object { @@ -52,8 +55,11 @@ Object { exports[`custom link get transaction fetches without filter 1`] = ` Object { "apm": Object { - "events": Array [ - "transaction", + "sources": Array [ + Object { + "documentType": "transactionEvent", + "rollupInterval": "none", + }, ], }, "body": Object { diff --git a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts index d454b447b17f..58cdd55b2d44 100644 --- a/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts +++ b/x-pack/plugins/apm/server/routes/settings/custom_link/get_transaction.ts @@ -7,7 +7,8 @@ import * as t from 'io-ts'; import { compact } from 'lodash'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; import { filterOptionsRt } from './custom_link_types'; import { splitFilterValueByComma } from './helper'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; @@ -29,10 +30,15 @@ export async function getTransaction({ }) ); - const params = { + const resp = await apmEventClient.search('get_transaction_for_custom_link', { terminate_after: 1, apm: { - events: [ProcessorEvent.transaction as const], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, @@ -43,10 +49,6 @@ export async function getTransaction({ }, }, }, - }; - const resp = await apmEventClient.search( - 'get_transaction_for_custom_link', - params - ); + }); return resp.hits.hits[0]?._source; } diff --git a/x-pack/plugins/apm/server/routes/traces/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/traces/__snapshots__/queries.test.ts.snap index a490aec44a36..d64c33a421e1 100644 --- a/x-pack/plugins/apm/server/routes/traces/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/traces/__snapshots__/queries.test.ts.snap @@ -3,8 +3,11 @@ exports[`trace queries fetches a trace 1`] = ` Object { "apm": Object { - "events": Array [ - "error", + "sources": Array [ + Object { + "documentType": "error", + "rollupInterval": "none", + }, ], }, "body": Object { diff --git a/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts b/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts index a1637b29d8e7..3a3e9b8fe295 100644 --- a/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/routes/traces/get_trace_items.ts @@ -55,6 +55,8 @@ import { } from '../../../common/waterfall/typings'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; import { getSpanLinksCountById } from '../span_links/get_linked_children'; +import { ApmDocumentType } from '../../../common/document_type'; +import { RollupInterval } from '../../../common/rollup'; export interface TraceItems { exceedsMax: boolean; @@ -87,7 +89,12 @@ export async function getTraceItems({ const errorResponsePromise = apmEventClient.search('get_errors_docs', { apm: { - events: [ProcessorEvent.error], + sources: [ + { + documentType: ApmDocumentType.ErrorEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap index 4ff86970a611..deb1dec096f0 100644 --- a/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/routes/transactions/__snapshots__/queries.test.ts.snap @@ -3,8 +3,11 @@ exports[`transaction queries fetches a transaction 1`] = ` Object { "apm": Object { - "events": Array [ - "transaction", + "sources": Array [ + Object { + "documentType": "transactionEvent", + "rollupInterval": "none", + }, ], }, "body": Object { diff --git a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts index 77935244361b..8854f3075e59 100644 --- a/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/routes/transactions/get_transaction/index.ts @@ -6,10 +6,11 @@ */ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; -import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { TRACE_ID, TRANSACTION_ID } from '../../../../common/es_fields/apm'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; +import { ApmDocumentType } from '../../../../common/document_type'; +import { RollupInterval } from '../../../../common/rollup'; export async function getTransaction({ transactionId, @@ -26,7 +27,12 @@ export async function getTransaction({ }) { const resp = await apmEventClient.search('get_transaction', { apm: { - events: [ProcessorEvent.transaction], + sources: [ + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + }, + ], }, body: { track_total_hits: false, diff --git a/x-pack/plugins/apm/tsconfig.json b/x-pack/plugins/apm/tsconfig.json index 0c0e2780950e..db829dc3ed5f 100644 --- a/x-pack/plugins/apm/tsconfig.json +++ b/x-pack/plugins/apm/tsconfig.json @@ -103,7 +103,10 @@ "@kbn/monaco", "@kbn/shared-svg", "@kbn/deeplinks-observability", - "@kbn/shared-ux-link-redirect-app" + "@kbn/custom-icons", + "@kbn/elastic-agent-utils", + "@kbn/shared-ux-link-redirect-app", + "@kbn/observability-get-padded-alert-time-range-util" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/apm/typings/es_schemas/ui/fields/agent.ts b/x-pack/plugins/apm/typings/es_schemas/ui/fields/agent.ts index 4f1979300481..5aaba852055b 100644 --- a/x-pack/plugins/apm/typings/es_schemas/ui/fields/agent.ts +++ b/x-pack/plugins/apm/typings/es_schemas/ui/fields/agent.ts @@ -5,39 +5,13 @@ * 2.0. */ -export type ElasticAgentName = - | 'go' - | 'java' - | 'js-base' - | 'iOS/swift' - | 'rum-js' - | 'nodejs' - | 'python' - | 'dotnet' - | 'ruby' - | 'php' - | 'android/java'; +import type { AgentName } from '@kbn/elastic-agent-utils'; -export type OpenTelemetryAgentName = - | 'otlp' - | 'opentelemetry/cpp' - | 'opentelemetry/dotnet' - | 'opentelemetry/erlang' - | 'opentelemetry/go' - | 'opentelemetry/java' - | 'opentelemetry/nodejs' - | 'opentelemetry/php' - | 'opentelemetry/python' - | 'opentelemetry/ruby' - | 'opentelemetry/rust' - | 'opentelemetry/swift' - | 'opentelemetry/webjs'; - -/* - * Support additional agent types by appending definitions in mappings.json - * (for telemetry) and the AgentName type. - */ -export type AgentName = ElasticAgentName | OpenTelemetryAgentName; +export type { + ElasticAgentName, + OpenTelemetryAgentName, + AgentName, +} from '@kbn/elastic-agent-utils'; export interface Agent { ephemeral_id?: string; diff --git a/x-pack/plugins/asset_manager/common/constants_routes.ts b/x-pack/plugins/asset_manager/common/constants_routes.ts index 969df93d1bc9..6bbde84cc668 100644 --- a/x-pack/plugins/asset_manager/common/constants_routes.ts +++ b/x-pack/plugins/asset_manager/common/constants_routes.ts @@ -18,3 +18,4 @@ export const GET_ASSETS_DIFF = base('/assets/diff'); export const GET_HOSTS = base('/assets/hosts'); export const GET_SERVICES = base('/assets/services'); export const GET_CONTAINERS = base('/assets/containers'); +export const GET_PODS = base('/assets/pods'); diff --git a/x-pack/plugins/asset_manager/common/types_api.ts b/x-pack/plugins/asset_manager/common/types_api.ts index dd555c69328e..40d9749378d4 100644 --- a/x-pack/plugins/asset_manager/common/types_api.ts +++ b/x-pack/plugins/asset_manager/common/types_api.ts @@ -170,16 +170,19 @@ export const assetFiltersSingleKindRT = rt.exact( type: rt.union([assetTypeRT, rt.array(assetTypeRT)]), ean: rt.union([rt.string, rt.array(rt.string)]), id: rt.string, + parentEan: rt.string, ['cloud.provider']: rt.string, ['cloud.region']: rt.string, + ['orchestrator.cluster.name']: rt.string, }) ); export type SingleKindAssetFilters = rt.TypeOf; +const supportedKindRT = rt.union([rt.literal('host'), rt.literal('service')]); export const assetFiltersRT = rt.intersection([ assetFiltersSingleKindRT, - rt.partial({ kind: rt.union([assetKindRT, rt.array(assetKindRT)]) }), + rt.partial({ kind: rt.union([supportedKindRT, rt.array(supportedKindRT)]) }), ]); export type AssetFilters = rt.TypeOf; @@ -247,7 +250,6 @@ export const getServiceAssetsQueryOptionsRT = rt.intersection([ from: assetDateRT, to: assetDateRT, size: sizeRT, - parent: rt.string, stringFilters: rt.string, filters: assetFiltersSingleKindRT, }), @@ -258,3 +260,39 @@ export const getServiceAssetsResponseRT = rt.type({ services: rt.array(assetRT), }); export type GetServiceAssetsResponse = rt.TypeOf; + +/** + * Pods + */ +export const getPodAssetsQueryOptionsRT = rt.intersection([ + rt.strict({ from: assetDateRT }), + rt.partial({ + to: assetDateRT, + size: sizeRT, + stringFilters: rt.string, + filters: assetFiltersSingleKindRT, + }), +]); +export type GetPodAssetsQueryOptions = rt.TypeOf; +export const getPodAssetsResponseRT = rt.type({ + pods: rt.array(assetRT), +}); +export type GetPodAssetsResponse = rt.TypeOf; + +/** + * Assets + */ +export const getAssetsQueryOptionsRT = rt.intersection([ + rt.strict({ from: assetDateRT }), + rt.partial({ + to: assetDateRT, + size: sizeRT, + stringFilters: rt.string, + filters: assetFiltersRT, + }), +]); +export type GetAssetsQueryOptions = rt.TypeOf; +export const getAssetsResponseRT = rt.type({ + assets: rt.array(assetRT), +}); +export type GetAssetsResponse = rt.TypeOf; diff --git a/x-pack/plugins/asset_manager/common/types_client.ts b/x-pack/plugins/asset_manager/common/types_client.ts index 40b3eb5e07e8..e779a8a15ae3 100644 --- a/x-pack/plugins/asset_manager/common/types_client.ts +++ b/x-pack/plugins/asset_manager/common/types_client.ts @@ -19,8 +19,6 @@ export interface SharedAssetsOptionsPublic { export type GetHostsOptionsPublic = SharedAssetsOptionsPublic; export type GetContainersOptionsPublic = SharedAssetsOptionsPublic; - -export interface GetServicesOptionsPublic - extends SharedAssetsOptionsPublic { - parent?: string; -} +export type GetPodsOptionsPublic = SharedAssetsOptionsPublic; +export type GetServicesOptionsPublic = SharedAssetsOptionsPublic; +export type GetAssetsOptionsPublic = SharedAssetsOptionsPublic; diff --git a/x-pack/plugins/asset_manager/public/lib/public_assets_client.test.ts b/x-pack/plugins/asset_manager/public/lib/public_assets_client.test.ts index f465fa66ad2b..649bcfcb83dc 100644 --- a/x-pack/plugins/asset_manager/public/lib/public_assets_client.test.ts +++ b/x-pack/plugins/asset_manager/public/lib/public_assets_client.test.ts @@ -110,7 +110,7 @@ describe('Public assets client', () => { it('should include provided filters, but in string form', async () => { const client = new PublicAssetsClient(http); - const filters = { id: '*id-1*' }; + const filters = { id: '*id-1*', parentEan: 'container:123' }; await client.getServices({ from: 'x', filters }); expect(http.get).toBeCalledWith(routePaths.GET_SERVICES, { query: { @@ -120,14 +120,6 @@ describe('Public assets client', () => { }); }); - it('should include specified "parent" parameter in http.get query', async () => { - const client = new PublicAssetsClient(http); - await client.getServices({ from: 'x', to: 'y', parent: 'container:123' }); - expect(http.get).toBeCalledWith(routePaths.GET_SERVICES, { - query: { from: 'x', to: 'y', parent: 'container:123' }, - }); - }); - it('should return the direct results of http.get', async () => { const client = new PublicAssetsClient(http); http.get.mockResolvedValueOnce('my services'); diff --git a/x-pack/plugins/asset_manager/public/lib/public_assets_client.ts b/x-pack/plugins/asset_manager/public/lib/public_assets_client.ts index 7ff5617d8ceb..130e723da34a 100644 --- a/x-pack/plugins/asset_manager/public/lib/public_assets_client.ts +++ b/x-pack/plugins/asset_manager/public/lib/public_assets_client.ts @@ -10,13 +10,23 @@ import { GetContainersOptionsPublic, GetHostsOptionsPublic, GetServicesOptionsPublic, + GetPodsOptionsPublic, + GetAssetsOptionsPublic, } from '../../common/types_client'; import { GetContainerAssetsResponse, GetHostAssetsResponse, GetServiceAssetsResponse, + GetPodAssetsResponse, + GetAssetsResponse, } from '../../common/types_api'; -import { GET_CONTAINERS, GET_HOSTS, GET_SERVICES } from '../../common/constants_routes'; +import { + GET_CONTAINERS, + GET_HOSTS, + GET_SERVICES, + GET_PODS, + GET_ASSETS, +} from '../../common/constants_routes'; import { IPublicAssetsClient } from '../types'; export class PublicAssetsClient implements IPublicAssetsClient { @@ -57,4 +67,28 @@ export class PublicAssetsClient implements IPublicAssetsClient { return results; } + + async getPods(options: GetPodsOptionsPublic) { + const { filters, ...otherOptions } = options; + const results = await this.http.get(GET_PODS, { + query: { + stringFilters: JSON.stringify(filters), + ...otherOptions, + }, + }); + + return results; + } + + async getAssets(options: GetAssetsOptionsPublic) { + const { filters, ...otherOptions } = options; + const results = await this.http.get(GET_ASSETS, { + query: { + stringFilters: JSON.stringify(filters), + ...otherOptions, + }, + }); + + return results; + } } diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/containers/get_containers.test.ts b/x-pack/plugins/asset_manager/server/lib/accessors/containers/get_containers.test.ts index 0a7b34b9ad1a..8a7aad907a36 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/containers/get_containers.test.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/containers/get_containers.test.ts @@ -32,7 +32,7 @@ function createBaseOptions({ }; } -describe('getHosts', () => { +describe('getContainers', () => { let getApmIndicesMock = createGetApmIndicesMock(); let metricsDataClientMock = MetricsDataClientMock.create(); let baseOptions = createBaseOptions({ getApmIndicesMock, metricsDataClientMock }); diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.test.ts b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.test.ts index 147d7d7aed5b..1f7d1e7007bb 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.test.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.test.ts @@ -135,8 +135,8 @@ describe('getHosts', () => { }, }, { - term: { - 'host.hostname': mockHostName, + terms: { + 'host.hostname': [mockHostName], }, }, ]) diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.ts b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.ts index 62c4fe404c0a..8252c57da3b0 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts.ts @@ -29,19 +29,22 @@ export async function getHosts(options: GetHostsOptionsInjected): Promise<{ host const filters: QueryDslQueryContainer[] = []; if (options.filters?.ean) { - const ean = Array.isArray(options.filters.ean) ? options.filters.ean[0] : options.filters.ean; - const { kind, id } = parseEan(ean); + const eans = Array.isArray(options.filters.ean) ? options.filters.ean : [options.filters.ean]; + const hostnames = eans + .map(parseEan) + .filter(({ kind }) => kind === 'host') + .map(({ id }) => id); // if EAN filter isn't targeting a host asset, we don't need to do this query - if (kind !== 'host') { + if (hostnames.length === 0) { return { hosts: [], }; } filters.push({ - term: { - 'host.hostname': id, + terms: { + 'host.hostname': hostnames, }, }); } diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.test.ts b/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.test.ts new file mode 100644 index 000000000000..94d367963588 --- /dev/null +++ b/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.test.ts @@ -0,0 +1,341 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import { GetApmIndicesMethod } from '../../asset_client_types'; +import { getPods } from './get_pods'; +import { + createGetApmIndicesMock, + expectToThrowValidationErrorWithStatusCode, +} from '../../../test_utils'; +import { MetricsDataClient, MetricsDataClientMock } from '@kbn/metrics-data-access-plugin/server'; +import { SearchRequest } from '@elastic/elasticsearch/lib/api/types'; + +function createBaseOptions({ + getApmIndicesMock, + metricsDataClientMock, +}: { + getApmIndicesMock: GetApmIndicesMethod; + metricsDataClientMock: MetricsDataClient; +}) { + return { + sourceIndices: { + logs: 'my-logs*', + }, + getApmIndices: getApmIndicesMock, + metricsClient: metricsDataClientMock, + }; +} + +describe('getPods', () => { + let getApmIndicesMock = createGetApmIndicesMock(); + let metricsDataClientMock = MetricsDataClientMock.create(); + let baseOptions = createBaseOptions({ getApmIndicesMock, metricsDataClientMock }); + let esClientMock = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + let soClientMock = savedObjectsClientMock.create(); + + function resetMocks() { + getApmIndicesMock = createGetApmIndicesMock(); + metricsDataClientMock = MetricsDataClientMock.create(); + baseOptions = createBaseOptions({ getApmIndicesMock, metricsDataClientMock }); + esClientMock = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + soClientMock = savedObjectsClientMock.create(); + } + + beforeEach(() => { + resetMocks(); + + // ES returns no results, just enough structure to not blow up + esClientMock.search.mockResolvedValueOnce({ + took: 1, + timed_out: false, + _shards: { + failed: 0, + successful: 1, + total: 1, + }, + hits: { + hits: [], + }, + }); + }); + + it('should query Elasticsearch correctly', async () => { + await getPods({ + ...baseOptions, + from: 'now-5d', + to: 'now-3d', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + }); + + expect(metricsDataClientMock.getMetricIndices).toHaveBeenCalledTimes(1); + expect(metricsDataClientMock.getMetricIndices).toHaveBeenCalledWith({ + savedObjectsClient: soClientMock, + }); + + const dsl = esClientMock.search.mock.lastCall?.[0] as SearchRequest | undefined; + const { bool } = dsl?.query || {}; + expect(bool).toBeDefined(); + + expect(bool?.filter).toEqual([ + { + range: { + '@timestamp': { + gte: 'now-5d', + lte: 'now-3d', + }, + }, + }, + ]); + + expect(bool?.must).toEqual([ + { + exists: { + field: 'kubernetes.pod.uid', + }, + }, + { + exists: { + field: 'kubernetes.node.name', + }, + }, + ]); + }); + + it('should correctly include an EAN filter as a pod ID term query', async () => { + const mockPodId = '123abc'; + + await getPods({ + ...baseOptions, + from: 'now-1h', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + filters: { + ean: `pod:${mockPodId}`, + }, + }); + + const dsl = esClientMock.search.mock.lastCall?.[0] as SearchRequest | undefined; + const { bool } = dsl?.query || {}; + expect(bool).toBeDefined(); + + expect(bool?.must).toEqual( + expect.arrayContaining([ + { + exists: { + field: 'kubernetes.pod.uid', + }, + }, + { + exists: { + field: 'kubernetes.node.name', + }, + }, + { + term: { + 'kubernetes.pod.uid': mockPodId, + }, + }, + ]) + ); + }); + + it('should not query ES and return empty if filtering on non-pod EAN', async () => { + const mockId = 'some-id-123'; + + const result = await getPods({ + ...baseOptions, + from: 'now-1h', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + filters: { + ean: `container:${mockId}`, + }, + }); + + expect(esClientMock.search).toHaveBeenCalledTimes(0); + expect(result).toEqual({ pods: [] }); + }); + + it('should include a wildcard ID filter when an ID filter is provided with asterisks included', async () => { + const mockIdPattern = '*partial-id*'; + + await getPods({ + ...baseOptions, + from: 'now-1h', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + filters: { + id: mockIdPattern, + }, + }); + + const dsl = esClientMock.search.mock.lastCall?.[0] as SearchRequest | undefined; + const { bool } = dsl?.query || {}; + expect(bool).toBeDefined(); + + expect(bool?.must).toEqual( + expect.arrayContaining([ + { + exists: { + field: 'kubernetes.pod.uid', + }, + }, + { + exists: { + field: 'kubernetes.node.name', + }, + }, + { + wildcard: { + 'kubernetes.pod.uid': mockIdPattern, + }, + }, + ]) + ); + }); + + it('should include a term ID filter when an ID filter is provided without asterisks included', async () => { + const mockId = 'full-id'; + + await getPods({ + ...baseOptions, + from: 'now-1h', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + filters: { + id: mockId, + }, + }); + + const dsl = esClientMock.search.mock.lastCall?.[0] as SearchRequest | undefined; + const { bool } = dsl?.query || {}; + expect(bool).toBeDefined(); + + expect(bool?.must).toEqual( + expect.arrayContaining([ + { + exists: { + field: 'kubernetes.pod.uid', + }, + }, + { + exists: { + field: 'kubernetes.node.name', + }, + }, + { + term: { + 'kubernetes.pod.uid': mockId, + }, + }, + ]) + ); + }); + + it('should include a term filter for cloud filters', async () => { + const mockCloudProvider = 'gcp'; + const mockCloudRegion = 'us-central-1'; + + await getPods({ + ...baseOptions, + from: 'now-1h', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + filters: { + 'cloud.provider': mockCloudProvider, + 'cloud.region': mockCloudRegion, + }, + }); + + const dsl = esClientMock.search.mock.lastCall?.[0] as SearchRequest | undefined; + const { bool } = dsl?.query || {}; + expect(bool).toBeDefined(); + + expect(bool?.must).toEqual( + expect.arrayContaining([ + { + exists: { + field: 'kubernetes.pod.uid', + }, + }, + { + exists: { + field: 'kubernetes.node.name', + }, + }, + { + term: { + 'cloud.provider': mockCloudProvider, + }, + }, + { + term: { + 'cloud.region': mockCloudRegion, + }, + }, + ]) + ); + }); + + it('should reject with 400 for invalid "from" date', () => { + return expectToThrowValidationErrorWithStatusCode( + () => + getPods({ + ...baseOptions, + from: 'now-1zz', + to: 'now-3d', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + }), + { statusCode: 400 } + ); + }); + + it('should reject with 400 for invalid "to" date', () => { + return expectToThrowValidationErrorWithStatusCode( + () => + getPods({ + ...baseOptions, + from: 'now-5d', + to: 'now-3fe', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + }), + { statusCode: 400 } + ); + }); + + it('should reject with 400 when "from" is a date that is after "to"', () => { + return expectToThrowValidationErrorWithStatusCode( + () => + getPods({ + ...baseOptions, + from: 'now', + to: 'now-5d', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + }), + { statusCode: 400 } + ); + }); + + it('should reject with 400 when "from" is in the future', () => { + return expectToThrowValidationErrorWithStatusCode( + () => + getPods({ + ...baseOptions, + from: 'now+1d', + elasticsearchClient: esClientMock, + savedObjectsClient: soClientMock, + }), + { statusCode: 400 } + ); + }); +}); diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.ts b/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.ts new file mode 100644 index 000000000000..db2bc11ae231 --- /dev/null +++ b/x-pack/plugins/asset_manager/server/lib/accessors/pods/get_pods.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import { Asset } from '../../../../common/types_api'; +import { GetPodsOptionsPublic } from '../../../../common/types_client'; +import { + AssetClientDependencies, + AssetClientOptionsWithInjectedValues, +} from '../../asset_client_types'; +import { parseEan } from '../../parse_ean'; +import { collectPods } from '../../collectors/pods'; +import { validateStringDateRange } from '../../validators/validate_date_range'; + +export type GetPodsOptions = GetPodsOptionsPublic & AssetClientDependencies; +export type GetPodsOptionsInjected = AssetClientOptionsWithInjectedValues; + +export async function getPods(options: GetPodsOptionsInjected): Promise<{ pods: Asset[] }> { + validateStringDateRange(options.from, options.to); + + const metricsIndices = await options.metricsClient.getMetricIndices({ + savedObjectsClient: options.savedObjectsClient, + }); + + const filters: QueryDslQueryContainer[] = []; + + if (options.filters?.ean) { + const ean = Array.isArray(options.filters.ean) ? options.filters.ean[0] : options.filters.ean; + const { kind, id } = parseEan(ean); + + // if EAN filter isn't targeting a pod asset, we don't need to do this query + if (kind !== 'pod') { + return { + pods: [], + }; + } + + filters.push({ + term: { + 'kubernetes.pod.uid': id, + }, + }); + } + + if (options.filters?.id) { + const fn = options.filters.id.includes('*') ? 'wildcard' : 'term'; + filters.push({ + [fn]: { + 'kubernetes.pod.uid': options.filters.id, + }, + }); + } + + if (options.filters?.['orchestrator.cluster.name']) { + filters.push({ + term: { + 'orchestrator.cluster.name': options.filters['orchestrator.cluster.name'], + }, + }); + } + + if (options.filters?.['cloud.provider']) { + filters.push({ + term: { + 'cloud.provider': options.filters['cloud.provider'], + }, + }); + } + + if (options.filters?.['cloud.region']) { + filters.push({ + term: { + 'cloud.region': options.filters['cloud.region'], + }, + }); + } + + const { assets } = await collectPods({ + client: options.elasticsearchClient, + from: options.from, + to: options.to || 'now', + filters, + sourceIndices: { + metrics: metricsIndices, + logs: options.sourceIndices.logs, + }, + }); + + return { + pods: assets, + }; +} diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services.ts b/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services.ts index 2831c5d58987..b5a68028efcd 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { Asset } from '../../../../common/types_api'; import { collectServices } from '../../collectors/services'; import { parseEan } from '../../parse_ean'; @@ -23,10 +24,30 @@ export async function getServices( ): Promise<{ services: Asset[] }> { validateStringDateRange(options.from, options.to); - const filters = []; + const filters: QueryDslQueryContainer[] = []; - if (options.parent) { - const { kind, id } = parseEan(options.parent); + if (options.filters?.ean) { + const eans = Array.isArray(options.filters.ean) ? options.filters.ean : [options.filters.ean]; + const services = eans + .map(parseEan) + .filter(({ kind }) => kind === 'service') + .map(({ id }) => id); + + if (services.length === 0) { + return { + services: [], + }; + } + + filters.push({ + terms: { + 'service.name': services, + }, + }); + } + + if (options.filters?.parentEan) { + const { kind, id } = parseEan(options.filters?.parentEan); if (kind === 'host') { filters.push({ @@ -47,6 +68,31 @@ export async function getServices( } } + if (options.filters?.id) { + const fn = options.filters.id.includes('*') ? 'wildcard' : 'term'; + filters.push({ + [fn]: { + 'service.name': options.filters.id, + }, + }); + } + + if (options.filters?.['cloud.provider']) { + filters.push({ + term: { + 'cloud.provider': options.filters['cloud.provider'], + }, + }); + } + + if (options.filters?.['cloud.region']) { + filters.push({ + term: { + 'cloud.region': options.filters['cloud.region'], + }, + }); + } + const apmIndices = await options.getApmIndices(options.savedObjectsClient); const { assets } = await collectServices({ client: options.elasticsearchClient, diff --git a/x-pack/plugins/asset_manager/server/lib/asset_client.ts b/x-pack/plugins/asset_manager/server/lib/asset_client.ts index a7aad8f6a01c..9de64a9e6c00 100644 --- a/x-pack/plugins/asset_manager/server/lib/asset_client.ts +++ b/x-pack/plugins/asset_manager/server/lib/asset_client.ts @@ -5,11 +5,17 @@ * 2.0. */ +import { orderBy } from 'lodash'; import { Asset } from '../../common/types_api'; +import { GetAssetsOptionsPublic } from '../../common/types_client'; import { getContainers, GetContainersOptions } from './accessors/containers/get_containers'; import { getHosts, GetHostsOptions } from './accessors/hosts/get_hosts'; import { getServices, GetServicesOptions } from './accessors/services/get_services'; +import { getPods, GetPodsOptions } from './accessors/pods/get_pods'; import { AssetClientBaseOptions, AssetClientOptionsWithInjectedValues } from './asset_client_types'; +import { AssetClientDependencies } from './asset_client_types'; + +type GetAssetsOptions = GetAssetsOptionsPublic & AssetClientDependencies; export class AssetClient { constructor(private baseOptions: AssetClientBaseOptions) {} @@ -35,4 +41,16 @@ export class AssetClient { const withInjected = this.injectOptions(options); return await getContainers(withInjected); } + + async getPods(options: GetPodsOptions): Promise<{ pods: Asset[] }> { + const withInjected = this.injectOptions(options); + return await getPods(withInjected); + } + + async getAssets(options: GetAssetsOptions): Promise<{ assets: Asset[] }> { + const withInjected = this.injectOptions(options); + const { hosts } = await getHosts(withInjected); + const { services } = await getServices(withInjected); + return { assets: orderBy(hosts.concat(services), ['@timestamp'], ['desc']) }; + } } diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts b/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts index 5cbf357e6956..f9a4e2e22ae5 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts @@ -9,11 +9,24 @@ import { estypes } from '@elastic/elasticsearch'; import { Asset } from '../../../common/types_api'; import { CollectorOptions, QUERY_MAX_SIZE } from '.'; -export async function collectPods({ client, from, to, sourceIndices, afterKey }: CollectorOptions) { +export async function collectPods({ + client, + from, + to, + sourceIndices, + filters = [], + afterKey, +}: CollectorOptions) { if (!sourceIndices?.metrics || !sourceIndices?.logs) { throw new Error('missing required metrics/logs indices'); } + const musts = [ + ...filters, + { exists: { field: 'kubernetes.pod.uid' } }, + { exists: { field: 'kubernetes.node.name' } }, + ]; + const { metrics, logs } = sourceIndices; const dsl: estypes.SearchRequest = { index: [metrics, logs], @@ -42,10 +55,7 @@ export async function collectPods({ client, from, to, sourceIndices, afterKey }: }, }, ], - must: [ - { exists: { field: 'kubernetes.pod.uid' } }, - { exists: { field: 'kubernetes.node.name' } }, - ], + must: musts, }, }, }; diff --git a/x-pack/plugins/asset_manager/server/routes/assets/index.ts b/x-pack/plugins/asset_manager/server/routes/assets/index.ts new file mode 100644 index 000000000000..421e6a39baf3 --- /dev/null +++ b/x-pack/plugins/asset_manager/server/routes/assets/index.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createRouteValidationFunction } from '@kbn/io-ts-utils'; +import { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import { GetAssetsQueryOptions, getAssetsQueryOptionsRT } from '../../../common/types_api'; +import { debug } from '../../../common/debug_log'; +import { SetupRouteOptions } from '../types'; +import * as routePaths from '../../../common/constants_routes'; +import { getClientsFromContext, validateStringAssetFilters } from '../utils'; +import { AssetsValidationError } from '../../lib/validators/validation_error'; + +export function assetsRoutes({ + router, + assetClient, +}: SetupRouteOptions) { + const validate = createRouteValidationFunction(getAssetsQueryOptionsRT); + router.get( + { + path: routePaths.GET_ASSETS, + validate: { + query: (q, res) => { + const [invalidResponse, validatedFilters] = validateStringAssetFilters(q, res); + if (invalidResponse) { + return invalidResponse; + } + if (validatedFilters) { + q.filters = validatedFilters; + } + return validate(q, res); + }, + }, + }, + async (context, req, res) => { + const { from = 'now-24h', to = 'now', filters } = req.query || {}; + const { elasticsearchClient, savedObjectsClient } = await getClientsFromContext(context); + + try { + const response = await assetClient.getAssets({ + from, + to, + filters, + elasticsearchClient, + savedObjectsClient, + }); + + return res.ok({ body: response }); + } catch (error: unknown) { + debug('Error while looking up asset records', error); + + if (error instanceof AssetsValidationError) { + return res.customError({ + statusCode: error.statusCode, + body: { + message: `Error while looking up asset records - ${error.message}`, + }, + }); + } + return res.customError({ + statusCode: 500, + body: { message: 'Error while looking up asset records - ' + `${error}` }, + }); + } + } + ); +} diff --git a/x-pack/plugins/asset_manager/server/routes/assets/pods.ts b/x-pack/plugins/asset_manager/server/routes/assets/pods.ts new file mode 100644 index 000000000000..beed936bd5b4 --- /dev/null +++ b/x-pack/plugins/asset_manager/server/routes/assets/pods.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createRouteValidationFunction } from '@kbn/io-ts-utils'; +import { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import { GetPodAssetsQueryOptions, getPodAssetsQueryOptionsRT } from '../../../common/types_api'; +import { debug } from '../../../common/debug_log'; +import { SetupRouteOptions } from '../types'; +import * as routePaths from '../../../common/constants_routes'; +import { getClientsFromContext, validateStringAssetFilters } from '../utils'; +import { AssetsValidationError } from '../../lib/validators/validation_error'; + +export function podsRoutes({ + router, + assetClient, +}: SetupRouteOptions) { + const validate = createRouteValidationFunction(getPodAssetsQueryOptionsRT); + router.get( + { + path: routePaths.GET_PODS, + validate: { + query: (q, res) => { + const [invalidResponse, validatedFilters] = validateStringAssetFilters(q, res); + if (invalidResponse) { + return invalidResponse; + } + if (validatedFilters) { + q.filters = validatedFilters; + } + return validate(q, res); + }, + }, + }, + async (context, req, res) => { + const { from = 'now-24h', to = 'now', filters } = req.query || {}; + const { elasticsearchClient, savedObjectsClient } = await getClientsFromContext(context); + + try { + const response = await assetClient.getPods({ + from, + to, + filters, + elasticsearchClient, + savedObjectsClient, + }); + + return res.ok({ body: response }); + } catch (error: unknown) { + debug('Error while looking up POD asset records', error); + + if (error instanceof AssetsValidationError) { + return res.customError({ + statusCode: error.statusCode, + body: { + message: `Error while looking up pod asset records - ${error.message}`, + }, + }); + } + return res.customError({ + statusCode: 500, + body: { message: 'Error while looking up pod asset records - ' + `${error}` }, + }); + } + } + ); +} diff --git a/x-pack/plugins/asset_manager/server/routes/assets/services.ts b/x-pack/plugins/asset_manager/server/routes/assets/services.ts index 0e7103512ebf..3a025ae5b57f 100644 --- a/x-pack/plugins/asset_manager/server/routes/assets/services.ts +++ b/x-pack/plugins/asset_manager/server/routes/assets/services.ts @@ -14,29 +14,39 @@ import { import { debug } from '../../../common/debug_log'; import { SetupRouteOptions } from '../types'; import * as routePaths from '../../../common/constants_routes'; -import { getClientsFromContext } from '../utils'; +import { getClientsFromContext, validateStringAssetFilters } from '../utils'; import { AssetsValidationError } from '../../lib/validators/validation_error'; export function servicesRoutes({ router, assetClient, }: SetupRouteOptions) { + const validate = createRouteValidationFunction(getServiceAssetsQueryOptionsRT); // GET /assets/services router.get( { path: routePaths.GET_SERVICES, validate: { - query: createRouteValidationFunction(getServiceAssetsQueryOptionsRT), + query: (q, res) => { + const [invalidResponse, validatedFilters] = validateStringAssetFilters(q, res); + if (invalidResponse) { + return invalidResponse; + } + if (validatedFilters) { + q.filters = validatedFilters; + } + return validate(q, res); + }, }, }, async (context, req, res) => { - const { from = 'now-24h', to = 'now', parent } = req.query || {}; + const { from = 'now-24h', to = 'now', filters } = req.query || {}; const { elasticsearchClient, savedObjectsClient } = await getClientsFromContext(context); try { const response = await assetClient.getServices({ from, to, - parent, + filters, elasticsearchClient, savedObjectsClient, }); diff --git a/x-pack/plugins/asset_manager/server/routes/index.ts b/x-pack/plugins/asset_manager/server/routes/index.ts index 20f5abf889e7..52d3198bb8a9 100644 --- a/x-pack/plugins/asset_manager/server/routes/index.ts +++ b/x-pack/plugins/asset_manager/server/routes/index.ts @@ -9,9 +9,11 @@ import { RequestHandlerContext } from '@kbn/core/server'; import { SetupRouteOptions } from './types'; import { pingRoute } from './ping'; import { sampleAssetsRoutes } from './sample_assets'; +import { assetsRoutes } from './assets'; import { hostsRoutes } from './assets/hosts'; import { servicesRoutes } from './assets/services'; import { containersRoutes } from './assets/containers'; +import { podsRoutes } from './assets/pods'; export function setupRoutes({ router, @@ -19,7 +21,9 @@ export function setupRoutes({ }: SetupRouteOptions) { pingRoute({ router, assetClient }); sampleAssetsRoutes({ router, assetClient }); + assetsRoutes({ router, assetClient }); hostsRoutes({ router, assetClient }); servicesRoutes({ router, assetClient }); containersRoutes({ router, assetClient }); + podsRoutes({ router, assetClient }); } diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx index 915676b8f6b5..f12a805cf18a 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/__stories__/editor_menu.stories.tsx @@ -70,8 +70,10 @@ const testVisTypes: BaseVisType[] = [ const testVisTypeAliases: VisTypeAlias[] = [ { title: 'Lens', - aliasApp: 'lens', - aliasPath: 'path/to/lens', + alias: { + app: 'lens', + path: 'path/to/lens', + }, icon: 'lensApp', name: 'lens', description: 'Description of Lens app', @@ -79,8 +81,10 @@ const testVisTypeAliases: VisTypeAlias[] = [ }, { title: 'Maps', - aliasApp: 'maps', - aliasPath: 'path/to/maps', + alias: { + app: 'maps', + path: 'path/to/maps', + }, icon: 'gisApp', name: 'maps', description: 'Description of Maps app', diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx index dbcd3b9cd278..d405a977affd 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx @@ -68,12 +68,14 @@ export const EditorMenu: FC = ({ addElement }) => { trackCanvasUiMetric(METRIC_TYPE.CLICK, `${visType.name}:create`); } - if ('aliasPath' in visType) { - appId = visType.aliasApp; - path = visType.aliasPath; - } else { + if (!('alias' in visType)) { + // this visualization is not an alias appId = 'visualize'; path = `#/create?type=${encodeURIComponent(visType.name)}`; + } else if (visType.alias && 'path' in visType.alias) { + // this visualization **is** an alias, and it has an app to redirect to for creation + appId = visType.alias.app; + path = visType.alias.path; } } else { appId = 'visualize'; @@ -134,7 +136,8 @@ export const EditorMenu: FC = ({ addElement }) => { .getAliases() .sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) => a === b ? 0 : a ? -1 : 1 - ); + ) + .filter(({ disableCreate }: VisTypeAlias) => !disableCreate); const factories = unwrappedEmbeddableFactories .filter( diff --git a/x-pack/plugins/cases/common/constants/index.ts b/x-pack/plugins/cases/common/constants/index.ts index 5a540b610135..ba7e98d775ef 100644 --- a/x-pack/plugins/cases/common/constants/index.ts +++ b/x-pack/plugins/cases/common/constants/index.ts @@ -162,6 +162,7 @@ export const READ_CASES_CAPABILITY = 'read_cases' as const; export const UPDATE_CASES_CAPABILITY = 'update_cases' as const; export const DELETE_CASES_CAPABILITY = 'delete_cases' as const; export const PUSH_CASES_CAPABILITY = 'push_cases' as const; +export const CASES_SETTINGS_CAPABILITY = 'cases_settings' as const; export const CASES_CONNECTORS_CAPABILITY = 'cases_connectors' as const; /** @@ -203,6 +204,7 @@ export const LOCAL_STORAGE_KEYS = { casesQueryParams: 'cases.list.queryParams', casesFilterOptions: 'cases.list.filterOptions', casesTableColumns: 'cases.list.tableColumns', + casesTableFiltersConfig: 'cases.list.tableFiltersConfig', }; /** diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts index 4283adf4c081..fc32ee0d360b 100644 --- a/x-pack/plugins/cases/common/index.ts +++ b/x-pack/plugins/cases/common/index.ts @@ -29,6 +29,7 @@ export type { Ecs, CaseViewRefreshPropInterface, CasesPermissions, + CasesCapabilities, CasesStatus, } from './ui/types'; @@ -52,12 +53,12 @@ export { CASE_COMMENT_SAVED_OBJECT, CASES_CONNECTORS_CAPABILITY, GET_CONNECTORS_CONFIGURE_API_TAG, + CASES_SETTINGS_CAPABILITY, } from './constants'; export type { AttachmentAttributes } from './types/domain'; export { ConnectorTypes, AttachmentType, ExternalReferenceStorageType } from './types/domain'; export { getCasesFromAlertsUrl, getCaseFindUserActionsUrl, throwErrors } from './api'; -export { StatusAll } from './ui/types'; export { createUICapabilities, type CasesUiCapabilities } from './utils/capabilities'; export { getApiTags, type CasesApiTags } from './utils/api_tags'; export { CaseMetricsFeature } from './types/api'; diff --git a/x-pack/plugins/cases/common/types/api/case/v1.ts b/x-pack/plugins/cases/common/types/api/case/v1.ts index 228de9c1c281..9efac679085e 100644 --- a/x-pack/plugins/cases/common/types/api/case/v1.ts +++ b/x-pack/plugins/cases/common/types/api/case/v1.ts @@ -189,11 +189,11 @@ export const CasesFindRequestRt = rt.intersection([ /** * The status of the case (open, closed, in-progress) */ - status: CaseStatusRt, + status: rt.union([CaseStatusRt, rt.array(CaseStatusRt)]), /** * The severity of the case */ - severity: CaseSeverityRt, + severity: rt.union([CaseSeverityRt, rt.array(CaseSeverityRt)]), /** * The uids of the user profiles to filter by */ diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts index 2a76e56a59fe..b4019861c06f 100644 --- a/x-pack/plugins/cases/common/ui/types.ts +++ b/x-pack/plugins/cases/common/ui/types.ts @@ -12,7 +12,11 @@ import type { READ_CASES_CAPABILITY, UPDATE_CASES_CAPABILITY, } from '..'; -import type { CASES_CONNECTORS_CAPABILITY, PUSH_CASES_CAPABILITY } from '../constants'; +import type { + CASES_CONNECTORS_CAPABILITY, + CASES_SETTINGS_CAPABILITY, + PUSH_CASES_CAPABILITY, +} from '../constants'; import type { SnakeToCamelCase } from '../types'; import type { CaseSeverity, @@ -26,6 +30,7 @@ import type { ExternalReferenceAttachment, PersistableStateAttachment, Configuration, + CustomFieldTypes, } from '../types/domain'; import type { CasePatchRequest, @@ -65,14 +70,6 @@ export interface CasesUiConfigType { }; } -export const StatusAll = 'all' as const; -export type StatusAllType = typeof StatusAll; - -export type CaseStatusWithAllStatus = CaseStatuses | StatusAllType; - -export const SeverityAll = 'all' as const; -export type CaseSeverityWithAll = CaseSeverity | typeof SeverityAll; - export const UserActionTypeAll = 'all' as const; export type CaseUserActionTypeWithAll = UserActionFindRequestTypes | typeof UserActionTypeAll; @@ -153,17 +150,27 @@ export interface ParsedUrlQueryParams extends Partial { export type LocalStorageQueryParams = Partial>; -export interface FilterOptions { +export interface SystemFilterOptions { search: string; searchFields: string[]; - severity: CaseSeverityWithAll; - status: CaseStatusWithAllStatus; + severity: CaseSeverity[]; + status: CaseStatuses[]; tags: string[]; assignees: Array | null; reporters: User[]; owner: string[]; category: string[]; } + +export interface FilterOptions extends SystemFilterOptions { + customFields: { + [key: string]: { + type: CustomFieldTypes; + options: string[]; + }; + }; +} + export type PartialFilterOptions = Partial; export type SingleCaseMetrics = SingleCaseMetricsResponse; @@ -299,6 +306,7 @@ export interface CasesPermissions { delete: boolean; push: boolean; connectors: boolean; + settings: boolean; } export interface CasesCapabilities { @@ -308,4 +316,5 @@ export interface CasesCapabilities { [DELETE_CASES_CAPABILITY]: boolean; [PUSH_CASES_CAPABILITY]: boolean; [CASES_CONNECTORS_CAPABILITY]: boolean; + [CASES_SETTINGS_CAPABILITY]: boolean; } diff --git a/x-pack/plugins/cases/common/utils/capabilities.test.tsx b/x-pack/plugins/cases/common/utils/capabilities.test.tsx new file mode 100644 index 000000000000..07b82ea0d0e8 --- /dev/null +++ b/x-pack/plugins/cases/common/utils/capabilities.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createUICapabilities } from './capabilities'; + +describe('createUICapabilities', () => { + it('returns the UI capabilities correctly', () => { + expect(createUICapabilities()).toMatchInlineSnapshot(` + Object { + "all": Array [ + "create_cases", + "read_cases", + "update_cases", + "push_cases", + "cases_connectors", + ], + "delete": Array [ + "delete_cases", + ], + "read": Array [ + "read_cases", + "cases_connectors", + ], + "settings": Array [ + "cases_settings", + ], + } + `); + }); +}); diff --git a/x-pack/plugins/cases/common/utils/capabilities.ts b/x-pack/plugins/cases/common/utils/capabilities.ts index 28b3fa00f927..6b33dd8c8dce 100644 --- a/x-pack/plugins/cases/common/utils/capabilities.ts +++ b/x-pack/plugins/cases/common/utils/capabilities.ts @@ -12,12 +12,14 @@ import { PUSH_CASES_CAPABILITY, READ_CASES_CAPABILITY, UPDATE_CASES_CAPABILITY, + CASES_SETTINGS_CAPABILITY, } from '../constants'; export interface CasesUiCapabilities { all: readonly string[]; read: readonly string[]; delete: readonly string[]; + settings: readonly string[]; } /** * Return the UI capabilities for each type of operation. These strings must match the values defined in the UI @@ -33,4 +35,5 @@ export const createUICapabilities = (): CasesUiCapabilities => ({ ] as const, read: [READ_CASES_CAPABILITY, CASES_CONNECTORS_CAPABILITY] as const, delete: [DELETE_CASES_CAPABILITY] as const, + settings: [CASES_SETTINGS_CAPABILITY] as const, }); diff --git a/x-pack/plugins/cases/docs/openapi/bundled.json b/x-pack/plugins/cases/docs/openapi/bundled.json index 54a9c31d3431..bf6b28c8441a 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled.json +++ b/x-pack/plugins/cases/docs/openapi/bundled.json @@ -1,9 +1,9 @@ { - "openapi": "3.0.1", + "openapi": "3.1.0", "info": { "title": "Cases", "description": "OpenAPI schema for Cases endpoints", - "version": "0.1", + "version": "0.2", "contact": { "name": "Cases Team" }, @@ -329,7 +329,7 @@ } } }, - "example": [ + "examples": [ { "id": "06116b80-e1c3-11ec-be9b-9b1838238ee6", "title": "security_case" @@ -417,18 +417,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -438,7 +444,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -449,34 +457,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -485,15 +513,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -502,13 +536,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -516,30 +557,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } } @@ -640,18 +696,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -661,7 +723,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -672,34 +736,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -708,15 +792,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -725,13 +815,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -739,30 +836,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } }, @@ -867,18 +979,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -888,7 +1006,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -899,34 +1019,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -935,15 +1075,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -952,13 +1098,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -966,30 +1119,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } }, @@ -1044,23 +1212,37 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } } @@ -1569,8 +1751,10 @@ "content": { "application/json": { "schema": { - "type": "object", - "nullable": true + "type": [ + "object", + "null" + ] } } } @@ -2103,7 +2287,7 @@ } } }, - "example": [ + "examples": [ { "id": "06116b80-e1c3-11ec-be9b-9b1838238ee6", "title": "security_case" @@ -2194,18 +2378,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -2215,7 +2405,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -2226,34 +2418,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -2262,15 +2474,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -2279,13 +2497,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -2293,30 +2518,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } } @@ -2420,18 +2660,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -2441,7 +2687,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -2452,34 +2700,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -2488,15 +2756,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -2505,13 +2779,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -2519,30 +2800,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } }, @@ -2650,18 +2946,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -2671,7 +2973,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-06-01T17:07:17.767Z" + "examples": [ + "2022-06-01T17:07:17.767Z" + ] }, "created_by": { "type": "object", @@ -2682,34 +2986,54 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "error": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "type": "string", - "example": "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + "examples": [ + "4a97a440-e1cd-11ec-be9b-9b1838238ee6" + ] }, "mappings": { "type": "array", @@ -2718,15 +3042,21 @@ "properties": { "action_type": { "type": "string", - "example": "overwrite" + "examples": [ + "overwrite" + ] }, "source": { "type": "string", - "example": "title" + "examples": [ + "title" + ] }, "target": { "type": "string", - "example": "summary" + "examples": [ + "summary" + ] } } } @@ -2735,13 +3065,20 @@ "$ref": "#/components/schemas/owners" }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": "2022-06-01T19:58:48.169Z" + "examples": [ + "2022-06-01T19:58:48.169Z" + ] }, "updated_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -2749,30 +3086,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "version": { "type": "string", - "example": "WzIwNzMsMV0=" + "examples": [ + "WzIwNzMsMV0=" + ] } } }, @@ -2909,23 +3261,37 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } } @@ -3515,8 +3881,10 @@ "content": { "application/json": { "schema": { - "type": "object", - "nullable": true + "type": [ + "object", + "null" + ] } } } @@ -3610,8 +3978,7 @@ "$ref": "#/components/parameters/space_id" }, { - "$ref": "#/components/parameters/page_index", - "example": "1" + "$ref": "#/components/parameters/page_index" }, { "$ref": "#/components/parameters/page_size" @@ -3679,7 +4046,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "parameters": { @@ -3703,9 +4071,13 @@ "type": "string", "minItems": 1, "maxItems": 100 - } - }, - "example": "d4e7abb0-b462-11ec-9a8d-698504725a43" + }, + "examples": [ + [ + "d4e7abb0-b462-11ec-9a8d-698504725a43" + ] + ] + } }, "assignees": { "in": "query", @@ -3740,11 +4112,15 @@ "items": { "type": "string" }, - "maxItems": 100 + "maxItems": 100, + "examples": [ + [ + "my-category" + ] + ] } ] - }, - "example": "my-category" + } }, "defaultSearchOperator": { "in": "query", @@ -3752,9 +4128,11 @@ "description": "he default operator to use for the simple_query_string.", "schema": { "type": "string", - "default": "OR" - }, - "example": "OR" + "default": "OR", + "examples": [ + "OR" + ] + } }, "from": { "in": "query", @@ -3762,7 +4140,9 @@ "description": "Returns only cases that were created after a specific date. The date must be specified as a KQL data range or date match expression.\n", "schema": { "type": "string", - "example": "now-1d" + "examples": [ + "now-1d" + ] } }, "owner": { @@ -3778,11 +4158,15 @@ "type": "array", "items": { "$ref": "#/components/schemas/owners" - } + }, + "examples": [ + [ + "cases" + ] + ] } ] - }, - "example": "cases" + } }, "page_index": { "in": "query", @@ -3791,7 +4175,10 @@ "required": false, "schema": { "type": "integer", - "default": 1 + "default": 1, + "examples": [ + 1 + ] } }, "page_size": { @@ -3819,11 +4206,15 @@ "items": { "type": "string" }, - "maxItems": 100 + "maxItems": 100, + "examples": [ + [ + "elastic" + ] + ] } ] - }, - "example": "elastic" + } }, "search": { "in": "query", @@ -3880,9 +4271,11 @@ "status", "severity" ], - "default": "createdAt" - }, - "example": "updatedAt" + "default": "createdAt", + "examples": [ + "updatedAt" + ] + } }, "sort_order": { "in": "query", @@ -3908,9 +4301,11 @@ "closed", "in-progress", "open" + ], + "examples": [ + "open" ] - }, - "example": "open" + } }, "tags": { "in": "query", @@ -3926,20 +4321,26 @@ "items": { "type": "string" }, - "maxItems": 100 + "maxItems": 100, + "examples": [ + [ + "tag-1" + ] + ] } ] - }, - "example": "tag-1" + } }, "to": { "in": "query", "name": "to", "description": "Returns only cases that were created before a specific date. The date must be specified as a KQL data range or date match expression.\n", "schema": { - "type": "string" - }, - "example": "now+1d" + "type": "string", + "examples": [ + "now+1d" + ] + } }, "alert_id": { "in": "path", @@ -3948,7 +4349,9 @@ "required": true, "schema": { "type": "string", - "example": "09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540" + "examples": [ + "09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540" + ] } }, "configuration_id": { @@ -3958,7 +4361,9 @@ "required": true, "schema": { "type": "string", - "example": "3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9" + "examples": [ + "3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9" + ] } }, "case_id": { @@ -3968,7 +4373,9 @@ "required": true, "schema": { "type": "string", - "example": "9c235210-6834-11ea-a78c-6ffb38a34414" + "examples": [ + "9c235210-6834-11ea-a78c-6ffb38a34414" + ] } }, "includeComments": { @@ -3988,7 +4395,9 @@ "required": true, "schema": { "type": "string", - "example": "71ec1870-725b-11ea-a0b2-c51ea50a58e2" + "examples": [ + "71ec1870-725b-11ea-a0b2-c51ea50a58e2" + ] } }, "connector_id": { @@ -3998,7 +4407,9 @@ "required": true, "schema": { "type": "string", - "example": "abed3a70-71bd-11ea-a0b2-c51ea50a58e2" + "examples": [ + "abed3a70-71bd-11ea-a0b2-c51ea50a58e2" + ] } }, "user_action_types": { @@ -4026,9 +4437,13 @@ "title", "user" ] - } - }, - "example": "create_case" + }, + "examples": [ + [ + "create_case" + ] + ] + } }, "space_id": { "in": "path", @@ -4037,16 +4452,20 @@ "required": true, "schema": { "type": "string", - "example": "default" + "examples": [ + "default" + ] } } }, "schemas": { "assignees": { - "type": "array", + "type": [ + "array", + "null" + ], "description": "An array containing users that are assigned to the case.", "maxItems": 10, - "nullable": true, "items": { "type": "object", "required": [ @@ -4056,7 +4475,9 @@ "uid": { "type": "string", "description": "A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API.", - "example": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + "examples": [ + "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0" + ] } } } @@ -4074,24 +4495,34 @@ "properties": { "fields": { "description": "An object containing the connector fields. To create a case without a connector, specify null. To update a case to remove the connector, specify null.", - "nullable": true, - "type": "string", - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "description": "The identifier for the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "description": "The type of connector. To create a case without a connector, use `.none`. To update a case to remove the connector, specify `.none`.", "type": "string", - "example": ".none", + "examples": [ + ".none" + ], "enum": [ ".none" ] @@ -4110,9 +4541,13 @@ "type": "object", "properties": { "fields": { - "type": "string", - "nullable": true, - "example": null + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "id": { "description": "The identifier for the connector. To retrieve connector IDs, use the find connectors API.", @@ -4125,7 +4560,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".cases-webhook", + "examples": [ + ".cases-webhook" + ], "enum": [ ".cases-webhook" ] @@ -4154,18 +4591,24 @@ "properties": { "issueType": { "description": "The type of issue.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "parent": { "description": "The key of the parent issue, when the issue type is sub-task.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "priority": { "description": "The priority of the issue.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -4180,7 +4623,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".jira", + "examples": [ + ".jira" + ], "enum": [ ".jira" ] @@ -4200,8 +4645,10 @@ "properties": { "fields": { "description": "An object containing the connector fields. If you want to omit any individual field, specify null as its value.", - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "required": [ "issueTypes", "severityCode" @@ -4231,7 +4678,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".resilient", + "examples": [ + ".resilient" + ], "enum": [ ".resilient" ] @@ -4262,28 +4711,38 @@ "properties": { "category": { "description": "The category of the incident.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "impact": { "description": "The effect an incident had on business.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "severity": { "description": "The severity of the incident.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "subcategory": { "description": "The subcategory of the incident.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "urgency": { "description": "The extent to which the incident resolution can be delayed.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -4298,7 +4757,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".servicenow", + "examples": [ + ".servicenow" + ], "enum": [ ".servicenow" ] @@ -4331,38 +4792,52 @@ "properties": { "category": { "description": "The category of the incident.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "destIp": { "description": "Indicates whether cases will send a comma-separated list of destination IPs.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "malwareHash": { "description": "Indicates whether cases will send a comma-separated list of malware hashes.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "malwareUrl": { "description": "Indicates whether cases will send a comma-separated list of malware URLs.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "priority": { "description": "The priority of the issue.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "sourceIp": { "description": "Indicates whether cases will send a comma-separated list of source IPs.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "subcategory": { "description": "The subcategory of the incident.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -4377,7 +4852,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".servicenow-sir", + "examples": [ + ".servicenow-sir" + ], "enum": [ ".servicenow-sir" ] @@ -4404,8 +4881,10 @@ "properties": { "caseId": { "description": "The case identifier for Swimlane connectors.", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] } } }, @@ -4420,7 +4899,9 @@ "type": { "description": "The type of connector.", "type": "string", - "example": ".swimlane", + "examples": [ + ".swimlane" + ], "enum": [ ".swimlane" ] @@ -4435,7 +4916,9 @@ "observability", "securitySolution" ], - "example": "cases" + "examples": [ + "cases" + ] }, "settings": { "type": "object", @@ -4447,7 +4930,9 @@ "syncAlerts": { "description": "Turns alert syncing on or off.", "type": "boolean", - "example": true + "examples": [ + true + ] } } }, @@ -4566,10 +5051,12 @@ "description": "The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`.\n", "oneOf": [ { - "type": "string", + "type": [ + "string", + "null" + ], "minLength": 1, - "maxLength": 160, - "nullable": true + "maxLength": 160 }, { "type": "boolean" @@ -4583,27 +5070,43 @@ }, "case_response_closed_by_properties": { "title": "Case response properties for closed_by", - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -4623,13 +5126,17 @@ "type": "array", "items": { "type": "string", - "example": "a6e12ac4-7bce-457b-84f6-d7ce8deb8446" + "examples": [ + "a6e12ac4-7bce-457b-84f6-d7ce8deb8446" + ] } }, "created_at": { "type": "string", "format": "date-time", - "example": "2023-11-06T19:29:38.424Z" + "examples": [ + "2023-11-06T19:29:38.424Z" + ] }, "created_by": { "type": "object", @@ -4640,48 +5147,73 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "id": { "type": "string", - "example": "73362370-ab1a-11ec-985f-97e55adae8b9" + "examples": [ + "73362370-ab1a-11ec-985f-97e55adae8b9" + ] }, "index": { "type": "array", "items": { "type": "string", - "example": ".internal.alerts-security.alerts-default-000001" + "examples": [ + ".internal.alerts-security.alerts-default-000001" + ] } }, "owner": { "$ref": "#/components/schemas/owners" }, "pushed_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "example": null, - "nullable": true + "examples": [ + null + ] }, "pushed_by": { - "type": "object", + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -4689,26 +5221,39 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } }, "rule": { "type": "object", @@ -4716,30 +5261,40 @@ "id": { "description": "The rule identifier.", "type": "string", - "example": "94d80550-aaf4-11ec-985f-97e55adae8b9" + "examples": [ + "94d80550-aaf4-11ec-985f-97e55adae8b9" + ] }, "name": { "description": "The rule name.", "type": "string", - "example": "security_rule" + "examples": [ + "security_rule" + ] } } }, "type": { "type": "string", - "example": "alert", + "examples": [ + "alert" + ], "enum": [ "alert" ] }, "updated_at": { - "type": "string", - "format": "date-time", - "nullable": true + "type": [ + "string", + "null" + ], + "format": "date-time" }, "updated_by": { - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "required": [ "email", "full_name", @@ -4747,29 +5302,45 @@ ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } } }, "version": { "type": "string", - "example": "WzMwNDgsMV0=" + "examples": [ + "WzMwNDgsMV0=" + ] } } }, @@ -4778,23 +5349,37 @@ "type": "object", "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -4805,27 +5390,43 @@ }, "case_response_pushed_by_properties": { "title": "Case response properties for pushed_by", - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -4836,27 +5437,43 @@ }, "case_response_updated_by_properties": { "title": "Case response properties for updated_by", - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -4874,57 +5491,77 @@ "properties": { "comment": { "type": "string", - "example": "A new comment." + "examples": [ + "A new comment." + ] }, "created_at": { "type": "string", "format": "date-time", - "example": "2022-05-13T09:16:17.416Z" + "examples": [ + "2022-05-13T09:16:17.416Z" + ] }, "created_by": { "$ref": "#/components/schemas/case_response_created_by_properties" }, "id": { "type": "string", - "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + "examples": [ + "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + ] }, "owner": { "$ref": "#/components/schemas/owners" }, "pushed_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": null + "examples": [ + null + ] }, "pushed_by": { "$ref": "#/components/schemas/case_response_pushed_by_properties" }, "type": { "type": "string", - "example": "user", + "examples": [ + "user" + ], "enum": [ "user" ] }, "updated_at": { - "type": "string", + "type": [ + "string", + "null" + ], "format": "date-time", - "nullable": true, - "example": null + "examples": [ + null + ] }, "updated_by": { "$ref": "#/components/schemas/case_response_updated_by_properties" }, "version": { "type": "string", - "example": "WzIwNDMxLDFd" + "examples": [ + "WzIwNDMxLDFd" + ] } } }, "external_service": { - "type": "object", - "nullable": true, + "type": [ + "object", + "null" + ], "properties": { "connector_id": { "type": "string" @@ -4946,29 +5583,45 @@ "format": "date-time" }, "pushed_by": { - "type": "object", + "type": [ + "object", + "null" + ], "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } - }, - "nullable": true + } } } }, @@ -5012,14 +5665,18 @@ "$ref": "#/components/schemas/assignees" }, "category": { - "type": "string", - "description": "The case category.", - "nullable": true + "type": [ + "string", + "null" + ], + "description": "The case category." }, "closed_at": { - "type": "string", - "format": "date-time", - "nullable": true + "type": [ + "string", + "null" + ], + "format": "date-time" }, "closed_by": { "$ref": "#/components/schemas/case_response_closed_by_properties" @@ -5075,7 +5732,9 @@ "created_at": { "type": "string", "format": "date-time", - "example": "2022-05-13T09:16:17.416Z" + "examples": [ + "2022-05-13T09:16:17.416Z" + ] }, "created_by": { "$ref": "#/components/schemas/case_response_created_by_properties" @@ -5103,10 +5762,12 @@ "description": "The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`.\n", "oneOf": [ { - "type": "string", + "type": [ + "string", + "null" + ], "minLength": 1, - "maxLength": 160, - "nullable": true + "maxLength": 160 }, { "type": "boolean" @@ -5118,20 +5779,28 @@ }, "description": { "type": "string", - "example": "A case description." + "examples": [ + "A case description." + ] }, "duration": { - "type": "integer", + "type": [ + "integer", + "null" + ], "description": "The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero.\n", - "nullable": true, - "example": 120 + "examples": [ + 120 + ] }, "external_service": { "$ref": "#/components/schemas/external_service" }, "id": { "type": "string", - "example": "66b9aa00-94fa-11ea-9f74-e7e108796192" + "examples": [ + "66b9aa00-94fa-11ea-9f74-e7e108796192" + ] }, "owner": { "$ref": "#/components/schemas/owners" @@ -5150,33 +5819,45 @@ "items": { "type": "string" }, - "example": [ - "tag-1" + "examples": [ + [ + "tag-1" + ] ] }, "title": { "type": "string", - "example": "Case title 1" + "examples": [ + "Case title 1" + ] }, "totalAlerts": { "type": "integer", - "example": 0 + "examples": [ + 0 + ] }, "totalComment": { "type": "integer", - "example": 0 + "examples": [ + 0 + ] }, "updated_at": { - "type": "string", - "format": "date-time", - "nullable": true + "type": [ + "string", + "null" + ], + "format": "date-time" }, "updated_by": { "$ref": "#/components/schemas/case_response_updated_by_properties" }, "version": { "type": "string", - "example": "WzUzMiwxXQ==" + "examples": [ + "WzUzMiwxXQ==" + ] } } }, @@ -5186,14 +5867,18 @@ "properties": { "error": { "type": "string", - "example": "Unauthorized" + "examples": [ + "Unauthorized" + ] }, "message": { "type": "string" }, "statusCode": { "type": "integer", - "example": 401 + "examples": [ + 401 + ] } } }, @@ -5280,10 +5965,12 @@ "description": "The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`.\n", "oneOf": [ { - "type": "string", + "type": [ + "string", + "null" + ], "minLength": 1, - "maxLength": 160, - "nullable": true + "maxLength": 160 }, { "type": "boolean" @@ -5349,7 +6036,9 @@ "close-by-pushing", "close-by-user" ], - "example": "close-by-user" + "examples": [ + "close-by-user" + ] }, "connector_types": { "type": "string", @@ -5363,7 +6052,9 @@ ".servicenow-sir", ".swimlane" ], - "example": ".none" + "examples": [ + ".none" + ] }, "set_case_configuration_request": { "title": "Set case configuration request", @@ -5384,18 +6075,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -5472,18 +6169,24 @@ "properties": { "fields": { "description": "The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`.", - "nullable": true, - "type": "object" + "type": [ + "object", + "null" + ] }, "id": { "description": "The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -5539,7 +6242,9 @@ "version": { "description": "The version of the connector. To retrieve the version value, use the get configuration API.\n", "type": "string", - "example": "WzIwMiwxXQ==" + "examples": [ + "WzIwMiwxXQ==" + ] } } }, @@ -5576,7 +6281,9 @@ } ], "x-technical-preview": true, - "example": "6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42" + "examples": [ + "6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42" + ] }, "alert_indices": { "title": "Alert indices", @@ -5604,12 +6311,16 @@ "id": { "description": "The rule identifier.", "type": "string", - "example": "94d80550-aaf4-11ec-985f-97e55adae8b9" + "examples": [ + "94d80550-aaf4-11ec-985f-97e55adae8b9" + ] }, "name": { "description": "The rule name.", "type": "string", - "example": "security_rule" + "examples": [ + "security_rule" + ] } } }, @@ -5640,7 +6351,9 @@ "type": { "description": "The type of comment.", "type": "string", - "example": "alert", + "examples": [ + "alert" + ], "enum": [ "alert" ] @@ -5656,7 +6369,9 @@ "description": "The new comment. It is required only when `type` is `user`.", "type": "string", "maxLength": 30000, - "example": "A new comment." + "examples": [ + "A new comment." + ] }, "owner": { "$ref": "#/components/schemas/owners" @@ -5664,7 +6379,9 @@ "type": { "type": "string", "description": "The type of comment.", - "example": "user", + "examples": [ + "user" + ], "enum": [ "user" ] @@ -5711,7 +6428,9 @@ "id": { "type": "string", "description": "The identifier for the comment. To retrieve comment IDs, use the get comments API.\n", - "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + "examples": [ + "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + ] }, "index": { "$ref": "#/components/schemas/alert_indices" @@ -5728,12 +6447,16 @@ "enum": [ "alert" ], - "example": "alert" + "examples": [ + "alert" + ] }, "version": { "description": "The current comment version. To retrieve version values, use the get comments API.\n", "type": "string", - "example": "Wzk1LDFd" + "examples": [ + "Wzk1LDFd" + ] } } }, @@ -5746,12 +6469,16 @@ "description": "The new comment. It is required only when `type` is `user`.", "type": "string", "maxLength": 30000, - "example": "A new comment." + "examples": [ + "A new comment." + ] }, "id": { "type": "string", "description": "The identifier for the comment. To retrieve comment IDs, use the get comments API.\n", - "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + "examples": [ + "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + ] }, "owner": { "$ref": "#/components/schemas/owners" @@ -5762,12 +6489,16 @@ "enum": [ "user" ], - "example": "user" + "examples": [ + "user" + ] }, "version": { "description": "The current comment version. To retrieve version values, use the get comments API.\n", "type": "string", - "example": "Wzk1LDFd" + "examples": [ + "Wzk1LDFd" + ] } }, "required": [ @@ -5802,7 +6533,9 @@ "push_to_service", "update" ], - "example": "create" + "examples": [ + "create" + ] }, "payload_alert_comment": { "type": "object", @@ -5814,7 +6547,9 @@ "oneOf": [ { "type": "string", - "example": "1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d" + "examples": [ + "1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d" + ] }, { "type": "array", @@ -5828,7 +6563,9 @@ "oneOf": [ { "type": "string", - "example": ".alerts-observability.logs.alerts-default" + "examples": [ + ".alerts-observability.logs.alerts-default" + ] }, { "type": "array", @@ -5847,12 +6584,16 @@ "id": { "description": "The rule identifier.", "type": "string", - "example": "94d80550-aaf4-11ec-985f-97e55adae8b9" + "examples": [ + "94d80550-aaf4-11ec-985f-97e55adae8b9" + ] }, "name": { "description": "The rule name.", "type": "string", - "example": "security_rule" + "examples": [ + "security_rule" + ] } } }, @@ -5881,9 +6622,11 @@ "type": "object", "properties": { "fields": { - "description": "An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.", - "nullable": true, - "type": "object", + "description": "An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.\n", + "type": [ + "object", + "null" + ], "properties": { "caseId": { "description": "The case identifier for Swimlane connectors.", @@ -5895,8 +6638,10 @@ }, "destIp": { "description": "Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "impact": { "description": "The effect an incident had on business for ServiceNow ITSM connectors.", @@ -5915,13 +6660,17 @@ }, "malwareHash": { "description": "Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "malwareUrl": { "description": "Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "parent": { "description": "The key of the parent issue, when the issue type is sub-task for Jira connectors.", @@ -5941,8 +6690,10 @@ }, "sourceIp": { "description": "Indicates whether cases will send a comma-separated list of source IPs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "subcategory": { "description": "The subcategory of the incident for ServiceNow ITSM connectors.", @@ -5953,17 +6704,23 @@ "type": "string" } }, - "example": null + "examples": [ + null + ] }, "id": { "description": "The identifier for the connector. To create a case without a connector, use `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. To create a case without a connector, use `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -5982,9 +6739,11 @@ "type": "object", "properties": { "fields": { - "description": "An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.", - "nullable": true, - "type": "object", + "description": "An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.\n", + "type": [ + "object", + "null" + ], "properties": { "caseId": { "description": "The case identifier for Swimlane connectors.", @@ -5996,8 +6755,10 @@ }, "destIp": { "description": "Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "impact": { "description": "The effect an incident had on business for ServiceNow ITSM connectors.", @@ -6016,13 +6777,17 @@ }, "malwareHash": { "description": "Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "malwareUrl": { "description": "Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "parent": { "description": "The key of the parent issue, when the issue type is sub-task for Jira connectors.", @@ -6042,8 +6807,10 @@ }, "sourceIp": { "description": "Indicates whether cases will send a comma-separated list of source IPs for ServiceNow SecOps connectors.", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "subcategory": { "description": "The subcategory of the incident for ServiceNow ITSM connectors.", @@ -6054,17 +6821,23 @@ "type": "string" } }, - "example": null + "examples": [ + null + ] }, "id": { "description": "The identifier for the connector. To create a case without a connector, use `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "name": { "description": "The name of the connector. To create a case without a connector, use `none`.", "type": "string", - "example": "none" + "examples": [ + "none" + ] }, "type": { "$ref": "#/components/schemas/connector_types" @@ -6089,11 +6862,13 @@ "tags": { "type": "array", "items": { - "type": "string", - "example": [ + "type": "string" + }, + "examples": [ + [ "tag-1" ] - } + ] }, "title": { "type": "string" @@ -6101,9 +6876,11 @@ } }, "payload_delete": { - "type": "object", - "description": "If the `action` is `delete` and the `type` is `delete_case`, the payload is nullable.", - "nullable": true + "type": [ + "object", + "null" + ], + "description": "If the `action` is `delete` and the `type` is `delete_case`, the payload is nullable." }, "payload_description": { "type": "object", @@ -6153,8 +6930,10 @@ "items": { "type": "string" }, - "example": [ - "tag-1" + "examples": [ + [ + "tag-1" + ] ] } } @@ -6206,7 +6985,9 @@ "settings", "severity" ], - "example": "create_case" + "examples": [ + "create_case" + ] }, "user_actions_response_properties": { "type": "object", @@ -6227,43 +7008,67 @@ }, "action_id": { "type": "string", - "example": "22fd3e30-03b1-11ed-920c-974bfa104448" + "examples": [ + "22fd3e30-03b1-11ed-920c-974bfa104448" + ] }, "case_id": { "type": "string", - "example": "22df07d0-03b1-11ed-920c-974bfa104448" + "examples": [ + "22df07d0-03b1-11ed-920c-974bfa104448" + ] }, "comment_id": { - "type": "string", - "nullable": true, - "example": "578608d0-03b1-11ed-920c-974bfa104448" + "type": [ + "string", + "null" + ], + "examples": [ + "578608d0-03b1-11ed-920c-974bfa104448" + ] }, "created_at": { "type": "string", "format": "date-time", - "example": "2022-05-13T09:16:17.416Z" + "examples": [ + "2022-05-13T09:16:17.416Z" + ] }, "created_by": { "type": "object", "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -6341,36 +7146,56 @@ "$ref": "#/components/schemas/actions" }, "comment_id": { - "type": "string", - "nullable": true, - "example": "578608d0-03b1-11ed-920c-974bfa104448" + "type": [ + "string", + "null" + ], + "examples": [ + "578608d0-03b1-11ed-920c-974bfa104448" + ] }, "created_at": { "type": "string", "format": "date-time", - "example": "2022-05-13T09:16:17.416Z" + "examples": [ + "2022-05-13T09:16:17.416Z" + ] }, "created_by": { "type": "object", "properties": { "email": { - "type": "string", - "example": null, - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "full_name": { - "type": "string", - "example": null, - "nullable": true - }, - "username": { - "type": "string", - "example": "elastic", - "nullable": true + "type": [ + "string", + "null" + ], + "examples": [ + null + ] }, "profile_uid": { "type": "string", - "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + "examples": [ + "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + ] + }, + "username": { + "type": [ + "string", + "null" + ], + "examples": [ + "elastic" + ] } }, "required": [ @@ -6381,7 +7206,9 @@ }, "id": { "type": "string", - "example": "22fd3e30-03b1-11ed-920c-974bfa104448" + "examples": [ + "22fd3e30-03b1-11ed-920c-974bfa104448" + ] }, "owner": { "$ref": "#/components/schemas/owners" @@ -6431,7 +7258,9 @@ }, "version": { "type": "string", - "example": "WzM1ODg4LDFd" + "examples": [ + "WzM1ODg4LDFd" + ] }, "type": { "type": "string", @@ -6449,7 +7278,9 @@ "settings", "severity" ], - "example": "create_case" + "examples": [ + "create_case" + ] } } } diff --git a/x-pack/plugins/cases/docs/openapi/bundled.yaml b/x-pack/plugins/cases/docs/openapi/bundled.yaml index 8347d7d85741..e837ef766ab0 100644 --- a/x-pack/plugins/cases/docs/openapi/bundled.yaml +++ b/x-pack/plugins/cases/docs/openapi/bundled.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Cases description: OpenAPI schema for Cases endpoints - version: '0.1' + version: '0.2' contact: name: Cases Team license: @@ -194,7 +194,7 @@ paths: title: type: string description: The case title. - example: + examples: - id: 06116b80-e1c3-11ec-be9b-9b1838238ee6 title: security_case '401': @@ -258,22 +258,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -282,27 +286,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -310,46 +324,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: getConfigurationResponse: $ref: '#/components/examples/get_case_configuration_response' @@ -419,22 +447,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -443,27 +475,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -471,46 +513,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: setCaseConfigResponse: $ref: '#/components/examples/set_case_configuration_response' @@ -582,22 +638,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -606,27 +666,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -634,46 +704,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: updateCaseConfigurationResponse: $ref: '#/components/examples/update_case_configuration_response' @@ -709,20 +793,27 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic examples: getReportersResponse: $ref: '#/components/examples/get_reporters_response' @@ -1028,8 +1119,9 @@ paths: content: application/json: schema: - type: object - nullable: true + type: + - object + - 'null' responses: '200': description: Indicates a successful call. @@ -1344,7 +1436,7 @@ paths: title: type: string description: The case title. - example: + examples: - id: 06116b80-e1c3-11ec-be9b-9b1838238ee6 title: security_case '401': @@ -1409,22 +1501,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -1433,27 +1529,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -1461,46 +1567,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: getConfigurationResponse: $ref: '#/components/examples/get_case_configuration_response' @@ -1571,22 +1691,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -1595,27 +1719,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -1623,46 +1757,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: setCaseConfigResponse: $ref: '#/components/examples/set_case_configuration_response' @@ -1735,22 +1883,26 @@ paths: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' created_at: type: string format: date-time - example: '2022-06-01T17:07:17.767Z' + examples: + - '2022-06-01T17:07:17.767Z' created_by: type: object required: @@ -1759,27 +1911,37 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic error: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -1787,46 +1949,60 @@ paths: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: '#/components/schemas/owners' updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: '2022-06-01T19:58:48.169Z' + examples: + - '2022-06-01T19:58:48.169Z' updated_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzIwNzMsMV0= + examples: + - WzIwNzMsMV0= examples: updateCaseConfigurationResponse: $ref: '#/components/examples/update_case_configuration_response' @@ -1913,20 +2089,27 @@ paths: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic examples: getReportersResponse: $ref: '#/components/examples/get_reporters_response' @@ -2269,8 +2452,9 @@ paths: content: application/json: schema: - type: object - nullable: true + type: + - object + - 'null' responses: '200': description: Indicates a successful call. @@ -2326,7 +2510,6 @@ paths: - $ref: '#/components/parameters/case_id' - $ref: '#/components/parameters/space_id' - $ref: '#/components/parameters/page_index' - example: '1' - $ref: '#/components/parameters/page_size' - $ref: '#/components/parameters/sort_order' - $ref: '#/components/parameters/user_action_types' @@ -2365,7 +2548,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -2386,7 +2570,8 @@ components: type: string minItems: 1 maxItems: 100 - example: d4e7abb0-b462-11ec-9a8d-698504725a43 + examples: + - - d4e7abb0-b462-11ec-9a8d-698504725a43 assignees: in: query name: assignees @@ -2410,7 +2595,8 @@ components: items: type: string maxItems: 100 - example: my-category + examples: + - - my-category defaultSearchOperator: in: query name: defaultSearchOperator @@ -2418,7 +2604,8 @@ components: schema: type: string default: OR - example: OR + examples: + - OR from: in: query name: from @@ -2426,7 +2613,8 @@ components: Returns only cases that were created after a specific date. The date must be specified as a KQL data range or date match expression. schema: type: string - example: now-1d + examples: + - now-1d owner: in: query name: owner @@ -2438,7 +2626,8 @@ components: - type: array items: $ref: '#/components/schemas/owners' - example: cases + examples: + - - cases page_index: in: query name: page @@ -2447,6 +2636,8 @@ components: schema: type: integer default: 1 + examples: + - 1 page_size: in: query name: perPage @@ -2467,7 +2658,8 @@ components: items: type: string maxItems: 100 - example: elastic + examples: + - - elastic search: in: query name: search @@ -2510,7 +2702,8 @@ components: - status - severity default: createdAt - example: updatedAt + examples: + - updatedAt sort_order: in: query name: sortOrder @@ -2532,7 +2725,8 @@ components: - closed - in-progress - open - example: open + examples: + - open tags: in: query name: tags @@ -2544,7 +2738,8 @@ components: items: type: string maxItems: 100 - example: tag-1 + examples: + - - tag-1 to: in: query name: to @@ -2552,7 +2747,8 @@ components: Returns only cases that were created before a specific date. The date must be specified as a KQL data range or date match expression. schema: type: string - example: now+1d + examples: + - now+1d alert_id: in: path name: alertId @@ -2560,7 +2756,8 @@ components: required: true schema: type: string - example: 09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540 + examples: + - 09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540 configuration_id: in: path name: configurationId @@ -2568,7 +2765,8 @@ components: required: true schema: type: string - example: 3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9 + examples: + - 3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9 case_id: in: path name: caseId @@ -2576,7 +2774,8 @@ components: required: true schema: type: string - example: 9c235210-6834-11ea-a78c-6ffb38a34414 + examples: + - 9c235210-6834-11ea-a78c-6ffb38a34414 includeComments: in: query name: includeComments @@ -2593,7 +2792,8 @@ components: required: true schema: type: string - example: 71ec1870-725b-11ea-a0b2-c51ea50a58e2 + examples: + - 71ec1870-725b-11ea-a0b2-c51ea50a58e2 connector_id: in: path name: connectorId @@ -2601,7 +2801,8 @@ components: required: true schema: type: string - example: abed3a70-71bd-11ea-a0b2-c51ea50a58e2 + examples: + - abed3a70-71bd-11ea-a0b2-c51ea50a58e2 user_action_types: in: query name: types @@ -2626,7 +2827,8 @@ components: - tags - title - user - example: create_case + examples: + - - create_case space_id: in: path name: spaceId @@ -2634,13 +2836,15 @@ components: required: true schema: type: string - example: default + examples: + - default schemas: assignees: - type: array + type: + - array + - 'null' description: An array containing users that are assigned to the case. maxItems: 10 - nullable: true items: type: object required: @@ -2649,7 +2853,8 @@ components: uid: type: string description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. - example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 + examples: + - u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 connector_properties_none: title: Create or update case request properties for no connector required: @@ -2662,21 +2867,26 @@ components: properties: fields: description: An object containing the connector fields. To create a case without a connector, specify null. To update a case to remove the connector, specify null. - nullable: true - type: string - example: null + type: + - string + - 'null' + examples: + - null id: description: The identifier for the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`. type: string - example: none + examples: + - none name: description: The name of the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`. type: string - example: none + examples: + - none type: description: The type of connector. To create a case without a connector, use `.none`. To update a case to remove the connector, specify `.none`. type: string - example: .none + examples: + - .none enum: - .none connector_properties_cases_webhook: @@ -2690,9 +2900,11 @@ components: type: object properties: fields: - type: string - nullable: true - example: null + type: + - string + - 'null' + examples: + - null id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -2702,7 +2914,8 @@ components: type: description: The type of connector. type: string - example: .cases-webhook + examples: + - .cases-webhook enum: - .cases-webhook connector_properties_jira: @@ -2725,16 +2938,19 @@ components: properties: issueType: description: The type of issue. - type: string - nullable: true + type: + - string + - 'null' parent: description: The key of the parent issue, when the issue type is sub-task. - type: string - nullable: true + type: + - string + - 'null' priority: description: The priority of the issue. - type: string - nullable: true + type: + - string + - 'null' id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -2744,7 +2960,8 @@ components: type: description: The type of connector. type: string - example: .jira + examples: + - .jira enum: - .jira connector_properties_resilient: @@ -2759,8 +2976,9 @@ components: properties: fields: description: An object containing the connector fields. If you want to omit any individual field, specify null as its value. - type: object - nullable: true + type: + - object + - 'null' required: - issueTypes - severityCode @@ -2782,7 +3000,8 @@ components: type: description: The type of connector. type: string - example: .resilient + examples: + - .resilient enum: - .resilient connector_properties_servicenow: @@ -2807,24 +3026,29 @@ components: properties: category: description: The category of the incident. - type: string - nullable: true + type: + - string + - 'null' impact: description: The effect an incident had on business. - type: string - nullable: true + type: + - string + - 'null' severity: description: The severity of the incident. - type: string - nullable: true + type: + - string + - 'null' subcategory: description: The subcategory of the incident. - type: string - nullable: true + type: + - string + - 'null' urgency: description: The extent to which the incident resolution can be delayed. - type: string - nullable: true + type: + - string + - 'null' id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -2834,7 +3058,8 @@ components: type: description: The type of connector. type: string - example: .servicenow + examples: + - .servicenow enum: - .servicenow connector_properties_servicenow_sir: @@ -2861,32 +3086,39 @@ components: properties: category: description: The category of the incident. - type: string - nullable: true + type: + - string + - 'null' destIp: description: Indicates whether cases will send a comma-separated list of destination IPs. - type: boolean - nullable: true + type: + - boolean + - 'null' malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes. - type: boolean - nullable: true + type: + - boolean + - 'null' malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs. - type: boolean - nullable: true + type: + - boolean + - 'null' priority: description: The priority of the issue. - type: string - nullable: true + type: + - string + - 'null' sourceIp: description: Indicates whether cases will send a comma-separated list of source IPs. - type: boolean - nullable: true + type: + - boolean + - 'null' subcategory: description: The subcategory of the incident. - type: string - nullable: true + type: + - string + - 'null' id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -2896,7 +3128,8 @@ components: type: description: The type of connector. type: string - example: .servicenow-sir + examples: + - .servicenow-sir enum: - .servicenow-sir connector_properties_swimlane: @@ -2917,8 +3150,9 @@ components: properties: caseId: description: The case identifier for Swimlane connectors. - type: string - nullable: true + type: + - string + - 'null' id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -2928,7 +3162,8 @@ components: type: description: The type of connector. type: string - example: .swimlane + examples: + - .swimlane enum: - .swimlane owners: @@ -2939,7 +3174,8 @@ components: - cases - observability - securitySolution - example: cases + examples: + - cases settings: type: object description: An object that contains the case settings. @@ -2949,7 +3185,8 @@ components: syncAlerts: description: Turns alert syncing on or off. type: boolean - example: true + examples: + - true severity_property: type: string description: The severity of the case. @@ -3036,31 +3273,40 @@ components: description: | The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`. oneOf: - - type: string + - type: + - string + - 'null' minLength: 1 maxLength: 160 - nullable: true - type: boolean case_response_closed_by_properties: title: Case response properties for closed_by - type: object - nullable: true + type: + - object + - 'null' properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name @@ -3075,11 +3321,13 @@ components: type: array items: type: string - example: a6e12ac4-7bce-457b-84f6-d7ce8deb8446 + examples: + - a6e12ac4-7bce-457b-84f6-d7ce8deb8446 created_at: type: string format: date-time - example: '2023-11-06T19:29:38.424Z' + examples: + - '2023-11-06T19:29:38.424Z' created_by: type: object required: @@ -3088,171 +3336,226 @@ components: - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic id: type: string - example: 73362370-ab1a-11ec-985f-97e55adae8b9 + examples: + - 73362370-ab1a-11ec-985f-97e55adae8b9 index: type: array items: type: string - example: .internal.alerts-security.alerts-default-000001 + examples: + - .internal.alerts-security.alerts-default-000001 owner: $ref: '#/components/schemas/owners' pushed_at: - type: string + type: + - string + - 'null' format: date-time - example: null - nullable: true + examples: + - null pushed_by: - type: object + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic rule: type: object properties: id: description: The rule identifier. type: string - example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + examples: + - 94d80550-aaf4-11ec-985f-97e55adae8b9 name: description: The rule name. type: string - example: security_rule + examples: + - security_rule type: type: string - example: alert + examples: + - alert enum: - alert updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true updated_by: - type: object - nullable: true + type: + - object + - 'null' required: - email - full_name - username properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic version: type: string - example: WzMwNDgsMV0= + examples: + - WzMwNDgsMV0= case_response_created_by_properties: title: Case response properties for created_by type: object properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name - username case_response_pushed_by_properties: title: Case response properties for pushed_by - type: object - nullable: true + type: + - object + - 'null' properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name - username case_response_updated_by_properties: title: Case response properties for updated_by - type: object - nullable: true + type: + - object + - 'null' properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name @@ -3265,43 +3568,53 @@ components: properties: comment: type: string - example: A new comment. + examples: + - A new comment. created_at: type: string format: date-time - example: '2022-05-13T09:16:17.416Z' + examples: + - '2022-05-13T09:16:17.416Z' created_by: $ref: '#/components/schemas/case_response_created_by_properties' id: type: string - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 owner: $ref: '#/components/schemas/owners' pushed_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: null + examples: + - null pushed_by: $ref: '#/components/schemas/case_response_pushed_by_properties' type: type: string - example: user + examples: + - user enum: - user updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true - example: null + examples: + - null updated_by: $ref: '#/components/schemas/case_response_updated_by_properties' version: type: string - example: WzIwNDMxLDFd + examples: + - WzIwNDMxLDFd external_service: - type: object - nullable: true + type: + - object + - 'null' properties: connector_id: type: string @@ -3317,24 +3630,32 @@ components: type: string format: date-time pushed_by: - type: object + type: + - object + - 'null' properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 - nullable: true + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic status: type: string description: The status of the case. @@ -3371,13 +3692,15 @@ components: assignees: $ref: '#/components/schemas/assignees' category: - type: string + type: + - string + - 'null' description: The case category. - nullable: true closed_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true closed_by: $ref: '#/components/schemas/case_response_closed_by_properties' comments: @@ -3406,7 +3729,8 @@ components: created_at: type: string format: date-time - example: '2022-05-13T09:16:17.416Z' + examples: + - '2022-05-13T09:16:17.416Z' created_by: $ref: '#/components/schemas/case_response_created_by_properties' customFields: @@ -3431,25 +3755,30 @@ components: description: | The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`. oneOf: - - type: string + - type: + - string + - 'null' minLength: 1 maxLength: 160 - nullable: true - type: boolean description: type: string - example: A case description. + examples: + - A case description. duration: - type: integer + type: + - integer + - 'null' description: | The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero. - nullable: true - example: 120 + examples: + - 120 external_service: $ref: '#/components/schemas/external_service' id: type: string - example: 66b9aa00-94fa-11ea-9f74-e7e108796192 + examples: + - 66b9aa00-94fa-11ea-9f74-e7e108796192 owner: $ref: '#/components/schemas/owners' settings: @@ -3462,38 +3791,45 @@ components: type: array items: type: string - example: - - tag-1 + examples: + - - tag-1 title: type: string - example: Case title 1 + examples: + - Case title 1 totalAlerts: type: integer - example: 0 + examples: + - 0 totalComment: type: integer - example: 0 + examples: + - 0 updated_at: - type: string + type: + - string + - 'null' format: date-time - nullable: true updated_by: $ref: '#/components/schemas/case_response_updated_by_properties' version: type: string - example: WzUzMiwxXQ== + examples: + - WzUzMiwxXQ== 4xx_response: type: object title: Unsuccessful cases API response properties: error: type: string - example: Unauthorized + examples: + - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 update_case_request: title: Update case request description: The update case API request body varies depending on the type of connector. @@ -3556,10 +3892,11 @@ components: description: | The custom field value. If the custom field is required, it cannot be explicitly set to null. However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`. oneOf: - - type: string + - type: + - string + - 'null' minLength: 1 maxLength: 160 - nullable: true - type: boolean description: description: An updated description for the case. @@ -3600,7 +3937,8 @@ components: enum: - close-by-pushing - close-by-user - example: close-by-user + examples: + - close-by-user connector_types: type: string description: The type of connector. @@ -3612,7 +3950,8 @@ components: - .servicenow - .servicenow-sir - .swimlane - example: .none + examples: + - .none set_case_configuration_request: title: Set case configuration request description: External connection details, such as the closure type and default connector for cases. @@ -3630,16 +3969,19 @@ components: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' required: @@ -3699,16 +4041,19 @@ components: properties: fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - object + - 'null' id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' required: @@ -3753,7 +4098,8 @@ components: description: | The version of the connector. To retrieve the version value, use the get configuration API. type: string - example: WzIwMiwxXQ== + examples: + - WzIwMiwxXQ== alert_response_properties: type: object properties: @@ -3777,7 +4123,8 @@ components: type: string maxItems: 1000 x-technical-preview: true - example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 + examples: + - 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 alert_indices: title: Alert indices description: | @@ -3799,11 +4146,13 @@ components: id: description: The rule identifier. type: string - example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + examples: + - 94d80550-aaf4-11ec-985f-97e55adae8b9 name: description: The rule name. type: string - example: security_rule + examples: + - security_rule add_alert_comment_request_properties: title: Add case comment request properties for alerts required: @@ -3826,7 +4175,8 @@ components: type: description: The type of comment. type: string - example: alert + examples: + - alert enum: - alert add_user_comment_request_properties: @@ -3838,13 +4188,15 @@ components: description: The new comment. It is required only when `type` is `user`. type: string maxLength: 30000 - example: A new comment. + examples: + - A new comment. owner: $ref: '#/components/schemas/owners' type: type: string description: The type of comment. - example: user + examples: + - user enum: - user required: @@ -3878,7 +4230,8 @@ components: type: string description: | The identifier for the comment. To retrieve comment IDs, use the get comments API. - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 index: $ref: '#/components/schemas/alert_indices' owner: @@ -3890,12 +4243,14 @@ components: type: string enum: - alert - example: alert + examples: + - alert version: description: | The current comment version. To retrieve version values, use the get comments API. type: string - example: Wzk1LDFd + examples: + - Wzk1LDFd update_user_comment_request_properties: title: Update case comment request properties for user comments description: Defines properties for case comment requests when type is user. @@ -3905,12 +4260,14 @@ components: description: The new comment. It is required only when `type` is `user`. type: string maxLength: 30000 - example: A new comment. + examples: + - A new comment. id: type: string description: | The identifier for the comment. To retrieve comment IDs, use the get comments API. - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 owner: $ref: '#/components/schemas/owners' type: @@ -3918,12 +4275,14 @@ components: description: The type of comment. enum: - user - example: user + examples: + - user version: description: | The current comment version. To retrieve version values, use the get comments API. type: string - example: Wzk1LDFd + examples: + - Wzk1LDFd required: - comment - id @@ -3946,7 +4305,8 @@ components: - delete - push_to_service - update - example: create + examples: + - create payload_alert_comment: type: object properties: @@ -3956,14 +4316,16 @@ components: alertId: oneOf: - type: string - example: 1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d + examples: + - 1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d - type: array items: type: string index: oneOf: - type: string - example: .alerts-observability.logs.alerts-default + examples: + - .alerts-observability.logs.alerts-default - type: array items: type: string @@ -3975,11 +4337,13 @@ components: id: description: The rule identifier. type: string - example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + examples: + - 94d80550-aaf4-11ec-985f-97e55adae8b9 name: description: The rule name. type: string - example: security_rule + examples: + - security_rule type: type: string enum: @@ -3996,9 +4360,11 @@ components: type: object properties: fields: - description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. - nullable: true - type: object + description: | + An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. + type: + - object + - 'null' properties: caseId: description: The case identifier for Swimlane connectors. @@ -4008,8 +4374,9 @@ components: type: string destIp: description: Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' impact: description: The effect an incident had on business for ServiceNow ITSM connectors. type: string @@ -4023,12 +4390,14 @@ components: type: string malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' parent: description: The key of the parent issue, when the issue type is sub-task for Jira connectors. type: string @@ -4043,23 +4412,27 @@ components: type: string sourceIp: description: Indicates whether cases will send a comma-separated list of source IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' subcategory: description: The subcategory of the incident for ServiceNow ITSM connectors. type: string urgency: description: The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors. type: string - example: null + examples: + - null id: description: The identifier for the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none name: description: The name of the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' payload_create_case: @@ -4071,9 +4444,11 @@ components: type: object properties: fields: - description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. - nullable: true - type: object + description: | + An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. + type: + - object + - 'null' properties: caseId: description: The case identifier for Swimlane connectors. @@ -4083,8 +4458,9 @@ components: type: string destIp: description: Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' impact: description: The effect an incident had on business for ServiceNow ITSM connectors. type: string @@ -4098,12 +4474,14 @@ components: type: string malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' parent: description: The key of the parent issue, when the issue type is sub-task for Jira connectors. type: string @@ -4118,23 +4496,27 @@ components: type: string sourceIp: description: Indicates whether cases will send a comma-separated list of source IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - boolean + - 'null' subcategory: description: The subcategory of the incident for ServiceNow ITSM connectors. type: string urgency: description: The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors. type: string - example: null + examples: + - null id: description: The identifier for the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none name: description: The name of the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none type: $ref: '#/components/schemas/connector_types' description: @@ -4151,14 +4533,15 @@ components: type: array items: type: string - example: - - tag-1 + examples: + - - tag-1 title: type: string payload_delete: - type: object + type: + - object + - 'null' description: If the `action` is `delete` and the `type` is `delete_case`, the payload is nullable. - nullable: true payload_description: type: object properties: @@ -4191,8 +4574,8 @@ components: type: array items: type: string - example: - - tag-1 + examples: + - - tag-1 payload_title: type: object properties: @@ -4228,7 +4611,8 @@ components: - status - settings - severity - example: create_case + examples: + - create_case user_actions_response_properties: type: object required: @@ -4246,36 +4630,48 @@ components: $ref: '#/components/schemas/actions' action_id: type: string - example: 22fd3e30-03b1-11ed-920c-974bfa104448 + examples: + - 22fd3e30-03b1-11ed-920c-974bfa104448 case_id: type: string - example: 22df07d0-03b1-11ed-920c-974bfa104448 + examples: + - 22df07d0-03b1-11ed-920c-974bfa104448 comment_id: - type: string - nullable: true - example: 578608d0-03b1-11ed-920c-974bfa104448 + type: + - string + - 'null' + examples: + - 578608d0-03b1-11ed-920c-974bfa104448 created_at: type: string format: date-time - example: '2022-05-13T09:16:17.416Z' + examples: + - '2022-05-13T09:16:17.416Z' created_by: type: object properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name @@ -4315,38 +4711,49 @@ components: action: $ref: '#/components/schemas/actions' comment_id: - type: string - nullable: true - example: 578608d0-03b1-11ed-920c-974bfa104448 + type: + - string + - 'null' + examples: + - 578608d0-03b1-11ed-920c-974bfa104448 created_at: type: string format: date-time - example: '2022-05-13T09:16:17.416Z' + examples: + - '2022-05-13T09:16:17.416Z' created_by: type: object properties: email: - type: string - example: null - nullable: true + type: + - string + - 'null' + examples: + - null full_name: - type: string - example: null - nullable: true - username: - type: string - example: elastic - nullable: true + type: + - string + - 'null' + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + username: + type: + - string + - 'null' + examples: + - elastic required: - email - full_name - username id: type: string - example: 22fd3e30-03b1-11ed-920c-974bfa104448 + examples: + - 22fd3e30-03b1-11ed-920c-974bfa104448 owner: $ref: '#/components/schemas/owners' payload: @@ -4366,7 +4773,8 @@ components: - $ref: '#/components/schemas/payload_user_comment' version: type: string - example: WzM1ODg4LDFd + examples: + - WzM1ODg4LDFd type: type: string description: The type of action. @@ -4382,7 +4790,8 @@ components: - status - settings - severity - example: create_case + examples: + - create_case examples: create_case_request: summary: Create a security case that uses a Jira connector. diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/alert_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/alert_id.yaml index 8677b327b91b..24c728f017d1 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/alert_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/alert_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the alert. required: true schema: type: string - example: 09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540 \ No newline at end of file + examples: + - 09f0c261e39e36351d75995b78bb83673774d1bc2cca9df2d15f0e5c0a99a540 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml index eebde8582374..de7cfebbeb6b 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml @@ -4,4 +4,5 @@ description: The identifier for the case. To retrieve case IDs, use the find cas required: true schema: type: string - example: 9c235210-6834-11ea-a78c-6ffb38a34414 \ No newline at end of file + examples: + - 9c235210-6834-11ea-a78c-6ffb38a34414 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/category.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/category.yaml index 8bf20d9aa245..8d28898750ae 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/category.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/category.yaml @@ -8,4 +8,5 @@ schema: items: type: string maxItems: 100 -example: my-category \ No newline at end of file + examples: + - [ my-category ] \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/comment_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/comment_id.yaml index a46f47569e8d..852ad328c6c4 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/comment_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/comment_id.yaml @@ -6,4 +6,5 @@ description: > required: true schema: type: string - example: '71ec1870-725b-11ea-a0b2-c51ea50a58e2' \ No newline at end of file + examples: + - '71ec1870-725b-11ea-a0b2-c51ea50a58e2' \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/configuration_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/configuration_id.yaml index 65cce12afaa9..884821a79952 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/configuration_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/configuration_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the configuration. required: true schema: type: string - example: 3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9 \ No newline at end of file + examples: + - 3297a0f0-b5ec-11ec-b141-0fdb20a7f9a9 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/connector_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/connector_id.yaml index 71cdc7191cfa..7fc146b22126 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/connector_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/connector_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the connector. To retrieve connector IDs, use the required: true schema: type: string - example: abed3a70-71bd-11ea-a0b2-c51ea50a58e2 \ No newline at end of file + examples: + - abed3a70-71bd-11ea-a0b2-c51ea50a58e2 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/defaultSearchOperator.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/defaultSearchOperator.yaml index 8e9004c859b4..cd3cf8cb1c00 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/defaultSearchOperator.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/defaultSearchOperator.yaml @@ -4,4 +4,5 @@ description: he default operator to use for the simple_query_string. schema: type: string default: OR -example: OR \ No newline at end of file + examples: + - OR \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/from.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/from.yaml index 6f9a24dae595..bf92b68ad6ba 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/from.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/from.yaml @@ -5,4 +5,5 @@ description: > The date must be specified as a KQL data range or date match expression. schema: type: string - example: now-1d \ No newline at end of file + examples: + - now-1d \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/ids.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/ids.yaml index c84ec64ab2a5..acd48cd0955a 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/ids.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/ids.yaml @@ -10,4 +10,5 @@ schema: type: string minItems: 1 maxItems: 100 -example: d4e7abb0-b462-11ec-9a8d-698504725a43 + examples: + - [ d4e7abb0-b462-11ec-9a8d-698504725a43 ] diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/owner.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/owner.yaml index 3c5e511742bf..d4f40a440372 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/owner.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/owner.yaml @@ -10,4 +10,5 @@ schema: - type: array items: $ref: '../schemas/owners.yaml' -example: cases \ No newline at end of file + examples: + - [ cases ] \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/page_index.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/page_index.yaml index 9176d3b62094..8ac69a105d15 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/page_index.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/page_index.yaml @@ -5,3 +5,5 @@ required: false schema: type: integer default: 1 + examples: + - 1 diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/reporters.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/reporters.yaml index db28a6c48ae0..3d4d24cafd3c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/reporters.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/reporters.yaml @@ -8,4 +8,5 @@ schema: items: type: string maxItems: 100 -example: elastic + examples: + - [ elastic ] diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/sortField.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/sortField.yaml index 9df834cf9f5a..d5a49214e9d9 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/sortField.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/sortField.yaml @@ -12,4 +12,5 @@ schema: - status - severity default: createdAt -example: updatedAt \ No newline at end of file + examples: + - updatedAt \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/space_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/space_id.yaml index 0a9fba457e3e..45787e844cae 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/space_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/space_id.yaml @@ -4,4 +4,5 @@ description: An identifier for the space. If `/s/` and the identifier are omitte required: true schema: type: string - example: default + examples: + - default diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/status.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/status.yaml index 0517e7516a87..b90edcd58286 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/status.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/status.yaml @@ -7,4 +7,5 @@ schema: - closed - in-progress - open -example: open \ No newline at end of file + examples: + - open \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/tags.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/tags.yaml index d899edbcc38e..b1732fb12457 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/tags.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/tags.yaml @@ -8,4 +8,5 @@ schema: items: type: string maxItems: 100 -example: tag-1 + examples: + - [ tag-1 ] diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/to.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/to.yaml index c176ce840780..dd326cabd8dc 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/to.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/to.yaml @@ -5,4 +5,5 @@ description: > The date must be specified as a KQL data range or date match expression. schema: type: string -example: now+1d \ No newline at end of file + examples: + - now+1d \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/user_action_types.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/user_action_types.yaml index 2b04b7c80662..320dc67b631c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/user_action_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/user_action_types.yaml @@ -21,4 +21,5 @@ schema: - tags - title - user -example: create_case \ No newline at end of file + examples: + - [ create_case ] \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/4xx_response.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/4xx_response.yaml index 75d0ac39903b..72d3bd82cbf6 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/4xx_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/4xx_response.yaml @@ -3,9 +3,11 @@ title: Unsuccessful cases API response properties: error: type: string - example: Unauthorized + examples: + - Unauthorized message: type: string statusCode: type: integer - example: 401 \ No newline at end of file + examples: + - 401 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml index 3568008b0700..140b606b4456 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/action_types.yaml @@ -13,4 +13,5 @@ enum: - status - settings - severity -example: create_case \ No newline at end of file +examples: + - create_case \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/actions.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/actions.yaml index 1638ed67c78e..f2b20517efd5 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/actions.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/actions.yaml @@ -5,4 +5,5 @@ enum: - delete - push_to_service - update -example: create \ No newline at end of file +examples: + - create \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml index c99ebb19cc81..192e12f62857 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml @@ -19,6 +19,7 @@ properties: type: description: The type of comment. type: string - example: alert + examples: + - alert enum: - alert \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml index beac63c377ad..a0740dbdc51b 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml @@ -6,13 +6,15 @@ properties: description: The new comment. It is required only when `type` is `user`. type: string maxLength: 30000 - example: A new comment. + examples: + - A new comment. owner: $ref: 'owners.yaml' type: type: string description: The type of comment. - example: user + examples: + - user enum: - user required: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml index 443d9dcc5552..3305732cee6e 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml @@ -7,11 +7,13 @@ properties: type: array items: type: string - example: a6e12ac4-7bce-457b-84f6-d7ce8deb8446 + examples: + - a6e12ac4-7bce-457b-84f6-d7ce8deb8446 created_at: type: string format: date-time - example: 2023-11-06T19:29:38.424Z + examples: + - 2023-11-06T19:29:38.424Z created_by: type: object required: @@ -22,44 +24,52 @@ properties: $ref: 'user_properties.yaml' id: type: string - example: 73362370-ab1a-11ec-985f-97e55adae8b9 + examples: + - 73362370-ab1a-11ec-985f-97e55adae8b9 index: type: array items: type: string - example: .internal.alerts-security.alerts-default-000001 + examples: + - .internal.alerts-security.alerts-default-000001 owner: $ref: 'owners.yaml' pushed_at: - type: string + type: + - "string" + - "null" format: date-time - example: null - nullable: true + examples: + - null pushed_by: - type: object + type: + - "object" + - "null" required: - email - full_name - username properties: $ref: 'user_properties.yaml' - nullable: true rule: type: object properties: $ref: 'rule_properties.yaml' type: type: string - example: alert + examples: + - alert enum: - alert updated_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true updated_by: - type: object - nullable: true + type: + - "object" + - "null" required: - email - full_name @@ -68,4 +78,5 @@ properties: $ref: 'user_properties.yaml' version: type: string - example: WzMwNDgsMV0= \ No newline at end of file + examples: + - WzMwNDgsMV0= \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml index cca8eb74f501..5a8f821931f5 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml @@ -13,4 +13,5 @@ oneOf: type: string maxItems: 1000 x-technical-preview: true -example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 \ No newline at end of file +examples: + - 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/assignees.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/assignees.yaml index 5b4e18517bd4..4109c4d47690 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/assignees.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/assignees.yaml @@ -1,7 +1,8 @@ -type: array +type: + - "array" + - "null" description: An array containing users that are assigned to the case. maxItems: 10 -nullable: true items: type: object required: @@ -10,4 +11,5 @@ items: uid: type: string description: A unique identifier for the user profile. These identifiers can be found by using the suggest user profile API. - example: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 \ No newline at end of file + examples: + - u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_connector_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_connector_properties.yaml index ce1669c37941..3873a8ae9e0f 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_connector_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_connector_properties.yaml @@ -1,14 +1,17 @@ fields: description: The fields specified in the case configuration are not used and are not propagated to individual cases, therefore it is recommended to set it to `null`. - nullable: true - type: object + type: + - "object" + - "null" id: description: The identifier for the connector. If you do not want a default connector, use `none`. To retrieve connector IDs, use the find connectors API. type: string - example: none + examples: + - none name: description: The name of the connector. If you do not want a default connector, use `none`. To retrieve connector names, use the find connectors API. type: string - example: none + examples: + - none type: $ref: 'connector_types.yaml' \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_response_properties.yaml index 62bddb7a2597..e85179f3053a 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_configure_response_properties.yaml @@ -15,7 +15,8 @@ connector: created_at: type: string format: date-time - example: 2022-06-01T17:07:17.767Z + examples: + - 2022-06-01T17:07:17.767Z created_by: type: object required: @@ -25,12 +26,15 @@ created_by: properties: $ref: 'user_properties.yaml' error: - type: string - nullable: true - example: null + type: + - "string" + - "null" + examples: + - null id: type: string - example: 4a97a440-e1cd-11ec-be9b-9b1838238ee6 + examples: + - 4a97a440-e1cd-11ec-be9b-9b1838238ee6 mappings: type: array items: @@ -38,29 +42,36 @@ mappings: properties: action_type: type: string - example: overwrite + examples: + - overwrite source: type: string - example: title + examples: + - title target: type: string - example: summary + examples: + - summary owner: $ref: 'owners.yaml' updated_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true - example: 2022-06-01T19:58:48.169Z + examples: + - 2022-06-01T19:58:48.169Z updated_by: - type: object + type: + - "object" + - "null" required: - email - full_name - username properties: $ref: 'user_properties.yaml' - nullable: true version: type: string - example: WzIwNzMsMV0= \ No newline at end of file + examples: + - WzIwNzMsMV0= \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_customfields.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_customfields.yaml index 4170833e818c..5a4c9f26e09b 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_customfields.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_customfields.yaml @@ -18,8 +18,9 @@ value: However, for cases that existed when the required custom field was added, the default value stored in Elasticsearch is `undefined`. The value returned in the API and user interface in this case is `null`. oneOf: - - type: string + - type: + - "string" + - "null" minLength: 1 maxLength: 160 - nullable: true - type: boolean diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml index 95bd14e4957a..26b3eaa7395e 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml @@ -1,6 +1,7 @@ title: Case response properties for closed_by -type: object -nullable: true +type: + - "object" + - "null" properties: $ref: 'user_properties.yaml' required: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml index 1ac30d325d45..18f79997e31c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml @@ -1,7 +1,8 @@ title: Case response properties for connector fields -type: object +type: + - "object" + - "null" description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. -nullable: true properties: caseId: description: The case identifier for Swimlane connectors. @@ -11,8 +12,9 @@ properties: type: string destIp: description: Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" impact: description: The effect an incident had on business for ServiceNow ITSM connectors. type: string @@ -26,12 +28,14 @@ properties: type: string malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" parent: description: The key of the parent issue, when the issue type is sub-task for Jira connectors. type: string diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml index 60c6520d2f4c..8f3de83d88c6 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml @@ -26,13 +26,15 @@ properties: assignees: $ref: 'assignees.yaml' category: - type: string + type: + - "string" + - "null" description: The case category. - nullable: true closed_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true closed_by: $ref: 'case_response_closed_by_properties.yaml' comments: @@ -61,7 +63,8 @@ properties: created_at: type: string format: date-time - example: '2022-05-13T09:16:17.416Z' + examples: + - '2022-05-13T09:16:17.416Z' created_by: $ref: 'case_response_created_by_properties.yaml' customFields: @@ -74,21 +77,25 @@ properties: $ref: 'case_customfields.yaml' description: type: string - example: A case description. + examples: + - A case description. duration: - type: integer + type: + - "integer" + - "null" description: > The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero. - nullable: true - example: 120 + examples: + - 120 external_service: $ref: 'external_service.yaml' id: type: string - example: 66b9aa00-94fa-11ea-9f74-e7e108796192 + examples: + - 66b9aa00-94fa-11ea-9f74-e7e108796192 owner: $ref: 'owners.yaml' settings: @@ -101,23 +108,28 @@ properties: type: array items: type: string - example: - - tag-1 + examples: + - [tag-1] title: type: string - example: Case title 1 + examples: + - Case title 1 totalAlerts: type: integer - example: 0 + examples: + - 0 totalComment: type: integer - example: 0 + examples: + - 0 updated_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true updated_by: $ref: 'case_response_updated_by_properties.yaml' version: type: string - example: WzUzMiwxXQ== + examples: + - WzUzMiwxXQ== diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml index c59a5565c98b..72f2c3ef619a 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml @@ -1,6 +1,7 @@ title: Case response properties for pushed_by -type: object -nullable: true +type: + - "object" + - "null" properties: $ref: 'user_properties.yaml' required: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml index cd1bae033f2f..8e475c5d205d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml @@ -1,6 +1,7 @@ title: Case response properties for updated_by -type: object -nullable: true +type: + - "object" + - "null" properties: $ref: 'user_properties.yaml' required: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/closure_types.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/closure_types.yaml index 6879f820d6f5..8484d4d051ca 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/closure_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/closure_types.yaml @@ -3,4 +3,5 @@ description: Indicates whether a case is automatically closed when it is pushed enum: - close-by-pushing - close-by-user -example: close-by-user \ No newline at end of file +examples: + - close-by-user \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/comment_types.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/comment_types.yaml index 9731b8ce4fad..6a41e07aada4 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/comment_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/comment_types.yaml @@ -3,4 +3,5 @@ description: The type of comment. enum: - alert - user -example: user \ No newline at end of file +examples: + - user \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties.yaml index 9416a31f3877..e68c226ee9b9 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties.yaml @@ -1,7 +1,11 @@ fields: - description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. - nullable: true - type: object + description: > + An object containing the connector fields. + To create a case without a connector, specify null. + If you want to omit any individual field, specify null as its value. + type: + - "object" + - "null" properties: caseId: description: The case identifier for Swimlane connectors. @@ -11,8 +15,9 @@ fields: type: string destIp: description: Indicates whether cases will send a comma-separated list of destination IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" impact: description: The effect an incident had on business for ServiceNow ITSM connectors. type: string @@ -26,12 +31,14 @@ fields: type: string malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" parent: description: The key of the parent issue, when the issue type is sub-task for Jira connectors. type: string @@ -46,22 +53,26 @@ fields: type: string sourceIp: description: Indicates whether cases will send a comma-separated list of source IPs for ServiceNow SecOps connectors. - type: boolean - nullable: true + type: + - "boolean" + - "null" subcategory: description: The subcategory of the incident for ServiceNow ITSM connectors. type: string urgency: description: The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors. type: string - example: null + examples: + - null id: description: The identifier for the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none name: description: The name of the connector. To create a case without a connector, use `none`. type: string - example: none + examples: + - none type: $ref: 'connector_types.yaml' \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_cases_webhook.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_cases_webhook.yaml index 871b3180bc22..b204dcbdd9f4 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_cases_webhook.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_cases_webhook.yaml @@ -8,9 +8,11 @@ description: Defines properties for connectors when type is `.cases-webhook`. type: object properties: fields: - type: string - nullable: true - example: null + type: + - "string" + - "null" + examples: + - null id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -20,6 +22,7 @@ properties: type: description: The type of connector. type: string - example: .cases-webhook + examples: + - .cases-webhook enum: - .cases-webhook \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_jira.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_jira.yaml index a63f1fbd568d..6eb1c0baa8e4 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_jira.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_jira.yaml @@ -17,16 +17,19 @@ properties: properties: issueType: description: The type of issue. - type: string - nullable: true + type: + - "string" + - "null" parent: description: The key of the parent issue, when the issue type is sub-task. - type: string - nullable: true + type: + - "string" + - "null" priority: description: The priority of the issue. - type: string - nullable: true + type: + - "string" + - "null" id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -36,6 +39,7 @@ properties: type: description: The type of connector. type: string - example: .jira + examples: + - .jira enum: - .jira diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_none.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_none.yaml index c1bc49372f64..2497b1357c86 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_none.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_none.yaml @@ -9,20 +9,25 @@ type: object properties: fields: description: An object containing the connector fields. To create a case without a connector, specify null. To update a case to remove the connector, specify null. - nullable: true - type: string - example: null + type: + - "string" + - "null" + examples: + - null id: description: The identifier for the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`. type: string - example: none + examples: + - none name: description: The name of the connector. To create a case without a connector, use `none`. To update a case to remove the connector, specify `none`. type: string - example: none + examples: + - none type: description: The type of connector. To create a case without a connector, use `.none`. To update a case to remove the connector, specify `.none`. type: string - example: .none + examples: + - .none enum: - .none \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_resilient.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_resilient.yaml index bf7929b3060e..df8e34057de0 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_resilient.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_resilient.yaml @@ -9,8 +9,9 @@ type: object properties: fields: description: An object containing the connector fields. If you want to omit any individual field, specify null as its value. - type: object - nullable: true + type: + - "object" + - "null" required: - issueTypes - severityCode @@ -32,6 +33,7 @@ properties: type: description: The type of connector. type: string - example: .resilient + examples: + - .resilient enum: - .resilient \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow.yaml index 5bc76ab7a9dd..7a57a9e69ccc 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow.yaml @@ -19,24 +19,29 @@ properties: properties: category: description: The category of the incident. - type: string - nullable: true + type: + - "string" + - "null" impact: description: The effect an incident had on business. - type: string - nullable: true + type: + - "string" + - "null" severity: description: The severity of the incident. - type: string - nullable: true + type: + - "string" + - "null" subcategory: description: The subcategory of the incident. - type: string - nullable: true + type: + - "string" + - "null" urgency: description: The extent to which the incident resolution can be delayed. - type: string - nullable: true + type: + - "string" + - "null" id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -46,6 +51,7 @@ properties: type: description: The type of connector. type: string - example: .servicenow + examples: + - .servicenow enum: - .servicenow \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow_sir.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow_sir.yaml index 42245f9771e3..cafff746d18f 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow_sir.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_servicenow_sir.yaml @@ -21,32 +21,39 @@ properties: properties: category: description: The category of the incident. - type: string - nullable: true + type: + - "string" + - "null" destIp: description: Indicates whether cases will send a comma-separated list of destination IPs. - type: boolean - nullable: true + type: + - "boolean" + - "null" malwareHash: description: Indicates whether cases will send a comma-separated list of malware hashes. - type: boolean - nullable: true + type: + - "boolean" + - "null" malwareUrl: description: Indicates whether cases will send a comma-separated list of malware URLs. - type: boolean - nullable: true + type: + - "boolean" + - "null" priority: description: The priority of the issue. - type: string - nullable: true + type: + - "string" + - "null" sourceIp: description: Indicates whether cases will send a comma-separated list of source IPs. - type: boolean - nullable: true + type: + - "boolean" + - "null" subcategory: description: The subcategory of the incident. - type: string - nullable: true + type: + - "string" + - "null" id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -56,6 +63,7 @@ properties: type: description: The type of connector. type: string - example: .servicenow-sir + examples: + - .servicenow-sir enum: - .servicenow-sir \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_swimlane.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_swimlane.yaml index f4c138463078..9cde6dd09d7c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_swimlane.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_properties_swimlane.yaml @@ -15,8 +15,9 @@ properties: properties: caseId: description: The case identifier for Swimlane connectors. - type: string - nullable: true + type: + - "string" + - "null" id: description: The identifier for the connector. To retrieve connector IDs, use the find connectors API. type: string @@ -26,6 +27,7 @@ properties: type: description: The type of connector. type: string - example: .swimlane + examples: + - .swimlane enum: - .swimlane \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_types.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_types.yaml index fc23b9cab5f8..4bc12b3ae948 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/connector_types.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/connector_types.yaml @@ -8,4 +8,5 @@ enum: - .servicenow - .servicenow-sir - .swimlane -example: .none \ No newline at end of file +examples: + - .none \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml index b3b3182b8c96..411f977928a8 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml @@ -1,5 +1,6 @@ -type: object -nullable: true +type: + - "object" + - "null" properties: connector_id: type: string @@ -15,7 +16,8 @@ properties: type: string format: date-time pushed_by: - type: object + type: + - "object" + - "null" properties: - $ref: 'user_properties.yaml' - nullable: true \ No newline at end of file + $ref: 'user_properties.yaml' \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/owners.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/owners.yaml index 9036fd5a3833..fa265756d950 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/owners.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/owners.yaml @@ -6,4 +6,5 @@ enum: - cases - observability - securitySolution -example: cases \ No newline at end of file +examples: + - cases \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_alert_comment.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_alert_comment.yaml index 0b0d3fc3c07c..eaaaa539a33c 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_alert_comment.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_alert_comment.yaml @@ -6,14 +6,16 @@ properties: alertId: oneOf: - type: string - example: 1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d + examples: + - 1c0b056b-cc9f-4b61-b5c9-cb801abd5e1d - type: array items: type: string index: oneOf: - type: string - example: .alerts-observability.logs.alerts-default + examples: + - .alerts-observability.logs.alerts-default - type: array items: type: string diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_create_case.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_create_case.yaml index 4c3043a25c7b..9bda777bccea 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_create_case.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_create_case.yaml @@ -20,6 +20,7 @@ properties: type: array items: type: string - example: ["tag-1"] + examples: + - ["tag-1"] title: type: string \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_delete.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_delete.yaml index 933d91305dca..29e16039ec27 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_delete.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_delete.yaml @@ -1,3 +1,4 @@ -type: object -description: If the `action` is `delete` and the `type` is `delete_case`, the payload is nullable. -nullable: true \ No newline at end of file +type: + - "object" + - "null" +description: If the `action` is `delete` and the `type` is `delete_case`, the payload is nullable. \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_tags.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_tags.yaml index bed767719e6f..8ea690280251 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/payload_tags.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/payload_tags.yaml @@ -4,4 +4,5 @@ properties: type: array items: type: string - example: ["tag-1"] \ No newline at end of file + examples: + - ["tag-1"] \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml index 09712b57ce13..0a4dfb828dcb 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml @@ -10,8 +10,10 @@ properties: id: description: The rule identifier. type: string - example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + examples: + - 94d80550-aaf4-11ec-985f-97e55adae8b9 name: description: The rule name. type: string - example: security_rule \ No newline at end of file + examples: + - security_rule \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/rule_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/rule_properties.yaml index 64b93b77429a..2ed5e0e89e8d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/rule_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/rule_properties.yaml @@ -1,8 +1,10 @@ id: description: The rule identifier. type: string - example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + examples: + - 94d80550-aaf4-11ec-985f-97e55adae8b9 name: description: The rule name. type: string - example: security_rule \ No newline at end of file + examples: + - security_rule \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/settings.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/settings.yaml index a344eb049195..576b8b9dff15 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/settings.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/settings.yaml @@ -6,4 +6,5 @@ properties: syncAlerts: description: Turns alert syncing on or off. type: boolean - example: true \ No newline at end of file + examples: + - true \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml index 2c7bd5dcc121..5c5619cec298 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml @@ -17,7 +17,8 @@ properties: description: > The identifier for the comment. To retrieve comment IDs, use the get comments API. - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 index: $ref: 'alert_indices.yaml' owner: @@ -29,10 +30,12 @@ properties: type: string enum: - alert - example: alert + examples: + - alert version: description: > The current comment version. To retrieve version values, use the get comments API. type: string - example: Wzk1LDFd \ No newline at end of file + examples: + - Wzk1LDFd \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_configuration_request.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_configuration_request.yaml index 86ba2794ea19..8a6a3aa7f302 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_configuration_request.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_configuration_request.yaml @@ -34,4 +34,5 @@ properties: The version of the connector. To retrieve the version value, use the get configuration API. type: string - example: WzIwMiwxXQ== \ No newline at end of file + examples: + - WzIwMiwxXQ== \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml index a83050e93eaa..003f12d63a30 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml @@ -6,13 +6,15 @@ properties: description: The new comment. It is required only when `type` is `user`. type: string maxLength: 30000 - example: A new comment. + examples: + - A new comment. id: type: string description: > The identifier for the comment. To retrieve comment IDs, use the get comments API. - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 owner: $ref: 'owners.yaml' type: @@ -20,13 +22,15 @@ properties: description: The type of comment. enum: - user - example: user + examples: + - user version: description: > The current comment version. To retrieve version values, use the get comments API. type: string - example: Wzk1LDFd + examples: + - Wzk1LDFd required: - comment - id diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_find_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_find_response_properties.yaml index a17f98d8007a..12b45d987598 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_find_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_find_response_properties.yaml @@ -13,13 +13,16 @@ properties: action: $ref: 'actions.yaml' comment_id: - type: string - nullable: true - example: 578608d0-03b1-11ed-920c-974bfa104448 + type: + - "string" + - "null" + examples: + - 578608d0-03b1-11ed-920c-974bfa104448 created_at: type: string format: date-time - example: 2022-05-13T09:16:17.416Z + examples: + - 2022-05-13T09:16:17.416Z created_by: type: object properties: @@ -30,7 +33,8 @@ properties: - username id: type: string - example: 22fd3e30-03b1-11ed-920c-974bfa104448 + examples: + - 22fd3e30-03b1-11ed-920c-974bfa104448 owner: $ref: 'owners.yaml' payload: @@ -50,7 +54,8 @@ properties: - $ref: 'payload_user_comment.yaml' version: type: string - example: WzM1ODg4LDFd + examples: + - WzM1ODg4LDFd type: type: string description: The type of action. @@ -66,4 +71,5 @@ properties: - status - settings - severity - example: create_case + examples: + - create_case diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml index ef39c531c357..02521d975d8d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_actions_response_properties.yaml @@ -14,18 +14,23 @@ properties: $ref: 'actions.yaml' action_id: type: string - example: 22fd3e30-03b1-11ed-920c-974bfa104448 + examples: + - 22fd3e30-03b1-11ed-920c-974bfa104448 case_id: type: string - example: 22df07d0-03b1-11ed-920c-974bfa104448 + examples: + - 22df07d0-03b1-11ed-920c-974bfa104448 comment_id: - type: string - nullable: true - example: 578608d0-03b1-11ed-920c-974bfa104448 + type: + - "string" + - "null" + examples: + - 578608d0-03b1-11ed-920c-974bfa104448 created_at: type: string format: date-time - example: 2022-05-13T09:16:17.416Z + examples: + - 2022-05-13T09:16:17.416Z created_by: type: object properties: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml index b1727d3279ab..832d603e366d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml @@ -5,37 +5,46 @@ required: properties: comment: type: string - example: A new comment. + examples: + - A new comment. created_at: type: string format: date-time - example: 2022-05-13T09:16:17.416Z + examples: + - 2022-05-13T09:16:17.416Z created_by: $ref: 'case_response_created_by_properties.yaml' id: type: string - example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + examples: + - 8af6ac20-74f6-11ea-b83a-553aecdb28b6 owner: $ref: 'owners.yaml' pushed_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true - example: null + examples: + - null pushed_by: $ref: 'case_response_pushed_by_properties.yaml' type: type: string - example: user + examples: + - user enum: - user updated_at: - type: string + type: + - "string" + - "null" format: date-time - nullable: true - example: null + examples: + - null updated_by: $ref: 'case_response_updated_by_properties.yaml' version: type: string - example: WzIwNDMxLDFd \ No newline at end of file + examples: + - WzIwNDMxLDFd \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml index 19b76a6000c0..3c5439ac7aee 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml @@ -1,15 +1,22 @@ email: - type: string - example: null - nullable: true + type: + - "string" + - "null" + examples: + - null full_name: - type: string - example: null - nullable: true -username: - type: string - example: elastic - nullable: true + type: + - "string" + - "null" + examples: + - null profile_uid: type: string - example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + examples: + - u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 +username: + type: + - "string" + - "null" + examples: + - elastic diff --git a/x-pack/plugins/cases/docs/openapi/entrypoint.yaml b/x-pack/plugins/cases/docs/openapi/entrypoint.yaml index 840d49eaa852..dff3dff43622 100644 --- a/x-pack/plugins/cases/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/cases/docs/openapi/entrypoint.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Cases description: OpenAPI schema for Cases endpoints - version: '0.1' + version: '0.2' contact: name: Cases Team license: @@ -90,7 +90,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - apiKeyAuth: [] diff --git a/x-pack/plugins/cases/docs/openapi/paths/api@cases@alerts@{alertid}.yaml b/x-pack/plugins/cases/docs/openapi/paths/api@cases@alerts@{alertid}.yaml index 64ff49d17b8c..7914c8a994c6 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/api@cases@alerts@{alertid}.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/api@cases@alerts@{alertid}.yaml @@ -28,7 +28,7 @@ get: title: type: string description: The case title. - example: + examples: - id: 06116b80-e1c3-11ec-be9b-9b1838238ee6 title: security_case '401': diff --git a/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}@connector@{connectorid}@_push.yaml b/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}@connector@{connectorid}@_push.yaml index 321f2f6938c5..8b52cf5d013c 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}@connector@{connectorid}@_push.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}@connector@{connectorid}@_push.yaml @@ -14,8 +14,9 @@ post: content: application/json: schema: - type: object - nullable: true + type: + - "object" + - "null" responses: '200': description: Indicates a successful call. diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@alerts@{alertid}.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@alerts@{alertid}.yaml index f1e287e05d30..0ffe229fd9e6 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@alerts@{alertid}.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@alerts@{alertid}.yaml @@ -28,7 +28,7 @@ get: title: type: string description: The case title. - example: + examples: - id: 06116b80-e1c3-11ec-be9b-9b1838238ee6 title: security_case '401': diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml index bee91522dde2..c06972c8dd0e 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml @@ -18,8 +18,9 @@ post: content: application/json: schema: - type: object - nullable: true + type: + - "object" + - "null" responses: '200': description: Indicates a successful call. diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@user_actions@_find.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@user_actions@_find.yaml index 0b5a6e660da8..9fda51fa5979 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@user_actions@_find.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@user_actions@_find.yaml @@ -11,7 +11,6 @@ get: - $ref: '../components/parameters/case_id.yaml' - $ref: '../components/parameters/space_id.yaml' - $ref: '../components/parameters/page_index.yaml' - example: "1" - $ref: '../components/parameters/page_size.yaml' - $ref: '../components/parameters/sort_order.yaml' - $ref: '../components/parameters/user_action_types.yaml' diff --git a/x-pack/plugins/cases/public/client/helpers/can_use_cases.ts b/x-pack/plugins/cases/public/client/helpers/can_use_cases.ts index 1cc22c079970..90b0d3b18908 100644 --- a/x-pack/plugins/cases/public/client/helpers/can_use_cases.ts +++ b/x-pack/plugins/cases/public/client/helpers/can_use_cases.ts @@ -40,10 +40,19 @@ export const canUseCases = acc.update = acc.update || userCapabilitiesForOwner.update; acc.delete = acc.delete || userCapabilitiesForOwner.delete; acc.push = acc.push || userCapabilitiesForOwner.push; + acc.connectors = acc.connectors || userCapabilitiesForOwner.connectors; + acc.settings = acc.settings || userCapabilitiesForOwner.settings; + const allFromAcc = - acc.create && acc.read && acc.update && acc.delete && acc.push && acc.connectors; + acc.create && + acc.read && + acc.update && + acc.delete && + acc.push && + acc.connectors && + acc.settings; + acc.all = acc.all || userCapabilitiesForOwner.all || allFromAcc; - acc.connectors = acc.connectors || userCapabilitiesForOwner.connectors; return acc; }, @@ -55,6 +64,7 @@ export const canUseCases = delete: false, push: false, connectors: false, + settings: false, } ); diff --git a/x-pack/plugins/cases/public/client/helpers/capabilities.test.ts b/x-pack/plugins/cases/public/client/helpers/capabilities.test.ts index a3f741f37303..ce374243b10b 100644 --- a/x-pack/plugins/cases/public/client/helpers/capabilities.test.ts +++ b/x-pack/plugins/cases/public/client/helpers/capabilities.test.ts @@ -17,6 +17,7 @@ describe('getUICapabilities', () => { "delete": false, "push": false, "read": false, + "settings": false, "update": false, } `); @@ -31,6 +32,7 @@ describe('getUICapabilities', () => { "delete": false, "push": false, "read": false, + "settings": false, "update": false, } `); @@ -45,6 +47,7 @@ describe('getUICapabilities', () => { "delete": false, "push": false, "read": false, + "settings": false, "update": false, } `); @@ -68,6 +71,7 @@ describe('getUICapabilities', () => { "delete": false, "push": false, "read": false, + "settings": false, "update": false, } `); @@ -82,6 +86,7 @@ describe('getUICapabilities', () => { "delete": false, "push": false, "read": false, + "settings": false, "update": false, } `); @@ -105,6 +110,7 @@ describe('getUICapabilities', () => { "delete": true, "push": true, "read": true, + "settings": false, "update": true, } `); @@ -113,23 +119,65 @@ describe('getUICapabilities', () => { it('returns false for the all field when cases_connectors is false', () => { expect( getUICapabilities({ - create_cases: false, + create_cases: true, read_cases: true, update_cases: true, delete_cases: true, push_cases: true, cases_connectors: false, + cases_settings: true, }) ).toMatchInlineSnapshot(` Object { "all": false, "connectors": false, - "create": false, + "create": true, + "delete": true, + "push": true, + "read": true, + "settings": true, + "update": true, + } + `); + }); + + it('returns false for the all field when cases_settings is false', () => { + expect( + getUICapabilities({ + create_cases: true, + read_cases: true, + update_cases: true, + delete_cases: true, + push_cases: true, + cases_connectors: true, + cases_settings: false, + }) + ).toMatchInlineSnapshot(` + Object { + "all": false, + "connectors": true, + "create": true, "delete": true, "push": true, "read": true, + "settings": false, "update": true, } `); }); + + it('returns true for cases_settings when it is set to true in the ui capabilities', () => { + expect(getUICapabilities({ cases_settings: true })).toMatchInlineSnapshot(` + Object { + "all": false, + "connectors": false, + "create": false, + "delete": false, + "push": false, + "read": false, + "settings": true, + "update": false, + } + `); + }); }); diff --git a/x-pack/plugins/cases/public/client/helpers/capabilities.ts b/x-pack/plugins/cases/public/client/helpers/capabilities.ts index 278512fef623..9be5b5f05f64 100644 --- a/x-pack/plugins/cases/public/client/helpers/capabilities.ts +++ b/x-pack/plugins/cases/public/client/helpers/capabilities.ts @@ -8,6 +8,7 @@ import type { CasesPermissions } from '../../../common'; import { CASES_CONNECTORS_CAPABILITY, + CASES_SETTINGS_CAPABILITY, CREATE_CASES_CAPABILITY, DELETE_CASES_CAPABILITY, PUSH_CASES_CAPABILITY, @@ -24,7 +25,9 @@ export const getUICapabilities = ( const deletePriv = !!featureCapabilities?.[DELETE_CASES_CAPABILITY]; const push = !!featureCapabilities?.[PUSH_CASES_CAPABILITY]; const connectors = !!featureCapabilities?.[CASES_CONNECTORS_CAPABILITY]; - const all = create && read && update && deletePriv && push && connectors; + const settings = !!featureCapabilities?.[CASES_SETTINGS_CAPABILITY]; + + const all = create && read && update && deletePriv && push && connectors && settings; return { all, @@ -34,5 +37,6 @@ export const getUICapabilities = ( delete: deletePriv, push, connectors, + settings, }; }; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/hooks.ts b/x-pack/plugins/cases/public/common/lib/kibana/hooks.ts index c540824b1ebb..39b4d3d1edc7 100644 --- a/x-pack/plugins/cases/public/common/lib/kibana/hooks.ts +++ b/x-pack/plugins/cases/public/common/lib/kibana/hooks.ts @@ -10,7 +10,7 @@ import moment from 'moment-timezone'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import type { NavigateToAppOptions } from '@kbn/core/public'; import { getUICapabilities } from '../../../client/helpers/capabilities'; import { convertToCamelCase } from '../../../api/utils'; @@ -194,6 +194,7 @@ export const useApplicationCapabilities = (): UseApplicationCapabilities => { delete: permissions.delete, push: permissions.push, connectors: permissions.connectors, + settings: permissions.settings, }, visualize: { crud: !!capabilities.visualize?.save, read: !!capabilities.visualize?.show }, dashboard: { @@ -215,6 +216,7 @@ export const useApplicationCapabilities = (): UseApplicationCapabilities => { permissions.delete, permissions.push, permissions.connectors, + permissions.settings, ] ); }; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.tsx b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.tsx index 31ea452874c2..195c1f433a8e 100644 --- a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.tsx +++ b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.tsx @@ -75,6 +75,7 @@ export const createStartServicesMock = ({ license }: StartServiceArgs = {}): Sta delete_cases: true, push_cases: true, cases_connectors: true, + cases_settings: true, }, visualize: { save: true, show: true }, dashboard: { show: true, createNew: true }, diff --git a/x-pack/plugins/cases/public/common/mock/permissions.ts b/x-pack/plugins/cases/public/common/mock/permissions.ts index 4d68e9d36c77..fce274cd7f33 100644 --- a/x-pack/plugins/cases/public/common/mock/permissions.ts +++ b/x-pack/plugins/cases/public/common/mock/permissions.ts @@ -16,7 +16,9 @@ export const noCasesPermissions = () => delete: false, push: false, connectors: false, + settings: false, }); + export const readCasesPermissions = () => buildCasesPermissions({ read: true, @@ -25,6 +27,7 @@ export const readCasesPermissions = () => delete: false, push: false, connectors: true, + settings: false, }); export const noCreateCasesPermissions = () => buildCasesPermissions({ create: false }); export const noUpdateCasesPermissions = () => buildCasesPermissions({ update: false }); @@ -34,6 +37,7 @@ export const writeCasesPermissions = () => buildCasesPermissions({ read: false } export const onlyDeleteCasesPermission = () => buildCasesPermissions({ read: false, create: false, update: false, delete: true, push: false }); export const noConnectorsCasePermission = () => buildCasesPermissions({ connectors: false }); +export const noCasesSettingsPermission = () => buildCasesPermissions({ settings: false }); export const buildCasesPermissions = (overrides: Partial> = {}) => { const create = overrides.create ?? true; @@ -42,7 +46,8 @@ export const buildCasesPermissions = (overrides: Partial delete_cases: false, push_cases: false, cases_connectors: false, + cases_settings: false, }); export const readCasesCapabilities = () => buildCasesCapabilities({ @@ -71,6 +78,7 @@ export const readCasesCapabilities = () => update_cases: false, delete_cases: false, push_cases: false, + cases_settings: false, }); export const writeCasesCapabilities = () => { return buildCasesCapabilities({ @@ -86,5 +94,6 @@ export const buildCasesCapabilities = (overrides?: Partial) = delete_cases: overrides?.delete_cases ?? true, push_cases: overrides?.push_cases ?? true, cases_connectors: overrides?.cases_connectors ?? true, + cases_settings: overrides?.cases_settings ?? true, }; }; diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx index 846ae8172b32..0361014cbfb6 100644 --- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/cases/public/common/mock/test_providers.tsx @@ -129,7 +129,7 @@ export interface AppMockRenderer { render: UiRender; coreStart: StartServices; queryClient: QueryClient; - AppWrapper: React.FC<{ children: React.ReactElement }>; + AppWrapper: React.FC<{ children: React.ReactNode }>; getFilesClient: () => ScopedFilesClient; } @@ -176,7 +176,7 @@ export const createAppMockRenderer = ({ const getFilesClient = mockGetFilesClient(); - const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( + const AppWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( ({ eui: euiDarkVars, darkMode: true })}> diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx index 4bd497a3c76f..6a425b9a803a 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx @@ -22,7 +22,7 @@ import { } from '../../common/mock'; import { useGetCasesMockState, connectorsMock } from '../../containers/mock'; -import { SortFieldCase, StatusAll } from '../../../common/ui/types'; +import { SortFieldCase } from '../../../common/ui/types'; import { CaseSeverity, CaseStatuses } from '../../../common/types/domain'; import { SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { getEmptyCellValue } from '../empty_value'; @@ -38,11 +38,8 @@ import { useGetSupportedActionConnectors } from '../../containers/configure/use_ import { useGetTags } from '../../containers/use_get_tags'; import { useGetCategories } from '../../containers/use_get_categories'; import { useUpdateCase } from '../../containers/use_update_case'; -import { - useGetCases, - DEFAULT_QUERY_PARAMS, - DEFAULT_FILTER_OPTIONS, -} from '../../containers/use_get_cases'; +import { useGetCases } from '../../containers/use_get_cases'; +import { DEFAULT_QUERY_PARAMS, DEFAULT_FILTER_OPTIONS } from '../../containers/constants'; import { useGetCurrentUserProfile } from '../../containers/user_profiles/use_get_current_user_profile'; import { userProfiles, userProfilesMap } from '../../containers/user_profiles/api.mock'; import { useBulkGetUserProfiles } from '../../containers/user_profiles/use_bulk_get_user_profiles'; @@ -100,7 +97,7 @@ describe('AllCasesListGeneric', () => { }; const defaultColumnArgs = { - filterStatus: CaseStatuses.open, + filterStatus: [CaseStatuses.open], handleIsLoading: jest.fn(), isLoadingCases: [], isLoadingColumns: false, @@ -403,7 +400,8 @@ describe('AllCasesListGeneric', () => { it('should sort by status', async () => { appMockRenderer.render(); - userEvent.click(screen.getByTitle('Status')); + // 0 is the status filter button label + userEvent.click(screen.getAllByTitle('Status')[1]); await waitFor(() => { expect(useGetCasesMock).toHaveBeenLastCalledWith( @@ -424,14 +422,16 @@ describe('AllCasesListGeneric', () => { expect(screen.getByTitle('Name')).toBeInTheDocument(); expect(screen.getByTitle('Category')).toBeInTheDocument(); expect(screen.getByTitle('Created on')).toBeInTheDocument(); - expect(screen.getByTitle('Severity')).toBeInTheDocument(); + // 0 is the severity filter button label + expect(screen.getAllByTitle('Severity')[1]).toBeInTheDocument(); }); }); it('should sort by severity', async () => { appMockRenderer.render(); - userEvent.click(screen.getByTitle('Severity')); + // 0 is the severity filter button label + userEvent.click(screen.getAllByTitle('Severity')[1]); await waitFor(() => { expect(useGetCasesMock).toHaveBeenLastCalledWith( @@ -503,7 +503,7 @@ describe('AllCasesListGeneric', () => { it('should filter by category', async () => { appMockRenderer.render(); - userEvent.click(screen.getByTestId('options-filter-popover-button-Categories')); + userEvent.click(screen.getByTestId('options-filter-popover-button-category')); await waitForEuiPopoverOpen(); userEvent.click(screen.getByTestId('options-filter-popover-item-twix')); @@ -511,7 +511,7 @@ describe('AllCasesListGeneric', () => { expect(useGetCasesMock).toHaveBeenLastCalledWith({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, - searchFields: [], + searchFields: ['title', 'description'], owner: ['securitySolution'], category: ['twix'], }, @@ -520,72 +520,22 @@ describe('AllCasesListGeneric', () => { }); }); - it('should filter by status: closed', async () => { - appMockRenderer.render(); - userEvent.click(screen.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-status-filter-closed')); - await waitFor(() => { - expect(useGetCasesMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - queryParams: { ...DEFAULT_QUERY_PARAMS, sortField: SortFieldCase.closedAt }, - }) - ); - }); - }); - - it('should filter by status: in-progress', async () => { - appMockRenderer.render(); - userEvent.click(screen.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-status-filter-in-progress')); - await waitFor(() => { - expect(useGetCasesMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - queryParams: DEFAULT_QUERY_PARAMS, - }) - ); - }); - }); - - it('should filter by status: open', async () => { - appMockRenderer.render(); - userEvent.click(screen.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-status-filter-in-progress')); - await waitFor(() => { - expect(useGetCasesMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - queryParams: DEFAULT_QUERY_PARAMS, - }) - ); - }); - }); - it('should show the correct count on stats', async () => { appMockRenderer.render(); - userEvent.click(screen.getByTestId('case-status-filter')); + userEvent.click(screen.getByTestId('options-filter-popover-button-status')); await waitFor(() => { - expect(screen.getByTestId('case-status-filter-open')).toHaveTextContent('Open (20)'); - expect(screen.getByTestId('case-status-filter-in-progress')).toHaveTextContent( + expect(screen.getByTestId('options-filter-popover-item-open')).toHaveTextContent('Open (20)'); + expect(screen.getByTestId('options-filter-popover-item-in-progress')).toHaveTextContent( 'In progress (40)' ); - expect(screen.getByTestId('case-status-filter-closed')).toHaveTextContent('Closed (130)'); + expect(screen.getByTestId('options-filter-popover-item-closed')).toHaveTextContent( + 'Closed (130)' + ); }); }); - it('renders the first available status when hiddenStatus is given', async () => { - appMockRenderer.render( - - ); - - await waitFor(() => - expect(screen.getAllByTestId('case-status-badge-in-progress')[0]).toBeInTheDocument() - ); - }); - it('shows Solution column if there are no set owners', async () => { render( @@ -642,9 +592,9 @@ describe('AllCasesListGeneric', () => { expect(checkbox).toBeChecked(); } - userEvent.click(screen.getByTestId('case-status-filter')); + userEvent.click(screen.getByTestId('options-filter-popover-button-status')); await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-status-filter-closed')); + userEvent.click(screen.getByTestId('options-filter-popover-item-open')); for (const checkbox of checkboxes) { expect(checkbox).not.toBeChecked(); @@ -701,24 +651,25 @@ describe('AllCasesListGeneric', () => { expect(useGetCasesMock).toHaveBeenCalledWith({ filterOptions: { search: '', - searchFields: [], - severity: 'all', + searchFields: ['title', 'description'], + severity: [], reporters: [], - status: 'all', + status: [], tags: [], assignees: [], owner: ['securitySolution', 'observability'], category: [], + customFields: {}, }, queryParams: DEFAULT_QUERY_PARAMS, }); - userEvent.click(getByTestId('solution-filter-popover-button')); + userEvent.click(getByTestId('options-filter-popover-button-owner')); await waitForEuiPopoverOpen(); userEvent.click( - getByTestId(`solution-filter-popover-item-${SECURITY_SOLUTION_OWNER}`), + getByTestId(`options-filter-popover-item-${SECURITY_SOLUTION_OWNER}`), undefined, { skipPointerEventsCheck: true, @@ -728,20 +679,21 @@ describe('AllCasesListGeneric', () => { expect(useGetCasesMock).toBeCalledWith({ filterOptions: { search: '', - searchFields: [], - severity: 'all', + searchFields: ['title', 'description'], + severity: [], reporters: [], - status: 'all', + status: [], tags: [], assignees: [], owner: ['securitySolution'], category: [], + customFields: {}, }, queryParams: DEFAULT_QUERY_PARAMS, }); userEvent.click( - getByTestId(`solution-filter-popover-item-${SECURITY_SOLUTION_OWNER}`), + getByTestId(`options-filter-popover-item-${SECURITY_SOLUTION_OWNER}`), undefined, { skipPointerEventsCheck: true, @@ -751,14 +703,15 @@ describe('AllCasesListGeneric', () => { expect(useGetCasesMock).toHaveBeenLastCalledWith({ filterOptions: { search: '', - searchFields: [], - severity: 'all', + searchFields: ['title', 'description'], + severity: [], reporters: [], - status: 'all', + status: [], tags: [], assignees: [], owner: ['securitySolution', 'observability'], category: [], + customFields: {}, }, queryParams: DEFAULT_QUERY_PARAMS, }); @@ -771,7 +724,7 @@ describe('AllCasesListGeneric', () => { ); - expect(queryByTestId('solution-filter-popover-button')).toBeFalsy(); + expect(queryByTestId('options-filter-popover-button-owner')).toBeFalsy(); }); it('should call useGetCases with the correct owner on initial render', async () => { @@ -784,14 +737,15 @@ describe('AllCasesListGeneric', () => { expect(useGetCasesMock).toHaveBeenCalledWith({ filterOptions: { search: '', - searchFields: [], - severity: 'all', + searchFields: ['title', 'description'], + severity: [], reporters: [], - status: 'all', + status: [], tags: [], assignees: [], owner: ['securitySolution'], category: [], + customFields: {}, }, queryParams: DEFAULT_QUERY_PARAMS, }); diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx index 75fe22f8e53b..a997e25a59f2 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx @@ -11,19 +11,12 @@ import { EuiProgress } from '@elastic/eui'; import { difference, head, isEmpty } from 'lodash/fp'; import styled, { css } from 'styled-components'; -import type { - CaseUI, - CaseStatusWithAllStatus, - FilterOptions, - CasesUI, -} from '../../../common/ui/types'; -import type { CasesOwners } from '../../client/helpers/can_use_cases'; -import type { EuiBasicTableOnChange, Solution } from './types'; +import type { CaseUI, FilterOptions, CasesUI } from '../../../common/ui/types'; +import type { EuiBasicTableOnChange } from './types'; -import { SortFieldCase, StatusAll } from '../../../common/ui/types'; -import { CaseStatuses, caseStatuses } from '../../../common/types/domain'; -import { OWNER_INFO } from '../../../common/constants'; -import { useAvailableCasesOwners } from '../app/use_available_owners'; +import { SortFieldCase } from '../../../common/ui/types'; +import type { CaseStatuses } from '../../../common/types/domain'; +import { caseStatuses } from '../../../common/types/domain'; import { useCasesColumns } from './use_cases_columns'; import { CasesTableFilters } from './table_filters'; import { CASES_TABLE_PERPAGE_VALUES } from './types'; @@ -37,6 +30,7 @@ import { useGetCurrentUserProfile } from '../../containers/user_profiles/use_get import { getAllPermissionsExceptFrom, isReadOnlyPermissions } from '../../utils/permissions'; import { useIsLoadingCases } from './use_is_loading_cases'; import { useAllCasesState } from './use_all_cases_state'; +import { useAvailableCasesOwners } from '../app/use_available_owners'; import { useCasesColumnsSelection } from './use_cases_columns_selection'; const ProgressLoader = styled(EuiProgress)` @@ -56,19 +50,8 @@ const getSortField = (field: string): SortFieldCase => // @ts-ignore SortFieldCase[field] ?? SortFieldCase.title; -const isValidSolution = (solution: string): solution is CasesOwners => - Object.keys(OWNER_INFO).includes(solution); - -const mapToReadableSolutionName = (solution: string): Solution => { - if (isValidSolution(solution)) { - return OWNER_INFO[solution]; - } - - return { id: solution, label: solution, iconType: '' }; -}; - export interface AllCasesListProps { - hiddenStatuses?: CaseStatusWithAllStatus[]; + hiddenStatuses?: CaseStatuses[]; isSelectorView?: boolean; onRowClick?: (theCase?: CaseUI, isCreateCase?: boolean) => void; } @@ -82,7 +65,7 @@ export const AllCasesList = React.memo( const hasOwner = !!owner.length; const firstAvailableStatus = head(difference(caseStatuses, hiddenStatuses)); const initialFilterOptions = { - ...(!isEmpty(hiddenStatuses) && firstAvailableStatus && { status: firstAvailableStatus }), + ...(!isEmpty(hiddenStatuses) && firstAvailableStatus && { status: [firstAvailableStatus] }), owner: hasOwner ? owner : availableSolutions, }; @@ -161,59 +144,16 @@ export const AllCasesList = React.memo( const onFilterChangedCallback = useCallback( (newFilterOptions: Partial) => { - if ( - newFilterOptions?.status === CaseStatuses.closed && - queryParams.sortField === SortFieldCase.createdAt - ) { - setQueryParams({ sortField: SortFieldCase.closedAt }); - } else if ( - newFilterOptions.status && - [CaseStatuses.open, CaseStatuses['in-progress'], StatusAll].includes( - newFilterOptions.status - ) && - queryParams.sortField === SortFieldCase.closedAt - ) { - setQueryParams({ sortField: SortFieldCase.createdAt }); - } - deselectCases(); - setFilterOptions({ - ...newFilterOptions, - /** - * If the user selects and deselects all solutions - * then the owner is set to an empty array. This results in fetching all cases the user has access to including - * the ones with read access. We want to show only the cases the user has full access to. - * For that reason we fallback to availableSolutions if the owner is empty. - * - * If the consumer of cases has passed an owner we fallback to the provided owner - */ - ...(newFilterOptions.owner != null && !hasOwner - ? { - owner: - newFilterOptions.owner.length === 0 ? availableSolutions : newFilterOptions.owner, - } - : newFilterOptions.owner != null && hasOwner - ? { - owner: newFilterOptions.owner.length === 0 ? owner : newFilterOptions.owner, - } - : {}), - }); + setFilterOptions(newFilterOptions); }, - [ - queryParams.sortField, - deselectCases, - setFilterOptions, - hasOwner, - availableSolutions, - owner, - setQueryParams, - ] + [deselectCases, setFilterOptions] ); const { selectedColumns, setSelectedColumns } = useCasesColumnsSelection(); const { columns, isLoadingColumns } = useCasesColumns({ - filterStatus: filterOptions.status ?? StatusAll, + filterStatus: filterOptions.status ?? [], userProfiles: userProfiles ?? new Map(), isSelectorView, connectors, @@ -249,10 +189,6 @@ export const AllCasesList = React.memo( [] ); - const availableSolutionsLabels = availableSolutions.map((solution) => - mapToReadableSolutionName(solution) - ); - const onCreateCasePressed = useCallback(() => { onRowClick?.(undefined, true); }, [onRowClick]); @@ -271,23 +207,14 @@ export const AllCasesList = React.memo( countOpenCases={data.countOpenCases} countInProgressCases={data.countInProgressCases} onFilterChanged={onFilterChangedCallback} - availableSolutions={hasOwner ? [] : availableSolutionsLabels} - initial={{ - search: filterOptions.search, - searchFields: filterOptions.searchFields, - assignees: filterOptions.assignees, - reporters: filterOptions.reporters, - tags: filterOptions.tags, - status: filterOptions.status, - owner: filterOptions.owner, - severity: filterOptions.severity, - category: filterOptions.category, - }} + availableSolutions={hasOwner ? [] : availableSolutions} hiddenStatuses={hiddenStatuses} onCreateCasePressed={onCreateCasePressed} + initialFilterOptions={initialFilterOptions} isSelectorView={isSelectorView} isLoading={isLoadingCurrentUserProfile} currentUserProfile={currentUserProfile} + filterOptions={filterOptions} /> = ({ diff --git a/x-pack/plugins/cases/public/components/all_cases/header.test.tsx b/x-pack/plugins/cases/public/components/all_cases/header.test.tsx index 08bd228b32e1..333f33039444 100644 --- a/x-pack/plugins/cases/public/components/all_cases/header.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/header.test.tsx @@ -46,9 +46,9 @@ describe('CasesTableHeader', () => { expect(result.getByTestId('configure-case-button')).toBeInTheDocument(); }); - it('does not display the configure button when the user does not have update privileges', () => { + it('does not display the configure button when the user does not have settings privileges', () => { appMockRender = createAppMockRenderer({ - permissions: buildCasesPermissions({ update: false }), + permissions: buildCasesPermissions({ settings: false }), }); const result = appMockRender.render(); diff --git a/x-pack/plugins/cases/public/components/all_cases/index.test.tsx b/x-pack/plugins/cases/public/components/all_cases/index.test.tsx index d34be81d499f..ce26440da3cd 100644 --- a/x-pack/plugins/cases/public/components/all_cases/index.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/index.test.tsx @@ -15,6 +15,7 @@ import { useGetActionLicense } from '../../containers/use_get_action_license'; import { connectorsMock, useGetCasesMockState } from '../../containers/mock'; import { useGetSupportedActionConnectors } from '../../containers/configure/use_get_supported_action_connectors'; import { useGetTags } from '../../containers/use_get_tags'; +import { useGetCategories } from '../../containers/use_get_categories'; import { useGetCases } from '../../containers/use_get_cases'; import { useGetCurrentUserProfile } from '../../containers/user_profiles/use_get_current_user_profile'; import { userProfiles, userProfilesMap } from '../../containers/user_profiles/api.mock'; @@ -22,6 +23,7 @@ import { useBulkGetUserProfiles } from '../../containers/user_profiles/use_bulk_ jest.mock('../../common/lib/kibana'); jest.mock('../../containers/use_get_tags'); +jest.mock('../../containers/use_get_categories'); jest.mock('../../containers/use_get_action_license', () => { return { useGetActionLicense: jest.fn(), @@ -62,6 +64,10 @@ describe('AllCases', () => { beforeAll(() => { (useGetTags as jest.Mock).mockReturnValue({ data: ['coke', 'pepsi'], refetch: jest.fn() }); + (useGetCategories as jest.Mock).mockReturnValue({ + data: ['beverages', 'snacks'], + refetch: jest.fn(), + }); useGetConnectorsMock.mockImplementation(() => ({ data: connectorsMock, isLoading: false })); useGetActionLicenseMock.mockReturnValue(defaultActionLicense); useGetCasesMock.mockReturnValue(defaultGetCases); diff --git a/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.test.tsx new file mode 100644 index 000000000000..5210e3d52e21 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.test.tsx @@ -0,0 +1,183 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { MultiSelectFilter } from './multi_select_filter'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; + +describe('multi select filter', () => { + it('should render the amount of options available', async () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + { label: 'tag c', key: 'tag c' }, + { label: 'tag d', key: 'tag d' }, + ], + onChange, + }; + + render(); + + userEvent.click(screen.getByRole('button', { name: 'Tags' })); + await waitForEuiPopoverOpen(); + + expect(screen.getByText('4 options')).toBeInTheDocument(); + }); + + it('hides the limit reached warning when a selected tag is removed', async () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + selectedOptionKeys: ['tag a'], + limit: 1, + limitReachedMessage: 'Limit reached', + }; + + const { rerender } = render(); + + userEvent.click(screen.getByRole('button', { name: 'Tags' })); + await waitForEuiPopoverOpen(); + + expect(screen.getByText('Limit reached')).toBeInTheDocument(); + + userEvent.click(screen.getByRole('option', { name: 'tag a' })); + + expect(onChange).toHaveBeenCalledWith({ filterId: 'tags', selectedOptionKeys: [] }); + rerender(); + + expect(screen.queryByText('Limit reached')).not.toBeInTheDocument(); + }); + + it('displays the limit reached warning when the maximum number of tags is selected', async () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + selectedOptionKeys: ['tag a'], + limit: 2, + limitReachedMessage: 'Limit reached', + }; + + const { rerender } = render(); + + userEvent.click(screen.getByRole('button', { name: 'Tags' })); + await waitForEuiPopoverOpen(); + + expect(screen.queryByText('Limit reached')).not.toBeInTheDocument(); + + userEvent.click(screen.getByRole('option', { name: 'tag b' })); + + expect(onChange).toHaveBeenCalledWith({ + filterId: 'tags', + selectedOptionKeys: ['tag a', 'tag b'], + }); + rerender(); + + expect(screen.getByText('Limit reached')).toBeInTheDocument(); + }); + + it('should not call onChange when the limit has been reached', async () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + selectedOptionKeys: ['tag a'], + limit: 1, + limitReachedMessage: 'Limit reached', + }; + + render(); + + userEvent.click(screen.getByRole('button', { name: 'Tags' })); + await waitForEuiPopoverOpen(); + + expect(screen.getByText('Limit reached')).toBeInTheDocument(); + + userEvent.click(screen.getByRole('option', { name: 'tag b' })); + + expect(onChange).not.toHaveBeenCalled(); + }); + + it('should remove selected option if it suddenly disappeared from the list', async () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + selectedOptionKeys: ['tag b'], + }; + + const { rerender } = render(); + rerender(); + expect(onChange).toHaveBeenCalledWith({ filterId: 'tags', selectedOptionKeys: [] }); + }); + + it('activates custom renderOption when set', async () => { + const TEST_ID = 'test-render-option-id'; + const onChange = jest.fn(); + const renderOption = () =>
    ; + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + renderOption, + }; + + render(); + userEvent.click(screen.getByRole('button', { name: 'Tags' })); + await waitForEuiPopoverOpen(); + expect(screen.getAllByTestId(TEST_ID).length).toBe(2); + }); + + it('should not show the amount of options if hideActiveOptionsNumber is active', () => { + const onChange = jest.fn(); + const props = { + id: 'tags', + buttonLabel: 'Tags', + options: [ + { label: 'tag a', key: 'tag a' }, + { label: 'tag b', key: 'tag b' }, + ], + onChange, + selectedOptionKeys: ['tag b'], + }; + + const { rerender } = render(); + expect(screen.queryByLabelText('1 active filters')).toBeInTheDocument(); + rerender(); + expect(screen.queryByLabelText('1 active filters')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.tsx b/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.tsx new file mode 100644 index 000000000000..cbfdb30d122a --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/multi_select_filter.tsx @@ -0,0 +1,192 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect } from 'react'; +import { css } from '@emotion/react'; +import type { EuiSelectableOption } from '@elastic/eui'; +import { + EuiPopoverTitle, + EuiCallOut, + EuiHorizontalRule, + EuiPopover, + EuiSelectable, + EuiFilterButton, + EuiTextColor, + EuiSpacer, + useEuiTheme, +} from '@elastic/eui'; +import { isEqual } from 'lodash/fp'; +import * as i18n from './translations'; + +type FilterOption = EuiSelectableOption<{ + key: K; + label: T; +}>; + +export type { FilterOption as MultiSelectFilterOption }; + +export const mapToMultiSelectOption = (options: T[]) => { + return options.map((option) => { + return { + key: option, + label: option, + }; + }); +}; + +const fromRawOptionsToEuiSelectableOptions = ( + options: Array>, + selectedOptionKeys: string[] +): Array> => { + return options.map(({ key, label }) => { + const selectableOption: FilterOption = { label, key }; + if (selectedOptionKeys.includes(key)) { + selectableOption.checked = 'on'; + } + selectableOption['data-test-subj'] = `options-filter-popover-item-${key.split(' ').join('-')}`; + return selectableOption; + }); +}; + +const fromEuiSelectableOptionToRawOption = ( + options: Array> +): string[] => { + return options.map((option) => option.key); +}; + +const getEuiSelectableCheckedOptions = ( + options: Array> +) => options.filter((option) => option.checked === 'on') as Array>; + +interface UseFilterParams { + buttonLabel?: string; + buttonIconType?: string; + hideActiveOptionsNumber?: boolean; + id: string; + limit?: number; + limitReachedMessage?: string; + onChange: (params: { filterId: string; selectedOptionKeys: string[] }) => void; + options: Array>; + selectedOptionKeys?: string[]; + renderOption?: (option: FilterOption) => React.ReactNode; +} +export const MultiSelectFilter = ({ + buttonLabel, + buttonIconType, + hideActiveOptionsNumber, + id, + limit, + limitReachedMessage, + onChange, + options: rawOptions, + selectedOptionKeys = [], + renderOption, +}: UseFilterParams) => { + const { euiTheme } = useEuiTheme(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const toggleIsPopoverOpen = () => setIsPopoverOpen((prevValue) => !prevValue); + const showActiveOptionsNumber = !hideActiveOptionsNumber; + const isInvalid = Boolean(limit && limitReachedMessage && selectedOptionKeys.length >= limit); + const options = fromRawOptionsToEuiSelectableOptions(rawOptions, selectedOptionKeys); + + useEffect(() => { + const newSelectedOptions = selectedOptionKeys.filter((selectedOptionKey) => + rawOptions.some(({ key: optionKey }) => optionKey === selectedOptionKey) + ); + if (!isEqual(newSelectedOptions, selectedOptionKeys)) { + onChange({ + filterId: id, + selectedOptionKeys: newSelectedOptions, + }); + } + }, [selectedOptionKeys, rawOptions, id, onChange]); + + const _onChange = (newOptions: Array>) => { + const newSelectedOptions = getEuiSelectableCheckedOptions(newOptions); + if (isInvalid && limit && newSelectedOptions.length >= limit) { + return; + } + + onChange({ + filterId: id, + selectedOptionKeys: fromEuiSelectableOptionToRawOption(newSelectedOptions), + }); + }; + + return ( + 0 : undefined} + numActiveFilters={showActiveOptionsNumber ? selectedOptionKeys.length : undefined} + aria-label={buttonLabel} + > + {buttonLabel} + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + panelPaddingSize="none" + repositionOnScroll + > + {isInvalid && ( + <> + + + + + )} + > + options={options} + searchable + searchProps={{ + placeholder: buttonLabel, + compressed: false, + 'data-test-subj': `${id}-search-input`, + }} + emptyMessage={i18n.EMPTY_FILTER_MESSAGE} + onChange={_onChange} + singleSelection={false} + renderOption={renderOption} + > + {(list, search) => ( +
    + {search} +
    + {i18n.OPTIONS(options.length)} +
    + + {list} +
    + )} + +
    + ); +}; + +MultiSelectFilter.displayName = 'MultiSelectFilter'; diff --git a/x-pack/plugins/cases/public/components/all_cases/nav_buttons.test.tsx b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.test.tsx new file mode 100644 index 000000000000..b825f5c27f2e --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.test.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen } from '@testing-library/react'; +import type { AppMockRenderer } from '../../common/mock'; +import { + createAppMockRenderer, + noCasesSettingsPermission, + noCreateCasesPermissions, + buildCasesPermissions, +} from '../../common/mock'; +import { NavButtons } from './nav_buttons'; + +describe('NavButtons', () => { + let appMockRenderer: AppMockRenderer; + + beforeEach(() => { + appMockRenderer = createAppMockRenderer(); + }); + + it('shows the configure case button', () => { + appMockRenderer.render(); + + expect(screen.getByTestId('configure-case-button')).toBeInTheDocument(); + }); + + it('does not render the case create button with no create permissions', () => { + appMockRenderer = createAppMockRenderer({ permissions: noCreateCasesPermissions() }); + appMockRenderer.render(); + + expect(screen.queryByTestId('createNewCaseBtn')).not.toBeInTheDocument(); + }); + + it('does not render the case configure button with no settings permissions', () => { + appMockRenderer = createAppMockRenderer({ permissions: noCasesSettingsPermission() }); + appMockRenderer.render(); + + expect(screen.queryByTestId('configure-case-button')).not.toBeInTheDocument(); + }); + + it('does not render any button with no create and no settings permissions', () => { + appMockRenderer = createAppMockRenderer({ + permissions: buildCasesPermissions({ create: false, settings: false }), + }); + appMockRenderer.render(); + + expect(screen.queryByTestId('createNewCaseBtn')).not.toBeInTheDocument(); + expect(screen.queryByTestId('configure-case-button')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx index aafb287eed86..05febf94f431 100644 --- a/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx @@ -43,14 +43,14 @@ export const NavButtons: FunctionComponent = ({ actionsErrors }) => { [navigateToCreateCase] ); - if (!permissions.create && !permissions.update) { + if (!permissions.create && !permissions.settings) { return null; } return ( - {permissions.update && ( + {permissions.settings && ( { beforeEach(() => { jest.clearAllMocks(); appMockRenderer = createAppMockRenderer(); + (useGetTags as jest.Mock).mockReturnValue({ data: ['coke', 'pepsi'], refetch: jest.fn() }); + (useGetCategories as jest.Mock).mockReturnValue({ + data: ['beverages', 'snacks'], + refetch: jest.fn(), + }); }); it('renders', () => { diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx index c03ba9e05947..7cda95df5e75 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx @@ -16,12 +16,13 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import type { CaseUI, CaseStatusWithAllStatus } from '../../../../common/ui/types'; +import type { CaseStatuses } from '../../../../common/types/domain'; +import type { CaseUI } from '../../../../common/ui/types'; import * as i18n from '../../../common/translations'; import { AllCasesList } from '../all_cases_list'; export interface AllCasesSelectorModalProps { - hiddenStatuses?: CaseStatusWithAllStatus[]; + hiddenStatuses?: CaseStatuses[]; onRowClick?: (theCase?: CaseUI) => void; onClose?: (theCase?: CaseUI, isCreateCase?: boolean) => void; onCreateCaseClicked?: () => void; diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx index a80e1935d1ad..e7aa9e37961b 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx @@ -11,7 +11,6 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import AllCasesSelectorModal from '.'; import type { CaseUI } from '../../../../common'; -import { StatusAll } from '../../../../common'; import { CaseStatuses } from '../../../../common/types/domain'; import type { AppMockRenderer } from '../../../common/mock'; import { allCasesPermissions, createAppMockRenderer } from '../../../common/mock'; @@ -117,7 +116,7 @@ describe('use cases add to existing case modal hook', () => { expect.objectContaining({ type: CasesContextStoreActionsList.OPEN_ADD_TO_CASE_MODAL, payload: expect.objectContaining({ - hiddenStatuses: [CaseStatuses.closed, StatusAll], + hiddenStatuses: [CaseStatuses.closed], }), }) ); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx index 35d15fa7e89e..f311fdad66a4 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.tsx @@ -10,7 +10,6 @@ import { CaseStatuses } from '../../../../common/types/domain'; import type { AllCasesSelectorModalProps } from '.'; import { useCasesToast } from '../../../common/use_cases_toast'; import type { CaseUI } from '../../../containers/types'; -import { StatusAll } from '../../../containers/types'; import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer'; import { useCasesContext } from '../../cases_context/use_cases_context'; import { useCasesAddToNewCaseFlyout } from '../../create/flyout/use_cases_add_to_new_case_flyout'; @@ -128,7 +127,7 @@ export const useCasesAddToExistingCaseModal = (props: AddToExistingCaseModalProp type: CasesContextStoreActionsList.OPEN_ADD_TO_CASE_MODAL, payload: { ...props, - hiddenStatuses: [CaseStatuses.closed, StatusAll], + hiddenStatuses: [CaseStatuses.closed], onRowClick: (theCase?: CaseUI) => { handleOnRowClick(theCase, getAttachments); }, diff --git a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx index 26169e16c5be..6924cbd13f1c 100644 --- a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx @@ -10,52 +10,46 @@ import React from 'react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import userEvent from '@testing-library/user-event'; -import { waitFor } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import { SeverityFilter } from './severity_filter'; describe('Severity form field', () => { - const onSeverityChange = jest.fn(); + const onChange = jest.fn(); let appMockRender: AppMockRenderer; const props = { - isLoading: false, - selectedSeverity: CaseSeverity.LOW, - isDisabled: false, - onSeverityChange, + selectedOptionKeys: [], + onChange, }; + beforeEach(() => { appMockRender = createAppMockRenderer(); }); - it('renders', () => { - const result = appMockRender.render(); - expect(result.getByTestId('case-severity-filter')).not.toHaveAttribute('disabled'); - }); - // default to LOW in this test configuration - it('defaults to the correct value', () => { - const result = appMockRender.render(); - // Popver span and ID was removed here: - // https://github.com/elastic/eui/pull/6630#discussion_r1123655995 - expect(result.getAllByTestId('case-severity-filter-low').length).toBe(1); - }); + it('renders', async () => { + appMockRender.render(); + expect(screen.getByTestId('options-filter-popover-button-severity')).toBeInTheDocument(); + expect(screen.getByTestId('options-filter-popover-button-severity')).not.toBeDisabled(); - it('selects the correct value when changed', async () => { - const result = appMockRender.render(); - userEvent.click(result.getByTestId('case-severity-filter')); + userEvent.click(screen.getByRole('button', { name: 'Severity' })); await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('case-severity-filter-high')); - await waitFor(() => { - expect(onSeverityChange).toHaveBeenCalledWith('high'); - }); + + expect(screen.getByRole('option', { name: CaseSeverity.LOW })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: CaseSeverity.MEDIUM })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: CaseSeverity.HIGH })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: CaseSeverity.CRITICAL })).toBeInTheDocument(); + expect(screen.getAllByRole('option').length).toBe(4); }); - it('selects the correct value when changed (all)', async () => { - const result = appMockRender.render(); - userEvent.click(result.getByTestId('case-severity-filter')); + it('selects the correct value when changed', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'Severity' })); await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('case-severity-filter-all')); + userEvent.click(screen.getByRole('option', { name: 'high' })); + await waitFor(() => { - expect(onSeverityChange).toHaveBeenCalledWith('all'); + expect(onChange).toHaveBeenCalledWith({ filterId: 'severity', selectedOptionKeys: ['high'] }); }); }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/severity_filter.tsx b/x-pack/plugins/cases/public/components/all_cases/severity_filter.tsx index f421d8828dc2..650e5215c6aa 100644 --- a/x-pack/plugins/cases/public/components/all_cases/severity_filter.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/severity_filter.tsx @@ -5,61 +5,41 @@ * 2.0. */ -import type { EuiSuperSelectOption } from '@elastic/eui'; -import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiHealth } from '@elastic/eui'; import React from 'react'; -import type { CaseSeverityWithAll } from '../../containers/types'; -import { SeverityAll } from '../../containers/types'; -import { severitiesWithAll } from '../severity/config'; +import type { CaseSeverity } from '../../../common/types/domain'; +import { severities } from '../severity/config'; +import type { MultiSelectFilterOption } from './multi_select_filter'; +import { MultiSelectFilter, mapToMultiSelectOption } from './multi_select_filter'; +import * as i18n from './translations'; interface Props { - selectedSeverity: CaseSeverityWithAll; - onSeverityChange: (status: CaseSeverityWithAll) => void; - isLoading: boolean; - isDisabled: boolean; + selectedOptionKeys: CaseSeverity[]; + onChange: (params: { filterId: string; selectedOptionKeys: string[] }) => void; } -export const SeverityFilter: React.FC = ({ - selectedSeverity, - onSeverityChange, - isLoading, - isDisabled, -}) => { - const caseSeverities = Object.keys(severitiesWithAll) as CaseSeverityWithAll[]; - const options: Array> = caseSeverities.map( - (severity) => { - const severityData = severitiesWithAll[severity]; - return { - value: severity, - inputDisplay: ( - - - {severity === SeverityAll ? ( - {severityData.label} - ) : ( - {severityData.label} - )} - - - ), - }; - } - ); +const options = mapToMultiSelectOption(Object.keys(severities) as CaseSeverity[]); + +export const SeverityFilter: React.FC = ({ selectedOptionKeys, onChange }) => { + const renderOption = (option: MultiSelectFilterOption) => { + const severityData = severities[option.label]; + return ( + + + {severityData.label} + + + ); + }; return ( - + buttonLabel={i18n.SEVERITY} + id={'severity'} + onChange={onChange} options={options} - valueOfSelected={selectedSeverity} - onChange={onSeverityChange} - data-test-subj="case-severity-filter" + renderOption={renderOption} + selectedOptionKeys={selectedOptionKeys} /> ); }; diff --git a/x-pack/plugins/cases/public/components/all_cases/solution_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/solution_filter.test.tsx index dcb469448b03..69c757e354b8 100644 --- a/x-pack/plugins/cases/public/components/all_cases/solution_filter.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/solution_filter.test.tsx @@ -6,35 +6,20 @@ */ import React from 'react'; +import { screen } from '@testing-library/react'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; -import type { Solution } from './types'; -import { - OWNER_INFO, - SECURITY_SOLUTION_OWNER, - OBSERVABILITY_OWNER, -} from '../../../common/constants'; +import { SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER } from '../../../common/constants'; import { SolutionFilter } from './solution_filter'; import userEvent from '@testing-library/user-event'; describe('SolutionFilter ', () => { let appMockRender: AppMockRenderer; - const onSelectedOptionsChanged = jest.fn(); - const solutions: Solution[] = [ - { - id: SECURITY_SOLUTION_OWNER, - label: OWNER_INFO[SECURITY_SOLUTION_OWNER].label, - iconType: OWNER_INFO[SECURITY_SOLUTION_OWNER].iconType, - }, - { - id: OBSERVABILITY_OWNER, - label: OWNER_INFO[OBSERVABILITY_OWNER].label, - iconType: OWNER_INFO[OBSERVABILITY_OWNER].iconType, - }, - ]; + const onChange = jest.fn(); + const solutions = [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER]; beforeEach(() => { appMockRender = createAppMockRenderer(); @@ -43,85 +28,148 @@ describe('SolutionFilter ', () => { it('renders button correctly', () => { const { getByTestId } = appMockRender.render( - + ); - expect(getByTestId('solution-filter-popover-button')).toBeInTheDocument(); + expect(getByTestId('options-filter-popover-button-owner')).toBeInTheDocument(); }); - it('renders empty label correctly', async () => { - const { getByTestId, getByText } = appMockRender.render( - - ); - - userEvent.click(getByTestId('solution-filter-popover-button')); - - await waitForEuiPopoverOpen(); - - expect(getByText('No options available')).toBeInTheDocument(); + describe('when the owner is a single solution', () => { + beforeEach(() => { + // by default, the owner will be the same but we set it explicitly here to make it clear + appMockRender = createAppMockRenderer({ owner: [SECURITY_SOLUTION_OWNER] }); + jest.clearAllMocks(); + }); + + it('renders options correctly', async () => { + appMockRender.render( + + ); + + expect(screen.getByTestId('options-filter-popover-button-owner')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('options-filter-popover-button-owner')); + + await waitForEuiPopoverOpen(); + + expect(screen.getByTestId(`options-filter-popover-item-${solutions[0]}`)).toBeInTheDocument(); + expect( + screen.queryByTestId(`options-filter-popover-item-${solutions[1]}`) + ).not.toBeInTheDocument(); + }); + + it('should call onChange with selected solution id when no option selected yet', async () => { + const { getByTestId } = appMockRender.render( + + ); + + userEvent.click(getByTestId('options-filter-popover-button-owner')); + + await waitForEuiPopoverOpen(); + + userEvent.click(getByTestId(`options-filter-popover-item-${solutions[0]}`)); + + expect(onChange).toHaveBeenCalledWith({ + filterId: 'owner', + selectedOptionKeys: [solutions[0]], + }); + }); + + it('should call onChange with [owner] when the last solution option selected is deselected', async () => { + const { getByTestId } = appMockRender.render( + + ); + + userEvent.click(getByTestId('options-filter-popover-button-owner')); + + await waitForEuiPopoverOpen(); + + userEvent.click(getByTestId(`options-filter-popover-item-${solutions[0]}`)); + + expect(onChange).toHaveBeenCalledWith({ + filterId: 'owner', + selectedOptionKeys: [solutions[0]], + }); + }); }); - it('renders options correctly', async () => { - const { getByTestId } = appMockRender.render( - - ); + describe('when no owner set', () => { + beforeEach(() => { + appMockRender = createAppMockRenderer({ owner: [] }); + jest.clearAllMocks(); + }); - expect(getByTestId('solution-filter-popover-button')).toBeInTheDocument(); + it('renders options correctly', async () => { + const { getByTestId } = appMockRender.render( + + ); - userEvent.click(getByTestId('solution-filter-popover-button')); + expect(getByTestId('options-filter-popover-button-owner')).toBeInTheDocument(); - await waitForEuiPopoverOpen(); + userEvent.click(getByTestId('options-filter-popover-button-owner')); - expect(getByTestId(`solution-filter-popover-item-${solutions[0].id}`)).toBeInTheDocument(); - expect(getByTestId(`solution-filter-popover-item-${solutions[0].id}`)).toBeInTheDocument(); - }); + await waitForEuiPopoverOpen(); - it('should call onSelectionChange with selected solution id', async () => { - const { getByTestId } = appMockRender.render( - - ); + expect(getByTestId(`options-filter-popover-item-${solutions[0]}`)).toBeInTheDocument(); + expect(getByTestId(`options-filter-popover-item-${solutions[1]}`)).toBeInTheDocument(); + }); - userEvent.click(getByTestId('solution-filter-popover-button')); + it('should call onChange with selected solution id when no option selected yet', async () => { + const { getByTestId } = appMockRender.render( + + ); - await waitForEuiPopoverOpen(); + userEvent.click(getByTestId('options-filter-popover-button-owner')); - userEvent.click(getByTestId(`solution-filter-popover-item-${solutions[0].id}`)); + await waitForEuiPopoverOpen(); - expect(onSelectedOptionsChanged).toHaveBeenCalledWith([solutions[0].id]); - }); + userEvent.click(getByTestId(`options-filter-popover-item-${solutions[0]}`)); - it('should call onSelectionChange with empty array when solution option is deselected', async () => { - const { getByTestId } = appMockRender.render( - - ); + expect(onChange).toHaveBeenCalledWith({ + filterId: 'owner', + selectedOptionKeys: [solutions[0]], + }); + }); + + it('should call onChange with [all solutions] when the last solution option selected is deselected', async () => { + const { getByTestId } = appMockRender.render( + + ); - userEvent.click(getByTestId('solution-filter-popover-button')); + userEvent.click(getByTestId('options-filter-popover-button-owner')); - await waitForEuiPopoverOpen(); + await waitForEuiPopoverOpen(); - userEvent.click(getByTestId(`solution-filter-popover-item-${solutions[1].id}`)); + userEvent.click(getByTestId(`options-filter-popover-item-${solutions[0]}`)); - expect(onSelectedOptionsChanged).toHaveBeenCalledWith([]); + expect(onChange).toHaveBeenCalledWith({ + filterId: 'owner', + selectedOptionKeys: [solutions[0], solutions[1]], + }); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/solution_filter.tsx b/x-pack/plugins/cases/public/components/all_cases/solution_filter.tsx index b776895e2fe9..6f4eabddc0f8 100644 --- a/x-pack/plugins/cases/public/components/all_cases/solution_filter.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/solution_filter.tsx @@ -5,117 +5,96 @@ * 2.0. */ -import React, { useCallback, useState } from 'react'; -import { - EuiFilterButton, - EuiFilterSelectItem, - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiPopover, - EuiText, - EuiIcon, -} from '@elastic/eui'; -import styled from 'styled-components'; +import React from 'react'; +import type { EuiSelectableOption } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { OWNER_INFO } from '../../../common/constants'; import * as i18n from './translations'; import type { Solution } from './types'; +import { MultiSelectFilter, mapToMultiSelectOption } from './multi_select_filter'; +import type { CasesOwners } from '../../client/helpers/can_use_cases'; +import { useCasesContext } from '../cases_context/use_cases_context'; interface FilterPopoverProps { - onSelectedOptionsChanged: (value: string[]) => void; - options: Solution[]; - optionsEmptyLabel?: string; - selectedOptions: string[]; + onChange: (params: { filterId: string; selectedOptionKeys: string[] }) => void; + selectedOptionKeys: string[]; + availableSolutions: string[]; } -const ScrollableDiv = styled.div` - max-height: 250px; - overflow: auto; -`; +const isValidSolution = (solution: string): solution is CasesOwners => + Object.keys(OWNER_INFO).includes(solution); -const toggleSelectedGroup = (group: string, selectedGroups: string[]): string[] => { - const selectedGroupIndex = selectedGroups.indexOf(group); - if (selectedGroupIndex >= 0) { - return [ - ...selectedGroups.slice(0, selectedGroupIndex), - ...selectedGroups.slice(selectedGroupIndex + 1), - ]; +const mapToReadableSolutionName = (solution: string): Solution => { + if (isValidSolution(solution)) { + return OWNER_INFO[solution]; } - return [...selectedGroups, group]; + + return { id: solution, label: solution, iconType: '' }; }; -/** - * Popover for selecting a field to filter on - * - * @param buttonLabel label on dropdwon button - * @param onSelectedOptionsChanged change listener to be notified when option selection changes - * @param options to display for filtering - * @param optionsEmptyLabel shows when options empty - * @param selectedOptions manage state of selectedOptions - */ export const SolutionFilterComponent = ({ - onSelectedOptionsChanged, - options, - optionsEmptyLabel, - selectedOptions, + onChange, + selectedOptionKeys, + availableSolutions, }: FilterPopoverProps) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const { owner } = useCasesContext(); + const hasOwner = Boolean(owner.length); + const options = mapToMultiSelectOption(hasOwner ? owner : availableSolutions); + const solutions = availableSolutions.map((solution) => mapToReadableSolutionName(solution)); - const setIsPopoverOpenCb = useCallback(() => setIsPopoverOpen(!isPopoverOpen), [isPopoverOpen]); - const toggleSelectedGroupCb = useCallback( - (option) => onSelectedOptionsChanged(toggleSelectedGroup(option, selectedOptions)), - [selectedOptions, onSelectedOptionsChanged] - ); + /** + * If the user selects and deselects all solutions then the owner is set to an empty array. + * This results in fetching all cases the user has access to including + * the ones with read access. We want to show only the cases the user has full access to. + * For that reason we fallback to availableSolutions if the owner is empty. + * + * If the consumer of cases has passed an owner we fallback to the provided owner + */ + const _onChange = ({ + filterId, + selectedOptionKeys: newOptions, + }: { + filterId: string; + selectedOptionKeys: string[]; + }) => { + if (hasOwner) { + onChange({ + filterId, + selectedOptionKeys: newOptions.length === 0 ? owner : newOptions, + }); + } else { + onChange({ + filterId, + selectedOptionKeys: newOptions.length === 0 ? availableSolutions : newOptions, + }); + } + }; + + const selectedOptionsInFilter = + selectedOptionKeys.length === availableSolutions.length ? [] : selectedOptionKeys; + + const renderOption = (option: EuiSelectableOption) => { + const solution = solutions.find((solutionData) => solutionData.id === option.label) as Solution; + return ( + + + + + {solution.label} + + ); + }; return ( - 0} - numActiveFilters={selectedOptions.length} - aria-label={i18n.SOLUTION} - > - {i18n.SOLUTION} - - } - isOpen={isPopoverOpen} - closePopover={setIsPopoverOpenCb} - panelPaddingSize="none" - repositionOnScroll - > - - {options.map((option, index) => ( - - - - - - {option.label} - - - ))} - - {options.length === 0 && optionsEmptyLabel != null && ( - - - - {optionsEmptyLabel} - - - - )} - + ); }; diff --git a/x-pack/plugins/cases/public/components/all_cases/status_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/status_filter.test.tsx index e58f885972d4..3dac9d201ced 100644 --- a/x-pack/plugins/cases/public/components/all_cases/status_filter.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/status_filter.test.tsx @@ -6,78 +6,71 @@ */ import React from 'react'; -import { mount } from 'enzyme'; -import { waitFor } from '@testing-library/react'; - -import { StatusAll } from '../../../common/ui/types'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { CaseStatuses } from '../../../common/types/domain'; import { StatusFilter } from './status_filter'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import * as i18n from './translations'; -const stats = { - [StatusAll]: 0, - [CaseStatuses.open]: 2, - [CaseStatuses['in-progress']]: 5, - [CaseStatuses.closed]: 7, +const LABELS = { + closed: i18n.STATUS_CLOSED, + open: i18n.STATUS_OPEN, + inProgress: i18n.STATUS_IN_PROGRESS, }; describe('StatusFilter', () => { - const onStatusChanged = jest.fn(); + const onChange = jest.fn(); const defaultProps = { - selectedStatus: CaseStatuses.open, - onStatusChanged, - stats, + selectedOptionKeys: [], + countClosedCases: 7, + countInProgressCases: 5, + countOpenCases: 2, + onChange, }; - it('should render', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="case-status-filter"]').exists()).toBeTruthy(); + afterEach(() => { + jest.clearAllMocks(); }); - it('should call onStatusChanged when changing status to open', async () => { - const wrapper = mount(); + it('should render', async () => { + render(); - wrapper.find('button[data-test-subj="case-status-filter"]').simulate('click'); - wrapper.find('button[data-test-subj="case-status-filter-open"]').simulate('click'); - await waitFor(() => { - expect(onStatusChanged).toBeCalledWith('open'); - }); - }); + expect(screen.getByTestId('options-filter-popover-button-status')).toBeInTheDocument(); + expect(screen.getByTestId('options-filter-popover-button-status')).not.toBeDisabled(); - it('should call onStatusChanged when changing status to in-progress', async () => { - const wrapper = mount(); + userEvent.click(screen.getByRole('button', { name: 'Status' })); + await waitForEuiPopoverOpen(); - wrapper.find('button[data-test-subj="case-status-filter"]').simulate('click'); - wrapper.find('button[data-test-subj="case-status-filter-in-progress"]').simulate('click'); - await waitFor(() => { - expect(onStatusChanged).toBeCalledWith('in-progress'); - }); + expect(screen.getByRole('option', { name: LABELS.open })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: LABELS.inProgress })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: LABELS.closed })).toBeInTheDocument(); + expect(screen.getAllByRole('option').length).toBe(3); }); - it('should call onStatusChanged when changing status to closed', async () => { - const wrapper = mount(); + it('should call onStatusChanged when changing status to open', async () => { + render(); + + userEvent.click(screen.getByRole('button', { name: 'Status' })); + await waitForEuiPopoverOpen(); + userEvent.click(screen.getByRole('option', { name: LABELS.open })); - wrapper.find('button[data-test-subj="case-status-filter"]').simulate('click'); - wrapper.find('button[data-test-subj="case-status-filter-closed"]').simulate('click'); await waitFor(() => { - expect(onStatusChanged).toBeCalledWith('closed'); + expect(onChange).toHaveBeenCalledWith({ + filterId: 'status', + selectedOptionKeys: [CaseStatuses.open], + }); }); }); - it('should not render hidden statuses', () => { - const wrapper = mount( - - ); - - wrapper.find('button[data-test-subj="case-status-filter"]').simulate('click'); - - expect(wrapper.find(`[data-test-subj="case-status-filter-all"]`).exists()).toBeFalsy(); - expect(wrapper.find('button[data-test-subj="case-status-filter-closed"]').exists()).toBeFalsy(); + it('should not render hidden statuses', async () => { + render(); - expect(wrapper.find('button[data-test-subj="case-status-filter-open"]').exists()).toBeTruthy(); + userEvent.click(screen.getByRole('button', { name: 'Status' })); + await waitForEuiPopoverOpen(); - expect( - wrapper.find('button[data-test-subj="case-status-filter-in-progress"]').exists() - ).toBeTruthy(); + expect(screen.getAllByRole('option')).toHaveLength(2); + expect(screen.getByRole('option', { name: LABELS.open })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: LABELS.inProgress })).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx b/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx index 58ba9127566a..cc4b032f96c7 100644 --- a/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx @@ -5,62 +5,78 @@ * 2.0. */ -import React, { memo } from 'react'; -import type { EuiSuperSelectOption } from '@elastic/eui'; -import { EuiSuperSelect, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Status } from '@kbn/cases-components/src/status/status'; -import { allCaseStatus, statuses } from '../status'; -import type { CaseStatusWithAllStatus } from '../../../common/ui/types'; -import { StatusAll } from '../../../common/ui/types'; +import { CaseStatuses } from '../../../common/types/domain'; + +import type { MultiSelectFilterOption } from './multi_select_filter'; +import { MultiSelectFilter } from './multi_select_filter'; +import * as i18n from './translations'; interface Props { - stats: Record; - selectedStatus: CaseStatusWithAllStatus; - onStatusChanged: (status: CaseStatusWithAllStatus) => void; - hiddenStatuses?: CaseStatusWithAllStatus[]; + countClosedCases: number | null; + countInProgressCases: number | null; + countOpenCases: number | null; + hiddenStatuses?: CaseStatuses[]; + onChange: (params: { filterId: string; selectedOptionKeys: string[] }) => void; + selectedOptionKeys: string[]; } -const AllStatusBadge = () => { - return ( - - {allCaseStatus[StatusAll].label} - - ); -}; - -AllStatusBadge.displayName = 'AllStatusBadge'; +const caseStatuses = [ + { key: CaseStatuses.open, label: i18n.STATUS_OPEN }, + { key: CaseStatuses['in-progress'], label: i18n.STATUS_IN_PROGRESS }, + { key: CaseStatuses.closed, label: i18n.STATUS_CLOSED }, +]; -const StatusFilterComponent: React.FC = ({ - stats, - selectedStatus, - onStatusChanged, +export const StatusFilterComponent = ({ + countClosedCases, + countInProgressCases, + countOpenCases, hiddenStatuses = [], -}) => { - const caseStatuses = Object.keys(statuses) as CaseStatusWithAllStatus[]; - const options: Array> = [StatusAll, ...caseStatuses] - .filter((status) => !hiddenStatuses.includes(status)) - .map((status) => ({ - value: status, - inputDisplay: ( - - - {status === 'all' ? : } - - {status !== StatusAll && {` (${stats[status]})`}} - - ), - 'data-test-subj': `case-status-filter-${status}`, - })); - + onChange, + selectedOptionKeys, +}: Props) => { + const stats = useMemo( + () => ({ + [CaseStatuses.open]: countOpenCases ?? 0, + [CaseStatuses['in-progress']]: countInProgressCases ?? 0, + [CaseStatuses.closed]: countClosedCases ?? 0, + }), + [countClosedCases, countInProgressCases, countOpenCases] + ); + const options = useMemo( + () => + [...caseStatuses].filter((status) => !hiddenStatuses.includes(status.key)) as Array< + MultiSelectFilterOption + >, + [hiddenStatuses] + ); + const renderOption = (option: MultiSelectFilterOption) => { + const selectedStatus = option.key; + return ( + + + + + + + {` (${stats[selectedStatus]})`} + + ); + }; return ( - ); }; -StatusFilterComponent.displayName = 'StatusFilter'; -export const StatusFilter = memo(StatusFilterComponent); +StatusFilterComponent.displayName = 'StatusFilterComponent'; + +export const StatusFilter = React.memo(StatusFilterComponent); diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/more_filters_selectable.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/more_filters_selectable.tsx new file mode 100644 index 000000000000..e89ff2af0724 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/more_filters_selectable.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import type { MultiSelectFilterOption } from '../multi_select_filter'; +import { MultiSelectFilter } from '../multi_select_filter'; +import { MORE_FILTERS_LABEL } from '../translations'; + +export const MoreFiltersSelectable = ({ + options, + activeFilters, + onChange, +}: { + options: Array>; + activeFilters: string[]; + onChange: (params: { filterId: string; selectedOptionKeys: string[] }) => void; +}) => { + return ( + + ); +}; +MoreFiltersSelectable.displayName = 'MoreFiltersSelectable'; diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/types.ts b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/types.ts new file mode 100644 index 000000000000..368c86d545bf --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FilterOptions } from '../../../../common/ui'; + +export interface FilterConfigState { + key: string; + isActive: boolean; +} + +export type FilterChangeHandler = (params: Partial) => void; + +export interface FilterConfigRenderParams { + filterOptions: FilterOptions; +} + +export interface FilterConfig { + key: string; + label: string; + isActive: boolean; + isAvailable: boolean; + getEmptyOptions: () => Partial; + render: (params: FilterConfigRenderParams) => React.ReactNode; +} diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_custom_fields_filter_config.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_custom_fields_filter_config.tsx new file mode 100644 index 000000000000..3193b1a1cc70 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_custom_fields_filter_config.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect } from 'react'; +import type { CustomFieldTypes } from '../../../../common/types/domain'; +import { builderMap as customFieldsBuilder } from '../../custom_fields/builder'; +import { useGetCaseConfiguration } from '../../../containers/configure/use_get_case_configuration'; +import type { FilterChangeHandler, FilterConfig, FilterConfigRenderParams } from './types'; +import { MultiSelectFilter } from '../multi_select_filter'; + +export const CUSTOM_FIELD_KEY_PREFIX = 'cf_'; + +interface CustomFieldFilterOptionFactoryProps { + buttonLabel: string; + customFieldOptions: Array<{ key: string; label: string }>; + fieldKey: string; + onFilterOptionsChange: FilterChangeHandler; + type: CustomFieldTypes; +} +const customFieldFilterOptionFactory = ({ + buttonLabel, + customFieldOptions, + fieldKey, + onFilterOptionsChange, + type, +}: CustomFieldFilterOptionFactoryProps) => { + return { + key: `${CUSTOM_FIELD_KEY_PREFIX}${fieldKey}`, // this prefix is set in case custom field has the same key as a system field + isActive: false, + isAvailable: true, + label: buttonLabel, + getEmptyOptions: () => { + return { + customFields: { + [fieldKey]: { + type, + options: [], + }, + }, + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => { + const onCustomFieldChange = ({ + filterId, + selectedOptionKeys, + }: { + filterId: string; + selectedOptionKeys: string[]; + }) => { + onFilterOptionsChange({ + customFields: { + [filterId.replace(CUSTOM_FIELD_KEY_PREFIX, '')]: { + options: selectedOptionKeys, + type, + }, + }, + }); + }; + + return ( + ({ + key: option.key, + label: option.label, + }))} + selectedOptionKeys={filterOptions.customFields[fieldKey]?.options || []} + /> + ); + }, + }; +}; + +export const useCustomFieldsFilterConfig = ({ + isSelectorView, + onFilterOptionsChange, +}: { + isSelectorView: boolean; + onFilterOptionsChange: FilterChangeHandler; +}) => { + const [filterConfig, setFilterConfig] = useState([]); + + const { + data: { customFields }, + } = useGetCaseConfiguration(); + + useEffect(() => { + if (isSelectorView) return; + + const customFieldsFilterConfig: FilterConfig[] = []; + for (const { key: fieldKey, type, label: buttonLabel } of customFields ?? []) { + if (customFieldsBuilder[type]) { + const { filterOptions: customFieldOptions } = customFieldsBuilder[type](); + + if (customFieldOptions) { + customFieldsFilterConfig.push( + customFieldFilterOptionFactory({ + buttonLabel, + customFieldOptions, + fieldKey, + onFilterOptionsChange, + type, + }) + ); + } + } + } + + setFilterConfig(customFieldsFilterConfig); + }, [customFields, isSelectorView, onFilterOptionsChange]); + + return { customFieldsFilterConfig: filterConfig }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx new file mode 100644 index 000000000000..cb4de3942746 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import type { AppMockRenderer } from '../../../common/mock'; +import { createAppMockRenderer } from '../../../common/mock'; +import type { FilterConfig, FilterConfigRenderParams } from './types'; +import { getCaseConfigure } from '../../../containers/configure/api'; +import { useFilterConfig } from './use_filter_config'; + +jest.mock('../../../containers/configure/api', () => { + const originalModule = jest.requireActual('../../../containers/configure/api'); + return { + ...originalModule, + getCaseConfigure: jest.fn(), + }; +}); + +const getCaseConfigureMock = getCaseConfigure as jest.Mock; + +describe('useFilterConfig', () => { + let appMockRender: AppMockRenderer; + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + localStorage.clear(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should remove a selected option if the filter is deleted', async () => { + getCaseConfigureMock.mockReturnValue(() => { + return []; + }); + const onFilterOptionsChange = jest.fn(); + const getEmptyOptions = jest.fn().mockReturnValue({ severity: [] }); + const filters: FilterConfig[] = [ + { + key: 'severity', + label: 'Severity', + isActive: true, + isAvailable: true, + getEmptyOptions, + render: ({ filterOptions }: FilterConfigRenderParams) => null, + }, + { + key: 'tags', + label: 'Tags', + isActive: true, + isAvailable: true, + getEmptyOptions() { + return { tags: ['initialValue'] }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => null, + }, + ]; + + const { rerender } = renderHook(useFilterConfig, { + wrapper: ({ children }) => {children}, + initialProps: { + systemFilterConfig: filters, + onFilterOptionsChange, + isSelectorView: false, + }, + }); + + expect(onFilterOptionsChange).not.toHaveBeenCalled(); + rerender({ systemFilterConfig: [], onFilterOptionsChange, isSelectorView: false }); + expect(getEmptyOptions).toHaveBeenCalledTimes(1); + expect(onFilterOptionsChange).toHaveBeenCalledTimes(1); + expect(onFilterOptionsChange).toHaveBeenCalledWith({ + severity: [], + tags: ['initialValue'], + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.tsx new file mode 100644 index 000000000000..9c30264b274a --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.tsx @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useState } from 'react'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { merge } from 'lodash'; +import type { FilterOptions } from '../../../../common/ui'; +import { LOCAL_STORAGE_KEYS } from '../../../../common/constants'; +import type { FilterConfig, FilterConfigState } from './types'; +import { useCustomFieldsFilterConfig } from './use_custom_fields_filter_config'; +import { useCasesContext } from '../../cases_context/use_cases_context'; + +const mergeSystemAndCustomFieldConfigs = ({ + systemFilterConfig, + customFieldsFilterConfig, +}: { + systemFilterConfig: FilterConfig[]; + customFieldsFilterConfig: FilterConfig[]; +}) => { + const newFilterConfig = new Map( + [...systemFilterConfig, ...customFieldsFilterConfig] + .filter((filter) => filter.isAvailable) + .map((filter) => [filter.key, filter]) + ); + + return newFilterConfig; +}; + +export const useFilterConfig = ({ + isSelectorView, + onFilterOptionsChange, + systemFilterConfig, +}: { + isSelectorView: boolean; + onFilterOptionsChange: (params: Partial) => void; + systemFilterConfig: FilterConfig[]; +}) => { + const { appId } = useCasesContext(); + const { customFieldsFilterConfig } = useCustomFieldsFilterConfig({ + isSelectorView, + onFilterOptionsChange, + }); + const [filterConfigs, setFilterConfigs] = useState>( + () => new Map([...systemFilterConfig].map((filter) => [filter.key, filter])) + ); + /** + * Initially we won't save any order, it will use the default config as it is defined in the system. + * Once the user adds/removes a filter, we start saving the order and the visible state. + */ + const [activeByFilterKey, setActiveByFilterKey] = useLocalStorage( + `${appId}.${LOCAL_STORAGE_KEYS.casesTableFiltersConfig}`, + [] + ); + + /** + * This effect is needed in case a filter (mostly custom field) is removed from the settings + * but the user was filtering by it. + */ + useEffect(() => { + const newFilterConfig = mergeSystemAndCustomFieldConfigs({ + systemFilterConfig, + customFieldsFilterConfig, + }); + + const emptyOptions: Array> = []; + filterConfigs.forEach((filter) => { + if (!newFilterConfig.has(filter.key)) { + emptyOptions.push(filter.getEmptyOptions()); + } + }); + + if (emptyOptions.length > 0) { + const mergedEmptyOptions = merge({}, ...emptyOptions); + onFilterOptionsChange(mergedEmptyOptions); + } + }, [filterConfigs, systemFilterConfig, customFieldsFilterConfig, onFilterOptionsChange]); + + /** + * As custom fields are loaded by fetching an API and they might also be removed + * while using the app, we merge the system and custom fields configs on every time + * they change. + */ + useEffect(() => { + setFilterConfigs( + mergeSystemAndCustomFieldConfigs({ + systemFilterConfig, + customFieldsFilterConfig, + }) + ); + }, [systemFilterConfig, customFieldsFilterConfig]); + + const onChange = ({ selectedOptionKeys }: { filterId: string; selectedOptionKeys: string[] }) => { + const newActiveByFilterKey = [...(activeByFilterKey || [])]; + const deactivatedFilters: string[] = []; + + // for each filter in the current state, this way we keep the order + (activeByFilterKey || []).forEach(({ key, isActive: prevIsActive }) => { + const currentIndex = newActiveByFilterKey.findIndex((filter) => filter.key === key); + if (filterConfigs.has(key)) { + const isActive = selectedOptionKeys.find((optionKey) => optionKey === key); + if (isActive && !prevIsActive) { + // remove/insert to the end with isActive = true + newActiveByFilterKey.splice(currentIndex, 1); + newActiveByFilterKey.push({ key, isActive: true }); + } else if (!isActive && prevIsActive) { + // dont move, just update isActive = false + deactivatedFilters.push(key); + newActiveByFilterKey[currentIndex] = { key, isActive: false }; + } + } else { + // we might have in local storage a key of a field that don't exist anymore + newActiveByFilterKey.splice(currentIndex, 1); + } + }); + + // for each filter in the config + filterConfigs.forEach(({ key: configKey }) => { + // add it if its a new filter + if (!newActiveByFilterKey.find(({ key }) => key === configKey)) { + // first time, the current state is empty, all filters will be added + // isActive = true if the filter is in the selectedOptionKeys + const isActive = selectedOptionKeys.find((optionKey) => optionKey === configKey); + if (!isActive) { + // for system filter that is removed as first action + deactivatedFilters.push(configKey); + } + newActiveByFilterKey.push({ + key: configKey, + isActive: Boolean(isActive), + }); + } + }); + + const emptyOptions = deactivatedFilters + .filter((key) => filterConfigs.has(key)) + .map((key) => (filterConfigs.get(key) as FilterConfig).getEmptyOptions()); + + if (emptyOptions.length > 0) { + const mergedEmptyOptions = merge({}, ...emptyOptions); + onFilterOptionsChange(mergedEmptyOptions); + } + + setActiveByFilterKey(newActiveByFilterKey); + }; + + const filterConfigArray = Array.from(filterConfigs.values()); + const selectableOptions = filterConfigArray + .map(({ key, label }) => ({ + key, + label, + })) + .sort((a, b) => { + if (a.label > b.label) return 1; + if (a.label < b.label) return -1; + return a.key > b.key ? 1 : -1; + }); + const source = + activeByFilterKey && activeByFilterKey.length > 0 ? activeByFilterKey : filterConfigArray; + const activeFilters = source + .filter((filter) => filter.isActive && filterConfigs.has(filter.key)) + .map((filter) => filterConfigs.get(filter.key)) as FilterConfig[]; + const activeFilterKeys = activeFilters.map((filter) => filter.key); + + return { + activeSelectableOptionKeys: activeFilterKeys, + filters: activeFilters, + onFilterConfigChange: onChange, + selectableOptions, + }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_system_filter_config.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_system_filter_config.tsx new file mode 100644 index 000000000000..4e921e222d4d --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_system_filter_config.tsx @@ -0,0 +1,272 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect } from 'react'; + +import type { FilterOptions } from '../../../../common/ui'; +import type { CaseStatuses } from '../../../../common/types/domain'; +import { MAX_TAGS_FILTER_LENGTH, MAX_CATEGORY_FILTER_LENGTH } from '../../../../common/constants'; +import { MultiSelectFilter, mapToMultiSelectOption } from '../multi_select_filter'; +import { SolutionFilter } from '../solution_filter'; +import { StatusFilter } from '../status_filter'; +import * as i18n from '../translations'; +import { SeverityFilter } from '../severity_filter'; +import { AssigneesFilterPopover } from '../assignees_filter'; +import type { CurrentUserProfile } from '../../types'; +import type { AssigneesFilteringSelection } from '../../user_profiles/types'; +import type { FilterChangeHandler, FilterConfig, FilterConfigRenderParams } from './types'; + +interface UseFilterConfigProps { + availableSolutions: string[]; + caseAssignmentAuthorized: boolean; + categories: string[]; + countClosedCases: number | null; + countInProgressCases: number | null; + countOpenCases: number | null; + currentUserProfile: CurrentUserProfile; + handleSelectedAssignees: (newAssignees: AssigneesFilteringSelection[]) => void; + hiddenStatuses?: CaseStatuses[]; + initialFilterOptions: Partial; + isLoading: boolean; + isSelectorView?: boolean; + onFilterOptionsChange: FilterChangeHandler; + selectedAssignees: AssigneesFilteringSelection[]; + tags: string[]; +} + +export const getSystemFilterConfig = ({ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, +}: UseFilterConfigProps): FilterConfig[] => { + const onSystemFilterChange = ({ + filterId, + selectedOptionKeys, + }: { + filterId: string; + selectedOptionKeys: string[]; + }) => { + onFilterOptionsChange({ + [filterId]: selectedOptionKeys, + }); + }; + return [ + { + key: 'severity', + label: i18n.SEVERITY, + isActive: true, + isAvailable: true, + getEmptyOptions: () => { + return { + severity: initialFilterOptions.severity || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => ( + + ), + }, + { + key: 'status', + label: i18n.STATUS, + isActive: true, + isAvailable: true, + getEmptyOptions: () => { + return { + status: initialFilterOptions.status || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => ( + + ), + }, + { + key: 'assignees', + label: i18n.ASSIGNEES, + isActive: true, + isAvailable: caseAssignmentAuthorized && !isSelectorView, + getEmptyOptions: () => { + return { + assignees: initialFilterOptions.assignees || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => { + return ( + + ); + }, + }, + { + key: 'tags', + label: i18n.TAGS, + isActive: true, + isAvailable: true, + getEmptyOptions: () => { + return { + tags: initialFilterOptions.tags || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => ( + + ), + }, + { + key: 'category', + label: i18n.CATEGORIES, + isActive: true, + isAvailable: true, + getEmptyOptions: () => { + return { + category: initialFilterOptions.category || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => ( + + ), + }, + { + key: 'owner', + label: i18n.SOLUTION, + isActive: true, + isAvailable: availableSolutions.length > 1, + getEmptyOptions: () => { + return { + owner: initialFilterOptions.owner || [], + }; + }, + render: ({ filterOptions }: FilterConfigRenderParams) => ( + + ), + }, + ]; +}; + +export const useSystemFilterConfig = ({ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, +}: UseFilterConfigProps) => { + const [filterConfig, setFilterConfig] = useState(() => + getSystemFilterConfig({ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, + }) + ); + + useEffect(() => { + setFilterConfig( + getSystemFilterConfig({ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, + }) + ); + }, [ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, + ]); + + return { + systemFilterConfig: filterConfig, + }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filters.test.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filters.test.tsx index 831fa63ef7e4..a08e0650e5f2 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table_filters.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table_filters.test.tsx @@ -6,54 +6,94 @@ */ import React from 'react'; -import { screen } from '@testing-library/react'; +import { screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import { waitForComponentToUpdate } from '../../common/test_utils'; -import { CaseStatuses } from '../../../common/types/domain'; -import { - OWNER_INFO, - SECURITY_SOLUTION_OWNER, - OBSERVABILITY_OWNER, - MAX_TAGS_FILTER_LENGTH, - MAX_CATEGORY_FILTER_LENGTH, -} from '../../../common/constants'; +import { CaseStatuses, CustomFieldTypes } from '../../../common/types/domain'; +import { SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER } from '../../../common/constants'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; -import { DEFAULT_FILTER_OPTIONS } from '../../containers/use_get_cases'; +import { DEFAULT_FILTER_OPTIONS } from '../../containers/constants'; import { CasesTableFilters } from './table_filters'; import { useGetTags } from '../../containers/use_get_tags'; import { useGetCategories } from '../../containers/use_get_categories'; import { useSuggestUserProfiles } from '../../containers/user_profiles/use_suggest_user_profiles'; import { userProfiles } from '../../containers/user_profiles/api.mock'; +import { getCaseConfigure } from '../../containers/configure/api'; +import { CUSTOM_FIELD_KEY_PREFIX } from './table_filter_config/use_custom_fields_filter_config'; jest.mock('../../containers/use_get_tags'); jest.mock('../../containers/use_get_categories'); jest.mock('../../containers/user_profiles/use_suggest_user_profiles'); +jest.mock('../../containers/configure/api', () => { + const originalModule = jest.requireActual('../../containers/configure/api'); + return { + ...originalModule, + getCaseConfigure: jest.fn(), + }; +}); + +const getCaseConfigureMock = getCaseConfigure as jest.Mock; const onFilterChanged = jest.fn(); -const setFilterRefetch = jest.fn(); const props = { countClosedCases: 1234, countOpenCases: 99, countInProgressCases: 54, onFilterChanged, - initial: DEFAULT_FILTER_OPTIONS, - setFilterRefetch, + filterOptions: DEFAULT_FILTER_OPTIONS, availableSolutions: [], isLoading: false, + initialFilterOptions: DEFAULT_FILTER_OPTIONS, currentUserProfile: undefined, }; describe('CasesTableFilters ', () => { let appMockRender: AppMockRenderer; + // eslint-disable-next-line prefer-object-spread + const originalGetComputedStyle = Object.assign({}, window.getComputedStyle); + + beforeAll(() => { + // The JSDOM implementation is too slow + // Especially for dropdowns that try to position themselves + // perf issue - https://github.com/jsdom/jsdom/issues/3234 + Object.defineProperty(window, 'getComputedStyle', { + value: (el: HTMLElement) => { + /** + * This is based on the jsdom implementation of getComputedStyle + * https://github.com/jsdom/jsdom/blob/9dae17bf0ad09042cfccd82e6a9d06d3a615d9f4/lib/jsdom/browser/Window.js#L779-L820 + * + * It is missing global style parsing and will only return styles applied directly to an element. + * Will not return styles that are global or from emotion + */ + const declaration = new CSSStyleDeclaration(); + const { style } = el; + + Array.prototype.forEach.call(style, (property: string) => { + declaration.setProperty( + property, + style.getPropertyValue(property), + style.getPropertyPriority(property) + ); + }); + + return declaration; + }, + configurable: true, + writable: true, + }); + }); + + afterAll(() => { + Object.defineProperty(window, 'getComputedStyle', originalGetComputedStyle); + }); beforeEach(() => { appMockRender = createAppMockRenderer(); - jest.clearAllMocks(); (useGetTags as jest.Mock).mockReturnValue({ data: ['coke', 'pepsi'], isLoading: false }); (useGetCategories as jest.Mock).mockReturnValue({ data: ['twix', 'snickers'], @@ -62,44 +102,49 @@ describe('CasesTableFilters ', () => { (useSuggestUserProfiles as jest.Mock).mockReturnValue({ data: userProfiles, isLoading: false }); }); + afterEach(() => { + jest.clearAllMocks(); + window.localStorage.clear(); + }); + it('should render the case status filter dropdown', () => { appMockRender.render(); - expect(screen.getByTestId('case-status-filter')).toBeInTheDocument(); + expect(screen.getByTestId('options-filter-popover-button-status')).toBeInTheDocument(); }); it('should render the case severity filter dropdown', () => { appMockRender.render(); - expect(screen.getByTestId('case-severity-filter')).toBeTruthy(); + expect(screen.getByTestId('options-filter-popover-button-severity')).toBeTruthy(); }); it('should call onFilterChange when the severity filter changes', async () => { appMockRender.render(); - userEvent.click(screen.getByTestId('case-severity-filter')); + userEvent.click(screen.getByTestId('options-filter-popover-button-severity')); await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-severity-filter-high')); + userEvent.click(screen.getByTestId('options-filter-popover-item-high')); - expect(onFilterChanged).toBeCalledWith({ severity: 'high' }); + expect(onFilterChanged).toBeCalledWith({ ...DEFAULT_FILTER_OPTIONS, severity: ['high'] }); }); it('should call onFilterChange when selected tags change', async () => { appMockRender.render(); - userEvent.click(screen.getByTestId('options-filter-popover-button-Tags')); + userEvent.click(screen.getByTestId('options-filter-popover-button-tags')); await waitForEuiPopoverOpen(); userEvent.click(screen.getByTestId('options-filter-popover-item-coke')); - expect(onFilterChanged).toBeCalledWith({ tags: ['coke'] }); + expect(onFilterChanged).toBeCalledWith({ ...DEFAULT_FILTER_OPTIONS, tags: ['coke'] }); }); it('should call onFilterChange when selected category changes', async () => { appMockRender.render(); - userEvent.click(screen.getByTestId('options-filter-popover-button-Categories')); + userEvent.click(screen.getByTestId('options-filter-popover-button-category')); await waitForEuiPopoverOpen(); userEvent.click(screen.getByTestId('options-filter-popover-item-twix')); - expect(onFilterChanged).toBeCalledWith({ category: ['twix'] }); + expect(onFilterChanged).toBeCalledWith({ ...DEFAULT_FILTER_OPTIONS, category: ['twix'] }); }); it('should call onFilterChange when selected assignees change', async () => { @@ -127,7 +172,7 @@ describe('CasesTableFilters ', () => { it('should call onFilterChange when search changes', async () => { appMockRender.render(); - await userEvent.type(screen.getByTestId('search-cases'), 'My search{enter}'); + userEvent.type(screen.getByTestId('search-cases'), 'My search{enter}'); expect(onFilterChanged).toBeCalledWith({ search: 'My search' }); }); @@ -135,115 +180,27 @@ describe('CasesTableFilters ', () => { it('should call onFilterChange when changing status', async () => { appMockRender.render(); - userEvent.click(screen.getByTestId('case-status-filter')); + userEvent.click(screen.getByTestId('options-filter-popover-button-status')); await waitForEuiPopoverOpen(); - userEvent.click(screen.getByTestId('case-status-filter-closed')); - - expect(onFilterChanged).toBeCalledWith({ status: CaseStatuses.closed }); - }); + userEvent.click(screen.getByTestId('options-filter-popover-item-closed')); - it('should remove tag from selected tags when tag no longer exists', () => { - const ourProps = { - ...props, - initial: { - ...DEFAULT_FILTER_OPTIONS, - tags: ['pepsi', 'rc'], - }, - }; - - appMockRender.render(); - expect(onFilterChanged).toHaveBeenCalledWith({ tags: ['pepsi'] }); - }); - - it('should show warning message when maximum tags selected', async () => { - const newTags = Array(MAX_TAGS_FILTER_LENGTH).fill('coke'); - (useGetTags as jest.Mock).mockReturnValue({ data: newTags, isLoading: false }); - - const ourProps = { - ...props, - initial: { - ...DEFAULT_FILTER_OPTIONS, - tags: newTags, - }, - }; - - appMockRender.render(); - - userEvent.click(screen.getByTestId('options-filter-popover-button-Tags')); - - await waitForEuiPopoverOpen(); - - expect(screen.getByTestId('maximum-length-warning')).toBeInTheDocument(); - }); - - it('should show warning message when tags selection reaches maximum limit', async () => { - const newTags = Array(MAX_TAGS_FILTER_LENGTH - 1).fill('coke'); - const tags = [...newTags, 'pepsi']; - (useGetTags as jest.Mock).mockReturnValue({ data: tags, isLoading: false }); - - const ourProps = { - ...props, - initial: { - ...DEFAULT_FILTER_OPTIONS, - tags: newTags, - }, - }; - - appMockRender.render(); - - userEvent.click(screen.getByTestId('options-filter-popover-button-Tags')); - - await waitForEuiPopoverOpen(); - - userEvent.click(screen.getByTestId(`options-filter-popover-item-${tags[tags.length - 1]}`)); - - expect(screen.getByTestId('maximum-length-warning')).toBeInTheDocument(); + expect(onFilterChanged).toBeCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + status: [CaseStatuses.closed], + }); }); - it('should not show warning message when one of the tags deselected after reaching the limit', async () => { - const newTags = Array(MAX_TAGS_FILTER_LENGTH).fill('coke'); - (useGetTags as jest.Mock).mockReturnValue({ data: newTags, isLoading: false }); - - const ourProps = { - ...props, - initial: { - ...DEFAULT_FILTER_OPTIONS, - tags: newTags, - }, - }; - - appMockRender.render(); - - userEvent.click(screen.getByTestId('options-filter-popover-button-Tags')); + it('should show in progress status only when "in p" is searched in the filter', async () => { + appMockRender.render(); + userEvent.click(screen.getByTestId('options-filter-popover-button-status')); await waitForEuiPopoverOpen(); - expect(screen.getByTestId('maximum-length-warning')).toBeInTheDocument(); - - userEvent.click(screen.getAllByTestId(`options-filter-popover-item-${newTags[0]}`)[0]); - - expect(screen.queryByTestId('maximum-length-warning')).not.toBeInTheDocument(); - }); - - it('should show warning message when maximum categories selected', async () => { - const newCategories = Array(MAX_CATEGORY_FILTER_LENGTH).fill('snickers'); - (useGetCategories as jest.Mock).mockReturnValue({ data: newCategories, isLoading: false }); - - const ourProps = { - ...props, - initial: { - ...DEFAULT_FILTER_OPTIONS, - category: newCategories, - }, - }; - - appMockRender.render(); - - userEvent.click(screen.getByTestId('options-filter-popover-button-Categories')); - - await waitForEuiPopoverOpen(); + userEvent.type(screen.getByTestId('status-search-input'), 'in p'); - expect(screen.getByTestId('maximum-length-warning')).toBeInTheDocument(); + const allOptions = screen.getAllByRole('option'); + expect(allOptions).toHaveLength(1); + expect(allOptions[0]).toHaveTextContent('In progress'); }); it('should remove assignee from selected assignees when assignee no longer exists', async () => { @@ -280,97 +237,54 @@ describe('CasesTableFilters ', () => { `); }); - it('StatusFilterWrapper should have a fixed width of 180px', () => { - appMockRender.render(); - - expect(screen.getByTestId('status-filter-wrapper')).toHaveStyleRule('flex-basis', '180px', { - modifier: '&&', - }); - }); - describe('Solution filter', () => { - const securitySolution = { - id: SECURITY_SOLUTION_OWNER, - label: OWNER_INFO[SECURITY_SOLUTION_OWNER].label, - iconType: OWNER_INFO[SECURITY_SOLUTION_OWNER].iconType, - }; - const observabilitySolution = { - id: OBSERVABILITY_OWNER, - label: OWNER_INFO[OBSERVABILITY_OWNER].label, - iconType: OWNER_INFO[OBSERVABILITY_OWNER].iconType, - }; - it('shows Solution filter when provided more than 1 availableSolutions', () => { appMockRender.render( ); - expect(screen.getByTestId('solution-filter-popover-button')).toBeInTheDocument(); + expect(screen.getByTestId('options-filter-popover-button-owner')).toBeInTheDocument(); }); it('does not show Solution filter when provided less than 1 availableSolutions', () => { appMockRender.render( - + ); - expect(screen.queryByTestId('solution-filter-popover-button')).not.toBeInTheDocument(); + expect(screen.queryByTestId('options-filter-popover-button-owner')).not.toBeInTheDocument(); }); - it('should call onFilterChange when selected solution changes', async () => { + it('does not select a solution on initial render', () => { appMockRender.render( ); - userEvent.click(screen.getByTestId('solution-filter-popover-button')); - - await waitForEuiPopoverOpen(); - userEvent.click( - screen.getByTestId(`solution-filter-popover-item-${SECURITY_SOLUTION_OWNER}`) + expect(screen.getByTestId('options-filter-popover-button-owner')).not.toHaveAttribute( + 'hasActiveFilters' ); - - expect(onFilterChanged).toBeCalledWith({ owner: [SECURITY_SOLUTION_OWNER] }); }); - it('should deselect all solutions', async () => { + it('should reset the filter setting all available solutions when deactivated', async () => { appMockRender.render( ); - userEvent.click(screen.getByTestId('solution-filter-popover-button')); - + userEvent.click(screen.getByRole('button', { name: 'More' })); await waitForEuiPopoverOpen(); + userEvent.click(screen.getByRole('option', { name: 'Solution' })); - userEvent.click( - screen.getByTestId(`solution-filter-popover-item-${SECURITY_SOLUTION_OWNER}`) - ); - - expect(onFilterChanged).toBeCalledWith({ owner: [SECURITY_SOLUTION_OWNER] }); - - userEvent.click( - screen.getByTestId(`solution-filter-popover-item-${SECURITY_SOLUTION_OWNER}`) - ); - - expect(onFilterChanged).toBeCalledWith({ owner: [] }); - }); - - it('does not select a solution on initial render', () => { - appMockRender.render( - - ); - - expect(screen.getByTestId('solution-filter-popover-button')).not.toHaveAttribute( - 'hasActiveFilters' - ); + expect(onFilterChanged).toHaveBeenCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + owner: [SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER], + }); }); }); @@ -428,4 +342,519 @@ describe('CasesTableFilters ', () => { expect(onCreateCasePressed).toHaveBeenCalledWith(); }); }); + + describe('toggle type custom field filter', () => { + const customFieldKey = 'toggleKey'; + const uiCustomFieldKey = `${CUSTOM_FIELD_KEY_PREFIX}${customFieldKey}`; + + beforeEach(() => { + const previousState = [{ key: uiCustomFieldKey, isActive: true }]; + localStorage.setItem( + 'testAppId.cases.list.tableFiltersConfig', + JSON.stringify(previousState) + ); + getCaseConfigureMock.mockImplementation(() => { + return { + customFields: [{ type: 'toggle', key: customFieldKey, label: 'Toggle', required: false }], + }; + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + localStorage.clear(); + }); + + it('should render its options', async () => { + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'Toggle' })); + await waitForEuiPopoverOpen(); + + const allOptions = screen.getAllByRole('option'); + expect(allOptions).toHaveLength(2); + expect(allOptions[0]).toHaveTextContent('On'); + expect(allOptions[1]).toHaveTextContent('Off'); + }); + + it('should call onFilterChange when On option changes', async () => { + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'Toggle' })); + await waitForEuiPopoverOpen(); + + userEvent.click(screen.getByTestId('options-filter-popover-item-on')); + + expect(onFilterChanged).toBeCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + customFields: { + [customFieldKey]: { + type: 'toggle', + options: ['on'], + }, + }, + }); + }); + + it('should call onFilterChange when Off option changes', async () => { + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'Toggle' })); + await waitForEuiPopoverOpen(); + + userEvent.click(screen.getByTestId('options-filter-popover-item-off')); + + expect(onFilterChanged).toBeCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + customFields: { + [customFieldKey]: { + type: 'toggle', + options: ['off'], + }, + }, + }); + }); + + it('should call onFilterChange when second option is clicked', async () => { + const customProps = { + ...props, + filterOptions: { + ...props.filterOptions, + customFields: { + [customFieldKey]: { + type: CustomFieldTypes.TOGGLE, + options: ['on'], + }, + }, + }, + }; + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'Toggle' })); + await waitForEuiPopoverOpen(); + + userEvent.click(screen.getByTestId('options-filter-popover-item-off')); + + expect(onFilterChanged).toHaveBeenCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + customFields: { + [customFieldKey]: { + type: 'toggle', + options: ['on', 'off'], + }, + }, + }); + }); + + it('should reset the selected options when a custom field filter is deactivated', async () => { + const previousState = [{ key: uiCustomFieldKey, isActive: true }]; + localStorage.setItem( + 'testAppId.cases.list.tableFiltersConfig', + JSON.stringify(previousState) + ); + const customProps = { + ...props, + filterOptions: { + ...props.filterOptions, + customFields: { + [customFieldKey]: { + type: CustomFieldTypes.TOGGLE, + options: ['on'], + }, + }, + }, + }; + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'More' })); + userEvent.click(await screen.findByRole('option', { name: 'Toggle' })); + + expect(onFilterChanged).toHaveBeenCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + customFields: { + [customFieldKey]: { + type: CustomFieldTypes.TOGGLE, + options: [], + }, + }, + }); + }); + }); + + describe('custom filters configuration', () => { + beforeEach(() => { + getCaseConfigureMock.mockImplementation(() => { + return { + customFields: [ + { type: 'toggle', key: 'toggle', label: 'Toggle', required: false }, + { type: 'text', key: 'text', label: 'Text', required: false }, + ], + }; + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('shouldnt render the more button when in selector view', async () => { + appMockRender.render(); + expect(screen.queryByRole('button', { name: 'More' })).not.toBeInTheDocument(); + }); + + it('should render all options in the popover, including custom fields', async () => { + appMockRender.render(); + + expect(screen.getByRole('button', { name: 'More' })).toBeInTheDocument(); + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(5)); + + expect(screen.getByTestId('options-filter-popover-item-status')).toBeInTheDocument(); + expect( + screen.getByTestId(`options-filter-popover-item-${CUSTOM_FIELD_KEY_PREFIX}toggle`) + ).toBeInTheDocument(); + }); + + it('should not add text type custom fields', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitForEuiPopoverOpen(); + + expect(screen.queryByTestId('options-filter-popover-item-text')).not.toBeInTheDocument(); + }); + + it('when a filter gets activated, it should be rendered at the end of the list', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(5)); + + expect(screen.queryByRole('button', { name: 'Toggle' })).not.toBeInTheDocument(); + userEvent.click(screen.getByRole('option', { name: 'Toggle' })); + expect(screen.getByRole('button', { name: 'Toggle' })).toBeInTheDocument(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + const allFilters = within(filterBar).getAllByRole('button'); + const orderedFilterLabels = ['Severity', 'Status', 'Tags', 'Categories', 'Toggle', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + }); + + it('when a filter gets activated, it should be updated in the local storage', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(5)); + + userEvent.click(screen.getByRole('option', { name: 'Toggle' })); + const storedFilterState = localStorage.getItem('testAppId.cases.list.tableFiltersConfig'); + expect(storedFilterState).toBeTruthy(); + expect(JSON.parse(storedFilterState!)).toMatchInlineSnapshot(` + Array [ + Object { + "isActive": true, + "key": "severity", + }, + Object { + "isActive": true, + "key": "status", + }, + Object { + "isActive": true, + "key": "tags", + }, + Object { + "isActive": true, + "key": "category", + }, + Object { + "isActive": true, + "key": "cf_toggle", + }, + ] + `); + }); + + it('when a filter gets deactivated, it should be removed from the list', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(5)); + + expect(screen.getByRole('button', { name: 'Status' })).toBeInTheDocument(); + userEvent.click(screen.getByRole('option', { name: 'Status' })); + expect(screen.queryByRole('button', { name: 'Status' })).not.toBeInTheDocument(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + const allFilters = within(filterBar).getAllByRole('button'); + const orderedFilterLabels = ['Severity', 'Tags', 'Categories', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + }); + + it('should reset the selected options when a system field filter is deactivated', async () => { + const customProps = { + ...props, + filterOptions: { + ...props.filterOptions, + status: [CaseStatuses.open], + }, + }; + appMockRender.render(); + + userEvent.click(await screen.findByRole('button', { name: 'More' })); + userEvent.click(await screen.findByRole('option', { name: 'Status' })); + + expect(onFilterChanged).toHaveBeenCalledWith({ + ...DEFAULT_FILTER_OPTIONS, + status: [], + customFields: { + toggle: { + type: CustomFieldTypes.TOGGLE, + options: [], + }, + }, + }); + }); + + it('when a filter gets deactivated, it should be updated in the local storage', async () => { + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => expect(screen.getAllByRole('option')).toHaveLength(5)); + + userEvent.click(screen.getByRole('option', { name: 'Status' })); + + const storedFilterState = localStorage.getItem('testAppId.cases.list.tableFiltersConfig'); + expect(storedFilterState).toBeTruthy(); + expect(JSON.parse(storedFilterState || '')).toMatchInlineSnapshot(` + Array [ + Object { + "isActive": true, + "key": "severity", + }, + Object { + "isActive": false, + "key": "status", + }, + Object { + "isActive": true, + "key": "tags", + }, + Object { + "isActive": true, + "key": "category", + }, + Object { + "isActive": false, + "key": "cf_toggle", + }, + ] + `); + }); + + it('should recover the stored state from the local storage with the right order', async () => { + const previousState = [ + { key: `${CUSTOM_FIELD_KEY_PREFIX}toggle`, isActive: true }, + { key: 'owner', isActive: false }, + { key: 'category', isActive: false }, + { key: 'tags', isActive: true }, + { key: 'assignee', isActive: false }, + { key: 'status', isActive: false }, + { key: 'severity', isActive: true }, + ]; + localStorage.setItem( + 'testAppId.cases.list.tableFiltersConfig', + JSON.stringify(previousState) + ); + + appMockRender.render(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + let allFilters: HTMLElement[]; + await waitFor(() => { + allFilters = within(filterBar).getAllByRole('button'); + expect(allFilters).toHaveLength(4); + }); + + const orderedFilterLabels = ['Toggle', 'Tags', 'Severity', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + }); + + it('it should not render a filter that was stored but does not exist anymore', async () => { + const previousState = [ + { key: 'severity', isActive: true }, + { key: 'status', isActive: false }, + { key: 'fakeField', isActive: true }, // does not exist + { key: 'tags', isActive: true }, + { key: 'category', isActive: false }, + { key: 'owner', isActive: false }, + { key: `${CUSTOM_FIELD_KEY_PREFIX}toggle`, isActive: true }, + ]; + localStorage.setItem( + 'testAppId.cases.list.tableFiltersConfig', + JSON.stringify(previousState) + ); + + appMockRender.render(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + let allFilters: HTMLElement[]; + await waitFor(() => { + allFilters = within(filterBar).getAllByRole('button'); + expect(allFilters).toHaveLength(4); + }); + + const orderedFilterLabels = ['Severity', 'Tags', 'Toggle', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + }); + + it('should sort the labels shown in the popover (on equal label, sort by key)', async () => { + getCaseConfigureMock.mockImplementation(() => { + return { + customFields: [ + { type: 'toggle', key: 'za', label: 'ZToggle', required: false }, + { type: 'toggle', key: 'tc', label: 'Toggle', required: false }, + { type: 'toggle', key: 'ta', label: 'Toggle', required: false }, + { type: 'toggle', key: 'tb', label: 'Toggle', required: false }, + { type: 'toggle', key: 'aa', label: 'AToggle', required: false }, + ], + }; + }); + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + await waitFor(() => { + expect(screen.getAllByRole('option')).toHaveLength(9); + }); + const allOptions = screen.getAllByRole('option'); + const orderedKey = [ + `${CUSTOM_FIELD_KEY_PREFIX}aa`, + 'category', + 'severity', + 'status', + 'tags', + `${CUSTOM_FIELD_KEY_PREFIX}ta`, + `${CUSTOM_FIELD_KEY_PREFIX}tb`, + `${CUSTOM_FIELD_KEY_PREFIX}tc`, + `${CUSTOM_FIELD_KEY_PREFIX}za`, + ]; + orderedKey.forEach((key, index) => { + expect(allOptions[index].getAttribute('data-test-subj')).toBe( + `options-filter-popover-item-${key}` + ); + }); + }); + + it('when a filter is active and isnt last in the list, it should move the filter to last position after deactivating and activating', async () => { + appMockRender.render(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + let allFilters = within(filterBar).getAllByRole('button'); + let orderedFilterLabels = ['Severity', 'Status', 'Tags', 'Categories', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + + expect(screen.getByRole('button', { name: 'Status' })).toBeInTheDocument(); + userEvent.click(screen.getByRole('button', { name: 'More' })); + userEvent.click(await screen.findByRole('option', { name: 'Status' })); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + userEvent.click(await screen.findByRole('option', { name: 'Status' })); + + allFilters = within(filterBar).getAllByRole('button'); + orderedFilterLabels = ['Severity', 'Tags', 'Categories', 'Status', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + }); + + it('should avoid key collisions between custom fields and default fields', async () => { + getCaseConfigureMock.mockImplementation(() => { + return { + customFields: [ + { type: 'toggle', key: 'severity', label: 'Fake Severity', required: false }, + { type: 'toggle', key: 'status', label: 'Fake Status', required: false }, + ], + }; + }); + appMockRender.render(); + + const filterBar = screen.getByTestId('cases-table-filters-group'); + let allFilters: HTMLElement[]; + await waitFor(() => { + allFilters = within(filterBar).getAllByRole('button'); + expect(allFilters).toHaveLength(5); + }); + + const orderedFilterLabels = ['Severity', 'Status', 'Tags', 'Categories', 'More']; + orderedFilterLabels.forEach((label, index) => { + expect(allFilters[index]).toHaveTextContent(label); + }); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + let allOptions: HTMLElement[]; + await waitFor(() => { + allOptions = screen.getAllByRole('option'); + expect(allOptions).toHaveLength(6); + }); + }); + + it('should delete stored filters that dont exist anymore', async () => { + const previousState = [ + { key: 'severity', isActive: true }, + { key: 'status', isActive: false }, + { key: 'fakeField', isActive: true }, // does not exist, should be removed + { key: 'tags', isActive: true }, + { key: 'category', isActive: false }, + { key: 'owner', isActive: false }, // isnt available, should be removed + { key: `${CUSTOM_FIELD_KEY_PREFIX}toggle`, isActive: true }, + ]; + localStorage.setItem( + 'testAppId.cases.list.tableFiltersConfig', + JSON.stringify(previousState) + ); + + appMockRender.render(); + + userEvent.click(screen.getByRole('button', { name: 'More' })); + // we need any user action to trigger the filter config update + userEvent.click(await screen.findByRole('option', { name: 'Toggle' })); + + const storedFilterState = localStorage.getItem('testAppId.cases.list.tableFiltersConfig'); + // the fakeField and owner filter should be removed and toggle should update isActive + expect(JSON.parse(storedFilterState || '')).toMatchInlineSnapshot(` + Array [ + Object { + "isActive": true, + "key": "severity", + }, + Object { + "isActive": false, + "key": "status", + }, + Object { + "isActive": true, + "key": "tags", + }, + Object { + "isActive": false, + "key": "category", + }, + Object { + "isActive": false, + "key": "cf_toggle", + }, + ] + `); + }); + }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filters.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filters.tsx index a6aa406b2632..0fa7ea1e0c54 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table_filters.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table_filters.tsx @@ -5,74 +5,58 @@ * 2.0. */ -import React, { useCallback, useEffect, useState, useMemo } from 'react'; +import React, { useCallback, useState } from 'react'; import { isEqual } from 'lodash/fp'; -import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem, EuiFieldSearch, EuiFilterGroup, EuiButton } from '@elastic/eui'; - -import type { CaseStatusWithAllStatus, CaseSeverityWithAll } from '../../../common/ui/types'; -import { MAX_TAGS_FILTER_LENGTH, MAX_CATEGORY_FILTER_LENGTH } from '../../../common/constants'; -import { StatusAll } from '../../../common/ui/types'; -import { CaseStatuses } from '../../../common/types/domain'; +import { mergeWith } from 'lodash'; +import { MoreFiltersSelectable } from './table_filter_config/more_filters_selectable'; +import type { CaseStatuses } from '../../../common/types/domain'; import type { FilterOptions } from '../../containers/types'; -import { FilterPopover } from '../filter_popover'; -import { SolutionFilter } from './solution_filter'; -import { StatusFilter } from './status_filter'; import * as i18n from './translations'; -import { SeverityFilter } from './severity_filter'; import { useGetTags } from '../../containers/use_get_tags'; import { useGetCategories } from '../../containers/use_get_categories'; -import { DEFAULT_FILTER_OPTIONS } from '../../containers/use_get_cases'; -import { AssigneesFilterPopover } from './assignees_filter'; import type { CurrentUserProfile } from '../types'; import { useCasesFeatures } from '../../common/use_cases_features'; import type { AssigneesFilteringSelection } from '../user_profiles/types'; -import type { Solution } from './types'; +import { useSystemFilterConfig } from './table_filter_config/use_system_filter_config'; +import { useFilterConfig } from './table_filter_config/use_filter_config'; interface CasesTableFiltersProps { countClosedCases: number | null; countInProgressCases: number | null; countOpenCases: number | null; onFilterChanged: (filterOptions: Partial) => void; - initial: FilterOptions; - hiddenStatuses?: CaseStatusWithAllStatus[]; - availableSolutions: Solution[]; + hiddenStatuses?: CaseStatuses[]; + availableSolutions: string[]; isSelectorView?: boolean; onCreateCasePressed?: () => void; + initialFilterOptions: Partial; isLoading: boolean; currentUserProfile: CurrentUserProfile; + filterOptions: FilterOptions; } -// Fix the width of the status dropdown to prevent hiding long text items -const StatusFilterWrapper = styled(EuiFlexItem)` - && { - flex-basis: 180px; - } -`; - -const SeverityFilterWrapper = styled(EuiFlexItem)` - && { - flex-basis: 180px; +const mergeCustomizer = (objValue: string | string[], srcValue: string | string[], key: string) => { + if (Array.isArray(objValue)) { + return srcValue; } -`; +}; const CasesTableFiltersComponent = ({ countClosedCases, countOpenCases, countInProgressCases, onFilterChanged, - initial = DEFAULT_FILTER_OPTIONS, hiddenStatuses, availableSolutions, isSelectorView = false, onCreateCasePressed, + initialFilterOptions, isLoading, currentUserProfile, + filterOptions, }: CasesTableFiltersProps) => { - const [search, setSearch] = useState(initial.search); - const [selectedTags, setSelectedTags] = useState(initial.tags); - const [selectedCategories, setSelectedCategories] = useState(initial.category); - const [selectedOwner, setSelectedOwner] = useState([]); + const [search, setSearch] = useState(filterOptions.search); const [selectedAssignees, setSelectedAssignees] = useState([]); const { data: tags = [] } = useGetTags(); const { data: categories = [] } = useGetCategories(); @@ -90,42 +74,40 @@ const CasesTableFiltersComponent = ({ [selectedAssignees, onFilterChanged] ); - const handleSelectedTags = useCallback( - (newTags) => { - if (!isEqual(newTags, selectedTags)) { - setSelectedTags(newTags); - onFilterChanged({ tags: newTags }); + const onFilterOptionsChange = useCallback( + (partialFilterOptions: Partial) => { + const newFilterOptions = mergeWith({}, filterOptions, partialFilterOptions, mergeCustomizer); + if (!isEqual(newFilterOptions, filterOptions)) { + onFilterChanged(newFilterOptions); } }, - [onFilterChanged, selectedTags] + [filterOptions, onFilterChanged] ); - const handleSelectedSolution = useCallback( - (newOwner) => { - if (!isEqual(newOwner, selectedOwner)) { - setSelectedOwner(newOwner); - onFilterChanged({ owner: newOwner }); - } - }, - [onFilterChanged, selectedOwner] - ); - - const handleSelectedCategories = useCallback( - (newCategories) => { - if (!isEqual(newCategories, selectedCategories)) { - setSelectedCategories(newCategories); - onFilterChanged({ category: newCategories }); - } - }, - [onFilterChanged, selectedCategories] - ); - - useEffect(() => { - if (selectedTags.length) { - const newTags = selectedTags.filter((t) => tags.includes(t)); - handleSelectedTags(newTags); - } - }, [handleSelectedTags, selectedTags, tags]); + const { systemFilterConfig } = useSystemFilterConfig({ + availableSolutions, + caseAssignmentAuthorized, + categories, + countClosedCases, + countInProgressCases, + countOpenCases, + currentUserProfile, + handleSelectedAssignees, + hiddenStatuses, + initialFilterOptions, + isLoading, + isSelectorView, + onFilterOptionsChange, + selectedAssignees, + tags, + }); + + const { + filters: activeFilters, + selectableOptions, + activeSelectableOptionKeys, + onFilterConfigChange, + } = useFilterConfig({ systemFilterConfig, onFilterOptionsChange, isSelectorView }); const handleOnSearch = useCallback( (newSearch) => { @@ -138,30 +120,6 @@ const CasesTableFiltersComponent = ({ [onFilterChanged, search] ); - const onStatusChanged = useCallback( - (status: CaseStatusWithAllStatus) => { - onFilterChanged({ status }); - }, - [onFilterChanged] - ); - - const onSeverityChanged = useCallback( - (severity: CaseSeverityWithAll) => { - onFilterChanged({ severity }); - }, - [onFilterChanged] - ); - - const stats = useMemo( - () => ({ - [StatusAll]: null, - [CaseStatuses.open]: countOpenCases ?? 0, - [CaseStatuses['in-progress']]: countInProgressCases ?? 0, - [CaseStatuses.closed]: countClosedCases ?? 0, - }), - [countClosedCases, countInProgressCases, countOpenCases] - ); - const handleOnCreateCasePressed = useCallback(() => { if (onCreateCasePressed) { onCreateCasePressed(); @@ -169,82 +127,39 @@ const CasesTableFiltersComponent = ({ }, [onCreateCasePressed]); return ( - - - - {isSelectorView && onCreateCasePressed ? ( - - - {i18n.CREATE_CASE_TITLE} - - - ) : null} - - - - - - - - - - + + {isSelectorView && onCreateCasePressed ? ( + + + {i18n.CREATE_CASE_TITLE} + + + ) : null} + + - - {caseAssignmentAuthorized && !isSelectorView ? ( - - ) : null} - - - {availableSolutions.length > 1 && ( - + {activeFilters.map((filter) => ( + {filter.render({ filterOptions })} + ))} + {isSelectorView || ( + )} diff --git a/x-pack/plugins/cases/public/components/all_cases/translations.ts b/x-pack/plugins/cases/public/components/all_cases/translations.ts index a041fd58c3f7..f0c402d097e8 100644 --- a/x-pack/plugins/cases/public/components/all_cases/translations.ts +++ b/x-pack/plugins/cases/public/components/all_cases/translations.ts @@ -9,6 +9,11 @@ import { i18n } from '@kbn/i18n'; export * from '../../common/translations'; export * from '../user_profiles/translations'; +export { + OPEN as STATUS_OPEN, + IN_PROGRESS as STATUS_IN_PROGRESS, + CLOSED as STATUS_CLOSED, +} from '@kbn/cases-components/src/status/translations'; export const NO_CASES = i18n.translate('xpack.cases.caseTable.noCases.title', { defaultMessage: 'No cases to display', @@ -203,3 +208,20 @@ export const SEARCH_COLUMNS = i18n.translate( export const DRAG_HANDLE = i18n.translate('xpack.cases.allCasesView.columnSelectionDragHandle', { defaultMessage: 'Drag Handle', }); + +export const EMPTY_FILTER_MESSAGE = i18n.translate( + 'xpack.cases.tableFilters.useFilters.emptyMessage', + { + defaultMessage: 'No options', + } +); + +export const OPTIONS = (totalCount: number) => + i18n.translate('xpack.cases.tableFilters.useFilters.options', { + defaultMessage: '{totalCount, plural, one {# option} other {# options}}', + values: { totalCount }, + }); + +export const MORE_FILTERS_LABEL = i18n.translate('xpack.cases.tableFilters.moreFiltersLabel', { + defaultMessage: 'More', +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx index ecc9233fc327..dcec2558aad4 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx @@ -43,6 +43,7 @@ describe('useActions', () => { "align": "right", "name": "Actions", "render": [Function], + "width": "100px", }, } `); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx index ea43f79b4954..70a163bcd69a 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx @@ -244,6 +244,7 @@ export const useActions = ({ disableActions }: UseBulkActionsProps): UseBulkActi ); }, + width: '100px', } : null, }; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx index 3fddf315acdb..30de5acb0bfa 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx @@ -15,8 +15,12 @@ import { getQueryParamsLocalStorageKey, getFilterOptionsLocalStorageKey, } from './use_all_cases_state'; -import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from '../../containers/use_get_cases'; -import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../containers/constants'; +import { + DEFAULT_FILTER_OPTIONS, + DEFAULT_QUERY_PARAMS, + DEFAULT_TABLE_ACTIVE_PAGE, + DEFAULT_TABLE_LIMIT, +} from '../../containers/constants'; import { CaseStatuses } from '../../../common/types/domain'; import { SortFieldCase } from '../../containers/types'; import { stringifyToURL } from '../utils'; @@ -91,7 +95,7 @@ describe('useAllCasesQueryParams', () => { }); it('takes into account input filter options', () => { - const existingLocalStorageValues = { owner: ['foobar'], status: CaseStatuses.open }; + const existingLocalStorageValues = { owner: ['foobar'], status: [CaseStatuses.open] }; const { result } = renderHook(() => useAllCasesState(false, existingLocalStorageValues), { wrapper: ({ children }) => {children}, @@ -139,7 +143,7 @@ describe('useAllCasesQueryParams', () => { }); it('takes into account existing localStorage filter options values on first run', () => { - const existingLocalStorageValues = { severity: 'critical', status: 'open' }; + const existingLocalStorageValues = { severity: ['critical'], status: ['open'] }; localStorage.setItem( LOCALSTORAGE_FILTER_OPTIONS_KEY, @@ -153,6 +157,42 @@ describe('useAllCasesQueryParams', () => { expect(result.current.filterOptions).toMatchObject(existingLocalStorageValues); }); + it('takes into account legacy localStorage filter values as string', () => { + const existingLocalStorageValues = { severity: 'critical', status: 'open' }; + + localStorage.setItem( + LOCALSTORAGE_FILTER_OPTIONS_KEY, + JSON.stringify(existingLocalStorageValues) + ); + + const { result } = renderHook(() => useAllCasesState(), { + wrapper: ({ children }) => {children}, + }); + + expect(result.current.filterOptions).toMatchObject({ + severity: ['critical'], + status: ['open'], + }); + }); + + it('takes into account legacy localStorage filter value all', () => { + const existingLocalStorageValues = { severity: 'all', status: 'all' }; + + localStorage.setItem( + LOCALSTORAGE_FILTER_OPTIONS_KEY, + JSON.stringify(existingLocalStorageValues) + ); + + const { result } = renderHook(() => useAllCasesState(), { + wrapper: ({ children }) => {children}, + }); + + expect(result.current.filterOptions).toMatchObject({ + severity: [], + status: [], + }); + }); + it('takes into account existing url query params on first run', () => { const nonDefaultUrlParams = { page: DEFAULT_TABLE_ACTIVE_PAGE + 1, @@ -185,6 +225,24 @@ describe('useAllCasesQueryParams', () => { }); }); + it('takes into account legacy url filter option "all"', () => { + const nonDefaultUrlParams = new URLSearchParams(); + nonDefaultUrlParams.append('severity', 'all'); + nonDefaultUrlParams.append('status', 'all'); + nonDefaultUrlParams.append('status', 'open'); + nonDefaultUrlParams.append('severity', 'low'); + + mockLocation.search = stringifyToURL(nonDefaultUrlParams); + + renderHook(() => useAllCasesState(), { + wrapper: ({ children }) => {children}, + }); + + expect(useHistory().replace).toHaveBeenCalledWith({ + search: 'severity=low&status=open&page=1&perPage=10&sortField=createdAt&sortOrder=desc', + }); + }); + it('preserves other url parameters', () => { const nonDefaultUrlParams = { foo: 'bar', @@ -197,8 +255,7 @@ describe('useAllCasesQueryParams', () => { }); expect(useHistory().replace).toHaveBeenCalledWith({ - search: - 'foo=bar&page=1&perPage=10&sortField=createdAt&sortOrder=desc&severity=all&status=all', + search: 'foo=bar&page=1&perPage=10&sortField=createdAt&sortOrder=desc&severity=&status=', }); }); @@ -234,14 +291,14 @@ describe('useAllCasesQueryParams', () => { localStorage.setItem( LOCALSTORAGE_FILTER_OPTIONS_KEY, - JSON.stringify({ severity: 'low', status: 'closed' }) + JSON.stringify({ severity: ['low'], status: ['closed'] }) ); const { result } = renderHook(() => useAllCasesState(), { wrapper: ({ children }) => {children}, }); - expect(result.current.filterOptions).toMatchObject(nonDefaultUrlParams); + expect(result.current.filterOptions).toMatchObject({ severity: ['high'], status: ['open'] }); }); describe('validation', () => { @@ -266,7 +323,7 @@ describe('useAllCasesQueryParams', () => { }); expect(useHistory().replace).toHaveBeenCalledWith({ - search: 'perPage=100&page=1&sortField=createdAt&sortOrder=desc&severity=all&status=all', + search: 'perPage=100&page=1&sortField=createdAt&sortOrder=desc&severity=&status=', }); mockLocation.search = ''; @@ -292,7 +349,7 @@ describe('useAllCasesQueryParams', () => { }); expect(useHistory().replace).toHaveBeenCalledWith({ - search: 'sortOrder=desc&page=1&perPage=10&sortField=createdAt&severity=all&status=all', + search: 'sortOrder=desc&page=1&perPage=10&sortField=createdAt&severity=&status=', }); }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.tsx b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.tsx index 69572abf9455..b988cf501cdd 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.tsx @@ -11,6 +11,7 @@ import { isEqual } from 'lodash'; import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { removeLegacyValuesFromOptions, getStorableFilters } from './utils/sanitize_filter_options'; import type { FilterOptions, PartialFilterOptions, @@ -20,13 +21,15 @@ import type { ParsedUrlQueryParams, } from '../../../common/ui/types'; -import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from '../../containers/use_get_cases'; +import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from '../../containers/constants'; import { parseUrlQueryParams } from './utils'; import { stringifyToURL, parseURL } from '../utils'; import { LOCAL_STORAGE_KEYS } from '../../../common/constants'; import { SORT_ORDER_VALUES } from '../../../common/ui/types'; import { useCasesContext } from '../cases_context/use_cases_context'; import { CASES_TABLE_PERPAGE_VALUES } from './types'; +import { parseURLWithFilterOptions } from './utils/parse_url_with_filter_options'; +import { serializeUrlParams } from './utils/serialize_url_params'; export const getQueryParamsLocalStorageKey = (appId: string) => { const filteringKey = LOCAL_STORAGE_KEYS.casesQueryParams; @@ -80,6 +83,18 @@ const validateQueryParams = (queryParams: QueryParams): QueryParams => { return { ...queryParams, perPage, sortOrder }; }; +/** + * Previously, 'status' and 'severity' were represented as single options (strings). + * To maintain backward compatibility while transitioning to the new type of string[], + * we map the legacy type to the new type. + */ +const convertToFilterOptionArray = (value: string | string[] | undefined) => { + if (typeof value === 'string') { + return [value]; + } + return value; +}; + const getFilterOptions = ( filterOptions: FilterOptions, params: FilterOptions, @@ -89,26 +104,19 @@ const getFilterOptions = ( const severity = params?.severity ?? urlParams?.severity ?? - localStorageFilterOptions?.severity ?? + convertToFilterOptionArray(localStorageFilterOptions?.severity) ?? DEFAULT_FILTER_OPTIONS.severity; + const status = params?.status ?? urlParams?.status ?? - localStorageFilterOptions?.status ?? + convertToFilterOptionArray(localStorageFilterOptions?.status) ?? DEFAULT_FILTER_OPTIONS.status; return { ...filterOptions, ...params, - severity, - status, - }; -}; - -const getSupportedFilterOptions = (filterOptions: PartialFilterOptions): PartialFilterOptions => { - return { - ...(filterOptions.severity && { severity: filterOptions.severity }), - ...(filterOptions.status && { status: filterOptions.status }), + ...removeLegacyValuesFromOptions({ status, severity }), }; }; @@ -168,12 +176,11 @@ export function useAllCasesState( const newFilterOptions: FilterOptions = getFilterOptions( filterOptions, params, - parseURL(location.search), + parseURLWithFilterOptions(location.search), localStorageFilterOptions ); - const newPersistedFilterOptions: PartialFilterOptions = - getSupportedFilterOptions(newFilterOptions); + const newPersistedFilterOptions: PartialFilterOptions = getStorableFilters(newFilterOptions); const newLocalStorageFilterOptions: PartialFilterOptions = { ...localStorageFilterOptions, @@ -192,23 +199,25 @@ export function useAllCasesState( ); const updateLocation = useCallback(() => { - const parsedUrlParams = parseURL(location.search); + const parsedUrlParams = parseURLWithFilterOptions(location.search); const stateUrlParams = { ...parsedUrlParams, ...queryParams, - ...getSupportedFilterOptions(filterOptions), + ...getStorableFilters(filterOptions), page: queryParams.page.toString(), perPage: queryParams.perPage.toString(), }; if (!isEqual(parsedUrlParams, stateUrlParams)) { try { + const urlParams = serializeUrlParams({ + ...parsedUrlParams, + ...stateUrlParams, + }); + const newHistory = { ...location, - search: stringifyToURL({ ...parsedUrlParams, ...stateUrlParams } as unknown as Record< - string, - string - >), + search: stringifyToURL(urlParams), }; history.replace(newHistory); } catch { diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx index b61e7548b089..5ad01f44f6a5 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx @@ -43,7 +43,7 @@ const DEFAULT_SELECTED_COLUMNS = [ describe('useCasesColumns ', () => { let appMockRender: AppMockRenderer; const useCasesColumnsProps: GetCasesColumn = { - filterStatus: CaseStatuses.open, + filterStatus: [CaseStatuses.open], userProfiles: userProfilesMap, isSelectorView: false, selectedColumns: DEFAULT_SELECTED_COLUMNS, @@ -90,13 +90,12 @@ describe('useCasesColumns ', () => { "field": "assignees", "name": "Assignees", "render": [Function], - "width": "180px", }, Object { "field": "tags", "name": "Tags", "render": [Function], - "width": "15%", + "width": "12%", }, Object { "align": "right", @@ -110,13 +109,14 @@ describe('useCasesColumns ', () => { "field": "totalComment", "name": "Comments", "render": [Function], + "width": "90px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -139,13 +139,13 @@ describe('useCasesColumns ', () => { Object { "name": "External incident", "render": [Function], - "width": undefined, }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, + "width": "110px", }, Object { "field": "severity", @@ -158,6 +158,7 @@ describe('useCasesColumns ', () => { "align": "right", "name": "Actions", "render": [Function], + "width": "100px", }, ], "isLoadingColumns": false, @@ -190,13 +191,12 @@ describe('useCasesColumns ', () => { "field": "assignees", "name": "Assignees", "render": [Function], - "width": "180px", }, Object { "field": "tags", "name": "Tags", "render": [Function], - "width": "15%", + "width": "12%", }, Object { "align": "right", @@ -210,13 +210,14 @@ describe('useCasesColumns ', () => { "field": "totalComment", "name": "Comments", "render": [Function], + "width": "90px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -233,13 +234,13 @@ describe('useCasesColumns ', () => { Object { "name": "External incident", "render": [Function], - "width": undefined, }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, + "width": "110px", }, Object { "field": "severity", @@ -252,6 +253,7 @@ describe('useCasesColumns ', () => { "align": "right", "name": "Actions", "render": [Function], + "width": "100px", }, ], "isLoadingColumns": false, @@ -288,7 +290,7 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -336,7 +338,7 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -384,7 +386,7 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -430,7 +432,7 @@ describe('useCasesColumns ', () => { "field": "tags", "name": "Tags", "render": [Function], - "width": "15%", + "width": "12%", }, Object { "align": "right", @@ -444,13 +446,14 @@ describe('useCasesColumns ', () => { "field": "totalComment", "name": "Comments", "render": [Function], + "width": "90px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -467,13 +470,13 @@ describe('useCasesColumns ', () => { Object { "name": "External incident", "render": [Function], - "width": undefined, }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, + "width": "110px", }, Object { "field": "severity", @@ -536,7 +539,7 @@ describe('useCasesColumns ', () => { "field": "tags", "name": "Tags", "render": [Function], - "width": "15%", + "width": "12%", }, Object { "align": "right", @@ -550,13 +553,14 @@ describe('useCasesColumns ', () => { "field": "totalComment", "name": "Comments", "render": [Function], + "width": "90px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "100px", + "width": "120px", }, Object { "field": "createdAt", @@ -573,13 +577,13 @@ describe('useCasesColumns ', () => { Object { "name": "External incident", "render": [Function], - "width": undefined, }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, + "width": "110px", }, Object { "field": "severity", diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index 6ef5dcae9fe6..5abe787bf7b1 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -70,7 +70,7 @@ const renderStringField = (field: string, dataTestSubj: string) => field != null ? {field} : getEmptyCellValue(); export interface GetCasesColumn { - filterStatus: string; + filterStatus: string[]; userProfiles: Map; isSelectorView: boolean; selectedColumns: CasesColumnSelection[]; @@ -137,7 +137,6 @@ export const useCasesColumns = ({ render: (assignees: CaseUI['assignees']) => ( ), - width: '180px', }, tags: { field: casesColumnsConfig.tags.field, @@ -184,7 +183,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: '15%', + width: '12%', }, totalAlerts: { field: casesColumnsConfig.totalAlerts.field, @@ -204,6 +203,7 @@ export const useCasesColumns = ({ totalComment != null ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) : getEmptyCellValue(), + width: '90px', }, category: { field: casesColumnsConfig.category.field, @@ -217,7 +217,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: '100px', + width: '120px', }, closedAt: { field: casesColumnsConfig.closedAt.field, @@ -273,7 +273,6 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: isSelectorView ? '80px' : undefined, }, status: { field: casesColumnsConfig.status.field, @@ -286,6 +285,7 @@ export const useCasesColumns = ({ return getEmptyCellValue(); }, + width: '110px', }, severity: { field: casesColumnsConfig.severity.field, diff --git a/x-pack/plugins/cases/public/components/all_cases/utils.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utils.test.tsx deleted file mode 100644 index 5e5d91e9a592..000000000000 --- a/x-pack/plugins/cases/public/components/all_cases/utils.test.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { CasesColumnsConfiguration } from './use_cases_columns_configuration'; -import type { CasesColumnSelection } from './types'; - -import { mergeSelectedColumnsWithConfiguration, parseUrlQueryParams } from './utils'; -import { DEFAULT_QUERY_PARAMS } from '../../containers/use_get_cases'; - -const DEFAULT_STRING_QUERY_PARAMS = { - ...DEFAULT_QUERY_PARAMS, - page: String(DEFAULT_QUERY_PARAMS.page), - perPage: String(DEFAULT_QUERY_PARAMS.perPage), -}; - -describe('utils', () => { - describe('parseUrlQueryParams', () => { - it('valid input is processed correctly', () => { - expect(parseUrlQueryParams(DEFAULT_STRING_QUERY_PARAMS)).toStrictEqual(DEFAULT_QUERY_PARAMS); - }); - - it('empty string value for page/perPage is ignored', () => { - expect( - parseUrlQueryParams({ - ...DEFAULT_STRING_QUERY_PARAMS, - page: '', - perPage: '', - }) - ).toStrictEqual({ - sortField: DEFAULT_QUERY_PARAMS.sortField, - sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, - }); - }); - - it('0 value for page/perPage is ignored', () => { - expect( - parseUrlQueryParams({ - ...DEFAULT_STRING_QUERY_PARAMS, - page: '0', - perPage: '0', - }) - ).toStrictEqual({ - sortField: DEFAULT_QUERY_PARAMS.sortField, - sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, - }); - }); - - it('invalid string values for page/perPage are ignored', () => { - expect( - parseUrlQueryParams({ - ...DEFAULT_STRING_QUERY_PARAMS, - page: 'foo', - perPage: 'bar', - }) - ).toStrictEqual({ - sortField: DEFAULT_QUERY_PARAMS.sortField, - sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, - }); - }); - - it('additional URL parameters are ignored', () => { - expect( - parseUrlQueryParams({ - ...DEFAULT_STRING_QUERY_PARAMS, - foo: 'bar', - }) - ).toStrictEqual(DEFAULT_QUERY_PARAMS); - }); - }); - - describe('mergeSelectedColumnsWithConfiguration', () => { - const mockConfiguration: CasesColumnsConfiguration = { - foo: { field: 'foo', name: 'foo', canDisplay: true, isCheckedDefault: true }, - bar: { field: 'bar', name: 'bar', canDisplay: true, isCheckedDefault: true }, - }; - const mockSelectedColumns: CasesColumnSelection[] = [ - { field: 'foo', name: 'foo', isChecked: true }, - { field: 'bar', name: 'bar', isChecked: true }, - ]; - - it('does not return selectedColumns without a matching configuration', () => { - expect( - mergeSelectedColumnsWithConfiguration({ - selectedColumns: [ - ...mockSelectedColumns, - { field: 'foobar', name: 'foobar', isChecked: true }, - ], - casesColumnsConfig: mockConfiguration, - }) - ).toStrictEqual(mockSelectedColumns); - }); - - it('does not return selectedColumns with canDisplay value false in configuration', () => { - expect( - mergeSelectedColumnsWithConfiguration({ - selectedColumns: mockSelectedColumns, - casesColumnsConfig: { - ...mockConfiguration, - bar: { ...mockConfiguration.bar, canDisplay: false }, - }, - }) - ).toStrictEqual([mockSelectedColumns[0]]); - }); - - it('does not return selectedColumns without a field in the configuration', () => { - expect( - mergeSelectedColumnsWithConfiguration({ - selectedColumns: mockSelectedColumns, - casesColumnsConfig: { - ...mockConfiguration, - bar: { ...mockConfiguration.bar, field: '' }, - }, - }) - ).toStrictEqual([mockSelectedColumns[0]]); - }); - - it('result contains columns missing in the selectedColumns with isChecked false', () => { - expect( - mergeSelectedColumnsWithConfiguration({ - selectedColumns: [], - casesColumnsConfig: mockConfiguration, - }) - ).toStrictEqual([ - { field: 'foo', name: 'foo', isChecked: true }, - { field: 'bar', name: 'bar', isChecked: true }, - ]); - }); - - it('result does not include columns missing in the selectedColumns when canDisplay=false', () => { - expect( - mergeSelectedColumnsWithConfiguration({ - selectedColumns: [], - casesColumnsConfig: { - ...mockConfiguration, - foobar: { field: 'foobar', name: 'foobar', canDisplay: false, isCheckedDefault: false }, - }, - }) - ).toStrictEqual([ - { field: 'foo', name: 'foo', isChecked: true }, - { field: 'bar', name: 'bar', isChecked: true }, - ]); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/all_cases/utils.ts b/x-pack/plugins/cases/public/components/all_cases/utils.ts deleted file mode 100644 index 82ba4484701a..000000000000 --- a/x-pack/plugins/cases/public/components/all_cases/utils.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { difference } from 'lodash'; -import type { ParsedUrlQueryParams, PartialQueryParams } from '../../../common/ui/types'; -import type { CasesColumnSelection } from './types'; -import type { CasesColumnsConfiguration } from './use_cases_columns_configuration'; - -export const parseUrlQueryParams = (parsedUrlParams: ParsedUrlQueryParams): PartialQueryParams => { - const urlParams: PartialQueryParams = { - ...(parsedUrlParams.sortField && { sortField: parsedUrlParams.sortField }), - ...(parsedUrlParams.sortOrder && { sortOrder: parsedUrlParams.sortOrder }), - }; - - const intPage = parsedUrlParams.page && parseInt(parsedUrlParams.page, 10); - const intPerPage = parsedUrlParams.perPage && parseInt(parsedUrlParams.perPage, 10); - - // page=0 is deliberately ignored - if (intPage) { - urlParams.page = intPage; - } - - // perPage=0 is deliberately ignored - if (intPerPage) { - urlParams.perPage = intPerPage; - } - - return urlParams; -}; - -export const mergeSelectedColumnsWithConfiguration = ({ - selectedColumns, - casesColumnsConfig, -}: { - selectedColumns: CasesColumnSelection[]; - casesColumnsConfig: CasesColumnsConfiguration; -}): CasesColumnSelection[] => { - const result = selectedColumns.reduce((accumulator, { field, isChecked }) => { - if ( - field in casesColumnsConfig && - casesColumnsConfig[field].field !== '' && - casesColumnsConfig[field].canDisplay - ) { - accumulator.push({ - field: casesColumnsConfig[field].field, - name: casesColumnsConfig[field].name, - isChecked, - }); - } - return accumulator; - }, [] as CasesColumnSelection[]); - - // This will include any new customFields and/or changes to the case attributes - const missingColumns = difference( - Object.keys(casesColumnsConfig), - selectedColumns.map(({ field }) => field) - ); - - missingColumns.forEach((field) => { - // can be an empty string - if (casesColumnsConfig[field].field && casesColumnsConfig[field].canDisplay) { - result.push({ - field: casesColumnsConfig[field].field, - name: casesColumnsConfig[field].name, - isChecked: casesColumnsConfig[field].isCheckedDefault, - }); - } - }); - - return result; -}; diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/index.ts b/x-pack/plugins/cases/public/components/all_cases/utils/index.ts new file mode 100644 index 000000000000..bbc48210bfaa --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/index.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { difference } from 'lodash'; +import type { ParsedUrlQueryParams, PartialQueryParams } from '../../../../common/ui/types'; +import type { CasesColumnSelection } from '../types'; +import type { CasesColumnsConfiguration } from '../use_cases_columns_configuration'; + +export const parseUrlQueryParams = (parsedUrlParams: ParsedUrlQueryParams): PartialQueryParams => { + const urlParams: PartialQueryParams = { + ...(parsedUrlParams.sortField && { sortField: parsedUrlParams.sortField }), + ...(parsedUrlParams.sortOrder && { sortOrder: parsedUrlParams.sortOrder }), + }; + + const intPage = parsedUrlParams.page && parseInt(parsedUrlParams.page, 10); + const intPerPage = parsedUrlParams.perPage && parseInt(parsedUrlParams.perPage, 10); + + // page=0 is deliberately ignored + if (intPage) { + urlParams.page = intPage; + } + + // perPage=0 is deliberately ignored + if (intPerPage) { + urlParams.perPage = intPerPage; + } + + return urlParams; +}; + +export const mergeSelectedColumnsWithConfiguration = ({ + selectedColumns, + casesColumnsConfig, +}: { + selectedColumns: CasesColumnSelection[]; + casesColumnsConfig: CasesColumnsConfiguration; +}): CasesColumnSelection[] => { + const result = selectedColumns.reduce((accumulator, { field, isChecked }) => { + if ( + field in casesColumnsConfig && + casesColumnsConfig[field].field !== '' && + casesColumnsConfig[field].canDisplay + ) { + accumulator.push({ + field: casesColumnsConfig[field].field, + name: casesColumnsConfig[field].name, + isChecked, + }); + } + return accumulator; + }, [] as CasesColumnSelection[]); + + // This will include any new customFields and/or changes to the case attributes + const missingColumns = difference( + Object.keys(casesColumnsConfig), + selectedColumns.map(({ field }) => field) + ); + + missingColumns.forEach((field) => { + // can be an empty string + if (casesColumnsConfig[field].field && casesColumnsConfig[field].canDisplay) { + result.push({ + field: casesColumnsConfig[field].field, + name: casesColumnsConfig[field].name, + isChecked: casesColumnsConfig[field].isCheckedDefault, + }); + } + }); + + return result; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.test.tsx new file mode 100644 index 000000000000..2cfa14f3af32 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.test.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// This file was contributed to by generative AI + +import { parseURLWithFilterOptions } from './parse_url_with_filter_options'; + +describe('parseURLWithFilterOptions', () => { + it('parses a url with search=foo', () => { + const url = 'search=foo'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ search: 'foo' }); + }); + + it('parses a url with status=foo,bar', () => { + const url = 'status=foo,bar'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ status: ['foo', 'bar'] }); + }); + + it('parses a url with status=foo', () => { + const url = 'status=foo'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ status: ['foo'] }); + }); + + it('parses a url with status=foo&status=bar', () => { + const url = 'status=foo&status=bar'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ status: ['foo', 'bar'] }); + }); + + it('parses a url with status=foo,bar&status=baz', () => { + const url = 'status=foo,bar&status=baz'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ status: ['foo', 'bar', 'baz'] }); + }); + + it('parses a url with status=foo,bar&status=baz,qux', () => { + const url = 'status=foo,bar&status=baz,qux'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ + status: ['foo', 'bar', 'baz', 'qux'], + }); + }); + + it('parses a url with status=foo,bar&status=baz,qux&status=quux', () => { + const url = 'status=foo,bar&status=baz,qux&status=quux'; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ + status: ['foo', 'bar', 'baz', 'qux', 'quux'], + }); + }); + + it('parses a url with status=', () => { + const url = 'status='; + expect(parseURLWithFilterOptions(url)).toStrictEqual({ status: [] }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.tsx new file mode 100644 index 000000000000..6467dc99ab44 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/parse_url_with_filter_options.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DEFAULT_FILTER_OPTIONS } from '../../../containers/constants'; + +/** + * Parses filter options from a URL query string. + * + * The behavior is influenced by the predefined DEFAULT_FILTER_OPTIONS: + * - If an option is defined as an array there, it will always be returned as an array. + * - Parameters in the query string can have multiple formats: + * 1. Comma-separated values (e.g., "status=foo,bar") + * 2. A single value (e.g., "status=foo") + * 3. Repeated keys (e.g., "status=foo&status=bar") + * + * This function ensures the output respects the format indicated in DEFAULT_FILTER_OPTIONS. + */ +export const parseURLWithFilterOptions = (search: string) => { + const urlParams = new URLSearchParams(search); + + const paramKeysWithTypeArray = Object.entries(DEFAULT_FILTER_OPTIONS) + .map(([key, val]) => (Array.isArray(val) ? key : undefined)) + .filter(Boolean); + + const parsedUrlParams: { [key in string]: string[] | string } = {}; + for (const [key, value] of urlParams.entries()) { + if (paramKeysWithTypeArray.includes(key)) { + if (!parsedUrlParams[key]) parsedUrlParams[key] = []; + // only applies if the value is separated by commas (e.g., "foo,bar") + const splittedValues = value.split(',').filter(Boolean); + (parsedUrlParams[key] as string[]).push(...splittedValues); + } else { + parsedUrlParams[key] = value; + } + } + + return parsedUrlParams; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.test.tsx new file mode 100644 index 000000000000..b96dbc40fe66 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// This file was contributed to by generative AI + +import { CaseStatuses, CaseSeverity } from '../../../../common/types/domain'; +import { removeLegacyValuesFromOptions, getStorableFilters } from './sanitize_filter_options'; + +describe('removeLegacyValuesFromOptions', () => { + it('should remove legacy values from options', () => { + const options: { + status: Array; + severity: Array; + } = { + status: ['all', CaseStatuses.open, CaseStatuses['in-progress'], 'all'], + severity: ['all', CaseSeverity.LOW, 'all'], + }; + + expect(removeLegacyValuesFromOptions(options)).toEqual({ + status: ['open', 'in-progress'], + severity: ['low'], + }); + }); +}); + +describe('getStorableFilters', () => { + it('should return the filters if provided', () => { + expect( + getStorableFilters({ + status: [CaseStatuses.open, CaseStatuses['in-progress']], + severity: [CaseSeverity.LOW], + }) + ).toEqual({ + status: [CaseStatuses.open, CaseStatuses['in-progress']], + severity: [CaseSeverity.LOW], + }); + }); + + it('should return undefined if no filters are provided', () => { + expect(getStorableFilters({})).toEqual({ status: undefined, severity: undefined }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.tsx new file mode 100644 index 000000000000..498d2998a0a2 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/sanitize_filter_options.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FilterOptions } from '../../../../common/ui/types'; +import type { CaseStatuses, CaseSeverity } from '../../../../common/types/domain'; + +const notAll = (option: string) => option !== 'all'; + +/** + * In earlier versions, the options 'status' and 'severity' could have a value of 'all'. + * This function ensures such legacy values are removed from the URL parameters to maintain + * backwards compatibility. + */ +export const removeLegacyValuesFromOptions = ({ + status: legacyStatus, + severity: legacySeverity, +}: { + status: Array; + severity: Array; +}): { status: CaseStatuses[]; severity: CaseSeverity[] } => { + return { + status: legacyStatus.filter(notAll).filter(Boolean) as CaseStatuses[], + severity: legacySeverity.filter(notAll).filter(Boolean) as CaseSeverity[], + }; +}; + +export const getStorableFilters = ( + filterOptions: Partial +): { status: CaseStatuses[] | undefined; severity: CaseSeverity[] | undefined } => { + const { status, severity } = filterOptions; + + return { severity, status }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.test.tsx new file mode 100644 index 000000000000..ace5fdda934a --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.test.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { serializeUrlParams } from './serialize_url_params'; + +describe('serializeUrlParams', () => { + const commonProps = { + page: '1', + perPage: '5', + sortField: 'createdAt', + sortOrder: 'desc', + }; + + it('empty severity and status', () => { + const urlParams = { + ...commonProps, + status: [], + severity: [], + }; + + expect(serializeUrlParams(urlParams).toString()).toEqual( + 'page=1&perPage=5&sortField=createdAt&sortOrder=desc&status=&severity=' + ); + }); + + it('severity and status with one value', () => { + const urlParams = { + ...commonProps, + status: ['open'], + severity: ['low'], + }; + + expect(serializeUrlParams(urlParams).toString()).toEqual( + 'page=1&perPage=5&sortField=createdAt&sortOrder=desc&status=open&severity=low' + ); + }); + + it('severity and status with multiple values', () => { + const urlParams = { + ...commonProps, + status: ['open', 'closed'], + severity: ['low', 'high'], + }; + + expect(serializeUrlParams(urlParams).toString()).toEqual( + 'page=1&perPage=5&sortField=createdAt&sortOrder=desc&status=open&status=closed&severity=low&severity=high' + ); + }); + + it('severity and status are undefined', () => { + const urlParams = { + ...commonProps, + status: undefined, + severity: undefined, + }; + + expect(serializeUrlParams(urlParams).toString()).toEqual( + 'page=1&perPage=5&sortField=createdAt&sortOrder=desc' + ); + }); + + it('severity and status are undefined but there are more filters to serialize', () => { + const urlParams = { + status: undefined, + severity: undefined, + ...commonProps, + }; + + expect(serializeUrlParams(urlParams).toString()).toEqual( + 'page=1&perPage=5&sortField=createdAt&sortOrder=desc' + ); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.tsx new file mode 100644 index 000000000000..4b3e352b894d --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/serialize_url_params.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function serializeUrlParams(urlParams: { + [key in string]: string[] | string | undefined; +}) { + const urlSearchParams = new URLSearchParams(); + for (const [key, value] of Object.entries(urlParams)) { + if (value) { + if (Array.isArray(value)) { + if (value.length === 0) { + urlSearchParams.append(key, ''); + } else { + value.forEach((v) => urlSearchParams.append(key, v)); + } + } else { + urlSearchParams.append(key, value); + } + } + } + + return urlSearchParams; +} diff --git a/x-pack/plugins/cases/public/components/all_cases/utils/utils.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utils/utils.test.tsx new file mode 100644 index 000000000000..3fdb9f035f41 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utils/utils.test.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { parseUrlQueryParams } from '.'; +import { DEFAULT_QUERY_PARAMS } from '../../../containers/constants'; + +const DEFAULT_STRING_QUERY_PARAMS = { + ...DEFAULT_QUERY_PARAMS, + page: String(DEFAULT_QUERY_PARAMS.page), + perPage: String(DEFAULT_QUERY_PARAMS.perPage), +}; + +describe('utils', () => { + describe('parseUrlQueryParams', () => { + it('valid input is processed correctly', () => { + expect(parseUrlQueryParams(DEFAULT_STRING_QUERY_PARAMS)).toStrictEqual(DEFAULT_QUERY_PARAMS); + }); + + it('empty string value for page/perPage is ignored', () => { + expect( + parseUrlQueryParams({ + ...DEFAULT_STRING_QUERY_PARAMS, + page: '', + perPage: '', + }) + ).toStrictEqual({ + sortField: DEFAULT_QUERY_PARAMS.sortField, + sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, + }); + }); + + it('0 value for page/perPage is ignored', () => { + expect( + parseUrlQueryParams({ + ...DEFAULT_STRING_QUERY_PARAMS, + page: '0', + perPage: '0', + }) + ).toStrictEqual({ + sortField: DEFAULT_QUERY_PARAMS.sortField, + sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, + }); + }); + + it('invalid string values for page/perPage are ignored', () => { + expect( + parseUrlQueryParams({ + ...DEFAULT_STRING_QUERY_PARAMS, + page: 'foo', + perPage: 'bar', + }) + ).toStrictEqual({ + sortField: DEFAULT_QUERY_PARAMS.sortField, + sortOrder: DEFAULT_QUERY_PARAMS.sortOrder, + }); + }); + + it('additional URL parameters are ignored', () => { + expect( + parseUrlQueryParams({ + ...DEFAULT_STRING_QUERY_PARAMS, + foo: 'bar', + }) + ).toStrictEqual(DEFAULT_QUERY_PARAMS); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/app/routes.test.tsx b/x-pack/plugins/cases/public/components/app/routes.test.tsx index 53dc47de9073..9c435e2b163b 100644 --- a/x-pack/plugins/cases/public/components/app/routes.test.tsx +++ b/x-pack/plugins/cases/public/components/app/routes.test.tsx @@ -11,8 +11,8 @@ import type { MemoryRouterProps } from 'react-router'; import { render, screen, waitFor } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { + noCasesSettingsPermission, noCreateCasesPermissions, - noUpdateCasesPermissions, readCasesPermissions, TestProviders, } from '../../common/mock'; @@ -96,14 +96,14 @@ describe('Cases routes', () => { }); }); - describe('Configure cases', () => { - it('navigates to the configure cases page', () => { + describe('Cases settings', () => { + it('navigates to the cases settings page', () => { renderWithRouter(['/cases/configure']); expect(screen.getByText('Settings')).toBeInTheDocument(); }); - it('shows the no privileges page if the user does not have update privileges', () => { - renderWithRouter(['/cases/configure'], noUpdateCasesPermissions()); + it('shows the no privileges page if the user does not have settings privileges', () => { + renderWithRouter(['/cases/configure'], noCasesSettingsPermission()); expect(screen.getByText('Privileges required')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cases/public/components/app/routes.tsx b/x-pack/plugins/cases/public/components/app/routes.tsx index 7f4e35fc4ac8..27bf536b11ab 100644 --- a/x-pack/plugins/cases/public/components/app/routes.tsx +++ b/x-pack/plugins/cases/public/components/app/routes.tsx @@ -71,7 +71,7 @@ const CasesRoutesComponent: React.FC = ({ - {permissions.update ? ( + {permissions.settings ? ( ) : ( diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx index d648fc2b6fae..5d9a6836f6e5 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_activity.test.tsx @@ -134,7 +134,8 @@ const useGetCaseUsersMock = useGetCaseUsers as jest.Mock; const useOnUpdateFieldMock = useOnUpdateField as jest.Mock; const useCasesFeaturesMock = useCasesFeatures as jest.Mock; -describe('Case View Page activity tab', () => { +// FLAKY: https://github.com/elastic/kibana/issues/171575 +describe.skip('Case View Page activity tab', () => { const caseConnectors = getCaseConnectorsMockResponse(); beforeAll(() => { diff --git a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx index f9b913af4d42..b7c87f3356d3 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.test.tsx @@ -37,11 +37,21 @@ describe('CustomFieldsList', () => { it('shows CustomFieldsList correctly', async () => { appMockRender.render(); - expect(screen.getByTestId('custom-fields-list')).toBeInTheDocument(); + expect(await screen.findByTestId('custom-fields-list')).toBeInTheDocument(); - for (const field of customFieldsConfigurationMock) { - expect(screen.getByTestId(`custom-field-${field.key}-${field.type}`)).toBeInTheDocument(); - } + expect( + await screen.findByTestId( + `custom-field-${customFieldsConfigurationMock[0].key}-${customFieldsConfigurationMock[0].type}` + ) + ).toBeInTheDocument(); + expect(await screen.findByText('Text')).toBeInTheDocument(); + expect(await screen.findByText('Required')).toBeInTheDocument(); + expect( + await screen.findByTestId( + `custom-field-${customFieldsConfigurationMock[1].key}-${customFieldsConfigurationMock[1].type}` + ) + ).toBeInTheDocument(); + expect(await screen.findByText('Toggle')).toBeInTheDocument(); }); it('shows single CustomFieldsList correctly', async () => { @@ -49,16 +59,21 @@ describe('CustomFieldsList', () => { ); - const list = screen.getByTestId('custom-fields-list'); + const list = await screen.findByTestId('custom-fields-list'); expect(list).toBeInTheDocument(); expect( - screen.getByTestId( + await screen.findByTestId( `custom-field-${customFieldsConfigurationMock[0].key}-${customFieldsConfigurationMock[0].type}` ) ).toBeInTheDocument(); + expect(await screen.findByText('Text')).toBeInTheDocument(); + expect(await screen.findByText('Required')).toBeInTheDocument(); + expect( + await within(list).findByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-edit`) + ).toBeInTheDocument(); expect( - within(list).getByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-delete`) + await within(list).findByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-delete`) ).toBeInTheDocument(); }); @@ -76,10 +91,12 @@ describe('CustomFieldsList', () => { it('shows confirmation modal when deleting a field ', async () => { appMockRender.render(); - const list = screen.getByTestId('custom-fields-list'); + const list = await screen.findByTestId('custom-fields-list'); userEvent.click( - within(list).getByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-delete`) + await within(list).findByTestId( + `${customFieldsConfigurationMock[0].key}-custom-field-delete` + ) ); expect(await screen.findByTestId('confirm-delete-custom-field-modal')).toBeInTheDocument(); @@ -88,15 +105,17 @@ describe('CustomFieldsList', () => { it('calls onDeleteCustomField when confirm', async () => { appMockRender.render(); - const list = screen.getByTestId('custom-fields-list'); + const list = await screen.findByTestId('custom-fields-list'); userEvent.click( - within(list).getByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-delete`) + await within(list).findByTestId( + `${customFieldsConfigurationMock[0].key}-custom-field-delete` + ) ); expect(await screen.findByTestId('confirm-delete-custom-field-modal')).toBeInTheDocument(); - userEvent.click(screen.getByText('Delete')); + userEvent.click(await screen.findByText('Delete')); await waitFor(() => { expect(screen.queryByTestId('confirm-delete-custom-field-modal')).not.toBeInTheDocument(); @@ -109,15 +128,17 @@ describe('CustomFieldsList', () => { it('does not call onDeleteCustomField when cancel', async () => { appMockRender.render(); - const list = screen.getByTestId('custom-fields-list'); + const list = await screen.findByTestId('custom-fields-list'); userEvent.click( - within(list).getByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-delete`) + await within(list).findByTestId( + `${customFieldsConfigurationMock[0].key}-custom-field-delete` + ) ); expect(await screen.findByTestId('confirm-delete-custom-field-modal')).toBeInTheDocument(); - userEvent.click(screen.getByText('Cancel')); + userEvent.click(await screen.findByText('Cancel')); await waitFor(() => { expect(screen.queryByTestId('confirm-delete-custom-field-modal')).not.toBeInTheDocument(); @@ -134,10 +155,10 @@ describe('CustomFieldsList', () => { it('calls onEditCustomField correctly', async () => { appMockRender.render(); - const list = screen.getByTestId('custom-fields-list'); + const list = await screen.findByTestId('custom-fields-list'); userEvent.click( - within(list).getByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-edit`) + await within(list).findByTestId(`${customFieldsConfigurationMock[0].key}-custom-field-edit`) ); await waitFor(() => { diff --git a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.tsx b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.tsx index 649b0ec5d339..cfccb53e48db 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/custom_fields_list/index.tsx @@ -13,7 +13,10 @@ import { EuiSpacer, EuiText, EuiButtonIcon, + useEuiTheme, + EuiBadge, } from '@elastic/eui'; +import * as i18n from '../translations'; import type { CustomFieldTypes, CustomFieldsConfiguration } from '../../../../common/types/domain'; import { builderMap } from '../builder'; @@ -28,6 +31,7 @@ export interface Props { const CustomFieldsListComponent: React.FC = (props) => { const { customFields, onDeleteCustomField, onEditCustomField } = props; const [selectedItem, setSelectedItem] = useState(null); + const { euiTheme } = useEuiTheme(); const renderTypeLabel = (type?: CustomFieldTypes) => { const createdBuilder = type && builderMap[type]; @@ -69,7 +73,12 @@ const CustomFieldsListComponent: React.FC = (props) => {

    {customField.label}

    - {renderTypeLabel(customField.type)} + + {renderTypeLabel(customField.type)} + + {customField.required && ( + {i18n.REQUIRED} + )}
    diff --git a/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_text_field.test.ts b/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_text_field.test.ts index 2cebda62800a..3ac05ad6b867 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_text_field.test.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_text_field.test.ts @@ -20,6 +20,10 @@ describe('configureToggleCustomFieldFactory ', () => { label: 'Toggle', getEuiTableColumn: expect.any(Function), build: expect.any(Function), + filterOptions: [ + { key: 'on', label: 'On', value: true }, + { key: 'off', label: 'Off', value: false }, + ], }); }); }); diff --git a/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_toggle_field.ts b/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_toggle_field.ts index 5076cff23a21..6b82f423256c 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_toggle_field.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/toggle/configure_toggle_field.ts @@ -26,4 +26,8 @@ export const configureToggleCustomFieldFactory: CustomFieldFactory i18n.translate('xpack.cases.customFields.requiredField', { values: { fieldName }, @@ -98,3 +102,17 @@ export const DELETE_FIELD_DESCRIPTION = i18n.translate( export const DELETE = i18n.translate('xpack.cases.customFields.fieldOptions.Delete', { defaultMessage: 'Delete', }); + +export const TOGGLE_FIELD_ON_LABEL = i18n.translate( + 'xpack.cases.customFields.tableFilters.toggle.on', + { + defaultMessage: 'On', + } +); + +export const TOGGLE_FIELD_OFF_LABEL = i18n.translate( + 'xpack.cases.customFields.tableFilters.toggle.off', + { + defaultMessage: 'Off', + } +); diff --git a/x-pack/plugins/cases/public/components/custom_fields/types.ts b/x-pack/plugins/cases/public/components/custom_fields/types.ts index 6e87cbb8c6cd..856ff7e9e1c6 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/types.ts +++ b/x-pack/plugins/cases/public/components/custom_fields/types.ts @@ -33,6 +33,12 @@ export interface CustomFieldType { }>; } +export interface CustomFieldFactoryFilterOption { + key: string; + label: string; + value: boolean | null; +} + export type CustomFieldEuiTableColumn = Pick< EuiTableComputedColumnType, 'name' | 'width' | 'data-test-subj' @@ -45,6 +51,7 @@ export type CustomFieldFactory = () => { label: string; getEuiTableColumn: (params: { label: string }) => CustomFieldEuiTableColumn; build: () => CustomFieldType; + filterOptions?: CustomFieldFactoryFilterOption[]; }; export type CustomFieldBuilderMap = { diff --git a/x-pack/plugins/cases/public/components/severity/config.ts b/x-pack/plugins/cases/public/components/severity/config.ts index 6169cfb14d5b..85df4b527c1b 100644 --- a/x-pack/plugins/cases/public/components/severity/config.ts +++ b/x-pack/plugins/cases/public/components/severity/config.ts @@ -7,8 +7,7 @@ import { euiLightVars } from '@kbn/ui-theme'; import { CaseSeverity } from '../../../common/types/domain'; -import { SeverityAll } from '../../containers/types'; -import { ALL_SEVERITIES, CRITICAL, HIGH, LOW, MEDIUM } from './translations'; +import { CRITICAL, HIGH, LOW, MEDIUM } from './translations'; export const severities = { [CaseSeverity.LOW]: { @@ -28,11 +27,3 @@ export const severities = { label: CRITICAL, }, }; - -export const severitiesWithAll = { - [SeverityAll]: { - color: 'transparent', - label: ALL_SEVERITIES, - }, - ...severities, -}; diff --git a/x-pack/plugins/cases/public/components/severity/translations.ts b/x-pack/plugins/cases/public/components/severity/translations.ts index b70dbebe41d1..b5982c70ed69 100644 --- a/x-pack/plugins/cases/public/components/severity/translations.ts +++ b/x-pack/plugins/cases/public/components/severity/translations.ts @@ -26,7 +26,3 @@ export const CRITICAL = i18n.translate('xpack.cases.severity.critical', { export const SEVERITY_TITLE = i18n.translate('xpack.cases.severity.title', { defaultMessage: 'Severity', }); - -export const ALL_SEVERITIES = i18n.translate('xpack.cases.severity.all', { - defaultMessage: 'All severities', -}); diff --git a/x-pack/plugins/cases/public/components/status/config.ts b/x-pack/plugins/cases/public/components/status/config.ts index d6f66515580c..dfe8f94eb89c 100644 --- a/x-pack/plugins/cases/public/components/status/config.ts +++ b/x-pack/plugins/cases/public/components/status/config.ts @@ -5,17 +5,12 @@ * 2.0. */ import { getStatusConfiguration } from '@kbn/cases-components/src/status/config'; -import { StatusAll } from '../../../common/ui/types'; import { CaseStatuses } from '../../../common/types/domain'; import * as i18n from './translations'; -import type { AllCaseStatus, Statuses } from './types'; +import type { Statuses } from './types'; const statusConfiguration = getStatusConfiguration(); -export const allCaseStatus: AllCaseStatus = { - [StatusAll]: { color: 'hollow', label: i18n.ALL }, -}; - export const statuses: Statuses = { [CaseStatuses.open]: { ...statusConfiguration[CaseStatuses.open], diff --git a/x-pack/plugins/cases/public/components/status/types.ts b/x-pack/plugins/cases/public/components/status/types.ts index b871e51b78f6..689ffdfe7cf4 100644 --- a/x-pack/plugins/cases/public/components/status/types.ts +++ b/x-pack/plugins/cases/public/components/status/types.ts @@ -7,9 +7,6 @@ import type { EuiIconType } from '@elastic/eui/src/components/icon/icon'; import type { CaseStatuses } from '../../../common/types/domain'; -import type { StatusAllType } from '../../../common/ui/types'; - -export type AllCaseStatus = Record; export type Statuses = Record< CaseStatuses, diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.test.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.test.tsx index 868e9be03ff6..2dfd0d188f5b 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.test.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.test.tsx @@ -6,14 +6,18 @@ */ import React from 'react'; -import { mount } from 'enzyme'; +import { screen } from '@testing-library/react'; import type { CallOutProps } from './callout'; import { CallOut } from './callout'; import { CLOSED_CASE_PUSH_ERROR_ID } from './types'; -import { TestProviders } from '../../../common/mock'; +import type { AppMockRenderer } from '../../../common/mock'; +import { noCasesSettingsPermission, createAppMockRenderer } from '../../../common/mock'; +import userEvent from '@testing-library/user-event'; describe('Callout', () => { + let appMockRenderer: AppMockRenderer; + const handleButtonClick = jest.fn(); const defaultProps: CallOutProps = { id: 'md5-hex', @@ -31,50 +35,19 @@ describe('Callout', () => { beforeEach(() => { jest.clearAllMocks(); + appMockRenderer = createAppMockRenderer(); }); it('It renders the callout', () => { - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="callout-onclick-md5-hex"]`).exists()).toBeTruthy(); + appMockRenderer.render(); + expect(screen.getByTestId('case-callout-md5-hex')).toBeInTheDocument(); + expect(screen.getByTestId('callout-messages-md5-hex')).toBeInTheDocument(); + expect(screen.getByTestId('callout-onclick-md5-hex')).toBeInTheDocument(); }); it('does not shows any messages when the list is empty', () => { - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeFalsy(); - }); - - it('transform the button color correctly - primary', () => { - const wrapper = mount(); - const className = - wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ?? - ''; - expect(className.includes('primary')).toBeTruthy(); - }); - - it('transform the button color correctly - success', () => { - const wrapper = mount(); - const className = - wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ?? - ''; - expect(className.includes('success')).toBeTruthy(); - }); - - it('transform the button color correctly - warning', () => { - const wrapper = mount(); - const className = - wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ?? - ''; - expect(className.includes('warning')).toBeTruthy(); - }); - - it('transform the button color correctly - danger', () => { - const wrapper = mount(); - const className = - wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).first().prop('className') ?? - ''; - expect(className.includes('danger')).toBeTruthy(); + appMockRenderer.render(); + expect(screen.queryByTestId('callout-messages-md5-hex')).not.toBeInTheDocument(); }); it('does not show the button when case is closed error is present', () => { @@ -89,15 +62,9 @@ describe('Callout', () => { ], }; - const wrapper = mount( - - - - ); + appMockRenderer.render(); - expect(wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).exists()).toEqual( - false - ); + expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument(); }); it('does not show the button when license error is present', () => { @@ -106,22 +73,27 @@ describe('Callout', () => { hasLicenseError: true, }; - const wrapper = mount( - - - - ); + appMockRenderer.render(); + + expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument(); + }); + + it('does not show the button with no settings permissions', () => { + appMockRenderer = createAppMockRenderer({ permissions: noCasesSettingsPermission() }); - expect(wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).exists()).toEqual( - false - ); + appMockRenderer.render(); + + expect(screen.queryByTestId('callout-onclick-md5-hex')).not.toBeInTheDocument(); }); // use this for storage if we ever want to bring that back it('onClick passes id and type', () => { - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-onclick-md5-hex"]`).exists()).toBeTruthy(); - wrapper.find(`button[data-test-subj="callout-onclick-md5-hex"]`).simulate('click'); + appMockRenderer.render(); + + expect(screen.getByTestId('callout-onclick-md5-hex')).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('callout-onclick-md5-hex')); + expect(handleButtonClick.mock.calls[0][1]).toEqual('md5-hex'); expect(handleButtonClick.mock.calls[0][2]).toEqual('primary'); }); diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx index ffd19f836625..c94fbb826df4 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx @@ -12,6 +12,7 @@ import React, { memo, useCallback, useMemo } from 'react'; import type { ErrorMessage } from './types'; import { CLOSED_CASE_PUSH_ERROR_ID } from './types'; import * as i18n from './translations'; +import { useCasesContext } from '../../cases_context/use_cases_context'; export interface CallOutProps { handleButtonClick: ( @@ -32,6 +33,8 @@ const CallOutComponent = ({ type, hasLicenseError, }: CallOutProps) => { + const { permissions } = useCasesContext(); + const handleCallOut = useCallback( (e) => handleButtonClick(e, id, type), [handleButtonClick, id, type] @@ -57,7 +60,7 @@ const CallOutComponent = ({ size="s" > - {!isCaseClosed && !hasLicenseError && ( + {!isCaseClosed && !hasLicenseError && permissions.settings && ( { window.sessionStorage.removeItem(key); }; -export const stringifyToURL = (parsedParams: Record) => +export const stringifyToURL = (parsedParams: Record | URLSearchParams) => new URLSearchParams(parsedParams).toString(); export const parseURL = (queryString: string) => Object.fromEntries(new URLSearchParams(queryString)); diff --git a/x-pack/plugins/cases/public/containers/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/__mocks__/api.ts index 68484fb98ee0..9d99f658e9da 100644 --- a/x-pack/plugins/cases/public/containers/__mocks__/api.ts +++ b/x-pack/plugins/cases/public/containers/__mocks__/api.ts @@ -38,7 +38,6 @@ import type { ResolvedCase, CaseUserActionsStats, } from '../../../common/ui/types'; -import { SeverityAll } from '../../../common/ui/types'; import type { SingleCaseMetricsResponse, CasePostRequest, @@ -87,15 +86,16 @@ export const getCaseUserActionsStats = async ( export const getCases = async ({ filterOptions = { - severity: SeverityAll, + severity: [], search: '', searchFields: [], assignees: [], reporters: [], - status: CaseStatuses.open, + status: [CaseStatuses.open], tags: [], owner: [], category: [], + customFields: {}, }, queryParams = { page: 1, diff --git a/x-pack/plugins/cases/public/containers/api.test.tsx b/x-pack/plugins/cases/public/containers/api.test.tsx index aeec96524c6e..6f42c31186dc 100644 --- a/x-pack/plugins/cases/public/containers/api.test.tsx +++ b/x-pack/plugins/cases/public/containers/api.test.tsx @@ -66,7 +66,7 @@ import { basicFileMock, } from './mock'; -import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases'; +import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './constants'; import { getCasesStatus } from '../api'; import { getCaseConnectorsMockResponse } from '../common/mock/connectors'; import { set } from '@kbn/safer-lodash-set'; @@ -77,6 +77,7 @@ import { CaseStatuses, ConnectorTypes, AttachmentType, + CustomFieldTypes, } from '../../common/types/domain'; const abortCtrl = new AbortController(); const mockKibanaServices = KibanaServices.get as jest.Mock; @@ -212,12 +213,12 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -229,29 +230,30 @@ describe('Cases API', () => { assignees: ['123'], reporters: [{ username: 'username', full_name: null, email: null }], tags, - status: CaseStatuses.open, - severity: CaseSeverity.HIGH, + status: [CaseStatuses.open], + severity: [CaseSeverity.HIGH], search: 'hello', owner: [SECURITY_SOLUTION_OWNER], category: [], + customFields: {}, }, queryParams: DEFAULT_QUERY_PARAMS, signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + status: [CaseStatuses.open], + severity: [CaseSeverity.HIGH], assignees: ['123'], reporters: ['username'], tags: ['coke', 'pepsi'], search: 'hello', searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - status: CaseStatuses.open, - severity: CaseSeverity.HIGH, owner: [SECURITY_SOLUTION_OWNER], - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -260,39 +262,39 @@ describe('Cases API', () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, - severity: CaseSeverity.HIGH, + severity: [CaseSeverity.HIGH], }, queryParams: DEFAULT_QUERY_PARAMS, signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + severity: [CaseSeverity.HIGH], searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - severity: CaseSeverity.HIGH, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); - it('should not send the severity field with "all" severity value', async () => { + it('should not send the severity field if empty', async () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, - severity: 'all', + severity: [], }, queryParams: DEFAULT_QUERY_PARAMS, signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -301,39 +303,39 @@ describe('Cases API', () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, - status: CaseStatuses.open, + status: [CaseStatuses.open], }, queryParams: DEFAULT_QUERY_PARAMS, signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + status: [CaseStatuses.open], searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - status: CaseStatuses.open, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); - it('should not send the severity field with "all" status value', async () => { + it('should not send the status field if empty', async () => { await getCases({ filterOptions: { ...DEFAULT_FILTER_OPTIONS, - status: 'all', + status: [], }, queryParams: DEFAULT_QUERY_PARAMS, signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -348,12 +350,12 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -368,13 +370,13 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, - searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ assignees: 'none', - }, + searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -389,13 +391,13 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, - searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ assignees: ['none', '123'], - }, + searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -409,7 +411,7 @@ describe('Cases API', () => { assignees: ['123'], reporters: [{ username: undefined, full_name: undefined, email: undefined }], tags: weirdTags, - status: CaseStatuses.open, + status: [CaseStatuses.open], search: 'hello', owner: [SECURITY_SOLUTION_OWNER], }, @@ -417,18 +419,18 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + status: [CaseStatuses.open], assignees: ['123'], reporters: [], tags: ['(', '"double"'], search: 'hello', searchFields: DEFAULT_FILTER_OPTIONS.searchFields, - status: CaseStatuses.open, owner: [SECURITY_SOLUTION_OWNER], - }, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); @@ -453,12 +455,74 @@ describe('Cases API', () => { signal: abortCtrl.signal, }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + searchFields: DEFAULT_FILTER_OPTIONS.searchFields, ...DEFAULT_QUERY_PARAMS, + }), + signal: abortCtrl.signal, + }); + }); + + it('should send custom fields', async () => { + await getCases({ + filterOptions: { + ...DEFAULT_FILTER_OPTIONS, + customFields: { + activeCustomFieldKey: { + type: CustomFieldTypes.TOGGLE, + options: ['on'], + }, + inactiveCustomFieldKey: { + type: CustomFieldTypes.TOGGLE, + options: ['off'], + }, + emptyCustomFieldKey: { + type: CustomFieldTypes.TOGGLE, + options: [], + }, + }, + }, + queryParams: DEFAULT_QUERY_PARAMS, + signal: abortCtrl.signal, + }); + + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + customFields: { + activeCustomFieldKey: [true], + inactiveCustomFieldKey: [false], + }, + ...DEFAULT_QUERY_PARAMS, + }), + signal: abortCtrl.signal, + }); + }); + + it('should not send empty custom fields', async () => { + await getCases({ + filterOptions: { + ...DEFAULT_FILTER_OPTIONS, + customFields: { + emptyCustomFieldKey: { + type: CustomFieldTypes.TOGGLE, + options: [], + }, + }, }, + queryParams: DEFAULT_QUERY_PARAMS, + signal: abortCtrl.signal, + }); + + expect(fetchMock).toHaveBeenCalledWith(`${CASES_INTERNAL_URL}/_search`, { + method: 'POST', + body: JSON.stringify({ + searchFields: DEFAULT_FILTER_OPTIONS.searchFields, + ...DEFAULT_QUERY_PARAMS, + }), signal: abortCtrl.signal, }); }); diff --git a/x-pack/plugins/cases/public/containers/api.ts b/x-pack/plugins/cases/public/containers/api.ts index ae65aaad6c83..c15b41cb458a 100644 --- a/x-pack/plugins/cases/public/containers/api.ts +++ b/x-pack/plugins/cases/public/containers/api.ts @@ -33,8 +33,9 @@ import type { CaseUsers, CasesFindResponseUI, CasesUI, + FilterOptions, } from '../../common/ui/types'; -import { SeverityAll, SortFieldCase, StatusAll } from '../../common/ui/types'; +import { SortFieldCase } from '../../common/ui/types'; import { getCaseCommentsUrl, getCasesDeleteFileAttachmentsUrl, @@ -53,6 +54,7 @@ import { CASES_URL, INTERNAL_BULK_CREATE_ATTACHMENTS_URL, INTERNAL_GET_CASE_CATEGORIES_URL, + CASES_INTERNAL_URL, } from '../../common/constants'; import { getAllConnectorTypesUrl } from '../../common/utils/connectors_api'; @@ -85,6 +87,7 @@ import { constructAssigneesFilter, constructReportersFilter, decodeCaseUserActionStatsResponse, + constructCustomFieldsFilter, } from './utils'; import { decodeCasesFindResponse } from '../api/decoders'; @@ -234,17 +237,31 @@ export const getCaseUserActionsStats = async ( return convertToCamelCase(decodeCaseUserActionStatsResponse(response)); }; +const removeOptionFromFilter = ({ + filterKey, + filterOptions, + optionToBeRemoved, +}: { + filterKey: keyof FilterOptions; + filterOptions: string[]; + optionToBeRemoved: string; +}) => { + const resultingFilterOptions = filterOptions.filter((option) => option !== optionToBeRemoved); + return resultingFilterOptions.length === 0 ? {} : { [filterKey]: resultingFilterOptions }; +}; + export const getCases = async ({ filterOptions = { search: '', searchFields: [], - severity: SeverityAll, + severity: [], assignees: [], reporters: [], - status: StatusAll, + status: [], tags: [], owner: [], category: [], + customFields: {}, }, queryParams = { page: 1, @@ -254,9 +271,17 @@ export const getCases = async ({ }, signal, }: FetchCasesProps): Promise => { - const query = { - ...(filterOptions.status !== StatusAll ? { status: filterOptions.status } : {}), - ...(filterOptions.severity !== SeverityAll ? { severity: filterOptions.severity } : {}), + const body = { + ...removeOptionFromFilter({ + filterKey: 'status', + filterOptions: filterOptions.status, + optionToBeRemoved: 'all', + }), + ...removeOptionFromFilter({ + filterKey: 'severity', + filterOptions: filterOptions.severity, + optionToBeRemoved: 'all', + }), ...constructAssigneesFilter(filterOptions.assignees), ...constructReportersFilter(filterOptions.reporters), ...(filterOptions.tags.length > 0 ? { tags: filterOptions.tags } : {}), @@ -264,14 +289,18 @@ export const getCases = async ({ ...(filterOptions.searchFields.length > 0 ? { searchFields: filterOptions.searchFields } : {}), ...(filterOptions.owner.length > 0 ? { owner: filterOptions.owner } : {}), ...(filterOptions.category.length > 0 ? { category: filterOptions.category } : {}), + ...constructCustomFieldsFilter(filterOptions.customFields), ...queryParams, }; - const response = await KibanaServices.get().http.fetch(`${CASES_URL}/_find`, { - method: 'GET', - query, - signal, - }); + const response = await KibanaServices.get().http.fetch( + `${CASES_INTERNAL_URL}/_search`, + { + method: 'POST', + body: JSON.stringify(body), + signal, + } + ); return convertAllCasesToCamel(decodeCasesFindResponse(response)); }; diff --git a/x-pack/plugins/cases/public/containers/constants.ts b/x-pack/plugins/cases/public/containers/constants.ts index 148885362a0c..224ea2c8bd04 100644 --- a/x-pack/plugins/cases/public/containers/constants.ts +++ b/x-pack/plugins/cases/public/containers/constants.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { SingleCaseMetricsFeature } from './types'; +import type { FilterOptions, QueryParams, SingleCaseMetricsFeature } from './types'; +import { SortFieldCase } from './types'; export const DEFAULT_TABLE_ACTIVE_PAGE = 1; export const DEFAULT_TABLE_LIMIT = 10; @@ -62,3 +63,25 @@ export const casesMutationsKeys = { bulkCreateAttachments: ['bulk-create-attachments'] as const, persistCaseConfiguration: ['persist-case-configuration'] as const, }; + +const DEFAULT_SEARCH_FIELDS = ['title', 'description']; + +export const DEFAULT_FILTER_OPTIONS: FilterOptions = { + search: '', + searchFields: DEFAULT_SEARCH_FIELDS, + severity: [], + assignees: [], + reporters: [], + status: [], + tags: [], + owner: [], + category: [], + customFields: {}, +}; + +export const DEFAULT_QUERY_PARAMS: QueryParams = { + page: DEFAULT_TABLE_ACTIVE_PAGE, + perPage: DEFAULT_TABLE_LIMIT, + sortField: SortFieldCase.createdAt, + sortOrder: 'desc', +}; diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx index 39cedf782857..cd63e741327b 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx @@ -6,7 +6,8 @@ */ import { renderHook } from '@testing-library/react-hooks'; -import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS, useGetCases } from './use_get_cases'; +import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './constants'; +import { useGetCases } from './use_get_cases'; import * as api from './api'; import type { AppMockRenderer } from '../common/mock'; import { createAppMockRenderer } from '../common/mock'; diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.tsx index df1bb4cf1f40..c182cfbfe3cc 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.tsx @@ -7,35 +7,13 @@ import type { UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; -import { casesQueriesKeys, DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from './constants'; +import { casesQueriesKeys, DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './constants'; import type { CasesFindResponseUI, FilterOptions, QueryParams } from './types'; -import { SortFieldCase, StatusAll, SeverityAll } from './types'; import { useToasts } from '../common/lib/kibana'; import * as i18n from './translations'; import { getCases } from './api'; import type { ServerError } from '../types'; -const DEFAULT_SEARCH_FIELDS = ['title', 'description']; - -export const DEFAULT_FILTER_OPTIONS: FilterOptions = { - search: '', - searchFields: DEFAULT_SEARCH_FIELDS, - severity: SeverityAll, - assignees: [], - reporters: [], - status: StatusAll, - tags: [], - owner: [], - category: [], -}; - -export const DEFAULT_QUERY_PARAMS: QueryParams = { - page: DEFAULT_TABLE_ACTIVE_PAGE, - perPage: DEFAULT_TABLE_LIMIT, - sortField: SortFieldCase.createdAt, - sortOrder: 'desc', -}; - export const initialData: CasesFindResponseUI = { cases: [], countClosedCases: 0, diff --git a/x-pack/plugins/cases/public/containers/utils.test.ts b/x-pack/plugins/cases/public/containers/utils.test.ts index b7a0b17ec5ff..16dd6f25f3d2 100644 --- a/x-pack/plugins/cases/public/containers/utils.test.ts +++ b/x-pack/plugins/cases/public/containers/utils.test.ts @@ -11,9 +11,11 @@ import { createUpdateSuccessToaster, constructAssigneesFilter, constructReportersFilter, + constructCustomFieldsFilter, } from './utils'; import type { CaseUI } from './types'; +import { CustomFieldTypes } from '../../common/types/domain'; const caseBeforeUpdate = { comments: [ @@ -186,4 +188,39 @@ describe('utils', () => { ).toEqual({ reporters: ['test', '123'] }); }); }); + + describe('constructCustomFieldsFilter', () => { + it('returns an empty object if the customFields is empty', () => { + expect(constructCustomFieldsFilter({})).toEqual({}); + }); + + it('returns the customFields correctly', () => { + expect( + constructCustomFieldsFilter({ + '957846f4-a792-45a2-bc9a-c028973dfdde': { + type: CustomFieldTypes.TOGGLE, + options: ['on'], + }, + 'dbeb8e9c-240b-4adb-b83e-e645e86c07ed': { + type: CustomFieldTypes.TOGGLE, + options: ['off'], + }, + 'c1f0c0a0-2aaf-11ec-8d3d-0242ac130003': { + type: CustomFieldTypes.TOGGLE, + options: [], + }, + 'e0e8c50a-8d65-4f00-b6f0-d8a131fd34b4': { + type: CustomFieldTypes.TOGGLE, + options: ['on', 'off'], + }, + }) + ).toEqual({ + customFields: { + '957846f4-a792-45a2-bc9a-c028973dfdde': [true], + 'dbeb8e9c-240b-4adb-b83e-e645e86c07ed': [false], + 'e0e8c50a-8d65-4f00-b6f0-d8a131fd34b4': [true, false], + }, + }); + }); + }); }); diff --git a/x-pack/plugins/cases/public/containers/utils.ts b/x-pack/plugins/cases/public/containers/utils.ts index c5713d8f1fac..50f8524dbe78 100644 --- a/x-pack/plugins/cases/public/containers/utils.ts +++ b/x-pack/plugins/cases/public/containers/utils.ts @@ -11,6 +11,7 @@ import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import type { ToastInputFields } from '@kbn/core/public'; +import { builderMap as customFieldsBuilder } from '../components/custom_fields/builder'; import { AttachmentType, CaseRt, @@ -42,6 +43,7 @@ import { NO_ASSIGNEES_FILTERING_KEYWORD } from '../../common/constants'; import { throwErrors } from '../../common/api'; import type { CaseUI, FilterOptions, UpdateByKey } from './types'; import * as i18n from './translations'; +import type { CustomFieldFactoryFilterOption } from '../components/custom_fields/types'; export const getTypedPayload = (a: unknown): T => a as T; @@ -170,3 +172,40 @@ export const constructReportersFilter = (reporters: User[]) => { } : {}; }; + +export const constructCustomFieldsFilter = ( + optionKeysByCustomFieldKey: FilterOptions['customFields'] +) => { + if (!optionKeysByCustomFieldKey || Object.keys(optionKeysByCustomFieldKey).length === 0) { + return {}; + } + + const valuesByCustomFieldKey: { + [key in string]: Array; + } = {}; + + for (const [customFieldKey, customField] of Object.entries(optionKeysByCustomFieldKey)) { + const { type, options: selectedOptions } = customField; + if (customFieldsBuilder[type]) { + const { filterOptions: customFieldFilterOptionsConfig = [] } = customFieldsBuilder[type](); + const values = selectedOptions + .map((selectedOption) => { + const filterOptionConfig = customFieldFilterOptionsConfig.find( + (filterOption) => filterOption.key === selectedOption + ); + return filterOptionConfig ? filterOptionConfig.value : undefined; + }) + .filter((option) => option !== undefined) as Array; + + if (values.length > 0) { + valuesByCustomFieldKey[customFieldKey] = values; + } + } + } + + return Object.keys(valuesByCustomFieldKey).length + ? { + customFields: valuesByCustomFieldKey, + } + : {}; +}; diff --git a/x-pack/plugins/cases/public/mocks.ts b/x-pack/plugins/cases/public/mocks.ts index e429e6461e72..237d7150aec6 100644 --- a/x-pack/plugins/cases/public/mocks.ts +++ b/x-pack/plugins/cases/public/mocks.ts @@ -46,6 +46,8 @@ const helpersMock: jest.Mocked = { update: false, delete: false, push: false, + connectors: false, + settings: false, }), getRuleIdFromEvent: jest.fn(), groupAlertsByRule: jest.fn(), diff --git a/x-pack/plugins/cases/server/client/utils.test.ts b/x-pack/plugins/cases/server/client/utils.test.ts index 8fb54f907927..8f9e8648a126 100644 --- a/x-pack/plugins/cases/server/client/utils.test.ts +++ b/x-pack/plugins/cases/server/client/utils.test.ts @@ -514,6 +514,50 @@ describe('utils', () => { `); }); + it('should create a filter for multiple status values', () => { + const status = [CaseStatuses.open, CaseStatuses['in-progress']]; + expect(constructQueryOptions({ status }).filter).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.status", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "0", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.status", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "10", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + it.each([ [CaseSeverity.LOW, CasePersistedSeverity.LOW], [CaseSeverity.MEDIUM, CasePersistedSeverity.MEDIUM], @@ -540,6 +584,50 @@ describe('utils', () => { `); }); + it('should create a filter for multiple severity values', () => { + const severity = [CaseSeverity.MEDIUM, CaseSeverity.CRITICAL]; + expect(constructQueryOptions({ severity }).filter).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.severity", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "10", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.severity", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "30", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + it('creates a filter for the time range', () => { expect(constructQueryOptions({ from: 'now-1M', to: 'now' }).filter).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/cases/server/client/utils.ts b/x-pack/plugins/cases/server/client/utils.ts index d0911758ca58..24cbce31b32f 100644 --- a/x-pack/plugins/cases/server/client/utils.ts +++ b/x-pack/plugins/cases/server/client/utils.ts @@ -154,14 +154,29 @@ export const getAlertIds = (comment: AttachmentRequest): string[] => { return []; }; -const addStatusFilter = (status: CaseStatuses): KueryNode => { +const addStatusFilter = (status: CaseStatuses | CaseStatuses[]): KueryNode | undefined => { + if (Array.isArray(status)) { + return buildFilter({ + filters: status.map((_status) => `${STATUS_EXTERNAL_TO_ESMODEL[_status]}`), + field: 'status', + operator: 'or', + }); + } + return nodeBuilder.is( `${CASE_SAVED_OBJECT}.attributes.status`, `${STATUS_EXTERNAL_TO_ESMODEL[status]}` ); }; -const addSeverityFilter = (severity: CaseSeverity): KueryNode => { +const addSeverityFilter = (severity: CaseSeverity | CaseSeverity[]): KueryNode | undefined => { + if (Array.isArray(severity)) { + return buildFilter({ + filters: severity.map((_severity) => `${SEVERITY_EXTERNAL_TO_ESMODEL[_severity]}`), + field: 'severity', + operator: 'or', + }); + } return nodeBuilder.is( `${CASE_SAVED_OBJECT}.attributes.severity`, `${SEVERITY_EXTERNAL_TO_ESMODEL[severity]}` diff --git a/x-pack/plugins/cases/server/features.ts b/x-pack/plugins/cases/server/features.ts index b44c3589ecd0..62276ad4fcc3 100644 --- a/x-pack/plugins/cases/server/features.ts +++ b/x-pack/plugins/cases/server/features.ts @@ -100,6 +100,33 @@ export const getCasesKibanaFeature = (): KibanaFeatureConfig => { }, ], }, + { + name: i18n.translate('xpack.cases.features.casesSettingsSubFeatureName', { + defaultMessage: 'Case Settings', + }), + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cases_settings', + name: i18n.translate('xpack.cases.features.casesSettingsSubFeatureDetails', { + defaultMessage: 'Edit Case Settings', + }), + includeIn: 'all', + savedObject: { + all: [...filesSavedObjectTypes], + read: [...filesSavedObjectTypes], + }, + cases: { + settings: [APP_ID], + }, + ui: capabilities.settings, + }, + ], + }, + ], + }, ], }; }; diff --git a/x-pack/plugins/cases/server/services/user_profiles/index.ts b/x-pack/plugins/cases/server/services/user_profiles/index.ts index ab8a9d8cf7d5..7808cf74b011 100644 --- a/x-pack/plugins/cases/server/services/user_profiles/index.ts +++ b/x-pack/plugins/cases/server/services/user_profiles/index.ts @@ -151,9 +151,7 @@ export class UserProfileService { private static buildRequiredPrivileges(owners: string[], security: SecurityPluginStart) { const privileges: string[] = []; for (const owner of owners) { - for (const operation of [Operations.updateCase.name, Operations.getCase.name]) { - privileges.push(security.authz.actions.cases.get(owner, operation)); - } + privileges.push(security.authz.actions.cases.get(owner, Operations.getCase.name)); } return privileges; diff --git a/x-pack/plugins/cloud/public/plugin.test.ts b/x-pack/plugins/cloud/public/plugin.test.ts index 3709dd7cfcb9..99e6f97946cc 100644 --- a/x-pack/plugins/cloud/public/plugin.test.ts +++ b/x-pack/plugins/cloud/public/plugin.test.ts @@ -197,8 +197,10 @@ describe('Cloud Plugin', () => { return { coreSetup, plugin }; }; - it('registers help support URL', async () => { - const { plugin } = startPlugin(); + it('registers help support URL: default', async () => { + const { plugin } = startPlugin({ + id: undefined, + }); const coreStart = coreMock.createStart(); plugin.start(coreStart); @@ -211,6 +213,41 @@ describe('Cloud Plugin', () => { `); }); + it('registers help support URL: serverless projects', async () => { + const { plugin } = startPlugin({ + id: 'my-awesome-project-id', + serverless: { + project_id: 'my-awesome-serverless-project-id', + }, + }); + + const coreStart = coreMock.createStart(); + plugin.start(coreStart); + + expect(coreStart.chrome.setHelpSupportUrl).toHaveBeenCalledTimes(1); + expect(coreStart.chrome.setHelpSupportUrl.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://support.elastic.co/?serverless_project_id=my-awesome-serverless-project-id", + ] + `); + }); + + it('registers help support URL: non-serverless projects', async () => { + const { plugin } = startPlugin({ + id: 'my-awesome-project-id', + }); + + const coreStart = coreMock.createStart(); + plugin.start(coreStart); + + expect(coreStart.chrome.setHelpSupportUrl).toHaveBeenCalledTimes(1); + expect(coreStart.chrome.setHelpSupportUrl.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://support.elastic.co/?cloud_deployment_id=my-awesome-project-id", + ] + `); + }); + describe('isServerlessEnabled', () => { it('is `true` when `serverless.projectId` is set', () => { const { plugin } = startPlugin({ diff --git a/x-pack/plugins/cloud/public/plugin.tsx b/x-pack/plugins/cloud/public/plugin.tsx index 3aaaf8f14fe2..f0e7b8f713e8 100644 --- a/x-pack/plugins/cloud/public/plugin.tsx +++ b/x-pack/plugins/cloud/public/plugin.tsx @@ -11,10 +11,11 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kb import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url'; -import { ELASTIC_SUPPORT_LINK, CLOUD_SNAPSHOTS_PATH } from '../common/constants'; +import { CLOUD_SNAPSHOTS_PATH } from '../common/constants'; import { decodeCloudId, type DecodedCloudId } from '../common/decode_cloud_id'; import type { CloudSetup, CloudStart } from './types'; import { getFullCloudUrl } from '../common/utils'; +import { getSupportUrl } from './utils'; export interface CloudConfigType { id?: string; @@ -103,7 +104,7 @@ export class CloudPlugin implements Plugin { } public start(coreStart: CoreStart): CloudStart { - coreStart.chrome.setHelpSupportUrl(ELASTIC_SUPPORT_LINK); + coreStart.chrome.setHelpSupportUrl(getSupportUrl(this.config)); // Nest all the registered context providers under the Cloud Services Provider. // This way, plugins only need to require Cloud's context provider to have all the enriched Cloud services. diff --git a/x-pack/plugins/cloud/public/utils.ts b/x-pack/plugins/cloud/public/utils.ts new file mode 100644 index 000000000000..d2381c428fe0 --- /dev/null +++ b/x-pack/plugins/cloud/public/utils.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ELASTIC_SUPPORT_LINK } from '../common/constants'; +import { CloudConfigType } from './plugin'; + +export function getSupportUrl(config: CloudConfigType): string { + let supportUrl = ELASTIC_SUPPORT_LINK; + if (config.serverless?.project_id) { + // serverless projects use config.id and config.serverless.project_id + supportUrl += '?serverless_project_id=' + config.serverless.project_id; + } else if (config.id) { + // non-serverless Cloud projects only use config.id + supportUrl += '?cloud_deployment_id=' + config.id; + } + return supportUrl; +} diff --git a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.test.ts b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.test.ts index 836cafa8ac7a..b0abbbe568d2 100644 --- a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.test.ts +++ b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.test.ts @@ -6,9 +6,9 @@ */ import { coreMock } from '@kbn/core/public/mocks'; -import type { CloudFullStoryConfigType } from '../server/config'; -import { CloudFullStoryPlugin } from './plugin'; import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; +import { duration } from 'moment'; +import { CloudFullStoryConfig, CloudFullStoryPlugin } from './plugin'; describe('Cloud Plugin', () => { describe('#setup', () => { @@ -22,7 +22,7 @@ describe('Cloud Plugin', () => { isCloudEnabled = true, isElasticStaffOwned = false, }: { - config?: Partial; + config?: Partial; isCloudEnabled?: boolean; isElasticStaffOwned?: boolean; }) => { @@ -55,6 +55,20 @@ describe('Cloud Plugin', () => { }); }); + test('register the shipper FullStory with the correct duration', async () => { + const { coreSetup } = await setupPlugin({ + config: { org_id: 'foo', pageVarsDebounceTime: `${duration(500, 'ms')}` }, + }); + + expect(coreSetup.analytics.registerShipper).toHaveBeenCalled(); + expect(coreSetup.analytics.registerShipper).toHaveBeenCalledWith(expect.anything(), { + fullStoryOrgId: 'foo', + pageVarsDebounceTimeMs: 500, + scriptUrl: '/internal/cloud/100/fullstory.js', + namespace: 'FSKibana', + }); + }); + it('does not call initializeFullStory when isCloudEnabled=false', async () => { const { coreSetup } = await setupPlugin({ config: { org_id: 'foo' }, diff --git a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts index a248b27f9371..7636d38b681e 100755 --- a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts +++ b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts @@ -13,15 +13,17 @@ import type { Plugin, } from '@kbn/core/public'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; +import { duration } from 'moment'; interface SetupFullStoryDeps { analytics: AnalyticsServiceSetup; basePath: IBasePath; } -interface CloudFullStoryConfig { +export interface CloudFullStoryConfig { org_id?: string; eventTypesAllowlist: string[]; + pageVarsDebounceTime: string; } interface CloudFullStorySetupDeps { @@ -61,7 +63,7 @@ export class CloudFullStoryPlugin implements Plugin { * @private */ private async setupFullStory({ analytics, basePath }: SetupFullStoryDeps) { - const { org_id: fullStoryOrgId, eventTypesAllowlist } = this.config; + const { org_id: fullStoryOrgId, eventTypesAllowlist, pageVarsDebounceTime } = this.config; if (!fullStoryOrgId) { return; // do not load any FullStory code in the browser if not enabled } @@ -71,6 +73,10 @@ export class CloudFullStoryPlugin implements Plugin { analytics.registerShipper(FullStoryShipper, { eventTypesAllowlist, fullStoryOrgId, + // Duration configs get stringified when forwarded to the UI and need reconversion + ...(pageVarsDebounceTime + ? { pageVarsDebounceTimeMs: duration(pageVarsDebounceTime).asMilliseconds() } + : {}), // Load an Elastic-internally audited script. Ideally, it should be hosted on a CDN. scriptUrl: basePath.prepend( `/internal/cloud/${this.initializerContext.env.packageInfo.buildNum}/fullstory.js` diff --git a/x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts b/x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts index 85822bae819e..8c6eb180f1db 100644 --- a/x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts +++ b/x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @@ -26,6 +26,7 @@ const configSchema = schema.object({ 'Host Flyout Filter Added', // Worst-case scenario once per second - AT RISK, ], }), + pageVarsDebounceTime: schema.duration({ defaultValue: '500ms' }), }); export type CloudFullStoryConfigType = TypeOf; @@ -34,6 +35,7 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { org_id: true, eventTypesAllowlist: true, + pageVarsDebounceTime: true, }, schema: configSchema, deprecations: () => [ diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/connection_details_modal.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/connection_details_modal.tsx new file mode 100644 index 000000000000..d7be45e1db24 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/connection_details_modal.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import type { CoreStart } from '@kbn/core/public'; +import type { DocLinksStart } from '@kbn/core-doc-links-browser'; +import type { CloudStart } from '@kbn/cloud-plugin/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { + DeploymentDetailsKibanaProvider, + DeploymentDetailsModal, +} from '@kbn/cloud/deployment_details'; + +interface Props { + closeModal: () => void; + core: CoreStart; + docLinks: DocLinksStart; + cloud: CloudStart; + share: SharePluginStart; +} + +export const ConnectionDetailsModal = ({ core, share, cloud, docLinks, closeModal }: Props) => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx deleted file mode 100644 index 7c6b23d352f1..000000000000 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/endpoints_modal.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import type { CoreStart } from '@kbn/core/public'; -import type { DocLinksStart } from '@kbn/core-doc-links-browser'; -import type { CloudStart } from '@kbn/cloud-plugin/public'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import { - DeploymentDetailsKibanaProvider, - DeploymentDetailsModal, -} from '@kbn/cloud/deployment_details'; - -interface Props { - closeModal: () => void; - core: CoreStart; - docLinks: DocLinksStart; - cloud: CloudStart; - share: SharePluginStart; -} - -export const EndpointsModal = ({ core, share, cloud, docLinks, closeModal }: Props) => { - return ( - - - - ); -}; diff --git a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx index 15270c587621..05ea7b9ce30c 100644 --- a/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_links/public/maybe_add_cloud_links/help_menu_links.tsx @@ -13,7 +13,7 @@ import type { CloudStart } from '@kbn/cloud-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; -import { EndpointsModal } from './endpoints_modal'; +import { ConnectionDetailsModal } from './connection_details_modal'; export const createHelpMenuLinks = ({ docLinks, @@ -50,15 +50,15 @@ export const createHelpMenuLinks = ({ href: docLinks.links.kibana.feedback, }, { - title: i18n.translate('xpack.cloudLinks.helpMenuLinks.endpoints', { - defaultMessage: 'Endpoints', + title: i18n.translate('xpack.cloudLinks.helpMenuLinks.connectionDetails', { + defaultMessage: 'Connection details', }), iconType: 'console', - dataTestSubj: 'endpointsHelpLink', + dataTestSubj: 'connectionDetailsHelpLink', onClick: () => { const modal = overlays.openModal( toMountPoint( - { "title": "Give feedback", }, Object { - "dataTestSubj": "endpointsHelpLink", + "dataTestSubj": "connectionDetailsHelpLink", "iconType": "console", "onClick": [Function], - "title": "Endpoints", + "title": "Connection details", }, ], ] @@ -168,10 +168,10 @@ describe('maybeAddCloudLinks', () => { "title": "Give feedback", }, Object { - "dataTestSubj": "endpointsHelpLink", + "dataTestSubj": "connectionDetailsHelpLink", "iconType": "console", "onClick": [Function], - "title": "Endpoints", + "title": "Connection details", }, ], ] diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index 1cc356cbfd5e..d2fffa9d26a2 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -10,7 +10,6 @@ import { VulnSeverity, AwsCredentialsTypeFieldMap, GcpCredentialsTypeFieldMap, - AzureCredentialsTypeFieldMap, } from './types'; export const STATUS_ROUTE_PATH = '/internal/cloud_security_posture/status'; @@ -161,7 +160,25 @@ export const GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP: GcpCredentialsTypeFieldMap = { 'credentials-json': ['gcp.credentials.json'], }; -export const AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP: AzureCredentialsTypeFieldMap = { - manual: [], +export const AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP = { arm_template: [], + service_principal_with_client_secret: [ + 'azure.credentials.tenant_id', + 'azure.credentials.client_id', + 'azure.credentials.client_secret', + ], + service_principal_with_client_certificate: [ + 'azure.credentials.tenant_id', + 'azure.credentials.client_id', + 'azure.credentials.client_certificate_path', + 'azure.credentials.client_certificate_password', + ], + service_principal_with_client_username_and_password: [ + 'azure.credentials.tenant_id', + 'azure.credentials.client_id', + 'azure.credentials.client_username', + 'azure.credentials.client_password', + ], + managed_identity: [], + manual: [], }; diff --git a/x-pack/plugins/cloud_security_posture/common/types.ts b/x-pack/plugins/cloud_security_posture/common/types.ts index 092129a6762e..aa25c70eb247 100644 --- a/x-pack/plugins/cloud_security_posture/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/common/types.ts @@ -30,7 +30,13 @@ export type GcpCredentialsTypeFieldMap = { [key in GcpCredentialsType]: string[]; }; -export type AzureCredentialsType = 'arm_template' | 'manual'; +export type AzureCredentialsType = + | 'arm_template' + | 'service_principal_with_client_secret' + | 'service_principal_with_client_certificate' + | 'service_principal_with_client_username_and_password' + | 'managed_identity' + | 'manual'; export type AzureCredentialsTypeFieldMap = { [key in AzureCredentialsType]: string[]; @@ -74,6 +80,18 @@ export interface Cluster { trend: PostureTrend[]; } +export interface BenchmarkData { + meta: { + benchmarkId: CspFinding['rule']['benchmark']['id']; + benchmarkVersion: CspFinding['rule']['benchmark']['version']; + benchmarkName: CspFinding['rule']['benchmark']['name']; + assetCount: number; + }; + stats: Stats; + groupedFindingsEvaluation: GroupedFindingsEvaluation[]; + trend: PostureTrend[]; +} + export interface ComplianceDashboardData { stats: Stats; groupedFindingsEvaluation: GroupedFindingsEvaluation[]; @@ -81,6 +99,13 @@ export interface ComplianceDashboardData { trend: PostureTrend[]; } +export interface ComplianceDashboardDataV2 { + stats: Stats; + groupedFindingsEvaluation: GroupedFindingsEvaluation[]; + trend: PostureTrend[]; + benchmarks: BenchmarkData[]; +} + export type CspStatusCode = | 'indexed' // latest findings index exists and has results | 'indexing' // index timeout was not surpassed since installation, assumes data is being indexed diff --git a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts index 85815e780b06..ba8e6f981383 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts @@ -124,7 +124,7 @@ export const cleanupCredentials = (packagePolicy: NewPackagePolicy | UpdatePacka const azureCredentialType: AzureCredentialsType | undefined = enabledInput?.streams?.[0].vars?.['azure.credentials.type']?.value; - if (awsCredentialType || gcpCredentialType) { + if (awsCredentialType || gcpCredentialType || azureCredentialType) { let credsToKeep: string[] = [' ']; let credFields: string[] = [' ']; if (awsCredentialType) { diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts index 68ab9dfc698f..834a75581519 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts @@ -7,7 +7,7 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query'; import { useKibana } from '../hooks/use_kibana'; -import { ComplianceDashboardData, PosturePolicyTemplate } from '../../../common/types'; +import { ComplianceDashboardDataV2, PosturePolicyTemplate } from '../../../common/types'; import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE, @@ -23,23 +23,25 @@ export const getStatsRoute = (policyTemplate: PosturePolicyTemplate) => { }; export const useCspmStatsApi = ( - options: UseQueryOptions + options: UseQueryOptions ) => { const { http } = useKibana().services; return useQuery( getCspmStatsKey, - () => http.get(getStatsRoute(CSPM_POLICY_TEMPLATE), { version: '1' }), + () => + http.get(getStatsRoute(CSPM_POLICY_TEMPLATE), { version: '2' }), options ); }; export const useKspmStatsApi = ( - options: UseQueryOptions + options: UseQueryOptions ) => { const { http } = useKibana().services; return useQuery( getKspmStatsKey, - () => http.get(getStatsRoute(KSPM_POLICY_TEMPLATE), { version: '1' }), + () => + http.get(getStatsRoute(KSPM_POLICY_TEMPLATE), { version: '2' }), options ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 7641745b897f..5ea356e4a383 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -45,6 +45,8 @@ export const LOCAL_STORAGE_PAGE_SIZE_BENCHMARK_KEY = 'cloudPosture:benchmark:pag export const LOCAL_STORAGE_PAGE_SIZE_RULES_KEY = 'cloudPosture:rules:pageSize'; export const LOCAL_STORAGE_DASHBOARD_CLUSTER_SORT_KEY = 'cloudPosture:complianceDashboard:clusterSort'; +export const LOCAL_STORAGE_DASHBOARD_BENCHMARK_SORT_KEY = + 'cloudPosture:complianceDashboard:benchmarkSort'; export const LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY = 'cloudPosture:findings:lastSelectedTab'; export type CloudPostureIntegrations = Record< diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/index.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/index.ts new file mode 100644 index 000000000000..b026744f008b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './use_cloud_posture_data_table'; +export * from './use_base_es_query'; +export * from './use_persisted_query'; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts new file mode 100644 index 000000000000..4adffa100e48 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildEsQuery, EsQueryConfig } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; +import { useEffect, useMemo } from 'react'; +import { FindingsBaseESQueryConfig, FindingsBaseProps, FindingsBaseURLQuery } from '../../types'; +import { useKibana } from '../use_kibana'; + +const getBaseQuery = ({ + dataView, + query, + filters, + config, +}: FindingsBaseURLQuery & FindingsBaseProps & FindingsBaseESQueryConfig) => { + try { + return { + query: buildEsQuery(dataView, query, filters, config), // will throw for malformed query + }; + } catch (error) { + return { + query: undefined, + error: error instanceof Error ? error : new Error('Unknown Error'), + }; + } +}; + +export const useBaseEsQuery = ({ + dataView, + filters = [], + query, + nonPersistedFilters, +}: FindingsBaseURLQuery & FindingsBaseProps) => { + const { + notifications: { toasts }, + data: { + query: { filterManager, queryString }, + }, + uiSettings, + } = useKibana().services; + const allowLeadingWildcards = uiSettings.get('query:allowLeadingWildcards'); + const config: EsQueryConfig = useMemo(() => ({ allowLeadingWildcards }), [allowLeadingWildcards]); + const baseEsQuery = useMemo( + () => + getBaseQuery({ + dataView, + filters: filters.concat(nonPersistedFilters ?? []).flat(), + query, + config, + }), + [dataView, filters, nonPersistedFilters, query, config] + ); + + /** + * Sync filters with the URL query + */ + useEffect(() => { + filterManager.setAppFilters(filters); + queryString.setQuery(query); + }, [filters, filterManager, queryString, query]); + + const handleMalformedQueryError = () => { + const error = baseEsQuery instanceof Error ? baseEsQuery : undefined; + if (error) { + toasts.addError(error, { + title: i18n.translate('xpack.csp.findings.search.queryErrorToastMessage', { + defaultMessage: 'Query Error', + }), + toastLifeTimeMs: 1000 * 5, + }); + } + }; + + useEffect(handleMalformedQueryError, [baseEsQuery, toasts]); + + return baseEsQuery; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts new file mode 100644 index 000000000000..ae21f45c7a4e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Dispatch, SetStateAction, useCallback } from 'react'; +import { type DataView } from '@kbn/data-views-plugin/common'; +import { BoolQuery, Filter } from '@kbn/es-query'; +import { CriteriaWithPagination } from '@elastic/eui'; +import { DataTableRecord } from '@kbn/discover-utils/types'; +import { useUrlQuery } from '../use_url_query'; +import { usePageSize } from '../use_page_size'; +import { getDefaultQuery } from './utils'; +import { LOCAL_STORAGE_DATA_TABLE_COLUMNS_KEY } from '../../constants'; +import { FindingsBaseURLQuery } from '../../types'; +import { useBaseEsQuery } from './use_base_es_query'; +import { usePersistedQuery } from './use_persisted_query'; + +type URLQuery = FindingsBaseURLQuery & Record; + +type SortOrder = [string, string]; + +export interface CloudPostureDataTableResult { + setUrlQuery: (query: Record) => void; + sort: SortOrder[]; + filters: Filter[]; + query: { bool: BoolQuery }; + queryError?: Error; + pageIndex: number; + urlQuery: URLQuery; + setTableOptions: (options: CriteriaWithPagination) => void; + handleUpdateQuery: (query: URLQuery) => void; + pageSize: number; + setPageSize: Dispatch>; + onChangeItemsPerPage: (newPageSize: number) => void; + onChangePage: (newPageIndex: number) => void; + onSort: (sort: string[][]) => void; + onResetFilters: () => void; + columnsLocalStorageKey: string; + getRowsFromPages: (data: Array<{ page: DataTableRecord[] }> | undefined) => DataTableRecord[]; +} + +/* + Hook for managing common table state and methods for the Cloud Posture DataTable +*/ +export const useCloudPostureDataTable = ({ + defaultQuery = getDefaultQuery, + dataView, + paginationLocalStorageKey, + columnsLocalStorageKey, + nonPersistedFilters, +}: { + defaultQuery?: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; + dataView: DataView; + paginationLocalStorageKey: string; + columnsLocalStorageKey?: string; + nonPersistedFilters?: Filter[]; +}): CloudPostureDataTableResult => { + const getPersistedDefaultQuery = usePersistedQuery(defaultQuery); + const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); + const { pageSize, setPageSize } = usePageSize(paginationLocalStorageKey); + + const onChangeItemsPerPage = useCallback( + (newPageSize) => { + setPageSize(newPageSize); + setUrlQuery({ + pageIndex: 0, + pageSize: newPageSize, + }); + }, + [setPageSize, setUrlQuery] + ); + + const onResetFilters = useCallback(() => { + setUrlQuery({ + pageIndex: 0, + filters: [], + query: { + query: '', + language: 'kuery', + }, + }); + }, [setUrlQuery]); + + const onChangePage = useCallback( + (newPageIndex) => { + setUrlQuery({ + pageIndex: newPageIndex, + }); + }, + [setUrlQuery] + ); + + const onSort = useCallback( + (sort) => { + setUrlQuery({ + sort, + }); + }, + [setUrlQuery] + ); + + const setTableOptions = useCallback( + ({ page, sort }) => { + setPageSize(page.size); + setUrlQuery({ + sort, + pageIndex: page.index, + }); + }, + [setUrlQuery, setPageSize] + ); + + /** + * Page URL query to ES query + */ + const baseEsQuery = useBaseEsQuery({ + dataView, + filters: urlQuery.filters, + query: urlQuery.query, + ...(nonPersistedFilters ? { nonPersistedFilters } : {}), + }); + + const handleUpdateQuery = useCallback( + (query) => { + setUrlQuery({ ...query, pageIndex: 0 }); + }, + [setUrlQuery] + ); + + const getRowsFromPages = (data: Array<{ page: DataTableRecord[] }> | undefined) => + data + ?.map(({ page }: { page: DataTableRecord[] }) => { + return page; + }) + .flat() || []; + + const queryError = baseEsQuery instanceof Error ? baseEsQuery : undefined; + + return { + setUrlQuery, + sort: urlQuery.sort, + filters: urlQuery.filters, + query: baseEsQuery.query + ? baseEsQuery.query + : { + bool: { + must: [], + filter: [], + should: [], + must_not: [], + }, + }, + queryError, + pageIndex: urlQuery.pageIndex, + urlQuery, + setTableOptions, + handleUpdateQuery, + pageSize, + setPageSize, + onChangeItemsPerPage, + onChangePage, + onSort, + onResetFilters, + columnsLocalStorageKey: columnsLocalStorageKey || LOCAL_STORAGE_DATA_TABLE_COLUMNS_KEY, + getRowsFromPages, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_persisted_query.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_persisted_query.ts new file mode 100644 index 000000000000..c3731c0139ce --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_persisted_query.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { type Query } from '@kbn/es-query'; +import { FindingsBaseURLQuery } from '../../types'; +import { useKibana } from '../use_kibana'; + +export const usePersistedQuery = (getter: ({ filters, query }: FindingsBaseURLQuery) => T) => { + const { + data: { + query: { filterManager, queryString }, + }, + } = useKibana().services; + + return useCallback( + () => + getter({ + filters: filterManager.getAppFilters(), + query: queryString.getQuery() as Query, + }), + [getter, filterManager, queryString] + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/utils.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/utils.ts new file mode 100644 index 000000000000..c715b6a90b4c --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/utils.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EuiBasicTableProps, Pagination } from '@elastic/eui'; + +type TablePagination = NonNullable['pagination']>; + +export const getPaginationTableParams = ( + params: TablePagination & Pick, 'pageIndex' | 'pageSize'>, + pageSizeOptions = [10, 25, 100], + showPerPageOptions = true +): Required => ({ + ...params, + pageSizeOptions, + showPerPageOptions, +}); + +export const getPaginationQuery = ({ + pageIndex, + pageSize, +}: Required>) => ({ + from: pageIndex * pageSize, + size: pageSize, +}); + +export const getDefaultQuery = ({ query, filters }: any): any => ({ + query, + filters, + sort: { field: '@timestamp', direction: 'desc' }, + pageIndex: 0, +}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/types.ts b/x-pack/plugins/cloud_security_posture/public/common/types.ts index 6ebfe7c7a0fa..a4c26643293f 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/types.ts @@ -14,6 +14,10 @@ export type FindingsGroupByKind = 'default' | 'resource'; export interface FindingsBaseURLQuery { query: Query; filters: Filter[]; + /** + * Filters that are part of the query but not persisted in the URL or in the Filter Manager + */ + nonPersistedFilters?: Filter[]; } export interface FindingsBaseProps { diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.test.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.test.ts new file mode 100644 index 000000000000..23cf2512ad2c --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAbbreviatedNumber } from './get_abbreviated_number'; + +describe('getAbbreviatedNumber', () => { + it('should return the same value if it is less than 1000', () => { + expect(getAbbreviatedNumber(0)).toBe(0); + expect(getAbbreviatedNumber(1)).toBe(1); + expect(getAbbreviatedNumber(500)).toBe(500); + expect(getAbbreviatedNumber(999)).toBe(999); + }); + + it('should use numeral to format the value if it is greater than or equal to 1000', () => { + expect(getAbbreviatedNumber(1000)).toBe('1.0k'); + + expect(getAbbreviatedNumber(1200)).toBe('1.2k'); + + expect(getAbbreviatedNumber(3500000)).toBe('3.5m'); + + expect(getAbbreviatedNumber(2800000000)).toBe('2.8b'); + + expect(getAbbreviatedNumber(5900000000000)).toBe('5.9t'); + + expect(getAbbreviatedNumber(59000000000000000)).toBe('59000.0t'); + }); + + it('should return 0 if the value is NaN', () => { + expect(getAbbreviatedNumber(NaN)).toBe(0); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.ts b/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.ts new file mode 100644 index 000000000000..353a6482f470 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import numeral from '@elastic/numeral'; + +/** + * Returns an abbreviated number when the value is greater than or equal to 1000. + * The abbreviated number is formatted using numeral: + * - thousand: k + * - million: m + * - billion: b + * - trillion: t + * */ +export const getAbbreviatedNumber = (value: number) => { + if (isNaN(value)) { + return 0; + } + return value < 1000 ? value : numeral(value).format('0.0a'); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx index 418b1c37a1bd..4feee3a5e228 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/accounts_evaluated_widget.tsx @@ -8,10 +8,10 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { CIS_AWS, CIS_GCP, CIS_AZURE, CIS_K8S, CIS_EKS } from '../../common/constants'; -import { Cluster } from '../../common/types'; import { CISBenchmarkIcon } from './cis_benchmark_icon'; import { CompactFormattedNumber } from './compact_formatted_number'; import { useNavigateFindings } from '../common/hooks/use_navigate_findings'; +import { BenchmarkData } from '../../common/types'; // order in array will determine order of appearance in the dashboard const benchmarks = [ @@ -43,17 +43,17 @@ const benchmarks = [ ]; export const AccountsEvaluatedWidget = ({ - clusters, + benchmarkAssets, benchmarkAbbreviateAbove = 999, }: { - clusters: Cluster[]; + benchmarkAssets: BenchmarkData[]; /** numbers higher than the value of this field will be abbreviated using compact notation and have a tooltip displaying the full value */ benchmarkAbbreviateAbove?: number; }) => { const { euiTheme } = useEuiTheme(); - const filterClustersById = (benchmarkId: string) => { - return clusters?.filter((obj) => obj?.meta.benchmark.id === benchmarkId) || []; + const filterBenchmarksById = (benchmarkId: string) => { + return benchmarkAssets?.filter((obj) => obj?.meta.benchmarkId === benchmarkId) || []; }; const navToFindings = useNavigateFindings(); @@ -67,10 +67,10 @@ export const AccountsEvaluatedWidget = ({ }; const benchmarkElements = benchmarks.map((benchmark) => { - const clusterAmount = filterClustersById(benchmark.type).length; + const cloudAssetAmount = filterBenchmarksById(benchmark.type).length; return ( - clusterAmount > 0 && ( + cloudAssetAmount > 0 && ( { @@ -98,7 +98,7 @@ export const AccountsEvaluatedWidget = ({ diff --git a/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx b/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx index b6ffc9f0157b..6c813c480ed8 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx @@ -23,6 +23,7 @@ interface ChartPanelProps { isLoading?: boolean; isError?: boolean; rightSideItems?: ReactNode[]; + styles?: React.CSSProperties; } const Loading = () => ( @@ -54,6 +55,7 @@ export const ChartPanel: React.FC = ({ isError, children, rightSideItems, + styles, }) => { const { euiTheme } = useEuiTheme(); const renderChart = () => { @@ -63,7 +65,7 @@ export const ChartPanel: React.FC = ({ }; return ( - + diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/additional_controls.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/additional_controls.tsx index 61a85e9993ec..ff411d2dcd9e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/additional_controls.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/additional_controls.tsx @@ -8,13 +8,18 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, EuiFlexItem } from '@elastic/eui'; import { type DataView } from '@kbn/data-views-plugin/common'; -import numeral from '@elastic/numeral'; import { FieldsSelectorModal } from './fields_selector'; -import { FindingsGroupBySelector } from '../../pages/configurations/layout/findings_group_by_selector'; import { useStyles } from './use_styles'; +import { getAbbreviatedNumber } from '../../common/utils/get_abbreviated_number'; -const formatNumber = (value: number) => { - return value < 1000 ? value : numeral(value).format('0.0a'); +const GroupSelectorWrapper: React.FC = ({ children }) => { + const styles = useStyles(); + + return ( + + {children} + + ); }; export const AdditionalControls = ({ @@ -24,6 +29,7 @@ export const AdditionalControls = ({ columns, onAddColumn, onRemoveColumn, + groupSelectorComponent, }: { total: number; title: string; @@ -31,9 +37,8 @@ export const AdditionalControls = ({ columns: string[]; onAddColumn: (column: string) => void; onRemoveColumn: (column: string) => void; + groupSelectorComponent?: JSX.Element; }) => { - const styles = useStyles(); - const [isFieldSelectorModalVisible, setIsFieldSelectorModalVisible] = useState(false); const closeModal = () => setIsFieldSelectorModalVisible(false); @@ -51,7 +56,7 @@ export const AdditionalControls = ({ /> )} - {`${formatNumber(total)} ${title}`} + {`${getAbbreviatedNumber(total)} ${title}`} - - - + {groupSelectorComponent && ( + {groupSelectorComponent} + )} ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx index 9487b405fbba..50e81a0a0c7e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx @@ -69,6 +69,15 @@ interface CloudSecurityDataGridProps { */ loadMore: () => void; 'data-test-subj'?: string; + /** + * This is the component that will be rendered in the group selector. + * This component will receive the current group and a function to change the group. + */ + groupSelectorComponent?: JSX.Element; + /** + * Height override for the data grid. + */ + height?: number; } export const CloudSecurityDataTable = ({ @@ -82,6 +91,8 @@ export const CloudSecurityDataTable = ({ loadMore, title, customCellRenderer, + groupSelectorComponent, + height, ...rest }: CloudSecurityDataGridProps) => { const { @@ -209,6 +220,7 @@ export const CloudSecurityDataTable = ({ columns={currentColumns} onAddColumn={onAddColumn} onRemoveColumn={onRemoveColumn} + groupSelectorComponent={groupSelectorComponent} /> ); @@ -216,7 +228,7 @@ export const CloudSecurityDataTable = ({ // Change the height of the grid to fit the page // If there are filters, leave space for the filter bar // Todo: Replace this component with EuiAutoSizer - height: `calc(100vh - ${filters.length > 0 ? 443 : 403}px)`, + height: height ?? `calc(100vh - ${filters?.length > 0 ? 443 : 403}px)`, }; const rowHeightState = 0; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/use_styles.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/use_styles.ts index b3b0fa1b172b..a2b923bf26b5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/use_styles.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/use_styles.ts @@ -23,9 +23,6 @@ export const useStyles = () => { border-bottom: none; margin-bottom: ${euiTheme.size.s}; border-top: none; - & .euiButtonEmpty { - font-weight: ${euiTheme.font.weight.bold}; - } } & .euiDataGrid--headerUnderline .euiDataGridHeaderCell { border-bottom: ${euiTheme.border.width.thick} solid ${euiTheme.colors.fullShade}; @@ -76,7 +73,6 @@ export const useStyles = () => { `; const groupBySelector = css` - width: 188px; margin-left: auto; `; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/cloud_security_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/cloud_security_grouping.tsx new file mode 100644 index 000000000000..4ec3d3578a54 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/cloud_security_grouping.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useGrouping } from '@kbn/securitysolution-grouping'; +import { ParsedGroupingAggregation } from '@kbn/securitysolution-grouping/src'; +import { Filter } from '@kbn/es-query'; +import React from 'react'; +import { css } from '@emotion/react'; +import { CSP_GROUPING, CSP_GROUPING_LOADING } from '../test_subjects'; + +interface CloudSecurityGroupingProps { + data: ParsedGroupingAggregation; + renderChildComponent: (groupFilter: Filter[]) => JSX.Element; + grouping: ReturnType; + activePageIndex: number; + isFetching: boolean; + pageSize: number; + onChangeGroupsItemsPerPage: (size: number) => void; + onChangeGroupsPage: (index: number) => void; + selectedGroup: string; + isGroupLoading?: boolean; +} + +/** + * This component is used to render the loading state of the CloudSecurityGrouping component + * It's used to avoid the flickering of the table when the data is loading + */ +const CloudSecurityGroupingLoading = ({ + grouping, + pageSize, +}: Pick) => { + return ( +
    + {grouping.getGrouping({ + activePage: 0, + data: { + groupsCount: { value: 1 }, + unitsCount: { value: 1 }, + }, + groupingLevel: 0, + inspectButton: undefined, + isLoading: true, + itemsPerPage: pageSize, + renderChildComponent: () => <>, + onGroupClose: () => {}, + selectedGroup: '', + takeActionItems: () => [], + })} +
    + ); +}; + +export const CloudSecurityGrouping = ({ + data, + renderChildComponent, + grouping, + activePageIndex, + isFetching, + pageSize, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + selectedGroup, + isGroupLoading, +}: CloudSecurityGroupingProps) => { + if (isGroupLoading) { + return ; + } + return ( +
    .euiFlexItem:last-child { + display: none; + } + && [data-test-subj='group-stats'] > .euiFlexItem:not(:first-child) > span { + border-right: none; + margin-right: 0; + } + `} + > + {grouping.getGrouping({ + activePage: activePageIndex, + data, + groupingLevel: 0, + inspectButton: undefined, + isLoading: isFetching, + itemsPerPage: pageSize, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + renderChildComponent, + onGroupClose: () => {}, + selectedGroup, + takeActionItems: () => [], + })} +
    + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts new file mode 100644 index 000000000000..35a321d06119 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { useCloudSecurityGrouping } from './use_cloud_security_grouping'; +export { CloudSecurityGrouping } from './cloud_security_grouping'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts new file mode 100644 index 000000000000..c59d38214452 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { isNoneGroup, useGrouping } from '@kbn/securitysolution-grouping'; +import * as uuid from 'uuid'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { + GroupOption, + GroupPanelRenderer, + GroupStatsRenderer, +} from '@kbn/securitysolution-grouping/src'; +import { useUrlQuery } from '../../common/hooks/use_url_query'; + +import { FindingsBaseURLQuery } from '../../common/types'; +import { useBaseEsQuery, usePersistedQuery } from '../../common/hooks/use_cloud_posture_data_table'; + +const DEFAULT_PAGE_SIZE = 10; +const GROUPING_ID = 'cspLatestFindings'; +const MAX_GROUPING_LEVELS = 1; + +/* + Utility hook to handle the grouping logic of the cloud security components +*/ +export const useCloudSecurityGrouping = ({ + dataView, + groupingTitle, + defaultGroupingOptions, + getDefaultQuery, + unit, + groupPanelRenderer, + groupStatsRenderer, +}: { + dataView: DataView; + groupingTitle: string; + defaultGroupingOptions: GroupOption[]; + getDefaultQuery: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; + unit: (count: number) => string; + groupPanelRenderer?: GroupPanelRenderer; + groupStatsRenderer?: GroupStatsRenderer; +}) => { + const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); + const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); + const [activePageIndex, setActivePageIndex] = useState(0); + const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); + + const { query, error } = useBaseEsQuery({ + dataView, + filters: urlQuery.filters, + query: urlQuery.query, + }); + + /** + * Reset the active page when the filters or query change + * This is needed because the active page is not automatically reset when the filters or query change + */ + useEffect(() => { + setActivePageIndex(0); + }, [urlQuery.filters, urlQuery.query]); + + const grouping = useGrouping({ + componentProps: { + unit, + groupPanelRenderer, + groupStatsRenderer, + }, + defaultGroupingOptions, + fields: dataView.fields, + groupingId: GROUPING_ID, + maxGroupingLevels: MAX_GROUPING_LEVELS, + title: groupingTitle, + onGroupChange: () => { + setActivePageIndex(0); + }, + }); + + const selectedGroup = grouping.selectedGroups[0]; + + // This is recommended by the grouping component to cover an edge case + // where the selectedGroup has multiple values + const uniqueValue = useMemo(() => `${selectedGroup}-${uuid.v4()}`, [selectedGroup]); + + const isNoneSelected = isNoneGroup(grouping.selectedGroups); + + const onChangeGroupsItemsPerPage = (size: number) => { + setActivePageIndex(0); + setPageSize(size); + }; + + const onResetFilters = useCallback(() => { + setUrlQuery({ + filters: [], + query: { + query: '', + language: 'kuery', + }, + }); + }, [setUrlQuery]); + + const onChangeGroupsPage = (index: number) => setActivePageIndex(index); + + return { + activePageIndex, + grouping, + pageSize, + query, + error, + selectedGroup, + setUrlQuery, + uniqueValue, + isNoneSelected, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + onResetFilters, + filters: urlQuery.filters, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx index 8f866079ab16..d71d6c2e2384 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx @@ -6,11 +6,12 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { css, SerializedStyles } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { calculatePostureScore } from '../../common/utils/helpers'; import { statusColors } from '../common/constants'; +import { CSP_FINDINGS_COMPLIANCE_SCORE } from './test_subjects'; /** * This component will take 100% of the width set by the parent @@ -18,20 +19,26 @@ import { statusColors } from '../common/constants'; export const ComplianceScoreBar = ({ totalPassed, totalFailed, + size = 'm', + overrideCss, }: { totalPassed: number; totalFailed: number; + size?: 'm' | 'l'; + overrideCss?: SerializedStyles; }) => { const { euiTheme } = useEuiTheme(); const complianceScore = calculatePostureScore(totalPassed, totalFailed); + // ensures the compliance bar takes full width of its parent + const fullWidthTooltipCss = css` + width: 100%; + `; + return ( - + {!!totalPassed && ( )} {!!totalFailed && ( )} - + {`${complianceScore.toFixed(0)}%`} diff --git a/x-pack/plugins/cloud_security_posture/public/components/empty_state.tsx b/x-pack/plugins/cloud_security_posture/public/components/empty_state.tsx index 9c38e635062f..43f39023c9c3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/empty_state.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/empty_state.tsx @@ -30,7 +30,9 @@ export const EmptyState = ({ && > .euiEmptyPrompt__main { gap: ${euiTheme.size.xl}; } - margin-top: ${euiTheme.size.xxxl}}; + && { + margin-top: ${euiTheme.size.xxxl}}; + } `} data-test-subj={EMPTY_STATE_TEST_SUBJ} icon={ diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx index 19fe841e3b01..ab8770b20f0c 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx @@ -5,7 +5,18 @@ * 2.0. */ import React, { useEffect } from 'react'; -import { EuiLink, EuiSpacer, EuiText, EuiTitle, EuiCallOut, EuiHorizontalRule } from '@elastic/eui'; +import { + EuiLink, + EuiSpacer, + EuiText, + EuiTitle, + EuiCallOut, + EuiHorizontalRule, + EuiFormRow, + EuiSelect, + EuiFieldPassword, + EuiFieldText, +} from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; import { NewPackagePolicyInput, PackageInfo } from '@kbn/fleet-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -14,8 +25,13 @@ import { i18n } from '@kbn/i18n'; import semverValid from 'semver/functions/valid'; import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; +import { + AzureOptions, + getAzureCredentialsFormManualOptions, +} from './get_azure_credentials_form_options'; +import { AzureCredentialsType } from '../../../../common/types'; import { SetupFormat, useAzureCredentialsForm } from './hooks'; -import { NewPackagePolicyPostureInput } from '../utils'; +import { getPosturePolicy, NewPackagePolicyPostureInput } from '../utils'; import { CspRadioOption, RadioGroup } from '../csp_boxed_radio_group'; interface AzureSetupInfoContentProps { @@ -161,7 +177,31 @@ const ArmTemplateSetup = ({ ); }; -const ManualSetup = ({ integrationLink }: { integrationLink: string }) => { +const AzureCredentialTypeSelector = ({ + type, + onChange, +}: { + onChange(type: AzureCredentialsType): void; + type: AzureCredentialsType; +}) => ( + + { + onChange(optionElem.target.value as AzureCredentialsType); + }} + /> + +); + +const TemporaryManualSetup = ({ integrationLink }: { integrationLink: string }) => { return ( <> @@ -206,6 +246,53 @@ const ManualSetup = ({ integrationLink }: { integrationLink: string }) => { }; const AZURE_MINIMUM_PACKAGE_VERSION = '1.6.0'; +const AZURE_MANUAL_FIELDS_PACKAGE_VERSION = '1.7.0'; + +export const getDefaultAzureManualCredentialType = (packageInfo: PackageInfo) => { + const packageSemanticVersion = semverValid(packageInfo.version); + const cleanPackageVersion = semverCoerce(packageSemanticVersion) || ''; + + const isPackageVersionValidForManualFields = !semverLt( + cleanPackageVersion, + AZURE_MANUAL_FIELDS_PACKAGE_VERSION + ); + + return isPackageVersionValidForManualFields ? 'managed_identity' : 'manual'; +}; + +const AzureInputVarFields = ({ + fields, + onChange, +}: { + fields: Array; + onChange: (key: string, value: string) => void; +}) => ( +
    + {fields.map((field) => ( + + <> + {field.type === 'password' && ( + onChange(field.id, event.target.value)} + /> + )} + {field.type === 'text' && ( + onChange(field.id, event.target.value)} + /> + )} + + + ))} +
    +); export const AzureCredentialsForm = ({ input, @@ -216,15 +303,22 @@ export const AzureCredentialsForm = ({ setIsValid, disabled, }: Props) => { - const { setupFormat, onSetupFormatChange, integrationLink, hasArmTemplateUrl } = - useAzureCredentialsForm({ - newPolicy, - input, - packageInfo, - onChange, - setIsValid, - updatePolicy, - }); + const { + group, + fields, + azureCredentialsType, + setupFormat, + onSetupFormatChange, + integrationLink, + hasArmTemplateUrl, + } = useAzureCredentialsForm({ + newPolicy, + input, + packageInfo, + onChange, + setIsValid, + updatePolicy, + }); useEffect(() => { if (!setupFormat) { @@ -238,6 +332,10 @@ export const AzureCredentialsForm = ({ cleanPackageVersion, AZURE_MINIMUM_PACKAGE_VERSION ); + const isPackageVersionValidForManualFields = !semverLt( + cleanPackageVersion, + AZURE_MANUAL_FIELDS_PACKAGE_VERSION + ); useEffect(() => { setIsValid(isPackageVersionValidForAzure); @@ -280,8 +378,52 @@ export const AzureCredentialsForm = ({ {setupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE && ( )} - {setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && ( - + {setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && !isPackageVersionValidForManualFields && ( + + )} + {setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && isPackageVersionValidForManualFields && ( + <> + { + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'azure.credentials.type': { value: optionId }, + }) + ); + }} + /> + + { + updatePolicy(getPosturePolicy(newPolicy, input.type, { [key]: { value } })); + }} + /> + + {group.info} + + + + {i18n.translate('xpack.csp.azureIntegration.documentationLinkText', { + defaultMessage: 'documentation', + })} + + ), + }} + /> + + )} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx index 5a074ad4c4eb..455fe9352ba0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx @@ -8,18 +8,32 @@ import { NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; import React from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiText } from '@elastic/eui'; import { AzureCredentialsType } from '../../../../common/types'; export type AzureCredentialsFields = Record; export interface AzureOptionValue { label: string; - info: React.ReactNode; + info?: React.ReactNode; fields: AzureCredentialsFields; } export type AzureOptions = Record; +export const getAzureCredentialsFormManualOptions = (): Array<{ + value: AzureCredentialsType; + text: string; +}> => { + return Object.entries(getAzureCredentialsFormOptions()) + .map(([key, value]) => ({ + value: key as AzureCredentialsType, + text: value.label, + })) + .filter(({ value }) => value !== 'arm_template'); +}; + export const getInputVarsFields = (input: NewPackagePolicyInput, fields: AzureCredentialsFields) => Object.entries(input.streams[0].vars || {}) .filter(([id]) => id in fields) @@ -33,19 +47,102 @@ export const getInputVarsFields = (input: NewPackagePolicyInput, fields: AzureCr } as const; }); -export const DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE = 'manual'; +const I18N_TENANT_ID = i18n.translate('xpack.csp.azureIntegration.tenantIdLabel', { + defaultMessage: 'Tenant ID', +}); + +const I18N_CLIENT_ID = i18n.translate('xpack.csp.azureIntegration.clientIdLabel', { + defaultMessage: 'Client ID', +}); export const getAzureCredentialsFormOptions = (): AzureOptions => ({ + managed_identity: { + label: i18n.translate('xpack.csp.azureIntegration.credentialType.managedIdentityLabel', { + defaultMessage: 'Managed Identity', + }), + info: ( + + + + ), + fields: {}, + }, arm_template: { label: 'ARM Template', info: [], fields: {}, }, + service_principal_with_client_secret: { + label: i18n.translate('xpack.csp.azureIntegration.servicePrincipalWithClientSecretLabel', { + defaultMessage: 'Service principal with Client Secret', + }), + fields: { + 'azure.credentials.tenant_id': { label: I18N_TENANT_ID }, + 'azure.credentials.client_id': { label: I18N_CLIENT_ID }, + 'azure.credentials.client_secret': { + type: 'password', + label: i18n.translate('xpack.csp.azureIntegration.clientSecretLabel', { + defaultMessage: 'Client Secret', + }), + }, + }, + }, + service_principal_with_client_certificate: { + label: i18n.translate('xpack.csp.azureIntegration.servicePrincipalWithClientCertificateLabel', { + defaultMessage: 'Service principal with Client Certificate', + }), + fields: { + 'azure.credentials.tenant_id': { label: I18N_TENANT_ID }, + 'azure.credentials.client_id': { label: I18N_CLIENT_ID }, + 'azure.credentials.client_certificate_path': { + label: i18n.translate('xpack.csp.azureIntegration.clientCertificatePathLabel', { + defaultMessage: 'Client Certificate Path', + }), + }, + 'azure.credentials.client_certificate_password': { + type: 'password', + label: i18n.translate('xpack.csp.azureIntegration.clientCertificatePasswordLabel', { + defaultMessage: 'Client Certificate Password', + }), + }, + }, + }, + service_principal_with_client_username_and_password: { + label: i18n.translate( + 'xpack.csp.azureIntegration.servicePrincipalWithClientUsernameAndPasswordLabel', + { defaultMessage: 'Service principal with Client Username and Password' } + ), + fields: { + 'azure.credentials.tenant_id': { label: I18N_TENANT_ID }, + 'azure.credentials.client_id': { label: I18N_CLIENT_ID }, + 'azure.credentials.client_username': { + label: i18n.translate('xpack.csp.azureIntegration.clientUsernameLabel', { + defaultMessage: 'Client Username', + }), + }, + 'azure.credentials.client_password': { + type: 'password', + label: i18n.translate('xpack.csp.azureIntegration.clientPasswordLabel', { + defaultMessage: 'Client Password', + }), + }, + }, + }, manual: { label: i18n.translate('xpack.csp.azureIntegration.credentialType.manualLabel', { defaultMessage: 'Manual', }), - info: [], + info: ( + + + + ), fields: {}, }, }); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts index 011c39cf8038..b68828be5811 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts @@ -7,7 +7,10 @@ import { useEffect, useRef } from 'react'; import { NewPackagePolicy, PackageInfo } from '@kbn/fleet-plugin/common'; -import { AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE } from './azure_credentials_form'; +import { + AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE, + getDefaultAzureManualCredentialType, +} from './azure_credentials_form'; import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; import { getArmTemplateUrlFromCspmPackage, @@ -15,14 +18,28 @@ import { NewPackagePolicyPostureInput, } from '../utils'; import { - DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE, getAzureCredentialsFormOptions, getInputVarsFields, } from './get_azure_credentials_form_options'; import { CLOUDBEAT_AZURE } from '../../../../common/constants'; import { AzureCredentialsType } from '../../../../common/types'; -export type SetupFormat = AzureCredentialsType; +export type SetupFormat = 'arm_template' | 'manual'; + +const getSetupFormatFromInput = ( + input: Extract, + hasArmTemplateUrl: boolean +): SetupFormat => { + const credentialsType = getAzureCredentialsType(input); + if (!credentialsType && hasArmTemplateUrl) { + return 'arm_template'; + } + if (credentialsType !== 'arm_template') { + return 'manual'; + } + + return 'arm_template'; +}; const getAzureCredentialsType = ( input: Extract @@ -107,7 +124,7 @@ export const useAzureCredentialsForm = ({ const hasArmTemplateUrl = !!getArmTemplateUrlFromCspmPackage(packageInfo); - const setupFormat = azureCredentialsType; + const setupFormat = getSetupFormatFromInput(input, hasArmTemplateUrl); const group = options[azureCredentialsType]; const fields = getInputVarsFields(input, group.fields); @@ -134,6 +151,8 @@ export const useAzureCredentialsForm = ({ setupFormat, }); + const defaultAzureManualCredentialType = getDefaultAzureManualCredentialType(packageInfo); + const onSetupFormatChange = (newSetupFormat: SetupFormat) => { if (newSetupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE) { fieldsSnapshot.current = Object.fromEntries( @@ -155,7 +174,7 @@ export const useAzureCredentialsForm = ({ updatePolicy( getPosturePolicy(newPolicy, input.type, { 'azure.credentials.type': { - value: lastManualCredentialsType.current || DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE, + value: lastManualCredentialsType.current || defaultAzureManualCredentialType, type: 'text', }, ...fieldsSnapshot.current, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts index 0cde5fe86ac6..4c1b04a260df 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts @@ -162,8 +162,15 @@ const getPolicyMock = ( }; const azureVarsMock = { + 'azure.credentials.type': { value: 'arm_template', type: 'text' }, 'azure.account_type': { type: 'text' }, - 'azure.credentials.type': { type: 'text' }, + 'azure.credentials.tenant_id': { type: 'text' }, + 'azure.credentials.client_id': { type: 'text' }, + 'azure.credentials.client_secret': { type: 'text' }, + 'azure.credentials.client_certificate_path': { type: 'text' }, + 'azure.credentials.client_certificate_password': { type: 'text' }, + 'azure.credentials.client_username': { type: 'text' }, + 'azure.credentials.client_password': { type: 'text' }, }; const dataStream = { type: 'logs', dataset: 'cloud_security_posture.findings' }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index b1880eeb0c7e..d0c1f4d454b4 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -1330,6 +1330,27 @@ describe('', () => { ).toBeInTheDocument(); }); + it(`doesnt render ${CLOUDBEAT_AZURE} Manual fields when version is not at least version 1.7.0`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'manual' }, + 'azure.account_type': { value: 'single-account' }, + }); + + const { queryByRole } = render( + + ); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + expect( + queryByRole('option', { name: 'Service principal with Client Secret', selected: true }) + ).not.toBeInTheDocument(); + }); + it(`selects default ${CLOUDBEAT_AZURE} fields`, () => { let policy = getMockPolicyAzure(); policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { @@ -1344,5 +1365,242 @@ describe('', () => { updatedPolicy: policy, }); }); + + it(`renders ${CLOUDBEAT_AZURE} Service Principal with Client Secret fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_secret' }, + }); + + const { getByLabelText, getByRole } = render( + + ); + + expect( + getByRole('option', { name: 'Service principal with Client Secret', selected: true }) + ).toBeInTheDocument(); + expect(getByLabelText('Tenant ID')).toBeInTheDocument(); + expect(getByLabelText('Client ID')).toBeInTheDocument(); + expect(getByLabelText('Client Secret')).toBeInTheDocument(); + }); + + it(`updates ${CLOUDBEAT_AZURE} Service Principal with Client Secret fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_secret' }, + }); + + const { rerender, getByLabelText } = render( + + ); + + userEvent.type(getByLabelText('Tenant ID'), 'a'); + + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.tenant_id': { value: 'a' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client ID'), 'b'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_id': { value: 'b' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client Secret'), 'c'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_secret': { value: 'c' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + }); + }); + + it(`renders Service principal with Client Certificate fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_certificate' }, + }); + + const { getByLabelText, getByRole } = render( + + ); + + expect( + getByRole('option', { name: 'Service principal with Client Certificate', selected: true }) + ).toBeInTheDocument(); + expect(getByLabelText('Tenant ID')).toBeInTheDocument(); + expect(getByLabelText('Client ID')).toBeInTheDocument(); + expect(getByLabelText('Client Certificate Path')).toBeInTheDocument(); + expect(getByLabelText('Client Certificate Password')).toBeInTheDocument(); + }); + + it(`updates Service principal with Client Certificate fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_certificate' }, + }); + + const { rerender, getByLabelText } = render( + + ); + + userEvent.type(getByLabelText('Tenant ID'), 'a'); + + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.tenant_id': { value: 'a' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client ID'), 'b'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_id': { value: 'b' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client Certificate Path'), 'c'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_certificate_path': { value: 'c' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client Certificate Password'), 'd'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_certificate_password': { value: 'd' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + }); + + it(`renders Service principal with Client Username and Password fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_username_and_password' }, + }); + + const { getByLabelText, getByRole } = render( + + ); + + expect( + getByRole('option', { + name: 'Service principal with Client Username and Password', + selected: true, + }) + ).toBeInTheDocument(); + expect(getByLabelText('Tenant ID')).toBeInTheDocument(); + expect(getByLabelText('Client ID')).toBeInTheDocument(); + expect(getByLabelText('Client Username')).toBeInTheDocument(); + expect(getByLabelText('Client Password')).toBeInTheDocument(); + }); + + it(`updates Service principal with Client Username and Password fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_username_and_password' }, + }); + + const { rerender, getByLabelText } = render( + + ); + + userEvent.type(getByLabelText('Tenant ID'), 'a'); + + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.tenant_id': { value: 'a' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client ID'), 'b'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_id': { value: 'b' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client Username'), 'c'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_username': { value: 'c' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + + rerender( + + ); + + userEvent.type(getByLabelText('Client Password'), 'd'); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.client_password': { value: 'd' }, + }); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); }); }); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 92ee1f34a59b..163857b27e0f 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -48,6 +48,7 @@ import { type NewPackagePolicyPostureInput, isPostureInput, getMaxPackageName, + isBelowMinVersion, } from './utils'; import { PolicyTemplateInfo, @@ -138,19 +139,23 @@ const getGcpAccountTypeOptions = (isGcpOrgDisabled: boolean): CspRadioGroupProps }, ]; -const getAzureAccountTypeOptions = (): CspRadioGroupProps['options'] => [ +const getAzureAccountTypeOptions = ( + isAzureOrganizationDisabled: boolean +): CspRadioGroupProps['options'] => [ { id: AZURE_ORGANIZATION_ACCOUNT, label: i18n.translate('xpack.csp.fleetIntegration.azureAccountType.azureOrganizationLabel', { defaultMessage: 'Azure Organization', }), - disabled: true, - tooltip: i18n.translate( - 'xpack.csp.fleetIntegration.azureAccountType.azureOrganizationDisabledTooltip', - { - defaultMessage: 'Coming Soon', - } - ), + disabled: isAzureOrganizationDisabled, + tooltip: isAzureOrganizationDisabled + ? i18n.translate( + 'xpack.csp.fleetIntegration.azureAccountType.azureOrganizationDisabledTooltip', + { + defaultMessage: 'Coming Soon', + } + ) + : undefined, }, { id: AZURE_SINGLE_ACCOUNT, @@ -409,18 +414,26 @@ const getAzureAccountType = ( input: Extract ): AzureAccountType | undefined => input.streams[0].vars?.['azure.account_type']?.value; +const AZURE_ORG_MINIMUM_PACKAGE_VERSION = '1.7.0'; + const AzureAccountTypeSelect = ({ input, newPolicy, updatePolicy, disabled, + packageInfo, }: { input: Extract; newPolicy: NewPackagePolicy; updatePolicy: (updatedPolicy: NewPackagePolicy) => void; disabled: boolean; + packageInfo: PackageInfo; }) => { - const azureAccountTypeOptions = getAzureAccountTypeOptions(); + const isAzureOrganizationDisabled = isBelowMinVersion( + packageInfo.version, + AZURE_ORG_MINIMUM_PACKAGE_VERSION + ); + const azureAccountTypeOptions = getAzureAccountTypeOptions(isAzureOrganizationDisabled); useEffect(() => { if (!getAzureAccountType(input)) { @@ -697,6 +710,7 @@ export const CspPolicyTemplateForm = memo )} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts index b710741652b6..266cd98ab045 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts @@ -10,6 +10,7 @@ import { getPostureInputHiddenVars, getPosturePolicy, getCspmCloudShellDefaultValue, + isBelowMinVersion, } from './utils'; import { getMockPolicyAWS, getMockPolicyK8s, getMockPolicyEKS } from './mocks'; import type { PackageInfo } from '@kbn/fleet-plugin/common'; @@ -252,3 +253,30 @@ describe('getCspmCloudShellDefaultValue', () => { expect(result).toBe('URL'); }); }); + +describe('isBelowMinVersion', () => { + test.each([ + ['1.2.3', '2.0.0', true], // Version '1.2.3' is below '2.0.0', expect true + ['1.2.3-preview20', '2.0.0', true], // Version '1.2.3-preview20' is below '2.0.0', expect true + ['2.0.0', '1.2.3', false], // Version '2.0.0' is not below '1.2.3', expect false + ['1.2.3', '1.2.3', false], // Version '1.2.3' is not below itself, expect false + ])('returns expected boolean for version and minVersion', (version, minVersion, expected) => { + const result = isBelowMinVersion(version, minVersion); + + expect(result).toBe(expected); + }); + + test.each([ + ['invalid', '1.0.0'], // Invalid version, expect error + ['1.2', '1.0.0'], // Invalid version, expect error + ['', '1.0.0'], // Empty version, expect error + ['1.0.0', ''], // Empty minVersion, expect error + ['', ''], // Empty version and minVersion, expect error + ])('semver return errors when invalid versions are used', (version, minVersion) => { + try { + isBelowMinVersion(version, minVersion); + } catch (error) { + expect(error).toBeDefined(); + } + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 148a482714a1..ae7c02ade79d 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -13,6 +13,9 @@ import type { RegistryVarsEntry, } from '@kbn/fleet-plugin/common'; import merge from 'lodash/merge'; +import semverValid from 'semver/functions/valid'; +import semverCoerce from 'semver/functions/coerce'; +import semverLt from 'semver/functions/lt'; import { CLOUDBEAT_AWS, CLOUDBEAT_EKS, @@ -263,3 +266,9 @@ export const getCspmCloudShellDefaultValue = (packageInfo: PackageInfo): string return cloudShellUrl; }; + +export const isBelowMinVersion = (version: string, minVersion: string) => { + const semanticVersion = semverValid(version); + const versionNumberOnly = semverCoerce(semanticVersion) || ''; + return semverLt(versionNumberOnly, minVersion); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx b/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx index 644455e5a2a6..a2d8f4fe32c0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx @@ -6,15 +6,8 @@ */ import React from 'react'; -import { EuiEmptyPrompt, EuiPageSection } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiLink, EuiPageSection } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { SubscriptionLink } from '@kbn/subscription-tracking'; -import type { SubscriptionContextData } from '@kbn/subscription-tracking'; - -const subscriptionContext: SubscriptionContextData = { - feature: 'cloud-security-posture', - source: 'security__cloud-security-posture', -}; export const SubscriptionNotAllowed = ({ licenseManagementLocator, @@ -41,12 +34,12 @@ export const SubscriptionNotAllowed = ({ defaultMessage="To use these cloud security features, you must {link}." values={{ link: ( - + - + ), }} /> diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index 91589cee3dcf..1f603a67ae1f 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -39,3 +39,7 @@ export const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vulnerabilities_cvss_score export const TAKE_ACTION_SUBJ = 'csp:take_action'; export const CREATE_RULE_ACTION_SUBJ = 'csp:create_rule'; + +export const CSP_GROUPING = 'cloudSecurityGrouping'; +export const CSP_GROUPING_LOADING = 'cloudSecurityGroupingLoading'; +export const CSP_FINDINGS_COMPLIANCE_SCORE = 'cloudSecurityFindingsComplianceScore'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/compliance_score_chart.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/compliance_score_chart.tsx index 956f63ed2d3b..2067a9c98fd2 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/compliance_score_chart.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_charts/compliance_score_chart.tsx @@ -30,6 +30,7 @@ import { import { FormattedDate, FormattedTime } from '@kbn/i18n-react'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; import { DASHBOARD_COMPLIANCE_SCORE_CHART } from '../test_subjects'; import { statusColors } from '../../../common/constants'; import { RULE_FAILED, RULE_PASSED } from '../../../../common/constants'; @@ -45,6 +46,123 @@ interface ComplianceScoreChartProps { onEvalCounterClick: (evaluation: Evaluation) => void; } +const CounterButtonLink = ({ + text, + count, + color, + onClick, +}: { + count: number; + text: string; + color: EuiTextProps['color']; + onClick: EuiLinkButtonProps['onClick']; +}) => { + const { euiTheme } = useEuiTheme(); + + return ( + <> + + {text} + + + + + +   + + + + ); +}; + +const CompactPercentageLabels = ({ + onEvalCounterClick, + stats, +}: { + onEvalCounterClick: (evaluation: Evaluation) => void; + stats: { totalPassed: number; totalFailed: number }; +}) => ( + <> + onEvalCounterClick(RULE_PASSED)} + tooltipContent={i18n.translate( + 'xpack.csp.complianceScoreChart.counterLink.passedFindingsTooltip', + { defaultMessage: 'Passed findings' } + )} + /> +  -  + onEvalCounterClick(RULE_FAILED)} + tooltipContent={i18n.translate( + 'xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip', + { defaultMessage: 'Failed findings' } + )} + /> + +); + +const NonCompactPercentageLabels = ({ + onEvalCounterClick, + stats, +}: { + onEvalCounterClick: (evaluation: Evaluation) => void; + stats: { totalPassed: number; totalFailed: number }; +}) => { + const { euiTheme } = useEuiTheme(); + const borderLeftStyles = { borderLeft: euiTheme.border.thin, paddingLeft: euiTheme.size.m }; + return ( + + + onEvalCounterClick(RULE_PASSED)} + /> + + + onEvalCounterClick(RULE_FAILED)} + /> + + + ); +}; + const getPostureScorePercentage = (postureScore: number): string => `${Math.round(postureScore)}%`; const PercentageInfo = ({ @@ -177,27 +295,17 @@ export const ComplianceScoreChart = ({ alignItems="flexStart" style={{ paddingRight: euiTheme.size.xl }} > - onEvalCounterClick(RULE_PASSED)} - tooltipContent={i18n.translate( - 'xpack.csp.complianceScoreChart.counterLink.passedFindingsTooltip', - { defaultMessage: 'Passed findings' } - )} - /> -  -  - onEvalCounterClick(RULE_FAILED)} - tooltipContent={i18n.translate( - 'xpack.csp.complianceScoreChart.counterLink.failedFindingsTooltip', - { defaultMessage: 'Failed findings' } - )} - /> + {compact ? ( + + ) : ( + + )}
    diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.test.tsx index 1c8da9db2787..18e5118f772e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.test.tsx @@ -32,7 +32,11 @@ import { KSPM_INTEGRATION_NOT_INSTALLED_TEST_SUBJECT, PACKAGE_NOT_INSTALLED_TEST_SUBJECT, } from '../../components/cloud_posture_page'; -import { BaseCspSetupStatus, ComplianceDashboardData, CspStatusCode } from '../../../common/types'; +import { + BaseCspSetupStatus, + ComplianceDashboardDataV2, + CspStatusCode, +} from '../../../common/types'; jest.mock('../../common/api/use_setup_status_api'); jest.mock('../../common/api/use_stats_api'); @@ -779,31 +783,31 @@ describe('getDefaultTab', () => { it('returns CSPM tab if only CSPM has findings', () => { const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus; - const cspmStats = getStatsMock(1) as ComplianceDashboardData; - const kspmStats = getStatsMock(0) as ComplianceDashboardData; + const cspmStats = getStatsMock(1) as ComplianceDashboardDataV2; + const kspmStats = getStatsMock(0) as ComplianceDashboardDataV2; expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('cspm'); }); it('returns CSPM tab if both CSPM and KSPM has findings', () => { const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus; - const cspmStats = getStatsMock(1) as ComplianceDashboardData; - const kspmStats = getStatsMock(1) as ComplianceDashboardData; + const cspmStats = getStatsMock(1) as ComplianceDashboardDataV2; + const kspmStats = getStatsMock(1) as ComplianceDashboardDataV2; expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('cspm'); }); it('returns KSPM tab if only KSPM has findings', () => { const pluginStatus = getPluginStatusMock('indexed', 'indexed') as BaseCspSetupStatus; - const cspmStats = getStatsMock(0) as ComplianceDashboardData; - const kspmStats = getStatsMock(1) as ComplianceDashboardData; + const cspmStats = getStatsMock(0) as ComplianceDashboardDataV2; + const kspmStats = getStatsMock(1) as ComplianceDashboardDataV2; expect(getDefaultTab(pluginStatus, cspmStats, kspmStats)).toEqual('kspm'); }); it('when no findings preffers CSPM tab unless not-installed or unprivileged', () => { - const cspmStats = getStatsMock(0) as ComplianceDashboardData; - const kspmStats = getStatsMock(0) as ComplianceDashboardData; + const cspmStats = getStatsMock(0) as ComplianceDashboardDataV2; + const kspmStats = getStatsMock(0) as ComplianceDashboardDataV2; const CspStatusCodeArray: CspStatusCode[] = [ 'indexed', 'indexing', @@ -833,13 +837,13 @@ describe('getDefaultTab', () => { }); it('returns CSPM tab is plugin status and kspm status is not provided', () => { - const cspmStats = getStatsMock(1) as ComplianceDashboardData; + const cspmStats = getStatsMock(1) as ComplianceDashboardDataV2; expect(getDefaultTab(undefined, cspmStats, undefined)).toEqual('cspm'); }); it('returns KSPM tab is plugin status and csp status is not provided', () => { - const kspmStats = getStatsMock(1) as ComplianceDashboardData; + const kspmStats = getStatsMock(1) as ComplianceDashboardDataV2; expect(getDefaultTab(undefined, undefined, kspmStats)).toEqual('kspm'); }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.tsx index 8b7b0d5c841a..9e3b8df0c1d3 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/compliance_dashboard.tsx @@ -15,7 +15,7 @@ import { NO_FINDINGS_STATUS_TEST_SUBJ } from '../../components/test_subjects'; import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link'; import type { PosturePolicyTemplate, - ComplianceDashboardData, + ComplianceDashboardDataV2, BaseCspSetupStatus, } from '../../../common/types'; import { CloudPosturePageTitle } from '../../components/cloud_posture_page_title'; @@ -127,7 +127,7 @@ const IntegrationPostureDashboard = ({ isIntegrationInstalled, dashboardType, }: { - complianceData: ComplianceDashboardData | undefined; + complianceData: ComplianceDashboardDataV2 | undefined; notInstalledConfig: CspNoDataPageProps; isIntegrationInstalled?: boolean; dashboardType: PosturePolicyTemplate; @@ -188,8 +188,8 @@ const IntegrationPostureDashboard = ({ export const getDefaultTab = ( pluginStatus?: BaseCspSetupStatus, - cspmStats?: ComplianceDashboardData, - kspmStats?: ComplianceDashboardData + cspmStats?: ComplianceDashboardDataV2, + kspmStats?: ComplianceDashboardDataV2 ) => { const cspmTotalFindings = cspmStats?.stats.totalFindings; const kspmTotalFindings = kspmStats?.stats.totalFindings; @@ -223,7 +223,7 @@ export const getDefaultTab = ( return preferredDashboard; }; -const determineDashboardDataRefetchInterval = (data: ComplianceDashboardData | undefined) => { +const determineDashboardDataRefetchInterval = (data: ComplianceDashboardDataV2 | undefined) => { if (data?.stats.totalFindings === 0) { return NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS; } @@ -258,7 +258,7 @@ const TabContent = ({ posturetype }: { posturetype: PosturePolicyTemplate }) => let integrationLink; let dataTestSubj; let policyTemplate: PosturePolicyTemplate; - let getDashboardData: UseQueryResult; + let getDashboardData: UseQueryResult; switch (posturetype) { case POSTURE_TYPE_CSPM: diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmark_details_box.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmark_details_box.tsx new file mode 100644 index 000000000000..de982b50f48f --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmark_details_box.tsx @@ -0,0 +1,176 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiText, + EuiTitle, + EuiToolTip, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { getBenchmarkIdQuery } from './benchmarks_section'; +import { BenchmarkData } from '../../../../common/types'; +import { useNavigateFindings } from '../../../common/hooks/use_navigate_findings'; +import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon'; +import cisLogoIcon from '../../../assets/icons/cis_logo.svg'; +export const BenchmarkDetailsBox = ({ benchmark }: { benchmark: BenchmarkData }) => { + const navToFindings = useNavigateFindings(); + + const handleBenchmarkClick = () => { + return navToFindings(getBenchmarkIdQuery(benchmark)); + }; + + const getBenchmarkInfo = ( + benchmarkId: string, + cloudAssetCount: number + ): { name: string; assetType: string } => { + const benchmarks: Record = { + cis_gcp: { + name: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisGcpBenchmarkName', + { + defaultMessage: 'CIS GCP', + } + ), + assetType: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisGcpBenchmarkAssetType', + { + defaultMessage: '{count, plural, one {# Project} other {# Projects}}', + values: { count: cloudAssetCount }, + } + ), + }, + cis_aws: { + name: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisAwsBenchmarkName', + { + defaultMessage: 'CIS AWS', + } + ), + assetType: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisAwsBenchmarkAssetType', + { + defaultMessage: '{count, plural, one {# Account} other {# Accounts}}', + values: { count: cloudAssetCount }, + } + ), + }, + cis_azure: { + name: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisAzureBenchmarkName', + { + defaultMessage: 'CIS Azure', + } + ), + assetType: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisAzureBenchmarkAssetType', + { + defaultMessage: '{count, plural, one {# Subscription} other {# Subscriptions}}', + values: { count: cloudAssetCount }, + } + ), + }, + cis_k8s: { + name: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisK8sBenchmarkName', + { + defaultMessage: 'CIS Kubernetes', + } + ), + assetType: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisK8sBenchmarkAssetType', + { + defaultMessage: '{count, plural, one {# Cluster} other {# Clusters}}', + values: { count: cloudAssetCount }, + } + ), + }, + cis_eks: { + name: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisEksBenchmarkName', + { + defaultMessage: 'CIS EKS', + } + ), + assetType: i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisEksBenchmarkAssetType', + { + defaultMessage: '{count, plural, one {# Cluster} other {# Clusters}}', + values: { count: cloudAssetCount }, + } + ), + }, + }; + return benchmarks[benchmarkId]; + }; + + const cisTooltip = i18n.translate( + 'xpack.csp.dashboard.benchmarkSection.benchmarkName.cisBenchmarkTooltip', + { + defaultMessage: 'Center of Internet Security', + } + ); + + const benchmarkInfo = getBenchmarkInfo(benchmark.meta.benchmarkId, benchmark.meta.assetCount); + + const benchmarkId = benchmark.meta.benchmarkId; + const benchmarkVersion = benchmark.meta.benchmarkVersion; + const benchmarkName = benchmark.meta.benchmarkName; + + return ( + + + + + + + + + } + > + + +
    {benchmarkInfo.name}
    +
    +
    +
    + + + {benchmarkInfo.assetType} + +
    + + + + + + + + {benchmarkVersion} + + + +
    + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.test.tsx index 5293eec114fc..79b644af3779 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { BenchmarksSection } from './benchmarks_section'; -import { getMockDashboardData, getClusterMockData } from '../mock'; +import { getMockDashboardData, getBenchmarkMockData } from '../mock'; import { TestProvider } from '../../../test/test_provider'; import { KSPM_POLICY_TEMPLATE } from '../../../../common/constants'; import { @@ -30,22 +30,22 @@ describe('', () => { describe('Sorting', () => { const mockDashboardDataCopy = getMockDashboardData(); - const clusterMockDataCopy = getClusterMockData(); - clusterMockDataCopy.stats.postureScore = 50; - clusterMockDataCopy.meta.assetIdentifierId = '1'; + const benchmarkMockDataCopy = getBenchmarkMockData(); + benchmarkMockDataCopy.stats.postureScore = 50; + benchmarkMockDataCopy.meta.benchmarkId = 'cis_aws'; - const clusterMockDataCopy1 = getClusterMockData(); - clusterMockDataCopy1.stats.postureScore = 95; - clusterMockDataCopy1.meta.assetIdentifierId = '2'; + const benchmarkMockDataCopy1 = getBenchmarkMockData(); + benchmarkMockDataCopy1.stats.postureScore = 95; + benchmarkMockDataCopy1.meta.benchmarkId = 'cis_azure'; - const clusterMockDataCopy2 = getClusterMockData(); - clusterMockDataCopy2.stats.postureScore = 45; - clusterMockDataCopy2.meta.assetIdentifierId = '3'; + const benchmarkMockDataCopy2 = getBenchmarkMockData(); + benchmarkMockDataCopy2.stats.postureScore = 45; + benchmarkMockDataCopy2.meta.benchmarkId = 'cis_gcp'; - mockDashboardDataCopy.clusters = [ - clusterMockDataCopy, - clusterMockDataCopy1, - clusterMockDataCopy2, + mockDashboardDataCopy.benchmarks = [ + benchmarkMockDataCopy, + benchmarkMockDataCopy1, + benchmarkMockDataCopy2, ]; it('sorts by ascending order of compliance scores', () => { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx index 96da28e0c801..2ac91288475d 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/benchmarks_section.tsx @@ -7,102 +7,102 @@ import React, { useMemo } from 'react'; import useLocalStorage from 'react-use/lib/useLocalStorage'; -import type { EuiIconProps } from '@elastic/eui'; +import { EuiIconProps, EuiPanel } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTitle, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import type { - Cluster, - ComplianceDashboardData, + BenchmarkData, + ComplianceDashboardDataV2, Evaluation, PosturePolicyTemplate, } from '../../../../common/types'; -import { LOCAL_STORAGE_DASHBOARD_CLUSTER_SORT_KEY } from '../../../common/constants'; import { RisksTable } from '../compliance_charts/risks_table'; -import { - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, - RULE_FAILED, -} from '../../../../common/constants'; +import { RULE_FAILED } from '../../../../common/constants'; +import { LOCAL_STORAGE_DASHBOARD_BENCHMARK_SORT_KEY } from '../../../common/constants'; import { NavFilter, useNavigateFindings } from '../../../common/hooks/use_navigate_findings'; -import { ClusterDetailsBox } from './cluster_details_box'; import { dashboardColumnsGrow, getPolicyTemplateQuery } from './summary_section'; import { DASHBOARD_TABLE_COLUMN_SCORE_TEST_ID, DASHBOARD_TABLE_HEADER_SCORE_TEST_ID, } from '../test_subjects'; import { ComplianceScoreChart } from '../compliance_charts/compliance_score_chart'; +import { BenchmarkDetailsBox } from './benchmark_details_box'; +const BENCHMARK_DEFAULT_SORT_ORDER = 'asc'; -const CLUSTER_DEFAULT_SORT_ORDER = 'asc'; - -export const getClusterIdQuery = (cluster: Cluster): NavFilter => { - if (cluster.meta.benchmark.posture_type === CSPM_POLICY_TEMPLATE) { - // TODO: remove assertion after typing CspFinding as discriminating union - return { 'cloud.account.id': cluster.meta.cloud!.account.id }; - } - return { cluster_id: cluster.meta.assetIdentifierId }; +export const getBenchmarkIdQuery = (benchmark: BenchmarkData): NavFilter => { + return { + 'rule.benchmark.id': benchmark.meta.benchmarkId, + 'rule.benchmark.version': benchmark.meta.benchmarkVersion, + }; }; export const BenchmarksSection = ({ complianceData, dashboardType, }: { - complianceData: ComplianceDashboardData; + complianceData: ComplianceDashboardDataV2; dashboardType: PosturePolicyTemplate; }) => { const { euiTheme } = useEuiTheme(); const navToFindings = useNavigateFindings(); - const [clusterSorting, setClusterSorting] = useLocalStorage<'asc' | 'desc'>( - LOCAL_STORAGE_DASHBOARD_CLUSTER_SORT_KEY, - CLUSTER_DEFAULT_SORT_ORDER + const [benchmarkSorting, setBenchmarkSorting] = useLocalStorage<'asc' | 'desc'>( + LOCAL_STORAGE_DASHBOARD_BENCHMARK_SORT_KEY, + BENCHMARK_DEFAULT_SORT_ORDER ); - const isClusterSortingAsc = clusterSorting === 'asc'; + const isBenchmarkSortingAsc = benchmarkSorting === 'asc'; - const clusterSortingIcon: EuiIconProps['type'] = isClusterSortingAsc ? 'sortUp' : 'sortDown'; + const benchmarkSortingIcon: EuiIconProps['type'] = isBenchmarkSortingAsc ? 'sortUp' : 'sortDown'; - const navToFindingsByClusterAndEvaluation = (cluster: Cluster, evaluation: Evaluation) => { + const navToFindingsByBenchmarkAndEvaluation = ( + benchmark: BenchmarkData, + evaluation: Evaluation + ) => { navToFindings({ ...getPolicyTemplateQuery(dashboardType), - ...getClusterIdQuery(cluster), + ...getBenchmarkIdQuery(benchmark), 'result.evaluation': evaluation, }); }; - const navToFailedFindingsByClusterAndSection = (cluster: Cluster, ruleSection: string) => { + const navToFailedFindingsByBenchmarkAndSection = ( + benchmark: BenchmarkData, + ruleSection: string + ) => { navToFindings({ ...getPolicyTemplateQuery(dashboardType), - ...getClusterIdQuery(cluster), + ...getBenchmarkIdQuery(benchmark), 'rule.section': ruleSection, 'result.evaluation': RULE_FAILED, }); }; - const navToFailedFindingsByCluster = (cluster: Cluster) => { - navToFindingsByClusterAndEvaluation(cluster, RULE_FAILED); + const navToFailedFindingsByBenchmark = (benchmark: BenchmarkData) => { + navToFindingsByBenchmarkAndEvaluation(benchmark, RULE_FAILED); }; - const toggleClustersSortingDirection = () => { - setClusterSorting(isClusterSortingAsc ? 'desc' : 'asc'); + const toggleBenchmarkSortingDirection = () => { + setBenchmarkSorting(isBenchmarkSortingAsc ? 'desc' : 'asc'); }; - const clusters = useMemo(() => { - return [...complianceData.clusters].sort((clusterA, clusterB) => - isClusterSortingAsc - ? clusterA.stats.postureScore - clusterB.stats.postureScore - : clusterB.stats.postureScore - clusterA.stats.postureScore + const benchmarks = useMemo(() => { + return [...complianceData.benchmarks].sort((benchmarkA, benchmarkB) => + isBenchmarkSortingAsc + ? benchmarkA.stats.postureScore - benchmarkB.stats.postureScore + : benchmarkB.stats.postureScore - benchmarkA.stats.postureScore ); - }, [complianceData.clusters, isClusterSortingAsc]); + }, [complianceData.benchmarks, isBenchmarkSortingAsc]); return ( - <> +
    - {dashboardType === KSPM_POLICY_TEMPLATE ? ( - - ) : ( - - )} +
    @@ -155,18 +148,20 @@ export const BenchmarksSection = ({
    - {clusters.map((cluster) => ( + {benchmarks.map((benchmark) => ( - + - navToFindingsByClusterAndEvaluation(cluster, evaluation) + navToFindingsByBenchmarkAndEvaluation(benchmark, evaluation) } /> @@ -193,27 +188,23 @@ export const BenchmarksSection = ({ > - navToFailedFindingsByClusterAndSection(cluster, resourceTypeName) + navToFailedFindingsByBenchmarkAndSection(benchmark, resourceTypeName) } viewAllButtonTitle={i18n.translate( - 'xpack.csp.dashboard.risksTable.clusterCardViewAllButtonTitle', + 'xpack.csp.dashboard.risksTable.benchmarkCardViewAllButtonTitle', { - defaultMessage: 'View all failed findings for this {postureAsset}', - values: { - postureAsset: - dashboardType === CSPM_POLICY_TEMPLATE ? 'cloud account' : 'cluster', - }, + defaultMessage: 'View all failed findings for this benchmark', } )} - onViewAllClick={() => navToFailedFindingsByCluster(cluster)} + onViewAllClick={() => navToFailedFindingsByBenchmark(benchmark)} /> ))} - +
    ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/cluster_details_box.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/cluster_details_box.tsx deleted file mode 100644 index 7b42445d26b9..000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/cluster_details_box.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiText, - EuiTitle, - EuiToolTip, - useEuiTheme, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import moment from 'moment'; -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { getClusterIdQuery } from './benchmarks_section'; -import { CSPM_POLICY_TEMPLATE, INTERNAL_FEATURE_FLAGS } from '../../../../common/constants'; -import { Cluster } from '../../../../common/types'; -import { useNavigateFindings } from '../../../common/hooks/use_navigate_findings'; -import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon'; - -const defaultClusterTitle = i18n.translate( - 'xpack.csp.dashboard.benchmarkSection.defaultClusterTitle', - { defaultMessage: 'ID' } -); - -const getClusterTitle = (cluster: Cluster) => { - if (cluster.meta.benchmark.posture_type === CSPM_POLICY_TEMPLATE) { - return cluster.meta.cloud?.account.name; - } - - return cluster.meta.cluster?.name; -}; - -const getClusterId = (cluster: Cluster) => { - const assetIdentifierId = cluster.meta.assetIdentifierId; - if (cluster.meta.benchmark.posture_type === CSPM_POLICY_TEMPLATE) return assetIdentifierId; - return assetIdentifierId.slice(0, 6); -}; - -export const ClusterDetailsBox = ({ cluster }: { cluster: Cluster }) => { - const { euiTheme } = useEuiTheme(); - const navToFindings = useNavigateFindings(); - - const assetId = getClusterId(cluster); - const title = getClusterTitle(cluster) || defaultClusterTitle; - - const handleClusterTitleClick = () => { - return navToFindings(getClusterIdQuery(cluster)); - }; - - return ( - - - - - - - - - } - > - - -
    - -
    -
    -
    -
    - - - -
    - - - - {INTERNAL_FEATURE_FLAGS.showManageRulesMock && ( - - - - - - )} -
    - ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx index 50d549338746..ca4a55c45ebd 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx @@ -6,7 +6,13 @@ */ import React, { useMemo } from 'react'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiFlexItemProps } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlexItemProps, + useEuiTheme, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { useCspIntegrationLink } from '../../../common/navigation/use_csp_integration_link'; @@ -16,16 +22,12 @@ import { CompactFormattedNumber } from '../../../components/compact_formatted_nu import { ChartPanel } from '../../../components/chart_panel'; import { ComplianceScoreChart } from '../compliance_charts/compliance_score_chart'; import type { - ComplianceDashboardData, + ComplianceDashboardDataV2, Evaluation, PosturePolicyTemplate, } from '../../../../common/types'; import { RisksTable } from '../compliance_charts/risks_table'; -import { - NavFilter, - useNavigateFindings, - useNavigateFindingsByResource, -} from '../../../common/hooks/use_navigate_findings'; +import { NavFilter, useNavigateFindings } from '../../../common/hooks/use_navigate_findings'; import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE, @@ -52,13 +54,14 @@ export const SummarySection = ({ complianceData, }: { dashboardType: PosturePolicyTemplate; - complianceData: ComplianceDashboardData; + complianceData: ComplianceDashboardDataV2; }) => { const navToFindings = useNavigateFindings(); - const navToFindingsByResource = useNavigateFindingsByResource(); const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE); const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE); + const { euiTheme } = useEuiTheme(); + const handleEvalCounterClick = (evaluation: Evaluation) => { navToFindings({ 'result.evaluation': evaluation, ...getPolicyTemplateQuery(dashboardType) }); }; @@ -89,7 +92,7 @@ export const SummarySection = ({ 'xpack.csp.dashboard.summarySection.counterCard.accountsEvaluatedDescription', { defaultMessage: 'Accounts Evaluated' } ), - title: , + title: , button: ( { - navToFindingsByResource(getPolicyTemplateQuery(dashboardType)); + navToFindings(getPolicyTemplateQuery(dashboardType)); }} > {i18n.translate( @@ -133,21 +136,20 @@ export const SummarySection = ({ }, ], [ - complianceData.clusters, + complianceData.benchmarks, complianceData.stats.resourcesEvaluated, cspmIntegrationLink, dashboardType, kspmIntegrationLink, - navToFindingsByResource, + navToFindings, ] ); - - const chartTitle = i18n.translate('xpack.csp.dashboard.summarySection.postureScorePanelTitle', { - defaultMessage: 'Overall {type} Posture Score', - values: { - type: dashboardType === KSPM_POLICY_TEMPLATE ? 'Kubernetes' : 'Cloud', - }, - }); + const chartTitle = i18n.translate( + 'xpack.csp.dashboard.summarySection.complianceScorePanelTitle', + { + defaultMessage: 'Compliance Score', + } + ); return ( ({ +export const getMockDashboardData = () => ({ + ...mockDashboardData, +}); + +export const getBenchmarkMockData = (): BenchmarkData => ({ meta: { - assetIdentifierId: '8f9c5b98-cc02-4827-8c82-316e2cc25870', - lastUpdate: '2022-11-07T13:14:34.990Z', - cloud: { - provider: 'aws', - account: { - name: 'build-security-dev', - id: '704479110758', - }, - }, - benchmark: { - name: 'CIS Amazon Web Services Foundations', - rule_number: '1.4', - id: 'cis_aws', - posture_type: 'cspm', - version: 'v1.5.0', - }, - cluster: { - name: '8f9c5b98-cc02-4827-8c82-316e2cc25870', - }, + benchmarkId: 'cis_aws', + benchmarkVersion: '1.2.3', + benchmarkName: 'CIS AWS Foundations Benchmark', + assetCount: 153, }, stats: { totalFailed: 17, @@ -104,11 +93,7 @@ export const getClusterMockData = (): Cluster => ({ ], }); -export const getMockDashboardData = () => ({ - ...mockDashboardData, -}); - -export const mockDashboardData: ComplianceDashboardData = { +export const mockDashboardData: ComplianceDashboardDataV2 = { stats: { totalFailed: 17, totalPassed: 155, @@ -167,7 +152,7 @@ export const mockDashboardData: ComplianceDashboardData = { postureScore: 50.0, }, ], - clusters: [getClusterMockData()], + benchmarks: [getBenchmarkMockData()], trend: [ { timestamp: '2022-05-22T11:03:00.000Z', diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts new file mode 100644 index 000000000000..e2e4585906ba --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { GroupOption } from '@kbn/securitysolution-grouping'; +import { FindingsBaseURLQuery } from '../../../common/types'; +import { CloudSecurityDefaultColumn } from '../../../components/cloud_security_data_table'; + +export const FINDINGS_UNIT = (totalCount: number) => + i18n.translate('xpack.csp.findings.unit', { + values: { totalCount }, + defaultMessage: `{totalCount, plural, =1 {finding} other {findings}}`, + }); + +export const GROUPING_OPTIONS = { + RESOURCE_NAME: 'resource.name', + RULE_NAME: 'rule.name', + CLOUD_ACCOUNT_NAME: 'cloud.account.name', + ORCHESTRATOR_CLUSTER_NAME: 'orchestrator.cluster.name', +}; + +export const NULL_GROUPING_UNIT = i18n.translate('xpack.csp.findings.grouping.nullGroupUnit', { + defaultMessage: 'findings', +}); + +export const NULL_GROUPING_MESSAGES = { + RESOURCE_NAME: i18n.translate('xpack.csp.findings.grouping.resource.nullGroupTitle', { + defaultMessage: 'No resource', + }), + RULE_NAME: i18n.translate('xpack.csp.findings.grouping.rule.nullGroupTitle', { + defaultMessage: 'No rule', + }), + CLOUD_ACCOUNT_NAME: i18n.translate('xpack.csp.findings.grouping.cloudAccount.nullGroupTitle', { + defaultMessage: 'No cloud account', + }), + ORCHESTRATOR_CLUSTER_NAME: i18n.translate( + 'xpack.csp.findings.grouping.kubernetes.nullGroupTitle', + { defaultMessage: 'No Kubernetes cluster' } + ), + DEFAULT: i18n.translate('xpack.csp.findings.grouping.default.nullGroupTitle', { + defaultMessage: 'No grouping', + }), +}; + +export const defaultGroupingOptions: GroupOption[] = [ + { + label: i18n.translate('xpack.csp.findings.latestFindings.groupByResource', { + defaultMessage: 'Resource', + }), + key: GROUPING_OPTIONS.RESOURCE_NAME, + }, + { + label: i18n.translate('xpack.csp.findings.latestFindings.groupByRuleName', { + defaultMessage: 'Rule name', + }), + key: GROUPING_OPTIONS.RULE_NAME, + }, + { + label: i18n.translate('xpack.csp.findings.latestFindings.groupByCloudAccount', { + defaultMessage: 'Cloud account', + }), + key: GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME, + }, + { + label: i18n.translate('xpack.csp.findings.latestFindings.groupByKubernetesCluster', { + defaultMessage: 'Kubernetes cluster', + }), + key: GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME, + }, +]; + +export const groupingTitle = i18n.translate('xpack.csp.findings.latestFindings.groupBy', { + defaultMessage: 'Group findings by', +}); + +export const DEFAULT_TABLE_HEIGHT = 512; + +export const getDefaultQuery = ({ + query, + filters, +}: FindingsBaseURLQuery): FindingsBaseURLQuery & { + sort: string[][]; +} => ({ + query, + filters, + sort: [['@timestamp', 'desc']], +}); + +export const defaultColumns: CloudSecurityDefaultColumn[] = [ + { id: 'result.evaluation', width: 80 }, + { id: 'resource.id' }, + { id: 'resource.name' }, + { id: 'resource.sub_type' }, + { id: 'rule.benchmark.rule_number' }, + { id: 'rule.name' }, + { id: 'rule.section' }, + { id: '@timestamp' }, +]; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx index 9abae7af4a21..9d536f0f0b18 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx @@ -4,180 +4,97 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useMemo } from 'react'; -import { EuiDataGridCellValueElementProps, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { DataTableRecord } from '@kbn/discover-utils/types'; -import { Filter, Query } from '@kbn/es-query'; -import { TimestampTableCell } from '../../../components/timestamp_table_cell'; -import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; -import type { Evaluation } from '../../../../common/types'; -import type { FindingsBaseProps, FindingsBaseURLQuery } from '../../../common/types'; +import React, { useCallback } from 'react'; +import { Filter } from '@kbn/es-query'; +import { EuiSpacer } from '@elastic/eui'; +import { EmptyState } from '../../../components/empty_state'; +import { CloudSecurityGrouping } from '../../../components/cloud_security_grouping'; +import type { FindingsBaseProps } from '../../../common/types'; import { FindingsSearchBar } from '../layout/findings_search_bar'; -import * as TEST_SUBJECTS from '../test_subjects'; -import { useLatestFindings } from './use_latest_findings'; +import { DEFAULT_TABLE_HEIGHT } from './constants'; +import { useLatestFindingsGrouping } from './use_latest_findings_grouping'; +import { LatestFindingsTable } from './latest_findings_table'; +import { groupPanelRenderer, groupStatsRenderer } from './latest_findings_group_renderer'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; -import { getFilters } from '../utils/utils'; import { ErrorCallout } from '../layout/error_callout'; -import { LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY } from '../../../common/constants'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; -import { useCloudPostureTable } from '../../../common/hooks/use_cloud_posture_table'; -import { - CloudSecurityDataTable, - CloudSecurityDefaultColumn, -} from '../../../components/cloud_security_data_table'; -import { FindingsRuleFlyout } from '../findings_flyout/findings_flyout'; - -const getDefaultQuery = ({ - query, - filters, -}: { - query: Query; - filters: Filter[]; -}): FindingsBaseURLQuery & { - sort: string[][]; -} => ({ - query, - filters, - sort: [['@timestamp', 'desc']], -}); - -const defaultColumns: CloudSecurityDefaultColumn[] = [ - { id: 'result.evaluation', width: 80 }, - { id: 'resource.id' }, - { id: 'resource.name' }, - { id: 'resource.sub_type' }, - { id: 'rule.benchmark.rule_number' }, - { id: 'rule.name' }, - { id: 'rule.section' }, - { id: '@timestamp' }, -]; - -/** - * Type Guard for checking if the given source is a CspFinding - */ -const isCspFinding = (source: Record | undefined): source is CspFinding => { - return source?.result?.evaluation !== undefined; -}; - -/** - * This Wrapper component renders the children if the given row is a CspFinding - * it uses React's Render Props pattern - */ -const CspFindingRenderer = ({ - row, - children, -}: { - row: DataTableRecord; - children: ({ finding }: { finding: CspFinding }) => JSX.Element; -}) => { - const source = row.raw._source; - const finding = isCspFinding(source) && (source as CspFinding); - if (!finding) return <>; - return children({ finding }); -}; - -/** - * Flyout component for the latest findings table - */ -const flyoutComponent = (row: DataTableRecord, onCloseFlyout: () => void): JSX.Element => { - return ( - - {({ finding }) => } - - ); -}; - -const columnsLocalStorageKey = 'cloudPosture:latestFindings:columns'; - -const title = i18n.translate('xpack.csp.findings.latestFindings.tableRowTypeLabel', { - defaultMessage: 'Findings', -}); - -const customCellRenderer = (rows: DataTableRecord[]) => ({ - 'result.evaluation': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( - - {({ finding }) => } - - ), - '@timestamp': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( - - {({ finding }) => } - - ), -}); export const LatestFindingsContainer = ({ dataView }: FindingsBaseProps) => { - const cloudPostureTable = useCloudPostureTable({ - dataView, - paginationLocalStorageKey: LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY, - columnsLocalStorageKey, - defaultQuery: getDefaultQuery, - }); - - const { query, sort, queryError, setUrlQuery, filters, getRowsFromPages } = cloudPostureTable; + const renderChildComponent = useCallback( + (groupFilters: Filter[]) => { + return ( + + ); + }, + [dataView] + ); const { - data, - error: fetchError, + isGroupSelected, + groupData, + grouping, isFetching, - fetchNextPage, - } = useLatestFindings({ - query, - sort, - enabled: !queryError, - }); - - const rows = useMemo(() => getRowsFromPages(data?.pages), [data?.pages, getRowsFromPages]); - - const error = fetchError || queryError; - - const passed = data?.pages[0].count.passed || 0; - const failed = data?.pages[0].count.failed || 0; - const total = data?.pages[0].total || 0; - - const handleDistributionClick = (evaluation: Evaluation) => { - setUrlQuery({ - filters: getFilters({ - filters, - dataView, - field: 'result.evaluation', - value: evaluation, - negate: false, - }), - }); - }; + activePageIndex, + pageSize, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + isGroupLoading, + onResetFilters, + error, + totalPassedFindings, + onDistributionBarClick, + totalFailedFindings, + isEmptyResults, + } = useLatestFindingsGrouping({ dataView, groupPanelRenderer, groupStatsRenderer }); + + if (error || isEmptyResults) { + return ( + <> + + + {error && } + {isEmptyResults && } + + ); + } + if (isGroupSelected) { + return ( + <> + +
    + + + +
    + + ); + } return ( - + <> - - {error && } - {!error && ( - <> - {total > 0 && ( - - )} - - - - )} - + + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx new file mode 100644 index 000000000000..d0684452fb23 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx @@ -0,0 +1,312 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiIconTip, + EuiSkeletonTitle, + EuiText, + EuiTextBlockTruncate, + EuiToolTip, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { + ECSField, + GroupPanelRenderer, + RawBucket, + StatRenderer, +} from '@kbn/securitysolution-grouping/src'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { getAbbreviatedNumber } from '../../../common/utils/get_abbreviated_number'; +import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon'; +import { ComplianceScoreBar } from '../../../components/compliance_score_bar'; +import { FindingsGroupingAggregation } from './use_grouped_findings'; +import { GROUPING_OPTIONS, NULL_GROUPING_MESSAGES, NULL_GROUPING_UNIT } from './constants'; +import { FINDINGS_GROUPING_COUNTER } from '../test_subjects'; + +/** + * Return first non-null value. If the field contains an array, this will return the first value that isn't null. If the field isn't an array it'll be returned unless it's null. + */ +export function firstNonNullValue(valueOrCollection: ECSField): T | undefined { + if (valueOrCollection === null) { + return undefined; + } else if (Array.isArray(valueOrCollection)) { + for (const value of valueOrCollection) { + if (value !== null) { + return value; + } + } + } else { + return valueOrCollection; + } +} + +const NullGroupComponent = ({ + title, + field, + unit = NULL_GROUPING_UNIT, +}: { + title: string; + field: string; + unit?: string; +}) => { + return ( + + {title} + + + + + ), + field: {field}, + unit, + }} + /> + + } + position="right" + /> + + ); +}; + +export const groupPanelRenderer: GroupPanelRenderer = ( + selectedGroup, + bucket, + nullGroupMessage, + isLoading +) => { + if (isLoading) { + return ( + + + + ); + } + const benchmarkId = firstNonNullValue(bucket.benchmarkId?.buckets?.[0]?.key); + switch (selectedGroup) { + case GROUPING_OPTIONS.RESOURCE_NAME: + return nullGroupMessage ? ( + + ) : ( + + + + + + + {bucket.key_as_string} {bucket.resourceName?.buckets?.[0].key} + + + + + + {bucket.resourceSubType?.buckets?.[0].key} + + + + + + ); + case GROUPING_OPTIONS.RULE_NAME: + return nullGroupMessage ? ( + + ) : ( + + + + + + {bucket.key_as_string} + + + + + {firstNonNullValue(bucket.benchmarkName?.buckets?.[0].key)}{' '} + {firstNonNullValue(bucket.benchmarkVersion?.buckets?.[0].key)} + + + + + + ); + case GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME: + return nullGroupMessage ? ( + + ) : ( + + {benchmarkId && ( + + + + )} + + + + + {bucket.key_as_string} + + + + + {bucket.benchmarkName?.buckets?.[0]?.key} + + + + + + ); + case GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME: + return nullGroupMessage ? ( + + ) : ( + + {benchmarkId && ( + + + + )} + + + + + {bucket.key_as_string} + + + + + {bucket.benchmarkName?.buckets?.[0]?.key} + + + + + + ); + default: + return nullGroupMessage ? ( + + ) : ( + + + + + + {bucket.key_as_string} + + + + + + ); + } +}; + +const FindingsCountComponent = ({ bucket }: { bucket: RawBucket }) => { + const { euiTheme } = useEuiTheme(); + + return ( + + + {getAbbreviatedNumber(bucket.doc_count)} + + + ); +}; + +const FindingsCount = React.memo(FindingsCountComponent); + +const ComplianceBarComponent = ({ bucket }: { bucket: RawBucket }) => { + const { euiTheme } = useEuiTheme(); + + const totalFailed = bucket.failedFindings?.doc_count || 0; + const totalPassed = bucket.doc_count - totalFailed; + return ( + + ); +}; + +const ComplianceBar = React.memo(ComplianceBarComponent); + +export const groupStatsRenderer = ( + selectedGroup: string, + bucket: RawBucket +): StatRenderer[] => { + const defaultBadges = [ + { + title: i18n.translate('xpack.csp.findings.grouping.stats.badges.findings', { + defaultMessage: 'Findings', + }), + renderer: , + }, + { + title: i18n.translate('xpack.csp.findings.grouping.stats.badges.compliance', { + defaultMessage: 'Compliance', + }), + renderer: , + }, + ]; + + return defaultBadges; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx new file mode 100644 index 000000000000..be6d34a1df93 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Filter } from '@kbn/es-query'; +import { DataTableRecord } from '@kbn/discover-utils/types'; +import { i18n } from '@kbn/i18n'; +import { EuiDataGridCellValueElementProps, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import React from 'react'; +import { FindingsBaseProps } from '../../../common/types'; +import * as TEST_SUBJECTS from '../test_subjects'; +import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; +import { ErrorCallout } from '../layout/error_callout'; +import { CloudSecurityDataTable } from '../../../components/cloud_security_data_table'; +import { getDefaultQuery, defaultColumns } from './constants'; +import { useLatestFindingsTable } from './use_latest_findings_table'; +import { TimestampTableCell } from '../../../components/timestamp_table_cell'; +import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; +import { CspFinding } from '../../../../common/schemas/csp_finding'; +import { FindingsRuleFlyout } from '../findings_flyout/findings_flyout'; + +type LatestFindingsTableProps = FindingsBaseProps & { + groupSelectorComponent?: JSX.Element; + height?: number; + showDistributionBar?: boolean; + nonPersistedFilters?: Filter[]; +}; + +/** + * Type Guard for checking if the given source is a CspFinding + */ +const isCspFinding = (source: Record | undefined): source is CspFinding => { + return source?.result?.evaluation !== undefined; +}; + +/** + * This Wrapper component renders the children if the given row is a CspFinding + * it uses React's Render Props pattern + */ +const CspFindingRenderer = ({ + row, + children, +}: { + row: DataTableRecord; + children: ({ finding }: { finding: CspFinding }) => JSX.Element; +}) => { + const source = row.raw._source; + const finding = isCspFinding(source) && (source as CspFinding); + if (!finding) return <>; + return children({ finding }); +}; + +/** + * Flyout component for the latest findings table + */ +const flyoutComponent = (row: DataTableRecord, onCloseFlyout: () => void): JSX.Element => { + return ( + + {({ finding }) => } + + ); +}; + +const title = i18n.translate('xpack.csp.findings.latestFindings.tableRowTypeLabel', { + defaultMessage: 'Findings', +}); + +const customCellRenderer = (rows: DataTableRecord[]) => ({ + 'result.evaluation': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( + + {({ finding }) => } + + ), + '@timestamp': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( + + {({ finding }) => } + + ), +}); + +export const LatestFindingsTable = ({ + dataView, + groupSelectorComponent, + height, + showDistributionBar = true, + nonPersistedFilters, +}: LatestFindingsTableProps) => { + const { + cloudPostureTable, + rows, + error, + isFetching, + fetchNextPage, + passed, + failed, + total, + canShowDistributionBar, + onDistributionBarClick, + } = useLatestFindingsTable({ + dataView, + getDefaultQuery, + nonPersistedFilters, + showDistributionBar, + }); + + return ( + + {error ? ( + <> + + + + ) : ( + <> + {canShowDistributionBar && ( + <> + + + + + )} + + + )} + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx new file mode 100644 index 000000000000..c67c1250d1be --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IKibanaSearchResponse } from '@kbn/data-plugin/public'; +import { GenericBuckets, GroupingQuery, RootAggregation } from '@kbn/securitysolution-grouping/src'; +import { useQuery } from '@tanstack/react-query'; +import { lastValueFrom } from 'rxjs'; +import { CSP_LATEST_FINDINGS_DATA_VIEW } from '../../../../common/constants'; +import { useKibana } from '../../../common/hooks/use_kibana'; +import { showErrorToast } from '../../../common/utils/show_error_toast'; + +// Elasticsearch returns `null` when a sub-aggregation cannot be computed +type NumberOrNull = number | null; + +export interface FindingsRootGroupingAggregation + extends RootAggregation { + failedFindings?: { + doc_count?: NumberOrNull; + }; + passedFindings?: { + doc_count?: NumberOrNull; + }; +} + +export interface FindingsGroupingAggregation { + unitsCount?: { + value?: NumberOrNull; + }; + groupsCount?: { + value?: NumberOrNull; + }; + failedFindings?: { + doc_count?: NumberOrNull; + }; + passedFindings?: { + doc_count?: NumberOrNull; + }; + groupByFields?: { + buckets?: GenericBuckets[]; + }; + description?: { + buckets?: GenericBuckets[]; + }; + resourceName?: { + buckets?: GenericBuckets[]; + }; + resourceSubType?: { + buckets?: GenericBuckets[]; + }; + resourceType?: { + buckets?: GenericBuckets[]; + }; + benchmarkName?: { + buckets?: GenericBuckets[]; + }; + benchmarkVersion?: { + buckets?: GenericBuckets[]; + }; + benchmarkId?: { + buckets?: GenericBuckets[]; + }; + isLoading?: boolean; +} + +export const getGroupedFindingsQuery = (query: GroupingQuery) => ({ + ...query, + index: CSP_LATEST_FINDINGS_DATA_VIEW, + size: 0, +}); + +export const useGroupedFindings = ({ + query, + enabled = true, +}: { + query: GroupingQuery; + enabled: boolean; +}) => { + const { + data, + notifications: { toasts }, + } = useKibana().services; + + return useQuery( + ['csp_grouped_findings', { query }], + async () => { + const { + rawResponse: { aggregations }, + } = await lastValueFrom( + data.search.search< + {}, + IKibanaSearchResponse> + >({ + params: getGroupedFindingsQuery(query), + }) + ); + + if (!aggregations) throw new Error('Failed to aggregate by, missing resource id'); + + return aggregations; + }, + { + onError: (err: Error) => showErrorToast(toasts, err), + enabled, + // This allows the UI to keep the previous data while the new data is being fetched + keepPreviousData: true, + } + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts index 9ce029217583..0c0aee860d34 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts @@ -16,7 +16,10 @@ import { CspFinding } from '../../../../common/schemas/csp_finding'; import { useKibana } from '../../../common/hooks/use_kibana'; import type { FindingsBaseEsQuery } from '../../../common/types'; import { getAggregationCount, getFindingsCountAggQuery } from '../utils/utils'; -import { CSP_LATEST_FINDINGS_DATA_VIEW } from '../../../../common/constants'; +import { + CSP_LATEST_FINDINGS_DATA_VIEW, + LATEST_FINDINGS_RETENTION_POLICY, +} from '../../../../common/constants'; import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; import { showErrorToast } from '../../../common/utils/show_error_toast'; @@ -41,11 +44,27 @@ interface FindingsAggs { export const getFindingsQuery = ({ query, sort }: UseFindingsOptions, pageParam: any) => ({ index: CSP_LATEST_FINDINGS_DATA_VIEW, - query, sort: getMultiFieldsSort(sort), size: MAX_FINDINGS_TO_LOAD, aggs: getFindingsCountAggQuery(), ignore_unavailable: false, + query: { + ...query, + bool: { + ...query?.bool, + filter: [ + ...(query?.bool?.filter ?? []), + { + range: { + '@timestamp': { + gte: `now-${LATEST_FINDINGS_RETENTION_POLICY}`, + lte: 'now', + }, + }, + }, + ], + }, + }, ...(pageParam ? { search_after: pageParam } : {}), }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx new file mode 100644 index 000000000000..be5253cc710b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx @@ -0,0 +1,244 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { getGroupingQuery } from '@kbn/securitysolution-grouping'; +import { + GroupingAggregation, + GroupPanelRenderer, + GroupStatsRenderer, + isNoneGroup, + NamedAggregation, + parseGroupingQuery, +} from '@kbn/securitysolution-grouping/src'; +import { useMemo } from 'react'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { Evaluation } from '../../../../common/types'; +import { LATEST_FINDINGS_RETENTION_POLICY } from '../../../../common/constants'; +import { + FindingsGroupingAggregation, + FindingsRootGroupingAggregation, + useGroupedFindings, +} from './use_grouped_findings'; +import { + FINDINGS_UNIT, + groupingTitle, + defaultGroupingOptions, + getDefaultQuery, + GROUPING_OPTIONS, +} from './constants'; +import { useCloudSecurityGrouping } from '../../../components/cloud_security_grouping'; +import { getFilters } from '../utils/get_filters'; + +const getTermAggregation = (key: keyof FindingsGroupingAggregation, field: string) => ({ + [key]: { + terms: { field, size: 1 }, + }, +}); + +const getAggregationsByGroupField = (field: string): NamedAggregation[] => { + if (isNoneGroup([field])) { + return []; + } + const aggMetrics: NamedAggregation[] = [ + { + groupByField: { + cardinality: { + field, + }, + }, + failedFindings: { + filter: { + term: { + 'result.evaluation': { value: 'failed' }, + }, + }, + }, + passedFindings: { + filter: { + term: { + 'result.evaluation': { value: 'passed' }, + }, + }, + }, + complianceScore: { + bucket_script: { + buckets_path: { + passed: 'passedFindings>_count', + failed: 'failedFindings>_count', + }, + script: 'params.passed / (params.passed + params.failed)', + }, + }, + }, + ]; + + switch (field) { + case GROUPING_OPTIONS.RESOURCE_NAME: + return [ + ...aggMetrics, + getTermAggregation('resourceName', 'resource.id'), + getTermAggregation('resourceSubType', 'resource.sub_type'), + getTermAggregation('resourceType', 'resource.type'), + ]; + case GROUPING_OPTIONS.RULE_NAME: + return [ + ...aggMetrics, + getTermAggregation('benchmarkName', 'rule.benchmark.name'), + getTermAggregation('benchmarkVersion', 'rule.benchmark.version'), + ]; + case GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME: + return [ + ...aggMetrics, + getTermAggregation('benchmarkName', 'rule.benchmark.name'), + getTermAggregation('benchmarkId', 'rule.benchmark.id'), + ]; + case GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME: + return [ + ...aggMetrics, + getTermAggregation('benchmarkName', 'rule.benchmark.name'), + getTermAggregation('benchmarkId', 'rule.benchmark.id'), + ]; + } + return aggMetrics; +}; + +/** + * Type Guard for checking if the given source is a FindingsRootGroupingAggregation + */ +export const isFindingsRootGroupingAggregation = ( + groupData: Record | undefined +): groupData is FindingsRootGroupingAggregation => { + return ( + groupData?.passedFindings?.doc_count !== undefined && + groupData?.failedFindings?.doc_count !== undefined + ); +}; + +/** + * Utility hook to get the latest findings grouping data + * for the findings page + */ +export const useLatestFindingsGrouping = ({ + dataView, + groupPanelRenderer, + groupStatsRenderer, +}: { + dataView: DataView; + groupPanelRenderer?: GroupPanelRenderer; + groupStatsRenderer?: GroupStatsRenderer; +}) => { + const { + activePageIndex, + grouping, + pageSize, + query, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + uniqueValue, + isNoneSelected, + onResetFilters, + error, + filters, + } = useCloudSecurityGrouping({ + dataView, + groupingTitle, + defaultGroupingOptions, + getDefaultQuery, + unit: FINDINGS_UNIT, + groupPanelRenderer, + groupStatsRenderer, + }); + + const groupingQuery = getGroupingQuery({ + additionalFilters: query ? [query] : [], + groupByField: selectedGroup, + uniqueValue, + from: `now-${LATEST_FINDINGS_RETENTION_POLICY}`, + to: 'now', + pageNumber: activePageIndex * pageSize, + size: pageSize, + sort: [{ groupByField: { order: 'desc' } }, { complianceScore: { order: 'asc' } }], + statsAggregations: getAggregationsByGroupField(selectedGroup), + rootAggregations: [ + { + failedFindings: { + filter: { + term: { + 'result.evaluation': { value: 'failed' }, + }, + }, + }, + passedFindings: { + filter: { + term: { + 'result.evaluation': { value: 'passed' }, + }, + }, + }, + }, + ], + }); + + const { data, isFetching } = useGroupedFindings({ + query: groupingQuery, + enabled: !isNoneSelected, + }); + + const groupData = useMemo( + () => + parseGroupingQuery( + selectedGroup, + uniqueValue, + data as GroupingAggregation + ), + [data, selectedGroup, uniqueValue] + ); + + const totalPassedFindings = isFindingsRootGroupingAggregation(groupData) + ? groupData?.passedFindings?.doc_count || 0 + : 0; + const totalFailedFindings = isFindingsRootGroupingAggregation(groupData) + ? groupData?.failedFindings?.doc_count || 0 + : 0; + + const onDistributionBarClick = (evaluation: Evaluation) => { + setUrlQuery({ + filters: getFilters({ + filters, + dataView, + field: 'result.evaluation', + value: evaluation, + negate: false, + }), + }); + }; + + const isEmptyResults = + !isFetching && isFindingsRootGroupingAggregation(groupData) && !groupData.unitsCount?.value; + + return { + groupData, + grouping, + isFetching, + activePageIndex, + pageSize, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + isGroupSelected: !isNoneSelected, + isGroupLoading: !data, + onResetFilters, + filters, + error, + onDistributionBarClick, + totalPassedFindings, + totalFailedFindings, + isEmptyResults, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx new file mode 100644 index 000000000000..2bcc895ddd4b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataView } from '@kbn/data-views-plugin/common'; +import { Filter } from '@kbn/es-query'; +import { useMemo } from 'react'; +import { FindingsBaseURLQuery } from '../../../common/types'; +import { Evaluation } from '../../../../common/types'; +import { LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY } from '../../../common/constants'; +import { useCloudPostureDataTable } from '../../../common/hooks/use_cloud_posture_data_table'; +import { getFilters } from '../utils/get_filters'; +import { useLatestFindings } from './use_latest_findings'; + +const columnsLocalStorageKey = 'cloudPosture:latestFindings:columns'; + +export const useLatestFindingsTable = ({ + dataView, + getDefaultQuery, + nonPersistedFilters, + showDistributionBar, +}: { + dataView: DataView; + getDefaultQuery: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; + nonPersistedFilters?: Filter[]; + showDistributionBar?: boolean; +}) => { + const cloudPostureTable = useCloudPostureDataTable({ + dataView, + paginationLocalStorageKey: LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY, + columnsLocalStorageKey, + defaultQuery: getDefaultQuery, + nonPersistedFilters, + }); + + const { query, sort, queryError, setUrlQuery, filters, getRowsFromPages } = cloudPostureTable; + + const { + data, + error: fetchError, + isFetching, + fetchNextPage, + } = useLatestFindings({ + query, + sort, + enabled: !queryError, + }); + + const rows = useMemo(() => getRowsFromPages(data?.pages), [data?.pages, getRowsFromPages]); + + const error = fetchError || queryError; + + const passed = data?.pages[0].count.passed || 0; + const failed = data?.pages[0].count.failed || 0; + const total = data?.pages[0].total || 0; + + const onDistributionBarClick = (evaluation: Evaluation) => { + setUrlQuery({ + filters: getFilters({ + filters, + dataView, + field: 'result.evaluation', + value: evaluation, + negate: false, + }), + }); + }; + + const canShowDistributionBar = showDistributionBar && total > 0; + + return { + cloudPostureTable, + rows, + error, + isFetching, + fetchNextPage, + passed, + failed, + total, + canShowDistributionBar, + onDistributionBarClick, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx index 7f483c3ee084..3054ad352a5b 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx @@ -39,6 +39,9 @@ const getDefaultQuery = ({ sort: { field: 'compliance_score' as keyof CspFinding, direction: 'asc' }, }); +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ export const FindingsByResourceContainer = ({ dataView }: FindingsBaseProps) => ( ); +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => { const { queryError, query, pageSize, setTableOptions, urlQuery, setUrlQuery, onResetFilters } = useCloudPostureTable({ diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx index ce3f55e03417..71c4219d3b85 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx @@ -29,6 +29,10 @@ import { } from '../layout/findings_layout'; import { EmptyState } from '../../../components/empty_state'; +/** + * @deprecated: This function is deprecated and will be removed in the next release. + * use getAbbreviatedNumber from x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.ts + */ export const formatNumber = (value: number) => value < 1000 ? value : numeral(value).format('0.0a'); @@ -44,11 +48,17 @@ interface Props { onResetFilters: () => void; } +/** + * @deprecated: This function is deprecated and will be removed in the next release. + */ export const getResourceId = (resource: FindingsByResourcePage) => { const sections = resource['rule.section'] || []; return [resource.resource_id, ...sections].join('/'); }; +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ const FindingsByResourceTableComponent = ({ items, loading, @@ -189,8 +199,14 @@ const baseColumns: Array> = type BaseFindingColumnName = typeof baseColumns[number]['field']; +/** + * @deprecated: This function is deprecated and will be removed in the next release. + */ export const findingsByResourceColumns = Object.fromEntries( baseColumns.map((column) => [column.field, column]) ) as Record; +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ export const FindingsByResourceTable = React.memo(FindingsByResourceTableComponent); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx index 83182d66665d..f606241862ee 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx @@ -95,6 +95,9 @@ const getResourceFindingSharedValues = (sharedValues: { }, ]; +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { const params = useParams<{ resourceId: string }>(); const decodedResourceId = decodeURIComponent(params.resourceId); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx index 09f046f504ea..4dd7070af88f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx @@ -106,4 +106,7 @@ const ResourceFindingsTableComponent = ({ ); }; +/** + * @deprecated: This component is deprecated and will be removed in the next release. + */ export const ResourceFindingsTable = React.memo(ResourceFindingsTableComponent); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts index cd1a3484548c..46a5e1266566 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts @@ -80,6 +80,9 @@ const getResourceFindingsQuery = ({ ignore_unavailable: false, }); +/** + * @deprecated: This hook is deprecated and will be removed in the next release. + */ export const useResourceFindings = (options: UseResourceFindingsOptions) => { const { data, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts index d0253966bc87..e4bbd955f609 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts @@ -76,6 +76,9 @@ interface FindingsAggBucket extends AggregationsStringRareTermsBucketKeys { cis_sections: AggregationsMultiBucketAggregateBase; } +/** + * @deprecated: This hook is deprecated and will be removed in the next release. + */ export const getFindingsByResourceAggQuery = ({ query, sortDirection, @@ -168,6 +171,9 @@ const createFindingsByResource = (resource: FindingsAggBucket): FindingsByResour }, }); +/** + * @deprecated: This hook is deprecated and will be removed in the next release. + */ export const useFindingsByResource = (options: UseFindingsByResourceOptions) => { const { data, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_distribution_bar.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_distribution_bar.tsx index 294b05d9dd80..1cf084220ea2 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_distribution_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_distribution_bar.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import numeral from '@elastic/numeral'; +import { getAbbreviatedNumber } from '../../../common/utils/get_abbreviated_number'; import { RULE_FAILED, RULE_PASSED } from '../../../../common/constants'; import { statusColors } from '../../../common/constants'; import type { Evaluation } from '../../../../common/types'; @@ -28,8 +28,6 @@ interface Props { distributionOnClick: (evaluation: Evaluation) => void; } -const formatNumber = (value: number) => (value < 1000 ? value : numeral(value).format('0.0a')); - export const CurrentPageOfTotal = ({ pageEnd, pageStart, @@ -48,7 +46,7 @@ export const CurrentPageOfTotal = ({ values={{ pageStart: {pageStart}, pageEnd: {pageEnd}, - total: {formatNumber(total)}, + total: {getAbbreviatedNumber(total)}, type, }} /> @@ -113,7 +111,7 @@ const DistributionBar: React.FC> = ({ gutterSize="none" css={css` height: 8px; - background: ${euiTheme.colors.subduedText}; + background: ${euiTheme.colors.lightestShade}; `} > {label}
    - {formatNumber(value)} + {getAbbreviatedNumber(value)}
    ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/test_subjects.ts index b0d5a8ffd19f..b465b58f4588 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/test_subjects.ts @@ -20,6 +20,7 @@ export const LATEST_FINDINGS_CONTAINER = 'latest_findings_container'; export const LATEST_FINDINGS_TABLE = 'latest_findings_table'; export const FINDINGS_GROUP_BY_SELECTOR = 'findings_group_by_selector'; +export const FINDINGS_GROUPING_COUNTER = 'findings_grouping_counter'; export const getFindingsTableRowTestId = (id: string) => `findings_table_row_${id}`; export const getFindingsTableCellTestId = (columnId: string, rowId: string) => diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx index 966f95cb367f..67e46d82020c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx @@ -99,16 +99,6 @@ export const Findings = () => { - - - { defaultMessage="Misconfigurations" /> + + + )} diff --git a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx index 3f89c934e5dd..bdccb0785162 100755 --- a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx +++ b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx @@ -11,7 +11,6 @@ import { I18nProvider } from '@kbn/i18n-react'; // eslint-disable-next-line no-restricted-imports import { Router } from 'react-router-dom'; import { Route, Routes } from '@kbn/shared-ux-router'; -import { MockSubscriptionTrackingProvider } from '@kbn/subscription-tracking/mocks'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { coreMock } from '@kbn/core/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; @@ -52,11 +51,9 @@ export const TestProvider: React.FC> = ({ - - - <>{children}} /> - - + + <>{children}} /> + diff --git a/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts b/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts index 95dca041521e..ebce74d89b2d 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts @@ -9,25 +9,45 @@ import { ElasticsearchClient, type Logger } from '@kbn/core/server'; import { getSafePostureTypeRuntimeMapping } from '../../common/runtime_mappings/get_safe_posture_type_runtime_mapping'; import { IndexStatus, PostureTypes } from '../../common/types'; +export interface PostureTypeAndRetention { + postureType?: PostureTypes; + retentionTime?: string; +} + export const checkIndexStatus = async ( esClient: ElasticsearchClient, index: string, logger: Logger, - postureType?: PostureTypes + PostureTypeAndRetention?: PostureTypeAndRetention ): Promise => { - const query = - !postureType || postureType === 'all' || postureType === 'vuln_mgmt' - ? undefined - : { - bool: { - filter: { - term: { - safe_posture_type: postureType, + const isNotKspmOrCspm = + !PostureTypeAndRetention?.postureType || + PostureTypeAndRetention?.postureType === 'all' || + PostureTypeAndRetention?.postureType === 'vuln_mgmt'; + + const query = { + bool: { + filter: [ + ...(isNotKspmOrCspm + ? [] + : [ + { + term: { + safe_posture_type: PostureTypeAndRetention?.postureType, + }, }, + ]), + { + range: { + '@timestamp': { + gte: `now-${PostureTypeAndRetention?.retentionTime}`, + lte: 'now', }, }, - }; - + }, + ], + }, + }; try { const queryResult = await esClient.search({ index, @@ -37,7 +57,6 @@ export const checkIndexStatus = async ( query, size: 1, }); - return queryResult.hits.hits.length ? 'not-empty' : 'empty'; } catch (e) { logger.debug(e); diff --git a/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.test.ts b/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.test.ts new file mode 100644 index 000000000000..848a7ac0aa39 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + toBenchmarkDocFieldKey, + toBenchmarkMappingFieldKey, + MAPPING_VERSION_DELIMITER, +} from './mapping_field_util'; // replace 'yourFile' with the actual file name + +describe('Benchmark Field Key Functions', () => { + const sampleBenchmarkId = 'cis_aws'; + const sampleBenchmarkVersion = '1.0.0'; + + it('toBenchmarkDocFieldKey should keep the same benchmark id and version key for benchmark document', () => { + const result = toBenchmarkDocFieldKey(sampleBenchmarkId, sampleBenchmarkVersion); + const expected = `${sampleBenchmarkId};${sampleBenchmarkVersion}`; + expect(result).toEqual(expected); + }); + + it('toBenchmarkDocFieldKey should convert benchmark version with . delimiter correctly', () => { + const benchmarkVersionWithDelimiter = '1_0_0'; + const result = toBenchmarkDocFieldKey(sampleBenchmarkId, benchmarkVersionWithDelimiter); + const expected = `${sampleBenchmarkId};1.0.0`; + expect(result).toEqual(expected); + }); + + it('toBenchmarkMappingFieldKey should convert benchmark version with _ delimiter correctly', () => { + const result = toBenchmarkMappingFieldKey(sampleBenchmarkVersion); + const expected = '1_0_0'; + expect(result).toEqual(expected); + }); + + it('toBenchmarkMappingFieldKey should handle benchmark version with dots correctly', () => { + const benchmarkVersionWithDots = '1.0.0'; + const result = toBenchmarkMappingFieldKey(benchmarkVersionWithDots); + const expected = '1_0_0'; + expect(result).toEqual(expected); + }); + + it('MAPPING_VERSION_DELIMITER should be an underscore', () => { + expect(MAPPING_VERSION_DELIMITER).toBe('_'); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.ts b/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.ts new file mode 100644 index 000000000000..7cc392d3da74 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/lib/mapping_field_util.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const MAPPING_VERSION_DELIMITER = '_'; + +/* + * The latest finding index store benchmark version field value `v1.2.0` + * when we store the benchmark id and version field name in the benchmark scores index, + * we need benchmark version with _ delimiter to avoid JSON mapping for each dot notation + * to be read as key. e.g. `v1.2.0` will be `v1_2_0` + */ + +export const toBenchmarkDocFieldKey = (benchmarkId: string, benchmarkVersion: string) => + benchmarkVersion.includes(MAPPING_VERSION_DELIMITER) + ? `${benchmarkId};${benchmarkVersion.replaceAll('_', '.')}` + : `${benchmarkId};${benchmarkVersion}`; + +export const toBenchmarkMappingFieldKey = (benchmarkVersion: string) => + `${benchmarkVersion.replaceAll('.', '_')}`; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts index b827f5a31b4e..88c7afd5aca1 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts @@ -14,6 +14,7 @@ import type { PosturePolicyTemplate, ComplianceDashboardData, GetComplianceDashboardRequest, + ComplianceDashboardDataV2, } from '../../../common/types'; import { LATEST_FINDINGS_INDEX_DEFAULT_NS, STATS_ROUTE_PATH } from '../../../common/constants'; import { getGroupedFindingsEvaluation } from './get_grouped_findings_evaluation'; @@ -21,6 +22,8 @@ import { ClusterWithoutTrend, getClusters } from './get_clusters'; import { getStats } from './get_stats'; import { CspRouter } from '../../types'; import { getTrends, Trends } from './get_trends'; +import { BenchmarkWithoutTrend, getBenchmarks } from './get_benchmarks'; +import { toBenchmarkDocFieldKey } from '../../lib/mapping_field_util'; export interface KeyDocCount { key: TKey; @@ -36,6 +39,23 @@ const getClustersTrends = (clustersWithoutTrends: ClusterWithoutTrend[], trends: })), })); +const getBenchmarksTrends = (benchmarksWithoutTrends: BenchmarkWithoutTrend[], trends: Trends) => { + return benchmarksWithoutTrends.map((benchmark) => ({ + ...benchmark, + trend: trends.map(({ timestamp, benchmarks: benchmarksTrendData }) => { + const benchmarkIdVersion = toBenchmarkDocFieldKey( + benchmark.meta.benchmarkId, + benchmark.meta.benchmarkVersion + ); + + return { + timestamp, + ...benchmarksTrendData[benchmarkIdVersion], + }; + }), + })); +}; + const getSummaryTrend = (trends: Trends) => trends.map(({ timestamp, summary }) => ({ timestamp, ...summary })); @@ -56,6 +76,7 @@ export const defineGetComplianceDashboardRoute = (router: CspRouter) => }, async (context, request, response) => { const cspContext = await context.csp; + const logger = cspContext.logger; try { const esClient = cspContext.esClient.asCurrentUser; @@ -79,16 +100,16 @@ export const defineGetComplianceDashboardRoute = (router: CspRouter) => const [stats, groupedFindingsEvaluation, clustersWithoutTrends, trends] = await Promise.all([ - getStats(esClient, query, pitId, runtimeMappings), - getGroupedFindingsEvaluation(esClient, query, pitId, runtimeMappings), - getClusters(esClient, query, pitId, runtimeMappings), - getTrends(esClient, policyTemplate), + getStats(esClient, query, pitId, runtimeMappings, logger), + getGroupedFindingsEvaluation(esClient, query, pitId, runtimeMappings, logger), + getClusters(esClient, query, pitId, runtimeMappings, logger), + getTrends(esClient, policyTemplate, logger), ]); // Try closing the PIT, if it fails we can safely ignore the error since it closes itself after the keep alive // ends. Not waiting on the promise returned from the `closePointInTime` call to avoid delaying the request esClient.closePointInTime({ id: pitId }).catch((err) => { - cspContext.logger.warn(`Could not close PIT for stats endpoint: ${err}`); + logger.warn(`Could not close PIT for stats endpoint: ${err}`); }); const clusters = getClustersTrends(clustersWithoutTrends, trends); @@ -106,7 +127,80 @@ export const defineGetComplianceDashboardRoute = (router: CspRouter) => }); } catch (err) { const error = transformError(err); - cspContext.logger.error(`Error while fetching CSP stats: ${err}`); + logger.error(`Error while fetching CSP stats: ${err}`); + logger.error(err.stack); + + return response.customError({ + body: { message: error.message }, + statusCode: error.statusCode, + }); + } + } + ) + .addVersion( + { + version: '2', + validate: { + request: { + params: getComplianceDashboardSchema, + }, + }, + }, + async (context, request, response) => { + const cspContext = await context.csp; + const logger = cspContext.logger; + + try { + const esClient = cspContext.esClient.asCurrentUser; + + const { id: pitId } = await esClient.openPointInTime({ + index: LATEST_FINDINGS_INDEX_DEFAULT_NS, + keep_alive: '30s', + }); + + const params: GetComplianceDashboardRequest = request.params; + const policyTemplate = params.policy_template as PosturePolicyTemplate; + + // runtime mappings create the `safe_posture_type` field, which equals to `kspm` or `cspm` based on the value and existence of the `posture_type` field which was introduced at 8.7 + // the `query` is then being passed to our getter functions to filter per posture type even for older findings before 8.7 + const runtimeMappings: MappingRuntimeFields = getSafePostureTypeRuntimeMapping(); + const query: QueryDslQueryContainer = { + bool: { + filter: [{ term: { safe_posture_type: policyTemplate } }], + }, + }; + + const [stats, groupedFindingsEvaluation, benchmarksWithoutTrends, trends] = + await Promise.all([ + getStats(esClient, query, pitId, runtimeMappings, logger), + getGroupedFindingsEvaluation(esClient, query, pitId, runtimeMappings, logger), + getBenchmarks(esClient, query, pitId, runtimeMappings, logger), + getTrends(esClient, policyTemplate, logger), + ]); + + // Try closing the PIT, if it fails we can safely ignore the error since it closes itself after the keep alive + // ends. Not waiting on the promise returned from the `closePointInTime` call to avoid delaying the request + esClient.closePointInTime({ id: pitId }).catch((err) => { + logger.warn(`Could not close PIT for stats endpoint: ${err}`); + }); + + const benchmarks = getBenchmarksTrends(benchmarksWithoutTrends, trends); + const trend = getSummaryTrend(trends); + + const body: ComplianceDashboardDataV2 = { + stats, + groupedFindingsEvaluation, + benchmarks, + trend, + }; + + return response.ok({ + body, + }); + } catch (err) { + const error = transformError(err); + logger.error(`Error while fetching v2 CSP stats: ${err}`); + logger.error(err.stack); return response.customError({ body: { message: error.message }, diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.test.ts new file mode 100644 index 000000000000..cf4d1632a6b5 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.test.ts @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BenchmarkBucket, getBenchmarksFromAggs } from './get_benchmarks'; + +const mockBenchmarkBuckets: BenchmarkBucket[] = [ + { + key: 'cis_aws', + doc_count: 12, + aggs_by_benchmark_version: { + buckets: [ + { + key: 'v1.5.0', + doc_count: 12, + asset_count: { + value: 1, + }, + aggs_by_resource_type: { + buckets: [ + { + key: 'foo_type', + doc_count: 6, + passed_findings: { + doc_count: 3, + }, + failed_findings: { + doc_count: 3, + }, + score: { + value: 0.5, + }, + }, + { + key: 'boo_type', + doc_count: 6, + passed_findings: { + doc_count: 3, + }, + failed_findings: { + doc_count: 3, + }, + score: { + value: 0.5, + }, + }, + ], + }, + aggs_by_benchmark_name: { + buckets: [ + { + key: 'CIS Amazon Web Services Foundations', + doc_count: 12, + }, + ], + }, + passed_findings: { + doc_count: 6, + }, + failed_findings: { + doc_count: 6, + }, + }, + ], + }, + }, +]; + +describe('getBenchmarksFromAggs', () => { + it('should return value matching ComplianceDashboardDataV2["benchmarks"]', async () => { + const benchmarks = getBenchmarksFromAggs(mockBenchmarkBuckets); + expect(benchmarks).toEqual([ + { + meta: { + benchmarkId: 'cis_aws', + benchmarkVersion: 'v1.5.0', + benchmarkName: 'CIS Amazon Web Services Foundations', + assetCount: 1, + }, + stats: { + totalFindings: 12, + totalFailed: 6, + totalPassed: 6, + postureScore: 50.0, + }, + groupedFindingsEvaluation: [ + { + name: 'foo_type', + totalFindings: 6, + totalFailed: 3, + totalPassed: 3, + postureScore: 50.0, + }, + { + name: 'boo_type', + totalFindings: 6, + totalFailed: 3, + totalPassed: 3, + postureScore: 50.0, + }, + ], + }, + ]); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.ts new file mode 100644 index 000000000000..b1f8335a6186 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_benchmarks.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from '@kbn/core/server'; +import type { + AggregationsMultiBucketAggregateBase as Aggregation, + QueryDslQueryContainer, + SearchRequest, +} from '@elastic/elasticsearch/lib/api/types'; +import type { Logger } from '@kbn/core/server'; +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; +import type { BenchmarkData } from '../../../common/types'; +import { + failedFindingsAggQuery, + BenchmarkVersionQueryResult, + getPostureStatsFromAggs, +} from './get_grouped_findings_evaluation'; +import { findingsEvaluationAggsQuery, getStatsFromFindingsEvaluationsAggs } from './get_stats'; +import { KeyDocCount } from './compliance_dashboard'; +import { getIdentifierRuntimeMapping } from '../../../common/runtime_mappings/get_identifier_runtime_mapping'; + +export interface BenchmarkBucket extends KeyDocCount { + aggs_by_benchmark_version: Aggregation; +} + +interface BenchmarkQueryResult extends KeyDocCount { + aggs_by_benchmark: Aggregation; +} + +export type BenchmarkWithoutTrend = Omit; + +const MAX_BENCHMARKS = 500; + +export const getBenchmarksQuery = ( + query: QueryDslQueryContainer, + pitId: string, + runtimeMappings: MappingRuntimeFields +): SearchRequest => ({ + size: 0, + runtime_mappings: { ...runtimeMappings, ...getIdentifierRuntimeMapping() }, + query, + aggs: { + aggs_by_benchmark: { + terms: { + field: 'rule.benchmark.id', + order: { + _count: 'desc', + }, + size: MAX_BENCHMARKS, + }, + aggs: { + aggs_by_benchmark_version: { + terms: { + field: 'rule.benchmark.version', + }, + aggs: { + aggs_by_benchmark_name: { + terms: { + field: 'rule.benchmark.name', + }, + }, + asset_count: { + cardinality: { + field: 'asset_identifier', + }, + }, + // Result evalution for passed or failed findings + ...findingsEvaluationAggsQuery, + // CIS Section Compliance Score and Failed Findings + ...failedFindingsAggQuery, + }, + }, + }, + }, + }, + pit: { + id: pitId, + }, +}); + +export const getBenchmarksFromAggs = (benchmarks: BenchmarkBucket[]) => { + return benchmarks.flatMap((benchmarkAggregation: BenchmarkBucket) => { + const benchmarkId = benchmarkAggregation.key; + const versions = benchmarkAggregation.aggs_by_benchmark_version.buckets; + if (!Array.isArray(versions)) throw new Error('missing aggs by benchmark version'); + + return versions.map((version: BenchmarkVersionQueryResult) => { + const benchmarkVersion = version.key; + const assetCount = version.asset_count.value; + const resourcesTypesAggs = version.aggs_by_resource_type.buckets; + + let benchmarkName = ''; + + if (!Array.isArray(version.aggs_by_benchmark_name.buckets)) + throw new Error('missing aggs by benchmark name'); + + if (version.aggs_by_benchmark_name && version.aggs_by_benchmark_name.buckets.length > 0) { + benchmarkName = version.aggs_by_benchmark_name.buckets[0].key; + } + + if (!Array.isArray(resourcesTypesAggs)) + throw new Error('missing aggs by resource type per benchmark'); + + const { passed_findings: passedFindings, failed_findings: failedFindings } = version; + const stats = getStatsFromFindingsEvaluationsAggs({ + passed_findings: passedFindings, + failed_findings: failedFindings, + }); + + const groupedFindingsEvaluation = getPostureStatsFromAggs(resourcesTypesAggs); + + return { + meta: { + benchmarkId, + benchmarkVersion, + benchmarkName, + assetCount, + }, + stats, + groupedFindingsEvaluation, + }; + }); + }); +}; + +export const getBenchmarks = async ( + esClient: ElasticsearchClient, + query: QueryDslQueryContainer, + pitId: string, + runtimeMappings: MappingRuntimeFields, + logger: Logger +): Promise => { + try { + const queryResult = await esClient.search( + getBenchmarksQuery(query, pitId, runtimeMappings) + ); + + const benchmarks = queryResult.aggregations?.aggs_by_benchmark.buckets; + if (!Array.isArray(benchmarks)) throw new Error('missing aggs by benchmark id'); + + return getBenchmarksFromAggs(benchmarks); + } catch (err) { + logger.error(`Failed to fetch benchmark stats ${err.message}`); + logger.error(err); + throw err; + } +}; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts index ae40f0525863..51d5c71673ed 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts @@ -13,13 +13,11 @@ import type { AggregationsTopHitsAggregate, SearchHit, } from '@elastic/elasticsearch/lib/api/types'; +import type { Logger } from '@kbn/core/server'; import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; import { CspFinding } from '../../../common/schemas/csp_finding'; import type { Cluster } from '../../../common/types'; -import { - getFailedFindingsFromAggs, - failedFindingsAggQuery, -} from './get_grouped_findings_evaluation'; +import { getPostureStatsFromAggs, failedFindingsAggQuery } from './get_grouped_findings_evaluation'; import type { FailedFindingsQueryResult } from './get_grouped_findings_evaluation'; import { findingsEvaluationAggsQuery, getStatsFromFindingsEvaluationsAggs } from './get_stats'; import { KeyDocCount } from './compliance_dashboard'; @@ -99,7 +97,7 @@ export const getClustersFromAggs = (clusters: ClusterBucket[]): ClusterWithoutTr const resourcesTypesAggs = clusterBucket.aggs_by_resource_type.buckets; if (!Array.isArray(resourcesTypesAggs)) throw new Error('missing aggs by resource type per cluster'); - const groupedFindingsEvaluation = getFailedFindingsFromAggs(resourcesTypesAggs); + const groupedFindingsEvaluation = getPostureStatsFromAggs(resourcesTypesAggs); return { meta, @@ -112,14 +110,21 @@ export const getClusters = async ( esClient: ElasticsearchClient, query: QueryDslQueryContainer, pitId: string, - runtimeMappings: MappingRuntimeFields + runtimeMappings: MappingRuntimeFields, + logger: Logger ): Promise => { - const queryResult = await esClient.search( - getClustersQuery(query, pitId, runtimeMappings) - ); + try { + const queryResult = await esClient.search( + getClustersQuery(query, pitId, runtimeMappings) + ); - const clusters = queryResult.aggregations?.aggs_by_asset_identifier.buckets; - if (!Array.isArray(clusters)) throw new Error('missing aggs by cluster id'); + const clusters = queryResult.aggregations?.aggs_by_asset_identifier.buckets; + if (!Array.isArray(clusters)) throw new Error('missing aggs by cluster id'); - return getClustersFromAggs(clusters); + return getClustersFromAggs(clusters); + } catch (err) { + logger.error(`Failed to fetch cluster stats ${err.message}`); + logger.error(err); + throw err; + } }; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.test.ts index 6af6d97f51e2..5ebc5231dee6 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.test.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { getFailedFindingsFromAggs, FailedFindingsBucket } from './get_grouped_findings_evaluation'; +import { getPostureStatsFromAggs, PostureStatsBucket } from './get_grouped_findings_evaluation'; -const resourceTypeBuckets: FailedFindingsBucket[] = [ +const resourceTypeBuckets: PostureStatsBucket[] = [ { key: 'foo_type', doc_count: 41, @@ -36,9 +36,9 @@ const resourceTypeBuckets: FailedFindingsBucket[] = [ }, ]; -describe('getFailedFindingsFromAggs', () => { +describe('getPostureStatsFromAggs', () => { it('should return value matching ComplianceDashboardData["resourcesTypes"]', async () => { - const resourceTypes = getFailedFindingsFromAggs(resourceTypeBuckets); + const resourceTypes = getPostureStatsFromAggs(resourceTypeBuckets); expect(resourceTypes).toEqual([ { name: 'foo_type', diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.ts index 239801350c7a..74b239f14d24 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_grouped_findings_evaluation.ts @@ -11,16 +11,30 @@ import type { QueryDslQueryContainer, SearchRequest, } from '@elastic/elasticsearch/lib/api/types'; +import type { Logger } from '@kbn/core/server'; import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; import { calculatePostureScore } from '../../../common/utils/helpers'; import type { ComplianceDashboardData } from '../../../common/types'; import { KeyDocCount } from './compliance_dashboard'; export interface FailedFindingsQueryResult { - aggs_by_resource_type: Aggregation; + aggs_by_resource_type: Aggregation; } -export interface FailedFindingsBucket extends KeyDocCount { +export interface BenchmarkVersionQueryResult extends KeyDocCount, FailedFindingsQueryResult { + failed_findings: { + doc_count: number; + }; + passed_findings: { + doc_count: number; + }; + asset_count: { + value: number; + }; + aggs_by_benchmark_name: Aggregation; +} + +export interface PostureStatsBucket extends KeyDocCount { failed_findings: { doc_count: number; }; @@ -79,8 +93,8 @@ export const getRisksEsQuery = ( }, }); -export const getFailedFindingsFromAggs = ( - queryResult: FailedFindingsBucket[] +export const getPostureStatsFromAggs = ( + queryResult: PostureStatsBucket[] ): ComplianceDashboardData['groupedFindingsEvaluation'] => queryResult.map((bucket) => { const totalPassed = bucket.passed_findings.doc_count || 0; @@ -99,16 +113,23 @@ export const getGroupedFindingsEvaluation = async ( esClient: ElasticsearchClient, query: QueryDslQueryContainer, pitId: string, - runtimeMappings: MappingRuntimeFields + runtimeMappings: MappingRuntimeFields, + logger: Logger ): Promise => { - const resourceTypesQueryResult = await esClient.search( - getRisksEsQuery(query, pitId, runtimeMappings) - ); + try { + const resourceTypesQueryResult = await esClient.search( + getRisksEsQuery(query, pitId, runtimeMappings) + ); - const ruleSections = resourceTypesQueryResult.aggregations?.aggs_by_resource_type.buckets; - if (!Array.isArray(ruleSections)) { - return []; - } + const ruleSections = resourceTypesQueryResult.aggregations?.aggs_by_resource_type.buckets; + if (!Array.isArray(ruleSections)) { + return []; + } - return getFailedFindingsFromAggs(ruleSections); + return getPostureStatsFromAggs(ruleSections); + } catch (err) { + logger.error(`Failed to fetch findings stats ${err.message}`); + logger.error(err); + throw err; + } }; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_stats.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_stats.ts index 2f0e1c1b1710..f639f8a7e142 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_stats.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_stats.ts @@ -8,6 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import type { QueryDslQueryContainer, SearchRequest } from '@elastic/elasticsearch/lib/api/types'; import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; +import type { Logger } from '@kbn/core/server'; import { calculatePostureScore } from '../../../common/utils/helpers'; import type { ComplianceDashboardData } from '../../../common/types'; @@ -81,14 +82,21 @@ export const getStats = async ( esClient: ElasticsearchClient, query: QueryDslQueryContainer, pitId: string, - runtimeMappings: MappingRuntimeFields + runtimeMappings: MappingRuntimeFields, + logger: Logger ): Promise => { - const evaluationsQueryResult = await esClient.search( - getEvaluationsQuery(query, pitId, runtimeMappings) - ); + try { + const evaluationsQueryResult = await esClient.search( + getEvaluationsQuery(query, pitId, runtimeMappings) + ); - const findingsEvaluations = evaluationsQueryResult.aggregations; - if (!findingsEvaluations) throw new Error('missing findings evaluations'); + const findingsEvaluations = evaluationsQueryResult.aggregations; + if (!findingsEvaluations) throw new Error('missing findings evaluations'); - return getStatsFromFindingsEvaluationsAggs(findingsEvaluations); + return getStatsFromFindingsEvaluationsAggs(findingsEvaluations); + } catch (err) { + logger.error(`Failed to fetch stats ${err.message}`); + logger.error(err); + throw err; + } }; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts index 127cf3e1a3f8..f26760221292 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getTrendsFromQueryResult, ScoreTrendDoc } from './get_trends'; +import { formatTrends, ScoreTrendDoc } from './get_trends'; const trendDocs: ScoreTrendDoc[] = [ { @@ -20,6 +20,15 @@ const trendDocs: ScoreTrendDoc[] = [ failed_findings: 15, }, }, + score_by_benchmark_id: { + cis_gcp: { + v2_0_0: { + total_findings: 6, + passed_findings: 3, + failed_findings: 3, + }, + }, + }, }, { '@timestamp': '2022-04-06T15:00:00Z', @@ -38,22 +47,27 @@ const trendDocs: ScoreTrendDoc[] = [ failed_findings: 5, }, }, - }, - { - '@timestamp': '2022-04-05T15:30:00Z', - total_findings: 30, - passed_findings: 25, - failed_findings: 5, - score_by_cluster_id: { - forth_cluster_id: { - total_findings: 25, - passed_findings: 25, - failed_findings: 0, + score_by_benchmark_id: { + cis_gcp: { + v2_0_0: { + total_findings: 6, + passed_findings: 3, + failed_findings: 3, + }, }, - fifth_cluster_id: { - total_findings: 5, - passed_findings: 0, - failed_findings: 5, + cis_azure: { + v2_0_0: { + total_findings: 6, + passed_findings: 3, + failed_findings: 3, + }, + }, + cis_aws: { + v1_5_0: { + total_findings: 6, + passed_findings: 3, + failed_findings: 3, + }, }, }, }, @@ -61,7 +75,7 @@ const trendDocs: ScoreTrendDoc[] = [ describe('getTrendsFromQueryResult', () => { it('should return value matching Trends type definition, in descending order, and with postureScore', async () => { - const trends = getTrendsFromQueryResult(trendDocs); + const trends = formatTrends(trendDocs); expect(trends).toEqual([ { timestamp: '2022-04-06T15:30:00Z', @@ -79,6 +93,14 @@ describe('getTrendsFromQueryResult', () => { postureScore: 25.0, }, }, + benchmarks: { + 'cis_gcp;v2.0.0': { + totalFailed: 3, + totalFindings: 6, + totalPassed: 3, + postureScore: 50, + }, + }, }, { timestamp: '2022-04-06T15:00:00Z', @@ -102,27 +124,24 @@ describe('getTrendsFromQueryResult', () => { postureScore: 75.0, }, }, - }, - { - timestamp: '2022-04-05T15:30:00Z', - summary: { - totalFindings: 30, - totalPassed: 25, - totalFailed: 5, - postureScore: 83.3, - }, - clusters: { - forth_cluster_id: { - totalFindings: 25, - totalPassed: 25, - totalFailed: 0, - postureScore: 100.0, + benchmarks: { + 'cis_gcp;v2.0.0': { + totalFailed: 3, + totalFindings: 6, + totalPassed: 3, + postureScore: 50.0, }, - fifth_cluster_id: { - totalFindings: 5, - totalPassed: 0, - totalFailed: 5, - postureScore: 0, + 'cis_azure;v2.0.0': { + totalFailed: 3, + totalFindings: 6, + totalPassed: 3, + postureScore: 50.0, + }, + 'cis_aws;v1.5.0': { + totalFailed: 3, + totalFindings: 6, + totalPassed: 3, + postureScore: 50.0, }, }, }, diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts index cc8234fa6d7a..00acd14d960f 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_trends.ts @@ -5,36 +5,49 @@ * 2.0. */ -import { ElasticsearchClient } from '@kbn/core/server'; +import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { calculatePostureScore } from '../../../common/utils/helpers'; import { BENCHMARK_SCORE_INDEX_DEFAULT_NS } from '../../../common/constants'; import type { PosturePolicyTemplate, Stats } from '../../../common/types'; +import { toBenchmarkDocFieldKey } from '../../lib/mapping_field_util'; +import { CSPM_FINDINGS_STATS_INTERVAL } from '../../tasks/findings_stats_task'; + +interface FindingsDetails { + total_findings: number; + passed_findings: number; + failed_findings: number; +} + +interface ScoreByClusterId { + [clusterId: string]: FindingsDetails; +} + +interface ScoreByBenchmarkId { + [benchmarkId: string]: { + [key: string]: FindingsDetails; + }; +} export interface ScoreTrendDoc { '@timestamp': string; total_findings: number; passed_findings: number; failed_findings: number; - score_by_cluster_id: Record< - string, - { - total_findings: number; - passed_findings: number; - failed_findings: number; - } - >; + score_by_cluster_id: ScoreByClusterId; + score_by_benchmark_id: ScoreByBenchmarkId; } export type Trends = Array<{ timestamp: string; summary: Stats; clusters: Record; + benchmarks: Record; }>; export const getTrendsQuery = (policyTemplate: PosturePolicyTemplate) => ({ index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - // large number that should be sufficient for 24 hours considering we write to the score index every 5 minutes - size: 999, + // Amount of samples of the last 24 hours (accounting that we take a sample every 5 minutes) + size: (24 * 60) / CSPM_FINDINGS_STATS_INTERVAL, sort: '@timestamp:desc', query: { bool: { @@ -51,40 +64,71 @@ export const getTrendsQuery = (policyTemplate: PosturePolicyTemplate) => ({ }, }); -export const getTrendsFromQueryResult = (scoreTrendDocs: ScoreTrendDoc[]): Trends => - scoreTrendDocs.map((data) => ({ - timestamp: data['@timestamp'], - summary: { - totalFindings: data.total_findings, - totalFailed: data.failed_findings, - totalPassed: data.passed_findings, - postureScore: calculatePostureScore(data.passed_findings, data.failed_findings), - }, - clusters: Object.fromEntries( - Object.entries(data.score_by_cluster_id).map(([clusterId, cluster]) => [ - clusterId, - { - totalFindings: cluster.total_findings, - totalFailed: cluster.failed_findings, - totalPassed: cluster.passed_findings, - postureScore: calculatePostureScore(cluster.passed_findings, cluster.failed_findings), - }, - ]) - ), - })); +export const formatTrends = (scoreTrendDocs: ScoreTrendDoc[]): Trends => { + return scoreTrendDocs.map((data) => { + return { + timestamp: data['@timestamp'], + summary: { + totalFindings: data.total_findings, + totalFailed: data.failed_findings, + totalPassed: data.passed_findings, + postureScore: calculatePostureScore(data.passed_findings, data.failed_findings), + }, + clusters: Object.fromEntries( + Object.entries(data.score_by_cluster_id).map(([clusterId, cluster]) => [ + clusterId, + { + totalFindings: cluster.total_findings, + totalFailed: cluster.failed_findings, + totalPassed: cluster.passed_findings, + postureScore: calculatePostureScore(cluster.passed_findings, cluster.failed_findings), + }, + ]) + ), + benchmarks: data.score_by_benchmark_id + ? Object.fromEntries( + Object.entries(data.score_by_benchmark_id).flatMap(([benchmarkId, benchmark]) => + Object.entries(benchmark).map(([benchmarkVersion, benchmarkStats]) => { + const benchmarkIdVersion = toBenchmarkDocFieldKey(benchmarkId, benchmarkVersion); + return [ + benchmarkIdVersion, + { + totalFindings: benchmarkStats.total_findings, + totalFailed: benchmarkStats.failed_findings, + totalPassed: benchmarkStats.passed_findings, + postureScore: calculatePostureScore( + benchmarkStats.passed_findings, + benchmarkStats.failed_findings + ), + }, + ]; + }) + ) + ) + : {}, + }; + }); +}; export const getTrends = async ( esClient: ElasticsearchClient, - policyTemplate: PosturePolicyTemplate + policyTemplate: PosturePolicyTemplate, + logger: Logger ): Promise => { - const trendsQueryResult = await esClient.search(getTrendsQuery(policyTemplate)); + try { + const trendsQueryResult = await esClient.search(getTrendsQuery(policyTemplate)); - if (!trendsQueryResult.hits.hits) throw new Error('missing trend results from score index'); + if (!trendsQueryResult.hits.hits) throw new Error('missing trend results from score index'); - const scoreTrendDocs = trendsQueryResult.hits.hits.map((hit) => { - if (!hit._source) throw new Error('missing _source data for one or more of trend results'); - return hit._source; - }); + const scoreTrendDocs = trendsQueryResult.hits.hits.map((hit) => { + if (!hit._source) throw new Error('missing _source data for one or more of trend results'); + return hit._source; + }); - return getTrendsFromQueryResult(scoreTrendDocs); + return formatTrends(scoreTrendDocs); + } catch (err) { + logger.error(`Failed to fetch trendlines data ${err.message}`); + logger.error(err); + throw err; + } }; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts index 86b0d0a66802..ed3bcd99746f 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts @@ -29,6 +29,9 @@ import { POSTURE_TYPES, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, VULN_MGMT_POLICY_TEMPLATE, + POSTURE_TYPE_ALL, + LATEST_VULNERABILITIES_RETENTION_POLICY, + LATEST_FINDINGS_RETENTION_POLICY, } from '../../../common/constants'; import type { CspApiRequestHandlerContext, @@ -168,20 +171,53 @@ export const getCspStatus = async ({ installedPackagePoliciesVulnMgmt, installedPolicyTemplates, ] = await Promise.all([ - checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger), - checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger), - checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger), - - checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger, 'cspm'), - checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger, 'cspm'), - checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger, 'cspm'), - - checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger, 'kspm'), - checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger, 'kspm'), - checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger, 'kspm'), - - checkIndexStatus(esClient, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, logger), - checkIndexStatus(esClient, VULNERABILITIES_INDEX_PATTERN, logger, VULN_MGMT_POLICY_TEMPLATE), + checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger, { + postureType: POSTURE_TYPE_ALL, + retentionTime: LATEST_VULNERABILITIES_RETENTION_POLICY, + }), + checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger, { + postureType: POSTURE_TYPE_ALL, + retentionTime: LATEST_VULNERABILITIES_RETENTION_POLICY, + }), + checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger, { + postureType: POSTURE_TYPE_ALL, + retentionTime: LATEST_VULNERABILITIES_RETENTION_POLICY, + }), + + checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger, { + postureType: CSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger, { + postureType: CSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger, { + postureType: CSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + + checkIndexStatus(esClient, LATEST_FINDINGS_INDEX_DEFAULT_NS, logger, { + postureType: KSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + checkIndexStatus(esClient, FINDINGS_INDEX_PATTERN, logger, { + postureType: KSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + checkIndexStatus(esClient, BENCHMARK_SCORE_INDEX_DEFAULT_NS, logger, { + postureType: KSPM_POLICY_TEMPLATE, + retentionTime: LATEST_FINDINGS_RETENTION_POLICY, + }), + + checkIndexStatus(esClient, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, logger, { + postureType: VULN_MGMT_POLICY_TEMPLATE, + retentionTime: LATEST_VULNERABILITIES_RETENTION_POLICY, + }), + checkIndexStatus(esClient, VULNERABILITIES_INDEX_PATTERN, logger, { + postureType: VULN_MGMT_POLICY_TEMPLATE, + retentionTime: LATEST_VULNERABILITIES_RETENTION_POLICY, + }), packageService.asInternalUser.getInstallation(CLOUD_SECURITY_POSTURE_PACKAGE_NAME), packageService.asInternalUser.fetchFindLatestPackage(CLOUD_SECURITY_POSTURE_PACKAGE_NAME), @@ -295,6 +331,7 @@ export const getCspStatus = async ({ { latest: vulnerabilitiesLatestIndexStatus, stream: vulnerabilitiesIndexStatus, + score: scoreIndexStatus, }, installation, healthyAgentsVulMgmt, diff --git a/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts b/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts index f40ce3f7dc4a..c157e8081546 100644 --- a/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts +++ b/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts @@ -32,10 +32,11 @@ import { type LatestTaskStateSchema, type TaskHealthStatus, } from './task_state'; +import { toBenchmarkMappingFieldKey } from '../lib/mapping_field_util'; const CSPM_FINDINGS_STATS_TASK_ID = 'cloud_security_posture-findings_stats'; const CSPM_FINDINGS_STATS_TASK_TYPE = 'cloud_security_posture-stats_task'; -const CSPM_FINDINGS_STATS_INTERVAL = '5m'; +export const CSPM_FINDINGS_STATS_INTERVAL = 5; export async function scheduleFindingsStatsTask( taskManager: TaskManagerStartContract, @@ -47,7 +48,7 @@ export async function scheduleFindingsStatsTask( id: CSPM_FINDINGS_STATS_TASK_ID, taskType: CSPM_FINDINGS_STATS_TASK_TYPE, schedule: { - interval: CSPM_FINDINGS_STATS_INTERVAL, + interval: `${CSPM_FINDINGS_STATS_INTERVAL}m`, }, state: emptyState, params: {}, @@ -177,6 +178,39 @@ const getScoreQuery = (): SearchRequest => ({ }, }, }, + score_by_benchmark_id: { + terms: { + field: 'rule.benchmark.id', + }, + aggregations: { + benchmark_versions: { + terms: { + field: 'rule.benchmark.version', + }, + aggs: { + total_findings: { + value_count: { + field: 'result.evaluation', + }, + }, + passed_findings: { + filter: { + term: { + 'result.evaluation': 'passed', + }, + }, + }, + failed_findings: { + filter: { + term: { + 'result.evaluation': 'failed', + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -255,6 +289,27 @@ const getFindingsScoresDocIndexingPromises = ( ]; }) ); + // creating score per benchmark id and version + const benchmarkStats = Object.fromEntries( + policyTemplateTrend.score_by_benchmark_id.buckets.map((benchmarkIdBucket) => { + const benchmarkId = benchmarkIdBucket.key; + const benchmarkVersions = Object.fromEntries( + benchmarkIdBucket.benchmark_versions.buckets.map((benchmarkVersionBucket) => { + const benchmarkVersion = toBenchmarkMappingFieldKey(benchmarkVersionBucket.key); + return [ + benchmarkVersion, + { + total_findings: benchmarkVersionBucket.total_findings.value, + passed_findings: benchmarkVersionBucket.passed_findings.doc_count, + failed_findings: benchmarkVersionBucket.failed_findings.doc_count, + }, + ]; + }) + ); + + return [benchmarkId, benchmarkVersions]; + }) + ); // each document contains the policy template and its scores return esClient.index({ @@ -265,6 +320,7 @@ const getFindingsScoresDocIndexingPromises = ( failed_findings: policyTemplateTrend.failed_findings.doc_count, total_findings: policyTemplateTrend.total_findings.value, score_by_cluster_id: clustersStats, + score_by_benchmark_id: benchmarkStats, }, }); }); diff --git a/x-pack/plugins/cloud_security_posture/server/tasks/types.ts b/x-pack/plugins/cloud_security_posture/server/tasks/types.ts index 56ca619dcec5..839d4823ca47 100644 --- a/x-pack/plugins/cloud_security_posture/server/tasks/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/tasks/types.ts @@ -23,6 +23,20 @@ export interface ScoreByPolicyTemplateBucket { total_findings: { value: number }; }>; }; + score_by_benchmark_id: { + buckets: Array<{ + key: string; // benchmark id + doc_count: number; + benchmark_versions: { + buckets: Array<{ + key: string; // benchmark version + passed_findings: { doc_count: number }; + failed_findings: { doc_count: number }; + total_findings: { value: number }; + }>; + }; + }>; + }; }>; }; } diff --git a/x-pack/plugins/cloud_security_posture/tsconfig.json b/x-pack/plugins/cloud_security_posture/tsconfig.json index 113ddcb92202..48fc1a30594f 100755 --- a/x-pack/plugins/cloud_security_posture/tsconfig.json +++ b/x-pack/plugins/cloud_security_posture/tsconfig.json @@ -50,7 +50,6 @@ "@kbn/share-plugin", "@kbn/core-http-server", "@kbn/core-http-browser", - "@kbn/subscription-tracking", "@kbn/discover-utils", "@kbn/unified-data-table", "@kbn/cell-actions", @@ -60,7 +59,8 @@ "@kbn/ui-actions-plugin", "@kbn/core-http-server-mocks", "@kbn/field-formats-plugin", - "@kbn/data-view-field-editor-plugin" + "@kbn/data-view-field-editor-plugin", + "@kbn/securitysolution-grouping" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js index e020950668a8..839aa48464bb 100644 --- a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js @@ -309,7 +309,7 @@ describe('', () => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/100951 + // FLAKY: https://github.com/elastic/kibana/issues/142774 describe.skip('detail panel', () => { test('should open a detail panel when clicking on a follower index', async () => { expect(exists('followerIndexDetail')).toBe(false); @@ -372,7 +372,8 @@ describe('', () => { ); }); - test('should have a section to render the follower index shards stats', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/100951 + test.skip('should have a section to render the follower index shards stats', async () => { await actions.clickFollowerIndexAt(0); expect(exists('followerIndexDetail.shardsStatsSection')).toBe(true); diff --git a/x-pack/plugins/dataset_quality/README.md b/x-pack/plugins/dataset_quality/README.md index cd5bfc30658d..fd38679a2d77 100755 --- a/x-pack/plugins/dataset_quality/README.md +++ b/x-pack/plugins/dataset_quality/README.md @@ -1,3 +1,53 @@ # Dataset Quality In order to make ongoing maintenance of log collection easy we want to introduce the concept of dataset quality, where users can easily get an overview on the datasets they have with information such as integration, size, last activity, among others. + +## Development + +### Tests + +#### Unit tests + +Kibana primarily uses Jest for unit testing. Each plugin or package defines a `jest.config.js` that extends a preset provided by the `@kbn/test` package. The following command runs all Dataset quality unit tests: + +``` +yarn jest --config x-pack/plugins/dataset_quality/jest.config.js +``` + +You can also run a specific test by passing the filepath as an argument, e.g.: + +``` +yarn jest --config x-pack/plugins/dataset_quality/jest.config.js x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/get_data_streams.test.ts +``` + +#### API integration tests + +| Option | Description | +| ------------ | ----------------------------------------------- | +| --server | Only start ES and Kibana | +| --runner | Only run tests | +| --grep | Specify the specs to run | +| --grep-files | Specify the files to run | +| --inspect | Add --inspect-brk flag to the ftr for debugging | +| --times | Repeat the test n number of times | + +The API tests are located in [`x-pack/test/dataset_quality_api_integration/`](/x-pack/test/dataset_quality_api_integration/). + +#### Start server and run test (single process) + +``` +node x-pack/plugins/dataset_quality/scripts/api [--help] +``` + +The above command will start an ES instance on http://localhost:9220, a Kibana instance on http://localhost:5620 and run the api tests. +Once the tests finish, the instances will be terminated. + +#### Start server and run test (separate processes) + +```sh +# start server +node x-pack/plugins/dataset_quality/scripts/api --server + +# run tests +node x-pack/plugins/dataset_quality/scripts/api --runner --grep-files=error_group_list +``` diff --git a/x-pack/plugins/dataset_quality/common/constants.ts b/x-pack/plugins/dataset_quality/common/constants.ts new file mode 100644 index 000000000000..febb7d2a0f9f --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/constants.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DATASET_QUALITY_APP_ID = 'dataset_quality'; +export const DATA_STREAMS_STATS_URL = '/internal/dataset_quality/data_streams/stats'; diff --git a/x-pack/plugins/dataset_quality/common/data_streams/index.ts b/x-pack/plugins/dataset_quality/common/data_streams/index.ts new file mode 100644 index 000000000000..6cc0ccaa93a6 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './types'; diff --git a/x-pack/plugins/dataset_quality/common/data_streams/types.ts b/x-pack/plugins/dataset_quality/common/data_streams/types.ts new file mode 100644 index 000000000000..1a47a0d7e5ac --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; + +export const dataStreamTypesRt = t.partial({ + type: t.union([ + t.literal('logs'), + t.literal('metrics'), + t.literal('traces'), + t.literal('synthetics'), + t.literal('profiling'), + ]), +}); diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts new file mode 100644 index 000000000000..5fd2a2ffc1ff --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Integration } from './integration'; +import { DataStreamStatType, IntegrationType } from './types'; + +export class DataStreamStat { + name: DataStreamStatType['name']; + title: string; + size?: DataStreamStatType['size']; + sizeBytes?: DataStreamStatType['size_bytes']; + lastActivity?: DataStreamStatType['last_activity']; + integration?: IntegrationType; + + private constructor(dataStreamStat: DataStreamStat) { + this.name = dataStreamStat.name; + this.title = dataStreamStat.title ?? dataStreamStat.name; + this.size = dataStreamStat.size; + this.sizeBytes = dataStreamStat.sizeBytes; + this.lastActivity = dataStreamStat.lastActivity; + this.integration = dataStreamStat.integration; + } + + public static create(dataStreamStat: DataStreamStatType) { + const [_type, dataset, namespace] = dataStreamStat.name.split('-'); + + const dataStreamStatProps = { + name: dataStreamStat.name, + title: `${dataset}-${namespace}`, + size: dataStreamStat.size, + sizeBytes: dataStreamStat.size_bytes, + lastActivity: dataStreamStat.last_activity, + integration: dataStreamStat.integration + ? Integration.create(dataStreamStat.integration) + : undefined, + }; + + return new DataStreamStat(dataStreamStatProps); + } +} diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/errors.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/errors.ts new file mode 100644 index 000000000000..de47f4cb8c39 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/errors.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export class GetDataStreamsStatsError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = 'GetDataStreamsStatsError'; + } +} diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/index.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/index.ts new file mode 100644 index 000000000000..28c7b0a8c274 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './types'; +export * from './errors'; diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/integration.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/integration.ts new file mode 100644 index 000000000000..937efd407e6f --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/integration.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IntegrationType } from './types'; + +export class Integration { + name: IntegrationType['name']; + title: IntegrationType['title']; + version: IntegrationType['version']; + icons?: IntegrationType['icons']; + + private constructor(integration: Integration) { + this.name = integration.name; + this.title = integration.title || integration.name; + this.version = integration.version || '1.0.0'; + this.icons = integration.icons; + } + + public static create(integration: IntegrationType) { + const integrationProps = { + ...integration, + title: integration.title || integration.name, + version: integration.version || '1.0.0', + }; + + return new Integration(integrationProps); + } +} diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/types.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/types.ts new file mode 100644 index 000000000000..f9a202798fb3 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { APIClientRequestParamsOf, APIReturnType } from '../rest/create_call_dataset_quality_api'; +import { DataStreamStat } from './data_stream_stat'; + +export type GetDataStreamsStatsParams = + APIClientRequestParamsOf<`GET /internal/dataset_quality/data_streams/stats`>['params']; +export type GetDataStreamsStatsQuery = GetDataStreamsStatsParams['query']; +export type GetDataStreamsStatsResponse = + APIReturnType<`GET /internal/dataset_quality/data_streams/stats`>; +export type DataStreamStatServiceResponse = DataStreamStat[]; +export type DataStreamStatType = GetDataStreamsStatsResponse['dataStreamsStats'][0]; +export type IntegrationType = GetDataStreamsStatsResponse['integrations'][0]; diff --git a/x-pack/plugins/dataset_quality/common/fetch_options.ts b/x-pack/plugins/dataset_quality/common/fetch_options.ts new file mode 100644 index 000000000000..3a72a72762de --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/fetch_options.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { HttpFetchOptions } from '@kbn/core/public'; + +export type FetchOptions = Omit & { + pathname: string; + method?: string; + body?: any; +}; diff --git a/x-pack/plugins/dataset_quality/common/index.ts b/x-pack/plugins/dataset_quality/common/index.ts index 440e8780e6bf..b015815eeaac 100644 --- a/x-pack/plugins/dataset_quality/common/index.ts +++ b/x-pack/plugins/dataset_quality/common/index.ts @@ -6,3 +6,5 @@ */ export type { DatasetQualityConfig } from './plugin_config'; +export type { FetchOptions } from './fetch_options'; +export type { APIClientRequestParamsOf, APIReturnType } from './rest'; diff --git a/x-pack/plugins/dataset_quality/common/rest/call_api.ts b/x-pack/plugins/dataset_quality/common/rest/call_api.ts new file mode 100644 index 000000000000..a70e2f8d407e --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/rest/call_api.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, CoreStart } from '@kbn/core/public'; +import { FetchOptions } from '..'; + +function getFetchOptions(fetchOptions: FetchOptions) { + const { body, ...rest } = fetchOptions; + + return { + ...rest, + ...(body !== undefined ? { body: JSON.stringify(body) } : {}), + query: { + ...fetchOptions.query, + }, + }; +} + +export type CallApi = typeof callApi; + +export async function callApi( + { http }: CoreStart | CoreSetup, + fetchOptions: FetchOptions +): Promise { + const { pathname, method = 'get', ...options } = getFetchOptions(fetchOptions); + + const lowercaseMethod = method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch'; + + const res = await http[lowercaseMethod](pathname, options); + + return res; +} diff --git a/x-pack/plugins/dataset_quality/common/rest/create_call_dataset_quality_api.ts b/x-pack/plugins/dataset_quality/common/rest/create_call_dataset_quality_api.ts new file mode 100644 index 000000000000..8e3929bb77e7 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/rest/create_call_dataset_quality_api.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, CoreStart } from '@kbn/core/public'; +import type { + ClientRequestParamsOf, + ReturnOf, + RouteRepositoryClient, +} from '@kbn/server-route-repository'; +import { formatRequest } from '@kbn/server-route-repository'; +import { FetchOptions } from '..'; +import type { APIEndpoint, DatasetQualityServerRouteRepository } from '../../server/routes'; +import { CallApi, callApi } from './call_api'; + +export type DatasetQualityClientOptions = Omit< + FetchOptions, + 'query' | 'body' | 'pathname' | 'signal' +> & { + signal: AbortSignal | null; +}; + +export type DatasetQualityClient = RouteRepositoryClient< + DatasetQualityServerRouteRepository, + DatasetQualityClientOptions +>; + +export type AutoAbortedClient = RouteRepositoryClient< + DatasetQualityServerRouteRepository, + Omit +>; + +export type APIReturnType = ReturnOf< + DatasetQualityServerRouteRepository, + TEndpoint +>; + +export type APIClientRequestParamsOf = ClientRequestParamsOf< + DatasetQualityServerRouteRepository, + TEndpoint +>; + +export let callDatasetQualityApi: DatasetQualityClient = () => { + throw new Error( + 'callDatasetQualityApi has to be initialized before used. Call createCallApi first.' + ); +}; + +export function createCallDatasetQualityApi(core: CoreStart | CoreSetup) { + callDatasetQualityApi = ((endpoint, options) => { + const { params } = options as unknown as { + params?: Partial>; + }; + + const { method, pathname } = formatRequest(endpoint, params?.path); + + return callApi(core, { + ...options, + method, + pathname, + body: params?.body, + query: params?.query, + } as unknown as Parameters[1]); + }) as DatasetQualityClient; +} diff --git a/x-pack/plugins/dataset_quality/common/rest/index.ts b/x-pack/plugins/dataset_quality/common/rest/index.ts new file mode 100644 index 000000000000..559acfe62e50 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/rest/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './call_api'; +export * from './create_call_dataset_quality_api'; diff --git a/x-pack/plugins/dataset_quality/common/translations.ts b/x-pack/plugins/dataset_quality/common/translations.ts new file mode 100644 index 000000000000..b26b7ca5c902 --- /dev/null +++ b/x-pack/plugins/dataset_quality/common/translations.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const datasetQualityAppTitle = i18n.translate('xpack.datasetQuality.appTitle', { + defaultMessage: 'Datasets', +}); + +export const onboardingLinkTitle = i18n.translate('xpack.datasetQuality.onboardingLinkTitle', { + defaultMessage: 'Add data', +}); + +export const noDatasetsDescription = i18n.translate('xpack.datasetQuality.noDatasetsDescription', { + defaultMessage: 'Try adjusting your time or filter.', +}); + +export const noDatasetsTitle = i18n.translate('xpack.datasetQuality.noDatasetsTitle', { + defaultMessage: 'There is no data to display.', +}); + +export const loadingDatasetsText = i18n.translate('xpack.datasetQuality.loadingDatasetsText', { + defaultMessage: 'Loading data', +}); + +export const tableSummaryAllText = i18n.translate('xpack.datasetQuality.tableSummaryAllText', { + defaultMessage: 'All', +}); + +export const tableSummaryOfText = i18n.translate('xpack.datasetQuality.tableSummaryOfText', { + defaultMessage: 'of', +}); diff --git a/x-pack/plugins/dataset_quality/kibana.jsonc b/x-pack/plugins/dataset_quality/kibana.jsonc index 133537a76d83..710d7e82890c 100644 --- a/x-pack/plugins/dataset_quality/kibana.jsonc +++ b/x-pack/plugins/dataset_quality/kibana.jsonc @@ -8,7 +8,7 @@ "server": true, "browser": true, "configPath": ["xpack", "datasetQuality"], - "requiredPlugins": ["data", "kibanaReact", "kibanaUtils", "controls", "embeddable", "share"], + "requiredPlugins": ["data", "kibanaReact", "kibanaUtils", "controls", "embeddable", "share", "observabilityShared", "fleet", "fieldFormats"], "optionalPlugins": [], "requiredBundles": [], "extraPublicDirs": ["common"] diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx b/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx new file mode 100644 index 000000000000..aa653a95d622 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { PackageIcon } from '@kbn/fleet-plugin/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { DataStreamStat } from '../../../common/data_streams_stats/data_stream_stat'; +import loggingIcon from '../../icons/logging.svg'; + +const nameColumnName = i18n.translate('xpack.datasetQuality.nameColumnName', { + defaultMessage: 'Dataset Name', +}); + +const sizeColumnName = i18n.translate('xpack.datasetQuality.sizeColumnName', { + defaultMessage: 'Size', +}); + +const lastActivityColumnName = i18n.translate('xpack.datasetQuality.lastActivityColumnName', { + defaultMessage: 'Last Activity', +}); + +export const getDatasetQualitTableColumns = ({ + fieldFormats, +}: { + fieldFormats: FieldFormatsStart; +}): Array> => { + return [ + { + name: nameColumnName, + field: 'title', + sortable: true, + render: (title: string, dataStreamStat: DataStreamStat) => { + const { integration } = dataStreamStat; + + return ( + + + {integration ? ( + + ) : ( + + )} + + {title} + + ); + }, + }, + { + name: sizeColumnName, + field: 'size', + sortable: true, + }, + { + name: lastActivityColumnName, + field: 'lastActivity', + render: (timestamp: number) => + fieldFormats + .getDefaultInstance(KBN_FIELD_TYPES.DATE, [ES_FIELD_TYPES.DATE]) + .convert(timestamp), + sortable: true, + }, + ]; +}; diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/context.ts b/x-pack/plugins/dataset_quality/public/components/dataset_quality/context.ts new file mode 100644 index 000000000000..64029b649a58 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/context.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { createContext, useContext } from 'react'; +import { IDataStreamsStatsClient } from '../../services/data_streams_stats'; + +export interface DatasetQualityContextValue { + dataStreamsStatsServiceClient: IDataStreamsStatsClient; +} + +export const DatasetQualityContext = createContext({} as DatasetQualityContextValue); + +export function useDatasetQualityContext() { + return useContext(DatasetQualityContext); +} diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/dataset_quality.tsx b/x-pack/plugins/dataset_quality/public/components/dataset_quality/dataset_quality.tsx new file mode 100644 index 000000000000..9fe6ca8db3b2 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/dataset_quality.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { CoreStart } from '@kbn/core/public'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { DataStreamsStatsService } from '../../services/data_streams_stats/data_streams_stats_service'; +import { DatasetQualityContext, DatasetQualityContextValue } from './context'; +import { useKibanaContextForPluginProvider } from '../../utils'; +import { DatasetQualityStartDeps } from '../../types'; +import { Header } from './header'; +import { Table } from './table'; + +export interface CreateDatasetQualityArgs { + core: CoreStart; + plugins: DatasetQualityStartDeps; +} + +export const createDatasetQuality = ({ core, plugins }: CreateDatasetQualityArgs) => { + return () => { + const KibanaContextProviderForPlugin = useKibanaContextForPluginProvider(core, plugins); + + const dataStreamsStatsServiceClient = new DataStreamsStatsService().start({ + http: core.http, + }).client; + + const datasetQualityProviderValue: DatasetQualityContextValue = { + dataStreamsStatsServiceClient, + }; + + return ( + + + + + + ); + }; +}; + +function DatasetQuality() { + return ( + + +
    + + + + + + ); +} diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/header.tsx b/x-pack/plugins/dataset_quality/public/components/dataset_quality/header.tsx new file mode 100644 index 000000000000..5126a645f7b6 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/header.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiPageHeader, EuiButton } from '@elastic/eui'; +import { + ObservabilityOnboardingLocatorParams, + OBSERVABILITY_ONBOARDING_LOCATOR, +} from '@kbn/deeplinks-observability'; +import { datasetQualityAppTitle, onboardingLinkTitle } from '../../../common/translations'; +import { useKibanaContextForPlugin } from '../../utils'; + +export function Header() { + const { + services: { share }, + } = useKibanaContextForPlugin(); + + const OnboardingLink = React.memo(() => { + const locator = share.url.locators.get( + OBSERVABILITY_ONBOARDING_LOCATOR + ); + + const onboardingUrl = locator?.getRedirectUrl({}); + + return ( + + {onboardingLinkTitle} + + ); + }); + + return ( + ]} + /> + ); +} diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/index.ts b/x-pack/plugins/dataset_quality/public/components/dataset_quality/index.ts new file mode 100644 index 000000000000..1a8591d0d3c8 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './dataset_quality'; diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/table.tsx b/x-pack/plugins/dataset_quality/public/components/dataset_quality/table.tsx new file mode 100644 index 000000000000..f45df6717063 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/table.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiBasicTable, EuiHorizontalRule, EuiSpacer, EuiText, EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { loadingDatasetsText, noDatasetsTitle } from '../../../common/translations'; +import { useDatasetQualityTable } from '../../hooks'; + +export const Table = () => { + const { sort, onTableChange, pagination, renderedItems, columns, loading, resultsCount } = + useDatasetQualityTable(); + + return ( + <> + + + + + + {noDatasetsTitle}} + hasBorder={false} + titleSize="m" + /> + ) + } + /> + + ); +}; diff --git a/x-pack/plugins/dataset_quality/public/hooks/index.ts b/x-pack/plugins/dataset_quality/public/hooks/index.ts new file mode 100644 index 000000000000..36b6f1540c82 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/hooks/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './use_dataset_quality_table'; diff --git a/x-pack/plugins/dataset_quality/public/hooks/use_dataset_quality_table.tsx b/x-pack/plugins/dataset_quality/public/hooks/use_dataset_quality_table.tsx new file mode 100644 index 000000000000..30bbd7f437da --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/hooks/use_dataset_quality_table.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { orderBy } from 'lodash'; +import React, { useState, useMemo, useCallback } from 'react'; +import { useFetcher } from '@kbn/observability-shared-plugin/public'; +import { tableSummaryAllText, tableSummaryOfText } from '../../common/translations'; +import { DataStreamStat } from '../../common/data_streams_stats/data_stream_stat'; +import { getDatasetQualitTableColumns } from '../components/dataset_quality/columns'; +import { useDatasetQualityContext } from '../components/dataset_quality/context'; +import { useKibanaContextForPlugin } from '../utils'; + +const DEFAULT_SORT_FIELD = 'title'; +const DEFAULT_SORT_DIRECTION = 'desc'; +type DIRECTION = 'asc' | 'desc'; +type SORT_FIELD = keyof DataStreamStat; + +const sortingOverrides: Partial<{ [key in SORT_FIELD]: SORT_FIELD }> = { + ['size']: 'sizeBytes', +}; + +export const useDatasetQualityTable = () => { + const { + services: { fieldFormats }, + } = useKibanaContextForPlugin(); + const [pageIndex, setPageIndex] = useState(0); + const [pageSize, setPageSize] = useState(10); + const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); + const [sortDirection, setSortDirection] = useState(DEFAULT_SORT_DIRECTION); + + const { dataStreamsStatsServiceClient: client } = useDatasetQualityContext(); + const { data = [], loading } = useFetcher(async () => client.getDataStreamsStats(), []); + + const columns = useMemo(() => getDatasetQualitTableColumns({ fieldFormats }), [fieldFormats]); + + const pagination = { + pageIndex, + pageSize, + totalItemCount: data.length, + hidePerPageOptions: true, + }; + + const onTableChange = useCallback( + (options: { + page: { index: number; size: number }; + sort?: { field: SORT_FIELD; direction: DIRECTION }; + }) => { + setPageIndex(options.page.index); + setPageSize(options.page.size); + setSortField(options.sort?.field || DEFAULT_SORT_FIELD); + setSortDirection(options.sort?.direction || DEFAULT_SORT_DIRECTION); + }, + [] + ); + + const sort = { + sort: { field: sortField, direction: sortDirection }, + }; + + const renderedItems = useMemo(() => { + const overridenSortingField = sortingOverrides[sortField] || sortField; + const sortedItems = orderBy(data, overridenSortingField, sortDirection); + + return sortedItems.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize); + }, [data, sortField, sortDirection, pageIndex, pageSize]); + + const resultsCount = useMemo(() => { + const startNumberItemsOnPage = pageSize * pageIndex + (renderedItems.length ? 1 : 0); + const endNumberItemsOnPage = pageSize * pageIndex + renderedItems.length; + + return pageSize === 0 ? ( + {tableSummaryAllText} + ) : ( + <> + + {startNumberItemsOnPage}-{endNumberItemsOnPage} + {' '} + {tableSummaryOfText} {data.length} + + ); + }, [data.length, pageIndex, pageSize, renderedItems.length]); + + return { sort, onTableChange, pagination, renderedItems, columns, loading, resultsCount }; +}; diff --git a/x-pack/plugins/dataset_quality/public/icons/logging.svg b/x-pack/plugins/dataset_quality/public/icons/logging.svg new file mode 100644 index 000000000000..41d5251b3ea1 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/icons/logging.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/dataset_quality/public/index.ts b/x-pack/plugins/dataset_quality/public/index.ts index 339be1ec1de9..e57d36776edf 100644 --- a/x-pack/plugins/dataset_quality/public/index.ts +++ b/x-pack/plugins/dataset_quality/public/index.ts @@ -14,3 +14,5 @@ export type { DatasetQualityPluginSetup, DatasetQualityPluginStart } from './typ export function plugin(context: PluginInitializerContext) { return new DatasetQualityPlugin(context); } + +export { datasetQualityAppTitle } from '../common/translations'; diff --git a/x-pack/plugins/dataset_quality/public/plugin.ts b/x-pack/plugins/dataset_quality/public/plugin.ts deleted file mode 100644 index 520c02481cd6..000000000000 --- a/x-pack/plugins/dataset_quality/public/plugin.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; -import { - DatasetQualityPluginSetup, - DatasetQualityPluginStart, - DatasetQualitySetupDependencies, - DatasetQualityStartDependencies, -} from './types'; - -export class DatasetQualityPlugin - implements Plugin -{ - constructor(context: PluginInitializerContext) {} - - public setup(core: CoreSetup, plugins: DatasetQualitySetupDependencies) { - return {}; - } - - public start( - core: CoreStart, - plugins: DatasetQualityStartDependencies - ): DatasetQualityPluginStart { - return {}; - } -} diff --git a/x-pack/plugins/dataset_quality/public/plugin.tsx b/x-pack/plugins/dataset_quality/public/plugin.tsx new file mode 100644 index 000000000000..c2ab65542263 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/plugin.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; +import { createDatasetQuality } from './components/dataset_quality'; +import { + DatasetQualityPluginSetup, + DatasetQualityPluginStart, + DatasetQualitySetupDeps, + DatasetQualityStartDeps, +} from './types'; + +export class DatasetQualityPlugin + implements Plugin +{ + constructor(context: PluginInitializerContext) {} + + public setup(core: CoreSetup, plugins: DatasetQualitySetupDeps) { + return {}; + } + + public start(core: CoreStart, plugins: DatasetQualityStartDeps): DatasetQualityPluginStart { + const DatasetQuality = createDatasetQuality({ + core, + plugins, + }); + + return { DatasetQuality }; + } +} diff --git a/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts new file mode 100644 index 000000000000..83028a3c4d66 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { find, merge } from 'lodash'; +import { HttpStart } from '@kbn/core/public'; +import { DataStreamStat } from '../../../common/data_streams_stats/data_stream_stat'; +import { DATA_STREAMS_STATS_URL } from '../../../common/constants'; +import { + GetDataStreamsStatsError, + GetDataStreamsStatsResponse, + GetDataStreamsStatsQuery, + DataStreamStatServiceResponse, +} from '../../../common/data_streams_stats'; +import { IDataStreamsStatsClient } from './types'; + +export class DataStreamsStatsClient implements IDataStreamsStatsClient { + constructor(private readonly http: HttpStart) {} + + public async getDataStreamsStats( + params: GetDataStreamsStatsQuery = { type: 'logs' } + ): Promise { + const { dataStreamsStats, integrations } = await this.http + .get(DATA_STREAMS_STATS_URL, { + query: params, + }) + .catch((error) => { + throw new GetDataStreamsStatsError(`Failed to fetch data streams stats": ${error}`); + }); + + const mergedDataStreamsStats = dataStreamsStats.map((statsItem) => { + const integration = find(integrations, { name: statsItem.integration }); + + return integration ? merge({}, statsItem, { integration }) : statsItem; + }); + + return mergedDataStreamsStats.map(DataStreamStat.create); + } +} diff --git a/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_service.ts b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_service.ts new file mode 100644 index 000000000000..c57fe3c90ebb --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/data_streams_stats_service.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataStreamsStatsClient } from './data_streams_stats_client'; +import { + DataStreamsStatsServiceSetup, + DataStreamsStatsServiceStartDeps, + DataStreamsStatsServiceStart, +} from './types'; + +export class DataStreamsStatsService { + constructor() {} + + public setup(): DataStreamsStatsServiceSetup {} + + public start({ http }: DataStreamsStatsServiceStartDeps): DataStreamsStatsServiceStart { + const client = new DataStreamsStatsClient(http); + + return { + client, + }; + } +} diff --git a/x-pack/plugins/dataset_quality/public/services/data_streams_stats/index.ts b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/index.ts new file mode 100644 index 000000000000..8f33568e1e88 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './data_streams_stats_client'; +export * from './data_streams_stats_service'; +export * from './types'; diff --git a/x-pack/plugins/dataset_quality/public/services/data_streams_stats/types.ts b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/types.ts new file mode 100644 index 000000000000..7023dbe25478 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/services/data_streams_stats/types.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HttpStart } from '@kbn/core/public'; +import { + DataStreamStatServiceResponse, + GetDataStreamsStatsQuery, +} from '../../../common/data_streams_stats'; + +export type DataStreamsStatsServiceSetup = void; + +export interface DataStreamsStatsServiceStart { + client: IDataStreamsStatsClient; +} + +export interface DataStreamsStatsServiceStartDeps { + http: HttpStart; +} + +export interface IDataStreamsStatsClient { + getDataStreamsStats(params?: GetDataStreamsStatsQuery): Promise; +} diff --git a/x-pack/plugins/dataset_quality/public/types.ts b/x-pack/plugins/dataset_quality/public/types.ts index 2d57bd6bb1b2..482aff3b242b 100644 --- a/x-pack/plugins/dataset_quality/public/types.ts +++ b/x-pack/plugins/dataset_quality/public/types.ts @@ -5,14 +5,22 @@ * 2.0. */ +import { ComponentType } from 'react'; +import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; + // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface DatasetQualityPluginSetup {} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface DatasetQualityPluginStart {} +export interface DatasetQualityPluginStart { + DatasetQuality: ComponentType; +} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface DatasetQualityStartDependencies {} +export interface DatasetQualityStartDeps { + share: SharePluginStart; + fieldFormats: FieldFormatsStart; +} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface DatasetQualitySetupDependencies {} +export interface DatasetQualitySetupDeps { + share: SharePluginSetup; +} diff --git a/x-pack/plugins/dataset_quality/public/utils/index.ts b/x-pack/plugins/dataset_quality/public/utils/index.ts new file mode 100644 index 000000000000..c7d8b7ba1dca --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/utils/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './use_kibana'; diff --git a/x-pack/plugins/dataset_quality/public/utils/use_kibana.tsx b/x-pack/plugins/dataset_quality/public/utils/use_kibana.tsx new file mode 100644 index 000000000000..cd13ced6af9b --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/utils/use_kibana.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart } from '@kbn/core/public'; +import { + createKibanaReactContext, + KibanaReactContextValue, + useKibana, +} from '@kbn/kibana-react-plugin/public'; +import { useMemo } from 'react'; +import { DatasetQualityStartDeps } from '../types'; + +export type PluginKibanaContextValue = CoreStart & DatasetQualityStartDeps; + +export const createKibanaContextForPlugin = (core: CoreStart, plugins: DatasetQualityStartDeps) => + createKibanaReactContext({ + ...core, + ...plugins, + }); + +export const useKibanaContextForPlugin = + useKibana as () => KibanaReactContextValue; + +export const useKibanaContextForPluginProvider = ( + core: CoreStart, + plugins: DatasetQualityStartDeps +) => { + const { Provider } = useMemo(() => createKibanaContextForPlugin(core, plugins), [core, plugins]); + + return Provider; +}; diff --git a/x-pack/plugins/dataset_quality/scripts/api.js b/x-pack/plugins/dataset_quality/scripts/api.js new file mode 100644 index 000000000000..343a1d2c2994 --- /dev/null +++ b/x-pack/plugins/dataset_quality/scripts/api.js @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable no-console */ +const { times } = require('lodash'); +const yargs = require('yargs'); +const path = require('path'); +const childProcess = require('child_process'); + +const { argv } = yargs(process.argv.slice(2)) + .option('server', { + default: false, + type: 'boolean', + description: 'Only start ES and Kibana', + }) + .option('runner', { + default: false, + type: 'boolean', + description: 'Only run tests', + }) + .option('grep', { + alias: 'spec', + type: 'string', + description: 'Specify the specs to run', + }) + .option('grep-files', { + alias: 'files', + type: 'array', + string: true, + description: 'Specify the files to run', + }) + .option('times', { + type: 'number', + description: 'Repeat the test n number of times', + }) + .check((argv) => { + const { inspect, runner } = argv; + if (inspect && !runner) { + throw new Error('--inspect can only be used with --runner'); + } else { + return true; + } + }) + .help(); + +const { server, runner, grep, grepFiles } = argv; + +const license = 'basic'; + +let ftrScript = 'functional_tests'; +if (server) { + ftrScript = 'functional_tests_server'; +} else if (runner) { + ftrScript = 'functional_test_runner'; +} + +const cmd = [ + 'node', + `../../../../scripts/${ftrScript}`, + ...(grep ? [`--grep "${grep}"`] : []), + `--config ../../../test/dataset_quality_api_integration/${license}/config.ts`, +].join(' '); + +console.log(`Running: "${cmd}"`); + +function runTests() { + childProcess.execSync(cmd, { + cwd: path.join(__dirname), + stdio: 'inherit', + env: { + ...process.env, + DATASET_QUALITY_TEST_GREP_FILES: JSON.stringify(grepFiles), + }, + }); +} + +if (argv.times) { + const runCounter = { succeeded: 0, failed: 0, remaining: argv.times }; + let exitStatus = 0; + times(argv.times, () => { + try { + runTests(); + runCounter.succeeded++; + } catch (e) { + exitStatus = 1; + runCounter.failed++; + } + runCounter.remaining--; + if (argv.times > 1) { + console.log(runCounter); + } + }); + process.exit(exitStatus); +} else { + runTests(); +} diff --git a/x-pack/plugins/dataset_quality/server/index.ts b/x-pack/plugins/dataset_quality/server/index.ts index 17b028aa1943..4a5e3ce0747c 100644 --- a/x-pack/plugins/dataset_quality/server/index.ts +++ b/x-pack/plugins/dataset_quality/server/index.ts @@ -5,6 +5,9 @@ * 2.0. */ -import { DatasetQualityServerPlugin } from './plugin'; +import { PluginInitializerContext } from '@kbn/core-plugins-server'; -export const plugin = () => new DatasetQualityServerPlugin(); +export async function plugin(initializerContext: PluginInitializerContext) { + const { DatasetQualityServerPlugin } = await import('./plugin'); + return new DatasetQualityServerPlugin(initializerContext); +} diff --git a/x-pack/plugins/dataset_quality/server/plugin.ts b/x-pack/plugins/dataset_quality/server/plugin.ts index b673fed3ad62..c34409d69798 100644 --- a/x-pack/plugins/dataset_quality/server/plugin.ts +++ b/x-pack/plugins/dataset_quality/server/plugin.ts @@ -5,10 +5,54 @@ * 2.0. */ -import { Plugin } from '@kbn/core/server'; +import { CoreSetup, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import { mapValues } from 'lodash'; +import { getDatasetQualityServerRouteRepository } from './routes'; +import { registerRoutes } from './routes/register_routes'; +import { DatasetQualityRouteHandlerResources } from './routes/types'; +import { + DatasetQualityPluginSetupDependencies, + DatasetQualityPluginStart, + DatasetQualityPluginStartDependencies, +} from './types'; export class DatasetQualityServerPlugin implements Plugin { - setup() {} + private readonly logger: Logger; - start() {} + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + setup( + core: CoreSetup, + plugins: DatasetQualityPluginSetupDependencies + ) { + this.logger.debug('dataset_quality: Setup'); + + const resourcePlugins = mapValues(plugins, (value, key) => { + return { + setup: value, + start: () => + core.getStartServices().then((services) => { + const [, pluginsStartContracts] = services; + return pluginsStartContracts[key as keyof DatasetQualityPluginStartDependencies]; + }), + }; + }) as DatasetQualityRouteHandlerResources['plugins']; + + registerRoutes({ + core, + logger: this.logger, + repository: getDatasetQualityServerRouteRepository(), + plugins: resourcePlugins, + }); + + return {}; + } + + start() { + this.logger.debug('dataset_quality: Started'); + + return {}; + } } diff --git a/x-pack/plugins/dataset_quality/server/routes/create_datasets_quality_server_route.ts b/x-pack/plugins/dataset_quality/server/routes/create_datasets_quality_server_route.ts new file mode 100644 index 000000000000..c76d1d800de9 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/create_datasets_quality_server_route.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { createServerRouteFactory } from '@kbn/server-route-repository'; +import { DatasetQualityRouteCreateOptions, DatasetQualityRouteHandlerResources } from './types'; + +export const createDatasetQualityServerRoute = createServerRouteFactory< + DatasetQualityRouteHandlerResources, + DatasetQualityRouteCreateOptions +>(); diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/get_data_streams.test.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/get_data_streams.test.ts new file mode 100644 index 000000000000..0b45d6fa8b34 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/get_data_streams.test.ts @@ -0,0 +1,173 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { dataStreamService } from '../../../services'; + +import { getDataStreams } from '.'; + +jest.mock('../../../services/data_stream', () => { + return { + dataStreamService: { + getMatchingDataStreams: jest.fn().mockImplementation(() => { + return [ + { + name: 'logs-elastic_agent-default', + timestamp_field: { name: '@timestamp' }, + indices: [ + { + index_name: '.ds-logs-elastic_agent-default-2023.05.17-000001', + index_uuid: 'EcqQR36PTNCKVnfAftq_Rw', + }, + ], + generation: 1, + _meta: { managed_by: 'fleet', managed: true, package: { name: 'elastic_agent' } }, + status: 'YELLOW', + template: 'logs-elastic_agent', + ilm_policy: 'logs', + hidden: false, + system: false, + allow_custom_routing: false, + replicated: false, + }, + { + name: 'logs-elastic_agent.filebeat-default', + timestamp_field: { name: '@timestamp' }, + indices: [ + { + index_name: '.ds-logs-elastic_agent.filebeat-default-2023.05.17-000001', + index_uuid: 'v5uEn55TRrurU3Bf4CBtzw', + }, + ], + generation: 1, + _meta: { managed_by: 'fleet', managed: true, package: { name: 'elastic_agent' } }, + status: 'YELLOW', + template: 'logs-elastic_agent.filebeat', + ilm_policy: 'logs', + hidden: false, + system: false, + allow_custom_routing: false, + replicated: false, + }, + { + name: 'logs-elastic_agent.fleet_server-default', + timestamp_field: { name: '@timestamp' }, + indices: [ + { + index_name: '.ds-logs-elastic_agent.fleet_server-default-2023.05.17-000001', + index_uuid: 'nThe6dkaQnagAlyNsAyYsA', + }, + ], + generation: 1, + _meta: { managed_by: 'fleet', managed: true, package: { name: 'elastic_agent' } }, + status: 'YELLOW', + template: 'logs-elastic_agent.fleet_server', + ilm_policy: 'logs', + hidden: false, + system: false, + allow_custom_routing: false, + replicated: false, + }, + { + name: 'logs-elastic_agent.metricbeat-default', + timestamp_field: { name: '@timestamp' }, + indices: [ + { + index_name: '.ds-logs-elastic_agent.metricbeat-default-2023.05.17-000001', + index_uuid: 'Y5vQ7V6-QSSMM-CPdqOkCg', + }, + ], + generation: 1, + _meta: { managed_by: 'fleet', managed: true, package: { name: 'elastic_agent' } }, + status: 'YELLOW', + template: 'logs-elastic_agent.metricbeat', + ilm_policy: 'logs', + hidden: false, + system: false, + allow_custom_routing: false, + replicated: false, + }, + { + name: 'logs-test.test-default', + timestamp_field: { name: '@timestamp' }, + indices: [ + { + index_name: '.ds-logs-elastic_agent.metricbeat-default-2023.05.17-000001', + index_uuid: 'Y5vQ7V6-QSSMM-CPdqOkCg', + }, + ], + }, + ]; + }), + }, + }; +}); + +describe('getDataStreams', () => { + it('Passes the correct parameters to the DataStreamService', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + await getDataStreams({ + esClient: esClientMock, + type: 'logs', + datasetQuery: 'nginx', + uncategorisedOnly: true, + }); + expect(dataStreamService.getMatchingDataStreams).toHaveBeenCalledWith(expect.anything(), { + type: 'logs', + dataset: '*nginx*', + }); + }); + describe('uncategorisedOnly option', () => { + it('Returns the correct number of results when true', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + const results = await getDataStreams({ + esClient: esClientMock, + type: 'logs', + datasetQuery: 'nginx', + uncategorisedOnly: true, + }); + expect(results.items.length).toBe(1); + }); + it('Returns the correct number of results when false', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + const results = await getDataStreams({ + esClient: esClientMock, + type: 'logs', + datasetQuery: 'nginx', + uncategorisedOnly: false, + }); + expect(results.items.length).toBe(5); + }); + }); + it('Formats the items correctly', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + const results = await getDataStreams({ + esClient: esClientMock, + type: 'logs', + uncategorisedOnly: false, + }); + expect(results.items.sort()).toEqual([ + { + name: 'logs-elastic_agent-default', + integration: 'elastic_agent', + }, + { + name: 'logs-elastic_agent.filebeat-default', + integration: 'elastic_agent', + }, + { + name: 'logs-elastic_agent.fleet_server-default', + integration: 'elastic_agent', + }, + { + name: 'logs-elastic_agent.metricbeat-default', + integration: 'elastic_agent', + }, + { name: 'logs-test.test-default' }, + ]); + }); +}); diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts new file mode 100644 index 000000000000..6154e3bc11a2 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core/server'; +import { dataStreamService } from '../../../services'; +import { DataStreamTypes } from '../../../types/data_stream'; + +export async function getDataStreams(options: { + esClient: ElasticsearchClient; + type?: DataStreamTypes; + datasetQuery?: string; + uncategorisedOnly: boolean; +}) { + const { esClient, type, datasetQuery, uncategorisedOnly } = options; + + const allDataStreams = await dataStreamService.getMatchingDataStreams(esClient, { + type: type ?? '*', + dataset: datasetQuery ? `*${datasetQuery}*` : '*', + }); + + const filteredDataStreams = uncategorisedOnly + ? allDataStreams.filter((stream) => { + return !stream._meta || !stream._meta.managed_by || stream._meta.managed_by !== 'fleet'; + }) + : allDataStreams; + + const mappedDataStreams = filteredDataStreams.map((dataStream) => ({ + name: dataStream.name, + integration: dataStream._meta?.package?.name, + })); + + return { + items: mappedDataStreams, + }; +} diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts new file mode 100644 index 000000000000..830c3b162573 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { dataStreamService } from '../../../services'; + +import { getDataStreamsStats } from '.'; + +jest.mock('../../../services/data_stream', () => { + return { + dataStreamService: { + getMatchingDataStreamsStats: jest.fn().mockImplementation(() => { + return [ + { + data_stream: 'logs-elastic_agent-default', + backing_indices: 1, + store_size: '1gb', + store_size_bytes: 1170805528, + maximum_timestamp: 1698916071000, + }, + { + data_stream: 'logs-elastic_agent.filebeat-default', + backing_indices: 1, + store_size: '1.3mb', + store_size_bytes: 1459100, + maximum_timestamp: 1698902209996, + }, + { + data_stream: 'logs-elastic_agent.fleet_server-default', + backing_indices: 1, + store_size: '2.9mb', + store_size_bytes: 3052148, + maximum_timestamp: 1698914110010, + }, + { + data_stream: 'logs-elastic_agent.metricbeat-default', + backing_indices: 1, + store_size: '1.6mb', + store_size_bytes: 1704807, + maximum_timestamp: 1698672046707, + }, + { + data_stream: 'logs-test.test-default', + backing_indices: 1, + store_size: '6.2mb', + store_size_bytes: 6570447, + maximum_timestamp: 1698913802000, + }, + ]; + }), + }, + }; +}); + +describe('getDataStreams', () => { + it('Passes the correct parameters to the DataStreamService', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + await getDataStreamsStats({ + esClient: esClientMock, + type: 'logs', + datasetQuery: 'nginx', + }); + expect(dataStreamService.getMatchingDataStreamsStats).toHaveBeenCalledWith(expect.anything(), { + type: 'logs', + dataset: '*nginx*', + }); + }); + it('Formats the items correctly', async () => { + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(); + const results = await getDataStreamsStats({ + esClient: esClientMock, + type: 'logs', + }); + expect(results.items.sort()).toEqual([ + { + name: 'logs-elastic_agent-default', + size: '1gb', + size_bytes: 1170805528, + last_activity: 1698916071000, + }, + { + name: 'logs-elastic_agent.filebeat-default', + size: '1.3mb', + size_bytes: 1459100, + last_activity: 1698902209996, + }, + { + name: 'logs-elastic_agent.fleet_server-default', + size: '2.9mb', + size_bytes: 3052148, + last_activity: 1698914110010, + }, + { + name: 'logs-elastic_agent.metricbeat-default', + size: '1.6mb', + size_bytes: 1704807, + last_activity: 1698672046707, + }, + { + name: 'logs-test.test-default', + size: '6.2mb', + size_bytes: 6570447, + last_activity: 1698913802000, + }, + ]); + }); +}); diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts new file mode 100644 index 000000000000..9ec252d09635 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core/server'; +import { dataStreamService } from '../../../services'; +import { DataStreamTypes } from '../../../types/data_stream'; + +export async function getDataStreamsStats(options: { + esClient: ElasticsearchClient; + type?: DataStreamTypes; + datasetQuery?: string; +}) { + const { esClient, type, datasetQuery } = options; + + const matchingDataStreamsStats = await dataStreamService.getMatchingDataStreamsStats(esClient, { + type: type ?? '*', + dataset: datasetQuery ? `*${datasetQuery}*` : '*', + }); + + const mappedDataStreams = matchingDataStreamsStats.map((dataStream) => { + return { + name: dataStream.data_stream, + size: dataStream.store_size, + size_bytes: dataStream.store_size_bytes, + last_activity: dataStream.maximum_timestamp, + }; + }); + + return { + items: mappedDataStreams, + }; +} diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts new file mode 100644 index 000000000000..4217b9711226 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { keyBy, merge, values } from 'lodash'; +import { dataStreamTypesRt } from '../../../common/data_streams'; +import { DataStreamsStatResponse } from '../../types/data_stream'; +import { createDatasetQualityServerRoute } from '../create_datasets_quality_server_route'; +import { getDataStreams } from './get_data_streams'; +import { getDataStreamsStats } from './get_data_streams_stats'; + +const statsRoute = createDatasetQualityServerRoute({ + endpoint: 'GET /internal/dataset_quality/data_streams/stats', + params: t.type({ + query: t.intersection([ + dataStreamTypesRt, + t.partial({ + datasetQuery: t.string, + }), + ]), + }), + options: { + tags: [], + }, + async handler(resources): Promise { + const { context, params, plugins } = resources; + const coreContext = await context.core; + + // Query datastreams as the current user as the Kibana internal user may not have all the required permissions + const esClient = coreContext.elasticsearch.client.asCurrentUser; + + const fleetPluginStart = await plugins.fleet.start(); + const packageClient = fleetPluginStart.packageService.asInternalUser; + const packages = await packageClient.getPackages(); + + const [dataStreams, dataStreamsStats] = await Promise.all([ + getDataStreams({ + esClient, + ...params.query, + uncategorisedOnly: false, + }), + getDataStreamsStats({ esClient, ...params.query }), + ]); + + const installedPackages = dataStreams.items.map((item) => item.integration); + + const integrations = packages + .filter((pkg) => installedPackages.includes(pkg.name)) + .map((p) => ({ + name: p.name, + title: p.title, + version: p.version, + icons: p.icons, + })); + + return { + dataStreamsStats: values( + merge(keyBy(dataStreams.items, 'name'), keyBy(dataStreamsStats.items, 'name')) + ), + integrations, + }; + }, +}); + +export const dataStreamsRouteRepository = { + ...statsRoute, +}; diff --git a/x-pack/plugins/dataset_quality/server/routes/index.ts b/x-pack/plugins/dataset_quality/server/routes/index.ts new file mode 100644 index 000000000000..bb242e0db872 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { EndpointOf, ServerRouteRepository } from '@kbn/server-route-repository'; +import { dataStreamsRouteRepository } from './data_streams/routes'; + +function getTypedDatasetQualityServerRouteRepository() { + const repository = { + ...dataStreamsRouteRepository, + }; + + return repository; +} + +export const getDatasetQualityServerRouteRepository = (): ServerRouteRepository => { + return getTypedDatasetQualityServerRouteRepository(); +}; + +export type DatasetQualityServerRouteRepository = ReturnType< + typeof getTypedDatasetQualityServerRouteRepository +>; + +export type APIEndpoint = EndpointOf; diff --git a/x-pack/plugins/dataset_quality/server/routes/register_routes.ts b/x-pack/plugins/dataset_quality/server/routes/register_routes.ts new file mode 100644 index 000000000000..7ebecaa1346f --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/register_routes.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; +import { CoreSetup, Logger, RouteRegistrar } from '@kbn/core/server'; +import { + ServerRouteRepository, + decodeRequestParams, + parseEndpoint, + routeValidationObject, +} from '@kbn/server-route-repository'; +import * as t from 'io-ts'; +import { DatasetQualityRequestHandlerContext } from '../types'; +import { DatasetQualityRouteHandlerResources } from './types'; + +interface RegisterRoutes { + core: CoreSetup; + repository: ServerRouteRepository; + logger: Logger; + plugins: DatasetQualityRouteHandlerResources['plugins']; +} + +export function registerRoutes({ repository, core, logger, plugins }: RegisterRoutes) { + const routes = Object.values(repository); + + const router = core.http.createRouter(); + + routes.forEach((route) => { + const { endpoint, options, handler, params } = route; + const { pathname, method } = parseEndpoint(endpoint); + + (router[method] as RouteRegistrar)( + { + path: pathname, + validate: routeValidationObject, + options, + }, + async (context, request, response) => { + try { + const decodedParams = decodeRequestParams( + { + params: request.params, + body: request.body, + query: request.query, + }, + params ?? t.strict({}) + ); + + const data = (await handler({ + context, + request, + logger, + params: decodedParams, + plugins, + })) as any; + + if (data === undefined) { + return response.noContent(); + } + + return response.ok({ body: data }); + } catch (error) { + if (Boom.isBoom(error)) { + logger.error(error.output.payload.message); + return response.customError({ + statusCode: error.output.statusCode, + body: { message: error.output.payload.message }, + }); + } + + logger.error(error); + const opts = { + statusCode: 500, + body: { + message: error.message, + }, + }; + + if (error instanceof errors.RequestAbortedError) { + opts.statusCode = 499; + opts.body.message = 'Client closed request'; + } + + return response.customError(opts); + } + } + ); + }); +} diff --git a/x-pack/plugins/dataset_quality/server/routes/types.ts b/x-pack/plugins/dataset_quality/server/routes/types.ts new file mode 100644 index 000000000000..8507bcde5763 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/types.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { KibanaRequest, Logger } from '@kbn/core/server'; +import { DatasetQualityServerRouteRepository } from '.'; +import { + DatasetQualityPluginSetupDependencies, + DatasetQualityPluginStartDependencies, + DatasetQualityRequestHandlerContext, +} from '../types'; + +export type { DatasetQualityServerRouteRepository }; + +export interface DatasetQualityRouteHandlerResources { + context: DatasetQualityRequestHandlerContext; + logger: Logger; + request: KibanaRequest; + plugins: { + [key in keyof DatasetQualityPluginSetupDependencies]: { + setup: Required[key]; + start: () => Promise[key]>; + }; + }; +} + +export interface DatasetQualityRouteCreateOptions { + options: { + tags: string[]; + }; +} diff --git a/x-pack/plugins/dataset_quality/server/services/data_stream.ts b/x-pack/plugins/dataset_quality/server/services/data_stream.ts new file mode 100644 index 000000000000..e0fc6e674882 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/services/data_stream.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + IndicesDataStream, + IndicesDataStreamsStatsDataStreamsStatsItem, +} from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient } from '@kbn/core/server'; + +class DataStreamService { + public streamPartsToIndexPattern({ type, dataset }: { dataset: string; type: string }) { + return `${type}-${dataset}`; + } + + public async getMatchingDataStreams( + esClient: ElasticsearchClient, + dataStreamParts: { + dataset: string; + type: string; + } + ): Promise { + try { + const { data_streams: dataStreamsInfo } = await esClient.indices.getDataStream({ + name: this.streamPartsToIndexPattern(dataStreamParts), + }); + + return dataStreamsInfo; + } catch (e) { + if (e.statusCode === 404) { + return []; + } + throw e; + } + } + + public async getMatchingDataStreamsStats( + esClient: ElasticsearchClient, + dataStreamParts: { + dataset: string; + type: string; + } + ): Promise { + try { + const { data_streams: dataStreamsStats } = await esClient.indices.dataStreamsStats({ + name: this.streamPartsToIndexPattern(dataStreamParts), + human: true, + }); + + return dataStreamsStats; + } catch (e) { + if (e.statusCode === 404) { + return []; + } + throw e; + } + } +} + +export const dataStreamService = new DataStreamService(); diff --git a/x-pack/plugins/dataset_quality/server/services/index.ts b/x-pack/plugins/dataset_quality/server/services/index.ts new file mode 100644 index 000000000000..86173c476dd0 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/services/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { dataStreamService } from './data_stream'; diff --git a/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/authentication.ts b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/authentication.ts new file mode 100644 index 000000000000..4b30ccbf00d9 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/authentication.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum DatasetQualityUsername { + noAccessUser = 'no_access_user', + viewerUser = 'viewer', + editorUser = 'editor', + datasetQualityLogsUser = 'dataset_quality_logs_user', +} + +export enum DatasetQualityCustomRolename { + datasetQualityLogsUser = 'dataset_quality_logs_user', +} + +export const customRoles = { + [DatasetQualityCustomRolename.datasetQualityLogsUser]: { + elasticsearch: { + indices: [ + { + names: ['logs-*-*'], + privileges: ['monitor'], + }, + ], + }, + }, +}; + +export const users: Record< + DatasetQualityUsername, + { + builtInRoleNames?: string[]; + customRoleNames?: DatasetQualityCustomRolename[]; + } +> = { + [DatasetQualityUsername.noAccessUser]: {}, + [DatasetQualityUsername.viewerUser]: { + builtInRoleNames: ['viewer'], + }, + [DatasetQualityUsername.editorUser]: { + builtInRoleNames: ['editor'], + }, + [DatasetQualityUsername.datasetQualityLogsUser]: { + builtInRoleNames: ['editor'], + customRoleNames: [DatasetQualityCustomRolename.datasetQualityLogsUser], + }, +}; + +export const DATASET_QUALITY_TEST_PASSWORD = 'changeme'; diff --git a/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts new file mode 100644 index 000000000000..879b02f8a93c --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/call_kibana.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import axios, { AxiosRequestConfig, AxiosError } from 'axios'; +import { once } from 'lodash'; +import { Elasticsearch, Kibana } from '..'; + +export async function callKibana({ + elasticsearch, + kibana, + options, +}: { + elasticsearch: Omit; + kibana: Kibana; + options: AxiosRequestConfig; +}): Promise { + const baseUrl = await getBaseUrl(kibana.hostname); + const { username, password } = elasticsearch; + + const { data } = await axios.request({ + ...options, + baseURL: baseUrl, + auth: { username, password }, + headers: { 'kbn-xsrf': 'true', ...options.headers }, + }); + return data; +} + +const getBaseUrl = once(async (kibanaHostname: string) => { + try { + await axios.request({ url: kibanaHostname, maxRedirects: 0 }); + } catch (e) { + if (isAxiosError(e)) { + const location = e.response?.headers?.location ?? ''; + const hasBasePath = RegExp(/^\/\w{3}$/).test(location); + const basePath = hasBasePath ? location : ''; + return `${kibanaHostname}${basePath}`; + } + + throw e; + } + return kibanaHostname; +}); + +export function isAxiosError(e: AxiosError | Error): e is AxiosError { + return 'isAxiosError' in e; +} + +export class AbortError extends Error { + constructor(message: string) { + super(message); + } +} diff --git a/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_custom_role.ts b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_custom_role.ts new file mode 100644 index 000000000000..141f5333c28b --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_custom_role.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Elasticsearch, Kibana } from '..'; +import { customRoles, DatasetQualityCustomRolename } from '../authentication'; +import { callKibana } from './call_kibana'; + +export async function createCustomRole({ + elasticsearch, + kibana, + roleName, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; + roleName: DatasetQualityCustomRolename; +}) { + const role = customRoles[roleName]; + + await callKibana({ + elasticsearch, + kibana, + options: { + method: 'PUT', + url: `/api/security/role/${roleName}`, + data: role, + }, + }); +} diff --git a/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_or_update_user.ts b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_or_update_user.ts new file mode 100644 index 000000000000..57e9e6a64c0d --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/helpers/create_or_update_user.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable no-console */ + +import { difference, union } from 'lodash'; +import { Elasticsearch, Kibana } from '..'; +import { callKibana, isAxiosError } from './call_kibana'; + +interface User { + username: string; + roles: string[]; + full_name?: string; + email?: string; + enabled?: boolean; +} + +export async function createOrUpdateUser({ + elasticsearch, + kibana, + user, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; + user: User; +}) { + const existingUser = await getUser({ + elasticsearch, + kibana, + username: user.username, + }); + if (!existingUser) { + return createUser({ elasticsearch, kibana, newUser: user }); + } + + return updateUser({ + elasticsearch, + kibana, + existingUser, + newUser: user, + }); +} + +async function createUser({ + elasticsearch, + kibana, + newUser, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; + newUser: User; +}) { + const user = await callKibana({ + elasticsearch, + kibana, + options: { + method: 'POST', + url: `/internal/security/users/${newUser.username}`, + data: { + ...newUser, + enabled: true, + password: elasticsearch.password, + }, + }, + }); + + console.log(`User "${newUser.username}" was created`); + return user; +} + +async function updateUser({ + elasticsearch, + kibana, + existingUser, + newUser, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; + existingUser: User; + newUser: User; +}) { + const { username } = newUser; + const allRoles = union(existingUser.roles, newUser.roles); + const hasAllRoles = difference(allRoles, existingUser.roles).length === 0; + if (hasAllRoles) { + console.log(`Skipping: User "${username}" already has necessary roles: "${newUser.roles}"`); + return; + } + + // assign role to user + await callKibana({ + elasticsearch, + kibana, + options: { + method: 'POST', + url: `/internal/security/users/${username}`, + data: { ...existingUser, roles: allRoles }, + }, + }); + + console.log(`User "${username}" was updated`); +} + +async function getUser({ + elasticsearch, + kibana, + username, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; + username: string; +}) { + try { + return await callKibana({ + elasticsearch, + kibana, + options: { + url: `/internal/security/users/${username}`, + }, + }); + } catch (e) { + // return empty if user doesn't exist + if (isAxiosError(e) && e.response?.status === 404) { + return null; + } + + throw e; + } +} diff --git a/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/index.ts b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/index.ts new file mode 100644 index 000000000000..9cfb2f1dc66d --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/test_helpers/create_dataset_quality_users/index.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { asyncForEach } from '@kbn/std'; +import { AbortError, callKibana } from './helpers/call_kibana'; +import { createOrUpdateUser } from './helpers/create_or_update_user'; +import { DatasetQualityUsername, users } from './authentication'; +import { createCustomRole } from './helpers/create_custom_role'; + +export interface Elasticsearch { + node: string; + username: string; + password: string; +} + +export interface Kibana { + hostname: string; +} + +export async function createDatasetQualityUsers({ + kibana, + elasticsearch, +}: { + kibana: Kibana; + elasticsearch: Elasticsearch; +}) { + const isCredentialsValid = await getIsCredentialsValid({ + elasticsearch, + kibana, + }); + + if (!isCredentialsValid) { + throw new AbortError('Invalid username/password'); + } + + const isSecurityEnabled = await getIsSecurityEnabled({ + elasticsearch, + kibana, + }); + + if (!isSecurityEnabled) { + throw new AbortError('Security must be enabled!'); + } + + const datasetQualityUsers = Object.values(DatasetQualityUsername); + await asyncForEach(datasetQualityUsers, async (username) => { + const user = users[username]; + const { builtInRoleNames = [], customRoleNames = [] } = user; + + // create custom roles + await Promise.all( + customRoleNames.map(async (roleName) => createCustomRole({ elasticsearch, kibana, roleName })) + ); + + // create user + const roles = builtInRoleNames.concat(customRoleNames); + await createOrUpdateUser({ + elasticsearch, + kibana, + user: { username, roles }, + }); + }); + + return datasetQualityUsers; +} + +async function getIsSecurityEnabled({ + elasticsearch, + kibana, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; +}) { + try { + await callKibana({ + elasticsearch, + kibana, + options: { + url: `/internal/security/me`, + }, + }); + return true; + } catch (err) { + return false; + } +} + +async function getIsCredentialsValid({ + elasticsearch, + kibana, +}: { + elasticsearch: Elasticsearch; + kibana: Kibana; +}) { + try { + await callKibana({ + elasticsearch, + kibana, + options: { + validateStatus: (status) => status >= 200 && status < 400, + url: `/`, + }, + }); + return true; + } catch (err) { + return false; + } +} diff --git a/x-pack/plugins/dataset_quality/server/types.ts b/x-pack/plugins/dataset_quality/server/types.ts new file mode 100644 index 000000000000..3874040f5d3b --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CustomRequestHandlerContext } from '@kbn/core/server'; +import { FleetSetupContract, FleetStartContract } from '@kbn/fleet-plugin/server'; + +export interface DatasetQualityPluginSetupDependencies { + fleet: FleetSetupContract; +} + +export interface DatasetQualityPluginStartDependencies { + fleet: FleetStartContract; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface DatasetQualityPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface DatasetQualityPluginStart {} + +export type DatasetQualityRequestHandlerContext = CustomRequestHandlerContext<{}>; diff --git a/x-pack/plugins/dataset_quality/server/types/data_stream.ts b/x-pack/plugins/dataset_quality/server/types/data_stream.ts new file mode 100644 index 000000000000..423d85985c59 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/types/data_stream.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ByteSize } from '@elastic/elasticsearch/lib/api/types'; +import { Integration } from './integration'; + +export interface DataStreamsStatResponse { + dataStreamsStats: DataStreamStat[]; + integrations: Integration[]; +} + +export interface DataStreamStat { + name: string; + size?: ByteSize; + size_bytes?: number; + last_activity?: number; + integration?: Integration; +} + +export type DataStreamTypes = 'logs' | 'metrics' | 'traces' | 'synthetics' | 'profiling'; diff --git a/x-pack/plugins/dataset_quality/server/types/integration.ts b/x-pack/plugins/dataset_quality/server/types/integration.ts new file mode 100644 index 000000000000..2595a120c8b7 --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/types/integration.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface Integration { + name: string; + title?: string; + version?: string; + icons?: IntegrationIcon[]; +} + +export interface IntegrationIcon { + path: string; + src: string; + title?: string; + size?: string; + type?: string; +} diff --git a/x-pack/plugins/dataset_quality/tsconfig.json b/x-pack/plugins/dataset_quality/tsconfig.json index efe7ece5983a..32baf4671143 100644 --- a/x-pack/plugins/dataset_quality/tsconfig.json +++ b/x-pack/plugins/dataset_quality/tsconfig.json @@ -4,14 +4,28 @@ "outDir": "target/types" }, "include": [ - "../../../typings/**/*", "common/**/*", "public/**/*", - "server/**/*.ts", - "../../typings/**/*" + "server/**/*", + "../../../typings/**/*", ], "kbn_references": [ "@kbn/core", + "@kbn/core-plugins-server", + "@kbn/core-elasticsearch-server-mocks", + "@kbn/deeplinks-observability", + "@kbn/fleet-plugin", + "@kbn/observability-shared-plugin", + "@kbn/server-route-repository", + "@kbn/share-plugin", + "@kbn/std", + "@kbn/i18n", + "@kbn/kibana-react-plugin", + "@kbn/i18n-react", + "@kbn/field-formats-plugin", + "@kbn/field-types" ], - "exclude": ["target/**/*"] + "exclude": [ + "target/**/*", + ] } diff --git a/x-pack/plugins/elastic_assistant/server/lib/executor.ts b/x-pack/plugins/elastic_assistant/server/lib/executor.ts index 88266914f36e..27064f3fb196 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/executor.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/executor.ts @@ -31,15 +31,7 @@ export const executeAction = async ({ const actionResult = await actionsClient.execute({ actionId: connectorId, - params: { - ...request.body.params, - subActionParams: - // TODO: Remove in part 2 of streaming work for security solution - // tracked here: https://github.com/elastic/security-team/issues/7363 - request.body.params.subAction === 'invokeAI' - ? request.body.params.subActionParams - : { body: JSON.stringify(request.body.params.subActionParams), stream: true }, - }, + params: request.body.params, }); if (actionResult.status === 'error') { diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts index 7f06b4b45619..7db042a9c9cf 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts @@ -97,9 +97,13 @@ describe('callAgentExecutor', () => { kbResource: ESQL_RESOURCE, }); - expect(mockCall).toHaveBeenCalledWith({ - input: '\n\nDo you know my name?', - }); + // We don't care about the `config` argument, so we use `expect.anything()` + expect(mockCall).toHaveBeenCalledWith( + { + input: '\n\nDo you know my name?', + }, + expect.anything() + ); }); it('kicks off the chain with the expected message when langChainMessages has only one entry', async () => { @@ -115,9 +119,13 @@ describe('callAgentExecutor', () => { kbResource: ESQL_RESOURCE, }); - expect(mockCall).toHaveBeenCalledWith({ - input: 'What is my name?', - }); + // We don't care about the `config` argument, so we use `expect.anything()` + expect(mockCall).toHaveBeenCalledWith( + { + input: 'What is my name?', + }, + expect.anything() + ); }); it('returns the expected response body', async () => { diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts index ad54b0d1e8b4..3a27226dc804 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts @@ -14,7 +14,16 @@ import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { ActionsClientLlm } from '../llm/actions_client_llm'; import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; import type { AgentExecutorParams, AgentExecutorResponse } from '../executors/types'; +import { withAssistantSpan } from '../tracers/with_assistant_span'; +import { APMTracer } from '../tracers/apm_tracer'; +export const DEFAULT_AGENT_EXECUTOR_ID = 'Elastic AI Assistant Agent Executor'; + +/** + * The default agent executor used by the Elastic AI Assistant. Main agent/chain that wraps the ActionsClientLlm, + * sets up a conversation BufferMemory from chat history, and registers tools like the ESQLKnowledgeBaseTool. + * + */ export const callAgentExecutor = async ({ actions, connectorId, @@ -25,6 +34,7 @@ export const callAgentExecutor = async ({ request, elserId, kbResource, + traceOptions, }: AgentExecutorParams): AgentExecutorResponse => { const llm = new ActionsClientLlm({ actions, connectorId, request, llmType, logger }); @@ -58,12 +68,14 @@ export const callAgentExecutor = async ({ // Create a chain that uses the ELSER backed ElasticsearchStore, override k=10 for esql query generation for now const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever(10)); + // TODO: Dependency inject these tools const tools: Tool[] = [ new ChainTool({ - name: 'esql-language-knowledge-base', + name: 'ESQLKnowledgeBaseTool', description: 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', chain, + tags: ['esql', 'query-generation', 'knowledge-base'], }), ]; @@ -73,11 +85,37 @@ export const callAgentExecutor = async ({ verbose: false, }); - await executor.call({ input: latestMessage[0].content }); + // Sets up tracer for tracing executions to APM. See x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx + // If LangSmith env vars are set, executions will be traced there as well. See https://docs.smith.langchain.com/tracing + const apmTracer = new APMTracer({ projectName: traceOptions?.projectName ?? 'default' }, logger); + + let traceData; + + // Wrap executor call with an APM span for instrumentation + await withAssistantSpan(DEFAULT_AGENT_EXECUTOR_ID, async (span) => { + if (span?.transaction?.ids['transaction.id'] != null && span?.ids['trace.id'] != null) { + traceData = { + // Transactions ID since this span is the parent + transaction_id: span.transaction.ids['transaction.id'], + trace_id: span.ids['trace.id'], + }; + span.addLabels({ evaluationId: traceOptions?.evaluationId }); + } + + return executor.call( + { input: latestMessage[0].content }, + { + callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], + runName: DEFAULT_AGENT_EXECUTOR_ID, + tags: traceOptions?.tags ?? [], + } + ); + }); return { connector_id: connectorId, data: llm.getActionResultData(), // the response from the actions framework + trace_data: traceData, status: 'ok', }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts index 608b15eed384..32c9c0988f4d 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts @@ -14,6 +14,11 @@ import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { ActionsClientLlm } from '../llm/actions_client_llm'; import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; import type { AgentExecutorParams, AgentExecutorResponse } from './types'; +import { withAssistantSpan } from '../tracers/with_assistant_span'; +import { APMTracer } from '../tracers/apm_tracer'; + +export const OPEN_AI_FUNCTIONS_AGENT_EXECUTOR_ID = + 'Elastic AI Assistant Agent Executor (OpenAI Functions)'; /** * This is an agent executor to be used with the model evaluation API for benchmarking. @@ -25,11 +30,13 @@ export const callOpenAIFunctionsExecutor = async ({ actions, connectorId, esClient, - elserId, langChainMessages, llmType, logger, request, + elserId, + kbResource, + traceOptions, }: AgentExecutorParams): AgentExecutorResponse => { const llm = new ActionsClientLlm({ actions, connectorId, request, llmType, logger }); @@ -45,15 +52,32 @@ export const callOpenAIFunctionsExecutor = async ({ }); // ELSER backed ElasticsearchStore for Knowledge Base - const esStore = new ElasticsearchStore(esClient, KNOWLEDGE_BASE_INDEX_PATTERN, logger, elserId); - const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever()); + const esStore = new ElasticsearchStore( + esClient, + KNOWLEDGE_BASE_INDEX_PATTERN, + logger, + elserId, + kbResource + ); + + const modelExists = await esStore.isModelInstalled(); + if (!modelExists) { + throw new Error( + 'Please ensure ELSER is configured to use the Knowledge Base, otherwise disable the Knowledge Base in Advanced Settings to continue.' + ); + } + + // Create a chain that uses the ELSER backed ElasticsearchStore, override k=10 for esql query generation for now + const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever(10)); + // TODO: Dependency inject these tools const tools: Tool[] = [ new ChainTool({ - name: 'esql-language-knowledge-base', + name: 'ESQLKnowledgeBaseTool', description: 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language.', chain, + tags: ['esql', 'query-generation', 'knowledge-base'], }), ]; @@ -63,11 +87,37 @@ export const callOpenAIFunctionsExecutor = async ({ verbose: false, }); - await executor.call({ input: latestMessage[0].content }); + // Sets up tracer for tracing executions to APM. See x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx + // If LangSmith env vars are set, executions will be traced there as well. See https://docs.smith.langchain.com/tracing + const apmTracer = new APMTracer({ projectName: traceOptions?.projectName ?? 'default' }, logger); + + let traceData; + + // Wrap executor call with an APM span for instrumentation + await withAssistantSpan(OPEN_AI_FUNCTIONS_AGENT_EXECUTOR_ID, async (span) => { + if (span?.transaction?.ids['transaction.id'] != null && span?.ids['trace.id'] != null) { + traceData = { + // Transactions ID since this span is the parent + transaction_id: span.transaction.ids['transaction.id'], + trace_id: span.ids['trace.id'], + }; + span.addLabels({ evaluationId: traceOptions?.evaluationId }); + } + + return executor.call( + { input: latestMessage[0].content }, + { + callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], + runName: OPEN_AI_FUNCTIONS_AGENT_EXECUTOR_ID, + tags: traceOptions?.tags ?? [], + } + ); + }); return { connector_id: connectorId, data: llm.getActionResultData(), // the response from the actions framework + trace_data: traceData, status: 'ok', }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts index 1c15ff8c97da..e4d564f677e1 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts @@ -10,6 +10,7 @@ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { BaseMessage } from 'langchain/schema'; import { Logger } from '@kbn/logging'; import { KibanaRequest } from '@kbn/core-http-server'; +import type { LangChainTracer } from 'langchain/callbacks'; import { RequestBody, ResponseBody } from '../types'; export interface AgentExecutorParams { @@ -22,10 +23,31 @@ export interface AgentExecutorParams { logger: Logger; request: KibanaRequest; elserId?: string; + traceOptions?: TraceOptions; } export type AgentExecutorResponse = Promise; export type AgentExecutor = (params: AgentExecutorParams) => AgentExecutorResponse; -export type AgentExecutorEvaluator = (langChainMessages: BaseMessage[]) => AgentExecutorResponse; +export type AgentExecutorEvaluator = ( + langChainMessages: BaseMessage[], + exampleId?: string +) => AgentExecutorResponse; + +export interface AgentExecutorEvaluatorWithMetadata { + agentEvaluator: AgentExecutorEvaluator; + metadata: { + connectorName: string; + runName: string; + }; +} + +export interface TraceOptions { + evaluationId?: string; + exampleId?: string; + projectName?: string; + runName?: string; + tags?: string[]; + tracers?: LangChainTracer[]; +} diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts index 99fa1ac94690..ca1afdeef736 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { v4 as uuidv4 } from 'uuid'; import { KibanaRequest, Logger } from '@kbn/core/server'; import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; import { LLM } from 'langchain/llms/base'; @@ -15,12 +16,22 @@ import { RequestBody } from '../types'; const LLM_TYPE = 'ActionsClientLlm'; +interface ActionsClientLlmParams { + actions: ActionsPluginStart; + connectorId: string; + llmType?: string; + logger: Logger; + request: KibanaRequest; + traceId?: string; +} + export class ActionsClientLlm extends LLM { #actions: ActionsPluginStart; #connectorId: string; #logger: Logger; #request: KibanaRequest; #actionResultData: string; + #traceId: string; // Local `llmType` as it can change and needs to be accessed by abstract `_llmType()` method // Not using getter as `this._llmType()` is called in the constructor via `super({})` @@ -29,20 +40,16 @@ export class ActionsClientLlm extends LLM { constructor({ actions, connectorId, + traceId = uuidv4(), llmType, logger, request, - }: { - actions: ActionsPluginStart; - connectorId: string; - llmType?: string; - logger: Logger; - request: KibanaRequest; - }) { + }: ActionsClientLlmParams) { super({}); this.#actions = actions; this.#connectorId = connectorId; + this.#traceId = traceId; this.llmType = llmType ?? LLM_TYPE; this.#logger = logger; this.#request = request; @@ -68,7 +75,9 @@ export class ActionsClientLlm extends LLM { // convert the Langchain prompt to an assistant message: const assistantMessage = getMessageContentAndRole(prompt); this.#logger.debug( - `ActionsClientLlm#_call assistantMessage:\n${JSON.stringify(assistantMessage)} ` + `ActionsClientLlm#_call\ntraceId: ${this.#traceId}\nassistantMessage:\n${JSON.stringify( + assistantMessage + )} ` ); // create a new connector request body with the assistant message: const requestBody = { diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx new file mode 100644 index 000000000000..9e5bec7ea337 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx @@ -0,0 +1,68 @@ +### Tracing LangChain Retrievers, LLMs, Chains, and Tools using Elastic APM and LangSmith + +This document describes how to trace LangChain retrievers, LLMs, chains, and tools using Elastic APM and LangSmith. + +If the `assistantModelEvaluation` experimental feature flag is enabled, and an APM server is configured, messages that have a corresponding trace will have an additional `View APM trace` action in the message title bar: + +

    + +

    + +Viewing the trace you can see a breakdown of the time spent in each retriever, llm, chain, and tool: +

    + +

    + +The Evaluation interface has been updated to support adding additional metadata like `Project Name`, `Run Name`, and pulling test datasets from LangSmith. Predictions can now also be run without having to run an Evaluation, so datasets can quickly be run for manual analysis. + +

    + +

    + + +

    + +

    + + +### Configuring APM + +First, enable the `assistantModelEvaluation` experimental feature flag by adding the following to your `kibana.dev.yml`: + +``` +xpack.securitySolution.enableExperimental: [ 'assistantModelEvaluation' ] +``` + +Next, you'll need an APM server to collect the traces. You can either [follow the documentation for installing](https://www.elastic.co/guide/en/apm/guide/current/installing.html) the released artifact, or [run from source](https://github.com/elastic/apm-server#apm-server-development) and set up using the [quickstart guide provided](https://www.elastic.co/guide/en/apm/guide/current/apm-quick-start.html) (be sure to install the APM Server integration to ensure the necessary indices are created!). Once your APM server is running, add your APM server configuration to your `kibana.dev.yml` as well using the following: + +``` +# APM +elastic.apm: + active: true + environment: 'SpongBox5002c™' + serverUrl: 'http://localhost:8200' + transactionSampleRate: 1.0 + breakdownMetrics: true + spanStackTraceMinDuration: 10ms + # Disables Kibana RUM + servicesOverrides.kibana-frontend.active: false +``` + +> [!NOTE] +> If connecting to a cloud APM server (like our [ai-assistant apm deployment](https://ai-assistant-apm-do-not-delete.kb.us-central1.gcp.cloud.es.io/)), follow [these steps](https://www.elastic.co/guide/en/apm/guide/current/api-key.html#create-an-api-key) to create an API key, and then set it via `apiKey` and also set your `serverUrl` as shown in the APM Integration details within fleet. Note that the `View APM trace` button within the UI will link to your local instance, not the cloud instance. + +> [!NOTE] +> If you're an Elastic developer running Kibana from source, you can just enable APM as above, and _not_ include a `serverUrl`, and your traces will be sent to the https://kibana-cloud-apm.elastic.dev cluster. Note that the `View APM trace` button within the UI will link to your local instance, not the cloud instance. + +### Configuring LangSmith + +If wanting to push traces to LangSmith, or leverage any datasets that you may have hosted in a project, all you need to do is configure a few environment variables, and then start the kibana server. See the [LangSmith Traces documentation](https://docs.smith.langchain.com/tracing) for details, or just add the below env variables to enable: + +``` +# LangChain LangSmith +export LANGCHAIN_TRACING_V2=true +export LANGCHAIN_ENDPOINT="https://api.smith.langchain.com" +export LANGCHAIN_API_KEY="" +export LANGCHAIN_PROJECT="8.12 ESQL Query Generation" +``` + diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/apm_tracer.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/apm_tracer.ts new file mode 100644 index 000000000000..6aa00effc16f --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/apm_tracer.ts @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BaseCallbackHandlerInput, BaseTracer, Run } from 'langchain/callbacks'; +import agent from 'elastic-apm-node'; +import type { Logger } from '@kbn/core/server'; + +export interface LangChainTracerFields extends BaseCallbackHandlerInput { + exampleId?: string; + projectName?: string; +} + +type Span = Exclude; + +/** + * APMTracer is a tracer that uses the Elastic APM agent to trace langchain retrievers, llms, chains, and tools. + */ +export class APMTracer extends BaseTracer implements LangChainTracerFields { + name = 'apm_tracer'; + projectName?: string; + exampleId?: string; + logger: Logger; + + retrieverSpans: Span[] = []; + llmSpans: Span[] = []; + chainSpans: Span[] = []; + toolSpans: Span[] = []; + + constructor(fields: LangChainTracerFields = {}, logger: Logger) { + super(fields); + const { exampleId, projectName } = fields; + + this.projectName = projectName ?? 'default'; + this.exampleId = exampleId; + this.logger = logger; + } + + protected async persistRun(_run: Run): Promise {} + + /** + * LangChain Run's contain a lot of useful information, so here we unpack as much of it as we can + * into labels that can be added to the corresponding span. Stringifying outputs at the moment since + * the Run schema is a loose KVMap, but we should more elegantly unpack relevant data that we find useful + * + * See BaseRun interface Run extends from + * + * @param run + * @protected + */ + protected _getLabelsFromRun(run: Run): agent.Labels { + try { + return { + tags: JSON.stringify(run.tags), + outputs: JSON.stringify(run.outputs), + events: JSON.stringify(run.events), + inputs: JSON.stringify(run.inputs), + }; + } catch (e) { + this.logger.error(`Error parsing run into labels:\n${e}`); + return {}; + } + } + + protected createAndAddSpanFromRun(run: Run, spans: Span[]) { + const span = agent.startSpan(run.name) ?? undefined; + + if (span) { + span.addLabels(this._getLabelsFromRun(run)); + spans.push(span); + } + } + + async onRetrieverStart(run: Run): Promise { + this.logger.debug(`onRetrieverStart: run:\n${JSON.stringify(run, null, 2)}`); + this.createAndAddSpanFromRun(run, this.retrieverSpans); + } + + async onRetrieverEnd(run: Run): Promise { + this.logger.debug(`onRetrieverEnd: run:\n${JSON.stringify(run, null, 2)}`); + const span = this.retrieverSpans.pop(); + if (span != null) { + span.addLabels(this._getLabelsFromRun(run)); + span.end(); + } + } + + async onRetrieverError(run: Run): Promise { + this.logger.debug(`onRetrieverError: run:\n${JSON.stringify(run, null, 2)}`); + } + + async onLLMStart(run: Run): Promise { + this.logger.debug(`onLLMStart: run:\n${JSON.stringify(run, null, 2)}`); + this.createAndAddSpanFromRun(run, this.llmSpans); + } + + async onLLMEnd(run: Run): Promise { + this.logger.debug(`onLLMEnd: run:\n${JSON.stringify(run, null, 2)}`); + const span = this.llmSpans.pop(); + if (span != null) { + span.addLabels(this._getLabelsFromRun(run)); + span.end(); + } + } + + async onLLMError(run: Run): Promise { + this.logger.debug(`onLLMError: run:\n${JSON.stringify(run, null, 2)}`); + } + + async onChainStart(run: Run): Promise { + this.logger.debug(`onChainStart: run:\n${JSON.stringify(run, null, 2)}`); + this.createAndAddSpanFromRun(run, this.chainSpans); + } + + async onChainEnd(run: Run): Promise { + this.logger.debug(`onChainEnd: run:\n${JSON.stringify(run, null, 2)}`); + const span = this.chainSpans.pop(); + if (span != null) { + span.addLabels(this._getLabelsFromRun(run)); + span.end(); + } + } + + async onChainError(run: Run): Promise { + this.logger.debug(`onChainError: run:\n${JSON.stringify(run, null, 2)}`); + } + + async onToolStart(run: Run): Promise { + this.logger.debug(`onToolStart: run:\n${JSON.stringify(run, null, 2)}`); + this.createAndAddSpanFromRun(run, this.toolSpans); + } + + async onToolEnd(run: Run): Promise { + this.logger.debug(`onToolEnd: run:\n${JSON.stringify(run, null, 2)}`); + const span = this.toolSpans.pop(); + if (span != null) { + span.addLabels(this._getLabelsFromRun(run)); + span.end(); + } + } + + async onToolError(run: Run): Promise { + this.logger.debug(`onToolError: run:\n${JSON.stringify(run, null, 2)}`); + } +} diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/with_assistant_span.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/with_assistant_span.ts new file mode 100644 index 000000000000..8f9ef99c255a --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/with_assistant_span.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SpanOptions } from '@kbn/apm-utils'; +import { withSpan } from '@kbn/apm-utils'; +import type agent from 'elastic-apm-node'; + +type Span = Exclude; + +/** + * This is a thin wrapper around withSpan from @kbn/apm-utils, which sets + * span type to 'elasticAssistant' by default. This span type is used to + * distinguish assistant spans from everything else when inspecting traces. + * + * Use this method to capture information about the execution of a specific + * code path and highlight it in APM UI. + * + * @param optionsOrName Span name or span options object + * @param cb Code block you want to measure + * + * @returns Whatever the measured code block returns + */ +export const withAssistantSpan = ( + optionsOrName: SpanOptions | string, + cb: (span?: Span) => Promise +) => + withSpan( + { + type: 'elasticAssistant', + ...(typeof optionsOrName === 'string' ? { name: optionsOrName } : optionsOrName), + }, + cb + ); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts index 620f2554ecf4..03f106b4b879 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts @@ -13,4 +13,8 @@ export interface ResponseBody { status: string; data: string; connector_id: string; + trace_data?: { + transaction_id: string; + trace_id: string; + }; } diff --git a/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/evaluation.ts b/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/evaluation.ts index e4c4e45c0140..54040d3d1b58 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/evaluation.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/evaluation.ts @@ -8,34 +8,40 @@ import { loadEvaluator } from 'langchain/evaluation'; import { LLM } from 'langchain/llms/base'; import { ChainValues, HumanMessage } from 'langchain/schema'; -import { chunk } from 'lodash/fp'; +import { chunk as createChunks } from 'lodash/fp'; import { Logger } from '@kbn/core/server'; import { ToolingLog } from '@kbn/tooling-log'; -import { asyncForEach } from '@kbn/std'; -import { AgentExecutorEvaluator } from '../langchain/executors/types'; +import { LangChainTracer, RunCollectorCallbackHandler } from 'langchain/callbacks'; +import { AgentExecutorEvaluatorWithMetadata } from '../langchain/executors/types'; import { Dataset } from '../../schemas/evaluate/post_evaluate'; -import { callAgentWithRetry, getMessageFromLangChainResponse, wait } from './utils'; +import { callAgentWithRetry, getMessageFromLangChainResponse } from './utils'; import { ResponseBody } from '../langchain/types'; +import { isLangSmithEnabled, writeLangSmithFeedback } from '../../routes/evaluate/utils'; export interface PerformEvaluationParams { - agentExecutorEvaluators: AgentExecutorEvaluator[]; + agentExecutorEvaluators: AgentExecutorEvaluatorWithMetadata[]; dataset: Dataset; evaluationId: string; - evaluatorModel: LLM; + evaluatorModel?: LLM; evaluationPrompt?: string; - evaluationType: string; - maxConcurrency?: number; + evaluationType?: string; logger: Logger | ToolingLog; + maxConcurrency?: number; + runName?: string; } export interface EvaluationResult { '@timestamp': string; + connectorName: string; evaluation: ChainValues; evaluationId: string; input: string; + inputExampleId?: string | undefined; + langSmithLink?: string | undefined; prediction: string; predictionResponse: PromiseSettledResult; reference: string; + runName: string; } export interface EvaluationSummary { @@ -44,6 +50,8 @@ export interface EvaluationSummary { evaluationEnd: number; evaluationId: string; evaluationDuration: number; + langSmithLink?: string | undefined; + runName: string; totalAgents: number; totalRequests: number; totalInput: number; @@ -61,45 +69,85 @@ export const performEvaluation = async ({ evaluatorModel, evaluationPrompt, evaluationType, - maxConcurrency = 3, + maxConcurrency = 1, logger, + runName = 'default-run-name', }: PerformEvaluationParams) => { const startTime = new Date().getTime(); const evaluationResults: EvaluationResult[] = []; - const predictionRequests = dataset.flatMap(({ input, reference }) => - agentExecutorEvaluators.map((agent) => ({ - input, - reference, - request: callAgentWithRetry({ agent, messages: [new HumanMessage(input)], logger }), - })) + const predictionRequests = dataset.flatMap(({ input, reference, id: exampleId }) => + agentExecutorEvaluators.map( + ({ agentEvaluator: agent, metadata: { connectorName, runName: agentRunName } }) => ({ + connectorName, + input, + reference, + exampleId, + request: () => + callAgentWithRetry({ agent, exampleId, messages: [new HumanMessage(input)], logger }), + runName: agentRunName, + }) + ) ); + const requestChunks = createChunks(maxConcurrency, predictionRequests); + const totalChunks = requestChunks.length; + logger.info(`Total prediction requests: ${predictionRequests.length}`); - logger.info(`Chunk size: ${maxConcurrency}`); + logger.info(`Chunk size (maxConcurrency): ${maxConcurrency}`); + logger.info(`Total chunks: ${totalChunks}`); logger.info('Fetching predictions...'); - const requestChunks = chunk(maxConcurrency, predictionRequests); - await asyncForEach(requestChunks, async (c, i) => { - logger.info(`Prediction request chunk: ${i + 1} of ${requestChunks.length}`); + + while (requestChunks.length) { + const chunk = requestChunks.shift() ?? []; + const chunkNumber = totalChunks - requestChunks.length; + logger.info(`Prediction request chunk: ${chunkNumber} of ${totalChunks}`); + logger.debug(chunk); // Note, order is kept between chunk and dataset, and is preserved w/ Promise.allSettled - const chunkResults = await Promise.allSettled(c.map((r) => r.request)); - logger.info(`Prediction request chunk ${i + 1} response:\n${JSON.stringify(chunkResults)}`); + const chunkResults = await Promise.allSettled(chunk.map((r) => r.request())); + logger.info( + `Prediction request chunk ${chunkNumber} response:\n${JSON.stringify(chunkResults)}` + ); chunkResults.forEach((response, chunkResultIndex) => evaluationResults.push({ '@timestamp': new Date().toISOString(), - input: c[chunkResultIndex].input, - reference: c[chunkResultIndex].reference, + connectorName: chunk[chunkResultIndex].connectorName, + input: chunk[chunkResultIndex].input, + inputExampleId: chunk[chunkResultIndex].exampleId, + reference: chunk[chunkResultIndex].reference, evaluationId, evaluation: {}, prediction: getMessageFromLangChainResponse(response), predictionResponse: response, + runName: chunk[chunkResultIndex].runName, }) ); - }); + } logger.info(`Prediction results:\n${JSON.stringify(evaluationResults)}`); + if (evaluatorModel == null) { + const endTime = new Date().getTime(); + + const evaluationSummary: EvaluationSummary = { + evaluationId, + '@timestamp': new Date().toISOString(), + evaluationStart: startTime, + evaluationEnd: endTime, + evaluationDuration: endTime - startTime, + runName, + totalAgents: agentExecutorEvaluators.length, + totalInput: dataset.length, + totalRequests: predictionRequests.length, + }; + + logger.info(`Final results:\n${JSON.stringify(evaluationResults)}`); + + return { evaluationResults, evaluationSummary }; + } + + // Continue with actual evaluation if expected logger.info('Performing evaluation....'); logger.info(`Evaluation model: ${evaluatorModel._llmType()}`); @@ -109,22 +157,53 @@ export const performEvaluation = async ({ criteria: 'correctness', llm: evaluatorModel, }); - await asyncForEach(evaluationResults, async ({ input, prediction, reference }, index) => { - // TODO: Rate limit evaluator calls, though haven't seen any `429`'s yet in testing datasets up to 10 w/ azure/bedrock - const evaluation = await evaluator.evaluateStrings({ - input, - prediction, - reference, + + for (const result of evaluationResults) { + const { input, inputExampleId: exampleId, prediction, reference } = result; + // Create an eval tracer so eval traces end up in the right project (runName in this instance as to correlate + // with the test run), don't supply `exampleID` as that results in a new Dataset `Test` run being created and + // polluting the `predictions` that ran above + const evalTracer = new LangChainTracer({ + projectName: runName, }); - evaluationResults[index].evaluation = evaluation; - await wait(1000); - }); + // Create RunCollector for uploading evals to LangSmith, no TS variant for `EvaluatorCallbackHandler` or + // `run_on_dataset` w/ eval config, so using `RunCollectorCallbackHandler` and then uploading manually via + // client.createFeedback() + // See: https://github.com/langchain-ai/langsmith-sdk/blob/18449e5848d85ac0a320f320c37f454f949de1e1/js/src/client.ts#L1249-L1256 + const runCollector = new RunCollectorCallbackHandler({ exampleId }); + const evaluation = await evaluator.evaluateStrings( + { + input, + prediction, + reference, + }, + { + callbacks: [...(isLangSmithEnabled() ? [evalTracer, runCollector] : [])], + tags: ['security-assistant-evaluation'], + } + ); + result.evaluation = evaluation; + + // Write to LangSmith + if (isLangSmithEnabled()) { + const langSmithLink = await writeLangSmithFeedback( + runCollector.tracedRuns[0], + evaluationId, + logger + ); + result.langSmithLink = langSmithLink; + } + } } else if (evaluationType === 'esql-validator') { logger.info('Evaluation type: esql-validator'); // TODO: Implement esql-validator here } else if (evaluationType === 'custom') { logger.info('Evaluation type: custom'); // TODO: Implement custom evaluation here + // const llm = new ChatOpenAI({ temperature: 0, tags: ["my-llm-tag"] }); + // const prompt = PromptTemplate.fromTemplate("Say {input}"); + // const chain = prompt.pipe(llm).withConfig( { tags: ["my-bash-tag", "another-tag"] }); + // await chain.invoke({ input: "Hello, World!"}, { tags: ["shared-tags"] }); } const endTime = new Date().getTime(); @@ -135,12 +214,13 @@ export const performEvaluation = async ({ evaluationStart: startTime, evaluationEnd: endTime, evaluationDuration: endTime - startTime, + runName, totalAgents: agentExecutorEvaluators.length, totalInput: dataset.length, totalRequests: predictionRequests.length, }; - logger.info(`Final results:\n${JSON.stringify(evaluationResults, null, 2)}`); + logger.info(`Final results:\n${JSON.stringify(evaluationResults)}`); return { evaluationResults, evaluationSummary }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/utils.ts b/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/utils.ts index af0f57de95a3..fd11928c9087 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/model_evaluator/utils.ts @@ -15,19 +15,21 @@ export const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, export interface CallAgentWithRetryParams { agent: AgentExecutorEvaluator; + exampleId?: string; messages: BaseMessage[]; logger: Logger | ToolingLog; maxRetries?: number; } export const callAgentWithRetry = async ({ agent, + exampleId, messages, logger, maxRetries = 3, }: CallAgentWithRetryParams) => { for (let attempt = 0; attempt < maxRetries; attempt++) { try { - return await agent(messages); + return await agent(messages, exampleId); } catch (error) { // Check for 429, and then if there is a retry-after header const { isRateLimitError, retryAfter } = parseErrorMessage(error); diff --git a/x-pack/plugins/elastic_assistant/server/plugin.ts b/x-pack/plugins/elastic_assistant/server/plugin.ts index 827b428c9780..a0df33969588 100755 --- a/x-pack/plugins/elastic_assistant/server/plugin.ts +++ b/x-pack/plugins/elastic_assistant/server/plugin.ts @@ -80,7 +80,7 @@ export class ElasticAssistantPlugin const getElserId: GetElser = once( async (request: KibanaRequest, savedObjectsClient: SavedObjectsClientContract) => { return (await plugins.ml.trainedModelsProvider(request, savedObjectsClient).getELSER()) - .name; + .model_id; } ); diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts index 1b533e49c4cf..52f820db17a0 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts @@ -18,13 +18,16 @@ import { PostEvaluateBody, PostEvaluatePathQuery } from '../../schemas/evaluate/ import { performEvaluation } from '../../lib/model_evaluator/evaluation'; import { callAgentExecutor } from '../../lib/langchain/execute_custom_llm_chain'; import { callOpenAIFunctionsExecutor } from '../../lib/langchain/executors/openai_functions_executor'; -import { AgentExecutor, AgentExecutorEvaluator } from '../../lib/langchain/executors/types'; +import { + AgentExecutor, + AgentExecutorEvaluatorWithMetadata, +} from '../../lib/langchain/executors/types'; import { ActionsClientLlm } from '../../lib/langchain/llm/actions_client_llm'; import { indexEvaluations, setupEvaluationIndex, } from '../../lib/model_evaluator/output_index/utils'; -import { getLlmType } from './utils'; +import { fetchLangSmithDataset, getConnectorName, getLangSmithTracer, getLlmType } from './utils'; import { RequestBody } from '../../lib/langchain/types'; /** @@ -50,34 +53,41 @@ export const postEvaluateRoute = ( }, async (context, request, response) => { // TODO: Limit route based on experimental feature - const resp = buildResponse(response); const logger: Logger = (await context.elasticAssistant).logger; - - const { evalModel, evaluationType, outputIndex } = request.query; - const { dataset, evalPrompt } = request.body; - const connectorIds = request.query.models?.split(',') || []; - const agentNames = request.query.agents?.split(',') || []; - - const evaluationId = uuidv4(); - - logger.info('postEvaluateRoute:'); - logger.info(`request.query:\n${JSON.stringify(request.query, null, 2)}`); - logger.info(`request.body:\n${JSON.stringify(request.body, null, 2)}`); - logger.info(`Evaluation ID: ${evaluationId}`); - - const totalExecutions = connectorIds.length * agentNames.length * dataset.length; - logger.info('Creating agents:'); - logger.info(`\tconnectors/models: ${connectorIds.length}`); - logger.info(`\tagents: ${agentNames.length}`); - logger.info(`\tdataset: ${dataset.length}`); - logger.warn(`\ttotal baseline agent executions: ${totalExecutions} `); - if (totalExecutions > 50) { - logger.warn( - `Total baseline agent executions >= 50! This may take a while, and cost some money...` - ); - } - try { + const evaluationId = uuidv4(); + const { + evalModel, + evaluationType, + outputIndex, + datasetName, + projectName = 'default', + runName = evaluationId, + } = request.query; + const { dataset: customDataset = [], evalPrompt } = request.body; + const connectorIds = request.query.models?.split(',') || []; + const agentNames = request.query.agents?.split(',') || []; + + const dataset = + datasetName != null ? await fetchLangSmithDataset(datasetName, logger) : customDataset; + + logger.info('postEvaluateRoute:'); + logger.info(`request.query:\n${JSON.stringify(request.query, null, 2)}`); + logger.info(`request.body:\n${JSON.stringify(request.body, null, 2)}`); + logger.info(`Evaluation ID: ${evaluationId}`); + + const totalExecutions = connectorIds.length * agentNames.length * dataset.length; + logger.info('Creating agents:'); + logger.info(`\tconnectors/models: ${connectorIds.length}`); + logger.info(`\tagents: ${agentNames.length}`); + logger.info(`\tdataset: ${dataset.length}`); + logger.warn(`\ttotal baseline agent executions: ${totalExecutions} `); + if (totalExecutions > 50) { + logger.warn( + `Total baseline agent executions >= 50! This may take a while, and cost some money...` + ); + } + // Get the actions plugin start contract from the request context for the agents const actions = (await context.elasticAssistant).actions; @@ -112,35 +122,58 @@ export const postEvaluateRoute = ( // Create an array of executor functions to call in batches // One for each connector/model + agent combination // Hoist `langChainMessages` so they can be batched by dataset.input in the evaluator - const agents: AgentExecutorEvaluator[] = []; + const agents: AgentExecutorEvaluatorWithMetadata[] = []; connectorIds.forEach((connectorId) => { agentNames.forEach((agentName) => { logger.info(`Creating agent: ${connectorId} + ${agentName}`); const llmType = getLlmType(connectorId, connectors); - agents.push((langChainMessages) => - AGENT_EXECUTOR_MAP[agentName]({ - actions, - connectorId, - esClient, - elserId, - langChainMessages, - llmType, - logger, - request: skeletonRequest, - kbResource: ESQL_RESOURCE, - }) - ); + const connectorName = + getConnectorName(connectorId, connectors) ?? '[unknown connector]'; + const detailedRunName = `${runName} - ${connectorName} + ${agentName}`; + agents.push({ + agentEvaluator: (langChainMessages, exampleId) => + AGENT_EXECUTOR_MAP[agentName]({ + actions, + connectorId, + esClient, + elserId, + langChainMessages, + llmType, + logger, + request: skeletonRequest, + kbResource: ESQL_RESOURCE, + traceOptions: { + exampleId, + projectName, + runName: detailedRunName, + evaluationId, + tags: [ + 'security-assistant-prediction', + ...(connectorName != null ? [connectorName] : []), + runName, + ], + tracers: getLangSmithTracer(detailedRunName, exampleId, logger), + }, + }), + metadata: { + connectorName, + runName: detailedRunName, + }, + }); }); }); - logger.info(`Agents created: ${agents.length}`); - const evaluatorModel = new ActionsClientLlm({ - actions, - connectorId: evalModel, - request: skeletonRequest, - logger, - }); + // Evaluator Model is optional to support just running predictions + const evaluatorModel = + evalModel == null || evalModel === '' + ? undefined + : new ActionsClientLlm({ + actions, + connectorId: evalModel, + request: skeletonRequest, + logger, + }); const { evaluationResults, evaluationSummary } = await performEvaluation({ agentExecutorEvaluators: agents, @@ -150,6 +183,7 @@ export const postEvaluateRoute = ( evaluationPrompt: evalPrompt, evaluationType, logger, + runName, }); logger.info(`Writing evaluation results to index: ${outputIndex}`); @@ -163,14 +197,15 @@ export const postEvaluateRoute = ( }); return response.ok({ - body: { success: true }, + body: { evaluationId, success: true }, }); } catch (err) { logger.error(err); const error = transformError(err); + const resp = buildResponse(response); return resp.error({ - body: error.message, + body: { success: false, error: error.message }, statusCode: error.statusCode, }); } diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts index f208fe1d5739..550e89667256 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/utils.ts @@ -5,8 +5,14 @@ * 2.0. */ +import { Client } from 'langsmith'; import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/openai/constants'; import type { ActionResult } from '@kbn/actions-plugin/server'; +import type { Logger } from '@kbn/core/server'; +import type { Run } from 'langsmith/schemas'; +import { ToolingLog } from '@kbn/tooling-log'; +import { LangChainTracer } from 'langchain/callbacks'; +import { Dataset } from '../../schemas/evaluate/post_evaluate'; /** * Returns the LangChain `llmType` for the given connectorId/connectors @@ -29,3 +35,133 @@ export const getLlmType = (connectorId: string, connectors: ActionResult[]): str return undefined; }; + +/** + * Return connector name for the given connectorId/connectors + * + * @param connectorId + * @param connectors + */ +export const getConnectorName = ( + connectorId: string, + connectors: ActionResult[] +): string | undefined => { + return connectors.find((c) => c.id === connectorId)?.name; +}; + +/** + * Fetches a dataset from LangSmith. Note that `client` will use env vars + * + * @param datasetName + * @param logger + */ +export const fetchLangSmithDataset = async ( + datasetName: string | undefined, + logger: Logger +): Promise => { + if (datasetName === undefined || !isLangSmithEnabled()) { + throw new Error('LangSmith dataset name not provided or LangSmith not enabled'); + } + + try { + const client = new Client(); + + const examples = []; + for await (const example of client.listExamples({ datasetName })) { + examples.push(example); + } + + // Convert to internal Dataset type -- TODO: add generic support for the different LangSmith test dataset formats + const dataset: Dataset = examples.map((example) => ({ + id: example.id, + input: example.inputs.input as string, + reference: (example.outputs?.output as string) ?? '', + tags: [], // TODO: Consider adding tags from example data, e.g.: `datasetId:${example.dataset_id}`, `exampleName:${example.name}` + prediction: undefined, + })); + + return dataset; + } catch (e) { + logger.error(`Error fetching dataset from LangSmith: ${e.message}`); + return []; + } +}; + +/** + * Write Feedback to LangSmith for a given Run + * + * @param run + * @param evaluationId + * @param logger + */ +export const writeLangSmithFeedback = async ( + run: Run, + evaluationId: string, + logger: Logger | ToolingLog +): Promise => { + try { + const client = new Client(); + const feedback = { + score: run.feedback_stats?.score, + value: run.feedback_stats?.value, + correction: run.feedback_stats?.correction, + comment: run.feedback_stats?.comment, + sourceInfo: run.feedback_stats?.sourceInfo, + feedbackSourceType: run.feedback_stats?.feedbackSourceType, + sourceRunId: run.feedback_stats?.sourceRunId, + feedbackId: run.feedback_stats?.feedbackId, + eager: run.feedback_stats?.eager, + }; + await client.createFeedback(run.id, evaluationId, feedback); + const runUrl = await client.getRunUrl({ run }); + return runUrl; + } catch (e) { + logger.error(`Error writing feedback to LangSmith: ${e.message}`); + return ''; + } +}; + +/** + * Returns a custom LangChainTracer which adds the `exampleId` so Dataset 'Test' runs are written to LangSmith + * If `exampleId` is present (and a corresponding example exists in LangSmith) trace is written to the Dataset's `Tests` + * section, otherwise it is written to the `Project` provided + * + * @param projectName Name of project to trace results to + * @param exampleId Dataset exampleId to associate trace with + * @param logger + */ +export const getLangSmithTracer = ( + projectName: string | undefined, + exampleId: string | undefined, + logger: Logger | ToolingLog +): LangChainTracer[] => { + try { + if (!isLangSmithEnabled()) { + return []; + } + const lcTracer = new LangChainTracer({ + projectName: projectName ?? 'default', // Shows as the 'test' run's 'name' in langsmith ui + exampleId, + }); + + return [lcTracer]; + } catch (e) { + // Note: creating a tracer can fail if the LangSmith env vars are not set correctly + logger.error(`Error creating LangSmith tracer: ${e.message}`); + } + + return []; +}; + +/** + * Returns true if LangSmith/tracing is enabled + */ +export const isLangSmithEnabled = (): boolean => { + try { + // Just checking if apiKey is available, if better way to check for enabled that is not env var please update + const config = Client.getDefaultClientConfig(); + return config.apiKey != null; + } catch (e) { + return false; + } +}; diff --git a/x-pack/plugins/elastic_assistant/server/schemas/evaluate/post_evaluate.ts b/x-pack/plugins/elastic_assistant/server/schemas/evaluate/post_evaluate.ts index f006fe091bf1..c9c0ee1f00e5 100644 --- a/x-pack/plugins/elastic_assistant/server/schemas/evaluate/post_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/schemas/evaluate/post_evaluate.ts @@ -26,16 +26,21 @@ const outputIndex = new t.Type( /** Validates the URL path of a POST request to the `/evaluate` endpoint */ export const PostEvaluatePathQuery = t.type({ agents: t.string, - evaluationType: t.string, - evalModel: t.string, - outputIndex, + datasetName: t.union([t.string, t.undefined]), + evaluationType: t.union([t.string, t.undefined]), + evalModel: t.union([t.string, t.undefined]), models: t.string, + outputIndex, + projectName: t.union([t.string, t.undefined]), + runName: t.union([t.string, t.undefined]), }); export type DatasetItem = t.TypeOf; export const DatasetItem = t.type({ + id: t.union([t.string, t.undefined]), input: t.string, reference: t.string, + tags: t.union([t.array(t.string), t.undefined]), prediction: t.union([t.string, t.undefined]), }); @@ -44,7 +49,7 @@ export const Dataset = t.array(DatasetItem); /** Validates the body of a POST request to the `/evaluate` endpoint */ export const PostEvaluateBody = t.type({ - dataset: Dataset, + dataset: t.union([Dataset, t.undefined]), evalPrompt: t.union([t.string, t.undefined]), }); diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index 45dec8428e8c..53616fc2dc2b 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -29,9 +29,9 @@ "@kbn/tooling-log", "@kbn/core-elasticsearch-server", "@kbn/logging", - "@kbn/std", "@kbn/stack-connectors-plugin", "@kbn/ml-plugin", + "@kbn/apm-utils", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts index 321b93c8452e..7bde0d619054 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts @@ -10,7 +10,7 @@ import stringify from 'json-stable-stringify'; import typeDetect from 'type-detect'; import type { Logger } from '@kbn/core/server'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { EncryptedSavedObjectAttributesDefinition } from './encrypted_saved_object_type_definition'; import { EncryptionError, EncryptionErrorOperation } from './encryption_error'; diff --git a/x-pack/plugins/enterprise_search/README.md b/x-pack/plugins/enterprise_search/README.md index af0cdd43d97b..bc49c47fe688 100644 --- a/x-pack/plugins/enterprise_search/README.md +++ b/x-pack/plugins/enterprise_search/README.md @@ -137,4 +137,4 @@ To track what Cypress is doing while running tests, you can pass in `--config vi See [our functional test runner README](../../test/functional_enterprise_search). -Our automated accessibility tests can be found in [x-pack/test/accessibility/apps](../../test/accessibility/apps/enterprise_search.ts). \ No newline at end of file +Our automated accessibility tests can be found in [x-pack/test/accessibility/apps](../../test/accessibility/apps/group3/enterprise_search.ts). \ No newline at end of file diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts index f5f7945376d9..78af0a862d30 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.test.ts @@ -6,7 +6,7 @@ */ import { MlTrainedModelConfig, MlTrainedModelStats } from '@elastic/elasticsearch/lib/api/types'; -import { BUILT_IN_MODEL_TAG } from '@kbn/ml-trained-models-utils'; +import { BUILT_IN_MODEL_TAG, TRAINED_MODEL_TYPE } from '@kbn/ml-trained-models-utils'; import { MlInferencePipeline, TrainedModelState } from '../types/pipelines'; @@ -14,6 +14,7 @@ import { generateMlInferencePipelineBody, getMlModelTypesForModelConfig, parseMlInferenceParametersFromPipeline, + parseModelState, parseModelStateFromStats, parseModelStateReasonFromStats, } from '.'; @@ -265,8 +266,12 @@ describe('parseMlInferenceParametersFromPipeline', () => { }); describe('parseModelStateFromStats', () => { - it('returns not deployed for undefined stats', () => { - expect(parseModelStateFromStats()).toEqual(TrainedModelState.NotDeployed); + it('returns Started for the lang_ident model', () => { + expect( + parseModelStateFromStats({ + model_type: TRAINED_MODEL_TYPE.LANG_IDENT, + }) + ).toEqual(TrainedModelState.Started); }); it('returns Started', () => { expect( @@ -315,6 +320,28 @@ describe('parseModelStateFromStats', () => { }); }); +describe('parseModelState', () => { + it('returns Started', () => { + expect(parseModelState('started')).toEqual(TrainedModelState.Started); + expect(parseModelState('fully_allocated')).toEqual(TrainedModelState.Started); + }); + it('returns Starting', () => { + expect(parseModelState('starting')).toEqual(TrainedModelState.Starting); + expect(parseModelState('downloading')).toEqual(TrainedModelState.Starting); + expect(parseModelState('downloaded')).toEqual(TrainedModelState.Starting); + }); + it('returns Stopping', () => { + expect(parseModelState('stopping')).toEqual(TrainedModelState.Stopping); + }); + it('returns Failed', () => { + expect(parseModelState('failed')).toEqual(TrainedModelState.Failed); + }); + it('returns NotDeployed for an unknown state', () => { + expect(parseModelState(undefined)).toEqual(TrainedModelState.NotDeployed); + expect(parseModelState('other_state')).toEqual(TrainedModelState.NotDeployed); + }); +}); + describe('parseModelStateReasonFromStats', () => { it('returns reason from deployment_stats', () => { const reason = 'This is the reason the model is in a failed state'; diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts index 95c6672df692..5f56c1105b29 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts @@ -202,10 +202,18 @@ export const parseModelStateFromStats = ( modelTypes?.includes(TRAINED_MODEL_TYPE.LANG_IDENT) ) return TrainedModelState.Started; - switch (model?.deployment_stats?.state) { + + return parseModelState(model?.deployment_stats?.state); +}; + +export const parseModelState = (state?: string) => { + switch (state) { case 'started': + case 'fully_allocated': return TrainedModelState.Started; case 'starting': + case 'downloading': + case 'downloaded': return TrainedModelState.Starting; case 'stopping': return TrainedModelState.Stopping; diff --git a/x-pack/plugins/enterprise_search/common/types/ml.ts b/x-pack/plugins/enterprise_search/common/types/ml.ts index a09ad4129c8c..5723d4383d1e 100644 --- a/x-pack/plugins/enterprise_search/common/types/ml.ts +++ b/x-pack/plugins/enterprise_search/common/types/ml.ts @@ -22,3 +22,25 @@ export interface MlModelDeploymentStatus { targetAllocationCount: number; threadsPerAllocation: number; } + +export interface MlModel { + modelId: string; + /** Model inference type, e.g. ner, text_classification */ + type: string; + title: string; + description?: string; + license?: string; + modelDetailsPageUrl?: string; + deploymentState: MlModelDeploymentState; + deploymentStateReason?: string; + startTime: number; + targetAllocationCount: number; + nodeAllocationCount: number; + threadsPerAllocation: number; + /** Is this model one of the promoted ones (e.g. ELSER, E5)? */ + isPromoted?: boolean; + /** Does this model object act as a placeholder before installing the model? */ + isPlaceholder: boolean; + /** Does this model have deployment stats? */ + hasStats: boolean; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.test.ts new file mode 100644 index 000000000000..6d66ed570472 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.test.ts @@ -0,0 +1,229 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../__mocks__/kea_logic'; + +import { HttpError, Status } from '../../../../../common/types/api'; +import { MlModelDeploymentState } from '../../../../../common/types/ml'; + +import { MlModel } from '../../../../../common/types/ml'; + +import { + CachedFetchModelsApiLogic, + CachedFetchModelsApiLogicValues, +} from './cached_fetch_models_api_logic'; +import { FetchModelsApiLogic } from './fetch_models_api_logic'; + +const DEFAULT_VALUES: CachedFetchModelsApiLogicValues = { + data: [], + isInitialLoading: false, + isLoading: false, + modelsData: null, + pollTimeoutId: null, + status: Status.IDLE, +}; + +const FETCH_MODELS_API_DATA_RESPONSE: MlModel[] = [ + { + modelId: 'model_1', + title: 'Model 1', + type: 'ner', + deploymentState: MlModelDeploymentState.NotDeployed, + startTime: 0, + targetAllocationCount: 0, + nodeAllocationCount: 0, + threadsPerAllocation: 0, + isPlaceholder: false, + hasStats: false, + }, +]; +const FETCH_MODELS_API_ERROR_RESPONSE = { + body: { + error: 'Error while fetching models', + message: 'Error while fetching models', + statusCode: 500, + }, +} as HttpError; + +jest.useFakeTimers(); + +describe('TextExpansionCalloutLogic', () => { + const { mount } = new LogicMounter(CachedFetchModelsApiLogic); + const { mount: mountFetchModelsApiLogic } = new LogicMounter(FetchModelsApiLogic); + + beforeEach(() => { + jest.clearAllMocks(); + mountFetchModelsApiLogic(); + mount(); + }); + + describe('listeners', () => { + describe('apiError', () => { + it('sets new polling timeout if a timeout ID is already set', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout'); + + CachedFetchModelsApiLogic.actions.apiError(FETCH_MODELS_API_ERROR_RESPONSE); + + expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled(); + }); + }); + + describe('apiSuccess', () => { + it('sets new polling timeout if a timeout ID is already set', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout'); + + CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE); + + expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled(); + }); + }); + + describe('createPollTimeout', () => { + const duration = 5000; + it('clears polling timeout if it is set', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + + CachedFetchModelsApiLogic.actions.createPollTimeout(duration); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + }); + it('sets polling timeout', () => { + jest.spyOn(global, 'setTimeout'); + jest.spyOn(CachedFetchModelsApiLogic.actions, 'setTimeoutId'); + + CachedFetchModelsApiLogic.actions.createPollTimeout(duration); + + expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), duration); + expect(CachedFetchModelsApiLogic.actions.setTimeoutId).toHaveBeenCalled(); + }); + }); + + describe('startPolling', () => { + it('clears polling timeout if it is set', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + + CachedFetchModelsApiLogic.actions.startPolling(); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + }); + it('makes API request and sets polling timeout', () => { + jest.spyOn(CachedFetchModelsApiLogic.actions, 'makeRequest'); + jest.spyOn(CachedFetchModelsApiLogic.actions, 'createPollTimeout'); + + CachedFetchModelsApiLogic.actions.startPolling(); + + expect(CachedFetchModelsApiLogic.actions.makeRequest).toHaveBeenCalled(); + expect(CachedFetchModelsApiLogic.actions.createPollTimeout).toHaveBeenCalled(); + }); + }); + + describe('stopPolling', () => { + it('clears polling timeout if it is set', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + + CachedFetchModelsApiLogic.actions.stopPolling(); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + }); + it('clears polling timeout value', () => { + jest.spyOn(CachedFetchModelsApiLogic.actions, 'clearPollTimeout'); + + CachedFetchModelsApiLogic.actions.stopPolling(); + + expect(CachedFetchModelsApiLogic.actions.clearPollTimeout).toHaveBeenCalled(); + }); + }); + }); + + describe('reducers', () => { + describe('modelsData', () => { + it('gets cleared on API reset', () => { + mount({ + ...DEFAULT_VALUES, + modelsData: [], + }); + + CachedFetchModelsApiLogic.actions.apiReset(); + + expect(CachedFetchModelsApiLogic.values.modelsData).toBe(null); + }); + it('gets set on API success', () => { + CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE); + + expect(CachedFetchModelsApiLogic.values.modelsData).toEqual(FETCH_MODELS_API_DATA_RESPONSE); + }); + }); + + describe('pollTimeoutId', () => { + it('gets cleared on clear timeout action', () => { + mount({ + ...DEFAULT_VALUES, + pollTimeoutId: 'timeout-id', + }); + + CachedFetchModelsApiLogic.actions.clearPollTimeout(); + + expect(CachedFetchModelsApiLogic.values.pollTimeoutId).toBe(null); + }); + it('gets set on set timeout action', () => { + const timeout = setTimeout(() => {}, 500); + + CachedFetchModelsApiLogic.actions.setTimeoutId(timeout); + + expect(CachedFetchModelsApiLogic.values.pollTimeoutId).toEqual(timeout); + }); + }); + }); + + describe('selectors', () => { + describe('isInitialLoading', () => { + it('true if API is idle', () => { + mount(DEFAULT_VALUES); + + expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(true); + }); + it('true if API is loading for the first time', () => { + mount({ + ...DEFAULT_VALUES, + status: Status.LOADING, + }); + + expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(true); + }); + it('false if the API is neither idle nor loading', () => { + CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE); + + expect(CachedFetchModelsApiLogic.values.isInitialLoading).toBe(false); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.ts new file mode 100644 index 000000000000..d65af6ec2fcf --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/cached_fetch_models_api_logic.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { isEqual } from 'lodash'; + +import { Status } from '../../../../../common/types/api'; +import { MlModel } from '../../../../../common/types/ml'; +import { Actions } from '../../../shared/api_logic/create_api_logic'; + +import { FetchModelsApiLogic, FetchModelsApiResponse } from './fetch_models_api_logic'; + +const FETCH_MODELS_POLLING_DURATION = 5000; // 5 seconds +const FETCH_MODELS_POLLING_DURATION_ON_FAILURE = 30000; // 30 seconds + +export interface CachedFetchModlesApiLogicActions { + apiError: Actions<{}, FetchModelsApiResponse>['apiError']; + apiReset: Actions<{}, FetchModelsApiResponse>['apiReset']; + apiSuccess: Actions<{}, FetchModelsApiResponse>['apiSuccess']; + clearPollTimeout(): void; + createPollTimeout(duration: number): { duration: number }; + makeRequest: Actions<{}, FetchModelsApiResponse>['makeRequest']; + setTimeoutId(id: NodeJS.Timeout): { id: NodeJS.Timeout }; + startPolling(): void; + stopPolling(): void; +} + +export interface CachedFetchModelsApiLogicValues { + data: FetchModelsApiResponse; + isInitialLoading: boolean; + isLoading: boolean; + modelsData: MlModel[] | null; + pollTimeoutId: NodeJS.Timeout | null; + status: Status; +} + +export const CachedFetchModelsApiLogic = kea< + MakeLogicType +>({ + actions: { + clearPollTimeout: true, + createPollTimeout: (duration) => ({ duration }), + setTimeoutId: (id) => ({ id }), + startPolling: true, + stopPolling: true, + }, + connect: { + actions: [FetchModelsApiLogic, ['apiSuccess', 'apiError', 'apiReset', 'makeRequest']], + values: [FetchModelsApiLogic, ['data', 'status']], + }, + events: ({ values }) => ({ + beforeUnmount: () => { + if (values.pollTimeoutId) { + clearTimeout(values.pollTimeoutId); + } + }, + }), + listeners: ({ actions, values }) => ({ + apiError: () => { + if (values.pollTimeoutId) { + actions.createPollTimeout(FETCH_MODELS_POLLING_DURATION_ON_FAILURE); + } + }, + apiSuccess: () => { + if (values.pollTimeoutId) { + actions.createPollTimeout(FETCH_MODELS_POLLING_DURATION); + } + }, + createPollTimeout: ({ duration }) => { + if (values.pollTimeoutId) { + clearTimeout(values.pollTimeoutId); + } + + const timeoutId = setTimeout(() => { + actions.makeRequest({}); + }, duration); + actions.setTimeoutId(timeoutId); + }, + startPolling: () => { + if (values.pollTimeoutId) { + clearTimeout(values.pollTimeoutId); + } + actions.makeRequest({}); + actions.createPollTimeout(FETCH_MODELS_POLLING_DURATION); + }, + stopPolling: () => { + if (values.pollTimeoutId) { + clearTimeout(values.pollTimeoutId); + } + actions.clearPollTimeout(); + }, + }), + path: ['enterprise_search', 'content', 'api', 'fetch_models_api_wrapper'], + reducers: { + modelsData: [ + null, + { + apiReset: () => null, + apiSuccess: (currentState, newState) => + isEqual(currentState, newState) ? currentState : newState, + }, + ], + pollTimeoutId: [ + null, + { + clearPollTimeout: () => null, + setTimeoutId: (_, { id }) => id, + }, + ], + }, + selectors: ({ selectors }) => ({ + isInitialLoading: [ + () => [selectors.status, selectors.modelsData], + ( + status: CachedFetchModelsApiLogicValues['status'], + modelsData: CachedFetchModelsApiLogicValues['modelsData'] + ) => status === Status.IDLE || (modelsData === null && status === Status.LOADING), + ], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.test.ts new file mode 100644 index 000000000000..78ef03010ac2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { createModel } from './create_model_api_logic'; + +describe('CreateModelApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('createModel', () => { + it('calls correct api', async () => { + const mockResponseBody = { modelId: 'model_1', deploymentState: '' }; + http.post.mockReturnValue(Promise.resolve(mockResponseBody)); + + const result = createModel({ modelId: 'model_1' }); + await nextTick(); + expect(http.post).toHaveBeenCalledWith('/internal/enterprise_search/ml/models/model_1'); + await expect(result).resolves.toEqual(mockResponseBody); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.ts new file mode 100644 index 000000000000..6852e56cea67 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/create_model_api_logic.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Actions, createApiLogic } from '../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../shared/http'; + +export interface CreateModelArgs { + modelId: string; +} + +export interface CreateModelResponse { + deploymentState: string; + modelId: string; +} + +export const createModel = async ({ modelId }: CreateModelArgs): Promise => { + const route = `/internal/enterprise_search/ml/models/${modelId}`; + return await HttpLogic.values.http.post(route); +}; + +export const CreateModelApiLogic = createApiLogic(['create_model_api_logic'], createModel, { + showErrorFlash: false, +}); + +export type CreateModelApiLogicActions = Actions; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/create_e5_multilingual_model_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/create_e5_multilingual_model_api_logic.ts new file mode 100644 index 000000000000..e4b50c70bfc8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/create_e5_multilingual_model_api_logic.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Actions, createApiLogic } from '../../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../../shared/http'; + +export interface CreateE5MultilingualModelArgs { + modelId: string; +} + +export interface CreateE5MultilingualModelResponse { + deploymentState: string; + modelId: string; +} + +export const createE5MultilingualModel = async ({ + modelId, +}: CreateE5MultilingualModelArgs): Promise => { + const route = `/internal/enterprise_search/ml/models/${modelId}`; + return await HttpLogic.values.http.post(route); +}; + +export const CreateE5MultilingualModelApiLogic = createApiLogic( + ['create_e5_multilingual_model_api_logic'], + createE5MultilingualModel, + { showErrorFlash: false } +); + +export type CreateE5MultilingualModelApiLogicActions = Actions< + CreateE5MultilingualModelArgs, + CreateE5MultilingualModelResponse +>; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/fetch_e5_multilingual_model_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/fetch_e5_multilingual_model_api_logic.ts new file mode 100644 index 000000000000..88918a56fb33 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/fetch_e5_multilingual_model_api_logic.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Actions, createApiLogic } from '../../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../../shared/http'; + +export interface FetchE5MultilingualModelArgs { + modelId: string; +} + +export interface FetchE5MultilingualModelResponse { + deploymentState: string; + modelId: string; + targetAllocationCount: number; + nodeAllocationCount: number; + threadsPerAllocation: number; +} + +export const fetchE5MultilingualModelStatus = async ({ modelId }: FetchE5MultilingualModelArgs) => { + return await HttpLogic.values.http.get( + `/internal/enterprise_search/ml/models/${modelId}` + ); +}; + +export const FetchE5MultilingualModelApiLogic = createApiLogic( + ['fetch_e5_multilingual_model_api_logic'], + fetchE5MultilingualModelStatus, + { showErrorFlash: false } +); + +export type FetchE5MultilingualModelApiLogicActions = Actions< + FetchE5MultilingualModelArgs, + FetchE5MultilingualModelResponse +>; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/start_e5_multilingual_model_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/start_e5_multilingual_model_api_logic.ts new file mode 100644 index 000000000000..9b0e1520da71 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/e5_multilingual/start_e5_multilingual_model_api_logic.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Actions, createApiLogic } from '../../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../../shared/http'; + +export interface StartE5MultilingualModelArgs { + modelId: string; +} + +export interface StartE5MultilingualModelResponse { + deploymentState: string; + modelId: string; +} + +export const startE5MultilingualModel = async ({ + modelId, +}: StartE5MultilingualModelArgs): Promise => { + const route = `/internal/enterprise_search/ml/models/${modelId}/deploy`; + return await HttpLogic.values.http.post(route); +}; + +export const StartE5MultilingualModelApiLogic = createApiLogic( + ['start_e5_multilingual_model_api_logic'], + startE5MultilingualModel, + { showErrorFlash: false } +); + +export type StartE5MultilingualModelApiLogicActions = Actions< + StartE5MultilingualModelArgs, + StartE5MultilingualModelResponse +>; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.test.ts new file mode 100644 index 000000000000..77f2a0548fa6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { fetchModels } from './fetch_models_api_logic'; + +describe('FetchModelsApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('fetchModels', () => { + it('calls correct api', async () => { + const mockResponseBody = [{ modelId: 'model_1' }, { modelId: 'model_2' }]; + http.get.mockReturnValue(Promise.resolve(mockResponseBody)); + + const result = fetchModels(); + await nextTick(); + expect(http.get).toHaveBeenCalledWith('/internal/enterprise_search/ml/models'); + await expect(result).resolves.toEqual(mockResponseBody); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.ts new file mode 100644 index 000000000000..751a03546b05 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/fetch_models_api_logic.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MlModel } from '../../../../../common/types/ml'; +import { Actions, createApiLogic } from '../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../shared/http'; + +export type FetchModelsApiResponse = MlModel[]; + +export const fetchModels = async () => { + const route = '/internal/enterprise_search/ml/models'; + return await HttpLogic.values.http.get(route); +}; + +export const FetchModelsApiLogic = createApiLogic(['fetch_models_api_logic'], fetchModels, { + showErrorFlash: false, +}); + +export type FetchModelsApiLogicActions = Actions<{}, FetchModelsApiResponse>; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.test.ts new file mode 100644 index 000000000000..0c9d9da875e5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { startModel } from './start_model_api_logic'; + +describe('StartModelApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('startModel', () => { + it('calls correct api', async () => { + const mockResponseBody = { modelId: 'model_1', deploymentState: 'started' }; + http.post.mockReturnValue(Promise.resolve(mockResponseBody)); + + const result = startModel({ modelId: 'model_1' }); + await nextTick(); + expect(http.post).toHaveBeenCalledWith( + '/internal/enterprise_search/ml/models/model_1/deploy' + ); + await expect(result).resolves.toEqual(mockResponseBody); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.ts new file mode 100644 index 000000000000..333b23cd6524 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/ml_models/start_model_api_logic.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Actions, createApiLogic } from '../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../shared/http'; + +export interface StartModelArgs { + modelId: string; +} + +export interface StartModelResponse { + deploymentState: string; + modelId: string; +} + +export const startModel = async ({ modelId }: StartModelArgs): Promise => { + const route = `/internal/enterprise_search/ml/models/${modelId}/deploy`; + return await HttpLogic.values.http.post(route); +}; + +export const StartModelApiLogic = createApiLogic(['start_model_api_logic'], startModel, { + showErrorFlash: false, +}); + +export type StartModelApiLogicActions = Actions; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents.tsx index b2932c9547e2..999bd333a0ff 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/documents.tsx @@ -26,7 +26,6 @@ import { ENTERPRISE_SEARCH_DOCUMENTS_DEFAULT_DOC_COUNT, } from '../../../../../common/constants'; import { Status } from '../../../../../common/types/api'; -import { stripSearchPrefix } from '../../../../../common/utils/strip_search_prefix'; import { DEFAULT_META } from '../../../shared/constants'; import { KibanaLogic } from '../../../shared/kibana'; @@ -69,7 +68,7 @@ export const SearchIndexDocuments: React.FC = () => { const indexToShow = selectedIndexType === 'content-index' ? indexName - : stripSearchPrefix(indexName, CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX); + : `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}${indexName}`; const mappingLogic = mappingsWithPropsApiLogic(indexToShow); const documentLogic = searchDocumentsApiLogic(indexToShow); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx index bdae531bb39c..970b1488010c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx @@ -16,7 +16,6 @@ import { EuiButtonIcon, EuiPanel, EuiTextColor, EuiTitle } from '@elastic/eui'; import { InferencePipeline, TrainedModelState } from '../../../../../../common/types/pipelines'; import { InferencePipelineCard } from './inference_pipeline_card'; -import { TrainedModelHealth } from './ml_model_health'; import { MLModelTypeBadge } from './ml_model_type_badge'; export const DEFAULT_VALUES: InferencePipeline = { @@ -37,13 +36,12 @@ describe('InferencePipelineCard', () => { it('renders the item', () => { const wrapper = shallow(); expect(wrapper.find(EuiPanel)).toHaveLength(1); - expect(wrapper.find(TrainedModelHealth)).toHaveLength(1); }); - it('renders model type as title', () => { + it('renders pipeline as title', () => { const wrapper = shallow(); expect(wrapper.find(EuiTitle)).toHaveLength(1); const title = wrapper.find(EuiTitle).dive(); - expect(title.text()).toBe('Named Entity Recognition'); + expect(title.text()).toBe(DEFAULT_VALUES.pipelineName); }); it('renders pipeline as title with unknown model type', () => { const values = { @@ -57,11 +55,11 @@ describe('InferencePipelineCard', () => { const title = wrapper.find(EuiTitle).dive(); expect(title.text()).toBe(DEFAULT_VALUES.pipelineName); }); - it('renders pipeline as subtitle', () => { + it('renders model ID as subtitle', () => { const wrapper = shallow(); expect(wrapper.find(EuiTextColor)).toHaveLength(1); const subtitle = wrapper.find(EuiTextColor).dive(); - expect(subtitle.text()).toBe(DEFAULT_VALUES.pipelineName); + expect(subtitle.text()).toBe(DEFAULT_VALUES.modelId); }); it('renders model type as badge', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx index 4ee18025e5c4..dcc4b2a0cad8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx @@ -17,7 +17,6 @@ import { EuiFlexItem, EuiPanel, EuiPopover, - EuiPopoverTitle, EuiText, EuiTextColor, EuiTitle, @@ -51,151 +50,137 @@ export const InferencePipelineCard: React.FC = (pipeline) => setShowConfirmDelete(true); setIsPopOverOpen(false); }; - const { pipelineName, types: modelTypes } = pipeline; + const { modelId, pipelineName, types: modelTypes } = pipeline; const modelType = getMLType(modelTypes); const modelTitle = getModelDisplayTitle(modelType); const actionButton = ( setIsPopOverOpen(!isPopOverOpen)} > - {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.actionButton', { - defaultMessage: 'Actions', - })} + ); return ( - + - + - -

    {modelTitle ?? pipelineName}

    -
    + + + +

    {pipelineName ?? modelTitle}

    +
    +
    + +
    - - setIsPopOverOpen(false)} - > - - {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.title', { - defaultMessage: 'Actions', - })} - - - -
    - - {i18n.translate( - 'xpack.enterpriseSearch.inferencePipelineCard.action.view', - { defaultMessage: 'View in Stack Management' } - )} - -
    -
    - -
    - { - detachMlPipeline({ indexName, pipelineName }); - setIsPopOverOpen(false); - }} - > - {i18n.translate( - 'xpack.enterpriseSearch.inferencePipelineCard.action.detach', - { defaultMessage: 'Detach pipeline' } - )} - -
    + {modelTitle && ( + + + + {modelId} -
    - -
    + + +
    -
    -
    +
    + )}
    - - - - - {modelTitle && ( - - {pipelineName} - - )} - - + setIsPopOverOpen(false)} + > + {pipeline.modelState === TrainedModelState.NotDeployed && ( + + + - - {pipeline.modelState === TrainedModelState.NotDeployed && ( - - - - - - )} - - - - - - - - - - - - + + + )} + + +
    + + {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.view', { + defaultMessage: 'View in Stack Management', + })} + +
    +
    + +
    + { + detachMlPipeline({ indexName, pipelineName }); + setIsPopOverOpen(false); + }} + > + {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.detach', { + defaultMessage: 'Detach pipeline', + })} + +
    +
    + +
    + +
    +
    +
    +
    + {showConfirmDelete && ( setShowConfirmDelete(false)} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.test.tsx index 2a3432d4d523..68bf7fc48e7d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.test.tsx @@ -33,7 +33,6 @@ import { NoModelsPanel } from './no_models'; import { ReviewPipeline } from './review_pipeline'; import { TestPipeline } from './test_pipeline'; import { AddInferencePipelineSteps } from './types'; -import { UpdateMappings } from './update_mappings'; const supportedMLModels: TrainedModelConfigResponse[] = [ { @@ -122,16 +121,6 @@ describe('AddInferencePipelineFlyout', () => { const wrapper = shallow(); expect(wrapper.find(ConfigureFields)).toHaveLength(1); }); - it('renders mappings step', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { - step: AddInferencePipelineSteps.Mappings, - }, - }); - const wrapper = shallow(); - expect(wrapper.find(UpdateMappings)).toHaveLength(1); - }); it('renders test step', () => { setMockValues({ ...DEFAULT_VALUES, @@ -156,9 +145,8 @@ describe('AddInferencePipelineFlyout', () => { describe('AddInferencePipelineHorizontalSteps', () => { const CONFIGURE_STEP_INDEX = 0; const FIELDS_STEP_INDEX = 1; - const MAPPINGS_STEP_INDEX = 2; - const TEST_STEP_INDEX = 3; - const REVIEW_STEP_INDEX = 4; + const TEST_STEP_INDEX = 2; + const REVIEW_STEP_INDEX = 3; const onAddInferencePipelineStepChange = jest.fn(); beforeEach(() => { setMockActions({ @@ -225,24 +213,6 @@ describe('AddInferencePipelineFlyout', () => { }); testStepStatus(FIELDS_STEP_INDEX, 'Fields', 'complete'); }); - it('mappings step is current when on step', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { - step: AddInferencePipelineSteps.Mappings, - }, - }); - testStepStatus(MAPPINGS_STEP_INDEX, 'Mappings', 'current'); - }); - it('mappings step is complete when on later step', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { - step: AddInferencePipelineSteps.Review, - }, - }); - testStepStatus(MAPPINGS_STEP_INDEX, 'Mappings', 'complete'); - }); it('test step is current when on step', () => { setMockValues({ ...DEFAULT_VALUES, @@ -294,9 +264,6 @@ describe('AddInferencePipelineFlyout', () => { it('clicking fields step updates step', () => { testClickStep(FIELDS_STEP_INDEX, AddInferencePipelineSteps.Fields); }); - it('clicking mappings step updates step', () => { - testClickStep(MAPPINGS_STEP_INDEX, AddInferencePipelineSteps.Mappings); - }); it('clicking test step updates step', () => { testClickStep(TEST_STEP_INDEX, AddInferencePipelineSteps.Test); }); @@ -319,13 +286,6 @@ describe('AddInferencePipelineFlyout', () => { }); testCannotClickInvalidStep(FIELDS_STEP_INDEX); }); - it('cannot click mappings step when data is invalid', () => { - setMockValues({ - ...DEFAULT_VALUES, - isPipelineDataValid: false, - }); - testCannotClickInvalidStep(MAPPINGS_STEP_INDEX); - }); it('cannot click test step when data is invalid', () => { setMockValues({ ...DEFAULT_VALUES, @@ -378,23 +338,6 @@ describe('AddInferencePipelineFlyout', () => { cancelBtn.prop('onClick')!({} as any); expect(onClose).toHaveBeenCalledTimes(1); }); - it('renders cancel button on mappings step', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { - ...DEFAULT_VALUES.addInferencePipelineModal, - step: AddInferencePipelineSteps.Mappings, - }, - }); - const wrapper = shallow( - - ); - expect(wrapper.find(EuiButtonEmpty)).toHaveLength(2); - const cancelBtn = wrapper.find(EuiButtonEmpty).at(0); - expect(cancelBtn.prop('children')).toBe('Cancel'); - cancelBtn.prop('onClick')!({} as any); - expect(onClose).toHaveBeenCalledTimes(1); - }); it('renders cancel button on test step', () => { setMockValues({ ...DEFAULT_VALUES, @@ -456,11 +399,8 @@ describe('AddInferencePipelineFlyout', () => { it('renders back button on fields step', () => { testBackButton(AddInferencePipelineSteps.Fields, AddInferencePipelineSteps.Configuration); }); - it('renders back button on mappings step', () => { - testBackButton(AddInferencePipelineSteps.Mappings, AddInferencePipelineSteps.Fields); - }); it('renders back button on test step', () => { - testBackButton(AddInferencePipelineSteps.Test, AddInferencePipelineSteps.Mappings); + testBackButton(AddInferencePipelineSteps.Test, AddInferencePipelineSteps.Fields); }); it('renders back button on review step', () => { testBackButton(AddInferencePipelineSteps.Review, AddInferencePipelineSteps.Test); @@ -504,26 +444,6 @@ describe('AddInferencePipelineFlyout', () => { expect(contBtn.prop('children')).toBe('Continue'); expect(contBtn.prop('disabled')).toBe(false); contBtn.prop('onClick')!({} as any); - expect(actions.onAddInferencePipelineStepChange).toHaveBeenCalledWith( - AddInferencePipelineSteps.Mappings - ); - }); - it('renders continue button on mappings step', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { - ...DEFAULT_VALUES.addInferencePipelineModal, - step: AddInferencePipelineSteps.Mappings, - }, - }); - const wrapper = shallow( - - ); - const contBtn = wrapper.find(EuiButton); - expect(contBtn).toHaveLength(1); - expect(contBtn.prop('children')).toBe('Continue'); - expect(contBtn.prop('disabled')).toBe(false); - contBtn.prop('onClick')!({} as any); expect(actions.onAddInferencePipelineStepChange).toHaveBeenCalledWith( AddInferencePipelineSteps.Test ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.tsx index 85ef342dcaa5..654cdafad35e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/add_inference_pipeline_flyout.tsx @@ -47,7 +47,6 @@ import { TestPipeline } from './test_pipeline'; import { AddInferencePipelineSteps } from './types'; import './add_inference_pipeline_flyout.scss'; -import { UpdateMappings } from './update_mappings'; export interface AddInferencePipelineFlyoutProps { onClose: () => void; @@ -132,7 +131,6 @@ export const AddInferencePipelineContent = ({ onClose }: AddInferencePipelineFly {step === AddInferencePipelineSteps.Configuration && } {step === AddInferencePipelineSteps.Fields && } - {step === AddInferencePipelineSteps.Mappings && } {step === AddInferencePipelineSteps.Test && } {step === AddInferencePipelineSteps.Review && } @@ -191,22 +189,6 @@ export const AddInferencePipelineHorizontalSteps: React.FC = () => { } ), }, - { - // Mappings - onClick: () => { - if (!isPipelineDataValid) return; - onAddInferencePipelineStepChange(AddInferencePipelineSteps.Mappings); - }, - status: isPipelineDataValid - ? getStepStatus(step, AddInferencePipelineSteps.Mappings) - : 'disabled', - title: i18n.translate( - 'xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.updateMappings.title', - { - defaultMessage: 'Mappings', - } - ), - }, { // Test onClick: () => { @@ -265,18 +247,13 @@ export const AddInferencePipelineFooter: React.FC< isContinueButtonEnabled = isConfigureStepValid; break; case AddInferencePipelineSteps.Fields: - nextStep = AddInferencePipelineSteps.Mappings; + nextStep = AddInferencePipelineSteps.Test; previousStep = AddInferencePipelineSteps.Configuration; isContinueButtonEnabled = isPipelineDataValid; break; - case AddInferencePipelineSteps.Mappings: - nextStep = AddInferencePipelineSteps.Test; - previousStep = AddInferencePipelineSteps.Fields; - isContinueButtonEnabled = true; - break; case AddInferencePipelineSteps.Test: nextStep = AddInferencePipelineSteps.Review; - previousStep = AddInferencePipelineSteps.Mappings; + previousStep = AddInferencePipelineSteps.Fields; isContinueButtonEnabled = true; break; case AddInferencePipelineSteps.Review: diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx index 37a7c7153586..e3f771d0ba7e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx @@ -5,95 +5,64 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { useValues, useActions } from 'kea'; import { + EuiCallOut, EuiFieldText, - EuiFlexGroup, - EuiFlexItem, EuiForm, EuiFormRow, - EuiLink, - EuiSelect, EuiSuperSelect, EuiSuperSelectOption, EuiSpacer, + EuiTabbedContent, + EuiTabbedContentTab, EuiTitle, EuiText, - EuiPanel, - EuiHorizontalRule, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { docLinks } from '../../../../../shared/doc_links'; - -import { IndexNameLogic } from '../../index_name_logic'; import { IndexViewLogic } from '../../index_view_logic'; -import { InferenceConfiguration } from './inference_config'; import { EMPTY_PIPELINE_CONFIGURATION, MLInferenceLogic } from './ml_inference_logic'; -import { MlModelSelectOption } from './model_select_option'; +import { ModelSelect } from './model_select'; +import { ModelSelectLogic } from './model_select_logic'; import { PipelineSelectOption } from './pipeline_select_option'; -import { TextExpansionCallOut } from './text_expansion_callout'; -import { MODEL_REDACTED_VALUE, MODEL_SELECT_PLACEHOLDER } from './utils'; -const MODEL_SELECT_PLACEHOLDER_VALUE = 'model_placeholder$$'; const PIPELINE_SELECT_PLACEHOLDER_VALUE = 'pipeline_placeholder$$'; -const CHOOSE_EXISTING_LABEL = i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel', - { defaultMessage: 'Choose' } -); -const CHOOSE_NEW_LABEL = i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel', - { defaultMessage: 'New pipeline' } +const CREATE_NEW_TAB_NAME = i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.tabs.createNew.name', + { defaultMessage: 'Create new' } ); -const CHOOSE_PIPELINE_LABEL = i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel', - { defaultMessage: 'Existing pipeline' } + +const USE_EXISTING_TAB_NAME = i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.tabs.useExisting.name', + { defaultMessage: 'Use existing' } ); +export enum ConfigurePipelineTabId { + CREATE_NEW = 'create_new', + USE_EXISTING = 'use_existing', +} + export const ConfigurePipeline: React.FC = () => { const { addInferencePipelineModal: { configuration }, formErrors, existingInferencePipelines, - supportedMLModels, } = useValues(MLInferenceLogic); const { selectExistingPipeline, setInferencePipelineConfiguration } = useActions(MLInferenceLogic); const { ingestionMethod } = useValues(IndexViewLogic); - const { indexName } = useValues(IndexNameLogic); - - const { existingPipeline, modelID, pipelineName } = configuration; - - useEffect(() => { - setInferencePipelineConfiguration({ - ...configuration, - pipelineName: pipelineName || indexName, - }); - }, []); + const { modelStateChangeError } = useValues(ModelSelectLogic); + const { pipelineName } = configuration; const nameError = formErrors.pipelineName !== undefined && pipelineName.length > 0; - const modelOptions: Array> = [ - { - disabled: true, - inputDisplay: - existingPipeline && pipelineName.length > 0 - ? MODEL_REDACTED_VALUE - : MODEL_SELECT_PLACEHOLDER, - value: MODEL_SELECT_PLACEHOLDER_VALUE, - }, - ...supportedMLModels.map((model) => ({ - dropdownDisplay: , - inputDisplay: model.model_id, - value: model.model_id, - })), - ]; const pipelineOptions: Array> = [ { disabled: true, @@ -113,222 +82,160 @@ export const ConfigurePipeline: React.FC = () => { const inputsDisabled = configuration.existingPipeline !== false; - return ( - <> - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.title', - { defaultMessage: 'Create or select a pipeline' } - )} -

    -
    + const tabs: EuiTabbedContentTab[] = [ + { + content: ( + <> - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.description', - { - defaultMessage: - 'Build or reuse a child pipeline that will be used as a processor in your main pipeline.', - } - )} -

    -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionUsePipelines', + + - - - - - - + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText', + { + defaultMessage: + 'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens. This will create a pipeline named {pipelineName}.', + values: { + pipelineName: `ml-inference-${pipelineName}`, + }, + } + )} + + ) + } + error={nameError && formErrors.pipelineName} + isInvalid={nameError} + > + - - setInferencePipelineConfiguration({ - ...EMPTY_PIPELINE_CONFIGURATION, - existingPipeline: e.target.value === 'true', - }) + prepend="ml-inference-" + placeholder={i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.namePlaceholder', + { + defaultMessage: 'Enter a unique name for this pipeline', } - value={configuration.existingPipeline?.toString() ?? ''} - /> - - {configuration.existingPipeline === true ? ( - - 0 ? pipelineName : PIPELINE_SELECT_PLACEHOLDER_VALUE - } - options={pipelineOptions} - onChange={(value) => selectExistingPipeline(value)} - /> - - ) : ( - + setInferencePipelineConfiguration({ + ...configuration, + isPipelineNameUserSupplied: e.target.value.length > 0, + pipelineName: e.target.value, + }) + } + /> + + {modelStateChangeError && ( + <> + + - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText', - { - defaultMessage: - 'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens. This will create a pipeline named {pipelineName}.', - values: { - pipelineName: `ml-inference-${pipelineName}`, - }, - } - )} - - ) - } - error={nameError && formErrors.pipelineName} - isInvalid={nameError} + color="danger" + iconType="error" > - - setInferencePipelineConfiguration({ - ...configuration, - pipelineName: e.target.value, - }) - } - /> - - )} - - - - - - - - -

    - {i18n.translate( + {modelStateChangeError} + + + + )} + - + > + + + + + ), + id: ConfigurePipelineTabId.CREATE_NEW, + name: CREATE_NEW_TAB_NAME, + }, + { + content: ( + <> - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionDeployTrainedModel', - { - defaultMessage: - 'To perform natural language processing tasks in your cluster, you must deploy an appropriate trained model.', - } - )} -

    - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink', + + -
    - - - - - + - - setInferencePipelineConfiguration({ - ...configuration, - inferenceConfig: undefined, - modelID: value, - fieldMappings: undefined, - }) - } - options={modelOptions} - valueOfSelected={modelID === '' ? MODEL_SELECT_PLACEHOLDER_VALUE : modelID} - /> - - - - - - - - + hasDividers + data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-configureInferencePipeline-selectExistingPipeline`} + valueOfSelected={ + pipelineName.length > 0 ? pipelineName : PIPELINE_SELECT_PLACEHOLDER_VALUE + } + options={pipelineOptions} + onChange={(value) => selectExistingPipeline(value)} + /> + + + + ), + id: ConfigurePipelineTabId.USE_EXISTING, + name: USE_EXISTING_TAB_NAME, + }, + ]; + + return ( + <> + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.title', + { defaultMessage: 'Configure a pipeline' } + )} +

    +
    + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.description', + { + defaultMessage: + 'Build or reuse a child pipeline that will be used as a processor in your main pipeline.', + } + )} +

    +
    + + { + const isExistingPipeline = tab.id === ConfigurePipelineTabId.USE_EXISTING; + if (isExistingPipeline !== configuration.existingPipeline) { + setInferencePipelineConfiguration({ + ...EMPTY_PIPELINE_CONFIGURATION, + existingPipeline: isExistingPipeline, + }); + } + }} + /> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.test.tsx deleted file mode 100644 index 356de3acc9dc..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setMockValues } from '../../../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiButton } from '@elastic/eui'; - -import { DeployModel } from './deploy_model'; -import { TextExpansionDismissButton } from './text_expansion_callout'; - -const DEFAULT_VALUES = { - startTextExpansionModelError: undefined, - isCreateButtonDisabled: false, - isModelDownloadInProgress: false, - isModelDownloaded: false, - isModelStarted: false, - isStartButtonDisabled: false, -}; - -describe('DeployModel', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(DEFAULT_VALUES); - }); - it('renders deploy button', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isCreateButtonDisabled={false} - isDismissable={false} - /> - ); - expect(wrapper.find(EuiButton).length).toBe(1); - const button = wrapper.find(EuiButton); - expect(button.prop('disabled')).toBe(false); - }); - it('renders disabled deploy button if it is set to disabled', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isCreateButtonDisabled - isDismissable={false} - /> - ); - expect(wrapper.find(EuiButton).length).toBe(1); - const button = wrapper.find(EuiButton); - expect(button.prop('disabled')).toBe(true); - }); - it('renders dismiss button if it is set to dismissable', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isCreateButtonDisabled={false} - isDismissable - /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); - }); - it('does not render dismiss button if it is set to non-dismissable', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isCreateButtonDisabled={false} - isDismissable={false} - /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx deleted file mode 100644 index ef7dd486e5eb..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { useActions } from 'kea'; - -import { - EuiBadge, - EuiButton, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, FormattedHTMLMessage } from '@kbn/i18n-react'; - -import { docLinks } from '../../../../../shared/doc_links'; - -import { TextExpansionCallOutState, TextExpansionDismissButton } from './text_expansion_callout'; -import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; - -export const DeployModel = ({ - dismiss, - ingestionMethod, - isCreateButtonDisabled, - isDismissable, -}: Pick< - TextExpansionCallOutState, - 'dismiss' | 'ingestionMethod' | 'isCreateButtonDisabled' | 'isDismissable' ->) => { - const { createTextExpansionModel } = useActions(TextExpansionCalloutLogic); - - return ( - - - - - - - - - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title', - { defaultMessage: 'Improve your results with ELSER v2' } - )} -

    -
    -
    - {isDismissable && ( - - - - )} -
    -
    - - - - - - - - - - - createTextExpansionModel()} - > - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.deployButton.label', - { - defaultMessage: 'Deploy', - } - )} - - - - - - - - - - - -
    -
    - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.test.tsx new file mode 100644 index 000000000000..739e709ea10f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +import { DeployModel } from './deploy_model'; +import { E5MultilingualDismissButton } from './e5_multilingual_callout'; + +const DEFAULT_VALUES = { + startE5MultilingualModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('DeployModel', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders deploy button', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(false); + }); + it('renders disabled deploy button if it is set to disabled', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled + isDismissable={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(true); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable + /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable={false} + /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.tsx new file mode 100644 index 000000000000..6d616a453e9f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/deploy_model.tsx @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions } from 'kea'; + +import { + EuiBadge, + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedHTMLMessage, FormattedMessage } from '@kbn/i18n-react'; + +import { E5MultilingualCallOutState, E5MultilingualDismissButton } from './e5_multilingual_callout'; +import { E5MultilingualCalloutLogic } from './e5_multilingual_callout_logic'; + +export const DeployModel = ({ + dismiss, + ingestionMethod, + isCreateButtonDisabled, + isDismissable, +}: Pick< + E5MultilingualCallOutState, + 'dismiss' | 'ingestionMethod' | 'isCreateButtonDisabled' | 'isDismissable' +>) => { + const { createE5MultilingualModel } = useActions(E5MultilingualCalloutLogic); + + return ( + + + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.title', + { defaultMessage: 'Improve your results with E5' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + + + + + + + + + + createE5MultilingualModel()} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCallOut.deployButton.label', + { + defaultMessage: 'Deploy', + } + )} + + + + + + + + + + + +
    +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.test.tsx new file mode 100644 index 000000000000..ad9f99960ad0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.test.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { DeployModel } from './deploy_model'; +import { E5MultilingualCallOut } from './e5_multilingual_callout'; +import { E5MultilingualErrors } from './e5_multilingual_errors'; +import { ModelDeployed } from './model_deployed'; +import { ModelDeploymentInProgress } from './model_deployment_in_progress'; +import { ModelStarted } from './model_started'; + +const DEFAULT_VALUES = { + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('E5MultilingualCallOut', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders error panel instead of normal panel if there are some errors', () => { + setMockValues({ + ...DEFAULT_VALUES, + e5MultilingualError: { + title: 'Error with E5 Multilingual deployment', + message: 'Mocked error message', + }, + }); + + const wrapper = shallow(); + expect(wrapper.find(E5MultilingualErrors).length).toBe(1); + }); + it('renders panel with deployment instructions if the model is not deployed', () => { + const wrapper = shallow(); + expect(wrapper.find(DeployModel).length).toBe(1); + }); + it('renders panel with deployment in progress status if the model is being deployed', () => { + setMockValues({ + ...DEFAULT_VALUES, + isModelDownloadInProgress: true, + }); + + const wrapper = shallow(); + expect(wrapper.find(ModelDeploymentInProgress).length).toBe(1); + }); + it('renders panel with deployment in progress status if the model has been deployed', () => { + setMockValues({ + ...DEFAULT_VALUES, + isModelDownloaded: true, + }); + + const wrapper = shallow(); + expect(wrapper.find(ModelDeployed).length).toBe(1); + }); + it('renders panel with deployment in progress status if the model has been started', () => { + setMockValues({ + ...DEFAULT_VALUES, + isModelStarted: true, + }); + + const wrapper = shallow(); + expect(wrapper.find(ModelStarted).length).toBe(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.tsx new file mode 100644 index 000000000000..bfe92e5b7c96 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout.tsx @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useCallback, useState } from 'react'; + +import { useValues } from 'kea'; + +import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { KibanaLogic } from '../../../../../../shared/kibana'; + +import { useLocalStorage } from '../../../../../../shared/use_local_storage'; + +import { IndexViewLogic } from '../../../index_view_logic'; + +import { TRAINED_MODELS_PATH } from '../utils'; + +import { DeployModel } from './deploy_model'; +import { E5MultilingualCalloutLogic } from './e5_multilingual_callout_logic'; +import { E5MultilingualErrors } from './e5_multilingual_errors'; +import { ModelDeployed } from './model_deployed'; +import { ModelDeploymentInProgress } from './model_deployment_in_progress'; +import { ModelStarted } from './model_started'; + +export interface E5MultilingualCallOutState { + dismiss: () => void; + ingestionMethod: string; + isCompact: boolean; + isCreateButtonDisabled: boolean; + isDismissable: boolean; + isSingleThreaded: boolean; + isStartButtonDisabled: boolean; + show: boolean; +} + +export interface E5MultilingualCallOutProps { + isCompact?: boolean; + isDismissable?: boolean; +} + +export const E5_MULTILINGUAL_CALL_OUT_DISMISSED_KEY = + 'enterprise-search-e5-multilingual-callout-dismissed'; + +export const E5MultilingualDismissButton = ({ + dismiss, +}: Pick) => { + return ( + + ); +}; + +export const FineTuneModelsButton: React.FC = () => ( + + KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, { + shouldNotCreateHref: true, + }) + } + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCallOut.fineTuneModelButton', + { + defaultMessage: 'Fine-tune performance', + } + )} + +); + +export const E5MultilingualCallOut: React.FC = (props) => { + const isCompact = props.isCompact !== undefined ? props.isCompact : false; + const isDismissable = props.isDismissable !== undefined ? props.isDismissable : false; + + const [calloutDismissed, setCalloutDismissed] = useLocalStorage( + E5_MULTILINGUAL_CALL_OUT_DISMISSED_KEY, + false + ); + + const [show, setShow] = useState(() => { + if (!isDismissable) return true; + return !calloutDismissed; + }); + + const dismiss = useCallback(() => { + setShow(false); + setCalloutDismissed(true); + }, []); + + const { ingestionMethod } = useValues(IndexViewLogic); + const { + isCreateButtonDisabled, + isModelDownloadInProgress, + isModelDownloaded, + isModelRunningSingleThreaded, + isModelStarted, + e5MultilingualError, + isStartButtonDisabled, + } = useValues(E5MultilingualCalloutLogic); + + if (e5MultilingualError) return ; + + if (!show) return null; + + if (isModelDownloadInProgress) { + return ; + } else if (isModelDownloaded) { + return ( + + ); + } else if (isModelStarted) { + return ( + + ); + } + + return ( + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.test.ts new file mode 100644 index 000000000000..0ea1d546d407 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.test.ts @@ -0,0 +1,469 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../../../../__mocks__/kea_logic'; + +import { HttpResponse } from '@kbn/core/public'; + +import { ErrorResponse, HttpError, Status } from '../../../../../../../../common/types/api'; +import { MlModelDeploymentState } from '../../../../../../../../common/types/ml'; +import { CreateE5MultilingualModelApiLogic } from '../../../../../api/ml_models/e5_multilingual/create_e5_multilingual_model_api_logic'; +import { FetchE5MultilingualModelApiLogic } from '../../../../../api/ml_models/e5_multilingual/fetch_e5_multilingual_model_api_logic'; +import { StartE5MultilingualModelApiLogic } from '../../../../../api/ml_models/e5_multilingual/start_e5_multilingual_model_api_logic'; + +import { + E5MultilingualCalloutLogic, + E5MultilingualCalloutValues, + getE5MultilingualError, +} from './e5_multilingual_callout_logic'; + +const DEFAULT_VALUES: E5MultilingualCalloutValues = { + createE5MultilingualModelError: undefined, + createE5MultilingualModelStatus: Status.IDLE, + createdE5MultilingualModel: undefined, + fetchE5MultilingualModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelRunningSingleThreaded: false, + isModelStarted: false, + isPollingE5MultilingualModelActive: false, + isStartButtonDisabled: false, + startE5MultilingualModelError: undefined, + startE5MultilingualModelStatus: Status.IDLE, + e5MultilingualModel: undefined, + e5MultilingualModelPollTimeoutId: null, + e5MultilingualError: null, +}; + +jest.useFakeTimers(); + +describe('E5MultilingualCalloutLogic', () => { + const { mount } = new LogicMounter(E5MultilingualCalloutLogic); + const { mount: mountCreateE5MultilingualModelApiLogic } = new LogicMounter( + CreateE5MultilingualModelApiLogic + ); + const { mount: mountFetchE5MultilingualModelApiLogic } = new LogicMounter( + FetchE5MultilingualModelApiLogic + ); + const { mount: mountStartE5MultilingualModelApiLogic } = new LogicMounter( + StartE5MultilingualModelApiLogic + ); + + beforeEach(() => { + jest.clearAllMocks(); + mountCreateE5MultilingualModelApiLogic(); + mountFetchE5MultilingualModelApiLogic(); + mountStartE5MultilingualModelApiLogic(); + mount(); + }); + + it('has expected default values', () => { + expect(E5MultilingualCalloutLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('getE5MultilingualError', () => { + const error = { + body: { + error: 'some-error', + message: 'some-error-message', + statusCode: 500, + }, + } as HttpError; + it('returns null if there is no error', () => { + expect(getE5MultilingualError(undefined, undefined, undefined)).toBe(null); + }); + it('uses the correct title and message from a create error', () => { + expect(getE5MultilingualError(error, undefined, undefined)).toEqual({ + title: 'Error with E5 Multilingual deployment', + message: error.body?.message, + }); + }); + it('uses the correct title and message from a fetch error', () => { + expect(getE5MultilingualError(undefined, error, undefined)).toEqual({ + title: 'Error fetching E5 Multilingual model', + message: error.body?.message, + }); + }); + it('uses the correct title and message from a start error', () => { + expect(getE5MultilingualError(undefined, undefined, error)).toEqual({ + title: 'Error starting E5 Multilingual deployment', + message: error.body?.message, + }); + }); + }); + + describe('listeners', () => { + describe('createE5MultilingualModelPollingTimeout', () => { + const duration = 5000; + it('sets polling timeout', () => { + jest.spyOn(global, 'setTimeout'); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'setE5MultilingualModelPollingId'); + + E5MultilingualCalloutLogic.actions.createE5MultilingualModelPollingTimeout(duration); + + expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), duration); + expect( + E5MultilingualCalloutLogic.actions.setE5MultilingualModelPollingId + ).toHaveBeenCalled(); + }); + it('clears polling timeout if it is set', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + + E5MultilingualCalloutLogic.actions.createE5MultilingualModelPollingTimeout(duration); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + }); + }); + + describe('createE5MultilingualModelSuccess', () => { + it('sets createdE5MultilingualModel', () => { + jest.spyOn(E5MultilingualCalloutLogic.actions, 'fetchE5MultilingualModel'); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'startPollingE5MultilingualModel'); + + E5MultilingualCalloutLogic.actions.createE5MultilingualModelSuccess({ + deploymentState: MlModelDeploymentState.Downloading, + modelId: 'mock-model-id', + }); + + expect(E5MultilingualCalloutLogic.actions.fetchE5MultilingualModel).toHaveBeenCalled(); + expect( + E5MultilingualCalloutLogic.actions.startPollingE5MultilingualModel + ).toHaveBeenCalled(); + }); + }); + + describe('fetchE5MultilingualModelSuccess', () => { + const data = { + deploymentState: MlModelDeploymentState.Downloading, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }; + + it('starts polling when the model is downloading and polling is not active', () => { + mount({ + ...DEFAULT_VALUES, + }); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'startPollingE5MultilingualModel'); + + E5MultilingualCalloutLogic.actions.fetchE5MultilingualModelSuccess(data); + + expect( + E5MultilingualCalloutLogic.actions.startPollingE5MultilingualModel + ).toHaveBeenCalled(); + }); + it('sets polling timeout when the model is downloading and polling is active', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'createE5MultilingualModelPollingTimeout'); + + E5MultilingualCalloutLogic.actions.fetchE5MultilingualModelSuccess(data); + + expect( + E5MultilingualCalloutLogic.actions.createE5MultilingualModelPollingTimeout + ).toHaveBeenCalled(); + }); + it('stops polling when the model is downloaded and polling is active', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'stopPollingE5MultilingualModel'); + + E5MultilingualCalloutLogic.actions.fetchE5MultilingualModelSuccess({ + deploymentState: MlModelDeploymentState.Downloaded, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + + expect( + E5MultilingualCalloutLogic.actions.stopPollingE5MultilingualModel + ).toHaveBeenCalled(); + }); + }); + + describe('fetchE5MultilingualModelError', () => { + it('stops polling if it is active', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'createE5MultilingualModelPollingTimeout'); + + E5MultilingualCalloutLogic.actions.fetchE5MultilingualModelError({ + body: { + error: '', + message: 'some error', + statusCode: 500, + }, + } as HttpResponse); + + expect( + E5MultilingualCalloutLogic.actions.createE5MultilingualModelPollingTimeout + ).toHaveBeenCalled(); + }); + }); + + describe('startPollingE5MultilingualModel', () => { + it('sets polling timeout', () => { + jest.spyOn(E5MultilingualCalloutLogic.actions, 'createE5MultilingualModelPollingTimeout'); + + E5MultilingualCalloutLogic.actions.startPollingE5MultilingualModel(); + + expect( + E5MultilingualCalloutLogic.actions.createE5MultilingualModelPollingTimeout + ).toHaveBeenCalled(); + }); + it('clears polling timeout if it is set', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + + E5MultilingualCalloutLogic.actions.startPollingE5MultilingualModel(); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + }); + }); + + describe('startE5MultilingualModelSuccess', () => { + it('sets startedE5MultilingualModel', () => { + jest.spyOn(E5MultilingualCalloutLogic.actions, 'fetchE5MultilingualModel'); + + E5MultilingualCalloutLogic.actions.startE5MultilingualModelSuccess({ + deploymentState: MlModelDeploymentState.FullyAllocated, + modelId: 'mock-model-id', + }); + + expect(E5MultilingualCalloutLogic.actions.fetchE5MultilingualModel).toHaveBeenCalled(); + }); + }); + + describe('stopPollingE5MultilingualModel', () => { + it('clears polling timeout and poll timeout ID if it is set', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + + jest.spyOn(global, 'clearTimeout'); + jest.spyOn(E5MultilingualCalloutLogic.actions, 'clearE5MultilingualModelPollingId'); + + E5MultilingualCalloutLogic.actions.stopPollingE5MultilingualModel(); + + expect(clearTimeout).toHaveBeenCalledWith('timeout-id'); + expect( + E5MultilingualCalloutLogic.actions.clearE5MultilingualModelPollingId + ).toHaveBeenCalled(); + }); + }); + }); + + describe('reducers', () => { + describe('e5MultilingualModelPollTimeoutId', () => { + it('gets cleared on clearE5MultilingualModelPollingId', () => { + E5MultilingualCalloutLogic.actions.clearE5MultilingualModelPollingId(); + + expect(E5MultilingualCalloutLogic.values.e5MultilingualModelPollTimeoutId).toBe(null); + }); + it('gets set on setE5MultilingualModelPollingId', () => { + const timeout = setTimeout(() => {}, 500); + E5MultilingualCalloutLogic.actions.setE5MultilingualModelPollingId(timeout); + + expect(E5MultilingualCalloutLogic.values.e5MultilingualModelPollTimeoutId).toEqual(timeout); + }); + }); + }); + + describe('selectors', () => { + describe('isCreateButtonDisabled', () => { + it('is set to false if the fetch model API is idle', () => { + CreateE5MultilingualModelApiLogic.actions.apiReset(); + expect(E5MultilingualCalloutLogic.values.isCreateButtonDisabled).toBe(false); + }); + it('is set to true if the fetch model API is not idle', () => { + CreateE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.Downloading, + modelId: 'mock-model-id', + }); + expect(E5MultilingualCalloutLogic.values.isCreateButtonDisabled).toBe(true); + }); + }); + + describe('e5MultilingualError', () => { + const error = { + body: { + error: 'Error with E5 Multilingual deployment', + message: 'Mocked error message', + statusCode: 500, + }, + } as HttpError; + + it('returns null when there are no errors', () => { + CreateE5MultilingualModelApiLogic.actions.apiReset(); + FetchE5MultilingualModelApiLogic.actions.apiReset(); + StartE5MultilingualModelApiLogic.actions.apiReset(); + expect(E5MultilingualCalloutLogic.values.e5MultilingualError).toBe(null); + }); + it('returns extracted error for create', () => { + CreateE5MultilingualModelApiLogic.actions.apiError(error); + expect(E5MultilingualCalloutLogic.values.e5MultilingualError).toStrictEqual({ + title: 'Error with E5 Multilingual deployment', + message: 'Mocked error message', + }); + }); + it('returns extracted error for fetch', () => { + FetchE5MultilingualModelApiLogic.actions.apiError(error); + expect(E5MultilingualCalloutLogic.values.e5MultilingualError).toStrictEqual({ + title: 'Error fetching E5 Multilingual model', + message: 'Mocked error message', + }); + }); + it('returns extracted error for start', () => { + StartE5MultilingualModelApiLogic.actions.apiError(error); + expect(E5MultilingualCalloutLogic.values.e5MultilingualError).toStrictEqual({ + title: 'Error starting E5 Multilingual deployment', + message: 'Mocked error message', + }); + }); + }); + + describe('isModelDownloadInProgress', () => { + it('is set to true if the model is downloading', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.Downloading, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelDownloadInProgress).toBe(true); + }); + it('is set to false if the model is downloading', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.Started, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelDownloadInProgress).toBe(false); + }); + }); + + describe('isModelDownloaded', () => { + it('is set to true if the model is downloaded', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.Downloaded, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelDownloaded).toBe(true); + }); + it('is set to false if the model is not downloaded', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.NotDeployed, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelDownloaded).toBe(false); + }); + }); + + describe('isModelRunningSingleThreaded', () => { + it('is set to true if the model has 1 target allocation and 1 thread', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.FullyAllocated, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelRunningSingleThreaded).toBe(true); + }); + it('is set to false if the model has multiple target allocations', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.FullyAllocated, + modelId: 'mock-model-id', + targetAllocationCount: 2, + nodeAllocationCount: 2, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelRunningSingleThreaded).toBe(false); + }); + it('is set to false if the model runs on multiple threads', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.FullyAllocated, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 4, + }); + expect(E5MultilingualCalloutLogic.values.isModelRunningSingleThreaded).toBe(false); + }); + }); + + describe('isModelStarted', () => { + it('is set to true if the model is started', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.FullyAllocated, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelStarted).toBe(true); + }); + it('is set to false if the model is not started', () => { + FetchE5MultilingualModelApiLogic.actions.apiSuccess({ + deploymentState: MlModelDeploymentState.NotDeployed, + modelId: 'mock-model-id', + targetAllocationCount: 1, + nodeAllocationCount: 1, + threadsPerAllocation: 1, + }); + expect(E5MultilingualCalloutLogic.values.isModelStarted).toBe(false); + }); + }); + + describe('isPollingE5MultilingualModelActive', () => { + it('is set to false if polling is not active', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: null, + }); + + expect(E5MultilingualCalloutLogic.values.isPollingE5MultilingualModelActive).toBe(false); + }); + it('is set to true if polling is active', () => { + mount({ + ...DEFAULT_VALUES, + e5MultilingualModelPollTimeoutId: 'timeout-id', + }); + + expect(E5MultilingualCalloutLogic.values.isPollingE5MultilingualModelActive).toBe(true); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.ts new file mode 100644 index 000000000000..4c2a9acb453b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_callout_logic.ts @@ -0,0 +1,308 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { i18n } from '@kbn/i18n'; + +import { HttpError, Status } from '../../../../../../../../common/types/api'; +import { MlModelDeploymentState } from '../../../../../../../../common/types/ml'; +import { getErrorsFromHttpResponse } from '../../../../../../shared/flash_messages/handle_api_errors'; + +import { + CreateE5MultilingualModelApiLogic, + CreateE5MultilingualModelApiLogicActions, + CreateE5MultilingualModelResponse, +} from '../../../../../api/ml_models/e5_multilingual/create_e5_multilingual_model_api_logic'; +import { + FetchE5MultilingualModelApiLogic, + FetchE5MultilingualModelApiLogicActions, + FetchE5MultilingualModelResponse, +} from '../../../../../api/ml_models/e5_multilingual/fetch_e5_multilingual_model_api_logic'; +import { + StartE5MultilingualModelApiLogic, + StartE5MultilingualModelApiLogicActions, +} from '../../../../../api/ml_models/e5_multilingual/start_e5_multilingual_model_api_logic'; + +const FETCH_E5_MULTILINGUAL_MODEL_POLLING_DURATION = 5000; // 5 seconds +const FETCH_E5_MULTILINGUAL_MODEL_POLLING_DURATION_ON_FAILURE = 30000; // 30 seconds +const E5_MULTILINGUAL_MODEL_ID = '.multilingual-e5-small'; + +interface E5MultilingualCalloutActions { + clearE5MultilingualModelPollingId: () => void; + createE5MultilingualModel: () => void; + createE5MultilingualModelMakeRequest: CreateE5MultilingualModelApiLogicActions['makeRequest']; + createE5MultilingualModelPollingTimeout: (duration: number) => { duration: number }; + createE5MultilingualModelSuccess: CreateE5MultilingualModelApiLogicActions['apiSuccess']; + fetchE5MultilingualModel: () => void; + fetchE5MultilingualModelMakeRequest: FetchE5MultilingualModelApiLogicActions['makeRequest']; + fetchE5MultilingualModelError: FetchE5MultilingualModelApiLogicActions['apiError']; + fetchE5MultilingualModelSuccess: FetchE5MultilingualModelApiLogicActions['apiSuccess']; + setE5MultilingualModelPollingId: (pollTimeoutId: ReturnType) => { + pollTimeoutId: ReturnType; + }; + startPollingE5MultilingualModel: () => void; + startE5MultilingualModel: () => void; + startE5MultilingualModelMakeRequest: StartE5MultilingualModelApiLogicActions['makeRequest']; + startE5MultilingualModelSuccess: StartE5MultilingualModelApiLogicActions['apiSuccess']; + stopPollingE5MultilingualModel: () => void; + e5MultilingualModel: FetchE5MultilingualModelApiLogicActions['apiSuccess']; +} + +export interface E5MultilingualCalloutError { + title: string; + message: string; +} + +export interface E5MultilingualCalloutValues { + createE5MultilingualModelError: HttpError | undefined; + createE5MultilingualModelStatus: Status; + createdE5MultilingualModel: CreateE5MultilingualModelResponse | undefined; + fetchE5MultilingualModelError: HttpError | undefined; + isCreateButtonDisabled: boolean; + isModelDownloadInProgress: boolean; + isModelDownloaded: boolean; + isModelRunningSingleThreaded: boolean; + isModelStarted: boolean; + isPollingE5MultilingualModelActive: boolean; + isStartButtonDisabled: boolean; + startE5MultilingualModelError: HttpError | undefined; + startE5MultilingualModelStatus: Status; + e5MultilingualModel: FetchE5MultilingualModelResponse | undefined; + e5MultilingualModelPollTimeoutId: null | ReturnType; + e5MultilingualError: E5MultilingualCalloutError | null; +} + +/** + * Extracts the topmost error in precedence order (create > start > fetch). + * @param createError + * @param fetchError + * @param startError + * @returns the extracted error or null if there is no error + */ +export const getE5MultilingualError = ( + createError: HttpError | undefined, + fetchError: HttpError | undefined, + startError: HttpError | undefined +) => { + return createError !== undefined + ? { + title: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCreateError.title', + { + defaultMessage: 'Error with E5 Multilingual deployment', + } + ), + message: getErrorsFromHttpResponse(createError)[0], + } + : startError !== undefined + ? { + title: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualStartError.title', + { + defaultMessage: 'Error starting E5 Multilingual deployment', + } + ), + message: getErrorsFromHttpResponse(startError)[0], + } + : fetchError !== undefined + ? { + title: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualFetchError.title', + { + defaultMessage: 'Error fetching E5 Multilingual model', + } + ), + message: getErrorsFromHttpResponse(fetchError)[0], + } + : null; +}; + +export const E5MultilingualCalloutLogic = kea< + MakeLogicType +>({ + actions: { + clearE5MultilingualModelPollingId: true, + createE5MultilingualModelPollingTimeout: (duration) => ({ duration }), + setE5MultilingualModelPollingId: (pollTimeoutId: ReturnType) => ({ + pollTimeoutId, + }), + startPollingE5MultilingualModel: true, + stopPollingE5MultilingualModel: true, + createE5MultilingualModel: true, + fetchE5MultilingualModel: true, + startE5MultilingualModel: true, + }, + connect: { + actions: [ + CreateE5MultilingualModelApiLogic, + [ + 'makeRequest as createE5MultilingualModelMakeRequest', + 'apiSuccess as createE5MultilingualModelSuccess', + 'apiError as createE5MultilingualModelError', + ], + FetchE5MultilingualModelApiLogic, + [ + 'makeRequest as fetchE5MultilingualModelMakeRequest', + 'apiSuccess as fetchE5MultilingualModelSuccess', + 'apiError as fetchE5MultilingualModelError', + ], + StartE5MultilingualModelApiLogic, + [ + 'makeRequest as startE5MultilingualModelMakeRequest', + 'apiSuccess as startE5MultilingualModelSuccess', + 'apiError as startE5MultilingualModelError', + ], + ], + values: [ + CreateE5MultilingualModelApiLogic, + [ + 'data as createdE5MultilingualModel', + 'status as createE5MultilingualModelStatus', + 'error as createE5MultilingualModelError', + ], + FetchE5MultilingualModelApiLogic, + ['data as e5MultilingualModel', 'error as fetchE5MultilingualModelError'], + StartE5MultilingualModelApiLogic, + ['status as startE5MultilingualModelStatus', 'error as startE5MultilingualModelError'], + ], + }, + events: ({ actions, values }) => ({ + afterMount: () => { + actions.fetchE5MultilingualModel(); + }, + beforeUnmount: () => { + if (values.e5MultilingualModelPollTimeoutId !== null) { + actions.stopPollingE5MultilingualModel(); + } + }, + }), + listeners: ({ actions, values }) => ({ + createE5MultilingualModel: () => + actions.createE5MultilingualModelMakeRequest({ modelId: E5_MULTILINGUAL_MODEL_ID }), + fetchE5MultilingualModel: () => + actions.fetchE5MultilingualModelMakeRequest({ modelId: E5_MULTILINGUAL_MODEL_ID }), + startE5MultilingualModel: () => + actions.startE5MultilingualModelMakeRequest({ modelId: E5_MULTILINGUAL_MODEL_ID }), + createE5MultilingualModelPollingTimeout: ({ duration }) => { + if (values.e5MultilingualModelPollTimeoutId !== null) { + clearTimeout(values.e5MultilingualModelPollTimeoutId); + } + const timeoutId = setTimeout(() => { + actions.fetchE5MultilingualModel(); + }, duration); + actions.setE5MultilingualModelPollingId(timeoutId); + }, + createE5MultilingualModelSuccess: () => { + actions.fetchE5MultilingualModel(); + actions.startPollingE5MultilingualModel(); + }, + fetchE5MultilingualModelError: () => { + if (values.isPollingE5MultilingualModelActive) { + actions.createE5MultilingualModelPollingTimeout( + FETCH_E5_MULTILINGUAL_MODEL_POLLING_DURATION_ON_FAILURE + ); + } + }, + fetchE5MultilingualModelSuccess: (data) => { + if (data?.deploymentState === MlModelDeploymentState.Downloading) { + if (!values.isPollingE5MultilingualModelActive) { + actions.startPollingE5MultilingualModel(); + } else { + actions.createE5MultilingualModelPollingTimeout( + FETCH_E5_MULTILINGUAL_MODEL_POLLING_DURATION + ); + } + } else if ( + data?.deploymentState === MlModelDeploymentState.Downloaded && + values.isPollingE5MultilingualModelActive + ) { + actions.stopPollingE5MultilingualModel(); + } + }, + startPollingE5MultilingualModel: () => { + if (values.e5MultilingualModelPollTimeoutId !== null) { + clearTimeout(values.e5MultilingualModelPollTimeoutId); + } + actions.createE5MultilingualModelPollingTimeout(FETCH_E5_MULTILINGUAL_MODEL_POLLING_DURATION); + }, + startE5MultilingualModelSuccess: () => { + actions.fetchE5MultilingualModel(); + }, + stopPollingE5MultilingualModel: () => { + if (values.e5MultilingualModelPollTimeoutId !== null) { + clearTimeout(values.e5MultilingualModelPollTimeoutId); + actions.clearE5MultilingualModelPollingId(); + } + }, + }), + path: ['enterprise_search', 'content', 'e5_multilingual_callout_logic'], + reducers: { + e5MultilingualModelPollTimeoutId: [ + null, + { + clearE5MultilingualModelPollingId: () => null, + setE5MultilingualModelPollingId: (_, { pollTimeoutId }) => pollTimeoutId, + }, + ], + }, + selectors: ({ selectors }) => ({ + isCreateButtonDisabled: [ + () => [selectors.createE5MultilingualModelStatus], + (status: Status) => status !== Status.IDLE && status !== Status.ERROR, + ], + isModelDownloadInProgress: [ + () => [selectors.e5MultilingualModel], + (data: FetchE5MultilingualModelResponse) => + data?.deploymentState === MlModelDeploymentState.Downloading, + ], + isModelDownloaded: [ + () => [selectors.e5MultilingualModel], + (data: FetchE5MultilingualModelResponse) => + data?.deploymentState === MlModelDeploymentState.Downloaded, + ], + isModelStarted: [ + () => [selectors.e5MultilingualModel], + (data: FetchE5MultilingualModelResponse) => + data?.deploymentState === MlModelDeploymentState.Starting || + data?.deploymentState === MlModelDeploymentState.Started || + data?.deploymentState === MlModelDeploymentState.FullyAllocated, + ], + isPollingE5MultilingualModelActive: [ + () => [selectors.e5MultilingualModelPollTimeoutId], + (pollingTimeoutId: E5MultilingualCalloutValues['e5MultilingualModelPollTimeoutId']) => + pollingTimeoutId !== null, + ], + e5MultilingualError: [ + () => [ + selectors.createE5MultilingualModelError, + selectors.fetchE5MultilingualModelError, + selectors.startE5MultilingualModelError, + ], + ( + createE5MultilingualError: E5MultilingualCalloutValues['createE5MultilingualModelError'], + fetchE5MultilingualError: E5MultilingualCalloutValues['fetchE5MultilingualModelError'], + startE5MultilingualError: E5MultilingualCalloutValues['startE5MultilingualModelError'] + ) => + getE5MultilingualError( + createE5MultilingualError, + fetchE5MultilingualError, + startE5MultilingualError + ), + ], + isStartButtonDisabled: [ + () => [selectors.startE5MultilingualModelStatus], + (status: Status) => status !== Status.IDLE && status !== Status.ERROR, + ], + isModelRunningSingleThreaded: [ + () => [selectors.e5MultilingualModel], + (data: FetchE5MultilingualModelResponse) => + // Running single threaded if model has max 1 deployment on 1 node with 1 thread + data?.targetAllocationCount * data?.threadsPerAllocation <= 1, + ], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.test.tsx new file mode 100644 index 000000000000..d218c8d111a2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiCallOut } from '@elastic/eui'; + +import { E5MultilingualErrors } from './e5_multilingual_errors'; + +describe('E5MultilingualErrors', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + const error = { + title: 'some-error-title', + message: 'some-error-message', + }; + it('extracts error panel with the given title and message', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiCallOut).length).toBe(1); + expect(wrapper.find(EuiCallOut).prop('title')).toEqual(error.title); + expect(wrapper.find(EuiCallOut).find('p').length).toBe(1); + expect(wrapper.find(EuiCallOut).find('p').text()).toEqual(error.message); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.tsx new file mode 100644 index 000000000000..78038fee5d12 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/e5_multilingual_errors.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiCallOut } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { EuiLinkTo } from '../../../../../../shared/react_router_helpers'; + +import { SendEnterpriseSearchTelemetry } from '../../../../../../shared/telemetry'; + +import { ML_NOTIFICATIONS_PATH } from '../../../../../routes'; + +export function E5MultilingualErrors({ error }: { error: { title: string; message: string } }) { + return ( + <> + + +

    {error.message}

    + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCreateError.mlNotificationsLink', + { + defaultMessage: 'Machine Learning notifications', + } + )} + +
    + + ); +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.test.tsx new file mode 100644 index 000000000000..58df830f43e2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +import { E5MultilingualDismissButton } from './e5_multilingual_callout'; +import { ModelDeployed } from './model_deployed'; + +const DEFAULT_VALUES = { + startE5MultilingualModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelDeployed', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders start button', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(false); + }); + it('renders disabled start button if it is set to disabled', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(true); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.tsx new file mode 100644 index 000000000000..20444dd5f705 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployed.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions } from 'kea'; + +import { + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { + E5MultilingualCallOutState, + E5MultilingualDismissButton, + FineTuneModelsButton, +} from './e5_multilingual_callout'; +import { E5MultilingualCalloutLogic } from './e5_multilingual_callout_logic'; + +export const ModelDeployed = ({ + dismiss, + ingestionMethod, + isDismissable, + isStartButtonDisabled, +}: Pick< + E5MultilingualCallOutState, + 'dismiss' | 'ingestionMethod' | 'isDismissable' | 'isStartButtonDisabled' +>) => { + const { startE5MultilingualModel } = useActions(E5MultilingualCalloutLogic); + + return ( + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.deployedTitle', + { defaultMessage: 'Your E5 model has deployed but not started.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.deployedBody', + { + defaultMessage: + 'You may start the model in a single-threaded configuration for testing, or tune the performance for a production environment.', + } + )} +

    +
    +
    + + + + + + + startE5MultilingualModel()} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCallOut.startModelButton.label', + { + defaultMessage: 'Start single-threaded', + } + )} + + + + + + + +
    +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.test.tsx new file mode 100644 index 000000000000..1594824aa1a8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.test.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { E5MultilingualDismissButton } from './e5_multilingual_callout'; +import { ModelDeploymentInProgress } from './model_deployment_in_progress'; + +const DEFAULT_VALUES = { + startE5MultilingualModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelDeploymentInProgress', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( {}} isDismissable />); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( {}} isDismissable={false} />); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.tsx new file mode 100644 index 000000000000..7f7627a6f03f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_deployment_in_progress.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { E5MultilingualCallOutState, E5MultilingualDismissButton } from './e5_multilingual_callout'; + +export const ModelDeploymentInProgress = ({ + dismiss, + isDismissable, +}: Pick) => ( + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.deployingTitle', + { defaultMessage: 'Your E5 model is deploying.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.deployingBody', + { + defaultMessage: + 'You can continue creating your pipeline with other uploaded models in the meantime.', + } + )} +

    +
    +
    +
    +
    +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.test.tsx new file mode 100644 index 000000000000..80563cef58cc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiText } from '@elastic/eui'; + +import { E5MultilingualDismissButton, FineTuneModelsButton } from './e5_multilingual_callout'; +import { ModelStarted } from './model_started'; + +const DEFAULT_VALUES = { + startE5MultilingualModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelStarted', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable isSingleThreaded /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable={false} isSingleThreaded /> + ); + expect(wrapper.find(E5MultilingualDismissButton).length).toBe(0); + }); + it('renders fine-tune button if the model is running single-threaded', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable isSingleThreaded /> + ); + expect(wrapper.find(FineTuneModelsButton).length).toBe(1); + }); + it('does not render description if it is set to compact', () => { + const wrapper = shallow( + {}} isCompact isDismissable isSingleThreaded /> + ); + expect(wrapper.find(EuiText).length).toBe(1); // Title only + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.tsx new file mode 100644 index 000000000000..c6a444373886 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/e5_multilingual_callout/model_started.tsx @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { + EuiButtonEmpty, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { KibanaLogic } from '../../../../../../shared/kibana'; + +import { TRAINED_MODELS_PATH } from '../utils'; + +import { + E5MultilingualCallOutState, + E5MultilingualDismissButton, + FineTuneModelsButton, +} from './e5_multilingual_callout'; + +export const ModelStarted = ({ + dismiss, + isCompact, + isDismissable, + isSingleThreaded, +}: Pick< + E5MultilingualCallOutState, + 'dismiss' | 'isCompact' | 'isDismissable' | 'isSingleThreaded' +>) => ( + + + + + + + + + +

    + {isSingleThreaded + ? isCompact + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedSingleThreadedTitleCompact', + { defaultMessage: 'Your E5 model is running single-threaded.' } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedSingleThreadedTitle', + { defaultMessage: 'Your E5 model has started single-threaded.' } + ) + : isCompact + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedTitleCompact', + { defaultMessage: 'Your E5 model is running.' } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedTitle', + { defaultMessage: 'Your E5 model has started.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + {!isCompact && ( + <> + + +

    + {isSingleThreaded + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedSingleThreadedBody', + { + defaultMessage: + 'This single-threaded configuration is great for testing your custom inference pipelines, however performance should be fine-tuned for production.', + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.e5MultilingualCallOut.startedBody', + { + defaultMessage: 'Enjoy the power of E5 in your custom Inference pipeline.', + } + )} +

    +
    +
    + + + + {isSingleThreaded ? ( + + ) : ( + + KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, { + shouldNotCreateHref: true, + }) + } + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.e5MultilingualCallOut.viewModelsButton', + { + defaultMessage: 'View details', + } + )} + + )} + + + + + )} +
    +
    +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.test.tsx deleted file mode 100644 index a17eae3ef75f..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setMockValues } from '../../../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiButton } from '@elastic/eui'; - -import { ModelDeployed } from './model_deployed'; -import { TextExpansionDismissButton } from './text_expansion_callout'; - -const DEFAULT_VALUES = { - startTextExpansionModelError: undefined, - isCreateButtonDisabled: false, - isModelDownloadInProgress: false, - isModelDownloaded: false, - isModelStarted: false, - isStartButtonDisabled: false, -}; - -describe('ModelDeployed', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(DEFAULT_VALUES); - }); - it('renders start button', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isDismissable={false} - isStartButtonDisabled={false} - /> - ); - expect(wrapper.find(EuiButton).length).toBe(1); - const button = wrapper.find(EuiButton); - expect(button.prop('disabled')).toBe(false); - }); - it('renders disabled start button if it is set to disabled', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isDismissable={false} - isStartButtonDisabled - /> - ); - expect(wrapper.find(EuiButton).length).toBe(1); - const button = wrapper.find(EuiButton); - expect(button.prop('disabled')).toBe(true); - }); - it('renders dismiss button if it is set to dismissable', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isDismissable - isStartButtonDisabled={false} - /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); - }); - it('does not render dismiss button if it is set to non-dismissable', () => { - const wrapper = shallow( - {}} - ingestionMethod="crawler" - isDismissable={false} - isStartButtonDisabled={false} - /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx deleted file mode 100644 index 50d8ea47fb8f..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { useActions } from 'kea'; - -import { - EuiButton, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiText, - EuiIcon, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { - TextExpansionCallOutState, - TextExpansionDismissButton, - FineTuneModelsButton, -} from './text_expansion_callout'; -import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; - -export const ModelDeployed = ({ - dismiss, - ingestionMethod, - isDismissable, - isStartButtonDisabled, -}: Pick< - TextExpansionCallOutState, - 'dismiss' | 'ingestionMethod' | 'isDismissable' | 'isStartButtonDisabled' ->) => { - const { startTextExpansionModel } = useActions(TextExpansionCalloutLogic); - - return ( - - - - - - - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedTitle', - { defaultMessage: 'Your ELSER v2 model has deployed but not started.' } - )} -

    -
    -
    - {isDismissable && ( - - - - )} -
    -
    - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedBody', - { - defaultMessage: - 'You may start the model in a single-threaded configuration for testing, or tune the performance for a production environment.', - } - )} -

    -
    -
    - - - - - - - startTextExpansionModel()} - > - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.startModelButton.label', - { - defaultMessage: 'Start single-threaded', - } - )} - - - - - - - -
    -
    - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.test.tsx deleted file mode 100644 index f147778539f5..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setMockValues } from '../../../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ModelDeploymentInProgress } from './model_deployment_in_progress'; -import { TextExpansionDismissButton } from './text_expansion_callout'; - -const DEFAULT_VALUES = { - startTextExpansionModelError: undefined, - isCreateButtonDisabled: false, - isModelDownloadInProgress: false, - isModelDownloaded: false, - isModelStarted: false, - isStartButtonDisabled: false, -}; - -describe('ModelDeploymentInProgress', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(DEFAULT_VALUES); - }); - it('renders dismiss button if it is set to dismissable', () => { - const wrapper = shallow( {}} isDismissable />); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); - }); - it('does not render dismiss button if it is set to non-dismissable', () => { - const wrapper = shallow( {}} isDismissable={false} />); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx deleted file mode 100644 index 8804f4ec5843..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { TextExpansionCallOutState, TextExpansionDismissButton } from './text_expansion_callout'; - -export const ModelDeploymentInProgress = ({ - dismiss, - isDismissable, -}: Pick) => ( - - - - - - - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingTitle', - { defaultMessage: 'Your ELSER v2 model is deploying.' } - )} -

    -
    -
    - {isDismissable && ( - - - - )} -
    -
    - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingBody', - { - defaultMessage: - 'You can continue creating your pipeline with other uploaded models in the meantime.', - } - )} -

    -
    -
    -
    -
    -); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx new file mode 100644 index 000000000000..15fb492fae56 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockActions, setMockValues } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiSelectable } from '@elastic/eui'; + +import { ModelSelect } from './model_select'; + +const DEFAULT_VALUES = { + addInferencePipelineModal: { + configuration: {}, + }, + selectableModels: [ + { + modelId: 'model_1', + }, + { + modelId: 'model_2', + }, + ], + indexName: 'my-index', +}; +const MOCK_ACTIONS = { + setInferencePipelineConfiguration: jest.fn(), +}; + +describe('ModelSelect', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + setMockActions(MOCK_ACTIONS); + }); + it('renders model select with no options', () => { + setMockValues({ + ...DEFAULT_VALUES, + selectableModels: null, + }); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + expect(selectable.prop('options')).toEqual([]); + }); + it('renders model select with options', () => { + setMockValues(DEFAULT_VALUES); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + expect(selectable.prop('options')).toEqual([ + { + modelId: 'model_1', + label: 'model_1', + }, + { + modelId: 'model_2', + label: 'model_2', + }, + ]); + }); + it('selects the chosen option', () => { + setMockValues({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + configuration: { + ...DEFAULT_VALUES.addInferencePipelineModal.configuration, + modelID: 'model_2', + }, + }, + }); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + expect(selectable.prop('options')[1].checked).toEqual('on'); + }); + it('sets model ID on selecting an item and clears config', () => { + setMockValues(DEFAULT_VALUES); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + selectable.simulate('change', [{ modelId: 'model_1' }, { modelId: 'model_2', checked: 'on' }]); + expect(MOCK_ACTIONS.setInferencePipelineConfiguration).toHaveBeenCalledWith( + expect.objectContaining({ + inferenceConfig: undefined, + modelID: 'model_2', + fieldMappings: undefined, + }) + ); + }); + it('generates pipeline name on selecting an item', () => { + setMockValues(DEFAULT_VALUES); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + selectable.simulate('change', [{ modelId: 'model_1' }, { modelId: 'model_2', checked: 'on' }]); + expect(MOCK_ACTIONS.setInferencePipelineConfiguration).toHaveBeenCalledWith( + expect.objectContaining({ + pipelineName: 'my-index-model_2', + }) + ); + }); + it('does not generate pipeline name on selecting an item if it a name was supplied by the user', () => { + setMockValues({ + ...DEFAULT_VALUES, + addInferencePipelineModal: { + configuration: { + ...DEFAULT_VALUES.addInferencePipelineModal.configuration, + pipelineName: 'user-pipeline', + isPipelineNameUserSupplied: true, + }, + }, + }); + + const wrapper = shallow(); + expect(wrapper.find(EuiSelectable)).toHaveLength(1); + const selectable = wrapper.find(EuiSelectable); + selectable.simulate('change', [{ modelId: 'model_1' }, { modelId: 'model_2', checked: 'on' }]); + expect(MOCK_ACTIONS.setInferencePipelineConfiguration).toHaveBeenCalledWith( + expect.objectContaining({ + pipelineName: 'user-pipeline', + }) + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx new file mode 100644 index 000000000000..86c91c483702 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions, useValues } from 'kea'; + +import { EuiSelectable, useIsWithinMaxBreakpoint } from '@elastic/eui'; + +import { MlModel } from '../../../../../../../common/types/ml'; +import { IndexNameLogic } from '../../index_name_logic'; +import { IndexViewLogic } from '../../index_view_logic'; + +import { MLInferenceLogic } from './ml_inference_logic'; +import { ModelSelectLogic } from './model_select_logic'; +import { ModelSelectOption, ModelSelectOptionProps } from './model_select_option'; +import { normalizeModelName } from './utils'; + +export const ModelSelect: React.FC = () => { + const { indexName } = useValues(IndexNameLogic); + const { ingestionMethod } = useValues(IndexViewLogic); + const { + addInferencePipelineModal: { configuration }, + } = useValues(MLInferenceLogic); + const { selectableModels, isLoading } = useValues(ModelSelectLogic); + const { setInferencePipelineConfiguration } = useActions(MLInferenceLogic); + + const { modelID, pipelineName, isPipelineNameUserSupplied } = configuration; + + const getModelSelectOptionProps = (models: MlModel[]): ModelSelectOptionProps[] => + (models ?? []).map((model) => ({ + ...model, + label: model.modelId, + checked: model.modelId === modelID ? 'on' : undefined, + })); + + const onChange = (options: ModelSelectOptionProps[]) => { + const selectedOption = options.find((option) => option.checked === 'on'); + setInferencePipelineConfiguration({ + ...configuration, + inferenceConfig: undefined, + modelID: selectedOption?.modelId ?? '', + fieldMappings: undefined, + pipelineName: isPipelineNameUserSupplied + ? pipelineName + : indexName + '-' + normalizeModelName(selectedOption?.modelId ?? ''), + }); + }; + + const renderOption = (option: ModelSelectOptionProps) => ; + + return ( + + {(list, search) => ( + <> + {search} + {list} + + )} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.test.ts new file mode 100644 index 000000000000..1252d77bb776 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.test.ts @@ -0,0 +1,160 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../../../__mocks__/kea_logic'; + +import { HttpError } from '../../../../../../../common/types/api'; +import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml'; +import { CachedFetchModelsApiLogic } from '../../../../api/ml_models/cached_fetch_models_api_logic'; +import { + CreateModelApiLogic, + CreateModelResponse, +} from '../../../../api/ml_models/create_model_api_logic'; +import { StartModelApiLogic } from '../../../../api/ml_models/start_model_api_logic'; + +import { ModelSelectLogic } from './model_select_logic'; + +const CREATE_MODEL_API_RESPONSE: CreateModelResponse = { + modelId: 'model_1', + deploymentState: MlModelDeploymentState.NotDeployed, +}; +const FETCH_MODELS_API_DATA_RESPONSE: MlModel[] = [ + { + modelId: 'model_1', + title: 'Model 1', + type: 'ner', + deploymentState: MlModelDeploymentState.NotDeployed, + startTime: 0, + targetAllocationCount: 0, + nodeAllocationCount: 0, + threadsPerAllocation: 0, + isPlaceholder: false, + hasStats: false, + }, +]; + +describe('ModelSelectLogic', () => { + const { mount } = new LogicMounter(ModelSelectLogic); + const { mount: mountCreateModelApiLogic } = new LogicMounter(CreateModelApiLogic); + const { mount: mountCachedFetchModelsApiLogic } = new LogicMounter(CachedFetchModelsApiLogic); + const { mount: mountStartModelApiLogic } = new LogicMounter(StartModelApiLogic); + + beforeEach(() => { + jest.clearAllMocks(); + mountCreateModelApiLogic(); + mountCachedFetchModelsApiLogic(); + mountStartModelApiLogic(); + mount(); + }); + + describe('listeners', () => { + describe('createModel', () => { + it('creates the model', () => { + const modelId = 'model_1'; + jest.spyOn(ModelSelectLogic.actions, 'createModelMakeRequest'); + + ModelSelectLogic.actions.createModel(modelId); + + expect(ModelSelectLogic.actions.createModelMakeRequest).toHaveBeenCalledWith({ modelId }); + }); + }); + + describe('createModelSuccess', () => { + it('starts polling models', () => { + jest.spyOn(ModelSelectLogic.actions, 'startPollingModels'); + + ModelSelectLogic.actions.createModelSuccess(CREATE_MODEL_API_RESPONSE); + + expect(ModelSelectLogic.actions.startPollingModels).toHaveBeenCalled(); + }); + }); + + describe('fetchModels', () => { + it('makes fetch models request', () => { + jest.spyOn(ModelSelectLogic.actions, 'fetchModelsMakeRequest'); + + ModelSelectLogic.actions.fetchModels(); + + expect(ModelSelectLogic.actions.fetchModelsMakeRequest).toHaveBeenCalled(); + }); + }); + + describe('startModel', () => { + it('makes start model request', () => { + const modelId = 'model_1'; + jest.spyOn(ModelSelectLogic.actions, 'startModelMakeRequest'); + + ModelSelectLogic.actions.startModel(modelId); + + expect(ModelSelectLogic.actions.startModelMakeRequest).toHaveBeenCalledWith({ modelId }); + }); + }); + + describe('startModelSuccess', () => { + it('starts polling models', () => { + jest.spyOn(ModelSelectLogic.actions, 'startPollingModels'); + + ModelSelectLogic.actions.startModelSuccess(CREATE_MODEL_API_RESPONSE); + + expect(ModelSelectLogic.actions.startPollingModels).toHaveBeenCalled(); + }); + }); + }); + + describe('selectors', () => { + describe('areActionButtonsDisabled', () => { + it('is set to false if create and start APIs are idle', () => { + CreateModelApiLogic.actions.apiReset(); + StartModelApiLogic.actions.apiReset(); + + expect(ModelSelectLogic.values.areActionButtonsDisabled).toBe(false); + }); + it('is set to true if create API is making a request', () => { + CreateModelApiLogic.actions.makeRequest({ modelId: 'model_1' }); + + expect(ModelSelectLogic.values.areActionButtonsDisabled).toBe(true); + }); + it('is set to true if start API is making a request', () => { + StartModelApiLogic.actions.makeRequest({ modelId: 'model_1' }); + + expect(ModelSelectLogic.values.areActionButtonsDisabled).toBe(true); + }); + }); + + describe('modelStateChangeError', () => { + it('gets error from API error response', () => { + const error = { + body: { + error: 'some-error', + message: 'some-error-message', + statusCode: 500, + }, + } as HttpError; + + StartModelApiLogic.actions.apiError(error); + + expect(ModelSelectLogic.values.modelStateChangeError).toEqual('some-error-message'); + }); + }); + + describe('selectableModels', () => { + it('gets models data from API response', () => { + CachedFetchModelsApiLogic.actions.apiSuccess(FETCH_MODELS_API_DATA_RESPONSE); + + expect(ModelSelectLogic.values.selectableModels).toEqual(FETCH_MODELS_API_DATA_RESPONSE); + }); + }); + + describe('isLoading', () => { + it('is set to true if the fetch API is loading the first time', () => { + CachedFetchModelsApiLogic.actions.apiReset(); + + expect(ModelSelectLogic.values.isLoading).toBe(true); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts new file mode 100644 index 000000000000..5cfa2148203e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { HttpError, Status } from '../../../../../../../common/types/api'; +import { MlModel } from '../../../../../../../common/types/ml'; +import { getErrorsFromHttpResponse } from '../../../../../shared/flash_messages/handle_api_errors'; +import { + CachedFetchModelsApiLogic, + CachedFetchModlesApiLogicActions, +} from '../../../../api/ml_models/cached_fetch_models_api_logic'; +import { + CreateModelApiLogic, + CreateModelApiLogicActions, +} from '../../../../api/ml_models/create_model_api_logic'; +import { FetchModelsApiResponse } from '../../../../api/ml_models/fetch_models_api_logic'; +import { + StartModelApiLogic, + StartModelApiLogicActions, +} from '../../../../api/ml_models/start_model_api_logic'; + +export interface ModelSelectActions { + createModel: (modelId: string) => { modelId: string }; + createModelError: CreateModelApiLogicActions['apiError']; + createModelMakeRequest: CreateModelApiLogicActions['makeRequest']; + createModelSuccess: CreateModelApiLogicActions['apiSuccess']; + + fetchModels: () => void; + fetchModelsError: CachedFetchModlesApiLogicActions['apiError']; + fetchModelsMakeRequest: CachedFetchModlesApiLogicActions['makeRequest']; + fetchModelsSuccess: CachedFetchModlesApiLogicActions['apiSuccess']; + startPollingModels: CachedFetchModlesApiLogicActions['startPolling']; + + startModel: (modelId: string) => { modelId: string }; + startModelError: CreateModelApiLogicActions['apiError']; + startModelMakeRequest: StartModelApiLogicActions['makeRequest']; + startModelSuccess: StartModelApiLogicActions['apiSuccess']; +} + +export interface ModelSelectValues { + areActionButtonsDisabled: boolean; + createModelError: HttpError | undefined; + createModelStatus: Status; + isLoading: boolean; + isInitialLoading: boolean; + modelStateChangeError: string | undefined; + modelsData: FetchModelsApiResponse | undefined; + modelsStatus: Status; + selectableModels: MlModel[]; + startModelError: HttpError | undefined; + startModelStatus: Status; +} + +export const ModelSelectLogic = kea>({ + actions: { + createModel: (modelId: string) => ({ modelId }), + fetchModels: true, + startModel: (modelId: string) => ({ modelId }), + }, + connect: { + actions: [ + CreateModelApiLogic, + [ + 'makeRequest as createModelMakeRequest', + 'apiSuccess as createModelSuccess', + 'apiError as createModelError', + ], + CachedFetchModelsApiLogic, + [ + 'makeRequest as fetchModelsMakeRequest', + 'apiSuccess as fetchModelsSuccess', + 'apiError as fetchModelsError', + 'startPolling as startPollingModels', + ], + StartModelApiLogic, + [ + 'makeRequest as startModelMakeRequest', + 'apiSuccess as startModelSuccess', + 'apiError as startModelError', + ], + ], + values: [ + CreateModelApiLogic, + ['status as createModelStatus', 'error as createModelError'], + CachedFetchModelsApiLogic, + ['modelsData', 'status as modelsStatus', 'isInitialLoading'], + StartModelApiLogic, + ['status as startModelStatus', 'error as startModelError'], + ], + }, + events: ({ actions }) => ({ + afterMount: () => { + actions.startPollingModels(); + }, + }), + listeners: ({ actions }) => ({ + createModel: ({ modelId }) => { + actions.createModelMakeRequest({ modelId }); + }, + createModelSuccess: () => { + actions.startPollingModels(); + }, + fetchModels: () => { + actions.fetchModelsMakeRequest({}); + }, + startModel: ({ modelId }) => { + actions.startModelMakeRequest({ modelId }); + }, + startModelSuccess: () => { + actions.startPollingModels(); + }, + }), + path: ['enterprise_search', 'content', 'model_select_logic'], + selectors: ({ selectors }) => ({ + areActionButtonsDisabled: [ + () => [selectors.createModelStatus, selectors.startModelStatus], + (createModelStatus: Status, startModelStatus: Status) => + createModelStatus === Status.LOADING || startModelStatus === Status.LOADING, + ], + modelStateChangeError: [ + () => [selectors.createModelError, selectors.startModelError], + (createModelError?: HttpError, startModelError?: HttpError) => { + if (!createModelError && !startModelError) return undefined; + + return getErrorsFromHttpResponse(createModelError ?? startModelError!)[0]; + }, + ], + selectableModels: [ + () => [selectors.modelsData], + (response: FetchModelsApiResponse) => response ?? [], + ], + isLoading: [() => [selectors.isInitialLoading], (isInitialLoading) => isInitialLoading], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx new file mode 100644 index 000000000000..411bb8947257 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiBadge, EuiText } from '@elastic/eui'; + +import { MlModelDeploymentState } from '../../../../../../../common/types/ml'; +import { TrainedModelHealth } from '../ml_model_health'; + +import { + DeployModelButton, + getContextMenuPanel, + ModelSelectOption, + ModelSelectOptionProps, + StartModelButton, +} from './model_select_option'; + +const DEFAULT_PROPS: ModelSelectOptionProps = { + modelId: 'model_1', + type: 'ner', + label: 'Model 1', + title: 'Model 1', + description: 'Model 1 description', + license: 'elastic', + deploymentState: MlModelDeploymentState.NotDeployed, + startTime: 0, + targetAllocationCount: 0, + nodeAllocationCount: 0, + threadsPerAllocation: 0, + isPlaceholder: false, + hasStats: false, +}; + +describe('ModelSelectOption', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues({}); + }); + it('renders with license badge if present', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiBadge)).toHaveLength(1); + }); + it('renders without license badge if not present', () => { + const props = { + ...DEFAULT_PROPS, + license: undefined, + }; + + const wrapper = shallow(); + expect(wrapper.find(EuiBadge)).toHaveLength(0); + }); + it('renders with description if present', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiText)).toHaveLength(1); + }); + it('renders without description if not present', () => { + const props = { + ...DEFAULT_PROPS, + description: undefined, + }; + + const wrapper = shallow(); + expect(wrapper.find(EuiText)).toHaveLength(0); + }); + it('renders deploy button for a model placeholder', () => { + const props = { + ...DEFAULT_PROPS, + isPlaceholder: true, + }; + + const wrapper = shallow(); + expect(wrapper.find(DeployModelButton)).toHaveLength(1); + }); + it('renders start button for a downloaded model', () => { + const props = { + ...DEFAULT_PROPS, + deploymentState: MlModelDeploymentState.Downloaded, + }; + + const wrapper = shallow(); + expect(wrapper.find(StartModelButton)).toHaveLength(1); + }); + it('renders status badge if there is no action button', () => { + const wrapper = shallow(); + expect(wrapper.find(TrainedModelHealth)).toHaveLength(1); + }); + + describe('getContextMenuPanel', () => { + it('gets model details link if URL is present', () => { + const panels = getContextMenuPanel('https://model.ai'); + expect(panels[0].items).toHaveLength(2); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx index a9efa4064454..3133dc6feb3b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx @@ -5,55 +5,250 @@ * 2.0. */ -import React from 'react'; +import React, { useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiTextColor, EuiTitle } from '@elastic/eui'; +import { useActions, useValues } from 'kea'; import { - getMlModelTypesForModelConfig, - parseModelStateFromStats, - parseModelStateReasonFromStats, -} from '../../../../../../../common/ml_inference_pipeline'; -import { TrainedModel } from '../../../../api/ml_models/ml_trained_models_logic'; -import { getMLType, getModelDisplayTitle } from '../../../shared/ml_inference/utils'; + EuiBadge, + EuiButton, + EuiButtonEmpty, + EuiButtonIcon, + EuiContextMenu, + EuiContextMenuPanelDescriptor, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiRadio, + EuiText, + EuiTextColor, + EuiTitle, + useIsWithinMaxBreakpoint, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml'; +import { KibanaLogic } from '../../../../../shared/kibana'; import { TrainedModelHealth } from '../ml_model_health'; -import { MLModelTypeBadge } from '../ml_model_type_badge'; - -export interface MlModelSelectOptionProps { - model: TrainedModel; -} -export const MlModelSelectOption: React.FC = ({ model }) => { - const type = getMLType(getMlModelTypesForModelConfig(model)); - const title = getModelDisplayTitle(type); + +import { ModelSelectLogic } from './model_select_logic'; +import { TRAINED_MODELS_PATH } from './utils'; + +export const getContextMenuPanel = ( + modelDetailsPageUrl?: string +): EuiContextMenuPanelDescriptor[] => { + return [ + { + id: 0, + items: [ + { + name: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.actionMenu.tuneModelPerformance.label', + { + defaultMessage: 'Tune model performance', + } + ), + icon: 'controlsHorizontal', + onClick: () => + KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, { + shouldNotCreateHref: true, + }), + }, + ...(modelDetailsPageUrl + ? [ + { + name: i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.actionMenu.modelDetails.label', + { + defaultMessage: 'Model details', + } + ), + icon: 'popout', + href: modelDetailsPageUrl, + target: '_blank', + }, + ] + : []), + ], + }, + ]; +}; + +export type ModelSelectOptionProps = MlModel & { + label: string; + checked?: 'on'; +}; + +export const DeployModelButton: React.FC<{ onClick: () => void; disabled: boolean }> = ({ + onClick, + disabled, +}) => { return ( - - - -

    {title ?? model.model_id}

    -
    + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.deployButton.label', + { + defaultMessage: 'Deploy', + } + )} + + ); +}; + +export const StartModelButton: React.FC<{ onClick: () => void; disabled: boolean }> = ({ + onClick, + disabled, +}) => { + return ( + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.startButton.label', + { + defaultMessage: 'Start', + } + )} + + ); +}; + +export const ModelMenuPopover: React.FC<{ + onClick: () => void; + closePopover: () => void; + isOpen: boolean; + modelDetailsPageUrl?: string; +}> = ({ onClick, closePopover, isOpen, modelDetailsPageUrl }) => { + return ( + + } + isOpen={isOpen} + closePopover={closePopover} + anchorPosition="leftCenter" + panelPaddingSize="none" + > + + + ); +}; + +export const ModelSelectOption: React.FC = ({ + modelId, + title, + description, + license, + deploymentState, + deploymentStateReason, + modelDetailsPageUrl, + isPlaceholder, + checked, +}) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const onMenuButtonClick = () => setIsPopoverOpen((isOpen) => !isOpen); + const closePopover = () => setIsPopoverOpen(false); + + const { createModel, startModel } = useActions(ModelSelectLogic); + const { areActionButtonsDisabled } = useValues(ModelSelectLogic); + + return ( + + {/* Selection radio button */} + + null} + // @ts-ignore + inert + /> - - - {title && ( + {/* Title, model ID, description, license */} + + + + +

    {title}

    +
    +
    + + {modelId} + + {(license || description) && ( - {model.model_id} + + {license && ( + + {/* Wrap in a div to prevent the badge from growing to a whole row on mobile */} +
    + + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.licenseBadge.label', + { + defaultMessage: 'License: {license}', + values: { + license, + }, + } + )} + +
    +
    + )} + {description && ( + + +
    + {description} +
    +
    +
    + )} +
    )} - +
    +
    + {/* Status indicator OR action button */} + + {/* Wrap in a div to prevent the badge/button from growing to a whole row on mobile */} +
    + {isPlaceholder ? ( + createModel(modelId)} + disabled={areActionButtonsDisabled} + /> + ) : deploymentState === MlModelDeploymentState.Downloaded ? ( + startModel(modelId)} + disabled={areActionButtonsDisabled} + /> + ) : ( - - - - - - - - - + )} +
    +
    + {/* Actions menu */} + +
    ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.test.tsx deleted file mode 100644 index c98ca42a4112..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.test.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setMockValues } from '../../../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiText } from '@elastic/eui'; - -import { ModelStarted } from './model_started'; -import { TextExpansionDismissButton, FineTuneModelsButton } from './text_expansion_callout'; - -const DEFAULT_VALUES = { - startTextExpansionModelError: undefined, - isCreateButtonDisabled: false, - isModelDownloadInProgress: false, - isModelDownloaded: false, - isModelStarted: false, - isStartButtonDisabled: false, -}; - -describe('ModelStarted', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(DEFAULT_VALUES); - }); - it('renders dismiss button if it is set to dismissable', () => { - const wrapper = shallow( - {}} isCompact={false} isDismissable isSingleThreaded /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); - }); - it('does not render dismiss button if it is set to non-dismissable', () => { - const wrapper = shallow( - {}} isCompact={false} isDismissable={false} isSingleThreaded /> - ); - expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); - }); - it('renders fine-tune button if the model is running single-threaded', () => { - const wrapper = shallow( - {}} isCompact={false} isDismissable isSingleThreaded /> - ); - expect(wrapper.find(FineTuneModelsButton).length).toBe(1); - }); - it('does not render description if it is set to compact', () => { - const wrapper = shallow( - {}} isCompact isDismissable isSingleThreaded /> - ); - expect(wrapper.find(EuiText).length).toBe(1); // Title only - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx deleted file mode 100644 index fa5a46d43804..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiText, - EuiButtonEmpty, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -import { KibanaLogic } from '../../../../../shared/kibana'; - -import { - TextExpansionCallOutState, - TextExpansionDismissButton, - FineTuneModelsButton, -} from './text_expansion_callout'; -import { TRAINED_MODELS_PATH } from './utils'; - -export const ModelStarted = ({ - dismiss, - isCompact, - isDismissable, - isSingleThreaded, -}: Pick< - TextExpansionCallOutState, - 'dismiss' | 'isCompact' | 'isDismissable' | 'isSingleThreaded' ->) => ( - - - - - - - - - -

    - {isSingleThreaded - ? isCompact - ? i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitleCompact', - { defaultMessage: 'Your ELSER v2 model is running single-threaded.' } - ) - : i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitle', - { defaultMessage: 'Your ELSER v2 model has started single-threaded.' } - ) - : isCompact - ? i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitleCompact', - { defaultMessage: 'Your ELSER v2 model is running.' } - ) - : i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitle', - { defaultMessage: 'Your ELSER v2 model has started.' } - )} -

    -
    -
    - {isDismissable && ( - - - - )} -
    -
    - {!isCompact && ( - <> - - -

    - {isSingleThreaded - ? i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedBody', - { - defaultMessage: - 'This single-threaded configuration is great for testing your custom inference pipelines, however performance should be fine-tuned for production.', - } - ) - : i18n.translate( - 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedBody', - { - defaultMessage: - 'Enjoy the power of ELSER v2 in your custom Inference pipeline.', - } - )} -

    -
    -
    - - - - {isSingleThreaded ? ( - - ) : ( - - KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, { - shouldNotCreateHref: true, - }) - } - > - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.viewModelsButton', - { - defaultMessage: 'View details', - } - )} - - )} - - - - - )} -
    -
    -); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.test.tsx new file mode 100644 index 000000000000..6e5e2cb3fbbb --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +import { DeployModel } from './deploy_model'; +import { TextExpansionDismissButton } from './text_expansion_callout'; + +const DEFAULT_VALUES = { + startTextExpansionModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('DeployModel', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders deploy button', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(false); + }); + it('renders disabled deploy button if it is set to disabled', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled + isDismissable={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(true); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable + /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isCreateButtonDisabled={false} + isDismissable={false} + /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.tsx new file mode 100644 index 000000000000..74ce840252a8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/deploy_model.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions } from 'kea'; + +import { + EuiBadge, + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedHTMLMessage, FormattedMessage } from '@kbn/i18n-react'; + +import { docLinks } from '../../../../../../shared/doc_links'; + +import { TextExpansionCallOutState, TextExpansionDismissButton } from './text_expansion_callout'; +import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; + +export const DeployModel = ({ + dismiss, + ingestionMethod, + isCreateButtonDisabled, + isDismissable, +}: Pick< + TextExpansionCallOutState, + 'dismiss' | 'ingestionMethod' | 'isCreateButtonDisabled' | 'isDismissable' +>) => { + const { createTextExpansionModel } = useActions(TextExpansionCalloutLogic); + + return ( + + + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title', + { defaultMessage: 'Improve your results with ELSER' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + + + + + + + + + + createTextExpansionModel()} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.deployButton.label', + { + defaultMessage: 'Deploy', + } + )} + + + + + + + + + + + +
    +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.test.tsx new file mode 100644 index 000000000000..84172ce34ccc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +import { ModelDeployed } from './model_deployed'; +import { TextExpansionDismissButton } from './text_expansion_callout'; + +const DEFAULT_VALUES = { + startTextExpansionModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelDeployed', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders start button', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(false); + }); + it('renders disabled start button if it is set to disabled', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled + /> + ); + expect(wrapper.find(EuiButton).length).toBe(1); + const button = wrapper.find(EuiButton); + expect(button.prop('disabled')).toBe(true); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} + ingestionMethod="crawler" + isDismissable={false} + isStartButtonDisabled={false} + /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.tsx new file mode 100644 index 000000000000..fe8f0b7953c7 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployed.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions } from 'kea'; + +import { + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { + TextExpansionCallOutState, + TextExpansionDismissButton, + FineTuneModelsButton, +} from './text_expansion_callout'; +import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; + +export const ModelDeployed = ({ + dismiss, + ingestionMethod, + isDismissable, + isStartButtonDisabled, +}: Pick< + TextExpansionCallOutState, + 'dismiss' | 'ingestionMethod' | 'isDismissable' | 'isStartButtonDisabled' +>) => { + const { startTextExpansionModel } = useActions(TextExpansionCalloutLogic); + + return ( + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedTitle', + { defaultMessage: 'Your ELSER model has deployed but not started.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedBody', + { + defaultMessage: + 'You may start the model in a single-threaded configuration for testing, or tune the performance for a production environment.', + } + )} +

    +
    +
    + + + + + + + startTextExpansionModel()} + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.startModelButton.label', + { + defaultMessage: 'Start single-threaded', + } + )} + + + + + + + +
    +
    + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.test.tsx new file mode 100644 index 000000000000..e2493fad0e4c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.test.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { ModelDeploymentInProgress } from './model_deployment_in_progress'; +import { TextExpansionDismissButton } from './text_expansion_callout'; + +const DEFAULT_VALUES = { + startTextExpansionModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelDeploymentInProgress', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( {}} isDismissable />); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( {}} isDismissable={false} />); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.tsx new file mode 100644 index 000000000000..f9b943983325 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_deployment_in_progress.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { TextExpansionCallOutState, TextExpansionDismissButton } from './text_expansion_callout'; + +export const ModelDeploymentInProgress = ({ + dismiss, + isDismissable, +}: Pick) => ( + + + + + + + + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingTitle', + { defaultMessage: 'Your ELSER model is deploying.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + + +

    + {i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingBody', + { + defaultMessage: + 'You can continue creating your pipeline with other uploaded models in the meantime.', + } + )} +

    +
    +
    +
    +
    +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.test.tsx new file mode 100644 index 000000000000..e5bf09b61e41 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiText } from '@elastic/eui'; + +import { ModelStarted } from './model_started'; +import { TextExpansionDismissButton, FineTuneModelsButton } from './text_expansion_callout'; + +const DEFAULT_VALUES = { + startTextExpansionModelError: undefined, + isCreateButtonDisabled: false, + isModelDownloadInProgress: false, + isModelDownloaded: false, + isModelStarted: false, + isStartButtonDisabled: false, +}; + +describe('ModelStarted', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + }); + it('renders dismiss button if it is set to dismissable', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable isSingleThreaded /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(1); + }); + it('does not render dismiss button if it is set to non-dismissable', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable={false} isSingleThreaded /> + ); + expect(wrapper.find(TextExpansionDismissButton).length).toBe(0); + }); + it('renders fine-tune button if the model is running single-threaded', () => { + const wrapper = shallow( + {}} isCompact={false} isDismissable isSingleThreaded /> + ); + expect(wrapper.find(FineTuneModelsButton).length).toBe(1); + }); + it('does not render description if it is set to compact', () => { + const wrapper = shallow( + {}} isCompact isDismissable isSingleThreaded /> + ); + expect(wrapper.find(EuiText).length).toBe(1); // Title only + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.tsx new file mode 100644 index 000000000000..1a15b8e96ab3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/model_started.tsx @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiText, + EuiButtonEmpty, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { KibanaLogic } from '../../../../../../shared/kibana'; + +import { TRAINED_MODELS_PATH } from '../utils'; + +import { + TextExpansionCallOutState, + TextExpansionDismissButton, + FineTuneModelsButton, +} from './text_expansion_callout'; + +export const ModelStarted = ({ + dismiss, + isCompact, + isDismissable, + isSingleThreaded, +}: Pick< + TextExpansionCallOutState, + 'dismiss' | 'isCompact' | 'isDismissable' | 'isSingleThreaded' +>) => ( + + + + + + + + + +

    + {isSingleThreaded + ? isCompact + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitleCompact', + { defaultMessage: 'Your ELSER model is running single-threaded.' } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitle', + { defaultMessage: 'Your ELSER model has started single-threaded.' } + ) + : isCompact + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitleCompact', + { defaultMessage: 'Your ELSER model is running.' } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitle', + { defaultMessage: 'Your ELSER model has started.' } + )} +

    +
    +
    + {isDismissable && ( + + + + )} +
    +
    + {!isCompact && ( + <> + + +

    + {isSingleThreaded + ? i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedBody', + { + defaultMessage: + 'This single-threaded configuration is great for testing your custom inference pipelines, however performance should be fine-tuned for production.', + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedBody', + { + defaultMessage: + 'Enjoy the power of ELSER in your custom Inference pipeline.', + } + )} +

    +
    +
    + + + + {isSingleThreaded ? ( + + ) : ( + + KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, { + shouldNotCreateHref: true, + }) + } + > + {i18n.translate( + 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.viewModelsButton', + { + defaultMessage: 'View details', + } + )} + + )} + + + + + )} +
    +
    +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.test.tsx similarity index 97% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.test.tsx index 1ef7480b25c8..4abd583e4a79 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { setMockValues } from '../../../../../__mocks__/kea_logic'; +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; import React from 'react'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.tsx similarity index 95% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.tsx index 310f8f273a2c..1ea2c63ccaaa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout.tsx @@ -12,8 +12,10 @@ import { useValues } from 'kea'; import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { KibanaLogic } from '../../../../../shared/kibana'; -import { IndexViewLogic } from '../../index_view_logic'; +import { KibanaLogic } from '../../../../../../shared/kibana'; +import { IndexViewLogic } from '../../../index_view_logic'; + +import { TRAINED_MODELS_PATH } from '../utils'; import { DeployModel } from './deploy_model'; import { ModelDeployed } from './model_deployed'; @@ -22,7 +24,6 @@ import { ModelStarted } from './model_started'; import { useTextExpansionCallOutData } from './text_expansion_callout_data'; import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; import { TextExpansionErrors } from './text_expansion_errors'; -import { TRAINED_MODELS_PATH } from './utils'; export interface TextExpansionCallOutState { dismiss: () => void; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_data.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_data.tsx similarity index 96% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_data.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_data.tsx index 849bcd7964f7..4cddec9b7d2d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_data.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_data.tsx @@ -9,7 +9,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useValues } from 'kea'; -import { IndexViewLogic } from '../../index_view_logic'; +import { IndexViewLogic } from '../../../index_view_logic'; import { TextExpansionCallOutProps, TextExpansionCallOutState } from './text_expansion_callout'; import { TextExpansionCalloutLogic } from './text_expansion_callout_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.test.ts similarity index 94% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.test.ts index e39230ee2b69..1380e05e4c57 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.test.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { LogicMounter } from '../../../../../__mocks__/kea_logic'; +import { LogicMounter } from '../../../../../../__mocks__/kea_logic'; import { HttpResponse } from '@kbn/core/public'; -import { ErrorResponse, HttpError, Status } from '../../../../../../../common/types/api'; -import { MlModelDeploymentState } from '../../../../../../../common/types/ml'; -import { CreateTextExpansionModelApiLogic } from '../../../../api/ml_models/text_expansion/create_text_expansion_model_api_logic'; -import { FetchTextExpansionModelApiLogic } from '../../../../api/ml_models/text_expansion/fetch_text_expansion_model_api_logic'; -import { StartTextExpansionModelApiLogic } from '../../../../api/ml_models/text_expansion/start_text_expansion_model_api_logic'; +import { ErrorResponse, HttpError, Status } from '../../../../../../../../common/types/api'; +import { MlModelDeploymentState } from '../../../../../../../../common/types/ml'; +import { CreateTextExpansionModelApiLogic } from '../../../../../api/ml_models/text_expansion/create_text_expansion_model_api_logic'; +import { FetchTextExpansionModelApiLogic } from '../../../../../api/ml_models/text_expansion/fetch_text_expansion_model_api_logic'; +import { StartTextExpansionModelApiLogic } from '../../../../../api/ml_models/text_expansion/start_text_expansion_model_api_logic'; import { getTextExpansionError, @@ -80,19 +80,19 @@ describe('TextExpansionCalloutLogic', () => { }); it('uses the correct title and message from a create error', () => { expect(getTextExpansionError(error, undefined, undefined)).toEqual({ - title: 'Error with ELSER v2 deployment', + title: 'Error with ELSER deployment', message: error.body?.message, }); }); it('uses the correct title and message from a fetch error', () => { expect(getTextExpansionError(undefined, error, undefined)).toEqual({ - title: 'Error fetching ELSER v2 model', + title: 'Error fetching ELSER model', message: error.body?.message, }); }); it('uses the correct title and message from a start error', () => { expect(getTextExpansionError(undefined, undefined, error)).toEqual({ - title: 'Error starting ELSER v2 deployment', + title: 'Error starting ELSER deployment', message: error.body?.message, }); }); @@ -303,7 +303,7 @@ describe('TextExpansionCalloutLogic', () => { describe('textExpansionError', () => { const error = { body: { - error: 'Error with ELSER v2 deployment', + error: 'Error with ELSER deployment', message: 'Mocked error message', statusCode: 500, }, @@ -318,21 +318,21 @@ describe('TextExpansionCalloutLogic', () => { it('returns extracted error for create', () => { CreateTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error with ELSER v2 deployment', + title: 'Error with ELSER deployment', message: 'Mocked error message', }); }); it('returns extracted error for fetch', () => { FetchTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error fetching ELSER v2 model', + title: 'Error fetching ELSER model', message: 'Mocked error message', }); }); it('returns extracted error for start', () => { StartTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error starting ELSER v2 deployment', + title: 'Error starting ELSER deployment', message: 'Mocked error message', }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.ts similarity index 93% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.ts index e8e6913c38ce..35544bc5d568 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_callout_logic.ts @@ -9,26 +9,26 @@ import { kea, MakeLogicType } from 'kea'; import { i18n } from '@kbn/i18n'; -import { HttpError, Status } from '../../../../../../../common/types/api'; -import { MlModelDeploymentState } from '../../../../../../../common/types/ml'; -import { getErrorsFromHttpResponse } from '../../../../../shared/flash_messages/handle_api_errors'; +import { HttpError, Status } from '../../../../../../../../common/types/api'; +import { MlModelDeploymentState } from '../../../../../../../../common/types/ml'; +import { getErrorsFromHttpResponse } from '../../../../../../shared/flash_messages/handle_api_errors'; -import { KibanaLogic } from '../../../../../shared/kibana'; +import { KibanaLogic } from '../../../../../../shared/kibana'; import { CreateTextExpansionModelApiLogic, CreateTextExpansionModelApiLogicActions, CreateTextExpansionModelResponse, -} from '../../../../api/ml_models/text_expansion/create_text_expansion_model_api_logic'; +} from '../../../../../api/ml_models/text_expansion/create_text_expansion_model_api_logic'; import { FetchTextExpansionModelApiLogic, FetchTextExpansionModelApiLogicActions, FetchTextExpansionModelResponse, -} from '../../../../api/ml_models/text_expansion/fetch_text_expansion_model_api_logic'; +} from '../../../../../api/ml_models/text_expansion/fetch_text_expansion_model_api_logic'; import { StartTextExpansionModelApiLogic, StartTextExpansionModelApiLogicActions, -} from '../../../../api/ml_models/text_expansion/start_text_expansion_model_api_logic'; +} from '../../../../../api/ml_models/text_expansion/start_text_expansion_model_api_logic'; const FETCH_TEXT_EXPANSION_MODEL_POLLING_DURATION = 5000; // 5 seconds const FETCH_TEXT_EXPANSION_MODEL_POLLING_DURATION_ON_FAILURE = 30000; // 30 seconds @@ -97,7 +97,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCreateError.title', { - defaultMessage: 'Error with ELSER v2 deployment', + defaultMessage: 'Error with ELSER deployment', } ), message: getErrorsFromHttpResponse(createError)[0], @@ -107,7 +107,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionStartError.title', { - defaultMessage: 'Error starting ELSER v2 deployment', + defaultMessage: 'Error starting ELSER deployment', } ), message: getErrorsFromHttpResponse(startError)[0], @@ -117,7 +117,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionFetchError.title', { - defaultMessage: 'Error fetching ELSER v2 model', + defaultMessage: 'Error fetching ELSER model', } ), message: getErrorsFromHttpResponse(fetchError)[0], @@ -179,7 +179,7 @@ export const TextExpansionCalloutLogic = kea< afterMount: async () => { const elserModel = await KibanaLogic.values.ml.elasticModels?.getELSER({ version: 2 }); if (elserModel != null) { - actions.setElserModelId(elserModel.name); + actions.setElserModelId(elserModel.model_id); actions.fetchTextExpansionModel(); } }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.test.tsx similarity index 93% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.test.tsx index cb15c2c5c541..2a7a6ea610bd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { setMockValues } from '../../../../../__mocks__/kea_logic'; +import { setMockValues } from '../../../../../../__mocks__/kea_logic'; import React from 'react'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.tsx similarity index 84% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.tsx index a46105586af1..e55f6109c177 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_errors.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout/text_expansion_errors.tsx @@ -13,10 +13,10 @@ import { EuiCallOut, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { HttpLogic } from '../../../../../shared/http'; +import { HttpLogic } from '../../../../../../shared/http'; -import { SendEnterpriseSearchTelemetry } from '../../../../../shared/telemetry'; -import { ML_NOTIFICATIONS_PATH } from '../../../../routes'; +import { SendEnterpriseSearchTelemetry } from '../../../../../../shared/telemetry'; +import { ML_NOTIFICATIONS_PATH } from '../../../../../routes'; export const TextExpansionErrors = ({ error }: { error: { title: string; message: string } }) => { const { http } = useValues(HttpLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts index a9402e7e966b..3a645dcbba3b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/types.ts @@ -12,6 +12,7 @@ import { InferencePipelineInferenceConfig } from '../../../../../../../common/ty export interface InferencePipelineConfiguration { existingPipeline?: boolean; inferenceConfig?: InferencePipelineInferenceConfig; + isPipelineNameUserSupplied?: boolean; modelID: string; pipelineName: string; fieldMappings?: FieldMapping[]; @@ -27,7 +28,6 @@ export interface AddInferencePipelineFormErrors { export enum AddInferencePipelineSteps { Configuration, Fields, - Mappings, Test, Review, } diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.test.tsx deleted file mode 100644 index b615b7930130..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setMockValues } from '../../../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { EuiBasicTable } from '@elastic/eui'; - -import { - UpdateMappings, - UpdateMappingsAutomatic, - UpdateMappingsInstructions, -} from './update_mappings'; - -describe('UpdateMappings', () => { - const DEFAULT_VALUES = { - isTextExpansionModelSelected: false, - addInferencePipelineModal: { configuration: { existingPipeline: false } }, - }; - - beforeEach(() => { - jest.clearAllMocks(); - setMockValues(DEFAULT_VALUES); - }); - it('renders selected fields', () => { - const wrapper = shallow(); - expect(wrapper.find(EuiBasicTable)).toHaveLength(1); - }); - it('renders instructions if mappings need to be updated manually', () => { - const wrapper = shallow(); - expect(wrapper.find(UpdateMappingsInstructions)).toHaveLength(1); - }); - it('renders instructions when attaching existing pipeline', () => { - setMockValues({ - ...DEFAULT_VALUES, - addInferencePipelineModal: { configuration: { existingPipeline: true } }, - }); - const wrapper = shallow(); - expect(wrapper.find(UpdateMappingsInstructions)).toHaveLength(1); - }); - it('renders info panel if text expansion model is selected', () => { - setMockValues({ - ...DEFAULT_VALUES, - isTextExpansionModelSelected: true, - }); - const wrapper = shallow(); - expect(wrapper.find(UpdateMappingsAutomatic)).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.tsx deleted file mode 100644 index e8bf9f5cff5e..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/update_mappings.tsx +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { useValues } from 'kea'; - -import { - EuiFlexGroup, - EuiFlexItem, - EuiTitle, - EuiText, - EuiPanel, - EuiBasicTableColumn, - EuiBasicTable, - EuiCallOut, - EuiLink, -} from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; - -import { FieldMapping } from '../../../../../../../common/ml_inference_pipeline'; - -import { docLinks } from '../../../../../shared/doc_links'; - -import { MLInferenceLogic } from './ml_inference_logic'; - -export const UpdateMappingsInstructions: React.FC = () => ( - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.title', - { - defaultMessage: 'Update your index mappings', - } - )} -

    -
    -
    - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.description', - { - defaultMessage: - 'You must manually update your index mappings before you can start indexing documents through the pipeline.', - } - )} -

    -
    -
    - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.presentInMapping', - { - defaultMessage: - 'Make sure the selected inference output fields are present in the mapping.', - } - )} -

    -
    -
    - - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.docsLink', - { - defaultMessage: 'Learn more', - } - )} - - -
    -); - -export const UpdateMappingsAutomatic: React.FC = () => ( - - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.titleNoAction', - { - defaultMessage: 'Review index mapping updates', - } - )} -

    -
    -
    - - -

    - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.descriptionNoAction', - { - defaultMessage: - 'Your index mappings will automatically be updated to include the selected inference output fields.', - } - )} -

    -
    -
    - - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.docsLink', - { - defaultMessage: 'Learn more', - } - )} - - -
    -); - -export const UpdateMappings: React.FC = () => { - const { - addInferencePipelineModal: { configuration }, - isTextExpansionModelSelected, - } = useValues(MLInferenceLogic); - - const areMappingsAutoUpdated = isTextExpansionModelSelected && !configuration.existingPipeline; - - const columns: Array> = [ - { - field: 'targetField', - name: areMappingsAutoUpdated - ? i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappings', - { - defaultMessage: 'Field mappings', - } - ) - : i18n.translate( - 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappingsRequired', - { - defaultMessage: 'Required field mappings', - } - ), - }, - ]; - - return ( - <> - - - {areMappingsAutoUpdated ? : } - - - - - - - - - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.test.ts index fc39d2f429a2..4710564b695a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isValidPipelineName } from './utils'; +import { isValidPipelineName, normalizeModelName } from './utils'; describe('ml inference utils', () => { describe('isValidPipelineName', () => { @@ -24,4 +24,16 @@ describe('ml inference utils', () => { expect(isValidPipelineName('a_pipeline_name_1"')).toEqual(false); }); }); + describe('normalizeModelName', () => { + it('no normalization', () => { + expect(normalizeModelName('valid_model_name_123')).toEqual('valid_model_name_123'); + expect(normalizeModelName('valid-model-name-123')).toEqual('valid-model-name-123'); + }); + it('normalize model name', () => { + expect(normalizeModelName('.elser_model_2')).toEqual('_elser_model_2'); + expect(normalizeModelName('model!@with#$special%^chars&*123')).toEqual( + 'model__with__special__chars__123' + ); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts index d05b1453547b..02cf5a7463dd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/utils.ts @@ -12,6 +12,7 @@ import { FetchPipelineResponse } from '../../../../api/pipelines/fetch_pipeline' import { AddInferencePipelineFormErrors, InferencePipelineConfiguration } from './types'; const VALID_PIPELINE_NAME_REGEX = /^[\w\-]+$/; +const NORMALIZABLE_PIPELINE_CHARS_REGEX = /[^\w\-]/g; export const TRAINED_MODELS_PATH = '/app/ml/trained_models'; export const isValidPipelineName = (input: string): boolean => { @@ -79,6 +80,10 @@ export const validateInferencePipelineFields = ( return errors; }; +export const normalizeModelName = (modelName: string): string => { + return modelName.replace(NORMALIZABLE_PIPELINE_CHARS_REGEX, '_'); +}; + export const EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELDS = ( commaSeparatedMissingSourceFields: string ) => diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference_pipeline_processors_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference_pipeline_processors_card.tsx index 6d3ad46a985c..9aa4cebe878d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference_pipeline_processors_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference_pipeline_processors_card.tsx @@ -18,7 +18,8 @@ import { IndexNameLogic } from '../index_name_logic'; import { InferencePipelineCard } from './inference_pipeline_card'; import { AddMLInferencePipelineButton } from './ml_inference/add_ml_inference_button'; -import { TextExpansionCallOut } from './ml_inference/text_expansion_callout'; +import { E5MultilingualCallOut } from './ml_inference/e5_multilingual_callout/e5_multilingual_callout'; +import { TextExpansionCallOut } from './ml_inference/text_expansion_callout/text_expansion_callout'; import { PipelinesLogic } from './pipelines_logic'; export const MlInferencePipelineProcessorsCard: React.FC = () => { @@ -38,6 +39,7 @@ export const MlInferencePipelineProcessorsCard: React.FC = () => { return ( {hasMLPermissions && !isGated && } + {hasMLPermissions && !isGated && } openAddMlInferencePipelineModal()} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx index 47136ff90f79..65bfbc0951d3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx @@ -13,6 +13,7 @@ import { shallow } from 'enzyme'; import { EuiHealth } from '@elastic/eui'; +import { MlModelDeploymentState } from '../../../../../../common/types/ml'; import { InferencePipeline, TrainedModelState } from '../../../../../../common/types/pipelines'; import { TrainedModelHealth } from './ml_model_health'; @@ -30,6 +31,18 @@ describe('TrainedModelHealth', () => { pipelineReferences: [], types: ['pytorch'], }; + it('renders model downloading', () => { + const wrapper = shallow(); + const health = wrapper.find(EuiHealth); + expect(health.prop('children')).toEqual('Downloading'); + expect(health.prop('color')).toEqual('warning'); + }); + it('renders model downloaded', () => { + const wrapper = shallow(); + const health = wrapper.find(EuiHealth); + expect(health.prop('children')).toEqual('Downloaded'); + expect(health.prop('color')).toEqual('subdued'); + }); it('renders model started', () => { const pipeline: InferencePipeline = { ...commonModelData, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx index 45fd54b6bf4f..133582520deb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx @@ -12,8 +12,33 @@ import { EuiHealth, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { MlModelDeploymentState } from '../../../../../../common/types/ml'; import { TrainedModelState } from '../../../../../../common/types/pipelines'; +const modelDownloadingText = i18n.translate( + 'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloading', + { + defaultMessage: 'Downloading', + } +); +const modelDownloadingTooltip = i18n.translate( + 'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloading.tooltip', + { + defaultMessage: 'This trained model is downloading', + } +); +const modelDownloadedText = i18n.translate( + 'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloaded', + { + defaultMessage: 'Downloaded', + } +); +const modelDownloadedTooltip = i18n.translate( + 'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloaded.tooltip', + { + defaultMessage: 'This trained model is downloaded and can be started', + } +); const modelStartedText = i18n.translate( 'xpack.enterpriseSearch.inferencePipelineCard.modelState.started', { @@ -73,7 +98,7 @@ const modelNotDeployedTooltip = i18n.translate( ); export interface TrainedModelHealthProps { - modelState: TrainedModelState; + modelState: TrainedModelState | MlModelDeploymentState; modelStateReason?: string; } @@ -87,27 +112,52 @@ export const TrainedModelHealth: React.FC = ({ tooltipText: React.ReactNode; }; switch (modelState) { - case TrainedModelState.Started: + case TrainedModelState.NotDeployed: + case MlModelDeploymentState.NotDeployed: modelHealth = { - healthColor: 'success', - healthText: modelStartedText, - tooltipText: modelStartedTooltip, + healthColor: 'danger', + healthText: modelNotDeployedText, + tooltipText: modelNotDeployedTooltip, }; break; - case TrainedModelState.Stopping: + case MlModelDeploymentState.Downloading: modelHealth = { healthColor: 'warning', - healthText: modelStoppingText, - tooltipText: modelStoppingTooltip, + healthText: modelDownloadingText, + tooltipText: modelDownloadingTooltip, + }; + break; + case MlModelDeploymentState.Downloaded: + modelHealth = { + healthColor: 'subdued', + healthText: modelDownloadedText, + tooltipText: modelDownloadedTooltip, }; break; case TrainedModelState.Starting: + case MlModelDeploymentState.Starting: modelHealth = { healthColor: 'warning', healthText: modelStartingText, tooltipText: modelStartingTooltip, }; break; + case TrainedModelState.Started: + case MlModelDeploymentState.Started: + case MlModelDeploymentState.FullyAllocated: + modelHealth = { + healthColor: 'success', + healthText: modelStartedText, + tooltipText: modelStartedTooltip, + }; + break; + case TrainedModelState.Stopping: + modelHealth = { + healthColor: 'warning', + healthText: modelStoppingText, + tooltipText: modelStoppingTooltip, + }; + break; case TrainedModelState.Failed: modelHealth = { healthColor: 'danger', @@ -133,7 +183,7 @@ export const TrainedModelHealth: React.FC = ({ ), }; break; - case TrainedModelState.NotDeployed: + default: modelHealth = { healthColor: 'danger', healthText: modelNotDeployedText, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.test.tsx index c29790700c43..f9f38e7c1333 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.test.tsx @@ -14,8 +14,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiCallOut, EuiButton } from '@elastic/eui'; - import { AddContentEmptyPrompt } from '../../../shared/add_content_empty_prompt'; import { ElasticsearchResources } from '../../../shared/elasticsearch_resources'; import { GettingStartedSteps } from '../../../shared/getting_started_steps'; @@ -75,20 +73,6 @@ describe('SearchIndices', () => { expect(wrapper.find(ElasticsearchResources)).toHaveLength(0); expect(mockActions.fetchIndices).toHaveBeenCalled(); - expect(wrapper.find(EuiCallOut)).toHaveLength(1); - }); - - it('dismisses callout on click to button', () => { - setMockValues(mockValues); - setMockActions(mockActions); - - const wrapper = shallow(); - const dismissButton = wrapper.find(EuiCallOut).find(EuiButton); - expect(global.localStorage.getItem('enterprise-search-indices-callout-dismissed')).toBe( - 'false' - ); - dismissButton.simulate('click'); - expect(global.localStorage.getItem('enterprise-search-indices-callout-dismissed')).toBe('true'); }); // Move this test to the indices table when writing tests there diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx index 8e778228857e..beb91be46801 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx @@ -18,7 +18,6 @@ import { EuiTitle, EuiSwitch, EuiSearchBar, - EuiLink, EuiToolTip, EuiCode, } from '@elastic/eui'; @@ -27,14 +26,12 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { AddContentEmptyPrompt } from '../../../shared/add_content_empty_prompt'; -import { docLinks } from '../../../shared/doc_links'; import { ElasticsearchResources } from '../../../shared/elasticsearch_resources'; import { GettingStartedSteps } from '../../../shared/getting_started_steps'; import { HttpLogic } from '../../../shared/http/http_logic'; import { KibanaLogic } from '../../../shared/kibana'; import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers'; import { handlePageChange } from '../../../shared/table_pagination'; -import { useLocalStorage } from '../../../shared/use_local_storage'; import { NEW_INDEX_PATH } from '../../routes'; import { EnterpriseSearchContentPageTemplate } from '../layout/page_template'; @@ -62,11 +59,6 @@ export const SearchIndices: React.FC = () => { const { config } = useValues(KibanaLogic); const { errorConnectingMessage } = useValues(HttpLogic); - const [calloutDismissed, setCalloutDismissed] = useLocalStorage( - 'enterprise-search-indices-callout-dismissed', - false - ); - useEffect(() => { // We don't want to trigger loading for each search query change, so we need this // flag to set if the call to backend is first request. @@ -162,46 +154,6 @@ export const SearchIndices: React.FC = () => { )} {!hasNoIndices ? ( - {!calloutDismissed && ( - - - -

    - - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.callout.docLink', - { - defaultMessage: 'read the documentation', - } - )} - - ), - }} - /> -

    - setCalloutDismissed(true)}> - {i18n.translate('xpack.enterpriseSearch.content.callout.dismissButton', { - defaultMessage: 'Dismiss', - })} - -
    -
    - )} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts index c635e6c78531..3d97f52c659c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts @@ -28,7 +28,7 @@ export const NLP_DISPLAY_TITLES: Record = { question_answering: i18n.translate( 'xpack.enterpriseSearch.content.ml_inference.question_answering', { - defaultMessage: 'Named Entity Recognition', + defaultMessage: 'Question Answering', } ), text_classification: i18n.translate( @@ -41,7 +41,7 @@ export const NLP_DISPLAY_TITLES: Record = { defaultMessage: 'Dense Vector Text Embedding', }), text_expansion: i18n.translate('xpack.enterpriseSearch.content.ml_inference.text_expansion', { - defaultMessage: 'ELSER Text Expansion', + defaultMessage: 'Elastic Learned Sparse EncodeR (ELSER)', }), zero_shot_classification: i18n.translate( 'xpack.enterpriseSearch.content.ml_inference.zero_shot_classification', diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx index abb569361e7c..26d826d7b8fb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/ingestion_selector.tsx @@ -11,18 +11,33 @@ import { generatePath } from 'react-router-dom'; import { useValues } from 'kea'; -import { EuiButton, EuiCard, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { + EuiButton, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, + EuiText, + IconType, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ENTERPRISE_SEARCH_CONTENT_PLUGIN, + ENTERPRISE_SEARCH_ELASTICSEARCH_URL, INGESTION_METHOD_IDS, } from '../../../../../common/constants'; import apiLogo from '../../../../assets/images/api_cloud.svg'; +import connectorIcon from '../../../../assets/images/connector.svg'; +import crawlerIcon from '../../../../assets/images/crawler.svg'; +import fileUploadLogo from '../../../../assets/images/file_upload_logo.svg'; +import sampleDataLogo from '../../../../assets/images/sample_data_logo.svg'; import connectorLogo from '../../../../assets/images/search_connector.svg'; import crawlerLogo from '../../../../assets/images/search_crawler.svg'; +import languageClientsLogo from '../../../../assets/images/search_language_clients.svg'; import { NEW_API_PATH, @@ -31,104 +46,229 @@ import { } from '../../../enterprise_search_content/routes'; import { HttpLogic } from '../../../shared/http/http_logic'; import { KibanaLogic } from '../../../shared/kibana'; -import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers'; - -const START_LABEL = i18n.translate('xpack.enterpriseSearch.ingestSelector.startButton', { - defaultMessage: 'Start', -}); +import { EuiLinkTo } from '../../../shared/react_router_helpers'; export const IngestionSelector: React.FC = () => { - const { config, productFeatures } = useValues(KibanaLogic); + const { + application: { navigateToApp }, + config, + productFeatures, + } = useValues(KibanaLogic); const { errorConnectingMessage } = useValues(HttpLogic); const crawlerDisabled = Boolean(errorConnectingMessage || !config.host); return ( - - - } - textAlign="left" - title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.api', { - defaultMessage: 'API', - })} - description={i18n.translate( - 'xpack.enterpriseSearch.ingestSelector.method.api.description', - { - defaultMessage: - 'Add documents programmatically by connecting with the API using your preferred language client.', - } - )} - footer={ - - {START_LABEL} - - } - /> - - {productFeatures.hasConnectors && ( + <> + - } - textAlign="left" - title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.connectors', { - defaultMessage: 'Connectors', + - {START_LABEL} - - } /> - )} - {productFeatures.hasWebCrawler && ( + {productFeatures.hasConnectors && ( + + + + )} + {productFeatures.hasWebCrawler && ( + + + + )} + + + - } - textAlign="left" - title={i18n.translate('xpack.enterpriseSearch.ingestSelector.method.crawler', { - defaultMessage: 'Web Crawler', + - {START_LABEL} - - } + buttonIcon="visVega" + buttonLabel={i18n.translate( + 'xpack.enterpriseSearch.ingestSelector.method.browseClientsLabel', + { + defaultMessage: 'Browse clients', + } + )} + href={generatePath(ENTERPRISE_SEARCH_ELASTICSEARCH_URL)} /> - )} - + + navigateToApp('home', { path: '#/tutorial_directory/fileDataViz' })} + /> + + + navigateToApp('home', { path: '#/tutorial_directory/sampleData' })} + /> + + + + ); +}; + +interface IngestionCardProps { + buttonIcon: IconType; + buttonLabel: string; + description: string; + href?: string; + isDisabled?: boolean; + logo: IconType; + onClick?: () => void; + title: string; +} + +const IngestionCard: React.FC = ({ + buttonIcon, + buttonLabel, + description, + href, + isDisabled, + logo, + onClick, + title, +}) => { + return ( + + + + + + {title} + + + + } + description={ + + {description} + + } + footer={ + onClick ? ( + + {buttonLabel} + + ) : ( + + + {buttonLabel} + + + ) + } + /> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.scss b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.scss index 8d0286800837..b21b889138b1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.scss +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.scss @@ -1,7 +1,3 @@ -.entSearchProductSelectorHeader { - background-color: $euiColorPrimary; -} - .entSearchProductSelectorHeader > div { padding-bottom: 0; padding-top: 0; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx index 13b84c9c6e40..cd869c5444b3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx @@ -18,7 +18,6 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { WelcomeBanner } from '@kbn/search-api-panels'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; @@ -39,6 +38,7 @@ import { EnterpriseSearchProductCard } from './enterprise_search_product_card'; import { IngestionSelector } from './ingestion_selector'; import './product_selector.scss'; +import { WelcomeBanner } from './welcome_banner'; interface ProductSelectorProps { access: { @@ -81,9 +81,7 @@ export const ProductSelector: React.FC = ({ - - - + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/welcome_banner.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/welcome_banner.tsx new file mode 100644 index 000000000000..ea14d118d4c6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/welcome_banner.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiTitle, EuiText, EuiImage } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { AuthenticatedUser } from '@kbn/security-plugin/public'; + +export interface WelcomeBannerProps { + assetBasePath?: string; + image?: string; + user?: AuthenticatedUser; +} + +export const WelcomeBanner: React.FC = ({ user, assetBasePath, image }) => ( + <> + + + + {/* Reversing column direction here so screenreaders keep h1 as the first element */} + + + +

    + +

    +
    + + + {i18n.translate('xpack.enterpriseSearch.welcomeBanner.header.titleDescription', { + defaultMessage: + "There's endless ways to ingest and explore data with Elasticsearch, but here's a few of the most popular", + })} + +
    + {Boolean(user) && ( + + +

    + {user + ? i18n.translate( + 'xpack.enterpriseSearch.welcomeBanner.header.greeting.customTitle', + { + defaultMessage: '👋 Hi {name}!', + values: { name: user.full_name || user.username }, + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.welcomeBanner.header.greeting.defaultTitle', + { + defaultMessage: '👋 Hi', + } + )} +

    +
    +
    + )} +
    +
    + + + +
    + + +); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts b/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts index 82a4eedcd9c3..5ba714684872 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/doc_links/doc_links.ts @@ -119,7 +119,6 @@ class DocLinks { public licenseManagement: string; public machineLearningStart: string; public mlDocumentEnrichment: string; - public mlDocumentEnrichmentUpdateMappings: string; public pluginsIngestAttachment: string; public queryDsl: string; public restApis: string; @@ -290,7 +289,6 @@ class DocLinks { this.licenseManagement = ''; this.machineLearningStart = ''; this.mlDocumentEnrichment = ''; - this.mlDocumentEnrichmentUpdateMappings = ''; this.pluginsIngestAttachment = ''; this.queryDsl = ''; this.restApis = ''; @@ -463,8 +461,6 @@ class DocLinks { this.licenseManagement = docLinks.links.enterpriseSearch.licenseManagement; this.machineLearningStart = docLinks.links.enterpriseSearch.machineLearningStart; this.mlDocumentEnrichment = docLinks.links.enterpriseSearch.mlDocumentEnrichment; - this.mlDocumentEnrichmentUpdateMappings = - docLinks.links.enterpriseSearch.mlDocumentEnrichmentUpdateMappings; this.pluginsIngestAttachment = docLinks.links.plugins.ingestAttachment; this.queryDsl = docLinks.links.query.queryDsl; this.restApis = docLinks.links.apis.restApis; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index f68a2eee1c5a..5caeba721f36 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -26,6 +26,91 @@ const DEFAULT_PRODUCT_ACCESS: ProductAccess = { hasAppSearchAccess: true, hasWorkplaceSearchAccess: true, }; +const baseNavItems = [ + expect.objectContaining({ + href: '/app/enterprise_search/overview', + id: 'home', + items: undefined, + }), + { + id: 'content', + items: [ + { + href: '/app/enterprise_search/content/search_indices', + id: 'search_indices', + items: undefined, + name: 'Indices', + }, + { + href: '/app/enterprise_search/content/settings', + id: 'settings', + items: undefined, + name: 'Settings', + }, + ], + name: 'Content', + }, + { + id: 'applications', + items: [ + { + href: '/app/enterprise_search/applications/search_applications', + id: 'searchApplications', + items: undefined, + name: 'Search Applications', + }, + { + href: '/app/enterprise_search/analytics', + id: 'analyticsCollections', + items: undefined, + name: 'Behavioral Analytics', + }, + ], + name: 'Applications', + }, + { + id: 'es_getting_started', + items: [ + { + href: '/app/enterprise_search/elasticsearch', + id: 'elasticsearch', + items: undefined, + name: 'Elasticsearch', + }, + { + href: '/app/enterprise_search/vector_search', + id: 'vectorSearch', + items: undefined, + name: 'Vector Search', + }, + { + href: '/app/enterprise_search/ai_search', + id: 'aiSearch', + items: undefined, + name: 'AI Search', + }, + ], + name: 'Getting started', + }, + { + id: 'enterpriseSearch', + items: [ + { + href: '/app/enterprise_search/app_search', + id: 'app_search', + items: undefined, + name: 'App Search', + }, + { + href: '/app/enterprise_search/workplace_search', + id: 'workplace_search', + items: undefined, + name: 'Workplace Search', + }, + ], + name: 'Enterprise Search', + }, +]; describe('useEnterpriseSearchContentNav', () => { beforeEach(() => { @@ -41,79 +126,7 @@ describe('useEnterpriseSearchContentNav', () => { productFeatures: DEFAULT_PRODUCT_FEATURES, }); - expect(useEnterpriseSearchNav()).toEqual([ - { - id: 'content', - items: [ - { - href: '/app/enterprise_search/content/search_indices', - id: 'search_indices', - name: 'Indices', - }, - { - href: '/app/enterprise_search/content/settings', - id: 'settings', - items: undefined, - name: 'Settings', - }, - ], - name: 'Content', - }, - { - id: 'applications', - items: [ - { - href: '/app/enterprise_search/applications/search_applications', - id: 'searchApplications', - name: 'Search Applications', - }, - { - href: '/app/enterprise_search/analytics', - id: 'analyticsCollections', - name: 'Behavioral Analytics', - }, - ], - name: 'Applications', - }, - { - href: '/app/enterprise_search/overview', - id: 'es_getting_started', - items: [ - { - href: '/app/enterprise_search/elasticsearch', - id: 'elasticsearch', - name: 'Elasticsearch', - }, - { - href: '/app/enterprise_search/vector_search', - id: 'vectorSearch', - name: 'Vector Search', - }, - { - href: '/app/enterprise_search/ai_search', - id: 'aiSearch', - name: 'AI Search', - }, - ], - name: 'Getting started', - }, - { - id: 'enterpriseSearch', - items: [ - { - href: '/app/enterprise_search/app_search', - id: 'app_search', - name: 'App Search', - }, - { - href: '/app/enterprise_search/workplace_search', - id: 'workplace_search', - name: 'Workplace Search', - }, - ], - name: 'Enterprise Search', - }, - ]); + expect(useEnterpriseSearchNav()).toEqual(baseNavItems); }); it('excludes legacy products when the user has no access to them', () => { @@ -205,84 +218,14 @@ describe('useEnterpriseSearchApplicationNav', () => { }); it('returns an array of top-level Enterprise Search nav items', () => { - expect(useEnterpriseSearchApplicationNav()).toEqual([ - { - id: 'content', - items: [ - { - href: '/app/enterprise_search/content/search_indices', - id: 'search_indices', - name: 'Indices', - }, - { - href: '/app/enterprise_search/content/settings', - id: 'settings', - name: 'Settings', - }, - ], - name: 'Content', - }, - { - id: 'applications', - items: [ - { - href: '/app/enterprise_search/applications/search_applications', - id: 'searchApplications', - name: 'Search Applications', - }, - { - href: '/app/enterprise_search/analytics', - id: 'analyticsCollections', - name: 'Behavioral Analytics', - }, - ], - name: 'Applications', - }, - { - href: '/app/enterprise_search/overview', - id: 'es_getting_started', - items: [ - { - href: '/app/enterprise_search/elasticsearch', - id: 'elasticsearch', - name: 'Elasticsearch', - }, - { - href: '/app/enterprise_search/vector_search', - id: 'vectorSearch', - name: 'Vector Search', - }, - { - href: '/app/enterprise_search/ai_search', - id: 'aiSearch', - name: 'AI Search', - }, - ], - name: 'Getting started', - }, - { - id: 'enterpriseSearch', - items: [ - { - href: '/app/enterprise_search/app_search', - id: 'app_search', - name: 'App Search', - }, - { - href: '/app/enterprise_search/workplace_search', - id: 'workplace_search', - name: 'Workplace Search', - }, - ], - name: 'Enterprise Search', - }, - ]); + expect(useEnterpriseSearchApplicationNav()).toEqual(baseNavItems); }); it('returns selected engine sub nav items', () => { const engineName = 'my-test-engine'; const navItems = useEnterpriseSearchApplicationNav(engineName); - expect(navItems?.map((ni) => ni.name)).toEqual([ + expect(navItems![0].id).toEqual('home'); + expect(navItems?.slice(1).map((ni) => ni.name)).toEqual([ 'Content', 'Applications', 'Getting started', @@ -338,7 +281,8 @@ describe('useEnterpriseSearchApplicationNav', () => { it('returns selected engine without tabs when isEmpty', () => { const engineName = 'my-test-engine'; const navItems = useEnterpriseSearchApplicationNav(engineName, true); - expect(navItems?.map((ni) => ni.name)).toEqual([ + expect(navItems![0].id).toEqual('home'); + expect(navItems?.slice(1).map((ni) => ni.name)).toEqual([ 'Content', 'Applications', 'Getting started', @@ -397,74 +341,6 @@ describe('useEnterpriseSearchApplicationNav', () => { }); describe('useEnterpriseSearchAnalyticsNav', () => { - const baseNavs = [ - { - id: 'content', - items: [ - { - href: '/app/enterprise_search/content/search_indices', - id: 'search_indices', - name: 'Indices', - }, - ], - name: 'Content', - }, - { - id: 'applications', - items: [ - { - href: '/app/enterprise_search/applications/search_applications', - id: 'searchApplications', - name: 'Search Applications', - }, - { - href: '/app/enterprise_search/analytics', - id: 'analyticsCollections', - name: 'Behavioral Analytics', - }, - ], - name: 'Applications', - }, - { - href: '/app/enterprise_search/overview', - id: 'es_getting_started', - items: [ - { - href: '/app/enterprise_search/elasticsearch', - id: 'elasticsearch', - name: 'Elasticsearch', - }, - { - href: '/app/enterprise_search/vector_search', - id: 'vectorSearch', - name: 'Vector Search', - }, - { - href: '/app/enterprise_search/ai_search', - id: 'aiSearch', - name: 'AI Search', - }, - ], - name: 'Getting started', - }, - { - id: 'enterpriseSearch', - items: [ - { - href: '/app/enterprise_search/app_search', - id: 'app_search', - name: 'App Search', - }, - { - href: '/app/enterprise_search/workplace_search', - id: 'workplace_search', - name: 'Workplace Search', - }, - ], - name: 'Enterprise Search', - }, - ]; - beforeEach(() => { jest.clearAllMocks(); setMockValues({ @@ -474,12 +350,36 @@ describe('useEnterpriseSearchAnalyticsNav', () => { it('returns basic nav all params are empty', () => { const navItems = useEnterpriseSearchAnalyticsNav(); - expect(navItems).toEqual(baseNavs); + // filter out settings item because we're setting hasDefaultIngestPipeline to false + expect(navItems).toEqual( + baseNavItems.map((item) => + item.id === 'content' + ? { + ...item, + items: item.items?.filter( + (contentItem: { id: string }) => contentItem.id !== 'settings' + ), + } + : item + ) + ); }); it('returns basic nav if only name provided', () => { + // filter out settings item because we're setting hasDefaultIngestPipeline to false const navItems = useEnterpriseSearchAnalyticsNav('my-test-collection'); - expect(navItems).toEqual(baseNavs); + expect(navItems).toEqual( + baseNavItems.map((item) => + item.id === 'content' + ? { + ...item, + items: item.items?.filter( + (contentItem: { id: string }) => contentItem.id !== 'settings' + ), + } + : item + ) + ); }); it('returns nav with sub items when name and paths provided', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx index 8fe9c36766c6..dd41511a436a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useValues } from 'kea'; -import { EuiFlexGroup, EuiIcon, EuiSideNavItemType } from '@elastic/eui'; +import { EuiFlexGroup, EuiIcon, EuiSideNavItemType, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { @@ -34,6 +34,21 @@ export const useEnterpriseSearchNav = () => { if (!isSidebarEnabled) return undefined; const navItems: Array> = [ + { + id: 'home', + name: ( + + {i18n.translate('xpack.enterpriseSearch.nav.homeTitle', { + defaultMessage: 'Home', + })} + + ), + ...generateNavLink({ + shouldNotCreateHref: true, + shouldShowActiveForSubroutes: true, + to: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + }), + }, { id: 'content', items: [ @@ -98,13 +113,6 @@ export const useEnterpriseSearchNav = () => { }, { id: 'es_getting_started', - name: i18n.translate('xpack.enterpriseSearch.nav.enterpriseSearchOverviewTitle', { - defaultMessage: 'Getting started', - }), - ...generateNavLink({ - shouldNotCreateHref: true, - to: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, - }), items: [ { id: 'elasticsearch', @@ -135,6 +143,9 @@ export const useEnterpriseSearchNav = () => { }), }, ], + name: i18n.translate('xpack.enterpriseSearch.nav.enterpriseSearchOverviewTitle', { + defaultMessage: 'Getting started', + }), }, ...(productAccess.hasAppSearchAccess || productAccess.hasWorkplaceSearchAccess ? [ diff --git a/x-pack/plugins/enterprise_search/public/assets/images/connector.svg b/x-pack/plugins/enterprise_search/public/assets/images/connector.svg new file mode 100644 index 000000000000..3b37b963f435 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/assets/images/connector.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/x-pack/plugins/enterprise_search/public/assets/images/crawler.svg b/x-pack/plugins/enterprise_search/public/assets/images/crawler.svg new file mode 100644 index 000000000000..94aafafddf68 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/assets/images/crawler.svg @@ -0,0 +1,4 @@ + + + + diff --git a/x-pack/plugins/enterprise_search/public/assets/images/file_upload_logo.svg b/x-pack/plugins/enterprise_search/public/assets/images/file_upload_logo.svg new file mode 100644 index 000000000000..90bbc987154a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/assets/images/file_upload_logo.svg @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/enterprise_search/public/assets/images/sample_data_logo.svg b/x-pack/plugins/enterprise_search/public/assets/images/sample_data_logo.svg new file mode 100644 index 000000000000..07e0d8fe5818 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/assets/images/sample_data_logo.svg @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/enterprise_search/public/assets/images/search_language_clients.svg b/x-pack/plugins/enterprise_search/public/assets/images/search_language_clients.svg new file mode 100644 index 000000000000..c4ff851bc70e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/assets/images/search_language_clients.svg @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.test.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.test.ts index 978896289763..6c5d44b00628 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.test.ts @@ -345,7 +345,7 @@ describe('startSync lib function', () => { }, filtering: null, id: 'connectorId', - index_name: `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}index_name`, + index_name: `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}search-index_name`, language: null, pipeline: null, service_type: null, diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.ts index ab58fd1417b7..634d7e97de5e 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/start_sync.ts @@ -23,7 +23,6 @@ import { } from '../../../common/constants'; import { ErrorCode } from '../../../common/types/error_codes'; -import { stripSearchPrefix } from '../../../common/utils/strip_search_prefix'; export const startSync = async ( client: IScopedClusterClient, @@ -70,10 +69,9 @@ export const startSync = async ( }); } - const indexNameWithoutSearchPrefix = index_name ? stripSearchPrefix(index_name) : ''; const targetIndexName = jobType === SyncJobType.ACCESS_CONTROL - ? `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}${indexNameWithoutSearchPrefix}` + ? `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}${index_name}` : index_name ?? undefined; return await startConnectorSync(client.asCurrentUser, { diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.test.ts index 0439c12c203d..fc14896e23c5 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.test.ts @@ -32,7 +32,7 @@ describe('deleteAccessControlIndex lib function', () => { deleteAccessControlIndex(mockClient as unknown as IScopedClusterClient, 'indexName') ).resolves.toEqual(true); expect(mockClient.asCurrentUser.indices.delete).toHaveBeenCalledWith({ - index: 'indexName', + index: '.search-acl-filter-indexName', }); }); }); @@ -58,7 +58,7 @@ describe('deleteAccessControlIndex lib function', () => { deleteAccessControlIndex(mockClient as unknown as IScopedClusterClient, 'indexName') ).resolves.not.toThrowError(); expect(mockClient.asCurrentUser.indices.delete).toHaveBeenCalledWith({ - index: 'indexName', + index: '.search-acl-filter-indexName', }); }); }); @@ -84,7 +84,7 @@ describe('deleteAccessControlIndex lib function', () => { deleteAccessControlIndex(mockClient as unknown as IScopedClusterClient, 'indexName') ).rejects.toEqual(mockErrorRejection); expect(mockClient.asCurrentUser.indices.delete).toHaveBeenCalledWith({ - index: 'indexName', + index: '.search-acl-filter-indexName', }); }); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.ts b/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.ts index 1937df11b912..19769f09fa24 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/delete_access_control_index.ts @@ -8,14 +8,15 @@ import { IScopedClusterClient } from '@kbn/core/server'; import { CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX } from '../../../common/constants'; -import { stripSearchPrefix } from '../../../common/utils/strip_search_prefix'; import { isIndexNotFoundException } from '../../utils/identify_exceptions'; -export const deleteAccessControlIndex = async (client: IScopedClusterClient, index: string) => { +export const deleteAccessControlIndex = async (client: IScopedClusterClient, indexName: string) => { + const aclIndexName = `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}${indexName}`; + try { return await client.asCurrentUser.indices.delete({ - index: stripSearchPrefix(index, CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX), + index: aclIndexName, }); } catch (e) { // Gracefully exit if index not found. This is a valid case. diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts index a28450108290..92c87b354a47 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts @@ -94,7 +94,7 @@ describe('generateApiKey lib function', () => { cluster: ['monitor'], index: [ { - names: ['search-test', '.search-acl-filter-test', `${CONNECTORS_INDEX}*`], + names: ['search-test', '.search-acl-filter-search-test', `${CONNECTORS_INDEX}*`], privileges: ['all'], }, ], diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts index d256bc6a91d8..fb2ddbaad9f9 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts @@ -7,13 +7,16 @@ import { IScopedClusterClient } from '@kbn/core/server'; -import { ConnectorDocument, CONNECTORS_INDEX } from '@kbn/search-connectors'; +import { + ConnectorDocument, + CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX, + CONNECTORS_INDEX, +} from '@kbn/search-connectors'; import { toAlphanumeric } from '../../../common/utils/to_alphanumeric'; export const generateApiKey = async (client: IScopedClusterClient, indexName: string) => { - // removes the "search-" prefix if present, and applies the new prefix - const aclIndexName = indexName.replace(/^(?:search-)?(.*)$/, '.search-acl-filter-$1'); + const aclIndexName = `${CONNECTORS_ACCESS_CONTROL_INDEX_PREFIX}${indexName}`; const apiKeyResult = await client.asCurrentUser.security.createApiKey({ name: `${indexName}-connector`, diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts new file mode 100644 index 000000000000..790b34a964d5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts @@ -0,0 +1,425 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MlTrainedModels } from '@kbn/ml-plugin/server'; + +import { MlModelDeploymentState } from '../../../common/types/ml'; + +import { fetchMlModels } from './fetch_ml_models'; +import { + E5_LINUX_OPTIMIZED_MODEL_ID, + E5_MODEL_ID, + ELSER_LINUX_OPTIMIZED_MODEL_ID, + ELSER_MODEL_ID, +} from './utils'; + +describe('fetchMlModels', () => { + const mockTrainedModelsProvider = { + getTrainedModels: jest.fn(), + getTrainedModelsStats: jest.fn(), + getCuratedModelConfig: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + // getCuratedModelConfig() default behavior is to return the cross-platform models + mockTrainedModelsProvider.getCuratedModelConfig.mockImplementation((modelName) => ({ + model_id: modelName === 'elser' ? ELSER_MODEL_ID : E5_MODEL_ID, + modelName, + })); + }); + + it('errors when there is no trained model provider', () => { + expect(() => fetchMlModels(undefined)).rejects.toThrowError('Machine Learning is not enabled'); + }); + + it('returns placeholders if no model is found', async () => { + const mockModelConfigs = { + count: 0, + trained_model_configs: [], + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(2); + expect(models[0]).toMatchObject({ + modelId: ELSER_MODEL_ID, + isPlaceholder: true, + deploymentState: MlModelDeploymentState.NotDeployed, + }); + expect(models[1]).toMatchObject({ + modelId: E5_MODEL_ID, + isPlaceholder: true, + deploymentState: MlModelDeploymentState.NotDeployed, + }); + expect(mockTrainedModelsProvider.getTrainedModelsStats).not.toHaveBeenCalled(); + }); + + it('combines existing models with placeholders', async () => { + const mockModelConfigs = { + count: 2, + trained_model_configs: [ + { + model_id: E5_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: 'model_1', + inference_config: { + text_classification: {}, + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: [ + { + model_id: E5_MODEL_ID, + }, + { + model_id: 'model_1', + }, + ], + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(3); + expect(models[0].modelId).toEqual(ELSER_MODEL_ID); // Placeholder + expect(models[1]).toMatchObject({ + modelId: E5_MODEL_ID, + isPlaceholder: false, + }); + expect(models[2]).toMatchObject({ + modelId: 'model_1', + isPlaceholder: false, + }); + }); + + it('filters non-supported models', async () => { + const mockModelConfigs = { + count: 2, + trained_model_configs: [ + { + model_id: 'model_1', + inference_config: { + not_supported_1: {}, + }, + }, + { + model_id: 'model_2', + inference_config: { + not_supported_2: {}, + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: mockModelConfigs.trained_model_configs.map((modelConfig) => ({ + model_id: modelConfig.model_id, + })), + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(2); + expect(models[0].modelId).toEqual(ELSER_MODEL_ID); // Placeholder + expect(models[1].modelId).toEqual(E5_MODEL_ID); // Placeholder + }); + + it('filters incompatible model variants of promoted models', async () => { + const mockModelConfigs = { + count: 2, + trained_model_configs: [ + { + model_id: E5_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: E5_LINUX_OPTIMIZED_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: ELSER_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + { + model_id: ELSER_LINUX_OPTIMIZED_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: mockModelConfigs.trained_model_configs.map((modelConfig) => ({ + model_id: modelConfig.model_id, + })), + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(2); + expect(models[0].modelId).toEqual(ELSER_MODEL_ID); + expect(models[1].modelId).toEqual(E5_MODEL_ID); + }); + + it('filters incompatible model variants of promoted models (Linux variants)', async () => { + const mockModelConfigs = { + count: 2, + trained_model_configs: [ + { + model_id: E5_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: E5_LINUX_OPTIMIZED_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: ELSER_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + { + model_id: ELSER_LINUX_OPTIMIZED_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: mockModelConfigs.trained_model_configs.map((modelConfig) => ({ + model_id: modelConfig.model_id, + })), + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + mockTrainedModelsProvider.getCuratedModelConfig.mockImplementation((modelName) => ({ + model_id: + modelName === 'elser' ? ELSER_LINUX_OPTIMIZED_MODEL_ID : E5_LINUX_OPTIMIZED_MODEL_ID, + modelName, + })); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(2); + expect(models[0].modelId).toEqual(ELSER_LINUX_OPTIMIZED_MODEL_ID); + expect(models[1].modelId).toEqual(E5_LINUX_OPTIMIZED_MODEL_ID); + }); + + it('sets deployment state on models', async () => { + const mockModelConfigs = { + count: 3, + trained_model_configs: [ + { + model_id: ELSER_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + { + model_id: E5_MODEL_ID, + inference_config: { + text_embedding: {}, + }, + }, + { + model_id: 'model_1', + inference_config: { + ner: {}, + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: [ + { + model_id: ELSER_MODEL_ID, + deployment_stats: { + allocation_status: { + state: 'fully_allocated', + }, + }, + }, + { + model_id: E5_MODEL_ID, + deployment_stats: { + allocation_status: { + state: 'started', + }, + }, + }, + { + model_id: 'model_1', // No deployment_stats -> not deployed + }, + ], + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(3); + expect(models[0]).toMatchObject({ + modelId: ELSER_MODEL_ID, + deploymentState: MlModelDeploymentState.FullyAllocated, + }); + expect(models[1]).toMatchObject({ + modelId: E5_MODEL_ID, + deploymentState: MlModelDeploymentState.Started, + }); + expect(models[2]).toMatchObject({ + modelId: 'model_1', + deploymentState: MlModelDeploymentState.NotDeployed, + }); + }); + + it('determines downloading/downloaded deployment state for promoted models', async () => { + const mockModelConfigs = { + count: 1, + trained_model_configs: [ + { + model_id: ELSER_MODEL_ID, + inference_config: { + text_expansion: {}, + }, + }, + ], + }; + const mockModelConfigsWithDefinition = { + count: 1, + trained_model_configs: [ + { + ...mockModelConfigs.trained_model_configs[0], + fully_defined: true, + }, + ], + }; + const mockModelStats = { + trained_model_stats: [ + { + model_id: ELSER_MODEL_ID, // No deployment_stats -> not deployed + }, + ], + }; + + // 1st call: get models + // 2nd call: get definition_status for ELSER + mockTrainedModelsProvider.getTrainedModels + .mockImplementationOnce(() => Promise.resolve(mockModelConfigs)) + .mockImplementationOnce(() => Promise.resolve(mockModelConfigsWithDefinition)); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(2); + expect(models[0]).toMatchObject({ + modelId: ELSER_MODEL_ID, + deploymentState: MlModelDeploymentState.Downloaded, + }); + expect(mockTrainedModelsProvider.getTrainedModels).toHaveBeenCalledTimes(2); + }); + + it('pins promoted models on top and sorts others by title', async () => { + const mockModelConfigs = { + count: 3, + trained_model_configs: [ + { + model_id: 'model_1', + inference_config: { + ner: {}, // "Named Entity Recognition" + }, + }, + { + model_id: 'model_2', + inference_config: { + text_embedding: {}, // "Dense Vector Text Embedding" + }, + }, + { + model_id: 'model_3', + inference_config: { + text_classification: {}, // "Text Classification" + }, + }, + ], + }; + const mockModelStats = { + trained_model_stats: mockModelConfigs.trained_model_configs.map((modelConfig) => ({ + model_id: modelConfig.model_id, + })), + }; + + mockTrainedModelsProvider.getTrainedModels.mockImplementation(() => + Promise.resolve(mockModelConfigs) + ); + mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() => + Promise.resolve(mockModelStats) + ); + + const models = await fetchMlModels(mockTrainedModelsProvider as unknown as MlTrainedModels); + + expect(models.length).toBe(5); + expect(models[0].modelId).toEqual(ELSER_MODEL_ID); // Pinned to top + expect(models[1].modelId).toEqual(E5_MODEL_ID); // Pinned to top + expect(models[2].modelId).toEqual('model_2'); // "Dense Vector Text Embedding" + expect(models[3].modelId).toEqual('model_1'); // "Named Entity Recognition" + expect(models[4].modelId).toEqual('model_3'); // "Text Classification" + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts new file mode 100644 index 000000000000..1062356a5dbe --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MlTrainedModelConfig, MlTrainedModelStats } from '@elastic/elasticsearch/lib/api/types'; +import { MlTrainedModels } from '@kbn/ml-plugin/server'; + +import { MlModelDeploymentState, MlModel } from '../../../common/types/ml'; + +import { + BASE_MODEL, + ELSER_LINUX_OPTIMIZED_MODEL_PLACEHOLDER, + ELSER_MODEL_ID, + ELSER_MODEL_PLACEHOLDER, + E5_LINUX_OPTIMIZED_MODEL_PLACEHOLDER, + E5_MODEL_ID, + E5_MODEL_PLACEHOLDER, + LANG_IDENT_MODEL_ID, + MODEL_TITLES_BY_TYPE, + E5_LINUX_OPTIMIZED_MODEL_ID, + ELSER_LINUX_OPTIMIZED_MODEL_ID, +} from './utils'; + +let compatibleElserModelId = ELSER_MODEL_ID; +let compatibleE5ModelId = E5_MODEL_ID; + +/** + * Fetches and enriches trained model information and deployment status. Pins promoted models (ELSER, E5) to the top. If a promoted model doesn't exist, a placeholder will be used. + * + * @param trainedModelsProvider Trained ML models provider + * @returns List of models + */ +export const fetchMlModels = async ( + trainedModelsProvider: MlTrainedModels | undefined +): Promise => { + if (!trainedModelsProvider) { + throw new Error('Machine Learning is not enabled'); + } + + // Set the compatible ELSER and E5 model IDs based on platform architecture + [compatibleElserModelId, compatibleE5ModelId] = await fetchCompatiblePromotedModelIds( + trainedModelsProvider + ); + + // This array will contain all models, let's add placeholders first (compatible variants only) + const models: MlModel[] = [ + ELSER_MODEL_PLACEHOLDER, + ELSER_LINUX_OPTIMIZED_MODEL_PLACEHOLDER, + E5_MODEL_PLACEHOLDER, + E5_LINUX_OPTIMIZED_MODEL_PLACEHOLDER, + ].filter((model) => isCompatiblePromotedModelId(model.modelId)); + + // Fetch all models and their deployment stats using the ML client + const modelsResponse = await trainedModelsProvider.getTrainedModels({}); + if (modelsResponse.count === 0) { + return models; + } + const modelsStatsResponse = await trainedModelsProvider.getTrainedModelsStats({}); + + modelsResponse.trained_model_configs + // Filter unsupported models + .filter((modelConfig) => isSupportedModel(modelConfig)) + // Get corresponding model stats and compose full model object + .map((modelConfig) => + getModel( + modelConfig, + modelsStatsResponse.trained_model_stats.find((m) => m.model_id === modelConfig.model_id) + ) + ) + // Merge models with placeholders + // (Note: properties from the placeholder that are undefined in the model are preserved) + .forEach((model) => mergeModel(model, models)); + + // Undeployed placeholder models might be in the Downloading phase; let's evaluate this with a call + // We must do this one by one because the API doesn't support fetching multiple models with include=definition_status + for (const model of models) { + if (model.isPromoted && !model.isPlaceholder && !model.hasStats) { + await enrichModelWithDownloadStatus(model, trainedModelsProvider); + } + } + + // Pin ELSER to the top, then E5 below, then the rest of the models sorted alphabetically + return models.sort(sortModels); +}; + +/** + * Fetches model IDs of promoted models (ELSER, E5) that are compatible with the platform architecture. The fetches + * are executed in parallel. + * Defaults to the cross-platform variant of a model if its ID is not present in the trained models client's response. + * @param trainedModelsProvider Trained ML models provider + * @returns Array of model IDs [0: ELSER, 1: E5] + */ +export const fetchCompatiblePromotedModelIds = async (trainedModelsProvider: MlTrainedModels) => { + const compatibleModelConfigs = await Promise.all([ + trainedModelsProvider.getCuratedModelConfig('elser', { version: 2 }), + trainedModelsProvider.getCuratedModelConfig('e5'), + ]); + + return [ + compatibleModelConfigs.find((modelConfig) => modelConfig?.modelName === 'elser')?.model_id ?? + ELSER_MODEL_ID, + compatibleModelConfigs.find((modelConfig) => modelConfig?.modelName === 'e5')?.model_id ?? + E5_MODEL_ID, + ]; +}; + +const getModel = (modelConfig: MlTrainedModelConfig, modelStats?: MlTrainedModelStats): MlModel => { + { + const modelId = modelConfig.model_id; + const type = modelConfig.inference_config ? Object.keys(modelConfig.inference_config)[0] : ''; + const model = { + ...BASE_MODEL, + modelId, + type, + title: getUserFriendlyTitle(modelId, type), + isPromoted: [ + ELSER_MODEL_ID, + ELSER_LINUX_OPTIMIZED_MODEL_ID, + E5_MODEL_ID, + E5_LINUX_OPTIMIZED_MODEL_ID, + ].includes(modelId), + }; + + // Enrich deployment stats + if (modelStats && modelStats.deployment_stats) { + model.hasStats = true; + model.deploymentState = getDeploymentState( + modelStats.deployment_stats.allocation_status.state + ); + model.nodeAllocationCount = modelStats.deployment_stats.allocation_status.allocation_count; + model.targetAllocationCount = + modelStats.deployment_stats.allocation_status.target_allocation_count; + model.threadsPerAllocation = modelStats.deployment_stats.threads_per_allocation; + model.startTime = modelStats.deployment_stats.start_time; + } else if (model.modelId === LANG_IDENT_MODEL_ID) { + model.deploymentState = MlModelDeploymentState.FullyAllocated; + } + + return model; + } +}; + +const enrichModelWithDownloadStatus = async ( + model: MlModel, + trainedModelsProvider: MlTrainedModels +) => { + const modelConfigWithDefinitionStatus = await trainedModelsProvider.getTrainedModels({ + model_id: model.modelId, + include: 'definition_status', + }); + + if (modelConfigWithDefinitionStatus && modelConfigWithDefinitionStatus.count > 0) { + model.deploymentState = modelConfigWithDefinitionStatus.trained_model_configs[0].fully_defined + ? MlModelDeploymentState.Downloaded + : MlModelDeploymentState.Downloading; + } +}; + +const mergeModel = (model: MlModel, models: MlModel[]) => { + const i = models.findIndex((m) => m.modelId === model.modelId); + if (i >= 0) { + const { title, ...modelWithoutTitle } = model; + + models[i] = Object.assign({}, models[i], modelWithoutTitle); + } else { + models.push(model); + } +}; + +const isCompatiblePromotedModelId = (modelId: string) => + [compatibleElserModelId, compatibleE5ModelId].includes(modelId); + +/** + * A model is supported if: + * - The inference type is supported, AND + * - The model is the compatible variant of ELSER/E5, or it's a 3rd party model + */ +const isSupportedModel = (modelConfig: MlTrainedModelConfig) => + isSupportedInferenceType(modelConfig) && + ((!modelConfig.model_id.startsWith(ELSER_MODEL_ID) && + !modelConfig.model_id.startsWith(E5_MODEL_ID)) || + isCompatiblePromotedModelId(modelConfig.model_id)); + +const isSupportedInferenceType = (modelConfig: MlTrainedModelConfig) => + Object.keys(modelConfig.inference_config || {}).some((inferenceType) => + Object.keys(MODEL_TITLES_BY_TYPE).includes(inferenceType) + ) || modelConfig.model_id === LANG_IDENT_MODEL_ID; + +/** + * Sort function for models; makes ELSER go to the top, then E5, then the rest of the models sorted by title. + */ +const sortModels = (m1: MlModel, m2: MlModel) => + m1.modelId.startsWith(ELSER_MODEL_ID) + ? -1 + : m2.modelId.startsWith(ELSER_MODEL_ID) + ? 1 + : m1.modelId.startsWith(E5_MODEL_ID) + ? -1 + : m2.modelId.startsWith(E5_MODEL_ID) + ? 1 + : m1.title.localeCompare(m2.title); + +const getUserFriendlyTitle = (modelId: string, modelType: string) => { + return MODEL_TITLES_BY_TYPE[modelType] !== undefined + ? MODEL_TITLES_BY_TYPE[modelType]! + : modelId === LANG_IDENT_MODEL_ID + ? 'Lanugage Identification' + : modelId; +}; + +const getDeploymentState = (state: string): MlModelDeploymentState => { + switch (state) { + case 'starting': + return MlModelDeploymentState.Starting; + case 'started': + return MlModelDeploymentState.Started; + case 'fully_allocated': + return MlModelDeploymentState.FullyAllocated; + } + + return MlModelDeploymentState.NotDeployed; +}; diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/start_ml_model_deployment.ts b/x-pack/plugins/enterprise_search/server/lib/ml/start_ml_model_deployment.ts index 4f65dbf9ced6..becd34a6c3c9 100644 --- a/x-pack/plugins/enterprise_search/server/lib/ml/start_ml_model_deployment.ts +++ b/x-pack/plugins/enterprise_search/server/lib/ml/start_ml_model_deployment.ts @@ -43,7 +43,7 @@ export const startMlModelDeployment = async ( // we're downloaded already, but not deployed yet - let's deploy it const startRequest: MlStartTrainedModelDeploymentRequest = { model_id: modelName, - wait_for: 'started', + wait_for: 'starting', }; await trainedModelsProvider.startTrainedModelDeployment(startRequest); diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/utils.ts b/x-pack/plugins/enterprise_search/server/lib/ml/utils.ts new file mode 100644 index 000000000000..817e8716f73e --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/ml/utils.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils'; + +import { MlModelDeploymentState, MlModel } from '../../../common/types/ml'; + +export const ELSER_MODEL_ID = '.elser_model_2'; +export const ELSER_LINUX_OPTIMIZED_MODEL_ID = '.elser_model_2_linux-x86_64'; +export const E5_MODEL_ID = '.multilingual-e5-small'; +export const E5_LINUX_OPTIMIZED_MODEL_ID = '.multilingual-e5-small_linux-x86_64'; +export const LANG_IDENT_MODEL_ID = 'lang_ident_model_1'; + +export const MODEL_TITLES_BY_TYPE: Record = { + fill_mask: i18n.translate('xpack.enterpriseSearch.content.ml_inference.fill_mask', { + defaultMessage: 'Fill Mask', + }), + lang_ident: i18n.translate('xpack.enterpriseSearch.content.ml_inference.lang_ident', { + defaultMessage: 'Language Identification', + }), + ner: i18n.translate('xpack.enterpriseSearch.content.ml_inference.ner', { + defaultMessage: 'Named Entity Recognition', + }), + question_answering: i18n.translate( + 'xpack.enterpriseSearch.content.ml_inference.question_answering', + { + defaultMessage: 'Question Answering', + } + ), + text_classification: i18n.translate( + 'xpack.enterpriseSearch.content.ml_inference.text_classification', + { + defaultMessage: 'Text Classification', + } + ), + text_embedding: i18n.translate('xpack.enterpriseSearch.content.ml_inference.text_embedding', { + defaultMessage: 'Dense Vector Text Embedding', + }), + text_expansion: i18n.translate('xpack.enterpriseSearch.content.ml_inference.text_expansion', { + defaultMessage: 'Elastic Learned Sparse EncodeR (ELSER)', + }), + zero_shot_classification: i18n.translate( + 'xpack.enterpriseSearch.content.ml_inference.zero_shot_classification', + { + defaultMessage: 'Zero-Shot Text Classification', + } + ), +}; + +export const BASE_MODEL = { + deploymentState: MlModelDeploymentState.NotDeployed, + nodeAllocationCount: 0, + startTime: 0, + targetAllocationCount: 0, + threadsPerAllocation: 0, + isPlaceholder: false, + hasStats: false, +}; + +export const ELSER_MODEL_PLACEHOLDER: MlModel = { + ...BASE_MODEL, + modelId: ELSER_MODEL_ID, + type: SUPPORTED_PYTORCH_TASKS.TEXT_EXPANSION, + title: 'ELSER (Elastic Learned Sparse EncodeR)', + description: i18n.translate('xpack.enterpriseSearch.modelCard.elserPlaceholder.description', { + defaultMessage: + "ELSER is Elastic's NLP model for English semantic search, utilizing sparse vectors. It prioritizes intent and contextual meaning over literal term matching, optimized specifically for English documents and queries on the Elastic platform.", + }), + isPlaceholder: true, +}; + +export const ELSER_LINUX_OPTIMIZED_MODEL_PLACEHOLDER = { + ...ELSER_MODEL_PLACEHOLDER, + modelId: ELSER_LINUX_OPTIMIZED_MODEL_ID, + title: 'ELSER (Elastic Learned Sparse EncodeR), optimized for linux-x86_64', +}; + +export const E5_MODEL_PLACEHOLDER: MlModel = { + ...BASE_MODEL, + modelId: E5_MODEL_ID, + type: SUPPORTED_PYTORCH_TASKS.TEXT_EMBEDDING, + title: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + description: i18n.translate('xpack.enterpriseSearch.modelCard.e5Placeholder.description', { + defaultMessage: + 'E5 is an NLP model that enables you to perform multi-lingual semantic search by using dense vector representations. This model performs best for non-English language documents and queries.', + }), + license: 'MIT', + modelDetailsPageUrl: 'https://huggingface.co/intfloat/multilingual-e5-small', + isPlaceholder: true, +}; + +export const E5_LINUX_OPTIMIZED_MODEL_PLACEHOLDER = { + ...E5_MODEL_PLACEHOLDER, + modelId: E5_LINUX_OPTIMIZED_MODEL_ID, + title: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts index e0278ff63923..eb2462457d43 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts @@ -60,6 +60,9 @@ jest.mock('../../lib/indices/pipelines/ml_inference/get_ml_inference_errors', () jest.mock('../../lib/pipelines/ml_inference/get_ml_inference_pipelines', () => ({ getMlInferencePipelines: jest.fn(), })); +jest.mock('../../lib/ml/fetch_ml_models', () => ({ + fetchMlModels: jest.fn(), +})); jest.mock('../../lib/ml/get_ml_model_deployment_status', () => ({ getMlModelDeploymentStatus: jest.fn(), })); @@ -85,6 +88,7 @@ import { preparePipelineAndIndexForMlInference } from '../../lib/indices/pipelin import { deleteMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; import { detachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors'; +import { fetchMlModels } from '../../lib/ml/fetch_ml_models'; import { getMlModelDeploymentStatus } from '../../lib/ml/get_ml_model_deployment_status'; import { startMlModelDeployment } from '../../lib/ml/start_ml_model_deployment'; import { startMlModelDownload } from '../../lib/ml/start_ml_model_download'; @@ -1175,6 +1179,58 @@ describe('Enterprise Search Managed Indices', () => { }); }); + describe('GET /internal/enterprise_search/ml/models', () => { + let mockMl: MlPluginSetup; + let mockTrainedModelsProvider: MlTrainedModels; + + beforeEach(() => { + const context = { + core: Promise.resolve(mockCore), + } as unknown as jest.Mocked; + + mockRouter = new MockRouter({ + context, + method: 'get', + path: '/internal/enterprise_search/ml/models', + }); + + mockTrainedModelsProvider = { + getTrainedModels: jest.fn(), + getTrainedModelsStats: jest.fn(), + } as unknown as MlTrainedModels; + + mockMl = { + trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), + } as unknown as jest.Mocked; + + registerIndexRoutes({ + ...mockDependencies, + ml: mockMl, + router: mockRouter.router, + }); + }); + + it('fetches models', async () => { + const request = {}; + + const mockResponse = [ + { + modelId: 'model_1', + deploymentState: MlModelDeploymentState.Starting, + }, + ]; + + (fetchMlModels as jest.Mock).mockResolvedValueOnce(mockResponse); + + await mockRouter.callRoute(request); + + expect(mockRouter.response.ok).toHaveBeenCalledWith({ + body: mockResponse, + headers: { 'content-type': 'application/json' }, + }); + }); + }); + describe('GET /internal/enterprise_search/ml/models/{modelName}', () => { let mockMl: MlPluginSetup; let mockTrainedModelsProvider: MlTrainedModels; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index a43846aafab6..d96130fb0247 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -41,6 +41,7 @@ import { preparePipelineAndIndexForMlInference } from '../../lib/indices/pipelin import { deleteMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/delete_ml_inference_pipeline'; import { detachMlInferencePipeline } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/detach_ml_inference_pipeline'; import { fetchMlInferencePipelineProcessors } from '../../lib/indices/pipelines/ml_inference/pipeline_processors/get_ml_inference_pipeline_processors'; +import { fetchMlModels } from '../../lib/ml/fetch_ml_models'; import { getMlModelDeploymentStatus } from '../../lib/ml/get_ml_model_deployment_status'; import { startMlModelDeployment } from '../../lib/ml/start_ml_model_deployment'; import { startMlModelDownload } from '../../lib/ml/start_ml_model_download'; @@ -1100,6 +1101,28 @@ export function registerIndexRoutes({ }) ); + router.get( + { + path: '/internal/enterprise_search/ml/models', + validate: {}, + }, + elasticsearchErrorHandler(log, async (context, request, response) => { + const { + savedObjects: { client: savedObjectsClient }, + } = await context.core; + const trainedModelsProvider = ml + ? await ml.trainedModelsProvider(request, savedObjectsClient) + : undefined; + + const modelsResult = await fetchMlModels(trainedModelsProvider); + + return response.ok({ + body: modelsResult, + headers: { 'content-type': 'application/json' }, + }); + }) + ); + router.get( { path: '/internal/enterprise_search/ml/models/{modelName}', diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx index 4e81ca840199..5d43f5bd1e6d 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx @@ -12,8 +12,6 @@ import { sampleAttribute } from '../../configurations/test_data/sample_attribute import * as pluginHook from '../../../../../hooks/use_plugin_context'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { ExpViewActionMenuContent } from './action_menu'; -import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public'; -import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions'; jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ appMountParameters: { @@ -21,13 +19,6 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ }, } as any); -jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockImplementation( - () => - ({ - useGetUserCasesPermissions: jest.fn(() => mockUseGetCasesPermissions()), - } as any) -); - describe('Action Menu', function () { afterAll(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx index 7b4e0cb5cc57..83cae3e8b4eb 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx @@ -12,8 +12,6 @@ import { ExploratoryView } from './exploratory_view'; import * as obsvDataViews from '../../../utils/observability_data_views/observability_data_views'; import * as pluginHook from '../../../hooks/use_plugin_context'; import { createStubIndexPattern } from '@kbn/data-plugin/common/stubs'; -import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public/utils/cases_permissions'; -import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions'; jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ appMountParameters: { @@ -21,13 +19,6 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ }, } as any); -jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockImplementation( - () => - ({ - useGetUserCasesPermissions: jest.fn(() => mockUseGetCasesPermissions()), - } as any) -); - describe('ExploratoryView', () => { mockAppDataView(); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx index ffccfdf6db3f..1d42716bf405 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx @@ -13,10 +13,15 @@ import * as useCaseHook from '../hooks/use_add_to_case'; import * as datePicker from '../components/date_range_picker'; import moment from 'moment'; import { noCasesPermissions as mockUseGetCasesPermissions } from '@kbn/observability-shared-plugin/public'; -import * as obsHooks from '@kbn/observability-shared-plugin/public/hooks/use_get_user_cases_permissions'; -jest.spyOn(obsHooks, 'useGetUserCasesPermissions').mockReturnValue(mockUseGetCasesPermissions()); describe('AddToCaseAction', function () { + const coreRenderProps = { + cases: { + ui: { getAllCasesSelectorModal: jest.fn() }, + helpers: { canUseCases: () => mockUseGetCasesPermissions() }, + }, + }; + beforeEach(() => { jest.spyOn(datePicker, 'parseRelativeDate').mockRestore(); }); @@ -26,7 +31,8 @@ describe('AddToCaseAction', function () { + />, + { core: coreRenderProps } ); expect(await findByText('Add to case')).toBeInTheDocument(); }); @@ -39,7 +45,8 @@ describe('AddToCaseAction', function () { + />, + { core: coreRenderProps } ); expect(await findByText('Add to case')).toBeInTheDocument(); @@ -60,7 +67,8 @@ describe('AddToCaseAction', function () { const useAddToCaseHook = jest.spyOn(useCaseHook, 'useAddToCase'); const { getByText } = render( - + , + { core: coreRenderProps } ); expect(await forNearestButton(getByText)('Add to case')).toBeDisabled(); @@ -95,7 +103,7 @@ describe('AddToCaseAction', function () { lensAttributes={{ title: 'Performance distribution' } as any} timeRange={{ to: 'now', from: 'now-5m' }} />, - { initSeries } + { initSeries, core: coreRenderProps } ); fireEvent.click(await findByText('Add to case')); @@ -111,6 +119,7 @@ describe('AddToCaseAction', function () { delete: false, push: false, connectors: false, + settings: false, }, }) ); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.tsx index 1cbb904f6500..590451eaea6e 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.tsx @@ -16,7 +16,6 @@ import { } from '@kbn/cases-plugin/public'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { observabilityFeatureId } from '@kbn/observability-shared-plugin/public'; -import { useGetUserCasesPermissions } from '@kbn/observability-shared-plugin/public'; import { ObservabilityAppServices } from '../../../../application/types'; import { useAddToCase } from '../hooks/use_add_to_case'; import { parseRelativeDate } from '../components/date_range_picker'; @@ -37,7 +36,7 @@ export function AddToCaseAction({ timeRange, }: AddToCaseProps) { const kServices = useKibana().services; - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = kServices.cases.helpers.canUseCases([observabilityFeatureId]); const { cases, diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 3a56b080bb91..49c001c890b6 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -204,6 +204,16 @@ export interface FeatureKibanaPrivileges { * ``` */ delete?: readonly string[]; + /** + * List of case owners which users should have settings access to when granted this privilege. + * @example + * ```ts + * { + * settings: ['securitySolution'] + * } + * ``` + */ + settings?: readonly string[]; }; /** diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index 62e868e77e52..7247c1d23cb0 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -558,6 +558,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ @@ -710,6 +711,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ @@ -1032,6 +1034,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ @@ -1169,6 +1172,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ @@ -1321,6 +1325,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ @@ -1643,6 +1648,7 @@ Array [ "delete": Array [], "push": Array [], "read": Array [], + "settings": Array [], "update": Array [], }, "catalogue": Array [ diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts index f2f6ed1071f8..58a39c85bf9e 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts @@ -77,6 +77,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -146,6 +147,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -214,6 +216,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -284,6 +287,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -324,6 +328,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -385,6 +390,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -431,6 +437,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -498,6 +505,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -559,6 +567,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -605,6 +614,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -672,6 +682,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -734,6 +745,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -783,6 +795,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type', 'cases-update-sub-type'], delete: ['cases-delete-type', 'cases-delete-sub-type'], push: ['cases-push-type', 'cases-push-sub-type'], + settings: ['cases-settings-type', 'cases-settings-sub-type'], }, ui: ['ui-action', 'ui-sub-type'], }, @@ -818,6 +831,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-action', 'ui-sub-type'], }, @@ -860,6 +874,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -964,6 +979,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -998,6 +1014,7 @@ describe('featurePrivilegeIterator', () => { update: [], delete: [], push: [], + settings: [], }, ui: ['ui-action'], }, @@ -1038,6 +1055,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -1100,6 +1118,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -1149,6 +1168,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type', 'cases-update-sub-type'], delete: ['cases-delete-type', 'cases-delete-sub-type'], push: ['cases-push-type', 'cases-push-sub-type'], + settings: ['cases-settings-type', 'cases-settings-sub-type'], }, ui: ['ui-action', 'ui-sub-type'], }, @@ -1341,6 +1361,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -1390,6 +1411,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -1425,6 +1447,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-sub-type'], delete: ['cases-delete-sub-type'], push: ['cases-push-sub-type'], + settings: ['cases-settings-sub-type'], }, ui: ['ui-sub-type'], }, @@ -1465,6 +1488,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -1555,6 +1579,7 @@ describe('featurePrivilegeIterator', () => { update: ['cases-update-type'], delete: ['cases-delete-type'], push: ['cases-push-type'], + settings: ['cases-settings-type'], }, ui: ['ui-action'], }, @@ -1589,6 +1614,7 @@ describe('featurePrivilegeIterator', () => { update: [], delete: [], push: [], + settings: [], }, ui: ['ui-action'], }, diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts index 9392b3b3fee3..0d1dc8e3ab78 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts @@ -147,6 +147,10 @@ function mergeWithSubFeatures( subFeaturePrivilege.cases?.delete ?? [] ), push: mergeArrays(mergedConfig.cases?.push ?? [], subFeaturePrivilege.cases?.push ?? []), + settings: mergeArrays( + mergedConfig.cases?.settings ?? [], + subFeaturePrivilege.cases?.settings ?? [] + ), }; } return mergedConfig; diff --git a/x-pack/plugins/features/server/feature_registry.test.ts b/x-pack/plugins/features/server/feature_registry.test.ts index d3021bf33947..e0d0591c67d8 100644 --- a/x-pack/plugins/features/server/feature_registry.test.ts +++ b/x-pack/plugins/features/server/feature_registry.test.ts @@ -52,7 +52,7 @@ describe('FeatureRegistry', () => { app: ['app1'], savedObject: { all: ['space', 'etc', 'telemetry'], - read: ['canvas', 'config', 'url'], + read: ['canvas', 'config', 'config-global', 'url'], }, api: ['someApiEndpointTag', 'anotherEndpointTag'], ui: ['allowsFoo', 'showBar', 'showBaz'], @@ -60,7 +60,7 @@ describe('FeatureRegistry', () => { read: { savedObject: { all: [], - read: ['config', 'url', 'telemetry'], + read: ['config', 'config-global', 'url', 'telemetry'], }, ui: [], }, @@ -125,7 +125,7 @@ describe('FeatureRegistry', () => { app: ['app1'], savedObject: { all: ['space', 'etc', 'telemetry'], - read: ['canvas', 'config', 'url'], + read: ['canvas', 'config', 'config-global', 'url'], }, api: ['someApiEndpointTag', 'anotherEndpointTag'], ui: ['allowsFoo', 'showBar', 'showBaz'], @@ -290,7 +290,7 @@ describe('FeatureRegistry', () => { expect(allPrivilege?.savedObject.all).toEqual(['telemetry']); }); - it(`automatically grants access to config, url, and telemetry saved objects`, () => { + it(`automatically grants access to config, config-global, url, and telemetry saved objects`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -324,11 +324,16 @@ describe('FeatureRegistry', () => { const allPrivilege = result[0].privileges?.all; const readPrivilege = result[0].privileges?.read; - expect(allPrivilege?.savedObject.read).toEqual(['config', 'url']); - expect(readPrivilege?.savedObject.read).toEqual(['config', 'telemetry', 'url']); + expect(allPrivilege?.savedObject.read).toEqual(['config', 'config-global', 'url']); + expect(readPrivilege?.savedObject.read).toEqual([ + 'config', + 'config-global', + 'telemetry', + 'url', + ]); }); - it(`automatically grants 'all' access to telemetry and 'read' to [config, url] saved objects for the reserved privilege`, () => { + it(`automatically grants 'all' access to telemetry and 'read' to [config, config-global, url] saved objects for the reserved privilege`, () => { const feature: KibanaFeatureConfig = { id: 'test-feature', name: 'Test Feature', @@ -359,7 +364,7 @@ describe('FeatureRegistry', () => { const reservedPrivilege = result[0]!.reserved!.privileges[0].privilege; expect(reservedPrivilege.savedObject.all).toEqual(['telemetry']); - expect(reservedPrivilege.savedObject.read).toEqual(['config', 'url']); + expect(reservedPrivilege.savedObject.read).toEqual(['config', 'config-global', 'url']); }); it(`does not duplicate the automatic grants if specified on the incoming feature`, () => { @@ -373,14 +378,14 @@ describe('FeatureRegistry', () => { ui: [], savedObject: { all: ['telemetry'], - read: ['config', 'url'], + read: ['config', 'config-global', 'url'], }, }, read: { ui: [], savedObject: { all: [], - read: ['config', 'url'], + read: ['config', 'config-global', 'url'], }, }, }, @@ -397,8 +402,13 @@ describe('FeatureRegistry', () => { const allPrivilege = result[0].privileges!.all; const readPrivilege = result[0].privileges!.read; expect(allPrivilege?.savedObject.all).toEqual(['telemetry']); - expect(allPrivilege?.savedObject.read).toEqual(['config', 'url']); - expect(readPrivilege?.savedObject.read).toEqual(['config', 'url', 'telemetry']); + expect(allPrivilege?.savedObject.read).toEqual(['config', 'config-global', 'url']); + expect(readPrivilege?.savedObject.read).toEqual([ + 'config', + 'config-global', + 'url', + 'telemetry', + ]); }); it(`does not allow duplicate features to be registered`, () => { @@ -484,7 +494,7 @@ describe('FeatureRegistry', () => { name: 'Foo', app: ['app1', 'app2'], savedObject: { - all: ['config', 'space', 'etc'], + all: ['config', 'config-global', 'space', 'etc'], read: ['canvas'], }, api: ['someApiEndpointTag', 'anotherEndpointTag'], diff --git a/x-pack/plugins/features/server/feature_registry.ts b/x-pack/plugins/features/server/feature_registry.ts index cbcd426f6acc..40c278b2fe4e 100644 --- a/x-pack/plugins/features/server/feature_registry.ts +++ b/x-pack/plugins/features/server/feature_registry.ts @@ -118,7 +118,12 @@ function applyAutomaticAllPrivilegeGrants( allPrivileges.forEach((allPrivilege) => { if (allPrivilege) { allPrivilege.savedObject.all = uniq([...allPrivilege.savedObject.all, 'telemetry']); - allPrivilege.savedObject.read = uniq([...allPrivilege.savedObject.read, 'config', 'url']); + allPrivilege.savedObject.read = uniq([ + ...allPrivilege.savedObject.read, + 'config', + 'config-global', + 'url', + ]); } }); } @@ -131,6 +136,7 @@ function applyAutomaticReadPrivilegeGrants( readPrivilege.savedObject.read = uniq([ ...readPrivilege.savedObject.read, 'config', + 'config-global', 'telemetry', 'url', ]); diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index 416a9bf534b3..b332ea355dcc 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -82,6 +82,7 @@ const casesSchemaObject = schema.maybe( update: schema.maybe(casesSchema), delete: schema.maybe(casesSchema), push: schema.maybe(casesSchema), + settings: schema.maybe(casesSchema), }) ); diff --git a/x-pack/plugins/fleet/.storybook/context/ui_settings.ts b/x-pack/plugins/fleet/.storybook/context/ui_settings.ts index b5757c84875f..6dec0c3764d5 100644 --- a/x-pack/plugins/fleet/.storybook/context/ui_settings.ts +++ b/x-pack/plugins/fleet/.storybook/context/ui_settings.ts @@ -26,6 +26,9 @@ const uiSettings: IUiSettingsClient = { set: async () => true, getUpdate$: () => of({ key: 'setting', newValue: get('setting'), oldValue: get('setting') }), getUpdateErrors$: () => of(new Error()), + validateValue: async () => { + return { successfulValidation: true, valid: true }; + }, }; export const getUiSettings = () => uiSettings; diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index ca14d612ffea..3c275f87e1ae 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -55,3 +55,5 @@ export const FLEET_SERVER_INDICES = [ export const DATA_TIERS = ['data_hot']; export const FLEET_ENROLLMENT_API_PREFIX = 'fleet-enrollment-api-keys'; + +export * from './mappings'; diff --git a/x-pack/plugins/fleet/common/constants/mappings.ts b/x-pack/plugins/fleet/common/constants/mappings.ts new file mode 100644 index 000000000000..f869889bf6cd --- /dev/null +++ b/x-pack/plugins/fleet/common/constants/mappings.ts @@ -0,0 +1,374 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * ATTENTION: Mappings for Fleet are defined in the ElasticSearch repo. + * + * The following mappings declared here closely mirror them + * But they are only used to perform validation on the endpoints using ListWithKuery + * They're needed to perform searches on these mapping trough the KQL searchboxes in the UI. + * Whenever a field is added on any of these mappings in ES, make sure to add it here as well + */ + +export const AGENT_POLICY_MAPPINGS = { + properties: { + agent_features: { + properties: { + name: { type: 'keyword' }, + enabled: { type: 'boolean' }, + }, + }, + data_output_id: { type: 'keyword' }, + description: { type: 'text' }, + download_source_id: { type: 'keyword' }, + fleet_server_host_id: { type: 'keyword' }, + inactivity_timeout: { type: 'integer' }, + is_default: { type: 'boolean' }, + is_default_fleet_server: { type: 'boolean' }, + is_managed: { type: 'boolean' }, + is_preconfigured: { type: 'keyword' }, + is_protected: { type: 'boolean' }, + monitoring_enabled: { type: 'keyword', index: false }, + monitoring_output_id: { type: 'keyword' }, + name: { type: 'keyword' }, + namespace: { type: 'keyword' }, + revision: { type: 'integer' }, + schema_version: { type: 'version' }, + status: { type: 'keyword' }, + unenroll_timeout: { type: 'integer' }, + updated_at: { type: 'date' }, + updated_by: { type: 'keyword' }, + }, +} as const; + +export const PACKAGE_POLICIES_MAPPINGS = { + properties: { + name: { type: 'keyword' }, + description: { type: 'text' }, + namespace: { type: 'keyword' }, + enabled: { type: 'boolean' }, + is_managed: { type: 'boolean' }, + policy_id: { type: 'keyword' }, + package: { + properties: { + name: { type: 'keyword' }, + title: { type: 'keyword' }, + version: { type: 'keyword' }, + }, + }, + elasticsearch: { + dynamic: false, + properties: {}, + }, + vars: { type: 'flattened' }, + inputs: { + dynamic: false, + properties: {}, + }, + secret_references: { properties: { id: { type: 'keyword' } } }, + revision: { type: 'integer' }, + updated_at: { type: 'date' }, + updated_by: { type: 'keyword' }, + created_at: { type: 'date' }, + created_by: { type: 'keyword' }, + }, +} as const; + +export const AGENT_MAPPINGS = { + properties: { + access_api_key_id: { + type: 'keyword', + }, + action_seq_no: { + type: 'integer', + }, + active: { + type: 'boolean', + }, + agent: { + properties: { + id: { + type: 'keyword', + }, + version: { + type: 'keyword', + }, + }, + }, + default_api_key: { + type: 'keyword', + }, + default_api_key_id: { + type: 'keyword', + }, + enrollment_id: { + type: 'keyword', + }, + enrolled_at: { + type: 'date', + }, + last_checkin: { + type: 'date', + }, + last_checkin_message: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + last_checkin_status: { + type: 'keyword', + }, + last_updated: { + type: 'date', + }, + local_metadata: { + properties: { + elastic: { + properties: { + agent: { + properties: { + build: { + properties: { + original: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, + id: { + type: 'keyword', + }, + log_level: { + type: 'keyword', + }, + snapshot: { + type: 'boolean', + }, + upgradeable: { + type: 'boolean', + }, + version: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, + }, + }, + host: { + properties: { + architecture: { + type: 'keyword', + }, + hostname: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + id: { + type: 'keyword', + }, + ip: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + mac: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + name: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, + os: { + properties: { + family: { + type: 'keyword', + }, + full: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + kernel: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + name: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + platform: { + type: 'keyword', + }, + version: { + type: 'text', + properties: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, + }, + }, + packages: { + type: 'keyword', + }, + policy_output_permissions_hash: { + type: 'keyword', + }, + policy_coordinator_idx: { + type: 'integer', + }, + policy_id: { + type: 'keyword', + }, + policy_revision_idx: { + type: 'integer', + }, + type: { + type: 'keyword', + }, + tags: { + type: 'keyword', + }, + unenrolled_at: { + type: 'date', + }, + unenrollment_started_at: { + type: 'date', + }, + unenrolled_reason: { + type: 'keyword', + }, + updated_at: { + type: 'date', + }, + upgrade_started_at: { + type: 'date', + }, + upgraded_at: { + type: 'date', + }, + upgrade_status: { + type: 'keyword', + }, + upgrade_details: { + properties: { + target_version: { + type: 'text', + fields: { + keyword: { + type: 'keyword', + }, + }, + }, + action_id: { + type: 'keyword', + }, + state: { + type: 'keyword', + }, + metadata: { + properties: { + scheduled_at: { + type: 'date', + }, + download_percent: { + type: 'double', + }, + failed_state: { + type: 'keyword', + }, + error_msg: { + type: 'text', + fields: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, + }, + }, + // added to allow validation on status field + status: { + type: 'keyword', + }, + }, +} as const; + +export const ENROLLMENT_API_KEY_MAPPINGS = { + properties: { + active: { + type: 'boolean', + }, + api_key: { + type: 'keyword', + }, + api_key_id: { + type: 'keyword', + }, + created_at: { + type: 'date', + }, + expire_at: { + type: 'date', + }, + name: { + type: 'keyword', + }, + policy_id: { + type: 'keyword', + }, + updated_at: { + type: 'date', + }, + }, +} as const; diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index e0b754430521..102a80ad003f 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -6069,6 +6069,35 @@ "install_format_schema_version": { "type": "string" }, + "latest_install_failed_attempts": { + "description": "Latest failed install errors", + "type": "array", + "items": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "target_version": { + "type": "string" + }, + "error": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "message": { + "type": "string" + }, + "stack": { + "type": "string" + } + } + } + } + } + }, "verification_status": { "type": "string", "enum": [ @@ -6120,7 +6149,8 @@ "install_version", "install_started_at", "install_source", - "verification_status" + "verification_status", + "latest_install_failed_attempts" ] }, "search_result": { @@ -8257,6 +8287,50 @@ "type" ] }, + "output_create_request_remote_elasticsearch": { + "title": "remote_elasticsearch", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "is_default": { + "type": "boolean" + }, + "is_default_monitoring": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "remote_elasticsearch" + ] + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + }, + "service_token": { + "type": "string" + }, + "secrets": { + "type": "object", + "properties": { + "service_token": { + "type": "string" + } + } + } + }, + "required": [ + "name" + ] + }, "output_create_request": { "title": "Output", "oneOf": [ @@ -8268,6 +8342,9 @@ }, { "$ref": "#/components/schemas/output_create_request_logstash" + }, + { + "$ref": "#/components/schemas/output_create_request_remote_elasticsearch" } ], "discriminator": { @@ -8275,7 +8352,8 @@ "mapping": { "elasticsearch": "#/components/schemas/output_create_request_elasticsearch", "kafka": "#/components/schemas/output_create_request_kafka", - "logstash": "#/components/schemas/output_create_request_logstash" + "logstash": "#/components/schemas/output_create_request_logstash", + "remote_elasticsearch": "#/components/schemas/output_create_request_remote_elasticsearch" } } }, diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index d977af4f9c2b..2e47aaf00306 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -3824,6 +3824,25 @@ components: type: string install_format_schema_version: type: string + latest_install_failed_attempts: + description: Latest failed install errors + type: array + items: + type: object + properties: + created_at: + type: string + target_version: + type: string + error: + type: object + properties: + name: + type: string + message: + type: string + stack: + type: string verification_status: type: string enum: @@ -3863,6 +3882,7 @@ components: - install_started_at - install_source - verification_status + - latest_install_failed_attempts search_result: title: Search result type: object @@ -5331,18 +5351,49 @@ components: - name - hosts - type + output_create_request_remote_elasticsearch: + title: remote_elasticsearch + type: object + properties: + id: + type: string + is_default: + type: boolean + is_default_monitoring: + type: boolean + name: + type: string + type: + type: string + enum: + - remote_elasticsearch + hosts: + type: array + items: + type: string + service_token: + type: string + secrets: + type: object + properties: + service_token: + type: string + required: + - name output_create_request: title: Output oneOf: - $ref: '#/components/schemas/output_create_request_elasticsearch' - $ref: '#/components/schemas/output_create_request_kafka' - $ref: '#/components/schemas/output_create_request_logstash' + - $ref: '#/components/schemas/output_create_request_remote_elasticsearch' discriminator: propertyName: type mapping: elasticsearch: '#/components/schemas/output_create_request_elasticsearch' kafka: '#/components/schemas/output_create_request_kafka' logstash: '#/components/schemas/output_create_request_logstash' + remote_elasticsearch: '#/components/schemas/output_create_request_remote_elasticsearch' output_update_request_elasticsearch: title: elasticsearch type: object diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml index 4d13611a6afb..c5db5f12d4cc 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml @@ -47,6 +47,25 @@ properties: type: string install_format_schema_version: type: string + latest_install_failed_attempts: + description: Latest failed install errors + type: array + items: + type: object + properties: + created_at: + type: string + target_version: + type: string + error: + type: object + properties: + name: + type: string + message: + type: string + stack: + type: string verification_status: type: string enum: @@ -86,3 +105,4 @@ required: - install_started_at - install_source - verification_status + - latest_install_failed_attempts diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request.yaml index 21506825cfd6..9fc0ad6d2459 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request.yaml @@ -3,9 +3,11 @@ oneOf: - $ref: './output_create_request_elasticsearch.yaml' - $ref: './output_create_request_kafka.yaml' - $ref: './output_create_request_logstash.yaml' + - $ref: './output_create_request_remote_elasticsearch.yaml' discriminator: propertyName: type mapping: elasticsearch: './output_create_request_elasticsearch.yaml' kafka: './output_create_request_kafka.yaml' logstash: './output_create_request_logstash.yaml' + remote_elasticsearch: './output_create_request_remote_elasticsearch.yaml' diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_remote_elasticsearch.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_remote_elasticsearch.yaml new file mode 100644 index 000000000000..844b92df39b8 --- /dev/null +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/output_create_request_remote_elasticsearch.yaml @@ -0,0 +1,27 @@ +title: remote_elasticsearch +type: object +properties: + id: + type: string + is_default: + type: boolean + is_default_monitoring: + type: boolean + name: + type: string + type: + type: string + enum: ['remote_elasticsearch'] + hosts: + type: array + items: + type: string + service_token: + type: string + secrets: + type: object + properties: + service_token: + type: string +required: + - name diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index c4d4e9c76376..24bde5b5f5f5 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -530,6 +530,16 @@ export interface ExperimentalDataStreamFeature { features: Partial>; } +export interface InstallFailedAttempt { + created_at: string; + target_version: string; + error: { + name: string; + message: string; + stack?: string; + }; +} + export interface Installation { installed_kibana: KibanaAssetReference[]; installed_es: EsAssetReference[]; @@ -549,6 +559,7 @@ export interface Installation { experimental_data_stream_features?: ExperimentalDataStreamFeature[]; internal?: boolean; removable?: boolean; + latest_install_failed_attempts?: InstallFailedAttempt[]; } export interface PackageUsageStats { diff --git a/x-pack/plugins/fleet/common/types/models/output.ts b/x-pack/plugins/fleet/common/types/models/output.ts index 3283f4d01e54..8d721509495e 100644 --- a/x-pack/plugins/fleet/common/types/models/output.ts +++ b/x-pack/plugins/fleet/common/types/models/output.ts @@ -23,7 +23,12 @@ export type KafkaPartitionType = typeof kafkaPartitionType; export type KafkaTopicWhenType = typeof kafkaTopicWhenType; export type KafkaAcknowledgeReliabilityLevel = typeof kafkaAcknowledgeReliabilityLevel; export type KafkaVerificationMode = typeof kafkaVerificationModes; - +export type OutputSecret = + | string + | { + id: string; + hash?: string; + }; interface NewBaseOutput { is_default: boolean; is_default_monitoring: boolean; @@ -43,15 +48,7 @@ interface NewBaseOutput { proxy_id?: string | null; shipper?: ShipperOutput | null; allow_edit?: string[]; - secrets?: { - ssl?: { - key?: - | string - | { - id: string; - }; - }; - }; + secrets?: {}; } export interface NewElasticsearchOutput extends NewBaseOutput { @@ -61,10 +58,18 @@ export interface NewElasticsearchOutput extends NewBaseOutput { export interface NewRemoteElasticsearchOutput extends NewBaseOutput { type: OutputType['RemoteElasticsearch']; service_token?: string; + secrets?: { + service_token?: OutputSecret; + }; } export interface NewLogstashOutput extends NewBaseOutput { type: OutputType['Logstash']; + secrets?: { + ssl?: { + key?: OutputSecret; + }; + }; } export type NewOutput = @@ -131,17 +136,9 @@ export interface KafkaOutput extends NewBaseOutput { broker_timeout?: number; required_acks?: ValueOf; secrets?: { - password?: - | string - | { - id: string; - }; + password?: OutputSecret; ssl?: { - key?: - | string - | { - id: string; - }; + key?: OutputSecret; }; }; } diff --git a/x-pack/plugins/fleet/cypress/tasks/common.ts b/x-pack/plugins/fleet/cypress/tasks/common.ts index ebb631b310b1..6d922f6b003f 100644 --- a/x-pack/plugins/fleet/cypress/tasks/common.ts +++ b/x-pack/plugins/fleet/cypress/tasks/common.ts @@ -49,6 +49,7 @@ export const request = ({ const NEW_FEATURES_TOUR_STORAGE_KEYS = { RULE_MANAGEMENT_PAGE: 'securitySolution.rulesManagementPage.newFeaturesTour.v8.9', + TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour', }; const disableNewFeaturesTours = (window: Window) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx index 5478aca7c5ba..ebbbeb0814bc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx @@ -6,12 +6,20 @@ */ import React from 'react'; +import { act } from '@testing-library/react'; import type { FieldSpec } from '@kbn/data-plugin/common'; import { createFleetTestRendererMock } from '../../../mock'; -import { SearchBar, filterAndConvertFields } from './search_bar'; +import { + AGENTS_PREFIX, + FLEET_ENROLLMENT_API_PREFIX, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + AGENT_POLICY_SAVED_OBJECT_TYPE, +} from '../constants'; + +import { SearchBar, getFieldSpecs } from './search_bar'; const fields = [ { @@ -36,39 +44,6 @@ const fields = [ }, ] as FieldSpec[]; -const allFields = [ - { - name: 'test-index._id', - type: 'string', - esTypes: ['_id'], - }, - { - name: 'test-index.api_key', - type: 'string', - esTypes: ['keyword'], - }, - { - name: 'test-index.name', - type: 'string', - esTypes: ['keyword'], - }, - { - name: 'another-index.version', - type: 'string', - esTypes: ['keyword'], - }, - { - name: 'test2-index.name', - type: 'string', - esTypes: ['keyword'], - }, - { - name: 'fleet-agents.actions', - type: 'string', - esTypes: ['keyword'], - }, -] as FieldSpec[]; - jest.mock('../hooks', () => { return { ...jest.requireActual('../hooks'), @@ -87,23 +62,6 @@ jest.mock('../hooks', () => { }, data: { dataViews: { - getFieldsForWildcard: jest.fn().mockResolvedValue([ - { - name: '_id', - type: 'string', - esTypes: ['_id'], - }, - { - name: 'api_key', - type: 'string', - esTypes: ['keyword'], - }, - { - name: 'name', - type: 'string', - esTypes: ['keyword'], - }, - ]), create: jest.fn().mockResolvedValue({ fields, }), @@ -197,6 +155,9 @@ describe('SearchBar', () => { ); it('renders the search box', async () => { + await act(async () => { + result.queryByTestId('queryInput'); + }); const textArea = result.queryByTestId('queryInput'); expect(textArea).not.toBeNull(); expect(textArea?.getAttribute('placeholder')).toEqual('Filter your data using KQL syntax'); @@ -207,60 +168,243 @@ describe('SearchBar', () => { }); }); -describe('filterAndConvertFields', () => { - it('leaves the fields names unchanged and does not hide any fields if fieldPrefix is not passed', async () => { - expect(filterAndConvertFields(fields, '.test-index')).toEqual({ - _id: { esTypes: ['_id'], name: '_id', type: 'string' }, - api_key: { esTypes: ['keyword'], name: 'api_key', type: 'string' }, - name: { esTypes: ['keyword'], name: 'name', type: 'string' }, - version: { esTypes: ['keyword'], name: 'version', type: 'string' }, - }); +describe('getFieldSpecs', () => { + it('returns fieldSpecs for fleet-agents', () => { + expect(getFieldSpecs(`.${AGENTS_PREFIX}`)).toHaveLength(66); }); - - it('filters out the fields from other indices if indexPattern === .kibana-ingest', async () => { - expect(filterAndConvertFields(allFields, '.kibana_ingest', 'test-index')).toEqual({ - 'test-index._id': { esTypes: ['_id'], name: 'test-index._id', type: 'string' }, - 'test-index.api_key': { esTypes: ['keyword'], name: 'test-index.api_key', type: 'string' }, - 'test-index.name': { esTypes: ['keyword'], name: 'test-index.name', type: 'string' }, - }); + it('returns getFieldSpecs for fleet-enrollment-api-keys', () => { + const indexPattern = `.${FLEET_ENROLLMENT_API_PREFIX}`; + expect(getFieldSpecs(indexPattern)).toHaveLength(8); + expect(getFieldSpecs(indexPattern)).toEqual([ + { + aggregatable: true, + esTypes: ['boolean'], + name: 'active', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'api_key', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'api_key_id', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['date'], + name: 'created_at', + searchable: true, + type: 'date', + }, + { + aggregatable: true, + esTypes: ['date'], + name: 'expire_at', + searchable: true, + type: 'date', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'name', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'policy_id', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['date'], + name: 'updated_at', + searchable: true, + type: 'date', + }, + ]); }); - it('returns fields unchanged if fieldPrefix and indexPattern are not passed', async () => { - expect(filterAndConvertFields(allFields, undefined, undefined)).toEqual({ - 'another-index.version': { + it('returns getFieldSpecs for fleet-agent-policy', () => { + const indexPattern = `.${AGENT_POLICY_SAVED_OBJECT_TYPE}`; + expect(getFieldSpecs(indexPattern)).toHaveLength(23); + expect(getFieldSpecs(indexPattern)).toEqual([ + { + aggregatable: true, esTypes: ['keyword'], - name: 'another-index.version', + name: 'agent_features.name', + searchable: true, type: 'string', }, - 'fleet-agents.actions': { + { + aggregatable: true, + esTypes: ['boolean'], + name: 'agent_features.enabled', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, esTypes: ['keyword'], - name: 'fleet-agents.actions', + name: 'data_output_id', + searchable: true, type: 'string', }, - 'test-index._id': { - esTypes: ['_id'], - name: 'test-index._id', + { + aggregatable: true, + esTypes: ['text'], + name: 'description', + searchable: true, type: 'string', }, - 'test-index.api_key': { + { + aggregatable: true, esTypes: ['keyword'], - name: 'test-index.api_key', + name: 'download_source_id', + searchable: true, type: 'string', }, - 'test-index.name': { + { + aggregatable: true, + esTypes: ['keyword'], + name: 'fleet_server_host_id', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['integer'], + name: 'inactivity_timeout', + searchable: true, + type: 'number', + }, + { + aggregatable: true, + esTypes: ['boolean'], + name: 'is_default', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, + esTypes: ['boolean'], + name: 'is_default_fleet_server', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, + esTypes: ['boolean'], + name: 'is_managed', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, esTypes: ['keyword'], - name: 'test-index.name', + name: 'is_preconfigured', + searchable: true, type: 'string', }, - 'test2-index.name': { + { + aggregatable: true, + esTypes: ['boolean'], + name: 'is_protected', + searchable: true, + type: 'boolean', + }, + { + aggregatable: true, esTypes: ['keyword'], - name: 'test2-index.name', + name: 'monitoring_enabled', + searchable: true, type: 'string', }, - }); + { + aggregatable: true, + esTypes: ['false'], + name: 'monitoring_enabled.index', + searchable: true, + type: 'false', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'monitoring_output_id', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'name', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'namespace', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['integer'], + name: 'revision', + searchable: true, + type: 'number', + }, + { + aggregatable: true, + esTypes: ['version'], + name: 'schema_version', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'status', + searchable: true, + type: 'string', + }, + { + aggregatable: true, + esTypes: ['integer'], + name: 'unenroll_timeout', + searchable: true, + type: 'number', + }, + { + aggregatable: true, + esTypes: ['date'], + name: 'updated_at', + searchable: true, + type: 'date', + }, + { + aggregatable: true, + esTypes: ['keyword'], + name: 'updated_by', + searchable: true, + type: 'string', + }, + ]); }); + expect(getFieldSpecs(`.${PACKAGE_POLICY_SAVED_OBJECT_TYPE}`)).toHaveLength(18); - it('returns empty object if fields is empty', async () => { - expect(filterAndConvertFields([], '.kibana_ingest', 'test-index')).toEqual({}); + it('returns empty array if indexPattern is not one of the previous', async () => { + expect(getFieldSpecs('.kibana_ingest')).toEqual([]); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index 5e610a46e3f3..6f23d25f3812 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -16,9 +16,19 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { i18n } from '@kbn/i18n'; import { useStartServices } from '../hooks'; -import { INDEX_NAME, AGENTS_PREFIX } from '../constants'; - -const HIDDEN_FIELDS = [`${AGENTS_PREFIX}.actions`, '_id', '_index']; +import { + INDEX_NAME, + AGENTS_PREFIX, + FLEET_ENROLLMENT_API_PREFIX, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + AGENT_POLICY_SAVED_OBJECT_TYPE, +} from '../constants'; +import { + AGENT_POLICY_MAPPINGS, + PACKAGE_POLICIES_MAPPINGS, + AGENT_MAPPINGS, + ENROLLMENT_API_KEY_MAPPINGS, +} from '../../../../common/constants'; const NoWrapQueryStringInput = styled(QueryStringInput)` .kbnQueryBar__textarea { @@ -35,39 +45,69 @@ interface Props { dataTestSubj?: string; } -/** Exported for testing only **/ -export const filterAndConvertFields = ( - fields: FieldSpec[], - indexPattern?: string, - fieldPrefix?: string -) => { - if (!fields) return {}; - let filteredFields: FieldSpec[] = []; - - if (fieldPrefix) { - // exclude fields from different indices - if (indexPattern === INDEX_NAME) { - filteredFields = fields.filter((field) => field.name.startsWith(fieldPrefix)); +const getMappings = (indexPattern: string) => { + switch (indexPattern) { + case `.${AGENTS_PREFIX}`: + return AGENT_MAPPINGS; + case `.${AGENT_POLICY_SAVED_OBJECT_TYPE}`: + return AGENT_POLICY_MAPPINGS; + case `.${PACKAGE_POLICY_SAVED_OBJECT_TYPE}`: + return PACKAGE_POLICIES_MAPPINGS; + case `.${FLEET_ENROLLMENT_API_PREFIX}`: + return ENROLLMENT_API_KEY_MAPPINGS; + default: + return {}; + } +}; + +const getType = (type: string) => { + switch (type) { + case 'keyword': + return 'string'; + case 'text': + return 'string'; + case 'version': + return 'string'; + case 'integer': + return 'number'; + case 'double': + return 'number'; + default: + return type; + } +}; + +const concatKeys = (obj: any, parentKey = '') => { + let result: string[] = []; + for (const key in obj) { + if (typeof obj[key] === 'object') { + result = result.concat(concatKeys(obj[key], `${parentKey}${key}.`)); } else { - // filter out fields that have names to be hidden - filteredFields = fields.filter((field) => { - for (const hiddenField of HIDDEN_FIELDS) { - if (field.name.includes(hiddenField)) { - return false; - } - } - return true; - }); + result.push(`${parentKey}${key}:${obj[key]}`); } - } else { - filteredFields = fields; } - - const fieldsMap = filteredFields.reduce((acc: Record, curr: FieldSpec) => { - acc[curr.name] = curr; - return acc; - }, {}); - return fieldsMap; + return result; +}; +/** Exported for testing only **/ +export const getFieldSpecs = (indexPattern: string) => { + const mapping = getMappings(indexPattern); + // @ts-ignore-next-line + const rawFields = concatKeys(mapping?.properties) || []; + const fields = rawFields + .map((field) => field.replaceAll(/.properties/g, '')) + .map((field) => field.replace(/.type/g, '')) + .map((field) => field.split(':')); + + const fieldSpecs: FieldSpec[] = fields.map((field) => { + return { + name: field[0], + type: getType(field[1]), + searchable: true, + aggregatable: true, + esTypes: [field[1]], + }; + }); + return fieldSpecs; }; export const SearchBar: React.FunctionComponent = ({ @@ -108,16 +148,11 @@ export const SearchBar: React.FunctionComponent = ({ useEffect(() => { const fetchFields = async () => { try { - const fields: FieldSpec[] = await data.dataViews.getFieldsForWildcard({ - pattern: indexPattern, - }); - const fieldsMap = filterAndConvertFields(fields, indexPattern, fieldPrefix); - // Refetch only if fieldsMap is empty - const skipFetchField = !!fieldsMap; - + const fieldSpecs = getFieldSpecs(indexPattern); + const fieldsMap = data.dataViews.fieldArrayToMap(fieldSpecs); const newDataView = await data.dataViews.create( { title: indexPattern, fields: fieldsMap }, - skipFetchField + true ); setDataView(newDataView); } catch (err) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx index 1deb84143d2a..9321f7788608 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_var_field.tsx @@ -23,11 +23,16 @@ import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, + EuiLink, + EuiToolTip, + EuiIcon, } from '@elastic/eui'; import styled from 'styled-components'; import { CodeEditor } from '@kbn/kibana-react-plugin/public'; +import { useStartServices } from '../../../../../../../../hooks'; + import { ExperimentalFeaturesService } from '../../../../../../services'; import { DATASET_VAR_NAME } from '../../../../../../../../../common/constants'; @@ -41,6 +46,16 @@ const FixedHeightDiv = styled.div` height: 300px; `; +const FormRow = styled(EuiFormRow)` + .euiFormRow__label { + flex: 1; + } + + .euiFormRow__fieldWrapper > .euiPanel { + padding: ${(props) => props.theme.eui.euiSizeXS}; + } +`; + interface InputFieldProps { varDef: RegistryVarsEntry; value: any; @@ -125,11 +140,11 @@ export const PackagePolicyInputVarField: React.FunctionComponent : fieldLabel} labelAppend={ isOptional ? ( @@ -138,13 +153,16 @@ export const PackagePolicyInputVarField: React.FunctionComponent - ) : null + ) : undefined } helpText={description && } + fullWidth > {field} - + ); + + return varDef.secret ? {formRow} : formRow; } ); @@ -296,6 +314,53 @@ function getInputComponent({ } } +const SecretFieldWrapper = ({ children }: { children: React.ReactNode }) => { + const { docLinks } = useStartServices(); + + return ( + + {children} + + + + + + + + + + ); +}; + +const SecretFieldLabel = ({ fieldLabel }: { fieldLabel: string }) => { + return ( + <> + + + {fieldLabel} + + + + } + > + + + + + + + + ); +}; + function SecretInputField({ varDef, value, @@ -311,12 +376,39 @@ function SecretInputField({ setIsDirty, isDirty, }: InputComponentProps) { - const [editMode, setEditMode] = useState(isEditPage && !value); + const [isReplacing, setIsReplacing] = useState(isEditPage && !value); const valueOnFirstRender = useRef(value); + + const hasExistingValue = !!valueOnFirstRender.current; const lowercaseTitle = varDef.title?.toLowerCase(); - if (isEditPage && !editMode) { + const showInactiveReplaceUi = isEditPage && !isReplacing && hasExistingValue; + const valueIsSecretRef = value && value?.isSecretRef; + + const inputComponent = getInputComponent({ + varDef, + value: isReplacing && valueIsSecretRef ? '' : value, + onChange, + frozen, + packageName, + packageType, + datastreams, + isEditPage, + isInvalid, + fieldLabel, + fieldTestSelector, + isDirty, + setIsDirty, + }); + + // If there's no value for this secret, display the input as its "brand new" creation state + // instead of the "replace" state + if (!hasExistingValue) { + return inputComponent; + } + + if (showInactiveReplaceUi) { return ( - + <> setEditMode(true)} + onClick={() => setIsReplacing(true)} color="primary" iconType="refresh" iconSide="left" @@ -342,32 +434,15 @@ function SecretInputField({ }} /> - + ); } - const valueIsSecretRef = value && value?.isSecretRef; - const field = getInputComponent({ - varDef, - value: editMode && valueIsSecretRef ? '' : value, - onChange, - frozen, - packageName, - packageType, - datastreams, - isEditPage, - isInvalid, - fieldLabel, - fieldTestSelector, - isDirty, - setIsDirty, - }); - - if (editMode) { + if (isReplacing) { const cancelButton = ( { - setEditMode(false); + setIsReplacing(false); setIsDirty(false); onChange(valueOnFirstRender.current); }} @@ -388,12 +463,12 @@ function SecretInputField({ return ( - {field} + {inputComponent} {cancelButton} ); } - return field; + return inputComponent; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/upgrade.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/upgrade.tsx index 99eba56ea6a9..8f10a53afcf2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/upgrade.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/components/upgrade.tsx @@ -24,10 +24,18 @@ import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle, + EuiSpacer, } from '@elastic/eui'; import styled from 'styled-components'; +import type { + DryRunPackagePolicy, + PackagePolicy, + RegistryVarsEntry, +} from '../../../../../../../common'; + import type { UpgradePackagePolicyDryRunResponse } from '../../../../../../../common/types/rest_spec'; +import { useStartServices } from '../../../../hooks'; const FlyoutBody = styled(EuiFlyoutBody)` .euiFlyoutBody__overflowContent { @@ -35,18 +43,125 @@ const FlyoutBody = styled(EuiFlyoutBody)` } `; +const HasNewSecretsCallOut = ({ newSecrets }: { newSecrets: RegistryVarsEntry[] }) => { + const { docLinks } = useStartServices(); + + return ( + + + Learn more. + + ), + }} + /> + + + + + {newSecrets.map((secret) => ( +
  • {secret.title}
  • + ))} + + ), + }} + /> +
    + ); +}; + +const HasConflictsCallout = ({ + currentPackagePolicy, + proposedUpgradePackagePolicy, + onPreviousConfigurationClick, +}: { + currentPackagePolicy?: PackagePolicy; + proposedUpgradePackagePolicy?: DryRunPackagePolicy; + onPreviousConfigurationClick?: () => void; +}) => { + return ( + + + + + ), + }} + /> + + ); +}; + +const ReadyToUpgradeCallOut = ({ + currentPackagePolicy, + proposedUpgradePackagePolicy, +}: { + currentPackagePolicy?: PackagePolicy; + proposedUpgradePackagePolicy?: DryRunPackagePolicy; +}) => { + return ( + + + + ); +}; + export const UpgradeStatusCallout: React.FunctionComponent<{ dryRunData: UpgradePackagePolicyDryRunResponse; -}> = ({ dryRunData }) => { + newSecrets: RegistryVarsEntry[]; +}> = ({ dryRunData, newSecrets }) => { const [isPreviousVersionFlyoutOpen, setIsPreviousVersionFlyoutOpen] = useState(false); if (!dryRunData) { return null; } - const isReadyForUpgrade = !dryRunData[0].hasErrors; - + const hasNewSecrets = newSecrets.length > 0; const [currentPackagePolicy, proposedUpgradePackagePolicy] = dryRunData[0].diff || []; + const isReadyForUpgrade = currentPackagePolicy && !dryRunData[0].hasErrors; return ( <> @@ -73,48 +188,23 @@ export const UpgradeStatusCallout: React.FunctionComponent<{ )} - {isReadyForUpgrade && currentPackagePolicy ? ( - - - + {isReadyForUpgrade ? ( + ) : ( - - setIsPreviousVersionFlyoutOpen(true)}> - - - ), - }} - /> - + setIsPreviousVersionFlyoutOpen(true)} + /> + )} + {hasNewSecrets && ( + <> + + + )} ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx index 2f66c590ae3f..36b1134f9151 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx @@ -99,7 +99,9 @@ export function usePackagePolicyWithRelatedData( policy: { elasticsearch, ...restPackagePolicy }, } = await prepareInputPackagePolicyDataset(packagePolicy); const result = await sendUpdatePackagePolicy(packagePolicyId, restPackagePolicy); + setFormState('SUBMITTED'); + return result; }; // Update package policy validation diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index e3b36999ed0b..033c083882f4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -19,7 +19,6 @@ import { EuiErrorBoundary, } from '@elastic/eui'; -import type { PackageInfo } from '../../../types'; import { useLink, useBreadcrumbs, @@ -55,6 +54,7 @@ import { generateUpdatePackagePolicyDevToolsRequest } from '../services'; import { UpgradeStatusCallout } from './components'; import { usePackagePolicyWithRelatedData, useHistoryBlock } from './hooks'; +import { getNewSecrets } from './utils'; export const EditPackagePolicyPage = memo(() => { const { @@ -91,7 +91,6 @@ export const EditPackagePolicyForm = memo<{ } = useConfig(); const { getHref } = useLink(); - const [] = useState(); const { // data agentPolicy, @@ -117,6 +116,14 @@ export const EditPackagePolicyForm = memo<{ const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; + const newSecrets = useMemo(() => { + if (!packageInfo) { + return []; + } + + return getNewSecrets({ packageInfo, packagePolicy }); + }, [packageInfo, packagePolicy]); + const policyId = agentPolicy?.id ?? ''; // Retrieve agent count @@ -418,7 +425,7 @@ export const EditPackagePolicyForm = memo<{ )} {isUpgrade && upgradeDryRunData && ( <> - + )} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.test.ts new file mode 100644 index 000000000000..80ae49ed3626 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PackageInfo, UpdatePackagePolicy } from '../../../../types'; + +import { getNewSecrets } from './get_new_secrets'; + +describe('getNewSecrets', () => { + it('does not find new secrets when there are no secrets configured', () => { + const packageInfo = { + name: 'mock-package', + title: 'Mock package', + version: '0.0.0', + vars: [ + { + name: 'package-var', + type: 'string', + secret: false, + }, + ], + policy_templates: [ + { + name: 'test-policy-template', + inputs: [ + { + type: 'test-input', + title: 'Test input', + description: 'Test input', + vars: [ + { + name: 'policy-template-var', + type: 'string', + secret: false, + }, + ], + }, + ], + }, + ], + } as unknown as PackageInfo; + + const packagePolicy = { + vars: [ + { + name: 'package-var', + value: 'test', + }, + ], + inputs: [ + { + name: 'test-input', + vars: { + 'policy-template-var': { + value: 'test', + }, + }, + }, + ], + } as unknown as UpdatePackagePolicy; + + expect( + getNewSecrets({ + packageInfo, + packagePolicy, + }) + ).toEqual([]); + }); + + it('finds new secrets when they exist', () => { + const packageInfo = { + name: 'mock-package', + title: 'Mock package', + version: '0.0.0', + vars: [ + { + name: 'package-var', + type: 'string', + secret: true, + }, + ], + policy_templates: [ + { + name: 'test-policy-template', + inputs: [ + { + type: 'test-input', + title: 'Test input', + description: 'Test input', + vars: [ + { + name: 'policy-template-var', + type: 'string', + secret: true, + }, + ], + }, + ], + }, + ], + } as unknown as PackageInfo; + + const packagePolicy = { + vars: [ + { + name: 'package-var', + value: 'test', + }, + ], + inputs: [ + { + name: 'test-input', + vars: { + 'policy-template-var': { + value: 'test', + }, + }, + }, + ], + } as unknown as UpdatePackagePolicy; + + expect( + getNewSecrets({ + packageInfo, + packagePolicy, + }) + ).toEqual([ + { + name: 'package-var', + secret: true, + type: 'string', + }, + { + name: 'policy-template-var', + secret: true, + type: 'string', + }, + ]); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.ts new file mode 100644 index 000000000000..68f677bbfb89 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/get_new_secrets.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isInputOnlyPolicyTemplate } from '../../../../../../../common/services'; + +import type { PackageInfo, UpdatePackagePolicy } from '../../../../types'; + +export const getNewSecrets = ({ + packageInfo, + packagePolicy, +}: { + packageInfo: PackageInfo; + packagePolicy: UpdatePackagePolicy; +}) => { + const result = []; + + for (const packageVar of packageInfo.vars ?? []) { + const isVarSecretOnPolicy = packagePolicy.vars?.[packageVar.name]?.value?.isSecretRef; + + if (packageVar.secret && !isVarSecretOnPolicy) { + result.push(packageVar); + } + } + + for (const policyTemplate of packageInfo.policy_templates ?? []) { + if (isInputOnlyPolicyTemplate(policyTemplate)) { + for (const packageVar of policyTemplate.vars ?? []) { + const isVarSecretOnPolicy = + packagePolicy.inputs?.[0]?.vars?.[packageVar.name]?.value?.isSecretRef; + + if (packageVar.secret && !isVarSecretOnPolicy) { + result.push(packageVar); + } + } + } else { + for (const input of policyTemplate.inputs ?? []) { + for (const packageVar of input.vars ?? []) { + const isVarSecretOnPolicy = + packagePolicy.inputs?.[0]?.vars?.[packageVar.name]?.value?.isSecretRef; + + if (packageVar.secret && !isVarSecretOnPolicy) { + result.push(packageVar); + } + } + } + } + } + + return result; +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/index.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/index.ts index be01b9834a7d..5aa227e55bad 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/utils/index.ts @@ -7,3 +7,4 @@ export * from './has_upgrade_available'; export { fixApmDurationVars } from './fix_apm_duration_vars'; +export * from './get_new_secrets'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx index ab742ee54f0d..e7c691fce5ea 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx @@ -260,6 +260,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }); setSearch(newSearch); }} + indexPattern={`.${AGENT_POLICY_SAVED_OBJECT_TYPE}`} fieldPrefix={AGENT_POLICY_SAVED_OBJECT_TYPE} dataTestSubj="agentPolicyList.queryInput" /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx index 6de1a3caaa2c..6e965dc9eca6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx @@ -63,6 +63,8 @@ describe('AgentLogsUI', () => { const state = { datasets: ['elastic_agent'], logLevels: ['info', 'error'], + start: '2023-20-04T14:00:00.340Z', + end: '2023-20-04T14:20:00.340Z', query: '', } as any; return render(); @@ -97,7 +99,10 @@ describe('AgentLogsUI', () => { it('should render Open in Logs UI if capabilities not set', () => { mockStartServices(); const result = renderComponent(); - expect(result.getByTestId('viewInLogsBtn')).not.toBeNull(); + expect(result.getByTestId('viewInLogsBtn')).toHaveAttribute( + 'href', + `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-20-04T14%3A20%3A00.340Z'%2Cstart%3A'2023-20-04T14%3A00%3A00.340Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Ainfo%20or%20log.level%3Aerror)'%2Ckind%3Akuery)` + ); }); it('should render Open in Discover if serverless enabled', () => { @@ -106,7 +111,7 @@ describe('AgentLogsUI', () => { const viewInDiscover = result.getByTestId('viewInDiscoverBtn'); expect(viewInDiscover).toHaveAttribute( 'href', - `http://localhost:5620/app/discover#/?_a=(index:'logs-*',query:(language:kuery,query:'data_stream.dataset:elastic_agent%20AND%20elastic_agent.id:agent1'))` + `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-20-04T14:00:00.340Z',to:'2023-20-04T14:20:00.340Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:info or log.level:error)'))` ); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx index 8efef6592f87..05efb3abfdca 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx @@ -4,21 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import url from 'url'; -import { stringify } from 'querystring'; - import React, { memo, useMemo, useState, useCallback, useEffect } from 'react'; import styled from 'styled-components'; -import { encode } from '@kbn/rison'; import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker, EuiFilterGroup, EuiPanel, - EuiButton, - EuiButtonEmpty, EuiCallOut, EuiLink, } from '@elastic/eui'; @@ -42,6 +35,7 @@ import { LogLevelFilter } from './filter_log_level'; import { LogQueryBar } from './query_bar'; import { buildQuery } from './build_query'; import { SelectLogLevel } from './select_log_level'; +import { ViewLogsButton } from './view_logs_button'; const WrapperFlexGroup = styled(EuiFlexGroup)` height: 100%; @@ -118,7 +112,7 @@ const AgentPolicyLogsNotEnabledCallout: React.FunctionComponent<{ agentPolicy: A export const AgentLogsUI: React.FunctionComponent = memo( ({ agent, agentPolicy, state }) => { - const { data, application, http, cloud } = useStartServices(); + const { data, application, cloud } = useStartServices(); const { update: updateState } = AgentLogsUrlStateHelper.useTransitions(); const isLogsUIAvailable = !cloud?.isServerlessEnabled; @@ -218,37 +212,6 @@ export const AgentLogsUI: React.FunctionComponent = memo( [agent.id, state.datasets, state.logLevels, state.query] ); - // Generate URL to pass page state to Logs UI - const viewInLogsUrl = useMemo( - () => - http.basePath.prepend( - url.format({ - pathname: '/app/logs/stream', - search: stringify({ - logPosition: encode({ - start: state.start, - end: state.end, - streamLive: false, - }), - logFilter: encode({ - expression: logStreamQuery, - kind: 'kuery', - }), - }), - }) - ), - [http.basePath, state.start, state.end, logStreamQuery] - ); - - const viewInDiscoverUrl = useMemo(() => { - const index = 'logs-*'; - const datasetQuery = 'data_stream.dataset:elastic_agent'; - const agentIdQuery = `elastic_agent.id:${agent.id}`; - return http.basePath.prepend( - `/app/discover#/?_a=(index:'${index}',query:(language:kuery,query:'${datasetQuery}%20AND%20${agentIdQuery}'))` - ); - }, [http.basePath, agent.id]); - const agentVersion = agent.local_metadata?.elastic?.agent?.version; const isLogFeatureAvailable = useMemo(() => { if (!agentVersion) { @@ -357,30 +320,12 @@ export const AgentLogsUI: React.FunctionComponent = memo( application, }} > - {isLogsUIAvailable ? ( - - - - ) : ( - - - - )} +
    diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx new file mode 100644 index 000000000000..762c34ad7bc3 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import url from 'url'; +import { stringify } from 'querystring'; + +import React, { useMemo } from 'react'; +import { encode } from '@kbn/rison'; +import { EuiButton } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { useStartServices } from '../../../../../hooks'; + +interface ViewLogsProps { + viewInLogs: boolean; + logStreamQuery: string; + startTime: string; + endTime: string; +} + +/* + Button that takes to the Logs view Ui when that is available, otherwise fallback to the Discover UI + The urls are built using same logStreamQuery (provided by a prop), startTime and endTime, ensuring that they'll both will target same log lines +*/ +export const ViewLogsButton: React.FunctionComponent = ({ + viewInLogs, + logStreamQuery, + startTime, + endTime, +}) => { + const { http } = useStartServices(); + + // Generate URL to pass page state to Logs UI + const viewInLogsUrl = useMemo( + () => + http.basePath.prepend( + url.format({ + pathname: '/app/logs/stream', + search: stringify({ + logPosition: encode({ + start: startTime, + end: endTime, + streamLive: false, + }), + logFilter: encode({ + expression: logStreamQuery, + kind: 'kuery', + }), + }), + }) + ), + [http.basePath, startTime, endTime, logStreamQuery] + ); + + const viewInDiscoverUrl = useMemo(() => { + const index = 'logs-*'; + const query = encode({ + query: logStreamQuery, + language: 'kuery', + }); + return http.basePath.prepend( + `/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'${startTime}',to:'${endTime}'))&_a=(columns:!(event.dataset,message),index:'${index}',query:${query})` + ); + }, [logStreamQuery, http.basePath, startTime, endTime]); + + return viewInLogs ? ( + + + + ) : ( + + + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx index dffa4bc665bd..1518a68fd6f0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx @@ -244,8 +244,7 @@ describe('AgentUpgradeStatus', () => { expect(results.queryAllByText('Info')).toEqual([]); }); - // Unskip this test when minVersion is set. - it.skip('should render an icon with tooltip if the agent is upgrading', async () => { + it('should render an icon with tooltip if the agent is upgrading', async () => { const results = render({ agentUpgradeStartedAt: '2023-10-03T14:34:12Z', agentUpgradedAt: null, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx index 572b86d62c73..ab4835757f94 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx @@ -225,7 +225,7 @@ export const AgentUpgradeStatus: React.FC<{ [agentUpgradeStartedAt, agentUpgradedAt] ); const status = useMemo(() => getStatusComponents(agentUpgradeDetails), [agentUpgradeDetails]); - const minVersion = undefined; // Change this to a string in order for a tooltip to render for upgrading agents with no upgrade details. + const minVersion = '8.12'; if (isAgentUpgradable) { return ( @@ -249,7 +249,7 @@ export const AgentUpgradeStatus: React.FC<{ ); } - if (minVersion && isAgentUpgrading) { + if (isAgentUpgrading) { return ( { + return { + ...jest.requireActual('../../../../hooks'), + useLink: jest.fn(), + useStartServices: jest.fn(), + }; +}); + +const mockUseStartServices = useStartServices as jest.Mock; + jest.mock('@kbn/shared-ux-link-redirect-app', () => ({ RedirectAppLinks: (props: any) => { return
    {props.children}
    ; }, })); -jest.mock('../../../../hooks', () => { - return { - useStartServices: jest.fn().mockReturnValue({ - http: { - basePath: { - prepend: jest.fn().mockImplementation((str) => 'http://localhost' + str), +const mockStartServices = (isServerlessEnabled?: boolean) => { + mockUseStartServices.mockReturnValue({ + application: {}, + data: { + query: { + timefilter: { + timefilter: { + calculateBounds: jest.fn().mockReturnValue({ + min: '2023-10-04T13:08:53.340Z', + max: '2023-10-05T13:08:53.340Z', + }), + }, }, }, - }), - }; -}); + }, + http: { + basePath: { + prepend: (url: string) => 'http://localhost:5620' + url, + }, + }, + cloud: { + isServerlessEnabled, + }, + }); +}; describe('ViewErrors', () => { const renderComponent = (action: ActionStatus) => { @@ -41,7 +67,30 @@ describe('ViewErrors', () => { ); }; - it('should render error message with btn to logs', () => { + it('should render error message with btn to Logs view if serverless not enabled', () => { + mockStartServices(); + const result = renderComponent({ + actionId: 'action1', + latestErrors: [ + { + agentId: 'agent1', + error: 'Agent agent1 is not upgradeable', + timestamp: '2023-03-06T14:51:24.709Z', + }, + ], + } as any); + + const errorText = result.getByTestId('errorText'); + expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable'); + + const viewErrorBtn = result.getByTestId('viewInLogsBtn'); + expect(viewErrorBtn.getAttribute('href')).toEqual( + `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-03-06T14%3A56%3A24.709Z'%2Cstart%3A'2023-03-06T14%3A46%3A24.709Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Aerror)'%2Ckind%3Akuery)` + ); + }); + + it('should render error message with btn to Discover view if serverless enabled', () => { + mockStartServices(true); const result = renderComponent({ actionId: 'action1', latestErrors: [ @@ -56,9 +105,9 @@ describe('ViewErrors', () => { const errorText = result.getByTestId('errorText'); expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable'); - const viewErrorBtn = result.getByTestId('viewLogsBtn'); + const viewErrorBtn = result.getByTestId('viewInDiscoverBtn'); expect(viewErrorBtn.getAttribute('href')).toEqual( - `http://localhost/app/logs/stream?logPosition=(position%3A(time%3A1678114284709)%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Aerror)'%2Ckind%3Akuery)` + `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-03-06T14:46:24.709Z',to:'2023-03-06T14:56:24.709Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:error)'))` ); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx index d49be8d4cacd..4d43c9a60a61 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx @@ -5,21 +5,19 @@ * 2.0. */ -import { stringify } from 'querystring'; - import styled from 'styled-components'; import React from 'react'; -import { encode } from '@kbn/rison'; import type { EuiBasicTableProps } from '@elastic/eui'; -import { EuiButton, EuiAccordion, EuiToolTip, EuiText, EuiBasicTable } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiAccordion, EuiToolTip, EuiText, EuiBasicTable } from '@elastic/eui'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import moment from 'moment'; import { i18n } from '@kbn/i18n'; import type { ActionErrorResult } from '../../../../../../../common/types'; import { buildQuery } from '../../agent_details_page/components/agent_logs/build_query'; +import { ViewLogsButton } from '../../agent_details_page/components/agent_logs/view_logs_button'; import type { ActionStatus } from '../../../../types'; import { useStartServices } from '../../../../hooks'; @@ -32,27 +30,26 @@ const TruncatedEuiText = styled(EuiText)` export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ action }) => { const coreStart = useStartServices(); + const isLogsUIAvailable = !coreStart.cloud?.isServerlessEnabled; + + const getLogsButton = (agentId: string, timestamp: string, viewInLogs: boolean) => { + const startTime = moment(timestamp).subtract(5, 'm').toISOString(); + const endTime = moment(timestamp).add(5, 'm').toISOString(); - const logStreamQuery = (agentId: string) => - buildQuery({ + const logStreamQuery = buildQuery({ agentId, datasets: ['elastic_agent'], logLevels: ['error'], userQuery: '', }); - - const getErrorLogsUrl = (agentId: string, timestamp: string) => { - const queryParams = stringify({ - logPosition: encode({ - position: { time: Date.parse(timestamp) }, - streamLive: false, - }), - logFilter: encode({ - expression: logStreamQuery(agentId), - kind: 'kuery', - }), - }); - return coreStart.http.basePath.prepend(`/app/logs/stream?${queryParams}`); + return ( + + ); }; const columns: EuiBasicTableProps['columns'] = [ @@ -89,16 +86,7 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ const errorItem = (action.latestErrors ?? []).find((item) => item.agentId === agentId); return ( - - - + {getLogsButton(agentId, errorItem!.timestamp, !!isLogsUIAvailable)} ); }, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx index ddd68d838041..2126a275818e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx @@ -11,6 +11,7 @@ import type { Output } from '../../../../types'; import { createFleetTestRendererMock } from '../../../../../../mock'; import { useFleetStatus } from '../../../../../../hooks/use_fleet_status'; import { ExperimentalFeaturesService } from '../../../../../../services'; +import { useStartServices } from '../../../../hooks'; import { EditOutputFlyout } from '.'; @@ -25,6 +26,16 @@ jest.mock('../../../../../../hooks/use_fleet_status', () => ({ useFleetStatus: jest.fn().mockReturnValue({}), })); +jest.mock('../../../../hooks', () => { + return { + ...jest.requireActual('../../../../hooks'), + useBreadcrumbs: jest.fn(), + useStartServices: jest.fn(), + }; +}); + +const mockUseStartServices = useStartServices as jest.Mock; + const mockedUsedFleetStatus = useFleetStatus as jest.MockedFunction; function renderFlyout(output?: Output) { @@ -67,6 +78,22 @@ const kafkaSectionsLabels = [ const remoteEsOutputLabels = ['Hosts', 'Service Token']; describe('EditOutputFlyout', () => { + const mockStartServices = (isServerlessEnabled?: boolean) => { + mockUseStartServices.mockReturnValue({ + notifications: { toasts: {} }, + docLinks: { + links: { fleet: {}, logstash: {}, kibana: {} }, + }, + cloud: { + isServerlessEnabled, + }, + }); + }; + + beforeEach(() => { + mockStartServices(false); + }); + it('should render the flyout if there is not output provided', async () => { renderFlyout(); }); @@ -164,7 +191,9 @@ describe('EditOutputFlyout', () => { }); it('should render the flyout if the output provided is a remote ES output', async () => { - jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ remoteESOutput: true }); + jest + .spyOn(ExperimentalFeaturesService, 'get') + .mockReturnValue({ remoteESOutput: true, outputSecretsStorage: true }); const { utils } = renderFlyout({ type: 'remote_elasticsearch', name: 'remote es output', @@ -177,5 +206,28 @@ describe('EditOutputFlyout', () => { expect(utils.queryByLabelText(label)).not.toBeNull(); }); expect(utils.queryByTestId('serviceTokenCallout')).not.toBeNull(); + + expect(utils.queryByTestId('settingsOutputsFlyout.typeInput')?.textContent).toContain( + 'Remote Elasticsearch' + ); + + expect(utils.queryByTestId('serviceTokenSecretInput')).not.toBeNull(); + }); + + it('should not display remote ES output in type lists if serverless', async () => { + jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ remoteESOutput: true }); + mockUseStartServices.mockReset(); + mockStartServices(true); + const { utils } = renderFlyout({ + type: 'elasticsearch', + name: 'dummy', + id: 'output', + is_default: false, + is_default_monitoring: false, + }); + + expect(utils.queryByTestId('settingsOutputsFlyout.typeInput')?.textContent).not.toContain( + 'Remote Elasticsearch' + ); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx index b35162bc5166..0e742876af82 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx @@ -70,7 +70,7 @@ export const EditOutputFlyout: React.FunctionComponent = useBreadcrumbs('settings'); const form = useOutputForm(onClose, output); const inputs = form.inputs; - const { docLinks } = useStartServices(); + const { docLinks, cloud } = useStartServices(); const { euiTheme } = useEuiTheme(); const { outputSecretsStorage: isOutputSecretsStorageEnabled } = ExperimentalFeaturesService.get(); const [useSecretsStorage, setUseSecretsStorage] = React.useState(isOutputSecretsStorageEnabled); @@ -87,10 +87,12 @@ export const EditOutputFlyout: React.FunctionComponent = const { kafkaOutput: isKafkaOutputEnabled, remoteESOutput: isRemoteESOutputEnabled } = ExperimentalFeaturesService.get(); const isRemoteESOutput = inputs.typeInput.value === outputType.RemoteElasticsearch; + // Remote ES output not yet supported in serverless + const isStateful = !cloud?.isServerlessEnabled; const OUTPUT_TYPE_OPTIONS = [ { value: outputType.Elasticsearch, text: 'Elasticsearch' }, - ...(isRemoteESOutputEnabled + ...(isRemoteESOutputEnabled && isStateful ? [{ value: outputType.RemoteElasticsearch, text: 'Remote Elasticsearch' }] : []), { value: outputType.Logstash, text: 'Logstash' }, @@ -270,7 +272,13 @@ export const EditOutputFlyout: React.FunctionComponent = const renderRemoteElasticsearchSection = () => { if (isRemoteESOutputEnabled) { - return ; + return ( + + ); } return null; }; @@ -320,7 +328,7 @@ export const EditOutputFlyout: React.FunctionComponent = case outputType.Elasticsearch: return i18n.translate('xpack.fleet.settings.editOutputFlyout.esOutputTypeCallout', { defaultMessage: - 'This output type does not support connectivity to a remote Elasticsearch cluster, please the Remote Elasticsearch type for that.', + 'This output type does not support connectivity to a remote Elasticsearch cluster, please use the Remote Elasticsearch type for that.', }); } }; @@ -333,7 +341,7 @@ export const EditOutputFlyout: React.FunctionComponent = defaultMessage="Enter your output hosts, service token for your remote cluster, and any advanced YAML configuration. Learn more about how to use these parameters in {doc}." values={{ doc: ( - + {i18n.translate('xpack.fleet.settings.editOutputFlyout.docLabel', { defaultMessage: 'our documentation', })} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx index 9b4c8f085af9..9e5fe1bc519f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_remote_es.tsx @@ -13,13 +13,16 @@ import { i18n } from '@kbn/i18n'; import { MultiRowInput } from '../multi_row_input'; import type { OutputFormInputsType } from './use_output_form'; +import { SecretFormRow } from './output_form_secret_form_row'; interface Props { inputs: OutputFormInputsType; + useSecretsStorage: boolean; + onUsePlainText: () => void; } export const OutputFormRemoteEsSection: React.FunctionComponent = (props) => { - const { inputs } = props; + const { inputs, useSecretsStorage, onUsePlainText } = props; return ( <> @@ -38,27 +41,50 @@ export const OutputFormRemoteEsSection: React.FunctionComponent = (props) isUrl /> - + } + {...inputs.serviceTokenInput.formRowProps} + > + - } - {...inputs.serviceTokenInput.formRowProps} - > - + ) : ( + - + title={i18n.translate('xpack.fleet.settings.editOutputFlyout.serviceTokenLabel', { + defaultMessage: 'Service Token', + })} + {...inputs.serviceTokenSecretInput.formRowProps} + onUsePlainText={onUsePlainText} + > + + + )} ; caTrustedFingerprintInput: ReturnType; serviceTokenInput: ReturnType; + serviceTokenSecretInput: ReturnType; sslCertificateInput: ReturnType; sslKeyInput: ReturnType; sslKeySecretInput: ReturnType; @@ -215,6 +217,12 @@ export function useOutputForm(onSucess: () => void, output?: Output) { validateServiceToken, isDisabled('service_token') ); + + const serviceTokenSecretInput = useSecretInput( + (output as NewRemoteElasticsearchOutput)?.secrets?.service_token ?? '', + validateServiceTokenSecret, + isDisabled('service_token') + ); /* Shipper feature flag - currently depends on the content of the yaml # Enables the shipper: @@ -293,7 +301,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { const sslKeyInput = useInput(output?.ssl?.key ?? '', validateSSLKey, isSSLEditable); const sslKeySecretInput = useSecretInput( - output?.secrets?.ssl?.key, + (output as NewLogstashOutput)?.secrets?.ssl?.key, validateSSLKeySecret, isSSLEditable ); @@ -503,6 +511,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { defaultMonitoringOutputInput, caTrustedFingerprintInput, serviceTokenInput, + serviceTokenSecretInput, sslCertificateInput, sslKeyInput, sslKeySecretInput, @@ -562,6 +571,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { const additionalYamlConfigValid = additionalYamlConfigInput.validate(); const caTrustedFingerprintValid = caTrustedFingerprintInput.validate(); const serviceTokenValid = serviceTokenInput.validate(); + const serviceTokenSecretValid = serviceTokenSecretInput.validate(); const sslCertificateValid = sslCertificateInput.validate(); const sslKeyValid = sslKeyInput.validate(); const sslKeySecretValid = sslKeySecretInput.validate(); @@ -607,7 +617,11 @@ export function useOutputForm(onSucess: () => void, output?: Output) { } if (isRemoteElasticsearch) { return ( - elasticsearchUrlsValid && additionalYamlConfigValid && nameInputValid && serviceTokenValid + elasticsearchUrlsValid && + additionalYamlConfigValid && + nameInputValid && + ((serviceTokenInput.value && serviceTokenValid) || + (serviceTokenSecretInput.value && serviceTokenSecretValid)) ); } else { // validate ES @@ -637,6 +651,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { additionalYamlConfigInput, caTrustedFingerprintInput, serviceTokenInput, + serviceTokenSecretInput, sslCertificateInput, sslKeyInput, sslKeySecretInput, @@ -851,7 +866,13 @@ export function useOutputForm(onSucess: () => void, output?: Output) { is_default: false, is_default_monitoring: defaultMonitoringOutputInput.value, config_yaml: additionalYamlConfigInput.value, - service_token: serviceTokenInput.value, + service_token: serviceTokenInput.value || undefined, + ...(!serviceTokenInput.value && + serviceTokenSecretInput.value && { + secrets: { + service_token: serviceTokenSecretInput.value, + }, + }), proxy_id: proxyIdValue, ...shipperParams, } as NewRemoteElasticsearchOutput; @@ -958,6 +979,7 @@ export function useOutputForm(onSucess: () => void, output?: Output) { elasticsearchUrlInput.value, caTrustedFingerprintInput.value, serviceTokenInput.value, + serviceTokenSecretInput.value, confirm, notifications.toasts, ]); diff --git a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx index ea17bc3f201c..dd43244da0c4 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/components/header/deployment_details.tsx @@ -32,9 +32,9 @@ export const DeploymentDetails = () => { } const button = ( - setIsOpen(!isOpen)} iconType="iInCircle" iconSide="left" isActive> - {i18n.translate('xpack.fleet.integrations.endpointsButton', { - defaultMessage: 'Endpoints', + setIsOpen(!isOpen)} isActive> + {i18n.translate('xpack.fleet.integrations.connectionDetailsButton', { + defaultMessage: 'Connection details', })} ); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx index 2d08fb50af8b..2177f8e21436 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_card.tsx @@ -48,6 +48,7 @@ export function PackageCard({ isUnverified, isUpdateAvailable, showLabels = true, + extraLabelsBadges, }: PackageCardProps) { let releaseBadge: React.ReactNode | null = null; @@ -63,7 +64,6 @@ export function PackageCard({ } let verifiedBadge: React.ReactNode | null = null; - if (isUnverified && showLabels) { verifiedBadge = ( @@ -106,7 +106,7 @@ export function PackageCard({ - + + {showLabels && extraLabelsBadges ? extraLabelsBadges : null} {verifiedBadge} {updateAvailableBadge} {releaseBadge} diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx index 517c0552f925..8844a0cb128a 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx @@ -327,7 +327,7 @@ export const OverviewPage: React.FC = memo( /> ) : null} - +
    diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx index 9c2ca98479a8..adeb17a5efdc 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx @@ -141,6 +141,11 @@ export const SettingsPage: React.FC = memo(({ packageInfo, theme$ }: Prop [packagePoliciesData] ); + const agentPolicyIds = useMemo( + () => packagePoliciesData?.items.map(({ policy_id: agentPolicyId }) => agentPolicyId) ?? [], + [packagePoliciesData] + ); + const { data: dryRunData } = useUpgradePackagePolicyDryRunQuery( packagePolicyIds ?? [], latestVersion, @@ -329,6 +334,7 @@ export const SettingsPage: React.FC = memo(({ packageInfo, theme$ }: Prop { dryRunData?: UpgradePackagePolicyDryRunResponse | null; packagePolicyIds?: string[]; + agentPolicyIds: string[]; isUpgradingPackagePolicies?: boolean; setIsUpgradingPackagePolicies?: React.Dispatch>; theme$: Observable; @@ -73,6 +73,7 @@ export const UpdateButton: React.FunctionComponent = ({ isUpgradingPackagePolicies = false, name, packagePolicyIds = [], + agentPolicyIds = [], setIsUpgradingPackagePolicies = () => {}, title, version, @@ -92,16 +93,7 @@ export const UpdateButton: React.FunctionComponent = ({ const [isUpdateModalVisible, setIsUpdateModalVisible] = useState(false); const [upgradePackagePolicies, setUpgradePackagePolicies] = useState(true); - const { data: agentPolicyData } = useGetAgentPoliciesQuery({ - perPage: SO_SEARCH_LIMIT, - page: 1, - // Fetch all agent policies that include one of the eligible package policies - kuery: packagePolicyIds.length - ? `${AGENT_POLICY_SAVED_OBJECT_TYPE}.package_policies:${packagePolicyIds - .map((id) => `"${id}"`) - .join(' or ')}` - : '', - }); + const { data: agentPolicyData } = useBulkGetAgentPoliciesQuery(agentPolicyIds, { full: true }); const packagePolicyCount = useMemo(() => packagePolicyIds.length, [packagePolicyIds]); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.test.tsx new file mode 100644 index 000000000000..327d550df578 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.test.tsx @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { createIntegrationsTestRendererMock } from '../../../../../../mock'; +import type { PackageListItem } from '../../../../types'; + +import { getIntegrationLabels } from './card_utils'; + +function renderIntegrationLabels(item: Partial) { + const renderer = createIntegrationsTestRendererMock(); + + return renderer.render(<>{getIntegrationLabels(item as any)}); +} + +describe('Card utils', () => { + describe('getIntegrationLabels', () => { + it('should return an empty list for an integration without errors', () => { + const res = renderIntegrationLabels({ + installationInfo: { + install_status: 'installed', + } as any, + }); + const badges = res.container.querySelectorAll('.euiBadge'); + expect(badges).toHaveLength(0); + }); + + it('should return a badge for install_failed for an integration with status:install_failled', () => { + const res = renderIntegrationLabels({ + installationInfo: { + install_status: 'install_failed', + } as any, + }); + const badges = res.container.querySelectorAll('.euiBadge'); + expect(badges).toHaveLength(1); + expect(res.queryByText('Install failed')).not.toBeNull(); + }); + + it('should return a badge if there is an upgrade failed in the last_attempt_errors', () => { + const res = renderIntegrationLabels({ + installationInfo: { + version: '1.0.0', + install_status: 'installed', + latest_install_failed_attempts: [ + { + created_at: new Date().toISOString(), + error: { + name: 'Test', + message: 'test error 123', + }, + target_version: '2.0.0', + }, + ], + } as any, + }); + const badges = res.container.querySelectorAll('.euiBadge'); + expect(badges).toHaveLength(1); + expect(res.queryByText('Update failed')).not.toBeNull(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.tsx new file mode 100644 index 000000000000..910b872bf5ce --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/card_utils.tsx @@ -0,0 +1,232 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage, FormattedDate, FormattedTime } from '@kbn/i18n-react'; +import { EuiBadge, EuiFlexItem, EuiSpacer, EuiToolTip } from '@elastic/eui'; +import semverLt from 'semver/functions/lt'; + +import type { + CustomIntegration, + CustomIntegrationIcon, +} from '@kbn/custom-integrations-plugin/common'; + +import { hasDeferredInstallations } from '../../../../../../services/has_deferred_installations'; +import { getPackageReleaseLabel } from '../../../../../../../common/services'; + +import { installationStatuses } from '../../../../../../../common/constants'; +import type { + InstallFailedAttempt, + IntegrationCardReleaseLabel, + PackageSpecIcon, +} from '../../../../../../../common/types'; + +import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants'; +import { isPackageUnverified, isPackageUpdatable } from '../../../../services'; + +import type { PackageListItem } from '../../../../types'; + +export interface IntegrationCardItem { + url: string; + release?: IntegrationCardReleaseLabel; + description: string; + name: string; + title: string; + version: string; + icons: Array; + integration: string; + id: string; + categories: string[]; + fromIntegrations?: string; + isReauthorizationRequired?: boolean; + isUnverified?: boolean; + isUpdateAvailable?: boolean; + showLabels?: boolean; + extraLabelsBadges?: React.ReactNode[]; +} + +export const mapToCard = ({ + getAbsolutePath, + getHref, + item, + addBasePath, + packageVerificationKeyId, + selectedCategory, +}: { + getAbsolutePath: (p: string) => string; + getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => string; + addBasePath: (url: string) => string; + item: CustomIntegration | PackageListItem; + packageVerificationKeyId?: string; + selectedCategory?: string; +}): IntegrationCardItem => { + let uiInternalPathUrl: string; + + let isUnverified = false; + + const version = 'version' in item ? item.version || '' : ''; + + let isUpdateAvailable = false; + let isReauthorizationRequired = false; + if (item.type === 'ui_link') { + uiInternalPathUrl = item.id.includes('language_client.') + ? addBasePath(item.uiInternalPath) + : item.uiExternalLink || getAbsolutePath(item.uiInternalPath); + } else { + let urlVersion = item.version; + if (item?.installationInfo?.version) { + urlVersion = item.installationInfo.version || item.version; + isUnverified = isPackageUnverified(item, packageVerificationKeyId); + isUpdateAvailable = isPackageUpdatable(item); + + isReauthorizationRequired = hasDeferredInstallations(item); + } + + const url = getHref('integration_details_overview', { + pkgkey: `${item.name}-${urlVersion}`, + ...(item.integration ? { integration: item.integration } : {}), + }); + + uiInternalPathUrl = url; + } + + const release: IntegrationCardReleaseLabel = getPackageReleaseLabel(version); + + let extraLabelsBadges: React.ReactNode[] | undefined; + if (item.type === 'integration') { + extraLabelsBadges = getIntegrationLabels(item); + } + + return { + id: `${item.type === 'ui_link' ? 'ui_link' : 'epr'}:${item.id}`, + description: item.description, + icons: !item.icons || !item.icons.length ? [] : item.icons, + title: item.title, + url: uiInternalPathUrl, + fromIntegrations: selectedCategory, + integration: 'integration' in item ? item.integration || '' : '', + name: 'name' in item ? item.name : item.id, + version, + release, + categories: ((item.categories || []) as string[]).filter((c: string) => !!c), + isReauthorizationRequired, + isUnverified, + isUpdateAvailable, + extraLabelsBadges, + }; +}; + +export function getIntegrationLabels(item: PackageListItem): React.ReactNode[] { + const extraLabelsBadges: React.ReactNode[] = []; + + if ( + item?.installationInfo?.latest_install_failed_attempts?.some( + (attempt) => + item.installationInfo && semverLt(item.installationInfo.version, attempt.target_version) + ) + ) { + const updateFailedAttempt = item.installationInfo?.latest_install_failed_attempts?.find( + (attempt) => + item.installationInfo && semverLt(item.installationInfo.version, attempt.target_version) + ); + extraLabelsBadges.push( + + + + + } + content={updateFailedAttempt ? formatAttempt(updateFailedAttempt) : undefined} + > + + + + + + + ); + } + + if (item.installationInfo?.install_status === installationStatuses.InstallFailed) { + const installFailedAttempt = item.installationInfo?.latest_install_failed_attempts?.find( + (attempt) => attempt.target_version === item.installationInfo?.version + ); + + extraLabelsBadges.push( + + + + + } + content={installFailedAttempt ? formatAttempt(installFailedAttempt) : undefined} + > + + + + + + + ); + } + + return extraLabelsBadges; +} + +function formatAttempt(attempt: InstallFailedAttempt): React.ReactNode { + return ( + <> + + + <> @ + + + ), + }} + /> +

    + {attempt.error?.name || ''} : {attempt.error?.message || ''} +

    + + ); +} diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx index b74ee9692996..2276d2df1924 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/category_facets.tsx @@ -22,6 +22,9 @@ export interface CategoryFacet { } export const UPDATES_AVAILABLE = 'updates_available'; +export const INSTALL_FAILED = 'install_failed'; +export const UPDATE_FAILED = 'update_failed'; + export type ExtendedIntegrationCategory = IntegrationCategory | typeof UPDATES_AVAILABLE | ''; export const ALL_CATEGORY = { @@ -45,6 +48,20 @@ export const UPDATES_AVAILABLE_CATEGORY = { }), }; +export const INSTALL_FAILED_CATEGORY = { + id: INSTALL_FAILED, + title: i18n.translate('xpack.fleet.epmList.installFailedFilterLinkText', { + defaultMessage: 'Install failed', + }), +}; + +export const UPDATE_FAILED_CATEGORY = { + id: UPDATE_FAILED, + title: i18n.translate('xpack.fleet.epmList.updateFailedFilterLinkText', { + defaultMessage: 'Update failed', + }), +}; + export interface Props { isLoading?: boolean; categories: CategoryFacet[]; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx index 78d919a565fa..81dec69d0d91 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx @@ -8,26 +8,11 @@ import React, { useState, useMemo } from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import type { - CustomIntegration, - CustomIntegrationIcon, -} from '@kbn/custom-integrations-plugin/common'; - -import { hasDeferredInstallations } from '../../../../../../services/has_deferred_installations'; -import { getPackageReleaseLabel } from '../../../../../../../common/services'; - import { installationStatuses } from '../../../../../../../common/constants'; -import type { - PackageSpecIcon, - IntegrationCardReleaseLabel, -} from '../../../../../../../common/types'; -import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants'; import { INTEGRATIONS_ROUTING_PATHS, INTEGRATIONS_SEARCH_QUERYPARAM } from '../../../../constants'; import { DefaultLayout } from '../../../../layouts'; -import { isPackageUnverified, isPackageUpdatable } from '../../../../services'; - -import type { PackageListItem } from '../../../../types'; +import { isPackageUpdatable } from '../../../../services'; import { useGetPackagesQuery } from '../../../../hooks'; @@ -36,29 +21,13 @@ import type { CategoryFacet, ExtendedIntegrationCategory } from './category_face import { InstalledPackages } from './installed_packages'; import { AvailablePackages } from './available_packages'; +export { mapToCard, type IntegrationCardItem } from './card_utils'; + export interface CategoryParams { category?: ExtendedIntegrationCategory; subcategory?: string; } -export interface IntegrationCardItem { - url: string; - release?: IntegrationCardReleaseLabel; - description: string; - name: string; - title: string; - version: string; - icons: Array; - integration: string; - id: string; - categories: string[]; - fromIntegrations?: string; - isReauthorizationRequired?: boolean; - isUnverified?: boolean; - isUpdateAvailable?: boolean; - showLabels?: boolean; -} - export const getParams = (params: CategoryParams, search: string) => { const { category, subcategory } = params; const selectedCategory: ExtendedIntegrationCategory = category || ''; @@ -71,71 +40,6 @@ export const categoryExists = (category: string, categories: CategoryFacet[]) => return categories.some((c) => c.id === category); }; -export const mapToCard = ({ - getAbsolutePath, - getHref, - item, - addBasePath, - packageVerificationKeyId, - selectedCategory, -}: { - getAbsolutePath: (p: string) => string; - getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => string; - addBasePath: (url: string) => string; - item: CustomIntegration | PackageListItem; - packageVerificationKeyId?: string; - selectedCategory?: string; -}): IntegrationCardItem => { - let uiInternalPathUrl: string; - - let isUnverified = false; - - const version = 'version' in item ? item.version || '' : ''; - - let isUpdateAvailable = false; - let isReauthorizationRequired = false; - if (item.type === 'ui_link') { - uiInternalPathUrl = item.id.includes('language_client.') - ? addBasePath(item.uiInternalPath) - : item.uiExternalLink || getAbsolutePath(item.uiInternalPath); - } else { - let urlVersion = item.version; - if (item?.installationInfo?.version) { - urlVersion = item.installationInfo.version || item.version; - isUnverified = isPackageUnverified(item, packageVerificationKeyId); - isUpdateAvailable = isPackageUpdatable(item); - - isReauthorizationRequired = hasDeferredInstallations(item); - } - - const url = getHref('integration_details_overview', { - pkgkey: `${item.name}-${urlVersion}`, - ...(item.integration ? { integration: item.integration } : {}), - }); - - uiInternalPathUrl = url; - } - - const release: IntegrationCardReleaseLabel = getPackageReleaseLabel(version); - - return { - id: `${item.type === 'ui_link' ? 'ui_link' : 'epr'}:${item.id}`, - description: item.description, - icons: !item.icons || !item.icons.length ? [] : item.icons, - title: item.title, - url: uiInternalPathUrl, - fromIntegrations: selectedCategory, - integration: 'integration' in item ? item.integration || '' : '', - name: 'name' in item ? item.name : item.id, - version, - release, - categories: ((item.categories || []) as string[]).filter((c: string) => !!c), - isReauthorizationRequired, - isUnverified, - isUpdateAvailable, - }; -}; - export const EPMHomePage: React.FC = () => { const [prereleaseEnabled, setPrereleaseEnabled] = useState(false); @@ -145,7 +49,12 @@ export const EPMHomePage: React.FC = () => { }); const installedPackages = useMemo( - () => (allPackages?.items || []).filter((pkg) => pkg.status === installationStatuses.Installed), + () => + (allPackages?.items || []).filter( + (pkg) => + pkg.status === installationStatuses.Installed || + pkg.status === installationStatuses.InstallFailed + ), [allPackages] ); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx index bf916f231ca4..b4de5073a167 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx @@ -21,12 +21,16 @@ import { useGetPackageVerificationKeyId, } from '../../../../hooks'; import { PackageListGrid } from '../../components/package_list_grid'; - +import { installationStatuses } from '../../../../../../../common/constants'; import type { PackageListItem } from '../../../../types'; import type { IntegrationsURLParameters } from './hooks/use_available_packages'; -import type { CategoryFacet, ExtendedIntegrationCategory } from './category_facets'; +import { + type CategoryFacet, + type ExtendedIntegrationCategory, + UPDATE_FAILED, +} from './category_facets'; import { CategoryFacets } from './category_facets'; import type { CategoryParams } from '.'; @@ -34,7 +38,10 @@ import { getParams, categoryExists, mapToCard } from '.'; import { ALL_INSTALLED_CATEGORY, UPDATES_AVAILABLE, + INSTALL_FAILED, UPDATES_AVAILABLE_CATEGORY, + UPDATE_FAILED_CATEGORY, + INSTALL_FAILED_CATEGORY, } from './category_facets'; const AnnouncementLink = () => { @@ -176,6 +183,26 @@ export const InstalledPackages: React.FC<{ [installedPackages] ); + // Todo move to another place + const installationFailedPackages = useMemo( + () => + installedPackages.filter( + (item) => item?.installationInfo?.install_status === installationStatuses.InstallFailed + ), + [installedPackages] + ); + + const updateFailedPackages = useMemo( + () => + installedPackages.filter((item) => + item?.installationInfo?.latest_install_failed_attempts?.some( + (attempt) => + item.installationInfo && semverLt(item.installationInfo.version, attempt.target_version) + ) + ), + [installedPackages] + ); + const categories: CategoryFacet[] = useMemo( () => [ { @@ -186,40 +213,61 @@ export const InstalledPackages: React.FC<{ ...UPDATES_AVAILABLE_CATEGORY, count: updatablePackages.length, }, + { + ...UPDATE_FAILED_CATEGORY, + count: updateFailedPackages.length, + }, + { + ...INSTALL_FAILED_CATEGORY, + count: installationFailedPackages.length, + }, ], - [installedPackages.length, updatablePackages.length] + [ + installedPackages.length, + updatablePackages.length, + installationFailedPackages.length, + updateFailedPackages.length, + ] ); + const cards = useMemo(() => { + let packages: PackageListItem[]; + if (selectedCategory === UPDATES_AVAILABLE) { + packages = updatablePackages; + } else if (selectedCategory === INSTALL_FAILED) { + packages = installationFailedPackages; + } else if (selectedCategory === UPDATE_FAILED) { + packages = updateFailedPackages; + } else { + packages = installedPackages; + } + return packages.map((item) => + mapToCard({ + getAbsolutePath, + getHref, + addBasePath, + item, + selectedCategory: selectedCategory || 'installed', + packageVerificationKeyId, + }) + ); + }, [ + selectedCategory, + updatablePackages, + installedPackages, + updateFailedPackages, + installationFailedPackages, + packageVerificationKeyId, + addBasePath, + getHref, + getAbsolutePath, + ]); + if (!categoryExists(selectedCategory, categories)) { setUrlandReplaceHistory({ searchString: searchTerm, categoryId: '' }); return null; } - const controls = ( - { - setCategory(id as ExtendedIntegrationCategory); - setSearchTerm(''); - setUrlandPushHistory({ searchString: '', categoryId: id }); - }} - /> - ); - - const cards = ( - selectedCategory === UPDATES_AVAILABLE ? updatablePackages : installedPackages - ).map((item) => - mapToCard({ - getAbsolutePath, - getHref, - addBasePath, - item, - selectedCategory: selectedCategory || 'installed', - packageVerificationKeyId, - }) - ); - let CalloutComponent = ; const unverifiedCount = cards.filter((c) => c.isUnverified).length; @@ -229,11 +277,22 @@ export const InstalledPackages: React.FC<{ } else if (updateAvailableCount) { CalloutComponent = ; } - const callout = selectedCategory === UPDATES_AVAILABLE || isLoading ? null : CalloutComponent; + const callout = selectedCategory !== '' || isLoading ? null : CalloutComponent; return ( { + setCategory(id as ExtendedIntegrationCategory); + setSearchTerm(''); + setUrlandPushHistory({ searchString: '', categoryId: id }); + }} + /> + } selectedCategory={selectedCategory} setCategory={setCategory} setUrlandPushHistory={setUrlandPushHistory} diff --git a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx index 4090c4520bf2..26668c406298 100644 --- a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx +++ b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx @@ -14,8 +14,12 @@ import { useStartServices } from './hooks'; import type { PackageAssetsComponent } from './types'; export const CustomLogsAssetsExtension: PackageAssetsComponent = () => { - const { http } = useStartServices(); - const logStreamUrl = http.basePath.prepend('/app/logs/stream'); + const { http, cloud } = useStartServices(); + const isLogsUIAvailable = !cloud?.isServerlessEnabled; + // if logs ui is not available, link to discover + const logStreamUrl = isLogsUIAvailable + ? http.basePath.prepend('/app/logs/stream') + : http.basePath.prepend('/app/discover'); const views: CustomAssetsAccordionProps['views'] = [ { diff --git a/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts b/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts index aed03272c470..6d42d401cd81 100644 --- a/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts +++ b/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts @@ -11,6 +11,8 @@ import type { AzureArmTemplateProps } from '../components/agent_enrollment_flyou import { useGetSettings } from './use_request'; +const ARM_TEMPLATE_DEFAULT_ACCOUNT_TYPE = 'single-account'; + export const useCreateAzureArmTemplateUrl = ({ enrollmentAPIKey, azureArmTemplateProps, @@ -40,7 +42,14 @@ export const useCreateAzureArmTemplateUrl = ({ }); } - const azureArmTemplateUrl = azureArmTemplateProps?.templateUrl; + let azureArmTemplateUrl = azureArmTemplateProps?.templateUrl; + + if (azureArmTemplateUrl?.includes('ACCOUNT_TYPE')) { + azureArmTemplateUrl = azureArmTemplateUrl.replace( + 'ACCOUNT_TYPE', + azureArmTemplateProps?.azureAccountType || ARM_TEMPLATE_DEFAULT_ACCOUNT_TYPE + ); + } return { isLoading, diff --git a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts index ee0481bd373a..6ce49febdeca 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/agent_policy.ts @@ -22,6 +22,7 @@ import type { CopyAgentPolicyResponse, DeleteAgentPolicyRequest, DeleteAgentPolicyResponse, + BulkGetAgentPoliciesResponse, } from '../../types'; import { useRequest, sendRequest, useConditionalRequest, sendRequestForRq } from './use_request'; @@ -47,6 +48,17 @@ export const useGetAgentPoliciesQuery = (query?: GetAgentPoliciesRequest['query' ); }; +export const useBulkGetAgentPoliciesQuery = (ids: string[], options?: { full?: boolean }) => { + return useQuery(['agentPolicies', ids], () => + sendRequestForRq({ + path: agentPolicyRouteService.getBulkGetPath(), + method: 'post', + body: JSON.stringify({ ids, full: options?.full }), + version: API_VERSIONS.public.v1, + }) + ); +}; + export const sendGetAgentPolicies = (query?: GetAgentPoliciesRequest['query']) => { return sendRequest({ path: agentPolicyRouteService.getListPath(), diff --git a/x-pack/plugins/fleet/public/types/index.ts b/x-pack/plugins/fleet/public/types/index.ts index 8c7d3ddcf5b4..63837dc80955 100644 --- a/x-pack/plugins/fleet/public/types/index.ts +++ b/x-pack/plugins/fleet/public/types/index.ts @@ -137,6 +137,7 @@ export type { KibanaSavedObjectType, GetInputsTemplatesRequest, GetInputsTemplatesResponse, + BulkGetAgentPoliciesResponse, } from '../../common/types'; export { entries, diff --git a/x-pack/plugins/fleet/server/constants/index.ts b/x-pack/plugins/fleet/server/constants/index.ts index 7a03f7c33ab3..5534961cf40b 100644 --- a/x-pack/plugins/fleet/server/constants/index.ts +++ b/x-pack/plugins/fleet/server/constants/index.ts @@ -102,4 +102,4 @@ export { } from './fleet_es_assets'; export { FILE_STORAGE_DATA_AGENT_INDEX } from './fleet_es_assets'; export { FILE_STORAGE_METADATA_AGENT_INDEX } from './fleet_es_assets'; -export * from './mappings'; +export * from '../../common/constants/mappings'; diff --git a/x-pack/plugins/fleet/server/constants/mappings.ts b/x-pack/plugins/fleet/server/constants/mappings.ts deleted file mode 100644 index 75ff9cbb549b..000000000000 --- a/x-pack/plugins/fleet/server/constants/mappings.ts +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/** - * ATTENTION: New mappings for Fleet are defined in the ElasticSearch repo. - * - * The following mappings declared here closely mirror them - * But they are only used to perform validation on the endpoints using ListWithKuery - * They're needed to perform searches on these mapping trough the KQL searchboxes in the UI. - * Whenever a field is added on any of these mappings in ES, make sure to add it here as well - */ - -export const AGENT_POLICY_MAPPINGS = { - properties: { - agent_features: { - properties: { - name: { type: 'keyword' }, - enabled: { type: 'boolean' }, - }, - }, - data_output_id: { type: 'keyword' }, - description: { type: 'text' }, - download_source_id: { type: 'keyword' }, - fleet_server_host_id: { type: 'keyword' }, - inactivity_timeout: { type: 'integer' }, - is_default: { type: 'boolean' }, - is_default_fleet_server: { type: 'boolean' }, - is_managed: { type: 'boolean' }, - is_preconfigured: { type: 'keyword' }, - is_protected: { type: 'boolean' }, - monitoring_enabled: { type: 'keyword', index: false }, - monitoring_output_id: { type: 'keyword' }, - name: { type: 'keyword' }, - namespace: { type: 'keyword' }, - revision: { type: 'integer' }, - schema_version: { type: 'version' }, - status: { type: 'keyword' }, - unenroll_timeout: { type: 'integer' }, - updated_at: { type: 'date' }, - updated_by: { type: 'keyword' }, - }, -} as const; - -export const PACKAGE_POLICIES_MAPPINGS = { - properties: { - name: { type: 'keyword' }, - description: { type: 'text' }, - namespace: { type: 'keyword' }, - enabled: { type: 'boolean' }, - is_managed: { type: 'boolean' }, - policy_id: { type: 'keyword' }, - package: { - properties: { - name: { type: 'keyword' }, - title: { type: 'keyword' }, - version: { type: 'keyword' }, - }, - }, - elasticsearch: { - dynamic: false, - properties: {}, - }, - vars: { type: 'flattened' }, - inputs: { - dynamic: false, - properties: {}, - }, - secret_references: { properties: { id: { type: 'keyword' } } }, - revision: { type: 'integer' }, - updated_at: { type: 'date' }, - updated_by: { type: 'keyword' }, - created_at: { type: 'date' }, - created_by: { type: 'keyword' }, - }, -} as const; - -export const AGENT_MAPPINGS = { - properties: { - access_api_key_id: { - type: 'keyword', - }, - action_seq_no: { - type: 'integer', - }, - active: { - type: 'boolean', - }, - agent: { - properties: { - id: { - type: 'keyword', - }, - version: { - type: 'keyword', - }, - }, - }, - default_api_key: { - type: 'keyword', - }, - default_api_key_id: { - type: 'keyword', - }, - enrollment_id: { - type: 'keyword', - }, - enrolled_at: { - type: 'date', - }, - last_checkin: { - type: 'date', - }, - last_checkin_message: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - last_checkin_status: { - type: 'keyword', - }, - last_updated: { - type: 'date', - }, - local_metadata: { - properties: { - elastic: { - properties: { - agent: { - properties: { - build: { - properties: { - original: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - }, - }, - id: { - type: 'keyword', - }, - log_level: { - type: 'keyword', - }, - snapshot: { - type: 'boolean', - }, - upgradeable: { - type: 'boolean', - }, - version: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - }, - }, - }, - }, - host: { - properties: { - architecture: { - type: 'keyword', - }, - hostname: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - id: { - type: 'keyword', - }, - ip: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - mac: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - name: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - }, - }, - os: { - properties: { - family: { - type: 'keyword', - }, - full: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - kernel: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - name: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - platform: { - type: 'keyword', - }, - version: { - type: 'text', - properties: { - keyword: { - type: 'keyword', - }, - }, - }, - }, - }, - }, - }, - packages: { - type: 'keyword', - }, - policy_output_permissions_hash: { - type: 'keyword', - }, - policy_coordinator_idx: { - type: 'integer', - }, - policy_id: { - type: 'keyword', - }, - policy_revision_idx: { - type: 'integer', - }, - type: { - type: 'keyword', - }, - tags: { - type: 'keyword', - }, - unenrolled_at: { - type: 'date', - }, - unenrollment_started_at: { - type: 'date', - }, - unenrolled_reason: { - type: 'keyword', - }, - updated_at: { - type: 'date', - }, - upgrade_started_at: { - type: 'date', - }, - upgraded_at: { - type: 'date', - }, - upgrade_status: { - type: 'keyword', - }, - upgrade_details: { - properties: { - target_version: { - type: 'text', - fields: { - keyword: { - type: 'keyword', - ignore_above: 16, - }, - }, - }, - action_id: { - type: 'keyword', - }, - state: { - type: 'keyword', - }, - metadata: { - properties: { - scheduled_at: { - type: 'date', - }, - download_percent: { - type: 'double', - }, - failed_state: { - type: 'keyword', - }, - error_msg: { - type: 'text', - fields: { - keyword: { - type: 'keyword', - ignore_above: 1024, - }, - }, - }, - }, - }, - }, - }, - // added to allow validation on status field - status: { - type: 'keyword', - }, - }, -} as const; - -export const ENROLLMENT_API_KEY_MAPPINGS = { - properties: { - active: { - type: 'boolean', - }, - api_key: { - type: 'keyword', - }, - api_key_id: { - type: 'keyword', - }, - created_at: { - type: 'date', - }, - expire_at: { - type: 'date', - }, - name: { - type: 'keyword', - }, - policy_id: { - type: 'keyword', - }, - updated_at: { - type: 'date', - }, - }, -} as const; diff --git a/x-pack/plugins/fleet/server/errors/handlers.ts b/x-pack/plugins/fleet/server/errors/handlers.ts index edc34d50598e..7bd380af258e 100644 --- a/x-pack/plugins/fleet/server/errors/handlers.ts +++ b/x-pack/plugins/fleet/server/errors/handlers.ts @@ -34,6 +34,13 @@ import { PackagePolicyNotFoundError, FleetUnauthorizedError, PackagePolicyNameExistsError, + PackageOutdatedError, + PackageInvalidArchiveError, + BundledPackageLocationNotFoundError, + PackageRemovalError, + PackageESError, + KibanaSOReferenceError, + PackageAlreadyInstalledError, } from '.'; type IngestErrorHandler = ( @@ -47,30 +54,30 @@ interface IngestErrorHandlerParams { } // unsure if this is correct. would prefer to use something "official" // this type is based on BadRequest values observed while debugging https://github.com/elastic/kibana/issues/75862 - const getHTTPResponseCode = (error: FleetError): number => { - if (error instanceof RegistryResponseError) { - // 4xx/5xx's from EPR - return 500; + // Bad Request + if (error instanceof PackageFailedVerificationError) { + return 400; } - if (error instanceof RegistryConnectionError || error instanceof RegistryError) { - // Connection errors (ie. RegistryConnectionError) / fallback (RegistryError) from EPR - return 502; // Bad Gateway + if (error instanceof PackageOutdatedError) { + return 400; } - if (error instanceof PackageNotFoundError || error instanceof PackagePolicyNotFoundError) { - return 404; // Not Found + if (error instanceof PackageInvalidArchiveError) { + return 400; } - if (error instanceof AgentPolicyNameExistsError) { - return 409; // Conflict + if (error instanceof PackageRemovalError) { + return 400; } - if (error instanceof PackageUnsupportedMediaTypeError) { - return 415; // Unsupported Media Type + if (error instanceof KibanaSOReferenceError) { + return 400; } - if (error instanceof PackageFailedVerificationError) { - return 400; // Bad Request + // Unauthorized + if (error instanceof FleetUnauthorizedError) { + return 403; } - if (error instanceof ConcurrentInstallOperationError) { - return 409; // Conflict + // Not Found + if (error instanceof PackageNotFoundError || error instanceof PackagePolicyNotFoundError) { + return 404; } if (error instanceof AgentNotFoundError) { return 404; @@ -78,14 +85,41 @@ const getHTTPResponseCode = (error: FleetError): number => { if (error instanceof AgentActionNotFoundError) { return 404; } - if (error instanceof FleetUnauthorizedError) { - return 403; // Unauthorized + // Conflict + if (error instanceof AgentPolicyNameExistsError) { + return 409; + } + if (error instanceof ConcurrentInstallOperationError) { + return 409; } if (error instanceof PackagePolicyNameExistsError) { - return 409; // Conflict + return 409; + } + if (error instanceof PackageAlreadyInstalledError) { + return 409; + } + // Unsupported Media Type + if (error instanceof PackageUnsupportedMediaTypeError) { + return 415; } + // Internal Server Error if (error instanceof UninstallTokenError) { - return 500; // Internal Error + return 500; + } + if (error instanceof BundledPackageLocationNotFoundError) { + return 500; + } + if (error instanceof PackageESError) { + return 500; + } + if (error instanceof RegistryResponseError) { + // 4xx/5xx's from EPR + return 500; + } + // Bad Gateway + if (error instanceof RegistryConnectionError || error instanceof RegistryError) { + // Connection errors (ie. RegistryConnectionError) / fallback (RegistryError) from EPR + return 502; } return 400; // Bad Request }; @@ -115,7 +149,7 @@ export function fleetErrorToResponseOptions(error: IngestErrorHandlerParams['err }; } - // not sure what type of error this is. log as much as possible + // default response is 500 logger.error(error); return { statusCode: 500, diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 0b2c6b0fc5e9..7f607f469277 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -26,8 +26,9 @@ export class RegistryResponseError extends RegistryError { super(message); } } + +// Package errors export class PackageNotFoundError extends FleetError {} -export class PackageKeyInvalidError extends FleetError {} export class PackageOutdatedError extends FleetError {} export class PackageFailedVerificationError extends FleetError { constructor(pkgName: string, pkgVersion: string) { @@ -37,22 +38,25 @@ export class PackageFailedVerificationError extends FleetError { }; } } +export class PackageUnsupportedMediaTypeError extends FleetError {} +export class PackageInvalidArchiveError extends FleetError {} +export class PackageRemovalError extends FleetError {} +export class PackageESError extends FleetError {} +export class ConcurrentInstallOperationError extends FleetError {} +export class BundledPackageLocationNotFoundError extends FleetError {} +export class KibanaSOReferenceError extends FleetError {} +export class PackageAlreadyInstalledError extends FleetError {} + export class AgentPolicyError extends FleetError {} export class AgentPolicyNotFoundError extends FleetError {} export class AgentNotFoundError extends FleetError {} export class AgentActionNotFoundError extends FleetError {} export class AgentPolicyNameExistsError extends AgentPolicyError {} -export class PackageUnsupportedMediaTypeError extends FleetError {} -export class PackageInvalidArchiveError extends FleetError {} -export class PackageCacheError extends FleetError {} -export class PackageOperationNotSupportedError extends FleetError {} -export class ConcurrentInstallOperationError extends FleetError {} export class AgentReassignmentError extends FleetError {} export class PackagePolicyIneligibleForUpgradeError extends FleetError {} export class PackagePolicyValidationError extends FleetError {} export class PackagePolicyNameExistsError extends FleetError {} export class PackagePolicyNotFoundError extends FleetError {} -export class BundledPackageNotFoundError extends FleetError {} export class HostedAgentPolicyRestrictionRelatedError extends FleetError { constructor(message = 'Cannot perform that action') { super( diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index 2716fd82b681..ec8ada164623 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -201,5 +201,7 @@ export function createUninstallTokenServiceMock(): UninstallTokenServiceInterfac generateTokensForPolicyIds: jest.fn(), generateTokensForAllPolicies: jest.fn(), encryptTokens: jest.fn(), + checkTokenValidityForAllPolicies: jest.fn(), + checkTokenValidityForPolicy: jest.fn(), }; } diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index 0373971c664e..8333d0257a8f 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -524,6 +524,9 @@ export class FleetPlugin this.policyWatcher.start(licenseService); + // We only retry when this feature flag is enabled (Serverless) + const setupAttempts = this.configInitialValue.internal?.retrySetupOnBoot ? 25 : 1; + const fleetSetupPromise = (async () => { try { // Fleet remains `available` during setup as to excessively delay Kibana's boot process. @@ -555,10 +558,9 @@ export class FleetPlugin ); }, { - // We only retry when this feature flag is enabled - numOfAttempts: this.configInitialValue.internal?.retrySetupOnBoot ? Infinity : 1, - // 250ms initial backoff - startingDelay: 250, + numOfAttempts: setupAttempts, + // 1s initial backoff + startingDelay: 1000, // 5m max backoff maxDelay: 60000 * 5, timeMultiple: 2, @@ -566,7 +568,7 @@ export class FleetPlugin jitter: 'full', retry: (error: any, attemptCount: number) => { const summary = `Fleet setup attempt ${attemptCount} failed, will retry after backoff`; - logger.debug(summary, { error: { message: error } }); + logger.warn(summary, { error: { message: error } }); this.fleetStatus$.next({ level: ServiceStatusLevels.available, @@ -586,7 +588,9 @@ export class FleetPlugin summary: 'Fleet is available', }); } catch (error) { - logger.warn('Fleet setup failed', { error: { message: error } }); + logger.warn(`Fleet setup failed after ${setupAttempts} attempts`, { + error: { message: error }, + }); this.fleetStatus$.next({ // As long as Fleet has a dependency on EPR, we can't reliably set Kibana status to `unavailable` here. diff --git a/x-pack/plugins/fleet/server/routes/epm/file_handler.test.ts b/x-pack/plugins/fleet/server/routes/epm/file_handler.test.ts new file mode 100644 index 000000000000..708d0e16a66f --- /dev/null +++ b/x-pack/plugins/fleet/server/routes/epm/file_handler.test.ts @@ -0,0 +1,241 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { httpServerMock } from '@kbn/core-http-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import { Headers } from 'node-fetch'; + +import { getBundledPackageByPkgKey } from '../../services/epm/packages/bundled_packages'; +import { getFile, getInstallation } from '../../services/epm/packages/get'; +import type { FleetRequestHandlerContext } from '../..'; +import { appContextService } from '../../services'; +import { unpackBufferEntries, getArchiveEntry } from '../../services/epm/archive'; +import { getAsset } from '../../services/epm/archive/storage'; + +import { getFileHandler } from './file_handler'; + +jest.mock('../../services/app_context'); +jest.mock('../../services/epm/archive'); +jest.mock('../../services/epm/archive/storage'); +jest.mock('../../services/epm/packages/bundled_packages'); +jest.mock('../../services/epm/packages/get'); + +const mockedGetBundledPackageByPkgKey = jest.mocked(getBundledPackageByPkgKey); +const mockedGetInstallation = jest.mocked(getInstallation); +const mockedGetFile = jest.mocked(getFile); +const mockedGetArchiveEntry = jest.mocked(getArchiveEntry); +const mockedUnpackBufferEntries = jest.mocked(unpackBufferEntries); +const mockedGetAsset = jest.mocked(getAsset); + +function mockContext() { + const mockSavedObjectsClient = savedObjectsClientMock.create(); + const mockElasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + return { + fleet: { + internalSOClient: async () => mockSavedObjectsClient, + }, + core: { + savedObjects: { + client: mockSavedObjectsClient, + }, + elasticsearch: { + client: { + asInternalUser: mockElasticsearchClient, + }, + }, + }, + } as unknown as FleetRequestHandlerContext; +} + +describe('getFileHandler', () => { + beforeEach(() => { + const logger = loggingSystemMock.createLogger(); + jest.mocked(appContextService).getLogger.mockReturnValue(logger); + mockedGetBundledPackageByPkgKey.mockReset(); + mockedUnpackBufferEntries.mockReset(); + mockedGetFile.mockReset(); + mockedGetInstallation.mockReset(); + mockedGetArchiveEntry.mockReset(); + mockedGetAsset.mockReset(); + }); + + it('should return the file for bundled package and an existing file', async () => { + mockedGetBundledPackageByPkgKey.mockResolvedValue({} as any); + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'README.md', + }, + }); + const buffer = Buffer.from(`TEST`); + mockedUnpackBufferEntries.mockResolvedValue([ + { + path: 'test-1.0.0/README.md', + buffer, + }, + ]); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 200, + body: buffer, + headers: expect.objectContaining({ + 'content-type': 'text/markdown; charset=utf-8', + }), + }) + ); + }); + + it('should a 404 for bundled package with a non existing file', async () => { + mockedGetBundledPackageByPkgKey.mockResolvedValue({} as any); + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'idonotexists.md', + }, + }); + mockedUnpackBufferEntries.mockResolvedValue([ + { + path: 'test-1.0.0/README.md', + buffer: Buffer.from(`TEST`), + }, + ]); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 404, + body: 'bundled package file not found: idonotexists.md', + }) + ); + }); + + it('should proxy registry 200 for non bundled and non installed package', async () => { + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'idonotexists.md', + }, + }); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + + mockedGetFile.mockResolvedValue({ + status: 200, + // @ts-expect-error + body: 'test', + headers: new Headers({ + raw: '', + 'content-type': 'text/markdown', + }), + }); + + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 200, + body: 'test', + headers: expect.objectContaining({ + 'content-type': 'text/markdown', + }), + }) + ); + }); + + it('should proxy registry 404 for non bundled and non installed package', async () => { + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'idonotexists.md', + }, + }); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + + mockedGetFile.mockResolvedValue({ + status: 404, + // @ts-expect-error + body: 'not found', + headers: new Headers({ + raw: '', + 'content-type': 'text', + }), + }); + + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 404, + body: 'not found', + headers: expect.objectContaining({ + 'content-type': 'text', + }), + }) + ); + }); + + it('should return the file from installation for installed package', async () => { + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'README.md', + }, + }); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + + mockedGetInstallation.mockResolvedValue({ version: '1.0.0' } as any); + mockedGetArchiveEntry.mockReturnValue(Buffer.from('test')); + + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 200, + headers: expect.objectContaining({ + 'content-type': 'text/markdown; charset=utf-8', + }), + }) + ); + }); + + it('should a 404 if the file from installation do not exists for installed package', async () => { + const request = httpServerMock.createKibanaRequest({ + params: { + pkgName: 'test', + pkgVersion: '1.0.0', + filePath: 'README.md', + }, + }); + const response = httpServerMock.createResponseFactory(); + const context = mockContext(); + + mockedGetInstallation.mockResolvedValue({ version: '1.0.0' } as any); + await getFileHandler(context, request, response); + + expect(response.custom).toBeCalledWith( + expect.objectContaining({ + statusCode: 404, + body: 'installed package file not found: README.md', + }) + ); + }); +}); diff --git a/x-pack/plugins/fleet/server/routes/epm/file_handler.ts b/x-pack/plugins/fleet/server/routes/epm/file_handler.ts new file mode 100644 index 000000000000..b7572f1980cd --- /dev/null +++ b/x-pack/plugins/fleet/server/routes/epm/file_handler.ts @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import path from 'path'; + +import type { TypeOf } from '@kbn/config-schema'; +import mime from 'mime-types'; +import type { ResponseHeaders, KnownHeaders, HttpResponseOptions } from '@kbn/core/server'; + +import type { GetFileRequestSchema, FleetRequestHandler } from '../../types'; +import { getFile, getInstallation } from '../../services/epm/packages'; +import { defaultFleetErrorHandler } from '../../errors'; +import { getArchiveEntry } from '../../services/epm/archive'; +import { getAsset } from '../../services/epm/archive/storage'; +import { getBundledPackageByPkgKey } from '../../services/epm/packages/bundled_packages'; +import { pkgToPkgKey } from '../../services/epm/registry'; +import { unpackBufferEntries } from '../../services/epm/archive'; + +const CACHE_CONTROL_10_MINUTES_HEADER: HttpResponseOptions['headers'] = { + 'cache-control': 'max-age=600', +}; +export const getFileHandler: FleetRequestHandler< + TypeOf +> = async (context, request, response) => { + try { + const { pkgName, pkgVersion, filePath } = request.params; + const savedObjectsClient = (await context.fleet).internalSoClient; + + const installation = await getInstallation({ savedObjectsClient, pkgName }); + const useLocalFile = pkgVersion === installation?.version; + const assetPath = `${pkgName}-${pkgVersion}/${filePath}`; + + if (useLocalFile) { + const fileBuffer = getArchiveEntry(assetPath); + // only pull local installation if we don't have it cached + const storedAsset = !fileBuffer && (await getAsset({ savedObjectsClient, path: assetPath })); + + // error, if neither is available + if (!fileBuffer && !storedAsset) { + return response.custom({ + body: `installed package file not found: ${filePath}`, + statusCode: 404, + }); + } + + // if storedAsset is not available, fileBuffer *must* be + // b/c we error if we don't have at least one, and storedAsset is the least likely + const { buffer, contentType } = storedAsset + ? { + contentType: storedAsset.media_type, + buffer: storedAsset.data_utf8 + ? Buffer.from(storedAsset.data_utf8, 'utf8') + : Buffer.from(storedAsset.data_base64, 'base64'), + } + : { + contentType: mime.contentType(path.extname(assetPath)), + buffer: fileBuffer, + }; + + if (!contentType) { + return response.custom({ + body: `unknown content type for file: ${filePath}`, + statusCode: 400, + }); + } + + return response.custom({ + body: buffer, + statusCode: 200, + headers: { + ...CACHE_CONTROL_10_MINUTES_HEADER, + 'content-type': contentType, + }, + }); + } + + const bundledPackage = await getBundledPackageByPkgKey( + pkgToPkgKey({ name: pkgName, version: pkgVersion }) + ); + if (bundledPackage) { + const bufferEntries = await unpackBufferEntries(bundledPackage.buffer, 'application/zip'); + + const fileBuffer = bufferEntries.find((entry) => entry.path === assetPath)?.buffer; + + if (!fileBuffer) { + return response.custom({ + body: `bundled package file not found: ${filePath}`, + statusCode: 404, + }); + } + + // if storedAsset is not available, fileBuffer *must* be + // b/c we error if we don't have at least one, and storedAsset is the least likely + const { buffer, contentType } = { + contentType: mime.contentType(path.extname(assetPath)), + buffer: fileBuffer, + }; + + if (!contentType) { + return response.custom({ + body: `unknown content type for file: ${filePath}`, + statusCode: 400, + }); + } + + return response.custom({ + body: buffer, + statusCode: 200, + headers: { + ...CACHE_CONTROL_10_MINUTES_HEADER, + 'content-type': contentType, + }, + }); + } else { + const registryResponse = await getFile(pkgName, pkgVersion, filePath); + const headersToProxy: KnownHeaders[] = ['content-type']; + const proxiedHeaders = headersToProxy.reduce((headers, knownHeader) => { + const value = registryResponse.headers.get(knownHeader); + if (value !== null) { + headers[knownHeader] = value; + } + return headers; + }, {} as ResponseHeaders); + + return response.custom({ + body: registryResponse.body, + statusCode: registryResponse.status, + headers: { ...CACHE_CONTROL_10_MINUTES_HEADER, ...proxiedHeaders }, + }); + } + } catch (error) { + return defaultFleetErrorHandler({ error, response }); + } +}; diff --git a/x-pack/plugins/fleet/server/routes/epm/handlers.ts b/x-pack/plugins/fleet/server/routes/epm/handlers.ts index 8ce1bf7006f6..6fadeff5180c 100644 --- a/x-pack/plugins/fleet/server/routes/epm/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/epm/handlers.ts @@ -5,12 +5,9 @@ * 2.0. */ -import path from 'path'; - import type { TypeOf } from '@kbn/config-schema'; -import mime from 'mime-types'; import semverValid from 'semver/functions/valid'; -import type { ResponseHeaders, KnownHeaders, HttpResponseOptions } from '@kbn/core/server'; +import type { HttpResponseOptions } from '@kbn/core/server'; import { pick } from 'lodash'; @@ -41,7 +38,6 @@ import type { GetPackagesRequestSchema, GetInstalledPackagesRequestSchema, GetDataStreamsRequestSchema, - GetFileRequestSchema, GetInfoRequestSchema, InstallPackageFromRegistryRequestSchema, InstallPackageByUploadRequestSchema, @@ -60,21 +56,17 @@ import { getCategories, getPackages, getInstalledPackages, - getFile, getPackageInfo, isBulkInstallError, installPackage, removeInstallation, getLimitedPackages, - getInstallation, getBulkAssets, getTemplateInputs, } from '../../services/epm/packages'; import type { BulkInstallResponse } from '../../services/epm/packages'; import { defaultFleetErrorHandler, fleetErrorToResponseOptions, FleetError } from '../../errors'; import { appContextService, checkAllowedPackages } from '../../services'; -import { getArchiveEntry } from '../../services/epm/archive/cache'; -import { getAsset } from '../../services/epm/archive/storage'; import { getPackageUsageStats } from '../../services/epm/packages/get'; import { updatePackage } from '../../services/epm/packages/update'; import { getGpgKeyIdOrUndefined } from '../../services/epm/packages/package_verification'; @@ -206,80 +198,6 @@ export const getLimitedListHandler: FleetRequestHandler< } }; -export const getFileHandler: FleetRequestHandler< - TypeOf -> = async (context, request, response) => { - try { - const { pkgName, pkgVersion, filePath } = request.params; - const savedObjectsClient = (await context.fleet).internalSoClient; - const installation = await getInstallation({ savedObjectsClient, pkgName }); - const useLocalFile = pkgVersion === installation?.version; - - if (useLocalFile) { - const assetPath = `${pkgName}-${pkgVersion}/${filePath}`; - const fileBuffer = getArchiveEntry(assetPath); - // only pull local installation if we don't have it cached - const storedAsset = !fileBuffer && (await getAsset({ savedObjectsClient, path: assetPath })); - - // error, if neither is available - if (!fileBuffer && !storedAsset) { - return response.custom({ - body: `installed package file not found: ${filePath}`, - statusCode: 404, - }); - } - - // if storedAsset is not available, fileBuffer *must* be - // b/c we error if we don't have at least one, and storedAsset is the least likely - const { buffer, contentType } = storedAsset - ? { - contentType: storedAsset.media_type, - buffer: storedAsset.data_utf8 - ? Buffer.from(storedAsset.data_utf8, 'utf8') - : Buffer.from(storedAsset.data_base64, 'base64'), - } - : { - contentType: mime.contentType(path.extname(assetPath)), - buffer: fileBuffer, - }; - - if (!contentType) { - return response.custom({ - body: `unknown content type for file: ${filePath}`, - statusCode: 400, - }); - } - - return response.custom({ - body: buffer, - statusCode: 200, - headers: { - ...CACHE_CONTROL_10_MINUTES_HEADER, - 'content-type': contentType, - }, - }); - } else { - const registryResponse = await getFile(pkgName, pkgVersion, filePath); - const headersToProxy: KnownHeaders[] = ['content-type']; - const proxiedHeaders = headersToProxy.reduce((headers, knownHeader) => { - const value = registryResponse.headers.get(knownHeader); - if (value !== null) { - headers[knownHeader] = value; - } - return headers; - }, {} as ResponseHeaders); - - return response.custom({ - body: registryResponse.body, - statusCode: registryResponse.status, - headers: { ...CACHE_CONTROL_10_MINUTES_HEADER, ...proxiedHeaders }, - }); - } - } catch (error) { - return defaultFleetErrorHandler({ error, response }); - } -}; - export const getInfoHandler: FleetRequestHandler< TypeOf, TypeOf @@ -690,7 +608,9 @@ const soToInstallationInfo = (pkg: PackageListItem | PackageInfo) => { verification_status: attributes.verification_status, verification_key_id: attributes.verification_key_id, experimental_data_stream_features: attributes.experimental_data_stream_features, + latest_install_failed_attempts: attributes.latest_install_failed_attempts, }; + return { // When savedObject gets removed, replace `pkg` with `...omit(pkg, 'savedObject')` ...pkg, diff --git a/x-pack/plugins/fleet/server/routes/epm/index.ts b/x-pack/plugins/fleet/server/routes/epm/index.ts index 6e0000bf4ccb..5245381a409d 100644 --- a/x-pack/plugins/fleet/server/routes/epm/index.ts +++ b/x-pack/plugins/fleet/server/routes/epm/index.ts @@ -55,7 +55,6 @@ import { getListHandler, getInstalledListHandler, getLimitedListHandler, - getFileHandler, getInfoHandler, getBulkAssetsHandler, installPackageFromRegistryHandler, @@ -70,6 +69,7 @@ import { createCustomIntegrationHandler, getInputsHandler, } from './handlers'; +import { getFileHandler } from './file_handler'; const MAX_FILE_SIZE_BYTES = 104857600; // 100MB diff --git a/x-pack/plugins/fleet/server/routes/output/handler.test.ts b/x-pack/plugins/fleet/server/routes/output/handler.test.ts new file mode 100644 index 000000000000..5cf3b544e155 --- /dev/null +++ b/x-pack/plugins/fleet/server/routes/output/handler.test.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { agentPolicyService, appContextService, outputService } from '../../services'; + +import { postOutputHandler, putOutputHandler } from './handler'; + +describe('output handler', () => { + const mockContext = { + core: Promise.resolve({ + savedObjects: {}, + elasticsearch: { + client: {}, + }, + }), + } as any; + const mockResponse = { + customError: jest.fn().mockImplementation((options) => options), + ok: jest.fn().mockImplementation((options) => options), + }; + + beforeEach(() => { + jest.spyOn(appContextService, 'getLogger').mockReturnValue({ error: jest.fn() } as any); + jest.spyOn(outputService, 'create').mockResolvedValue({ id: 'output1' } as any); + jest.spyOn(outputService, 'update').mockResolvedValue({ id: 'output1' } as any); + jest.spyOn(outputService, 'get').mockResolvedValue({ id: 'output1' } as any); + jest.spyOn(agentPolicyService, 'bumpAllAgentPoliciesForOutput').mockResolvedValue({} as any); + }); + + it('should return error on post output using remote_elasticsearch in serverless', async () => { + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any); + + const res = await postOutputHandler( + mockContext, + { body: { id: 'output1', type: 'remote_elasticsearch' } } as any, + mockResponse as any + ); + + expect(res).toEqual({ + body: { message: 'Output type remote_elasticsearch not supported in serverless' }, + statusCode: 400, + }); + }); + + it('should return ok on post output using remote_elasticsearch in stateful', async () => { + jest + .spyOn(appContextService, 'getCloud') + .mockReturnValue({ isServerlessEnabled: false } as any); + + const res = await postOutputHandler( + mockContext, + { body: { type: 'remote_elasticsearch' } } as any, + mockResponse as any + ); + + expect(res).toEqual({ body: { item: { id: 'output1' } } }); + }); + + it('should return error on put output using remote_elasticsearch in serverless', async () => { + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any); + + const res = await putOutputHandler( + mockContext, + { body: { id: 'output1', type: 'remote_elasticsearch' } } as any, + mockResponse as any + ); + + expect(res).toEqual({ + body: { message: 'Output type remote_elasticsearch not supported in serverless' }, + statusCode: 400, + }); + }); + + it('should return ok on put output using remote_elasticsearch in stateful', async () => { + jest + .spyOn(appContextService, 'getCloud') + .mockReturnValue({ isServerlessEnabled: false } as any); + + const res = await putOutputHandler( + mockContext, + { body: { type: 'remote_elasticsearch' }, params: { outputId: 'output1' } } as any, + mockResponse as any + ); + + expect(res).toEqual({ body: { item: { id: 'output1' } } }); + }); + + it('should return error if both service_token and secrets.service_token is provided for remote_elasticsearch output', async () => { + jest + .spyOn(appContextService, 'getCloud') + .mockReturnValue({ isServerlessEnabled: false } as any); + + const res = await postOutputHandler( + mockContext, + { + body: { + type: 'remote_elasticsearch', + service_token: 'token1', + secrets: { service_token: 'token2' }, + }, + } as any, + mockResponse as any + ); + + expect(res).toEqual({ + body: { message: 'Cannot specify both service_token and secrets.service_token' }, + statusCode: 400, + }); + }); + + it('should return ok if one of service_token and secrets.service_token is provided for remote_elasticsearch output', async () => { + jest + .spyOn(appContextService, 'getCloud') + .mockReturnValue({ isServerlessEnabled: false } as any); + + const res = await postOutputHandler( + mockContext, + { body: { type: 'remote_elasticsearch', secrets: { service_token: 'token2' } } } as any, + mockResponse as any + ); + + expect(res).toEqual({ body: { item: { id: 'output1' } } }); + }); +}); diff --git a/x-pack/plugins/fleet/server/routes/output/handler.ts b/x-pack/plugins/fleet/server/routes/output/handler.ts index 475e7e962550..dc6682fe8272 100644 --- a/x-pack/plugins/fleet/server/routes/output/handler.ts +++ b/x-pack/plugins/fleet/server/routes/output/handler.ts @@ -10,6 +10,8 @@ import type { TypeOf } from '@kbn/config-schema'; import Boom from '@hapi/boom'; +import type { ValueOf } from '@elastic/eui'; + import { outputType } from '../../../common/constants'; import type { @@ -23,20 +25,32 @@ import type { GetOneOutputResponse, GetOutputsResponse, Output, + OutputType, PostLogstashApiKeyResponse, } from '../../../common/types'; import { outputService } from '../../services/output'; import { defaultFleetErrorHandler, FleetUnauthorizedError } from '../../errors'; -import { agentPolicyService } from '../../services'; +import { agentPolicyService, appContextService } from '../../services'; import { generateLogstashApiKey, canCreateLogstashApiKey } from '../../services/api_keys'; function ensureNoDuplicateSecrets(output: Partial) { if (output.type === outputType.Kafka && output?.password && output?.secrets?.password) { throw Boom.badRequest('Cannot specify both password and secrets.password'); } - if (output.ssl?.key && output.secrets?.ssl?.key) { + if ( + (output.type === outputType.Kafka || output.type === outputType.Logstash) && + output.ssl?.key && + output.secrets?.ssl?.key + ) { throw Boom.badRequest('Cannot specify both ssl.key and secrets.ssl.key'); } + if ( + output.type === outputType.RemoteElasticsearch && + output.service_token && + output.secrets?.service_token + ) { + throw Boom.badRequest('Cannot specify both service_token and secrets.service_token'); + } } export const getOutputsHandler: RequestHandler = async (context, request, response) => { @@ -89,8 +103,9 @@ export const putOutputHandler: RequestHandler< const soClient = coreContext.savedObjects.client; const esClient = coreContext.elasticsearch.client.asInternalUser; const outputUpdate = request.body; - ensureNoDuplicateSecrets(outputUpdate); try { + validateOutputServerless(outputUpdate.type); + ensureNoDuplicateSecrets(outputUpdate); await outputService.update(soClient, esClient, request.params.outputId, outputUpdate); const output = await outputService.get(soClient, request.params.outputId); if (output.is_default || output.is_default_monitoring) { @@ -125,6 +140,7 @@ export const postOutputHandler: RequestHandler< const esClient = coreContext.elasticsearch.client.asInternalUser; try { const { id, ...newOutput } = request.body; + validateOutputServerless(newOutput.type); ensureNoDuplicateSecrets(newOutput); const output = await outputService.create(soClient, esClient, newOutput, { id }); if (output.is_default || output.is_default_monitoring) { @@ -141,6 +157,13 @@ export const postOutputHandler: RequestHandler< } }; +function validateOutputServerless(type?: ValueOf): void { + const cloudSetup = appContextService.getCloud(); + if (cloudSetup?.isServerlessEnabled && type === outputType.RemoteElasticsearch) { + throw Boom.badRequest('Output type remote_elasticsearch not supported in serverless'); + } +} + export const deleteOutputHandler: RequestHandler< TypeOf > = async (context, request, response) => { diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index b87310e850c8..c470140d8ac2 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -270,6 +270,12 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ }, }, }, + service_token: { + dynamic: false, + properties: { + id: { type: 'keyword' }, + }, + }, }, }, }, @@ -304,6 +310,25 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ }, ], }, + '3': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + secrets: { + properties: { + service_token: { + dynamic: false, + properties: { + id: { type: 'keyword' }, + }, + }, + }, + }, + }, + }, + ], + }, }, migrations: { '7.13.0': migrateOutputToV7130, @@ -451,6 +476,7 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ deferred: { type: 'boolean' }, }, }, + latest_install_failed_attempts: { type: 'object', enabled: false }, installed_kibana: { dynamic: false, properties: {}, @@ -481,6 +507,18 @@ const getSavedObjectTypes = (): { [key: string]: SavedObjectsType } => ({ }, }, }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + latest_install_failed_attempts: { type: 'object', enabled: false }, + }, + }, + ], + }, + }, migrations: { '7.14.0': migrateInstallationToV7140, '7.14.1': migrateInstallationToV7140, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 710ac46b9459..931168f545b5 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -32,6 +32,7 @@ import { getFullAgentPolicy } from './agent_policies'; import * as outputsHelpers from './agent_policies/outputs_helpers'; import { auditLoggingService } from './audit_logging'; import { licenseService } from './license'; +import type { UninstallTokenServiceInterface } from './security/uninstall_token_service'; function getSavedObjectMock(agentPolicyAttributes: any) { const mock = savedObjectsClientMock.create(); @@ -182,13 +183,13 @@ describe('agent policy', () => { }); }); - it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { + it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', async () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - expect( + await expect( agentPolicyService.create(soClient, esClient, { name: 'test', namespace: 'default', @@ -199,13 +200,13 @@ describe('agent policy', () => { ); }); - it('should not throw FleetUnauthorizedError if is_protected=false with insufficient license', () => { + it('should not throw FleetUnauthorizedError if is_protected=false with insufficient license', async () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - expect( + await expect( agentPolicyService.create(soClient, esClient, { name: 'test', namespace: 'default', @@ -619,7 +620,7 @@ describe('agent policy', () => { }); }); - it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { + it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', async () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); @@ -632,7 +633,7 @@ describe('agent policy', () => { references: [], }); - expect( + await expect( agentPolicyService.update(soClient, esClient, 'test-id', { name: 'test', namespace: 'default', @@ -643,7 +644,7 @@ describe('agent policy', () => { ); }); - it('should not throw FleetUnauthorizedError if is_protected=false with insufficient license', () => { + it('should not throw FleetUnauthorizedError if is_protected=false with insufficient license', async () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); @@ -656,7 +657,7 @@ describe('agent policy', () => { references: [], }); - expect( + await expect( agentPolicyService.update(soClient, esClient, 'test-id', { name: 'test', namespace: 'default', @@ -665,6 +666,34 @@ describe('agent policy', () => { new FleetUnauthorizedError('Tamper protection requires Platinum license') ); }); + + it('should throw Error if is_protected=true with invalid uninstall token', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + + mockedAppContextService.getUninstallTokenService.mockReturnValueOnce({ + checkTokenValidityForPolicy: jest + .fn() + .mockResolvedValueOnce({ error: new Error('reason') }), + } as unknown as UninstallTokenServiceInterface); + + const soClient = getAgentPolicyCreateMock(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + + soClient.get.mockResolvedValue({ + attributes: {}, + id: 'test-id', + type: 'mocked', + references: [], + }); + + await expect( + agentPolicyService.update(soClient, esClient, 'test-id', { + name: 'test', + namespace: 'default', + is_protected: true, + }) + ).rejects.toThrowError(new Error('Cannot enable Agent Tamper Protection: reason')); + }); }); describe('deployPolicy', () => { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 8673bd6ad91a..568829fda978 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -512,6 +512,7 @@ class AgentPolicyService { } this.checkTamperProtectionLicense(agentPolicy); + await this.checkForValidUninstallToken(agentPolicy, id); const logger = appContextService.getLogger(); @@ -1212,6 +1213,24 @@ class AgentPolicyService { throw new FleetUnauthorizedError('Tamper protection requires Platinum license'); } } + private async checkForValidUninstallToken( + agentPolicy: { is_protected?: boolean }, + policyId: string + ): Promise { + if (agentPolicy?.is_protected) { + const uninstallTokenService = appContextService.getUninstallTokenService(); + + const uninstallTokenError = await uninstallTokenService?.checkTokenValidityForPolicy( + policyId + ); + + if (uninstallTokenError) { + throw new Error( + `Cannot enable Agent Tamper Protection: ${uninstallTokenError.error.message}` + ); + } + } + } } export const agentPolicyService = new AgentPolicyService(); diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index 11cb82123a34..9d1b3a9f01a5 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -7,7 +7,7 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import type { HTTPAuthorizationHeader } from '../../common/http_authorization_header'; diff --git a/x-pack/plugins/fleet/server/services/agents/agent_metrics.ts b/x-pack/plugins/fleet/server/services/agents/agent_metrics.ts index 22fc64dad9e5..34cfbe547d6d 100644 --- a/x-pack/plugins/fleet/server/services/agents/agent_metrics.ts +++ b/x-pack/plugins/fleet/server/services/agents/agent_metrics.ts @@ -11,6 +11,8 @@ import type { Agent } from '../../types'; import { appContextService } from '../app_context'; import { DATA_TIERS } from '../../../common/constants'; +const AGGREGATION_MAX_SIZE = 1000; + export async function fetchAndAssignAgentMetrics(esClient: ElasticsearchClient, agents: Agent[]) { try { return await _fetchAndAssignAgentMetrics(esClient, agents); @@ -112,6 +114,7 @@ const aggregationQueryBuilder = (agentIds: string[]) => ({ agents: { terms: { field: 'elastic_agent.id', + size: AGGREGATION_MAX_SIZE, }, aggs: { sum_memory_size: { @@ -127,6 +130,7 @@ const aggregationQueryBuilder = (agentIds: string[]) => ({ processes: { terms: { field: 'elastic_agent.process', + size: AGGREGATION_MAX_SIZE, order: { _count: 'desc', }, diff --git a/x-pack/plugins/fleet/server/services/agents/crud.test.ts b/x-pack/plugins/fleet/server/services/agents/crud.test.ts index e542881fe13f..db08161c9519 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.test.ts @@ -151,7 +151,8 @@ describe('Agents CRUD test', () => { }); }); - describe('getAgentsByKuery', () => { + // FLAKY: https://github.com/elastic/kibana/issues/171541 + describe.skip('getAgentsByKuery', () => { it('should return upgradeable on first page', async () => { searchMock .mockImplementationOnce(() => Promise.resolve(getEsResponse(['1', '2', '3', '4', '5'], 7))) diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade.test.ts b/x-pack/plugins/fleet/server/services/agents/upgrade.test.ts index 8327e09842f8..d847bf1aceb3 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade.test.ts @@ -25,7 +25,11 @@ jest.mock('./action_status', () => { }; }); -describe('sendUpgradeAgentsActions (plural)', () => { +// FLAKY: https://github.com/elastic/kibana/issues/171052 +// FLAKY: https://github.com/elastic/kibana/issues/172114 +// FLAKY: https://github.com/elastic/kibana/issues/171536 +// FLAKY: https://github.com/elastic/kibana/issues/171160 +describe.skip('sendUpgradeAgentsActions (plural)', () => { beforeEach(async () => { appContextService.start(createAppContextStartContractMock()); }); diff --git a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts index 8bd0f823cb5c..10d8c7560b26 100644 --- a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts +++ b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts @@ -368,7 +368,7 @@ spec: value: "1" # Set to true to communicate with Fleet with either insecure HTTP or unverified HTTPS - name: FLEET_INSECURE - value: "true" + value: "false" # Fleet Server URL to enroll the Elastic Agent into # FLEET_URL can be found in Kibana, go to Management > Fleet > Settings - name: FLEET_URL @@ -393,7 +393,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name - # The following ELASTIC_NETINFO:false variable will disable the netinfo.enabled option of add-host-metadata processor. This will remove fields host.ip and host.mac. + # The following ELASTIC_NETINFO:false variable will disable the netinfo.enabled option of add-host-metadata processor. This will remove fields host.ip and host.mac. # For more info: https://www.elastic.co/guide/en/beats/metricbeat/current/add-host-metadata.html - name: ELASTIC_NETINFO value: "false" diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts index 077aa720b96d..0bc220a500fb 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -10,17 +10,18 @@ import { safeLoad, safeDump } from 'js-yaml'; import type { PackagePolicyConfigRecord } from '../../../../common/types'; import { toCompiledSecretRef } from '../../secrets'; +import { PackageInvalidArchiveError } from '../../../errors'; const handlebars = Handlebars.create(); export function compileTemplate(variables: PackagePolicyConfigRecord, templateStr: string) { - const { vars, yamlValues } = buildTemplateVariables(variables, templateStr); + const { vars, yamlValues } = buildTemplateVariables(variables); let compiledTemplate: string; try { const template = handlebars.compile(templateStr, { noEscape: true }); compiledTemplate = template(vars); } catch (err) { - throw new Error(`Error while compiling agent template: ${err.message}`); + throw new PackageInvalidArchiveError(`Error while compiling agent template: ${err.message}`); } compiledTemplate = replaceRootLevelYamlVariables(yamlValues, compiledTemplate); @@ -64,7 +65,7 @@ function replaceVariablesInYaml(yamlVariables: { [k: string]: any }, yaml: any) return yaml; } -function buildTemplateVariables(variables: PackagePolicyConfigRecord, templateStr: string) { +function buildTemplateVariables(variables: PackagePolicyConfigRecord) { const yamlValues: { [k: string]: any } = {}; const vars = Object.entries(variables).reduce((acc, [key, recordEntry]) => { // support variables with . like key.patterns @@ -72,13 +73,17 @@ function buildTemplateVariables(variables: PackagePolicyConfigRecord, templateSt const lastKeyPart = keyParts.pop(); if (!lastKeyPart || !isValidKey(lastKeyPart)) { - throw new Error('Invalid key'); + throw new PackageInvalidArchiveError( + `Error while compiling agent template: Invalid key ${lastKeyPart}` + ); } let varPart = acc; for (const keyPart of keyParts) { if (!isValidKey(keyPart)) { - throw new Error('Invalid key'); + throw new PackageInvalidArchiveError( + `Error while compiling agent template: Invalid key ${keyPart}` + ); } if (!varPart[keyPart]) { varPart[keyPart] = {}; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts index cfa110589a01..81d55c5fd313 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts @@ -19,6 +19,7 @@ import type { InstallSource, PackageAssetReference, } from '../../../../common/types'; +import { PackageInvalidArchiveError, PackageNotFoundError } from '../../../errors'; import { appContextService } from '../../app_context'; @@ -70,13 +71,13 @@ export async function archiveEntryToESDocument(opts: { // validation: filesize? asset type? anything else if (dataUtf8.length > currentMaxAssetBytes) { - throw new Error( + throw new PackageInvalidArchiveError( `File at ${path} is larger than maximum allowed size of ${currentMaxAssetBytes}` ); } if (dataBase64.length > currentMaxAssetBytes) { - throw new Error( + throw new PackageInvalidArchiveError( `After base64 encoding file at ${path} is larger than maximum allowed size of ${currentMaxAssetBytes}` ); } @@ -113,7 +114,7 @@ export async function saveArchiveEntries(opts: { const bulkBody = await Promise.all( paths.map((path) => { const buffer = getArchiveEntry(path); - if (!buffer) throw new Error(`Could not find ArchiveEntry at ${path}`); + if (!buffer) throw new PackageNotFoundError(`Could not find ArchiveEntry at ${path}`); const { name, version } = packageInfo; return archiveEntryToBulkCreateObject({ path, buffer, name, version, installSource }); }) diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index 3aa86b526add..61a75d28b799 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -14,6 +14,7 @@ import { getAsset, getPathParts } from '../../archive'; import { updateEsAssetReferences } from '../../packages/install'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; +import { PackageInvalidArchiveError } from '../../../../errors'; export async function installILMPolicy( packageInfo: InstallablePackage, @@ -57,7 +58,7 @@ export async function installILMPolicy( { logger } ); } catch (err) { - throw new Error(err.message); + throw new PackageInvalidArchiveError(`Couldn't install ilm policies: ${err.message}`); } }) ); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index d65d8de5a382..2e67c70874e4 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -535,7 +535,7 @@ export function prepareTemplate({ const validFields = processFields(fields); - const mappings = generateMappings(validFields); + const mappings = generateMappings(validFields, isIndexModeTimeSeries); const templateName = generateTemplateName(dataStream); const templateIndexPattern = generateTemplateIndexPattern(dataStream); const templatePriority = getTemplatePriority(dataStream); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index 96a2547c9e58..a621df33062a 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -897,7 +897,30 @@ describe('EPM template', () => { }; const fields: Field[] = safeLoad(literalYml); const processedFields = processFields(fields); - const mappings = generateMappings(processedFields); + const mappings = generateMappings(processedFields, true); + expect(mappings).toEqual(expectedMapping); + }); + + it('tests processing dimension field on a keyword - tsdb disabled', () => { + const literalYml = ` +- name: example.id + type: keyword + dimension: true + `; + const expectedMapping = { + properties: { + example: { + properties: { + id: { + type: 'keyword', + }, + }, + }, + }, + }; + const fields: Field[] = safeLoad(literalYml); + const processedFields = processFields(fields); + const mappings = generateMappings(processedFields, false); expect(mappings).toEqual(expectedMapping); }); @@ -921,7 +944,7 @@ describe('EPM template', () => { }; const fields: Field[] = safeLoad(literalYml); const processedFields = processFields(fields); - const mappings = generateMappings(processedFields); + const mappings = generateMappings(processedFields, true); expect(mappings).toEqual(expectedMapping); }); @@ -955,7 +978,40 @@ describe('EPM template', () => { }; const fields: Field[] = safeLoad(literalYml); const processedFields = processFields(fields); - const mappings = generateMappings(processedFields); + const mappings = generateMappings(processedFields, true); + expect(mappings).toEqual(expectedMapping); + }); + + it('tests processing metric_type field - tsdb disabled', () => { + const literalYml = ` +- name: total.norm.pct + type: scaled_float + metric_type: gauge + unit: percent + format: percent +`; + const expectedMapping = { + properties: { + total: { + properties: { + norm: { + properties: { + pct: { + scaling_factor: 1000, + type: 'scaled_float', + meta: { + unit: 'percent', + }, + }, + }, + }, + }, + }, + }, + }; + const fields: Field[] = safeLoad(literalYml); + const processedFields = processFields(fields); + const mappings = generateMappings(processedFields, false); expect(mappings).toEqual(expectedMapping); }); @@ -982,7 +1038,7 @@ describe('EPM template', () => { }; const fields: Field[] = safeLoad(literalYml); const processedFields = processFields(fields); - const mappings = generateMappings(processedFields); + const mappings = generateMappings(processedFields, true); expect(mappings).toEqual(expectedMapping); }); @@ -1292,7 +1348,7 @@ describe('EPM template', () => { }; const fields: Field[] = safeLoad(textWithRuntimeFieldsLiteralYml); const processedFields = processFields(fields); - const mappings = generateMappings(processedFields); + const mappings = generateMappings(processedFields, true); expect(mappings).toEqual(runtimeFieldMapping); }); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index 622538e15283..a26aa2c8e011 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -33,6 +33,7 @@ import { } from '../../../../constants'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; +import { PackageESError, PackageInvalidArchiveError } from '../../../../errors'; import { getDefaultProperties, histogram, keyword, scaledFloat } from './mappings'; @@ -102,7 +103,9 @@ export function getTemplate({ isIndexModeTimeSeries, }); if (template.template.settings.index.final_pipeline) { - throw new Error(`Error template for ${templateIndexPattern} contains a final_pipeline`); + throw new PackageInvalidArchiveError( + `Error template for ${templateIndexPattern} contains a final_pipeline` + ); } const esBaseComponents = getBaseEsComponents(type, !!isIndexModeTimeSeries); @@ -141,46 +144,53 @@ const getBaseEsComponents = (type: string, isIndexModeTimeSeries: boolean): stri * * @param fields */ -export function generateMappings(fields: Field[]): IndexTemplateMappings { +export function generateMappings( + fields: Field[], + isIndexModeTimeSeries = false +): IndexTemplateMappings { const dynamicTemplates: Array> = []; const dynamicTemplateNames = new Set(); const runtimeFields: RuntimeFields = {}; - const { properties } = _generateMappings(fields, { - addDynamicMapping: (dynamicMapping: { - path: string; - matchingType: string; - pathMatch: string; - properties: Properties; - runtimeProperties?: Properties; - }) => { - const name = dynamicMapping.path; - if (dynamicTemplateNames.has(name)) { - return; - } + const { properties } = _generateMappings( + fields, + { + addDynamicMapping: (dynamicMapping: { + path: string; + matchingType: string; + pathMatch: string; + properties: Properties; + runtimeProperties?: Properties; + }) => { + const name = dynamicMapping.path; + if (dynamicTemplateNames.has(name)) { + return; + } - const dynamicTemplate: Properties = {}; - if (dynamicMapping.runtimeProperties !== undefined) { - dynamicTemplate.runtime = dynamicMapping.runtimeProperties; - } else { - dynamicTemplate.mapping = dynamicMapping.properties; - } + const dynamicTemplate: Properties = {}; + if (dynamicMapping.runtimeProperties !== undefined) { + dynamicTemplate.runtime = dynamicMapping.runtimeProperties; + } else { + dynamicTemplate.mapping = dynamicMapping.properties; + } - if (dynamicMapping.matchingType) { - dynamicTemplate.match_mapping_type = dynamicMapping.matchingType; - } + if (dynamicMapping.matchingType) { + dynamicTemplate.match_mapping_type = dynamicMapping.matchingType; + } - if (dynamicMapping.pathMatch) { - dynamicTemplate.path_match = dynamicMapping.pathMatch; - } + if (dynamicMapping.pathMatch) { + dynamicTemplate.path_match = dynamicMapping.pathMatch; + } - dynamicTemplateNames.add(name); - dynamicTemplates.push({ [dynamicMapping.path]: dynamicTemplate }); - }, - addRuntimeField: (runtimeField: { path: string; properties: Properties }) => { - runtimeFields[`${runtimeField.path}`] = runtimeField.properties; + dynamicTemplateNames.add(name); + dynamicTemplates.push({ [dynamicMapping.path]: dynamicTemplate }); + }, + addRuntimeField: (runtimeField: { path: string; properties: Properties }) => { + runtimeFields[`${runtimeField.path}`] = runtimeField.properties; + }, }, - }); + isIndexModeTimeSeries + ); const indexTemplateMappings: IndexTemplateMappings = { properties }; if (dynamicTemplates.length > 0) { @@ -206,7 +216,8 @@ function _generateMappings( addDynamicMapping: any; addRuntimeField: any; groupFieldName?: string; - } + }, + isIndexModeTimeSeries: boolean ): { properties: IndexTemplateMappings['properties']; hasNonDynamicTemplateMappings: boolean; @@ -294,7 +305,9 @@ function _generateMappings( case 'long': case 'boolean': dynProperties.type = field.object_type; - dynProperties.time_series_metric = field.metric_type; + if (isIndexModeTimeSeries) { + dynProperties.time_series_metric = field.metric_type; + } matchingType = field.object_type_mapping_type ?? field.object_type; default: break; @@ -359,7 +372,9 @@ function _generateMappings( case 'float': case 'half_float': dynProperties.type = field.object_type; - dynProperties.time_series_metric = field.metric_type; + if (isIndexModeTimeSeries) { + dynProperties.time_series_metric = field.metric_type; + } matchingType = field.object_type_mapping_type ?? 'double'; break; case 'byte': @@ -367,18 +382,24 @@ function _generateMappings( case 'short': case 'unsigned_long': dynProperties.type = field.object_type; - dynProperties.time_series_metric = field.metric_type; + if (isIndexModeTimeSeries) { + dynProperties.time_series_metric = field.metric_type; + } matchingType = field.object_type_mapping_type ?? 'long'; break; case 'integer': // Map integers as long, as in other cases. dynProperties.type = 'long'; - dynProperties.time_series_metric = field.metric_type; + if (isIndexModeTimeSeries) { + dynProperties.time_series_metric = field.metric_type; + } matchingType = field.object_type_mapping_type ?? 'long'; break; case 'boolean': dynProperties.type = field.object_type; - dynProperties.time_series_metric = field.metric_type; + if (isIndexModeTimeSeries) { + dynProperties.time_series_metric = field.metric_type; + } matchingType = field.object_type_mapping_type ?? field.object_type; break; case 'group': @@ -390,12 +411,16 @@ function _generateMappings( type: 'object', object_type: subField.object_type ?? subField.type, })); - const mappings = _generateMappings(subFields, { - ...ctx, - groupFieldName: ctx.groupFieldName - ? `${ctx.groupFieldName}.${field.name}` - : field.name, - }); + const mappings = _generateMappings( + subFields, + { + ...ctx, + groupFieldName: ctx.groupFieldName + ? `${ctx.groupFieldName}.${field.name}` + : field.name, + }, + isIndexModeTimeSeries + ); if (mappings.hasDynamicTemplateMappings) { hasDynamicTemplateMappings = true; } @@ -405,8 +430,8 @@ function _generateMappings( matchingType = field.object_type_mapping_type ?? 'object'; break; default: - throw new Error( - `no dynamic mapping generated for field ${path} of type ${field.object_type}` + throw new PackageInvalidArchiveError( + `No dynamic mapping generated for field ${path} of type ${field.object_type}` ); } @@ -422,12 +447,16 @@ function _generateMappings( switch (type) { case 'group': - const mappings = _generateMappings(field.fields!, { - ...ctx, - groupFieldName: ctx.groupFieldName - ? `${ctx.groupFieldName}.${field.name}` - : field.name, - }); + const mappings = _generateMappings( + field.fields!, + { + ...ctx, + groupFieldName: ctx.groupFieldName + ? `${ctx.groupFieldName}.${field.name}` + : field.name, + }, + isIndexModeTimeSeries + ); if (mappings.hasNonDynamicTemplateMappings) { fieldProps = { properties: @@ -450,12 +479,16 @@ function _generateMappings( break; case 'group-nested': fieldProps = { - properties: _generateMappings(field.fields!, { - ...ctx, - groupFieldName: ctx.groupFieldName - ? `${ctx.groupFieldName}.${field.name}` - : field.name, - }).properties, + properties: _generateMappings( + field.fields!, + { + ...ctx, + groupFieldName: ctx.groupFieldName + ? `${ctx.groupFieldName}.${field.name}` + : field.name, + }, + isIndexModeTimeSeries + ).properties, ...generateNestedProps(field), type: 'nested', }; @@ -543,10 +576,10 @@ function _generateMappings( } } - if ('metric_type' in field) { + if ('metric_type' in field && isIndexModeTimeSeries) { fieldProps.time_series_metric = field.metric_type; } - if (field.dimension) { + if (field.dimension && isIndexModeTimeSeries) { fieldProps.time_series_dimension = field.dimension; } @@ -878,7 +911,9 @@ const rolloverDataStream = (dataStreamName: string, esClient: ElasticsearchClien alias: dataStreamName, }); } catch (error) { - throw new Error(`cannot rollover data stream [${dataStreamName}] due to error: ${error}`); + throw new PackageESError( + `Cannot rollover data stream [${dataStreamName}] due to error: ${error}` + ); } }; @@ -1025,7 +1060,11 @@ const updateExistingDataStream = async ({ { logger } ); } catch (err) { - throw new Error(`could not update lifecycle settings for ${dataStreamName}: ${err.message}`); + // Check if this error can happen because of invalid settings; + // We are returning a 500 but in that case it should be a 400 instead + throw new PackageESError( + `Could not update lifecycle settings for ${dataStreamName}: ${err.message}` + ); } } @@ -1048,6 +1087,8 @@ const updateExistingDataStream = async ({ { logger } ); } catch (err) { - throw new Error(`could not update index template settings for ${dataStreamName}`); + // Same as above - Check if this error can happen because of invalid settings; + // We are returning a 500 but in that case it should be a 400 instead + throw new PackageESError(`Could not update index template settings for ${dataStreamName}`); } }; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 20a0484c77a4..23327a2253f8 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -35,6 +35,7 @@ import { savedObjectTypes } from '../../packages'; import { indexPatternTypes, getIndexPatternSavedObjects } from '../index_pattern/install'; import { saveKibanaAssetsRefs } from '../../packages/install'; import { deleteKibanaSavedObjectsAssets } from '../../packages/remove'; +import { KibanaSOReferenceError } from '../../../../errors'; import { withPackageSpan } from '../../packages/utils'; @@ -340,7 +341,7 @@ export async function installKibanaSavedObjects({ ); if (otherErrors?.length) { - throw new Error( + throw new KibanaSOReferenceError( `Encountered ${ otherErrors.length } errors creating saved objects: ${formatImportErrorsForLog(otherErrors)}` @@ -383,7 +384,7 @@ export async function installKibanaSavedObjects({ }); if (resolveErrors?.length) { - throw new Error( + throw new KibanaSOReferenceError( `Encountered ${ resolveErrors.length } errors resolving reference errors: ${formatImportErrorsForLog(resolveErrors)}` diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.ts b/x-pack/plugins/fleet/server/services/epm/package_service.ts index 39ca950af93d..e6f71cb7cb96 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.ts @@ -29,7 +29,7 @@ import type { } from '../../types'; import type { FleetAuthzRouteConfig } from '../security/types'; import { checkSuperuser, getAuthzFromRequest, doesNotHaveRequiredFleetAuthz } from '../security'; -import { FleetUnauthorizedError } from '../../errors'; +import { FleetUnauthorizedError, FleetError } from '../../errors'; import { INSTALL_PACKAGES_AUTHZ, READ_PACKAGE_INFO_AUTHZ } from '../../routes/epm'; import { installTransforms, isTransform } from './elasticsearch/transform/install'; @@ -208,7 +208,7 @@ class PackageClientImpl implements PackageClient { const transformPaths = assetPaths.filter(isTransform); if (transformPaths.length !== assetPaths.length) { - throw new Error('reinstallEsAssets is currently only implemented for transform assets'); + throw new FleetError('reinstallEsAssets is currently only implemented for transform assets'); } if (transformPaths.length) { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 105331f54d2c..d8a943fef534 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -57,6 +57,7 @@ import { installIndexTemplatesAndPipelines, } from './install'; import { withPackageSpan } from './utils'; +import { clearLatestFailedAttempts } from './install_errors_helpers'; // this is only exported for testing // use a leading underscore to indicate it's not the supported path @@ -333,6 +334,10 @@ export async function _installPackage({ install_status: 'installed', package_assets: packageAssetRefs, install_format_schema_version: FLEET_INSTALL_FORMAT_VERSION, + latest_install_failed_attempts: clearLatestFailedAttempts( + pkgVersion, + installedPkg?.attributes.latest_install_failed_attempts ?? [] + ), }) ); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/bundled_packages.ts b/x-pack/plugins/fleet/server/services/epm/packages/bundled_packages.ts index 7078761a4a58..92f967465610 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/bundled_packages.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/bundled_packages.ts @@ -9,7 +9,7 @@ import fs from 'fs/promises'; import path from 'path'; import type { BundledPackage, Installation } from '../../../types'; -import { FleetError } from '../../../errors'; +import { BundledPackageLocationNotFoundError } from '../../../errors'; import { appContextService } from '../../app_context'; import { splitPkgKey, pkgToPkgKey } from '../registry'; @@ -19,7 +19,9 @@ export async function getBundledPackages(): Promise { const bundledPackageLocation = config?.developer?.bundledPackageLocation; if (!bundledPackageLocation) { - throw new FleetError('xpack.fleet.developer.bundledPackageLocation is not configured'); + throw new BundledPackageLocationNotFoundError( + 'xpack.fleet.developer.bundledPackageLocation is not configured' + ); } // If the bundled package directory is missing, we log a warning during setup, @@ -51,7 +53,7 @@ export async function getBundledPackages(): Promise { return result; } catch (err) { const logger = appContextService.getLogger(); - logger.debug(`Unable to read bundled packages from ${bundledPackageLocation}`); + logger.warn(`Unable to read bundled packages from ${bundledPackageLocation}`); return []; } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index 68a884fd5f19..a3ed5f62d7f1 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -44,7 +44,6 @@ import type { } from '../../../../common/types'; import type { Installation, PackageInfo, PackagePolicySOAttributes } from '../../../types'; import { - FleetError, PackageFailedVerificationError, PackageNotFoundError, RegistryResponseError, @@ -575,6 +574,7 @@ export async function getPackageFromSource(options: { logger.debug(`retrieved installed package ${pkgName}-${pkgVersion}`); } catch (error) { if (error instanceof PackageFailedVerificationError) { + logger.error(`package ${pkgName}-${pkgVersion} failed verification`); throw error; } // treating this is a 404 as no status code returned @@ -600,7 +600,7 @@ export async function getPackageFromSource(options: { } } if (!res) { - throw new FleetError(`package info for ${pkgName}-${pkgVersion} does not exist`); + throw new PackageNotFoundError(`Package info for ${pkgName}-${pkgVersion} does not exist`); } return { paths: res.paths, diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts index f3e464d7a9f6..bc3e138b5619 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts @@ -243,6 +243,7 @@ describe('install', () => { it('should send telemetry on install failure, async error', async () => { jest.mocked(install._installPackage).mockRejectedValue(new Error('error')); jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ spaceId: DEFAULT_SPACE_ID, installSource: 'registry', diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index 3a7fc7809615..2dbf1662d436 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -57,11 +57,13 @@ import { DATASET_VAR_NAME, } from '../../../../common/constants'; import { - type FleetError, + FleetError, PackageOutdatedError, PackagePolicyValidationError, ConcurrentInstallOperationError, FleetUnauthorizedError, + PackageInvalidArchiveError, + PackageNotFoundError, } from '../../../errors'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; import { dataStreamService, licenseService } from '../..'; @@ -104,6 +106,7 @@ import { cacheAssets } from './custom_integrations/assets/cache'; import { generateDatastreamEntries } from './custom_integrations/assets/dataset/utils'; import { checkForNamingCollision } from './custom_integrations/validation/check_naming_collision'; import { checkDatasetsNameFormat } from './custom_integrations/validation/check_dataset_name_format'; +import { addErrorToLatestFailedAttempts } from './install_errors_helpers'; export async function isPackageInstalled(options: { savedObjectsClient: SavedObjectsClientContract; @@ -202,7 +205,7 @@ export async function ensureInstalledPackage(options: { } const installation = await getInstallation({ savedObjectsClient, pkgName }); - if (!installation) throw new Error(`could not get installation ${pkgName}`); + if (!installation) throw new FleetError(`Could not get installation for ${pkgName}`); return installation; } @@ -234,22 +237,33 @@ export async function handleInstallPackageFailure({ version: pkgVersion, }); + const latestInstallFailedAttempts = addErrorToLatestFailedAttempts({ + error, + targetVersion: pkgVersion, + createdAt: new Date().toISOString(), + latestAttempts: installedPkg?.attributes.latest_install_failed_attempts, + }); + // if there is an unknown server error, uninstall any package assets or reinstall the previous version if update try { const installType = getInstallType({ pkgVersion, installedPkg }); - if (installType === 'install' || installType === 'reinstall') { + if (installType === 'install') { logger.error(`uninstalling ${pkgkey} after error installing: [${error.toString()}]`); await removeInstallation({ savedObjectsClient, pkgName, pkgVersion, esClient }); return; } - await updateInstallStatus({ savedObjectsClient, pkgName, status: 'install_failed' }).catch( - (err) => { - if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { - logger.error(`failed to update package status to: install_failed ${err}`); - } - } - ); + await updateInstallStatusToFailed({ + logger, + savedObjectsClient, + pkgName, + status: 'install_failed', + latestInstallFailedAttempts, + }); + + if (installType === 'reinstall') { + logger.error(`Failed to reinstall ${pkgkey}: [${error.toString()}]`, { error }); + } if (installType === 'update') { if (!installedPkg) { @@ -272,13 +286,20 @@ export async function handleInstallPackageFailure({ } } catch (e) { // If an error happens while removing the integration or while doing a rollback update the status to failed - await updateInstallStatus({ savedObjectsClient, pkgName, status: 'install_failed' }).catch( - (err) => { - if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { - logger.error(`failed to update package status to: install_failed ${err}`); - } - } - ); + await updateInstallStatusToFailed({ + logger, + savedObjectsClient, + pkgName, + status: 'install_failed', + latestInstallFailedAttempts: installedPkg + ? addErrorToLatestFailedAttempts({ + error: e, + targetVersion: installedPkg.attributes.version, + createdAt: installedPkg.attributes.install_started_at, + latestAttempts: latestInstallFailedAttempts, + }) + : [], + }); logger.error(`failed to uninstall or rollback package after installation error ${e}`); } } @@ -597,7 +618,9 @@ async function installPackageCommon(options: { return { assets, status: 'installed', installType, installSource }; }) .catch(async (err: Error) => { - logger.warn(`Failure to install package [${pkgName}]: [${err.toString()}]`); + logger.warn(`Failure to install package [${pkgName}]: [${err.toString()}]`, { + error: { stack_trace: err.stack }, + }); await handleInstallPackageFailure({ savedObjectsClient, error: err, @@ -712,7 +735,7 @@ export type InstallPackageParams = { export async function installPackage(args: InstallPackageParams): Promise { if (!('installSource' in args)) { - throw new Error('installSource is required'); + throw new FleetError('installSource is required'); } const logger = appContextService.getLogger(); @@ -803,7 +826,7 @@ export async function installPackage(args: InstallPackageParams): Promise { auditLoggingService.writeCustomSoAuditLog({ action: 'update', id: pkgName, savedObjectType: PACKAGES_SAVED_OBJECT_TYPE, }); - - return savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { - install_status: status, - }); + try { + return await savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { + install_status: status, + latest_install_failed_attempts: latestInstallFailedAttempts, + }); + } catch (err) { + if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { + logger.error(`failed to update package status to: install_failed ${err}`); + } + } }; export async function restartInstallation(options: { @@ -1273,7 +1306,7 @@ export async function installAssetsForInputPackagePolicy(opts: { if (pkgInfo.type !== 'input') return; const paths = await getArchiveFilelist(pkgInfo); - if (!paths) throw new Error('No paths found for '); + if (!paths) throw new PackageInvalidArchiveError(`No paths found for ${pkgInfo.name}`); const datasetName = packagePolicy.inputs[0].streams[0].vars?.[DATASET_VAR_NAME]?.value; const [dataStream] = getNormalizedDataStreams(pkgInfo, datasetName); @@ -1336,7 +1369,9 @@ export async function installAssetsForInputPackagePolicy(opts: { logger, }); if (!installedPkg) - throw new Error('Unable to find installed package while creating index templates'); + throw new PackageNotFoundError( + `Error while creating index templates: unable to find installed package ${pkgInfo.name}` + ); await installIndexTemplatesAndPipelines({ installedPkg, paths, @@ -1381,5 +1416,5 @@ export function getInstallType(args: NoPkgArgs | HasPkgArgs): OnlyInstall | NotI if (pkgVersion === lastStartedInstallVersion && pkgVersion !== currentPkgVersion) return 'reupdate'; if (pkgVersion !== lastStartedInstallVersion && pkgVersion !== currentPkgVersion) return 'update'; - throw new Error('unknown install type'); + throw new FleetError('Unknown install type'); } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.test.ts new file mode 100644 index 000000000000..264ce1cbd550 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { InstallFailedAttempt } from '../../../types'; + +import { + clearLatestFailedAttempts, + addErrorToLatestFailedAttempts, +} from './install_errors_helpers'; + +const generateFailedAttempt = (version: string) => ({ + target_version: version, + created_at: new Date().toISOString(), + error: { + name: 'test', + message: 'test', + }, +}); + +const mapFailledAttempsToTargetVersion = (attemps: InstallFailedAttempt[]) => + attemps.map((attempt) => attempt.target_version); + +describe('Install error helpers', () => { + describe('clearLatestFailedAttempts', () => { + const previousFailedAttemps: InstallFailedAttempt[] = [ + generateFailedAttempt('0.1.0'), + generateFailedAttempt('0.2.0'), + ]; + it('should clear previous error on succesfull upgrade', () => { + const currentFailledAttemps = clearLatestFailedAttempts('0.2.0', previousFailedAttemps); + + expect(mapFailledAttempsToTargetVersion(currentFailledAttemps)).toEqual([]); + }); + + it('should not clear previous upgrade error on succesfull rollback', () => { + const currentFailledAttemps = clearLatestFailedAttempts('0.1.0', previousFailedAttemps); + + expect(mapFailledAttempsToTargetVersion(currentFailledAttemps)).toEqual(['0.2.0']); + }); + }); + + describe('addErrorToLatestFailedAttempts', () => { + it('should only keep 5 errors', () => { + const previousFailedAttemps: InstallFailedAttempt[] = [ + generateFailedAttempt('0.2.5'), + generateFailedAttempt('0.2.4'), + generateFailedAttempt('0.2.3'), + generateFailedAttempt('0.2.2'), + generateFailedAttempt('0.2.1'), + ]; + const currentFailledAttemps = addErrorToLatestFailedAttempts({ + targetVersion: '0.2.6', + createdAt: new Date().toISOString(), + error: new Error('new test'), + latestAttempts: previousFailedAttemps, + }); + + expect(mapFailledAttempsToTargetVersion(currentFailledAttemps)).toEqual([ + '0.2.6', + '0.2.5', + '0.2.4', + '0.2.3', + '0.2.2', + ]); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.ts new file mode 100644 index 000000000000..1642acd7349b --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_errors_helpers.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { lt } from 'semver'; + +import type { InstallFailedAttempt } from '../../../types'; + +const MAX_ATTEMPTS_TO_KEEP = 5; + +export function clearLatestFailedAttempts( + installedVersion: string, + latestAttempts: InstallFailedAttempt[] = [] +) { + return latestAttempts.filter((attempt) => lt(installedVersion, attempt.target_version)); +} + +export function addErrorToLatestFailedAttempts({ + error, + createdAt, + targetVersion, + latestAttempts = [], +}: { + createdAt: string; + targetVersion: string; + error: Error; + latestAttempts?: InstallFailedAttempt[]; +}): InstallFailedAttempt[] { + return [ + { + created_at: createdAt, + target_version: targetVersion, + error: { + name: error.name, + message: error.message, + stack: error.stack, + }, + }, + ...latestAttempts, + ].slice(0, MAX_ATTEMPTS_TO_KEEP); +} diff --git a/x-pack/plugins/fleet/server/services/epm/packages/reinstall.ts b/x-pack/plugins/fleet/server/services/epm/packages/reinstall.ts index d2672b608981..cb2b91de252f 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/reinstall.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/reinstall.ts @@ -11,6 +11,8 @@ import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; import type { Installation } from '../../../types'; import { pkgToPkgKey } from '../registry'; +import { PackageNotFoundError, PackageAlreadyInstalledError } from '../../../errors'; + import { getBundledPackageForInstallation } from './bundled_packages'; import { installPackage } from './install'; @@ -29,9 +31,11 @@ export async function reinstallPackageForInstallation({ const matchingBundledPackage = await getBundledPackageForInstallation(installation); if (!matchingBundledPackage) { if (installation.install_source === 'bundled') { - throw new Error(`Cannot reinstall: ${installation.name}, bundled package not found`); + throw new PackageNotFoundError( + `Cannot reinstall: ${installation.name}, bundled package not found` + ); } else { - throw new Error('Cannot reinstall an uploaded package'); + throw new PackageAlreadyInstalledError('Cannot reinstall an uploaded package'); } } } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.test.ts index f15043fe5292..badb1bc7c1f4 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.test.ts @@ -18,6 +18,7 @@ jest.mock('../..', () => { getLogger: jest.fn().mockReturnValue({ info: jest.fn(), error: jest.fn(), + warn: jest.fn(), }), }, packagePolicyService: { @@ -78,7 +79,7 @@ describe('removeInstallation', () => { force: false, }) ).rejects.toThrowError( - `unable to remove package with existing package policy(s) in use by agent(s)` + `Unable to remove package with existing package policy(s) in use by agent(s)` ); }); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts index c65a4d165cf7..ba9bace6a0de 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts @@ -7,8 +7,6 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; -import Boom from '@hapi/boom'; - import type { SavedObject } from '@kbn/core/server'; import { SavedObjectsClient } from '@kbn/core/server'; @@ -42,6 +40,7 @@ import { deleteIlms } from '../elasticsearch/datastream_ilm/remove'; import { removeArchiveEntries } from '../archive/storage'; import { auditLoggingService } from '../../audit_logging'; +import { FleetError, PackageRemovalError } from '../../../errors'; import { populatePackagePolicyAssignedAgentsCount } from '../../package_policies/populate_package_policy_assigned_agents_count'; @@ -56,7 +55,7 @@ export async function removeInstallation(options: { }): Promise { const { savedObjectsClient, pkgName, pkgVersion, esClient } = options; const installation = await getInstallation({ savedObjectsClient, pkgName }); - if (!installation) throw Boom.badRequest(`${pkgName} is not installed`); + if (!installation) throw new PackageRemovalError(`${pkgName} is not installed`); const { total, items } = await packagePolicyService.list(savedObjectsClient, { kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${pkgName}`, @@ -72,17 +71,12 @@ export async function removeInstallation(options: { if (options.force || items.every((item) => (item.agents ?? 0) === 0)) { // delete package policies const ids = items.map((item) => item.id); - appContextService - .getLogger() - .info( - `deleting package policies of ${pkgName} package because not used by agents or force flag was enabled: ${ids}` - ); await packagePolicyService.delete(savedObjectsClient, esClient, ids, { force: options.force, }); } else { - throw Boom.badRequest( - `unable to remove package with existing package policy(s) in use by agent(s)` + throw new PackageRemovalError( + `Unable to remove package with existing package policy(s) in use by agent(s)` ); } } @@ -242,7 +236,7 @@ async function deleteIndexTemplate(esClient: ElasticsearchClient, name: string): try { await esClient.indices.deleteIndexTemplate({ name }, { ignore: [404] }); } catch { - throw new Error(`error deleting index template ${name}`); + throw new FleetError(`Error deleting index template ${name}`); } } } @@ -253,7 +247,7 @@ async function deleteComponentTemplate(esClient: ElasticsearchClient, name: stri try { await esClient.cluster.deleteComponentTemplate({ name }, { ignore: [404] }); } catch (error) { - throw new Error(`error deleting component template ${name}`); + throw new FleetError(`Error deleting component template ${name}`); } } } diff --git a/x-pack/plugins/fleet/server/services/epm/packages/update.ts b/x-pack/plugins/fleet/server/services/epm/packages/update.ts index 3072dfed8663..72c43b6dc688 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/update.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/update.ts @@ -12,7 +12,7 @@ import type { ExperimentalIndexingFeature } from '../../../../common/types'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; import type { Installation, UpdatePackageRequestSchema } from '../../../types'; -import { FleetError } from '../../../errors'; +import { PackageNotFoundError } from '../../../errors'; import { auditLoggingService } from '../../audit_logging'; @@ -29,7 +29,7 @@ export async function updatePackage( const installedPackage = await getInstallationObject({ savedObjectsClient, pkgName }); if (!installedPackage) { - throw new FleetError(`package ${pkgName} is not installed`); + throw new PackageNotFoundError(`Error while updating package: ${pkgName} is not installed`); } auditLoggingService.writeCustomSoAuditLog({ diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.ts index 487faf55730b..24c81dd02324 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.ts @@ -43,6 +43,7 @@ import { PackageNotFoundError, RegistryResponseError, PackageFailedVerificationError, + PackageUnsupportedMediaTypeError, } from '../../../errors'; import { getBundledPackageByName } from '../packages/bundled_packages'; @@ -364,8 +365,11 @@ export async function getPackage( function ensureContentType(archivePath: string) { const contentType = mime.lookup(archivePath); + if (!contentType) { - throw new Error(`Unknown compression format for '${archivePath}'. Please use .zip or .gz`); + throw new PackageUnsupportedMediaTypeError( + `Unknown compression format for '${archivePath}'. Please use .zip or .gz` + ); } return contentType; } diff --git a/x-pack/plugins/fleet/server/services/fleet_proxies.ts b/x-pack/plugins/fleet/server/services/fleet_proxies.ts index 604276e6d588..cf45b90804c2 100644 --- a/x-pack/plugins/fleet/server/services/fleet_proxies.ts +++ b/x-pack/plugins/fleet/server/services/fleet_proxies.ts @@ -205,7 +205,7 @@ async function updateRelatedSavedObject( outputService.update(soClient, esClient, output.id, { ...omit(output, 'id'), proxy_id: null, - }); + } as Partial); }, { concurrency: 20 } ); diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index 0cb1099b58eb..016026533e3c 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -419,7 +419,12 @@ class OutputService { soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, output: NewOutput, - options?: { id?: string; fromPreconfiguration?: boolean; overwrite?: boolean } + options?: { + id?: string; + fromPreconfiguration?: boolean; + overwrite?: boolean; + secretHashes?: Record; + } ): Promise { const data: OutputSOAttributes = { ...omit(output, ['ssl', 'secrets']) }; if (output.type === outputType.RemoteElasticsearch) { @@ -555,6 +560,7 @@ class OutputService { const { output: outputWithSecrets } = await extractAndWriteOutputSecrets({ output, esClient, + secretHashes: output.is_preconfigured ? options?.secretHashes : undefined, }); if (outputWithSecrets.secrets) data.secrets = outputWithSecrets.secrets; @@ -716,7 +722,10 @@ class OutputService { esClient: ElasticsearchClient, id: string, data: Partial, - { fromPreconfiguration = false }: { fromPreconfiguration: boolean } = { + { + fromPreconfiguration = false, + secretHashes, + }: { fromPreconfiguration: boolean; secretHashes?: Record } = { fromPreconfiguration: false, } ) { @@ -747,6 +756,7 @@ class OutputService { oldOutput: originalOutput, outputUpdate: data, esClient, + secretHashes: data.is_preconfigured ? secretHashes : undefined, }); updateData.secrets = secretsRes.outputUpdate.secrets; diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.ts b/x-pack/plugins/fleet/server/services/preconfiguration.ts index 350909d3de0a..2a76a9660778 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.ts @@ -255,10 +255,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( ); }); - apm.startTransaction( - 'fleet.preconfiguration.addPackagePolicies.improved.prReview.50', - 'fleet' - ); + const s = apm.startSpan('Add preconfigured package policies', 'preconfiguration'); await addPreconfiguredPolicyPackages( soClient, esClient, @@ -267,7 +264,7 @@ export async function ensurePreconfiguredPackagesAndPolicies( defaultOutput, true ); - apm.endTransaction('fleet.preconfiguration.addPackagePolicies.improved.prReview.50'); + s?.end(); // Add the is_managed flag after configuring package policies to avoid errors if (shouldAddIsManagedFlag) { diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts index 1023e1bdb7b5..174b8051a991 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.test.ts @@ -17,6 +17,7 @@ import { createOrUpdatePreconfiguredOutputs, cleanPreconfiguredOutputs, getPreconfiguredOutputFromConfig, + hashSecret, } from './outputs'; jest.mock('../agent_policy_update'); @@ -46,24 +47,70 @@ const spyAgentPolicyServicBumpAllAgentPoliciesForOutput = jest.spyOn( ); describe('output preconfiguration', () => { - beforeEach(() => { + beforeEach(async () => { mockedOutputService.create.mockReset(); mockedOutputService.update.mockReset(); mockedOutputService.delete.mockReset(); mockedOutputService.getDefaultDataOutputId.mockReset(); mockedOutputService.getDefaultESHosts.mockReturnValue(['http://default-es:9200']); + const keyHash = (await hashSecret('secretKey')) as string; + const passwordHash = (await hashSecret('secretPassword')) as string; + const serviceTokenHash = (await hashSecret('secretServiceToken')) as string; mockedOutputService.bulkGet.mockImplementation(async (soClient, id): Promise => { return [ { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', // @ts-ignore type: 'elasticsearch', hosts: ['http://es.co:80'], is_preconfigured: true, }, + { + id: 'existing-logstash-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output 1', + type: 'logstash', + hosts: ['test:4343'], + is_preconfigured: true, + ssl: { + key: 'unsecureKey', + }, + }, + { + id: 'existing-logstash-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output With Secrets 1', + type: 'logstash', + hosts: ['test:4343'], + is_preconfigured: true, + secrets: { + ssl: { + key: { + id: '123', + hash: keyHash, + }, + }, + }, + }, + { + id: 'existing-logstash-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output With Secrets 2', + type: 'logstash', + hosts: ['test:4343'], + is_preconfigured: true, + secrets: { + ssl: { + key: 'secretKey', + }, + }, + }, { id: 'existing-kafka-output-1', is_default: false, @@ -73,11 +120,91 @@ describe('output preconfiguration', () => { type: 'kafka', hosts: ['kafka.co:80'], is_preconfigured: true, + password: 'unsecurePassword', + ssl: { + key: 'unsecureKey', + }, + }, + { + id: 'existing-kafka-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Kafka Output With Secrets 1', + type: 'kafka', + hosts: ['kafka.co:80'], + is_preconfigured: true, + secrets: { + password: { + id: '456', + hash: passwordHash, + }, + ssl: { + key: { + id: '789', + hash: keyHash, + }, + }, + }, + }, + { + id: 'existing-kafka-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Kafka Output With Secrets 2', + type: 'kafka', + hosts: ['kafka.co:80'], + is_preconfigured: true, + secrets: { + password: 'secretPassword', + ssl: { + key: 'secretKey', + }, + }, + }, + { + id: 'existing-remote-es-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output 1', + type: 'remote_elasticsearch', + hosts: ['https:es.co:80'], + is_preconfigured: true, + service_token: 'unsecureServiceToken', + }, + { + id: 'existing-remote-es-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output With Secrets 1', + type: 'remote_elasticsearch', + hosts: ['https:es.co:80'], + is_preconfigured: true, + secrets: { + service_token: { + id: '101112', + hash: serviceTokenHash, + }, + }, + }, + { + id: 'existing-remote-es-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output With Secrets 2', + type: 'remote_elasticsearch', + hosts: ['https:es.co:80'], + is_preconfigured: true, + secrets: { + service_token: 'secretServiceToken', + }, }, ]; }); + spyAgentPolicyServicBumpAllAgentPoliciesForOutput.mockClear(); }); + // Output creation + it('should generate a preconfigured output if elasticsearch.hosts is set in the config', async () => { expect( getPreconfiguredOutputFromConfig({ @@ -104,13 +231,13 @@ describe('output preconfiguration', () => { `); }); - it('should create preconfigured output that does not exists', async () => { + it('should create a preconfigured ES output that does not exist', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'non-existing-output-1', - name: 'Output 1', + id: 'non-existing-es-output-1', + name: 'ES Output 1', type: 'elasticsearch', is_default: false, is_default_monitoring: false, @@ -123,37 +250,86 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); - it('should create preconfigured kafka output that does not exists', async () => { + it('should create a preconfigured ES output with ca_trusted_fingerprint that does not exist', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'non-existing-kafka-output-1', - name: 'Output 1', - type: 'kafka', + id: 'non-existing-es-output-1', + name: 'ES Output 1', + type: 'elasticsearch', is_default: false, is_default_monitoring: false, - hosts: ['test.fr:2000'], + hosts: ['http://test.fr'], + ca_trusted_fingerprint: 'testfingerprint', }, ]); expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.create).toBeCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ + ca_trusted_fingerprint: 'testfingerprint', + }), + expect.anything() + ); expect(mockedOutputService.update).not.toBeCalled(); expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); - it('should create a preconfigured output with ca_trusted_fingerprint that does not exists', async () => { + it('should create a preconfigured ES output with default hosts if the output does not exist and hosts is not set', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'non-existing-output-1', + id: 'non-existing-es-output-1', name: 'Output 1', type: 'elasticsearch', is_default: false, is_default_monitoring: false, - hosts: ['http://test.fr'], - ca_trusted_fingerprint: 'testfingerprint', + }, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.create.mock.calls[0][2].hosts).toEqual(['http://default-es:9200']); + }); + + it('should create a preconfigured logstash output that does not exist', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-logstash-output-1', + name: 'Logstash Output 1', + type: 'logstash', + is_default: false, + is_default_monitoring: false, + hosts: ['test:4343'], + ssl: { certificate: 'test', key: 'test' }, + }, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should create a preconfigured logstash output with secrets that does not exist', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-logstash-output-with-secrets-1', + name: 'Logstash Output With Secrets 1', + type: 'logstash', + is_default: false, + is_default_monitoring: false, + secrets: { + ssl: { + key: 'secretKey', + }, + }, }, ]); @@ -162,7 +338,11 @@ describe('output preconfiguration', () => { expect.anything(), expect.anything(), expect.objectContaining({ - ca_trusted_fingerprint: 'testfingerprint', + secrets: { + ssl: { + key: 'secretKey', + }, + }, }), expect.anything() ); @@ -170,18 +350,17 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); - it('should create preconfigured logstash output that does not exist', async () => { + it('should create preconfigured kafka output that does not exist', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'non-existing-output-1', - name: 'Output 1', - type: 'logstash', + id: 'non-existing-kafka-output-1', + name: 'Kafka Output 1', + type: 'kafka', is_default: false, is_default_monitoring: false, - hosts: ['test.fr'], - ssl: { certificate: 'test', key: 'test' }, + hosts: ['test.fr:2000'], }, ]); @@ -190,33 +369,83 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); - it('should set default hosts if hosts is not set output that does not exists', async () => { + it('should create a preconfigured kafka output with secrets that does not exist', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'non-existing-output-1', - name: 'Output 1', - type: 'elasticsearch', + id: 'non-existing-kafka-output-with-secrets-1', + name: 'Kafka Output With Secrets 2', + type: 'kafka', is_default: false, is_default_monitoring: false, + secrets: { + password: 'secretPassword', + ssl: { + key: 'secretKey', + }, + }, }, ]); expect(mockedOutputService.create).toBeCalled(); - expect(mockedOutputService.create.mock.calls[0][2].hosts).toEqual(['http://default-es:9200']); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should create a preconfigured remote ES output that does not exist', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-remote-es-output-1', + name: 'Remote ES Output 1', + type: 'remote_elasticsearch', + is_default: false, + is_default_monitoring: false, + hosts: ['test.fr'], + service_token: 'serviceToken', + } as PreconfiguredOutput, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should create a preconfigured remote ES output with secrets that does not exist', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'non-existing-remote-es-output-with-secrets-1', + name: 'Remote ES Output With Secrets 2', + type: 'remote_elasticsearch', + is_default: false, + is_default_monitoring: false, + secrets: { + remote_elasticsearch: 'secretServiceToken', + }, + }, + ]); + + expect(mockedOutputService.create).toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); - it('should update output if non preconfigured output with the same id exists', async () => { + // Output should update + + it('should update output if non preconfigured ES output with the same id exists', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); mockedOutputService.bulkGet.mockResolvedValue([ { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', // @ts-ignore type: 'elasticsearch', hosts: ['http://es.co:80'], @@ -225,10 +454,10 @@ describe('output preconfiguration', () => { ]); await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', type: 'elasticsearch', hosts: ['http://es.co:80'], }, @@ -239,7 +468,7 @@ describe('output preconfiguration', () => { expect(mockedOutputService.update).toBeCalledWith( expect.anything(), expect.anything(), - 'existing-output-1', + 'existing-es-output-1', expect.objectContaining({ is_preconfigured: true, }), @@ -248,16 +477,16 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); }); - it('should update output if preconfigured output exists and changed', async () => { + it('should update output if preconfigured ES output exists and changed', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', type: 'elasticsearch', hosts: ['http://newhostichanged.co:9201'], // field that changed }, @@ -268,6 +497,54 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); }); + it('should update output if a preconfigured logstash ouput exists and has changed', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-logstash-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output 1', + type: 'logstash', + hosts: ['test:4343'], + is_preconfigured: true, + ssl: { + key: 'unsecureKey2', // field that changed + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + it('should update output if a preconfigured logstash ouput with secrets exists and has changed', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-logstash-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output With Secrets 1', + type: 'logstash', + secrets: { + ssl: { + key: 'secretKey2', // field that changed + }, + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + it('should update output if preconfigured kafka output exists and changed', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; @@ -279,7 +556,7 @@ describe('output preconfiguration', () => { is_default_monitoring: false, name: 'Kafka Output 1', type: 'kafka', - hosts: ['kafka.co:8080'], + hosts: ['kafka.co:8080'], // field that changed }, ]); @@ -288,18 +565,92 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); }); - it('should not update output if preconfigured output exists and did not changed', async () => { + it('should update ouput if a preconfigured kafka with secrets exists and has changed', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ { - id: 'existing-output-1', + id: 'existing-kafka-output-with-secrets-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', - type: 'elasticsearch', - hosts: ['http://newhostichanged.co:9201'], // field that changed + name: 'Kafka Output With Secrets 1', + type: 'kafka', + secrets: { + password: 'secretPassword2', // field that changed + ssl: { + key: 'secretKey2', + }, + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + it('should update output if preconfigured remote ES output exists and changed', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-remote-es-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output 1', + type: 'remote_elasticsearch', + is_preconfigured: true, + service_token: 'stillUnsecureServiceToken', // field that changed + } as PreconfiguredOutput, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + it('should update ouput if a preconfigured remote ES with secrets exists and has changed', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-remote-es-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output With Secrets 1', + type: 'remote_elasticsearch', + is_preconfigured: true, + secrets: { + service_token: 'secretServiceToken2', // field that changed + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + it('should update output if a preconfigured logstash output with plain value secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-logstash-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output With Secrets 2', + type: 'logstash', + hosts: ['test:4343'], + secrets: { + ssl: { + key: 'secretKey', // no change + }, + }, }, ]); @@ -308,6 +659,101 @@ describe('output preconfiguration', () => { expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); }); + it('should update output if a preconfigured kafka output with plain value secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-kafka-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Kafka Output With Secrets 2', + type: 'kafka', + hosts: ['kafka.co:80'], + secrets: { + password: 'secretPassword', // no change + ssl: { + key: 'secretKey', // no change + }, + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + it('should update output if a preconfigured remote ES output with plain value secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-remote-es-output-with-secrets-2', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output With Secrets 2', + type: 'remote_elasticsearch', + is_preconfigured: true, + secrets: { + service_token: 'secretServiceToken', // no change + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + }); + + // Output should not update + + it('should not update output if preconfigured ES output exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-es-output-1', + is_default: false, + is_default_monitoring: false, + name: 'ES Output 1', + type: 'elasticsearch', + hosts: ['http://es.co:80'], + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should not update output if preconfigured logstash output exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-logstash-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output 1', + type: 'logstash', + hosts: ['test:4343'], + is_preconfigured: true, + ssl: { + key: 'unsecureKey', + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + it('should not update output if preconfigured kafka output exists and did not change', async () => { const soClient = savedObjectsClientMock.create(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; @@ -319,23 +765,124 @@ describe('output preconfiguration', () => { is_default_monitoring: false, name: 'Kafka Output 1', type: 'kafka', - hosts: ['kafka.co:8080'], + hosts: ['kafka.co:80'], + password: 'unsecurePassword', + ssl: { + key: 'unsecureKey', + }, + } as PreconfiguredOutput, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should not update output if preconfigured remote ES output exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-remote-es-output-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output 1', + type: 'remote_elasticsearch', + hosts: ['https:es.co:80'], + is_preconfigured: true, + service_token: 'unsecureServiceToken', + } as PreconfiguredOutput, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should not update output if a preconfigured logstash output with secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-logstash-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Logstash Output With Secrets 1', + type: 'logstash', + hosts: ['test:4343'], + secrets: { + ssl: { + key: 'secretKey', + }, + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should not update output if a preconfigured kafka output with secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-kafka-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Kafka Output With Secrets 1', + type: 'kafka', + hosts: ['kafka.co:80'], + secrets: { + password: 'secretPassword', + ssl: { + key: 'secretKey', + }, + }, }, ]); expect(mockedOutputService.create).not.toBeCalled(); - expect(mockedOutputService.update).toBeCalled(); - expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); + }); + + it('should not update output if a preconfigured remote ES output with secrets exists and did not change', async () => { + const soClient = savedObjectsClientMock.create(); + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 }); + await createOrUpdatePreconfiguredOutputs(soClient, esClient, [ + { + id: 'existing-remote-es-output-with-secrets-1', + is_default: false, + is_default_monitoring: false, + name: 'Remote ES Output With Secrets 1', + type: 'remote_elasticsearch', + hosts: ['https:es.co:80'], + is_preconfigured: true, + secrets: { + service_token: 'secretServiceToken', + }, + }, + ]); + + expect(mockedOutputService.create).not.toBeCalled(); + expect(mockedOutputService.update).not.toBeCalled(); + expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled(); }); const SCENARIOS: Array<{ name: string; data: PreconfiguredOutput }> = [ { name: 'no changes', data: { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', type: 'elasticsearch', hosts: ['http://es.co:80'], }, @@ -343,10 +890,10 @@ describe('output preconfiguration', () => { { name: 'hosts without port', data: { - id: 'existing-output-1', + id: 'existing-es-output-1', is_default: false, is_default_monitoring: false, - name: 'Output 1', + name: 'ES Output 1', type: 'elasticsearch', hosts: ['http://es.co'], }, diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 5bc7c452b481..ac105fc29a35 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -5,11 +5,20 @@ * 2.0. */ +import crypto from 'crypto'; + import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import { isEqual } from 'lodash'; import { safeDump } from 'js-yaml'; -import type { PreconfiguredOutput, Output, NewOutput } from '../../../common/types'; +import type { + PreconfiguredOutput, + Output, + NewOutput, + OutputSecret, + KafkaOutput, + NewLogstashOutput, +} from '../../../common/types'; import { normalizeHostsForAgents } from '../../../common/services'; import type { FleetConfigType } from '../../config'; import { DEFAULT_OUTPUT_ID, DEFAULT_OUTPUT } from '../../constants'; @@ -82,7 +91,7 @@ export async function createOrUpdatePreconfiguredOutputs( ca_sha256: outputData.ca_sha256 ?? null, ca_trusted_fingerprint: outputData.ca_trusted_fingerprint ?? null, ssl: outputData.ssl ?? null, - }; + } as NewOutput; if (!data.hosts || data.hosts.length === 0) { data.hosts = outputService.getDefaultESHosts(); @@ -99,25 +108,101 @@ export async function createOrUpdatePreconfiguredOutputs( } const isUpdateWithNewData = - existingOutput && isPreconfiguredOutputDifferentFromCurrent(existingOutput, data); - - if (isCreate) { - logger.debug(`Creating output ${output.id}`); - await outputService.create(soClient, esClient, data, { id, fromPreconfiguration: true }); - } else if (isUpdateWithNewData) { - logger.debug(`Updating output ${output.id}`); - await outputService.update(soClient, esClient, id, data, { fromPreconfiguration: true }); - // Bump revision of all policies using that output - if (outputData.is_default || outputData.is_default_monitoring) { - await agentPolicyService.bumpAllAgentPolicies(soClient, esClient); - } else { - await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id); + existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)); + + if (isCreate || isUpdateWithNewData) { + const secretHashes = await hashSecrets(output); + + if (isCreate) { + logger.debug(`Creating preconfigured output ${output.id}`); + await outputService.create(soClient, esClient, data, { + id, + fromPreconfiguration: true, + secretHashes, + }); + } else if (isUpdateWithNewData) { + logger.debug(`Updating preconfigured output ${output.id}`); + await outputService.update(soClient, esClient, id, data, { + fromPreconfiguration: true, + secretHashes, + }); + // Bump revision of all policies using that output + if (outputData.is_default || outputData.is_default_monitoring) { + await agentPolicyService.bumpAllAgentPolicies(soClient, esClient); + } else { + await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id); + } } } }) ); } +// Values recommended by NodeJS documentation +const keyLength = 64; +const saltLength = 16; + +// N=2^14 (16 MiB), r=8 (1024 bytes), p=5 +const scryptParams = { + cost: 16384, + blockSize: 8, + parallelization: 5, +}; + +export async function hashSecret(secret: string) { + return new Promise((resolve, reject) => { + const salt = crypto.randomBytes(saltLength).toString('hex'); + crypto.scrypt(secret, salt, keyLength, scryptParams, (err, derivedKey) => { + if (err) reject(err); + resolve(`${salt}:${derivedKey.toString('hex')}`); + }); + }); +} + +async function verifySecret(hash: string, secret: string) { + return new Promise((resolve, reject) => { + const [salt, key] = hash.split(':'); + crypto.scrypt(secret, salt, keyLength, scryptParams, (err, derivedKey) => { + if (err) reject(err); + resolve(crypto.timingSafeEqual(Buffer.from(key, 'hex'), derivedKey)); + }); + }); +} + +async function hashSecrets(output: PreconfiguredOutput) { + if (output.type === 'kafka') { + const kafkaOutput = output as KafkaOutput; + if (typeof kafkaOutput.secrets?.password === 'string') { + const password = await hashSecret(kafkaOutput.secrets?.password); + return { + password, + }; + } + if (typeof kafkaOutput.secrets?.ssl?.key === 'string') { + const key = await hashSecret(kafkaOutput.secrets?.ssl?.key); + return { + ssl: { + key, + }, + }; + } + } + if (output.type === 'logstash') { + const logstashOutput = output as NewLogstashOutput; + + if (typeof logstashOutput.secrets?.ssl?.key === 'string') { + const key = await hashSecret(logstashOutput.secrets?.ssl?.key); + return { + ssl: { + key, + }, + }; + } + } + + return undefined; +} + export async function cleanPreconfiguredOutputs( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, @@ -165,15 +250,56 @@ export async function cleanPreconfiguredOutputs( } } -function isPreconfiguredOutputDifferentFromCurrent( +const hasHash = (secret?: OutputSecret): secret is { id: string; hash: string } => { + return !!secret && typeof secret !== 'string' && !!secret.hash; +}; + +async function isSecretDifferent( + preconfiguredValue: OutputSecret | undefined, + existingSecret: OutputSecret | undefined +): Promise { + if (!existingSecret && preconfiguredValue) { + return true; + } + + if (!preconfiguredValue && existingSecret) { + return true; + } + + if (!preconfiguredValue && !existingSecret) { + return false; + } + + if (hasHash(existingSecret) && typeof preconfiguredValue === 'string') { + // verifying the has tells us if the value has changed + const hashIsVerified = await verifySecret(existingSecret.hash, preconfiguredValue!); + + return !hashIsVerified; + } else { + // if there is no hash then the safest thing to do is assume the value has changed + return true; + } +} + +async function isPreconfiguredOutputDifferentFromCurrent( existingOutput: Output, preconfiguredOutput: Partial -): boolean { - const kafkaFieldsAreDifferent = (): boolean => { +): Promise { + const kafkaFieldsAreDifferent = async (): Promise => { if (existingOutput.type !== 'kafka' || preconfiguredOutput.type !== 'kafka') { return false; } + const passwordHashIsDifferent = await isSecretDifferent( + preconfiguredOutput.secrets?.password, + existingOutput.secrets?.password + ); + + const sslKeyHashIsDifferent = await isSecretDifferent( + preconfiguredOutput.secrets?.ssl?.key, + existingOutput.secrets?.ssl?.key + ); + return ( isDifferent(existingOutput.client_id, preconfiguredOutput.client_id) || isDifferent(existingOutput.version, preconfiguredOutput.version) || @@ -193,8 +319,22 @@ function isPreconfiguredOutputDifferentFromCurrent( isDifferent(existingOutput.headers, preconfiguredOutput.headers) || isDifferent(existingOutput.timeout, preconfiguredOutput.timeout) || isDifferent(existingOutput.broker_timeout, preconfiguredOutput.broker_timeout) || - isDifferent(existingOutput.required_acks, preconfiguredOutput.required_acks) + isDifferent(existingOutput.required_acks, preconfiguredOutput.required_acks) || + passwordHashIsDifferent || + sslKeyHashIsDifferent + ); + }; + + const logstashFieldsAreDifferent = async (): Promise => { + if (existingOutput.type !== 'logstash' || preconfiguredOutput.type !== 'logstash') { + return false; + } + const sslKeyHashIsDifferent = await isSecretDifferent( + preconfiguredOutput.secrets?.ssl?.key, + existingOutput.secrets?.ssl?.key ); + + return sslKeyHashIsDifferent; }; return ( @@ -221,6 +361,7 @@ function isPreconfiguredOutputDifferentFromCurrent( isDifferent(existingOutput.config_yaml, preconfiguredOutput.config_yaml) || isDifferent(existingOutput.proxy_id, preconfiguredOutput.proxy_id) || isDifferent(existingOutput.allow_edit ?? [], preconfiguredOutput.allow_edit ?? []) || - kafkaFieldsAreDifferent() + (await kafkaFieldsAreDifferent()) || + (await logstashFieldsAreDifferent()) ); } diff --git a/x-pack/plugins/fleet/server/services/secrets.test.ts b/x-pack/plugins/fleet/server/services/secrets.test.ts index 66b13638085d..3a46d90f557e 100644 --- a/x-pack/plugins/fleet/server/services/secrets.test.ts +++ b/x-pack/plugins/fleet/server/services/secrets.test.ts @@ -12,584 +12,918 @@ * 2[0]. */ +import { v4 as uuidv4 } from 'uuid'; + +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; + +import { createAppContextStartContractMock } from '../mocks'; + import type { NewPackagePolicy, PackageInfo } from '../types'; -import { getPolicySecretPaths, diffSecretPaths } from './secrets'; +import { appContextService } from './app_context'; +import { + getPolicySecretPaths, + diffSecretPaths, + diffOutputSecretPaths, + extractAndWriteSecrets, +} from './secrets'; -describe('getPolicySecretPaths', () => { - describe('integration package with one policy template', () => { - const mockIntegrationPackage = { - name: 'mock-package', - title: 'Mock package', - version: '0[0].0', - description: 'description', - type: 'integration', - status: 'not_installed', - vars: [ - { name: 'pkg-secret-1', type: 'text', secret: true }, - { name: 'pkg-secret-2', type: 'text', secret: true }, - ], - data_streams: [ - { - dataset: 'somedataset', - streams: [ +describe('secrets', () => { + let mockContract: ReturnType; + + beforeEach(async () => { + // prevents `Logger not set.` and other appContext errors + mockContract = createAppContextStartContractMock(); + appContextService.start(mockContract); + }); + + describe('getPolicySecretPaths', () => { + describe('integration package with one policy template', () => { + const mockIntegrationPackage = { + name: 'mock-package', + title: 'Mock package', + version: '0[0].0', + description: 'description', + type: 'integration', + status: 'not_installed', + vars: [ + { name: 'pkg-secret-1', type: 'text', secret: true }, + { name: 'pkg-secret-2', type: 'text', secret: true }, + ], + data_streams: [ + { + dataset: 'somedataset', + streams: [ + { + input: 'foo', + title: 'Foo', + vars: [ + { name: 'stream-secret-1', type: 'text', secret: true }, + { name: 'stream-secret-2', type: 'text', secret: true }, + ], + }, + ], + }, + ], + policy_templates: [ + { + name: 'pkgPolicy1', + title: 'Package policy 1', + description: 'test package policy', + inputs: [ + { + type: 'foo', + title: 'Foo', + vars: [ + { default: 'foo-input-var-value', name: 'foo-input-var-name', type: 'text' }, + { + name: 'input-secret-1', + type: 'text', + secret: true, + }, + { + name: 'input-secret-2', + type: 'text', + secret: true, + }, + { name: 'foo-input3-var-name', type: 'text', multi: true }, + ], + }, + ], + }, + ], + } as unknown as PackageInfo; + it('policy with package level secret vars', () => { + const packagePolicy = { + vars: { + 'pkg-secret-1': { + value: 'pkg-secret-1-val', + }, + 'pkg-secret-2': { + value: 'pkg-secret-2-val', + }, + }, + inputs: [], + } as unknown as NewPackagePolicy; + + expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ + { + path: 'vars.pkg-secret-1', + value: { + value: 'pkg-secret-1-val', + }, + }, + { + path: 'vars.pkg-secret-2', + value: { + value: 'pkg-secret-2-val', + }, + }, + ]); + }); + it('policy with package level secret vars and only one set', () => { + const packagePolicy = { + vars: { + 'pkg-secret-1': { + value: 'pkg-secret-1-val', + }, + }, + inputs: [], + } as unknown as NewPackagePolicy; + + expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ + { + path: 'vars.pkg-secret-1', + value: { + value: 'pkg-secret-1-val', + }, + }, + ]); + }); + it('policy with input level secret vars', () => { + const packagePolicy = { + inputs: [ { - input: 'foo', - title: 'Foo', - vars: [ - { name: 'stream-secret-1', type: 'text', secret: true }, - { name: 'stream-secret-2', type: 'text', secret: true }, - ], + type: 'foo', + policy_template: 'pkgPolicy1', + vars: { + 'input-secret-1': { + value: 'input-secret-1-val', + }, + 'input-secret-2': { + value: 'input-secret-2-val', + }, + }, + streams: [], }, ], - }, - ], - policy_templates: [ - { - name: 'pkgPolicy1', - title: 'Package policy 1', - description: 'test package policy', + } as unknown as NewPackagePolicy; + + expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ + { + path: 'inputs[0].vars.input-secret-1', + value: { value: 'input-secret-1-val' }, + }, + { + path: 'inputs[0].vars.input-secret-2', + value: { value: 'input-secret-2-val' }, + }, + ]); + }); + it('stream level secret vars', () => { + const packagePolicy = { inputs: [ { type: 'foo', - title: 'Foo', - vars: [ - { default: 'foo-input-var-value', name: 'foo-input-var-name', type: 'text' }, - { - name: 'input-secret-1', - type: 'text', - secret: true, - }, + policy_template: 'pkgPolicy1', + streams: [ { - name: 'input-secret-2', - type: 'text', - secret: true, + data_stream: { + dataset: 'somedataset', + type: 'logs', + }, + vars: { + 'stream-secret-1': { + value: 'stream-secret-1-value', + }, + 'stream-secret-2': { + value: 'stream-secret-2-value', + }, + }, }, - { name: 'foo-input3-var-name', type: 'text', multi: true }, ], }, ], - }, - ], - } as unknown as PackageInfo; - it('policy with package level secret vars', () => { - const packagePolicy = { - vars: { - 'pkg-secret-1': { - value: 'pkg-secret-1-val', - }, - 'pkg-secret-2': { - value: 'pkg-secret-2-val', - }, - }, - inputs: [], - } as unknown as NewPackagePolicy; + } as unknown as NewPackagePolicy; - expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ - { - path: 'vars.pkg-secret-1', - value: { - value: 'pkg-secret-1-val', + expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ + { + path: 'inputs[0].streams[0].vars.stream-secret-1', + value: { value: 'stream-secret-1-value' }, }, - }, - { - path: 'vars.pkg-secret-2', - value: { - value: 'pkg-secret-2-val', + { + path: 'inputs[0].streams[0].vars.stream-secret-2', + value: { value: 'stream-secret-2-value' }, }, - }, - ]); + ]); + }); }); - it('policy with package level secret vars and only one set', () => { - const packagePolicy = { - vars: { - 'pkg-secret-1': { - value: 'pkg-secret-1-val', - }, - }, - inputs: [], - } as unknown as NewPackagePolicy; - expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ - { - path: 'vars.pkg-secret-1', - value: { - value: 'pkg-secret-1-val', + describe('integration package with multiple policy templates (e.g AWS)', () => { + const miniAWsPackage = { + name: 'aws', + title: 'AWS', + version: '0.5.3', + release: 'beta', + description: 'AWS Integration', + type: 'integration', + policy_templates: [ + { + name: 'billing', + title: 'AWS Billing', + description: 'Collect AWS billing metrics', + data_streams: ['billing'], + inputs: [ + { + type: 'aws/metrics', + title: 'Collect billing metrics', + description: 'Collect billing metrics', + input_group: 'metrics', + vars: [ + { + name: 'password', + type: 'text', + secret: true, + }, + ], + }, + ], }, - }, - ]); - }); - it('policy with input level secret vars', () => { - const packagePolicy = { - inputs: [ - { - type: 'foo', - policy_template: 'pkgPolicy1', - vars: { - 'input-secret-1': { - value: 'input-secret-1-val', + { + name: 'cloudtrail', + title: 'AWS Cloudtrail', + description: 'Collect logs from AWS Cloudtrail', + data_streams: ['cloudtrail'], + inputs: [ + { + type: 's3', + title: 'Collect logs from Cloudtrail service', + description: 'Collecting Cloudtrail logs using S3 input', + input_group: 'logs', + vars: [ + { + name: 'password', + type: 'text', + secret: true, + }, + ], }, - 'input-secret-2': { - value: 'input-secret-2-val', + { + type: 'httpjson', + title: 'Collect logs from third-party REST API (experimental)', + description: 'Collect logs from third-party REST API (experimental)', + input_group: 'logs', + vars: [ + { + name: 'password', + type: 'text', + secret: true, + }, + ], }, - }, - streams: [], + ], }, ], - } as unknown as NewPackagePolicy; - - expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ - { - path: 'inputs[0].vars.input-secret-1', - value: { value: 'input-secret-1-val' }, - }, - { - path: 'inputs[0].vars.input-secret-2', - value: { value: 'input-secret-2-val' }, - }, - ]); - }); - it('stream level secret vars', () => { - const packagePolicy = { - inputs: [ + vars: [ { - type: 'foo', - policy_template: 'pkgPolicy1', + name: 'secret_access_key', + type: 'text', + title: 'Secret Access Key', + multi: false, + required: false, + show_user: false, + secret: true, + }, + ], + data_streams: [ + { + type: 'metrics', + dataset: 'aws.billing', + title: 'AWS billing metrics', + release: 'beta', streams: [ { - data_stream: { - dataset: 'somedataset', - type: 'logs', - }, - vars: { - 'stream-secret-1': { - value: 'stream-secret-1-value', + input: 'aws/metrics', + vars: [ + { + name: 'password', + type: 'text', + secret: true, }, - 'stream-secret-2': { - value: 'stream-secret-2-value', + ], + template_path: 'stream.yml.hbs', + title: 'AWS Billing metrics', + description: 'Collect AWS billing metrics', + enabled: true, + }, + ], + package: 'aws', + path: 'billing', + }, + { + type: 'logs', + dataset: 'aws.cloudtrail', + title: 'AWS CloudTrail logs', + release: 'beta', + ingest_pipeline: 'default', + streams: [ + { + input: 's3', + vars: [ + { + name: 'password', + type: 'text', + secret: true, }, - }, + ], + template_path: 's3.yml.hbs', + }, + { + input: 'httpjson', + vars: [ + { + name: 'username', + type: 'text', + title: 'Splunk REST API Username', + multi: false, + required: true, + show_user: true, + }, + { + name: 'password', + type: 'password', + title: 'Splunk REST API Password', + multi: false, + required: true, + show_user: true, + secret: true, + }, + ], + template_path: 'httpjson.yml.hbs', }, ], + package: 'aws', + path: 'cloudtrail', }, ], - } as unknown as NewPackagePolicy; - - expect(getPolicySecretPaths(packagePolicy, mockIntegrationPackage)).toEqual([ - { - path: 'inputs[0].streams[0].vars.stream-secret-1', - value: { value: 'stream-secret-1-value' }, - }, - { - path: 'inputs[0].streams[0].vars.stream-secret-2', - value: { value: 'stream-secret-2-value' }, - }, - ]); - }); - }); - - describe('integration package with multiple policy templates (e.g AWS)', () => { - const miniAWsPackage = { - name: 'aws', - title: 'AWS', - version: '0.5.3', - release: 'beta', - description: 'AWS Integration', - type: 'integration', - policy_templates: [ - { - name: 'billing', - title: 'AWS Billing', - description: 'Collect AWS billing metrics', - data_streams: ['billing'], + } as PackageInfo; + it('single policy with package + input + stream level secret var', () => { + const policy = { + vars: { + secret_access_key: { + value: 'my_secret_access_key', + }, + }, inputs: [ { type: 'aws/metrics', - title: 'Collect billing metrics', - description: 'Collect billing metrics', - input_group: 'metrics', - vars: [ + policy_template: 'billing', + enabled: true, + vars: { + password: { value: 'billing_input_password', type: 'text' }, + }, + streams: [ { - name: 'password', - type: 'text', - secret: true, + enabled: true, + data_stream: { type: 'metrics', dataset: 'aws.billing' }, + vars: { + password: { value: 'billing_stream_password', type: 'text' }, + }, }, ], }, ], - }, - { - name: 'cloudtrail', - title: 'AWS Cloudtrail', - description: 'Collect logs from AWS Cloudtrail', - data_streams: ['cloudtrail'], - inputs: [ - { - type: 's3', - title: 'Collect logs from Cloudtrail service', - description: 'Collecting Cloudtrail logs using S3 input', - input_group: 'logs', - vars: [ - { - name: 'password', - type: 'text', - secret: true, - }, - ], + }; + expect( + getPolicySecretPaths( + policy as unknown as NewPackagePolicy, + miniAWsPackage as unknown as PackageInfo + ) + ).toEqual([ + { + path: 'vars.secret_access_key', + value: { + value: 'my_secret_access_key', + }, + }, + { + path: 'inputs[0].vars.password', + value: { + type: 'text', + value: 'billing_input_password', + }, + }, + { + path: 'inputs[0].streams[0].vars.password', + value: { + type: 'text', + value: 'billing_stream_password', + }, + }, + ]); + }); + it('double policy with package + input + stream level secret var', () => { + const policy = { + vars: { + secret_access_key: { + value: 'my_secret_access_key', }, + }, + inputs: [ { type: 'httpjson', - title: 'Collect logs from third-party REST API (experimental)', - description: 'Collect logs from third-party REST API (experimental)', - input_group: 'logs', - vars: [ + policy_template: 'cloudtrail', + enabled: false, + vars: { + password: { value: 'cloudtrail_httpjson_input_password' }, + }, + streams: [ { - name: 'password', - type: 'text', - secret: true, + data_stream: { type: 'logs', dataset: 'aws.cloudtrail' }, + vars: { + username: { value: 'hop_dev' }, + password: { value: 'cloudtrail_httpjson_stream_password' }, + }, }, ], }, - ], - }, - ], - vars: [ - { - name: 'secret_access_key', - type: 'text', - title: 'Secret Access Key', - multi: false, - required: false, - show_user: false, - secret: true, - }, - ], - data_streams: [ - { - type: 'metrics', - dataset: 'aws.billing', - title: 'AWS billing metrics', - release: 'beta', - streams: [ { - input: 'aws/metrics', - vars: [ + type: 's3', + policy_template: 'cloudtrail', + enabled: true, + vars: { + password: { value: 'cloudtrail_s3_input_password' }, + }, + streams: [ { - name: 'password', - type: 'text', - secret: true, + enabled: true, + data_stream: { type: 'logs', dataset: 'aws.cloudtrail' }, + vars: { + password: { value: 'cloudtrail_s3_stream_password' }, + }, }, ], - template_path: 'stream.yml.hbs', - title: 'AWS Billing metrics', - description: 'Collect AWS billing metrics', - enabled: true, }, ], - package: 'aws', - path: 'billing', - }, - { - type: 'logs', - dataset: 'aws.cloudtrail', - title: 'AWS CloudTrail logs', - release: 'beta', - ingest_pipeline: 'default', - streams: [ - { - input: 's3', - vars: [ - { - name: 'password', - type: 'text', - secret: true, - }, - ], - template_path: 's3.yml.hbs', + }; + + expect( + getPolicySecretPaths( + policy as unknown as NewPackagePolicy, + miniAWsPackage as unknown as PackageInfo + ) + ).toEqual([ + { + path: 'vars.secret_access_key', + value: { + value: 'my_secret_access_key', }, - { - input: 'httpjson', - vars: [ - { - name: 'username', - type: 'text', - title: 'Splunk REST API Username', - multi: false, - required: true, - show_user: true, - }, - { - name: 'password', - type: 'password', - title: 'Splunk REST API Password', - multi: false, - required: true, - show_user: true, - secret: true, - }, - ], - template_path: 'httpjson.yml.hbs', + }, + { + path: 'inputs[0].vars.password', + value: { + value: 'cloudtrail_httpjson_input_password', }, - ], - package: 'aws', - path: 'cloudtrail', - }, - ], - } as PackageInfo; - it('single policy with package + input + stream level secret var', () => { - const policy = { - vars: { - secret_access_key: { - value: 'my_secret_access_key', }, - }, - inputs: [ { - type: 'aws/metrics', - policy_template: 'billing', - enabled: true, - vars: { - password: { value: 'billing_input_password', type: 'text' }, + path: 'inputs[0].streams[0].vars.password', + value: { + value: 'cloudtrail_httpjson_stream_password', }, - streams: [ + }, + { + path: 'inputs[1].vars.password', + value: { + value: 'cloudtrail_s3_input_password', + }, + }, + { + path: 'inputs[1].streams[0].vars.password', + value: { + value: 'cloudtrail_s3_stream_password', + }, + }, + ]); + }); + }); + + describe('input package', () => { + const mockInputPackage = { + name: 'log', + version: '2.0.0', + description: 'Collect custom logs with Elastic Agent.', + title: 'Custom Logs', + format_version: '2.6.0', + owner: { + github: 'elastic/elastic-agent-data-plane', + }, + type: 'input', + categories: ['custom', 'custom_logs'], + conditions: {}, + icons: [], + policy_templates: [ + { + name: 'logs', + title: 'Custom log file', + description: 'Collect your custom log files.', + multiple: true, + input: 'logfile', + type: 'logs', + template_path: 'input.yml.hbs', + vars: [ { - enabled: true, - data_stream: { type: 'metrics', dataset: 'aws.billing' }, - vars: { - password: { value: 'billing_stream_password', type: 'text' }, - }, + name: 'paths', + required: true, + title: 'Log file path', + description: 'Path to log files to be collected', + type: 'text', + multi: true, + }, + { + name: 'data_stream.dataset', + required: true, + title: 'Dataset name', + description: + "Set the name for your dataset. Changing the dataset will send the data to a different index. You can't use `-` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html).\n", + type: 'text', + }, + { + name: 'secret-1', + type: 'text', + secret: true, + }, + { + name: 'secret-2', + type: 'text', + secret: true, }, ], }, ], }; - expect( - getPolicySecretPaths( - policy as unknown as NewPackagePolicy, - miniAWsPackage as unknown as PackageInfo - ) - ).toEqual([ + it('template level vars', () => { + const policy = { + inputs: [ + { + type: 'logfile', + policy_template: 'logs', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + type: 'logs', + dataset: 'log.logs', + }, + vars: { + paths: { + value: ['/tmp/test.log'], + }, + 'data_stream.dataset': { + value: 'hello', + }, + 'secret-1': { + value: 'secret-1-value', + }, + 'secret-2': { + value: 'secret-2-value', + }, + }, + }, + ], + }, + ], + }; + + expect( + getPolicySecretPaths( + policy as unknown as NewPackagePolicy, + mockInputPackage as unknown as PackageInfo + ) + ).toEqual([ + { + path: 'inputs[0].streams[0].vars.secret-1', + value: { + value: 'secret-1-value', + }, + }, + { + path: 'inputs[0].streams[0].vars.secret-2', + value: { + value: 'secret-2-value', + }, + }, + ]); + }); + }); + }); + + describe('diffSecretPaths', () => { + it('should return empty array if no secrets', () => { + expect(diffSecretPaths([], [])).toEqual({ + toCreate: [], + toDelete: [], + noChange: [], + }); + }); + it('should return empty array if single secret not changed', () => { + const paths = [ { - path: 'vars.secret_access_key', + path: 'somepath', value: { - value: 'my_secret_access_key', + value: { + isSecretRef: true, + id: 'secret-1', + }, }, }, + ]; + expect(diffSecretPaths(paths, paths)).toEqual({ + toCreate: [], + toDelete: [], + noChange: paths, + }); + }); + it('should return empty array if multiple secrets not changed', () => { + const paths = [ { - path: 'inputs[0].vars.password', + path: 'somepath', value: { - type: 'text', - value: 'billing_input_password', + value: { + isSecretRef: true, + id: 'secret-1', + }, }, }, { - path: 'inputs[0].streams[0].vars.password', + path: 'somepath2', value: { - type: 'text', - value: 'billing_stream_password', + value: { + isSecretRef: true, + id: 'secret-2', + }, }, }, - ]); + { + path: 'somepath3', + value: { + value: { + isSecretRef: true, + id: 'secret-3', + }, + }, + }, + ]; + + expect(diffSecretPaths(paths, paths.slice().reverse())).toEqual({ + toCreate: [], + toDelete: [], + noChange: paths, + }); }); - it('double policy with package + input + stream level secret var', () => { - const policy = { - vars: { - secret_access_key: { - value: 'my_secret_access_key', + it('single secret modified', () => { + const paths1 = [ + { + path: 'somepath1', + value: { + value: { + isSecretRef: true, + id: 'secret-1', + }, + }, + }, + { + path: 'somepath2', + value: { + value: { isSecretRef: true, id: 'secret-2' }, }, }, - inputs: [ + ]; + + const paths2 = [ + paths1[0], + { + path: 'somepath2', + value: { value: 'newvalue' }, + }, + ]; + + expect(diffSecretPaths(paths1, paths2)).toEqual({ + toCreate: [ { - type: 'httpjson', - policy_template: 'cloudtrail', - enabled: false, - vars: { - password: { value: 'cloudtrail_httpjson_input_password' }, - }, - streams: [ - { - data_stream: { type: 'logs', dataset: 'aws.cloudtrail' }, - vars: { - username: { value: 'hop_dev' }, - password: { value: 'cloudtrail_httpjson_stream_password' }, - }, - }, - ], + path: 'somepath2', + value: { value: 'newvalue' }, }, + ], + toDelete: [ { - type: 's3', - policy_template: 'cloudtrail', - enabled: true, - vars: { - password: { value: 'cloudtrail_s3_input_password' }, - }, - streams: [ - { - enabled: true, - data_stream: { type: 'logs', dataset: 'aws.cloudtrail' }, - vars: { - password: { value: 'cloudtrail_s3_stream_password' }, - }, + path: 'somepath2', + value: { + value: { + isSecretRef: true, + id: 'secret-2', }, - ], + }, }, ], - }; - - expect( - getPolicySecretPaths( - policy as unknown as NewPackagePolicy, - miniAWsPackage as unknown as PackageInfo - ) - ).toEqual([ + noChange: [paths1[0]], + }); + }); + it('double secret modified', () => { + const paths1 = [ { - path: 'vars.secret_access_key', + path: 'somepath1', value: { - value: 'my_secret_access_key', + value: { + isSecretRef: true, + id: 'secret-1', + }, }, }, { - path: 'inputs[0].vars.password', + path: 'somepath2', value: { - value: 'cloudtrail_httpjson_input_password', + value: { + isSecretRef: true, + id: 'secret-2', + }, }, }, + ]; + + const paths2 = [ { - path: 'inputs[0].streams[0].vars.password', - value: { - value: 'cloudtrail_httpjson_stream_password', - }, + path: 'somepath1', + value: { value: 'newvalue1' }, }, { - path: 'inputs[1].vars.password', - value: { - value: 'cloudtrail_s3_input_password', - }, + path: 'somepath2', + value: { value: 'newvalue2' }, }, + ]; + + expect(diffSecretPaths(paths1, paths2)).toEqual({ + toCreate: [ + { + path: 'somepath1', + value: { value: 'newvalue1' }, + }, + { + path: 'somepath2', + value: { value: 'newvalue2' }, + }, + ], + toDelete: [ + { + path: 'somepath1', + value: { + value: { + isSecretRef: true, + id: 'secret-1', + }, + }, + }, + { + path: 'somepath2', + value: { + value: { + isSecretRef: true, + id: 'secret-2', + }, + }, + }, + ], + noChange: [], + }); + }); + + it('single secret added', () => { + const paths1 = [ { - path: 'inputs[1].streams[0].vars.password', + path: 'somepath1', value: { - value: 'cloudtrail_s3_stream_password', + value: { + isSecretRef: true, + id: 'secret-1', + }, }, }, - ]); + ]; + + const paths2 = [ + paths1[0], + { + path: 'somepath2', + value: { value: 'newvalue' }, + }, + ]; + + expect(diffSecretPaths(paths1, paths2)).toEqual({ + toCreate: [ + { + path: 'somepath2', + value: { value: 'newvalue' }, + }, + ], + toDelete: [], + noChange: [paths1[0]], + }); }); }); - describe('input package', () => { - const mockInputPackage = { - name: 'log', - version: '2.0.0', - description: 'Collect custom logs with Elastic Agent.', - title: 'Custom Logs', - format_version: '2.6.0', - owner: { - github: 'elastic/elastic-agent-data-plane', - }, - type: 'input', - categories: ['custom', 'custom_logs'], - conditions: {}, - icons: [], - policy_templates: [ + describe('extractAndWriteSecrets', () => { + const esClientMock = elasticsearchServiceMock.createInternalClient(); + + esClientMock.transport.request.mockImplementation(async (req) => { + return { + id: uuidv4(), + }; + }); + + beforeEach(() => { + esClientMock.transport.request.mockClear(); + }); + + const mockIntegrationPackage = { + name: 'mock-package', + title: 'Mock package', + version: '0.0.0', + description: 'description', + type: 'integration', + status: 'not_installed', + vars: [ + { name: 'pkg-secret-1', type: 'text', secret: true, required: true }, + { name: 'pkg-secret-2', type: 'text', secret: true, required: false }, + ], + data_streams: [ { - name: 'logs', - title: 'Custom log file', - description: 'Collect your custom log files.', - multiple: true, - input: 'logfile', - type: 'logs', - template_path: 'input.yml.hbs', - vars: [ - { - name: 'paths', - required: true, - title: 'Log file path', - description: 'Path to log files to be collected', - type: 'text', - multi: true, - }, - { - name: 'data_stream.dataset', - required: true, - title: 'Dataset name', - description: - "Set the name for your dataset. Changing the dataset will send the data to a different index. You can't use `-` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html).\n", - type: 'text', - }, + dataset: 'somedataset', + streams: [ { - name: 'secret-1', - type: 'text', - secret: true, + input: 'foo', + title: 'Foo', }, + ], + }, + ], + policy_templates: [ + { + name: 'pkgPolicy1', + title: 'Package policy 1', + description: 'test package policy', + inputs: [ { - name: 'secret-2', - type: 'text', - secret: true, + type: 'foo', + title: 'Foo', + vars: [], }, ], }, ], - }; - it('template level vars', () => { - const policy = { - inputs: [ - { - type: 'logfile', - policy_template: 'logs', - enabled: true, - streams: [ - { - enabled: true, - data_stream: { - type: 'logs', - dataset: 'log.logs', - }, - vars: { - paths: { - value: ['/tmp/test.log'], - }, - 'data_stream.dataset': { - value: 'hello', - }, - 'secret-1': { - value: 'secret-1-value', - }, - 'secret-2': { - value: 'secret-2-value', - }, - }, - }, - ], - }, - ], - }; + } as unknown as PackageInfo; - expect( - getPolicySecretPaths( - policy as unknown as NewPackagePolicy, - mockInputPackage as unknown as PackageInfo - ) - ).toEqual([ - { - path: 'inputs[0].streams[0].vars.secret-1', - value: { - value: 'secret-1-value', + describe('when only required secret value is provided', () => { + it('returns single secret reference for required secret', async () => { + const mockPackagePolicy = { + vars: { + 'pkg-secret-1': { + value: 'pkg-secret-1-val', + }, }, - }, - { - path: 'inputs[0].streams[0].vars.secret-2', - value: { - value: 'secret-2-value', + inputs: [], + } as unknown as NewPackagePolicy; + + const result = await extractAndWriteSecrets({ + packagePolicy: mockPackagePolicy, + packageInfo: mockIntegrationPackage, + esClient: esClientMock, + }); + + expect(esClientMock.transport.request).toHaveBeenCalledTimes(1); + expect(result.secretReferences).toHaveLength(1); + }); + }); + + describe('when both required and optional secret values are provided', () => { + it('returns secret reference for both required and optional secret', async () => { + const mockPackagePolicy = { + vars: { + 'pkg-secret-1': { + value: 'pkg-secret-1-val', + }, + 'pkg-secret-2': { + value: 'pkg-secret-2-val', + }, }, - }, - ]); + inputs: [], + } as unknown as NewPackagePolicy; + + const result = await extractAndWriteSecrets({ + packagePolicy: mockPackagePolicy, + packageInfo: mockIntegrationPackage, + esClient: esClientMock, + }); + + expect(esClientMock.transport.request).toHaveBeenCalledTimes(2); + expect(result.secretReferences).toHaveLength(2); + }); }); }); }); -describe('diffSecretPaths', () => { +describe('diffOutputSecretPaths', () => { it('should return empty array if no secrets', () => { - expect(diffSecretPaths([], [])).toEqual({ + expect(diffOutputSecretPaths([], [])).toEqual({ toCreate: [], toDelete: [], noChange: [], @@ -600,14 +934,11 @@ describe('diffSecretPaths', () => { { path: 'somepath', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, ]; - expect(diffSecretPaths(paths, paths)).toEqual({ + expect(diffOutputSecretPaths(paths, paths)).toEqual({ toCreate: [], toDelete: [], noChange: paths, @@ -618,33 +949,24 @@ describe('diffSecretPaths', () => { { path: 'somepath', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, { path: 'somepath2', value: { - value: { - isSecretRef: true, - id: 'secret-2', - }, + id: 'secret-2', }, }, { path: 'somepath3', value: { - value: { - isSecretRef: true, - id: 'secret-3', - }, + id: 'secret-3', }, }, ]; - expect(diffSecretPaths(paths, paths.slice().reverse())).toEqual({ + expect(diffOutputSecretPaths(paths, paths.slice().reverse())).toEqual({ toCreate: [], toDelete: [], noChange: paths, @@ -655,16 +977,13 @@ describe('diffSecretPaths', () => { { path: 'somepath1', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, { path: 'somepath2', value: { - value: { isSecretRef: true, id: 'secret-2' }, + id: 'secret-2', }, }, ]; @@ -673,25 +992,22 @@ describe('diffSecretPaths', () => { paths1[0], { path: 'somepath2', - value: { value: 'newvalue' }, + value: 'newvalue', }, ]; - expect(diffSecretPaths(paths1, paths2)).toEqual({ + expect(diffOutputSecretPaths(paths1, paths2)).toEqual({ toCreate: [ { path: 'somepath2', - value: { value: 'newvalue' }, + value: 'newvalue', }, ], toDelete: [ { path: 'somepath2', value: { - value: { - isSecretRef: true, - id: 'secret-2', - }, + id: 'secret-2', }, }, ], @@ -703,19 +1019,13 @@ describe('diffSecretPaths', () => { { path: 'somepath1', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, { path: 'somepath2', value: { - value: { - isSecretRef: true, - id: 'secret-2', - }, + id: 'secret-2', }, }, ]; @@ -723,42 +1033,36 @@ describe('diffSecretPaths', () => { const paths2 = [ { path: 'somepath1', - value: { value: 'newvalue1' }, + value: 'newvalue1', }, { path: 'somepath2', - value: { value: 'newvalue2' }, + value: 'newvalue2', }, ]; - expect(diffSecretPaths(paths1, paths2)).toEqual({ + expect(diffOutputSecretPaths(paths1, paths2)).toEqual({ toCreate: [ { path: 'somepath1', - value: { value: 'newvalue1' }, + value: 'newvalue1', }, { path: 'somepath2', - value: { value: 'newvalue2' }, + value: 'newvalue2', }, ], toDelete: [ { path: 'somepath1', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, { path: 'somepath2', value: { - value: { - isSecretRef: true, - id: 'secret-2', - }, + id: 'secret-2', }, }, ], @@ -771,10 +1075,7 @@ describe('diffSecretPaths', () => { { path: 'somepath1', value: { - value: { - isSecretRef: true, - id: 'secret-1', - }, + id: 'secret-1', }, }, ]; @@ -783,15 +1084,15 @@ describe('diffSecretPaths', () => { paths1[0], { path: 'somepath2', - value: { value: 'newvalue' }, + value: 'newvalue', }, ]; - expect(diffSecretPaths(paths1, paths2)).toEqual({ + expect(diffOutputSecretPaths(paths1, paths2)).toEqual({ toCreate: [ { path: 'somepath2', - value: { value: 'newvalue' }, + value: 'newvalue', }, ], toDelete: [], diff --git a/x-pack/plugins/fleet/server/services/secrets.ts b/x-pack/plugins/fleet/server/services/secrets.ts index 36a88b4a7a4c..c425a8a9e172 100644 --- a/x-pack/plugins/fleet/server/services/secrets.ts +++ b/x-pack/plugins/fleet/server/services/secrets.ts @@ -7,10 +7,16 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; -import { keyBy } from 'lodash'; +import { get, keyBy } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; -import type { KafkaOutput, Output, OutputSecretPath } from '../../common/types'; +import type { + KafkaOutput, + NewLogstashOutput, + NewRemoteElasticsearchOutput, + Output, + OutputSecretPath, +} from '../../common/types'; import { packageHasNoPolicyTemplates } from '../../common/services/policy_template'; @@ -228,13 +234,15 @@ export async function extractAndWriteSecrets(opts: { return { packagePolicy, secretReferences: [] }; } + const secretsToCreate = secretPaths.filter((secretPath) => !!secretPath.value.value); + const secrets = await createSecrets({ esClient, - values: secretPaths.map((secretPath) => secretPath.value.value), + values: secretsToCreate.map((secretPath) => secretPath.value.value), }); const policyWithSecretRefs = JSON.parse(JSON.stringify(packagePolicy)); - secretPaths.forEach((secretPath, i) => { + secretsToCreate.forEach((secretPath, i) => { set(policyWithSecretRefs, secretPath.path + '.value', toVarSecretRef(secrets[i].id)); }); @@ -247,8 +255,9 @@ export async function extractAndWriteSecrets(opts: { export async function extractAndWriteOutputSecrets(opts: { output: NewOutput; esClient: ElasticsearchClient; + secretHashes?: Record; }): Promise<{ output: NewOutput; secretReferences: PolicySecretReference[] }> { - const { output, esClient } = opts; + const { output, esClient, secretHashes = {} } = opts; const secretPaths = getOutputSecretPaths(output.type, output).filter( (path) => typeof path.value === 'string' @@ -265,7 +274,12 @@ export async function extractAndWriteOutputSecrets(opts: { const outputWithSecretRefs = JSON.parse(JSON.stringify(output)); secretPaths.forEach((secretPath, i) => { - set(outputWithSecretRefs, secretPath.path, { id: secrets[i].id }); + const pathWithoutPrefix = secretPath.path.replace('secrets.', ''); + const maybeHash = get(secretHashes, pathWithoutPrefix); + set(outputWithSecretRefs, secretPath.path, { + id: secrets[i].id, + ...(typeof maybeHash === 'string' && { hash: maybeHash }), + }); }); return { @@ -280,11 +294,14 @@ function getOutputSecretPaths( ): OutputSecretPath[] { const outputSecretPaths: OutputSecretPath[] = []; - if ((outputType === 'kafka' || outputType === 'logstash') && output.secrets?.ssl?.key) { - outputSecretPaths.push({ - path: 'secrets.ssl.key', - value: output.secrets.ssl.key, - }); + if (outputType === 'logstash') { + const logstashOutput = output as NewLogstashOutput; + if (logstashOutput?.secrets?.ssl?.key) { + outputSecretPaths.push({ + path: 'secrets.ssl.key', + value: logstashOutput.secrets.ssl.key, + }); + } } if (outputType === 'kafka') { @@ -295,6 +312,22 @@ function getOutputSecretPaths( value: kafkaOutput.secrets.password, }); } + if (kafkaOutput?.secrets?.ssl?.key) { + outputSecretPaths.push({ + path: 'secrets.ssl.key', + value: kafkaOutput.secrets.ssl.key, + }); + } + } + + if (outputType === 'remote_elasticsearch') { + const remoteESOutput = output as NewRemoteElasticsearchOutput; + if (remoteESOutput.secrets?.service_token) { + outputSecretPaths.push({ + path: 'secrets.service_token', + value: remoteESOutput.secrets.service_token, + }); + } } return outputSecretPaths; @@ -340,6 +373,15 @@ export function getOutputSecretReferences(output: Output): PolicySecretReference }); } + if ( + output.type === 'remote_elasticsearch' && + typeof output?.secrets?.service_token === 'object' + ) { + outputSecretPaths.push({ + id: output.secrets.service_token.id, + }); + } + return outputSecretPaths; } @@ -384,7 +426,7 @@ export async function extractAndUpdateSecrets(opts: { // check if the previous secret is actually a secret refrerence // it may be that secrets were not enabled at the time of creation // in which case they are just stored as plain text - if (secretPath.value.value.isSecretRef) { + if (secretPath.value.value?.isSecretRef) { secretsToDelete.push({ id: secretPath.value.value.id }); } }); @@ -399,12 +441,13 @@ export async function extractAndUpdateOutputSecrets(opts: { oldOutput: Output; outputUpdate: Partial; esClient: ElasticsearchClient; + secretHashes?: Record; }): Promise<{ outputUpdate: Partial; secretReferences: PolicySecretReference[]; secretsToDelete: PolicySecretReference[]; }> { - const { oldOutput, outputUpdate, esClient } = opts; + const { oldOutput, outputUpdate, esClient, secretHashes } = opts; const outputType = outputUpdate.type || oldOutput.type; const oldSecretPaths = getOutputSecretPaths(outputType, oldOutput); const updatedSecretPaths = getOutputSecretPaths(outputType, outputUpdate); @@ -425,7 +468,13 @@ export async function extractAndUpdateOutputSecrets(opts: { const outputWithSecretRefs = JSON.parse(JSON.stringify(outputUpdate)); toCreate.forEach((secretPath, i) => { - set(outputWithSecretRefs, secretPath.path, { id: createdSecrets[i].id }); + const pathWithoutPrefix = secretPath.path.replace('secrets.', ''); + const maybeHash = get(secretHashes, pathWithoutPrefix); + + set(outputWithSecretRefs, secretPath.path, { + id: createdSecrets[i].id, + ...(typeof maybeHash === 'string' && { hash: maybeHash }), + }); }); const secretReferences = [ @@ -509,10 +558,12 @@ export function diffOutputSecretPaths( const newPath = newPathsByPath[oldPath.path]; if (newPath && newPath.value) { const newValue = newPath.value; - if (typeof newValue === 'string') toCreate.push(newPath); - toDelete.push(oldPath); - } else { - noChange.push(newPath); + if (typeof newValue === 'string') { + toCreate.push(newPath); + toDelete.push(oldPath); + } else { + noChange.push(newPath); + } } delete newPathsByPath[oldPath.path]; } diff --git a/x-pack/plugins/fleet/server/services/security/fleet_router.test.ts b/x-pack/plugins/fleet/server/services/security/fleet_router.test.ts index 1e7d09f26160..5de46b845bfc 100644 --- a/x-pack/plugins/fleet/server/services/security/fleet_router.test.ts +++ b/x-pack/plugins/fleet/server/services/security/fleet_router.test.ts @@ -5,7 +5,11 @@ * 2.0. */ -import type { CheckPrivilegesDynamically } from '@kbn/security-plugin/server/authorization/check_privileges_dynamically'; +import type { + CheckPrivilegesDynamically, + CheckPrivilegesResponse, + CheckPrivilegesPayload, +} from '@kbn/security-plugin/server'; import type { RequestHandler } from '@kbn/core/server'; import type { VersionedRouter } from '@kbn/core-http-server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; @@ -14,10 +18,6 @@ import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { coreMock } from '@kbn/core/server/mocks'; -import type { CheckPrivilegesPayload } from '@kbn/security-plugin/server'; - -import type { CheckPrivilegesResponse } from '@kbn/security-plugin/server/authorization/types'; - import { API_VERSIONS } from '../../../common/constants'; import type { FleetRequestHandlerContext } from '../..'; diff --git a/x-pack/plugins/fleet/server/services/security/message_signing_service.ts b/x-pack/plugins/fleet/server/services/security/message_signing_service.ts index 77d2a2a272ca..b3d08e9a0b8e 100644 --- a/x-pack/plugins/fleet/server/services/security/message_signing_service.ts +++ b/x-pack/plugins/fleet/server/services/security/message_signing_service.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { backOff } from 'exponential-backoff'; - import { generateKeyPairSync, createSign, randomBytes } from 'crypto'; +import { backOff } from 'exponential-backoff'; + import type { LoggerFactory, Logger } from '@kbn/core/server'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { @@ -202,10 +202,10 @@ export class MessageSigningService implements MessageSigningServiceInterface { soDoc = await this.getCurrentKeyPairObj(); }, { - maxDelay: 60 * 60 * 1000, // 1 hour in milliseconds startingDelay: 1000, // 1 second + maxDelay: 3000, // 3 seconds jitter: 'full', - numOfAttempts: Infinity, + numOfAttempts: 10, retry: (_err: Error, attempt: number) => { // not logging the error since we don't control what's in the error and it might contain sensitive data // ESO already logs specific caught errors before passing the error along @@ -250,7 +250,13 @@ export class MessageSigningService implements MessageSigningServiceInterface { } | undefined > { - const currentKeyPair = await this.getCurrentKeyPairObjWithRetry(); + let currentKeyPair; + try { + currentKeyPair = await this.getCurrentKeyPairObjWithRetry(); + } catch (e) { + throw new MessageSigningError('Cannot read existing Message Signing Key pair'); + } + if (!currentKeyPair) { return; } diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts index 4cf657b7255c..a782fc605ccf 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts @@ -13,6 +13,8 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { UninstallTokenError } from '../../../../common/errors'; + import { SO_SEARCH_LIMIT } from '../../../../common'; import type { @@ -252,7 +254,7 @@ describe('UninstallTokenService', () => { mockCreatePointInTimeFinder(canEncrypt, defaultBuckets); await expect(uninstallTokenService.getTokenMetadata()).rejects.toThrowError( - 'Uninstall Token is missing creation date.' + 'Invalid uninstall token: Saved object is missing creation date.' ); }); @@ -264,7 +266,7 @@ describe('UninstallTokenService', () => { mockCreatePointInTimeFinder(canEncrypt, defaultBuckets); await expect(uninstallTokenService.getTokenMetadata()).rejects.toThrowError( - 'Uninstall Token is missing policy ID.' + 'Invalid uninstall token: Saved object is missing the policy id attribute.' ); }); }); @@ -499,5 +501,114 @@ describe('UninstallTokenService', () => { }); }); }); + + describe('check validity of tokens', () => { + const okaySO = getDefaultSO(canEncrypt); + + const errorWithDecryptionSO2 = { + ...getDefaultSO2(canEncrypt), + error: new Error('error reason'), + }; + const missingTokenSO2 = { + ...getDefaultSO2(canEncrypt), + attributes: { + ...getDefaultSO2(canEncrypt).attributes, + token: undefined, + token_plain: undefined, + }, + }; + + describe('checkTokenValidityForAllPolicies', () => { + it('returns null if all of the tokens are available', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + + await expect( + uninstallTokenService.checkTokenValidityForAllPolicies() + ).resolves.toBeNull(); + }); + + it('returns error if any of the tokens is missing', async () => { + mockCreatePointInTimeFinderAsInternalUser([okaySO, missingTokenSO2]); + + await expect( + uninstallTokenService.checkTokenValidityForAllPolicies() + ).resolves.toStrictEqual({ + error: new UninstallTokenError( + 'Invalid uninstall token: Saved object is missing the token attribute.' + ), + }); + }); + + it('returns error if token decryption gives error', async () => { + mockCreatePointInTimeFinderAsInternalUser([okaySO, errorWithDecryptionSO2]); + + await expect( + uninstallTokenService.checkTokenValidityForAllPolicies() + ).resolves.toStrictEqual({ + error: new UninstallTokenError( + "Error when reading Uninstall Token with id 'test-so-id-two'." + ), + }); + }); + + it('throws error in case of unknown error', async () => { + esoClientMock.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockRejectedValueOnce('some error'); + + await expect( + uninstallTokenService.checkTokenValidityForAllPolicies() + ).rejects.toThrowError('Unknown error happened while checking Uninstall Tokens validity'); + }); + }); + + describe('checkTokenValidityForPolicy', () => { + it('returns empty array if token is available', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + + await expect( + uninstallTokenService.checkTokenValidityForPolicy(okaySO.attributes.policy_id) + ).resolves.toBeNull(); + }); + + it('returns error if token is missing', async () => { + mockCreatePointInTimeFinderAsInternalUser([okaySO, missingTokenSO2]); + + await expect( + uninstallTokenService.checkTokenValidityForPolicy(missingTokenSO2.attributes.policy_id) + ).resolves.toStrictEqual({ + error: new UninstallTokenError( + 'Invalid uninstall token: Saved object is missing the token attribute.' + ), + }); + }); + + it('returns error if token decryption gives error', async () => { + mockCreatePointInTimeFinderAsInternalUser([okaySO, errorWithDecryptionSO2]); + + await expect( + uninstallTokenService.checkTokenValidityForPolicy( + errorWithDecryptionSO2.attributes.policy_id + ) + ).resolves.toStrictEqual({ + error: new UninstallTokenError( + "Error when reading Uninstall Token with id 'test-so-id-two'." + ), + }); + }); + + it('throws error in case of unknown error', async () => { + esoClientMock.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockRejectedValueOnce('some error'); + + await expect( + uninstallTokenService.checkTokenValidityForPolicy( + errorWithDecryptionSO2.attributes.policy_id + ) + ).rejects.toThrowError('Unknown error happened while checking Uninstall Tokens validity'); + }); + }); + }); }); }); diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts index 8309910be6f5..7a2bdedffcdc 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts @@ -55,6 +55,10 @@ interface UninstallTokenSOAggregation { by_policy_id: AggregationsMultiBucketAggregateBase; } +export interface UninstallTokenInvalidError { + error: UninstallTokenError; +} + export interface UninstallTokenServiceInterface { /** * Get uninstall token based on its id. @@ -109,7 +113,7 @@ export interface UninstallTokenServiceInterface { * @param force generate a new token even if one already exists * @returns hashedToken */ - generateTokenForPolicyId(policyId: string, force?: boolean): Promise; + generateTokenForPolicyId(policyId: string, force?: boolean): Promise; /** * Generate uninstall tokens for given policy ids @@ -119,7 +123,7 @@ export interface UninstallTokenServiceInterface { * @param force generate a new token even if one already exists * @returns Record */ - generateTokensForPolicyIds(policyIds: string[], force?: boolean): Promise>; + generateTokensForPolicyIds(policyIds: string[], force?: boolean): Promise; /** * Generate uninstall tokens all policies @@ -128,12 +132,26 @@ export interface UninstallTokenServiceInterface { * @param force generate a new token even if one already exists * @returns Record */ - generateTokensForAllPolicies(force?: boolean): Promise>; + generateTokensForAllPolicies(force?: boolean): Promise; /** * If encryption is available, checks for any plain text uninstall tokens and encrypts them */ encryptTokens(): Promise; + + /** + * Check whether the selected policy has a valid uninstall token. Rejects returning promise if not. + * + * @param policyId policy Id to check + */ + checkTokenValidityForPolicy(policyId: string): Promise; + + /** + * Check whether all policies have a valid uninstall token. Rejects returning promise if not. + * + * @param policyId policy Id to check + */ + checkTokenValidityForAllPolicies(): Promise; } export class UninstallTokenService implements UninstallTokenServiceInterface { @@ -210,7 +228,11 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { tokensFinder.close(); const uninstallTokens: UninstallToken[] = tokenObject.map( - ({ id: _id, attributes, created_at: createdAt }) => { + ({ id: _id, attributes, created_at: createdAt, error }) => { + if (error) { + throw new UninstallTokenError(`Error when reading Uninstall Token with id '${_id}'.`); + } + this.assertPolicyId(attributes); this.assertToken(attributes); this.assertCreatedAt(createdAt); @@ -304,32 +326,30 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { return this.getHashedTokensForPolicyIds(policyIds); } - public async generateTokenForPolicyId(policyId: string, force: boolean = false): Promise { - return (await this.generateTokensForPolicyIds([policyId], force))[policyId]; + public generateTokenForPolicyId(policyId: string, force: boolean = false): Promise { + return this.generateTokensForPolicyIds([policyId], force); } public async generateTokensForPolicyIds( policyIds: string[], force: boolean = false - ): Promise> { + ): Promise { const { agentTamperProtectionEnabled } = appContextService.getExperimentalFeatures(); if (!agentTamperProtectionEnabled || !policyIds.length) { - return {}; + return; } - const existingTokens = force - ? {} - : (await this.getDecryptedTokensForPolicyIds(policyIds)).reduce( - (acc, { policy_id: policyId, token }) => { - acc[policyId] = token; - return acc; - }, - {} as Record - ); + const existingTokens = new Set(); + + if (!force) { + (await this.getTokenObjectsByIncludeFilter(policyIds)).forEach((tokenObject) => { + existingTokens.add(tokenObject._source[UNINSTALL_TOKENS_SAVED_OBJECT_TYPE].policy_id); + }); + } const missingTokenPolicyIds = force ? policyIds - : policyIds.filter((policyId) => !existingTokens[policyId]); + : policyIds.filter((policyId) => !existingTokens.has(policyId)); const newTokensMap = missingTokenPolicyIds.reduce((acc, policyId) => { const token = this.generateToken(); @@ -338,7 +358,6 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { [policyId]: token, }; }, {} as Record); - await this.persistTokens(missingTokenPolicyIds, newTokensMap); if (force) { const config = appContextService.getConfig(); @@ -349,21 +368,9 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { await agentPolicyService.deployPolicies(this.soClient, policyIdsBatch) ); } - - const tokensMap = { - ...existingTokens, - ...newTokensMap, - }; - - return Object.entries(tokensMap).reduce((acc, [policyId, token]) => { - acc[policyId] = this.hashToken(token); - return acc; - }, {} as Record); } - public async generateTokensForAllPolicies( - force: boolean = false - ): Promise> { + public async generateTokensForAllPolicies(force: boolean = false): Promise { const policyIds = await this.getAllPolicyIds(); return this.generateTokensForPolicyIds(policyIds, force); } @@ -486,25 +493,61 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { return this._soClient; } + public async checkTokenValidityForPolicy( + policyId: string + ): Promise { + return await this.checkTokenValidity([policyId]); + } + + public async checkTokenValidityForAllPolicies(): Promise { + const policyIds = await this.getAllPolicyIds(); + return await this.checkTokenValidity(policyIds); + } + + private async checkTokenValidity( + policyIds: string[] + ): Promise { + try { + await this.getDecryptedTokensForPolicyIds(policyIds); + } catch (error) { + if (error instanceof UninstallTokenError) { + // known errors are considered non-fatal + return { error }; + } else { + const errorMessage = 'Unknown error happened while checking Uninstall Tokens validity'; + appContextService.getLogger().error(`${errorMessage}: '${error}'`); + throw new UninstallTokenError(errorMessage); + } + } + + return null; + } + private get isEncryptionAvailable(): boolean { return appContextService.getEncryptedSavedObjectsSetup()?.canEncrypt ?? false; } private assertCreatedAt(createdAt: string | undefined): asserts createdAt is string { if (!createdAt) { - throw new UninstallTokenError('Uninstall Token is missing creation date.'); + throw new UninstallTokenError( + 'Invalid uninstall token: Saved object is missing creation date.' + ); } } private assertToken(attributes: UninstallTokenSOAttributes | undefined) { if (!attributes?.token && !attributes?.token_plain) { - throw new UninstallTokenError('Uninstall Token is missing the token.'); + throw new UninstallTokenError( + 'Invalid uninstall token: Saved object is missing the token attribute.' + ); } } private assertPolicyId(attributes: UninstallTokenSOAttributes | undefined) { if (!attributes?.policy_id) { - throw new UninstallTokenError('Uninstall Token is missing policy ID.'); + throw new UninstallTokenError( + 'Invalid uninstall token: Saved object is missing the policy id attribute.' + ); } } } diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 270cfefb56a8..e0b3bdfea0bd 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -7,11 +7,15 @@ import fs from 'fs/promises'; +import apm from 'elastic-apm-node'; + import { compact } from 'lodash'; import pMap from 'p-map'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; +import { MessageSigningError } from '../../common/errors'; + import { AUTO_UPDATE_PACKAGES } from '../../common/constants'; import type { PreconfigurationError } from '../../common/constants'; import type { DefaultPackagesInstallationError } from '../../common/types'; @@ -49,11 +53,16 @@ import { getPreconfiguredFleetServerHostFromConfig, } from './preconfiguration/fleet_server_host'; import { cleanUpOldFileIndices } from './setup/clean_old_fleet_indices'; +import type { UninstallTokenInvalidError } from './security/uninstall_token_service'; export interface SetupStatus { isInitialized: boolean; nonFatalErrors: Array< - PreconfigurationError | DefaultPackagesInstallationError | UpgradeManagedPackagePoliciesResult + | PreconfigurationError + | DefaultPackagesInstallationError + | UpgradeManagedPackagePoliciesResult + | UninstallTokenInvalidError + | { error: MessageSigningError } >; } @@ -61,7 +70,17 @@ export async function setupFleet( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient ): Promise { - return awaitIfPending(async () => createSetupSideEffects(soClient, esClient)); + const t = apm.startTransaction('fleet-setup', 'fleet'); + + try { + return await awaitIfPending(async () => createSetupSideEffects(soClient, esClient)); + } catch (error) { + apm.captureError(error); + t.setOutcome('failure'); + throw error; + } finally { + t.end(); + } } async function createSetupSideEffects( @@ -113,7 +132,9 @@ async function createSetupSideEffects( const defaultOutput = await outputService.ensureDefaultOutput(soClient, esClient); logger.debug('Setting up Fleet Elasticsearch assets'); + let stepSpan = apm.startSpan('Install Fleet global assets', 'preconfiguration'); await ensureFleetGlobalEsAssets(soClient, esClient); + stepSpan?.end(); // Ensure that required packages are always installed even if they're left out of the config const preconfiguredPackageNames = new Set(packages.map((pkg) => pkg.name)); @@ -136,6 +157,7 @@ async function createSetupSideEffects( logger.debug('Setting up initial Fleet packages'); + stepSpan = apm.startSpan('Install preconfigured packages and policies', 'preconfiguration'); const { nonFatalErrors: preconfiguredPackagesNonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies( soClient, @@ -146,23 +168,36 @@ async function createSetupSideEffects( defaultDownloadSource, DEFAULT_SPACE_ID ); + stepSpan?.end(); + stepSpan = apm.startSpan('Upgrade managed package policies', 'preconfiguration'); const packagePolicyUpgradeErrors = ( await upgradeManagedPackagePolicies(soClient, esClient) ).filter((result) => (result.errors ?? []).length > 0); - - const nonFatalErrors = [...preconfiguredPackagesNonFatalErrors, ...packagePolicyUpgradeErrors]; + stepSpan?.end(); logger.debug('Upgrade Fleet package install versions'); + stepSpan = apm.startSpan('Upgrade package install format version', 'preconfiguration'); await upgradePackageInstallVersion({ soClient, esClient, logger }); + stepSpan?.end(); logger.debug('Generating key pair for message signing'); + stepSpan = apm.startSpan('Configure message signing', 'preconfiguration'); if (!appContextService.getMessageSigningService()?.isEncryptionAvailable) { logger.warn( 'xpack.encryptedSavedObjects.encryptionKey is not configured, private key passphrase is being stored in plain text' ); } - await appContextService.getMessageSigningService()?.generateKeyPair(); + let messageSigningServiceNonFatalError: { error: MessageSigningError } | undefined; + try { + await appContextService.getMessageSigningService()?.generateKeyPair(); + } catch (error) { + if (error instanceof MessageSigningError) { + messageSigningServiceNonFatalError = { error }; + } else { + throw error; + } + } logger.debug('Generating Agent uninstall tokens'); if (!appContextService.getEncryptedSavedObjectsSetup()?.canEncrypt) { @@ -177,15 +212,38 @@ async function createSetupSideEffects( await appContextService.getUninstallTokenService()?.encryptTokens(); } + logger.debug('Checking validity of Uninstall Tokens'); + const uninstallTokenError = await appContextService + .getUninstallTokenService() + ?.checkTokenValidityForAllPolicies(); + stepSpan?.end(); + + stepSpan = apm.startSpan('Upgrade agent policy schema', 'preconfiguration'); + logger.debug('Upgrade Agent policy schema version'); await upgradeAgentPolicySchemaVersion(soClient); + stepSpan?.end(); + stepSpan = apm.startSpan('Set up enrollment keys for preconfigured policies', 'preconfiguration'); logger.debug('Setting up Fleet enrollment keys'); await ensureDefaultEnrollmentAPIKeysExists(soClient, esClient); + stepSpan?.end(); + + const nonFatalErrors = [ + ...preconfiguredPackagesNonFatalErrors, + ...packagePolicyUpgradeErrors, + ...(messageSigningServiceNonFatalError ? [messageSigningServiceNonFatalError] : []), + ...(uninstallTokenError ? [uninstallTokenError] : []), + ]; if (nonFatalErrors.length > 0) { logger.info('Encountered non fatal errors during Fleet setup'); - formatNonFatalErrors(nonFatalErrors).forEach((error) => logger.info(JSON.stringify(error))); + formatNonFatalErrors(nonFatalErrors) + .map((e) => JSON.stringify(e)) + .forEach((error) => { + logger.info(error); + apm.captureError(error); + }); } logger.info('Fleet setup completed'); @@ -222,6 +280,7 @@ export async function ensureFleetGlobalEsAssets( esClient, installation, }).catch((err) => { + apm.captureError(err); logger.error( `Package needs to be manually reinstalled ${installation.name} after installing Fleet global assets: ${err.message}` ); diff --git a/x-pack/plugins/fleet/server/services/setup_utils.ts b/x-pack/plugins/fleet/server/services/setup_utils.ts index 4ac77e8e7d60..a9801e3470b7 100644 --- a/x-pack/plugins/fleet/server/services/setup_utils.ts +++ b/x-pack/plugins/fleet/server/services/setup_utils.ts @@ -12,7 +12,7 @@ let isPending = false; let onResolve = (value?: unknown) => {}; let onReject = (reason: any) => {}; -export async function awaitIfPending(asyncFunction: Function): Promise { +export async function awaitIfPending(asyncFunction: () => Promise): Promise { // pending successful or failed attempt if (isPending) { // don't run concurrent installs diff --git a/x-pack/plugins/fleet/server/types/index.tsx b/x-pack/plugins/fleet/server/types/index.tsx index b9dc7528651e..d56c92eb7aa8 100644 --- a/x-pack/plugins/fleet/server/types/index.tsx +++ b/x-pack/plugins/fleet/server/types/index.tsx @@ -41,6 +41,7 @@ export type { Installation, EpmPackageInstallStatus, InstallationStatus, + InstallFailedAttempt, PackageInfo, ArchivePackage, RegistryVarsEntry, diff --git a/x-pack/plugins/fleet/server/types/models/output.ts b/x-pack/plugins/fleet/server/types/models/output.ts index d77663b65e78..4c391e8383a5 100644 --- a/x-pack/plugins/fleet/server/types/models/output.ts +++ b/x-pack/plugins/fleet/server/types/models/output.ts @@ -130,13 +130,23 @@ const ElasticSearchUpdateSchema = { export const RemoteElasticSearchSchema = { ...ElasticSearchSchema, type: schema.literal(outputType.RemoteElasticsearch), - service_token: schema.string(), + service_token: schema.maybe(schema.string()), + secrets: schema.maybe( + schema.object({ + service_token: schema.maybe(secretRefSchema), + }) + ), }; const RemoteElasticSearchUpdateSchema = { ...ElasticSearchUpdateSchema, type: schema.maybe(schema.literal(outputType.RemoteElasticsearch)), service_token: schema.maybe(schema.string()), + secrets: schema.maybe( + schema.object({ + service_token: schema.maybe(secretRefSchema), + }) + ), }; /** diff --git a/x-pack/plugins/fleet/server/types/so_attributes.ts b/x-pack/plugins/fleet/server/types/so_attributes.ts index 66974744d4ad..df98f0b00a42 100644 --- a/x-pack/plugins/fleet/server/types/so_attributes.ts +++ b/x-pack/plugins/fleet/server/types/so_attributes.ts @@ -154,7 +154,9 @@ interface OutputSoElasticsearchAttributes extends OutputSoBaseAttributes { export interface OutputSoRemoteElasticsearchAttributes extends OutputSoBaseAttributes { type: OutputType['RemoteElasticsearch']; service_token?: string; - secrets?: {}; + secrets?: { + service_token?: { id: string }; + }; } interface OutputSoLogstashAttributes extends OutputSoBaseAttributes { diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 4d3c850b9e75..4503d328e150 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -102,5 +102,6 @@ "@kbn/dashboard-plugin", "@kbn/cloud", "@kbn/config", + "@kbn/core-http-server-mocks", ] } diff --git a/x-pack/plugins/index_management/common/constants/index.ts b/x-pack/plugins/index_management/common/constants/index.ts index a41f3d71bc6b..efe9630a5f23 100644 --- a/x-pack/plugins/index_management/common/constants/index.ts +++ b/x-pack/plugins/index_management/common/constants/index.ts @@ -10,6 +10,10 @@ export { API_BASE_PATH, INTERNAL_API_BASE_PATH } from './api_base_path'; export { INVALID_INDEX_PATTERN_CHARS, INVALID_TEMPLATE_NAME_CHARS } from './invalid_characters'; export * from './index_statuses'; +// Since each index can have a max length or 255 characters and the max length of +// the request is 4096 bytes we can fit a max of 16 indices in a single request. +export const MAX_INDICES_PER_REQUEST = 16; + export { UIM_APP_NAME, UIM_APP_LOAD, diff --git a/x-pack/plugins/index_management/common/lib/template_serialization.ts b/x-pack/plugins/index_management/common/lib/template_serialization.ts index bb871b1556d3..8a38b40258db 100644 --- a/x-pack/plugins/index_management/common/lib/template_serialization.ts +++ b/x-pack/plugins/index_management/common/lib/template_serialization.ts @@ -74,7 +74,7 @@ export function deserializeTemplate( indexPatterns: indexPatterns.sort(), template, ilmPolicy: settings?.index?.lifecycle, - composedOf, + composedOf: composedOf ?? [], dataStream, allowAutoCreate, _meta, diff --git a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx index 9f5629696d55..87002e604227 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx @@ -58,7 +58,6 @@ export const PoliciesTable: FunctionComponent = ({ fill iconType="plusInCircle" {...reactRouterNavigate(history, '/enrich_policies/create')} - data-test-subj="enrichPoliciesPoliciesTableCreateButton" > indexTemplate.index_template.composed_of.includes(name)) + .filter((indexTemplate) => indexTemplate.index_template?.composed_of?.includes(name)) .map((indexTemplate) => indexTemplate.index_template.index_patterns) .flat() .join(','); @@ -39,6 +39,7 @@ async function getDatastreamsForComponentTemplate( if (datastreamNames.length < 0) { return []; } + const { data_streams: dataStreams } = await esClient.indices.getDataStream({ name: datastreamNames, }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/helpers.test.ts b/x-pack/plugins/index_management/server/routes/api/indices/helpers.test.ts new file mode 100644 index 000000000000..fd44742d26e4 --- /dev/null +++ b/x-pack/plugins/index_management/server/routes/api/indices/helpers.test.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IScopedClusterClient } from '@kbn/core/server'; + +import { executeAsyncByChunks } from './helpers'; + +const generateIndices = (count: number) => { + const indices = []; + + for (let i = 0; i < count; i++) { + indices.push(`index-${i}`); + } + + return indices; +}; + +const mockClient = { + asCurrentUser: { + indices: { + delete: jest.fn(), + }, + }, +} as unknown as IScopedClusterClient; + +describe('executeAsyncByChunks', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should make just one request for one index', async () => { + const params = { + index: generateIndices(1), + }; + + await executeAsyncByChunks(params, mockClient, 'delete'); + + expect(mockClient.asCurrentUser.indices.delete).toHaveBeenCalledTimes(1); + }); + + it('should make 2 requests for 32 indices', async () => { + const params = { + index: generateIndices(32), + }; + + await executeAsyncByChunks(params, mockClient, 'delete'); + + expect(mockClient.asCurrentUser.indices.delete).toHaveBeenCalledTimes(2); + }); +}); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/helpers.ts b/x-pack/plugins/index_management/server/routes/api/indices/helpers.ts new file mode 100644 index 000000000000..bb04cbd2c15c --- /dev/null +++ b/x-pack/plugins/index_management/server/routes/api/indices/helpers.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { chunk } from 'lodash'; + +import type { IScopedClusterClient } from '@kbn/core/server'; +import { MAX_INDICES_PER_REQUEST } from '../../../../common/constants'; + +// To avoid having to to match method signatures with the client +// type, we use a generic CallableFn type. +type CallableFn = (args: Record) => Promise; + +export async function executeAsyncByChunks( + // Since we are using a key to access the index method, we need + // to use a generic type. + params: { + index: T[]; + format?: string; + expand_wildcards?: string; + max_num_segments?: number; + }, + dataClient: IScopedClusterClient, + methodName: keyof IScopedClusterClient['asCurrentUser']['indices'] +) { + const { index: indices, ...commonParams } = params; + + // When the number of indices is small, we can execute in a single request + // + // Otherwise we need to split the indices into chunks and execute them in multiple requests because + // if we try to execute an action with too many indices that account for a long string in the request + // ES will throw an error saying that the HTTP line is too large. + if (indices.length <= MAX_INDICES_PER_REQUEST) { + await (dataClient.asCurrentUser.indices[methodName] as CallableFn)({ + ...commonParams, + index: indices, + }); + } else { + const chunks = chunk(indices, MAX_INDICES_PER_REQUEST); + + await Promise.all( + chunks.map((chunkOfIndices) => + (dataClient.asCurrentUser.indices[methodName] as CallableFn)({ + ...commonParams, + index: chunkOfIndices, + }) + ) + ); + } +} diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts index a46a23b8fe47..bfedf6f4cb0c 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -28,7 +29,8 @@ export function registerClearCacheRoute({ router, lib: { handleEsError } }: Rout }; try { - await client.asCurrentUser.indices.clearCache(params); + await executeAsyncByChunks(params, client, 'clearCache'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts index 69d33b7fc799..b83c781f6457 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_close_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -28,7 +29,7 @@ export function registerCloseRoute({ router, lib: { handleEsError } }: RouteDepe }; try { - await client.asCurrentUser.indices.close(params); + await executeAsyncByChunks(params, client, 'close'); return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts index b72a2059beb1..b3931c1d5617 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_delete_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -22,13 +23,14 @@ export function registerDeleteRoute({ router, lib: { handleEsError } }: RouteDep const { indices = [] } = request.body as typeof bodySchema.type; const params = { - expand_wildcards: 'none' as const, format: 'json', + expand_wildcards: 'none' as const, index: indices, }; try { - await client.asCurrentUser.indices.delete(params); + await executeAsyncByChunks(params, client, 'delete'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts index cc07b92e7090..6ba8000306fe 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_flush_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -28,7 +29,8 @@ export function registerFlushRoute({ router, lib: { handleEsError } }: RouteDepe }; try { - await client.asCurrentUser.indices.flush(params); + await executeAsyncByChunks(params, client, 'flush'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts index af07a7371cf6..ffbe50598f19 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -36,7 +37,8 @@ export function registerForcemergeRoute({ router, lib: { handleEsError } }: Rout } try { - await client.asCurrentUser.indices.forcemerge(params); + await executeAsyncByChunks(params, client, 'forcemerge'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts index dde9e72af39d..9d0ae0a44b4e 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_open_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -28,7 +29,8 @@ export function registerOpenRoute({ router, lib: { handleEsError } }: RouteDepen }; try { - await client.asCurrentUser.indices.open(params); + await executeAsyncByChunks(params, client, 'open'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts index 2483cd534b80..c414a73cd73c 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_refresh_route.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '..'; +import { executeAsyncByChunks } from './helpers'; const bodySchema = schema.object({ indices: schema.arrayOf(schema.string()), @@ -28,7 +29,8 @@ export function registerRefreshRoute({ router, lib: { handleEsError } }: RouteDe }; try { - await client.asCurrentUser.indices.refresh(params); + await executeAsyncByChunks(params, client, 'refresh'); + return response.ok(); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts b/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts index 91a04187fc23..d64c6b1013d6 100644 --- a/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/indices/register_reload_route.ts @@ -5,8 +5,10 @@ * 2.0. */ +import { chunk } from 'lodash'; import { schema } from '@kbn/config-schema'; +import { MAX_INDICES_PER_REQUEST } from '../../../../common/constants'; import { RouteDependencies } from '../../../types'; import { fetchIndices } from '../../../lib/fetch_indices'; import { addBasePath } from '..'; @@ -30,7 +32,27 @@ export function registerReloadRoute({ const { indexNames = [] } = (request.body as typeof bodySchema.type) ?? {}; try { - const indices = await fetchIndices({ client, indexDataEnricher, config, indexNames }); + let indices; + + // When the number of indices is small, we can execute in a single request + // + // Otherwise we need to split the indices into chunks and execute them in multiple requests because + // if we try to execute an action with too many indices that account for a long string in the request + // ES will throw an error saying that the HTTP line is too large. + if (indexNames.length <= MAX_INDICES_PER_REQUEST) { + indices = await fetchIndices({ client, indexDataEnricher, config, indexNames }); + } else { + const chunks = chunk(indexNames, MAX_INDICES_PER_REQUEST); + + indices = ( + await Promise.all( + chunks.map((indexNamesChunk) => + fetchIndices({ client, indexDataEnricher, config, indexNames: indexNamesChunk }) + ) + ) + ).flat(); + } + return response.ok({ body: indices }); } catch (error) { return handleEsError({ error, response }); diff --git a/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts b/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts index a8b78bf2efcc..85193973ed91 100644 --- a/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts +++ b/x-pack/plugins/infra/common/dependency_mocks/index_patterns.ts @@ -49,7 +49,6 @@ export const createIndexPatternMock = ({ getComputedFields: () => ({ runtimeFields: runtimeFields ?? {}, scriptFields: {}, - storedFields: [], docvalueFields: [], }), getRuntimeMappings: () => runtimeFields ?? {}, diff --git a/x-pack/plugins/infra/common/http_api/latest.ts b/x-pack/plugins/infra/common/http_api/latest.ts index 98787a2c581a..9b9ba2a0c54f 100644 --- a/x-pack/plugins/infra/common/http_api/latest.ts +++ b/x-pack/plugins/infra/common/http_api/latest.ts @@ -10,3 +10,4 @@ export * from './log_alerts/v1'; export * from './log_analysis/results/v1'; export * from './log_analysis/validation/v1'; export * from './metrics_explorer_views/v1'; +export * from './log_analysis/id_formats/v1/id_formats'; diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/id_formats/v1/id_formats.ts b/x-pack/plugins/infra/common/http_api/log_analysis/id_formats/v1/id_formats.ts new file mode 100644 index 000000000000..c148df6c4c50 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/log_analysis/id_formats/v1/id_formats.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; +import { logEntryRateJobTypeRT, logEntryCategoriesJobTypeRT } from '../../../../log_analysis'; + +export const idFormatRT = rt.union([rt.literal('legacy'), rt.literal('hashed')]); +export type IdFormat = rt.TypeOf; + +const jobTypeRT = rt.union([logEntryRateJobTypeRT, logEntryCategoriesJobTypeRT]); +export type JobType = rt.TypeOf; + +export const idFormatByJobTypeRT = rt.record(jobTypeRT, idFormatRT); +export type IdFormatByJobType = rt.TypeOf; + +export const LOG_ANALYSIS_GET_ID_FORMATS = '/api/infra/log_analysis/id_formats'; + +export const getLogAnalysisIdFormatsRequestPayloadRT = rt.type({ + data: rt.type({ + logViewId: rt.string, + spaceId: rt.string, + }), +}); + +export type GetLogAnalysisIdFormatsRequestPayload = rt.TypeOf< + typeof getLogAnalysisIdFormatsRequestPayloadRT +>; + +export const getLogAnalysisIdFormatsSuccessResponsePayloadRT = rt.type({ + data: rt.record(rt.union([logEntryRateJobTypeRT, logEntryCategoriesJobTypeRT]), idFormatRT), +}); + +export type GetLogAnalysisIdFormatsSuccessResponsePayload = rt.TypeOf< + typeof getLogAnalysisIdFormatsSuccessResponsePayloadRT +>; diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies.ts index 355396206399..38244c6a869b 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies.ts @@ -8,6 +8,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; +import { idFormatByJobTypeRT } from '../../id_formats/v1/id_formats'; import { timeRangeRT, routeTimingMetadataRT } from '../../../shared'; import { logEntryAnomalyRT, @@ -54,6 +55,7 @@ export const getLogEntryAnomaliesRequestPayloadRT = rt.type({ rt.type({ // log view logView: persistedLogViewReferenceRT, + idFormats: idFormatByJobTypeRT, // the time range to fetch the log entry anomalies from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies_datasets.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies_datasets.ts index c07007be0511..5b6031ce2758 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies_datasets.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_anomalies_datasets.ts @@ -14,6 +14,7 @@ import { timeRangeRT, routeTimingMetadataRT, } from '../../../shared'; +import { idFormatByJobTypeRT } from '../../id_formats/v1/id_formats'; export const LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH = '/api/infra/log_analysis/results/log_entry_anomalies_datasets'; @@ -26,6 +27,7 @@ export const getLogEntryAnomaliesDatasetsRequestPayloadRT = rt.type({ data: rt.type({ // log view logView: persistedLogViewReferenceRT, + idFormats: idFormatByJobTypeRT, // the time range to fetch the anomalies datasets from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_categories.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_categories.ts index e84825b8c683..525292fb46ee 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_categories.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_categories.ts @@ -8,6 +8,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; +import { idFormatRT } from '../../id_formats/v1/id_formats'; import { badRequestErrorRT, forbiddenErrorRT, @@ -41,6 +42,7 @@ export const getLogEntryCategoriesRequestPayloadRT = rt.type({ categoryCount: rt.number, // log view logView: persistedLogViewReferenceRT, + idFormat: idFormatRT, // the time range to fetch the categories from timeRange: timeRangeRT, // a list of histograms to create diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_datasets.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_datasets.ts index e051e313d9b8..5b258d05e6cc 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_datasets.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_datasets.ts @@ -8,6 +8,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; +import { idFormatRT } from '../../id_formats/v1/id_formats'; import { badRequestErrorRT, forbiddenErrorRT, @@ -25,6 +26,7 @@ export const getLogEntryCategoryDatasetsRequestPayloadRT = rt.type({ data: rt.type({ // log view logView: persistedLogViewReferenceRT, + idFormat: idFormatRT, // the time range to fetch the category datasets from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_examples.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_examples.ts index fc6ece5d7b7f..c0b7b3c00b55 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_examples.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_category_examples.ts @@ -7,6 +7,7 @@ import { logEntryContextRT, persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; import * as rt from 'io-ts'; +import { idFormatRT } from '../../id_formats/v1/id_formats'; import { badRequestErrorRT, forbiddenErrorRT, @@ -29,6 +30,7 @@ export const getLogEntryCategoryExamplesRequestPayloadRT = rt.type({ exampleCount: rt.number, // log view logView: persistedLogViewReferenceRT, + idFormat: idFormatRT, // the time range to fetch the category examples from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_examples.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_examples.ts index ebc78693f498..4a0779a9128f 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_examples.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/v1/log_entry_examples.ts @@ -7,6 +7,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; +import { idFormatRT } from '../../id_formats/v1/id_formats'; import { logEntryExampleRT } from '../../../../log_analysis'; import { badRequestErrorRT, @@ -31,6 +32,7 @@ export const getLogEntryExamplesRequestPayloadRT = rt.type({ exampleCount: rt.number, // logView logView: persistedLogViewReferenceRT, + idFormat: idFormatRT, // the time range to fetch the log rate examples from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/profiling_api.ts b/x-pack/plugins/infra/common/http_api/profiling_api.ts new file mode 100644 index 000000000000..d6a27155477a --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/profiling_api.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; + +export const InfraProfilingFlamegraphRequestParamsRT = rt.type({ + hostname: rt.string, + from: rt.number, + to: rt.number, +}); + +export const InfraProfilingFunctionsRequestParamsRT = rt.type({ + hostname: rt.string, + from: rt.number, + to: rt.number, + startIndex: rt.number, + endIndex: rt.number, +}); + +export type InfraProfilingFlamegraphRequestParams = rt.TypeOf< + typeof InfraProfilingFlamegraphRequestParamsRT +>; + +export type InfraProfilingFunctionsRequestParams = rt.TypeOf< + typeof InfraProfilingFunctionsRequestParamsRT +>; diff --git a/x-pack/plugins/infra/common/log_analysis/job_parameters.ts b/x-pack/plugins/infra/common/log_analysis/job_parameters.ts index 1a695af80a4d..22fcdea971e2 100644 --- a/x-pack/plugins/infra/common/log_analysis/job_parameters.ts +++ b/x-pack/plugins/infra/common/log_analysis/job_parameters.ts @@ -6,6 +6,8 @@ */ import * as rt from 'io-ts'; +import { v5 } from 'uuid'; +import { IdFormat, JobType } from '../http_api/latest'; export const bucketSpan = 900000; @@ -13,14 +15,32 @@ export const categoriesMessageField = 'message'; export const partitionField = 'event.dataset'; -export const getJobIdPrefix = (spaceId: string, sourceId: string) => - `kibana-logs-ui-${spaceId}-${sourceId}-`; +const ID_NAMESPACE = 'f91b78c0-fdd3-425d-a4ba-4c028fe57e0f'; -export const getJobId = (spaceId: string, logViewId: string, jobType: string) => - `${getJobIdPrefix(spaceId, logViewId)}${jobType}`; +export const getJobIdPrefix = (spaceId: string, sourceId: string, idFormat: IdFormat) => { + if (idFormat === 'legacy') { + return `kibana-logs-ui-${spaceId}-${sourceId}-`; + } else { + // A UUID is 36 characters but based on the ML job names for logs, our limit is 32 characters + // Thus we remove the 4 dashes + const uuid = v5(`${spaceId}-${sourceId}`, ID_NAMESPACE).replaceAll('-', ''); + return `logs-${uuid}-`; + } +}; -export const getDatafeedId = (spaceId: string, logViewId: string, jobType: string) => - `datafeed-${getJobId(spaceId, logViewId, jobType)}`; +export const getJobId = ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + jobType: JobType +) => `${getJobIdPrefix(spaceId, logViewId, idFormat)}${jobType}`; + +export const getDatafeedId = ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + jobType: JobType +) => `datafeed-${getJobId(spaceId, logViewId, idFormat, jobType)}`; export const datasetFilterRT = rt.union([ rt.strict({ diff --git a/x-pack/plugins/infra/common/log_analysis/log_entry_categories_analysis.ts b/x-pack/plugins/infra/common/log_analysis/log_entry_categories_analysis.ts index 1ea952d7a8a1..d22c75dc3cf5 100644 --- a/x-pack/plugins/infra/common/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/plugins/infra/common/log_analysis/log_entry_categories_analysis.ts @@ -8,9 +8,7 @@ import * as rt from 'io-ts'; import { sortRT } from './log_analysis_results'; -export const logEntryCategoriesJobTypeRT = rt.keyof({ - 'log-entry-categories-count': null, -}); +export const logEntryCategoriesJobTypeRT = rt.literal('log-entry-categories-count'); export type LogEntryCategoriesJobType = rt.TypeOf; @@ -18,6 +16,8 @@ export const logEntryCategoriesJobTypes: LogEntryCategoriesJobType[] = [ 'log-entry-categories-count', ]; +export const logEntryCategoriesJobType: LogEntryCategoriesJobType = 'log-entry-categories-count'; + export const logEntryCategoryDatasetRT = rt.type({ name: rt.string, maximumAnomalyScore: rt.number, diff --git a/x-pack/plugins/infra/common/log_analysis/log_entry_rate_analysis.ts b/x-pack/plugins/infra/common/log_analysis/log_entry_rate_analysis.ts index b13cf58764e3..e634f5fc4ce8 100644 --- a/x-pack/plugins/infra/common/log_analysis/log_entry_rate_analysis.ts +++ b/x-pack/plugins/infra/common/log_analysis/log_entry_rate_analysis.ts @@ -7,10 +7,9 @@ import * as rt from 'io-ts'; -export const logEntryRateJobTypeRT = rt.keyof({ - 'log-entry-rate': null, -}); +export const logEntryRateJobTypeRT = rt.literal('log-entry-rate'); export type LogEntryRateJobType = rt.TypeOf; -export const logEntryRateJobTypes: LogEntryRateJobType[] = ['log-entry-rate']; +export const logEntryRateJobType: LogEntryRateJobType = 'log-entry-rate'; +export const logEntryRateJobTypes: LogEntryRateJobType[] = [logEntryRateJobType]; diff --git a/x-pack/plugins/infra/common/plugin_config_types.ts b/x-pack/plugins/infra/common/plugin_config_types.ts index 8f39680959bb..b69afe176cab 100644 --- a/x-pack/plugins/infra/common/plugin_config_types.ts +++ b/x-pack/plugins/infra/common/plugin_config_types.ts @@ -34,6 +34,7 @@ export interface InfraConfig { metricThresholdAlertRuleEnabled: boolean; logThresholdAlertRuleEnabled: boolean; alertsAndRulesDropdownEnabled: boolean; + profilingEnabled: boolean; }; } diff --git a/x-pack/plugins/infra/kibana.jsonc b/x-pack/plugins/infra/kibana.jsonc index b97a273b91f7..a5ffd146b618 100644 --- a/x-pack/plugins/infra/kibana.jsonc +++ b/x-pack/plugins/infra/kibana.jsonc @@ -35,7 +35,7 @@ "usageCollection", "visTypeTimeseries" ], - "optionalPlugins": ["spaces", "ml", "home", "embeddable", "osquery", "cloud"], + "optionalPlugins": ["spaces", "ml", "home", "embeddable", "osquery", "cloud", "profilingDataAccess"], "requiredBundles": [ "unifiedSearch", "observability", diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx index 15b30ab3b79c..5d6f6e6a7ce8 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx @@ -18,7 +18,7 @@ import moment from 'moment'; import { useTheme } from '@emotion/react'; import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { getPaddedAlertTimeRange } from '@kbn/observability-alert-details'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { get, identity } from 'lodash'; import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { useLogView } from '@kbn/logs-shared-plugin/public'; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx index d73aec96da4d..17aadc136b2b 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx @@ -24,6 +24,9 @@ const mockedChartStartContract = chartPluginMock.createStartContract(); jest.mock('@kbn/observability-alert-details', () => ({ AlertAnnotation: () => {}, AlertActiveTimeRangeAnnotation: () => {}, +})); + +jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ getPaddedAlertTimeRange: () => ({ from: '2023-03-28T10:43:13.802Z', to: '2023-03-29T13:14:09.581Z', diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx index 466d032b5c01..6b19b7b340d5 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx @@ -22,11 +22,8 @@ import { import { AlertSummaryField, TopAlert } from '@kbn/observability-plugin/public'; import { ALERT_END, ALERT_START, ALERT_EVALUATION_VALUES } from '@kbn/rule-data-utils'; import { Rule } from '@kbn/alerting-plugin/common'; -import { - AlertAnnotation, - getPaddedAlertTimeRange, - AlertActiveTimeRangeAnnotation, -} from '@kbn/observability-alert-details'; +import { AlertAnnotation, AlertActiveTimeRangeAnnotation } from '@kbn/observability-alert-details'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { metricValueFormatter } from '../../../../common/alerting/metrics/metric_value_formatter'; import { TIME_LABELS } from '../../common/criterion_preview_chart/criterion_preview_chart'; import { Threshold } from '../../common/components/threshold'; diff --git a/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx b/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx index 09e5cf268407..312ed7eb04a9 100644 --- a/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx +++ b/x-pack/plugins/infra/public/common/asset_details_config/asset_details_tabs.tsx @@ -27,6 +27,12 @@ export const commonFlyoutTabs: Tab[] = [ defaultMessage: 'Processes', }), }, + { + id: ContentTabIds.PROFILING, + name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.profiling', { + defaultMessage: 'Universal Profiling', + }), + }, { id: ContentTabIds.LOGS, name: i18n.translate('xpack.infra.nodeDetails.tabs.logs.title', { diff --git a/x-pack/plugins/infra/public/common/visualizations/constants.ts b/x-pack/plugins/infra/public/common/visualizations/constants.ts index 98fafda2e23c..76b2eb7c3d70 100644 --- a/x-pack/plugins/infra/public/common/visualizations/constants.ts +++ b/x-pack/plugins/infra/public/common/visualizations/constants.ts @@ -7,3 +7,6 @@ export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics'; export const HOST_METRICS_DOTTED_LINES_DOC_HREF = 'https://ela.st/docs-infra-why-dotted'; + +export const KPI_CHART_HEIGHT = 150; +export const METRIC_CHART_HEIGHT = 300; diff --git a/x-pack/plugins/infra/public/common/visualizations/index.ts b/x-pack/plugins/infra/public/common/visualizations/index.ts index 35a8dc512061..6bfe3f0df588 100644 --- a/x-pack/plugins/infra/public/common/visualizations/index.ts +++ b/x-pack/plugins/infra/public/common/visualizations/index.ts @@ -5,5 +5,9 @@ * 2.0. */ -export * from './lens/dashboards'; -export * from './lens/formulas'; +export { METRICS_TOOLTIP } from './translations'; +export { + HOST_METRICS_DOC_HREF, + HOST_METRICS_DOTTED_LINES_DOC_HREF, + KPI_CHART_HEIGHT, +} from './constants'; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_kpi_charts.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_kpi_charts.ts deleted file mode 100644 index 9805fd317668..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_kpi_charts.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import { METRICS_TOOLTIP } from '../../translations'; -import type { KPIChartProps } from '../../types'; - -export const hostKPICharts: KPIChartProps[] = [ - { - id: 'cpuUsage', - title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title', { - defaultMessage: 'CPU Usage', - }), - layers: { - data: { - ...hostLensFormulas.cpuUsage, - format: hostLensFormulas.cpuUsage.format - ? { - ...hostLensFormulas.cpuUsage.format, - params: { - decimals: 1, - }, - } - : undefined, - }, - options: { - backgroundColor: '#F1D86F', - showTrendLine: true, - }, - type: 'visualization', - }, - toolTip: METRICS_TOOLTIP.cpuUsage, - }, - { - id: 'normalizedLoad1m', - title: i18n.translate( - 'xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title', - { - defaultMessage: 'Normalized Load', - } - ), - layers: { - data: { - ...hostLensFormulas.normalizedLoad1m, - format: hostLensFormulas.normalizedLoad1m.format - ? { - ...hostLensFormulas.normalizedLoad1m.format, - params: { - decimals: 1, - }, - } - : undefined, - }, - options: { - backgroundColor: '#79AAD9', - showTrendLine: true, - }, - type: 'visualization', - }, - toolTip: METRICS_TOOLTIP.normalizedLoad1m, - }, - { - id: 'memoryUsage', - title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title', { - defaultMessage: 'Memory Usage', - }), - layers: { - data: { - ...hostLensFormulas.memoryUsage, - format: hostLensFormulas.memoryUsage.format - ? { - ...hostLensFormulas.memoryUsage.format, - params: { - decimals: 1, - }, - } - : undefined, - }, - options: { - backgroundColor: '#A987D1', - showTrendLine: true, - }, - type: 'visualization', - }, - toolTip: METRICS_TOOLTIP.memoryUsage, - }, - { - id: 'diskSpaceUsage', - title: i18n.translate('xpack.infra.assetDetailsEmbeddable.overview.kpi.diskUsage.title', { - defaultMessage: 'Disk Usage', - }), - layers: { - data: { - ...hostLensFormulas.diskUsage, - format: hostLensFormulas.diskUsage.format - ? { - ...hostLensFormulas.diskUsage.format, - params: { - decimals: 1, - }, - } - : undefined, - }, - options: { - backgroundColor: '#F5A35C', - showTrendLine: true, - }, - type: 'visualization', - }, - toolTip: METRICS_TOOLTIP.diskSpaceUsage, - }, -]; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_metric_charts.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_metric_charts.ts deleted file mode 100644 index b4dfc1abf5eb..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/host_metric_charts.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { cpuUsage, normalizedLoad1m, cpuUsageBreakdown, loadBreakdown } from '../metric_charts/cpu'; -import { - diskSpaceUsageAvailable, - diskThroughputReadWrite, - diskIOReadWrite, - diskUsageByMountPoint, -} from '../metric_charts/disk'; -import { logRate } from '../metric_charts/log'; -import { memoryUsage, memoryUsageBreakdown } from '../metric_charts/memory'; -import { rxTx } from '../metric_charts/network'; -import type { XYConfig } from '../../types'; - -export const hostMetricFlyoutCharts: XYConfig[] = [ - cpuUsage, - memoryUsage, - normalizedLoad1m, - logRate, - diskSpaceUsageAvailable, - diskUsageByMountPoint, - diskThroughputReadWrite, - diskIOReadWrite, - rxTx, -]; - -export const hostMetricChartsFullPage: XYConfig[] = [ - cpuUsage, - cpuUsageBreakdown, - memoryUsage, - memoryUsageBreakdown, - normalizedLoad1m, - loadBreakdown, - logRate, - diskSpaceUsageAvailable, - diskUsageByMountPoint, - diskThroughputReadWrite, - diskIOReadWrite, - rxTx, -]; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/kubernetes_charts.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/kubernetes_charts.ts deleted file mode 100644 index 83ca15b4deb0..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/host/kubernetes_charts.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { kubernetesLensFormulas } from '../../../formulas'; -import { XY_OVERRIDES } from '../../constants'; -import type { XYConfig } from '../../types'; - -export const kubernetesCharts: XYConfig[] = [ - { - id: 'nodeCpuCapacity', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity', { - defaultMessage: 'Node CPU Capacity', - }), - - layers: [ - { - data: [kubernetesLensFormulas.nodeCpuCapacity, kubernetesLensFormulas.nodeCpuUsed], - type: 'visualization', - options: { - seriesType: 'area', - }, - }, - ], - dataViewOrigin: 'metrics', - overrides: { - settings: XY_OVERRIDES.settings, - }, - }, - { - id: 'nodeMemoryCapacity', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodeMemoryCapacity', { - defaultMessage: 'Node Memory Capacity', - }), - - layers: [ - { - data: [kubernetesLensFormulas.nodeMemoryCapacity, kubernetesLensFormulas.nodeMemoryUsed], - type: 'visualization', - options: { - seriesType: 'area', - }, - }, - ], - dataViewOrigin: 'metrics', - overrides: { - settings: XY_OVERRIDES.settings, - }, - }, - { - id: 'nodeDiskCapacity', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodeDiskCapacity', { - defaultMessage: 'Node Disk Capacity', - }), - - layers: [ - { - data: [kubernetesLensFormulas.nodeDiskCapacity, kubernetesLensFormulas.nodeDiskUsed], - type: 'visualization', - options: { - seriesType: 'area', - }, - }, - ], - dataViewOrigin: 'metrics', - overrides: { - settings: XY_OVERRIDES.settings, - }, - }, - { - id: 'nodePodCapacity', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodePodCapacity', { - defaultMessage: 'Node Pod Capacity', - }), - - layers: [ - { - data: [kubernetesLensFormulas.nodePodCapacity, kubernetesLensFormulas.nodePodUsed], - type: 'visualization', - options: { - seriesType: 'area', - }, - }, - ], - dataViewOrigin: 'metrics', - overrides: { - settings: XY_OVERRIDES.settings, - }, - }, -]; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/index.ts deleted file mode 100644 index aef6787c088f..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { hostMetricFlyoutCharts, hostMetricChartsFullPage } from './host/host_metric_charts'; -import { hostKPICharts } from './host/host_kpi_charts'; -import { kubernetesCharts } from './host/kubernetes_charts'; - -export const assetDetailsDashboards = { - host: { hostMetricFlyoutCharts, hostMetricChartsFullPage, hostKPICharts, keyField: 'host.name' }, - kubernetes: { - kubernetesCharts, - keyField: 'kubernetes.node.name', - dependsOn: ['kubernetes.node'], - }, -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/cpu.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/cpu.ts deleted file mode 100644 index 27925b29da72..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/cpu.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import { REFERENCE_LINE, XY_OVERRIDES } from '../../constants'; -import type { XYConfig } from '../../types'; - -export const cpuUsage: XYConfig = { - id: 'cpuUsage', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.cpuUsage', { - defaultMessage: 'CPU Usage', - }), - - layers: [ - { - data: [hostLensFormulas.cpuUsage], - type: 'visualization', - }, - ], - dataViewOrigin: 'metrics', - overrides: { - axisLeft: XY_OVERRIDES.axisLeft, - }, -}; - -export const cpuUsageBreakdown: XYConfig = { - id: 'cpuUsageBreakdown', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.cpuUsage', { - defaultMessage: 'CPU Usage', - }), - layers: [ - { - data: [ - hostLensFormulas.cpuUsageIowait, - hostLensFormulas.cpuUsageIrq, - hostLensFormulas.cpuUsageNice, - hostLensFormulas.cpuUsageSoftirq, - hostLensFormulas.cpuUsageSteal, - hostLensFormulas.cpuUsageUser, - hostLensFormulas.cpuUsageSystem, - ], - options: { - seriesType: 'area_stacked', - }, - type: 'visualization', - }, - ], - overrides: { - axisLeft: XY_OVERRIDES.axisLeft, - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; - -export const normalizedLoad1m: XYConfig = { - id: 'normalizedLoad1m', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.normalizedLoad1m', { - defaultMessage: 'Normalized Load', - }), - layers: [ - { - data: [hostLensFormulas.normalizedLoad1m], - type: 'visualization', - }, - { - data: [REFERENCE_LINE], - type: 'referenceLines', - }, - ], - dataViewOrigin: 'metrics', -}; - -export const loadBreakdown: XYConfig = { - id: 'loadBreakdown', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.load', { - defaultMessage: 'Load', - }), - layers: [ - { - data: [hostLensFormulas.load1m, hostLensFormulas.load5m, hostLensFormulas.load15m], - options: { - seriesType: 'area', - }, - type: 'visualization', - }, - ], - overrides: { - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/disk.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/disk.ts deleted file mode 100644 index daf5ee2ecaac..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/disk.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import { XY_OVERRIDES } from '../../constants'; -import type { XYConfig } from '../../types'; - -const TOP_VALUES_SIZE = 5; - -export const diskSpaceUsageAvailable: XYConfig = { - id: 'diskSpaceUsageAvailable', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskUsage', { - defaultMessage: 'Disk Usage', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.diskUsage, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskUsage.label.used', { - defaultMessage: 'Used', - }), - }, - { - ...hostLensFormulas.diskSpaceAvailability, - label: i18n.translate( - 'xpack.infra.assetDetails.metricsCharts.diskUsage.label.available', - { - defaultMessage: 'Available', - } - ), - }, - ], - options: { - seriesType: 'area', - }, - type: 'visualization', - }, - ], - overrides: { - axisLeft: XY_OVERRIDES.axisLeft, - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; - -export const diskUsageByMountPoint: XYConfig = { - id: 'DiskUsageByMountPoint', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskUsageByMountingPoint', { - defaultMessage: 'Disk Usage by Mount Point', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.diskUsage, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskUsage.label.used', { - defaultMessage: 'Used', - }), - }, - ], - options: { - seriesType: 'area', - breakdown: { - type: 'top_values', - field: 'system.filesystem.mount_point', - params: { - size: TOP_VALUES_SIZE, - }, - }, - }, - type: 'visualization', - }, - ], - overrides: { - axisLeft: XY_OVERRIDES.axisLeft, - }, - dataViewOrigin: 'metrics', -}; - -export const diskThroughputReadWrite: XYConfig = { - id: 'diskThroughputReadWrite', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskIOPS', { - defaultMessage: 'Disk IOPS', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.diskIORead, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.read', { - defaultMessage: 'Read', - }), - }, - { - ...hostLensFormulas.diskIOWrite, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.write', { - defaultMessage: 'Write', - }), - }, - ], - options: { - seriesType: 'area', - }, - type: 'visualization', - }, - ], - overrides: { - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; - -export const diskIOReadWrite: XYConfig = { - id: 'diskIOReadWrite', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.diskThroughput', { - defaultMessage: 'Disk Throughput', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.diskReadThroughput, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.read', { - defaultMessage: 'Read', - }), - }, - { - ...hostLensFormulas.diskWriteThroughput, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.write', { - defaultMessage: 'Write', - }), - }, - ], - options: { - seriesType: 'area', - }, - type: 'visualization', - }, - ], - overrides: { - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/log.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/log.ts deleted file mode 100644 index 267474c4363f..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/log.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import type { XYConfig } from '../../types'; - -export const logRate: XYConfig = { - id: 'logRate', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.logRate', { - defaultMessage: 'Log Rate', - }), - layers: [ - { - data: [hostLensFormulas.logRate], - type: 'visualization', - }, - ], - dataViewOrigin: 'logs', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/memory.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/memory.ts deleted file mode 100644 index dae8d46832c0..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/memory.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import { XY_OVERRIDES } from '../../constants'; -import type { XYConfig } from '../../types'; - -export const memoryUsage: XYConfig = { - id: 'memoryUsage', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.memoryUsage', { - defaultMessage: 'Memory Usage', - }), - layers: [ - { - data: [hostLensFormulas.memoryUsage], - type: 'visualization', - }, - ], - dataViewOrigin: 'metrics', - overrides: { - axisLeft: XY_OVERRIDES.axisLeft, - }, -}; - -export const memoryUsageBreakdown: XYConfig = { - id: 'memoryUsage', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.memoryUsage', { - defaultMessage: 'Memory Usage', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.memoryCache, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.cache', { - defaultMessage: 'Cache', - }), - }, - { - ...hostLensFormulas.memoryUsed, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.used', { - defaultMessage: 'Used', - }), - }, - { - ...hostLensFormulas.memoryFreeExcludingCache, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.metric.label.free', { - defaultMessage: 'Free', - }), - }, - ], - options: { - seriesType: 'area_stacked', - }, - type: 'visualization', - }, - ], - overrides: { - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/network.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/network.ts deleted file mode 100644 index aae8de6a9617..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/asset_details/metric_charts/network.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { hostLensFormulas } from '../../../formulas'; -import { XY_OVERRIDES } from '../../constants'; -import type { XYConfig } from '../../types'; - -export const rxTx: XYConfig = { - id: 'rxTx', - title: i18n.translate('xpack.infra.assetDetails.metricsCharts.network', { - defaultMessage: 'Network', - }), - layers: [ - { - data: [ - { - ...hostLensFormulas.rx, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.network.label.rx', { - defaultMessage: 'Inbound (RX)', - }), - }, - { - ...hostLensFormulas.tx, - label: i18n.translate('xpack.infra.assetDetails.metricsCharts.network.label.tx', { - defaultMessage: 'Outbound (TX)', - }), - }, - ], - options: { - seriesType: 'area', - }, - type: 'visualization', - }, - ], - overrides: { - settings: XY_OVERRIDES.settings, - }, - dataViewOrigin: 'metrics', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/constants.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/constants.ts deleted file mode 100644 index 5efc100ada73..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/constants.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { StaticValueConfig, XYVisualOptions } from '@kbn/lens-embeddable-utils'; -import type { AllowedSettingsOverrides, AllowedXYOverrides } from '@kbn/lens-plugin/common/types'; - -interface XYOverrides { - axisLeft: AllowedXYOverrides['axisLeft']; - settings: AllowedSettingsOverrides['settings']; -} - -export const REFERENCE_LINE: StaticValueConfig = { - value: '1', - format: { - id: 'percent', - params: { - decimals: 0, - }, - }, - color: '#6092c0', -}; - -export const XY_OVERRIDES: XYOverrides = { - axisLeft: { - domain: { - min: 0, - max: 1, - }, - }, - settings: { - showLegend: true, - legendPosition: 'bottom', - legendSize: 50, - }, -}; - -export const XY_MISSING_VALUE_DOTTED_LINE_CONFIG: XYVisualOptions = { - showDottedLine: true, - missingValues: 'Linear', -}; - -export const KPI_CHART_HEIGHT = 150; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/hosts_metric_charts.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/hosts_metric_charts.ts deleted file mode 100644 index d7b1898c321e..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/hosts_metric_charts.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { XYLayerOptions } from '@kbn/lens-embeddable-utils'; -import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { hostLensFormulas } from '../../formulas'; -import type { XYChartLayerParams } from '../../../types'; -import { REFERENCE_LINE, XY_OVERRIDES } from '../constants'; - -const XY_LAYER_OPTIONS: XYLayerOptions = { - breakdown: { - type: 'top_values', - field: 'host.name', - params: { - size: 20, - }, - }, -}; - -export const hostsMetricCharts: Array< - Pick & { - layers: XYChartLayerParams[]; - } -> = [ - { - id: 'cpuUsage', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.cpuUsage', { - defaultMessage: 'CPU Usage', - }), - layers: [ - { data: [hostLensFormulas.cpuUsage], options: XY_LAYER_OPTIONS, type: 'visualization' }, - ], - overrides: { axisLeft: XY_OVERRIDES.axisLeft }, - }, - { - id: 'normalizedLoad1m', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.normalizedLoad1m', { - defaultMessage: 'Normalized Load', - }), - layers: [ - { - data: [hostLensFormulas.normalizedLoad1m], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - { - data: [REFERENCE_LINE], - type: 'referenceLines', - }, - ], - }, - { - id: 'memoryUsage', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.memoryUsage', { - defaultMessage: 'Memory Usage', - }), - layers: [ - { - data: [hostLensFormulas.memoryUsage], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - overrides: { axisLeft: XY_OVERRIDES.axisLeft }, - }, - { - id: 'memoryFree', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.memoryFree', { - defaultMessage: 'Memory Free', - }), - layers: [ - { - data: [hostLensFormulas.memoryFree], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'diskSpaceUsed', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskUsage', { - defaultMessage: 'Disk Usage', - }), - layers: [ - { - data: [hostLensFormulas.diskUsage], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - overrides: { axisLeft: XY_OVERRIDES.axisLeft }, - }, - { - id: 'diskSpaceAvailable', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskSpaceAvailable', { - defaultMessage: 'Disk Space Available', - }), - layers: [ - { - data: [hostLensFormulas.diskSpaceAvailable], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'diskIORead', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskIORead', { - defaultMessage: 'Disk Read IOPS', - }), - layers: [ - { - data: [hostLensFormulas.diskIORead], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'diskIOWrite', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskIOWrite', { - defaultMessage: 'Disk Write IOPS', - }), - layers: [ - { - data: [hostLensFormulas.diskIOWrite], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'diskReadThroughput', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskReadThroughput', { - defaultMessage: 'Disk Read Throughput', - }), - layers: [ - { - data: [hostLensFormulas.diskReadThroughput], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'diskWriteThroughput', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.diskWriteThroughput', { - defaultMessage: 'Disk Write Throughput', - }), - layers: [ - { - data: [hostLensFormulas.diskWriteThroughput], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'rx', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.rx', { - defaultMessage: 'Network Inbound (RX)', - }), - layers: [ - { - data: [hostLensFormulas.rx], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, - { - id: 'tx', - title: i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.tx', { - defaultMessage: 'Network Outbound (TX)', - }), - layers: [ - { - data: [hostLensFormulas.tx], - options: XY_LAYER_OPTIONS, - type: 'visualization', - }, - ], - }, -]; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/index.ts deleted file mode 100644 index 73d468f206eb..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/hosts_view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { hostsMetricCharts } from './hosts_metric_charts'; - -export const hostsViewDashboards = { - hostsMetricCharts, -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/index.ts deleted file mode 100644 index 446c39158d8c..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { assetDetailsDashboards } from './asset_details'; -export { hostsViewDashboards } from './hosts_view'; -export { AVERAGE_SUBTITLE, METRICS_TOOLTIP } from './translations'; -export { XY_MISSING_VALUE_DOTTED_LINE_CONFIG, KPI_CHART_HEIGHT } from './constants'; -export * from './types'; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/translations.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/translations.ts deleted file mode 100644 index c14674f7d7f4..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/translations.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const METRICS_TOOLTIP = { - hostCount: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.hostCount', { - defaultMessage: 'Number of hosts returned by your search criteria.', - }), - - cpuUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage', { - defaultMessage: - 'Percentage of CPU time spent in states other than Idle and IOWait, normalized by the number of CPU cores. This includes both time spent on user space and kernel space.', - }), - diskSpaceUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage', { - defaultMessage: 'Percentage of disk space used.', - }), - diskLatency: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskLatency', { - defaultMessage: 'Time spent to service disk requests.', - }), - memoryFree: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryFree', { - defaultMessage: 'Total available memory including page cache.', - }), - memoryTotal: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryTotal', { - defaultMessage: 'Total memory capacity.', - }), - memoryUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryUsage', { - defaultMessage: 'Percentage of main memory usage excluding page cache.', - }), - normalizedLoad1m: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m', { - defaultMessage: '1 minute load average normalized by the number of CPU cores. ', - }), - rx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.rx', { - defaultMessage: - 'Number of bytes which have been received per second on the public interfaces of the hosts.', - }), - tx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.tx', { - defaultMessage: - 'Number of bytes which have been sent per second on the public interfaces of the hosts.', - }), -}; - -export const AVERAGE_SUBTITLE = i18n.translate( - 'xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average', - { - defaultMessage: 'Average', - } -); diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/types.ts b/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/types.ts deleted file mode 100644 index 90899c11573e..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/dashboards/types.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import type { DataViewOrigin } from '../../../../components/asset_details/types'; -import type { MetricChartLayerParams, XYChartLayerParams } from '../../types'; - -type BaseProps = Pick; - -export interface AssetXYChartProps extends BaseProps { - layers: XYChartLayerParams[]; -} - -export interface XYConfig extends AssetXYChartProps { - dataViewOrigin: DataViewOrigin; -} - -export interface KPIChartProps extends BaseProps { - layers: MetricChartLayerParams; - toolTip: string; -} diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/index.ts deleted file mode 100644 index 25b21adb7195..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { cpuUsage } from './cpu_usage'; -import { cpuUsageIowait } from './cpu_usage_iowait'; -import { cpuUsageIrq } from './cpu_usage_irq'; -import { cpuUsageNice } from './cpu_usage_nice'; -import { cpuUsageSoftirq } from './cpu_usage_softirq'; -import { cpuUsageSteal } from './cpu_usage_steal'; -import { cpuUsageUser } from './cpu_usage_user'; -import { cpuUsageSystem } from './cpu_usage_system'; -import { diskIORead } from './disk_read_iops'; -import { diskIOWrite } from './disk_write_iops'; -import { diskReadThroughput } from './disk_read_throughput'; -import { diskWriteThroughput } from './disk_write_throughput'; -import { diskSpaceAvailability } from './disk_space_availability'; -import { diskSpaceAvailable } from './disk_space_available'; -import { diskUsage } from './disk_usage'; -import { hostCount } from './host_count'; -import { logRate } from './log_rate'; -import { normalizedLoad1m } from './normalized_load_1m'; -import { load1m } from './load_1m'; -import { load5m } from './load_5m'; -import { load15m } from './load_15m'; -import { memoryUsage } from './memory_usage'; -import { memoryFree } from './memory_free'; -import { memoryUsed } from './memory_used'; -import { memoryFreeExcludingCache } from './memory_free_excluding_cache'; -import { memoryCache } from './memory_cache'; -import { rx } from './rx'; -import { tx } from './tx'; - -export const hostLensFormulas = { - cpuUsage, - cpuUsageIowait, - cpuUsageIrq, - cpuUsageNice, - cpuUsageSoftirq, - cpuUsageSteal, - cpuUsageUser, - cpuUsageSystem, - diskIORead, - diskIOWrite, - diskReadThroughput, - diskWriteThroughput, - diskSpaceAvailability, - diskSpaceAvailable, - diskUsage, - hostCount, - logRate, - normalizedLoad1m, - load1m, - load5m, - load15m, - memoryUsage, - memoryFree, - memoryUsed, - memoryFreeExcludingCache, - memoryCache, - rx, - tx, -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/rx.ts b/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/rx.ts deleted file mode 100644 index 87536f1a573e..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/rx.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; - -export const rx: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.rx', { - defaultMessage: 'Network Inbound (RX)', - }), - value: - "average(host.network.ingress.bytes) * 8 / (max(metricset.period, kql='host.network.ingress.bytes: *') / 1000)", - format: { - id: 'bits', - params: { - decimals: 1, - }, - }, - timeScale: 's', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/tx.ts b/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/tx.ts deleted file mode 100644 index 2aefe2c4cd11..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/tx.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; - -export const tx: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.tx', { - defaultMessage: 'Network Outbound (TX)', - }), - value: - "average(host.network.egress.bytes) * 8 / (max(metricset.period, kql='host.network.egress.bytes: *') / 1000)", - format: { - id: 'bits', - params: { - decimals: 1, - }, - }, - timeScale: 's', -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/formulas/index.ts deleted file mode 100644 index fbdb959e0e94..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { hostLensFormulas } from './host'; -export { kubernetesLensFormulas } from './kubernetes'; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/index.ts b/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/index.ts deleted file mode 100644 index f7593588f254..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { nodeCpuCapacity } from './node_cpu_capacity'; -import { nodeCpuUsed } from './node_cpu_used'; -import { nodeDiskCapacity } from './node_disk_capacity'; -import { nodeDiskUsed } from './node_disk_used'; -import { nodeMemoryCapacity } from './node_memory_capacity'; -import { nodeMemoryUsed } from './node_memory_used'; -import { nodePodCapacity } from './node_pod_capacity'; -import { nodePodUsed } from './node_pod_used'; - -export const kubernetesLensFormulas = { - nodeCpuCapacity, - nodeCpuUsed, - nodeDiskCapacity, - nodeDiskUsed, - nodeMemoryCapacity, - nodeMemoryUsed, - nodePodCapacity, - nodePodUsed, -}; diff --git a/x-pack/plugins/infra/public/common/visualizations/translations.ts b/x-pack/plugins/infra/public/common/visualizations/translations.ts new file mode 100644 index 000000000000..c29f4e49d9eb --- /dev/null +++ b/x-pack/plugins/infra/public/common/visualizations/translations.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const METRICS_TOOLTIP = { + hostCount: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.hostCount', { + defaultMessage: 'Number of hosts returned by your search criteria.', + }), + + cpuUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.cpuUsage', { + defaultMessage: + 'Percentage of CPU time spent in states other than Idle and IOWait, normalized by the number of CPU cores. This includes both time spent on user space and kernel space.', + }), + diskUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskSpaceUsage', { + defaultMessage: 'Percentage of disk space used.', + }), + diskLatency: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.diskLatency', { + defaultMessage: 'Time spent to service disk requests.', + }), + memoryFree: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryFree', { + defaultMessage: 'Total available memory including page cache.', + }), + memoryTotal: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryTotal', { + defaultMessage: 'Total memory capacity.', + }), + memoryUsage: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.memoryUsage', { + defaultMessage: 'Percentage of main memory usage excluding page cache.', + }), + normalizedLoad1m: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.normalizedLoad1m', { + defaultMessage: '1 minute load average normalized by the number of CPU cores. ', + }), + rx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.rx', { + defaultMessage: + 'Number of bytes which have been received per second on the public interfaces of the hosts.', + }), + tx: i18n.translate('xpack.infra.hostsViewPage.metrics.tooltip.tx', { + defaultMessage: + 'Number of bytes which have been sent per second on the public interfaces of the hosts.', + }), +}; diff --git a/x-pack/plugins/infra/public/common/visualizations/types.ts b/x-pack/plugins/infra/public/common/visualizations/types.ts deleted file mode 100644 index 301908cec952..000000000000 --- a/x-pack/plugins/infra/public/common/visualizations/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { - MetricLayerConfig, - XYLayerConfig, - XYReferenceLinesLayerConfig, -} from '@kbn/lens-embeddable-utils'; - -export type XYChartLayerParams = - | (XYLayerConfig & { type: 'visualization' }) - | (XYReferenceLinesLayerConfig & { type: 'referenceLines' }); - -export type MetricChartLayerParams = MetricLayerConfig & { type: 'visualization' }; diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx index e779808347ec..e55a70978a74 100644 --- a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx @@ -190,6 +190,7 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => { metricThresholdAlertRuleEnabled: true, logThresholdAlertRuleEnabled: true, alertsAndRulesDropdownEnabled: true, + profilingEnabled: false, }, }; diff --git a/x-pack/plugins/infra/public/components/asset_details/constants.ts b/x-pack/plugins/infra/public/components/asset_details/constants.ts index 3375c76bcfd3..4e3ed09e1d46 100644 --- a/x-pack/plugins/infra/public/components/asset_details/constants.ts +++ b/x-pack/plugins/infra/public/components/asset_details/constants.ts @@ -10,7 +10,6 @@ import { INTEGRATION_NAME } from './types'; export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout'; export const ASSET_DETAILS_PAGE_COMPONENT_NAME = 'infraAssetDetailsPage'; -export const METRIC_CHART_HEIGHT = 300; export const APM_HOST_FILTER_FIELD = 'host.hostname'; export const ASSET_DETAILS_URL_STATE_KEY = 'assetDetails'; diff --git a/x-pack/plugins/infra/public/components/asset_details/content/content.tsx b/x-pack/plugins/infra/public/components/asset_details/content/content.tsx index 9ffd94fcd9e7..49ad1cb87398 100644 --- a/x-pack/plugins/infra/public/components/asset_details/content/content.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/content/content.tsx @@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { DatePicker } from '../date_picker/date_picker'; import { useTabSwitcherContext } from '../hooks/use_tab_switcher'; -import { Anomalies, Metadata, Processes, Osquery, Logs, Overview } from '../tabs'; +import { Anomalies, Metadata, Processes, Osquery, Logs, Overview, Profiling } from '../tabs'; import { ContentTabIds } from '../types'; export const Content = () => { @@ -22,6 +22,7 @@ export const Content = () => { ContentTabIds.LOGS, ContentTabIds.METADATA, ContentTabIds.PROCESSES, + ContentTabIds.PROFILING, ContentTabIds.ANOMALIES, ]} /> @@ -45,6 +46,9 @@ export const Content = () => { + + + ); diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts index 4b5ec03b3300..42abaf1c5bc9 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts @@ -49,6 +49,7 @@ const TabIdRT = rt.union([ rt.literal(ContentTabIds.OVERVIEW), rt.literal(ContentTabIds.METADATA), rt.literal(ContentTabIds.PROCESSES), + rt.literal(ContentTabIds.PROFILING), rt.literal(ContentTabIds.LOGS), rt.literal(ContentTabIds.ANOMALIES), rt.literal(ContentTabIds.OSQUERY), diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx index a7e0b311d334..3fae1eca66a4 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx @@ -113,8 +113,9 @@ const useFeatureFlagTabs = () => { const featureFlagControlledTabs: Partial> = useMemo( () => ({ [ContentTabIds.OSQUERY]: featureFlags.osqueryEnabled, + [ContentTabIds.PROFILING]: featureFlags.profilingEnabled, }), - [featureFlags.osqueryEnabled] + [featureFlags.osqueryEnabled, featureFlags.profilingEnabled] ); const isTabEnabled = useCallback( diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_flamegraph_data.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_flamegraph_data.ts new file mode 100644 index 000000000000..872e1ee9ef0d --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_flamegraph_data.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useMemo } from 'react'; +import type { BaseFlameGraph } from '@kbn/profiling-utils'; +import { type InfraProfilingFlamegraphRequestParams } from '../../../../common/http_api/profiling_api'; +import { useHTTPRequest } from '../../../hooks/use_http_request'; +import { useRequestObservable } from './use_request_observable'; + +interface Props { + params: InfraProfilingFlamegraphRequestParams; + isActive: boolean; +} + +export function useProfilingFlamegraphData({ params, isActive }: Props) { + const { request$ } = useRequestObservable(); + const fetchOptions = useMemo(() => ({ query: params }), [params]); + const { loading, error, response, makeRequest } = useHTTPRequest( + `/api/infra/profiling/flamegraph`, + 'GET', + undefined, + undefined, + undefined, + undefined, + true, + fetchOptions + ); + + useEffect(() => { + if (!isActive) { + return; + } + + request$.next(makeRequest); + }, [isActive, makeRequest, request$]); + + return { + loading, + error, + response, + }; +} diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_functions_data.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_functions_data.ts new file mode 100644 index 000000000000..20d780528c30 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_profiling_functions_data.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useMemo } from 'react'; +import type { TopNFunctions } from '@kbn/profiling-utils'; +import { type InfraProfilingFunctionsRequestParams } from '../../../../common/http_api/profiling_api'; +import { useHTTPRequest } from '../../../hooks/use_http_request'; +import { useRequestObservable } from './use_request_observable'; + +interface Props { + params: InfraProfilingFunctionsRequestParams; + isActive: boolean; +} + +export function useProfilingFunctionsData({ params, isActive }: Props) { + const { request$ } = useRequestObservable(); + const fetchOptions = useMemo(() => ({ query: params }), [params]); + const { loading, error, response, makeRequest } = useHTTPRequest( + '/api/infra/profiling/functions', + 'GET', + undefined, + undefined, + undefined, + undefined, + true, + fetchOptions + ); + + useEffect(() => { + if (!isActive) { + return; + } + + request$.next(makeRequest); + }, [isActive, makeRequest, request$]); + + return { + loading, + error, + response, + }; +} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/index.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/index.ts index 4a3cde85a3ca..779531d15910 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/index.ts +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/index.ts @@ -8,6 +8,7 @@ export { Anomalies } from './anomalies/anomalies'; export { Metadata } from './metadata/metadata'; export { Processes } from './processes/processes'; +export { Profiling } from './profiling/profiling'; export { Osquery } from './osquery/osquery'; export { Logs } from './logs/logs'; export { Overview } from './overview/overview'; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx index f586aeaab763..4047d365b8f2 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx @@ -8,21 +8,20 @@ import React, { useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import { TimeRange } from '@kbn/es-query'; +import { ChartModel } from '@kbn/lens-embeddable-utils'; +import { METRICS_TOOLTIP } from '../../../../../common/visualizations'; import { LensChart, TooltipContent } from '../../../../lens'; -import { AVERAGE_SUBTITLE, type KPIChartProps } from '../../../../../common/visualizations'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; import { useLoadingStateContext } from '../../../hooks/use_loading_state'; export const Kpi = ({ id, - title, - layers, - toolTip, height, - dataView, assetName, dateRange, -}: KPIChartProps & { + dataView, + ...chartProps +}: ChartModel & { height: number; dataView?: DataView; assetName: string; @@ -39,20 +38,23 @@ export const Kpi = ({ ]; }, [dataView, assetName]); - const tooltipContent = useMemo(() => , [toolTip]); + const tooltipContent = useMemo( + () => + id in METRICS_TOOLTIP ? ( + + ) : undefined, + [id] + ); return ( { + const model = findInventoryModel('host'); + const { euiTheme } = useEuiTheme(); + + const { value: dashboards } = useAsync(() => { + return model.metrics.getDashboards(); + }); + + const charts = useMemo( + () => + dashboards?.kpi.get({ + metricsDataView: dataView, + options: { + backgroundColor: euiTheme.colors.lightestShade, + }, + }).charts ?? [], + [dataView, euiTheme.colors.lightestShade, dashboards?.kpi] + ); return ( - {assetDetailsDashboards.host.hostKPICharts.map((chartProps, index) => ( + {charts.map((chartProps, index) => ( diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx index 72d7f27c7dc4..d1e3bc1bdee3 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx @@ -5,47 +5,37 @@ * 2.0. */ import React, { useCallback, useMemo } from 'react'; -import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; -import type { DataView } from '@kbn/data-views-plugin/public'; +import type { ChartModel } from '@kbn/lens-embeddable-utils'; import type { TimeRange } from '@kbn/es-query'; +import { METRIC_CHART_HEIGHT } from '../../../../../common/visualizations/constants'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { type BrushEndArgs, LensChart, type OnFilterEvent } from '../../../../lens'; -import { METRIC_CHART_HEIGHT } from '../../../constants'; +import { type BrushEndArgs, LensChart, type OnFilterEvent, LensChartProps } from '../../../../lens'; import { useDatePickerContext } from '../../../hooks/use_date_picker'; import { extractRangeFromChartFilterEvent } from './chart_utils'; -import type { XYConfig } from '../../../../../common/visualizations'; import { useLoadingStateContext } from '../../../hooks/use_loading_state'; -export interface ChartProps extends XYConfig { - visualOptions?: XYVisualOptions; - metricsDataView?: DataView; - logsDataView?: DataView; - filterFieldName: string; - dateRange: TimeRange; - assetName: string; - ['data-test-subj']: string; -} +export type ChartProps = ChartModel & + Pick & { + filterFieldName: string; + dateRange: TimeRange; + assetName: string; + dataViewOrigin?: 'metrics' | 'logs'; + ['data-test-subj']: string; + }; export const Chart = ({ id, - title, - layers, - metricsDataView, - logsDataView, filterFieldName, - visualOptions, dataViewOrigin, overrides, dateRange, assetName, + dataView, ...props }: ChartProps) => { const { setDateRange } = useDatePickerContext(); const { searchSessionId } = useLoadingStateContext(); - - const dataView = useMemo(() => { - return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; - }, [dataViewOrigin, logsDataView, metricsDataView]); + const { ['data-test-subj']: dataTestSubj, ...chartProps } = { ...props }; const filters = useMemo(() => { return [ @@ -85,18 +75,15 @@ export const Chart = ({ return ( diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx index 1050ff72a246..d2697112cd0d 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx @@ -4,61 +4,31 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useMemo } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; +import React from 'react'; import { EuiFlexItem, EuiFlexGrid } from '@elastic/eui'; import type { TimeRange } from '@kbn/es-query'; -import { - type XYConfig, - XY_MISSING_VALUE_DOTTED_LINE_CONFIG, -} from '../../../../../common/visualizations'; -import { useMetadataStateContext } from '../../../hooks/use_metadata_state'; +import type { ChartModel } from '@kbn/lens-embeddable-utils'; import { Chart } from './chart'; interface Props { assetName: string; dateRange: TimeRange; - metricsDataView?: DataView; - logsDataView?: DataView; filterFieldName: string; - charts: Array; + charts: ChartModel[]; ['data-test-subj']: string; } -export const MetricsGrid = ({ - assetName, - metricsDataView, - logsDataView, - dateRange, - filterFieldName, - charts, - ...props -}: Props) => { - const { metadata } = useMetadataStateContext(); - - const chartsToRender = useMemo( - () => - charts.filter( - (c) => - !c.dependsOn || - c.dependsOn.every((d) => (metadata?.features ?? []).some((f) => d === f.name)) - ), - [charts, metadata?.features] - ); - +export const MetricsGrid = ({ assetName, dateRange, filterFieldName, charts, ...props }: Props) => { return ( - {chartsToRender.map((chartProp, index) => ( + {charts.map((chartProp, index) => ( ))} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx index f6baa4038c23..3750b5bf422a 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx @@ -10,7 +10,8 @@ import { EuiFlexItem } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { TimeRange } from '@kbn/es-query'; import { EuiFlexGroup } from '@elastic/eui'; -import { assetDetailsDashboards } from '../../../../../common/visualizations'; +import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; +import useAsync from 'react-use/lib/useAsync'; import { MetricsSectionTitle, KubernetesMetricsSectionTitle, @@ -25,31 +26,45 @@ interface Props { logsDataView?: DataView; } -const { host, kubernetes } = assetDetailsDashboards; - export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateRange }: Props) => { + const model = findInventoryModel('host'); + + const { value } = useAsync(() => { + return model.metrics.getDashboards(); + }); + + const dashboards = useMemo( + () => ({ + hosts: value?.assetDetails.get({ + metricsDataView, + logsDataView, + }), + kubernetes: value?.assetDetailsKubernetesNode.get({ + metricsDataView, + }), + }), + + [logsDataView, metricsDataView, value?.assetDetails, value?.assetDetailsKubernetesNode] + ); + return (
    -
    +
    @@ -61,19 +76,33 @@ export const MetricsSectionCompact = ({ metricsDataView, logsDataView, dateRange, -}: Props) => ( -
    - -
    -); +}: Props) => { + const model = findInventoryModel('host'); + const { value } = useAsync(() => { + return model.metrics.getDashboards(); + }); + + const charts = useMemo( + () => + value?.assetDetailsFlyout.get({ + metricsDataView, + logsDataView, + }).charts ?? [], + [metricsDataView, logsDataView, value?.assetDetailsFlyout] + ); + + return ( +
    + +
    + ); +}; const Section = ({ title, diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/error_prompt.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/error_prompt.tsx new file mode 100644 index 000000000000..ea18987869b1 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/error_prompt.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +export function ErrorPrompt() { + return ( + + {i18n.translate('xpack.infra.profiling.loadErrorTitle', { + defaultMessage: 'Unable to load the Profiling data', + })} +

    + } + body={ +

    + {i18n.translate('xpack.infra.profiling.loadErrorBody', { + defaultMessage: + 'There was an error while trying to load profiling data. Try refreshing the page', + })} +

    + } + /> + ); +} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/flamegraph.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/flamegraph.tsx new file mode 100644 index 000000000000..a0fbeb25ca3d --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/flamegraph.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { EmbeddableFlamegraph } from '@kbn/observability-shared-plugin/public'; +import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; +import { useDatePickerContext } from '../../hooks/use_date_picker'; +import { useProfilingFlamegraphData } from '../../hooks/use_profiling_flamegraph_data'; +import { useTabSwitcherContext } from '../../hooks/use_tab_switcher'; +import { ContentTabIds } from '../../types'; +import { ErrorPrompt } from './error_prompt'; +import { ProfilingLinks } from './profiling_links'; + +export function Flamegraph() { + const { asset } = useAssetDetailsRenderPropsContext(); + const { activeTabId } = useTabSwitcherContext(); + const { getDateRangeInTimestamp } = useDatePickerContext(); + const { from, to } = getDateRangeInTimestamp(); + + const params = useMemo( + () => ({ + hostname: asset.name, + from, + to, + }), + [asset.name, from, to] + ); + const { error, loading, response } = useProfilingFlamegraphData({ + isActive: activeTabId === ContentTabIds.PROFILING, + params, + }); + + if (error !== null) { + return ; + } + + return ( + <> + + + + + ); +} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/functions.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/functions.tsx new file mode 100644 index 000000000000..b6089df1bc67 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/functions.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EmbeddableFunctions } from '@kbn/observability-shared-plugin/public'; +import { EuiSpacer } from '@elastic/eui'; +import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; +import { useDatePickerContext } from '../../hooks/use_date_picker'; +import { useProfilingFunctionsData } from '../../hooks/use_profiling_functions_data'; +import { useTabSwitcherContext } from '../../hooks/use_tab_switcher'; +import { ContentTabIds } from '../../types'; +import { ErrorPrompt } from './error_prompt'; +import { ProfilingLinks } from './profiling_links'; + +export function Functions() { + const { asset } = useAssetDetailsRenderPropsContext(); + const { activeTabId } = useTabSwitcherContext(); + const { getDateRangeInTimestamp } = useDatePickerContext(); + const { from, to } = getDateRangeInTimestamp(); + + const params = useMemo( + () => ({ + hostname: asset.name, + from, + to, + startIndex: 0, + endIndex: 10, + }), + [asset.name, from, to] + ); + + const { error, loading, response } = useProfilingFunctionsData({ + isActive: activeTabId === ContentTabIds.PROFILING, + params, + }); + + if (error !== null) { + return ; + } + + return ( + <> + + + + + ); +} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling.tsx new file mode 100644 index 000000000000..b89ef9fa42cd --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; + +import { EuiSpacer, EuiTabbedContent, type EuiTabbedContentProps } from '@elastic/eui'; +import React from 'react'; +import { Flamegraph } from './flamegraph'; +import { Functions } from './functions'; + +export function Profiling() { + const tabs: EuiTabbedContentProps['tabs'] = [ + { + id: 'flamegraph', + name: i18n.translate('xpack.infra.profiling.flamegraphTabName', { + defaultMessage: 'Flamegraph', + }), + content: ( + <> + + + + ), + }, + { + id: 'functions', + name: i18n.translate('xpack.infra.tabs.profiling.functionsTabName', { + defaultMessage: 'Top 10 Functions', + }), + content: ( + <> + + + + ), + }, + ]; + + return ( + <> + + + ); +} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling_links.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling_links.tsx new file mode 100644 index 000000000000..451a4c493eaf --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/profiling/profiling_links.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { HOST_FIELD } from '../../../../../common/constants'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; + +const PROFILING_FEEDBACK_URL = 'https://ela.st/profiling-feedback'; + +export type ProfilingPath = 'flamegraphs' | 'functions'; + +interface Props { + hostname: string; + profilingPath: ProfilingPath; +} + +export function ProfilingLinks({ hostname, profilingPath }: Props) { + const { services } = useKibanaContextForPlugin(); + const queryParams = new URLSearchParams({ + kuery: `${HOST_FIELD}:"${hostname}"`, + }); + const profilingLinkURL = services.http.basePath.prepend( + `/app/profiling/${profilingPath}?${queryParams}` + ); + const profilingLinkLabel = + profilingPath === 'flamegraphs' + ? i18n.translate('xpack.infra.flamegraph.profilingAppFlamegraphLink', { + defaultMessage: 'Go to Universal Profiling Flamegraph', + }) + : i18n.translate('xpack.infra.flamegraph.profilingAppFunctionsLink', { + defaultMessage: 'Go to Universal Profiling Functions', + }); + + return ( + + + + {profilingLinkLabel} + + + + + {i18n.translate('xpack.infra.flamegraph.profilingFeedbackLink', { + defaultMessage: 'Give feedback about profiling', + })} + + + + ); +} diff --git a/x-pack/plugins/infra/public/components/asset_details/types.ts b/x-pack/plugins/infra/public/components/asset_details/types.ts index 56f62a5ebc08..dd3ae9af9d62 100644 --- a/x-pack/plugins/infra/public/components/asset_details/types.ts +++ b/x-pack/plugins/infra/public/components/asset_details/types.ts @@ -21,6 +21,7 @@ export enum ContentTabIds { OVERVIEW = 'overview', METADATA = 'metadata', PROCESSES = 'processes', + PROFILING = 'profiling', ANOMALIES = 'anomalies', OSQUERY = 'osquery', LOGS = 'logs', diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/setup_flyout/module_list.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/setup_flyout/module_list.tsx index 0ccd208cf24b..0eec13f778e4 100644 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/setup_flyout/module_list.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/setup_flyout/module_list.tsx @@ -7,6 +7,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useCallback } from 'react'; +import { logEntryCategoriesJobType, logEntryRateJobType } from '../../../../../common/log_analysis'; import { useLogAnalysisCapabilitiesContext } from '../../../../containers/logs/log_analysis'; import { logEntryCategoriesModule, @@ -40,7 +41,7 @@ export const LogAnalysisModuleList: React.FC<{ +

    diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts index dd4fc9144976..b27938f795ee 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_cleanup.ts @@ -8,20 +8,22 @@ import * as rt from 'io-ts'; import type { HttpHandler } from '@kbn/core/public'; +import { IdFormat, JobType } from '../../../../../common/http_api/latest'; import { getDatafeedId, getJobId } from '../../../../../common/log_analysis'; import { decodeOrThrow } from '../../../../../common/runtime_types'; -interface DeleteJobsRequestArgs { +interface DeleteJobsRequestArgs { spaceId: string; logViewId: string; - jobTypes: JobType[]; + idFormat: IdFormat; + jobTypes: T[]; } -export const callDeleteJobs = async ( - requestArgs: DeleteJobsRequestArgs, +export const callDeleteJobs = async ( + requestArgs: DeleteJobsRequestArgs, fetch: HttpHandler ) => { - const { spaceId, logViewId, jobTypes } = requestArgs; + const { spaceId, logViewId, idFormat, jobTypes } = requestArgs; // NOTE: Deleting the jobs via this API will delete the datafeeds at the same time const deleteJobsResponse = await fetch('/internal/ml/jobs/delete_jobs', { @@ -29,7 +31,7 @@ export const callDeleteJobs = async ( version: '1', body: JSON.stringify( deleteJobsRequestPayloadRT.encode({ - jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, jobType)), + jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, idFormat, jobType)), }) ), }); @@ -45,17 +47,18 @@ export const callGetJobDeletionTasks = async (fetch: HttpHandler) => { return decodeOrThrow(getJobDeletionTasksResponsePayloadRT)(jobDeletionTasksResponse); }; -interface StopDatafeedsRequestArgs { +interface StopDatafeedsRequestArgs { spaceId: string; logViewId: string; - jobTypes: JobType[]; + idFormat: IdFormat; + jobTypes: T[]; } -export const callStopDatafeeds = async ( - requestArgs: StopDatafeedsRequestArgs, +export const callStopDatafeeds = async ( + requestArgs: StopDatafeedsRequestArgs, fetch: HttpHandler ) => { - const { spaceId, logViewId, jobTypes } = requestArgs; + const { spaceId, logViewId, idFormat, jobTypes } = requestArgs; // Stop datafeed due to https://github.com/elastic/kibana/issues/44652 const stopDatafeedResponse = await fetch('/internal/ml/jobs/stop_datafeeds', { @@ -63,7 +66,9 @@ export const callStopDatafeeds = async ( version: '1', body: JSON.stringify( stopDatafeedsRequestPayloadRT.encode({ - datafeedIds: jobTypes.map((jobType) => getDatafeedId(spaceId, logViewId, jobType)), + datafeedIds: jobTypes.map((jobType) => + getDatafeedId(spaceId, logViewId, idFormat, jobType) + ), }) ), }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts index 35c678f7b20c..9e2996215df8 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_get_jobs_summary_api.ts @@ -8,26 +8,28 @@ import * as rt from 'io-ts'; import type { HttpHandler } from '@kbn/core/public'; +import { IdFormat, JobType } from '../../../../../common/http_api/latest'; import { getJobId, jobCustomSettingsRT } from '../../../../../common/log_analysis'; import { decodeOrThrow } from '../../../../../common/runtime_types'; -interface RequestArgs { +interface RequestArgs { spaceId: string; logViewId: string; - jobTypes: JobType[]; + idFormat: IdFormat; + jobTypes: T[]; } -export const callJobsSummaryAPI = async ( - requestArgs: RequestArgs, +export const callJobsSummaryAPI = async ( + requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { spaceId, logViewId, jobTypes } = requestArgs; + const { spaceId, logViewId, idFormat, jobTypes } = requestArgs; const response = await fetch('/internal/ml/jobs/jobs_summary', { method: 'POST', version: '1', body: JSON.stringify( fetchJobStatusRequestPayloadRT.encode({ - jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, jobType)), + jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, idFormat, jobType)), }) ), }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts index f19c754ada38..f1e34cdd4051 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts @@ -46,7 +46,7 @@ export const callSetupMlModuleAPI = async (requestArgs: RequestArgs, fetch: Http start, end, indexPatternName: indexPattern, - prefix: getJobIdPrefix(spaceId, sourceId), + prefix: getJobIdPrefix(spaceId, sourceId, 'hashed'), startDatafeed: true, jobOverrides, datafeedOverrides, diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx index b9668311df06..b70ca688f53d 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_cleanup.tsx @@ -6,17 +6,19 @@ */ import type { HttpHandler } from '@kbn/core/public'; +import { IdFormat, JobType } from '../../../../common/http_api/latest'; import { getJobId } from '../../../../common/log_analysis'; import { callDeleteJobs, callGetJobDeletionTasks, callStopDatafeeds } from './api/ml_cleanup'; -export const cleanUpJobsAndDatafeeds = async ( +export const cleanUpJobsAndDatafeeds = async ( spaceId: string, logViewId: string, - jobTypes: JobType[], + idFormat: IdFormat, + jobTypes: T[], fetch: HttpHandler ) => { try { - await callStopDatafeeds({ spaceId, logViewId, jobTypes }, fetch); + await callStopDatafeeds({ spaceId, logViewId, idFormat, jobTypes }, fetch); } catch (err) { // Proceed only if datafeed has been deleted or didn't exist in the first place if (err?.response?.status !== 404) { @@ -24,27 +26,32 @@ export const cleanUpJobsAndDatafeeds = async ( } } - return await deleteJobs(spaceId, logViewId, jobTypes, fetch); + return await deleteJobs(spaceId, logViewId, idFormat, jobTypes, fetch); }; -const deleteJobs = async ( +const deleteJobs = async ( spaceId: string, logViewId: string, - jobTypes: JobType[], + idFormat: IdFormat, + jobTypes: T[], fetch: HttpHandler ) => { - const deleteJobsResponse = await callDeleteJobs({ spaceId, logViewId, jobTypes }, fetch); - await waitUntilJobsAreDeleted(spaceId, logViewId, jobTypes, fetch); + const deleteJobsResponse = await callDeleteJobs( + { spaceId, logViewId, idFormat, jobTypes }, + fetch + ); + await waitUntilJobsAreDeleted(spaceId, logViewId, idFormat, jobTypes, fetch); return deleteJobsResponse; }; -const waitUntilJobsAreDeleted = async ( +const waitUntilJobsAreDeleted = async ( spaceId: string, logViewId: string, - jobTypes: JobType[], + idFormat: IdFormat, + jobTypes: T[], fetch: HttpHandler ) => { - const moduleJobIds = jobTypes.map((jobType) => getJobId(spaceId, logViewId, jobType)); + const moduleJobIds = jobTypes.map((jobType) => getJobId(spaceId, logViewId, idFormat, jobType)); while (true) { const { jobs } = await callGetJobDeletionTasks(fetch); const needToWait = jobs diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx index 58bade0a81d0..25ddd466e6e8 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx @@ -7,22 +7,27 @@ import { useCallback, useMemo } from 'react'; import { useUiTracker } from '@kbn/observability-shared-plugin/public'; +import { useLogMlJobIdFormatsShimContext } from '../../../pages/logs/shared/use_log_ml_job_id_formats_shim'; +import { IdFormat, JobType } from '../../../../common/http_api/latest'; import { DatasetFilter } from '../../../../common/log_analysis'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { useModuleStatus } from './log_analysis_module_status'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; -export const useLogAnalysisModule = ({ +export const useLogAnalysisModule = ({ sourceConfiguration, + idFormat, moduleDescriptor, }: { sourceConfiguration: ModuleSourceConfiguration; - moduleDescriptor: ModuleDescriptor; + idFormat: IdFormat; + moduleDescriptor: ModuleDescriptor; }) => { const { services } = useKibanaContextForPlugin(); const { spaceId, sourceId: logViewId, timestampField, runtimeMappings } = sourceConfiguration; const [moduleStatus, dispatchModuleStatus] = useModuleStatus(moduleDescriptor.jobTypes); + const { migrateIdFormat } = useLogMlJobIdFormatsShimContext(); const trackMetric = useUiTracker({ app: 'infra_logs' }); @@ -31,7 +36,12 @@ export const useLogAnalysisModule = ({ cancelPreviousOn: 'resolution', createPromise: async () => { dispatchModuleStatus({ type: 'fetchingJobStatuses' }); - return await moduleDescriptor.getJobSummary(spaceId, logViewId, services.http.fetch); + return await moduleDescriptor.getJobSummary( + spaceId, + logViewId, + idFormat, + services.http.fetch + ); }, onResolve: (jobResponse) => { dispatchModuleStatus({ @@ -39,13 +49,14 @@ export const useLogAnalysisModule = ({ payload: jobResponse, spaceId, logViewId, + idFormat, }); }, onReject: () => { dispatchModuleStatus({ type: 'failedFetchingJobStatuses' }); }, }, - [spaceId, logViewId] + [spaceId, logViewId, idFormat] ); const [, setUpModule] = useTrackedPromise( @@ -74,6 +85,7 @@ export const useLogAnalysisModule = ({ const jobSummaries = await moduleDescriptor.getJobSummary( spaceId, logViewId, + 'hashed', services.http.fetch ); return { setupResult, jobSummaries }; @@ -105,7 +117,9 @@ export const useLogAnalysisModule = ({ jobSummaries, spaceId, logViewId, + idFormat: 'hashed', }); + migrateIdFormat(moduleDescriptor.jobTypes[0]); }, onReject: (e: any) => { dispatchModuleStatus({ type: 'failedSetup' }); @@ -121,13 +135,18 @@ export const useLogAnalysisModule = ({ { cancelPreviousOn: 'resolution', createPromise: async () => { - return await moduleDescriptor.cleanUpModule(spaceId, logViewId, services.http.fetch); + return await moduleDescriptor.cleanUpModule( + spaceId, + logViewId, + idFormat, + services.http.fetch + ); }, onReject: (e) => { throw new Error(`Failed to clean up previous ML job: ${e}`); }, }, - [spaceId, logViewId] + [spaceId, logViewId, idFormat] ); const isCleaningUp = useMemo( @@ -159,8 +178,8 @@ export const useLogAnalysisModule = ({ }, [dispatchModuleStatus]); const jobIds = useMemo( - () => moduleDescriptor.getJobIds(spaceId, logViewId), - [moduleDescriptor, spaceId, logViewId] + () => moduleDescriptor.getJobIds(spaceId, logViewId, idFormat), + [moduleDescriptor, spaceId, logViewId, idFormat] ); return { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_configuration.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_configuration.ts index 057580679210..5cf26d75e9f0 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_configuration.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_configuration.ts @@ -7,14 +7,15 @@ import { useMemo } from 'react'; import equal from 'fast-deep-equal'; +import { JobType } from '../../../../common/http_api/latest'; import { JobSummary } from './api/ml_get_jobs_summary_api'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; -export const useLogAnalysisModuleConfiguration = ({ +export const useLogAnalysisModuleConfiguration = ({ moduleDescriptor, sourceConfiguration, }: { - moduleDescriptor: ModuleDescriptor; + moduleDescriptor: ModuleDescriptor; sourceConfiguration: ModuleSourceConfiguration; }) => { const getIsJobConfigurationOutdated = useMemo( @@ -28,8 +29,8 @@ export const useLogAnalysisModuleConfiguration = ({ }; export const isJobConfigurationOutdated = - ( - { bucketSpan }: ModuleDescriptor, + ( + { bucketSpan }: ModuleDescriptor, currentSourceConfiguration: ModuleSourceConfiguration ) => (jobSummary: JobSummary): boolean => { diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx index 61de3681b574..b75f91317032 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_definition.tsx @@ -6,6 +6,7 @@ */ import { useCallback, useMemo, useState } from 'react'; +import { IdFormat, JobType } from '../../../../common/http_api/latest'; import { getJobId } from '../../../../common/log_analysis'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; @@ -13,12 +14,14 @@ import { JobSummary } from './api/ml_get_jobs_summary_api'; import { GetMlModuleResponsePayload, JobDefinition } from './api/ml_get_module'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; -export const useLogAnalysisModuleDefinition = ({ +export const useLogAnalysisModuleDefinition = ({ sourceConfiguration: { spaceId, sourceId }, + idFormat, moduleDescriptor, }: { sourceConfiguration: ModuleSourceConfiguration; - moduleDescriptor: ModuleDescriptor; + idFormat: IdFormat; + moduleDescriptor: ModuleDescriptor; }) => { const { services } = useKibanaContextForPlugin(); const [moduleDefinition, setModuleDefinition] = useState< @@ -31,12 +34,12 @@ export const useLogAnalysisModuleDefinition = ({ ? moduleDefinition.jobs.reduce>( (accumulatedJobDefinitions, jobDefinition) => ({ ...accumulatedJobDefinitions, - [getJobId(spaceId, sourceId, jobDefinition.id)]: jobDefinition, + [getJobId(spaceId, sourceId, idFormat, jobDefinition.id as T)]: jobDefinition, }), {} ) : {}, - [moduleDefinition, sourceId, spaceId] + [moduleDefinition, sourceId, spaceId, idFormat] ); const [fetchModuleDefinitionRequest, fetchModuleDefinition] = useTrackedPromise( diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx index 6fcfea1038a0..b6ce4085286e 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx @@ -7,6 +7,7 @@ import { useReducer } from 'react'; +import { IdFormat, JobType } from '../../../../common/http_api/latest'; import { JobStatus, getDatafeedId, @@ -18,8 +19,8 @@ import { FetchJobStatusResponsePayload, JobSummary } from './api/ml_get_jobs_sum import { SetupMlModuleResponsePayload } from './api/ml_setup_module_api'; import { MandatoryProperty } from '../../../../common/utility_types'; -interface StatusReducerState { - jobStatus: Record; +interface StatusReducerState { + jobStatus: Record; jobSummaries: JobSummary[]; lastSetupErrorMessages: string[]; setupStatus: SetupStatus; @@ -31,6 +32,7 @@ type StatusReducerAction = type: 'finishedSetup'; logViewId: string; spaceId: string; + idFormat: IdFormat; jobSetupResults: SetupMlModuleResponsePayload['jobs']; jobSummaries: FetchJobStatusResponsePayload; datafeedSetupResults: SetupMlModuleResponsePayload['datafeeds']; @@ -41,22 +43,23 @@ type StatusReducerAction = type: 'fetchedJobStatuses'; spaceId: string; logViewId: string; + idFormat: IdFormat; payload: FetchJobStatusResponsePayload; } | { type: 'failedFetchingJobStatuses' } | { type: 'viewedResults' }; -const createInitialState = ({ +const createInitialState = ({ jobTypes, }: { - jobTypes: JobType[]; -}): StatusReducerState => ({ + jobTypes: T[]; +}): StatusReducerState => ({ jobStatus: jobTypes.reduce( (accumulatedJobStatus, jobType) => ({ ...accumulatedJobStatus, [jobType]: 'unknown', }), - {} as Record + {} as Record ), jobSummaries: [], lastSetupErrorMessages: [], @@ -64,11 +67,8 @@ const createInitialState = ({ }); const createStatusReducer = - (jobTypes: JobType[]) => - ( - state: StatusReducerState, - action: StatusReducerAction - ): StatusReducerState => { + (jobTypes: T[]) => + (state: StatusReducerState, action: StatusReducerAction): StatusReducerState => { switch (action.type) { case 'startedSetup': { return { @@ -78,25 +78,34 @@ const createStatusReducer = ...accumulatedJobStatus, [jobType]: 'initializing', }), - {} as Record + {} as Record ), setupStatus: { type: 'pending' }, }; } case 'finishedSetup': { - const { datafeedSetupResults, jobSetupResults, jobSummaries, spaceId, logViewId } = action; + const { + datafeedSetupResults, + jobSetupResults, + jobSummaries, + spaceId, + logViewId, + idFormat, + } = action; const nextJobStatus = jobTypes.reduce( (accumulatedJobStatus, jobType) => ({ ...accumulatedJobStatus, [jobType]: - hasSuccessfullyCreatedJob(getJobId(spaceId, logViewId, jobType))(jobSetupResults) && - hasSuccessfullyStartedDatafeed(getDatafeedId(spaceId, logViewId, jobType))( + hasSuccessfullyCreatedJob(getJobId(spaceId, logViewId, idFormat, jobType))( + jobSetupResults + ) && + hasSuccessfullyStartedDatafeed(getDatafeedId(spaceId, logViewId, idFormat, jobType))( datafeedSetupResults ) ? 'started' : 'failed', }), - {} as Record + {} as Record ); const nextSetupStatus: SetupStatus = Object.values(nextJobStatus).every( (jobState) => jobState === 'started' || jobState === 'starting' @@ -129,7 +138,7 @@ const createStatusReducer = ...accumulatedJobStatus, [jobType]: 'failed', }), - {} as Record + {} as Record ), setupStatus: { type: 'failed', reasons: action.reason ? [action.reason] : ['unknown'] }, }; @@ -142,15 +151,15 @@ const createStatusReducer = }; } case 'fetchedJobStatuses': { - const { payload: jobSummaries, spaceId, logViewId } = action; + const { payload: jobSummaries, spaceId, logViewId, idFormat } = action; const { setupStatus } = state; const nextJobStatus = jobTypes.reduce( (accumulatedJobStatus, jobType) => ({ ...accumulatedJobStatus, - [jobType]: getJobStatus(getJobId(spaceId, logViewId, jobType))(jobSummaries), + [jobType]: getJobStatus(getJobId(spaceId, logViewId, idFormat, jobType))(jobSummaries), }), - {} as Record + {} as Record ); const nextSetupStatus = getSetupStatus(nextJobStatus)(setupStatus); @@ -170,7 +179,7 @@ const createStatusReducer = ...accumulatedJobStatus, [jobType]: 'unknown', }), - {} as Record + {} as Record ), }; } @@ -243,7 +252,7 @@ const getJobStatus = })[0] || 'missing'; const getSetupStatus = - (everyJobStatus: Record) => + (everyJobStatus: Record) => (previousSetupStatus: SetupStatus): SetupStatus => Object.entries(everyJobStatus).reduce((setupStatus, [, jobStatus]) => { if (jobStatus === 'missing') { @@ -265,6 +274,6 @@ const hasError = ( value: Value ): value is MandatoryProperty => value.error != null; -export const useModuleStatus = (jobTypes: JobType[]) => { +export const useModuleStatus = (jobTypes: T[]) => { return useReducer(createStatusReducer(jobTypes), { jobTypes }, createInitialState); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts index d6e95b7feebe..2e0a6b742ce1 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_types.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IdFormat, JobType } from '../../../../common/http_api/latest'; import { ValidateLogEntryDatasetsResponsePayload, ValidationIndicesResponsePayload, @@ -19,16 +20,17 @@ import { SetupMlModuleResponsePayload } from './api/ml_setup_module_api'; export type { JobModelSizeStats, JobSummary } from './api/ml_get_jobs_summary_api'; -export interface ModuleDescriptor { +export interface ModuleDescriptor { moduleId: string; moduleName: string; moduleDescription: string; - jobTypes: JobType[]; + jobTypes: T[]; bucketSpan: number; - getJobIds: (spaceId: string, logViewId: string) => Record; + getJobIds: (spaceId: string, logViewId: string, idFormat: IdFormat) => Record; getJobSummary: ( spaceId: string, logViewId: string, + idFormat: IdFormat, fetch: HttpHandler ) => Promise; getModuleDefinition: (fetch: HttpHandler) => Promise; @@ -42,6 +44,7 @@ export interface ModuleDescriptor { cleanUpModule: ( spaceId: string, logViewId: string, + idFormat: IdFormat, fetch: HttpHandler ) => Promise; validateSetupIndices: ( diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts index fad6fd56f625..14251d5f4dbf 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts @@ -8,6 +8,7 @@ import { isEqual } from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; +import { JobType } from '../../../../common/http_api/latest'; import { combineDatasetFilters, DatasetFilter, @@ -30,21 +31,21 @@ type SetupHandler = ( datasetFilter: DatasetFilter ) => void; -interface AnalysisSetupStateArguments { +interface AnalysisSetupStateArguments { cleanUpAndSetUpModule: SetupHandler; - moduleDescriptor: ModuleDescriptor; + moduleDescriptor: ModuleDescriptor; setUpModule: SetupHandler; sourceConfiguration: ModuleSourceConfiguration; } const fourWeeksInMs = 86400000 * 7 * 4; -export const useAnalysisSetupState = ({ +export const useAnalysisSetupState = ({ cleanUpAndSetUpModule, moduleDescriptor: { validateSetupDatasets, validateSetupIndices }, setUpModule, sourceConfiguration, -}: AnalysisSetupStateArguments) => { +}: AnalysisSetupStateArguments) => { const { services } = useKibanaContextForPlugin(); const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs); const [endTime, setEndTime] = useState(undefined); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts index 07a183973178..fbcc4d166d4b 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/module_descriptor.ts @@ -8,11 +8,13 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import type { HttpHandler } from '@kbn/core/public'; +import { IdFormat } from '../../../../../../common/http_api/latest'; import { bucketSpan, categoriesMessageField, DatasetFilter, getJobId, + logEntryCategoriesJobType, LogEntryCategoriesJobType, logEntryCategoriesJobTypes, partitionField, @@ -36,21 +38,26 @@ const moduleDescription = i18n.translate( } ); -const getJobIds = (spaceId: string, logViewId: string) => +const getJobIds = (spaceId: string, logViewId: string, idFormat: IdFormat) => logEntryCategoriesJobTypes.reduce( (accumulatedJobIds, jobType) => ({ ...accumulatedJobIds, - [jobType]: getJobId(spaceId, logViewId, jobType), + [jobType]: getJobId(spaceId, logViewId, idFormat, jobType), }), {} as Record ); -const getJobSummary = async (spaceId: string, logViewId: string, fetch: HttpHandler) => { +const getJobSummary = async ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + fetch: HttpHandler +) => { const response = await callJobsSummaryAPI( - { spaceId, logViewId, jobTypes: logEntryCategoriesJobTypes }, + { spaceId, logViewId, idFormat, jobTypes: logEntryCategoriesJobTypes }, fetch ); - const jobIds = Object.values(getJobIds(spaceId, logViewId)); + const jobIds = Object.values(getJobIds(spaceId, logViewId, idFormat)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; @@ -69,7 +76,7 @@ const setUpModule = async ( const indexNamePattern = indices.join(','); const jobOverrides = [ { - job_id: 'log-entry-categories-count' as const, + job_id: logEntryCategoriesJobType, analysis_config: { bucket_span: `${bucketSpan}ms`, }, @@ -88,7 +95,7 @@ const setUpModule = async ( ]; const datafeedOverrides = [ { - job_id: 'log-entry-categories-count' as const, + job_id: logEntryCategoriesJobType, runtime_mappings: runtimeMappings, }, ]; @@ -130,8 +137,19 @@ const setUpModule = async ( ); }; -const cleanUpModule = async (spaceId: string, logViewId: string, fetch: HttpHandler) => { - return await cleanUpJobsAndDatafeeds(spaceId, logViewId, logEntryCategoriesJobTypes, fetch); +const cleanUpModule = async ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + fetch: HttpHandler +) => { + return await cleanUpJobsAndDatafeeds( + spaceId, + logViewId, + idFormat, + logEntryCategoriesJobTypes, + fetch + ); }; const validateSetupIndices = async ( diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx index 3f4d80294097..a8c371fa9439 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_categories/use_log_entry_categories_module.tsx @@ -8,6 +8,7 @@ import createContainer from 'constate'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useMemo } from 'react'; +import { IdFormat } from '../../../../../../common/http_api/latest'; import { useLogAnalysisModule } from '../../log_analysis_module'; import { useLogAnalysisModuleConfiguration } from '../../log_analysis_module_configuration'; import { useLogAnalysisModuleDefinition } from '../../log_analysis_module_definition'; @@ -19,12 +20,14 @@ export const useLogEntryCategoriesModule = ({ indexPattern, logViewId, spaceId, + idFormat, timestampField, runtimeMappings, }: { indexPattern: string; logViewId: string; spaceId: string; + idFormat: IdFormat; timestampField: string; runtimeMappings: estypes.MappingRuntimeFields; }) => { @@ -41,6 +44,7 @@ export const useLogEntryCategoriesModule = ({ const logAnalysisModule = useLogAnalysisModule({ moduleDescriptor: logEntryCategoriesModule, + idFormat, sourceConfiguration, }); @@ -51,6 +55,7 @@ export const useLogEntryCategoriesModule = ({ const { fetchModuleDefinition, getIsJobDefinitionOutdated } = useLogAnalysisModuleDefinition({ sourceConfiguration, + idFormat, moduleDescriptor: logEntryCategoriesModule, }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts index a2e0219da991..a0dc8e68bf9a 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/module_descriptor.ts @@ -8,10 +8,12 @@ import { i18n } from '@kbn/i18n'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { HttpHandler } from '@kbn/core/public'; +import { IdFormat } from '../../../../../../common/http_api/latest'; import { bucketSpan, DatasetFilter, getJobId, + logEntryRateJobType, LogEntryRateJobType, logEntryRateJobTypes, partitionField, @@ -35,21 +37,26 @@ const moduleDescription = i18n.translate( } ); -const getJobIds = (spaceId: string, logViewId: string) => +const getJobIds = (spaceId: string, logViewId: string, idFormat: IdFormat) => logEntryRateJobTypes.reduce( (accumulatedJobIds, jobType) => ({ ...accumulatedJobIds, - [jobType]: getJobId(spaceId, logViewId, jobType), + [jobType]: getJobId(spaceId, logViewId, idFormat, jobType), }), {} as Record ); -const getJobSummary = async (spaceId: string, logViewId: string, fetch: HttpHandler) => { +const getJobSummary = async ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + fetch: HttpHandler +) => { const response = await callJobsSummaryAPI( - { spaceId, logViewId, jobTypes: logEntryRateJobTypes }, + { spaceId, logViewId, idFormat, jobTypes: logEntryRateJobTypes }, fetch ); - const jobIds = Object.values(getJobIds(spaceId, logViewId)); + const jobIds = Object.values(getJobIds(spaceId, logViewId, idFormat)); return response.filter((jobSummary) => jobIds.includes(jobSummary.id)); }; @@ -68,7 +75,8 @@ const setUpModule = async ( const indexNamePattern = indices.join(','); const jobOverrides = [ { - job_id: 'log-entry-rate' as const, + description: `Logs UI (${spaceId}/${sourceId}): Detects anomalies in the log entry ingestion rate`, + job_id: logEntryRateJobType, analysis_config: { bucket_span: `${bucketSpan}ms`, }, @@ -86,7 +94,7 @@ const setUpModule = async ( ]; const datafeedOverrides = [ { - job_id: 'log-entry-rate' as const, + job_id: logEntryRateJobType, runtime_mappings: runtimeMappings, }, ]; @@ -122,8 +130,13 @@ const setUpModule = async ( ); }; -const cleanUpModule = async (spaceId: string, logViewId: string, fetch: HttpHandler) => { - return await cleanUpJobsAndDatafeeds(spaceId, logViewId, logEntryRateJobTypes, fetch); +const cleanUpModule = async ( + spaceId: string, + logViewId: string, + idFormat: IdFormat, + fetch: HttpHandler +) => { + return await cleanUpJobsAndDatafeeds(spaceId, logViewId, idFormat, logEntryRateJobTypes, fetch); }; const validateSetupIndices = async ( diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx index 65bddee00ce3..a00d9f0017c3 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/modules/log_entry_rate/use_log_entry_rate_module.tsx @@ -8,6 +8,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import createContainer from 'constate'; import { useMemo } from 'react'; +import { IdFormat } from '../../../../../../common/http_api/latest'; import { ModuleSourceConfiguration } from '../../log_analysis_module_types'; import { useLogAnalysisModule } from '../../log_analysis_module'; import { useLogAnalysisModuleConfiguration } from '../../log_analysis_module_configuration'; @@ -18,12 +19,14 @@ export const useLogEntryRateModule = ({ indexPattern, logViewId, spaceId, + idFormat, timestampField, runtimeMappings, }: { indexPattern: string; logViewId: string; spaceId: string; + idFormat: IdFormat; timestampField: string; runtimeMappings: estypes.MappingRuntimeFields; }) => { @@ -40,6 +43,7 @@ export const useLogEntryRateModule = ({ const logAnalysisModule = useLogAnalysisModule({ moduleDescriptor: logEntryRateModule, + idFormat, sourceConfiguration, }); @@ -50,6 +54,7 @@ export const useLogEntryRateModule = ({ const { fetchModuleDefinition, getIsJobDefinitionOutdated } = useLogAnalysisModuleDefinition({ sourceConfiguration, + idFormat, moduleDescriptor: logEntryRateModule, }); diff --git a/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts b/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts index afb1ee211a75..1cd85d448e7b 100644 --- a/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts +++ b/x-pack/plugins/infra/public/containers/ml/api/ml_get_module.ts @@ -8,7 +8,7 @@ import * as rt from 'io-ts'; import type { HttpHandler } from '@kbn/core/public'; -import { jobCustomSettingsRT } from '../../../../common/log_analysis'; +import { jobCustomSettingsRT } from '../../../../common/infra_ml'; import { decodeOrThrow } from '../../../../common/runtime_types'; export const callGetMlModuleAPI = async (moduleId: string, fetch: HttpHandler) => { diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx index 88b7cfd94109..1dca20d586a5 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_module_definition.tsx @@ -6,7 +6,7 @@ */ import { useCallback, useMemo, useState } from 'react'; -import { getJobId } from '../../../common/log_analysis'; +import { getJobId } from '../../../common/infra_ml'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { useTrackedPromise } from '../../utils/use_tracked_promise'; import { JobSummary } from './api/ml_get_jobs_summary_api'; diff --git a/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx index 43d4e8913564..1b9980bf5f17 100644 --- a/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx +++ b/x-pack/plugins/infra/public/containers/plugin_config_context.test.tsx @@ -28,6 +28,7 @@ describe('usePluginConfig()', () => { metricThresholdAlertRuleEnabled: true, logThresholdAlertRuleEnabled: true, alertsAndRulesDropdownEnabled: true, + profilingEnabled: false, }, }; const { result } = renderHook(() => usePluginConfig(), { diff --git a/x-pack/plugins/infra/public/hooks/use_http_request.tsx b/x-pack/plugins/infra/public/hooks/use_http_request.tsx index 819667700471..370d4a9ccf38 100644 --- a/x-pack/plugins/infra/public/hooks/use_http_request.tsx +++ b/x-pack/plugins/infra/public/hooks/use_http_request.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { HttpHandler, ToastInput } from '@kbn/core/public'; +import { HttpFetchOptions, HttpHandler, ToastInput } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { AbortError } from '@kbn/kibana-utils-plugin/common'; import { useTrackedPromise, CanceledPromiseError } from '../utils/use_tracked_promise'; @@ -20,7 +20,8 @@ export function useHTTPRequest( decode: (response: any) => Response = (response) => response, fetch?: HttpHandler, toastDanger?: (input: ToastInput) => void, - abortable = false + abortable = false, + fetchOptions?: Omit ) { const kibana = useKibana(); const fetchService = fetch ? fetch : kibana.services.http?.fetch; @@ -100,6 +101,7 @@ export function useHTTPRequest( signal: abortController.current.signal, method, body, + ...fetchOptions, }); }, onResolve: (resp) => { @@ -114,7 +116,7 @@ export function useHTTPRequest( onError(e); }, }, - [pathname, body, method, fetch, toast, onError] + [pathname, body, method, fetch, toast, onError, fetchOptions] ); const loading = request.state === 'uninitialized' || request.state === 'pending'; diff --git a/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx b/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx index 2a72a2d3b3d6..8b7d76113eea 100644 --- a/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx +++ b/x-pack/plugins/infra/public/hooks/use_kibana_index_patterns.mock.tsx @@ -99,7 +99,6 @@ export const createIndexPatternMock = ({ return accumulatedRuntimeFields; }, {}), scriptFields: {}, - storedFields: [], }), }; }; diff --git a/x-pack/plugins/infra/public/hooks/use_lens_attributes.test.ts b/x-pack/plugins/infra/public/hooks/use_lens_attributes.test.ts index 116107a64a43..a0bf9dd6c1fc 100644 --- a/x-pack/plugins/infra/public/hooks/use_lens_attributes.test.ts +++ b/x-pack/plugins/infra/public/hooks/use_lens_attributes.test.ts @@ -15,7 +15,6 @@ import { CoreStart } from '@kbn/core/public'; import type { InfraClientStartDeps } from '../types'; import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; import { FilterStateStore } from '@kbn/es-query'; -import { hostLensFormulas } from '../common/visualizations'; jest.mock('@kbn/kibana-react-plugin/public'); const useKibanaMock = useKibana as jest.MockedFunction; @@ -31,7 +30,16 @@ const mockDataView = { metaFields: [], } as unknown as jest.Mocked; -const normalizedLoad1m = hostLensFormulas.normalizedLoad1m; +const normalizedLoad1m = { + label: 'Normalized Load', + value: 'average(system.load.1) / max(system.load.cores)', + format: { + id: 'percent', + params: { + decimals: 0, + }, + }, +}; const lensPluginMockStart = lensPluginMock.createStartContract(); const mockUseKibana = () => { @@ -55,7 +63,6 @@ describe('useHostTable hook', () => { layers: [ { data: [normalizedLoad1m], - type: 'visualization', options: { buckets: { type: 'date_histogram', @@ -68,6 +75,7 @@ describe('useHostTable hook', () => { }, }, }, + layerType: 'data', }, { data: [ @@ -81,7 +89,7 @@ describe('useHostTable hook', () => { }, }, ], - type: 'referenceLines', + layerType: 'referenceLine', }, ], title: 'Injected Normalized Load', @@ -195,11 +203,12 @@ describe('useHostTable hook', () => { it('should return extra actions', async () => { const { result, waitForNextUpdate } = renderHook(() => useLensAttributes({ + title: 'Chart', visualizationType: 'lnsXY', layers: [ { data: [normalizedLoad1m], - type: 'visualization', + layerType: 'data', }, ], dataView: mockDataView, diff --git a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts index aa5feb4dc0b4..7a5f07d171eb 100644 --- a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts @@ -15,9 +15,10 @@ import useAsync from 'react-use/lib/useAsync'; import { FormulaPublicApi } from '@kbn/lens-plugin/public'; import { type LensVisualizationState, - type XYVisualOptions, type Chart, type LensAttributes, + type ChartModel, + type XYLayerConfig, LensAttributesBuilder, XYChart, MetricChart, @@ -26,35 +27,17 @@ import { XYReferenceLinesLayer, } from '@kbn/lens-embeddable-utils'; import { InfraClientSetupDeps } from '../types'; -import type { MetricChartLayerParams, XYChartLayerParams } from '../common/visualizations/types'; -interface UseLensAttributesBaseParams { - dataView?: DataView; - title?: string; -} - -export interface UseLensAttributesXYChartParams extends UseLensAttributesBaseParams { - layers: XYChartLayerParams[]; - visualizationType: 'lnsXY'; - visualOptions?: XYVisualOptions; -} - -export interface UseLensAttributesMetricChartParams extends UseLensAttributesBaseParams { - layers: MetricChartLayerParams; - visualizationType: 'lnsMetric'; - subtitle?: string; -} - -export type UseLensAttributesParams = - | UseLensAttributesXYChartParams - | UseLensAttributesMetricChartParams; +export type UseLensAttributesParams = Omit; export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesParams) => { const { services: { lens }, } = useKibana(); const { navigateToPrefilledEditor } = lens; - const { value, error } = useAsync(lens.stateHelperApi, [lens]); + const { value, error } = useAsync(() => { + return lens.stateHelperApi(); + }, [lens]); const { formula: formulaAPI } = value ?? {}; const attributes = useMemo(() => { @@ -144,7 +127,7 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara const getFormula = () => { const firstDataLayer = [ ...(Array.isArray(params.layers) ? params.layers : [params.layers]), - ].find((p) => p.type === 'visualization'); + ].find((p) => p.layerType === 'data'); if (!firstDataLayer) { return ''; @@ -174,32 +157,27 @@ const chartFactory = ({ throw new Error(`Invalid layers type. Expected an array of layers.`); } - const xyLayerFactory = (layer: XYChartLayerParams) => { - switch (layer.type) { - case 'visualization': { - return new XYDataLayer({ - data: layer.data, - options: layer.options, - }); + const xyLayerFactory = (layer: XYLayerConfig) => { + switch (layer.layerType) { + case 'data': { + return new XYDataLayer(layer); } - case 'referenceLines': { - return new XYReferenceLinesLayer({ - data: layer.data, - }); + case 'referenceLine': { + return new XYReferenceLinesLayer(layer); } default: throw new Error(`Invalid layer type`); } }; + const { layers, ...rest } = params; return new XYChart({ dataView, formulaAPI, - layers: params.layers.map((layerItem) => { + layers: layers.map((layerItem) => { return xyLayerFactory(layerItem); }), - title: params.title, - visualOptions: params.visualOptions, + ...rest, }); case 'lnsMetric': @@ -212,7 +190,8 @@ const chartFactory = ({ formulaAPI, layers: new MetricLayer({ data: params.layers.data, - options: { ...params.layers.options, subtitle: params.subtitle }, + options: { ...params.layers.options }, + layerType: params.layers.layerType, }), title: params.title, }); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page.tsx index 34634b194cb8..f5b1e89c69e0 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page.tsx @@ -11,6 +11,7 @@ import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; import { LogEntryCategoriesPageContent } from './page_content'; import { LogEntryCategoriesPageProviders } from './page_providers'; import { logCategoriesTitle } from '../../../translations'; +import { LogMlJobIdFormatsShimProvider } from '../shared/use_log_ml_job_id_formats_shim'; export const LogEntryCategoriesPage = () => { useLogsBreadcrumbs([ @@ -21,9 +22,11 @@ export const LogEntryCategoriesPage = () => { return ( - - - + + + + + ); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx index d6a1e9f2ddc5..c58ffc5f36e8 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback, useEffect } from 'react'; import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; -import { isJobStatusWithResults } from '../../../../common/log_analysis'; +import { isJobStatusWithResults, logEntryCategoriesJobType } from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, @@ -26,6 +26,7 @@ import { useLogEntryCategoriesModuleContext } from '../../../containers/logs/log import { LogsPageTemplate } from '../shared/page_template'; import { LogEntryCategoriesResultsContent } from './page_results_content'; import { LogEntryCategoriesSetupContent } from './page_setup_content'; +import { useLogMlJobIdFormatsShimContext } from '../shared/use_log_ml_job_id_formats_shim'; const logCategoriesTitle = i18n.translate('xpack.infra.logs.logCategoriesTitle', { defaultMessage: 'Categories', @@ -52,6 +53,8 @@ export const LogEntryCategoriesPageContent = () => { } }, [fetchJobStatus, hasLogAnalysisReadCapabilities]); + const { idFormats } = useLogMlJobIdFormatsShimContext(); + if (!hasLogAnalysisCapabilites) { return ( { ); - } else if (isJobStatusWithResults(jobStatus['log-entry-categories-count'])) { + } else if (isJobStatusWithResults(jobStatus[logEntryCategoriesJobType])) { return ( <> diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_providers.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_providers.tsx index 5cb6a12166c5..89bcd98d0958 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_providers.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_providers.tsx @@ -7,12 +7,14 @@ import React from 'react'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; +import { logEntryCategoriesJobType } from '../../../../common/log_analysis'; import { InlineLogViewSplashPage } from '../../../components/logging/inline_log_view_splash_page'; import { LogAnalysisSetupFlyoutStateProvider } from '../../../components/logging/log_analysis_setup/setup_flyout'; import { SourceLoadingPage } from '../../../components/source_loading_page'; import { LogEntryCategoriesModuleProvider } from '../../../containers/logs/log_analysis/modules/log_entry_categories'; import { useActiveKibanaSpace } from '../../../hooks/use_kibana_space'; import { ConnectedLogViewErrorPage } from '../shared/page_log_view_error'; +import { useLogMlJobIdFormatsShimContext } from '../shared/use_log_ml_job_id_formats_shim'; export const LogEntryCategoriesPageProviders: React.FunctionComponent = ({ children }) => { const { @@ -25,6 +27,8 @@ export const LogEntryCategoriesPageProviders: React.FunctionComponent = ({ child revertToDefaultLogView, } = useLogViewContext(); const { space } = useActiveKibanaSpace(); + const { idFormats, isLoadingLogAnalysisIdFormats, hasFailedLoadingLogAnalysisIdFormats } = + useLogMlJobIdFormatsShimContext(); // This is a rather crude way of guarding the dependent providers against // arguments that are only made available asynchronously. Ideally, we'd use @@ -33,9 +37,9 @@ export const LogEntryCategoriesPageProviders: React.FunctionComponent = ({ child return null; } else if (!isPersistedLogView) { return ; - } else if (hasFailedLoading) { + } else if (hasFailedLoading || hasFailedLoadingLogAnalysisIdFormats) { return ; - } else if (isLoading || isUninitialized) { + } else if (isLoading || isUninitialized || isLoadingLogAnalysisIdFormats || !idFormats) { return ; } else if (resolvedLogView != null) { if (logViewReference.type === 'log-view-inline') { @@ -46,6 +50,7 @@ export const LogEntryCategoriesPageProviders: React.FunctionComponent = ({ child indexPattern={resolvedLogView.indices} logViewId={logViewReference.logViewId} spaceId={space.id} + idFormat={idFormats[logEntryCategoriesJobType]} timestampField={resolvedLogView.timestampField} runtimeMappings={resolvedLogView.runtimeMappings} > diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx index e1e317136dee..e1db34f31a5e 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_results_content.tsx @@ -16,6 +16,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { MLJobsAwaitingNodeWarning, ML_PAGES, useMlHref } from '@kbn/ml-plugin/public'; import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; +import { logEntryCategoriesJobType } from '../../../../common/log_analysis'; import { TimeRange } from '../../../../common/time/time_range'; import { CategoryJobNoticesSection } from '../../../components/logging/log_analysis_job_status'; import { AnalyzeInMlButton } from '../../../components/logging/log_analysis_results'; @@ -33,17 +34,19 @@ import { StringTimeRange, useLogEntryCategoriesResultsUrlState, } from './use_log_entry_categories_results_url_state'; +import { IdFormat } from '../../../../common/http_api/latest'; const JOB_STATUS_POLLING_INTERVAL = 30000; interface LogEntryCategoriesResultsContentProps { onOpenSetup: () => void; pageTitle: string; + idFormat: IdFormat; } export const LogEntryCategoriesResultsContent: React.FunctionComponent< LogEntryCategoriesResultsContentProps -> = ({ onOpenSetup, pageTitle }) => { +> = ({ onOpenSetup, pageTitle, idFormat }) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results', delay: 15000 }); @@ -110,6 +113,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent< filteredDatasets: categoryQueryDatasets, onGetTopLogEntryCategoriesError: showLoadDataErrorNotification, logViewReference: { type: 'log-view-reference', logViewId }, + idFormat, startTime: categoryQueryTimeRange.timeRange.startTime, }); @@ -195,7 +199,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent< const analyzeInMlLink = useMlHref(ml, http.basePath.get(), { page: ML_PAGES.ANOMALY_EXPLORER, pageState: { - jobIds: [jobIds['log-entry-categories-count']], + jobIds: [jobIds[logEntryCategoriesJobType]], timeRange: { from: moment(categoryQueryTimeRange.timeRange.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), to: moment(categoryQueryTimeRange.timeRange.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), @@ -264,7 +268,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent< = ({ categoryId, timeRange, logViewReference }) => { + const { idFormats } = useLogMlJobIdFormatsShimContext(); + const { getLogEntryCategoryExamples, hasFailedLoadingLogEntryCategoryExamples, @@ -29,6 +33,7 @@ export const CategoryDetailsRow: React.FunctionComponent<{ endTime: timeRange.endTime, exampleCount, logViewReference, + idFormat: idFormats?.[logEntryCategoriesJobType], startTime: timeRange.startTime, }); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts index 14e7ebfbebd3..4a194eb1fb07 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_datasets.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../../common/http_api/latest'; import { getLogEntryCategoryDatasetsRequestPayloadRT, @@ -17,6 +18,7 @@ import { decodeOrThrow } from '../../../../../common/runtime_types'; interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormat: IdFormat; startTime: number; endTime: number; } @@ -25,7 +27,7 @@ export const callGetLogEntryCategoryDatasetsAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { logViewReference, startTime, endTime } = requestArgs; + const { logViewReference, idFormat, startTime, endTime } = requestArgs; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH, { method: 'POST', @@ -33,6 +35,7 @@ export const callGetLogEntryCategoryDatasetsAPI = async ( getLogEntryCategoryDatasetsRequestPayloadRT.encode({ data: { logView: logViewReference, + idFormat, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts index 3e4947ca1e84..dece712414ce 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_log_entry_category_examples.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../../common/http_api/latest'; import { getLogEntryCategoryExamplesRequestPayloadRT, @@ -17,6 +18,7 @@ import { decodeOrThrow } from '../../../../../common/runtime_types'; interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormat: IdFormat; startTime: number; endTime: number; categoryId: number; @@ -27,7 +29,7 @@ export const callGetLogEntryCategoryExamplesAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { logViewReference, startTime, endTime, categoryId, exampleCount } = requestArgs; + const { logViewReference, idFormat, startTime, endTime, categoryId, exampleCount } = requestArgs; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH, { method: 'POST', @@ -37,6 +39,7 @@ export const callGetLogEntryCategoryExamplesAPI = async ( categoryId, exampleCount, logView: logViewReference, + idFormat, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts index c4a1b6d095a2..2b2808bf4646 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/service_calls/get_top_log_entry_categories.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../../common/http_api/latest'; import { getLogEntryCategoriesRequestPayloadRT, @@ -18,6 +19,7 @@ import { decodeOrThrow } from '../../../../../common/runtime_types'; interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormat: IdFormat; startTime: number; endTime: number; categoryCount: number; @@ -29,7 +31,8 @@ export const callGetTopLogEntryCategoriesAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { logViewReference, startTime, endTime, categoryCount, datasets, sort } = requestArgs; + const { logViewReference, idFormat, startTime, endTime, categoryCount, datasets, sort } = + requestArgs; const intervalDuration = endTime - startTime; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH, { @@ -38,6 +41,7 @@ export const callGetTopLogEntryCategoriesAPI = async ( getLogEntryCategoriesRequestPayloadRT.encode({ data: { logView: logViewReference, + idFormat, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts index 20f7adb10685..030c0298d011 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_categories_results.ts @@ -8,6 +8,7 @@ import { useMemo, useState } from 'react'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../common/http_api/latest'; import { GetLogEntryCategoriesSuccessResponsePayload, GetLogEntryCategoryDatasetsSuccessResponsePayload, @@ -32,6 +33,7 @@ export const useLogEntryCategoriesResults = ({ onGetLogEntryCategoryDatasetsError, onGetTopLogEntryCategoriesError, logViewReference, + idFormat, startTime, }: { categoriesCount: number; @@ -40,6 +42,7 @@ export const useLogEntryCategoriesResults = ({ onGetLogEntryCategoryDatasetsError?: (error: Error) => void; onGetTopLogEntryCategoriesError?: (error: Error) => void; logViewReference: PersistedLogViewReference; + idFormat: IdFormat; startTime: number; }) => { const [sortOptions, setSortOptions] = useState({ @@ -58,6 +61,7 @@ export const useLogEntryCategoriesResults = ({ return await callGetTopLogEntryCategoriesAPI( { logViewReference, + idFormat, startTime, endTime, categoryCount: categoriesCount, @@ -80,7 +84,15 @@ export const useLogEntryCategoriesResults = ({ } }, }, - [categoriesCount, endTime, filteredDatasets, logViewReference.logViewId, startTime, sortOptions] + [ + categoriesCount, + endTime, + filteredDatasets, + logViewReference.logViewId, + startTime, + sortOptions, + idFormat, + ] ); const [getLogEntryCategoryDatasetsRequest, getLogEntryCategoryDatasets] = useTrackedPromise( @@ -88,7 +100,7 @@ export const useLogEntryCategoriesResults = ({ cancelPreviousOn: 'creation', createPromise: async () => { return await callGetLogEntryCategoryDatasetsAPI( - { logViewReference, startTime, endTime }, + { logViewReference, idFormat, startTime, endTime }, services.http.fetch ); }, @@ -105,7 +117,7 @@ export const useLogEntryCategoriesResults = ({ } }, }, - [categoriesCount, endTime, logViewReference.logViewId, startTime] + [categoriesCount, endTime, logViewReference.logViewId, idFormat, startTime] ); const isLoadingTopLogEntryCategories = useMemo( diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx index c5516fdbc02f..e50664b957d7 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/use_log_entry_category_examples.tsx @@ -8,6 +8,7 @@ import { useMemo, useState } from 'react'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../common/http_api/latest'; import { LogEntryCategoryExample } from '../../../../common/http_api'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; @@ -18,12 +19,14 @@ export const useLogEntryCategoryExamples = ({ endTime, exampleCount, logViewReference, + idFormat, startTime, }: { categoryId: number; endTime: number; exampleCount: number; logViewReference: PersistedLogViewReference; + idFormat?: IdFormat; startTime: number; }) => { const { services } = useKibanaContextForPlugin(); @@ -36,9 +39,14 @@ export const useLogEntryCategoryExamples = ({ { cancelPreviousOn: 'creation', createPromise: async () => { + if (!idFormat) { + throw new Error('idFormat is undefined'); + } + return await callGetLogEntryCategoryExamplesAPI( { logViewReference, + idFormat, startTime, endTime, categoryId, @@ -51,7 +59,7 @@ export const useLogEntryCategoryExamples = ({ setLogEntryCategoryExamples(examples); }, }, - [categoryId, endTime, exampleCount, logViewReference, startTime] + [categoryId, endTime, exampleCount, logViewReference, startTime, idFormat] ); const isLoadingLogEntryCategoryExamples = useMemo( diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page.tsx index 94950b24b1a9..50a4852c458c 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page.tsx @@ -11,6 +11,7 @@ import { LogEntryRatePageContent } from './page_content'; import { LogEntryRatePageProviders } from './page_providers'; import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; import { anomaliesTitle } from '../../../translations'; +import { LogMlJobIdFormatsShimProvider } from '../shared/use_log_ml_job_id_formats_shim'; export const LogEntryRatePage = () => { useLogsBreadcrumbs([ @@ -20,9 +21,11 @@ export const LogEntryRatePage = () => { ]); return ( - - - + + + + + ); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx index 533381dcbf7c..e4dc0694c3f7 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx @@ -10,7 +10,11 @@ import React, { memo, useCallback, useEffect } from 'react'; import useInterval from 'react-use/lib/useInterval'; import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; -import { isJobStatusWithResults } from '../../../../common/log_analysis'; +import { + isJobStatusWithResults, + logEntryCategoriesJobType, + logEntryRateJobType, +} from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, @@ -28,6 +32,7 @@ import { useLogEntryRateModuleContext } from '../../../containers/logs/log_analy import { LogsPageTemplate } from '../shared/page_template'; import { LogEntryRateResultsContent } from './page_results_content'; import { LogEntryRateSetupContent } from './page_setup_content'; +import { useLogMlJobIdFormatsShimContext } from '../shared/use_log_ml_job_id_formats_shim'; const JOB_STATUS_POLLING_INTERVAL = 30000; @@ -89,6 +94,8 @@ export const LogEntryRatePageContent = memo(() => { } }, JOB_STATUS_POLLING_INTERVAL); + const { idFormats } = useLogMlJobIdFormatsShimContext(); + if (!hasLogAnalysisCapabilites) { return ( { ); } else if ( - isJobStatusWithResults(logEntryCategoriesJobStatus['log-entry-categories-count']) || - isJobStatusWithResults(logEntryRateJobStatus['log-entry-rate']) + isJobStatusWithResults(logEntryCategoriesJobStatus[logEntryCategoriesJobType]) || + isJobStatusWithResults(logEntryRateJobStatus[logEntryRateJobType]) ) { return ( <> - + ); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx index 46ce90cff63c..273874f83ae3 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_providers.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; +import { logEntryCategoriesJobType, logEntryRateJobType } from '../../../../common/log_analysis'; import { InlineLogViewSplashPage } from '../../../components/logging/inline_log_view_splash_page'; import { LogAnalysisSetupFlyoutStateProvider } from '../../../components/logging/log_analysis_setup/setup_flyout'; import { SourceLoadingPage } from '../../../components/source_loading_page'; @@ -15,6 +16,7 @@ import { LogEntryRateModuleProvider } from '../../../containers/logs/log_analysi import { LogEntryFlyoutProvider } from '../../../containers/logs/log_flyout'; import { useActiveKibanaSpace } from '../../../hooks/use_kibana_space'; import { ConnectedLogViewErrorPage } from '../shared/page_log_view_error'; +import { useLogMlJobIdFormatsShimContext } from '../shared/use_log_ml_job_id_formats_shim'; export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) => { const { @@ -29,6 +31,9 @@ export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) const { space } = useActiveKibanaSpace(); + const { idFormats, isLoadingLogAnalysisIdFormats, hasFailedLoadingLogAnalysisIdFormats } = + useLogMlJobIdFormatsShimContext(); + // This is a rather crude way of guarding the dependent providers against // arguments that are only made available asynchronously. Ideally, we'd use // React concurrent mode and Suspense in order to handle that more gracefully. @@ -36,9 +41,9 @@ export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) return null; } else if (!isPersistedLogView) { return ; - } else if (isLoading || isUninitialized) { + } else if (isLoading || isUninitialized || isLoadingLogAnalysisIdFormats || !idFormats) { return ; - } else if (hasFailedLoading) { + } else if (hasFailedLoading || hasFailedLoadingLogAnalysisIdFormats) { return ; } else if (resolvedLogView != null) { if (logViewReference.type === 'log-view-inline') { @@ -50,6 +55,7 @@ export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) indexPattern={resolvedLogView.indices} logViewId={logViewReference.logViewId} spaceId={space.id} + idFormat={idFormats[logEntryRateJobType]} timestampField={resolvedLogView.timestampField} runtimeMappings={resolvedLogView.runtimeMappings} > @@ -57,6 +63,7 @@ export const LogEntryRatePageProviders: React.FunctionComponent = ({ children }) indexPattern={resolvedLogView.indices} logViewId={logViewReference.logViewId} spaceId={space.id} + idFormat={idFormats[logEntryCategoriesJobType]} timestampField={resolvedLogView.timestampField} runtimeMappings={resolvedLogView.runtimeMappings} > diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx index a4d861e38ade..21eb5aacb2ce 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx @@ -15,7 +15,12 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { MLJobsAwaitingNodeWarning } from '@kbn/ml-plugin/public'; import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; import { useLogViewContext, LogEntryFlyout } from '@kbn/logs-shared-plugin/public'; -import { isJobStatusWithResults } from '../../../../common/log_analysis'; +import { IdFormatByJobType } from '../../../../common/http_api/latest'; +import { + isJobStatusWithResults, + logEntryCategoriesJobType, + logEntryRateJobType, +} from '../../../../common/log_analysis'; import { TimeKey } from '../../../../common/time'; import { CategoryJobNoticesSection, @@ -45,7 +50,8 @@ export const PAGINATION_DEFAULTS = { export const LogEntryRateResultsContent: React.FunctionComponent<{ pageTitle: string; -}> = ({ pageTitle }) => { + idFormats: IdFormatByJobType | null; +}> = ({ pageTitle, idFormats }) => { useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results' }); useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results', delay: 15000 }); @@ -82,11 +88,11 @@ export const LogEntryRateResultsContent: React.FunctionComponent<{ const jobIds = useMemo(() => { return [ - ...(isJobStatusWithResults(logEntryRateJobStatus['log-entry-rate']) - ? [logEntryRateJobIds['log-entry-rate']] + ...(isJobStatusWithResults(logEntryRateJobStatus[logEntryRateJobType]) + ? [logEntryRateJobIds[logEntryRateJobType]] : []), - ...(isJobStatusWithResults(logEntryCategoriesJobStatus['log-entry-categories-count']) - ? [logEntryCategoriesJobIds['log-entry-categories-count']] + ...(isJobStatusWithResults(logEntryCategoriesJobStatus[logEntryCategoriesJobType]) + ? [logEntryCategoriesJobIds[logEntryCategoriesJobType]] : []), ]; }, [ @@ -146,6 +152,7 @@ export const LogEntryRateResultsContent: React.FunctionComponent<{ isLoadingDatasets, } = useLogEntryAnomaliesResults({ logViewReference, + idFormats, startTime: timeRange.value.startTime, endTime: timeRange.value.endTime, defaultSortOptions: SORT_DEFAULTS, @@ -199,6 +206,7 @@ export const LogEntryRateResultsContent: React.FunctionComponent<{ return ( = ({ anomaly, timeRange }) => { const { logViewReference } = useLogViewContext(); + const { idFormats } = useLogMlJobIdFormatsShimContext(); if (logViewReference.type === 'log-view-inline') { throw new Error('Logs ML features only support persisted Log Views'); @@ -44,6 +50,7 @@ export const AnomaliesTableExpandedRow: React.FunctionComponent<{ endTime: anomaly.startTime + anomaly.duration, exampleCount: EXAMPLE_COUNT, logViewReference, + idFormat: idFormats?.[logEntryRateJobType], startTime: anomaly.startTime, categoryId: isCategoryAnomaly(anomaly) ? anomaly.categoryId : undefined, }); diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts index b6a515ae6f13..5f6ad4deda08 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormatByJobType } from '../../../../../common/http_api/latest'; import { getLogEntryAnomaliesRequestPayloadRT, getLogEntryAnomaliesSuccessReponsePayloadRT, @@ -17,6 +18,7 @@ import { AnomaliesSort, Pagination } from '../../../../../common/log_analysis'; interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormats: IdFormatByJobType; startTime: number; endTime: number; sort: AnomaliesSort; @@ -25,13 +27,15 @@ interface RequestArgs { } export const callGetLogEntryAnomaliesAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { - const { logViewReference, startTime, endTime, sort, pagination, datasets } = requestArgs; + const { logViewReference, idFormats, startTime, endTime, sort, pagination, datasets } = + requestArgs; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getLogEntryAnomaliesRequestPayloadRT.encode({ data: { logView: logViewReference, + idFormats, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts index a93712c5d5a8..38ed7144140a 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_anomalies_datasets.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormatByJobType } from '../../../../../common/http_api/latest'; import { decodeOrThrow } from '../../../../../common/runtime_types'; import { getLogEntryAnomaliesDatasetsRequestPayloadRT, @@ -16,6 +17,7 @@ import { interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormats: IdFormatByJobType; startTime: number; endTime: number; } @@ -24,13 +26,14 @@ export const callGetLogEntryAnomaliesDatasetsAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { logViewReference, startTime, endTime } = requestArgs; + const { logViewReference, idFormats, startTime, endTime } = requestArgs; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH, { method: 'POST', body: JSON.stringify( getLogEntryAnomaliesDatasetsRequestPayloadRT.encode({ data: { logView: logViewReference, + idFormats, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts index 6cf35b95868e..a4abfbd15ba5 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_examples.ts @@ -7,6 +7,7 @@ import type { HttpHandler } from '@kbn/core/public'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../../common/http_api/latest'; import { getLogEntryExamplesRequestPayloadRT, @@ -17,6 +18,7 @@ import { decodeOrThrow } from '../../../../../common/runtime_types'; interface RequestArgs { logViewReference: PersistedLogViewReference; + idFormat: IdFormat; startTime: number; endTime: number; dataset: string; @@ -25,7 +27,8 @@ interface RequestArgs { } export const callGetLogEntryExamplesAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { - const { logViewReference, startTime, endTime, dataset, exampleCount, categoryId } = requestArgs; + const { logViewReference, idFormat, startTime, endTime, dataset, exampleCount, categoryId } = + requestArgs; const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH, { method: 'POST', body: JSON.stringify( @@ -34,6 +37,7 @@ export const callGetLogEntryExamplesAPI = async (requestArgs: RequestArgs, fetch dataset, exampleCount, logView: logViewReference, + idFormat, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts index 745b5a7cd5ae..598f57751dae 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_anomalies_results.ts @@ -8,6 +8,7 @@ import { useMemo, useState, useCallback, useEffect, useReducer } from 'react'; import useMount from 'react-use/lib/useMount'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormatByJobType } from '../../../../common/http_api/latest'; import { useTrackedPromise, CanceledPromiseError } from '../../../utils/use_tracked_promise'; import { callGetLogEntryAnomaliesAPI } from './service_calls/get_log_entry_anomalies'; import { callGetLogEntryAnomaliesDatasetsAPI } from './service_calls/get_log_entry_anomalies_datasets'; @@ -139,6 +140,7 @@ export const useLogEntryAnomaliesResults = ({ endTime, startTime, logViewReference, + idFormats, defaultSortOptions, defaultPaginationOptions, onGetLogEntryAnomaliesDatasetsError, @@ -147,6 +149,7 @@ export const useLogEntryAnomaliesResults = ({ endTime: number; startTime: number; logViewReference: PersistedLogViewReference; + idFormats: IdFormatByJobType | null; defaultSortOptions: AnomaliesSort; defaultPaginationOptions: Pick; onGetLogEntryAnomaliesDatasetsError?: (error: Error) => void; @@ -175,6 +178,10 @@ export const useLogEntryAnomaliesResults = ({ { cancelPreviousOn: 'creation', createPromise: async () => { + if (!idFormats) { + throw new Error('idFormats is undefined'); + } + const { timeRange: { start: queryStartTime, end: queryEndTime }, sortOptions, @@ -185,6 +192,7 @@ export const useLogEntryAnomaliesResults = ({ return await callGetLogEntryAnomaliesAPI( { logViewReference, + idFormats, startTime: queryStartTime, endTime: queryEndTime, sort: sortOptions, @@ -218,6 +226,7 @@ export const useLogEntryAnomaliesResults = ({ }, [ logViewReference, + idFormats, dispatch, reducerState.timeRange, reducerState.sortOptions, @@ -294,8 +303,12 @@ export const useLogEntryAnomaliesResults = ({ { cancelPreviousOn: 'creation', createPromise: async () => { + if (!idFormats) { + throw new Error('idFormats is undefined'); + } + return await callGetLogEntryAnomaliesDatasetsAPI( - { logViewReference, startTime, endTime }, + { logViewReference, idFormats, startTime, endTime }, services.http.fetch ); }, @@ -312,7 +325,7 @@ export const useLogEntryAnomaliesResults = ({ } }, }, - [endTime, logViewReference, startTime] + [endTime, logViewReference, idFormats, startTime] ); const isLoadingDatasets = useMemo( diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts index 4301f08ab41d..58e7b15842a1 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_examples.ts @@ -8,6 +8,7 @@ import { useMemo, useState } from 'react'; import { PersistedLogViewReference } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../../common/http_api/latest'; import { LogEntryExample } from '../../../../common/log_analysis'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; @@ -18,6 +19,7 @@ export const useLogEntryExamples = ({ endTime, exampleCount, logViewReference, + idFormat, startTime, categoryId, }: { @@ -25,6 +27,7 @@ export const useLogEntryExamples = ({ endTime: number; exampleCount: number; logViewReference: PersistedLogViewReference; + idFormat?: IdFormat; startTime: number; categoryId?: string; }) => { @@ -35,9 +38,14 @@ export const useLogEntryExamples = ({ { cancelPreviousOn: 'creation', createPromise: async () => { + if (!idFormat) { + throw new Error('idFormat is undefined'); + } + return await callGetLogEntryExamplesAPI( { logViewReference, + idFormat, startTime, endTime, dataset, @@ -51,7 +59,7 @@ export const useLogEntryExamples = ({ setLogEntryExamples(examples); }, }, - [dataset, endTime, exampleCount, logViewReference, startTime] + [dataset, endTime, exampleCount, logViewReference, startTime, idFormat] ); const isLoadingLogEntryExamples = useMemo( diff --git a/x-pack/plugins/infra/public/pages/logs/shared/call_get_log_analysis_id_formats.ts b/x-pack/plugins/infra/public/pages/logs/shared/call_get_log_analysis_id_formats.ts new file mode 100644 index 000000000000..7099e9fe9a76 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/shared/call_get_log_analysis_id_formats.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HttpHandler } from '@kbn/core/public'; +import { decodeOrThrow } from '../../../../common/runtime_types'; +import { + getLogAnalysisIdFormatsRequestPayloadRT, + getLogAnalysisIdFormatsSuccessResponsePayloadRT, + LOG_ANALYSIS_GET_ID_FORMATS, +} from '../../../../common/http_api/latest'; + +interface RequestArgs { + spaceId: string; + logViewId: string; +} + +export const callGetLogAnalysisIdFormats = async (requestArgs: RequestArgs, fetch: HttpHandler) => { + const { logViewId, spaceId } = requestArgs; + const response = await fetch(LOG_ANALYSIS_GET_ID_FORMATS, { + method: 'POST', + body: JSON.stringify( + getLogAnalysisIdFormatsRequestPayloadRT.encode({ + data: { + logViewId, + spaceId, + }, + }) + ), + version: '1', + }); + + return decodeOrThrow(getLogAnalysisIdFormatsSuccessResponsePayloadRT)(response); +}; diff --git a/x-pack/plugins/infra/public/pages/logs/shared/use_log_ml_job_id_formats_shim.tsx b/x-pack/plugins/infra/public/pages/logs/shared/use_log_ml_job_id_formats_shim.tsx new file mode 100644 index 000000000000..ffa63908b8b5 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/shared/use_log_ml_job_id_formats_shim.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import createContainer from 'constate'; +import { useState, useEffect, useCallback } from 'react'; +import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; +import { IdFormatByJobType, JobType } from '../../../../common/http_api/latest'; +import { useActiveKibanaSpace } from '../../../hooks/use_kibana_space'; +import { useTrackedPromise } from '../../../utils/use_tracked_promise'; + +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; +import { callGetLogAnalysisIdFormats } from './call_get_log_analysis_id_formats'; + +const useLogMlJobIdFormatsShim = () => { + const [idFormats, setIdFormats] = useState(null); + + const { logViewReference } = useLogViewContext(); + const { space } = useActiveKibanaSpace(); + const { services } = useKibanaContextForPlugin(); + + const [getLogAnalysisIdFormatsRequest, getLogAnalysisIdFormats] = useTrackedPromise( + { + cancelPreviousOn: 'creation', + createPromise: async () => { + if (!space) { + return { data: null }; + } + + if (logViewReference.type === 'log-view-inline') { + throw new Error('Logs ML features only support persisted Log Views'); + } + + return await callGetLogAnalysisIdFormats( + { + logViewId: logViewReference.logViewId, + spaceId: space.id, + }, + services.http.fetch + ); + }, + onResolve: ({ data }) => { + setIdFormats(data); + }, + }, + [logViewReference, space] + ); + + useEffect(() => { + getLogAnalysisIdFormats(); + }, [getLogAnalysisIdFormats]); + + const isLoadingLogAnalysisIdFormats = getLogAnalysisIdFormatsRequest.state === 'pending'; + const hasFailedLoadingLogAnalysisIdFormats = getLogAnalysisIdFormatsRequest.state === 'rejected'; + + const migrateIdFormat = useCallback((jobType: JobType) => { + setIdFormats((previousValue) => { + if (!previousValue) { + return null; + } + + return { + ...previousValue, + [jobType]: 'hashed', + }; + }); + }, []); + + return { + idFormats, + migrateIdFormat, + isLoadingLogAnalysisIdFormats, + hasFailedLoadingLogAnalysisIdFormats, + }; +}; + +export const [LogMlJobIdFormatsShimProvider, useLogMlJobIdFormatsShimContext] = + createContainer(useLogMlJobIdFormatsShim); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_content.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_content.tsx index 7dea5303aad2..5496dcf64cd5 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_content.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_content.tsx @@ -15,6 +15,7 @@ import { HostsViewProvider } from '../hooks/use_hosts_view'; import { HostsTableProvider } from '../hooks/use_hosts_table'; import { ErrorCallout } from './error_callout'; import { useUnifiedSearchContext } from '../hooks/use_unified_search'; +import { HostCountProvider } from '../hooks/use_host_count'; export const HostsContent = () => { const { error } = useUnifiedSearchContext(); @@ -28,7 +29,9 @@ export const HostsContent = () => { - + + + diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/host_count_kpi.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/host_count_kpi.tsx index 22f07d829906..8d4794aaa6c4 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/host_count_kpi.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/host_count_kpi.tsx @@ -6,24 +6,30 @@ */ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { hostLensFormulas, METRICS_TOOLTIP } from '../../../../../common/visualizations'; +import { useTheme } from '@kbn/observability-shared-plugin/public'; +import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; +import useAsync from 'react-use/lib/useAsync'; +import { METRICS_TOOLTIP } from '../../../../../common/visualizations'; import { useHostCountContext } from '../../hooks/use_host_count'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; - import { type Props, MetricChartWrapper } from '../chart/metric_chart_wrapper'; import { TooltipContent } from '../../../../../components/lens'; -const HOSTS_CHART: Omit = { - id: 'hostsViewKPI-hostsCount', - color: '#6DCCB1', - title: i18n.translate('xpack.infra.hostsViewPage.kpi.hostCount.title', { - defaultMessage: 'Hosts', - }), -}; - export const HostCountKpi = ({ height }: { height: number }) => { + const inventoryModel = findInventoryModel('host'); const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); const { searchCriteria } = useUnifiedSearchContext(); + const euiTheme = useTheme(); + + const { value: formulas } = useAsync(() => inventoryModel.metrics.getFormulas()); + + const hostsCountChart: Omit = { + id: 'hostsViewKPI-hostsCount', + color: euiTheme.eui.euiColorLightestShade, + title: i18n.translate('xpack.infra.hostsViewPage.kpi.hostCount.title', { + defaultMessage: 'Hosts', + }), + }; const getSubtitle = () => { return searchCriteria.limit < (hostCountData?.count.value ?? 0) @@ -38,13 +44,13 @@ export const HostCountKpi = ({ height }: { height: number }) => { return ( } diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx index d57f28b6b71e..e14d72ac7207 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx @@ -5,21 +5,25 @@ * 2.0. */ import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; +import { ChartModel } from '@kbn/lens-embeddable-utils'; +import { METRICS_TOOLTIP } from '../../../../../common/visualizations'; import { LensChart, TooltipContent } from '../../../../../components/lens'; -import { type KPIChartProps, AVERAGE_SUBTITLE } from '../../../../../common/visualizations'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { useMetricsDataViewContext } from '../../hooks/use_data_view'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; import { useHostsViewContext } from '../../hooks/use_hosts_view'; import { useHostCountContext } from '../../hooks/use_host_count'; import { useAfterLoadedState } from '../../hooks/use_after_loaded_state'; -export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { height: number }) => { +export const Kpi = ({ + id, + height, + visualizationType = 'lnsMetric', + dataView, + ...chartProps +}: ChartModel & { height: number }) => { const { searchCriteria } = useUnifiedSearchContext(); - const { dataView } = useMetricsDataViewContext(); const { hostNodes, loading: hostsLoading, searchSessionId } = useHostsViewContext(); - const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); + const { isRequestRunning: hostCountLoading } = useHostCountContext(); const shouldUseSearchCriteria = hostNodes.length === 0; const loading = hostsLoading || hostCountLoading; @@ -34,16 +38,6 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he }), ]; - const subtitle = - searchCriteria.limit < (hostCountData?.count.value ?? 0) - ? i18n.translate('xpack.infra.hostsViewPage.kpi.subtitle.average.limit', { - defaultMessage: 'Average (of {limit} hosts)', - values: { - limit: searchCriteria.limit, - }, - }) - : AVERAGE_SUBTITLE; - // prevents requestTs and searchCriteria state from reloading the chart // we want it to reload only once the table has finished loading. // attributes passed to useAfterLoadedState don't need to be memoized @@ -52,26 +46,29 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he query: shouldUseSearchCriteria ? searchCriteria.query : undefined, filters, searchSessionId, - subtitle, }); - const tooltipComponent = useMemo(() => , [toolTip]); + const tooltipContent = useMemo( + () => + id in METRICS_TOOLTIP ? ( + + ) : undefined, + [id] + ); return ( diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi_grid.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi_grid.tsx index d9c7a59eb942..055793f6b53c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi_grid.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi_grid.tsx @@ -4,31 +4,68 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; - +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; +import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; +import { useEuiTheme } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import useAsync from 'react-use/lib/useAsync'; +import { KPI_CHART_HEIGHT } from '../../../../../common/visualizations'; import { HostMetricsDocsLink } from '../../../../../components/lens'; import { Kpi } from './kpi'; -import { HostCountProvider } from '../../hooks/use_host_count'; +import { useHostCountContext } from '../../hooks/use_host_count'; import { HostCountKpi } from './host_count_kpi'; -import { assetDetailsDashboards, KPI_CHART_HEIGHT } from '../../../../../common/visualizations'; +import { useMetricsDataViewContext } from '../../hooks/use_data_view'; +import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; export const KPIGrid = () => { + const model = findInventoryModel('host'); + const { searchCriteria } = useUnifiedSearchContext(); + const { euiTheme } = useEuiTheme(); + const { dataView } = useMetricsDataViewContext(); + const { data: hostCountData } = useHostCountContext(); + + const { value: dashboards } = useAsync(() => { + return model.metrics.getDashboards(); + }); + + const subtitle = + searchCriteria.limit < (hostCountData?.count.value ?? 0) + ? i18n.translate('xpack.infra.hostsViewPage.kpi.subtitle.average.limit', { + defaultMessage: 'Average (of {limit} hosts)', + values: { + limit: searchCriteria.limit, + }, + }) + : undefined; + + const charts = useMemo( + () => + dashboards?.kpi.get({ + metricsDataView: dataView, + options: { + backgroundColor: euiTheme.colors.lightestShade, + ...(subtitle ? { subtitle } : {}), + }, + }).charts ?? [], + [dashboards?.kpi, dataView, euiTheme.colors.lightestShade, subtitle] + ); + return ( - + <> - {assetDetailsDashboards.host.hostKPICharts.map((chartProp, index) => ( + {charts.map((chartProp, index) => ( ))} - + ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/table/entry_title.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/table/entry_title.tsx index b2fdcc1a1a73..0f6e65ef4c1d 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/table/entry_title.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/table/entry_title.tsx @@ -5,19 +5,13 @@ * 2.0. */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiToolTip, IconType } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiToolTip } from '@elastic/eui'; import { useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { CloudProviderIcon } from '@kbn/custom-icons'; import { useNodeDetailsRedirect } from '../../../../link_to'; -import type { CloudProvider, HostNodeRow } from '../../hooks/use_hosts_table'; +import type { HostNodeRow } from '../../hooks/use_hosts_table'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; -const cloudIcons: Record = { - gcp: 'logoGCP', - aws: 'logoAWS', - azure: 'logoAzure', - unknownProvider: 'cloudSunny', -}; - interface EntryTitleProps { onClick: () => void; title: HostNodeRow['title']; @@ -40,7 +34,6 @@ export const EntryTitle = ({ onClick, title }: EntryTitleProps) => { }), }); - const iconType = (cloudProvider && cloudIcons[cloudProvider]) || cloudIcons.unknownProvider; const providerName = cloudProvider ?? 'Unknown'; return ( @@ -52,7 +45,7 @@ export const EntryTitle = ({ onClick, title }: EntryTitleProps) => { > - + diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx index d7af2f06d4b0..1d82f0d76da2 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx @@ -5,24 +5,21 @@ * 2.0. */ import React, { useMemo } from 'react'; -import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; -import type { AssetXYChartProps } from '../../../../../../common/visualizations'; +import type { ChartModel, XYVisualOptions } from '@kbn/lens-embeddable-utils'; +import { METRIC_CHART_HEIGHT } from '../../../../../../common/visualizations/constants'; import { LensChart } from '../../../../../../components/lens'; -import { useMetricsDataViewContext } from '../../../hooks/use_data_view'; import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; import { useHostsViewContext } from '../../../hooks/use_hosts_view'; import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build'; import { useHostsTableContext } from '../../../hooks/use_hosts_table'; import { useAfterLoadedState } from '../../../hooks/use_after_loaded_state'; -import { METRIC_CHART_HEIGHT } from '../../../constants'; -export interface ChartProps extends AssetXYChartProps { +export interface ChartProps extends Omit { visualOptions?: XYVisualOptions; } -export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProps) => { +export const Chart = ({ dataView, ...chartProps }: ChartProps) => { const { searchCriteria } = useUnifiedSearchContext(); - const { dataView } = useMetricsDataViewContext(); const { loading, searchSessionId } = useHostsViewContext(); const { currentPage } = useHostsTableContext(); @@ -51,20 +48,16 @@ export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProp return ( ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx index d9310ae0d816..37424447d9d7 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx @@ -4,22 +4,38 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { EuiFlexGrid, EuiFlexItem, EuiText, EuiFlexGroup, EuiSpacer } from '@elastic/eui'; -import { - hostsViewDashboards, - XY_MISSING_VALUE_DOTTED_LINE_CONFIG, -} from '../../../../../../common/visualizations'; +import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; +import useAsync from 'react-use/lib/useAsync'; import { HostMetricsExplanationContent } from '../../../../../../components/lens'; import { Chart } from './chart'; import { Popover } from '../../table/popover'; +import { useMetricsDataViewContext } from '../../../hooks/use_data_view'; export const MetricsGrid = () => { + const model = findInventoryModel('host'); + const { dataView } = useMetricsDataViewContext(); + + const { value: dashboards } = useAsync(() => { + return model.metrics.getDashboards(); + }); + + const charts = useMemo( + () => dashboards?.hostsView.get({ metricsDataView: dataView }).charts ?? [], + [dataView, dashboards] + ); + return ( <> - Learn more about metrics + + {i18n.translate('xpack.infra.metricsGrid.learnMoreAboutMetricsTextLabel', { + defaultMessage: 'Learn more about metrics', + })} + @@ -30,9 +46,9 @@ export const MetricsGrid = () => { - {hostsViewDashboards.hostsMetricCharts.map((chartProp, index) => ( + {charts.map((chartProp, index) => ( - + ))} diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts index 997ae6fd5ed6..cba547f072a6 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/constants.ts @@ -12,7 +12,5 @@ export const DEFAULT_PAGE_SIZE = 10; export const LOCAL_STORAGE_HOST_LIMIT_KEY = 'hostsView:hostLimitSelection'; export const LOCAL_STORAGE_PAGE_SIZE_KEY = 'hostsView:pageSizeSelection'; -export const METRIC_CHART_HEIGHT = 300; - export const HOST_LIMIT_OPTIONS = [50, 100, 500] as const; export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics'; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx index 290062a2f1d4..23aee3a6c1e3 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx @@ -13,9 +13,11 @@ import { type EuiBasicTable, } from '@elastic/eui'; import createContainer from 'constate'; +import useAsync from 'react-use/lib/useAsync'; import { isEqual } from 'lodash'; import { isNumber } from 'lodash/fp'; -import { hostLensFormulas } from '../../../../common/visualizations'; +import { CloudProvider } from '@kbn/custom-icons'; +import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { createInventoryMetricFormatter } from '../../inventory_view/lib/create_inventory_metric_formatter'; import { EntryTitle } from '../components/table/entry_title'; @@ -35,7 +37,6 @@ import { buildCombinedHostsFilter } from '../../../../utils/filters/build'; /** * Columns and items types */ -export type CloudProvider = 'gcp' | 'aws' | 'azure' | 'unknownProvider'; type HostMetrics = Record; interface HostMetadata { @@ -124,9 +125,12 @@ const sortTableData = * Build a table columns and items starting from the snapshot nodes. */ export const useHostsTable = () => { + const inventoryModel = findInventoryModel('host'); const [selectedItems, setSelectedItems] = useState([]); const { hostNodes } = useHostsViewContext(); + const { value: formulas } = useAsync(() => inventoryModel.metrics.getFormulas()); + const [{ detailsItemId, pagination, sorting }, setProperties] = useHostsTableUrlState(); const { services: { @@ -241,7 +245,7 @@ export const useHostsTable = () => { ), field: 'cpu', @@ -255,7 +259,7 @@ export const useHostsTable = () => { ), field: 'normalizedLoad1m', @@ -269,7 +273,7 @@ export const useHostsTable = () => { ), field: 'memory', @@ -283,7 +287,7 @@ export const useHostsTable = () => { ), field: 'memoryFree', @@ -296,8 +300,8 @@ export const useHostsTable = () => { name: ( ), field: 'diskSpaceUsage', @@ -311,7 +315,7 @@ export const useHostsTable = () => { ), field: 'rx', @@ -326,7 +330,7 @@ export const useHostsTable = () => { ), field: 'tx', @@ -337,7 +341,18 @@ export const useHostsTable = () => { width: '120px', }, ], - [detailsItemId, reportHostEntryClick, setProperties] + [ + detailsItemId, + formulas?.cpuUsage.value, + formulas?.diskUsage.value, + formulas?.memoryFree.value, + formulas?.memoryUsage.value, + formulas?.normalizedLoad1m.value, + formulas?.rx.value, + formulas?.tx.value, + reportHostEntryClick, + setProperties, + ] ); const selection: EuiTableSelectionType = { diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts index 7f10c7aa4aa7..36433a2bca01 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts @@ -19,6 +19,7 @@ export const getFilteredMetrics = ( .map((data) => data && data.name); return requiredMetrics.filter((metric) => { const metricModelCreator = metrics.tsvb[metric]; + // We just need to get a dummy version of the model so we can filter // using the `requires` attribute. const metricModel = metricModelCreator(TIMESTAMP_FIELD, 'test', '>=1m'); diff --git a/x-pack/plugins/infra/server/infra_server.ts b/x-pack/plugins/infra/server/infra_server.ts index 6ab8781bdfc4..b041f495057a 100644 --- a/x-pack/plugins/infra/server/infra_server.ts +++ b/x-pack/plugins/infra/server/infra_server.ts @@ -21,6 +21,7 @@ import { initGetLogEntryExamplesRoute, initValidateLogAnalysisDatasetsRoute, initValidateLogAnalysisIndicesRoute, + initGetLogAnalysisIdFormatsRoute, } from './routes/log_analysis'; import { initMetadataRoute } from './routes/metadata'; import { initMetricsAPIRoute } from './routes/metrics_api'; @@ -31,6 +32,7 @@ import { initProcessListRoute } from './routes/process_list'; import { initSnapshotRoute } from './routes/snapshot'; import { initInfraMetricsRoute } from './routes/infra'; import { initMetricsExplorerViewRoutes } from './routes/metrics_explorer_views'; +import { initProfilingRoutes } from './routes/profiling'; export const initInfraServer = (libs: InfraBackendLibs) => { initIpToHostName(libs); @@ -45,6 +47,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initSnapshotRoute(libs); initNodeDetailsRoute(libs); initMetricsSourceConfigurationRoutes(libs); + initGetLogAnalysisIdFormatsRoute(libs); initValidateLogAnalysisDatasetsRoute(libs); initValidateLogAnalysisIndicesRoute(libs); initGetLogEntryExamplesRoute(libs); @@ -57,4 +60,5 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initProcessListRoute(libs); initOverviewRoute(libs); initInfraMetricsRoute(libs); + initProfilingRoutes(libs); }; 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 986a6a874951..a6bba3babfa8 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 @@ -27,6 +27,10 @@ import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { LogsSharedPluginSetup, LogsSharedPluginStart } from '@kbn/logs-shared-plugin/server'; import { VersionedRouteConfig } from '@kbn/core-http-server'; import { MetricsDataPluginSetup } from '@kbn/metrics-data-access-plugin/server'; +import { + ProfilingDataAccessPluginSetup, + ProfilingDataAccessPluginStart, +} from '@kbn/profiling-data-access-plugin/server'; export interface InfraServerPluginSetupDeps { alerting: AlertingPluginContract; @@ -42,12 +46,14 @@ export interface InfraServerPluginSetupDeps { ml?: MlPluginSetup; logsShared: LogsSharedPluginSetup; metricsDataAccess: MetricsDataPluginSetup; + profilingDataAccess?: ProfilingDataAccessPluginSetup; } export interface InfraServerPluginStartDeps { data: DataPluginStart; dataViews: DataViewsPluginStart; logsShared: LogsSharedPluginStart; + profilingDataAccess?: ProfilingDataAccessPluginStart; } export interface CallWithRequestParams extends estypes.RequestBase { diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_condition_script.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_condition_script.ts index 37a39d215edd..a62f5d92dac0 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_condition_script.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_condition_script.ts @@ -25,7 +25,8 @@ export const createConditionScript = ( } if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) { return { - source: `params.value < params.threshold0 && params.value > params.threshold1 ? 1 : 0`, + // OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0 + source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`, params: { threshold0: threshold[0], threshold1: threshold[1], diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/create_condition_script.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/create_condition_script.ts index b4285863dbcc..1320607685a8 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/create_condition_script.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/create_condition_script.ts @@ -18,7 +18,8 @@ export const createConditionScript = (threshold: number[], comparator: Comparato } if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) { return { - source: `params.value < params.threshold0 && params.value > params.threshold1 ? 1 : 0`, + // OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0 + source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`, params: { threshold0: threshold[0], threshold1: threshold[1], diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 81974728acc5..2c88148bc2fa 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -2272,6 +2272,7 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ metricThresholdAlertRuleEnabled: true, logThresholdAlertRuleEnabled: true, alertsAndRulesDropdownEnabled: true, + profilingEnabled: false, }, enabled: true, sources, diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts index 591376450be3..41152d17572a 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts @@ -7,13 +7,16 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { PersistedLogViewReference, ResolvedLogView } from '@kbn/logs-shared-plugin/common'; +import { IdFormat, IdFormatByJobType } from '../../../common/http_api/latest'; import { AnomaliesSort, getJobId, isCategoryAnomaly, jobCustomSettingsRT, LogEntryAnomalyDatasets, + logEntryCategoriesJobType, logEntryCategoriesJobTypes, + logEntryRateJobType, logEntryRateJobTypes, Pagination, } from '../../../common/log_analysis'; @@ -55,10 +58,21 @@ interface MappedAnomalyHit { async function getCompatibleAnomaliesJobIds( spaceId: string, logViewId: string, + idFormats: IdFormatByJobType, mlAnomalyDetectors: MlAnomalyDetectors ) { - const logRateJobId = getJobId(spaceId, logViewId, logEntryRateJobTypes[0]); - const logCategoriesJobId = getJobId(spaceId, logViewId, logEntryCategoriesJobTypes[0]); + const logRateJobId = getJobId( + spaceId, + logViewId, + idFormats[logEntryRateJobType], + logEntryRateJobType + ); + const logCategoriesJobId = getJobId( + spaceId, + logViewId, + idFormats[logEntryCategoriesJobType], + logEntryCategoriesJobType + ); const jobIds: string[] = []; let jobSpans: TracingSpan[] = []; @@ -100,6 +114,7 @@ export async function getLogEntryAnomalies( infra: Promise>; }, logView: PersistedLogViewReference, + idFormats: IdFormatByJobType, startTime: number, endTime: number, sort: AnomaliesSort, @@ -115,6 +130,7 @@ export async function getLogEntryAnomalies( } = await getCompatibleAnomaliesJobIds( infraContext.spaceId, logView.logViewId, + idFormats, infraContext.mlAnomalyDetectors ); @@ -156,7 +172,8 @@ export async function getLogEntryAnomalies( const logEntryCategoriesCountJobId = getJobId( infraContext.spaceId, logView.logViewId, - logEntryCategoriesJobTypes[0] + idFormats[logEntryCategoriesJobType], + logEntryCategoriesJobType ); const { logEntryCategoriesById } = await fetchLogEntryCategories( @@ -332,6 +349,7 @@ export async function getLogEntryExamples( infra: Promise>; }, logView: PersistedLogViewReference, + idFormat: IdFormat, startTime: number, endTime: number, dataset: string, @@ -346,6 +364,7 @@ export async function getLogEntryExamples( const jobId = getJobId( infraContext.spaceId, logView.logViewId, + idFormat, categoryId != null ? logEntryCategoriesJobTypes[0] : logEntryRateJobTypes[0] ); @@ -371,6 +390,7 @@ export async function getLogEntryExamples( } = await fetchLogEntryExamples( context, logView, + idFormat, indices, runtimeMappings, timestampField, @@ -398,6 +418,7 @@ export async function fetchLogEntryExamples( infra: Promise>; }, logView: PersistedLogViewReference, + idFormat: IdFormat, indices: string, runtimeMappings: estypes.MappingRuntimeFields, timestampField: string, @@ -421,6 +442,7 @@ export async function fetchLogEntryExamples( const logEntryCategoriesCountJobId = getJobId( infraContext.spaceId, logView.logViewId, + idFormat, logEntryCategoriesJobTypes[0] ); @@ -484,6 +506,7 @@ export async function getLogEntryAnomaliesDatasets( }; }, logView: PersistedLogViewReference, + idFormats: IdFormatByJobType, startTime: number, endTime: number ) { @@ -493,6 +516,7 @@ export async function getLogEntryAnomaliesDatasets( } = await getCompatibleAnomaliesJobIds( context.infra.spaceId, logView.logViewId, + idFormats, context.infra.mlAnomalyDetectors ); diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts index 88678f4c79c5..b9e908bf49ee 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_categories_analysis.ts @@ -12,6 +12,7 @@ import { PersistedLogViewReference, ResolvedLogView, } from '@kbn/logs-shared-plugin/common'; +import { IdFormat } from '../../../common/http_api/latest'; import { CategoriesSort, compareDatasetsByMaximumAnomalyScore, @@ -51,6 +52,7 @@ export async function getTopLogEntryCategories( }; }, logView: PersistedLogViewReference, + idFormat: IdFormat, startTime: number, endTime: number, categoryCount: number, @@ -63,6 +65,7 @@ export async function getTopLogEntryCategories( const logEntryCategoriesCountJobId = getJobId( context.infra.spaceId, logView.logViewId, + idFormat, logEntryCategoriesJobTypes[0] ); @@ -123,12 +126,14 @@ export async function getLogEntryCategoryDatasets( }; }, logView: PersistedLogViewReference, + idFormat: IdFormat, startTime: number, endTime: number ) { const logEntryCategoriesCountJobId = getJobId( context.infra.spaceId, logView.logViewId, + idFormat, logEntryCategoriesJobTypes[0] ); @@ -147,6 +152,7 @@ export async function getLogEntryCategoryExamples( }; }, logView: PersistedLogViewReference, + idFormat: IdFormat, startTime: number, endTime: number, categoryId: number, @@ -158,6 +164,7 @@ export async function getLogEntryCategoryExamples( const logEntryCategoriesCountJobId = getJobId( context.infra.spaceId, logView.logViewId, + idFormat, logEntryCategoriesJobTypes[0] ); diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_rate_analysis.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_rate_analysis.ts index 1e043fed0986..5231fb5dc14e 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_rate_analysis.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_rate_analysis.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { IdFormat } from '../../../common/http_api/latest'; import { decodeOrThrow } from '../../../common/runtime_types'; import { logRateModelPlotResponseRT, @@ -12,7 +13,7 @@ import { LogRateModelPlotBucket, CompositeTimestampPartitionKey, } from './queries'; -import { getJobId } from '../../../common/log_analysis'; +import { getJobId, logEntryRateJobType } from '../../../common/log_analysis'; import type { MlSystem } from '../../types'; const COMPOSITE_AGGREGATION_BATCH_SIZE = 1000; @@ -25,12 +26,13 @@ export async function getLogEntryRateBuckets( }; }, logViewId: string, + idFormat: IdFormat, startTime: number, endTime: number, bucketDuration: number, datasets?: string[] ) { - const logRateJobId = getJobId(context.infra.spaceId, logViewId, 'log-entry-rate'); + const logRateJobId = getJobId(context.infra.spaceId, logViewId, idFormat, logEntryRateJobType); let mlModelPlotBuckets: LogRateModelPlotBucket[] = []; let afterLatestBatchKey: CompositeTimestampPartitionKey | undefined; diff --git a/x-pack/plugins/infra/server/lib/log_analysis/resolve_id_formats.ts b/x-pack/plugins/infra/server/lib/log_analysis/resolve_id_formats.ts new file mode 100644 index 000000000000..48f3b3e2fdc5 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/log_analysis/resolve_id_formats.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MlAnomalyDetectors } from '@kbn/ml-plugin/server'; +import { IdFormat, IdFormatByJobType, JobType } from '../../../common/http_api/latest'; +import { + getJobId, + logEntryCategoriesJobType, + logEntryRateJobType, +} from '../../../common/log_analysis'; + +export async function resolveIdFormats( + spaceId: string, + logViewId: string, + mlAnomalyDetectors: MlAnomalyDetectors +): Promise { + const entryRateFormat = await resolveIdFormat( + spaceId, + logViewId, + logEntryRateJobType, + mlAnomalyDetectors + ); + const entryCategoriesCountFormat = await resolveIdFormat( + spaceId, + logViewId, + logEntryCategoriesJobType, + mlAnomalyDetectors + ); + + return { + [logEntryRateJobType]: entryRateFormat, + [logEntryCategoriesJobType]: entryCategoriesCountFormat, + }; +} + +async function resolveIdFormat( + spaceId: string, + logViewId: string, + jobType: JobType, + mlAnomalyDetectors: MlAnomalyDetectors +): Promise { + try { + const hashedJobId = getJobId(spaceId, logViewId, 'hashed', jobType); + const hashedJobs = await mlAnomalyDetectors.jobs(hashedJobId); + if (hashedJobs.count > 0) { + return 'hashed'; + } + } catch (e) { + // Ignore 404 in case the job isn't found + if (e.statusCode !== 404) { + throw e; + } + } + + try { + const legacyJobId = getJobId(spaceId, logViewId, 'legacy', jobType); + const legacyJobs = await mlAnomalyDetectors.jobs(legacyJobId); + if (legacyJobs.count > 0) { + return 'legacy'; + } + } catch (e) { + // Ignore 404 in case the job isn't found + if (e.statusCode !== 404) { + throw e; + } + } + + return 'hashed'; +} diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index 27f232eed3c9..ef58e5a98577 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -101,6 +101,7 @@ const createMockStaticConfiguration = (): InfraConfig => ({ metricThresholdAlertRuleEnabled: true, logThresholdAlertRuleEnabled: true, alertsAndRulesDropdownEnabled: true, + profilingEnabled: false, }, enabled: true, }); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index afcbe69c01f5..63bb40f66c32 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -112,6 +112,15 @@ export const config: PluginConfigDescriptor = { traditional: schema.boolean({ defaultValue: true }), serverless: schema.boolean({ defaultValue: true }), }), + /** + * This flag depends on profilingDataAccess optional plugin, + * make sure to enable it with `xpack.profiling.enabled: true` + * before enabling this flag. + */ + profilingEnabled: offeringBasedSchema({ + traditional: schema.boolean({ defaultValue: false }), + serverless: schema.boolean({ defaultValue: false }), + }), }), }), exposeToBrowser: publicConfigKeys, diff --git a/x-pack/plugins/infra/server/routes/log_analysis/id_formats.ts b/x-pack/plugins/infra/server/routes/log_analysis/id_formats.ts new file mode 100644 index 000000000000..800d43df448d --- /dev/null +++ b/x-pack/plugins/infra/server/routes/log_analysis/id_formats.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import Boom from '@hapi/boom'; +import { createValidationFunction } from '@kbn/logs-shared-plugin/common/runtime_types'; +import { + LOG_ANALYSIS_GET_ID_FORMATS, + getLogAnalysisIdFormatsRequestPayloadRT, + getLogAnalysisIdFormatsSuccessResponsePayloadRT, +} from '../../../common/http_api/latest'; +import { InfraBackendLibs } from '../../lib/infra_types'; +import { isMlPrivilegesError } from '../../lib/log_analysis'; +import { resolveIdFormats } from '../../lib/log_analysis/resolve_id_formats'; +import { assertHasInfraMlPlugins } from '../../utils/request_context'; + +export const initGetLogAnalysisIdFormatsRoute = ({ framework }: InfraBackendLibs) => { + framework + .registerVersionedRoute({ + access: 'internal', + method: 'post', + path: LOG_ANALYSIS_GET_ID_FORMATS, + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: createValidationFunction(getLogAnalysisIdFormatsRequestPayloadRT), + }, + }, + }, + framework.router.handleLegacyErrors(async (requestContext, request, response) => { + const { + data: { logViewId, spaceId }, + } = request.body; + + try { + const infraMlContext = await assertHasInfraMlPlugins(requestContext); + const mlAnomalyDetectors = (await infraMlContext.infra).mlAnomalyDetectors; + + const idFormatByJobType = await resolveIdFormats(logViewId, spaceId, mlAnomalyDetectors); + + return response.ok({ + body: getLogAnalysisIdFormatsSuccessResponsePayloadRT.encode({ + data: idFormatByJobType, + }), + }); + } catch (error) { + if (Boom.isBoom(error)) { + throw error; + } + + if (isMlPrivilegesError(error)) { + return response.customError({ + statusCode: 403, + body: { + message: error.message, + }, + }); + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + }) + ); +}; diff --git a/x-pack/plugins/infra/server/routes/log_analysis/index.ts b/x-pack/plugins/infra/server/routes/log_analysis/index.ts index a642cd830b6f..a3266adfd6dd 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/index.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/index.ts @@ -7,3 +7,4 @@ export * from './results'; export * from './validation'; +export { initGetLogAnalysisIdFormatsRoute } from './id_formats'; diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies.ts index 30a9aadda432..1af2b1e7f980 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies.ts @@ -40,6 +40,7 @@ export const initGetLogEntryAnomaliesRoute = ({ framework }: InfraBackendLibs) = const { data: { logView, + idFormats, timeRange: { startTime, endTime }, sort: sortParam, pagination: paginationParam, @@ -60,6 +61,7 @@ export const initGetLogEntryAnomaliesRoute = ({ framework }: InfraBackendLibs) = } = await getLogEntryAnomalies( infraMlContext, logView, + idFormats, startTime, endTime, sort, diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies_datasets.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies_datasets.ts index ce10ba09a059..0b6444c1a9d7 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies_datasets.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_anomalies_datasets.ts @@ -39,6 +39,7 @@ export const initGetLogEntryAnomaliesDatasetsRoute = ({ framework }: InfraBacken const { data: { logView, + idFormats, timeRange: { startTime, endTime }, }, } = request.body; @@ -49,6 +50,7 @@ export const initGetLogEntryAnomaliesDatasetsRoute = ({ framework }: InfraBacken const { datasets, timing } = await getLogEntryAnomaliesDatasets( { infra: await infraMlContext.infra }, logView, + idFormats, startTime, endTime ); diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_categories.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_categories.ts index f51f81a846bb..92221d5ce359 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_categories.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_categories.ts @@ -41,6 +41,7 @@ export const initGetLogEntryCategoriesRoute = ({ framework }: InfraBackendLibs) categoryCount, histograms, logView, + idFormat, timeRange: { startTime, endTime }, datasets, sort, @@ -53,6 +54,7 @@ export const initGetLogEntryCategoriesRoute = ({ framework }: InfraBackendLibs) const { data: topLogEntryCategories, timing } = await getTopLogEntryCategories( { infra: await infraMlContext.infra }, logView, + idFormat, startTime, endTime, categoryCount, diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_datasets.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_datasets.ts index 9ed89f1adb05..1c62b67091a5 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_datasets.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_datasets.ts @@ -39,6 +39,7 @@ export const initGetLogEntryCategoryDatasetsRoute = ({ framework }: InfraBackend const { data: { logView, + idFormat, timeRange: { startTime, endTime }, }, } = request.body; @@ -49,6 +50,7 @@ export const initGetLogEntryCategoryDatasetsRoute = ({ framework }: InfraBackend const { data: logEntryCategoryDatasets, timing } = await getLogEntryCategoryDatasets( { infra: await infraMlContext.infra }, logView, + idFormat, startTime, endTime ); diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts index 828912143d41..c80aed6eab0f 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_category_examples.ts @@ -44,6 +44,7 @@ export const initGetLogEntryCategoryExamplesRoute = ({ categoryId, exampleCount, logView, + idFormat, timeRange: { startTime, endTime }, }, } = request.body; @@ -59,6 +60,7 @@ export const initGetLogEntryCategoryExamplesRoute = ({ const { data: logEntryCategoryExamples, timing } = await getLogEntryCategoryExamples( { infra: await infraMlContext.infra, core: await infraMlContext.core }, logView, + idFormat, startTime, endTime, categoryId, diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_examples.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_examples.ts index df79783a56ed..8be303ca01f8 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_examples.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_examples.ts @@ -44,6 +44,7 @@ export const initGetLogEntryExamplesRoute = ({ dataset, exampleCount, logView, + idFormat, timeRange: { startTime, endTime }, categoryId, }, @@ -60,6 +61,7 @@ export const initGetLogEntryExamplesRoute = ({ const { data: logEntryExamples, timing } = await getLogEntryExamples( infraMlContext, logView, + idFormat, startTime, endTime, dataset, diff --git a/x-pack/plugins/infra/server/routes/profiling/index.ts b/x-pack/plugins/infra/server/routes/profiling/index.ts new file mode 100644 index 000000000000..d322fcca37b5 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/profiling/index.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { + InfraProfilingFlamegraphRequestParamsRT, + InfraProfilingFunctionsRequestParamsRT, +} from '../../../common/http_api/profiling_api'; +import type { InfraBackendLibs } from '../../lib/infra_types'; +import { fetchProfilingFlamegraph } from './lib/fetch_profiling_flamegraph'; +import { fetchProfilingFunctions } from './lib/fetch_profiling_functions'; +import { fetchProfilingStatus } from './lib/fetch_profiling_status'; +import { getProfilingDataAccess } from './lib/get_profiling_data_access'; + +const CACHE_CONTROL_HEADER_VALUE = 'private, max-age=3600'; + +export function initProfilingRoutes({ framework, getStartServices, logger }: InfraBackendLibs) { + if (!Object.hasOwn(framework.plugins, 'profilingDataAccess')) { + logger.info( + "Skipping initialization of Profiling endpoints because 'profilingDataAccess' plugin is not available" + ); + return; + } + + framework.registerRoute( + { + method: 'get', + path: '/api/infra/profiling/status', + validate: false, + }, + async (requestContext, request, response) => { + const [coreRequestContext, infraRequestContext, profilingDataAccess] = await Promise.all([ + requestContext.core, + requestContext.infra, + getProfilingDataAccess(getStartServices), + ]); + + const profilingStatus = await fetchProfilingStatus( + profilingDataAccess, + coreRequestContext, + infraRequestContext + ); + + return response.ok({ + body: profilingStatus, + }); + } + ); + + framework.registerRoute( + { + method: 'get', + path: '/api/infra/profiling/flamegraph', + validate: { + query: schema.object({ + hostname: schema.string(), + from: schema.number(), + to: schema.number(), + }), + }, + }, + async (requestContext, request, response) => { + const params = decodeOrThrow(InfraProfilingFlamegraphRequestParamsRT)(request.query); + + const [coreRequestContext, profilingDataAccess] = await Promise.all([ + requestContext.core, + getProfilingDataAccess(getStartServices), + ]); + + const flamegraph = await fetchProfilingFlamegraph( + params, + profilingDataAccess, + coreRequestContext + ); + + return response.ok({ + body: flamegraph, + headers: { + 'cache-control': CACHE_CONTROL_HEADER_VALUE, + }, + }); + } + ); + + framework.registerRoute( + { + method: 'get', + path: '/api/infra/profiling/functions', + validate: { + query: schema.object({ + hostname: schema.string(), + from: schema.number(), + to: schema.number(), + startIndex: schema.number(), + endIndex: schema.number(), + }), + }, + }, + async (requestContext, request, response) => { + const params = decodeOrThrow(InfraProfilingFunctionsRequestParamsRT)(request.query); + + const [coreRequestContext, profilingDataAccess] = await Promise.all([ + requestContext.core, + getProfilingDataAccess(getStartServices), + ]); + + const functions = await fetchProfilingFunctions( + params, + profilingDataAccess, + coreRequestContext + ); + + return response.ok({ + body: functions, + headers: { + 'cache-control': CACHE_CONTROL_HEADER_VALUE, + }, + }); + } + ); +} diff --git a/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_flamegraph.ts b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_flamegraph.ts new file mode 100644 index 000000000000..4f7ff72c3e72 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_flamegraph.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreRequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server'; +import type { BaseFlameGraph } from '@kbn/profiling-utils'; +import { HOST_FIELD } from '../../../../common/constants'; +import type { InfraProfilingFlamegraphRequestParams } from '../../../../common/http_api/profiling_api'; + +export async function fetchProfilingFlamegraph( + { hostname, from, to }: InfraProfilingFlamegraphRequestParams, + profilingDataAccess: ProfilingDataAccessPluginStart, + coreRequestContext: CoreRequestHandlerContext +): Promise { + return await profilingDataAccess.services.fetchFlamechartData({ + core: coreRequestContext, + esClient: coreRequestContext.elasticsearch.client.asCurrentUser, + rangeFromMs: from, + rangeToMs: to, + kuery: `${HOST_FIELD} : "${hostname}"`, + }); +} diff --git a/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_functions.ts b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_functions.ts new file mode 100644 index 000000000000..d445e364d143 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_functions.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreRequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server'; +import type { TopNFunctions } from '@kbn/profiling-utils'; +import { HOST_FIELD } from '../../../../common/constants'; +import type { InfraProfilingFunctionsRequestParams } from '../../../../common/http_api/profiling_api'; + +export async function fetchProfilingFunctions( + params: InfraProfilingFunctionsRequestParams, + profilingDataAccess: ProfilingDataAccessPluginStart, + coreRequestContext: CoreRequestHandlerContext +): Promise { + const { hostname, from, to, startIndex, endIndex } = params; + + return await profilingDataAccess.services.fetchFunction({ + core: coreRequestContext, + esClient: coreRequestContext.elasticsearch.client.asCurrentUser, + rangeFromMs: from, + rangeToMs: to, + kuery: `${HOST_FIELD} : "${hostname}"`, + startIndex, + endIndex, + }); +} diff --git a/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_status.ts b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_status.ts new file mode 100644 index 000000000000..3ef929eeef5a --- /dev/null +++ b/x-pack/plugins/infra/server/routes/profiling/lib/fetch_profiling_status.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreRequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server'; +import type { ProfilingStatus } from '@kbn/profiling-utils'; +import type { InfraRequestHandlerContext } from '../../../types'; + +export async function fetchProfilingStatus( + profilingDataAccess: ProfilingDataAccessPluginStart, + coreRequestContext: CoreRequestHandlerContext, + infraRequestContext: InfraRequestHandlerContext +): Promise { + return await profilingDataAccess.services.getStatus({ + esClient: coreRequestContext.elasticsearch.client, + soClient: coreRequestContext.savedObjects.client, + spaceId: infraRequestContext.spaceId, + }); +} diff --git a/x-pack/plugins/infra/server/routes/profiling/lib/get_profiling_data_access.ts b/x-pack/plugins/infra/server/routes/profiling/lib/get_profiling_data_access.ts new file mode 100644 index 000000000000..2e54b38b4c80 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/profiling/lib/get_profiling_data_access.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ProfilingDataAccessPluginStart } from '@kbn/profiling-data-access-plugin/server'; +import type { InfraPluginStartServicesAccessor } from '../../../types'; + +export async function getProfilingDataAccess( + getStartServices: InfraPluginStartServicesAccessor +): Promise { + const [, { profilingDataAccess }] = await getStartServices(); + + if (profilingDataAccess === undefined) { + throw new Error( + "Trying to access profilingDataAccess plugin but it's not in the start dependencies" + ); + } + + return profilingDataAccess; +} diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index e3b71afa5700..cbcbdbbbc365 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -74,7 +74,12 @@ "@kbn/expressions-plugin", "@kbn/chart-icons", "@kbn/advanced-settings-plugin", - "@kbn/cloud-plugin" + "@kbn/cloud-plugin", + "@kbn/custom-icons", + "@kbn/profiling-utils", + "@kbn/profiling-data-access-plugin", + "@kbn/core-http-request-handler-context-server", + "@kbn/observability-get-padded-alert-time-range-util" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts index d54cc4de89fa..267671a06265 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable_column.ts @@ -45,6 +45,7 @@ export interface ColumnState { summaryRow?: 'none' | 'sum' | 'avg' | 'count' | 'min' | 'max'; summaryLabel?: string; collapseFn?: CollapseFunction; + isMetric?: boolean; } export type DatatableColumnResult = ColumnState & { type: 'lens_datatable_column' }; diff --git a/x-pack/plugins/lens/kibana.jsonc b/x-pack/plugins/lens/kibana.jsonc index 04bb96af5938..1813264f7ca5 100644 --- a/x-pack/plugins/lens/kibana.jsonc +++ b/x-pack/plugins/lens/kibana.jsonc @@ -56,6 +56,7 @@ "embeddable", "fieldFormats", "charts", + "textBasedLanguages", ], "extraPublicDirs": [ "common/constants" diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 9f5a9eb6d5a4..83cc485e09c7 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -538,9 +538,10 @@ describe('Lens App', () => { } async function testSave(inst: ReactWrapper, saveProps: SaveProps) { - await getButton(inst).run(inst.getDOMNode()); - inst.update(); - const handler = inst.find('SavedObjectSaveModalOrigin').prop('onSave') as ( + getButton(inst).run(inst.getDOMNode()); + // wait a tick since SaveModalContainer initializes asynchronously + await new Promise(process.nextTick); + const handler = inst.update().find('SavedObjectSaveModalOrigin').prop('onSave') as ( p: unknown ) => void; handler(saveProps); diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal.tsx index 1a4d7c5bfb02..508e8409eb26 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal.tsx +++ b/x-pack/plugins/lens/public/app_plugin/save_modal.tsx @@ -24,6 +24,7 @@ export interface Props { savingToLibraryPermitted?: boolean; originatingApp?: string; + getOriginatingPath?: (dashboardId: string) => string; allowByValueEmbeddables: boolean; savedObjectsTagging?: SavedObjectTaggingPluginStart; @@ -35,7 +36,7 @@ export interface Props { getAppNameFromId: () => string | undefined; returnToOriginSwitchLabel?: string; - + returnToOrigin?: boolean; onClose: () => void; onSave: (props: SaveProps, options: { saveToLibrary: boolean }) => void; } @@ -43,6 +44,7 @@ export interface Props { export const SaveModal = (props: Props) => { const { originatingApp, + getOriginatingPath, savingToLibraryPermitted, savedObjectsTagging, tagsIds, @@ -54,10 +56,11 @@ export const SaveModal = (props: Props) => { getAppNameFromId, onClose, onSave, + returnToOrigin, } = props; // Use the modal with return-to-origin features if we're in an app's edit flow or if by-value embeddables are disabled - if (originatingApp || !allowByValueEmbeddables) { + if ((originatingApp || !allowByValueEmbeddables) && returnToOrigin !== false) { return ( { defaultMessage: 'Lens visualization', })} data-test-subj="lnsApp_saveModalDashboard" + getOriginatingPath={getOriginatingPath} /> ); }; diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx index 9a9fb2661f30..83ae6cd66702 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { isFilterPinned } from '@kbn/es-query'; import { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; import type { SavedObjectReference } from '@kbn/core/public'; +import { EuiLoadingSpinner } from '@elastic/eui'; import { SaveModal } from './save_modal'; import type { LensAppProps, LensAppServices } from './types'; import type { SaveProps } from './app'; @@ -25,11 +26,12 @@ type ExtraProps = Pick & export type SaveModalContainerProps = { originatingApp?: string; + getOriginatingPath?: (dashboardId: string) => string; persistedDoc?: Document; lastKnownDoc?: Document; returnToOriginSwitchLabel?: string; onClose: () => void; - onSave?: () => void; + onSave?: (saveProps: SaveProps) => void; runSave?: (saveProps: SaveProps, options: { saveToLibrary: boolean }) => void; isSaveable?: boolean; getAppNameFromId?: () => string | undefined; @@ -44,6 +46,7 @@ export function SaveModalContainer({ runSave, persistedDoc, originatingApp, + getOriginatingPath, initialInput, redirectTo, redirectToOrigin, @@ -56,6 +59,7 @@ export function SaveModalContainer({ let title = ''; let description; let savedObjectId; + const [initializing, setInitializing] = useState(true); const [lastKnownDoc, setLastKnownDoc] = useState(initLastKnownDoc); if (lastKnownDoc) { title = lastKnownDoc.title; @@ -90,9 +94,15 @@ export function SaveModalContainer({ getPersisted({ initialInput, lensServices, - }).then((persisted) => { - if (persisted?.doc && isMounted) setLastKnownDoc(persisted.doc); - }); + }) + .then((persisted) => { + if (persisted?.doc && isMounted) setLastKnownDoc(persisted.doc); + }) + .finally(() => { + setInitializing(false); + }); + } else { + setInitializing(false); } return () => { @@ -119,6 +129,7 @@ export function SaveModalContainer({ redirectTo, redirectToOrigin, originatingApp, + getOriginatingPath, getIsByValueMode: () => false, onAppLeave: () => {}, savedObjectStore: lensServices.savedObjectStore, @@ -126,17 +137,22 @@ export function SaveModalContainer({ saveProps, options ).then(() => { - onSave?.(); + onSave?.(saveProps); onClose(); }); } }; + if (initializing) { + return ; + } + const savingToLibraryPermitted = Boolean(isSaveable && application.capabilities.visualize.save); return ( ); } @@ -158,11 +175,15 @@ const redirectToDashboard = ({ embeddableInput, dashboardFeatureFlag, dashboardId, + originatingApp, + getOriginatingPath, stateTransfer, }: { embeddableInput: LensEmbeddableInput; dashboardId: string; dashboardFeatureFlag: LensAppServices['dashboardFeatureFlag']; + originatingApp?: string; + getOriginatingPath?: (dashboardId: string) => string | undefined; stateTransfer: LensAppServices['stateTransfer']; }) => { if (!dashboardFeatureFlag.allowByValueEmbeddables) { @@ -174,8 +195,11 @@ const redirectToDashboard = ({ type: LENS_EMBEDDABLE_TYPE, }; - const path = dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`; - stateTransfer.navigateToWithEmbeddablePackage('dashboards', { + const path = + getOriginatingPath?.(dashboardId) ?? + (dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`); + const appId = originatingApp ?? 'dashboards'; + stateTransfer.navigateToWithEmbeddablePackage(appId, { state, path, }); @@ -208,6 +232,7 @@ export const runSaveLensVisualization = async ( getIsByValueMode: () => boolean; persistedDoc?: Document; originatingApp?: string; + getOriginatingPath?: (dashboardId: string) => string; textBasedLanguageSave?: boolean; switchDatasource?: () => void; savedObjectStore: SavedObjectIndexStore; @@ -248,7 +273,6 @@ export const runSaveLensVisualization = async ( persistedDoc && savedObjectsTagging ? savedObjectsTagging.ui.getTagIdsFromReferences(persistedDoc.references) : []; - references = savedObjectsTagging.ui.updateTagsReferences( references, saveProps.newTags || tagsIds @@ -305,7 +329,6 @@ export const runSaveLensVisualization = async ( timeRange: saveProps.panelTimeRange, }; } - if (saveProps.returnToOrigin && redirectToOrigin) { // disabling the validation on app leave because the document has been saved. onAppLeave?.((actions) => { @@ -323,6 +346,8 @@ export const runSaveLensVisualization = async ( dashboardId: saveProps.dashboardId, stateTransfer, dashboardFeatureFlag, + originatingApp: props.originatingApp, + getOriginatingPath: props.getOriginatingPath, }); return; } diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx new file mode 100644 index 000000000000..5f0abbf3a952 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/flyout_wrapper.tsx @@ -0,0 +1,157 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiTitle, + EuiToolTip, + EuiButton, + EuiLink, + EuiBetaBadge, +} from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { FlyoutWrapperProps } from './types'; + +export const FlyoutWrapper = ({ + children, + isInlineFlyoutVisible, + isScrollable, + displayFlyoutHeader, + language, + attributesChanged, + onCancel, + navigateToLensEditor, + onApply, +}: FlyoutWrapperProps) => { + return ( + <> + {isInlineFlyoutVisible && displayFlyoutHeader && ( + + + + +

    + {i18n.translate('xpack.lens.config.editVisualizationLabel', { + defaultMessage: 'Edit {lang} visualization', + values: { lang: language }, + })} + + + +

    +
    +
    + {navigateToLensEditor && ( + + + {i18n.translate('xpack.lens.config.editLinkLabel', { + defaultMessage: 'Edit in Lens', + })} + + + )} +
    +
    + )} + + * { + pointer-events: auto; + } + } + .euiFlyoutBody__overflowContent { + padding: 0; + block-size: 100%; + } + `} + > + {children} + + {isInlineFlyoutVisible && ( + + + + + + + + + + + + + + + )} + + ); +}; diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.test.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.test.tsx index 34adf0c9c254..26428091032e 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.test.tsx @@ -39,11 +39,11 @@ describe('Lens flyout', () => { newDatasourceState: 'newDatasourceState', }) ); - expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', null); + expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', null, 'testVis'); store.dispatch( updateVisualizationState({ visualizationId: 'testVis', newState: 'newVisState' }) ); - expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', 'newVisState'); + expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', 'newVisState', 'testVis'); }); test('updater is not run if it does not modify visualization or datasource state', () => { diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx index fc6511b66ec1..91b094c14116 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback } from 'react'; +import React, { useCallback, useState } from 'react'; import { EuiFlyout, EuiLoadingSpinner, EuiOverlayMask } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Provider } from 'react-redux'; @@ -25,16 +25,21 @@ import { } from '../../../state_management'; import { generateId } from '../../../id_generator'; import type { DatasourceMap, VisualizationMap } from '../../../types'; -import { - LensEditConfigurationFlyout, - type EditConfigPanelProps, -} from './lens_configuration_flyout'; +import { LensEditConfigurationFlyout } from './lens_configuration_flyout'; +import type { EditConfigPanelProps } from './types'; import { SavedObjectIndexStore, type Document } from '../../../persistence'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; import { DOC_TYPE } from '../../../../common/constants'; export type EditLensConfigurationProps = Omit< EditConfigPanelProps, - 'startDependencies' | 'coreStart' | 'visualizationMap' | 'datasourceMap' | 'saveByRef' + | 'startDependencies' + | 'coreStart' + | 'visualizationMap' + | 'datasourceMap' + | 'saveByRef' + | 'setCurrentAttributes' + | 'previousAttributes' >; function LoadingSpinnerWithOverlay() { return ( @@ -44,7 +49,11 @@ function LoadingSpinnerWithOverlay() { ); } -type UpdaterType = (datasourceState: unknown, visualizationState: unknown) => void; +type UpdaterType = ( + datasourceState: unknown, + visualizationState: unknown, + visualizationType?: string +) => void; // exported for testing export const updatingMiddleware = @@ -68,7 +77,12 @@ export const updatingMiddleware = if (initExisting.match(action) || initEmpty.match(action)) { return; } - updater(datasourceStates[activeDatasourceId].state, visualization.state); + + updater( + datasourceStates[activeDatasourceId].state, + visualization.state, + visualization.activeId + ); } }; @@ -88,6 +102,7 @@ export async function getEditLensConfiguration( return ({ attributes, updatePanelState, + updateSuggestion, closeFlyout, wrapInFlyout, datasourceId, @@ -98,10 +113,13 @@ export async function getEditLensConfiguration( updateByRefInput, navigateToLensEditor, displayFlyoutHeader, + canEditTextBasedQuery, }: EditLensConfigurationProps) => { if (!lensServices || !datasourceMap || !visualizationMap) { return ; } + const [currentAttributes, setCurrentAttributes] = + useState(attributes); /** * During inline editing of a by reference panel, the panel is converted to a by value one. * When the user applies the changes we save them to the Lens SO @@ -117,7 +135,7 @@ export async function getEditLensConfiguration( }, [savedObjectId] ); - const datasourceState = attributes.state.datasourceStates[datasourceId]; + const datasourceState = currentAttributes.state.datasourceStates[datasourceId]; const storeDeps = { lensServices, datasourceMap, @@ -135,7 +153,7 @@ export async function getEditLensConfiguration( lensStore.dispatch( loadInitial({ initialInput: { - attributes, + attributes: currentAttributes, id: panelId ?? generateId(), }, inlineEditing: true, @@ -148,6 +166,7 @@ export async function getEditLensConfiguration( { closeFlyout?.(); }} @@ -169,8 +188,9 @@ export async function getEditLensConfiguration( }; const configPanelProps = { - attributes, + attributes: currentAttributes, updatePanelState, + updateSuggestion, closeFlyout, datasourceId, coreStart, @@ -184,6 +204,8 @@ export async function getEditLensConfiguration( updateByRefInput, navigateToLensEditor, displayFlyoutHeader, + canEditTextBasedQuery, + setCurrentAttributes, }; return getWrapper( diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.test.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.test.ts new file mode 100644 index 000000000000..0fe5f148a25d --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.test.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import { createMockStartDependencies } from '../../../editor_frame_service/mocks'; +import { + mockVisualizationMap, + mockDatasourceMap, + mockDataViewWithTimefield, + mockAllSuggestions, +} from '../../../mocks'; +import { suggestionsApi } from '../../../lens_suggestions_api'; +import { fetchDataFromAggregateQuery } from '../../../datasources/text_based/fetch_data_from_aggregate_query'; +import { getSuggestions } from './helpers'; + +const mockSuggestionApi = suggestionsApi as jest.Mock; +const mockFetchData = fetchDataFromAggregateQuery as jest.Mock; + +jest.mock('../../../lens_suggestions_api', () => ({ + suggestionsApi: jest.fn(() => mockAllSuggestions), +})); + +jest.mock('../../../datasources/text_based/fetch_data_from_aggregate_query', () => ({ + fetchDataFromAggregateQuery: jest.fn(() => { + return { + columns: [ + { + name: '@timestamp', + id: '@timestamp', + meta: { + type: 'date', + }, + }, + { + name: 'bytes', + id: 'bytes', + meta: { + type: 'number', + }, + }, + { + name: 'memory', + id: 'memory', + meta: { + type: 'number', + }, + }, + ], + }; + }), +})); + +describe('getSuggestions', () => { + const query = { + esql: 'from index1 | limit 10 | stats average = avg(bytes', + }; + const mockStartDependencies = + createMockStartDependencies() as unknown as LensPluginStartDependencies; + const dataViews = dataViewPluginMocks.createStartContract(); + dataViews.create.mockResolvedValue(mockDataViewWithTimefield); + const dataviewSpecArr = [ + { + id: 'd2588ae7-9ea0-4439-9f5b-f808754a3b97', + title: 'index1', + timeFieldName: '@timestamp', + sourceFilters: [], + fieldFormats: {}, + runtimeFieldMap: {}, + fieldAttrs: {}, + allowNoIndex: false, + name: 'index1', + }, + ]; + const startDependencies = { + ...mockStartDependencies, + dataViews, + }; + + it('returns the suggestions attributes correctly', async () => { + const suggestionsAttributes = await getSuggestions( + query, + startDependencies, + mockDatasourceMap(), + mockVisualizationMap(), + dataviewSpecArr, + jest.fn() + ); + expect(suggestionsAttributes?.visualizationType).toBe(mockAllSuggestions[0].visualizationId); + expect(suggestionsAttributes?.state.visualization).toStrictEqual( + mockAllSuggestions[0].visualizationState + ); + }); + + it('returns undefined if no suggestions are computed', async () => { + mockSuggestionApi.mockResolvedValueOnce([]); + const suggestionsAttributes = await getSuggestions( + query, + startDependencies, + mockDatasourceMap(), + mockVisualizationMap(), + dataviewSpecArr, + jest.fn() + ); + expect(suggestionsAttributes).toBeUndefined(); + }); + + it('returns an error if fetching the data fails', async () => { + mockFetchData.mockImplementation(() => { + throw new Error('sorry!'); + }); + const setErrorsSpy = jest.fn(); + const suggestionsAttributes = await getSuggestions( + query, + startDependencies, + mockDatasourceMap(), + mockVisualizationMap(), + dataviewSpecArr, + setErrorsSpy + ); + expect(suggestionsAttributes).toBeUndefined(); + expect(setErrorsSpy).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts new file mode 100644 index 000000000000..faecb37ba7fd --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; +import { getIndexPatternFromSQLQuery, getIndexPatternFromESQLQuery } from '@kbn/es-query'; +import type { AggregateQuery, Query, Filter } from '@kbn/es-query'; +import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/public'; +import type { Suggestion } from '../../../types'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import type { DatasourceMap, VisualizationMap } from '../../../types'; +import { fetchDataFromAggregateQuery } from '../../../datasources/text_based/fetch_data_from_aggregate_query'; +import { suggestionsApi } from '../../../lens_suggestions_api'; + +export const getQueryColumns = async ( + query: AggregateQuery, + dataView: DataView, + deps: LensPluginStartDependencies +) => { + // Fetching only columns for ES|QL for performance reasons with limit 0 + // Important note: ES doesnt return the warnings for 0 limit, + // I am skipping them in favor of performance now + // but we should think another way to get them (from Lens embeddable or store) + const performantQuery = { ...query }; + if ('esql' in performantQuery && performantQuery.esql) { + performantQuery.esql = `${performantQuery.esql} | limit 0`; + } + const table = await fetchDataFromAggregateQuery( + performantQuery, + dataView, + deps.data, + deps.expressions + ); + return table?.columns; +}; + +export const getSuggestions = async ( + query: AggregateQuery, + deps: LensPluginStartDependencies, + datasourceMap: DatasourceMap, + visualizationMap: VisualizationMap, + adHocDataViews: DataViewSpec[], + setErrors: (errors: Error[]) => void +) => { + try { + let indexPattern = ''; + if ('sql' in query) { + indexPattern = getIndexPatternFromSQLQuery(query.sql); + } + if ('esql' in query) { + indexPattern = getIndexPatternFromESQLQuery(query.esql); + } + const dataViewSpec = adHocDataViews.find((adHoc) => { + return adHoc.name === indexPattern; + }); + + const dataView = await deps.dataViews.create( + dataViewSpec ?? { + title: indexPattern, + } + ); + if (dataView.fields.getByName('@timestamp')?.type === 'date' && !dataViewSpec) { + dataView.timeFieldName = '@timestamp'; + } + const columns = await getQueryColumns(query, dataView, deps); + const context = { + dataViewSpec: dataView?.toSpec(), + fieldName: '', + textBasedColumns: columns, + query, + }; + + const allSuggestions = + suggestionsApi({ context, dataView, datasourceMap, visualizationMap }) ?? []; + + // Lens might not return suggestions for some cases, i.e. in case of errors + if (!allSuggestions.length) return undefined; + + const firstSuggestion = allSuggestions[0]; + + const attrs = getLensAttributes({ + filters: [], + query, + suggestion: firstSuggestion, + dataView, + }); + return attrs; + } catch (e) { + setErrors([e]); + } + return undefined; +}; + +export const getLensAttributes = ({ + filters, + query, + suggestion, + dataView, +}: { + filters: Filter[]; + query: Query | AggregateQuery; + suggestion: Suggestion | undefined; + dataView?: DataView; +}) => { + const suggestionDatasourceState = Object.assign({}, suggestion?.datasourceState); + const suggestionVisualizationState = Object.assign({}, suggestion?.visualizationState); + const datasourceStates = + suggestion && suggestion.datasourceState + ? { + [suggestion.datasourceId!]: { + ...suggestionDatasourceState, + }, + } + : { + formBased: {}, + }; + const visualization = suggestionVisualizationState; + const attributes = { + title: suggestion + ? suggestion.title + : i18n.translate('xpack.lens.config.suggestion.title', { + defaultMessage: 'New suggestion', + }), + references: [ + { + id: dataView?.id ?? '', + name: `textBasedLanguages-datasource-layer-suggestion`, + type: 'index-pattern', + }, + ], + state: { + datasourceStates, + filters, + query, + visualization, + ...(dataView && + dataView.id && + !dataView.isPersisted() && { + adHocDataViews: { [dataView.id]: dataView.toSpec(false) }, + }), + }, + visualizationType: suggestion ? suggestion.visualizationId : 'lnsXY', + } as TypedLensByValueInput['attributes']; + return attributes; +}; diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/layer_configuration_section.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/layer_configuration_section.tsx new file mode 100644 index 000000000000..7ae7b456ab66 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/layer_configuration_section.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EuiSpacer, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { VisualizationToolbar } from '../../../editor_frame_service/editor_frame/workspace_panel'; +import { ConfigPanelWrapper } from '../../../editor_frame_service/editor_frame/config_panel/config_panel'; +import { createIndexPatternService } from '../../../data_views_service/service'; +import { useLensDispatch, updateIndexPatterns } from '../../../state_management'; +import { replaceIndexpattern } from '../../../state_management/lens_slice'; +import type { LayerConfigurationProps } from './types'; +import { useLensSelector } from '../../../state_management'; + +export function LayerConfiguration({ + attributes, + coreStart, + startDependencies, + visualizationMap, + datasourceMap, + datasourceId, + framePublicAPI, + hasPadding, + setIsInlineFlyoutVisible, +}: LayerConfigurationProps) { + const dispatch = useLensDispatch(); + const { euiTheme } = useEuiTheme(); + const { visualization } = useLensSelector((state) => state.lens); + const activeVisualization = + visualizationMap[visualization.activeId ?? attributes.visualizationType]; + const indexPatternService = useMemo( + () => + createIndexPatternService({ + dataViews: startDependencies.dataViews, + uiActions: startDependencies.uiActions, + core: coreStart, + updateIndexPatterns: (newIndexPatternsState, options) => { + dispatch(updateIndexPatterns(newIndexPatternsState)); + }, + replaceIndexPattern: (newIndexPattern, oldId, options) => { + dispatch(replaceIndexpattern({ newIndexPattern, oldId })); + }, + }), + [coreStart, dispatch, startDependencies.dataViews, startDependencies.uiActions] + ); + + const layerPanelsProps = { + framePublicAPI, + datasourceMap, + visualizationMap, + core: coreStart, + dataViews: startDependencies.dataViews, + uiActions: startDependencies.uiActions, + hideLayerHeader: datasourceId === 'textBased', + indexPatternService, + setIsInlineFlyoutVisible, + }; + return ( +
    + + + +
    + ); +} diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx index 4731afe03724..0462e4ad251d 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx @@ -14,10 +14,8 @@ import { mockVisualizationMap, mockDatasourceMap, mockDataPlugin } from '../../. import type { LensPluginStartDependencies } from '../../../plugin'; import { createMockStartDependencies } from '../../../editor_frame_service/mocks'; import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; -import { - LensEditConfigurationFlyout, - type EditConfigPanelProps, -} from './lens_configuration_flyout'; +import { LensEditConfigurationFlyout } from './lens_configuration_flyout'; +import type { EditConfigPanelProps } from './types'; const lensAttributes = { title: 'test', @@ -29,14 +27,12 @@ const lensAttributes = { visualization: {}, filters: [], query: { - language: 'lucene', - query: '', + esql: 'from index1 | limit 10', }, }, filters: [], query: { - language: 'lucene', - query: '', + esql: 'from index1 | limit 10', }, references: [], } as unknown as TypedLensByValueInput['attributes']; @@ -109,6 +105,16 @@ describe('LensEditConfigurationFlyout', () => { expect(closeFlyoutSpy).toHaveBeenCalled(); }); + it('should call the updatePanelState callback if cancel button is clicked', async () => { + const updatePanelStateSpy = jest.fn(); + renderConfigFlyout({ + updatePanelState: updatePanelStateSpy, + }); + expect(screen.getByTestId('lns-layerPanel-0')).toBeInTheDocument(); + userEvent.click(screen.getByTestId('cancelFlyoutButton')); + expect(updatePanelStateSpy).toHaveBeenCalled(); + }); + it('should call the updateByRefInput callback if cancel button is clicked and savedObjectId exists', async () => { const updateByRefInputSpy = jest.fn(); @@ -135,4 +141,41 @@ describe('LensEditConfigurationFlyout', () => { expect(updateByRefInputSpy).toHaveBeenCalled(); expect(saveByRefSpy).toHaveBeenCalled(); }); + + it('should not display the editor if canEditTextBasedQuery prop is false', async () => { + renderConfigFlyout({ + canEditTextBasedQuery: false, + }); + expect(screen.queryByTestId('TextBasedLangEditor')).toBeNull(); + }); + + it('should not display the editor if canEditTextBasedQuery prop is true but the query is not text based', async () => { + renderConfigFlyout({ + canEditTextBasedQuery: true, + attributes: { + ...lensAttributes, + state: { + ...lensAttributes.state, + query: { + type: 'kql', + query: '', + } as unknown as Query, + }, + }, + }); + expect(screen.queryByTestId('TextBasedLangEditor')).toBeNull(); + }); + + it('should display the suggestions if canEditTextBasedQuery prop is true', async () => { + renderConfigFlyout( + { + canEditTextBasedQuery: true, + }, + { + esql: 'from index1 | limit 10', + } + ); + expect(screen.getByTestId('InlineEditingESQLEditor')).toBeInTheDocument(); + expect(screen.getByTestId('InlineEditingSuggestions')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index a60e3df063aa..72dbd313d645 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -6,85 +6,34 @@ */ import React, { useMemo, useCallback, useRef, useEffect, useState } from 'react'; +import { isEqual } from 'lodash'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; import { - EuiButtonEmpty, - EuiButton, - EuiFlyoutBody, - EuiFlyoutFooter, EuiTitle, - EuiLink, - EuiIcon, - EuiToolTip, - EuiSpacer, + EuiAccordion, + useEuiTheme, EuiFlexGroup, EuiFlexItem, - useEuiTheme, - EuiCallOut, + euiScrollBarStyles, } from '@elastic/eui'; -import { isEqual } from 'lodash'; -import type { Observable } from 'rxjs'; import { euiThemeVars } from '@kbn/ui-theme'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { css } from '@emotion/react'; -import type { CoreStart } from '@kbn/core/public'; import type { Datatable } from '@kbn/expressions-plugin/public'; -import type { LensPluginStartDependencies } from '../../../plugin'; import { - useLensSelector, - selectFramePublicAPI, - useLensDispatch, - updateIndexPatterns, -} from '../../../state_management'; -import { replaceIndexpattern } from '../../../state_management/lens_slice'; -import { VisualizationToolbar } from '../../../editor_frame_service/editor_frame/workspace_panel'; - -import type { DatasourceMap, VisualizationMap } from '../../../types'; + getAggregateQueryMode, + isOfAggregateQueryType, + getLanguageDisplayName, +} from '@kbn/es-query'; +import type { AggregateQuery, Query } from '@kbn/es-query'; +import { TextBasedLangEditor } from '@kbn/text-based-languages/public'; +import { useLensSelector, selectFramePublicAPI } from '../../../state_management'; import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; -import type { LensEmbeddableOutput } from '../../../embeddable'; -import type { LensInspector } from '../../../lens_inspector_service'; -import { ConfigPanelWrapper } from '../../../editor_frame_service/editor_frame/config_panel/config_panel'; import { extractReferencesFromState } from '../../../utils'; -import type { Document } from '../../../persistence'; -import { createIndexPatternService } from '../../../data_views_service/service'; - -export interface EditConfigPanelProps { - coreStart: CoreStart; - startDependencies: LensPluginStartDependencies; - visualizationMap: VisualizationMap; - datasourceMap: DatasourceMap; - /** The attributes of the Lens embeddable */ - attributes: TypedLensByValueInput['attributes']; - /** Callback for updating the visualization and datasources state */ - updatePanelState: (datasourceState: unknown, visualizationState: unknown) => void; - /** Lens visualizations can be either created from ESQL (textBased) or from dataviews (formBased) */ - datasourceId: 'formBased' | 'textBased'; - /** Embeddable output observable, useful for dashboard flyout */ - output$?: Observable; - /** Contains the active data, necessary for some panel configuration such as coloring */ - lensAdapters?: LensInspector['adapters']; - /** Optional callback called when updating the by reference embeddable */ - updateByRefInput?: (soId: string) => void; - /** Callback for closing the edit flyout */ - closeFlyout?: () => void; - /** Boolean used for adding a flyout wrapper */ - wrapInFlyout?: boolean; - /** Optional parameter for panel identification - * If not given, Lens generates a new one - */ - panelId?: string; - /** Optional parameter for saved object id - * Should be given if the lens embeddable is a by reference one - * (saved in the library) - */ - savedObjectId?: string; - /** Callback for saving the embeddable as a SO */ - saveByRef?: (attrs: Document) => void; - /** Optional callback for navigation from the header of the flyout */ - navigateToLensEditor?: () => void; - /** If set to true it displays a header on the flyout */ - displayFlyoutHeader?: boolean; -} +import { LayerConfiguration } from './layer_configuration_section'; +import type { EditConfigPanelProps } from './types'; +import { FlyoutWrapper } from './flyout_wrapper'; +import { getSuggestions } from './helpers'; +import { SuggestionPanel } from '../../../editor_frame_service/editor_frame/suggestion_panel'; export function LensEditConfigurationFlyout({ attributes, @@ -94,6 +43,8 @@ export function LensEditConfigurationFlyout({ datasourceMap, datasourceId, updatePanelState, + updateSuggestion, + setCurrentAttributes, closeFlyout, saveByRef, savedObjectId, @@ -102,15 +53,21 @@ export function LensEditConfigurationFlyout({ lensAdapters, navigateToLensEditor, displayFlyoutHeader, + canEditTextBasedQuery, }: EditConfigPanelProps) { + const euiTheme = useEuiTheme(); const previousAttributes = useRef(attributes); + const prevQuery = useRef(attributes.state.query); + const [query, setQuery] = useState(attributes.state.query); + const [errors, setErrors] = useState(); + const [isInlineFlyoutVisible, setIsInlineFlyoutVisible] = useState(true); + const [isLayerAccordionOpen, setIsLayerAccordionOpen] = useState(true); + const [isSuggestionsAccordionOpen, setIsSuggestionsAccordionOpen] = useState(false); const datasourceState = attributes.state.datasourceStates[datasourceId]; const activeVisualization = visualizationMap[attributes.visualizationType]; const activeDatasource = datasourceMap[datasourceId]; - const [isInlineFooterVisible, setIsInlineFlyoutFooterVisible] = useState(true); - const { euiTheme } = useEuiTheme(); const { datasourceStates, visualization, isLoading } = useLensSelector((state) => state.lens); - const dispatch = useLensDispatch(); + const suggestsLimitedColumns = activeDatasource?.suggestsLimitedColumns?.(datasourceState); const activeData: Record = useMemo(() => { return {}; }, []); @@ -149,28 +106,34 @@ export function LensEditConfigurationFlyout({ const onCancel = useCallback(() => { const previousAttrs = previousAttributes.current; - if (attributesChanged) { - const currentDatasourceState = datasourceMap[datasourceId].injectReferencesToLayers - ? datasourceMap[datasourceId]?.injectReferencesToLayers?.( - previousAttrs.state.datasourceStates[datasourceId], - previousAttrs.references - ) - : previousAttrs.state.datasourceStates[datasourceId]; - updatePanelState?.(currentDatasourceState, previousAttrs.state.visualization); + if (previousAttrs.visualizationType === visualization.activeId) { + const currentDatasourceState = datasourceMap[datasourceId].injectReferencesToLayers + ? datasourceMap[datasourceId]?.injectReferencesToLayers?.( + previousAttrs.state.datasourceStates[datasourceId], + previousAttrs.references + ) + : previousAttrs.state.datasourceStates[datasourceId]; + updatePanelState?.(currentDatasourceState, previousAttrs.state.visualization); + } else { + updateSuggestion?.(previousAttrs); + } if (savedObjectId) { updateByRefInput?.(savedObjectId); } } closeFlyout?.(); }, [ + previousAttributes, attributesChanged, - savedObjectId, closeFlyout, datasourceMap, datasourceId, updatePanelState, + updateSuggestion, + savedObjectId, updateByRefInput, + visualization, ]); const onApply = useCallback(() => { @@ -218,20 +181,33 @@ export function LensEditConfigurationFlyout({ datasourceMap, ]); - const indexPatternService = useMemo( - () => - createIndexPatternService({ - dataViews: startDependencies.dataViews, - uiActions: startDependencies.uiActions, - core: coreStart, - updateIndexPatterns: (newIndexPatternsState, options) => { - dispatch(updateIndexPatterns(newIndexPatternsState)); - }, - replaceIndexPattern: (newIndexPattern, oldId, options) => { - dispatch(replaceIndexpattern({ newIndexPattern, oldId })); - }, - }), - [coreStart, dispatch, startDependencies.dataViews, startDependencies.uiActions] + // needed for text based languages mode which works ONLY with adHoc dataviews + const adHocDataViews = Object.values(attributes.state.adHocDataViews ?? {}); + + const runQuery = useCallback( + async (q) => { + const attrs = await getSuggestions( + q, + startDependencies, + datasourceMap, + visualizationMap, + adHocDataViews, + setErrors + ); + if (attrs) { + setCurrentAttributes?.(attrs); + setErrors([]); + updateSuggestion?.(attrs); + } + }, + [ + startDependencies, + datasourceMap, + visualizationMap, + adHocDataViews, + setCurrentAttributes, + updateSuggestion, + ] ); const framePublicAPI = useLensSelector((state) => { @@ -244,155 +220,197 @@ export function LensEditConfigurationFlyout({ }; return selectFramePublicAPI(newState, datasourceMap); }); + + const textBasedMode = isOfAggregateQueryType(query) ? getAggregateQueryMode(query) : undefined; + if (isLoading) return null; + // Example is the Discover editing where we dont want to render the text based editor on the panel + if (!canEditTextBasedQuery) { + return ( + + + + ); + } - const layerPanelsProps = { - framePublicAPI, - datasourceMap, - visualizationMap, - core: coreStart, - dataViews: startDependencies.dataViews, - uiActions: startDependencies.uiActions, - hideLayerHeader: datasourceId === 'textBased', - indexPatternService, - setIsInlineFlyoutFooterVisible, - }; return ( <> - * { - pointer-events: auto; - } - } - .euiFlyoutBody__overflowContent { - padding: 0; - } - `} + - - {displayFlyoutHeader && ( - - - - - - -

    - {i18n.translate('xpack.lens.config.editVisualizationLabel', { - defaultMessage: 'Edit visualization', - })} -

    -
    -
    - - - - - -
    -
    - {navigateToLensEditor && ( - - - {i18n.translate('xpack.lens.config.editLinkLabel', { - defaultMessage: 'Edit in Lens', - })} - - - )} -
    + + {isOfAggregateQueryType(query) && ( + + { + setQuery(q); + prevQuery.current = q; + }} + expandCodeEditor={(status: boolean) => {}} + isCodeEditorExpanded + detectTimestamp={Boolean(adHocDataViews?.[0]?.timeFieldName)} + errors={errors} + warning={ + suggestsLimitedColumns + ? i18n.translate('xpack.lens.config.configFlyoutCallout', { + defaultMessage: + 'Displaying a limited portion of the available fields. Add more from the configuration panel.', + }) + : undefined + } + hideMinimizeButton + editorIsInline + hideRunQueryText + disableSubmitAction={isEqual(query, prevQuery.current)} + onTextLangQuerySubmit={(q) => { + if (q) { + runQuery(q); + } + }} + isDisabled={false} + /> )} - {datasourceId === 'textBased' && ( - +
    + {i18n.translate('xpack.lens.config.layerConfigurationLabel', { + defaultMessage: 'Layer configuration', + })} +
    + + } + buttonProps={{ + paddingSize: 'm', + }} + initialIsOpen={isLayerAccordionOpen} + forceState={isLayerAccordionOpen ? 'open' : 'closed'} + onToggle={(status) => { + if (status && isSuggestionsAccordionOpen) { + setIsSuggestionsAccordionOpen(!status); + } + setIsLayerAccordionOpen(!isLayerAccordionOpen); + }} + > + - )} - - - - +
    + + + { + if (!status && isLayerAccordionOpen) { + setIsLayerAccordionOpen(status); + } + setIsSuggestionsAccordionOpen(!isSuggestionsAccordionOpen); + }} />
    -
    - {isInlineFooterVisible && ( - - - - - - - - - - - - - - - )} + ); } diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts new file mode 100644 index 000000000000..ae207865bbf9 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Observable } from 'rxjs'; +import type { CoreStart } from '@kbn/core/public'; +import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import type { LensPluginStartDependencies } from '../../../plugin'; +import type { DatasourceMap, VisualizationMap, FramePublicAPI } from '../../../types'; +import type { LensEmbeddableOutput } from '../../../embeddable'; +import type { LensInspector } from '../../../lens_inspector_service'; +import type { Document } from '../../../persistence'; + +export interface FlyoutWrapperProps { + children: JSX.Element; + isInlineFlyoutVisible: boolean; + isScrollable: boolean; + displayFlyoutHeader?: boolean; + language?: string; + attributesChanged?: boolean; + onCancel?: () => void; + onApply?: () => void; + navigateToLensEditor?: () => void; +} + +export interface EditConfigPanelProps { + coreStart: CoreStart; + startDependencies: LensPluginStartDependencies; + visualizationMap: VisualizationMap; + datasourceMap: DatasourceMap; + /** The attributes of the Lens embeddable */ + attributes: TypedLensByValueInput['attributes']; + /** Callback for updating the visualization and datasources state.*/ + updatePanelState: ( + datasourceState: unknown, + visualizationState: unknown, + visualizationType?: string + ) => void; + updateSuggestion?: (attrs: TypedLensByValueInput['attributes']) => void; + /** Set the attributes state */ + setCurrentAttributes?: (attrs: TypedLensByValueInput['attributes']) => void; + /** Lens visualizations can be either created from ESQL (textBased) or from dataviews (formBased) */ + datasourceId: 'formBased' | 'textBased'; + /** Embeddable output observable, useful for dashboard flyout */ + output$?: Observable; + /** Contains the active data, necessary for some panel configuration such as coloring */ + lensAdapters?: LensInspector['adapters']; + /** Optional callback called when updating the by reference embeddable */ + updateByRefInput?: (soId: string) => void; + /** Callback for closing the edit flyout */ + closeFlyout?: () => void; + /** Boolean used for adding a flyout wrapper */ + wrapInFlyout?: boolean; + /** Optional parameter for panel identification + * If not given, Lens generates a new one + */ + panelId?: string; + /** Optional parameter for saved object id + * Should be given if the lens embeddable is a by reference one + * (saved in the library) + */ + savedObjectId?: string; + /** Callback for saving the embeddable as a SO */ + saveByRef?: (attrs: Document) => void; + /** Optional callback for navigation from the header of the flyout */ + navigateToLensEditor?: () => void; + /** If set to true it displays a header on the flyout */ + displayFlyoutHeader?: boolean; + /** If set to true the layout changes to accordion and the text based query (i.e. ES|QL) can be edited */ + canEditTextBasedQuery?: boolean; +} + +export interface LayerConfigurationProps { + attributes: TypedLensByValueInput['attributes']; + coreStart: CoreStart; + startDependencies: LensPluginStartDependencies; + visualizationMap: VisualizationMap; + datasourceMap: DatasourceMap; + datasourceId: 'formBased' | 'textBased'; + framePublicAPI: FramePublicAPI; + hasPadding?: boolean; + setIsInlineFlyoutVisible: (flag: boolean) => void; +} diff --git a/x-pack/plugins/lens/public/app_plugin/tags_saved_object_save_modal_dashboard_wrapper.tsx b/x-pack/plugins/lens/public/app_plugin/tags_saved_object_save_modal_dashboard_wrapper.tsx index 39c2f55bdd67..9f932d0b23fd 100644 --- a/x-pack/plugins/lens/public/app_plugin/tags_saved_object_save_modal_dashboard_wrapper.tsx +++ b/x-pack/plugins/lens/public/app_plugin/tags_saved_object_save_modal_dashboard_wrapper.tsx @@ -28,6 +28,7 @@ export type TagEnhancedSavedObjectSaveModalDashboardProps = Omit< initialTags: string[]; savedObjectsTagging?: SavedObjectTaggingPluginStart; onSave: (props: DashboardSaveProps) => void; + getOriginatingPath?: (dashboardId: string) => string; }; const SavedObjectSaveModalDashboard = withSuspense(LazySavedObjectSaveModalDashboard); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/math_completion.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/math_completion.ts index baa176a1cb51..221339123584 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/math_completion.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/editor/math_completion.ts @@ -215,18 +215,18 @@ export function getPossibleFunctions( operationDefinitionMap?: Record ) { const available = memoizedGetAvailableOperationsByMetadata(indexPattern, operationDefinitionMap); - const possibleOperationNames: string[] = []; - available.forEach((a) => { + const possibleOperationNames: Set = new Set(); + for (const a of available) { if (a.operationMetaData.dataType === 'number' && !a.operationMetaData.isBucketed) { - possibleOperationNames.push( - ...a.operations - .filter((o) => o.type !== 'managedReference' || o.usedInMath) - .map((o) => o.operationType) - ); + for (const o of a.operations) { + if (o.type !== 'managedReference' || o.usedInMath) { + possibleOperationNames.add(o.operationType); + } + } } - }); + } - return [...uniq(possibleOperationNames), ...Object.keys(tinymathFunctions)]; + return Array.from(possibleOperationNames.keys()).concat(Object.keys(tinymathFunctions)); } function getFunctionSuggestions( @@ -261,7 +261,7 @@ function getArgumentSuggestions( if (tinymathFunction) { if (tinymathFunction.positionalArguments[position]) { return { - list: uniq(getPossibleFunctions(indexPattern, operationDefinitionMap)).map((f) => ({ + list: getPossibleFunctions(indexPattern, operationDefinitionMap).map((f) => ({ type: 'math' as const, label: f, })), diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx index fbcfaf3c36b9..af00ba7cb5c6 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx @@ -66,8 +66,9 @@ export const staticValueOperation: OperationDefinition< }, getErrorMessage(layer, columnId) { const column = layer.columns[columnId] as StaticValueIndexPatternColumn; + const isValid = isValidNumber(column.params.value, false, undefined, undefined, 15); - return column.params.value != null && !isValidNumber(column.params.value) + return column.params.value != null && !isValid ? [ i18n.translate('xpack.lens.indexPattern.staticValueError', { defaultMessage: 'The static value of {value} is not a valid number', @@ -89,7 +90,8 @@ export const staticValueOperation: OperationDefinition< const params = currentColumn.params; // TODO: improve this logic const useDisplayLabel = currentColumn.label !== defaultLabel; - const label = isValidNumber(params.value) + const isValid = isValidNumber(params.value, false, undefined, undefined, 15); + const label = isValid ? useDisplayLabel ? currentColumn.label : params?.value ?? defaultLabel @@ -98,11 +100,11 @@ export const staticValueOperation: OperationDefinition< return [ { type: 'function', - function: isValidNumber(params.value) ? 'mathColumn' : 'mapColumn', + function: isValid ? 'mathColumn' : 'mapColumn', arguments: { id: [columnId], name: [label || defaultLabel], - expression: [String(isValidNumber(params.value) ? params.value! : defaultValue)], + expression: [String(isValid ? params.value! : defaultValue)], }, }, ]; @@ -163,7 +165,10 @@ export const staticValueOperation: OperationDefinition< const onChange = useCallback( (newValue) => { // even if debounced it's triggering for empty string with the previous valid value - if (currentColumn.params.value === newValue) { + if ( + currentColumn.params.value === newValue || + !isValidNumber(newValue, false, undefined, undefined, 15) + ) { return; } // Because of upstream specific UX flows, we need fresh layer state here @@ -209,13 +214,26 @@ export const staticValueOperation: OperationDefinition< const onChangeHandler = useCallback( (e: React.ChangeEvent) => { const value = e.currentTarget.value; - handleInputChange(isValidNumber(value) ? value : undefined); + handleInputChange(value); }, [handleInputChange] ); + const inputValueIsValid = isValidNumber(inputValue, false, undefined, undefined, 15); + return ( - + { } as unknown as DatasourceDimensionDropHandlerProps; expect(getDropProps(props)).toBeUndefined(); }); + it('should not return undefined if source is a non-numeric field, target is a metric dimension but datatable doesnt have numeric fields', () => { + const props = { + ...defaultProps, + state: { + ...defaultProps.state, + layers: { + first: { + columns: [column1, column2, column3], + allColumns: [...fieldListNonNumericOnly, column1, column2, column3], + }, + }, + fieldList: fieldListNonNumericOnly, + }, + source: notNumericDraggedField, + } as unknown as DatasourceDimensionDropHandlerProps; + expect(getDropProps(props)).toEqual({ dropTypes: ['field_replace'], nextLabel: 'category' }); + }); it('should return reorder if source and target are operations from the same group', () => { const props = { ...defaultProps, diff --git a/x-pack/plugins/lens/public/datasources/text_based/dnd/get_drop_props.tsx b/x-pack/plugins/lens/public/datasources/text_based/dnd/get_drop_props.tsx index 9f79fff3d608..78e1c98f3a30 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/dnd/get_drop_props.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/dnd/get_drop_props.tsx @@ -10,6 +10,7 @@ import { isOperation } from '../../../types'; import type { TextBasedPrivateState } from '../types'; import type { GetDropPropsArgs } from '../../../types'; import { isDraggedField, isOperationFromTheSameGroup } from '../../../utils'; +import { canColumnBeDroppedInMetricDimension } from '../utils'; export const getDropProps = ( props: GetDropPropsArgs @@ -44,14 +45,24 @@ export const getDropProps = ( return { dropTypes: ['reorder'], nextLabel }; } + const sourceFieldCanMoveToMetricDimension = canColumnBeDroppedInMetricDimension( + layer.allColumns, + sourceField?.meta?.type + ); + + const targetFieldCanMoveToMetricDimension = canColumnBeDroppedInMetricDimension( + layer.allColumns, + targetField?.meta?.type + ); + const isMoveable = !target?.isMetricDimension || - (target.isMetricDimension && sourceField?.meta?.type === 'number'); + (target.isMetricDimension && sourceFieldCanMoveToMetricDimension); if (targetColumn) { const isSwappable = (isMoveable && !source?.isMetricDimension) || - (source.isMetricDimension && targetField?.meta?.type === 'number'); + (source.isMetricDimension && targetFieldCanMoveToMetricDimension); if (isMoveable) { if (isSwappable) { return { diff --git a/x-pack/plugins/lens/public/datasources/text_based/dnd/mocks.tsx b/x-pack/plugins/lens/public/datasources/text_based/dnd/mocks.tsx index 5cb3bcd37e2c..90a37acab104 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/dnd/mocks.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/dnd/mocks.tsx @@ -83,6 +83,37 @@ export const numericDraggedField = { }, }; +export const fieldListNonNumericOnly = [ + { + columnId: 'category', + fieldName: 'category', + meta: { + type: 'string', + }, + }, + { + columnId: 'currency', + fieldName: 'currency', + meta: { + type: 'string', + }, + }, + { + columnId: 'products.sold_date', + fieldName: 'products.sold_date', + meta: { + type: 'date', + }, + }, + { + columnId: 'products.buyer', + fieldName: 'products.buyer', + meta: { + type: 'string', + }, + }, +]; + export const fieldList = [ { columnId: 'category', diff --git a/x-pack/plugins/lens/public/datasources/text_based/layerpanel.test.tsx b/x-pack/plugins/lens/public/datasources/text_based/layerpanel.test.tsx deleted file mode 100644 index d6e4be8c9938..000000000000 --- a/x-pack/plugins/lens/public/datasources/text_based/layerpanel.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { DatatableColumn } from '@kbn/expressions-plugin/public'; -import { TextBasedPrivateState } from './types'; -import type { DataViewsState } from '../../state_management/types'; - -import { TextBasedLayerPanelProps, LayerPanel } from './layerpanel'; -import { shallowWithIntl as shallow } from '@kbn/test-jest-helpers'; -import { ChangeIndexPattern } from '../../shared_components/dataview_picker/dataview_picker'; - -const fields = [ - { - name: 'timestamp', - id: 'timestamp', - meta: { - type: 'date', - }, - }, - { - name: 'bytes', - id: 'bytes', - meta: { - type: 'number', - }, - }, - { - name: 'memory', - id: 'memory', - meta: { - type: 'number', - }, - }, -] as DatatableColumn[]; - -const initialState: TextBasedPrivateState = { - layers: { - first: { - index: '1', - columns: [], - allColumns: [], - query: { sql: 'SELECT * FROM foo' }, - }, - }, - indexPatternRefs: [ - { id: '1', title: 'my-fake-index-pattern' }, - { id: '2', title: 'my-fake-restricted-pattern' }, - { id: '3', title: 'my-compatible-pattern' }, - ], - fieldList: fields, -}; -describe('Layer Data Panel', () => { - let defaultProps: TextBasedLayerPanelProps; - - beforeEach(() => { - defaultProps = { - layerId: 'first', - state: initialState, - onChangeIndexPattern: jest.fn(), - dataViews: { - indexPatternRefs: [ - { id: '1', title: 'my-fake-index-pattern', name: 'My fake index pattern' }, - { id: '2', title: 'my-fake-restricted-pattern', name: 'my-fake-restricted-pattern' }, - { id: '3', title: 'my-compatible-pattern', name: 'my-compatible-pattern' }, - ], - indexPatterns: {}, - } as DataViewsState, - }; - }); - - it('should display the selected dataview but disabled', () => { - const instance = shallow(); - expect(instance.find(ChangeIndexPattern).prop('trigger')).toStrictEqual({ - fontWeight: 'normal', - isDisabled: true, - label: 'my-fake-index-pattern', - size: 's', - title: 'my-fake-index-pattern', - }); - }); -}); diff --git a/x-pack/plugins/lens/public/datasources/text_based/layerpanel.tsx b/x-pack/plugins/lens/public/datasources/text_based/layerpanel.tsx deleted file mode 100644 index 3ce8c333114f..000000000000 --- a/x-pack/plugins/lens/public/datasources/text_based/layerpanel.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { DatasourceLayerPanelProps } from '../../types'; -import { TextBasedPrivateState } from './types'; -import { ChangeIndexPattern } from '../../shared_components/dataview_picker/dataview_picker'; - -export interface TextBasedLayerPanelProps extends DatasourceLayerPanelProps { - state: TextBasedPrivateState; -} - -export function LayerPanel({ state, layerId, dataViews }: TextBasedLayerPanelProps) { - const layer = state.layers[layerId]; - const dataView = state.indexPatternRefs.find((ref) => ref.id === layer.index); - - const notFoundTitleLabel = i18n.translate('xpack.lens.layerPanel.missingDataView', { - defaultMessage: 'Data view not found', - }); - return ( - {}} - /> - ); -} diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts index 8aab2f367095..604e45f72ec8 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts @@ -116,7 +116,7 @@ describe('Textbased Data Source', () => { }, ], index: 'foo', - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, }, }, fieldList: [ @@ -226,7 +226,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: 'foo', }, }, @@ -261,7 +261,7 @@ describe('Textbased Data Source', () => { ...baseState.layers, newLayer: { index: 'foo', - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, allColumns: [ { columnId: 'col1', @@ -296,7 +296,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: 'foo', }, }, @@ -353,7 +353,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: 'foo', }, }, @@ -401,13 +401,22 @@ describe('Textbased Data Source', () => { ); expect(suggestions[0].state).toEqual({ ...state, + initialContext: undefined, fieldList: textBasedQueryColumns, + indexPatternRefs: [ + { + id: '1', + timeField: undefined, + title: 'foo', + }, + ], layers: { newid: { allColumns: [ { columnId: 'bytes', fieldName: 'bytes', + inMetricDimension: true, meta: { type: 'number', }, @@ -424,6 +433,7 @@ describe('Textbased Data Source', () => { { columnId: 'bytes', fieldName: 'bytes', + inMetricDimension: true, meta: { type: 'number', }, @@ -466,6 +476,7 @@ describe('Textbased Data Source', () => { ], isMultiRow: false, layerId: 'newid', + notAssignedMetrics: false, }); }); @@ -504,6 +515,176 @@ describe('Textbased Data Source', () => { ); expect(suggestions).toEqual([]); }); + + it('should return the correct suggestions if non numeric columns are given', () => { + const textBasedQueryColumns = [ + { + id: '@timestamp', + name: '@timestamp', + meta: { + type: 'date', + }, + }, + { + id: 'dest', + name: 'dest', + meta: { + type: 'string', + }, + }, + ]; + const state = { + layers: {}, + initialContext: { + textBasedColumns: textBasedQueryColumns, + query: { esql: 'from foo' }, + dataViewSpec: { + title: 'foo', + id: '1', + name: 'Foo', + }, + }, + } as unknown as TextBasedPrivateState; + const suggestions = TextBasedDatasource.getDatasourceSuggestionsForVisualizeField( + state, + '1', + '', + indexPatterns + ); + expect(suggestions[0].state).toEqual({ + ...state, + initialContext: undefined, + fieldList: textBasedQueryColumns, + indexPatternRefs: [ + { + id: '1', + timeField: undefined, + title: 'foo', + }, + ], + layers: { + newid: { + allColumns: [ + { + columnId: '@timestamp', + fieldName: '@timestamp', + inMetricDimension: true, + meta: { + type: 'date', + }, + }, + { + columnId: 'dest', + fieldName: 'dest', + inMetricDimension: true, + meta: { + type: 'string', + }, + }, + ], + columns: [ + { + columnId: '@timestamp', + fieldName: '@timestamp', + inMetricDimension: true, + meta: { + type: 'date', + }, + }, + { + columnId: 'dest', + fieldName: 'dest', + inMetricDimension: true, + meta: { + type: 'string', + }, + }, + ], + index: '1', + query: { + esql: 'from foo', + }, + }, + }, + }); + + expect(suggestions[0].table).toEqual({ + changeType: 'initial', + columns: [ + { + columnId: '@timestamp', + operation: { + dataType: 'date', + isBucketed: true, + label: '@timestamp', + }, + }, + { + columnId: 'dest', + operation: { + dataType: 'string', + isBucketed: true, + label: 'dest', + }, + }, + ], + isMultiRow: false, + layerId: 'newid', + notAssignedMetrics: true, + }); + }); + }); + + describe('#suggestsLimitedColumns', () => { + it('should return true if query returns big number of columns', () => { + const fieldList = [ + { + id: 'a', + name: 'Test 1', + meta: { + type: 'number', + }, + }, + { + id: 'b', + name: 'Test 2', + meta: { + type: 'number', + }, + }, + { + id: 'c', + name: 'Test 3', + meta: { + type: 'date', + }, + }, + { + id: 'd', + name: 'Test 4', + meta: { + type: 'string', + }, + }, + { + id: 'e', + name: 'Test 5', + meta: { + type: 'string', + }, + }, + ]; + const state = { + fieldList, + layers: { + a: { + query: { esql: 'from foo' }, + index: 'foo', + }, + }, + } as unknown as TextBasedPrivateState; + expect(TextBasedDatasource?.suggestsLimitedColumns?.(state)).toBeTruthy(); + }); }); describe('#getUserMessages', () => { @@ -544,7 +725,7 @@ describe('Textbased Data Source', () => { }, ], errors: [new Error('error 1'), new Error('error 2')], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: 'foo', }, }, @@ -626,7 +807,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: '1', }, }, @@ -673,7 +854,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: '1', }, }, @@ -731,7 +912,7 @@ describe('Textbased Data Source', () => { }, }, ], - query: { sql: 'SELECT * FROM foo' }, + query: { esql: 'FROM foo' }, index: '1', }, }, @@ -759,11 +940,14 @@ describe('Textbased Data Source', () => { }, Object { "arguments": Object { + "locale": Array [ + "en", + ], "query": Array [ - "SELECT * FROM foo", + "FROM foo", ], }, - "function": "essql", + "function": "esql", "type": "function", }, Object { diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx index 43d971caf24a..bc46f0b4076d 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx @@ -42,10 +42,10 @@ import type { } from './types'; import { FieldSelect } from './field_select'; import type { Datasource } from '../../types'; -import { LayerPanel } from './layerpanel'; import { getUniqueLabelGenerator, nonNullable } from '../../utils'; import { onDrop, getDropProps } from './dnd'; import { removeColumn } from './remove_column'; +import { canColumnBeUsedBeInMetricDimension, MAX_NUM_OF_COLUMNS } from './utils'; function getLayerReferenceName(layerId: string) { return `textBasedLanguages-datasource-layer-${layerId}`; @@ -88,12 +88,20 @@ export function getTextBasedDatasource({ layerId: id, columns: layer.columns?.map((f) => { + const inMetricDimension = canColumnBeUsedBeInMetricDimension( + layer.allColumns, + f?.meta?.type + ); return { columnId: f.columnId, operation: { dataType: f?.meta?.type as DataType, label: f.fieldName, isBucketed: Boolean(f?.meta?.type !== 'number'), + // makes non-number fields to act as metrics, used for datatable suggestions + ...(inMetricDimension && { + inMetricDimension, + }), }, }; }) ?? [], @@ -113,11 +121,23 @@ export function getTextBasedDatasource({ if (context && 'dataViewSpec' in context && context.dataViewSpec.title && context.query) { const newLayerId = generateId(); const textBasedQueryColumns = context.textBasedColumns ?? []; + // Number fields are assigned automatically as metrics (!isBucketed). There are cases where the query + // will not return number fields. In these cases we want to suggest a datatable + // Datatable works differently in this case. On the metrics dimension can be all type of fields + const hasNumberTypeColumns = textBasedQueryColumns?.some((c) => c?.meta?.type === 'number'); const newColumns = textBasedQueryColumns.map((c) => { + const inMetricDimension = canColumnBeUsedBeInMetricDimension( + textBasedQueryColumns, + c?.meta?.type + ); return { columnId: c.id, fieldName: c.name, meta: c.meta, + // makes non-number fields to act as metrics, used for datatable suggestions + ...(inMetricDimension && { + inMetricDimension, + }), }; }); @@ -125,13 +145,25 @@ export function getTextBasedDatasource({ const query = context.query; const updatedState = { ...state, + initialContext: undefined, fieldList: textBasedQueryColumns, + ...(context.dataViewSpec.id + ? { + indexPatternRefs: [ + { + id: context.dataViewSpec.id, + title: context.dataViewSpec.title, + timeField: context.dataViewSpec.timeFieldName, + }, + ], + } + : {}), layers: { ...state.layers, [newLayerId]: { index, query, - columns: newColumns ?? [], + columns: newColumns.slice(0, MAX_NUM_OF_COLUMNS) ?? [], allColumns: newColumns ?? [], timeField: context.dataViewSpec.timeFieldName, }, @@ -146,9 +178,10 @@ export function getTextBasedDatasource({ table: { changeType: 'initial' as TableChangeType, isMultiRow: false, + notAssignedMetrics: !hasNumberTypeColumns, layerId: newLayerId, columns: - newColumns?.map((f) => { + newColumns?.slice(0, MAX_NUM_OF_COLUMNS)?.map((f) => { return { columnId: f.columnId, operation: { @@ -304,6 +337,13 @@ export function getTextBasedDatasource({ getLayers(state: TextBasedPrivateState) { return state && state.layers ? Object.keys(state?.layers) : []; }, + // there are cases where a query can return a big amount of columns + // at this case we don't suggest all columns in a table but the first + // MAX_NUM_OF_COLUMNS + suggestsLimitedColumns(state: TextBasedPrivateState) { + const fieldsList = state?.fieldList ?? []; + return fieldsList.length >= MAX_NUM_OF_COLUMNS; + }, isTimeBased: (state, indexPatterns) => { if (!state) return false; const { layers } = state; @@ -382,20 +422,21 @@ export function getTextBasedDatasource({ DimensionEditorComponent: (props: DatasourceDimensionEditorProps) => { const fields = props.state.fieldList; - const selectedField = props.state.layers[props.layerId]?.allColumns?.find( - (column) => column.columnId === props.columnId - ); + const allColumns = props.state.layers[props.layerId]?.allColumns; + const selectedField = allColumns?.find((column) => column.columnId === props.columnId); + const hasNumberTypeColumns = allColumns?.some((c) => c?.meta?.type === 'number'); const updatedFields = fields?.map((f) => { return { ...f, - compatible: props.isMetricDimension - ? props.filterOperations({ - dataType: f.meta.type as DataType, - isBucketed: Boolean(f?.meta?.type !== 'number'), - scale: 'ordinal', - }) - : true, + compatible: + props.isMetricDimension && hasNumberTypeColumns + ? props.filterOperations({ + dataType: f.meta.type as DataType, + isBucketed: Boolean(f?.meta?.type !== 'number'), + scale: 'ordinal', + }) + : true, }; }); return ( @@ -472,7 +513,7 @@ export function getTextBasedDatasource({ }, LayerPanelComponent: (props: DatasourceLayerPanelProps) => { - return ; + return null; }, uniqueLabels(state: TextBasedPrivateState) { @@ -519,6 +560,7 @@ export function getTextBasedDatasource({ dataType: column?.meta?.type as DataType, label: columnLabelMap[columnId] ?? column?.fieldName, isBucketed: Boolean(column?.meta?.type !== 'number'), + inMetricDimension: column.inMetricDimension, hasTimeShift: false, hasReducedTimeRange: false, }; diff --git a/x-pack/plugins/lens/public/datasources/text_based/types.ts b/x-pack/plugins/lens/public/datasources/text_based/types.ts index 8da183f9b905..4d1f9dfea510 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/types.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/types.ts @@ -13,6 +13,7 @@ export interface TextBasedLayerColumn { columnId: string; fieldName: string; meta?: DatatableColumn['meta']; + inMetricDimension?: boolean; } export interface TextBasedField { diff --git a/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts b/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts index 593d34f45021..3a01a7ba9efe 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts @@ -15,6 +15,7 @@ import { loadIndexPatternRefs, getStateFromAggregateQuery, getAllColumns, + canColumnBeUsedBeInMetricDimension, } from './utils'; import type { TextBasedLayerColumn } from './types'; import { type AggregateQuery } from '@kbn/es-query'; @@ -485,4 +486,111 @@ describe('Text based languages utils', () => { }); }); }); + + describe('canColumnBeUsedBeInMetricDimension', () => { + it('should return true if there are non numeric field', async () => { + const fieldList = [ + { + id: 'a', + name: 'Test 1', + meta: { + type: 'string', + }, + }, + { + id: 'b', + name: 'Test 2', + meta: { + type: 'string', + }, + }, + ] as DatatableColumn[]; + const flag = canColumnBeUsedBeInMetricDimension(fieldList, 'string'); + expect(flag).toBeTruthy(); + }); + + it('should return true if there are numeric field and the selected type is number', async () => { + const fieldList = [ + { + id: 'a', + name: 'Test 1', + meta: { + type: 'number', + }, + }, + { + id: 'b', + name: 'Test 2', + meta: { + type: 'string', + }, + }, + ] as DatatableColumn[]; + const flag = canColumnBeUsedBeInMetricDimension(fieldList, 'number'); + expect(flag).toBeTruthy(); + }); + + it('should return false if there are non numeric fields and the selected type is non numeric', async () => { + const fieldList = [ + { + id: 'a', + name: 'Test 1', + meta: { + type: 'number', + }, + }, + { + id: 'b', + name: 'Test 2', + meta: { + type: 'string', + }, + }, + ] as DatatableColumn[]; + const flag = canColumnBeUsedBeInMetricDimension(fieldList, 'date'); + expect(flag).toBeFalsy(); + }); + + it('should return true if there are many columns regardless the types', async () => { + const fieldList = [ + { + id: 'a', + name: 'Test 1', + meta: { + type: 'number', + }, + }, + { + id: 'b', + name: 'Test 2', + meta: { + type: 'number', + }, + }, + { + id: 'c', + name: 'Test 3', + meta: { + type: 'date', + }, + }, + { + id: 'd', + name: 'Test 4', + meta: { + type: 'string', + }, + }, + { + id: 'e', + name: 'Test 5', + meta: { + type: 'string', + }, + }, + ] as DatatableColumn[]; + const flag = canColumnBeUsedBeInMetricDimension(fieldList, 'date'); + expect(flag).toBeTruthy(); + }); + }); }); diff --git a/x-pack/plugins/lens/public/datasources/text_based/utils.ts b/x-pack/plugins/lens/public/datasources/text_based/utils.ts index aea93add7368..ecf4fbcd12ff 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/utils.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/utils.ts @@ -20,6 +20,8 @@ import { fetchDataFromAggregateQuery } from './fetch_data_from_aggregate_query'; import type { IndexPatternRef, TextBasedPrivateState, TextBasedLayerColumn } from './types'; import type { DataViewsState } from '../../state_management'; +export const MAX_NUM_OF_COLUMNS = 5; + export async function loadIndexPatternRefs( indexPatternsService: DataViewsPublicPluginStart ): Promise { @@ -146,3 +148,25 @@ export function getIndexPatternFromTextBasedQuery(query: AggregateQuery): string return indexPattern; } + +export function canColumnBeDroppedInMetricDimension( + columns: TextBasedLayerColumn[] | DatatableColumn[], + selectedColumnType?: string +): boolean { + // check if at least one numeric field exists + const hasNumberTypeColumns = columns?.some((c) => c?.meta?.type === 'number'); + return !hasNumberTypeColumns || (hasNumberTypeColumns && selectedColumnType === 'number'); +} + +export function canColumnBeUsedBeInMetricDimension( + columns: TextBasedLayerColumn[] | DatatableColumn[], + selectedColumnType?: string +): boolean { + // check if at least one numeric field exists + const hasNumberTypeColumns = columns?.some((c) => c?.meta?.type === 'number'); + return ( + !hasNumberTypeColumns || + columns.length >= MAX_NUM_OF_COLUMNS || + (hasNumberTypeColumns && selectedColumnType === 'number') + ); +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx index 41184d2212c4..8c31fb2f9d80 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx @@ -370,7 +370,7 @@ export function LayerPanels( } }, registerLibraryAnnotationGroup: registerLibraryAnnotationGroupFunction, - isInlineEditing: Boolean(props?.setIsInlineFlyoutFooterVisible), + isInlineEditing: Boolean(props?.setIsInlineFlyoutVisible), })} ); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index 78a06408902b..024fb04998d3 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -95,7 +95,7 @@ export function LayerPanel( indexPatternService?: IndexPatternServiceAPI; getUserMessages?: UserMessagesGetter; displayLayerSettings: boolean; - setIsInlineFlyoutFooterVisible?: (status: boolean) => void; + setIsInlineFlyoutVisible?: (status: boolean) => void; } ) { const [activeDimension, setActiveDimension] = useState( @@ -139,7 +139,7 @@ export function LayerPanel( useEffect(() => { // is undefined when the dimension panel is closed const activeDimensionId = activeDimension.activeId; - props?.setIsInlineFlyoutFooterVisible?.(!Boolean(activeDimensionId)); + props?.setIsInlineFlyoutVisible?.(!Boolean(activeDimensionId)); }, [activeDimension.activeId, activeVisualization.id, props]); const panelRef = useRef(null); @@ -394,6 +394,7 @@ export function LayerPanel( )}
    {props.indexPatternService && + !isTextBasedLanguage && (layerDatasource || activeVisualization.LayerPanelComponent) && ( )} @@ -680,7 +681,7 @@ export function LayerPanel( setPanelSettingsOpen(false); return true; }} - isInlineEditing={Boolean(props?.setIsInlineFlyoutFooterVisible)} + isInlineEditing={Boolean(props?.setIsInlineFlyoutVisible)} >
    @@ -749,7 +750,7 @@ export function LayerPanel( isOpen={isDimensionPanelOpen} isFullscreen={isFullscreen} groupLabel={activeGroup?.dimensionEditorGroupLabel ?? (activeGroup?.groupLabel || '')} - isInlineEditing={Boolean(props?.setIsInlineFlyoutFooterVisible)} + isInlineEditing={Boolean(props?.setIsInlineFlyoutVisible)} handleClose={() => { if (layerDatasource) { if (layerDatasource.updateStateOnCloseDimension) { @@ -828,7 +829,7 @@ export function LayerPanel( addLayer: props.addLayer, removeLayer: props.onRemoveLayer, panelRef, - isInlineEditing: Boolean(props?.setIsInlineFlyoutFooterVisible), + isInlineEditing: Boolean(props?.setIsInlineFlyoutVisible), }} />
    diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts index 6d06dfb7e6aa..2ef775b51f54 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts @@ -29,7 +29,7 @@ export interface ConfigPanelWrapperProps { uiActions: UiActionsStart; getUserMessages?: UserMessagesGetter; hideLayerHeader?: boolean; - setIsInlineFlyoutFooterVisible?: (status: boolean) => void; + setIsInlineFlyoutVisible?: (status: boolean) => void; } export interface LayerPanelProps { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index c1032d144ac3..fd2868b8a406 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -150,6 +150,7 @@ export function getSuggestions({ return filteredCount || filteredCount === datasourceSuggestion.keptLayerIds.length; }) .flatMap((datasourceSuggestion) => { + const datasourceId = datasourceSuggestion.datasourceId; const table = datasourceSuggestion.table; const currentVisualizationState = visualizationId === activeVisualization?.id ? visualizationState : undefined; @@ -170,7 +171,8 @@ export function getSuggestions({ palette, visualizeTriggerFieldContext && 'isVisualizeAction' in visualizeTriggerFieldContext, activeData, - allowMixed + allowMixed, + datasourceId ); }); }) @@ -240,7 +242,8 @@ function getVisualizationSuggestions( mainPalette?: SuggestionRequest['mainPalette'], isFromContext?: boolean, activeData?: Record, - allowMixed?: boolean + allowMixed?: boolean, + datasourceId?: string ) { try { return visualization @@ -253,6 +256,7 @@ function getVisualizationSuggestions( isFromContext, activeData, allowMixed, + datasourceId, }) .map(({ state, ...visualizationSuggestion }) => ({ ...visualizationSuggestion, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss index f139bbe3ca12..cd2ee706c1e1 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.scss @@ -1,6 +1,10 @@ @import '../../mixins'; @import '../../variables'; +.lnsSuggestionPanel .euiAccordion__buttonContent { + width: 100%; +} + .lnsSuggestionPanel__suggestions { @include euiScrollBar; @include lnsOverflowShadowHorizontal; @@ -16,14 +20,9 @@ margin-right: -$euiSizeXS; } -.lnsSuggestionPanel { - padding-bottom: $euiSizeS; -} - .lnsSuggestionPanel__button { position: relative; // Let the expression progress indicator position itself against the button flex: 0 0 auto; - width: $lnsSuggestionWidth !important; // sass-lint:disable-line no-important height: $lnsSuggestionHeight; margin-right: $euiSizeS; margin-left: $euiSizeXS / 2; @@ -58,6 +57,10 @@ } } +.lnsSuggestionPanel__button-fixedWidth { + width: $lnsSuggestionWidth !important; // sass-lint:disable-line no-important +} + .lnsSuggestionPanel__suggestionIcon { color: $euiColorDarkShade; width: 100%; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index a4e65b280d20..c487f31fd82f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -10,6 +10,7 @@ import './suggestion_panel.scss'; import { camelCase, pick } from 'lodash'; import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; import useLocalStorage from 'react-use/lib/useLocalStorage'; import { EuiIcon, @@ -20,7 +21,9 @@ import { EuiButtonEmpty, EuiAccordion, EuiText, + EuiNotificationBadge, } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Ast, fromExpression, toExpression } from '@kbn/interpreter'; import { i18n } from '@kbn/i18n'; @@ -65,6 +68,7 @@ import { selectFramePublicAPI, } from '../../state_management'; import { filterAndSortUserMessages } from '../../app_plugin/get_application_user_messages'; + const MAX_SUGGESTIONS_DISPLAYED = 5; const LOCAL_STORAGE_SUGGESTIONS_PANEL = 'LENS_SUGGESTIONS_PANEL_HIDDEN'; @@ -99,10 +103,13 @@ export interface SuggestionPanelProps { visualizationMap: VisualizationMap; ExpressionRenderer: ReactExpressionRendererType; frame: FramePublicAPI; - getUserMessages: UserMessagesGetter; + getUserMessages?: UserMessagesGetter; nowProvider: DataPublicPluginStart['nowProvider']; core: CoreStart; showOnlyIcons?: boolean; + wrapSuggestions?: boolean; + isAccordionOpen?: boolean; + toggleAccordionCb?: (flag: boolean) => void; } const PreviewRenderer = ({ @@ -165,6 +172,7 @@ const SuggestionPreview = ({ onSelect, showTitleAsLabel, onRender, + wrapSuggestions, }: { onSelect: () => void; preview: { @@ -177,15 +185,30 @@ const SuggestionPreview = ({ selected: boolean; showTitleAsLabel?: boolean; onRender: () => void; + wrapSuggestions?: boolean; }) => { return ( - +
    selectFramePublicAPI(state, datasourceMap)); const changesApplied = useLensSelector(selectChangesApplied); // get user's selection from localStorage, this key defines if the suggestions panel will be hidden or not + const initialAccordionStatusValue = + typeof isAccordionOpen !== 'undefined' ? !Boolean(isAccordionOpen) : false; const [hideSuggestions, setHideSuggestions] = useLocalStorage( LOCAL_STORAGE_SUGGESTIONS_PANEL, - false + initialAccordionStatusValue ); + useEffect(() => { + if (typeof isAccordionOpen !== 'undefined') { + setHideSuggestions(!Boolean(isAccordionOpen)); + } + }, [isAccordionOpen, setHideSuggestions]); const toggleSuggestions = useCallback(() => { setHideSuggestions(!hideSuggestions); - }, [setHideSuggestions, hideSuggestions]); + toggleAccordionCb?.(!hideSuggestions); + }, [setHideSuggestions, hideSuggestions, toggleAccordionCb]); const missingIndexPatterns = getMissingIndexPattern( activeDatasourceId ? datasourceMap[activeDatasourceId] : null, @@ -304,8 +338,10 @@ export function SuggestionPanel({ ), })); - const hasErrors = - getUserMessages(['visualization', 'visualizationInEditor'], { severity: 'error' }).length > 0; + const hasErrors = getUserMessages + ? getUserMessages(['visualization', 'visualizationInEditor'], { severity: 'error' }).length > + 0 + : false; const newStateExpression = currentVisualization.state && currentVisualization.activeId && !hasErrors @@ -450,6 +486,7 @@ export function SuggestionPanel({ selected={lastSelectedSuggestion === -1} showTitleAsLabel onRender={() => onSuggestionRender(0)} + wrapSuggestions={wrapSuggestions} /> )} {!hideSuggestions && @@ -474,64 +511,88 @@ export function SuggestionPanel({ selected={index === lastSelectedSuggestion} onRender={() => onSuggestionRender(index + 1)} showTitleAsLabel={showOnlyIcons} + wrapSuggestions={wrapSuggestions} /> ); })} ); }; - + const title = ( + +

    + +

    +
    + ); return ( -
    - -

    - -

    - - } - forceState={hideSuggestions ? 'closed' : 'open'} - onToggle={toggleSuggestions} - extraAction={ - existsStagedPreview && - !hideSuggestions && ( - - { - dispatchLens(submitSuggestion()); - }} - > - {i18n.translate('xpack.lens.sugegstion.refreshSuggestionLabel', { - defaultMessage: 'Refresh', + + {existsStagedPreview && ( + - - ) - } + > + { + dispatchLens(submitSuggestion()); + }} + > + {i18n.translate('xpack.lens.sugegstion.refreshSuggestionLabel', { + defaultMessage: 'Refresh', + })} + + + )} + {wrapSuggestions && ( + + {suggestions.length + 1} + + )} + + ) + } + > +
    -
    - {changesApplied ? renderSuggestionsUI() : renderApplyChangesPrompt()} -
    - -
    + {changesApplied ? renderSuggestionsUI() : renderApplyChangesPrompt()} +
    + ); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.scss index 391361570d04..2c0d374a7d07 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.scss @@ -149,3 +149,10 @@ 75% { transform: translateY(15%); } 100% { transform: translateY(10%); } } + +.lnsVisualizationToolbar--fixed { + position: fixed; + width: 100%; + z-index: 1; + background-color: $euiColorLightestShade; +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index ea2c8d27086f..f5ee47cbcd29 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -53,10 +53,11 @@ export interface WorkspacePanelWrapperProps { export function VisualizationToolbar(props: { activeVisualization: Visualization | null; framePublicAPI: FramePublicAPI; + isFixedPosition?: boolean; }) { const dispatchLens = useLensDispatch(); const visualization = useLensSelector(selectVisualizationState); - const { activeVisualization } = props; + const { activeVisualization, isFixedPosition } = props; const setVisualizationState = useCallback( (newState: unknown) => { if (!activeVisualization) { @@ -77,7 +78,12 @@ export function VisualizationToolbar(props: { return ( <> {ToolbarComponent && ( - + {ToolbarComponent({ frame: props.framePublicAPI, state: visualization.state, diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index b9d0bae19790..16d730139c14 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -176,7 +176,6 @@ interface LensBaseEmbeddableInput extends EmbeddableInput { onTableRowClick?: ( data: Simplify ) => void; - shouldShowLegendAction?: (actionId: string) => boolean; } export type LensByValueInput = { @@ -748,7 +747,11 @@ export class Embeddable * Gets the Lens embeddable's datasource and visualization states * updates the embeddable input */ - async updateVisualization(datasourceState: unknown, visualizationState: unknown) { + async updateVisualization( + datasourceState: unknown, + visualizationState: unknown, + visualizationType?: string + ) { const viz = this.savedVis; const activeDatasourceId = (this.activeDatasourceId ?? 'formBased') as EditLensConfigurationProps['datasourceId']; @@ -770,7 +773,7 @@ export class Embeddable ), visualizationState, activeVisualization: this.activeVisualizationId - ? this.deps.visualizationMap[this.activeVisualizationId] + ? this.deps.visualizationMap[visualizationType ?? this.activeVisualizationId] : undefined, }); const attrs = { @@ -781,6 +784,7 @@ export class Embeddable datasourceStates, }, references, + visualizationType: visualizationType ?? viz.visualizationType, }; /** @@ -796,6 +800,15 @@ export class Embeddable } } + async updateSuggestion(attrs: LensSavedObjectAttributes) { + const viz = this.savedVis; + const newViz = { + ...viz, + ...attrs, + }; + this.updateInput({ attributes: newViz }); + } + /** * Callback which allows the navigation to the editor. * Used for the Edit in Lens link inside the inline editing flyout. @@ -849,6 +862,7 @@ export class Embeddable ); } @@ -1110,7 +1125,6 @@ export class Embeddable }} noPadding={this.visDisplayOptions.noPadding} docLinks={this.deps.coreStart.docLinks} - shouldShowLegendAction={input.shouldShowLegendAction} /> (a.order ?? Infinity) - (b.order ?? Infinity)) .map((action) => ({ id: action.id, + type: action.type, iconType: action.getIconType({ embeddable, data, trigger: cellValueTrigger })!, displayName: action.getDisplayName({ embeddable, data, trigger: cellValueTrigger }), execute: (cellData) => diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx index d93e3729a654..986f2f65c693 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx @@ -9,6 +9,7 @@ import React, { FC, useEffect } from 'react'; import type { CoreStart } from '@kbn/core/public'; import type { Action, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; +import { PanelLoader } from '@kbn/panel-loader'; import { EuiLoadingChart } from '@elastic/eui'; import { EmbeddableFactory, @@ -160,7 +161,7 @@ const EmbeddablePanelWrapper: FC = ({ }, [embeddable, input]); if (loading || !embeddable) { - return ; + return ; } return ( diff --git a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx index 75b141514f20..82205c5b5990 100644 --- a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx @@ -47,7 +47,6 @@ export interface ExpressionWrapperProps { lensInspector: LensInspector; noPadding?: boolean; docLinks: CoreStart['docLinks']; - shouldShowLegendAction?: (actionId: string) => boolean; } export function ExpressionWrapper({ @@ -74,7 +73,6 @@ export function ExpressionWrapper({ lensInspector, noPadding, docLinks, - shouldShowLegendAction, }: ExpressionWrapperProps) { if (!expression) return null; return ( @@ -106,7 +104,6 @@ export function ExpressionWrapper({ onEvent={handleEvent} hasCompatibleActions={hasCompatibleActions} getCompatibleCellValueActions={getCompatibleCellValueActions} - shouldShowLegendAction={shouldShowLegendAction} />
    diff --git a/x-pack/plugins/lens/public/mocks/dataview_mock.ts b/x-pack/plugins/lens/public/mocks/dataview_mock.ts new file mode 100644 index 000000000000..880b9a3f287d --- /dev/null +++ b/x-pack/plugins/lens/public/mocks/dataview_mock.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; + +const fields = [ + { + name: '_index', + type: 'string', + scripted: false, + filterable: true, + }, + { + name: '@timestamp', + displayName: 'timestamp', + type: 'date', + scripted: false, + filterable: true, + aggregatable: true, + sortable: true, + }, + { + name: 'message', + displayName: 'message', + type: 'string', + scripted: false, + filterable: false, + }, + { + name: 'extension', + displayName: 'extension', + type: 'string', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + scripted: false, + filterable: true, + aggregatable: true, + }, +] as DataView['fields']; + +export const mockDataViewWithTimefield = buildDataViewMock({ + name: 'index-pattern-with-timefield', + fields, + timeFieldName: '%timestamp', +}); diff --git a/x-pack/plugins/lens/public/mocks/index.ts b/x-pack/plugins/lens/public/mocks/index.ts index 6cc3ff02ff92..f90ecc9b99fe 100644 --- a/x-pack/plugins/lens/public/mocks/index.ts +++ b/x-pack/plugins/lens/public/mocks/index.ts @@ -29,6 +29,8 @@ export { renderWithReduxStore, } from './store_mocks'; export { lensPluginMock } from './lens_plugin_mock'; +export { mockDataViewWithTimefield } from './dataview_mock'; +export { mockAllSuggestions } from './suggestions_mock'; export type FrameMock = jest.Mocked; diff --git a/x-pack/plugins/lens/public/mocks/suggestions_mock.ts b/x-pack/plugins/lens/public/mocks/suggestions_mock.ts new file mode 100644 index 000000000000..0ed32fbfd84d --- /dev/null +++ b/x-pack/plugins/lens/public/mocks/suggestions_mock.ts @@ -0,0 +1,291 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Suggestion } from '../types'; + +export const currentSuggestionMock = { + title: 'Heat map', + hide: false, + score: 0.6, + previewIcon: 'heatmap', + visualizationId: 'lnsHeatmap', + visualizationState: { + shape: 'heatmap', + layerId: '46aa21fa-b747-4543-bf90-0b40007c546d', + layerType: 'data', + legend: { + isVisible: true, + position: 'right', + type: 'heatmap_legend', + }, + gridConfig: { + type: 'heatmap_grid', + isCellLabelVisible: false, + isYAxisLabelVisible: true, + isXAxisLabelVisible: true, + isYAxisTitleVisible: false, + isXAxisTitleVisible: false, + }, + valueAccessor: '5b9b8b76-0836-4a12-b9c0-980c9900502f', + xAccessor: '81e332d6-ee37-42a8-a646-cea4fc75d2d3', + }, + keptLayerIds: ['46aa21fa-b747-4543-bf90-0b40007c546d'], + datasourceState: { + layers: { + '46aa21fa-b747-4543-bf90-0b40007c546d': { + index: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + query: { + esql: 'FROM kibana_sample_data_flights | keep Dest, AvgTicketPrice', + }, + columns: [ + { + columnId: '81e332d6-ee37-42a8-a646-cea4fc75d2d3', + fieldName: 'Dest', + meta: { + type: 'string', + }, + }, + { + columnId: '5b9b8b76-0836-4a12-b9c0-980c9900502f', + fieldName: 'AvgTicketPrice', + meta: { + type: 'number', + }, + }, + ], + allColumns: [ + { + columnId: '81e332d6-ee37-42a8-a646-cea4fc75d2d3', + fieldName: 'Dest', + meta: { + type: 'string', + }, + }, + { + columnId: '5b9b8b76-0836-4a12-b9c0-980c9900502f', + fieldName: 'AvgTicketPrice', + meta: { + type: 'number', + }, + }, + ], + timeField: 'timestamp', + }, + }, + fieldList: [], + indexPatternRefs: [], + initialContext: { + dataViewSpec: { + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + version: 'WzM1ODA3LDFd', + title: 'kibana_sample_data_flights', + timeFieldName: 'timestamp', + sourceFilters: [], + fields: { + AvgTicketPrice: { + count: 0, + name: 'AvgTicketPrice', + type: 'number', + esTypes: ['float'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'number', + params: { + pattern: '$0,0.[00]', + }, + }, + shortDotsEnable: false, + isMapped: true, + }, + Dest: { + count: 0, + name: 'Dest', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'string', + }, + shortDotsEnable: false, + isMapped: true, + }, + timestamp: { + count: 0, + name: 'timestamp', + type: 'date', + esTypes: ['date'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'date', + }, + shortDotsEnable: false, + isMapped: true, + }, + }, + allowNoIndex: false, + name: 'Kibana Sample Data Flights', + }, + fieldName: '', + contextualFields: ['Dest', 'AvgTicketPrice'], + query: { + esql: 'FROM "kibana_sample_data_flights"', + }, + }, + }, + datasourceId: 'textBased', + columns: 2, + changeType: 'initial', +} as Suggestion; + +export const mockAllSuggestions = [ + currentSuggestionMock, + { + title: 'Donut', + score: 0.46, + visualizationId: 'lnsPie', + previewIcon: 'pie', + visualizationState: { + shape: 'donut', + layers: [ + { + layerId: '2513a3d4-ad9d-48ea-bd58-8b6419ab97e6', + primaryGroups: ['923f0681-3fe1-4987-aa27-d9c91fb95fa6'], + metrics: ['b5f41c04-4bca-4abe-ae5c-b1d4d6fb00e0'], + numberDisplay: 'percent', + categoryDisplay: 'default', + legendDisplay: 'default', + nestedLegend: false, + layerType: 'data', + }, + ], + }, + keptLayerIds: ['2513a3d4-ad9d-48ea-bd58-8b6419ab97e6'], + datasourceState: { + layers: { + '2513a3d4-ad9d-48ea-bd58-8b6419ab97e6': { + index: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + query: { + esql: 'FROM "kibana_sample_data_flights"', + }, + columns: [ + { + columnId: '923f0681-3fe1-4987-aa27-d9c91fb95fa6', + fieldName: 'Dest', + meta: { + type: 'string', + }, + }, + { + columnId: 'b5f41c04-4bca-4abe-ae5c-b1d4d6fb00e0', + fieldName: 'AvgTicketPrice', + meta: { + type: 'number', + }, + }, + ], + allColumns: [ + { + columnId: '923f0681-3fe1-4987-aa27-d9c91fb95fa6', + fieldName: 'Dest', + meta: { + type: 'string', + }, + }, + { + columnId: 'b5f41c04-4bca-4abe-ae5c-b1d4d6fb00e0', + fieldName: 'AvgTicketPrice', + meta: { + type: 'number', + }, + }, + ], + timeField: 'timestamp', + }, + }, + fieldList: [], + indexPatternRefs: [], + initialContext: { + dataViewSpec: { + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + version: 'WzM1ODA3LDFd', + title: 'kibana_sample_data_flights', + timeFieldName: 'timestamp', + sourceFilters: [], + fields: { + AvgTicketPrice: { + count: 0, + name: 'AvgTicketPrice', + type: 'number', + esTypes: ['float'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'number', + params: { + pattern: '$0,0.[00]', + }, + }, + shortDotsEnable: false, + isMapped: true, + }, + Dest: { + count: 0, + name: 'Dest', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'string', + }, + shortDotsEnable: false, + isMapped: true, + }, + timestamp: { + count: 0, + name: 'timestamp', + type: 'date', + esTypes: ['date'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + format: { + id: 'date', + }, + shortDotsEnable: false, + isMapped: true, + }, + }, + typeMeta: {}, + allowNoIndex: false, + name: 'Kibana Sample Data Flights', + }, + fieldName: '', + contextualFields: ['Dest', 'AvgTicketPrice'], + query: { + esql: 'FROM "kibana_sample_data_flights"', + }, + }, + }, + datasourceId: 'textBased', + columns: 2, + changeType: 'unchanged', + } as Suggestion, +]; diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 63eab92016d5..460864d1c86f 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -127,6 +127,8 @@ import { downloadCsvShareProvider } from './app_plugin/csv_download_provider/csv import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; import type { EditLensConfigurationProps } from './app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; +export type { SaveProps } from './app_plugin'; + export interface LensPluginSetupDependencies { urlForwarding: UrlForwardingSetup; expressions: ExpressionsSetup; diff --git a/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx b/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx index 9d55284cc36c..c4efd626d477 100644 --- a/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx +++ b/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx @@ -6,9 +6,11 @@ */ import { i18n } from '@kbn/i18n'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; import React, { useState } from 'react'; import { EuiPopover, EuiPopoverTitle, EuiSelectableProps } from '@elastic/eui'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; +import { css } from '@emotion/react'; import { type IndexPatternRef } from '../../types'; import { type ChangeIndexPatternTriggerProps, TriggerButton } from './trigger'; @@ -30,43 +32,47 @@ export function ChangeIndexPattern({ const [isPopoverOpen, setPopoverIsOpen] = useState(false); return ( - <> - setPopoverIsOpen(!isPopoverOpen)} - /> - } - panelProps={{ - ['data-test-subj']: 'lnsChangeIndexPatternPopover', - }} - isOpen={isPopoverOpen} - closePopover={() => setPopoverIsOpen(false)} - display="block" - panelPaddingSize="none" - ownFocus + setPopoverIsOpen(!isPopoverOpen)} + /> + } + panelProps={{ + ['data-test-subj']: 'lnsChangeIndexPatternPopover', + }} + isOpen={isPopoverOpen} + closePopover={() => setPopoverIsOpen(false)} + display="block" + panelPaddingSize="none" + ownFocus + > +
    -
    - - {i18n.translate('xpack.lens.indexPattern.changeDataViewTitle', { - defaultMessage: 'Data view', - })} - + + {i18n.translate('xpack.lens.indexPattern.changeDataViewTitle', { + defaultMessage: 'Data view', + })} + - { - onChangeIndexPattern(newId); - setPopoverIsOpen(false); - }} - currentDataViewId={indexPatternId} - selectableProps={selectableProps} - /> -
    - - + { + onChangeIndexPattern(newId); + setPopoverIsOpen(false); + }} + currentDataViewId={indexPatternId} + selectableProps={selectableProps} + /> +
    +
    ); } diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.scss b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.scss index 56cfe41c4b88..6572fd969a5b 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.scss +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.scss @@ -1,6 +1,7 @@ // styles needed to display extra drop targets that are outside of the config panel main area while also allowing to scroll vertically .lnsConfigPanel__overlay { clip-path: polygon(-100% 0, 100% 0, 100% 100%, -100% 100%); + background: $euiColorLightestShade; .kbnOverlayMountWrapper { padding-left: $euiFormMaxWidth; margin-left: -$euiFormMaxWidth; diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts index b1647876581f..8fd011fddfb2 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/helpers.ts @@ -52,6 +52,7 @@ export async function executeAction({ embeddable, startDependencies, overlays, t size: 's', 'data-test-subj': 'customizeLens', type: 'push', + paddingSize: 'm', hideCloseButton: true, onClose: (overlayRef) => { if (overlayTracker) overlayTracker.clearOverlays(); diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 6ac2b98569d7..e5c9fad96d6c 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -198,6 +198,8 @@ export interface TableSuggestion { * The change type indicates what was changed in this table compared to the currently active table of this layer. */ changeType: TableChangeType; + + notAssignedMetrics?: boolean; } /** @@ -509,6 +511,8 @@ export interface Datasource { ) => Promise; injectReferencesToLayers?: (state: T, references?: SavedObjectReference[]) => T; + + suggestsLimitedColumns?: (state: T) => boolean; } export interface DatasourceFixAction { @@ -746,6 +750,7 @@ export interface OperationMetadata { export interface OperationDescriptor extends Operation { hasTimeShift: boolean; hasReducedTimeRange: boolean; + inMetricDimension?: boolean; } export interface VisualizationConfigProps { @@ -882,6 +887,7 @@ export interface SuggestionRequest { subVisualizationId?: string; activeData?: Record; allowMixed?: boolean; + datasourceId?: string; } /** @@ -1416,6 +1422,7 @@ export type LensTopNavMenuEntryGenerator = (props: { export interface LensCellValueAction { id: string; iconType: string; + type?: string; displayName: string; execute: (data: CellValueContext['data']) => void; } diff --git a/x-pack/plugins/lens/public/vis_type_alias.ts b/x-pack/plugins/lens/public/vis_type_alias.ts index 2fc493df38ed..20822ee76a09 100644 --- a/x-pack/plugins/lens/public/vis_type_alias.ts +++ b/x-pack/plugins/lens/public/vis_type_alias.ts @@ -11,8 +11,10 @@ import { getBasePath, getEditPath } from '../common/constants'; import { getLensClient } from './persistence/lens_client'; export const getLensAliasConfig = (): VisTypeAlias => ({ - aliasPath: getBasePath(), - aliasApp: 'lens', + alias: { + path: getBasePath(), + app: 'lens', + }, name: 'lens', promotion: true, title: i18n.translate('xpack.lens.visTypeAlias.title', { @@ -41,8 +43,7 @@ export const getLensAliasConfig = (): VisTypeAlias => ({ title, description, updatedAt, - editUrl: getEditPath(id), - editApp: 'lens', + editor: { editUrl: getEditPath(id), editApp: 'lens' }, icon: 'lensApp', stage: 'production', savedObjectType: type, diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/columns.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/columns.tsx index 51aa500bbfeb..c31486d0a0f0 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/columns.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/columns.tsx @@ -19,10 +19,15 @@ import type { DatatableColumnMeta, } from '@kbn/expressions-plugin/common'; import { EuiDataGridColumnCellAction } from '@elastic/eui/src/components/datagrid/data_grid_types'; +import { FILTER_CELL_ACTION_TYPE } from '@kbn/cell-actions/constants'; import type { FormatFactory } from '../../../../common/types'; import type { ColumnConfig } from '../../../../common/expressions'; import { LensCellValueAction } from '../../../types'; +const hasFilterCellAction = (actions: LensCellValueAction[]) => { + return actions.some(({ type }) => type === FILTER_CELL_ACTION_TYPE); +}; + export const createGridColumns = ( bucketColumns: string[], table: Datatable, @@ -81,7 +86,16 @@ export const createGridColumns = ( const columnArgs = columnConfig.columns.find(({ columnId }) => columnId === field); const cellActions: EuiDataGridColumnCellAction[] = []; - if (filterable && handleFilterClick && !columnArgs?.oneClickFilter) { + + // compatible cell actions from actions registry + const compatibleCellActions = columnCellValueActions?.[colIndex] ?? []; + + if ( + !hasFilterCellAction(compatibleCellActions) && + filterable && + handleFilterClick && + !columnArgs?.oneClickFilter + ) { cellActions.push( ({ rowIndex, columnId, Component }: EuiDataGridColumnCellActionProps) => { const { rowValue, contentsIsDefined, cellContent } = getContentData({ @@ -166,8 +180,6 @@ export const createGridColumns = ( ); } - // Add all the column compatible cell actions - const compatibleCellActions = columnCellValueActions?.[colIndex] ?? []; compatibleCellActions.forEach((action) => { cellActions.push(({ rowIndex, columnId, Component }: EuiDataGridColumnCellActionProps) => { const rowValue = table.rows[rowIndex][columnId]; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx index a6810e77d438..a3f4f6f797ee 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.test.tsx @@ -138,6 +138,26 @@ describe('Datatable Visualization', () => { expect(suggestions.length).toBeGreaterThan(0); }); + it('should force table as suggestion when there are no number fields', () => { + const suggestions = datatableVisualization.getSuggestions({ + state: { + layerId: 'first', + layerType: LayerTypes.DATA, + columns: [{ columnId: 'col1' }], + }, + table: { + isMultiRow: true, + layerId: 'first', + changeType: 'initial', + columns: [strCol('col1'), strCol('col2')], + notAssignedMetrics: true, + }, + keptLayerIds: [], + }); + + expect(suggestions.length).toBeGreaterThan(0); + }); + it('should reject suggestion with static value', () => { function staticValueCol(columnId: string): TableSuggestionColumn { return { @@ -387,6 +407,48 @@ describe('Datatable Visualization', () => { }).groups[2].accessors ).toEqual([{ columnId: 'c' }, { columnId: 'b' }]); }); + + it('should compute the groups correctly for text based languages', () => { + const datasource = createMockDatasource('textBased', { + isTextBasedLanguage: jest.fn(() => true), + }); + datasource.publicAPIMock.getTableSpec.mockReturnValue([ + { columnId: 'c', fields: [] }, + { columnId: 'b', fields: [] }, + ]); + const frame = mockFrame(); + frame.datasourceLayers = { first: datasource.publicAPIMock }; + + const groups = datatableVisualization.getConfiguration({ + layerId: 'first', + state: { + layerId: 'first', + layerType: LayerTypes.DATA, + columns: [{ columnId: 'b', isMetric: true }, { columnId: 'c' }], + }, + frame, + }).groups; + + // rows + expect(groups[0].accessors).toEqual([ + { + columnId: 'c', + triggerIconType: undefined, + }, + ]); + + // columns + expect(groups[1].accessors).toEqual([]); + + // metrics + expect(groups[2].accessors).toEqual([ + { + columnId: 'b', + triggerIconType: undefined, + palette: undefined, + }, + ]); + }); }); describe('#removeDimension', () => { @@ -462,7 +524,11 @@ describe('Datatable Visualization', () => { ).toEqual({ layerId: 'layer1', layerType: LayerTypes.DATA, - columns: [{ columnId: 'b' }, { columnId: 'c' }, { columnId: 'd', isTransposed: false }], + columns: [ + { columnId: 'b' }, + { columnId: 'c' }, + { columnId: 'd', isTransposed: false, isMetric: false }, + ], }); }); @@ -482,7 +548,7 @@ describe('Datatable Visualization', () => { ).toEqual({ layerId: 'layer1', layerType: LayerTypes.DATA, - columns: [{ columnId: 'b', isTransposed: false }, { columnId: 'c' }], + columns: [{ columnId: 'b', isTransposed: false, isMetric: false }, { columnId: 'c' }], }); }); }); diff --git a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx index 35757771af75..505b20bdc3e5 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx @@ -165,11 +165,14 @@ export const getDatatableVisualization = ({ ? 0.5 : 1; + // forcing datatable as a suggestion when there are no metrics (number fields) + const forceSuggestion = Boolean(table?.notAssignedMetrics); + return [ { title, // table with >= 10 columns will have a score of 0.4, fewer columns reduce score - score: (Math.min(table.columns.length, 10) / 10) * 0.4 * changeFactor, + score: forceSuggestion ? 1 : (Math.min(table.columns.length, 10) / 10) * 0.4 * changeFactor, state: { ...(state || {}), layerId: table.layerId, @@ -187,6 +190,13 @@ export const getDatatableVisualization = ({ ]; }, + /* + Datatable works differently on text based datasource and form based + - Form based: It relies on the isBucketed flag to identify groups. It allows only numeric fields + on the Metrics dimension + - Text based: It relies on the isMetric flag to identify groups. It allows all type of fields + on the Metric dimension in cases where there are no numeric columns + **/ getConfiguration({ state, frame, layerId }) { const { sortedColumns, datasource } = getDataSourceAndSortedColumns(state, frame.datasourceLayers, layerId) || {}; @@ -199,9 +209,11 @@ export const getDatatableVisualization = ({ if (!sortedColumns) { return { groups: [] }; } + const isTextBasedLanguage = datasource?.isTextBasedLanguage(); return { groups: [ + // In this group we get columns that are not transposed and are not on the metric dimension { groupId: 'rows', groupLabel: i18n.translate('xpack.lens.datatable.breakdownRows', { @@ -216,11 +228,17 @@ export const getDatatableVisualization = ({ }), layerId: state.layerId, accessors: sortedColumns - .filter( - (c) => - datasource!.getOperationForColumnId(c)?.isBucketed && - !state.columns.find((col) => col.columnId === c)?.isTransposed - ) + .filter((c) => { + const column = state.columns.find((col) => col.columnId === c); + if (isTextBasedLanguage) { + return ( + !datasource!.getOperationForColumnId(c)?.inMetricDimension && + !column?.isMetric && + !column?.isTransposed + ); + } + return datasource!.getOperationForColumnId(c)?.isBucketed && !column?.isTransposed; + }) .map((accessor) => ({ columnId: accessor, triggerIconType: columnMap[accessor].hidden @@ -236,6 +254,7 @@ export const getDatatableVisualization = ({ hideGrouping: true, nestingOrder: 1, }, + // In this group we get columns that are transposed and are not on the metric dimension { groupId: 'columns', groupLabel: i18n.translate('xpack.lens.datatable.breakdownColumns', { @@ -250,11 +269,15 @@ export const getDatatableVisualization = ({ }), layerId: state.layerId, accessors: sortedColumns - .filter( - (c) => + .filter((c) => { + if (isTextBasedLanguage) { + return state.columns.find((col) => col.columnId === c)?.isTransposed; + } + return ( datasource!.getOperationForColumnId(c)?.isBucketed && state.columns.find((col) => col.columnId === c)?.isTransposed - ) + ); + }) .map((accessor) => ({ columnId: accessor })), supportsMoreColumns: true, filterOperations: (op) => op.isBucketed, @@ -263,6 +286,7 @@ export const getDatatableVisualization = ({ hideGrouping: true, nestingOrder: 0, }, + // In this group we get columns are on the metric dimension { groupId: 'metrics', groupLabel: i18n.translate('xpack.lens.datatable.metrics', { @@ -278,7 +302,16 @@ export const getDatatableVisualization = ({ }, layerId: state.layerId, accessors: sortedColumns - .filter((c) => !datasource!.getOperationForColumnId(c)?.isBucketed) + .filter((c) => { + const operation = datasource!.getOperationForColumnId(c); + if (isTextBasedLanguage) { + return ( + operation?.inMetricDimension || + state.columns.find((col) => col.columnId === c)?.isMetric + ); + } + return !operation?.isBucketed; + }) .map((accessor) => { const columnConfig = columnMap[accessor]; const stops = columnConfig?.palette?.params?.stops; @@ -316,7 +349,12 @@ export const getDatatableVisualization = ({ ...prevState, columns: prevState.columns.map((column) => { if (column.columnId === columnId || column.columnId === previousColumn) { - return { ...column, columnId, isTransposed: groupId === 'columns' }; + return { + ...column, + columnId, + isTransposed: groupId === 'columns', + isMetric: groupId === 'metrics', + }; } return column; }), @@ -324,7 +362,10 @@ export const getDatatableVisualization = ({ } return { ...prevState, - columns: [...prevState.columns, { columnId, isTransposed: groupId === 'columns' }], + columns: [ + ...prevState.columns, + { columnId, isTransposed: groupId === 'columns', isMetric: groupId === 'metrics' }, + ], }; }, removeDimension({ prevState, columnId }) { @@ -371,9 +412,11 @@ export const getDatatableVisualization = ({ ): Ast | null { const { sortedColumns, datasource } = getDataSourceAndSortedColumns(state, datasourceLayers, state.layerId) || {}; + const isTextBasedLanguage = datasource?.isTextBasedLanguage(); if ( sortedColumns?.length && + !isTextBasedLanguage && sortedColumns.filter((c) => !datasource!.getOperationForColumnId(c)?.isBucketed).length === 0 ) { return null; @@ -435,6 +478,15 @@ export const getDatatableVisualization = ({ const canColor = datasource!.getOperationForColumnId(column.columnId)?.dataType === 'number'; + let isTransposable = + !isTextBasedLanguage && + !datasource!.getOperationForColumnId(column.columnId)?.isBucketed; + + if (isTextBasedLanguage) { + const operation = datasource!.getOperationForColumnId(column.columnId); + isTransposable = Boolean(column?.isMetric || operation?.inMetricDimension); + } + const datatableColumnFn = buildExpressionFunction( 'lens_datatable_column', { @@ -443,8 +495,7 @@ export const getDatatableVisualization = ({ oneClickFilter: column.oneClickFilter, width: column.width, isTransposed: column.isTransposed, - transposable: !datasource!.getOperationForColumnId(column.columnId)?.isBucketed, - alignment: column.alignment, + transposable: isTransposable, colorMode: canColor && column.colorMode ? column.colorMode : 'none', palette: paletteService.get(CUSTOM_PALETTE).toExpression(paletteParams), summaryRow: hasNoSummaryRow ? undefined : column.summaryRow!, diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.test.ts b/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.test.ts index ff631ee605a5..8a89bca65a2d 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.test.ts +++ b/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.test.ts @@ -305,6 +305,70 @@ describe('heatmap suggestions', () => { }, ]); }); + + test('when no metric dimension but groups', () => { + expect( + getSuggestions({ + table: { + layerId: 'first', + isMultiRow: true, + columns: [ + { + columnId: 'date-column', + operation: { + isBucketed: true, + dataType: 'date', + scale: 'interval', + label: 'Date', + }, + }, + { + columnId: 'string-column-01', + operation: { + isBucketed: true, + dataType: 'string', + label: 'Bucket 1', + }, + }, + ], + changeType: 'initial', + }, + state: { + layerId: 'first', + layerType: LayerTypes.DATA, + } as HeatmapVisualizationState, + keptLayerIds: ['first'], + }) + ).toEqual([ + { + state: { + layerId: 'first', + layerType: LayerTypes.DATA, + shape: 'heatmap', + xAccessor: 'date-column', + yAccessor: 'string-column-01', + gridConfig: { + type: HEATMAP_GRID_FUNCTION, + isCellLabelVisible: false, + isYAxisLabelVisible: true, + isXAxisLabelVisible: true, + isYAxisTitleVisible: false, + isXAxisTitleVisible: false, + }, + legend: { + isVisible: true, + position: Position.Right, + type: LEGEND_FUNCTION, + }, + }, + title: 'Heat map', + hide: true, + incomplete: true, + previewIcon: IconChartHeatmap, + score: 0, + }, + ]); + }); test('for tables with a single bucket dimension', () => { expect( getSuggestions({ diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.ts b/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.ts index ccb9c1014c25..3f748485bdb0 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.ts +++ b/x-pack/plugins/lens/public/visualizations/heatmap/suggestions.ts @@ -61,6 +61,7 @@ export const getSuggestions: Visualization['getSugges const isSingleBucketDimension = groups.length === 1 && metrics.length === 0; const isOnlyMetricDimension = groups.length === 0 && metrics.length === 1; + const isOnlyBucketDimension = groups.length > 0 && metrics.length === 0; /** * Hide for: @@ -77,6 +78,7 @@ export const getSuggestions: Visualization['getSugges table.changeType === 'reorder' || isSingleBucketDimension || hasOnlyDatehistogramBuckets || + isOnlyBucketDimension || isOnlyMetricDimension; const newState: HeatmapVisualizationState = { @@ -130,7 +132,7 @@ export const getSuggestions: Visualization['getSugges hide, previewIcon: IconChartHeatmap, score: Number(score.toFixed(1)), - incomplete: isSingleBucketDimension || isOnlyMetricDimension, + incomplete: isSingleBucketDimension || isOnlyMetricDimension || isOnlyBucketDimension, }, ]; }; diff --git a/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.test.ts b/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.test.ts index e1803e106f2e..e4b4dc187945 100644 --- a/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.test.ts +++ b/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.test.ts @@ -98,6 +98,7 @@ describe('metric_suggestions', () => { ).map((table) => expect(getSuggestions({ table, keptLayerIds: ['l1'] })).toEqual([])) ); }); + test('does not suggest for a static value', () => { const suggestion = getSuggestions({ table: { @@ -133,6 +134,29 @@ describe('metric_suggestions', () => { expect(suggestion).toHaveLength(0); }); + + test('does not suggest for text based languages', () => { + const col = { + columnId: 'id', + operation: { + dataType: 'number', + label: `Top values`, + isBucketed: false, + }, + } as const; + const suggestion = getSuggestions({ + table: { + columns: [col], + isMultiRow: false, + layerId: 'l1', + changeType: 'unchanged', + }, + keptLayerIds: [], + datasourceId: 'textBased', + }); + + expect(suggestion).toHaveLength(0); + }); test('suggests a basic metric chart', () => { const [suggestion, ...rest] = getSuggestions({ table: { diff --git a/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.ts b/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.ts index c48e463ec83d..7e00322fedcd 100644 --- a/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.ts +++ b/x-pack/plugins/lens/public/visualizations/legacy_metric/metric_suggestions.ts @@ -20,6 +20,7 @@ export function getSuggestions({ table, state, keptLayerIds, + datasourceId, }: SuggestionRequest): Array> { // We only render metric charts for single-row queries. We require a single, numeric column. if ( @@ -39,6 +40,11 @@ export function getSuggestions({ return []; } + // do not return the legacy metric vis for the textbased mode (i.e. ES|QL) + if (datasourceId === 'textBased') { + return []; + } + return [getSuggestion(table)]; } diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/layer_header.tsx b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/layer_header.tsx index 99c7b2bec30d..30ffc3a32b1f 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/layer_header.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/layer_header.tsx @@ -170,7 +170,6 @@ function DataLayerHeader(props: VisualizationLayerWidgetProps) { return ( setPopoverIsOpen(!isPopoverOpen)} @@ -188,7 +187,11 @@ function DataLayerHeader(props: VisualizationLayerWidgetProps) { defaultMessage: 'Layer visualization type', })} -
    +
    { @@ -443,69 +442,5 @@ describe('licensing plugin', () => { expect(removeInterceptorMock).toHaveBeenCalledTimes(1); }); - - it('registers the subscription upsell events', async () => { - const sessionStorage = coreMock.createStorage(); - plugin = new LicensingPlugin(coreMock.createPluginInitializerContext(), sessionStorage); - - const coreSetup = coreMock.createSetup(); - - await plugin.setup(coreSetup); - await plugin.stop(); - - expect(findRegisteredEventTypeByName('subscription__upsell__click', coreSetup.analytics)) - .toMatchInlineSnapshot(` - Array [ - Object { - "eventType": "subscription__upsell__click", - "schema": Object { - "feature": Object { - "_meta": Object { - "description": "A human-readable identifier describing the feature that is being promoted", - }, - "type": "keyword", - }, - "source": Object { - "_meta": Object { - "description": "A human-readable identifier describing the location of the beginning of the subscription flow", - }, - "type": "keyword", - }, - }, - }, - ] - `); - expect(findRegisteredEventTypeByName('subscription__upsell__impression', coreSetup.analytics)) - .toMatchInlineSnapshot(` - Array [ - Object { - "eventType": "subscription__upsell__impression", - "schema": Object { - "feature": Object { - "_meta": Object { - "description": "A human-readable identifier describing the feature that is being promoted", - }, - "type": "keyword", - }, - "source": Object { - "_meta": Object { - "description": "A human-readable identifier describing the location of the beginning of the subscription flow", - }, - "type": "keyword", - }, - }, - }, - ] - `); - }); }); }); - -function findRegisteredEventTypeByName( - eventTypeName: string, - analyticsClientMock: jest.Mocked -) { - return analyticsClientMock.registerEventType.mock.calls.find( - ([{ eventType }]) => eventType === eventTypeName - )!; -} diff --git a/x-pack/plugins/licensing/public/plugin.ts b/x-pack/plugins/licensing/public/plugin.ts index bc350675d7dd..3953a29a0821 100644 --- a/x-pack/plugins/licensing/public/plugin.ts +++ b/x-pack/plugins/licensing/public/plugin.ts @@ -8,7 +8,6 @@ import { Observable, Subject, Subscription } from 'rxjs'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; -import { registerEvents as registerSubscriptionTrackingEvents } from '@kbn/subscription-tracking'; import { ILicense } from '../common/types'; import { LicensingPluginSetup, LicensingPluginStart } from './types'; import { createLicenseUpdate } from '../common/license_update'; @@ -85,7 +84,6 @@ export class LicensingPlugin implements Plugin { if (license.isAvailable) { diff --git a/x-pack/plugins/licensing/tsconfig.json b/x-pack/plugins/licensing/tsconfig.json index 1deb735f9946..804bf057afa6 100644 --- a/x-pack/plugins/licensing/tsconfig.json +++ b/x-pack/plugins/licensing/tsconfig.json @@ -14,8 +14,6 @@ "@kbn/std", "@kbn/i18n", "@kbn/analytics-client", - "@kbn/subscription-tracking", - "@kbn/core-analytics-browser", "@kbn/logging-mocks" ], "exclude": ["target/**/*"] diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts index 4ebfcd0fec91..529e1bac24af 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts @@ -53,18 +53,19 @@ export const getExceptionListItemSchemaMock = ( * This is useful for end to end tests where we remove the auto generated parts for comparisons * such as created_at, updated_at, and id. */ -export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = - (): Partial => ({ - comments: [], - created_by: ELASTIC_USER, - description: DESCRIPTION, - entries: ENTRIES, - item_id: ITEM_ID, - list_id: LIST_ID, - name: NAME, - namespace_type: 'single', - os_types: OS_TYPES, - tags: [], - type: ITEM_TYPE, - updated_by: ELASTIC_USER, - }); +export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = ( + elasticUser: string = ELASTIC_USER +): Partial => ({ + comments: [], + created_by: elasticUser, + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + os_types: OS_TYPES, + tags: [], + type: ITEM_TYPE, + updated_by: elasticUser, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index eca17b4c835d..cdf86c2cc720 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -82,17 +82,18 @@ export const getTrustedAppsListSchemaMock = (): ExceptionListSchema => { * This is useful for end to end tests where we remove the auto generated parts for comparisons * such as created_at, updated_at, and id. */ -export const getExceptionResponseMockWithoutAutoGeneratedValues = - (): Partial => ({ - created_by: ELASTIC_USER, - description: DESCRIPTION, - immutable: IMMUTABLE, - list_id: LIST_ID, - name: NAME, - namespace_type: 'single', - os_types: [], - tags: [], - type: ENDPOINT_TYPE, - updated_by: ELASTIC_USER, - version: VERSION, - }); +export const getExceptionResponseMockWithoutAutoGeneratedValues = ( + elasticUser: string = ELASTIC_USER +): Partial => ({ + created_by: elasticUser, + description: DESCRIPTION, + immutable: IMMUTABLE, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + os_types: [], + tags: [], + type: ENDPOINT_TYPE, + updated_by: elasticUser, + version: VERSION, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts index cce497f87335..4d773fa63306 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_item_schema.mock.ts @@ -40,10 +40,12 @@ export const getListItemResponseMock = (): ListItemSchema => ({ * This is useful for end to end tests where we remove the auto generated parts for comparisons * such as created_at, updated_at, and id. */ -export const getListItemResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, +export const getListItemResponseMockWithoutAutoGeneratedValues = ( + elasticUser: string = ELASTIC_USER +): Partial => ({ + created_by: elasticUser, list_id: LIST_ID, type: TYPE, - updated_by: ELASTIC_USER, + updated_by: elasticUser, value: VALUE, }); diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts index abc52634e023..7e6f1647ceb3 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.mock.ts @@ -44,12 +44,14 @@ export const getListResponseMock = (): ListSchema => ({ * This is useful for end to end tests where we remove the auto generated parts for comparisons * such as created_at, updated_at, and id. */ -export const getListResponseMockWithoutAutoGeneratedValues = (): Partial => ({ - created_by: ELASTIC_USER, +export const getListResponseMockWithoutAutoGeneratedValues = ( + elasticUser: string = ELASTIC_USER +): Partial => ({ + created_by: elasticUser, description: DESCRIPTION, immutable: IMMUTABLE, name: NAME, type: TYPE, - updated_by: ELASTIC_USER, + updated_by: elasticUser, version: VERSION, }); diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx index 7edcf5b53f72..5c2bfb904568 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx @@ -20,7 +20,7 @@ import { isOperator, matchesOperator, } from '@kbn/securitysolution-list-utils'; -import { validateFilePathInput } from '@kbn/securitysolution-utils'; +import { validatePotentialWildcardInput } from '@kbn/securitysolution-utils'; import { useFindListsBySize } from '@kbn/securitysolution-list-hooks'; import type { FieldSpec } from '@kbn/data-plugin/common'; import { fields, getField } from '@kbn/data-plugin/common/mocks'; @@ -1050,7 +1050,7 @@ describe('BuilderEntryItem', () => { test('it invokes "setWarningsExist" when invalid value in field value input', async () => { const mockSetWarningsExists = jest.fn(); - (validateFilePathInput as jest.Mock).mockReturnValue('some warning message'); + (validatePotentialWildcardInput as jest.Mock).mockReturnValue('some warning message'); wrapper = mount( { test('it does not invoke "setWarningsExist" when valid value in field value input', async () => { const mockSetWarningsExists = jest.fn(); - (validateFilePathInput as jest.Mock).mockReturnValue(undefined); + (validatePotentialWildcardInput as jest.Mock).mockReturnValue(undefined); wrapper = mount( = ({ const renderOperatorInput = (isFirst: boolean): JSX.Element => { // for event filters forms - // show extra operators for wildcards when field is `file.path.text` - const isFilePathTextField = entry.field !== undefined && entry.field.name === 'file.path.text'; + // show extra operators for wildcards when field supports matches + const doesFieldSupportMatches = entry.field !== undefined && fieldSupportsMatches(entry.field); const isEventFilterList = listType === 'endpoint_events'; const augmentedOperatorsList = - operatorsList && isFilePathTextField && isEventFilterList + operatorsList && doesFieldSupportMatches && isEventFilterList ? operatorsList : operatorsList?.filter((operator) => operator.type !== OperatorTypeEnum.WILDCARD); @@ -358,8 +359,8 @@ export const BuilderEntryItem: React.FC = ({ } }; - // show this when wildcard filename with matches operator - const getWildcardWarning = (precedingWarning: string): React.ReactNode => { + // show this when wildcard with matches operator + const getWildcardWarningInfo = (precedingWarning: string): React.ReactNode => { return (

    {precedingWarning}{' '} @@ -368,7 +369,7 @@ export const BuilderEntryItem: React.FC = ({ content={ } size="m" @@ -430,11 +431,13 @@ export const BuilderEntryItem: React.FC = ({ if (osTypes) { [os] = osTypes as OperatingSystem[]; } - const warning = validateFilePathInput({ os, value: wildcardValue }); + const warning = validatePotentialWildcardInput({ + field: entry.field?.name, + os, + value: wildcardValue, + }); actualWarning = - warning === FILENAME_WILDCARD_WARNING - ? warning && getWildcardWarning(warning) - : warning; + warning === WILDCARD_WARNING ? warning && getWildcardWarningInfo(warning) : warning; } return ( diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts index 3cc350629ff9..ef3982166e19 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/helpers.test.ts @@ -212,7 +212,7 @@ describe('Exception builder helpers', () => { expect(output).toEqual(expected); }); - test('it returns all fields unfiletered if "item.nested" is not "child" or "parent"', () => { + test('it returns all fields unfiltered if "item.nested" is not "child" or "parent"', () => { const payloadIndexPattern = getMockIndexPattern(); const payloadItem: FormattedBuilderEntry = getMockBuilderEntry(); const output = getFilteredIndexPatterns(payloadIndexPattern, payloadItem); diff --git a/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.test.ts b/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.test.ts index 2785def1f292..0b241f4502f7 100644 --- a/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.test.ts +++ b/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.test.ts @@ -10,16 +10,14 @@ import { LogExplorerLocatorDefinition } from './log_explorer_locator'; import { LogExplorerLocatorDependencies } from './types'; const setup = async () => { - const discoverSetupContract: LogExplorerLocatorDependencies = { - discover: { - locator: sharePluginMock.createLocator(), - }, + const logExplorerLocatorDependencies: LogExplorerLocatorDependencies = { + discoverAppLocator: sharePluginMock.createLocator(), }; - const logExplorerLocator = new LogExplorerLocatorDefinition(discoverSetupContract); + const logExplorerLocator = new LogExplorerLocatorDefinition(logExplorerLocatorDependencies); return { logExplorerLocator, - discoverGetLocation: discoverSetupContract.discover.locator?.getLocation, + discoverGetLocation: logExplorerLocatorDependencies.discoverAppLocator?.getLocation, }; }; diff --git a/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.ts b/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.ts index f0265e088a20..2cc0e192c585 100644 --- a/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.ts +++ b/x-pack/plugins/log_explorer/common/locators/log_explorer/log_explorer_locator.ts @@ -29,7 +29,7 @@ export class LogExplorerLocatorDefinition implements LocatorDefinition; } diff --git a/x-pack/plugins/log_explorer/public/components/flyout_detail/flyout_highlights.tsx b/x-pack/plugins/log_explorer/public/components/flyout_detail/flyout_highlights.tsx index 74d65d73f23b..e74ee0a4b813 100644 --- a/x-pack/plugins/log_explorer/public/components/flyout_detail/flyout_highlights.tsx +++ b/x-pack/plugins/log_explorer/public/components/flyout_detail/flyout_highlights.tsx @@ -7,7 +7,10 @@ import React from 'react'; import { FlyoutContentActions } from '@kbn/discover-plugin/public'; import { DataTableRecord } from '@kbn/discover-utils/src/types'; +import { AgentIcon, CloudProvider, CloudProviderIcon } from '@kbn/custom-icons'; import { useMeasure } from 'react-use/lib'; +import { AgentName } from '@kbn/elastic-agent-utils'; +import { first } from 'lodash'; import { FlyoutDoc } from './types'; import * as constants from '../../../common/constants'; import { HighlightField } from './sub_components/highlight_field'; @@ -47,156 +50,170 @@ export function FlyoutHighlights({ }) { const [ref, dimensions] = useMeasure(); const { columns, fieldWidth } = useFlyoutColumnWidth(dimensions.width); + return ( + {/* Service highlight */} {formattedDoc[constants.SERVICE_NAME_FIELD] && ( + } + label={flyoutServiceLabel} + value={flattenedDoc[constants.SERVICE_NAME_FIELD]} width={fieldWidth} /> )} {formattedDoc[constants.TRACE_ID_FIELD] && ( )} - + {/* Infrastructure highlight */} {formattedDoc[constants.HOST_NAME_FIELD] && ( )} {formattedDoc[constants.ORCHESTRATOR_CLUSTER_NAME_FIELD] && ( )} {formattedDoc[constants.ORCHESTRATOR_RESOURCE_ID_FIELD] && ( )} - + {/* Cloud highlight */} {formattedDoc[constants.CLOUD_PROVIDER_FIELD] && ( + } + label={flyoutCloudProviderLabel} + value={flattenedDoc[constants.CLOUD_PROVIDER_FIELD]} width={fieldWidth} /> )} {formattedDoc[constants.CLOUD_REGION_FIELD] && ( )} {formattedDoc[constants.CLOUD_AVAILABILITY_ZONE_FIELD] && ( )} {formattedDoc[constants.CLOUD_PROJECT_ID_FIELD] && ( )} {formattedDoc[constants.CLOUD_INSTANCE_ID_FIELD] && ( )} - + {/* Other highlights */} {formattedDoc[constants.LOG_FILE_PATH_FIELD] && ( )} {formattedDoc[constants.DATASTREAM_NAMESPACE_FIELD] && ( )} {formattedDoc[constants.DATASTREAM_DATASET_FIELD] && ( )} {formattedDoc[constants.AGENT_NAME_FIELD] && ( )} diff --git a/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/highlight_field.tsx b/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/highlight_field.tsx index ca47b1054823..1034a3015cc8 100644 --- a/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/highlight_field.tsx +++ b/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/highlight_field.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiText, copyToClipboard } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiText, copyToClipboard, EuiTextTruncate } from '@elastic/eui'; import React, { ReactNode, useMemo, useState } from 'react'; import { HoverAction, HoverActionType } from './hover_action'; import { @@ -18,21 +18,22 @@ import { import { useDiscoverActionsContext } from '../../../hooks/use_discover_action'; interface HighlightFieldProps { - label: string | ReactNode; field: string; - value: unknown; formattedValue: string; - dataTestSubj: string; + icon?: ReactNode; + label: string | ReactNode; + value: unknown; width: number; } export function HighlightField({ - label, field, - value, formattedValue, - dataTestSubj, + icon, + label, + value, width, + ...props }: HighlightFieldProps) { const filterForText = flyoutHoverActionFilterForText(value); const filterOutText = flyoutHoverActionFilterOutText(value); @@ -89,14 +90,33 @@ export function HighlightField({ [filterForText, filterOutText, actions, field, value, columnAdded] ); return formattedValue ? ( - + {label} - + + + {icon && {icon}} + + + {(truncatedText: string) => ( + + )} + + + + ) : null; diff --git a/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/hover_action.tsx b/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/hover_action.tsx index 5ed25be2b36d..1b5883ed082e 100644 --- a/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/hover_action.tsx +++ b/x-pack/plugins/log_explorer/public/components/flyout_detail/sub_components/hover_action.tsx @@ -7,14 +7,7 @@ import React from 'react'; -import { - EuiFlexGroup, - EuiToolTip, - EuiButtonIcon, - useEuiTheme, - EuiTextTruncate, - EuiText, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiToolTip, EuiButtonIcon, useEuiTheme, EuiFlexItem } from '@elastic/eui'; import type { IconType } from '@elastic/eui'; export interface HoverActionType { @@ -26,12 +19,11 @@ export interface HoverActionType { } interface HoverActionProps { - displayText: string; + children: React.ReactNode; actions: HoverActionType[]; - width: number; } -export const HoverAction = ({ displayText, actions, width }: HoverActionProps) => { +export const HoverAction = ({ children, actions }: HoverActionProps) => { const { euiTheme } = useEuiTheme(); return ( @@ -49,14 +41,7 @@ export const HoverAction = ({ displayText, actions, width }: HoverActionProps) = }, }} > - - {(truncatedText: string) => ( - - )} - + {children} (DISCOVER_APP_LOCATOR); // Register Locators const logExplorerLocator = share.url.locators.create( new LogExplorerLocatorDefinition({ - discover, + discoverAppLocator, }) ); diff --git a/x-pack/plugins/log_explorer/server/plugin.ts b/x-pack/plugins/log_explorer/server/plugin.ts index 140d32a564ca..99ec9e5caa5d 100644 --- a/x-pack/plugins/log_explorer/server/plugin.ts +++ b/x-pack/plugins/log_explorer/server/plugin.ts @@ -5,10 +5,34 @@ * 2.0. */ -import { Plugin } from '@kbn/core/server'; +import { Plugin, CoreSetup } from '@kbn/core/server'; +import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; +import { LogExplorerLocatorDefinition, LogExplorerLocators } from '../common/locators'; +import type { LogExplorerSetupDeps } from './types'; export class LogExplorerServerPlugin implements Plugin { - setup() {} + private locators?: LogExplorerLocators; + + setup(core: CoreSetup, plugins: LogExplorerSetupDeps) { + const { share } = plugins; + const discoverAppLocator = + share.url.locators.get(DISCOVER_APP_LOCATOR); + + // Register Locators + const logExplorerLocator = share.url.locators.create( + new LogExplorerLocatorDefinition({ + discoverAppLocator, + }) + ); + + this.locators = { + logExplorerLocator, + }; + + return { + locators: this.locators, + }; + } start() {} } diff --git a/x-pack/plugins/log_explorer/server/types.ts b/x-pack/plugins/log_explorer/server/types.ts new file mode 100644 index 000000000000..a63f08c95adc --- /dev/null +++ b/x-pack/plugins/log_explorer/server/types.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SharePluginSetup } from '@kbn/share-plugin/server'; + +export interface LogExplorerSetupDeps { + share: SharePluginSetup; +} diff --git a/x-pack/plugins/log_explorer/tsconfig.json b/x-pack/plugins/log_explorer/tsconfig.json index d80736004536..a36d764cbee5 100644 --- a/x-pack/plugins/log_explorer/tsconfig.json +++ b/x-pack/plugins/log_explorer/tsconfig.json @@ -25,7 +25,9 @@ "@kbn/core-ui-settings-browser", "@kbn/discover-utils", "@kbn/deeplinks-observability", - "@kbn/field-formats-plugin" + "@kbn/field-formats-plugin", + "@kbn/custom-icons", + "@kbn/elastic-agent-utils" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx index 335a02ab3a05..e2b61d211583 100644 --- a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx +++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx @@ -77,12 +77,20 @@ export const LogAIAssistant = withProviders(({ doc }: LogAIAssistantProps) => { {aiAssistant.isEnabled() && explainLogMessageMessages ? ( - + ) : null} {aiAssistant.isEnabled() && similarLogMessageMessages ? ( - + ) : null} diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 06c84a7d0626..456748a3752f 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -342,3 +342,6 @@ export enum MASK_OPERATOR { // Maplibre does not provide any feedback when rendering is complete. // Workaround is hard-coded timeout period. export const RENDER_TIMEOUT = 1000; + +export const MIDDLE_TRUNCATION_PROPS = { truncation: 'middle' as const }; +export const SINGLE_SELECTION_AS_TEXT_PROPS = { asPlainText: true }; diff --git a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts index aa4c30fc1cb4..1977173a0207 100644 --- a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.ts @@ -11,6 +11,7 @@ import type { KibanaExecutionContext } from '@kbn/core/public'; import type { Query } from '@kbn/data-plugin/common'; import type { Filter } from '@kbn/es-query'; import type { TimeRange } from '@kbn/es-query'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import { MapExtent } from './map_descriptor'; export type Timeslice = { @@ -91,6 +92,7 @@ export type VectorTileLayerMeta = { export type DataRequestMeta = { // request stop time in milliseconds since epoch requestStopTime?: number; + warnings?: SearchResponseWarning[]; } & Partial< SourceRequestMeta & VectorSourceRequestMeta & diff --git a/x-pack/plugins/maps/common/mvt_request_body.test.ts b/x-pack/plugins/maps/common/mvt_request_body.test.ts index bb8945231b70..3a8c654b2979 100644 --- a/x-pack/plugins/maps/common/mvt_request_body.test.ts +++ b/x-pack/plugins/maps/common/mvt_request_body.test.ts @@ -52,6 +52,26 @@ describe('getHitsTileRequest', () => { expect(path).toEqual('/my%20index/_mvt/my%20location/0/0/0'); }); + test(`Should use requestBody.size to set both track_total_hits and size parameters`, () => { + const searchRequest = { + size: 20000, + runtime_mappings: {}, + query: {}, + }; + const { body } = getHitsTileRequest({ + buffer: 5, + risonRequestBody: rison.encode(searchRequest), + geometryFieldName: 'my location', + hasLabels: true, + index: 'my index', + x: 0, + y: 0, + z: 0, + }); + expect(body?.track_total_hits).toEqual(20001); + expect(body?.size).toEqual(20000); + }); + describe('sort', () => { test(`Should include sort`, () => { const searchRequest = { diff --git a/x-pack/plugins/maps/common/mvt_request_body.ts b/x-pack/plugins/maps/common/mvt_request_body.ts index 9a765505960e..d87707ad6b90 100644 --- a/x-pack/plugins/maps/common/mvt_request_body.ts +++ b/x-pack/plugins/maps/common/mvt_request_body.ts @@ -83,6 +83,7 @@ export function getHitsTileRequest({ if (!requestBody) { throw new Error('Required requestBody parameter not provided'); } + const size = typeof requestBody.size === 'number' ? requestBody.size : 10000; const tileRequestBody = { buffer, grid_precision: 0, // no aggs @@ -90,7 +91,12 @@ export function getHitsTileRequest({ extent: 4096, // full resolution, query: requestBody.query, runtime_mappings: requestBody.runtime_mappings, - track_total_hits: typeof requestBody.size === 'number' ? requestBody.size + 1 : false, + // Number of hits matching the query to count accurately + // Used to notify users of truncated results + track_total_hits: size + 1, + // Maximum number of features to return in the hits layer + // Used to fetch number of hits that correspondes with track_total_hits + size, with_labels: hasLabels, } as SearchMvtRequest['body']; if (requestBody.fields) { diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index d93348dd8ef8..70cdc8ace4cf 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -10,12 +10,18 @@ import { i18n } from '@kbn/i18n'; import type { Map as MbMap } from '@kbn/mapbox-gl'; import type { Query } from '@kbn/es-query'; +import { + getWarningsTitle, + type SearchResponseWarning, + ViewDetailsPopover, +} from '@kbn/search-response-warnings'; import _ from 'lodash'; import React, { ReactElement, ReactNode } from 'react'; import { EuiIcon } from '@elastic/eui'; import { v4 as uuidv4 } from 'uuid'; import { FeatureCollection } from 'geojson'; import { DataRequest } from '../util/data_request'; +import { hasIncompleteResults } from '../util/tile_meta_feature_utils'; import { LAYER_TYPE, MAX_ZOOM, @@ -41,9 +47,16 @@ import { LICENSED_FEATURES } from '../../licensed_features'; import { IESSource } from '../sources/es_source'; import { TileErrorsList } from './tile_errors_list'; -export interface LayerError { +export const INCOMPLETE_RESULTS_WARNING = i18n.translate( + 'xpack.maps.layer.incompleteResultsWarning', + { + defaultMessage: `Layer had issues returning data and results might be incomplete.`, + } +); + +export interface LayerMessage { title: string; - error: ReactNode; + body: ReactNode; } export interface ILayer { @@ -77,7 +90,9 @@ export interface ILayer { isLayerLoading(zoom: number): boolean; isFilteredByGlobalTime(): Promise; hasErrors(): boolean; - getErrors(): LayerError[]; + getErrors(): LayerMessage[]; + hasWarnings(): boolean; + getWarnings(): LayerMessage[]; /* * ILayer.getMbLayerIds returns a list of all mapbox layers assoicated with this layer. @@ -405,14 +420,14 @@ export class AbstractLayer implements ILayer { }); } - getErrors(): LayerError[] { - const errors: LayerError[] = []; + getErrors(): LayerMessage[] { + const errors: LayerMessage[] = []; const sourceError = this.getSourceDataRequest()?.renderError(); if (sourceError) { errors.push({ title: this._getSourceErrorTitle(), - error: sourceError, + body: sourceError, }); } @@ -421,13 +436,59 @@ export class AbstractLayer implements ILayer { title: i18n.translate('xpack.maps.layer.tileErrorTitle', { defaultMessage: `An error occurred when loading layer tiles`, }), - error: , + body: , }); } return errors; } + hasWarnings(): boolean { + const hasDataRequestWarnings = this._dataRequests.some((dataRequest) => { + const dataRequestMeta = dataRequest.getMeta(); + return dataRequestMeta?.warnings?.length; + }); + + if (hasDataRequestWarnings) { + return true; + } + + return this._isTiled() ? this._getTileMetaFeatures().some(hasIncompleteResults) : false; + } + + getWarnings(): LayerMessage[] { + const warningMessages: LayerMessage[] = []; + + const dataRequestWarnings: SearchResponseWarning[] = []; + this._dataRequests.forEach((dataRequest) => { + const dataRequestMeta = dataRequest.getMeta(); + if (dataRequestMeta?.warnings?.length) { + dataRequestWarnings.push(...dataRequestMeta.warnings); + } + }); + + if (dataRequestWarnings.length) { + warningMessages.push({ + title: getWarningsTitle(dataRequestWarnings), + body: ( + <> + {INCOMPLETE_RESULTS_WARNING}{' '} + + + ), + }); + } + + if (this._isTiled() && this._getTileMetaFeatures().some(hasIncompleteResults)) { + warningMessages.push({ + title: '', + body: INCOMPLETE_RESULTS_WARNING, + }); + } + + return warningMessages; + } + async syncData(syncContext: DataRequestContext) { // no-op by default } diff --git a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx index 7b7ac229f154..7bdab791f59f 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer_group/layer_group.tsx @@ -28,7 +28,7 @@ import { import { ISource, SourceEditorArgs } from '../../sources/source'; import { type DataRequestContext } from '../../../actions'; import { getLayersExtent } from '../../../actions/get_layers_extent'; -import { ILayer, LayerIcon, LayerError } from '../layer'; +import { ILayer, LayerIcon, LayerMessage } from '../layer'; import { IStyle } from '../../styles/style'; import { LICENSED_FEATURES } from '../../../licensed_features'; @@ -299,14 +299,33 @@ export class LayerGroup implements ILayer { }); } - getErrors(): LayerError[] { + getErrors(): LayerMessage[] { return this.hasErrors() ? [ { title: i18n.translate('xpack.maps.layerGroup.childrenErrorMessage', { defaultMessage: `An error occurred when loading nested layers`, }), - error: '', + body: '', + }, + ] + : []; + } + + hasWarnings(): boolean { + return this._children.some((child) => { + return child.hasWarnings(); + }); + } + + getWarnings(): LayerMessage[] { + return this.hasWarnings() + ? [ + { + title: i18n.translate('xpack.maps.layerGroup.incompleteResultsWarning', { + defaultMessage: `Nested layer(s) had issues returning data and results might be incomplete.`, + }), + body: '', }, ] : []; diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/blended_vector_layer/blended_vector_layer.ts index a1f2ed1792e0..fec564c838bd 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/blended_vector_layer/blended_vector_layer.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import { IVectorLayer } from '../vector_layer'; import { GeoJsonVectorLayer } from '../geojson_vector_layer'; import { IVectorStyle, VectorStyle } from '../../../styles/vector/vector_style'; @@ -183,7 +184,7 @@ export class BlendedVectorLayer extends GeoJsonVectorLayer implements IVectorLay return layerDescriptor; } - private readonly _isClustered: boolean; + private _isClustered: boolean; private readonly _clusterSource: ESGeoGridSource; private readonly _clusterStyle: VectorStyle; private readonly _documentSource: ESSearchSource; @@ -313,11 +314,22 @@ export class BlendedVectorLayer extends GeoJsonVectorLayer implements IVectorLay let isSyncClustered; try { syncContext.startLoading(dataRequestId, requestToken, requestMeta); + const warnings: SearchResponseWarning[] = []; isSyncClustered = !(await this._documentSource.canLoadAllDocuments( + await this.getDisplayName(this._documentSource), requestMeta, - syncContext.registerCancelCallback.bind(null, requestToken) + syncContext.registerCancelCallback.bind(null, requestToken), + syncContext.inspectorAdapters, + (warning) => { + warnings.push(warning); + } )); - syncContext.stopLoading(dataRequestId, requestToken, { isSyncClustered }, requestMeta); + syncContext.stopLoading( + dataRequestId, + requestToken, + { isSyncClustered }, + { ...requestMeta, warnings } + ); } catch (error) { if (!(error instanceof DataRequestAbortError) || !isSearchSourceAbortError(error)) { syncContext.onLoadError(dataRequestId, requestToken, error); @@ -325,9 +337,11 @@ export class BlendedVectorLayer extends GeoJsonVectorLayer implements IVectorLay return; } if (isSyncClustered) { + this._isClustered = true; activeSource = this._clusterSource; activeStyle = this._clusterStyle; } else { + this._isClustered = false; activeSource = this._documentSource; activeStyle = this._documentStyle; } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx index 4faa32668f7d..30272f503837 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/geojson_vector_layer.tsx @@ -28,7 +28,7 @@ import { DataRequestContext } from '../../../../actions'; import { IVectorStyle, VectorStyle } from '../../../styles/vector/vector_style'; import { ISource } from '../../../sources/source'; import { IVectorSource } from '../../../sources/vector_source'; -import { AbstractLayer, LayerError, LayerIcon } from '../../layer'; +import { AbstractLayer, LayerMessage, LayerIcon } from '../../layer'; import { AbstractVectorLayer, noResultsIcon, @@ -158,7 +158,7 @@ export class GeoJsonVectorLayer extends AbstractVectorLayer { ); } - getErrors(): LayerError[] { + getErrors(): LayerMessage[] { const errors = super.getErrors(); this.getValidJoins().forEach((join) => { @@ -168,7 +168,7 @@ export class GeoJsonVectorLayer extends AbstractVectorLayer { title: i18n.translate('xpack.maps.geojsonVectorLayer.joinErrorTitle', { defaultMessage: `An error occurred when adding join metrics to layer features`, }), - error: joinDescriptor.error, + body: joinDescriptor.error, }); } }); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts index 70049304c9d9..0fceb0729f81 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts @@ -81,8 +81,8 @@ const mockVectorSource = { }, } as unknown as IVectorSource; const innerJoin = new InnerJoin(joinDescriptor, mockVectorSource); -const propertiesMap = new Map>(); -propertiesMap.set('alpha', { [COUNT_PROPERTY_NAME]: 1 }); +const joinMetrics = new Map>(); +joinMetrics.set('alpha', { [COUNT_PROPERTY_NAME]: 1 }); test('should skip join when no state has changed', async () => { const updateSourceData = sinon.spy(); @@ -170,7 +170,7 @@ test('should call updateSourceData with feature collection with updated feature dataHasChanged: false, join: innerJoin, joinIndex: 0, - propertiesMap, + joinMetrics, }, ], updateSourceData, @@ -277,7 +277,7 @@ test('should call updateSourceData when no results returned from terms aggregati dataHasChanged: true, join: innerJoin, joinIndex: 0, - propertiesMap: new Map>(), + joinMetrics: new Map>(), }, ], updateSourceData, @@ -321,8 +321,8 @@ test('should call onJoinError when there are no matching features', async () => const setJoinError = sinon.spy(); // instead of returning military alphabet like "alpha" or "bravo", mismatched key returns numbers, like '1' - const propertiesMapFromMismatchedKey = new Map>(); - propertiesMapFromMismatchedKey.set('1', { [COUNT_PROPERTY_NAME]: 1 }); + const joinMetricsFromMismatchedKey = new Map>(); + joinMetricsFromMismatchedKey.set('1', { [COUNT_PROPERTY_NAME]: 1 }); await performInnerJoins( { @@ -334,7 +334,7 @@ test('should call onJoinError when there are no matching features', async () => dataHasChanged: true, join: innerJoin, joinIndex: 0, - propertiesMap: propertiesMapFromMismatchedKey, + joinMetrics: joinMetricsFromMismatchedKey, }, ], updateSourceData, diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts index 55401c8edcb7..947aed099c9d 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.ts @@ -59,8 +59,8 @@ export async function performInnerJoins( if (joinKey !== null) { joinStatus.keys.push(joinKey); } - const canJoinOnCurrent = joinState.propertiesMap - ? innerJoin.joinPropertiesToFeature(feature, joinState.propertiesMap) + const canJoinOnCurrent = joinState.joinMetrics + ? innerJoin.joinPropertiesToFeature(feature, joinState.joinMetrics) : false; if (canJoinOnCurrent && !joinStatus.joinedWithAtLeastOneFeature) { joinStatus.joinedWithAtLeastOneFeature = true; @@ -108,8 +108,7 @@ async function getJoinError(joinStatus: { return; } - const hasTerms = - joinStatus.joinState.propertiesMap && joinStatus.joinState.propertiesMap.size > 0; + const hasTerms = joinStatus.joinState.joinMetrics && joinStatus.joinState.joinMetrics.size > 0; if (!hasTerms || joinStatus.joinedWithAtLeastOneFeature) { return; @@ -129,9 +128,7 @@ async function getJoinError(joinStatus: { leftFieldName, leftFieldValues: prettyPrintArray(joinStatus.keys), rightFieldName, - rightFieldValues: prettyPrintArray( - Array.from(joinStatus.joinState.propertiesMap!.keys()) - ), + rightFieldValues: prettyPrintArray(Array.from(joinStatus.joinState.joinMetrics!.keys())), }, }); } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/types.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/types.ts index 05fc9dd98eac..930d32fa5355 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/types.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/types.ts @@ -12,5 +12,5 @@ export interface JoinState { dataHasChanged: boolean; join: InnerJoin; joinIndex: number; - propertiesMap?: PropertiesMap; + joinMetrics?: PropertiesMap; } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index b3974bdc67f4..0d60b2dc1b6b 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -50,7 +50,7 @@ import { VectorStyleRequestMeta, } from '../../../../common/descriptor_types'; import { IVectorSource } from '../../sources/vector_source'; -import { LayerIcon, ILayer, LayerError } from '../layer'; +import { LayerIcon, ILayer, LayerMessage } from '../layer'; import { InnerJoin } from '../../joins/inner_join'; import { isSpatialJoin } from '../../joins/is_spatial_join'; import { IField } from '../../fields/field'; @@ -274,7 +274,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { }); } - getErrors(): LayerError[] { + getErrors(): LayerMessage[] { const errors = super.getErrors(); this.getValidJoins().forEach((join) => { @@ -285,7 +285,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { title: i18n.translate('xpack.maps.vectorLayer.joinFetchErrorTitle', { defaultMessage: `An error occurred when loading join metrics`, }), - error: joinError, + body: joinError, }); } }); @@ -469,7 +469,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { startLoading(dataRequestId, requestToken, nextMeta); const layerName = await this.getDisplayName(source); - const styleMeta = await (source as IESSource).loadStylePropsMeta({ + const { styleMeta, warnings } = await (source as IESSource).loadStylePropsMeta({ layerName, style, dynamicStyleProps, @@ -481,7 +481,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { executionContext: dataFilters.executionContext, }); - stopLoading(dataRequestId, requestToken, styleMeta, nextMeta); + stopLoading(dataRequestId, requestToken, styleMeta, { ...nextMeta, warnings }); } catch (error) { if (!(error instanceof DataRequestAbortError)) { onLoadError(dataRequestId, requestToken, error); @@ -605,27 +605,25 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { dataHasChanged: false, join, joinIndex, - propertiesMap: prevDataRequest?.getData() as PropertiesMap, + joinMetrics: prevDataRequest?.getData() as PropertiesMap, }; } try { startLoading(sourceDataId, requestToken, joinRequestMeta); - const leftSourceName = await this._source.getDisplayName(); - const propertiesMap = await joinSource.getPropertiesMap( + const { joinMetrics, warnings } = await joinSource.getJoinMetrics( joinRequestMeta, - leftSourceName, - join.getLeftField().getName(), + await this.getDisplayName(), registerCancelCallback.bind(null, requestToken), inspectorAdapters, featureCollection ); - stopLoading(sourceDataId, requestToken, propertiesMap); + stopLoading(sourceDataId, requestToken, joinMetrics, { warnings }); return { dataHasChanged: true, join, joinIndex, - propertiesMap, + joinMetrics, }; } catch (error) { if (!(error instanceof DataRequestAbortError)) { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 7e23353460df..105b17dcd5a2 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -27,6 +27,13 @@ import { LICENSED_FEATURES } from '../../../licensed_features'; jest.mock('../../../kibana_services'); export class MockSearchSource { + getField(fieldName: string) { + if (fieldName === 'filter') { + return []; + } + + throw new Error(`Unsupported search source field: ${fieldName}`); + } setField = jest.fn(); setParent() {} getSearchRequestBody() { @@ -324,7 +331,7 @@ describe('ESGeoGridSource', () => { index: 'foo-*', renderAs: 'heatmap', requestBody: - "(fields:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':())))", + "(fields:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':()),'7':('0':filter,'1':!((meta:(),query:(exists:(field:bar)))))))", token: '1234', }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index 85cfbd48a2a0..703ab4f45b96 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -14,12 +14,14 @@ import type { AggregationsCompositeAggregate, SearchResponse, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import type { KibanaExecutionContext } from '@kbn/core/public'; import { ISearchSource } from '@kbn/data-plugin/common/search/search_source'; import { DataView } from '@kbn/data-plugin/common'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public'; import { getTileUrlParams } from '@kbn/maps-vector-tile-utils'; +import { type Filter, buildExistsFilter } from '@kbn/es-query'; import { makeESBbox } from '../../../../common/elasticsearch_util'; import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; import { UpdateSourceEditor } from './update_source_editor'; @@ -43,7 +45,12 @@ import { DataRequestAbortError } from '../../util/data_request'; import { LICENSED_FEATURES } from '../../../licensed_features'; import { getHttp } from '../../../kibana_services'; -import { GetFeatureActionsArgs, GeoJsonWithMeta, IMvtVectorSource } from '../vector_source'; +import { + GetFeatureActionsArgs, + GeoJsonWithMeta, + IMvtVectorSource, + getLayerFeaturesRequestName, +} from '../vector_source'; import { DataFilters, ESGeoGridSourceDescriptor, @@ -281,6 +288,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo bufferedExtent, inspectorAdapters, executionContext, + onWarning, }: { searchSource: ISearchSource; searchSessionId?: string; @@ -293,6 +301,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo bufferedExtent: MapExtent; inspectorAdapters: Adapters; executionContext: KibanaExecutionContext; + onWarning: (warning: SearchResponseWarning) => void; }) { const gridsPerRequest: number = Math.floor(DEFAULT_MAX_BUCKETS_LIMIT / bucketsPerGrid); const aggs: any = { @@ -352,34 +361,16 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo : this.getId(); const esResponse: SearchResponse = await this._runEsQuery({ requestId, - requestName: i18n.translate('xpack.maps.source.esGrid.compositeInspector.requestName', { - defaultMessage: '{layerName} {bucketsName} composite request ({requestCount})', - values: { - bucketsName: this.getBucketsName(), - layerName, - requestCount, - }, - }), + requestName: getLayerFeaturesRequestName(`${layerName} (${requestCount})`), searchSource, registerCancelCallback, - requestDescription: i18n.translate( - 'xpack.maps.source.esGrid.compositeInspectorDescription', - { - defaultMessage: - 'Get {bucketsName} from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - bucketsName: this.getBucketsName(), - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - }, - } - ), searchSessionId, executionContext: mergeExecutionContext( { description: 'es_geo_grid_source:cluster_composite' }, executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning, }); features.push(...convertCompositeRespToGeoJson(esResponse, this._descriptor.requestType)); @@ -406,6 +397,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo tooManyBuckets, inspectorAdapters, executionContext, + onWarning, }: { searchSource: ISearchSource; searchSessionId?: string; @@ -417,6 +409,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo tooManyBuckets: boolean; inspectorAdapters: Adapters; executionContext: KibanaExecutionContext; + onWarning: (warning: SearchResponseWarning) => void; }): Promise { const valueAggsDsl = tooManyBuckets ? this.getValueAggsDsl(indexPattern, (metric) => { @@ -446,30 +439,16 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo const esResponse = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.source.esGrid.inspector.requestName', { - defaultMessage: '{layerName} {bucketsName} request', - values: { - bucketsName: this.getBucketsName(), - layerName, - }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.source.esGrid.inspector.requestDescription', { - defaultMessage: - 'Get {bucketsName} from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - bucketsName: this.getBucketsName(), - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - }, - }), searchSessionId, executionContext: mergeExecutionContext( { description: 'es_geo_grid_source:cluster' }, executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning, }); return convertRegularRespToGeoJson(esResponse, this._descriptor.requestType); @@ -516,6 +495,10 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo const supportsCompositeAgg = !(await this._isGeoShape()); const precision = this.getGeoGridPrecision(requestMeta.zoom); + const warnings: SearchResponseWarning[] = []; + const onWarning = (warning: SearchResponseWarning) => { + warnings.push(warning); + }; const features: Feature[] = supportsCompositeAgg && tooManyBuckets ? await this._compositeAggRequest({ @@ -530,6 +513,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo bufferedExtent: requestMeta.buffer, inspectorAdapters, executionContext: requestMeta.executionContext, + onWarning, }) : await this._nonCompositeAggRequest({ searchSource, @@ -542,6 +526,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo tooManyBuckets, inspectorAdapters, executionContext: requestMeta.executionContext, + onWarning, }); return { @@ -551,6 +536,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo }, meta: { areResultsTrimmed: false, + warnings, }, } as GeoJsonWithMeta; } @@ -568,6 +554,11 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo const dataView = await this.getIndexPattern(); const searchSource = await this.makeSearchSource(requestMeta, 0); searchSource.setField('aggs', this.getValueAggsDsl(dataView)); + // Filter out documents without geo fields for broad index-pattern support + searchSource.setField('filter', [ + ...(searchSource.getField('filter') as Filter[]), + buildExistsFilter({ name: this._descriptor.geoField, type: 'geo_point' }, dataView), + ]); const mvtUrlServicePath = getHttp().basePath.prepend( `${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf` diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx index 24cafe66de35..82bb8fec4323 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/es_geo_line_source.tsx @@ -11,6 +11,7 @@ import React from 'react'; import { GeoJsonProperties } from 'geojson'; import { i18n } from '@kbn/i18n'; import { type Filter, buildPhraseFilter } from '@kbn/es-query'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; import { EMPTY_FEATURE_COLLECTION, @@ -33,7 +34,7 @@ import { ESDocField } from '../../fields/es_doc_field'; import { InlineField } from '../../fields/inline_field'; import { UpdateSourceEditor } from './update_source_editor'; import { ImmutableSourceProperty, SourceEditorArgs } from '../source'; -import { GeoJsonWithMeta } from '../vector_source'; +import { GeoJsonWithMeta, getLayerFeaturesRequestName } from '../vector_source'; import { isValidStringConfig } from '../../util/valid_string_config'; import { IField } from '../../fields/field'; import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property'; @@ -261,33 +262,21 @@ export class ESGeoLineSource extends AbstractESAggSource { }, }); + const warnings: SearchResponseWarning[] = []; const resp = await this._runEsQuery({ requestId: `${this.getId()}_tracks`, - requestName: i18n.translate('xpack.maps.source.esGeoLine.timeSeriesTrackRequestName', { - defaultMessage: `'{layerName}' tracks request (time series)`, - values: { - layerName, - }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate( - 'xpack.maps.source.esGeoLine.timeSeriesTrackRequestDescription', - { - defaultMessage: - 'Get tracks from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - }, - } - ), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_geo_line:time_series_tracks' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const { featureCollection } = convertToGeoJson(resp, TIME_SERIES_ID_FIELD_NAME); @@ -303,7 +292,8 @@ export class ESGeoLineSource extends AbstractESAggSource { entityCount, numTrimmedTracks: 0, // geo_line by time series never truncates tracks and instead simplifies tracks totalEntities: resp?.aggregations?.totalEntities?.value ?? 0, - } as ESGeoLineSourceResponseMeta, + warnings, + }, }; } @@ -333,6 +323,7 @@ export class ESGeoLineSource extends AbstractESAggSource { } const indexPattern = await this.getIndexPattern(); + const warnings: SearchResponseWarning[] = []; // Request is broken into 2 requests // 1) fetch entities: filtered by buffer so that top entities in view are returned @@ -367,27 +358,22 @@ export class ESGeoLineSource extends AbstractESAggSource { const entityResp = await this._runEsQuery({ requestId: `${this.getId()}_entities`, requestName: i18n.translate('xpack.maps.source.esGeoLine.entityRequestName', { - defaultMessage: `'{layerName}' entities request`, + defaultMessage: `load track entities ({layerName})`, values: { layerName, }, }), searchSource: entitySearchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.source.esGeoLine.entityRequestDescription', { - defaultMessage: - 'Get entities within map buffer from data view: {dataViewName}, entities: {splitFieldName}', - values: { - dataViewName: indexPattern.getName(), - splitFieldName: this._descriptor.splitField, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_geo_line:entities' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const entityBuckets: Array<{ key: string; doc_count: number }> = _.get( entityResp, @@ -446,29 +432,18 @@ export class ESGeoLineSource extends AbstractESAggSource { }); const tracksResp = await this._runEsQuery({ requestId: `${this.getId()}_tracks`, - requestName: i18n.translate('xpack.maps.source.esGeoLine.trackRequestName', { - defaultMessage: `'{layerName}' tracks request (terms)`, - values: { - layerName, - }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource: tracksSearchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.source.esGeoLine.trackRequestDescription', { - defaultMessage: - 'Get tracks for {numEntities} entities from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - numEntities: entityBuckets.length, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_geo_line:terms_tracks' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const { featureCollection, numTrimmedTracks } = convertToGeoJson( tracksResp, @@ -487,7 +462,8 @@ export class ESGeoLineSource extends AbstractESAggSource { entityCount: entityBuckets.length, numTrimmedTracks, totalEntities, - } as ESGeoLineSourceResponseMeta, + warnings, + }, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.tsx index eaa6f0c716e1..9540a22bf6a4 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.tsx @@ -9,6 +9,7 @@ import React from 'react'; import turfBbox from '@turf/bbox'; import { multiPoint } from '@turf/helpers'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import { type Filter, buildExistsFilter } from '@kbn/es-query'; import { lastValueFrom } from 'rxjs'; import type { @@ -34,7 +35,7 @@ import { VectorSourceRequestMeta, } from '../../../../common/descriptor_types'; import { isValidStringConfig } from '../../util/valid_string_config'; -import { BoundsRequestMeta, GeoJsonWithMeta } from '../vector_source'; +import { BoundsRequestMeta, GeoJsonWithMeta, getLayerFeaturesRequestName } from '../vector_source'; const MAX_GEOTILE_LEVEL = 29; @@ -188,29 +189,21 @@ export class ESPewPewSource extends AbstractESAggSource { buildExistsFilter({ name: this._descriptor.sourceGeoField, type: 'geo_point' }, indexPattern), ]); + const warnings: SearchResponseWarning[] = []; const esResponse = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.pewPew.requestName', { - defaultMessage: '{layerName} paths request', - values: { layerName }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.source.pewPew.inspectorDescription', { - defaultMessage: - 'Get paths from data view: {dataViewName}, source: {sourceFieldName}, destination: {destFieldName}', - values: { - dataViewName: indexPattern.getName(), - destFieldName: this._descriptor.destGeoField, - sourceFieldName: this._descriptor.sourceGeoField, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_pew_pew_source:connections' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const { featureCollection } = convertToLines(esResponse); @@ -219,6 +212,7 @@ export class ESPewPewSource extends AbstractESAggSource { data: featureCollection, meta: { areResultsTrimmed: false, + warnings, }, }; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts index 7f7fde393de9..3585150459b8 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts @@ -53,6 +53,13 @@ describe('ESSearchSource', () => { beforeEach(async () => { const mockSearchSource = { + getField: (fieldName: string) => { + if (fieldName === 'filter') { + return []; + } + + throw new Error(`Unsupported search source field: ${fieldName}`); + }, setField: jest.fn(), getSearchRequestBody() { return { @@ -131,7 +138,7 @@ describe('ESSearchSource', () => { hasLabels: 'false', index: 'foobar-title-*', requestBody: - "(fields:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(_id)),'7':('0':source,'1':!f),'8':('0':fields,'1':!(tooltipField,styleField))))", + "(fields:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(_id)),'7':('0':source,'1':!f),'8':('0':fields,'1':!(tooltipField,styleField)),'9':('0':filter,'1':!((meta:(),query:(exists:(field:bar)))))))", token: '1234', }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index f56155284232..5d0f6aa59c55 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -9,9 +9,10 @@ import _ from 'lodash'; import React, { ReactElement } from 'react'; import type { QueryDslFieldLookup } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import { GeoJsonProperties, Geometry, Position } from 'geojson'; import type { KibanaExecutionContext } from '@kbn/core/public'; -import { type Filter, buildPhraseFilter, type TimeRange } from '@kbn/es-query'; +import { type Filter, buildExistsFilter, buildPhraseFilter, type TimeRange } from '@kbn/es-query'; import type { DataViewField, DataView } from '@kbn/data-plugin/common'; import { lastValueFrom } from 'rxjs'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; @@ -58,6 +59,7 @@ import { import { ImmutableSourceProperty, SourceEditorArgs } from '../source'; import { IField } from '../../fields/field'; import { + getLayerFeaturesRequestName, GetFeatureActionsArgs, GeoJsonWithMeta, IMvtVectorSource, @@ -377,29 +379,21 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } } + const warnings: SearchResponseWarning[] = []; const resp = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.esSearchSource.topHits.requestName', { - defaultMessage: '{layerName} top hits request', - values: { layerName }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.esSearchSource.topHits.requestDescription', { - defaultMessage: - 'Get top hits from data view: {dataViewName}, entities: {entitiesFieldName}, geospatial field: {geoFieldName}', - values: { - dataViewName: indexPattern.getName(), - entitiesFieldName: topHitsGroupByTimeseries ? '_tsid' : topHitsSplitFieldName, - geoFieldName: this._descriptor.geoField, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_search_source:top_hits' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const allHits: any[] = []; @@ -424,6 +418,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource areEntitiesTrimmed, entityCount: entityBuckets.length, totalEntities, + warnings, }, }; } @@ -435,6 +430,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource registerCancelCallback: (callback: () => void) => void, inspectorAdapters: Adapters ) { + const warnings: SearchResponseWarning[] = []; const indexPattern = await this.getIndexPattern(); const { docValueFields, sourceOnlyFields } = getDocValueAndSourceFields( @@ -451,7 +447,15 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource delete requestMetaWithoutTimeslice.timeslice; const useRequestMetaWithoutTimeslice = requestMeta.timeslice !== undefined && - (await this.canLoadAllDocuments(requestMetaWithoutTimeslice, registerCancelCallback)); + (await this.canLoadAllDocuments( + layerName, + requestMetaWithoutTimeslice, + registerCancelCallback, + inspectorAdapters, + (warning) => { + warnings.push(warning); + } + )); const maxResultWindow = await this.getMaxResultWindow(); const searchSource = await this.makeSearchSource( @@ -473,26 +477,18 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource const resp = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.esSearchSource.requestName', { - defaultMessage: '{layerName} documents request', - values: { layerName }, - }), + requestName: getLayerFeaturesRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.esSearchSource.requestDescription', { - defaultMessage: - 'Get documents from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_search_source:doc_search' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const isTimeExtentForTimeslice = @@ -506,6 +502,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource ? requestMeta.timeslice : timerangeToTimeextent(requestMeta.timeFilters), isTimeExtentForTimeslice, + warnings, }, }; } @@ -926,6 +923,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource }) ); + // Filter out documents without geo fields to avoid shard failures for indices without geo fields + searchSource.setField('filter', [ + ...(searchSource.getField('filter') as Filter[]), + buildExistsFilter({ name: this._descriptor.geoField, type: 'geo_point' }, dataView), + ]); + const mvtUrlServicePath = getHttp().basePath.prepend(`${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`); const tileUrlParams = getTileUrlParams({ @@ -990,25 +993,31 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async canLoadAllDocuments( + layerName: string, requestMeta: VectorSourceRequestMeta, - registerCancelCallback: (callback: () => void) => void + registerCancelCallback: (callback: () => void) => void, + inspectorAdapters: Adapters, + onWarning: (warning: SearchResponseWarning) => void ) { - const abortController = new AbortController(); - registerCancelCallback(() => abortController.abort()); const maxResultWindow = await this.getMaxResultWindow(); const searchSource = await this.makeSearchSource(requestMeta, 0); searchSource.setField('trackTotalHits', maxResultWindow + 1); - const { rawResponse: resp } = await lastValueFrom( - searchSource.fetch$({ - abortSignal: abortController.signal, - sessionId: requestMeta.searchSessionId, - legacyHitsTotal: false, - executionContext: mergeExecutionContext( - { description: 'es_search_source:all_doc_counts' }, - requestMeta.executionContext - ), - }) - ); + const resp = await this._runEsQuery({ + requestId: this.getId() + 'features_count', + requestName: i18n.translate('xpack.maps.vectorSource.featuresCountRequestName', { + defaultMessage: 'load features count ({layerName})', + values: { layerName }, + }), + searchSource, + registerCancelCallback, + searchSessionId: requestMeta.searchSessionId, + executionContext: mergeExecutionContext( + { description: 'es_search_source:all_doc_counts' }, + requestMeta.executionContext + ), + requestsAdapter: inspectorAdapters.requests, + onWarning, + }); return !isTotalHitsGreaterThan(resp.hits.total as unknown as TotalHits, maxResultWindow); } diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts index cfde9257ca3b..2b5ec413ba6e 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts @@ -15,13 +15,15 @@ import type { KibanaExecutionContext } from '@kbn/core/public'; import { RequestAdapter } from '@kbn/inspector-plugin/common/adapters/request'; import { lastValueFrom } from 'rxjs'; import type { TimeRange } from '@kbn/es-query'; +import { extractWarnings, type SearchResponseWarning } from '@kbn/search-response-warnings'; import type { IESAggSource } from '../es_agg_source'; import { AbstractVectorSource, BoundsRequestMeta } from '../vector_source'; import { getAutocompleteService, getIndexPatternService, - getTimeFilter, + getInspector, getSearchService, + getTimeFilter, } from '../../../kibana_services'; import { getDataViewNotFoundMessage } from '../../../../common/i18n_getters'; import { createExtentFilter } from '../../../../common/elasticsearch_util'; @@ -34,6 +36,7 @@ import { AbstractSourceDescriptor, DynamicStylePropertyOptions, MapExtent, + StyleMetaData, VectorSourceRequestMeta, } from '../../../../common/descriptor_types'; import { IVectorStyle } from '../../styles/vector/vector_style'; @@ -78,7 +81,7 @@ export interface IESSource extends IVectorSource { searchSessionId?: string; inspectorAdapters: Adapters; executionContext: KibanaExecutionContext; - }): Promise; + }): Promise<{ styleMeta: StyleMetaData; warnings: SearchResponseWarning[] }>; } export class AbstractESSource extends AbstractVectorSource implements IESSource { @@ -157,26 +160,28 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource async _runEsQuery({ registerCancelCallback, - requestDescription, requestId, requestName, searchSessionId, searchSource, executionContext, requestsAdapter, + onWarning, }: { registerCancelCallback: (callback: () => void) => void; - requestDescription: string; requestId: string; requestName: string; searchSessionId?: string; searchSource: ISearchSource; executionContext: KibanaExecutionContext; requestsAdapter: RequestAdapter | undefined; + onWarning?: (warning: SearchResponseWarning) => void; }): Promise { const abortController = new AbortController(); registerCancelCallback(() => abortController.abort()); + const disableWarningToasts = onWarning !== undefined && requestsAdapter !== undefined; + try { const { rawResponse: resp } = await lastValueFrom( searchSource.fetch$({ @@ -187,11 +192,18 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource adapter: requestsAdapter, id: requestId, title: requestName, - description: requestDescription, }, executionContext, + disableWarningToasts, }) ); + + if (disableWarningToasts) { + extractWarnings(resp, getInspector(), requestsAdapter, requestName, requestId).forEach( + onWarning + ); + } + return resp; } catch (error) { if (isSearchSourceAbortError(error)) { @@ -462,7 +474,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource searchSessionId?: string; inspectorAdapters: Adapters; executionContext: KibanaExecutionContext; - }): Promise { + }) { const promises = dynamicStyleProps.map((dynamicStyleProp) => { return dynamicStyleProp.getFieldMetaRequest(); }); @@ -495,30 +507,30 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource } } + const warnings: SearchResponseWarning[] = []; const resp = await this._runEsQuery({ requestId: `${this.getId()}_styleMeta`, requestName: i18n.translate('xpack.maps.source.esSource.stylePropsMetaRequestName', { - defaultMessage: '{layerName} - metadata', + defaultMessage: 'load symbolization ranges ({layerName})', values: { layerName }, }), searchSource, registerCancelCallback, - requestDescription: i18n.translate( - 'xpack.maps.source.esSource.stylePropsMetaRequestDescription', - { - defaultMessage: - 'Elasticsearch request retrieving field metadata used for calculating symbolization bands.', - } - ), searchSessionId, executionContext: mergeExecutionContext( { description: 'es_source:style_meta' }, executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); - return resp.aggregations; + return { + styleMeta: resp.aggregations, + warnings, + }; } getValueSuggestions = async (field: IField, query: string): Promise => { diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/es_distance_source/es_distance_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/es_distance_source/es_distance_source.ts index 8bb3d903d61f..e3cf6f7a1fda 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/es_distance_source/es_distance_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/es_distance_source/es_distance_source.ts @@ -7,6 +7,7 @@ import { FeatureCollection } from 'geojson'; import { i18n } from '@kbn/i18n'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import type { Query } from '@kbn/es-query'; import { ISearchSource } from '@kbn/data-plugin/public'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; @@ -19,7 +20,6 @@ import { ESDistanceSourceDescriptor, VectorSourceRequestMeta, } from '../../../../../common/descriptor_types'; -import { PropertiesMap } from '../../../../../common/elasticsearch_util'; import { isValidStringConfig } from '../../../util/valid_string_config'; import { IJoinSource } from '../types'; import type { IESAggSource, ESAggsSourceSyncMeta } from '../../es_agg_source'; @@ -27,6 +27,7 @@ import { IField } from '../../../fields/field'; import { mergeExecutionContext } from '../../execution_context_utils'; import { processDistanceResponse } from './process_distance_response'; import { isSpatialSourceComplete } from '../is_spatial_source_complete'; +import { getJoinMetricsRequestName } from '../i18n_utils'; export const DEFAULT_WITHIN_DISTANCE = 5; @@ -80,14 +81,13 @@ export class ESDistanceSource extends AbstractESAggSource implements IJoinSource }); } - async getPropertiesMap( + async getJoinMetrics( requestMeta: VectorSourceRequestMeta, - leftSourceName: string, - leftFieldName: string, + layerName: string, registerCancelCallback: (callback: () => void) => void, inspectorAdapters: Adapters, featureCollection?: FeatureCollection - ): Promise { + ) { if (featureCollection === undefined) { throw new Error( i18n.translate('xpack.maps.esDistanceSource.noFeatureCollectionMsg', { @@ -97,7 +97,10 @@ export class ESDistanceSource extends AbstractESAggSource implements IJoinSource } if (!this.hasCompleteConfig()) { - return new Map(); + return { + joinMetrics: new Map(), + warnings: [], + }; } const distance = `${this._descriptor.distance}km`; @@ -119,7 +122,10 @@ export class ESDistanceSource extends AbstractESAggSource implements IJoinSource } if (!hasFilters) { - return new Map(); + return { + joinMetrics: new Map(), + warnings: [], + }; } const indexPattern = await this.getIndexPattern(); @@ -133,31 +139,27 @@ export class ESDistanceSource extends AbstractESAggSource implements IJoinSource aggs: this.getValueAggsDsl(indexPattern), }, }); + const warnings: SearchResponseWarning[] = []; const rawEsData = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.distanceSource.requestName', { - defaultMessage: '{leftSourceName} within distance join request', - values: { leftSourceName }, - }), + requestName: getJoinMetricsRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.distanceSource.requestDescription', { - defaultMessage: - 'Get metrics from data view: {dataViewName}, geospatial field: {geoFieldName}', - values: { - dataViewName: indexPattern.getName(), - geoFieldName: this._descriptor.geoField, - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_distance_source:distance_join_request' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); - return processDistanceResponse(rawEsData, this.getAggKey(AGG_TYPE.COUNT)); + return { + joinMetrics: processDistanceResponse(rawEsData, this.getAggKey(AGG_TYPE.COUNT)), + warnings, + }; } isFilterByMapBounds(): boolean { diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts index da477c76baab..8a1978f6e7d9 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/es_term_source/es_term_source.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import type { Query } from '@kbn/es-query'; import { ISearchSource } from '@kbn/data-plugin/public'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; @@ -36,6 +37,7 @@ import type { IESAggSource, ESAggsSourceSyncMeta } from '../../es_agg_source'; import { IField } from '../../../fields/field'; import { mergeExecutionContext } from '../../execution_context_utils'; import { isTermSourceComplete } from './is_term_source_complete'; +import { getJoinMetricsRequestName } from '../i18n_utils'; const TERMS_AGG_NAME = 'join'; const TERMS_BUCKET_KEYS_TO_IGNORE = ['key', 'doc_count']; @@ -125,15 +127,17 @@ export class ESTermSource extends AbstractESAggSource implements ITermJoinSource : super.getAggLabel(aggType, fieldLabel); } - async getPropertiesMap( + async getJoinMetrics( requestMeta: VectorSourceRequestMeta, - leftSourceName: string, - leftFieldName: string, + layerName: string, registerCancelCallback: (callback: () => void) => void, inspectorAdapters: Adapters - ): Promise { + ) { if (!this.hasCompleteConfig()) { - return new Map(); + return { + joinMetrics: new Map(), + warnings: [], + }; } const indexPattern = await this.getIndexPattern(); @@ -150,31 +154,28 @@ export class ESTermSource extends AbstractESAggSource implements ITermJoinSource }, }); + const warnings: SearchResponseWarning[] = []; const rawEsData = await this._runEsQuery({ requestId: this.getId(), - requestName: i18n.translate('xpack.maps.termSource.requestName', { - defaultMessage: '{leftSourceName} term join request', - values: { leftSourceName }, - }), + requestName: getJoinMetricsRequestName(layerName), searchSource, registerCancelCallback, - requestDescription: i18n.translate('xpack.maps.termSource.requestDescription', { - defaultMessage: 'Get metrics from data view: {dataViewName}, term field: {termFieldName}', - values: { - dataViewName: indexPattern.getName(), - termFieldName: this._termField.getName(), - }, - }), searchSessionId: requestMeta.searchSessionId, executionContext: mergeExecutionContext( { description: 'es_term_source:terms' }, requestMeta.executionContext ), requestsAdapter: inspectorAdapters.requests, + onWarning: (warning: SearchResponseWarning) => { + warnings.push(warning); + }, }); const countPropertyName = this.getAggKey(AGG_TYPE.COUNT); - return extractPropertiesMap(rawEsData, countPropertyName); + return { + joinMetrics: extractPropertiesMap(rawEsData, countPropertyName), + warnings, + }; } isFilterByMapBounds(): boolean { diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/i18n_utils.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/i18n_utils.ts new file mode 100644 index 000000000000..354fcae53c3a --- /dev/null +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/i18n_utils.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const getJoinMetricsRequestName = (layerName: string) => { + return i18n.translate('xpack.maps.joinSource.joinMetricsRequestName', { + defaultMessage: 'load join metrics ({layerName})', + values: { layerName }, + }); +}; diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts index df9c11a99daa..95b2b6fae1cd 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.test.ts @@ -17,7 +17,7 @@ describe('TableSource', () => { }); }); - describe('getPropertiesMap', () => { + describe('getJoinMetrics', () => { it('should roll up results', async () => { const tableSource = new TableSource({ term: 'iso', @@ -53,18 +53,17 @@ describe('TableSource', () => { ], }); - const propertiesMap = await tableSource.getPropertiesMap( + const { joinMetrics } = await tableSource.getJoinMetrics( {} as unknown as VectorSourceRequestMeta, - 'a', - 'b', + 'layer1', () => {} ); - expect(propertiesMap.size).toEqual(2); - expect(propertiesMap.get('US')).toEqual({ + expect(joinMetrics.size).toEqual(2); + expect(joinMetrics.get('US')).toEqual({ population: 100, }); - expect(propertiesMap.get('CN')).toEqual({ + expect(joinMetrics.get('CN')).toEqual({ population: 400, }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts index c1321649168a..0fb24d198bf7 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts @@ -54,12 +54,11 @@ export class TableSource extends AbstractVectorSource implements ITermJoinSource return `table source ${uuidv4()}`; } - async getPropertiesMap( + async getJoinMetrics( requestMeta: VectorSourceRequestMeta, - leftSourceName: string, - leftFieldName: string, + layerName: string, registerCancelCallback: (callback: () => void) => void - ): Promise { + ) { const propertiesMap: PropertiesMap = new Map(); const columnNames = this._descriptor.__columns.map((column) => { @@ -86,7 +85,10 @@ export class TableSource extends AbstractVectorSource implements ITermJoinSource } } - return propertiesMap; + return { + joinMetrics: propertiesMap, + warnings: [], + }; } getTermField(): IField { diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts index 06c87f3469ec..74d124c6b979 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/types.ts @@ -6,6 +6,7 @@ */ import { FeatureCollection, GeoJsonProperties } from 'geojson'; +import type { SearchResponseWarning } from '@kbn/search-response-warnings'; import type { KibanaExecutionContext } from '@kbn/core/public'; import { Query } from '@kbn/data-plugin/common/query'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; @@ -18,14 +19,16 @@ import { ISource } from '../source'; export interface IJoinSource extends ISource { hasCompleteConfig(): boolean; getWhereQuery(): Query | undefined; - getPropertiesMap( + getJoinMetrics( requestMeta: VectorSourceRequestMeta, - leftSourceName: string, - leftFieldName: string, + layerName: string, registerCancelCallback: (callback: () => void) => void, inspectorAdapters: Adapters, featureCollection?: FeatureCollection - ): Promise; + ): Promise<{ + joinMetrics: PropertiesMap; + warnings: SearchResponseWarning[]; + }>; /* * Use getSyncMeta to expose join configurations that require join data re-fetch when changed. diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/index.ts b/x-pack/plugins/maps/public/classes/sources/vector_source/index.ts index f2f834d1d55d..e33a7c63ad24 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/index.ts +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/index.ts @@ -6,4 +6,12 @@ */ export * from './vector_source'; +import { i18n } from '@kbn/i18n'; export type { IMvtVectorSource } from './mvt_vector_source'; + +export const getLayerFeaturesRequestName = (layerName: string) => { + return i18n.translate('xpack.maps.vectorSource.featuresRequestName', { + defaultMessage: 'load layer features ({layerName})', + values: { layerName }, + }); +}; diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index c4da68816d26..5adaf6ec20c4 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -29,7 +29,7 @@ import { AbstractSource, ISource } from '../source'; import { IField } from '../../fields/field'; import { DataFilters, - ESSearchSourceResponseMeta, + DataRequestMeta, MapExtent, Timeslice, VectorSourceRequestMeta, @@ -43,11 +43,9 @@ export interface SourceStatus { isDeprecated?: boolean; } -export type GeoJsonFetchMeta = ESSearchSourceResponseMeta; - export interface GeoJsonWithMeta { data: FeatureCollection; - meta?: GeoJsonFetchMeta; + meta?: DataRequestMeta; } export interface BoundsRequestMeta { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx index 3de0292292b4..a2c5f69e55e6 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx @@ -6,36 +6,18 @@ */ import React from 'react'; - -import { - EuiComboBox, - EuiComboBoxProps, - EuiComboBoxOptionOption, - EuiHighlight, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; +import { EuiComboBox, EuiComboBoxProps, EuiComboBoxOptionOption } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FieldIcon } from '@kbn/react-field'; -import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../common/constants'; +import { + FIELD_ORIGIN, + MIDDLE_TRUNCATION_PROPS, + SINGLE_SELECTION_AS_TEXT_PROPS, + VECTOR_STYLES, +} from '../../../../../common/constants'; import { StyleField } from '../style_fields_helper'; -function renderOption( - option: EuiComboBoxOptionOption, - searchValue: string, - contentClassName: string -) { - const fieldIcon = option.value ? : null; - return ( - - {fieldIcon} - - {option.label} - - - ); -} - function groupFieldsByOrigin(fields: StyleField[]) { const fieldsByOriginMap = new Map(); fields.forEach((field) => { @@ -56,6 +38,9 @@ function groupFieldsByOrigin(fields: StyleField[]) { label: field.label, disabled: field.isUnsupported, title: field.unsupportedMsg, + prepend: field.type ? ( + + ) : null, }; }) .sort((a, b) => { @@ -129,19 +114,24 @@ export function FieldSelect({ fields, selectedFieldName, onChange, styleName, .. } } + const options = groupFieldsByOrigin(fields); + + const panelMinWidth = calculateWidthFromEntries(fields, ['label']); + return ( ); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx index ad7497d97a6e..d695e605d7b8 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx @@ -8,6 +8,7 @@ import _ from 'lodash'; import React, { ChangeEvent, Component } from 'react'; import { EuiComboBox, EuiComboBoxOptionOption, EuiFieldText } from '@elastic/eui'; +import { SINGLE_SELECTION_AS_TEXT_PROPS } from '../../../../../common/constants'; import { IField } from '../../../fields/field'; interface Props { @@ -132,7 +133,7 @@ export class StopInput extends Component { { test('should extract doc_count = 0 from meta features when there are no matches', () => { @@ -376,3 +381,73 @@ describe('getHitsMeta', () => { }); }); }); + +describe('hasIncompleteResults', () => { + const metaFeature = { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [0, 0], + }, + properties: { + '_clusters.skipped': 0, + '_clusters.partial': 0, + '_shards.failed': 0, + timed_out: false, + 'hits.total.relation': 'eq', + 'hits.total.value': 28, + }, + } as TileMetaFeature; + + test('should return false when all shards and clusters are successful', () => { + expect(hasIncompleteResults(metaFeature)).toBe(false); + }); + + test('should return true when local cluster has time out', () => { + expect( + hasIncompleteResults({ + ...metaFeature, + properties: { + ...metaFeature.properties, + timed_out: true, + }, + }) + ).toBe(true); + }); + + test('should return true when local cluster has shard failure', () => { + expect( + hasIncompleteResults({ + ...metaFeature, + properties: { + ...metaFeature.properties, + '_shards.failed': 1, + }, + }) + ).toBe(true); + }); + + test('should return true when remote cluster is skipped', () => { + expect( + hasIncompleteResults({ + ...metaFeature, + properties: { + ...metaFeature.properties, + '_clusters.skipped': 1, + }, + }) + ).toBe(true); + }); + + test('should return true when remote cluster has shard failure', () => { + expect( + hasIncompleteResults({ + ...metaFeature, + properties: { + ...metaFeature.properties, + '_clusters.partial': 1, + }, + }) + ).toBe(true); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/util/tile_meta_feature_utils.ts b/x-pack/plugins/maps/public/classes/util/tile_meta_feature_utils.ts index ac12399a2e01..0af0b64b77a5 100644 --- a/x-pack/plugins/maps/public/classes/util/tile_meta_feature_utils.ts +++ b/x-pack/plugins/maps/public/classes/util/tile_meta_feature_utils.ts @@ -68,3 +68,35 @@ export function getAggRange( } : null; } + +export function hasIncompleteResults(tileMetaFeature: TileMetaFeature) { + if ( + typeof tileMetaFeature.properties?.timed_out === 'boolean' && + tileMetaFeature.properties.timed_out + ) { + return true; + } + + if ( + typeof tileMetaFeature.properties?.['_shards.failed'] === 'number' && + tileMetaFeature.properties['_shards.failed'] > 0 + ) { + return true; + } + + if ( + typeof tileMetaFeature.properties?.['_clusters.skipped'] === 'number' && + tileMetaFeature.properties['_clusters.skipped'] > 0 + ) { + return true; + } + + if ( + typeof tileMetaFeature.properties?.['_clusters.partial'] === 'number' && + tileMetaFeature.properties['_clusters.partial'] > 0 + ) { + return true; + } + + return false; +} diff --git a/x-pack/plugins/maps/public/components/single_field_select.tsx b/x-pack/plugins/maps/public/components/single_field_select.tsx index 50bbe6da66a7..5a2a8f35755a 100644 --- a/x-pack/plugins/maps/public/components/single_field_select.tsx +++ b/x-pack/plugins/maps/public/components/single_field_select.tsx @@ -7,22 +7,17 @@ import _ from 'lodash'; import React from 'react'; - -import { - EuiComboBox, - EuiComboBoxProps, - EuiComboBoxOptionOption, - EuiHighlight, - EuiFlexGroup, - EuiFlexItem, - EuiToolTip, -} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { EuiComboBox, EuiComboBoxProps, EuiComboBoxOptionOption, EuiToolTip } from '@elastic/eui'; import { FieldIcon } from '@kbn/react-field'; import { DataViewField } from '@kbn/data-views-plugin/public'; +import { calculateWidthFromEntries } from '@kbn/calculate-width-from-char-count'; +import { MIDDLE_TRUNCATION_PROPS } from '../../common/constants'; function fieldsToOptions( fields?: DataViewField[], - isFieldDisabled?: (field: DataViewField) => boolean + isFieldDisabled?: (field: DataViewField) => boolean, + getFieldDisabledReason?: (field: DataViewField) => string | null ): Array> { if (!fields) { return []; @@ -30,12 +25,43 @@ function fieldsToOptions( return fields .map((field) => { + const FieldTypeIcon = field.type ? ( + + ) : null; const option: EuiComboBoxOptionOption = { value: field, label: field.displayName ? field.displayName : field.name, + prepend: FieldTypeIcon, }; if (isFieldDisabled && isFieldDisabled(field)) { option.disabled = true; + + const disabledReason = + option.disabled && getFieldDisabledReason ? getFieldDisabledReason(option.value!) : null; + + if (disabledReason) { + option.prepend = ( + <> + {FieldTypeIcon} + +
    + + + ); + } } return option; }) @@ -63,34 +89,6 @@ export function SingleFieldSelect({ value, ...rest }: Props) { - function renderOption( - option: EuiComboBoxOptionOption, - searchValue: string, - contentClassName: string - ) { - const content = ( - - - - - - {option.label} - - - ); - - const disabledReason = - option.disabled && getFieldDisabledReason ? getFieldDisabledReason(option.value!) : null; - - return disabledReason ? ( - - {content} - - ) : ( - content - ); - } - const onSelection = (selectedOptions: Array>) => { onChange(_.get(selectedOptions, '0.value.name')); }; @@ -108,14 +106,19 @@ export function SingleFieldSelect({ } } + const options = fieldsToOptions(fields, isFieldDisabled, getFieldDisabledReason); + + const panelMinWidth = calculateWidthFromEntries(options, ['label']); + return ( ); diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_error_cache.ts b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_error_cache.ts index 9d54457056f7..213f88376231 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_error_cache.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_error_cache.ts @@ -18,6 +18,15 @@ export function getErrorCacheTileKey(canonical: { x: number; y: number; z: numbe export class TileErrorCache { private _cache: Record> = {}; + public clearLayer(layerId: string, onClear: () => void) { + if (!(layerId in this._cache)) { + return; + } + + delete this._cache[layerId]; + onClear(); + } + public clearTileError(layerId: string | undefined, tileKey: string, onClear: () => void) { if (!layerId || !(layerId in this._cache)) { return; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.test.tsx index 546001cc23b3..c8d6395c743b 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.test.tsx @@ -12,6 +12,7 @@ import type { Map as MbMap, MapSourceDataEvent } from '@kbn/mapbox-gl'; import type { TileError, TileMetaFeature } from '../../../../common/descriptor_types'; import { TileStatusTracker } from './tile_status_tracker'; import { ILayer } from '../../../classes/layers/layer'; +import type { IVectorSource } from '../../../classes/sources/vector_source'; class MockMbMap { public listeners: Array<{ type: string; callback: (e: unknown) => void }> = []; @@ -249,6 +250,53 @@ describe('TileStatusTracker', () => { expect(tileErrorsMap.get('layer2')).toBeUndefined(); }); + test('should clear layer tile errors when layer is not tiled', async () => { + const mockMbMap = new MockMbMap(); + const layer1 = createMockLayer('layer1', 'layer1Source'); + + const wrapper = mount( + + ); + + mockMbMap.emit( + 'sourcedataloading', + createSourceDataEvent('layer1Source', IN_VIEW_CANONICAL_TILE) + ); + mockMbMap.emit('error', { + ...createSourceDataEvent('layer1Source', IN_VIEW_CANONICAL_TILE), + error: { + message: 'simulated error', + }, + }); + + // simulate delay. Cache-checking is debounced. + await sleep(300); + + expect(tileErrorsMap.get('layer1')?.length).toBe(1); + + const geojsonLayer1 = createMockLayer('layer1', 'layer1Source'); + geojsonLayer1.getSource = () => { + return { + isESSource() { + return true; + }, + isMvt() { + return false; + }, + } as unknown as IVectorSource; + }; + wrapper.setProps({ layerList: [geojsonLayer1] }); + + // simulate delay. Cache-checking is debounced. + await sleep(300); + + expect(tileErrorsMap.get('layer1')).toBeUndefined(); + }); + test('should only return tile errors within map zoom', async () => { const mockMbMap = new MockMbMap(); diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.tsx index ccb1ca6d06c5..972e691f6695 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tile_status_tracker/tile_status_tracker.tsx @@ -12,6 +12,7 @@ import type { AJAXError, Map as MbMap, MapSourceDataEvent } from '@kbn/mapbox-gl import type { TileError, TileMetaFeature } from '../../../../common/descriptor_types'; import { SPATIAL_FILTERS_LAYER_ID } from '../../../../common/constants'; import { ILayer } from '../../../classes/layers/layer'; +import { isLayerGroup } from '../../../classes/layers/layer_group'; import { IVectorSource } from '../../../classes/sources/vector_source'; import { getTileKey as getCenterTileKey } from '../../../classes/util/geo_tile_utils'; import { boundsToExtent } from '../../../classes/util/maplibre_utils'; @@ -62,6 +63,24 @@ export class TileStatusTracker extends Component { this.props.mbMap.on('moveend', this._onMoveEnd); } + componentDidUpdate() { + this.props.layerList.forEach((layer) => { + if (isLayerGroup(layer)) { + return; + } + + const source = layer.getSource(); + if ( + source.isESSource() && + typeof (source as IVectorSource).isMvt === 'function' && + !(source as IVectorSource).isMvt() + ) { + // clear tile cache when layer is not tiled + this._tileErrorCache.clearLayer(layer.getId(), this._updateTileStatusForAllLayers); + } + }); + } + componentWillUnmount() { this._isMounted = false; this.props.mbMap.off('error', this._onError); diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/__snapshots__/layer_control.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/__snapshots__/layer_control.test.tsx.snap index 20395d067451..81e0f8500451 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/__snapshots__/layer_control.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/__snapshots__/layer_control.test.tsx.snap @@ -120,7 +120,7 @@ exports[`LayerControl isLayerTOCOpen Should render expand button 1`] = ` position="left" > @@ -135,7 +135,7 @@ exports[`LayerControl isLayerTOCOpen Should render expand button with error icon position="left" > @@ -150,7 +150,7 @@ exports[`LayerControl isLayerTOCOpen Should render expand button with loading ic position="left" > diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/expand_button.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/expand_button.tsx index f80a84dc6782..75116d10bbf1 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/expand_button.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/expand_button.tsx @@ -10,12 +10,12 @@ import { EuiButtonEmpty, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; interface Props { - hasErrors: boolean; + hasErrorsOrWarnings: boolean; isLoading: boolean; onClick: () => void; } -export function ExpandButton({ hasErrors, isLoading, onClick }: Props) { +export function ExpandButton({ hasErrorsOrWarnings, isLoading, onClick }: Props) { // isLoading indicates at least one layer is loading. // Expand button should never be disabled. // Not using EuiButton* with iconType props because EuiButton* disables button when isLoading prop is true. @@ -34,7 +34,7 @@ export function ExpandButton({ hasErrors, isLoading, onClick }: Props) {
    ) : ( - + )} ); diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx index c0b0c13ada2d..ed3235bf7af3 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.test.tsx @@ -71,6 +71,9 @@ describe('LayerControl', () => { hasErrors: () => { return false; }, + hasWarnings: () => { + return false; + }, isLayerLoading: () => { return true; }, @@ -86,6 +89,9 @@ describe('LayerControl', () => { hasErrors: () => { return true; }, + hasWarnings: () => { + return false; + }, isLayerLoading: () => { return false; }, diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx index e1c34223483c..b0fc2a7620bd 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_control.tsx @@ -52,8 +52,8 @@ export function LayerControl({ if (isScreenshotMode()) { return null; } - const hasErrors = layerList.some((layer) => { - return layer.hasErrors(); + const hasErrorsOrWarnings = layerList.some((layer) => { + return layer.hasErrors() || layer.hasWarnings(); }); const isLoading = layerList.some((layer) => { return layer.isLayerLoading(zoom); @@ -67,7 +67,11 @@ export function LayerControl({ })} position="left" > - +
    ); } diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap index 9a7816a6de39..f770aeed8749 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/__snapshots__/toc_entry.test.tsx.snap @@ -478,9 +478,22 @@ exports[`TOCEntry props should display layer details when isLegendDetailsOpen is className="mapTocEntry__layerDetails" data-test-subj="mapLayerTOCDetailslayer_1" > -
    - TOC details mock -
    + { + const mockLayer = { + getErrors: () => { + return [ + { + title: 'simulated error', + body:
    , + }, + ]; + }, + getWarnings: () => { + return [ + { + title: 'simulated warning', + body:
    , + }, + ]; + }, + renderLegendDetails: () => { + return
    ; + }, + } as unknown as ILayer; + + test('Should only render errors when layer contains errors', () => { + render(); + screen.getByTestId('layer-error'); + const error = screen.queryByTestId('layer-error'); + expect(error).not.toBeNull(); + const warning = screen.queryByTestId('layer-warning'); + expect(warning).toBeNull(); + const legend = screen.queryByTestId('layer-legend'); + expect(legend).toBeNull(); + }); + + test('Should render warnings and legend when layer contains warnings', () => { + render( + { + return []; + }, + }} + /> + ); + const error = screen.queryByTestId('layer-error'); + expect(error).toBeNull(); + const warning = screen.queryByTestId('layer-warning'); + expect(warning).not.toBeNull(); + const legend = screen.queryByTestId('layer-legend'); + expect(legend).not.toBeNull(); + }); +}); diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/legend_details.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/legend_details.tsx new file mode 100644 index 000000000000..1561d47aa494 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/legend_details.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import type { ILayer } from '../../../../../classes/layers/layer'; + +interface Props { + layer: ILayer; +} + +export function LegendDetails({ layer }: Props) { + const errors = layer.getErrors(); + if (errors.length) { + return ( + <> + {errors.map(({ title, body }, index) => ( +
    + + {body} + + +
    + ))} + + ); + } + + const warnings = layer.getWarnings(); + return warnings.length ? ( + <> + {warnings.map(({ title, body }, index) => ( +
    + + {body} + + +
    + ))} + {layer.renderLegendDetails()} + + ) : ( + layer.renderLegendDetails() + ); +} diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx index eb77812d5b62..488f9a64083d 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry.tsx @@ -9,14 +9,7 @@ import React, { Component } from 'react'; import classNames from 'classnames'; import type { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - EuiIcon, - EuiButtonIcon, - EuiCallOut, - EuiConfirmModal, - EuiButtonEmpty, - EuiSpacer, -} from '@elastic/eui'; +import { EuiIcon, EuiButtonIcon, EuiConfirmModal, EuiButtonEmpty } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; import { @@ -25,6 +18,7 @@ import { EDIT_LAYER_SETTINGS_LABEL, FIT_TO_DATA_LABEL, } from './action_labels'; +import { LegendDetails } from './legend_details'; import { ILayer } from '../../../../../classes/layers/layer'; import { isLayerGroup } from '../../../../../classes/layers/layer_group'; @@ -111,7 +105,9 @@ export class TOCEntry extends Component { async _loadHasLegendDetails() { const hasLegendDetails = - (await this.props.layer.hasLegendDetails()) && + ((await this.props.layer.hasLegendDetails()) || + this.props.layer.hasErrors() || + this.props.layer.hasWarnings()) && this.props.layer.isVisible() && this.props.layer.showAtZoomLevel(this.props.zoom); if (this._isMounted && hasLegendDetails !== this.state.hasLegendDetails) { @@ -150,10 +146,6 @@ export class TOCEntry extends Component { this.props.toggleVisible(this.props.layer.getId()); }; - _getLayerErrors = () => { - return isLayerGroup(this.props.layer) ? [] : this.props.layer.getErrors(); - }; - _renderCancelModal() { if (!this.state.shouldShowModal) { return null; @@ -240,8 +232,7 @@ export class TOCEntry extends Component { } _renderDetailsToggle() { - const errors = this._getLayerErrors(); - if (this.props.isDragging || (!this.state.hasLegendDetails && errors.length === 0)) { + if (this.props.isDragging || !this.state.hasLegendDetails) { return null; } @@ -304,32 +295,6 @@ export class TOCEntry extends Component { ); } - _renderLegendDetails = () => { - if (!this.props.isLegendDetailsOpen) { - return null; - } - - const errors = this._getLayerErrors(); - - return this.state.hasLegendDetails || errors.length ? ( -
    - {errors.length - ? errors.map(({ title, error }, index) => ( -
    - - {error} - - -
    - )) - : this.props.layer.renderLegendDetails()} -
    - ) : null; - }; - _hightlightAsSelectedLayer() { if (this.props.isCombineLayer) { return false; @@ -365,7 +330,16 @@ export class TOCEntry extends Component { > {this._renderLayerHeader()} - {this._renderLegendDetails()} + {this.props.isLegendDetailsOpen && + this.state.hasLegendDetails && + !isLayerGroup(this.props.layer) ? ( +
    + +
    + ) : null} {this._renderDetailsToggle()} diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx index 71d5a9f70849..ba832f2aa321 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_button/toc_entry_button.tsx @@ -9,7 +9,7 @@ import React, { Component, Fragment, ReactNode } from 'react'; import { EuiButtonEmpty, EuiIcon, EuiToolTip, EuiLoadingSpinner } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ILayer } from '../../../../../../classes/layers/layer'; +import { type ILayer, INCOMPLETE_RESULTS_WARNING } from '../../../../../../classes/layers/layer'; import { IVectorSource } from '../../../../../../classes/sources/vector_source'; import { isLayerGroup } from '../../../../../../classes/layers/layer_group'; @@ -18,12 +18,6 @@ interface Footnote { message?: string | null; } -interface IconAndTooltipContent { - icon?: ReactNode; - tooltipContent?: ReactNode; - footnotes: Footnote[]; -} - export interface ReduxStateProps { isUsingSearch: boolean; zoom: number; @@ -69,22 +63,35 @@ export class TOCEntryButton extends Component { } } - getIconAndTooltipContent(): IconAndTooltipContent { - if (this.props.layer.hasErrors()) { - return { - icon: ( - - ), - tooltipContent: this.props.layer - .getErrors() - .map(({ title }) =>
    {title}
    ), - footnotes: [], - }; + getIconAndTooltipContent(): { + icon?: ReactNode; + tooltipContent?: ReactNode; + footnotes: Footnote[]; + postScript?: string; + } { + const errors = this.props.layer.getErrors(); + if (errors.length) { + const errorIcon = ( + + ); + return isLayerGroup(this.props.layer) + ? { + icon: errorIcon, + footnotes: [], + postScript: errors[0].title, + } + : { + icon: errorIcon, + tooltipContent: this.props.layer + .getErrors() + .map(({ title }) =>
    {title}
    ), + footnotes: [], + }; } if (!this.props.layer.isVisible()) { @@ -118,10 +125,26 @@ export class TOCEntryButton extends Component { }; } - const { icon, tooltipContent } = this.props.layer.getLayerIcon(true); + const { icon: layerIcon, tooltipContent } = this.props.layer.getLayerIcon(true); + const warnings = this.props.layer.getWarnings(); + const icon = warnings.length ? ( + + ) : ( + layerIcon + ); if (isLayerGroup(this.props.layer)) { - return { icon, tooltipContent, footnotes: [] }; + return { + icon, + tooltipContent, + footnotes: [], + postScript: warnings.length ? warnings[0].title : undefined, + }; } const footnotes = []; @@ -158,11 +181,12 @@ export class TOCEntryButton extends Component { icon, tooltipContent, footnotes, + postScript: warnings.length ? INCOMPLETE_RESULTS_WARNING : undefined, }; } render() { - const { icon, tooltipContent, footnotes } = this.getIconAndTooltipContent(); + const { icon, tooltipContent, footnotes, postScript } = this.getIconAndTooltipContent(); const footnoteIcons = footnotes.map((footnote, index) => { return ( @@ -189,6 +213,9 @@ export class TOCEntryButton extends Component { {tooltipContent} {footnoteTooltipContent} + {postScript ? ( +

    {postScript}

    + ) : null}
    } data-test-subj="layerTocTooltip" diff --git a/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts b/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts index 922d45b2effc..c8bb1a8fb81b 100644 --- a/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts +++ b/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts @@ -126,6 +126,7 @@ test('Should return elasticsearch vector tile request for hits tiles', () => { type: 'long', }, }, + size: 10000, sort: [ { '@timestamp': { diff --git a/x-pack/plugins/maps/public/maps_vis_type_alias.ts b/x-pack/plugins/maps/public/maps_vis_type_alias.ts index bcbf0170afb2..e16168964361 100644 --- a/x-pack/plugins/maps/public/maps_vis_type_alias.ts +++ b/x-pack/plugins/maps/public/maps_vis_type_alias.ts @@ -24,8 +24,10 @@ export function getMapsVisTypeAlias() { }); return { - aliasApp: APP_ID, - aliasPath: `/${MAP_PATH}`, + alias: { + app: APP_ID, + path: `/${MAP_PATH}`, + }, name: APP_ID, title: APP_NAME, description: appDescription, @@ -45,8 +47,10 @@ export function getMapsVisTypeAlias() { title, description, updatedAt, - editUrl: getEditPath(id), - editApp: APP_ID, + editor: { + editUrl: getEditPath(id), + editApp: APP_ID, + }, icon: APP_ICON, stage: 'production' as VisualizationStage, savedObjectType: type, diff --git a/x-pack/plugins/maps/tsconfig.json b/x-pack/plugins/maps/tsconfig.json index 364a6d24473d..2380d7c3a942 100644 --- a/x-pack/plugins/maps/tsconfig.json +++ b/x-pack/plugins/maps/tsconfig.json @@ -74,6 +74,8 @@ "@kbn/content-management-table-list-view", "@kbn/serverless", "@kbn/logging", + "@kbn/search-response-warnings", + "@kbn/calculate-width-from-char-count", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/metrics_data_access/common/index.ts b/x-pack/plugins/metrics_data_access/common/index.ts index 38970225a864..a236ceeac16f 100644 --- a/x-pack/plugins/metrics_data_access/common/index.ts +++ b/x-pack/plugins/metrics_data_access/common/index.ts @@ -13,7 +13,7 @@ export { metrics, } from './inventory_models'; -export { podSnapshotMetricTypes } from './inventory_models/pod'; +export { podSnapshotMetricTypes } from './inventory_models/kubernetes/pod'; export { containerSnapshotMetricTypes } from './inventory_models/container'; export { awsS3SnapshotMetricTypes } from './inventory_models/aws_s3'; export { hostSnapshotMetricTypes } from './inventory_models/host'; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/create_dashboard_model.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/create_dashboard_model.ts new file mode 100644 index 000000000000..8fc63d9a91a2 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/create_dashboard_model.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DashboardModel } from './types'; + +export const createDashboardModel = ({ + charts, + dependsOn = [], +}: DashboardModel): DashboardModel => { + return { + dependsOn, + charts, + }; +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/index.ts index 0b7389b74537..e1d4f60bc9f7 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/host/index.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/index.ts @@ -12,10 +12,9 @@ import { aws as awsRequiredMetrics, nginx as nginxRequireMetrics, } from '../shared/metrics/required_metrics'; - export { hostSnapshotMetricTypes } from './metrics'; -export const host: InventoryModel = { +export const host: InventoryModel = { id: 'host', displayName: i18n.translate('xpack.metricsData.inventoryModel.host.displayName', { defaultMessage: 'Hosts', diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/cpu_charts.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/cpu_charts.ts new file mode 100644 index 000000000000..307db0766acc --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/cpu_charts.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { StaticValueConfig, XYChartModel } from '@kbn/lens-embeddable-utils'; +import { formulas } from '../formulas'; +import type { ChartArgs } from './types'; + +export const REFERENCE_LINE: StaticValueConfig = { + value: '1', + format: { + id: 'percent', + params: { + decimals: 0, + }, + }, + color: '#6092c0', +}; + +export const cpuUsageBreakdown = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'cpuUsageBreakdown', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.cpuUsage', { + defaultMessage: 'CPU Usage', + }), + layers: [ + { + data: [ + formulas.cpuUsageIowait, + formulas.cpuUsageIrq, + formulas.cpuUsageNice, + formulas.cpuUsageSoftirq, + formulas.cpuUsageSteal, + formulas.cpuUsageUser, + formulas.cpuUsageSystem, + ], + options: { + seriesType: 'area_stacked', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView, + }), +}; + +export const normalizedLoad1m = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'normalizedLoad1m', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.normalizedLoad1m', { + defaultMessage: 'Normalized Load', + }), + layers: [ + { data: [formulas.normalizedLoad1m], layerType: 'data' }, + { data: [REFERENCE_LINE], layerType: 'referenceLine' }, + ], + visualizationType: 'lnsXY', + dataView, + }), +}; + +export const loadBreakdown = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'loadBreakdown', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.load', { + defaultMessage: 'Load', + }), + layers: [ + { + data: [formulas.load1m, formulas.load5m, formulas.load15m], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView, + }), +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/disk_charts.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/disk_charts.ts new file mode 100644 index 000000000000..53f2c3e8ea50 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/disk_charts.ts @@ -0,0 +1,192 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { XYChartModel } from '@kbn/lens-embeddable-utils'; +import { formulas } from '../formulas'; +import type { ChartArgs } from './types'; + +const TOP_VALUES_SIZE = 5; + +export const diskSpaceUsageAvailable = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'diskSpaceUsageAvailable', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskUsage', { + defaultMessage: 'Disk Usage', + }), + layers: [ + { + data: [ + { + ...formulas.diskUsage, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used', + { + defaultMessage: 'Used', + } + ), + }, + { + ...formulas.diskSpaceAvailability, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.available', + { + defaultMessage: 'Available', + } + ), + }, + ], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView, + }), +}; + +export const diskUsageByMountPoint = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'DiskUsageByMountPoint', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint', { + defaultMessage: 'Disk Usage by Mount Point', + }), + layers: [ + { + data: [ + { + ...formulas.diskUsage, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used', + { + defaultMessage: 'Used', + } + ), + }, + ], + options: { + seriesType: 'area', + breakdown: { + type: 'top_values', + field: 'system.filesystem.mount_point', + params: { + size: TOP_VALUES_SIZE, + }, + }, + }, + layerType: 'data', + }, + ], + visualOptions: { + legend: { + isVisible: true, + position: 'bottom', + legendSize: 50 as any, + }, + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + visualizationType: 'lnsXY', + dataView, + }), +}; +export const diskThroughputReadWrite = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'diskThroughputReadWrite', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskIOPS', { + defaultMessage: 'Disk IOPS', + }), + layers: [ + { + data: [ + { + ...formulas.diskIORead, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.read', + { + defaultMessage: 'Read', + } + ), + }, + { + ...formulas.diskIOWrite, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.write', + { + defaultMessage: 'Write', + } + ), + }, + ], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualOptions: { + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + visualizationType: 'lnsXY', + dataView, + }), +}; + +export const diskIOReadWrite = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'diskIOReadWrite', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskThroughput', { + defaultMessage: 'Disk Throughput', + }), + layers: [ + { + data: [ + { + ...formulas.diskReadThroughput, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.read', + { + defaultMessage: 'Read', + } + ), + }, + { + ...formulas.diskWriteThroughput, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.write', + { + defaultMessage: 'Write', + } + ), + }, + ], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualOptions: { + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + visualizationType: 'lnsXY', + dataView, + }), +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/index.ts new file mode 100644 index 000000000000..1f0a3947e461 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/index.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + type ChartModel, + type XYChartModel, + type MetricChartModel, + type XYLayerOptions, + type MetricLayerOptions, + type ChartTypes, + type XYVisualOptions, + XY_ID, +} from '@kbn/lens-embeddable-utils'; +import type { HostFormulaNames } from '../formulas'; +import { formulas } from '../formulas'; + +type ChartByFormula = Record< + HostFormulaNames, + TType extends typeof XY_ID ? XYChartModel : MetricChartModel +>; + +type BaseArgs = Pick & { + formulaIds: HostFormulaNames[]; + visualizationType: TType; + layerOptions?: TType extends typeof XY_ID ? XYLayerOptions : MetricLayerOptions; + visualOptions?: TType extends typeof XY_ID ? XYVisualOptions : never; +}; + +export const createBasicCharts = ({ + formulaIds, + visualizationType, + dataView, + layerOptions, + ...rest +}: BaseArgs): ChartByFormula => { + return formulaIds.reduce((acc, curr) => { + const layers = { + data: visualizationType === XY_ID ? [formulas[curr]] : formulas[curr], + layerType: visualizationType === XY_ID ? 'data' : 'metricTrendline', + options: layerOptions, + }; + + const chartModel = { + id: curr, + title: formulas[curr].label, + dataView, + visualizationType, + layers: visualizationType === XY_ID ? [layers] : layers, + ...rest, + } as TType extends typeof XY_ID ? XYChartModel : MetricChartModel; + + return { + ...acc, + [curr]: chartModel, + }; + }, {} as ChartByFormula); +}; + +// custom charts +export { cpuUsageBreakdown, normalizedLoad1m, loadBreakdown } from './cpu_charts'; +export { + diskIOReadWrite, + diskSpaceUsageAvailable, + diskThroughputReadWrite, + diskUsageByMountPoint, +} from './disk_charts'; +export { memoryUsageBreakdown } from './memory_charts'; +export { rxTx } from './network_charts'; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/memory_charts.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/memory_charts.ts new file mode 100644 index 000000000000..95c30fcdb18e --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/memory_charts.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { XYChartModel } from '@kbn/lens-embeddable-utils'; +import { formulas } from '../formulas'; +import type { ChartArgs } from './types'; + +export const memoryUsageBreakdown = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'memoryUsageBreakdown', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.memoryUsage', { + defaultMessage: 'Memory Usage', + }), + layers: [ + { + data: [ + { + ...formulas.memoryCache, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.cache', + { + defaultMessage: 'Cache', + } + ), + }, + { + ...formulas.memoryUsed, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.used', + { + defaultMessage: 'Used', + } + ), + }, + { + ...formulas.memoryFreeExcludingCache, + label: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.metric.label.free', + { + defaultMessage: 'Free', + } + ), + }, + ], + options: { + seriesType: 'area_stacked', + }, + layerType: 'data', + }, + ], + visualOptions: { + legend: { + isVisible: true, + position: 'bottom', + legendSize: 50 as any, + }, + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + visualizationType: 'lnsXY', + dataView, + }), +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/network_charts.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/network_charts.ts new file mode 100644 index 000000000000..5181b5b07576 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/network_charts.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { XYChartModel } from '@kbn/lens-embeddable-utils'; +import { formulas } from '../formulas'; +import type { ChartArgs } from './types'; + +export const rxTx = { + get: ({ dataView }: ChartArgs): XYChartModel => ({ + id: 'rxTx', + title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network', { + defaultMessage: 'Network', + }), + layers: [ + { + data: [ + { + ...formulas.rx, + label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network.label.rx', { + defaultMessage: 'Inbound (RX)', + }), + }, + { + ...formulas.tx, + label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network.label.tx', { + defaultMessage: 'Outbound (TX)', + }), + }, + ], + options: { + seriesType: 'area', + }, + + layerType: 'data', + }, + ], + visualOptions: { + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + visualizationType: 'lnsXY', + dataView, + }), +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/types.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/types.ts new file mode 100644 index 000000000000..f3634648b4fd --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/charts/types.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataView } from '@kbn/data-views-plugin/common'; + +export interface ChartArgs { + dataView?: DataView; +} diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details.ts new file mode 100644 index 000000000000..c6fc7c1cdc9a --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { DataView } from '@kbn/data-views-plugin/common'; +import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; +import { createDashboardModel } from '../../../create_dashboard_model'; +import { + createBasicCharts, + cpuUsageBreakdown, + diskSpaceUsageAvailable, + diskUsageByMountPoint, + diskIOReadWrite, + diskThroughputReadWrite, + memoryUsageBreakdown, + loadBreakdown, + rxTx, +} from '../charts'; + +export const assetDetails = { + get: ({ + metricsDataView, + logsDataView, + }: { + metricsDataView?: DataView; + logsDataView?: DataView; + }) => { + const commonVisualOptions: XYVisualOptions = { + showDottedLine: true, + missingValues: 'Linear', + }; + + const legend: XYVisualOptions = { + legend: { + isVisible: true, + position: 'bottom', + }, + }; + + const { cpuUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: ['cpuUsage', 'memoryUsage', 'normalizedLoad1m'], + dataView: metricsDataView, + visualOptions: commonVisualOptions, + }); + + const { logRate } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: ['logRate'], + dataView: logsDataView, + visualOptions: commonVisualOptions, + }); + + return createDashboardModel({ + charts: [ + cpuUsage, + { + ...cpuUsageBreakdown.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + memoryUsage, + { + ...memoryUsageBreakdown.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + normalizedLoad1m, + { + ...loadBreakdown.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + logRate, + { + ...diskSpaceUsageAvailable.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskUsageByMountPoint.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskThroughputReadWrite.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskIOReadWrite.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...rxTx.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + ], + }); + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_flyout.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_flyout.ts new file mode 100644 index 000000000000..96436e3d00f4 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_flyout.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { DataView } from '@kbn/data-views-plugin/common'; +import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; +import { createDashboardModel } from '../../../create_dashboard_model'; +import { + createBasicCharts, + diskSpaceUsageAvailable, + diskUsageByMountPoint, + diskIOReadWrite, + diskThroughputReadWrite, + rxTx, +} from '../charts'; + +export const assetDetailsFlyout = { + get: ({ + metricsDataView, + logsDataView, + }: { + metricsDataView?: DataView; + logsDataView?: DataView; + }) => { + const commonVisualOptions: XYVisualOptions = { + showDottedLine: true, + missingValues: 'Linear', + }; + + const legend: XYVisualOptions = { + legend: { + isVisible: true, + position: 'bottom', + }, + }; + + const { cpuUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: ['cpuUsage', 'memoryUsage', 'normalizedLoad1m'], + dataView: metricsDataView, + visualOptions: commonVisualOptions, + }); + + const { logRate } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: ['logRate'], + dataView: logsDataView, + visualOptions: commonVisualOptions, + }); + + return createDashboardModel({ + charts: [ + cpuUsage, + memoryUsage, + normalizedLoad1m, + logRate, + { + ...diskSpaceUsageAvailable.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskUsageByMountPoint.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskThroughputReadWrite.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...diskIOReadWrite.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + { + ...rxTx.get({ dataView: metricsDataView }), + visualOptions: { ...commonVisualOptions, ...legend }, + }, + ], + }); + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_kubernetes_node.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_kubernetes_node.ts new file mode 100644 index 000000000000..cd9dd1591f35 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/asset_details_kubernetes_node.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { DataView } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; +import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; +import { createDashboardModel } from '../../../create_dashboard_model'; +import { formulas } from '../../../kubernetes/node/metrics'; + +export const assetDetailsKubernetesNode = { + get: ({ metricsDataView }: { metricsDataView?: DataView }) => { + const commonVisualOptions: XYVisualOptions = { + showDottedLine: true, + missingValues: 'Linear', + legend: { + isVisible: true, + position: 'bottom', + }, + }; + + return createDashboardModel({ + dependsOn: ['kubernetes.node'], + charts: [ + { + id: 'nodeCpuCapacity', + title: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity', + { + defaultMessage: 'Node CPU Capacity', + } + ), + layers: [ + { + data: [formulas.nodeCpuCapacity, formulas.nodeCpuUsed], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + dataView: metricsDataView, + visualizationType: 'lnsXY', + visualOptions: commonVisualOptions, + }, + { + id: 'nodeMemoryCapacity', + title: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity', + { + defaultMessage: 'Node Memory Capacity', + } + ), + layers: [ + { + data: [formulas.nodeMemoryCapacity, formulas.nodeMemoryUsed], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView: metricsDataView, + visualOptions: commonVisualOptions, + }, + { + id: 'nodeDiskCapacity', + title: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity', + { + defaultMessage: 'Node Disk Capacity', + } + ), + layers: [ + { + data: [formulas.nodeDiskCapacity, formulas.nodeDiskUsed], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView: metricsDataView, + visualOptions: commonVisualOptions, + }, + { + id: 'nodePodCapacity', + title: i18n.translate( + 'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity', + { + defaultMessage: 'Node Pod Capacity', + } + ), + layers: [ + { + data: [formulas.nodePodCapacity, formulas.nodePodUsed], + options: { + seriesType: 'area', + }, + layerType: 'data', + }, + ], + visualizationType: 'lnsXY', + dataView: metricsDataView, + visualOptions: commonVisualOptions, + }, + ], + }); + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/hosts_view.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/hosts_view.ts new file mode 100644 index 000000000000..8ba14603e85a --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/hosts_view.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataView } from '@kbn/data-views-plugin/common'; +import { XYChartModel, XYLayerOptions } from '@kbn/lens-embeddable-utils'; +import { createDashboardModel } from '../../../create_dashboard_model'; +import { createBasicCharts } from '../charts'; + +export const hostsView = { + get: ({ metricsDataView }: { metricsDataView?: DataView }) => { + const commonVisualOptions: XYChartModel['visualOptions'] = { + showDottedLine: true, + missingValues: 'Linear', + }; + + const layerOptions: XYLayerOptions = { + breakdown: { + type: 'top_values', + field: 'host.name', + params: { + size: 20, + }, + }, + }; + + const { + memoryUsage, + memoryFree, + diskUsage, + diskSpaceAvailable, + diskIORead, + diskIOWrite, + diskReadThroughput, + diskWriteThroughput, + rx, + tx, + } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: [ + 'cpuUsage', + 'memoryUsage', + 'normalizedLoad1m', + 'memoryFree', + 'diskUsage', + 'diskSpaceAvailable', + 'diskIORead', + 'diskIOWrite', + 'diskReadThroughput', + 'diskWriteThroughput', + 'rx', + 'tx', + ], + dataView: metricsDataView, + layerOptions, + visualOptions: commonVisualOptions, + }); + + const { cpuUsage, normalizedLoad1m } = createBasicCharts({ + visualizationType: 'lnsXY', + formulaIds: ['cpuUsage', 'normalizedLoad1m'], + layerOptions, + visualOptions: { + ...commonVisualOptions, + yLeftExtent: { + mode: 'dataBounds', + lowerBound: 0, + upperBound: 1, + }, + }, + dataView: metricsDataView, + }); + + return createDashboardModel({ + charts: [ + cpuUsage, + normalizedLoad1m, + memoryUsage, + memoryFree, + diskUsage, + diskSpaceAvailable, + diskIORead, + diskIOWrite, + diskReadThroughput, + diskWriteThroughput, + rx, + tx, + ], + }); + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/index.ts new file mode 100644 index 000000000000..99cb745fa5ed --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { assetDetails } from './asset_details'; +import { assetDetailsFlyout } from './asset_details_flyout'; +import { hostsView } from './hosts_view'; +import { kpi } from './kpi'; +import { assetDetailsKubernetesNode } from './asset_details_kubernetes_node'; + +export const dashboards = { + assetDetails, + assetDetailsFlyout, + hostsView, + kpi, + assetDetailsKubernetesNode, +}; + +export type HostDashboards = typeof dashboards; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/kpi.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/kpi.ts new file mode 100644 index 000000000000..28a929f147e7 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/dashboards/kpi.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { DataView } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; +import type { MetricLayerOptions } from '@kbn/lens-embeddable-utils'; +import { createDashboardModel } from '../../../create_dashboard_model'; +import { createBasicCharts } from '../charts'; + +const AVERAGE = i18n.translate('xpack.metricsData.assetDetails.overview.kpi.subtitle.average', { + defaultMessage: 'Average', +}); + +export const kpi = { + get: ({ + metricsDataView, + options, + }: { + metricsDataView?: DataView; + options?: MetricLayerOptions; + }) => { + const { cpuUsage, diskUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({ + visualizationType: 'lnsMetric', + formulaIds: ['cpuUsage', 'diskUsage', 'memoryUsage', 'normalizedLoad1m'], + layerOptions: { + showTrendLine: true, + subtitle: AVERAGE, + ...options, + }, + dataView: metricsDataView, + }); + + return createDashboardModel({ + charts: [ + { + ...cpuUsage, + layers: { + ...cpuUsage.layers, + data: { + ...cpuUsage.layers.data, + format: cpuUsage.layers.data.format + ? { + ...cpuUsage.layers.data.format, + params: { + decimals: 1, + }, + } + : undefined, + }, + }, + }, + { + ...normalizedLoad1m, + layers: { + ...normalizedLoad1m.layers, + data: { + ...normalizedLoad1m.layers.data, + format: normalizedLoad1m.layers.data.format + ? { + ...normalizedLoad1m.layers.data.format, + params: { + decimals: 1, + }, + } + : undefined, + }, + }, + }, + + { + ...memoryUsage, + layers: { + ...memoryUsage.layers, + data: { + ...memoryUsage.layers.data, + format: memoryUsage.layers.data.format + ? { + ...memoryUsage.layers.data.format, + params: { + decimals: 1, + }, + } + : undefined, + }, + }, + }, + { + ...diskUsage, + layers: { + ...diskUsage.layers, + data: { + ...diskUsage.layers.data, + format: diskUsage.layers.data.format + ? { + ...diskUsage.layers.data.format, + params: { + decimals: 1, + }, + } + : undefined, + }, + }, + }, + ], + }); + }, +}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage.ts index f98c02643dc2..5fc722ef8ee7 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsage: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage', { defaultMessage: 'CPU Usage', }), value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_iowait.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_iowait.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_iowait.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_iowait.ts index b43f77252dcc..884306852f87 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_iowait.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_iowait.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageIowait: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.iowaitLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel', { defaultMessage: 'iowait', }), value: 'average(system.cpu.iowait.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_irq.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_irq.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_irq.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_irq.ts index f5fb7f231976..148939a0ffd3 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_irq.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_irq.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageIrq: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.irqLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel', { defaultMessage: 'irq', }), value: 'average(system.cpu.irq.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_nice.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_nice.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_nice.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_nice.ts index 94093af85a90..24d2400d0a2c 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_nice.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_nice.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageNice: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.niceLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel', { defaultMessage: 'nice', }), value: 'average(system.cpu.nice.norm.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_softirq.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_softirq.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_softirq.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_softirq.ts index adc9428a2494..8ec868af679a 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_softirq.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_softirq.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageSoftirq: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.softirqLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel', { defaultMessage: 'softirq', }), value: 'average(system.cpu.softirq.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_steal.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_steal.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_steal.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_steal.ts index 4ca7ffb7c335..a400551d492e 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_steal.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_steal.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageSteal: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.stealLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel', { defaultMessage: 'steal', }), value: 'average(system.cpu.steal.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_system.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_system.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_system.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_system.ts index 591734973647..80e2e369f3f2 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_system.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_system.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageSystem: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.systemLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel', { defaultMessage: 'system', }), value: 'average(system.cpu.system.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_user.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_user.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_user.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_user.ts index 8fe8d2baf1f3..6fb45344f889 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/cpu_usage_user.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/cpu_usage_user.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const cpuUsageUser: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.cpuUsage.userLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel', { defaultMessage: 'user', }), value: 'average(system.cpu.user.pct) / max(system.cpu.cores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_iops.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_iops.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_iops.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_iops.ts index 74f3b6b27b2e..a21a735856de 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_iops.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_iops.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskIORead: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskIORead', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIORead', { defaultMessage: 'Disk Read IOPS', }), value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')", diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_throughput.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_throughput.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_throughput.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_throughput.ts index eb92ba34406e..73b684dc5a65 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_read_throughput.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_read_throughput.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskReadThroughput: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskReadThroughput', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskReadThroughput', { defaultMessage: 'Disk Read Throughput', }), value: "counter_rate(max(system.diskio.read.bytes), kql='system.diskio.read.bytes: *')", diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_availability.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_availability.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_availability.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_availability.ts index 02fc69d72b10..6ea6811d30d0 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_availability.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_availability.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskSpaceAvailability: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskSpaceAvailability', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailability', { defaultMessage: 'Disk Space Availability', }), value: '1 - average(system.filesystem.used.pct)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_available.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_available.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_available.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_available.ts index f8d34c24ffee..c6e9919b4c53 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_space_available.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_space_available.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskSpaceAvailable: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskSpaceAvailable', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailable', { defaultMessage: 'Disk Space Available', }), value: 'average(system.filesystem.free)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_usage.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_usage.ts index bce105387021..e9a2ff6f93cb 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_usage.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskUsage: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskUsage', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskUsage', { defaultMessage: 'Disk Usage', }), value: 'average(system.filesystem.used.pct)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_iops.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_iops.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_iops.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_iops.ts index 6936f6eee3d6..881a8bcd0529 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_iops.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_iops.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskIOWrite: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskIOWrite', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIOWrite', { defaultMessage: 'Disk Write IOPS', }), value: "counter_rate(max(system.diskio.write.count), kql='system.diskio.write.count: *')", diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_throughput.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_throughput.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_throughput.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_throughput.ts index 6c1a536c7a3a..2290ed6e3b83 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/disk_write_throughput.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/disk_write_throughput.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const diskWriteThroughput: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.diskWriteThroughput', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskWriteThroughput', { defaultMessage: 'Disk Write Throughput', }), value: "counter_rate(max(system.diskio.write.bytes), kql='system.diskio.write.bytes: *')", diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/host_count.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/host_count.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/host_count.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/host_count.ts index 1fb01045d6ee..d5cea36319d6 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/host_count.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/host_count.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const hostCount: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.hostCount.hostsLabel', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel', { defaultMessage: 'Hosts', }), value: 'unique_count(host.name)', diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/index.ts new file mode 100644 index 000000000000..f290d9f89427 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/index.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { cpuUsage } from './cpu_usage'; +import { cpuUsageIowait } from './cpu_usage_iowait'; +import { cpuUsageIrq } from './cpu_usage_irq'; +import { cpuUsageNice } from './cpu_usage_nice'; +import { cpuUsageSoftirq } from './cpu_usage_softirq'; +import { cpuUsageSteal } from './cpu_usage_steal'; +import { cpuUsageUser } from './cpu_usage_user'; +import { cpuUsageSystem } from './cpu_usage_system'; +import { diskIORead } from './disk_read_iops'; +import { diskIOWrite } from './disk_write_iops'; +import { diskReadThroughput } from './disk_read_throughput'; +import { diskWriteThroughput } from './disk_write_throughput'; +import { diskSpaceAvailability } from './disk_space_availability'; +import { diskSpaceAvailable } from './disk_space_available'; +import { diskUsage } from './disk_usage'; +import { hostCount } from './host_count'; +import { logRate } from './log_rate'; +import { normalizedLoad1m } from './normalized_load_1m'; +import { load1m } from './load_1m'; +import { load5m } from './load_5m'; +import { load15m } from './load_15m'; +import { memoryUsage } from './memory_usage'; +import { memoryFree } from './memory_free'; +import { memoryUsed } from './memory_used'; +import { memoryFreeExcludingCache } from './memory_free_excluding_cache'; +import { memoryCache } from './memory_cache'; +import { rx } from './rx'; +import { tx } from './tx'; + +export const formulas = { + cpuUsage, + cpuUsageIowait, + cpuUsageIrq, + cpuUsageNice, + cpuUsageSoftirq, + cpuUsageSteal, + cpuUsageUser, + cpuUsageSystem, + diskIORead, + diskIOWrite, + diskReadThroughput, + diskWriteThroughput, + diskSpaceAvailability, + diskSpaceAvailable, + diskUsage, + hostCount, + logRate, + normalizedLoad1m, + load1m, + load5m, + load15m, + memoryUsage, + memoryFree, + memoryUsed, + memoryFreeExcludingCache, + memoryCache, + rx, + tx, +}; + +export type HostFormulas = typeof formulas; +export type HostFormulaNames = keyof HostFormulas; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_15m.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_15m.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_15m.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_15m.ts index 84b865d4081c..79179241b414 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_15m.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_15m.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const load15m: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.load15m', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.load15m', { defaultMessage: 'Load (15m)', }), value: 'average(system.load.15)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_1m.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_1m.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_1m.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_1m.ts index 8656176be2f0..7346023dc01b 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_1m.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_1m.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const load1m: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.load1m', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.load1m', { defaultMessage: 'Load (1m)', }), value: 'average(system.load.1)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_5m.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_5m.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_5m.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_5m.ts index b76ae333f093..027d05ef012b 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/load_5m.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/load_5m.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const load5m: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.load5m', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.load5m', { defaultMessage: 'Load (5m)', }), value: 'average(system.load.5)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/log_rate.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/log_rate.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/log_rate.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/log_rate.ts index 2db54217e323..21b1309841b7 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/log_rate.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/log_rate.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const logRate: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.logRate', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.logRate', { defaultMessage: 'Log Rate', }), value: 'differences(cumulative_sum(count()))', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_cache.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_cache.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_cache.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_cache.ts index 10e54d99dc62..3e5b32b256fb 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_cache.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_cache.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const memoryCache: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.metric.label.cache', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.cache', { defaultMessage: 'cache', }), value: 'average(system.memory.used.bytes) - average(system.memory.actual.used.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free.ts similarity index 88% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free.ts index 8b2032a63a5e..2c07c2265092 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const memoryFree: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.memoryFree', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryFree', { defaultMessage: 'Memory Free', }), value: 'max(system.memory.total) - average(system.memory.actual.used.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free_excluding_cache.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free_excluding_cache.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free_excluding_cache.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free_excluding_cache.ts index 71f03b974bf3..97df7baed7df 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_free_excluding_cache.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_free_excluding_cache.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const memoryFreeExcludingCache: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.metric.label.free', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.free', { defaultMessage: 'free', }), value: 'average(system.memory.free)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_usage.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_usage.ts index 59e09889e65a..8a4641cd365a 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_usage.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const memoryUsage: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.memoryUsage', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryUsage', { defaultMessage: 'Memory Usage', }), value: 'average(system.memory.actual.used.pct)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_used.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_used.ts similarity index 86% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_used.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_used.ts index 2c02a22f393b..373164e3705e 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/memory_used.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/memory_used.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const memoryUsed: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.metric.label.used', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.used', { defaultMessage: 'used', }), value: 'average(system.memory.actual.used.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/normalized_load_1m.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/normalized_load_1m.ts similarity index 87% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/normalized_load_1m.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/normalized_load_1m.ts index d0e70374829e..48d130868667 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/host/normalized_load_1m.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/normalized_load_1m.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const normalizedLoad1m: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.normalizedLoad1m', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.normalizedLoad1m', { defaultMessage: 'Normalized Load', }), value: 'average(system.load.1) / max(system.load.cores)', diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/rx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/rx.ts new file mode 100644 index 000000000000..ec341acf9be6 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/rx.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; + +export const rx: FormulaValueConfig = { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.rx', { + defaultMessage: 'Network Inbound (RX)', + }), + value: + "average(host.network.ingress.bytes) * 8 / (max(metricset.period, kql='host.network.ingress.bytes: *') / 1000)", + format: { + id: 'bits', + params: { + decimals: 1, + }, + }, + timeScale: 's', +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/tx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/tx.ts new file mode 100644 index 000000000000..52ada97dd06d --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/formulas/tx.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; + +export const tx: FormulaValueConfig = { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.tx', { + defaultMessage: 'Network Outbound (TX)', + }), + value: + "average(host.network.egress.bytes) * 8 / (max(metricset.period, kql='host.network.egress.bytes: *') / 1000)", + format: { + id: 'bits', + params: { + decimals: 1, + }, + }, + timeScale: 's', +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/index.ts index e59aaefb2b82..55ee6e29ee39 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/index.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/index.ts @@ -4,79 +4,25 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { snapshot } from './snapshot'; +import { tsvb } from './tsvb'; +import { InventoryMetricsWithDashboards } from '../../types'; +import { type HostFormulas } from './formulas'; +import { type HostDashboards } from './dashboards'; -import { cpu } from './snapshot/cpu'; -import { diskLatency } from './snapshot/disk_latency'; -import { diskSpaceUsage } from './snapshot/disk_space_usage'; -import { count } from '../../shared/metrics/snapshot/count'; -import { load } from './snapshot/load'; -import { logRate } from './snapshot/log_rate'; -import { memory } from './snapshot/memory'; -import { memoryFree } from './snapshot/memory_free'; -import { memoryTotal } from './snapshot/memory_total'; -import { normalizedLoad1m } from './snapshot/normalized_load_1m'; -import { rx } from './snapshot/rx'; -import { tx } from './snapshot/tx'; - -import { hostSystemOverview } from './tsvb/host_system_overview'; -import { hostCpuUsage } from './tsvb/host_cpu_usage'; -import { hostLoad } from './tsvb/host_load'; -import { hostMemoryUsage } from './tsvb/host_memory_usage'; -import { hostNetworkTraffic } from './tsvb/host_network_traffic'; -import { hostFilesystem } from './tsvb/host_filesystem'; - -import { hostK8sOverview } from './tsvb/host_k8s_overview'; -import { hostK8sCpuCap } from './tsvb/host_k8s_cpu_cap'; -import { hostK8sPodCap } from './tsvb/host_k8s_pod_cap'; -import { hostK8sDiskCap } from './tsvb/host_k8s_disk_cap'; -import { hostK8sMemoryCap } from './tsvb/host_k8s_memory_cap'; - -import { hostDockerTop5ByMemory } from './tsvb/host_docker_top_5_by_memory'; -import { hostDockerTop5ByCpu } from './tsvb/host_docker_top_5_by_cpu'; -import { hostDockerOverview } from './tsvb/host_docker_overview'; -import { hostDockerInfo } from './tsvb/host_docker_info'; - -import { InventoryMetrics } from '../../types'; - -const exposedHostSnapshotMetrics = { - cpu, - diskLatency, - diskSpaceUsage, - load, - logRate, - memory, - memoryFree, - memoryTotal, - normalizedLoad1m, - rx, - tx, -}; // not sure why this is the only model with "count" -const hostSnapshotMetrics = { count, ...exposedHostSnapshotMetrics }; +const { count, ...exposedHostSnapshotMetrics } = snapshot; export const hostSnapshotMetricTypes = Object.keys(exposedHostSnapshotMetrics) as Array< keyof typeof exposedHostSnapshotMetrics >; -export const metrics: InventoryMetrics = { - tsvb: { - hostSystemOverview, - hostCpuUsage, - hostLoad, - hostMemoryUsage, - hostNetworkTraffic, - hostFilesystem, - hostK8sOverview, - hostK8sCpuCap, - hostK8sPodCap, - hostK8sDiskCap, - hostK8sMemoryCap, - hostDockerOverview, - hostDockerInfo, - hostDockerTop5ByMemory, - hostDockerTop5ByCpu, - }, - snapshot: hostSnapshotMetrics, +export const metrics: InventoryMetricsWithDashboards = { + tsvb, + snapshot, + getFormulas: async () => await import('./formulas').then(({ formulas }) => ({ ...formulas })), + getDashboards: async () => + await import('./dashboards').then(({ dashboards }) => ({ ...dashboards })), defaultSnapshot: 'cpu', defaultTimeRangeInSeconds: 3600, // 1 hour }; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/snapshot/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/snapshot/index.ts new file mode 100644 index 000000000000..8cf567b40165 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/snapshot/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { cpu } from './cpu'; +import { diskLatency } from './disk_latency'; +import { diskSpaceUsage } from './disk_space_usage'; +import { count } from '../../../shared/metrics/snapshot/count'; +import { load } from './load'; +import { logRate } from './log_rate'; +import { memory } from './memory'; +import { memoryFree } from './memory_free'; +import { memoryTotal } from './memory_total'; +import { normalizedLoad1m } from './normalized_load_1m'; +import { rx } from './rx'; +import { tx } from './tx'; + +export const snapshot = { + cpu, + diskLatency, + diskSpaceUsage, + count, + load, + logRate, + memory, + memoryFree, + memoryTotal, + normalizedLoad1m, + rx, + tx, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/tsvb/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/tsvb/index.ts new file mode 100644 index 000000000000..fb91ee9dd8b2 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/host/metrics/tsvb/index.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { hostSystemOverview } from './host_system_overview'; +import { hostCpuUsage } from './host_cpu_usage'; +import { hostLoad } from './host_load'; +import { hostMemoryUsage } from './host_memory_usage'; +import { hostNetworkTraffic } from './host_network_traffic'; +import { hostFilesystem } from './host_filesystem'; + +import { hostK8sOverview } from './host_k8s_overview'; +import { hostK8sCpuCap } from './host_k8s_cpu_cap'; +import { hostK8sPodCap } from './host_k8s_pod_cap'; +import { hostK8sDiskCap } from './host_k8s_disk_cap'; +import { hostK8sMemoryCap } from './host_k8s_memory_cap'; + +import { hostDockerTop5ByMemory } from './host_docker_top_5_by_memory'; +import { hostDockerTop5ByCpu } from './host_docker_top_5_by_cpu'; +import { hostDockerOverview } from './host_docker_overview'; +import { hostDockerInfo } from './host_docker_info'; + +export const tsvb = { + hostSystemOverview, + hostCpuUsage, + hostLoad, + hostMemoryUsage, + hostNetworkTraffic, + hostFilesystem, + hostK8sOverview, + hostK8sCpuCap, + hostK8sPodCap, + hostK8sDiskCap, + hostK8sMemoryCap, + hostDockerOverview, + hostDockerInfo, + hostDockerTop5ByMemory, + hostDockerTop5ByCpu, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/index.ts index 6d683f287c99..f3199f21593d 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/index.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/index.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { POD_FIELD, HOST_FIELD, CONTAINER_FIELD } from '../constants'; import { host } from './host'; -import { pod } from './pod'; +import { pod } from './kubernetes/pod'; import { awsEC2 } from './aws_ec2'; import { awsS3 } from './aws_s3'; import { awsRDS } from './aws_rds'; @@ -17,9 +17,21 @@ import { container } from './container'; import { InventoryItemType } from './types'; export { metrics } from './metrics'; -export const inventoryModels = [host, pod, container, awsEC2, awsS3, awsRDS, awsSQS]; +const catalog = { + host, + pod, + container, + awsEC2, + awsS3, + awsRDS, + awsSQS, +} as const; -export const findInventoryModel = (type: InventoryItemType) => { +export const inventoryModels = Object.values(catalog); + +type InventoryModels = typeof catalog[T]; + +export const findInventoryModel = (type: T): InventoryModels => { const model = inventoryModels.find((m) => m.id === type); if (!model) { throw new Error( @@ -28,7 +40,8 @@ export const findInventoryModel = (type: InventoryItemType) => { }) ); } - return model; + + return model as InventoryModels; }; const LEGACY_TYPES = ['host', 'pod', 'container']; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/index.ts new file mode 100644 index 000000000000..5203d1a0abf3 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { nodeCpuCapacity } from './node_cpu_capacity'; +import { nodeCpuUsed } from './node_cpu_used'; +import { nodeDiskCapacity } from './node_disk_capacity'; +import { nodeDiskUsed } from './node_disk_used'; +import { nodeMemoryCapacity } from './node_memory_capacity'; +import { nodeMemoryUsed } from './node_memory_used'; +import { nodePodCapacity } from './node_pod_capacity'; +import { nodePodUsed } from './node_pod_used'; + +export const formulas = { + nodeCpuCapacity, + nodeCpuUsed, + nodeDiskCapacity, + nodeDiskUsed, + nodeMemoryCapacity, + nodeMemoryUsed, + nodePodCapacity, + nodePodUsed, +}; diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_capacity.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_capacity.ts similarity index 77% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_capacity.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_capacity.ts index 1be71eb6c1a5..952edac1d5de 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_capacity.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_capacity.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeCpuCapacity: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', { defaultMessage: 'Capacity', }), value: 'max(kubernetes.node.cpu.allocatable.cores) * 1000000000', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_used.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_used.ts similarity index 77% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_used.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_used.ts index ece5d4437961..4561303430d1 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_cpu_used.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_cpu_used.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeCpuUsed: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', { defaultMessage: 'Used', }), value: 'average(kubernetes.node.cpu.usage.nanocores)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_capacity.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_capacity.ts similarity index 76% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_capacity.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_capacity.ts index ef30107970d0..45e0e61c1b8f 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_capacity.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_capacity.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeDiskCapacity: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', { defaultMessage: 'Capacity', }), value: 'max(kubernetes.node.fs.capacity.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_used.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_used.ts similarity index 76% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_used.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_used.ts index 8a38f22cfe14..4f6d07a0a437 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_disk_used.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_disk_used.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeDiskUsed: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', { defaultMessage: 'Used', }), value: 'average(kubernetes.node.fs.used.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_capacity.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_capacity.ts similarity index 76% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_capacity.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_capacity.ts index 379580c7fba3..4607f002194a 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_capacity.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_capacity.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeMemoryCapacity: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', { defaultMessage: 'Capacity', }), value: 'max(kubernetes.node.memory.allocatable.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_used.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_used.ts similarity index 76% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_used.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_used.ts index 34d5bffebd92..cdcaf32593a3 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_memory_used.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_memory_used.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodeMemoryUsed: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', { defaultMessage: 'Used', }), value: 'average(kubernetes.node.memory.usage.bytes)', diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_capacity.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_capacity.ts similarity index 78% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_capacity.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_capacity.ts index d3990328c055..9bf455df9ccf 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_capacity.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_capacity.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodePodCapacity: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', { defaultMessage: 'Capacity', }), value: diff --git a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_used.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_used.ts similarity index 76% rename from x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_used.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_used.ts index 6c3e3e952d63..697ceaca02f6 100644 --- a/x-pack/plugins/infra/public/common/visualizations/lens/formulas/kubernetes/node_pod_used.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/formulas/node_pod_used.ts @@ -6,10 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; +import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils'; export const nodePodUsed: FormulaValueConfig = { - label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', { + label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', { defaultMessage: 'Used', }), value: 'unique_count(kubernetes.pod.uid)', diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/index.ts new file mode 100644 index 000000000000..7340df0d8c04 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/node/metrics/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { formulas } from './formulas'; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/index.ts new file mode 100644 index 000000000000..a61abbfeb01e --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/index.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { metrics } from './metrics'; +import { InventoryModel } from '../../types'; +import { nginx as nginxRequiredMetrics } from '../../shared/metrics/required_metrics'; + +export { podSnapshotMetricTypes } from './metrics'; + +export const pod: InventoryModel = { + id: 'pod', + displayName: i18n.translate('xpack.metricsData.inventoryModel.pod.displayName', { + defaultMessage: 'Kubernetes Pods', + }), + singularDisplayName: i18n.translate('xpack.metricsData.inventoryModels.pod.singularDisplayName', { + defaultMessage: 'Kubernetes Pod', + }), + requiredModule: 'kubernetes', + crosslinkSupport: { + details: true, + logs: true, + apm: true, + uptime: true, + }, + fields: { + id: 'kubernetes.pod.uid', + name: 'kubernetes.pod.name', + ip: 'kubernetes.pod.ip', + }, + metrics, + requiredMetrics: [ + 'podOverview', + 'podCpuUsage', + 'podMemoryUsage', + 'podNetworkTraffic', + ...nginxRequiredMetrics, + ], + tooltipMetrics: ['cpu', 'memory', 'rx', 'tx'], +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/index.ts new file mode 100644 index 000000000000..eeae2c2ec586 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/index.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { cpu } from './snapshot/cpu'; +import { memory } from './snapshot/memory'; +import { rx } from './snapshot/rx'; +import { tx } from './snapshot/tx'; + +import { podOverview } from './tsvb/pod_overview'; +import { podCpuUsage } from './tsvb/pod_cpu_usage'; +import { podLogUsage } from './tsvb/pod_log_usage'; +import { podMemoryUsage } from './tsvb/pod_memory_usage'; +import { podNetworkTraffic } from './tsvb/pod_network_traffic'; +import { InventoryMetrics } from '../../../types'; + +const podSnapshotMetrics = { cpu, memory, rx, tx }; + +export const podSnapshotMetricTypes = Object.keys(podSnapshotMetrics) as Array< + keyof typeof podSnapshotMetrics +>; + +export const metrics: InventoryMetrics = { + tsvb: { + podOverview, + podCpuUsage, + podLogUsage, + podNetworkTraffic, + podMemoryUsage, + }, + snapshot: podSnapshotMetrics, + defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 3600, // 1 hour +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/cpu.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/cpu.ts new file mode 100644 index 000000000000..5a190a1530b5 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/cpu.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MetricsUIAggregation } from '../../../../types'; + +export const cpu: MetricsUIAggregation = { + cpu_with_limit: { + avg: { + field: 'kubernetes.pod.cpu.usage.limit.pct', + }, + }, + cpu_without_limit: { + avg: { + field: 'kubernetes.pod.cpu.usage.node.pct', + }, + }, + cpu: { + bucket_script: { + buckets_path: { + with_limit: 'cpu_with_limit', + without_limit: 'cpu_without_limit', + }, + script: { + source: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/memory.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/memory.ts new file mode 100644 index 000000000000..70640bdc2ac6 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/memory.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MetricsUIAggregation } from '../../../../types'; + +export const memory: MetricsUIAggregation = { + memory_with_limit: { + avg: { + field: 'kubernetes.pod.memory.usage.limit.pct', + }, + }, + memory_without_limit: { + avg: { + field: 'kubernetes.pod.memory.usage.node.pct', + }, + }, + memory: { + bucket_script: { + buckets_path: { + with_limit: 'memory_with_limit', + without_limit: 'memory_without_limit', + }, + script: { + source: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, +}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/rx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/rx.ts new file mode 100644 index 000000000000..8108b699eb29 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/rx.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { networkTraffic } from '../../../../shared/metrics/snapshot/network_traffic'; +export const rx = networkTraffic('rx', 'kubernetes.pod.network.rx.bytes'); diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/tx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/tx.ts new file mode 100644 index 000000000000..4a0e1d6e4e16 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/snapshot/tx.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { networkTraffic } from '../../../../shared/metrics/snapshot/network_traffic'; +export const tx = networkTraffic('tx', 'kubernetes.pod.network.tx.bytes'); diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_cpu_usage.ts similarity index 99% rename from x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_cpu_usage.ts index a7574fc68813..c1d4234725ae 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_cpu_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_cpu_usage.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../types'; +import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../../types'; export const podCpuUsage: TSVBMetricModelCreator = ( timeField, diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_log_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_log_usage.ts similarity index 99% rename from x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_log_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_log_usage.ts index 0e2a58846316..e57b839c4d0c 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_log_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_log_usage.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../types'; +import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../../types'; export const podLogUsage: TSVBMetricModelCreator = ( timeField, diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_memory_usage.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_memory_usage.ts similarity index 99% rename from x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_memory_usage.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_memory_usage.ts index 9c774e1b18ed..408d7d21386b 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_memory_usage.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_memory_usage.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../types'; +import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../../types'; export const podMemoryUsage: TSVBMetricModelCreator = ( timeField, diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_network_traffic.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_network_traffic.ts similarity index 99% rename from x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_network_traffic.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_network_traffic.ts index c7a2db09497a..b95fd8e2f463 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_network_traffic.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_network_traffic.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../types'; +import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../../types'; export const podNetworkTraffic: TSVBMetricModelCreator = ( timeField, diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_overview.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_overview.ts similarity index 99% rename from x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_overview.ts rename to x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_overview.ts index 0fe94c7f53da..f9789dff288c 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/tsvb/pod_overview.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/kubernetes/pod/metrics/tsvb/pod_overview.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../types'; +import { TSVBMetricModelCreator, TSVBMetricModel } from '../../../../types'; export const podOverview: TSVBMetricModelCreator = ( timeField, diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/metrics.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/metrics.ts index 0f73cdb6ef3b..00937a064a7b 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/metrics.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/metrics.ts @@ -7,7 +7,7 @@ import { metrics as hostMetrics } from './host/metrics'; import { metrics as sharedMetrics } from './shared/metrics'; -import { metrics as podMetrics } from './pod/metrics'; +import { metrics as podMetrics } from './kubernetes/pod/metrics'; import { metrics as containerMetrics } from './container/metrics'; import { metrics as awsEC2Metrics } from './aws_ec2/metrics'; import { metrics as awsS3Metrics } from './aws_s3/metrics'; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/index.ts deleted file mode 100644 index 3a8cf778c00f..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { metrics } from './metrics'; -import { InventoryModel } from '../types'; -import { nginx as nginxRequiredMetrics } from '../shared/metrics/required_metrics'; - -export { podSnapshotMetricTypes } from './metrics'; - -export const pod: InventoryModel = { - id: 'pod', - displayName: i18n.translate('xpack.metricsData.inventoryModel.pod.displayName', { - defaultMessage: 'Kubernetes Pods', - }), - singularDisplayName: i18n.translate('xpack.metricsData.inventoryModels.pod.singularDisplayName', { - defaultMessage: 'Kubernetes Pod', - }), - requiredModule: 'kubernetes', - crosslinkSupport: { - details: true, - logs: true, - apm: true, - uptime: true, - }, - fields: { - id: 'kubernetes.pod.uid', - name: 'kubernetes.pod.name', - ip: 'kubernetes.pod.ip', - }, - metrics, - requiredMetrics: [ - 'podOverview', - 'podCpuUsage', - 'podMemoryUsage', - 'podNetworkTraffic', - ...nginxRequiredMetrics, - ], - tooltipMetrics: ['cpu', 'memory', 'rx', 'tx'], -}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/index.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/index.ts deleted file mode 100644 index 25ec090da3a5..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { cpu } from './snapshot/cpu'; -import { memory } from './snapshot/memory'; -import { rx } from './snapshot/rx'; -import { tx } from './snapshot/tx'; - -import { podOverview } from './tsvb/pod_overview'; -import { podCpuUsage } from './tsvb/pod_cpu_usage'; -import { podLogUsage } from './tsvb/pod_log_usage'; -import { podMemoryUsage } from './tsvb/pod_memory_usage'; -import { podNetworkTraffic } from './tsvb/pod_network_traffic'; -import { InventoryMetrics } from '../../types'; - -const podSnapshotMetrics = { cpu, memory, rx, tx }; - -export const podSnapshotMetricTypes = Object.keys(podSnapshotMetrics) as Array< - keyof typeof podSnapshotMetrics ->; - -export const metrics: InventoryMetrics = { - tsvb: { - podOverview, - podCpuUsage, - podLogUsage, - podNetworkTraffic, - podMemoryUsage, - }, - snapshot: podSnapshotMetrics, - defaultSnapshot: 'cpu', - defaultTimeRangeInSeconds: 3600, // 1 hour -}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/cpu.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/cpu.ts deleted file mode 100644 index fe8c0d1740e6..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/cpu.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { MetricsUIAggregation } from '../../../types'; - -export const cpu: MetricsUIAggregation = { - cpu_with_limit: { - avg: { - field: 'kubernetes.pod.cpu.usage.limit.pct', - }, - }, - cpu_without_limit: { - avg: { - field: 'kubernetes.pod.cpu.usage.node.pct', - }, - }, - cpu: { - bucket_script: { - buckets_path: { - with_limit: 'cpu_with_limit', - without_limit: 'cpu_without_limit', - }, - script: { - source: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', - lang: 'painless', - }, - gap_policy: 'skip', - }, - }, -}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/memory.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/memory.ts deleted file mode 100644 index 480fdc055a03..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/memory.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { MetricsUIAggregation } from '../../../types'; - -export const memory: MetricsUIAggregation = { - memory_with_limit: { - avg: { - field: 'kubernetes.pod.memory.usage.limit.pct', - }, - }, - memory_without_limit: { - avg: { - field: 'kubernetes.pod.memory.usage.node.pct', - }, - }, - memory: { - bucket_script: { - buckets_path: { - with_limit: 'memory_with_limit', - without_limit: 'memory_without_limit', - }, - script: { - source: 'params.with_limit > 0.0 ? params.with_limit : params.without_limit', - lang: 'painless', - }, - gap_policy: 'skip', - }, - }, -}; diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/rx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/rx.ts deleted file mode 100644 index c2162499c32d..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/rx.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { networkTraffic } from '../../../shared/metrics/snapshot/network_traffic'; -export const rx = networkTraffic('rx', 'kubernetes.pod.network.rx.bytes'); diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/tx.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/tx.ts deleted file mode 100644 index 4d43262e904f..000000000000 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/pod/metrics/snapshot/tx.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { networkTraffic } from '../../../shared/metrics/snapshot/network_traffic'; -export const tx = networkTraffic('tx', 'kubernetes.pod.network.tx.bytes'); diff --git a/x-pack/plugins/metrics_data_access/common/inventory_models/types.ts b/x-pack/plugins/metrics_data_access/common/inventory_models/types.ts index 5bc36429e2ba..25bc3ab001b2 100644 --- a/x-pack/plugins/metrics_data_access/common/inventory_models/types.ts +++ b/x-pack/plugins/metrics_data_access/common/inventory_models/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { ChartModel, FormulaValueConfig } from '@kbn/lens-embeddable-utils'; import * as rt from 'io-ts'; export const ItemTypeRT = rt.keyof({ @@ -384,11 +385,21 @@ export interface InventoryMetrics { defaultTimeRangeInSeconds: number; } -export interface InventoryModel { +export interface InventoryMetricsWithDashboards< + TFormula extends Record, + TDashboard extends Record +> extends InventoryMetrics { + getFormulas: () => Promise; + getDashboards: () => Promise; +} + +type Modules = 'aws' | 'docker' | 'system' | 'kubernetes'; + +export interface InventoryModel { id: string; displayName: string; singularDisplayName: string; - requiredModule: string; + requiredModule: Modules; fields: { id: string; name: string; @@ -402,8 +413,17 @@ export interface InventoryModel { apm: boolean; uptime: boolean; }; - metrics: InventoryMetrics; + metrics: TMetrics; requiredMetrics: InventoryMetric[]; tooltipMetrics: SnapshotMetricType[]; nodeFilter?: object[]; } + +export interface DashboardFn { + get: (...args: any[]) => DashboardModel; +} + +export interface DashboardModel { + charts: ChartModel[]; + dependsOn?: string[]; +} diff --git a/x-pack/plugins/metrics_data_access/tsconfig.json b/x-pack/plugins/metrics_data_access/tsconfig.json index 5eecf2fc3173..5f387443ed53 100644 --- a/x-pack/plugins/metrics_data_access/tsconfig.json +++ b/x-pack/plugins/metrics_data_access/tsconfig.json @@ -33,6 +33,7 @@ "@kbn/observability-shared-plugin", "@kbn/i18n-react", "@kbn/logging", - "@kbn/core-http-request-handler-context-server" + "@kbn/core-http-request-handler-context-server", + "@kbn/lens-embeddable-utils" ] } diff --git a/x-pack/plugins/ml/common/constants/locator.ts b/x-pack/plugins/ml/common/constants/locator.ts index 92c89c5aedf9..614c037c1302 100644 --- a/x-pack/plugins/ml/common/constants/locator.ts +++ b/x-pack/plugins/ml/common/constants/locator.ts @@ -55,6 +55,7 @@ export const ML_PAGES = { ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE: 'jobs/new_job/step/job_type', ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX: 'jobs/new_job/step/index_or_search', ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: 'jobs/new_job/from_lens', + ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS: 'jobs/new_job/from_pattern_analysis', ANOMALY_DETECTION_CREATE_JOB_FROM_MAP: 'jobs/new_job/from_map', ANOMALY_DETECTION_MODULES_VIEW_OR_CREATE: 'modules/check_view_or_create', SETTINGS: 'settings', diff --git a/x-pack/plugins/ml/common/constants/new_job.ts b/x-pack/plugins/ml/common/constants/new_job.ts index 24584a6e8d29..676182d0ac16 100644 --- a/x-pack/plugins/ml/common/constants/new_job.ts +++ b/x-pack/plugins/ml/common/constants/new_job.ts @@ -26,6 +26,7 @@ export enum CREATED_BY_LABEL { APM_TRANSACTION = 'ml-module-apm-transaction', SINGLE_METRIC_FROM_LENS = 'single-metric-wizard-from-lens', MULTI_METRIC_FROM_LENS = 'multi-metric-wizard-from-lens', + CATEGORIZATION_FROM_PATTERN_ANALYSIS = 'categorization-wizard-from-pattern-analysis', } export const DEFAULT_MODEL_MEMORY_LIMIT = '10MB'; diff --git a/x-pack/plugins/ml/common/openapi/ml_apis.yaml b/x-pack/plugins/ml/common/openapi/ml_apis.yaml index 5b7a68309c94..9f2a7de49818 100644 --- a/x-pack/plugins/ml/common/openapi/ml_apis.yaml +++ b/x-pack/plugins/ml/common/openapi/ml_apis.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Machine learning APIs description: Kibana APIs for the machine learning feature - version: "1.0.1" + version: "1.0.2" license: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license @@ -82,7 +82,8 @@ components: required: false schema: type: boolean - example: 'true' + examples: + - true securitySchemes: basicAuth: type: http @@ -187,12 +188,14 @@ components: properties: error: type: string - example: Unauthorized + examples: + - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 examples: mlSyncExample: summary: Two anomaly detection jobs required synchronization in this example. diff --git a/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml b/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml index 649bc3db06ac..6ff44e29517e 100644 --- a/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml +++ b/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Machine learning APIs description: Kibana APIs for the machine learning feature - version: "1.0.1" + version: "1.0.2" license: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license @@ -46,7 +46,8 @@ components: required: false schema: type: boolean - example: 'true' + examples: + - true securitySchemes: apiKeyAuth: type: apiKey @@ -148,12 +149,14 @@ components: properties: error: type: string - example: Unauthorized + examples: + - Unauthorized message: type: string statusCode: type: integer - example: 401 + examples: + - 401 examples: mlSyncExample: summary: Two anomaly detection jobs required synchronization in this example. diff --git a/x-pack/plugins/ml/common/types/locator.ts b/x-pack/plugins/ml/common/types/locator.ts index 329ba59ba907..85b2550eb8e3 100644 --- a/x-pack/plugins/ml/common/types/locator.ts +++ b/x-pack/plugins/ml/common/types/locator.ts @@ -49,6 +49,7 @@ export type MlGenericUrlState = MLPageState< | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_LENS | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_MAP + | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_TYPE | typeof ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_SELECT_INDEX | typeof ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB diff --git a/x-pack/plugins/ml/common/types/ml_server_info.ts b/x-pack/plugins/ml/common/types/ml_server_info.ts index e5141d6f2e78..215f46c26bef 100644 --- a/x-pack/plugins/ml/common/types/ml_server_info.ts +++ b/x-pack/plugins/ml/common/types/ml_server_info.ts @@ -20,6 +20,8 @@ export interface MlServerDefaults { export interface MlServerLimits { max_model_memory_limit?: string; effective_max_model_memory_limit?: string; + max_single_ml_node_processors?: number; + total_ml_processors?: number; } export interface MlInfoResponse { diff --git a/x-pack/plugins/ml/common/types/trained_models.ts b/x-pack/plugins/ml/common/types/trained_models.ts index 70f588712c35..95815cd3b87a 100644 --- a/x-pack/plugins/ml/common/types/trained_models.ts +++ b/x-pack/plugins/ml/common/types/trained_models.ts @@ -98,6 +98,7 @@ export type TrainedModelConfigResponse = estypes.MlTrainedModelConfig & { * Associated pipelines. Extends response from the ES endpoint. */ pipelines?: Record | null; + origin_job_exists?: boolean; metadata?: { analytics_config: DataFrameAnalyticsConfig; diff --git a/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx b/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx index 3919f9f9e5cc..70c3be96c667 100644 --- a/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx +++ b/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx @@ -65,6 +65,7 @@ export const ChangePointDetectionPage: FC = () => { 'share', 'storage', 'theme', + 'uiActions', 'uiSettings', 'unifiedSearch', 'usageCollection', diff --git a/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx b/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx index 455ff9bfc137..187843505cef 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx @@ -56,6 +56,7 @@ export const LogCategorizationPage: FC = () => { 'share', 'storage', 'theme', + 'uiActions', 'uiSettings', 'unifiedSearch', ])} diff --git a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx index c20264a129ea..4c2c1dfd637d 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx @@ -59,6 +59,7 @@ export const LogRateAnalysisPage: FC = () => { 'share', 'storage', 'theme', + 'uiActions', 'uiSettings', 'unifiedSearch', ])} diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx index 556dd5c810d8..eb5450d0d61b 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.tsx @@ -361,7 +361,7 @@ const CategoryExamples: FC<{ definition: CategoryDefinition; examples: string[] {definition !== undefined && definition.terms && ( diff --git a/x-pack/plugins/ml/public/application/components/job_selector/job_selector_table/job_selector_table.js b/x-pack/plugins/ml/public/application/components/job_selector/job_selector_table/job_selector_table.js index 40ebecd13554..1afed1eaac8c 100644 --- a/x-pack/plugins/ml/public/application/components/job_selector/job_selector_table/job_selector_table.js +++ b/x-pack/plugins/ml/public/application/components/job_selector/job_selector_table/job_selector_table.js @@ -28,6 +28,7 @@ import { i18n } from '@kbn/i18n'; import { useMlKibana } from '../../../contexts/kibana'; import { ML_PAGES } from '../../../../../common/constants/locator'; import { PLUGIN_ID } from '../../../../../common/constants/app'; +import { MlNodeAvailableWarningShared } from '../../node_available_warning'; const JOB_FILTER_FIELDS = ['job_id', 'groups']; const GROUP_FILTER_FIELDS = ['id']; @@ -43,11 +44,15 @@ export function JobSelectorTable({ withTimeRangeSelector, }) { const [sortableProperties, setSortableProperties] = useState(); + const [mlNodesAvailable, setMlNodesAvailable] = useState(true); const [currentTab, setCurrentTab] = useState('Jobs'); const { services: { - application: { navigateToApp }, + application: { + navigateToApp, + capabilities: { ml: mlCapabilities }, + }, }, } = useMlKibana(); @@ -258,6 +263,7 @@ export function JobSelectorTable({ return ( + {jobs.length === 0 && ( - + { + return { MlNodeAvailableWarningShared: () =>
    }; +}); const props = { ganttBarWidth: 299, diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx index e617d05f94d3..aecbb0aa0108 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx @@ -101,7 +101,7 @@ export interface ScatterplotMatrixProps { legendType?: LegendType; searchQuery?: estypes.QueryDslQueryContainer; runtimeMappings?: RuntimeMappings; - indexPattern?: DataView; + dataView?: DataView; query?: Query; } @@ -113,7 +113,7 @@ export const ScatterplotMatrix: FC = ({ legendType, searchQuery, runtimeMappings, - indexPattern, + dataView, query, }) => { const { esSearch } = useMlApiContext(); @@ -210,9 +210,7 @@ export const ScatterplotMatrix: FC = ({ vegaSpec.data = { url: { '%context%': true, - ...(indexPattern?.timeFieldName - ? { ['%timefield%']: `${indexPattern?.timeFieldName}` } - : {}), + ...(dataView?.timeFieldName ? { ['%timefield%']: `${dataView?.timeFieldName}` } : {}), index, body: { fields: fieldsToFetch, @@ -300,7 +298,7 @@ export const ScatterplotMatrix: FC = ({ } const combinedRuntimeMappings = - indexPattern && getCombinedRuntimeMappings(indexPattern, runtimeMappings); + dataView && getCombinedRuntimeMappings(dataView, runtimeMappings); const body = { fields: queryFields, diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/__mocks__/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/__mocks__/kibana_context.ts index 477dda87408f..355f66f2bf9f 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/__mocks__/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/__mocks__/kibana_context.ts @@ -38,7 +38,15 @@ export const kibanaContextMock = { services: { uiSettings: { get: jest.fn() }, chrome: { recentlyAccessed: { add: jest.fn() } }, - application: { navigateToApp: jest.fn(), navigateToUrl: jest.fn() }, + application: { + navigateToApp: jest.fn(), + navigateToUrl: jest.fn(), + capabilities: { + ml: { + canCreateJob: true, + }, + }, + }, http: { basePath: { get: jest.fn(), diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts index 6cd5c40d66e4..139b49f7c2b4 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/use_results_view_config.ts @@ -37,12 +37,10 @@ export const useResultsViewConfig = (jobId: string) => { } = useMlKibana(); const trainedModelsApiService = useTrainedModelsApiService(); - const [indexPattern, setIndexPattern] = useState(undefined); - const [indexPatternErrorMessage, setIndexPatternErrorMessage] = useState( - undefined - ); + const [dataView, setDataView] = useState(undefined); + const [dataViewErrorMessage, setDataViewErrorMessage] = useState(undefined); const [isInitialized, setIsInitialized] = useState(false); - const [needsDestIndexPattern, setNeedsDestIndexPattern] = useState(false); + const [needsDestDataView, setNeedsDestDataView] = useState(false); const [isLoadingJobConfig, setIsLoadingJobConfig] = useState(false); const [jobConfig, setJobConfig] = useState(undefined); const [jobCapsServiceErrorMessage, setJobCapsServiceErrorMessage] = useState( @@ -100,39 +98,39 @@ export const useResultsViewConfig = (jobId: string) => { try { const destIndex = getDestinationIndex(jobConfigUpdate); const destDataViewId = (await getDataViewIdFromName(destIndex)) ?? destIndex; - let dataView: DataView | undefined; + let fetchedDataView: DataView | undefined; try { - dataView = await dataViews.get(destDataViewId); + fetchedDataView = await dataViews.get(destDataViewId); // Force refreshing the fields list here because a user directly coming // from the job creation wizard might land on the page without the // data view being fully initialized because it was created // before the analytics job populated the destination index. - await dataViews.refreshFields(dataView); + await dataViews.refreshFields(fetchedDataView); } catch (e) { - dataView = undefined; + fetchedDataView = undefined; } - if (dataView === undefined) { - setNeedsDestIndexPattern(true); + if (fetchedDataView === undefined) { + setNeedsDestDataView(true); const sourceIndex = jobConfigUpdate.source.index[0]; const sourceDataViewId = (await getDataViewIdFromName(sourceIndex)) ?? sourceIndex; try { - dataView = await dataViews.get(sourceDataViewId); + fetchedDataView = await dataViews.get(sourceDataViewId); } catch (e) { - dataView = undefined; + fetchedDataView = undefined; } } - if (dataView !== undefined) { - await newJobCapsServiceAnalytics.initializeFromDataVIew(dataView); + if (fetchedDataView !== undefined) { + await newJobCapsServiceAnalytics.initializeFromDataVIew(fetchedDataView); setJobConfig(analyticsConfigs.data_frame_analytics[0]); - setIndexPattern(dataView); + setDataView(fetchedDataView); setIsInitialized(true); setIsLoadingJobConfig(false); } else { - setIndexPatternErrorMessage( + setDataViewErrorMessage( i18n.translate('xpack.ml.dataframe.analytics.results.dataViewMissingErrorMessage', { defaultMessage: 'To view this page, a Kibana data view is necessary for either the destination or source index of this analytics job.', @@ -153,15 +151,15 @@ export const useResultsViewConfig = (jobId: string) => { }, []); return { - indexPattern, - indexPatternErrorMessage, + dataView, + dataViewErrorMessage, isInitialized, isLoadingJobConfig, jobCapsServiceErrorMessage, jobConfig, jobConfigErrorMessage, jobStatus, - needsDestIndexPattern, + needsDestDataView, totalFeatureImportance, }; }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx index c574a6f66108..d065ef84fa97 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx @@ -356,9 +356,9 @@ export const ConfigurationStepForm: FC = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const indexPatternFieldsTableItems = useMemo(() => { - if (indexData?.indexPatternFields !== undefined) { - return indexData.indexPatternFields.map((field) => ({ + const dataViewFieldsTableItems = useMemo(() => { + if (indexData?.dataViewFields !== undefined) { + return indexData.dataViewFields.map((field) => ({ name: field, is_included: false, is_required: false, @@ -366,7 +366,7 @@ export const ConfigurationStepForm: FC = ({ } return []; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [`${indexData?.indexPatternFields}`]); + }, [`${indexData?.dataViewFields}`]); useEffect(() => { if (typeof savedSearchQueryStr === 'string') { @@ -377,11 +377,11 @@ export const ConfigurationStepForm: FC = ({ useEffect(() => { if (isJobTypeWithDepVar) { - const indexPatternRuntimeFields = getCombinedRuntimeMappings(selectedDataView); + const dataViewRuntimeFields = getCombinedRuntimeMappings(selectedDataView); let runtimeOptions; - if (indexPatternRuntimeFields) { - runtimeOptions = getRuntimeDepVarOptions(jobType, indexPatternRuntimeFields); + if (dataViewRuntimeFields) { + runtimeOptions = getRuntimeDepVarOptions(jobType, dataViewRuntimeFields); } loadDepVarOptions(form, runtimeOptions); @@ -527,7 +527,7 @@ export const ConfigurationStepForm: FC = ({ legendType: getScatterplotMatrixLegendType(jobType), searchQuery: jobConfigQuery, runtimeMappings, - indexPattern: selectedDataView, + dataView: selectedDataView, }), // eslint-disable-next-line react-hooks/exhaustive-deps [ @@ -571,7 +571,7 @@ export const ConfigurationStepForm: FC = ({ const tableItems = includesTableItems.length > 0 && !noDocsContainMappedFields ? includesTableItems - : indexPatternFieldsTableItems; + : dataViewFieldsTableItems; return ( = ({ fullWidth > diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx index dab035945778..fb29df680eda 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx @@ -195,7 +195,7 @@ export const CreateAnalyticsAdvancedEditor: FC = (prop ))} - + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/create_step.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/create_step.tsx index c32530658e6f..63b31ec37feb 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/create_step.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_step/create_step.tsx @@ -5,62 +5,46 @@ * 2.0. */ -import React, { FC, useEffect, useMemo, useState } from 'react'; +import React, { FC, useState } from 'react'; import { EuiButton, - EuiCheckbox, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer, - EuiText, + EuiSwitch, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { CreateDataViewForm } from '@kbn/ml-data-view-utils/components/create_data_view_form_row'; -import { useMlKibana } from '../../../../../contexts/kibana'; import { CreateAnalyticsFormProps } from '../../../analytics_management/hooks/use_create_analytics_form'; import { Messages } from '../shared'; import { ANALYTICS_STEPS } from '../../page'; +import { useCanCreateDataView } from '../../hooks/use_can_create_data_view'; +import { useDataViewTimeFields } from '../../hooks/use_data_view_time_fields'; import { CreateStepFooter } from '../create_step_footer'; interface Props extends CreateAnalyticsFormProps { step: ANALYTICS_STEPS; + showCreateDataView?: boolean; } -export const CreateStep: FC = ({ actions, state, step }) => { - const { - services: { - application: { capabilities }, - }, - } = useMlKibana(); - - const canCreateDataView = useMemo( - () => - capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, - [capabilities] - ); +export const CreateStep: FC = ({ actions, state, step, showCreateDataView = false }) => { + const canCreateDataView = useCanCreateDataView(); + const { dataViewAvailableTimeFields, onTimeFieldChanged } = useDataViewTimeFields({ + actions, + state, + }); const { createAnalyticsJob, setFormState, startAnalyticsJob } = actions; const { isAdvancedEditorValidJson, isJobCreated, isJobStarted, isValid, requestMessages } = state; - const { - createIndexPattern, - destinationIndex, - destinationIndexPatternTitleExists, - jobId, - jobType, - } = state.form; + const { createDataView, destinationDataViewTitleExists, jobId, jobType, timeFieldName } = + state.form; const [startChecked, setStartChecked] = useState(true); const [creationTriggered, setCreationTriggered] = useState(false); const [showProgress, setShowProgress] = useState(false); - useEffect(() => { - if (canCreateDataView === false) { - setFormState({ createIndexPattern: false }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [capabilities]); - if (step !== ANALYTICS_STEPS.CREATE) return null; const handleCreation = async () => { @@ -80,125 +64,62 @@ export const CreateStep: FC = ({ actions, state, step }) => { return (
    {!isJobCreated && !isJobStarted && ( - - - - - - { - setStartChecked(e.target.checked); - if (e.target.checked === false) { - setFormState({ createIndexPattern: false }); - } - }} - /> - - - {startChecked ? ( - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.create.dataViewPermissionWarning', - { - defaultMessage: 'You need permission to create data views.', - } - )} - , - ] - : []), - ...(createIndexPattern && destinationIndexPatternTitleExists - ? [ - i18n.translate( - 'xpack.ml.dataframe.analytics.create.dataViewExistsError', - { - defaultMessage: - 'A data view with the title {title} already exists.', - values: { title: destinationIndex }, - } - ), - ] - : []), - ...(!createIndexPattern && !destinationIndexPatternTitleExists - ? [ - - {i18n.translate( - 'xpack.ml.dataframe.analytics.create.shouldCreateDataViewMessage', - { - defaultMessage: - 'You may not be able to view job results if a data view is not created for the destination index.', - } - )} - , - ] - : []), - ]} - > - setFormState({ createIndexPattern: !createIndexPattern })} - data-test-subj="mlAnalyticsCreateJobWizardCreateIndexPatternCheckbox" - /> - - - ) : null} - - - - - {i18n.translate('xpack.ml.dataframe.analytics.create.wizardCreateButton', { - defaultMessage: 'Create', - })} - - - + <> + {showCreateDataView && ( + <> + setFormState({ createDataView: !createDataView })} + dataViewAvailableTimeFields={dataViewAvailableTimeFields} + dataViewTimeField={timeFieldName} + onTimeFieldChanged={onTimeFieldChanged} + /> + + + )} + + + + + { + setStartChecked(e.target.checked); + }} + /> + + + + + {i18n.translate('xpack.ml.dataframe.analytics.create.wizardCreateButton', { + defaultMessage: 'Create', + })} + + + + )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_form.tsx index 2a86ea3f723c..1948915da69c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_form.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_form.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import React, { FC, Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { FC, Fragment, useEffect, useMemo, useRef, useState } from 'react'; import { debounce } from 'lodash'; -import { EuiFieldText, EuiFormRow, EuiLink, EuiSpacer, EuiSwitch, EuiTextArea } from '@elastic/eui'; +import { EuiFieldText, EuiFormRow, EuiSpacer, EuiSwitch, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { extractErrorMessage } from '@kbn/ml-error-utils'; +import { CreateDataViewForm } from '@kbn/ml-data-view-utils/components/create_data_view_form_row'; +import { DestinationIndexForm } from '@kbn/ml-creation-wizard-utils/components/destination_index_form'; import { useMlKibana } from '../../../../../contexts/kibana'; import { CreateAnalyticsStepProps } from '../../../analytics_management/hooks/use_create_analytics_form'; @@ -17,8 +19,8 @@ import { JOB_ID_MAX_LENGTH } from '../../../../../../../common/constants/validat import { ContinueButton } from '../continue_button'; import { ANALYTICS_STEPS } from '../../page'; import { ml } from '../../../../../services/ml_api_service'; -import { useDataSource } from '../../../../../contexts/ml'; -import { DetailsStepTimeField } from './details_step_time_field'; +import { useCanCreateDataView } from '../../hooks/use_can_create_data_view'; +import { useDataViewTimeFields } from '../../hooks/use_data_view_time_fields'; import { AdditionalSection } from './additional_section'; const DEFAULT_RESULTS_FIELD = 'ml'; @@ -40,13 +42,19 @@ export const DetailsStepForm: FC = ({ services: { docLinks, notifications }, } = useMlKibana(); - const { selectedDataView } = useDataSource(); + const canCreateDataView = useCanCreateDataView(); + const { dataViewAvailableTimeFields, onTimeFieldChanged } = useDataViewTimeFields({ + actions, + state, + }); const createIndexLink = docLinks.links.apis.createIndex; const { setFormState } = actions; const { form, cloneJob, hasSwitchedToEditor, isJobCreated } = state; const { + createDataView, description, + destinationDataViewTitleExists, destinationIndex, destinationIndexNameEmpty, destinationIndexNameExists, @@ -67,41 +75,6 @@ export const DetailsStepForm: FC = ({ (cloneJob === undefined && hasSwitchedToEditor === false && resultsField === undefined) || (cloneJob !== undefined && resultsField === DEFAULT_RESULTS_FIELD) ); - const [dataViewAvailableTimeFields, setDataViewAvailableTimeFields] = useState([]); - - const onTimeFieldChanged = useCallback( - (e: React.ChangeEvent) => { - const value = e.target.value; - // If the value is an empty string, it's not a valid selection - if (value === '') { - return; - } - // Find the time field based on the selected value - // this is to account for undefined when user chooses not to use a date field - const timeField = dataViewAvailableTimeFields.find((col) => col === value); - - setFormState({ timeFieldName: timeField }); - }, - [dataViewAvailableTimeFields, setFormState] - ); - - useEffect(() => { - // Default timeFieldName to the source data view's time field if it exists - if (selectedDataView !== undefined) { - setFormState({ timeFieldName: selectedDataView.timeFieldName }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - // Get possible timefields for the results data view - if (selectedDataView !== undefined) { - const timefields = selectedDataView.fields - .filter((f) => f.type === 'date') - .map((f) => f.name); - setDataViewAvailableTimeFields(timefields); - } - }, [selectedDataView, setFormState]); const forceInput = useRef(null); @@ -110,7 +83,8 @@ export const DetailsStepForm: FC = ({ jobIdExists === true || jobIdValid === false || destinationIndexNameEmpty === true || - destinationIndexNameValid === false; + destinationIndexNameValid === false || + (createDataView && destinationDataViewTitleExists === true); const debouncedIndexCheck = debounce(async () => { try { @@ -265,73 +239,24 @@ export const DetailsStepForm: FC = ({ data-test-subj="mlDFAnalyticsJobCreationJobDescription" /> - - setDestIndexSameAsId(!destIndexSameAsId)} - data-test-subj="mlAnalyticsCreateJobWizardDestIndexSameAsIdSwitch" - /> - - {destIndexSameAsId === false && ( - - {i18n.translate( - 'xpack.ml.dataframe.analytics.create.destinationIndexInvalidError', - { - defaultMessage: 'Invalid destination index name.', - } - )} -
    - - {i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink', - { - defaultMessage: 'Learn more about index name limitations.', - } - )} - - , - ] + setFormState({ destinationIndex: d })} + setDestIndexSameAsId={setDestIndexSameAsId} + switchLabel={i18n.translate( + 'xpack.ml.dataframe.analytics.create.destinationIndexFormSwitchLabel', + { + defaultMessage: 'Use job ID as destination index name', } - > - setFormState({ destinationIndex: e.target.value })} - aria-label={i18n.translate( - 'xpack.ml.dataframe.analytics.create.destinationIndexInputAriaLabel', - { - defaultMessage: 'Choose a unique destination index name.', - } - )} - isInvalid={!destinationIndexNameEmpty && !destinationIndexNameValid} - data-test-subj="mlAnalyticsCreateJobFlyoutDestinationIndexInput" - /> -
    - )} + )} + /> = ({ /> )} - {destinationIndexNameValid && dataViewAvailableTimeFields.length > 0 ? ( - - ) : null} + setFormState({ createDataView: !createDataView })} + dataViewAvailableTimeFields={dataViewAvailableTimeFields} + dataViewTimeField={timeFieldName} + onTimeFieldChanged={onTimeFieldChanged} + /> diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_time_field.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_time_field.tsx deleted file mode 100644 index d7d88325fd1d..000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/details_step/details_step_time_field.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC } from 'react'; -import { EuiFormRow, EuiSelect } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; - -interface Props { - dataViewAvailableTimeFields: string[]; - dataViewTimeField: string | undefined; - onTimeFieldChanged: (e: React.ChangeEvent) => void; -} - -export const DetailsStepTimeField: FC = ({ - dataViewAvailableTimeFields, - dataViewTimeField, - onTimeFieldChanged, -}) => { - const noTimeFieldLabel = i18n.translate( - 'xpack.ml.dataframe.analytics.create.detailsStep.noTimeFieldOptionLabel', - { - defaultMessage: "I don't want to use the time field option", - } - ); - - const noTimeFieldOption = { - text: noTimeFieldLabel, - value: undefined, - }; - - const disabledDividerOption = { - disabled: true, - text: '───', - value: '', - }; - - return ( - - } - helpText={ - - } - > - ({ text })), - disabledDividerOption, - noTimeFieldOption, - ]} - value={dataViewTimeField} - onChange={onTimeFieldChanged} - data-test-subj="mlDataFrameAnalyticsCreateDataViewTimeFieldSelect" - /> - - ); -}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_can_create_data_view.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_can_create_data_view.ts new file mode 100644 index 000000000000..44a362c82a60 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_can_create_data_view.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; + +import { useMlKibana } from '../../../../contexts/kibana'; + +export const useCanCreateDataView = () => { + const { + services: { + application: { capabilities }, + }, + } = useMlKibana(); + + return useMemo( + () => + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, + [capabilities] + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_data_view_time_fields.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_data_view_time_fields.ts new file mode 100644 index 000000000000..624545f0b88c --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_data_view_time_fields.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useEffect, useState } from 'react'; + +import { useDataSource } from '../../../../contexts/ml'; + +import { CreateAnalyticsFormProps } from '../../analytics_management/hooks/use_create_analytics_form'; + +export const useDataViewTimeFields = ({ actions, state }: CreateAnalyticsFormProps) => { + const { setFormState } = actions; + + const { selectedDataView } = useDataSource(); + + const [dataViewAvailableTimeFields, setDataViewAvailableTimeFields] = useState([]); + + const onTimeFieldChanged = useCallback( + (e: React.ChangeEvent) => { + const value = e.target.value; + // If the value is an empty string, it's not a valid selection + if (value === '') { + return; + } + // Find the time field based on the selected value + // this is to account for undefined when user chooses not to use a date field + const timeField = dataViewAvailableTimeFields.find((col) => col === value); + + setFormState({ timeFieldName: timeField }); + }, + [dataViewAvailableTimeFields, setFormState] + ); + + useEffect(() => { + // Default timeFieldName to the source data view's time field if it exists + if (selectedDataView !== undefined) { + setFormState({ timeFieldName: selectedDataView.timeFieldName }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + // Get possible timefields for the results data view + if (selectedDataView !== undefined) { + const timefields = selectedDataView.fields + .filter((f) => f.type === 'date') + .map((f) => f.name); + setDataViewAvailableTimeFields(timefields); + } + }, [selectedDataView, setFormState]); + + return { dataViewAvailableTimeFields, onTimeFieldChanged }; +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts index cf3c0fcf05ef..2336113f917d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts @@ -25,7 +25,7 @@ import { getFieldType, getDataGridSchemaFromKibanaFieldType, getDataGridSchemaFromESFieldType, - getFieldsFromKibanaIndexPattern, + getFieldsFromKibanaDataView, showDataGridColumnChartErrorMessageToast, useDataGrid, useRenderCellValue, @@ -58,8 +58,8 @@ function getRuntimeFieldColumns(runtimeMappings: RuntimeMappings) { }); } -function getIndexPatternColumns(indexPattern: DataView, fieldsFilter: string[]) { - const { fields } = indexPattern; +function getDataViewColumns(dataView: DataView, fieldsFilter: string[]) { + const { fields } = dataView; return fields .filter((field) => fieldsFilter.includes(field.name)) @@ -78,7 +78,7 @@ function getIndexPatternColumns(indexPattern: DataView, fieldsFilter: string[]) } export const useIndexData = ( - indexPattern: DataView, + dataView: DataView, query: Record | undefined, toastNotifications: CoreSetup['notifications']['toasts'], runtimeMappings?: RuntimeMappings @@ -87,7 +87,7 @@ export const useIndexData = ( // This is a workaround to avoid passing potentially thousands of unpopulated fields // (for example, as part of filebeat/metricbeat/ECS based indices) // to the data grid component which would significantly slow down the page. - const [indexPatternFields, setIndexPatternFields] = useState(); + const [dataViewFields, setDataViewFields] = useState(); const [timeRangeMs, setTimeRangeMs] = useState(); useEffect(() => { @@ -96,7 +96,7 @@ export const useIndexData = ( setStatus(INDEX_STATUS.LOADING); const esSearchRequest = { - index: indexPattern.title, + index: dataView.title, body: { fields: ['*'], _source: false, @@ -116,13 +116,13 @@ export const useIndexData = ( // Get all field names for each returned doc and flatten it // to a list of unique field names used across all docs. - const allDataViewFields = getFieldsFromKibanaIndexPattern(indexPattern); + const allDataViewFields = getFieldsFromKibanaDataView(dataView); const populatedFields = [...new Set(docs.map(Object.keys).flat(1))] .filter((d) => allDataViewFields.includes(d)) .sort(); setStatus(INDEX_STATUS.LOADED); - setIndexPatternFields(populatedFields); + setDataViewFields(populatedFields); } catch (e) { setErrorMessage(extractErrorMessage(e)); setStatus(INDEX_STATUS.ERROR); @@ -136,20 +136,20 @@ export const useIndexData = ( // To be used for data grid column selection // and will be applied to doc and chart queries. const combinedRuntimeMappings = useMemo( - () => getCombinedRuntimeMappings(indexPattern, runtimeMappings), - [indexPattern, runtimeMappings] + () => getCombinedRuntimeMappings(dataView, runtimeMappings), + [dataView, runtimeMappings] ); // Available data grid columns, will be a combination of index pattern and runtime fields. const [columns, setColumns] = useState([]); useEffect(() => { - if (Array.isArray(indexPatternFields)) { + if (Array.isArray(dataViewFields)) { setColumns([ - ...getIndexPatternColumns(indexPattern, indexPatternFields), + ...getDataViewColumns(dataView, dataViewFields), ...(combinedRuntimeMappings ? getRuntimeFieldColumns(combinedRuntimeMappings) : []), ]); } - }, [indexPattern, indexPatternFields, combinedRuntimeMappings]); + }, [dataView, dataViewFields, combinedRuntimeMappings]); const dataGrid = useDataGrid(columns); @@ -175,19 +175,19 @@ export const useIndexData = ( setErrorMessage(''); setStatus(INDEX_STATUS.LOADING); - const timeFieldName = indexPattern.getTimeField()?.name; + const timeFieldName = dataView.getTimeField()?.name; const sort: EsSorting = sortingColumns.reduce((s, column) => { s[column.id] = { order: column.direction }; return s; }, {} as EsSorting); const esSearchRequest = { - index: indexPattern.title, + index: dataView.title, body: { query, from: pagination.pageIndex * pagination.pageSize, size: pagination.pageSize, fields: [ - ...(indexPatternFields ?? []), + ...(dataViewFields ?? []), ...(isRuntimeMappings(combinedRuntimeMappings) ? Object.keys(combinedRuntimeMappings) : []), @@ -246,22 +246,22 @@ export const useIndexData = ( } } - if (indexPatternFields !== undefined && query !== undefined) { + if (dataViewFields !== undefined && query !== undefined) { fetchIndexData(); } // custom comparison // eslint-disable-next-line react-hooks/exhaustive-deps }, [ - indexPattern.title, - indexPatternFields, + dataView.title, + dataViewFields, // eslint-disable-next-line react-hooks/exhaustive-deps JSON.stringify([query, pagination, sortingColumns, combinedRuntimeMappings]), ]); const dataLoader = useMemo( - () => new DataLoader(indexPattern, toastNotifications), + () => new DataLoader(dataView, toastNotifications), // eslint-disable-next-line react-hooks/exhaustive-deps - [indexPattern] + [dataView] ); useEffect(() => { @@ -291,16 +291,16 @@ export const useIndexData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [ dataGrid.chartsVisible, - indexPattern.title, + dataView.title, // eslint-disable-next-line react-hooks/exhaustive-deps JSON.stringify([query, dataGrid.visibleColumns, runtimeMappings]), ]); - const renderCellValue = useRenderCellValue(indexPattern, pagination, tableItems); + const renderCellValue = useRenderCellValue(dataView, pagination, tableItems); return { ...dataGrid, - indexPatternFields, + dataViewFields, renderCellValue, timeRangeMs, }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx new file mode 100644 index 000000000000..922ef80b3d1f --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/data_view_prompt.tsx @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC, useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiLink, EuiText } from '@elastic/eui'; +import { useMlKibana } from '../../../../../contexts/kibana'; + +interface Props { + color?: string; + destIndex?: string; +} + +export const DataViewPrompt: FC = ({ destIndex, color }) => { + const { + services: { + http: { basePath }, + application: { capabilities }, + }, + } = useMlKibana(); + + const canCreateDataView = useMemo( + () => + capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, + [capabilities] + ); + + return ( + <> + + + {canCreateDataView === true ? ( + + + + ), + }} + /> + ) : null} + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/index.ts new file mode 100644 index 000000000000..4c5dbfd0a67b --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/data_view_prompt/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { DataViewPrompt } from './data_view_prompt'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx index 4e89a2a0833a..d47dc0212f50 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx @@ -59,7 +59,7 @@ import { replaceStringTokens } from '../../../../../util/string_utils'; import { parseInterval } from '../../../../../../../common/util/parse_interval'; import { ExpandableSection, ExpandableSectionProps, HEADER_ITEMS_LOADING } from '.'; -import { IndexPatternPrompt } from '../index_pattern_prompt'; +import { DataViewPrompt } from '../data_view_prompt'; const showingDocs = i18n.translate( 'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText', @@ -121,9 +121,9 @@ const getResultsSectionHeaderItems = ( interface ExpandableSectionResultsProps { colorRange?: ReturnType; indexData: UseIndexDataReturnType; - indexPattern?: DataView; + dataView?: DataView; jobConfig?: DataFrameAnalyticsConfig; - needsDestIndexPattern: boolean; + needsDestDataView: boolean; resultsField?: string; searchQuery: estypes.QueryDslQueryContainer; } @@ -131,9 +131,9 @@ interface ExpandableSectionResultsProps { export const ExpandableSectionResults: FC = ({ colorRange, indexData, - indexPattern, + dataView, jobConfig, - needsDestIndexPattern, + needsDestDataView, resultsField, searchQuery, }) => { @@ -146,7 +146,7 @@ export const ExpandableSectionResults: FC = ({ }, } = useMlKibana(); - const dataViewId = indexPattern?.id; + const dataViewId = dataView?.id; const discoverLocator = useMemo( () => share.url.locators.get('DISCOVER_APP_LOCATOR'), @@ -206,7 +206,7 @@ export const ExpandableSectionResults: FC = ({ if (discoverLocator !== undefined) { const url = await discoverLocator.getRedirectUrl({ - indexPatternId: dataViewId, + dataViewId, timeRange: data.query.timefilter.timefilter.getTime(), filters: data.query.filterManager.getFilters(), query: { @@ -239,7 +239,7 @@ export const ExpandableSectionResults: FC = ({ if (timeRangeInterval !== null) { // Create a copy of the record as we are adding properties into it. const record = cloneDeep(item); - const timestamp = record[indexPattern!.timeFieldName!]; + const timestamp = record[dataView!.timeFieldName!]; const configuredUrlValue = customUrl.url_value; if (configuredUrlValue.includes('$earliest$')) { @@ -373,9 +373,9 @@ export const ExpandableSectionResults: FC = ({ const resultsSectionContent = ( <> - {jobConfig !== undefined && needsDestIndexPattern && ( + {jobConfig !== undefined && needsDestDataView && (
    - +
    )} {jobConfig !== undefined && @@ -386,7 +386,7 @@ export const ExpandableSectionResults: FC = ({ )} {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && - indexPattern !== undefined && ( + dataView !== undefined && ( <> {columnsWithCharts.length > 0 && (tableItems.length > 0 || status === INDEX_STATUS.LOADED) && ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx index 348c7051993a..bd5cd677a714 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx @@ -35,7 +35,7 @@ import { LoadingPanel } from '../loading_panel'; import { FeatureImportanceSummaryPanelProps } from '../total_feature_importance_summary/feature_importance_summary'; import { useExplorationUrlState } from '../../hooks/use_exploration_url_state'; import { ExplorationQueryBarProps } from '../exploration_query_bar/exploration_query_bar'; -import { IndexPatternPrompt } from '../index_pattern_prompt'; +import { DataViewPrompt } from '../data_view_prompt'; function getFilters(resultsField: string) { return { @@ -84,15 +84,15 @@ export const ExplorationPageWrapper: FC = ({ FeatureImportanceSummaryPanel, }) => { const { - indexPattern, - indexPatternErrorMessage, + dataView, + dataViewErrorMessage, isInitialized, isLoadingJobConfig, jobCapsServiceErrorMessage, jobConfig, jobConfigErrorMessage, jobStatus, - needsDestIndexPattern, + needsDestDataView, totalFeatureImportance, } = useResultsViewConfig(jobId); @@ -121,13 +121,13 @@ export const ExplorationPageWrapper: FC = ({ const destIndex = getDestinationIndex(jobConfig); const scatterplotFieldOptions = useScatterplotFieldOptions( - indexPattern, + dataView, jobConfig?.analyzed_fields?.includes, jobConfig?.analyzed_fields?.excludes, resultsField ); - if (indexPatternErrorMessage !== undefined) { + if (dataViewErrorMessage !== undefined) { return ( = ({ iconType="cross" >

    - {indexPatternErrorMessage} - {needsDestIndexPattern ? ( - - ) : null} + {dataViewErrorMessage} + {needsDestDataView ? : null}

    @@ -170,7 +168,7 @@ export const ExplorationPageWrapper: FC = ({ )} - {indexPattern !== undefined && jobConfig && ( + {dataView !== undefined && jobConfig && ( <> @@ -178,7 +176,7 @@ export const ExplorationPageWrapper: FC = ({ = ({ = ({ {isLoadingJobConfig === true && jobConfig === undefined && } {isLoadingJobConfig === false && jobConfig !== undefined && - indexPattern !== undefined && + dataView !== undefined && isInitialized === true && ( )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx index e2998651f2c2..e1efd592e956 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx @@ -25,7 +25,7 @@ import { removeFilterFromQueryString } from '../../../../../explorer/explorer_ut import { useMlKibana } from '../../../../../contexts/kibana'; export interface ExplorationQueryBarProps { - indexPattern: DataView; + dataView: DataView; setSearchQuery: (update: { queryString: string; query?: estypes.QueryDslQueryContainer; @@ -41,7 +41,7 @@ export interface ExplorationQueryBarProps { } export const ExplorationQueryBar: FC = ({ - indexPattern, + dataView, setSearchQuery, filters, query, @@ -99,7 +99,7 @@ export const ExplorationQueryBar: FC = ({ case SEARCH_QUERY_LANGUAGE.KUERY: convertedQuery = toElasticsearchQuery( fromKueryExpression(query.query as string), - indexPattern + dataView ); break; case SEARCH_QUERY_LANGUAGE.LUCENE: @@ -181,7 +181,7 @@ export const ExplorationQueryBar: FC = ({ = React.memo( - ({ indexPattern, jobConfig, needsDestIndexPattern, searchQuery }) => { + ({ dataView, jobConfig, needsDestDataView, searchQuery }) => { const { services: { mlServices: { mlApiServices }, @@ -39,7 +39,7 @@ export const ExplorationResultsTable: FC = React.memo( } = useMlKibana(); const classificationData = useExplorationResults( - indexPattern, + dataView, jobConfig, searchQuery, getToastNotifications(), @@ -54,10 +54,10 @@ export const ExplorationResultsTable: FC = React.memo(
    diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts index c7216037241d..0a5dd784a649 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts @@ -43,7 +43,7 @@ import { useTrainedModelsApiService } from '../../../../../services/ml_api_servi import { useExplorationDataGrid } from './use_exploration_data_grid'; export const useExplorationResults = ( - indexPattern: DataView | undefined, + dataView: DataView | undefined, jobConfig: DataFrameAnalyticsConfig | undefined, searchQuery: estypes.QueryDslQueryContainer, toastNotifications: CoreSetup['notifications']['toasts'], @@ -54,7 +54,7 @@ export const useExplorationResults = ( const trainedModelsApiService = useTrainedModelsApiService(); const needsDestIndexFields = - indexPattern !== undefined && indexPattern.title === jobConfig?.source.index[0]; + dataView !== undefined && dataView.title === jobConfig?.source.index[0]; const columns: EuiDataGridColumn[] = []; @@ -90,10 +90,9 @@ export const useExplorationResults = ( }, [jobConfig && jobConfig.id, dataGrid.pagination, searchQuery, dataGrid.sortingColumns]); const dataLoader = useMemo( - () => - indexPattern !== undefined ? new DataLoader(indexPattern, toastNotifications) : undefined, + () => (dataView !== undefined ? new DataLoader(dataView, toastNotifications) : undefined), // eslint-disable-next-line react-hooks/exhaustive-deps - [indexPattern] + [dataView] ); const fetchColumnChartsData = async function () { @@ -179,7 +178,7 @@ export const useExplorationResults = ( const resultsField = jobConfig?.dest.results_field ?? DEFAULT_RESULTS_FIELD; const renderCellValue = useRenderCellValue( - indexPattern, + dataView, dataGrid.pagination, dataGrid.tableItems, resultsField diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index.ts deleted file mode 100644 index e78ffe1c9086..000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { IndexPatternPrompt } from './index_pattern_prompt'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx deleted file mode 100644 index cd60be7290b9..000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC, useMemo } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiLink, EuiText } from '@elastic/eui'; -import { useMlKibana } from '../../../../../contexts/kibana'; - -interface Props { - color?: string; - destIndex?: string; -} - -export const IndexPatternPrompt: FC = ({ destIndex, color }) => { - const { - services: { - http: { basePath }, - application: { capabilities }, - }, - } = useMlKibana(); - - const canCreateDataView = useMemo( - () => - capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true, - [capabilities] - ); - - return ( - <> - - - {canCreateDataView === true ? ( - - - - ), - }} - /> - ) : null} - - - ); -}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx index 9fc517d293e7..9cbca46a03c8 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx @@ -37,7 +37,7 @@ export const JobConfigErrorCallout: FC = ({ application: { getUrlForApp }, }, } = useMlKibana(); - const containsIndexPatternLink = + const containsDataViewLink = typeof jobCapsServiceErrorMessage === 'string' && jobCapsServiceErrorMessage.includes('locate that index-pattern') && jobCapsServiceErrorMessage.includes('click here to re-create'); @@ -45,7 +45,7 @@ export const JobConfigErrorCallout: FC = ({ const message = (

    {jobConfigErrorMessage ? jobConfigErrorMessage : jobCapsServiceErrorMessage}

    ); - const newIndexPatternUrl = useMemo( + const newDataViewUrl = useMemo( () => getUrlForApp('management', { path: 'kibana/indexPatterns', @@ -54,8 +54,8 @@ export const JobConfigErrorCallout: FC = ({ [] ); - const calloutBody = containsIndexPatternLink ? ( - + const calloutBody = containsDataViewLink ? ( + {message} ) : ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx index f8fa311cb8a2..8259ec4188c3 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx @@ -33,7 +33,7 @@ import { getFeatureCount } from './common'; import { useOutlierData } from './use_outlier_data'; import { useExplorationUrlState } from '../../hooks/use_exploration_url_state'; import { ExplorationQueryBarProps } from '../exploration_query_bar/exploration_query_bar'; -import { IndexPatternPrompt } from '../index_pattern_prompt'; +import { DataViewPrompt } from '../data_view_prompt'; export type TableItem = Record; @@ -42,12 +42,12 @@ interface ExplorationProps { } export const OutlierExploration: FC = React.memo(({ jobId }) => { - const { indexPattern, indexPatternErrorMessage, jobConfig, needsDestIndexPattern } = + const { dataView, dataViewErrorMessage, jobConfig, needsDestDataView } = useResultsViewConfig(jobId); const [pageUrlState, setPageUrlState] = useExplorationUrlState(); const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); - const outlierData = useOutlierData(indexPattern, jobConfig, searchQuery); + const outlierData = useOutlierData(dataView, jobConfig, searchQuery); const searchQueryUpdateHandler: ExplorationQueryBarProps['setSearchQuery'] = useCallback( (update) => { @@ -81,20 +81,20 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = // If feature influence was enabled for the legacy job we'll show a callout // with some additional information for a workaround. const showLegacyFeatureInfluenceFormatCallout = - !needsDestIndexPattern && + !needsDestDataView && isOutlierAnalysis(jobConfig?.analysis) && jobConfig?.analysis.outlier_detection.compute_feature_influence === true && columnsWithCharts.findIndex((d) => d.id === `${resultsField}.${FEATURE_INFLUENCE}`) === -1; const scatterplotFieldOptions = useScatterplotFieldOptions( - indexPattern, + dataView, jobConfig?.analyzed_fields?.includes, jobConfig?.analyzed_fields?.excludes, resultsField ); const destIndex = getDestinationIndex(jobConfig); - if (indexPatternErrorMessage !== undefined) { + if (dataViewErrorMessage !== undefined) { return ( = React.memo(({ jobId }) = iconType="cross" >

    - {indexPatternErrorMessage} - {needsDestIndexPattern ? ( - - ) : null} + {dataViewErrorMessage} + {needsDestDataView ? : null}

    @@ -124,10 +122,10 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = )} {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && - indexPattern !== undefined && ( + dataView !== undefined && ( <> @@ -165,9 +163,9 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = showColorRange && !showLegacyFeatureInfluenceFormatCallout ? colorRange : undefined } indexData={outlierData} - indexPattern={indexPattern} + dataView={dataView} jobConfig={jobConfig} - needsDestIndexPattern={needsDestIndexPattern} + needsDestDataView={needsDestDataView} searchQuery={searchQuery} /> diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts index 73d88ecff6a2..4be312056992 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts @@ -41,17 +41,17 @@ import { getFeatureCount, getOutlierScoreFieldName } from './common'; import { useExplorationDataGrid } from '../exploration_results_table/use_exploration_data_grid'; export const useOutlierData = ( - indexPattern: DataView | undefined, + dataView: DataView | undefined, jobConfig: DataFrameAnalyticsConfig | undefined, searchQuery: estypes.QueryDslQueryContainer ): UseIndexDataReturnType => { const needsDestIndexFields = - indexPattern !== undefined && indexPattern.title === jobConfig?.source.index[0]; + dataView !== undefined && dataView.title === jobConfig?.source.index[0]; const columns = useMemo(() => { const newColumns: EuiDataGridColumn[] = []; - if (jobConfig !== undefined && indexPattern !== undefined) { + if (jobConfig !== undefined && dataView !== undefined) { const resultsField = jobConfig.dest.results_field; const { fieldTypes } = getIndexFields(jobConfig, needsDestIndexFields); newColumns.push( @@ -63,7 +63,7 @@ export const useOutlierData = ( return newColumns; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [jobConfig, indexPattern]); + }, [jobConfig, dataView]); const dataGrid = useExplorationDataGrid( columns, @@ -95,11 +95,8 @@ export const useOutlierData = ( }, [jobConfig && jobConfig.id, dataGrid.pagination, searchQuery, dataGrid.sortingColumns]); const dataLoader = useMemo( - () => - indexPattern !== undefined - ? new DataLoader(indexPattern, getToastNotifications()) - : undefined, - [indexPattern] + () => (dataView !== undefined ? new DataLoader(dataView, getToastNotifications()) : undefined), + [dataView] ); const fetchColumnChartsData = async function () { @@ -146,7 +143,7 @@ export const useOutlierData = ( ); const renderCellValue = useRenderCellValue( - indexPattern, + dataView, dataGrid.pagination, dataGrid.tableItems, jobConfig?.dest.results_field ?? DEFAULT_RESULTS_FIELD, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx index 3d22ed72487f..d18c43cda549 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_modal.tsx @@ -21,12 +21,12 @@ export const DeleteActionModal: FC = ({ closeModal, deleteAndCloseModal, deleteTargetIndex, - deleteIndexPattern, - indexPatternExists, + deleteDataView, + dataViewExists, isLoading, item, toggleDeleteIndex, - toggleDeleteIndexPattern, + toggleDeleteDataView, userCanDeleteIndex, userCanDeleteDataView, }) => { @@ -77,15 +77,15 @@ export const DeleteActionModal: FC = ({ )}
    - {userCanDeleteIndex && indexPatternExists && ( + {userCanDeleteIndex && dataViewExists && ( )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx index d9a888b9e314..03364165095d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/delete_action_name.test.tsx @@ -99,7 +99,7 @@ describe('DeleteAction', () => { fireEvent.click(deleteButton); expect(getByTestId('mlAnalyticsJobDeleteModal')).toBeInTheDocument(); expect(queryByTestId('mlAnalyticsJobDeleteIndexSwitch')).toBeNull(); - expect(queryByTestId('mlAnalyticsJobDeleteIndexPatternSwitch')).toBeNull(); + expect(queryByTestId('mlAnalyticsJobDeleteDataViewSwitch')).toBeNull(); mock.mockRestore(); }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx index 1a828f6b6cdf..f4c2773cd42f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_delete/use_delete_action.tsx @@ -42,10 +42,10 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { const [isDeleteJobCheckModalVisible, setDeleteJobCheckModalVisible] = useState(false); const [deleteItem, setDeleteItem] = useState(false); const [deleteTargetIndex, setDeleteTargetIndex] = useState(true); - const [deleteIndexPattern, setDeleteIndexPattern] = useState(true); + const [deleteDataView, setDeleteDataView] = useState(true); const [userCanDeleteIndex, setUserCanDeleteIndex] = useState(false); const [userCanDeleteDataView, setUserCanDeleteDataView] = useState(false); - const [indexPatternExists, setIndexPatternExists] = useState(false); + const [dataViewExists, setDataViewExists] = useState(false); const [isLoading, setIsLoading] = useState(false); const { @@ -57,13 +57,13 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { const toastNotificationService = useToastNotificationService(); - const checkIndexPatternExists = async () => { + const checkDataViewExists = async () => { try { const dv = (await dataViews.getIdsWithTitle()).find(({ title }) => title === indexName); if (dv !== undefined) { - setIndexPatternExists(true); + setDataViewExists(true); } else { - setIndexPatternExists(false); + setDataViewExists(false); } setIsLoading(false); } catch (e) { @@ -93,7 +93,7 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { capabilities.indexPatterns.save === true; setUserCanDeleteDataView(canDeleteDataView); if (canDeleteDataView === false) { - setDeleteIndexPattern(false); + setDeleteDataView(false); } } catch (e) { const error = extractErrorMessage(e); @@ -116,7 +116,7 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { setIsLoading(true); // Check if a data view exists corresponding to current DFA job // if data view does exist, show it to user - checkIndexPatternExists(); + checkDataViewExists(); // Check if an user has permission to delete the index & data view checkUserIndexPermission(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -129,12 +129,12 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { setModalVisible(false); if (item !== undefined) { - if ((userCanDeleteIndex && deleteTargetIndex) || (userCanDeleteIndex && deleteIndexPattern)) { + if ((userCanDeleteIndex && deleteTargetIndex) || (userCanDeleteIndex && deleteDataView)) { deleteAnalyticsAndDestIndex( item.config, item.stats, deleteTargetIndex, - indexPatternExists && deleteIndexPattern, + dataViewExists && deleteDataView, toastNotificationService ); } else { @@ -143,7 +143,7 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { } }; const toggleDeleteIndex = () => setDeleteTargetIndex(!deleteTargetIndex); - const toggleDeleteIndexPattern = () => setDeleteIndexPattern(!deleteIndexPattern); + const toggleDeleteDataView = () => setDeleteDataView(!deleteDataView); const openModal = (newItem: DataFrameAnalyticsListRowEssentials) => { setItem(newItem); @@ -181,9 +181,9 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { closeModal, deleteAndCloseModal, deleteTargetIndex, - deleteIndexPattern, + deleteDataView, deleteItem, - indexPatternExists, + dataViewExists, isDeleteJobCheckModalVisible, isModalVisible, isLoading, @@ -192,7 +192,7 @@ export const useDeleteAction = (canDeleteDataFrameAnalytics: boolean) => { openModal, openDeleteJobCheckModal, toggleDeleteIndex, - toggleDeleteIndexPattern, + toggleDeleteDataView, userCanDeleteIndex, userCanDeleteDataView, }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index 89c16fbb9305..9525042f6a47 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -146,7 +146,7 @@ export const SourceSelection: FC = () => { type: 'index-pattern', getIconForSavedObject: () => 'indexPatternApp', name: i18n.translate( - 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern', + 'xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.dataView', { defaultMessage: 'Data view', } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/actions.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/actions.ts index b9b8de0ce0d5..a1dffe771d8d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/actions.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/actions.ts @@ -18,7 +18,7 @@ export enum ACTION { RESET_FORM, SET_ADVANCED_EDITOR_RAW_STRING, SET_FORM_STATE, - SET_INDEX_PATTERN_TITLES, + SET_DATA_VIEW_TITLES, SET_IS_JOB_CREATED, SET_IS_JOB_STARTED, SET_IS_MODAL_BUTTON_DISABLED, @@ -51,9 +51,9 @@ export type Action = } | { type: ACTION.SET_FORM_STATE; payload: Partial } | { - type: ACTION.SET_INDEX_PATTERN_TITLES; + type: ACTION.SET_DATA_VIEW_TITLES; payload: { - indexPatternsMap: SourceIndexMap; + dataViewsMap: SourceIndexMap; }; } | { type: ACTION.SET_IS_JOB_CREATED; isJobCreated: State['isJobCreated'] } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts index 1a5beada2c3c..5f02d7bbbb4f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts @@ -39,7 +39,7 @@ const getMockState = ({ jobIdEmpty: false, jobIdValid: true, jobIdExists: false, - createIndexPattern: false, + createDataView: false, }, jobConfig: { source: { index }, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts index 69eececeba12..d2689a009fb1 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts @@ -148,7 +148,7 @@ export const validateNumTopFeatureImportanceValues = ( }; export const validateAdvancedEditor = (state: State): State => { - const { jobIdEmpty, jobIdValid, jobIdExists, jobType, createIndexPattern } = state.form; + const { jobIdEmpty, jobIdValid, jobIdExists, jobType, createDataView } = state.form; const { jobConfig } = state; state.advancedEditorMessages = []; @@ -161,8 +161,7 @@ export const validateAdvancedEditor = (state: State): State => { const destinationIndexName = jobConfig?.dest?.index ?? ''; const destinationIndexNameEmpty = destinationIndexName === ''; const destinationIndexNameValid = isValidIndexName(destinationIndexName); - const destinationIndexPatternTitleExists = - state.indexPatternsMap[destinationIndexName] !== undefined; + const destinationDataViewTitleExists = state.dataViewsMap[destinationIndexName] !== undefined; const analyzedFields = jobConfig?.analyzed_fields?.includes || []; @@ -294,7 +293,7 @@ export const validateAdvancedEditor = (state: State): State => { ), message: '', }); - } else if (destinationIndexPatternTitleExists && !createIndexPattern) { + } else if (destinationDataViewTitleExists && !createDataView) { state.advancedEditorMessages.push({ error: i18n.translate( 'xpack.ml.dataframe.analytics.create.advancedEditorMessage.destinationIndexNameExistsWarn', @@ -360,7 +359,7 @@ export const validateAdvancedEditor = (state: State): State => { }); } - state.form.destinationIndexPatternTitleExists = destinationIndexPatternTitleExists; + state.form.destinationDataViewTitleExists = destinationDataViewTitleExists; state.isValid = includesValid && @@ -377,7 +376,7 @@ export const validateAdvancedEditor = (state: State): State => { !dependentVariableEmpty && !modelMemoryLimitEmpty && (numTopFeatureImportanceValuesValid || jobType === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION) && - (!destinationIndexPatternTitleExists || !createIndexPattern); + (!destinationDataViewTitleExists || !createDataView); return state; }; @@ -425,8 +424,8 @@ const validateForm = (state: State): State => { sourceIndexNameValid, destinationIndexNameEmpty, destinationIndexNameValid, - destinationIndexPatternTitleExists, - createIndexPattern, + destinationDataViewTitleExists, + createDataView, dependentVariable, modelMemoryLimit, numTopFeatureImportanceValuesValid, @@ -458,7 +457,7 @@ const validateForm = (state: State): State => { destinationIndexNameValid && !dependentVariableEmpty && (numTopFeatureImportanceValuesValid || jobType === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION) && - (!destinationIndexPatternTitleExists || !createIndexPattern); + (!destinationDataViewTitleExists || !createDataView); return state; }; @@ -513,8 +512,8 @@ export function reducer(state: State, action: Action): State { if (action.payload.destinationIndex !== undefined) { newFormState.destinationIndexNameEmpty = newFormState.destinationIndex === ''; newFormState.destinationIndexNameValid = isValidIndexName(newFormState.destinationIndex); - newFormState.destinationIndexPatternTitleExists = - state.indexPatternsMap[newFormState.destinationIndex] !== undefined; + newFormState.destinationDataViewTitleExists = + state.dataViewsMap[newFormState.destinationIndex] !== undefined; } if (action.payload.jobId !== undefined) { @@ -541,13 +540,13 @@ export function reducer(state: State, action: Action): State { ? validateAdvancedEditor({ ...state, form: newFormState }) : validateForm({ ...state, form: newFormState }); - case ACTION.SET_INDEX_PATTERN_TITLES: { + case ACTION.SET_DATA_VIEW_TITLES: { const newState = { ...state, ...action.payload, }; - newState.form.destinationIndexPatternTitleExists = - newState.indexPatternsMap[newState.form.destinationIndex] !== undefined; + newState.form.destinationDataViewTitleExists = + newState.dataViewsMap[newState.form.destinationIndex] !== undefined; return newState; } @@ -591,8 +590,8 @@ export function reducer(state: State, action: Action): State { formState.destinationIndexNameEmpty = formState.destinationIndex === ''; formState.destinationIndexNameValid = isValidIndexName(formState.destinationIndex || ''); - formState.destinationIndexPatternTitleExists = - state.indexPatternsMap[formState.destinationIndex || ''] !== undefined; + formState.destinationDataViewTitleExists = + state.dataViewsMap[formState.destinationIndex || ''] !== undefined; if (formState.numTopFeatureImportanceValues !== undefined) { formState.numTopFeatureImportanceValuesValid = validateNumTopFeatureImportanceValues( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts index d567c7d19b3d..efffc221c317 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts @@ -35,13 +35,10 @@ export const UNSET_CONFIG_ITEM = '--'; export type EsIndexName = string; export type DependentVariable = string; -export type IndexPatternTitle = string; +export type DataViewTitle = string; export type AnalyticsJobType = DataFrameAnalysisConfigType | undefined; -type IndexPatternId = string; -export type SourceIndexMap = Record< - IndexPatternTitle, - { label: IndexPatternTitle; value: IndexPatternId } ->; +type DataViewId = string; +export type SourceIndexMap = Record; export interface FormMessage { error?: string; @@ -55,7 +52,7 @@ export interface State { form: { alpha: undefined | number; computeFeatureInfluence: string; - createIndexPattern: boolean; + createDataView: boolean; classAssignmentObjective: undefined | string; dependentVariable: DependentVariable; description: string; @@ -63,7 +60,7 @@ export interface State { destinationIndexNameExists: boolean; destinationIndexNameEmpty: boolean; destinationIndexNameValid: boolean; - destinationIndexPatternTitleExists: boolean; + destinationDataViewTitleExists: boolean; downsampleFactor: undefined | number; earlyStoppingEnabled: undefined | boolean; eta: undefined | number; @@ -120,7 +117,7 @@ export interface State { useEstimatedMml: boolean; }; disabled: boolean; - indexPatternsMap: SourceIndexMap; + dataViewsMap: SourceIndexMap; isAdvancedEditorEnabled: boolean; isAdvancedEditorValidJson: boolean; hasSwitchedToEditor: boolean; @@ -141,7 +138,7 @@ export const getInitialState = (): State => ({ form: { alpha: undefined, computeFeatureInfluence: 'true', - createIndexPattern: true, + createDataView: true, classAssignmentObjective: undefined, dependentVariable: '', description: '', @@ -149,7 +146,7 @@ export const getInitialState = (): State => ({ destinationIndexNameExists: false, destinationIndexNameEmpty: true, destinationIndexNameValid: false, - destinationIndexPatternTitleExists: false, + destinationDataViewTitleExists: false, earlyStoppingEnabled: undefined, downsampleFactor: undefined, eta: undefined, @@ -210,7 +207,7 @@ export const getInitialState = (): State => ({ !mlNodesAvailable() || !checkPermission('canCreateDataFrameAnalytics') || !checkPermission('canStartStopDataFrameAnalytics'), - indexPatternsMap: {}, + dataViewsMap: {}, isAdvancedEditorEnabled: false, isAdvancedEditorValidJson: true, hasSwitchedToEditor: false, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/use_create_analytics_form.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/use_create_analytics_form.ts index e7b618808100..c097577bc289 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/use_create_analytics_form.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/use_create_analytics_form.ts @@ -18,7 +18,6 @@ import { ml } from '../../../../../services/ml_api_service'; import { useRefreshAnalyticsList } from '../../../../common'; import { extractCloningConfig, isAdvancedConfig } from '../../components/action_clone'; -import { createKibanaDataView } from '../../../../../components/ml_inference/retry_create_data_view'; import { ActionDispatchers, ACTION } from './actions'; import { reducer } from './reducer'; @@ -59,8 +58,7 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => { const { refresh } = useRefreshAnalyticsList(); const { form, jobConfig, isAdvancedEditorEnabled } = state; - const { createIndexPattern, jobId } = form; - let { destinationIndex } = form; + const { createDataView, jobId } = form; const addRequestMessage = (requestMessage: FormMessage) => dispatch({ type: ACTION.ADD_REQUEST_MESSAGE, requestMessage }); @@ -73,8 +71,8 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => { const setAdvancedEditorRawString = (advancedEditorRawString: string) => dispatch({ type: ACTION.SET_ADVANCED_EDITOR_RAW_STRING, advancedEditorRawString }); - const setIndexPatternTitles = (payload: { indexPatternsMap: SourceIndexMap }) => - dispatch({ type: ACTION.SET_INDEX_PATTERN_TITLES, payload }); + const setDataViewTitles = (payload: { dataViewsMap: SourceIndexMap }) => + dispatch({ type: ACTION.SET_DATA_VIEW_TITLES, payload }); const setIsJobCreated = (isJobCreated: boolean) => dispatch({ type: ACTION.SET_IS_JOB_CREATED, isJobCreated }); @@ -94,12 +92,13 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => { isAdvancedEditorEnabled ? jobConfig : getJobConfigFromFormState(form) ) as DataFrameAnalyticsConfig; - if (isAdvancedEditorEnabled) { - destinationIndex = analyticsJobConfig.dest.index; - } - try { - await ml.dataFrameAnalytics.createDataFrameAnalytics(jobId, analyticsJobConfig); + await ml.dataFrameAnalytics.createDataFrameAnalytics( + jobId, + analyticsJobConfig, + createDataView, + form.timeFieldName + ); addRequestMessage({ message: i18n.translate( 'xpack.ml.dataframe.stepCreateForm.createDataFrameAnalyticsSuccessMessage', @@ -110,9 +109,6 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => { ), }); setIsJobCreated(true); - if (createIndexPattern) { - createKibanaDataView(destinationIndex, dataViews, form.timeFieldName, addRequestMessage); - } refresh(); return true; } catch (e) { @@ -132,17 +128,17 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => { const prepareFormValidation = async () => { try { // Set the existing data view names. - const indexPatternsMap: SourceIndexMap = {}; + const dataViewsMap: SourceIndexMap = {}; const savedObjects = (await dataViews.getCache()) || []; savedObjects.forEach((obj) => { const title = obj?.attributes?.title; if (title !== undefined) { const id = obj?.id || ''; - indexPatternsMap[title] = { label: title, value: id }; + dataViewsMap[title] = { label: title, value: id }; } }); - setIndexPatternTitles({ - indexPatternsMap, + setDataViewTitles({ + dataViewsMap, }); } catch (e) { addRequestMessage({ diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts index 8929f39bea43..ea3c24884bbe 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts @@ -48,7 +48,7 @@ export const deleteAnalyticsAndDestIndex = async ( analyticsConfig: DataFrameAnalyticsListRow['config'], analyticsStats: DataFrameAnalyticsListRow['stats'], deleteDestIndex: boolean, - deleteDestIndexPattern: boolean, + deleteDestDataView: boolean, toastNotificationService: ToastNotificationService ) => { const destinationIndex = analyticsConfig.dest.index; @@ -59,7 +59,7 @@ export const deleteAnalyticsAndDestIndex = async ( const status = await ml.dataFrameAnalytics.deleteDataFrameAnalyticsAndDestIndex( analyticsConfig.id, deleteDestIndex, - deleteDestIndexPattern + deleteDestDataView ); if (status.analyticsJobDeleted?.success) { toastNotificationService.displaySuccessToast( @@ -97,7 +97,7 @@ export const deleteAnalyticsAndDestIndex = async ( ); } - if (status.destIndexPatternDeleted?.success) { + if (status.destDataViewDeleted?.success) { toastNotificationService.displaySuccessToast( i18n.translate( 'xpack.ml.dataframe.analyticsList.deleteAnalyticsWithDataViewSuccessMessage', @@ -108,8 +108,8 @@ export const deleteAnalyticsAndDestIndex = async ( ) ); } - if (status.destIndexPatternDeleted?.error) { - const error = extractErrorMessage(status.destIndexPatternDeleted.error); + if (status.destDataViewDeleted?.error) { + const error = extractErrorMessage(status.destDataViewDeleted.error); toastNotificationService.displayDangerToast( i18n.translate('xpack.ml.dataframe.analyticsList.deleteAnalyticsWithDataViewErrorMessage', { defaultMessage: 'An error occurred deleting data view {destinationIndex}: {error}', diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/_legend.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/_legend.scss index 5a3af985446c..7e7168595a44 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/_legend.scss +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/_legend.scss @@ -37,6 +37,15 @@ display: 'inline-block'; } +.mlJobMapLegend__analyticsMissing { + height: $euiSizeM; + width: $euiSizeM; + background-color: $euiColorGhost; + border: $euiBorderWidthThick solid $euiColorFullShade; + border-radius: 50%; + display: 'inline-block'; +} + .mlJobMapLegend__sourceNode { height: $euiSizeM; width: $euiSizeM; @@ -44,4 +53,4 @@ border: $euiBorderThin; border-radius: $euiBorderRadius; display: 'inline-block'; -} +} \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx index 82695b39e006..2786046610fc 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx @@ -196,7 +196,17 @@ export const Controls: FC = React.memo( // Set up Cytoscape event handlers useEffect(() => { const selectHandler: cytoscape.EventHandler = (event) => { - setSelectedNode(event.target); + const targetNode = event.target; + if (targetNode._private.data.type === JOB_MAP_NODE_TYPES.ANALYTICS_JOB_MISSING) { + toasts.addWarning( + i18n.translate('xpack.ml.dataframe.analyticsMap.flyout.jobMissingMessage', { + defaultMessage: 'There is no data available for job {label}.', + values: { label: targetNode._private.data.label }, + }) + ); + return; + } + setSelectedNode(targetNode); setShowFlyout(true); }; @@ -211,7 +221,7 @@ export const Controls: FC = React.memo( cy.removeListener('unselect', 'node', deselect); } }; - }, [cy, deselect]); + }, [cy, deselect, toasts]); useEffect( function updateElementsOnClose() { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape_options.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape_options.tsx index 9cdd41dfb9c8..b7ca710fb43f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape_options.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape_options.tsx @@ -28,6 +28,8 @@ function shapeForNode(el: cytoscape.NodeSingular, theme: EuiThemeType): MapShape switch (type) { case JOB_MAP_NODE_TYPES.ANALYTICS: return MAP_SHAPES.ELLIPSE; + case JOB_MAP_NODE_TYPES.ANALYTICS_JOB_MISSING: + return MAP_SHAPES.ELLIPSE; case JOB_MAP_NODE_TYPES.TRANSFORM: return MAP_SHAPES.RECTANGLE; case JOB_MAP_NODE_TYPES.INDEX: @@ -65,6 +67,8 @@ function borderColorForNode(el: cytoscape.NodeSingular, theme: EuiThemeType) { const type = el.data('type'); switch (type) { + case JOB_MAP_NODE_TYPES.ANALYTICS_JOB_MISSING: + return theme.euiColorFullShade; case JOB_MAP_NODE_TYPES.ANALYTICS: return theme.euiColorSuccess; case JOB_MAP_NODE_TYPES.TRANSFORM: diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx index 9494f7fc0879..53379c4809d9 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx @@ -32,7 +32,10 @@ const getJobTypeList = () => ( ); -export const JobMapLegend: FC<{ theme: EuiThemeType }> = ({ theme }) => { +export const JobMapLegend: FC<{ hasMissingJobNode: boolean; theme: EuiThemeType }> = ({ + hasMissingJobNode, + theme, +}) => { const [showJobTypes, setShowJobTypes] = useState(false); return ( @@ -122,6 +125,23 @@ export const JobMapLegend: FC<{ theme: EuiThemeType }> = ({ theme }) => {
    + {hasMissingJobNode ? ( + + + + + + + + + + + + + ) : null} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx index ae1adea95895..f4ba7e3a4c1d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useEffect, useState } from 'react'; +import React, { FC, useEffect, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; @@ -150,6 +150,10 @@ export const JobMap: FC = ({ defaultHeight, analyticsId, modelId, forceRe const { ref, width, height } = useRefDimensions(); const refreshCallback = () => fetchAndSetElementsWrapper({ analyticsId, modelId }); + const hasMissingJobNode = useMemo( + () => elements.map(({ data }) => data.type).includes(JOB_MAP_NODE_TYPES.ANALYTICS_JOB_MISSING), + [elements] + ); const h = defaultHeight ?? height; return ( @@ -157,7 +161,7 @@ export const JobMap: FC = ({ defaultHeight, analyticsId, modelId, forceRe - + void; } /** @@ -187,6 +188,7 @@ export const SwimlaneContainer: FC = ({ showLegend = true, 'data-test-subj': dataTestSubj, yAxisWidth, + onRenderComplete, }) => { const [chartWidth, setChartWidth] = useState(0); @@ -407,6 +409,10 @@ export const SwimlaneContainer: FC = ({ const noSwimLaneData = !isLoading && !showSwimlane && !!noDataWarning; + if (noSwimLaneData) { + onRenderComplete?.(); + } + // A resize observer is required to compute the bucket span based on the chart width to fetch the data accordingly return ( @@ -453,6 +459,11 @@ export const SwimlaneContainer: FC = ({ debugState={window._echDebugStateFlag ?? false} onBrushEnd={onBrushEnd as BrushEndListener} locale={i18n.getLocale()} + onRenderChange={(isRendered) => { + if (isRendered && onRenderComplete) { + onRenderComplete(); + } + }} /> j.blocked !== undefined)) { + if ( + blockingJobsRefreshTimeout === null && + jobsSummaryList.some((j) => j.blocked !== undefined) + ) { // if there are some jobs in a deleting state, start polling for // deleting jobs so we can update the jobs list once the // deleting tasks are over diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_dashboard/quick_create_job_base.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_dashboard/quick_create_job_base.ts index 4b4ce7299277..f5f491426b0a 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_dashboard/quick_create_job_base.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_dashboard/quick_create_job_base.ts @@ -69,21 +69,21 @@ export class QuickJobCreatorBase { datafeedConfig, jobConfig, createdByLabel, - dashboard, start, end, startJob, runInRealTime, + dashboard, }: { jobId: string; datafeedConfig: Datafeed; jobConfig: Job; createdByLabel: CREATED_BY_LABEL; - dashboard: Dashboard; start: number | undefined; end: number | undefined; startJob: boolean; runInRealTime: boolean; + dashboard?: Dashboard; }) { const datafeedId = createDatafeedId(jobId); const datafeed = { ...datafeedConfig, job_id: jobId, datafeed_id: datafeedId }; @@ -93,7 +93,7 @@ export class QuickJobCreatorBase { job_id: jobId, custom_settings: { created_by: createdByLabel, - ...(await this.getCustomUrls(dashboard, datafeed)), + ...(dashboard ? await this.getCustomUrls(dashboard, datafeed) : {}), }, }; @@ -230,7 +230,7 @@ export class QuickJobCreatorBase { return mergedQueries; } - protected async createDashboardLink(dashboard: Dashboard, datafeedConfig: estypes.MlDatafeed) { + private async createDashboardLink(dashboard: Dashboard, datafeedConfig: estypes.MlDatafeed) { const dashboardTitle = dashboard?.getTitle(); if (dashboardTitle === undefined || dashboardTitle === '') { // embeddable may have not been in a dashboard @@ -274,7 +274,7 @@ export class QuickJobCreatorBase { return { url_name: urlName, url_value: url, time_range: 'auto' }; } - protected async getCustomUrls(dashboard: Dashboard, datafeedConfig: estypes.MlDatafeed) { + private async getCustomUrls(dashboard: Dashboard, datafeedConfig: estypes.MlDatafeed) { const customUrls = await this.createDashboardLink(dashboard, datafeedConfig); return dashboard !== undefined && customUrls !== null ? { custom_urls: [customUrls] } : {}; } diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts index 2ade08c3cf23..4df2b74347f4 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts @@ -135,7 +135,7 @@ export class QuickLensJobCreator extends QuickJobCreatorBase { } } - async createJob( + private async createJob( chartInfo: ChartInfo, startString: string, endString: string, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/route_resolver.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/route_resolver.ts index 9dcce1facf29..c8ad1ee6942e 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/route_resolver.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/route_resolver.ts @@ -15,7 +15,7 @@ import type { DashboardStart } from '@kbn/dashboard-plugin/public'; import { QuickLensJobCreator } from './quick_create_job'; import type { MlApiServices } from '../../../services/ml_api_service'; -import { getDefaultQuery } from '../utils/new_job_utils'; +import { getDefaultQuery, getRisonValue } from '../utils/new_job_utils'; interface Dependencies { lens: LensPublicStart; @@ -27,8 +27,8 @@ interface Dependencies { export async function resolver( deps: Dependencies, lensSavedObjectRisonString: string | undefined, - fromRisonStrong: string, - toRisonStrong: string, + fromRisonString: string, + toRisonString: string, queryRisonString: string, filtersRisonString: string, layerIndexRisonString: string @@ -43,37 +43,11 @@ export async function resolver( throw new Error('Cannot create visualization'); } - let query: Query; - let filters: Filter[]; - try { - query = rison.decode(queryRisonString) as Query; - } catch (error) { - query = getDefaultQuery(); - } - try { - filters = rison.decode(filtersRisonString) as Filter[]; - } catch (error) { - filters = []; - } - - let from: string; - let to: string; - try { - from = rison.decode(fromRisonStrong) as string; - } catch (error) { - from = ''; - } - try { - to = rison.decode(toRisonStrong) as string; - } catch (error) { - to = ''; - } - let layerIndex: number | undefined; - try { - layerIndex = rison.decode(layerIndexRisonString) as number; - } catch (error) { - layerIndex = undefined; - } + const query = getRisonValue(queryRisonString, getDefaultQuery()) as Query; + const filters = getRisonValue(filtersRisonString, []); + const from = getRisonValue(fromRisonString, ''); + const to = getRisonValue(toRisonString, ''); + const layerIndex = getRisonValue(layerIndexRisonString, undefined); const jobCreator = new QuickLensJobCreator( lens, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/quick_create_job.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/quick_create_job.ts index e590600cd404..954abd2d14ab 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/quick_create_job.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/quick_create_job.ts @@ -162,7 +162,7 @@ export class QuickGeoJobCreator extends QuickJobCreatorBase { } } - async createGeoJob({ + private async createGeoJob({ dataViewId, sourceDataView, from, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/route_resolver.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/route_resolver.ts index 39753c77038c..0728ca3c61d5 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/route_resolver.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_map/route_resolver.ts @@ -5,16 +5,13 @@ * 2.0. */ -import rison from '@kbn/rison'; -import type { Query } from '@kbn/es-query'; -import type { Filter } from '@kbn/es-query'; import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import type { TimefilterContract } from '@kbn/data-plugin/public'; import type { DashboardStart } from '@kbn/dashboard-plugin/public'; import type { MlApiServices } from '../../../services/ml_api_service'; import { QuickGeoJobCreator } from './quick_create_job'; -import { getDefaultQuery } from '../utils/new_job_utils'; +import { getDefaultQuery, getRisonValue } from '../utils/new_job_utils'; interface Dependencies { kibanaConfig: IUiSettingsClient; @@ -24,66 +21,32 @@ interface Dependencies { } export async function resolver( deps: Dependencies, - dashboard: string, - dataViewId: string, - embeddable: string, - geoField: string, - splitField: string, + dashboardRisonString: string, + dataViewIdRisonString: string, + embeddableRisonString: string, + geoFieldRisonString: string, + splitFieldRisonString: string, fromRisonString: string, toRisonString: string, - layer?: string + layerRisonString?: string ) { const { kibanaConfig, timeFilter, dashboardService, mlApiServices } = deps; - let decodedDashboard; - let decodedEmbeddable; - let decodedLayer; - let splitFieldDecoded; - let dvId; + const defaultLayer = { query: getDefaultQuery(), filters: [] }; - try { - dvId = rison.decode(dataViewId) as string; - } catch (error) { - dvId = ''; - } + const dashboard = getRisonValue(dashboardRisonString, defaultLayer); + const embeddable = getRisonValue(embeddableRisonString, defaultLayer); - try { - decodedDashboard = rison.decode(dashboard) as { query: Query; filters: Filter[] }; - } catch (error) { - decodedDashboard = { query: getDefaultQuery(), filters: [] }; - } + const layer = + layerRisonString !== undefined + ? getRisonValue(layerRisonString, defaultLayer) + : defaultLayer; - try { - decodedEmbeddable = rison.decode(embeddable) as { query: Query; filters: Filter[] }; - } catch (error) { - decodedEmbeddable = { query: getDefaultQuery(), filters: [] }; - } + const geoField = getRisonValue(geoFieldRisonString, ''); + const splitField = getRisonValue(splitFieldRisonString, null); + const dataViewId = getRisonValue(dataViewIdRisonString, ''); - if (layer) { - try { - decodedLayer = rison.decode(layer) as { query: Query }; - } catch (error) { - decodedLayer = { query: getDefaultQuery(), filters: [] }; - } - } - - try { - splitFieldDecoded = rison.decode(splitField) as string; - } catch (error) { - splitFieldDecoded = null; - } - - let from: string; - let to: string; - try { - from = rison.decode(fromRisonString) as string; - } catch (error) { - from = ''; - } - try { - to = rison.decode(toRisonString) as string; - } catch (error) { - to = ''; - } + const from = getRisonValue(fromRisonString, ''); + const to = getRisonValue(toRisonString, ''); const jobCreator = new QuickGeoJobCreator( kibanaConfig, @@ -93,15 +56,15 @@ export async function resolver( ); await jobCreator.createAndStashGeoJob( - dvId, + dataViewId, from, to, - decodedDashboard.query, - decodedDashboard.filters, - decodedEmbeddable.query, - decodedEmbeddable.filters, + dashboard.query, + dashboard.filters, + embeddable.query, + embeddable.filters, geoField, - splitFieldDecoded, - decodedLayer?.query + splitField, + layer?.query ); } diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/index.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/index.ts new file mode 100644 index 000000000000..51b3194f28c9 --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + QuickCategorizationJobCreator, + CATEGORIZATION_TYPE, + type CategorizationType, +} from './quick_create_job'; + +export { resolver } from './route_resolver'; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/quick_create_job.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/quick_create_job.ts new file mode 100644 index 000000000000..721d48d1908b --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/quick_create_job.ts @@ -0,0 +1,209 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IUiSettingsClient } from '@kbn/core/public'; +import type { DataPublicPluginStart, TimefilterContract } from '@kbn/data-plugin/public'; +import type { DashboardStart } from '@kbn/dashboard-plugin/public'; +import { DataViewField, DataView } from '@kbn/data-views-plugin/common'; +import type { TimeRange } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; +import { MLCATEGORY, ML_JOB_AGGREGATION } from '@kbn/ml-anomaly-utils'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { CREATED_BY_LABEL, DEFAULT_BUCKET_SPAN } from '../../../../../common/constants/new_job'; +import { type CreateState, QuickJobCreatorBase } from '../job_from_dashboard/quick_create_job_base'; +import type { MlApiServices } from '../../../services/ml_api_service'; +import { createEmptyDatafeed, createEmptyJob } from '../common/job_creator/util/default_configs'; +import { stashJobForCloning } from '../common/job_creator/util/general'; +import type { JobCreatorType } from '../common/job_creator'; + +export const CATEGORIZATION_TYPE = { + COUNT: ML_JOB_AGGREGATION.COUNT, + RARE: ML_JOB_AGGREGATION.RARE, +} as const; + +export type CategorizationType = typeof CATEGORIZATION_TYPE[keyof typeof CATEGORIZATION_TYPE]; + +export class QuickCategorizationJobCreator extends QuickJobCreatorBase { + constructor( + kibanaConfig: IUiSettingsClient, + timeFilter: TimefilterContract, + dashboardService: DashboardStart, + private data: DataPublicPluginStart, + mlApiServices: MlApiServices + ) { + super(kibanaConfig, timeFilter, dashboardService, mlApiServices); + } + + public async createAndSaveJob( + categorizationType: CategorizationType, + jobId: string, + bucketSpan: string, + dataView: DataView, + field: DataViewField, + partitionField: DataViewField | null, + stopOnWarn: boolean, + query: QueryDslQueryContainer, + timeRange: TimeRange, + startJob: boolean, + runInRealTime: boolean + ): Promise { + if (query === undefined) { + throw new Error('Cannot create job, query and filters are undefined'); + } + + const { jobConfig, datafeedConfig, start, end } = await this.createJob( + categorizationType, + dataView, + field, + partitionField, + stopOnWarn, + timeRange, + query, + bucketSpan + ); + const createdByLabel = CREATED_BY_LABEL.CATEGORIZATION_FROM_PATTERN_ANALYSIS; + + const result = await this.putJobAndDataFeed({ + jobId, + datafeedConfig, + jobConfig, + createdByLabel, + start, + end, + startJob, + runInRealTime, + }); + return result; + } + + public async createAndStashADJob( + categorizationType: CategorizationType, + dataViewId: string, + fieldName: string, + partitionFieldName: string | null, + stopOnWarn: boolean, + startString: string, + endString: string, + query: QueryDslQueryContainer + ) { + try { + const dataView = await this.data.dataViews.get(dataViewId); + const field = dataView.getFieldByName(fieldName); + const partitionField = partitionFieldName + ? dataView.getFieldByName(partitionFieldName) ?? null + : null; + + if (field === undefined) { + throw new Error('Cannot create job, field is undefined'); + } + + const { jobConfig, datafeedConfig, start, end, includeTimeRange } = await this.createJob( + categorizationType, + dataView, + field, + partitionField, + stopOnWarn, + { from: startString, to: endString }, + query, + DEFAULT_BUCKET_SPAN + ); + + // add job config and start and end dates to the + // job cloning stash, so they can be used + // by the new job wizards + stashJobForCloning( + { + jobConfig, + datafeedConfig, + createdBy: CREATED_BY_LABEL.CATEGORIZATION_FROM_PATTERN_ANALYSIS, + start, + end, + } as JobCreatorType, + true, + includeTimeRange, + !includeTimeRange + ); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + } + } + + private async createJob( + categorizationType: CategorizationType, + dataView: DataView, + field: DataViewField, + partitionField: DataViewField | null, + stopOnWarn: boolean, + timeRange: TimeRange, + query: QueryDslQueryContainer, + bucketSpan: string + ) { + const jobConfig = createEmptyJob(); + const datafeedConfig = createEmptyDatafeed(dataView.getIndexPattern()); + + datafeedConfig.query = query; + jobConfig.analysis_config = { + categorization_field_name: field.name, + per_partition_categorization: { + enabled: partitionField !== null, + stop_on_warn: stopOnWarn, + }, + influencers: [MLCATEGORY], + detectors: [ + { + function: categorizationType, + by_field_name: MLCATEGORY, + }, + ], + bucket_span: bucketSpan, + }; + + if (partitionField !== null) { + jobConfig.analysis_config.detectors[0].partition_field_name = partitionField.name; + jobConfig.analysis_config.influencers!.push(partitionField.name); + } + + jobConfig.data_description.time_field = dataView.timeFieldName; + + let start: number | undefined; + let end: number | undefined; + let includeTimeRange = true; + + try { + // attempt to parse the start and end dates. + // if start and end values cannot be determined + // instruct the job cloning code to auto-select the + // full time range for the index. + const { min, max } = this.timeFilter.calculateBounds(timeRange); + start = min?.valueOf(); + end = max?.valueOf(); + + if (start === undefined || end === undefined || isNaN(start) || isNaN(end)) { + throw Error( + i18n.translate('xpack.ml.newJob.fromLens.createJob.error.timeRange', { + defaultMessage: 'Incompatible time range', + }) + ); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + includeTimeRange = false; + start = undefined; + end = undefined; + } + + return { + jobConfig, + datafeedConfig, + start, + end, + includeTimeRange, + }; + } +} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/route_resolver.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/route_resolver.ts new file mode 100644 index 000000000000..0f8462128d2c --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/route_resolver.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import type { DataPublicPluginStart, TimefilterContract } from '@kbn/data-plugin/public'; +import type { DashboardStart } from '@kbn/dashboard-plugin/public'; +import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; +import { + type CategorizationType, + QuickCategorizationJobCreator, + CATEGORIZATION_TYPE, +} from './quick_create_job'; +import type { MlApiServices } from '../../../services/ml_api_service'; + +import { getDefaultDatafeedQuery, getRisonValue } from '../utils/new_job_utils'; + +interface Dependencies { + kibanaConfig: IUiSettingsClient; + timeFilter: TimefilterContract; + dashboardService: DashboardStart; + data: DataPublicPluginStart; + mlApiServices: MlApiServices; +} +export async function resolver( + deps: Dependencies, + categorizationTypeRisonString: string, + dataViewIdRisonString: string, + fieldRisonString: string, + partitionFieldRisonString: string | null, + stopOnWarnRisonString: string, + fromRisonString: string, + toRisonString: string, + queryRisonString: string +) { + const { mlApiServices, timeFilter, kibanaConfig, dashboardService, data } = deps; + + const query = getRisonValue(queryRisonString, getDefaultDatafeedQuery()); + const from = getRisonValue(fromRisonString, ''); + const to = getRisonValue(toRisonString, ''); + const categorizationType = getRisonValue( + categorizationTypeRisonString, + CATEGORIZATION_TYPE.COUNT + ); + const dataViewId = getRisonValue(dataViewIdRisonString, ''); + const field = getRisonValue(fieldRisonString, ''); + const partitionField = + partitionFieldRisonString === null ? '' : getRisonValue(partitionFieldRisonString, ''); + const stopOnWarn = getRisonValue(stopOnWarnRisonString, false); + + const jobCreator = new QuickCategorizationJobCreator( + kibanaConfig, + timeFilter, + dashboardService, + data, + mlApiServices + ); + await jobCreator.createAndStashADJob( + categorizationType, + dataViewId, + field, + partitionField, + stopOnWarn, + from, + to, + query + ); +} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/utils.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/utils.ts new file mode 100644 index 000000000000..4bc84a4df20d --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_pattern_analysis/utils.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; +import { ML_APP_LOCATOR } from '../../../../../common/constants/locator'; +import { ML_PAGES } from '../../../../locator'; +import type { CategorizationType } from './quick_create_job'; + +export async function redirectToADJobWizards( + categorizationType: CategorizationType, + dataView: DataView, + field: DataViewField, + partitionField: DataViewField | null, + stopOnWarn: boolean, + query: QueryDslQueryContainer, + timeRange: TimeRange, + share: SharePluginStart +) { + const locator = share.url.locators.get(ML_APP_LOCATOR)!; + + const url = await locator.getUrl({ + page: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS, + pageState: { + categorizationType, + dataViewId: dataView.id, + field: field.name, + partitionField: partitionField?.name || null, + stopOnWarn, + from: timeRange.from, + to: timeRange.to, + query: JSON.stringify(query), + }, + }); + + window.open(url, '_blank'); +} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts index b13cde5e94cc..ba31ff5e4cd9 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts @@ -55,6 +55,7 @@ async function getWizardUrlFromCloningJob(createdBy: string | undefined, dataVie page = JOB_TYPE.POPULATION; break; case CREATED_BY_LABEL.CATEGORIZATION: + case CREATED_BY_LABEL.CATEGORIZATION_FROM_PATTERN_ANALYSIS: page = JOB_TYPE.CATEGORIZATION; break; case CREATED_BY_LABEL.RARE: diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/kibana_objects.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/kibana_objects.tsx index 95ac0b4043f5..55692ac50719 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/kibana_objects.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/kibana_objects.tsx @@ -23,11 +23,11 @@ import { KibanaObjectUi } from '../page'; export interface KibanaObjectItemProps { objectType: string; - kibanaObjects: KibanaObjectUi[]; + kibanaObjects: KibanaObjectUi[] | undefined; isSaving: boolean; } -export const KibanaObjects: FC = memo( +export const KibanaObjectList: FC = memo( ({ objectType, kibanaObjects, isSaving }) => { const kibanaObjectLabels: Record = { dashboard: i18n.translate('xpack.ml.newJob.recognize.dashboardsLabel', { @@ -41,6 +41,10 @@ export const KibanaObjects: FC = memo( }), }; + if (kibanaObjects === undefined) { + return null; + } + return ( <> @@ -53,7 +57,7 @@ export const KibanaObjects: FC = memo( - + {title} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx index 8be908871fe2..fe2c5dfa966a 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx @@ -30,11 +30,12 @@ import { JobOverride, JobResponse, KibanaObject, + KibanaObjects, KibanaObjectResponse, ModuleJob, } from '../../../../../common/types/modules'; import { CreateResultCallout } from './components/create_result_callout'; -import { KibanaObjects } from './components/kibana_objects'; +import { KibanaObjectList } from './components/kibana_objects'; import { ModuleJobs } from './components/module_jobs'; import { JobSettingsForm, JobSettingsFormValues } from './components/job_settings_form'; import { TimeRange } from '../common/components'; @@ -50,10 +51,6 @@ export interface ModuleJobUI extends ModuleJob { export type KibanaObjectUi = KibanaObject & KibanaObjectResponse; -export interface KibanaObjects { - [objectType: string]: KibanaObjectUi[]; -} - interface PageProps { moduleId: string; existingGroupIds: string[]; @@ -111,6 +108,7 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { try { const response = await getDataRecognizerModule({ moduleId }); setJobs(response.jobs); + setKibanaObjects(response.kibana); setSaveState(SAVE_STATE.NOT_SAVED); @@ -365,7 +363,7 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { {Object.keys(kibanaObjects).map((objectType, i) => ( - ( + risonString: string, + defaultValue: T +) { + try { + return rison.decode(risonString) as T; + } catch (error) { + return defaultValue; + } +} diff --git a/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx b/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx new file mode 100644 index 000000000000..6c69446b8725 --- /dev/null +++ b/x-pack/plugins/ml/public/application/model_management/add_model_flyout.tsx @@ -0,0 +1,505 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBadge, + EuiButton, + EuiButtonEmpty, + EuiCheckableCard, + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFormFieldset, + EuiIcon, + EuiLink, + EuiSpacer, + EuiSteps, + EuiTab, + EuiTabs, + EuiText, + EuiTitle, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React, { type FC, useMemo, useState } from 'react'; +import { groupBy } from 'lodash'; +import { usePermissionCheck } from '../capabilities/check_capabilities'; +import { useMlKibana } from '../contexts/kibana'; +import { ModelItem } from './models_list'; + +export interface AddModelFlyoutProps { + modelDownloads: ModelItem[]; + onClose: () => void; + onSubmit: (modelId: string) => void; +} + +type FlyoutTabId = 'clickToDownload' | 'manualDownload'; + +/** + * Flyout for downloading elastic curated models and showing instructions for importing third-party models. + */ +export const AddModelFlyout: FC = ({ onClose, onSubmit, modelDownloads }) => { + const canCreateTrainedModels = usePermissionCheck('canCreateTrainedModels'); + const isClickToDownloadTabVisible = canCreateTrainedModels && modelDownloads.length > 0; + + const [selectedTabId, setSelectedTabId] = useState( + isClickToDownloadTabVisible ? 'clickToDownload' : 'manualDownload' + ); + + const tabs = useMemo(() => { + return [ + ...(isClickToDownloadTabVisible + ? [ + { + id: 'clickToDownload' as const, + name: ( + + ), + content: ( + + ), + }, + ] + : []), + { + id: 'manualDownload' as const, + name: ( + + ), + content: , + }, + ]; + }, [isClickToDownloadTabVisible, modelDownloads, onSubmit]); + + const selectedTabContent = useMemo(() => { + return tabs.find((obj) => obj.id === selectedTabId)?.content; + }, [selectedTabId, tabs]); + + return ( + + + +

    + +

    +
    + + {tabs.map((tab) => ( + + {tab.name} + + ))} + +
    + {selectedTabContent} + + + + + + + + + +
    + ); +}; + +interface ClickToDownloadTabContentProps { + modelDownloads: ModelItem[]; + onModelDownload: (modelId: string) => void; +} + +/** + * Tab content for selecting a model to download. + */ +const ClickToDownloadTabContent: FC = ({ + modelDownloads, + onModelDownload, +}) => { + const { + services: { docLinks }, + } = useMlKibana(); + + const [selectedModelId, setSelectedModelId] = useState( + modelDownloads.find((m) => m.recommended)?.model_id + ); + + return ( + <> + {Object.entries(groupBy(modelDownloads, 'modelName')).map(([modelName, models]) => { + return ( + + {modelName === 'elser' ? ( +
    + + + + + + +

    + +

    +
    +
    +
    + +

    + + + +

    + +

    + + + +

    + +
    + ) : null} + + {modelName === 'e5' ? ( +
    + +

    + +

    +
    + +

    + + + +

    + + + + + + + + + + + + + + +
    + ) : null} + + + ), + }} + > + {models.map((model, index) => { + return ( + + + +
    + + + {model.os === 'Linux' && model.arch === 'amd64' ? ( + + ) : ( + + )} + + +
    + + {model.model_id} + +
    + {model.recommended ? ( + + + } + > + + + + + + ) : null} +
    + } + name={model.model_id} + value={model.model_id} + checked={model.model_id === selectedModelId} + onChange={setSelectedModelId.bind(null, model.model_id)} + /> + {index < models.length - 1 ? : null} + + ); + })} + + + + ); + })} + + + + + ); +}; + +/** + * Manual download tab content for showing instructions for importing third-party models. + */ +const ManualDownloadTabContent: FC = () => { + const { + services: { docLinks }, + } = useMlKibana(); + + return ( + <> + + +

    + + + pip + + ), + pypiLink: ( + + PyPI + + ), + }} + /> + +

    +

    + + $ python -m pip install eland + +

    +

    + + + Conda + + ), + condaForgeLink: ( + + Conda Forge + + ), + }} + /> + +

    +

    + + $ conda install -c conda-forge eland + +

    + + ), + }, + { + title: i18n.translate('xpack.ml.trainedModels.addModelFlyout.thirdParty.step2Title', { + defaultMessage: 'Importing your third-party model', + }), + children: ( + +

    + + + +

    + +

    + + + + + + eland_import_hub_model
    + --cloud-id <cloud-id> \
    + -u <username> -p <password> \
    + --hub-model-id <model-id> \
    + --task-type ner \ +
    +

    + + + + + + + + + + + + + +
    + ), + }, + { + title: i18n.translate('xpack.ml.trainedModels.addModelFlyout.thirdParty.step4Title', { + defaultMessage: 'Deploy your model', + }), + children: ( + <> + +

    + +

    +
    + + +

    + +

    +
    + + ), + }, + ]} + /> + + ); +}; diff --git a/x-pack/plugins/ml/public/application/model_management/deployment_setup.tsx b/x-pack/plugins/ml/public/application/model_management/deployment_setup.tsx index 3ac6960af55c..102af34d3e95 100644 --- a/x-pack/plugins/ml/public/application/model_management/deployment_setup.tsx +++ b/x-pack/plugins/ml/public/application/model_management/deployment_setup.tsx @@ -31,7 +31,7 @@ import type { I18nStart, OverlayStart, ThemeServiceStart } from '@kbn/core/publi import { css } from '@emotion/react'; import { numberValidator } from '@kbn/ml-agg-utils'; import { toMountPoint } from '@kbn/react-kibana-mount'; -import { isCloudTrial } from '../services/ml_server_info'; +import { getNewJobLimits, isCloudTrial } from '../services/ml_server_info'; import { composeValidators, dictionaryValidator, @@ -42,7 +42,7 @@ import { ModelItem } from './models_list'; interface DeploymentSetupProps { config: ThreadingParams; onConfigChange: (config: ThreadingParams) => void; - errors: Partial>; + errors: Partial>>; isUpdate?: boolean; deploymentsParams?: Record; } @@ -66,6 +66,11 @@ export const DeploymentSetup: FC = ({ isUpdate, deploymentsParams, }) => { + const { + total_ml_processors: totalMlProcessors, + max_single_ml_node_processors: maxSingleMlNodeProcessors, + } = getNewJobLimits(); + const numOfAllocation = config.numOfAllocations; const threadsPerAllocations = config.threadsPerAllocations; @@ -76,17 +81,20 @@ export const DeploymentSetup: FC = ({ const threadsPerAllocationsOptions = useMemo( () => - new Array(THREADS_MAX_EXPONENT).fill(null).map((v, i) => { - const value = Math.pow(2, i); - const id = value.toString(); - - return { - id, - label: id, - value, - }; - }), - [] + new Array(THREADS_MAX_EXPONENT) + .fill(null) + .map((v, i) => Math.pow(2, i)) + .filter(maxSingleMlNodeProcessors ? (v) => v <= maxSingleMlNodeProcessors : (v) => true) + .map((value) => { + const id = value.toString(); + + return { + id, + label: id, + value, + }; + }), + [maxSingleMlNodeProcessors] ); const disableThreadingControls = config.priority === 'low'; @@ -251,11 +259,28 @@ export const DeploymentSetup: FC = ({ } hasChildLabel={false} isDisabled={disableThreadingControls} + isInvalid={!!errors.numOfAllocations} + error={ + errors?.numOfAllocations?.min ? ( + + ) : errors?.numOfAllocations?.max ? ( + + ) : null + } > = ({ }) => { const isUpdate = !!initialParams; + const { total_ml_processors: totalMlProcessors } = getNewJobLimits(); + const [config, setConfig] = useState( initialParams ?? { numOfAllocations: 1, @@ -373,7 +400,7 @@ export const StartUpdateDeploymentModal: FC = ({ const numOfAllocationsValidator = composeValidators( requiredValidator(), - numberValidator({ min: 1, integerOnly: true }) + numberValidator({ min: 1, max: totalMlProcessors, integerOnly: true }) ); const numOfAllocationsErrors = numOfAllocationsValidator(config.numOfAllocations); diff --git a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx index 7c39528cf5b4..d91e944602d9 100644 --- a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx +++ b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx @@ -42,12 +42,14 @@ export function useModelActions({ isLoading, fetchModels, modelAndDeploymentIds, + onModelDownloadRequest, }: { isLoading: boolean; onDfaTestAction: (model: ModelItem) => void; onTestAction: (model: ModelItem) => void; onModelsDeleteRequest: (models: ModelItem[]) => void; onModelDeployRequest: (model: ModelItem) => void; + onModelDownloadRequest: (modelId: string) => void; onLoading: (isLoading: boolean) => void; fetchModels: () => Promise; modelAndDeploymentIds: string[]; @@ -130,18 +132,19 @@ export function useModelActions({ return useMemo( () => [ { - name: i18n.translate('xpack.ml.trainedModels.modelsList.viewTrainingDataActionLabel', { + name: i18n.translate('xpack.ml.trainedModels.modelsList.viewTrainingDataNameActionLabel', { defaultMessage: 'View training data', }), description: i18n.translate( 'xpack.ml.trainedModels.modelsList.viewTrainingDataActionLabel', { - defaultMessage: 'View training data', + defaultMessage: 'Training data can be viewed when data frame analytics job exists.', } ), icon: 'visTable', type: 'icon', available: (item) => !!item.metadata?.analytics_config?.id, + enabled: (item) => item.origin_job_exists === true, onClick: async (item) => { if (item.metadata?.analytics_config === undefined) return; @@ -164,7 +167,6 @@ export function useModelActions({ await navigateToUrl(url); }, - isPrimary: true, }, { name: i18n.translate('xpack.ml.inference.modelsList.analyticsMapActionLabel', { @@ -410,31 +412,7 @@ export function useModelActions({ item.state === MODEL_STATE.NOT_DOWNLOADED, enabled: (item) => !isLoading, onClick: async (item) => { - try { - onLoading(true); - await trainedModelsApiService.installElasticTrainedModelConfig(item.model_id); - displaySuccessToast( - i18n.translate('xpack.ml.trainedModels.modelsList.downloadSuccess', { - defaultMessage: '"{modelId}" model download has been started successfully.', - values: { - modelId: item.model_id, - }, - }) - ); - // Need to fetch model state updates - await fetchModels(); - } catch (e) { - displayErrorToast( - e, - i18n.translate('xpack.ml.trainedModels.modelsList.downloadFailed', { - defaultMessage: 'Failed to download "{modelId}"', - values: { - modelId: item.model_id, - }, - }) - ); - onLoading(false); - } + onModelDownloadRequest(item.model_id); }, }, { @@ -481,7 +459,7 @@ export function useModelActions({ ); }, enabled: (item) => { - return item.state !== MODEL_STATE.STARTED; + return canStartStopTrainedModels && item.state !== MODEL_STATE.STARTED; }, }, { @@ -614,6 +592,7 @@ export function useModelActions({ onTestAction, trainedModelsApiService, urlLocator, + onModelDownloadRequest, ] ); } diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx index 56486d1bbbd4..0fc27fcb33fd 100644 --- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx @@ -45,6 +45,7 @@ import { } from '@kbn/ml-trained-models-utils'; import { isDefined } from '@kbn/ml-is-defined'; import { useStorage } from '@kbn/ml-local-storage'; +import { AddModelFlyout } from './add_model_flyout'; import { getModelStateColor } from './get_model_state_color'; import { ML_ELSER_CALLOUT_DISMISSED } from '../../../common/types/storage'; import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; @@ -79,10 +80,17 @@ export type ModelItem = TrainedModelConfigResponse & { type?: string[]; stats?: Stats & { deployment_stats: TrainedModelDeploymentStatsResponse[] }; pipelines?: ModelPipelines['pipelines'] | null; + origin_job_exists?: boolean; deployment_ids: string[]; putModelConfig?: object; state: ModelState; recommended?: boolean; + /** + * Model name, e.g. elser + */ + modelName?: string; + os?: string; + arch?: string; }; export type ModelItemFull = Required; @@ -152,7 +160,7 @@ export const ModelsList: FC = ({ const trainedModelsApiService = useTrainedModelsApiService(); - const { displayErrorToast } = useToastNotificationService(); + const { displayErrorToast, displaySuccessToast } = useToastNotificationService(); const [isInitialized, setIsInitialized] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -165,6 +173,7 @@ export const ModelsList: FC = ({ ); const [modelToTest, setModelToTest] = useState(null); const [dfaModelToTest, setDfaModelToTest] = useState(null); + const [isAddModelFlyoutVisible, setIsAddModelFlyoutVisible] = useState(false); const isBuiltInModel = useCallback( (item: ModelItem) => item.tags.includes(BUILT_IN_MODEL_TAG), @@ -253,21 +262,24 @@ export const ModelsList: FC = ({ ); const forDownload = await trainedModelsApiService.getTrainedModelDownloads(); const notDownloaded: ModelItem[] = forDownload - .filter(({ name, hidden, recommended }) => { - if (recommended && idMap.has(name)) { - idMap.get(name)!.recommended = true; + .filter(({ model_id: modelId, hidden, recommended }) => { + if (recommended && idMap.has(modelId)) { + idMap.get(modelId)!.recommended = true; } - return !idMap.has(name) && !hidden; + return !idMap.has(modelId) && !hidden; }) .map((modelDefinition) => { return { - model_id: modelDefinition.name, - type: [ELASTIC_MODEL_TYPE], - tags: [ELASTIC_MODEL_TAG], + model_id: modelDefinition.model_id, + type: modelDefinition.type, + tags: modelDefinition.type?.includes(ELASTIC_MODEL_TAG) ? [ELASTIC_MODEL_TAG] : [], putModelConfig: modelDefinition.config, description: modelDefinition.description, state: MODEL_STATE.NOT_DOWNLOADED, recommended: !!modelDefinition.recommended, + modelName: modelDefinition.modelName, + os: modelDefinition.os, + arch: modelDefinition.arch, } as ModelItem; }); resultItems = [...resultItems, ...notDownloaded]; @@ -405,6 +417,33 @@ export const ModelsList: FC = ({ [existingModels] ); + const onModelDownloadRequest = useCallback( + async (modelId: string) => { + try { + setIsLoading(true); + await trainedModelsApiService.installElasticTrainedModelConfig(modelId); + displaySuccessToast( + i18n.translate('xpack.ml.trainedModels.modelsList.downloadSuccess', { + defaultMessage: '"{modelId}" model download has been started successfully.', + values: { modelId }, + }) + ); + // Need to fetch model state updates + await fetchModelsData(); + } catch (e) { + displayErrorToast( + e, + i18n.translate('xpack.ml.trainedModels.modelsList.downloadFailed', { + defaultMessage: 'Failed to download "{modelId}"', + values: { modelId }, + }) + ); + setIsLoading(true); + } + }, + [displayErrorToast, displaySuccessToast, fetchModelsData, trainedModelsApiService] + ); + /** * Table actions */ @@ -417,6 +456,7 @@ export const ModelsList: FC = ({ onModelDeployRequest: setModelToDeploy, onLoading: setIsLoading, modelAndDeploymentIds, + onModelDownloadRequest, }); const toggleDetails = async (item: ModelItem) => { @@ -688,13 +728,24 @@ export const ModelsList: FC = ({ <> - {modelsStats && ( - <> - - - - - )} + {modelsStats ? ( + + + + ) : null} + + + + +
    @@ -775,6 +826,16 @@ export const ModelsList: FC = ({ model={modelToDeploy} /> ) : null} + {isAddModelFlyoutVisible ? ( + i.state === MODEL_STATE.NOT_DOWNLOADED)} + onClose={setIsAddModelFlyoutVisible.bind(null, false)} + onSubmit={(modelId) => { + onModelDownloadRequest(modelId); + setIsAddModelFlyoutVisible(false); + }} + /> + ) : null} ); }; diff --git a/x-pack/plugins/ml/public/application/routing/routes/new_job/from_pattern_analysis.tsx b/x-pack/plugins/ml/public/application/routing/routes/new_job/from_pattern_analysis.tsx new file mode 100644 index 000000000000..1ac93184f201 --- /dev/null +++ b/x-pack/plugins/ml/public/application/routing/routes/new_job/from_pattern_analysis.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { Redirect } from 'react-router-dom'; +import { parse } from 'query-string'; +import { useMlKibana } from '../../../contexts/kibana'; +import { ML_PAGES } from '../../../../locator'; +import { createPath, MlRoute, PageLoader, PageProps } from '../../router'; +import { useRouteResolver } from '../../use_resolver'; +import { resolver } from '../../../jobs/new_job/job_from_pattern_analysis'; + +export const fromPatternAnalysisRouteFactory = (): MlRoute => ({ + path: createPath(ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS), + render: (props, deps) => , + breadcrumbs: [], +}); + +const PageWrapper: FC = ({ location }) => { + const { + categorizationType, + dataViewId, + field, + partitionField, + stopOnWarn, + from, + to, + query, + }: Record = parse(location.search, { + sort: false, + }); + const { + services: { + data, + dashboard: dashboardService, + uiSettings: kibanaConfig, + mlServices: { mlApiServices }, + }, + } = useMlKibana(); + + const { context } = useRouteResolver('full', ['canCreateJob'], { + redirect: () => + resolver( + { + mlApiServices, + timeFilter: data.query.timefilter.timefilter, + kibanaConfig, + dashboardService, + data, + }, + categorizationType, + dataViewId, + field, + partitionField, + stopOnWarn, + from, + to, + query + ), + }); + + return ( + + {} + + ); +}; diff --git a/x-pack/plugins/ml/public/application/routing/routes/new_job/index.ts b/x-pack/plugins/ml/public/application/routing/routes/new_job/index.ts index 675b391d1e82..d4876aba2444 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/new_job/index.ts +++ b/x-pack/plugins/ml/public/application/routing/routes/new_job/index.ts @@ -12,3 +12,4 @@ export * from './wizard'; export * from './recognize'; export * from './from_lens'; export * from './from_map'; +export * from './from_pattern_analysis'; diff --git a/x-pack/plugins/ml/public/application/services/elastic_models_service.ts b/x-pack/plugins/ml/public/application/services/elastic_models_service.ts index 2591fb6d82e7..efc6249f9582 100644 --- a/x-pack/plugins/ml/public/application/services/elastic_models_service.ts +++ b/x-pack/plugins/ml/public/application/services/elastic_models_service.ts @@ -5,7 +5,10 @@ * 2.0. */ -import type { ModelDefinitionResponse, GetElserOptions } from '@kbn/ml-trained-models-utils'; +import type { + ModelDefinitionResponse, + GetModelDownloadConfigOptions, +} from '@kbn/ml-trained-models-utils'; import { type TrainedModelsApiService } from './ml_api_service/trained_models'; export class ElasticModels { @@ -17,7 +20,7 @@ export class ElasticModels { * If any of the ML nodes run a different OS rather than Linux, or the CPU architecture isn't x86_64, * a portable version of the model is returned. */ - public async getELSER(options?: GetElserOptions): Promise { + public async getELSER(options?: GetModelDownloadConfigOptions): Promise { return await this.trainedModels.getElserConfig(options); } } diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts index 9d9d0f859655..5794de5151e8 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts @@ -49,7 +49,7 @@ export interface DeleteDataFrameAnalyticsWithIndexResponse { acknowledged: boolean; analyticsJobDeleted: DeleteDataFrameAnalyticsWithIndexStatus; destIndexDeleted: DeleteDataFrameAnalyticsWithIndexStatus; - destIndexPatternDeleted: DeleteDataFrameAnalyticsWithIndexStatus; + destDataViewDeleted: DeleteDataFrameAnalyticsWithIndexStatus; } export interface JobsExistsResponse { @@ -83,12 +83,15 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({ }, createDataFrameAnalytics( analyticsId: string, - analyticsConfig: DeepPartial + analyticsConfig: DeepPartial, + createDataView: boolean = false, + timeFieldName?: string ) { const body = JSON.stringify(analyticsConfig); return httpService.http({ path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}`, method: 'PUT', + query: { createDataView, timeFieldName }, body, version: '1', }); @@ -152,11 +155,11 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({ deleteDataFrameAnalyticsAndDestIndex( analyticsId: string, deleteDestIndex: boolean, - deleteDestIndexPattern: boolean + deleteDestDataView: boolean ) { return httpService.http({ path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}`, - query: { deleteDestIndex, deleteDestIndexPattern }, + query: { deleteDestIndex, deleteDestDataView }, method: 'DELETE', version: '1', }); diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts index b886f6f7df8e..9bf880fb2b31 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts @@ -11,7 +11,10 @@ import type { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { useMemo } from 'react'; import type { HttpFetchQuery } from '@kbn/core/public'; import type { ErrorType } from '@kbn/ml-error-utils'; -import type { GetElserOptions, ModelDefinitionResponse } from '@kbn/ml-trained-models-utils'; +import type { + GetModelDownloadConfigOptions, + ModelDefinitionResponse, +} from '@kbn/ml-trained-models-utils'; import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app'; import type { MlSavedObjectType } from '../../../../common/types/saved_objects'; import { HttpService } from '../http_service'; @@ -73,7 +76,7 @@ export function trainedModelsApiProvider(httpService: HttpService) { /** * Gets ELSER config for download based on the cluster OS and CPU architecture. */ - getElserConfig(options?: GetElserOptions) { + getElserConfig(options?: GetModelDownloadConfigOptions) { return httpService.http({ path: `${ML_INTERNAL_BASE_PATH}/trained_models/elser_config`, method: 'GET', diff --git a/x-pack/plugins/ml/public/application/services/new_job_capabilities/new_job_capabilities_service.ts b/x-pack/plugins/ml/public/application/services/new_job_capabilities/new_job_capabilities_service.ts index f073c4afea84..511a1a1457b0 100644 --- a/x-pack/plugins/ml/public/application/services/new_job_capabilities/new_job_capabilities_service.ts +++ b/x-pack/plugins/ml/public/application/services/new_job_capabilities/new_job_capabilities_service.ts @@ -14,15 +14,21 @@ import { EVENT_RATE_FIELD_ID, } from '@kbn/ml-anomaly-utils'; import { getGeoFields, filterCategoryFields } from '../../../../common/util/fields_utils'; -import { ml } from '../ml_api_service'; +import { ml, type MlApiServices } from '../ml_api_service'; import { processTextAndKeywordFields, NewJobCapabilitiesServiceBase } from './new_job_capabilities'; -class NewJobCapsService extends NewJobCapabilitiesServiceBase { +export class NewJobCapsService extends NewJobCapabilitiesServiceBase { private _catFields: Field[] = []; private _dateFields: Field[] = []; private _geoFields: Field[] = []; private _includeEventRateField: boolean = true; private _removeTextFields: boolean = true; + private _mlApiService: MlApiServices; + + constructor(mlApiService: MlApiServices) { + super(); + this._mlApiService = mlApiService; + } public get catFields(): Field[] { return this._catFields; @@ -49,7 +55,10 @@ class NewJobCapsService extends NewJobCapabilitiesServiceBase { this._includeEventRateField = includeEventRateField; this._removeTextFields = removeTextFields; - const resp = await ml.jobs.newJobCaps(dataView.getIndexPattern(), dataView.type === 'rollup'); + const resp = await this._mlApiService.jobs.newJobCaps( + dataView.getIndexPattern(), + dataView.type === 'rollup' + ); const { fields: allFields, aggs } = createObjects(resp, dataView.getIndexPattern()); if (this._includeEventRateField === true) { @@ -175,4 +184,4 @@ function addEventRateField(aggs: Aggregation[], fields: Field[]) { fields.splice(0, 0, eventRateField); } -export const newJobCapsService = new NewJobCapsService(); +export const newJobCapsService = new NewJobCapsService(ml); diff --git a/x-pack/plugins/ml/public/application/util/index_utils.ts b/x-pack/plugins/ml/public/application/util/index_utils.ts index faa663e579bc..5ec52d74c07c 100644 --- a/x-pack/plugins/ml/public/application/util/index_utils.ts +++ b/x-pack/plugins/ml/public/application/util/index_utils.ts @@ -126,9 +126,9 @@ export function timeBasedIndexCheck(dataView: DataView, showNotification = false } /** - * Returns true if the data view index pattern contains a : + * Returns true if the index pattern contains a : * which means it is cross-cluster */ -export function isCcsIndexPattern(dataViewIndexPattern: string) { - return dataViewIndexPattern.includes(':'); +export function isCcsIndexPattern(indexPattern: string) { + return indexPattern.includes(':'); } diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/embeddable_swim_lane_container.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/embeddable_swim_lane_container.tsx index 7186148caf6e..a64a9f0bb859 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/embeddable_swim_lane_container.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/embeddable_swim_lane_container.tsx @@ -79,7 +79,7 @@ export const EmbeddableSwimLaneContainer: FC = ( services, chartWidth, fromPage, - { onRenderComplete, onError, onLoading } + { onError, onLoading } ); useEffect(() => { @@ -108,6 +108,7 @@ export const EmbeddableSwimLaneContainer: FC = ( ); if (error) { + onRenderComplete(); return ( = ( /> } chartsService={chartsService} + onRenderComplete={onRenderComplete} />
    ); diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.test.ts b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.test.ts index eace431179da..4e0f491007cd 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.test.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.test.ts @@ -22,7 +22,6 @@ describe('useSwimlaneInputResolver', () => { const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const renderCallbacks = { - onRenderComplete: jest.fn(), onLoading: jest.fn(), onError: jest.fn(), }; @@ -113,7 +112,6 @@ describe('useSwimlaneInputResolver', () => { expect(services[2].anomalyTimelineService.loadOverallData).toHaveBeenCalledTimes(1); expect(renderCallbacks.onLoading).toHaveBeenCalledTimes(1); - expect(renderCallbacks.onRenderComplete).toHaveBeenCalledTimes(1); await act(async () => { embeddableInput.next({ @@ -130,7 +128,6 @@ describe('useSwimlaneInputResolver', () => { expect(services[2].anomalyTimelineService.loadOverallData).toHaveBeenCalledTimes(2); expect(renderCallbacks.onLoading).toHaveBeenCalledTimes(2); - expect(renderCallbacks.onRenderComplete).toHaveBeenCalledTimes(2); await act(async () => { embeddableInput.next({ @@ -147,7 +144,6 @@ describe('useSwimlaneInputResolver', () => { expect(services[2].anomalyTimelineService.loadOverallData).toHaveBeenCalledTimes(3); expect(renderCallbacks.onLoading).toHaveBeenCalledTimes(3); - expect(renderCallbacks.onRenderComplete).toHaveBeenCalledTimes(3); }); test('should not complete the observable on error', async () => { diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts index d543ff4cc9bf..8669c3b7bd52 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts @@ -50,8 +50,7 @@ export function useSwimlaneInputResolver( services: [CoreStart, MlStartDependencies, AnomalySwimlaneServices], chartWidth: number, fromPage: number, - renderCallbacks: { - onRenderComplete: () => void; + reportingCallbacks: { onLoading: () => void; onError: (error: Error) => void; } @@ -131,7 +130,7 @@ export function useSwimlaneInputResolver( tap(setIsLoading.bind(null, true)), debounceTime(FETCH_RESULTS_DEBOUNCE_MS), tap(() => { - renderCallbacks.onLoading(); + reportingCallbacks.onLoading(); }), switchMap(([explorerJobs, input, bucketInterval, fromPageInput, perPageFromState]) => { if (!explorerJobs) { @@ -246,18 +245,11 @@ export function useSwimlaneInputResolver( useEffect(() => { if (error) { - renderCallbacks.onError(error); + reportingCallbacks.onError(error); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [error]); - useEffect(() => { - if (swimlaneData) { - renderCallbacks.onRenderComplete(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [swimlaneData]); - return [ swimlaneType, swimlaneData, diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/create_job.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/create_job.tsx new file mode 100644 index 000000000000..5e52b0f5cd21 --- /dev/null +++ b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/create_job.tsx @@ -0,0 +1,273 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC, useCallback, useMemo, useState, useEffect } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { + EuiCheckableCard, + EuiTitle, + EuiSpacer, + EuiSwitch, + EuiHorizontalRule, + EuiComboBoxOptionOption, + EuiComboBox, + EuiFormRow, + EuiCallOut, +} from '@elastic/eui'; + +import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; +import type { TimeRange } from '@kbn/es-query'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { redirectToADJobWizards } from '../../../../application/jobs/new_job/job_from_pattern_analysis/utils'; +import { createFieldOptions } from '../../../../application/jobs/new_job/common/job_creator/util/general'; +import { NewJobCapsService } from '../../../../application/services/new_job_capabilities/new_job_capabilities_service'; +import { + type CategorizationType, + CATEGORIZATION_TYPE, + QuickCategorizationJobCreator, +} from '../../../../application/jobs/new_job/job_from_pattern_analysis'; +import { useMlFromLensKibanaContext } from '../../common/context'; +import { JobDetails, type CreateADJobParams } from '../../common/job_details'; + +interface Props { + dataView: DataView; + field: DataViewField; + query: QueryDslQueryContainer; + timeRange: TimeRange; +} + +export const CreateJob: FC = ({ dataView, field, query, timeRange }) => { + const { + services: { + data, + share, + uiSettings, + mlServices: { mlApiServices }, + dashboardService, + }, + } = useMlFromLensKibanaContext(); + + const [categorizationType, setCategorizationType] = useState( + CATEGORIZATION_TYPE.COUNT + ); + const [enablePerPartitionCategorization, setEnablePerPartitionCategorization] = useState(false); + const [stopOnWarn, setStopOnWarn] = useState(false); + const [categoryFieldOptions, setCategoryFieldsOptions] = useState([]); + const [selectedPartitionFieldOptions, setSelectedPartitionFieldOptions] = useState< + EuiComboBoxOptionOption[] + >([]); + const [formComplete, setFormComplete] = useState(undefined); + + const toggleEnablePerPartitionCategorization = useCallback( + () => setEnablePerPartitionCategorization(!enablePerPartitionCategorization), + [enablePerPartitionCategorization] + ); + + const toggleStopOnWarn = useCallback(() => setStopOnWarn(!stopOnWarn), [stopOnWarn]); + + useMemo(() => { + const newJobCapsService = new NewJobCapsService(mlApiServices); + newJobCapsService.initializeFromDataVIew(dataView).then(() => { + const options: EuiComboBoxOptionOption[] = [ + ...createFieldOptions(newJobCapsService.categoryFields, []), + ].map((o) => ({ + ...o, + })); + setCategoryFieldsOptions(options); + }); + }, [dataView, mlApiServices]); + + const quickJobCreator = useMemo( + () => + new QuickCategorizationJobCreator( + uiSettings, + data.query.timefilter.timefilter, + dashboardService, + data, + mlApiServices + ), + + [dashboardService, data, mlApiServices, uiSettings] + ); + + function createADJobInWizard() { + const partitionField = selectedPartitionFieldOptions.length + ? dataView.getFieldByName(selectedPartitionFieldOptions[0].label) ?? null + : null; + redirectToADJobWizards( + categorizationType, + dataView, + field, + partitionField, + stopOnWarn, + query, + timeRange, + share + ); + } + + useEffect(() => { + setSelectedPartitionFieldOptions([]); + setStopOnWarn(false); + }, [enablePerPartitionCategorization]); + + useEffect(() => { + setFormComplete( + enablePerPartitionCategorization === false || selectedPartitionFieldOptions.length > 0 + ); + }, [enablePerPartitionCategorization, selectedPartitionFieldOptions]); + + async function createADJob({ jobId, bucketSpan, startJob, runInRealTime }: CreateADJobParams) { + const partitionField = selectedPartitionFieldOptions.length + ? dataView.getFieldByName(selectedPartitionFieldOptions[0].label) ?? null + : null; + const result = await quickJobCreator.createAndSaveJob( + categorizationType, + jobId, + bucketSpan, + dataView, + field, + partitionField, + stopOnWarn, + query, + timeRange, + startJob, + runInRealTime + ); + return result; + } + return ( + + <> + + +
    + +
    +
    + + + + } + checked={categorizationType === CATEGORIZATION_TYPE.COUNT} + onChange={() => setCategorizationType(CATEGORIZATION_TYPE.COUNT)} + /> + + + + + +
    + +
    +
    + + + + } + checked={categorizationType === CATEGORIZATION_TYPE.RARE} + onChange={() => setCategorizationType(CATEGORIZATION_TYPE.RARE)} + /> + + + } + /> + + {enablePerPartitionCategorization ? ( + <> + + + + } + /> + + + + + } + > + + + + + + + } + /> + + ) : null} + + + + + +
    + ); +}; diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/flyout.tsx new file mode 100644 index 000000000000..48781b177614 --- /dev/null +++ b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/flyout.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiFlyoutBody, + EuiTitle, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TimeRange } from '@kbn/es-query'; +import { CreateJob } from './create_job'; + +interface Props { + dataView: DataView; + field: DataViewField; + query: QueryDslQueryContainer; + timeRange: TimeRange; + onClose: () => void; +} + +export const CreateCategorizationJobFlyout: FC = ({ + onClose, + dataView, + field, + query, + timeRange, +}) => { + return ( + <> + + +

    + +

    +
    + + + + +
    + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/index.ts b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/index.ts new file mode 100644 index 000000000000..ab544dc3d55b --- /dev/null +++ b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/flyout/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { CreateCategorizationJobFlyout } from './flyout'; diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/aiops/index.ts b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/index.ts new file mode 100644 index 000000000000..a156caa5ef57 --- /dev/null +++ b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { showPatternAnalysisToADJobFlyout } from './show_flyout'; diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/aiops/show_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/show_flyout.tsx new file mode 100644 index 000000000000..c1fe261cbe92 --- /dev/null +++ b/x-pack/plugins/ml/public/embeddables/job_creation/aiops/show_flyout.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import type { CoreStart } from '@kbn/core/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { LensPublicStart } from '@kbn/lens-plugin/public'; +import type { DashboardStart } from '@kbn/dashboard-plugin/public'; +import type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { TimeRange } from '@kbn/es-query'; +import { createFlyout, type FlyoutComponentProps } from '../common/create_flyout'; +import { CreateCategorizationJobFlyout } from './flyout'; + +export async function showPatternAnalysisToADJobFlyout( + dataView: DataView, + field: DataViewField, + query: QueryDslQueryContainer, + timeRange: TimeRange, + coreStart: CoreStart, + share: SharePluginStart, + data: DataPublicPluginStart, + dashboardService: DashboardStart, + lens?: LensPublicStart +): Promise { + const Comp: FC = ({ onClose }) => ( + + ); + return createFlyout(Comp, coreStart, share, data, dashboardService, lens); +} diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/lens/context.ts b/x-pack/plugins/ml/public/embeddables/job_creation/common/context.ts similarity index 100% rename from x-pack/plugins/ml/public/embeddables/job_creation/lens/context.ts rename to x-pack/plugins/ml/public/embeddables/job_creation/common/context.ts diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx index 7fd5f9e86fca..b1bc9ec47ba9 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx @@ -14,15 +14,16 @@ import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import type { MapEmbeddable } from '@kbn/maps-plugin/public'; -import type { Embeddable } from '@kbn/lens-plugin/public'; import type { DashboardStart } from '@kbn/dashboard-plugin/public'; import { getMlGlobalServices } from '../../../application/app'; +export interface FlyoutComponentProps { + onClose: () => void; +} + export function createFlyout( FlyoutComponent: React.FunctionComponent, - embeddable: MapEmbeddable | Embeddable, coreStart: CoreStart, share: SharePluginStart, data: DataPublicPluginStart, @@ -57,7 +58,6 @@ export function createFlyout( }} > { onFlyoutClose(); resolve(); diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/common/job_details.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/common/job_details.tsx index e2fff3bd286c..312d75a2a97b 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/common/job_details.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/common/job_details.tsx @@ -32,6 +32,7 @@ import type { Embeddable } from '@kbn/lens-plugin/public'; import type { MapEmbeddable } from '@kbn/maps-plugin/public'; import { extractErrorMessage } from '@kbn/ml-error-utils'; +import type { TimeRange } from '@kbn/es-query'; import { QuickLensJobCreator } from '../../../application/jobs/new_job/job_from_lens'; import type { LayerResult } from '../../../application/jobs/new_job/job_from_lens'; import type { CreateState } from '../../../application/jobs/new_job/job_from_dashboard'; @@ -40,12 +41,12 @@ import { basicJobValidation } from '../../../../common/util/job_utils'; import { JOB_ID_MAX_LENGTH } from '../../../../common/constants/validation'; import { invalidTimeIntervalMessage } from '../../../application/jobs/new_job/common/job_validator/util'; import { ML_APP_LOCATOR, ML_PAGES } from '../../../../common/constants/locator'; -import { useMlFromLensKibanaContext } from '../lens/context'; +import { useMlFromLensKibanaContext } from './context'; export interface CreateADJobParams { jobId: string; bucketSpan: string; - embeddable: MapEmbeddable | Embeddable; + embeddable: MapEmbeddable | Embeddable | undefined; startJob: boolean; runInRealTime: boolean; } @@ -56,8 +57,10 @@ interface Props { createADJob: (args: CreateADJobParams) => Promise; layer?: LayerResult; layerIndex: number; - embeddable: Embeddable | MapEmbeddable; + embeddable: Embeddable | MapEmbeddable | undefined; + timeRange: TimeRange | undefined; incomingCreateError?: { text: string; errorText: string }; + outerFormComplete?: boolean; } enum STATE { @@ -75,7 +78,9 @@ export const JobDetails: FC = ({ layer, layerIndex, embeddable, + timeRange, incomingCreateError, + outerFormComplete, }) => { const { services: { @@ -121,7 +126,6 @@ export const JobDetails: FC = ({ const viewResults = useCallback( async (type: JOB_TYPE | null) => { - const { timeRange } = embeddable.getInput(); const locator = share.url.locators.get(ML_APP_LOCATOR); if (locator) { const page = startJob @@ -144,7 +148,7 @@ export const JobDetails: FC = ({ application.navigateToUrl(url); } }, - [jobId, embeddable, share, application, startJob] + [share, startJob, jobId, timeRange, application] ); function setStartJobWrapper(start: boolean) { @@ -313,7 +317,8 @@ export const JobDetails: FC = ({ state === STATE.VALIDATING || jobId === '' || jobIdValidationError !== '' || - bucketSpanValidationError !== '' + bucketSpanValidationError !== '' || + outerFormComplete === false } onClick={createJob.bind(null, layerIndex)} size="s" diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/flyout.tsx index 06420c071c22..dc0ab2edd4a1 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/flyout.tsx @@ -23,7 +23,7 @@ import { import { Layer } from './layer'; import type { LayerResult } from '../../../../application/jobs/new_job/job_from_lens'; import { VisualizationExtractor } from '../../../../application/jobs/new_job/job_from_lens'; -import { useMlFromLensKibanaContext } from '../context'; +import { useMlFromLensKibanaContext } from '../../common/context'; interface Props { embeddable: Embeddable; diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/layer/compatible_layer.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/layer/compatible_layer.tsx index 0d024bd2d77a..d82ddbf94dd8 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/layer/compatible_layer.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/lens/lens_vis_layer_selection_flyout/layer/compatible_layer.tsx @@ -17,7 +17,7 @@ import { } from '../../../../../application/jobs/new_job/job_from_lens'; import type { LayerResult } from '../../../../../application/jobs/new_job/job_from_lens'; import { JOB_TYPE } from '../../../../../../common/constants/new_job'; -import { useMlFromLensKibanaContext } from '../../context'; +import { useMlFromLensKibanaContext } from '../../../common/context'; import { JobDetails, CreateADJobParams } from '../../../common/job_details'; interface Props { @@ -79,6 +79,7 @@ export const CompatibleLayer: FC = ({ layer, layerIndex, embeddable }) => createADJob={createADJob} createADJobInWizard={createADJobInWizard} embeddable={embeddable} + timeRange={embeddable.getInput().timeRange} layer={layer} layerIndex={layerIndex} > diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx index 91e6f6f00186..375588765bd1 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx @@ -5,13 +5,14 @@ * 2.0. */ +import React, { FC } from 'react'; import type { Embeddable } from '@kbn/lens-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import type { DashboardStart } from '@kbn/dashboard-plugin/public'; -import { createFlyout } from '../common/create_flyout'; +import { createFlyout, type FlyoutComponentProps } from '../common/create_flyout'; import { LensLayerSelectionFlyout } from './lens_vis_layer_selection_flyout'; export async function showLensVisToADJobFlyout( @@ -19,16 +20,11 @@ export async function showLensVisToADJobFlyout( coreStart: CoreStart, share: SharePluginStart, data: DataPublicPluginStart, - lens: LensPublicStart, - dashboardService: DashboardStart + dashboardService: DashboardStart, + lens: LensPublicStart ): Promise { - return createFlyout( - LensLayerSelectionFlyout, - embeddable, - coreStart, - share, - data, - dashboardService, - lens + const Comp: FC = ({ onClose }) => ( + ); + return createFlyout(Comp, coreStart, share, data, dashboardService, lens); } diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/map/map_vis_layer_selection_flyout/layer/compatible_layer.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/map/map_vis_layer_selection_flyout/layer/compatible_layer.tsx index d4075414e3a9..8f368dc0a82c 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/map/map_vis_layer_selection_flyout/layer/compatible_layer.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/map/map_vis_layer_selection_flyout/layer/compatible_layer.tsx @@ -25,7 +25,7 @@ import { QuickGeoJobCreator, redirectToGeoJobWizard, } from '../../../../../application/jobs/new_job/job_from_map'; -import { useMlFromLensKibanaContext } from '../../../lens/context'; +import { useMlFromLensKibanaContext } from '../../../common/context'; import { JobDetails, CreateADJobParams } from '../../../common/job_details'; interface DropDownLabel { @@ -147,6 +147,7 @@ export const CompatibleLayer: FC = ({ embeddable, layer, layerIndex }) => createADJob={createGeoJob} createADJobInWizard={createGeoJobInWizard} embeddable={embeddable} + timeRange={embeddable.getInput().timeRange} incomingCreateError={createError} > <> diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx index 5380513f1dc9..293ec69b30db 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React, { FC } from 'react'; import type { CoreStart } from '@kbn/core/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; @@ -12,7 +13,7 @@ import type { MapEmbeddable } from '@kbn/maps-plugin/public'; import type { DashboardStart } from '@kbn/dashboard-plugin/public'; import { GeoJobFlyout } from './flyout'; -import { createFlyout } from '../common/create_flyout'; +import { createFlyout, type FlyoutComponentProps } from '../common/create_flyout'; export async function showMapVisToADJobFlyout( embeddable: MapEmbeddable, @@ -21,5 +22,8 @@ export async function showMapVisToADJobFlyout( data: DataPublicPluginStart, dashboardService: DashboardStart ): Promise { - return createFlyout(GeoJobFlyout, embeddable, coreStart, share, data, dashboardService); + const Comp: FC = ({ onClose }) => ( + + ); + return createFlyout(Comp, coreStart, share, data, dashboardService); } diff --git a/x-pack/plugins/ml/public/locator/ml_locator.ts b/x-pack/plugins/ml/public/locator/ml_locator.ts index e397778315a6..05fe312fd9a4 100644 --- a/x-pack/plugins/ml/public/locator/ml_locator.ts +++ b/x-pack/plugins/ml/public/locator/ml_locator.ts @@ -85,6 +85,7 @@ export class MlLocatorDefinition implements LocatorDefinition { case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_ADVANCED: case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_LENS: case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_MAP: + case ML_PAGES.ANOMALY_DETECTION_CREATE_JOB_FROM_PATTERN_ANALYSIS: case ML_PAGES.DATA_VISUALIZER: case ML_PAGES.DATA_VISUALIZER_FILE: case ML_PAGES.DATA_VISUALIZER_INDEX_VIEWER: diff --git a/x-pack/plugins/ml/public/mocks.ts b/x-pack/plugins/ml/public/mocks.ts index be18bfb1f49f..8a2c7efefc9c 100644 --- a/x-pack/plugins/ml/public/mocks.ts +++ b/x-pack/plugins/ml/public/mocks.ts @@ -20,7 +20,7 @@ const createElasticModelsMock = (): jest.Mocked => { }, }, description: 'Elastic Learned Sparse EncodeR v2 (Tech Preview)', - name: '.elser_model_2', + model_id: '.elser_model_2', }), } as unknown as jest.Mocked; }; diff --git a/x-pack/plugins/ml/public/ui_actions/index.ts b/x-pack/plugins/ml/public/ui_actions/index.ts index 4067547e0895..4e756d9d44d5 100644 --- a/x-pack/plugins/ml/public/ui_actions/index.ts +++ b/x-pack/plugins/ml/public/ui_actions/index.ts @@ -8,9 +8,14 @@ import { CoreSetup } from '@kbn/core/public'; import { UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import { CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER } from '@kbn/ml-ui-actions'; import { createEditSwimlanePanelAction } from './edit_swimlane_panel_action'; import { createOpenInExplorerAction } from './open_in_anomaly_explorer_action'; import { createVisToADJobAction } from './open_vis_in_ml_action'; +import { + createCategorizationADJobAction, + createCategorizationADJobTrigger, +} from './open_create_categorization_job_action'; import { MlPluginStart, MlStartDependencies } from '../plugin'; import { createApplyInfluencerFiltersAction } from './apply_influencer_filters_action'; import { @@ -45,6 +50,7 @@ export function registerMlUiActions( const clearSelectionAction = createClearSelectionAction(core.getStartServices); const editExplorerPanelAction = createEditAnomalyChartsPanelAction(core.getStartServices); const visToAdJobAction = createVisToADJobAction(core.getStartServices); + const categorizationADJobAction = createCategorizationADJobAction(core.getStartServices); // Register actions uiActions.registerAction(editSwimlanePanelAction); @@ -54,6 +60,7 @@ export function registerMlUiActions( uiActions.registerAction(applyTimeRangeSelectionAction); uiActions.registerAction(clearSelectionAction); uiActions.registerAction(editExplorerPanelAction); + uiActions.registerAction(categorizationADJobAction); // Assign triggers uiActions.attachAction(CONTEXT_MENU_TRIGGER, editSwimlanePanelAction.id); @@ -62,6 +69,7 @@ export function registerMlUiActions( uiActions.registerTrigger(swimLaneSelectionTrigger); uiActions.registerTrigger(entityFieldSelectionTrigger); + uiActions.registerTrigger(createCategorizationADJobTrigger); uiActions.addTriggerAction(SWIM_LANE_SELECTION_TRIGGER, applyInfluencerFiltersAction); uiActions.addTriggerAction(SWIM_LANE_SELECTION_TRIGGER, applyTimeRangeSelectionAction); @@ -69,4 +77,8 @@ export function registerMlUiActions( uiActions.addTriggerAction(SWIM_LANE_SELECTION_TRIGGER, clearSelectionAction); uiActions.addTriggerAction(EXPLORER_ENTITY_FIELD_SELECTION_TRIGGER, applyEntityFieldFilterAction); uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, visToAdJobAction); + uiActions.addTriggerAction( + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER, + categorizationADJobAction + ); } diff --git a/x-pack/plugins/ml/public/ui_actions/open_create_categorization_job_action.tsx b/x-pack/plugins/ml/public/ui_actions/open_create_categorization_job_action.tsx new file mode 100644 index 000000000000..2855020a201d --- /dev/null +++ b/x-pack/plugins/ml/public/ui_actions/open_create_categorization_job_action.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { Trigger, UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; +import { + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION, + CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER, + type CreateCategorizationADJobContext, +} from '@kbn/ml-ui-actions'; +import type { MlCoreSetup } from '../plugin'; + +export const createCategorizationADJobTrigger: Trigger = { + id: CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_TRIGGER, + title: i18n.translate('xpack.ml.actions.createADJobFromPatternAnalysis', { + defaultMessage: 'Create categorization anomaly detection job', + }), + description: i18n.translate('xpack.ml.actions.createADJobFromPatternAnalysis', { + defaultMessage: 'Create categorization anomaly detection job', + }), +}; + +export function createCategorizationADJobAction( + getStartServices: MlCoreSetup['getStartServices'] +): UiActionsActionDefinition { + return { + id: 'create-ml-categorization-ad-job-action', + type: CREATE_PATTERN_ANALYSIS_TO_ML_AD_JOB_ACTION, + getIconType(context): string { + return 'machineLearningApp'; + }, + getDisplayName: () => + i18n.translate('xpack.ml.actions.createADJobFromPatternAnalysis', { + defaultMessage: 'Create categorization anomaly detection job', + }), + async execute({ dataView, field, query, timeRange }: CreateCategorizationADJobContext) { + if (!dataView) { + throw new Error('Not possible to execute an action without the embeddable context'); + } + + try { + const [{ showPatternAnalysisToADJobFlyout }, [coreStart, { share, data, dashboard }]] = + await Promise.all([import('../embeddables/job_creation/aiops'), getStartServices()]); + + await showPatternAnalysisToADJobFlyout( + dataView, + field, + query, + timeRange, + coreStart, + share, + data, + dashboard + ); + } catch (e) { + return Promise.reject(); + } + }, + async isCompatible({ dataView, field }: CreateCategorizationADJobContext) { + return ( + dataView.timeFieldName !== undefined && + dataView.fields.find((f) => f.name === field.name) !== undefined + ); + }, + }; +} diff --git a/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx b/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx index fb0aa38e44d9..f47df760ea9c 100644 --- a/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx +++ b/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx @@ -39,7 +39,7 @@ export function createVisToADJobAction( if (lens === undefined) { return; } - await showLensVisToADJobFlyout(embeddable, coreStart, share, data, lens, dashboard); + await showLensVisToADJobFlyout(embeddable, coreStart, share, data, dashboard, lens); } else if (isMapEmbeddable(embeddable)) { const [{ showMapVisToADJobFlyout }, [coreStart, { share, data, dashboard }]] = await Promise.all([import('../embeddables/job_creation/map'), getStartServices()]); diff --git a/x-pack/plugins/ml/readme.md b/x-pack/plugins/ml/readme.md index 72739cc79fff..235cc4e0458b 100644 --- a/x-pack/plugins/ml/readme.md +++ b/x-pack/plugins/ml/readme.md @@ -149,7 +149,7 @@ With PATH_TO_CONFIG and other options as follows. - PATH_TO_CONFIG: `test/accessibility/config.ts` - Add `--grep=ml` to the test runner command - - Tests are located in `x-pack/test/accessibility/apps` + - Tests are located in `x-pack/test/accessibility/apps/group2` ## Generating docs screenshots diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts index cd5e50acdc12..f959683b6ae8 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts @@ -67,6 +67,16 @@ export class AnalyticsManager { this._jobs = jobs.data_frame_analytics; } + private getMissingJobNode(label: string): AnalyticsMapNodeElement { + return { + data: { + id: `${label}-${JOB_MAP_NODE_TYPES.ANALYTICS}`, + label, + type: JOB_MAP_NODE_TYPES.ANALYTICS_JOB_MISSING, + }, + }; + } + private isDuplicateElement(analyticsId: string, elements: MapElements[]): boolean { let isDuplicate = false; elements.forEach((elem) => { @@ -106,12 +116,8 @@ export class AnalyticsManager { ); } - private findJob(id: string): estypes.MlDataframeAnalyticsSummary { - const job = this._jobs.find((js) => js.id === id); - if (job === undefined) { - throw Error(`No known job with id '${id}'`); - } - return job; + private findJob(id: string): estypes.MlDataframeAnalyticsSummary | undefined { + return this._jobs.find((js) => js.id === id); } private findTrainedModel(id: string): estypes.MlTrainedModelConfig { @@ -156,14 +162,16 @@ export class AnalyticsManager { private getAnalyticsModelElements( analyticsId: string, - analyticsCreateTime: number + analyticsCreateTime?: number ): { modelElement?: AnalyticsMapNodeElement; modelDetails?: any; edgeElement?: AnalyticsMapEdgeElement; } { // Get trained model for analytics job and create model node - const analyticsModel = this.findJobModel(analyticsId, analyticsCreateTime); + const analyticsModel = analyticsCreateTime + ? this.findJobModel(analyticsId, analyticsCreateTime) + : undefined; let modelElement; let edgeElement; @@ -221,7 +229,7 @@ export class AnalyticsManager { const resultElements = []; const modelElements = []; const details: any = {}; - let data: estypes.MlTrainedModelConfig | estypes.MlDataframeAnalyticsSummary; + let data: estypes.MlTrainedModelConfig | estypes.MlDataframeAnalyticsSummary | undefined; // fetch model data and create model elements data = this.findTrainedModel(modelId); const modelNodeId = `${data.model_id}-${JOB_MAP_NODE_TYPES.TRAINED_MODEL}`; @@ -243,37 +251,35 @@ export class AnalyticsManager { details[modelNodeId] = data; // fetch source job data and create elements if (sourceJobId !== undefined) { - try { - data = this.findJob(sourceJobId); - - nextLinkId = data?.source?.index[0]; - nextType = JOB_MAP_NODE_TYPES.INDEX; - - previousNodeId = `${data.id}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; - - resultElements.push({ - data: { - id: previousNodeId, - label: data.id, - type: JOB_MAP_NODE_TYPES.ANALYTICS, - analysisType: getAnalysisType(data?.analysis), - }, - }); - // Create edge between job and model - modelElements.push({ - data: { - id: `${previousNodeId}~${modelNodeId}`, - source: previousNodeId, - target: modelNodeId, - }, - }); + data = this.findJob(sourceJobId); + + nextLinkId = data?.source?.index[0]; + nextType = JOB_MAP_NODE_TYPES.INDEX; + previousNodeId = `${data?.id ?? sourceJobId}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; + // If data is undefined - job wasn't found. Create missing job node. + resultElements.push( + data === undefined + ? this.getMissingJobNode(sourceJobId) + : { + data: { + id: previousNodeId, + label: data.id, + type: JOB_MAP_NODE_TYPES.ANALYTICS, + analysisType: getAnalysisType(data?.analysis), + }, + } + ); + // Create edge between job and model + modelElements.push({ + data: { + id: `${previousNodeId}~${modelNodeId}`, + source: previousNodeId, + target: modelNodeId, + }, + }); + if (data) { details[previousNodeId] = data; - } catch (error) { - // fail silently if job doesn't exist - if (error.statusCode !== 404) { - throw error.body ?? error; - } } } @@ -295,21 +301,25 @@ export class AnalyticsManager { const nextLinkId = data?.source?.index[0]; const nextType: JobMapNodeTypes = JOB_MAP_NODE_TYPES.INDEX; + const previousNodeId = `${data?.id ?? jobId}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; - const previousNodeId = `${data.id}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; - - resultElements.push({ - data: { - id: previousNodeId, - label: data.id, - type: JOB_MAP_NODE_TYPES.ANALYTICS, - analysisType: getAnalysisType(data?.analysis), - isRoot: true, - }, - }); - - details[previousNodeId] = data; + resultElements.push( + data === undefined + ? this.getMissingJobNode(jobId) + : { + data: { + id: previousNodeId, + label: data.id, + type: JOB_MAP_NODE_TYPES.ANALYTICS, + analysisType: getAnalysisType(data?.analysis), + isRoot: true, + }, + } + ); + if (data) { + details[previousNodeId] = data; + } const { modelElement, modelDetails, edgeElement } = this.getAnalyticsModelElements( jobId, jobCreateTime @@ -429,33 +439,40 @@ export class AnalyticsManager { nextType = JOB_MAP_NODE_TYPES.TRANSFORM; } } else if (isJobDataLinkReturnType(link) && link.isJob === true) { + // Create missing job node here if job is undefined data = link.jobData; - const nodeId = `${data.id}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; + const nodeId = `${data?.id ?? nextLinkId}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; previousNodeId = nodeId; - result.elements.unshift({ - data: { - id: nodeId, - label: data.id, - type: JOB_MAP_NODE_TYPES.ANALYTICS, - analysisType: getAnalysisType(data?.analysis), - }, - }); + result.elements.unshift( + data === undefined + ? this.getMissingJobNode(nextLinkId) + : { + data: { + id: nodeId, + label: data.id, + type: JOB_MAP_NODE_TYPES.ANALYTICS, + analysisType: getAnalysisType(data?.analysis), + }, + } + ); result.details[nodeId] = data; nextLinkId = data?.source?.index[0]; nextType = JOB_MAP_NODE_TYPES.INDEX; - // Get trained model for analytics job and create model node - ({ modelElement, modelDetails, edgeElement } = this.getAnalyticsModelElements( - data.id, - data.create_time - )); - if (isAnalyticsMapNodeElement(modelElement)) { - modelElements.push(modelElement); - result.details[modelElement.data.id] = modelDetails; - } - if (isAnalyticsMapEdgeElement(edgeElement)) { - modelElements.push(edgeElement); + if (data) { + // Get trained model for analytics job and create model node + ({ modelElement, modelDetails, edgeElement } = this.getAnalyticsModelElements( + data.id, + data.create_time + )); + if (isAnalyticsMapNodeElement(modelElement)) { + modelElements.push(modelElement); + result.details[modelElement.data.id] = modelDetails; + } + if (isAnalyticsMapEdgeElement(edgeElement)) { + modelElements.push(edgeElement); + } } } else if (isTransformLinkReturnType(link) && link.isTransform === true) { data = link.transformData; @@ -626,7 +643,7 @@ export class AnalyticsManager { if (analyticsId !== undefined) { const jobData = this.findJob(analyticsId); - const currentJobNodeId = `${jobData.id}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; + const currentJobNodeId = `${jobData?.id ?? analyticsId}-${JOB_MAP_NODE_TYPES.ANALYTICS}`; rootIndex = Array.isArray(jobData?.dest?.index) ? jobData?.dest?.index[0] : jobData?.dest?.index; @@ -635,7 +652,7 @@ export class AnalyticsManager { // Fetch trained model for incoming job id and add node and edge const { modelElement, modelDetails, edgeElement } = this.getAnalyticsModelElements( analyticsId, - jobData.create_time! + jobData?.create_time ); if (isAnalyticsMapNodeElement(modelElement)) { result.elements.push(modelElement); diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts deleted file mode 100644 index fc07c69d8dc7..000000000000 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataViewsService } from '@kbn/data-views-plugin/common'; - -export class DataViewHandler { - constructor(private dataViewService: DataViewsService) {} - // returns a id based on an index pattern name - async getDataViewId(indexName: string) { - const dv = (await this.dataViewService.find(indexName)).find( - ({ title }) => title === indexName - ); - return dv?.id; - } - - async deleteDataViewById(dataViewId: string) { - return await this.dataViewService.delete(dataViewId); - } -} diff --git a/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts b/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts index 679cfd49ef63..ff18327fdea5 100644 --- a/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts +++ b/x-pack/plugins/ml/server/models/model_management/model_provider.test.ts @@ -54,24 +54,53 @@ describe('modelsProvider', () => { config: { input: { field_names: ['text_field'] } }, description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)', hidden: true, - name: '.elser_model_1', + model_id: '.elser_model_1', version: 1, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], }, { config: { input: { field_names: ['text_field'] } }, default: true, description: 'Elastic Learned Sparse EncodeR v2', - name: '.elser_model_2', + model_id: '.elser_model_2', version: 2, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], }, { arch: 'amd64', config: { input: { field_names: ['text_field'] } }, description: 'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64', - name: '.elser_model_2_linux-x86_64', + model_id: '.elser_model_2_linux-x86_64', os: 'Linux', recommended: true, version: 2, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], + }, + { + config: { input: { field_names: ['text_field'] } }, + description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + model_id: '.multilingual-e5-small', + default: true, + version: 1, + modelName: 'e5', + license: 'MIT', + type: ['pytorch', 'text_embedding'], + }, + { + arch: 'amd64', + config: { input: { field_names: ['text_field'] } }, + description: + 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + model_id: '.multilingual-e5-small_linux-x86_64', + os: 'Linux', + recommended: true, + version: 1, + modelName: 'e5', + license: 'MIT', + type: ['pytorch', 'text_embedding'], }, ]); }); @@ -105,23 +134,51 @@ describe('modelsProvider', () => { config: { input: { field_names: ['text_field'] } }, description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)', hidden: true, - name: '.elser_model_1', + model_id: '.elser_model_1', version: 1, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], }, { config: { input: { field_names: ['text_field'] } }, recommended: true, description: 'Elastic Learned Sparse EncodeR v2', - name: '.elser_model_2', + model_id: '.elser_model_2', version: 2, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], }, { arch: 'amd64', config: { input: { field_names: ['text_field'] } }, description: 'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64', - name: '.elser_model_2_linux-x86_64', + model_id: '.elser_model_2_linux-x86_64', os: 'Linux', version: 2, + modelName: 'elser', + type: ['elastic', 'pytorch', 'text_expansion'], + }, + { + config: { input: { field_names: ['text_field'] } }, + description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)', + model_id: '.multilingual-e5-small', + recommended: true, + version: 1, + modelName: 'e5', + type: ['pytorch', 'text_embedding'], + license: 'MIT', + }, + { + arch: 'amd64', + config: { input: { field_names: ['text_field'] } }, + description: + 'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64', + model_id: '.multilingual-e5-small_linux-x86_64', + os: 'Linux', + version: 1, + modelName: 'e5', + type: ['pytorch', 'text_embedding'], + license: 'MIT', }, ]); }); @@ -130,7 +187,7 @@ describe('modelsProvider', () => { describe('getELSER', () => { test('provides a recommended definition by default', async () => { const result = await modelService.getELSER(); - expect(result.name).toEqual('.elser_model_2_linux-x86_64'); + expect(result.model_id).toEqual('.elser_model_2_linux-x86_64'); }); test('provides a default version if there is no recommended', async () => { @@ -156,17 +213,50 @@ describe('modelsProvider', () => { }); const result = await modelService.getELSER(); - expect(result.name).toEqual('.elser_model_2'); + expect(result.model_id).toEqual('.elser_model_2'); }); test('provides the requested version', async () => { const result = await modelService.getELSER({ version: 1 }); - expect(result.name).toEqual('.elser_model_1'); + expect(result.model_id).toEqual('.elser_model_1'); }); test('provides the requested version of a recommended architecture', async () => { const result = await modelService.getELSER({ version: 2 }); - expect(result.name).toEqual('.elser_model_2_linux-x86_64'); + expect(result.model_id).toEqual('.elser_model_2_linux-x86_64'); + }); + }); + + describe('getCuratedModelConfig', () => { + test('provides a recommended definition by default', async () => { + const result = await modelService.getCuratedModelConfig('e5'); + expect(result.model_id).toEqual('.multilingual-e5-small_linux-x86_64'); + }); + + test('provides a default version if there is no recommended', async () => { + mockCloud.cloudId = undefined; + (mockClient.asInternalUser.transport.request as jest.Mock).mockResolvedValueOnce({ + _nodes: { + total: 1, + successful: 1, + failed: 0, + }, + cluster_name: 'default', + nodes: { + yYmqBqjpQG2rXsmMSPb9pQ: { + name: 'node-0', + roles: ['ml'], + attributes: {}, + os: { + name: 'Mac OS X', + arch: 'aarch64', + }, + }, + }, + }); + + const result = await modelService.getCuratedModelConfig('e5'); + expect(result.model_id).toEqual('.multilingual-e5-small'); }); }); }); diff --git a/x-pack/plugins/ml/server/models/model_management/models_provider.ts b/x-pack/plugins/ml/server/models/model_management/models_provider.ts index db8b0b0d6503..6d3ba51a9b76 100644 --- a/x-pack/plugins/ml/server/models/model_management/models_provider.ts +++ b/x-pack/plugins/ml/server/models/model_management/models_provider.ts @@ -19,10 +19,11 @@ import type { } from '@elastic/elasticsearch/lib/api/types'; import { ELASTIC_MODEL_DEFINITIONS, - type GetElserOptions, + type GetModelDownloadConfigOptions, type ModelDefinitionResponse, } from '@kbn/ml-trained-models-utils'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; +import type { ElasticCuratedModelName } from '@kbn/ml-trained-models-utils'; import type { PipelineDefinition } from '../../../common/types/trained_models'; import type { MlClient } from '../../lib/ml_client'; import type { MLSavedObjectService } from '../../saved_objects'; @@ -52,6 +53,8 @@ interface ModelMapResult { error: null | any; } +export type GetCuratedModelConfigParams = Parameters; + export class ModelsProvider { private _transforms?: TransformGetTransformTransformSummary[]; @@ -410,8 +413,6 @@ export class ModelsProvider { } throw error; } - - return result; } /** @@ -460,17 +461,17 @@ export class ModelsProvider { const modelDefinitionMap = new Map(); - for (const [name, def] of Object.entries(ELASTIC_MODEL_DEFINITIONS)) { + for (const [modelId, def] of Object.entries(ELASTIC_MODEL_DEFINITIONS)) { const recommended = (isCloud && def.os === 'Linux' && def.arch === 'amd64') || (sameArch && !!def?.os && def?.os === osName && def?.arch === arch); - const { modelName, ...rest } = def; + const { modelName } = def; const modelDefinitionResponse = { - ...rest, + ...def, ...(recommended ? { recommended } : {}), - name, + model_id: modelId, }; if (modelDefinitionMap.has(modelName)) { @@ -494,14 +495,19 @@ export class ModelsProvider { } /** - * Provides an ELSER model name and configuration for download based on the current cluster architecture. - * The current default version is 2. If running on Cloud it returns the Linux x86_64 optimized version. - * If any of the ML nodes run a different OS rather than Linux, or the CPU architecture isn't x86_64, - * a portable version of the model is returned. + * Provides an appropriate model ID and configuration for download based on the current cluster architecture. + * + * @param modelName + * @param options + * @returns */ - async getELSER(options?: GetElserOptions): Promise | never { - const modelDownloadConfig = await this.getModelDownloads(); - + async getCuratedModelConfig( + modelName: ElasticCuratedModelName, + options?: GetModelDownloadConfigOptions + ): Promise | never { + const modelDownloadConfig = (await this.getModelDownloads()).filter( + (model) => model.modelName === modelName + ); let requestedModel: ModelDefinitionResponse | undefined; let recommendedModel: ModelDefinitionResponse | undefined; let defaultModel: ModelDefinitionResponse | undefined; @@ -527,6 +533,18 @@ export class ModelsProvider { return requestedModel || recommendedModel || defaultModel!; } + /** + * Provides an ELSER model name and configuration for download based on the current cluster architecture. + * The current default version is 2. If running on Cloud it returns the Linux x86_64 optimized version. + * If any of the ML nodes run a different OS rather than Linux, or the CPU architecture isn't x86_64, + * a portable version of the model is returned. + */ + async getELSER( + options?: GetModelDownloadConfigOptions + ): Promise | never { + return await this.getCuratedModelConfig('elser', options); + } + /** * Puts the requested ELSER model into elasticsearch, triggering elasticsearch to download the model. * Assigns the model to the * space. @@ -535,7 +553,7 @@ export class ModelsProvider { */ async installElasticModel(modelId: string, mlSavedObjectService: MLSavedObjectService) { const availableModels = await this.getModelDownloads(); - const model = availableModels.find((m) => m.name === modelId); + const model = availableModels.find((m) => m.model_id === modelId); if (!model) { throw Boom.notFound('Model not found'); } @@ -556,7 +574,7 @@ export class ModelsProvider { } const putResponse = await this._mlClient.putTrainedModel({ - model_id: model.name, + model_id: model.model_id, body: model.config, }); diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index 302a8b2c89bb..b951c23ed4d8 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -6,49 +6,43 @@ */ import type { IScopedClusterClient } from '@kbn/core/server'; -import type { DataViewsService } from '@kbn/data-views-plugin/common'; +import type { RuntimeField } from '@kbn/data-views-plugin/common'; import type { Field, Aggregation } from '@kbn/ml-anomaly-utils'; import { JOB_MAP_NODE_TYPES, type DeleteDataFrameAnalyticsWithIndexStatus, } from '@kbn/ml-data-frame-analytics-utils'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; +import { dataViewCreateQuerySchema } from '@kbn/ml-data-view-utils/schemas/api_create_query_schema'; +import { createDataViewFn } from '@kbn/ml-data-view-utils/actions/create'; +import { deleteDataViewFn } from '@kbn/ml-data-view-utils/actions/delete'; + import { type MlFeatures, ML_INTERNAL_BASE_PATH } from '../../common/constants/app'; import { wrapError } from '../client/error_wrapper'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; import type { RouteInitialization } from '../types'; import { - dataAnalyticsJobConfigSchema, - dataAnalyticsJobUpdateSchema, - dataAnalyticsEvaluateSchema, - dataAnalyticsExplainSchema, - analyticsIdSchema, - analyticsMapQuerySchema, + dataFrameAnalyticsJobConfigSchema, + dataFrameAnalyticsJobUpdateSchema, + dataFrameAnalyticsEvaluateSchema, + dataFrameAnalyticsExplainSchema, + dataFrameAnalyticsIdSchema, + dataFrameAnalyticsMapQuerySchema, stopsDataFrameAnalyticsJobQuerySchema, deleteDataFrameAnalyticsJobSchema, - jobsExistSchema, - analyticsQuerySchema, - analyticsNewJobCapsParamsSchema, - analyticsNewJobCapsQuerySchema, -} from './schemas/data_analytics_schema'; + dataFrameAnalyticsJobsExistSchema, + dataFrameAnalyticsQuerySchema, + dataFrameAnalyticsNewJobCapsParamsSchema, + dataFrameAnalyticsNewJobCapsQuerySchema, + type PutDataFrameAnalyticsResponseSchema, +} from './schemas/data_frame_analytics_schema'; import type { ExtendAnalyticsMapArgs } from '../models/data_frame_analytics/types'; -import { DataViewHandler } from '../models/data_frame_analytics/index_patterns'; import { AnalyticsManager } from '../models/data_frame_analytics/analytics_manager'; import { validateAnalyticsJob } from '../models/data_frame_analytics/validation'; import { fieldServiceProvider } from '../models/job_service/new_job_caps/field_service'; import { getAuthorizationHeader } from '../lib/request_authorization'; import type { MlClient } from '../lib/ml_client'; -function getDataViewId(dataViewsService: DataViewsService, patternName: string) { - const iph = new DataViewHandler(dataViewsService); - return iph.getDataViewId(patternName); -} - -function deleteDestDataViewById(dataViewsService: DataViewsService, dataViewId: string) { - const iph = new DataViewHandler(dataViewsService); - return iph.deleteDataViewById(dataViewId); -} - function getExtendedMap( mlClient: MlClient, client: IScopedClusterClient, @@ -144,7 +138,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - query: analyticsQuerySchema, + query: dataFrameAnalyticsQuerySchema, }, }, }, @@ -185,8 +179,8 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, - query: analyticsQuerySchema, + params: dataFrameAnalyticsIdSchema, + query: dataFrameAnalyticsQuerySchema, }, }, }, @@ -262,7 +256,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, + params: dataFrameAnalyticsIdSchema, }, }, }, @@ -305,29 +299,65 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, - body: dataAnalyticsJobConfigSchema, + params: dataFrameAnalyticsIdSchema, + query: dataViewCreateQuerySchema, + body: dataFrameAnalyticsJobConfigSchema, }, }, }, - routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { - try { + routeGuard.fullLicenseAPIGuard( + async ({ mlClient, request, response, getDataViewsService }) => { const { analyticsId } = request.params; - const body = await mlClient.putDataFrameAnalytics( - { + const { createDataView, timeFieldName } = request.query; + + const fullResponse: PutDataFrameAnalyticsResponseSchema = { + dataFrameAnalyticsJobsCreated: [], + dataFrameAnalyticsJobsErrors: [], + dataViewsCreated: [], + dataViewsErrors: [], + }; + + try { + const resp = await mlClient.putDataFrameAnalytics( + { + id: analyticsId, + // @ts-expect-error @elastic-elasticsearch Data frame types incomplete + body: request.body, + }, + getAuthorizationHeader(request) + ); + + if (resp.id && resp.create_time) { + fullResponse.dataFrameAnalyticsJobsCreated.push({ id: analyticsId }); + } else { + fullResponse.dataFrameAnalyticsJobsErrors.push({ + id: analyticsId, + error: wrapError(resp), + }); + } + } catch (e) { + fullResponse.dataFrameAnalyticsJobsErrors.push({ id: analyticsId, - // @ts-expect-error @elastic-elasticsearch Data frame types incomplete - body: request.body, - }, - getAuthorizationHeader(request) - ); - return response.ok({ - body, - }); - } catch (e) { - return response.customError(wrapError(e)); + error: wrapError(e), + }); + } + + if (createDataView) { + const { dataViewsCreated, dataViewsErrors } = await createDataViewFn({ + dataViewsService: await getDataViewsService(), + dataViewName: request.body.dest.index, + runtimeMappings: request.body.source.runtime_mappings as Record, + timeFieldName, + errorFallbackId: analyticsId, + }); + + fullResponse.dataViewsCreated = dataViewsCreated; + fullResponse.dataViewsErrors = dataViewsErrors; + } + + return response.ok({ body: fullResponse }); } - }) + ) ); /** @@ -352,7 +382,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - body: dataAnalyticsEvaluateSchema, + body: dataFrameAnalyticsEvaluateSchema, }, }, }, @@ -397,7 +427,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - body: dataAnalyticsExplainSchema, + body: dataFrameAnalyticsExplainSchema, }, }, }, @@ -440,7 +470,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, + params: dataFrameAnalyticsIdSchema, query: deleteDataFrameAnalyticsJobSchema, }, }, @@ -449,11 +479,11 @@ export function dataFrameAnalyticsRoutes( async ({ mlClient, client, request, response, getDataViewsService }) => { try { const { analyticsId } = request.params; - const { deleteDestIndex, deleteDestIndexPattern } = request.query; + const { deleteDestIndex, deleteDestDataView } = request.query; let destinationIndex: string | undefined; const analyticsJobDeleted: DeleteDataFrameAnalyticsWithIndexStatus = { success: false }; const destIndexDeleted: DeleteDataFrameAnalyticsWithIndexStatus = { success: false }; - const destIndexPatternDeleted: DeleteDataFrameAnalyticsWithIndexStatus = { + let destDataViewDeleted: DeleteDataFrameAnalyticsWithIndexStatus = { success: false, }; @@ -473,7 +503,7 @@ export function dataFrameAnalyticsRoutes( return response.customError(wrapError(e)); } - if (deleteDestIndex || deleteDestIndexPattern) { + if (deleteDestIndex || deleteDestDataView) { // If user checks box to delete the destinationIndex associated with the job if (destinationIndex && deleteDestIndex) { // Verify if user has privilege to delete the destination index @@ -493,18 +523,12 @@ export function dataFrameAnalyticsRoutes( } } - // Delete the index pattern if there's an index pattern that matches the name of dest index - if (destinationIndex && deleteDestIndexPattern) { - try { - const dataViewsService = await getDataViewsService(); - const dataViewId = await getDataViewId(dataViewsService, destinationIndex); - if (dataViewId) { - await deleteDestDataViewById(dataViewsService, dataViewId); - } - destIndexPatternDeleted.success = true; - } catch (deleteDestIndexPatternError) { - destIndexPatternDeleted.error = deleteDestIndexPatternError; - } + // Delete the data view if there's a data view that matches the name of dest index + if (destinationIndex && deleteDestDataView) { + destDataViewDeleted = await deleteDataViewFn({ + dataViewsService: await getDataViewsService(), + dataViewName: destinationIndex, + }); } } // Grab the target index from the data frame analytics job id @@ -521,7 +545,7 @@ export function dataFrameAnalyticsRoutes( const results = { analyticsJobDeleted, destIndexDeleted, - destIndexPatternDeleted, + destDataViewDeleted, }; return response.ok({ body: results, @@ -555,7 +579,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, + params: dataFrameAnalyticsIdSchema, }, }, }, @@ -597,7 +621,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, + params: dataFrameAnalyticsIdSchema, query: stopsDataFrameAnalyticsJobQuerySchema, }, }, @@ -640,8 +664,8 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, - body: dataAnalyticsJobUpdateSchema, + params: dataFrameAnalyticsIdSchema, + body: dataFrameAnalyticsJobUpdateSchema, }, }, }, @@ -686,7 +710,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, + params: dataFrameAnalyticsIdSchema, }, }, }, @@ -728,7 +752,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - body: jobsExistSchema, + body: dataFrameAnalyticsJobsExistSchema, }, }, }, @@ -785,8 +809,8 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsIdSchema, - query: analyticsMapQuerySchema, + params: dataFrameAnalyticsIdSchema, + query: dataFrameAnalyticsMapQuerySchema, }, }, }, @@ -851,8 +875,8 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - params: analyticsNewJobCapsParamsSchema, - query: analyticsNewJobCapsQuerySchema, + params: dataFrameAnalyticsNewJobCapsParamsSchema, + query: dataFrameAnalyticsNewJobCapsQuerySchema, }, }, }, @@ -906,7 +930,7 @@ export function dataFrameAnalyticsRoutes( version: '1', validate: { request: { - body: dataAnalyticsJobConfigSchema, + body: dataFrameAnalyticsJobConfigSchema, }, }, }, diff --git a/x-pack/plugins/ml/server/routes/schemas/data_analytics_schema.ts b/x-pack/plugins/ml/server/routes/schemas/data_analytics_schema.ts deleted file mode 100644 index 7b67a56fe485..000000000000 --- a/x-pack/plugins/ml/server/routes/schemas/data_analytics_schema.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { runtimeMappingsSchema } from './runtime_mappings_schema'; - -export const dataAnalyticsJobConfigSchema = schema.object({ - description: schema.maybe(schema.string()), - _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), - dest: schema.object({ - index: schema.string(), - results_field: schema.maybe(schema.string()), - }), - source: schema.object({ - index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), - query: schema.maybe(schema.any()), - runtime_mappings: runtimeMappingsSchema, - _source: schema.maybe( - schema.object({ - /** Fields to include in results */ - includes: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), - /** Fields to exclude from results */ - excludes: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), - }) - ), - }), - allow_lazy_start: schema.maybe(schema.boolean()), - analysis: schema.any(), - analyzed_fields: schema.any(), - model_memory_limit: schema.string(), - max_num_threads: schema.maybe(schema.number()), -}); - -export const dataAnalyticsEvaluateSchema = schema.object({ - index: schema.string(), - query: schema.maybe(schema.any()), - evaluation: schema.maybe( - schema.object({ - regression: schema.maybe(schema.any()), - classification: schema.maybe(schema.any()), - outlier_detection: schema.maybe(schema.any()), - }) - ), -}); - -export const dataAnalyticsExplainSchema = schema.object({ - description: schema.maybe(schema.string()), - dest: schema.maybe(schema.any()), - /** Source */ - source: schema.object({ - index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), - query: schema.maybe(schema.any()), - runtime_mappings: runtimeMappingsSchema, - }), - analysis: schema.any(), - analyzed_fields: schema.maybe(schema.any()), - model_memory_limit: schema.maybe(schema.string()), - max_num_threads: schema.maybe(schema.number()), - _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}); - -export const analyticsIdSchema = schema.object({ - /** - * Analytics ID - */ - analyticsId: schema.string(), -}); - -export const analyticsQuerySchema = schema.object({ - /** - * Analytics Query - */ - excludeGenerated: schema.maybe(schema.boolean()), - size: schema.maybe(schema.number()), -}); - -export const deleteDataFrameAnalyticsJobSchema = schema.object({ - /** - * Analytics Destination Index - */ - deleteDestIndex: schema.maybe(schema.boolean()), - deleteDestIndexPattern: schema.maybe(schema.boolean()), -}); - -export const dataAnalyticsJobUpdateSchema = schema.object({ - description: schema.maybe(schema.string()), - model_memory_limit: schema.maybe(schema.string()), - allow_lazy_start: schema.maybe(schema.boolean()), - max_num_threads: schema.maybe(schema.number()), - _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}); - -export const stopsDataFrameAnalyticsJobQuerySchema = schema.object({ - force: schema.maybe(schema.boolean()), -}); - -export const jobsExistSchema = schema.object({ - analyticsIds: schema.arrayOf(schema.string()), - allSpaces: schema.maybe(schema.boolean()), -}); - -export const analyticsMapQuerySchema = schema.maybe( - schema.object({ treatAsRoot: schema.maybe(schema.any()), type: schema.maybe(schema.string()) }) -); - -export const analyticsNewJobCapsParamsSchema = schema.object({ indexPattern: schema.string() }); - -export const analyticsNewJobCapsQuerySchema = schema.maybe( - schema.object({ rollup: schema.maybe(schema.string()) }) -); diff --git a/x-pack/plugins/ml/server/routes/schemas/data_frame_analytics_schema.ts b/x-pack/plugins/ml/server/routes/schemas/data_frame_analytics_schema.ts new file mode 100644 index 000000000000..050722816eeb --- /dev/null +++ b/x-pack/plugins/ml/server/routes/schemas/data_frame_analytics_schema.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import type { CreateDataViewApiResponseSchema } from '@kbn/ml-data-view-utils/types/api_create_response_schema'; + +import { runtimeMappingsSchema } from './runtime_mappings_schema'; + +export const dataFrameAnalyticsJobConfigSchema = schema.object({ + description: schema.maybe(schema.string()), + _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), + dest: schema.object({ + index: schema.string(), + results_field: schema.maybe(schema.string()), + }), + source: schema.object({ + index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), + query: schema.maybe(schema.any()), + runtime_mappings: runtimeMappingsSchema, + _source: schema.maybe( + schema.object({ + /** Fields to include in results */ + includes: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), + /** Fields to exclude from results */ + excludes: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), + }) + ), + }), + allow_lazy_start: schema.maybe(schema.boolean()), + analysis: schema.any(), + analyzed_fields: schema.any(), + model_memory_limit: schema.string(), + max_num_threads: schema.maybe(schema.number()), +}); + +export const dataFrameAnalyticsEvaluateSchema = schema.object({ + index: schema.string(), + query: schema.maybe(schema.any()), + evaluation: schema.maybe( + schema.object({ + regression: schema.maybe(schema.any()), + classification: schema.maybe(schema.any()), + outlier_detection: schema.maybe(schema.any()), + }) + ), +}); + +export const dataFrameAnalyticsExplainSchema = schema.object({ + description: schema.maybe(schema.string()), + dest: schema.maybe(schema.any()), + /** Source */ + source: schema.object({ + index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), + query: schema.maybe(schema.any()), + runtime_mappings: runtimeMappingsSchema, + }), + analysis: schema.any(), + analyzed_fields: schema.maybe(schema.any()), + model_memory_limit: schema.maybe(schema.string()), + max_num_threads: schema.maybe(schema.number()), + _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}); + +export const dataFrameAnalyticsIdSchema = schema.object({ + /** + * Analytics ID + */ + analyticsId: schema.string(), +}); + +export const dataFrameAnalyticsQuerySchema = schema.object({ + /** + * Analytics Query + */ + excludeGenerated: schema.maybe(schema.boolean()), + size: schema.maybe(schema.number()), +}); + +export const deleteDataFrameAnalyticsJobSchema = schema.object({ + /** + * Analytics Destination Index + */ + deleteDestIndex: schema.maybe(schema.boolean()), + deleteDestDataView: schema.maybe(schema.boolean()), +}); + +export const dataFrameAnalyticsJobUpdateSchema = schema.object({ + description: schema.maybe(schema.string()), + model_memory_limit: schema.maybe(schema.string()), + allow_lazy_start: schema.maybe(schema.boolean()), + max_num_threads: schema.maybe(schema.number()), + _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}); + +export const stopsDataFrameAnalyticsJobQuerySchema = schema.object({ + force: schema.maybe(schema.boolean()), +}); + +export const dataFrameAnalyticsJobsExistSchema = schema.object({ + analyticsIds: schema.arrayOf(schema.string()), + allSpaces: schema.maybe(schema.boolean()), +}); + +export const dataFrameAnalyticsMapQuerySchema = schema.maybe( + schema.object({ treatAsRoot: schema.maybe(schema.any()), type: schema.maybe(schema.string()) }) +); + +export const dataFrameAnalyticsNewJobCapsParamsSchema = schema.object({ + indexPattern: schema.string(), +}); + +export const dataFrameAnalyticsNewJobCapsQuerySchema = schema.maybe( + schema.object({ rollup: schema.maybe(schema.string()) }) +); + +interface DataFrameAnalyticsJobsCreated { + id: string; +} +interface CreatedError { + id: string; + error: any; +} + +export interface PutDataFrameAnalyticsResponseSchema extends CreateDataViewApiResponseSchema { + dataFrameAnalyticsJobsCreated: DataFrameAnalyticsJobsCreated[]; + dataFrameAnalyticsJobsErrors: CreatedError[]; +} diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index 8095411f911e..34cbaf755c1e 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -29,9 +29,9 @@ import { createIngestPipelineSchema, modelDownloadsQuery, } from './schemas/inference_schema'; -import type { +import { PipelineDefinition, - TrainedModelConfigResponse, + type TrainedModelConfigResponse, } from '../../common/types/trained_models'; import { mlLog } from '../lib/log'; import { forceQuerySchema } from './schemas/anomaly_detectors_schema'; @@ -39,10 +39,9 @@ import { modelsProvider } from '../models/model_management'; export const DEFAULT_TRAINED_MODELS_PAGE_SIZE = 10000; -export function filterForEnabledFeatureModels( - models: TrainedModelConfigResponse[] | estypes.MlTrainedModelConfig[], - enabledFeatures: MlFeatures -) { +export function filterForEnabledFeatureModels< + T extends TrainedModelConfigResponse | estypes.MlTrainedModelConfig +>(models: T[], enabledFeatures: MlFeatures) { let filteredModels = models; if (enabledFeatures.nlp === false) { filteredModels = filteredModels.filter((m) => m.model_type === 'tree_ensemble'); @@ -191,10 +190,38 @@ export function trainedModelsRoutes( mlLog.debug(e); } - const body = filterForEnabledFeatureModels(result, getEnabledFeatures()); + const filteredModels = filterForEnabledFeatureModels(result, getEnabledFeatures()); + + try { + const jobIds = filteredModels + .map((model) => { + const id = model.metadata?.analytics_config?.id; + if (id) { + return `${id}*`; + } + }) + .filter((id) => id !== undefined); + + if (jobIds.length) { + const { data_frame_analytics: jobs } = await mlClient.getDataFrameAnalytics({ + id: jobIds.join(','), + allow_no_match: true, + }); + + filteredModels.forEach((model) => { + const dfaId = model?.metadata?.analytics_config?.id; + if (dfaId !== undefined) { + // if this is a dfa model, set origin_job_exists + model.origin_job_exists = jobs.find((job) => job.id === dfaId) !== undefined; + } + }); + } + } catch (e) { + // Swallow error to prevent blocking trained models result + } return response.ok({ - body, + body: filteredModels, }); } catch (e) { return response.customError(wrapError(e)); diff --git a/x-pack/plugins/ml/server/shared_services/providers/__mocks__/trained_models.ts b/x-pack/plugins/ml/server/shared_services/providers/__mocks__/trained_models.ts index 9af448058ce8..fa37f3d468fc 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/__mocks__/trained_models.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/__mocks__/trained_models.ts @@ -16,7 +16,8 @@ const trainedModelsServiceMock = { deleteTrainedModel: jest.fn(), updateTrainedModelDeployment: jest.fn(), putTrainedModel: jest.fn(), - getELSER: jest.fn().mockResolvedValue({ name: '' }), + getELSER: jest.fn().mockResolvedValue({ model_id: '.elser_model_2' }), + getCuratedModelConfig: jest.fn().mockResolvedValue({ model_id: '.elser_model_2' }), } as jest.Mocked; export const createTrainedModelsProviderMock = () => diff --git a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts index 4a1edbbcb3e4..6b04a3e7580d 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/trained_models.ts @@ -8,7 +8,10 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { KibanaRequest, SavedObjectsClientContract } from '@kbn/core/server'; -import type { GetElserOptions, ModelDefinitionResponse } from '@kbn/ml-trained-models-utils'; +import type { + GetModelDownloadConfigOptions, + ModelDefinitionResponse, +} from '@kbn/ml-trained-models-utils'; import type { MlInferTrainedModelRequest, MlStopTrainedModelDeploymentRequest, @@ -16,6 +19,7 @@ import type { UpdateTrainedModelDeploymentResponse, } from '../../lib/ml_client/types'; import { modelsProvider } from '../../models/model_management'; +import type { GetCuratedModelConfigParams } from '../../models/model_management/models_provider'; import type { GetGuards } from '../shared_services'; export interface TrainedModelsProvider { @@ -47,7 +51,8 @@ export interface TrainedModelsProvider { putTrainedModel( params: estypes.MlPutTrainedModelRequest ): Promise; - getELSER(params?: GetElserOptions): Promise; + getELSER(params?: GetModelDownloadConfigOptions): Promise; + getCuratedModelConfig(...params: GetCuratedModelConfigParams): Promise; }; } @@ -123,7 +128,7 @@ export function getTrainedModelsProvider( return mlClient.putTrainedModel(params); }); }, - async getELSER(params?: GetElserOptions) { + async getELSER(params?: GetModelDownloadConfigOptions) { return await guards .isFullLicense() .hasMlCapabilities(['canGetTrainedModels']) @@ -131,6 +136,14 @@ export function getTrainedModelsProvider( return modelsProvider(scopedClient, mlClient, cloud).getELSER(params); }); }, + async getCuratedModelConfig(...params: GetCuratedModelConfigParams) { + return await guards + .isFullLicense() + .hasMlCapabilities(['canGetTrainedModels']) + .ok(async ({ scopedClient, mlClient }) => { + return modelsProvider(scopedClient, mlClient, cloud).getCuratedModelConfig(...params); + }); + }, }; }, }; diff --git a/x-pack/plugins/ml/tsconfig.json b/x-pack/plugins/ml/tsconfig.json index cca832eee042..f1383ef078c8 100644 --- a/x-pack/plugins/ml/tsconfig.json +++ b/x-pack/plugins/ml/tsconfig.json @@ -96,6 +96,7 @@ "@kbn/ml-runtime-field-utils", "@kbn/ml-date-utils", "@kbn/ml-category-validator", + "@kbn/ml-ui-actions", "@kbn/deeplinks-ml", "@kbn/core-notifications-browser-mocks", "@kbn/unified-field-list", @@ -110,5 +111,7 @@ "@kbn/alerts-as-data-utils", "@kbn/rule-registry-plugin", "@kbn/securitysolution-ecs", + "@kbn/ml-data-view-utils", + "@kbn/ml-creation-wizard-utils", ], } diff --git a/x-pack/plugins/monitoring/server/config.test.ts b/x-pack/plugins/monitoring/server/config.test.ts index 0b4a4e1bb57d..0d6a6b169fc8 100644 --- a/x-pack/plugins/monitoring/server/config.test.ts +++ b/x-pack/plugins/monitoring/server/config.test.ts @@ -22,6 +22,7 @@ describe('config schema', () => { }, "enabled": true, }, + "enabled": true, "kibana": Object { "collection": Object { "enabled": true, @@ -66,7 +67,7 @@ describe('config schema', () => { "logFetchCount": 10, "logQueries": false, "maxIdleSockets": 256, - "maxSockets": Infinity, + "maxSockets": 800, "pingTimeout": "PT30S", "requestHeadersWhitelist": Array [ "authorization", diff --git a/x-pack/plugins/monitoring/server/config.ts b/x-pack/plugins/monitoring/server/config.ts index 70253f6d4690..e5670bda2c82 100644 --- a/x-pack/plugins/monitoring/server/config.ts +++ b/x-pack/plugins/monitoring/server/config.ts @@ -82,6 +82,7 @@ export const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: true }), }), }), + enabled: schema.boolean({ defaultValue: true }), }); export class MonitoringElasticsearchConfig extends ElasticsearchConfig { diff --git a/x-pack/plugins/notifications/README.md b/x-pack/plugins/notifications/README.mdx similarity index 100% rename from x-pack/plugins/notifications/README.md rename to x-pack/plugins/notifications/README.mdx diff --git a/x-pack/plugins/observability/common/custom_threshold_rule/constants.ts b/x-pack/plugins/observability/common/custom_threshold_rule/constants.ts deleted file mode 100644 index 7f7c3a5bcbb3..000000000000 --- a/x-pack/plugins/observability/common/custom_threshold_rule/constants.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const METRIC_EXPLORER_AGGREGATIONS = [ - 'avg', - 'max', - 'min', - 'cardinality', - 'count', - 'sum', -] as const; - -export const CUSTOM_AGGREGATOR = 'custom'; diff --git a/x-pack/plugins/observability/common/custom_threshold_rule/get_view_in_app_url.ts b/x-pack/plugins/observability/common/custom_threshold_rule/get_view_in_app_url.ts new file mode 100644 index 000000000000..658d1debe0a9 --- /dev/null +++ b/x-pack/plugins/observability/common/custom_threshold_rule/get_view_in_app_url.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; +import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; +import type { TimeRange } from '@kbn/es-query'; +import type { LocatorPublic } from '@kbn/share-plugin/common'; +import type { CustomThresholdExpressionMetric } from './types'; + +export const getViewInAppUrl = ( + metrics: CustomThresholdExpressionMetric[], + startedAt?: string, + logExplorerLocator?: LocatorPublic, + filter?: string, + dataViewId?: string, + endedAt?: string +) => { + if (!logExplorerLocator) return ''; + + let timeRange: TimeRange | undefined; + if (startedAt) { + timeRange = getPaddedAlertTimeRange(startedAt, endedAt); + timeRange.to = endedAt ? timeRange.to : 'now'; + } + + const query = { + query: '', + language: 'kuery', + }; + const isOneCountConditionWithFilter = + metrics.length === 1 && metrics[0].aggType === 'count' && metrics[0].filter; + if (filter && isOneCountConditionWithFilter) { + query.query = `${filter} and ${metrics[0].filter}`; + } else if (isOneCountConditionWithFilter) { + query.query = metrics[0].filter!; + } else if (filter) { + query.query = filter; + } + + return logExplorerLocator?.getRedirectUrl({ + dataset: dataViewId, + timeRange, + query, + }); +}; diff --git a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts index 40d569152d1a..7668e19dc390 100644 --- a/x-pack/plugins/observability/common/custom_threshold_rule/types.ts +++ b/x-pack/plugins/observability/common/custom_threshold_rule/types.ts @@ -8,7 +8,6 @@ import * as rt from 'io-ts'; import { SerializedSearchSourceFields } from '@kbn/data-plugin/common'; import { TimeUnitChar } from '../utils/formatters/duration'; -import { CUSTOM_AGGREGATOR } from './constants'; export const ThresholdFormatterTypeRT = rt.keyof({ abbreviatedNumber: null, @@ -84,7 +83,6 @@ export interface CustomThresholdExpressionMetric { } export interface CustomMetricExpressionParams extends BaseMetricExpressionParams { - aggType: typeof CUSTOM_AGGREGATOR; metrics: CustomThresholdExpressionMetric[]; equation?: string; label?: string; diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts index f8f032f93bda..3a86e264095b 100644 --- a/x-pack/plugins/observability/common/index.ts +++ b/x-pack/plugins/observability/common/index.ts @@ -41,10 +41,13 @@ export { enableCriticalPath, syntheticsThrottlingEnabled, apmEnableProfilingIntegration, - profilingUseLegacyFlamegraphAPI, profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, + profilingUseLegacyCo2Calculation, + profilingPervCPUWattArm64, + profilingAWSCostDiscountRate, + profilingCostPervCPUPerHour, } from './ui_settings_keys'; export { diff --git a/x-pack/plugins/observability/common/ui_settings_keys.ts b/x-pack/plugins/observability/common/ui_settings_keys.ts index 2a9471644609..5745882055ca 100644 --- a/x-pack/plugins/observability/common/ui_settings_keys.ts +++ b/x-pack/plugins/observability/common/ui_settings_keys.ts @@ -27,7 +27,10 @@ export const apmEnableContinuousRollups = 'observability:apmEnableContinuousRoll export const syntheticsThrottlingEnabled = 'observability:syntheticsThrottlingEnabled'; export const enableLegacyUptimeApp = 'observability:enableLegacyUptimeApp'; export const apmEnableProfilingIntegration = 'observability:apmEnableProfilingIntegration'; -export const profilingUseLegacyFlamegraphAPI = 'observability:profilingUseLegacyFlamegraphAPI'; -export const profilingPerCoreWatt = 'observability:profilingPerCoreWatt'; +export const profilingPervCPUWattX86 = 'observability:profilingPerVCPUWattX86'; +export const profilingPervCPUWattArm64 = 'observability:profilingPervCPUWattArm64'; export const profilingCo2PerKWH = 'observability:profilingCo2PerKWH'; export const profilingDatacenterPUE = 'observability:profilingDatacenterPUE'; +export const profilingUseLegacyCo2Calculation = 'observability:profilingUseLegacyCo2Calculation'; +export const profilingAWSCostDiscountRate = 'observability:profilingAWSCostDiscountRate'; +export const profilingCostPervCPUPerHour = 'observability:profilingCostPervCPUPerHour'; diff --git a/x-pack/plugins/observability/docs/openapi/slo/bundled.json b/x-pack/plugins/observability/docs/openapi/slo/bundled.json index fbc6c0bb2e52..ff366afc2ff1 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/bundled.json +++ b/x-pack/plugins/observability/docs/openapi/slo/bundled.json @@ -143,7 +143,7 @@ { "name": "page", "in": "query", - "description": "The page to use for pagination, must be greater or equal than 1", + "description": "The page number to return", "schema": { "type": "integer", "default": 1 @@ -153,7 +153,7 @@ { "name": "perPage", "in": "query", - "description": "Number of SLOs returned by page", + "description": "The number of SLOs to return per page", "schema": { "type": "integer", "default": 25, @@ -280,7 +280,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/slo_with_summary_response" + "$ref": "#/components/schemas/slo_response" } } } @@ -361,7 +361,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/slo_definition_response" + "$ref": "#/components/schemas/slo_response" } } } @@ -605,79 +605,6 @@ } } }, - "/s/{spaceId}/api/observability/slos/{sloId}/_reset": { - "post": { - "summary": "Resets an SLO.", - "operationId": "resetSloOp", - "description": "You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", - "tags": [ - "slo" - ], - "parameters": [ - { - "$ref": "#/components/parameters/kbn_xsrf" - }, - { - "$ref": "#/components/parameters/space_id" - }, - { - "$ref": "#/components/parameters/slo_id" - } - ], - "responses": { - "204": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/slo_definition_response" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/400_response" - } - } - } - }, - "401": { - "description": "Unauthorized response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/401_response" - } - } - } - }, - "403": { - "description": "Unauthorized response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/403_response" - } - } - } - }, - "404": { - "description": "Not found response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/404_response" - } - } - } - } - } - } - }, "/s/{spaceId}/internal/observability/slos/_historical_summary": { "post": { "summary": "Retrieves the historical summary for a list of SLOs", @@ -748,104 +675,6 @@ } } }, - "/s/{spaceId}/internal/observability/slos/_definitions": { - "get": { - "summary": "Get the SLO definitions", - "operationId": "getDefinitionsOp", - "description": "You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges.\n", - "tags": [ - "slo" - ], - "parameters": [ - { - "$ref": "#/components/parameters/kbn_xsrf" - }, - { - "$ref": "#/components/parameters/space_id" - }, - { - "name": "includeOutdatedOnly", - "in": "query", - "description": "Indicates if the API returns only outdated SLO or all SLO definitions", - "schema": { - "type": "boolean" - }, - "example": true - }, - { - "name": "search", - "in": "query", - "description": "Filters the SLOs by name", - "schema": { - "type": "string" - }, - "example": "my service availability" - }, - { - "name": "page", - "in": "query", - "description": "The page to use for pagination, must be greater or equal than 1", - "schema": { - "type": "number" - }, - "example": 1 - }, - { - "name": "perPage", - "in": "query", - "description": "Number of SLOs returned by page", - "schema": { - "type": "integer", - "default": 100, - "maximum": 1000 - }, - "example": 100 - } - ], - "responses": { - "200": { - "description": "Successful request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/find_slo_definitions_response" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/400_response" - } - } - } - }, - "401": { - "description": "Unauthorized response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/401_response" - } - } - } - }, - "403": { - "description": "Unauthorized response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/403_response" - } - } - } - } - } - } - }, "/s/{spaceId}/api/observability/slos/_delete_instances": { "post": { "summary": "Batch delete rollup and summary data for the matching list of sloId and instanceId", @@ -924,7 +753,8 @@ "apiKeyAuth": { "type": "apiKey", "in": "header", - "name": "ApiKey" + "name": "Authorization", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" } }, "parameters": { @@ -1757,7 +1587,7 @@ } } }, - "slo_with_summary_response": { + "slo_response": { "title": "SLO response", "type": "object", "required": [ @@ -1776,8 +1606,7 @@ "instanceId", "tags", "createdAt", - "updatedAt", - "version" + "updatedAt" ], "properties": { "id": { @@ -1879,11 +1708,6 @@ "description": "The last update date", "type": "string", "example": "2023-01-12T10:03:19.000Z" - }, - "version": { - "description": "The internal SLO version", - "type": "number", - "example": 2 } } }, @@ -1907,7 +1731,7 @@ "results": { "type": "array", "items": { - "$ref": "#/components/schemas/slo_with_summary_response" + "$ref": "#/components/schemas/slo_response" } } } @@ -2170,126 +1994,6 @@ } } }, - "slo_definition_response": { - "title": "SLO definition response", - "type": "object", - "required": [ - "id", - "name", - "description", - "indicator", - "timeWindow", - "budgetingMethod", - "objective", - "settings", - "revision", - "enabled", - "groupBy", - "tags", - "createdAt", - "updatedAt", - "version" - ], - "properties": { - "id": { - "description": "The identifier of the SLO.", - "type": "string", - "example": "8853df00-ae2e-11ed-90af-09bb6422b258" - }, - "name": { - "description": "The name of the SLO.", - "type": "string", - "example": "My Service SLO" - }, - "description": { - "description": "The description of the SLO.", - "type": "string", - "example": "My SLO description" - }, - "indicator": { - "discriminator": { - "propertyName": "type", - "mapping": { - "sli.apm.transactionErrorRate": "#/components/schemas/indicator_properties_apm_availability", - "sli.kql.custom": "#/components/schemas/indicator_properties_custom_kql", - "sli.apm.transactionDuration": "#/components/schemas/indicator_properties_apm_latency", - "sli.metric.custom": "#/components/schemas/indicator_properties_custom_metric", - "sli.histogram.custom": "#/components/schemas/indicator_properties_histogram", - "sli.metric.timeslice": "#/components/schemas/indicator_properties_timeslice_metric" - } - }, - "oneOf": [ - { - "$ref": "#/components/schemas/indicator_properties_custom_kql" - }, - { - "$ref": "#/components/schemas/indicator_properties_apm_availability" - }, - { - "$ref": "#/components/schemas/indicator_properties_apm_latency" - }, - { - "$ref": "#/components/schemas/indicator_properties_custom_metric" - }, - { - "$ref": "#/components/schemas/indicator_properties_histogram" - }, - { - "$ref": "#/components/schemas/indicator_properties_timeslice_metric" - } - ] - }, - "timeWindow": { - "$ref": "#/components/schemas/time_window" - }, - "budgetingMethod": { - "$ref": "#/components/schemas/budgeting_method" - }, - "objective": { - "$ref": "#/components/schemas/objective" - }, - "settings": { - "$ref": "#/components/schemas/settings" - }, - "revision": { - "description": "The SLO revision", - "type": "number", - "example": 2 - }, - "enabled": { - "description": "Indicate if the SLO is enabled", - "type": "boolean", - "example": true - }, - "groupBy": { - "description": "optional group by field to use to generate an SLO per distinct value", - "type": "string", - "example": "some.field" - }, - "tags": { - "description": "List of tags", - "type": "array", - "items": { - "type": "string" - } - }, - "createdAt": { - "description": "The creation date", - "type": "string", - "example": "2023-01-12T10:03:19.000Z" - }, - "updatedAt": { - "description": "The last update date", - "type": "string", - "example": "2023-01-12T10:03:19.000Z" - }, - "version": { - "description": "The internal SLO version", - "type": "number", - "example": 2 - } - } - }, "historical_summary_request": { "title": "Historical summary request", "type": "object", @@ -2333,31 +2037,6 @@ } } }, - "find_slo_definitions_response": { - "title": "Find SLO definitions response", - "description": "A paginated response of SLO definitions matching the query.\n", - "type": "object", - "properties": { - "page": { - "type": "number", - "example": 2 - }, - "perPage": { - "type": "number", - "example": 100 - }, - "total": { - "type": "number", - "example": 123 - }, - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/slo_definition_response" - } - } - } - }, "delete_slo_instances_request": { "title": "Delete SLO instances request", "description": "The delete SLO instances request takes a list of SLO id and instance id, then delete the rollup and summary data. This API can be used to remove the staled data of an instance SLO that no longer get updated.\n", diff --git a/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml b/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml index c5b75cdaf73c..5aa20726b6a0 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/bundled.yaml @@ -86,14 +86,14 @@ paths: example: 'slo.name:latency* and slo.tags : "prod"' - name: page in: query - description: The page to use for pagination, must be greater or equal than 1 + description: The page number to return schema: type: integer default: 1 example: 1 - name: perPage in: query - description: Number of SLOs returned by page + description: The number of SLOs to return per page schema: type: integer default: 25 @@ -176,7 +176,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/slo_with_summary_response' + $ref: '#/components/schemas/slo_response' '400': description: Bad request content: @@ -224,7 +224,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/slo_definition_response' + $ref: '#/components/schemas/slo_response' '400': description: Bad request content: @@ -365,49 +365,6 @@ paths: application/json: schema: $ref: '#/components/schemas/404_response' - /s/{spaceId}/api/observability/slos/{sloId}/_reset: - post: - summary: Resets an SLO. - operationId: resetSloOp - description: | - You must have the `write` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. - tags: - - slo - parameters: - - $ref: '#/components/parameters/kbn_xsrf' - - $ref: '#/components/parameters/space_id' - - $ref: '#/components/parameters/slo_id' - responses: - '204': - description: Successful request - content: - application/json: - schema: - $ref: '#/components/schemas/slo_definition_response' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/400_response' - '401': - description: Unauthorized response - content: - application/json: - schema: - $ref: '#/components/schemas/401_response' - '403': - description: Unauthorized response - content: - application/json: - schema: - $ref: '#/components/schemas/403_response' - '404': - description: Not found response - content: - application/json: - schema: - $ref: '#/components/schemas/404_response' /s/{spaceId}/internal/observability/slos/_historical_summary: post: summary: Retrieves the historical summary for a list of SLOs @@ -450,68 +407,6 @@ paths: application/json: schema: $ref: '#/components/schemas/403_response' - /s/{spaceId}/internal/observability/slos/_definitions: - get: - summary: Get the SLO definitions - operationId: getDefinitionsOp - description: | - You must have the `read` privileges for the **SLOs** feature in the **Observability** section of the Kibana feature privileges. - tags: - - slo - parameters: - - $ref: '#/components/parameters/kbn_xsrf' - - $ref: '#/components/parameters/space_id' - - name: includeOutdatedOnly - in: query - description: Indicates if the API returns only outdated SLO or all SLO definitions - schema: - type: boolean - example: true - - name: search - in: query - description: Filters the SLOs by name - schema: - type: string - example: my service availability - - name: page - in: query - description: The page to use for pagination, must be greater or equal than 1 - schema: - type: number - example: 1 - - name: perPage - in: query - description: Number of SLOs returned by page - schema: - type: integer - default: 100 - maximum: 1000 - example: 100 - responses: - '200': - description: Successful request - content: - application/json: - schema: - $ref: '#/components/schemas/find_slo_definitions_response' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/400_response' - '401': - description: Unauthorized response - content: - application/json: - schema: - $ref: '#/components/schemas/401_response' - '403': - description: Unauthorized response - content: - application/json: - schema: - $ref: '#/components/schemas/403_response' /s/{spaceId}/api/observability/slos/_delete_instances: post: summary: Batch delete rollup and summary data for the matching list of sloId and instanceId @@ -560,7 +455,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' parameters: kbn_xsrf: schema: @@ -1207,7 +1103,7 @@ components: example: 0.9836 errorBudget: $ref: '#/components/schemas/error_budget' - slo_with_summary_response: + slo_response: title: SLO response type: object required: @@ -1227,7 +1123,6 @@ components: - tags - createdAt - updatedAt - - version properties: id: description: The identifier of the SLO. @@ -1297,10 +1192,6 @@ components: description: The last update date type: string example: '2023-01-12T10:03:19.000Z' - version: - description: The internal SLO version - type: number - example: 2 find_slo_response: title: Find SLO response description: | @@ -1319,7 +1210,7 @@ components: results: type: array items: - $ref: '#/components/schemas/slo_with_summary_response' + $ref: '#/components/schemas/slo_response' 400_response: title: Bad request type: object @@ -1495,92 +1386,6 @@ components: type: array items: type: string - slo_definition_response: - title: SLO definition response - type: object - required: - - id - - name - - description - - indicator - - timeWindow - - budgetingMethod - - objective - - settings - - revision - - enabled - - groupBy - - tags - - createdAt - - updatedAt - - version - properties: - id: - description: The identifier of the SLO. - type: string - example: 8853df00-ae2e-11ed-90af-09bb6422b258 - name: - description: The name of the SLO. - type: string - example: My Service SLO - description: - description: The description of the SLO. - type: string - example: My SLO description - indicator: - discriminator: - propertyName: type - mapping: - sli.apm.transactionErrorRate: '#/components/schemas/indicator_properties_apm_availability' - sli.kql.custom: '#/components/schemas/indicator_properties_custom_kql' - sli.apm.transactionDuration: '#/components/schemas/indicator_properties_apm_latency' - sli.metric.custom: '#/components/schemas/indicator_properties_custom_metric' - sli.histogram.custom: '#/components/schemas/indicator_properties_histogram' - sli.metric.timeslice: '#/components/schemas/indicator_properties_timeslice_metric' - oneOf: - - $ref: '#/components/schemas/indicator_properties_custom_kql' - - $ref: '#/components/schemas/indicator_properties_apm_availability' - - $ref: '#/components/schemas/indicator_properties_apm_latency' - - $ref: '#/components/schemas/indicator_properties_custom_metric' - - $ref: '#/components/schemas/indicator_properties_histogram' - - $ref: '#/components/schemas/indicator_properties_timeslice_metric' - timeWindow: - $ref: '#/components/schemas/time_window' - budgetingMethod: - $ref: '#/components/schemas/budgeting_method' - objective: - $ref: '#/components/schemas/objective' - settings: - $ref: '#/components/schemas/settings' - revision: - description: The SLO revision - type: number - example: 2 - enabled: - description: Indicate if the SLO is enabled - type: boolean - example: true - groupBy: - description: optional group by field to use to generate an SLO per distinct value - type: string - example: some.field - tags: - description: List of tags - type: array - items: - type: string - createdAt: - description: The creation date - type: string - example: '2023-01-12T10:03:19.000Z' - updatedAt: - description: The last update date - type: string - example: '2023-01-12T10:03:19.000Z' - version: - description: The internal SLO version - type: number - example: 2 historical_summary_request: title: Historical summary request type: object @@ -1611,25 +1416,6 @@ components: example: 0.9836 errorBudget: $ref: '#/components/schemas/error_budget' - find_slo_definitions_response: - title: Find SLO definitions response - description: | - A paginated response of SLO definitions matching the query. - type: object - properties: - page: - type: number - example: 2 - perPage: - type: number - example: 100 - total: - type: number - example: 123 - results: - type: array - items: - $ref: '#/components/schemas/slo_definition_response' delete_slo_instances_request: title: Delete SLO instances request description: | diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_definitions_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_definitions_response.yaml deleted file mode 100644 index 274bdc7016a0..000000000000 --- a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_definitions_response.yaml +++ /dev/null @@ -1,18 +0,0 @@ -title: Find SLO definitions response -description: > - A paginated response of SLO definitions matching the query. -type: object -properties: - page: - type: number - example: 2 - perPage: - type: number - example: 100 - total: - type: number - example: 123 - results: - type: array - items: - $ref: 'slo_definition_response.yaml' \ No newline at end of file diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_response.yaml index b94aa6e6dc1c..36a701efa34f 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_response.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/find_slo_response.yaml @@ -15,4 +15,4 @@ properties: results: type: array items: - $ref: 'slo_with_summary_response.yaml' \ No newline at end of file + $ref: 'slo_response.yaml' \ No newline at end of file diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_definition_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_definition_response.yaml deleted file mode 100644 index 0b4ffa774d10..000000000000 --- a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_definition_response.yaml +++ /dev/null @@ -1,85 +0,0 @@ -title: SLO definition response -type: object -required: - - id - - name - - description - - indicator - - timeWindow - - budgetingMethod - - objective - - settings - - revision - - enabled - - groupBy - - tags - - createdAt - - updatedAt - - version -properties: - id: - description: The identifier of the SLO. - type: string - example: 8853df00-ae2e-11ed-90af-09bb6422b258 - name: - description: The name of the SLO. - type: string - example: My Service SLO - description: - description: The description of the SLO. - type: string - example: My SLO description - indicator: - discriminator: - propertyName: type - mapping: - sli.apm.transactionErrorRate: './indicator_properties_apm_availability.yaml' - sli.kql.custom: './indicator_properties_custom_kql.yaml' - sli.apm.transactionDuration: './indicator_properties_apm_latency.yaml' - sli.metric.custom: './indicator_properties_custom_metric.yaml' - sli.histogram.custom: './indicator_properties_histogram.yaml' - sli.metric.timeslice: './indicator_properties_timeslice_metric.yaml' - oneOf: - - $ref: "indicator_properties_custom_kql.yaml" - - $ref: "indicator_properties_apm_availability.yaml" - - $ref: "indicator_properties_apm_latency.yaml" - - $ref: "indicator_properties_custom_metric.yaml" - - $ref: "indicator_properties_histogram.yaml" - - $ref: "indicator_properties_timeslice_metric.yaml" - timeWindow: - $ref: "time_window.yaml" - budgetingMethod: - $ref: "budgeting_method.yaml" - objective: - $ref: "objective.yaml" - settings: - $ref: "settings.yaml" - revision: - description: The SLO revision - type: number - example: 2 - enabled: - description: Indicate if the SLO is enabled - type: boolean - example: true - groupBy: - description: optional group by field to use to generate an SLO per distinct value - type: string - example: "some.field" - tags: - description: List of tags - type: array - items: - type: string - createdAt: - description: The creation date - type: string - example: "2023-01-12T10:03:19.000Z" - updatedAt: - description: The last update date - type: string - example: "2023-01-12T10:03:19.000Z" - version: - description: The internal SLO version - type: number - example: 2 \ No newline at end of file diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_response.yaml new file mode 100644 index 000000000000..bd58e88c7b64 --- /dev/null +++ b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_response.yaml @@ -0,0 +1,88 @@ +title: SLO response +type: object +required: + - id + - name + - description + - indicator + - timeWindow + - budgetingMethod + - objective + - settings + - revision + - summary + - enabled + - groupBy + - instanceId + - tags + - createdAt + - updatedAt +properties: + id: + description: The identifier of the SLO. + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + name: + description: The name of the SLO. + type: string + example: My Service SLO + description: + description: The description of the SLO. + type: string + example: My SLO description + indicator: + discriminator: + propertyName: type + mapping: + sli.apm.transactionErrorRate: './indicator_properties_apm_availability.yaml' + sli.kql.custom: './indicator_properties_custom_kql.yaml' + sli.apm.transactionDuration: './indicator_properties_apm_latency.yaml' + sli.metric.custom: './indicator_properties_custom_metric.yaml' + sli.histogram.custom: './indicator_properties_histogram.yaml' + sli.metric.timeslice: './indicator_properties_timeslice_metric.yaml' + oneOf: + - $ref: "indicator_properties_custom_kql.yaml" + - $ref: "indicator_properties_apm_availability.yaml" + - $ref: "indicator_properties_apm_latency.yaml" + - $ref: "indicator_properties_custom_metric.yaml" + - $ref: "indicator_properties_histogram.yaml" + - $ref: "indicator_properties_timeslice_metric.yaml" + timeWindow: + $ref: "time_window.yaml" + budgetingMethod: + $ref: "budgeting_method.yaml" + objective: + $ref: "objective.yaml" + settings: + $ref: "settings.yaml" + revision: + description: The SLO revision + type: number + example: 2 + summary: + $ref: "summary.yaml" + enabled: + description: Indicate if the SLO is enabled + type: boolean + example: true + groupBy: + description: optional group by field to use to generate an SLO per distinct value + type: string + example: "some.field" + instanceId: + description: the value derived from the groupBy field, if present, otherwise '*' + type: string + example: 'host-abcde' + tags: + description: List of tags + type: array + items: + type: string + createdAt: + description: The creation date + type: string + example: "2023-01-12T10:03:19.000Z" + updatedAt: + description: The last update date + type: string + example: "2023-01-12T10:03:19.000Z" diff --git a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_with_summary_response.yaml b/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_with_summary_response.yaml deleted file mode 100644 index df8e35996feb..000000000000 --- a/x-pack/plugins/observability/docs/openapi/slo/components/schemas/slo_with_summary_response.yaml +++ /dev/null @@ -1,93 +0,0 @@ -title: SLO response -type: object -required: - - id - - name - - description - - indicator - - timeWindow - - budgetingMethod - - objective - - settings - - revision - - summary - - enabled - - groupBy - - instanceId - - tags - - createdAt - - updatedAt - - version -properties: - id: - description: The identifier of the SLO. - type: string - example: 8853df00-ae2e-11ed-90af-09bb6422b258 - name: - description: The name of the SLO. - type: string - example: My Service SLO - description: - description: The description of the SLO. - type: string - example: My SLO description - indicator: - discriminator: - propertyName: type - mapping: - sli.apm.transactionErrorRate: './indicator_properties_apm_availability.yaml' - sli.kql.custom: './indicator_properties_custom_kql.yaml' - sli.apm.transactionDuration: './indicator_properties_apm_latency.yaml' - sli.metric.custom: './indicator_properties_custom_metric.yaml' - sli.histogram.custom: './indicator_properties_histogram.yaml' - sli.metric.timeslice: './indicator_properties_timeslice_metric.yaml' - oneOf: - - $ref: "indicator_properties_custom_kql.yaml" - - $ref: "indicator_properties_apm_availability.yaml" - - $ref: "indicator_properties_apm_latency.yaml" - - $ref: "indicator_properties_custom_metric.yaml" - - $ref: "indicator_properties_histogram.yaml" - - $ref: "indicator_properties_timeslice_metric.yaml" - timeWindow: - $ref: "time_window.yaml" - budgetingMethod: - $ref: "budgeting_method.yaml" - objective: - $ref: "objective.yaml" - settings: - $ref: "settings.yaml" - revision: - description: The SLO revision - type: number - example: 2 - summary: - $ref: "summary.yaml" - enabled: - description: Indicate if the SLO is enabled - type: boolean - example: true - groupBy: - description: optional group by field to use to generate an SLO per distinct value - type: string - example: "some.field" - instanceId: - description: the value derived from the groupBy field, if present, otherwise '*' - type: string - example: 'host-abcde' - tags: - description: List of tags - type: array - items: - type: string - createdAt: - description: The creation date - type: string - example: "2023-01-12T10:03:19.000Z" - updatedAt: - description: The last update date - type: string - example: "2023-01-12T10:03:19.000Z" - version: - description: The internal SLO version - type: number - example: 2 \ No newline at end of file diff --git a/x-pack/plugins/observability/docs/openapi/slo/entrypoint.yaml b/x-pack/plugins/observability/docs/openapi/slo/entrypoint.yaml index b951be467e00..910f795aa40a 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/entrypoint.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/entrypoint.yaml @@ -20,15 +20,11 @@ paths: "/s/{spaceId}/api/observability/slos/{sloId}": $ref: "paths/s@{spaceid}@api@slos@{sloid}.yaml" "/s/{spaceId}/api/observability/slos/{sloId}/enable": - $ref: "paths/s@{spaceid}@api@slos@{sloid}@enable.yaml" + $ref: "paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml" "/s/{spaceId}/api/observability/slos/{sloId}/disable": - $ref: "paths/s@{spaceid}@api@slos@{sloid}@disable.yaml" - "/s/{spaceId}/api/observability/slos/{sloId}/_reset": - $ref: "paths/s@{spaceid}@api@slos@{sloid}@_reset.yaml" + $ref: "paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml" "/s/{spaceId}/internal/observability/slos/_historical_summary": $ref: "paths/s@{spaceid}@api@slos@_historical_summary.yaml" - "/s/{spaceId}/internal/observability/slos/_definitions": - $ref: "paths/s@{spaceid}@api@slos@_definitions.yaml" "/s/{spaceId}/api/observability/slos/_delete_instances": $ref: "paths/s@{spaceid}@api@slos@_delete_instances.yaml" components: @@ -39,7 +35,8 @@ components: apiKeyAuth: type: apiKey in: header - name: ApiKey + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' security: - basicAuth: [] - apiKeyAuth: [] diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml index 782e8fb477f9..b606a0aac05f 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml @@ -68,14 +68,14 @@ get: example: 'slo.name:latency* and slo.tags : "prod"' - name: page in: query - description: The page to use for pagination, must be greater or equal than 1 + description: The page number to return schema: type: integer default: 1 example: 1 - name: perPage in: query - description: Number of SLOs returned by page + description: The number of SLOs to return per page schema: type: integer default: 25 diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_definitions.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_definitions.yaml deleted file mode 100644 index 508c3cc86f8f..000000000000 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@_definitions.yaml +++ /dev/null @@ -1,62 +0,0 @@ -get: - summary: Get the SLO definitions - operationId: getDefinitionsOp - description: > - You must have the `read` privileges for the **SLOs** feature in the - **Observability** section of the Kibana feature privileges. - tags: - - slo - parameters: - - $ref: ../components/headers/kbn_xsrf.yaml - - $ref: ../components/parameters/space_id.yaml - - name: includeOutdatedOnly - in: query - description: Indicates if the API returns only outdated SLO or all SLO definitions - schema: - type: boolean - example: true - - name: search - in: query - description: Filters the SLOs by name - schema: - type: string - example: 'my service availability' - - name: page - in: query - description: The page to use for pagination, must be greater or equal than 1 - schema: - type: number - example: 1 - - name: perPage - in: query - description: Number of SLOs returned by page - schema: - type: integer - default: 100 - maximum: 1000 - example: 100 - responses: - '200': - description: Successful request - content: - application/json: - schema: - $ref: '../components/schemas/find_slo_definitions_response.yaml' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '../components/schemas/400_response.yaml' - '401': - description: Unauthorized response - content: - application/json: - schema: - $ref: '../components/schemas/401_response.yaml' - '403': - description: Unauthorized response - content: - application/json: - schema: - $ref: '../components/schemas/403_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml index 76d8f0eb640d..a7740b751746 100644 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml +++ b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}.yaml @@ -22,7 +22,7 @@ get: content: application/json: schema: - $ref: '../components/schemas/slo_with_summary_response.yaml' + $ref: '../components/schemas/slo_response.yaml' '400': description: Bad request content: @@ -72,7 +72,7 @@ put: content: application/json: schema: - $ref: '../components/schemas/slo_definition_response.yaml' + $ref: '../components/schemas/slo_response.yaml' '400': description: Bad request content: diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@_reset.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@_reset.yaml deleted file mode 100644 index 6739d3df7832..000000000000 --- a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@_reset.yaml +++ /dev/null @@ -1,43 +0,0 @@ -post: - summary: Resets an SLO. - operationId: resetSloOp - description: > - You must have the `write` privileges for the **SLOs** feature in the - **Observability** section of the Kibana feature privileges. - tags: - - slo - parameters: - - $ref: ../components/headers/kbn_xsrf.yaml - - $ref: ../components/parameters/space_id.yaml - - $ref: ../components/parameters/slo_id.yaml - responses: - '204': - description: Successful request - content: - application/json: - schema: - $ref: '../components/schemas/slo_definition_response.yaml' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '../components/schemas/400_response.yaml' - '401': - description: Unauthorized response - content: - application/json: - schema: - $ref: '../components/schemas/401_response.yaml' - '403': - description: Unauthorized response - content: - application/json: - schema: - $ref: '../components/schemas/403_response.yaml' - '404': - description: Not found response - content: - application/json: - schema: - $ref: '../components/schemas/404_response.yaml' diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@disable.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml similarity index 100% rename from x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@disable.yaml rename to x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{disable}.yaml diff --git a/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@enable.yaml b/x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml similarity index 100% rename from x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@enable.yaml rename to x-pack/plugins/observability/docs/openapi/slo/paths/s@{spaceid}@api@slos@{sloid}@{enable}.yaml diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc index c03e0b499d42..96bfbb4738b2 100644 --- a/x-pack/plugins/observability/kibana.jsonc +++ b/x-pack/plugins/observability/kibana.jsonc @@ -34,12 +34,13 @@ "unifiedSearch", "visualizations", "dashboard", - "expressions" + "expressions", + "logExplorer", + "licensing" ], "optionalPlugins": [ "discover", "home", - "licensing", "usageCollection", "cloud", "spaces", diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx index 8eb2bfe7df7b..4a99d3648af3 100644 --- a/x-pack/plugins/observability/public/application/index.tsx +++ b/x-pack/plugins/observability/public/application/index.tsx @@ -20,7 +20,6 @@ import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; -import { HasDataContextProvider } from '../context/has_data_context/has_data_context'; import { PluginContext } from '../context/plugin_context/plugin_context'; import { ConfigSchema, ObservabilityPublicPluginsStart } from '../plugin'; import { routes } from '../routes/routes'; @@ -119,9 +118,7 @@ export const renderApp = ({ data-test-subj="observabilityMainContainer" > - - - + diff --git a/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_footer.tsx b/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_footer.tsx index 27cbd3a62fdc..324a96845137 100644 --- a/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_footer.tsx +++ b/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_footer.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; + +import React, { useState, useEffect } from 'react'; import { EuiFlyoutFooter, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useKibana } from '../../utils/kibana_react'; @@ -25,17 +26,22 @@ export function AlertsFlyoutFooter({ alert, isInApp }: FlyoutProps & { isInApp: }, } = useKibana().services; const { config } = usePluginContext(); + const [viewInAppUrl, setViewInAppUrl] = useState(); + + useEffect(() => { + if (!alert.hasBasePath) { + setViewInAppUrl(prepend(alert.link ?? '')); + } else { + setViewInAppUrl(alert.link); + } + }, [alert.hasBasePath, alert.link, prepend]); return ( {!alert.link || isInApp ? null : ( - + {i18n.translate('xpack.observability.alertsFlyout.viewInAppButtonText', { defaultMessage: 'View in app', })} diff --git a/x-pack/plugins/observability/public/components/burn_rate_rule_editor/slo_selector.tsx b/x-pack/plugins/observability/public/components/burn_rate_rule_editor/slo_selector.tsx index 6e35ce265bad..5ec21da2efc1 100644 --- a/x-pack/plugins/observability/public/components/burn_rate_rule_editor/slo_selector.tsx +++ b/x-pack/plugins/observability/public/components/burn_rate_rule_editor/slo_selector.tsx @@ -22,7 +22,7 @@ function SloSelector({ initialSlo, onSelected, errors }: Props) { const [options, setOptions] = useState>>([]); const [selectedOptions, setSelectedOptions] = useState>>(); const [searchValue, setSearchValue] = useState(''); - const { isLoading, data } = useFetchSloDefinitions({ name: searchValue }); + const { isLoading, data: sloList } = useFetchSloDefinitions({ name: searchValue }); const hasError = errors !== undefined && errors.length > 0; useEffect(() => { @@ -30,17 +30,17 @@ function SloSelector({ initialSlo, onSelected, errors }: Props) { }, [initialSlo]); useEffect(() => { - const isLoadedWithData = !isLoading && !!data?.results; + const isLoadedWithData = !isLoading && sloList !== undefined; const opts: Array> = isLoadedWithData - ? data?.results?.map((slo) => ({ value: slo.id, label: slo.name })) + ? sloList.map((slo) => ({ value: slo.id, label: slo.name })) : []; setOptions(opts); - }, [isLoading, data]); + }, [isLoading, sloList]); const onChange = (opts: Array>) => { setSelectedOptions(opts); const selectedSlo = - opts.length === 1 ? data?.results?.find((slo) => slo.id === opts[0].value) : undefined; + opts.length === 1 ? sloList?.find((slo) => slo.id === opts[0].value) : undefined; onSelected(selectedSlo); }; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap b/x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap index 2e1219343572..0446f2fe1d4a 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap @@ -22,7 +22,6 @@ Array [ "title": "unknown-index", }, "expression": Object { - "aggType": "custom", "comparator": ">", "metrics": Array [ Object { diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx index d1ab267f1ce2..8747558251da 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.test.tsx @@ -24,6 +24,9 @@ const mockedChartStartContract = chartPluginMock.createStartContract(); jest.mock('@kbn/observability-alert-details', () => ({ AlertAnnotation: () => {}, AlertActiveTimeRangeAnnotation: () => {}, +})); + +jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ getPaddedAlertTimeRange: () => ({ from: '2023-03-28T10:43:13.802Z', to: '2023-03-29T13:14:09.581Z', diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx index a5a029d764a8..c9b17b4f48c9 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/alert_details_app_section.tsx @@ -22,11 +22,8 @@ import { } from '@elastic/eui'; import { ALERT_END, ALERT_START, ALERT_EVALUATION_VALUES } from '@kbn/rule-data-utils'; import { Rule, RuleTypeParams } from '@kbn/alerting-plugin/common'; -import { - AlertAnnotation, - getPaddedAlertTimeRange, - AlertActiveTimeRangeAnnotation, -} from '@kbn/observability-alert-details'; +import { AlertAnnotation, AlertActiveTimeRangeAnnotation } from '@kbn/observability-alert-details'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { DataView } from '@kbn/data-views-plugin/common'; import { MetricsExplorerChartType } from '../../../../common/custom_threshold_rule/types'; import { useKibana } from '../../../utils/kibana_react'; @@ -134,7 +131,7 @@ export default function AlertDetailsAppSection({ -

    {criterion.aggType.toUpperCase()}

    +

    {criterion.label || 'CUSTOM'}

    = { expression: { - aggType: CUSTOM_AGGREGATOR, metrics: [ { name: 'A', @@ -120,7 +118,6 @@ CustomEquationEditorDefault.args = { CustomEquationEditorWithEquationErrors.args = { ...BASE_ARGS, expression: { - aggType: CUSTOM_AGGREGATOR, equation: 'Math.round(A / B)', metrics: [ { name: 'A', aggType: Aggregators.AVERAGE, field: 'system.cpu.user.pct' }, diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx index 164db3bac168..e15248d72c49 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx @@ -22,6 +22,7 @@ import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataViewBase } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; +import { adjustThresholdBasedOnFormat } from '../../helpers/adjust_threshold_based_on_format'; import { Aggregators, CustomThresholdExpressionMetric, @@ -71,7 +72,12 @@ export function CustomEquationEditor({ const currentVars = previous?.map((m) => m.name) ?? []; const name = first(xor(VAR_NAMES, currentVars))!; const nextMetrics = [...(previous || []), { ...NEW_METRIC, name }]; - debouncedOnChange({ ...expression, metrics: nextMetrics, equation }); + debouncedOnChange({ + ...expression, + metrics: nextMetrics, + equation, + threshold: adjustThresholdBasedOnFormat(previous, nextMetrics, expression.threshold), + }); return nextMetrics; }); }, [debouncedOnChange, equation, expression]); @@ -81,7 +87,12 @@ export function CustomEquationEditor({ setCustomMetrics((previous) => { const nextMetrics = previous?.filter((row) => row.name !== name) ?? [NEW_METRIC]; const finalMetrics = (nextMetrics.length && nextMetrics) || [NEW_METRIC]; - debouncedOnChange({ ...expression, metrics: finalMetrics, equation }); + debouncedOnChange({ + ...expression, + metrics: finalMetrics, + equation, + threshold: adjustThresholdBasedOnFormat(previous, nextMetrics, expression.threshold), + }); return finalMetrics; }); }, @@ -92,7 +103,12 @@ export function CustomEquationEditor({ (metric: CustomThresholdExpressionMetric) => { setCustomMetrics((previous) => { const nextMetrics = previous?.map((m) => (m.name === metric.name ? metric : m)); - debouncedOnChange({ ...expression, metrics: nextMetrics, equation }); + debouncedOnChange({ + ...expression, + metrics: nextMetrics, + equation, + threshold: adjustThresholdBasedOnFormat(previous, nextMetrics, expression.threshold), + }); return nextMetrics; }); }, diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_controls.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_controls.tsx index d43c09d7c378..305be75390df 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_controls.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_controls.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; +import { EuiButtonIcon } from '@elastic/eui'; import { DELETE_LABEL } from '../../i18n_strings'; interface MetricRowControlProps { @@ -15,19 +15,16 @@ interface MetricRowControlProps { export function MetricRowControls({ onDelete, disableDelete }: MetricRowControlProps) { return ( - <> - - - - + ); } diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx index 51c4713fef26..a00a086ef552 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx @@ -112,117 +112,123 @@ export function MetricRowWithAgg({ const isFieldInvalid = get(errors, ['metrics', name, 'field']) != null || !field; return ( - <> - - - - { - setAggTypePopoverOpen(true); - }} - isInvalid={aggType !== Aggregators.COUNT && !field} - /> - - } - isOpen={aggTypePopoverOpen} - closePopover={() => { - setAggTypePopoverOpen(false); - }} - display="block" - ownFocus - anchorPosition={'downLeft'} - repositionOnScroll - > -
    - setAggTypePopoverOpen(false)}> - - + + + + + {i18n.translate( + 'xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationLabel', + { defaultMessage: 'Aggregation {name}', values: { name } } + )} + + {!disableDelete && ( + + + + )} + + } + > + { + setAggTypePopoverOpen(true); + }} + isInvalid={aggType !== Aggregators.COUNT && !field} + /> + + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + display="block" + ownFocus + anchorPosition={'downLeft'} + repositionOnScroll + > +
    + setAggTypePopoverOpen(false)}> + + - - + + + + { + handleAggChange(e.target.value); + }} + options={Object.values(aggregationTypes).map(({ text, value }) => { + return { + text, + value, + }; + })} + isInvalid={isAggInvalid} + /> + + + + {aggType === Aggregators.COUNT ? ( + + + + ) : ( - { - handleAggChange(e.target.value); - }} - options={Object.values(aggregationTypes).map(({ text, value }) => { - return { - text, - value, - }; - })} - isInvalid={isAggInvalid} + isInvalid={isFieldInvalid} + singleSelection={{ asPlainText: true }} + options={fieldOptions} + selectedOptions={field ? [{ label: field }] : []} + onChange={handleFieldChange} /> - - - {aggType === Aggregators.COUNT ? ( - - - - ) : ( - - - - )} - - -
    - - - - - + )} + + +
    +
    +
    +
    ); } diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_chart.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_chart.test.tsx index 956391a3f29b..5af6cae385d7 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_chart.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_chart.test.tsx @@ -12,7 +12,6 @@ import { DataViewBase } from '@kbn/es-query'; import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import React, { ReactElement } from 'react'; import { act } from 'react-dom/test-utils'; -import { CUSTOM_AGGREGATOR } from '../../../../common/custom_threshold_rule/constants'; import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types'; import { MetricExpression } from '../types'; import { ExpressionChart } from './expression_chart'; @@ -77,7 +76,6 @@ describe('ExpressionChart', () => { it('should display no data message', async () => { const expression: MetricExpression = { - aggType: CUSTOM_AGGREGATOR, metrics: [ { name: 'A', diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.test.tsx index 8b0a4de92bd7..2bdd1f2def08 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.test.tsx @@ -9,7 +9,6 @@ import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import React from 'react'; import { act } from 'react-dom/test-utils'; -import { CUSTOM_AGGREGATOR } from '../../../../common/custom_threshold_rule/constants'; import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types'; import { MetricExpression } from '../types'; import { ExpressionRow } from './expression_row'; @@ -18,6 +17,7 @@ describe('ExpressionRow', () => { async function setup(expression: MetricExpression) { const wrapper = mountWithIntl( Condition} canDelete={false} fields={[ { @@ -57,7 +57,6 @@ describe('ExpressionRow', () => { it('should display thresholds as a percentage for pct metrics', async () => { const expression: MetricExpression = { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -83,7 +82,6 @@ describe('ExpressionRow', () => { it('should display thresholds as a decimal for all other metrics', async () => { const expression = { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.tsx index 0f53594bd49e..6b0643791596 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/expression_row.tsx @@ -12,9 +12,10 @@ import { EuiFlexItem, EuiFormRow, EuiSpacer, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState, ReactElement } from 'react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { AggregationType, @@ -47,6 +48,7 @@ const customComparators = { }; interface ExpressionRowProps { + title: ReactElement; fields: DataViewFieldBase[]; expressionId: number; expression: MetricExpression; @@ -77,6 +79,7 @@ export const ExpressionRow: React.FC = (props) => { remove, fields, canDelete, + title, } = props; const { metrics, comparator = Comparator.GT, threshold = [] } = expression; @@ -146,6 +149,29 @@ export const ExpressionRow: React.FC = (props) => { ); return ( <> + + + +
    {title}
    +
    +
    + {canDelete && ( + + remove(expressionId)} + /> + + )} +
    @@ -178,25 +204,8 @@ export const ExpressionRow: React.FC = (props) => { - {canDelete && ( - - remove(expressionId)} - /> - - )} {children} - ); }; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.test.tsx index 9226da0ca237..bc478e54135b 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.test.tsx @@ -9,12 +9,11 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { DataView } from '@kbn/data-views-plugin/common'; import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; -import { CUSTOM_AGGREGATOR } from '../../../../../common/custom_threshold_rule/constants'; import { Comparator, Aggregators } from '../../../../../common/custom_threshold_rule/types'; import { useKibana } from '../../../../utils/kibana_react'; import { kibanaStartMock } from '../../../../utils/kibana_react.mock'; import { MetricExpression } from '../../types'; -import { PreviewChart } from './preview_chart'; +import { getBufferThreshold, PreviewChart } from './preview_chart'; jest.mock('../../../../utils/kibana_react'); @@ -55,7 +54,6 @@ describe('Preview chart', () => { it('should display no data message', async () => { const expression: MetricExpression = { - aggType: CUSTOM_AGGREGATOR, metrics: [ { name: 'A', @@ -72,3 +70,18 @@ describe('Preview chart', () => { expect(wrapper.find('[data-test-subj="thresholdRuleNoChartData"]').exists()).toBeTruthy(); }); }); + +describe('getBufferThreshold', () => { + const testData = [ + { threshold: undefined, buffer: '0.00' }, + { threshold: 0.1, buffer: '0.12' }, + { threshold: 0.01, buffer: '0.02' }, + { threshold: 0.001, buffer: '0.01' }, + { threshold: 0.00098, buffer: '0.01' }, + { threshold: 130, buffer: '143.00' }, + ]; + + it.each(testData)('getBufferThreshold($threshold) = $buffer', ({ threshold, buffer }) => { + expect(getBufferThreshold(threshold)).toBe(buffer); + }); +}); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.tsx index d5a8b763ca7b..1c25d22b3a59 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/preview_chart/preview_chart.tsx @@ -44,6 +44,9 @@ const getOperationTypeFromRuleAggType = (aggType: AggType): OperationType => { return aggType; }; +export const getBufferThreshold = (threshold?: number): string => + (Math.ceil((threshold || 0) * 1.1 * 100) / 100).toFixed(2).toString(); + export function PreviewChart({ metricExpression, dataView, @@ -147,7 +150,7 @@ export function PreviewChart({ const bufferRefLine = new XYReferenceLinesLayer({ data: [ { - value: Math.round((threshold[0] || 0) * 1.1).toString(), + value: getBufferThreshold(threshold[0]), color: 'transparent', fill, format, @@ -218,12 +221,7 @@ export function PreviewChart({ decimals: isPercent ? 0 : 2, }, }, - filter: { - language: 'kuery', - query: filterQuery || '', - }, }; - const xYDataLayerOptions: XYLayerOptions = { buckets: { type: 'date_histogram', @@ -252,7 +250,6 @@ export function PreviewChart({ value: layer.value, label: layer.label, format: layer.format, - filter: layer.filter, })), options: xYDataLayerOptions, }); @@ -333,6 +330,10 @@ export function PreviewChart({ timeRange={{ from: `now-${timeSize * 20}${timeUnit}`, to: 'now' }} attributes={attributes} disableTriggers={true} + query={{ + language: 'kuery', + query: filterQuery || '', + }} />
    ); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/validation.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/validation.tsx index f360b415fa1b..2144757216fb 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/validation.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/validation.tsx @@ -27,17 +27,12 @@ export function validateCustomThreshold({ const validationResult = { errors: {} }; const errors: { [id: string]: { - aggField: string[]; timeSizeUnit: string[]; timeWindowSize: string[]; critical: { threshold0: string[]; threshold1: string[]; }; - warning: { - threshold0: string[]; - threshold1: string[]; - }; metricsError?: string; metrics: Record; equation?: string; @@ -91,23 +86,9 @@ export function validateCustomThreshold({ threshold0: [], threshold1: [], }, - warning: { - threshold0: [], - threshold1: [], - }, metric: [], metrics: {}, }; - if (!c.aggType) { - errors[id].aggField.push( - i18n.translate( - 'xpack.observability.customThreshold.rule.alertFlyout.error.aggregationRequired', - { - defaultMessage: 'Aggregation is required.', - } - ) - ); - } if (!c.threshold || !c.threshold.length) { errors[id].critical.threshold0.push( @@ -120,8 +101,30 @@ export function validateCustomThreshold({ ); } - if (c.warningThreshold && !c.warningThreshold.length) { - errors[id].warning.threshold0.push( + // The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i]. + // We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element. + const { comparator, threshold } = { comparator: c.comparator, threshold: c.threshold } as { + comparator?: Comparator; + threshold?: number[]; + }; + if (threshold && threshold.length && ![...threshold].every(isNumber)) { + [...threshold].forEach((v, i) => { + if (!isNumber(v)) { + const key = i === 0 ? 'threshold0' : 'threshold1'; + errors[id].critical[key].push( + i18n.translate( + 'xpack.observability.customThreshold.rule.alertFlyout.error.thresholdTypeRequired', + { + defaultMessage: 'Thresholds must contain a valid number.', + } + ) + ); + } + }); + } + + if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) { + errors[id].critical.threshold1.push( i18n.translate( 'xpack.observability.customThreshold.rule.alertFlyout.error.thresholdRequired', { @@ -131,45 +134,6 @@ export function validateCustomThreshold({ ); } - for (const props of [ - { comparator: c.comparator, threshold: c.threshold, type: 'critical' }, - { comparator: c.warningComparator, threshold: c.warningThreshold, type: 'warning' }, - ]) { - // The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i]. - // We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element. - const { comparator, threshold, type } = props as { - comparator?: Comparator; - threshold?: number[]; - type: 'critical' | 'warning'; - }; - if (threshold && threshold.length && ![...threshold].every(isNumber)) { - [...threshold].forEach((v, i) => { - if (!isNumber(v)) { - const key = i === 0 ? 'threshold0' : 'threshold1'; - errors[id][type][key].push( - i18n.translate( - 'xpack.observability.customThreshold.rule.alertFlyout.error.thresholdTypeRequired', - { - defaultMessage: 'Thresholds must contain a valid number.', - } - ) - ); - } - }); - } - - if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) { - errors[id][type].threshold1.push( - i18n.translate( - 'xpack.observability.customThreshold.rule.alertFlyout.error.thresholdRequired', - { - defaultMessage: 'Threshold is required.', - } - ) - ); - } - } - if (!c.timeSize) { errors[id].timeWindowSize.push( i18n.translate('xpack.observability.customThreshold.rule.alertFlyout.error.timeRequred', { diff --git a/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx b/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx index 78fa6c324442..0f1742469c31 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx @@ -92,10 +92,9 @@ describe('Expression', () => { }, ], comparator: Comparator.GT, - threshold: [1000], + threshold: [100], timeSize: 1, timeUnit: 'm', - aggType: 'custom', }, ]); }); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx b/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx index 2c5f7438b048..539f8fbf4f58 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx +++ b/x-pack/plugins/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx @@ -14,6 +14,7 @@ import { EuiEmptyPrompt, EuiFormErrorText, EuiFormRow, + EuiHorizontalRule, EuiIcon, EuiLink, EuiLoadingSpinner, @@ -36,7 +37,6 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { useKibana } from '../../utils/kibana_react'; -import { CUSTOM_AGGREGATOR } from '../../../common/custom_threshold_rule/constants'; import { Aggregators, Comparator } from '../../../common/custom_threshold_rule/types'; import { TimeUnitChar } from '../../../common/utils/formatters/duration'; import { AlertContextMeta, AlertParams, MetricExpression } from './types'; @@ -52,7 +52,6 @@ type Props = Omit< >; export const defaultExpression: MetricExpression = { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -60,7 +59,7 @@ export const defaultExpression: MetricExpression = { aggType: Aggregators.COUNT, }, ], - threshold: [1000], + threshold: [100], timeSize: 1, timeUnit: 'm', }; @@ -202,11 +201,8 @@ export default function Expressions(props: Props) { const removeExpression = useCallback( (id: number) => { - const ruleCriteria = ruleParams.criteria?.slice() || []; - if (ruleCriteria.length > 1) { - ruleCriteria.splice(id, 1); - setRuleParams('criteria', ruleCriteria); - } + const ruleCriteria = ruleParams.criteria?.filter((_, index) => index !== id) || []; + setRuleParams('criteria', ruleCriteria); }, [setRuleParams, ruleParams.criteria] ); @@ -375,30 +371,11 @@ export default function Expressions(props: Props) { )} - -
    - -
    -
    {ruleParams.criteria && ruleParams.criteria.map((e, idx) => { return (
    - {/* index has semantic meaning, we show the condition title starting from the 2nd one */} - {idx >= 1 && ( - -
    - -
    -
    - )} + {idx > 0 && } 1) || false} fields={derivedIndexPattern.fields} @@ -410,6 +387,20 @@ export default function Expressions(props: Props) { errors={(errors[idx] as IErrorObject) || emptyError} expression={e || {}} dataView={derivedIndexPattern} + title={ + ruleParams.criteria.length === 1 ? ( + + ) : ( + + ) + } > { + test('previous: nonPercent, next: percent -> threshold / 100', () => { + const previous: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + aggType: Aggregators.COUNT, + }, + ]; + const next: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + field: 'system.cpu.system.pct', + aggType: Aggregators.AVERAGE, + }, + ]; + const threshold: number[] = [100]; + const expectedThreshold: number[] = [1]; + + expect(adjustThresholdBasedOnFormat(previous, next, threshold)).toEqual(expectedThreshold); + }); + + test('previous: percent, next: nonPercent -> threshold * 100', () => { + const previous: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + field: 'system.cpu.system.pct', + aggType: Aggregators.AVERAGE, + }, + ]; + const next: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + aggType: Aggregators.COUNT, + }, + ]; + const threshold: number[] = [1]; + const expectedThreshold: number[] = [100]; + + expect(adjustThresholdBasedOnFormat(previous, next, threshold)).toEqual(expectedThreshold); + }); + + test('previous: percent, next: percent -> no threshold change', () => { + const previous: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + field: 'system.cpu.system.pct', + aggType: Aggregators.AVERAGE, + }, + ]; + const next: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + field: 'system.cpu.total.norm.pct', + aggType: Aggregators.AVERAGE, + }, + ]; + const threshold: number[] = [1]; + + expect(adjustThresholdBasedOnFormat(previous, next, threshold)).toEqual(threshold); + }); + + test('previous: nonPercent, next: nonPercent -> threshold * 100', () => { + const previous: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + field: 'host.disk.read.bytes', + aggType: Aggregators.AVERAGE, + }, + ]; + const next: CustomThresholdExpressionMetric[] = [ + { + name: 'A', + aggType: Aggregators.COUNT, + }, + ]; + const threshold: number[] = [100]; + + expect(adjustThresholdBasedOnFormat(previous, next, threshold)).toEqual(threshold); + }); +}); diff --git a/x-pack/plugins/observability/public/components/custom_threshold/helpers/adjust_threshold_based_on_format.ts b/x-pack/plugins/observability/public/components/custom_threshold/helpers/adjust_threshold_based_on_format.ts new file mode 100644 index 000000000000..ba4976684e38 --- /dev/null +++ b/x-pack/plugins/observability/public/components/custom_threshold/helpers/adjust_threshold_based_on_format.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CustomThresholdExpressionMetric } from '../../../../common/custom_threshold_rule/types'; +import { decimalToPct, pctToDecimal } from './corrected_percent_convert'; + +export const adjustThresholdBasedOnFormat = ( + previous: CustomThresholdExpressionMetric[], + next: CustomThresholdExpressionMetric[], + threshold: number[] +) => { + const isPreviousPercent = Boolean(previous.length === 1 && previous[0].field?.endsWith('.pct')); + const isPercent = Boolean(next.length === 1 && next[0].field?.endsWith('.pct')); + return isPercent === isPreviousPercent + ? threshold + : isPercent + ? threshold.map((v: number) => pctToDecimal(v)) + : isPreviousPercent + ? threshold.map((v: number) => decimalToPct(v)) + : threshold; +}; diff --git a/x-pack/plugins/observability/public/components/custom_threshold/hooks/use_expression_chart_data.ts b/x-pack/plugins/observability/public/components/custom_threshold/hooks/use_expression_chart_data.ts index 1f135473c086..65bb84defa03 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/hooks/use_expression_chart_data.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/hooks/use_expression_chart_data.ts @@ -52,11 +52,10 @@ export const useExpressionChartData = ( equation: expression.equation, }, ], - aggregation: expression.aggType || 'custom', + aggregation: 'custom', }), // eslint-disable-next-line react-hooks/exhaustive-deps [ - expression.aggType, expression.equation, // eslint-disable-next-line react-hooks/exhaustive-deps JSON.stringify(expression.metrics), diff --git a/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts b/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts index f93bac2b0f10..cfe41b6bd9d0 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/mocks/custom_threshold_rule.ts @@ -6,7 +6,6 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { CUSTOM_AGGREGATOR } from '../../../../common/custom_threshold_rule/constants'; import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types'; import { CustomThresholdAlert, CustomThresholdRule } from '../components/alert_details_app_section'; @@ -60,7 +59,6 @@ export const buildCustomThresholdRule = ( params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -73,7 +71,6 @@ export const buildCustomThresholdRule = ( timeUnit: 'm', }, { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -89,7 +86,6 @@ export const buildCustomThresholdRule = ( warningThreshold: [2.2], }, { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -155,7 +151,6 @@ export const buildCustomThresholdAlert = ( 'kibana.alert.rule.parameters': { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -169,7 +164,6 @@ export const buildCustomThresholdAlert = ( timeUnit: 'm', }, { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -190,7 +184,7 @@ export const buildCustomThresholdAlert = ( alertOnGroupDisappear: true, }, 'kibana.alert.evaluation.values': [2500, 5], - 'kibana.alert.rule.category': 'Custom threshold (Technical Preview)', + 'kibana.alert.rule.category': 'Custom threshold (Beta)', 'kibana.alert.rule.consumer': 'alerts', 'kibana.alert.rule.execution.uuid': '62dd07ef-ead9-4b1f-a415-7c83d03925f7', 'kibana.alert.rule.name': 'One condition', diff --git a/x-pack/plugins/observability/public/components/custom_threshold/types.ts b/x-pack/plugins/observability/public/components/custom_threshold/types.ts index e726a8fd0132..dc0ad4eb7162 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/types.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/types.ts @@ -74,8 +74,6 @@ export interface InfraClientStartDeps { uiActions: UiActionsStart; unifiedSearch: UnifiedSearchPublicPluginStart; usageCollection: UsageCollectionStart; - // TODO:: check if needed => https://github.com/elastic/kibana/issues/159340 - // telemetry: ITelemetryClient; } export type RendererResult = React.ReactElement | null; diff --git a/x-pack/plugins/observability/public/components/slo/error_rate_chart/use_lens_definition.ts b/x-pack/plugins/observability/public/components/slo/error_rate_chart/use_lens_definition.ts index 36cea6b76404..ce01ac20ee69 100644 --- a/x-pack/plugins/observability/public/components/slo/error_rate_chart/use_lens_definition.ts +++ b/x-pack/plugins/observability/public/components/slo/error_rate_chart/use_lens_definition.ts @@ -555,7 +555,7 @@ export function useLensDefinition(slo: SLOResponse): TypedLensByValueInput['attr adHocDataViews: { '32ca1ad4-81c0-4daf-b9d1-07118044bdc5': { id: '32ca1ad4-81c0-4daf-b9d1-07118044bdc5', - title: '.slo-observability.sli-v3.*', + title: '.slo-observability.sli-v2.*', timeFieldName: '@timestamp', sourceFilters: [], fieldFormats: {}, diff --git a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.tsx b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.tsx index 485355a27872..76a1a0efef11 100644 --- a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.tsx +++ b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_active_alerts_badge.tsx @@ -14,11 +14,12 @@ import { paths } from '../../../../common/locators/paths'; import { useKibana } from '../../../utils/kibana_react'; export interface Props { + viewMode?: 'compact' | 'default'; activeAlerts?: number; slo: SLOWithSummaryResponse; } -export function SloActiveAlertsBadge({ slo, activeAlerts }: Props) { +export function SloActiveAlertsBadge({ slo, activeAlerts, viewMode = 'default' }: Props) { const { application: { navigateToUrl }, http: { basePath }, @@ -50,10 +51,12 @@ export function SloActiveAlertsBadge({ slo, activeAlerts }: Props) { )} data-test-subj="o11ySloActiveAlertsBadge" > - {i18n.translate('xpack.observability.slo.slo.activeAlertsBadge.label', { - defaultMessage: '{count, plural, one {# alert} other {# alerts}}', - values: { count: activeAlerts }, - })} + {viewMode !== 'default' + ? activeAlerts + : i18n.translate('xpack.observability.slo.slo.activeAlertsBadge.label', { + defaultMessage: '{count, plural, one {# alert} other {# alerts}}', + values: { count: activeAlerts }, + })} ); diff --git a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx index 455d6d9d24ed..f79b700ed9be 100644 --- a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx +++ b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx @@ -5,24 +5,25 @@ * 2.0. */ -import { EuiBadge, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { EuiBadge, EuiBadgeProps, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; -import { euiLightVars } from '@kbn/ui-theme'; import React from 'react'; +import { euiLightVars } from '@kbn/ui-theme'; export interface Props { + color?: EuiBadgeProps['color']; slo: SLOWithSummaryResponse; } -export function SloGroupByBadge({ slo }: Props) { +export function SloGroupByBadge({ slo, color }: Props) { if (!slo.groupBy || slo.groupBy === ALL_VALUE) { return null; } return ( - + ({}); - const isExploratoryView = useRouteMatch('/exploratory-view'); - useEffect( () => { - if (!isExploratoryView) - asyncForEach(apps, async (app) => { - try { - const updateState = ({ - hasData, - indices, - serviceName, - }: { - hasData?: boolean; - serviceName?: string; - indices?: string | ApmIndicesConfig; - }) => { - setHasDataMap((prevState) => ({ - ...prevState, - [app]: { - hasData, - ...(serviceName ? { serviceName } : {}), - ...(indices ? { indices } : {}), - status: FETCH_STATUS.SUCCESS, - }, - })); - }; - switch (app) { - case UX_APP: - const params = { absoluteTime: { start: absoluteStart!, end: absoluteEnd! } }; - const resultUx = await getDataHandler(app)?.hasData(params); - updateState({ - hasData: resultUx?.hasData, - indices: resultUx?.indices, - serviceName: resultUx?.serviceName as string, - }); - break; - case UPTIME_APP: - const resultSy = await getDataHandler(app)?.hasData(); - updateState({ hasData: resultSy?.hasData, indices: resultSy?.indices }); - - break; - case APM_APP: - const resultApm = await getDataHandler(app)?.hasData(); - updateState({ hasData: resultApm?.hasData, indices: resultApm?.indices }); - - break; - case INFRA_LOGS_APP: - const resultInfraLogs = await getDataHandler(app)?.hasData(); - updateState({ - hasData: resultInfraLogs?.hasData, - indices: resultInfraLogs?.indices, - }); - break; - case INFRA_METRICS_APP: - const resultInfraMetrics = await getDataHandler(app)?.hasData(); - updateState({ - hasData: resultInfraMetrics?.hasData, - indices: resultInfraMetrics?.indices, - }); - break; - case UNIVERSAL_PROFILING_APP: - // Profiling only shows the empty section for now - updateState({ hasData: false }); - break; - } - } catch (e) { + asyncForEach(apps, async (app) => { + try { + const updateState = ({ + hasData, + indices, + serviceName, + }: { + hasData?: boolean; + serviceName?: string; + indices?: string | ApmIndicesConfig; + }) => { setHasDataMap((prevState) => ({ ...prevState, [app]: { - hasData: undefined, - status: FETCH_STATUS.FAILURE, + hasData, + ...(serviceName ? { serviceName } : {}), + ...(indices ? { indices } : {}), + status: FETCH_STATUS.SUCCESS, }, })); + }; + switch (app) { + case UX_APP: + const params = { absoluteTime: { start: absoluteStart!, end: absoluteEnd! } }; + const resultUx = await getDataHandler(app)?.hasData(params); + updateState({ + hasData: resultUx?.hasData, + indices: resultUx?.indices, + serviceName: resultUx?.serviceName as string, + }); + break; + case UPTIME_APP: + const resultSy = await getDataHandler(app)?.hasData(); + updateState({ hasData: resultSy?.hasData, indices: resultSy?.indices }); + + break; + case APM_APP: + const resultApm = await getDataHandler(app)?.hasData(); + updateState({ hasData: resultApm?.hasData, indices: resultApm?.indices }); + + break; + case INFRA_LOGS_APP: + const resultInfraLogs = await getDataHandler(app)?.hasData(); + updateState({ + hasData: resultInfraLogs?.hasData, + indices: resultInfraLogs?.indices, + }); + break; + case INFRA_METRICS_APP: + const resultInfraMetrics = await getDataHandler(app)?.hasData(); + updateState({ + hasData: resultInfraMetrics?.hasData, + indices: resultInfraMetrics?.indices, + }); + break; + case UNIVERSAL_PROFILING_APP: + // Profiling only shows the empty section for now + updateState({ hasData: false }); + break; } - }); + } catch (e) { + setHasDataMap((prevState) => ({ + ...prevState, + [app]: { + hasData: undefined, + status: FETCH_STATUS.FAILURE, + }, + })); + } + }); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [isExploratoryView] + [] ); useEffect(() => { diff --git a/x-pack/plugins/observability/public/data/slo/slo.ts b/x-pack/plugins/observability/public/data/slo/slo.ts index c53d55a32839..5e210526884f 100644 --- a/x-pack/plugins/observability/public/data/slo/slo.ts +++ b/x-pack/plugins/observability/public/data/slo/slo.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { ALL_VALUE, FindSLOResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { cloneDeep } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; +import { ALL_VALUE, FindSLOResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { buildDegradingSummary, buildHealthySummary, @@ -16,8 +16,8 @@ import { buildTimeslicesObjective, buildViolatedSummary, } from './common'; -import { buildApmAvailabilityIndicator, buildCustomKqlIndicator } from './indicator'; import { buildCalendarAlignedTimeWindow, buildRollingTimeWindow } from './time_window'; +import { buildApmAvailabilityIndicator, buildCustomKqlIndicator } from './indicator'; export const emptySloList: FindSLOResponse = { results: [], @@ -68,7 +68,6 @@ const baseSlo: Omit = { enabled: true, createdAt: now, updatedAt: now, - version: 2, }; export const sloList: FindSLOResponse = { diff --git a/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts b/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts index feec4d475e3a..b56a0576396f 100644 --- a/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts +++ b/x-pack/plugins/observability/public/hooks/slo/query_key_factory.ts @@ -32,7 +32,8 @@ export const sloKeys = { globalDiagnosis: () => [...sloKeys.all, 'globalDiagnosis'] as const, burnRates: (sloId: string, instanceId: string | undefined) => [...sloKeys.all, 'burnRates', sloId, instanceId] as const, - preview: (indicator?: Indicator) => [...sloKeys.all, 'preview', indicator] as const, + preview: (indicator: Indicator, range: { start: number; end: number }) => + [...sloKeys.all, 'preview', indicator, range] as const, }; export type SloKeys = typeof sloKeys; diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts index 2d234b57ab8e..33ae5ffac263 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts @@ -12,6 +12,7 @@ import { ALL_VALUE, SLOResponse } from '@kbn/slo-schema'; import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +import { SLO_LONG_REFETCH_INTERVAL } from '../../constants'; type SLO = Pick; @@ -71,7 +72,6 @@ interface FindApiResponse { }; } -const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute const EMPTY_ACTIVE_ALERTS_MAP = new ActiveAlerts(); export function useFetchActiveAlerts({ @@ -141,7 +141,7 @@ export function useFetchActiveAlerts({ } }, refetchOnWindowFocus: false, - refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined, + refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined, enabled: Boolean(sloIdsAndInstanceIds.length), }); diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_historical_summary.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_historical_summary.ts index a20b721f11bb..63bdc55d7eaf 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_historical_summary.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_historical_summary.ts @@ -10,6 +10,7 @@ import { FetchHistoricalSummaryResponse } from '@kbn/slo-schema'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +import { SLO_LONG_REFETCH_INTERVAL } from '../../constants'; export interface UseFetchHistoricalSummaryResponse { data: FetchHistoricalSummaryResponse | undefined; @@ -25,8 +26,6 @@ export interface Params { shouldRefetch?: boolean; } -const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute - export function useFetchHistoricalSummary({ list = [], shouldRefetch, @@ -50,7 +49,7 @@ export function useFetchHistoricalSummary({ // ignore error } }, - refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined, + refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined, refetchOnWindowFocus: false, keepPreviousData: true, }); diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_burn_rates.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_burn_rates.ts index 20092609bdfa..07ba25e0e524 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_burn_rates.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_burn_rates.ts @@ -13,6 +13,7 @@ import { import { ALL_VALUE, GetSLOBurnRatesResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +import { SLO_LONG_REFETCH_INTERVAL } from '../../constants'; export interface UseFetchSloBurnRatesResponse { isInitialLoading: boolean; @@ -26,8 +27,6 @@ export interface UseFetchSloBurnRatesResponse { ) => Promise>; } -const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute - interface UseFetchSloBurnRatesParams { slo: SLOWithSummaryResponse; windows: Array<{ name: string; duration: string }>; @@ -58,7 +57,7 @@ export function useFetchSloBurnRates({ // ignore error } }, - refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined, + refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined, refetchOnWindowFocus: false, keepPreviousData: true, } diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_definitions.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_definitions.ts index b3b7f59dd37c..e74b3570177e 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_definitions.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_definitions.ts @@ -5,16 +5,24 @@ * 2.0. */ -import { FindSLODefinitionsResponse } from '@kbn/slo-schema'; -import { useQuery } from '@tanstack/react-query'; +import { FindSloDefinitionsResponse, SLOResponse } from '@kbn/slo-schema'; +import { + QueryObserverResult, + RefetchOptions, + RefetchQueryFilters, + useQuery, +} from '@tanstack/react-query'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; export interface UseFetchSloDefinitionsResponse { - data: FindSLODefinitionsResponse | undefined; isLoading: boolean; isSuccess: boolean; isError: boolean; + data: SLOResponse[] | undefined; + refetch: ( + options?: (RefetchOptions & RefetchQueryFilters) | undefined + ) => Promise>; } interface Params { @@ -25,13 +33,18 @@ export function useFetchSloDefinitions({ name = '' }: Params): UseFetchSloDefini const { http } = useKibana().services; const search = name.endsWith('*') ? name : `${name}*`; - const { isLoading, isError, isSuccess, data } = useQuery({ + const { isLoading, isError, isSuccess, data, refetch } = useQuery({ queryKey: sloKeys.definitions(search), queryFn: async ({ signal }) => { try { - const response = await http.get( - '/api/observability/slos/_definitions', - { query: { search }, signal } + const response = await http.get( + '/internal/observability/slos/_definitions', + { + query: { + search, + }, + signal, + } ); return response; @@ -43,5 +56,5 @@ export function useFetchSloDefinitions({ name = '' }: Params): UseFetchSloDefini refetchOnWindowFocus: false, }); - return { isLoading, isError, isSuccess, data }; + return { isLoading, isError, isSuccess, data, refetch }; } diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_details.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_details.ts index ad5511433522..76864996168b 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_details.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_details.ts @@ -12,6 +12,7 @@ import { RefetchQueryFilters, useQuery, } from '@tanstack/react-query'; +import { SLO_LONG_REFETCH_INTERVAL } from '../../constants'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; @@ -27,8 +28,6 @@ export interface UseFetchSloDetailsResponse { ) => Promise>; } -const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute - export function useFetchSloDetails({ sloId, instanceId, @@ -59,7 +58,7 @@ export function useFetchSloDetails({ }, keepPreviousData: true, enabled: Boolean(sloId), - refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined, + refetchInterval: shouldRefetch ? SLO_LONG_REFETCH_INTERVAL : undefined, refetchOnWindowFocus: false, } ); diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts index 8f7a9e21b20c..a05ec3c61695 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FindSLOResponse } from '@kbn/slo-schema'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; +import { SLO_LONG_REFETCH_INTERVAL, SLO_SHORT_REFETCH_INTERVAL } from '../../constants'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; @@ -30,9 +31,6 @@ export interface UseFetchSloListResponse { data: FindSLOResponse | undefined; } -const SHORT_REFETCH_INTERVAL = 1000 * 5; // 5 seconds -const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute - export function useFetchSloList({ kqlQuery = '', page = 1, @@ -45,7 +43,9 @@ export function useFetchSloList({ notifications: { toasts }, } = useKibana().services; const queryClient = useQueryClient(); - const [stateRefetchInterval, setStateRefetchInterval] = useState(SHORT_REFETCH_INTERVAL); + const [stateRefetchInterval, setStateRefetchInterval] = useState( + SLO_SHORT_REFETCH_INTERVAL + ); const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: sloKeys.list({ kqlQuery, page, sortBy, sortDirection }), @@ -81,9 +81,9 @@ export function useFetchSloList({ } if (results.find((slo) => slo.summary.status === 'NO_DATA' || !slo.summary)) { - setStateRefetchInterval(SHORT_REFETCH_INTERVAL); + setStateRefetchInterval(SLO_SHORT_REFETCH_INTERVAL); } else { - setStateRefetchInterval(LONG_REFETCH_INTERVAL); + setStateRefetchInterval(SLO_LONG_REFETCH_INTERVAL); } }, onError: (error: Error) => { diff --git a/x-pack/plugins/observability/public/hooks/slo/use_get_preview_data.ts b/x-pack/plugins/observability/public/hooks/slo/use_get_preview_data.ts index 0dfe9cbebc82..3a3b5d91871e 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_get_preview_data.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_get_preview_data.ts @@ -6,57 +6,48 @@ */ import { GetPreviewDataResponse, Indicator } from '@kbn/slo-schema'; -import { - QueryObserverResult, - RefetchOptions, - RefetchQueryFilters, - useQuery, -} from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; export interface UseGetPreviewData { data: GetPreviewDataResponse | undefined; isInitialLoading: boolean; - isRefetching: boolean; isLoading: boolean; isSuccess: boolean; isError: boolean; - refetch: ( - options?: (RefetchOptions & RefetchQueryFilters) | undefined - ) => Promise>; } -export function useGetPreviewData(isValid: boolean, indicator: Indicator): UseGetPreviewData { +export function useGetPreviewData( + isValid: boolean, + indicator: Indicator, + range: { start: number; end: number } +): UseGetPreviewData { const { http } = useKibana().services; - const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery( - { - queryKey: sloKeys.preview(indicator), - queryFn: async ({ signal }) => { - const response = await http.post( - '/internal/observability/slos/_preview', - { - body: JSON.stringify({ indicator }), - signal, - } - ); + const { isInitialLoading, isLoading, isError, isSuccess, data } = useQuery({ + queryKey: sloKeys.preview(indicator, range), + queryFn: async ({ signal }) => { + const response = await http.post( + '/internal/observability/slos/_preview', + { + body: JSON.stringify({ indicator, range }), + signal, + } + ); - return Array.isArray(response) ? response : []; - }, - retry: false, - refetchOnWindowFocus: false, - enabled: isValid, - } - ); + return Array.isArray(response) ? response : []; + }, + retry: false, + refetchOnWindowFocus: false, + enabled: isValid, + }); return { data, isLoading, - isRefetching, isInitialLoading, isSuccess, isError, - refetch, }; } diff --git a/x-pack/plugins/observability/public/hooks/use_get_user_cases_permissions.tsx b/x-pack/plugins/observability/public/hooks/use_get_user_cases_permissions.tsx deleted file mode 100644 index ea80fc8f8cc1..000000000000 --- a/x-pack/plugins/observability/public/hooks/use_get_user_cases_permissions.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect, useState } from 'react'; -import { CasesPermissions } from '@kbn/cases-plugin/common'; -import { useKibana } from '../utils/kibana_react'; -import { casesFeatureId } from '../../common'; - -export function useGetUserCasesPermissions() { - const [casesPermissions, setCasesPermissions] = useState({ - all: false, - read: false, - create: false, - update: false, - delete: false, - push: false, - connectors: false, - }); - const uiCapabilities = useKibana().services.application.capabilities; - - const casesCapabilities = useKibana().services.cases.helpers.getUICapabilities( - uiCapabilities[casesFeatureId] - ); - - useEffect(() => { - setCasesPermissions({ - all: casesCapabilities.all, - create: casesCapabilities.create, - read: casesCapabilities.read, - update: casesCapabilities.update, - delete: casesCapabilities.delete, - push: casesCapabilities.push, - connectors: casesCapabilities.connectors, - }); - }, [ - casesCapabilities.all, - casesCapabilities.create, - casesCapabilities.read, - casesCapabilities.update, - casesCapabilities.delete, - casesCapabilities.push, - casesCapabilities.connectors, - ]); - - return casesPermissions; -} diff --git a/x-pack/plugins/observability/public/locators/slo_edit.test.ts b/x-pack/plugins/observability/public/locators/slo_edit.test.ts index cb485ea3e387..a01a988dcdb5 100644 --- a/x-pack/plugins/observability/public/locators/slo_edit.test.ts +++ b/x-pack/plugins/observability/public/locators/slo_edit.test.ts @@ -20,7 +20,7 @@ describe('SloEditLocator', () => { it('should return correct url when slo is provided', async () => { const location = await locator.getLocation(buildSlo({ id: 'foo' })); expect(location.path).toEqual( - "/slos/edit/foo?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',id:foo,indicator:(params:(filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z',version:2)" + "/slos/edit/foo?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',id:foo,indicator:(params:(filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z')" ); }); }); diff --git a/x-pack/plugins/observability/public/locators/slo_list.test.ts b/x-pack/plugins/observability/public/locators/slo_list.test.ts index f12bab21f6dd..68bf2c2589fe 100644 --- a/x-pack/plugins/observability/public/locators/slo_list.test.ts +++ b/x-pack/plugins/observability/public/locators/slo_list.test.ts @@ -14,7 +14,7 @@ describe('SloListLocator', () => { const location = await locator.getLocation({}); expect(location.app).toEqual('observability'); expect(location.path).toEqual( - "/slos?search=(kqlQuery:'',page:0,sort:(by:status,direction:desc))" + "/slos?search=(kqlQuery:'',page:0,sort:(by:status,direction:desc),viewMode:compact)" ); }); @@ -24,7 +24,7 @@ describe('SloListLocator', () => { }); expect(location.app).toEqual('observability'); expect(location.path).toEqual( - "/slos?search=(kqlQuery:'slo.name:%20%22Service%20Availability%22%20and%20slo.indicator.type%20:%20%22sli.kql.custom%22',page:0,sort:(by:status,direction:desc))" + "/slos?search=(kqlQuery:'slo.name:%20%22Service%20Availability%22%20and%20slo.indicator.type%20:%20%22sli.kql.custom%22',page:0,sort:(by:status,direction:desc),viewMode:compact)" ); }); }); diff --git a/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx b/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx index dfb1f571b6d4..756f90ecd97c 100644 --- a/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx @@ -76,16 +76,6 @@ jest.mock('../../hooks/use_fetch_rule', () => { }; }); jest.mock('@kbn/observability-shared-plugin/public'); -jest.mock('../../hooks/use_get_user_cases_permissions', () => ({ - useGetUserCasesPermissions: () => ({ - all: true, - create: true, - delete: true, - push: true, - read: true, - update: true, - }), -})); const useFetchAlertDetailMock = useFetchAlertDetail as jest.Mock; const useParamsMock = useParams as jest.Mock; diff --git a/x-pack/plugins/observability/public/pages/alert_details/alert_details.tsx b/x-pack/plugins/observability/public/pages/alert_details/alert_details.tsx index a7661ba43fdd..06da477896c5 100644 --- a/x-pack/plugins/observability/public/pages/alert_details/alert_details.tsx +++ b/x-pack/plugins/observability/public/pages/alert_details/alert_details.tsx @@ -58,7 +58,7 @@ export function AlertDetails() { const [isLoading, alert] = useFetchAlertDetail(alertId); const [ruleTypeModel, setRuleTypeModel] = useState(null); const CasesContext = getCasesContext(); - const userCasesPermissions = canUseCases(); + const userCasesPermissions = canUseCases([observabilityFeatureId]); const { rule } = useFetchRule({ ruleId: alert?.fields[ALERT_RULE_UUID], }); diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx index 9e80d01ed82e..c1b1493daa3d 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts.tsx @@ -19,12 +19,10 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { rulesLocatorID } from '../../../common'; import { RulesParams } from '../../locators/rules'; import { useKibana } from '../../utils/kibana_react'; -import { useHasData } from '../../hooks/use_has_data'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useTimeBuckets } from '../../hooks/use_time_buckets'; import { useGetFilteredRuleTypes } from '../../hooks/use_get_filtered_rule_types'; import { useToasts } from '../../hooks/use_toast'; -import { LoadingObservability } from '../../components/loading_observability'; import { renderRuleStats, RuleStatsState } from './components/rule_stats'; import { ObservabilityAlertSearchBar } from '../../components/alert_search_bar/alert_search_bar'; import { @@ -94,7 +92,6 @@ function InternalAlertsPage() { error: 0, snoozed: 0, }); - const { hasAnyData, isAllRequestsComplete } = useHasData(); const [esQuery, setEsQuery] = useState<{ bool: BoolQuery }>(); const timeBuckets = useTimeBuckets(); const bucketSize = useMemo( @@ -173,10 +170,6 @@ function InternalAlertsPage() { const manageRulesHref = http.basePath.prepend('/app/observability/alerts/rules'); - if (!hasAnyData && !isAllRequestsComplete) { - return ; - } - return ( ({ __esModule: true, useKibana: jest.fn(() => mockUseKibanaReturnValue), })); -jest.mock('../../../hooks/use_get_user_cases_permissions', () => ({ - useGetUserCasesPermissions: jest.fn(() => ({ create: true, read: true })), -})); - jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana/kibana_react', () => ({ useKibana: jest.fn(() => ({ services: { notifications: { toasts: { addDanger: jest.fn(), addSuccess: jest.fn() } } }, @@ -175,4 +174,18 @@ describe('ObservabilityActions component', () => { expect(refresh).toHaveBeenCalled(); }); + + it('should hide the case actions without permissions', async () => { + mockUseKibanaReturnValue.services.cases.helpers.canUseCases.mockReturnValue( + noCasesPermissions() + ); + + const wrapper = await setup('nothing'); + wrapper.find('[data-test-subj="alertsTableRowActionMore"]').hostNodes().simulate('click'); + + expect(wrapper.find('[data-test-subj="add-to-new-case-action"]').hostNodes().length).toBe(0); + expect(wrapper.find('[data-test-subj="add-to-existing-case-action"]').hostNodes().length).toBe( + 0 + ); + }); }); diff --git a/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.tsx b/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.tsx index 779965590890..0f2531f6ff79 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.tsx @@ -14,28 +14,25 @@ import { EuiToolTip, } from '@elastic/eui'; -import React, { useMemo, useState, useCallback } from 'react'; +import React, { useMemo, useState, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public'; import { AttachmentType } from '@kbn/cases-plugin/common'; import { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { TimelineNonEcsData } from '@kbn/timelines-plugin/common'; import { - ALERT_RULE_TYPE_ID, ALERT_RULE_UUID, ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_UUID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, } from '@kbn/rule-data-utils'; import { useBulkUntrackAlerts } from '@kbn/triggers-actions-ui-plugin/public'; import { useKibana } from '../../../utils/kibana_react'; -import { useGetUserCasesPermissions } from '../../../hooks/use_get_user_cases_permissions'; import { isAlertDetailsEnabledPerApp } from '../../../utils/is_alert_details_enabled'; import { parseAlert } from '../helpers/parse_alert'; import { paths } from '../../../../common/locators/paths'; import { RULE_DETAILS_PAGE_ID } from '../../rule_details/constants'; -import type { ObservabilityRuleTypeRegistry } from '../../..'; +import { observabilityFeatureId, ObservabilityRuleTypeRegistry } from '../../..'; import type { ConfigSchema } from '../../../plugin'; import type { TopAlert } from '../../../typings/alerts'; @@ -62,15 +59,16 @@ export function AlertActions({ }: Props) { const { cases: { - helpers: { getRuleIdFromEvent }, + helpers: { getRuleIdFromEvent, canUseCases }, hooks: { useCasesAddToNewCaseFlyout, useCasesAddToExistingCaseModal }, }, http: { basePath: { prepend }, }, } = useKibana().services; - const userCasesPermissions = useGetUserCasesPermissions(); const { mutateAsync: untrackAlerts } = useBulkUntrackAlerts(); + const userCasesPermissions = canUseCases([observabilityFeatureId]); + const [viewInAppUrl, setViewInAppUrl] = useState(); const parseObservabilityAlert = useMemo( () => parseAlert(observabilityRuleTypeRegistry), @@ -80,6 +78,14 @@ export function AlertActions({ const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); const alert = parseObservabilityAlert(dataFieldEs); + useEffect(() => { + if (!alert.hasBasePath) { + setViewInAppUrl(prepend(alert.link ?? '')); + } else { + setViewInAppUrl(alert.link); + } + }, [alert.hasBasePath, alert.link, prepend]); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); const ruleId = alert.fields[ALERT_RULE_UUID] ?? null; @@ -237,10 +243,7 @@ export function AlertActions({ return ( <> - {/* Hide the View In App for the Threshold alerts, temporarily https://github.com/elastic/kibana/pull/159915 */} - {alert.fields[ALERT_RULE_TYPE_ID] === OBSERVABILITY_THRESHOLD_RULE_TYPE_ID ? ( - - ) : ( + {viewInAppUrl ? ( + ) : ( + )} diff --git a/x-pack/plugins/observability/public/pages/cases/cases.tsx b/x-pack/plugins/observability/public/pages/cases/cases.tsx index 5f746bcc4d49..13fc73e90960 100644 --- a/x-pack/plugins/observability/public/pages/cases/cases.tsx +++ b/x-pack/plugins/observability/public/pages/cases/cases.tsx @@ -7,23 +7,17 @@ import React from 'react'; -import { useGetUserCasesPermissions } from '../../hooks/use_get_user_cases_permissions'; +import { observabilityFeatureId } from '../../../common'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { useHasData } from '../../hooks/use_has_data'; import { Cases } from './components/cases'; -import { LoadingObservability } from '../../components/loading_observability'; import { CaseFeatureNoPermissions } from './components/feature_no_permissions'; import { HeaderMenu } from '../overview/components/header_menu/header_menu'; +import { useKibana } from '../../utils/kibana_react'; export function CasesPage() { - const userCasesPermissions = useGetUserCasesPermissions(); const { ObservabilityPageTemplate } = usePluginContext(); - - const { hasAnyData, isAllRequestsComplete } = useHasData(); - - if (!hasAnyData && !isAllRequestsComplete) { - return ; - } + const { canUseCases } = useKibana().services.cases.helpers; + const userCasesPermissions = canUseCases([observabilityFeatureId]); return userCasesPermissions.read ? ( diff --git a/x-pack/plugins/observability/public/pages/cases/components/cases.stories.tsx b/x-pack/plugins/observability/public/pages/cases/components/cases.stories.tsx index d0fc1d01734f..695165d05e1b 100644 --- a/x-pack/plugins/observability/public/pages/cases/components/cases.stories.tsx +++ b/x-pack/plugins/observability/public/pages/cases/components/cases.stories.tsx @@ -27,6 +27,7 @@ const defaultProps: CasesProps = { push: true, update: true, connectors: true, + settings: true, }, }; @@ -43,5 +44,6 @@ CasesPageWithNoPermissions.args = { push: false, update: false, connectors: false, + settings: false, }, }; diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/events_chart_panel.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/events_chart_panel.tsx new file mode 100644 index 000000000000..10655cd98b12 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slo_details/components/events_chart_panel.tsx @@ -0,0 +1,167 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + Axis, + BarSeries, + Chart, + Position, + ScaleType, + Settings, + Tooltip, + TooltipType, +} from '@elastic/charts'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLoadingChart, + EuiPanel, + EuiText, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import numeral from '@elastic/numeral'; +import { useActiveCursor } from '@kbn/charts-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import moment from 'moment'; +import React, { useRef } from 'react'; +import { useGetPreviewData } from '../../../hooks/slo/use_get_preview_data'; +import { useKibana } from '../../../utils/kibana_react'; + +export interface Props { + slo: SLOWithSummaryResponse; + range: { + start: number; + end: number; + }; +} + +export function EventsChartPanel({ slo, range }: Props) { + const { charts, uiSettings } = useKibana().services; + const { euiTheme } = useEuiTheme(); + const { isLoading, data } = useGetPreviewData(true, slo.indicator, range); + const theme = charts.theme.useChartsTheme(); + const baseTheme = charts.theme.useChartsBaseTheme(); + const chartRef = useRef(null); + const handleCursorUpdate = useActiveCursor(charts.activeCursor, chartRef, { + isDateHistogram: true, + }); + + const dateFormat = uiSettings.get('dateFormat'); + + return ( + + + + + +

    + {i18n.translate('xpack.observability.slo.sloDetails.eventsChartPanel.title', { + defaultMessage: 'Good vs bad events', + })} +

    +
    +
    + + + {i18n.translate('xpack.observability.slo.sloDetails.eventsChartPanel.duration', { + defaultMessage: 'Last 24h', + })} + + +
    + + + {isLoading && } + + {!isLoading && ( + + + + } + onPointerUpdate={handleCursorUpdate} + externalPointerEvents={{ + tooltip: { visible: true }, + }} + pointerUpdateDebounce={0} + pointerUpdateTrigger={'x'} + locale={i18n.getLocale()} + /> + + moment(d).format(dateFormat)} + /> + numeral(d).format('0,0')} + /> + + ({ + key: new Date(datum.date).getTime(), + value: datum.events?.good, + })) ?? [] + } + /> + + ({ + key: new Date(datum.date).getTime(), + value: datum.events?.bad, + })) ?? [] + } + /> + + )} + +
    +
    + ); +} diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx index b8c18aa457b4..615edf3ef65f 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx @@ -33,13 +33,14 @@ export interface Props { export function HeaderControl({ isLoading, slo }: Props) { const { - application: { navigateToUrl }, + application: { navigateToUrl, capabilities }, http: { basePath }, share: { url: { locators }, }, triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout }, } = useKibana().services; + const hasApmReadCapabilities = capabilities.apm.show; const { hasWriteCapabilities } = useCapabilities(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -202,6 +203,7 @@ export function HeaderControl({ isLoading, slo }: Props) { diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx index e05c9c7403dd..3bb1ea99ad0c 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx @@ -15,7 +15,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; @@ -23,6 +23,7 @@ import { useFetchHistoricalSummary } from '../../../hooks/slo/use_fetch_historic import { formatHistoricalData } from '../../../utils/slo/chart_data_formatter'; import { BurnRates } from './burn_rates'; import { ErrorBudgetChartPanel } from './error_budget_chart_panel'; +import { EventsChartPanel } from './events_chart_panel'; import { Overview } from './overview/overview'; import { SliChartPanel } from './sli_chart_panel'; import { SloDetailsAlerts } from './slo_detail_alerts'; @@ -35,6 +36,7 @@ export interface Props { const TAB_ID_URL_PARAM = 'tabId'; const OVERVIEW_TAB_ID = 'overview'; const ALERTS_TAB_ID = 'alerts'; +const DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000; type TabId = typeof OVERVIEW_TAB_ID | typeof ALERTS_TAB_ID; @@ -56,6 +58,22 @@ export function SloDetails({ slo, isAutoRefreshing }: Props) { historicalSummary.instanceId === (slo.instanceId ?? ALL_VALUE) ); + const [range, setRange] = useState({ + start: new Date().getTime() - DAY_IN_MILLISECONDS, + end: new Date().getTime(), + }); + + useEffect(() => { + let intervalId: any; + if (isAutoRefreshing) { + intervalId = setInterval(() => { + setRange({ start: new Date().getTime() - DAY_IN_MILLISECONDS, end: new Date().getTime() }); + }, 60 * 1000); + } + + return () => clearInterval(intervalId); + }, [isAutoRefreshing]); + const errorBudgetBurnDownData = formatHistoricalData( sloHistoricalSummary?.data, 'error_budget_remaining' @@ -94,6 +112,11 @@ export function SloDetails({ slo, isAutoRefreshing }: Props) { slo={slo} />
    + {slo.indicator.type !== 'sli.metric.timeslice' ? ( + + + + ) : null} diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx index 4f938a809a82..92ea62f385ab 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { fireEvent, screen, waitFor } from '@testing-library/react'; +import type { Capabilities } from '@kbn/core/public'; import { useKibana } from '../../utils/kibana_react'; import { useParams, useLocation } from 'react-router-dom'; @@ -60,6 +61,9 @@ const mockNavigate = jest.fn(); const mockLocator = jest.fn(); const mockClone = jest.fn(); const mockDelete = jest.fn(); +const mockCapabilities = { + apm: { show: true }, +} as unknown as Capabilities; const mockKibana = () => { useKibanaMock.mockReturnValue({ @@ -68,7 +72,7 @@ const mockKibana = () => { lens: { EmbeddableComponent: () =>
    mocked component
    , }, - application: { navigateToUrl: mockNavigate }, + application: { navigateToUrl: mockNavigate, capabilities: mockCapabilities }, charts: chartPluginMock.createStartContract(), http: { basePath: { @@ -252,7 +256,6 @@ describe('SLO Details Page', () => { settings, updatedAt, instanceId, - version, ...newSlo } = slo; diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_common/field_selector.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_common/field_selector.tsx index 74176db75c54..e41e51a7361e 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_common/field_selector.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_common/field_selector.tsx @@ -65,6 +65,8 @@ export function FieldSelector({ : [] ).concat(createOptions(suggestions)); + const isDisabled = name !== 'indicator.params.service' && !serviceName; + return ( ( { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/data_preview_chart.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/data_preview_chart.tsx index 7dc2e00f6082..dfa52e6e572a 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/data_preview_chart.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/data_preview_chart.tsx @@ -29,11 +29,11 @@ import { } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { max, min } from 'lodash'; import moment from 'moment'; -import React from 'react'; +import React, { useState } from 'react'; import { useFormContext } from 'react-hook-form'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { min, max } from 'lodash'; import { useKibana } from '../../../../utils/kibana_react'; import { useDebouncedGetPreviewData } from '../../hooks/use_preview'; import { useSectionFormValidation } from '../../hooks/use_section_form_validation'; @@ -47,6 +47,8 @@ interface DataPreviewChartProps { thresholdMessage?: string; } +const ONE_HOUR_IN_MILLISECONDS = 1 * 60 * 60 * 1000; + export function DataPreviewChart({ formatPattern, threshold, @@ -63,12 +65,17 @@ export function DataPreviewChart({ watch, }); + const [range, _] = useState({ + start: new Date().getTime() - ONE_HOUR_IN_MILLISECONDS, + end: new Date().getTime(), + }); + const { data: previewData, isLoading: isPreviewLoading, isSuccess, isError, - } = useDebouncedGetPreviewData(isIndicatorSectionValid, watch('indicator')); + } = useDebouncedGetPreviewData(isIndicatorSectionValid, watch('indicator'), range); const theme = charts.theme.useChartsTheme(); const baseTheme = charts.theme.useChartsBaseTheme(); diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx index 936d39dfa9b9..367ff255edde 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx @@ -46,7 +46,7 @@ export function IndexFieldSelector({ defaultValue={defaultValue} name={name} control={control} - rules={{ required: isRequired }} + rules={{ required: isRequired && !isDisabled }} render={({ field, fieldState }) => ( {...field} diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx index 6c5d4dce730b..05b58ab2aa19 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx @@ -32,22 +32,20 @@ export function CustomKqlIndicatorTypeForm() { - - - + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_preview.ts b/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_preview.ts index 72cad2455525..0aa79a391433 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_preview.ts +++ b/x-pack/plugins/observability/public/pages/slo_edit/hooks/use_preview.ts @@ -10,7 +10,11 @@ import { debounce } from 'lodash'; import { useCallback, useEffect, useState } from 'react'; import { useGetPreviewData } from '../../../hooks/slo/use_get_preview_data'; -export function useDebouncedGetPreviewData(isIndicatorValid: boolean, indicator: Indicator) { +export function useDebouncedGetPreviewData( + isIndicatorValid: boolean, + indicator: Indicator, + range: { start: number; end: number } +) { const serializedIndicator = JSON.stringify(indicator); const [indicatorState, setIndicatorState] = useState(serializedIndicator); @@ -25,5 +29,5 @@ export function useDebouncedGetPreviewData(isIndicatorValid: boolean, indicator: } }, [indicatorState, serializedIndicator, store]); - return useGetPreviewData(isIndicatorValid, JSON.parse(indicatorState)); + return useGetPreviewData(isIndicatorValid, JSON.parse(indicatorState), range); } diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.stories.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.stories.tsx index 267ebac0ce9b..67869e7f0e76 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.stories.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.stories.tsx @@ -11,7 +11,7 @@ import { ComponentStory } from '@storybook/react'; import { EuiFlexGroup } from '@elastic/eui'; import { buildForecastedSlo } from '../../../../data/slo/slo'; import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; -import { SloBadges as Component, Props } from './slo_badges'; +import { SloBadges as Component, SloBadgesProps } from './slo_badges'; export default { component: Component, @@ -19,7 +19,7 @@ export default { decorators: [KibanaReactStorybookDecorator], }; -const Template: ComponentStory = (props: Props) => ( +const Template: ComponentStory = (props: SloBadgesProps) => ( diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.tsx index deccd010205a..9ff1e3c14a2b 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_badges.tsx @@ -17,8 +17,9 @@ import { SloTimeWindowBadge } from './slo_time_window_badge'; import { SloRulesBadge } from './slo_rules_badge'; import type { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo'; import { SloGroupByBadge } from '../../../../components/slo/slo_status_badge/slo_group_by_badge'; +export type ViewMode = 'default' | 'compact'; -export interface Props { +export interface SloBadgesProps { activeAlerts?: number; isLoading: boolean; rules: Array> | undefined; @@ -26,33 +27,17 @@ export interface Props { onClickRuleBadge: () => void; } -export function SloBadges({ activeAlerts, isLoading, rules, slo, onClickRuleBadge }: Props) { +export function SloBadges({ + activeAlerts, + isLoading, + rules, + slo, + onClickRuleBadge, +}: SloBadgesProps) { return ( {isLoading ? ( - <> - - - - + ) : ( <> @@ -66,3 +51,31 @@ export function SloBadges({ activeAlerts, isLoading, rules, slo, onClickRuleBadg ); } + +export function LoadingBadges() { + return ( + <> + + + + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx index ad73af3d73bf..c85eb6776680 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx @@ -6,21 +6,22 @@ */ import React from 'react'; -import { EuiBadge, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { EuiBadge, EuiFlexItem, EuiToolTip, EuiBadgeProps } from '@elastic/eui'; import { SLOWithSummaryResponse } from '@kbn/slo-schema'; -import { euiLightVars } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; +import { euiLightVars } from '@kbn/ui-theme'; import { useKibana } from '../../../../utils/kibana_react'; import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url'; import { isApmIndicatorType } from '../../../../utils/slo/indicator'; import { toIndicatorTypeLabel } from '../../../../utils/slo/labels'; export interface Props { + color?: EuiBadgeProps['color']; slo: SLOWithSummaryResponse; } -export function SloIndicatorTypeBadge({ slo }: Props) { +export function SloIndicatorTypeBadge({ slo, color }: Props) { const { application: { navigateToUrl }, http: { basePath }, @@ -54,7 +55,7 @@ export function SloIndicatorTypeBadge({ slo }: Props) { return ( <> - + {toIndicatorTypeLabel(slo.indicator.type)} @@ -68,7 +69,7 @@ export function SloIndicatorTypeBadge({ slo }: Props) { })} > - +
    ); diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_time_window_badge.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_time_window_badge.tsx index d218eeda7f0e..b5d4ecd0224f 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_time_window_badge.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_time_window_badge.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiBadge, EuiFlexItem } from '@elastic/eui'; +import { EuiBadge, EuiBadgeProps, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { rollingTimeWindowTypeSchema, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { euiLightVars } from '@kbn/ui-theme'; @@ -15,16 +15,17 @@ import { toCalendarAlignedMomentUnitOfTime } from '../../../../utils/slo/duratio import { toDurationLabel } from '../../../../utils/slo/labels'; export interface Props { + color?: EuiBadgeProps['color']; slo: SLOWithSummaryResponse; } -export function SloTimeWindowBadge({ slo }: Props) { +export function SloTimeWindowBadge({ slo, color }: Props) { const unit = slo.timeWindow.duration.slice(-1); if (rollingTimeWindowTypeSchema.is(slo.timeWindow.type)) { return ( @@ -45,7 +46,7 @@ export function SloTimeWindowBadge({ slo }: Props) { return ( - + {i18n.translate('xpack.observability.slo.slo.timeWindow.calendar', { defaultMessage: '{elapsed}/{total} days', values: { diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/badges_portal.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/badges_portal.tsx new file mode 100644 index 000000000000..aace661240d2 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/badges_portal.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactNode, useEffect, useMemo } from 'react'; +import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; +import ReactDOM from 'react-dom'; +export interface Props { + children: ReactNode; + containerRef: React.RefObject; +} + +export function SloCardBadgesPortal({ children, containerRef }: Props) { + const portalNode = useMemo(() => createHtmlPortalNode(), []); + + useEffect(() => { + if (containerRef?.current) { + setTimeout(() => { + const gapDiv = containerRef?.current?.querySelector('.echMetricText__gap'); + if (!gapDiv) return; + ReactDOM.render(, gapDiv); + }, 100); + } + + return () => { + portalNode.unmount(); + }; + }, [portalNode, containerRef]); + + return {children}; +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/cards_per_row.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/cards_per_row.tsx new file mode 100644 index 000000000000..04e787d7b353 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/cards_per_row.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; + +export const SLO_CARD_VIEW_PER_ROW_SIZE = 'slo-card-view-per-row-size'; + +export function CardsPerRow({ + setCardsPerRow, +}: { + setCardsPerRow: (cardsPerRow?: string) => void; +}) { + const [value, setValue] = useLocalStorage(SLO_CARD_VIEW_PER_ROW_SIZE, '3'); + + useEffect(() => { + setCardsPerRow(value); + }, [setCardsPerRow, value]); + + const options = [ + { value: '3', text: '3' }, + { value: '4', text: '4' }, + ]; + + return ( + + } + > + setValue(e.target.value)} + /> + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx new file mode 100644 index 000000000000..ac649a71e360 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + Chart, + DARK_THEME, + isMetricElementEvent, + Metric, + MetricTrendShape, + Settings, +} from '@elastic/charts'; +import { EuiIcon, EuiPanel, useEuiBackgroundColor } from '@elastic/eui'; +import { ALL_VALUE, HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { SloCardBadgesPortal } from './badges_portal'; +import { useSloListActions } from '../../hooks/use_slo_list_actions'; +import { BurnRateRuleFlyout } from '../common/burn_rate_rule_flyout'; +import { formatHistoricalData } from '../../../../utils/slo/chart_data_formatter'; +import { useKibana } from '../../../../utils/kibana_react'; +import { useSloFormattedSummary } from '../../hooks/use_slo_summary'; +import { SloCardItemActions } from './slo_card_item_actions'; +import { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo'; +import { SloDeleteConfirmationModal } from '../../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal'; +import { SloCardItemBadges } from './slo_card_item_badges'; + +export interface Props { + slo: SLOWithSummaryResponse; + rules: Array> | undefined; + historicalSummary?: HistoricalSummaryResponse[]; + historicalSummaryLoading: boolean; + activeAlerts?: number; + loading: boolean; + error: boolean; + cardsPerRow: number; +} + +const useCardColor = (status?: SLOWithSummaryResponse['summary']['status']) => { + const colors = { + DEGRADING: useEuiBackgroundColor('warning'), + VIOLATED: useEuiBackgroundColor('danger'), + HEALTHY: useEuiBackgroundColor('success'), + NO_DATA: useEuiBackgroundColor('subdued'), + }; + + return colors[status ?? 'NO_DATA']; +}; + +const getSubTitle = (slo: SLOWithSummaryResponse, cardsPerRow: number) => { + return slo.groupBy && slo.groupBy !== ALL_VALUE ? `${slo.groupBy}: ${slo.instanceId}` : ''; +}; + +export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cardsPerRow }: Props) { + const { + application: { navigateToUrl }, + } = useKibana().services; + + const containerRef = React.useRef(null); + + const [isMouseOver, setIsMouseOver] = useState(false); + const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); + const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false); + const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false); + + const { sliValue, sloTarget, sloDetailsUrl } = useSloFormattedSummary(slo); + + const cardColor = useCardColor(slo.summary.status); + + const subTitle = getSubTitle(slo, cardsPerRow); + + const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value'); + + const { handleCreateRule, handleDeleteCancel, handleDeleteConfirm } = useSloListActions({ + slo, + setDeleteConfirmationModalOpen, + setIsActionsPopoverOpen, + setIsAddRuleFlyoutOpen, + }); + + return ( + <> + } + onMouseOver={() => { + if (!isMouseOver) { + setIsMouseOver(true); + } + }} + onMouseLeave={() => { + if (isMouseOver) { + setIsMouseOver(false); + } + }} + paddingSize="none" + style={{ + height: '182px', + overflow: 'hidden', + position: 'relative', + }} + title={slo.summary.status} + > + + { + if (isMetricElementEvent(d)) { + navigateToUrl(sloDetailsUrl); + } + }} + locale={i18n.getLocale()} + /> + ({ + x: d.key as number, + y: d.value as number, + })), + extra: ( + + ), + icon: () => , + color: cardColor, + }, + ], + ]} + /> + + {(isMouseOver || isActionsPopoverOpen) && ( + + )} + + + + + + + + {isDeleteConfirmationModalOpen ? ( + + ) : null} + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx new file mode 100644 index 000000000000..51d1887d433f --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import styled from 'styled-components'; +import { useEuiShadow } from '@elastic/eui'; +import { SloItemActions } from '../slo_item_actions'; + +type PopoverPosition = 'relative' | 'default'; + +interface ActionContainerProps { + boxShadow: string; + position: PopoverPosition; +} + +const Container = styled.div` + ${({ position }) => + position === 'relative' + ? // custom styles used to overlay the popover button on `MetricItem` + ` + display: inline-block; + position: relative; + bottom: 42px; + left: 12px; + z-index: 1; +` + : // otherwise, no custom position needed + ''} + + border-radius: ${({ theme }) => theme.eui.euiBorderRadius}; + ${({ boxShadow, position }) => (position === 'relative' ? boxShadow : '')} +`; + +interface Props { + slo: SLOWithSummaryResponse; + isActionsPopoverOpen: boolean; + setIsActionsPopoverOpen: (value: boolean) => void; + setDeleteConfirmationModalOpen: (value: boolean) => void; + setIsAddRuleFlyoutOpen: (value: boolean) => void; +} + +export function SloCardItemActions(props: Props) { + const euiShadow = useEuiShadow('l'); + + return ( + + + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx new file mode 100644 index 000000000000..4a3663b0a8c5 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import React from 'react'; +import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; +import styled from 'styled-components'; +import { EuiFlexGroup } from '@elastic/eui'; +import { LoadingBadges } from '../badges/slo_badges'; +import { SloIndicatorTypeBadge } from '../badges/slo_indicator_type_badge'; +import { SloTimeWindowBadge } from '../badges/slo_time_window_badge'; +import { SloActiveAlertsBadge } from '../../../../components/slo/slo_status_badge/slo_active_alerts_badge'; +import { SloRulesBadge } from '../badges/slo_rules_badge'; +import { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo'; + +interface Props { + hasGroupBy: boolean; + activeAlerts?: number; + slo: SLOWithSummaryResponse; + rules: Array> | undefined; + handleCreateRule: () => void; +} + +const Container = styled.div` + display: inline-block; + margin-top: 5px; +`; + +export function SloCardItemBadges({ slo, activeAlerts, rules, handleCreateRule }: Props) { + return ( + + + {!slo.summary ? ( + + ) : ( + <> + + + + + + )} + + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx new file mode 100644 index 000000000000..4e4df93967fd --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFlexGrid, + EuiFlexItem, + EuiPanel, + EuiSkeletonText, + useIsWithinBreakpoints, +} from '@elastic/eui'; +import { SLOWithSummaryResponse, ALL_VALUE } from '@kbn/slo-schema'; +import { EuiFlexGridProps } from '@elastic/eui/src/components/flex/flex_grid'; +import { ActiveAlerts } from '../../../../hooks/slo/use_fetch_active_alerts'; +import type { UseFetchRulesForSloResponse } from '../../../../hooks/slo/use_fetch_rules_for_slo'; +import { useFetchHistoricalSummary } from '../../../../hooks/slo/use_fetch_historical_summary'; +import { SloCardItem } from './slo_card_item'; + +export interface Props { + sloList: SLOWithSummaryResponse[]; + loading: boolean; + error: boolean; + cardsPerRow?: string; + activeAlertsBySlo: ActiveAlerts; + rulesBySlo?: UseFetchRulesForSloResponse['data']; +} + +const useColumns = (cardsPerRow: string | undefined) => { + const isMobile = useIsWithinBreakpoints(['xs', 's']); + const isMedium = useIsWithinBreakpoints(['m']); + const isLarge = useIsWithinBreakpoints(['l']); + + const columns = (Number(cardsPerRow) as EuiFlexGridProps['columns']) ?? 3; + + switch (true) { + case isMobile: + return 1; + case isMedium: + return columns > 2 ? 2 : columns; + case isLarge: + return columns > 3 ? 3 : columns; + default: + return columns; + } +}; + +export function SloListCardView({ + sloList, + loading, + error, + cardsPerRow, + rulesBySlo, + activeAlertsBySlo, +}: Props) { + const { isLoading: historicalSummaryLoading, data: historicalSummaries = [] } = + useFetchHistoricalSummary({ + list: sloList.map((slo) => ({ sloId: slo.id, instanceId: slo.instanceId ?? ALL_VALUE })), + }); + + const columns = useColumns(cardsPerRow); + + if (loading && sloList.length === 0) { + return ; + } + + return ( + + {sloList.map((slo) => ( + + + historicalSummary.sloId === slo.id && + historicalSummary.instanceId === (slo.instanceId ?? ALL_VALUE) + )?.data + } + historicalSummaryLoading={historicalSummaryLoading} + cardsPerRow={Number(cardsPerRow)} + /> + + ))} + + ); +} + +function LoadingSloGrid({ gridSize }: { gridSize: number }) { + const ROWS = 4; + const COLUMNS = gridSize; + const loaders = Array(ROWS * COLUMNS).fill(null); + return ( + <> + + {loaders.map((_, i) => ( + + + + {' '} + + ))} + + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx b/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx new file mode 100644 index 000000000000..a02730231ae5 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { useQueryClient } from '@tanstack/react-query'; +import { useGetFilteredRuleTypes } from '../../../../hooks/use_get_filtered_rule_types'; +import { sloKeys } from '../../../../hooks/slo/query_key_factory'; +import { useKibana } from '../../../../utils/kibana_react'; +import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../../common/constants'; +import { sloFeatureId } from '../../../../../common'; + +export function BurnRateRuleFlyout({ + slo, + isAddRuleFlyoutOpen, + setIsAddRuleFlyoutOpen, +}: { + slo: SLOWithSummaryResponse; + isAddRuleFlyoutOpen: boolean; + setIsAddRuleFlyoutOpen: (value: boolean) => void; +}) { + const { + triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout }, + } = useKibana().services; + + const filteredRuleTypes = useGetFilteredRuleTypes(); + + const queryClient = useQueryClient(); + + const handleSavedRule = async () => { + queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); + }; + + return isAddRuleFlyoutOpen ? ( + { + setIsAddRuleFlyoutOpen(false); + }} + useRuleProducer + /> + ) : null; +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx new file mode 100644 index 000000000000..4fb03968d40a --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx @@ -0,0 +1,217 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiButtonIcon, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiPopover, + EuiButtonIconProps, + useEuiShadow, + EuiPanel, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import styled from 'styled-components'; +import { useCapabilities } from '../../../hooks/slo/use_capabilities'; +import { useCloneSlo } from '../../../hooks/slo/use_clone_slo'; +import { useKibana } from '../../../utils/kibana_react'; +import { paths } from '../../../../common/locators/paths'; +import { RulesParams } from '../../../locators/rules'; +import { rulesLocatorID } from '../../../../common'; +import { + transformCreateSLOFormToCreateSLOInput, + transformSloResponseToCreateSloForm, +} from '../../slo_edit/helpers/process_slo_form_values'; + +interface Props { + slo: SLOWithSummaryResponse; + isActionsPopoverOpen: boolean; + setIsActionsPopoverOpen: (value: boolean) => void; + setDeleteConfirmationModalOpen: (value: boolean) => void; + setIsAddRuleFlyoutOpen: (value: boolean) => void; + btnProps?: Partial; +} +const CustomShadowPanel = styled(EuiPanel)<{ shadow: string }>` + ${(props) => props.shadow} +`; + +function IconPanel({ children, hasPanel }: { children: JSX.Element; hasPanel: boolean }) { + const shadow = useEuiShadow('s'); + if (!hasPanel) return children; + return ( + + {children} + + ); +} + +export function SloItemActions({ + slo, + isActionsPopoverOpen, + setIsActionsPopoverOpen, + setIsAddRuleFlyoutOpen, + setDeleteConfirmationModalOpen, + btnProps, +}: Props) { + const { + application: { navigateToUrl }, + http: { basePath }, + share: { + url: { locators }, + }, + } = useKibana().services; + const { hasWriteCapabilities } = useCapabilities(); + const { mutate: cloneSlo } = useCloneSlo(); + + const sloDetailsUrl = basePath.prepend( + paths.observability.sloDetails( + slo.id, + slo.groupBy !== ALL_VALUE && slo.instanceId ? slo.instanceId : undefined + ) + ); + + const handleClickActions = () => { + setIsActionsPopoverOpen(!isActionsPopoverOpen); + }; + + const handleViewDetails = () => { + navigateToUrl(sloDetailsUrl); + }; + + const handleEdit = () => { + navigateToUrl(basePath.prepend(paths.observability.sloEdit(slo.id))); + }; + + const handleNavigateToRules = async () => { + const locator = locators.get(rulesLocatorID); + locator?.navigate({ params: { sloId: slo.id } }, { replace: false }); + }; + + const handleClone = () => { + const newSlo = transformCreateSLOFormToCreateSLOInput( + transformSloResponseToCreateSloForm({ ...slo, name: `[Copy] ${slo.name}` })! + ); + + cloneSlo({ slo: newSlo, originalSloId: slo.id }); + setIsActionsPopoverOpen(false); + }; + + const handleDelete = () => { + setDeleteConfirmationModalOpen(true); + setIsActionsPopoverOpen(false); + }; + + const handleCreateRule = () => { + setIsActionsPopoverOpen(false); + setIsAddRuleFlyoutOpen(true); + }; + + const btn = ( + + ); + + return ( + {btn} : btn} + panelPaddingSize="m" + closePopover={handleClickActions} + isOpen={isActionsPopoverOpen} + > + + {i18n.translate('xpack.observability.slo.item.actions.details', { + defaultMessage: 'Details', + })} + , + + {i18n.translate('xpack.observability.slo.item.actions.edit', { + defaultMessage: 'Edit', + })} + , + + {i18n.translate('xpack.observability.slo.item.actions.createRule', { + defaultMessage: 'Create new alert rule', + })} + , + + {i18n.translate('xpack.observability.slo.item.actions.manageRules', { + defaultMessage: 'Manage rules', + })} + , + + {i18n.translate('xpack.observability.slo.item.actions.clone', { + defaultMessage: 'Clone', + })} + , + + {i18n.translate('xpack.observability.slo.item.actions.delete', { + defaultMessage: 'Delete', + })} + , + ]} + /> + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx index 380d0100db1a..ee1fff8e17c1 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list.tsx @@ -8,9 +8,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiPagination } from '@elastic/eui'; import { useIsMutating } from '@tanstack/react-query'; import React, { useState } from 'react'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { SlosView } from './slos_view'; +import { SLO_CARD_VIEW_PER_ROW_SIZE } from './card_view/cards_per_row'; +import { SLOViewType, ToggleSLOView } from './toggle_slo_view'; import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list'; import { useUrlSearchState } from '../hooks/use_url_search_state'; -import { SloListItems } from './slo_list_items'; import { SloListSearchBar, SortField } from './slo_list_search_bar'; export interface Props { @@ -24,6 +27,8 @@ export function SloList({ autoRefresh }: Props) { const [sort, setSort] = useState(state.sort.by); const [direction] = useState<'asc' | 'desc'>(state.sort.direction); + const [sloView, setSLOView] = useState('cardView'); + const { isLoading, isRefetching, @@ -43,6 +48,7 @@ export function SloList({ autoRefresh }: Props) { const isCloningSlo = Boolean(useIsMutating(['cloningSlo'])); const isUpdatingSlo = Boolean(useIsMutating(['updatingSlo'])); const isDeletingSlo = Boolean(useIsMutating(['deleteSlo'])); + const [cardsPerRow, setCardsPerRow] = useLocalStorage(SLO_CARD_VIEW_PER_ROW_SIZE, '4'); const handlePageClick = (pageNumber: number) => { setPage(pageNumber); @@ -71,9 +77,16 @@ export function SloList({ autoRefresh }: Props) { initialState={state} /> - - + + + {total > 0 ? ( diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx index ae843977a0ee..90757be5dc7a 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx @@ -5,37 +5,16 @@ * 2.0. */ -import { - EuiButtonIcon, - EuiContextMenuItem, - EuiContextMenuPanel, - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiPopover, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { ALL_VALUE, HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; +import { HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; -import { useQueryClient } from '@tanstack/react-query'; import React, { useState } from 'react'; +import { useSloFormattedSummary } from '../hooks/use_slo_summary'; +import { BurnRateRuleFlyout } from './common/burn_rate_rule_flyout'; +import { useSloListActions } from '../hooks/use_slo_list_actions'; +import { SloItemActions } from './slo_item_actions'; import { SloDeleteConfirmationModal } from '../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal'; -import { rulesLocatorID, sloFeatureId } from '../../../../common'; -import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../common/constants'; -import { paths } from '../../../../common/locators/paths'; -import { sloKeys } from '../../../hooks/slo/query_key_factory'; -import { useCapabilities } from '../../../hooks/slo/use_capabilities'; -import { useCloneSlo } from '../../../hooks/slo/use_clone_slo'; -import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo'; import type { SloRule } from '../../../hooks/slo/use_fetch_rules_for_slo'; -import { useGetFilteredRuleTypes } from '../../../hooks/use_get_filtered_rule_types'; -import type { RulesParams } from '../../../locators/rules'; -import { useKibana } from '../../../utils/kibana_react'; -import { - transformCreateSLOFormToCreateSLOInput, - transformSloResponseToCreateSloForm, -} from '../../slo_edit/helpers/process_slo_form_values'; import { SloBadges } from './badges/slo_badges'; import { SloSummary } from './slo_summary'; @@ -54,80 +33,18 @@ export function SloListItem({ historicalSummaryLoading, activeAlerts, }: SloListItemProps) { - const { - application: { navigateToUrl }, - http: { basePath }, - share: { - url: { locators }, - }, - triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout }, - } = useKibana().services; - const { hasWriteCapabilities } = useCapabilities(); - const queryClient = useQueryClient(); - - const filteredRuleTypes = useGetFilteredRuleTypes(); - - const { mutate: cloneSlo } = useCloneSlo(); - const { mutate: deleteSlo } = useDeleteSlo(); - const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false); const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false); - const handleClickActions = () => { - setIsActionsPopoverOpen(!isActionsPopoverOpen); - }; - - const sloDetailsUrl = basePath.prepend( - paths.observability.sloDetails( - slo.id, - slo.groupBy !== ALL_VALUE && slo.instanceId ? slo.instanceId : undefined - ) - ); - const handleViewDetails = () => { - navigateToUrl(sloDetailsUrl); - }; - - const handleEdit = () => { - navigateToUrl(basePath.prepend(paths.observability.sloEdit(slo.id))); - }; - - const handleCreateRule = () => { - setIsActionsPopoverOpen(false); - setIsAddRuleFlyoutOpen(true); - }; - - const handleSavedRule = async () => { - queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); - }; + const { sloDetailsUrl } = useSloFormattedSummary(slo); - const handleNavigateToRules = async () => { - const locator = locators.get(rulesLocatorID); - locator?.navigate({ params: { sloId: slo.id } }, { replace: false }); - }; - - const handleClone = () => { - const newSlo = transformCreateSLOFormToCreateSLOInput( - transformSloResponseToCreateSloForm({ ...slo, name: `[Copy] ${slo.name}` })! - ); - - cloneSlo({ slo: newSlo, originalSloId: slo.id }); - setIsActionsPopoverOpen(false); - }; - - const handleDelete = () => { - setDeleteConfirmationModalOpen(true); - setIsActionsPopoverOpen(false); - }; - - const handleDeleteConfirm = () => { - setDeleteConfirmationModalOpen(false); - deleteSlo({ id: slo.id, name: slo.name }); - }; - - const handleDeleteCancel = () => { - setDeleteConfirmationModalOpen(false); - }; + const { handleCreateRule, handleDeleteCancel, handleDeleteConfirm } = useSloListActions({ + slo, + setDeleteConfirmationModalOpen, + setIsActionsPopoverOpen, + setIsAddRuleFlyoutOpen, + }); return ( @@ -172,113 +89,21 @@ export function SloListItem({ {/* ACTIONS */} - - } - panelPaddingSize="m" - closePopover={handleClickActions} - isOpen={isActionsPopoverOpen} - > - - {i18n.translate('xpack.observability.slo.item.actions.details', { - defaultMessage: 'Details', - })} - , - - {i18n.translate('xpack.observability.slo.item.actions.edit', { - defaultMessage: 'Edit', - })} - , - - {i18n.translate('xpack.observability.slo.item.actions.createRule', { - defaultMessage: 'Create new alert rule', - })} - , - - {i18n.translate('xpack.observability.slo.item.actions.manageRules', { - defaultMessage: 'Manage rules', - })} - , - - {i18n.translate('xpack.observability.slo.item.actions.clone', { - defaultMessage: 'Clone', - })} - , - - {i18n.translate('xpack.observability.slo.item.actions.delete', { - defaultMessage: 'Delete', - })} - , - ]} - /> - + - {isAddRuleFlyoutOpen ? ( - { - setIsAddRuleFlyoutOpen(false); - }} - useRuleProducer - /> - ) : null} + {isDeleteConfirmationModalOpen ? ( = (props: Props) => [slo.id, slo.instanceId ?? ALL_VALUE] as [string, string] - ); - - const { data: activeAlertsBySlo } = useFetchActiveAlerts({ sloIdsAndInstanceIds }); - const { data: rulesBySlo } = useFetchRulesForSlo({ - sloIds: sloIdsAndInstanceIds.map((item) => item[0]), - }); +export function SloListItems({ sloList, activeAlertsBySlo, rulesBySlo }: Props) { const { isLoading: historicalSummaryLoading, data: historicalSummaries = [] } = useFetchHistoricalSummary({ list: sloList.map((slo) => ({ sloId: slo.id, instanceId: slo.instanceId ?? ALL_VALUE })), }); - if (!loading && !error && sloList.length === 0) { - return ; - } - if (!loading && error) { - return ; - } - return ( {sloList.map((slo) => ( diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx index 401118e3c8df..77d23d6301ae 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_summary.tsx @@ -6,13 +6,11 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui'; -import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; import { HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; -import { useKibana } from '../../../utils/kibana_react'; +import { useSloFormattedSummary } from '../hooks/use_slo_summary'; import { formatHistoricalData } from '../../../utils/slo/chart_data_formatter'; -import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; import { SloSparkline } from './slo_sparkline'; export interface Props { @@ -22,18 +20,12 @@ export interface Props { } export function SloSummary({ slo, historicalSummary = [], historicalSummaryLoading }: Props) { - const { uiSettings } = useKibana().services; - const percentFormat = uiSettings.get('format:percent:defaultPattern'); + const { sliValue, sloTarget, errorBudgetRemaining } = useSloFormattedSummary(slo); const isSloFailed = slo.summary.status === 'VIOLATED' || slo.summary.status === 'DEGRADING'; const titleColor = isSloFailed ? 'danger' : ''; const errorBudgetBurnDownData = formatHistoricalData(historicalSummary, 'error_budget_remaining'); const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value'); - const errorBudgetRemaining = - slo.summary.errorBudget.remaining <= 0 - ? Math.trunc(slo.summary.errorBudget.remaining * 100) / 100 - : slo.summary.errorBudget.remaining; - return ( @@ -48,13 +40,9 @@ export function SloSummary({ slo, historicalSummary = [], historicalSummaryLoadi [slo.id, slo.instanceId ?? ALL_VALUE] as [string, string] + ); + + const { data: activeAlertsBySlo } = useFetchActiveAlerts({ sloIdsAndInstanceIds }); + const { data: rulesBySlo } = useFetchRulesForSlo({ + sloIds: sloIdsAndInstanceIds.map((item) => item[0]), + }); + + if (!loading && !error && sloList.length === 0) { + return ; + } + if (!loading && error) { + return ; + } + + return sloView === 'cardView' ? ( + + + + ) : ( + + + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx new file mode 100644 index 000000000000..43b5d849b2e0 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/components/toggle_slo_view.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { + EuiButtonGroup, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiPopoverTitle, +} from '@elastic/eui'; +import { CardsPerRow } from './card_view/cards_per_row'; + +export type SLOViewType = 'cardView' | 'listView'; + +interface Props { + setCardsPerRow: (gridSize?: string) => void; + setSLOView: (view: SLOViewType) => void; + sloView: SLOViewType; +} +const toggleButtonsIcons = [ + { + id: `cardView`, + label: 'Card View', + iconType: 'visGauge', + 'data-test-subj': 'sloCardViewButton', + }, + { + id: `listView`, + label: 'List View', + iconType: 'list', + 'data-test-subj': 'sloListViewButton', + }, +]; + +export function ToggleSLOView({ sloView, setSLOView, setCardsPerRow }: Props) { + return ( + + + setSLOView(id as SLOViewType)} + isIconOnly + /> + + {sloView === 'cardView' && ( + + + + )} + + ); +} + +function ViewSettings({ setCardsPerRow }: { setCardsPerRow: (cardsPerRow?: string) => void }) { + const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); + + return ( + setIsPopoverOpen(!isPopoverOpen)} + /> + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + anchorPosition="downCenter" + > + + + +
    + +
    +
    + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts new file mode 100644 index 000000000000..169e1e54c522 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo'; + +export function useSloListActions({ + slo, + setIsAddRuleFlyoutOpen, + setIsActionsPopoverOpen, + setDeleteConfirmationModalOpen, +}: { + slo: SLOWithSummaryResponse; + setIsActionsPopoverOpen: (val: boolean) => void; + setIsAddRuleFlyoutOpen: (val: boolean) => void; + setDeleteConfirmationModalOpen: (val: boolean) => void; +}) { + const { mutate: deleteSlo } = useDeleteSlo(); + + const handleDeleteConfirm = () => { + setDeleteConfirmationModalOpen(false); + deleteSlo({ id: slo.id, name: slo.name }); + }; + + const handleDeleteCancel = () => { + setDeleteConfirmationModalOpen(false); + }; + const handleCreateRule = () => { + setIsActionsPopoverOpen(false); + setIsAddRuleFlyoutOpen(true); + }; + + return { + handleDeleteConfirm, + handleDeleteCancel, + handleCreateRule, + }; +} diff --git a/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_summary.ts b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_summary.ts new file mode 100644 index 000000000000..547bd41b4f5d --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_summary.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import numeral from '@elastic/numeral'; +import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { paths } from '../../../../common/locators/paths'; +import { useKibana } from '../../../utils/kibana_react'; +import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; + +export const useSloFormattedSummary = (slo: SLOWithSummaryResponse) => { + const { + http: { basePath }, + } = useKibana().services; + const { uiSettings } = useKibana().services; + const percentFormat = uiSettings.get('format:percent:defaultPattern'); + + const sliValue = + slo.summary.status === 'NO_DATA' + ? NOT_AVAILABLE_LABEL + : numeral(slo.summary.sliValue).format(percentFormat); + + const sloTarget = numeral(slo.objective.target).format(percentFormat); + const errorBudgetRemaining = + slo.summary.errorBudget.remaining <= 0 + ? Math.trunc(slo.summary.errorBudget.remaining * 100) / 100 + : slo.summary.errorBudget.remaining; + + const errorBudgetRemainingTitle = + slo.summary.status === 'NO_DATA' + ? NOT_AVAILABLE_LABEL + : numeral(errorBudgetRemaining).format(percentFormat); + + const sloDetailsUrl = basePath.prepend( + paths.observability.sloDetails( + slo.id, + slo.groupBy !== ALL_VALUE && slo.instanceId ? slo.instanceId : undefined + ) + ); + + return { + sloDetailsUrl, + sliValue, + sloTarget, + errorBudgetRemaining: errorBudgetRemainingTitle, + }; +}; diff --git a/x-pack/plugins/observability/public/pages/slos/hooks/use_url_search_state.ts b/x-pack/plugins/observability/public/pages/slos/hooks/use_url_search_state.ts index 7a0c03215fb9..aaa87cb921ae 100644 --- a/x-pack/plugins/observability/public/pages/slos/hooks/use_url_search_state.ts +++ b/x-pack/plugins/observability/public/pages/slos/hooks/use_url_search_state.ts @@ -8,6 +8,7 @@ import { useHistory } from 'react-router-dom'; import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import deepmerge from 'deepmerge'; +import { ViewMode } from '../components/badges/slo_badges'; import type { SortField } from '../components/slo_list_search_bar'; export const SLO_LIST_SEARCH_URL_STORAGE_KEY = 'search'; @@ -19,12 +20,14 @@ export interface SearchState { by: SortField; direction: 'asc' | 'desc'; }; + viewMode: ViewMode; } export const DEFAULT_STATE = { kqlQuery: '', page: 0, sort: { by: 'status' as const, direction: 'desc' as const }, + viewMode: 'compact' as const, }; export function useUrlSearchState(): { diff --git a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx index 3e19b7a466be..6c63d270ef8e 100644 --- a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx +++ b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, screen, waitFor } from '@testing-library/react'; import React from 'react'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; @@ -211,6 +211,9 @@ describe('SLOs Page', () => { await act(async () => { render(); }); + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + + fireEvent.click(screen.getByTestId('sloListViewButton')); expect(screen.queryByTestId('slosPage')).toBeTruthy(); expect(screen.queryByTestId('sloList')).toBeTruthy(); @@ -229,6 +232,8 @@ describe('SLOs Page', () => { await act(async () => { render(); }); + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + fireEvent.click(screen.getByTestId('sloListViewButton')); screen.getAllByLabelText('Actions').at(0)?.click(); @@ -256,7 +261,8 @@ describe('SLOs Page', () => { await act(async () => { render(); }); - + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + fireEvent.click(screen.getByTestId('sloListViewButton')); screen.getAllByLabelText('Actions').at(0)?.click(); await waitForEuiPopoverOpen(); @@ -281,7 +287,8 @@ describe('SLOs Page', () => { await act(async () => { render(); }); - + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + fireEvent.click(screen.getByTestId('sloListViewButton')); screen.getAllByLabelText('Actions').at(0)?.click(); await waitForEuiPopoverOpen(); @@ -307,6 +314,8 @@ describe('SLOs Page', () => { render(); }); + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + fireEvent.click(screen.getByTestId('sloListViewButton')); screen.getAllByLabelText('Actions').at(0)?.click(); await waitForEuiPopoverOpen(); @@ -337,6 +346,8 @@ describe('SLOs Page', () => { render(); }); + expect(await screen.findByTestId('sloListViewButton')).toBeTruthy(); + fireEvent.click(screen.getByTestId('sloListViewButton')); screen.getAllByLabelText('Actions').at(0)?.click(); await waitForEuiPopoverOpen(); diff --git a/x-pack/plugins/observability/public/pages/slos/slos.tsx b/x-pack/plugins/observability/public/pages/slos/slos.tsx index 579b1bb8d19a..e010df224ce1 100644 --- a/x-pack/plugins/observability/public/pages/slos/slos.tsx +++ b/x-pack/plugins/observability/public/pages/slos/slos.tsx @@ -32,7 +32,7 @@ export function SlosPage() { const { hasWriteCapabilities } = useCapabilities(); const { hasAtLeast } = useLicense(); - const { isInitialLoading, isLoading, isError, data: sloList } = useFetchSloList(); + const { isLoading, isError, data: sloList } = useFetchSloList(); const { total } = sloList ?? { total: 0 }; const { storeAutoRefreshState, getAutoRefreshState } = useAutoRefreshStorage(); @@ -63,10 +63,6 @@ export function SlosPage() { storeAutoRefreshState(!isAutoRefreshing); }; - if (isInitialLoading) { - return null; - } - return ( ; - export interface ObservabilityPublicPluginsSetup { data: DataPublicPluginSetup; observabilityShared: ObservabilitySharedPluginSetup; @@ -114,8 +115,8 @@ export interface ObservabilityPublicPluginsSetup { home?: HomePublicPluginSetup; usageCollection: UsageCollectionSetup; embeddable: EmbeddableSetup; + licensing: LicensingPluginSetup; } - export interface ObservabilityPublicPluginsStart { actionTypeRegistry: ActionTypeRegistryContract; cases: CasesUiStart; @@ -144,7 +145,6 @@ export interface ObservabilityPublicPluginsStart { aiops: AiopsPluginStart; serverless?: ServerlessPluginStart; } - export type ObservabilityPublicStart = ReturnType; export class Plugin @@ -237,6 +237,9 @@ export class Plugin const sloEditLocator = pluginsSetup.share.url.locators.create(new SloEditLocatorDefinition()); const sloListLocator = pluginsSetup.share.url.locators.create(new SloListLocatorDefinition()); + const logExplorerLocator = + pluginsSetup.share.url.locators.get(LOG_EXPLORER_LOCATOR_ID); + const mount = async (params: AppMountParameters) => { // Load application bundle const { renderApp } = await import('./application'); @@ -290,15 +293,26 @@ export class Plugin coreSetup.application.register(app); - registerObservabilityRuleTypes(config, this.observabilityRuleTypeRegistry); - const registerSloEmbeddableFactory = async () => { - const { SloOverviewEmbeddableFactoryDefinition } = await import( - './embeddable/slo/overview/slo_embeddable_factory' - ); - const factory = new SloOverviewEmbeddableFactoryDefinition(coreSetup.getStartServices); - pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); + registerObservabilityRuleTypes(config, this.observabilityRuleTypeRegistry, logExplorerLocator); + + const assertPlatinumLicense = async () => { + const licensing = await pluginsSetup.licensing; + const license = await firstValueFrom(licensing.license$); + + const hasPlatinumLicense = license.hasAtLeast('platinum'); + if (hasPlatinumLicense) { + const registerSloOverviewEmbeddableFactory = async () => { + const { SloOverviewEmbeddableFactoryDefinition } = await import( + './embeddable/slo/overview/slo_embeddable_factory' + ); + const factory = new SloOverviewEmbeddableFactoryDefinition(coreSetup.getStartServices); + pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); + }; + registerSloOverviewEmbeddableFactory(); + } }; - registerSloEmbeddableFactory(); + + assertPlatinumLicense(); if (pluginsSetup.home) { pluginsSetup.home.featureCatalogue.registerSolution({ diff --git a/x-pack/plugins/observability/public/routes/routes.tsx b/x-pack/plugins/observability/public/routes/routes.tsx index e1559050056f..87fc22c09434 100644 --- a/x-pack/plugins/observability/public/routes/routes.tsx +++ b/x-pack/plugins/observability/public/routes/routes.tsx @@ -37,6 +37,7 @@ import { SLO_DETAIL_PATH, SLO_EDIT_PATH, } from '../../common/locators/paths'; +import { HasDataContextProvider } from '../context/has_data_context/has_data_context'; // Note: React Router DOM component was not working here // so I've recreated this simple version for this purpose. @@ -65,7 +66,11 @@ export const routes = { }, [LANDING_PATH]: { handler: () => { - return ; + return ( + + + + ); }, params: {}, exact: true, @@ -73,9 +78,11 @@ export const routes = { [OVERVIEW_PATH]: { handler: () => { return ( - - - + + + + + ); }, params: {}, diff --git a/x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts b/x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts index aef7c5eca6ce..76c3d8c89662 100644 --- a/x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts +++ b/x-pack/plugins/observability/public/rules/create_observability_rule_type_registry.ts @@ -16,7 +16,7 @@ import { AsDuration, AsPercent } from '../../common/utils/formatters'; export type ObservabilityRuleTypeFormatter = (options: { fields: ParsedTechnicalFields & Record; formatters: { asDuration: AsDuration; asPercent: AsPercent }; -}) => { reason: string; link?: string }; +}) => { reason: string; link?: string; hasBasePath?: boolean }; export interface ObservabilityRuleTypeModel extends RuleTypeModel { diff --git a/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts b/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts index d807de2499c5..a1faec27f6c8 100644 --- a/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts +++ b/x-pack/plugins/observability/public/rules/register_observability_rule_types.ts @@ -7,15 +7,24 @@ import { lazy } from 'react'; import { i18n } from '@kbn/i18n'; -import { ALERT_REASON, OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils'; - +import type { SerializedSearchSourceFields } from '@kbn/data-plugin/common'; +import { + ALERT_REASON, + ALERT_RULE_PARAMETERS, + ALERT_START, + OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, +} from '@kbn/rule-data-utils'; +import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; +import type { LocatorPublic } from '@kbn/share-plugin/common'; +import type { MetricExpression } from '../components/custom_threshold/types'; +import type { CustomThresholdExpressionMetric } from '../../common/custom_threshold_rule/types'; +import { getViewInAppUrl } from '../../common/custom_threshold_rule/get_view_in_app_url'; import { SLO_ID_FIELD, SLO_INSTANCE_ID_FIELD } from '../../common/field_names/slo'; import { ConfigSchema } from '../plugin'; import { ObservabilityRuleTypeRegistry } from './create_observability_rule_type_registry'; import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../common/constants'; import { validateBurnRateRule } from '../components/burn_rate_rule_editor/validation'; import { validateCustomThreshold } from '../components/custom_threshold/components/validation'; -import { formatReason } from '../components/custom_threshold/rule_data_formatters'; const sloBurnRateDefaultActionMessage = i18n.translate( 'xpack.observability.slo.rules.burnRate.defaultActionMessage', @@ -71,9 +80,15 @@ const thresholdDefaultRecoveryMessage = i18n.translate( } ); -export const registerObservabilityRuleTypes = ( +const getDataViewId = (searchConfiguration?: SerializedSearchSourceFields) => + typeof searchConfiguration?.index === 'string' + ? searchConfiguration.index + : searchConfiguration?.index?.title; + +export const registerObservabilityRuleTypes = async ( config: ConfigSchema, - observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry + observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry, + logExplorerLocator?: LocatorPublic ) => { observabilityRuleTypeRegistry.register({ id: SLO_BURN_RATE_RULE_TYPE_ID, @@ -121,7 +136,27 @@ export const registerObservabilityRuleTypes = ( defaultActionMessage: thresholdDefaultActionMessage, defaultRecoveryMessage: thresholdDefaultRecoveryMessage, requiresAppContext: false, - format: formatReason, + format: ({ fields }) => { + const searchConfiguration = fields[ALERT_RULE_PARAMETERS]?.searchConfiguration as + | SerializedSearchSourceFields + | undefined; + const criteria = fields[ALERT_RULE_PARAMETERS]?.criteria as MetricExpression[]; + const metrics: CustomThresholdExpressionMetric[] = + criteria.length === 1 ? criteria[0].metrics : []; + + const dataViewId = getDataViewId(searchConfiguration); + return { + reason: fields[ALERT_REASON] ?? '-', + link: getViewInAppUrl( + metrics, + fields[ALERT_START], + logExplorerLocator, + (searchConfiguration?.query as { query: string }).query, + dataViewId + ), + hasBasePath: true, + }; + }, alertDetailsAppSection: lazy( () => import('../components/custom_threshold/components/alert_details_app_section') ), diff --git a/x-pack/plugins/observability/public/typings/alerts.ts b/x-pack/plugins/observability/public/typings/alerts.ts index 2e5dfe3ca86f..45a44169121f 100644 --- a/x-pack/plugins/observability/public/typings/alerts.ts +++ b/x-pack/plugins/observability/public/typings/alerts.ts @@ -15,4 +15,5 @@ export interface TopAlert = {} reason: string; link?: string; active: boolean; + hasBasePath?: boolean; } diff --git a/x-pack/plugins/observability/public/utils/cases_permissions.ts b/x-pack/plugins/observability/public/utils/cases_permissions.ts deleted file mode 100644 index 2b3ff9cfbaf5..000000000000 --- a/x-pack/plugins/observability/public/utils/cases_permissions.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const noCasesPermissions = () => ({ - all: false, - create: false, - read: false, - update: false, - delete: false, - push: false, -}); diff --git a/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts b/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts index 0da5408df695..71896e2593f0 100644 --- a/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts +++ b/x-pack/plugins/observability/server/assets/component_templates/slo_mappings_template.ts @@ -12,14 +12,6 @@ export const getSLOMappingsTemplate = (name: string) => ({ template: { mappings: { properties: { - event: { - properties: { - ingested: { - type: 'date', - format: 'strict_date_optional_time', - }, - }, - }, '@timestamp': { type: 'date', format: 'date_optional_time||epoch_millis', @@ -58,10 +50,34 @@ export const getSLOMappingsTemplate = (name: string) => ({ revision: { type: 'long', }, + groupBy: { + type: 'keyword', + ignore_above: 256, + }, instanceId: { type: 'keyword', ignore_above: 256, }, + name: { + type: 'keyword', + ignore_above: 256, + }, + description: { + type: 'keyword', + ignore_above: 256, + }, + tags: { + type: 'keyword', + ignore_above: 256, + }, + indicator: { + properties: { + type: { + type: 'keyword', + ignore_above: 256, + }, + }, + }, objective: { properties: { target: { diff --git a/x-pack/plugins/observability/server/assets/component_templates/slo_summary_mappings_template.ts b/x-pack/plugins/observability/server/assets/component_templates/slo_summary_mappings_template.ts index bfdbe3b33112..fa8e80363118 100644 --- a/x-pack/plugins/observability/server/assets/component_templates/slo_summary_mappings_template.ts +++ b/x-pack/plugins/observability/server/assets/component_templates/slo_summary_mappings_template.ts @@ -55,10 +55,12 @@ export const getSLOSummaryMappingsTemplate = (name: string) => ({ ignore_above: 256, }, name: { - type: 'text', + type: 'keyword', + ignore_above: 256, }, description: { - type: 'text', + type: 'keyword', + ignore_above: 256, }, tags: { type: 'keyword', @@ -118,14 +120,6 @@ export const getSLOSummaryMappingsTemplate = (name: string) => ({ isTempDoc: { type: 'boolean', }, - latestSliTimestamp: { - type: 'date', - format: 'date_optional_time||epoch_millis', - }, - summaryUpdatedAt: { - type: 'date', - format: 'date_optional_time||epoch_millis', - }, }, }, }, diff --git a/x-pack/plugins/observability/server/assets/constants.ts b/x-pack/plugins/observability/server/assets/constants.ts index 5e1bedac6a6a..0dd9df915eee 100644 --- a/x-pack/plugins/observability/server/assets/constants.ts +++ b/x-pack/plugins/observability/server/assets/constants.ts @@ -5,9 +5,8 @@ * 2.0. */ -export const SLO_MODEL_VERSION = 2; -export const SLO_RESOURCES_VERSION = 3; -export const SLO_SUMMARY_TRANSFORMS_VERSION = 4; +export const SLO_RESOURCES_VERSION = 2; +export const SLO_SUMMARY_TRANSFORMS_VERSION = 3; export const SLO_COMPONENT_TEMPLATE_MAPPINGS_NAME = '.slo-observability.sli-mappings'; export const SLO_COMPONENT_TEMPLATE_SETTINGS_NAME = '.slo-observability.sli-settings'; @@ -33,7 +32,6 @@ export const SLO_SUMMARY_TEMP_INDEX_NAME = `.slo-observability.summary-v${SLO_RE export const SLO_SUMMARY_DESTINATION_INDEX_PATTERN = `.slo-observability.summary-v${SLO_RESOURCES_VERSION}*`; // include temp and non-temp summary indices export const SLO_SUMMARY_INGEST_PIPELINE_NAME = `.slo-observability.summary.pipeline`; -export const SLO_SUMMARY_ENRICH_POLICY_NAME = `slo-observability.summary.enrich_policy`; export const getSLOTransformId = (sloId: string, sloRevision: number) => `slo-${sloId}-${sloRevision}`; diff --git a/x-pack/plugins/observability/server/assets/enrich_policies/slo_summary_enrich_policy.ts b/x-pack/plugins/observability/server/assets/enrich_policies/slo_summary_enrich_policy.ts deleted file mode 100644 index fc089f8259f7..000000000000 --- a/x-pack/plugins/observability/server/assets/enrich_policies/slo_summary_enrich_policy.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SO_SLO_TYPE } from '../../saved_objects'; -import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants'; - -export const getSLOSummaryEnrichPolicy = () => ({ - name: SLO_SUMMARY_ENRICH_POLICY_NAME, - match: { - indices: '.kibana', - match_field: 'slo.id', - enrich_fields: [ - 'slo.name', - 'slo.description', - 'slo.tags', - 'slo.indicator.type', - 'slo.objective.target', - 'slo.budgetingMethod', - 'slo.timeWindow.type', - 'slo.timeWindow.duration', - 'slo.groupBy', - ], - query: { - bool: { - filter: [ - { - match_phrase: { - type: SO_SLO_TYPE, - }, - }, - ], - }, - }, - }, -}); diff --git a/x-pack/plugins/observability/server/assets/ingest_templates/slo_pipeline_template.ts b/x-pack/plugins/observability/server/assets/ingest_templates/slo_pipeline_template.ts index e803a8011e2e..eafa7399a7c3 100644 --- a/x-pack/plugins/observability/server/assets/ingest_templates/slo_pipeline_template.ts +++ b/x-pack/plugins/observability/server/assets/ingest_templates/slo_pipeline_template.ts @@ -5,48 +5,12 @@ * 2.0. */ -import { SLO_RESOURCES_VERSION, SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants'; +import { SLO_RESOURCES_VERSION } from '../constants'; export const getSLOPipelineTemplate = (id: string, indexNamePrefix: string) => ({ id, description: 'Monthly date-time index naming for SLO data', processors: [ - { - enrich: { - field: 'slo.id', - policy_name: SLO_SUMMARY_ENRICH_POLICY_NAME, - target_field: '_enrich', - }, - }, - { - set: { - field: 'slo.timeWindow', - copy_from: '_enrich.slo.timeWindow', - }, - }, - { - set: { - field: 'slo.budgetingMethod', - copy_from: '_enrich.slo.budgetingMethod', - }, - }, - { - set: { - field: 'slo.objective.target', - copy_from: '_enrich.slo.objective.target', - }, - }, - { - remove: { - field: '_enrich', - }, - }, - { - set: { - field: 'event.ingested', - value: '{{{_ingest.timestamp}}}', - }, - }, { date_index_name: { field: '@timestamp', diff --git a/x-pack/plugins/observability/server/assets/ingest_templates/slo_summary_pipeline_template.ts b/x-pack/plugins/observability/server/assets/ingest_templates/slo_summary_pipeline_template.ts index ccdcb24e61c1..d3c8e04b9373 100644 --- a/x-pack/plugins/observability/server/assets/ingest_templates/slo_summary_pipeline_template.ts +++ b/x-pack/plugins/observability/server/assets/ingest_templates/slo_summary_pipeline_template.ts @@ -5,12 +5,19 @@ * 2.0. */ -import { SLO_RESOURCES_VERSION, SLO_SUMMARY_ENRICH_POLICY_NAME } from '../constants'; +import { SLO_RESOURCES_VERSION } from '../constants'; export const getSLOSummaryPipelineTemplate = (id: string) => ({ id, description: 'SLO summary ingest pipeline', processors: [ + { + split: { + description: 'Split comma separated list of tags into an array', + field: 'slo.tags', + separator: ',', + }, + }, { set: { description: "if 'statusCode == 0', set status to NO_DATA", @@ -43,72 +50,6 @@ export const getSLOSummaryPipelineTemplate = (id: string) => ({ value: 'HEALTHY', }, }, - { - enrich: { - field: 'slo.id', - policy_name: SLO_SUMMARY_ENRICH_POLICY_NAME, - target_field: '_enrich', - }, - }, - { - set: { - field: 'slo.name', - copy_from: '_enrich.slo.name', - }, - }, - { - set: { - field: 'slo.description', - copy_from: '_enrich.slo.description', - }, - }, - { - set: { - field: 'slo.indicator', - copy_from: '_enrich.slo.indicator', - }, - }, - { - set: { - field: 'slo.timeWindow', - copy_from: '_enrich.slo.timeWindow', - }, - }, - { - set: { - field: 'slo.groupBy', - copy_from: '_enrich.slo.groupBy', - }, - }, - { - set: { - field: 'slo.tags', - copy_from: '_enrich.slo.tags', - }, - }, - { - set: { - field: 'slo.objective', - copy_from: '_enrich.slo.objective', - }, - }, - { - set: { - field: 'slo.budgetingMethod', - copy_from: '_enrich.slo.budgetingMethod', - }, - }, - { - remove: { - field: '_enrich', - }, - }, - { - set: { - field: 'summaryUpdatedAt', - value: '{{{_ingest.timestamp}}}', - }, - }, ], _meta: { description: 'SLO summary ingest pipeline', diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts index e5301b8ac8da..b769f5f32b73 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts @@ -21,7 +21,6 @@ import { CustomThresholdAlertContext } from './types'; import { Evaluation } from './lib/evaluate_rule'; import type { LogMeta, Logger } from '@kbn/logging'; import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; -import { CUSTOM_AGGREGATOR } from '../../../../common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -30,6 +29,9 @@ import { } from '../../../../common/custom_threshold_rule/types'; jest.mock('./lib/evaluate_rule', () => ({ evaluateRule: jest.fn() })); +jest.mock('../../../../common/custom_threshold_rule/get_view_in_app_url', () => ({ + getViewInAppUrl: () => 'mockedViewInApp', +})); interface AlertTestInstance { instance: AlertInstanceMock; @@ -135,7 +137,7 @@ const setEvaluationResults = (response: Array>) => { jest.requireMock('./lib/evaluate_rule').evaluateRule.mockImplementation(() => response); }; -describe('The metric threshold alert type', () => { +describe('The custom threshold alert type', () => { describe('querying the entire infrastructure', () => { afterAll(() => clearInstances()); const instanceID = '*'; @@ -1340,6 +1342,7 @@ describe('The metric threshold alert type', () => { timestamp: STARTED_AT_MOCK_DATE.toISOString(), value: ['[NO DATA]', null], tags: [], + viewInAppUrl: 'mockedViewInApp', }); expect(recentAction).toBeNoDataAction(); }); @@ -1766,6 +1769,7 @@ const mockLibs: any = { groupByPageSize: 10_000, }, }, + locators: {}, }; const executor = createCustomThresholdExecutor(mockLibs); @@ -1781,6 +1785,7 @@ const mockedIndex = { }; const mockedDataView = { getIndexPattern: () => 'mockedIndexPattern', + getName: () => 'mockedDataViewName', ...mockedIndex, }; const mockedSearchSource = { @@ -1883,7 +1888,6 @@ declare global { } const customThresholdNonCountCriterion: CustomMetricExpressionParams = { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { @@ -1898,7 +1902,6 @@ const customThresholdNonCountCriterion: CustomMetricExpressionParams = { }; const customThresholdCountCriterion: CustomMetricExpressionParams = { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, metrics: [ { diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts index 2e50c33048f5..ac052a6b8f4d 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts @@ -6,6 +6,7 @@ */ import { isEqual } from 'lodash'; +import { LogExplorerLocatorParams } from '@kbn/deeplinks-observability'; import { ALERT_ACTION_GROUP, ALERT_EVALUATION_VALUES, @@ -17,6 +18,7 @@ import { RecoveredActionGroup } from '@kbn/alerting-plugin/common'; import { IBasePath, Logger } from '@kbn/core/server'; import { LifecycleRuleExecutor } from '@kbn/rule-registry-plugin/server'; import { AlertsLocatorParams, getAlertUrl } from '../../../../common'; +import { getViewInAppUrl } from '../../../../common/custom_threshold_rule/get_view_in_app_url'; import { ObservabilityConfig } from '../../..'; import { FIRED_ACTIONS_ID, NO_DATA_ACTIONS_ID, UNGROUPED_FACTORY_KEY } from './constants'; import { @@ -48,16 +50,21 @@ import { EvaluatedRuleParams, evaluateRule } from './lib/evaluate_rule'; import { MissingGroupsRecord } from './lib/check_missing_group'; import { convertStringsToMissingGroupsRecord } from './lib/convert_strings_to_missing_groups_record'; +export interface CustomThresholdLocators { + alertsLocator?: LocatorPublic; + logExplorerLocator?: LocatorPublic; +} + export const createCustomThresholdExecutor = ({ - alertsLocator, basePath, logger, config, + locators: { alertsLocator, logExplorerLocator }, }: { basePath: IBasePath; logger: Logger; config: ObservabilityConfig; - alertsLocator?: LocatorPublic; + locators: CustomThresholdLocators; }): LifecycleRuleExecutor< CustomThresholdRuleParams, CustomThresholdRuleTypeState, @@ -132,21 +139,22 @@ export const createCustomThresholdExecutor = ({ : []; const initialSearchSource = await searchSourceClient.create(params.searchConfiguration!); - const dataView = initialSearchSource.getField('index')!.getIndexPattern(); - const dataViewName = initialSearchSource.getField('index')!.name; - const timeFieldName = initialSearchSource.getField('index')?.timeFieldName; - if (!dataView) { + const dataView = initialSearchSource.getField('index')!; + const { id: dataViewId, timeFieldName } = dataView; + const dataViewIndexPattern = dataView.getIndexPattern(); + const dataViewName = dataView.getName(); + if (!dataViewIndexPattern) { throw new Error('No matched data view'); } else if (!timeFieldName) { throw new Error('The selected data view does not have a timestamp field'); } - // Calculate initial start and end date with no time window, as each criteria has it's own time window + // Calculate initial start and end date with no time window, as each criterion has its own time window const { dateStart, dateEnd } = getTimeRange(); const alertResults = await evaluateRule( services.scopedClusterClient.asCurrentUser, params as EvaluatedRuleParams, - dataView, + dataViewIndexPattern, timeFieldName, compositeSize, alertOnGroupDisappear, @@ -270,13 +278,20 @@ export const createCustomThresholdExecutor = ({ group: groupByKeysObjectMapping[group], reason, timestamp, - value: alertResults.map((result, index) => { + value: alertResults.map((result) => { const evaluation = result[group]; if (!evaluation) { return null; } return formatAlertResult(evaluation).currentValue; }), + viewInAppUrl: getViewInAppUrl( + alertResults.length === 1 ? alertResults[0][group].metrics : [], + indexedStartedAt, + logExplorerLocator, + params.searchConfiguration.query.query, + params.searchConfiguration?.index?.title ?? dataViewId + ), ...additionalContext, }); } diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/create_condition_script.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/create_condition_script.ts index ad4aaa980aa6..2e5eda9fa32b 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/create_condition_script.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/create_condition_script.ts @@ -19,7 +19,8 @@ export const createConditionScript = (threshold: number[], comparator: Comparato } if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) { return { - source: `params.value < params.threshold0 && params.value > params.threshold1 ? 1 : 0`, + // OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0 + source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`, params: { threshold0: threshold[0], threshold1: threshold[1], diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/metric_query.test.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/metric_query.test.ts index 53a89303fa17..01d94dd5f7d6 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/metric_query.test.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/lib/metric_query.test.ts @@ -6,7 +6,6 @@ */ import moment from 'moment'; -import { CUSTOM_AGGREGATOR } from '../../../../../common/custom_threshold_rule/constants'; import { Comparator, Aggregators, @@ -23,7 +22,6 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => { field: 'system.is.a.good.puppy.dog', }, ], - aggType: CUSTOM_AGGREGATOR, timeUnit: 'm', timeSize: 1, threshold: [1], diff --git a/x-pack/plugins/observability/server/lib/rules/custom_threshold/register_custom_threshold_rule_type.ts b/x-pack/plugins/observability/server/lib/rules/custom_threshold/register_custom_threshold_rule_type.ts index 2166c21db860..cf27867125ca 100644 --- a/x-pack/plugins/observability/server/lib/rules/custom_threshold/register_custom_threshold_rule_type.ts +++ b/x-pack/plugins/observability/server/lib/rules/custom_threshold/register_custom_threshold_rule_type.ts @@ -16,13 +16,8 @@ import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils'; import { createLifecycleExecutor, IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { LicenseType } from '@kbn/licensing-plugin/server'; -import { LocatorPublic } from '@kbn/share-plugin/common'; import { EsQueryRuleParamsExtractedParams } from '@kbn/stack-alerts-plugin/server/rule_types/es_query/rule_type_params'; -import { - AlertsLocatorParams, - observabilityFeatureId, - observabilityPaths, -} from '../../../../common'; +import { observabilityFeatureId, observabilityPaths } from '../../../../common'; import { Comparator } from '../../../../common/custom_threshold_rule/types'; import { THRESHOLD_RULE_REGISTRATION_CONTEXT } from '../../../common/constants'; @@ -38,12 +33,15 @@ import { tagsActionVariableDescription, timestampActionVariableDescription, valueActionVariableDescription, + viewInAppUrlActionVariableDescription, } from './translations'; import { oneOfLiterals, validateKQLStringFilter } from './utils'; -import { createCustomThresholdExecutor } from './custom_threshold_executor'; +import { + createCustomThresholdExecutor, + CustomThresholdLocators, +} from './custom_threshold_executor'; import { FIRED_ACTION, NO_DATA_ACTION } from './constants'; import { ObservabilityConfig } from '../../..'; -import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/custom_threshold_rule/constants'; export const MetricsRulesTypeAlertDefinition: IRuleTypeAlerts = { context: THRESHOLD_RULE_REGISTRATION_CONTEXT, @@ -70,7 +68,7 @@ export function thresholdRuleType( config: ObservabilityConfig, logger: Logger, ruleDataClient: IRuleDataClient, - alertsLocator?: LocatorPublic + locators: CustomThresholdLocators ) { const baseCriterion = { threshold: schema.arrayOf(schema.number()), @@ -79,27 +77,9 @@ export function thresholdRuleType( timeSize: schema.number(), }; - const nonCountCriterion = schema.object({ - ...baseCriterion, - metric: schema.string(), - aggType: oneOfLiterals(METRIC_EXPLORER_AGGREGATIONS), - metrics: schema.never(), - equation: schema.never(), - label: schema.never(), - }); - - const countCriterion = schema.object({ - ...baseCriterion, - aggType: schema.literal('count'), - metric: schema.never(), - metrics: schema.never(), - equation: schema.never(), - label: schema.never(), - }); - const customCriterion = schema.object({ ...baseCriterion, - aggType: schema.literal('custom'), + aggType: schema.maybe(schema.literal('custom')), metric: schema.never(), metrics: schema.arrayOf( schema.oneOf([ @@ -128,14 +108,12 @@ export function thresholdRuleType( return { id: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, name: i18n.translate('xpack.observability.threshold.ruleName', { - defaultMessage: 'Custom threshold (Technical Preview)', + defaultMessage: 'Custom threshold (Beta)', }), validate: { params: schema.object( { - criteria: schema.arrayOf( - schema.oneOf([countCriterion, nonCountCriterion, customCriterion]) - ), + criteria: schema.arrayOf(customCriterion), groupBy: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])), alertOnNoData: schema.maybe(schema.boolean()), alertOnGroupDisappear: schema.maybe(schema.boolean()), @@ -149,7 +127,7 @@ export function thresholdRuleType( minimumLicenseRequired: 'basic' as LicenseType, isExportable: true, executor: createLifecycleRuleExecutor( - createCustomThresholdExecutor({ alertsLocator, basePath, logger, config }) + createCustomThresholdExecutor({ basePath, logger, config, locators }) ), doesSetRecoveryContext: true, actionVariables: { @@ -169,6 +147,7 @@ export function thresholdRuleType( { name: 'orchestrator', description: orchestratorActionVariableDescription }, { name: 'labels', description: labelsActionVariableDescription }, { name: 'tags', description: tagsActionVariableDescription }, + { name: 'viewInAppUrl', description: viewInAppUrlActionVariableDescription }, ], }, useSavedObjectReferences: { diff --git a/x-pack/plugins/observability/server/lib/rules/register_rule_types.ts b/x-pack/plugins/observability/server/lib/rules/register_rule_types.ts index 0e1abfc1037d..c90ee35f8655 100644 --- a/x-pack/plugins/observability/server/lib/rules/register_rule_types.ts +++ b/x-pack/plugins/observability/server/lib/rules/register_rule_types.ts @@ -7,7 +7,6 @@ import { PluginSetupContract } from '@kbn/alerting-plugin/server'; import { IBasePath, Logger } from '@kbn/core/server'; -import { LocatorPublic } from '@kbn/share-plugin/common'; import { createLifecycleExecutor, Dataset, @@ -15,7 +14,8 @@ import { } from '@kbn/rule-registry-plugin/server'; import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; -import { sloFeatureId, AlertsLocatorParams, observabilityFeatureId } from '../../../common'; +import { CustomThresholdLocators } from './custom_threshold/custom_threshold_executor'; +import { sloFeatureId, observabilityFeatureId } from '../../../common'; import { ObservabilityConfig } from '../..'; import { SLO_RULE_REGISTRATION_CONTEXT, @@ -27,11 +27,11 @@ import { sloRuleFieldMap } from './slo_burn_rate/field_map'; export function registerRuleTypes( alertingPlugin: PluginSetupContract, - logger: Logger, - ruleDataService: IRuleDataService, basePath: IBasePath, config: ObservabilityConfig, - alertsLocator?: LocatorPublic + logger: Logger, + ruleDataService: IRuleDataService, + locators: CustomThresholdLocators ) { // SLO RULE const ruleDataClientSLO = ruleDataService.initializeIndex({ @@ -55,7 +55,7 @@ export function registerRuleTypes( ruleDataClientSLO ); alertingPlugin.registerType( - sloBurnRateRuleType(createLifecycleRuleExecutorSLO, basePath, alertsLocator) + sloBurnRateRuleType(createLifecycleRuleExecutorSLO, basePath, locators.alertsLocator) ); // Threshold RULE @@ -85,7 +85,7 @@ export function registerRuleTypes( config, logger, ruleDataClientThreshold, - alertsLocator + locators ) ); } diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts index 17476d335f48..6726b8abfe17 100644 --- a/x-pack/plugins/observability/server/plugin.ts +++ b/x-pack/plugins/observability/server/plugin.ts @@ -18,6 +18,7 @@ import { Plugin, PluginInitializerContext, } from '@kbn/core/server'; +import { LOG_EXPLORER_LOCATOR_ID, LogExplorerLocatorParams } from '@kbn/deeplinks-observability'; import { PluginSetupContract as FeaturesSetup } from '@kbn/features-plugin/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; @@ -101,6 +102,8 @@ export class ObservabilityPlugin implements Plugin { const config = this.initContext.config.get(); const alertsLocator = plugins.share.url.locators.create(new AlertsLocatorDefinition()); + const logExplorerLocator = + plugins.share.url.locators.get(LOG_EXPLORER_LOCATOR_ID); plugins.features.registerKibanaFeature({ id: casesFeatureId, @@ -175,6 +178,36 @@ export class ObservabilityPlugin implements Plugin { }, ], }, + { + name: i18n.translate('xpack.observability.featureRegistry.casesSettingsSubFeatureName', { + defaultMessage: 'Case Settings', + }), + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cases_settings', + name: i18n.translate( + 'xpack.observability.featureRegistry.casesSettingsSubFeatureDetails', + { + defaultMessage: 'Edit Case Settings', + } + ), + includeIn: 'all', + savedObject: { + all: [...filesSavedObjectTypes], + read: [...filesSavedObjectTypes], + }, + cases: { + settings: [observabilityFeatureId], + }, + ui: casesCapabilities.settings, + }, + ], + }, + ], + }, ], }); @@ -302,14 +335,10 @@ export class ObservabilityPlugin implements Plugin { core.savedObjects.registerType(slo); core.savedObjects.registerType(threshold); - registerRuleTypes( - plugins.alerting, - this.logger, - ruleDataService, - core.http.basePath, - config, - alertsLocator - ); + registerRuleTypes(plugins.alerting, core.http.basePath, config, this.logger, ruleDataService, { + alertsLocator, + logExplorerLocator, + }); registerSloUsageCollector(plugins.usageCollection); core.getStartServices().then(([coreStart, pluginStart]) => { diff --git a/x-pack/plugins/observability/server/routes/slo/route.ts b/x-pack/plugins/observability/server/routes/slo/route.ts index d3bab20c436c..ade3f1714ddf 100644 --- a/x-pack/plugins/observability/server/routes/slo/route.ts +++ b/x-pack/plugins/observability/server/routes/slo/route.ts @@ -19,7 +19,6 @@ import { getSLOInstancesParamsSchema, getSLOParamsSchema, manageSLOParamsSchema, - resetSLOParamsSchema, updateSLOParamsSchema, } from '@kbn/slo-schema'; import type { IndicatorTypes } from '../../domain/models'; @@ -42,7 +41,6 @@ import { GetPreviewData } from '../../services/slo/get_preview_data'; import { GetSLOInstances } from '../../services/slo/get_slo_instances'; import { DefaultHistoricalSummaryClient } from '../../services/slo/historical_summary_client'; import { ManageSLO } from '../../services/slo/manage_slo'; -import { ResetSLO } from '../../services/slo/reset_slo'; import { DefaultSummarySearchClient } from '../../services/slo/summary_search_client'; import { ApmTransactionDurationTransformGenerator, @@ -50,8 +48,8 @@ import { HistogramTransformGenerator, KQLCustomTransformGenerator, MetricCustomTransformGenerator, - TimesliceMetricTransformGenerator, TransformGenerator, + TimesliceMetricTransformGenerator, } from '../../services/slo/transform_generators'; import type { ObservabilityRequestHandlerContext } from '../../types'; import { createObservabilityServerRoute } from '../create_observability_server_route'; @@ -85,11 +83,10 @@ const createSLORoute = createObservabilityServerRoute({ await assertPlatinumLicense(context); const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const systemEsClient = (await context.core).elasticsearch.client.asInternalUser; const soClient = (await context.core).savedObjects.client; const repository = new KibanaSavedObjectsSLORepository(soClient); const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger); - const createSLO = new CreateSLO(esClient, systemEsClient, repository, transformManager); + const createSLO = new CreateSLO(esClient, repository, transformManager); const response = await createSLO.execute(params.body); @@ -108,12 +105,11 @@ const updateSLORoute = createObservabilityServerRoute({ await assertPlatinumLicense(context); const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const systemEsClient = (await context.core).elasticsearch.client.asInternalUser; const soClient = (await context.core).savedObjects.client; const repository = new KibanaSavedObjectsSLORepository(soClient); const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger); - const updateSLO = new UpdateSLO(repository, transformManager, esClient, systemEsClient); + const updateSLO = new UpdateSLO(repository, transformManager, esClient); const response = await updateSLO.execute(params.path.id, params.body); @@ -138,20 +134,13 @@ const deleteSLORoute = createObservabilityServerRoute({ await assertPlatinumLicense(context); const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const systemEsClient = (await context.core).elasticsearch.client.asInternalUser; const soClient = (await context.core).savedObjects.client; const rulesClient = getRulesClientWithRequest(request); const repository = new KibanaSavedObjectsSLORepository(soClient); const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger); - const deleteSLO = new DeleteSLO( - repository, - transformManager, - esClient, - rulesClient, - systemEsClient - ); + const deleteSLO = new DeleteSLO(repository, transformManager, esClient, rulesClient); await deleteSLO.execute(params.path.id); }, @@ -225,29 +214,6 @@ const disableSLORoute = createObservabilityServerRoute({ }, }); -const resetSLORoute = createObservabilityServerRoute({ - endpoint: 'POST /api/observability/slos/{id}/_reset 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', - }, - params: resetSLOParamsSchema, - handler: async ({ context, params, logger }) => { - await assertPlatinumLicense(context); - - const soClient = (await context.core).savedObjects.client; - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - - const repository = new KibanaSavedObjectsSLORepository(soClient); - const transformManager = new DefaultTransformManager(transformGenerators, esClient, logger); - const resetSLO = new ResetSLO(esClient, repository, transformManager); - - const response = await resetSLO.execute(params.path.id); - - return response; - }, -}); - const findSLORoute = createObservabilityServerRoute({ endpoint: 'GET /api/observability/slos 2023-10-31', options: { @@ -287,9 +253,10 @@ const deleteSloInstancesRoute = createObservabilityServerRoute({ }); const findSloDefinitionsRoute = createObservabilityServerRoute({ - endpoint: 'GET /api/observability/slos/_definitions 2023-10-31', + endpoint: 'GET /internal/observability/slos/_definitions', options: { tags: ['access:slo_read'], + access: 'internal', }, params: findSloDefinitionsParamsSchema, handler: async ({ context, params }) => { @@ -299,7 +266,7 @@ const findSloDefinitionsRoute = createObservabilityServerRoute({ const repository = new KibanaSavedObjectsSLORepository(soClient); const findSloDefinitions = new FindSLODefinitions(repository); - const response = await findSloDefinitions.execute(params?.query ?? {}); + const response = await findSloDefinitions.execute(params.query.search); return response; }, @@ -428,5 +395,4 @@ export const sloRouteRepository = { ...getSloBurnRates, ...getPreviewData, ...getSLOInstancesRoute, - ...resetSLORoute, }; diff --git a/x-pack/plugins/observability/server/saved_objects/slo.ts b/x-pack/plugins/observability/server/saved_objects/slo.ts index 058596e160fd..41cb509d8375 100644 --- a/x-pack/plugins/observability/server/saved_objects/slo.ts +++ b/x-pack/plugins/observability/server/saved_objects/slo.ts @@ -17,6 +17,7 @@ type StoredSLOBefore890 = StoredSLO & { isCalendar?: boolean; }; }; + const migrateSlo890: SavedObjectMigrationFn = (doc) => { const { timeWindow, ...other } = doc.attributes; return { @@ -37,21 +38,6 @@ export const slo: SavedObjectsType = { name: SO_SLO_TYPE, hidden: false, namespaceType: 'multiple-isolated', - switchToModelVersionAt: '8.10.0', - modelVersions: { - 1: { - changes: [ - { type: 'mappings_addition', addedMappings: { version: { type: 'long' } } }, - { - type: 'data_backfill', - backfillFn: (doc) => { - // we explicitely set the version to 1, so we know which SLOs requires a migration to the following version. - return { attributes: { version: doc.attributes.version ?? 1 } }; - }, - }, - ], - }, - }, mappings: { dynamic: false, properties: { @@ -67,7 +53,6 @@ export const slo: SavedObjectsType = { budgetingMethod: { type: 'keyword' }, enabled: { type: 'boolean' }, tags: { type: 'keyword' }, - version: { type: 'long' }, }, }, management: { diff --git a/x-pack/plugins/observability/server/services/slo/__snapshots__/create_slo.test.ts.snap b/x-pack/plugins/observability/server/services/slo/__snapshots__/create_slo.test.ts.snap index c9e32e24f698..e66f1f8124a1 100644 --- a/x-pack/plugins/observability/server/services/slo/__snapshots__/create_slo.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/__snapshots__/create_slo.test.ts.snap @@ -41,16 +41,8 @@ Array [ }, }, "id": "slo-unique-id", - "index": ".slo-observability.summary-v3.temp", + "index": ".slo-observability.summary-v2.temp", "refresh": true, }, ] `; - -exports[`CreateSLO happy path calls the expected services 2`] = ` -Array [ - Object { - "name": "slo-observability.summary.enrich_policy", - }, -] -`; diff --git a/x-pack/plugins/observability/server/services/slo/__snapshots__/get_slo_instances.test.ts.snap b/x-pack/plugins/observability/server/services/slo/__snapshots__/get_slo_instances.test.ts.snap index 8ad9792a22b2..be3b681db0af 100644 --- a/x-pack/plugins/observability/server/services/slo/__snapshots__/get_slo_instances.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/__snapshots__/get_slo_instances.test.ts.snap @@ -11,7 +11,7 @@ Array [ }, }, }, - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ diff --git a/x-pack/plugins/observability/server/services/slo/__snapshots__/summary_search_client.test.ts.snap b/x-pack/plugins/observability/server/services/slo/__snapshots__/summary_search_client.test.ts.snap index daf5e47a0a66..ea94e840aac0 100644 --- a/x-pack/plugins/observability/server/services/slo/__snapshots__/summary_search_client.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/__snapshots__/summary_search_client.test.ts.snap @@ -3,7 +3,7 @@ exports[`Summary Search Client returns the summary documents without duplicate temporary summary documents 1`] = ` Array [ Object { - "index": ".slo-observability.summary-v3*", + "index": ".slo-observability.summary-v2*", "query": Object { "bool": Object { "filter": Array [ diff --git a/x-pack/plugins/observability/server/services/slo/__snapshots__/update_slo.test.ts.snap b/x-pack/plugins/observability/server/services/slo/__snapshots__/update_slo.test.ts.snap index 79e676bc13f5..ae7a966951f7 100644 --- a/x-pack/plugins/observability/server/services/slo/__snapshots__/update_slo.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/__snapshots__/update_slo.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`UpdateSLO when the revision bumps indexes a temporary summary document 1`] = ` +exports[`UpdateSLO index a temporary summary document 1`] = ` Array [ Object { "document": Object { @@ -44,7 +44,7 @@ Array [ }, }, "id": "slo-unique-id", - "index": ".slo-observability.summary-v3.temp", + "index": ".slo-observability.summary-v2.temp", "refresh": true, }, ] diff --git a/x-pack/plugins/observability/server/services/slo/create_slo.test.ts b/x-pack/plugins/observability/server/services/slo/create_slo.test.ts index 504fa85b82aa..bd34d652e5fa 100644 --- a/x-pack/plugins/observability/server/services/slo/create_slo.test.ts +++ b/x-pack/plugins/observability/server/services/slo/create_slo.test.ts @@ -15,22 +15,15 @@ import { TransformManager } from './transform_manager'; describe('CreateSLO', () => { let esClientMock: ElasticsearchClientMock; - let esSystemClientMock: ElasticsearchClientMock; let mockRepository: jest.Mocked; let mockTransformManager: jest.Mocked; let createSLO: CreateSLO; beforeEach(() => { esClientMock = elasticsearchServiceMock.createElasticsearchClient(); - esSystemClientMock = elasticsearchServiceMock.createElasticsearchClient(); mockRepository = createSLORepositoryMock(); mockTransformManager = createTransformManagerMock(); - createSLO = new CreateSLO( - esClientMock, - esSystemClientMock, - mockRepository, - mockTransformManager - ); + createSLO = new CreateSLO(esClientMock, mockRepository, mockTransformManager); }); describe('happy path', () => { @@ -66,7 +59,6 @@ describe('CreateSLO', () => { expect(mockTransformManager.start).toHaveBeenCalledWith('slo-transform-id'); expect(response).toEqual(expect.objectContaining({ id: 'unique-id' })); expect(esClientMock.index.mock.calls[0]).toMatchSnapshot(); - expect(esSystemClientMock.enrich.executePolicy.mock.calls[0]).toMatchSnapshot(); }); it('overrides the default values when provided', async () => { diff --git a/x-pack/plugins/observability/server/services/slo/create_slo.ts b/x-pack/plugins/observability/server/services/slo/create_slo.ts index 659b04adb562..51c3fbec71dc 100644 --- a/x-pack/plugins/observability/server/services/slo/create_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/create_slo.ts @@ -8,11 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { ALL_VALUE, CreateSLOParams, CreateSLOResponse } from '@kbn/slo-schema'; import { v4 as uuidv4 } from 'uuid'; -import { - SLO_MODEL_VERSION, - SLO_SUMMARY_ENRICH_POLICY_NAME, - SLO_SUMMARY_TEMP_INDEX_NAME, -} from '../../assets/constants'; +import { SLO_SUMMARY_TEMP_INDEX_NAME } from '../../assets/constants'; import { Duration, DurationUnit, SLO } from '../../domain/models'; import { validateSLO } from '../../domain/services'; import { SLORepository } from './slo_repository'; @@ -22,7 +18,6 @@ import { TransformManager } from './transform_manager'; export class CreateSLO { constructor( private esClient: ElasticsearchClient, - private systemClient: ElasticsearchClient, private repository: SLORepository, private transformManager: TransformManager ) {} @@ -59,8 +54,6 @@ export class CreateSLO { refresh: true, }); - await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }); - return this.toResponse(slo); } @@ -79,7 +72,6 @@ export class CreateSLO { createdAt: now, updatedAt: now, groupBy: !!params.groupBy ? params.groupBy : ALL_VALUE, - version: SLO_MODEL_VERSION, }; } diff --git a/x-pack/plugins/observability/server/services/slo/delete_slo.test.ts b/x-pack/plugins/observability/server/services/slo/delete_slo.test.ts index d1f9342c32ba..a136945edcd2 100644 --- a/x-pack/plugins/observability/server/services/slo/delete_slo.test.ts +++ b/x-pack/plugins/observability/server/services/slo/delete_slo.test.ts @@ -24,7 +24,6 @@ describe('DeleteSLO', () => { let mockRepository: jest.Mocked; let mockTransformManager: jest.Mocked; let mockEsClient: jest.Mocked; - let mockSystemEsClient: jest.Mocked; let mockRulesClient: jest.Mocked; let deleteSLO: DeleteSLO; @@ -32,15 +31,8 @@ describe('DeleteSLO', () => { mockRepository = createSLORepositoryMock(); mockTransformManager = createTransformManagerMock(); mockEsClient = elasticsearchServiceMock.createElasticsearchClient(); - mockSystemEsClient = elasticsearchServiceMock.createElasticsearchClient(); mockRulesClient = rulesClientMock.create(); - deleteSLO = new DeleteSLO( - mockRepository, - mockTransformManager, - mockEsClient, - mockRulesClient, - mockSystemEsClient - ); + deleteSLO = new DeleteSLO(mockRepository, mockTransformManager, mockEsClient, mockRulesClient); }); describe('happy path', () => { @@ -80,7 +72,6 @@ describe('DeleteSLO', () => { }, }) ); - expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled(); expect(mockRulesClient.bulkDeleteRules).toHaveBeenCalledWith({ filter: `alert.attributes.params.sloId:${slo.id}`, }); diff --git a/x-pack/plugins/observability/server/services/slo/delete_slo.ts b/x-pack/plugins/observability/server/services/slo/delete_slo.ts index 6df784cd19f4..de908ceac784 100644 --- a/x-pack/plugins/observability/server/services/slo/delete_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/delete_slo.ts @@ -11,7 +11,6 @@ import { getSLOTransformId, SLO_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, - SLO_SUMMARY_ENRICH_POLICY_NAME, } from '../../assets/constants'; import { SLORepository } from './slo_repository'; import { TransformManager } from './transform_manager'; @@ -21,8 +20,7 @@ export class DeleteSLO { private repository: SLORepository, private transformManager: TransformManager, private esClient: ElasticsearchClient, - private rulesClient: RulesClientApi, - private systemClient: ElasticsearchClient + private rulesClient: RulesClientApi ) {} public async execute(sloId: string): Promise { @@ -36,7 +34,6 @@ export class DeleteSLO { await this.deleteSummaryData(slo.id); await this.deleteAssociatedRules(slo.id); await this.repository.deleteById(slo.id); - await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }); } private async deleteRollupData(sloId: string): Promise { diff --git a/x-pack/plugins/observability/server/services/slo/delete_slo_instances.test.ts b/x-pack/plugins/observability/server/services/slo/delete_slo_instances.test.ts index ca4eac790bd0..8a9c64a6b441 100644 --- a/x-pack/plugins/observability/server/services/slo/delete_slo_instances.test.ts +++ b/x-pack/plugins/observability/server/services/slo/delete_slo_instances.test.ts @@ -43,7 +43,7 @@ describe('DeleteSLOInstances', () => { expect(mockEsClient.deleteByQuery).toHaveBeenCalledTimes(2); expect(mockEsClient.deleteByQuery.mock.calls[0][0]).toMatchInlineSnapshot(` Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "should": Array [ @@ -103,7 +103,7 @@ describe('DeleteSLOInstances', () => { `); expect(mockEsClient.deleteByQuery.mock.calls[1][0]).toMatchInlineSnapshot(` Object { - "index": ".slo-observability.summary-v3*", + "index": ".slo-observability.summary-v2*", "query": Object { "bool": Object { "should": Array [ diff --git a/x-pack/plugins/observability/server/services/slo/find_slo.test.ts b/x-pack/plugins/observability/server/services/slo/find_slo.test.ts index 93319e4e53fd..10436bc0fad5 100644 --- a/x-pack/plugins/observability/server/services/slo/find_slo.test.ts +++ b/x-pack/plugins/observability/server/services/slo/find_slo.test.ts @@ -5,14 +5,13 @@ * 2.0. */ -import { ALL_VALUE, Paginated } from '@kbn/slo-schema'; -import { SLO_MODEL_VERSION } from '../../assets/constants'; +import { ALL_VALUE } from '@kbn/slo-schema'; import { SLO } from '../../domain/models'; import { FindSLO } from './find_slo'; import { createSLO } from './fixtures/slo'; import { createSLORepositoryMock, createSummarySearchClientMock } from './mocks'; import { SLORepository } from './slo_repository'; -import { SLOSummary, SummarySearchClient } from './summary_search_client'; +import { Paginated, SLOSummary, SummarySearchClient } from './summary_search_client'; describe('FindSLO', () => { let mockRepository: jest.Mocked; @@ -96,7 +95,6 @@ describe('FindSLO', () => { revision: slo.revision, groupBy: slo.groupBy, instanceId: ALL_VALUE, - version: SLO_MODEL_VERSION, }, ], }); diff --git a/x-pack/plugins/observability/server/services/slo/find_slo.ts b/x-pack/plugins/observability/server/services/slo/find_slo.ts index 6237b6e48832..cf8150db3e62 100644 --- a/x-pack/plugins/observability/server/services/slo/find_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/find_slo.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { FindSLOParams, FindSLOResponse, findSLOResponseSchema, Pagination } from '@kbn/slo-schema'; +import { FindSLOParams, FindSLOResponse, findSLOResponseSchema } from '@kbn/slo-schema'; import { SLO, SLOWithSummary } from '../../domain/models'; import { IllegalArgumentError } from '../../errors'; import { SLORepository } from './slo_repository'; -import { SLOSummary, Sort, SummarySearchClient } from './summary_search_client'; +import { Pagination, SLOSummary, Sort, SummarySearchClient } from './summary_search_client'; const DEFAULT_PAGE = 1; const DEFAULT_PER_PAGE = 25; @@ -55,7 +55,7 @@ function toPagination(params: FindSLOParams): Pagination { const perPage = Number(params.perPage); if (!isNaN(perPage) && perPage > MAX_PER_PAGE) { - throw new IllegalArgumentError(`perPage limit to ${MAX_PER_PAGE}`); + throw new IllegalArgumentError('perPage limit to 5000'); } return { diff --git a/x-pack/plugins/observability/server/services/slo/find_slo_definitions.ts b/x-pack/plugins/observability/server/services/slo/find_slo_definitions.ts index a9a4b8bf6175..157e5b4be569 100644 --- a/x-pack/plugins/observability/server/services/slo/find_slo_definitions.ts +++ b/x-pack/plugins/observability/server/services/slo/find_slo_definitions.ts @@ -5,40 +5,14 @@ * 2.0. */ -import { - FindSLODefinitionsParams, - FindSLODefinitionsResponse, - findSloDefinitionsResponseSchema, - Pagination, -} from '@kbn/slo-schema'; -import { IllegalArgumentError } from '../../errors'; +import { FindSloDefinitionsResponse, findSloDefinitionsResponseSchema } from '@kbn/slo-schema'; import { SLORepository } from './slo_repository'; -const MAX_PER_PAGE = 1000; -const DEFAULT_PER_PAGE = 100; -const DEFAULT_PAGE = 1; - export class FindSLODefinitions { constructor(private repository: SLORepository) {} - public async execute(params: FindSLODefinitionsParams): Promise { - const result = await this.repository.search(params.search ?? '', toPagination(params), { - includeOutdatedOnly: params.includeOutdatedOnly === true ? true : false, - }); - return findSloDefinitionsResponseSchema.encode(result); - } -} - -function toPagination(params: FindSLODefinitionsParams): Pagination { - const page = Number(params.page); - const perPage = Number(params.perPage); - - if (!isNaN(perPage) && perPage > MAX_PER_PAGE) { - throw new IllegalArgumentError(`perPage limit to ${MAX_PER_PAGE}`); + public async execute(search: string): Promise { + const sloList = await this.repository.search(search); + return findSloDefinitionsResponseSchema.encode(sloList); } - - return { - page: !isNaN(page) && page >= 1 ? page : DEFAULT_PAGE, - perPage: !isNaN(perPage) && perPage >= 1 ? perPage : DEFAULT_PER_PAGE, - }; } diff --git a/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts b/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts index 146900f64679..2bd320cbb8d6 100644 --- a/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts +++ b/x-pack/plugins/observability/server/services/slo/fixtures/slo.ts @@ -15,7 +15,6 @@ import { } from '@kbn/slo-schema'; import { cloneDeep } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; -import { SLO_MODEL_VERSION } from '../../../assets/constants'; import { APMTransactionDurationIndicator, APMTransactionErrorRateIndicator, @@ -140,7 +139,7 @@ export const createHistogramIndicator = ( }, }); -const defaultSLO: Omit = { +const defaultSLO: Omit = { name: 'irrelevant', description: 'irrelevant', timeWindow: sevenDaysRolling(), @@ -191,7 +190,6 @@ export const createSLO = (params: Partial = {}): SLO => { revision: 1, createdAt: now, updatedAt: now, - version: SLO_MODEL_VERSION, ...params, }); }; diff --git a/x-pack/plugins/observability/server/services/slo/get_preview_data.ts b/x-pack/plugins/observability/server/services/slo/get_preview_data.ts index 2fd80c09d387..ea8be2c3b6ef 100644 --- a/x-pack/plugins/observability/server/services/slo/get_preview_data.ts +++ b/x-pack/plugins/observability/server/services/slo/get_preview_data.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { calculateAuto } from '@kbn/calculate-auto'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { @@ -18,6 +19,7 @@ import { TimesliceMetricIndicator, } from '@kbn/slo-schema'; import { assertNever } from '@kbn/std'; +import moment from 'moment'; import { APMTransactionDurationIndicator } from '../../domain/models'; import { computeSLI } from '../../domain/services'; import { InvalidQueryError } from '../../errors'; @@ -27,11 +29,19 @@ import { GetTimesliceMetricIndicatorAggregation, } from './aggregations'; +interface Options { + range: { + start: number; + end: number; + }; + interval: string; +} export class GetPreviewData { constructor(private esClient: ElasticsearchClient) {} private async getAPMTransactionDurationPreviewData( - indicator: APMTransactionDurationIndicator + indicator: APMTransactionDurationIndicator, + options: Options ): Promise { const filter = []; if (indicator.params.service !== ALL_VALUE) @@ -61,7 +71,7 @@ export class GetPreviewData { query: { bool: { filter: [ - { range: { '@timestamp': { gte: 'now-60m' } } }, + { range: { '@timestamp': { gte: options.range.start, lte: options.range.end } } }, { terms: { 'processor.event': ['metric'] } }, { term: { 'metricset.name': 'transaction' } }, { exists: { field: 'transaction.duration.histogram' } }, @@ -73,7 +83,7 @@ export class GetPreviewData { perMinute: { date_histogram: { field: '@timestamp', - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { _good: { @@ -105,11 +115,17 @@ export class GetPreviewData { date: bucket.key_as_string, sliValue: !!bucket.good && !!bucket.total ? computeSLI(bucket.good.value, bucket.total.value) : null, + events: { + good: bucket.good?.value ?? 0, + bad: (bucket.total?.value ?? 0) - (bucket.good?.value ?? 0), + total: bucket.total?.value ?? 0, + }, })); } private async getAPMTransactionErrorPreviewData( - indicator: APMTransactionErrorRateIndicator + indicator: APMTransactionErrorRateIndicator, + options: Options ): Promise { const filter = []; if (indicator.params.service !== ALL_VALUE) @@ -137,7 +153,7 @@ export class GetPreviewData { query: { bool: { filter: [ - { range: { '@timestamp': { gte: 'now-60m' } } }, + { range: { '@timestamp': { gte: options.range.start, lte: options.range.end } } }, { term: { 'metricset.name': 'transaction' } }, { terms: { 'event.outcome': ['success', 'failure'] } }, ...filter, @@ -148,7 +164,7 @@ export class GetPreviewData { perMinute: { date_histogram: { field: '@timestamp', - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { good: { @@ -179,28 +195,37 @@ export class GetPreviewData { !!bucket.good && !!bucket.total ? computeSLI(bucket.good.doc_count, bucket.total.doc_count) : null, + events: { + good: bucket.good?.doc_count ?? 0, + bad: (bucket.total?.doc_count ?? 0) - (bucket.good?.doc_count ?? 0), + total: bucket.total?.doc_count ?? 0, + }, })); } private async getHistogramPreviewData( - indicator: HistogramIndicator + indicator: HistogramIndicator, + options: Options ): Promise { const getHistogramIndicatorAggregations = new GetHistogramIndicatorAggregation(indicator); const filterQuery = getElastichsearchQueryOrThrow(indicator.params.filter); const timestampField = indicator.params.timestampField; - const options = { + const result = await this.esClient.search({ index: indicator.params.index, size: 0, query: { bool: { - filter: [{ range: { [timestampField]: { gte: 'now-60m' } } }, filterQuery], + filter: [ + { range: { [timestampField]: { gte: options.range.start, lte: options.range.end } } }, + filterQuery, + ], }, }, aggs: { perMinute: { date_histogram: { field: timestampField, - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { ...getHistogramIndicatorAggregations.execute({ @@ -214,19 +239,24 @@ export class GetPreviewData { }, }, }, - }; - const result = await this.esClient.search(options); + }); // @ts-ignore buckets is not improperly typed return result.aggregations?.perMinute.buckets.map((bucket) => ({ date: bucket.key_as_string, sliValue: !!bucket.good && !!bucket.total ? computeSLI(bucket.good.value, bucket.total.value) : null, + events: { + good: bucket.good?.value ?? 0, + bad: (bucket.total?.value ?? 0) - (bucket.good?.value ?? 0), + total: bucket.total?.value ?? 0, + }, })); } private async getCustomMetricPreviewData( - indicator: MetricCustomIndicator + indicator: MetricCustomIndicator, + options: Options ): Promise { const timestampField = indicator.params.timestampField; const filterQuery = getElastichsearchQueryOrThrow(indicator.params.filter); @@ -236,14 +266,17 @@ export class GetPreviewData { size: 0, query: { bool: { - filter: [{ range: { [timestampField]: { gte: 'now-60m' } } }, filterQuery], + filter: [ + { range: { [timestampField]: { gte: options.range.start, lte: options.range.end } } }, + filterQuery, + ], }, }, aggs: { perMinute: { date_histogram: { field: timestampField, - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { ...getCustomMetricIndicatorAggregation.execute({ @@ -264,11 +297,17 @@ export class GetPreviewData { date: bucket.key_as_string, sliValue: !!bucket.good && !!bucket.total ? computeSLI(bucket.good.value, bucket.total.value) : null, + events: { + good: bucket.good?.value ?? 0, + bad: (bucket.total?.value ?? 0) - (bucket.good?.value ?? 0), + total: bucket.total?.value ?? 0, + }, })); } private async getTimesliceMetricPreviewData( - indicator: TimesliceMetricIndicator + indicator: TimesliceMetricIndicator, + options: Options ): Promise { const timestampField = indicator.params.timestampField; const filterQuery = getElastichsearchQueryOrThrow(indicator.params.filter); @@ -280,14 +319,17 @@ export class GetPreviewData { size: 0, query: { bool: { - filter: [{ range: { [timestampField]: { gte: 'now-60m' } } }, filterQuery], + filter: [ + { range: { [timestampField]: { gte: options.range.start, lte: options.range.end } } }, + filterQuery, + ], }, }, aggs: { perMinute: { date_histogram: { field: timestampField, - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { ...getCustomMetricIndicatorAggregation.execute('metric'), @@ -304,7 +346,8 @@ export class GetPreviewData { } private async getCustomKQLPreviewData( - indicator: KQLCustomIndicator + indicator: KQLCustomIndicator, + options: Options ): Promise { const filterQuery = getElastichsearchQueryOrThrow(indicator.params.filter); const goodQuery = getElastichsearchQueryOrThrow(indicator.params.good); @@ -315,14 +358,17 @@ export class GetPreviewData { size: 0, query: { bool: { - filter: [{ range: { [timestampField]: { gte: 'now-60m' } } }, filterQuery], + filter: [ + { range: { [timestampField]: { gte: options.range.start, lte: options.range.end } } }, + filterQuery, + ], }, }, aggs: { perMinute: { date_histogram: { field: timestampField, - fixed_interval: '1m', + fixed_interval: options.interval, }, aggs: { good: { filter: goodQuery }, @@ -339,25 +385,41 @@ export class GetPreviewData { !!bucket.good && !!bucket.total ? computeSLI(bucket.good.doc_count, bucket.total.doc_count) : null, + events: { + good: bucket.good?.doc_count ?? 0, + bad: (bucket.total?.doc_count ?? 0) - (bucket.good?.doc_count ?? 0), + total: bucket.total?.doc_count ?? 0, + }, })); } public async execute(params: GetPreviewDataParams): Promise { try { + const bucketSize = Math.max( + calculateAuto + .near(100, moment.duration(params.range.end - params.range.start, 'ms')) + ?.asMinutes() ?? 0, + 1 + ); + const options: Options = { + range: params.range, + interval: `${bucketSize}m`, + }; + const type = params.indicator.type; switch (type) { case 'sli.apm.transactionDuration': - return this.getAPMTransactionDurationPreviewData(params.indicator); + return this.getAPMTransactionDurationPreviewData(params.indicator, options); case 'sli.apm.transactionErrorRate': - return this.getAPMTransactionErrorPreviewData(params.indicator); + return this.getAPMTransactionErrorPreviewData(params.indicator, options); case 'sli.kql.custom': - return this.getCustomKQLPreviewData(params.indicator); + return this.getCustomKQLPreviewData(params.indicator, options); case 'sli.histogram.custom': - return this.getHistogramPreviewData(params.indicator); + return this.getHistogramPreviewData(params.indicator, options); case 'sli.metric.custom': - return this.getCustomMetricPreviewData(params.indicator); + return this.getCustomMetricPreviewData(params.indicator, options); case 'sli.metric.timeslice': - return this.getTimesliceMetricPreviewData(params.indicator); + return this.getTimesliceMetricPreviewData(params.indicator, options); default: assertNever(type); } diff --git a/x-pack/plugins/observability/server/services/slo/get_slo.test.ts b/x-pack/plugins/observability/server/services/slo/get_slo.test.ts index 148db2479970..1a5efccc9eb2 100644 --- a/x-pack/plugins/observability/server/services/slo/get_slo.test.ts +++ b/x-pack/plugins/observability/server/services/slo/get_slo.test.ts @@ -6,7 +6,6 @@ */ import { ALL_VALUE } from '@kbn/slo-schema'; -import { SLO_MODEL_VERSION } from '../../assets/constants'; import { createAPMTransactionErrorRateIndicator, createSLO } from './fixtures/slo'; import { GetSLO } from './get_slo'; import { createSummaryClientMock, createSLORepositoryMock } from './mocks'; @@ -85,7 +84,6 @@ describe('GetSLO', () => { revision: slo.revision, groupBy: slo.groupBy, instanceId: ALL_VALUE, - version: SLO_MODEL_VERSION, }); }); }); diff --git a/x-pack/plugins/observability/server/services/slo/reset_slo.test.ts b/x-pack/plugins/observability/server/services/slo/reset_slo.test.ts deleted file mode 100644 index 9b10bd944666..000000000000 --- a/x-pack/plugins/observability/server/services/slo/reset_slo.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ElasticsearchClient } from '@kbn/core/server'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -import { - getSLOTransformId, - SLO_DESTINATION_INDEX_PATTERN, - SLO_MODEL_VERSION, - SLO_SUMMARY_DESTINATION_INDEX_PATTERN, -} from '../../assets/constants'; -import { createSLO } from './fixtures/slo'; -import { createSLORepositoryMock, createTransformManagerMock } from './mocks'; -import { ResetSLO } from './reset_slo'; -import { SLORepository } from './slo_repository'; -import { TransformManager } from './transform_manager'; - -describe('ResetSLO', () => { - let mockRepository: jest.Mocked; - let mockTransformManager: jest.Mocked; - let mockEsClient: jest.Mocked; - let resetSLO: ResetSLO; - - beforeEach(() => { - mockRepository = createSLORepositoryMock(); - mockTransformManager = createTransformManagerMock(); - mockEsClient = elasticsearchServiceMock.createElasticsearchClient(); - resetSLO = new ResetSLO(mockEsClient, mockRepository, mockTransformManager); - }); - - it('resets the SLO', async () => { - const slo = createSLO({ version: 1 }); - mockRepository.findById.mockResolvedValueOnce(slo); - mockRepository.save.mockImplementation((v) => Promise.resolve(v)); - - await resetSLO.execute(slo.id); - - const transformId = getSLOTransformId(slo.id, slo.revision); - expect(mockTransformManager.stop).toBeCalledWith(transformId); - expect(mockTransformManager.uninstall).toBeCalledWith(transformId); - - expect(mockEsClient.deleteByQuery).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - index: SLO_DESTINATION_INDEX_PATTERN, - query: { - bool: { - filter: [{ term: { 'slo.id': slo.id } }], - }, - }, - }) - ); - expect(mockEsClient.deleteByQuery).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN, - query: { - bool: { - filter: [{ term: { 'slo.id': slo.id } }], - }, - }, - }) - ); - - expect(mockTransformManager.install).toBeCalledWith(slo); - expect(mockTransformManager.preview).toBeCalledWith(transformId); - expect(mockTransformManager.start).toBeCalledWith(transformId); - - expect(mockRepository.save).toHaveBeenCalledWith({ - ...slo, - version: SLO_MODEL_VERSION, - updatedAt: expect.anything(), - }); - }); -}); diff --git a/x-pack/plugins/observability/server/services/slo/reset_slo.ts b/x-pack/plugins/observability/server/services/slo/reset_slo.ts deleted file mode 100644 index e91bd68e8aa9..000000000000 --- a/x-pack/plugins/observability/server/services/slo/reset_slo.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ElasticsearchClient } from '@kbn/core/server'; -import { resetSLOResponseSchema } from '@kbn/slo-schema'; -import { - getSLOTransformId, - SLO_DESTINATION_INDEX_PATTERN, - SLO_MODEL_VERSION, - SLO_SUMMARY_DESTINATION_INDEX_PATTERN, - SLO_SUMMARY_TEMP_INDEX_NAME, -} from '../../assets/constants'; -import { SLORepository } from './slo_repository'; -import { createTempSummaryDocument } from './summary_transform/helpers/create_temp_summary'; -import { TransformManager } from './transform_manager'; - -export class ResetSLO { - constructor( - private esClient: ElasticsearchClient, - private repository: SLORepository, - private transformManager: TransformManager - ) {} - - public async execute(sloId: string) { - const slo = await this.repository.findById(sloId); - - const transformId = getSLOTransformId(slo.id, slo.revision); - await this.transformManager.stop(transformId); - await this.transformManager.uninstall(transformId); - - await Promise.all([this.deleteRollupData(slo.id), this.deleteSummaryData(slo.id)]); - - await this.transformManager.install(slo); - - try { - await this.transformManager.preview(transformId); - await this.transformManager.start(transformId); - } catch (err) { - await this.transformManager.uninstall(transformId); - throw err; - } - - await this.esClient.index({ - index: SLO_SUMMARY_TEMP_INDEX_NAME, - id: `slo-${slo.id}`, - document: createTempSummaryDocument(slo), - refresh: true, - }); - - const updatedSlo = await this.repository.save( - Object.assign({ ...slo, version: SLO_MODEL_VERSION, updatedAt: new Date() }) - ); - - return resetSLOResponseSchema.encode(updatedSlo); - } - - /** - * Deleting all SLI rollup data matching the sloId. All revision will be deleted in case of - * residual documents. - * - * @param sloId - */ - private async deleteRollupData(sloId: string): Promise { - await this.esClient.deleteByQuery({ - index: SLO_DESTINATION_INDEX_PATTERN, - refresh: true, - query: { - bool: { - filter: [{ term: { 'slo.id': sloId } }], - }, - }, - }); - } - - /** - * Deleting the summary documents matching the sloId. All revision will be deleted in case of - * residual documents. - * - * @param sloId - */ - private async deleteSummaryData(sloId: string): Promise { - await this.esClient.deleteByQuery({ - index: SLO_SUMMARY_DESTINATION_INDEX_PATTERN, - refresh: true, - query: { - bool: { - filter: [{ term: { 'slo.id': sloId } }], - }, - }, - }); - } -} diff --git a/x-pack/plugins/observability/server/services/slo/resource_installer.test.ts b/x-pack/plugins/observability/server/services/slo/resource_installer.test.ts index 4182c0ee9b68..8337c85b5f15 100644 --- a/x-pack/plugins/observability/server/services/slo/resource_installer.test.ts +++ b/x-pack/plugins/observability/server/services/slo/resource_installer.test.ts @@ -14,20 +14,15 @@ import { SLO_INGEST_PIPELINE_NAME, SLO_SUMMARY_COMPONENT_TEMPLATE_MAPPINGS_NAME, SLO_SUMMARY_COMPONENT_TEMPLATE_SETTINGS_NAME, - SLO_SUMMARY_ENRICH_POLICY_NAME, SLO_SUMMARY_INDEX_TEMPLATE_NAME, SLO_SUMMARY_INGEST_PIPELINE_NAME, } from '../../assets/constants'; -import { getSLOSummaryEnrichPolicy } from '../../assets/enrich_policies/slo_summary_enrich_policy'; import { DefaultResourceInstaller } from './resource_installer'; describe('resourceInstaller', () => { it('installs the common resources', async () => { const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient(); mockClusterClient.indices.getIndexTemplate.mockResponseOnce({ index_templates: [] }); - mockClusterClient.enrich.getPolicy.mockResponseOnce({ - policies: [], - }); const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create()); await installer.ensureCommonResourcesInstalled(); @@ -59,21 +54,6 @@ describe('resourceInstaller', () => { expect.objectContaining({ name: SLO_SUMMARY_INDEX_TEMPLATE_NAME }) ); - expect(mockClusterClient.enrich.getPolicy).toHaveBeenCalledTimes(1); - expect(mockClusterClient.enrich.getPolicy).toHaveBeenNthCalledWith(1, { - name: SLO_SUMMARY_ENRICH_POLICY_NAME, - }); - - expect(mockClusterClient.enrich.putPolicy).toHaveBeenCalledTimes(1); - expect(mockClusterClient.enrich.putPolicy).toHaveBeenNthCalledWith( - 1, - getSLOSummaryEnrichPolicy() - ); - expect(mockClusterClient.enrich.executePolicy).toHaveBeenCalledTimes(1); - expect(mockClusterClient.enrich.executePolicy).toHaveBeenNthCalledWith(1, { - name: SLO_SUMMARY_ENRICH_POLICY_NAME, - }); - expect(mockClusterClient.ingest.putPipeline).toHaveBeenCalledTimes(2); expect(mockClusterClient.ingest.putPipeline).toHaveBeenNthCalledWith( 1, @@ -84,34 +64,4 @@ describe('resourceInstaller', () => { expect.objectContaining({ id: SLO_SUMMARY_INGEST_PIPELINE_NAME }) ); }); - it('skips installing the enrich policy if it exists', async () => { - const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient(); - mockClusterClient.indices.getIndexTemplate.mockResponseOnce({ index_templates: [] }); - mockClusterClient.enrich.getPolicy.mockResponseOnce({ - policies: [ - { - config: { - // Sigh.... the Elasticsarch type for an enrich policy has defined the - // query as a string which is completely wrong, it's a QueryDSLContainer! - // - // See: https://github.com/elastic/elasticsearch-js/issues/2074 - match: { - ...getSLOSummaryEnrichPolicy().match, - name: SLO_SUMMARY_ENRICH_POLICY_NAME, - } as any, - }, - }, - ], - }); - const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create()); - - await installer.ensureCommonResourcesInstalled(); - - expect(mockClusterClient.enrich.getPolicy).toHaveBeenCalledTimes(1); - expect(mockClusterClient.enrich.getPolicy).toHaveBeenNthCalledWith(1, { - name: SLO_SUMMARY_ENRICH_POLICY_NAME, - }); - expect(mockClusterClient.enrich.putPolicy).not.toHaveBeenCalled(); - expect(mockClusterClient.enrich.executePolicy).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/observability/server/services/slo/resource_installer.ts b/x-pack/plugins/observability/server/services/slo/resource_installer.ts index dfc0960dc7b9..4fc77ea2399c 100644 --- a/x-pack/plugins/observability/server/services/slo/resource_installer.ts +++ b/x-pack/plugins/observability/server/services/slo/resource_installer.ts @@ -7,7 +7,6 @@ import type { ClusterPutComponentTemplateRequest, - EnrichPutPolicyRequest, IndicesPutIndexTemplateRequest, IngestPutPipelineRequest, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -32,7 +31,6 @@ import { SLO_SUMMARY_INGEST_PIPELINE_NAME, SLO_SUMMARY_TEMP_INDEX_NAME, } from '../../assets/constants'; -import { getSLOSummaryEnrichPolicy } from '../../assets/enrich_policies/slo_summary_enrich_policy'; import { getSLOIndexTemplate } from '../../assets/index_templates/slo_index_templates'; import { getSLOSummaryIndexTemplate } from '../../assets/index_templates/slo_summary_index_templates'; import { getSLOPipelineTemplate } from '../../assets/ingest_templates/slo_pipeline_template'; @@ -86,8 +84,6 @@ export class DefaultResourceInstaller implements ResourceInstaller { await this.createIndex(SLO_SUMMARY_DESTINATION_INDEX_NAME); await this.createIndex(SLO_SUMMARY_TEMP_INDEX_NAME); - await this.createOrUpdateEnrichPolicy(getSLOSummaryEnrichPolicy()); - await this.createOrUpdateIngestPipelineTemplate( getSLOPipelineTemplate(SLO_INGEST_PIPELINE_NAME, SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX) ); @@ -116,20 +112,6 @@ export class DefaultResourceInstaller implements ResourceInstaller { return this.execute(() => this.esClient.ingest.putPipeline(template)); } - private async createOrUpdateEnrichPolicy(policy: EnrichPutPolicyRequest) { - return this.execute(async () => { - const existingPolicy = await this.esClient.enrich.getPolicy({ name: policy.name }); - if (existingPolicy.policies.some(({ config }) => config.match?.name === policy.name)) { - this.logger.info(`SLO summary erich policy [${policy.name}] already exists.`); - return; - } - this.logger.info(`Installing SLO summary erich policy [${policy.name}]`); - return this.esClient.enrich - .putPolicy(policy) - .then(() => this.esClient.enrich.executePolicy({ name: policy.name })); - }); - } - private async createIndex(indexName: string) { try { await this.execute(() => this.esClient.indices.create({ index: indexName })); diff --git a/x-pack/plugins/observability/server/services/slo/slo_repository.test.ts b/x-pack/plugins/observability/server/services/slo/slo_repository.test.ts index 6956867b31c1..4b61bff04ea6 100644 --- a/x-pack/plugins/observability/server/services/slo/slo_repository.test.ts +++ b/x-pack/plugins/observability/server/services/slo/slo_repository.test.ts @@ -8,7 +8,6 @@ import { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import { sloSchema } from '@kbn/slo-schema'; -import { SLO_MODEL_VERSION } from '../../assets/constants'; import { SLO, StoredSLO } from '../../domain/models'; import { SLOIdConflict, SLONotFound } from '../../errors'; import { SO_SLO_TYPE } from '../../saved_objects'; @@ -165,42 +164,19 @@ describe('KibanaSavedObjectsSLORepository', () => { expect(soClientMock.delete).toHaveBeenCalledWith(SO_SLO_TYPE, SOME_SLO.id); }); - describe('search', () => { - it('searches by name', async () => { - const repository = new KibanaSavedObjectsSLORepository(soClientMock); - soClientMock.find.mockResolvedValueOnce(soFindResponse([SOME_SLO, ANOTHER_SLO])); - - const results = await repository.search(SOME_SLO.name, { page: 1, perPage: 100 }); - - expect(results.results).toEqual([SOME_SLO, ANOTHER_SLO]); - expect(soClientMock.find).toHaveBeenCalledWith({ - type: SO_SLO_TYPE, - page: 1, - perPage: 100, - search: SOME_SLO.name, - searchFields: ['name'], - }); - }); - - it('searches only the outdated ones', async () => { - const repository = new KibanaSavedObjectsSLORepository(soClientMock); - soClientMock.find.mockResolvedValueOnce(soFindResponse([SOME_SLO, ANOTHER_SLO])); + it('searches by name', async () => { + const repository = new KibanaSavedObjectsSLORepository(soClientMock); + soClientMock.find.mockResolvedValueOnce(soFindResponse([SOME_SLO, ANOTHER_SLO])); - const results = await repository.search( - SOME_SLO.name, - { page: 1, perPage: 100 }, - { includeOutdatedOnly: true } - ); + const results = await repository.search(SOME_SLO.name); - expect(results.results).toEqual([SOME_SLO, ANOTHER_SLO]); - expect(soClientMock.find).toHaveBeenCalledWith({ - type: SO_SLO_TYPE, - page: 1, - perPage: 100, - search: SOME_SLO.name, - searchFields: ['name'], - filter: `slo.attributes.version < ${SLO_MODEL_VERSION}`, - }); + expect(results).toEqual([SOME_SLO, ANOTHER_SLO]); + expect(soClientMock.find).toHaveBeenCalledWith({ + type: SO_SLO_TYPE, + page: 1, + perPage: 25, + search: SOME_SLO.name, + searchFields: ['name'], }); }); }); diff --git a/x-pack/plugins/observability/server/services/slo/slo_repository.ts b/x-pack/plugins/observability/server/services/slo/slo_repository.ts index 80d0e6368b4c..cc595ed0b009 100644 --- a/x-pack/plugins/observability/server/services/slo/slo_repository.ts +++ b/x-pack/plugins/observability/server/services/slo/slo_repository.ts @@ -7,11 +7,10 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; -import { Paginated, Pagination, sloSchema } from '@kbn/slo-schema'; +import { sloSchema } from '@kbn/slo-schema'; import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import * as t from 'io-ts'; -import { SLO_MODEL_VERSION } from '../../assets/constants'; import { SLO, StoredSLO } from '../../domain/models'; import { SLOIdConflict, SLONotFound } from '../../errors'; import { SO_SLO_TYPE } from '../../saved_objects'; @@ -21,11 +20,7 @@ export interface SLORepository { findAllByIds(ids: string[]): Promise; findById(id: string): Promise; deleteById(id: string): Promise; - search( - search: string, - pagination: Pagination, - options?: { includeOutdatedOnly?: boolean } - ): Promise>; + search(search: string): Promise; } export class KibanaSavedObjectsSLORepository implements SLORepository { @@ -104,28 +99,19 @@ export class KibanaSavedObjectsSLORepository implements SLORepository { } } - async search( - search: string, - pagination: Pagination, - options: { includeOutdatedOnly?: boolean } = { includeOutdatedOnly: false } - ): Promise> { - const response = await this.soClient.find({ - type: SO_SLO_TYPE, - page: pagination.page, - perPage: pagination.perPage, - search, - searchFields: ['name'], - ...(!!options.includeOutdatedOnly && { - filter: `slo.attributes.version < ${SLO_MODEL_VERSION}`, - }), - }); - - return { - total: response.total, - perPage: response.per_page, - page: response.page, - results: response.saved_objects.map((slo) => toSLO(slo.attributes)), - }; + async search(search: string): Promise { + try { + const response = await this.soClient.find({ + type: SO_SLO_TYPE, + page: 1, + perPage: 25, + search, + searchFields: ['name'], + }); + return response.saved_objects.map((slo) => toSLO(slo.attributes)); + } catch (err) { + throw err; + } } } @@ -135,13 +121,7 @@ function toStoredSLO(slo: SLO): StoredSLO { function toSLO(storedSLO: StoredSLO): SLO { return pipe( - sloSchema.decode({ - ...storedSLO, - // version was added in 8.12.0. This is a safeguard against SO migration issue. - // if not present, we considered the version to be 1, e.g. not migrated. - // We would need to call the _reset api on this SLO. - version: storedSLO.version ?? 1, - }), + sloSchema.decode(storedSLO), fold(() => { throw new Error('Invalid Stored SLO'); }, t.identity) diff --git a/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts b/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts index 9036611b1fed..fc53bf1e7181 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_search_client.test.ts @@ -7,13 +7,17 @@ import { ElasticsearchClientMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; -import { Pagination } from '@kbn/slo-schema/src/models/pagination'; import { aHitFromSummaryIndex, aHitFromTempSummaryIndex, aSummaryDocument, } from './fixtures/summary_search_document'; -import { DefaultSummarySearchClient, Sort, SummarySearchClient } from './summary_search_client'; +import { + DefaultSummarySearchClient, + Pagination, + Sort, + SummarySearchClient, +} from './summary_search_client'; const defaultSort: Sort = { field: 'sli_value', diff --git a/x-pack/plugins/observability/server/services/slo/summary_search_client.ts b/x-pack/plugins/observability/server/services/slo/summary_search_client.ts index 7412e1e6e0f8..f2bfa1ed29df 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_search_client.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_search_client.ts @@ -6,7 +6,7 @@ */ import { ElasticsearchClient, Logger } from '@kbn/core/server'; -import { ALL_VALUE, Paginated, Pagination } from '@kbn/slo-schema'; +import { ALL_VALUE } from '@kbn/slo-schema'; import { assertNever } from '@kbn/std'; import _ from 'lodash'; import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN } from '../../assets/constants'; @@ -30,6 +30,13 @@ interface EsSummaryDocument { isTempDoc: boolean; } +export interface Paginated { + total: number; + page: number; + perPage: number; + results: T[]; +} + export interface SLOSummary { id: SLOId; instanceId: string; @@ -42,6 +49,11 @@ export interface Sort { direction: 'asc' | 'desc'; } +export interface Pagination { + page: number; + perPage: number; +} + export interface SummarySearchClient { search(kqlQuery: string, sort: Sort, pagination: Pagination): Promise>; } diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/__snapshots__/summary_transform_installer.test.ts.snap b/x-pack/plugins/observability/server/services/slo/summary_transform/__snapshots__/summary_transform_installer.test.ts.snap index 4dba4a5b8988..5161c5e5cb51 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/__snapshots__/summary_transform_installer.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/__snapshots__/summary_transform_installer.test.ts.snap @@ -7,11 +7,11 @@ Array [ "_meta": Object { "managed": true, "managed_by": "observability", - "version": 4, + "version": 3, }, "description": "Summarize every SLO with timeslices budgeting method and a 7 days rolling time window", "dest": Object { - "index": ".slo-observability.summary-v3", + "index": ".slo-observability.summary-v2", "pipeline": ".slo-observability.summary.pipeline", }, "frequency": "1m", @@ -52,11 +52,6 @@ Array [ "field": "slo.isGoodSlice", }, }, - "latestSliTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, "sliValue": Object { "bucket_script": Object { "buckets_path": Object { @@ -112,21 +107,46 @@ Array [ "field": "slo.budgetingMethod", }, }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, "slo.timeWindow.duration": Object { "terms": Object { "field": "slo.timeWindow.duration", @@ -156,7 +176,7 @@ Array [ "unattended": true, }, "source": Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ @@ -199,8 +219,8 @@ Array [ }, "sync": Object { "time": Object { - "delay": "65s", - "field": "event.ingested", + "delay": "125s", + "field": "@timestamp", }, }, "transform_id": "slo-summary-timeslices-7d-rolling", @@ -216,11 +236,11 @@ Array [ "_meta": Object { "managed": true, "managed_by": "observability", - "version": 4, + "version": 3, }, "description": "Summarize every SLO with timeslices budgeting method and a 30 days rolling time window", "dest": Object { - "index": ".slo-observability.summary-v3", + "index": ".slo-observability.summary-v2", "pipeline": ".slo-observability.summary.pipeline", }, "frequency": "1m", @@ -261,11 +281,6 @@ Array [ "field": "slo.isGoodSlice", }, }, - "latestSliTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, "sliValue": Object { "bucket_script": Object { "buckets_path": Object { @@ -321,21 +336,46 @@ Array [ "field": "slo.budgetingMethod", }, }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, "slo.timeWindow.duration": Object { "terms": Object { "field": "slo.timeWindow.duration", @@ -365,7 +405,7 @@ Array [ "unattended": true, }, "source": Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ @@ -408,8 +448,8 @@ Array [ }, "sync": Object { "time": Object { - "delay": "65s", - "field": "event.ingested", + "delay": "125s", + "field": "@timestamp", }, }, "transform_id": "slo-summary-timeslices-30d-rolling", @@ -425,11 +465,11 @@ Array [ "_meta": Object { "managed": true, "managed_by": "observability", - "version": 4, + "version": 3, }, "description": "Summarize every SLO with timeslices budgeting method and a 90 days rolling time window", "dest": Object { - "index": ".slo-observability.summary-v3", + "index": ".slo-observability.summary-v2", "pipeline": ".slo-observability.summary.pipeline", }, "frequency": "1m", @@ -470,11 +510,6 @@ Array [ "field": "slo.isGoodSlice", }, }, - "latestSliTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, "sliValue": Object { "bucket_script": Object { "buckets_path": Object { @@ -530,21 +565,46 @@ Array [ "field": "slo.budgetingMethod", }, }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, "slo.timeWindow.duration": Object { "terms": Object { "field": "slo.timeWindow.duration", @@ -574,7 +634,7 @@ Array [ "unattended": true, }, "source": Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ @@ -617,8 +677,8 @@ Array [ }, "sync": Object { "time": Object { - "delay": "65s", - "field": "event.ingested", + "delay": "125s", + "field": "@timestamp", }, }, "transform_id": "slo-summary-timeslices-90d-rolling", @@ -634,11 +694,11 @@ Array [ "_meta": Object { "managed": true, "managed_by": "observability", - "version": 4, + "version": 3, }, "description": "Summarize every SLO with timeslices budgeting method and a weekly calendar aligned time window", "dest": Object { - "index": ".slo-observability.summary-v3", + "index": ".slo-observability.summary-v2", "pipeline": ".slo-observability.summary.pipeline", }, "frequency": "1m", @@ -694,11 +754,6 @@ Array [ "field": "slo.isGoodSlice", }, }, - "latestSliTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, "sliValue": Object { "bucket_script": Object { "buckets_path": Object { @@ -752,21 +807,46 @@ Array [ "field": "slo.budgetingMethod", }, }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, "slo.timeWindow.duration": Object { "terms": Object { "field": "slo.timeWindow.duration", @@ -796,7 +876,7 @@ Array [ "unattended": true, }, "source": Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ @@ -839,8 +919,8 @@ Array [ }, "sync": Object { "time": Object { - "delay": "65s", - "field": "event.ingested", + "delay": "125s", + "field": "@timestamp", }, }, "transform_id": "slo-summary-timeslices-weekly-aligned", @@ -856,11 +936,11 @@ Array [ "_meta": Object { "managed": true, "managed_by": "observability", - "version": 4, + "version": 3, }, "description": "Summarize every SLO with timeslices budgeting method and a monthly calendar aligned time window", "dest": Object { - "index": ".slo-observability.summary-v3", + "index": ".slo-observability.summary-v2", "pipeline": ".slo-observability.summary.pipeline", }, "frequency": "1m", @@ -883,7 +963,7 @@ Array [ }, "script": Object { "source": " - Date d = new Date(); + Date d = new Date(); Instant instant = Instant.ofEpochMilli(d.getTime()); LocalDateTime now = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); LocalDateTime startOfMonth = now @@ -893,7 +973,7 @@ Array [ .withSecond(0); LocalDateTime startOfNextMonth = startOfMonth.plusMonths(1); double sliceDurationInMinutes = params.sliceDurationInSeconds / 60; - + return Math.ceil(Duration.between(startOfMonth, startOfNextMonth).toMinutes() / sliceDurationInMinutes); ", }, @@ -931,11 +1011,6 @@ Array [ "field": "slo.isGoodSlice", }, }, - "latestSliTimestamp": Object { - "max": Object { - "field": "@timestamp", - }, - }, "sliValue": Object { "bucket_script": Object { "buckets_path": Object { @@ -989,21 +1064,46 @@ Array [ "field": "slo.budgetingMethod", }, }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, "slo.timeWindow.duration": Object { "terms": Object { "field": "slo.timeWindow.duration", @@ -1033,7 +1133,7 @@ Array [ "unattended": true, }, "source": Object { - "index": ".slo-observability.sli-v3*", + "index": ".slo-observability.sli-v2*", "query": Object { "bool": Object { "filter": Array [ @@ -1076,8 +1176,8 @@ Array [ }, "sync": Object { "time": Object { - "delay": "65s", - "field": "event.ingested", + "delay": "125s", + "field": "@timestamp", }, }, "transform_id": "slo-summary-timeslices-monthly-aligned", diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/common.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/common.ts index 9ae627b4cf20..c99a6c2be9d3 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/common.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/common.ts @@ -16,11 +16,36 @@ export const groupBy = { field: 'slo.revision', }, }, + 'slo.groupBy': { + terms: { + field: 'slo.groupBy', + }, + }, 'slo.instanceId': { terms: { field: 'slo.instanceId', }, }, + 'slo.name': { + terms: { + field: 'slo.name', + }, + }, + 'slo.description': { + terms: { + field: 'slo.description', + }, + }, + 'slo.tags': { + terms: { + field: 'slo.tags', + }, + }, + 'slo.indicator.type': { + terms: { + field: 'slo.indicator.type', + }, + }, 'slo.budgetingMethod': { terms: { field: 'slo.budgetingMethod', diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_30d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_30d_rolling.ts index b3ee6d1d9e51..4fea113a5423 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_30d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_30d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_OCCURRENCES_30D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_OCCURRENCES_30D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_7d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_7d_rolling.ts index 18fd235bfe11..629f7b234843 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_7d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_7d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_OCCURRENCES_7D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_OCCURRENCES_7D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_90d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_90d_rolling.ts index 7dcf080beefb..dfd77783ef3d 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_90d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_90d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_OCCURRENCES_90D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_OCCURRENCES_90D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_monthly_aligned.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_monthly_aligned.ts index 172758eae833..9d07bcf9cd5a 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_monthly_aligned.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_monthly_aligned.ts @@ -128,11 +128,6 @@ export const SUMMARY_OCCURRENCES_MONTHLY_ALIGNED: TransformPutTransformRequest = 'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }', }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -140,8 +135,8 @@ export const SUMMARY_OCCURRENCES_MONTHLY_ALIGNED: TransformPutTransformRequest = frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_weekly_aligned.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_weekly_aligned.ts index 923959a7db6e..0fc3ec19d3cf 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_weekly_aligned.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_occurrences_weekly_aligned.ts @@ -128,11 +128,6 @@ export const SUMMARY_OCCURRENCES_WEEKLY_ALIGNED: TransformPutTransformRequest = 'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }', }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -140,8 +135,8 @@ export const SUMMARY_OCCURRENCES_WEEKLY_ALIGNED: TransformPutTransformRequest = frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_30d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_30d_rolling.ts index facaab299f5e..5f48a86d0bca 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_30d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_30d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_TIMESLICES_30D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_TIMESLICES_30D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_7d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_7d_rolling.ts index 9edb2998dc1d..7a491337fba6 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_7d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_7d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_TIMESLICES_7D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_TIMESLICES_7D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_90d_rolling.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_90d_rolling.ts index 38473989dcd2..c26c9f84e554 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_90d_rolling.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_90d_rolling.ts @@ -130,11 +130,6 @@ export const SUMMARY_TIMESLICES_90D_ROLLING: TransformPutTransformRequest = { }, }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -142,8 +137,8 @@ export const SUMMARY_TIMESLICES_90D_ROLLING: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_monthly_aligned.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_monthly_aligned.ts index 370daa6e7b6e..18fd40a72940 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_monthly_aligned.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_monthly_aligned.ts @@ -78,7 +78,7 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest = }, script: { source: ` - Date d = new Date(); + Date d = new Date(); Instant instant = Instant.ofEpochMilli(d.getTime()); LocalDateTime now = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); LocalDateTime startOfMonth = now @@ -88,7 +88,7 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest = .withSecond(0); LocalDateTime startOfNextMonth = startOfMonth.plusMonths(1); double sliceDurationInMinutes = params.sliceDurationInSeconds / 60; - + return Math.ceil(Duration.between(startOfMonth, startOfNextMonth).toMinutes() / sliceDurationInMinutes); `, }, @@ -158,11 +158,6 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest = 'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }', }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -170,8 +165,8 @@ export const SUMMARY_TIMESLICES_MONTHLY_ALIGNED: TransformPutTransformRequest = frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_weekly_aligned.ts b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_weekly_aligned.ts index e85a298a3761..af062b7b6abe 100644 --- a/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_weekly_aligned.ts +++ b/x-pack/plugins/observability/server/services/slo/summary_transform/templates/summary_timeslices_weekly_aligned.ts @@ -143,11 +143,6 @@ export const SUMMARY_TIMESLICES_WEEKLY_ALIGNED: TransformPutTransformRequest = { 'if (params.sliValue == -1) { return 0 } else if (params.sliValue >= params.objective) { return 4 } else if (params.errorBudgetRemaining > 0) { return 2 } else { return 1 }', }, }, - latestSliTimestamp: { - max: { - field: '@timestamp', - }, - }, }, }, description: @@ -155,8 +150,8 @@ export const SUMMARY_TIMESLICES_WEEKLY_ALIGNED: TransformPutTransformRequest = { frequency: '1m', sync: { time: { - field: 'event.ingested', - delay: '65s', + field: '@timestamp', + delay: '125s', }, }, settings: { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap index 6b0214eee954..d5ac57c80e40 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap @@ -190,21 +190,66 @@ Object { "field": "service.environment", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, } `; @@ -259,21 +304,66 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, } `; @@ -323,21 +413,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -392,21 +527,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.type": Object { "terms": Object { "field": "transaction.type", @@ -420,11 +600,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -480,26 +660,71 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -569,30 +794,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.apm.transactionDuration')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -610,11 +889,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -661,21 +940,66 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -745,24 +1069,78 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.apm.transactionDuration')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap index d84eb813c5e1..c8d687383b51 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap @@ -178,21 +178,66 @@ Object { "field": "service.environment", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, } `; @@ -243,21 +288,66 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, } `; @@ -303,21 +393,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -368,21 +503,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.type": Object { "terms": Object { "field": "transaction.type", @@ -396,11 +576,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -449,26 +629,71 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -534,30 +759,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.apm.transactionErrorRate')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -575,11 +854,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -619,21 +898,66 @@ Object { "field": "service.name", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -699,24 +1023,78 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.apm.transactionErrorRate')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap index 900093be8f78..cdbdd8c52704 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap @@ -77,11 +77,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -151,26 +151,71 @@ Object { "fixed_interval": "2m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -208,30 +253,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.histogram.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -249,11 +348,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -314,21 +413,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -366,24 +510,78 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.histogram.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap index c207f1c21c2a..27da87629465 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -118,11 +118,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -166,26 +166,71 @@ Object { "fixed_interval": "2m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -223,30 +268,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.kql.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -264,11 +363,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -303,21 +402,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -355,24 +499,78 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.kql.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap index 6e633758bb3d..55ed414bd2ec 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap @@ -117,11 +117,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -203,26 +203,71 @@ Object { "fixed_interval": "2m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -260,30 +305,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.metric.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -301,11 +400,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -378,21 +477,66 @@ Object { "fixed_interval": "1m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -430,24 +574,78 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('occurrences')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.metric.custom')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.999)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/timeslice_metric.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/timeslice_metric.test.ts.snap index eaba259a5992..e2698ba3e179 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/timeslice_metric.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/timeslice_metric.test.ts.snap @@ -33,11 +33,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -173,26 +173,71 @@ Object { "fixed_interval": "2m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -227,30 +272,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.metric.timeslice')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { @@ -268,11 +367,11 @@ Object { "_meta": Object { "managed": true, "managed_by": "observability", - "version": 3, + "version": 2, }, "description": "Rolled-up SLI data for SLO: irrelevant", "dest": Object { - "index": ".slo-observability.sli-v3", + "index": ".slo-observability.sli-v2", "pipeline": ".slo-observability.sli.pipeline", }, "frequency": "1m", @@ -408,26 +507,71 @@ Object { "fixed_interval": "2m", }, }, + "slo.budgetingMethod": Object { + "terms": Object { + "field": "slo.budgetingMethod", + }, + }, + "slo.description": Object { + "terms": Object { + "field": "slo.description", + }, + }, + "slo.groupBy": Object { + "terms": Object { + "field": "slo.groupBy", + }, + }, "slo.id": Object { "terms": Object { "field": "slo.id", }, }, + "slo.indicator.type": Object { + "terms": Object { + "field": "slo.indicator.type", + }, + }, "slo.instanceId": Object { "terms": Object { "field": "slo.instanceId", }, }, + "slo.name": Object { + "terms": Object { + "field": "slo.name", + }, + }, "slo.objective.sliceDurationInSeconds": Object { "terms": Object { "field": "slo.objective.sliceDurationInSeconds", }, }, + "slo.objective.target": Object { + "terms": Object { + "field": "slo.objective.target", + }, + }, "slo.revision": Object { "terms": Object { "field": "slo.revision", }, }, + "slo.tags": Object { + "terms": Object { + "field": "slo.tags", + }, + }, + "slo.timeWindow.duration": Object { + "terms": Object { + "field": "slo.timeWindow.duration", + }, + }, + "slo.timeWindow.type": Object { + "terms": Object { + "field": "slo.timeWindow.type", + }, + }, }, }, "settings": Object { @@ -462,30 +606,84 @@ Object { }, }, "runtime_mappings": Object { + "slo.budgetingMethod": Object { + "script": Object { + "source": "emit('timeslices')", + }, + "type": "keyword", + }, + "slo.description": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, + "slo.groupBy": Object { + "script": Object { + "source": "emit('*')", + }, + "type": "keyword", + }, "slo.id": Object { "script": Object { "source": Any, }, "type": "keyword", }, + "slo.indicator.type": Object { + "script": Object { + "source": "emit('sli.metric.timeslice')", + }, + "type": "keyword", + }, "slo.instanceId": Object { "script": Object { "source": "emit('*')", }, "type": "keyword", }, + "slo.name": Object { + "script": Object { + "source": "emit('irrelevant')", + }, + "type": "keyword", + }, "slo.objective.sliceDurationInSeconds": Object { "script": Object { "source": "emit(120)", }, "type": "long", }, + "slo.objective.target": Object { + "script": Object { + "source": "emit(0.98)", + }, + "type": "double", + }, "slo.revision": Object { "script": Object { "source": "emit(1)", }, "type": "long", }, + "slo.tags": Object { + "script": Object { + "source": "emit('critical,k8s')", + }, + "type": "keyword", + }, + "slo.timeWindow.duration": Object { + "script": Object { + "source": "emit('7d')", + }, + "type": "keyword", + }, + "slo.timeWindow.type": Object { + "script": Object { + "source": "emit('rolling')", + }, + "type": "keyword", + }, }, }, "sync": Object { diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts index 66d75467836e..42572e61b38a 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/transform_generator.ts @@ -32,6 +32,12 @@ export abstract class TransformGenerator { source: `emit(${slo.revision})`, }, }, + 'slo.groupBy': { + type: 'keyword', + script: { + source: `emit('${!!slo.groupBy ? slo.groupBy : ALL_VALUE}')`, + }, + }, ...(mustIncludeAllInstanceId && { 'slo.instanceId': { type: 'keyword', @@ -40,6 +46,36 @@ export abstract class TransformGenerator { }, }, }), + 'slo.name': { + type: 'keyword', + script: { + source: `emit('${slo.name}')`, + }, + }, + 'slo.description': { + type: 'keyword', + script: { + source: `emit('${slo.description}')`, + }, + }, + 'slo.tags': { + type: 'keyword', + script: { + source: `emit('${slo.tags}')`, + }, + }, + 'slo.indicator.type': { + type: 'keyword', + script: { + source: `emit('${slo.indicator.type}')`, + }, + }, + 'slo.objective.target': { + type: 'double', + script: { + source: `emit(${slo.objective.target})`, + }, + }, ...(slo.objective.timesliceWindow && { 'slo.objective.sliceDurationInSeconds': { type: 'long', @@ -48,6 +84,24 @@ export abstract class TransformGenerator { }, }, }), + 'slo.budgetingMethod': { + type: 'keyword', + script: { + source: `emit('${slo.budgetingMethod}')`, + }, + }, + 'slo.timeWindow.duration': { + type: 'keyword', + script: { + source: `emit('${slo.timeWindow.duration.format()}')`, + }, + }, + 'slo.timeWindow.type': { + type: 'keyword', + script: { + source: `emit('${slo.timeWindow.type}')`, + }, + }, }; } @@ -71,12 +125,21 @@ export abstract class TransformGenerator { return { 'slo.id': { terms: { field: 'slo.id' } }, 'slo.revision': { terms: { field: 'slo.revision' } }, + 'slo.groupBy': { terms: { field: 'slo.groupBy' } }, 'slo.instanceId': { terms: { field: instanceIdField } }, + 'slo.name': { terms: { field: 'slo.name' } }, + 'slo.description': { terms: { field: 'slo.description' } }, + 'slo.tags': { terms: { field: 'slo.tags' } }, + 'slo.indicator.type': { terms: { field: 'slo.indicator.type' } }, + 'slo.objective.target': { terms: { field: 'slo.objective.target' } }, ...(slo.objective.timesliceWindow && { 'slo.objective.sliceDurationInSeconds': { terms: { field: 'slo.objective.sliceDurationInSeconds' }, }, }), + 'slo.budgetingMethod': { terms: { field: 'slo.budgetingMethod' } }, + 'slo.timeWindow.duration': { terms: { field: 'slo.timeWindow.duration' } }, + 'slo.timeWindow.type': { terms: { field: 'slo.timeWindow.type' } }, ...extraGroupByFields, // @timestamp field defined in the destination index '@timestamp': { diff --git a/x-pack/plugins/observability/server/services/slo/update_slo.test.ts b/x-pack/plugins/observability/server/services/slo/update_slo.test.ts index 2d1b588f215f..797f6eb2218e 100644 --- a/x-pack/plugins/observability/server/services/slo/update_slo.test.ts +++ b/x-pack/plugins/observability/server/services/slo/update_slo.test.ts @@ -8,7 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { UpdateSLOParams } from '@kbn/slo-schema'; -import { cloneDeep, omit, pick } from 'lodash'; +import { cloneDeep, pick, omit } from 'lodash'; import { getSLOTransformId, @@ -16,14 +16,12 @@ import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN, } from '../../assets/constants'; import { SLO } from '../../domain/models'; -import { fiveMinute, oneMinute, twoMinute } from './fixtures/duration'; +import { fiveMinute, oneMinute } from './fixtures/duration'; import { createAPMTransactionErrorRateIndicator, createSLO, createSLOWithTimeslicesBudgetingMethod, - createMetricCustomIndicator, } from './fixtures/slo'; -import { thirtyDaysRolling } from './fixtures/time_window'; import { createSLORepositoryMock, createTransformManagerMock } from './mocks'; import { SLORepository } from './slo_repository'; import { TransformManager } from './transform_manager'; @@ -33,23 +31,25 @@ describe('UpdateSLO', () => { let mockRepository: jest.Mocked; let mockTransformManager: jest.Mocked; let mockEsClient: jest.Mocked; - let mockSystemEsClient: jest.Mocked; let updateSLO: UpdateSLO; beforeEach(() => { mockRepository = createSLORepositoryMock(); mockTransformManager = createTransformManagerMock(); mockEsClient = elasticsearchServiceMock.createElasticsearchClient(); - mockSystemEsClient = elasticsearchServiceMock.createElasticsearchClient(); - updateSLO = new UpdateSLO( - mockRepository, - mockTransformManager, - mockEsClient, - mockSystemEsClient - ); + updateSLO = new UpdateSLO(mockRepository, mockTransformManager, mockEsClient); }); describe('when the update payload does not change the original SLO', () => { + function expectNoCallsToAnyMocks() { + expect(mockTransformManager.stop).not.toBeCalled(); + expect(mockTransformManager.uninstall).not.toBeCalled(); + expect(mockTransformManager.install).not.toBeCalled(); + expect(mockTransformManager.preview).not.toBeCalled(); + expect(mockTransformManager.start).not.toBeCalled(); + expect(mockEsClient.deleteByQuery).not.toBeCalled(); + } + it('returns early with a full identical SLO payload', async () => { const slo = createSLO(); mockRepository.findById.mockResolvedValueOnce(slo); @@ -157,14 +157,11 @@ describe('UpdateSLO', () => { }); }); - it("bumps the revision when changing 'settings'", async () => { + it('updates the settings correctly', async () => { const slo = createSLO(); mockRepository.findById.mockResolvedValueOnce(slo); - const newSettings = { - syncDelay: twoMinute(), - frequency: fiveMinute(), - }; + const newSettings = { ...slo.settings, timestamp_field: 'newField' }; await updateSLO.execute(slo.id, { settings: newSettings }); expectDeletionOfOriginalSLO(slo); @@ -172,14 +169,14 @@ describe('UpdateSLO', () => { expect.objectContaining({ ...slo, settings: newSettings, - revision: slo.revision + 1, + revision: 2, updatedAt: expect.anything(), }) ); expectInstallationOfNewSLOTransform(); }); - it("bumps the revision when changing 'budgetingMethod'", async () => { + it('updates the budgeting method correctly', async () => { const slo = createSLO({ budgetingMethod: 'occurrences' }); mockRepository.findById.mockResolvedValueOnce(slo); @@ -193,23 +190,10 @@ describe('UpdateSLO', () => { }); expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - budgetingMethod: 'timeslices', - objective: { - target: slo.objective.target, - timesliceTarget: 0.9, - timesliceWindow: oneMinute(), - }, - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); expectInstallationOfNewSLOTransform(); }); - it("bumps the revision when changing 'objective.timesliceTarget'", async () => { + it('updates the timeslice target correctly', async () => { const slo = createSLOWithTimeslicesBudgetingMethod(); mockRepository.findById.mockResolvedValueOnce(slo); @@ -222,22 +206,10 @@ describe('UpdateSLO', () => { }); expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - objective: { - target: slo.objective.target, - timesliceTarget: 0.1, - timesliceWindow: slo.objective.timesliceWindow, - }, - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); expectInstallationOfNewSLOTransform(); }); - it("bumps the revision when changing 'objective.timesliceWindow'", async () => { + it('consideres a timeslice window change as a breaking change', async () => { const slo = createSLOWithTimeslicesBudgetingMethod(); mockRepository.findById.mockResolvedValueOnce(slo); @@ -250,165 +222,41 @@ describe('UpdateSLO', () => { }); expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - objective: { - target: slo.objective.target, - timesliceTarget: slo.objective.timesliceTarget, - timesliceWindow: fiveMinute(), - }, - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); expectInstallationOfNewSLOTransform(); }); - it("bumps the revision when changing 'objective'", async () => { - const slo = createSLO(); - mockRepository.findById.mockResolvedValueOnce(slo); - - await updateSLO.execute(slo.id, { - objective: { - target: 0.5, - }, + it('index a temporary summary document', async () => { + const slo = createSLO({ + id: 'unique-id', + indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }), }); - - expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - objective: { - target: 0.5, - }, - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); - expectInstallationOfNewSLOTransform(); - }); - - it("bumps the revision when changing 'timeWindow'", async () => { - const slo = createSLO(); mockRepository.findById.mockResolvedValueOnce(slo); - await updateSLO.execute(slo.id, { - timeWindow: thirtyDaysRolling(), - }); + const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' }); + await updateSLO.execute(slo.id, { indicator: newIndicator }); - expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - timeWindow: thirtyDaysRolling(), - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); - expectInstallationOfNewSLOTransform(); + expect(mockEsClient.index.mock.calls[0]).toMatchSnapshot(); }); - it("bumps the revision when changing 'groupBy'", async () => { - const slo = createSLO({ groupBy: 'labels.projectId' }); - mockRepository.findById.mockResolvedValueOnce(slo); - - await updateSLO.execute(slo.id, { - groupBy: '*', + it('removes the original data from the original SLO', async () => { + const slo = createSLO({ + indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }), }); - - expectDeletionOfOriginalSLO(slo); - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - groupBy: '*', - revision: slo.revision + 1, - updatedAt: expect.anything(), - }) - ); - expectInstallationOfNewSLOTransform(); - }); - - it("bumps the revision when changing 'indicator'", async () => { - const slo = createSLO(); mockRepository.findById.mockResolvedValueOnce(slo); - await updateSLO.execute(slo.id, { - indicator: createMetricCustomIndicator(), - }); + const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' }); + await updateSLO.execute(slo.id, { indicator: newIndicator }); - expectDeletionOfOriginalSLO(slo); expect(mockRepository.save).toBeCalledWith( expect.objectContaining({ ...slo, - indicator: createMetricCustomIndicator(), - revision: slo.revision + 1, + indicator: newIndicator, + revision: 2, updatedAt: expect.anything(), }) ); expectInstallationOfNewSLOTransform(); - }); - - describe('when the revision does not bump', () => { - it('stores the updated SLO', async () => { - const slo = createSLO(); - mockRepository.findById.mockResolvedValueOnce(slo); - - await updateSLO.execute(slo.id, { - name: 'a new name', - description: 'a new description', - tags: ['some', 'new tags'], - }); - - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - name: 'a new name', - description: 'a new description', - tags: ['some', 'new tags'], - revision: slo.revision, - updatedAt: expect.anything(), - }) - ); - expectNoCallsToAnyMocks(); - }); - }); - - describe('when the revision bumps', () => { - it('indexes a temporary summary document', async () => { - const slo = createSLO({ - id: 'unique-id', - indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }), - }); - mockRepository.findById.mockResolvedValueOnce(slo); - - const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' }); - await updateSLO.execute(slo.id, { indicator: newIndicator }); - - expect(mockEsClient.index.mock.calls[0]).toMatchSnapshot(); - expect(mockSystemEsClient.enrich.executePolicy).toBeCalled(); - }); - - it('removes the original data from the original SLO', async () => { - const slo = createSLO({ - indicator: createAPMTransactionErrorRateIndicator({ environment: 'development' }), - }); - mockRepository.findById.mockResolvedValueOnce(slo); - - const newIndicator = createAPMTransactionErrorRateIndicator({ environment: 'production' }); - await updateSLO.execute(slo.id, { indicator: newIndicator }); - - expect(mockRepository.save).toBeCalledWith( - expect.objectContaining({ - ...slo, - indicator: newIndicator, - revision: 2, - updatedAt: expect.anything(), - }) - ); - expectInstallationOfNewSLOTransform(); - expectDeletionOfOriginalSLO(slo); - }); + expectDeletionOfOriginalSLO(slo); }); describe('when error happens during the transform installation step', () => { @@ -426,7 +274,6 @@ describe('UpdateSLO', () => { ); expect(mockRepository.save).toHaveBeenCalledWith(slo); - expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled(); expect(mockTransformManager.preview).not.toHaveBeenCalled(); expect(mockTransformManager.start).not.toHaveBeenCalled(); expect(mockTransformManager.stop).not.toHaveBeenCalled(); @@ -453,21 +300,11 @@ describe('UpdateSLO', () => { getSLOTransformId(slo.id, slo.revision + 1) ); expect(mockRepository.save).toHaveBeenCalledWith(slo); - expect(mockSystemEsClient.enrich.executePolicy).toHaveBeenCalled(); expect(mockTransformManager.stop).not.toHaveBeenCalled(); expect(mockEsClient.deleteByQuery).not.toHaveBeenCalled(); }); }); - function expectNoCallsToAnyMocks() { - expect(mockTransformManager.stop).not.toBeCalled(); - expect(mockTransformManager.uninstall).not.toBeCalled(); - expect(mockTransformManager.install).not.toBeCalled(); - expect(mockTransformManager.preview).not.toBeCalled(); - expect(mockTransformManager.start).not.toBeCalled(); - expect(mockEsClient.deleteByQuery).not.toBeCalled(); - } - function expectInstallationOfNewSLOTransform() { expect(mockTransformManager.install).toBeCalled(); expect(mockTransformManager.preview).toBeCalled(); diff --git a/x-pack/plugins/observability/server/services/slo/update_slo.ts b/x-pack/plugins/observability/server/services/slo/update_slo.ts index addf86584e47..97f6ed2e7bba 100644 --- a/x-pack/plugins/observability/server/services/slo/update_slo.ts +++ b/x-pack/plugins/observability/server/services/slo/update_slo.ts @@ -7,12 +7,11 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { UpdateSLOParams, UpdateSLOResponse, updateSLOResponseSchema } from '@kbn/slo-schema'; -import { isEqual, pick } from 'lodash'; +import { isEqual } from 'lodash'; import { getSLOTransformId, SLO_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_DESTINATION_INDEX_PATTERN, - SLO_SUMMARY_ENRICH_POLICY_NAME, SLO_SUMMARY_TEMP_INDEX_NAME, } from '../../assets/constants'; import { SLO } from '../../domain/models'; @@ -25,8 +24,7 @@ export class UpdateSLO { constructor( private repository: SLORepository, private transformManager: TransformManager, - private esClient: ElasticsearchClient, - private systemClient: ElasticsearchClient + private esClient: ElasticsearchClient ) {} public async execute(sloId: string, params: UpdateSLOParams): Promise { @@ -39,38 +37,23 @@ export class UpdateSLO { return this.toResponse(originalSlo); } - const fields = [ - 'indicator', - 'groupBy', - 'timeWindow', - 'objective', - 'budgetingMethod', - 'settings', - ]; - const requireRevisionBump = !isEqual(pick(originalSlo, fields), pick(updatedSlo, fields)); - updatedSlo = Object.assign(updatedSlo, { updatedAt: new Date(), - revision: requireRevisionBump ? originalSlo.revision + 1 : originalSlo.revision, + revision: originalSlo.revision + 1, }); validateSLO(updatedSlo); - await this.repository.save(updatedSlo); - await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }); - if (!requireRevisionBump) { - return this.toResponse(updatedSlo); - } + const updatedSloTransformId = getSLOTransformId(updatedSlo.id, updatedSlo.revision); + await this.repository.save(updatedSlo); try { await this.transformManager.install(updatedSlo); } catch (err) { await this.repository.save(originalSlo); - await this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }); throw err; } - const updatedSloTransformId = getSLOTransformId(updatedSlo.id, updatedSlo.revision); try { await this.transformManager.preview(updatedSloTransformId); await this.transformManager.start(updatedSloTransformId); @@ -78,7 +61,6 @@ export class UpdateSLO { await Promise.all([ this.transformManager.uninstall(updatedSloTransformId), this.repository.save(originalSlo), - this.systemClient.enrich.executePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }), ]); throw err; diff --git a/x-pack/plugins/observability/server/ui_settings.ts b/x-pack/plugins/observability/server/ui_settings.ts index 1facce3f0998..98260fff5f4c 100644 --- a/x-pack/plugins/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability/server/ui_settings.ts @@ -30,10 +30,13 @@ import { syntheticsThrottlingEnabled, enableLegacyUptimeApp, apmEnableProfilingIntegration, - profilingUseLegacyFlamegraphAPI, profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, + profilingUseLegacyCo2Calculation, + profilingPervCPUWattArm64, + profilingAWSCostDiscountRate, + profilingCostPervCPUPerHour, } from '../common/ui_settings_keys'; const betaLabel = i18n.translate('xpack.observability.uiSettings.betaLabel', { @@ -378,23 +381,30 @@ export const uiSettings: Record = { schema: schema.boolean(), requiresPageReload: false, }, - [profilingUseLegacyFlamegraphAPI]: { + [profilingPervCPUWattX86]: { category: [observabilityFeatureId], - name: i18n.translate('xpack.observability.profilingUseLegacyFlamegraphAPI', { - defaultMessage: 'Use legacy Flamegraph API in Universal Profiling', + name: i18n.translate('xpack.observability.profilingPervCPUWattX86UiSettingName', { + defaultMessage: 'Per vCPU Watts - x86', }), - value: false, - schema: schema.boolean(), + value: 7, + description: i18n.translate('xpack.observability.profilingPervCPUWattX86UiSettingDescription', { + defaultMessage: `The average amortized per-core power consumption (based on 100% CPU utilization) for x86 architecture.`, + }), + schema: schema.number({ min: 0 }), + requiresPageReload: true, }, - [profilingPerCoreWatt]: { + [profilingPervCPUWattArm64]: { category: [observabilityFeatureId], - name: i18n.translate('xpack.observability.profilingPerCoreWattUiSettingName', { - defaultMessage: 'Per Core Watts', - }), - value: 7, - description: i18n.translate('xpack.observability.profilingPerCoreWattUiSettingDescription', { - defaultMessage: `The average amortized per-core power consumption (based on 100% CPU utilization).`, + name: i18n.translate('xpack.observability.profilingPervCPUWattArm64UiSettingName', { + defaultMessage: 'Per vCPU Watts - arm64', }), + value: 2.8, + description: i18n.translate( + 'xpack.observability.profilingPervCPUWattArm64UiSettingDescription', + { + defaultMessage: `The average amortized per-core power consumption (based on 100% CPU utilization) for arm64 architecture.`, + } + ), schema: schema.number({ min: 0 }), requiresPageReload: true, }, @@ -450,6 +460,45 @@ export const uiSettings: Record = { schema: schema.number({ min: 0 }), requiresPageReload: true, }, + [profilingUseLegacyCo2Calculation]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.profilingUseLegacyCo2Calculation', { + defaultMessage: 'Use legacy CO2 and Dollar cost calculations in Universal Profiling', + }), + value: false, + schema: schema.boolean(), + }, + [profilingAWSCostDiscountRate]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.profilingAWSCostDiscountRateUiSettingName', { + defaultMessage: 'AWS EDP discount rate (%)', + }), + value: 6, + schema: schema.number({ min: 0, max: 100 }), + requiresPageReload: true, + description: i18n.translate( + 'xpack.observability.profilingAWSCostDiscountRateUiSettingDescription', + { + defaultMessage: + "If you're enrolled in the AWS Enterprise Discount Program (EDP), enter your discount rate to update the profiling cost calculation.", + } + ), + }, + [profilingCostPervCPUPerHour]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.profilingCostPervCPUPerHourUiSettingName', { + defaultMessage: 'Cost per vCPU per hour ($)', + }), + value: 0.0425, + description: i18n.translate( + 'xpack.observability.profilingCostPervCPUPerHourUiSettingNameDescription', + { + defaultMessage: `Default average cost per CPU core per hour (Non-AWS instances only)`, + } + ), + schema: schema.number({ min: 0, max: 100 }), + requiresPageReload: true, + }, }; function throttlingDocsLink({ href }: { href: string }) { diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index 57a1deb07133..15e2aade480c 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -71,6 +71,7 @@ "@kbn/rison", "@kbn/io-ts-utils", "@kbn/observability-alert-details", + "@kbn/observability-get-padded-alert-time-range-util", "@kbn/ui-actions-plugin", "@kbn/field-types", "@kbn/safer-lodash-set", @@ -94,7 +95,8 @@ "@kbn/core-chrome-browser", "@kbn/lens-embeddable-utils", "@kbn/serverless", - "@kbn/dashboard-plugin" + "@kbn/dashboard-plugin", + "@kbn/calculate-auto" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_ai_assistant/jest.config.js b/x-pack/plugins/observability_ai_assistant/jest.config.js index 5eaabe2dcf49..1d6798f6c762 100644 --- a/x-pack/plugins/observability_ai_assistant/jest.config.js +++ b/x-pack/plugins/observability_ai_assistant/jest.config.js @@ -10,4 +10,6 @@ module.exports = { rootDir: '../../..', roots: ['/x-pack/plugins/observability_ai_assistant'], setupFiles: ['/x-pack/plugins/observability_ai_assistant/.storybook/jest_setup.js'], + collectCoverage: true, + coverageReporters: ['html'], }; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/action_menu_item/action_menu_item.tsx b/x-pack/plugins/observability_ai_assistant/public/components/action_menu_item/action_menu_item.tsx index ca47c242df49..e77b055e568f 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/action_menu_item/action_menu_item.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/action_menu_item/action_menu_item.tsx @@ -6,19 +6,15 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiHeaderLink, EuiLoadingSpinner } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { ObservabilityAIAssistantChatServiceProvider } from '../../context/observability_ai_assistant_chat_service_provider'; import { useAbortableAsync } from '../../hooks/use_abortable_async'; -import { useConversation } from '../../hooks/use_conversation'; -import { useGenAIConnectors } from '../../hooks/use_genai_connectors'; import { useObservabilityAIAssistant } from '../../hooks/use_observability_ai_assistant'; -import { EMPTY_CONVERSATION_TITLE } from '../../i18n'; import { AssistantAvatar } from '../assistant_avatar'; import { ChatFlyout } from '../chat/chat_flyout'; export function ObservabilityAIAssistantActionMenuItem() { const service = useObservabilityAIAssistant(); - const connectors = useGenAIConnectors(); const [isOpen, setIsOpen] = useState(false); @@ -32,14 +28,7 @@ export function ObservabilityAIAssistantActionMenuItem() { [service, isOpen] ); - const [conversationId, setConversationId] = useState(); - - const { conversation, displayedMessages, setDisplayedMessages, save, saveTitle } = - useConversation({ - conversationId, - connectorId: connectors.selectedConnector, - chatService: chatService.value, - }); + const initialMessages = useMemo(() => [], []); if (!service.isEnabled()) { return null; @@ -72,26 +61,12 @@ export function ObservabilityAIAssistantActionMenuItem() { {chatService.value ? ( { - setIsOpen(() => false); - }} - onChatComplete={(messages) => { - save(messages) - .then((nextConversation) => { - setConversationId(nextConversation.conversation.id); - }) - .catch(() => {}); - }} - onChatUpdate={(nextMessages) => { - setDisplayedMessages(nextMessages); - }} - onChatTitleSave={(newTitle) => { - saveTitle(newTitle); + setIsOpen(false); }} /> diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.stories.tsx index 4b8d749abf9f..52c927795c41 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.stories.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.stories.tsx @@ -21,8 +21,8 @@ const meta: ComponentMeta = { export default meta; const defaultProps: ComponentStoryObj = { args: { - title: 'My Conversation', - messages: [ + initialTitle: 'My Conversation', + initialMessages: [ getAssistantSetupMessage({ contexts: [] }), { '@timestamp': new Date().toISOString(), @@ -64,8 +64,6 @@ const defaultProps: ComponentStoryObj = { currentUser: { username: 'elastic', }, - onChatUpdate: () => {}, - onChatComplete: () => {}, }, render: (props) => { return ( diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx index 5e4aa5e0659e..afbb042d2ead 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import React, { useEffect, useRef, useState } from 'react'; -import { flatten, last } from 'lodash'; import { + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -16,21 +15,26 @@ import { EuiSpacer, } from '@elastic/eui'; import { css } from '@emotion/css'; -import { euiThemeVars } from '@kbn/ui-theme'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import type { Message } from '../../../common/types'; +import { euiThemeVars } from '@kbn/ui-theme'; +import React, { useEffect, useRef, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { Conversation, Message, MessageRole } from '../../../common/types'; +import { ChatState } from '../../hooks/use_chat'; +import { useConversation } from '../../hooks/use_conversation'; import type { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors'; import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; -import { useTimeline } from '../../hooks/use_timeline'; import { useLicense } from '../../hooks/use_license'; import { useObservabilityAIAssistantChatService } from '../../hooks/use_observability_ai_assistant_chat_service'; -import { ExperimentalFeatureBanner } from './experimental_feature_banner'; -import { InitialSetupPanel } from './initial_setup_panel'; -import { IncorrectLicensePanel } from './incorrect_license_panel'; +import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; import { ChatHeader } from './chat_header'; import { ChatPromptEditor } from './chat_prompt_editor'; import { ChatTimeline } from './chat_timeline'; -import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; +import { ExperimentalFeatureBanner } from './experimental_feature_banner'; +import { IncorrectLicensePanel } from './incorrect_license_panel'; +import { InitialSetupPanel } from './initial_setup_panel'; +import { ChatActionClickType } from './types'; +import { EMPTY_CONVERSATION_TITLE } from '../../i18n'; const timelineClassName = css` overflow-y: auto; @@ -45,48 +49,45 @@ const incorrectLicenseContainer = css` padding: ${euiThemeVars.euiPanelPaddingModifiers.paddingMedium}; `; +const chatBodyContainerClassNameWithError = css` + align-self: center; +`; + export function ChatBody({ - title, - loading, - messages, + initialTitle, + initialMessages, + initialConversationId, connectors, knowledgeBase, connectorsManagementHref, modelsManagementHref, - conversationId, currentUser, startedFrom, - onChatUpdate, - onChatComplete, - onSaveTitle, + onConversationUpdate, }: { - title: string; - loading: boolean; - messages: Message[]; + initialTitle?: string; + initialMessages?: Message[]; + initialConversationId?: string; connectors: UseGenAIConnectorsResult; knowledgeBase: UseKnowledgeBaseResult; connectorsManagementHref: string; modelsManagementHref: string; - conversationId?: string; currentUser?: Pick; startedFrom?: StartedFrom; - onChatUpdate: (messages: Message[]) => void; - onChatComplete: (messages: Message[]) => void; - onSaveTitle: (title: string) => void; + onConversationUpdate: (conversation: Conversation) => void; }) { const license = useLicense(); const hasCorrectLicense = license?.hasAtLeast('enterprise'); const chatService = useObservabilityAIAssistantChatService(); - const timeline = useTimeline({ + const { conversation, messages, next, state, stop, saveTitle } = useConversation({ + initialConversationId, + initialMessages, + initialTitle, chatService, - connectors, - currentUser, - messages, - startedFrom, - onChatUpdate, - onChatComplete, + connectorId: connectors.selectedConnector, + onConversationUpdate, }); const timelineContainerRef = useRef(null); @@ -94,7 +95,10 @@ export function ChatBody({ let footer: React.ReactNode; const isLoading = Boolean( - connectors.loading || knowledgeBase.status.loading || last(flatten(timeline.items))?.loading + connectors.loading || + knowledgeBase.status.loading || + state === ChatState.Loading || + conversation.loading ); const containerClassName = css` @@ -139,12 +143,12 @@ export function ChatBody({ }); const handleCopyConversation = () => { - const content = JSON.stringify({ title, messages }); + const content = JSON.stringify({ title: initialTitle, messages }); navigator.clipboard?.writeText(content || ''); }; - if (!hasCorrectLicense && !conversationId) { + if (!hasCorrectLicense && !initialConversationId) { footer = ( <> @@ -155,19 +159,29 @@ export function ChatBody({ - + { + next(messages.concat(message)); + }} + /> ); - } else if (connectors.loading || knowledgeBase.status.loading) { + } else if ( + connectors.loading || + knowledgeBase.status.loading || + (!conversation.value && conversation.loading) + ) { footer = ( ); - } else if (connectors.connectors?.length === 0 && !conversationId) { + } else if (connectors.connectors?.length === 0 && !initialConversationId) { footer = ( { + const indexOf = messages.indexOf(editedMessage); + next(messages.slice(0, indexOf).concat(newMessage)); + }} + onFeedback={(message, feedback) => {}} + onRegenerate={(message) => { + const indexOf = messages.indexOf(message); + next(messages.slice(0, indexOf)); + }} + onStopGenerating={() => { + stop(); + }} onActionClick={(payload) => { setStickToBottom(true); - return timeline.onActionClick(payload); + switch (payload.type) { + case ChatActionClickType.executeEsqlQuery: + next( + messages.concat({ + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: '', + function_call: { + name: 'execute_query', + arguments: JSON.stringify({ + query: payload.query, + }), + trigger: MessageRole.User, + }, + }, + }) + ); + break; + } }} /> @@ -207,7 +253,7 @@ export function ChatBody({ disabled={!connectors.selectedConnector || !hasCorrectLicense} onSubmit={(message) => { setStickToBottom(true); - return timeline.onSubmit(message); + return next(messages.concat(message)); }} /> @@ -217,6 +263,33 @@ export function ChatBody({ ); } + if (conversation.error) { + return ( + + + + {i18n.translate('xpack.observabilityAiAssistant.couldNotFindConversationContent', { + defaultMessage: + 'Could not find a conversation with id {conversationId}. Make sure the conversation exists and you have access to it.', + values: { conversationId: initialConversationId }, + })} + + + + ); + } + return ( {connectors.selectedConnector ? ( @@ -224,20 +297,45 @@ export function ChatBody({
    ) : null} - + + {conversation.error ? ( + + {i18n.translate('xpack.observabilityAiAssistant.couldNotFindConversationContent', { + defaultMessage: + 'Could not find a conversation with id {conversationId}. Make sure the conversation exists and you have access to it.', + values: { conversationId: initialConversationId }, + })} + + ) : null} + { + saveTitle(newTitle); + }} /> diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_consolidated_items.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_consolidated_items.tsx index 346ccfe501f3..18a98c09ff38 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_consolidated_items.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_consolidated_items.tsx @@ -120,12 +120,12 @@ export function ChatConsolidatedItems({ key={index} {...item} onFeedbackClick={(feedback) => { - onFeedback(item, feedback); + onFeedback(item.message, feedback); }} onRegenerateClick={() => { - onRegenerate(item); + onRegenerate(item.message); }} - onEditSubmit={(message) => onEditSubmit(item, message)} + onEditSubmit={(message) => onEditSubmit(item.message, message)} onStopGeneratingClick={onStopGenerating} onActionClick={onActionClick} /> diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.stories.tsx index 30f56a6ab63a..bf54e20c3ec5 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.stories.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.stories.tsx @@ -29,13 +29,10 @@ const Template: ComponentStory = (props: ChatFlyoutProps) => { const defaultProps: ChatFlyoutProps = { isOpen: true, - title: 'How is this working', - messages: [getAssistantSetupMessage({ contexts: [] })], + initialTitle: 'How is this working', + initialMessages: [getAssistantSetupMessage({ contexts: [] })], startedFrom: 'appTopNavbar', onClose: () => {}, - onChatComplete: () => {}, - onChatTitleSave: () => {}, - onChatUpdate: () => {}, }; export const ChatFlyout = Template.bind({}); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx index ef4635d873e8..ef4961b87b7c 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx @@ -7,7 +7,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiFlyout, EuiLink, EuiPanel, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { useState } from 'react'; import type { Message } from '../../../common/types'; import { useCurrentUser } from '../../hooks/use_current_user'; import { useGenAIConnectors } from '../../hooks/use_genai_connectors'; @@ -28,25 +28,17 @@ const bodyClassName = css` `; export function ChatFlyout({ - title, - messages, - conversationId, + initialTitle, + initialMessages, + onClose, isOpen, startedFrom, - onClose, - onChatUpdate, - onChatComplete, - onChatTitleSave, }: { - title: string; - messages: Message[]; - conversationId?: string; + initialTitle: string; + initialMessages: Message[]; isOpen: boolean; startedFrom: StartedFrom; onClose: () => void; - onChatUpdate: (messages: Message[]) => void; - onChatComplete: (messages: Message[]) => void; - onChatTitleSave: (title: string) => void; }) { const { euiTheme } = useEuiTheme(); const { @@ -61,6 +53,8 @@ export function ChatFlyout({ const knowledgeBase = useKnowledgeBase(); + const [conversationId, setConversationId] = useState(undefined); + return isOpen ? ( { - if (onChatUpdate) { - onChatUpdate(nextMessages); - } - }} - onChatComplete={(nextMessages) => { - if (onChatComplete) { - onChatComplete(nextMessages); - } - }} - onSaveTitle={(newTitle) => { - onChatTitleSave(newTitle); + onConversationUpdate={(conversation) => { + setConversationId(conversation.conversation.id); }} /> diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx index 0630f9c36d9d..977b342bbe1d 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx @@ -90,7 +90,12 @@ export function ChatHeader({ { defaultMessage: 'Edit conversation' } )} editModeProps={{ inputProps: { inputRef } }} - isReadOnly={!connectors.selectedConnector || licenseInvalid || !Boolean(onSaveTitle)} + isReadOnly={ + !conversationId || + !connectors.selectedConnector || + licenseInvalid || + !Boolean(onSaveTitle) + } onSave={onSaveTitle} /> ) : null} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx index 7ec1084a26b2..09cb52a1c30b 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item.tsx @@ -27,7 +27,7 @@ import { FailedToLoadResponse } from '../message_panel/failed_to_load_response'; import { ChatActionClickHandler } from './types'; export interface ChatItemProps extends ChatTimelineItem { - onEditSubmit: (message: Message) => Promise; + onEditSubmit: (message: Message) => void; onFeedbackClick: (feedback: Feedback) => void; onRegenerateClick: () => void; onStopGeneratingClick: () => void; @@ -66,13 +66,14 @@ const noPanelMessageClassName = css` export function ChatItem({ actions: { canCopy, canEdit, canGiveFeedback, canRegenerate }, display: { collapsed }, + message: { + message: { function_call: functionCall, role }, + }, content, currentUser, element, error, - function_call: functionCall, loading, - role, title, onEditSubmit, onFeedbackClick, diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx index df57f069d91d..4f702eed2e16 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_content_inline_prompt_editor.tsx @@ -22,7 +22,7 @@ interface Props { | undefined; loading: boolean; editing: boolean; - onSubmit: (message: Message) => Promise; + onSubmit: (message: Message) => void; onActionClick: ChatActionClickHandler; } export function ChatItemContentInlinePromptEditor({ diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx index 21e9e3871205..f34288d5755e 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx @@ -5,20 +5,20 @@ * 2.0. */ -import React, { useCallback, useEffect, useRef, useState } from 'react'; import { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, + EuiFocusTrap, EuiPanel, EuiSpacer, EuiTextArea, keys, - EuiFocusTrap, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { CodeEditor } from '@kbn/kibana-react-plugin/public'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { MessageRole, type Message } from '../../../common'; import { useJsonEditorModel } from '../../hooks/use_json_editor_model'; import { FunctionListPopover } from './function_list_popover'; @@ -30,7 +30,7 @@ export interface ChatPromptEditorProps { initialSelectedFunctionName?: string; initialFunctionPayload?: string; trigger?: MessageRole; - onSubmit: (message: Message) => Promise; + onSubmit: (message: Message) => void; } export function ChatPromptEditor({ @@ -216,7 +216,10 @@ export function ChatPromptEditor({ {selectedFunctionName ? ( 8 ? '200px' : '120px'} @@ -284,7 +287,10 @@ export function ChatPromptEditor({ = (props: ChatTimelineProps) => { - const [count, setCount] = useState(props.items.length - 1); + const [count, setCount] = useState(props.messages.length - 1); return ( <> - index <= count)} /> + index <= count)} /> setCount(count >= 0 && count < props.items.length - 1 ? count + 1 : 0)} + onClick={() => setCount(count >= 0 && count < props.messages.length - 1 ? count + 1 : 0)} > Add message @@ -61,13 +63,23 @@ const defaultProps: ComponentProps = { installError: undefined, install: async () => {}, }, - items: [ - buildChatInitItem(), - buildUserChatItem(), - buildAssistantChatItem(), - buildUserChatItem({ content: 'How does it work?' }), - buildAssistantChatItem({ - content: `The way functions work depends on whether we are talking about mathematical functions or programming functions. Let's explore both: + chatService: { + hasRenderFunction: () => false, + } as unknown as ObservabilityAIAssistantChatService, + chatState: ChatState.Ready, + hasConnector: true, + currentUser: { + full_name: 'John Doe', + username: 'johndoe', + }, + messages: [ + buildSystemMessage(), + buildUserMessage(), + buildAssistantMessage(), + buildUserMessage({ message: { content: 'How does it work?' } }), + buildAssistantMessage({ + message: { + content: `The way functions work depends on whether we are talking about mathematical functions or programming functions. Let's explore both: Mathematical Functions: In mathematics, a function maps input values to corresponding output values based on a specific rule or expression. The general process of how a mathematical function works can be summarized as follows: @@ -78,55 +90,34 @@ const defaultProps: ComponentProps = { Step 3: Output - After processing the input, the function produces an output value, denoted as 'f(x)' or 'y'. This output represents the dependent variable and is the result of applying the function's rule to the input. Step 4: Uniqueness - A well-defined mathematical function ensures that each input value corresponds to exactly one output value. In other words, the function should yield the same output for the same input whenever it is called.`, + }, }), - buildUserChatItem({ - content: 'Can you execute a function?', + buildUserMessage({ + message: { content: 'Can you execute a function?' }, }), - buildAssistantChatItem({ - content: 'Sure, I can do that.', - title: 'suggested a function', - function_call: { - name: 'a_function', - arguments: '{ "foo": "bar" }', - trigger: MessageRole.Assistant, - }, - actions: { - canEdit: false, - canCopy: true, - canGiveFeedback: true, - canRegenerate: true, + buildAssistantMessage({ + message: { + content: 'Sure, I can do that.', + function_call: { + name: 'a_function', + arguments: '{ "foo": "bar" }', + trigger: MessageRole.Assistant, + }, }, }), - buildFunctionChatItem({ - content: '{ "message": "The arguments are wrong" }', - error: new Error(), - actions: { - canRegenerate: false, - canEdit: true, - canGiveFeedback: false, - canCopy: true, - }, + buildFunctionResponseMessage({ + message: { content: '{ "message": "The arguments are wrong" }' }, }), - buildAssistantChatItem({ - content: '', - title: 'suggested a function', - function_call: { - name: 'a_function', - arguments: '{ "bar": "foo" }', - trigger: MessageRole.Assistant, - }, - actions: { - canEdit: true, - canCopy: true, - canGiveFeedback: true, - canRegenerate: true, + buildAssistantMessage({ + message: { + content: '', + function_call: { + name: 'a_function', + arguments: '{ "bar": "foo" }', + trigger: MessageRole.Assistant, + }, }, }), - buildFunctionChatItem({ - content: '', - title: 'are executing a function', - loading: true, - }), ], onEdit: async () => {}, onFeedback: () => {}, diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx index e42924e76560..065208695349 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useMemo } from 'react'; import { css } from '@emotion/css'; import { EuiCommentList } from '@elastic/eui'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; @@ -16,6 +16,12 @@ import type { Feedback } from '../feedback_buttons'; import { type Message } from '../../../common'; import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; import type { ChatActionClickHandler } from './types'; +import { + getTimelineItemsfromConversation, + StartedFrom, +} from '../../utils/get_timeline_items_from_conversation'; +import { ObservabilityAIAssistantChatService } from '../../types'; +import { ChatState } from '../../hooks/use_chat'; export interface ChatTimelineItem extends Pick { @@ -35,27 +41,70 @@ export interface ChatTimelineItem element?: React.ReactNode; currentUser?: Pick; error?: any; + message: Message; } export interface ChatTimelineProps { - items: Array; + messages: Message[]; knowledgeBase: UseKnowledgeBaseResult; - onEdit: (item: ChatTimelineItem, message: Message) => Promise; - onFeedback: (item: ChatTimelineItem, feedback: Feedback) => void; - onRegenerate: (item: ChatTimelineItem) => void; + chatService: ObservabilityAIAssistantChatService; + hasConnector: boolean; + chatState: ChatState; + currentUser?: Pick; + startedFrom?: StartedFrom; + onEdit: (message: Message, messageAfterEdit: Message) => void; + onFeedback: (message: Message, feedback: Feedback) => void; + onRegenerate: (message: Message) => void; onStopGenerating: () => void; onActionClick: ChatActionClickHandler; } export function ChatTimeline({ - items = [], + messages, knowledgeBase, + chatService, + hasConnector, + currentUser, + startedFrom, onEdit, onFeedback, onRegenerate, onStopGenerating, onActionClick, + chatState, }: ChatTimelineProps) { + const items = useMemo(() => { + const timelineItems = getTimelineItemsfromConversation({ + chatService, + hasConnector, + messages, + currentUser, + startedFrom, + chatState, + }); + + const consolidatedChatItems: Array = []; + let currentGroup: ChatTimelineItem[] | null = null; + + for (const item of timelineItems) { + if (item.display.hide || !item) continue; + + if (item.display.collapsed) { + if (currentGroup) { + currentGroup.push(item); + } else { + currentGroup = [item]; + consolidatedChatItems.push(currentGroup); + } + } else { + consolidatedChatItems.push(item); + currentGroup = null; + } + } + + return consolidatedChatItems; + }, [chatService, hasConnector, messages, currentUser, startedFrom, chatState]); + return ( ) : ( - items.map((item, index) => - Array.isArray(item) ? ( + items.map((item, index) => { + return Array.isArray(item) ? ( { - onFeedback(item, feedback); + onFeedback(item.message, feedback); }} onRegenerateClick={() => { - onRegenerate(item); + onRegenerate(item.message); + }} + onEditSubmit={(message) => { + onEdit(item.message, message); }} - onEditSubmit={(message) => onEdit(item, message)} onStopGeneratingClick={onStopGenerating} onActionClick={onActionClick} /> - ) - ) + ); + }) )} ); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts b/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts index 4edd3d7dcdda..017f2f81a6f6 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/types.ts @@ -20,4 +20,4 @@ export enum ChatActionClickType { executeEsqlQuery = 'executeEsqlQuery', } -export type ChatActionClickHandler = (payload: ChatActionClickPayload) => Promise; +export type ChatActionClickHandler = (payload: ChatActionClickPayload) => void; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx index 8c6463ca9318..48ba86a98fbe 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx @@ -4,20 +4,17 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { first } from 'lodash'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { AbortError } from '@kbn/kibana-utils-plugin/common'; -import { isObservable, Subscription } from 'rxjs'; +import { last } from 'lodash'; +import React, { useEffect, useRef, useState } from 'react'; import { MessageRole, type Message } from '../../../common/types'; import { ObservabilityAIAssistantChatServiceProvider } from '../../context/observability_ai_assistant_chat_service_provider'; -import { useKibana } from '../../hooks/use_kibana'; import { useAbortableAsync } from '../../hooks/use_abortable_async'; -import { useConversation } from '../../hooks/use_conversation'; +import { ChatState, useChat } from '../../hooks/use_chat'; import { useGenAIConnectors } from '../../hooks/use_genai_connectors'; +import { useKibana } from '../../hooks/use_kibana'; import { useObservabilityAIAssistant } from '../../hooks/use_observability_ai_assistant'; import { useObservabilityAIAssistantChatService } from '../../hooks/use_observability_ai_assistant_chat_service'; -import type { PendingMessage } from '../../types'; import { getConnectorsManagementHref } from '../../utils/get_connectors_management_href'; import { RegenerateResponseButton } from '../buttons/regenerate_response_button'; import { StartChatButton } from '../buttons/start_chat_button'; @@ -40,197 +37,40 @@ function ChatContent({ }) { const chatService = useObservabilityAIAssistantChatService(); - const [pendingMessage, setPendingMessage] = useState(); - - const [loading, setLoading] = useState(false); - const [subscription, setSubscription] = useState(); + const initialMessagesRef = useRef(initialMessages); - const [conversationId, setConversationId] = useState(); - - const { - conversation, - displayedMessages, - setDisplayedMessages, - getSystemMessage, - save, - saveTitle, - } = useConversation({ - conversationId, - connectorId, + const { messages, next, state, stop } = useChat({ chatService, + connectorId, initialMessages, }); - const conversationTitle = conversationId - ? conversation.value?.conversation.title || '' - : defaultTitle; - - const controllerRef = useRef(new AbortController()); - - const reloadRecalledMessages = useCallback( - async (messages: Message[]) => { - controllerRef.current.abort(); - - const controller = (controllerRef.current = new AbortController()); - - const isStartOfConversation = - messages.some((message) => message.message.role === MessageRole.Assistant) === false; - - if (isStartOfConversation && chatService.hasFunction('recall')) { - // manually execute recall function and append to list of - // messages - const functionCall = { - name: 'recall', - args: JSON.stringify({ queries: [], contexts: [] }), - }; - - const response = await chatService.executeFunction({ - ...functionCall, - messages, - signal: controller.signal, - connectorId, - }); - - if (isObservable(response)) { - throw new Error('Recall function unexpectedly returned an Observable'); - } - - return [ - { - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.Assistant, - content: '', - function_call: { - name: functionCall.name, - arguments: functionCall.args, - trigger: MessageRole.User as const, - }, - }, - }, - { - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.User, - name: functionCall.name, - content: JSON.stringify(response.content), - }, - }, - ]; - } - - return []; - }, - [chatService, connectorId] + const lastAssistantResponse = last( + messages.filter((message) => message.message.role === MessageRole.Assistant) ); - const reloadConversation = useCallback(async () => { - setLoading(true); - - setDisplayedMessages(initialMessages); - setPendingMessage(undefined); - - const messages = [getSystemMessage(), ...initialMessages]; - - const recalledMessages = await reloadRecalledMessages(messages); - const next = messages.concat(recalledMessages); - - setDisplayedMessages(next); - - let lastPendingMessage: PendingMessage | undefined; - - const nextSubscription = chatService - .chat({ messages: next, connectorId, function: 'none' }) - .subscribe({ - next: (msg) => { - lastPendingMessage = msg; - setPendingMessage(() => msg); - }, - complete: () => { - setDisplayedMessages((prev) => - prev.concat({ - '@timestamp': new Date().toISOString(), - ...lastPendingMessage!, - }) - ); - setPendingMessage(lastPendingMessage); - setLoading(false); - }, - }); - - setSubscription(nextSubscription); - }, [ - reloadRecalledMessages, - chatService, - connectorId, - initialMessages, - getSystemMessage, - setDisplayedMessages, - ]); - - useEffect(() => { - reloadConversation(); - }, [reloadConversation]); - useEffect(() => { - setDisplayedMessages(initialMessages); - }, [initialMessages, setDisplayedMessages]); + next(initialMessagesRef.current); + }, [next]); const [isOpen, setIsOpen] = useState(false); - const messagesWithPending = useMemo(() => { - return pendingMessage - ? displayedMessages.concat({ - '@timestamp': new Date().toISOString(), - message: { - ...pendingMessage.message, - }, - }) - : displayedMessages; - }, [pendingMessage, displayedMessages]); - - const firstAssistantMessage = first( - messagesWithPending.filter( - (message) => - message.message.role === MessageRole.Assistant && - (!message.message.function_call?.trigger || - message.message.function_call.trigger === MessageRole.Assistant) - ) - ); - return ( <> {}} /> } - error={pendingMessage?.error} + error={state === ChatState.Error} controls={ - loading ? ( + state === ChatState.Loading ? ( { - subscription?.unsubscribe(); - setLoading(false); - setDisplayedMessages((prevMessages) => - prevMessages.concat({ - '@timestamp': new Date().toISOString(), - message: { - ...pendingMessage!.message, - }, - }) - ); - setPendingMessage((prev) => ({ - message: { - role: MessageRole.Assistant, - ...prev?.message, - }, - aborted: true, - error: new AbortError(), - })); + stop(); }} /> ) : ( @@ -238,7 +78,7 @@ function ChatContent({ { - reloadConversation(); + next(initialMessages); }} /> @@ -254,33 +94,27 @@ function ChatContent({ } /> { - setIsOpen(() => false); + setIsOpen(false); }} - messages={displayedMessages} - conversationId={conversationId} + initialMessages={messages} + initialTitle={defaultTitle} startedFrom="contextualInsight" - onChatComplete={(nextMessages) => { - save(nextMessages) - .then((nextConversation) => { - setConversationId(nextConversation.conversation.id); - }) - .catch(() => {}); - }} - onChatUpdate={(nextMessages) => { - setDisplayedMessages(nextMessages); - }} - onChatTitleSave={(newTitle) => { - saveTitle(newTitle); - }} /> ); } -export function Insight({ messages, title }: { messages: Message[]; title: string }) { +export function Insight({ + messages, + title, + dataTestSubj, +}: { + messages: Message[]; + title: string; + dataTestSubj?: string; +}) { const [hasOpened, setHasOpened] = useState(false); const connectors = useGenAIConnectors(); @@ -322,6 +156,7 @@ export function Insight({ messages, title }: { messages: Message[]; title: strin }} controls={} loading={connectors.loading || chatService.loading} + dataTestSubj={dataTestSubj} > {chatService.value ? ( diff --git a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.tsx b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.tsx index b6c0b4db906b..f288129c7ba9 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight_base.tsx @@ -32,6 +32,7 @@ export interface InsightBaseProps { onToggle: (isOpen: boolean) => void; children: React.ReactNode; loading?: boolean; + dataTestSubj?: string; } export function InsightBase({ @@ -44,6 +45,7 @@ export function InsightBase({ actions, onToggle, loading, + dataTestSubj = 'obsAiAssistantInsightButton', }: InsightBaseProps) { const { euiTheme } = useEuiTheme(); @@ -59,7 +61,7 @@ export function InsightBase({ id="obsAiAssistantInsight" arrowProps={{ css: { alignSelf: 'flex-start' } }} buttonContent={ - + diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx index 393bbeee28f8..9af3e3cf285b 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.stories.tsx @@ -71,7 +71,7 @@ export const ContentFailed: ComponentStoryObj = { onActionClick={async () => {}} /> ), - error: new Error(), + error: true, }, }; @@ -111,7 +111,7 @@ export const Controls: ComponentStoryObj = { onActionClick={async () => {}} /> ), - error: new Error(), + error: true, controls: {}} />, }, }; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.tsx index 78a1e8fae477..820ab2a55c27 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_panel.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { FailedToLoadResponse } from './failed_to_load_response'; interface Props { - error?: Error; + error?: boolean; body?: React.ReactNode; controls?: React.ReactNode; } diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_abortable_async.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_abortable_async.ts index a37624d44175..afd776dc1399 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_abortable_async.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_abortable_async.ts @@ -18,9 +18,9 @@ export type AbortableAsyncState = (T extends Promise : State) & { refresh: () => void }; export function useAbortableAsync( - fn: ({}: { signal: AbortSignal }) => T, + fn: ({}: { signal: AbortSignal }) => T | Promise, deps: any[], - options?: { clearValueOnNext?: boolean } + options?: { clearValueOnNext?: boolean; defaultValue?: () => T } ): AbortableAsyncState { const clearValueOnNext = options?.clearValueOnNext; @@ -30,7 +30,7 @@ export function useAbortableAsync( const [error, setError] = useState(); const [loading, setLoading] = useState(false); - const [value, setValue] = useState(); + const [value, setValue] = useState(options?.defaultValue); useEffect(() => { controllerRef.current.abort(); diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.test.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.test.ts new file mode 100644 index 000000000000..22bc997a4c92 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.test.ts @@ -0,0 +1,464 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; +import { type RenderHookResult, renderHook, act } from '@testing-library/react-hooks'; +import { Subject } from 'rxjs'; +import { MessageRole } from '../../common'; +import type { ObservabilityAIAssistantChatService, PendingMessage } from '../types'; +import { type UseChatResult, useChat, type UseChatProps, ChatState } from './use_chat'; +import * as useKibanaModule from './use_kibana'; + +type MockedChatService = DeeplyMockedKeys; + +const mockChatService: MockedChatService = { + chat: jest.fn(), + executeFunction: jest.fn(), + getContexts: jest.fn().mockReturnValue([{ name: 'core', description: '' }]), + getFunctions: jest.fn().mockReturnValue([]), + hasFunction: jest.fn().mockReturnValue(false), + hasRenderFunction: jest.fn().mockReturnValue(true), + renderFunction: jest.fn(), +}; + +const addErrorMock = jest.fn(); + +jest.spyOn(useKibanaModule, 'useKibana').mockReturnValue({ + services: { + notifications: { + toasts: { + addError: addErrorMock, + }, + }, + }, +} as any); + +let hookResult: RenderHookResult; + +describe('useChat', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('initially', () => { + beforeEach(() => { + hookResult = renderHook(useChat, { + initialProps: { + connectorId: 'my-connector', + chatService: mockChatService, + initialMessages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'hello', + }, + }, + ], + } as UseChatProps, + }); + }); + + it('returns the initial messages including the system message', () => { + const { messages } = hookResult.result.current; + expect(messages.length).toBe(2); + expect(messages[0].message.role).toBe('system'); + expect(messages[1].message.content).toBe('hello'); + }); + + it('sets chatState to ready', () => { + expect(hookResult.result.current.state).toBe(ChatState.Ready); + }); + }); + + describe('when calling next()', () => { + let subject: Subject; + + beforeEach(() => { + hookResult = renderHook(useChat, { + initialProps: { + connectorId: 'my-connector', + chatService: mockChatService, + initialMessages: [], + } as UseChatProps, + }); + + subject = new Subject(); + + mockChatService.chat.mockReturnValueOnce(subject); + + act(() => { + hookResult.result.current.next([ + ...hookResult.result.current.messages, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'hello', + }, + }, + ]); + }); + }); + + it('sets the chatState to loading', () => { + expect(hookResult.result.current.state).toBe(ChatState.Loading); + }); + + describe('after asking for another response', () => { + beforeEach(() => { + act(() => { + hookResult.result.current.next([]); + subject.next({ + message: { + role: MessageRole.User, + content: 'goodbye', + }, + }); + subject.complete(); + }); + }); + + it('shows an empty list of messages', () => { + expect(hookResult.result.current.messages.length).toBe(1); + expect(hookResult.result.current.messages[0].message.role).toBe(MessageRole.System); + }); + + it('aborts the running request', () => { + expect(subject.observed).toBe(false); + }); + }); + + describe('after a partial response', () => { + it('updates the returned messages', () => { + act(() => { + subject.next({ + message: { + content: 'good', + role: MessageRole.Assistant, + }, + }); + }); + + expect(hookResult.result.current.messages[2].message.content).toBe('good'); + }); + }); + + describe('after a completed response', () => { + it('updates the returned messages and the loading state', () => { + act(() => { + subject.next({ + message: { + content: 'good', + role: MessageRole.Assistant, + }, + }); + subject.next({ + message: { + content: 'goodbye', + role: MessageRole.Assistant, + }, + }); + subject.complete(); + }); + + expect(hookResult.result.current.messages[2].message.content).toBe('goodbye'); + expect(hookResult.result.current.state).toBe(ChatState.Ready); + }); + }); + + describe('after aborting a response', () => { + beforeEach(() => { + act(() => { + subject.next({ + message: { + content: 'good', + role: MessageRole.Assistant, + }, + aborted: true, + }); + subject.complete(); + }); + }); + + it('shows the partial message and sets chatState to aborted', () => { + expect(hookResult.result.current.messages[2].message.content).toBe('good'); + expect(hookResult.result.current.state).toBe(ChatState.Aborted); + }); + + it('does not show an error toast', () => { + expect(addErrorMock).not.toHaveBeenCalled(); + }); + }); + + describe('after a response errors out', () => { + beforeEach(() => { + act(() => { + subject.next({ + message: { + content: 'good', + role: MessageRole.Assistant, + }, + error: new Error('foo'), + }); + subject.complete(); + }); + }); + + it('shows the partial message and sets chatState to error', () => { + expect(hookResult.result.current.messages[2].message.content).toBe('good'); + expect(hookResult.result.current.state).toBe(ChatState.Error); + }); + + it('shows an error toast', () => { + expect(addErrorMock).toHaveBeenCalled(); + }); + }); + + describe('after the LLM responds with a function call', () => { + let resolve: (data: any) => void; + let reject: (error: Error) => void; + + beforeEach(() => { + mockChatService.executeFunction.mockResolvedValueOnce( + new Promise((...args) => { + resolve = args[0]; + reject = args[1]; + }) + ); + + act(() => { + subject.next({ + message: { + content: '', + role: MessageRole.Assistant, + function_call: { + name: 'my_function', + arguments: JSON.stringify({ foo: 'bar' }), + trigger: MessageRole.Assistant, + }, + }, + }); + subject.complete(); + }); + }); + + it('the chat state stays loading', () => { + expect(hookResult.result.current.state).toBe(ChatState.Loading); + }); + + it('adds a message', () => { + const { messages } = hookResult.result.current; + + expect(messages.length).toBe(3); + expect(messages[2]).toEqual({ + '@timestamp': expect.any(String), + message: { + content: '', + function_call: { + arguments: JSON.stringify({ foo: 'bar' }), + name: 'my_function', + trigger: MessageRole.Assistant, + }, + role: MessageRole.Assistant, + }, + }); + }); + + describe('the function call succeeds', () => { + beforeEach(async () => { + subject = new Subject(); + mockChatService.chat.mockReturnValueOnce(subject); + + await act(async () => { + resolve({ content: { foo: 'bar' }, data: { bar: 'foo' } }); + }); + }); + + it('adds a message', () => { + const { messages } = hookResult.result.current; + + expect(messages.length).toBe(4); + expect(messages[3]).toEqual({ + '@timestamp': expect.any(String), + message: { + content: JSON.stringify({ foo: 'bar' }), + data: JSON.stringify({ bar: 'foo' }), + name: 'my_function', + role: MessageRole.User, + }, + }); + }); + + it('keeps the chat state in loading', () => { + expect(hookResult.result.current.state).toBe(ChatState.Loading); + }); + it('sends the function call back to the LLM for a response', () => { + expect(mockChatService.chat).toHaveBeenCalledTimes(2); + expect(mockChatService.chat).toHaveBeenLastCalledWith({ + connectorId: 'my-connector', + messages: hookResult.result.current.messages, + }); + }); + }); + + describe('the function call fails', () => { + beforeEach(async () => { + subject = new Subject(); + mockChatService.chat.mockReturnValue(subject); + + await act(async () => { + reject(new Error('connection error')); + }); + }); + + it('keeps the chat state in loading', () => { + expect(hookResult.result.current.state).toBe(ChatState.Loading); + }); + + it('adds a message', () => { + const { messages } = hookResult.result.current; + + expect(messages.length).toBe(4); + expect(messages[3]).toEqual({ + '@timestamp': expect.any(String), + message: { + content: JSON.stringify({ + message: 'Error: connection error', + error: {}, + }), + name: 'my_function', + role: MessageRole.User, + }, + }); + }); + + it('does not show an error toast', () => { + expect(addErrorMock).not.toHaveBeenCalled(); + }); + + it('sends the function call back to the LLM for a response', () => { + expect(mockChatService.chat).toHaveBeenCalledTimes(2); + expect(mockChatService.chat).toHaveBeenLastCalledWith({ + connectorId: 'my-connector', + messages: hookResult.result.current.messages, + }); + }); + }); + + describe('stop() is called', () => { + beforeEach(() => { + act(() => { + hookResult.result.current.stop(); + }); + }); + + it('sets the chatState to aborted', () => { + expect(hookResult.result.current.state).toBe(ChatState.Aborted); + }); + + it('has called the abort controller', () => { + const signal = mockChatService.executeFunction.mock.calls[0][0].signal; + + expect(signal.aborted).toBe(true); + }); + + it('is not updated after the promise is rejected', () => { + const numRenders = hookResult.result.all.length; + + act(() => { + reject(new Error('Request aborted')); + }); + + expect(numRenders).toBe(hookResult.result.all.length); + }); + + it('removes all subscribers', () => { + expect(subject.observed).toBe(false); + }); + }); + + describe('setMessages() is called', () => {}); + }); + }); + + describe('when calling next() with the recall function available', () => { + let subject: Subject; + + beforeEach(async () => { + hookResult = renderHook(useChat, { + initialProps: { + connectorId: 'my-connector', + chatService: mockChatService, + initialMessages: [], + } as UseChatProps, + }); + + subject = new Subject(); + + mockChatService.hasFunction.mockReturnValue(true); + mockChatService.executeFunction.mockResolvedValueOnce({ + content: [ + { + id: 'my_document', + text: 'My text', + }, + ], + }); + + mockChatService.chat.mockReturnValueOnce(subject); + + await act(async () => { + hookResult.result.current.next([ + ...hookResult.result.current.messages, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'hello', + }, + }, + ]); + }); + }); + + it('adds a user message and a recall function request', () => { + expect(hookResult.result.current.messages[1].message.content).toBe('hello'); + expect(hookResult.result.current.messages[2].message.function_call?.name).toBe('recall'); + expect(hookResult.result.current.messages[2].message.content).toBe(''); + expect(hookResult.result.current.messages[2].message.function_call?.arguments).toBe( + JSON.stringify({ queries: [], contexts: [] }) + ); + expect(hookResult.result.current.messages[3].message.name).toBe('recall'); + expect(hookResult.result.current.messages[3].message.content).toBe( + JSON.stringify([ + { + id: 'my_document', + text: 'My text', + }, + ]) + ); + }); + + it('executes the recall function', () => { + expect(mockChatService.executeFunction).toHaveBeenCalled(); + expect(mockChatService.executeFunction).toHaveBeenCalledWith({ + signal: expect.any(AbortSignal), + connectorId: 'my-connector', + args: JSON.stringify({ queries: [], contexts: [] }), + name: 'recall', + messages: [...hookResult.result.current.messages.slice(0, -1)], + }); + }); + + it('sends the user message, function request and recall response to the LLM', () => { + expect(mockChatService.chat).toHaveBeenCalledWith({ + connectorId: 'my-connector', + messages: [...hookResult.result.current.messages], + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.ts new file mode 100644 index 000000000000..aeef36127f6c --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_chat.ts @@ -0,0 +1,260 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { last } from 'lodash'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { isObservable } from 'rxjs'; +import { type Message, MessageRole } from '../../common'; +import { getAssistantSetupMessage } from '../service/get_assistant_setup_message'; +import type { ObservabilityAIAssistantChatService, PendingMessage } from '../types'; +import { useKibana } from './use_kibana'; +import { useOnce } from './use_once'; + +export enum ChatState { + Ready = 'ready', + Loading = 'loading', + Error = 'error', + Aborted = 'aborted', +} + +export interface UseChatResult { + messages: Message[]; + setMessages: (messages: Message[]) => void; + state: ChatState; + next: (messages: Message[]) => void; + stop: () => void; +} + +export interface UseChatProps { + initialMessages: Message[]; + chatService: ObservabilityAIAssistantChatService; + connectorId?: string; + onChatComplete?: (messages: Message[]) => void; +} + +export function useChat({ + initialMessages, + chatService, + connectorId, + onChatComplete, +}: UseChatProps): UseChatResult { + const [chatState, setChatState] = useState(ChatState.Ready); + + const systemMessage = useMemo(() => { + return getAssistantSetupMessage({ contexts: chatService.getContexts() }); + }, [chatService]); + + useOnce(initialMessages); + + const [messages, setMessages] = useState(initialMessages); + + const [pendingMessage, setPendingMessage] = useState(); + + const abortControllerRef = useRef(new AbortController()); + + const { + services: { notifications }, + } = useKibana(); + + const onChatCompleteRef = useRef(onChatComplete); + + onChatCompleteRef.current = onChatComplete; + + const handleSignalAbort = useCallback(() => { + setChatState(ChatState.Aborted); + }, []); + + const next = useCallback( + async (nextMessages: Message[]) => { + // make sure we ignore any aborts for the previous signal + abortControllerRef.current.signal.removeEventListener('abort', handleSignalAbort); + + // cancel running requests + abortControllerRef.current.abort(); + + const lastMessage = last(nextMessages); + + const allMessages = [ + systemMessage, + ...nextMessages.filter((message) => message.message.role !== MessageRole.System), + ]; + + setMessages(allMessages); + + if (!lastMessage || !connectorId) { + setChatState(ChatState.Ready); + onChatCompleteRef.current?.(nextMessages); + return; + } + + const isUserMessage = lastMessage.message.role === MessageRole.User; + const functionCall = lastMessage.message.function_call; + const isAssistantMessageWithFunctionRequest = + lastMessage.message.role === MessageRole.Assistant && functionCall && !!functionCall.name; + + const isFunctionResult = isUserMessage && !!lastMessage.message.name; + + const isRecallFunctionAvailable = chatService.hasFunction('recall'); + + if (!isUserMessage && !isAssistantMessageWithFunctionRequest) { + setChatState(ChatState.Ready); + onChatCompleteRef.current?.(nextMessages); + return; + } + + const abortController = (abortControllerRef.current = new AbortController()); + + abortController.signal.addEventListener('abort', handleSignalAbort); + + setChatState(ChatState.Loading); + + if (isUserMessage && !isFunctionResult && isRecallFunctionAvailable) { + const allMessagesWithRecall = allMessages.concat({ + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: '', + function_call: { + name: 'recall', + arguments: JSON.stringify({ queries: [], contexts: [] }), + trigger: MessageRole.Assistant, + }, + }, + }); + next(allMessagesWithRecall); + return; + } + + function handleError(error: Error) { + setChatState(ChatState.Error); + notifications.toasts.addError(error, { + title: i18n.translate('xpack.observabilityAiAssistant.failedToLoadResponse', { + defaultMessage: 'Failed to load response from the AI Assistant', + }), + }); + } + + const response = isAssistantMessageWithFunctionRequest + ? await chatService + .executeFunction({ + name: functionCall.name, + signal: abortController.signal, + args: functionCall.arguments, + connectorId, + messages: allMessages, + }) + .catch((error) => { + return { + content: { + message: error.toString(), + error, + }, + data: undefined, + }; + }) + : chatService.chat({ + messages: allMessages, + connectorId, + }); + + if (abortController.signal.aborted) { + return; + } + + if (isObservable(response)) { + let localPendingMessage: PendingMessage = { + message: { + content: '', + role: MessageRole.User, + }, + }; + + const subscription = response.subscribe({ + next: (nextPendingMessage) => { + localPendingMessage = nextPendingMessage; + setPendingMessage(nextPendingMessage); + }, + complete: () => { + setPendingMessage(undefined); + const allMessagesWithResolved = allMessages.concat({ + message: { + ...localPendingMessage.message, + }, + '@timestamp': new Date().toISOString(), + }); + if (localPendingMessage.aborted) { + setChatState(ChatState.Aborted); + setMessages(allMessagesWithResolved); + } else if (localPendingMessage.error) { + handleError(localPendingMessage.error); + setMessages(allMessagesWithResolved); + } else { + next(allMessagesWithResolved); + } + }, + error: (error) => { + handleError(error); + }, + }); + + abortController.signal.addEventListener('abort', () => { + subscription.unsubscribe(); + }); + } else { + const allMessagesWithFunctionReply = allMessages.concat({ + '@timestamp': new Date().toISOString(), + message: { + name: functionCall!.name, + role: MessageRole.User, + content: JSON.stringify(response.content), + data: JSON.stringify(response.data), + }, + }); + next(allMessagesWithFunctionReply); + } + }, + [connectorId, chatService, handleSignalAbort, notifications.toasts, systemMessage] + ); + + useEffect(() => { + return () => { + abortControllerRef.current.abort(); + }; + }, []); + + const memoizedMessages = useMemo(() => { + const includingSystemMessage = [ + systemMessage, + ...messages.filter((message) => message.message.role !== MessageRole.System), + ]; + + return pendingMessage + ? includingSystemMessage.concat({ + ...pendingMessage, + '@timestamp': new Date().toISOString(), + }) + : includingSystemMessage; + }, [systemMessage, messages, pendingMessage]); + + const setMessagesWithAbort = useCallback((nextMessages: Message[]) => { + abortControllerRef.current.abort(); + setPendingMessage(undefined); + setChatState(ChatState.Ready); + setMessages(nextMessages); + }, []); + + return { + messages: memoizedMessages, + setMessages: setMessagesWithAbort, + state: chatState, + next, + stop: () => { + abortControllerRef.current.abort(); + }, + }; +} diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.test.tsx b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.test.tsx new file mode 100644 index 000000000000..884aaff592a4 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.test.tsx @@ -0,0 +1,703 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { + useConversation, + type UseConversationProps, + type UseConversationResult, +} from './use_conversation'; +import { + act, + renderHook, + type RenderHookResult, + type WrapperComponent, +} from '@testing-library/react-hooks'; +import type { ObservabilityAIAssistantService, PendingMessage } from '../types'; +import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; +import { ObservabilityAIAssistantProvider } from '../context/observability_ai_assistant_provider'; +import * as useKibanaModule from './use_kibana'; +import { Message, MessageRole } from '../../common'; +import { ChatState } from './use_chat'; +import { createMockChatService } from '../service/create_mock_chat_service'; +import { Subject } from 'rxjs'; +import { EMPTY_CONVERSATION_TITLE } from '../i18n'; +import { merge, omit } from 'lodash'; + +let hookResult: RenderHookResult; + +type MockedService = DeeplyMockedKeys; + +const mockService: MockedService = { + callApi: jest.fn(), + getCurrentUser: jest.fn(), + getLicense: jest.fn(), + getLicenseManagementLocator: jest.fn(), + isEnabled: jest.fn(), + start: jest.fn(), +}; + +const mockChatService = createMockChatService(); + +const addErrorMock = jest.fn(); + +jest.spyOn(useKibanaModule, 'useKibana').mockReturnValue({ + services: { + notifications: { + toasts: { + addError: addErrorMock, + }, + }, + }, +} as any); + +describe('useConversation', () => { + let wrapper: WrapperComponent; + + beforeEach(() => { + jest.clearAllMocks(); + wrapper = ({ children }) => ( + + {children} + + ); + }); + + describe('with initial messages and a conversation id', () => { + beforeEach(() => { + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialMessages: [ + { + '@timestamp': new Date().toISOString(), + message: { content: '', role: MessageRole.User }, + }, + ], + initialConversationId: 'foo', + }, + wrapper, + }); + }); + it('throws an error', () => { + expect(hookResult.result.error).toBeTruthy(); + }); + }); + + describe('without initial messages and a conversation id', () => { + beforeEach(() => { + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + }, + wrapper, + }); + }); + + it('returns only the system message', () => { + expect(hookResult.result.current.messages).toEqual([ + { + '@timestamp': expect.any(String), + message: { + content: '', + role: MessageRole.System, + }, + }, + ]); + }); + + it('returns a ready state', () => { + expect(hookResult.result.current.state).toBe(ChatState.Ready); + }); + + it('does not call the fetch api', () => { + expect(mockService.callApi).not.toHaveBeenCalled(); + }); + }); + + describe('with initial messages', () => { + beforeEach(() => { + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialMessages: [ + { + '@timestamp': new Date().toISOString(), + message: { + content: 'Test', + role: MessageRole.User, + }, + }, + ], + }, + wrapper, + }); + }); + + it('returns the system message and the initial messages', () => { + expect(hookResult.result.current.messages).toEqual([ + { + '@timestamp': expect.any(String), + message: { + content: '', + role: MessageRole.System, + }, + }, + { + '@timestamp': expect.any(String), + message: { + content: 'Test', + role: MessageRole.User, + }, + }, + ]); + }); + }); + + describe('with a conversation id that successfully loads', () => { + beforeEach(async () => { + mockService.callApi.mockResolvedValueOnce({ + conversation: { + id: 'my-conversation-id', + }, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'User', + }, + }, + ], + }); + + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialConversationId: 'my-conversation-id', + }, + wrapper, + }); + + await act(async () => {}); + }); + + it('returns the loaded conversation', () => { + expect(hookResult.result.current.conversation.value).toEqual({ + conversation: { + id: 'my-conversation-id', + }, + messages: [ + { + '@timestamp': expect.any(String), + message: { + content: 'System', + role: MessageRole.System, + }, + }, + { + '@timestamp': expect.any(String), + message: { + content: 'User', + role: MessageRole.User, + }, + }, + ], + }); + }); + + it('sets messages to the messages of the conversation', () => { + expect(hookResult.result.current.messages).toEqual([ + { + '@timestamp': expect.any(String), + message: { + content: expect.any(String), + role: MessageRole.System, + }, + }, + { + '@timestamp': expect.any(String), + message: { + content: 'User', + role: MessageRole.User, + }, + }, + ]); + }); + + it('overrides the system message', () => { + expect(hookResult.result.current.messages[0].message.content).toBe(''); + }); + }); + + describe('with a conversation id that fails to load', () => { + beforeEach(async () => { + mockService.callApi.mockRejectedValueOnce(new Error('failed to load')); + + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialConversationId: 'my-conversation-id', + }, + wrapper, + }); + + await act(async () => {}); + }); + + it('returns an error', () => { + expect(hookResult.result.current.conversation.error).toBeTruthy(); + }); + + it('resets the messages', () => { + expect(hookResult.result.current.messages.length).toBe(1); + }); + }); + + describe('when chat completes without an initial conversation id', () => { + let subject: Subject; + const expectedMessages = [ + { + '@timestamp': expect.any(String), + message: { + role: MessageRole.System, + content: '', + }, + }, + { + '@timestamp': expect.any(String), + message: { + role: MessageRole.User, + content: 'Hello', + }, + }, + { + '@timestamp': expect.any(String), + message: { + role: MessageRole.Assistant, + content: 'Goodbye', + }, + }, + { + '@timestamp': expect.any(String), + message: { + role: MessageRole.User, + content: 'Hello again', + }, + }, + { + '@timestamp': expect.any(String), + message: { + role: MessageRole.Assistant, + content: 'Goodbye again', + }, + }, + ]; + beforeEach(() => { + subject = new Subject(); + mockService.callApi.mockImplementation(async (endpoint, request) => + merge( + { + conversation: { + id: 'my-conversation-id', + }, + messages: expectedMessages, + }, + (request as any).params.body + ) + ); + + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialMessages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: 'Goodbye', + }, + }, + ], + }, + wrapper, + }); + + mockChatService.chat.mockImplementationOnce(() => { + return subject; + }); + + act(() => { + hookResult.result.current.next( + hookResult.result.current.messages.concat({ + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello again', + }, + }) + ); + }); + }); + + describe('when chat completes with an error', () => { + beforeEach(async () => { + mockService.callApi.mockClear(); + act(() => { + subject.next({ + message: { + role: MessageRole.Assistant, + content: 'Goodbye', + }, + error: new Error(), + }); + subject.complete(); + }); + await act(async () => {}); + }); + + it('does not store the conversation', () => { + expect(mockService.callApi).not.toHaveBeenCalled(); + }); + }); + + describe('when chat completes without an error', () => { + beforeEach(async () => { + act(() => { + subject.next({ + message: { + role: MessageRole.Assistant, + content: 'Goodbye again', + }, + }); + subject.complete(); + }); + + await act(async () => {}); + }); + it('the conversation is created including the initial messages', async () => { + expect(mockService.callApi.mock.calls[0]).toEqual([ + 'POST /internal/observability_ai_assistant/conversation', + { + params: { + body: { + conversation: { + '@timestamp': expect.any(String), + conversation: { + title: EMPTY_CONVERSATION_TITLE, + }, + messages: expectedMessages, + labels: {}, + numeric_labels: {}, + public: false, + }, + }, + }, + signal: null, + }, + ]); + + expect(hookResult.result.current.conversation.error).toBeUndefined(); + + expect(hookResult.result.current.messages).toEqual(expectedMessages); + }); + }); + }); + + describe('when chat completes with an initial conversation id', () => { + let subject: Subject; + + const initialMessages: Message[] = [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: '', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'user', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: 'assistant', + }, + }, + ]; + + beforeEach(async () => { + mockService.callApi.mockImplementation(async (endpoint, request) => ({ + '@timestamp': new Date().toISOString(), + conversation: { + id: 'my-conversation-id', + title: EMPTY_CONVERSATION_TITLE, + }, + labels: {}, + numeric_labels: {}, + public: false, + messages: initialMessages, + })); + + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialConversationId: 'my-conversation-id', + }, + wrapper, + }); + + await act(async () => {}); + }); + + it('the conversation is loadeded', async () => { + expect(mockService.callApi.mock.calls[0]).toEqual([ + 'GET /internal/observability_ai_assistant/conversation/{conversationId}', + { + signal: expect.anything(), + params: { + path: { + conversationId: 'my-conversation-id', + }, + }, + }, + ]); + + expect(hookResult.result.current.messages).toEqual( + initialMessages.map((msg) => ({ ...msg, '@timestamp': expect.any(String) })) + ); + }); + + describe('after chat completes', () => { + const nextUserMessage: Message = { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello again', + }, + }; + + const nextAssistantMessage: Message = { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: 'Goodbye again', + }, + }; + + beforeEach(async () => { + mockService.callApi.mockClear(); + subject = new Subject(); + + mockChatService.chat.mockImplementationOnce(() => { + return subject; + }); + + act(() => { + hookResult.result.current.next( + hookResult.result.current.messages.concat(nextUserMessage) + ); + subject.next(omit(nextAssistantMessage, '@timestamp')); + subject.complete(); + }); + + await act(async () => {}); + }); + + it('saves the updated message', () => { + expect(mockService.callApi.mock.calls[0]).toEqual([ + 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', + { + params: { + path: { + conversationId: 'my-conversation-id', + }, + body: { + conversation: { + '@timestamp': expect.any(String), + conversation: { + title: EMPTY_CONVERSATION_TITLE, + id: 'my-conversation-id', + }, + messages: initialMessages + .concat([nextUserMessage, nextAssistantMessage]) + .map((msg) => ({ ...msg, '@timestamp': expect.any(String) })), + labels: {}, + numeric_labels: {}, + public: false, + }, + }, + }, + signal: null, + }, + ]); + }); + }); + }); + + describe('when the title is updated', () => { + describe('without a stored conversation', () => { + beforeEach(() => { + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialMessages: [ + { + '@timestamp': new Date().toISOString(), + message: { content: '', role: MessageRole.User }, + }, + ], + initialConversationId: 'foo', + }, + wrapper, + }); + }); + + it('throws an error', () => { + expect(() => hookResult.result.current.saveTitle('my-new-title')).toThrow(); + }); + }); + + describe('with a stored conversation', () => { + let resolve: (value: unknown) => void; + beforeEach(async () => { + mockService.callApi.mockImplementation(async (endpoint, request) => { + if ( + endpoint === 'PUT /internal/observability_ai_assistant/conversation/{conversationId}' + ) { + return new Promise((_resolve) => { + resolve = _resolve; + }); + } + return { + '@timestamp': new Date().toISOString(), + conversation: { + id: 'my-conversation-id', + title: EMPTY_CONVERSATION_TITLE, + }, + labels: {}, + numeric_labels: {}, + public: false, + messages: [], + }; + }); + + await act(async () => { + hookResult = renderHook(useConversation, { + initialProps: { + chatService: mockChatService, + connectorId: 'my-connector', + initialConversationId: 'my-conversation-id', + }, + wrapper, + }); + }); + }); + + it('does not throw an error', () => { + expect(() => hookResult.result.current.saveTitle('my-new-title')).not.toThrow(); + }); + + it('calls the update API', async () => { + act(() => { + hookResult.result.current.saveTitle('my-new-title'); + }); + + expect(resolve).not.toBeUndefined(); + + expect(mockService.callApi.mock.calls[1]).toEqual([ + 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', + { + signal: null, + params: { + path: { + conversationId: 'my-conversation-id', + }, + body: { + conversation: { + '@timestamp': expect.any(String), + conversation: { + title: 'my-new-title', + id: 'my-conversation-id', + }, + labels: expect.anything(), + messages: expect.anything(), + numeric_labels: expect.anything(), + public: expect.anything(), + }, + }, + }, + }, + ]); + + mockService.callApi.mockImplementation(async (endpoint, request) => { + return { + '@timestamp': new Date().toISOString(), + conversation: { + id: 'my-conversation-id', + title: 'my-new-title', + }, + labels: {}, + numeric_labels: {}, + public: false, + messages: [], + }; + }); + + await act(async () => { + resolve({ + conversation: { + title: 'my-new-title', + }, + }); + }); + + expect(mockService.callApi.mock.calls[2]).toEqual([ + 'GET /internal/observability_ai_assistant/conversation/{conversationId}', + { + signal: expect.anything(), + params: { + path: { + conversationId: 'my-conversation-id', + }, + }, + }, + ]); + + expect(hookResult.result.current.conversation.value?.conversation.title).toBe( + 'my-new-title' + ); + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts index 6970c53e28bf..c753f7c7b192 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts @@ -6,145 +6,127 @@ */ import { i18n } from '@kbn/i18n'; import { merge, omit } from 'lodash'; -import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react'; -import { type Conversation, type Message } from '../../common'; -import { ConversationCreateRequest, MessageRole } from '../../common/types'; -import { getAssistantSetupMessage } from '../service/get_assistant_setup_message'; -import { ObservabilityAIAssistantChatService } from '../types'; +import { useState } from 'react'; +import type { Conversation, Message } from '../../common'; +import type { ConversationCreateRequest } from '../../common/types'; +import { EMPTY_CONVERSATION_TITLE } from '../i18n'; +import type { ObservabilityAIAssistantChatService } from '../types'; import { useAbortableAsync, type AbortableAsyncState } from './use_abortable_async'; +import { useChat, UseChatResult } from './use_chat'; import { useKibana } from './use_kibana'; import { useObservabilityAIAssistant } from './use_observability_ai_assistant'; -import { createNewConversation } from './use_timeline'; +import { useOnce } from './use_once'; + +function createNewConversation({ + title = EMPTY_CONVERSATION_TITLE, +}: { title?: string } = {}): ConversationCreateRequest { + return { + '@timestamp': new Date().toISOString(), + messages: [], + conversation: { + title, + }, + labels: {}, + numeric_labels: {}, + public: false, + }; +} + +export interface UseConversationProps { + initialConversationId?: string; + initialMessages?: Message[]; + initialTitle?: string; + chatService: ObservabilityAIAssistantChatService; + connectorId: string | undefined; + onConversationUpdate?: (conversation: Conversation) => void; +} + +export type UseConversationResult = { + conversation: AbortableAsyncState; + saveTitle: (newTitle: string) => void; +} & Omit; + +const DEFAULT_INITIAL_MESSAGES: Message[] = []; export function useConversation({ - conversationId, + initialConversationId: initialConversationIdFromProps, + initialMessages: initialMessagesFromProps = DEFAULT_INITIAL_MESSAGES, + initialTitle: initialTitleFromProps, chatService, connectorId, - initialMessages = [], -}: { - conversationId?: string; - chatService?: ObservabilityAIAssistantChatService; // will eventually resolve to a non-nullish value - connectorId: string | undefined; - initialMessages?: Message[]; -}): { - conversation: AbortableAsyncState; - displayedMessages: Message[]; - setDisplayedMessages: Dispatch>; - getSystemMessage: () => Message; - save: (messages: Message[], handleRefreshConversations?: () => void) => Promise; - saveTitle: ( - title: string, - handleRefreshConversations?: () => void - ) => Promise; -} { + onConversationUpdate, +}: UseConversationProps): UseConversationResult { const service = useObservabilityAIAssistant(); const { services: { notifications }, } = useKibana(); - const [displayedMessages, setDisplayedMessages] = useState(initialMessages); - - const getSystemMessage = useCallback(() => { - return getAssistantSetupMessage({ contexts: chatService?.getContexts() || [] }); - }, [chatService]); + const initialConversationId = useOnce(initialConversationIdFromProps); + const initialMessages = useOnce(initialMessagesFromProps); + const initialTitle = useOnce(initialTitleFromProps); - const displayedMessagesWithHardcodedSystemMessage = useMemo(() => { - if (!chatService) { - return displayedMessages; - } + if (initialMessages.length && initialConversationId) { + throw new Error('Cannot set initialMessages if initialConversationId is set'); + } - const systemMessage = getSystemMessage(); - - if (displayedMessages[0]?.message.role === MessageRole.User) { - return [systemMessage, ...displayedMessages]; - } - - return [systemMessage, ...displayedMessages.slice(1)]; - }, [displayedMessages, chatService, getSystemMessage]); + const update = (nextConversationObject: Conversation) => { + return service + .callApi(`PUT /internal/observability_ai_assistant/conversation/{conversationId}`, { + signal: null, + params: { + path: { + conversationId: nextConversationObject.conversation.id, + }, + body: { + conversation: merge( + { + '@timestamp': nextConversationObject['@timestamp'], + conversation: { + id: nextConversationObject.conversation.id, + }, + }, + omit(nextConversationObject, 'conversation.last_updated', 'namespace', 'user') + ), + }, + }, + }) + .catch((err) => { + notifications.toasts.addError(err, { + title: i18n.translate('xpack.observabilityAiAssistant.errorUpdatingConversation', { + defaultMessage: 'Could not update conversation', + }), + }); + throw err; + }); + }; - const conversation: AbortableAsyncState = - useAbortableAsync( - ({ signal }) => { - if (!conversationId) { - const nextConversation = createNewConversation({ - contexts: chatService?.getContexts() || [], - }); - setDisplayedMessages(nextConversation.messages); - return nextConversation; - } + const save = (nextMessages: Message[]) => { + const conversationObject = conversation.value!; - return service - .callApi('GET /internal/observability_ai_assistant/conversation/{conversationId}', { - signal, - params: { path: { conversationId } }, - }) - .then((nextConversation) => { - setDisplayedMessages(nextConversation.messages); - return nextConversation; - }) - .catch((error) => { - setDisplayedMessages([]); - throw error; - }); - }, - [conversationId, chatService] - ); + const nextConversationObject = merge({}, omit(conversationObject, 'messages'), { + messages: nextMessages, + }); - return { - conversation, - displayedMessages: displayedMessagesWithHardcodedSystemMessage, - setDisplayedMessages, - getSystemMessage, - save: (messages: Message[], handleRefreshConversations?: () => void) => { - const conversationObject = conversation.value!; - - return conversationId - ? service - .callApi(`PUT /internal/observability_ai_assistant/conversation/{conversationId}`, { - signal: null, - params: { - path: { - conversationId, - }, - body: { - conversation: merge( - { - '@timestamp': conversationObject['@timestamp'], - conversation: { - id: conversationId, - }, - }, - omit( - conversationObject, - 'conversation.last_updated', - 'namespace', - 'user', - 'messages' - ), - { messages } - ), - }, - }, - }) - .catch((err) => { - notifications.toasts.addError(err, { - title: i18n.translate('xpack.observabilityAiAssistant.errorUpdatingConversation', { - defaultMessage: 'Could not update conversation', - }), - }); - throw err; - }) + return ( + displayedConversationId + ? update( + merge( + { conversation: { id: displayedConversationId } }, + nextConversationObject + ) as Conversation + ) : service .callApi(`POST /internal/observability_ai_assistant/conversation`, { signal: null, params: { body: { - conversation: merge({}, conversationObject, { messages }), + conversation: nextConversationObject, }, }, }) .then((nextConversation) => { + setDisplayedConversationId(nextConversation.conversation.id); if (connectorId) { service .callApi( @@ -162,7 +144,7 @@ export function useConversation({ } ) .then(() => { - handleRefreshConversations?.(); + onConversationUpdate?.(nextConversation); return conversation.refresh(); }); } @@ -175,27 +157,78 @@ export function useConversation({ }), }); throw err; - }); + }) + ).then((nextConversation) => { + onConversationUpdate?.(nextConversation); + return nextConversation; + }); + }; + + const { next, messages, setMessages, state, stop } = useChat({ + initialMessages, + chatService, + connectorId, + onChatComplete: (nextMessages) => { + save(nextMessages); }, - saveTitle: (title: string, handleRefreshConversations?: () => void) => { - if (conversationId) { + }); + + const [displayedConversationId, setDisplayedConversationId] = useState(initialConversationId); + + const conversation: AbortableAsyncState = + useAbortableAsync( + ({ signal }) => { + if (!displayedConversationId) { + const nextConversation = createNewConversation({ title: initialTitle }); + return nextConversation; + } + return service - .callApi('PUT /internal/observability_ai_assistant/conversation/{conversationId}/title', { - signal: null, - params: { - path: { - conversationId, - }, - body: { - title, - }, - }, + .callApi('GET /internal/observability_ai_assistant/conversation/{conversationId}', { + signal, + params: { path: { conversationId: displayedConversationId } }, + }) + .then((nextConversation) => { + setMessages(nextConversation.messages); + return nextConversation; }) - .then(() => { - handleRefreshConversations?.(); + .catch((error) => { + setMessages([]); + throw error; }); + }, + [displayedConversationId, initialTitle], + { + defaultValue: () => { + if (!displayedConversationId) { + const nextConversation = createNewConversation({ title: initialTitle }); + return nextConversation; + } + return undefined; + }, + } + ); + + return { + conversation, + state, + next, + stop, + messages, + saveTitle: (title: string) => { + if (!displayedConversationId || !conversation.value) { + throw new Error('Cannot save title if conversation is not stored'); } - return Promise.resolve(); + const nextConversation = merge({}, conversation.value as Conversation, { + conversation: { title }, + }); + return update(nextConversation) + .then(() => { + return conversation.refresh(); + }) + .then(() => { + onConversationUpdate?.(nextConversation); + }); }, }; } diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_current_user.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_current_user.ts index 8e8f437a87fb..6414e7f604f6 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_current_user.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_current_user.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { useEffect, useState } from 'react'; import { useObservabilityAIAssistant } from './use_observability_ai_assistant'; diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_force_update.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_force_update.ts new file mode 100644 index 000000000000..479a043b847c --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_force_update.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState } from 'react'; + +export function useForceUpdate() { + const [_, setCounter] = useState(0); + + return () => { + setCounter((prev) => prev + 1); + }; +} diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_knowledge_base.tsx b/x-pack/plugins/observability_ai_assistant/public/hooks/use_knowledge_base.tsx index d7c76e0ab4f8..24c83d3fa8eb 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_knowledge_base.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_knowledge_base.tsx @@ -57,6 +57,7 @@ export function useKnowledgeBase(): UseKnowledgeBaseResult { text: i18n.translate('xpack.observabilityAiAssistant.knowledgeBaseReadyContentReload', { defaultMessage: 'A page reload is needed to be able to use it.', }), + toastLifeTimeMs: Number.MAX_VALUE, }); }) .catch((error) => { diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_once.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_once.ts new file mode 100644 index 000000000000..00dab01456af --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_once.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useRef } from 'react'; + +export function useOnce(variable: T): T { + const ref = useRef(variable); + + if (ref.current !== variable) { + // eslint-disable-next-line no-console + console.trace( + `Variable changed from ${ref.current} to ${variable}, but only the initial value will be taken into account` + ); + } + + return ref.current; +} diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts deleted file mode 100644 index 6ad1d0746a51..000000000000 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { FindActionResult } from '@kbn/actions-plugin/server'; -import { AbortError } from '@kbn/kibana-utils-plugin/common'; -import { - act, - renderHook, - type Renderer, - type RenderHookResult, -} from '@testing-library/react-hooks'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { MessageRole } from '../../common'; -import { ChatTimelineItem } from '../components/chat/chat_timeline'; -import type { PendingMessage } from '../types'; -import { useTimeline, UseTimelineResult } from './use_timeline'; - -type HookProps = Parameters[0]; - -const WAIT_OPTIONS = { timeout: 1500 }; - -jest.mock('./use_kibana', () => ({ - useKibana: () => ({ - services: { - notifications: { - toasts: { - addError: jest.fn(), - }, - }, - }, - }), -})); - -describe('useTimeline', () => { - let hookResult: RenderHookResult>; - - describe('with an empty conversation', () => { - beforeAll(() => { - hookResult = renderHook((props) => useTimeline(props), { - initialProps: { - connectors: { - loading: false, - selectedConnector: 'OpenAI', - selectConnector: () => {}, - connectors: [{ id: 'OpenAI' }] as FindActionResult[], - }, - chatService: {}, - messages: [], - onChatComplete: jest.fn(), - onChatUpdate: jest.fn(), - } as unknown as HookProps, - }); - }); - it('renders the correct timeline items', () => { - expect(hookResult.result.current.items.length).toEqual(1); - - expect(hookResult.result.current.items[0]).toEqual({ - display: { - collapsed: false, - hide: false, - }, - actions: { - canCopy: false, - canEdit: false, - canRegenerate: false, - canGiveFeedback: false, - }, - role: MessageRole.User, - title: 'started a conversation', - loading: false, - id: expect.any(String), - }); - }); - }); - - describe('with an existing conversation', () => { - beforeAll(() => { - hookResult = renderHook((props) => useTimeline(props), { - initialProps: { - messages: [ - { - message: { - role: MessageRole.System, - content: 'You are a helpful assistant for Elastic Observability', - }, - }, - { - message: { - role: MessageRole.User, - content: 'hello', - }, - }, - { - message: { - role: MessageRole.Assistant, - content: '', - function_call: { - name: 'recall', - trigger: MessageRole.User, - }, - }, - }, - { - message: { - name: 'recall', - role: MessageRole.User, - content: '', - }, - }, - { - message: { - content: 'goodbye', - function_call: { - name: '', - arguments: '', - trigger: MessageRole.Assistant, - }, - role: MessageRole.Assistant, - }, - }, - ], - connectors: { - selectedConnector: 'foo', - }, - chatService: { - chat: () => {}, - hasRenderFunction: () => {}, - hasFunction: () => {}, - }, - } as unknown as HookProps, - }); - }); - it('renders the correct timeline items', () => { - expect(hookResult.result.current.items.length).toEqual(4); - - expect(hookResult.result.current.items[1]).toEqual({ - actions: { canCopy: true, canEdit: true, canGiveFeedback: false, canRegenerate: false }, - content: 'hello', - currentUser: undefined, - display: { collapsed: false, hide: false }, - element: undefined, - function_call: undefined, - id: expect.any(String), - loading: false, - role: MessageRole.User, - title: '', - }); - - expect(hookResult.result.current.items[3]).toEqual({ - actions: { canCopy: true, canEdit: false, canGiveFeedback: false, canRegenerate: true }, - content: 'goodbye', - currentUser: undefined, - display: { collapsed: false, hide: false }, - element: undefined, - function_call: { - arguments: '', - name: '', - trigger: MessageRole.Assistant, - }, - id: expect.any(String), - loading: false, - role: MessageRole.Assistant, - title: '', - }); - - // Items that are function calls are collapsed into an array. - - // 'title' is a component. This throws Jest for a loop. - const collapsedItemsWithoutTitle = ( - hookResult.result.current.items[2] as ChatTimelineItem[] - ).map(({ title, ...rest }) => rest); - - expect(collapsedItemsWithoutTitle).toEqual([ - { - display: { - collapsed: true, - hide: false, - }, - actions: { - canCopy: true, - canEdit: true, - canRegenerate: false, - canGiveFeedback: false, - }, - currentUser: undefined, - function_call: { - name: 'recall', - trigger: MessageRole.User, - }, - role: MessageRole.User, - content: `\`\`\` -{ - \"name\": \"recall\" -} -\`\`\``, - loading: false, - id: expect.any(String), - }, - { - display: { - collapsed: true, - hide: false, - }, - actions: { - canCopy: true, - canEdit: false, - canRegenerate: false, - canGiveFeedback: false, - }, - currentUser: undefined, - function_call: undefined, - role: MessageRole.User, - content: `\`\`\` -{} -\`\`\``, - loading: false, - id: expect.any(String), - }, - ]); - }); - }); - - describe('when submitting a new prompt', () => { - let subject: Subject; - - let props: Omit & { - onChatUpdate: jest.MockedFn; - onChatComplete: jest.MockedFn; - chatService: Omit & { - executeFunction: jest.MockedFn; - }; - }; - - beforeEach(() => { - props = { - messages: [], - connectors: { - selectedConnector: 'foo', - }, - chatService: { - chat: jest.fn().mockImplementation(() => { - subject = new BehaviorSubject({ - message: { - role: MessageRole.Assistant, - content: '', - }, - }); - return subject; - }), - executeFunction: jest.fn(), - hasFunction: jest.fn(), - hasRenderFunction: jest.fn(), - }, - onChatUpdate: jest.fn().mockImplementation((messages) => { - props = { ...props, messages }; - hookResult.rerender(props as unknown as HookProps); - }), - onChatComplete: jest.fn(), - } as any; - - hookResult = renderHook((nextProps) => useTimeline(nextProps), { - initialProps: props as unknown as HookProps, - }); - }); - - describe("and it's loading", () => { - beforeEach(() => { - act(() => { - hookResult.result.current.onSubmit({ - '@timestamp': new Date().toISOString(), - message: { role: MessageRole.User, content: 'Hello' }, - }); - }); - }); - - it('adds two items of which the last one is loading', async () => { - expect((hookResult.result.current.items[0] as ChatTimelineItem).role).toEqual( - MessageRole.User - ); - expect((hookResult.result.current.items[1] as ChatTimelineItem).role).toEqual( - MessageRole.User - ); - - expect((hookResult.result.current.items[2] as ChatTimelineItem).role).toEqual( - MessageRole.Assistant - ); - - expect(hookResult.result.current.items[1]).toMatchObject({ - role: MessageRole.User, - content: 'Hello', - loading: false, - }); - - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: '', - loading: true, - actions: { - canRegenerate: false, - canGiveFeedback: false, - }, - }); - - expect(hookResult.result.current.items.length).toBe(3); - - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: '', - loading: true, - actions: { - canRegenerate: false, - canGiveFeedback: false, - }, - }); - }); - - describe('and it pushes the next part', () => { - beforeEach(() => { - act(() => { - subject.next({ message: { role: MessageRole.Assistant, content: 'Goodbye' } }); - }); - }); - - it('adds the partial response', () => { - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: 'Goodbye', - loading: true, - actions: { - canRegenerate: false, - canGiveFeedback: false, - }, - }); - }); - - describe('and it completes', () => { - beforeEach(async () => { - act(() => { - subject.complete(); - }); - - await hookResult.waitForNextUpdate(WAIT_OPTIONS); - }); - - it('adds the completed message', () => { - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: 'Goodbye', - loading: false, - actions: { - canRegenerate: true, - canGiveFeedback: false, - }, - }); - }); - - describe('and the user edits a message', () => { - beforeEach(() => { - act(() => { - hookResult.result.current.onEdit( - hookResult.result.current.items[1] as ChatTimelineItem, - { - '@timestamp': new Date().toISOString(), - message: { content: 'Edited message', role: MessageRole.User }, - } - ); - subject.next({ message: { role: MessageRole.Assistant, content: '' } }); - subject.complete(); - }); - }); - - it('calls onChatUpdate with the edited message', () => { - expect(hookResult.result.current.items.length).toEqual(4); - expect((hookResult.result.current.items[2] as ChatTimelineItem).content).toEqual( - 'Edited message' - ); - expect((hookResult.result.current.items[3] as ChatTimelineItem).content).toEqual(''); - }); - }); - }); - }); - - describe('and it is being aborted', () => { - beforeEach(() => { - act(() => { - subject.next({ message: { role: MessageRole.Assistant, content: 'My partial' } }); - subject.next({ - message: { - role: MessageRole.Assistant, - content: 'My partial', - }, - aborted: true, - error: new AbortError(), - }); - subject.complete(); - }); - }); - - it('adds the partial response', async () => { - expect(hookResult.result.current.items.length).toBe(3); - - expect(hookResult.result.current.items[2]).toEqual({ - actions: { - canEdit: false, - canRegenerate: true, - canGiveFeedback: false, - canCopy: true, - }, - display: { - collapsed: false, - hide: false, - }, - content: 'My partial', - id: expect.any(String), - loading: false, - title: '', - role: MessageRole.Assistant, - error: expect.any(AbortError), - }); - }); - - describe('and it is being regenerated', () => { - beforeEach(() => { - act(() => { - hookResult.result.current.onRegenerate( - hookResult.result.current.items[2] as ChatTimelineItem - ); - subject.next({ message: { role: MessageRole.Assistant, content: '' } }); - }); - }); - - it('updates the last item in the array to be loading', () => { - expect(hookResult.result.current.items.length).toEqual(3); - - expect(hookResult.result.current.items[2]).toEqual({ - display: { - hide: false, - collapsed: false, - }, - actions: { - canCopy: true, - canEdit: false, - canRegenerate: false, - canGiveFeedback: false, - }, - content: '', - id: expect.any(String), - loading: true, - title: '', - role: MessageRole.Assistant, - }); - }); - - describe('and it is regenerated again', () => { - beforeEach(async () => { - act(() => { - hookResult.result.current.onStopGenerating(); - }); - - act(() => { - hookResult.result.current.onRegenerate( - hookResult.result.current.items[2] as ChatTimelineItem - ); - }); - }); - - it('updates the last item to be not loading again', async () => { - expect(hookResult.result.current.items.length).toBe(3); - - expect(hookResult.result.current.items[2]).toEqual({ - actions: { - canCopy: true, - canEdit: false, - canRegenerate: false, - canGiveFeedback: false, - }, - display: { - collapsed: false, - hide: false, - }, - content: '', - id: expect.any(String), - loading: true, - title: '', - role: MessageRole.Assistant, - }); - - act(() => { - subject.next({ message: { role: MessageRole.Assistant, content: 'Regenerated' } }); - subject.complete(); - }); - - await hookResult.waitForNextUpdate(WAIT_OPTIONS); - - expect(hookResult.result.current.items.length).toBe(3); - - expect(hookResult.result.current.items[2]).toEqual({ - display: { - collapsed: false, - hide: false, - }, - actions: { - canCopy: true, - canEdit: false, - canRegenerate: true, - canGiveFeedback: false, - }, - content: 'Regenerated', - currentUser: undefined, - function_call: undefined, - id: expect.any(String), - element: undefined, - loading: false, - title: '', - role: MessageRole.Assistant, - }); - }); - }); - }); - }); - - describe('and a function call is returned', () => { - it('the function call is executed and its response is sent as a user reply', async () => { - jest.clearAllMocks(); - - act(() => { - subject.next({ - message: { - role: MessageRole.Assistant, - function_call: { - trigger: MessageRole.Assistant, - name: 'my_function', - arguments: '{}', - }, - }, - }); - subject.complete(); - }); - - props.chatService.executeFunction.mockResolvedValueOnce({ - content: { - message: 'my-response', - }, - }); - - await hookResult.waitForNextUpdate(WAIT_OPTIONS); - - expect(props.onChatUpdate).toHaveBeenCalledTimes(2); - - expect( - props.onChatUpdate.mock.calls[0][0].map( - (msg) => msg.message.content || msg.message.function_call?.name - ) - ).toEqual(['Hello', 'my_function']); - - expect( - props.onChatUpdate.mock.calls[1][0].map( - (msg) => msg.message.content || msg.message.function_call?.name - ) - ).toEqual(['Hello', 'my_function', JSON.stringify({ message: 'my-response' })]); - - expect(props.onChatComplete).not.toHaveBeenCalled(); - - expect(props.chatService.executeFunction).toHaveBeenCalledWith({ - name: 'my_function', - args: '{}', - connectorId: 'foo', - messages: [ - { - '@timestamp': expect.any(String), - message: { - content: 'Hello', - role: MessageRole.User, - }, - }, - ], - signal: expect.any(Object), - }); - - act(() => { - subject.next({ - message: { - role: MessageRole.Assistant, - content: 'looks like my-function returned my-response', - }, - }); - subject.complete(); - }); - - await hookResult.waitForNextUpdate(WAIT_OPTIONS); - - expect(props.onChatComplete).toHaveBeenCalledTimes(1); - - expect( - props.onChatComplete.mock.calls[0][0].map( - (msg) => msg.message.content || msg.message.function_call?.name - ) - ).toEqual([ - 'Hello', - 'my_function', - JSON.stringify({ message: 'my-response' }), - 'looks like my-function returned my-response', - ]); - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts deleted file mode 100644 index 64d82cabb943..000000000000 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { AbortError } from '@kbn/kibana-utils-plugin/common'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { flatten, last } from 'lodash'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import usePrevious from 'react-use/lib/usePrevious'; -import { isObservable, Observable, Subscription } from 'rxjs'; -import { - ContextDefinition, - MessageRole, - type ConversationCreateRequest, - type Message, -} from '../../common/types'; -import type { ChatPromptEditorProps } from '../components/chat/chat_prompt_editor'; -import type { ChatTimelineItem, ChatTimelineProps } from '../components/chat/chat_timeline'; -import { ChatActionClickType } from '../components/chat/types'; -import { EMPTY_CONVERSATION_TITLE } from '../i18n'; -import type { ObservabilityAIAssistantChatService, PendingMessage } from '../types'; -import { - getTimelineItemsfromConversation, - StartedFrom, -} from '../utils/get_timeline_items_from_conversation'; -import type { UseGenAIConnectorsResult } from './use_genai_connectors'; -import { useKibana } from './use_kibana'; - -export function createNewConversation({ - contexts, -}: { - contexts: ContextDefinition[]; -}): ConversationCreateRequest { - return { - '@timestamp': new Date().toISOString(), - messages: [], - conversation: { - title: EMPTY_CONVERSATION_TITLE, - }, - labels: {}, - numeric_labels: {}, - public: false, - }; -} - -export type UseTimelineResult = Pick< - ChatTimelineProps, - 'onEdit' | 'onFeedback' | 'onRegenerate' | 'onStopGenerating' | 'onActionClick' | 'items' -> & - Pick; - -export function useTimeline({ - messages, - connectors, - conversationId, - currentUser, - chatService, - startedFrom, - onChatUpdate, - onChatComplete, -}: { - messages: Message[]; - conversationId?: string; - connectors: UseGenAIConnectorsResult; - currentUser?: Pick; - chatService: ObservabilityAIAssistantChatService; - startedFrom?: StartedFrom; - onChatUpdate: (messages: Message[]) => void; - onChatComplete: (messages: Message[]) => void; -}): UseTimelineResult { - const connectorId = connectors.selectedConnector; - - const hasConnector = !!connectorId; - - const { - services: { notifications }, - } = useKibana(); - - const conversationItems = useMemo(() => { - const items = getTimelineItemsfromConversation({ - currentUser, - chatService, - hasConnector, - messages, - startedFrom, - }); - - return items; - }, [currentUser, chatService, hasConnector, messages, startedFrom]); - - const [subscription, setSubscription] = useState(); - - const controllerRef = useRef(new AbortController()); - - const [pendingMessage, setPendingMessage] = useState(); - - const [isFunctionLoading, setIsFunctionLoading] = useState(false); - - const prevConversationId = usePrevious(conversationId); - - useEffect(() => { - if (prevConversationId !== conversationId && pendingMessage?.error) { - setPendingMessage(undefined); - } - }, [conversationId, pendingMessage?.error, prevConversationId]); - - function chat( - nextMessages: Message[], - response$: Observable | undefined = undefined - ): Promise { - const controller = new AbortController(); - - return new Promise(async (resolve, reject) => { - try { - if (!connectorId) { - reject(new Error('Can not add a message without a connector')); - return; - } - - const isStartOfConversation = - nextMessages.some((message) => message.message.role === MessageRole.Assistant) === false; - - if (isStartOfConversation && chatService.hasFunction('recall')) { - nextMessages = nextMessages.concat({ - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.Assistant, - content: '', - function_call: { - name: 'recall', - arguments: JSON.stringify({ queries: [], contexts: [] }), - trigger: MessageRole.User, - }, - }, - }); - } - - onChatUpdate(nextMessages); - const lastMessage = last(nextMessages); - if (lastMessage?.message.function_call?.name) { - // the user has edited a function suggestion, no need to talk to the LLM - resolve(undefined); - return; - } - - response$ = - response$ || - chatService!.chat({ - messages: nextMessages, - connectorId, - }); - let pendingMessageLocal = pendingMessage; - const nextSubscription = response$.subscribe({ - next: (nextPendingMessage) => { - pendingMessageLocal = nextPendingMessage; - setPendingMessage(() => nextPendingMessage); - }, - error: reject, - complete: () => { - const error = pendingMessageLocal?.error; - if (error) { - notifications.toasts.addError(error, { - title: i18n.translate('xpack.observabilityAiAssistant.failedToLoadResponse', { - defaultMessage: 'Failed to load response from the AI Assistant', - }), - }); - } - resolve(pendingMessageLocal!); - }, - }); - setSubscription(() => { - controllerRef.current = controller; - return nextSubscription; - }); - } catch (error) { - reject(error); - } - }).then(async (reply) => { - if (reply?.error) { - return nextMessages; - } - if (reply?.aborted) { - return nextMessages; - } - - setPendingMessage(undefined); - - const messagesAfterChat = reply - ? nextMessages.concat({ - '@timestamp': new Date().toISOString(), - message: { - ...reply.message, - }, - }) - : nextMessages; - - onChatUpdate(messagesAfterChat); - - const lastMessage = last(messagesAfterChat); - - if (lastMessage?.message.function_call?.name) { - const name = lastMessage.message.function_call.name; - - setIsFunctionLoading(true); - - try { - let message = await chatService!.executeFunction({ - name, - args: lastMessage.message.function_call.arguments, - messages: messagesAfterChat.slice(0, -1), - signal: controller.signal, - connectorId: connectorId!, - }); - - let nextResponse$: Observable | undefined; - - if (isObservable(message)) { - nextResponse$ = message; - message = { content: '', data: '' }; - } - - return await chat( - messagesAfterChat.concat({ - '@timestamp': new Date().toISOString(), - message: { - name, - role: MessageRole.User, - content: JSON.stringify(message.content), - data: JSON.stringify(message.data), - }, - }), - nextResponse$ - ); - } catch (error) { - return await chat( - messagesAfterChat.concat({ - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.User, - name, - content: JSON.stringify({ - message: error.toString(), - error, - }), - }, - }) - ); - } finally { - setIsFunctionLoading(false); - } - } - - return messagesAfterChat; - }); - } - - const itemsWithAddedLoadingStates = useMemo(() => { - // While we're loading we add an empty loading chat item: - if (pendingMessage || isFunctionLoading) { - const nextItems = conversationItems.concat({ - id: '', - actions: { - canCopy: true, - canEdit: false, - canGiveFeedback: false, - canRegenerate: pendingMessage?.aborted || !!pendingMessage?.error, - }, - display: { - collapsed: false, - hide: pendingMessage?.message.role === MessageRole.System, - }, - content: pendingMessage?.message.content, - currentUser, - error: pendingMessage?.error, - function_call: pendingMessage?.message.function_call, - loading: !pendingMessage?.aborted && !pendingMessage?.error, - role: pendingMessage?.message.role || MessageRole.Assistant, - title: '', - }); - - return nextItems; - } - - if (!isFunctionLoading) { - return conversationItems; - } - - return conversationItems.map((item, index) => { - // When we're done loading we remove the placeholder item again - if (index < conversationItems.length - 1) { - return item; - } - return { - ...item, - loading: true, - }; - }); - }, [conversationItems, pendingMessage, currentUser, isFunctionLoading]); - - const items = useMemo(() => { - const consolidatedChatItems: Array = []; - let currentGroup: ChatTimelineItem[] | null = null; - - for (const item of itemsWithAddedLoadingStates) { - if (item.display.hide || !item) continue; - - if (item.display.collapsed) { - if (currentGroup) { - currentGroup.push(item); - } else { - currentGroup = [item]; - consolidatedChatItems.push(currentGroup); - } - } else { - consolidatedChatItems.push(item); - currentGroup = null; - } - } - - return consolidatedChatItems; - }, [itemsWithAddedLoadingStates]); - - useEffect(() => { - return () => { - subscription?.unsubscribe(); - }; - }, [subscription]); - - return { - items, - onEdit: async (item, newMessage) => { - const indexOf = flatten(items).indexOf(item); - const sliced = messages.slice(0, indexOf); - const nextMessages = await chat(sliced.concat(newMessage)); - onChatComplete(nextMessages); - }, - onFeedback: (item, feedback) => {}, - onRegenerate: (item) => { - const indexOf = flatten(items).indexOf(item); - - chat(messages.slice(0, indexOf)).then((nextMessages) => onChatComplete(nextMessages)); - }, - onStopGenerating: () => { - subscription?.unsubscribe(); - setPendingMessage((prevPendingMessage) => ({ - message: { - role: MessageRole.Assistant, - ...prevPendingMessage?.message, - }, - aborted: true, - error: new AbortError(), - })); - setSubscription(undefined); - }, - onSubmit: async (message) => { - const nextMessages = await chat(messages.concat(message)); - onChatComplete(nextMessages); - }, - onActionClick: async (payload) => { - switch (payload.type) { - case ChatActionClickType.executeEsqlQuery: - const nextMessages = await chat( - messages.concat({ - '@timestamp': new Date().toISOString(), - message: { - role: MessageRole.Assistant, - content: '', - function_call: { - name: 'execute_query', - arguments: JSON.stringify({ - query: payload.query, - }), - trigger: MessageRole.User, - }, - }, - }) - ); - onChatComplete(nextMessages); - break; - } - }, - }; -} diff --git a/x-pack/plugins/observability_ai_assistant/public/routes/config.tsx b/x-pack/plugins/observability_ai_assistant/public/routes/config.tsx index f4245cb69d9e..ed0ac18302cc 100644 --- a/x-pack/plugins/observability_ai_assistant/public/routes/config.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/routes/config.tsx @@ -31,11 +31,18 @@ const observabilityAIAssistantRoutes = { element: , }, '/conversations/{conversationId}': { - params: t.type({ - path: t.type({ - conversationId: t.string, + params: t.intersection([ + t.type({ + path: t.type({ + conversationId: t.string, + }), }), - }), + t.partial({ + state: t.partial({ + prevConversationKey: t.string, + }), + }), + ]), element: , }, '/conversations': { diff --git a/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx b/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx index 5af2e740deb9..ca8bf82178ff 100644 --- a/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx @@ -4,36 +4,34 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useMemo, useState } from 'react'; -import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; +import React, { useMemo, useRef, useState } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; +import { v4 } from 'uuid'; import { ChatBody } from '../../components/chat/chat_body'; import { ConversationList } from '../../components/chat/conversation_list'; import { ObservabilityAIAssistantChatServiceProvider } from '../../context/observability_ai_assistant_chat_service_provider'; import { useAbortableAsync } from '../../hooks/use_abortable_async'; import { useConfirmModal } from '../../hooks/use_confirm_modal'; -import { useConversation } from '../../hooks/use_conversation'; import { useCurrentUser } from '../../hooks/use_current_user'; +import { useForceUpdate } from '../../hooks/use_force_update'; import { useGenAIConnectors } from '../../hooks/use_genai_connectors'; import { useKibana } from '../../hooks/use_kibana'; import { useKnowledgeBase } from '../../hooks/use_knowledge_base'; import { useObservabilityAIAssistant } from '../../hooks/use_observability_ai_assistant'; import { useObservabilityAIAssistantParams } from '../../hooks/use_observability_ai_assistant_params'; import { useObservabilityAIAssistantRouter } from '../../hooks/use_observability_ai_assistant_router'; +import { EMPTY_CONVERSATION_TITLE } from '../../i18n'; import { getConnectorsManagementHref } from '../../utils/get_connectors_management_href'; import { getModelsManagementHref } from '../../utils/get_models_management_href'; -import { EMPTY_CONVERSATION_TITLE } from '../../i18n'; const containerClassName = css` max-width: 100%; `; -const chatBodyContainerClassNameWithError = css` - align-self: center; -`; - const conversationListContainerName = css` min-width: 250px; width: 250px; @@ -80,12 +78,24 @@ export function ConversationView() { const conversationId = 'conversationId' in path ? path.conversationId : undefined; - const { conversation, displayedMessages, setDisplayedMessages, save, saveTitle } = - useConversation({ - conversationId, - chatService: chatService.value, - connectorId: connectors.selectedConnector, - }); + // Regenerate the key only when the id changes, except after + // creating the conversation. Ideally this happens by adding + // state to the current route, but I'm not keen on adding + // the concept of state to the router, due to a mismatch + // between router.link() and router.push(). So, this is a + // pretty gross workaround for persisting a key under some + // conditions. + const chatBodyKeyRef = useRef(v4()); + const keepPreviousKeyRef = useRef(false); + const prevConversationId = usePrevious(conversationId); + + if (conversationId !== prevConversationId && keepPreviousKeyRef.current === false) { + chatBodyKeyRef.current = v4(); + } + + keepPreviousKeyRef.current = false; + + const forceUpdate = useForceUpdate(); const conversations = useAbortableAsync( ({ signal }) => { @@ -111,14 +121,17 @@ export function ConversationView() { ]; }, [conversations.value?.conversations, conversationId, observabilityAIAssistantRouter]); - function navigateToConversation(nextConversationId?: string) { - observabilityAIAssistantRouter.push( - nextConversationId ? '/conversations/{conversationId}' : '/conversations/new', - { - path: { conversationId: nextConversationId }, + function navigateToConversation(nextConversationId?: string, usePrevConversationKey?: boolean) { + if (nextConversationId) { + observabilityAIAssistantRouter.push('/conversations/{conversationId}', { + path: { + conversationId: nextConversationId, + }, query: {}, - } - ); + }); + } else { + observabilityAIAssistantRouter.push('/conversations/new', { path: {}, query: {} }); + } } function handleRefreshConversations() { @@ -136,10 +149,16 @@ export function ConversationView() { error={conversations.error} conversations={displayedConversations} onClickNewChat={() => { - observabilityAIAssistantRouter.push('/conversations/new', { - path: {}, - query: {}, - }); + if (conversationId) { + observabilityAIAssistantRouter.push('/conversations/new', { + path: {}, + query: {}, + }); + } else { + // clear the chat + chatBodyKeyRef.current = v4(); + forceUpdate(); + } }} onClickDeleteConversation={(id) => { confirmDeleteFunction() @@ -194,69 +213,36 @@ export function ConversationView() { /> - - {conversation.error ? ( - + + + + + + ) : null} + {chatService.value && ( + + { + if (!conversationId) { + keepPreviousKeyRef.current = true; + navigateToConversation(conversation.conversation.id); } - )} - iconType="warning" - > - {i18n.translate('xpack.observabilityAiAssistant.couldNotFindConversationContent', { - defaultMessage: - 'Could not find a conversation with id {conversationId}. Make sure the conversation exists and you have access to it.', - values: { conversationId }, - })} - - ) : null} - {!chatService.value ? ( - - - - - - - ) : null} - {conversation.value && chatService.value && !conversation.error ? ( - - { - setDisplayedMessages(messages); - }} - onChatComplete={(messages) => { - save(messages, handleRefreshConversations) - .then((nextConversation) => { - conversations.refresh(); - if (!conversationId && nextConversation?.conversation?.id) { - navigateToConversation(nextConversation.conversation.id); - } - }) - .catch((e) => {}); - }} - onSaveTitle={(title) => { - saveTitle(title, handleRefreshConversations); - }} - /> - - ) : null} - + handleRefreshConversations(); + }} + /> + + )}
    ); diff --git a/x-pack/plugins/observability_ai_assistant/public/service/create_mock_chat_service.ts b/x-pack/plugins/observability_ai_assistant/public/service/create_mock_chat_service.ts new file mode 100644 index 000000000000..e255aa830467 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/service/create_mock_chat_service.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; +import type { ObservabilityAIAssistantChatService } from '../types'; + +type MockedChatService = DeeplyMockedKeys; + +export const createMockChatService = (): MockedChatService => { + const mockChatService: MockedChatService = { + chat: jest.fn(), + executeFunction: jest.fn(), + getContexts: jest.fn().mockReturnValue([{ name: 'core', description: '' }]), + getFunctions: jest.fn().mockReturnValue([]), + hasFunction: jest.fn().mockReturnValue(false), + hasRenderFunction: jest.fn().mockReturnValue(true), + renderFunction: jest.fn(), + }; + return mockChatService; +}; diff --git a/x-pack/plugins/observability_ai_assistant/public/utils/builders.ts b/x-pack/plugins/observability_ai_assistant/public/utils/builders.ts index ed318397de73..6f2d1e5c2f09 100644 --- a/x-pack/plugins/observability_ai_assistant/public/utils/builders.ts +++ b/x-pack/plugins/observability_ai_assistant/public/utils/builders.ts @@ -6,106 +6,98 @@ */ import { merge, uniqueId } from 'lodash'; -import { MessageRole, Conversation, FunctionDefinition } from '../../common/types'; -import { ChatTimelineItem } from '../components/chat/chat_timeline'; +import { DeepPartial } from 'utility-types'; +import { MessageRole, Conversation, FunctionDefinition, Message } from '../../common/types'; import { getAssistantSetupMessage } from '../service/get_assistant_setup_message'; -type ChatItemBuildProps = Omit, 'actions' | 'display' | 'currentUser'> & { - actions?: Partial; - display?: Partial; - currentUser?: Partial; -} & Pick; +type BuildMessageProps = DeepPartial & { + message: { + role: MessageRole; + function_call?: { + name: string; + trigger: MessageRole.Assistant | MessageRole.User | MessageRole.Elastic; + }; + }; +}; -export function buildChatItem(params: ChatItemBuildProps): ChatTimelineItem { +export function buildMessage(params: BuildMessageProps): Message { return merge( { - id: uniqueId(), - title: '', - actions: { - canCopy: true, - canEdit: false, - canGiveFeedback: false, - canRegenerate: params.role === MessageRole.Assistant, - }, - display: { - collapsed: false, - hide: false, - }, - currentUser: { - username: 'elastic', - }, - loading: false, + '@timestamp': new Date().toISOString(), }, params ); } -export function buildSystemChatItem(params?: Omit) { - return buildChatItem({ - role: MessageRole.System, - ...params, - }); -} - -export function buildChatInitItem() { - return buildChatItem({ - role: MessageRole.User, - title: 'started a conversation', - actions: { - canEdit: false, - canCopy: true, - canGiveFeedback: false, - canRegenerate: false, - }, - }); -} - -export function buildUserChatItem(params?: Omit) { - return buildChatItem({ - role: MessageRole.User, - content: "What's a function?", - actions: { - canCopy: true, - canEdit: true, - canGiveFeedback: false, - canRegenerate: true, - }, - ...params, - }); +export function buildSystemMessage( + params?: Omit & { + message: DeepPartial>; + } +) { + return buildMessage( + merge({}, params, { + message: { role: MessageRole.System }, + }) + ); } -export function buildAssistantChatItem(params?: Omit) { - return buildChatItem({ - role: MessageRole.Assistant, - content: `In computer programming and mathematics, a function is a fundamental concept that represents a relationship between input values and output values. It takes one or more input values (also known as arguments or parameters) and processes them to produce a result, which is the output of the function. The input values are passed to the function, and the function performs a specific set of operations or calculations on those inputs to produce the desired output. - A function is often defined with a name, which serves as an identifier to call and use the function in the code. It can be thought of as a reusable block of code that can be executed whenever needed, and it helps in organizing code and making it more modular and maintainable.`, - actions: { - canCopy: true, - canEdit: false, - canRegenerate: true, - canGiveFeedback: true, - }, - ...params, - }); +export function buildUserMessage( + params?: Omit & { + message?: DeepPartial>; + } +) { + return buildMessage( + merge( + { + message: { + content: "What's a function?", + }, + }, + params, + { + message: { role: MessageRole.User }, + } + ) + ); } -export function buildFunctionChatItem(params: Omit) { - return buildChatItem({ - role: MessageRole.User, - title: 'executed a function', - function_call: { - name: 'leftpad', - arguments: '{ foo: "bar" }', - trigger: MessageRole.Assistant, - }, - ...params, - }); +export function buildAssistantMessage( + params?: Omit & { + message: DeepPartial>; + } +) { + return buildMessage( + merge( + { + message: { + content: `In computer programming and mathematics, a function is a fundamental concept that represents a relationship between input values and output values. It takes one or more input values (also known as arguments or parameters) and processes them to produce a result, which is the output of the function. The input values are passed to the function, and the function performs a specific set of operations or calculations on those inputs to produce the desired output. + A function is often defined with a name, which serves as an identifier to call and use the function in the code. It can be thought of as a reusable block of code that can be executed whenever needed, and it helps in organizing code and making it more modular and maintainable.`, + }, + }, + params, + { + message: { role: MessageRole.Assistant }, + } + ) + ); } -export function buildTimelineItems() { - return { - items: [buildSystemChatItem(), buildUserChatItem(), buildAssistantChatItem()], - }; +export function buildFunctionResponseMessage( + params?: Omit & { + message: DeepPartial>; + } +) { + return buildUserMessage( + merge( + {}, + { + message: { + name: 'leftpad', + }, + ...params, + } + ) + ); } export function buildConversation(params?: Partial) { diff --git a/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.test.tsx b/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.test.tsx new file mode 100644 index 000000000000..f066b7a9db37 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.test.tsx @@ -0,0 +1,597 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { last, pick } from 'lodash'; +import { render } from '@testing-library/react'; +import { Message, MessageRole } from '../../common'; +import { createMockChatService } from '../service/create_mock_chat_service'; +import { getTimelineItemsfromConversation } from './get_timeline_items_from_conversation'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { ObservabilityAIAssistantChatServiceProvider } from '../context/observability_ai_assistant_chat_service_provider'; +import { ChatState } from '../hooks/use_chat'; + +const mockChatService = createMockChatService(); + +let items: ReturnType; + +describe('getTimelineItemsFromConversation', () => { + describe('returns an opening message only', () => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + messages: [], + chatState: ChatState.Ready, + }); + + expect(items.length).toBe(1); + expect(items[0].title).toBe('started a conversation'); + }); + + describe('with a start of a conversation', () => { + beforeEach(() => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + currentUser: { + username: 'johndoe', + full_name: 'John Doe', + }, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'User', + }, + }, + ], + }); + }); + it('excludes the system message', () => { + expect(items.length).toBe(2); + expect(items[0].title).toBe('started a conversation'); + }); + + it('includes the rest of the conversation', () => { + expect(items[1].currentUser?.full_name).toEqual('John Doe'); + expect(items[1].content).toEqual('User'); + }); + + it('formats the user message', () => { + expect(pick(items[1], 'title', 'actions', 'display', 'loading')).toEqual({ + title: '', + actions: { + canCopy: true, + canEdit: true, + canGiveFeedback: false, + canRegenerate: false, + }, + display: { + collapsed: false, + hide: false, + }, + loading: false, + }); + }); + }); + + describe('with function calling', () => { + beforeEach(() => { + mockChatService.hasRenderFunction.mockImplementation(() => false); + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + function_call: { + name: 'recall', + arguments: JSON.stringify({ queries: [], contexts: [] }), + trigger: MessageRole.Assistant, + }, + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + name: 'recall', + content: JSON.stringify([]), + }, + }, + ], + }); + }); + + it('formats the function request', () => { + expect(pick(items[2], 'actions', 'display', 'loading')).toEqual({ + actions: { + canCopy: true, + canEdit: true, + canGiveFeedback: false, + canRegenerate: true, + }, + display: { + collapsed: true, + hide: false, + }, + loading: false, + }); + + const { container } = render(items[2].title as React.ReactElement, { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(container.textContent).toBe('requested the function recall'); + }); + + it('formats the function response', () => { + expect(pick(items[3], 'actions', 'display', 'loading')).toEqual({ + actions: { + canCopy: true, + canEdit: false, + canGiveFeedback: false, + canRegenerate: false, + }, + display: { + collapsed: true, + hide: false, + }, + loading: false, + }); + + const { container } = render(items[3].title as React.ReactElement, { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(container.textContent).toBe('executed the function recall'); + }); + }); + describe('with a render function', () => { + beforeEach(() => { + mockChatService.hasRenderFunction.mockImplementation(() => true); + mockChatService.renderFunction.mockImplementation(() => 'Rendered'); + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + function_call: { + name: 'my_render_function', + arguments: JSON.stringify({ foo: 'bar' }), + trigger: MessageRole.Assistant, + }, + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + name: 'my_render_function', + content: JSON.stringify([]), + }, + }, + ], + }); + }); + + it('renders a display element', () => { + expect(mockChatService.hasRenderFunction).toHaveBeenCalledWith('my_render_function'); + + expect(pick(items[3], 'actions', 'display')).toEqual({ + actions: { + canCopy: true, + canEdit: false, + canGiveFeedback: false, + canRegenerate: false, + }, + display: { + collapsed: false, + hide: false, + }, + }); + + expect(items[3].element).toBeTruthy(); + + const { container } = render(items[3].element as React.ReactElement, { + wrapper: ({ children }) => ( + + + {children} + + + ), + }); + + expect(mockChatService.renderFunction).toHaveBeenCalledWith( + 'my_render_function', + JSON.stringify({ foo: 'bar' }), + { content: '[]', name: 'my_render_function', role: 'user' } + ); + + expect(container.textContent).toEqual('Rendered'); + }); + }); + + describe('with a function that errors out', () => { + beforeEach(() => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Hello', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + function_call: { + name: 'my_render_function', + arguments: JSON.stringify({ foo: 'bar' }), + trigger: MessageRole.Assistant, + }, + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + name: 'my_render_function', + content: JSON.stringify({ + error: { + message: 'An error occurred', + }, + }), + }, + }, + ], + }); + }); + + it('returns a title that reflects a failure to execute the function', () => { + const { container } = render(items[3].title as React.ReactElement, { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(container.textContent).toBe('failed to execute the function my_render_function'); + }); + + it('formats the messages correctly', () => { + expect(pick(items[3], 'actions', 'display', 'loading')).toEqual({ + actions: { + canCopy: true, + canEdit: false, + canGiveFeedback: false, + canRegenerate: false, + }, + display: { + collapsed: true, + hide: false, + }, + loading: false, + }); + }); + }); + + describe('with an invalid JSON response', () => { + beforeEach(() => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + currentUser: { + username: 'johndoe', + full_name: 'John Doe', + }, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: '', + function_call: { + name: 'my_function', + arguments: JSON.stringify({}), + trigger: MessageRole.User, + }, + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'invalid-json', + name: 'my_function', + }, + }, + ], + }); + }); + + it('sets the invalid json as content', () => { + expect(items[2].content).toBe( + `\`\`\` +{ + "content": "invalid-json" +} +\`\`\`` + ); + }); + }); + + describe('when starting from a contextual insight', () => { + beforeEach(() => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + currentUser: { + username: 'johndoe', + full_name: 'John Doe', + }, + chatState: ChatState.Ready, + startedFrom: 'contextualInsight', + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Test', + }, + }, + ], + }); + }); + + it('hides the first user message', () => { + expect(items[1].display.collapsed).toBe(true); + }); + }); + + describe('with function calling suggested by the user', () => { + beforeEach(() => { + mockChatService.hasRenderFunction.mockImplementation(() => false); + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + chatState: ChatState.Ready, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + function_call: { + name: 'recall', + arguments: JSON.stringify({ queries: [], contexts: [] }), + trigger: MessageRole.User, + }, + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + name: 'recall', + content: JSON.stringify([]), + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: 'Reply from assistant', + }, + }, + ], + }); + }); + + it('formats the function request', () => { + expect(pick(items[1], 'actions', 'display')).toEqual({ + actions: { + canCopy: true, + canRegenerate: false, + canEdit: true, + canGiveFeedback: false, + }, + display: { + collapsed: true, + hide: false, + }, + }); + }); + + it('formats the assistant response', () => { + expect(pick(items[3], 'actions', 'display')).toEqual({ + actions: { + canCopy: true, + canRegenerate: true, + canEdit: false, + canGiveFeedback: false, + }, + display: { + collapsed: false, + hide: false, + }, + }); + }); + }); + + describe('while the chat is loading', () => { + const renderWithLoading = (extraMessages: Message[]) => { + items = getTimelineItemsfromConversation({ + chatService: mockChatService, + hasConnector: true, + chatState: ChatState.Loading, + messages: [ + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.System, + content: 'System', + }, + }, + { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.User, + content: 'Test', + }, + }, + ...extraMessages, + ], + }); + }; + + describe('with a user message last', () => { + beforeEach(() => { + renderWithLoading([]); + }); + + it('adds an assistant message which is loading', () => { + expect(pick(last(items), 'display', 'actions', 'loading', 'role', 'content')).toEqual({ + loading: true, + role: MessageRole.Assistant, + actions: { + canCopy: false, + canRegenerate: false, + canEdit: false, + canGiveFeedback: false, + }, + display: { + collapsed: false, + hide: false, + }, + content: '', + }); + }); + }); + + describe('with a function request as the last message', () => { + beforeEach(() => { + renderWithLoading([ + { + '@timestamp': new Date().toISOString(), + message: { + function_call: { + name: 'my_function_call', + trigger: MessageRole.Assistant, + }, + role: MessageRole.Assistant, + }, + }, + ]); + }); + + it('adds an assistant message which is loading', () => { + expect(pick(last(items), 'display', 'actions', 'loading', 'role', 'content')).toEqual({ + loading: true, + role: MessageRole.Assistant, + actions: { + canCopy: false, + canRegenerate: false, + canEdit: false, + canGiveFeedback: false, + }, + display: { + collapsed: false, + hide: false, + }, + content: '', + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.tsx b/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.tsx index 61f2a4fcbd38..3bf54ec628f2 100644 --- a/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/utils/get_timeline_items_from_conversation.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; import { v4 } from 'uuid'; -import { isEmpty, omitBy } from 'lodash'; +import { isEmpty, last, omitBy } from 'lodash'; import { useEuiTheme } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -15,6 +15,15 @@ import { Message, MessageRole } from '../../common'; import type { ChatTimelineItem } from '../components/chat/chat_timeline'; import { RenderFunction } from '../components/render_function'; import type { ObservabilityAIAssistantChatService } from '../types'; +import { ChatState } from '../hooks/use_chat'; + +function safeParse(jsonStr: string) { + try { + return JSON.parse(jsonStr); + } catch (err) { + return jsonStr; + } +} function convertMessageToMarkdownCodeBlock(message: Message['message']) { let value: object; @@ -22,7 +31,7 @@ function convertMessageToMarkdownCodeBlock(message: Message['message']) { if (!message.name) { const name = message.function_call?.name; const args = message.function_call?.arguments - ? JSON.parse(message.function_call.arguments) + ? safeParse(message.function_call.arguments) : undefined; value = { @@ -32,9 +41,9 @@ function convertMessageToMarkdownCodeBlock(message: Message['message']) { } else { const content = message.role !== MessageRole.Assistant && message.content - ? JSON.parse(message.content) + ? safeParse(message.content) : message.content; - const data = message.data ? JSON.parse(message.data) : undefined; + const data = message.data ? safeParse(message.data) : undefined; value = omitBy( { content, @@ -61,26 +70,36 @@ export function getTimelineItemsfromConversation({ hasConnector, messages, startedFrom, + chatState, }: { chatService: ObservabilityAIAssistantChatService; currentUser?: Pick; hasConnector: boolean; messages: Message[]; startedFrom?: StartedFrom; + chatState: ChatState; }): ChatTimelineItem[] { - return [ + const messagesWithoutSystem = messages.filter( + (message) => message.message.role !== MessageRole.System + ); + + const items: ChatTimelineItem[] = [ { id: v4(), actions: { canCopy: false, canEdit: false, canGiveFeedback: false, canRegenerate: false }, display: { collapsed: false, hide: false }, currentUser, loading: false, - role: MessageRole.User, + message: { + '@timestamp': new Date().toISOString(), + message: { role: MessageRole.User }, + }, title: i18n.translate('xpack.observabilityAiAssistant.conversationStartTitle', { defaultMessage: 'started a conversation', }), + role: MessageRole.User, }, - ...messages.map((message, index) => { + ...messagesWithoutSystem.map((message, index) => { const id = v4(); let title: React.ReactNode = ''; @@ -88,8 +107,10 @@ export function getTimelineItemsfromConversation({ let element: React.ReactNode | undefined; const prevFunctionCall = - message.message.name && messages[index - 1] && messages[index - 1].message.function_call - ? messages[index - 1].message.function_call + message.message.name && + messagesWithoutSystem[index - 1] && + messagesWithoutSystem[index - 1].message.function_call + ? messagesWithoutSystem[index - 1].message.function_call : undefined; let role = message.message.function_call?.trigger || message.message.role; @@ -107,10 +128,6 @@ export function getTimelineItemsfromConversation({ }; switch (role) { - case MessageRole.System: - display.hide = true; - break; - case MessageRole.User: actions.canCopy = true; actions.canGiveFeedback = false; @@ -120,16 +137,15 @@ export function getTimelineItemsfromConversation({ // User executed a function: if (message.message.name && prevFunctionCall) { - let parsedContent; + let isError = false; try { - parsedContent = JSON.parse(message.message.content ?? 'null'); + const parsedContent = JSON.parse(message.message.content ?? 'null'); + isError = + parsedContent && typeof parsedContent === 'object' && 'error' in parsedContent; } catch (error) { - parsedContent = message.message.content; + isError = true; } - const isError = - parsedContent && typeof parsedContent === 'object' && 'error' in parsedContent; - title = !isError ? ( el.message.role === MessageRole.User ); @@ -252,7 +268,53 @@ export function getTimelineItemsfromConversation({ currentUser, function_call: message.message.function_call, loading: false, + message, }; }), ]; + + const isLoading = chatState === ChatState.Loading; + + let lastMessage = last(items); + + const isNaturalLanguageOnlyAnswerFromAssistant = + lastMessage?.message.message.role === MessageRole.Assistant && + !lastMessage.message.message.function_call?.name; + + const addLoadingPlaceholder = isLoading && !isNaturalLanguageOnlyAnswerFromAssistant; + + if (addLoadingPlaceholder) { + items.push({ + id: v4(), + actions: { + canCopy: false, + canEdit: false, + canGiveFeedback: false, + canRegenerate: false, + }, + display: { + collapsed: false, + hide: false, + }, + content: '', + currentUser, + loading: chatState === ChatState.Loading, + role: MessageRole.Assistant, + title: '', + message: { + '@timestamp': new Date().toISOString(), + message: { + role: MessageRole.Assistant, + content: '', + }, + }, + }); + lastMessage = last(items); + } + + if (isLoading && lastMessage) { + lastMessage.loading = isLoading; + } + + return items; } diff --git a/x-pack/plugins/observability_ai_assistant/tsconfig.json b/x-pack/plugins/observability_ai_assistant/tsconfig.json index afdc9a4a8924..93817dcf7919 100644 --- a/x-pack/plugins/observability_ai_assistant/tsconfig.json +++ b/x-pack/plugins/observability_ai_assistant/tsconfig.json @@ -46,7 +46,8 @@ "@kbn/es-query", "@kbn/rule-registry-plugin", "@kbn/licensing-plugin", - "@kbn/share-plugin" + "@kbn/share-plugin", + "@kbn/utility-types-jest" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_log_explorer/kibana.jsonc b/x-pack/plugins/observability_log_explorer/kibana.jsonc index 72d03b82d338..92d2ad70c317 100644 --- a/x-pack/plugins/observability_log_explorer/kibana.jsonc +++ b/x-pack/plugins/observability_log_explorer/kibana.jsonc @@ -19,6 +19,7 @@ "observabilityShared", "share", "kibanaUtils", + "datasetQuality" ], "optionalPlugins": [ "serverless" diff --git a/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx b/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx index a8c6602f9d49..8a49db753635 100644 --- a/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx +++ b/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx @@ -10,7 +10,7 @@ import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { Route, Router, Routes } from '@kbn/shared-ux-router'; import React from 'react'; import ReactDOM from 'react-dom'; -import { ObservablityLogExplorerMainRoute } from '../routes/main'; +import { DatasetQualityRoute, ObservablityLogExplorerMainRoute } from '../routes/main'; import { ObservabilityLogExplorerAppMountParameters, ObservabilityLogExplorerPluginStart, @@ -72,6 +72,11 @@ export const ObservabilityLogExplorerApp = ({ exact={true} render={() => } /> + } + /> diff --git a/x-pack/plugins/observability_log_explorer/public/components/page_template.tsx b/x-pack/plugins/observability_log_explorer/public/components/page_template.tsx index e79b8b1bc627..d128c6e8a777 100644 --- a/x-pack/plugins/observability_log_explorer/public/components/page_template.tsx +++ b/x-pack/plugins/observability_log_explorer/public/components/page_template.tsx @@ -13,10 +13,14 @@ import React from 'react'; export const ObservabilityLogExplorerPageTemplate = ({ children, observabilityShared, + pageProps, }: React.PropsWithChildren<{ observabilityShared: ObservabilitySharedPluginStart; + pageProps?: EuiPageSectionProps; }>) => ( - + {children} ); diff --git a/x-pack/plugins/observability_log_explorer/public/routes/main/dataset_quality_route.tsx b/x-pack/plugins/observability_log_explorer/public/routes/main/dataset_quality_route.tsx new file mode 100644 index 000000000000..b76a462eba25 --- /dev/null +++ b/x-pack/plugins/observability_log_explorer/public/routes/main/dataset_quality_route.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart } from '@kbn/core/public'; +import React from 'react'; +import { EuiBreadcrumb } from '@elastic/eui'; +import { datasetQualityAppTitle } from '@kbn/dataset-quality-plugin/public'; +import { ObservabilityLogExplorerPageTemplate } from '../../components/page_template'; +import { useBreadcrumbs } from '../../utils/breadcrumbs'; +import { useKibanaContextForPlugin } from '../../utils/use_kibana'; + +export interface DatasetQualityRouteProps { + core: CoreStart; +} + +export const DatasetQualityRoute = ({ core }: DatasetQualityRouteProps) => { + const { services } = useKibanaContextForPlugin(); + const { observabilityShared, serverless, datasetQuality: DatasetQuality } = services; + const breadcrumb: EuiBreadcrumb[] = [ + { + text: datasetQualityAppTitle, + }, + ]; + + useBreadcrumbs(breadcrumb, core.chrome, serverless); + + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/observability_log_explorer/public/routes/main/index.tsx b/x-pack/plugins/observability_log_explorer/public/routes/main/index.tsx index 889e340497cf..9d755f302d16 100644 --- a/x-pack/plugins/observability_log_explorer/public/routes/main/index.tsx +++ b/x-pack/plugins/observability_log_explorer/public/routes/main/index.tsx @@ -6,3 +6,4 @@ */ export * from './main_route'; +export * from './dataset_quality_route'; diff --git a/x-pack/plugins/observability_log_explorer/public/types.ts b/x-pack/plugins/observability_log_explorer/public/types.ts index 8b315ad206ce..5f455088b744 100644 --- a/x-pack/plugins/observability_log_explorer/public/types.ts +++ b/x-pack/plugins/observability_log_explorer/public/types.ts @@ -13,6 +13,7 @@ import { ServerlessPluginStart } from '@kbn/serverless/public'; import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import { AppMountParameters, ScopedHistory } from '@kbn/core/public'; import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public'; +import { DatasetQualityPluginStart } from '@kbn/dataset-quality-plugin/public'; import { ObservabilityLogExplorerLocators, ObservabilityLogExplorerLocationState, @@ -38,6 +39,7 @@ export interface ObservabilityLogExplorerStartDeps { observabilityShared: ObservabilitySharedPluginStart; serverless?: ServerlessPluginStart; share: SharePluginStart; + datasetQuality: DatasetQualityPluginStart; } export type ObservabilityLogExplorerHistory = ScopedHistory; diff --git a/x-pack/plugins/observability_log_explorer/tsconfig.json b/x-pack/plugins/observability_log_explorer/tsconfig.json index 109b54b929ec..24327c31c26a 100644 --- a/x-pack/plugins/observability_log_explorer/tsconfig.json +++ b/x-pack/plugins/observability_log_explorer/tsconfig.json @@ -34,7 +34,8 @@ "@kbn/xstate-utils", "@kbn/shared-ux-utility", "@kbn/ui-theme", - "@kbn/logs-shared-plugin" + "@kbn/logs-shared-plugin", + "@kbn/dataset-quality-plugin" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx new file mode 100644 index 000000000000..02908cdf67a0 --- /dev/null +++ b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/embeddable_profiling_search_bar.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { default as React, useEffect, useRef, useState } from 'react'; +import { EMBEDDABLE_PROFILING_SEARCH_BAR } from '.'; +import { ObservabilitySharedStart } from '../../../plugin'; + +export interface EmbeddableProfilingSearchBarProps { + kuery: string; + showDatePicker?: boolean; + onQuerySubmit: (params: { + dateRange: { from: string; to: string; mode?: 'absolute' | 'relative' }; + query: string; + }) => void; + onRefresh: () => void; + rangeFrom: string; + rangeTo: string; +} + +export function EmbeddableProfilingSearchBar(props: EmbeddableProfilingSearchBarProps) { + const { embeddable: embeddablePlugin } = useKibana().services; + const [embeddable, setEmbeddable] = useState(); + const embeddableRoot: React.RefObject = useRef(null); + + useEffect(() => { + async function createEmbeddable() { + const factory = embeddablePlugin?.getEmbeddableFactory(EMBEDDABLE_PROFILING_SEARCH_BAR); + const input = { + id: 'embeddable_profiling', + }; + const embeddableObject = await factory?.create(input); + setEmbeddable(embeddableObject); + } + createEmbeddable(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (embeddableRoot.current && embeddable) { + embeddable.render(embeddableRoot.current); + } + }, [embeddable, embeddableRoot]); + + useEffect(() => { + if (embeddable) { + embeddable.updateInput({ + ...props, + }); + embeddable.reload(); + } + }, [embeddable, props]); + + return ( +
    + ); +} diff --git a/x-pack/plugins/observability_shared/public/components/profiling/embeddables/index.ts b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/index.ts index 2e346d55c835..05556b839cff 100644 --- a/x-pack/plugins/observability_shared/public/components/profiling/embeddables/index.ts +++ b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/index.ts @@ -14,3 +14,11 @@ export { EmbeddableFlamegraph } from './embeddable_flamegraph'; export const EMBEDDABLE_FUNCTIONS = 'EMBEDDABLE_FUNCTIONS'; /** Profiling functions embeddable */ export { EmbeddableFunctions } from './embeddable_functions'; + +/** Profiling search bar embeddable key */ +export const EMBEDDABLE_PROFILING_SEARCH_BAR = 'EMBEDDABLE_PROFILING_SEARCH_BAR'; +/** Profiling search bar embeddable */ +export { + EmbeddableProfilingSearchBar, + type EmbeddableProfilingSearchBarProps, +} from './embeddable_profiling_search_bar'; diff --git a/x-pack/plugins/observability_shared/public/components/profiling/embeddables/profiling_embeddable.tsx b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/profiling_embeddable.tsx index 1a703d11ed6c..00f29c10c159 100644 --- a/x-pack/plugins/observability_shared/public/components/profiling/embeddables/profiling_embeddable.tsx +++ b/x-pack/plugins/observability_shared/public/components/profiling/embeddables/profiling_embeddable.tsx @@ -31,7 +31,11 @@ export function ProfilingEmbeddable({ useEffect(() => { async function createEmbeddable() { const factory = embeddablePlugin?.getEmbeddableFactory(embeddableFactoryId); - const input = { id: 'embeddable_profiling', data, isLoading }; + const input = { + id: 'embeddable_profiling', + data, + isLoading, + }; const embeddableObject = await factory?.create(input); setEmbeddable(embeddableObject); } @@ -47,7 +51,11 @@ export function ProfilingEmbeddable({ useEffect(() => { if (embeddable) { - embeddable.updateInput({ data, isLoading, ...props }); + embeddable.updateInput({ + data, + isLoading, + ...props, + }); embeddable.reload(); } }, [data, embeddable, isLoading, props]); diff --git a/x-pack/plugins/observability_shared/public/hooks/use_get_user_cases_permissions.tsx b/x-pack/plugins/observability_shared/public/hooks/use_get_user_cases_permissions.tsx deleted file mode 100644 index 21c6a08815b7..000000000000 --- a/x-pack/plugins/observability_shared/public/hooks/use_get_user_cases_permissions.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect, useState } from 'react'; -import { CasesPermissions } from '@kbn/cases-plugin/common'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { casesFeatureId } from '../../common'; -import { ObservabilitySharedStart } from '../plugin'; - -export function useGetUserCasesPermissions() { - const [casesPermissions, setCasesPermissions] = useState({ - all: false, - read: false, - create: false, - update: false, - delete: false, - push: false, - connectors: false, - }); - const uiCapabilities = useKibana().services.application!.capabilities; - - const casesCapabilities = - useKibana().services.cases.helpers.getUICapabilities( - uiCapabilities[casesFeatureId] - ); - - useEffect(() => { - setCasesPermissions({ - all: casesCapabilities.all, - create: casesCapabilities.create, - read: casesCapabilities.read, - update: casesCapabilities.update, - delete: casesCapabilities.delete, - push: casesCapabilities.push, - connectors: casesCapabilities.connectors, - }); - }, [ - casesCapabilities.all, - casesCapabilities.create, - casesCapabilities.read, - casesCapabilities.update, - casesCapabilities.delete, - casesCapabilities.push, - casesCapabilities.connectors, - ]); - - return casesPermissions; -} diff --git a/x-pack/plugins/observability_shared/public/index.ts b/x-pack/plugins/observability_shared/public/index.ts index 66492328e4b8..8d8556e509e2 100644 --- a/x-pack/plugins/observability_shared/public/index.ts +++ b/x-pack/plugins/observability_shared/public/index.ts @@ -57,7 +57,6 @@ export { } from './hooks/use_track_metric'; export type { TrackEvent } from './hooks/use_track_metric'; export { useQuickTimeRanges } from './hooks/use_quick_time_ranges'; -export { useGetUserCasesPermissions } from './hooks/use_get_user_cases_permissions'; export { useTimeZone } from './hooks/use_time_zone'; export { useChartTheme } from './hooks/use_chart_theme'; export { useLinkProps, shouldHandleLinkEvent } from './hooks/use_link_props'; @@ -66,7 +65,7 @@ export { NavigationWarningPromptProvider, Prompt } from './components/navigation export type { ApmIndicesConfig, UXMetrics } from './types'; -export { noCasesPermissions } from './utils/cases_permissions'; +export { noCasesPermissions, allCasesPermissions } from './utils/cases_permissions'; export { type ObservabilityActionContextMenuItemProps, @@ -83,6 +82,9 @@ export { export { EMBEDDABLE_FLAMEGRAPH, EMBEDDABLE_FUNCTIONS, + EMBEDDABLE_PROFILING_SEARCH_BAR, EmbeddableFlamegraph, EmbeddableFunctions, + EmbeddableProfilingSearchBar, + type EmbeddableProfilingSearchBarProps, } from './components/profiling/embeddables'; diff --git a/x-pack/plugins/observability_shared/public/utils/cases_permissions.ts b/x-pack/plugins/observability_shared/public/utils/cases_permissions.ts index a0b6a8aed95b..0ceea46ad0d3 100644 --- a/x-pack/plugins/observability_shared/public/utils/cases_permissions.ts +++ b/x-pack/plugins/observability_shared/public/utils/cases_permissions.ts @@ -13,4 +13,16 @@ export const noCasesPermissions = () => ({ delete: false, push: false, connectors: false, + settings: false, +}); + +export const allCasesPermissions = () => ({ + all: true, + create: true, + read: true, + update: true, + delete: true, + push: true, + connectors: true, + settings: true, }); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts index 7f6f0a006e05..d9cbe5c69ed6 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts @@ -65,10 +65,12 @@ describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () => it('runs osquery against alert and creates a new case', () => { const [caseName, caseDescription] = generateRandomStringName(2); - cy.getBySel('expand-event').first().click({ force: true }); + cy.getBySel('expand-event').first().click(); cy.getBySel('take-action-dropdown-btn').click(); cy.getBySel('osquery-action-item').click(); cy.contains(/^\d+ agen(t|ts) selected/); + cy.getBySel('globalLoadingIndicator').should('not.exist'); + cy.wait(1000); cy.contains('Run a set of queries in a pack').click(); cy.get(OSQUERY_FLYOUT_BODY_EDITOR).should('not.exist'); cy.getBySel('globalLoadingIndicator').should('not.exist'); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts index cb4ce27a6903..f0d3c3468f16 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts @@ -15,6 +15,7 @@ import { packFixture, } from '../../tasks/api_fixtures'; import { + RESPONSE_ACTIONS_ERRORS, OSQUERY_RESPONSE_ACTION_ADD_BUTTON, RESPONSE_ACTIONS_ITEM_0, RESPONSE_ACTIONS_ITEM_1, @@ -66,6 +67,48 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve cy.getBySel('globalLoadingIndicator').should('not.exist'); cy.contains('Response actions are run on each rule execution.'); cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); + + cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => { + cy.contains('Query is a required field'); + cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist'); + }); + + // check if changing error state of one input doesn't clear other errors - START + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains('Advanced').click(); + cy.getBySel('timeout-input').clear(); + cy.contains('Timeout value must be greater than 60 seconds.'); + }); + + cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => { + cy.contains('Query is a required field'); + cy.contains('Timeout value must be greater than 60 seconds.'); + }); + + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.getBySel('timeout-input').type('6'); + cy.contains('Timeout value must be greater than 60 seconds.'); + }); + cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => { + cy.contains('Query is a required field'); + cy.contains('Timeout value must be greater than 60 seconds.'); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.getBySel('timeout-input').type('6'); + cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist'); + }); + cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => { + cy.contains('Query is a required field'); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.getBySel('timeout-input').type('6'); + }); + cy.getBySel(RESPONSE_ACTIONS_ERRORS).within(() => { + cy.contains('Query is a required field'); + cy.contains('Timeout value must be greater than 60 seconds.').should('not.exist'); + }); + // check if changing error state of one input doesn't clear other errors - END + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { cy.contains('Query is a required field'); inputQuery('select * from uptime1'); @@ -74,7 +117,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { cy.contains('Run a set of queries in a pack').click(); }); - cy.getBySel('response-actions-error') + cy.getBySel(RESPONSE_ACTIONS_ERRORS) .within(() => { cy.contains('Pack is a required field'); }) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts index e43dbf4b5d48..04a3a24fbabb 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/live_query.cy.ts @@ -37,10 +37,10 @@ describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => { cy.contains('Query is a required field').should('not.exist'); checkResults(); getAdvancedButton().click(); - fillInQueryTimeout('91'); + fillInQueryTimeout('910'); submitQuery(); cy.contains('Timeout value must be lower than 900 seconds.'); - fillInQueryTimeout('89'); + fillInQueryTimeout('890'); submitQuery(); cy.contains('Timeout value must be lower than 900 seconds.').should('not.exist'); typeInOsqueryFieldInput('days{downArrow}{enter}'); @@ -58,7 +58,10 @@ describe('ALL - Live Query', { tags: ['@ess', '@serverless'] }, () => { expect(interception.response?.body.data.queries[0]).to.have.property('timeout', 890); }); checkResults(); - cy.get('[data-gridcell-column-index="0"][data-gridcell-row-index="0"]').should('exist').click(); + cy.get('[data-gridcell-column-index="0"][data-gridcell-row-index="0"]').should('exist'); + cy.get( + '[data-gridcell-column-index="0"][data-gridcell-row-index="0"] [data-datagrid-interactable="true"]' + ).click(); cy.url().should('include', 'app/fleet/agents/'); }); diff --git a/x-pack/plugins/osquery/cypress/tasks/response_actions.ts b/x-pack/plugins/osquery/cypress/tasks/response_actions.ts index d686392431b7..8f0b5638bdcb 100644 --- a/x-pack/plugins/osquery/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/osquery/cypress/tasks/response_actions.ts @@ -10,6 +10,7 @@ import { ServerlessRoleName } from '../support/roles'; import { cleanupRule, loadRule } from './api_fixtures'; import { closeDateTabIfVisible } from './integrations'; +export const RESPONSE_ACTIONS_ERRORS = 'response-actions-error'; export const RESPONSE_ACTIONS_ITEM_0 = 'response-actions-list-item-0'; export const RESPONSE_ACTIONS_ITEM_1 = 'response-actions-list-item-1'; export const RESPONSE_ACTIONS_ITEM_2 = 'response-actions-list-item-2'; diff --git a/x-pack/plugins/osquery/package.json b/x-pack/plugins/osquery/package.json index a708e9a38303..4e9070d780d2 100644 --- a/x-pack/plugins/osquery/package.json +++ b/x-pack/plugins/osquery/package.json @@ -12,7 +12,7 @@ "cypress:run": "yarn cypress run", "cypress:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ../security_solution/scripts/start_cypress_parallel --config-file ../osquery/cypress/serverless_cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/serverless_cli_config", "cypress:serverless:open": "yarn cypress:serverless open", - "cypress:serverless:run": "yarn cypress:serverless run --spec ./cypress/e2e/all/packs_integration.cy.ts", + "cypress:serverless:run": "yarn cypress:serverless run", "nyc": "../../../node_modules/.bin/nyc report --reporter=text-summary", "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-osquery/cypress/results/mochawesome*.json > ../../../target/kibana-osquery/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-osquery/cypress/results/output.json --reportDir ../../../target/kibana-osquery/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-osquery/cypress/results/*.xml ../../../target/junit/", "junit:transform": "node ../security_solution/scripts/junit_transformer --pathPattern '../../../target/kibana-osquery/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Osquery Cypress' --writeInPlace", diff --git a/x-pack/plugins/osquery/public/common/schemas/ecs/v8.11.0.json b/x-pack/plugins/osquery/public/common/schemas/ecs/v8.11.0.json new file mode 100644 index 000000000000..dc58c0738689 --- /dev/null +++ b/x-pack/plugins/osquery/public/common/schemas/ecs/v8.11.0.json @@ -0,0 +1 @@ +[{"field":"labels","type":"object","normalization":"","example":{"application":"foo-bar","env":"production"},"description":"Custom key/value pairs."},{"field":"message","type":"match_only_text","normalization":"","example":"Hello World","description":"Log message optimized for viewing in a log viewer."},{"field":"tags","type":"keyword","normalization":"array","example":["production","env2"],"description":"List of keywords used to tag each event."},{"field":"agent.build.original","type":"keyword","normalization":"","example":"metricbeat version 7.6.0 (amd64), libbeat 7.6.0 [6a23e8f8f30f5001ba344e4e54d8d9cb82cb107c built 2020-02-05 23:10:10 +0000 UTC]","description":"Extended build information for the agent."},{"field":"client.address","type":"keyword","normalization":"","example":"","description":"Client network address."},{"field":"client.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"client.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"client.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"client.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the client to the server."},{"field":"client.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the client."},{"field":"client.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"client.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"client.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"client.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"client.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"client.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"client.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"client.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"client.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"client.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"client.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"client.ip","type":"ip","normalization":"","example":"","description":"IP address of the client."},{"field":"client.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the client."},{"field":"client.nat.ip","type":"ip","normalization":"","example":"","description":"Client NAT ip address"},{"field":"client.nat.port","type":"long","normalization":"","example":"","description":"Client NAT port"},{"field":"client.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the client to the server."},{"field":"client.port","type":"long","normalization":"","example":"","description":"Port of the client."},{"field":"client.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered client domain, stripped of the subdomain."},{"field":"client.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"client.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"client.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"client.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"client.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"client.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"client.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"client.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"client.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"client.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"client.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"client.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"client.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"client.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"cloud.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.origin.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.origin.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.origin.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.origin.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.origin.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.origin.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.origin.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.origin.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.origin.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.origin.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.origin.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"cloud.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"cloud.target.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.target.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.target.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.target.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.target.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.target.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.target.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.target.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.target.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.target.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.target.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"container.cpu.usage","type":"scaled_float","normalization":"","example":"","description":"Percent CPU used, between 0 and 1."},{"field":"container.disk.read.bytes","type":"long","normalization":"","example":"","description":"The number of bytes read by all disks."},{"field":"container.disk.write.bytes","type":"long","normalization":"","example":"","description":"The number of bytes written on all disks."},{"field":"container.id","type":"keyword","normalization":"","example":"","description":"Unique container id."},{"field":"container.image.hash.all","type":"keyword","normalization":"array","example":"[sha256:f8fefc80e3273dc756f288a63945820d6476ad64883892c771b5e2ece6bf1b26]","description":"An array of digests of the image the container was built on."},{"field":"container.image.name","type":"keyword","normalization":"","example":"","description":"Name of the image the container was built on."},{"field":"container.image.tag","type":"keyword","normalization":"array","example":"","description":"Container image tags."},{"field":"container.labels","type":"object","normalization":"","example":"","description":"Image labels."},{"field":"container.memory.usage","type":"scaled_float","normalization":"","example":"","description":"Percent memory used, between 0 and 1."},{"field":"container.name","type":"keyword","normalization":"","example":"","description":"Container name."},{"field":"container.network.egress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes sent on all network interfaces."},{"field":"container.network.ingress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes received on all network interfaces."},{"field":"container.runtime","type":"keyword","normalization":"","example":"docker","description":"Runtime managing this container."},{"field":"container.security_context.privileged","type":"boolean","normalization":"","example":"","description":"Indicates whether the container is running in privileged mode."},{"field":"data_stream.dataset","type":"constant_keyword","normalization":"","example":"nginx.access","description":"The field can contain anything that makes sense to signify the source of the data."},{"field":"data_stream.namespace","type":"constant_keyword","normalization":"","example":"production","description":"A user defined namespace. Namespaces are useful to allow grouping of data."},{"field":"data_stream.type","type":"constant_keyword","normalization":"","example":"logs","description":"An overarching type for the data stream."},{"field":"destination.address","type":"keyword","normalization":"","example":"","description":"Destination network address."},{"field":"destination.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"destination.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"destination.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"destination.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the destination to the source."},{"field":"destination.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the destination."},{"field":"destination.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"destination.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"destination.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"destination.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"destination.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"destination.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"destination.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"destination.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"destination.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"destination.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"destination.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"destination.ip","type":"ip","normalization":"","example":"","description":"IP address of the destination."},{"field":"destination.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the destination."},{"field":"destination.nat.ip","type":"ip","normalization":"","example":"","description":"Destination NAT ip"},{"field":"destination.nat.port","type":"long","normalization":"","example":"","description":"Destination NAT Port"},{"field":"destination.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the destination to the source."},{"field":"destination.port","type":"long","normalization":"","example":"","description":"Port of the destination."},{"field":"destination.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered destination domain, stripped of the subdomain."},{"field":"destination.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"destination.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"destination.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"destination.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"destination.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"destination.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"destination.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"destination.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"destination.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"destination.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"destination.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"destination.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"destination.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"destination.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"device.id","type":"keyword","normalization":"","example":"00000000-54b3-e7c7-0000-000046bffd97","description":"The unique identifier of a device."},{"field":"device.manufacturer","type":"keyword","normalization":"","example":"Samsung","description":"The vendor name of the device manufacturer."},{"field":"device.model.identifier","type":"keyword","normalization":"","example":"SM-G920F","description":"The machine readable identifier of the device model."},{"field":"device.model.name","type":"keyword","normalization":"","example":"Samsung Galaxy S6","description":"The human readable marketing name of the device model."},{"field":"dll.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"dll.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"dll.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"dll.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"dll.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"dll.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"dll.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"dll.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"dll.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"dll.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"dll.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"dll.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"dll.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"dll.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"dll.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"dll.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"dll.name","type":"keyword","normalization":"","example":"kernel32.dll","description":"Name of the library."},{"field":"dll.path","type":"keyword","normalization":"","example":"C:\\Windows\\System32\\kernel32.dll","description":"Full file path of the library."},{"field":"dll.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"dll.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"dll.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"dll.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"dll.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"dll.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"dll.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"dll.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"dll.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"dll.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"dll.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"dll.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"dll.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"dll.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"dll.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"dll.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"dll.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"dll.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"dll.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"dll.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"dll.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"dll.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"dll.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"dns.answers","type":"object","normalization":"array","example":"","description":"Array of DNS answers."},{"field":"dns.answers.class","type":"keyword","normalization":"","example":"IN","description":"The class of DNS data contained in this resource record."},{"field":"dns.answers.data","type":"keyword","normalization":"","example":"10.10.10.10","description":"The data describing the resource."},{"field":"dns.answers.name","type":"keyword","normalization":"","example":"www.example.com","description":"The domain name to which this resource record pertains."},{"field":"dns.answers.ttl","type":"long","normalization":"","example":180,"description":"The time interval in seconds that this resource record may be cached before it should be discarded."},{"field":"dns.answers.type","type":"keyword","normalization":"","example":"CNAME","description":"The type of data contained in this resource record."},{"field":"dns.header_flags","type":"keyword","normalization":"array","example":["RD","RA"],"description":"Array of DNS header flags."},{"field":"dns.id","type":"keyword","normalization":"","example":62111,"description":"The DNS packet identifier assigned by the program that generated the query. The identifier is copied to the response."},{"field":"dns.op_code","type":"keyword","normalization":"","example":"QUERY","description":"The DNS operation code that specifies the kind of query in the message."},{"field":"dns.question.class","type":"keyword","normalization":"","example":"IN","description":"The class of records being queried."},{"field":"dns.question.name","type":"keyword","normalization":"","example":"www.example.com","description":"The name being queried."},{"field":"dns.question.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered domain, stripped of the subdomain."},{"field":"dns.question.subdomain","type":"keyword","normalization":"","example":"www","description":"The subdomain of the domain."},{"field":"dns.question.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"dns.question.type","type":"keyword","normalization":"","example":"AAAA","description":"The type of record being queried."},{"field":"dns.resolved_ip","type":"ip","normalization":"array","example":["10.10.10.10","10.10.10.11"],"description":"Array containing all IPs seen in answers.data"},{"field":"dns.response_code","type":"keyword","normalization":"","example":"NOERROR","description":"The DNS response code."},{"field":"dns.type","type":"keyword","normalization":"","example":"answer","description":"The type of DNS event captured, query or answer."},{"field":"email.attachments","type":"nested","normalization":"array","example":"","description":"List of objects describing the attachments."},{"field":"email.attachments.file.extension","type":"keyword","normalization":"","example":"txt","description":"Attachment file extension."},{"field":"email.attachments.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"email.attachments.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"email.attachments.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"email.attachments.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"email.attachments.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"email.attachments.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"email.attachments.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"email.attachments.file.mime_type","type":"keyword","normalization":"","example":"text/plain","description":"MIME type of the attachment file."},{"field":"email.attachments.file.name","type":"keyword","normalization":"","example":"attachment.txt","description":"Name of the attachment file."},{"field":"email.attachments.file.size","type":"long","normalization":"","example":64329,"description":"Attachment file size."},{"field":"email.bcc.address","type":"keyword","normalization":"array","example":"bcc.user1@example.com","description":"Email address of BCC recipient"},{"field":"email.cc.address","type":"keyword","normalization":"array","example":"cc.user1@example.com","description":"Email address of CC recipient"},{"field":"email.content_type","type":"keyword","normalization":"","example":"text/plain","description":"MIME type of the email message."},{"field":"email.delivery_timestamp","type":"date","normalization":"","example":"2020-11-10T22:12:34.8196921Z","description":"Date and time when message was delivered."},{"field":"email.direction","type":"keyword","normalization":"","example":"inbound","description":"Direction of the message."},{"field":"email.from.address","type":"keyword","normalization":"array","example":"sender@example.com","description":"The sender's email address."},{"field":"email.local_id","type":"keyword","normalization":"","example":"c26dbea0-80d5-463b-b93c-4e8b708219ce","description":"Unique identifier given by the source."},{"field":"email.message_id","type":"wildcard","normalization":"","example":"81ce15$8r2j59@mail01.example.com","description":"Value from the Message-ID header."},{"field":"email.origination_timestamp","type":"date","normalization":"","example":"2020-11-10T22:12:34.8196921Z","description":"Date and time the email was composed."},{"field":"email.reply_to.address","type":"keyword","normalization":"array","example":"reply.here@example.com","description":"Address replies should be delivered to."},{"field":"email.sender.address","type":"keyword","normalization":"","example":"","description":"Address of the message sender."},{"field":"email.subject","type":"keyword","normalization":"","example":"Please see this important message.","description":"The subject of the email message."},{"field":"email.subject.text","type":"match_only_text","normalization":"","example":"Please see this important message.","description":"The subject of the email message."},{"field":"email.to.address","type":"keyword","normalization":"array","example":"user1@example.com","description":"Email address of recipient"},{"field":"email.x_mailer","type":"keyword","normalization":"","example":"Spambot v2.5","description":"Application that drafted email."},{"field":"error.code","type":"keyword","normalization":"","example":"","description":"Error code describing the error."},{"field":"error.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the error."},{"field":"error.message","type":"match_only_text","normalization":"","example":"","description":"Error message."},{"field":"error.stack_trace","type":"wildcard","normalization":"","example":"","description":"The stack trace of this error in plain text."},{"field":"error.stack_trace.text","type":"match_only_text","normalization":"","example":"","description":"The stack trace of this error in plain text."},{"field":"error.type","type":"keyword","normalization":"","example":"java.lang.NullPointerException","description":"The type of the error, for example the class name of the exception."},{"field":"event.action","type":"keyword","normalization":"","example":"user-password-change","description":"The action captured by the event."},{"field":"event.category","type":"keyword","normalization":"array","example":"authentication","description":"Event category. The second categorization field in the hierarchy."},{"field":"event.code","type":"keyword","normalization":"","example":4648,"description":"Identification code for this event."},{"field":"event.created","type":"date","normalization":"","example":"2016-05-23T08:05:34.857Z","description":"Time when the event was first read by an agent or by your pipeline."},{"field":"event.dataset","type":"keyword","normalization":"","example":"apache.access","description":"Name of the dataset."},{"field":"event.duration","type":"long","normalization":"","example":"","description":"Duration of the event in nanoseconds."},{"field":"event.end","type":"date","normalization":"","example":"","description":"`event.end` contains the date when the event ended or when the activity was last observed."},{"field":"event.hash","type":"keyword","normalization":"","example":"123456789012345678901234567890ABCD","description":"Hash (perhaps logstash fingerprint) of raw field to be able to demonstrate log integrity."},{"field":"event.id","type":"keyword","normalization":"","example":"8a4f500d","description":"Unique ID to describe the event."},{"field":"event.kind","type":"keyword","normalization":"","example":"alert","description":"The kind of the event. The highest categorization field in the hierarchy."},{"field":"event.original","type":"keyword","normalization":"","example":"Sep 19 08:26:10 host CEF:0|Security| threatmanager|1.0|100| worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2spt=1232","description":"Raw text message of entire event."},{"field":"event.outcome","type":"keyword","normalization":"","example":"success","description":"The outcome of the event. The lowest level categorization field in the hierarchy."},{"field":"event.provider","type":"keyword","normalization":"","example":"kernel","description":"Source of the event."},{"field":"event.reason","type":"keyword","normalization":"","example":"Terminated an unexpected process","description":"Reason why this event happened, according to the source"},{"field":"event.reference","type":"keyword","normalization":"","example":"https://system.example.com/event/#0001234","description":"Event reference URL"},{"field":"event.risk_score","type":"float","normalization":"","example":"","description":"Risk score or priority of the event (e.g. security solutions). Use your system's original value here."},{"field":"event.risk_score_norm","type":"float","normalization":"","example":"","description":"Normalized risk score or priority of the event (0-100)."},{"field":"event.sequence","type":"long","normalization":"","example":"","description":"Sequence number of the event."},{"field":"event.severity","type":"long","normalization":"","example":7,"description":"Numeric severity of the event."},{"field":"event.start","type":"date","normalization":"","example":"","description":"`event.start` contains the date when the event started or when the activity was first observed."},{"field":"event.timezone","type":"keyword","normalization":"","example":"","description":"Event time zone."},{"field":"event.type","type":"keyword","normalization":"array","example":"","description":"Event type. The third categorization field in the hierarchy."},{"field":"event.url","type":"keyword","normalization":"","example":"https://mysystem.example.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe","description":"Event investigation URL"},{"field":"faas.coldstart","type":"boolean","normalization":"","example":"","description":"Boolean value indicating a cold start of a function."},{"field":"faas.execution","type":"keyword","normalization":"","example":"af9d5aa4-a685-4c5f-a22b-444f80b3cc28","description":"The execution ID of the current function execution."},{"field":"faas.id","type":"keyword","normalization":"","example":"arn:aws:lambda:us-west-2:123456789012:function:my-function","description":"The unique identifier of a serverless function."},{"field":"faas.name","type":"keyword","normalization":"","example":"my-function","description":"The name of a serverless function."},{"field":"faas.trigger.request_id","type":"keyword","normalization":"","example":123456789,"description":"The ID of the trigger request , message, event, etc."},{"field":"faas.trigger.type","type":"keyword","normalization":"","example":"http","description":"The trigger for the function execution."},{"field":"faas.version","type":"keyword","normalization":"","example":123,"description":"The version of a serverless function."},{"field":"file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"file.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"file.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"file.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"file.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"file.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"file.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"file.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"host.boot.id","type":"keyword","normalization":"","example":"88a1f0ed-5ae5-41ee-af6b-41921c311872","description":"Linux boot uuid taken from /proc/sys/kernel/random/boot_id"},{"field":"host.cpu.usage","type":"scaled_float","normalization":"","example":"","description":"Percent CPU used, between 0 and 1."},{"field":"host.disk.read.bytes","type":"long","normalization":"","example":"","description":"The number of bytes read by all disks."},{"field":"host.disk.write.bytes","type":"long","normalization":"","example":"","description":"The number of bytes written on all disks."},{"field":"host.domain","type":"keyword","normalization":"","example":"CONTOSO","description":"Name of the directory the group is a member of."},{"field":"host.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"host.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"host.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"host.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"host.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"host.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"host.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"host.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"host.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"host.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"host.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"host.name","type":"keyword","normalization":"","example":"","description":"Name of the host."},{"field":"host.network.egress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes sent on all network interfaces."},{"field":"host.network.egress.packets","type":"long","normalization":"","example":"","description":"The number of packets sent on all network interfaces."},{"field":"host.network.ingress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes received on all network interfaces."},{"field":"host.network.ingress.packets","type":"long","normalization":"","example":"","description":"The number of packets received on all network interfaces."},{"field":"host.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"host.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"host.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"host.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"host.pid_ns_ino","type":"keyword","normalization":"","example":256383,"description":"Pid namespace inode"},{"field":"host.risk.calculated_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"host.risk.calculated_score","type":"float","normalization":"","example":880.73,"description":"A risk classification score calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"host.risk.calculated_score_norm","type":"float","normalization":"","example":88.73,"description":"A normalized risk score calculated by an internal system."},{"field":"host.risk.static_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"host.risk.static_score","type":"float","normalization":"","example":830,"description":"A risk classification score obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"host.risk.static_score_norm","type":"float","normalization":"","example":83,"description":"A normalized risk score calculated by an external system."},{"field":"host.type","type":"keyword","normalization":"","example":"","description":"Type of host."},{"field":"host.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the host has been up."},{"field":"http.request.body.bytes","type":"long","normalization":"","example":887,"description":"Size in bytes of the request body."},{"field":"http.request.body.content","type":"wildcard","normalization":"","example":"Hello world","description":"The full HTTP request body."},{"field":"http.request.body.content.text","type":"match_only_text","normalization":"","example":"Hello world","description":"The full HTTP request body."},{"field":"http.request.bytes","type":"long","normalization":"","example":1437,"description":"Total size in bytes of the request (body and headers)."},{"field":"http.request.id","type":"keyword","normalization":"","example":"123e4567-e89b-12d3-a456-426614174000","description":"HTTP request ID."},{"field":"http.request.method","type":"keyword","normalization":"","example":"POST","description":"HTTP request method."},{"field":"http.request.mime_type","type":"keyword","normalization":"","example":"image/gif","description":"Mime type of the body of the request."},{"field":"http.request.referrer","type":"keyword","normalization":"","example":"https://blog.example.com/","description":"Referrer for this HTTP request."},{"field":"http.response.body.bytes","type":"long","normalization":"","example":887,"description":"Size in bytes of the response body."},{"field":"http.response.body.content","type":"wildcard","normalization":"","example":"Hello world","description":"The full HTTP response body."},{"field":"http.response.body.content.text","type":"match_only_text","normalization":"","example":"Hello world","description":"The full HTTP response body."},{"field":"http.response.bytes","type":"long","normalization":"","example":1437,"description":"Total size in bytes of the response (body and headers)."},{"field":"http.response.mime_type","type":"keyword","normalization":"","example":"image/gif","description":"Mime type of the body of the response."},{"field":"http.response.status_code","type":"long","normalization":"","example":404,"description":"HTTP response status code."},{"field":"http.version","type":"keyword","normalization":"","example":1.1,"description":"HTTP version."},{"field":"log.file.path","type":"keyword","normalization":"","example":"/var/log/fun-times.log","description":"Full path to the log file this event came from."},{"field":"log.level","type":"keyword","normalization":"","example":"error","description":"Log level of the log event."},{"field":"log.logger","type":"keyword","normalization":"","example":"org.elasticsearch.bootstrap.Bootstrap","description":"Name of the logger."},{"field":"log.origin.file.line","type":"long","normalization":"","example":42,"description":"The line number of the file which originated the log event."},{"field":"log.origin.file.name","type":"keyword","normalization":"","example":"Bootstrap.java","description":"The code file which originated the log event."},{"field":"log.origin.function","type":"keyword","normalization":"","example":"init","description":"The function which originated the log event."},{"field":"log.syslog","type":"object","normalization":"","example":"","description":"Syslog metadata"},{"field":"log.syslog.appname","type":"keyword","normalization":"","example":"sshd","description":"The device or application that originated the Syslog message."},{"field":"log.syslog.facility.code","type":"long","normalization":"","example":23,"description":"Syslog numeric facility of the event."},{"field":"log.syslog.facility.name","type":"keyword","normalization":"","example":"local7","description":"Syslog text-based facility of the event."},{"field":"log.syslog.hostname","type":"keyword","normalization":"","example":"example-host","description":"The host that originated the Syslog message."},{"field":"log.syslog.msgid","type":"keyword","normalization":"","example":"ID47","description":"An identifier for the type of Syslog message."},{"field":"log.syslog.priority","type":"long","normalization":"","example":135,"description":"Syslog priority of the event."},{"field":"log.syslog.procid","type":"keyword","normalization":"","example":12345,"description":"The process name or ID that originated the Syslog message."},{"field":"log.syslog.severity.code","type":"long","normalization":"","example":3,"description":"Syslog numeric severity of the event."},{"field":"log.syslog.severity.name","type":"keyword","normalization":"","example":"Error","description":"Syslog text-based severity of the event."},{"field":"log.syslog.structured_data","type":"flattened","normalization":"","example":"","description":"Structured data expressed in RFC 5424 messages."},{"field":"log.syslog.version","type":"keyword","normalization":"","example":1,"description":"Syslog protocol version."},{"field":"network.application","type":"keyword","normalization":"","example":"aim","description":"Application level protocol name."},{"field":"network.bytes","type":"long","normalization":"","example":368,"description":"Total bytes transferred in both directions."},{"field":"network.community_id","type":"keyword","normalization":"","example":"1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=","description":"A hash of source and destination IPs and ports."},{"field":"network.direction","type":"keyword","normalization":"","example":"inbound","description":"Direction of the network traffic."},{"field":"network.forwarded_ip","type":"ip","normalization":"","example":"192.1.1.2","description":"Host IP address when the source IP address is the proxy."},{"field":"network.iana_number","type":"keyword","normalization":"","example":6,"description":"IANA Protocol Number."},{"field":"network.inner","type":"object","normalization":"","example":"","description":"Inner VLAN tag information"},{"field":"network.inner.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"network.inner.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"network.name","type":"keyword","normalization":"","example":"Guest Wifi","description":"Name given by operators to sections of their network."},{"field":"network.packets","type":"long","normalization":"","example":24,"description":"Total packets transferred in both directions."},{"field":"network.protocol","type":"keyword","normalization":"","example":"http","description":"Application protocol name."},{"field":"network.transport","type":"keyword","normalization":"","example":"tcp","description":"Protocol Name corresponding to the field `iana_number`."},{"field":"network.type","type":"keyword","normalization":"","example":"ipv4","description":"In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc"},{"field":"network.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"network.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.egress","type":"object","normalization":"","example":"","description":"Object field for egress information"},{"field":"observer.egress.interface.alias","type":"keyword","normalization":"","example":"outside","description":"Interface alias"},{"field":"observer.egress.interface.id","type":"keyword","normalization":"","example":10,"description":"Interface ID"},{"field":"observer.egress.interface.name","type":"keyword","normalization":"","example":"eth0","description":"Interface name"},{"field":"observer.egress.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"observer.egress.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.egress.zone","type":"keyword","normalization":"","example":"Public_Internet","description":"Observer Egress zone"},{"field":"observer.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"observer.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"observer.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"observer.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"observer.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"observer.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"observer.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"observer.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"observer.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"observer.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"observer.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"observer.hostname","type":"keyword","normalization":"","example":"","description":"Hostname of the observer."},{"field":"observer.ingress","type":"object","normalization":"","example":"","description":"Object field for ingress information"},{"field":"observer.ingress.interface.alias","type":"keyword","normalization":"","example":"outside","description":"Interface alias"},{"field":"observer.ingress.interface.id","type":"keyword","normalization":"","example":10,"description":"Interface ID"},{"field":"observer.ingress.interface.name","type":"keyword","normalization":"","example":"eth0","description":"Interface name"},{"field":"observer.ingress.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"observer.ingress.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.ingress.zone","type":"keyword","normalization":"","example":"DMZ","description":"Observer ingress zone"},{"field":"observer.ip","type":"ip","normalization":"array","example":"","description":"IP addresses of the observer."},{"field":"observer.mac","type":"keyword","normalization":"array","example":["00-00-5E-00-53-23","00-00-5E-00-53-24"],"description":"MAC addresses of the observer."},{"field":"observer.name","type":"keyword","normalization":"","example":"1_proxySG","description":"Custom name of the observer."},{"field":"observer.os.family","type":"keyword","normalization":"","example":"debian","description":"OS family (such as redhat, debian, freebsd, windows)."},{"field":"observer.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"observer.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"observer.os.kernel","type":"keyword","normalization":"","example":"4.4.0-112-generic","description":"Operating system kernel version as a raw string."},{"field":"observer.os.name","type":"keyword","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"observer.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"observer.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"observer.os.type","type":"keyword","normalization":"","example":"macos","description":"Which commercial OS family (one of: linux, macos, unix, windows, ios or android)."},{"field":"observer.os.version","type":"keyword","normalization":"","example":"10.14.1","description":"Operating system version as a raw string."},{"field":"observer.product","type":"keyword","normalization":"","example":"s200","description":"The product name of the observer."},{"field":"observer.serial_number","type":"keyword","normalization":"","example":"","description":"Observer serial number."},{"field":"observer.type","type":"keyword","normalization":"","example":"firewall","description":"The type of the observer the data is coming from."},{"field":"observer.vendor","type":"keyword","normalization":"","example":"Symantec","description":"Vendor name of the observer."},{"field":"observer.version","type":"keyword","normalization":"","example":"","description":"Observer version."},{"field":"orchestrator.api_version","type":"keyword","normalization":"","example":"v1beta1","description":"API version being used to carry out the action"},{"field":"orchestrator.cluster.id","type":"keyword","normalization":"","example":"","description":"Unique ID of the cluster."},{"field":"orchestrator.cluster.name","type":"keyword","normalization":"","example":"","description":"Name of the cluster."},{"field":"orchestrator.cluster.url","type":"keyword","normalization":"","example":"","description":"URL of the API used to manage the cluster."},{"field":"orchestrator.cluster.version","type":"keyword","normalization":"","example":"","description":"The version of the cluster."},{"field":"orchestrator.namespace","type":"keyword","normalization":"","example":"kube-system","description":"Namespace in which the action is taking place."},{"field":"orchestrator.organization","type":"keyword","normalization":"","example":"elastic","description":"Organization affected by the event (for multi-tenant orchestrator setups)."},{"field":"orchestrator.resource.annotation","type":"keyword","normalization":"array","example":"['key1:value1', 'key2:value2', 'key3:value3']","description":"The list of annotations added to the resource."},{"field":"orchestrator.resource.id","type":"keyword","normalization":"","example":"","description":"Unique ID of the resource being acted upon."},{"field":"orchestrator.resource.ip","type":"ip","normalization":"array","example":"","description":"IP address assigned to the resource associated with the event being observed."},{"field":"orchestrator.resource.label","type":"keyword","normalization":"array","example":"['key1:value1', 'key2:value2', 'key3:value3']","description":"The list of labels added to the resource."},{"field":"orchestrator.resource.name","type":"keyword","normalization":"","example":"test-pod-cdcws","description":"Name of the resource being acted upon."},{"field":"orchestrator.resource.parent.type","type":"keyword","normalization":"","example":"DaemonSet","description":"Type or kind of the parent resource associated with the event being observed."},{"field":"orchestrator.resource.type","type":"keyword","normalization":"","example":"service","description":"Type of resource being acted upon."},{"field":"orchestrator.type","type":"keyword","normalization":"","example":"kubernetes","description":"Orchestrator cluster type (e.g. kubernetes, nomad or cloudfoundry)."},{"field":"organization.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the organization."},{"field":"organization.name","type":"keyword","normalization":"","example":"","description":"Organization name."},{"field":"organization.name.text","type":"match_only_text","normalization":"","example":"","description":"Organization name."},{"field":"package.architecture","type":"keyword","normalization":"","example":"x86_64","description":"Package architecture."},{"field":"package.build_version","type":"keyword","normalization":"","example":"36f4f7e89dd61b0988b12ee000b98966867710cd","description":"Build version information"},{"field":"package.checksum","type":"keyword","normalization":"","example":"68b329da9893e34099c7d8ad5cb9c940","description":"Checksum of the installed package for verification."},{"field":"package.description","type":"keyword","normalization":"","example":"Open source programming language to build simple/reliable/efficient software.","description":"Description of the package."},{"field":"package.install_scope","type":"keyword","normalization":"","example":"global","description":"Indicating how the package was installed, e.g. user-local, global."},{"field":"package.installed","type":"date","normalization":"","example":"","description":"Time when package was installed."},{"field":"package.license","type":"keyword","normalization":"","example":"Apache License 2.0","description":"Package license"},{"field":"package.name","type":"keyword","normalization":"","example":"go","description":"Package name"},{"field":"package.path","type":"keyword","normalization":"","example":"/usr/local/Cellar/go/1.12.9/","description":"Path where the package is installed."},{"field":"package.reference","type":"keyword","normalization":"","example":"https://golang.org","description":"Package home page or reference URL"},{"field":"package.size","type":"long","normalization":"","example":62231,"description":"Package size in bytes."},{"field":"package.type","type":"keyword","normalization":"","example":"rpm","description":"Package type"},{"field":"package.version","type":"keyword","normalization":"","example":"1.12.9","description":"Package version"},{"field":"process.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"process.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"process.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"process.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"process.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"process.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"process.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"process.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"process.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"process.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"process.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"process.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"process.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"process.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"process.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"process.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"process.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"process.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"process.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"process.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"process.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"process.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"process.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"process.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"process.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"process.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"process.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"process.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"process.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"process.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"process.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"process.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"process.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"process.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"process.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"process.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"process.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"process.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"process.end","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process ended."},{"field":"process.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.entry_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.entry_leader.attested_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.attested_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.attested_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.attested_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.entry_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.entry_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.entry_meta.source.ip","type":"ip","normalization":"","example":"","description":"IP address of the source."},{"field":"process.entry_leader.entry_meta.type","type":"keyword","normalization":"","example":"","description":"The entry type for the entry session leader."},{"field":"process.entry_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.entry_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.entry_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.entry_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.entry_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.entry_leader.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.parent.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.parent.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.parent.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.parent.session_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.entry_leader.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.parent.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.entry_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.entry_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.entry_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.entry_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.entry_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.entry_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.entry_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.env_vars","type":"keyword","normalization":"array","example":["PATH=/usr/local/bin:/usr/bin","USER=ubuntu"],"description":"Array of environment variable bindings."},{"field":"process.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.exit_code","type":"long","normalization":"","example":137,"description":"The exit code of the process."},{"field":"process.group_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.group_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.group_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.group_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.group_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.group_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.group_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.group_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.group_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.group_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.group_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.group_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.group_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.group_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.group_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.group_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.group_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.group_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.group_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"process.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"process.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"process.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"process.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"process.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"process.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"process.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.io","type":"object","normalization":"","example":"","description":"A chunk of input or output (IO) from a single process."},{"field":"process.io.bytes_skipped","type":"object","normalization":"array","example":"","description":"An array of byte offsets and lengths denoting where IO data has been skipped."},{"field":"process.io.bytes_skipped.length","type":"long","normalization":"","example":"","description":"The length of bytes skipped."},{"field":"process.io.bytes_skipped.offset","type":"long","normalization":"","example":"","description":"The byte offset into this event's io.text (or io.bytes in the future) where length bytes were skipped."},{"field":"process.io.max_bytes_per_process_exceeded","type":"boolean","normalization":"","example":"","description":"If true, the process producing the output has exceeded the max_kilobytes_per_process configuration setting."},{"field":"process.io.text","type":"wildcard","normalization":"","example":"","description":"A chunk of output or input sanitized to UTF-8."},{"field":"process.io.total_bytes_captured","type":"long","normalization":"","example":"","description":"The total number of bytes captured in this event."},{"field":"process.io.total_bytes_skipped","type":"long","normalization":"","example":"","description":"The total number of bytes that were not captured due to implementation restrictions such as buffer size limits."},{"field":"process.io.type","type":"keyword","normalization":"","example":"","description":"The type of object on which the IO action (read or write) was taken."},{"field":"process.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"process.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"process.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"process.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"process.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"process.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"process.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"process.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.parent.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.parent.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"process.parent.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"process.parent.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"process.parent.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"process.parent.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"process.parent.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"process.parent.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"process.parent.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"process.parent.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"process.parent.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.parent.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.parent.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"process.parent.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"process.parent.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"process.parent.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"process.parent.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"process.parent.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"process.parent.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"process.parent.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"process.parent.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"process.parent.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"process.parent.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"process.parent.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"process.parent.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"process.parent.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"process.parent.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"process.parent.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"process.parent.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"process.parent.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"process.parent.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"process.parent.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"process.parent.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"process.parent.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"process.parent.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"process.parent.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"process.parent.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"process.parent.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"process.parent.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"process.parent.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"process.parent.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"process.parent.end","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process ended."},{"field":"process.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.parent.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.parent.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.parent.exit_code","type":"long","normalization":"","example":137,"description":"The exit code of the process."},{"field":"process.parent.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.group_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.parent.group_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.parent.group_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.parent.group_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.parent.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"process.parent.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"process.parent.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"process.parent.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"process.parent.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"process.parent.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"process.parent.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"process.parent.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.parent.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"process.parent.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"process.parent.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"process.parent.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"process.parent.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"process.parent.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"process.parent.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"process.parent.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"process.parent.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"process.parent.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"process.parent.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"process.parent.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"process.parent.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"process.parent.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"process.parent.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"process.parent.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"process.parent.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"process.parent.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"process.parent.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"process.parent.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"process.parent.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"process.parent.pgid","type":"long","normalization":"","example":"","description":"Deprecated identifier of the group of processes the process belongs to."},{"field":"process.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.parent.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.parent.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.thread.capabilities.effective","type":"keyword","normalization":"array","example":["CAP_BPF","CAP_SYS_ADMIN"],"description":"Array of capabilities used for permission checks."},{"field":"process.parent.thread.capabilities.permitted","type":"keyword","normalization":"array","example":["CAP_BPF","CAP_SYS_ADMIN"],"description":"Array of capabilities a thread could assume."},{"field":"process.parent.thread.id","type":"long","normalization":"","example":4242,"description":"Thread ID."},{"field":"process.parent.thread.name","type":"keyword","normalization":"","example":"thread-0","description":"Thread name."},{"field":"process.parent.title","type":"keyword","normalization":"","example":"","description":"Process title."},{"field":"process.parent.title.text","type":"match_only_text","normalization":"","example":"","description":"Process title."},{"field":"process.parent.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.parent.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.parent.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.parent.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the process has been up."},{"field":"process.parent.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.parent.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.parent.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"process.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"process.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"process.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"process.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"process.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"process.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"process.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"process.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"process.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"process.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"process.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"process.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"process.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"process.pgid","type":"long","normalization":"","example":"","description":"Deprecated identifier of the group of processes the process belongs to."},{"field":"process.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.previous.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.previous.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.previous.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.previous.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.session_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.session_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.session_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.session_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.session_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.session_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.session_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.session_leader.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.parent.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.parent.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.parent.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.parent.session_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.session_leader.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.parent.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.session_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.session_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.session_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.session_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.session_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.session_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.thread.capabilities.effective","type":"keyword","normalization":"array","example":["CAP_BPF","CAP_SYS_ADMIN"],"description":"Array of capabilities used for permission checks."},{"field":"process.thread.capabilities.permitted","type":"keyword","normalization":"array","example":["CAP_BPF","CAP_SYS_ADMIN"],"description":"Array of capabilities a thread could assume."},{"field":"process.thread.id","type":"long","normalization":"","example":4242,"description":"Thread ID."},{"field":"process.thread.name","type":"keyword","normalization":"","example":"thread-0","description":"Thread name."},{"field":"process.title","type":"keyword","normalization":"","example":"","description":"Process title."},{"field":"process.title.text","type":"match_only_text","normalization":"","example":"","description":"Process title."},{"field":"process.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.tty.columns","type":"long","normalization":"","example":80,"description":"The number of character columns per line. e.g terminal width"},{"field":"process.tty.rows","type":"long","normalization":"","example":24,"description":"The number of character rows in the terminal. e.g terminal height"},{"field":"process.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the process has been up."},{"field":"process.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.vpid","type":"long","normalization":"","example":4242,"description":"Virtual process id."},{"field":"process.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"related.hash","type":"keyword","normalization":"array","example":"","description":"All the hashes seen on your event."},{"field":"related.hosts","type":"keyword","normalization":"array","example":"","description":"All the host identifiers seen on your event."},{"field":"related.ip","type":"ip","normalization":"array","example":"","description":"All of the IPs seen on your event."},{"field":"related.user","type":"keyword","normalization":"array","example":"","description":"All the user names or other user identifiers seen on the event."},{"field":"rule.author","type":"keyword","normalization":"array","example":["Star-Lord"],"description":"Rule author"},{"field":"rule.category","type":"keyword","normalization":"","example":"Attempted Information Leak","description":"Rule category"},{"field":"rule.description","type":"keyword","normalization":"","example":"Block requests to public DNS over HTTPS / TLS protocols","description":"Rule description"},{"field":"rule.id","type":"keyword","normalization":"","example":101,"description":"Rule ID"},{"field":"rule.license","type":"keyword","normalization":"","example":"Apache 2.0","description":"Rule license"},{"field":"rule.name","type":"keyword","normalization":"","example":"BLOCK_DNS_over_TLS","description":"Rule name"},{"field":"rule.reference","type":"keyword","normalization":"","example":"https://en.wikipedia.org/wiki/DNS_over_TLS","description":"Rule reference URL"},{"field":"rule.ruleset","type":"keyword","normalization":"","example":"Standard_Protocol_Filters","description":"Rule ruleset"},{"field":"rule.uuid","type":"keyword","normalization":"","example":1100110011,"description":"Rule UUID"},{"field":"rule.version","type":"keyword","normalization":"","example":1.1,"description":"Rule version"},{"field":"server.address","type":"keyword","normalization":"","example":"","description":"Server network address."},{"field":"server.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"server.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"server.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"server.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the server to the client."},{"field":"server.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the server."},{"field":"server.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"server.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"server.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"server.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"server.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"server.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"server.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"server.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"server.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"server.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"server.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"server.ip","type":"ip","normalization":"","example":"","description":"IP address of the server."},{"field":"server.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the server."},{"field":"server.nat.ip","type":"ip","normalization":"","example":"","description":"Server NAT ip"},{"field":"server.nat.port","type":"long","normalization":"","example":"","description":"Server NAT port"},{"field":"server.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the server to the client."},{"field":"server.port","type":"long","normalization":"","example":"","description":"Port of the server."},{"field":"server.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered server domain, stripped of the subdomain."},{"field":"server.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"server.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"server.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"server.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"server.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"server.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"server.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"server.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"server.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"server.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"server.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"server.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"server.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"server.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"service.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.origin.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.origin.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.origin.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.origin.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.origin.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.origin.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.origin.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.origin.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.origin.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.origin.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.origin.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"service.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.target.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.target.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.target.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.target.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.target.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.target.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.target.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.target.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.target.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.target.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.target.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"service.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"source.address","type":"keyword","normalization":"","example":"","description":"Source network address."},{"field":"source.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"source.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"source.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"source.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the source to the destination."},{"field":"source.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the source."},{"field":"source.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"source.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"source.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"source.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"source.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"source.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"source.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"source.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"source.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"source.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"source.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"source.ip","type":"ip","normalization":"","example":"","description":"IP address of the source."},{"field":"source.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the source."},{"field":"source.nat.ip","type":"ip","normalization":"","example":"","description":"Source NAT ip"},{"field":"source.nat.port","type":"long","normalization":"","example":"","description":"Source NAT port"},{"field":"source.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the source to the destination."},{"field":"source.port","type":"long","normalization":"","example":"","description":"Port of the source."},{"field":"source.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered source domain, stripped of the subdomain."},{"field":"source.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"source.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"source.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"source.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"source.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"source.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"source.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"source.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"source.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"source.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"source.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"source.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"source.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"source.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"span.id","type":"keyword","normalization":"","example":"3ff9a8981b7ccd5a","description":"Unique identifier of the span within the scope of its trace."},{"field":"threat.enrichments","type":"nested","normalization":"array","example":"","description":"List of objects containing indicators enriching the event."},{"field":"threat.enrichments.indicator","type":"object","normalization":"","example":"","description":"Object containing indicators enriching the event."},{"field":"threat.enrichments.indicator.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"threat.enrichments.indicator.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.enrichments.indicator.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.enrichments.indicator.confidence","type":"keyword","normalization":"","example":"Medium","description":"Indicator confidence rating"},{"field":"threat.enrichments.indicator.description","type":"keyword","normalization":"","example":"IP x.x.x.x was observed delivering the Angler EK.","description":"Indicator description"},{"field":"threat.enrichments.indicator.email.address","type":"keyword","normalization":"","example":"phish@example.com","description":"Indicator email address"},{"field":"threat.enrichments.indicator.file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"threat.enrichments.indicator.file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"threat.enrichments.indicator.file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"threat.enrichments.indicator.file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"threat.enrichments.indicator.file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"threat.enrichments.indicator.file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"threat.enrichments.indicator.file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"threat.enrichments.indicator.file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"threat.enrichments.indicator.file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"threat.enrichments.indicator.file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"threat.enrichments.indicator.file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"threat.enrichments.indicator.file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"threat.enrichments.indicator.file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"threat.enrichments.indicator.file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"threat.enrichments.indicator.file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"threat.enrichments.indicator.file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"threat.enrichments.indicator.file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"threat.enrichments.indicator.file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.enrichments.indicator.file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.enrichments.indicator.file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"threat.enrichments.indicator.file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"threat.enrichments.indicator.file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"threat.enrichments.indicator.file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"threat.enrichments.indicator.file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"threat.enrichments.indicator.file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"threat.enrichments.indicator.file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"threat.enrichments.indicator.file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"threat.enrichments.indicator.file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"threat.enrichments.indicator.file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"threat.enrichments.indicator.file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"threat.enrichments.indicator.file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"threat.enrichments.indicator.file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"threat.enrichments.indicator.file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"threat.enrichments.indicator.file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"threat.enrichments.indicator.file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"threat.enrichments.indicator.file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"threat.enrichments.indicator.file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"threat.enrichments.indicator.file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"threat.enrichments.indicator.file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"threat.enrichments.indicator.file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"threat.enrichments.indicator.file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"threat.enrichments.indicator.file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"threat.enrichments.indicator.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"threat.enrichments.indicator.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"threat.enrichments.indicator.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"threat.enrichments.indicator.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"threat.enrichments.indicator.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"threat.enrichments.indicator.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"threat.enrichments.indicator.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"threat.enrichments.indicator.file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"threat.enrichments.indicator.file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"threat.enrichments.indicator.file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"threat.enrichments.indicator.file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"threat.enrichments.indicator.file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"threat.enrichments.indicator.file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"threat.enrichments.indicator.file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.enrichments.indicator.file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.enrichments.indicator.file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"threat.enrichments.indicator.file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"threat.enrichments.indicator.file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.enrichments.indicator.file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.enrichments.indicator.file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"threat.enrichments.indicator.file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"threat.enrichments.indicator.file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"threat.enrichments.indicator.file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"threat.enrichments.indicator.file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"threat.enrichments.indicator.file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"threat.enrichments.indicator.file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.enrichments.indicator.file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.enrichments.indicator.file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"threat.enrichments.indicator.file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"threat.enrichments.indicator.file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.enrichments.indicator.file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.enrichments.indicator.file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.enrichments.indicator.file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.enrichments.indicator.file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.enrichments.indicator.file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.enrichments.indicator.file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.enrichments.indicator.file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.enrichments.indicator.file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.enrichments.indicator.file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.enrichments.indicator.file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.enrichments.indicator.file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.enrichments.indicator.file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.enrichments.indicator.first_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was first reported."},{"field":"threat.enrichments.indicator.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"threat.enrichments.indicator.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"threat.enrichments.indicator.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"threat.enrichments.indicator.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"threat.enrichments.indicator.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"threat.enrichments.indicator.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"threat.enrichments.indicator.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"threat.enrichments.indicator.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"threat.enrichments.indicator.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"threat.enrichments.indicator.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"threat.enrichments.indicator.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"threat.enrichments.indicator.ip","type":"ip","normalization":"","example":"1.2.3.4","description":"Indicator IP address"},{"field":"threat.enrichments.indicator.last_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last reported."},{"field":"threat.enrichments.indicator.marking.tlp","type":"keyword","normalization":"","example":"CLEAR","description":"Indicator TLP marking"},{"field":"threat.enrichments.indicator.marking.tlp_version","type":"keyword","normalization":"","example":2,"description":"Indicator TLP version"},{"field":"threat.enrichments.indicator.modified_at","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last updated."},{"field":"threat.enrichments.indicator.name","type":"keyword","normalization":"","example":"5.2.75.227","description":"Indicator display name"},{"field":"threat.enrichments.indicator.port","type":"long","normalization":"","example":443,"description":"Indicator port"},{"field":"threat.enrichments.indicator.provider","type":"keyword","normalization":"","example":"lrz_urlhaus","description":"Indicator provider"},{"field":"threat.enrichments.indicator.reference","type":"keyword","normalization":"","example":"https://system.example.com/indicator/0001234","description":"Indicator reference URL"},{"field":"threat.enrichments.indicator.registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"threat.enrichments.indicator.registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"threat.enrichments.indicator.registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"threat.enrichments.indicator.registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"threat.enrichments.indicator.registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"threat.enrichments.indicator.registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"threat.enrichments.indicator.registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"threat.enrichments.indicator.scanner_stats","type":"long","normalization":"","example":4,"description":"Scanner statistics"},{"field":"threat.enrichments.indicator.sightings","type":"long","normalization":"","example":20,"description":"Number of times indicator observed"},{"field":"threat.enrichments.indicator.type","type":"keyword","normalization":"","example":"ipv4-addr","description":"Type of indicator"},{"field":"threat.enrichments.indicator.url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"threat.enrichments.indicator.url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"threat.enrichments.indicator.url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"threat.enrichments.indicator.url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.enrichments.indicator.url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.enrichments.indicator.url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.enrichments.indicator.url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.enrichments.indicator.url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"threat.enrichments.indicator.url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"threat.enrichments.indicator.url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"threat.enrichments.indicator.url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"threat.enrichments.indicator.url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"threat.enrichments.indicator.url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"threat.enrichments.indicator.url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"threat.enrichments.indicator.url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"threat.enrichments.indicator.url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"threat.enrichments.indicator.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.enrichments.indicator.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.enrichments.indicator.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.enrichments.indicator.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.enrichments.indicator.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.enrichments.indicator.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.enrichments.indicator.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.enrichments.indicator.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.enrichments.indicator.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.enrichments.indicator.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.enrichments.indicator.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.enrichments.indicator.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.enrichments.indicator.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.enrichments.indicator.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.enrichments.indicator.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.enrichments.indicator.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.enrichments.matched.atomic","type":"keyword","normalization":"","example":"bad-domain.com","description":"Matched indicator value"},{"field":"threat.enrichments.matched.field","type":"keyword","normalization":"","example":"file.hash.sha256","description":"Matched indicator field"},{"field":"threat.enrichments.matched.id","type":"keyword","normalization":"","example":"ff93aee5-86a1-4a61-b0e6-0cdc313d01b5","description":"Matched indicator identifier"},{"field":"threat.enrichments.matched.index","type":"keyword","normalization":"","example":"filebeat-8.0.0-2021.05.23-000011","description":"Matched indicator index"},{"field":"threat.enrichments.matched.occurred","type":"date","normalization":"","example":"2021-10-05T17:00:58.326Z","description":"Date of match"},{"field":"threat.enrichments.matched.type","type":"keyword","normalization":"","example":"indicator_match_rule","description":"Type of indicator match"},{"field":"threat.feed.dashboard_id","type":"keyword","normalization":"","example":"5ba16340-72e6-11eb-a3e3-b3cc7c78a70f","description":"Feed dashboard ID."},{"field":"threat.feed.description","type":"keyword","normalization":"","example":"Threat feed from the AlienVault Open Threat eXchange network.","description":"Description of the threat feed."},{"field":"threat.feed.name","type":"keyword","normalization":"","example":"AlienVault OTX","description":"Name of the threat feed."},{"field":"threat.feed.reference","type":"keyword","normalization":"","example":"https://otx.alienvault.com","description":"Reference for the threat feed."},{"field":"threat.framework","type":"keyword","normalization":"","example":"MITRE ATT&CK","description":"Threat classification framework."},{"field":"threat.group.alias","type":"keyword","normalization":"array","example":["Magecart Group 6"],"description":"Alias of the group."},{"field":"threat.group.id","type":"keyword","normalization":"","example":"G0037","description":"ID of the group."},{"field":"threat.group.name","type":"keyword","normalization":"","example":"FIN6","description":"Name of the group."},{"field":"threat.group.reference","type":"keyword","normalization":"","example":"https://attack.mitre.org/groups/G0037/","description":"Reference URL of the group."},{"field":"threat.indicator.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"threat.indicator.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.indicator.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.indicator.confidence","type":"keyword","normalization":"","example":"Medium","description":"Indicator confidence rating"},{"field":"threat.indicator.description","type":"keyword","normalization":"","example":"IP x.x.x.x was observed delivering the Angler EK.","description":"Indicator description"},{"field":"threat.indicator.email.address","type":"keyword","normalization":"","example":"phish@example.com","description":"Indicator email address"},{"field":"threat.indicator.file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"threat.indicator.file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"threat.indicator.file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"threat.indicator.file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"threat.indicator.file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"threat.indicator.file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"threat.indicator.file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"threat.indicator.file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"threat.indicator.file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"threat.indicator.file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"threat.indicator.file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"threat.indicator.file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"threat.indicator.file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"threat.indicator.file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"threat.indicator.file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"threat.indicator.file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"threat.indicator.file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"threat.indicator.file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"threat.indicator.file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"threat.indicator.file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"threat.indicator.file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"threat.indicator.file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"threat.indicator.file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.indicator.file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.indicator.file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"threat.indicator.file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"threat.indicator.file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"threat.indicator.file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"threat.indicator.file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"threat.indicator.file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"threat.indicator.file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"threat.indicator.file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"threat.indicator.file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"threat.indicator.file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.indicator.file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"threat.indicator.file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"threat.indicator.file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.indicator.file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"threat.indicator.file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"threat.indicator.file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"threat.indicator.file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"threat.indicator.file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"threat.indicator.file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.indicator.file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"threat.indicator.file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"threat.indicator.file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"threat.indicator.file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"threat.indicator.file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"threat.indicator.file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"threat.indicator.file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"threat.indicator.file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"threat.indicator.file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"threat.indicator.file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"threat.indicator.file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"threat.indicator.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"threat.indicator.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"threat.indicator.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"threat.indicator.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"threat.indicator.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"threat.indicator.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"threat.indicator.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"threat.indicator.file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"threat.indicator.file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"threat.indicator.file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"threat.indicator.file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"threat.indicator.file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"threat.indicator.file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"threat.indicator.file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.indicator.file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.indicator.file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"threat.indicator.file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"threat.indicator.file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"threat.indicator.file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.indicator.file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.indicator.file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"threat.indicator.file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"threat.indicator.file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.indicator.file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"threat.indicator.file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"threat.indicator.file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.indicator.file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"threat.indicator.file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"threat.indicator.file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.indicator.file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"threat.indicator.file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"threat.indicator.file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.indicator.file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.indicator.file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"threat.indicator.file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"threat.indicator.file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.indicator.file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.indicator.file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.indicator.file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.indicator.file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.indicator.file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.indicator.file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.indicator.file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.indicator.file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.indicator.file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.indicator.file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.indicator.file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.indicator.file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.indicator.file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.indicator.file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.indicator.file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.indicator.file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.indicator.file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.indicator.first_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was first reported."},{"field":"threat.indicator.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"threat.indicator.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"threat.indicator.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"threat.indicator.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"threat.indicator.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"threat.indicator.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"threat.indicator.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"threat.indicator.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"threat.indicator.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"threat.indicator.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"threat.indicator.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"threat.indicator.ip","type":"ip","normalization":"","example":"1.2.3.4","description":"Indicator IP address"},{"field":"threat.indicator.last_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last reported."},{"field":"threat.indicator.marking.tlp","type":"keyword","normalization":"","example":"CLEAR","description":"Indicator TLP marking"},{"field":"threat.indicator.marking.tlp_version","type":"keyword","normalization":"","example":2,"description":"Indicator TLP version"},{"field":"threat.indicator.modified_at","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last updated."},{"field":"threat.indicator.name","type":"keyword","normalization":"","example":"5.2.75.227","description":"Indicator display name"},{"field":"threat.indicator.port","type":"long","normalization":"","example":443,"description":"Indicator port"},{"field":"threat.indicator.provider","type":"keyword","normalization":"","example":"lrz_urlhaus","description":"Indicator provider"},{"field":"threat.indicator.reference","type":"keyword","normalization":"","example":"https://system.example.com/indicator/0001234","description":"Indicator reference URL"},{"field":"threat.indicator.registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"threat.indicator.registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"threat.indicator.registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"threat.indicator.registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"threat.indicator.registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"threat.indicator.registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"threat.indicator.registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"threat.indicator.scanner_stats","type":"long","normalization":"","example":4,"description":"Scanner statistics"},{"field":"threat.indicator.sightings","type":"long","normalization":"","example":20,"description":"Number of times indicator observed"},{"field":"threat.indicator.type","type":"keyword","normalization":"","example":"ipv4-addr","description":"Type of indicator"},{"field":"threat.indicator.url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"threat.indicator.url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"threat.indicator.url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"threat.indicator.url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.indicator.url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.indicator.url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.indicator.url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.indicator.url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"threat.indicator.url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"threat.indicator.url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"threat.indicator.url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"threat.indicator.url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"threat.indicator.url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"threat.indicator.url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"threat.indicator.url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"threat.indicator.url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"threat.indicator.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.indicator.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.indicator.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.indicator.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.indicator.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.indicator.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.indicator.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.indicator.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.indicator.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.indicator.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.indicator.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.indicator.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.indicator.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.indicator.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.indicator.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.indicator.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.indicator.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.indicator.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.software.alias","type":"keyword","normalization":"array","example":["X-Agent"],"description":"Alias of the software"},{"field":"threat.software.id","type":"keyword","normalization":"","example":"S0552","description":"ID of the software"},{"field":"threat.software.name","type":"keyword","normalization":"","example":"AdFind","description":"Name of the software."},{"field":"threat.software.platforms","type":"keyword","normalization":"array","example":["Windows"],"description":"Platforms of the software."},{"field":"threat.software.reference","type":"keyword","normalization":"","example":"https://attack.mitre.org/software/S0552/","description":"Software reference URL."},{"field":"threat.software.type","type":"keyword","normalization":"","example":"Tool","description":"Software type."},{"field":"threat.tactic.id","type":"keyword","normalization":"array","example":"TA0002","description":"Threat tactic id."},{"field":"threat.tactic.name","type":"keyword","normalization":"array","example":"Execution","description":"Threat tactic."},{"field":"threat.tactic.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/tactics/TA0002/","description":"Threat tactic URL reference."},{"field":"threat.technique.id","type":"keyword","normalization":"array","example":"T1059","description":"Threat technique id."},{"field":"threat.technique.name","type":"keyword","normalization":"array","example":"Command and Scripting Interpreter","description":"Threat technique name."},{"field":"threat.technique.name.text","type":"match_only_text","normalization":"","example":"Command and Scripting Interpreter","description":"Threat technique name."},{"field":"threat.technique.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/techniques/T1059/","description":"Threat technique URL reference."},{"field":"threat.technique.subtechnique.id","type":"keyword","normalization":"array","example":"T1059.001","description":"Threat subtechnique id."},{"field":"threat.technique.subtechnique.name","type":"keyword","normalization":"array","example":"PowerShell","description":"Threat subtechnique name."},{"field":"threat.technique.subtechnique.name.text","type":"match_only_text","normalization":"","example":"PowerShell","description":"Threat subtechnique name."},{"field":"threat.technique.subtechnique.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/techniques/T1059/001/","description":"Threat subtechnique URL reference."},{"field":"tls.cipher","type":"keyword","normalization":"","example":"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","description":"String indicating the cipher used during the current connection."},{"field":"tls.client.certificate","type":"keyword","normalization":"","example":"MII...","description":"PEM-encoded stand-alone certificate offered by the client."},{"field":"tls.client.certificate_chain","type":"keyword","normalization":"array","example":["MII...","MII..."],"description":"Array of PEM-encoded certificates that make up the certificate chain offered by the client."},{"field":"tls.client.hash.md5","type":"keyword","normalization":"","example":"0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC","description":"Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.hash.sha1","type":"keyword","normalization":"","example":"9E393D93138888D288266C2D915214D1D1CCEB2A","description":"Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.hash.sha256","type":"keyword","normalization":"","example":"0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0","description":"Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.issuer","type":"keyword","normalization":"","example":"CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com","description":"Distinguished name of subject of the issuer of the x.509 certificate presented by the client."},{"field":"tls.client.ja3","type":"keyword","normalization":"","example":"d4e5b18d6b55c71272893221c96ba240","description":"A hash that identifies clients based on how they perform an SSL/TLS handshake."},{"field":"tls.client.not_after","type":"date","normalization":"","example":"2021-01-01T00:00:00.000Z","description":"Date/Time indicating when client certificate is no longer considered valid."},{"field":"tls.client.not_before","type":"date","normalization":"","example":"1970-01-01T00:00:00.000Z","description":"Date/Time indicating when client certificate is first considered valid."},{"field":"tls.client.server_name","type":"keyword","normalization":"","example":"www.elastic.co","description":"Hostname the client is trying to connect to. Also called the SNI."},{"field":"tls.client.subject","type":"keyword","normalization":"","example":"CN=myclient, OU=Documentation Team, DC=example, DC=com","description":"Distinguished name of subject of the x.509 certificate presented by the client."},{"field":"tls.client.supported_ciphers","type":"keyword","normalization":"array","example":["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","..."],"description":"Array of ciphers offered by the client during the client hello."},{"field":"tls.client.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"tls.client.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"tls.client.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"tls.client.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"tls.client.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"tls.client.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"tls.client.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"tls.client.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.client.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"tls.client.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"tls.client.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"tls.client.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"tls.client.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"tls.client.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"tls.client.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"tls.client.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"tls.client.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"tls.client.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"tls.client.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"tls.client.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"tls.client.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"tls.client.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"tls.client.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.client.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"tls.curve","type":"keyword","normalization":"","example":"secp256r1","description":"String indicating the curve used for the given cipher, when applicable."},{"field":"tls.established","type":"boolean","normalization":"","example":"","description":"Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel."},{"field":"tls.next_protocol","type":"keyword","normalization":"","example":"http/1.1","description":"String indicating the protocol being tunneled."},{"field":"tls.resumed","type":"boolean","normalization":"","example":"","description":"Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation."},{"field":"tls.server.certificate","type":"keyword","normalization":"","example":"MII...","description":"PEM-encoded stand-alone certificate offered by the server."},{"field":"tls.server.certificate_chain","type":"keyword","normalization":"array","example":["MII...","MII..."],"description":"Array of PEM-encoded certificates that make up the certificate chain offered by the server."},{"field":"tls.server.hash.md5","type":"keyword","normalization":"","example":"0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC","description":"Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.hash.sha1","type":"keyword","normalization":"","example":"9E393D93138888D288266C2D915214D1D1CCEB2A","description":"Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.hash.sha256","type":"keyword","normalization":"","example":"0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0","description":"Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.issuer","type":"keyword","normalization":"","example":"CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com","description":"Subject of the issuer of the x.509 certificate presented by the server."},{"field":"tls.server.ja3s","type":"keyword","normalization":"","example":"394441ab65754e2207b1e1b457b3641d","description":"A hash that identifies servers based on how they perform an SSL/TLS handshake."},{"field":"tls.server.not_after","type":"date","normalization":"","example":"2021-01-01T00:00:00.000Z","description":"Timestamp indicating when server certificate is no longer considered valid."},{"field":"tls.server.not_before","type":"date","normalization":"","example":"1970-01-01T00:00:00.000Z","description":"Timestamp indicating when server certificate is first considered valid."},{"field":"tls.server.subject","type":"keyword","normalization":"","example":"CN=www.example.com, OU=Infrastructure Team, DC=example, DC=com","description":"Subject of the x.509 certificate presented by the server."},{"field":"tls.server.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"tls.server.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"tls.server.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"tls.server.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"tls.server.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"tls.server.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"tls.server.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"tls.server.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.server.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"tls.server.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"tls.server.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"tls.server.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"tls.server.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"tls.server.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"tls.server.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"tls.server.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"tls.server.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"tls.server.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"tls.server.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"tls.server.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"tls.server.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"tls.server.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"tls.server.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.server.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"tls.version","type":"keyword","normalization":"","example":1.2,"description":"Numeric part of the version parsed from the original string."},{"field":"tls.version_protocol","type":"keyword","normalization":"","example":"tls","description":"Normalized lowercase protocol name parsed from original string."},{"field":"trace.id","type":"keyword","normalization":"","example":"4bf92f3577b34da6a3ce929d0e0e4736","description":"Unique identifier of the trace."},{"field":"transaction.id","type":"keyword","normalization":"","example":"00f067aa0ba902b7","description":"Unique identifier of the transaction within the scope of its trace."},{"field":"url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"user.changes.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.changes.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.changes.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.changes.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.changes.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.changes.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.changes.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.changes.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.changes.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.changes.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.changes.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.changes.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.effective.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.effective.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.effective.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.effective.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.effective.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.effective.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.effective.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.effective.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.effective.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.effective.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.effective.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.effective.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.risk.calculated_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"user.risk.calculated_score","type":"float","normalization":"","example":880.73,"description":"A risk classification score calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"user.risk.calculated_score_norm","type":"float","normalization":"","example":88.73,"description":"A normalized risk score calculated by an internal system."},{"field":"user.risk.static_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"user.risk.static_score","type":"float","normalization":"","example":830,"description":"A risk classification score obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"user.risk.static_score_norm","type":"float","normalization":"","example":83,"description":"A normalized risk score calculated by an external system."},{"field":"user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.target.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.target.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.target.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.target.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.target.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.target.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.target.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.target.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.target.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.target.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.target.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.target.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user_agent.device.name","type":"keyword","normalization":"","example":"iPhone","description":"Name of the device."},{"field":"user_agent.name","type":"keyword","normalization":"","example":"Safari","description":"Name of the user agent."},{"field":"user_agent.original","type":"keyword","normalization":"","example":"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1","description":"Unparsed user_agent string."},{"field":"user_agent.original.text","type":"match_only_text","normalization":"","example":"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1","description":"Unparsed user_agent string."},{"field":"user_agent.os.family","type":"keyword","normalization":"","example":"debian","description":"OS family (such as redhat, debian, freebsd, windows)."},{"field":"user_agent.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"user_agent.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"user_agent.os.kernel","type":"keyword","normalization":"","example":"4.4.0-112-generic","description":"Operating system kernel version as a raw string."},{"field":"user_agent.os.name","type":"keyword","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"user_agent.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"user_agent.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"user_agent.os.type","type":"keyword","normalization":"","example":"macos","description":"Which commercial OS family (one of: linux, macos, unix, windows, ios or android)."},{"field":"user_agent.os.version","type":"keyword","normalization":"","example":"10.14.1","description":"Operating system version as a raw string."},{"field":"user_agent.version","type":"keyword","normalization":"","example":12,"description":"Version of the user agent."},{"field":"vulnerability.category","type":"keyword","normalization":"array","example":["Firewall"],"description":"Category of a vulnerability."},{"field":"vulnerability.classification","type":"keyword","normalization":"","example":"CVSS","description":"Classification of the vulnerability."},{"field":"vulnerability.description","type":"keyword","normalization":"","example":"In macOS before 2.12.6, there is a vulnerability in the RPC...","description":"Description of the vulnerability."},{"field":"vulnerability.description.text","type":"match_only_text","normalization":"","example":"In macOS before 2.12.6, there is a vulnerability in the RPC...","description":"Description of the vulnerability."},{"field":"vulnerability.enumeration","type":"keyword","normalization":"","example":"CVE","description":"Identifier of the vulnerability."},{"field":"vulnerability.id","type":"keyword","normalization":"","example":"CVE-2019-00001","description":"ID of the vulnerability."},{"field":"vulnerability.reference","type":"keyword","normalization":"","example":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111","description":"Reference of the vulnerability."},{"field":"vulnerability.report_id","type":"keyword","normalization":"","example":20191018.0001,"description":"Scan identification number."},{"field":"vulnerability.scanner.vendor","type":"keyword","normalization":"","example":"Tenable","description":"Name of the scanner vendor."},{"field":"vulnerability.score.base","type":"float","normalization":"","example":5.5,"description":"Vulnerability Base score."},{"field":"vulnerability.score.environmental","type":"float","normalization":"","example":5.5,"description":"Vulnerability Environmental score."},{"field":"vulnerability.score.temporal","type":"float","normalization":"","example":"","description":"Vulnerability Temporal score."},{"field":"vulnerability.score.version","type":"keyword","normalization":"","example":2,"description":"CVSS version."},{"field":"vulnerability.severity","type":"keyword","normalization":"","example":"Critical","description":"Severity of the vulnerability."}] diff --git a/x-pack/plugins/osquery/public/common/schemas/ecs/v8.7.0.json b/x-pack/plugins/osquery/public/common/schemas/ecs/v8.7.0.json deleted file mode 100644 index 0961ad25572a..000000000000 --- a/x-pack/plugins/osquery/public/common/schemas/ecs/v8.7.0.json +++ /dev/null @@ -1 +0,0 @@ -[{"field":"labels","type":"object","normalization":"","example":{"application":"foo-bar","env":"production"},"description":"Custom key/value pairs."},{"field":"message","type":"match_only_text","normalization":"","example":"Hello World","description":"Log message optimized for viewing in a log viewer."},{"field":"tags","type":"keyword","normalization":"array","example":["production","env2"],"description":"List of keywords used to tag each event."},{"field":"agent.build.original","type":"keyword","normalization":"","example":"metricbeat version 7.6.0 (amd64), libbeat 7.6.0 [6a23e8f8f30f5001ba344e4e54d8d9cb82cb107c built 2020-02-05 23:10:10 +0000 UTC]","description":"Extended build information for the agent."},{"field":"client.address","type":"keyword","normalization":"","example":"","description":"Client network address."},{"field":"client.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"client.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"client.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"client.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the client to the server."},{"field":"client.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the client."},{"field":"client.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"client.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"client.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"client.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"client.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"client.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"client.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"client.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"client.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"client.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"client.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"client.ip","type":"ip","normalization":"","example":"","description":"IP address of the client."},{"field":"client.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the client."},{"field":"client.nat.ip","type":"ip","normalization":"","example":"","description":"Client NAT ip address"},{"field":"client.nat.port","type":"long","normalization":"","example":"","description":"Client NAT port"},{"field":"client.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the client to the server."},{"field":"client.port","type":"long","normalization":"","example":"","description":"Port of the client."},{"field":"client.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered client domain, stripped of the subdomain."},{"field":"client.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"client.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"client.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"client.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"client.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"client.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"client.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"client.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"client.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"client.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"client.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"client.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"client.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"client.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"cloud.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.origin.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.origin.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.origin.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.origin.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.origin.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.origin.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.origin.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.origin.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.origin.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.origin.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.origin.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"cloud.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"cloud.target.account.id","type":"keyword","normalization":"","example":666777888999,"description":"The cloud account or organization id."},{"field":"cloud.target.account.name","type":"keyword","normalization":"","example":"elastic-dev","description":"The cloud account name."},{"field":"cloud.target.availability_zone","type":"keyword","normalization":"","example":"us-east-1c","description":"Availability zone in which this host, resource, or service is located."},{"field":"cloud.target.instance.id","type":"keyword","normalization":"","example":"i-1234567890abcdef0","description":"Instance ID of the host machine."},{"field":"cloud.target.instance.name","type":"keyword","normalization":"","example":"","description":"Instance name of the host machine."},{"field":"cloud.target.machine.type","type":"keyword","normalization":"","example":"t2.medium","description":"Machine type of the host machine."},{"field":"cloud.target.project.id","type":"keyword","normalization":"","example":"my-project","description":"The cloud project id."},{"field":"cloud.target.project.name","type":"keyword","normalization":"","example":"my project","description":"The cloud project name."},{"field":"cloud.target.provider","type":"keyword","normalization":"","example":"aws","description":"Name of the cloud provider."},{"field":"cloud.target.region","type":"keyword","normalization":"","example":"us-east-1","description":"Region in which this host, resource, or service is located."},{"field":"cloud.target.service.name","type":"keyword","normalization":"","example":"lambda","description":"The cloud service name."},{"field":"container.cpu.usage","type":"scaled_float","normalization":"","example":"","description":"Percent CPU used, between 0 and 1."},{"field":"container.disk.read.bytes","type":"long","normalization":"","example":"","description":"The number of bytes read by all disks."},{"field":"container.disk.write.bytes","type":"long","normalization":"","example":"","description":"The number of bytes written on all disks."},{"field":"container.id","type":"keyword","normalization":"","example":"","description":"Unique container id."},{"field":"container.image.hash.all","type":"keyword","normalization":"array","example":"[sha256:f8fefc80e3273dc756f288a63945820d6476ad64883892c771b5e2ece6bf1b26]","description":"An array of digests of the image the container was built on."},{"field":"container.image.name","type":"keyword","normalization":"","example":"","description":"Name of the image the container was built on."},{"field":"container.image.tag","type":"keyword","normalization":"array","example":"","description":"Container image tags."},{"field":"container.labels","type":"object","normalization":"","example":"","description":"Image labels."},{"field":"container.memory.usage","type":"scaled_float","normalization":"","example":"","description":"Percent memory used, between 0 and 1."},{"field":"container.name","type":"keyword","normalization":"","example":"","description":"Container name."},{"field":"container.network.egress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes sent on all network interfaces."},{"field":"container.network.ingress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes received on all network interfaces."},{"field":"container.runtime","type":"keyword","normalization":"","example":"docker","description":"Runtime managing this container."},{"field":"data_stream.dataset","type":"constant_keyword","normalization":"","example":"nginx.access","description":"The field can contain anything that makes sense to signify the source of the data."},{"field":"data_stream.namespace","type":"constant_keyword","normalization":"","example":"production","description":"A user defined namespace. Namespaces are useful to allow grouping of data."},{"field":"data_stream.type","type":"constant_keyword","normalization":"","example":"logs","description":"An overarching type for the data stream."},{"field":"destination.address","type":"keyword","normalization":"","example":"","description":"Destination network address."},{"field":"destination.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"destination.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"destination.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"destination.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the destination to the source."},{"field":"destination.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the destination."},{"field":"destination.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"destination.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"destination.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"destination.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"destination.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"destination.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"destination.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"destination.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"destination.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"destination.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"destination.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"destination.ip","type":"ip","normalization":"","example":"","description":"IP address of the destination."},{"field":"destination.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the destination."},{"field":"destination.nat.ip","type":"ip","normalization":"","example":"","description":"Destination NAT ip"},{"field":"destination.nat.port","type":"long","normalization":"","example":"","description":"Destination NAT Port"},{"field":"destination.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the destination to the source."},{"field":"destination.port","type":"long","normalization":"","example":"","description":"Port of the destination."},{"field":"destination.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered destination domain, stripped of the subdomain."},{"field":"destination.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"destination.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"destination.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"destination.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"destination.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"destination.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"destination.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"destination.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"destination.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"destination.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"destination.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"destination.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"destination.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"destination.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"device.id","type":"keyword","normalization":"","example":"00000000-54b3-e7c7-0000-000046bffd97","description":"The unique identifier of a device."},{"field":"device.manufacturer","type":"keyword","normalization":"","example":"Samsung","description":"The vendor name of the device manufacturer."},{"field":"device.model.identifier","type":"keyword","normalization":"","example":"SM-G920F","description":"The machine readable identifier of the device model."},{"field":"device.model.name","type":"keyword","normalization":"","example":"Samsung Galaxy S6","description":"The human readable marketing name of the device model."},{"field":"dll.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"dll.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"dll.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"dll.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"dll.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"dll.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"dll.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"dll.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"dll.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"dll.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"dll.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"dll.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"dll.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"dll.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"dll.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"dll.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"dll.name","type":"keyword","normalization":"","example":"kernel32.dll","description":"Name of the library."},{"field":"dll.path","type":"keyword","normalization":"","example":"C:\\Windows\\System32\\kernel32.dll","description":"Full file path of the library."},{"field":"dll.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"dll.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"dll.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"dll.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"dll.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"dll.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"dll.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"dll.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"dll.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"dll.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"dll.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"dll.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"dll.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"dll.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"dll.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"dll.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"dll.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"dll.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"dll.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"dll.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"dll.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"dll.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"dll.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"dns.answers","type":"object","normalization":"array","example":"","description":"Array of DNS answers."},{"field":"dns.answers.class","type":"keyword","normalization":"","example":"IN","description":"The class of DNS data contained in this resource record."},{"field":"dns.answers.data","type":"keyword","normalization":"","example":"10.10.10.10","description":"The data describing the resource."},{"field":"dns.answers.name","type":"keyword","normalization":"","example":"www.example.com","description":"The domain name to which this resource record pertains."},{"field":"dns.answers.ttl","type":"long","normalization":"","example":180,"description":"The time interval in seconds that this resource record may be cached before it should be discarded."},{"field":"dns.answers.type","type":"keyword","normalization":"","example":"CNAME","description":"The type of data contained in this resource record."},{"field":"dns.header_flags","type":"keyword","normalization":"array","example":["RD","RA"],"description":"Array of DNS header flags."},{"field":"dns.id","type":"keyword","normalization":"","example":62111,"description":"The DNS packet identifier assigned by the program that generated the query. The identifier is copied to the response."},{"field":"dns.op_code","type":"keyword","normalization":"","example":"QUERY","description":"The DNS operation code that specifies the kind of query in the message."},{"field":"dns.question.class","type":"keyword","normalization":"","example":"IN","description":"The class of records being queried."},{"field":"dns.question.name","type":"keyword","normalization":"","example":"www.example.com","description":"The name being queried."},{"field":"dns.question.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered domain, stripped of the subdomain."},{"field":"dns.question.subdomain","type":"keyword","normalization":"","example":"www","description":"The subdomain of the domain."},{"field":"dns.question.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"dns.question.type","type":"keyword","normalization":"","example":"AAAA","description":"The type of record being queried."},{"field":"dns.resolved_ip","type":"ip","normalization":"array","example":["10.10.10.10","10.10.10.11"],"description":"Array containing all IPs seen in answers.data"},{"field":"dns.response_code","type":"keyword","normalization":"","example":"NOERROR","description":"The DNS response code."},{"field":"dns.type","type":"keyword","normalization":"","example":"answer","description":"The type of DNS event captured, query or answer."},{"field":"email.attachments","type":"nested","normalization":"array","example":"","description":"List of objects describing the attachments."},{"field":"email.attachments.file.extension","type":"keyword","normalization":"","example":"txt","description":"Attachment file extension."},{"field":"email.attachments.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"email.attachments.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"email.attachments.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"email.attachments.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"email.attachments.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"email.attachments.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"email.attachments.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"email.attachments.file.mime_type","type":"keyword","normalization":"","example":"text/plain","description":"MIME type of the attachment file."},{"field":"email.attachments.file.name","type":"keyword","normalization":"","example":"attachment.txt","description":"Name of the attachment file."},{"field":"email.attachments.file.size","type":"long","normalization":"","example":64329,"description":"Attachment file size."},{"field":"email.bcc.address","type":"keyword","normalization":"array","example":"bcc.user1@example.com","description":"Email address of BCC recipient"},{"field":"email.cc.address","type":"keyword","normalization":"array","example":"cc.user1@example.com","description":"Email address of CC recipient"},{"field":"email.content_type","type":"keyword","normalization":"","example":"text/plain","description":"MIME type of the email message."},{"field":"email.delivery_timestamp","type":"date","normalization":"","example":"2020-11-10T22:12:34.8196921Z","description":"Date and time when message was delivered."},{"field":"email.direction","type":"keyword","normalization":"","example":"inbound","description":"Direction of the message."},{"field":"email.from.address","type":"keyword","normalization":"array","example":"sender@example.com","description":"The sender's email address."},{"field":"email.local_id","type":"keyword","normalization":"","example":"c26dbea0-80d5-463b-b93c-4e8b708219ce","description":"Unique identifier given by the source."},{"field":"email.message_id","type":"wildcard","normalization":"","example":"81ce15$8r2j59@mail01.example.com","description":"Value from the Message-ID header."},{"field":"email.origination_timestamp","type":"date","normalization":"","example":"2020-11-10T22:12:34.8196921Z","description":"Date and time the email was composed."},{"field":"email.reply_to.address","type":"keyword","normalization":"array","example":"reply.here@example.com","description":"Address replies should be delivered to."},{"field":"email.sender.address","type":"keyword","normalization":"","example":"","description":"Address of the message sender."},{"field":"email.subject","type":"keyword","normalization":"","example":"Please see this important message.","description":"The subject of the email message."},{"field":"email.subject.text","type":"match_only_text","normalization":"","example":"Please see this important message.","description":"The subject of the email message."},{"field":"email.to.address","type":"keyword","normalization":"array","example":"user1@example.com","description":"Email address of recipient"},{"field":"email.x_mailer","type":"keyword","normalization":"","example":"Spambot v2.5","description":"Application that drafted email."},{"field":"error.code","type":"keyword","normalization":"","example":"","description":"Error code describing the error."},{"field":"error.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the error."},{"field":"error.message","type":"match_only_text","normalization":"","example":"","description":"Error message."},{"field":"error.stack_trace","type":"wildcard","normalization":"","example":"","description":"The stack trace of this error in plain text."},{"field":"error.stack_trace.text","type":"match_only_text","normalization":"","example":"","description":"The stack trace of this error in plain text."},{"field":"error.type","type":"keyword","normalization":"","example":"java.lang.NullPointerException","description":"The type of the error, for example the class name of the exception."},{"field":"event.action","type":"keyword","normalization":"","example":"user-password-change","description":"The action captured by the event."},{"field":"event.category","type":"keyword","normalization":"array","example":"authentication","description":"Event category. The second categorization field in the hierarchy."},{"field":"event.code","type":"keyword","normalization":"","example":4648,"description":"Identification code for this event."},{"field":"event.created","type":"date","normalization":"","example":"2016-05-23T08:05:34.857Z","description":"Time when the event was first read by an agent or by your pipeline."},{"field":"event.dataset","type":"keyword","normalization":"","example":"apache.access","description":"Name of the dataset."},{"field":"event.duration","type":"long","normalization":"","example":"","description":"Duration of the event in nanoseconds."},{"field":"event.end","type":"date","normalization":"","example":"","description":"event.end contains the date when the event ended or when the activity was last observed."},{"field":"event.hash","type":"keyword","normalization":"","example":"123456789012345678901234567890ABCD","description":"Hash (perhaps logstash fingerprint) of raw field to be able to demonstrate log integrity."},{"field":"event.id","type":"keyword","normalization":"","example":"8a4f500d","description":"Unique ID to describe the event."},{"field":"event.kind","type":"keyword","normalization":"","example":"alert","description":"The kind of the event. The highest categorization field in the hierarchy."},{"field":"event.original","type":"keyword","normalization":"","example":"Sep 19 08:26:10 host CEF:0|Security| threatmanager|1.0|100| worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2spt=1232","description":"Raw text message of entire event."},{"field":"event.outcome","type":"keyword","normalization":"","example":"success","description":"The outcome of the event. The lowest level categorization field in the hierarchy."},{"field":"event.provider","type":"keyword","normalization":"","example":"kernel","description":"Source of the event."},{"field":"event.reason","type":"keyword","normalization":"","example":"Terminated an unexpected process","description":"Reason why this event happened, according to the source"},{"field":"event.reference","type":"keyword","normalization":"","example":"https://system.example.com/event/#0001234","description":"Event reference URL"},{"field":"event.risk_score","type":"float","normalization":"","example":"","description":"Risk score or priority of the event (e.g. security solutions). Use your system's original value here."},{"field":"event.risk_score_norm","type":"float","normalization":"","example":"","description":"Normalized risk score or priority of the event (0-100)."},{"field":"event.sequence","type":"long","normalization":"","example":"","description":"Sequence number of the event."},{"field":"event.severity","type":"long","normalization":"","example":7,"description":"Numeric severity of the event."},{"field":"event.start","type":"date","normalization":"","example":"","description":"event.start contains the date when the event started or when the activity was first observed."},{"field":"event.timezone","type":"keyword","normalization":"","example":"","description":"Event time zone."},{"field":"event.type","type":"keyword","normalization":"array","example":"","description":"Event type. The third categorization field in the hierarchy."},{"field":"event.url","type":"keyword","normalization":"","example":"https://mysystem.example.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe","description":"Event investigation URL"},{"field":"faas.coldstart","type":"boolean","normalization":"","example":"","description":"Boolean value indicating a cold start of a function."},{"field":"faas.execution","type":"keyword","normalization":"","example":"af9d5aa4-a685-4c5f-a22b-444f80b3cc28","description":"The execution ID of the current function execution."},{"field":"faas.id","type":"keyword","normalization":"","example":"arn:aws:lambda:us-west-2:123456789012:function:my-function","description":"The unique identifier of a serverless function."},{"field":"faas.name","type":"keyword","normalization":"","example":"my-function","description":"The name of a serverless function."},{"field":"faas.trigger","type":"nested","normalization":"","example":"","description":"Details about the function trigger."},{"field":"faas.trigger.request_id","type":"keyword","normalization":"","example":123456789,"description":"The ID of the trigger request , message, event, etc."},{"field":"faas.trigger.type","type":"keyword","normalization":"","example":"http","description":"The trigger for the function execution."},{"field":"faas.version","type":"keyword","normalization":"","example":123,"description":"The version of a serverless function."},{"field":"file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"file.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"file.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"file.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"file.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"file.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"file.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"file.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"host.boot.id","type":"keyword","normalization":"","example":"88a1f0ed-5ae5-41ee-af6b-41921c311872","description":"Linux boot uuid taken from /proc/sys/kernel/random/boot_id"},{"field":"host.cpu.usage","type":"scaled_float","normalization":"","example":"","description":"Percent CPU used, between 0 and 1."},{"field":"host.disk.read.bytes","type":"long","normalization":"","example":"","description":"The number of bytes read by all disks."},{"field":"host.disk.write.bytes","type":"long","normalization":"","example":"","description":"The number of bytes written on all disks."},{"field":"host.domain","type":"keyword","normalization":"","example":"CONTOSO","description":"Name of the directory the group is a member of."},{"field":"host.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"host.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"host.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"host.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"host.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"host.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"host.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"host.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"host.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"host.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"host.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"host.name","type":"keyword","normalization":"","example":"","description":"Name of the host."},{"field":"host.network.egress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes sent on all network interfaces."},{"field":"host.network.egress.packets","type":"long","normalization":"","example":"","description":"The number of packets sent on all network interfaces."},{"field":"host.network.ingress.bytes","type":"long","normalization":"","example":"","description":"The number of bytes received on all network interfaces."},{"field":"host.network.ingress.packets","type":"long","normalization":"","example":"","description":"The number of packets received on all network interfaces."},{"field":"host.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"host.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"host.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"host.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"host.pid_ns_ino","type":"keyword","normalization":"","example":256383,"description":"Pid namespace inode"},{"field":"host.risk.calculated_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"host.risk.calculated_score","type":"float","normalization":"","example":880.73,"description":"A risk classification score calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"host.risk.calculated_score_norm","type":"float","normalization":"","example":88.73,"description":"A normalized risk score calculated by an internal system."},{"field":"host.risk.static_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"host.risk.static_score","type":"float","normalization":"","example":830,"description":"A risk classification score obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"host.risk.static_score_norm","type":"float","normalization":"","example":83,"description":"A normalized risk score calculated by an external system."},{"field":"host.type","type":"keyword","normalization":"","example":"","description":"Type of host."},{"field":"host.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the host has been up."},{"field":"http.request.body.bytes","type":"long","normalization":"","example":887,"description":"Size in bytes of the request body."},{"field":"http.request.body.content","type":"wildcard","normalization":"","example":"Hello world","description":"The full HTTP request body."},{"field":"http.request.body.content.text","type":"match_only_text","normalization":"","example":"Hello world","description":"The full HTTP request body."},{"field":"http.request.bytes","type":"long","normalization":"","example":1437,"description":"Total size in bytes of the request (body and headers)."},{"field":"http.request.id","type":"keyword","normalization":"","example":"123e4567-e89b-12d3-a456-426614174000","description":"HTTP request ID."},{"field":"http.request.method","type":"keyword","normalization":"","example":"POST","description":"HTTP request method."},{"field":"http.request.mime_type","type":"keyword","normalization":"","example":"image/gif","description":"Mime type of the body of the request."},{"field":"http.request.referrer","type":"keyword","normalization":"","example":"https://blog.example.com/","description":"Referrer for this HTTP request."},{"field":"http.response.body.bytes","type":"long","normalization":"","example":887,"description":"Size in bytes of the response body."},{"field":"http.response.body.content","type":"wildcard","normalization":"","example":"Hello world","description":"The full HTTP response body."},{"field":"http.response.body.content.text","type":"match_only_text","normalization":"","example":"Hello world","description":"The full HTTP response body."},{"field":"http.response.bytes","type":"long","normalization":"","example":1437,"description":"Total size in bytes of the response (body and headers)."},{"field":"http.response.mime_type","type":"keyword","normalization":"","example":"image/gif","description":"Mime type of the body of the response."},{"field":"http.response.status_code","type":"long","normalization":"","example":404,"description":"HTTP response status code."},{"field":"http.version","type":"keyword","normalization":"","example":1.1,"description":"HTTP version."},{"field":"log.file.path","type":"keyword","normalization":"","example":"/var/log/fun-times.log","description":"Full path to the log file this event came from."},{"field":"log.level","type":"keyword","normalization":"","example":"error","description":"Log level of the log event."},{"field":"log.logger","type":"keyword","normalization":"","example":"org.elasticsearch.bootstrap.Bootstrap","description":"Name of the logger."},{"field":"log.origin.file.line","type":"long","normalization":"","example":42,"description":"The line number of the file which originated the log event."},{"field":"log.origin.file.name","type":"keyword","normalization":"","example":"Bootstrap.java","description":"The code file which originated the log event."},{"field":"log.origin.function","type":"keyword","normalization":"","example":"init","description":"The function which originated the log event."},{"field":"log.syslog","type":"object","normalization":"","example":"","description":"Syslog metadata"},{"field":"log.syslog.appname","type":"keyword","normalization":"","example":"sshd","description":"The device or application that originated the Syslog message."},{"field":"log.syslog.facility.code","type":"long","normalization":"","example":23,"description":"Syslog numeric facility of the event."},{"field":"log.syslog.facility.name","type":"keyword","normalization":"","example":"local7","description":"Syslog text-based facility of the event."},{"field":"log.syslog.hostname","type":"keyword","normalization":"","example":"example-host","description":"The host that originated the Syslog message."},{"field":"log.syslog.msgid","type":"keyword","normalization":"","example":"ID47","description":"An identifier for the type of Syslog message."},{"field":"log.syslog.priority","type":"long","normalization":"","example":135,"description":"Syslog priority of the event."},{"field":"log.syslog.procid","type":"keyword","normalization":"","example":12345,"description":"The process name or ID that originated the Syslog message."},{"field":"log.syslog.severity.code","type":"long","normalization":"","example":3,"description":"Syslog numeric severity of the event."},{"field":"log.syslog.severity.name","type":"keyword","normalization":"","example":"Error","description":"Syslog text-based severity of the event."},{"field":"log.syslog.structured_data","type":"flattened","normalization":"","example":"","description":"Structured data expressed in RFC 5424 messages."},{"field":"log.syslog.version","type":"keyword","normalization":"","example":1,"description":"Syslog protocol version."},{"field":"network.application","type":"keyword","normalization":"","example":"aim","description":"Application level protocol name."},{"field":"network.bytes","type":"long","normalization":"","example":368,"description":"Total bytes transferred in both directions."},{"field":"network.community_id","type":"keyword","normalization":"","example":"1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=","description":"A hash of source and destination IPs and ports."},{"field":"network.direction","type":"keyword","normalization":"","example":"inbound","description":"Direction of the network traffic."},{"field":"network.forwarded_ip","type":"ip","normalization":"","example":"192.1.1.2","description":"Host IP address when the source IP address is the proxy."},{"field":"network.iana_number","type":"keyword","normalization":"","example":6,"description":"IANA Protocol Number."},{"field":"network.inner","type":"object","normalization":"","example":"","description":"Inner VLAN tag information"},{"field":"network.inner.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"network.inner.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"network.name","type":"keyword","normalization":"","example":"Guest Wifi","description":"Name given by operators to sections of their network."},{"field":"network.packets","type":"long","normalization":"","example":24,"description":"Total packets transferred in both directions."},{"field":"network.protocol","type":"keyword","normalization":"","example":"http","description":"Application protocol name."},{"field":"network.transport","type":"keyword","normalization":"","example":"tcp","description":"Protocol Name corresponding to the field `iana_number`."},{"field":"network.type","type":"keyword","normalization":"","example":"ipv4","description":"In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc"},{"field":"network.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"network.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.egress","type":"object","normalization":"","example":"","description":"Object field for egress information"},{"field":"observer.egress.interface.alias","type":"keyword","normalization":"","example":"outside","description":"Interface alias"},{"field":"observer.egress.interface.id","type":"keyword","normalization":"","example":10,"description":"Interface ID"},{"field":"observer.egress.interface.name","type":"keyword","normalization":"","example":"eth0","description":"Interface name"},{"field":"observer.egress.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"observer.egress.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.egress.zone","type":"keyword","normalization":"","example":"Public_Internet","description":"Observer Egress zone"},{"field":"observer.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"observer.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"observer.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"observer.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"observer.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"observer.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"observer.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"observer.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"observer.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"observer.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"observer.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"observer.hostname","type":"keyword","normalization":"","example":"","description":"Hostname of the observer."},{"field":"observer.ingress","type":"object","normalization":"","example":"","description":"Object field for ingress information"},{"field":"observer.ingress.interface.alias","type":"keyword","normalization":"","example":"outside","description":"Interface alias"},{"field":"observer.ingress.interface.id","type":"keyword","normalization":"","example":10,"description":"Interface ID"},{"field":"observer.ingress.interface.name","type":"keyword","normalization":"","example":"eth0","description":"Interface name"},{"field":"observer.ingress.vlan.id","type":"keyword","normalization":"","example":10,"description":"VLAN ID as reported by the observer."},{"field":"observer.ingress.vlan.name","type":"keyword","normalization":"","example":"outside","description":"Optional VLAN name as reported by the observer."},{"field":"observer.ingress.zone","type":"keyword","normalization":"","example":"DMZ","description":"Observer ingress zone"},{"field":"observer.ip","type":"ip","normalization":"array","example":"","description":"IP addresses of the observer."},{"field":"observer.mac","type":"keyword","normalization":"array","example":["00-00-5E-00-53-23","00-00-5E-00-53-24"],"description":"MAC addresses of the observer."},{"field":"observer.name","type":"keyword","normalization":"","example":"1_proxySG","description":"Custom name of the observer."},{"field":"observer.os.family","type":"keyword","normalization":"","example":"debian","description":"OS family (such as redhat, debian, freebsd, windows)."},{"field":"observer.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"observer.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"observer.os.kernel","type":"keyword","normalization":"","example":"4.4.0-112-generic","description":"Operating system kernel version as a raw string."},{"field":"observer.os.name","type":"keyword","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"observer.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"observer.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"observer.os.type","type":"keyword","normalization":"","example":"macos","description":"Which commercial OS family (one of: linux, macos, unix, windows, ios or android)."},{"field":"observer.os.version","type":"keyword","normalization":"","example":"10.14.1","description":"Operating system version as a raw string."},{"field":"observer.product","type":"keyword","normalization":"","example":"s200","description":"The product name of the observer."},{"field":"observer.serial_number","type":"keyword","normalization":"","example":"","description":"Observer serial number."},{"field":"observer.type","type":"keyword","normalization":"","example":"firewall","description":"The type of the observer the data is coming from."},{"field":"observer.vendor","type":"keyword","normalization":"","example":"Symantec","description":"Vendor name of the observer."},{"field":"observer.version","type":"keyword","normalization":"","example":"","description":"Observer version."},{"field":"orchestrator.api_version","type":"keyword","normalization":"","example":"v1beta1","description":"API version being used to carry out the action"},{"field":"orchestrator.cluster.id","type":"keyword","normalization":"","example":"","description":"Unique ID of the cluster."},{"field":"orchestrator.cluster.name","type":"keyword","normalization":"","example":"","description":"Name of the cluster."},{"field":"orchestrator.cluster.url","type":"keyword","normalization":"","example":"","description":"URL of the API used to manage the cluster."},{"field":"orchestrator.cluster.version","type":"keyword","normalization":"","example":"","description":"The version of the cluster."},{"field":"orchestrator.namespace","type":"keyword","normalization":"","example":"kube-system","description":"Namespace in which the action is taking place."},{"field":"orchestrator.organization","type":"keyword","normalization":"","example":"elastic","description":"Organization affected by the event (for multi-tenant orchestrator setups)."},{"field":"orchestrator.resource.id","type":"keyword","normalization":"","example":"","description":"Unique ID of the resource being acted upon."},{"field":"orchestrator.resource.ip","type":"ip","normalization":"array","example":"","description":"IP address assigned to the resource associated with the event being observed."},{"field":"orchestrator.resource.name","type":"keyword","normalization":"","example":"test-pod-cdcws","description":"Name of the resource being acted upon."},{"field":"orchestrator.resource.parent.type","type":"keyword","normalization":"","example":"DaemonSet","description":"Type or kind of the parent resource associated with the event being observed."},{"field":"orchestrator.resource.type","type":"keyword","normalization":"","example":"service","description":"Type of resource being acted upon."},{"field":"orchestrator.type","type":"keyword","normalization":"","example":"kubernetes","description":"Orchestrator cluster type (e.g. kubernetes, nomad or cloudfoundry)."},{"field":"organization.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the organization."},{"field":"organization.name","type":"keyword","normalization":"","example":"","description":"Organization name."},{"field":"organization.name.text","type":"match_only_text","normalization":"","example":"","description":"Organization name."},{"field":"package.architecture","type":"keyword","normalization":"","example":"x86_64","description":"Package architecture."},{"field":"package.build_version","type":"keyword","normalization":"","example":"36f4f7e89dd61b0988b12ee000b98966867710cd","description":"Build version information"},{"field":"package.checksum","type":"keyword","normalization":"","example":"68b329da9893e34099c7d8ad5cb9c940","description":"Checksum of the installed package for verification."},{"field":"package.description","type":"keyword","normalization":"","example":"Open source programming language to build simple/reliable/efficient software.","description":"Description of the package."},{"field":"package.install_scope","type":"keyword","normalization":"","example":"global","description":"Indicating how the package was installed, e.g. user-local, global."},{"field":"package.installed","type":"date","normalization":"","example":"","description":"Time when package was installed."},{"field":"package.license","type":"keyword","normalization":"","example":"Apache License 2.0","description":"Package license"},{"field":"package.name","type":"keyword","normalization":"","example":"go","description":"Package name"},{"field":"package.path","type":"keyword","normalization":"","example":"/usr/local/Cellar/go/1.12.9/","description":"Path where the package is installed."},{"field":"package.reference","type":"keyword","normalization":"","example":"https://golang.org","description":"Package home page or reference URL"},{"field":"package.size","type":"long","normalization":"","example":62231,"description":"Package size in bytes."},{"field":"package.type","type":"keyword","normalization":"","example":"rpm","description":"Package type"},{"field":"package.version","type":"keyword","normalization":"","example":"1.12.9","description":"Package version"},{"field":"process.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"process.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"process.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"process.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"process.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"process.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"process.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"process.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"process.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"process.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"process.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"process.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"process.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"process.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"process.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"process.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"process.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"process.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"process.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"process.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"process.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"process.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"process.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"process.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"process.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"process.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"process.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"process.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"process.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"process.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"process.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"process.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"process.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"process.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"process.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"process.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"process.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"process.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"process.end","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process ended."},{"field":"process.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.entry_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.entry_leader.attested_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.attested_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.attested_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.attested_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.entry_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.entry_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.entry_meta.source.ip","type":"ip","normalization":"","example":"","description":"IP address of the source."},{"field":"process.entry_leader.entry_meta.type","type":"keyword","normalization":"","example":"","description":"The entry type for the entry session leader."},{"field":"process.entry_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.entry_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.entry_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.entry_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.entry_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.entry_leader.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.parent.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.entry_leader.parent.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.parent.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.entry_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.entry_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.entry_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.entry_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.entry_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.entry_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.entry_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.entry_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.entry_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.entry_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.entry_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.env_vars","type":"keyword","normalization":"array","example":["PATH=/usr/local/bin:/usr/bin","USER=ubuntu"],"description":"Array of environment variable bindings."},{"field":"process.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.exit_code","type":"long","normalization":"","example":137,"description":"The exit code of the process."},{"field":"process.group_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.group_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.group_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.group_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.group_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.group_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.group_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.group_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.group_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.group_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.group_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.group_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.group_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.group_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.group_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.group_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.group_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.group_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.group_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.group_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.group_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.group_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"process.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"process.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"process.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"process.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"process.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"process.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"process.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.io","type":"object","normalization":"","example":"","description":"A chunk of input or output (IO) from a single process."},{"field":"process.io.bytes_skipped","type":"object","normalization":"array","example":"","description":"An array of byte offsets and lengths denoting where IO data has been skipped."},{"field":"process.io.bytes_skipped.length","type":"long","normalization":"","example":"","description":"The length of bytes skipped."},{"field":"process.io.bytes_skipped.offset","type":"long","normalization":"","example":"","description":"The byte offset into this event's io.text (or io.bytes in the future) where length bytes were skipped."},{"field":"process.io.max_bytes_per_process_exceeded","type":"boolean","normalization":"","example":"","description":"If true, the process producing the output has exceeded the max_kilobytes_per_process configuration setting."},{"field":"process.io.text","type":"wildcard","normalization":"","example":"","description":"A chunk of output or input sanitized to UTF-8."},{"field":"process.io.total_bytes_captured","type":"long","normalization":"","example":"","description":"The total number of bytes captured in this event."},{"field":"process.io.total_bytes_skipped","type":"long","normalization":"","example":"","description":"The total number of bytes that were not captured due to implementation restrictions such as buffer size limits."},{"field":"process.io.type","type":"keyword","normalization":"","example":"","description":"The type of object on which the IO action (read or write) was taken."},{"field":"process.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"process.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"process.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"process.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"process.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"process.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"process.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"process.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.parent.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.parent.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"process.parent.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"process.parent.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"process.parent.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"process.parent.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"process.parent.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"process.parent.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"process.parent.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"process.parent.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"process.parent.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.parent.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.parent.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"process.parent.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"process.parent.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"process.parent.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"process.parent.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"process.parent.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"process.parent.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"process.parent.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"process.parent.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"process.parent.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"process.parent.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"process.parent.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"process.parent.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"process.parent.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"process.parent.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"process.parent.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"process.parent.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"process.parent.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"process.parent.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"process.parent.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"process.parent.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"process.parent.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"process.parent.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"process.parent.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"process.parent.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"process.parent.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"process.parent.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"process.parent.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"process.parent.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"process.parent.end","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process ended."},{"field":"process.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.parent.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.parent.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.parent.exit_code","type":"long","normalization":"","example":137,"description":"The exit code of the process."},{"field":"process.parent.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.group_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.parent.group_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.parent.group_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.parent.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"process.parent.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"process.parent.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"process.parent.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"process.parent.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"process.parent.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"process.parent.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"process.parent.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.parent.macho.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a Mach-O file."},{"field":"process.parent.macho.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.macho.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.macho.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.macho.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.macho.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a Mach-O file."},{"field":"process.parent.macho.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.macho.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.macho.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.macho.sections","type":"nested","normalization":"array","example":"","description":"Section information of the Mach-O file."},{"field":"process.parent.macho.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.macho.sections.name","type":"keyword","normalization":"","example":"","description":"Mach-O Section List name."},{"field":"process.parent.macho.sections.physical_size","type":"long","normalization":"","example":"","description":"Mach-O Section List physical size."},{"field":"process.parent.macho.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.macho.sections.virtual_size","type":"long","normalization":"","example":"","description":"Mach-O Section List virtual size. This is always the same as `physical_size`."},{"field":"process.parent.macho.symhash","type":"keyword","normalization":"","example":"d3ccf195b62a9279c3c19af1080497ec","description":"A hash of the imports in a Mach-O file."},{"field":"process.parent.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.parent.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"process.parent.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"process.parent.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"process.parent.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"process.parent.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"process.parent.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.parent.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.parent.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.parent.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"process.parent.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"process.parent.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.parent.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.parent.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"process.parent.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"process.parent.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"process.parent.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"process.parent.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.parent.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"process.parent.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"process.parent.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.parent.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"process.parent.pgid","type":"long","normalization":"","example":"","description":"Deprecated identifier of the group of processes the process belongs to."},{"field":"process.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.parent.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.parent.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.parent.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.parent.thread.id","type":"long","normalization":"","example":4242,"description":"Thread ID."},{"field":"process.parent.thread.name","type":"keyword","normalization":"","example":"thread-0","description":"Thread name."},{"field":"process.parent.title","type":"keyword","normalization":"","example":"","description":"Process title."},{"field":"process.parent.title.text","type":"match_only_text","normalization":"","example":"","description":"Process title."},{"field":"process.parent.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.parent.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.parent.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.parent.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the process has been up."},{"field":"process.parent.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.parent.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.parent.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.parent.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"process.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"process.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"process.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"process.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"process.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"process.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"process.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"process.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"process.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"process.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"process.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"process.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"process.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"process.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"process.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"process.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"process.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"process.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"process.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"process.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"process.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"process.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"process.pgid","type":"long","normalization":"","example":"","description":"Deprecated identifier of the group of processes the process belongs to."},{"field":"process.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.previous.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.previous.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.previous.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.previous.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.args","type":"keyword","normalization":"array","example":["/usr/bin/ssh","-l","user","10.0.0.16"],"description":"Array of process arguments."},{"field":"process.session_leader.args_count","type":"long","normalization":"","example":4,"description":"Length of the process.args array."},{"field":"process.session_leader.command_line","type":"wildcard","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.session_leader.command_line.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh -l user 10.0.0.16","description":"Full command line that started the process."},{"field":"process.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.executable","type":"keyword","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.session_leader.executable.text","type":"match_only_text","normalization":"","example":"/usr/bin/ssh","description":"Absolute path to the process executable."},{"field":"process.session_leader.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.interactive","type":"boolean","normalization":"","example":"True","description":"Whether the process is connected to an interactive shell."},{"field":"process.session_leader.name","type":"keyword","normalization":"","example":"ssh","description":"Process name."},{"field":"process.session_leader.name.text","type":"match_only_text","normalization":"","example":"ssh","description":"Process name."},{"field":"process.session_leader.parent.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.parent.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.parent.session_leader.entity_id","type":"keyword","normalization":"","example":"c2c455d9f99375d","description":"Unique identifier for the process."},{"field":"process.session_leader.parent.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.parent.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.parent.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.pid","type":"long","normalization":"","example":4242,"description":"Process id."},{"field":"process.session_leader.real_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.real_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.real_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.real_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.real_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.same_as_process","type":"boolean","normalization":"","example":"True","description":"This boolean is used to identify if a leader process is the same as the top level process."},{"field":"process.session_leader.saved_group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.saved_group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.saved_user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.saved_user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.saved_user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.session_leader.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.session_leader.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.session_leader.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.session_leader.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.session_leader.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.session_leader.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.session_leader.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.session_leader.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.session_leader.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.start","type":"date","normalization":"","example":"2016-05-23T08:05:34.853Z","description":"The time the process started."},{"field":"process.supplemental_groups.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"process.supplemental_groups.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"process.thread.id","type":"long","normalization":"","example":4242,"description":"Thread ID."},{"field":"process.thread.name","type":"keyword","normalization":"","example":"thread-0","description":"Thread name."},{"field":"process.title","type":"keyword","normalization":"","example":"","description":"Process title."},{"field":"process.title.text","type":"match_only_text","normalization":"","example":"","description":"Process title."},{"field":"process.tty","type":"object","normalization":"","example":"","description":"Information about the controlling TTY device."},{"field":"process.tty.char_device.major","type":"long","normalization":"","example":4,"description":"The TTY character device's major number."},{"field":"process.tty.char_device.minor","type":"long","normalization":"","example":1,"description":"The TTY character device's minor number."},{"field":"process.tty.columns","type":"long","normalization":"","example":80,"description":"The number of character columns per line. e.g terminal width"},{"field":"process.tty.rows","type":"long","normalization":"","example":24,"description":"The number of character rows in the terminal. e.g terminal height"},{"field":"process.uptime","type":"long","normalization":"","example":1325,"description":"Seconds the process has been up."},{"field":"process.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"process.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"process.working_directory","type":"keyword","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"process.working_directory.text","type":"match_only_text","normalization":"","example":"/home/alice","description":"The working directory of the process."},{"field":"registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"related.hash","type":"keyword","normalization":"array","example":"","description":"All the hashes seen on your event."},{"field":"related.hosts","type":"keyword","normalization":"array","example":"","description":"All the host identifiers seen on your event."},{"field":"related.ip","type":"ip","normalization":"array","example":"","description":"All of the IPs seen on your event."},{"field":"related.user","type":"keyword","normalization":"array","example":"","description":"All the user names or other user identifiers seen on the event."},{"field":"rule.author","type":"keyword","normalization":"array","example":["Star-Lord"],"description":"Rule author"},{"field":"rule.category","type":"keyword","normalization":"","example":"Attempted Information Leak","description":"Rule category"},{"field":"rule.description","type":"keyword","normalization":"","example":"Block requests to public DNS over HTTPS / TLS protocols","description":"Rule description"},{"field":"rule.id","type":"keyword","normalization":"","example":101,"description":"Rule ID"},{"field":"rule.license","type":"keyword","normalization":"","example":"Apache 2.0","description":"Rule license"},{"field":"rule.name","type":"keyword","normalization":"","example":"BLOCK_DNS_over_TLS","description":"Rule name"},{"field":"rule.reference","type":"keyword","normalization":"","example":"https://en.wikipedia.org/wiki/DNS_over_TLS","description":"Rule reference URL"},{"field":"rule.ruleset","type":"keyword","normalization":"","example":"Standard_Protocol_Filters","description":"Rule ruleset"},{"field":"rule.uuid","type":"keyword","normalization":"","example":1100110011,"description":"Rule UUID"},{"field":"rule.version","type":"keyword","normalization":"","example":1.1,"description":"Rule version"},{"field":"server.address","type":"keyword","normalization":"","example":"","description":"Server network address."},{"field":"server.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"server.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"server.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"server.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the server to the client."},{"field":"server.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the server."},{"field":"server.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"server.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"server.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"server.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"server.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"server.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"server.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"server.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"server.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"server.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"server.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"server.ip","type":"ip","normalization":"","example":"","description":"IP address of the server."},{"field":"server.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the server."},{"field":"server.nat.ip","type":"ip","normalization":"","example":"","description":"Server NAT ip"},{"field":"server.nat.port","type":"long","normalization":"","example":"","description":"Server NAT port"},{"field":"server.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the server to the client."},{"field":"server.port","type":"long","normalization":"","example":"","description":"Port of the server."},{"field":"server.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered server domain, stripped of the subdomain."},{"field":"server.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"server.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"server.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"server.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"server.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"server.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"server.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"server.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"server.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"server.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"server.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"server.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"server.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"server.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"service.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.origin.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.origin.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.origin.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.origin.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.origin.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.origin.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.origin.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.origin.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.origin.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.origin.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.origin.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"service.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.target.address","type":"keyword","normalization":"","example":"172.26.0.2:5432","description":"Address of this service."},{"field":"service.target.environment","type":"keyword","normalization":"","example":"production","description":"Environment of the service."},{"field":"service.target.ephemeral_id","type":"keyword","normalization":"","example":"8a4f500f","description":"Ephemeral identifier of this service."},{"field":"service.target.id","type":"keyword","normalization":"","example":"d37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6","description":"Unique identifier of the running service."},{"field":"service.target.name","type":"keyword","normalization":"","example":"elasticsearch-metrics","description":"Name of the service."},{"field":"service.target.node.name","type":"keyword","normalization":"","example":"instance-0000000016","description":"Name of the service node."},{"field":"service.target.node.role","type":"keyword","normalization":"","example":"background_tasks","description":"Deprecated role (singular) of the service node."},{"field":"service.target.node.roles","type":"keyword","normalization":"array","example":["ui","background_tasks"],"description":"Roles of the service node."},{"field":"service.target.state","type":"keyword","normalization":"","example":"","description":"Current state of the service."},{"field":"service.target.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.target.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"service.type","type":"keyword","normalization":"","example":"elasticsearch","description":"The type of the service."},{"field":"service.version","type":"keyword","normalization":"","example":"3.2.4","description":"Version of the service."},{"field":"source.address","type":"keyword","normalization":"","example":"","description":"Source network address."},{"field":"source.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"source.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"source.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"source.bytes","type":"long","normalization":"","example":184,"description":"Bytes sent from the source to the destination."},{"field":"source.domain","type":"keyword","normalization":"","example":"foo.example.com","description":"The domain name of the source."},{"field":"source.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"source.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"source.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"source.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"source.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"source.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"source.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"source.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"source.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"source.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"source.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"source.ip","type":"ip","normalization":"","example":"","description":"IP address of the source."},{"field":"source.mac","type":"keyword","normalization":"","example":"00-00-5E-00-53-23","description":"MAC address of the source."},{"field":"source.nat.ip","type":"ip","normalization":"","example":"","description":"Source NAT ip"},{"field":"source.nat.port","type":"long","normalization":"","example":"","description":"Source NAT port"},{"field":"source.packets","type":"long","normalization":"","example":12,"description":"Packets sent from the source to the destination."},{"field":"source.port","type":"long","normalization":"","example":"","description":"Port of the source."},{"field":"source.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered source domain, stripped of the subdomain."},{"field":"source.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"source.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"source.user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"source.user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"source.user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"source.user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"source.user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"source.user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"source.user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"source.user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"source.user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"source.user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"source.user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"source.user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"span.id","type":"keyword","normalization":"","example":"3ff9a8981b7ccd5a","description":"Unique identifier of the span within the scope of its trace."},{"field":"threat.enrichments","type":"nested","normalization":"array","example":"","description":"List of objects containing indicators enriching the event."},{"field":"threat.enrichments.indicator","type":"object","normalization":"","example":"","description":"Object containing indicators enriching the event."},{"field":"threat.enrichments.indicator.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"threat.enrichments.indicator.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.enrichments.indicator.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.enrichments.indicator.confidence","type":"keyword","normalization":"","example":"Medium","description":"Indicator confidence rating"},{"field":"threat.enrichments.indicator.description","type":"keyword","normalization":"","example":"IP x.x.x.x was observed delivering the Angler EK.","description":"Indicator description"},{"field":"threat.enrichments.indicator.email.address","type":"keyword","normalization":"","example":"phish@example.com","description":"Indicator email address"},{"field":"threat.enrichments.indicator.file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"threat.enrichments.indicator.file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"threat.enrichments.indicator.file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"threat.enrichments.indicator.file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"threat.enrichments.indicator.file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"threat.enrichments.indicator.file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"threat.enrichments.indicator.file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"threat.enrichments.indicator.file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"threat.enrichments.indicator.file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"threat.enrichments.indicator.file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"threat.enrichments.indicator.file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"threat.enrichments.indicator.file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"threat.enrichments.indicator.file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"threat.enrichments.indicator.file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"threat.enrichments.indicator.file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"threat.enrichments.indicator.file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"threat.enrichments.indicator.file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"threat.enrichments.indicator.file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"threat.enrichments.indicator.file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.enrichments.indicator.file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.enrichments.indicator.file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"threat.enrichments.indicator.file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"threat.enrichments.indicator.file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"threat.enrichments.indicator.file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"threat.enrichments.indicator.file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"threat.enrichments.indicator.file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"threat.enrichments.indicator.file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"threat.enrichments.indicator.file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"threat.enrichments.indicator.file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"threat.enrichments.indicator.file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"threat.enrichments.indicator.file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"threat.enrichments.indicator.file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"threat.enrichments.indicator.file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"threat.enrichments.indicator.file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"threat.enrichments.indicator.file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"threat.enrichments.indicator.file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"threat.enrichments.indicator.file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"threat.enrichments.indicator.file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"threat.enrichments.indicator.file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"threat.enrichments.indicator.file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"threat.enrichments.indicator.file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"threat.enrichments.indicator.file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"threat.enrichments.indicator.file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"threat.enrichments.indicator.file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"threat.enrichments.indicator.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"threat.enrichments.indicator.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"threat.enrichments.indicator.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"threat.enrichments.indicator.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"threat.enrichments.indicator.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"threat.enrichments.indicator.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"threat.enrichments.indicator.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"threat.enrichments.indicator.file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"threat.enrichments.indicator.file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"threat.enrichments.indicator.file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"threat.enrichments.indicator.file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"threat.enrichments.indicator.file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"threat.enrichments.indicator.file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"threat.enrichments.indicator.file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.enrichments.indicator.file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.enrichments.indicator.file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"threat.enrichments.indicator.file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"threat.enrichments.indicator.file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.enrichments.indicator.file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.enrichments.indicator.file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.enrichments.indicator.file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"threat.enrichments.indicator.file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.enrichments.indicator.file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"threat.enrichments.indicator.file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"threat.enrichments.indicator.file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"threat.enrichments.indicator.file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"threat.enrichments.indicator.file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"threat.enrichments.indicator.file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.enrichments.indicator.file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"threat.enrichments.indicator.file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"threat.enrichments.indicator.file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.enrichments.indicator.file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.enrichments.indicator.file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"threat.enrichments.indicator.file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"threat.enrichments.indicator.file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.enrichments.indicator.file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.enrichments.indicator.file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.enrichments.indicator.file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.enrichments.indicator.file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.enrichments.indicator.file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.enrichments.indicator.file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.enrichments.indicator.file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.enrichments.indicator.file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.enrichments.indicator.file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.enrichments.indicator.file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.enrichments.indicator.file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.enrichments.indicator.file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.enrichments.indicator.file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.enrichments.indicator.file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.enrichments.indicator.first_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was first reported."},{"field":"threat.enrichments.indicator.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"threat.enrichments.indicator.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"threat.enrichments.indicator.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"threat.enrichments.indicator.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"threat.enrichments.indicator.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"threat.enrichments.indicator.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"threat.enrichments.indicator.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"threat.enrichments.indicator.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"threat.enrichments.indicator.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"threat.enrichments.indicator.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"threat.enrichments.indicator.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"threat.enrichments.indicator.ip","type":"ip","normalization":"","example":"1.2.3.4","description":"Indicator IP address"},{"field":"threat.enrichments.indicator.last_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last reported."},{"field":"threat.enrichments.indicator.marking.tlp","type":"keyword","normalization":"","example":"CLEAR","description":"Indicator TLP marking"},{"field":"threat.enrichments.indicator.marking.tlp_version","type":"keyword","normalization":"","example":2,"description":"Indicator TLP version"},{"field":"threat.enrichments.indicator.modified_at","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last updated."},{"field":"threat.enrichments.indicator.name","type":"keyword","normalization":"","example":"5.2.75.227","description":"Indicator display name"},{"field":"threat.enrichments.indicator.port","type":"long","normalization":"","example":443,"description":"Indicator port"},{"field":"threat.enrichments.indicator.provider","type":"keyword","normalization":"","example":"lrz_urlhaus","description":"Indicator provider"},{"field":"threat.enrichments.indicator.reference","type":"keyword","normalization":"","example":"https://system.example.com/indicator/0001234","description":"Indicator reference URL"},{"field":"threat.enrichments.indicator.registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"threat.enrichments.indicator.registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"threat.enrichments.indicator.registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"threat.enrichments.indicator.registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"threat.enrichments.indicator.registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"threat.enrichments.indicator.registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"threat.enrichments.indicator.registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"threat.enrichments.indicator.scanner_stats","type":"long","normalization":"","example":4,"description":"Scanner statistics"},{"field":"threat.enrichments.indicator.sightings","type":"long","normalization":"","example":20,"description":"Number of times indicator observed"},{"field":"threat.enrichments.indicator.type","type":"keyword","normalization":"","example":"ipv4-addr","description":"Type of indicator"},{"field":"threat.enrichments.indicator.url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"threat.enrichments.indicator.url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"threat.enrichments.indicator.url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"threat.enrichments.indicator.url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.enrichments.indicator.url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.enrichments.indicator.url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.enrichments.indicator.url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.enrichments.indicator.url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"threat.enrichments.indicator.url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"threat.enrichments.indicator.url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"threat.enrichments.indicator.url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"threat.enrichments.indicator.url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"threat.enrichments.indicator.url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"threat.enrichments.indicator.url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"threat.enrichments.indicator.url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"threat.enrichments.indicator.url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"threat.enrichments.indicator.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.enrichments.indicator.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.enrichments.indicator.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.enrichments.indicator.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.enrichments.indicator.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.enrichments.indicator.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.enrichments.indicator.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.enrichments.indicator.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.enrichments.indicator.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.enrichments.indicator.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.enrichments.indicator.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.enrichments.indicator.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.enrichments.indicator.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.enrichments.indicator.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.enrichments.indicator.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.enrichments.indicator.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.enrichments.indicator.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.enrichments.indicator.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.enrichments.indicator.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.enrichments.matched.atomic","type":"keyword","normalization":"","example":"bad-domain.com","description":"Matched indicator value"},{"field":"threat.enrichments.matched.field","type":"keyword","normalization":"","example":"file.hash.sha256","description":"Matched indicator field"},{"field":"threat.enrichments.matched.id","type":"keyword","normalization":"","example":"ff93aee5-86a1-4a61-b0e6-0cdc313d01b5","description":"Matched indicator identifier"},{"field":"threat.enrichments.matched.index","type":"keyword","normalization":"","example":"filebeat-8.0.0-2021.05.23-000011","description":"Matched indicator index"},{"field":"threat.enrichments.matched.occurred","type":"date","normalization":"","example":"2021-10-05T17:00:58.326Z","description":"Date of match"},{"field":"threat.enrichments.matched.type","type":"keyword","normalization":"","example":"indicator_match_rule","description":"Type of indicator match"},{"field":"threat.feed.dashboard_id","type":"keyword","normalization":"","example":"5ba16340-72e6-11eb-a3e3-b3cc7c78a70f","description":"Feed dashboard ID."},{"field":"threat.feed.description","type":"keyword","normalization":"","example":"Threat feed from the AlienVault Open Threat eXchange network.","description":"Description of the threat feed."},{"field":"threat.feed.name","type":"keyword","normalization":"","example":"AlienVault OTX","description":"Name of the threat feed."},{"field":"threat.feed.reference","type":"keyword","normalization":"","example":"https://otx.alienvault.com","description":"Reference for the threat feed."},{"field":"threat.framework","type":"keyword","normalization":"","example":"MITRE ATT&CK","description":"Threat classification framework."},{"field":"threat.group.alias","type":"keyword","normalization":"array","example":["Magecart Group 6"],"description":"Alias of the group."},{"field":"threat.group.id","type":"keyword","normalization":"","example":"G0037","description":"ID of the group."},{"field":"threat.group.name","type":"keyword","normalization":"","example":"FIN6","description":"Name of the group."},{"field":"threat.group.reference","type":"keyword","normalization":"","example":"https://attack.mitre.org/groups/G0037/","description":"Reference URL of the group."},{"field":"threat.indicator.as.number","type":"long","normalization":"","example":15169,"description":"Unique number allocated to the autonomous system."},{"field":"threat.indicator.as.organization.name","type":"keyword","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.indicator.as.organization.name.text","type":"match_only_text","normalization":"","example":"Google LLC","description":"Organization name."},{"field":"threat.indicator.confidence","type":"keyword","normalization":"","example":"Medium","description":"Indicator confidence rating"},{"field":"threat.indicator.description","type":"keyword","normalization":"","example":"IP x.x.x.x was observed delivering the Angler EK.","description":"Indicator description"},{"field":"threat.indicator.email.address","type":"keyword","normalization":"","example":"phish@example.com","description":"Indicator email address"},{"field":"threat.indicator.file.accessed","type":"date","normalization":"","example":"","description":"Last time the file was accessed."},{"field":"threat.indicator.file.attributes","type":"keyword","normalization":"array","example":["readonly","system"],"description":"Array of file attributes."},{"field":"threat.indicator.file.code_signature.digest_algorithm","type":"keyword","normalization":"","example":"sha256","description":"Hashing algorithm used to sign the process."},{"field":"threat.indicator.file.code_signature.exists","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if a signature is present."},{"field":"threat.indicator.file.code_signature.signing_id","type":"keyword","normalization":"","example":"com.apple.xpc.proxy","description":"The identifier used to sign the process."},{"field":"threat.indicator.file.code_signature.status","type":"keyword","normalization":"","example":"ERROR_UNTRUSTED_ROOT","description":"Additional information about the certificate status."},{"field":"threat.indicator.file.code_signature.subject_name","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Subject name of the code signer"},{"field":"threat.indicator.file.code_signature.team_id","type":"keyword","normalization":"","example":"EQHXZ8M8AV","description":"The team identifier used to sign the process."},{"field":"threat.indicator.file.code_signature.timestamp","type":"date","normalization":"","example":"2021-01-01T12:10:30Z","description":"When the signature was generated and signed."},{"field":"threat.indicator.file.code_signature.trusted","type":"boolean","normalization":"","example":true,"description":"Stores the trust status of the certificate chain."},{"field":"threat.indicator.file.code_signature.valid","type":"boolean","normalization":"","example":true,"description":"Boolean to capture if the digital signature is verified against the binary content."},{"field":"threat.indicator.file.created","type":"date","normalization":"","example":"","description":"File creation time."},{"field":"threat.indicator.file.ctime","type":"date","normalization":"","example":"","description":"Last time the file attributes or metadata changed."},{"field":"threat.indicator.file.device","type":"keyword","normalization":"","example":"sda","description":"Device that is the source of the file."},{"field":"threat.indicator.file.directory","type":"keyword","normalization":"","example":"/home/alice","description":"Directory where the file is located."},{"field":"threat.indicator.file.drive_letter","type":"keyword","normalization":"","example":"C","description":"Drive letter where the file is located."},{"field":"threat.indicator.file.elf.architecture","type":"keyword","normalization":"","example":"x86-64","description":"Machine architecture of the ELF file."},{"field":"threat.indicator.file.elf.byte_order","type":"keyword","normalization":"","example":"Little Endian","description":"Byte sequence of ELF file."},{"field":"threat.indicator.file.elf.cpu_type","type":"keyword","normalization":"","example":"Intel","description":"CPU type of the ELF file."},{"field":"threat.indicator.file.elf.creation_date","type":"date","normalization":"","example":"","description":"Build or compile date."},{"field":"threat.indicator.file.elf.exports","type":"flattened","normalization":"array","example":"","description":"List of exported element names and types."},{"field":"threat.indicator.file.elf.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in an ELF file."},{"field":"threat.indicator.file.elf.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.indicator.file.elf.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.elf.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.elf.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.indicator.file.elf.header.abi_version","type":"keyword","normalization":"","example":"","description":"Version of the ELF Application Binary Interface (ABI)."},{"field":"threat.indicator.file.elf.header.class","type":"keyword","normalization":"","example":"","description":"Header class of the ELF file."},{"field":"threat.indicator.file.elf.header.data","type":"keyword","normalization":"","example":"","description":"Data table of the ELF header."},{"field":"threat.indicator.file.elf.header.entrypoint","type":"long","normalization":"","example":"","description":"Header entrypoint of the ELF file."},{"field":"threat.indicator.file.elf.header.object_version","type":"keyword","normalization":"","example":"","description":"0x1\" for original ELF files."},{"field":"threat.indicator.file.elf.header.os_abi","type":"keyword","normalization":"","example":"","description":"Application Binary Interface (ABI) of the Linux OS."},{"field":"threat.indicator.file.elf.header.type","type":"keyword","normalization":"","example":"","description":"Header type of the ELF file."},{"field":"threat.indicator.file.elf.header.version","type":"keyword","normalization":"","example":"","description":"Version of the ELF header."},{"field":"threat.indicator.file.elf.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in an ELF file."},{"field":"threat.indicator.file.elf.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.indicator.file.elf.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.elf.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.elf.sections","type":"nested","normalization":"array","example":"","description":"Section information of the ELF file."},{"field":"threat.indicator.file.elf.sections.chi2","type":"long","normalization":"","example":"","description":"Chi-square probability distribution of the section."},{"field":"threat.indicator.file.elf.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.indicator.file.elf.sections.flags","type":"keyword","normalization":"","example":"","description":"ELF Section List flags."},{"field":"threat.indicator.file.elf.sections.name","type":"keyword","normalization":"","example":"","description":"ELF Section List name."},{"field":"threat.indicator.file.elf.sections.physical_offset","type":"keyword","normalization":"","example":"","description":"ELF Section List offset."},{"field":"threat.indicator.file.elf.sections.physical_size","type":"long","normalization":"","example":"","description":"ELF Section List physical size."},{"field":"threat.indicator.file.elf.sections.type","type":"keyword","normalization":"","example":"","description":"ELF Section List type."},{"field":"threat.indicator.file.elf.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.indicator.file.elf.sections.virtual_address","type":"long","normalization":"","example":"","description":"ELF Section List virtual address."},{"field":"threat.indicator.file.elf.sections.virtual_size","type":"long","normalization":"","example":"","description":"ELF Section List virtual size."},{"field":"threat.indicator.file.elf.segments","type":"nested","normalization":"array","example":"","description":"ELF object segment list."},{"field":"threat.indicator.file.elf.segments.sections","type":"keyword","normalization":"","example":"","description":"ELF object segment sections."},{"field":"threat.indicator.file.elf.segments.type","type":"keyword","normalization":"","example":"","description":"ELF object segment type."},{"field":"threat.indicator.file.elf.shared_libraries","type":"keyword","normalization":"array","example":"","description":"List of shared libraries used by this ELF object."},{"field":"threat.indicator.file.elf.telfhash","type":"keyword","normalization":"","example":"","description":"telfhash hash for ELF file."},{"field":"threat.indicator.file.extension","type":"keyword","normalization":"","example":"png","description":"File extension, excluding the leading dot."},{"field":"threat.indicator.file.fork_name","type":"keyword","normalization":"","example":"Zone.Identifer","description":"A fork is additional data associated with a filesystem object."},{"field":"threat.indicator.file.gid","type":"keyword","normalization":"","example":1001,"description":"Primary group ID (GID) of the file."},{"field":"threat.indicator.file.group","type":"keyword","normalization":"","example":"alice","description":"Primary group name of the file."},{"field":"threat.indicator.file.hash.md5","type":"keyword","normalization":"","example":"","description":"MD5 hash."},{"field":"threat.indicator.file.hash.sha1","type":"keyword","normalization":"","example":"","description":"SHA1 hash."},{"field":"threat.indicator.file.hash.sha256","type":"keyword","normalization":"","example":"","description":"SHA256 hash."},{"field":"threat.indicator.file.hash.sha384","type":"keyword","normalization":"","example":"","description":"SHA384 hash."},{"field":"threat.indicator.file.hash.sha512","type":"keyword","normalization":"","example":"","description":"SHA512 hash."},{"field":"threat.indicator.file.hash.ssdeep","type":"keyword","normalization":"","example":"","description":"SSDEEP hash."},{"field":"threat.indicator.file.hash.tlsh","type":"keyword","normalization":"","example":"","description":"TLSH hash."},{"field":"threat.indicator.file.inode","type":"keyword","normalization":"","example":256383,"description":"Inode representing the file in the filesystem."},{"field":"threat.indicator.file.mime_type","type":"keyword","normalization":"","example":"","description":"Media type of file, document, or arrangement of bytes."},{"field":"threat.indicator.file.mode","type":"keyword","normalization":"","example":"0640","description":"Mode of the file in octal representation."},{"field":"threat.indicator.file.mtime","type":"date","normalization":"","example":"","description":"Last time the file content was modified."},{"field":"threat.indicator.file.name","type":"keyword","normalization":"","example":"example.png","description":"Name of the file including the extension, without the directory."},{"field":"threat.indicator.file.owner","type":"keyword","normalization":"","example":"alice","description":"File owner's username."},{"field":"threat.indicator.file.path","type":"keyword","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.indicator.file.path.text","type":"match_only_text","normalization":"","example":"/home/alice/example.png","description":"Full path to the file, including the file name."},{"field":"threat.indicator.file.pe.architecture","type":"keyword","normalization":"","example":"x64","description":"CPU architecture target for the file."},{"field":"threat.indicator.file.pe.company","type":"keyword","normalization":"","example":"Microsoft Corporation","description":"Internal company name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.description","type":"keyword","normalization":"","example":"Paint","description":"Internal description of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.file_version","type":"keyword","normalization":"","example":"6.3.9600.17415","description":"Process name."},{"field":"threat.indicator.file.pe.go_import_hash","type":"keyword","normalization":"","example":"10bddcb4cee42080f76c88d9ff964491","description":"A hash of the Go language imports in a PE file."},{"field":"threat.indicator.file.pe.go_imports","type":"flattened","normalization":"","example":"","description":"List of imported Go language element names and types."},{"field":"threat.indicator.file.pe.go_imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.pe.go_imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of Go imports."},{"field":"threat.indicator.file.pe.go_stripped","type":"boolean","normalization":"","example":"","description":"Whether the file is a stripped or obfuscated Go executable."},{"field":"threat.indicator.file.pe.imphash","type":"keyword","normalization":"","example":"0c6803c4e922103c4dca5963aad36ddf","description":"A hash of the imports in a PE file."},{"field":"threat.indicator.file.pe.import_hash","type":"keyword","normalization":"","example":"d41d8cd98f00b204e9800998ecf8427e","description":"A hash of the imports in a PE file."},{"field":"threat.indicator.file.pe.imports","type":"flattened","normalization":"array","example":"","description":"List of imported element names and types."},{"field":"threat.indicator.file.pe.imports_names_entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.pe.imports_names_var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the list of imported element names and types."},{"field":"threat.indicator.file.pe.original_file_name","type":"keyword","normalization":"","example":"MSPAINT.EXE","description":"Internal name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.pehash","type":"keyword","normalization":"","example":"73ff189b63cd6be375a7ff25179a38d347651975","description":"A hash of the PE header and data from one or more PE sections."},{"field":"threat.indicator.file.pe.product","type":"keyword","normalization":"","example":"Microsoft® Windows® Operating System","description":"Internal product name of the file, provided at compile-time."},{"field":"threat.indicator.file.pe.sections","type":"nested","normalization":"array","example":"","description":"Section information of the PE file."},{"field":"threat.indicator.file.pe.sections.entropy","type":"long","normalization":"","example":"","description":"Shannon entropy calculation from the section."},{"field":"threat.indicator.file.pe.sections.name","type":"keyword","normalization":"","example":"","description":"PE Section List name."},{"field":"threat.indicator.file.pe.sections.physical_size","type":"long","normalization":"","example":"","description":"PE Section List physical size."},{"field":"threat.indicator.file.pe.sections.var_entropy","type":"long","normalization":"","example":"","description":"Variance for Shannon entropy calculation from the section."},{"field":"threat.indicator.file.pe.sections.virtual_size","type":"long","normalization":"","example":"","description":"PE Section List virtual size. This is always the same as `physical_size`."},{"field":"threat.indicator.file.size","type":"long","normalization":"","example":16384,"description":"File size in bytes."},{"field":"threat.indicator.file.target_path","type":"keyword","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.indicator.file.target_path.text","type":"match_only_text","normalization":"","example":"","description":"Target path for symlinks."},{"field":"threat.indicator.file.type","type":"keyword","normalization":"","example":"file","description":"File type (file, dir, or symlink)."},{"field":"threat.indicator.file.uid","type":"keyword","normalization":"","example":1001,"description":"The user ID (UID) or security identifier (SID) of the file owner."},{"field":"threat.indicator.file.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.indicator.file.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.indicator.file.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.indicator.file.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.indicator.file.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.file.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.indicator.file.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.indicator.file.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.indicator.file.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.indicator.file.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.indicator.file.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.indicator.file.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.indicator.file.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.indicator.file.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.indicator.file.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.indicator.file.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.indicator.file.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.indicator.file.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.indicator.file.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.indicator.file.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.file.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.indicator.first_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was first reported."},{"field":"threat.indicator.geo.city_name","type":"keyword","normalization":"","example":"Montreal","description":"City name."},{"field":"threat.indicator.geo.continent_code","type":"keyword","normalization":"","example":"NA","description":"Continent code."},{"field":"threat.indicator.geo.continent_name","type":"keyword","normalization":"","example":"North America","description":"Name of the continent."},{"field":"threat.indicator.geo.country_iso_code","type":"keyword","normalization":"","example":"CA","description":"Country ISO code."},{"field":"threat.indicator.geo.country_name","type":"keyword","normalization":"","example":"Canada","description":"Country name."},{"field":"threat.indicator.geo.location","type":"geo_point","normalization":"","example":{"lon":-73.61483,"lat":45.505918},"description":"Longitude and latitude."},{"field":"threat.indicator.geo.name","type":"keyword","normalization":"","example":"boston-dc","description":"User-defined description of a location."},{"field":"threat.indicator.geo.postal_code","type":"keyword","normalization":"","example":94040,"description":"Postal code."},{"field":"threat.indicator.geo.region_iso_code","type":"keyword","normalization":"","example":"CA-QC","description":"Region ISO code."},{"field":"threat.indicator.geo.region_name","type":"keyword","normalization":"","example":"Quebec","description":"Region name."},{"field":"threat.indicator.geo.timezone","type":"keyword","normalization":"","example":"America/Argentina/Buenos_Aires","description":"Time zone."},{"field":"threat.indicator.ip","type":"ip","normalization":"","example":"1.2.3.4","description":"Indicator IP address"},{"field":"threat.indicator.last_seen","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last reported."},{"field":"threat.indicator.marking.tlp","type":"keyword","normalization":"","example":"CLEAR","description":"Indicator TLP marking"},{"field":"threat.indicator.marking.tlp_version","type":"keyword","normalization":"","example":2,"description":"Indicator TLP version"},{"field":"threat.indicator.modified_at","type":"date","normalization":"","example":"2020-11-05T17:25:47.000Z","description":"Date/time indicator was last updated."},{"field":"threat.indicator.name","type":"keyword","normalization":"","example":"5.2.75.227","description":"Indicator display name"},{"field":"threat.indicator.port","type":"long","normalization":"","example":443,"description":"Indicator port"},{"field":"threat.indicator.provider","type":"keyword","normalization":"","example":"lrz_urlhaus","description":"Indicator provider"},{"field":"threat.indicator.reference","type":"keyword","normalization":"","example":"https://system.example.com/indicator/0001234","description":"Indicator reference URL"},{"field":"threat.indicator.registry.data.bytes","type":"keyword","normalization":"","example":"ZQBuAC0AVQBTAAAAZQBuAAAAAAA=","description":"Original bytes written with base64 encoding."},{"field":"threat.indicator.registry.data.strings","type":"wildcard","normalization":"array","example":"[\"C:\\rta\\red_ttp\\bin\\myapp.exe\"]","description":"List of strings representing what was written to the registry."},{"field":"threat.indicator.registry.data.type","type":"keyword","normalization":"","example":"REG_SZ","description":"Standard registry type for encoding contents"},{"field":"threat.indicator.registry.hive","type":"keyword","normalization":"","example":"HKLM","description":"Abbreviated name for the hive."},{"field":"threat.indicator.registry.key","type":"keyword","normalization":"","example":"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe","description":"Hive-relative path of keys."},{"field":"threat.indicator.registry.path","type":"keyword","normalization":"","example":"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger","description":"Full path, including hive, key and value"},{"field":"threat.indicator.registry.value","type":"keyword","normalization":"","example":"Debugger","description":"Name of the value written."},{"field":"threat.indicator.scanner_stats","type":"long","normalization":"","example":4,"description":"Scanner statistics"},{"field":"threat.indicator.sightings","type":"long","normalization":"","example":20,"description":"Number of times indicator observed"},{"field":"threat.indicator.type","type":"keyword","normalization":"","example":"ipv4-addr","description":"Type of indicator"},{"field":"threat.indicator.url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"threat.indicator.url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"threat.indicator.url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"threat.indicator.url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.indicator.url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"threat.indicator.url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.indicator.url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"threat.indicator.url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"threat.indicator.url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"threat.indicator.url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"threat.indicator.url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"threat.indicator.url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"threat.indicator.url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"threat.indicator.url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"threat.indicator.url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"threat.indicator.url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"threat.indicator.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"threat.indicator.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"threat.indicator.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"threat.indicator.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"threat.indicator.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"threat.indicator.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"threat.indicator.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"threat.indicator.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"threat.indicator.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"threat.indicator.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"threat.indicator.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"threat.indicator.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"threat.indicator.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"threat.indicator.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"threat.indicator.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"threat.indicator.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"threat.indicator.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"threat.indicator.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"threat.indicator.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"threat.indicator.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"threat.software.alias","type":"keyword","normalization":"array","example":["X-Agent"],"description":"Alias of the software"},{"field":"threat.software.id","type":"keyword","normalization":"","example":"S0552","description":"ID of the software"},{"field":"threat.software.name","type":"keyword","normalization":"","example":"AdFind","description":"Name of the software."},{"field":"threat.software.platforms","type":"keyword","normalization":"array","example":["Windows"],"description":"Platforms of the software."},{"field":"threat.software.reference","type":"keyword","normalization":"","example":"https://attack.mitre.org/software/S0552/","description":"Software reference URL."},{"field":"threat.software.type","type":"keyword","normalization":"","example":"Tool","description":"Software type."},{"field":"threat.tactic.id","type":"keyword","normalization":"array","example":"TA0002","description":"Threat tactic id."},{"field":"threat.tactic.name","type":"keyword","normalization":"array","example":"Execution","description":"Threat tactic."},{"field":"threat.tactic.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/tactics/TA0002/","description":"Threat tactic URL reference."},{"field":"threat.technique.id","type":"keyword","normalization":"array","example":"T1059","description":"Threat technique id."},{"field":"threat.technique.name","type":"keyword","normalization":"array","example":"Command and Scripting Interpreter","description":"Threat technique name."},{"field":"threat.technique.name.text","type":"match_only_text","normalization":"","example":"Command and Scripting Interpreter","description":"Threat technique name."},{"field":"threat.technique.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/techniques/T1059/","description":"Threat technique URL reference."},{"field":"threat.technique.subtechnique.id","type":"keyword","normalization":"array","example":"T1059.001","description":"Threat subtechnique id."},{"field":"threat.technique.subtechnique.name","type":"keyword","normalization":"array","example":"PowerShell","description":"Threat subtechnique name."},{"field":"threat.technique.subtechnique.name.text","type":"match_only_text","normalization":"","example":"PowerShell","description":"Threat subtechnique name."},{"field":"threat.technique.subtechnique.reference","type":"keyword","normalization":"array","example":"https://attack.mitre.org/techniques/T1059/001/","description":"Threat subtechnique URL reference."},{"field":"tls.cipher","type":"keyword","normalization":"","example":"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","description":"String indicating the cipher used during the current connection."},{"field":"tls.client.certificate","type":"keyword","normalization":"","example":"MII...","description":"PEM-encoded stand-alone certificate offered by the client."},{"field":"tls.client.certificate_chain","type":"keyword","normalization":"array","example":["MII...","MII..."],"description":"Array of PEM-encoded certificates that make up the certificate chain offered by the client."},{"field":"tls.client.hash.md5","type":"keyword","normalization":"","example":"0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC","description":"Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.hash.sha1","type":"keyword","normalization":"","example":"9E393D93138888D288266C2D915214D1D1CCEB2A","description":"Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.hash.sha256","type":"keyword","normalization":"","example":"0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0","description":"Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client."},{"field":"tls.client.issuer","type":"keyword","normalization":"","example":"CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com","description":"Distinguished name of subject of the issuer of the x.509 certificate presented by the client."},{"field":"tls.client.ja3","type":"keyword","normalization":"","example":"d4e5b18d6b55c71272893221c96ba240","description":"A hash that identifies clients based on how they perform an SSL/TLS handshake."},{"field":"tls.client.not_after","type":"date","normalization":"","example":"2021-01-01T00:00:00.000Z","description":"Date/Time indicating when client certificate is no longer considered valid."},{"field":"tls.client.not_before","type":"date","normalization":"","example":"1970-01-01T00:00:00.000Z","description":"Date/Time indicating when client certificate is first considered valid."},{"field":"tls.client.server_name","type":"keyword","normalization":"","example":"www.elastic.co","description":"Hostname the client is trying to connect to. Also called the SNI."},{"field":"tls.client.subject","type":"keyword","normalization":"","example":"CN=myclient, OU=Documentation Team, DC=example, DC=com","description":"Distinguished name of subject of the x.509 certificate presented by the client."},{"field":"tls.client.supported_ciphers","type":"keyword","normalization":"array","example":["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","..."],"description":"Array of ciphers offered by the client during the client hello."},{"field":"tls.client.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"tls.client.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"tls.client.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"tls.client.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"tls.client.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"tls.client.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"tls.client.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"tls.client.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.client.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"tls.client.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"tls.client.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"tls.client.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"tls.client.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"tls.client.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"tls.client.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"tls.client.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"tls.client.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"tls.client.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"tls.client.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"tls.client.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"tls.client.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"tls.client.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"tls.client.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.client.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"tls.curve","type":"keyword","normalization":"","example":"secp256r1","description":"String indicating the curve used for the given cipher, when applicable."},{"field":"tls.established","type":"boolean","normalization":"","example":"","description":"Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel."},{"field":"tls.next_protocol","type":"keyword","normalization":"","example":"http/1.1","description":"String indicating the protocol being tunneled."},{"field":"tls.resumed","type":"boolean","normalization":"","example":"","description":"Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation."},{"field":"tls.server.certificate","type":"keyword","normalization":"","example":"MII...","description":"PEM-encoded stand-alone certificate offered by the server."},{"field":"tls.server.certificate_chain","type":"keyword","normalization":"array","example":["MII...","MII..."],"description":"Array of PEM-encoded certificates that make up the certificate chain offered by the server."},{"field":"tls.server.hash.md5","type":"keyword","normalization":"","example":"0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC","description":"Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.hash.sha1","type":"keyword","normalization":"","example":"9E393D93138888D288266C2D915214D1D1CCEB2A","description":"Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.hash.sha256","type":"keyword","normalization":"","example":"0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0","description":"Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server."},{"field":"tls.server.issuer","type":"keyword","normalization":"","example":"CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com","description":"Subject of the issuer of the x.509 certificate presented by the server."},{"field":"tls.server.ja3s","type":"keyword","normalization":"","example":"394441ab65754e2207b1e1b457b3641d","description":"A hash that identifies servers based on how they perform an SSL/TLS handshake."},{"field":"tls.server.not_after","type":"date","normalization":"","example":"2021-01-01T00:00:00.000Z","description":"Timestamp indicating when server certificate is no longer considered valid."},{"field":"tls.server.not_before","type":"date","normalization":"","example":"1970-01-01T00:00:00.000Z","description":"Timestamp indicating when server certificate is first considered valid."},{"field":"tls.server.subject","type":"keyword","normalization":"","example":"CN=www.example.com, OU=Infrastructure Team, DC=example, DC=com","description":"Subject of the x.509 certificate presented by the server."},{"field":"tls.server.x509.alternative_names","type":"keyword","normalization":"array","example":"*.elastic.co","description":"List of subject alternative names (SAN)."},{"field":"tls.server.x509.issuer.common_name","type":"keyword","normalization":"array","example":"Example SHA2 High Assurance Server CA","description":"List of common name (CN) of issuing certificate authority."},{"field":"tls.server.x509.issuer.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) codes"},{"field":"tls.server.x509.issuer.distinguished_name","type":"keyword","normalization":"","example":"C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA","description":"Distinguished name (DN) of issuing certificate authority."},{"field":"tls.server.x509.issuer.locality","type":"keyword","normalization":"array","example":"Mountain View","description":"List of locality names (L)"},{"field":"tls.server.x509.issuer.organization","type":"keyword","normalization":"array","example":"Example Inc","description":"List of organizations (O) of issuing certificate authority."},{"field":"tls.server.x509.issuer.organizational_unit","type":"keyword","normalization":"array","example":"www.example.com","description":"List of organizational units (OU) of issuing certificate authority."},{"field":"tls.server.x509.issuer.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.server.x509.not_after","type":"date","normalization":"","example":"2020-07-16T03:15:39Z","description":"Time at which the certificate is no longer considered valid."},{"field":"tls.server.x509.not_before","type":"date","normalization":"","example":"2019-08-16T01:40:25Z","description":"Time at which the certificate is first considered valid."},{"field":"tls.server.x509.public_key_algorithm","type":"keyword","normalization":"","example":"RSA","description":"Algorithm used to generate the public key."},{"field":"tls.server.x509.public_key_curve","type":"keyword","normalization":"","example":"nistp521","description":"The curve used by the elliptic curve public key algorithm. This is algorithm specific."},{"field":"tls.server.x509.public_key_exponent","type":"long","normalization":"","example":65537,"description":"Exponent used to derive the public key. This is algorithm specific."},{"field":"tls.server.x509.public_key_size","type":"long","normalization":"","example":2048,"description":"The size of the public key space in bits."},{"field":"tls.server.x509.serial_number","type":"keyword","normalization":"","example":"55FBB9C7DEBF09809D12CCAA","description":"Unique serial number issued by the certificate authority."},{"field":"tls.server.x509.signature_algorithm","type":"keyword","normalization":"","example":"SHA256-RSA","description":"Identifier for certificate signature algorithm."},{"field":"tls.server.x509.subject.common_name","type":"keyword","normalization":"array","example":"shared.global.example.net","description":"List of common names (CN) of subject."},{"field":"tls.server.x509.subject.country","type":"keyword","normalization":"array","example":"US","description":"List of country \\(C) code"},{"field":"tls.server.x509.subject.distinguished_name","type":"keyword","normalization":"","example":"C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net","description":"Distinguished name (DN) of the certificate subject entity."},{"field":"tls.server.x509.subject.locality","type":"keyword","normalization":"array","example":"San Francisco","description":"List of locality names (L)"},{"field":"tls.server.x509.subject.organization","type":"keyword","normalization":"array","example":"Example, Inc.","description":"List of organizations (O) of subject."},{"field":"tls.server.x509.subject.organizational_unit","type":"keyword","normalization":"array","example":"","description":"List of organizational units (OU) of subject."},{"field":"tls.server.x509.subject.state_or_province","type":"keyword","normalization":"array","example":"California","description":"List of state or province names (ST, S, or P)"},{"field":"tls.server.x509.version_number","type":"keyword","normalization":"","example":3,"description":"Version of x509 format."},{"field":"tls.version","type":"keyword","normalization":"","example":1.2,"description":"Numeric part of the version parsed from the original string."},{"field":"tls.version_protocol","type":"keyword","normalization":"","example":"tls","description":"Normalized lowercase protocol name parsed from original string."},{"field":"trace.id","type":"keyword","normalization":"","example":"4bf92f3577b34da6a3ce929d0e0e4736","description":"Unique identifier of the trace."},{"field":"transaction.id","type":"keyword","normalization":"","example":"00f067aa0ba902b7","description":"Unique identifier of the transaction within the scope of its trace."},{"field":"url.domain","type":"keyword","normalization":"","example":"www.elastic.co","description":"Domain of the url."},{"field":"url.extension","type":"keyword","normalization":"","example":"png","description":"File extension from the request url, excluding the leading dot."},{"field":"url.fragment","type":"keyword","normalization":"","example":"","description":"Portion of the url after the `#`."},{"field":"url.full","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"url.full.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top","description":"Full unparsed URL."},{"field":"url.original","type":"wildcard","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"url.original.text","type":"match_only_text","normalization":"","example":"https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch","description":"Unmodified original url as seen in the event source."},{"field":"url.password","type":"keyword","normalization":"","example":"","description":"Password of the request."},{"field":"url.path","type":"wildcard","normalization":"","example":"","description":"Path of the request, such as \"/search\"."},{"field":"url.port","type":"long","normalization":"","example":443,"description":"Port of the request, such as 443."},{"field":"url.query","type":"keyword","normalization":"","example":"","description":"Query string of the request."},{"field":"url.registered_domain","type":"keyword","normalization":"","example":"example.com","description":"The highest registered url domain, stripped of the subdomain."},{"field":"url.scheme","type":"keyword","normalization":"","example":"https","description":"Scheme of the url."},{"field":"url.subdomain","type":"keyword","normalization":"","example":"east","description":"The subdomain of the domain."},{"field":"url.top_level_domain","type":"keyword","normalization":"","example":"co.uk","description":"The effective top level domain (com, org, net, co.uk)."},{"field":"url.username","type":"keyword","normalization":"","example":"","description":"Username of the request."},{"field":"user.changes.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.changes.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.changes.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.changes.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.changes.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.changes.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.changes.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.changes.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.changes.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.changes.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.changes.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.changes.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.effective.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.effective.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.effective.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.effective.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.effective.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.effective.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.effective.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.effective.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.effective.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.effective.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.effective.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.effective.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.risk.calculated_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"user.risk.calculated_score","type":"float","normalization":"","example":880.73,"description":"A risk classification score calculated by an internal system as part of entity analytics and entity risk scoring."},{"field":"user.risk.calculated_score_norm","type":"float","normalization":"","example":88.73,"description":"A normalized risk score calculated by an internal system."},{"field":"user.risk.static_level","type":"keyword","normalization":"","example":"High","description":"A risk classification level obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"user.risk.static_score","type":"float","normalization":"","example":830,"description":"A risk classification score obtained from outside the system, such as from some external Threat Intelligence Platform."},{"field":"user.risk.static_score_norm","type":"float","normalization":"","example":83,"description":"A normalized risk score calculated by an external system."},{"field":"user.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user.target.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the user is a member of."},{"field":"user.target.email","type":"keyword","normalization":"","example":"","description":"User email address."},{"field":"user.target.full_name","type":"keyword","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.target.full_name.text","type":"match_only_text","normalization":"","example":"Albert Einstein","description":"User's full name, if available."},{"field":"user.target.group.domain","type":"keyword","normalization":"","example":"","description":"Name of the directory the group is a member of."},{"field":"user.target.group.id","type":"keyword","normalization":"","example":"","description":"Unique identifier for the group on the system/platform."},{"field":"user.target.group.name","type":"keyword","normalization":"","example":"","description":"Name of the group."},{"field":"user.target.hash","type":"keyword","normalization":"","example":"","description":"Unique user hash to correlate information for a user in anonymized form."},{"field":"user.target.id","type":"keyword","normalization":"","example":"S-1-5-21-202424912787-2692429404-2351956786-1000","description":"Unique identifier of the user."},{"field":"user.target.name","type":"keyword","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.target.name.text","type":"match_only_text","normalization":"","example":"a.einstein","description":"Short name or login of the user."},{"field":"user.target.roles","type":"keyword","normalization":"array","example":["kibana_admin","reporting_user"],"description":"Array of user roles at the time of the event."},{"field":"user_agent.device.name","type":"keyword","normalization":"","example":"iPhone","description":"Name of the device."},{"field":"user_agent.name","type":"keyword","normalization":"","example":"Safari","description":"Name of the user agent."},{"field":"user_agent.original","type":"keyword","normalization":"","example":"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1","description":"Unparsed user_agent string."},{"field":"user_agent.original.text","type":"match_only_text","normalization":"","example":"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1","description":"Unparsed user_agent string."},{"field":"user_agent.os.family","type":"keyword","normalization":"","example":"debian","description":"OS family (such as redhat, debian, freebsd, windows)."},{"field":"user_agent.os.full","type":"keyword","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"user_agent.os.full.text","type":"match_only_text","normalization":"","example":"Mac OS Mojave","description":"Operating system name, including the version or code name."},{"field":"user_agent.os.kernel","type":"keyword","normalization":"","example":"4.4.0-112-generic","description":"Operating system kernel version as a raw string."},{"field":"user_agent.os.name","type":"keyword","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"user_agent.os.name.text","type":"match_only_text","normalization":"","example":"Mac OS X","description":"Operating system name, without the version."},{"field":"user_agent.os.platform","type":"keyword","normalization":"","example":"darwin","description":"Operating system platform (such centos, ubuntu, windows)."},{"field":"user_agent.os.type","type":"keyword","normalization":"","example":"macos","description":"Which commercial OS family (one of: linux, macos, unix, windows, ios or android)."},{"field":"user_agent.os.version","type":"keyword","normalization":"","example":"10.14.1","description":"Operating system version as a raw string."},{"field":"user_agent.version","type":"keyword","normalization":"","example":12,"description":"Version of the user agent."},{"field":"vulnerability.category","type":"keyword","normalization":"array","example":["Firewall"],"description":"Category of a vulnerability."},{"field":"vulnerability.classification","type":"keyword","normalization":"","example":"CVSS","description":"Classification of the vulnerability."},{"field":"vulnerability.description","type":"keyword","normalization":"","example":"In macOS before 2.12.6, there is a vulnerability in the RPC...","description":"Description of the vulnerability."},{"field":"vulnerability.description.text","type":"match_only_text","normalization":"","example":"In macOS before 2.12.6, there is a vulnerability in the RPC...","description":"Description of the vulnerability."},{"field":"vulnerability.enumeration","type":"keyword","normalization":"","example":"CVE","description":"Identifier of the vulnerability."},{"field":"vulnerability.id","type":"keyword","normalization":"","example":"CVE-2019-00001","description":"ID of the vulnerability."},{"field":"vulnerability.reference","type":"keyword","normalization":"","example":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111","description":"Reference of the vulnerability."},{"field":"vulnerability.report_id","type":"keyword","normalization":"","example":20191018.0001,"description":"Scan identification number."},{"field":"vulnerability.scanner.vendor","type":"keyword","normalization":"","example":"Tenable","description":"Name of the scanner vendor."},{"field":"vulnerability.score.base","type":"float","normalization":"","example":5.5,"description":"Vulnerability Base score."},{"field":"vulnerability.score.environmental","type":"float","normalization":"","example":5.5,"description":"Vulnerability Environmental score."},{"field":"vulnerability.score.temporal","type":"float","normalization":"","example":"","description":"Vulnerability Temporal score."},{"field":"vulnerability.score.version","type":"keyword","normalization":"","example":2,"description":"CVSS version."},{"field":"vulnerability.severity","type":"keyword","normalization":"","example":"Critical","description":"Severity of the vulnerability."}] \ No newline at end of file diff --git a/x-pack/plugins/osquery/public/common/schemas/osquery/v5.10.2.json b/x-pack/plugins/osquery/public/common/schemas/osquery/v5.10.2.json new file mode 100644 index 000000000000..41b1607e995c --- /dev/null +++ b/x-pack/plugins/osquery/public/common/schemas/osquery/v5.10.2.json @@ -0,0 +1 @@ +[{"name":"account_policy_data","description":"Additional macOS user account data from the AccountPolicy section of OpenDirectory.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the account was first created","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_login_count","description":"The number of failed login attempts using an incorrect password. Count resets after a correct password is entered.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_login_timestamp","description":"The time of the last failed login attempt. Resets after a correct password is entered","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"password_last_set_time","description":"The time the password was last changed","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"acpi_tables","description":"Firmware ACPI functional table common metadata and content.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"ACPI table name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of compiled table data","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table content","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ad_config","description":"macOS Active Directory configuration.","platforms":["darwin"],"columns":[{"name":"name","description":"The macOS-specific configuration name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain","description":"Active Directory trust domain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option","description":"Canonical name of option","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Variable typed option value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf","description":"macOS application layer firewall (ALF) service details.","platforms":["darwin"],"columns":[{"name":"allow_signed_enabled","description":"1 If allow signed mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"firewall_unload","description":"1 If firewall unloading enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"global_state","description":"1 If the firewall is enabled with exceptions, 2 if the firewall is configured to block all incoming connections, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_enabled","description":"1 If logging mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_option","description":"Firewall logging option","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"stealth_enabled","description":"1 If stealth mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Application Layer Firewall version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf_exceptions","description":"macOS application layer firewall (ALF) service exceptions.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to the executable that is excepted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Firewall exception state","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf_explicit_auths","description":"ALF services explicitly allowed to perform networking.","platforms":["darwin"],"columns":[{"name":"process","description":"Process name explicitly allowed","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"app_schemes","description":"macOS application schemes and handlers (e.g., http, file, mailto).","platforms":["darwin"],"columns":[{"name":"scheme","description":"Name of the scheme/protocol","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"handler","description":"Application label for the handler","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this handler is the OS default, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"external","description":"1 if this handler does NOT exist on macOS by default, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protected","description":"1 if this handler is protected (reserved) by macOS, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apparmor_events","description":"Track AppArmor events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Raw audit message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"apparmor","description":"Apparmor Status like ALLOWED, DENIED etc.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"operation","description":"Permission requested by the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process PID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"profile","description":"Apparmor profile name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"denied_mask","description":"Denied permissions for the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"capname","description":"Capability requested by the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ouid","description":"Object owner's user ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"capability","description":"Capability number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"requested_mask","description":"Requested access mask","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info","description":"Additional information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error","description":"Error information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"namespace","description":"AppArmor namespace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"AppArmor label","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apparmor_profiles","description":"Track active AppArmor profiles.","platforms":["linux"],"columns":[{"name":"path","description":"Unique, aa-status compatible, policy identifier.","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Policy name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"attach","description":"Which executable(s) a profile will attach to.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"How the policy is applied.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"A unique hash that identifies this policy.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"appcompat_shims","description":"Application Compatibility shims are a way to persist malware. This table presents the AppCompat Shim information from the registry in a nice format. See http://files.brucon.org/2015/Tomczak_and_Ballenthin_Shims_for_the_Win.pdf for more details.","platforms":["windows"],"columns":[{"name":"executable","description":"Name of the executable that is being shimmed. This is pulled from the registry.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the SDB database.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the SDB.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Install time of the SDB","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the SDB database.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdb_id","description":"Unique GUID of the SDB.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apps","description":"macOS applications installed in known search paths (e.g., /Applications).","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the Name.app folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute and full Name.app path","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"bundle_executable","description":"Info properties CFBundleExecutable label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"Info properties CFBundleIdentifier label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_name","description":"Info properties CFBundleName label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_short_version","description":"Info properties CFBundleShortVersionString label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_version","description":"Info properties CFBundleVersion label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_package_type","description":"Info properties CFBundlePackageType label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"environment","description":"Application-set environment variables","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"element","description":"Does the app identify as a background agent","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"compiler","description":"Info properties DTCompiler label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Info properties CFBundleDevelopmentRegion label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Info properties CFBundleDisplayName label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info_string","description":"Info properties CFBundleGetInfoString label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"minimum_system_version","description":"Minimum version of macOS required for the app to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The UTI that categorizes the app for the App Store","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"applescript_enabled","description":"Info properties NSAppleScriptEnabled label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"copyright","description":"Info properties NSHumanReadableCopyright label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"The time that the app was last used","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apt_sources","description":"Current list of APT repositories or software channels.","platforms":["linux"],"columns":[{"name":"name","description":"Repository name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base_uri","description":"Repository base URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"release","description":"Release name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Repository source version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Repository maintainer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"components","description":"Repository components","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architectures","description":"Repository architectures","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"arp_cache","description":"Address resolution cache, both static and dynamic (from ARP, NDP).","platforms":["darwin","linux","windows"],"columns":[{"name":"address","description":"IPv4 address target","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address of broadcasted address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"interface","description":"Interface of the network for the MAC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permanent","description":"1 for true, 0 for false","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"asl","description":"Queries the Apple System Log data structure for system events.","platforms":["darwin"],"columns":[{"name":"time","description":"Unix timestamp. Set automatically","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time_nano_sec","description":"Nanosecond time.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Sender's address (set by the server).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sender","description":"Sender's identification string. Default is process name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"facility","description":"Sender's facility. Default is 'user'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Sending process ID encoded as a string. Set automatically.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"GID that sent the log message (set by the server).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"UID that sent the log message (set by the server).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"Log level number. See levels in asl.h.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message text.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ref_pid","description":"Reference PID for messages proxied by launchd","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ref_proc","description":"Reference process for messages proxied by launchd","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extra","description":"Extra columns, in JSON format. Queries against this column are performed entirely in SQLite, so do not benefit from efficient querying via asl.h.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"atom_packages","description":"Lists all atom packages in a directory or globally installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Package's package.json path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the plugin","type":"bigint","notes":"","hidden":false,"required":false,"index":true}]},{"name":"augeas","description":"Configuration files parsed by augeas.","platforms":["darwin","linux"],"columns":[{"name":"node","description":"The node path of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"The value of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"The label of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path to the configuration file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authenticode","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"original_program_name","description":"The original program name that the publisher has signed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_name","description":"The certificate issuer name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_name","description":"The certificate subject name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"result","description":"The signature check result","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorization_mechanisms","description":"macOS Authorization mechanisms database.","platforms":["darwin"],"columns":[{"name":"label","description":"Label of the authorization right","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"plugin","description":"Authorization plugin name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mechanism","description":"Name of the mechanism that will be called","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"privileged","description":"If privileged it will run as root, else as an anonymous user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"entry","description":"The whole string entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorizations","description":"macOS Authorization rights database.","platforms":["darwin"],"columns":[{"name":"label","description":"Item name, usually in reverse domain format","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"modified","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"allow_root","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"timeout","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tries","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authenticate_user","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shared","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"session_owner","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorized_keys","description":"A line-delimited authorized_keys table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local owner of authorized_keys file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"algorithm","description":"Key type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Key encoded as base64","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Optional list of login options","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to the authorized_keys file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"autoexec","description":"Aggregate of executables that will automatically execute on the target machine. This is an amalgamation of other tables like services, scheduled_tasks, startup_items and more.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the executable","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source table of the autoexec item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_metadata","description":"Azure instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"location","description":"Azure Region the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offer","description":"Offer information for the VM image (Azure image gallery VMs only)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Publisher of the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sku","description":"SKU for the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Linux or Windows","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_update_domain","description":"Update domain the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_fault_domain","description":"Fault domain the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vm_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"vm_size","description":"VM size","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subscription_id","description":"Azure subscription for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resource_group_name","description":"Resource group for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"placement_group_id","description":"Placement group for the VM scale set","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vm_scale_set_name","description":"VM scale set name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_tags","description":"Azure instance tags.","platforms":["darwin","linux","windows"],"columns":[{"name":"vm_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"The tag key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The tag value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"background_activities_moderator","description":"Background Activities Moderator (BAM) tracks application execution.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"battery","description":"Provides information about the internal battery of a Macbook.","platforms":["darwin"],"columns":[{"name":"manufacturer","description":"The battery manufacturer's name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacture_date","description":"The date the battery was manufactured UNIX Epoch","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The battery's model number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The battery's unique serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cycle_count","description":"The number of charge/discharge cycles","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"health","description":"One of the following: \"Good\" describes a well-performing battery, \"Fair\" describes a functional battery with limited capacity, or \"Poor\" describes a battery that's not capable of providing power","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"condition","description":"One of the following: \"Normal\" indicates the condition of the battery is within normal tolerances, \"Service Needed\" indicates that the battery should be checked out by a licensed Mac repair service, \"Permanent Failure\" indicates the battery needs replacement","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"One of the following: \"AC Power\" indicates the battery is connected to an external power source, \"Battery Power\" indicates that the battery is drawing internal power, \"Off Line\" indicates the battery is off-line or no longer connected","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"charging","description":"1 if the battery is currently being charged by a power source. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"charged","description":"1 if the battery is currently completely charged. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"designed_capacity","description":"The battery's designed capacity in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"The battery's actual capacity when it is fully charged in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"current_capacity","description":"The battery's current charged capacity in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_remaining","description":"The percentage of battery remaining before it is drained","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"amperage","description":"The battery's current amperage in mA","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"voltage","description":"The battery's current voltage in mV","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes_until_empty","description":"The number of minutes until the battery is fully depleted. This value is -1 if this time is still being calculated","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes_to_full_charge","description":"The number of minutes until the battery is fully charged. This value is -1 if this time is still being calculated","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"bitlocker_info","description":"Retrieve bitlocker status of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"ID of the encrypted drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"Drive letter of the encrypted drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"persistent_volume_id","description":"Persistent ID of the drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"conversion_status","description":"The bitlocker conversion status of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protection_status","description":"The bitlocker protection status of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption_method","description":"The encryption type of the device.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The FVE metadata version of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percentage_encrypted","description":"The percentage of the drive that is encrypted.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lock_status","description":"The accessibility status of the drive from Windows.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"block_devices","description":"Block (buffered access) device file nodes: disks, ramdisks, and DMG containers.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Block device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Block device parent name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Block device vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"Block device model string identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Block device size in blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Block device Universally Unique Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Block device type string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Block device label string","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"bpf_process_events","description":"Track time/action process executions.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Binary path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"json_cmdline","description":"Command line arguments, in JSON format","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"bpf_socket_events","description":"Track network socket opens and closes.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The socket type","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"browser_plugins","description":"All C/NPAPI browser plugin details for all users. C/NPAPI has been deprecated on all major browsers. To query for plugins on modern browsers, try: `chrome_extensions` `firefox_addons` `safari_extensions`.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the plugin","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Plugin display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Plugin identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Plugin short version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Build SDK used to compile plugin","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Plugin description text","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Plugin language-localization","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"native","description":"Plugin requires native execution","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"disabled","description":"Is the plugin disabled. 1 = Disabled","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"carbon_black_info","description":"Returns info about a Carbon Black sensor install.","platforms":["darwin","linux","windows"],"columns":[{"name":"sensor_id","description":"Sensor ID of the Carbon Black sensor","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"config_name","description":"Sensor group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_store_files","description":"If the sensor is configured to send back binaries to the Carbon Black server","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_module_loads","description":"If the sensor is configured to capture module loads","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_module_info","description":"If the sensor is configured to collect metadata of binaries","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_file_mods","description":"If the sensor is configured to collect file modification events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_reg_mods","description":"If the sensor is configured to collect registry modification events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_net_conns","description":"If the sensor is configured to collect network connections","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_processes","description":"If the sensor is configured to process events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_cross_processes","description":"If the sensor is configured to cross process events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_emet_events","description":"If the sensor is configured to EMET events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_data_file_writes","description":"If the sensor is configured to collect non binary file writes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_process_user_context","description":"If the sensor is configured to collect the user running a process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_sensor_operations","description":"Unknown","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_mb","description":"Event file disk quota in MB","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_percentage","description":"Event file disk quota in a percentage","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protection_disabled","description":"If the sensor is configured to report tamper events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sensor_ip_addr","description":"IP address of the sensor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sensor_backend_server","description":"Carbon Black server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"event_queue","description":"Size in bytes of Carbon Black event files on disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"binary_queue","description":"Size in bytes of binaries waiting to be sent to Carbon Black server","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"carves","description":"List the set of completed and in-progress carves. If carve=1 then the query is treated as a new carve request.","platforms":["darwin","linux","windows"],"columns":[{"name":"time","description":"Time at which the carve was kicked off","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"A SHA256 sum of the carved archive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the carved archive","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the requested carve","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the carve, can be STARTING, PENDING, SUCCESS, or FAILED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"carve_guid","description":"Identifying value of the carve session","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"request_id","description":"Identifying value of the carve request (e.g., scheduled query name, distributed request, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"carve","description":"Set this value to '1' to start a file carve","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"certificates","description":"Certificate Authorities installed in Keychains/ca-bundles.","platforms":["darwin","linux","windows"],"columns":[{"name":"common_name","description":"Certificate CommonName","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject","description":"Certificate distinguished name (deprecated, use subject2)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer","description":"Certificate issuer distinguished name (deprecated, use issuer2)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ca","description":"1 if CA: true (certificate is an authority) else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"self_signed","description":"1 if self-signed, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"not_valid_before","description":"Lower bound of valid date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"not_valid_after","description":"Certificate expiration data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signing_algorithm","description":"Signing algorithm used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_algorithm","description":"Key algorithm used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_strength","description":"Key size used for RSA/DSA, or curve name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Certificate key usage and extended key usage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_key_id","description":"SKID an optionally included SHA1","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority_key_id","description":"AKID an optionally included SHA1","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the raw certificate contents","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Keychain or PEM bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"Certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"SID","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store_location","description":"Certificate system store location","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store","description":"Certificate system store","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"username","description":"Username","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store_id","description":"Exists for service/user stores. Contains raw store id provided by WinAPI.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"issuer2","description":"Certificate issuer distinguished name","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"subject2","description":"Certificate distinguished name","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"chassis_info","description":"Display information pertaining to the chassis and its security status.","platforms":["windows"],"columns":[{"name":"audible_alarm","description":"If TRUE, the frame is equipped with an audible alarm.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"breach_description","description":"If provided, gives a more detailed description of a detected security breach.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"chassis_types","description":"A comma-separated list of chassis types, such as Desktop or Laptop.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"An extended description of the chassis if available.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"lock","description":"If TRUE, the frame is equipped with a lock.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_breach","description":"The physical status of the chassis such as Breach Successful, Breach Attempted, etc.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"smbios_tag","description":"The assigned asset tag number of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sku","description":"The Stock Keeping Unit number if available.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"If available, gives various operational or nonoperational statuses such as OK, Degraded, and Pred Fail.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"visible_alarm","description":"If TRUE, the frame is equipped with a visual alarm.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chocolatey_packages","description":"Chocolatey packages installed in a system.","platforms":["windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this package resides","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chrome_extension_content_scripts","description":"Chrome browser extension content scripts.","platforms":["darwin","linux","windows"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"identifier","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script","description":"The content script used by the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"match","description":"The pattern that the script is matched against","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chrome_extensions","description":"Chrome-based browser extensions.","platforms":["darwin","linux","windows"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave, edge, edge_beta)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile","description":"The name of the Chrome profile that contains this extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced_identifier","description":"Extension identifier, as specified by the preferences file. Empty if the extension is not in the profile.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier, computed from its manifest. Empty in case of error.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Extension-optional description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"default_locale","description":"Default locale supported by extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_locale","description":"Current locale supported by extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"persistent","description":"1 If extension is persistent across all tabs else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"The permissions required by the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions_json","description":"The JSON-encoded permissions required by the extension","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"optional_permissions","description":"The permissions optionally required by the extensions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"optional_permissions_json","description":"The JSON-encoded permissions optionally required by the extensions","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"manifest_hash","description":"The SHA256 hash of the manifest.json file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"from_webstore","description":"True if this extension was installed from the web store","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"1 if this extension is enabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Extension install time, in its original Webkit format","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_timestamp","description":"Extension install time, converted to unix time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"manifest_json","description":"The manifest file of the extension","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"key","description":"The extension key, from the manifest file","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"connected_displays","description":"Provides information about the connected displays of the machine.","platforms":["darwin"],"columns":[{"name":"name","description":"The name of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"product_id","description":"The product ID of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The serial number of the display. (may not be unique)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"The vendor ID of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufactured_week","description":"The manufacture week of the display. This field is 0 if not supported","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufactured_year","description":"The manufacture year of the display. This field is 0 if not supported","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"display_id","description":"The display ID.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pixels","description":"The number of pixels of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resolution","description":"The resolution of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ambient_brightness_enabled","description":"The ambient brightness setting associated with the display. This will be 1 if enabled and is 0 if disabled or not supported.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"connection_type","description":"The connection type associated with the display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"display_type","description":"The type of display.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"main","description":"If the display is the main display.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mirror","description":"If the display is mirrored or not. This field is 1 if mirrored and 0 if not mirrored.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"online","description":"The online status of the display. This field is 1 if the display is online and 0 if it is offline.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"rotation","description":"The orientation of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"connectivity","description":"Provides the overall system's network state.","platforms":["windows"],"columns":[{"name":"disconnected","description":"True if the all interfaces are not connected to any network","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_no_traffic","description":"True if any interface is connected via IPv4, but has seen no traffic","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_no_traffic","description":"True if any interface is connected via IPv6, but has seen no traffic","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_subnet","description":"True if any interface is connected to the local subnet via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_local_network","description":"True if any interface is connected to a routed network via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_internet","description":"True if any interface is connected to the Internet via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_subnet","description":"True if any interface is connected to the local subnet via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_local_network","description":"True if any interface is connected to a routed network via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_internet","description":"True if any interface is connected to the Internet via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cpu_info","description":"Retrieve cpu hardware info of the machine.","platforms":["darwin","linux","windows"],"columns":[{"name":"device_id","description":"The DeviceID of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"processor_type","description":"The processor type, such as Central, Math, or Video.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_status","description":"The current operating status of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"number_of_cores","description":"The number of cores of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logical_processors","description":"The number of logical processors of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"address_width","description":"The width of the CPU address bus.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_clock_speed","description":"The current frequency of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_clock_speed","description":"The maximum possible frequency of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"socket_designation","description":"The assigned socket on the board for the given CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"availability","description":"The availability and status of the CPU.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"number_of_efficiency_cores","description":"The number of efficiency cores of the CPU. Only available on Apple Silicon","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"number_of_performance_cores","description":"The number of performance cores of the CPU. Only available on Apple Silicon","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]}]},{"name":"cpu_time","description":"Displays information from /proc/stat file about the time the cpu cores spent in different parts of the system.","platforms":["darwin","linux"],"columns":[{"name":"core","description":"Name of the cpu (core)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"Time spent in user mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Time spent in user mode with low priority (nice)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system","description":"Time spent in system mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"idle","description":"Time spent in the idle task","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"iowait","description":"Time spent waiting for I/O to complete","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"irq","description":"Time spent servicing interrupts","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"softirq","description":"Time spent servicing softirqs","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"steal","description":"Time spent in other operating systems when running in a virtualized environment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"guest","description":"Time spent running a virtual CPU for a guest OS under the control of the Linux kernel","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"guest_nice","description":"Time spent running a niced guest ","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cpuid","description":"Useful CPU features from the cpuid ASM call.","platforms":["darwin","linux","windows"],"columns":[{"name":"feature","description":"Present feature flags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Bit value or string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"output_register","description":"Register used to for feature value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"output_bit","description":"Bit in register value for feature value","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"input_eax","description":"Value of EAX used","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"crashes","description":"Application, System, and Mobile App crash logs.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of crash log","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Location of log file","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"identifier","description":"Identifier of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version info of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent PID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"responsible","description":"Process responsible for the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the crashed process","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"datetime","description":"Date/Time at which the crash occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crashed_thread","description":"Thread ID which crashed","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Most recent frame from the stack trace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_type","description":"Exception type of the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_codes","description":"Exception codes from the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_notes","description":"Exception notes from the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"The value of the system registers","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"crontab","description":"Line parsed values from system and user cron/tab.","platforms":["darwin","linux"],"columns":[{"name":"event","description":"The job @event name (rare)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"minute","description":"The exact minute for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hour","description":"The hour of the day for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"day_of_month","description":"The day of the month for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"month","description":"The month of the year for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"day_of_week","description":"The day of the week for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Raw command string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"File parsed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"cups_destinations","description":"Returns all configured printers.","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the printer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option_name","description":"Option name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option_value","description":"Option value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cups_jobs","description":"Returns all completed print jobs from cups.","platforms":["darwin"],"columns":[{"name":"title","description":"Title of the printed job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination","description":"The printer the job was sent to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The user who printed the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"format","description":"The format of the print job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the print job","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"completed_time","description":"When the job completed printing","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"processing_time","description":"How long the job took to process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the print request was initiated","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"curl","description":"Perform an http request and return stats about it.","platforms":["darwin","linux","windows"],"columns":[{"name":"url","description":"The url for the request","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"method","description":"The HTTP method for the request","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_agent","description":"The user-agent string to use for the request","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"response_code","description":"The HTTP status code for the response","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"round_trip_time","description":"Time taken to complete the request","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of bytes in the response","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"result","description":"The HTTP response body","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"curl_certificate","description":"Inspect TLS certificates by connecting to input hostnames.","platforms":["darwin","linux","windows"],"columns":[{"name":"hostname","description":"Hostname to CURL (domain[:port], e.g. osquery.io)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"common_name","description":"Common name of company issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"organization","description":"Organization issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"organization_unit","description":"Organization unit issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_common_name","description":"Issuer common name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_organization","description":"Issuer organization","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_organization_unit","description":"Issuer organization unit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valid_from","description":"Period of validity start date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valid_to","description":"Period of validity end date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256_fingerprint","description":"SHA-256 fingerprint","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1_fingerprint","description":"SHA1 fingerprint","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version Number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"signature_algorithm","description":"Signature Algorithm","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signature","description":"Signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_key_identifier","description":"Subject Key Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority_key_identifier","description":"Authority Key Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Usage of key in certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extended_key_usage","description":"Extended usage of key in certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policies","description":"Certificate Policies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_alternative_names","description":"Subject Alternative Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_alternative_names","description":"Issuer Alternative Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info_access","description":"Authority Information Access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_info_access","description":"Subject Information Access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_mappings","description":"Policy Mappings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"has_expired","description":"1 if the certificate has expired, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"basic_constraint","description":"Basic Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name_constraints","description":"Name Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_constraints","description":"Policy Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dump_certificate","description":"Set this value to '1' to dump certificate","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"timeout","description":"Set this value to the timeout in seconds to complete the TLS handshake (default 4s, use 0 for no timeout)","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"pem","description":"Certificate PEM format","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"deb_packages","description":"The installed DEB package database.","platforms":["linux"],"columns":[{"name":"name","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Package source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Package architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"Package revision","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Package status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Package maintainer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"section","description":"Package section","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"priority","description":"Package priority","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"admindir","description":"libdpkg admindir. Defaults to /var/lib/dpkg","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"default_environment","description":"Default environment variables and values.","platforms":["windows"],"columns":[{"name":"variable","description":"Name of the environment variable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the environment variable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"expand","description":"1 if the variable needs expanding, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_file","description":"Similar to the file table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"partition","description":"A partition number","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"path","description":"A logical path within the device node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Creation time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_firmware","description":"A best-effort list of discovered firmware versions.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"The device name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"version","description":"Firmware version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_hash","description":"Similar to the hash table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_partitions","description":"Use TSK to enumerate details about partitions on a disk device.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number or description","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offset","description":"","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Byte size of each block","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Number of blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Number of meta nodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"disk_encryption","description":"Disk encryption status and information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Disk name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Disk Universally Unique Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 If encrypted: true (disk is encrypted), else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Description of cipher type and mode if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption_status","description":"Disk encryption status with one of following values: encrypted | not encrypted | undefined","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Currently authenticated user if available","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"user_uuid","description":"UUID of authenticated user if available","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"filevault_status","description":"FileVault status with one of following values: on | off | unknown","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]}]},{"name":"disk_events","description":"Track DMG disk image events (appearance/disappearance) when opened.","platforms":["darwin"],"columns":[{"name":"action","description":"Appear or disappear","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the DMG file accessed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Disk event name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Disk event BSD name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"UUID of the volume inside DMG if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of partition in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ejectable","description":"1 if ejectable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mountable","description":"1 if mountable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"writable","description":"1 if writable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"content","description":"Disk event content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"media_name","description":"Disk event media name string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Disk event vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filesystem","description":"Filesystem if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"checksum","description":"UDIF Master checksum if available (CRC32)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of appearance/disappearance in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"disk_info","description":"Retrieve basic information about the physical disks of a system.","platforms":["windows"],"columns":[{"name":"partitions","description":"Number of detected partitions on disk.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_index","description":"Physical drive number of the disk.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The interface type of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"The unique identifier of the drive on the system.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pnp_device_id","description":"The unique identifier of the drive on the system.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_size","description":"Size of the disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hard drive model.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"The label of the disk object.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The OS's description of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"dns_cache","description":"Enumerate the DNS cache using the undocumented DnsGetCacheDataTable function in dnsapi.dll.","platforms":["windows"],"columns":[{"name":"name","description":"DNS record name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"DNS record type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"DNS record flags","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"dns_resolvers","description":"Resolvers used by this host.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Address type index or order","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Address type: sortlist, nameserver, search","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Resolver IP/IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Address (sortlist) netmask length","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Resolver options","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"docker_container_envs","description":"Docker container environment variables.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Environment variable name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_fs_changes","description":"Changes to files or directories on container's filesystem.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"path","description":"FIle or directory path relative to rootfs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"change_type","description":"Type of change: C:Modified, A:Added, D:Deleted","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_labels","description":"Docker container labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_mounts","description":"Docker container mounts.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Type of mount (bind, volume)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Optional mount name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"source","description":"Source path on host","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination","description":"Destination path inside container","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver providing the mount","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Mount options (rw, ro)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rw","description":"1 if read/write. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"propagation","description":"Mount propagation","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_networks","description":"Docker container networks.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Network name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"network_id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"endpoint_id","description":"Endpoint ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ip_address","description":"IP address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ip_prefix_len","description":"IP subnet prefix length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_gateway","description":"IPv6 gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_prefix_len","description":"IPv6 subnet prefix length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mac_address","description":"MAC address","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_ports","description":"Docker container ports.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Protocol (tcp, udp)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Port inside the container","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host_ip","description":"Host IP address on which public port is listening","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host_port","description":"Host port","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_processes","description":"Docker container processes.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start in seconds since boot (non-sleeping)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"User name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Cumulative CPU time. [DD-]HH:MM:SS format","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu","description":"CPU utilization as percentage","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"mem","description":"Memory utilization as percentage","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_stats","description":"Docker container statistics. Queries on this table take at least one second.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"name","description":"Container name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pids","description":"Number of processes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"read","description":"UNIX time when stats were read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"preread","description":"UNIX time when stats were last read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"interval","description":"Difference between read and preread in nano-seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_read","description":"Total disk read bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_write","description":"Total disk write bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"num_procs","description":"Number of processors","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_total_usage","description":"Total CPU usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_kernelmode_usage","description":"CPU kernel mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_usermode_usage","description":"CPU user mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_cpu_usage","description":"CPU system usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"online_cpus","description":"Online CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_total_usage","description":"Last read total CPU usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_kernelmode_usage","description":"Last read CPU kernel mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_usermode_usage","description":"Last read CPU user mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_system_cpu_usage","description":"Last read CPU system usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_online_cpus","description":"Last read online CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_usage","description":"Memory usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_cached","description":"Memory cached","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_max_usage","description":"Memory maximum usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"Memory limit","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"network_rx_bytes","description":"Total network bytes read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"network_tx_bytes","description":"Total network bytes transmitted","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_containers","description":"Docker containers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Container name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"image","description":"Docker image (name) used to launch this container","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"image_id","description":"Docker image ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Command with arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Container state (created, restarting, running, removing, paused, exited, dead)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Container status information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Identifier of the initial process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Container path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_entrypoint","description":"Container entrypoint(s)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"started_at","description":"Container start time as string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"finished_at","description":"Container finish time as string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"privileged","description":"Is the container privileged","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"security_options","description":"List of container security options","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"env_variables","description":"Container environmental variables","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"readonly_rootfs","description":"Is the root filesystem mounted as read only","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"ipc_namespace","description":"IPC namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"mnt_namespace","description":"Mount namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"net_namespace","description":"Network namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"pid_namespace","description":"PID namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"user_namespace","description":"User namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"uts_namespace","description":"UTS namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"docker_image_history","description":"Docker image history information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of instruction in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"created_by","description":"Created by instruction","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Instruction comment","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_image_labels","description":"Docker image labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_image_layers","description":"Docker image layers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"layer_id","description":"Layer ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"layer_order","description":"Layer Order (1 = base layer)","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_images","description":"Docker images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size_bytes","description":"Size of image in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of repository tags","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_info","description":"Docker system information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Docker system ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"containers","description":"Total number of containers","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_running","description":"Number of containers currently running","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_paused","description":"Number of containers in paused state","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_stopped","description":"Number of containers in stopped state","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"images","description":"Number of images","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"storage_driver","description":"Storage driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"1 if memory limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_limit","description":"1 if swap limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_memory","description":"1 if kernel memory limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_period","description":"1 if CPU Completely Fair Scheduler (CFS) period support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_quota","description":"1 if CPU Completely Fair Scheduler (CFS) quota support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_shares","description":"1 if CPU share weighting support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_set","description":"1 if CPU set selection support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_forwarding","description":"1 if IPv4 forwarding is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bridge_nf_iptables","description":"1 if bridge netfilter iptables is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bridge_nf_ip6tables","description":"1 if bridge netfilter ip6tables is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"oom_kill_disable","description":"1 if Out-of-memory kill is disabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_driver","description":"Logging driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cgroup_driver","description":"Control groups driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Operating system type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpus","description":"Number of CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory","description":"Total memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"http_proxy","description":"HTTP proxy","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"https_proxy","description":"HTTPS proxy","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"no_proxy","description":"Comma-separated list of domain extensions proxy should not be used for","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the docker host","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"server_version","description":"Server version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root_dir","description":"Docker root directory","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_network_labels","description":"Docker network labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_networks","description":"Docker networks information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Network name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Network driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_ipv6","description":"1 if IPv6 is enabled on this network. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"subnet","description":"Network subnet","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Network gateway","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_version","description":"Docker version information.","platforms":["darwin","linux"],"columns":[{"name":"version","description":"Docker version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"api_version","description":"API version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_api_version","description":"Minimum API version supported","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"git_commit","description":"Docker build git commit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"go_version","description":"Go version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Hardware architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Build time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_volume_labels","description":"Docker volume labels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_volumes","description":"Docker volumes information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"driver","description":"Volume driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mount_point","description":"Mount point","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Volume type","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"drivers","description":"Details for in-use Windows device drivers. This does not display installed but unused drivers.","platforms":["windows"],"columns":[{"name":"device_id","description":"Device ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_name","description":"Device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"image","description":"Path to driver image file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Driver description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service","description":"Driver service name, if one exists","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_key","description":"Driver service registry key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Driver version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inf","description":"Associated inf file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Device/driver class name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider","description":"Driver provider","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Device manufacturer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_key","description":"Driver key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Driver date","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"signed","description":"Whether the driver is signed or not","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_metadata","description":"EC2 instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_type","description":"EC2 instance type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture of this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"region","description":"AWS region in which this instance launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"availability_zone","description":"Availability zone in which this instance launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Private IPv4 DNS hostname of the first interface of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_ipv4","description":"Private IPv4 address of the first interface of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address for the first network interface of this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_groups","description":"Comma separated list of security group names","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iam_arn","description":"If there is an IAM role associated with the instance, contains instance profile ARN","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ami_id","description":"AMI ID used to launch this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reservation_id","description":"ID of the reservation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"account_id","description":"AWS account ID which owns this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_tags","description":"EC2 instance tag key value pairs.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Tag key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"es_process_events","description":"Process execution events from EndpointSecurity.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"original_parent","description":"Original parent process ID in case of reparenting","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline_count","description":"Number of command line arguments","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective User ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective Group ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signing_id","description":"Signature identifier of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team_id","description":"Team identifier of thd process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Codesigning hash of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_binary","description":"Indicates if the binary is Apple signed binary (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of a process in case of an exit event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"child_pid","description":"Process ID of a child process in case of a fork event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"codesigning_flags","description":"Codesigning flags matching one of these options, in a comma separated list: NOT_VALID, ADHOC, NOT_RUNTIME, INSTALLER. See kern/cs_blobs.h in XNU for descriptions.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"es_process_file_events","description":"File integrity monitoring events from EndpointSecurity including process context.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"The source or target filename for the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dest_filename","description":"Destination filename for the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"etc_hosts","description":"Line-parsed /etc/hosts.","platforms":["darwin","linux","windows"],"columns":[{"name":"address","description":"IP address mapping","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hostnames","description":"Raw hosts mapping","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"etc_protocols","description":"Line-parsed /etc/protocols.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Protocol name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number","description":"Protocol number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"alias","description":"Protocol alias","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Comment with protocol description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"etc_services","description":"Line-parsed /etc/services.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Service port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Optional space separated list of other names for a service","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment for a service.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"event_taps","description":"Returns information about installed event taps.","platforms":["darwin"],"columns":[{"name":"enabled","description":"Is the Event Tap enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"event_tap_id","description":"Unique ID for the Tap","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"event_tapped","description":"The mask that identifies the set of events to be observed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_being_tapped","description":"The process ID of the target application","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"tapping_process","description":"The process ID of the application that created the event tap.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"extended_attributes","description":"Returns the extended attributes for files (similar to Windows ADS).","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute file path","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the value generated from the extended attribute","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The parsed information from the attribute","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base64","description":"1 if the value is base64 encoded else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"fan_speed_sensors","description":"Fan speeds.","platforms":["darwin"],"columns":[{"name":"fan","description":"Fan number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Fan name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"actual","description":"Actual speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimum speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"target","description":"Target speed","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"file","description":"Interactive filesystem attributes and metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"Absolute file path","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"directory","description":"Directory of file(s)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Device ID (optional)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"btime","description":"(B)irth or (cr)eate time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"symlink","description":"1 if the path is a symlink, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"attributes","description":"File attrib string. See: https://ss64.com/nt/attrib.html","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"volume_serial","description":"Volume serial number","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"file_id","description":"file ID","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"file_version","description":"File version","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"product_version","description":"File product version","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"original_filename","description":"(Executable files only) Original filename","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"bsd_flags","description":"The BSD file flags (chflags). Possible values: NODUMP, UF_IMMUTABLE, UF_APPEND, OPAQUE, HIDDEN, ARCHIVED, SF_IMMUTABLE, SF_APPEND","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"file_events","description":"Track time/action changes to files specified in configuration data.","platforms":["darwin","linux"],"columns":[{"name":"target_path","description":"The path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file defined in the config","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"The MD5 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"The SHA1 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"The SHA256 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hashed","description":"1 if the file was hashed, 0 if not, -1 if hashing failed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"firefox_addons","description":"Firefox browser extensions, webapps, and addons.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local user that owns the addon","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Addon display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Addon identifier","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"creator","description":"Addon-supported creator string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Extension, addon, webapp","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Addon-supplied version string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Addon-supplied description string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source_url","description":"URL that installed the addon","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"visible","description":"1 If the addon is shown in browser else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If the addon is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 If the addon is application-disabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"1 If the addon applies background updates else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Global, profile location","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper","description":"macOS Gatekeeper Details.","platforms":["darwin"],"columns":[{"name":"assessments_enabled","description":"1 If a Gatekeeper is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"dev_id_enabled","description":"1 If a Gatekeeper allows execution from identified developers else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of Gatekeeper's gke.bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"opaque_version","description":"Version of Gatekeeper's gkopaque.bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper_approved_apps","description":"Gatekeeper apps a user has allowed to run.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of executable allowed to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"requirement","description":"Code signing requirement language","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last change time","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"groups","description":"Local system groups.","platforms":["darwin","linux","windows"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","notes":"","hidden":true,"required":false,"index":true,"platforms":["windows","win32","cygwin"]},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"hardware_events","description":"Hardware (PCI/USB/HID) events from UDEV or IOKit.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"Remove, insert, change properties, etc","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Local device path assigned (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of hardware and hardware event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver claiming the device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Hardware device vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded Hardware vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"Hardware device model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded Hardware model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"Device serial (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"Device revision (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of hardware event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"hash","description":"Filesystem hash data.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"directory","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"homebrew_packages","description":"The installed homebrew package database.","platforms":["darwin"],"columns":[{"name":"name","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Package install path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Current 'linked' version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"prefix","description":"Homebrew install prefix","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"hvci_status","description":"Retrieve HVCI info of the machine.","platforms":["windows"],"columns":[{"name":"version","description":"The version number of the Device Guard build.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_identifier","description":"The instance ID of Device Guard.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vbs_status","description":"The status of the virtualization based security settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"code_integrity_policy_enforcement_status","description":"The status of the code integrity policy enforcement settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"umci_policy_status","description":"The status of the User Mode Code Integrity security settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ibridge_info","description":"Information about the Apple iBridge hardware controller.","platforms":["darwin"],"columns":[{"name":"boot_uuid","description":"Boot UUID of the iBridge controller","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"coprocessor_version","description":"The manufacturer and chip version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"The build version of the firmware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unique_chip_id","description":"Unique id of the iBridge controller","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ie_extensions","description":"Internet Explorer browser extensions.","platforms":["windows"],"columns":[{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registry_path","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executable","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"intel_me_info","description":"Intel ME/CSE Info.","platforms":["linux","windows"],"columns":[{"name":"version","description":"Intel ME version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"interface_addresses","description":"Network interfaces and relevant metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mask","description":"Interface netmask","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"broadcast","description":"Broadcast address for the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"point_to_point","description":"PtP address for the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of address. One of dhcp, manual, auto, other, unknown","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"interface_details","description":"Detailed information and stats of network interfaces.","platforms":["darwin","linux","windows"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC of interface (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Interface type (includes virtual)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Network MTU","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"metric","description":"Metric based on the speed of the interface","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags (netdevice) for the device","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipackets","description":"Input packets","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"opackets","description":"Output packets","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ibytes","description":"Input bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"obytes","description":"Output bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ierrors","description":"Input errors","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"oerrors","description":"Output errors","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"idrops","description":"Input drops","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"odrops","description":"Output drops","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"collisions","description":"Packet Collisions detected","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Time of last device modification (optional)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"link_speed","description":"Interface speed in Mb/s","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"pci_slot","description":"PCI slot number","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"description","description":"Short description of the object a one-line string.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"manufacturer","description":"Name of the network adapter's manufacturer.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"connection_id","description":"Name of the network connection as it appears in the Network Connections Control Panel program.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"connection_status","description":"State of the network adapter connection to the network.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"enabled","description":"Indicates whether the adapter is enabled or not.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"physical_adapter","description":"Indicates whether the adapter is a physical or a logical adapter.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"speed","description":"Estimate of the current bandwidth in bits per second.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"service","description":"The name of the service the network adapter uses.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_enabled","description":"If TRUE, the dynamic host configuration protocol (DHCP) server automatically assigns an IP address to the computer system when establishing a network connection.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_lease_expires","description":"Expiration date and time for a leased IP address that was assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_lease_obtained","description":"Date and time the lease was obtained for the IP address assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_server","description":"IP address of the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_domain","description":"Organization name followed by a period and an extension that indicates the type of organization, such as 'microsoft.com'.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_domain_suffix_search_order","description":"Array of DNS domain suffixes to be appended to the end of host names during name resolution.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_host_name","description":"Host name used to identify the local computer for authentication by some utilities.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_server_search_order","description":"Array of server IP addresses to be used in querying for DNS servers.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"interface_ipv6","description":"IPv6 configuration and stats of network interfaces.","platforms":["darwin","linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hop_limit","description":"Current Hop Limit","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"forwarding_enabled","description":"Enable IP forwarding","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"redirect_accept","description":"Accept ICMP redirect messages","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"rtadv_accept","description":"Accept ICMP Router Advertisement","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iokit_devicetree","description":"The IOKit registry matching the DeviceTree plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Device node name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent device registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"device_path","description":"Device tree path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service","description":"1 if the device conforms to IOService else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the device is in a busy state else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The device reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"depth","description":"Device nested depth","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iokit_registry","description":"The full IOKit registry without selecting a plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Default name of the node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the node is in a busy state else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The node reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"depth","description":"Node nested depth","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iptables","description":"Linux IP packet filtering and NAT tool.","platforms":["linux"],"columns":[{"name":"filter_name","description":"Packet matching filter table name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"chain","description":"Size of module content.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy","description":"Policy that applies for this rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"target","description":"Target that applies for this rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Protocol number identification.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"src_port","description":"Protocol source port(s).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_port","description":"Protocol destination port(s).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"src_ip","description":"Source IP address.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"src_mask","description":"Source IP address mask.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iniface","description":"Input interface for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iniface_mask","description":"Input interface mask for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_ip","description":"Destination IP address.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_mask","description":"Destination IP address mask.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"outiface","description":"Output interface for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"outiface_mask","description":"Output interface mask for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"match","description":"Matching rule that applies.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"packets","description":"Number of matching packets for this rule.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of matching bytes for this rule.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_extensions","description":"macOS's kernel extensions, both loaded and within the load search path.","platforms":["darwin"],"columns":[{"name":"idx","description":"Extension load tag or index","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"refs","description":"Reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Bytes of wired memory used by extension","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"linked_against","description":"Indexes of extensions this extension is linked against","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Optional path to extension bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_info","description":"Basic active kernel information.","platforms":["darwin","linux","windows"],"columns":[{"name":"version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arguments","description":"Kernel arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Kernel path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Kernel device identifier","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_keys","description":"List of security data, authentication keys and encryption keys.","platforms":["linux"],"columns":[{"name":"serial_number","description":"The serial key of the key.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"A set of flags describing the state of the key.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"usage","description":"the number of threads and open file references thatrefer to this key.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"timeout","description":"The amount of time until the key will expire,expressed in human-readable form. The string perm heremeans that the key is permanent (no timeout). Thestring expd means that the key has already expired.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"The key permissions, expressed as four hexadecimalbytes containing, from left to right, thepossessor, user, group, and other permissions.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The user ID of the key owner.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"The group ID of the key.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The key type.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The key description.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_modules","description":"Linux kernel modules both loaded and within the load search path.","platforms":["linux"],"columns":[{"name":"name","description":"Module name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"used_by","description":"Module reverse dependencies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Kernel module status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_panics","description":"System kernel panic logs.","platforms":["darwin"],"columns":[{"name":"path","description":"Location of log file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Formatted time of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"A space delimited line of register:value pairs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"frame_backtrace","description":"Backtrace of the crashed module","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module_backtrace","description":"Modules appearing in the crashed module's backtrace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dependencies","description":"Module dependencies existing in crashed module's backtrace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name corresponding to crashed thread","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_version","description":"Version of the operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Version of the system kernel","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"system_model","description":"Physical system model, for example 'MacBookPro12,1 (Mac-E43C1C25D4880AD6)'","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"System uptime at kernel panic in nanoseconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_loaded","description":"Last loaded module before panic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_unloaded","description":"Last unloaded module before panic","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"keychain_acls","description":"Applications that have ACL entries in the keychain.","platforms":["darwin"],"columns":[{"name":"keychain_path","description":"The path of the keychain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authorizations","description":"A space delimited set of authorization attributes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the authorized application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The description included with the ACL entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"An optional label tag that may be included with the keychain entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"keychain_items","description":"Generic details about keychain items.","platforms":["darwin"],"columns":[{"name":"label","description":"Generic item name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional item description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional keychain comment","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"account","description":"Optional item account","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Date item was created","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified","description":"Date of last modification","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Keychain item type (class)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pk_hash","description":"Hash of associated public key (SHA1 of subjectPublicKey, see RFC 8520 4.2.1.2)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to keychain containing item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"known_hosts","description":"A line-delimited known_hosts table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local user that owns the known_hosts file","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"parsed authorized keys line","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to known_hosts file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kva_speculative_info","description":"Display kernel virtual address and speculative execution information for the system.","platforms":["windows"],"columns":[{"name":"kva_shadow_enabled","description":"Kernel Virtual Address shadowing is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_user_global","description":"User pages are marked as global.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_pcid","description":"Kernel VA PCID flushing optimization is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_inv_pcid","description":"Kernel VA INVPCID is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_mitigations","description":"Branch Prediction mitigations are enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_system_pol_disabled","description":"Branch Predictions are disabled via system policy.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_microcode_disabled","description":"Branch Predictions are disabled due to lack of microcode update.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_spec_ctrl_supported","description":"SPEC_CTRL MSR supported by CPU Microcode.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ibrs_support_enabled","description":"Windows uses IBRS.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"stibp_support_enabled","description":"Windows uses STIBP.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_pred_cmd_supported","description":"PRED_CMD MSR supported by CPU Microcode.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"last","description":"System logins and logouts.","platforms":["darwin","linux"],"columns":[{"name":"username","description":"Entry username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tty","description":"Entry terminal","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Entry type, according to ut_type types (utmp.h)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Entry type name, according to ut_type types (utmp.h)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Entry hostname","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"launchd","description":"LaunchAgents and LaunchDaemons from default search paths.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to daemon or agent plist","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"File name of plist (used by launchd)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Daemon or agent service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"program","description":"Path to target program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"run_at_load","description":"Should the program run on launch load","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"keep_alive","description":"Should the process be restarted if killed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"on_demand","description":"Deprecated key, replaced by keep_alive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Skip loading this daemon or agent on boot","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Run this daemon or agent as this username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Run this daemon or agent as this group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stdout_path","description":"Pipe stdout to a target path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stderr_path","description":"Pipe stderr to a target path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_interval","description":"Frequency to run in seconds","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"program_arguments","description":"Command line arguments passed to program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"watch_paths","description":"Key that launches daemon or agent if path is modified","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"queue_directories","description":"Similar to watch_paths but only with non-empty directories","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inetd_compatibility","description":"Run this daemon or agent as it was launched from inetd","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_on_mount","description":"Run daemon or agent every time a filesystem is mounted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root_directory","description":"Key used to specify a directory to chroot to before launch","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"working_directory","description":"Key used to specify a directory to chdir to before launch","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_type","description":"Key describes the intended purpose of the job","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"launchd_overrides","description":"Override keys, per user, for LaunchDaemons and Agents.","platforms":["darwin"],"columns":[{"name":"label","description":"Daemon or agent service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Name of the override key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Overridden value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID applied to the override, 0 applies to all","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to daemon or agent plist","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"listening_ports","description":"Processes with listening (bound) network sockets/ports.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Transport layer port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for bind","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path for UNIX domain sockets","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"load_average","description":"Displays information about the system wide load averages.","platforms":["darwin","linux"],"columns":[{"name":"period","description":"Period over which the average is calculated.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"average","description":"Load average over the specified period.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"location_services","description":"Reports the status of the Location Services feature of the OS.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 if Location Services are enabled, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"logged_in_users","description":"Users with an active shell on the system.","platforms":["darwin","linux","windows"],"columns":[{"name":"type","description":"Login type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"User login name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tty","description":"Device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Remote hostname","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time entry was made","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"The user's unique security identifier","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"registry_hive","description":"HKEY_USERS registry hive","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"logical_drives","description":"Details for logical drives on the system. A logical drive generally represents a single partition.","platforms":["windows"],"columns":[{"name":"device_id","description":"The drive id, usually the drive name, e.g., 'C:'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Deprecated (always 'Unknown').","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The canonical description of the drive, e.g. 'Logical Fixed Disk', 'CD-ROM Disk'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"free_space","description":"The amount of free space, in bytes, of the drive (-1 on failure).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The total amount of space, in bytes, of the drive (-1 on failure).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"file_system","description":"The file system of the drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"boot_partition","description":"True if Windows booted from this drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"logon_sessions","description":"Windows Logon Session.","platforms":["windows"],"columns":[{"name":"logon_id","description":"A locally unique identifier (LUID) that identifies a logon session.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The account name of the security principal that owns the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_domain","description":"The name of the domain used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authentication_package","description":"The authentication package used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_type","description":"The logon method.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"session_id","description":"The Terminal Services session identifier.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_sid","description":"The user's security identifier (SID).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_time","description":"The time the session owner logged on.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_server","description":"The name of the server used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dns_domain_name","description":"The DNS name for the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"upn","description":"The user principal name (UPN) for the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_script","description":"The script used for logging on.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The home directory for the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"home_directory","description":"The home directory for the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"home_directory_drive","description":"The drive location of the home directory of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_certificates","description":"LXD certificates information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fingerprint","description":"SHA256 hash of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"certificate","description":"Certificate content","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster","description":"LXD cluster information.","platforms":["linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether clustering enabled (1) or not (0) on this node","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_entity","description":"Type of configuration parameter for this node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_name","description":"Name of configuration parameter","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_key","description":"Config key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_value","description":"Config value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_description","description":"Config description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster_members","description":"LXD cluster members information.","platforms":["linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"url","description":"URL of the node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"database","description":"Whether the server is a database node (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the node (Online/Offline)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the node (Online/Offline)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_images","description":"LXD images information.","platforms":["linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"architecture","description":"Target architecture for the image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"OS on which image is based","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"release","description":"OS release version on which the image is based","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Image description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Comma-separated list of image aliases","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Filename of the image file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of image in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_update","description":"Whether the image auto-updates (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cached","description":"Whether image is cached (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"public","description":"Whether image is public (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of image creation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"expires_at","description":"ISO time of image expiration","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uploaded_at","description":"ISO time of image upload","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_used_at","description":"ISO time for the most recent use of this image in terms of container spawn","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_server","description":"Server for image update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_protocol","description":"Protocol used for image information update and image import from source server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_certificate","description":"Certificate for update source server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_alias","description":"Alias of image at update source server","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_config","description":"LXD instance configuration information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"key","description":"Configuration parameter name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Configuration parameter value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_devices","description":"LXD instance devices information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"device","description":"Name of the device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Device info param name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Device info param value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instances","description":"LXD instances information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"status","description":"Instance state (running, stopped, etc.)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stateful","description":"Whether the instance is stateful(1) or not(0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ephemeral","description":"Whether the instance is ephemeral(1) or not(0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of creation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base_image","description":"ID of image used to launch this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Instance architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"The OS of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Instance description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Instance's process ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"processes","description":"Number of processes running inside this instance","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_networks","description":"LXD network information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"managed","description":"1 if network created by LXD, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_address","description":"IPv4 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"used_by","description":"URLs for containers using this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_received","description":"Number of bytes received on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_sent","description":"Number of bytes sent on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"packets_received","description":"Number of packets received on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"packets_sent","description":"Number of packets sent on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hwaddr","description":"Hardware address for this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Network status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"MTU size","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_storage_pools","description":"LXD storage pool information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the storage pool","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Storage driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Storage pool source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the storage pool","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"space_used","description":"Storage space used in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"space_total","description":"Total available storage space in bytes for this storage pool","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_used","description":"Number of inodes used","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_total","description":"Total number of inodes available in this storage pool","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"magic","description":"Magic number recognition library table.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute path to target file","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"magic_db_files","description":"Colon(:) separated list of files where the magic db file can be found. By default one of the following is used: /usr/share/file/magic/magic, /usr/share/misc/magic or /usr/share/misc/magic.mgc","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Magic number data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mime_type","description":"MIME type data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mime_encoding","description":"MIME encoding data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"managed_policies","description":"The managed configuration policies from AD, MDM, MCX, etc.","platforms":["darwin"],"columns":[{"name":"domain","description":"System or manager-chosen domain key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Optional UUID assigned to policy set","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy key name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Policy value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Policy applies only this user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manual","description":"1 if policy was loaded manually, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_devices","description":"Software RAID array settings.","platforms":["linux"],"columns":[{"name":"device_name","description":"md device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Current state of the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"raid_level","description":"Current raid level of the array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"size of the array in blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"chunk_size","description":"chunk size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"raid_disks","description":"Number of configured RAID disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nr_raid_disks","description":"Number of partitions or disk devices to comprise the array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"working_disks","description":"Number of working disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active_disks","description":"Number of active disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_disks","description":"Number of failed disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"spare_disks","description":"Number of idle disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_state","description":"State of the superblock","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_version","description":"Version of the superblock","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_update_time","description":"Unix timestamp of last update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_on_mem","description":"Pages allocated in in-memory bitmap, if enabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_chunk_size","description":"Bitmap chunk size","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_external_file","description":"External referenced bitmap file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_progress","description":"Progress of the recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_finish","description":"Estimated duration of recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_speed","description":"Speed of recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_progress","description":"Progress of the resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_finish","description":"Estimated duration of resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_speed","description":"Speed of resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_progress","description":"Progress of the reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_finish","description":"Estimated duration of reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_speed","description":"Speed of reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_progress","description":"Progress of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_finish","description":"Estimated duration of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_speed","description":"Speed of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unused_devices","description":"Unused devices","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"other","description":"Other information associated with array from /proc/mdstat","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_drives","description":"Drive devices used for Software RAID.","platforms":["linux"],"columns":[{"name":"md_device_name","description":"md device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_name","description":"Drive device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"slot","description":"Slot position of disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the drive","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_personalities","description":"Software RAID setting supported by the kernel.","platforms":["linux"],"columns":[{"name":"name","description":"Name of personality supported by kernel","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"mdfind","description":"Run searches against the spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file returned from spotlight","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"The query that was run to find the file","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"mdls","description":"Query file metadata in the Spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the metadata key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value stored in the metadata key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valuetype","description":"CoreFoundation type of data stored in value","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"memory_array_mapped_addresses","description":"Data associated for address mapping of physical memory arrays.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_handle","description":"Handle of the memory array associated with this structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partition_width","description":"Number of memory devices that form a single row of memory for the address partition of this structure","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_arrays","description":"Data associated with collection of memory devices that operate to form a memory address.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Physical location of the memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"use","description":"Function for which the array is used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_error_correction","description":"Primary hardware error correction or detection method supported","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"Maximum capacity of array in gigabytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_error_info_handle","description":"Handle, or instance number, associated with any error that was detected for the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number_memory_devices","description":"Number of memory devices on array","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_device_mapped_addresses","description":"Data associated for address mapping of physical memory devices.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_device_handle","description":"Handle of the memory device structure associated with this structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_mapped_address_handle","description":"Handle of the memory array mapped address to which this device range is mapped to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partition_row_position","description":"Identifies the position of the referenced memory device in a row of the address partition","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interleave_position","description":"The position of the device in a interleave, i.e. 0 indicates non-interleave, 1 indicates 1st interleave, 2 indicates 2nd interleave, etc.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interleave_data_depth","description":"The max number of consecutive rows from memory device that are accessed in a single interleave transfer; 0 indicates device is non-interleave","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_devices","description":"Physical memory device (type 17) information retrieved from SMBIOS.","platforms":["darwin","linux","windows"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure in SMBIOS","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"array_handle","description":"The memory array that the device is attached to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Implementation form factor for this memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"total_width","description":"Total width, in bits, of this memory device, including any check or error-correction bits","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"data_width","description":"Data width, in bits, of this memory device","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of memory device in Megabyte","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"set","description":"Identifies if memory device is one of a set of devices. A value of 0 indicates no set affiliation.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"device_locator","description":"String number of the string that identifies the physically-labeled socket or board position where the memory device is located","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bank_locator","description":"String number of the string that identifies the physically-labeled bank where the memory device is located","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_type","description":"Type of memory used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_type_details","description":"Additional details for memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_speed","description":"Max speed of memory device in megatransfers per second (MT/s)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"configured_clock_speed","description":"Configured speed of memory device in megatransfers per second (MT/s)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Manufacturer ID string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Serial number of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"asset_tag","description":"Manufacturer specific asset tag of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"part_number","description":"Manufacturer specific serial number of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_voltage","description":"Minimum operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_voltage","description":"Maximum operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"configured_voltage","description":"Configured operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_error_info","description":"Data associated with errors of a physical memory array.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_type","description":"type of error associated with current error status for array or device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_granularity","description":"Granularity to which the error can be resolved","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_operation","description":"Memory access operation that caused the error","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_syndrome","description":"Vendor specific ECC syndrome or CRC data associated with the erroneous access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_error_address","description":"32 bit physical address of the error based on the addressing of the bus to which the memory array is connected","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_error_address","description":"32 bit physical address of the error relative to the start of the failing memory address, in bytes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_resolution","description":"Range, in bytes, within which this error can be determined, when an error address is given","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_info","description":"Main memory information in bytes.","platforms":["linux"],"columns":[{"name":"memory_total","description":"Total amount of physical RAM, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_free","description":"The amount of physical RAM, in bytes, left unused by the system","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_available","description":"The amount of physical RAM, in bytes, available for starting new applications, without swapping","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"buffers","description":"The amount of physical RAM, in bytes, used for file buffers","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cached","description":"The amount of physical RAM, in bytes, used as cache memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_cached","description":"The amount of swap, in bytes, used as cache memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"The total amount of buffer or page cache memory, in bytes, that is in active use","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"The total amount of buffer or page cache memory, in bytes, that are free and available","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_total","description":"The total amount of swap available, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_free","description":"The total amount of swap free, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_map","description":"OS memory region map.","platforms":["linux"],"columns":[{"name":"name","description":"Region name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start","description":"Start address of memory region","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"end","description":"End address of memory region","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"mounts","description":"System mounted devices and filesystems (not process specific).","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Mounted device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_alias","description":"Mounted device alias","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Mounted device path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Mounted device type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Block size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Mounted device used blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_free","description":"Mounted device free blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_available","description":"Mounted device available blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Mounted device used inodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_free","description":"Mounted device free inodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Mounted device flags","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"msr","description":"Various pieces of data stored in the model specific register per processor. NOTE: the msr kernel module must be enabled, and osquery must be run as root.","platforms":["linux"],"columns":[{"name":"processor_number","description":"The processor number as reported in /proc/cpuinfo","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"turbo_disabled","description":"Whether the turbo feature is disabled.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"turbo_ratio_limit","description":"The turbo feature ratio limit.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_info","description":"Platform information.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"perf_ctl","description":"Performance setting for the processor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"perf_status","description":"Performance status for the processor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"feature_control","description":"Bitfield controlling enabled features.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_power_limit","description":"Run Time Average Power Limiting power limit.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_energy_status","description":"Run Time Average Power Limiting energy status.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_power_units","description":"Run Time Average Power Limiting power units.","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"nfs_shares","description":"NFS shares exported by the host.","platforms":["darwin"],"columns":[{"name":"share","description":"Filesystem path to the share","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Options string set on the export share","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"readonly","description":"1 if the share is exported readonly else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"npm_packages","description":"Node packages installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Package-supplied description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Package-supplied author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where node_modules are located","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"ntdomains","description":"Display basic NT domain information of a Windows machine.","platforms":["windows"],"columns":[{"name":"name","description":"The label by which the object is known.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"client_site_name","description":"The name of the site where the domain controller is configured.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dc_site_name","description":"The name of the site where the domain controller is located.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dns_forest_name","description":"The name of the root of the DNS tree.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_controller_address","description":"The IP Address of the discovered domain controller..","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_controller_name","description":"The name of the discovered domain controller.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_name","description":"The name of the domain.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"The current status of the domain object.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ntfs_acl_permissions","description":"Retrieve NTFS ACL permission information for files and directories.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the file or directory.","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"type","description":"Type of access mode for the access control entry.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"principal","description":"User or group to which the ACE applies.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"access","description":"Specific permissions that indicate the rights described by the ACE.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inherited_from","description":"The inheritance policy of the ACE.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ntfs_journal_events","description":"Track time/action changes to files specified in configuration data.","platforms":["windows"],"columns":[{"name":"action","description":"Change action (Write, Delete, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category that the event originated from","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"old_path","description":"Old path (renames only)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"record_timestamp","description":"Journal record timestamp","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"record_usn","description":"The update sequence number that identifies the journal record","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"node_ref_number","description":"The ordinal that associates a journal record with a filename","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent_ref_number","description":"The ordinal that associates a journal record with a filename's parent directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"The drive letter identifying the source journal","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"file_attributes","description":"File attributes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partial","description":"Set to 1 if either path or old_path only contains the file or folder name","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"nvram","description":"Apple NVRAM variable listing.","platforms":["darwin"],"columns":[{"name":"name","description":"Variable name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Data type (CFData, CFString, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Raw variable data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"oem_strings","description":"OEM defined strings retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the Type 11 structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number","description":"The string index of the structure","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the OEM string","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"office_mru","description":"View recently opened Office documents.","platforms":["windows"],"columns":[{"name":"application","description":"Associated Office application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Office application version number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"File path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"Most recent opened time file was opened","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"os_version","description":"A single row containing the operating system name and version.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Distribution or product name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Pretty, suitable for presentation, OS version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"major","description":"Major release version","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minor","description":"Minor release version","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"patch","description":"Optional patch release","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build","description":"Optional build-specific or variant string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform","description":"OS Platform or ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_like","description":"Closely related platforms","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"codename","description":"OS version codename","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"OS Architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extra","description":"Optional extra release specification","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"install_date","description":"The install date of the OS.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"osquery_events","description":"Information about the event publishers and subscribers.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Event publisher or subscriber name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the associated publisher","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Either publisher or subscriber","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subscriptions","description":"Number of subscriptions the publisher received or subscriber used","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"events","description":"Number of events emitted or received since osquery started","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"refreshes","description":"Publisher only: number of runloop restarts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 if the publisher or subscriber is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_extensions","description":"List of active osquery extensions.","platforms":["darwin","linux","windows"],"columns":[{"name":"uuid","description":"The transient ID assigned for communication","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension's name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension's version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk_version","description":"osquery SDK version used to build the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the extension's Thrift connection or library path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"SDK extension type: core, extension, or module","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_flags","description":"Configurable flags that modify osquery's behavior.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Flag name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Flag type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Flag description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"default_value","description":"Flag default value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Flag value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell_only","description":"Is the flag shell only?","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_info","description":"Top level information about the running version of osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread/handle) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_id","description":"Unique, long-lived ID per instance of osquery","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"osquery toolkit version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_hash","description":"Hash of the working configuration state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_valid","description":"1 if the config was loaded and considered valid, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"extensions","description":"osquery extensions status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_platform","description":"osquery toolkit build platform","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_distro","description":"osquery toolkit platform distribution name (os version)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"UNIX time in seconds when the process started","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"watcher","description":"Process (or thread/handle) ID of optional watcher process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_mask","description":"The osquery platform bitmask","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_packs","description":"Information about the current query packs that are loaded in osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"The given name for this query pack","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform","description":"Platforms this query is supported on","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Minimum osquery version that this query will run on","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shard","description":"Shard restriction limit, 1-100, 0 meaning no restriction","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"discovery_cache_hits","description":"The number of times that the discovery query used cached values since the last time the config was reloaded","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"discovery_executions","description":"The number of times that the discovery queries have been executed since the last time the config was reloaded","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"Whether this pack is active (the version, platform and discovery queries match) yes=1, no=0.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_registry","description":"List the osquery registry plugins.","platforms":["darwin","linux","windows"],"columns":[{"name":"registry","description":"Name of the osquery registry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the plugin item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uuid","description":"Extension route UUID (0 for core)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"internal","description":"1 If the plugin is internal else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If this plugin is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_schedule","description":"Information about the current queries that are scheduled in osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"The given name for this query","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"The exact query to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"interval","description":"The interval in seconds to run this query, not an exact interval","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"executions","description":"Number of times the query was executed","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_executed","description":"UNIX time stamp in seconds of the last completed execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"denylisted","description":"1 if the query is denylisted else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"output_size","description":"Cumulative total number of bytes generated by the resultant rows of the query","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wall_time","description":"Total wall time in seconds spent executing (deprecated), hidden=True","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wall_time_ms","description":"Total wall time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_wall_time_ms","description":"Wall time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"Total user time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_user_time","description":"User time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"Total system time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_system_time","description":"System time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"average_memory","description":"Average of the bytes of resident memory left allocated after collecting results","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_memory","description":"Resident memory in bytes left allocated after collecting results of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"package_bom","description":"macOS package bill of materials (BOM) file list.","platforms":["darwin"],"columns":[{"name":"filepath","description":"Package file or directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Expected user of file or directory","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Expected group of file or directory","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Expected permissions","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Timestamp the file was installed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of package bom","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"package_install_history","description":"macOS package install history.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Label packageIdentifiers","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Label date as UNIX timestamp","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package display version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Install source: usually the installer process name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"content_type","description":"Package content_type (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"package_receipts","description":"macOS package receipt details.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Package domain identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"package_filename","description":"Filename of original .pkg file","type":"text","notes":"","hidden":true,"required":false,"index":true},{"name":"version","description":"Installed package version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Optional relative install path on volume","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Timestamp of install time","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"installer_name","description":"Name of installer process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of receipt plist","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"password_policy","description":"Password Policies for macOS.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID for the policy, -1 for policies that are global","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"policy_identifier","description":"Policy Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_content","description":"Policy content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_description","description":"Policy description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"patches","description":"Lists all the patches applied. Note: This does not include patches applied via MSI or downloaded from Windows Update (e.g. Service Packs).","platforms":["windows"],"columns":[{"name":"csname","description":"The name of the host the patch is installed on.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hotfix_id","description":"The KB ID of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"caption","description":"Short description of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Fuller description of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fix_comments","description":"Additional comments about the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"installed_by","description":"The system context in which the patch as installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the patch was installed. Lack of a value does not indicate that the patch was not installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"installed_on","description":"The date when the patch was installed.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"pci_devices","description":"PCI devices active on the host system.","platforms":["darwin","linux"],"columns":[{"name":"pci_slot","description":"PCI Device used slot","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pci_class","description":"PCI Device class","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"PCI Device used driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"PCI Device vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded PCI Device vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"PCI Device model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded PCI Device model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pci_class_id","description":"PCI Device class ID in hex format","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"pci_subclass_id","description":"PCI Device subclass in hex format","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"pci_subclass","description":"PCI Device subclass","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_vendor_id","description":"Vendor ID of PCI device subsystem","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_vendor","description":"Vendor of PCI device subsystem","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_model_id","description":"Model ID of PCI device subsystem","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_model","description":"Device description of PCI device subsystem","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"physical_disk_performance","description":"Provides provides raw data from performance counters that monitor hard or fixed disk drives on the system.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the physical disk","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_read","description":"Average number of bytes transferred from the disk during read operations","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_write","description":"Average number of bytes transferred to the disk during write operations","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_read_queue_length","description":"Average number of read requests that were queued for the selected disk during the sample interval","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_write_queue_length","description":"Average number of write requests that were queued for the selected disk during the sample interval","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_read","description":"Average time, in seconds, of a read operation of data from the disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_write","description":"Average time, in seconds, of a write operation of data to the disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"current_disk_queue_length","description":"Number of requests outstanding on the disk at the time the performance data is collected","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_read_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_write_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing write requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read or write requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_idle_time","description":"Percentage of time during the sample interval that the disk was idle","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"pipes","description":"Named and Anonymous pipes.","platforms":["windows"],"columns":[{"name":"pid","description":"Process ID of the process to which the pipe belongs","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the pipe","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instances","description":"Number of instances of the named pipe","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_instances","description":"The maximum number of instances creatable for this pipe","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"The flags indicating whether this pipe connection is a server or client end, and if the pipe for sending messages or bytes","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"platform_info","description":"Information about EFI/UEFI/ROM and platform/boot.","platforms":["darwin","linux","windows"],"columns":[{"name":"vendor","description":"Platform code vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Platform code version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Self-reported platform code update date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"BIOS major and minor revision","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extra","description":"Platform-specific additional information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"firmware_type","description":"The type of firmware (uefi, bios, iboot, openfirmware, unknown).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Relative address of firmware mapping","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"size","description":"Size in bytes of firmware","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"volume_size","description":"(Optional) size of firmware volume","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"plist","description":"Read and parse a plist file.","platforms":["darwin"],"columns":[{"name":"key","description":"Preference top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intermediate key path, includes lists/dicts","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"(required) read preferences from a plist","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"portage_keywords","description":"A summary about portage configurations like keywords, mask and unmask.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"keyword","description":"The keyword applied to the package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mask","description":"If the package is masked","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"unmask","description":"If the package is unmasked","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"portage_packages","description":"List of currently installed packages.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"slot","description":"The slot used by package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Unix time when package was built","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"repository","description":"From which repository the ebuild was used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eapi","description":"The eapi for the ebuild","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the package","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"world","description":"If package is in the world file","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"portage_use","description":"List of enabled portage USE values for specific package.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version of the installed package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"use","description":"USE flag which has been enabled for package","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"power_sensors","description":"Machine power (currents, voltages, wattages, etc) sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on macOS","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"category","description":"The sensor category: currents, voltage, wattage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of power source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Power in Watts","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"powershell_events","description":"Powershell script blocks reconstructed to their full script content, this table requires script block logging to be enabled.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received by the osquery event publisher","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the Powershell script event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_block_id","description":"The unique GUID of the powershell script to which this block belongs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_block_count","description":"The total number of script blocks for this script","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"script_text","description":"The text content of the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_name","description":"The name of the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_path","description":"The path for the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cosine_similarity","description":"How similar the Powershell script is to a provided 'normal' character frequency","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"preferences","description":"macOS defaults and managed preferences.","platforms":["darwin"],"columns":[{"name":"domain","description":"Application ID usually in com.name.product format","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Preference top-level key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"subkey","description":"Intemediate key path, includes lists/dicts","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"forced","description":"1 if the value is forced/managed, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"(optional) read preferences for a specific user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"'current' or 'any' host, where 'current' takes precedence","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"prefetch","description":"Prefetch files show metadata related to file execution.","platforms":["windows"],"columns":[{"name":"path","description":"Prefetch file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Executable filename.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hash","description":"Prefetch CRC hash.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Most recent time application was run.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"other_run_times","description":"Other execution times in prefetch file.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"run_count","description":"Number of times the application has been run.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Application file size.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_creation","description":"Volume creation time.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_files_count","description":"Number of files accessed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_directories_count","description":"Number of directories accessed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_files","description":"Files accessed by application within ten seconds of launch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_directories","description":"Directories accessed by application within ten seconds of launch.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_envs","description":"A key/value table of environment variables for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Environment variable name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_etw_events","description":"Windows process execution events.","platforms":["windows"],"columns":[{"name":"type","description":"Event Type (ProcessStart, ProcessStop)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ppid","description":"Parent Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"session_id","description":"Session ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Process Flags","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit Code - Present only on ProcessStop events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed binary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command Line","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"User rights - primary token username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"token_elevation_type","description":"Primary token elevation type - Present only on ProcessStart events","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"token_elevation_status","description":"Primary token elevation status - Present only on ProcessStart events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mandatory_label","description":"Primary token mandatory label sid - Present only on ProcessStart events","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Event timestamp in DATETIME format","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time_windows","description":"Event timestamp in Windows format","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"time","description":"Event timestamp in Unix format","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"header_pid","description":"Process ID of the process reporting the event","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"process_sequence_number","description":"Process Sequence Number - Present only on ProcessStart events","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"parent_process_sequence_number","description":"Parent Process Sequence Number - Present only on ProcessStart events","type":"bigint","notes":"","hidden":true,"required":false,"index":false}]},{"name":"process_events","description":"Track time/action process executions.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"File mode permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline_size","description":"Actual size (bytes) of command line arguments","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"env_size","description":"Actual size (bytes) of environment list","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"File owner user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_gid","description":"File owner group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"File last access in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"File modification in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"File last metadata change in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"btime","description":"File creation in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"overflows","description":"List of structures that overflowed","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"parent","description":"Process parent's PID, or -1 if cannot be determined.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"status","description":"OpenBSM Attribute: Status of the process","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"fsuid","description":"Filesystem user ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"suid","description":"Saved user ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"fsgid","description":"Filesystem group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"sgid","description":"Saved group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]},{"name":"syscall","description":"Syscall name: fork, vfork, clone, execve, execveat","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"process_file_events","description":"A File Integrity Monitor implementation using the audit service.","platforms":["linux"],"columns":[{"name":"operation","description":"Operation type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ppid","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"executable","description":"The executable path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partial","description":"True if this is a partial event (i.e.: this process existed before we started osquery)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The current working directory of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dest_path","description":"The canonical path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The uid of the process performing the action","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"The gid of the process performing the action","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"process_memory_map","description":"Process memory mapped files and pseudo device/regions.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"start","description":"Virtual start address (hex)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"end","description":"Virtual end address (hex)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"r=read, w=write, x=execute, p=private (cow)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset into mapped path","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"MA:MI Major/minor device ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Mapped path inode, 0 means uninitialized (BSS)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to mapped file or mapped type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pseudo","description":"1 If path is a pseudo path, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_namespaces","description":"Linux namespaces for processes running on the host system.","platforms":["linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"cgroup_namespace","description":"cgroup namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipc_namespace","description":"ipc namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mnt_namespace","description":"mnt namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"net namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_namespace","description":"pid namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_namespace","description":"user namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uts_namespace","description":"uts namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_files","description":"File descriptors for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"fd","description":"Process-specific file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Filesystem path of descriptor","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_pipes","description":"Pipes and partner processes for each process.","platforms":["linux"],"columns":[{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"File descriptor","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Pipe open mode (r/w)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Pipe inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Pipe Type: named vs unnamed/anonymous","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_pid","description":"Process ID of partner process sharing a particular pipe","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_fd","description":"File descriptor of shared pipe at partner's end","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_mode","description":"Mode of shared pipe at partner's end","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_sockets","description":"Processes which have open network sockets on the system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"fd","description":"Socket file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Socket local address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Socket remote address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Socket local port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Socket remote port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"For UNIX sockets (family=AF_UNIX), the domain path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"TCP socket state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"protection_type","description":"The protection type of the process","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"translated","description":"Indicates whether the process is running under the Rosetta Translation Environment, yes=1, no=0, error=-1.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cgroup_path","description":"The full hierarchical path of the process's control group","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]},{"name":"programs","description":"Represents products as they are installed by Windows Installer. A product generally correlates to one installation package on Windows. Some fields may be blank as Windows installation details are left to the discretion of the product author.","platforms":["windows"],"columns":[{"name":"name","description":"Commonly used product name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Product version information.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_location","description":"The installation location directory of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_source","description":"The installation source of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"language","description":"The language of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the product supplier.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uninstall_string","description":"Path and filename of the uninstaller.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Date that this product was installed on the system. ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifying_number","description":"Product identification such as a serial number on software, or a die number on a hardware chip.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"prometheus_metrics","description":"Retrieve metrics from a Prometheus server.","platforms":["darwin","linux"],"columns":[{"name":"target_name","description":"Address of prometheus target","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metric_name","description":"Name of collected Prometheus metric","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metric_value","description":"Value of collected Prometheus metric","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"timestamp_ms","description":"Unix timestamp of collected data in MS","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"python_packages","description":"Python packages installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where Python modules are located","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"quicklook_cache","description":"Files and thumbnails within macOS's Quicklook Cache.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rowid","description":"Quicklook file rowid key","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"fs_id","description":"Quicklook file fs_id key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_id","description":"Parsed volume ID from fs_id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Parsed file ID (inode) from fs_id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Parsed version date field","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Parsed version size field","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Parsed version 'gen' field","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_hit_date","description":"Apple date format for last thumbnail cache hit","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hit_count","description":"Number of cache hits on thumbnail","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"icon_mode","description":"Thumbnail icon mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cache_path","description":"Path to cache data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"registry","description":"All of the Windows registry hives.","platforms":["windows"],"columns":[{"name":"key","description":"Name of the key to search for","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Full path to the value","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the registry value entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the registry value, or 'subkey' if item is a subkey","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data content of registry value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"timestamp of the most recent registry write","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"routes","description":"The active route table for the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"destination","description":"Destination IP address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Netmask length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Route gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Route source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags to describe route","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interface","description":"Route local interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Maximum Transmission Unit for the route","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"metric","description":"Cost of route. Lowest is preferred","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of route","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hopcount","description":"Max hops expected","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"rpm_package_files","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"package","description":"RPM package name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"path","description":"File path within the package","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"username","description":"File default username from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"File default groupname from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"File permissions mode from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size in bytes from RPM info DB","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 file digest from RPM info DB","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"rpm_packages","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"name","description":"RPM package name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"version","description":"Package version","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"release","description":"Package release","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"source","description":"Source RPM package name (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the package contents","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"epoch","description":"Package epoch value","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"install_time","description":"When the package was installed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Package vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"package_group","description":"Package group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"running_apps","description":"macOS applications currently running on the host system.","platforms":["darwin"],"columns":[{"name":"pid","description":"The pid of the application","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"bundle_identifier","description":"The bundle identifier of the application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"is_active","description":"(DEPRECATED)","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"safari_extensions","description":"Safari browser extension details for all users. This table requires Full Disk Access (FDA) permission.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension long version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Bundle SDK used to compile extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Optional developer identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional extension description text","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension XAR bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_version","description":"The version of the build that identifies an iteration of the bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"copyright","description":"A human-readable copyright notice for the bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extension_type","description":"Extension Type: WebOrAppExtension or LegacyExtension","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sandboxes","description":"macOS application sandboxes container details.","platforms":["darwin"],"columns":[{"name":"label","description":"UTI-format bundle or label ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"Sandbox owner","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Application sandboxings enabled on container","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build_id","description":"Sandbox-specific identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"Application bundle used by the sandbox","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to sandbox container directory","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"scheduled_tasks","description":"Lists all of the tasks in the Windows task scheduler.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Actions executed by the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the executable to be run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether or not the scheduled task is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hidden","description":"Whether or not the task is visible in the UI","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Timestamp the task last ran","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"next_run_time","description":"Timestamp the task is scheduled to run next","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_message","description":"Exit status message of the last task run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_code","description":"Exit status code of the last task run","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"screenlock","description":"macOS screenlock status. Note: only fetches results for osquery's current logged-in user context. The user must also have recently logged in.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 If a password is required after sleep or the screensaver begins; else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"grace_period","description":"The amount of time in seconds the screen must be asleep or the screensaver on before a password is required on-wake. 0 = immediately; -1 = no password is required on-wake","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"seccomp_events","description":"A virtual table that tracks seccomp events.","platforms":["linux"],"columns":[{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID (loginuid) of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ses","description":"Session ID of the session from which the analyzed process was invoked","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exe","description":"The path to the executable that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sig","description":"Signal value sent to process by seccomp","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Information about the CPU architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"Type of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"compat","description":"Is system call in compatibility mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ip","description":"Instruction pointer value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"code","description":"The seccomp action","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"secureboot","description":"Secure Boot UEFI Settings.","platforms":["darwin","linux","windows"],"columns":[{"name":"secure_boot","description":"Whether secure boot is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"secure_mode","description":"Secure mode for Intel-based macOS: 0 disabled, 1 full security, 2 medium security","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"setup_mode","description":"Whether setup mode is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","windows","win32","cygwin"]}]},{"name":"security_profile_info","description":"Information on the security profile of a given system by listing the system Account and Audit Policies. This table mimics the exported securitypolicy output from the secedit tool.","platforms":["windows"],"columns":[{"name":"minimum_password_age","description":"Determines the minimum number of days that a password must be used before the user can change it","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"maximum_password_age","description":"Determines the maximum number of days that a password can be used before the client requires the user to change it","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minimum_password_length","description":"Determines the least number of characters that can make up a password for a user account","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"password_complexity","description":"Determines whether passwords must meet a series of strong-password guidelines","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"password_history_size","description":"Number of unique new passwords that must be associated with a user account before an old password can be reused","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lockout_bad_count","description":"Number of failed logon attempts after which a user account MUST be locked out","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_to_change_password","description":"Determines if logon session is required to change the password","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"force_logoff_when_expire","description":"Determines whether SMB client sessions with the SMB server will be forcibly disconnected when the client's logon hours expire","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"new_administrator_name","description":"Determines the name of the Administrator account on the local computer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"new_guest_name","description":"Determines the name of the Guest account on the local computer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"clear_text_password","description":"Determines whether passwords MUST be stored by using reversible encryption","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lsa_anonymous_name_lookup","description":"Determines if an anonymous user is allowed to query the local LSA policy","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_admin_account","description":"Determines whether the Administrator account on the local computer is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_guest_account","description":"Determines whether the Guest account on the local computer is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_system_events","description":"Determines whether the operating system MUST audit System Change, System Startup, System Shutdown, Authentication Component Load, and Loss or Excess of Security events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_logon_events","description":"Determines whether the operating system MUST audit each instance of a user attempt to log on or log off this computer","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_object_access","description":"Determines whether the operating system MUST audit each instance of user attempts to access a non-Active Directory object that has its own SACL specified","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_privilege_use","description":"Determines whether the operating system MUST audit each instance of user attempts to exercise a user right","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_policy_change","description":"Determines whether the operating system MUST audit each instance of user attempts to change user rights assignment policy, audit policy, account policy, or trust policy","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_account_manage","description":"Determines whether the operating system MUST audit each event of account management on a computer","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_process_tracking","description":"Determines whether the operating system MUST audit process-related events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_ds_access","description":"Determines whether the operating system MUST audit each instance of user attempts to access an Active Directory object that has its own system access control list (SACL) specified","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_account_logon","description":"Determines whether the operating system MUST audit each time this computer validates the credentials of an account","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"selinux_events","description":"Track SELinux events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"selinux_settings","description":"Track active SELinux settings.","platforms":["linux"],"columns":[{"name":"scope","description":"Where the key is located inside the SELinuxFS mount point.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Key or class name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Active value.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"services","description":"Lists all installed Windows services and their relevant data.","platforms":["windows"],"columns":[{"name":"name","description":"Service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_type","description":"Service Type: OWN_PROCESS, SHARE_PROCESS and maybe Interactive (can interact with the desktop)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Service Display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Service Current status: STOPPED, START_PENDING, STOP_PENDING, RUNNING, CONTINUE_PENDING, PAUSE_PENDING, PAUSED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"the Process ID of the service","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"start_type","description":"Service start type: BOOT_START, SYSTEM_START, AUTO_START, DEMAND_START, DISABLED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"win32_exit_code","description":"The error code that the service uses to report an error that occurs when it is starting or stopping","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"service_exit_code","description":"The service-specific error code that the service returns when an error occurs while the service is starting or stopping","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Service Executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module_path","description":"Path to ServiceDll","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Service Description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_account","description":"The name of the account that the service process will be logged on as when it runs. This name can be of the form Domain\\UserName. If the account belongs to the built-in domain, the name can be of the form .\\UserName.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shadow","description":"Local system users encrypted passwords and related information. Please note, that you usually need superuser rights to access `/etc/shadow`.","platforms":["linux"],"columns":[{"name":"password_status","description":"Password status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hash_alg","description":"Password hashing algorithm","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Date of last password change (starting from UNIX epoch date)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimal number of days between password changes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum number of days between password changes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"warning","description":"Number of days before password expires to warn user about it","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Number of days after password expires until account is blocked","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"expire","description":"Number of days since UNIX epoch date until account is disabled","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flag","description":"Reserved","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":true}]},{"name":"shared_folders","description":"Folders available to others via SMB or AFP.","platforms":["darwin"],"columns":[{"name":"name","description":"The shared name of the folder as it appears to other users","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute path of shared folder on the local system","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shared_memory","description":"OS shared memory regions.","platforms":["linux"],"columns":[{"name":"shmid","description":"Shared memory segment ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"User ID of owning process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creator_uid","description":"User ID of creator process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID to last use the segment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creator_pid","description":"Process ID that created the segment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Attached time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"dtime","description":"Detached time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Changed time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Memory segment permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"attached","description":"Number of attached processes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Destination/attach status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"locked","description":"1 if segment is locked else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shared_resources","description":"Displays shared resources on a computer system running Windows. This may be a disk drive, printer, interprocess communication, or other sharable device.","platforms":["windows"],"columns":[{"name":"description","description":"A textual description of the object","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the object was installed. Lack of a value does not indicate that the object is not installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"String that indicates the current status of the object.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"allow_maximum","description":"Number of concurrent users for this resource has been limited. If True, the value in the MaximumAllowed property is ignored.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"maximum_allowed","description":"Limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum property is set to FALSE.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Alias given to a path set up as a share on a computer system running Windows.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Local path of the Windows share.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of resource being shared. Types include: disk drives, print queues, interprocess communications (IPC), and general devices.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Human readable value for the 'type' column","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sharing_preferences","description":"macOS Sharing preferences.","platforms":["darwin"],"columns":[{"name":"screen_sharing","description":"1 If screen sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"file_sharing","description":"1 If file sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"printer_sharing","description":"1 If printer sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_login","description":"1 If remote login is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_management","description":"1 If remote management is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_apple_events","description":"1 If remote apple events are enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"internet_sharing","description":"1 If internet sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bluetooth_sharing","description":"1 If bluetooth sharing is enabled for any user else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disc_sharing","description":"1 If CD or DVD sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"content_caching","description":"1 If content caching is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shell_history","description":"A line-delimited (command) table of per-user .*_history data.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"Shell history owner","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp. It could be absent, default value is 0.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Unparsed date/line/command history line","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"history_file","description":"Path to the .*_history for this user","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shellbags","description":"Shows directories accessed via Windows Explorer.","platforms":["windows"],"columns":[{"name":"sid","description":"User SID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Shellbags source Registry file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Directory name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Directory Modified time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"created_time","description":"Directory Created time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_time","description":"Directory Accessed time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Directory master file table entry.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Directory master file table sequence.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shimcache","description":"Application Compatibility Cache, contains artifacts of execution.","platforms":["windows"],"columns":[{"name":"entry","description":"Execution order.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the executed file.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"File Modified time.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"execution_flag","description":"Boolean Execution flag, 1 for execution, 0 for no execution, -1 for missing (this flag does not exist on Windows 10 and higher).","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"signature","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["darwin"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"hash_resources","description":"Set to 1 to also hash resources, or 0 otherwise. Default is 1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"If applicable, the arch of the signed code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signed","description":"1 If the file is signed else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"The signing identifier sealed into the signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Hash of the application Code Directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team_identifier","description":"The team signing identifier sealed into the signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority","description":"Certificate Common Name","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sip_config","description":"Apple's System Integrity Protection (rootless) status.","platforms":["darwin"],"columns":[{"name":"config_flag","description":"The System Integrity Protection config flag","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this configuration is enabled, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled_nvram","description":"1 if this configuration is enabled, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"smbios_tables","description":"BIOS (DMI) structure common details and content.","platforms":["darwin","linux"],"columns":[{"name":"number","description":"Table entry number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Table entry type","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Table entry description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"handle","description":"Table entry handle","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"header_size","description":"Header size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Table entry size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"smc_keys","description":"Apple's system management controller keys.","platforms":["darwin"],"columns":[{"name":"key","description":"4-character key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"SMC-reported type literal type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Reported size of data in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"A type-encoded representation of the key value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hidden","description":"1 if this key is normally hidden, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"socket_events","description":"Track network socket opens and closes.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"The socket action (bind, listen, close)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Either 'succeeded', 'failed', 'in_progress' (connect() on non-blocking socket) or 'no_client' (null accept() on non-blocking socket)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"The local path (UNIX domain socket only)","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"success","description":"Deprecated. Use the 'status' column instead","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"ssh_configs","description":"A table of parsed ssh_configs.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local owner of the ssh_config file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block","description":"The host or match block","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option","description":"The option and value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_config_file","description":"Path to the ssh_config file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"startup_items","description":"Applications and binaries set as user/login startup items.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Name of startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"args","description":"Arguments provided to startup executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Startup Item or Login Item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Directory or plist containing startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Startup status; either enabled or disabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"The user associated with the startup item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sudoers","description":"Rules for running commands as other users via sudo.","platforms":["darwin","linux"],"columns":[{"name":"source","description":"Source file containing the given rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"header","description":"Symbol for given rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rule_details","description":"Rule definition","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"suid_bin","description":"suid binaries in common locations.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Binary path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Binary owner username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Binary owner group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Binary permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"syslog_events","description":"","platforms":["linux"],"columns":[{"name":"time","description":"Current unix epoch time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Time known to syslog","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Hostname configured for syslog","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"severity","description":"Syslog severity","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"facility","description":"Syslog facility","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tag","description":"The syslog tag","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"The syslog message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"system_controls","description":"sysctl names, values, and settings information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Full sysctl MIB name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"oid","description":"Control MIB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"Subsystem ID, control type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_value","description":"Value of setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_value","description":"The MIB value set in /etc/sysctl.conf","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"field_name","description":"Specific attribute of opaque type","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]}]},{"name":"system_extensions","description":"macOS (>= 10.15) system extension table.","platforms":["darwin"],"columns":[{"name":"path","description":"Original path of system extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"UUID","description":"Extension unique id","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"System extension state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"System extension version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"System extension category","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"System extension bundle path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team","description":"Signing team ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mdm_managed","description":"1 if managed by MDM system extension payload configuration, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"system_info","description":"System information for identification.","platforms":["darwin","linux","windows"],"columns":[{"name":"hostname","description":"Network hostname including domain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"CPU type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"CPU subtype","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_brand","description":"CPU brand string, contains vendor and model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_physical_cores","description":"Number of physical CPU cores in to the system","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_logical_cores","description":"Number of logical CPU cores available to the system","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_sockets","description":"Number of processor sockets in the system","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_microcode","description":"Microcode version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"physical_memory","description":"Total physical memory in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_vendor","description":"Hardware vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hardware model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_version","description":"Hardware version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_serial","description":"Device serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_vendor","description":"Board vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_model","description":"Board model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_version","description":"Board version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_serial","description":"Board serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Friendly computer name (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Local hostname (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"systemd_units","description":"Track systemd units.","platforms":["linux"],"columns":[{"name":"id","description":"Unique unit identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Unit description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"load_state","description":"Reflects whether the unit definition was properly loaded","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"active_state","description":"The high-level unit activation state, i.e. generalization of SUB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sub_state","description":"The low-level unit activation state, values depend on unit type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unit_file_state","description":"Whether the unit file is enabled, e.g. `enabled`, `masked`, `disabled`, etc","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"following","description":"The name of another unit that this unit follows in state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"object_path","description":"The object path for this unit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"job_id","description":"Next queued job id","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"job_type","description":"Job type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"job_path","description":"The object path for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fragment_path","description":"The unit file path this unit was read from, if there is any","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The configured user, if any","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source_path","description":"Path to the (possibly generated) unit configuration file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"temperature_sensors","description":"Machine's temperature sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on macOS","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of temperature source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"celsius","description":"Temperature in Celsius","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"fahrenheit","description":"Temperature in Fahrenheit","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"time","description":"Track current date and time in UTC.","platforms":["darwin","linux","windows"],"columns":[{"name":"weekday","description":"Current weekday in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"year","description":"Current year in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"month","description":"Current month in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"day","description":"Current day in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hour","description":"Current hour in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Current minutes in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Current seconds in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"timezone","description":"Timezone for reported time (hardcoded to UTC)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_timezone","description":"Current local timezone in of the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unix_time","description":"Current UNIX time in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"timestamp","description":"Current timestamp (log format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Current date and time (ISO format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iso_8601","description":"Current time (ISO format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"win_timestamp","description":"Timestamp value in 100 nanosecond units","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"time_machine_backups","description":"Backups to drives using TimeMachine.","platforms":["darwin"],"columns":[{"name":"destination_id","description":"Time Machine destination ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"backup_date","description":"Backup Date","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"time_machine_destinations","description":"Locations backed up to using Time Machine.","platforms":["darwin"],"columns":[{"name":"alias","description":"Human readable name of drive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination_id","description":"Time Machine destination ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"consistency_scan_date","description":"Consistency scan date","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"root_volume_uuid","description":"Root UUID of backup volume","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_available","description":"Bytes available on volume","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_used","description":"Bytes used on volume","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption","description":"Last known encrypted state","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"tpm_info","description":"A table that lists the TPM related information.","platforms":["windows"],"columns":[{"name":"activated","description":"TPM is activated","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"TPM is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"owned","description":"TPM is owned","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_version","description":"TPM version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_id","description":"TPM manufacturers ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_name","description":"TPM manufacturers name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"product_name","description":"Product name of the TPM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"physical_presence_version","description":"Version of the Physical Presence Interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"spec_version","description":"Trusted Computing Group specification that the TPM supports","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ulimit_info","description":"System resource usage limits.","platforms":["darwin","linux"],"columns":[{"name":"type","description":"System resource to be limited","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"soft_limit","description":"Current limit value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_limit","description":"Maximum limit value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"unified_log","description":"Queries the OSLog framework for entries in the system log. The maximum number of rows returned is limited for performance issues. Use timestamp > or >= constraints to optimize query performance. This table introduces a new idiom for extracting sequential data in batches using multiple queries, ordered by timestamp. To trigger it, the user should include the condition \"timestamp > -1\", and the table will handle pagination. Note that the saved pagination counter is incremented globally across all queries and table invocations within a query. To avoid multiple table invocations within a query, use only AND and = constraints in WHERE clause.","platforms":["darwin"],"columns":[{"name":"timestamp","description":"unix timestamp associated with the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"storage","description":"the storage category for the entry","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"composed message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"activity","description":"the activity ID associate with the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"process","description":"the name of the process that made the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"the pid of the process that made the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sender","description":"the name of the binary image that made the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"the tid of the thread that made the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"the category of the os_log_t used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"the subsystem of the os_log_t used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"the severity level of the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_rows","description":"the max number of rows returned (defaults to 100)","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"predicate","description":"predicate to search (see `log help predicates`), note that this is merged into the predicate created from the column constraints","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"uptime","description":"Track time passed since last boot. Some systems track this as calendar time, some as runtime.","platforms":["darwin","linux","windows"],"columns":[{"name":"days","description":"Days of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hours","description":"Hours of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Minutes of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Seconds of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"total_seconds","description":"Total uptime seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"usb_devices","description":"USB devices that are actively plugged into the host system.","platforms":["darwin","linux"],"columns":[{"name":"usb_address","description":"USB Device used address","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"usb_port","description":"USB Device used port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"USB Device vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded USB Device vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"USB Device version number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"USB Device model string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded USB Device model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"USB Device serial connection","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"USB Device class","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subclass","description":"USB Device subclass","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"USB Device protocol","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"removable","description":"1 If USB device is removable else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"user_events","description":"Track user events from the audit framework.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The file description for the process socket","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Supplied path from event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"The Internet protocol address or family ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"terminal","description":"The network protocol ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"user_groups","description":"Local system user group relationships.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true}]},{"name":"user_interaction_events","description":"Track user interaction events from macOS' event tapping framework.","platforms":["darwin"],"columns":[{"name":"time","description":"Time","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"user_ssh_keys","description":"Returns the private keys in the users ~/.ssh directory and whether or not they are encrypted.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local user that owns the key file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to key file","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"encrypted","description":"1 if key is encrypted, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"key_type","description":"The type of the private key. One of [rsa, dsa, dh, ec, hmac, cmac], or the empty string.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"userassist","description":"UserAssist Registry Key tracks when a user executes an application from Windows Explorer.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of times the application has been executed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"video_info","description":"Retrieve video card information of the machine.","platforms":["windows"],"columns":[{"name":"color_depth","description":"The amount of bits per pixel to represent color.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"The driver of the device.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_date","description":"The date listed on the installed driver.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_version","description":"The version of the installed driver.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"series","description":"The series of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"video_mode","description":"The current resolution of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"virtual_memory_info","description":"Darwin Virtual Memory statistics.","platforms":["darwin"],"columns":[{"name":"free","description":"Total number of free pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"Total number of active pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Total number of inactive pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"speculative","description":"Total number of speculative pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"throttled","description":"Total number of throttled pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wired","description":"Total number of wired down pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"purgeable","description":"Total number of purgeable pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"faults","description":"Total number of calls to vm_faults.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"copy","description":"Total number of copy-on-write pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"zero_fill","description":"Total number of zero filled pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"reactivated","description":"Total number of reactivated pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"purged","description":"Total number of purged pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"file_backed","description":"Total number of file backed pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"anonymous","description":"Total number of anonymous pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uncompressed","description":"Total number of uncompressed pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"compressor","description":"The number of pages used to store compressed VM pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"decompressed","description":"The total number of pages that have been decompressed by the VM compressor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"compressed","description":"The total number of pages that have been compressed by the VM compressor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"page_ins","description":"The total number of requests for pages from a pager.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"page_outs","description":"Total number of pages paged out.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_ins","description":"The total number of compressed pages that have been swapped out to disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_outs","description":"The total number of compressed pages that have been swapped back in from disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_networks","description":"macOS known/remembered Wi-Fi networks list.","platforms":["darwin"],"columns":[{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_connected","description":"Last time this network was connected to as a unix_time","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"passpoint","description":"1 if Passpoint is supported, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"possibly_hidden","description":"1 if network is possibly a hidden network, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"roaming","description":"1 if roaming is supported, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"roaming_profile","description":"Describe the roaming profile, usually one of Single, Dual or Multi","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_login","description":"1 if auto login is enabled, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"temporarily_disabled","description":"1 if this network is temporarily disabled, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 if this network is disabled, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"add_reason","description":"Shows why this network was added, via menubar or command line or something else ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"added_at","description":"Time this network was added as a unix_time","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"captive_portal","description":"1 if this network has a captive portal, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"captive_login_date","description":"Time this network logged in to a captive portal as unix_time","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"was_captive_network","description":"1 if this network was previously a captive network, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_join","description":"1 if this network set to join automatically, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"personal_hotspot","description":"1 if this network is a personal hotspot, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_status","description":"macOS current WiFi status.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"transmit_rate","description":"The current transmit rate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"The current operating mode for the Wi-Fi interface","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_survey","description":"Scan for nearby WiFi networks.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"winbaseobj","description":"Lists named Windows objects in the default object directories, across all terminal services sessions. Example Windows ojbect types include Mutexes, Events, Jobs and Semaphors.","platforms":["windows"],"columns":[{"name":"session_id","description":"Terminal Services Session Id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"object_name","description":"Object Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"object_type","description":"Object Type","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_crashes","description":"Extracted information from Windows crash logs (Minidumps).","platforms":["windows"],"columns":[{"name":"datetime","description":"Timestamp (log format) of the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module","description":"Path of the crashed module within the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the executable file for the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID of the crashed thread","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"File version info of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_uptime","description":"Uptime of the process in seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Multiple stack frames from the stack trace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_code","description":"The Windows exception code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_message","description":"The NTSTATUS error message associated with the exception code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_address","description":"Address (in hex) where the exception occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"The values of the system registers","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command_line","description":"Command-line string passed to the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_directory","description":"Current working directory of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username of the user who ran the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"machine_name","description":"Name of the machine where the crash happened","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"major_version","description":"Windows major version of the machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minor_version","description":"Windows minor version of the machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build_number","description":"Windows build number of the crashing machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of crash log","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Path of the log file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_eventlog","description":"Table for querying all recorded Windows event logs.","platforms":["windows"],"columns":[{"name":"channel","description":"Source or channel of the event","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"Severity level associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID which emitted the event record","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID which emitted the event record","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time_range","description":"System time to selectively filter the events","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"timestamp","description":"Timestamp to selectively filter the events","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"xpath","description":"The custom query to filter events","type":"text","notes":"","hidden":true,"required":true,"index":false}]},{"name":"windows_events","description":"Windows Event logs.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source or channel of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"The severity level associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"windows_firewall_rules","description":"Provides the list of Windows firewall rules.","platforms":["windows"],"columns":[{"name":"name","description":"Friendly name of the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"app_name","description":"Friendly name of the application to which the rule applies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Action for the rule or default setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if the rule is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"grouping","description":"Group to which an individual rule belongs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"direction","description":"Direction of traffic for which the rule applies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"IP protocol of the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_addresses","description":"Local addresses for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_addresses","description":"Remote addresses for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_ports","description":"Local ports for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_ports","description":"Remote ports for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"icmp_types_codes","description":"ICMP types and codes for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_domain","description":"1 if the rule profile type is domain","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_private","description":"1 if the rule profile type is private","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_public","description":"1 if the rule profile type is public","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"service_name","description":"Service name property of the application","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_optional_features","description":"Lists names and installation states of windows features. Maps to Win32_OptionalFeature WMI class.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the feature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"caption","description":"Caption of feature in settings UI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Installation state value. 1 == Enabled, 2 == Disabled, 3 == Absent","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"statename","description":"Installation state name. 'Enabled','Disabled','Absent'","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_search","description":"Run searches against the Windows system index database using Advanced Query Syntax. See https://learn.microsoft.com/en-us/windows/win32/search/-search-3x-advancedquerysyntax for details.","platforms":["windows"],"columns":[{"name":"name","description":"The name of the item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The full path of the item.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The item size in bytes.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"date_created","description":"The unix timestamp of when the item was created.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"date_modified","description":"The unix timestamp of when the item was last modified","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"owner","description":"The owner of the item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The item type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"properties","description":"Additional property values JSON","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"Windows search query","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"sort","description":"Sort for windows api","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"max_results","description":"Maximum number of results returned by windows api, set to -1 for unlimited","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"additional_properties","description":"Comma separated list of columns to include in properties JSON","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"windows_security_center","description":"The health status of Window Security features. Health values can be \"Good\", \"Poor\". \"Snoozed\", \"Not Monitored\", and \"Error\".","platforms":["windows"],"columns":[{"name":"firewall","description":"The health of the monitored Firewall (see windows_security_products)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"The health of the Windows Autoupdate feature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"antivirus","description":"The health of the monitored Antivirus solution (see windows_security_products)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"antispyware","description":"Deprecated (always 'Good').","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"internet_settings","description":"The health of the Internet Settings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"windows_security_center_service","description":"The health of the Windows Security Center Service","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_account_control","description":"The health of the User Account Control (UAC) capability in Windows","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_security_products","description":"Enumeration of registered Windows security products. Note: Not compatible with Windows Server.","platforms":["windows"],"columns":[{"name":"type","description":"Type of security product","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of product","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of protection","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state_timestamp","description":"Timestamp for the product state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remediation_path","description":"Remediation path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signatures_up_to_date","description":"1 if product signatures are up to date, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_update_history","description":"Provides the history of the windows update events.","platforms":["windows"],"columns":[{"name":"client_app_id","description":"Identifier of the client application that processed an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Date and the time an update was applied","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hresult","description":"HRESULT value that is returned from the operation on an update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"operation","description":"Operation on an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"result_code","description":"Result of an operation on an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"server_selection","description":"Value that indicates which server provided an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_id","description":"Service identifier of an update service that is not a Windows update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"support_url","description":"Hyperlink to the language-specific support information for an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"title","description":"Title of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_id","description":"Revision-independent identifier of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_revision","description":"Revision number of an update","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_bios_info","description":"Lists important information from the system bios.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the Bios setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the Bios setting","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_cli_event_consumers","description":"WMI CommandLineEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique name of a consumer.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command_line_template","description":"Standard string template that specifies the process to be started. This property can be NULL, and the ExecutablePath property is used as the command line.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"executable_path","description":"Module to execute. The string can specify the full path and file name of the module to execute, or it can specify a partial name. If a partial name is specified, the current drive and current directory are assumed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_event_filters","description":"Lists WMI event filters.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier of an event filter.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"Windows Management Instrumentation Query Language (WQL) event query that specifies the set of events for consumer notification, and the specific conditions for notification.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query_language","description":"Query language that the query is written in.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_filter_consumer_binding","description":"Lists the relationship between event consumers and filters.","platforms":["windows"],"columns":[{"name":"consumer","description":"Reference to an instance of __EventConsumer that represents the object path to a logical consumer, the recipient of an event.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filter","description":"Reference to an instance of __EventFilter that represents the object path to an event filter which is a query that specifies the type of event to be received.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_script_event_consumers","description":"WMI ActiveScriptEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier for the event consumer. ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"scripting_engine","description":"Name of the scripting engine to use, for example, 'VBScript'. This property cannot be NULL.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_file_name","description":"Name of the file from which the script text is read, intended as an alternative to specifying the text of the script in the ScriptText property.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_text","description":"Text of the script that is expressed in a language known to the scripting engine. This property must be NULL if the ScriptFileName property is not NULL.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_entries","description":"Database of the machine's XProtect signatures.","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"launch_type","description":"Launch services content type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identity","description":"XProtect identity (SHA1) of content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Use this file name to match","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filetype","description":"Use this file type to match","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"optional","description":"Match any of the identities/patterns for this XProtect name","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uses_pattern","description":"Uses a match pattern instead of identity","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_meta","description":"Database of the machine's XProtect browser-related signatures.","platforms":["darwin"],"columns":[{"name":"identifier","description":"Browser plugin or extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Either plugin or extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Developer identity (SHA1) of extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_version","description":"The minimum allowed plugin version.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_reports","description":"Database of XProtect matches (if user generated/sent an XProtect report).","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_action","description":"Action taken by user after prompted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Quarantine alert time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"yara","description":"Triggers one-off YARA query for files at the specified path. Requires one of `sig_group`, `sigfile`, or `sigrule`.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"The path scanned","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"matches","description":"List of YARA matches","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sig_group","description":"Signature group used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigfile","description":"Signature file used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigrule","description":"Signature strings used","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigurl","description":"Signature url","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"yara_events","description":"Track YARA matches for files specified in configuration data.","platforms":["darwin","linux","windows"],"columns":[{"name":"target_path","description":"The path scanned","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of the scan","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"ycloud_instance_metadata","description":"Yandex.Cloud instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"folder_id","description":"Folder identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cloud_id","description":"Cloud identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Hostname of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_port_enabled","description":"Indicates if serial port is enabled for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metadata_endpoint","description":"Endpoint used to fetch VM metadata","type":"text","notes":"","hidden":false,"required":false,"index":true}]},{"name":"yum_sources","description":"Current list of Yum repositories or software channels.","platforms":["linux"],"columns":[{"name":"name","description":"Repository name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"baseurl","description":"Repository base URL","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mirrorlist","description":"Mirrorlist URL","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether the repository is used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gpgcheck","description":"Whether packages are GPG checked","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gpgkey","description":"URL to GPG key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_groups","description":"Local system groups.","platforms":["darwin","linux","windows"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","notes":"","hidden":true,"required":false,"index":true,"platforms":["windows","win32","cygwin"]},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"protection_type","description":"The protection type of the process","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"translated","description":"Indicates whether the process is running under the Rosetta Translation Environment, yes=1, no=0, error=-1.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["darwin"]},{"name":"cgroup_path","description":"The full hierarchical path of the process's control group","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux"]}]}] \ No newline at end of file diff --git a/x-pack/plugins/osquery/public/common/schemas/osquery/v5.7.0.json b/x-pack/plugins/osquery/public/common/schemas/osquery/v5.7.0.json deleted file mode 100644 index 8649b18090b7..000000000000 --- a/x-pack/plugins/osquery/public/common/schemas/osquery/v5.7.0.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"account_policy_data","description":"Additional macOS user account data from the AccountPolicy section of OpenDirectory.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the account was first created","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_login_count","description":"The number of failed login attempts using an incorrect password. Count resets after a correct password is entered.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_login_timestamp","description":"The time of the last failed login attempt. Resets after a correct password is entered","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"password_last_set_time","description":"The time the password was last changed","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"acpi_tables","description":"Firmware ACPI functional table common metadata and content.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"ACPI table name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of compiled table data","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table content","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ad_config","description":"macOS Active Directory configuration.","platforms":["darwin"],"columns":[{"name":"name","description":"The macOS-specific configuration name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain","description":"Active Directory trust domain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option","description":"Canonical name of option","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Variable typed option value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf","description":"macOS application layer firewall (ALF) service details.","platforms":["darwin"],"columns":[{"name":"allow_signed_enabled","description":"1 If allow signed mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"firewall_unload","description":"1 If firewall unloading enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"global_state","description":"1 If the firewall is enabled with exceptions, 2 if the firewall is configured to block all incoming connections, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_enabled","description":"1 If logging mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_option","description":"Firewall logging option","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"stealth_enabled","description":"1 If stealth mode is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Application Layer Firewall version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf_exceptions","description":"macOS application layer firewall (ALF) service exceptions.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to the executable that is excepted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Firewall exception state","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"alf_explicit_auths","description":"ALF services explicitly allowed to perform networking.","platforms":["darwin"],"columns":[{"name":"process","description":"Process name explicitly allowed","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"app_schemes","description":"macOS application schemes and handlers (e.g., http, file, mailto).","platforms":["darwin"],"columns":[{"name":"scheme","description":"Name of the scheme/protocol","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"handler","description":"Application label for the handler","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this handler is the OS default, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"external","description":"1 if this handler does NOT exist on macOS by default, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protected","description":"1 if this handler is protected (reserved) by macOS, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apparmor_events","description":"Track AppArmor events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Raw audit message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"apparmor","description":"Apparmor Status like ALLOWED, DENIED etc.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"operation","description":"Permission requested by the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process PID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"profile","description":"Apparmor profile name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"denied_mask","description":"Denied permissions for the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"capname","description":"Capability requested by the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ouid","description":"Object owner's user ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"capability","description":"Capability number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"requested_mask","description":"Requested access mask","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info","description":"Additional information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error","description":"Error information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"namespace","description":"AppArmor namespace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"AppArmor label","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apparmor_profiles","description":"Track active AppArmor profiles.","platforms":["linux"],"columns":[{"name":"path","description":"Unique, aa-status compatible, policy identifier.","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Policy name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"attach","description":"Which executable(s) a profile will attach to.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"How the policy is applied.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"A unique hash that identifies this policy.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"appcompat_shims","description":"Application Compatibility shims are a way to persist malware. This table presents the AppCompat Shim information from the registry in a nice format. See http://files.brucon.org/2015/Tomczak_and_Ballenthin_Shims_for_the_Win.pdf for more details.","platforms":["windows"],"columns":[{"name":"executable","description":"Name of the executable that is being shimmed. This is pulled from the registry.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the SDB database.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the SDB.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Install time of the SDB","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the SDB database.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdb_id","description":"Unique GUID of the SDB.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apps","description":"macOS applications installed in known search paths (e.g., /Applications).","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the Name.app folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute and full Name.app path","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"bundle_executable","description":"Info properties CFBundleExecutable label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_identifier","description":"Info properties CFBundleIdentifier label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_name","description":"Info properties CFBundleName label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_short_version","description":"Info properties CFBundleShortVersionString label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_version","description":"Info properties CFBundleVersion label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_package_type","description":"Info properties CFBundlePackageType label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"environment","description":"Application-set environment variables","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"element","description":"Does the app identify as a background agent","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"compiler","description":"Info properties DTCompiler label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Info properties CFBundleDevelopmentRegion label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Info properties CFBundleDisplayName label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info_string","description":"Info properties CFBundleGetInfoString label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"minimum_system_version","description":"Minimum version of macOS required for the app to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The UTI that categorizes the app for the App Store","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"applescript_enabled","description":"Info properties NSAppleScriptEnabled label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"copyright","description":"Info properties NSHumanReadableCopyright label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"The time that the app was last used","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"apt_sources","description":"Current list of APT repositories or software channels.","platforms":["linux"],"columns":[{"name":"name","description":"Repository name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base_uri","description":"Repository base URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"release","description":"Release name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Repository source version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Repository maintainer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"components","description":"Repository components","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architectures","description":"Repository architectures","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"arp_cache","description":"Address resolution cache, both static and dynamic (from ARP, NDP).","platforms":["darwin","linux","windows"],"columns":[{"name":"address","description":"IPv4 address target","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address of broadcasted address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"interface","description":"Interface of the network for the MAC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permanent","description":"1 for true, 0 for false","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"asl","description":"Queries the Apple System Log data structure for system events.","platforms":["darwin"],"columns":[{"name":"time","description":"Unix timestamp. Set automatically","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time_nano_sec","description":"Nanosecond time.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Sender's address (set by the server).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sender","description":"Sender's identification string. Default is process name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"facility","description":"Sender's facility. Default is 'user'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Sending process ID encoded as a string. Set automatically.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"GID that sent the log message (set by the server).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"UID that sent the log message (set by the server).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"Log level number. See levels in asl.h.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message text.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ref_pid","description":"Reference PID for messages proxied by launchd","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ref_proc","description":"Reference process for messages proxied by launchd","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extra","description":"Extra columns, in JSON format. Queries against this column are performed entirely in SQLite, so do not benefit from efficient querying via asl.h.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"atom_packages","description":"Lists all atom packages in a directory or globally installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Package supplied description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Package's package.json path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License for package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the plugin","type":"bigint","notes":"","hidden":false,"required":false,"index":true}]},{"name":"augeas","description":"Configuration files parsed by augeas.","platforms":["darwin","linux"],"columns":[{"name":"node","description":"The node path of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"The value of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"The label of the configuration item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path to the configuration file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authenticode","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"original_program_name","description":"The original program name that the publisher has signed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_name","description":"The certificate issuer name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_name","description":"The certificate subject name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"result","description":"The signature check result","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorization_mechanisms","description":"macOS Authorization mechanisms database.","platforms":["darwin"],"columns":[{"name":"label","description":"Label of the authorization right","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"plugin","description":"Authorization plugin name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mechanism","description":"Name of the mechanism that will be called","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"privileged","description":"If privileged it will run as root, else as an anonymous user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"entry","description":"The whole string entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorizations","description":"macOS Authorization rights database.","platforms":["darwin"],"columns":[{"name":"label","description":"Item name, usually in reverse domain format","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"modified","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"allow_root","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"timeout","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tries","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authenticate_user","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shared","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"session_owner","description":"Label top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"authorized_keys","description":"A line-delimited authorized_keys table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local owner of authorized_keys file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"algorithm","description":"Key type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Key encoded as base64","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Optional list of login options","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to the authorized_keys file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"autoexec","description":"Aggregate of executables that will automatically execute on the target machine. This is an amalgamation of other tables like services, scheduled_tasks, startup_items and more.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the executable","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source table of the autoexec item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_metadata","description":"Azure instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"location","description":"Azure Region the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offer","description":"Offer information for the VM image (Azure image gallery VMs only)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Publisher of the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sku","description":"SKU for the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the VM image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Linux or Windows","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_update_domain","description":"Update domain the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_fault_domain","description":"Fault domain the VM is running in","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vm_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"vm_size","description":"VM size","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subscription_id","description":"Azure subscription for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resource_group_name","description":"Resource group for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"placement_group_id","description":"Placement group for the VM scale set","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vm_scale_set_name","description":"VM scale set name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"azure_instance_tags","description":"Azure instance tags.","platforms":["darwin","linux","windows"],"columns":[{"name":"vm_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"The tag key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The tag value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"background_activities_moderator","description":"Background Activities Moderator (BAM) tracks application execution.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"battery","description":"Provides information about the internal battery of a Macbook.","platforms":["darwin"],"columns":[{"name":"manufacturer","description":"The battery manufacturer's name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacture_date","description":"The date the battery was manufactured UNIX Epoch","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The battery's model number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"The battery's unique serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cycle_count","description":"The number of charge/discharge cycles","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"health","description":"One of the following: \"Good\" describes a well-performing battery, \"Fair\" describes a functional battery with limited capacity, or \"Poor\" describes a battery that's not capable of providing power","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"condition","description":"One of the following: \"Normal\" indicates the condition of the battery is within normal tolerances, \"Service Needed\" indicates that the battery should be checked out by a licensed Mac repair service, \"Permanent Failure\" indicates the battery needs replacement","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"One of the following: \"AC Power\" indicates the battery is connected to an external power source, \"Battery Power\" indicates that the battery is drawing internal power, \"Off Line\" indicates the battery is off-line or no longer connected","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"charging","description":"1 if the battery is currently being charged by a power source. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"charged","description":"1 if the battery is currently completely charged. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"designed_capacity","description":"The battery's designed capacity in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"The battery's actual capacity when it is fully charged in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"current_capacity","description":"The battery's current charged capacity in mAh","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_remaining","description":"The percentage of battery remaining before it is drained","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"amperage","description":"The battery's current amperage in mA","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"voltage","description":"The battery's current voltage in mV","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes_until_empty","description":"The number of minutes until the battery is fully depleted. This value is -1 if this time is still being calculated","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes_to_full_charge","description":"The number of minutes until the battery is fully charged. This value is -1 if this time is still being calculated","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"bitlocker_info","description":"Retrieve bitlocker status of the machine.","platforms":["windows"],"columns":[{"name":"device_id","description":"ID of the encrypted drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"Drive letter of the encrypted drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"persistent_volume_id","description":"Persistent ID of the drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"conversion_status","description":"The bitlocker conversion status of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protection_status","description":"The bitlocker protection status of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption_method","description":"The encryption type of the device.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The FVE metadata version of the drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percentage_encrypted","description":"The percentage of the drive that is encrypted.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lock_status","description":"The accessibility status of the drive from Windows.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"block_devices","description":"Block (buffered access) device file nodes: disks, ramdisks, and DMG containers.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Block device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Block device parent name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Block device vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"Block device model string identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Block device size in blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Block device Universally Unique Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Block device type string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Block device label string","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"bpf_process_events","description":"Track time/action process executions.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Binary path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"json_cmdline","description":"Command line arguments, in JSON format","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"bpf_socket_events","description":"Track network socket opens and closes.","platforms":["linux"],"columns":[{"name":"tid","description":"Thread ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cid","description":"Cgroup ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"probe_error","description":"Set to 1 if one or more buffers could not be captured","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"System call name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The socket type","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"duration","description":"How much time was spent inside the syscall (nsecs)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ntime","description":"The nsecs uptime timestamp as obtained from BPF","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"browser_plugins","description":"All C/NPAPI browser plugin details for all users. C/NPAPI has been deprecated on all major browsers. To query for plugins on modern browsers, try: `chrome_extensions` `firefox_addons` `safari_extensions`.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the plugin","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Plugin display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Plugin identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Plugin short version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Build SDK used to compile plugin","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Plugin description text","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"development_region","description":"Plugin language-localization","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"native","description":"Plugin requires native execution","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"disabled","description":"Is the plugin disabled. 1 = Disabled","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"carbon_black_info","description":"Returns info about a Carbon Black sensor install.","platforms":["darwin","linux","windows"],"columns":[{"name":"sensor_id","description":"Sensor ID of the Carbon Black sensor","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"config_name","description":"Sensor group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_store_files","description":"If the sensor is configured to send back binaries to the Carbon Black server","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_module_loads","description":"If the sensor is configured to capture module loads","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_module_info","description":"If the sensor is configured to collect metadata of binaries","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_file_mods","description":"If the sensor is configured to collect file modification events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_reg_mods","description":"If the sensor is configured to collect registry modification events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_net_conns","description":"If the sensor is configured to collect network connections","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_processes","description":"If the sensor is configured to process events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_cross_processes","description":"If the sensor is configured to cross process events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_emet_events","description":"If the sensor is configured to EMET events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_data_file_writes","description":"If the sensor is configured to collect non binary file writes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_process_user_context","description":"If the sensor is configured to collect the user running a process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"collect_sensor_operations","description":"Unknown","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_mb","description":"Event file disk quota in MB","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"log_file_disk_quota_percentage","description":"Event file disk quota in a percentage","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protection_disabled","description":"If the sensor is configured to report tamper events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sensor_ip_addr","description":"IP address of the sensor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sensor_backend_server","description":"Carbon Black server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"event_queue","description":"Size in bytes of Carbon Black event files on disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"binary_queue","description":"Size in bytes of binaries waiting to be sent to Carbon Black server","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"carves","description":"List the set of completed and in-progress carves. If carve=1 then the query is treated as a new carve request.","platforms":["darwin","linux","windows"],"columns":[{"name":"time","description":"Time at which the carve was kicked off","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"A SHA256 sum of the carved archive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the carved archive","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the requested carve","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the carve, can be STARTING, PENDING, SUCCESS, or FAILED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"carve_guid","description":"Identifying value of the carve session","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"request_id","description":"Identifying value of the carve request (e.g., scheduled query name, distributed request, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"carve","description":"Set this value to '1' to start a file carve","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"certificates","description":"Certificate Authorities installed in Keychains/ca-bundles.","platforms":["darwin","linux","windows"],"columns":[{"name":"common_name","description":"Certificate CommonName","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject","description":"Certificate distinguished name (deprecated, use subject2)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer","description":"Certificate issuer distinguished name (deprecated, use issuer2)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ca","description":"1 if CA: true (certificate is an authority) else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"self_signed","description":"1 if self-signed, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"not_valid_before","description":"Lower bound of valid date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"not_valid_after","description":"Certificate expiration data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signing_algorithm","description":"Signing algorithm used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_algorithm","description":"Key algorithm used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_strength","description":"Key size used for RSA/DSA, or curve name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Certificate key usage and extended key usage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_key_id","description":"SKID an optionally included SHA1","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority_key_id","description":"AKID an optionally included SHA1","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the raw certificate contents","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Keychain or PEM bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"Certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"SID","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store_location","description":"Certificate system store location","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store","description":"Certificate system store","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"username","description":"Username","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"store_id","description":"Exists for service/user stores. Contains raw store id provided by WinAPI.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"issuer2","description":"Certificate issuer distinguished name","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"subject2","description":"Certificate distinguished name","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"chassis_info","description":"Display information pertaining to the chassis and its security status.","platforms":["windows"],"columns":[{"name":"audible_alarm","description":"If TRUE, the frame is equipped with an audible alarm.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"breach_description","description":"If provided, gives a more detailed description of a detected security breach.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"chassis_types","description":"A comma-separated list of chassis types, such as Desktop or Laptop.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"An extended description of the chassis if available.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"lock","description":"If TRUE, the frame is equipped with a lock.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_breach","description":"The physical status of the chassis such as Breach Successful, Breach Attempted, etc.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"smbios_tag","description":"The assigned asset tag number of the chassis.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sku","description":"The Stock Keeping Unit number if available.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"If available, gives various operational or nonoperational statuses such as OK, Degraded, and Pred Fail.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"visible_alarm","description":"If TRUE, the frame is equipped with a visual alarm.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chocolatey_packages","description":"Chocolatey packages installed in a system.","platforms":["windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this package resides","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chrome_extension_content_scripts","description":"Chrome browser extension content scripts.","platforms":["darwin","linux","windows"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"identifier","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script","description":"The content script used by the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"match","description":"The pattern that the script is matched against","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"chrome_extensions","description":"Chrome-based browser extensions.","platforms":["darwin","linux","windows"],"columns":[{"name":"browser_type","description":"The browser type (Valid values: chrome, chromium, opera, yandex, brave, edge, edge_beta)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile","description":"The name of the Chrome profile that contains this extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The profile path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced_identifier","description":"Extension identifier, as specified by the preferences file. Empty if the extension is not in the profile.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier, computed from its manifest. Empty in case of error.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Extension-optional description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"default_locale","description":"Default locale supported by extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_locale","description":"Current locale supported by extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"persistent","description":"1 If extension is persistent across all tabs else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension folder","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"The permissions required by the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions_json","description":"The JSON-encoded permissions required by the extension","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"optional_permissions","description":"The permissions optionally required by the extensions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"optional_permissions_json","description":"The JSON-encoded permissions optionally required by the extensions","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"manifest_hash","description":"The SHA256 hash of the manifest.json file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"referenced","description":"1 if this extension is referenced by the Preferences file of the profile","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"from_webstore","description":"True if this extension was installed from the web store","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"1 if this extension is enabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Extension install time, in its original Webkit format","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_timestamp","description":"Extension install time, converted to unix time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"manifest_json","description":"The manifest file of the extension","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"key","description":"The extension key, from the manifest file","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"connectivity","description":"Provides the overall system's network state.","platforms":["windows"],"columns":[{"name":"disconnected","description":"True if the all interfaces are not connected to any network","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_no_traffic","description":"True if any interface is connected via IPv4, but has seen no traffic","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_no_traffic","description":"True if any interface is connected via IPv6, but has seen no traffic","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_subnet","description":"True if any interface is connected to the local subnet via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_local_network","description":"True if any interface is connected to a routed network via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_internet","description":"True if any interface is connected to the Internet via IPv4","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_subnet","description":"True if any interface is connected to the local subnet via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_local_network","description":"True if any interface is connected to a routed network via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_internet","description":"True if any interface is connected to the Internet via IPv6","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cpu_info","description":"Retrieve cpu hardware info of the machine.","platforms":["linux","windows"],"columns":[{"name":"device_id","description":"The DeviceID of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"processor_type","description":"The processor type, such as Central, Math, or Video.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_status","description":"The current operating status of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"number_of_cores","description":"The number of cores of the CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logical_processors","description":"The number of logical processors of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"address_width","description":"The width of the CPU address bus.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_clock_speed","description":"The current frequency of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_clock_speed","description":"The maximum possible frequency of the CPU.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"socket_designation","description":"The assigned socket on the board for the given CPU.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"availability","description":"The availability and status of the CPU.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"cpu_time","description":"Displays information from /proc/stat file about the time the cpu cores spent in different parts of the system.","platforms":["darwin","linux"],"columns":[{"name":"core","description":"Name of the cpu (core)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"Time spent in user mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Time spent in user mode with low priority (nice)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system","description":"Time spent in system mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"idle","description":"Time spent in the idle task","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"iowait","description":"Time spent waiting for I/O to complete","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"irq","description":"Time spent servicing interrupts","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"softirq","description":"Time spent servicing softirqs","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"steal","description":"Time spent in other operating systems when running in a virtualized environment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"guest","description":"Time spent running a virtual CPU for a guest OS under the control of the Linux kernel","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"guest_nice","description":"Time spent running a niced guest ","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cpuid","description":"Useful CPU features from the cpuid ASM call.","platforms":["darwin","linux","windows"],"columns":[{"name":"feature","description":"Present feature flags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Bit value or string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"output_register","description":"Register used to for feature value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"output_bit","description":"Bit in register value for feature value","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"input_eax","description":"Value of EAX used","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"crashes","description":"Application, System, and Mobile App crash logs.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of crash log","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Location of log file","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"identifier","description":"Identifier of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version info of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent PID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"responsible","description":"Process responsible for the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the crashed process","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"datetime","description":"Date/Time at which the crash occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crashed_thread","description":"Thread ID which crashed","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Most recent frame from the stack trace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_type","description":"Exception type of the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_codes","description":"Exception codes from the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_notes","description":"Exception notes from the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"The value of the system registers","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"crontab","description":"Line parsed values from system and user cron/tab.","platforms":["darwin","linux"],"columns":[{"name":"event","description":"The job @event name (rare)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"minute","description":"The exact minute for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hour","description":"The hour of the day for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"day_of_month","description":"The day of the month for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"month","description":"The month of the year for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"day_of_week","description":"The day of the week for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Raw command string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"File parsed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"cups_destinations","description":"Returns all configured printers.","platforms":["darwin"],"columns":[{"name":"name","description":"Name of the printer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option_name","description":"Option name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option_value","description":"Option value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"cups_jobs","description":"Returns all completed print jobs from cups.","platforms":["darwin"],"columns":[{"name":"title","description":"Title of the printed job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination","description":"The printer the job was sent to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The user who printed the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"format","description":"The format of the print job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the print job","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"completed_time","description":"When the job completed printing","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"processing_time","description":"How long the job took to process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"creation_time","description":"When the print request was initiated","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"curl","description":"Perform an http request and return stats about it.","platforms":["darwin","linux","windows"],"columns":[{"name":"url","description":"The url for the request","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"method","description":"The HTTP method for the request","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_agent","description":"The user-agent string to use for the request","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"response_code","description":"The HTTP status code for the response","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"round_trip_time","description":"Time taken to complete the request","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of bytes in the response","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"result","description":"The HTTP response body","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"curl_certificate","description":"Inspect TLS certificates by connecting to input hostnames.","platforms":["darwin","linux","windows"],"columns":[{"name":"hostname","description":"Hostname to CURL (domain[:port], e.g. osquery.io)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"common_name","description":"Common name of company issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"organization","description":"Organization issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"organization_unit","description":"Organization unit issued to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Certificate serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_common_name","description":"Issuer common name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_organization","description":"Issuer organization","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_organization_unit","description":"Issuer organization unit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valid_from","description":"Period of validity start date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valid_to","description":"Period of validity end date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256_fingerprint","description":"SHA-256 fingerprint","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1_fingerprint","description":"SHA1 fingerprint","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version Number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"signature_algorithm","description":"Signature Algorithm","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signature","description":"Signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_key_identifier","description":"Subject Key Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority_key_identifier","description":"Authority Key Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_usage","description":"Usage of key in certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extended_key_usage","description":"Extended usage of key in certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policies","description":"Certificate Policies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_alternative_names","description":"Subject Alternative Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"issuer_alternative_names","description":"Issuer Alternative Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"info_access","description":"Authority Information Access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subject_info_access","description":"Subject Information Access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_mappings","description":"Policy Mappings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"has_expired","description":"1 if the certificate has expired, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"basic_constraint","description":"Basic Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name_constraints","description":"Name Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_constraints","description":"Policy Constraints","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dump_certificate","description":"Set this value to '1' to dump certificate","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"timeout","description":"Set this value to the timeout in seconds to complete the TLS handshake (default 4s, use 0 for no timeout)","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"pem","description":"Certificate PEM format","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"deb_packages","description":"The installed DEB package database.","platforms":["linux"],"columns":[{"name":"name","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Package source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Package architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"Package revision","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Package status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"maintainer","description":"Package maintainer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"section","description":"Package section","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"priority","description":"Package priority","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"admindir","description":"libdpkg admindir. Defaults to /var/lib/dpkg","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"default_environment","description":"Default environment variables and values.","platforms":["windows"],"columns":[{"name":"variable","description":"Name of the environment variable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the environment variable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"expand","description":"1 if the variable needs expanding, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_file","description":"Similar to the file table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"partition","description":"A partition number","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"path","description":"A logical path within the device node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Creation time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_firmware","description":"A best-effort list of discovered firmware versions.","platforms":["darwin"],"columns":[{"name":"type","description":"Type of device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"The device name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"version","description":"Firmware version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_hash","description":"Similar to the hash table, but use TSK and allow block address access.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided inode data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"device_partitions","description":"Use TSK to enumerate details about partitions on a disk device.","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Absolute file path to device node","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"partition","description":"A partition number or description","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offset","description":"","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Byte size of each block","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Number of blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Number of meta nodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"disk_encryption","description":"Disk encryption status and information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Disk name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"uuid","description":"Disk Universally Unique Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"encrypted","description":"1 If encrypted: true (disk is encrypted), else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Description of cipher type and mode if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption_status","description":"Disk encryption status with one of following values: encrypted | not encrypted | undefined","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Currently authenticated user if available","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"user_uuid","description":"UUID of authenticated user if available","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"filevault_status","description":"FileVault status with one of following values: on | off | unknown","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]}]},{"name":"disk_events","description":"Track DMG disk image events (appearance/disappearance) when opened.","platforms":["darwin"],"columns":[{"name":"action","description":"Appear or disappear","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the DMG file accessed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Disk event name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Disk event BSD name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"UUID of the volume inside DMG if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of partition in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ejectable","description":"1 if ejectable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mountable","description":"1 if mountable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"writable","description":"1 if writable, 0 if not","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"content","description":"Disk event content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"media_name","description":"Disk event media name string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Disk event vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filesystem","description":"Filesystem if available","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"checksum","description":"UDIF Master checksum if available (CRC32)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of appearance/disappearance in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"disk_info","description":"Retrieve basic information about the physical disks of a system.","platforms":["windows"],"columns":[{"name":"partitions","description":"Number of detected partitions on disk.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_index","description":"Physical drive number of the disk.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The interface type of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"The unique identifier of the drive on the system.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pnp_device_id","description":"The unique identifier of the drive on the system.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_size","description":"Size of the disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hard drive model.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"The label of the disk object.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"The serial number of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The OS's description of the disk.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"dns_cache","description":"Enumerate the DNS cache using the undocumented DnsGetCacheDataTable function in dnsapi.dll.","platforms":["windows"],"columns":[{"name":"name","description":"DNS record name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"DNS record type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"DNS record flags","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"dns_resolvers","description":"Resolvers used by this host.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Address type index or order","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Address type: sortlist, nameserver, search","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Resolver IP/IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Address (sortlist) netmask length","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Resolver options","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"docker_container_envs","description":"Docker container environment variables.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Environment variable name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_fs_changes","description":"Changes to files or directories on container's filesystem.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"path","description":"FIle or directory path relative to rootfs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"change_type","description":"Type of change: C:Modified, A:Added, D:Deleted","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_labels","description":"Docker container labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_mounts","description":"Docker container mounts.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Type of mount (bind, volume)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Optional mount name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"source","description":"Source path on host","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination","description":"Destination path inside container","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver providing the mount","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Mount options (rw, ro)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rw","description":"1 if read/write. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"propagation","description":"Mount propagation","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_networks","description":"Docker container networks.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Network name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"network_id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"endpoint_id","description":"Endpoint ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ip_address","description":"IP address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ip_prefix_len","description":"IP subnet prefix length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_gateway","description":"IPv6 gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_prefix_len","description":"IPv6 subnet prefix length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mac_address","description":"MAC address","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_ports","description":"Docker container ports.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Protocol (tcp, udp)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Port inside the container","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host_ip","description":"Host IP address on which public port is listening","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host_port","description":"Host port","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_processes","description":"Docker container processes.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start in seconds since boot (non-sleeping)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"User name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Cumulative CPU time. [DD-]HH:MM:SS format","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu","description":"CPU utilization as percentage","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"mem","description":"Memory utilization as percentage","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_container_stats","description":"Docker container statistics. Queries on this table take at least one second.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"name","description":"Container name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pids","description":"Number of processes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"read","description":"UNIX time when stats were read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"preread","description":"UNIX time when stats were last read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"interval","description":"Difference between read and preread in nano-seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_read","description":"Total disk read bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_write","description":"Total disk write bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"num_procs","description":"Number of processors","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_total_usage","description":"Total CPU usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_kernelmode_usage","description":"CPU kernel mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_usermode_usage","description":"CPU user mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_cpu_usage","description":"CPU system usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"online_cpus","description":"Online CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_total_usage","description":"Last read total CPU usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_kernelmode_usage","description":"Last read CPU kernel mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_cpu_usermode_usage","description":"Last read CPU user mode usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_system_cpu_usage","description":"Last read CPU system usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pre_online_cpus","description":"Last read online CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_usage","description":"Memory usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_max_usage","description":"Memory maximum usage","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"Memory limit","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"network_rx_bytes","description":"Total network bytes read","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"network_tx_bytes","description":"Total network bytes transmitted","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_containers","description":"Docker containers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Container ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Container name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"image","description":"Docker image (name) used to launch this container","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"image_id","description":"Docker image ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Command with arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Container state (created, restarting, running, removing, paused, exited, dead)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Container status information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Identifier of the initial process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Container path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_entrypoint","description":"Container entrypoint(s)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"started_at","description":"Container start time as string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"finished_at","description":"Container finish time as string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"privileged","description":"Is the container privileged","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"security_options","description":"List of container security options","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"env_variables","description":"Container environmental variables","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"readonly_rootfs","description":"Is the root filesystem mounted as read only","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cgroup_namespace","description":"cgroup namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"ipc_namespace","description":"IPC namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mnt_namespace","description":"Mount namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"net_namespace","description":"Network namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"pid_namespace","description":"PID namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"user_namespace","description":"User namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"uts_namespace","description":"UTS namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"docker_image_history","description":"Docker image history information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of instruction in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"created_by","description":"Created by instruction","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Instruction comment","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_image_labels","description":"Docker image labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_image_layers","description":"Docker image layers information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"layer_id","description":"Layer ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"layer_order","description":"Layer Order (1 = base layer)","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_images","description":"Docker images information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size_bytes","description":"Size of image in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Comma-separated list of repository tags","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_info","description":"Docker system information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Docker system ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"containers","description":"Total number of containers","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_running","description":"Number of containers currently running","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_paused","description":"Number of containers in paused state","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"containers_stopped","description":"Number of containers in stopped state","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"images","description":"Number of images","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"storage_driver","description":"Storage driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_limit","description":"1 if memory limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_limit","description":"1 if swap limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_memory","description":"1 if kernel memory limit support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_period","description":"1 if CPU Completely Fair Scheduler (CFS) period support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_cfs_quota","description":"1 if CPU Completely Fair Scheduler (CFS) quota support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_shares","description":"1 if CPU share weighting support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_set","description":"1 if CPU set selection support is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_forwarding","description":"1 if IPv4 forwarding is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bridge_nf_iptables","description":"1 if bridge netfilter iptables is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bridge_nf_ip6tables","description":"1 if bridge netfilter ip6tables is enabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"oom_kill_disable","description":"1 if Out-of-memory kill is disabled. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logging_driver","description":"Logging driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cgroup_driver","description":"Control groups driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_type","description":"Operating system type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpus","description":"Number of CPUs","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory","description":"Total memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"http_proxy","description":"HTTP proxy","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"https_proxy","description":"HTTPS proxy","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"no_proxy","description":"Comma-separated list of domain extensions proxy should not be used for","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the docker host","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"server_version","description":"Server version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root_dir","description":"Docker root directory","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_network_labels","description":"Docker network labels.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_networks","description":"Docker networks information.","platforms":["darwin","linux"],"columns":[{"name":"id","description":"Network ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Network name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Network driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Time of creation as UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_ipv6","description":"1 if IPv6 is enabled on this network. 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"subnet","description":"Network subnet","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Network gateway","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_version","description":"Docker version information.","platforms":["darwin","linux"],"columns":[{"name":"version","description":"Docker version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"api_version","description":"API version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_api_version","description":"Minimum API version supported","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"git_commit","description":"Docker build git commit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"go_version","description":"Go version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"Operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Hardware architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Build time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_volume_labels","description":"Docker volume labels.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Label key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"value","description":"Optional label value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"docker_volumes","description":"Docker volumes information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Volume name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"driver","description":"Volume driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mount_point","description":"Mount point","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Volume type","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"drivers","description":"Details for in-use Windows device drivers. This does not display installed but unused drivers.","platforms":["windows"],"columns":[{"name":"device_id","description":"Device ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_name","description":"Device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"image","description":"Path to driver image file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Driver description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service","description":"Driver service name, if one exists","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_key","description":"Driver service registry key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Driver version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inf","description":"Associated inf file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Device/driver class name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider","description":"Driver provider","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Device manufacturer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_key","description":"Driver key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Driver date","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"signed","description":"Whether the driver is signed or not","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_metadata","description":"EC2 instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_type","description":"EC2 instance type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Hardware architecture of this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"region","description":"AWS region in which this instance launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"availability_zone","description":"Availability zone in which this instance launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Private IPv4 DNS hostname of the first interface of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_ipv4","description":"Private IPv4 address of the first interface of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC address for the first network interface of this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_groups","description":"Comma separated list of security group names","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iam_arn","description":"If there is an IAM role associated with the instance, contains instance profile ARN","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ami_id","description":"AMI ID used to launch this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reservation_id","description":"ID of the reservation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"account_id","description":"AWS account ID which owns this EC2 instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ec2_instance_tags","description":"EC2 instance tag key value pairs.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"EC2 instance ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Tag key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Tag value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"es_process_events","description":"Process execution events from EndpointSecurity.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"original_parent","description":"Original parent process ID in case of reparenting","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline_count","description":"Number of command line arguments","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective User ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective Group ID of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signing_id","description":"Signature identifier of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team_id","description":"Team identifier of thd process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Codesigning hash of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_binary","description":"Indicates if the binary is Apple signed binary (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"exit_code","description":"Exit code of a process in case of an exit event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"child_pid","description":"Process ID of a child process in case of a fork event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"codesigning_flags","description":"Codesigning flags matching one of these options, in a comma separated list: NOT_VALID, ADHOC, NOT_RUNTIME, INSTALLER. See kern/cs_blobs.h in XNU for descriptions.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"es_process_file_events","description":"Process execution events from EndpointSecurity.","platforms":["darwin"],"columns":[{"name":"version","description":"Version of EndpointSecurity event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seq_num","description":"Per event sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"global_seq_num","description":"Global sequence number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"The source or target filename for the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dest_filename","description":"Destination filename for the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"event_type","description":"Type of EndpointSecurity event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"etc_hosts","description":"Line-parsed /etc/hosts.","platforms":["darwin","linux","windows"],"columns":[{"name":"address","description":"IP address mapping","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hostnames","description":"Raw hosts mapping","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"etc_protocols","description":"Line-parsed /etc/protocols.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Protocol name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number","description":"Protocol number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"alias","description":"Protocol alias","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Comment with protocol description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"etc_services","description":"Line-parsed /etc/services.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Service port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Optional space separated list of other names for a service","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional comment for a service.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"event_taps","description":"Returns information about installed event taps.","platforms":["darwin"],"columns":[{"name":"enabled","description":"Is the Event Tap enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"event_tap_id","description":"Unique ID for the Tap","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"event_tapped","description":"The mask that identifies the set of events to be observed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_being_tapped","description":"The process ID of the target application","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"tapping_process","description":"The process ID of the application that created the event tap.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"extended_attributes","description":"Returns the extended attributes for files (similar to Windows ADS).","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute file path","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"directory","description":"Directory of file(s)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the value generated from the extended attribute","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The parsed information from the attribute","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base64","description":"1 if the value is base64 encoded else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"fan_speed_sensors","description":"Fan speeds.","platforms":["darwin"],"columns":[{"name":"fan","description":"Fan number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Fan name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"actual","description":"Actual speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimum speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum speed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"target","description":"Target speed","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"file","description":"Interactive filesystem attributes and metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"Absolute file path","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"directory","description":"Directory of file(s)","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"filename","description":"Name portion of file path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Device ID (optional)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block_size","description":"Block size of filesystem","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"btime","description":"(B)irth or (cr)eate time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_links","description":"Number of hard links","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"symlink","description":"1 if the path is a symlink, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"File status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"attributes","description":"File attrib string. See: https://ss64.com/nt/attrib.html","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"volume_serial","description":"Volume serial number","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"file_id","description":"file ID","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"file_version","description":"File version","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"product_version","description":"File product version","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"original_filename","description":"(Executable files only) Original filename","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"bsd_flags","description":"The BSD file flags (chflags). Possible values: NODUMP, UF_IMMUTABLE, UF_APPEND, OPAQUE, HIDDEN, ARCHIVED, SF_IMMUTABLE, SF_APPEND","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"file_events","description":"Track time/action changes to files specified in configuration data.","platforms":["darwin","linux"],"columns":[{"name":"target_path","description":"The path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file defined in the config","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Filesystem inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Owning user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Owning group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Permission bits","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of file in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Last access time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last status change time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"The MD5 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"The SHA1 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"The SHA256 of the file after change","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hashed","description":"1 if the file was hashed, 0 if not, -1 if hashing failed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"firefox_addons","description":"Firefox browser extensions, webapps, and addons.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local user that owns the addon","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Addon display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Addon identifier","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"creator","description":"Addon-supported creator string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Extension, addon, webapp","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Addon-supplied version string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Addon-supplied description string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source_url","description":"URL that installed the addon","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"visible","description":"1 If the addon is shown in browser else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If the addon is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 If the addon is application-disabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"1 If the addon applies background updates else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Global, profile location","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to plugin bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper","description":"macOS Gatekeeper Details.","platforms":["darwin"],"columns":[{"name":"assessments_enabled","description":"1 If a Gatekeeper is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"dev_id_enabled","description":"1 If a Gatekeeper allows execution from identified developers else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of Gatekeeper's gke.bundle","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"opaque_version","description":"Version of Gatekeeper's gkopaque.bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"gatekeeper_approved_apps","description":"Gatekeeper apps a user has allowed to run.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of executable allowed to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"requirement","description":"Code signing requirement language","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Last change time","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Last modification time","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"groups","description":"Local system groups.","platforms":["darwin","linux","windows"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","notes":"","hidden":true,"required":false,"index":true,"platforms":["windows","win32","cygwin"]},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"hardware_events","description":"Hardware (PCI/USB/HID) events from UDEV or IOKit.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"Remove, insert, change properties, etc","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Local device path assigned (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of hardware and hardware event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Driver claiming the device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Hardware device vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded Hardware vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"Hardware device model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded Hardware model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"Device serial (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"Device revision (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of hardware event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"hash","description":"Filesystem hash data.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"directory","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"md5","description":"MD5 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 hash of provided filesystem data","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"homebrew_packages","description":"The installed homebrew package database.","platforms":["darwin"],"columns":[{"name":"name","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Package install path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Current 'linked' version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"prefix","description":"Homebrew install prefix","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"hvci_status","description":"Retrieve HVCI info of the machine.","platforms":["windows"],"columns":[{"name":"version","description":"The version number of the Device Guard build.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_identifier","description":"The instance ID of Device Guard.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vbs_status","description":"The status of the virtualization based security settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"code_integrity_policy_enforcement_status","description":"The status of the code integrity policy enforcement settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"umci_policy_status","description":"The status of the User Mode Code Integrity security settings. Returns UNKNOWN if an error is encountered.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ibridge_info","description":"Information about the Apple iBridge hardware controller.","platforms":["darwin"],"columns":[{"name":"boot_uuid","description":"Boot UUID of the iBridge controller","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"coprocessor_version","description":"The manufacturer and chip version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"firmware_version","description":"The build version of the firmware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unique_chip_id","description":"Unique id of the iBridge controller","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ie_extensions","description":"Internet Explorer browser extensions.","platforms":["windows"],"columns":[{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registry_path","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Version of the executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executable","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"intel_me_info","description":"Intel ME/CSE Info.","platforms":["linux","windows"],"columns":[{"name":"version","description":"Intel ME version","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"interface_addresses","description":"Network interfaces and relevant metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mask","description":"Interface netmask","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"broadcast","description":"Broadcast address for the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"point_to_point","description":"PtP address for the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of address. One of dhcp, manual, auto, other, unknown","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"interface_details","description":"Detailed information and stats of network interfaces.","platforms":["darwin","linux","windows"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mac","description":"MAC of interface (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Interface type (includes virtual)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Network MTU","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"metric","description":"Metric based on the speed of the interface","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags (netdevice) for the device","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipackets","description":"Input packets","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"opackets","description":"Output packets","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ibytes","description":"Input bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"obytes","description":"Output bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ierrors","description":"Input errors","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"oerrors","description":"Output errors","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"idrops","description":"Input drops","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"odrops","description":"Output drops","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"collisions","description":"Packet Collisions detected","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Time of last device modification (optional)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"link_speed","description":"Interface speed in Mb/s","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"pci_slot","description":"PCI slot number","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"friendly_name","description":"The friendly display name of the interface.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"description","description":"Short description of the object a one-line string.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"manufacturer","description":"Name of the network adapter's manufacturer.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"connection_id","description":"Name of the network connection as it appears in the Network Connections Control Panel program.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"connection_status","description":"State of the network adapter connection to the network.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"enabled","description":"Indicates whether the adapter is enabled or not.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"physical_adapter","description":"Indicates whether the adapter is a physical or a logical adapter.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"speed","description":"Estimate of the current bandwidth in bits per second.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"service","description":"The name of the service the network adapter uses.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_enabled","description":"If TRUE, the dynamic host configuration protocol (DHCP) server automatically assigns an IP address to the computer system when establishing a network connection.","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_lease_expires","description":"Expiration date and time for a leased IP address that was assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_lease_obtained","description":"Date and time the lease was obtained for the IP address assigned to the computer by the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dhcp_server","description":"IP address of the dynamic host configuration protocol (DHCP) server.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_domain","description":"Organization name followed by a period and an extension that indicates the type of organization, such as 'microsoft.com'.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_domain_suffix_search_order","description":"Array of DNS domain suffixes to be appended to the end of host names during name resolution.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_host_name","description":"Host name used to identify the local computer for authentication by some utilities.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"dns_server_search_order","description":"Array of server IP addresses to be used in querying for DNS servers.","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"interface_ipv6","description":"IPv6 configuration and stats of network interfaces.","platforms":["darwin","linux"],"columns":[{"name":"interface","description":"Interface name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hop_limit","description":"Current Hop Limit","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"forwarding_enabled","description":"Enable IP forwarding","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"redirect_accept","description":"Accept ICMP redirect messages","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"rtadv_accept","description":"Accept ICMP Router Advertisement","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iokit_devicetree","description":"The IOKit registry matching the DeviceTree plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Device node name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent device registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"device_path","description":"Device tree path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service","description":"1 if the device conforms to IOService else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the device is in a busy state else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The device reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"depth","description":"Device nested depth","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iokit_registry","description":"The full IOKit registry without selecting a plane.","platforms":["darwin"],"columns":[{"name":"name","description":"Default name of the node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"Best matching device class (most-specific category)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"id","description":"IOKit internal registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Parent registry ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"busy_state","description":"1 if the node is in a busy state else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"retain_count","description":"The node reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"depth","description":"Node nested depth","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"iptables","description":"Linux IP packet filtering and NAT tool.","platforms":["linux"],"columns":[{"name":"filter_name","description":"Packet matching filter table name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"chain","description":"Size of module content.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy","description":"Policy that applies for this rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"target","description":"Target that applies for this rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Protocol number identification.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"src_port","description":"Protocol source port(s).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_port","description":"Protocol destination port(s).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"src_ip","description":"Source IP address.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"src_mask","description":"Source IP address mask.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iniface","description":"Input interface for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iniface_mask","description":"Input interface mask for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_ip","description":"Destination IP address.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dst_mask","description":"Destination IP address mask.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"outiface","description":"Output interface for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"outiface_mask","description":"Output interface mask for the rule.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"match","description":"Matching rule that applies.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"packets","description":"Number of matching packets for this rule.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes","description":"Number of matching bytes for this rule.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_extensions","description":"macOS's kernel extensions, both loaded and within the load search path.","platforms":["darwin"],"columns":[{"name":"idx","description":"Extension load tag or index","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"refs","description":"Reference count","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Bytes of wired memory used by extension","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension label","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"linked_against","description":"Indexes of extensions this extension is linked against","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Optional path to extension bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_info","description":"Basic active kernel information.","platforms":["darwin","linux","windows"],"columns":[{"name":"version","description":"Kernel version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arguments","description":"Kernel arguments","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Kernel path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"Kernel device identifier","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_modules","description":"Linux kernel modules both loaded and within the load search path.","platforms":["linux"],"columns":[{"name":"name","description":"Module name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of module content","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"used_by","description":"Module reverse dependencies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Kernel module status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Kernel module address","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kernel_panics","description":"System kernel panic logs.","platforms":["darwin"],"columns":[{"name":"path","description":"Location of log file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Formatted time of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"A space delimited line of register:value pairs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"frame_backtrace","description":"Backtrace of the crashed module","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module_backtrace","description":"Modules appearing in the crashed module's backtrace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dependencies","description":"Module dependencies existing in crashed module's backtrace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Process name corresponding to crashed thread","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os_version","description":"Version of the operating system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"kernel_version","description":"Version of the system kernel","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"system_model","description":"Physical system model, for example 'MacBookPro12,1 (Mac-E43C1C25D4880AD6)'","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"System uptime at kernel panic in nanoseconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_loaded","description":"Last loaded module before panic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_unloaded","description":"Last unloaded module before panic","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"keychain_acls","description":"Applications that have ACL entries in the keychain.","platforms":["darwin"],"columns":[{"name":"keychain_path","description":"The path of the keychain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authorizations","description":"A space delimited set of authorization attributes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path of the authorized application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The description included with the ACL entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"An optional label tag that may be included with the keychain entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"keychain_items","description":"Generic details about keychain items.","platforms":["darwin"],"columns":[{"name":"label","description":"Generic item name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional item description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"comment","description":"Optional keychain comment","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"account","description":"Optional item account","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"created","description":"Date item was created","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified","description":"Date of last modification","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Keychain item type (class)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to keychain containing item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"known_hosts","description":"A line-delimited known_hosts table.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"The local user that owns the known_hosts file","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"parsed authorized keys line","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key_file","description":"Path to known_hosts file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"kva_speculative_info","description":"Display kernel virtual address and speculative execution information for the system.","platforms":["windows"],"columns":[{"name":"kva_shadow_enabled","description":"Kernel Virtual Address shadowing is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_user_global","description":"User pages are marked as global.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_pcid","description":"Kernel VA PCID flushing optimization is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"kva_shadow_inv_pcid","description":"Kernel VA INVPCID is enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_mitigations","description":"Branch Prediction mitigations are enabled.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_system_pol_disabled","description":"Branch Predictions are disabled via system policy.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bp_microcode_disabled","description":"Branch Predictions are disabled due to lack of microcode update.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_spec_ctrl_supported","description":"SPEC_CTRL MSR supported by CPU Microcode.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ibrs_support_enabled","description":"Windows uses IBRS.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"stibp_support_enabled","description":"Windows uses STIBP.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_pred_cmd_supported","description":"PRED_CMD MSR supported by CPU Microcode.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"last","description":"System logins and logouts.","platforms":["darwin","linux"],"columns":[{"name":"username","description":"Entry username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tty","description":"Entry terminal","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Entry type, according to ut_type types (utmp.h)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Entry type name, according to ut_type types (utmp.h)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Entry hostname","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"launchd","description":"LaunchAgents and LaunchDaemons from default search paths.","platforms":["darwin"],"columns":[{"name":"path","description":"Path to daemon or agent plist","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"File name of plist (used by launchd)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Daemon or agent service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"program","description":"Path to target program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"run_at_load","description":"Should the program run on launch load","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"keep_alive","description":"Should the process be restarted if killed","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"on_demand","description":"Deprecated key, replaced by keep_alive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"Skip loading this daemon or agent on boot","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Run this daemon or agent as this username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Run this daemon or agent as this group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stdout_path","description":"Pipe stdout to a target path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stderr_path","description":"Pipe stderr to a target path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_interval","description":"Frequency to run in seconds","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"program_arguments","description":"Command line arguments passed to program","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"watch_paths","description":"Key that launches daemon or agent if path is modified","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"queue_directories","description":"Similar to watch_paths but only with non-empty directories","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inetd_compatibility","description":"Run this daemon or agent as it was launched from inetd","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_on_mount","description":"Run daemon or agent every time a filesystem is mounted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root_directory","description":"Key used to specify a directory to chroot to before launch","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"working_directory","description":"Key used to specify a directory to chdir to before launch","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_type","description":"Key describes the intended purpose of the job","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"launchd_overrides","description":"Override keys, per user, for LaunchDaemons and Agents.","platforms":["darwin"],"columns":[{"name":"label","description":"Daemon or agent service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Name of the override key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Overridden value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID applied to the override, 0 applies to all","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to daemon or agent plist","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"listening_ports","description":"Processes with listening (bound) network sockets/ports.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"port","description":"Transport layer port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Specific address for bind","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"Socket file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path for UNIX domain sockets","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"load_average","description":"Displays information about the system wide load averages.","platforms":["darwin","linux"],"columns":[{"name":"period","description":"Period over which the average is calculated.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"average","description":"Load average over the specified period.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"location_services","description":"Reports the status of the Location Services feature of the OS.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 if Location Services are enabled, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"logged_in_users","description":"Users with an active shell on the system.","platforms":["darwin","linux","windows"],"columns":[{"name":"type","description":"Login type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"User login name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tty","description":"Device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Remote hostname","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time entry was made","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"The user's unique security identifier","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"registry_hive","description":"HKEY_USERS registry hive","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"logical_drives","description":"Details for logical drives on the system. A logical drive generally represents a single partition.","platforms":["windows"],"columns":[{"name":"device_id","description":"The drive id, usually the drive name, e.g., 'C:'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Deprecated (always 'Unknown').","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"The canonical description of the drive, e.g. 'Logical Fixed Disk', 'CD-ROM Disk'.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"free_space","description":"The amount of free space, in bytes, of the drive (-1 on failure).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The total amount of space, in bytes, of the drive (-1 on failure).","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"file_system","description":"The file system of the drive.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"boot_partition","description":"True if Windows booted from this drive.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"logon_sessions","description":"Windows Logon Session.","platforms":["windows"],"columns":[{"name":"logon_id","description":"A locally unique identifier (LUID) that identifies a logon session.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The account name of the security principal that owns the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_domain","description":"The name of the domain used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authentication_package","description":"The authentication package used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_type","description":"The logon method.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"session_id","description":"The Terminal Services session identifier.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_sid","description":"The user's security identifier (SID).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_time","description":"The time the session owner logged on.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_server","description":"The name of the server used to authenticate the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dns_domain_name","description":"The DNS name for the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"upn","description":"The user principal name (UPN) for the owner of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_script","description":"The script used for logging on.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_path","description":"The home directory for the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"home_directory","description":"The home directory for the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"home_directory_drive","description":"The drive location of the home directory of the logon session.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_certificates","description":"LXD certificates information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fingerprint","description":"SHA256 hash of the certificate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"certificate","description":"Certificate content","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster","description":"LXD cluster information.","platforms":["linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether clustering enabled (1) or not (0) on this node","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_entity","description":"Type of configuration parameter for this node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_name","description":"Name of configuration parameter","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_key","description":"Config key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_value","description":"Config value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"member_config_description","description":"Config description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_cluster_members","description":"LXD cluster members information.","platforms":["linux"],"columns":[{"name":"server_name","description":"Name of the LXD server node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"url","description":"URL of the node","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"database","description":"Whether the server is a database node (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Status of the node (Online/Offline)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the node (Online/Offline)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_images","description":"LXD images information.","platforms":["linux"],"columns":[{"name":"id","description":"Image ID","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"architecture","description":"Target architecture for the image","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"OS on which image is based","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"release","description":"OS release version on which the image is based","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Image description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"aliases","description":"Comma-separated list of image aliases","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Filename of the image file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of image in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_update","description":"Whether the image auto-updates (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cached","description":"Whether image is cached (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"public","description":"Whether image is public (1) or not (0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of image creation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"expires_at","description":"ISO time of image expiration","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uploaded_at","description":"ISO time of image upload","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_used_at","description":"ISO time for the most recent use of this image in terms of container spawn","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_server","description":"Server for image update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_protocol","description":"Protocol used for image information update and image import from source server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_certificate","description":"Certificate for update source server","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_source_alias","description":"Alias of image at update source server","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_config","description":"LXD instance configuration information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"key","description":"Configuration parameter name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Configuration parameter value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instance_devices","description":"LXD instance devices information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"device","description":"Name of the device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_type","description":"Device type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Device info param name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Device info param value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_instances","description":"LXD instances information.","platforms":["linux"],"columns":[{"name":"name","description":"Instance name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"status","description":"Instance state (running, stopped, etc.)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"stateful","description":"Whether the instance is stateful(1) or not(0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ephemeral","description":"Whether the instance is ephemeral(1) or not(0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"created_at","description":"ISO time of creation","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"base_image","description":"ID of image used to launch this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"architecture","description":"Instance architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"os","description":"The OS of this instance","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Instance description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Instance's process ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"processes","description":"Number of processes running inside this instance","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_networks","description":"LXD network information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"managed","description":"1 if network created by LXD, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv4_address","description":"IPv4 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipv6_address","description":"IPv6 address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"used_by","description":"URLs for containers using this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_received","description":"Number of bytes received on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_sent","description":"Number of bytes sent on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"packets_received","description":"Number of packets received on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"packets_sent","description":"Number of packets sent on this network","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hwaddr","description":"Hardware address for this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Network status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"MTU size","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"lxd_storage_pools","description":"LXD storage pool information.","platforms":["linux"],"columns":[{"name":"name","description":"Name of the storage pool","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"Storage driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Storage pool source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of the storage pool","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"space_used","description":"Storage space used in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"space_total","description":"Total available storage space in bytes for this storage pool","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_used","description":"Number of inodes used","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_total","description":"Total number of inodes available in this storage pool","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"magic","description":"Magic number recognition library table.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Absolute path to target file","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"magic_db_files","description":"Colon(:) separated list of files where the magic db file can be found. By default one of the following is used: /usr/share/file/magic/magic, /usr/share/misc/magic or /usr/share/misc/magic.mgc","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Magic number data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mime_type","description":"MIME type data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mime_encoding","description":"MIME encoding data from libmagic","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"managed_policies","description":"The managed configuration policies from AD, MDM, MCX, etc.","platforms":["darwin"],"columns":[{"name":"domain","description":"System or manager-chosen domain key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Optional UUID assigned to policy set","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Policy key name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Policy value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Policy applies only this user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manual","description":"1 if policy was loaded manually, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_devices","description":"Software RAID array settings.","platforms":["linux"],"columns":[{"name":"device_name","description":"md device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Current state of the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"raid_level","description":"Current raid level of the array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"size of the array in blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"chunk_size","description":"chunk size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"raid_disks","description":"Number of configured RAID disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nr_raid_disks","description":"Number of partitions or disk devices to comprise the array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"working_disks","description":"Number of working disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active_disks","description":"Number of active disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"failed_disks","description":"Number of failed disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"spare_disks","description":"Number of idle disks in array","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_state","description":"State of the superblock","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_version","description":"Version of the superblock","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"superblock_update_time","description":"Unix timestamp of last update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_on_mem","description":"Pages allocated in in-memory bitmap, if enabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_chunk_size","description":"Bitmap chunk size","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bitmap_external_file","description":"External referenced bitmap file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_progress","description":"Progress of the recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_finish","description":"Estimated duration of recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"recovery_speed","description":"Speed of recovery activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_progress","description":"Progress of the resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_finish","description":"Estimated duration of resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"resync_speed","description":"Speed of resync activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_progress","description":"Progress of the reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_finish","description":"Estimated duration of reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"reshape_speed","description":"Speed of reshape activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_progress","description":"Progress of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_finish","description":"Estimated duration of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"check_array_speed","description":"Speed of the check array activity","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unused_devices","description":"Unused devices","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"other","description":"Other information associated with array from /proc/mdstat","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_drives","description":"Drive devices used for Software RAID.","platforms":["linux"],"columns":[{"name":"md_device_name","description":"md device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_name","description":"Drive device name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"slot","description":"Slot position of disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the drive","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"md_personalities","description":"Software RAID setting supported by the kernel.","platforms":["linux"],"columns":[{"name":"name","description":"Name of personality supported by kernel","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"mdfind","description":"Run searches against the spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file returned from spotlight","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"The query that was run to find the file","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"mdls","description":"Query file metadata in the Spotlight database.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of the file","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"key","description":"Name of the metadata key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value stored in the metadata key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"valuetype","description":"CoreFoundation type of data stored in value","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"memory_array_mapped_addresses","description":"Data associated for address mapping of physical memory arrays.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_handle","description":"Handle of the memory array associated with this structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partition_width","description":"Number of memory devices that form a single row of memory for the address partition of this structure","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_arrays","description":"Data associated with collection of memory devices that operate to form a memory address.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Physical location of the memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"use","description":"Function for which the array is used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_error_correction","description":"Primary hardware error correction or detection method supported","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_capacity","description":"Maximum capacity of array in gigabytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_error_info_handle","description":"Handle, or instance number, associated with any error that was detected for the array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number_memory_devices","description":"Number of memory devices on array","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_device_mapped_addresses","description":"Data associated for address mapping of physical memory devices.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_device_handle","description":"Handle of the memory device structure associated with this structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_mapped_address_handle","description":"Handle of the memory array mapped address to which this device range is mapped to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"starting_address","description":"Physical stating address, in kilobytes, of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ending_address","description":"Physical ending address of last kilobyte of a range of memory mapped to physical memory array","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partition_row_position","description":"Identifies the position of the referenced memory device in a row of the address partition","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interleave_position","description":"The position of the device in a interleave, i.e. 0 indicates non-interleave, 1 indicates 1st interleave, 2 indicates 2nd interleave, etc.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interleave_data_depth","description":"The max number of consecutive rows from memory device that are accessed in a single interleave transfer; 0 indicates device is non-interleave","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_devices","description":"Physical memory device (type 17) information retrieved from SMBIOS.","platforms":["darwin","linux","windows"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure in SMBIOS","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"array_handle","description":"The memory array that the device is attached to","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"form_factor","description":"Implementation form factor for this memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"total_width","description":"Total width, in bits, of this memory device, including any check or error-correction bits","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"data_width","description":"Data width, in bits, of this memory device","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size of memory device in Megabyte","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"set","description":"Identifies if memory device is one of a set of devices. A value of 0 indicates no set affiliation.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"device_locator","description":"String number of the string that identifies the physically-labeled socket or board position where the memory device is located","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bank_locator","description":"String number of the string that identifies the physically-labeled bank where the memory device is located","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_type","description":"Type of memory used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_type_details","description":"Additional details for memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_speed","description":"Max speed of memory device in megatransfers per second (MT/s)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"configured_clock_speed","description":"Configured speed of memory device in megatransfers per second (MT/s)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"Manufacturer ID string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_number","description":"Serial number of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"asset_tag","description":"Manufacturer specific asset tag of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"part_number","description":"Manufacturer specific serial number of memory device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_voltage","description":"Minimum operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_voltage","description":"Maximum operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"configured_voltage","description":"Configured operating voltage of device in millivolts","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_error_info","description":"Data associated with errors of a physical memory array.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_type","description":"type of error associated with current error status for array or device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_granularity","description":"Granularity to which the error can be resolved","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_operation","description":"Memory access operation that caused the error","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_syndrome","description":"Vendor specific ECC syndrome or CRC data associated with the erroneous access","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_array_error_address","description":"32 bit physical address of the error based on the addressing of the bus to which the memory array is connected","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_error_address","description":"32 bit physical address of the error relative to the start of the failing memory address, in bytes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"error_resolution","description":"Range, in bytes, within which this error can be determined, when an error address is given","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_info","description":"Main memory information in bytes.","platforms":["linux"],"columns":[{"name":"memory_total","description":"Total amount of physical RAM, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_free","description":"The amount of physical RAM, in bytes, left unused by the system","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"memory_available","description":"The amount of physical RAM, in bytes, available for starting new applications, without swapping","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"buffers","description":"The amount of physical RAM, in bytes, used for file buffers","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cached","description":"The amount of physical RAM, in bytes, used as cache memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_cached","description":"The amount of swap, in bytes, used as cache memory","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"The total amount of buffer or page cache memory, in bytes, that is in active use","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"The total amount of buffer or page cache memory, in bytes, that are free and available","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_total","description":"The total amount of swap available, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_free","description":"The total amount of swap free, in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"memory_map","description":"OS memory region map.","platforms":["linux"],"columns":[{"name":"name","description":"Region name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start","description":"Start address of memory region","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"end","description":"End address of memory region","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"mounts","description":"System mounted devices and filesystems (not process specific).","platforms":["darwin","linux"],"columns":[{"name":"device","description":"Mounted device","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"device_alias","description":"Mounted device alias","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Mounted device path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Mounted device type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_size","description":"Block size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks","description":"Mounted device used blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_free","description":"Mounted device free blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"blocks_available","description":"Mounted device available blocks","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes","description":"Mounted device used inodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inodes_free","description":"Mounted device free inodes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Mounted device flags","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"msr","description":"Various pieces of data stored in the model specific register per processor. NOTE: the msr kernel module must be enabled, and osquery must be run as root.","platforms":["linux"],"columns":[{"name":"processor_number","description":"The processor number as reported in /proc/cpuinfo","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"turbo_disabled","description":"Whether the turbo feature is disabled.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"turbo_ratio_limit","description":"The turbo feature ratio limit.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_info","description":"Platform information.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"perf_ctl","description":"Performance setting for the processor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"perf_status","description":"Performance status for the processor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"feature_control","description":"Bitfield controlling enabled features.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_power_limit","description":"Run Time Average Power Limiting power limit.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_energy_status","description":"Run Time Average Power Limiting energy status.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"rapl_power_units","description":"Run Time Average Power Limiting power units.","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"nfs_shares","description":"NFS shares exported by the host.","platforms":["darwin"],"columns":[{"name":"share","description":"Filesystem path to the share","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"options","description":"Options string set on the export share","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"readonly","description":"1 if the share is exported readonly else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"npm_packages","description":"Node packages installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Package-supplied description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Package-supplied author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"homepage","description":"Package supplied homepage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where node_modules are located","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"ntdomains","description":"Display basic NT domain information of a Windows machine.","platforms":["windows"],"columns":[{"name":"name","description":"The label by which the object is known.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"client_site_name","description":"The name of the site where the domain controller is configured.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dc_site_name","description":"The name of the site where the domain controller is located.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dns_forest_name","description":"The name of the root of the DNS tree.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_controller_address","description":"The IP Address of the discovered domain controller..","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_controller_name","description":"The name of the discovered domain controller.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"domain_name","description":"The name of the domain.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"The current status of the domain object.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ntfs_acl_permissions","description":"Retrieve NTFS ACL permission information for files and directories.","platforms":["windows"],"columns":[{"name":"path","description":"Path to the file or directory.","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"type","description":"Type of access mode for the access control entry.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"principal","description":"User or group to which the ACE applies.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"access","description":"Specific permissions that indicate the rights described by the ACE.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inherited_from","description":"The inheritance policy of the ACE.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ntfs_journal_events","description":"Track time/action changes to files specified in configuration data.","platforms":["windows"],"columns":[{"name":"action","description":"Change action (Write, Delete, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category that the event originated from","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"old_path","description":"Old path (renames only)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"record_timestamp","description":"Journal record timestamp","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"record_usn","description":"The update sequence number that identifies the journal record","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"node_ref_number","description":"The ordinal that associates a journal record with a filename","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"parent_ref_number","description":"The ordinal that associates a journal record with a filename's parent directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"drive_letter","description":"The drive letter identifying the source journal","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"file_attributes","description":"File attributes","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partial","description":"Set to 1 if either path or old_path only contains the file or folder name","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of file event","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"nvram","description":"Apple NVRAM variable listing.","platforms":["darwin"],"columns":[{"name":"name","description":"Variable name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Data type (CFData, CFString, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Raw variable data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"oem_strings","description":"OEM defined strings retrieved from SMBIOS.","platforms":["darwin","linux"],"columns":[{"name":"handle","description":"Handle, or instance number, associated with the Type 11 structure","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"number","description":"The string index of the structure","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"The value of the OEM string","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"office_mru","description":"View recently opened Office documents.","platforms":["windows"],"columns":[{"name":"application","description":"Associated Office application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Office application version number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"File path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_opened_time","description":"Most recent opened time file was opened","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"os_version","description":"A single row containing the operating system name and version.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Distribution or product name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Pretty, suitable for presentation, OS version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"major","description":"Major release version","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minor","description":"Minor release version","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"patch","description":"Optional patch release","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build","description":"Optional build-specific or variant string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform","description":"OS Platform or ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_like","description":"Closely related platforms","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"codename","description":"OS version codename","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"OS Architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"The install date of the OS.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"osquery_events","description":"Information about the event publishers and subscribers.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Event publisher or subscriber name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the associated publisher","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Either publisher or subscriber","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subscriptions","description":"Number of subscriptions the publisher received or subscriber used","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"events","description":"Number of events emitted or received since osquery started","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"refreshes","description":"Publisher only: number of runloop restarts","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 if the publisher or subscriber is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_extensions","description":"List of active osquery extensions.","platforms":["darwin","linux","windows"],"columns":[{"name":"uuid","description":"The transient ID assigned for communication","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Extension's name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension's version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk_version","description":"osquery SDK version used to build the extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the extension's Thrift connection or library path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"SDK extension type: core, extension, or module","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_flags","description":"Configurable flags that modify osquery's behavior.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Flag name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Flag type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Flag description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"default_value","description":"Flag default value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Flag value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell_only","description":"Is the flag shell only?","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_info","description":"Top level information about the running version of osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread/handle) ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instance_id","description":"Unique, long-lived ID per instance of osquery","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"osquery toolkit version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_hash","description":"Hash of the working configuration state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_valid","description":"1 if the config was loaded and considered valid, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"extensions","description":"osquery extensions status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_platform","description":"osquery toolkit build platform","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_distro","description":"osquery toolkit platform distribution name (os version)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"UNIX time in seconds when the process started","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"watcher","description":"Process (or thread/handle) ID of optional watcher process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"platform_mask","description":"The osquery platform bitmask","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_packs","description":"Information about the current query packs that are loaded in osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"The given name for this query pack","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"platform","description":"Platforms this query is supported on","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Minimum osquery version that this query will run on","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shard","description":"Shard restriction limit, 1-100, 0 meaning no restriction","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"discovery_cache_hits","description":"The number of times that the discovery query used cached values since the last time the config was reloaded","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"discovery_executions","description":"The number of times that the discovery queries have been executed since the last time the config was reloaded","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"Whether this pack is active (the version, platform and discovery queries match) yes=1, no=0.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_registry","description":"List the osquery registry plugins.","platforms":["darwin","linux","windows"],"columns":[{"name":"registry","description":"Name of the osquery registry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the plugin item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uuid","description":"Extension route UUID (0 for core)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"internal","description":"1 If the plugin is internal else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"1 If this plugin is active else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"osquery_schedule","description":"Information about the current queries that are scheduled in osquery.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"The given name for this query","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"The exact query to run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"interval","description":"The interval in seconds to run this query, not an exact interval","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"executions","description":"Number of times the query was executed","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_executed","description":"UNIX time stamp in seconds of the last completed execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"denylisted","description":"1 if the query is denylisted else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"output_size","description":"Cumulative total number of bytes generated by the resultant rows of the query","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wall_time","description":"Total wall time in seconds spent executing (deprecated), hidden=True","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wall_time_ms","description":"Total wall time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_wall_time_ms","description":"Wall time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"Total user time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_user_time","description":"User time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"Total system time in milliseconds spent executing","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_system_time","description":"System time in milliseconds of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"average_memory","description":"Average of the bytes of resident memory left allocated after collecting results","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_memory","description":"Resident memory in bytes left allocated after collecting results of the latest execution","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"package_bom","description":"macOS package bill of materials (BOM) file list.","platforms":["darwin"],"columns":[{"name":"filepath","description":"Package file or directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Expected user of file or directory","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Expected group of file or directory","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Expected permissions","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Timestamp the file was installed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of package bom","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"package_install_history","description":"macOS package install history.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Label packageIdentifiers","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Label date as UNIX timestamp","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package display version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Install source: usually the installer process name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"content_type","description":"Package content_type (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"package_receipts","description":"macOS package receipt details.","platforms":["darwin"],"columns":[{"name":"package_id","description":"Package domain identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"package_filename","description":"Filename of original .pkg file","type":"text","notes":"","hidden":true,"required":false,"index":true},{"name":"version","description":"Installed package version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"location","description":"Optional relative install path on volume","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_time","description":"Timestamp of install time","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"installer_name","description":"Name of installer process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of receipt plist","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"password_policy","description":"Password Policies for macOS.","platforms":["darwin"],"columns":[{"name":"uid","description":"User ID for the policy, -1 for policies that are global","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"policy_identifier","description":"Policy Identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_content","description":"Policy content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"policy_description","description":"Policy description","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"patches","description":"Lists all the patches applied. Note: This does not include patches applied via MSI or downloaded from Windows Update (e.g. Service Packs).","platforms":["windows"],"columns":[{"name":"csname","description":"The name of the host the patch is installed on.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hotfix_id","description":"The KB ID of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"caption","description":"Short description of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Fuller description of the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fix_comments","description":"Additional comments about the patch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"installed_by","description":"The system context in which the patch as installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the patch was installed. Lack of a value does not indicate that the patch was not installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"installed_on","description":"The date when the patch was installed.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"pci_devices","description":"PCI devices active on the host system.","platforms":["darwin","linux"],"columns":[{"name":"pci_slot","description":"PCI Device used slot","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pci_class","description":"PCI Device class","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"PCI Device used driver","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"PCI Device vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded PCI Device vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"PCI Device model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded PCI Device model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pci_class_id","description":"PCI Device class ID in hex format","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"pci_subclass_id","description":"PCI Device subclass in hex format","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"pci_subclass","description":"PCI Device subclass","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_vendor_id","description":"Vendor ID of PCI device subsystem","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_vendor","description":"Vendor of PCI device subsystem","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_model_id","description":"Model ID of PCI device subsystem","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"subsystem_model","description":"Device description of PCI device subsystem","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"physical_disk_performance","description":"Provides provides raw data from performance counters that monitor hard or fixed disk drives on the system.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the physical disk","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_read","description":"Average number of bytes transferred from the disk during read operations","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_bytes_per_write","description":"Average number of bytes transferred to the disk during write operations","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_read_queue_length","description":"Average number of read requests that were queued for the selected disk during the sample interval","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_write_queue_length","description":"Average number of write requests that were queued for the selected disk during the sample interval","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_read","description":"Average time, in seconds, of a read operation of data from the disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"avg_disk_sec_per_write","description":"Average time, in seconds, of a write operation of data to the disk","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"current_disk_queue_length","description":"Number of requests outstanding on the disk at the time the performance data is collected","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_read_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_write_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing write requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_disk_time","description":"Percentage of elapsed time that the selected disk drive is busy servicing read or write requests","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"percent_idle_time","description":"Percentage of time during the sample interval that the disk was idle","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"pipes","description":"Named and Anonymous pipes.","platforms":["windows"],"columns":[{"name":"pid","description":"Process ID of the process to which the pipe belongs","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the pipe","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"instances","description":"Number of instances of the named pipe","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"max_instances","description":"The maximum number of instances creatable for this pipe","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"The flags indicating whether this pipe connection is a server or client end, and if the pipe for sending messages or bytes","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"platform_info","description":"Information about EFI/UEFI/ROM and platform/boot.","platforms":["darwin","linux","windows"],"columns":[{"name":"vendor","description":"Platform code vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Platform code version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Self-reported platform code update date","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"revision","description":"BIOS major and minor revision","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"extra","description":"Platform-specific additional information","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"firmware_type","description":"The type of firmware (uefi, bios, iboot, openfirmware, unknown).","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"Relative address of firmware mapping","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"size","description":"Size in bytes of firmware","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]},{"name":"volume_size","description":"(Optional) size of firmware volume","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"plist","description":"Read and parse a plist file.","platforms":["darwin"],"columns":[{"name":"key","description":"Preference top-level key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subkey","description":"Intermediate key path, includes lists/dicts","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"(required) read preferences from a plist","type":"text","notes":"","hidden":false,"required":true,"index":false}]},{"name":"portage_keywords","description":"A summary about portage configurations like keywords, mask and unmask.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"keyword","description":"The keyword applied to the package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mask","description":"If the package is masked","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"unmask","description":"If the package is unmasked","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"portage_packages","description":"List of currently installed packages.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version which are affected by the use flags, empty means all","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"slot","description":"The slot used by package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"build_time","description":"Unix time when package was built","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"repository","description":"From which repository the ebuild was used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eapi","description":"The eapi for the ebuild","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"The size of the package","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"world","description":"If package is in the world file","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"portage_use","description":"List of enabled portage USE values for specific package.","platforms":["linux"],"columns":[{"name":"package","description":"Package name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"The version of the installed package","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"use","description":"USE flag which has been enabled for package","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"power_sensors","description":"Machine power (currents, voltages, wattages, etc) sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on macOS","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"category","description":"The sensor category: currents, voltage, wattage","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of power source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Power in Watts","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"powershell_events","description":"Powershell script blocks reconstructed to their full script content, this table requires script block logging to be enabled.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received by the osquery event publisher","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the Powershell script event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_block_id","description":"The unique GUID of the powershell script to which this block belongs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_block_count","description":"The total number of script blocks for this script","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"script_text","description":"The text content of the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_name","description":"The name of the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_path","description":"The path for the Powershell script","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cosine_similarity","description":"How similar the Powershell script is to a provided 'normal' character frequency","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"preferences","description":"macOS defaults and managed preferences.","platforms":["darwin"],"columns":[{"name":"domain","description":"Application ID usually in com.name.product format","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Preference top-level key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"subkey","description":"Intemediate key path, includes lists/dicts","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"String value of most CF types","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"forced","description":"1 if the value is forced/managed, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"(optional) read preferences for a specific user","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"'current' or 'any' host, where 'current' takes precedence","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"prefetch","description":"Prefetch files show metadata related to file execution.","platforms":["windows"],"columns":[{"name":"path","description":"Prefetch file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Executable filename.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hash","description":"Prefetch CRC hash.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Most recent time application was run.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"other_run_times","description":"Other execution times in prefetch file.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"run_count","description":"Number of times the application has been run.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Application file size.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_serial","description":"Volume serial number.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_creation","description":"Volume creation time.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_files_count","description":"Number of files accessed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_directories_count","description":"Number of directories accessed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_files","description":"Files accessed by application within ten seconds of launch.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_directories","description":"Directories accessed by application within ten seconds of launch.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_envs","description":"A key/value table of environment variables for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"key","description":"Environment variable name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Environment variable value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_events","description":"Track time/action process executions.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"File mode permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Command line arguments (argv)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline_size","description":"Actual size (bytes) of command line arguments","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"env","description":"Environment variables delimited by spaces","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"env_count","description":"Number of environment variables","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"env_size","description":"Actual size (bytes) of environment list","type":"bigint","notes":"","hidden":true,"required":false,"index":false},{"name":"cwd","description":"The process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID at process start","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"File owner user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_gid","description":"File owner group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"File last access in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"File modification in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"File last metadata change in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"btime","description":"File creation in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"overflows","description":"List of structures that overflowed","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"parent","description":"Process parent's PID, or -1 if cannot be determined.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"status","description":"OpenBSM Attribute: Status of the process","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"fsuid","description":"Filesystem user ID at process start","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"suid","description":"Saved user ID at process start","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"fsgid","description":"Filesystem group ID at process start","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"sgid","description":"Saved group ID at process start","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"syscall","description":"Syscall name: fork, vfork, clone, execve, execveat","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"process_file_events","description":"A File Integrity Monitor implementation using the audit service.","platforms":["linux"],"columns":[{"name":"operation","description":"Operation type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ppid","description":"Parent process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"executable","description":"The executable path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partial","description":"True if this is a partial event (i.e.: this process existed before we started osquery)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"The current working directory of the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"The path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"dest_path","description":"The canonical path associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"The uid of the process performing the action","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"The gid of the process performing the action","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Effective user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Effective group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsuid","description":"Filesystem user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fsgid","description":"Filesystem group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Saved user ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Saved group ID of the process using the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"process_memory_map","description":"Process memory mapped files and pseudo device/regions.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"start","description":"Virtual start address (hex)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"end","description":"Virtual end address (hex)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"r=read, w=write, x=execute, p=private (cow)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"offset","description":"Offset into mapped path","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"device","description":"MA:MI Major/minor device ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Mapped path inode, 0 means uninitialized (BSS)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to mapped file or mapped type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pseudo","description":"1 If path is a pseudo path, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_namespaces","description":"Linux namespaces for processes running on the host system.","platforms":["linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"cgroup_namespace","description":"cgroup namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ipc_namespace","description":"ipc namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mnt_namespace","description":"mnt namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"net namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_namespace","description":"pid namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_namespace","description":"user namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uts_namespace","description":"uts namespace inode","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_files","description":"File descriptors for each process.","platforms":["darwin","linux"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"fd","description":"Process-specific file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Filesystem path of descriptor","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_pipes","description":"Pipes and partner processes for each process.","platforms":["linux"],"columns":[{"name":"pid","description":"Process ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"File descriptor","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"Pipe open mode (r/w)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Pipe inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Pipe Type: named vs unnamed/anonymous","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_pid","description":"Process ID of partner process sharing a particular pipe","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_fd","description":"File descriptor of shared pipe at partner's end","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"partner_mode","description":"Mode of shared pipe at partner's end","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"process_open_sockets","description":"Processes which have open network sockets on the system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"fd","description":"Socket file descriptor number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"Socket handle or inode number","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"Network protocol (IPv4, IPv6)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"Transport protocol (TCP/UDP)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"local_address","description":"Socket local address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Socket remote address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Socket local port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Socket remote port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"For UNIX sockets (family=AF_UNIX), the domain path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"TCP socket state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"net_namespace","description":"The inode number of the network namespace","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"protection_type","description":"The protection type of the process","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"translated","description":"Indicates whether the process is running under the Rosetta Translation Environment, yes=1, no=0, error=-1.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cgroup_path","description":"The full hierarchical path of the process's control group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"programs","description":"Represents products as they are installed by Windows Installer. A product generally correlates to one installation package on Windows. Some fields may be blank as Windows installation details are left to the discretion of the product author.","platforms":["windows"],"columns":[{"name":"name","description":"Commonly used product name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Product version information.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_location","description":"The installation location directory of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_source","description":"The installation source of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"language","description":"The language of the product.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"publisher","description":"Name of the product supplier.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uninstall_string","description":"Path and filename of the uninstaller.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Date that this product was installed on the system. ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifying_number","description":"Product identification such as a serial number on software, or a die number on a hardware chip.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"prometheus_metrics","description":"Retrieve metrics from a Prometheus server.","platforms":["darwin","linux"],"columns":[{"name":"target_name","description":"Address of prometheus target","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metric_name","description":"Name of collected Prometheus metric","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metric_value","description":"Value of collected Prometheus metric","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"timestamp_ms","description":"Unix timestamp of collected data in MS","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"python_packages","description":"Python packages installed in a system.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Package display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Package-supplied version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"summary","description":"Package-supplied summary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional package author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"license","description":"License under which package is launched","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path at which this module resides","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"Directory where Python modules are located","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"quicklook_cache","description":"Files and thumbnails within macOS's Quicklook Cache.","platforms":["darwin"],"columns":[{"name":"path","description":"Path of file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rowid","description":"Quicklook file rowid key","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"fs_id","description":"Quicklook file fs_id key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"volume_id","description":"Parsed volume ID from fs_id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"inode","description":"Parsed file ID (inode) from fs_id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"Parsed version date field","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Parsed version size field","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"label","description":"Parsed version 'gen' field","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_hit_date","description":"Apple date format for last thumbnail cache hit","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hit_count","description":"Number of cache hits on thumbnail","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"icon_mode","description":"Thumbnail icon mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"cache_path","description":"Path to cache data","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"registry","description":"All of the Windows registry hives.","platforms":["windows"],"columns":[{"name":"key","description":"Name of the key to search for","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Full path to the value","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of the registry value entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of the registry value, or 'subkey' if item is a subkey","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data content of registry value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtime","description":"timestamp of the most recent registry write","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"routes","description":"The active route table for the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"destination","description":"Destination IP address","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"netmask","description":"Netmask length","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"gateway","description":"Route gateway","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Route source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"flags","description":"Flags to describe route","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"interface","description":"Route local interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mtu","description":"Maximum Transmission Unit for the route","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"metric","description":"Cost of route. Lowest is preferred","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of route","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hopcount","description":"Max hops expected","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["linux","darwin"]}]},{"name":"rpm_package_files","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"package","description":"RPM package name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"path","description":"File path within the package","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"username","description":"File default username from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"File default groupname from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"File permissions mode from info DB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Expected file size in bytes from RPM info DB","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha256","description":"SHA256 file digest from RPM info DB","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"rpm_packages","description":"RPM packages that are currently installed on the host system.","platforms":["linux"],"columns":[{"name":"name","description":"RPM package name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"version","description":"Package version","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"release","description":"Package release","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"source","description":"Source RPM package name (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Package size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sha1","description":"SHA1 hash of the package contents","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Architecture(s) supported","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"epoch","description":"Package epoch value","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"install_time","description":"When the package was installed","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"Package vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"package_group","description":"Package group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]},{"name":"mount_namespace_id","description":"Mount namespace id","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"running_apps","description":"macOS applications currently running on the host system.","platforms":["darwin"],"columns":[{"name":"pid","description":"The pid of the application","type":"integer","notes":"","hidden":false,"required":false,"index":true},{"name":"bundle_identifier","description":"The bundle identifier of the application","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"is_active","description":"(DEPRECATED)","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"safari_extensions","description":"Safari browser extension details for all users.","platforms":["darwin"],"columns":[{"name":"uid","description":"The local user that owns the extension","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Extension display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"Extension long version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sdk","description":"Bundle SDK used to compile extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_url","description":"Extension-supplied update URI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"author","description":"Optional extension author","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Optional developer identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional extension description text","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to extension XAR bundle","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sandboxes","description":"macOS application sandboxes container details.","platforms":["darwin"],"columns":[{"name":"label","description":"UTI-format bundle or label ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"Sandbox owner","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Application sandboxings enabled on container","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build_id","description":"Sandbox-specific identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"Application bundle used by the sandbox","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to sandbox container directory","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"scheduled_tasks","description":"Lists all of the tasks in the Windows task scheduler.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Actions executed by the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to the executable to be run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether or not the scheduled task is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of the scheduled task","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hidden","description":"Whether or not the task is visible in the UI","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_time","description":"Timestamp the task last ran","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"next_run_time","description":"Timestamp the task is scheduled to run next","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_message","description":"Exit status message of the last task run","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_run_code","description":"Exit status code of the last task run","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"screenlock","description":"macOS screenlock status. Note: only fetches results for osquery's current logged-in user context. The user must also have recently logged in.","platforms":["darwin"],"columns":[{"name":"enabled","description":"1 If a password is required after sleep or the screensaver begins; else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"grace_period","description":"The amount of time in seconds the screen must be asleep or the screensaver on before a password is required on-wake. 0 = immediately; -1 = no password is required on-wake","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"seccomp_events","description":"A virtual table that tracks seccomp events.","platforms":["linux"],"columns":[{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit user ID (loginuid) of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"User ID of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Group ID of the user who started the analyzed process","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ses","description":"Session ID of the session from which the analyzed process was invoked","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID","type":"unsigned_bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"comm","description":"Command-line name of the command that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exe","description":"The path to the executable that was used to invoke the analyzed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sig","description":"Signal value sent to process by seccomp","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"Information about the CPU architecture","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"syscall","description":"Type of the system call","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"compat","description":"Is system call in compatibility mode","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ip","description":"Instruction pointer value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"code","description":"The seccomp action","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"secureboot","description":"Secure Boot UEFI Settings.","platforms":["linux","windows"],"columns":[{"name":"secure_boot","description":"Whether secure boot is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"setup_mode","description":"Whether setup mode is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"security_profile_info","description":"Information on the security profile of a given system by listing the system Account and Audit Policies. This table mimics the exported securitypolicy output from the secedit tool.","platforms":["windows"],"columns":[{"name":"minimum_password_age","description":"Determines the minimum number of days that a password must be used before the user can change it","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"maximum_password_age","description":"Determines the maximum number of days that a password can be used before the client requires the user to change it","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minimum_password_length","description":"Determines the least number of characters that can make up a password for a user account","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"password_complexity","description":"Determines whether passwords must meet a series of strong-password guidelines","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"password_history_size","description":"Number of unique new passwords that must be associated with a user account before an old password can be reused","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lockout_bad_count","description":"Number of failed logon attempts after which a user account MUST be locked out","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"logon_to_change_password","description":"Determines if logon session is required to change the password","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"force_logoff_when_expire","description":"Determines whether SMB client sessions with the SMB server will be forcibly disconnected when the client's logon hours expire","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"new_administrator_name","description":"Determines the name of the Administrator account on the local computer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"new_guest_name","description":"Determines the name of the Guest account on the local computer","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"clear_text_password","description":"Determines whether passwords MUST be stored by using reversible encryption","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"lsa_anonymous_name_lookup","description":"Determines if an anonymous user is allowed to query the local LSA policy","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_admin_account","description":"Determines whether the Administrator account on the local computer is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enable_guest_account","description":"Determines whether the Guest account on the local computer is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_system_events","description":"Determines whether the operating system MUST audit System Change, System Startup, System Shutdown, Authentication Component Load, and Loss or Excess of Security events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_logon_events","description":"Determines whether the operating system MUST audit each instance of a user attempt to log on or log off this computer","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_object_access","description":"Determines whether the operating system MUST audit each instance of user attempts to access a non-Active Directory object that has its own SACL specified","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_privilege_use","description":"Determines whether the operating system MUST audit each instance of user attempts to exercise a user right","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_policy_change","description":"Determines whether the operating system MUST audit each instance of user attempts to change user rights assignment policy, audit policy, account policy, or trust policy","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_account_manage","description":"Determines whether the operating system MUST audit each event of account management on a computer","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_process_tracking","description":"Determines whether the operating system MUST audit process-related events","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_ds_access","description":"Determines whether the operating system MUST audit each instance of user attempts to access an Active Directory object that has its own system access control list (SACL) specified","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"audit_account_logon","description":"Determines whether the operating system MUST audit each time this computer validates the credentials of an account","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"selinux_events","description":"Track SELinux events.","platforms":["linux"],"columns":[{"name":"type","description":"Event type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"selinux_settings","description":"Track active SELinux settings.","platforms":["linux"],"columns":[{"name":"scope","description":"Where the key is located inside the SELinuxFS mount point.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"key","description":"Key or class name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Active value.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"services","description":"Lists all installed Windows services and their relevant data.","platforms":["windows"],"columns":[{"name":"name","description":"Service name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_type","description":"Service Type: OWN_PROCESS, SHARE_PROCESS and maybe Interactive (can interact with the desktop)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"display_name","description":"Service Display name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Service Current status: STOPPED, START_PENDING, STOP_PENDING, RUNNING, CONTINUE_PENDING, PAUSE_PENDING, PAUSED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"the Process ID of the service","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"start_type","description":"Service start type: BOOT_START, SYSTEM_START, AUTO_START, DEMAND_START, DISABLED","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"win32_exit_code","description":"The error code that the service uses to report an error that occurs when it is starting or stopping","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"service_exit_code","description":"The service-specific error code that the service returns when an error occurs while the service is starting or stopping","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to Service Executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module_path","description":"Path to ServiceDll","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Service Description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_account","description":"The name of the account that the service process will be logged on as when it runs. This name can be of the form Domain\\UserName. If the account belongs to the built-in domain, the name can be of the form .\\UserName.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shadow","description":"Local system users encrypted passwords and related information. Please note, that you usually need superuser rights to access `/etc/shadow`.","platforms":["linux"],"columns":[{"name":"password_status","description":"Password status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hash_alg","description":"Password hashing algorithm","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_change","description":"Date of last password change (starting from UNIX epoch date)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"min","description":"Minimal number of days between password changes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"max","description":"Maximum number of days between password changes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"warning","description":"Number of days before password expires to warn user about it","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Number of days after password expires until account is blocked","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"expire","description":"Number of days since UNIX epoch date until account is disabled","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"flag","description":"Reserved","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":true}]},{"name":"shared_folders","description":"Folders available to others via SMB or AFP.","platforms":["darwin"],"columns":[{"name":"name","description":"The shared name of the folder as it appears to other users","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Absolute path of shared folder on the local system","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shared_memory","description":"OS shared memory regions.","platforms":["linux"],"columns":[{"name":"shmid","description":"Shared memory segment ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"owner_uid","description":"User ID of owning process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creator_uid","description":"User ID of creator process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID to last use the segment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"creator_pid","description":"Process ID that created the segment","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"atime","description":"Attached time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"dtime","description":"Detached time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"ctime","description":"Changed time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Memory segment permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Size in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"attached","description":"Number of attached processes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Destination/attach status","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"locked","description":"1 if segment is locked else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shared_resources","description":"Displays shared resources on a computer system running Windows. This may be a disk drive, printer, interprocess communication, or other sharable device.","platforms":["windows"],"columns":[{"name":"description","description":"A textual description of the object","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"install_date","description":"Indicates when the object was installed. Lack of a value does not indicate that the object is not installed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"String that indicates the current status of the object.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"allow_maximum","description":"Number of concurrent users for this resource has been limited. If True, the value in the MaximumAllowed property is ignored.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"maximum_allowed","description":"Limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum property is set to FALSE.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Alias given to a path set up as a share on a computer system running Windows.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Local path of the Windows share.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of resource being shared. Types include: disk drives, print queues, interprocess communications (IPC), and general devices.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"type_name","description":"Human readable value for the 'type' column","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sharing_preferences","description":"macOS Sharing preferences.","platforms":["darwin"],"columns":[{"name":"screen_sharing","description":"1 If screen sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"file_sharing","description":"1 If file sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"printer_sharing","description":"1 If printer sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_login","description":"1 If remote login is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_management","description":"1 If remote management is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_apple_events","description":"1 If remote apple events are enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"internet_sharing","description":"1 If internet sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bluetooth_sharing","description":"1 If bluetooth sharing is enabled for any user else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disc_sharing","description":"1 If CD or DVD sharing is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"content_caching","description":"1 If content caching is enabled else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shell_history","description":"A line-delimited (command) table of per-user .*_history data.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"Shell history owner","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Entry timestamp. It could be absent, default value is 0.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"command","description":"Unparsed date/line/command history line","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"history_file","description":"Path to the .*_history for this user","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shellbags","description":"Shows directories accessed via Windows Explorer.","platforms":["windows"],"columns":[{"name":"sid","description":"User SID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Shellbags source Registry file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Directory name.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"Directory Modified time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"created_time","description":"Directory Created time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"accessed_time","description":"Directory Accessed time.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mft_entry","description":"Directory master file table entry.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"mft_sequence","description":"Directory master file table sequence.","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"shimcache","description":"Application Compatibility Cache, contains artifacts of execution.","platforms":["windows"],"columns":[{"name":"entry","description":"Execution order.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"This is the path to the executed file.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"modified_time","description":"File Modified time.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"execution_flag","description":"Boolean Execution flag, 1 for execution, 0 for no execution, -1 for missing (this flag does not exist on Windows 10 and higher).","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"signature","description":"File (executable, bundle, installer, disk) code signing status.","platforms":["darwin"],"columns":[{"name":"path","description":"Must provide a path or directory","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"hash_resources","description":"Set to 1 to also hash resources, or 0 otherwise. Default is 1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"arch","description":"If applicable, the arch of the signed code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signed","description":"1 If the file is signed else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"The signing identifier sealed into the signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cdhash","description":"Hash of the application Code Directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team_identifier","description":"The team signing identifier sealed into the signature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"authority","description":"Certificate Common Name","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sip_config","description":"Apple's System Integrity Protection (rootless) status.","platforms":["darwin"],"columns":[{"name":"config_flag","description":"The System Integrity Protection config flag","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if this configuration is enabled, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled_nvram","description":"1 if this configuration is enabled, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"smbios_tables","description":"BIOS (DMI) structure common details and content.","platforms":["darwin","linux"],"columns":[{"name":"number","description":"Table entry number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Table entry type","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Table entry description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"handle","description":"Table entry handle","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"header_size","description":"Header size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Table entry size in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"md5","description":"MD5 hash of table entry","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"smc_keys","description":"Apple's system management controller keys.","platforms":["darwin"],"columns":[{"name":"key","description":"4-character key","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"SMC-reported type literal type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"size","description":"Reported size of data in bytes","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"A type-encoded representation of the key value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hidden","description":"1 if this key is normally hidden, otherwise 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"socket_events","description":"Track network socket opens and closes.","platforms":["darwin","linux"],"columns":[{"name":"action","description":"The socket action (bind, listen, close)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of executed file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fd","description":"The file description for the process socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Either 'succeeded', 'failed', 'in_progress' (connect() on non-blocking socket) or 'no_client' (null accept() on non-blocking socket)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"family","description":"The Internet protocol family ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"The network protocol ID","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"local_address","description":"Local address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_address","description":"Remote address associated with socket","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_port","description":"Local network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_port","description":"Remote network protocol port number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"socket","description":"The local path (UNIX domain socket only)","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"success","description":"Deprecated. Use the 'status' column instead","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"ssh_configs","description":"A table of parsed ssh_configs.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local owner of the ssh_config file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"block","description":"The host or match block","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"option","description":"The option and value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_config_file","description":"Path to the ssh_config file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"startup_items","description":"Applications and binaries set as user/login startup items.","platforms":["darwin","linux","windows"],"columns":[{"name":"name","description":"Name of startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"args","description":"Arguments provided to startup executable","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Startup Item or Login Item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Directory or plist containing startup item","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"status","description":"Startup status; either enabled or disabled","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"The user associated with the startup item","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"sudoers","description":"Rules for running commands as other users via sudo.","platforms":["darwin","linux"],"columns":[{"name":"source","description":"Source file containing the given rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"header","description":"Symbol for given rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rule_details","description":"Rule definition","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"suid_bin","description":"suid binaries in common locations.","platforms":["darwin","linux"],"columns":[{"name":"path","description":"Binary path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Binary owner username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Binary owner group","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"permissions","description":"Binary permissions","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"syslog_events","description":"","platforms":["linux"],"columns":[{"name":"time","description":"Current unix epoch time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Time known to syslog","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"host","description":"Hostname configured for syslog","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"severity","description":"Syslog severity","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"facility","description":"Syslog facility","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tag","description":"The syslog tag","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"The syslog message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"system_controls","description":"sysctl names, values, and settings information.","platforms":["darwin","linux"],"columns":[{"name":"name","description":"Full sysctl MIB name","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"oid","description":"Control MIB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"Subsystem ID, control type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_value","description":"Value of setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"config_value","description":"The MIB value set in /etc/sysctl.conf","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Data type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"field_name","description":"Specific attribute of opaque type","type":"text","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]}]},{"name":"system_extensions","description":"macOS (>= 10.15) system extension table.","platforms":["darwin"],"columns":[{"name":"path","description":"Original path of system extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"UUID","description":"Extension unique id","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"System extension state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identifier","description":"Identifier name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"System extension version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"System extension category","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bundle_path","description":"System extension bundle path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"team","description":"Signing team ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mdm_managed","description":"1 if managed by MDM system extension payload configuration, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"system_info","description":"System information for identification.","platforms":["darwin","linux","windows"],"columns":[{"name":"hostname","description":"Network hostname including domain","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"Unique ID provided by the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_type","description":"CPU type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_subtype","description":"CPU subtype","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_brand","description":"CPU brand string, contains vendor and model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_physical_cores","description":"Number of physical CPU cores in to the system","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_logical_cores","description":"Number of logical CPU cores available to the system","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"cpu_microcode","description":"Microcode version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"physical_memory","description":"Total physical memory in bytes","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_vendor","description":"Hardware vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_model","description":"Hardware model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_version","description":"Hardware version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hardware_serial","description":"Device serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_vendor","description":"Board vendor","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_model","description":"Board model","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_version","description":"Board version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"board_serial","description":"Board serial number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Friendly computer name (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_hostname","description":"Local hostname (optional)","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"systemd_units","description":"Track systemd units.","platforms":["linux"],"columns":[{"name":"id","description":"Unique unit identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Unit description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"load_state","description":"Reflects whether the unit definition was properly loaded","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"active_state","description":"The high-level unit activation state, i.e. generalization of SUB","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sub_state","description":"The low-level unit activation state, values depend on unit type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"following","description":"The name of another unit that this unit follows in state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"object_path","description":"The object path for this unit","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"job_id","description":"Next queued job id","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"job_type","description":"Job type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"job_path","description":"The object path for the job","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"fragment_path","description":"The unit file path this unit was read from, if there is any","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user","description":"The configured user, if any","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source_path","description":"Path to the (possibly generated) unit configuration file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"temperature_sensors","description":"Machine's temperature sensors.","platforms":["darwin"],"columns":[{"name":"key","description":"The SMC key on macOS","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"Name of temperature source","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"celsius","description":"Temperature in Celsius","type":"double","notes":"","hidden":false,"required":false,"index":false},{"name":"fahrenheit","description":"Temperature in Fahrenheit","type":"double","notes":"","hidden":false,"required":false,"index":false}]},{"name":"time","description":"Track current date and time in UTC.","platforms":["darwin","linux","windows"],"columns":[{"name":"weekday","description":"Current weekday in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"year","description":"Current year in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"month","description":"Current month in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"day","description":"Current day in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hour","description":"Current hour in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Current minutes in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Current seconds in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"timezone","description":"Timezone for reported time (hardcoded to UTC)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_timezone","description":"Current local timezone in of the system","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"unix_time","description":"Current UNIX time in UTC","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"timestamp","description":"Current timestamp (log format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"Current date and time (ISO format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"iso_8601","description":"Current time (ISO format) in UTC","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"win_timestamp","description":"Timestamp value in 100 nanosecond units","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]}]},{"name":"time_machine_backups","description":"Backups to drives using TimeMachine.","platforms":["darwin"],"columns":[{"name":"destination_id","description":"Time Machine destination ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"backup_date","description":"Backup Date","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"time_machine_destinations","description":"Locations backed up to using Time Machine.","platforms":["darwin"],"columns":[{"name":"alias","description":"Human readable name of drive","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"destination_id","description":"Time Machine destination ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"consistency_scan_date","description":"Consistency scan date","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"root_volume_uuid","description":"Root UUID of backup volume","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_available","description":"Bytes available on volume","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"bytes_used","description":"Bytes used on volume","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"encryption","description":"Last known encrypted state","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"tpm_info","description":"A table that lists the TPM related information.","platforms":["windows"],"columns":[{"name":"activated","description":"TPM is activated","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"TPM is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"owned","description":"TPM is owned","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_version","description":"TPM version","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_id","description":"TPM manufacturers ID","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer_name","description":"TPM manufacturers name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"product_name","description":"Product name of the TPM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"physical_presence_version","description":"Version of the Physical Presence Interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"spec_version","description":"Trusted Computing Group specification that the TPM supports","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"ulimit_info","description":"System resource usage limits.","platforms":["darwin","linux"],"columns":[{"name":"type","description":"System resource to be limited","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"soft_limit","description":"Current limit value","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hard_limit","description":"Maximum limit value","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"unified_log","description":"Queries the OSLog framework for entries in the system log. The maximum number of rows returned is limited for performance issues. This table introduces a new idiom for extracting sequential data in batches using multiple queries, ordered by timestamp. To trigger it, the user should include the condition \"timestamp > -1\", and the table will handle pagination.","platforms":["darwin"],"columns":[{"name":"timestamp","description":"unix timestamp associated with the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"storage","description":"the storage category for the entry","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"composed message","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"activity","description":"the activity ID associate with the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"process","description":"the name of the process that made the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"the pid of the process that made the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sender","description":"the name of the binary image that made the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"the tid of the thread that made the entry","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"the category of the os_log_t used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subsystem","description":"the subsystem of the os_log_t used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"the severity level of the entry","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"max_rows","description":"the max number of rows returned (defaults to 100)","type":"integer","notes":"","hidden":true,"required":false,"index":false}]},{"name":"uptime","description":"Track time passed since last boot. Some systems track this as calendar time, some as runtime.","platforms":["darwin","linux","windows"],"columns":[{"name":"days","description":"Days of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"hours","description":"Hours of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minutes","description":"Minutes of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"seconds","description":"Seconds of uptime","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"total_seconds","description":"Total uptime seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"usb_devices","description":"USB devices that are actively plugged into the host system.","platforms":["darwin","linux"],"columns":[{"name":"usb_address","description":"USB Device used address","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"usb_port","description":"USB Device used port","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor","description":"USB Device vendor string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"vendor_id","description":"Hex encoded USB Device vendor identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"USB Device version number","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"USB Device model string","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model_id","description":"Hex encoded USB Device model identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial","description":"USB Device serial connection","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"USB Device class","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"subclass","description":"USB Device subclass","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"USB Device protocol","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"removable","description":"1 If USB device is removable else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"user_events","description":"Track user events from the audit framework.","platforms":["darwin","linux"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"auid","description":"Audit User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"message","description":"Message from the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"The file description for the process socket","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Supplied path from event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"address","description":"The Internet protocol address or family ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"terminal","description":"The network protocol ID","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of execution in UNIX time","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uptime","description":"Time of execution in system uptime","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"user_groups","description":"Local system user group relationships.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true}]},{"name":"user_interaction_events","description":"Track user interaction events from macOS' event tapping framework.","platforms":["darwin"],"columns":[{"name":"time","description":"Time","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"user_ssh_keys","description":"Returns the private keys in the users ~/.ssh directory and whether or not they are encrypted.","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"The local user that owns the key file","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to key file","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"encrypted","description":"1 if key is encrypted, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"key_type","description":"The type of the private key. One of [rsa, dsa, dh, ec, hmac, cmac], or the empty string.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"userassist","description":"UserAssist Registry Key tracks when a user executes an application from Windows Explorer.","platforms":["windows"],"columns":[{"name":"path","description":"Application file path.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_execution_time","description":"Most recent time application was executed.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of times the application has been executed.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sid","description":"User SID.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"video_info","description":"Retrieve video card information of the machine.","platforms":["windows"],"columns":[{"name":"color_depth","description":"The amount of bits per pixel to represent color.","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"driver","description":"The driver of the device.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_date","description":"The date listed on the installed driver.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"driver_version","description":"The version of the installed driver.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"manufacturer","description":"The manufacturer of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"model","description":"The model of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"series","description":"The series of the gpu.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"video_mode","description":"The current resolution of the display.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"virtual_memory_info","description":"Darwin Virtual Memory statistics.","platforms":["darwin"],"columns":[{"name":"free","description":"Total number of free pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"active","description":"Total number of active pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"inactive","description":"Total number of inactive pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"speculative","description":"Total number of speculative pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"throttled","description":"Total number of throttled pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"wired","description":"Total number of wired down pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"purgeable","description":"Total number of purgeable pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"faults","description":"Total number of calls to vm_faults.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"copy","description":"Total number of copy-on-write pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"zero_fill","description":"Total number of zero filled pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"reactivated","description":"Total number of reactivated pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"purged","description":"Total number of purged pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"file_backed","description":"Total number of file backed pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"anonymous","description":"Total number of anonymous pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uncompressed","description":"Total number of uncompressed pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"compressor","description":"The number of pages used to store compressed VM pages.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"decompressed","description":"The total number of pages that have been decompressed by the VM compressor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"compressed","description":"The total number of pages that have been compressed by the VM compressor.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"page_ins","description":"The total number of requests for pages from a pager.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"page_outs","description":"Total number of pages paged out.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_ins","description":"The total number of compressed pages that have been swapped out to disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"swap_outs","description":"The total number of compressed pages that have been swapped back in from disk.","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_networks","description":"macOS known/remembered Wi-Fi networks list.","platforms":["darwin"],"columns":[{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"last_connected","description":"Last time this network was connected to as a unix_time","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"passpoint","description":"1 if Passpoint is supported, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"possibly_hidden","description":"1 if network is possibly a hidden network, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"roaming","description":"1 if roaming is supported, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"roaming_profile","description":"Describe the roaming profile, usually one of Single, Dual or Multi","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_login","description":"1 if auto login is enabled, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"temporarily_disabled","description":"1 if this network is temporarily disabled, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"disabled","description":"1 if this network is disabled, 0 otherwise","type":"integer","notes":"","hidden":true,"required":false,"index":false},{"name":"add_reason","description":"Shows why this network was added, via menubar or command line or something else ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"added_at","description":"Time this network was added as a unix_time","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"captive_portal","description":"1 if this network has a captive portal, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"captive_login_date","description":"Time this network logged in to a captive portal as unix_time","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"was_captive_network","description":"1 if this network was previously a captive network, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"auto_join","description":"1 if this network set to join automatically, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"personal_hotspot","description":"1 if this network is a personal hotspot, 0 otherwise","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_status","description":"macOS current WiFi status.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"security_type","description":"Type of security on this network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"transmit_rate","description":"The current transmit rate","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mode","description":"The current operating mode for the Wi-Fi interface","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wifi_survey","description":"Scan for nearby WiFi networks.","platforms":["darwin"],"columns":[{"name":"interface","description":"Name of the interface","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssid","description":"SSID octets of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"bssid","description":"The current basic service set identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"network_name","description":"Name of the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"country_code","description":"The country code (ISO/IEC 3166-1:1997) for the network","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"rssi","description":"The current received signal strength indication (dbm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"noise","description":"The current noise measurement (dBm)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel","description":"Channel number","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_width","description":"Channel width","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"channel_band","description":"Channel band","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"winbaseobj","description":"Lists named Windows objects in the default object directories, across all terminal services sessions. Example Windows ojbect types include Mutexes, Events, Jobs and Semaphors.","platforms":["windows"],"columns":[{"name":"session_id","description":"Terminal Services Session Id","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"object_name","description":"Object Name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"object_type","description":"Object Type","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_crashes","description":"Extracted information from Windows crash logs (Minidumps).","platforms":["windows"],"columns":[{"name":"datetime","description":"Timestamp (log format) of the crash","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"module","description":"Path of the crashed module within the process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path of the executable file for the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID of the crashed process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID of the crashed thread","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"version","description":"File version info of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"process_uptime","description":"Uptime of the process in seconds","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"stack_trace","description":"Multiple stack frames from the stack trace","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_code","description":"The Windows exception code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_message","description":"The NTSTATUS error message associated with the exception code","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"exception_address","description":"Address (in hex) where the exception occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"registers","description":"The values of the system registers","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command_line","description":"Command-line string passed to the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"current_directory","description":"Current working directory of the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username of the user who ran the crashed process","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"machine_name","description":"Name of the machine where the crash happened","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"major_version","description":"Windows major version of the machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"minor_version","description":"Windows minor version of the machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"build_number","description":"Windows build number of the crashing machine","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Type of crash log","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"crash_path","description":"Path of the log file","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_eventlog","description":"Table for querying all recorded Windows event logs.","platforms":["windows"],"columns":[{"name":"channel","description":"Source or channel of the event","type":"text","notes":"","hidden":false,"required":true,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"Severity level associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid","description":"Process ID which emitted the event record","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"tid","description":"Thread ID which emitted the event record","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"time_range","description":"System time to selectively filter the events","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"timestamp","description":"Timestamp to selectively filter the events","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"xpath","description":"The custom query to filter events","type":"text","notes":"","hidden":true,"required":true,"index":false}]},{"name":"windows_events","description":"Windows Event logs.","platforms":["windows"],"columns":[{"name":"time","description":"Timestamp the event was received","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"datetime","description":"System time at which the event occurred","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"source","description":"Source or channel of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_name","description":"Provider name of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"provider_guid","description":"Provider guid of the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"computer_name","description":"Hostname of system where event was generated","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eventid","description":"Event ID of the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"task","description":"Task value associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"level","description":"The severity level associated with the event","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"keywords","description":"A bitmask of the keywords defined in the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"data","description":"Data associated with the event","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"windows_firewall_rules","description":"Provides the list of Windows firewall rules.","platforms":["windows"],"columns":[{"name":"name","description":"Friendly name of the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"app_name","description":"Friendly name of the application to which the rule applies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Action for the rule or default setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"1 if the rule is enabled","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"grouping","description":"Group to which an individual rule belongs","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"direction","description":"Direction of traffic for which the rule applies","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"protocol","description":"IP protocol of the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_addresses","description":"Local addresses for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_addresses","description":"Remote addresses for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"local_ports","description":"Local ports for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remote_ports","description":"Remote ports for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"icmp_types_codes","description":"ICMP types and codes for the rule","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_domain","description":"1 if the rule profile type is domain","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_private","description":"1 if the rule profile type is private","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"profile_public","description":"1 if the rule profile type is public","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"service_name","description":"Service name property of the application","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_optional_features","description":"Lists names and installation states of windows features. Maps to Win32_OptionalFeature WMI class.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the feature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"caption","description":"Caption of feature in settings UI","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Installation state value. 1 == Enabled, 2 == Disabled, 3 == Absent","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"statename","description":"Installation state name. 'Enabled','Disabled','Absent'","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_security_center","description":"The health status of Window Security features. Health values can be \"Good\", \"Poor\". \"Snoozed\", \"Not Monitored\", and \"Error\".","platforms":["windows"],"columns":[{"name":"firewall","description":"The health of the monitored Firewall (see windows_security_products)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"autoupdate","description":"The health of the Windows Autoupdate feature","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"antivirus","description":"The health of the monitored Antivirus solution (see windows_security_products)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"antispyware","description":"Deprecated (always 'Good').","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"internet_settings","description":"The health of the Internet Settings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"windows_security_center_service","description":"The health of the Windows Security Center Service","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_account_control","description":"The health of the User Account Control (UAC) capability in Windows","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_security_products","description":"Enumeration of registered Windows security products.","platforms":["windows"],"columns":[{"name":"type","description":"Type of security product","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of product","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"State of protection","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state_timestamp","description":"Timestamp for the product state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"remediation_path","description":"Remediation path","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"signatures_up_to_date","description":"1 if product signatures are up to date, else 0","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"windows_update_history","description":"Provides the history of the windows update events.","platforms":["windows"],"columns":[{"name":"client_app_id","description":"Identifier of the client application that processed an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"date","description":"Date and the time an update was applied","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hresult","description":"HRESULT value that is returned from the operation on an update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"operation","description":"Operation on an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"result_code","description":"Result of an operation on an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"server_selection","description":"Value that indicates which server provided an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"service_id","description":"Service identifier of an update service that is not a Windows update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"support_url","description":"Hyperlink to the language-specific support information for an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"title","description":"Title of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_id","description":"Revision-independent identifier of an update","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"update_revision","description":"Revision number of an update","type":"bigint","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_bios_info","description":"Lists important information from the system bios.","platforms":["windows"],"columns":[{"name":"name","description":"Name of the Bios setting","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"value","description":"Value of the Bios setting","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_cli_event_consumers","description":"WMI CommandLineEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique name of a consumer.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"command_line_template","description":"Standard string template that specifies the process to be started. This property can be NULL, and the ExecutablePath property is used as the command line.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"executable_path","description":"Module to execute. The string can specify the full path and file name of the module to execute, or it can specify a partial name. If a partial name is specified, the current drive and current directory are assumed.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_event_filters","description":"Lists WMI event filters.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier of an event filter.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query","description":"Windows Management Instrumentation Query Language (WQL) event query that specifies the set of events for consumer notification, and the specific conditions for notification.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"query_language","description":"Query language that the query is written in.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_filter_consumer_binding","description":"Lists the relationship between event consumers and filters.","platforms":["windows"],"columns":[{"name":"consumer","description":"Reference to an instance of __EventConsumer that represents the object path to a logical consumer, the recipient of an event.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filter","description":"Reference to an instance of __EventFilter that represents the object path to an event filter which is a query that specifies the type of event to be received.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"wmi_script_event_consumers","description":"WMI ActiveScriptEventConsumer, which can be used for persistence on Windows. See https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management-Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf for more details.","platforms":["windows"],"columns":[{"name":"name","description":"Unique identifier for the event consumer. ","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"scripting_engine","description":"Name of the scripting engine to use, for example, 'VBScript'. This property cannot be NULL.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_file_name","description":"Name of the file from which the script text is read, intended as an alternative to specifying the text of the script in the ScriptText property.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"script_text","description":"Text of the script that is expressed in a language known to the scripting engine. This property must be NULL if the ScriptFileName property is not NULL.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"class","description":"The name of the class.","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"relative_path","description":"Relative path to the class or instance.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_entries","description":"Database of the machine's XProtect signatures.","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"launch_type","description":"Launch services content type","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"identity","description":"XProtect identity (SHA1) of content","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filename","description":"Use this file name to match","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"filetype","description":"Use this file type to match","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"optional","description":"Match any of the identities/patterns for this XProtect name","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"uses_pattern","description":"Uses a match pattern instead of identity","type":"integer","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_meta","description":"Database of the machine's XProtect browser-related signatures.","platforms":["darwin"],"columns":[{"name":"identifier","description":"Browser plugin or extension identifier","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"type","description":"Either plugin or extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"developer_id","description":"Developer identity (SHA1) of extension","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"min_version","description":"The minimum allowed plugin version.","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"xprotect_reports","description":"Database of XProtect matches (if user generated/sent an XProtect report).","platforms":["darwin"],"columns":[{"name":"name","description":"Description of XProtected malware","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"user_action","description":"Action taken by user after prompted","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Quarantine alert time","type":"text","notes":"","hidden":false,"required":false,"index":false}]},{"name":"yara","description":"Triggers one-off YARA query for files at the specified path. Requires one of `sig_group`, `sigfile`, or `sigrule`.","platforms":["darwin","linux","windows"],"columns":[{"name":"path","description":"The path scanned","type":"text","notes":"","hidden":false,"required":true,"index":true},{"name":"matches","description":"List of YARA matches","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"sig_group","description":"Signature group used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigfile","description":"Signature file used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigrule","description":"Signature strings used","type":"text","notes":"","hidden":true,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"sigurl","description":"Signature url","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"yara_events","description":"Track YARA matches for files specified in configuration data.","platforms":["darwin","linux","windows"],"columns":[{"name":"target_path","description":"The path scanned","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"category","description":"The category of the file","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"action","description":"Change action (UPDATE, REMOVE, etc)","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"transaction_id","description":"ID used during bulk update","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"matches","description":"List of YARA matches","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"count","description":"Number of YARA matches","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"strings","description":"Matching strings","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"tags","description":"Matching tags","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"time","description":"Time of the scan","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"eid","description":"Event ID","type":"text","notes":"","hidden":true,"required":false,"index":false}]},{"name":"ycloud_instance_metadata","description":"Yandex.Cloud instance metadata.","platforms":["darwin","linux","windows"],"columns":[{"name":"instance_id","description":"Unique identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"folder_id","description":"Folder identifier for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"name","description":"Name of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Description of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"hostname","description":"Hostname of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"zone","description":"Availability zone of the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"ssh_public_key","description":"SSH public key. Only available if supplied at instance launch time","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"serial_port_enabled","description":"Indicates if serial port is enabled for the VM","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"metadata_endpoint","description":"Endpoint used to fetch VM metadata","type":"text","notes":"","hidden":false,"required":false,"index":true}]},{"name":"yum_sources","description":"Current list of Yum repositories or software channels.","platforms":["linux"],"columns":[{"name":"name","description":"Repository name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"baseurl","description":"Repository base URL","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"mirrorlist","description":"Mirrorlist URL","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"enabled","description":"Whether the repository is used","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gpgcheck","description":"Whether packages are GPG checked","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"gpgkey","description":"URL to GPG key","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_users","description":"Local user accounts (including domain accounts that have logged on locally (Windows)).","platforms":["darwin","linux","windows"],"columns":[{"name":"uid","description":"User ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid","description":"Group ID (unsigned)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"uid_signed","description":"User ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid_signed","description":"Default group ID as int64 signed (Apple)","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"username","description":"Username","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"description","description":"Optional user description","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"directory","description":"User's home directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"shell","description":"User's configured default shell","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uuid","description":"User's UUID (Apple) or SID (Windows)","type":"text","notes":"","hidden":false,"required":false,"index":true},{"name":"type","description":"Whether the account is roaming (domain), local, or a system profile","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_groups","description":"Local system groups.","platforms":["darwin","linux","windows"],"columns":[{"name":"gid","description":"Unsigned int64 group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"gid_signed","description":"A signed int64 version of gid","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"groupname","description":"Canonical local group name","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"group_sid","description":"Unique group ID","type":"text","notes":"","hidden":true,"required":false,"index":true,"platforms":["windows","win32","cygwin"]},{"name":"comment","description":"Remarks or comments associated with the group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"is_hidden","description":"IsHidden attribute set in OpenDirectory","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"pid_with_namespace","description":"Pids that contain a namespace","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]},{"name":"host_processes","description":"All running processes on the host system.","platforms":["darwin","linux","windows"],"columns":[{"name":"pid","description":"Process (or thread) ID","type":"bigint","notes":"","hidden":false,"required":false,"index":true},{"name":"name","description":"The process path or shorthand argv[0]","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"path","description":"Path to executed binary","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cmdline","description":"Complete argv","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"state","description":"Process state","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"cwd","description":"Process current working directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"root","description":"Process virtual root directory","type":"text","notes":"","hidden":false,"required":false,"index":false},{"name":"uid","description":"Unsigned user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"gid","description":"Unsigned group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"euid","description":"Unsigned effective user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"egid","description":"Unsigned effective group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"suid","description":"Unsigned saved user ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"sgid","description":"Unsigned saved group ID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"on_disk","description":"The process path exists yes=1, no=0, unknown=-1","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"wired_size","description":"Bytes of unpageable memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"resident_size","description":"Bytes of private memory used by process","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"total_size","description":"Total virtual memory size","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"user_time","description":"CPU time in milliseconds spent in user space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"system_time","description":"CPU time in milliseconds spent in kernel space","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_read","description":"Bytes read from disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"disk_bytes_written","description":"Bytes written to disk","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"start_time","description":"Process start time in seconds since Epoch, in case of error -1","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"parent","description":"Process parent's PID","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"pgroup","description":"Process group","type":"bigint","notes":"","hidden":false,"required":false,"index":false},{"name":"threads","description":"Number of threads used by process","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"nice","description":"Process nice level (-20 to 20, default 0)","type":"integer","notes":"","hidden":false,"required":false,"index":false},{"name":"elevated_token","description":"Process uses elevated token yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"secure_process","description":"Process is secure (IUM) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"protection_type","description":"The protection type of the process","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"virtual_process","description":"Process is virtual (e.g. System, Registry, vmmem) yes=1, no=0","type":"integer","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"elapsed_time","description":"Elapsed time in seconds this process has been running.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"handle_count","description":"Total number of handles that the process has open. This number is the sum of the handles currently opened by each thread in the process.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"percent_processor_time","description":"Returns elapsed time that all of the threads of this process used the processor to execute instructions in 100 nanoseconds ticks.","type":"bigint","notes":"","hidden":true,"required":false,"index":false,"platforms":["windows","win32","cygwin"]},{"name":"upid","description":"A 64bit pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"uppid","description":"The 64bit parent pid that is never reused. Returns -1 if we couldn't gather them from the system.","type":"bigint","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_type","description":"Indicates the specific processor designed for installation.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cpu_subtype","description":"Indicates the specific processor on which an entry may be used.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"translated","description":"Indicates whether the process is running under the Rosetta Translation Environment, yes=1, no=0, error=-1.","type":"integer","notes":"","hidden":false,"required":false,"index":false,"platforms":["darwin"]},{"name":"cgroup_path","description":"The full hierarchical path of the process's control group","type":"text","notes":"","hidden":true,"required":false,"index":false,"platforms":["linux"]}]}] \ No newline at end of file diff --git a/x-pack/plugins/osquery/public/components/osquery_schema_link.tsx b/x-pack/plugins/osquery/public/components/osquery_schema_link.tsx index 09e1be0923e4..23d5f4874db5 100644 --- a/x-pack/plugins/osquery/public/components/osquery_schema_link.tsx +++ b/x-pack/plugins/osquery/public/components/osquery_schema_link.tsx @@ -11,7 +11,7 @@ import React from 'react'; export const OsquerySchemaLink = React.memo(() => ( - + diff --git a/x-pack/plugins/osquery/public/editor/osquery_tables.ts b/x-pack/plugins/osquery/public/editor/osquery_tables.ts index 5b2e990fcccc..18a74cb6ac9b 100644 --- a/x-pack/plugins/osquery/public/editor/osquery_tables.ts +++ b/x-pack/plugins/osquery/public/editor/osquery_tables.ts @@ -17,7 +17,7 @@ let osqueryTables: TablesJSON | null = null; export const getOsqueryTables = () => { if (!osqueryTables) { // eslint-disable-next-line @typescript-eslint/no-var-requires - osqueryTables = normalizeTables(require('../common/schemas/osquery/v5.7.0.json')); + osqueryTables = normalizeTables(require('../common/schemas/osquery/v5.10.2.json')); } return osqueryTables; diff --git a/x-pack/plugins/osquery/public/form/timeout_field.tsx b/x-pack/plugins/osquery/public/form/timeout_field.tsx index a9ad26d11e17..cdbc415a69c8 100644 --- a/x-pack/plugins/osquery/public/form/timeout_field.tsx +++ b/x-pack/plugins/osquery/public/form/timeout_field.tsx @@ -7,37 +7,12 @@ import React, { useCallback, useMemo } from 'react'; import deepEqual from 'fast-deep-equal'; import { useController } from 'react-hook-form'; -import type { EuiFieldNumberProps } from '@elastic/eui'; -import { - EuiFieldNumber, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiIconTip, - EuiText, -} from '@elastic/eui'; +import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { QUERY_TIMEOUT } from '../../common/constants'; -const timeoutFieldValidations = { - min: { - message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMinNumberError', { - defaultMessage: 'Timeout value must be greater than {than} seconds.', - values: { than: QUERY_TIMEOUT.DEFAULT }, - }), - value: QUERY_TIMEOUT.DEFAULT, - }, - max: { - message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMaxNumberError', { - defaultMessage: 'Timeout value must be lower than {than} seconds.', - values: { than: QUERY_TIMEOUT.MAX }, - }), - value: QUERY_TIMEOUT.MAX, - }, -}; - interface TimeoutFieldProps { euiFieldProps?: Record; } @@ -50,12 +25,26 @@ const TimeoutFieldComponent = ({ euiFieldProps }: TimeoutFieldProps) => { name: 'timeout', defaultValue: QUERY_TIMEOUT.DEFAULT, rules: { - ...timeoutFieldValidations, + validate: (currentValue: number) => { + if (currentValue < QUERY_TIMEOUT.DEFAULT || isNaN(currentValue)) { + return i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMinNumberError', { + defaultMessage: 'Timeout value must be greater than {than} seconds.', + values: { than: QUERY_TIMEOUT.DEFAULT }, + }); + } + + if (currentValue > QUERY_TIMEOUT.MAX) { + return i18n.translate('xpack.osquery.pack.queryFlyoutForm.timeoutFieldMaxNumberError', { + defaultMessage: 'Timeout value must be lower than {than} seconds.', + values: { than: QUERY_TIMEOUT.MAX }, + }); + } + }, }, }); const handleChange = useCallback( (e: React.ChangeEvent) => { - const numberValue = e.target.valueAsNumber ? e.target.valueAsNumber : 0; + const numberValue = parseInt(e.target.value, 10); onChange(numberValue); }, [onChange] @@ -81,20 +70,10 @@ const TimeoutFieldComponent = ({ euiFieldProps }: TimeoutFieldProps) => { fullWidth error={error?.message} isInvalid={hasError} - labelAppend={ - - - - - - } > = ({ - + diff --git a/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts b/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts index 79e0cdb2d2a4..42612b25a673 100644 --- a/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts +++ b/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts @@ -46,15 +46,20 @@ export const createActionHandler = async ( const { soClient, metadata, alertData, error } = options; const savedObjectsClient = soClient ?? coreStartServices.savedObjects.createInternalRepository(); - + const elasticsearchClient = coreStartServices.elasticsearch.client.asInternalUser; // eslint-disable-next-line @typescript-eslint/naming-convention const { agent_all, agent_ids, agent_platforms, agent_policy_ids } = params; - const selectedAgents = await parseAgentSelection(internalSavedObjectsClient, osqueryContext, { - agents: agent_ids, - allAgentsSelected: !!agent_all, - platformsSelected: agent_platforms, - policiesSelected: agent_policy_ids, - }); + const selectedAgents = await parseAgentSelection( + internalSavedObjectsClient, + elasticsearchClient, + osqueryContext, + { + agents: agent_ids, + allAgentsSelected: !!agent_all, + platformsSelected: agent_platforms, + policiesSelected: agent_policy_ids, + } + ); if (!selectedAgents.length) { throw new CustomHttpRequestError('No agents found for selection', 400); diff --git a/x-pack/plugins/osquery/server/lib/parse_agent_groups.test.ts b/x-pack/plugins/osquery/server/lib/parse_agent_groups.test.ts new file mode 100644 index 000000000000..7728028a3eca --- /dev/null +++ b/x-pack/plugins/osquery/server/lib/parse_agent_groups.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { aggregateResults } from './parse_agent_groups'; +import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import type { OsqueryAppContext } from './osquery_app_context_services'; + +const mockOpenPointInTime = jest.fn().mockResolvedValue({ id: 'mockedPitId' }); +const mockClosePointInTime = jest.fn(); + +const mockElasticsearchClient = { + openPointInTime: mockOpenPointInTime, + closePointInTime: mockClosePointInTime, +} as unknown as ElasticsearchClientMock; + +const mockContext = {} as unknown as OsqueryAppContext; + +describe('aggregateResults', () => { + it('should handle one page of results', async () => { + const generatorMock = jest.fn().mockResolvedValue({ + results: ['result1', 'result2'], + total: 2, + }); + + const result = await aggregateResults(generatorMock, mockElasticsearchClient, mockContext); + + expect(generatorMock).toHaveBeenCalledWith(1, expect.any(Number)); // 1st page, PER_PAGE + expect(mockOpenPointInTime).not.toHaveBeenCalled(); + expect(mockClosePointInTime).not.toHaveBeenCalled(); + + expect(result).toEqual(['result1', 'result2']); + }); + + it('should handle multiple pages of results', async () => { + const generateResults = (run = 1, length = 9000) => + Array.from({ length }, (_, index) => `result_${index + 1 + (run - 1) * length}`); + + const generatorMock = jest + .fn() + .mockResolvedValueOnce({ + results: generateResults(), + total: 18001, + }) + .mockResolvedValueOnce({ + results: generateResults(), + total: 18001, + searchAfter: ['firstSort'], + }) + .mockResolvedValueOnce({ + results: generateResults(2), + total: 18001, + searchAfter: ['secondSort'], + }) + .mockResolvedValueOnce({ + results: ['result_18001'], + total: 18001, + searchAfter: ['thirdSort'], + }); + + const result = await aggregateResults(generatorMock, mockElasticsearchClient, mockContext); + expect(generatorMock).toHaveBeenCalledWith(1, expect.any(Number)); + expect(generatorMock).toHaveBeenCalledWith(1, expect.any(Number), undefined, 'mockedPitId'); + expect(generatorMock).toHaveBeenCalledWith(2, expect.any(Number), ['firstSort'], 'mockedPitId'); + expect(generatorMock).toHaveBeenCalledWith( + 3, + expect.any(Number), + ['secondSort'], + 'mockedPitId' + ); + expect(mockOpenPointInTime).toHaveBeenCalledTimes(1); + expect(mockClosePointInTime).toHaveBeenCalledTimes(1); + expect(mockClosePointInTime).toHaveBeenCalledWith({ id: 'mockedPitId' }); + expect(result.length).toEqual(18001); + }); +}); diff --git a/x-pack/plugins/osquery/server/lib/parse_agent_groups.ts b/x-pack/plugins/osquery/server/lib/parse_agent_groups.ts index 723216a675fb..642bfd4adfa2 100644 --- a/x-pack/plugins/osquery/server/lib/parse_agent_groups.ts +++ b/x-pack/plugins/osquery/server/lib/parse_agent_groups.ts @@ -6,8 +6,8 @@ */ import { uniq } from 'lodash'; -import type { SavedObjectsClientContract } from '@kbn/core/server'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; +import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { AGENTS_INDEX, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; import { OSQUERY_INTEGRATION_NAME } from '../../common'; import type { OsqueryAppContext } from './osquery_app_context_services'; @@ -20,15 +20,56 @@ export interface AgentSelection { const PER_PAGE = 9000; -const aggregateResults = async ( - generator: (page: number, perPage: number) => Promise<{ results: string[]; total: number }> +export const aggregateResults = async ( + generator: ( + page: number, + perPage: number, + searchAfter?: unknown[], + pitId?: string + ) => Promise<{ results: string[]; total: number; searchAfter?: unknown[] }>, + esClient: ElasticsearchClient, + context: OsqueryAppContext ) => { - const { results, total } = await generator(1, PER_PAGE); + let results: string[]; + const { results: initialResults, total } = await generator(1, PER_PAGE); const totalPages = Math.ceil(total / PER_PAGE); - let currPage = 2; - while (currPage <= totalPages) { - const { results: additionalResults } = await generator(currPage++, PER_PAGE); - results.push(...additionalResults); + if (totalPages === 1) { + // One page only, no need for PIT + results = initialResults; + } else { + const { id: pitId } = await esClient.openPointInTime({ + index: AGENTS_INDEX, + keep_alive: '10m', + }); + let currentSort: unknown[] | undefined; + // Refetch first page with PIT + const { results: pitInitialResults, searchAfter } = await generator( + 1, + PER_PAGE, + currentSort, // No searchAfter for first page, its built based on first page results + pitId + ); + results = pitInitialResults; + currentSort = searchAfter; + let currPage = 2; + while (currPage <= totalPages) { + const { results: additionalResults, searchAfter: additionalSearchAfter } = await generator( + currPage++, + PER_PAGE, + currentSort, + pitId + ); + results.push(...additionalResults); + currentSort = additionalSearchAfter; + } + + try { + await esClient.closePointInTime({ id: pitId }); + } catch (error) { + context.logFactory + .get() + .warn(`Error closing point in time with id: ${pitId}. Error: ${error.message}`); + } } return uniq(results); @@ -36,6 +77,7 @@ const aggregateResults = async ( export const parseAgentSelection = async ( soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, context: OsqueryAppContext, agentSelection: AgentSelection ) => { @@ -52,28 +94,42 @@ export const parseAgentSelection = async ( const kueryFragments = ['status:online']; if (agentService && packagePolicyService) { - const osqueryPolicies = await aggregateResults(async (page, perPage) => { - const { items, total } = await packagePolicyService.list(soClient, { - kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${OSQUERY_INTEGRATION_NAME}`, - perPage, - page, - }); + const osqueryPolicies = await aggregateResults( + async (page, perPage) => { + const { items, total } = await packagePolicyService.list(soClient, { + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${OSQUERY_INTEGRATION_NAME}`, + perPage, + page, + }); - return { results: items.map((it) => it.policy_id), total }; - }); + return { results: items.map((it) => it.policy_id), total }; + }, + esClient, + context + ); kueryFragments.push(`policy_id:(${uniq(osqueryPolicies).join(' or ')})`); if (allAgentsSelected) { const kuery = kueryFragments.join(' and '); - const fetchedAgents = await aggregateResults(async (page, perPage) => { - const res = await agentService.listAgents({ - perPage, - page, - kuery, - showInactive: false, - }); + const fetchedAgents = await aggregateResults( + async (page, perPage, searchAfter?: unknown[], pitId?: string) => { + const res = await agentService.listAgents({ + ...(searchAfter ? { searchAfter } : {}), + ...(pitId ? { pitId } : {}), + perPage, + page, + kuery, + showInactive: false, + }); - return { results: res.agents.map((agent) => agent.id), total: res.total }; - }); + return { + results: res.agents.map((agent) => agent.id), + total: res.total, + searchAfter: res.agents[res.agents.length - 1].sort, + }; + }, + esClient, + context + ); fetchedAgents.forEach(addAgent); } else { if (platformsSelected.length > 0 || policiesSelected.length > 0) { @@ -88,16 +144,26 @@ export const parseAgentSelection = async ( kueryFragments.push(`(${groupFragments.join(' or ')})`); const kuery = kueryFragments.join(' and '); - const fetchedAgents = await aggregateResults(async (page, perPage) => { - const res = await agentService.listAgents({ - perPage, - page, - kuery, - showInactive: false, - }); + const fetchedAgents = await aggregateResults( + async (page, perPage, searchAfter?: unknown[], pitId?: string) => { + const res = await agentService.listAgents({ + ...(searchAfter ? { searchAfter } : {}), + ...(pitId ? { pitId } : {}), + perPage, + page, + kuery, + showInactive: false, + }); - return { results: res.agents.map((agent) => agent.id), total: res.total }; - }); + return { + results: res.agents.map((agent) => agent.id), + total: res.total, + searchAfter: res.agents[res.agents.length - 1].sort, + }; + }, + esClient, + context + ); fetchedAgents.forEach(addAgent); } } diff --git a/x-pack/plugins/profiling/common/__fixtures__/README.md b/x-pack/plugins/profiling/common/__fixtures__/README.md deleted file mode 100644 index 1a26bca59066..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/README.md +++ /dev/null @@ -1,17 +0,0 @@ -The stacktrace fixtures in this directory are originally from Elasticsearch's -`POST /_profiling/stacktraces` endpoint. They were subsequently filtered -through the `shrink_stacktrace_response.js` command in `x-pack/plugins/profiling/scripts/` -to reduce the size without losing sampling fidelity (see the script for further -details). - -The naming convention for each stacktrace fixture follows this pattern: - -``` -stacktraces_{seconds}s_{upsampling rate}x.json -``` - -where `seconds` is the time span of the original query and `upsampling rate` is -the reciprocal of the sampling rate returned from the original query. - -To add a new stacktrace fixture to the test suite, update `stacktraces.ts` -appropriately. \ No newline at end of file diff --git a/x-pack/plugins/profiling/common/__fixtures__/base_flamegraph.ts b/x-pack/plugins/profiling/common/__fixtures__/base_flamegraph.ts new file mode 100644 index 000000000000..1e1b2bd341b8 --- /dev/null +++ b/x-pack/plugins/profiling/common/__fixtures__/base_flamegraph.ts @@ -0,0 +1,297 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BaseFlameGraph } from '@kbn/profiling-utils'; + +export const baseFlamegraph: BaseFlameGraph = { + Edges: [ + [1], + [2], + [3], + [4], + [5], + [6], + [7], + [8], + [9], + [10], + [11], + [12], + [13], + [14], + [15], + [16], + [17], + [18], + [19], + [20], + [21], + [22], + [23], + [24], + [25], + [26], + [27], + [28], + [29], + [30], + [31], + [32], + [33], + [34], + [], + ], + FileID: [ + '', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + 'fwIcP8qXDOl7k0VhWU8z9Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + '5JfXt00O17Yra2Rwh8HT8Q', + ], + FrameType: [ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, + ], + Inline: [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + ], + ExeFilename: [ + '', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'metricbeat', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + 'vmlinux', + ], + AddressOrLine: [ + 0, 43443520, 67880745, 67881145, 53704110, 53704665, 53696841, 53697537, 53700683, 53696841, + 52492674, 67626923, 67629380, 67630226, 51515812, 51512445, 51522994, 44606453, 43747101, + 43699300, 43538916, 43547623, 42994898, 42994925, 14680216, 14356875, 3732840, 3732678, 3721714, + 3719260, 3936007, 3897721, 4081162, 4458225, 1712873, + ], + FunctionName: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'entry_SYSCALL_64_after_hwframe', + 'do_syscall_64', + '__x64_sys_read', + 'ksys_read', + 'vfs_read', + 'new_sync_read', + 'seq_read_iter', + 'm_show', + 'show_mountinfo', + 'kernfs_sop_show_path', + 'cgroup_show_path', + ], + FunctionOffset: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + SourceFilename: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + SourceLine: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + CountInclusive: [ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, + ], + CountExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, + ], + AnnualCO2TonsInclusive: [ + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + 0.0013627551116480942, 0.0013627551116480942, 0.0013627551116480942, + ], + AnnualCO2TonsExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0.0013627551116480942, + ], + AnnualCostsUSDInclusive: [ + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, 61.30240940376492, + ], + AnnualCostsUSDExclusive: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 61.30240940376492, + ], + Size: 35, + SamplingRate: 1, + SelfCPU: 7, + TotalCPU: 245, + SelfAnnualCO2Tons: 0.0013627551116480942, + TotalAnnualCO2Tons: 0.04769642890768329, + SelfAnnualCostsUSD: 61.30240940376492, + TotalAnnualCostsUSD: 2145.5843291317715, + TotalSamples: 7, + TotalSeconds: 4.980000019073486, +}; diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces.ts b/x-pack/plugins/profiling/common/__fixtures__/stacktraces.ts deleted file mode 100644 index d831f5f20d48..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/stacktraces.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { StackTraceResponse } from '@kbn/profiling-utils'; - -import stackTraces1x from './stacktraces_60s_1x.json'; -import stackTraces5x from './stacktraces_3600s_5x.json'; -import stackTraces125x from './stacktraces_86400s_125x.json'; -import stackTraces625x from './stacktraces_604800s_625x.json'; - -export const stackTraceFixtures: Array<{ - response: StackTraceResponse; - seconds: number; - upsampledBy: number; -}> = [ - { response: stackTraces1x, seconds: 60, upsampledBy: 1 }, - { response: stackTraces5x, seconds: 3600, upsampledBy: 5 }, - { response: stackTraces125x, seconds: 86400, upsampledBy: 125 }, - { response: stackTraces625x, seconds: 604800, upsampledBy: 625 }, -]; diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_3600s_5x.json b/x-pack/plugins/profiling/common/__fixtures__/stacktraces_3600s_5x.json deleted file mode 100644 index cad5ac24c7a7..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_3600s_5x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"-njmbjRUBOZR5EgXpUQdRw":42,"ztDY3GPoIfO7CjHQxmyZ-Q":115,"Y8CwPu4zFwOz0m86XYzkGw":256,"QiwsJA6NJ0Q3f2M4DT-dxA":1192,"9_06LL00QkYIeiFNCWu0XQ":1033,"GApi1ybrprUZdnGMiSfUPA":675,"QpRRwD9tRNNrUmJ_2oOuSg":385,"43tbk4XHS6h_eSSkozr2lQ":480,"nORl1I4BGh3mzZiFR21ijQ":342,"ONNtRKFUjSc8lLm64B4nVQ":604,"IgUYn71JvS5hV0IssAqJCA":415,"u31aX9a6CI2OuomWQHSx1Q":486,"ZBYtP3yTV5OAbePvOl3arg":500,"ztbi9NfSFBK5AxpIlylSew":478,"-s21TvA-EsTWbfCutQG83Q":402,"APcbPjShNMH1PkL1e22JYg":381,"sGdKDAzt2D3ZK2brqGj4vQ":551,"hecRkAhRG62NML7wI512zA":225,"yqosCJmye4YNNxuB2s8zdQ":181,"JEl8c8qrwRMDRhl_VlTpFQ":234,"TFvQpP8OVc3AdHSKmIUBAA":218,"eUMH9Wf36CVzdkAZsN9itA":242,"57NvBalQc9mIcBwC1lPObg":229,"qaTBBEzEjIyGmsWUYfCBpA":189,"y7Mdo_ee9-4XsWhpA4MB0g":271,"vODIlh-kDOyM2hWSJhdfpA":235,"QKuCwkwTUdmVpouD1TSb6g":167,"zQ3yVnMIXoz1yUFx6SaSlA":146,"PfGJvpI_t-0Eiwgl8k31BA":148,"P-lVr6eiwDBuO8eZBdsdMQ":144,"KxQngfXsErVAsVuASxix6w":138,"NDxOvbKIocbTk6FkHrLlqQ":107,"2GP6bCEH-XkrLdH6ox0E3Q":95,"NYEjWS7muJ8dsj9z5lNehg":52,"Nr5XZDDmb-nXg0BzTFzdFA":44,"JVvUxIunvr6V68Rt99rK9w":38,"tagsGmBta7BnDHBzEbH9eQ":28,"CjP83pplY09FGl9PBMeqCg":13,"SQ6jhz-Ee7WHXLMOHOsDcQ":18,"eM1ATYEKUIN4nyPylmr13A":20,"9vNu8RjYClbqhYYGUiWI7A":12,"CU-T9AvnxmWd1TTRjgV01Q":17,"hoJT-ObO7MDFTgt9UeFJfg":9,"us5XzJaFA8Y8a8Jhq7VWzQ":34,"tWPDa1sBMePW-YFiahrHBA":9,"KKjaO47Ew4fmVCY-lBFkLg":6,"zxyQebekMWvnWWEuWSzR9Q":8,"UI-7Z494NKAWuv1FuNlxoQ":4,"6yHX0lcyWmly8MshBzd78Q":7,"uEL43HtanLRCO2rLB4ttzQ":3,"mXgK2ekWZ4qH-uHB8QaLtA":7,"1twYzjHR6hCfJqQLvJ81XA":5,"f-LRF9Sfj675yc68DOXczw":2,"p24lyWOwFjGMsQaWybQUMA":1,"KHat1RLkyP8wPwwR1uD04A":4,"B-OQjwP7KzSb4f6cXUL1bA":2,"kOWftL0Ttias8Z1isZi9oA":4,"JzGylmBPluUmIML9XnagKw":3,"tTw0tfSnPtZhbcyzyVHHpg":2,"E_F-N51BcZ4iQ9oPaHFKXw":2,"d04G8ZHV3kYQ0ekQBw1VYQ":3,"I-DofAMUQgh7q14tBJcZlA":3,"tGGi0acvAmmxOR5DbuF3dg":4,"Ws9TqFMz-kHv_-7zrBFdKw":3,"nBHRVpYV5wUL_UAb5ff6Zg":1,"vfw5EN0FEHQCAj0w-N2avQ":1,"lyeLQDjWsQDYEJbcY4aFJA":3,"cqzgaW0F-6gZ8uHz_Pf3hQ":1,"b89Eo7vMfG4HsPSBVvjiKQ":5,"5_-zAnLDYAi4FySmVgS6iw":2,"zOI_cRK31hVrh4Typ0-Fxg":5,"4U9ayDnwvWmqJPhn_AOKew":8,"Jt6CexOHLEwUl4IeTgASBQ":4,"8Rif7kuKG2cfhEYF2fJXmA":4,"cCjn5miDmyezrnBAe2jDww":12,"f8AFYpSQOpjCNbhqUuR3Rg":9,"dGMvgpGXk-ajX6PRi92qdg":9,"OxrG9ZVAzX9GwGtxUtIQNg":3,"QoW8uF5K3OBNL2DXI66leA":9,"zV-93oQDbZK9zB7UMAcCmw":5,"9CQVJEfCfL1rSnUaxlAfqg":3,"mGGvLNOYB74ofk9FRrMxxQ":2,"pnLCuJVNeqGwwFeJQIrkPw":2,"R77Zz6fBvENVXyt4GVb9dQ":1,"tgL-t2GJJjItpLjnwjc4zQ":1,"XNCSlgkv_bOXDIYn6zwekw":5,"jPN_jNGPJguImYjakYlBcA":1,"4K-SlZ4j8NjsVBpqyPj2dw":1,"W8IRlEZMfFJdYSgUQXDnMg":2,"qytuJG9brvKSB9NJCHV9fQ":1,"b116myovN7_XXb1AVLPH0g":1,"dNwgDmnCM1dIIF5EZm4ZgA":1,"KEdXtWOmrUdpIHsjndtg_A":1,"V2K_ZjA6rol7KyINtV45_A":1},"stack_traces":{"-njmbjRUBOZR5EgXpUQdRw":{"address_or_lines":[1277056],"file_ids":["G68hjsyagwq6LpWrMjDdng"],"frame_ids":["G68hjsyagwq6LpWrMjDdngAAAAAAE3yA"],"type_ids":[3]},"ztDY3GPoIfO7CjHQxmyZ-Q":{"address_or_lines":[4643458,4456960],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtqC","B8JRxL079xbhqQBqGvksAgAAAAAARAIA"],"type_ids":[3,3]},"Y8CwPu4zFwOz0m86XYzkGw":{"address_or_lines":[4597989,4390116,4390542],"file_ids":["6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w"],"frame_ids":["6kzBY4yj-1Fh1NCTZA3z0wAAAAAARijl","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQvzk","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQv6O"],"type_ids":[3,3,3]},"QiwsJA6NJ0Q3f2M4DT-dxA":{"address_or_lines":[4597989,4307812,4320019,4321918],"file_ids":["6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w","6kzBY4yj-1Fh1NCTZA3z0w"],"frame_ids":["6kzBY4yj-1Fh1NCTZA3z0wAAAAAARijl","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQbtk","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQesT","6kzBY4yj-1Fh1NCTZA3z0wAAAAAAQfJ-"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"GApi1ybrprUZdnGMiSfUPA":{"address_or_lines":[18434496,18109958,18105083,18107109,18183090,18183229],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABFFYG","j8DVIOTu7Btj9lgFefJ84AAAAAABFEL7","j8DVIOTu7Btj9lgFefJ84AAAAAABFErl","j8DVIOTu7Btj9lgFefJ84AAAAAABFXOy","j8DVIOTu7Btj9lgFefJ84AAAAAABFXQ9"],"type_ids":[3,3,3,3,3,3]},"QpRRwD9tRNNrUmJ_2oOuSg":{"address_or_lines":[4644672,40444780,40465086,40468873,40476239,4250662,4249714],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARt9A","B56YkhsK1JwqD-8F8sjS3AAAAAACaSNs","B56YkhsK1JwqD-8F8sjS3AAAAAACaXK-","B56YkhsK1JwqD-8F8sjS3AAAAAACaYGJ","B56YkhsK1JwqD-8F8sjS3AAAAAACaZ5P","B56YkhsK1JwqD-8F8sjS3AAAAAAAQNwm","B56YkhsK1JwqD-8F8sjS3AAAAAAAQNhy"],"type_ids":[3,3,3,3,3,3,3]},"43tbk4XHS6h_eSSkozr2lQ":{"address_or_lines":[18515232,22597677,22574090,22556393,22530363,22106663,22101077,22107662],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHQK","v6HIzNa4K6G4nRP9032RIAAAAAABWC7p","v6HIzNa4K6G4nRP9032RIAAAAAABV8k7","v6HIzNa4K6G4nRP9032RIAAAAAABUVIn","v6HIzNa4K6G4nRP9032RIAAAAAABUTxV","v6HIzNa4K6G4nRP9032RIAAAAAABUVYO"],"type_ids":[3,3,3,3,3,3,3,3]},"nORl1I4BGh3mzZiFR21ijQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271908,4256166,4255110,4288975,4287865],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qfk","FWZ9q3TQKZZok58ua1HDsgAAAAAAQPGm","FWZ9q3TQKZZok58ua1HDsgAAAAAAQO2G","FWZ9q3TQKZZok58ua1HDsgAAAAAAQXHP","FWZ9q3TQKZZok58ua1HDsgAAAAAAQW15"],"type_ids":[3,3,3,3,3,3,3,3,3]},"ONNtRKFUjSc8lLm64B4nVQ":{"address_or_lines":[4641312,7081613,7060969,4425906,7064267,7057968,6093476,6025643,4305623,4278829],"file_ids":["gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w","gNW12BepH17pXwK-ZuYt3w"],"frame_ids":["gNW12BepH17pXwK-ZuYt3wAAAAAARtIg","gNW12BepH17pXwK-ZuYt3wAAAAAAbA6N","gNW12BepH17pXwK-ZuYt3wAAAAAAa73p","gNW12BepH17pXwK-ZuYt3wAAAAAAQ4iy","gNW12BepH17pXwK-ZuYt3wAAAAAAa8rL","gNW12BepH17pXwK-ZuYt3wAAAAAAa7Iw","gNW12BepH17pXwK-ZuYt3wAAAAAAXPqk","gNW12BepH17pXwK-ZuYt3wAAAAAAW_Gr","gNW12BepH17pXwK-ZuYt3wAAAAAAQbLX","gNW12BepH17pXwK-ZuYt3wAAAAAAQUot"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"IgUYn71JvS5hV0IssAqJCA":{"address_or_lines":[4636100,4452920,4453106,4487396,4487396,4651100,10485923,16743,1136873,1113241,4849252],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARr3E","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ_I4","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ_Ly","B56YkhsK1JwqD-8F8sjS3AAAAAAARHjk","B56YkhsK1JwqD-8F8sjS3AAAAAAARHjk","B56YkhsK1JwqD-8F8sjS3AAAAAAARvhc","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEVjp","piWSMQrh4r040D0BPNaJvwAAAAAAEPyZ","piWSMQrh4r040D0BPNaJvwAAAAAASf5k"],"type_ids":[3,3,3,3,3,3,4,4,4,4,4]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"ZBYtP3yTV5OAbePvOl3arg":{"address_or_lines":[4636226,4469356,4468068,4466980,4460377,4459271,4243432,4415957,4652642,10485923,16743,1221731,1219038],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","B56YkhsK1JwqD-8F8sjS3A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARr5C","B56YkhsK1JwqD-8F8sjS3AAAAAAARDJs","B56YkhsK1JwqD-8F8sjS3AAAAAAARC1k","B56YkhsK1JwqD-8F8sjS3AAAAAAARCkk","B56YkhsK1JwqD-8F8sjS3AAAAAAARA9Z","B56YkhsK1JwqD-8F8sjS3AAAAAAARAsH","B56YkhsK1JwqD-8F8sjS3AAAAAAAQL_o","B56YkhsK1JwqD-8F8sjS3AAAAAAAQ2HV","B56YkhsK1JwqD-8F8sjS3AAAAAAARv5i","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEpne"],"type_ids":[3,3,3,3,3,3,3,3,3,4,4,4,4]},"ztbi9NfSFBK5AxpIlylSew":{"address_or_lines":[4594466,4444524,4443160,4438546,4391572,4609107,10485923,16807,2756288,2755416,2744627,2792698,4867725,4855327],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARhsi","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ9Fs","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ8wY","kajOqZqz7V1y0BdYQLFQrwAAAAAAQ7oS","kajOqZqz7V1y0BdYQLFQrwAAAAAAQwKU","kajOqZqz7V1y0BdYQLFQrwAAAAAARlRT","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAKpz6","A2oiHVwisByxRn5RDT4LjAAAAAAASkaN","A2oiHVwisByxRn5RDT4LjAAAAAAAShYf"],"type_ids":[3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"APcbPjShNMH1PkL1e22JYg":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54546893,54560984,44458726,43610833,43327941,43735894],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFHN","MNBJ5seVz_ocW6tcr1HSmwAAAAADQIjY","MNBJ5seVz_ocW6tcr1HSmwAAAAACpmLm","MNBJ5seVz_ocW6tcr1HSmwAAAAACmXLR","MNBJ5seVz_ocW6tcr1HSmwAAAAAClSHF","MNBJ5seVz_ocW6tcr1HSmwAAAAACm1tW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"sGdKDAzt2D3ZK2brqGj4vQ":{"address_or_lines":[4652224,22354871,22382638,22364302,56672751,58471189,58268669,58227812,58241853,31197476,7372151,7373114,7373997,4536145,4264900,4265340,4655641],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYMHv","-pk6w5puGcp-wKnQ61BZzQAAAAADfDMV","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH13","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIE6","-pk6w5puGcp-wKnQ61BZzQAAAAAAcISt","-pk6w5puGcp-wKnQ61BZzQAAAAAARTdR","-pk6w5puGcp-wKnQ61BZzQAAAAAAQRPE","-pk6w5puGcp-wKnQ61BZzQAAAAAAQRV8","-pk6w5puGcp-wKnQ61BZzQAAAAAARwoZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"yqosCJmye4YNNxuB2s8zdQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961653,27949894,18928855],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqk1","v6HIzNa4K6G4nRP9032RIAAAAAABqntG","v6HIzNa4K6G4nRP9032RIAAAAAABINTX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"JEl8c8qrwRMDRhl_VlTpFQ":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59181690,58121321,58026161,58173220,58175116,7294148,7295421,7297245,7300762,7297188,7304836,7297413,7309604,7298328,5114154],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwp6","B8JRxL079xbhqQBqGvksAgAAAAADdtxp","B8JRxL079xbhqQBqGvksAgAAAAADdWix","B8JRxL079xbhqQBqGvksAgAAAAADd6ck","B8JRxL079xbhqQBqGvksAgAAAAADd66M","B8JRxL079xbhqQBqGvksAgAAAAAAb0zE","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1mF","B8JRxL079xbhqQBqGvksAgAAAAAAb4kk","B8JRxL079xbhqQBqGvksAgAAAAAAb10Y","B8JRxL079xbhqQBqGvksAgAAAAAATgkq"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"TFvQpP8OVc3AdHSKmIUBAA":{"address_or_lines":[4652224,22357367,22385134,22366798,57092143,58893857,58677085,58641545,58657509,31313785,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7306724,5132868,4625639,4289536],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZygv","B8JRxL079xbhqQBqGvksAgAAAAADgqYh","B8JRxL079xbhqQBqGvksAgAAAAADf1dd","B8JRxL079xbhqQBqGvksAgAAAAADfsyJ","B8JRxL079xbhqQBqGvksAgAAAAADfwrl","B8JRxL079xbhqQBqGvksAgAAAAAB3c95","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb33k","B8JRxL079xbhqQBqGvksAgAAAAAATlJE","B8JRxL079xbhqQBqGvksAgAAAAAARpTn","B8JRxL079xbhqQBqGvksAgAAAAAAQXQA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"eUMH9Wf36CVzdkAZsN9itA":{"address_or_lines":[32443680,43151402,43152149,43153397,41329281,41441892,41443480,41222389,41225442,41240900,40679166,40714972,40707458,40707880,40710748,40690621,40679204,40688196,40679204,40688166,40644014,41210644],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7w0g","QvG8QEGAld88D676NL_Y2QAAAAACknAq","QvG8QEGAld88D676NL_Y2QAAAAACknMV","QvG8QEGAld88D676NL_Y2QAAAAACknf1","QvG8QEGAld88D676NL_Y2QAAAAACdqKB","QvG8QEGAld88D676NL_Y2QAAAAACeFpk","QvG8QEGAld88D676NL_Y2QAAAAACeGCY","QvG8QEGAld88D676NL_Y2QAAAAACdQD1","QvG8QEGAld88D676NL_Y2QAAAAACdQzi","QvG8QEGAld88D676NL_Y2QAAAAACdUlE","QvG8QEGAld88D676NL_Y2QAAAAACbLb-","QvG8QEGAld88D676NL_Y2QAAAAACbULc","QvG8QEGAld88D676NL_Y2QAAAAACbSWC","QvG8QEGAld88D676NL_Y2QAAAAACbSco","QvG8QEGAld88D676NL_Y2QAAAAACbTJc","QvG8QEGAld88D676NL_Y2QAAAAACbOO9","QvG8QEGAld88D676NL_Y2QAAAAACbLck","QvG8QEGAld88D676NL_Y2QAAAAACbNpE","QvG8QEGAld88D676NL_Y2QAAAAACbLck","QvG8QEGAld88D676NL_Y2QAAAAACbNom","QvG8QEGAld88D676NL_Y2QAAAAACbC2u","QvG8QEGAld88D676NL_Y2QAAAAACdNMU"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"57NvBalQc9mIcBwC1lPObg":{"address_or_lines":[4652224,31040261,31054565,31056612,31058888,31450411,30791748,25539462,25519688,25480413,25483943,25484196,4951332,4960527,4959954,4897957,4893996,4627954,4660663,10485923,16807,3103640,3100879],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAAB2aMF","B8JRxL079xbhqQBqGvksAgAAAAAB2drl","B8JRxL079xbhqQBqGvksAgAAAAAB2eLk","B8JRxL079xbhqQBqGvksAgAAAAAB2evI","B8JRxL079xbhqQBqGvksAgAAAAAB3-Ur","B8JRxL079xbhqQBqGvksAgAAAAAB1dhE","B8JRxL079xbhqQBqGvksAgAAAAABhbOG","B8JRxL079xbhqQBqGvksAgAAAAABhWZI","B8JRxL079xbhqQBqGvksAgAAAAABhMzd","B8JRxL079xbhqQBqGvksAgAAAAABhNqn","B8JRxL079xbhqQBqGvksAgAAAAABhNuk","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7EP","B8JRxL079xbhqQBqGvksAgAAAAAAS67S","B8JRxL079xbhqQBqGvksAgAAAAAASryl","B8JRxL079xbhqQBqGvksAgAAAAAASq0s","B8JRxL079xbhqQBqGvksAgAAAAAARp3y","B8JRxL079xbhqQBqGvksAgAAAAAARx23","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAL1uY","A2oiHVwisByxRn5RDT4LjAAAAAAAL1DP"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"qaTBBEzEjIyGmsWUYfCBpA":{"address_or_lines":[4652224,31040261,31054565,31056612,31058888,31450411,30791748,25539462,25520823,25502704,25503492,25480821,25481061,4953508,4960780,4898318,4893650,4898160,4745321,4757831,4219698,4219725,10485923,16755],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAAB2aMF","B8JRxL079xbhqQBqGvksAgAAAAAB2drl","B8JRxL079xbhqQBqGvksAgAAAAAB2eLk","B8JRxL079xbhqQBqGvksAgAAAAAB2evI","B8JRxL079xbhqQBqGvksAgAAAAAB3-Ur","B8JRxL079xbhqQBqGvksAgAAAAAB1dhE","B8JRxL079xbhqQBqGvksAgAAAAABhbOG","B8JRxL079xbhqQBqGvksAgAAAAABhWq3","B8JRxL079xbhqQBqGvksAgAAAAABhSPw","B8JRxL079xbhqQBqGvksAgAAAAABhScE","B8JRxL079xbhqQBqGvksAgAAAAABhM51","B8JRxL079xbhqQBqGvksAgAAAAABhM9l","B8JRxL079xbhqQBqGvksAgAAAAAAS5Wk","B8JRxL079xbhqQBqGvksAgAAAAAAS7IM","B8JRxL079xbhqQBqGvksAgAAAAAASr4O","B8JRxL079xbhqQBqGvksAgAAAAAASqvS","B8JRxL079xbhqQBqGvksAgAAAAAASr1w","B8JRxL079xbhqQBqGvksAgAAAAAASGhp","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"y7Mdo_ee9-4XsWhpA4MB0g":{"address_or_lines":[4652224,58223725,10400868,10401064,10401333,10401661,58236869,58227432,58120068,58163344,58184537,58041720,57725674,57726188,57066632,22280836,22281116,22396783,22397566,22398116,5362852,5363370,4271546,4264588,4299069],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAADeGxt","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrRk","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrUo","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrY1","6auiCMWq5cA-hAbqSYvdQQAAAAAAnrd9","6auiCMWq5cA-hAbqSYvdQQAAAAADeJ_F","6auiCMWq5cA-hAbqSYvdQQAAAAADeHro","6auiCMWq5cA-hAbqSYvdQQAAAAADdteE","6auiCMWq5cA-hAbqSYvdQQAAAAADd4CQ","6auiCMWq5cA-hAbqSYvdQQAAAAADd9NZ","6auiCMWq5cA-hAbqSYvdQQAAAAADdaV4","6auiCMWq5cA-hAbqSYvdQQAAAAADcNLq","6auiCMWq5cA-hAbqSYvdQQAAAAADcNTs","6auiCMWq5cA-hAbqSYvdQQAAAAADZsSI","6auiCMWq5cA-hAbqSYvdQQAAAAABU_qE","6auiCMWq5cA-hAbqSYvdQQAAAAABU_uc","6auiCMWq5cA-hAbqSYvdQQAAAAABVb9v","6auiCMWq5cA-hAbqSYvdQQAAAAABVcJ-","6auiCMWq5cA-hAbqSYvdQQAAAAABVcSk","6auiCMWq5cA-hAbqSYvdQQAAAAAAUdSk","6auiCMWq5cA-hAbqSYvdQQAAAAAAUdaq","6auiCMWq5cA-hAbqSYvdQQAAAAAAQS26","6auiCMWq5cA-hAbqSYvdQQAAAAAAQRKM","6auiCMWq5cA-hAbqSYvdQQAAAAAAQZk9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"vODIlh-kDOyM2hWSJhdfpA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19976893,19927481,19928567,19983876,19943049,19984068,19944276,19984260,19945213,19982696,19937907,19982884,19142858],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNK9","v6HIzNa4K6G4nRP9032RIAAAAAABMBG5","v6HIzNa4K6G4nRP9032RIAAAAAABMBX3","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMO-E","v6HIzNa4K6G4nRP9032RIAAAAAABMFb9","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMOok","v6HIzNa4K6G4nRP9032RIAAAAAABJBjK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"QKuCwkwTUdmVpouD1TSb6g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858562,18659470],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwSC","j8DVIOTu7Btj9lgFefJ84AAAAAABHLiO"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"zQ3yVnMIXoz1yUFx6SaSlA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528467,54488242,54489352,54492882,44042020,44050554,43824563,43838109,43282962,43282989,10485923,16807,2741196,2827770,2817934],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQAnT","MNBJ5seVz_ocW6tcr1HSmwAAAAADP2yy","MNBJ5seVz_ocW6tcr1HSmwAAAAADP3EI","MNBJ5seVz_ocW6tcr1HSmwAAAAADP37S","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAck","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCh6","MNBJ5seVz_ocW6tcr1HSmwAAAAACnLWz","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOqd","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv-O"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"PfGJvpI_t-0Eiwgl8k31BA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708921,24712242,24698684,24696100,20084020,20086666,20084847,20085083,18040582,18049603],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQc5","j8DVIOTu7Btj9lgFefJ84AAAAAABeRQy","j8DVIOTu7Btj9lgFefJ84AAAAAABeN88","j8DVIOTu7Btj9lgFefJ84AAAAAABeNUk","j8DVIOTu7Btj9lgFefJ84AAAAAABMnU0","j8DVIOTu7Btj9lgFefJ84AAAAAABMn-K","j8DVIOTu7Btj9lgFefJ84AAAAAABMnhv","j8DVIOTu7Btj9lgFefJ84AAAAAABMnlb","j8DVIOTu7Btj9lgFefJ84AAAAAABE0cG","j8DVIOTu7Btj9lgFefJ84AAAAAABE2pD"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"P-lVr6eiwDBuO8eZBdsdMQ":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528745,54499864,54500494,54477482,44044054,44044293,44044676,44051020,43988398,43982642,43988240,43826825,43837959,43282962,43282989,10485923,16755],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQArp","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5oY","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5yO","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA8W","MNBJ5seVz_ocW6tcr1HSmwAAAAACoBAF","MNBJ5seVz_ocW6tcr1HSmwAAAAACoBGE","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCpM","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzWu","MNBJ5seVz_ocW6tcr1HSmwAAAAACnx8y","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzUQ","MNBJ5seVz_ocW6tcr1HSmwAAAAACnL6J","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"KxQngfXsErVAsVuASxix6w":{"address_or_lines":[4652224,11645454,31861537,31858282,31847101,59040776,58304471,58312462,31457395,31076505,31042101,31058818,31448215,30842852,30845380,30848778,30847620,4952886,4953125,4953508,4960780,4898318,4893650,4898125,4628233,4660663,10485923,16807,3104019,8528279,936364],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAAsbIO","6auiCMWq5cA-hAbqSYvdQQAAAAAB5ish","6auiCMWq5cA-hAbqSYvdQQAAAAAB5h5q","6auiCMWq5cA-hAbqSYvdQQAAAAAB5fK9","6auiCMWq5cA-hAbqSYvdQQAAAAADhOQI","6auiCMWq5cA-hAbqSYvdQQAAAAADeafX","6auiCMWq5cA-hAbqSYvdQQAAAAADeccO","6auiCMWq5cA-hAbqSYvdQQAAAAAB4ABz","6auiCMWq5cA-hAbqSYvdQQAAAAAB2jCZ","6auiCMWq5cA-hAbqSYvdQQAAAAAB2ao1","6auiCMWq5cA-hAbqSYvdQQAAAAAB2euC","6auiCMWq5cA-hAbqSYvdQQAAAAAB39yX","6auiCMWq5cA-hAbqSYvdQQAAAAAB1p_k","6auiCMWq5cA-hAbqSYvdQQAAAAAB1qnE","6auiCMWq5cA-hAbqSYvdQQAAAAAB1rcK","6auiCMWq5cA-hAbqSYvdQQAAAAAB1rKE","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5M2","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5Ql","6auiCMWq5cA-hAbqSYvdQQAAAAAAS5Wk","6auiCMWq5cA-hAbqSYvdQQAAAAAAS7IM","6auiCMWq5cA-hAbqSYvdQQAAAAAASr4O","6auiCMWq5cA-hAbqSYvdQQAAAAAASqvS","6auiCMWq5cA-hAbqSYvdQQAAAAAASr1N","6auiCMWq5cA-hAbqSYvdQQAAAAAARp8J","6auiCMWq5cA-hAbqSYvdQQAAAAAARx23","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAL10T","ew01Dk0sWZctP-VaEpavqQAAAAAAgiGX","ew01Dk0sWZctP-VaEpavqQAAAAAADkms"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"NDxOvbKIocbTk6FkHrLlqQ":{"address_or_lines":[4652224,58222957,10400868,10401064,10401333,10401661,58236101,58226664,58119300,58162576,58183769,58040952,57724906,57725420,57065864,22280836,22281206,22412958,22408242,22413668,22416921,22341332,22109092,22108612,11325304,11325700,10718668,11154818,57469092,57466065,4552751,4263429],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADeGlt","B8JRxL079xbhqQBqGvksAgAAAAAAnrRk","B8JRxL079xbhqQBqGvksAgAAAAAAnrUo","B8JRxL079xbhqQBqGvksAgAAAAAAnrY1","B8JRxL079xbhqQBqGvksAgAAAAAAnrd9","B8JRxL079xbhqQBqGvksAgAAAAADeJzF","B8JRxL079xbhqQBqGvksAgAAAAADeHfo","B8JRxL079xbhqQBqGvksAgAAAAADdtSE","B8JRxL079xbhqQBqGvksAgAAAAADd32Q","B8JRxL079xbhqQBqGvksAgAAAAADd9BZ","B8JRxL079xbhqQBqGvksAgAAAAADdaJ4","B8JRxL079xbhqQBqGvksAgAAAAADcM_q","B8JRxL079xbhqQBqGvksAgAAAAADcNHs","B8JRxL079xbhqQBqGvksAgAAAAADZsGI","B8JRxL079xbhqQBqGvksAgAAAAABU_qE","B8JRxL079xbhqQBqGvksAgAAAAABU_v2","B8JRxL079xbhqQBqGvksAgAAAAABVf6e","B8JRxL079xbhqQBqGvksAgAAAAABVewy","B8JRxL079xbhqQBqGvksAgAAAAABVgFk","B8JRxL079xbhqQBqGvksAgAAAAABVg4Z","B8JRxL079xbhqQBqGvksAgAAAAABVObU","B8JRxL079xbhqQBqGvksAgAAAAABUVuk","B8JRxL079xbhqQBqGvksAgAAAAABUVnE","B8JRxL079xbhqQBqGvksAgAAAAAArM94","B8JRxL079xbhqQBqGvksAgAAAAAArNEE","B8JRxL079xbhqQBqGvksAgAAAAAAo43M","B8JRxL079xbhqQBqGvksAgAAAAAAqjWC","B8JRxL079xbhqQBqGvksAgAAAAADbOik","B8JRxL079xbhqQBqGvksAgAAAAADbNzR","B8JRxL079xbhqQBqGvksAgAAAAAARXgv","B8JRxL079xbhqQBqGvksAgAAAAAAQQ4F"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"2GP6bCEH-XkrLdH6ox0E3Q":{"address_or_lines":[4623648,7066994,7068484,7069849,7058446,10002970,10005676,10124500,9016547,11291366,9016547,24500423,24494926,9016547,10689293,10690744,9016547,24494153,24444068,9016547,24526481,9016547,12769368,12762703,6837766,6838366,6839304,5651373,5585348,5510696,4903076,4768780,4778619],"file_ids":["JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA"],"frame_ids":["JsObMPhfT_zO2Q_B1cPLxAAAAAAARo0g","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9Vy","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9tE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-CZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa7QO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKIa","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKys","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmnzU","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAArErm","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABddjH","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcNO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoxsN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoyC4","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcBJ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdPyk","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdj6R","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwthY","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwr5P","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFYG","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFhe","JsObMPhfT_zO2Q_B1cPLxAAAAAAAaFwI","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVjut","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVTnE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVBYo","JsObMPhfT_zO2Q_B1cPLxAAAAAAAStCk","JsObMPhfT_zO2Q_B1cPLxAAAAAAASMQM","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOp7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"NYEjWS7muJ8dsj9z5lNehg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19908516,19901477,19920683,18932457,18907996,18882195],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL_cr","v6HIzNa4K6G4nRP9032RIAAAAAABIOLp","v6HIzNa4K6G4nRP9032RIAAAAAABIINc","v6HIzNa4K6G4nRP9032RIAAAAAABIB6T"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Nr5XZDDmb-nXg0BzTFzdFA":{"address_or_lines":[4652224,22354871,22382638,22364302,56669071,58509234,58268669,58227812,58241853,31197553,31197973,31304315,4873273,4873930,4883062,4875761,4874468,8925121,8860356,8860667,8476967,4872825,5688954,8906989,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16890,16350,1408382],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYLOP","-pk6w5puGcp-wKnQ61BZzQAAAAADfMey","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Alx","-pk6w5puGcp-wKnQ61BZzQAAAAAB3AsV","-pk6w5puGcp-wKnQ61BZzQAAAAAB3ap7","-pk6w5puGcp-wKnQ61BZzQAAAAAASlw5","-pk6w5puGcp-wKnQ61BZzQAAAAAASl7K","-pk6w5puGcp-wKnQ61BZzQAAAAAASoJ2","-pk6w5puGcp-wKnQ61BZzQAAAAAASmXx","-pk6w5puGcp-wKnQ61BZzQAAAAAASmDk","-pk6w5puGcp-wKnQ61BZzQAAAAAAiC_B","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzLE","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzP7","-pk6w5puGcp-wKnQ61BZzQAAAAAAgVkn","-pk6w5puGcp-wKnQ61BZzQAAAAAASlp5","-pk6w5puGcp-wKnQ61BZzQAAAAAAVs56","-pk6w5puGcp-wKnQ61BZzQAAAAAAh-jt","-pk6w5puGcp-wKnQ61BZzQAAAAAAVUwE","-pk6w5puGcp-wKnQ61BZzQAAAAAAVATI","-pk6w5puGcp-wKnQ61BZzQAAAAAASsLk","-pk6w5puGcp-wKnQ61BZzQAAAAAASHZk","-pk6w5puGcp-wKnQ61BZzQAAAAAASJlH","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEH6","piWSMQrh4r040D0BPNaJvwAAAAAAAD_e","piWSMQrh4r040D0BPNaJvwAAAAAAFX1-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"JVvUxIunvr6V68Rt99rK9w":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19045737,19044484,19054298,18859716,18879913,10485923,16807,2741196,2827770,2817385,2759858,2758809,2558430,2672376],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8bE","v6HIzNa4K6G4nRP9032RIAAAAAABIBWp","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv1p","A2oiHVwisByxRn5RDT4LjAAAAAAAKhyy","A2oiHVwisByxRn5RDT4LjAAAAAAAKhiZ","A2oiHVwisByxRn5RDT4LjAAAAAAAJwne","A2oiHVwisByxRn5RDT4LjAAAAAAAKMb4"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"tagsGmBta7BnDHBzEbH9eQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927445,6732427,882422,8542429],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePaV","ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL","ew01Dk0sWZctP-VaEpavqQAAAAAADXb2","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"CjP83pplY09FGl9PBMeqCg":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895829,22487599,22488317,19128052,22462004,19128023,19127329,22526546,19673252,19587368,18920557,18789740,18799034,10485923,16743,2752800,2752044,2741274,6650246,6650090,7860129,6674998,6706857,2411027,2395208],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5YV","j8DVIOTu7Btj9lgFefJ84AAAAAABVyIv","j8DVIOTu7Btj9lgFefJ84AAAAAABVyT9","j8DVIOTu7Btj9lgFefJ84AAAAAABI970","j8DVIOTu7Btj9lgFefJ84AAAAAABVr40","j8DVIOTu7Btj9lgFefJ84AAAAAABI97X","j8DVIOTu7Btj9lgFefJ84AAAAAABI9wh","j8DVIOTu7Btj9lgFefJ84AAAAAABV7pS","j8DVIOTu7Btj9lgFefJ84AAAAAABLDCk","j8DVIOTu7Btj9lgFefJ84AAAAAABKuEo","j8DVIOTu7Btj9lgFefJ84AAAAAABILRt","j8DVIOTu7Btj9lgFefJ84AAAAAABHrVs","j8DVIOTu7Btj9lgFefJ84AAAAAABHtm6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjq","piWSMQrh4r040D0BPNaJvwAAAAAAd--h","piWSMQrh4r040D0BPNaJvwAAAAAAZdo2","piWSMQrh4r040D0BPNaJvwAAAAAAZlap","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIxI"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"SQ6jhz-Ee7WHXLMOHOsDcQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,6715099,4221812],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAZnbb","ew01Dk0sWZctP-VaEpavqQAAAAAAQGt0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"eM1ATYEKUIN4nyPylmr13A":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440021,7478164],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYaV","ew01Dk0sWZctP-VaEpavqQAAAAAAchuU"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"9vNu8RjYClbqhYYGUiWI7A":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,51380,55074,37132,20242,23612,47200,14250,1480561,1970211,1481652,1480953,2600004,1079669,52860,1480561,1970211,1481652,1480953,2600004,1079483,6166,60608,20250,65302,10604,14228,1479868,2600004,1079483,29728,14228,1479868,2600004,1069332,47952],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","DxQN3aM1Ddn1lUwovx75wQ","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0","U4Le8nh-beog_B7jq7uTIAAAAAAAANci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFw8","W8AFtEsepzrJ6AasHrCttwAAAAAAALhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAM58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","kSaNXrGzSS3BnDNNWezzMAAAAAAAABgW","ne8F__HPIVgxgycJADVSzAAAAAAAAOzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAE8a","O_h7elJSxPO7SiCsftYRZgAAAAAAAP8W","DxQN3aM1Ddn1lUwovx75wQAAAAAAACls","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAHQg","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEFEU","--q8cwZVXbHL2zOM_p3RlQAAAAAAALtQ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,1,1,3,3,3,1]},"CU-T9AvnxmWd1TTRjgV01Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7508830,6761766,2559050],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe","9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m","9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"hoJT-ObO7MDFTgt9UeFJfg":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2822585,3001783,2924437,3111967,3095700,156159,136664,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317318,469350,452199,518055,511351],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxG5","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3wf","-p9BlJh9JZMPPNjY_j92ngAAAAAALzyU","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhXY","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBnG","huWyXZbCBWCe2ZtK9BiokQAAAAAABylm","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB813"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"us5XzJaFA8Y8a8Jhq7VWzQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797926,6797556,2726254,449444],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0","ew01Dk0sWZctP-VaEpavqQAAAAAAKZlu","ew01Dk0sWZctP-VaEpavqQAAAAAABtuk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"tWPDa1sBMePW-YFiahrHBA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10489481,12583132,6878809,6871998,6871380,7366427,7371724,7390232,7379824,6863646,7218707,7217709,6862495,13713],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","5OhlekN4HU3KaqhG_GtinA"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J","9LzzIocepYcOjnUsLlgOjgAAAAAAwADc","9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ","9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-","9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU","9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb","9LzzIocepYcOjnUsLlgOjgAAAAAAcHvM","9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY","9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw","9LzzIocepYcOjnUsLlgOjgAAAAAAaLse","9LzzIocepYcOjnUsLlgOjgAAAAAAbiYT","9LzzIocepYcOjnUsLlgOjgAAAAAAbiIt","9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf","5OhlekN4HU3KaqhG_GtinAAAAAAAADWR"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"KKjaO47Ew4fmVCY-lBFkLg":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317297,1335062,1334886,452199,517552],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBmx","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF5m","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-Ww"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"zxyQebekMWvnWWEuWSzR9Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265873,31266293,31372635,4873273,4873930,4883062,4875761,4874468,8927681,8862916,8863227,8479623,4872825,5688954,8909549,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7925524,6772762,6770749,6770671,7937674,6744271,7917830,882422,8541549],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RRR","B8JRxL079xbhqQBqGvksAgAAAAAB3RX1","B8JRxL079xbhqQBqGvksAgAAAAAB3rVb","B8JRxL079xbhqQBqGvksAgAAAAAASlw5","B8JRxL079xbhqQBqGvksAgAAAAAASl7K","B8JRxL079xbhqQBqGvksAgAAAAAASoJ2","B8JRxL079xbhqQBqGvksAgAAAAAASmXx","B8JRxL079xbhqQBqGvksAgAAAAAASmDk","B8JRxL079xbhqQBqGvksAgAAAAAAiDnB","B8JRxL079xbhqQBqGvksAgAAAAAAhzzE","B8JRxL079xbhqQBqGvksAgAAAAAAhz37","B8JRxL079xbhqQBqGvksAgAAAAAAgWOH","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAh_Lt","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeO8U","A2oiHVwisByxRn5RDT4LjAAAAAAAZ1ga","A2oiHVwisByxRn5RDT4LjAAAAAAAZ1A9","A2oiHVwisByxRn5RDT4LjAAAAAAAZ0_v","A2oiHVwisByxRn5RDT4LjAAAAAAAeR6K","A2oiHVwisByxRn5RDT4LjAAAAAAAZujP","A2oiHVwisByxRn5RDT4LjAAAAAAAeNEG","A2oiHVwisByxRn5RDT4LjAAAAAAADXb2","A2oiHVwisByxRn5RDT4LjAAAAAAAglVt"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"UI-7Z494NKAWuv1FuNlxoQ":{"address_or_lines":[4652224,59049454,56939078,10401064,10401333,10401661,56939173,56937529,56937108,38310942,29802677,29803353,29746360,8752265,4268420,4265510,4264588,4297532,10488398,10493154,585663,12583132,6882905,21536,6881628,6877992,6877443,6876950,7370944,7369391,7367054,7370328,7370195,7369770,7552115,7547124,7496717,7491196,7486785,7507864,7393057,7394424,7384016,6867742,7222899,7221901,6866591,13650],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","R3YNZBiWt7Z3ZpFfTh6XyQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","R3YNZBiWt7Z3ZpFfTh6XyQ"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADhQXu","B8JRxL079xbhqQBqGvksAgAAAAADZNJG","B8JRxL079xbhqQBqGvksAgAAAAAAnrUo","B8JRxL079xbhqQBqGvksAgAAAAAAnrY1","B8JRxL079xbhqQBqGvksAgAAAAAAnrd9","B8JRxL079xbhqQBqGvksAgAAAAADZNKl","B8JRxL079xbhqQBqGvksAgAAAAADZMw5","B8JRxL079xbhqQBqGvksAgAAAAADZMqU","B8JRxL079xbhqQBqGvksAgAAAAACSJQe","B8JRxL079xbhqQBqGvksAgAAAAABxsC1","B8JRxL079xbhqQBqGvksAgAAAAABxsNZ","B8JRxL079xbhqQBqGvksAgAAAAABxeS4","B8JRxL079xbhqQBqGvksAgAAAAAAhYyJ","B8JRxL079xbhqQBqGvksAgAAAAAAQSGE","B8JRxL079xbhqQBqGvksAgAAAAAAQRYm","B8JRxL079xbhqQBqGvksAgAAAAAAQRKM","B8JRxL079xbhqQBqGvksAgAAAAAAQZM8","A2oiHVwisByxRn5RDT4LjAAAAAAAoApO","A2oiHVwisByxRn5RDT4LjAAAAAAAoBzi","A2oiHVwisByxRn5RDT4LjAAAAAAACO-_","A2oiHVwisByxRn5RDT4LjAAAAAAAwADc","A2oiHVwisByxRn5RDT4LjAAAAAAAaQZZ","R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAAFQg","A2oiHVwisByxRn5RDT4LjAAAAAAAaQFc","A2oiHVwisByxRn5RDT4LjAAAAAAAaPMo","A2oiHVwisByxRn5RDT4LjAAAAAAAaPED","A2oiHVwisByxRn5RDT4LjAAAAAAAaO8W","A2oiHVwisByxRn5RDT4LjAAAAAAAcHjA","A2oiHVwisByxRn5RDT4LjAAAAAAAcHKv","A2oiHVwisByxRn5RDT4LjAAAAAAAcGmO","A2oiHVwisByxRn5RDT4LjAAAAAAAcHZY","A2oiHVwisByxRn5RDT4LjAAAAAAAcHXT","A2oiHVwisByxRn5RDT4LjAAAAAAAcHQq","A2oiHVwisByxRn5RDT4LjAAAAAAAczxz","A2oiHVwisByxRn5RDT4LjAAAAAAAcyj0","A2oiHVwisByxRn5RDT4LjAAAAAAAcmQN","A2oiHVwisByxRn5RDT4LjAAAAAAAck58","A2oiHVwisByxRn5RDT4LjAAAAAAAcj1B","A2oiHVwisByxRn5RDT4LjAAAAAAAco-Y","A2oiHVwisByxRn5RDT4LjAAAAAAAcM8h","A2oiHVwisByxRn5RDT4LjAAAAAAAcNR4","A2oiHVwisByxRn5RDT4LjAAAAAAAcKvQ","A2oiHVwisByxRn5RDT4LjAAAAAAAaMse","A2oiHVwisByxRn5RDT4LjAAAAAAAbjZz","A2oiHVwisByxRn5RDT4LjAAAAAAAbjKN","A2oiHVwisByxRn5RDT4LjAAAAAAAaMaf","R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAADVS"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"6yHX0lcyWmly8MshBzd78Q":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,3132,30816,59306,1480561,1970211,1481652,1480953,2600004,1079483,36350,56142,27276,48820,6316,1479960,1494280,2600004,1079483,31058,15346,1479960,2600004,1079483,44156,54044,53948,63380,1479868,2600004,1079483,8496,63380,1479868,2600004,1056891,26970,28876,2143205,2040020],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","3FRCbvQLPuJyn2B-2wELGw","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAAw8","W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","EFJHOn-GACfHXgae-R1yDAAAAAAAAI3-","GdaBUD9IUEkKxIBryNqV2wAAAAAAANtO","QU8QLoFK6ojrywKrBFfTzAAAAAAAAGqM","V558DAsp4yi8bwa8eYwk5QAAAAAAAL60","tuTnMBfyc9UiPsI0QyvErAAAAAAAABis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAKx8","-9oyoP4Jj2iRkwEezqId-gAAAAAAANMc","3FRCbvQLPuJyn2B-2wELGwAAAAAAANK8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAACEw","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECB7","--q8cwZVXbHL2zOM_p3RlQAAAAAAAGla","yaTrLhUSIq2WitrTHLBy3QAAAAAAAHDM","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAILPl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHyDU"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3]},"uEL43HtanLRCO2rLB4ttzQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,64358,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,11986,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,51652,2573747,2594708,1091475,13186,2790352,1482889,1482415,2595076,1069851,33394,1493754,2595076,1049998,50014,45950,2995046,2994923,3072326,3072096,3066615,1917744],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8EY5iPD5-FtlXFBTyb6lkw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","dCCKy6JoX0PADOFic8hRNQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","7RLN3PNgotUSmdQVMRTSvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","43vJVfBcAahhLMzDSC-H0g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","RRFdsCrJw1U2erb6qtrrzQ","_zH-ed4x-42m0B4z2RmcdQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","dCCKy6JoX0PADOFic8hRNQAAAAAAAC7S","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","7RLN3PNgotUSmdQVMRTSvAAAAAAAAMnE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","43vJVfBcAahhLMzDSC-H0gAAAAAAADOC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFMb","ik6PIX946fW_erE7uBJlVQAAAAAAAIJy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsr6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAWO","RRFdsCrJw1U2erb6qtrrzQAAAAAAAMNe","_zH-ed4x-42m0B4z2RmcdQAAAAAAALN-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALbNm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALbLr","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsr3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUMw"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,1,1,3,3,3,3,3,3]},"mXgK2ekWZ4qH-uHB8QaLtA":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,824,116,12,8,54,12,46,22,1091612,1804498,665668,663668,1112453,1232178,833111,2265137,2264574,2258679],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","IlUL618nbeW5Kz4uyGZLrQ","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","7aaw2O1Vn7-6eR8XuUWQZQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4","IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu","7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAG4jS","G68hjsyagwq6LpWrMjDdngAAAAAACihE","G68hjsyagwq6LpWrMjDdngAAAAAACiB0","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEs0y","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInb3"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"1twYzjHR6hCfJqQLvJ81XA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,50892,43744,57354,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1075570,17430,40768,26744,7590,63980,23014,47110,19666,47110,34306,44426,44426,44426,44426,44426,44426,44426,44334,47110,46588,46966,1670488,3072326,3072096,3066777,1745028],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","O_h7elJSxPO7SiCsftYRZg","ZLTqiSLOmv4Ej_7d8yKLmw","qLiwuFhv6DIyQ0OgaSMXCg","ka2IKJhpWbD6PA3J3v624w","e8Lb_MV93AH-OkvHPPDitg","ka2IKJhpWbD6PA3J3v624w","1vivUE5hL65442lQ9a_ylg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","ka2IKJhpWbD6PA3J3v624w","fCsVLBj60GK9Hf8VtnMcgA","ka2IKJhpWbD6PA3J3v624w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAMbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGly","kSaNXrGzSS3BnDNNWezzMAAAAAAAAEQW","ne8F__HPIVgxgycJADVSzAAAAAAAAJ9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAAGh4","O_h7elJSxPO7SiCsftYRZgAAAAAAAB2m","ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAPns","qLiwuFhv6DIyQ0OgaSMXCgAAAAAAAFnm","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","e8Lb_MV93AH-OkvHPPDitgAAAAAAAEzS","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","1vivUE5hL65442lQ9a_ylgAAAAAAAIYC","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK0u","ka2IKJhpWbD6PA3J3v624wAAAAAAALgG","fCsVLBj60GK9Hf8VtnMcgAAAAAAAALX8","ka2IKJhpWbD6PA3J3v624wAAAAAAALd2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGX1Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsuZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGqCE"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3]},"f-LRF9Sfj675yc68DOXczw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,56302,2790352,1482889,1482415,2595076,1079144,25326,27384,368,1760,1481694,1828960,2573747,2594708,1091475,16910,2790352,1482889,1482415,2595076,1079144,25326,27384,368,1760,1481694,1828960,2573747,2594708,1073425,16424,24340,2572553,2928589,1108138,1105869,1310238,1245752,1200236,1192099,1183786,1104144,1103499,2268402,1775000,1761295,1048342],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","cfc92_adXFZraMPGbgbcDg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","WLefmNR3IpykzCX3WWNnMw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","IvJrzqPEgeoowZySdwFq3w","vkeP2ntYyoFN0A16x9eliw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","cfc92_adXFZraMPGbgbcDgAAAAAAANvu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","WLefmNR3IpykzCX3WWNnMwAAAAAAAEIO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","IvJrzqPEgeoowZySdwFq3wAAAAAAAEAo","vkeP2ntYyoFN0A16x9eliwAAAAAAAF8U","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0EJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALK_N","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEOiq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEN_N","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAE_4e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEwI4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAElBs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEjCj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEhAq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAENkQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAENaL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_8W"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"p24lyWOwFjGMsQaWybQUMA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,36384,21728,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959028,1099442],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MXHCWLuAJw7Gg6T7hdrPHA","ecHSwk0KAG7gFkiYdAgIZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAI4g","ecHSwk0KAG7gFkiYdAgIZwAAAAAAAFTg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeR0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEMay"],"type_ids":[3,3,3,3,3,3,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3]},"KHat1RLkyP8wPwwR1uD04A":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,40,38,174,104,68,80,38,174,104,68,60,38,174,104,68,382,38,174,104,68,24,38,174,104,68,28,38,174,104,68,0,1090933,1814182,788459,788130,1197048,1243240,1238413,1212345,1033898,429638],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","0cqvso24v07beLsmyC0nMw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","3WU6MO1xF7O0NmrHFj4y4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","x617yDiAG2Sqq3cLDkX4aA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZTmztUywGW_uHXPqWVr76w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZPAF8mJO2n0azNbxzkJ2rA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","0cqvso24v07beLsmyC0nMwAAAAAAAABQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","3WU6MO1xF7O0NmrHFj4y4AAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","x617yDiAG2Sqq3cLDkX4aAAAAAAAAAF-","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZTmztUywGW_uHXPqWVr76wAAAAAAAAAY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZPAF8mJO2n0azNbxzkJ2rAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvho","G68hjsyagwq6LpWrMjDdngAAAAAAEuWN","G68hjsyagwq6LpWrMjDdngAAAAAAEn-5","G68hjsyagwq6LpWrMjDdngAAAAAAD8aq","G68hjsyagwq6LpWrMjDdngAAAAAABo5G"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"B-OQjwP7KzSb4f6cXUL1bA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,3616,42208,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,50288,64358,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986405,1946637,1538878,2269465,2268402,1774938,1011120],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MXHCWLuAJw7Gg6T7hdrPHA","ecHSwk0KAG7gFkiYdAgIZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAA4g","ecHSwk0KAG7gFkiYdAgIZwAAAAAAAKTg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAMRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbQN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF3s-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIqEZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxVa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD22w"],"type_ids":[3,3,3,3,3,3,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"kOWftL0Ttias8Z1isZi9oA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,58710,61916,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,12482,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,49534,2790352,1482889,1482415,2595076,1097615,37614,39672,12656,17976,49494,2722496,3251876,3237020,1748920],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SOSrvCNmbstVFKAcqHNCvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAADDC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","SOSrvCNmbstVFKAcqHNCvAAAAAAAAMF-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEL-P","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKYrA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMZ6k","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWSc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGq-4"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3]},"JzGylmBPluUmIML9XnagKw":{"address_or_lines":[2599636,1079669,2228,5922,53516,36626,36806,45836,18932,13860,58864,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,56398,58456,31408,16708,2578675,2599636,1091600,36298,2795776,1483241,1482767,2600004,1074397,56398,58456,31408,16708,2578675,2599636,1091600,46582,2795776,1483241,1482767,2600004,1073803,56398,58456,31408,16492,49494,45794,2852079,2851771,2849353,2846190,2849353,2846190,2847233,2838792],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SD7uzoegJjRT3jYNpuQ5wQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAI_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAALMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAI3K","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SD7uzoegJjRT3jYNpuQ5wQAAAAAAALX2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAANxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY","J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3IB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK1EI"],"type_ids":[3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3]},"tTw0tfSnPtZhbcyzyVHHpg":{"address_or_lines":[4622976,4423302,48950246,48930003,48929418,48931768,15219528,15219797,15220198,48932134,15224283,15224488,15224631,15220795,15220538,48932900,48934534,48924362,21171091,15443915,15441240,6695879,6686586,6688471,15292865,6927608,7025423,9353786,9296758,9312446,9317924,5671585,9381613,9295438,6263620,6258992,6257863,6068365,6003908,5935528,5054445,4702860,4711258,10485923,16743,2752800,2752044,2741274,6650246,6650083,7384662,7382442,7451553,7447772,7441688,7327025,7328392,7317984,6802313,6799580,6799223,6797958],"file_ids":["-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","-SVIyCZG9IbFKK-fe2Wh4g","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-SVIyCZG9IbFKK-fe2Wh4gAAAAAARoqA","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAQ36G","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6uvm","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6pzT","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6pqK","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qO4","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6DtI","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6DxV","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6D3m","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qUm","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E3b","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E6o","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6E83","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6EA7","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6D86","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6qgk","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6q6G","-SVIyCZG9IbFKK-fe2Wh4gAAAAAC6obK","-SVIyCZG9IbFKK-fe2Wh4gAAAAABQwuT","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA66fL","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA651Y","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZivH","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZgd6","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAZg7X","-SVIyCZG9IbFKK-fe2Wh4gAAAAAA6VnB","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAabT4","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAazMP","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjro6","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjdt2","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjhi-","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAji4k","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAVoqh","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjybt","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAjdZO","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX5NE","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX4Ew","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAX3zH","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAXJiN","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAW5zE","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAWpGo","-SVIyCZG9IbFKK-fe2Wh4gAAAAAATR_t","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAR8KM","-SVIyCZG9IbFKK-fe2Wh4gAAAAAAR-Na","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjj","piWSMQrh4r040D0BPNaJvwAAAAAAcK5W","piWSMQrh4r040D0BPNaJvwAAAAAAcKWq","piWSMQrh4r040D0BPNaJvwAAAAAAcbOh","piWSMQrh4r040D0BPNaJvwAAAAAAcaTc","piWSMQrh4r040D0BPNaJvwAAAAAAcY0Y","piWSMQrh4r040D0BPNaJvwAAAAAAb80x","piWSMQrh4r040D0BPNaJvwAAAAAAb9KI","piWSMQrh4r040D0BPNaJvwAAAAAAb6ng","piWSMQrh4r040D0BPNaJvwAAAAAAZ8uJ","piWSMQrh4r040D0BPNaJvwAAAAAAZ8Dc","piWSMQrh4r040D0BPNaJvwAAAAAAZ793","piWSMQrh4r040D0BPNaJvwAAAAAAZ7qG"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"E_F-N51BcZ4iQ9oPaHFKXw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,400,38,174,104,68,20,38,174,104,68,88,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044780,2041460,1171829,2265239,2264574,2258463,1015963,2256180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","c-eM3dWacIPzBmA_7-OWBw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","w9AQfBE7-1YeE4mOMirPBg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAGQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","c-eM3dWacIPzBmA_7-OWBwAAAAAAAAAU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","w9AQfBE7-1YeE4mOMirPBgAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNs","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAD4Cb","G68hjsyagwq6LpWrMjDdngAAAAAAIm00"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"d04G8ZHV3kYQ0ekQBw1VYQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,62806,476,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17614,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,41518,2790352,1482889,1482415,2595076,1076587,25326,27384,368,1592,16726,55682,2846655,2846347,2843929,2840766,2843929,2840766,2843929,2840692,1912597,3072400],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uo8E5My6tupMEt-pfV-uhA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAETO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1h0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHS8V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuGQ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"I-DofAMUQgh7q14tBJcZlA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,30412,43744,6426,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1062336,60522,1844695,1847563,1481567,2595076,1079485,19388,48282,27404,1479608,1493928,2595076,1079485,63084,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,5750,41842,34364,63380,1479516,2595076,1079485,14544,63380,1479516,2595076,1056995,11370,55184,2188039,2032414,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABka","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAOxq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAEu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAALya","un9fLDZOLvDMO52ltZtuegAAAAAAAGsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAPZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAABZ2","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAADjQ","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECDj","--q8cwZVXbHL2zOM_p3RlQAAAAAAACxq","yaTrLhUSIq2WitrTHLBy3QAAAAAAANeQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIWMH","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHwMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3,3]},"tGGi0acvAmmxOR5DbuF3dg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,49488,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,20126,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,12078,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1079144,65228,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079144,28888,1480209,1827586,1940195,1986405,1946664,1775467,1749899,1745572,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","r1l-BTVp1g6dSvPPoOY_cg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAE6e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAC8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAP7M","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","r1l-BTVp1g6dSvPPoOY_cgAAAAAAAHDY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbQo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxdr","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGrOL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGqKk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"Ws9TqFMz-kHv_-7zrBFdKw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,188,38,174,104,68,60,38,174,104,68,98,38,174,104,68,8,38,174,104,68,36,38,174,104,14,32,166,1090933,19429,41240,50286],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","IcegEVkl4JzbMBhUeMqp0Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","tz0ps4QDYR1clO_q5ziJUQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M0gS5SrmklEEjlV4jbSIBA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","k5C4r96b77lEZ_fHFwCYkQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","tz0ps4QDYR1clO_q5ziJUQAAAAAAAABi","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M0gS5SrmklEEjlV4jbSIBAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","k5C4r96b77lEZ_fHFwCYkQAAAAAAAAAk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMRu"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"nBHRVpYV5wUL_UAb5ff6Zg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,33826,49772,35602,22316,60128,28682,1480209,1969795,1481300,1480601,2595076,1079144,51020,1480209,1969795,1481300,1480601,2595076,1062336,53402,1844695,1847563,1481567,2595076,1079485,35772,40874,43788,1479608,1493928,2595076,1079485,13932,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,1990,41842,34364,63380,1479516,2595076,1079485,8256,63380,1479516,2595076,1073749,4896,39178,32948,3149429,3144768,1903783,1765444,1761295,1048797],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","wXOyVgf5_nNg6CUH5kFBbg","zEgDK4qMawUAQZjg5YHyww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAFcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAOrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAHAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAMdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAANCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAJ-q","un9fLDZOLvDMO52ltZtuegAAAAAAAKsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAADZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAAAfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAACBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAABMg","wXOyVgf5_nNg6CUH5kFBbgAAAAAAAJkK","zEgDK4qMawUAQZjg5YHywwAAAAAAAIC0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMA51","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL_xA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHQyn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGvBE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEADd"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,1,3,3,3,3,3,3]},"vfw5EN0FEHQCAj0w-N2avQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,5462,8668,3444,60212,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,24902,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,21798,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,62098,2789627,1482889,1482415,2595076,1073425,9228,2567913,1848405,1837592,1848017,2712905,2221838,2208668,2039344],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","780bLUPADqfQ3x1T5lnVOg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","X0TUmWpd8saA6nnPGQi3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAACHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAAOs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAGFG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","780bLUPADqfQ3x1T5lnVOgAAAAAAAFUm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","X0TUmWpd8saA6nnPGQi3nQAAAAAAAPKS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","Npep8JfxWDWZ3roJSD7jPgAAAAAAACQM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDLR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKWVJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIecO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIbOc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHx4w"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3]},"lyeLQDjWsQDYEJbcY4aFJA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,51380,55074,37132,20242,15420,47200,6058,1480561,1970211,1481652,1480953,2600004,1079669,52860,1480561,1970211,1481652,1480953,2600004,1062448,62522,1845095,1847963,1481919,2600004,1079483,44204,61562,19788,1479960,1494280,2600004,1079483,22700,1479960,1494280,2600004,1079483,31058,15346,1479960,2600004,1079483,54374,42194,5116,30612,1479868,2600004,1079483,16608,30612,1479868,2600004,1074397,28580,3123760,766784,10485923,16807,2741468,2828042,2817657,2760130,2759130,4216293],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","-T5rZCijT5TDJjmoEi8Kxg","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","xLxcEbwnZ5oNrk99ZsxcSQ","Z_CHd3Zjsh2cWE2NSdbiNQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0","U4Le8nh-beog_B7jq7uTIAAAAAAAANci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S","grZNsSElR5ITq8H2yHCNSwAAAAAAADw8","W8AFtEsepzrJ6AasHrCttwAAAAAAALhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAM58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEDYw","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPQ6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCdn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDKb","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAKys","MYrgKQIxdDhr1gdpucfc-QAAAAAAAPB6","un9fLDZOLvDMO52ltZtuegAAAAAAAE1M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","tuTnMBfyc9UiPsI0QyvErAAAAAAAAFis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","rTFMSHhLRlj86vHPR06zoQAAAAAAANRm","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKTS","-T5rZCijT5TDJjmoEi8KxgAAAAAAABP8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEDg","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","--q8cwZVXbHL2zOM_p3RlQAAAAAAAG-k","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAL6ow","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7NA","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc","ew01Dk0sWZctP-VaEpavqQAAAAAAKycK","ew01Dk0sWZctP-VaEpavqQAAAAAAKv55","ew01Dk0sWZctP-VaEpavqQAAAAAAKh3C","ew01Dk0sWZctP-VaEpavqQAAAAAAKhna","ew01Dk0sWZctP-VaEpavqQAAAAAAQFXl"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,4,4,4,4,4,4,4,4]},"cqzgaW0F-6gZ8uHz_Pf3hQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,188,38,174,104,68,60,38,174,104,68,86,38,174,104,68,4,38,174,104,68,0,38,174,104,68,0,714,34,1115045,1179023,833111,2265137,2264574,2261229,1175338],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","IcegEVkl4JzbMBhUeMqp0Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","tz0ps4QDYR1clO_q5ziJUQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","O2RGJIowquMzuET0HYQ6aQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","Ht79I_xqXv3bOgaClTNQ4w","T8-enlAkCZXqinPHW4B8sw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","tz0ps4QDYR1clO_q5ziJUQAAAAAAAABW","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","O2RGJIowquMzuET0HYQ6aQAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","Ht79I_xqXv3bOgaClTNQ4wAAAAAAAALK","T8-enlAkCZXqinPHW4B8swAAAAAAAAAi","G68hjsyagwq6LpWrMjDdngAAAAAAEQOl","G68hjsyagwq6LpWrMjDdngAAAAAAEf2P","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAIoDt","G68hjsyagwq6LpWrMjDdngAAAAAAEe8q"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3]},"b89Eo7vMfG4HsPSBVvjiKQ":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,31334,49372,51700,46628,9712,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1091600,32150,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1091600,7938,2795051,1483241,1482767,2600004,1079483,28112,42150,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,12612,2578675,2599636,1079669,40672,1482046,1829360,2586325,1480953,1480561,1940968,1986911,1983192],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","3HhVgGD2yvuFLpoZq7RfKw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fDiQPd_MeGeyY9ZBOSU1Gg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAHpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAMDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAMn0","xwuAPHgc12-8PZB3i-320gAAAAAAALYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAH2W","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAB8C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAG3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","fDiQPd_MeGeyY9ZBOSU1GgAAAAAAAJ7g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkLY"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3]},"5_-zAnLDYAi4FySmVgS6iw":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,61666,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,9122,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,8610,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,11838,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,61238,1481694,1828960,2581297,2595076,1072525,49410,1646337,3072295,1865241,10489950,422647],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","b-3iFnlA7BmzAxDEzxShdA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8jcOoolAg5RmmHop7NqzWQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2LABj1asXFICsosP2OrbVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N1ZmsCOKFJHNThnHfFYo6Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAAPDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAACOi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","b-3iFnlA7BmzAxDEzxShdAAAAAAAACGi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8jcOoolAg5RmmHop7NqzWQAAAAAAAC4-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","2LABj1asXFICsosP2OrbVQAAAAAAAO82","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF2N","N1ZmsCOKFJHNThnHfFYo6QAAAAAAAMEC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGR8B","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnL3"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,4,4]},"zOI_cRK31hVrh4Typ0-Fxg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,16720,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,60990,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,44846,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,40354,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,48884,1481694,1828960,2581397,1480601,1480209,1940568,1986405,1948474,1768216,1756070,1865241,10490014,423063,2283967,2281647,2098628,2098378,8541549],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-gDCCFjiBc58_iqAxti3Kw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAO4-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAJ2i","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","-gDCCFjiBc58_iqAxti3KwAAAAAAAL70","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk9l","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHbs6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGvsY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGsum","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAItCv","A2oiHVwisByxRn5RDT4LjAAAAAAAIAXE","A2oiHVwisByxRn5RDT4LjAAAAAAAIATK","A2oiHVwisByxRn5RDT4LjAAAAAAAglVt"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"4U9ayDnwvWmqJPhn_AOKew":{"address_or_lines":[38782,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,50350,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,10266,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,31478,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,4998,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959065,1765336,1761295,1048381],"file_ids":["GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","d4jl580PLMUwu5s3I4wcXg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","tKago5vqLnwIkezk_wTBpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rpq4cV1KPyFZcnKfWjKdZw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uFElJcsK9my-kA6ZYzT1uw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["GP7h96O0_ppGVtc-UpQQIQAAAAAAAJd-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","d4jl580PLMUwu5s3I4wcXgAAAAAAAMSu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","tKago5vqLnwIkezk_wTBpQAAAAAAACga","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","rpq4cV1KPyFZcnKfWjKdZwAAAAAAAHr2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uFElJcsK9my-kA6ZYzT1uwAAAAAAABOG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_89"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3]},"Jt6CexOHLEwUl4IeTgASBQ":{"address_or_lines":[2795051,1483241,1482767,2600004,1079483,64976,13478,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,57670,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,51706,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1091600,59680,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,16708,2578675,2599636,1079669,0,1482046,1829360,2586325,1481195,1480561,1940968,1917658,1481652,1480953,2600004,1079483,41394,1480124,1827986,1940595,1986911,1983184],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yp8MidCGMe4czbl-NigsYQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2noK4QoWxdzASRHkjOFwVA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yO-OCNRiISNdCb_iVi4E_w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","mBpjyQvq6ftE7Wm1BUpcFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAP3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAADSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yp8MidCGMe4czbl-NigsYQAAAAAAAOFG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2noK4QoWxdzASRHkjOFwVAAAAAAAAMn6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yO-OCNRiISNdCb_iVi4E_wAAAAAAAOkg","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpnr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAKGy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpW8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkLQ"],"type_ids":[3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3]},"8Rif7kuKG2cfhEYF2fJXmA":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,18066,2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,53890,2789627,1482889,1482415,2595076,1073425,41996,2567913,1848405,1837592,1847724,1483518,1482415,2595076,1079144,6526,35438,63996,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,45806,47864,20848,34524,2573747,2594708,1091475,48638,2790352,1482889,1482415,2595076,1079485,45806,47864,20848,32520,56166,1479516,1828960,2573747,2594708,1091475,0,2789548,1848405,1837592,1848026,1002720],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","bcwppGWOjTWw86zVNJE_Jg","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NiCfOMPggzUjx-usqlmxvg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","Vot4T3F5OpUj8rbXhgpMDg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEaS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAANKC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","Npep8JfxWDWZ3roJSD7jPgAAAAAAAKQM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDGs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","bcwppGWOjTWw86zVNJE_JgAAAAAAABl-","TBeSzkyqIwKL8td602zDjAAAAAAAAIpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAAPn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NiCfOMPggzUjx-usqlmxvgAAAAAAAL3-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAALLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw","Vot4T3F5OpUj8rbXhgpMDgAAAAAAAH8I","eV_m28NnKeeTL60KO2H3SAAAAAAAANtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpCs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDLa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD0zg"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3]},"cCjn5miDmyezrnBAe2jDww":{"address_or_lines":[1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,46938,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,15022,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,57678,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1091600,1870,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,61764,2578675,2599636,1079669,19486,1482046,1829360,2586325,1480953,1480561,1940968,1986928],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","5nuRo5ZVtij8bTLlri7QXA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","hi5mlwAHRj-Yl1GNV_UEZQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uSWUCgHgLPG4OFtPdUp0rg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","-BjW54fwMksXBor9R-YN9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","wuSmWRANn3Cl-syjEtxMoQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","5nuRo5ZVtij8bTLlri7QXAAAAAAAALda","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","hi5mlwAHRj-Yl1GNV_UEZQAAAAAAADqu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAOFO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","-BjW54fwMksXBor9R-YN9wAAAAAAAAdO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","wuSmWRANn3Cl-syjEtxMoQAAAAAAAEwe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFw"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"f8AFYpSQOpjCNbhqUuR3Rg":{"address_or_lines":[2578675,2599636,1091600,13686,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,50302,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,31414,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,43062,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,49476,2578675,2599636,1091600,38710,2795776,1483241,1482767,2600004,1079483,31822,33880,6648,14264,54464,42150,1479868,1829983,2783616,2800188,3063028,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,37650],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rEbhXoMLMee0rf6bwU9RPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","pv4wAezdMMO0SVuGgaEMTgAAAAAAADV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAMR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAHq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAKg2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","rEbhXoMLMee0rf6bwU9RPwAAAAAAAJc2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABn4","0S3htaCNkzxOYeavDR1GTQAAAAAAADe4","rBzW547V0L_mH4nnWK1FUQAAAAAAANTA","eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKnmA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKro8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALrz0","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJMS"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"dGMvgpGXk-ajX6PRi92qdg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,17442,33388,19218,62806,476,52596,11060,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,16746,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,23102,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,0,2789627,1482889,1482415,2595076,1079485,13424,27494,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1592,33110,55262,3227220,1488310,1480209,1940568,3236384],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","z1-LQiSwGmfJHZm7Q223fQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAM10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAEFq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","z1-LQiSwGmfJHZm7Q223fQAAAAAAAFo-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANfe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMT5U","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFrW2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWIg"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3]},"OxrG9ZVAzX9GwGtxUtIQNg":{"address_or_lines":[51762,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,64822,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,45750,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,49476,2578675,2599636,1091600,58410,2795776,1483241,1482767,2600004,1073803,40014,42072,15024,49260,33110,13026,2852079,2851771,2849353,2846190,2849353,2846190,2849408,2846190,2848321,2268450,1775400,1761695,1048471],"file_ids":["xDXQtI2vA5YySwpx7QFiwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fSQ747oLNh0c0zFQjsVRWg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","yp8MidCGMe4czbl-NigsYQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2noK4QoWxdzASRHkjOFwVA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xDXQtI2vA5YySwpx7QFiwAAAAAAAAMoy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fSQ747oLNh0c0zFQjsVRWgAAAAAAAP02","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","yp8MidCGMe4czbl-NigsYQAAAAAAALK2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2noK4QoWxdzASRHkjOFwVAAAAAAAAOQq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3qA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3ZB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIp0i","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGxco","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGuGf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAD_-X"],"type_ids":[1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3]},"QoW8uF5K3OBNL2DXI66leA":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,44118,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,32266,2789627,1482889,1482415,2595076,1079485,54384,2918,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,0,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1079144,0,1481694,1828960,2581397,1480601,1480209,1940568,1986447,1982493,1959065,1765320],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Z-J8GEZK5aE8XNQ-3sO-Fg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","H-OlnUNurKAlPjkWfV0hTg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","Z-J8GEZK5aE8XNQ-3sO-FgAAAAAAAKxW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","H-OlnUNurKAlPjkWfV0hTgAAAAAAAH4K","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_I"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3]},"zV-93oQDbZK9zB7UMAcCmw":{"address_or_lines":[1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,38166,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,63374,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1091475,12690,2790352,1482889,1482415,2595076,1073749,41710,43768,16752,18140,2573747,2594708,1062336,11500,1844695,1837592,1847724,1483518,1482415,2595076,1079144,40398,15390,8700,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1079485,41710,43252,52070,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1072909,41710,43768,16752,18098,34934,1898256],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","pv4wAezdMMO0SVuGgaEMTg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","qns5vQ3LMi6QrIMOgD_TwQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J_Lkq1OzUHxWQhnTgF6FwA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","hrIwGgdEFsOBluJKOOs8Zg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","jhRfowFriqBKJWhZSTe7kg","B0e_Spx899MeGx2KSvzzow","v1UMuiFodNtdRCNi4iF0Rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","yzJdtc2TQHpJ_IY5QdUQKA","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","pv4wAezdMMO0SVuGgaEMTgAAAAAAAJUW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAPeO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAADGS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","hrIwGgdEFsOBluJKOOs8ZgAAAAAAACzs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHAoY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDGs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","jhRfowFriqBKJWhZSTe7kgAAAAAAAJ3O","B0e_Spx899MeGx2KSvzzowAAAAAAADwe","v1UMuiFodNtdRCNi4iF0RgAAAAAAACH8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAMtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF8N","ik6PIX946fW_erE7uBJlVQAAAAAAAKLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEay","yzJdtc2TQHpJ_IY5QdUQKAAAAAAAAIh2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHPcQ"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,3]},"9CQVJEfCfL1rSnUaxlAfqg":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,2830,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,16862,2789627,1482889,1482415,2595076,1079485,9328,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1079144,7050,1481694,1828960,2581297,2595076,1079144,21502,39750,29852,29250,6740,37336,26240,24712,1480209,1940568,1934986,1933934,3072096,3066615,1918105,1787434,3064390],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","q_M8ZB6aihtZKYZfHGkluQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MAFaasFcVIeoQsejXrnp0w","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","zpgqltXEgKujOhJUj-jAhg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAAEHe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","q_M8ZB6aihtZKYZfHGkluQAAAAAAABuK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","MAFaasFcVIeoQsejXrnp0wAAAAAAAFP-","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAGaA","zpgqltXEgKujOhJUj-jAhgAAAAAAAGCI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHYaK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHYJu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuBg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsr3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG0Yq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALsJG"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"mGGvLNOYB74ofk9FRrMxxQ":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,17196,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,38014,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,49476,2578675,2599636,1091600,62622,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1073803,35918,37976,10928,49260,33110,13026,2852079,2851771,2849353,2846190,2849443,2846638,1439925,1865540],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ihsoi5zicXHpPrWRA9bTnA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","HbU9j_4D3UaJfjASj-JljA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","awUBhCYYZvWyN4rrVw-u5A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","ihsoi5zicXHpPrWRA9bTnAAAAAAAAEMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","HbU9j_4D3UaJfjASj-JljAAAAAAAAJR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","awUBhCYYZvWyN4rrVw-u5AAAAAAAAPSe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3qj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHdE"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3]},"pnLCuJVNeqGwwFeJQIrkPw":{"address_or_lines":[2795776,1483241,1482767,2600004,1079483,52302,53844,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079483,52302,53844,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1091600,63066,2795051,1483241,1482767,2600004,1079483,48592,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1091600,62622,2795051,1483241,1482767,2600004,1079483,48592,62630,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,24900,2578675,2599636,1079669,27496,1482046,1829360,2586325,1480953,1480561,1940968,1986911,1982943],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","akZOzI9XwsEixvkTDGeDPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","d1LNRHMzWQ5PvB10hYiN3g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PmkUsVBZlaSEgaFwCOKZlg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","akZOzI9XwsEixvkTDGeDPwAAAAAAAPZa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","d1LNRHMzWQ5PvB10hYiN3gAAAAAAAPSe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","PmkUsVBZlaSEgaFwCOKZlgAAAAAAAGto","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlFf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHkHf"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3]},"R77Zz6fBvENVXyt4GVb9dQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,94,6,108,36,24,4,28,693765,935741],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","4xH83ZXxs_KV95Ur8Z59WQ","PWlQ4X4jsNu5q7FFJqlo_Q","LSxiso_u1cO_pWDBw25Egg","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAABe","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAk","4xH83ZXxs_KV95Ur8Z59WQAAAAAAAAAY","PWlQ4X4jsNu5q7FFJqlo_QAAAAAAAAAE","LSxiso_u1cO_pWDBw25EggAAAAAAAAAc","G68hjsyagwq6LpWrMjDdngAAAAAACpYF","G68hjsyagwq6LpWrMjDdngAAAAAADkc9"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"tgL-t2GJJjItpLjnwjc4zQ":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,40902,49932,35316,46628,9712,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,40322,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,6862,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20804,2578675,2599636,1091600,45714,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,20588,33110,49802,19187,41240,51007],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","f3fxdcTCg7rbloZ6VtA0_Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAJ_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAAMMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAIn0","xwuAPHgc12-8PZB3i-320gAAAAAAALYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAJ2C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAABrO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","f3fxdcTCg7rbloZ6VtA0_QAAAAAAALKS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMc_"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"XNCSlgkv_bOXDIYn6zwekw":{"address_or_lines":[2578675,2599636,1091600,10822,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1091600,40982,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1091600,6678,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,45380,2578675,2599636,1074067,39072,35338,13252,2577481,2934013,1108250,1105981,1310350,1245864,1200348,1190613,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165561,1146206,1245475,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165783,1162744,1226823,1225457,1224431,1198830,1177316,1176308,1173405,1172510,1172373,1102592],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uU7rISh8R_xr6YYB3RgLuA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","vQQdLrWHLywJs9twt3EH2Q","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PUIH740KQXWx70DXM4ZvgQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","dsOcslker2-lnNTIC5yERA","zUlsQG278t98_u2KV_JLSQ","vkeP2ntYyoFN0A16x9eliw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uU7rISh8R_xr6YYB3RgLuAAAAAAAACpG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","vQQdLrWHLywJs9twt3EH2QAAAAAAAKAW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","PUIH740KQXWx70DXM4ZvgQAAAAAAABoW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGOT","dsOcslker2-lnNTIC5yERAAAAAAAAJig","zUlsQG278t98_u2KV_JLSQAAAAAAAIoK","vkeP2ntYyoFN0A16x9eliwAAAAAAADPE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1RJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALMT9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOA9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAE_6O","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwKo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAElDc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEirV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEX1e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwEj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcnX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEb34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErhH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErLx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEq7v","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeQe","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeOV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAENMA"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"jPN_jNGPJguImYjakYlBcA":{"address_or_lines":[19534,21592,60080,53572,2578675,2599636,1091600,12394,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,53572,2578675,2599636,1091600,39546,2795776,1483241,1482767,2600004,1079669,19534,21418,26368,41208,8202,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,34238,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,53572,2578675,2599636,1091600,33554,2795776,1483241,1482767,2600004,1073803,19534,21592,60080,53356,33110,17122,2852079,2851771,2849353,2846190,2849353,2846190,2849353,2846190,2845695,2033924,2033070,1865524],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAADBq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAJp6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4","h0l-9tGi18mC40qpcJbyDwAAAAAAACAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAIW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAIMS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2v_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHwkE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHwWu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHc0"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"4K-SlZ4j8NjsVBpqyPj2dw":{"address_or_lines":[1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,6714,2790352,1482889,1482415,2595076,1079144,29422,31306,36256,31544,18122,5412,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,54286,19054,47612,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,60034,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,64446,2790352,1482889,1482415,2595076,1079485,29422,31480,4280,11896,52064,39782,1479516,1829583,2778192,2794764,3057572,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,37750],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zo4mnjDJ1PlZka7jS9k2BA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAABo6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO","TBeSzkyqIwKL8td602zDjAAAAAAAAEpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J3wpF3Lf_vPkis4aNGKFbwAAAAAAAOqC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPu-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABC4","0S3htaCNkzxOYeavDR1GTQAAAAAAAC54","rBzW547V0L_mH4nnWK1FUQAAAAAAAMtg","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKmRQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKqUM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALqek","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJN2"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"W8IRlEZMfFJdYSgUQXDnMg":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,72,38,174,104,68,88,38,174,104,68,124,38,38,10,38,174,104,68,72,38,174,104,68,120,38,174,104,68,276,6,108,20,50,50,2970,50,2970,50,1360,24,788130,1197115,1222867,1212996,1212720],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qkYSh95E1urNTie_gKbr7w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","V8ldXm9NGXsJ182jEHEsUw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xVaa0cBWNcFeS-8zFezQgA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","UBINlIxj95Sa_x2_k5IddA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gRRk0W_9P4SGZLXFJ5KU8Q","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","cbxfeE2AkqKne6oKUxdB6g","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","iLW1ehST1pGQ3S8RoqM9Qg","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qkYSh95E1urNTie_gKbr7wAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAEU","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU","cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAVQ","iLW1ehST1pGQ3S8RoqM9QgAAAAAAAAAY","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAEqjT","G68hjsyagwq6LpWrMjDdngAAAAAAEoJE","G68hjsyagwq6LpWrMjDdngAAAAAAEoEw"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3]},"qytuJG9brvKSB9NJCHV9fQ":{"address_or_lines":[1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,45506,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,10626,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,53572,2578675,2599636,1091600,54118,2795776,1483241,1482767,2600004,1073803,23630,25688,64176,53356,16726,17122,2852079,2851771,2849353,2846190,2849353,2846190,2849762,2846638,1439925,1865641,10490014,423063,2284223,2281903,2098884,2098647,2097658],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","9NWoah56eYULAP_zGE9Puw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IKrIDHd5n47PpDQsRXxvvg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oG7568kMJujZxPJfj7VMjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","9NWoah56eYULAP_zGE9PuwAAAAAAALHC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","IKrIDHd5n47PpDQsRXxvvgAAAAAAACmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","oG7568kMJujZxPJfj7VMjAAAAAAAANNm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3vi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHep","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnSX","ew01Dk0sWZctP-VaEpavqQAAAAAAItq_","ew01Dk0sWZctP-VaEpavqQAAAAAAItGv","ew01Dk0sWZctP-VaEpavqQAAAAAAIAbE","ew01Dk0sWZctP-VaEpavqQAAAAAAIAXX","ew01Dk0sWZctP-VaEpavqQAAAAAAIAH6"],"type_ids":[3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"b116myovN7_XXb1AVLPH0g":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,21010,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,32886,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52386,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1097633,38284,39750,58524,57922,35412,472,59182,472,59182,472,59182,472,59182,472,55416,2915906,959782,10485923,16807,2315878,2315735,2315122,2305825,2551628],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAFIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAIB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAMyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEL-h","MsEmysGbXhMvgdbwhcZDCgAAAAAAAJWM","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAOSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAOJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAIpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAANh4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALH5C","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADqUm","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAI1Zm","A2oiHVwisByxRn5RDT4LjAAAAAAAI1XX","A2oiHVwisByxRn5RDT4LjAAAAAAAI1Ny","A2oiHVwisByxRn5RDT4LjAAAAAAAIy8h","A2oiHVwisByxRn5RDT4LjAAAAAAAJu9M"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,4,4,4,4,4,4,4]},"dNwgDmnCM1dIIF5EZm4ZgA":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,132,38,174,104,68,16,38,38,10,38,174,104,68,4,38,174,104,68,8,38,38,10,38,38,10,38,174,104,68,16,140,10,38,174,104,68,20,140,10,38,174,104,68,92,1090933,1814182,788459,788130,1197048,1243240,1238413,1212345,1033898,428752],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iwnHqwtnoHjA-XW01rxhpw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","53nvYhJfd2eJh-qREaeFBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zwRZ32H5_95LpRJHzXkqVA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","JJab8JrsPDK66yfOtCG3zQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1XUiDryPjyncBxkTlbVecg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OIy8IFqaTWz5UoN3FSH-wQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iwnHqwtnoHjA-XW01rxhpwAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","53nvYhJfd2eJh-qREaeFBQAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zwRZ32H5_95LpRJHzXkqVAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","JJab8JrsPDK66yfOtCG3zQAAAAAAAAAQ","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1XUiDryPjyncBxkTlbVecgAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OIy8IFqaTWz5UoN3FSH-wQAAAAAAAABc","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvho","G68hjsyagwq6LpWrMjDdngAAAAAAEuWN","G68hjsyagwq6LpWrMjDdngAAAAAAEn-5","G68hjsyagwq6LpWrMjDdngAAAAAAD8aq","G68hjsyagwq6LpWrMjDdngAAAAAABorQ"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"KEdXtWOmrUdpIHsjndtg_A":{"address_or_lines":[13038,15096,53616,1756,2573747,2594708,1091475,37514,2789627,1482889,1482415,2595076,1079485,9328,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,33834,2790352,1482889,1482415,2595076,1079144,13038,14922,19872,15160,1738,54564,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,37902,2670,31228,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,20530,2790352,1482889,1482415,2595076,1076587,13038,15096,53616,1592,16726,2434,2846655,2846347,2843929,2840766,2843929,2840766,2844278,2841214,1439429,1865241,10489950,423063,2283967,2281306,2510155,2414579,2398792,2385273,8471622],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAJKK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAIQq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAE2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAADs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAAbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAANUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAAJQO","TBeSzkyqIwKL8td602zDjAAAAAAAAApu","NH3zvSjFAfTSy6bEocpNyQAAAAAAAHn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","J3wpF3Lf_vPkis4aNGKFbwAAAAAAAFAy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAAmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Z2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a","A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L","A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz","A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI","A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5","A2oiHVwisByxRn5RDT4LjAAAAAAAgURG"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"V2K_ZjA6rol7KyINtV45_A":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,178,1090933,1814182,788459,788130,1197048,1243204,1201241,1245991,1245236,1171829,2265239,2264574,2258463,922614,2256180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAACy","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvhE","G68hjsyagwq6LpWrMjDdngAAAAAAElRZ","G68hjsyagwq6LpWrMjDdngAAAAAAEwMn","G68hjsyagwq6LpWrMjDdngAAAAAAEwA0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAADhP2","G68hjsyagwq6LpWrMjDdngAAAAAAIm00"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEVjp":{"file_name":[],"function_name":["__x64_sys_nanosleep"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEPyZ":{"file_name":[],"function_name":["get_timespec64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAASf5k":{"file_name":[],"function_name":["_copy_from_user"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEqRj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEpne":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKpz6":{"file_name":[],"function_name":["pipe_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAASkaN":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAShYf":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAL1uY":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAL1DP":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEFz":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv-O":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL10T":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgiGX":{"file_name":[],"function_name":["__mutex_lock.isra.7"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADkms":{"file_name":[],"function_name":["mutex_spin_on_owner"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEH6":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAD_e":{"file_name":[],"function_name":["syscall_slow_exit_work"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAFX1-":{"file_name":[],"function_name":["__audit_syscall_exit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv1p":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKhyy":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKhiZ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJwne":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKMb4":{"file_name":[],"function_name":["memcg_kmem_get_cache"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg38":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKePq":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePaV":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL":{"file_name":[],"function_name":["sock_def_readable"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgljd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgEg":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKf4s":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdQa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd--h":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZdo2":{"file_name":[],"function_name":["sock_alloc_send_pskb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlap":{"file_name":[],"function_name":["alloc_skb_with_frags"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJMoT":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIxI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnbb":{"file_name":[],"function_name":["sock_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQGt0":{"file_name":[],"function_name":["security_socket_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYaV":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAchuU":{"file_name":[],"function_name":["tcp_rcv_space_adjust"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAANci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAJEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAE8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAALhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAM58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABgW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAOzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAE8a":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAP8W":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"DxQN3aM1Ddn1lUwovx75wQAAAAAAACls":{"file_name":["client.py"],"function_name":["_load_service_endpoints_ruleset"],"function_offset":[1],"line_number":[193]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAHQg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAALtQ":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK":{"file_name":[],"function_name":["kmem_cache_alloc_node"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_connect"],"function_offset":[],"line_number":[345]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhXY":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_get_server_certificate"],"function_offset":[],"line_number":[1234]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[266]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_ex_d2i"],"function_offset":[],"line_number":[235]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBnG":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[380]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABylm":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/objects/obj_lib.c"],"function_name":["OBJ_dup"],"function_offset":[],"line_number":[83]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/mem.c"],"function_name":["CRYPTO_malloc"],"function_offset":[],"line_number":[346]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3068]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB813":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["_int_malloc"],"function_offset":[],"line_number":[3995]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKZlu":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABtuk":{"file_name":[],"function_name":["__virt_addr_valid"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J":{"file_name":[],"function_name":["do_softirq_own_stack"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-":{"file_name":[],"function_name":["process_backlog"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU":{"file_name":[],"function_name":["__netif_receive_skb_one_core"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb":{"file_name":[],"function_name":["ip_rcv"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcHvM":{"file_name":[],"function_name":["ip_forward"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLse":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbiYT":{"file_name":[],"function_name":["__qdisc_run"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbiIt":{"file_name":[],"function_name":["sch_direct_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"5OhlekN4HU3KaqhG_GtinAAAAAAAADWR":{"file_name":[],"function_name":["ena_start_xmit"],"function_offset":[],"line_number":[]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBmx":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[377]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_item_new"],"function_offset":[],"line_number":[76]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF5m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["asn1_item_ex_combine_new"],"function_offset":[],"line_number":[179]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-Ww":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3031]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeO8U":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ1ga":{"file_name":[],"function_name":["consume_skb"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ1A9":{"file_name":[],"function_name":["skb_release_all"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ0_v":{"file_name":[],"function_name":["skb_release_head_state"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeR6K":{"file_name":[],"function_name":["unix_destruct_scm"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZujP":{"file_name":[],"function_name":["sock_wfree"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeNEG":{"file_name":[],"function_name":["unix_write_space"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAglVt":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoApO":{"file_name":[],"function_name":["ret_from_intr"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBzi":{"file_name":[],"function_name":["do_IRQ"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACO-_":{"file_name":[],"function_name":["irq_exit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaQZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAAFQg":{"file_name":[],"function_name":["ena_io_poll"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaQFc":{"file_name":[],"function_name":["napi_complete_done"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaPMo":{"file_name":[],"function_name":["gro_normal_list.part.132"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaPED":{"file_name":[],"function_name":["netif_receive_skb_list_internal"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaO8W":{"file_name":[],"function_name":["__netif_receive_skb_list_core"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHjA":{"file_name":[],"function_name":["ip_list_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHKv":{"file_name":[],"function_name":["ip_sublist_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcGmO":{"file_name":[],"function_name":["ip_sublist_rcv_finish"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHZY":{"file_name":[],"function_name":["ip_local_deliver"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHXT":{"file_name":[],"function_name":["ip_local_deliver_finish"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcHQq":{"file_name":[],"function_name":["ip_protocol_deliver_rcu"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAczxz":{"file_name":[],"function_name":["tcp_v4_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcyj0":{"file_name":[],"function_name":["tcp_v4_do_rcv"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcmQN":{"file_name":[],"function_name":["tcp_rcv_state_process"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAck58":{"file_name":[],"function_name":["tcp_data_queue"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcj1B":{"file_name":[],"function_name":["tcp_fin"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAco-Y":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcM8h":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcNR4":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAcKvQ":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaMse":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAbjZz":{"file_name":[],"function_name":["__qdisc_run"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAbjKN":{"file_name":[],"function_name":["sch_direct_xmit"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAaMaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"R3YNZBiWt7Z3ZpFfTh6XyQAAAAAAADVS":{"file_name":[],"function_name":["ena_start_xmit"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAJci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAAw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAI3-":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAANtO":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAAGqM":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAL60":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAABis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAKx8":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAANMc":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"3FRCbvQLPuJyn2B-2wELGwAAAAAAANK8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[527]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAACEw":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAGla":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAHDM":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAC7S":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"7RLN3PNgotUSmdQVMRTSvAAAAAAAAMnE":{"file_name":["_bootstrap.py"],"function_name":["exec_module"],"function_offset":[5],"line_number":[982]},"43vJVfBcAahhLMzDSC-H0gAAAAAAADOC":{"file_name":["util.py"],"function_name":[""],"function_offset":[266],"line_number":[267]},"ik6PIX946fW_erE7uBJlVQAAAAAAAIJy":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"RRFdsCrJw1U2erb6qtrrzQAAAAAAAMNe":{"file_name":["_bootstrap.py"],"function_name":["__enter__"],"function_offset":[2],"line_number":[171]},"_zH-ed4x-42m0B4z2RmcdQAAAAAAALN-":{"file_name":["_bootstrap.py"],"function_name":["_get_module_lock"],"function_offset":[34],"line_number":[213]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4":{"file_name":["application.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0":{"file_name":["application.py"],"function_name":["Application"],"function_offset":[91],"line_number":[206]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[18],"line_number":[155]},"7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW":{"file_name":["typing.py"],"function_name":["_type_convert"],"function_offset":[4],"line_number":[132]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAMbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAOAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAEQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAJ9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAAGh4":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAB2m":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAPns":{"file_name":["client.py"],"function_name":["_get_client_args"],"function_offset":[15],"line_number":[295]},"qLiwuFhv6DIyQ0OgaSMXCgAAAAAAAFnm":{"file_name":["args.py"],"function_name":["get_client_args"],"function_offset":[72],"line_number":[118]},"ka2IKJhpWbD6PA3J3v624wAAAAAAALgG":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"e8Lb_MV93AH-OkvHPPDitgAAAAAAAEzS":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[6],"line_number":[344]},"1vivUE5hL65442lQ9a_ylgAAAAAAAIYC":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[8],"line_number":[486]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK2K":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAK0u":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fCsVLBj60GK9Hf8VtnMcgAAAAAAAALX8":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[5],"line_number":[35]},"ka2IKJhpWbD6PA3J3v624wAAAAAAALd2":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"cfc92_adXFZraMPGbgbcDgAAAAAAANvu":{"file_name":["pyi_rth_inspect.py"],"function_name":[""],"function_offset":[43],"line_number":[44]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbg":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"WLefmNR3IpykzCX3WWNnMwAAAAAAAEIO":{"file_name":["inspect.py"],"function_name":[""],"function_offset":[1707],"line_number":[1708]},"IvJrzqPEgeoowZySdwFq3wAAAAAAAEAo":{"file_name":["dis.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"vkeP2ntYyoFN0A16x9eliwAAAAAAAF8U":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAI4g":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":[""],"function_offset":[13],"line_number":[14]},"ecHSwk0KAG7gFkiYdAgIZwAAAAAAAFTg":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":["_pyi_rth_multiprocessing"],"function_offset":[94],"line_number":[107]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAANRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAAtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAo":{"file_name":["client.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"0cqvso24v07beLsmyC0nMwAAAAAAAABQ":{"file_name":["args.py"],"function_name":[""],"function_offset":[15],"line_number":[28]},"3WU6MO1xF7O0NmrHFj4y4AAAAAAAAAA8":{"file_name":["regions.py"],"function_name":[""],"function_offset":[12],"line_number":[25]},"x617yDiAG2Sqq3cLDkX4aAAAAAAAAAF-":{"file_name":["auth.py"],"function_name":[""],"function_offset":[660],"line_number":[674]},"ZTmztUywGW_uHXPqWVr76wAAAAAAAAAY":{"file_name":["auth.py"],"function_name":[""],"function_offset":[3],"line_number":[17]},"ZPAF8mJO2n0azNbxzkJ2rAAAAAAAAAAc":{"file_name":["auth.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"MXHCWLuAJw7Gg6T7hdrPHAAAAAAAAA4g":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":[""],"function_offset":[13],"line_number":[14]},"ecHSwk0KAG7gFkiYdAgIZwAAAAAAAKTg":{"file_name":["pyi_rth_multiprocessing.py"],"function_name":["_pyi_rth_multiprocessing"],"function_offset":[94],"line_number":[107]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAMRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAPtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAGs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAADDC":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"SOSrvCNmbstVFKAcqHNCvAAAAAAAAMF-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[89],"line_number":[90]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAI_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAALMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAANxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAORY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAEFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAI3K":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"SD7uzoegJjRT3jYNpuQ5wQAAAAAAALX2":{"file_name":["configure.py"],"function_name":[""],"function_offset":[56],"line_number":[57]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAEBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjj":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcK5W":{"file_name":[],"function_name":["tcp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcKWq":{"file_name":[],"function_name":["tcp_sendmsg_locked"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcbOh":{"file_name":[],"function_name":["__tcp_push_pending_frames"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcaTc":{"file_name":[],"function_name":["tcp_write_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcY0Y":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb80x":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb9KI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb6ng":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ8uJ":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ8Dc":{"file_name":[],"function_name":["validate_xmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ793":{"file_name":[],"function_name":["netif_skb_features"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ7qG":{"file_name":[],"function_name":["skb_network_protocol"],"function_offset":[],"line_number":[]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAGQ":{"file_name":["application.py"],"function_name":[""],"function_offset":[58],"line_number":[59]},"c-eM3dWacIPzBmA_7-OWBwAAAAAAAAAU":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"w9AQfBE7-1YeE4mOMirPBgAAAAAAAABY":{"file_name":["basic.py"],"function_name":[""],"function_offset":[13],"line_number":[15]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAPVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAAHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAETO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABka":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAOxq":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAEu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAALya":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAGsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAPZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAABZ2":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAIY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAADjQ":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAACxq":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAANeQ":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAE6e":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAC8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAP7M":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"r1l-BTVp1g6dSvPPoOY_cgAAAAAAAHDY":{"file_name":["typing.py"],"function_name":["__new__"],"function_offset":[55],"line_number":[2965]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAAC8":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[32],"line_number":[33]},"IcegEVkl4JzbMBhUeMqp0QAAAAAAAAA8":{"file_name":["auto_suggest.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"tz0ps4QDYR1clO_q5ziJUQAAAAAAAABi":{"file_name":["document.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"M0gS5SrmklEEjlV4jbSIBAAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"k5C4r96b77lEZ_fHFwCYkQAAAAAAAAAk":{"file_name":["app.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[16],"line_number":[302]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAOrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAHAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAMdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAANCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAJ-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAKsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAADZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAAfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAACBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAABMg":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"wXOyVgf5_nNg6CUH5kFBbgAAAAAAAJkK":{"file_name":["loaders.py"],"function_name":[""],"function_offset":[0],"line_number":[273]},"zEgDK4qMawUAQZjg5YHywwAAAAAAAIC0":{"file_name":["genericpath.py"],"function_name":["isdir"],"function_offset":[6],"line_number":[45]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAACHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAOs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAADLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAANFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAGFG":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAFUm":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"X0TUmWpd8saA6nnPGQi3nQAAAAAAAPKS":{"file_name":["addsteps.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAACQM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAPQ6":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAKys":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAPB6":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAE1M":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAAFis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"rTFMSHhLRlj86vHPR06zoQAAAAAAANRm":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKTS":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"-T5rZCijT5TDJjmoEi8KxgAAAAAAABP8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[533]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAEDg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAG-k":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKycK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKv55":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKh3C":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhna":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQFXl":{"file_name":[],"function_name":["security_file_alloc"],"function_offset":[],"line_number":[]},"tz0ps4QDYR1clO_q5ziJUQAAAAAAAABW":{"file_name":["document.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"O2RGJIowquMzuET0HYQ6aQAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"Ht79I_xqXv3bOgaClTNQ4wAAAAAAAALK":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[131],"line_number":[310]},"T8-enlAkCZXqinPHW4B8swAAAAAAAAAi":{"file_name":["enum.py"],"function_name":["__setattr__"],"function_offset":[11],"line_number":[473]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAMDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAMn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAALYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAH2W":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAB8C":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAG3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"fDiQPd_MeGeyY9ZBOSU1GgAAAAAAAJ7g":{"file_name":["hashes.py"],"function_name":[""],"function_offset":[245],"line_number":[246]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAAPDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAACOi":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"b-3iFnlA7BmzAxDEzxShdAAAAAAAACGi":{"file_name":["config.py"],"function_name":[""],"function_offset":[24],"line_number":[25]},"8jcOoolAg5RmmHop7NqzWQAAAAAAAC4-":{"file_name":["endpoint.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"2LABj1asXFICsosP2OrbVQAAAAAAAO82":{"file_name":["hooks.py"],"function_name":["httpchecksum"],"function_offset":[67],"line_number":[68]},"N1ZmsCOKFJHNThnHfFYo6QAAAAAAAMEC":{"file_name":["hooks.py"],"function_name":["HierarchicalEmitter"],"function_offset":[155],"line_number":[321]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe":{"file_name":[],"function_name":["page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnL3":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAO4-":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAJ2i":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"-gDCCFjiBc58_iqAxti3KwAAAAAAAL70":{"file_name":["argparse.py"],"function_name":[""],"function_offset":[817],"line_number":[818]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItCv":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIAXE":{"file_name":[],"function_name":["__lru_cache_add"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIATK":{"file_name":[],"function_name":["pagevec_lru_move_fn"],"function_offset":[],"line_number":[]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAJd-":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"d4jl580PLMUwu5s3I4wcXgAAAAAAAMSu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"tKago5vqLnwIkezk_wTBpQAAAAAAACga":{"file_name":["package.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"rpq4cV1KPyFZcnKfWjKdZwAAAAAAAHr2":{"file_name":["s3uploader.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"uFElJcsK9my-kA6ZYzT1uwAAAAAAABOG":{"file_name":["manager.py"],"function_name":[""],"function_offset":[46],"line_number":[47]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAP3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"yp8MidCGMe4czbl-NigsYQAAAAAAAOFG":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAAMn6":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"yO-OCNRiISNdCb_iVi4E_wAAAAAAAOkg":{"file_name":["shutil.py"],"function_name":[""],"function_offset":[2003],"line_number":[2004]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAKGy":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"ik6PIX946fW_erE7uBJlVQAAAAAAALLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAALr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAFFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEaS":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"OlTvyWQFXjOweJcs3kiGygAAAAAAANKC":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAKQM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"bcwppGWOjTWw86zVNJE_JgAAAAAAABl-":{"file_name":["six.py"],"function_name":["__get__"],"function_offset":[9],"line_number":[104]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAPn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"NiCfOMPggzUjx-usqlmxvgAAAAAAAL3-":{"file_name":["queue.py"],"function_name":[""],"function_offset":[62],"line_number":[63]},"Vot4T3F5OpUj8rbXhgpMDgAAAAAAAH8I":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[4],"line_number":[938]},"eV_m28NnKeeTL60KO2H3SAAAAAAAANtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"5nuRo5ZVtij8bTLlri7QXAAAAAAAALda":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[29],"line_number":[30]},"hi5mlwAHRj-Yl1GNV_UEZQAAAAAAADqu":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[30],"line_number":[31]},"uSWUCgHgLPG4OFtPdUp0rgAAAAAAAOFO":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"-BjW54fwMksXBor9R-YN9wAAAAAAAAdO":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[575],"line_number":[576]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAALSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wuSmWRANn3Cl-syjEtxMoQAAAAAAAEwe":{"file_name":["ec.py"],"function_name":[""],"function_offset":[339],"line_number":[340]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAADV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAMFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAMR-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAHq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAKg2":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"rEbhXoMLMee0rf6bwU9RPwAAAAAAAJc2":{"file_name":["hashlib.py"],"function_name":[""],"function_offset":[300],"line_number":[301]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABn4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAADe4":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAANTA":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["__dlopen"],"function_offset":[],"line_number":[87]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlerror.c"],"function_name":["_dlerror_run"],"function_offset":[],"line_number":[163]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-error-skeleton.c"],"function_name":["__GI__dl_catch_error"],"function_offset":[],"line_number":[198]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["dlopen_doit"],"function_offset":[],"line_number":[66]},"3nN3bymnZ8E42aLEtgglmAAAAAAAASmo":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["_dl_open"],"function_offset":[],"line_number":[649]},"3nN3bymnZ8E42aLEtgglmAAAAAAAATA-":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[424]},"3nN3bymnZ8E42aLEtgglmAAAAAAAALbA":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-reloc.c"],"function_name":["_dl_relocate_object"],"function_offset":[],"line_number":[160]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["_dl_lookup_symbol_x"],"function_offset":[],"line_number":[833]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJMS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x"],"function_offset":[],"line_number":[413]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAM10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAEFq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"z1-LQiSwGmfJHZm7Q223fQAAAAAAAFo-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[18],"line_number":[19]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANfe":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"xDXQtI2vA5YySwpx7QFiwAAAAAAAAMoy":{"file_name":["popen_forkserver.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fSQ747oLNh0c0zFQjsVRWgAAAAAAAP02":{"file_name":["forkserver.py"],"function_name":[""],"function_offset":[80],"line_number":[81]},"yp8MidCGMe4czbl-NigsYQAAAAAAALK2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAAOQq":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAMBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAADLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"Z-J8GEZK5aE8XNQ-3sO-FgAAAAAAAKxW":{"file_name":["adaptive.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"H-OlnUNurKAlPjkWfV0hTgAAAAAAAH4K":{"file_name":["standard.py"],"function_name":[""],"function_offset":[279],"line_number":[280]},"ik6PIX946fW_erE7uBJlVQAAAAAAAKLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAEFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAAJUW":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAPeO":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAADGS":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"hrIwGgdEFsOBluJKOOs8ZgAAAAAAACzs":{"file_name":["docstringparser.py"],"function_name":[""],"function_offset":[172],"line_number":[173]},"jhRfowFriqBKJWhZSTe7kgAAAAAAAJ3O":{"file_name":["six.py"],"function_name":["__get__"],"function_offset":[9],"line_number":[100]},"B0e_Spx899MeGx2KSvzzowAAAAAAADwe":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[115]},"v1UMuiFodNtdRCNi4iF0RgAAAAAAACH8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[83]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAKj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEay":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"yzJdtc2TQHpJ_IY5QdUQKAAAAAAAAIh2":{"file_name":["posixpath.py"],"function_name":["dirname"],"function_offset":[8],"line_number":[158]},"VuJFonCXevADcEDW6NVbKgAAAAAAAGsG":{"file_name":["devcommands.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAAEHe":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAACRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"q_M8ZB6aihtZKYZfHGkluQAAAAAAABuK":{"file_name":["core.py"],"function_name":[""],"function_offset":[331],"line_number":[332]},"MAFaasFcVIeoQsejXrnp0wAAAAAAAFP-":{"file_name":["core.py"],"function_name":["TemplateStep"],"function_offset":[40],"line_number":[240]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAGaA":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zpgqltXEgKujOhJUj-jAhgAAAAAAAGCI":{"file_name":["_parser.py"],"function_name":["__getitem__"],"function_offset":[3],"line_number":[165]},"ihsoi5zicXHpPrWRA9bTnAAAAAAAAEMs":{"file_name":["base_events.py"],"function_name":[""],"function_offset":[190],"line_number":[191]},"HbU9j_4D3UaJfjASj-JljAAAAAAAAJR-":{"file_name":["staggered.py"],"function_name":[""],"function_offset":[1],"line_number":[2]},"awUBhCYYZvWyN4rrVw-u5AAAAAAAAPSe":{"file_name":["locks.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAPSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAGFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"akZOzI9XwsEixvkTDGeDPwAAAAAAAPZa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAL3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"d1LNRHMzWQ5PvB10hYiN3gAAAAAAAPSe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"PmkUsVBZlaSEgaFwCOKZlgAAAAAAAGto":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[166],"line_number":[167]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAABe":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[28],"line_number":[33]},"VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG":{"file_name":["re.py"],"function_name":["compile"],"function_offset":[2],"line_number":[252]},"SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs":{"file_name":["re.py"],"function_name":["_compile"],"function_offset":[15],"line_number":[304]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAk":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[9],"line_number":[768]},"4xH83ZXxs_KV95Ur8Z59WQAAAAAAAAAY":{"file_name":["sre_compile.py"],"function_name":["_code"],"function_offset":[6],"line_number":[604]},"PWlQ4X4jsNu5q7FFJqlo_QAAAAAAAAAE":{"file_name":["sre_compile.py"],"function_name":["_compile_info"],"function_offset":[4],"line_number":[540]},"LSxiso_u1cO_pWDBw25EggAAAAAAAAAc":{"file_name":["sre_parse.py"],"function_name":["getwidth"],"function_offset":[5],"line_number":[179]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJ_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAMMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAIn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAJ2C":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAABrO":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"f3fxdcTCg7rbloZ6VtA0_QAAAAAAALKS":{"file_name":["hbase.py"],"function_name":[""],"function_offset":[96],"line_number":[97]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"uU7rISh8R_xr6YYB3RgLuAAAAAAAACpG":{"file_name":["s3.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAALFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"vQQdLrWHLywJs9twt3EH2QAAAAAAAKAW":{"file_name":["subcommands.py"],"function_name":[""],"function_offset":[833],"line_number":[834]},"PUIH740KQXWx70DXM4ZvgQAAAAAAABoW":{"file_name":["s3handler.py"],"function_name":[""],"function_offset":[273],"line_number":[274]},"dsOcslker2-lnNTIC5yERAAAAAAAAJig":{"file_name":["results.py"],"function_name":[""],"function_offset":[550],"line_number":[551]},"zUlsQG278t98_u2KV_JLSQAAAAAAAIoK":{"file_name":["results.py"],"function_name":["_create_new_result_cls"],"function_offset":[10],"line_number":[48]},"vkeP2ntYyoFN0A16x9eliwAAAAAAADPE":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAANFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAADBq":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAJp6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAACAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAIMS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAANBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAELi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAABo6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAAOqC":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPu-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[780],"line_number":[781]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABC4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAAC54":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAAMtg":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJN2":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x"],"function_offset":[],"line_number":[420]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"qkYSh95E1urNTie_gKbr7wAAAAAAAABY":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8":{"file_name":["connection.py"],"function_name":[""],"function_offset":[14],"line_number":[15]},"xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAEU":{"file_name":["url.py"],"function_name":[""],"function_offset":[61],"line_number":[62]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[5],"line_number":[764]},"cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["parse"],"function_offset":[11],"line_number":[948]},"aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["_parse_sub"],"function_offset":[8],"line_number":[443]},"MebnOxK5WOhP29sl19JefwAAAAAAAAua":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[341],"line_number":[834]},"MebnOxK5WOhP29sl19JefwAAAAAAAAVQ":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[171],"line_number":[664]},"iLW1ehST1pGQ3S8RoqM9QgAAAAAAAAAY":{"file_name":["sre_parse.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[166]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"9NWoah56eYULAP_zGE9PuwAAAAAAALHC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[101],"line_number":[102]},"IKrIDHd5n47PpDQsRXxvvgAAAAAAACmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[81],"line_number":[82]},"oG7568kMJujZxPJfj7VMjAAAAAAAANNm":{"file_name":["frontend.py"],"function_name":[""],"function_offset":[390],"line_number":[391]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAItq_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAItGv":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAbE":{"file_name":[],"function_name":["__lru_cache_add"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAXX":{"file_name":[],"function_name":["pagevec_lru_move_fn"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIAH6":{"file_name":[],"function_name":["release_pages"],"function_offset":[],"line_number":[]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAFIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAIB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAMyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAJWM":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAOSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAOJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAIpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAAHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAOcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAANh4":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1Zm":{"file_name":[],"function_name":["__x64_sys_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1XX":{"file_name":[],"function_name":["__vm_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAI1Ny":{"file_name":[],"function_name":["__do_munmap"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIy8h":{"file_name":[],"function_name":["remove_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJu9M":{"file_name":[],"function_name":["kmem_cache_free"],"function_offset":[],"line_number":[]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACE":{"file_name":["compat.py"],"function_name":[""],"function_offset":[15],"line_number":[29]},"iwnHqwtnoHjA-XW01rxhpwAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[16]},"53nvYhJfd2eJh-qREaeFBQAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[7]},"zwRZ32H5_95LpRJHzXkqVAAAAAAAAAAI":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[7],"line_number":[10]},"JJab8JrsPDK66yfOtCG3zQAAAAAAAAAQ":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"1XUiDryPjyncBxkTlbVecgAAAAAAAAAU":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[9],"line_number":[10]},"OIy8IFqaTWz5UoN3FSH-wQAAAAAAAABc":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[37],"line_number":[41]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAJKK":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAIQq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAE2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAADs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAAbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAANUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAJQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAApu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAHn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAAFAy":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAAmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5":{"file_name":[],"function_name":["prep_new_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgURG":{"file_name":[],"function_name":["clear_page_erms"],"function_offset":[],"line_number":[]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAACy":{"file_name":["errors.py"],"function_name":[""],"function_offset":[45],"line_number":[50]}},"executables":{"G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","B8JRxL079xbhqQBqGvksAg":"kubelet","6kzBY4yj-1Fh1NCTZA3z0w":"aws-k8s-agent","j8DVIOTu7Btj9lgFefJ84A":"dockerd","B56YkhsK1JwqD-8F8sjS3A":"prometheus","v6HIzNa4K6G4nRP9032RIA":"dockerd","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","gNW12BepH17pXwK-ZuYt3w":"node_exporter","piWSMQrh4r040D0BPNaJvw":"vmlinux","kajOqZqz7V1y0BdYQLFQrw":"containerd-shim-runc-v2","A2oiHVwisByxRn5RDT4LjA":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","QvG8QEGAld88D676NL_Y2Q":"filebeat","6auiCMWq5cA-hAbqSYvdQQ":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","JsObMPhfT_zO2Q_B1cPLxA":"coredns","SbPwzb_Kog2bWn8uc7xhDQ":"aws","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","9LzzIocepYcOjnUsLlgOjg":"vmlinux","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","9HZ7GQCC6G9fZlRD7aGzXQ":"libssl.so.1.0.2k","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k","5OhlekN4HU3KaqhG_GtinA":"ena","R3YNZBiWt7Z3ZpFfTh6XyQ":"ena","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","-SVIyCZG9IbFKK-fe2Wh4g":"cluster-autoscaler","EX9l-cE0x8X9W8uz4iKUfw":"zlib.cpython-39-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","PVZV2uq5ZRt-FFaczL10BA":"libdl-2.26.so","3nN3bymnZ8E42aLEtgglmA":"ld-2.26.so","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so"},"total_frames":172380,"sampling_rate":0.2} diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_604800s_625x.json b/x-pack/plugins/profiling/common/__fixtures__/stacktraces_604800s_625x.json deleted file mode 100644 index 75ad39e9298d..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_604800s_625x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"oxpVfjjIF44Ceg6SK1UUdQ":43,"JTDxAdxqnTYIS6qzFXvK3g":100,"5tZzmji29IcMEbLCg170Tw":294,"0CNUMdOdpmKJxWeUmvWvXg":1343,"9_06LL00QkYIeiFNCWu0XQ":1109,"OtKh8npcfHhiQ7ynFMPOeQ":622,"TCJ8_VmEK5hAZOYdmPHyug":487,"OCdksb_5DbnTD8RB0r1Hmw":460,"2Ov4wSepfExdnFvsJSSjog":411,"668oRSTLMVtOeHPjJ80fWg":574,"VmRA1Zd-R_saxzv9stOlrw":519,"u31aX9a6CI2OuomWQHSx1Q":614,"oHTQoPZFXrc9eFjCRWW_BA":570,"tIRMz0rwuOf8rRZlytIuAQ":481,"-s21TvA-EsTWbfCutQG83Q":528,"LuHRiiYB6iq-QXoGUFYVXA":457,"5oh0023XVeE3U9ZP60NzUA":505,"hecRkAhRG62NML7wI512zA":286,"P-5EQ3lfGgit0Oj6qTKYqw":210,"fRxnoZgNqB73ndCJkUzrxg":263,"iww2NcKTwMO4dUHXUrsfKA":297,"dP8WPiIXitz7dopr2cbyrg":302,"c84Ph1EEsEpt9KFMdSQvtA":307,"DkjcsUWzUMWlzGIG7vWPLA":251,"O7XAt57p5nvwpgeB2KrNbw":312,"Oam9nmQfwQpA_10YTKZCkg":255,"gM71DK9QAb25Em9dhlNNXA":231,"VoyVx3eKZvx3I7o9LV75WA":180,"6MfMhGSHuQ0CLUxktz5OVg":175,"9pWzAEbyffmwRrKvRecyaQ":174,"DK4Iffrk3v05Awun60ygow":152,"4r_hCJ268ciweOwgH0Qwzw":129,"VC42Hg55_L_IfaF_actjIw":104,"7l18-g5emVzljYbZzZJDRA":62,"PkHiro08_uzuUWpeantpNA":42,"9EcGjMrQwznPlnAdDi9Lxw":38,"tagsGmBta7BnDHBzEbH9eQ":27,"euPXE4-KNZJD0T6j_TMfYw":24,"cL14TWzNnz1qK2PUYdE9bg":20,"9wXZUZEeGMQm83C5yXCZ2g":15,"bz1cYNqu8MBH2xCXTMEiAg":16,"fCScXsJaisrZL_JXgS4qQg":33,"V-MDb_Yh073ps9Vw4ypmDQ":17,"wAujHiFN47_oNUI63d6EtA":26,"zMMsPlSW5HOq5bsuVRh3KA":6,"pLdowTKUS5KSwivHyl5AgA":10,"_ef-NJahpYK_FzFC-KdtYQ":11,"omG-i9KffSi3YT8q0rYOiw":3,"XiONbb-veQ1sAuFD6_Fv0A":12,"krdohOL0KiVMtm4q-6fmjg":8,"N2LqhupgLi4T_B9D7JaDDQ":6,"7TvODt8WtQ5KXTmYPsDI3A":5,"u1L6jqeUaTNx1a2aJ9yFwA":2,"8uzy4VW9n0Z8KokUdeadfg":2,"EeUwhr9vbcywMBkIYZRfCw":3,"x443zjuudYI-A7cRu2DIGg":3,"rrrvnakD3SpJqProBGqoCQ":3,"sDfHX0MKzztQSqC8kl_-sg":2,"WmwSnxyphedkasVyGbhNdg":3,"NU5so_CJJJwGJM_hiEcxgQ":1,"A9B6bwuKQl9pC0MIYqtAgg":1,"X86DUuQ7tHAxGBaWu4tZLg":4,"T3fWxJzHMwU-oUs7rgXCcg":2,"vq75CDVua5N-eDXnfyZYMA":2,"oKVObqTWF9QIjxgKf8UkTw":6,"DaDdc6eLo0hc-QxL2XQh5Q":3,"YRZbUV2DChD6dl3Y2xjF8g":1,"EnsO3_jc7LnLdUHQbwkxMg":1,"V2XOOBv96QfYXHIIY7_OLA":6,"FTJM3wsT8Kc-UaiIK2yDMQ":4,"ivbgd9hswtvZ7aTts7HESw":3,"yXsgvY1JyekwdCV5rJdspg":7,"_TjN4epIphuKUiHZJZdqxQ":3,"ZQdwkmvvmLjNzNpTA4PPhw":8,"ssC7MBcE9kfM3yTim7UrNQ":12,"-yH5iqJp4uVN6clNHuFusA":7,"SrSwvDbs2pmPg3SRfXJBCA":13,"n5nFiHsDS01AKuzFKvQXdA":4,"XbtNNAnLtuHwAR-P2ynwqA":4,"Rr1Z3cNxrq9AQiD8wZZ1dA":9,"gESQTq4qRn3wnW-FPfxOfA":7,"CSpdzACT53hVs5DyKY8X5A":5,"AlH3zgnqwh5sdMMzX8AXxg":6,"ysEqok7gFOl9eLMLBwFm1g":3,"7B48NKNivOFEka6-8dK3Qg":1,"OC533YmmMZSw8TjJz41YiQ":1,"X6-W250nbzzPy4NasjncWg":1,"gi6S4ODPtJ-ERYxlMd4WHA":2,"EGm59IOxpyqZq7sEwgZb1g":1,"y7cw8NxReMWOs4KtDlMCFA":1,"L1ZLG1mjktr2Zy0xiQnH0w":1},"stack_traces":{"oxpVfjjIF44Ceg6SK1UUdQ":{"address_or_lines":[2357],"file_ids":["edNJ10OjHiWc5nzuTQdvig"],"frame_ids":["edNJ10OjHiWc5nzuTQdvigAAAAAAAAk1"],"type_ids":[3]},"JTDxAdxqnTYIS6qzFXvK3g":{"address_or_lines":[4636840,4373888],"file_ids":["LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g"],"frame_ids":["LvhLWomlc0dSPYzQ8C620gAAAAAARsCo","LvhLWomlc0dSPYzQ8C620gAAAAAAQr2A"],"type_ids":[3,3]},"5tZzmji29IcMEbLCg170Tw":{"address_or_lines":[18425733,18110445,18122515],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGSeF","j8DVIOTu7Btj9lgFefJ84AAAAAABFFft","j8DVIOTu7Btj9lgFefJ84AAAAAABFIcT"],"type_ids":[3,3,3]},"0CNUMdOdpmKJxWeUmvWvXg":{"address_or_lines":[32434917,32101228,32115955,32118104],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6gzz","QvG8QEGAld88D676NL_Y2QAAAAAB6hVY"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"OtKh8npcfHhiQ7ynFMPOeQ":{"address_or_lines":[4643458,4477392,4476996,4475762,4469018,4457110],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtqC","B8JRxL079xbhqQBqGvksAgAAAAAARFHQ","B8JRxL079xbhqQBqGvksAgAAAAAARFBE","B8JRxL079xbhqQBqGvksAgAAAAAAREty","B8JRxL079xbhqQBqGvksAgAAAAAARDEa","B8JRxL079xbhqQBqGvksAgAAAAAARAKW"],"type_ids":[3,3,3,3,3,3]},"TCJ8_VmEK5hAZOYdmPHyug":{"address_or_lines":[4652224,11517676,25223155,25230084,11538500,11501274,4847689],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAAAr77s","wfA2BgwfDNXUWsxkJ083RwAAAAABgN_z","wfA2BgwfDNXUWsxkJ083RwAAAAABgPsE","wfA2BgwfDNXUWsxkJ083RwAAAAAAsBBE","wfA2BgwfDNXUWsxkJ083RwAAAAAAr37a","wfA2BgwfDNXUWsxkJ083RwAAAAAASfhJ"],"type_ids":[3,3,3,3,3,3,3]},"OCdksb_5DbnTD8RB0r1Hmw":{"address_or_lines":[18515232,25399653,25432667,25428452,25361060,18103588,18097915,18123257],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABg5Fl","v6HIzNa4K6G4nRP9032RIAAAAAABhBJb","v6HIzNa4K6G4nRP9032RIAAAAAABhAHk","v6HIzNa4K6G4nRP9032RIAAAAAABgvqk","v6HIzNa4K6G4nRP9032RIAAAAAABFD0k","v6HIzNa4K6G4nRP9032RIAAAAAABFCb7","v6HIzNa4K6G4nRP9032RIAAAAAABFIn5"],"type_ids":[3,3,3,3,3,3,3,3]},"2Ov4wSepfExdnFvsJSSjog":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504548,5043327],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQck","FWZ9q3TQKZZok58ua1HDsgAAAAAATPR_"],"type_ids":[3,3,3,3,3,3,3,3,3]},"668oRSTLMVtOeHPjJ80fWg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9506710,10521925,4547584],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQ-W","FWZ9q3TQKZZok58ua1HDsgAAAAAAoI1F","FWZ9q3TQKZZok58ua1HDsgAAAAAARWQA"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"VmRA1Zd-R_saxzv9stOlrw":{"address_or_lines":[4650848,9850853,9880398,9883181,9807044,9827268,9781937,9782483,9784009,9784300,9829781],"file_ids":["QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg"],"frame_ids":["QaIvzvU8UoclQMd_OMt-PgAAAAAARvdg","QaIvzvU8UoclQMd_OMt-PgAAAAAAlk_l","QaIvzvU8UoclQMd_OMt-PgAAAAAAlsNO","QaIvzvU8UoclQMd_OMt-PgAAAAAAls4t","QaIvzvU8UoclQMd_OMt-PgAAAAAAlaTE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlfPE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUKx","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUTT","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUrJ","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUvs","QaIvzvU8UoclQMd_OMt-PgAAAAAAlf2V"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"oHTQoPZFXrc9eFjCRWW_BA":{"address_or_lines":[4646312,4475111,4248744,4416245,4662882,10485923,16807,1222099,1219772,1208264,769619,768516,8542429],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAAREjn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQNSo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ2L1","FWZ9q3TQKZZok58ua1HDsgAAAAAARyZi","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEpy8","ew01Dk0sWZctP-VaEpavqQAAAAAAEm_I","ew01Dk0sWZctP-VaEpavqQAAAAAAC75T","ew01Dk0sWZctP-VaEpavqQAAAAAAC7oE","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,4,4,4,4,4,4,4,4]},"tIRMz0rwuOf8rRZlytIuAQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10734948,4245427,4255110,4288384],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo81k","FWZ9q3TQKZZok58ua1HDsgAAAAAAQMez","FWZ9q3TQKZZok58ua1HDsgAAAAAAQO2G","FWZ9q3TQKZZok58ua1HDsgAAAAAAQW-A"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"LuHRiiYB6iq-QXoGUFYVXA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41428636,40303236,22534565,19333914,19319593],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCac","v6HIzNa4K6G4nRP9032RIAAAAAACZvqE","v6HIzNa4K6G4nRP9032RIAAAAAABV9ml","v6HIzNa4K6G4nRP9032RIAAAAAABJwMa","v6HIzNa4K6G4nRP9032RIAAAAAABJssp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"5oh0023XVeE3U9ZP60NzUA":{"address_or_lines":[4610335,4610076,4612877,4490724,4492388,4499312,4241704,4392309,4610754,10485923,16807,1221667,1219340,1207832,769603,768500,8537181],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARlkf","kajOqZqz7V1y0BdYQLFQrwAAAAAARlgc","kajOqZqz7V1y0BdYQLFQrwAAAAAARmMN","kajOqZqz7V1y0BdYQLFQrwAAAAAARIXk","kajOqZqz7V1y0BdYQLFQrwAAAAAARIxk","kajOqZqz7V1y0BdYQLFQrwAAAAAARKdw","kajOqZqz7V1y0BdYQLFQrwAAAAAAQLko","kajOqZqz7V1y0BdYQLFQrwAAAAAAQwV1","kajOqZqz7V1y0BdYQLFQrwAAAAAARlrC","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAEqQj","9LzzIocepYcOjnUsLlgOjgAAAAAAEpsM","9LzzIocepYcOjnUsLlgOjgAAAAAAEm4Y","9LzzIocepYcOjnUsLlgOjgAAAAAAC75D","9LzzIocepYcOjnUsLlgOjgAAAAAAC7n0","9LzzIocepYcOjnUsLlgOjgAAAAAAgkRd"],"type_ids":[3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"P-5EQ3lfGgit0Oj6qTKYqw":{"address_or_lines":[43732576,69263145,69263545,54339630,54340167,54179273,54179969,54177426,50376971,50377819,50384113,50377819,43742470,43723999,43620502,43619092,43672236,43616946,43623742],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIN8p","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIOC5","MNBJ5seVz_ocW6tcr1HSmwAAAAADPSgu","MNBJ5seVz_ocW6tcr1HSmwAAAAADPSpH","MNBJ5seVz_ocW6tcr1HSmwAAAAADOrXJ","MNBJ5seVz_ocW6tcr1HSmwAAAAADOriB","MNBJ5seVz_ocW6tcr1HSmwAAAAADOq6S","MNBJ5seVz_ocW6tcr1HSmwAAAAADALEL","MNBJ5seVz_ocW6tcr1HSmwAAAAADALRb","MNBJ5seVz_ocW6tcr1HSmwAAAAADAMzx","MNBJ5seVz_ocW6tcr1HSmwAAAAADALRb","MNBJ5seVz_ocW6tcr1HSmwAAAAACm3UG","MNBJ5seVz_ocW6tcr1HSmwAAAAACmyzf","MNBJ5seVz_ocW6tcr1HSmwAAAAACmZiW","MNBJ5seVz_ocW6tcr1HSmwAAAAACmZMU","MNBJ5seVz_ocW6tcr1HSmwAAAAACmmKs","MNBJ5seVz_ocW6tcr1HSmwAAAAACmYqy","MNBJ5seVz_ocW6tcr1HSmwAAAAACmaU-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"fRxnoZgNqB73ndCJkUzrxg":{"address_or_lines":[4652224,22354871,22382638,22364302,56669071,58509234,58268669,58227812,58241853,31197476,7372432,7294909,7296733,7300250,7296676,7304324,7296733,7300250,7296901,7319678],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYLOP","-pk6w5puGcp-wKnQ61BZzQAAAAADfMey","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH6Q","-pk6w5puGcp-wKnQ61BZzQAAAAAAb0-9","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1bd","-pk6w5puGcp-wKnQ61BZzQAAAAAAb2Sa","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1ak","-pk6w5puGcp-wKnQ61BZzQAAAAAAb3SE","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1bd","-pk6w5puGcp-wKnQ61BZzQAAAAAAb2Sa","-pk6w5puGcp-wKnQ61BZzQAAAAAAb1eF","-pk6w5puGcp-wKnQ61BZzQAAAAAAb7B-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"iww2NcKTwMO4dUHXUrsfKA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528745,54499864,54500494,54477482,44043537,44060985,43329158,43326819],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQArp","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5oY","MNBJ5seVz_ocW6tcr1HSmwAAAAADP5yO","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA0R","MNBJ5seVz_ocW6tcr1HSmwAAAAACoFE5","MNBJ5seVz_ocW6tcr1HSmwAAAAAClSaG","MNBJ5seVz_ocW6tcr1HSmwAAAAAClR1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"dP8WPiIXitz7dopr2cbyrg":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709512,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16807,2741196,2827770,2817684,2805156,3383048,8438368],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEI","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7A6","B8JRxL079xbhqQBqGvksAgAAAAAASFtz","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k","A2oiHVwisByxRn5RDT4LjAAAAAAAM58I","A2oiHVwisByxRn5RDT4LjAAAAAAAgMJg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"c84Ph1EEsEpt9KFMdSQvtA":{"address_or_lines":[152249,135481,144741,190122,831754,827742,928935,925466,103752,102294,97206,439344,486674,922914,10485923,16807,2756288,2755416,2924693,3066448,4344,2925966,8437662],"file_ids":["w5zBqPf1_9mIVEf-Rn7EdA","Z_CHd3Zjsh2cWE2NSdbiNQ","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","LHNvPtcKBt87cCBX8aTNhQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAlK5","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAjVl","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAuaq","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADLEK","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADKFe","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADiyn","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADh8a","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAXu2","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAABrQw","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB20S","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADhUi","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAALKCV","A2oiHVwisByxRn5RDT4LjAAAAAAALspQ","LHNvPtcKBt87cCBX8aTNhQAAAAAAABD4","A2oiHVwisByxRn5RDT4LjAAAAAAALKWO","A2oiHVwisByxRn5RDT4LjAAAAAAAgL-e"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"DkjcsUWzUMWlzGIG7vWPLA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54556506,44024036,44026008,44007166,43828228,43837959,43282962,43282989,10485923,16807,2845749,2845580,2841596,3335577,3325166,699747],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHda","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8Dk","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8iY","MNBJ5seVz_ocW6tcr1HSmwAAAAACn37-","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1","A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ","A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu","A2oiHVwisByxRn5RDT4LjAAAAAAACq1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"O7XAt57p5nvwpgeB2KrNbw":{"address_or_lines":[12540096,19004791,19032250,19014236,19907031,31278974,31279321,31305795,31279321,31290406,31279321,31317002,19907351,21668882,21654434,21097575,20766142,16277099,16285669,16307614,16278212,12403428,12120854,12121189,12544111],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAv1jA","67s2TwiMngM0yin5Y8pvEgAAAAABIf13","67s2TwiMngM0yin5Y8pvEgAAAAABImi6","67s2TwiMngM0yin5Y8pvEgAAAAABIiJc","67s2TwiMngM0yin5Y8pvEgAAAAABL8HX","67s2TwiMngM0yin5Y8pvEgAAAAAB3Ud-","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3bBD","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3XQm","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3dwK","67s2TwiMngM0yin5Y8pvEgAAAAABL8MX","67s2TwiMngM0yin5Y8pvEgAAAAABSqQS","67s2TwiMngM0yin5Y8pvEgAAAAABSmui","67s2TwiMngM0yin5Y8pvEgAAAAABQexn","67s2TwiMngM0yin5Y8pvEgAAAAABPN2-","67s2TwiMngM0yin5Y8pvEgAAAAAA-F5r","67s2TwiMngM0yin5Y8pvEgAAAAAA-H_l","67s2TwiMngM0yin5Y8pvEgAAAAAA-NWe","67s2TwiMngM0yin5Y8pvEgAAAAAA-GLE","67s2TwiMngM0yin5Y8pvEgAAAAAAvULk","67s2TwiMngM0yin5Y8pvEgAAAAAAuPMW","67s2TwiMngM0yin5Y8pvEgAAAAAAuPRl","67s2TwiMngM0yin5Y8pvEgAAAAAAv2hv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Oam9nmQfwQpA_10YTKZCkg":{"address_or_lines":[4652224,58596086,58544235,10401064,10401333,10401661,58561029,58544882,58545860,58550052,58558939,56502167,58377199,58374713,5176491,5212551,5201562,5198538,12589080,12593882,12537260,12591620,12402541,12450679,4552007,4551401],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAADfhr2","wfA2BgwfDNXUWsxkJ083RwAAAAADfVBr","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrUo","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrY1","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrd9","wfA2BgwfDNXUWsxkJ083RwAAAAADfZIF","wfA2BgwfDNXUWsxkJ083RwAAAAADfVLy","wfA2BgwfDNXUWsxkJ083RwAAAAADfVbE","wfA2BgwfDNXUWsxkJ083RwAAAAADfWck","wfA2BgwfDNXUWsxkJ083RwAAAAADfYnb","wfA2BgwfDNXUWsxkJ083RwAAAAADXieX","wfA2BgwfDNXUWsxkJ083RwAAAAADesPv","wfA2BgwfDNXUWsxkJ083RwAAAAADero5","wfA2BgwfDNXUWsxkJ083RwAAAAAATvyr","wfA2BgwfDNXUWsxkJ083RwAAAAAAT4mH","wfA2BgwfDNXUWsxkJ083RwAAAAAAT16a","wfA2BgwfDNXUWsxkJ083RwAAAAAAT1LK","wfA2BgwfDNXUWsxkJ083RwAAAAAAwBgY","wfA2BgwfDNXUWsxkJ083RwAAAAAAwCra","wfA2BgwfDNXUWsxkJ083RwAAAAAAv02s","wfA2BgwfDNXUWsxkJ083RwAAAAAAwCIE","wfA2BgwfDNXUWsxkJ083RwAAAAAAvT9t","wfA2BgwfDNXUWsxkJ083RwAAAAAAvft3","wfA2BgwfDNXUWsxkJ083RwAAAAAARXVH","wfA2BgwfDNXUWsxkJ083RwAAAAAARXLp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"gM71DK9QAb25Em9dhlNNXA":{"address_or_lines":[4602912,7755816,7756100,7759920,7760733,7744869,8376791,8749164,8618561,8132341,8137261,8133828,8067381,8671283,5977431,5085785,5087348,4663256,4670457,4680028,4694485,10485923,16807,2795169,2795020,2794811,2794363],"file_ids":["kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","kajOqZqz7V1y0BdYQLFQrw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["kajOqZqz7V1y0BdYQLFQrwAAAAAARjwg","kajOqZqz7V1y0BdYQLFQrwAAAAAAdlgo","kajOqZqz7V1y0BdYQLFQrwAAAAAAdllE","kajOqZqz7V1y0BdYQLFQrwAAAAAAdmgw","kajOqZqz7V1y0BdYQLFQrwAAAAAAdmtd","kajOqZqz7V1y0BdYQLFQrwAAAAAAdi1l","kajOqZqz7V1y0BdYQLFQrwAAAAAAf9HX","kajOqZqz7V1y0BdYQLFQrwAAAAAAhYBs","kajOqZqz7V1y0BdYQLFQrwAAAAAAg4JB","kajOqZqz7V1y0BdYQLFQrwAAAAAAfBb1","kajOqZqz7V1y0BdYQLFQrwAAAAAAfCot","kajOqZqz7V1y0BdYQLFQrwAAAAAAfBzE","kajOqZqz7V1y0BdYQLFQrwAAAAAAexk1","kajOqZqz7V1y0BdYQLFQrwAAAAAAhFAz","kajOqZqz7V1y0BdYQLFQrwAAAAAAWzVX","kajOqZqz7V1y0BdYQLFQrwAAAAAATZpZ","kajOqZqz7V1y0BdYQLFQrwAAAAAATaB0","kajOqZqz7V1y0BdYQLFQrwAAAAAARyfY","kajOqZqz7V1y0BdYQLFQrwAAAAAAR0P5","kajOqZqz7V1y0BdYQLFQrwAAAAAAR2lc","kajOqZqz7V1y0BdYQLFQrwAAAAAAR6HV","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKqah","9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM","9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7","9LzzIocepYcOjnUsLlgOjgAAAAAAKqN7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4]},"VoyVx3eKZvx3I7o9LV75WA":{"address_or_lines":[4652224,22354373,22356417,22043891,9840916,9838765,4872825,5688954,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7924288,7914841,6798266,6797590,6797444,2726038],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVRnF","B8JRxL079xbhqQBqGvksAgAAAAABVSHB","B8JRxL079xbhqQBqGvksAgAAAAABUFzz","B8JRxL079xbhqQBqGvksAgAAAAAAlikU","B8JRxL079xbhqQBqGvksAgAAAAAAliCt","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA","A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE","A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"6MfMhGSHuQ0CLUxktz5OVg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19907431,18154044,18082996],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8Nn","v6HIzNa4K6G4nRP9032RIAAAAAABFQI8","v6HIzNa4K6G4nRP9032RIAAAAAABE-y0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"9pWzAEbyffmwRrKvRecyaQ":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858041,18647118,18648496,18406502,18049625],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwJ5","j8DVIOTu7Btj9lgFefJ84AAAAAABHIhO","j8DVIOTu7Btj9lgFefJ84AAAAAABHI2w","j8DVIOTu7Btj9lgFefJ84AAAAAABGNxm","j8DVIOTu7Btj9lgFefJ84AAAAAABE2pZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"DK4Iffrk3v05Awun60ygow":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41460538,41453510,39933561,34157889,34191237,32888264,25716990,34278084,34202797,25717430,25848062,25843154,25848772,25852175,25783796,25513444,25512912,32939143,32929768,24984119,18131287],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeKM6","v6HIzNa4K6G4nRP9032RIAAAAAACeIfG","v6HIzNa4K6G4nRP9032RIAAAAAACYVZ5","v6HIzNa4K6G4nRP9032RIAAAAAACCTVB","v6HIzNa4K6G4nRP9032RIAAAAAACCbeF","v6HIzNa4K6G4nRP9032RIAAAAAAB9dXI","v6HIzNa4K6G4nRP9032RIAAAAAABiGj-","v6HIzNa4K6G4nRP9032RIAAAAAACCwrE","v6HIzNa4K6G4nRP9032RIAAAAAACCeSt","v6HIzNa4K6G4nRP9032RIAAAAAABiGq2","v6HIzNa4K6G4nRP9032RIAAAAAABimj-","v6HIzNa4K6G4nRP9032RIAAAAAABilXS","v6HIzNa4K6G4nRP9032RIAAAAAABimvE","v6HIzNa4K6G4nRP9032RIAAAAAABinkP","v6HIzNa4K6G4nRP9032RIAAAAAABiW30","v6HIzNa4K6G4nRP9032RIAAAAAABhU3k","v6HIzNa4K6G4nRP9032RIAAAAAABhUvQ","v6HIzNa4K6G4nRP9032RIAAAAAAB9pyH","v6HIzNa4K6G4nRP9032RIAAAAAAB9nfo","v6HIzNa4K6G4nRP9032RIAAAAAABfTo3","v6HIzNa4K6G4nRP9032RIAAAAAABFKlX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"4r_hCJ268ciweOwgH0Qwzw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756169,2891746,2888851],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg5J","A2oiHVwisByxRn5RDT4LjAAAAAAALB_i","A2oiHVwisByxRn5RDT4LjAAAAAAALBST"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"VC42Hg55_L_IfaF_actjIw":{"address_or_lines":[4652224,30971941,30986245,30988292,30990568,31382091,30723428,25540326,25548827,25550707,25503568,25504356,25481468,25481277,25484807,25485060,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813708,2804875,2803431,2801020,2796664,2900191,2900031],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAAB2Jgl","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NAF","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NgE","-pk6w5puGcp-wKnQ61BZzQAAAAAB2ODo","-pk6w5puGcp-wKnQ61BZzQAAAAAB3tpL","-pk6w5puGcp-wKnQ61BZzQAAAAAB1M1k","-pk6w5puGcp-wKnQ61BZzQAAAAABhbbm","-pk6w5puGcp-wKnQ61BZzQAAAAABhdgb","-pk6w5puGcp-wKnQ61BZzQAAAAABhd9z","-pk6w5puGcp-wKnQ61BZzQAAAAABhSdQ","-pk6w5puGcp-wKnQ61BZzQAAAAABhSpk","-pk6w5puGcp-wKnQ61BZzQAAAAABhND8","-pk6w5puGcp-wKnQ61BZzQAAAAABhNA9","-pk6w5puGcp-wKnQ61BZzQAAAAABhN4H","-pk6w5puGcp-wKnQ61BZzQAAAAABhN8E","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyL","piWSMQrh4r040D0BPNaJvwAAAAAAKsbn","piWSMQrh4r040D0BPNaJvwAAAAAAKr18","piWSMQrh4r040D0BPNaJvwAAAAAAKqx4","piWSMQrh4r040D0BPNaJvwAAAAAALEDf","piWSMQrh4r040D0BPNaJvwAAAAAALEA_"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"7l18-g5emVzljYbZzZJDRA":{"address_or_lines":[4652224,57367531,57370109,31789066,31776683,58631656,57895320,57890805,57903406,31388307,31007417,30973013,30989730,30933387,30773764,30777712,30779690,30778532,4952297,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813708,2804913,2798877,3355670,8461220],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAADa1vr","-pk6w5puGcp-wKnQ61BZzQAAAAADa2X9","-pk6w5puGcp-wKnQ61BZzQAAAAAB5RAK","-pk6w5puGcp-wKnQ61BZzQAAAAAB5N-r","-pk6w5puGcp-wKnQ61BZzQAAAAADfqXo","-pk6w5puGcp-wKnQ61BZzQAAAAADc2mY","-pk6w5puGcp-wKnQ61BZzQAAAAADc1f1","-pk6w5puGcp-wKnQ61BZzQAAAAADc4ku","-pk6w5puGcp-wKnQ61BZzQAAAAAB3vKT","-pk6w5puGcp-wKnQ61BZzQAAAAAB2SK5","-pk6w5puGcp-wKnQ61BZzQAAAAAB2JxV","-pk6w5puGcp-wKnQ61BZzQAAAAAB2N2i","-pk6w5puGcp-wKnQ61BZzQAAAAAB2AGL","-pk6w5puGcp-wKnQ61BZzQAAAAAB1ZIE","-pk6w5puGcp-wKnQ61BZzQAAAAAB1aFw","-pk6w5puGcp-wKnQ61BZzQAAAAAB1akq","-pk6w5puGcp-wKnQ61BZzQAAAAAB1aSk","-pk6w5puGcp-wKnQ61BZzQAAAAAAS5Dp","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyx","piWSMQrh4r040D0BPNaJvwAAAAAAKrUd","piWSMQrh4r040D0BPNaJvwAAAAAAMzQW","piWSMQrh4r040D0BPNaJvwAAAAAAgRuk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"PkHiro08_uzuUWpeantpNA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927405,7924037],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePZt","ew01Dk0sWZctP-VaEpavqQAAAAAAeOlF"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"9EcGjMrQwznPlnAdDi9Lxw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19908516,19901309,19904117,19988362,19897796,19899069,19901309,19904677,19901380,19901069],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7Z1","v6HIzNa4K6G4nRP9032RIAAAAAABMP-K","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6vE","v6HIzNa4K6G4nRP9032RIAAAAAABL6qN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"tagsGmBta7BnDHBzEbH9eQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19977269,22569935,22570653,19208948,22544340,19208919,19208225,22608882,19754692,19668808,19001325,18870508,18879802,10485923,16807,2756848,2756092,2745322,6715782,6715626,7927445,6732427,882422,8542429],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNQ1","v6HIzNa4K6G4nRP9032RIAAAAAABWGPP","v6HIzNa4K6G4nRP9032RIAAAAAABWGad","v6HIzNa4K6G4nRP9032RIAAAAAABJRr0","v6HIzNa4K6G4nRP9032RIAAAAAABV__U","v6HIzNa4K6G4nRP9032RIAAAAAABJRrX","v6HIzNa4K6G4nRP9032RIAAAAAABJRgh","v6HIzNa4K6G4nRP9032RIAAAAAABWPvy","v6HIzNa4K6G4nRP9032RIAAAAAABLW7E","v6HIzNa4K6G4nRP9032RIAAAAAABLB9I","v6HIzNa4K6G4nRP9032RIAAAAAABIe_t","v6HIzNa4K6G4nRP9032RIAAAAAABH_Ds","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw","ew01Dk0sWZctP-VaEpavqQAAAAAAKg38","ew01Dk0sWZctP-VaEpavqQAAAAAAKePq","ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG","ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq","ew01Dk0sWZctP-VaEpavqQAAAAAAePaV","ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL","ew01Dk0sWZctP-VaEpavqQAAAAAADXb2","ew01Dk0sWZctP-VaEpavqQAAAAAAgljd"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"euPXE4-KNZJD0T6j_TMfYw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,7046,2795776,1483241,1482767,2600004,1074397,11342,13400,51888,12612,2578675,2599636,1091600,7744,52134,33264,2795776,1483241,1482767,2600004,1073803,11342,13400,51888,12396,16726,41698,2852079,2851771,2850043,1501120,1495723],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lLD39yzd4Cg8F13tcGpzGQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","dCCKy6JoX0PADOFic8hRNQ","9w9lF96vJW7ZhBoZ8ETsBw","xUQuo4OgBaS_Le-fdAwt8A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lLD39yzd4Cg8F13tcGpzGQAAAAAAABuG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAACxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","dCCKy6JoX0PADOFic8hRNQAAAAAAAB5A","9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAMum","xUQuo4OgBaS_Le-fdAwt8AAAAAAAAIHw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAACxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAKLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3z7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFufA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFtKr"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3]},"cL14TWzNnz1qK2PUYdE9bg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791289,24794610,24781052,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756560,2755688,2744899,3827767,3827522,2050302,4868077,4855697,8473771],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekj5","v6HIzNa4K6G4nRP9032RIAAAAAABelXy","v6HIzNa4K6G4nRP9032RIAAAAAABeiD8","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3","ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC","ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-","ew01Dk0sWZctP-VaEpavqQAAAAAASkft","ew01Dk0sWZctP-VaEpavqQAAAAAASheR","ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"9wXZUZEeGMQm83C5yXCZ2g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696049,18965430,18965669,18966052,18973868,18911086,18905330,18910928,18783663,18799034,10485923,16900,15534,703491,2755412,3875596,3765212,3542694,3677893],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNTx","j8DVIOTu7Btj9lgFefJ84AAAAAABIWO2","j8DVIOTu7Btj9lgFefJ84AAAAAABIWSl","j8DVIOTu7Btj9lgFefJ84AAAAAABIWYk","j8DVIOTu7Btj9lgFefJ84AAAAAABIYSs","j8DVIOTu7Btj9lgFefJ84AAAAAABII9u","j8DVIOTu7Btj9lgFefJ84AAAAAABIHjy","j8DVIOTu7Btj9lgFefJ84AAAAAABII7Q","j8DVIOTu7Btj9lgFefJ84AAAAAABHp2v","j8DVIOTu7Btj9lgFefJ84AAAAAABHtm6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEIE","piWSMQrh4r040D0BPNaJvwAAAAAAADyu","piWSMQrh4r040D0BPNaJvwAAAAAACrwD","piWSMQrh4r040D0BPNaJvwAAAAAAKgtU","piWSMQrh4r040D0BPNaJvwAAAAAAOyMM","piWSMQrh4r040D0BPNaJvwAAAAAAOXPc","piWSMQrh4r040D0BPNaJvwAAAAAANg6m","piWSMQrh4r040D0BPNaJvwAAAAAAOB7F"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"bz1cYNqu8MBH2xCXTMEiAg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7507990,7549300],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpAW","ew01Dk0sWZctP-VaEpavqQAAAAAAczF0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"fCScXsJaisrZL_JXgS4qQg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7436960,6766701,6769642,2098164],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg","9LzzIocepYcOjnUsLlgOjgAAAAAAZ0Bt","9LzzIocepYcOjnUsLlgOjgAAAAAAZ0vq","9LzzIocepYcOjnUsLlgOjgAAAAAAIAP0"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"V-MDb_Yh073ps9Vw4ypmDQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797702,6797556,2726148],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7mG","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0","ew01Dk0sWZctP-VaEpavqQAAAAAAKZkE"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"wAujHiFN47_oNUI63d6EtA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7513502,6765905,6759805,2574033,2218596],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe","ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R","ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9","ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR","ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"zMMsPlSW5HOq5bsuVRh3KA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2822585,3001783,2924437,3111967,3095700,156159,136830,285452,1430646,1449979,1447865,1447752,1446446,1188192,1188137,220151,219438,219438,219438,219438,219438,219425,219589,1446206],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","9HZ7GQCC6G9fZlRD7aGzXQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","huWyXZbCBWCe2ZtK9BiokQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxG5","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3wf","-p9BlJh9JZMPPNjY_j92ngAAAAAALzyU","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_","9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhZ-","9HZ7GQCC6G9fZlRD7aGzXQAAAAAABFsM","huWyXZbCBWCe2ZtK9BiokQAAAAAAFdR2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFh_7","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhe5","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhdI","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhIu","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiFg","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiEp","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1v3","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1kh","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1nF","huWyXZbCBWCe2ZtK9BiokQAAAAAAFhE-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"pLdowTKUS5KSwivHyl5AgA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1344317,1318852,1317790,1316548,1337360,1338921,1188023],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBue","huWyXZbCBWCe2ZtK9BiokQAAAAAAFBbE","huWyXZbCBWCe2ZtK9BiokQAAAAAAFGgQ","huWyXZbCBWCe2ZtK9BiokQAAAAAAFG4p","huWyXZbCBWCe2ZtK9BiokQAAAAAAEiC3"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"_ef-NJahpYK_FzFC-KdtYQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,29942,33148,3444,27444,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1072174,33518,35576,8560,17976,49494,22596,3272936,3254825,1481992,1534257,3238809,3051716,67008,10485923,16807,2756288,2755416,2744627,3827463,3827218,2049230,2042319,2040147,2469374],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","eOfhJQFIxbIEScd007tROw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAAIF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFwu","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAFhE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMfDo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMaop","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp0I","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF2kx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMWuZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALpDE","eOfhJQFIxbIEScd007tROwAAAAAAAQXA","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAOmcH","A2oiHVwisByxRn5RDT4LjAAAAAAAOmYS","A2oiHVwisByxRn5RDT4LjAAAAAAAH0TO","A2oiHVwisByxRn5RDT4LjAAAAAAAHynP","A2oiHVwisByxRn5RDT4LjAAAAAAAHyFT","A2oiHVwisByxRn5RDT4LjAAAAAAAJa3-"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"omG-i9KffSi3YT8q0rYOiw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6869315,6866863,2620,6841654,6841533],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","6miIyyucTZf5zXHCk7PT1g","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD","ew01Dk0sWZctP-VaEpavqQAAAAAAaMev","6miIyyucTZf5zXHCk7PT1gAAAAAAAAo8","ew01Dk0sWZctP-VaEpavqQAAAAAAaGU2","ew01Dk0sWZctP-VaEpavqQAAAAAAaGS9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"XiONbb-veQ1sAuFD6_Fv0A":{"address_or_lines":[48,38,174,104,68,200,38,174,104,68,60,38,174,104,68,92,38,174,104,68,4,38,174,104,10,10,38,174,104,68,20,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044807,2041460,1171829,2265239,2264574,2258601,1016100],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5sij7Z672VAK_gGoPDPJBg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","PCeTYI0HN2oKNST6e1IaQQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","U4FmFVJMlNKhF1hVl3Xj1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","JR7ekk9KGQJKKPohpdwCLQ","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rpRn_rYC3CgtEgBAUrkZZg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAADI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5sij7Z672VAK_gGoPDPJBgAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","PCeTYI0HN2oKNST6e1IaQQAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","U4FmFVJMlNKhF1hVl3Xj1AAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","JR7ekk9KGQJKKPohpdwCLQAAAAAAAAAK","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rpRn_rYC3CgtEgBAUrkZZgAAAAAAAAAU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzOH","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInap","G68hjsyagwq6LpWrMjDdngAAAAAAD4Ek"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"krdohOL0KiVMtm4q-6fmjg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,5836,10976,12298,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,37910,8000,46852,32076,49840,40252,33434,32730,43978,37948,30428,26428,19370,1480209,1940645,1970099,1481300,1480695,2595076,1079144,20016,37192,1480141,1913750],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","okehWevKsEA4q6dk779jgw","-IuadWGT89NVzIyF_Emodw","XXJY7v4esGWnaxtMW3FA0g","FbrXdcA4j750RyQ3q9JXMw","pL34QuyxyP6XYzGDBMK_5w","IoAk4kM-M4DsDPp7ia5QXw","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","fB79lJck2X90l-j7VqPR-Q","gbMheDI1NZ3NY96J0seddg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GquRfhZBLBKr9rIBPuH3nA","_DA_LSFNMjbu9L2Dcselpw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE","okehWevKsEA4q6dk779jgwAAAAAAAH1M","-IuadWGT89NVzIyF_EmodwAAAAAAAMKw","XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08","FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa","pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a","IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK","uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc","fB79lJck2X90l-j7VqPR-QAAAAAAAGc8","gbMheDI1NZ3NY96J0seddgAAAAAAAEuq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpf3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w","_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpXN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHTOW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,3,3]},"N2LqhupgLi4T_B9D7JaDDQ":{"address_or_lines":[4623648,7066994,7068484,7069849,7058446,10002970,10005676,10124500,9016547,11291366,9016547,24500423,24494926,9016547,10689293,10690744,9016547,24494153,24444068,9016547,24526481,9016547,12769612,10684953,24495408,10128820,7327937,7071629,7072042,7142576,5627718,5631637,5512164,4910105,4760761,4777496,4778618,10485923,16743,6659981,6654519,6650911,6650061,8052504,7525822,7331115,7324128,6674998,6706722,6700261,2539310],"file_ids":["JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","JsObMPhfT_zO2Q_B1cPLxA","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["JsObMPhfT_zO2Q_B1cPLxAAAAAAARo0g","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9Vy","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa9tE","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-CZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa7QO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKIa","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmKys","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmnzU","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAArErm","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABddjH","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcNO","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoxsN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAoyC4","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcBJ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdPyk","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAABdj6R","JsObMPhfT_zO2Q_B1cPLxAAAAAAAiZTj","JsObMPhfT_zO2Q_B1cPLxAAAAAAAwtlM","JsObMPhfT_zO2Q_B1cPLxAAAAAAAowoZ","JsObMPhfT_zO2Q_B1cPLxAAAAAABdcUw","JsObMPhfT_zO2Q_B1cPLxAAAAAAAmo20","JsObMPhfT_zO2Q_B1cPLxAAAAAAAb9DB","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-eN","JsObMPhfT_zO2Q_B1cPLxAAAAAAAa-kq","JsObMPhfT_zO2Q_B1cPLxAAAAAAAbPyw","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVd9G","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVe6V","JsObMPhfT_zO2Q_B1cPLxAAAAAAAVBvk","JsObMPhfT_zO2Q_B1cPLxAAAAAAASuwZ","JsObMPhfT_zO2Q_B1cPLxAAAAAAASKS5","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOYY","JsObMPhfT_zO2Q_B1cPLxAAAAAAASOp6","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAZZ-N","piWSMQrh4r040D0BPNaJvwAAAAAAZYo3","piWSMQrh4r040D0BPNaJvwAAAAAAZXwf","piWSMQrh4r040D0BPNaJvwAAAAAAZXjN","piWSMQrh4r040D0BPNaJvwAAAAAAet8Y","piWSMQrh4r040D0BPNaJvwAAAAAActW-","piWSMQrh4r040D0BPNaJvwAAAAAAb90r","piWSMQrh4r040D0BPNaJvwAAAAAAb8Hg","piWSMQrh4r040D0BPNaJvwAAAAAAZdo2","piWSMQrh4r040D0BPNaJvwAAAAAAZlYi","piWSMQrh4r040D0BPNaJvwAAAAAAZjzl","piWSMQrh4r040D0BPNaJvwAAAAAAJr8u"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"7TvODt8WtQ5KXTmYPsDI3A":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,54988,10976,61450,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,21526,8000,30022,59542,29542,18986,21536,54462,53814,11024,12030,61026,21014,45460,42632,1480209,3459845,1479516,2595076,1050939,23882,1371605,2194798,2100556,2032414,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","cBO14nNDW8EW0oaZDaZipw","C64RiOp1JIPwHLB_iHDa0A","xvApUwdY2y4sFaZRNrMv5g","vsalcPHh9qLgsdKtk190IA","QsuqlohtoJfpo6vQ6tHa2A","8ep9l3WIVYErRiHtmAdvew","nPWpQrEmCn54Ou0__aZyJA","-xcELApECIipEESUIWed9w","L_saUsdri-UdXCut6Tdtng","uHLoBslr3h6S7ooNeXzEbw","p19NBQ2pky4eRJM7tgeenw","55ABUc9FqQ0uj-yn-sTq2A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1msFlmxT18lYvJkx-hfGPg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAANbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAPAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAFQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAAHVG","cBO14nNDW8EW0oaZDaZipwAAAAAAAOiW","C64RiOp1JIPwHLB_iHDa0AAAAAAAAHNm","xvApUwdY2y4sFaZRNrMv5gAAAAAAAEoq","vsalcPHh9qLgsdKtk190IAAAAAAAAFQg","QsuqlohtoJfpo6vQ6tHa2AAAAAAAANS-","8ep9l3WIVYErRiHtmAdvewAAAAAAANI2","nPWpQrEmCn54Ou0__aZyJAAAAAAAACsQ","-xcELApECIipEESUIWed9wAAAAAAAC7-","L_saUsdri-UdXCut6TdtngAAAAAAAO5i","uHLoBslr3h6S7ooNeXzEbwAAAAAAAFIW","p19NBQ2pky4eRJM7tgeenwAAAAAAALGU","55ABUc9FqQ0uj-yn-sTq2AAAAAAAAKaI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANMsF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAk7","1msFlmxT18lYvJkx-hfGPgAAAAAAAF1K","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFO3V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIX1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIA1M","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHwMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3]},"u1L6jqeUaTNx1a2aJ9yFwA":{"address_or_lines":[74,6,18,8,18,80,24,4,84,38,174,104,68,128,38,174,104,68,64,38,174,104,68,84,38,174,104,68,100,140,10,38,174,104,68,60,38,174,104,14,32,38,32,786829,1090933,2561389,794630,788130,1197115,2578326,1109790,1111453,1034624],"file_ids":["a5aMcPOeWx28QSVng73nBQ","inI9W0bfekFTCpu0ceKTHg","RPwdw40HEBL87wRkKV2ozw","pT2bgvKv3bKR6LMAYtKFRw","Rsr7q4vCSh2ppRtyNkwZAA","cKQfWSgZRgu_1Goz5QGSHw","T2fhmP8acUvRZslK7YRDPw","lrxXzNEmAlflj7bCNDjxdA","SMoSw8cr-PdrIATvljOPrQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xaCec3W8F6xlvd_EISI7vw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GYpj0RgmHJTfD-_w_Fx69w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","b78FoZPzgl20nGrU0Zu24g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5ZxW56RI3EOJxqCWjdkdHg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","7l7IlhF_Z6_Ribw1CW945Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","imaY9TOf2pKX0_q1vRTskQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAABK","inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG","RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS","pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI","Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS","cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ","T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY","lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE","SMoSw8cr-PdrIATvljOPrQAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xaCec3W8F6xlvd_EISI7vwAAAAAAAACA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GYpj0RgmHJTfD-_w_Fx69wAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","b78FoZPzgl20nGrU0Zu24gAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5ZxW56RI3EOJxqCWjdkdHgAAAAAAAABk","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","7l7IlhF_Z6_Ribw1CW945QAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAAm","imaY9TOf2pKX0_q1vRTskQAAAAAAAAAg","G68hjsyagwq6LpWrMjDdngAAAAAADAGN","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAJxVt","G68hjsyagwq6LpWrMjDdngAAAAAADCAG","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAJ1eW","G68hjsyagwq6LpWrMjDdngAAAAAAEO8e","G68hjsyagwq6LpWrMjDdngAAAAAAEPWd","G68hjsyagwq6LpWrMjDdngAAAAAAD8mA"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3]},"8uzy4VW9n0Z8KokUdeadfg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,14028,27360,55578,1480209,1969795,1481300,1480601,2595076,1079485,18126,36558,2460,42724,46700,1479608,1493928,2595076,1079485,30578,15346,1479608,2595076,1079485,57180,32508,1276,30612,1479516,2595076,1079485,63696,30612,1479516,2595076,1073749,60436,3118304,766784,10485923,16807,2741196,2827770,2817684,2804657,2869654],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","Kq9d0b1CBVEQZUtuJtmlJg","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAADbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAANka","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","EFJHOn-GACfHXgae-R1yDAAAAAAAAEbO","GdaBUD9IUEkKxIBryNqV2wAAAAAAAI7O","QU8QLoFK6ojrywKrBFfTzAAAAAAAAAmc","V558DAsp4yi8bwa8eYwk5QAAAAAAAKbk","grikUXlisBLUbeL_OWixIwAAAAAAALZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAN9c","-9oyoP4Jj2iRkwEezqId-gAAAAAAAH78","Kq9d0b1CBVEQZUtuJtmlJgAAAAAAAAT8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAPjQ","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAAOwU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL5Tg","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7NA","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKsux","A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,4,4,4,4,4,4,4]},"EeUwhr9vbcywMBkIYZRfCw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,46796,43744,53258,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1079144,13334,40862,834,1480209,1969795,1481300,1480601,2595076,1069341,58136,12466,1587508,1079485,50582,26272,1479608,1493928,2595076,1079211,60348,34084,42798,54954,4836,40660,62188,43850,13372,5488,20256,1924997],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","wpss7yv4AvkSwbtctTl0JA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SLUxdgyFrTF3l4NU1VRO_w","ZOgaFnYiv38tVz-8Hafu3w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","u1Za6xFXDX1Ys5Qeh_gy9Q","uq4_q8agTQ0rkhJvygJ3QA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","pK0zxAMiW-X23QjQRVzm5w","OP7EiuTwTtWCf_B7a-Zpig","WyVrojmISSgbkYAxEOnpQw","JdWBEAqhrU7LJg0YDuYO0w","cwZEcJVCN5Q4BJdAS3o8fw","iLNvi1vqLkBP_ehg4QlqeA","guXM5tmjJlv0Ehde0y1DFw","avBEfFKeFSrhKf93SLNe0Q","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","aAagm2yDcrnYaqBPCwyu8Q","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAALbM","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAANAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAADQW","ne8F__HPIVgxgycJADVSzAAAAAAAAJ-e","wpss7yv4AvkSwbtctTl0JAAAAAAAAANC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFEd","SLUxdgyFrTF3l4NU1VRO_wAAAAAAAOMY","ZOgaFnYiv38tVz-8Hafu3wAAAAAAADCy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGDk0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","u1Za6xFXDX1Ys5Qeh_gy9QAAAAAAAMWW","uq4_q8agTQ0rkhJvygJ3QAAAAAAAAGag","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHer","pK0zxAMiW-X23QjQRVzm5wAAAAAAAOu8","OP7EiuTwTtWCf_B7a-ZpigAAAAAAAIUk","WyVrojmISSgbkYAxEOnpQwAAAAAAAKcu","JdWBEAqhrU7LJg0YDuYO0wAAAAAAANaq","cwZEcJVCN5Q4BJdAS3o8fwAAAAAAABLk","iLNvi1vqLkBP_ehg4QlqeAAAAAAAAJ7U","guXM5tmjJlv0Ehde0y1DFwAAAAAAAPLs","avBEfFKeFSrhKf93SLNe0QAAAAAAAKtK","uHLoBslr3h6S7ooNeXzEbwAAAAAAADQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAABVw","aAagm2yDcrnYaqBPCwyu8QAAAAAAAE8g","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHV-F"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,1,1,3,3,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,3]},"x443zjuudYI-A7cRu2DIGg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,49094,58124,2548,13860,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28996,2578675,2599636,1091600,48574,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28996,2578675,2599636,1091600,63674,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,28780,342,57994,19187,38198,48990],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lpUCR1NQj5NOLBg7mvzlqg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAL_G","LF6DFcGHEMqhhhlptO_M_QAAAAAAAOMM","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAL2-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lpUCR1NQj5NOLBg7mvzlqgAAAAAAAPi6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAOKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAJU2","jaBVtokSUzfS97d-XKjijgAAAAAAAL9e"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"rrrvnakD3SpJqProBGqoCQ":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,1270,4476,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,19382,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,60558,2790352,1482889,1482415,2595076,1079144,8942,10826,15776,45470,57908,19178,5946,1481694,1535004,2095808],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","08DBZKRu4nC_Oi_uT40UHw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","n74P5OxFm1hAo5ZWtgcKHQ","zXbqXCWr0lCbi_b24hNBRQ","AOM_-6oRTyAxK8W79Wo5aQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAAT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAABF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAEu2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","08DBZKRu4nC_Oi_uT40UHwAAAAAAAOyO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAD2g","n74P5OxFm1hAo5ZWtgcKHQAAAAAAALGe","zXbqXCWr0lCbi_b24hNBRQAAAAAAAOI0","AOM_-6oRTyAxK8W79Wo5aQAAAAAAAErq","yaTrLhUSIq2WitrTHLBy3QAAAAAAABc6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF2wc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAH_rA"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3]},"sDfHX0MKzztQSqC8kl_-sg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,16720,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,52894,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,44846,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,32258,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50744,16726,2346,19187,41240,50359],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N0GNsPaCLYzoFsPJWnIJtQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fq0ezjB8ddCA6Pk0BY9arQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAM6e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fq0ezjB8ddCA6Pk0BY9arQAAAAAAAH4C","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAAkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMS3"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"WmwSnxyphedkasVyGbhNdg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,23142,41180,18932,30244,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,29418,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,58990,2795776,1483241,1482767,2600004,1073803,3150,5208,43696,4204,342,33506,2852079,2851771,2849353,2846190,2846190,2845732],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","l97YFeEKpeLfa-lEAZVNcA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAAHYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2wk"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"NU5so_CJJJwGJM_hiEcxgQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,4,38,174,104,68,16,38,174,104,68,256,140,10,38,174,104,68,0,12,8,28,12,8,54,12,120,1169291,1109342,1109180],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZBnr-5IlLVGCdkX_lTNKmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RDOEyok4432cuMjL10_tug","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_____________________w","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","25JFhMXA0rvP5hfyUpf34w","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RDOEyok4432cuMjL10_tugAAAAAAAAEA","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_____________________wAAAAAAAAAA","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","25JFhMXA0rvP5hfyUpf34wAAAAAAAAAc","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAB4","G68hjsyagwq6LpWrMjDdngAAAAAAEdeL","G68hjsyagwq6LpWrMjDdngAAAAAAEO1e","G68hjsyagwq6LpWrMjDdngAAAAAAEOy8"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3]},"A9B6bwuKQl9pC0MIYqtAgg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,34996,38690,20748,3858,37276,30816,26538,1480561,1970211,1481652,1480953,2600004,1079669,36476,1480561,1970211,1481652,1480953,2600004,1079669,13542,44224,26138,5558,16780,64790,18774,36466,18774,17314,43978,43978,43978,43978,43978,43978,43978,43886,18774,13462,1480561,1940968,1917658,1481652,1480953,2600004,1079669,27396,1480561,1827986,1940595,1909209,1934862,3077552,3072233,1745406,3070488],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","ZLTqiSLOmv4Ej_7d8yKLmw","v_WV3HQYVe0q1Ob-1gtx1A","ka2IKJhpWbD6PA3J3v624w","e8Lb_MV93AH-OkvHPPDitg","ka2IKJhpWbD6PA3J3v624w","1vivUE5hL65442lQ9a_ylg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","fh_7rTxpgngJ2cX2lBjVdg","ka2IKJhpWbD6PA3J3v624w","fCsVLBj60GK9Hf8VtnMcgA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","54xjnvwS2UtwpSVJMemggA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAJci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAJGc","W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAGeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAI58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","kSaNXrGzSS3BnDNNWezzMAAAAAAAADTm","ne8F__HPIVgxgycJADVSzAAAAAAAAKzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAGYa","O_h7elJSxPO7SiCsftYRZgAAAAAAABW2","ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAEGM","v_WV3HQYVe0q1Ob-1gtx1AAAAAAAAP0W","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","e8Lb_MV93AH-OkvHPPDitgAAAAAAAI5y","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","1vivUE5hL65442lQ9a_ylgAAAAAAAEOi","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK","fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKtu","ka2IKJhpWbD6PA3J3v624wAAAAAAAElW","fCsVLBj60GK9Hf8VtnMcgAAAAAAAADSW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","54xjnvwS2UtwpSVJMemggAAAAAAAAGsE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHSHZ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHYYO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvWw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALuDp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGqH-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALtoY"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"X86DUuQ7tHAxGBaWu4tZLg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,19046,37084,2548,13860,26096,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,64610,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,39726,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,0,2794972,1848805,1837992,1848417,2718329,2222078,2208786],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqXc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHAuo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDRh","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKXp5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIef-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIbQS"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"T3fWxJzHMwU-oUs7rgXCcg":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,172,669638,1091944,956540,2223054,995645,1276144],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","okgAOHfDrcA806m5xh4DMA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","okgAOHfDrcA806m5xh4DMAAAAAAAAACs","G68hjsyagwq6LpWrMjDdngAAAAAACjfG","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAADph8","G68hjsyagwq6LpWrMjDdngAAAAAAIevO","G68hjsyagwq6LpWrMjDdngAAAAAADzE9","G68hjsyagwq6LpWrMjDdngAAAAAAE3jw"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3]},"vq75CDVua5N-eDXnfyZYMA":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,620,51986,58710,61916,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,12034,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,38490,2790352,1482889,1482415,2595076,1076587,49902,51960,24944,34360,342,51586,2846655,2846347,2843929,2840766,2843954,2840766,2842897,2268402,1775000,1761295,1048455],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","aRRT4_vBG9Q4nqyirWo5FA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAC8C","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","aRRT4_vBG9Q4nqyirWo5FAAAAAAAAJZa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Uy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2ER","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_-H"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3]},"oKVObqTWF9QIjxgKf8UkTw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,51328,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,50170,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,13752,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41068,49494,4746,19187,41141,49404],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","08Dc0vnMK9C_nl7yQB6ZKQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zuPG_tF81PcJTwjfBwKlDg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKC1","jaBVtokSUzfS97d-XKjijgAAAAAAAMD8"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"DaDdc6eLo0hc-QxL2XQh5Q":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,336,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,28326,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,51274,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,43126,2790352,1482889,1482415,2595076,1073749,49902,51960,24944,34524,2573747,2594708,1091475,0,2790352,1482889,1482415,2595076,1071215,49902,51786,56736,43360,44552,32102],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ZyAwfhB8pqBFv6xiDVdvPQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","9alsKcnSosScCQ3ntwGT5w","xAINw9zPBhJlledr3DAcGA","xVweU0pD8q051c2YgF4PTw"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAG6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAAMhK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ZyAwfhB8pqBFv6xiDVdvPQAAAAAAAKh2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFhv","ik6PIX946fW_erE7uBJlVQAAAAAAAMLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAN2g","9alsKcnSosScCQ3ntwGT5wAAAAAAAKlg","xAINw9zPBhJlledr3DAcGAAAAAAAAK4I","xVweU0pD8q051c2YgF4PTwAAAAAAAH1m"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1]},"YRZbUV2DChD6dl3Y2xjF8g":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,49772,35602,38230,41436,19828,27444,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,57358,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,33966,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,59370,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,17976,49494,31018,19187,41240,50308],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","d4jl580PLMUwu5s3I4wcXg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","tKago5vqLnwIkezk_wTBpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAJVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAAGs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAOAO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","d4jl580PLMUwu5s3I4wcXgAAAAAAAISu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","tKago5vqLnwIkezk_wTBpQAAAAAAAOfq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSE"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"EnsO3_jc7LnLdUHQbwkxMg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,336,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,24230,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,47162,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,37090,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,41914,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34360,342,39210,19187,41240,51115],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAF6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAALg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAAJDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAAKO6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAJkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMer"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"V2XOOBv96QfYXHIIY7_OLA":{"address_or_lines":[3150,5208,43696,12612,2578675,2599636,1091600,42546,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,12274,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,15838,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,37594,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1079669,12698,1482046,1829360,2586225,2600004,1054235,21784,1973936,2600004,1051035,60416,55140,1372101,2194686,2080131],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Gp9aOxUrrpSVBx4-ftlTOA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","y9R94bQUxts02WzRWfV7xg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","uI6css-d8SGQRK6a_Ntl-A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SlnkBp0IIJFLHVOe4KbxwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7wBb3xHP1JZHNBpMGh4EdA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","u3fGdgL6eAYjYSRbRUri0g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aG0mH34tM6si5c1l397JVQ","GC-VoGaqaEobPzimayHQTQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAKYy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","y9R94bQUxts02WzRWfV7xgAAAAAAAC_y","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","uI6css-d8SGQRK6a_Ntl-AAAAAAAAD3e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SlnkBp0IIJFLHVOe4KbxwQAAAAAAAJLa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","7wBb3xHP1JZHNBpMGh4EdAAAAAAAADGa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEBYb","u3fGdgL6eAYjYSRbRUri0gAAAAAAAFUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHh6w","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEAmb","aG0mH34tM6si5c1l397JVQAAAAAAAOwA","GC-VoGaqaEobPzimayHQTQAAAAAAANdk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFO_F","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIXz-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAH72D"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,1,1,3,3,3]},"FTJM3wsT8Kc-UaiIK2yDMQ":{"address_or_lines":[33018,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,32502,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,6654,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,9126,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,27090,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1079144,39334,1481694,1828960,2581397,1480843,1480209,1940568,1917230,1844695,1996687],"file_ids":["PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","UfGck3qA2qF0xFB5gpY4Hg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","G9ShE3ODivDEFyHVdsnZ_g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","6AsJ0dA2BUqaic-ScDJBMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fr52ZDCgnkPZlzTNdLTQ5w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uqoEOAkLp1toolLH0q5LVw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["PmhxUKv5sePRxhCBONca8gAAAAAAAID6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","UfGck3qA2qF0xFB5gpY4HgAAAAAAAH72","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","G9ShE3ODivDEFyHVdsnZ_gAAAAAAABn-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","6AsJ0dA2BUqaic-ScDJBMAAAAAAAACOm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fr52ZDCgnkPZlzTNdLTQ5wAAAAAAAGnS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","uqoEOAkLp1toolLH0q5LVwAAAAAAAJmm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUEu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHneP"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3]},"ivbgd9hswtvZ7aTts7HESw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,49488,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,40502,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1091475,9946,2790352,1482889,1482415,2595076,1079485,8942,11000,49520,61192,19302,1479516,1828960,2573747,2594708,1091475,51250,2790352,1482889,1482415,2595076,1073749,8942,11000,49520,50908,2573747,2594708,1079144,0,1481694,1828960,2581297,2595076,1087128,0,23366,42140,41576,9542,41540,41016,39548,3072796],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","WjtMXFj0eujpoknR_rynvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","Vot4T3F5OpUj8rbXhgpMDg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EPS0ql6FPdCQLe9KByvDQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAJ42","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","WjtMXFj0eujpoknR_rynvAAAAAAAACba","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","Vot4T3F5OpUj8rbXhgpMDgAAAAAAAO8I","eV_m28NnKeeTL60KO2H3SAAAAAAAAEtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","EPS0ql6FPdCQLe9KByvDQAAAAAAAAMgy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAACLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEJaY","_____________________wAAAAAAAAAA","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAKSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAKJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG","E2b-mzlh_8261-JxcySn-AAAAAAAAKJE","E2b-mzlh_8261-JxcySn-AAAAAAAAKA4","E2b-mzlh_8261-JxcySn-AAAAAAAAJp8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuMc"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,1,3]},"yXsgvY1JyekwdCV5rJdspg":{"address_or_lines":[2573747,2594708,1091475,43746,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,51994,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,18382,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,10738,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1079144,0,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079485,46582,1479772,1827586,1940195,1986447,1982493,1959065,1765336,1761295,1048494],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XVsKc4e32xXUv-3uv2s-8Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","_____________________w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uPGvGNXBf1JXGeeDSsmGQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAAKri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAMsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAAEfO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XVsKc4e32xXUv-3uv2s-8QAAAAAAACny","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","_____________________wAAAAAAAAAA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","uPGvGNXBf1JXGeeDSsmGQAAAAAAAALX2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHk-P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHkAd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHeSZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGu_Y","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_-u"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3]},"_TjN4epIphuKUiHZJZdqxQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,38,10,38,174,104,68,30,56,382,1034444],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OwrnTUowquMzuETYoP67yQ","HmAocvtnsxREZJIec2I5gw","KHDki7BxJPyjGLtvY8M5lQ","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OwrnTUowquMzuETYoP67yQAAAAAAAAAe","HmAocvtnsxREZJIec2I5gwAAAAAAAAA4","KHDki7BxJPyjGLtvY8M5lQAAAAAAAAF-","G68hjsyagwq6LpWrMjDdngAAAAAAD8jM"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3]},"ZQdwkmvvmLjNzNpTA4PPhw":{"address_or_lines":[25326,27384,368,1756,2573747,2594708,1091475,48726,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,64878,2789627,1482889,1482415,2595076,1079485,21616,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,51982,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,58138,2790352,1482889,1482415,2595076,1067375,25326,27210,32160,46288],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XlQ19HBD_RNa2r3QWOR-nA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","it1vvnZdXdzy0fFROnaaOQ"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAL5W","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XlQ19HBD_RNa2r3QWOR-nAAAAAAAAP1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAMsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAAOMa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEElv","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAH2g","it1vvnZdXdzy0fFROnaaOQAAAAAAALTQ"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1]},"ssC7MBcE9kfM3yTim7UrNQ":{"address_or_lines":[4846,6904,45424,50908,2573747,2594708,1091475,58102,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,48494,2789627,1482889,1482415,2595076,1079485,1136,15206,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,27398,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,2830,2790352,1482889,1482415,2595076,1073749,4846,6904,45424,50908,2573747,2594708,1091475,4586,2790352,1482889,1482415,2595076,1067395,4846,6904,45240,53006,54142],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XlQ19HBD_RNa2r3QWOR-nA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VuJFonCXevADcEDW6NVbKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VFBd9VqCaQu0ZzjQ2K3pjg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PUSucJs4FC_WdMzOyH3QYw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","gZooqVYiItnHim-lK4feOg"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAOL2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XlQ19HBD_RNa2r3QWOR-nAAAAAAAAL1u","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAARw","eV_m28NnKeeTL60KO2H3SAAAAAAAADtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VuJFonCXevADcEDW6NVbKgAAAAAAAGsG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PUSucJs4FC_WdMzOyH3QYwAAAAAAABHq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEEmD","ik6PIX946fW_erE7uBJlVQAAAAAAABLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4","J1eggTwSzYdi9OsSu1q37gAAAAAAALC4","0S3htaCNkzxOYeavDR1GTQAAAAAAAM8O","gZooqVYiItnHim-lK4feOgAAAAAAANN-"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1]},"-yH5iqJp4uVN6clNHuFusA":{"address_or_lines":[2578675,2599636,1091600,5350,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,6974,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,5866,2795776,1483241,1482767,2600004,1079483,3150,4692,13478,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,58134,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12612,2578675,2599636,1091600,10246,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,12396,342,41610,19187,41240,50663],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","UfGck3qA2qF0xFB5gpY4Hg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","G9ShE3ODivDEFyHVdsnZ_g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","6AsJ0dA2BUqaic-ScDJBMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","VY0EiAO0DxwLRTE4PfFhdw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","A8AozG5gQfEN24i4IE7w5w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","UfGck3qA2qF0xFB5gpY4HgAAAAAAABTm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","G9ShE3ODivDEFyHVdsnZ_gAAAAAAABs-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","6AsJ0dA2BUqaic-ScDJBMAAAAAAAABbq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABJU","eV_m28NnKeeTL60KO2H3SAAAAAAAADSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","VY0EiAO0DxwLRTE4PfFhdwAAAAAAAOMW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","A8AozG5gQfEN24i4IE7w5wAAAAAAACgG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAKKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMXn"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"SrSwvDbs2pmPg3SRfXJBCA":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11318,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,15678,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,250,2790352,1482889,1482415,2595076,1076587,29422,31480,4464,17976,33110,51586,2846655,2846347,2843929,2840766,2843907,2841214,1439462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NGbZlnLCqeq3LFq89r_SpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PmhxUKv5sePRxhCBONca8gAAAAAAAAD6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbm"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3]},"n5nFiHsDS01AKuzFKvQXdA":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,302,38,174,104,68,382,120,38,258,658,1111840,1034048],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","OPpnYj88CDOiKneikdGPHA","ZJjPF65K8mBuISvhCfKfBg","xLxhp_367a_SbgOYuEJjlw","QHotkhNTqx5C4Kjd2F2_6w","Ht79I_xqXv3bOgaClTNQ4w","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAEu","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","OPpnYj88CDOiKneikdGPHAAAAAAAAAF-","ZJjPF65K8mBuISvhCfKfBgAAAAAAAAB4","xLxhp_367a_SbgOYuEJjlwAAAAAAAAAm","QHotkhNTqx5C4Kjd2F2_6wAAAAAAAAEC","Ht79I_xqXv3bOgaClTNQ4wAAAAAAAAKS","G68hjsyagwq6LpWrMjDdngAAAAAAEPcg","G68hjsyagwq6LpWrMjDdngAAAAAAD8dA"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"XbtNNAnLtuHwAR-P2ynwqA":{"address_or_lines":[1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,46454,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,17534,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,64182,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,22670,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1079669,35024,1482046,1829360,2586325,1480953,1480561,1940968,1986869,1946031,1991239,1990411,1912997,3078008,3077552,3072071,1641674,3069796],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aD-GPAkaW-Swis8ybNgyMQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","pv4wAezdMMO0SVuGgaEMTgAAAAAAALV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAER-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAPq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAFiO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","aD-GPAkaW-Swis8ybNgyMQAAAAAAAIjQ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlE1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHbGv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHmJH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHl8L","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHTCl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvd4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALvWw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALuBH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGQzK","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALtdk"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Rr1Z3cNxrq9AQiD8wZZ1dA":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,9150,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52246,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,48350,2789627,1482889,1482415,2595076,1079485,21616,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1079144,37050,1481694,1828960,2581297,2595076,1079144,2994,1480209,1940645,1970099,1481300,1480601,2595076,1067831,41714,39750,33948,33384,25926,33098,33348,34466,32098,39462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","HENgRXYeEs7mDD8Gk_MNmg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fFS0upy5lIaT99RhlTN5LQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lSdGU4igLMOpLhL_6XP15w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","QAp_Nt6XUeNsCXnAUgW7Xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","20O937106XMbOD0LQR4SPw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","HENgRXYeEs7mDD8Gk_MNmgAAAAAAACO-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fFS0upy5lIaT99RhlTN5LQAAAAAAAMwW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","lSdGU4igLMOpLhL_6XP15wAAAAAAALze","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","20O937106XMbOD0LQR4SPwAAAAAAAAuy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEEs3","gPzb0fXoBe1225fbKepMRAAAAAAAAKLy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAISc","_lF8o5tJDcePvza_IYtgSQAAAAAAAIJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAAGVG","E2b-mzlh_8261-JxcySn-AAAAAAAAIFK","E2b-mzlh_8261-JxcySn-AAAAAAAAIJE","E2b-mzlh_8261-JxcySn-AAAAAAAAIai","E2b-mzlh_8261-JxcySn-AAAAAAAAH1i","JrU1PwRIxl_8SXdnTESnogAAAAAAAJom"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1]},"gESQTq4qRn3wnW-FPfxOfA":{"address_or_lines":[2790352,1482889,1482415,2595076,1079485,62190,63732,7014,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,43746,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,2842,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,48542,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1050939,4144,1371605,1977020,2595076,1079485,8954,1479772,3459845,1479516,2595076,1072525,58674,1646337,3072295,1865241,10490014,423063,2283967,2281306,2510155,2414579,2398792,2385273,8471624],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lTFhQHSZwvS4-s94KVv5mA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","IcJVDEq52FRv22q0yHVMaw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","BDtQyw375W96A0PA_Z7SDQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0","eV_m28NnKeeTL60KO2H3SAAAAAAAABtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAAKri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAAsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAAL2e","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAk7","lTFhQHSZwvS4-s94KVv5mAAAAAAAABAw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFO3V","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHiq8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","IcJVDEq52FRv22q0yHVMawAAAAAAACL6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANMsF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEF2N","BDtQyw375W96A0PA_Z7SDQAAAAAAAOUy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGR8B","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a","A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L","A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz","A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI","A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5","A2oiHVwisByxRn5RDT4LjAAAAAAAgURI"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,1,3,3,3,3,3,1,3,3,3,4,4,4,4,4,4,4,4,4]},"CSpdzACT53hVs5DyKY8X5A":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,13654,16860,52596,11060,58864,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,36842,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,30778,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,47130,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,51886,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1592,33110,6110,3227324,1844695,1847563,1702665,1680736,1865128],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","skFt9oVHBFfMDC1On4IJhg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","g5zhfSuJlGbmNqPl5Qb2wg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","UoMth5MLnZ-vUHeTplwEvA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAADVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAEHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAM10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAI_q","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","skFt9oVHBFfMDC1On4IJhgAAAAAAAHg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","g5zhfSuJlGbmNqPl5Qb2wgAAAAAAALga","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","UoMth5MLnZ-vUHeTplwEvAAAAAAAAMqu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABfe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMT68","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGfsJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGaVg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"AlH3zgnqwh5sdMMzX8AXxg":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52130,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,61558,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17970,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1066158,3868,39750,21660,21058,64084,29144,22318,29144,18030,1840882,1970521,2595076,1049850,1910],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Gxt7_MN7XgUOe9547JcHVQ"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAMui","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAT6","Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,1]},"ysEqok7gFOl9eLMLBwFm1g":{"address_or_lines":[29422,31480,4464,18140,2573747,2594708,1091475,64774,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,18042,2789627,1482889,1482415,2595076,1079485,25712,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,2618,2790352,1482889,1482415,2595076,1079144,29422,31306,36256,31544,18122,5412,1481694,1829583,2567913,1848405,1978470,1481567,1493928,2595076,1079144,54286,19054,47612,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1073749,55752,56134,25756,25504,3350479,3072521,1865128],"file_ids":["ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","XkOSW26Xa6_lkqHv5givKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2L4SW1rQgEVXRj3pZAI3nQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","7bd6QJSfWZZfOOpDMHqLMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","J3wpF3Lf_vPkis4aNGKFbw","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","XkOSW26Xa6_lkqHv5givKgAAAAAAAP0G","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEZ6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAAo6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4","h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-rP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy7p","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDRV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHjBm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO","TBeSzkyqIwKL8td602zDjAAAAAAAAEpu","NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","J3wpF3Lf_vPkis4aNGKFbwAAAAAAANnI","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAGSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAGOg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMx_P","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuIJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHWo"],"type_ids":[1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,3,3,3]},"7B48NKNivOFEka6-8dK3Qg":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,8722,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,20598,2790352,1482889,1482415,2595076,1079485,33518,35060,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,41538,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,40098,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1074318,25764,6982,46236,45634,23124,53720,46894,53720,46894,53720,46894,53720,47420,41028,1347096],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","zpgqltXEgKujOhJUj-jAhg","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAACIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAAKJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGSO","MsEmysGbXhMvgdbwhcZDCgAAAAAAAGSk","jtp3NDFNJGnK6sK5oOFo8QAAAAAAABtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc","_lF8o5tJDcePvza_IYtgSQAAAAAAALJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALk8","zpgqltXEgKujOhJUj-jAhgAAAAAAAKBE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFI4Y"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3]},"OC533YmmMZSw8TjJz41YiQ":{"address_or_lines":[19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,27150,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,42322,2795776,1483241,1482767,2600004,1079483,19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079483,19534,21076,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,33092,2578675,2599636,1091600,30298,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,32876,16726,62090,20547,1659254,1860268],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","6GGFIt18C0VByIn0h-PdeQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","SA64oIT_DC3uHXf7ZjFqkw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","akZOzI9XwsEixvkTDGeDPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","6GGFIt18C0VByIn0h-PdeQAAAAAAAGoO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","SA64oIT_DC3uHXf7ZjFqkwAAAAAAAKVS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","akZOzI9XwsEixvkTDGeDPwAAAAAAAHZa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAPKK","ASi9f26ltguiwFajNwOaZwAAAAAAAFBD","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGVF2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHGKs"],"type_ids":[1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"X6-W250nbzzPy4NasjncWg":{"address_or_lines":[23630,25514,30464,8440,12298,26148,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,38814,1470,22780,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,51026,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,47386,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,324,2578675,2599636,1091600,19506,2795051,1483241,1482767,2600004,1079483,19920,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1073803,23630,25688,64176,108,16726,29410,2852079,2851771,2849353,2846190,2849331,2846638,1439925,1865566,1029925,10490014,422731,937148],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","AtF9VdLKnFQvB9H1lsFPjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Pf1McBfrZjVj1CxRZBq6Yw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAHcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAACD4","h0l-9tGi18mC40qpcJbyDwAAAAAAADAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAGYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAAJee","TBeSzkyqIwKL8td602zDjAAAAAAAAAW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAFj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAMdS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","AtF9VdLKnFQvB9H1lsFPjAAAAAAAALka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Pf1McBfrZjVj1CxRZBq6YwAAAAAAAEwy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs","p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHLi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3oz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2-u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFfi1","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHde","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAD7cl","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnNL","ew01Dk0sWZctP-VaEpavqQAAAAAADky8"],"type_ids":[1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,4,4,4]},"gi6S4ODPtJ-ERYxlMd4WHA":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1091600,55462,2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1091600,63874,2795776,1483241,1482767,2600004,1074397,60494,62552,35504,61764,2578675,2599636,1074067,0,29636,2577481,2934013,1108250,1105981,1310350,1245864,1200348,1190613,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165561,1146206,1245475,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165783,1162744,1226823,1225457,1224431,1198830,1177316,1176308,1173405,1172711,1172023,1171335,1170723,1169827,1169015,1167328,1166449,1165323,1165909],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","vkeP2ntYyoFN0A16x9eliw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAANim","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAPmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGOT","_____________________wAAAAAAAAAA","vkeP2ntYyoFN0A16x9eliwAAAAAAAHPE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1RJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALMT9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEOA9","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAE_6O","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwKo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAElDc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEirV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEX1e","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEwEj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcnX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEb34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErhH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAErLx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEq7v","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEkru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfbk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEfL0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeed","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeTn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEeI3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd-H","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEd0j","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdmj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEdZ3","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEc_g","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcxx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcgL","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEcpV"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"EGm59IOxpyqZq7sEwgZb1g":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,36,38,174,104,68,16,140,10,38,174,104,68,48,1992440,1112453,1098694,1112047],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","H5LY_MytOVgyAawi8TymCg","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","kUJz0cDHgh-y1O5Hi8equA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","H5LY_MytOVgyAawi8TymCgAAAAAAAAAQ","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","kUJz0cDHgh-y1O5Hi8equAAAAAAAAAAw","G68hjsyagwq6LpWrMjDdngAAAAAAHmb4","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEMPG","G68hjsyagwq6LpWrMjDdngAAAAAAEPfv"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"y7cw8NxReMWOs4KtDlMCFA":{"address_or_lines":[40014,41898,46848,24824,28682,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,17854,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,11362,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,14618,2795776,1483241,1482767,2600004,1074397,40014,42072,15024,28996,2578675,2599636,1091600,22130,2795051,1483241,1482767,2600004,1079483,36304,50342,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1079669,40014,42072,15024,28780,33110,57790,1480561,1827950,3236393,1482344,1535086,3273255,1482344,1535086,3245980,67155,10485923,16964,15598,703171,2759460,3901948,3791884,3567755],"file_ids":["LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","AtF9VdLKnFQvB9H1lsFPjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Pf1McBfrZjVj1CxRZBq6Yw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","eOfhJQFIxbIEScd007tROw","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAALcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAGD4","h0l-9tGi18mC40qpcJbyDwAAAAAAAHAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAEW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAACxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","AtF9VdLKnFQvB9H1lsFPjAAAAAAAADka","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","Pf1McBfrZjVj1CxRZBq6YwAAAAAAAFZy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY","J1eggTwSzYdi9OsSu1q37gAAAAAAADqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAOG-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-Ru","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMWIp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp5o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAF2xu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMfIn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp5o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAF2xu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAMYec","eOfhJQFIxbIEScd007tROwAAAAAAAQZT","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEJE","ew01Dk0sWZctP-VaEpavqQAAAAAAADzu","ew01Dk0sWZctP-VaEpavqQAAAAAACrrD","ew01Dk0sWZctP-VaEpavqQAAAAAAKhsk","ew01Dk0sWZctP-VaEpavqQAAAAAAO4n8","ew01Dk0sWZctP-VaEpavqQAAAAAAOdwM","ew01Dk0sWZctP-VaEpavqQAAAAAANnCL"],"type_ids":[1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"L1ZLG1mjktr2Zy0xiQnH0w":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,178,1090933,1814182,788459,788130,1197048,1243204,1201241,1245991,1245236,1171829,2265239,2264574,2258463,1169067],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAACy","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvhE","G68hjsyagwq6LpWrMjDdngAAAAAAElRZ","G68hjsyagwq6LpWrMjDdngAAAAAAEwMn","G68hjsyagwq6LpWrMjDdngAAAAAAEwA0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAEdar"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEpy8":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEm_I":{"file_name":[],"function_name":["futex_wake"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAC75T":{"file_name":[],"function_name":["wake_up_q"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAC7oE":{"file_name":[],"function_name":["try_to_wake_up"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgljd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEqQj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEpsM":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAEm4Y":{"file_name":[],"function_name":["futex_wake"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAC75D":{"file_name":[],"function_name":["wake_up_q"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAC7n0":{"file_name":[],"function_name":["try_to_wake_up"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAgkRd":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAM58I":{"file_name":[],"function_name":["kernfs_dop_revalidate"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgMJg":{"file_name":[],"function_name":["strcmp"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI":{"file_name":["libmount/src/tab_parse.c"],"function_name":["__mnt_table_parse_mtab"],"function_offset":[],"line_number":[1102]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W":{"file_name":["libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_file"],"function_offset":[],"line_number":[707]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAXu2":{"file_name":["libmount/src/tab_parse.c","libmount/src/tab_parse.c","/usr/include/bits/stdio.h"],"function_name":["mnt_table_parse_stream","mnt_table_parse_next","getline"],"function_offset":[],"line_number":[643,453,117]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAABrQw":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/libio/iogetdelim.c"],"function_name":["_IO_getdelim"],"function_offset":[],"line_number":[114]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB20S":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/libio/fileops.c"],"function_name":["_IO_new_file_underflow"],"function_offset":[],"line_number":[584]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALKCV":{"file_name":[],"function_name":["seq_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALspQ":{"file_name":[],"function_name":["show_mountinfo"],"function_offset":[],"line_number":[]},"LHNvPtcKBt87cCBX8aTNhQAAAAAAABD4":{"file_name":[],"function_name":["ovl_show_options"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALKWO":{"file_name":[],"function_name":["seq_escape"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgL-e":{"file_name":[],"function_name":["strlen"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1":{"file_name":[],"function_name":["__x64_sys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM":{"file_name":[],"function_name":["ksys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8":{"file_name":[],"function_name":["iterate_dir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ":{"file_name":[],"function_name":["proc_pid_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu":{"file_name":[],"function_name":["next_tgid"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACq1j":{"file_name":[],"function_name":["pid_nr_ns"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqah":{"file_name":[],"function_name":["__x64_sys_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM":{"file_name":[],"function_name":["do_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7":{"file_name":[],"function_name":["__do_pipe_flags"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqN7":{"file_name":[],"function_name":["create_pipe_files"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ":{"file_name":[],"function_name":["unix_stream_read_actor"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg5J":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALB_i":{"file_name":[],"function_name":["__fdget_pos"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALBST":{"file_name":[],"function_name":["__fget_light"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu8M":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyL":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKr18":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKqx4":{"file_name":[],"function_name":["follow_managed"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAALEDf":{"file_name":[],"function_name":["lookup_mnt"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAALEA_":{"file_name":[],"function_name":["__lookup_mnt"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyx":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKrUd":{"file_name":[],"function_name":["inode_permission"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAMzQW":{"file_name":[],"function_name":["kernfs_iop_permission"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAgRuk":{"file_name":[],"function_name":["mutex_lock"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhDw":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg38":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKePq":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePZt":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAeOlF":{"file_name":[],"function_name":["maybe_add_creds"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAePaV":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZrqL":{"file_name":[],"function_name":["sock_def_readable"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADXb2":{"file_name":[],"function_name":["__wake_up_common_lock"],"function_offset":[],"line_number":[]},"lLD39yzd4Cg8F13tcGpzGQAAAAAAABuG":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"LEy-wm0GIvRoYVAga55HiwAAAAAAACxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAADRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAMqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAB5A":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAMum":{"file_name":["functools.py"],"function_name":["register"],"function_offset":[50],"line_number":[902]},"xUQuo4OgBaS_Le-fdAwt8AAAAAAAAIHw":{"file_name":["functools.py"],"function_name":["_is_union_type"],"function_offset":[2],"line_number":[843]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAADBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAKLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkft":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASheR":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr":{"file_name":[],"function_name":["copy_user_generic_string"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEIE":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAADyu":{"file_name":[],"function_name":["exit_to_usermode_loop"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACrwD":{"file_name":[],"function_name":["task_work_run"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgtU":{"file_name":[],"function_name":["__fput"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOyMM":{"file_name":[],"function_name":["xfs_release"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOXPc":{"file_name":[],"function_name":["xfs_free_eofblocks"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAANg6m":{"file_name":[],"function_name":["xfs_bmapi_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAOB7F":{"file_name":[],"function_name":["xfs_iext_lookup_extent"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpAW":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAczF0":{"file_name":[],"function_name":["tcp_v4_send_check"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZ0Bt":{"file_name":[],"function_name":["__kfree_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZ0vq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAIAP0":{"file_name":[],"function_name":["__put_page"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7mG":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7j0":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKZkE":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9":{"file_name":[],"function_name":["__kmalloc_reserve.isra.57"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR":{"file_name":[],"function_name":["__kmalloc_node_track_caller"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk":{"file_name":[],"function_name":["kmalloc_slab"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAmH_":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_connect"],"function_offset":[],"line_number":[345]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAAAhZ-":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/s3_clnt.c"],"function_name":["ssl3_get_server_certificate"],"function_offset":[],"line_number":[1255]},"9HZ7GQCC6G9fZlRD7aGzXQAAAAAABFsM":{"file_name":["/usr/src/debug/openssl-1.0.2k/ssl/ssl_cert.c"],"function_name":["ssl_verify_cert_chain"],"function_offset":[],"line_number":[759]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFdR2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_vfy.c"],"function_name":["X509_verify_cert"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFh_7":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_STORE_CTX_get1_issuer"],"function_offset":[],"line_number":[617]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhe5":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_STORE_get_by_subject"],"function_offset":[],"line_number":[306]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhdI":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["X509_OBJECT_retrieve_by_subject"],"function_offset":[],"line_number":[480]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhIu":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["x509_object_idx_cnt"],"function_offset":[],"line_number":[454]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiFg":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["internal_find"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiEp":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["sk_sort"],"function_offset":[],"line_number":[374]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1v3":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["__GI___qsort_r","msort_with_tmp"],"function_offset":[],"line_number":[297,45]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1ku":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp","msort_with_tmp"],"function_offset":[],"line_number":[53,159]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1kh":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp","msort_with_tmp"],"function_offset":[],"line_number":[54,159]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAA1nF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/stdlib/msort.c"],"function_name":["msort_with_tmp"],"function_offset":[],"line_number":[83]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFhE-":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_lu.c"],"function_name":["x509_object_cmp"],"function_offset":[],"line_number":[168]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIM9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[266]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFB_E":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_ex_d2i"],"function_offset":[],"line_number":[235]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBue":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["x509_name_canon"],"function_offset":[],"line_number":[390]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFBbE":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/x_name.c"],"function_name":["i2d_name_canon"],"function_offset":[],"line_number":[508]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFGgQ":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_enc.c"],"function_name":["ASN1_item_ex_i2d"],"function_offset":[],"line_number":[148]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFG4p":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_enc.c"],"function_name":["asn1_template_ex_i2d"],"function_offset":[],"line_number":[360]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAEiC3":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/stack/stack.c"],"function_name":["sk_num"],"function_offset":[],"line_number":[344]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAMJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAIsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAIF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAGs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAFhE":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOmcH":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOmYS":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAH0TO":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAHynP":{"file_name":[],"function_name":["pagecache_get_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAHyFT":{"file_name":[],"function_name":["find_get_entry"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJa3-":{"file_name":[],"function_name":["PageHuge"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMev":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"6miIyyucTZf5zXHCk7PT1gAAAAAAAAo8":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaGU2":{"file_name":[],"function_name":["netif_rx"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaGS9":{"file_name":[],"function_name":["netif_rx_internal"],"function_offset":[],"line_number":[]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAADI":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[22],"line_number":[35]},"5sij7Z672VAK_gGoPDPJBgAAAAAAAAA8":{"file_name":["formatter.py"],"function_name":[""],"function_offset":[6],"line_number":[19]},"PCeTYI0HN2oKNST6e1IaQQAAAAAAAABc":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[50],"line_number":[51]},"U4FmFVJMlNKhF1hVl3Xj1AAAAAAAAAAE":{"file_name":["cyaml.py"],"function_name":[""],"function_offset":[0],"line_number":[3]},"JR7ekk9KGQJKKPohpdwCLQAAAAAAAAAK":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[2],"line_number":[1181]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"rpRn_rYC3CgtEgBAUrkZZgAAAAAAAAAU":{"file_name":["error.py"],"function_name":[""],"function_offset":[3],"line_number":[6]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAACrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAB9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"okehWevKsEA4q6dk779jgwAAAAAAAH1M":{"file_name":["session.py"],"function_name":["get_credentials"],"function_offset":[12],"line_number":[445]},"-IuadWGT89NVzIyF_EmodwAAAAAAAMKw":{"file_name":["credentials.py"],"function_name":["load_credentials"],"function_offset":[18],"line_number":[1953]},"XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08":{"file_name":["credentials.py"],"function_name":["load"],"function_offset":[18],"line_number":[1009]},"FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa":{"file_name":["utils.py"],"function_name":["retrieve_iam_role_credentials"],"function_offset":[30],"line_number":[517]},"pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a":{"file_name":["utils.py"],"function_name":["_get_iam_role"],"function_offset":[1],"line_number":[524]},"IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK":{"file_name":["utils.py"],"function_name":["_get_request"],"function_offset":[32],"line_number":[435]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"fB79lJck2X90l-j7VqPR-QAAAAAAAGc8":{"file_name":["connectionpool.py"],"function_name":["_make_request"],"function_offset":[116],"line_number":[494]},"gbMheDI1NZ3NY96J0seddgAAAAAAAEuq":{"file_name":["client.py"],"function_name":["getresponse"],"function_offset":[58],"line_number":[1389]},"GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w":{"file_name":["client.py"],"function_name":["__init__"],"function_offset":[28],"line_number":[276]},"_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI":{"file_name":["socket.py"],"function_name":["makefile"],"function_offset":[40],"line_number":[343]},"piWSMQrh4r040D0BPNaJvwAAAAAAZZ-N":{"file_name":[],"function_name":["__sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZYo3":{"file_name":[],"function_name":["___sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXwf":{"file_name":[],"function_name":["____sys_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjN":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAet8Y":{"file_name":[],"function_name":["udpv6_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAActW-":{"file_name":[],"function_name":["udp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb90r":{"file_name":[],"function_name":["ip_make_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb8Hg":{"file_name":[],"function_name":["__ip_append_data.isra.50"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZdo2":{"file_name":[],"function_name":["sock_alloc_send_pskb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlYi":{"file_name":[],"function_name":["alloc_skb_with_frags"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZjzl":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJr8u":{"file_name":[],"function_name":["__ksize"],"function_offset":[],"line_number":[]},"grZNsSElR5ITq8H2yHCNSwAAAAAAANbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAPAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAFQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAAHVG":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"cBO14nNDW8EW0oaZDaZipwAAAAAAAOiW":{"file_name":["session.py"],"function_name":["_resolve_region_name"],"function_offset":[20],"line_number":[876]},"C64RiOp1JIPwHLB_iHDa0AAAAAAAAHNm":{"file_name":["session.py"],"function_name":["get_config_variable"],"function_offset":[4],"line_number":[253]},"xvApUwdY2y4sFaZRNrMv5gAAAAAAAEoq":{"file_name":["configprovider.py"],"function_name":["get_config_variable"],"function_offset":[19],"line_number":[316]},"vsalcPHh9qLgsdKtk190IAAAAAAAAFQg":{"file_name":["configprovider.py"],"function_name":["provide"],"function_offset":[11],"line_number":[416]},"QsuqlohtoJfpo6vQ6tHa2AAAAAAAANS-":{"file_name":["utils.py"],"function_name":["provide"],"function_offset":[3],"line_number":[116]},"8ep9l3WIVYErRiHtmAdvewAAAAAAANI2":{"file_name":["utils.py"],"function_name":["_get_instance_metadata_region"],"function_offset":[3],"line_number":[121]},"nPWpQrEmCn54Ou0__aZyJAAAAAAAACsQ":{"file_name":["utils.py"],"function_name":["retrieve_region"],"function_offset":[19],"line_number":[172]},"-xcELApECIipEESUIWed9wAAAAAAAC7-":{"file_name":["utils.py"],"function_name":["_get_region"],"function_offset":[9],"line_number":[185]},"L_saUsdri-UdXCut6TdtngAAAAAAAO5i":{"file_name":["utils.py"],"function_name":["_fetch_metadata_token"],"function_offset":[28],"line_number":[400]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAFIW":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"p19NBQ2pky4eRJM7tgeenwAAAAAAALGU":{"file_name":["httpsession.py"],"function_name":["proxy_url_for"],"function_offset":[6],"line_number":[222]},"55ABUc9FqQ0uj-yn-sTq2AAAAAAAAKaI":{"file_name":["parse.py"],"function_name":["urlparse"],"function_offset":[28],"line_number":[393]},"1msFlmxT18lYvJkx-hfGPgAAAAAAAF1K":{"file_name":["parse.py"],"function_name":["urlsplit"],"function_offset":[49],"line_number":[481]},"a5aMcPOeWx28QSVng73nBQAAAAAAAABK":{"file_name":["aws"],"function_name":[""],"function_offset":[13],"line_number":[27]},"inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[2],"line_number":[166]},"Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[3],"line_number":[185]},"cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[8],"line_number":[97]},"T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[23],"line_number":[48]},"lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[1],"line_number":[62]},"SMoSw8cr-PdrIATvljOPrQAAAAAAAABU":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[8],"line_number":[76]},"xaCec3W8F6xlvd_EISI7vwAAAAAAAACA":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[16],"line_number":[29]},"GYpj0RgmHJTfD-_w_Fx69wAAAAAAAABA":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[7],"line_number":[20]},"b78FoZPzgl20nGrU0Zu24gAAAAAAAABU":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[22]},"5ZxW56RI3EOJxqCWjdkdHgAAAAAAAABk":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[12],"line_number":[17]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"7l7IlhF_Z6_Ribw1CW945QAAAAAAAAA8":{"file_name":["ec.py"],"function_name":[""],"function_offset":[8],"line_number":[13]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAAm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[5],"line_number":[291]},"imaY9TOf2pKX0_q1vRTskQAAAAAAAAAg":{"file_name":["pyimod01_archive.py"],"function_name":["__enter__"],"function_offset":[8],"line_number":[87]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAANka":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAEbO":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAAI7O":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAAAmc":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAKbk":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"grikUXlisBLUbeL_OWixIwAAAAAAALZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAN9c":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAAH78":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"Kq9d0b1CBVEQZUtuJtmlJgAAAAAAAAT8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[526]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAPjQ":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAOwU":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKsux":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAALbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAANAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAADQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAJ-e":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"wpss7yv4AvkSwbtctTl0JAAAAAAAAANC":{"file_name":["clidriver.py"],"function_name":["_display_response"],"function_offset":[7],"line_number":[952]},"SLUxdgyFrTF3l4NU1VRO_wAAAAAAAOMY":{"file_name":["formatter.py"],"function_name":["__call__"],"function_offset":[23],"line_number":[91]},"ZOgaFnYiv38tVz-8Hafu3wAAAAAAADCy":{"file_name":["paginate.py"],"function_name":["build_full_result"],"function_offset":[43],"line_number":[487]},"u1Za6xFXDX1Ys5Qeh_gy9QAAAAAAAMWW":{"file_name":["paginate.py"],"function_name":["__iter__"],"function_offset":[16],"line_number":[251]},"uq4_q8agTQ0rkhJvygJ3QAAAAAAAAGag":{"file_name":["paginate.py"],"function_name":["_make_request"],"function_offset":[1],"line_number":[329]},"pK0zxAMiW-X23QjQRVzm5wAAAAAAAOu8":{"file_name":["client.py"],"function_name":["_api_call"],"function_offset":[4],"line_number":[337]},"OP7EiuTwTtWCf_B7a-ZpigAAAAAAAIUk":{"file_name":["client.py"],"function_name":["_make_api_call"],"function_offset":[58],"line_number":[699]},"WyVrojmISSgbkYAxEOnpQwAAAAAAAKcu":{"file_name":["client.py"],"function_name":["_make_request"],"function_offset":[3],"line_number":[704]},"JdWBEAqhrU7LJg0YDuYO0wAAAAAAANaq":{"file_name":["endpoint.py"],"function_name":["make_request"],"function_offset":[3],"line_number":[101]},"cwZEcJVCN5Q4BJdAS3o8fwAAAAAAABLk":{"file_name":["endpoint.py"],"function_name":["_send_request"],"function_offset":[28],"line_number":[157]},"iLNvi1vqLkBP_ehg4QlqeAAAAAAAAJ7U":{"file_name":["endpoint.py"],"function_name":["_get_response"],"function_offset":[18],"line_number":[177]},"guXM5tmjJlv0Ehde0y1DFwAAAAAAAPLs":{"file_name":["endpoint.py"],"function_name":["_do_get_response"],"function_offset":[48],"line_number":[232]},"avBEfFKeFSrhKf93SLNe0QAAAAAAAKtK":{"file_name":["endpoint.py"],"function_name":["_send"],"function_offset":[1],"line_number":[271]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAADQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAABVw":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"aAagm2yDcrnYaqBPCwyu8QAAAAAAAE8g":{"file_name":["awsrequest.py"],"function_name":["copy"],"function_offset":[1],"line_number":[605]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAL_G":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAOMM":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAL2-":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"lpUCR1NQj5NOLBg7mvzlqgAAAAAAAPi6":{"file_name":["generatecliskeleton.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAOKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAAT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAABF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAACLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAMFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAEu2":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"08DBZKRu4nC_Oi_uT40UHwAAAAAAAOyO":{"file_name":["codecommit.py"],"function_name":[""],"function_offset":[156],"line_number":[157]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAACpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAD2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"n74P5OxFm1hAo5ZWtgcKHQAAAAAAALGe":{"file_name":["__init__.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[93]},"zXbqXCWr0lCbi_b24hNBRQAAAAAAAOI0":{"file_name":["pyimod02_importers.py"],"function_name":["find_spec"],"function_offset":[87],"line_number":[302]},"AOM_-6oRTyAxK8W79Wo5aQAAAAAAAErq":{"file_name":["pyimod02_importers.py"],"function_name":["get_filename"],"function_offset":[12],"line_number":[212]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAABc6":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"ik6PIX946fW_erE7uBJlVQAAAAAAABLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAABr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAM6e":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"N0GNsPaCLYzoFsPJWnIJtQAAAAAAAK8u":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[53],"line_number":[54]},"fq0ezjB8ddCA6Pk0BY9arQAAAAAAAH4C":{"file_name":["distro.py"],"function_name":[""],"function_offset":[608],"line_number":[609]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAAkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAFci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAHYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE":{"file_name":["application.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAAAQ":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"RDOEyok4432cuMjL10_tugAAAAAAAAEA":{"file_name":["base_events.py"],"function_name":[""],"function_offset":[44],"line_number":[45]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"25JFhMXA0rvP5hfyUpf34wAAAAAAAAAc":{"file_name":["typing.py"],"function_name":["Optional"],"function_offset":[7],"line_number":[479]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAB4":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[24],"line_number":[161]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAJci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAFEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAA8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAHhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAGeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAI58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAADTm":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAKzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAGYa":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAABW2":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"ZLTqiSLOmv4Ej_7d8yKLmwAAAAAAAEGM":{"file_name":["client.py"],"function_name":["_get_client_args"],"function_offset":[15],"line_number":[295]},"v_WV3HQYVe0q1Ob-1gtx1AAAAAAAAP0W":{"file_name":["args.py"],"function_name":["get_client_args"],"function_offset":[72],"line_number":[118]},"ka2IKJhpWbD6PA3J3v624wAAAAAAAElW":{"file_name":["copy.py"],"function_name":["copy"],"function_offset":[35],"line_number":[101]},"e8Lb_MV93AH-OkvHPPDitgAAAAAAAI5y":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[6],"line_number":[344]},"1vivUE5hL65442lQ9a_ylgAAAAAAAEOi":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[8],"line_number":[486]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKvK":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fh_7rTxpgngJ2cX2lBjVdgAAAAAAAKtu":{"file_name":["hooks.py"],"function_name":["_recursive_copy"],"function_offset":[12],"line_number":[500]},"fCsVLBj60GK9Hf8VtnMcgAAAAAAAADSW":{"file_name":["hooks.py"],"function_name":["__copy__"],"function_offset":[5],"line_number":[35]},"54xjnvwS2UtwpSVJMemggAAAAAAAAGsE":{"file_name":[""],"function_name":[""],"function_offset":[0],"line_number":[1]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"qordvIiilnF7CmkWCAd7eAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"okgAOHfDrcA806m5xh4DMAAAAAAAAACs":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAAMLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAC8C":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"aRRT4_vBG9Q4nqyirWo5FAAAAAAAAJZa":{"file_name":["codedeploy.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4":{"file_name":["abc.py"],"function_name":[""],"function_offset":[267],"line_number":[268]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAG6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAAMhK":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"ZyAwfhB8pqBFv6xiDVdvPQAAAAAAAKh2":{"file_name":["credentials.py"],"function_name":[""],"function_offset":[553],"line_number":[554]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAMpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAN2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"9alsKcnSosScCQ3ntwGT5wAAAAAAAKlg":{"file_name":["_bootstrap_external.py"],"function_name":["find_spec"],"function_offset":[22],"line_number":[1518]},"xAINw9zPBhJlledr3DAcGAAAAAAAAK4I":{"file_name":["_bootstrap_external.py"],"function_name":["_get_spec"],"function_offset":[29],"line_number":[1493]},"xVweU0pD8q051c2YgF4PTwAAAAAAAH1m":{"file_name":["_bootstrap_external.py"],"function_name":["find_spec"],"function_offset":[43],"line_number":[1647]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAOAO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"d4jl580PLMUwu5s3I4wcXgAAAAAAAISu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"tKago5vqLnwIkezk_wTBpQAAAAAAAOfq":{"file_name":["package.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAF6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAALg6":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAAJDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAAKO6":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAJkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAKYy":{"file_name":["auth.py"],"function_name":[""],"function_offset":[603],"line_number":[604]},"y9R94bQUxts02WzRWfV7xgAAAAAAAC_y":{"file_name":["auth.py"],"function_name":[""],"function_offset":[316],"line_number":[317]},"uI6css-d8SGQRK6a_Ntl-AAAAAAAAD3e":{"file_name":["auth.py"],"function_name":[""],"function_offset":[336],"line_number":[337]},"SlnkBp0IIJFLHVOe4KbxwQAAAAAAAJLa":{"file_name":["http.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"7wBb3xHP1JZHNBpMGh4EdAAAAAAAADGa":{"file_name":["io.py"],"function_name":[""],"function_offset":[408],"line_number":[409]},"u3fGdgL6eAYjYSRbRUri0gAAAAAAAFUY":{"file_name":["io.py"],"function_name":["SocketDomain"],"function_offset":[3],"line_number":[194]},"aG0mH34tM6si5c1l397JVQAAAAAAAOwA":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[93],"line_number":[457]},"GC-VoGaqaEobPzimayHQTQAAAAAAANdk":{"file_name":["enum.py"],"function_name":["_is_sunder"],"function_offset":[4],"line_number":[62]},"PmhxUKv5sePRxhCBONca8gAAAAAAAID6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"ik6PIX946fW_erE7uBJlVQAAAAAAAPLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"UfGck3qA2qF0xFB5gpY4HgAAAAAAAH72":{"file_name":["base.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"G9ShE3ODivDEFyHVdsnZ_gAAAAAAABn-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"6AsJ0dA2BUqaic-ScDJBMAAAAAAAACOm":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"fr52ZDCgnkPZlzTNdLTQ5wAAAAAAAGnS":{"file_name":["base.py"],"function_name":[""],"function_offset":[167],"line_number":[168]},"uqoEOAkLp1toolLH0q5LVwAAAAAAAJmm":{"file_name":["mouse_events.py"],"function_name":[""],"function_offset":[63],"line_number":[64]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMFQ":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAJ42":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"WjtMXFj0eujpoknR_rynvAAAAAAAACba":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[800],"line_number":[801]},"Vot4T3F5OpUj8rbXhgpMDgAAAAAAAO8I":{"file_name":["_bootstrap_external.py"],"function_name":["exec_module"],"function_offset":[4],"line_number":[938]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAEtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"EPS0ql6FPdCQLe9KByvDQAAAAAAAAMgy":{"file_name":["traceback.py"],"function_name":[""],"function_offset":[328],"line_number":[329]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAKSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAKJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAAKJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAKA4":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAJp8":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"V6gUZHzBRISi-Z25klK5DQAAAAAAAKri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"zWNEoAKVTnnzSns045VKhwAAAAAAAMsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAAEfO":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"XVsKc4e32xXUv-3uv2s-8QAAAAAAACny":{"file_name":["defaults.py"],"function_name":["emacs_state"],"function_offset":[32],"line_number":[33]},"uPGvGNXBf1JXGeeDSsmGQAAAAAAAALX2":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[194],"line_number":[679]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"OwrnTUowquMzuETYoP67yQAAAAAAAAAe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[4],"line_number":[5]},"HmAocvtnsxREZJIec2I5gwAAAAAAAAA4":{"file_name":["__init__.py"],"function_name":["HTTPStatus"],"function_offset":[41],"line_number":[46]},"KHDki7BxJPyjGLtvY8M5lQAAAAAAAAF-":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[64],"line_number":[152]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAL5W":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"XlQ19HBD_RNa2r3QWOR-nAAAAAAAAP1u":{"file_name":["commands.py"],"function_name":[""],"function_offset":[127],"line_number":[128]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAFRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VuJFonCXevADcEDW6NVbKgAAAAAAAGsG":{"file_name":["devcommands.py"],"function_name":[""],"function_offset":[49],"line_number":[50]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAMsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAAOMa":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAH2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"it1vvnZdXdzy0fFROnaaOQAAAAAAALTQ":{"file_name":["_bootstrap.py"],"function_name":["find_spec"],"function_offset":[28],"line_number":[950]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAOL2":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"XlQ19HBD_RNa2r3QWOR-nAAAAAAAAL1u":{"file_name":["commands.py"],"function_name":[""],"function_offset":[127],"line_number":[128]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAARw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VFBd9VqCaQu0ZzjQ2K3pjgAAAAAAAAsO":{"file_name":["factory.py"],"function_name":[""],"function_offset":[57],"line_number":[58]},"PUSucJs4FC_WdMzOyH3QYwAAAAAAABHq":{"file_name":["layout.py"],"function_name":[""],"function_offset":[130],"line_number":[131]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALC4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAAM8O":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"gZooqVYiItnHim-lK4feOgAAAAAAANN-":{"file_name":["_bootstrap.py"],"function_name":["_init_module_attrs"],"function_offset":[70],"line_number":[563]},"UfGck3qA2qF0xFB5gpY4HgAAAAAAABTm":{"file_name":["base.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"G9ShE3ODivDEFyHVdsnZ_gAAAAAAABs-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[34],"line_number":[35]},"6AsJ0dA2BUqaic-ScDJBMAAAAAAAABbq":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[38],"line_number":[39]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAADSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"VY0EiAO0DxwLRTE4PfFhdwAAAAAAAOMW":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"A8AozG5gQfEN24i4IE7w5wAAAAAAACgG":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[21],"line_number":[22]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAKKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"V6gUZHzBRISi-Z25klK5DQAAAAAAACri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"zWNEoAKVTnnzSns045VKhwAAAAAAAIsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"PmhxUKv5sePRxhCBONca8gAAAAAAAAD6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAEu":{"file_name":["client.py"],"function_name":[""],"function_offset":[1396],"line_number":[1397]},"OPpnYj88CDOiKneikdGPHAAAAAAAAAF-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[138],"line_number":[142]},"ZJjPF65K8mBuISvhCfKfBgAAAAAAAAB4":{"file_name":["enum.py"],"function_name":["_convert_"],"function_offset":[27],"line_number":[555]},"xLxhp_367a_SbgOYuEJjlwAAAAAAAAAm":{"file_name":["enum.py"],"function_name":["__call__"],"function_offset":[28],"line_number":[386]},"QHotkhNTqx5C4Kjd2F2_6wAAAAAAAAEC":{"file_name":["enum.py"],"function_name":["_create_"],"function_offset":[35],"line_number":[510]},"Ht79I_xqXv3bOgaClTNQ4wAAAAAAAAKS":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[122],"line_number":[301]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAALV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAER-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAAPq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAFiO":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"aD-GPAkaW-Swis8ybNgyMQAAAAAAAIjQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[455],"line_number":[456]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAACO-":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAAMwW":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAALze":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAAuy":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAKLy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAISc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAIJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAAGVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIFK":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAIai":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAH1i":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAAJom":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAABtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"zWNEoAKVTnnzSns045VKhwAAAAAAAAsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAAL2e":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"lTFhQHSZwvS4-s94KVv5mAAAAAAAABAw":{"file_name":["renderer.py"],"function_name":[""],"function_offset":[85],"line_number":[86]},"IcJVDEq52FRv22q0yHVMawAAAAAAACL6":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[6],"line_number":[351]},"BDtQyw375W96A0PA_Z7SDQAAAAAAAOUy":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[7],"line_number":[1557]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAIs9a":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJk1L":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJNfz":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJJpI":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAJGV5":{"file_name":[],"function_name":["prep_new_page"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgURI":{"file_name":[],"function_name":["clear_page_erms"],"function_offset":[],"line_number":[]},"grZNsSElR5ITq8H2yHCNSwAAAAAAADVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAEHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAM10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAOXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAI_q":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"skFt9oVHBFfMDC1On4IJhgAAAAAAAHg6":{"file_name":["ddb.py"],"function_name":[""],"function_offset":[26],"line_number":[27]},"g5zhfSuJlGbmNqPl5Qb2wgAAAAAAALga":{"file_name":["subcommands.py"],"function_name":[""],"function_offset":[64],"line_number":[65]},"UoMth5MLnZ-vUHeTplwEvAAAAAAAAMqu":{"file_name":["params.py"],"function_name":[""],"function_offset":[226],"line_number":[227]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABfe":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAMui":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2":{"file_name":["_parser.py"],"function_name":["__len__"],"function_offset":[1],"line_number":[159]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAP0G":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAEZ6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAAo6":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAI2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAHs4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAEbK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAABUk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANQO":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEpu":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAALn8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"J3wpF3Lf_vPkis4aNGKFbwAAAAAAANnI":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAGSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAGOg":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OlTvyWQFXjOweJcs3kiGygAAAAAAACIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAAKJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAGSk":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAABtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALk8":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zpgqltXEgKujOhJUj-jAhgAAAAAAAKBE":{"file_name":["_parser.py"],"function_name":["__getitem__"],"function_offset":[3],"line_number":[165]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"6GGFIt18C0VByIn0h-PdeQAAAAAAAGoO":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"SA64oIT_DC3uHXf7ZjFqkwAAAAAAAKVS":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[48],"line_number":[49]},"akZOzI9XwsEixvkTDGeDPwAAAAAAAHZa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAPKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAHcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAACD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAADAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAGYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAJee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAAW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAFj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAMdS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"AtF9VdLKnFQvB9H1lsFPjAAAAAAAALka":{"file_name":["parser.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"Pf1McBfrZjVj1CxRZBq6YwAAAAAAAEwy":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[443],"line_number":[444]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAE3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHLi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnNL":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADky8":{"file_name":[],"function_name":["down_read_trylock"],"function_offset":[],"line_number":[]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAOxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAPRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAPFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"XkOSW26Xa6_lkqHv5givKgAAAAAAANim":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAPmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"vkeP2ntYyoFN0A16x9eliwAAAAAAAHPE":{"file_name":["__init__.py"],"function_name":["namedtuple"],"function_offset":[164],"line_number":[512]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAk":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[22],"line_number":[27]},"H5LY_MytOVgyAawi8TymCgAAAAAAAAAQ":{"file_name":["_policybase.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"kUJz0cDHgh-y1O5Hi8equAAAAAAAAAAw":{"file_name":["header.py"],"function_name":[""],"function_offset":[14],"line_number":[19]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAJxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAALcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAGD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAHAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAEW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAKRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"fj70ljef7nDHOqVJGSIoEQAAAAAAACxi":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"AtF9VdLKnFQvB9H1lsFPjAAAAAAAADka":{"file_name":["parser.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"Pf1McBfrZjVj1CxRZBq6YwAAAAAAAFZy":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[443],"line_number":[444]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAI3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAMSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAOG-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEJE":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAADzu":{"file_name":[],"function_name":["exit_to_usermode_loop"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACrrD":{"file_name":[],"function_name":["task_work_run"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKhsk":{"file_name":[],"function_name":["__fput"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAO4n8":{"file_name":[],"function_name":["xfs_release"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOdwM":{"file_name":[],"function_name":["xfs_free_eofblocks"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAANnCL":{"file_name":[],"function_name":["xfs_bmapi_read"],"function_offset":[],"line_number":[]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAACy":{"file_name":["errors.py"],"function_name":[""],"function_offset":[45],"line_number":[50]}},"executables":{"edNJ10OjHiWc5nzuTQdvig":"linux-vdso.so.1","LvhLWomlc0dSPYzQ8C620g":"controller","j8DVIOTu7Btj9lgFefJ84A":"dockerd","QvG8QEGAld88D676NL_Y2Q":"filebeat","B8JRxL079xbhqQBqGvksAg":"kubelet","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","v6HIzNa4K6G4nRP9032RIA":"dockerd","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","QaIvzvU8UoclQMd_OMt-Pg":"elastic-operator","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","kajOqZqz7V1y0BdYQLFQrw":"containerd-shim-runc-v2","9LzzIocepYcOjnUsLlgOjg":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","A2oiHVwisByxRn5RDT4LjA":"vmlinux","w5zBqPf1_9mIVEf-Rn7EdA":"systemd","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","OTWX4UsOVMrSIF5cD4zUzg":"libmount.so.1.1.0","LHNvPtcKBt87cCBX8aTNhQ":"overlay","67s2TwiMngM0yin5Y8pvEg":"containerd","piWSMQrh4r040D0BPNaJvw":"vmlinux","SbPwzb_Kog2bWn8uc7xhDQ":"aws","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","9HZ7GQCC6G9fZlRD7aGzXQ":"libssl.so.1.0.2k","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","6miIyyucTZf5zXHCk7PT1g":"veth","G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","JsObMPhfT_zO2Q_B1cPLxA":"coredns","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","dGWvVtQJJ5wuqNyQVpi8lA":"zlib.cpython-311-x86_64-linux-gnu.so"},"total_frames":198526,"sampling_rate":0.0016000000000000003} diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_60s_1x.json b/x-pack/plugins/profiling/common/__fixtures__/stacktraces_60s_1x.json deleted file mode 100644 index 8a5c1acf7f93..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_60s_1x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"YdDJxgmO4Qwjr0AEbbpw5g":3,"ARUlXLnccHmzguHUjXRt-A":7,"fsUmzqifyqwKCmzKO1INZQ":24,"z_Kbu_3KsKjzL49rf-CSTA":94,"RpSSZ069-ac11a4PUFolMA":101,"H4U5LLhN4L_4fDVbcrz30A":57,"8jSwzubV-3-vgAsXwII0kA":26,"43tbk4XHS6h_eSSkozr2lQ":33,"1Hf53oSb-zH-2QD2FYxgyA":27,"ER-x6xVv257WtFQAI5qb9g":47,"Hr1OSWigQhS4BD9n1H0fVw":40,"g1qDjUCVlmghGHVDrjeDvw":44,"XU0AYWfaWEgxn6HS3Npe0Q":42,"Xi_OuuwxmtjxVLfRnOKl-w":43,"j3pRZrJva_6zVfPpTrRgMQ":34,"B0rzVoKcdftibP3e40EU_g":39,"jHWwY4al2R105ljWitJf8Q":51,"JFrKrVm1b8YVyjTALHwFPQ":17,"UkNqUaLVbzZ-0N4mRSSfPA":7,"EH1ElzcXDEuDqu7McdrBdQ":17,"VyF1fKBkXgRmNRnKNEu8Fw":23,"naNkvUaKAyxw8L7AmrJp_A":25,"INCPC3idrKxHgrRrb5yK7w":18,"4-XWrzbKLiMzMN29SCKUhA":18,"oazzZOrFVKPzoEMEINIH2g":14,"bgW4z1P_qeyGZ-BNg-EtzA":21,"_7muG2H-TTX5D3mi3LROgw":17,"nKCqWW03DZONEM_Nq2LvwQ":6,"08TjeY9jNFfBuPDWZvzcGA":16,"41gF_giRSTRZMXWPVpvLYA":10,"CCCw9Z7XCAUBXfzhCKjvyQ":12,"RK2MfkyDuA83Ote1DRpnig":9,"E9YrFLZE6ytYTLr5nOdeqA":8,"OaI2ikXPfU9oPJVr7qHqRA":6,"BeervgrHDOwHnECUdx-R1Q":1,"_E7kI3XeP50ndUGgLwozRw":1,"PiAbunsxsTWIrlVv5AJCxQ":2,"gcylfs4yiiRtiY_AHc1fkQ":2,"2J6chKI2om9Kbvwi1SgqlA":1,"YX2R7C2iz4FGt5q5Tnk6TA":1,"--7TGRswVMtk5qWYdGBDUw":1,"iVZ81pgajC_4cYBykPWgBg":1,"dg33Fg5TLDtB9bOuPSPREA":1},"stack_traces":{"YdDJxgmO4Qwjr0AEbbpw5g":{"address_or_lines":[2371],"file_ids":["Ij7mO1SCteAnvtNe95RpEg"],"frame_ids":["Ij7mO1SCteAnvtNe95RpEgAAAAAAAAlD"],"type_ids":[3]},"ARUlXLnccHmzguHUjXRt-A":{"address_or_lines":[4651602,2352],"file_ids":["B56YkhsK1JwqD-8F8sjS3A","Ij7mO1SCteAnvtNe95RpEg"],"frame_ids":["B56YkhsK1JwqD-8F8sjS3AAAAAAARvpS","Ij7mO1SCteAnvtNe95RpEgAAAAAAAAkw"],"type_ids":[3,3]},"fsUmzqifyqwKCmzKO1INZQ":{"address_or_lines":[32434917,32101228,32118123],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6hVr"],"type_ids":[3,3,3]},"z_Kbu_3KsKjzL49rf-CSTA":{"address_or_lines":[4646312,4318297,4332979,4334816],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQeRZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAQh2z","FWZ9q3TQKZZok58ua1HDsgAAAAAAQiTg"],"type_ids":[3,3,3,3]},"RpSSZ069-ac11a4PUFolMA":{"address_or_lines":[4646178,4471372,4470064,4464366,4415263],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuUi","FWZ9q3TQKZZok58ua1HDsgAAAAAARDpM","FWZ9q3TQKZZok58ua1HDsgAAAAAARDUw","FWZ9q3TQKZZok58ua1HDsgAAAAAARB7u","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ18f"],"type_ids":[3,3,3,3,3]},"H4U5LLhN4L_4fDVbcrz30A":{"address_or_lines":[12531204,12361900,12360536,12355924,12307483,12548548],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAvzYE","67s2TwiMngM0yin5Y8pvEgAAAAAAvKCs","67s2TwiMngM0yin5Y8pvEgAAAAAAvJtY","67s2TwiMngM0yin5Y8pvEgAAAAAAvIlU","67s2TwiMngM0yin5Y8pvEgAAAAAAu8wb","67s2TwiMngM0yin5Y8pvEgAAAAAAv3nE"],"type_ids":[3,3,3,3,3,3]},"8jSwzubV-3-vgAsXwII0kA":{"address_or_lines":[4635624,4317996,4333118,4324708,4325572,4330137,4587439],"file_ids":["-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw","-1kQFVGzdQWpzLSZ9TRmnw"],"frame_ids":["-1kQFVGzdQWpzLSZ9TRmnwAAAAAARrvo","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQeMs","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQh4-","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQf1k","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQgDE","-1kQFVGzdQWpzLSZ9TRmnwAAAAAAQhKZ","-1kQFVGzdQWpzLSZ9TRmnwAAAAAARf-v"],"type_ids":[3,3,3,3,3,3,3]},"43tbk4XHS6h_eSSkozr2lQ":{"address_or_lines":[18515232,22597677,22574090,22556393,22530363,22106663,22101077,22107662],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHQK","v6HIzNa4K6G4nRP9032RIAAAAAABWC7p","v6HIzNa4K6G4nRP9032RIAAAAAABV8k7","v6HIzNa4K6G4nRP9032RIAAAAAABUVIn","v6HIzNa4K6G4nRP9032RIAAAAAABUTxV","v6HIzNa4K6G4nRP9032RIAAAAAABUVYO"],"type_ids":[3,3,3,3,3,3,3,3]},"1Hf53oSb-zH-2QD2FYxgyA":{"address_or_lines":[4636706,4469836,4468509,4463096,4465892,4469227,4567193,4567640,5020934],"file_ids":["LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g","LvhLWomlc0dSPYzQ8C620g"],"frame_ids":["LvhLWomlc0dSPYzQ8C620gAAAAAARsAi","LvhLWomlc0dSPYzQ8C620gAAAAAARDRM","LvhLWomlc0dSPYzQ8C620gAAAAAARC8d","LvhLWomlc0dSPYzQ8C620gAAAAAARBn4","LvhLWomlc0dSPYzQ8C620gAAAAAARCTk","LvhLWomlc0dSPYzQ8C620gAAAAAARDHr","LvhLWomlc0dSPYzQ8C620gAAAAAARbCZ","LvhLWomlc0dSPYzQ8C620gAAAAAARbJY","LvhLWomlc0dSPYzQ8C620gAAAAAATJ0G"],"type_ids":[3,3,3,3,3,3,3,3,3]},"ER-x6xVv257WtFQAI5qb9g":{"address_or_lines":[4643592,4325284,4340382,4331972,4332836,4337401,4594856,4566419,4563908,4561911],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjqe","B8JRxL079xbhqQBqGvksAgAAAAAAQhnE","B8JRxL079xbhqQBqGvksAgAAAAAAQh0k","B8JRxL079xbhqQBqGvksAgAAAAAAQi75","B8JRxL079xbhqQBqGvksAgAAAAAARhyo","B8JRxL079xbhqQBqGvksAgAAAAAARa2T","B8JRxL079xbhqQBqGvksAgAAAAAARaPE","B8JRxL079xbhqQBqGvksAgAAAAAARZv3"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"Hr1OSWigQhS4BD9n1H0fVw":{"address_or_lines":[4646178,4471372,4470064,4464366,4415320,4209576,4209709,10485923,16807,3096172,3095028],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuUi","FWZ9q3TQKZZok58ua1HDsgAAAAAARDpM","FWZ9q3TQKZZok58ua1HDsgAAAAAARDUw","FWZ9q3TQKZZok58ua1HDsgAAAAAARB7u","FWZ9q3TQKZZok58ua1HDsgAAAAAAQ19Y","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDuo","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAALz5s","ew01Dk0sWZctP-VaEpavqQAAAAAALzn0"],"type_ids":[3,3,3,3,3,3,3,4,4,4,4]},"g1qDjUCVlmghGHVDrjeDvw":{"address_or_lines":[18425604,18258924,18257560,18253668,18248332,18043494,18206037,18442402,10485923,16743,1221731,1219041],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGScE","j8DVIOTu7Btj9lgFefJ84AAAAAABFpvs","j8DVIOTu7Btj9lgFefJ84AAAAAABFpaY","j8DVIOTu7Btj9lgFefJ84AAAAAABFodk","j8DVIOTu7Btj9lgFefJ84AAAAAABFnKM","j8DVIOTu7Btj9lgFefJ84AAAAAABE1Jm","j8DVIOTu7Btj9lgFefJ84AAAAAABFc1V","j8DVIOTu7Btj9lgFefJ84AAAAAABGWii","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEpnh"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4]},"XU0AYWfaWEgxn6HS3Npe0Q":{"address_or_lines":[18506340,18339660,18338296,18334404,18329068,18124198,18286773,18523138,10485923,16807,1222099,1220257,1210315],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGmJk","v6HIzNa4K6G4nRP9032RIAAAAAABF9dM","v6HIzNa4K6G4nRP9032RIAAAAAABF9H4","v6HIzNa4K6G4nRP9032RIAAAAAABF8LE","v6HIzNa4K6G4nRP9032RIAAAAAABF63s","v6HIzNa4K6G4nRP9032RIAAAAAABFI2m","v6HIzNa4K6G4nRP9032RIAAAAAABFwi1","v6HIzNa4K6G4nRP9032RIAAAAAABGqQC","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h","ew01Dk0sWZctP-VaEpavqQAAAAAAEnfL"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4]},"Xi_OuuwxmtjxVLfRnOKl-w":{"address_or_lines":[4643332,4460312,4460498,4495428,4495848,4496542,4426254,4658837,10485923,16807,633597,633524,633342,631364],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARtoE","6auiCMWq5cA-hAbqSYvdQQAAAAAARA8Y","6auiCMWq5cA-hAbqSYvdQQAAAAAARA_S","6auiCMWq5cA-hAbqSYvdQQAAAAAARJhE","6auiCMWq5cA-hAbqSYvdQQAAAAAARJno","6auiCMWq5cA-hAbqSYvdQQAAAAAARJye","6auiCMWq5cA-hAbqSYvdQQAAAAAAQ4oO","6auiCMWq5cA-hAbqSYvdQQAAAAAARxaV","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAACar9","ew01Dk0sWZctP-VaEpavqQAAAAAACaq0","ew01Dk0sWZctP-VaEpavqQAAAAAACan-","ew01Dk0sWZctP-VaEpavqQAAAAAACaJE"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4,4]},"j3pRZrJva_6zVfPpTrRgMQ":{"address_or_lines":[4435309,4435559,4470649,4243696,4243480,4398678,4639074,10485923,16807,1222099,1220257,1210438,1210021,1207727,1205915],"file_ids":["gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","gfRL5jyxmWedM28UI08hFQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["gfRL5jyxmWedM28UI08hFQAAAAAAQ61t","gfRL5jyxmWedM28UI08hFQAAAAAAQ65n","gfRL5jyxmWedM28UI08hFQAAAAAARDd5","gfRL5jyxmWedM28UI08hFQAAAAAAQMDw","gfRL5jyxmWedM28UI08hFQAAAAAAQMAY","gfRL5jyxmWedM28UI08hFQAAAAAAQx5W","gfRL5jyxmWedM28UI08hFQAAAAAARsli","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT","ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h","ew01Dk0sWZctP-VaEpavqQAAAAAAEnhG","ew01Dk0sWZctP-VaEpavqQAAAAAAEnal","ew01Dk0sWZctP-VaEpavqQAAAAAAEm2v","ew01Dk0sWZctP-VaEpavqQAAAAAAEmab"],"type_ids":[3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"B0rzVoKcdftibP3e40EU_g":{"address_or_lines":[4594276,4428280,4428466,4462056,4242611,4242276,4392174,4610690,10485923,16743,1221731,1219889,1210331,1133072,1132968,8474365],"file_ids":["1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","1QjX8mEQC0-5qYXzadOESA","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["1QjX8mEQC0-5qYXzadOESAAAAAAARhpk","1QjX8mEQC0-5qYXzadOESAAAAAAAQ5H4","1QjX8mEQC0-5qYXzadOESAAAAAAAQ5Ky","1QjX8mEQC0-5qYXzadOESAAAAAAARBXo","1QjX8mEQC0-5qYXzadOESAAAAAAAQLyz","1QjX8mEQC0-5qYXzadOESAAAAAAAQLtk","1QjX8mEQC0-5qYXzadOESAAAAAAAQwTu","1QjX8mEQC0-5qYXzadOESAAAAAAARlqC","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAEqRj","piWSMQrh4r040D0BPNaJvwAAAAAAEp0x","piWSMQrh4r040D0BPNaJvwAAAAAAEnfb","piWSMQrh4r040D0BPNaJvwAAAAAAEUoQ","piWSMQrh4r040D0BPNaJvwAAAAAAEUmo","piWSMQrh4r040D0BPNaJvwAAAAAAgU79"],"type_ids":[3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"jHWwY4al2R105ljWitJf8Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584294],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj6m"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"JFrKrVm1b8YVyjTALHwFPQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000312,40003155,27960932,18154776,18503217],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYls4","v6HIzNa4K6G4nRP9032RIAAAAAACYmZT","v6HIzNa4K6G4nRP9032RIAAAAAABqqZk","v6HIzNa4K6G4nRP9032RIAAAAAABFQUY","v6HIzNa4K6G4nRP9032RIAAAAAABGlYx"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"UkNqUaLVbzZ-0N4mRSSfPA":{"address_or_lines":[4652224,31039781,31054085,31056132,31058408,31449931,30791268,25539462,25547885,25549299,25502704,25503492,25480821,25481061,4953508,4960780,4898318,4893650,4898126],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAAB2aEl","wfA2BgwfDNXUWsxkJ083RwAAAAAB2dkF","wfA2BgwfDNXUWsxkJ083RwAAAAAB2eEE","wfA2BgwfDNXUWsxkJ083RwAAAAAB2eno","wfA2BgwfDNXUWsxkJ083RwAAAAAB3-NL","wfA2BgwfDNXUWsxkJ083RwAAAAAB1dZk","wfA2BgwfDNXUWsxkJ083RwAAAAABhbOG","wfA2BgwfDNXUWsxkJ083RwAAAAABhdRt","wfA2BgwfDNXUWsxkJ083RwAAAAABhdnz","wfA2BgwfDNXUWsxkJ083RwAAAAABhSPw","wfA2BgwfDNXUWsxkJ083RwAAAAABhScE","wfA2BgwfDNXUWsxkJ083RwAAAAABhM51","wfA2BgwfDNXUWsxkJ083RwAAAAABhM9l","wfA2BgwfDNXUWsxkJ083RwAAAAAAS5Wk","wfA2BgwfDNXUWsxkJ083RwAAAAAAS7IM","wfA2BgwfDNXUWsxkJ083RwAAAAAASr4O","wfA2BgwfDNXUWsxkJ083RwAAAAAASqvS","wfA2BgwfDNXUWsxkJ083RwAAAAAASr1O"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"EH1ElzcXDEuDqu7McdrBdQ":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297413,7309604,7297924,5094553],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1mF","B8JRxL079xbhqQBqGvksAgAAAAAAb4kk","B8JRxL079xbhqQBqGvksAgAAAAAAb1uE","B8JRxL079xbhqQBqGvksAgAAAAAATbyZ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"VyF1fKBkXgRmNRnKNEu8Fw":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709512,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16807,2741196,2827770,2817684,2805156,3382963],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEI","B8JRxL079xbhqQBqGvksAgAAAAAAS40k","B8JRxL079xbhqQBqGvksAgAAAAAAS7A6","B8JRxL079xbhqQBqGvksAgAAAAAASFtz","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM","A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6","A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U","A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k","A2oiHVwisByxRn5RDT4LjAAAAAAAM56z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"naNkvUaKAyxw8L7AmrJp_A":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602139,24420574,24417550,19100458,18003551],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8Xgb","j8DVIOTu7Btj9lgFefJ84AAAAAABdKDe","j8DVIOTu7Btj9lgFefJ84AAAAAABdJUO","j8DVIOTu7Btj9lgFefJ84AAAAAABI3Mq","j8DVIOTu7Btj9lgFefJ84AAAAAABErZf"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"INCPC3idrKxHgrRrb5yK7w":{"address_or_lines":[4652224,22357367,22385134,22366798,57079599,58878037,58675517,58634660,58648701,31265316,7372944,7295421,7297245,7300762,7297188,7304836,7297245,7300762,7297188,7304836,7297413,7310803,7320503],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAABVSV3","wfA2BgwfDNXUWsxkJ083RwAAAAABVZHu","wfA2BgwfDNXUWsxkJ083RwAAAAABVUpO","wfA2BgwfDNXUWsxkJ083RwAAAAADZvcv","wfA2BgwfDNXUWsxkJ083RwAAAAADgmhV","wfA2BgwfDNXUWsxkJ083RwAAAAADf1E9","wfA2BgwfDNXUWsxkJ083RwAAAAADfrGk","wfA2BgwfDNXUWsxkJ083RwAAAAADfuh9","wfA2BgwfDNXUWsxkJ083RwAAAAAB3RIk","wfA2BgwfDNXUWsxkJ083RwAAAAAAcICQ","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1G9","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1jd","wfA2BgwfDNXUWsxkJ083RwAAAAAAb2aa","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1ik","wfA2BgwfDNXUWsxkJ083RwAAAAAAb3aE","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1jd","wfA2BgwfDNXUWsxkJ083RwAAAAAAb2aa","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1ik","wfA2BgwfDNXUWsxkJ083RwAAAAAAb3aE","wfA2BgwfDNXUWsxkJ083RwAAAAAAb1mF","wfA2BgwfDNXUWsxkJ083RwAAAAAAb43T","wfA2BgwfDNXUWsxkJ083RwAAAAAAb7O3"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"4-XWrzbKLiMzMN29SCKUhA":{"address_or_lines":[4652224,31041029,31055333,31057380,31059656,31451286,31449907,25120346,25115948,4970003,4971223,4754617,4757981,4219698,4219725,10485923,16807,2777344,2775602,2826949,2809805,2807527,2804929,2869997],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAB2aYF","6auiCMWq5cA-hAbqSYvdQQAAAAAB2d3l","6auiCMWq5cA-hAbqSYvdQQAAAAAB2eXk","6auiCMWq5cA-hAbqSYvdQQAAAAAB2e7I","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-iW","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-Mz","6auiCMWq5cA-hAbqSYvdQQAAAAABf05a","6auiCMWq5cA-hAbqSYvdQQAAAAABfz0s","6auiCMWq5cA-hAbqSYvdQQAAAAAAS9YT","6auiCMWq5cA-hAbqSYvdQQAAAAAAS9rX","6auiCMWq5cA-hAbqSYvdQQAAAAAASIy5","6auiCMWq5cA-hAbqSYvdQQAAAAAASJnd","6auiCMWq5cA-hAbqSYvdQQAAAAAAQGMy","6auiCMWq5cA-hAbqSYvdQQAAAAAAQGNN","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKmEA","ew01Dk0sWZctP-VaEpavqQAAAAAAKloy","ew01Dk0sWZctP-VaEpavqQAAAAAAKyLF","ew01Dk0sWZctP-VaEpavqQAAAAAAKt_N","ew01Dk0sWZctP-VaEpavqQAAAAAAKtbn","ew01Dk0sWZctP-VaEpavqQAAAAAAKszB","ew01Dk0sWZctP-VaEpavqQAAAAAAK8rt"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"oazzZOrFVKPzoEMEINIH2g":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696100,20084005,20770646,20784592],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNUk","j8DVIOTu7Btj9lgFefJ84AAAAAABMnUl","j8DVIOTu7Btj9lgFefJ84AAAAAABPO9W","j8DVIOTu7Btj9lgFefJ84AAAAAABPSXQ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"bgW4z1P_qeyGZ-BNg-EtzA":{"address_or_lines":[43732576,54345578,54346325,54347573,52524033,52636324,52637912,52417621,52420674,52436132,51874398,51910204,51902690,51903112,51905980,51885853,51874436,51883428,51874436,51883428,51874436,51883398,51839246,52405829,52404692,44450492],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAADPT9q","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUJV","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUc1","MNBJ5seVz_ocW6tcr1HSmwAAAAADIXQB","MNBJ5seVz_ocW6tcr1HSmwAAAAADIyqk","MNBJ5seVz_ocW6tcr1HSmwAAAAADIzDY","MNBJ5seVz_ocW6tcr1HSmwAAAAADH9RV","MNBJ5seVz_ocW6tcr1HSmwAAAAADH-BC","MNBJ5seVz_ocW6tcr1HSmwAAAAADIByk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4pe","MNBJ5seVz_ocW6tcr1HSmwAAAAADGBY8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_ji","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_qI","MNBJ5seVz_ocW6tcr1HSmwAAAAADGAW8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF7cd","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62k","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62k","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4qE","MNBJ5seVz_ocW6tcr1HSmwAAAAADF62G","MNBJ5seVz_ocW6tcr1HSmwAAAAADFwEO","MNBJ5seVz_ocW6tcr1HSmwAAAAADH6ZF","MNBJ5seVz_ocW6tcr1HSmwAAAAADH6HU","MNBJ5seVz_ocW6tcr1HSmwAAAAACpkK8"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"_7muG2H-TTX5D3mi3LROgw":{"address_or_lines":[4652224,31041029,31055333,31057380,31059656,31451179,30792516,25540230,25548731,25550840,25503472,25504260,25481372,25481181,25484711,25484964,4951332,4960527,4959954,4897957,4893996,4627954,4660663,10485923,16807,3103928,3101167],"file_ids":["6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","6auiCMWq5cA-hAbqSYvdQQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["6auiCMWq5cA-hAbqSYvdQQAAAAAARvzA","6auiCMWq5cA-hAbqSYvdQQAAAAAB2aYF","6auiCMWq5cA-hAbqSYvdQQAAAAAB2d3l","6auiCMWq5cA-hAbqSYvdQQAAAAAB2eXk","6auiCMWq5cA-hAbqSYvdQQAAAAAB2e7I","6auiCMWq5cA-hAbqSYvdQQAAAAAB3-gr","6auiCMWq5cA-hAbqSYvdQQAAAAAB1dtE","6auiCMWq5cA-hAbqSYvdQQAAAAABhbaG","6auiCMWq5cA-hAbqSYvdQQAAAAABhde7","6auiCMWq5cA-hAbqSYvdQQAAAAABhd_4","6auiCMWq5cA-hAbqSYvdQQAAAAABhSbw","6auiCMWq5cA-hAbqSYvdQQAAAAABhSoE","6auiCMWq5cA-hAbqSYvdQQAAAAABhNCc","6auiCMWq5cA-hAbqSYvdQQAAAAABhM_d","6auiCMWq5cA-hAbqSYvdQQAAAAABhN2n","6auiCMWq5cA-hAbqSYvdQQAAAAABhN6k","6auiCMWq5cA-hAbqSYvdQQAAAAAAS40k","6auiCMWq5cA-hAbqSYvdQQAAAAAAS7EP","6auiCMWq5cA-hAbqSYvdQQAAAAAAS67S","6auiCMWq5cA-hAbqSYvdQQAAAAAASryl","6auiCMWq5cA-hAbqSYvdQQAAAAAASq0s","6auiCMWq5cA-hAbqSYvdQQAAAAAARp3y","6auiCMWq5cA-hAbqSYvdQQAAAAAARx23","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAL1y4","ew01Dk0sWZctP-VaEpavqQAAAAAAL1Hv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4]},"nKCqWW03DZONEM_Nq2LvwQ":{"address_or_lines":[12540096,19004791,19032250,19014236,19907031,31278974,31279321,31305795,31279321,31290406,31279321,31317002,19907351,21668882,21654220,21663244,21662923,16321295,16318241,16372475,15847297,16321906,16318704,15818442,15818729,12152742,12151794,12187561],"file_ids":["67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg","67s2TwiMngM0yin5Y8pvEg"],"frame_ids":["67s2TwiMngM0yin5Y8pvEgAAAAAAv1jA","67s2TwiMngM0yin5Y8pvEgAAAAABIf13","67s2TwiMngM0yin5Y8pvEgAAAAABImi6","67s2TwiMngM0yin5Y8pvEgAAAAABIiJc","67s2TwiMngM0yin5Y8pvEgAAAAABL8HX","67s2TwiMngM0yin5Y8pvEgAAAAAB3Ud-","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3bBD","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3XQm","67s2TwiMngM0yin5Y8pvEgAAAAAB3UjZ","67s2TwiMngM0yin5Y8pvEgAAAAAB3dwK","67s2TwiMngM0yin5Y8pvEgAAAAABL8MX","67s2TwiMngM0yin5Y8pvEgAAAAABSqQS","67s2TwiMngM0yin5Y8pvEgAAAAABSmrM","67s2TwiMngM0yin5Y8pvEgAAAAABSo4M","67s2TwiMngM0yin5Y8pvEgAAAAABSozL","67s2TwiMngM0yin5Y8pvEgAAAAAA-QsP","67s2TwiMngM0yin5Y8pvEgAAAAAA-P8h","67s2TwiMngM0yin5Y8pvEgAAAAAA-dL7","67s2TwiMngM0yin5Y8pvEgAAAAAA8c-B","67s2TwiMngM0yin5Y8pvEgAAAAAA-Q1y","67s2TwiMngM0yin5Y8pvEgAAAAAA-QDw","67s2TwiMngM0yin5Y8pvEgAAAAAA8V7K","67s2TwiMngM0yin5Y8pvEgAAAAAA8V_p","67s2TwiMngM0yin5Y8pvEgAAAAAAuW-m","67s2TwiMngM0yin5Y8pvEgAAAAAAuWvy","67s2TwiMngM0yin5Y8pvEgAAAAAAufep"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"08TjeY9jNFfBuPDWZvzcGA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708845,24702901,19816356,19817629,19819812,19827076,19819869,19823237,19819812,19819076],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbt","j8DVIOTu7Btj9lgFefJ84AAAAAABeO-1","j8DVIOTu7Btj9lgFefJ84AAAAAABLl-k","j8DVIOTu7Btj9lgFefJ84AAAAAABLmSd","j8DVIOTu7Btj9lgFefJ84AAAAAABLm0k","j8DVIOTu7Btj9lgFefJ84AAAAAABLomE","j8DVIOTu7Btj9lgFefJ84AAAAAABLm1d","j8DVIOTu7Btj9lgFefJ84AAAAAABLnqF","j8DVIOTu7Btj9lgFefJ84AAAAAABLm0k","j8DVIOTu7Btj9lgFefJ84AAAAAABLmpE"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"41gF_giRSTRZMXWPVpvLYA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19907099,19901069],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8Ib","v6HIzNa4K6G4nRP9032RIAAAAAABL6qN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"CCCw9Z7XCAUBXfzhCKjvyQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778468,20166836,20169482,20167663,20167859,19086136,19109575,19098127,19092114,19079610],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehbk","v6HIzNa4K6G4nRP9032RIAAAAAABM7i0","v6HIzNa4K6G4nRP9032RIAAAAAABM8MK","v6HIzNa4K6G4nRP9032RIAAAAAABM7vv","v6HIzNa4K6G4nRP9032RIAAAAAABM7yz","v6HIzNa4K6G4nRP9032RIAAAAAABIzs4","v6HIzNa4K6G4nRP9032RIAAAAAABI5bH","v6HIzNa4K6G4nRP9032RIAAAAAABI2oP","v6HIzNa4K6G4nRP9032RIAAAAAABI1KS","v6HIzNa4K6G4nRP9032RIAAAAAABIyG6"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"RK2MfkyDuA83Ote1DRpnig":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901252,19908516,19901309,19904677,19901477,19914228,19923006],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL930","v6HIzNa4K6G4nRP9032RIAAAAAABMAA-"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"E9YrFLZE6ytYTLr5nOdeqA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16755],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEFz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4]},"OaI2ikXPfU9oPJVr7qHqRA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19045737,19044484,19054298,18859716,18879913,10485923,16807,2741468,2828042,2818852,4377977,4376240],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8bE","v6HIzNa4K6G4nRP9032RIAAAAAABIBWp","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc","ew01Dk0sWZctP-VaEpavqQAAAAAAKycK","ew01Dk0sWZctP-VaEpavqQAAAAAAKwMk","ew01Dk0sWZctP-VaEpavqQAAAAAAQs15","ew01Dk0sWZctP-VaEpavqQAAAAAAQsaw"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4]},"BeervgrHDOwHnECUdx-R1Q":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54548081,54524484,54525381,54528188,54495447,54497074,54477482,44043465,44042020,44050767,44050194,43988037,43983308,43704594,43741015,10485923,16807,3103112,3099892,3094686,3393841,3393734,3091863,2557902,2671840],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFZx","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_pE","MNBJ5seVz_ocW6tcr1HSmwAAAAADP_3F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQAi8","MNBJ5seVz_ocW6tcr1HSmwAAAAADP4jX","MNBJ5seVz_ocW6tcr1HSmwAAAAADP48y","MNBJ5seVz_ocW6tcr1HSmwAAAAADP0Kq","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAzJ","MNBJ5seVz_ocW6tcr1HSmwAAAAACoAck","MNBJ5seVz_ocW6tcr1HSmwAAAAACoClP","MNBJ5seVz_ocW6tcr1HSmwAAAAACoCcS","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzRF","MNBJ5seVz_ocW6tcr1HSmwAAAAACnyHM","MNBJ5seVz_ocW6tcr1HSmwAAAAACmuES","MNBJ5seVz_ocW6tcr1HSmwAAAAACm29X","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAL1mI","9LzzIocepYcOjnUsLlgOjgAAAAAAL0z0","9LzzIocepYcOjnUsLlgOjgAAAAAALzie","9LzzIocepYcOjnUsLlgOjgAAAAAAM8kx","9LzzIocepYcOjnUsLlgOjgAAAAAAM8jG","9LzzIocepYcOjnUsLlgOjgAAAAAALy2X","9LzzIocepYcOjnUsLlgOjgAAAAAAJwfO","9LzzIocepYcOjnUsLlgOjgAAAAAAKMTg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"_E7kI3XeP50ndUGgLwozRw":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226539,39801748,39804999,39805475,40019662,39816300,32602256,32687470,24708823,24695729,24696049,18964841,18963588,18973402,18778948,18799145,10485923,16743,2737420,2823946,2813708,2804875,2803431,2800833,2865890],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdREr","j8DVIOTu7Btj9lgFefJ84AAAAAACX1OU","j8DVIOTu7Btj9lgFefJ84AAAAAACX2BH","j8DVIOTu7Btj9lgFefJ84AAAAAACX2Ij","j8DVIOTu7Btj9lgFefJ84AAAAAACYqbO","j8DVIOTu7Btj9lgFefJ84AAAAAACX4xs","j8DVIOTu7Btj9lgFefJ84AAAAAAB8XiQ","j8DVIOTu7Btj9lgFefJ84AAAAAAB8sVu","j8DVIOTu7Btj9lgFefJ84AAAAAABeQbX","j8DVIOTu7Btj9lgFefJ84AAAAAABeNOx","j8DVIOTu7Btj9lgFefJ84AAAAAABeNTx","j8DVIOTu7Btj9lgFefJ84AAAAAABIWFp","j8DVIOTu7Btj9lgFefJ84AAAAAABIVyE","j8DVIOTu7Btj9lgFefJ84AAAAAABIYLa","j8DVIOTu7Btj9lgFefJ84AAAAAABHotE","j8DVIOTu7Btj9lgFefJ84AAAAAABHtop","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu8M","piWSMQrh4r040D0BPNaJvwAAAAAAKsyL","piWSMQrh4r040D0BPNaJvwAAAAAAKsbn","piWSMQrh4r040D0BPNaJvwAAAAAAKrzB","piWSMQrh4r040D0BPNaJvwAAAAAAK7ri"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"PiAbunsxsTWIrlVv5AJCxQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7441528],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYx4"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"gcylfs4yiiRtiY_AHc1fkQ":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508562],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpJS"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"2J6chKI2om9Kbvwi1SgqlA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7441584,6770797,6773738,2395067],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYyw","ew01Dk0sWZctP-VaEpavqQAAAAAAZ1Bt","ew01Dk0sWZctP-VaEpavqQAAAAAAZ1vq","ew01Dk0sWZctP-VaEpavqQAAAAAAJIu7"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"YX2R7C2iz4FGt5q5Tnk6TA":{"address_or_lines":[18434496,22515341,22492438,22512730,32109966,22497902,40241913,34110888,40114070,40112026,41252858,41226601,40103401,19895453,19846041,19847127,19902436,19861609,19902628,19862836,19902820,19863773,19901256,19856467,19901444,19858248,18713630,18723524,18720816,19859472,18001099,10488398,10493154,585983,12583132,6817209,21184,6815932,6812296,6811747,6811254,7304819,7302120],"file_ids":["j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","j8DVIOTu7Btj9lgFefJ84A","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","_3bHXKBtA1BrvZVdhZK3vg","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["j8DVIOTu7Btj9lgFefJ84AAAAAABGUnA","j8DVIOTu7Btj9lgFefJ84AAAAAABV46N","j8DVIOTu7Btj9lgFefJ84AAAAAABVzUW","j8DVIOTu7Btj9lgFefJ84AAAAAABV4Ra","j8DVIOTu7Btj9lgFefJ84AAAAAAB6fWO","j8DVIOTu7Btj9lgFefJ84AAAAAABV0pu","j8DVIOTu7Btj9lgFefJ84AAAAAACZgr5","j8DVIOTu7Btj9lgFefJ84AAAAAACCH2o","j8DVIOTu7Btj9lgFefJ84AAAAAACZBeW","j8DVIOTu7Btj9lgFefJ84AAAAAACZA-a","j8DVIOTu7Btj9lgFefJ84AAAAAACdXf6","j8DVIOTu7Btj9lgFefJ84AAAAAACdRFp","j8DVIOTu7Btj9lgFefJ84AAAAAACY-3p","j8DVIOTu7Btj9lgFefJ84AAAAAABL5Sd","j8DVIOTu7Btj9lgFefJ84AAAAAABLtOZ","j8DVIOTu7Btj9lgFefJ84AAAAAABLtfX","j8DVIOTu7Btj9lgFefJ84AAAAAABL6_k","j8DVIOTu7Btj9lgFefJ84AAAAAABLxBp","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Ck","j8DVIOTu7Btj9lgFefJ84AAAAAABLxU0","j8DVIOTu7Btj9lgFefJ84AAAAAABL7Fk","j8DVIOTu7Btj9lgFefJ84AAAAAABLxjd","j8DVIOTu7Btj9lgFefJ84AAAAAABL6tI","j8DVIOTu7Btj9lgFefJ84AAAAAABLvxT","j8DVIOTu7Btj9lgFefJ84AAAAAABL6wE","j8DVIOTu7Btj9lgFefJ84AAAAAABLwNI","j8DVIOTu7Btj9lgFefJ84AAAAAABHYwe","j8DVIOTu7Btj9lgFefJ84AAAAAABHbLE","j8DVIOTu7Btj9lgFefJ84AAAAAABHagw","j8DVIOTu7Btj9lgFefJ84AAAAAABLwgQ","j8DVIOTu7Btj9lgFefJ84AAAAAABEqzL","piWSMQrh4r040D0BPNaJvwAAAAAAoApO","piWSMQrh4r040D0BPNaJvwAAAAAAoBzi","piWSMQrh4r040D0BPNaJvwAAAAAACPD_","piWSMQrh4r040D0BPNaJvwAAAAAAwADc","piWSMQrh4r040D0BPNaJvwAAAAAAaAW5","_3bHXKBtA1BrvZVdhZK3vgAAAAAAAFLA","piWSMQrh4r040D0BPNaJvwAAAAAAaAC8","piWSMQrh4r040D0BPNaJvwAAAAAAZ_KI","piWSMQrh4r040D0BPNaJvwAAAAAAZ_Bj","piWSMQrh4r040D0BPNaJvwAAAAAAZ-52","piWSMQrh4r040D0BPNaJvwAAAAAAb3Zz","piWSMQrh4r040D0BPNaJvwAAAAAAb2vo"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"--7TGRswVMtk5qWYdGBDUw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7439971,6798378,6797926,4866621,4855697,8473771],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq","ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm","ew01Dk0sWZctP-VaEpavqQAAAAAASkI9","ew01Dk0sWZctP-VaEpavqQAAAAAASheR","ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"iVZ81pgajC_4cYBykPWgBg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6869315,6866863,2643],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","6miIyyucTZf5zXHCk7PT1g"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD","ew01Dk0sWZctP-VaEpavqQAAAAAAaMev","6miIyyucTZf5zXHCk7PT1gAAAAAAAApT"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"dg33Fg5TLDtB9bOuPSPREA":{"address_or_lines":[980270,29770,3203438,1526226,1526293,1526410,1522622,1523799,453712,1320069,1900469,1899334,1898707,2062274,2293545,2285857,2284809,2485949,2472275,2784493,2826658,2823003,3007344,3001783,2924437,3112045,3104142,1417998,1456694,1456323,1393341,1348522,1348436,1345741,1348060,1347558,1345741,1348060,1347558,1345741,1348060,1347558,1345954,1343030,1342299,1335062,1334604,1334212,452199,518055,509958],"file_ids":["Z_CHd3Zjsh2cWE2NSdbiNQ","eOfhJQFIxbIEScd007tROw","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","-p9BlJh9JZMPPNjY_j92ng","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","huWyXZbCBWCe2ZtK9BiokQ","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ"],"frame_ids":["Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADvUu","eOfhJQFIxbIEScd007tROwAAAAAAAHRK","-p9BlJh9JZMPPNjY_j92ngAAAAAAMOFu","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0nS","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0oV","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0qK","-p9BlJh9JZMPPNjY_j92ngAAAAAAFzu-","-p9BlJh9JZMPPNjY_j92ngAAAAAAF0BX","-p9BlJh9JZMPPNjY_j92ngAAAAAABuxQ","-p9BlJh9JZMPPNjY_j92ngAAAAAAFCSF","-p9BlJh9JZMPPNjY_j92ngAAAAAAHP-1","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPtG","-p9BlJh9JZMPPNjY_j92ngAAAAAAHPjT","-p9BlJh9JZMPPNjY_j92ngAAAAAAH3fC","-p9BlJh9JZMPPNjY_j92ngAAAAAAIv8p","-p9BlJh9JZMPPNjY_j92ngAAAAAAIuEh","-p9BlJh9JZMPPNjY_j92ngAAAAAAIt0J","-p9BlJh9JZMPPNjY_j92ngAAAAAAJe69","-p9BlJh9JZMPPNjY_j92ngAAAAAAJblT","-p9BlJh9JZMPPNjY_j92ngAAAAAAKnzt","-p9BlJh9JZMPPNjY_j92ngAAAAAAKyGi","-p9BlJh9JZMPPNjY_j92ngAAAAAAKxNb","-p9BlJh9JZMPPNjY_j92ngAAAAAALeNw","-p9BlJh9JZMPPNjY_j92ngAAAAAALc23","-p9BlJh9JZMPPNjY_j92ngAAAAAALJ-V","-p9BlJh9JZMPPNjY_j92ngAAAAAAL3xt","-p9BlJh9JZMPPNjY_j92ngAAAAAAL12O","huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2","huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD","huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN","huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc","huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m","huWyXZbCBWCe2ZtK9BiokQAAAAAAFImi","huWyXZbCBWCe2ZtK9BiokQAAAAAAFH42","huWyXZbCBWCe2ZtK9BiokQAAAAAAFHtb","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W","huWyXZbCBWCe2ZtK9BiokQAAAAAAFF1M","huWyXZbCBWCe2ZtK9BiokQAAAAAAFFvE","huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB8gG"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAALz5s":{"file_name":[],"function_name":["__x64_sys_epoll_pwait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAALzn0":{"file_name":[],"function_name":["do_epoll_wait"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEqRj":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEpnh":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEqXT":{"file_name":[],"function_name":["__x64_sys_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEp6h":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnfL":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACar9":{"file_name":[],"function_name":["__x64_sys_tgkill"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACaq0":{"file_name":[],"function_name":["do_tkill"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACan-":{"file_name":[],"function_name":["do_send_specific"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAACaJE":{"file_name":[],"function_name":["do_send_sig_info"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnhG":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEnal":{"file_name":[],"function_name":["futex_wait_setup"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEm2v":{"file_name":[],"function_name":["get_futex_key"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAEmab":{"file_name":[],"function_name":["get_futex_key_refs.isra.8"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEp0x":{"file_name":[],"function_name":["do_futex"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEnfb":{"file_name":[],"function_name":["futex_wait"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEUoQ":{"file_name":[],"function_name":["hrtimer_cancel"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEUmo":{"file_name":[],"function_name":["hrtimer_try_to_cancel"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAgU79":{"file_name":[],"function_name":["__lock_text_start"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKdPM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyX6":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKv6U":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKs2k":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAM56z":{"file_name":[],"function_name":["kernfs_dop_revalidate"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKmEA":{"file_name":[],"function_name":["__do_sys_newfstatat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKloy":{"file_name":[],"function_name":["vfs_statx"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKyLF":{"file_name":[],"function_name":["filename_lookup"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKt_N":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKtbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKszB":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAK8rt":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL1y4":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAL1Hv":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEFz":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKdTc":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKycK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKwMk":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQs15":{"file_name":[],"function_name":["ima_file_check"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQsaw":{"file_name":[],"function_name":["process_measurement"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAL1mI":{"file_name":[],"function_name":["__x64_sys_epoll_ctl"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAL0z0":{"file_name":[],"function_name":["ep_insert"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAALzie":{"file_name":[],"function_name":["ep_item_poll.isra.15"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAM8kx":{"file_name":[],"function_name":["kernfs_fop_poll"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAM8jG":{"file_name":[],"function_name":["kernfs_generic_poll"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAALy2X":{"file_name":[],"function_name":["ep_ptable_queue_proc"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwfO":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKMTg":{"file_name":[],"function_name":["memcg_kmem_get_cache"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu8M":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsyL":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKsbn":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKrzB":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAK7ri":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYx4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpJS":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYyw":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ1Bt":{"file_name":[],"function_name":["__kfree_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ1vq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJIu7":{"file_name":[],"function_name":["free_unref_page"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoApO":{"file_name":[],"function_name":["ret_from_intr"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoBzi":{"file_name":[],"function_name":["do_IRQ"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACPD_":{"file_name":[],"function_name":["irq_exit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAaAW5":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"_3bHXKBtA1BrvZVdhZK3vgAAAAAAAFLA":{"file_name":[],"function_name":["ena_io_poll"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAaAC8":{"file_name":[],"function_name":["napi_complete_done"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ_KI":{"file_name":[],"function_name":["gro_normal_list.part.131"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ_Bj":{"file_name":[],"function_name":["netif_receive_skb_list_internal"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZ-52":{"file_name":[],"function_name":["__netif_receive_skb_list_core"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb3Zz":{"file_name":[],"function_name":["ip_list_rcv"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAb2vo":{"file_name":[],"function_name":["ip_rcv_core.isra.17"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYZj":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7wq":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZ7pm":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkI9":{"file_name":[],"function_name":["_copy_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASheR":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAgUyr":{"file_name":[],"function_name":["copy_user_generic_string"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaNFD":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMev":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"6miIyyucTZf5zXHCk7PT1gAAAAAAAApT":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"eOfhJQFIxbIEScd007tROwAAAAAAAHRK":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/nptl/pthread_create.c"],"function_name":["start_thread"],"function_offset":[],"line_number":[465]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFaMO":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/x509_d2.c"],"function_name":["X509_STORE_load_locations"],"function_offset":[],"line_number":[94]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjo2":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["by_file_ctrl"],"function_offset":[],"line_number":[117]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFjjD":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/x509/by_file.c"],"function_name":["X509_load_cert_crl_file"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFUK9":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/pem/pem_info.c"],"function_name":["PEM_X509_INFO_read_bio"],"function_offset":[],"line_number":[248]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJOq":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_d2i"],"function_offset":[],"line_number":[154]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJNU":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["ASN1_item_ex_d2i"],"function_offset":[],"line_number":[553]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFIjN":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[478]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFJHc":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_ex_d2i"],"function_offset":[],"line_number":[623]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFI_m":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_template_noexp_d2i"],"function_offset":[],"line_number":[735]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFImi":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_item_ex_d2i"],"function_offset":[],"line_number":[261]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFH42":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_d2i_ex_primitive"],"function_offset":[],"line_number":[874]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFHtb":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_dec.c"],"function_name":["asn1_ex_c2i"],"function_offset":[],"line_number":[903]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF8W":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_item_new"],"function_offset":[],"line_number":[76]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFF1M":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["asn1_item_ex_combine_new"],"function_offset":[],"line_number":[136]},"huWyXZbCBWCe2ZtK9BiokQAAAAAAFFvE":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/asn1/tasn_new.c"],"function_name":["ASN1_primitive_new"],"function_offset":[],"line_number":[342]},"huWyXZbCBWCe2ZtK9BiokQAAAAAABuZn":{"file_name":["/usr/src/debug/openssl-1.0.2k/crypto/mem.c"],"function_name":["CRYPTO_malloc"],"function_offset":[],"line_number":[346]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB-en":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["__GI___libc_malloc"],"function_offset":[],"line_number":[3068]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAB8gG":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/malloc/malloc.c"],"function_name":["_int_malloc"],"function_offset":[],"line_number":[3584]}},"executables":{"Ij7mO1SCteAnvtNe95RpEg":"linux-vdso.so.1","B56YkhsK1JwqD-8F8sjS3A":"prometheus","QvG8QEGAld88D676NL_Y2Q":"filebeat","FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","67s2TwiMngM0yin5Y8pvEg":"containerd","-1kQFVGzdQWpzLSZ9TRmnw":"kube-state-metrics","v6HIzNa4K6G4nRP9032RIA":"dockerd","LvhLWomlc0dSPYzQ8C620g":"controller","B8JRxL079xbhqQBqGvksAg":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","j8DVIOTu7Btj9lgFefJ84A":"dockerd","piWSMQrh4r040D0BPNaJvw":"vmlinux","6auiCMWq5cA-hAbqSYvdQQ":"kubelet","gfRL5jyxmWedM28UI08hFQ":"snapshot-controller","1QjX8mEQC0-5qYXzadOESA":"containerd-shim-runc-v2","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","A2oiHVwisByxRn5RDT4LjA":"vmlinux","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","9LzzIocepYcOjnUsLlgOjg":"vmlinux","_3bHXKBtA1BrvZVdhZK3vg":"ena","6miIyyucTZf5zXHCk7PT1g":"veth","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","eOfhJQFIxbIEScd007tROw":"libpthread-2.26.so","-p9BlJh9JZMPPNjY_j92ng":"awsagent","huWyXZbCBWCe2ZtK9BiokQ":"libcrypto.so.1.0.2k"},"total_frames":13116,"sampling_rate":1} diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_86400s_125x.json b/x-pack/plugins/profiling/common/__fixtures__/stacktraces_86400s_125x.json deleted file mode 100644 index 35bdfd788368..000000000000 --- a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_86400s_125x.json +++ /dev/null @@ -1 +0,0 @@ -{"stack_trace_events":{"clTcDPwSeibw16tpSQPVxA":38,"1sIZ88dgfmQewwimPWuaWw":80,"2gFeSnOvAhz1aSRiNEVnjQ":213,"0CNUMdOdpmKJxWeUmvWvXg":1062,"9_06LL00QkYIeiFNCWu0XQ":919,"StwAKCpFAmfI3NKtrFQDVg":494,"Jd0qjF7XxnghG2_AZCQTFA":408,"1Ez9iBhqi5bXK2tpNXVjRA":380,"2Ov4wSepfExdnFvsJSSjog":281,"DALs1IxJ3oi7BZ8FFjuM_Q":418,"VmRA1Zd-R_saxzv9stOlrw":364,"u31aX9a6CI2OuomWQHSx1Q":397,"7zatBTElj7KkoApkBS7dzw":438,"ErI-d7HGvspCKDUrR8E64A":371,"-s21TvA-EsTWbfCutQG83Q":373,"kryT_w4Id2yAnU578aXk1w":330,"AsgowTLQhiAbue_lxpHIHw":373,"hecRkAhRG62NML7wI512zA":230,"woPu0Q2DCHU5xpBNJFRNGw":179,"-t2pi-xr8qjFCfIHra96OA":203,"qbtMiMC37gp-mMp0u-WgYw":238,"ZZck2mgLZGHuLiBDFerx6w":244,"af-YU39AX7WoGwE66OjkRg":197,"DkjcsUWzUMWlzGIG7vWPLA":201,"9sZZ-MQWzCV4c64gJJBU6Q":261,"rQhVFvlTg_4aQXNpF_LGMQ":213,"-t0hOBsBrsbJ-S8NPXUTmg":175,"VoyVx3eKZvx3I7o9LV75WA":148,"SwXYsounAV_Jw1AjJobr2g":120,"Z84n0-wX6U6-iVSLGr0n7A":130,"PPkg_Kb06KioYNLVH5MUSw":114,"lMQPlrvTe5c5NiwvC7JXZg":102,"0BFlivqqa58juwW6lzxBVg":70,"cKHQmDxYocbgoxaTvYj6SA":53,"KnJHmq-Dv1WTEbftpdA5Zg":39,"2-DAEecFvG7qyB6YjY5nOg":38,"Ocoebh9gAlmO1k7rQilo0w":23,"XyR38J9TfiJQyusyqjnL0Q":12,"9s4s_y43ZAfUdYXm930H4A":9,"LeV2oAqU4BVeWoabuoh-cw":10,"2gcYNFzbFyKxWn73M5202w":12,"CU-T9AvnxmWd1TTRjgV01Q":27,"nnsc9UkL_oA5SAi5cs_ZPg":9,"wAujHiFN47_oNUI63d6EtA":15,"ia-QZTf1AEqK7KEggAUJSw":12,"YxsKA4n0U7pKfHmrePpfjA":2,"mqliNf10_gB69yQo7_zlzg":9,"24tLFB3hY9xz1zbZCjaBXA":1,"MLSOPRH6z6HuctKh5rsAnA":4,"krdohOL0KiVMtm4q-6fmjg":2,"FtHYpmBv9BwyjtHQeYFcCw":2,"FuFG7sSEAg94nZpDT4nzlA":3,"chida0TNeXOPGVvI0kALCQ":4,"UDWRHwtQcuK3KYw4Lj118w":3,"wQhKHV5i9LyZbGr1o38TMA":1,"TtsX1UxF45-CxViHFwbKJw":1,"iu7dYG1YyobzAXC7AJADOw":1,"WmwSnxyphedkasVyGbhNdg":2,"YWZby9VC56JtR6BAaYHEoA":1,"Hi8HEHDniMkBvPgm-_IXdg":2,"X86DUuQ7tHAxGBaWu4tZLg":3,"Tx8lhCcOjrVLOl1hWK6aBw":1,"oKVObqTWF9QIjxgKf8UkTw":3,"rsb7cL4OAenBHrp0F_Wcgg":2,"mWVVBnqMHfG9pWtaZUm47Q":1,"r1nqJ9JqsZyOKqlpBmuvLg":1,"5MDEZjYH98Woy4iHbcvgDg":1,"WYRZ4mSdJHjsW8s2yoKnfA":1,"C4ItszXjQjtRADEg560AUw":6,"8IBqDIuSolkkEHIjO_CfMw":5,"T2hqeT_yirkauwcO1cGJEw":4,"OIXgOJgQPE-F5rS7DPPzZA":2,"i0e78nPZCZ2CbzzLMEOcMw":4,"34DMF2kw8Djh_MjcdchMzw":6,"XG9tjujXJl2nWpbHppoRMA":6,"SrSwvDbs2pmPg3SRfXJBCA":8,"bcNRMcXtTRgNPl4vy6M5KQ":8,"XmiUdMqa5OViUnHQ_LS4Uw":3,"3odHGojcaqq4ImPnmLLSzw":6,"bRKRM4i4-XY2LCfN18mOow":8,"W936jUeelyxTrQQ2V9mn-w":3,"AlH3zgnqwh5sdMMzX8AXxg":3,"YHwQa4NMDpWa9cokfF0xqw":1,"AlRn0MJA_RCD0pN2OpIRZA":4,"inhNt-Ftru1dLAPaXB98Gw":2,"qaaAfLAUIerA8yhApFJRYQ":2,"cj3H8UtNXHeFFvSKCpbt_Q":1,"XT5dbBR70HCMmAkhladaCQ":1,"Kfnso_5TQwyEGb1cfr-n5A":1,"O3_UY4IxBGbcnXlHSqWz_w":2},"stack_traces":{"clTcDPwSeibw16tpSQPVxA":{"address_or_lines":[4646313],"file_ids":["FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWp"],"type_ids":[3]},"1sIZ88dgfmQewwimPWuaWw":{"address_or_lines":[4660883,2469],"file_ids":["B8JRxL079xbhqQBqGvksAg","edNJ10OjHiWc5nzuTQdvig"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARx6T","edNJ10OjHiWc5nzuTQdvigAAAAAAAAml"],"type_ids":[3,3]},"2gFeSnOvAhz1aSRiNEVnjQ":{"address_or_lines":[10486356,710610,1071113],"file_ids":["piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["piWSMQrh4r040D0BPNaJvwAAAAAAoAJU","piWSMQrh4r040D0BPNaJvwAAAAAACtfS","piWSMQrh4r040D0BPNaJvwAAAAAAEFgJ"],"type_ids":[4,4,4]},"0CNUMdOdpmKJxWeUmvWvXg":{"address_or_lines":[32434917,32101228,32115955,32118104],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7url","QvG8QEGAld88D676NL_Y2QAAAAAB6dNs","QvG8QEGAld88D676NL_Y2QAAAAAB6gzz","QvG8QEGAld88D676NL_Y2QAAAAAB6hVY"],"type_ids":[3,3,3,3]},"9_06LL00QkYIeiFNCWu0XQ":{"address_or_lines":[4643592,4325284,4339923,4341903,4293837],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARtsI","B8JRxL079xbhqQBqGvksAgAAAAAAQf-k","B8JRxL079xbhqQBqGvksAgAAAAAAQjjT","B8JRxL079xbhqQBqGvksAgAAAAAAQkCP","B8JRxL079xbhqQBqGvksAgAAAAAAQYTN"],"type_ids":[3,3,3,3,3]},"StwAKCpFAmfI3NKtrFQDVg":{"address_or_lines":[4646312,4600750,4594821,4561903,4559144,4562383],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARuWo","FWZ9q3TQKZZok58ua1HDsgAAAAAARjOu","FWZ9q3TQKZZok58ua1HDsgAAAAAARhyF","FWZ9q3TQKZZok58ua1HDsgAAAAAARZvv","FWZ9q3TQKZZok58ua1HDsgAAAAAARZEo","FWZ9q3TQKZZok58ua1HDsgAAAAAARZ3P"],"type_ids":[3,3,3,3,3,3]},"Jd0qjF7XxnghG2_AZCQTFA":{"address_or_lines":[43723813,43390308,43405438,43397462,43398148,43406419,43408369],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACmywl","MNBJ5seVz_ocW6tcr1HSmwAAAAAClhVk","MNBJ5seVz_ocW6tcr1HSmwAAAAACllB-","MNBJ5seVz_ocW6tcr1HSmwAAAAACljFW","MNBJ5seVz_ocW6tcr1HSmwAAAAACljQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACllRT","MNBJ5seVz_ocW6tcr1HSmwAAAAACllvx"],"type_ids":[3,3,3,3,3,3,3]},"1Ez9iBhqi5bXK2tpNXVjRA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9497568],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkOvg"],"type_ids":[3,3,3,3,3,3,3,3]},"2Ov4wSepfExdnFvsJSSjog":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504548,5043327],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQck","FWZ9q3TQKZZok58ua1HDsgAAAAAATPR_"],"type_ids":[3,3,3,3,3,3,3,3,3]},"DALs1IxJ3oi7BZ8FFjuM_Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271933,15288920,9572292,9504218,4890989,4889187],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6Qf9","FWZ9q3TQKZZok58ua1HDsgAAAAAA6UpY","FWZ9q3TQKZZok58ua1HDsgAAAAAAkg_E","FWZ9q3TQKZZok58ua1HDsgAAAAAAkQXa","FWZ9q3TQKZZok58ua1HDsgAAAAAASqFt","FWZ9q3TQKZZok58ua1HDsgAAAAAASppj"],"type_ids":[3,3,3,3,3,3,3,3,3,3]},"VmRA1Zd-R_saxzv9stOlrw":{"address_or_lines":[4650848,9850853,9880398,9883181,9807044,9827268,9781937,9782483,9784009,9784300,9829781],"file_ids":["QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg","QaIvzvU8UoclQMd_OMt-Pg"],"frame_ids":["QaIvzvU8UoclQMd_OMt-PgAAAAAARvdg","QaIvzvU8UoclQMd_OMt-PgAAAAAAlk_l","QaIvzvU8UoclQMd_OMt-PgAAAAAAlsNO","QaIvzvU8UoclQMd_OMt-PgAAAAAAls4t","QaIvzvU8UoclQMd_OMt-PgAAAAAAlaTE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlfPE","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUKx","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUTT","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUrJ","QaIvzvU8UoclQMd_OMt-PgAAAAAAlUvs","QaIvzvU8UoclQMd_OMt-PgAAAAAAlf2V"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3]},"u31aX9a6CI2OuomWQHSx1Q":{"address_or_lines":[4652224,22357367,22385134,22366798,57080079,58879477,58676957,58636100,58650141,31265796,7372663,7364083],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZvkP","B8JRxL079xbhqQBqGvksAgAAAAADgm31","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcH93","B8JRxL079xbhqQBqGvksAgAAAAAAcF3z"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3]},"7zatBTElj7KkoApkBS7dzw":{"address_or_lines":[32443680,58256816,58381230,58319266,58327970,58359946,58318775,58321276,58323254,58419093,58425670,32747421,32699470],"file_ids":["QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q","QvG8QEGAld88D676NL_Y2Q"],"frame_ids":["QvG8QEGAld88D676NL_Y2QAAAAAB7w0g","QvG8QEGAld88D676NL_Y2QAAAAADeO2w","QvG8QEGAld88D676NL_Y2QAAAAADetOu","QvG8QEGAld88D676NL_Y2QAAAAADeeGi","QvG8QEGAld88D676NL_Y2QAAAAADegOi","QvG8QEGAld88D676NL_Y2QAAAAADeoCK","QvG8QEGAld88D676NL_Y2QAAAAADed-3","QvG8QEGAld88D676NL_Y2QAAAAADeel8","QvG8QEGAld88D676NL_Y2QAAAAADefE2","QvG8QEGAld88D676NL_Y2QAAAAADe2eV","QvG8QEGAld88D676NL_Y2QAAAAADe4FG","QvG8QEGAld88D676NL_Y2QAAAAAB86-d","QvG8QEGAld88D676NL_Y2QAAAAAB8vRO"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3]},"ErI-d7HGvspCKDUrR8E64A":{"address_or_lines":[152249,135481,144741,190122,831754,827742,928935,925466,103752,102294,100426,61069,75059,73332],"file_ids":["w5zBqPf1_9mIVEf-Rn7EdA","Z_CHd3Zjsh2cWE2NSdbiNQ","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","w5zBqPf1_9mIVEf-Rn7EdA","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg","OTWX4UsOVMrSIF5cD4zUzg"],"frame_ids":["w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAlK5","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAjVl","w5zBqPf1_9mIVEf-Rn7EdAAAAAAAAuaq","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADLEK","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADKFe","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADiyn","w5zBqPf1_9mIVEf-Rn7EdAAAAAAADh8a","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAYhK","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAO6N","OTWX4UsOVMrSIF5cD4zUzgAAAAAAASUz","OTWX4UsOVMrSIF5cD4zUzgAAAAAAAR50"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-s21TvA-EsTWbfCutQG83Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10733159,10733818,10618404,10387225,4547736,4658752],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Zn","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8j6","FWZ9q3TQKZZok58ua1HDsgAAAAAAogYk","FWZ9q3TQKZZok58ua1HDsgAAAAAAnn8Z","FWZ9q3TQKZZok58ua1HDsgAAAAAARWSY","FWZ9q3TQKZZok58ua1HDsgAAAAAARxZA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"kryT_w4Id2yAnU578aXk1w":{"address_or_lines":[4652224,22357367,22385134,22366798,57089650,58932906,58679635,58644118,58665750,31406998,7372944,7295421,7297188,7304836,7297245,5131680],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZx5y","B8JRxL079xbhqQBqGvksAgAAAAADgz6q","B8JRxL079xbhqQBqGvksAgAAAAADf2FT","B8JRxL079xbhqQBqGvksAgAAAAADftaW","B8JRxL079xbhqQBqGvksAgAAAAADfysW","B8JRxL079xbhqQBqGvksAgAAAAAB3zuW","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAATk2g"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"AsgowTLQhiAbue_lxpHIHw":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41460538,41453510,39934947,37247976,34247181,33672088,18131287],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeKM6","v6HIzNa4K6G4nRP9032RIAAAAAACeIfG","v6HIzNa4K6G4nRP9032RIAAAAAACYVvj","v6HIzNa4K6G4nRP9032RIAAAAAACOFvo","v6HIzNa4K6G4nRP9032RIAAAAAACCpIN","v6HIzNa4K6G4nRP9032RIAAAAAACAcuY","v6HIzNa4K6G4nRP9032RIAAAAAABFKlX"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"hecRkAhRG62NML7wI512zA":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961373,27940684],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqgd","v6HIzNa4K6G4nRP9032RIAAAAAABqldM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"woPu0Q2DCHU5xpBNJFRNGw":{"address_or_lines":[43732576,54345578,54346325,54347573,52524033,52636324,52637912,52417621,52420674,52436132,51874398,51910204,51902690,51903112,51905980,51885853,51874212,51875084,44164621],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAADPT9q","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUJV","MNBJ5seVz_ocW6tcr1HSmwAAAAADPUc1","MNBJ5seVz_ocW6tcr1HSmwAAAAADIXQB","MNBJ5seVz_ocW6tcr1HSmwAAAAADIyqk","MNBJ5seVz_ocW6tcr1HSmwAAAAADIzDY","MNBJ5seVz_ocW6tcr1HSmwAAAAADH9RV","MNBJ5seVz_ocW6tcr1HSmwAAAAADH-BC","MNBJ5seVz_ocW6tcr1HSmwAAAAADIByk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4pe","MNBJ5seVz_ocW6tcr1HSmwAAAAADGBY8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_ji","MNBJ5seVz_ocW6tcr1HSmwAAAAADF_qI","MNBJ5seVz_ocW6tcr1HSmwAAAAADGAW8","MNBJ5seVz_ocW6tcr1HSmwAAAAADF7cd","MNBJ5seVz_ocW6tcr1HSmwAAAAADF4mk","MNBJ5seVz_ocW6tcr1HSmwAAAAADF40M","MNBJ5seVz_ocW6tcr1HSmwAAAAACoeYN"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-t2pi-xr8qjFCfIHra96OA":{"address_or_lines":[4620832,23557195,23527051,9749435,9749637,9750553,9750935,9746779,9746522,23527477,23529910,23522407,10849724,10839125,10834845,10836246,10842317,4508401,4247613,4282212],"file_ids":["hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg","hc6JHMKlLXjOZcU9MGxvfg"],"frame_ids":["hc6JHMKlLXjOZcU9MGxvfgAAAAAARoIg","hc6JHMKlLXjOZcU9MGxvfgAAAAABZ3RL","hc6JHMKlLXjOZcU9MGxvfgAAAAABZv6L","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMO7","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMSF","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMgZ","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlMmX","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlLlb","hc6JHMKlLXjOZcU9MGxvfgAAAAAAlLha","hc6JHMKlLXjOZcU9MGxvfgAAAAABZwA1","hc6JHMKlLXjOZcU9MGxvfgAAAAABZwm2","hc6JHMKlLXjOZcU9MGxvfgAAAAABZuxn","hc6JHMKlLXjOZcU9MGxvfgAAAAAApY28","hc6JHMKlLXjOZcU9MGxvfgAAAAAApWRV","hc6JHMKlLXjOZcU9MGxvfgAAAAAApVOd","hc6JHMKlLXjOZcU9MGxvfgAAAAAApVkW","hc6JHMKlLXjOZcU9MGxvfgAAAAAApXDN","hc6JHMKlLXjOZcU9MGxvfgAAAAAARMrx","hc6JHMKlLXjOZcU9MGxvfgAAAAAAQNA9","hc6JHMKlLXjOZcU9MGxvfgAAAAAAQVdk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"qbtMiMC37gp-mMp0u-WgYw":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7305194,5143289,5150220,5146267],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3fq","B8JRxL079xbhqQBqGvksAgAAAAAATnr5","B8JRxL079xbhqQBqGvksAgAAAAAATpYM","B8JRxL079xbhqQBqGvksAgAAAAAAToab"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"ZZck2mgLZGHuLiBDFerx6w":{"address_or_lines":[4652224,22357367,22385134,22366798,57076399,58917522,58676957,58636100,58650141,31265796,7372944,7295421,7297245,7300762,7297188,7304836,7297188,7304836,7297188,7304836,7297188,7303473],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVSV3","B8JRxL079xbhqQBqGvksAgAAAAABVZHu","B8JRxL079xbhqQBqGvksAgAAAAABVUpO","B8JRxL079xbhqQBqGvksAgAAAAADZuqv","B8JRxL079xbhqQBqGvksAgAAAAADgwKS","B8JRxL079xbhqQBqGvksAgAAAAADf1bd","B8JRxL079xbhqQBqGvksAgAAAAADfrdE","B8JRxL079xbhqQBqGvksAgAAAAADfu4d","B8JRxL079xbhqQBqGvksAgAAAAAB3RQE","B8JRxL079xbhqQBqGvksAgAAAAAAcICQ","B8JRxL079xbhqQBqGvksAgAAAAAAb1G9","B8JRxL079xbhqQBqGvksAgAAAAAAb1jd","B8JRxL079xbhqQBqGvksAgAAAAAAb2aa","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3aE","B8JRxL079xbhqQBqGvksAgAAAAAAb1ik","B8JRxL079xbhqQBqGvksAgAAAAAAb3Ex"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"af-YU39AX7WoGwE66OjkRg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000356,39998369,27959205,27961306,27960060,27907285,27885784,27888182,18793031,27888361],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYltk","v6HIzNa4K6G4nRP9032RIAAAAAACYlOh","v6HIzNa4K6G4nRP9032RIAAAAAABqp-l","v6HIzNa4K6G4nRP9032RIAAAAAABqqfa","v6HIzNa4K6G4nRP9032RIAAAAAABqqL8","v6HIzNa4K6G4nRP9032RIAAAAAABqdTV","v6HIzNa4K6G4nRP9032RIAAAAAABqYDY","v6HIzNa4K6G4nRP9032RIAAAAAABqYo2","v6HIzNa4K6G4nRP9032RIAAAAAABHsJH","v6HIzNa4K6G4nRP9032RIAAAAAABqYrp"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"DkjcsUWzUMWlzGIG7vWPLA":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54556506,44024036,44026008,44007166,43828228,43837959,43282962,43282989,10485923,16807,2845749,2845580,2841596,3335577,3325166,699747],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHda","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8Dk","MNBJ5seVz_ocW6tcr1HSmwAAAAACn8iY","MNBJ5seVz_ocW6tcr1HSmwAAAAACn37-","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMQE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1","A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ","A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu","A2oiHVwisByxRn5RDT4LjAAAAAAACq1j"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"9sZZ-MQWzCV4c64gJJBU6Q":{"address_or_lines":[4652224,59362286,59048854,59078134,59085018,59179681,31752932,6709540,4933796,4937114,4970099,4971610,4754617,4757981,4219698,4219725,10485923,16807,2777072,2775330,2826677,2809572,2808699,2807483,2863936],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAADicvu","B8JRxL079xbhqQBqGvksAgAAAAADhQOW","B8JRxL079xbhqQBqGvksAgAAAAADhXX2","B8JRxL079xbhqQBqGvksAgAAAAADhZDa","B8JRxL079xbhqQBqGvksAgAAAAADhwKh","B8JRxL079xbhqQBqGvksAgAAAAAB5ILk","B8JRxL079xbhqQBqGvksAgAAAAAAZmEk","B8JRxL079xbhqQBqGvksAgAAAAAAS0ik","B8JRxL079xbhqQBqGvksAgAAAAAAS1Wa","B8JRxL079xbhqQBqGvksAgAAAAAAS9Zz","B8JRxL079xbhqQBqGvksAgAAAAAAS9xa","B8JRxL079xbhqQBqGvksAgAAAAAASIy5","B8JRxL079xbhqQBqGvksAgAAAAAASJnd","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKl_w","A2oiHVwisByxRn5RDT4LjAAAAAAAKlki","A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1","A2oiHVwisByxRn5RDT4LjAAAAAAAKt7k","A2oiHVwisByxRn5RDT4LjAAAAAAAKtt7","A2oiHVwisByxRn5RDT4LjAAAAAAAKta7","A2oiHVwisByxRn5RDT4LjAAAAAAAK7NA"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"rQhVFvlTg_4aQXNpF_LGMQ":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41428732,20150746,19897796,19899069,19901252,19906953,20160590,19897796,19899069,19901252,19910358,18737412,18488391,18154825,18129756],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCb8","v6HIzNa4K6G4nRP9032RIAAAAAABM3na","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8GJ","v6HIzNa4K6G4nRP9032RIAAAAAABM6BO","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL87W","v6HIzNa4K6G4nRP9032RIAAAAAABHekE","v6HIzNa4K6G4nRP9032RIAAAAAABGhxH","v6HIzNa4K6G4nRP9032RIAAAAAABFQVJ","v6HIzNa4K6G4nRP9032RIAAAAAABFKNc"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"-t0hOBsBrsbJ-S8NPXUTmg":{"address_or_lines":[4652224,22033901,21942103,21951046,9844260,9839268,22072132,22072395,5590500,5508424,4907789,4749540,4757831,4219698,4219725,10485923,16807,2756576,2755820,2745050,6715782,6715626,7926696,6795731,4869416,4855393,8472925],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABUDXt","B8JRxL079xbhqQBqGvksAgAAAAABTs9X","B8JRxL079xbhqQBqGvksAgAAAAABTvJG","B8JRxL079xbhqQBqGvksAgAAAAAAljYk","B8JRxL079xbhqQBqGvksAgAAAAAAliKk","B8JRxL079xbhqQBqGvksAgAAAAABUMtE","B8JRxL079xbhqQBqGvksAgAAAAABUMxL","B8JRxL079xbhqQBqGvksAgAAAAAAVU3k","B8JRxL079xbhqQBqGvksAgAAAAAAVA1I","B8JRxL079xbhqQBqGvksAgAAAAAASuMN","B8JRxL079xbhqQBqGvksAgAAAAAASHjk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg_g","A2oiHVwisByxRn5RDT4LjAAAAAAAKgzs","A2oiHVwisByxRn5RDT4LjAAAAAAAKeLa","A2oiHVwisByxRn5RDT4LjAAAAAAAZnmG","A2oiHVwisByxRn5RDT4LjAAAAAAAZnjq","A2oiHVwisByxRn5RDT4LjAAAAAAAePOo","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7HT","A2oiHVwisByxRn5RDT4LjAAAAAAASk0o","A2oiHVwisByxRn5RDT4LjAAAAAAAShZh","A2oiHVwisByxRn5RDT4LjAAAAAAAgUld"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"VoyVx3eKZvx3I7o9LV75WA":{"address_or_lines":[4652224,22354373,22356417,22043891,9840916,9838765,4872825,5688954,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16807,2756288,2755416,2744627,6715329,7926130,7924288,7914841,6798266,6797590,6797444,2726038],"file_ids":["B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","B8JRxL079xbhqQBqGvksAg","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["B8JRxL079xbhqQBqGvksAgAAAAAARvzA","B8JRxL079xbhqQBqGvksAgAAAAABVRnF","B8JRxL079xbhqQBqGvksAgAAAAABVSHB","B8JRxL079xbhqQBqGvksAgAAAAABUFzz","B8JRxL079xbhqQBqGvksAgAAAAAAlikU","B8JRxL079xbhqQBqGvksAgAAAAAAliCt","B8JRxL079xbhqQBqGvksAgAAAAAASlp5","B8JRxL079xbhqQBqGvksAgAAAAAAVs56","B8JRxL079xbhqQBqGvksAgAAAAAAVUwE","B8JRxL079xbhqQBqGvksAgAAAAAAVATI","B8JRxL079xbhqQBqGvksAgAAAAAASsLk","B8JRxL079xbhqQBqGvksAgAAAAAASHZk","B8JRxL079xbhqQBqGvksAgAAAAAASJlH","B8JRxL079xbhqQBqGvksAgAAAAAAQGMy","B8JRxL079xbhqQBqGvksAgAAAAAAQGNN","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz","A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB","A2oiHVwisByxRn5RDT4LjAAAAAAAePFy","A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA","A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW","A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE","A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"SwXYsounAV_Jw1AjJobr2g":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791289,24794610,24781052,24778417,19045737,19044484,19054298,18859588,18399464,18130636],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekj5","v6HIzNa4K6G4nRP9032RIAAAAAABelXy","v6HIzNa4K6G4nRP9032RIAAAAAABeiD8","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp1p","v6HIzNa4K6G4nRP9032RIAAAAAABIpiE","v6HIzNa4K6G4nRP9032RIAAAAAABIr7a","v6HIzNa4K6G4nRP9032RIAAAAAABH8ZE","v6HIzNa4K6G4nRP9032RIAAAAAABGMDo","v6HIzNa4K6G4nRP9032RIAAAAAABFKbM"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"Z84n0-wX6U6-iVSLGr0n7A":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19907213,19923168],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8KN","v6HIzNa4K6G4nRP9032RIAAAAAABMADg"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"PPkg_Kb06KioYNLVH5MUSw":{"address_or_lines":[43732576,69269321,69269937,69272583,69273587,69274533,75195556,54542596,54557252,54545733,54547559,54558277,54570436,44043866,44037437,43989636,43829252,43837959,43282962,43282989,10485923,16807,2756288,2755416,2924231,3319181,3316454,2921821,2921711,8455053,8481479],"file_ids":["MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","MNBJ5seVz_ocW6tcr1HSmw","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["MNBJ5seVz_ocW6tcr1HSmwAAAAACm05g","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPdJ","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIPmx","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQQH","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQfz","MNBJ5seVz_ocW6tcr1HSmwAAAAAEIQul","MNBJ5seVz_ocW6tcr1HSmwAAAAAEe2Sk","MNBJ5seVz_ocW6tcr1HSmwAAAAADQEEE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQHpE","MNBJ5seVz_ocW6tcr1HSmwAAAAADQE1F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQFRn","MNBJ5seVz_ocW6tcr1HSmwAAAAADQH5F","MNBJ5seVz_ocW6tcr1HSmwAAAAADQK3E","MNBJ5seVz_ocW6tcr1HSmwAAAAACoA5a","MNBJ5seVz_ocW6tcr1HSmwAAAAACn_U9","MNBJ5seVz_ocW6tcr1HSmwAAAAACnzqE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnMgE","MNBJ5seVz_ocW6tcr1HSmwAAAAACnOoH","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIS","MNBJ5seVz_ocW6tcr1HSmwAAAAAClHIt","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A","A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY","A2oiHVwisByxRn5RDT4LjAAAAAAALJ7H","A2oiHVwisByxRn5RDT4LjAAAAAAAMqWN","A2oiHVwisByxRn5RDT4LjAAAAAAAMprm","A2oiHVwisByxRn5RDT4LjAAAAAAALJVd","A2oiHVwisByxRn5RDT4LjAAAAAAALJTv","A2oiHVwisByxRn5RDT4LjAAAAAAAgQON","A2oiHVwisByxRn5RDT4LjAAAAAAAgWrH"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"lMQPlrvTe5c5NiwvC7JXZg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429353,40304297,19976893,19927481,19928567,19983876,19943049,19984068,19944276,19984260,19945213,19982696,19937907,19983876,19943049,19984068,19944276,19982696,19937907,19935862,19142858],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeClp","v6HIzNa4K6G4nRP9032RIAAAAAACZv6p","v6HIzNa4K6G4nRP9032RIAAAAAABMNK9","v6HIzNa4K6G4nRP9032RIAAAAAABMBG5","v6HIzNa4K6G4nRP9032RIAAAAAABMBX3","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMO-E","v6HIzNa4K6G4nRP9032RIAAAAAABMFb9","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMO4E","v6HIzNa4K6G4nRP9032RIAAAAAABME6J","v6HIzNa4K6G4nRP9032RIAAAAAABMO7E","v6HIzNa4K6G4nRP9032RIAAAAAABMFNU","v6HIzNa4K6G4nRP9032RIAAAAAABMOlo","v6HIzNa4K6G4nRP9032RIAAAAAABMDpz","v6HIzNa4K6G4nRP9032RIAAAAAABMDJ2","v6HIzNa4K6G4nRP9032RIAAAAAABJBjK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"0BFlivqqa58juwW6lzxBVg":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791213,24785269,19897796,19899069,19901252,19908516,19901309,19904677,19901252,19908516,19901477,19920683,18932457,18903037],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekit","v6HIzNa4K6G4nRP9032RIAAAAAABejF1","v6HIzNa4K6G4nRP9032RIAAAAAABL53E","v6HIzNa4K6G4nRP9032RIAAAAAABL6K9","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6t9","v6HIzNa4K6G4nRP9032RIAAAAAABL7il","v6HIzNa4K6G4nRP9032RIAAAAAABL6tE","v6HIzNa4K6G4nRP9032RIAAAAAABL8ek","v6HIzNa4K6G4nRP9032RIAAAAAABL6wl","v6HIzNa4K6G4nRP9032RIAAAAAABL_cr","v6HIzNa4K6G4nRP9032RIAAAAAABIOLp","v6HIzNa4K6G4nRP9032RIAAAAAABIG_9"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"cKHQmDxYocbgoxaTvYj6SA":{"address_or_lines":[4652224,58814799,10400775,10401064,10401333,10401661,58829797,58814910,58812516,58789549,58791347,58770754,58772726,13824541,13825258,13823212,13823370,4964628,4731769,4742286,4757722,4219698,4219725,10485923,16807,2795169,2795020,2794811,2794650,2760034,2759532,2759330,2758281,2557765],"file_ids":["wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","wfA2BgwfDNXUWsxkJ083Rw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["wfA2BgwfDNXUWsxkJ083RwAAAAAARvzA","wfA2BgwfDNXUWsxkJ083RwAAAAADgXFP","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrQH","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrUo","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrY1","wfA2BgwfDNXUWsxkJ083RwAAAAAAnrd9","wfA2BgwfDNXUWsxkJ083RwAAAAADgavl","wfA2BgwfDNXUWsxkJ083RwAAAAADgXG-","wfA2BgwfDNXUWsxkJ083RwAAAAADgWhk","wfA2BgwfDNXUWsxkJ083RwAAAAADgQ6t","wfA2BgwfDNXUWsxkJ083RwAAAAADgRWz","wfA2BgwfDNXUWsxkJ083RwAAAAADgMVC","wfA2BgwfDNXUWsxkJ083RwAAAAADgMz2","wfA2BgwfDNXUWsxkJ083RwAAAAAA0vId","wfA2BgwfDNXUWsxkJ083RwAAAAAA0vTq","wfA2BgwfDNXUWsxkJ083RwAAAAAA0uzs","wfA2BgwfDNXUWsxkJ083RwAAAAAA0u2K","wfA2BgwfDNXUWsxkJ083RwAAAAAAS8EU","wfA2BgwfDNXUWsxkJ083RwAAAAAASDN5","wfA2BgwfDNXUWsxkJ083RwAAAAAASFyO","wfA2BgwfDNXUWsxkJ083RwAAAAAASJja","wfA2BgwfDNXUWsxkJ083RwAAAAAAQGMy","wfA2BgwfDNXUWsxkJ083RwAAAAAAQGNN","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKqah","9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM","9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7","9LzzIocepYcOjnUsLlgOjgAAAAAAKqSa","9LzzIocepYcOjnUsLlgOjgAAAAAAKh1i","9LzzIocepYcOjnUsLlgOjgAAAAAAKhts","9LzzIocepYcOjnUsLlgOjgAAAAAAKhqi","9LzzIocepYcOjnUsLlgOjgAAAAAAKhaJ","9LzzIocepYcOjnUsLlgOjgAAAAAAJwdF"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"KnJHmq-Dv1WTEbftpdA5Zg":{"address_or_lines":[4652224,30971941,30986245,30988292,30990568,30935955,30723428,25540326,25548591,25550478,25503568,25504356,25481468,25481277,25484807,25485060,4951332,4960314,4742003,4757981,4219698,4219725,10485923,16743,2737420,2823946,2813561,2756082,2755033,2554964,2554477,2553932,2551218,2411027,2394415],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAAB2Jgl","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NAF","-pk6w5puGcp-wKnQ61BZzQAAAAAB2NgE","-pk6w5puGcp-wKnQ61BZzQAAAAAB2ODo","-pk6w5puGcp-wKnQ61BZzQAAAAAB2AuT","-pk6w5puGcp-wKnQ61BZzQAAAAAB1M1k","-pk6w5puGcp-wKnQ61BZzQAAAAABhbbm","-pk6w5puGcp-wKnQ61BZzQAAAAABhdcv","-pk6w5puGcp-wKnQ61BZzQAAAAABhd6O","-pk6w5puGcp-wKnQ61BZzQAAAAABhSdQ","-pk6w5puGcp-wKnQ61BZzQAAAAABhSpk","-pk6w5puGcp-wKnQ61BZzQAAAAABhND8","-pk6w5puGcp-wKnQ61BZzQAAAAABhNA9","-pk6w5puGcp-wKnQ61BZzQAAAAABhN4H","-pk6w5puGcp-wKnQ61BZzQAAAAABhN8E","-pk6w5puGcp-wKnQ61BZzQAAAAAAS40k","-pk6w5puGcp-wKnQ61BZzQAAAAAAS7A6","-pk6w5puGcp-wKnQ61BZzQAAAAAASFtz","-pk6w5puGcp-wKnQ61BZzQAAAAAASJnd","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKcUM","piWSMQrh4r040D0BPNaJvwAAAAAAKxcK","piWSMQrh4r040D0BPNaJvwAAAAAAKu55","piWSMQrh4r040D0BPNaJvwAAAAAAKg3y","piWSMQrh4r040D0BPNaJvwAAAAAAKgnZ","piWSMQrh4r040D0BPNaJvwAAAAAAJvxU","piWSMQrh4r040D0BPNaJvwAAAAAAJvpt","piWSMQrh4r040D0BPNaJvwAAAAAAJvhM","piWSMQrh4r040D0BPNaJvwAAAAAAJu2y","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIkv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"2-DAEecFvG7qyB6YjY5nOg":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755650,4215846],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxC","ew01Dk0sWZctP-VaEpavqQAAAAAAQFQm"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"Ocoebh9gAlmO1k7rQilo0w":{"address_or_lines":[18515232,22597677,22574774,22595066,32287086,22580238,40442809,34294056,40314966,40312922,41455610,41429291,39997332,40000583,40001059,40220526,40011884,32784080,32870382,24791191,24778097,24778417,19046138,19039453,18993092,18869484,18879802,10485923,16807,2756560,2755688,2744899,3827767,3827522,2050302,4868077,4855663],"file_ids":["v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","v6HIzNa4K6G4nRP9032RIA","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["v6HIzNa4K6G4nRP9032RIAAAAAABGoUg","v6HIzNa4K6G4nRP9032RIAAAAAABWNAt","v6HIzNa4K6G4nRP9032RIAAAAAABWHa2","v6HIzNa4K6G4nRP9032RIAAAAAABWMX6","v6HIzNa4K6G4nRP9032RIAAAAAAB7Klu","v6HIzNa4K6G4nRP9032RIAAAAAABWIwO","v6HIzNa4K6G4nRP9032RIAAAAAACaRu5","v6HIzNa4K6G4nRP9032RIAAAAAACC0ko","v6HIzNa4K6G4nRP9032RIAAAAAACZyhW","v6HIzNa4K6G4nRP9032RIAAAAAACZyBa","v6HIzNa4K6G4nRP9032RIAAAAAACeI_6","v6HIzNa4K6G4nRP9032RIAAAAAACeCkr","v6HIzNa4K6G4nRP9032RIAAAAAACYk-U","v6HIzNa4K6G4nRP9032RIAAAAAACYlxH","v6HIzNa4K6G4nRP9032RIAAAAAACYl4j","v6HIzNa4K6G4nRP9032RIAAAAAACZbdu","v6HIzNa4K6G4nRP9032RIAAAAAACYohs","v6HIzNa4K6G4nRP9032RIAAAAAAB9D7Q","v6HIzNa4K6G4nRP9032RIAAAAAAB9Y_u","v6HIzNa4K6G4nRP9032RIAAAAAABekiX","v6HIzNa4K6G4nRP9032RIAAAAAABehVx","v6HIzNa4K6G4nRP9032RIAAAAAABehax","v6HIzNa4K6G4nRP9032RIAAAAAABIp76","v6HIzNa4K6G4nRP9032RIAAAAAABIoTd","v6HIzNa4K6G4nRP9032RIAAAAAABIc_E","v6HIzNa4K6G4nRP9032RIAAAAAABH-zs","v6HIzNa4K6G4nRP9032RIAAAAAABIBU6","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3","ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC","ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-","ew01Dk0sWZctP-VaEpavqQAAAAAASkft","ew01Dk0sWZctP-VaEpavqQAAAAAAShdv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"XyR38J9TfiJQyusyqjnL0Q":{"address_or_lines":[4652224,22354871,22382638,22364302,56672751,58471189,58268669,58227812,58241853,31197476,7372151,7373114,7374151,8925121,8860356,8860667,8477214,5688773,8906989,5590020,5506248,4899556,4748900,4757831,4219698,4219725,10485923,16743,2752512,2751640,2740851,6649793,7859650,7859044,6707098,6708074,2391221,2381065],"file_ids":["-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","-pk6w5puGcp-wKnQ61BZzQ","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-pk6w5puGcp-wKnQ61BZzQAAAAAARvzA","-pk6w5puGcp-wKnQ61BZzQAAAAABVRu3","-pk6w5puGcp-wKnQ61BZzQAAAAABVYgu","-pk6w5puGcp-wKnQ61BZzQAAAAABVUCO","-pk6w5puGcp-wKnQ61BZzQAAAAADYMHv","-pk6w5puGcp-wKnQ61BZzQAAAAADfDMV","-pk6w5puGcp-wKnQ61BZzQAAAAADeRv9","-pk6w5puGcp-wKnQ61BZzQAAAAADeHxk","-pk6w5puGcp-wKnQ61BZzQAAAAADeLM9","-pk6w5puGcp-wKnQ61BZzQAAAAAB3Akk","-pk6w5puGcp-wKnQ61BZzQAAAAAAcH13","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIE6","-pk6w5puGcp-wKnQ61BZzQAAAAAAcIVH","-pk6w5puGcp-wKnQ61BZzQAAAAAAiC_B","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzLE","-pk6w5puGcp-wKnQ61BZzQAAAAAAhzP7","-pk6w5puGcp-wKnQ61BZzQAAAAAAgVoe","-pk6w5puGcp-wKnQ61BZzQAAAAAAVs3F","-pk6w5puGcp-wKnQ61BZzQAAAAAAh-jt","-pk6w5puGcp-wKnQ61BZzQAAAAAAVUwE","-pk6w5puGcp-wKnQ61BZzQAAAAAAVATI","-pk6w5puGcp-wKnQ61BZzQAAAAAASsLk","-pk6w5puGcp-wKnQ61BZzQAAAAAASHZk","-pk6w5puGcp-wKnQ61BZzQAAAAAASJlH","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGMy","-pk6w5puGcp-wKnQ61BZzQAAAAAAQGNN","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgAA","piWSMQrh4r040D0BPNaJvwAAAAAAKfyY","piWSMQrh4r040D0BPNaJvwAAAAAAKdJz","piWSMQrh4r040D0BPNaJvwAAAAAAZXfB","piWSMQrh4r040D0BPNaJvwAAAAAAd-3C","piWSMQrh4r040D0BPNaJvwAAAAAAd-tk","piWSMQrh4r040D0BPNaJvwAAAAAAZlea","piWSMQrh4r040D0BPNaJvwAAAAAAZltq","piWSMQrh4r040D0BPNaJvwAAAAAAJHy1","piWSMQrh4r040D0BPNaJvwAAAAAAJFUJ"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4]},"9s4s_y43ZAfUdYXm930H4A":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,6711003,4219907],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAZmbb","9LzzIocepYcOjnUsLlgOjgAAAAAAQGQD"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4]},"LeV2oAqU4BVeWoabuoh-cw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7503313],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcn3R"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4]},"2gcYNFzbFyKxWn73M5202w":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7436960,2551475,2548988],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg","9LzzIocepYcOjnUsLlgOjgAAAAAAJu6z","9LzzIocepYcOjnUsLlgOjgAAAAAAJuT8"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4]},"CU-T9AvnxmWd1TTRjgV01Q":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7508830,6761766,2559050],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe","9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m","9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4]},"nnsc9UkL_oA5SAi5cs_ZPg":{"address_or_lines":[4195929,135481,1080531,1010960,1006705,1002538,905832,905294,893117,905294,893117,905294,895510,893117,905294,893117,905294,893117,905294,893117,905294,887126,310194,449006,905294,893117,905294,885107,310194,633609,646930,310194,366119,310194,448792,905294,895510,876495,513798,506886,539471,539386,531635],"file_ids":["YsKzCJ9e4eZnuT00vj7Pcw","Z_CHd3Zjsh2cWE2NSdbiNQ","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw","N4ILulabOfF5MnyRJbvDXw"],"frame_ids":["YsKzCJ9e4eZnuT00vj7PcwAAAAAAQAZZ","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","N4ILulabOfF5MnyRJbvDXwAAAAAAEHzT","N4ILulabOfF5MnyRJbvDXwAAAAAAD20Q","N4ILulabOfF5MnyRJbvDXwAAAAAAD1xx","N4ILulabOfF5MnyRJbvDXwAAAAAAD0wq","N4ILulabOfF5MnyRJbvDXwAAAAAADdJo","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaoW","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADYlW","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABtnu","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaC9","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADYFz","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAACasJ","N4ILulabOfF5MnyRJbvDXwAAAAAACd8S","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABZYn","N4ILulabOfF5MnyRJbvDXwAAAAAABLuy","N4ILulabOfF5MnyRJbvDXwAAAAAABtkY","N4ILulabOfF5MnyRJbvDXwAAAAAADdBO","N4ILulabOfF5MnyRJbvDXwAAAAAADaoW","N4ILulabOfF5MnyRJbvDXwAAAAAADV_P","N4ILulabOfF5MnyRJbvDXwAAAAAAB9cG","N4ILulabOfF5MnyRJbvDXwAAAAAAB7wG","N4ILulabOfF5MnyRJbvDXwAAAAAACDtP","N4ILulabOfF5MnyRJbvDXwAAAAAACDr6","N4ILulabOfF5MnyRJbvDXwAAAAAACByz"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"wAujHiFN47_oNUI63d6EtA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7513502,6765905,6759805,2574033,2218596],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe","ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R","ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9","ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR","ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"ia-QZTf1AEqK7KEggAUJSw":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2756560,2755688,2744899,6715329,7656460,7440136,7508344,7393457,7394824,7384416,6868281,6866019],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","ew01Dk0sWZctP-VaEpavqQAAAAAAoACj","ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn","ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q","ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo","ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD","ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB","ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM","ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI","ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4","ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx","ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI","ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g","ew01Dk0sWZctP-VaEpavqQAAAAAAaM05","ew01Dk0sWZctP-VaEpavqQAAAAAAaMRj"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"YxsKA4n0U7pKfHmrePpfjA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10489481,12583132,6878809,6871998,6871380,7366427,7363873,7362975,7354531,7354154,7352952,7752506,7093274,7753394,7707617],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J","9LzzIocepYcOjnUsLlgOjgAAAAAAwADc","9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ","9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-","9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU","9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb","9LzzIocepYcOjnUsLlgOjgAAAAAAcF0h","9LzzIocepYcOjnUsLlgOjgAAAAAAcFmf","9LzzIocepYcOjnUsLlgOjgAAAAAAcDij","9LzzIocepYcOjnUsLlgOjgAAAAAAcDcq","9LzzIocepYcOjnUsLlgOjgAAAAAAcDJ4","9LzzIocepYcOjnUsLlgOjgAAAAAAdks6","9LzzIocepYcOjnUsLlgOjgAAAAAAbDwa","9LzzIocepYcOjnUsLlgOjgAAAAAAdk6y","9LzzIocepYcOjnUsLlgOjgAAAAAAdZvh"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"mqliNf10_gB69yQo7_zlzg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,48188,14432,38826,1480561,1970211,1481652,1480953,2600004,1079483,19966,39758,10892,28340,55468,1479960,1494280,2600004,1079483,63826,64498,1479960,2600004,1079483,60540,21276,37564,30612,1479868,2600004,1079483,54304,30612,1479868,2600004,1066627,7128,57352],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","GdaBUD9IUEkKxIBryNqV2w","QU8QLoFK6ojrywKrBFfTzA","V558DAsp4yi8bwa8eYwk5Q","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cHp4MwXaY5FCuFRuAA6tWw","-9oyoP4Jj2iRkwEezqId-g","3FRCbvQLPuJyn2B-2wELGw","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAALw8","W8AFtEsepzrJ6AasHrCttwAAAAAAADhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","EFJHOn-GACfHXgae-R1yDAAAAAAAAE3-","GdaBUD9IUEkKxIBryNqV2wAAAAAAAJtO","QU8QLoFK6ojrywKrBFfTzAAAAAAAACqM","V558DAsp4yi8bwa8eYwk5QAAAAAAAG60","tuTnMBfyc9UiPsI0QyvErAAAAAAAANis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","cHp4MwXaY5FCuFRuAA6tWwAAAAAAAOx8","-9oyoP4Jj2iRkwEezqId-gAAAAAAAFMc","3FRCbvQLPuJyn2B-2wELGwAAAAAAAJK8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAANQg","FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEEaD","--q8cwZVXbHL2zOM_p3RlQAAAAAAABvY","yaTrLhUSIq2WitrTHLBy3QAAAAAAAOAI"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,1,1,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1]},"24tLFB3hY9xz1zbZCjaBXA":{"address_or_lines":[4654944,15291206,14341928,15275435,15271887,9565966,9575659,9566094,9566425,10732849,10691669,9933294,9934938,9900484,9900235,9617319,9584395,5101817,7575182,7550869,7561892,5676919,7561404,5629448,5551236,5477192,5131149,4738084,4746343,4209682,4209709,10485923,16807,2755760,2754888,2744099,6711233,7651644,7435512,7503672,7388865,7390232,7379824,6864947,6862495,2596,6843125,7212243],"file_ids":["FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","FWZ9q3TQKZZok58ua1HDsg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg","aUXpdArtZf510BJKvwiFDw","9LzzIocepYcOjnUsLlgOjg","9LzzIocepYcOjnUsLlgOjg"],"frame_ids":["FWZ9q3TQKZZok58ua1HDsgAAAAAARwdg","FWZ9q3TQKZZok58ua1HDsgAAAAAA6VNG","FWZ9q3TQKZZok58ua1HDsgAAAAAA2tco","FWZ9q3TQKZZok58ua1HDsgAAAAAA6RWr","FWZ9q3TQKZZok58ua1HDsgAAAAAA6QfP","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfcO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkhzr","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfeO","FWZ9q3TQKZZok58ua1HDsgAAAAAAkfjZ","FWZ9q3TQKZZok58ua1HDsgAAAAAAo8Ux","FWZ9q3TQKZZok58ua1HDsgAAAAAAoyRV","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5Hu","FWZ9q3TQKZZok58ua1HDsgAAAAAAl5ha","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxHE","FWZ9q3TQKZZok58ua1HDsgAAAAAAlxDL","FWZ9q3TQKZZok58ua1HDsgAAAAAAkr-n","FWZ9q3TQKZZok58ua1HDsgAAAAAAkj8L","FWZ9q3TQKZZok58ua1HDsgAAAAAATdj5","FWZ9q3TQKZZok58ua1HDsgAAAAAAc5aO","FWZ9q3TQKZZok58ua1HDsgAAAAAAczeV","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2Kk","FWZ9q3TQKZZok58ua1HDsgAAAAAAVp93","FWZ9q3TQKZZok58ua1HDsgAAAAAAc2C8","FWZ9q3TQKZZok58ua1HDsgAAAAAAVeYI","FWZ9q3TQKZZok58ua1HDsgAAAAAAVLSE","FWZ9q3TQKZZok58ua1HDsgAAAAAAU5NI","FWZ9q3TQKZZok58ua1HDsgAAAAAATkuN","FWZ9q3TQKZZok58ua1HDsgAAAAAASEwk","FWZ9q3TQKZZok58ua1HDsgAAAAAASGxn","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwS","FWZ9q3TQKZZok58ua1HDsgAAAAAAQDwt","9LzzIocepYcOjnUsLlgOjgAAAAAAoACj","9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn","9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw","9LzzIocepYcOjnUsLlgOjgAAAAAAKglI","9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j","9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB","9LzzIocepYcOjnUsLlgOjgAAAAAAdME8","9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4","9LzzIocepYcOjnUsLlgOjgAAAAAAcn84","9LzzIocepYcOjnUsLlgOjgAAAAAAcL7B","9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY","9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw","9LzzIocepYcOjnUsLlgOjgAAAAAAaMAz","9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf","aUXpdArtZf510BJKvwiFDwAAAAAAAAok","9LzzIocepYcOjnUsLlgOjgAAAAAAaGr1","9LzzIocepYcOjnUsLlgOjgAAAAAAbgzT"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]},"MLSOPRH6z6HuctKh5rsAnA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,29084,63584,18346,1480561,1970211,1481652,1480953,2600004,1079669,3708,1480561,1970211,1481652,1480953,2600004,1079669,5350,11456,17946,62630,26608,28264,8452,1480561,1941045,1970515,1481652,1481047,2600004,1058958,26942,1844654,1847116,1788409,1758317,1865641,10490014,422731,937166],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","ktj-IOmkEpvZJouiJkQjTg","O_h7elJSxPO7SiCsftYRZg","_s_-RvH9Io2qUzM6f5JLGg","8UGQaqEhTX9IIJEQCXnRsQ","jn4X0YIYIsTeszwLEaje9g","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","TesF2I_BvQoOuJH9P_M2mA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ","ew01Dk0sWZctP-VaEpavqQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAHGc","W8AFtEsepzrJ6AasHrCttwAAAAAAAPhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAEeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAA58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","kSaNXrGzSS3BnDNNWezzMAAAAAAAABTm","ne8F__HPIVgxgycJADVSzAAAAAAAACzA","ktj-IOmkEpvZJouiJkQjTgAAAAAAAEYa","O_h7elJSxPO7SiCsftYRZgAAAAAAAPSm","_s_-RvH9Io2qUzM6f5JLGgAAAAAAAGfw","8UGQaqEhTX9IIJEQCXnRsQAAAAAAAG5o","jn4X0YIYIsTeszwLEaje9gAAAAAAACEE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ41","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhFT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFplX","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECiO","TesF2I_BvQoOuJH9P_M2mAAAAAAAAGk-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCWu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHC9M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG0n5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGtRt","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHep","ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe","ew01Dk0sWZctP-VaEpavqQAAAAAABnNL","ew01Dk0sWZctP-VaEpavqQAAAAAADkzO"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,3,3,3,3,3,4,4,4]},"krdohOL0KiVMtm4q-6fmjg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,5836,10976,12298,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1079144,37910,8000,46852,32076,49840,40252,33434,32730,43978,37948,30428,26428,19370,1480209,1940645,1970099,1481300,1480695,2595076,1079144,20016,37192,1480141,1913750],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","ne8F__HPIVgxgycJADVSzA","CwUjPVV5_7q7c0GhtW0aPw","okehWevKsEA4q6dk779jgw","-IuadWGT89NVzIyF_Emodw","XXJY7v4esGWnaxtMW3FA0g","FbrXdcA4j750RyQ3q9JXMw","pL34QuyxyP6XYzGDBMK_5w","IoAk4kM-M4DsDPp7ia5QXw","uHLoBslr3h6S7ooNeXzEbw","iRoTPXvR_cRsnzDO-aurpQ","fB79lJck2X90l-j7VqPR-Q","gbMheDI1NZ3NY96J0seddg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GquRfhZBLBKr9rIBPuH3nA","_DA_LSFNMjbu9L2Dcselpw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAABbM","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW","ne8F__HPIVgxgycJADVSzAAAAAAAAB9A","CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE","okehWevKsEA4q6dk779jgwAAAAAAAH1M","-IuadWGT89NVzIyF_EmodwAAAAAAAMKw","XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08","FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa","pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a","IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK","uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8","iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc","fB79lJck2X90l-j7VqPR-QAAAAAAAGc8","gbMheDI1NZ3NY96J0seddgAAAAAAAEuq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpf3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w","_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpXN","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHTOW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,3,3]},"FtHYpmBv9BwyjtHQeYFcCw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1091475,64358,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,61360,18470,16624,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1079144,14936,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1076587,6244,3453440,1376741,1877279,3072226],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","8EY5iPD5-FtlXFBTyb6lkw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","dCCKy6JoX0PADOFic8hRNQ","9w9lF96vJW7ZhBoZ8ETsBw","xUQuo4OgBaS_Le-fdAwt8A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zkPjzY2Et3KehkHOcSphkA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mBpjyQvq6ftE7Wm1BUpcFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","dCCKy6JoX0PADOFic8hRNQAAAAAAAO-w","9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAEgm","xUQuo4OgBaS_Le-fdAwt8AAAAAAAAEDw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","zkPjzY2Et3KehkHOcSphkAAAAAAAADpY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAABhk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANLIA","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFQHl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHKUf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuDi"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3]},"FuFG7sSEAg94nZpDT4nzlA":{"address_or_lines":[4623936,24755503,6980046,23231210,6980046,23264536,6980046,23232004,23232150,6980046,23230455,6980046,23232004,23232150,6980046,23230455,6980046,23272795,6980046,23232004,23232150,6980046,24742300,6980046,23230455,6980046,23269877,22973163,22972451,22973163,22972451,22964890,22884541,11721444,11715672,11715835,11715578,22884850,22966101,22967654,19588556,8970856,8920596,9005417,9007845,7887684,7888285,7889956,7894532,7945899,4658568,4210208],"file_ids":["pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g","pRLjmMO0U8sO4DFopfFU5g"],"frame_ids":["pRLjmMO0U8sO4DFopfFU5gAAAAAARo5A","pRLjmMO0U8sO4DFopfFU5gAAAAABeb0v","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnrq","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYv0Y","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYx1b","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYn4E","pRLjmMO0U8sO4DFopfFU5gAAAAABYn6W","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABeYmc","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYnf3","pRLjmMO0U8sO4DFopfFU5gAAAAAAaoHO","pRLjmMO0U8sO4DFopfFU5gAAAAABYxH1","pRLjmMO0U8sO4DFopfFU5gAAAAABXorr","pRLjmMO0U8sO4DFopfFU5gAAAAABXogj","pRLjmMO0U8sO4DFopfFU5gAAAAABXorr","pRLjmMO0U8sO4DFopfFU5gAAAAABXogj","pRLjmMO0U8sO4DFopfFU5gAAAAABXmqa","pRLjmMO0U8sO4DFopfFU5gAAAAABXTC9","pRLjmMO0U8sO4DFopfFU5gAAAAAAstrk","pRLjmMO0U8sO4DFopfFU5gAAAAAAssRY","pRLjmMO0U8sO4DFopfFU5gAAAAAAssT7","pRLjmMO0U8sO4DFopfFU5gAAAAAAssP6","pRLjmMO0U8sO4DFopfFU5gAAAAABXTHy","pRLjmMO0U8sO4DFopfFU5gAAAAABXm9V","pRLjmMO0U8sO4DFopfFU5gAAAAABXnVm","pRLjmMO0U8sO4DFopfFU5gAAAAABKuXM","pRLjmMO0U8sO4DFopfFU5gAAAAAAiOJo","pRLjmMO0U8sO4DFopfFU5gAAAAAAiB4U","pRLjmMO0U8sO4DFopfFU5gAAAAAAiWlp","pRLjmMO0U8sO4DFopfFU5gAAAAAAiXLl","pRLjmMO0U8sO4DFopfFU5gAAAAAAeFtE","pRLjmMO0U8sO4DFopfFU5gAAAAAAeF2d","pRLjmMO0U8sO4DFopfFU5gAAAAAAeGQk","pRLjmMO0U8sO4DFopfFU5gAAAAAAeHYE","pRLjmMO0U8sO4DFopfFU5gAAAAAAeT6r","pRLjmMO0U8sO4DFopfFU5gAAAAAARxWI","pRLjmMO0U8sO4DFopfFU5gAAAAAAQD4g"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"chida0TNeXOPGVvI0kALCQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,824,116,12,8,54,12,46,22,1091612,1804498,665668,663668,1112453,1232178,833111,2265137,2264574,2258601,1016110,2256845],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","IlUL618nbeW5Kz4uyGZLrQ","U7DZUwH_4YU5DSkoQhGJWw","bmb3nSRfimrjfhanpjR1rQ","oN7OWDJeuc8DmI2f_earDQ","Yj7P3-Rt3nirG6apRl4A7A","pz3Evn9laHNJFMwOKIXbsw","7aaw2O1Vn7-6eR8XuUWQZQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4","IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0","U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM","bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI","oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2","Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM","pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu","7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAG4jS","G68hjsyagwq6LpWrMjDdngAAAAAACihE","G68hjsyagwq6LpWrMjDdngAAAAAACiB0","G68hjsyagwq6LpWrMjDdngAAAAAAEPmF","G68hjsyagwq6LpWrMjDdngAAAAAAEs0y","G68hjsyagwq6LpWrMjDdngAAAAAADLZX","G68hjsyagwq6LpWrMjDdngAAAAAAIpAx","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInap","G68hjsyagwq6LpWrMjDdngAAAAAAD4Eu","G68hjsyagwq6LpWrMjDdngAAAAAAIm_N"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3]},"UDWRHwtQcuK3KYw4Lj118w":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,30038,33244,3444,11060,9712,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,49806,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,61514,2790352,1482889,1482415,2595076,1057495,58094,59978,64928,29086,21086],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SD7uzoegJjRT3jYNpuQ5wQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","lOUbi56SanKTCh9Y7fIwDw","n74P5OxFm1hAo5ZWtgcKHQ","zXbqXCWr0lCbi_b24hNBRQ"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAIHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAA10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAMKO","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","SD7uzoegJjRT3jYNpuQ5wQAAAAAAAPBK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECLX","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOpK","lOUbi56SanKTCh9Y7fIwDwAAAAAAAP2g","n74P5OxFm1hAo5ZWtgcKHQAAAAAAAHGe","zXbqXCWr0lCbi_b24hNBRQAAAAAAAFJe"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1]},"wQhKHV5i9LyZbGr1o38TMA":{"address_or_lines":[4631744,4426728,23175065,22765086,22101979,22101626,22103238,19925815,19926028,19930622,22109732,19929162,22109403,22104583,22092442,20383549,20126576,20124268,7004126,6995902,6997458,19974869,19979184,7254420,7366379,8869213,8813007,8830631,8835818,5761274,8899923,8811367,6480793,6476612,6475553,6139725,6059982,5083307,5091601,4714216,4721177,4729434,10485923,16743,2752800,2752044,2741274,6650246,6650083,7384662,7382442,7451553,7447772,7440959,7439791],"file_ids":["-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","-V-5ede56KMAXhjFbz84Sw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["-V-5ede56KMAXhjFbz84SwAAAAAARqzA","-V-5ede56KMAXhjFbz84SwAAAAAAQ4vo","-V-5ede56KMAXhjFbz84SwAAAAABYZ-Z","-V-5ede56KMAXhjFbz84SwAAAAABW14e","-V-5ede56KMAXhjFbz84SwAAAAABUT_b","-V-5ede56KMAXhjFbz84SwAAAAABUT56","-V-5ede56KMAXhjFbz84SwAAAAABUUTG","-V-5ede56KMAXhjFbz84SwAAAAABMAs3","-V-5ede56KMAXhjFbz84SwAAAAABMAwM","-V-5ede56KMAXhjFbz84SwAAAAABMB3-","-V-5ede56KMAXhjFbz84SwAAAAABUV4k","-V-5ede56KMAXhjFbz84SwAAAAABMBhK","-V-5ede56KMAXhjFbz84SwAAAAABUVzb","-V-5ede56KMAXhjFbz84SwAAAAABUUoH","-V-5ede56KMAXhjFbz84SwAAAAABURqa","-V-5ede56KMAXhjFbz84SwAAAAABNwc9","-V-5ede56KMAXhjFbz84SwAAAAABMxtw","-V-5ede56KMAXhjFbz84SwAAAAABMxJs","-V-5ede56KMAXhjFbz84SwAAAAAAat_e","-V-5ede56KMAXhjFbz84SwAAAAAAar--","-V-5ede56KMAXhjFbz84SwAAAAAAasXS","-V-5ede56KMAXhjFbz84SwAAAAABMMrV","-V-5ede56KMAXhjFbz84SwAAAAABMNuw","-V-5ede56KMAXhjFbz84SwAAAAAAbrGU","-V-5ede56KMAXhjFbz84SwAAAAAAcGbr","-V-5ede56KMAXhjFbz84SwAAAAAAh1Vd","-V-5ede56KMAXhjFbz84SwAAAAAAhnnP","-V-5ede56KMAXhjFbz84SwAAAAAAhr6n","-V-5ede56KMAXhjFbz84SwAAAAAAhtLq","-V-5ede56KMAXhjFbz84SwAAAAAAV-j6","-V-5ede56KMAXhjFbz84SwAAAAAAh81T","-V-5ede56KMAXhjFbz84SwAAAAAAhnNn","-V-5ede56KMAXhjFbz84SwAAAAAAYuOZ","-V-5ede56KMAXhjFbz84SwAAAAAAYtNE","-V-5ede56KMAXhjFbz84SwAAAAAAYs8h","-V-5ede56KMAXhjFbz84SwAAAAAAXa9N","-V-5ede56KMAXhjFbz84SwAAAAAAXHfO","-V-5ede56KMAXhjFbz84SwAAAAAATZCr","-V-5ede56KMAXhjFbz84SwAAAAAATbER","-V-5ede56KMAXhjFbz84SwAAAAAAR-7o","-V-5ede56KMAXhjFbz84SwAAAAAASAoZ","-V-5ede56KMAXhjFbz84SwAAAAAASCpa","piWSMQrh4r040D0BPNaJvwAAAAAAoACj","piWSMQrh4r040D0BPNaJvwAAAAAAAEFn","piWSMQrh4r040D0BPNaJvwAAAAAAKgEg","piWSMQrh4r040D0BPNaJvwAAAAAAKf4s","piWSMQrh4r040D0BPNaJvwAAAAAAKdQa","piWSMQrh4r040D0BPNaJvwAAAAAAZXmG","piWSMQrh4r040D0BPNaJvwAAAAAAZXjj","piWSMQrh4r040D0BPNaJvwAAAAAAcK5W","piWSMQrh4r040D0BPNaJvwAAAAAAcKWq","piWSMQrh4r040D0BPNaJvwAAAAAAcbOh","piWSMQrh4r040D0BPNaJvwAAAAAAcaTc","piWSMQrh4r040D0BPNaJvwAAAAAAcYo_","piWSMQrh4r040D0BPNaJvwAAAAAAcYWv"],"type_ids":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4]},"TtsX1UxF45-CxViHFwbKJw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,17442,33388,19218,34134,37340,19828,11060,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,53982,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,41518,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,26922,19187,41240,50343],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uo8E5My6tupMEt-pfV-uhA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAIVW","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJHc","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAANLe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAGkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSn"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"iu7dYG1YyobzAXC7AJADOw":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,4,38,174,104,68,88,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044755,2041537,2044780,2041460,1171829,2265239,2264574,2258463,1179954],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ZBnr-5IlLVGCdkX_lTNKmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzNs","G68hjsyagwq6LpWrMjDdngAAAAAAHyZ0","G68hjsyagwq6LpWrMjDdngAAAAAAEeF1","G68hjsyagwq6LpWrMjDdngAAAAAAIpCX","G68hjsyagwq6LpWrMjDdngAAAAAAIo3-","G68hjsyagwq6LpWrMjDdngAAAAAAInYf","G68hjsyagwq6LpWrMjDdngAAAAAAEgEy"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"WmwSnxyphedkasVyGbhNdg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,23142,41180,18932,30244,42480,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,29418,2795776,1483241,1482767,2600004,1074397,3150,5208,43696,4420,2578675,2599636,1091600,58990,2795776,1483241,1482767,2600004,1073803,3150,5208,43696,4204,342,33506,2852079,2851771,2849353,2846190,2846190,2845732],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","l97YFeEKpeLfa-lEAZVNcA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0","xwuAPHgc12-8PZB3i-320gAAAAAAAHYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4Tv","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK4O7","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK3pJ","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK23u","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAK2wk"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3]},"YWZby9VC56JtR6BAaYHEoA":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,18612,22306,4364,53010,16796,14432,6058,1480561,1970211,1481652,1480953,2600004,1079669,20092,1480561,1970211,1481652,1480953,2600004,1062448,57610,1845095,1847963,1481919,2600004,1079483,60588,38154,52556,1479960,1494280,2600004,1079483,55468,1479960,1494280,2600004,1079483,14674,64498,1479960,2600004,1079483,48678,25810,37884,46996,1479868,2600004,1079483,7536,46996,1479868,2600004,1049946,29322],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","EFJHOn-GACfHXgae-R1yDA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kSaNXrGzSS3BnDNNWezzMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","tuTnMBfyc9UiPsI0QyvErA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","-T5rZCijT5TDJjmoEi8Kxg","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","--q8cwZVXbHL2zOM_p3RlQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0","U4Le8nh-beog_B7jq7uTIAAAAAAAAFci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEGc","W8AFtEsepzrJ6AasHrCttwAAAAAAADhg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","EFJHOn-GACfHXgae-R1yDAAAAAAAAE58","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhAj","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEDYw","kSaNXrGzSS3BnDNNWezzMAAAAAAAAOEK","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHCdn","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDKb","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAOys","MYrgKQIxdDhr1gdpucfc-QAAAAAAAJUK","un9fLDZOLvDMO52ltZtuegAAAAAAAM1M","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","tuTnMBfyc9UiPsI0QyvErAAAAAAAANis","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","oERZXsH8EPeoSRxNNaSWfQAAAAAAADlS","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpUY","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","rTFMSHhLRlj86vHPR06zoQAAAAAAAL4m","oArGmvsy3VNtTf_V9EHNeQAAAAAAAGTS","-T5rZCijT5TDJjmoEi8KxgAAAAAAAJP8","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","GEIvPhvjHWZLHz2BksVgvAAAAAAAAB1w","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEAVa","--q8cwZVXbHL2zOM_p3RlQAAAAAAAHKK"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1]},"Hi8HEHDniMkBvPgm-_IXdg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,50422,53628,36212,43828,42480,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,3426,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1091475,5270,2790352,1482889,1482415,2595076,1073749,53998,56056,29040,34524,2573747,2594708,1055190,28766,23366,29852,29250,6740,37336,23068],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ynoRUNDFNh_CC1ViETMulA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fxzD8soKl4etJ4L6nJl81g","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAMT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAANF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAI10","xwuAPHgc12-8PZB3i-320gAAAAAAAKs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAA1i","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ynoRUNDFNh_CC1ViETMulAAAAAAAABSW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAANLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEBnW","fxzD8soKl4etJ4L6nJl81gAAAAAAAHBe","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFoc"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1]},"X86DUuQ7tHAxGBaWu4tZLg":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1079669,2228,5922,53516,36626,19046,37084,2548,13860,26096,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,64610,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,39726,2795776,1483241,1482767,2600004,1074397,52302,54360,27312,324,2578675,2599636,1091600,0,2794972,1848805,1837992,1848417,2718329,2222078,2208786],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BrhWuphS0ZH9x8_V0fpb0A","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","780bLUPADqfQ3x1T5lnVOg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0","U4Le8nh-beog_B7jq7uTIAAAAAAAABci","CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM","SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S","grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm","LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc","Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0","xwuAPHgc12-8PZB3i-320gAAAAAAADYk","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqXc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHAuo","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDRh","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKXp5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIef-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAIbQS"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3]},"Tx8lhCcOjrVLOl1hWK6aBw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,33156,1058,33388,19218,38700,43744,45066,1480209,1969795,1481300,1480601,2595076,1079144,34636,1480209,1969795,1481300,1480601,2595076,1062336,4250,1844695,1847563,1481567,2595076,1079485,3004,57258,27404,1479608,1493928,2595076,1079485,63084,1479608,1493928,2595076,1079485,14194,64498,1479608,2595076,1079485,18374,41842,34364,14228,1479516,2595076,1079485,24640,14228,1479516,2595076,1087128,21352,26392,2571436,1909209],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","yaTrLhUSIq2WitrTHLBy3Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAJcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAALAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAABCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAN-q","un9fLDZOLvDMO52ltZtuegAAAAAAAGsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAPZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAADdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAAEfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy","7v-k2b21f_Xuf-3329jFywAAAAAAAIY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAGBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEJaY","--q8cwZVXbHL2zOM_p3RlQAAAAAAAFNo","yaTrLhUSIq2WitrTHLBy3QAAAAAAAGcY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJzys","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHSHZ"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,3,3]},"oKVObqTWF9QIjxgKf8UkTw":{"address_or_lines":[4201744,135481,4208244,4207404,2599636,1091600,51328,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,50170,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41284,2578675,2599636,1091600,13752,2795776,1483241,1482767,2600004,1079483,27726,29268,38054,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,27726,29784,2736,41068,49494,4746,19187,41141,49404],"file_ids":["SbPwzb_Kog2bWn8uc7xhDQ","Z_CHd3Zjsh2cWE2NSdbiNQ","SbPwzb_Kog2bWn8uc7xhDQ","SbPwzb_Kog2bWn8uc7xhDQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","DTRaillMS4wmG2CDEfm9rQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","08Dc0vnMK9C_nl7yQB6ZKQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zuPG_tF81PcJTwjfBwKlDg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["SbPwzb_Kog2bWn8uc7xhDQAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDZ0","SbPwzb_Kog2bWn8uc7xhDQAAAAAAQDMs","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKC1","jaBVtokSUzfS97d-XKjijgAAAAAAAMD8"],"type_ids":[3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"rsb7cL4OAenBHrp0F_Wcgg":{"address_or_lines":[30070,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,1150,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,47798,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1091600,18886,2795776,1483241,1482767,2600004,1074397,48206,50264,23216,33092,2578675,2599636,1074397,51858,2586225,2600004,1055835,28542,1975041,2600004,1079669,52004,1480561,1940968,1917658,1481652,1480953,2600004,1057290,36296,2944663],"file_ids":["pv4wAezdMMO0SVuGgaEMTg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","qns5vQ3LMi6QrIMOgD_TwQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","J_Lkq1OzUHxWQhnTgF6FwA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","XkOSW26Xa6_lkqHv5givKg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","BuJIbGFo3xNyZaTAXvW1Ag","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","L9BMhx_jo5vrPGr_NYlXCQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","pZhbjLL2hYCcec5rSvEEGw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","kkqG_q7yucIGLE7ky-QX9A","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["pv4wAezdMMO0SVuGgaEMTgAAAAAAAHV2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","qns5vQ3LMi6QrIMOgD_TwQAAAAAAAAR-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","J_Lkq1OzUHxWQhnTgF6FwAAAAAAAALq2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","XkOSW26Xa6_lkqHv5givKgAAAAAAAEnG","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAALxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","BuJIbGFo3xNyZaTAXvW1AgAAAAAAAMqS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEBxb","L9BMhx_jo5vrPGr_NYlXCQAAAAAAAG9-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHiMB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","pZhbjLL2hYCcec5rSvEEGwAAAAAAAMsk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAECIK","kkqG_q7yucIGLE7ky-QX9AAAAAAAAI3I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALO6X"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,1,3,3,3,1,3,3,3,3,3,3,3,1,3]},"mWVVBnqMHfG9pWtaZUm47Q":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,49540,1058,33388,19218,58614,61820,19828,11060,26096,1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11498,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,56810,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,31598,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,51498,19187,41240,50348],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","LF6DFcGHEMqhhhlptO_M_Q","Af6E3BeG383JVVbu67NJ0Q","xwuAPHgc12-8PZB3i-320g","6WJ6x4R10ox82_e3Ea4eiA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3HhVgGD2yvuFLpoZq7RfKw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uSWUCgHgLPG4OFtPdUp0rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAOT2","LF6DFcGHEMqhhhlptO_M_QAAAAAAAPF8","Af6E3BeG383JVVbu67NJ0QAAAAAAAE10","xwuAPHgc12-8PZB3i-320gAAAAAAACs0","6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAACzq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAN3q","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSs"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"r1nqJ9JqsZyOKqlpBmuvLg":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,16772,50210,17004,2834,30508,27360,36874,1480209,1969795,1481300,1480601,2595076,1079144,18252,1480209,1969795,1481300,1480601,2595076,1062336,61594,1844695,1847563,1481567,2595076,1079485,3004,49066,11020,1479608,1493928,2595076,1079485,46700,1479608,1493928,2595076,1079485,63346,48114,1479608,2595076,1079485,10182,25458,17980,63380,1479516,2595076,1079485,16448,63380,1479516,2595076,1073749,13188,3118087,767068,768138,10485923,16807,2845274,2841596,3817899,3815886,3627192],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs","W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAEdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q","un9fLDZOLvDMO52ltZtuegAAAAAAACsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAALZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAACfG","oArGmvsy3VNtTf_V9EHNeQAAAAAAAGNy","7v-k2b21f_Xuf-3329jFywAAAAAAAEY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAADOE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAL5QH","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7Rc","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7iK","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAK2pa","A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8","A2oiHVwisByxRn5RDT4LjAAAAAAAOkGr","A2oiHVwisByxRn5RDT4LjAAAAAAAOjnO","A2oiHVwisByxRn5RDT4LjAAAAAAAN1i4"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,3,3,3,4,4,4,4,4,4,4]},"5MDEZjYH98Woy4iHbcvgDg":{"address_or_lines":[2573747,2594708,1091475,65190,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,22586,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,12514,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,25530,2790352,1482889,1482415,2595076,1073749,58094,60152,33136,34524,2573747,2594708,1091475,37170,2790352,1482889,1482415,2595076,1079144,58108,1481694,1493928,2595076,1080441,8392,15128,1480209,1827586,3439453,2746712,2738096],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MU3fJpOZe9TA4mzeo52wZg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","auEGiAr7C6IfT0eiHbOlyA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","mP9Tk3T74fjOyYWKUaqdMQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","I4X8AC1-B0GuL4JyYemPzw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","s6flibJ32CsA8wnq-j6RkQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3EA5Wz2lIIw6eu5uv4gkTw","hjYcB64xHdoySaNOZ8xYqg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","MU3fJpOZe9TA4mzeo52wZgAAAAAAAP6m","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","auEGiAr7C6IfT0eiHbOlyAAAAAAAAFg6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","mP9Tk3T74fjOyYWKUaqdMQAAAAAAADDi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","I4X8AC1-B0GuL4JyYemPzwAAAAAAAGO6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAOLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","s6flibJ32CsA8wnq-j6RkQAAAAAAAJEy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","ik6PIX946fW_erE7uBJlVQAAAAAAAOL8","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHx5","3EA5Wz2lIIw6eu5uv4gkTwAAAAAAACDI","hjYcB64xHdoySaNOZ8xYqgAAAAAAADsY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAANHtd","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKelY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKcew"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,1,1,3,3,3,3,3]},"WYRZ4mSdJHjsW8s2yoKnfA":{"address_or_lines":[1858,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,30594,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1091475,34158,2790352,1482889,1482415,2595076,1073749,37614,39672,12656,18140,2573747,2594708,1079144,56186,1481694,1828960,2581397,1480843,1480209,1940568,1917258,1481300,1480601,2595076,1079485,9718,1479772,1827586,1940195,1986609,1483518,1482415,1493679,2595076,1073425,15208,2566502,1844254,1972704,2595076,1071886,41592,1850963,1844695,1917599,1539319,3072295,1865140],"file_ids":["Gp9aOxUrrpSVBx4-ftlTOA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","y9R94bQUxts02WzRWfV7xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uI6css-d8SGQRK6a_Ntl-A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","SlnkBp0IIJFLHVOe4KbxwQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uPGvGNXBf1JXGeeDSsmGQA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmtIuZrIdDPbhY30JCQRww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yos2k6ZH69vZXiBQV3d7cQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAAdC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","y9R94bQUxts02WzRWfV7xgAAAAAAAHeC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uI6css-d8SGQRK6a_Ntl-AAAAAAAAIVu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAJLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4","J1eggTwSzYdi9OsSu1q37gAAAAAAADFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","SlnkBp0IIJFLHVOe4KbxwQAAAAAAANt6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2OV","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpiL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZxY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUFK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","uPGvGNXBf1JXGeeDSsmGQAAAAAAAACX2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpRc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-MC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZrj","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHlAx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqL-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsqv","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGER","PmtIuZrIdDPbhY30JCQRwwAAAAAAADto","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJylm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCQe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhng","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEFsO","yos2k6ZH69vZXiBQV3d7cQAAAAAAAKJ4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHD5T","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHUKf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAF3z3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAALuEn","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHW0"],"type_ids":[1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3]},"C4ItszXjQjtRADEg560AUw":{"address_or_lines":[4201744,135481,4208244,4207404,2594708,1079144,388,33826,620,51986,30508,10976,36874,1480209,1969795,1481300,1480601,2595076,1079144,1868,1480209,1969795,1481300,1480601,2595076,1062336,61594,1844695,1847563,1481567,2595076,1079485,35772,49066,60172,1479608,1493928,2595076,1079485,30316,1479608,1493928,2595076,1079485,30578,15346,1479608,2595076,1079485,10678,9074,1596,46996,1479516,2595076,1079485,16448,46996,1479516,2595076,1073749,13088,6410,24756,3150002,920932,10485923,16807,2776792,2775330,2826677,2809533,2807255,2804657,2869654],"file_ids":["WpYcHtr4qx88B8CBJZ2GTw","Z_CHd3Zjsh2cWE2NSdbiNQ","WpYcHtr4qx88B8CBJZ2GTw","WpYcHtr4qx88B8CBJZ2GTw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","DTRaillMS4wmG2CDEfm9rQ","U4Le8nh-beog_B7jq7uTIA","CqoTgn4VUlwTNyUw7wsMHQ","SjQZVYGLzro7G-9yPjVJlg","grZNsSElR5ITq8H2yHCNSw","W8AFtEsepzrJ6AasHrCttw","sur1OQS0yB3u_A1ZgjRjFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EFJHOn-GACfHXgae-R1yDA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","kSaNXrGzSS3BnDNNWezzMA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xNMiNBkMujk7ZnRv0OEjrQ","MYrgKQIxdDhr1gdpucfc-Q","un9fLDZOLvDMO52ltZtueg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","grikUXlisBLUbeL_OWixIw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","oERZXsH8EPeoSRxNNaSWfQ","gMhgHDYSMmyInNJ15VwYFg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","rTFMSHhLRlj86vHPR06zoQ","oArGmvsy3VNtTf_V9EHNeQ","7v-k2b21f_Xuf-3329jFyw","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GEIvPhvjHWZLHz2BksVgvA","FqNqtF0e0OG1VJJtWE9clw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","--q8cwZVXbHL2zOM_p3RlQ","wXOyVgf5_nNg6CUH5kFBbg","zEgDK4qMawUAQZjg5YHyww","-Z7SlEXhuy5tL2BF-xmy3g","Z_CHd3Zjsh2cWE2NSdbiNQ","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["WpYcHtr4qx88B8CBJZ2GTwAAAAAAQB0Q","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDZ0","WpYcHtr4qx88B8CBJZ2GTwAAAAAAQDMs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE","U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi","CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs","SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS","grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs","W8AFtEsepzrJ6AasHrCttwAAAAAAACrg","sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg6D","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEDXA","kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHCXX","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHDEL","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFptf","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8","MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q","un9fLDZOLvDMO52ltZtuegAAAAAAAOsM","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","grikUXlisBLUbeL_OWixIwAAAAAAAHZs","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsuo","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy","gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpO4","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","rTFMSHhLRlj86vHPR06zoQAAAAAAACm2","oArGmvsy3VNtTf_V9EHNeQAAAAAAACNy","7v-k2b21f_Xuf-3329jFywAAAAAAAAY8","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA","FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","--q8cwZVXbHL2zOM_p3RlQAAAAAAADMg","wXOyVgf5_nNg6CUH5kFBbgAAAAAAABkK","zEgDK4qMawUAQZjg5YHywwAAAAAAAGC0","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAMBCy","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAADg1k","A2oiHVwisByxRn5RDT4LjAAAAAAAoACj","A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn","A2oiHVwisByxRn5RDT4LjAAAAAAAKl7Y","A2oiHVwisByxRn5RDT4LjAAAAAAAKlki","A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1","A2oiHVwisByxRn5RDT4LjAAAAAAAKt69","A2oiHVwisByxRn5RDT4LjAAAAAAAKtXX","A2oiHVwisByxRn5RDT4LjAAAAAAAKsux","A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW"],"type_ids":[3,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,1,3,3,3,3,1,1,3,3,3,1,1,1,1,3,3,3,1,1,3,3,3,1,1,1,3,3,4,4,4,4,4,4,4,4,4]},"8IBqDIuSolkkEHIjO_CfMw":{"address_or_lines":[1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,57338,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,46806,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,4702,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,25478,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1079144,57700,1481694,1828960,2580566,1480601,1493679,2595076,1052274,37402,1973088,2595076,1059438,7162],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","VY0EiAO0DxwLRTE4PfFhdw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2AkHKX3hFovQqnWGTZG4BA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","JEYMXKhPKBKP90oNIKO6Ww","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Fq3uvTWKo9OreZfu-LOYYQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","f2CfX6aaJGZ4Su3cCY2vCQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yxUFWTEZsQP-FeNV2RKnFQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Q2lceMFM0t8w5Hdokg8e8A"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","VY0EiAO0DxwLRTE4PfFhdwAAAAAAAN_6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2AkHKX3hFovQqnWGTZG4BAAAAAAAALbW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","JEYMXKhPKBKP90oNIKO6WwAAAAAAABJe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","Fq3uvTWKo9OreZfu-LOYYQAAAAAAAGOG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","f2CfX6aaJGZ4Su3cCY2vCQAAAAAAAOFk","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2BW","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFsqv","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEA5y","yxUFWTEZsQP-FeNV2RKnFQAAAAAAAJIa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhtg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAECpu","Q2lceMFM0t8w5Hdokg8e8AAAAAAAABv6"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,1,3,3,3,1]},"T2hqeT_yirkauwcO1cGJEw":{"address_or_lines":[74,6,18,8,18,80,24,4,84,38,174,104,68,116,38,174,104,68,4,38,174,104,68,96,38,174,104,68,60,38,38,10,38,174,104,68,124,38,174,104,68,124,38,174,104,68,100,140,10,38,174,104,68,76,38,174,34,24,10,10,786829,1091612,1986900,1997206,2238455,4240,5748,1213299,4101,76200,1213299,77535,52678,1213299,52081,33630,106222],"file_ids":["a5aMcPOeWx28QSVng73nBQ","inI9W0bfekFTCpu0ceKTHg","RPwdw40HEBL87wRkKV2ozw","pT2bgvKv3bKR6LMAYtKFRw","Rsr7q4vCSh2ppRtyNkwZAA","cKQfWSgZRgu_1Goz5QGSHw","T2fhmP8acUvRZslK7YRDPw","lrxXzNEmAlflj7bCNDjxdA","SMoSw8cr-PdrIATvljOPrQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xaCec3W8F6xlvd_EISI7vw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","QCNrAtEDVSYrGKsToy3LYA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ocuGLNOciiOP6W8cfH2-qw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bjI4Jot-SXYwqfMr0sl7Xg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjBJSIgrJ7WBnrV9WxdKEQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9-_Y7FNFlkawnHBUI4HVnA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","suQJt7m9qyZP3i8d45HwBQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5w2Emmm2pdiPFBnzFSNcKg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","1bzyoH1Mbbzc-oKA3fR-7Q","BXKFYOU6E7YaW5MDpfBf8w","zP58DjIs7uq1cghmzykyNA","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAABK","inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG","RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS","pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI","Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS","cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ","T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY","lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE","SMoSw8cr-PdrIATvljOPrQAAAAAAAABU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xaCec3W8F6xlvd_EISI7vwAAAAAAAAB0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","QCNrAtEDVSYrGKsToy3LYAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ocuGLNOciiOP6W8cfH2-qwAAAAAAAABg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bjI4Jot-SXYwqfMr0sl7XgAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjBJSIgrJ7WBnrV9WxdKEQAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9-_Y7FNFlkawnHBUI4HVnAAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","suQJt7m9qyZP3i8d45HwBQAAAAAAAABk","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5w2Emmm2pdiPFBnzFSNcKgAAAAAAAABM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAAAi","1bzyoH1Mbbzc-oKA3fR-7QAAAAAAAAAY","BXKFYOU6E7YaW5MDpfBf8wAAAAAAAAAK","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","G68hjsyagwq6LpWrMjDdngAAAAAADAGN","G68hjsyagwq6LpWrMjDdngAAAAAAEKgc","G68hjsyagwq6LpWrMjDdngAAAAAAHlFU","G68hjsyagwq6LpWrMjDdngAAAAAAHnmW","G68hjsyagwq6LpWrMjDdngAAAAAAIif3","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAAS7f","3nN3bymnZ8E42aLEtgglmAAAAAAAAM3G","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAAMtx","3nN3bymnZ8E42aLEtgglmAAAAAAAAINe","3nN3bymnZ8E42aLEtgglmAAAAAAAAZ7u"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"OIXgOJgQPE-F5rS7DPPzZA":{"address_or_lines":[2795776,1483241,1482767,2600004,1079483,23630,25172,33958,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1091600,20658,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1091600,0,2795776,1483241,1482767,2600004,1074397,23630,25688,64176,20804,2578675,2599636,1079669,0,1482046,1829360,2586225,2600004,1079669,36060,1482046,1829360,2586325,1481195,1480561,1940968,1917658,1481652,1480953,2600004,1079483,61874,1480124,1827986,1940595,1989057,1480953,1494106,2600004,1073803,20418,2569666],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","93AmMdBRQTTNSFcMQ_Ywdg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","_____________________w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","29RxCcCS3qayH8Wz47EBXQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","mBpjyQvq6ftE7Wm1BUpcFg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IWme5rHQfgYd-9YstXSeGA","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGJU","eV_m28NnKeeTL60KO2H3SAAAAAAAAISm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","93AmMdBRQTTNSFcMQ_YwdgAAAAAAAFCy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","_____________________wAAAAAAAAAA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","29RxCcCS3qayH8Wz47EBXQAAAAAAAIzc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3bV","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpnr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ3o","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHULa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAPGy","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpW8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-SS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZxz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHlnB","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFsxa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGKL","IWme5rHQfgYd-9YstXSeGAAAAAAAAE_C","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJzXC"],"type_ids":[3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,1,3]},"i0e78nPZCZ2CbzzLMEOcMw":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,38,10,38,38,10,38,174,104,14,32,190,1091944,2047231,2046923,2044755,2041537,2044733,2042086,2025366,954962],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-","G68hjsyagwq6LpWrMjDdngAAAAAAEKlo","G68hjsyagwq6LpWrMjDdngAAAAAAHzz_","G68hjsyagwq6LpWrMjDdngAAAAAAHzvL","G68hjsyagwq6LpWrMjDdngAAAAAAHzNT","G68hjsyagwq6LpWrMjDdngAAAAAAHybB","G68hjsyagwq6LpWrMjDdngAAAAAAHzM9","G68hjsyagwq6LpWrMjDdngAAAAAAHyjm","G68hjsyagwq6LpWrMjDdngAAAAAAHueW","G68hjsyagwq6LpWrMjDdngAAAAAADpJS"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"34DMF2kw8Djh_MjcdchMzw":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,34914,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,7430,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,3230,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1091600,61846,2795776,1483241,1482767,2600004,1074397,31822,33880,6832,33092,2578675,2599636,1079669,38686,1482046,1829360,2586225,2600004,1079669,15794,56134,43516,45442,36964,61672,47980,1480561,1940984,1479155],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","y4VaggFtn5eGbiM4h45zCg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","aovhV1VhdNHhPwAmk_rOhg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","px3SfTg4DYOeiT_Yemty2w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","opI8K6Q9RBhmYCrRVwNTgA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","cVEUVwL4zVVcM9r_4PTCXA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","GGxNFCJdZtgXLG8zgUfn_Q","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","y4VaggFtn5eGbiM4h45zCgAAAAAAAIhi","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","aovhV1VhdNHhPwAmk_rOhgAAAAAAAB0G","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","px3SfTg4DYOeiT_Yemty2wAAAAAAAAye","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","opI8K6Q9RBhmYCrRVwNTgAAAAAAAAPGW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY","J1eggTwSzYdi9OsSu1q37gAAAAAAABqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","cVEUVwL4zVVcM9r_4PTCXAAAAAAAAJce","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","GGxNFCJdZtgXLG8zgUfn_QAAAAAAAD2y","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAKn8","_lF8o5tJDcePvza_IYtgSQAAAAAAALGC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAJBk","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAPDo","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALts","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ34","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpHz"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,1,3,3,3]},"XG9tjujXJl2nWpbHppoRMA":{"address_or_lines":[2573747,2594708,1091475,39286,2790352,1482889,1482415,2595076,1079485,29422,30964,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10138,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,58142,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,17976,33110,47402,19187,41240,50602],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ZVYMRqiL5oPAMqs8XcON8Q","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1y9WuJpjgBMcQb3shY5phQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","dGWvVtQJJ5wuqNyQVpi8lA","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","ZVYMRqiL5oPAMqs8XcON8QAAAAAAAJl2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACea","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1y9WuJpjgBMcQb3shY5phQAAAAAAAOMe","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALkq","dGWvVtQJJ5wuqNyQVpi8lAAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMWq"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"SrSwvDbs2pmPg3SRfXJBCA":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,10978,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,35610,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,11318,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,15678,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,250,2790352,1482889,1482415,2595076,1076587,29422,31480,4464,17976,33110,51586,2846655,2846347,2843929,2840766,2843907,2841214,1439462],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","V6gUZHzBRISi-Z25klK5DQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWNEoAKVTnnzSns045VKhw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","n4Ao4OZE2osF0FygfcWo3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","NGbZlnLCqeq3LFq89r_SpQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","PmhxUKv5sePRxhCBONca8g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","V6gUZHzBRISi-Z25klK5DQAAAAAAACri","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWNEoAKVTnnzSns045VKhwAAAAAAAIsa","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","PmhxUKv5sePRxhCBONca8gAAAAAAAAD6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbm"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3]},"bcNRMcXtTRgNPl4vy6M5KQ":{"address_or_lines":[2573747,2594708,1091475,48050,2789627,1482889,1482415,2595076,1079485,29808,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,47414,2789627,1482889,1482415,2595076,1079485,29808,43878,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,21414,2790352,1482889,1482415,2595076,1073749,33518,35576,8560,18140,2573747,2594708,1091475,12682,2790352,1482889,1482415,2595076,1076587,33518,35576,8560,17976,49494,55682,2846655,2846347,2843929,2840766,2843929,2840766,2843954,2840766,2841312],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","xDXQtI2vA5YySwpx7QFiwA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fSQ747oLNh0c0zFQjsVRWg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","yp8MidCGMe4czbl-NigsYQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2noK4QoWxdzASRHkjOFwVA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","xDXQtI2vA5YySwpx7QFiwAAAAAAAALuy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fSQ747oLNh0c0zFQjsVRWgAAAAAAALk2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","yp8MidCGMe4czbl-NigsYQAAAAAAAFOm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2noK4QoWxdzASRHkjOFwVAAAAAAAADGK","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAILu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4","J1eggTwSzYdi9OsSu1q37gAAAAAAACFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2Uy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1rg"],"type_ids":[3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3]},"XmiUdMqa5OViUnHQ_LS4Uw":{"address_or_lines":[61654,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,61890,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,27010,2795051,1483241,1482767,2600004,1079483,32208,46246,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,324,2578675,2599636,1091600,2254,2795776,1483241,1482767,2600004,1074397,35918,37976,10928,108,49494,29322,19187,41240,50348],"file_ids":["mfGJjedIJMvFXgX3QuTMfQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","9NWoah56eYULAP_zGE9Puw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","IKrIDHd5n47PpDQsRXxvvg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","oG7568kMJujZxPJfj7VMjA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["mfGJjedIJMvFXgX3QuTMfQAAAAAAAPDW","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","9NWoah56eYULAP_zGE9PuwAAAAAAAPHC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","IKrIDHd5n47PpDQsRXxvvgAAAAAAAGmC","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAALSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","oG7568kMJujZxPJfj7VMjAAAAAAAAAjO","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY","J1eggTwSzYdi9OsSu1q37gAAAAAAACqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs","p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAHKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMSs"],"type_ids":[1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"3odHGojcaqq4ImPnmLLSzw":{"address_or_lines":[1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,43246,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,17846,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1091600,13950,2795051,1483241,1482767,2600004,1079483,60880,9382,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,64590,1112,39600,28996,2578675,2599636,1079669,4762,1482046,1829360,2586225,2600004,1079669,34130,1480561,1941045,1970515,1481652,1480953,2600004,1069341,25906,23366,39420,41384,9542,10212,11330,8962,13084,1693331,1865533],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","HENgRXYeEs7mDD8Gk_MNmg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fFS0upy5lIaT99RhlTN5LQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","lSdGU4igLMOpLhL_6XP15w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","QAp_Nt6XUeNsCXnAUgW7Xg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","20O937106XMbOD0LQR4SPw","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","HENgRXYeEs7mDD8Gk_MNmgAAAAAAAKju","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fFS0upy5lIaT99RhlTN5LQAAAAAAAEW2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","lSdGU4igLMOpLhL_6XP15wAAAAAAADZ-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAO3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAACSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY","J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAABKa","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ3Zx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","20O937106XMbOD0LQR4SPwAAAAAAAIVS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpdx","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHZ41","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHhFT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpu0","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpj5","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEFEd","gPzb0fXoBe1225fbKepMRAAAAAAAAGUy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAJn8","_lF8o5tJDcePvza_IYtgSQAAAAAAAKGo","OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG","E2b-mzlh_8261-JxcySn-AAAAAAAACfk","E2b-mzlh_8261-JxcySn-AAAAAAAACxC","E2b-mzlh_8261-JxcySn-AAAAAAAACMC","JrU1PwRIxl_8SXdnTESnogAAAAAAADMc","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAGdaT","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHHc9"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3]},"bRKRM4i4-XY2LCfN18mOow":{"address_or_lines":[1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,32078,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,9638,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1091475,5742,2789627,1482889,1482415,2595076,1079485,25712,39782,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,29422,31480,4464,18140,2573747,2594708,1079144,37050,1481694,1828960,2581297,2595076,1079144,25922,1480209,1940645,1970099,1481300,1480601,2595076,1052274,41714,56134,54428,53864,42310,53828,54946,52578,59942,1429990,1365958,1365461],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","HENgRXYeEs7mDD8Gk_MNmg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","fFS0upy5lIaT99RhlTN5LQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","lSdGU4igLMOpLhL_6XP15w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","QAp_Nt6XUeNsCXnAUgW7Xg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","20O937106XMbOD0LQR4SPw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","gPzb0fXoBe1225fbKepMRA","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","OHQX9IWLaZElAgxGbX3P5g","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","E2b-mzlh_8261-JxcySn-A","JrU1PwRIxl_8SXdnTESnog","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","HENgRXYeEs7mDD8Gk_MNmgAAAAAAAH1O","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","fFS0upy5lIaT99RhlTN5LQAAAAAAACWm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","lSdGU4igLMOpLhL_6XP15wAAAAAAABZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAHLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4","J1eggTwSzYdi9OsSu1q37gAAAAAAABFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ2Mx","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHdo","20O937106XMbOD0LQR4SPwAAAAAAAGVC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpYR","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHZyl","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHg-z","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFppU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpeZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEA5y","gPzb0fXoBe1225fbKepMRAAAAAAAAKLy","jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAANSc","_lF8o5tJDcePvza_IYtgSQAAAAAAANJo","OHQX9IWLaZElAgxGbX3P5gAAAAAAAKVG","E2b-mzlh_8261-JxcySn-AAAAAAAANJE","E2b-mzlh_8261-JxcySn-AAAAAAAANai","E2b-mzlh_8261-JxcySn-AAAAAAAAM1i","JrU1PwRIxl_8SXdnTESnogAAAAAAAOom","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFdHm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFNfG","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFNXV"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3]},"W936jUeelyxTrQQ2V9mn-w":{"address_or_lines":[1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,59834,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,60574,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,64656,2790352,1482889,1482415,2595076,1079485,13038,14580,23398,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,13038,15096,53616,1756,2573747,2594708,1091475,42430,2790352,1482889,1482415,2595076,1076587,13038,15096,53616,1592,16726,47490,2846655,2846347,2843929,2840766,2843929,2840766,2843929,2840766,2840766,2842897,2268402,1775000,1761295,1048381],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zWCVT22bUHN0NWIQIBSuKg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","zj3hc8VBXxWxcbGVwJZYLA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","EHb2BWbkIivImSAfaUtw-A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-7Nhzq0bVRejx7IVqpbbZQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zWCVT22bUHN0NWIQIBSuKgAAAAAAAOm6","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","zj3hc8VBXxWxcbGVwJZYLAAAAAAAAOye","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","EHb2BWbkIivImSAfaUtw-AAAAAAAAPyQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","-7Nhzq0bVRejx7IVqpbbZQAAAAAAAKW-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAADLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4","J1eggTwSzYdi9OsSu1q37gAAAAAAANFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAALmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2ER","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAIpzy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGxWY","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAGuAP","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAD_89"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"AlH3zgnqwh5sdMMzX8AXxg":{"address_or_lines":[1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,52130,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,61558,2790352,1482889,1482415,2595076,1079485,25326,26868,35686,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,8770,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1091475,17970,2790352,1482889,1482415,2595076,1073749,25326,27384,368,1756,2573747,2594708,1066158,3868,39750,21660,21058,64084,29144,22318,29144,18030,1840882,1970521,2595076,1049850,1910],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Gxt7_MN7XgUOe9547JcHVQ"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAAMui","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0","eV_m28NnKeeTL60KO2H3SAAAAAAAAItm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAGLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc","_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEAT6","Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2"],"type_ids":[3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,3,3,3,3,1]},"YHwQa4NMDpWa9cokfF0xqw":{"address_or_lines":[2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,35162,2795051,1483241,1482767,2600004,1079483,15824,29862,1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,62314,2795776,1483241,1482767,2600004,1079669,19534,21418,26368,41208,8202,42532,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,55198,34238,39164,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4420,2578675,2599636,1091600,55698,2795776,1483241,1482767,2600004,1074397,19534,21592,60080,4204,33110,33418,19187,41240,50763],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","2L4SW1rQgEVXRj3pZAI3nQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","Bd3XiVd_ucXTo7t4NwSjLA","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","p5XvqZgoydjTl8thPo5KGw","oR5jBuG11Az1rZkKaPBmAg","ASi9f26ltguiwFajNwOaZw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","2L4SW1rQgEVXRj3pZAI3nQAAAAAAAIla","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqYr","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q","eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAPNq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4","h0l-9tGi18mC40qpcJbyDwAAAAAAACAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAANee","TBeSzkyqIwKL8td602zDjAAAAAAAAIW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAANmS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAAExO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY","J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs","p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAIKK","ASi9f26ltguiwFajNwOaZwAAAAAAAErz","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMZL"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3]},"AlRn0MJA_RCD0pN2OpIRZA":{"address_or_lines":[1481694,1828960,2567559,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,11962,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,59882,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,31598,2790352,1482889,1482415,2595076,1073749,17134,19192,57712,1756,2573747,2594708,1091475,28926,2789627,1482889,1482415,2595076,1079485,13424,27494,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1076587,17134,19192,57712,1592,33110,51586,2846655,2846347,2843929,2840766,2843929,2840766,2843907,2841214,1439429,1865241,10489950,423063,2283967,2281521,8542303],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","GP7h96O0_ppGVtc-UpQQIQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","3HhVgGD2yvuFLpoZq7RfKw","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","uSWUCgHgLPG4OFtPdUp0rg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-BjW54fwMksXBor9R-YN9w","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","Npep8JfxWDWZ3roJSD7jPg","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","M_-aGo2vWhLu7lS5grLv9w","oR5jBuG11Az1rZkKaPBmAg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA","A2oiHVwisByxRn5RDT4LjA"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpve","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","GP7h96O0_ppGVtc-UpQQIQAAAAAAAC66","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","3HhVgGD2yvuFLpoZq7RfKwAAAAAAAOnq","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","-BjW54fwMksXBor9R-YN9wAAAAAAAHD-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpD7","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw","eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEG1r","ik6PIX946fW_erE7uBJlVQAAAAAAAELu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4","M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW","oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2-_","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK26L","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1i-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK2UD","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAK1p-","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFfbF","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHHYZ","A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe","A2oiHVwisByxRn5RDT4LjAAAAAAABnSX","A2oiHVwisByxRn5RDT4LjAAAAAAAItm_","A2oiHVwisByxRn5RDT4LjAAAAAAAItAx","A2oiHVwisByxRn5RDT4LjAAAAAAAglhf"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4]},"inhNt-Ftru1dLAPaXB98Gw":{"address_or_lines":[2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,8722,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,20598,2790352,1482889,1482415,2595076,1079485,62190,63732,7014,1479516,1828960,2567559,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,25154,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1091475,40098,2790352,1482889,1482415,2595076,1073749,62190,64248,37232,50908,2573747,2594708,1066158,25996,23366,46236,45634,23124,53720,46894,53720,46894,53720,46894,53720,42606,1840882,1970521,2594999,2587827],"file_ids":["-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","OlTvyWQFXjOweJcs3kiGyg","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","N2mxDWkAZe8CHgZMQpxZ7A","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","eV_m28NnKeeTL60KO2H3SA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","1eW8DnM19kiBGqMWGVkHPA","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","2kgk5qEgdkkSXT9cIdjqxQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","ik6PIX946fW_erE7uBJlVQ","r3Nzr2WeUwu3gjU4N-rWyA","J1eggTwSzYdi9OsSu1q37g","CNgPIV65Suq5GVbO7eJK7g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","MsEmysGbXhMvgdbwhcZDCg","jtp3NDFNJGnK6sK5oOFo8Q","7R-mHvx47pWvF_ng7rKpHw","_lF8o5tJDcePvza_IYtgSQ","TRd7r6mvdzYdjMdTtebtww","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","bgsqxCFBdtyNwHEAo-3p1w","5PnOjelHYJZ6ovJAXK5uiQ","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g","-Z7SlEXhuy5tL2BF-xmy3g"],"frame_ids":["-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","OlTvyWQFXjOweJcs3kiGygAAAAAAACIS","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEHi9","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0","eV_m28NnKeeTL60KO2H3SAAAAAAAABtm","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFpNc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAG-hg","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJy2H","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","1eW8DnM19kiBGqMWGVkHPAAAAAAAAGJC","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEKeT","2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAKpPQ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFqCJ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAFp6v","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5kE","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEGJV","ik6PIX946fW_erE7uBJlVQAAAAAAAPLu","r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4","J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw","CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ0Wz","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5eU","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAEESu","MsEmysGbXhMvgdbwhcZDCgAAAAAAAGWM","jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG","7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc","_lF8o5tJDcePvza_IYtgSQAAAAAAALJC","TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu","bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY","5PnOjelHYJZ6ovJAXK5uiQAAAAAAAKZu","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHBby","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAHhFZ","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ5i3","-Z7SlEXhuy5tL2BF-xmy3gAAAAAAJ3yz"],"type_ids":[3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"qaaAfLAUIerA8yhApFJRYQ":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,72,38,174,104,68,88,38,174,104,68,124,38,38,10,38,174,104,68,72,38,174,104,68,120,38,174,104,68,354,6,108,20,50,50,2970,50,2970,50,2970,50,684,1109029,956192],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qkYSh95E1urNTie_gKbr7w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","V8ldXm9NGXsJ182jEHEsUw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","xVaa0cBWNcFeS-8zFezQgA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","UBINlIxj95Sa_x2_k5IddA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gRRk0W_9P4SGZLXFJ5KU8Q","VIK6i3XoO6nxn9WkNabugA","SGPpASrxkViIc4Sq7x-WYQ","9xG1GRY3A4PQMfXDNvrOxQ","cbxfeE2AkqKne6oKUxdB6g","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","aEZUIXI_cV9kZCa4-U1NsQ","MebnOxK5WOhP29sl19Jefw","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qkYSh95E1urNTie_gKbr7wAAAAAAAABY","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAFi","VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG","SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs","9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU","cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAua","aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy","MebnOxK5WOhP29sl19JefwAAAAAAAAKs","G68hjsyagwq6LpWrMjDdngAAAAAAEOwl","G68hjsyagwq6LpWrMjDdngAAAAAADpcg"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3]},"cj3H8UtNXHeFFvSKCpbt_Q":{"address_or_lines":[1479868,1829360,2572487,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,58218,2795776,1483241,1482767,2600004,1079669,7246,9130,14080,57592,61450,9764,1482046,1829983,2572841,1848805,1978934,1481919,1494280,2600004,1079669,22430,50622,6396,1482046,1829360,2572487,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,51602,2795776,1483241,1482767,2600004,1074397,7246,9304,47792,324,2578675,2599636,1091600,62974,2795776,1483241,1482767,2600004,1079483,7246,9304,47608,55224,29888,17574,1479868,1829983,2783616,2800188,3063028,4240,5748,1213299,4101,76200,1213299,77886,46784,40082,38821],"file_ids":["xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","7bd6QJSfWZZfOOpDMHqLMA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","ZPxtkRXufuVf4tqV5k5k2Q","8R2Lkqe-tYqq-plJ22QNzA","h0l-9tGi18mC40qpcJbyDw","5EZV-eYYYtY-VAcSTmCvtg","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","705jmHYNd7I4Z4L4c0vfiA","TBeSzkyqIwKL8td602zDjA","NH3zvSjFAfTSy6bEocpNyQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","fj70ljef7nDHOqVJGSIoEQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","ywhwSu3fiEha0QwvHF6X9w","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","zo4mnjDJ1PlZka7jS9k2BA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","LEy-wm0GIvRoYVAga55Hiw","wdQNqQ99iFSdp4ceNJQKBg","J1eggTwSzYdi9OsSu1q37g","0S3htaCNkzxOYeavDR1GTQ","rBzW547V0L_mH4nnWK1FUQ","eV_m28NnKeeTL60KO2H3SA","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","xLxcEbwnZ5oNrk99ZsxcSQ","PVZV2uq5ZRt-FFaczL10BA","PVZV2uq5ZRt-FFaczL10BA","Z_CHd3Zjsh2cWE2NSdbiNQ","PVZV2uq5ZRt-FFaczL10BA","3nN3bymnZ8E42aLEtgglmA","Z_CHd3Zjsh2cWE2NSdbiNQ","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA","3nN3bymnZ8E42aLEtgglmA"],"frame_ids":["xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","7bd6QJSfWZZfOOpDMHqLMAAAAAAAAONq","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACOq","ZPxtkRXufuVf4tqV5k5k2QAAAAAAADcA","8R2Lkqe-tYqq-plJ22QNzAAAAAAAAOD4","h0l-9tGi18mC40qpcJbyDwAAAAAAAPAK","5EZV-eYYYtY-VAcSTmCvtgAAAAAAACYk","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0Ip","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHDXl","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAHjI2","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpy_","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFs0I","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHl1","705jmHYNd7I4Z4L4c0vfiAAAAAAAAFee","TBeSzkyqIwKL8td602zDjAAAAAAAAMW-","NH3zvSjFAfTSy6bEocpNyQAAAAAAABj8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFp0-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-nw","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ0DH","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","fj70ljef7nDHOqVJGSIoEQAAAAAAAMmS","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEGTd","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALqw","ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ1jz","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6rU","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEKgQ","zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPX-","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKqkA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqHp","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFqAP","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAJ6xE","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAEHi7","LEy-wm0GIvRoYVAga55HiwAAAAAAABxO","wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY","J1eggTwSzYdi9OsSu1q37gAAAAAAALn4","0S3htaCNkzxOYeavDR1GTQAAAAAAANe4","rBzW547V0L_mH4nnWK1FUQAAAAAAAHTA","eV_m28NnKeeTL60KO2H3SAAAAAAAAESm","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAFpS8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAG-xf","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKnmA","xLxcEbwnZ5oNrk99ZsxcSQAAAAAAKro8","xLxcEbwnZ5oNrk99ZsxcSQAAAAAALrz0","PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ","PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF","3nN3bymnZ8E42aLEtgglmAAAAAAAASmo","Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz","3nN3bymnZ8E42aLEtgglmAAAAAAAATA-","3nN3bymnZ8E42aLEtgglmAAAAAAAALbA","3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS","3nN3bymnZ8E42aLEtgglmAAAAAAAAJel"],"type_ids":[3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,3,3,3,1,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]},"XT5dbBR70HCMmAkhladaCQ":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,44,38,38,10,38,174,104,68,4,38,174,104,68,40,38,174,104,68,68,38,38,10,38,174,104,68,4,38,174,104,14,32,166,1090933,19429,42789,49059],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ED3bhsHkhBwZ5ynmMnkPRA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","cZ-wyq9rmPl5QnqP0Smp6Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GLV-c6bk0E-nhaaCp6u20w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","c_1Yb4rio2EAH6C9SFwQog","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","O4ILxZswquMzuET9RRf5QA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GLV-c6bk0E-nhaaCp6u20wAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","c_1Yb4rio2EAH6C9SFwQogAAAAAAAABE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","O4ILxZswquMzuET9RRf5QAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKcl","jaBVtokSUzfS97d-XKjijgAAAAAAAL-j"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3]},"Kfnso_5TQwyEGb1cfr-n5A":{"address_or_lines":[48,38,174,104,68,500,38,174,104,68,28,38,174,104,68,44,38,38,10,38,174,104,68,8,38,174,104,68,4,38,174,104,68,212,38,174,104,68,228,38,174,104,68,4,38,174,104,68,92,38,174,104,68,8,38,174,104,68,44,38,38,10,38,174,104,68,4,38,174,104,68,64,38,174,104,68,40,38,174,104,68,48,38,174,104,14,32,166,1090933,19429,41240,51098,10490014,423687,2280415,2277754,2506475,2411027,2395201],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","gZNrskHHFmNkCQ_HaCv8sA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","LUEJ1TSRGwRkHbcAyZ3RuQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","9h_0PKFtQeN0f7xWevHlTQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","nIG-LJ6Pj1PzNMyyppUoqg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ApbUUYSZlAYucbB88oZaGw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","bAXCoU3-CU0WlRxl5l1tmw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","qordvIiilnF7CmkWCAd7eA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","iWpqwwcHV8E8OOnqGCYj9g","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","M61AJsljWf0TM7wD6IJVZw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","ED3bhsHkhBwZ5ynmMnkPRA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","cZ-wyq9rmPl5QnqP0Smp6Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","GLV-c6bk0E-nhaaCp6u20w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rJZ4aC9w8bMvzrC0ApyIjg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","TC9v9fO0nTP4oypYCgB_1Q","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","NNy6Y3cHKuqblVbtSVjWfw","coeZ_4yf5sOePIKKlm8FNQ","G68hjsyagwq6LpWrMjDdng","EX9l-cE0x8X9W8uz4iKUfw","jaBVtokSUzfS97d-XKjijg","jaBVtokSUzfS97d-XKjijg","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw","piWSMQrh4r040D0BPNaJvw"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ApbUUYSZlAYucbB88oZaGwAAAAAAAADU","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","qordvIiilnF7CmkWCAd7eAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","GLV-c6bk0E-nhaaCp6u20wAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rJZ4aC9w8bMvzrC0ApyIjgAAAAAAAAAo","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","TC9v9fO0nTP4oypYCgB_1QAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO","NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg","coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","EX9l-cE0x8X9W8uz4iKUfwAAAAAAAEvl","jaBVtokSUzfS97d-XKjijgAAAAAAAKEY","jaBVtokSUzfS97d-XKjijgAAAAAAAMea","piWSMQrh4r040D0BPNaJvwAAAAAAoBCe","piWSMQrh4r040D0BPNaJvwAAAAAABncH","piWSMQrh4r040D0BPNaJvwAAAAAAIsvf","piWSMQrh4r040D0BPNaJvwAAAAAAIsF6","piWSMQrh4r040D0BPNaJvwAAAAAAJj7r","piWSMQrh4r040D0BPNaJvwAAAAAAJMoT","piWSMQrh4r040D0BPNaJvwAAAAAAJIxB"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,4,4,4,4,4,4,4]},"O3_UY4IxBGbcnXlHSqWz_w":{"address_or_lines":[48,38,174,104,68,60,38,174,104,68,64,38,174,104,68,20,140,10,38,174,104,68,28,38,38,10,38,174,104,68,12,38,174,104,68,4,38,174,104,68,12,38,174,104,68,156,38,174,104,68,48,140,10,38,174,104,68,16,38,138,138,16,100,12,4,6,4,38,174,104,68,8,38,174,104,68,32,38,174,104,68,24,140,10,38,174,104,68,210,1090933,1814182,788459,788130,1197048,1243927,788130,1197115,1198576,1948785,1941513],"file_ids":["a5aMcPOeWx28QSVng73nBQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","79pMuEW6_o55K0jHDJ-2dQ","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","mHiYHSEggclUi1ELZIxq4A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","_GLtmpX5QFDXCzO6KY35mA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","CF4TEudhKTIdEsoPP0l9iw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","5t_H28X3eSBfyQs-F2v7cA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","z0g3aE3w1Ik-suUArUsniA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","1VzILo0_Ivjn6dWL8BqT1A","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","rTTtzMEIQRrn8RDFEbl1zw","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","zjk1GYHhesH1oTuILj3ToA","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","r63cbyeLjspI6IMVvcBjIg","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","JaHOMfnX0DG4ZnNTpPORVA","MepUYc0jU0AjPrrjuvTgGg","yWt46REABLfKH6PXLAE18A","VQs3Erq77xz92EfpT8sTKw","n7IiY_TlCWEfi47-QpeCLw","Ua3frjTXWBuWpTsQD8aKeA","GtyMRLq4aaDvuQ4C3N95mA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","clFhkTaiph2aOjCNuZDWKA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","DLEY7W0VXWLE5Ol-plW-_w","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","RY-vzTa9LfseI7kmcIcbgQ","fiyOjJSGn-Eja0GP7-aFCg","zP58DjIs7uq1cghmzykyNA","OSzao_jV2aCbdBGfMYY-XA","-pUZ8YYbKKOu4w9rcMsXSw","XnUkhGmJNwiHTUPaIuILqg","4ES22TXzFLCEFBoqI_YoOg","-gq3a70QOgdn9HetYyf2Og","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng","G68hjsyagwq6LpWrMjDdng"],"frame_ids":["a5aMcPOeWx28QSVng73nBQAAAAAAAAAw","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","mHiYHSEggclUi1ELZIxq4AAAAAAAAABA","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK","JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK","MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ","yWt46REABLfKH6PXLAE18AAAAAAAAABk","VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM","n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE","Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG","GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY","fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM","zP58DjIs7uq1cghmzykyNAAAAAAAAAAK","OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm","-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu","XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo","4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE","-gq3a70QOgdn9HetYyf2OgAAAAAAAADS","G68hjsyagwq6LpWrMjDdngAAAAAAEKV1","G68hjsyagwq6LpWrMjDdngAAAAAAG66m","G68hjsyagwq6LpWrMjDdngAAAAAADAfr","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkP4","G68hjsyagwq6LpWrMjDdngAAAAAAEvsX","G68hjsyagwq6LpWrMjDdngAAAAAADAai","G68hjsyagwq6LpWrMjDdngAAAAAAEkQ7","G68hjsyagwq6LpWrMjDdngAAAAAAEknw","G68hjsyagwq6LpWrMjDdngAAAAAAHbxx","G68hjsyagwq6LpWrMjDdngAAAAAAHaAJ"],"type_ids":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3]}},"stack_frames":{"piWSMQrh4r040D0BPNaJvwAAAAAAoAJU":{"file_name":[],"function_name":["ret_from_fork"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAACtfS":{"file_name":[],"function_name":["kthread"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAEFgJ":{"file_name":[],"function_name":["rcu_gp_kthread"],"function_offset":[],"line_number":[]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAAhE5":{"file_name":["../csu/libc-start.c"],"function_name":["__libc_start_main"],"function_offset":[],"line_number":[308]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAZVI":{"file_name":["libmount/src/tab_parse.c"],"function_name":["__mnt_table_parse_mtab"],"function_offset":[],"line_number":[1102]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAY-W":{"file_name":["libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_file"],"function_offset":[],"line_number":[707]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAYhK":{"file_name":["libmount/src/tab_parse.c","libmount/src/tab_parse.c","libmount/src/tab_parse.c"],"function_name":["mnt_table_parse_stream","mnt_table_parse_next","mnt_parse_mountinfo_line"],"function_offset":[],"line_number":[643,506,215]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAO6N":{"file_name":["libmount/src/fs.c","libmount/src/fs.c"],"function_name":["mnt_fs_strdup_options","merge_optstr"],"function_offset":[],"line_number":[751,715]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAASUz":{"file_name":["libmount/src/optstr.c"],"function_name":["mnt_optstr_remove_option"],"function_offset":[],"line_number":[490]},"OTWX4UsOVMrSIF5cD4zUzgAAAAAAAR50":{"file_name":["libmount/src/optstr.c"],"function_name":["mnt_optstr_locate_option"],"function_offset":[],"line_number":[122]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2w1":{"file_name":[],"function_name":["__x64_sys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2uM":{"file_name":[],"function_name":["ksys_getdents64"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK1v8":{"file_name":[],"function_name":["iterate_dir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMuWZ":{"file_name":[],"function_name":["proc_pid_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMrzu":{"file_name":[],"function_name":["next_tgid"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAACq1j":{"file_name":[],"function_name":["pid_nr_ns"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKl_w":{"file_name":[],"function_name":["__do_sys_newfstatat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKlki":{"file_name":[],"function_name":["vfs_statx"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKyG1":{"file_name":[],"function_name":["filename_lookup"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKt7k":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKtt7":{"file_name":[],"function_name":["link_path_walk.part.33"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKta7":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK7NA":{"file_name":[],"function_name":["dput"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg_g":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgzs":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeLa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnjq":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePOo":{"file_name":[],"function_name":["unix_stream_sendmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7HT":{"file_name":[],"function_name":["skb_copy_datagram_from_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAASk0o":{"file_name":[],"function_name":["copy_page_from_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAShZh":{"file_name":[],"function_name":["copyin"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgUld":{"file_name":[],"function_name":["copy_user_enhanced_fast_string"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKg7A":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKgtY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKeEz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAePFy":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeOpA":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAeMVZ":{"file_name":[],"function_name":["unix_stream_read_actor"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7u6":{"file_name":[],"function_name":["skb_copy_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7kW":{"file_name":[],"function_name":["__skb_datagram_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAZ7iE":{"file_name":[],"function_name":["simple_copy_to_iter"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKZiW":{"file_name":[],"function_name":["__check_object_size"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJ7H":{"file_name":[],"function_name":["seq_read"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMqWN":{"file_name":[],"function_name":["proc_single_show"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAMprm":{"file_name":[],"function_name":["proc_pid_limits"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJVd":{"file_name":[],"function_name":["seq_printf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAALJTv":{"file_name":[],"function_name":["seq_vprintf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgQON":{"file_name":[],"function_name":["vsnprintf"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAgWrH":{"file_name":[],"function_name":["memcpy_erms"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqah":{"file_name":[],"function_name":["__x64_sys_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqYM":{"file_name":[],"function_name":["do_pipe2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqU7":{"file_name":[],"function_name":["__do_pipe_flags"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKqSa":{"file_name":[],"function_name":["create_pipe_files"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKh1i":{"file_name":[],"function_name":["alloc_file_clone"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhts":{"file_name":[],"function_name":["alloc_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhqi":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKhaJ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwdF":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAAEFn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKcUM":{"file_name":[],"function_name":["do_sys_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKxcK":{"file_name":[],"function_name":["do_filp_open"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKu55":{"file_name":[],"function_name":["path_openat"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKg3y":{"file_name":[],"function_name":["alloc_empty_file"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgnZ":{"file_name":[],"function_name":["__alloc_file"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvxU":{"file_name":[],"function_name":["kmem_cache_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvpt":{"file_name":[],"function_name":["__slab_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJvhM":{"file_name":[],"function_name":["___slab_alloc"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJu2y":{"file_name":[],"function_name":["new_slab"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJMoT":{"file_name":[],"function_name":["__alloc_pages_nodemask"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIkv":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoACj":{"file_name":[],"function_name":["entry_SYSCALL_64_after_hwframe"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAAEGn":{"file_name":[],"function_name":["do_syscall_64"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKg_Q":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxC":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAQFQm":{"file_name":[],"function_name":["security_file_permission"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKgxo":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAKeJD":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmg3":{"file_name":[],"function_name":["xfs_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAOmdC":{"file_name":[],"function_name":["xfs_file_buffered_aio_read"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAH0j-":{"file_name":[],"function_name":["generic_file_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAASkft":{"file_name":[],"function_name":["copy_page_to_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAShdv":{"file_name":[],"function_name":["copyout"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgAA":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKfyY":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdJz":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd-3C":{"file_name":[],"function_name":["unix_stream_recvmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAd-tk":{"file_name":[],"function_name":["unix_stream_read_generic"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZlea":{"file_name":[],"function_name":["consume_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZltq":{"file_name":[],"function_name":["skb_release_data"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJHy1":{"file_name":[],"function_name":["free_unref_page"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJFUJ":{"file_name":[],"function_name":["free_unref_page_prepare.part.71"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKgyw":{"file_name":[],"function_name":["ksys_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKglI":{"file_name":[],"function_name":["vfs_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAKd8j":{"file_name":[],"function_name":["new_sync_read"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZmbb":{"file_name":[],"function_name":["sock_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAQGQD":{"file_name":[],"function_name":["security_socket_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdME8":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXT4":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcn3R":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcXqg":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJu6z":{"file_name":[],"function_name":["kmem_cache_free"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJuT8":{"file_name":[],"function_name":["__slab_free"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcpNe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAZy0m":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAJwxK":{"file_name":[],"function_name":["kmem_cache_alloc_node"],"function_offset":[],"line_number":[]},"N4ILulabOfF5MnyRJbvDXwAAAAAAEHzT":{"file_name":["/usr/src/debug/Python-2.7.18/Modules/main.c"],"function_name":["Py_Main"],"function_offset":[],"line_number":[645]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD20Q":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["PyRun_SimpleFileExFlags"],"function_offset":[],"line_number":[957]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD1xx":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["PyRun_FileExFlags"],"function_offset":[],"line_number":[1371]},"N4ILulabOfF5MnyRJbvDXwAAAAAAD0wq":{"file_name":["/usr/src/debug/Python-2.7.18/Python/pythonrun.c"],"function_name":["run_mod"],"function_offset":[],"line_number":[1385]},"N4ILulabOfF5MnyRJbvDXwAAAAAADdJo":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalCode"],"function_offset":[],"line_number":[691]},"N4ILulabOfF5MnyRJbvDXwAAAAAADdBO":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalCodeEx"],"function_offset":[],"line_number":[3685]},"N4ILulabOfF5MnyRJbvDXwAAAAAADaC9":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","fast_function"],"function_offset":[],"line_number":[3087,4473,4548]},"N4ILulabOfF5MnyRJbvDXwAAAAAADaoW":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","fast_function"],"function_offset":[],"line_number":[3087,4473,4538]},"N4ILulabOfF5MnyRJbvDXwAAAAAADYlW":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","ext_do_call"],"function_offset":[],"line_number":[3126,4767]},"N4ILulabOfF5MnyRJbvDXwAAAAAABLuy":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/abstract.c"],"function_name":["PyObject_Call"],"function_offset":[],"line_number":[2544]},"N4ILulabOfF5MnyRJbvDXwAAAAAABtnu":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/funcobject.c"],"function_name":["function_call"],"function_offset":[],"line_number":[523]},"N4ILulabOfF5MnyRJbvDXwAAAAAADYFz":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c","/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx","call_function","do_call"],"function_offset":[],"line_number":[3087,4475,4670]},"N4ILulabOfF5MnyRJbvDXwAAAAAACasJ":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/typeobject.c"],"function_name":["type_call"],"function_offset":[],"line_number":[765]},"N4ILulabOfF5MnyRJbvDXwAAAAAACd8S":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/typeobject.c"],"function_name":["slot_tp_init"],"function_offset":[],"line_number":[5869]},"N4ILulabOfF5MnyRJbvDXwAAAAAABZYn":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/classobject.c"],"function_name":["instancemethod_call"],"function_offset":[],"line_number":[2600]},"N4ILulabOfF5MnyRJbvDXwAAAAAABtkY":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/funcobject.c"],"function_name":["function_call"],"function_offset":[],"line_number":[523]},"N4ILulabOfF5MnyRJbvDXwAAAAAADV_P":{"file_name":["/usr/src/debug/Python-2.7.18/Python/ceval.c"],"function_name":["PyEval_EvalFrameEx"],"function_offset":[],"line_number":[1629]},"N4ILulabOfF5MnyRJbvDXwAAAAAAB9cG":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/dictobject.c"],"function_name":["dict_subscript"],"function_offset":[],"line_number":[1261]},"N4ILulabOfF5MnyRJbvDXwAAAAAAB7wG":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/dictobject.c"],"function_name":["lookdict"],"function_offset":[],"line_number":[351]},"N4ILulabOfF5MnyRJbvDXwAAAAAACDtP":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["PyObject_RichCompareBool"],"function_offset":[],"line_number":[1009]},"N4ILulabOfF5MnyRJbvDXwAAAAAACDr6":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c","/usr/src/debug/Python-2.7.18/Objects/object.c","/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["PyObject_RichCompare","do_richcmp","try_3way_to_rich_compare"],"function_offset":[],"line_number":[987,940,921]},"N4ILulabOfF5MnyRJbvDXwAAAAAACByz":{"file_name":["/usr/src/debug/Python-2.7.18/Objects/object.c"],"function_name":["convert_3way_to_object"],"function_offset":[],"line_number":[881]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZnfB":{"file_name":[],"function_name":["sock_read_iter"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAdNQM":{"file_name":[],"function_name":["inet_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcYcI":{"file_name":[],"function_name":["tcp_recvmsg"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcqWe":{"file_name":[],"function_name":["__tcp_send_ack.part.47"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZz1R":{"file_name":[],"function_name":["__alloc_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAZyV9":{"file_name":[],"function_name":["__kmalloc_reserve.isra.57"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAJ0bR":{"file_name":[],"function_name":["__kmalloc_node_track_caller"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAIdpk":{"file_name":[],"function_name":["kmalloc_slab"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcpF4":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNCx":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcNYI":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAcK1g":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaM05":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAAaMRj":{"file_name":[],"function_name":["validate_xmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAoA6J":{"file_name":[],"function_name":["do_softirq_own_stack"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAwADc":{"file_name":[],"function_name":["__softirqentry_text_start"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaPZZ":{"file_name":[],"function_name":["net_rx_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNu-":{"file_name":[],"function_name":["process_backlog"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaNlU":{"file_name":[],"function_name":["__netif_receive_skb_one_core"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcGcb":{"file_name":[],"function_name":["ip_rcv"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcF0h":{"file_name":[],"function_name":["ip_rcv_finish"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcFmf":{"file_name":[],"function_name":["ip_rcv_finish_core.isra.16"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDij":{"file_name":[],"function_name":["ip_route_input_noref"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDcq":{"file_name":[],"function_name":["ip_route_input_rcu"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcDJ4":{"file_name":[],"function_name":["ip_route_input_slow"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdks6":{"file_name":[],"function_name":["__fib_lookup"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbDwa":{"file_name":[],"function_name":["fib_rules_lookup"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdk6y":{"file_name":[],"function_name":["fib4_rule_action"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAdZvh":{"file_name":[],"function_name":["fib_table_lookup"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAFci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAABEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAM8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAALw8":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAADhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAE3-":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"GdaBUD9IUEkKxIBryNqV2wAAAAAAAJtO":{"file_name":["clidriver.py"],"function_name":["create_parser"],"function_offset":[4],"line_number":[635]},"QU8QLoFK6ojrywKrBFfTzAAAAAAAACqM":{"file_name":["clidriver.py"],"function_name":["_get_command_table"],"function_offset":[3],"line_number":[580]},"V558DAsp4yi8bwa8eYwk5QAAAAAAAG60":{"file_name":["clidriver.py"],"function_name":["_create_command_table"],"function_offset":[18],"line_number":[615]},"tuTnMBfyc9UiPsI0QyvErAAAAAAAANis":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[700]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAAPvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"cHp4MwXaY5FCuFRuAA6tWwAAAAAAAOx8":{"file_name":["waiters.py"],"function_name":["add_waiters"],"function_offset":[11],"line_number":[36]},"-9oyoP4Jj2iRkwEezqId-gAAAAAAAFMc":{"file_name":["waiters.py"],"function_name":["get_waiter_model_from_service_model"],"function_offset":[5],"line_number":[48]},"3FRCbvQLPuJyn2B-2wELGwAAAAAAAJK8":{"file_name":["session.py"],"function_name":["get_waiter_model"],"function_offset":[4],"line_number":[527]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAHeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAANQg":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAABvY":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAOAI":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcn84":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcL7B":{"file_name":[],"function_name":["__ip_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcMQY":{"file_name":[],"function_name":["ip_output"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAcJtw":{"file_name":[],"function_name":["ip_finish_output2"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaMAz":{"file_name":[],"function_name":["__dev_queue_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaLaf":{"file_name":[],"function_name":["dev_hard_start_xmit"],"function_offset":[],"line_number":[]},"aUXpdArtZf510BJKvwiFDwAAAAAAAAok":{"file_name":[],"function_name":["veth_xmit"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAaGr1":{"file_name":[],"function_name":["__dev_forward_skb"],"function_offset":[],"line_number":[]},"9LzzIocepYcOjnUsLlgOjgAAAAAAbgzT":{"file_name":[],"function_name":["eth_type_trans"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAi0":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAABci":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAANEM":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAI8S":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAPhg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAEeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAA58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABTm":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAACzA":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"ktj-IOmkEpvZJouiJkQjTgAAAAAAAEYa":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[117],"line_number":[854]},"O_h7elJSxPO7SiCsftYRZgAAAAAAAPSm":{"file_name":["client.py"],"function_name":["create_client"],"function_offset":[52],"line_number":[142]},"_s_-RvH9Io2qUzM6f5JLGgAAAAAAAGfw":{"file_name":["client.py"],"function_name":["_create_client_class"],"function_offset":[12],"line_number":[160]},"8UGQaqEhTX9IIJEQCXnRsQAAAAAAAG5o":{"file_name":["client.py"],"function_name":["_create_methods"],"function_offset":[5],"line_number":[319]},"jn4X0YIYIsTeszwLEaje9gAAAAAAACEE":{"file_name":["client.py"],"function_name":["_create_api_method"],"function_offset":[25],"line_number":[356]},"TesF2I_BvQoOuJH9P_M2mAAAAAAAAGk-":{"file_name":["docstring.py"],"function_name":["__init__"],"function_offset":[9],"line_number":[36]},"ew01Dk0sWZctP-VaEpavqQAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAABnNL":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"ew01Dk0sWZctP-VaEpavqQAAAAAADkzO":{"file_name":[],"function_name":["down_read_trylock"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAAGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAIQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAAJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAMsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAABbM":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAACrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAADAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAAdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAJQW":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"ne8F__HPIVgxgycJADVSzAAAAAAAAB9A":{"file_name":["clidriver.py"],"function_name":["invoke"],"function_offset":[29],"line_number":[930]},"CwUjPVV5_7q7c0GhtW0aPwAAAAAAALcE":{"file_name":["session.py"],"function_name":["create_client"],"function_offset":[112],"line_number":[848]},"okehWevKsEA4q6dk779jgwAAAAAAAH1M":{"file_name":["session.py"],"function_name":["get_credentials"],"function_offset":[12],"line_number":[445]},"-IuadWGT89NVzIyF_EmodwAAAAAAAMKw":{"file_name":["credentials.py"],"function_name":["load_credentials"],"function_offset":[18],"line_number":[1953]},"XXJY7v4esGWnaxtMW3FA0gAAAAAAAJ08":{"file_name":["credentials.py"],"function_name":["load"],"function_offset":[18],"line_number":[1009]},"FbrXdcA4j750RyQ3q9JXMwAAAAAAAIKa":{"file_name":["utils.py"],"function_name":["retrieve_iam_role_credentials"],"function_offset":[30],"line_number":[517]},"pL34QuyxyP6XYzGDBMK_5wAAAAAAAH_a":{"file_name":["utils.py"],"function_name":["_get_iam_role"],"function_offset":[1],"line_number":[524]},"IoAk4kM-M4DsDPp7ia5QXwAAAAAAAKvK":{"file_name":["utils.py"],"function_name":["_get_request"],"function_offset":[32],"line_number":[435]},"uHLoBslr3h6S7ooNeXzEbwAAAAAAAJQ8":{"file_name":["httpsession.py"],"function_name":["send"],"function_offset":[56],"line_number":[487]},"iRoTPXvR_cRsnzDO-aurpQAAAAAAAHbc":{"file_name":["connectionpool.py"],"function_name":["urlopen"],"function_offset":[361],"line_number":[894]},"fB79lJck2X90l-j7VqPR-QAAAAAAAGc8":{"file_name":["connectionpool.py"],"function_name":["_make_request"],"function_offset":[116],"line_number":[494]},"gbMheDI1NZ3NY96J0seddgAAAAAAAEuq":{"file_name":["client.py"],"function_name":["getresponse"],"function_offset":[58],"line_number":[1389]},"GquRfhZBLBKr9rIBPuH3nAAAAAAAAE4w":{"file_name":["client.py"],"function_name":["__init__"],"function_offset":[28],"line_number":[276]},"_DA_LSFNMjbu9L2DcselpwAAAAAAAJFI":{"file_name":["socket.py"],"function_name":["makefile"],"function_offset":[40],"line_number":[343]},"8EY5iPD5-FtlXFBTyb6lkwAAAAAAAPtm":{"file_name":["pyi_rth_pkgutil.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"ik6PIX946fW_erE7uBJlVQAAAAAAAILu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAIr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"dCCKy6JoX0PADOFic8hRNQAAAAAAAO-w":{"file_name":["pkgutil.py"],"function_name":[""],"function_offset":[315],"line_number":[316]},"9w9lF96vJW7ZhBoZ8ETsBwAAAAAAAEgm":{"file_name":["functools.py"],"function_name":["register"],"function_offset":[50],"line_number":[902]},"xUQuo4OgBaS_Le-fdAwt8AAAAAAAAEDw":{"file_name":["functools.py"],"function_name":["_is_union_type"],"function_offset":[2],"line_number":[843]},"zkPjzY2Et3KehkHOcSphkAAAAAAAADpY":{"file_name":["typing.py"],"function_name":[""],"function_offset":[2084],"line_number":[2085]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAABhk":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"a5aMcPOeWx28QSVng73nBQAAAAAAAAAw":{"file_name":["aws"],"function_name":[""],"function_offset":[5],"line_number":[19]},"OSzao_jV2aCbdBGfMYY-XAAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[5],"line_number":[1007]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[19],"line_number":[986]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAABo":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[21],"line_number":[680]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAABE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[499]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAH0":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[49],"line_number":[62]},"gZNrskHHFmNkCQ_HaCv8sAAAAAAAAAAc":{"file_name":["core.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"LUEJ1TSRGwRkHbcAyZ3RuQAAAAAAAAAs":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[5],"line_number":[18]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAAAm":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[5],"line_number":[972]},"zP58DjIs7uq1cghmzykyNAAAAAAAAAAK":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[228]},"9h_0PKFtQeN0f7xWevHlTQAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"nIG-LJ6Pj1PzNMyyppUoqgAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAM4":{"file_name":["application.py"],"function_name":[""],"function_offset":[114],"line_number":[115]},"IlUL618nbeW5Kz4uyGZLrQAAAAAAAAB0":{"file_name":["application.py"],"function_name":["Application"],"function_offset":[91],"line_number":[206]},"U7DZUwH_4YU5DSkoQhGJWwAAAAAAAAAM":{"file_name":["typing.py"],"function_name":["inner"],"function_offset":[3],"line_number":[274]},"bmb3nSRfimrjfhanpjR1rQAAAAAAAAAI":{"file_name":["typing.py"],"function_name":["__getitem__"],"function_offset":[2],"line_number":[354]},"oN7OWDJeuc8DmI2f_earDQAAAAAAAAA2":{"file_name":["typing.py"],"function_name":["Union"],"function_offset":[32],"line_number":[466]},"Yj7P3-Rt3nirG6apRl4A7AAAAAAAAAAM":{"file_name":["typing.py"],"function_name":[""],"function_offset":[0],"line_number":[466]},"pz3Evn9laHNJFMwOKIXbswAAAAAAAAAu":{"file_name":["typing.py"],"function_name":["_type_check"],"function_offset":[18],"line_number":[155]},"7aaw2O1Vn7-6eR8XuUWQZQAAAAAAAAAW":{"file_name":["typing.py"],"function_name":["_type_convert"],"function_offset":[4],"line_number":[132]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAIGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAAQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAIJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAEsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAIHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAA10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAACs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAACXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAIFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAIbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAMKO":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"SD7uzoegJjRT3jYNpuQ5wQAAAAAAAPBK":{"file_name":["configure.py"],"function_name":[""],"function_offset":[56],"line_number":[57]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAOpK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"lOUbi56SanKTCh9Y7fIwDwAAAAAAAP2g":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1099]},"n74P5OxFm1hAo5ZWtgcKHQAAAAAAAHGe":{"file_name":["__init__.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[93]},"zXbqXCWr0lCbi_b24hNBRQAAAAAAAFJe":{"file_name":["pyimod02_importers.py"],"function_name":["find_spec"],"function_offset":[87],"line_number":[302]},"piWSMQrh4r040D0BPNaJvwAAAAAAKgEg":{"file_name":[],"function_name":["ksys_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKf4s":{"file_name":[],"function_name":["vfs_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAKdQa":{"file_name":[],"function_name":["new_sync_write"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXmG":{"file_name":[],"function_name":["sock_write_iter"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAZXjj":{"file_name":[],"function_name":["sock_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcK5W":{"file_name":[],"function_name":["tcp_sendmsg"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcKWq":{"file_name":[],"function_name":["tcp_sendmsg_locked"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcbOh":{"file_name":[],"function_name":["__tcp_push_pending_frames"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcaTc":{"file_name":[],"function_name":["tcp_write_xmit"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcYo_":{"file_name":[],"function_name":["__tcp_transmit_skb"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAcYWv":{"file_name":[],"function_name":["__tcp_select_window"],"function_offset":[],"line_number":[]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAEQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAIVW":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJHc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAE10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAGXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"ik6PIX946fW_erE7uBJlVQAAAAAAAHLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAANLe":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"uo8E5My6tupMEt-pfV-uhAAAAAAAAKIu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAEY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAGkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAAAE":{"file_name":["application.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"ZBnr-5IlLVGCdkX_lTNKmwAAAAAAAABY":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"4ES22TXzFLCEFBoqI_YoOgAAAAAAAAAO":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[13],"line_number":[482]},"NNy6Y3cHKuqblVbtSVjWfwAAAAAAAAAg":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[14],"line_number":[298]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAAC-":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[18],"line_number":[304]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAFpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAKDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAEn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAHYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"6WJ6x4R10ox82_e3Ea4eiAAAAAAAAKXw":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[10],"line_number":[78]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAAxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAABRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAKqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAHLq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"l97YFeEKpeLfa-lEAZVNcAAAAAAAAOZu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAABBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAAFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAILi":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEGc":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAABeq":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAE58":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAOEK":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAOys":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAJUK":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAM1M":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAADlS":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAL4m":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAGTS":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"-T5rZCijT5TDJjmoEi8KxgAAAAAAAJP8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[533]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAALeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAB1w":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAHKK":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAMT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAANF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAI10":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAAKs0":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"ik6PIX946fW_erE7uBJlVQAAAAAAANLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAANr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAHFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAA1i":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"ynoRUNDFNh_CC1ViETMulAAAAAAAABSW":{"file_name":["subscribe.py"],"function_name":[""],"function_offset":[150],"line_number":[151]},"fxzD8soKl4etJ4L6nJl81gAAAAAAAHBe":{"file_name":["utils.py"],"function_name":[""],"function_offset":[584],"line_number":[585]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAFtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAHSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAHJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAABpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAJHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFoc":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAEpm":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAJDc":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"Af6E3BeG383JVVbu67NJ0QAAAAAAAAn0":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[33],"line_number":[58]},"xwuAPHgc12-8PZB3i-320gAAAAAAADYk":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[2],"line_number":[63]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAMxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAANRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAGqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAAFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"BrhWuphS0ZH9x8_V0fpb0AAAAAAAAPxi":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[106],"line_number":[107]},"780bLUPADqfQ3x1T5lnVOgAAAAAAAJsu":{"file_name":["emr.py"],"function_name":[""],"function_offset":[42],"line_number":[43]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAJcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAKrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAALAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAIdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAABCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAAu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAN-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAAGsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAPZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAADdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"rTFMSHhLRlj86vHPR06zoQAAAAAAAEfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAKNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAIY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAADeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAGBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAAFNo":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"yaTrLhUSIq2WitrTHLBy3QAAAAAAAGcY":{"file_name":["posixpath.py"],"function_name":["join"],"function_offset":[21],"line_number":[92]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAMiA":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAGxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAHRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"08Dc0vnMK9C_nl7yQB6ZKQAAAAAAAMP6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[47],"line_number":[48]},"zuPG_tF81PcJTwjfBwKlDgAAAAAAADW4":{"file_name":["abc.py"],"function_name":[""],"function_offset":[267],"line_number":[268]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAKBs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAABKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"pv4wAezdMMO0SVuGgaEMTgAAAAAAAHV2":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[17],"line_number":[18]},"LEy-wm0GIvRoYVAga55HiwAAAAAAALxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAMRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAFqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAIFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"qns5vQ3LMi6QrIMOgD_TwQAAAAAAAAR-":{"file_name":["service.py"],"function_name":[""],"function_offset":[20],"line_number":[21]},"J_Lkq1OzUHxWQhnTgF6FwAAAAAAAALq2":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"XkOSW26Xa6_lkqHv5givKgAAAAAAAEnG":{"file_name":["compat.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"BuJIbGFo3xNyZaTAXvW1AgAAAAAAAMqS":{"file_name":["datetime.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"L9BMhx_jo5vrPGr_NYlXCQAAAAAAAG9-":{"file_name":["datetime.py"],"function_name":["timezone"],"function_offset":[97],"line_number":[2394]},"pZhbjLL2hYCcec5rSvEEGwAAAAAAAMsk":{"file_name":["datetime.py"],"function_name":["__neg__"],"function_offset":[3],"line_number":[768]},"kkqG_q7yucIGLE7ky-QX9AAAAAAAAI3I":{"file_name":["datetime.py"],"function_name":["__new__"],"function_offset":[99],"line_number":[691]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAOT2":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"LF6DFcGHEMqhhhlptO_M_QAAAAAAAPF8":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[12],"line_number":[101]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAACzq":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAN3q":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"uSWUCgHgLPG4OFtPdUp0rgAAAAAAAHtu":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"DTRaillMS4wmG2CDEfm9rQAAAAAAAEGE":{"file_name":["aws"],"function_name":[""],"function_offset":[25],"line_number":[26]},"U4Le8nh-beog_B7jq7uTIAAAAAAAAMQi":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"CqoTgn4VUlwTNyUw7wsMHQAAAAAAAEJs":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"SjQZVYGLzro7G-9yPjVJlgAAAAAAAAsS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[12],"line_number":[176]},"grZNsSElR5ITq8H2yHCNSwAAAAAAAHcs":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[18],"line_number":[200]},"W8AFtEsepzrJ6AasHrCttwAAAAAAAGrg":{"file_name":["clidriver.py"],"function_name":["_run_driver"],"function_offset":[2],"line_number":[180]},"sur1OQS0yB3u_A1ZgjRjFgAAAAAAAJAK":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[23],"line_number":[459]},"EFJHOn-GACfHXgae-R1yDAAAAAAAAEdM":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[7],"line_number":[595]},"kSaNXrGzSS3BnDNNWezzMAAAAAAAAPCa":{"file_name":["clidriver.py"],"function_name":["__call__"],"function_offset":[57],"line_number":[798]},"MYrgKQIxdDhr1gdpucfc-QAAAAAAAL-q":{"file_name":["clidriver.py"],"function_name":["_create_argument_table"],"function_offset":[26],"line_number":[867]},"un9fLDZOLvDMO52ltZtuegAAAAAAACsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAALZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAPdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAALvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAACfG":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAAGNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAEY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"FqNqtF0e0OG1VJJtWE9clwAAAAAAAPeU":{"file_name":["loaders.py"],"function_name":["_wrapper"],"function_offset":[8],"line_number":[132]},"GEIvPhvjHWZLHz2BksVgvAAAAAAAAEBA":{"file_name":["loaders.py"],"function_name":["load_service_model"],"function_offset":[45],"line_number":[386]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAADOE":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAC7Rc":{"file_name":["../sysdeps/posix/readdir.c"],"function_name":["__readdir"],"function_offset":[],"line_number":[65]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK2pa":{"file_name":[],"function_name":["__x64_sys_getdents"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOkGr":{"file_name":[],"function_name":["xfs_readdir"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAOjnO":{"file_name":[],"function_name":["xfs_dir2_sf_getdents.isra.9"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAN1i4":{"file_name":[],"function_name":["xfs_dir2_sf_get_parent_ino"],"function_offset":[],"line_number":[]},"MU3fJpOZe9TA4mzeo52wZgAAAAAAAP6m":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[297],"line_number":[298]},"auEGiAr7C6IfT0eiHbOlyAAAAAAAAFg6":{"file_name":["session.py"],"function_name":[""],"function_offset":[184],"line_number":[185]},"mP9Tk3T74fjOyYWKUaqdMQAAAAAAADDi":{"file_name":["client.py"],"function_name":[""],"function_offset":[119],"line_number":[120]},"I4X8AC1-B0GuL4JyYemPzwAAAAAAAGO6":{"file_name":["args.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"s6flibJ32CsA8wnq-j6RkQAAAAAAAJEy":{"file_name":["regions.py"],"function_name":[""],"function_offset":[139],"line_number":[140]},"ik6PIX946fW_erE7uBJlVQAAAAAAAOL8":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"3EA5Wz2lIIw6eu5uv4gkTwAAAAAAACDI":{"file_name":["_bootstrap.py"],"function_name":["__exit__"],"function_offset":[1],"line_number":[174]},"hjYcB64xHdoySaNOZ8xYqgAAAAAAADsY":{"file_name":["_bootstrap.py"],"function_name":["release"],"function_offset":[2],"line_number":[127]},"Gp9aOxUrrpSVBx4-ftlTOAAAAAAAAAdC":{"file_name":["auth.py"],"function_name":[""],"function_offset":[603],"line_number":[604]},"ik6PIX946fW_erE7uBJlVQAAAAAAAJLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAJr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAADFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"y9R94bQUxts02WzRWfV7xgAAAAAAAHeC":{"file_name":["auth.py"],"function_name":[""],"function_offset":[316],"line_number":[317]},"uI6css-d8SGQRK6a_Ntl-AAAAAAAAIVu":{"file_name":["auth.py"],"function_name":[""],"function_offset":[336],"line_number":[337]},"SlnkBp0IIJFLHVOe4KbxwQAAAAAAANt6":{"file_name":["http.py"],"function_name":[""],"function_offset":[231],"line_number":[232]},"uPGvGNXBf1JXGeeDSsmGQAAAAAAAACX2":{"file_name":["enum.py"],"function_name":["__new__"],"function_offset":[194],"line_number":[679]},"PmtIuZrIdDPbhY30JCQRwwAAAAAAADto":{"file_name":["enum.py"],"function_name":["__set_name__"],"function_offset":[96],"line_number":[333]},"yos2k6ZH69vZXiBQV3d7cQAAAAAAAKJ4":{"file_name":["enum.py"],"function_name":["__setattr__"],"function_offset":[11],"line_number":[839]},"xNMiNBkMujk7ZnRv0OEjrQAAAAAAAIu8":{"file_name":["clidriver.py"],"function_name":["arg_table"],"function_offset":[4],"line_number":[733]},"un9fLDZOLvDMO52ltZtuegAAAAAAAOsM":{"file_name":["clidriver.py"],"function_name":["_emit"],"function_offset":[1],"line_number":[874]},"grikUXlisBLUbeL_OWixIwAAAAAAAHZs":{"file_name":["session.py"],"function_name":["emit"],"function_offset":[1],"line_number":[699]},"oERZXsH8EPeoSRxNNaSWfQAAAAAAAHdy":{"file_name":["hooks.py"],"function_name":["emit"],"function_offset":[11],"line_number":[228]},"gMhgHDYSMmyInNJ15VwYFgAAAAAAADvy":{"file_name":["hooks.py"],"function_name":["_emit"],"function_offset":[38],"line_number":[215]},"rTFMSHhLRlj86vHPR06zoQAAAAAAACm2":{"file_name":["paginate.py"],"function_name":["unify_paging_params"],"function_offset":[51],"line_number":[175]},"oArGmvsy3VNtTf_V9EHNeQAAAAAAACNy":{"file_name":["paginate.py"],"function_name":["get_paginator_config"],"function_offset":[10],"line_number":[92]},"7v-k2b21f_Xuf-3329jFywAAAAAAAAY8":{"file_name":["session.py"],"function_name":["get_paginator_model"],"function_offset":[4],"line_number":[532]},"--q8cwZVXbHL2zOM_p3RlQAAAAAAADMg":{"file_name":["loaders.py"],"function_name":["list_available_services"],"function_offset":[38],"line_number":[285]},"wXOyVgf5_nNg6CUH5kFBbgAAAAAAABkK":{"file_name":["loaders.py"],"function_name":[""],"function_offset":[0],"line_number":[273]},"zEgDK4qMawUAQZjg5YHywwAAAAAAAGC0":{"file_name":["genericpath.py"],"function_name":["isdir"],"function_offset":[6],"line_number":[45]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKl7Y":{"file_name":[],"function_name":["__do_sys_newstat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKt69":{"file_name":[],"function_name":["path_lookupat"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKtXX":{"file_name":[],"function_name":["walk_component"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAKsux":{"file_name":[],"function_name":["lookup_fast"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAK8mW":{"file_name":[],"function_name":["__d_lookup_rcu"],"function_offset":[],"line_number":[]},"ik6PIX946fW_erE7uBJlVQAAAAAAAELu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAEr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"VY0EiAO0DxwLRTE4PfFhdwAAAAAAAN_6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"2AkHKX3hFovQqnWGTZG4BAAAAAAAALbW":{"file_name":["base.py"],"function_name":[""],"function_offset":[44],"line_number":[45]},"JEYMXKhPKBKP90oNIKO6WwAAAAAAABJe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[33],"line_number":[34]},"Fq3uvTWKo9OreZfu-LOYYQAAAAAAAGOG":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[2553],"line_number":[2554]},"f2CfX6aaJGZ4Su3cCY2vCQAAAAAAAOFk":{"file_name":["style.py"],"function_name":[""],"function_offset":[506],"line_number":[507]},"yxUFWTEZsQP-FeNV2RKnFQAAAAAAAJIa":{"file_name":["enum.py"],"function_name":["__prepare__"],"function_offset":[13],"line_number":[483]},"Q2lceMFM0t8w5Hdokg8e8AAAAAAAABv6":{"file_name":["enum.py"],"function_name":["__setitem__"],"function_offset":[93],"line_number":[446]},"a5aMcPOeWx28QSVng73nBQAAAAAAAABK":{"file_name":["aws"],"function_name":[""],"function_offset":[13],"line_number":[27]},"inI9W0bfekFTCpu0ceKTHgAAAAAAAAAG":{"file_name":["aws"],"function_name":["main"],"function_offset":[1],"line_number":[23]},"RPwdw40HEBL87wRkKV2ozwAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[1],"line_number":[86]},"pT2bgvKv3bKR6LMAYtKFRwAAAAAAAAAI":{"file_name":["clidriver.py"],"function_name":["main"],"function_offset":[2],"line_number":[166]},"Rsr7q4vCSh2ppRtyNkwZAAAAAAAAAAAS":{"file_name":["clidriver.py"],"function_name":["_do_main"],"function_offset":[3],"line_number":[185]},"cKQfWSgZRgu_1Goz5QGSHwAAAAAAAABQ":{"file_name":["clidriver.py"],"function_name":["create_clidriver"],"function_offset":[8],"line_number":[97]},"T2fhmP8acUvRZslK7YRDPwAAAAAAAAAY":{"file_name":["plugin.py"],"function_name":["load_plugins"],"function_offset":[23],"line_number":[48]},"lrxXzNEmAlflj7bCNDjxdAAAAAAAAAAE":{"file_name":["plugin.py"],"function_name":["_load_plugins"],"function_offset":[1],"line_number":[62]},"SMoSw8cr-PdrIATvljOPrQAAAAAAAABU":{"file_name":["plugin.py"],"function_name":["_import_plugins"],"function_offset":[8],"line_number":[76]},"xaCec3W8F6xlvd_EISI7vwAAAAAAAAB0":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[15],"line_number":[28]},"QCNrAtEDVSYrGKsToy3LYAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"ocuGLNOciiOP6W8cfH2-qwAAAAAAAABg":{"file_name":["package.py"],"function_name":[""],"function_offset":[12],"line_number":[26]},"bjI4Jot-SXYwqfMr0sl7XgAAAAAAAAA8":{"file_name":["s3uploader.py"],"function_name":[""],"function_offset":[8],"line_number":[22]},"zjBJSIgrJ7WBnrV9WxdKEQAAAAAAAAB8":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[130],"line_number":[143]},"9-_Y7FNFlkawnHBUI4HVnAAAAAAAAAB8":{"file_name":["compat.py"],"function_name":[""],"function_offset":[81],"line_number":[94]},"suQJt7m9qyZP3i8d45HwBQAAAAAAAABk":{"file_name":["managers.py"],"function_name":[""],"function_offset":[18],"line_number":[29]},"fiyOjJSGn-Eja0GP7-aFCgAAAAAAAACM":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[25],"line_number":[1058]},"5w2Emmm2pdiPFBnzFSNcKgAAAAAAAABM":{"file_name":["connection.py"],"function_name":[""],"function_offset":[11],"line_number":[21]},"XnUkhGmJNwiHTUPaIuILqgAAAAAAAAAi":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[7],"line_number":[666]},"1bzyoH1Mbbzc-oKA3fR-7QAAAAAAAAAY":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[7],"line_number":[565]},"BXKFYOU6E7YaW5MDpfBf8wAAAAAAAAAK":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[2],"line_number":[1173]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABCQ":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["__dlopen"],"function_offset":[],"line_number":[87]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABZ0":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlerror.c"],"function_name":["_dlerror_run"],"function_offset":[],"line_number":[163]},"Z_CHd3Zjsh2cWE2NSdbiNQAAAAAAEoNz":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-error-skeleton.c"],"function_name":["__GI__dl_catch_error"],"function_offset":[],"line_number":[198]},"PVZV2uq5ZRt-FFaczL10BAAAAAAAABAF":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/dlfcn/dlopen.c"],"function_name":["dlopen_doit"],"function_offset":[],"line_number":[66]},"3nN3bymnZ8E42aLEtgglmAAAAAAAASmo":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["_dl_open"],"function_offset":[],"line_number":[649]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAS7f":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[269]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAM3G":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-deps.c"],"function_name":["_dl_map_object_deps"],"function_offset":[],"line_number":[253]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAMtx":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-deps.c"],"function_name":["openaux"],"function_offset":[],"line_number":[64]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAINe":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-load.c"],"function_name":["_dl_map_object"],"function_offset":[],"line_number":[1943]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAFxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGJU":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAISm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAGRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAPqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAFFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"93AmMdBRQTTNSFcMQ_YwdgAAAAAAAFCy":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[22],"line_number":[23]},"29RxCcCS3qayH8Wz47EBXQAAAAAAAIzc":{"file_name":["_adapters.py"],"function_name":["CompatibilityFiles"],"function_offset":[81],"line_number":[123]},"mBpjyQvq6ftE7Wm1BUpcFgAAAAAAAPGy":{"file_name":["abc.py"],"function_name":["__new__"],"function_offset":[3],"line_number":[108]},"IWme5rHQfgYd-9YstXSeGAAAAAAAAE_C":{"file_name":["typing.py"],"function_name":["__init_subclass__"],"function_offset":[57],"line_number":[2092]},"79pMuEW6_o55K0jHDJ-2dQAAAAAAAAA8":{"file_name":["clidriver.py"],"function_name":[""],"function_offset":[8],"line_number":[21]},"mHiYHSEggclUi1ELZIxq4AAAAAAAAABA":{"file_name":["session.py"],"function_name":[""],"function_offset":[13],"line_number":[27]},"_GLtmpX5QFDXCzO6KY35mAAAAAAAAAAU":{"file_name":["client.py"],"function_name":[""],"function_offset":[3],"line_number":[16]},"CF4TEudhKTIdEsoPP0l9iwAAAAAAAAAc":{"file_name":["waiter.py"],"function_name":[""],"function_offset":[4],"line_number":[17]},"5t_H28X3eSBfyQs-F2v7cAAAAAAAAAAM":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"z0g3aE3w1Ik-suUArUsniAAAAAAAAAAE":{"file_name":["service.py"],"function_name":[""],"function_offset":[0],"line_number":[13]},"1VzILo0_Ivjn6dWL8BqT1AAAAAAAAAAM":{"file_name":["restdoc.py"],"function_name":[""],"function_offset":[2],"line_number":[15]},"rTTtzMEIQRrn8RDFEbl1zwAAAAAAAACc":{"file_name":["compat.py"],"function_name":[""],"function_offset":[17],"line_number":[31]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAAAw":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[10],"line_number":[11]},"r63cbyeLjspI6IMVvcBjIgAAAAAAAAAQ":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[2],"line_number":[3]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAHxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAIRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAABqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"y4VaggFtn5eGbiM4h45zCgAAAAAAAIhi":{"file_name":["formatter.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"aovhV1VhdNHhPwAmk_rOhgAAAAAAAB0G":{"file_name":["table.py"],"function_name":[""],"function_offset":[189],"line_number":[190]},"px3SfTg4DYOeiT_Yemty2wAAAAAAAAye":{"file_name":["."],"function_name":["utils"],"function_offset":[5],"line_number":[6]},"opI8K6Q9RBhmYCrRVwNTgAAAAAAAAPGW":{"file_name":["initialise.py"],"function_name":[""],"function_offset":[120],"line_number":[121]},"cVEUVwL4zVVcM9r_4PTCXAAAAAAAAJce":{"file_name":["ansitowin32.py"],"function_name":[""],"function_offset":[71],"line_number":[72]},"GGxNFCJdZtgXLG8zgUfn_QAAAAAAAD2y":{"file_name":["ansitowin32.py"],"function_name":["AnsiToWin32"],"function_offset":[182],"line_number":[254]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAANtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAKn8":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALGC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAJBk":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAPDo":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALts":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"ZVYMRqiL5oPAMqs8XcON8QAAAAAAAJl2":{"file_name":["prompttoolkit.py"],"function_name":[""],"function_offset":[58],"line_number":[59]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAHj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAJtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"V6gUZHzBRISi-Z25klK5DQAAAAAAACri":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[37],"line_number":[38]},"zWNEoAKVTnnzSns045VKhwAAAAAAAIsa":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[15],"line_number":[16]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACea":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"1y9WuJpjgBMcQb3shY5phQAAAAAAAOMe":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[45],"line_number":[46]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALkq":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"n4Ao4OZE2osF0FygfcWo3gAAAAAAACw2":{"file_name":["application.py"],"function_name":[""],"function_offset":[237],"line_number":[238]},"NGbZlnLCqeq3LFq89r_SpQAAAAAAAD0-":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[191],"line_number":[192]},"PmhxUKv5sePRxhCBONca8gAAAAAAAAD6":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[19],"line_number":[20]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAMmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"xDXQtI2vA5YySwpx7QFiwAAAAAAAALuy":{"file_name":["popen_forkserver.py"],"function_name":[""],"function_offset":[27],"line_number":[28]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAHRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAKtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"fSQ747oLNh0c0zFQjsVRWgAAAAAAALk2":{"file_name":["forkserver.py"],"function_name":[""],"function_offset":[80],"line_number":[81]},"yp8MidCGMe4czbl-NigsYQAAAAAAAFOm":{"file_name":["connection.py"],"function_name":[""],"function_offset":[524],"line_number":[525]},"2noK4QoWxdzASRHkjOFwVAAAAAAAADGK":{"file_name":["tempfile.py"],"function_name":[""],"function_offset":[547],"line_number":[548]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAMFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAANmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"mfGJjedIJMvFXgX3QuTMfQAAAAAAAPDW":{"file_name":["core.py"],"function_name":[""],"function_offset":[275],"line_number":[276]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAH3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAALSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAIxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAJRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAACqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"9NWoah56eYULAP_zGE9PuwAAAAAAAPHC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[101],"line_number":[102]},"IKrIDHd5n47PpDQsRXxvvgAAAAAAAGmC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[81],"line_number":[82]},"oG7568kMJujZxPJfj7VMjAAAAAAAAAjO":{"file_name":["frontend.py"],"function_name":[""],"function_offset":[390],"line_number":[391]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAABs":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAHKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAPxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAARY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"ywhwSu3fiEha0QwvHF6X9wAAAAAAAHFE":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[43],"line_number":[373]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAAKju":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAAEW2":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAADZ-":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAO3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAACSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAABKa":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAIVS":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAGUy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAJn8":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAKGo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAACVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAACfk":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAACxC":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAACMC":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAADMc":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"HENgRXYeEs7mDD8Gk_MNmgAAAAAAAH1O":{"file_name":["help.py"],"function_name":[""],"function_offset":[202],"line_number":[203]},"fFS0upy5lIaT99RhlTN5LQAAAAAAACWm":{"file_name":["clidocs.py"],"function_name":[""],"function_offset":[399],"line_number":[400]},"lSdGU4igLMOpLhL_6XP15wAAAAAAABZu":{"file_name":["argprocess.py"],"function_name":[""],"function_offset":[278],"line_number":[279]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAAGRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"QAp_Nt6XUeNsCXnAUgW7XgAAAAAAAJC6":{"file_name":["shorthand.py"],"function_name":[""],"function_offset":[132],"line_number":[133]},"20O937106XMbOD0LQR4SPwAAAAAAAGVC":{"file_name":["shorthand.py"],"function_name":["ShorthandParser"],"function_offset":[257],"line_number":[379]},"gPzb0fXoBe1225fbKepMRAAAAAAAAKLy":{"file_name":["shorthand.py"],"function_name":["__init__"],"function_offset":[2],"line_number":[53]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAANSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAANJo":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"OHQX9IWLaZElAgxGbX3P5gAAAAAAAKVG":{"file_name":["_compiler.py"],"function_name":["_code"],"function_offset":[13],"line_number":[584]},"E2b-mzlh_8261-JxcySn-AAAAAAAANJE":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAANai":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"E2b-mzlh_8261-JxcySn-AAAAAAAAM1i":{"file_name":["_compiler.py"],"function_name":["_compile"],"function_offset":[18],"line_number":[55]},"JrU1PwRIxl_8SXdnTESnogAAAAAAAOom":{"file_name":["_compiler.py"],"function_name":["_optimize_charset"],"function_offset":[138],"line_number":[379]},"ik6PIX946fW_erE7uBJlVQAAAAAAADLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAANFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"zWCVT22bUHN0NWIQIBSuKgAAAAAAAOm6":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[32],"line_number":[33]},"zj3hc8VBXxWxcbGVwJZYLAAAAAAAAOye":{"file_name":["basic.py"],"function_name":[""],"function_offset":[31],"line_number":[32]},"EHb2BWbkIivImSAfaUtw-AAAAAAAAPyQ":{"file_name":["named_commands.py"],"function_name":[""],"function_offset":[586],"line_number":[587]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAADj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAFtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"-7Nhzq0bVRejx7IVqpbbZQAAAAAAAKW-":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[96],"line_number":[97]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAAY4":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"M_-aGo2vWhLu7lS5grLv9wAAAAAAAEFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[150]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAALmC":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"ik6PIX946fW_erE7uBJlVQAAAAAAAGLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAAFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"OlTvyWQFXjOweJcs3kiGygAAAAAAAMui":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAPB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAGj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAItm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAACJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAEYy":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAA8c":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"jtp3NDFNJGnK6sK5oOFo8QAAAAAAAJtG":{"file_name":["__init__.py"],"function_name":["compile"],"function_offset":[2],"line_number":[227]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAAFSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAAFJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAPpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAAHHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAFcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAEZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"Gxt7_MN7XgUOe9547JcHVQAAAAAAAAd2":{"file_name":["_parser.py"],"function_name":["__len__"],"function_offset":[1],"line_number":[159]},"LEy-wm0GIvRoYVAga55HiwAAAAAAAExO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAOqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"2L4SW1rQgEVXRj3pZAI3nQAAAAAAAIla":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[97],"line_number":[98]},"Bd3XiVd_ucXTo7t4NwSjLAAAAAAAAD3Q":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1241]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAHSm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAPNq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAAFOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAAGcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAKD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAACAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAAKYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAANee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAIW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAAJj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAANmS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"p5XvqZgoydjTl8thPo5KGwAAAAAAAIFW":{"file_name":["pyimod02_importers.py"],"function_name":["get_code"],"function_offset":[13],"line_number":[158]},"oR5jBuG11Az1rZkKaPBmAgAAAAAAAIKK":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[37],"line_number":[202]},"GP7h96O0_ppGVtc-UpQQIQAAAAAAAC66":{"file_name":["handlers.py"],"function_name":[""],"function_offset":[105],"line_number":[106]},"3HhVgGD2yvuFLpoZq7RfKwAAAAAAAOnq":{"file_name":["cloudfront.py"],"function_name":[""],"function_offset":[179],"line_number":[180]},"-BjW54fwMksXBor9R-YN9wAAAAAAAHD-":{"file_name":["ssh.py"],"function_name":[""],"function_offset":[575],"line_number":[576]},"Npep8JfxWDWZ3roJSD7jPgAAAAAAADRw":{"file_name":["_bootstrap.py"],"function_name":["_handle_fromlist"],"function_offset":[34],"line_number":[1243]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAGtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"A2oiHVwisByxRn5RDT4LjAAAAAAAoBBe":{"file_name":[],"function_name":["page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAABnSX":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItm_":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAItAx":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"A2oiHVwisByxRn5RDT4LjAAAAAAAglhf":{"file_name":[],"function_name":["_raw_spin_lock"],"function_offset":[],"line_number":[]},"ik6PIX946fW_erE7uBJlVQAAAAAAAPLu":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1191]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPr4":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"J1eggTwSzYdi9OsSu1q37gAAAAAAAJFw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"CNgPIV65Suq5GVbO7eJK7gAAAAAAAMbc":{"file_name":["pyimod02_importers.py"],"function_name":["exec_module"],"function_offset":[30],"line_number":[352]},"OlTvyWQFXjOweJcs3kiGygAAAAAAACIS":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[155],"line_number":[156]},"N2mxDWkAZe8CHgZMQpxZ7AAAAAAAAFB2":{"file_name":["connection.py"],"function_name":[""],"function_offset":[87],"line_number":[88]},"r3Nzr2WeUwu3gjU4N-rWyAAAAAAAAPj0":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1156]},"eV_m28NnKeeTL60KO2H3SAAAAAAAABtm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"1eW8DnM19kiBGqMWGVkHPAAAAAAAAGJC":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[23],"line_number":[24]},"2kgk5qEgdkkSXT9cIdjqxQAAAAAAAJyi":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[258],"line_number":[259]},"MsEmysGbXhMvgdbwhcZDCgAAAAAAAGWM":{"file_name":["url.py"],"function_name":[""],"function_offset":[238],"line_number":[239]},"7R-mHvx47pWvF_ng7rKpHwAAAAAAALSc":{"file_name":["__init__.py"],"function_name":["_compile"],"function_offset":[27],"line_number":[299]},"_lF8o5tJDcePvza_IYtgSQAAAAAAALJC":{"file_name":["_compiler.py"],"function_name":["compile"],"function_offset":[21],"line_number":[759]},"TRd7r6mvdzYdjMdTtebtwwAAAAAAAFpU":{"file_name":["_parser.py"],"function_name":["parse"],"function_offset":[25],"line_number":[995]},"bgsqxCFBdtyNwHEAo-3p1wAAAAAAANHY":{"file_name":["_parser.py"],"function_name":["_parse_sub"],"function_offset":[58],"line_number":[505]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAALcu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"5PnOjelHYJZ6ovJAXK5uiQAAAAAAAKZu":{"file_name":["_parser.py"],"function_name":["_parse"],"function_offset":[0],"line_number":[507]},"zjk1GYHhesH1oTuILj3ToAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"qkYSh95E1urNTie_gKbr7wAAAAAAAABY":{"file_name":["connectionpool.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"V8ldXm9NGXsJ182jEHEsUwAAAAAAAAB8":{"file_name":["connection.py"],"function_name":[""],"function_offset":[14],"line_number":[15]},"xVaa0cBWNcFeS-8zFezQgAAAAAAAAABI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"UBINlIxj95Sa_x2_k5IddAAAAAAAAAB4":{"file_name":["ssl_.py"],"function_name":[""],"function_offset":[16],"line_number":[17]},"gRRk0W_9P4SGZLXFJ5KU8QAAAAAAAAFi":{"file_name":["url.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"VIK6i3XoO6nxn9WkNabugAAAAAAAAAAG":{"file_name":["re.py"],"function_name":["compile"],"function_offset":[2],"line_number":[252]},"SGPpASrxkViIc4Sq7x-WYQAAAAAAAABs":{"file_name":["re.py"],"function_name":["_compile"],"function_offset":[15],"line_number":[304]},"9xG1GRY3A4PQMfXDNvrOxQAAAAAAAAAU":{"file_name":["sre_compile.py"],"function_name":["compile"],"function_offset":[5],"line_number":[764]},"cbxfeE2AkqKne6oKUxdB6gAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["parse"],"function_offset":[11],"line_number":[948]},"aEZUIXI_cV9kZCa4-U1NsQAAAAAAAAAy":{"file_name":["sre_parse.py"],"function_name":["_parse_sub"],"function_offset":[8],"line_number":[443]},"MebnOxK5WOhP29sl19JefwAAAAAAAAua":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[341],"line_number":[834]},"MebnOxK5WOhP29sl19JefwAAAAAAAAKs":{"file_name":["sre_parse.py"],"function_name":["_parse"],"function_offset":[98],"line_number":[591]},"LEy-wm0GIvRoYVAga55HiwAAAAAAABxO":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load"],"function_offset":[24],"line_number":[1189]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAACRY":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALqw":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"7bd6QJSfWZZfOOpDMHqLMAAAAAAAAONq":{"file_name":["exceptions.py"],"function_name":[""],"function_offset":[319],"line_number":[320]},"wdQNqQ99iFSdp4ceNJQKBgAAAAAAACOq":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[34],"line_number":[1154]},"ZPxtkRXufuVf4tqV5k5k2QAAAAAAADcA":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[43],"line_number":[1097]},"8R2Lkqe-tYqq-plJ22QNzAAAAAAAAOD4":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[3],"line_number":[193]},"h0l-9tGi18mC40qpcJbyDwAAAAAAAPAK":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[24],"line_number":[446]},"5EZV-eYYYtY-VAcSTmCvtgAAAAAAACYk":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"705jmHYNd7I4Z4L4c0vfiAAAAAAAAFee":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[4],"line_number":[124]},"TBeSzkyqIwKL8td602zDjAAAAAAAAMW-":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"NH3zvSjFAfTSy6bEocpNyQAAAAAAABj8":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[3],"line_number":[88]},"fj70ljef7nDHOqVJGSIoEQAAAAAAAMmS":{"file_name":["client.py"],"function_name":[""],"function_offset":[211],"line_number":[212]},"zo4mnjDJ1PlZka7jS9k2BAAAAAAAAPX-":{"file_name":["ssl.py"],"function_name":[""],"function_offset":[780],"line_number":[781]},"J1eggTwSzYdi9OsSu1q37gAAAAAAALn4":{"file_name":["_bootstrap.py"],"function_name":["_load_unlocked"],"function_offset":[41],"line_number":[707]},"0S3htaCNkzxOYeavDR1GTQAAAAAAANe4":{"file_name":["_bootstrap.py"],"function_name":["module_from_spec"],"function_offset":[14],"line_number":[580]},"rBzW547V0L_mH4nnWK1FUQAAAAAAAHTA":{"file_name":["_bootstrap_external.py"],"function_name":["create_module"],"function_offset":[6],"line_number":[1237]},"eV_m28NnKeeTL60KO2H3SAAAAAAAAESm":{"file_name":["_bootstrap.py"],"function_name":["_call_with_frames_removed"],"function_offset":[8],"line_number":[241]},"3nN3bymnZ8E42aLEtgglmAAAAAAAATA-":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-open.c"],"function_name":["dl_open_worker"],"function_offset":[],"line_number":[424]},"3nN3bymnZ8E42aLEtgglmAAAAAAAALbA":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-reloc.c"],"function_name":["_dl_relocate_object"],"function_offset":[],"line_number":[160]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJyS":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["_dl_lookup_symbol_x"],"function_offset":[],"line_number":[833]},"3nN3bymnZ8E42aLEtgglmAAAAAAAAJel":{"file_name":["/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c","/usr/src/debug/glibc-2.26-193-ga0bc5dd3be/elf/dl-lookup.c"],"function_name":["do_lookup_x","do_lookup_unique","enter_unique_sym"],"function_offset":[],"line_number":[544,322,197]},"ApbUUYSZlAYucbB88oZaGwAAAAAAAADU":{"file_name":["application.py"],"function_name":[""],"function_offset":[40],"line_number":[41]},"bAXCoU3-CU0WlRxl5l1tmwAAAAAAAADk":{"file_name":["buffer.py"],"function_name":[""],"function_offset":[35],"line_number":[36]},"qordvIiilnF7CmkWCAd7eAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"iWpqwwcHV8E8OOnqGCYj9gAAAAAAAABc":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"M61AJsljWf0TM7wD6IJVZwAAAAAAAAAI":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[12],"line_number":[13]},"ED3bhsHkhBwZ5ynmMnkPRAAAAAAAAAAs":{"file_name":["ansi.py"],"function_name":[""],"function_offset":[3],"line_number":[4]},"cZ-wyq9rmPl5QnqP0Smp6QAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"GLV-c6bk0E-nhaaCp6u20wAAAAAAAAAo":{"file_name":["base.py"],"function_name":[""],"function_offset":[6],"line_number":[7]},"c_1Yb4rio2EAH6C9SFwQogAAAAAAAABE":{"file_name":["cursor_shapes.py"],"function_name":[""],"function_offset":[5],"line_number":[6]},"O4ILxZswquMzuET9RRf5QAAAAAAAAAAE":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[0],"line_number":[1]},"coeZ_4yf5sOePIKKlm8FNQAAAAAAAACm":{"file_name":["pyimod01_archive.py"],"function_name":["extract"],"function_offset":[16],"line_number":[302]},"GLV-c6bk0E-nhaaCp6u20wAAAAAAAABA":{"file_name":["base.py"],"function_name":[""],"function_offset":[8],"line_number":[9]},"rJZ4aC9w8bMvzrC0ApyIjgAAAAAAAAAo":{"file_name":["__init__.py"],"function_name":[""],"function_offset":[11],"line_number":[12]},"TC9v9fO0nTP4oypYCgB_1QAAAAAAAAAw":{"file_name":["defaults.py"],"function_name":[""],"function_offset":[7],"line_number":[8]},"piWSMQrh4r040D0BPNaJvwAAAAAAoBCe":{"file_name":[],"function_name":["async_page_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAABncH":{"file_name":[],"function_name":["__do_page_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAIsvf":{"file_name":[],"function_name":["handle_mm_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAIsF6":{"file_name":[],"function_name":["__handle_mm_fault"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJj7r":{"file_name":[],"function_name":["alloc_pages_vma"],"function_offset":[],"line_number":[]},"piWSMQrh4r040D0BPNaJvwAAAAAAJIxB":{"file_name":[],"function_name":["get_page_from_freelist"],"function_offset":[],"line_number":[]},"-pUZ8YYbKKOu4w9rcMsXSwAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_and_load_unlocked"],"function_offset":[15],"line_number":[982]},"JaHOMfnX0DG4ZnNTpPORVAAAAAAAAACK":{"file_name":["_bootstrap.py"],"function_name":["_find_spec"],"function_offset":[24],"line_number":[925]},"MepUYc0jU0AjPrrjuvTgGgAAAAAAAAAQ":{"file_name":["six.py"],"function_name":["find_spec"],"function_offset":[2],"line_number":[192]},"yWt46REABLfKH6PXLAE18AAAAAAAAABk":{"file_name":["_bootstrap.py"],"function_name":["spec_from_loader"],"function_offset":[16],"line_number":[431]},"VQs3Erq77xz92EfpT8sTKwAAAAAAAAAM":{"file_name":["six.py"],"function_name":["is_package"],"function_offset":[7],"line_number":[222]},"n7IiY_TlCWEfi47-QpeCLwAAAAAAAAAE":{"file_name":["six.py"],"function_name":["__getattr__"],"function_offset":[1],"line_number":[121]},"Ua3frjTXWBuWpTsQD8aKeAAAAAAAAAAG":{"file_name":["six.py"],"function_name":["_resolve"],"function_offset":[1],"line_number":[118]},"GtyMRLq4aaDvuQ4C3N95mAAAAAAAAAAE":{"file_name":["six.py"],"function_name":["_import_module"],"function_offset":[2],"line_number":[87]},"clFhkTaiph2aOjCNuZDWKAAAAAAAAAAI":{"file_name":["client.py"],"function_name":[""],"function_offset":[70],"line_number":[71]},"DLEY7W0VXWLE5Ol-plW-_wAAAAAAAAAg":{"file_name":["parser.py"],"function_name":[""],"function_offset":[7],"line_number":[12]},"RY-vzTa9LfseI7kmcIcbgQAAAAAAAAAY":{"file_name":["feedparser.py"],"function_name":[""],"function_offset":[21],"line_number":[26]},"-gq3a70QOgdn9HetYyf2OgAAAAAAAADS":{"file_name":["errors.py"],"function_name":[""],"function_offset":[51],"line_number":[56]}},"executables":{"FWZ9q3TQKZZok58ua1HDsg":"pf-debug-metadata-service","B8JRxL079xbhqQBqGvksAg":"kubelet","edNJ10OjHiWc5nzuTQdvig":"linux-vdso.so.1","piWSMQrh4r040D0BPNaJvw":"vmlinux","QvG8QEGAld88D676NL_Y2Q":"filebeat","MNBJ5seVz_ocW6tcr1HSmw":"metricbeat","QaIvzvU8UoclQMd_OMt-Pg":"elastic-operator","w5zBqPf1_9mIVEf-Rn7EdA":"systemd","Z_CHd3Zjsh2cWE2NSdbiNQ":"libc-2.26.so","OTWX4UsOVMrSIF5cD4zUzg":"libmount.so.1.1.0","v6HIzNa4K6G4nRP9032RIA":"dockerd","hc6JHMKlLXjOZcU9MGxvfg":"kube-proxy","A2oiHVwisByxRn5RDT4LjA":"vmlinux","wfA2BgwfDNXUWsxkJ083Rw":"kubelet","9LzzIocepYcOjnUsLlgOjg":"vmlinux","-pk6w5puGcp-wKnQ61BZzQ":"kubelet","ew01Dk0sWZctP-VaEpavqQ":"vmlinux","YsKzCJ9e4eZnuT00vj7Pcw":"python2.7","N4ILulabOfF5MnyRJbvDXw":"libpython2.7.so.1.0","SbPwzb_Kog2bWn8uc7xhDQ":"aws","xLxcEbwnZ5oNrk99ZsxcSQ":"libpython3.11.so.1.0","aUXpdArtZf510BJKvwiFDw":"veth","WpYcHtr4qx88B8CBJZ2GTw":"aws","-Z7SlEXhuy5tL2BF-xmy3g":"libpython3.11.so.1.0","pRLjmMO0U8sO4DFopfFU5g":"metrics-server","G68hjsyagwq6LpWrMjDdng":"libpython3.9.so.1.0","-V-5ede56KMAXhjFbz84Sw":"csi-provisioner","dGWvVtQJJ5wuqNyQVpi8lA":"zlib.cpython-311-x86_64-linux-gnu.so","jaBVtokSUzfS97d-XKjijg":"libz.so.1","ASi9f26ltguiwFajNwOaZw":"zlib.cpython-311-x86_64-linux-gnu.so","PVZV2uq5ZRt-FFaczL10BA":"libdl-2.26.so","3nN3bymnZ8E42aLEtgglmA":"ld-2.26.so","EX9l-cE0x8X9W8uz4iKUfw":"zlib.cpython-39-x86_64-linux-gnu.so"},"total_frames":150718,"sampling_rate":0.008000000000000002} diff --git a/x-pack/plugins/profiling/common/columnar_view_model.test.ts b/x-pack/plugins/profiling/common/columnar_view_model.test.ts index 12c86401e9de..484e035de716 100644 --- a/x-pack/plugins/profiling/common/columnar_view_model.test.ts +++ b/x-pack/plugins/profiling/common/columnar_view_model.test.ts @@ -5,110 +5,91 @@ * 2.0. */ -import { - createBaseFlameGraph, - createCalleeTree, - createFlameGraph, - decodeStackTraceResponse, -} from '@kbn/profiling-utils'; +import { createFlameGraph } from '@kbn/profiling-utils'; import { sum } from 'lodash'; import { createColumnarViewModel } from './columnar_view_model'; -import { stackTraceFixtures } from './__fixtures__/stacktraces'; +import { baseFlamegraph } from './__fixtures__/base_flamegraph'; describe('Columnar view model operations', () => { - stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { - const { events, stackTraces, stackFrames, executables, totalFrames, samplingRate } = - decodeStackTraceResponse(response); - const tree = createCalleeTree( - events, - stackTraces, - stackFrames, - executables, - totalFrames, - samplingRate - ); - const graph = createFlameGraph(createBaseFlameGraph(tree, samplingRate, seconds)); - - describe(`stacktraces from ${seconds} seconds and upsampled by ${upsampledBy}`, () => { - describe('color values are generated by default', () => { - const viewModel = createColumnarViewModel(graph); - - test('length of colors is equal to length of labels multipled by 4', () => { - expect(viewModel.color.length).toEqual(viewModel.label.length * 4); - }); - - test('length of position0 is equal to length of labels multipled by 2', () => { - expect(viewModel.position0.length).toEqual(viewModel.label.length * 2); - }); - - test('length of position1 is equal to length of labels multipled by 2', () => { - expect(viewModel.position1.length).toEqual(viewModel.label.length * 2); - }); - - test('length of size0 is equal to length of labels', () => { - expect(viewModel.size0.length).toEqual(viewModel.label.length); - }); - - test('length of size1 is equal to length of labels', () => { - expect(viewModel.size1.length).toEqual(viewModel.label.length); - }); - - test('length of values is equal to length of labels', () => { - expect(viewModel.value.length).toEqual(viewModel.label.length); - }); - - test('both position arrays are equal', () => { - expect(viewModel.position0).toEqual(viewModel.position1); - }); - - test('both size arrays are equal', () => { - expect(viewModel.size0).toEqual(viewModel.size1); - }); - - test('sum of colors is greater than zero', () => { - expect(sum(viewModel.color)).toBeGreaterThan(0); - }); - }); - - describe('color values are not generated when disabled', () => { - const viewModel = createColumnarViewModel(graph, false); - - test('length of colors is equal to length of labels multipled by 4', () => { - expect(viewModel.color.length).toEqual(viewModel.label.length * 4); - }); - - test('length of position0 is equal to length of labels multipled by 2', () => { - expect(viewModel.position0.length).toEqual(viewModel.label.length * 2); - }); - - test('length of position1 is equal to length of labels multipled by 2', () => { - expect(viewModel.position1.length).toEqual(viewModel.label.length * 2); - }); - - test('length of size0 is equal to length of labels', () => { - expect(viewModel.size0.length).toEqual(viewModel.label.length); - }); - - test('length of size1 is equal to length of labels', () => { - expect(viewModel.size1.length).toEqual(viewModel.label.length); - }); - - test('length of values is equal to length of labels', () => { - expect(viewModel.value.length).toEqual(viewModel.label.length); - }); - - test('both position arrays are equal', () => { - expect(viewModel.position0).toEqual(viewModel.position1); - }); - - test('both size arrays are equal', () => { - expect(viewModel.size0).toEqual(viewModel.size1); - }); - - test('sum of colors is equal to zero', () => { - expect(sum(viewModel.color)).toEqual(0); - }); - }); + const graph = createFlameGraph(baseFlamegraph); + + describe('color values are generated by default', () => { + const viewModel = createColumnarViewModel(graph); + + it('length of colors is equal to length of labels multipled by 4', () => { + expect(viewModel.color.length).toEqual(viewModel.label.length * 4); + }); + + it('length of position0 is equal to length of labels multipled by 2', () => { + expect(viewModel.position0.length).toEqual(viewModel.label.length * 2); + }); + + it('length of position1 is equal to length of labels multipled by 2', () => { + expect(viewModel.position1.length).toEqual(viewModel.label.length * 2); + }); + + it('length of size0 is equal to length of labels', () => { + expect(viewModel.size0.length).toEqual(viewModel.label.length); + }); + + it('length of size1 is equal to length of labels', () => { + expect(viewModel.size1.length).toEqual(viewModel.label.length); + }); + + it('length of values is equal to length of labels', () => { + expect(viewModel.value.length).toEqual(viewModel.label.length); + }); + + it('both position arrays are equal', () => { + expect(viewModel.position0).toEqual(viewModel.position1); + }); + + it('both size arrays are equal', () => { + expect(viewModel.size0).toEqual(viewModel.size1); + }); + + it('sum of colors is greater than zero', () => { + expect(sum(viewModel.color)).toBeGreaterThan(0); + }); + }); + + describe('color values are not generated when disabled', () => { + const viewModel = createColumnarViewModel(graph, false); + + it('length of colors is equal to length of labels multipled by 4', () => { + expect(viewModel.color.length).toEqual(viewModel.label.length * 4); + }); + + it('length of position0 is equal to length of labels multipled by 2', () => { + expect(viewModel.position0.length).toEqual(viewModel.label.length * 2); + }); + + it('length of position1 is equal to length of labels multipled by 2', () => { + expect(viewModel.position1.length).toEqual(viewModel.label.length * 2); + }); + + it('length of size0 is equal to length of labels', () => { + expect(viewModel.size0.length).toEqual(viewModel.label.length); + }); + + it('length of size1 is equal to length of labels', () => { + expect(viewModel.size1.length).toEqual(viewModel.label.length); + }); + + it('length of values is equal to length of labels', () => { + expect(viewModel.value.length).toEqual(viewModel.label.length); + }); + + it('both position arrays are equal', () => { + expect(viewModel.position0).toEqual(viewModel.position1); + }); + + it('both size arrays are equal', () => { + expect(viewModel.size0).toEqual(viewModel.size1); + }); + + it('sum of colors is equal to zero', () => { + expect(sum(viewModel.color)).toEqual(0); }); }); }); diff --git a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/differential_functions.cy.ts b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/differential_functions.cy.ts index bbbcb6c8abdc..aaf42b56542f 100644 --- a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/differential_functions.cy.ts +++ b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/differential_functions.cy.ts @@ -31,8 +31,8 @@ describe('Differential Functions page', () => { cy.wait('@getTopNFunctions'); [ { id: 'overallPerformance', value: '0%' }, - { id: 'annualizedCo2', value: '33.79 lbs / 15.33 kg' }, - { id: 'annualizedCost', value: '$318.32' }, + { id: 'annualizedCo2', value: '2.5k lbs / 1.13k kg' }, + { id: 'annualizedCost', value: '$10.66k' }, { id: 'totalNumberOfSamples', value: '513' }, ].forEach((item) => { cy.get(`[data-test-subj="${item.id}_value"]`).contains(item.value); @@ -50,8 +50,8 @@ describe('Differential Functions page', () => { cy.wait('@getTopNFunctions'); [ { id: 'overallPerformance', value: '0%' }, - { id: 'annualizedCo2', value: '0 lbs / 0 kg', comparisonValue: '33.79 lbs / 15.33 kg' }, - { id: 'annualizedCost', value: '$0', comparisonValue: '$318.32' }, + { id: 'annualizedCo2', value: '0 lbs / 0 kg', comparisonValue: '2.5k lbs / 1.13k kg' }, + { id: 'annualizedCost', value: '$0', comparisonValue: '$10.66k' }, { id: 'totalNumberOfSamples', value: '0', comparisonValue: '15,390' }, ].forEach((item) => { cy.get(`[data-test-subj="${item.id}_value"]`).contains(item.value); @@ -76,14 +76,14 @@ describe('Differential Functions page', () => { { id: 'overallPerformance', value: '65.89%', icon: 'sortUp_success' }, { id: 'annualizedCo2', - value: '33.79 lbs / 15.33 kg', - comparisonValue: '11.53 lbs / 5.23 kg (65.89%)', + value: '2.5k lbs / 1.13k kg', + comparisonValue: '548.84 lbs / 248.95 kg (78.01%', icon: 'comparison_sortUp_success', }, { id: 'annualizedCost', - value: '$318.32', - comparisonValue: '$108.59 (65.89%)', + value: '$10.66k', + comparisonValue: '$2.35k (78.01%)', icon: 'comparison_sortUp_success', }, { @@ -116,14 +116,14 @@ describe('Differential Functions page', () => { { id: 'overallPerformance', value: '193.14%', icon: 'sortDown_danger' }, { id: 'annualizedCo2', - value: '11.53 lbs / 5.23 kg', - comparisonValue: '33.79 lbs / 15.33 kg (193.14%)', + value: '548.84 lbs / 248.95 kg', + comparisonValue: '2.5k lbs / 1.13k kg (354.66%)', icon: 'comparison_sortDown_danger', }, { id: 'annualizedCost', - value: '$108.59', - comparisonValue: '$318.32 (193.14%)', + value: '$2.35k', + comparisonValue: '$10.66k (354.66%)', icon: 'comparison_sortDown_danger', }, { @@ -167,17 +167,8 @@ describe('Differential Functions page', () => { }); cy.wait('@getTopNFunctions'); cy.wait('@getTopNFunctions'); - cy.get('[data-test-subj="topNFunctionsGrid"] .euiDataGridRow').should('have.length.gt', 1); - cy.get('[data-test-subj="TopNFunctionsComparisonGrid"] .euiDataGridRow').should( - 'have.length.gt', - 1 - ); - cy.get( - '[data-test-subj="topNFunctionsGrid"] [data-test-subj="profilingStackFrameSummaryLink"]' - ).contains('vmlinux'); - cy.get( - '[data-test-subj="TopNFunctionsComparisonGrid"] [data-test-subj="profilingStackFrameSummaryLink"]' - ).contains('vmlinux'); + cy.get('[data-test-subj="frame"]').contains('vmlinux'); + cy.get('[data-test-subj="comparison_frame"]').contains('vmlinux'); cy.addKqlFilter({ key: 'process.thread.name', @@ -190,12 +181,8 @@ describe('Differential Functions page', () => { }); cy.wait('@getTopNFunctions'); cy.wait('@getTopNFunctions'); - cy.get( - '[data-test-subj="topNFunctionsGrid"] [data-test-subj="profilingStackFrameSummaryLink"]' - ).contains('libsystemd-shared-237.so'); - cy.get( - '[data-test-subj="TopNFunctionsComparisonGrid"] [data-test-subj="profilingStackFrameSummaryLink"]' - ).contains('libjvm.so'); + cy.get('[data-test-subj="frame"]').contains('libsystemd-shared-237.so'); + cy.get('[data-test-subj="comparison_frame"]').contains('libjvm.so'); }); }); }); diff --git a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/functions.cy.ts b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/functions.cy.ts index 738f80075607..272b5a1743d6 100644 --- a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/functions.cy.ts +++ b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/functions.cy.ts @@ -7,7 +7,7 @@ import { profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, } from '@kbn/observability-plugin/common'; describe('Functions page', () => { @@ -38,7 +38,7 @@ describe('Functions page', () => { cy.get(firstRowSelector).eq(2).contains('vmlinux'); cy.get(firstRowSelector).eq(3).contains('5.46%'); cy.get(firstRowSelector).eq(4).contains('5.46%'); - cy.get(firstRowSelector).eq(5).contains('1.84 lbs / 0.84 kg'); + cy.get(firstRowSelector).eq(5).contains('4.07 lbs / 1.84 kg'); cy.get(firstRowSelector).eq(6).contains('$17.37'); cy.get(firstRowSelector).eq(7).contains('28'); }); @@ -66,11 +66,11 @@ describe('Functions page', () => { { parentKey: 'impactEstimates', key: 'annualizedSelfCoreSeconds', value: '17.03 days' }, { parentKey: 'impactEstimates', key: 'co2Emission', value: '~0.00 lbs / ~0.00 kg' }, { parentKey: 'impactEstimates', key: 'selfCo2Emission', value: '~0.00 lbs / ~0.00 kg' }, - { parentKey: 'impactEstimates', key: 'annualizedCo2Emission', value: '1.84 lbs / 0.84 kg' }, + { parentKey: 'impactEstimates', key: 'annualizedCo2Emission', value: '4.07 lbs / 1.84 kg' }, { parentKey: 'impactEstimates', key: 'annualizedSelfCo2Emission', - value: '1.84 lbs / 0.84 kg', + value: '4.07 lbs / 1.84 kg', }, { parentKey: 'impactEstimates', key: 'dollarCost', value: '$~0.00' }, { parentKey: 'impactEstimates', key: 'selfDollarCost', value: '$~0.00' }, @@ -133,17 +133,17 @@ describe('Functions page', () => { columnKey: 'annualizedCo2', columnIndex: 5, highRank: 1, - lowRank: 389, - highValue: '1.84 lbs / 0.84 kg', - lowValue: undefined, + lowRank: 44, + highValue: '45.01 lbs / 20.42 kg', + lowValue: '0.15 lbs / 0.07 kg', }, { columnKey: 'annualizedDollarCost', columnIndex: 6, highRank: 1, - lowRank: 389, - highValue: '$17.37', - lowValue: undefined, + lowRank: 44, + highValue: '$192.36', + lowValue: '$0.62', }, ].forEach(({ columnKey, columnIndex, highRank, highValue, lowRank, lowValue }) => { cy.get(`[data-test-subj="dataGridHeaderCell-${columnKey}"]`).click(); @@ -174,15 +174,15 @@ describe('Functions page', () => { cy.get(firstRowSelector).eq(2).contains('/'); }); - describe('Test changing CO2 settings', () => { + // skipping this for now until the values are passed to the ES plugin + describe.skip('Test changing CO2 settings', () => { afterEach(() => { cy.updateAdvancedSettings({ [profilingCo2PerKWH]: 0.000379069, [profilingDatacenterPUE]: 1.7, - [profilingPerCoreWatt]: 7, + [profilingPervCPUWattX86]: 7, }); }); - it('changes CO2 settings and validate values in the table', () => { cy.intercept('GET', '/internal/profiling/topn/functions?*').as('getTopNFunctions'); cy.visitKibana('/app/profiling/functions', { rangeFrom, rangeTo }); @@ -199,7 +199,7 @@ describe('Functions page', () => { cy.get(`[data-test-subj="advancedSetting-editField-${profilingDatacenterPUE}"]`) .clear() .type('2.4'); - cy.get(`[data-test-subj="advancedSetting-editField-${profilingPerCoreWatt}"]`) + cy.get(`[data-test-subj="advancedSetting-editField-${profilingPervCPUWattX86}"]`) .clear() .type('20'); cy.contains('Save changes').click(); diff --git a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/settings.cy.ts b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/settings.cy.ts index 4863afbca437..01e5128aeafa 100644 --- a/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/settings.cy.ts +++ b/x-pack/plugins/profiling/e2e/cypress/e2e/profiling_views/settings.cy.ts @@ -13,7 +13,7 @@ import { profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, } from '@kbn/observability-plugin/common'; describe('Settings page', () => { @@ -25,7 +25,7 @@ describe('Settings page', () => { cy.updateAdvancedSettings({ [profilingCo2PerKWH]: 0.000379069, [profilingDatacenterPUE]: 1.7, - [profilingPerCoreWatt]: 7, + [profilingPervCPUWattX86]: 7, }); }); @@ -35,7 +35,10 @@ describe('Settings page', () => { cy.contains('CO2'); cy.contains('Regional Carbon Intensity (ton/kWh)'); cy.contains('Data Center PUE'); - cy.contains('Per Core Watts'); + cy.contains('Per vCPU Watts - x86'); + cy.contains('Per vCPU Watts - arm64'); + cy.contains('AWS EDP discount rate (%)'); + cy.contains('Cost per vCPU per hour ($)'); }); it('updates values', () => { @@ -48,7 +51,7 @@ describe('Settings page', () => { cy.get(`[data-test-subj="advancedSetting-editField-${profilingDatacenterPUE}"]`) .clear() .type('2.4'); - cy.get(`[data-test-subj="advancedSetting-editField-${profilingPerCoreWatt}"]`) + cy.get(`[data-test-subj="advancedSetting-editField-${profilingPervCPUWattX86}"]`) .clear() .type('20'); cy.get('[data-test-subj="profilingBottomBarActions"]').should('exist'); diff --git a/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx b/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx index 9e4ebc0afeae..3508f3f090c6 100644 --- a/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx +++ b/x-pack/plugins/profiling/public/components/contexts/profiling_dependencies/mock_profiling_dependencies_storybook.tsx @@ -43,6 +43,7 @@ const mockPlugin = { }; const mockCore = { + uiSettings: { get: () => {} }, application: { currentAppId$: new Observable(), getUrlForApp: (appId: string) => '', diff --git a/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_columns.tsx b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_columns.tsx new file mode 100644 index 000000000000..71ead9cd75a8 --- /dev/null +++ b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_columns.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiDataGridColumn, EuiDataGridColumnCellAction } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { TopNComparisonFunctionSortField, TopNFunctionSortField } from '@kbn/profiling-utils'; +import React from 'react'; +import { CPULabelWithHint } from '../cpu_label_with_hint'; +import { LabelWithHint } from '../label_with_hint'; + +export const getColumns = ( + compareFrameAction: EuiDataGridColumnCellAction +): EuiDataGridColumn[] => [ + { + id: TopNFunctionSortField.Rank, + actions: { showHide: false }, + displayAsText: 'Rank', + initialWidth: 65, + schema: 'numeric', + }, + { + id: TopNFunctionSortField.Frame, + actions: { showHide: false }, + displayAsText: i18n.translate('xpack.profiling.functionsView.functionColumnLabel', { + defaultMessage: 'Function', + }), + cellActions: [compareFrameAction], + }, + { + id: TopNFunctionSortField.Samples, + initialWidth: 120, + schema: 'numeric', + actions: { showHide: false }, + display: ( + + ), + }, + { + id: TopNFunctionSortField.SelfCPU, + actions: { showHide: false }, + schema: 'numeric', + initialWidth: 120, + display: ( + + ), + }, + { + id: TopNFunctionSortField.TotalCPU, + actions: { showHide: false }, + schema: 'numeric', + initialWidth: 120, + display: ( + + ), + }, + { + id: TopNComparisonFunctionSortField.ComparisonRank, + actions: { showHide: false }, + schema: 'numeric', + displayAsText: 'Rank', + initialWidth: 69, + displayHeaderCellProps: { className: 'thickBorderLeft' }, + }, + { + id: TopNComparisonFunctionSortField.ComparisonFrame, + actions: { showHide: false }, + displayAsText: i18n.translate('xpack.profiling.functionsView.functionColumnLabel', { + defaultMessage: 'Function', + }), + cellActions: [compareFrameAction], + }, + { + id: TopNComparisonFunctionSortField.ComparisonSamples, + actions: { showHide: false }, + schema: 'numeric', + initialWidth: 120, + display: ( + + ), + }, + { + id: TopNComparisonFunctionSortField.ComparisonSelfCPU, + actions: { showHide: false }, + schema: 'numeric', + initialWidth: 120, + display: ( + + ), + }, + { + id: TopNComparisonFunctionSortField.ComparisonTotalCPU, + actions: { showHide: false }, + schema: 'numeric', + initialWidth: 120, + display: ( + + ), + }, + { + displayAsText: 'Diff', + actions: { showHide: false }, + id: TopNComparisonFunctionSortField.ComparisonDiff, + initialWidth: 70, + isSortable: false, + }, +]; diff --git a/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_compare_frame_action.tsx b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_compare_frame_action.tsx new file mode 100644 index 000000000000..32f6bc826d98 --- /dev/null +++ b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/get_compare_frame_action.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBasicTable, + EuiDataGridColumnCellAction, + EuiDataGridColumnCellActionProps, + EuiPopover, + EuiPopoverTitle, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; +import { getCalleeFunction } from '@kbn/profiling-utils'; +import { getFrameIdentification, isComparisonColumn, SelectedFrame } from '.'; +import { IFunctionRow } from '../topn_functions/utils'; + +interface Props { + baseRows: IFunctionRow[]; + comparisonRows: IFunctionRow[]; + selectedFrame?: SelectedFrame; + onClick: (selectedFrame?: SelectedFrame) => void; +} + +export const getCompareFrameAction = + ({ baseRows, comparisonRows, selectedFrame, onClick }: Props): EuiDataGridColumnCellAction => + ({ rowIndex, columnId, Component }: EuiDataGridColumnCellActionProps) => { + const isComparison = isComparisonColumn(columnId); + const currentRow = isComparison ? comparisonRows[rowIndex] : baseRows[rowIndex]; + if (currentRow === undefined) { + return null; + } + const currentFrameId = getFrameIdentification(currentRow.frame); + + const isOpen = selectedFrame + ? selectedFrame.currentFrameId === currentFrameId && + selectedFrame.isComparison === isComparison + : false; + + const compareRow = isComparison + ? baseRows.find((item) => getFrameIdentification(item.frame) === currentFrameId) + : comparisonRows.find((item) => getFrameIdentification(item.frame) === currentFrameId); + + return ( + { + onClick({ currentFrameId, isComparison }); + }} + iconType="inspect" + > + {i18n.translate('xpack.profiling.compareFrame.component.findLabel', { + defaultMessage: 'Find corresponding frame', + })} + + } + isOpen={isOpen} + closePopover={() => { + onClick(undefined); + }} + anchorPosition="upRight" + css={css` + .euiPopover__anchor { + align-items: start; + display: flex; + } + `} + > + {compareRow ? ( +
    + + {isComparison + ? i18n.translate('xpack.profiling.diffTopNFunctions.baseLineFunction', { + defaultMessage: 'Baseline function', + }) + : i18n.translate('xpack.profiling.diffTopNFunctions.comparisonLineFunction', { + defaultMessage: 'Comparison function', + })} + + + {getCalleeFunction(compareRow.frame)} + + value.samples.toLocaleString(), + }, + { + field: 'selfCPUPerc', + name: 'Self CPU', + render: (_, value) => `${value.selfCPUPerc.toFixed(2)}%`, + }, + { + field: 'totalCPUPerc', + name: 'Total CPU', + render: (_, value) => `${value.totalCPUPerc.toFixed(2)}%`, + }, + ]} + /> +
    + ) : ( + + {i18n.translate('xpack.profiling.diffTopNFunctions.noCorrespondingValueFound', { + defaultMessage: 'No corresponding value found', + })} + + )} +
    + ); + }; diff --git a/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/index.tsx b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/index.tsx new file mode 100644 index 000000000000..a006a4724a9b --- /dev/null +++ b/x-pack/plugins/profiling/public/components/differential_topn_functions_grid/index.tsx @@ -0,0 +1,265 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiDataGrid, + EuiDataGridCellValueElementProps, + EuiDataGridColumn, + EuiDataGridSorting, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import { + getCalleeFunction, + StackFrameMetadata, + TopNComparisonFunctionSortField, + TopNFunctions, + TopNFunctionSortField, +} from '@kbn/profiling-utils'; +import { orderBy } from 'lodash'; +import React, { useEffect, useMemo, useState } from 'react'; +import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; +import { FunctionRow } from '../topn_functions/function_row'; +import { getFunctionsRows, IFunctionRow } from '../topn_functions/utils'; +import { getColumns } from './get_columns'; +import { getCompareFrameAction } from './get_compare_frame_action'; + +const removeComparisonFromId = (id: string) => id.replace('comparison_', ''); +export const isComparisonColumn = (id: string) => id.startsWith('comparison_'); + +type SortDirection = 'asc' | 'desc'; + +function sortRows(data: IFunctionRow[], sortField: string, sortDirection: SortDirection) { + switch (sortField) { + case TopNFunctionSortField.Frame: + return orderBy(data, (row) => getCalleeFunction(row.frame), sortDirection); + case TopNFunctionSortField.SelfCPU: + return orderBy(data, (row) => row.selfCPUPerc, sortDirection); + case TopNFunctionSortField.TotalCPU: + return orderBy(data, (row) => row.totalCPUPerc, sortDirection); + default: + return orderBy(data, sortField, sortDirection); + } +} + +export type OnChangeSortParams = + | { sortField: TopNFunctionSortField; sortDirection: SortDirection } + | { + comparisonSortField: TopNComparisonFunctionSortField; + comparisonSortDirection: SortDirection; + }; + +export function getFrameIdentification(frame: StackFrameMetadata) { + return [ + frame.SourceFilename, + frame.FunctionName, + frame.ExeFileName, + frame.FileID, + frame.AddressOrLine, + ].join('|'); +} + +export interface SelectedFrame { + currentFrameId?: string; + isComparison: boolean; +} + +interface Props { + base?: TopNFunctions; + baselineScaleFactor?: number; + comparison?: TopNFunctions; + comparisonScaleFactor?: number; + onChangePage: (nextPage: number) => void; + onChangeSort: (sorting: OnChangeSortParams) => void; + onFrameClick?: (functionName: string) => void; + pageIndex: number; + sortDirection: 'asc' | 'desc'; + sortField: TopNFunctionSortField; + comparisonSortDirection: 'asc' | 'desc'; + comparisonSortField: TopNComparisonFunctionSortField; + totalSeconds: number; +} + +export function DifferentialTopNFunctionsGrid({ + base, + baselineScaleFactor, + comparison, + comparisonScaleFactor, + onChangePage, + onChangeSort, + pageIndex, + sortDirection, + sortField, + totalSeconds, + onFrameClick, + comparisonSortDirection, + comparisonSortField, +}: Props) { + const calculateImpactEstimates = useCalculateImpactEstimate(); + const [selectedFrame, setSelectedFrame] = useState(); + const theme = useEuiTheme(); + + const totalCount = useMemo(() => { + if (!base || !base.TotalCount) { + return 0; + } + + return base.TotalCount; + }, [base]); + + function onSort(newSortingColumns: EuiDataGridSorting['columns']) { + // As newSortingColumns is an array and we only sort by a single field for both base and comparison + // I need to look for the item that is not the same as in the URL to identify what's the side being sorted. + const sortingItem = newSortingColumns.reverse().find((item) => { + const isComparison = isComparisonColumn(item.id); + if (isComparison) { + return !(comparisonSortField === item.id && comparisonSortDirection === item.direction); + } + return !(sortField === item.id && sortDirection === item.direction); + }); + if (sortingItem) { + const isComparison = isComparisonColumn(sortingItem.id); + onChangeSort( + isComparison + ? { + comparisonSortDirection: sortingItem.direction, + comparisonSortField: sortingItem.id as TopNComparisonFunctionSortField, + } + : { + sortDirection: sortingItem.direction, + sortField: sortingItem.id as TopNFunctionSortField, + } + ); + } + } + + const { baseRows, comparisonRows } = useMemo(() => { + return { + baseRows: getFunctionsRows({ + calculateImpactEstimates, + topNFunctions: base, + totalSeconds: 900, + }), + comparisonRows: getFunctionsRows({ + baselineScaleFactor, + calculateImpactEstimates, + comparisonScaleFactor, + comparisonTopNFunctions: base, + topNFunctions: comparison, + totalSeconds, + }), + }; + }, [ + base, + baselineScaleFactor, + calculateImpactEstimates, + comparison, + comparisonScaleFactor, + totalSeconds, + ]); + + const columns: EuiDataGridColumn[] = useMemo(() => { + const compareFrameAction = getCompareFrameAction({ + baseRows, + comparisonRows, + onClick: setSelectedFrame, + selectedFrame, + }); + return getColumns(compareFrameAction); + }, [baseRows, comparisonRows, selectedFrame]); + + const sortedBaseRows = useMemo(() => { + return sortRows(baseRows, sortField, sortDirection); + }, [baseRows, sortDirection, sortField]); + + const sortedComparisonRows = useMemo(() => { + return sortRows( + comparisonRows, + removeComparisonFromId(comparisonSortField), + comparisonSortDirection + ); + }, [comparisonRows, comparisonSortDirection, comparisonSortField]); + + const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id)); + + function CellValue({ rowIndex, columnId, setCellProps }: EuiDataGridCellValueElementProps) { + const isComparison = isComparisonColumn(columnId); + const data = isComparison ? sortedComparisonRows[rowIndex] : sortedBaseRows[rowIndex]; + + useEffect(() => { + // Add thick border to divide the baseline and comparison columns + if (isComparison && columnId === TopNComparisonFunctionSortField.ComparisonRank) { + setCellProps({ + style: { borderLeft: theme.euiTheme.border.thick }, + }); + } else if (columnId === TopNFunctionSortField.TotalCPU) { + setCellProps({ + style: { borderRight: theme.euiTheme.border.thin }, + }); + } + }, [columnId, isComparison, setCellProps]); + + if (data === undefined) { + return null; + } + + return ( +
    + +
    + ); + } + + const rowCount = Math.min(Math.max(sortedBaseRows.length, sortedComparisonRows.length), 100); + + return ( + {}, + onChangePage, + pageSizeOptions: [], + }} + rowHeightsOptions={{ defaultHeight: 'auto' }} + toolbarVisibility={{ + showColumnSelector: false, + showKeyboardShortcuts: false, + showDisplaySelector: false, + showSortSelector: false, + }} + /> + ); +} diff --git a/x-pack/plugins/profiling/public/components/flamegraph/flamegraph_tooltip.tsx b/x-pack/plugins/profiling/public/components/flamegraph/flamegraph_tooltip.tsx index 2f33170e44fc..75ba9258aeaf 100644 --- a/x-pack/plugins/profiling/public/components/flamegraph/flamegraph_tooltip.tsx +++ b/x-pack/plugins/profiling/public/components/flamegraph/flamegraph_tooltip.tsx @@ -21,48 +21,65 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { isNumber } from 'lodash'; import React from 'react'; +import { profilingUseLegacyCo2Calculation } from '@kbn/observability-plugin/common'; import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; import { asCost } from '../../utils/formatters/as_cost'; import { asPercentage } from '../../utils/formatters/as_percentage'; import { asWeight } from '../../utils/formatters/as_weight'; import { CPULabelWithHint } from '../cpu_label_with_hint'; import { TooltipRow } from './tooltip_row'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; interface Props { - isRoot: boolean; - label: string; - countInclusive: number; - countExclusive: number; - totalSamples: number; - totalSeconds: number; + annualCO2KgsInclusive: number; + annualCostsUSDInclusive: number; baselineScaleFactor?: number; - comparisonScaleFactor?: number; - comparisonCountInclusive?: number; + comparisonAnnualCO2KgsInclusive?: number; + comparisonAnnualCostsUSDInclusive?: number; comparisonCountExclusive?: number; + comparisonCountInclusive?: number; + comparisonScaleFactor?: number; comparisonTotalSamples?: number; comparisonTotalSeconds?: number; - onShowMoreClick?: () => void; + countExclusive: number; + countInclusive: number; inline: boolean; + isRoot: boolean; + label: string; + onShowMoreClick?: () => void; parentLabel?: string; + totalSamples: number; + totalSeconds: number; } export function FlameGraphTooltip({ - isRoot, - label, - countInclusive, - countExclusive, - totalSamples, - totalSeconds, + annualCO2KgsInclusive, + annualCostsUSDInclusive, baselineScaleFactor, - comparisonScaleFactor, - comparisonCountInclusive, + comparisonAnnualCO2KgsInclusive, + comparisonAnnualCostsUSDInclusive, comparisonCountExclusive, + comparisonCountInclusive, + comparisonScaleFactor, comparisonTotalSamples, comparisonTotalSeconds, - onShowMoreClick, + countExclusive, + countInclusive, inline, + isRoot, + label, + onShowMoreClick, parentLabel, + totalSamples, + totalSeconds, }: Props) { + const { + start: { core }, + } = useProfilingDependencies(); + const shouldUseLegacyCo2Calculation = core.uiSettings.get( + profilingUseLegacyCo2Calculation + ); + const theme = useEuiTheme(); const calculateImpactEstimates = useCalculateImpactEstimate(); @@ -170,9 +187,17 @@ export function FlameGraphTooltip({ label={i18n.translate('xpack.profiling.flameGraphTooltip.annualizedCo2', { defaultMessage: `Annualized CO2`, })} - value={impactEstimates.totalCPU.annualizedCo2} - comparison={comparisonImpactEstimates?.totalCPU.annualizedCo2} - formatValue={asWeight} + value={ + shouldUseLegacyCo2Calculation + ? impactEstimates.totalCPU.annualizedCo2 + : annualCO2KgsInclusive + } + comparison={ + shouldUseLegacyCo2Calculation + ? comparisonImpactEstimates?.totalCPU.annualizedCo2 + : comparisonAnnualCO2KgsInclusive + } + formatValue={(value) => asWeight(value, 'kgs')} showDifference formatDifferenceAsPercentage={false} /> @@ -180,8 +205,16 @@ export function FlameGraphTooltip({ label={i18n.translate('xpack.profiling.flameGraphTooltip.annualizedDollarCost', { defaultMessage: `Annualized dollar cost`, })} - value={impactEstimates.totalCPU.annualizedDollarCost} - comparison={comparisonImpactEstimates?.totalCPU.annualizedDollarCost} + value={ + shouldUseLegacyCo2Calculation + ? impactEstimates.totalCPU.annualizedDollarCost + : annualCostsUSDInclusive + } + comparison={ + shouldUseLegacyCo2Calculation + ? comparisonImpactEstimates?.totalCPU.annualizedDollarCost + : comparisonAnnualCostsUSDInclusive + } formatValue={asCost} showDifference formatDifferenceAsPercentage={false} diff --git a/x-pack/plugins/profiling/public/components/flamegraph/index.tsx b/x-pack/plugins/profiling/public/components/flamegraph/index.tsx index 56b0dcf62412..33879e1fa55d 100644 --- a/x-pack/plugins/profiling/public/components/flamegraph/index.tsx +++ b/x-pack/plugins/profiling/public/components/flamegraph/index.tsx @@ -10,23 +10,23 @@ import { Datum, Flame, FlameLayerValue, + FlameSpec, PartialTheme, Settings, Tooltip, - FlameSpec, } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { Maybe } from '@kbn/observability-plugin/common/typings'; -import React, { useEffect, useMemo, useState } from 'react'; import { useUiTracker } from '@kbn/observability-shared-plugin/public'; import type { ElasticFlameGraph } from '@kbn/profiling-utils'; -import { i18n } from '@kbn/i18n'; +import React, { useEffect, useMemo, useState } from 'react'; import { getFlamegraphModel } from '../../utils/get_flamegraph_model'; -import { FlameGraphLegend } from './flame_graph_legend'; -import { FrameInformationWindow } from '../frame_information_window'; +import { Frame } from '../frame_information_window'; import { FrameInformationTooltip } from '../frame_information_window/frame_information_tooltip'; -import { FlameGraphTooltip } from './flamegraph_tooltip'; import { ComparisonMode } from '../normalization_menu'; +import { FlameGraphTooltip } from './flamegraph_tooltip'; +import { FlameGraphLegend } from './flame_graph_legend'; interface Props { id: string; @@ -90,7 +90,7 @@ export function FlameGraph({ const [highlightedVmIndex, setHighlightedVmIndex] = useState(undefined); - const selected: undefined | React.ComponentProps['frame'] = + const selected: Frame | undefined = primaryFlamegraph && highlightedVmIndex !== undefined ? { fileID: primaryFlamegraph.FileID[highlightedVmIndex], @@ -102,6 +102,10 @@ export function FlameGraph({ sourceLine: primaryFlamegraph.SourceLine[highlightedVmIndex], countInclusive: primaryFlamegraph.CountInclusive[highlightedVmIndex], countExclusive: primaryFlamegraph.CountExclusive[highlightedVmIndex], + selfAnnualCO2Kgs: primaryFlamegraph.SelfAnnualCO2KgsItems[highlightedVmIndex], + totalAnnualCO2Kgs: primaryFlamegraph.TotalAnnualCO2KgsItems[highlightedVmIndex], + selfAnnualCostUSD: primaryFlamegraph.SelfAnnualCostsUSDItems[highlightedVmIndex], + totalAnnualCostUSD: primaryFlamegraph.TotalAnnualCostsUSDItems[highlightedVmIndex], } : undefined; @@ -154,23 +158,35 @@ export function FlameGraph({ return ( { trackProfilingEvent({ metric: 'flamegraph_node_details_click' }); toggleShowInformationWindow(); setHighlightedVmIndex(valueIndex); }} + totalSamples={totalSamples} + totalSeconds={totalSeconds} inline={inline} parentLabel={parentLabel} /> diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/get_impact_rows.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/get_impact_rows.tsx index f0510b2d07b4..29289faca843 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/get_impact_rows.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/get_impact_rows.tsx @@ -13,7 +13,23 @@ import { asNumber } from '../../utils/formatters/as_number'; import { asPercentage } from '../../utils/formatters/as_percentage'; import { asWeight } from '../../utils/formatters/as_weight'; import { CPULabelWithHint } from '../cpu_label_with_hint'; -import { CalculateImpactEstimates } from '../../hooks/use_calculate_impact_estimates'; +import { + ANNUAL_SECONDS, + CalculateImpactEstimates, +} from '../../hooks/use_calculate_impact_estimates'; + +interface Params { + countInclusive: number; + countExclusive: number; + totalSamples: number; + totalSeconds: number; + calculateImpactEstimates: CalculateImpactEstimates; + shouldUseLegacyCo2Calculation: boolean; + selfAnnualCO2Kgs: number; + totalAnnualCO2Kgs: number; + selfAnnualCostUSD: number; + totalAnnualCostUSD: number; +} export function getImpactRows({ countInclusive, @@ -21,13 +37,12 @@ export function getImpactRows({ totalSamples, totalSeconds, calculateImpactEstimates, -}: { - countInclusive: number; - countExclusive: number; - totalSamples: number; - totalSeconds: number; - calculateImpactEstimates: CalculateImpactEstimates; -}) { + shouldUseLegacyCo2Calculation, + selfAnnualCO2Kgs, + totalAnnualCO2Kgs, + selfAnnualCostUSD, + totalAnnualCostUSD, +}: Params) { const { selfCPU, totalCPU } = calculateImpactEstimates({ countInclusive, countExclusive, @@ -35,6 +50,8 @@ export function getImpactRows({ totalSeconds, }); + const annualSecondsRatio = ANNUAL_SECONDS / totalSeconds; + return [ { 'data-test-subj': 'totalCPU', @@ -100,7 +117,10 @@ export function getImpactRows({ defaultMessage: 'CO2 emission', } ), - value: asWeight(totalCPU.co2), + value: asWeight( + shouldUseLegacyCo2Calculation ? totalCPU.co2 : totalAnnualCO2Kgs / annualSecondsRatio, + 'kgs' + ), }, { 'data-test-subj': 'selfCo2Emission', @@ -108,7 +128,10 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.co2EmissionExclusiveLabel', { defaultMessage: 'CO2 emission (excl. children)' } ), - value: asWeight(selfCPU.co2), + value: asWeight( + shouldUseLegacyCo2Calculation ? selfCPU.co2 : selfAnnualCO2Kgs / annualSecondsRatio, + 'kgs' + ), }, { 'data-test-subj': 'annualizedCo2Emission', @@ -116,7 +139,10 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.annualizedCo2InclusiveLabel', { defaultMessage: 'Annualized CO2' } ), - value: asWeight(totalCPU.annualizedCo2), + value: asWeight( + shouldUseLegacyCo2Calculation ? totalCPU.annualizedCo2 : totalAnnualCO2Kgs, + 'kgs' + ), }, { 'data-test-subj': 'annualizedSelfCo2Emission', @@ -124,7 +150,10 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.annualizedCo2ExclusiveLabel', { defaultMessage: 'Annualized CO2 (excl. children)' } ), - value: asWeight(selfCPU.annualizedCo2), + value: asWeight( + shouldUseLegacyCo2Calculation ? selfCPU.annualizedCo2 : selfAnnualCO2Kgs, + 'kgs' + ), }, { 'data-test-subj': 'dollarCost', @@ -132,7 +161,11 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.dollarCostInclusiveLabel', { defaultMessage: 'Dollar cost' } ), - value: asCost(totalCPU.dollarCost), + value: asCost( + shouldUseLegacyCo2Calculation + ? totalCPU.dollarCost + : totalAnnualCostUSD / annualSecondsRatio + ), }, { 'data-test-subj': 'selfDollarCost', @@ -140,7 +173,9 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.dollarCostExclusiveLabel', { defaultMessage: 'Dollar cost (excl. children)' } ), - value: asCost(selfCPU.dollarCost), + value: asCost( + shouldUseLegacyCo2Calculation ? selfCPU.dollarCost : selfAnnualCostUSD / annualSecondsRatio + ), }, { 'data-test-subj': 'annualizedDollarCost', @@ -148,7 +183,9 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.annualizedDollarCostInclusiveLabel', { defaultMessage: 'Annualized dollar cost' } ), - value: asCost(totalCPU.annualizedDollarCost), + value: asCost( + shouldUseLegacyCo2Calculation ? totalCPU.annualizedDollarCost : totalAnnualCostUSD + ), }, { 'data-test-subj': 'annualizedSelfDollarCost', @@ -156,7 +193,9 @@ export function getImpactRows({ 'xpack.profiling.flameGraphInformationWindow.annualizedDollarCostExclusiveLabel', { defaultMessage: 'Annualized dollar cost (excl. children)' } ), - value: asCost(selfCPU.annualizedDollarCost), + value: asCost( + shouldUseLegacyCo2Calculation ? selfCPU.annualizedDollarCost : selfAnnualCostUSD + ), }, ]; } diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx index c5333d147787..a81eadd21520 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx @@ -8,6 +8,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FrameSymbolStatus, getFrameSymbolStatus } from '@kbn/profiling-utils'; import React from 'react'; +import { profilingUseLegacyCo2Calculation } from '@kbn/observability-plugin/common'; import { FrameInformationAIAssistant } from './frame_information_ai_assistant'; import { FrameInformationPanel } from './frame_information_panel'; import { getImpactRows } from './get_impact_rows'; @@ -15,6 +16,7 @@ import { getInformationRows } from './get_information_rows'; import { KeyValueList } from './key_value_list'; import { MissingSymbolsCallout } from './missing_symbols_callout'; import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; export interface Frame { fileID: string; @@ -26,6 +28,10 @@ export interface Frame { sourceLine: number; countInclusive: number; countExclusive: number; + selfAnnualCO2Kgs: number; + totalAnnualCO2Kgs: number; + selfAnnualCostUSD: number; + totalAnnualCostUSD: number; } export interface Props { @@ -43,6 +49,12 @@ export function FrameInformationWindow({ showSymbolsStatus = true, }: Props) { const calculateImpactEstimates = useCalculateImpactEstimate(); + const { + start: { core }, + } = useProfilingDependencies(); + const shouldUseLegacyCo2Calculation = core.uiSettings.get( + profilingUseLegacyCo2Calculation + ); if (!frame) { return ( @@ -72,6 +84,10 @@ export function FrameInformationWindow({ sourceLine, countInclusive, countExclusive, + selfAnnualCO2Kgs, + totalAnnualCO2Kgs, + selfAnnualCostUSD, + totalAnnualCostUSD, } = frame; const informationRows = getInformationRows({ @@ -90,6 +106,11 @@ export function FrameInformationWindow({ totalSamples, totalSeconds, calculateImpactEstimates, + shouldUseLegacyCo2Calculation, + selfAnnualCO2Kgs, + totalAnnualCO2Kgs, + selfAnnualCostUSD, + totalAnnualCostUSD, }); return ( diff --git a/x-pack/plugins/profiling/public/components/frames_summary/index.tsx b/x-pack/plugins/profiling/public/components/frames_summary/index.tsx index e90527ffefe1..e55f19d135f9 100644 --- a/x-pack/plugins/profiling/public/components/frames_summary/index.tsx +++ b/x-pack/plugins/profiling/public/components/frames_summary/index.tsx @@ -16,11 +16,13 @@ import { } from '@elastic/eui'; import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { profilingUseLegacyCo2Calculation } from '@kbn/observability-plugin/common'; import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; import { asCost } from '../../utils/formatters/as_cost'; import { asWeight } from '../../utils/formatters/as_weight'; import { calculateBaseComparisonDiff } from '../topn_functions/utils'; import { SummaryItem } from './summary_item'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; interface FrameValue { selfCPU: number; @@ -28,6 +30,8 @@ interface FrameValue { totalCount: number; duration: number; scaleFactor?: number; + totalAnnualCO2Kgs: number; + totalAnnualCostUSD: number; } interface Props { @@ -45,6 +49,12 @@ function getScaleFactor(scaleFactor: number = 1) { } export function FramesSummary({ baseValue, comparisonValue, isLoading }: Props) { + const { + start: { core }, + } = useProfilingDependencies(); + const shouldUseLegacyCo2Calculation = core.uiSettings.get( + profilingUseLegacyCo2Calculation + ); const calculateImpactEstimates = useCalculateImpactEstimate(); const baselineScaledTotalSamples = baseValue @@ -82,13 +92,25 @@ export function FramesSummary({ baseValue, comparisonValue, isLoading }: Props) comparisonValue: comparisonScaledTotalSamples || 0, }), co2EmissionDiff: calculateBaseComparisonDiff({ - baselineValue: baseImpactEstimates?.totalSamples?.annualizedCo2 || 0, - comparisonValue: comparisonImpactEstimates?.totalSamples.annualizedCo2 || 0, - formatValue: asWeight, + baselineValue: + (shouldUseLegacyCo2Calculation + ? baseImpactEstimates?.totalSamples?.annualizedCo2 + : baseValue?.totalAnnualCO2Kgs) || 0, + comparisonValue: + (shouldUseLegacyCo2Calculation + ? comparisonImpactEstimates?.totalSamples.annualizedCo2 + : comparisonValue?.totalAnnualCO2Kgs) || 0, + formatValue: (value) => asWeight(value, 'kgs'), }), costImpactDiff: calculateBaseComparisonDiff({ - baselineValue: baseImpactEstimates?.totalSamples.annualizedDollarCost || 0, - comparisonValue: comparisonImpactEstimates?.totalSamples.annualizedDollarCost || 0, + baselineValue: + (shouldUseLegacyCo2Calculation + ? baseImpactEstimates?.totalSamples.annualizedDollarCost + : baseValue?.totalAnnualCostUSD) || 0, + comparisonValue: + (shouldUseLegacyCo2Calculation + ? comparisonImpactEstimates?.totalSamples.annualizedDollarCost + : comparisonValue?.totalAnnualCostUSD) || 0, formatValue: asCost, }), }; @@ -98,6 +120,7 @@ export function FramesSummary({ baseValue, comparisonValue, isLoading }: Props) calculateImpactEstimates, comparisonScaledTotalSamples, comparisonValue, + shouldUseLegacyCo2Calculation, ]); const data = [ diff --git a/x-pack/plugins/profiling/public/components/profiling_app_page_template/profiling_search_bar.tsx b/x-pack/plugins/profiling/public/components/profiling_app_page_template/profiling_search_bar.tsx index f1c52e6db5d0..c41468f5dbff 100644 --- a/x-pack/plugins/profiling/public/components/profiling_app_page_template/profiling_search_bar.tsx +++ b/x-pack/plugins/profiling/public/components/profiling_app_page_template/profiling_search_bar.tsx @@ -12,19 +12,10 @@ import React, { useEffect, useState } from 'react'; import { INDEX_EVENTS } from '../../../common'; import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; -export function ProfilingSearchBar({ - kuery, - rangeFrom, - rangeTo, - onQuerySubmit, - onRefresh, - onRefreshClick, - showSubmitButton = true, - dataTestSubj = 'profilingUnifiedSearchBar', -}: { +interface Props { kuery: string; - rangeFrom: string; - rangeTo: string; + rangeFrom?: string; + rangeTo?: string; onQuerySubmit: ( payload: { dateRange: TimeRange; @@ -32,11 +23,26 @@ export function ProfilingSearchBar({ }, isUpdate?: boolean ) => void; - onRefresh: Required>['onRefresh']; + onRefresh?: Required>['onRefresh']; onRefreshClick: () => void; showSubmitButton?: boolean; dataTestSubj?: string; -}) { + showDatePicker?: boolean; + showQueryMenu?: boolean; +} + +export function ProfilingSearchBar({ + kuery, + rangeFrom, + rangeTo, + onQuerySubmit, + onRefresh, + onRefreshClick, + showSubmitButton = true, + dataTestSubj = 'profilingUnifiedSearchBar', + showDatePicker = true, + showQueryMenu = true, +}: Props) { const { start: { dataViews }, } = useProfilingDependencies(); @@ -67,7 +73,7 @@ export function ProfilingSearchBar({ onQuerySubmit({ dateRange, query }); }} showQueryInput - showDatePicker + showDatePicker={showDatePicker} showFilterBar={false} showSaveQuery={false} submitButtonStyle={!showSubmitButton ? 'iconOnly' : 'auto'} @@ -78,6 +84,7 @@ export function ProfilingSearchBar({ onRefresh={onRefresh} displayStyle="inPage" dataTestSubj={dataTestSubj} + showQueryMenu={showQueryMenu} /> ); } diff --git a/x-pack/plugins/profiling/public/components/topn_functions/function_row.tsx b/x-pack/plugins/profiling/public/components/topn_functions/function_row.tsx index 6cf0159dcdc0..1affab1df5f0 100644 --- a/x-pack/plugins/profiling/public/components/topn_functions/function_row.tsx +++ b/x-pack/plugins/profiling/public/components/topn_functions/function_row.tsx @@ -17,8 +17,10 @@ import { import { i18n } from '@kbn/i18n'; import { TopNFunctionSortField } from '@kbn/profiling-utils'; import React, { useEffect } from 'react'; +import { profilingUseLegacyCo2Calculation } from '@kbn/observability-plugin/common'; import { asCost } from '../../utils/formatters/as_cost'; import { asWeight } from '../../utils/formatters/as_weight'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; import { StackFrameSummary } from '../stack_frame_summary'; import { CPUStat } from './cpu_stat'; import { SampleStat } from './sample_stat'; @@ -39,6 +41,14 @@ export function FunctionRow({ onFrameClick, setCellProps, }: Props) { + const { + start: { core }, + } = useProfilingDependencies(); + + const shouldUseLegacyCo2Calculation = core.uiSettings.get( + profilingUseLegacyCo2Calculation + ); + if (columnId === TopNFunctionSortField.Diff) { return ; } @@ -72,16 +82,33 @@ export function FunctionRow({ if ( columnId === TopNFunctionSortField.AnnualizedCo2 && - functionRow.impactEstimates?.selfCPU?.annualizedCo2 + functionRow.impactEstimates?.totalCPU?.annualizedCo2 ) { - return
    {asWeight(functionRow.impactEstimates.selfCPU.annualizedCo2)}
    ; + return ( +
    + {asWeight( + shouldUseLegacyCo2Calculation + ? functionRow.impactEstimates.totalCPU.annualizedCo2 + : functionRow.totalAnnualCO2kgs, + 'kgs' + )} +
    + ); } if ( columnId === TopNFunctionSortField.AnnualizedDollarCost && - functionRow.impactEstimates?.selfCPU?.annualizedDollarCost + functionRow.impactEstimates?.totalCPU?.annualizedDollarCost ) { - return
    {asCost(functionRow.impactEstimates.selfCPU.annualizedDollarCost)}
    ; + return ( +
    + {asCost( + shouldUseLegacyCo2Calculation + ? functionRow.impactEstimates.totalCPU.annualizedDollarCost + : functionRow.totalAnnualCostUSD + )} +
    + ); } return null; @@ -112,7 +139,7 @@ function DiffColumn({ diff, setCellProps }: DiffColumnProps) { const dangerColor = useEuiBackgroundColor('danger'); useEffect(() => { - if (diff && diff.rank > 0) { + if (diff && diff.rank !== 0) { const color = diff.rank > 0 ? 'success' : 'danger'; setCellProps({ style: { backgroundColor: color === 'success' ? successColor : dangerColor }, diff --git a/x-pack/plugins/profiling/public/components/topn_functions/index.tsx b/x-pack/plugins/profiling/public/components/topn_functions/index.tsx index 90fd422e8d46..9d3275e319cc 100644 --- a/x-pack/plugins/profiling/public/components/topn_functions/index.tsx +++ b/x-pack/plugins/profiling/public/components/topn_functions/index.tsx @@ -21,12 +21,14 @@ import { getCalleeFunction, TopNFunctions, TopNFunctionSortField } from '@kbn/pr import { last, orderBy } from 'lodash'; import React, { forwardRef, Ref, useMemo, useState } from 'react'; import { GridOnScrollProps } from 'react-window'; +import { profilingUseLegacyCo2Calculation } from '@kbn/observability-plugin/common'; +import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; import { CPULabelWithHint } from '../cpu_label_with_hint'; import { FrameInformationTooltip } from '../frame_information_window/frame_information_tooltip'; import { LabelWithHint } from '../label_with_hint'; import { FunctionRow } from './function_row'; import { getFunctionsRows, IFunctionRow } from './utils'; -import { useCalculateImpactEstimate } from '../../hooks/use_calculate_impact_estimates'; interface Props { topNFunctions?: TopNFunctions; @@ -69,6 +71,12 @@ export const TopNFunctionsGrid = forwardRef( }: Props, ref: Ref | undefined ) => { + const { + start: { core }, + } = useProfilingDependencies(); + const shouldUseLegacyCo2Calculation = core.uiSettings.get( + profilingUseLegacyCo2Calculation + ); const [selectedRow, setSelectedRow] = useState(); const trackProfilingEvent = useUiTracker({ app: 'profiling' }); const calculateImpactEstimates = useCalculateImpactEstimate(); @@ -115,17 +123,27 @@ export const TopNFunctionsGrid = forwardRef( case TopNFunctionSortField.TotalCPU: return orderBy(rows, (row) => row.totalCPUPerc, sortDirection); case TopNFunctionSortField.AnnualizedCo2: - return orderBy(rows, (row) => row.impactEstimates?.selfCPU.annualizedCo2, sortDirection); + return orderBy( + rows, + (row) => + shouldUseLegacyCo2Calculation + ? row.impactEstimates?.totalCPU.annualizedCo2 + : row.totalAnnualCO2kgs, + sortDirection + ); case TopNFunctionSortField.AnnualizedDollarCost: return orderBy( rows, - (row) => row.impactEstimates?.selfCPU.annualizedDollarCost, + (row) => + shouldUseLegacyCo2Calculation + ? row.impactEstimates?.totalCPU.annualizedDollarCost + : row.totalAnnualCostUSD, sortDirection ); default: return orderBy(rows, sortField, sortDirection); } - }, [rows, sortDirection, sortField]); + }, [rows, shouldUseLegacyCo2Calculation, sortDirection, sortField]); const { columns, leadingControlColumns } = useMemo(() => { const gridColumns: EuiDataGridColumn[] = [ @@ -255,7 +273,11 @@ export const TopNFunctionsGrid = forwardRef( headerCellRender() { return ( - Controls + + {i18n.translate('xpack.profiling.topNFunctionsGrid.span.controlsLabel', { + defaultMessage: 'Controls', + })} + ); }, @@ -267,7 +289,10 @@ export const TopNFunctionsGrid = forwardRef( return ( 100 ? 100 : sortedRows.length} @@ -348,6 +376,10 @@ export const TopNFunctionsGrid = forwardRef( functionName: selectedRow.frame.FunctionName, sourceFileName: selectedRow.frame.SourceFilename, sourceLine: selectedRow.frame.SourceLine, + selfAnnualCO2Kgs: selectedRow.selfAnnualCO2kgs, + totalAnnualCO2Kgs: selectedRow.totalAnnualCO2kgs, + selfAnnualCostUSD: selectedRow.selfAnnualCostUSD, + totalAnnualCostUSD: selectedRow.totalAnnualCostUSD, }} totalSeconds={totalSeconds} totalSamples={totalCount} diff --git a/x-pack/plugins/profiling/public/components/topn_functions/utils.ts b/x-pack/plugins/profiling/public/components/topn_functions/utils.ts index 788c7397fa79..3e8389e4e1e9 100644 --- a/x-pack/plugins/profiling/public/components/topn_functions/utils.ts +++ b/x-pack/plugins/profiling/public/components/topn_functions/utils.ts @@ -33,6 +33,7 @@ export function scaleValue({ value, scaleFactor = 1 }: { value: number; scaleFac } export interface IFunctionRow { + id: string; rank: number; frame: StackFrameMetadata; samples: number; @@ -41,6 +42,10 @@ export interface IFunctionRow { selfCPUPerc: number; totalCPUPerc: number; impactEstimates?: ImpactEstimates; + selfAnnualCO2kgs: number; + selfAnnualCostUSD: number; + totalAnnualCO2kgs: number; + totalAnnualCostUSD: number; diff?: { rank: number; samples: number; @@ -49,6 +54,10 @@ export interface IFunctionRow { selfCPUPerc: number; totalCPUPerc: number; impactEstimates?: ImpactEstimates; + selfAnnualCO2kgs: number; + selfAnnualCostUSD: number; + totalAnnualCO2kgs: number; + totalAnnualCostUSD: number; }; } @@ -106,6 +115,7 @@ export function getFunctionsRows({ const scaledDiffSamples = scaledSelfCPU - comparisonScaledSelfCPU; return { + id: comparisonRow.Id, rank: topN.Rank - comparisonRow.Rank, samples: scaledDiffSamples, selfCPU: comparisonRow.CountExclusive, @@ -115,11 +125,16 @@ export function getFunctionsRows({ totalCPUPerc: totalCPUPerc - (comparisonRow.CountInclusive / comparisonTopNFunctions.TotalCount) * 100, + selfAnnualCO2kgs: comparisonRow.selfAnnualCO2kgs, + selfAnnualCostUSD: comparisonRow.selfAnnualCostUSD, + totalAnnualCO2kgs: comparisonRow.totalAnnualCO2kgs, + totalAnnualCostUSD: comparisonRow.totalAnnualCostUSD, }; } } return { + id: topN.Id, rank: topN.Rank, frame: topN.Frame, samples: scaledSelfCPU, @@ -128,6 +143,10 @@ export function getFunctionsRows({ selfCPU: topN.CountExclusive, totalCPU: topN.CountInclusive, impactEstimates, + selfAnnualCO2kgs: topN.selfAnnualCO2kgs, + selfAnnualCostUSD: topN.selfAnnualCostUSD, + totalAnnualCO2kgs: topN.totalAnnualCO2kgs, + totalAnnualCostUSD: topN.totalAnnualCostUSD, diff: calculateDiff(), }; }); diff --git a/x-pack/plugins/profiling/public/embeddables/functions/embeddable_functions.tsx b/x-pack/plugins/profiling/public/embeddables/functions/embeddable_functions.tsx index 4cfbe7ceddbb..9a198ae66e26 100644 --- a/x-pack/plugins/profiling/public/embeddables/functions/embeddable_functions.tsx +++ b/x-pack/plugins/profiling/public/embeddables/functions/embeddable_functions.tsx @@ -9,12 +9,12 @@ import { EMBEDDABLE_FUNCTIONS } from '@kbn/observability-shared-plugin/public'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { AsyncEmbeddableComponent } from '../async_embeddable_component'; -import { EmbeddableFunctionsEmbeddableInput } from './embeddable_functions_factory'; -import { EmbeddableFunctionsGrid } from './embeddable_functions_grid'; import { ProfilingEmbeddableProvider, ProfilingEmbeddablesDependencies, } from '../profiling_embeddable_provider'; +import { EmbeddableFunctionsEmbeddableInput } from './embeddable_functions_factory'; +import { EmbeddableFunctionsGrid } from './embeddable_functions_grid'; export class EmbeddableFunctions extends Embeddable< EmbeddableFunctionsEmbeddableInput, diff --git a/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx b/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx index d4db1e2d9fb7..b8defbdfa4ac 100644 --- a/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx +++ b/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx @@ -9,6 +9,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import React, { ReactChild, useMemo } from 'react'; import { CoreSetup, CoreStart } from '@kbn/core/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import { ProfilingDependenciesContextProvider } from '../components/contexts/profiling_dependencies/profiling_dependencies_context'; import { ProfilingPluginPublicSetupDeps, ProfilingPluginPublicStartDeps } from '../types'; import { Services } from '../services'; @@ -21,6 +22,8 @@ export interface ProfilingEmbeddablesDependencies { profilingFetchServices: Services; } +const storage = new Storage(localStorage); + export type GetProfilingEmbeddableDependencies = () => Promise; interface Props { @@ -44,13 +47,17 @@ export function ProfilingEmbeddableProvider({ deps, children }: Props) { [deps] ); + const i18nCore = deps.coreStart.i18n; + return ( - - - - {children} - - - + + + + + {children} + + + + ); } diff --git a/x-pack/plugins/profiling/public/embeddables/register_embeddables.ts b/x-pack/plugins/profiling/public/embeddables/register_embeddables.ts index d7b2e947144b..2c229414960a 100644 --- a/x-pack/plugins/profiling/public/embeddables/register_embeddables.ts +++ b/x-pack/plugins/profiling/public/embeddables/register_embeddables.ts @@ -9,10 +9,12 @@ import { EmbeddableSetup } from '@kbn/embeddable-plugin/public'; import { EMBEDDABLE_FLAMEGRAPH, EMBEDDABLE_FUNCTIONS, + EMBEDDABLE_PROFILING_SEARCH_BAR, } from '@kbn/observability-shared-plugin/public'; import { EmbeddableFlamegraphFactory } from './flamegraph/embeddable_flamegraph_factory'; import { EmbeddableFunctionsFactory } from './functions/embeddable_functions_factory'; import { GetProfilingEmbeddableDependencies } from './profiling_embeddable_provider'; +import { EmbeddableSearchBarFactory } from './search_bar/embeddable_search_bar_factory'; export function registerEmbeddables( embeddable: EmbeddableSetup, @@ -26,4 +28,8 @@ export function registerEmbeddables( EMBEDDABLE_FUNCTIONS, new EmbeddableFunctionsFactory(getProfilingEmbeddableDependencies) ); + embeddable.registerEmbeddableFactory( + EMBEDDABLE_PROFILING_SEARCH_BAR, + new EmbeddableSearchBarFactory(getProfilingEmbeddableDependencies) + ); } diff --git a/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar.tsx b/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar.tsx new file mode 100644 index 000000000000..cbc773abfc0f --- /dev/null +++ b/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { css } from '@emotion/react'; +import { Embeddable, EmbeddableOutput, IContainer } from '@kbn/embeddable-plugin/public'; +import { EMBEDDABLE_PROFILING_SEARCH_BAR } from '@kbn/observability-shared-plugin/public'; +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { ProfilingSearchBar } from '../../components/profiling_app_page_template/profiling_search_bar'; +import { + ProfilingEmbeddableProvider, + ProfilingEmbeddablesDependencies, +} from '../profiling_embeddable_provider'; +import { EmbeddableSearchBarEmbeddableInput } from './embeddable_search_bar_factory'; + +export class EmbeddableSearchBar extends Embeddable< + EmbeddableSearchBarEmbeddableInput, + EmbeddableOutput +> { + readonly type = EMBEDDABLE_PROFILING_SEARCH_BAR; + private _domNode?: HTMLElement; + + constructor( + private deps: ProfilingEmbeddablesDependencies, + initialInput: EmbeddableSearchBarEmbeddableInput, + parent?: IContainer + ) { + super(initialInput, {}, parent); + } + + render(domNode: HTMLElement) { + this._domNode = domNode; + const { showDatePicker, kuery, onQuerySubmit, onRefresh, rangeFrom, rangeTo } = this.input; + + render( + +
    + { + onQuerySubmit({ + dateRange, + query: typeof query?.query === 'string' ? query.query : '', + }); + }} + onRefresh={onRefresh} + onRefreshClick={onRefresh} + showQueryMenu={false} + rangeFrom={rangeFrom} + rangeTo={rangeTo} + /> +
    +
    , + domNode + ); + } + + public destroy() { + if (this._domNode) { + unmountComponentAtNode(this._domNode); + } + } + + reload() { + if (this._domNode) { + this.render(this._domNode); + } + } +} diff --git a/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar_factory.ts b/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar_factory.ts new file mode 100644 index 000000000000..cc7443976e1b --- /dev/null +++ b/x-pack/plugins/profiling/public/embeddables/search_bar/embeddable_search_bar_factory.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EmbeddableFactoryDefinition, + EmbeddableInput, + IContainer, +} from '@kbn/embeddable-plugin/public'; +import { + EmbeddableProfilingSearchBarProps, + EMBEDDABLE_PROFILING_SEARCH_BAR, +} from '@kbn/observability-shared-plugin/public'; +import type { GetProfilingEmbeddableDependencies } from '../profiling_embeddable_provider'; + +export type EmbeddableSearchBarEmbeddableInput = EmbeddableProfilingSearchBarProps & + EmbeddableInput; + +export class EmbeddableSearchBarFactory + implements EmbeddableFactoryDefinition +{ + readonly type = EMBEDDABLE_PROFILING_SEARCH_BAR; + + constructor(private getProfilingEmbeddableDependencies: GetProfilingEmbeddableDependencies) {} + + async isEditable() { + return false; + } + + async create(input: EmbeddableSearchBarEmbeddableInput, parent?: IContainer) { + const { EmbeddableSearchBar } = await import('./embeddable_search_bar'); + const deps = await this.getProfilingEmbeddableDependencies(); + return new EmbeddableSearchBar(deps, input, parent); + } + + getDisplayName() { + return 'Universal Profiling Search bar'; + } +} diff --git a/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.test.ts b/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.test.ts index 65666b95b7ab..f0e6d2cda5c3 100644 --- a/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.test.ts +++ b/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.test.ts @@ -9,7 +9,7 @@ import { useProfilingDependencies } from '../components/contexts/profiling_depen import { profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, } from '@kbn/observability-plugin/common'; jest.mock('../components/contexts/profiling_dependencies/use_profiling_dependencies'); @@ -21,7 +21,7 @@ describe('useCalculateImpactEstimate', () => { core: { uiSettings: { get: (key: string) => { - if (key === profilingPerCoreWatt) { + if (key === profilingPervCPUWattX86) { return 7; } if (key === profilingCo2PerKWH) { diff --git a/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.ts b/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.ts index 1a32cf541f54..69820a5090a8 100644 --- a/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.ts +++ b/x-pack/plugins/profiling/public/hooks/use_calculate_impact_estimates.ts @@ -8,7 +8,7 @@ import { profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, } from '@kbn/observability-plugin/common'; import { useProfilingDependencies } from '../components/contexts/profiling_dependencies/use_profiling_dependencies'; @@ -22,7 +22,7 @@ interface Params { export type CalculateImpactEstimates = ReturnType; export type ImpactEstimates = ReturnType; -const ANNUAL_SECONDS = 60 * 60 * 24 * 365; +export const ANNUAL_SECONDS = 60 * 60 * 24 * 365; // The cost of an x86 CPU core per hour, in US$. // (ARM is 60% less based graviton 3 data, see https://aws.amazon.com/ec2/graviton/) @@ -33,7 +33,7 @@ export function useCalculateImpactEstimate() { start: { core }, } = useProfilingDependencies(); - const perCoreWatts = core.uiSettings.get(profilingPerCoreWatt); + const perCoreWatts = core.uiSettings.get(profilingPervCPUWattX86); const co2PerTonKWH = core.uiSettings.get(profilingCo2PerKWH); const datacenterPUE = core.uiSettings.get(profilingDatacenterPUE); diff --git a/x-pack/plugins/profiling/public/routing/index.tsx b/x-pack/plugins/profiling/public/routing/index.tsx index cb92422a9407..9df36e393c38 100644 --- a/x-pack/plugins/profiling/public/routing/index.tsx +++ b/x-pack/plugins/profiling/public/routing/index.tsx @@ -6,33 +6,35 @@ */ import { i18n } from '@kbn/i18n'; import { toNumberRt } from '@kbn/io-ts-utils'; -import { createRouter, Outlet } from '@kbn/typed-react-router-config'; -import * as t from 'io-ts'; -import React from 'react'; import { StackTracesDisplayOption, - TopNType, + TopNComparisonFunctionSortField, + topNComparisonFunctionSortFieldRt, TopNFunctionSortField, topNFunctionSortFieldRt, + TopNType, } from '@kbn/profiling-utils'; +import { createRouter, Outlet } from '@kbn/typed-react-router-config'; +import * as t from 'io-ts'; +import React from 'react'; import { indexLifecyclePhaseRt, IndexLifecyclePhaseSelectOption, } from '../../common/storage_explorer'; import { ComparisonMode, NormalizationMode } from '../components/normalization_menu'; import { RedirectTo } from '../components/redirect_to'; +import { AddDataTabs, AddDataView } from '../views/add_data_view'; +import { DeleteDataView } from '../views/delete_data_view'; import { FlameGraphsView } from '../views/flamegraphs'; import { DifferentialFlameGraphsView } from '../views/flamegraphs/differential_flamegraphs'; import { FlameGraphView } from '../views/flamegraphs/flamegraph'; import { FunctionsView } from '../views/functions'; import { DifferentialTopNFunctionsView } from '../views/functions/differential_topn'; import { TopNFunctionsView } from '../views/functions/topn'; -import { AddDataTabs, AddDataView } from '../views/add_data_view'; +import { Settings } from '../views/settings'; import { StackTracesView } from '../views/stack_traces_view'; import { StorageExplorerView } from '../views/storage_explorer'; import { RouteBreadcrumb } from './route_breadcrumb'; -import { DeleteDataView } from '../views/delete_data_view'; -import { Settings } from '../views/settings'; const routes = { '/settings': { @@ -253,6 +255,8 @@ const routes = { t.literal(NormalizationMode.Scale), t.literal(NormalizationMode.Time), ]), + comparisonSortField: topNComparisonFunctionSortFieldRt, + comparisonSortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), t.partial({ baseline: toNumberRt, @@ -267,6 +271,8 @@ const routes = { comparisonRangeTo: 'now', comparisonKuery: '', normalizationMode: NormalizationMode.Time, + comparisonSortField: TopNComparisonFunctionSortField.ComparisonRank, + comparisonSortDirection: 'asc', }, }, }, diff --git a/x-pack/plugins/profiling/public/types.ts b/x-pack/plugins/profiling/public/types.ts index e583a4962dc6..cc949254e270 100644 --- a/x-pack/plugins/profiling/public/types.ts +++ b/x-pack/plugins/profiling/public/types.ts @@ -25,6 +25,10 @@ import { ObservabilityAIAssistantPluginStart, } from '@kbn/observability-ai-assistant-plugin/public'; import { EmbeddableSetup } from '@kbn/embeddable-plugin/public'; +import type { + UnifiedSearchPublicPluginStart, + UnifiedSearchPluginSetup, +} from '@kbn/unified-search-plugin/public'; export interface ProfilingPluginPublicSetupDeps { observability: ObservabilityPublicSetup; @@ -36,6 +40,7 @@ export interface ProfilingPluginPublicSetupDeps { licensing: LicensingPluginSetup; share: SharePluginSetup; embeddable: EmbeddableSetup; + unifiedSearch: UnifiedSearchPluginSetup; } export interface ProfilingPluginPublicStartDeps { @@ -46,4 +51,5 @@ export interface ProfilingPluginPublicStartDeps { data: DataPublicPluginStart; charts: ChartsPluginStart; share: SharePluginStart; + unifiedSearch: UnifiedSearchPublicPluginStart; } diff --git a/x-pack/plugins/profiling/public/utils/formatters/as_weight.test.ts b/x-pack/plugins/profiling/public/utils/formatters/as_weight.test.ts new file mode 100644 index 000000000000..5e6ca175d10c --- /dev/null +++ b/x-pack/plugins/profiling/public/utils/formatters/as_weight.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { asWeight } from './as_weight'; + +describe('asWeight', () => { + it('should correctly convert and format weight in pounds to kilograms', () => { + const valueInPounds = 150; + expect(asWeight(valueInPounds, 'lbs')).toBe('150 lbs / 68.04 kg'); + }); + + it('should correctly convert and format weight in kilograms to pounds', () => { + const valueInKilograms = 75; + expect(asWeight(valueInKilograms, 'kgs')).toBe('165.35 lbs / 75 kg'); + }); + + it('should handle NaN input', () => { + expect(asWeight(NaN, 'lbs')).toBe('N/A lbs / N/A kg'); + }); + + it('should handle zero input', () => { + expect(asWeight(0, 'kgs')).toBe('0 lbs / 0 kg'); + }); + + it('should format very small values in pounds as "~0.00"', () => { + expect(asWeight(0.0001, 'lbs')).toBe('~0.00 lbs / ~0.00 kg'); + }); +}); diff --git a/x-pack/plugins/profiling/public/utils/formatters/as_weight.ts b/x-pack/plugins/profiling/public/utils/formatters/as_weight.ts index 539e9669caff..8a8b1fe2be89 100644 --- a/x-pack/plugins/profiling/public/utils/formatters/as_weight.ts +++ b/x-pack/plugins/profiling/public/utils/formatters/as_weight.ts @@ -8,10 +8,16 @@ import { asNumber } from './as_number'; const ONE_POUND_TO_A_KILO = 0.45359237; +const ONE_KILO_TO_A_POUND = 2.20462; -export function asWeight(valueInPounds: number): string { - const lbs = asNumber(valueInPounds); - const kgs = asNumber(Number(valueInPounds * ONE_POUND_TO_A_KILO)); +export function asWeight(value: number, unit: 'kgs' | 'lbs'): string { + const formattedValue = asNumber(value); - return `${lbs} lbs / ${kgs} kg`; + if (unit === 'lbs') { + const kgs = asNumber(Number(value * ONE_POUND_TO_A_KILO)); + return `${formattedValue} lbs / ${kgs} kg`; + } + + const lbs = asNumber(Number(value * ONE_KILO_TO_A_POUND)); + return `${lbs} lbs / ${formattedValue} kg`; } diff --git a/x-pack/plugins/profiling/public/views/add_data_view/index.tsx b/x-pack/plugins/profiling/public/views/add_data_view/index.tsx index 556e29c1ba24..27e3ac639757 100644 --- a/x-pack/plugins/profiling/public/views/add_data_view/index.tsx +++ b/x-pack/plugins/profiling/public/views/add_data_view/index.tsx @@ -541,7 +541,7 @@ docker.elastic.co/observability/profiling-agent:${stackVersion} /root/pf-host-ag title={ diff --git a/x-pack/plugins/profiling/public/views/flamegraphs/differential_flamegraphs/index.tsx b/x-pack/plugins/profiling/public/views/flamegraphs/differential_flamegraphs/index.tsx index a6f0a9bb4220..7581d9a41861 100644 --- a/x-pack/plugins/profiling/public/views/flamegraphs/differential_flamegraphs/index.tsx +++ b/x-pack/plugins/profiling/public/views/flamegraphs/differential_flamegraphs/index.tsx @@ -131,6 +131,8 @@ export function DifferentialFlameGraphsView() { totalCPU: state.data.primaryFlamegraph.TotalCPU, totalCount: state.data.primaryFlamegraph.TotalSamples, scaleFactor: isNormalizedByTime ? baselineTime : baseline, + totalAnnualCO2Kgs: state.data.primaryFlamegraph.TotalAnnualCO2Kgs, + totalAnnualCostUSD: state.data.primaryFlamegraph.TotalAnnualCostsUSD, } : undefined } @@ -142,6 +144,8 @@ export function DifferentialFlameGraphsView() { totalCPU: state.data.comparisonFlamegraph.TotalCPU, totalCount: state.data.comparisonFlamegraph.TotalSamples, scaleFactor: isNormalizedByTime ? comparisonTime : comparison, + totalAnnualCO2Kgs: state.data.comparisonFlamegraph.TotalAnnualCO2Kgs, + totalAnnualCostUSD: state.data.comparisonFlamegraph.TotalAnnualCostsUSD, } : undefined } diff --git a/x-pack/plugins/profiling/public/views/functions/differential_topn/index.tsx b/x-pack/plugins/profiling/public/views/functions/differential_topn/index.tsx index cf538642afce..9551645bb756 100644 --- a/x-pack/plugins/profiling/public/views/functions/differential_topn/index.tsx +++ b/x-pack/plugins/profiling/public/views/functions/differential_topn/index.tsx @@ -4,28 +4,21 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - EuiDataGridRefProps, - EuiDataGridSorting, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiPanel, - EuiSpacer, -} from '@elastic/eui'; -import { TopNFunctionSortField } from '@kbn/profiling-utils'; -import React, { useRef } from 'react'; -import { GridOnScrollProps } from 'react-window'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel, EuiSpacer } from '@elastic/eui'; +import React from 'react'; import { AsyncComponent } from '../../../components/async_component'; import { useProfilingDependencies } from '../../../components/contexts/profiling_dependencies/use_profiling_dependencies'; import { FramesSummary } from '../../../components/frames_summary'; +import { + DifferentialTopNFunctionsGrid, + OnChangeSortParams, +} from '../../../components/differential_topn_functions_grid'; import { NormalizationMenu, NormalizationMode, NormalizationOptions, } from '../../../components/normalization_menu'; import { PrimaryAndComparisonSearchBar } from '../../../components/primary_and_comparison_search_bar'; -import { TopNFunctionsGrid } from '../../../components/topn_functions'; import { AsyncStatus } from '../../../hooks/use_async'; import { useProfilingParams } from '../../../hooks/use_profiling_params'; import { useProfilingRouter } from '../../../hooks/use_profiling_router'; @@ -34,8 +27,6 @@ import { useTimeRange } from '../../../hooks/use_time_range'; import { useTimeRangeAsync } from '../../../hooks/use_time_range_async'; export function DifferentialTopNFunctionsView() { - const baseGridRef = useRef(null); - const comparisonGridRef = useRef(null); const { query } = useProfilingParams('/functions/differential'); const { rangeFrom, @@ -50,6 +41,8 @@ export function DifferentialTopNFunctionsView() { baseline = 1, comparison = 1, pageIndex = 0, + comparisonSortDirection, + comparisonSortField, } = query; const timeRange = useTimeRange({ rangeFrom, rangeTo }); @@ -147,20 +140,6 @@ export function DifferentialTopNFunctionsView() { }); } - function handleBaseGridScroll(scroll: GridOnScrollProps) { - if (comparisonGridRef?.current?.scrollTo) { - comparisonGridRef.current.scrollTo({ - scrollTop: scroll.scrollTop, - }); - } - } - - function handleComparisonGridScroll(scroll: GridOnScrollProps) { - if (baseGridRef?.current?.scrollTo) { - baseGridRef.current.scrollTo({ scrollTop: scroll.scrollTop }); - } - } - function handlePageChange(nextPage: number) { profilingRouter.push('/functions/differential', { path: {}, @@ -168,14 +147,10 @@ export function DifferentialTopNFunctionsView() { }); } - function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { + function handleOnSort(sorting: OnChangeSortParams) { profilingRouter.push('/functions/differential', { path: {}, - query: { - ...query, - sortField: sorting.id as TopNFunctionSortField, - sortDirection: sorting.direction, - }, + query: { ...query, ...sorting }, }); } @@ -205,6 +180,8 @@ export function DifferentialTopNFunctionsView() { totalCount: state.data.TotalCount, totalCPU: state.data.totalCPU, scaleFactor: isNormalizedByTime ? baselineTime : baseline, + totalAnnualCO2Kgs: state.data.totalAnnualCO2Kgs, + totalAnnualCostUSD: state.data.totalAnnualCostUSD, } : undefined } @@ -216,6 +193,8 @@ export function DifferentialTopNFunctionsView() { totalCount: comparisonState.data.TotalCount, totalCPU: comparisonState.data.totalCPU, scaleFactor: isNormalizedByTime ? comparisonTime : comparison, + totalAnnualCO2Kgs: comparisonState.data.totalAnnualCO2Kgs, + totalAnnualCostUSD: comparisonState.data.totalAnnualCostUSD, } : undefined } @@ -223,50 +202,27 @@ export function DifferentialTopNFunctionsView() { - - - - - - - {comparisonTimeRange.inSeconds.start && comparisonTimeRange.inSeconds.end ? ( - - - - - - ) : null} - + + + diff --git a/x-pack/plugins/profiling/public/views/functions/index.tsx b/x-pack/plugins/profiling/public/views/functions/index.tsx index 1131056d9a9b..2e4ddb32bc03 100644 --- a/x-pack/plugins/profiling/public/views/functions/index.tsx +++ b/x-pack/plugins/profiling/public/views/functions/index.tsx @@ -8,6 +8,7 @@ import { EuiPageHeaderContentProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { TopNComparisonFunctionSortField } from '@kbn/profiling-utils'; import { NormalizationMode } from '../../components/normalization_menu'; import { ProfilingAppPageTemplate } from '../../components/profiling_app_page_template'; import { RedirectTo } from '../../components/redirect_to'; @@ -51,6 +52,12 @@ export function FunctionsView({ children }: { children: React.ReactElement }) { comparisonKuery: query.kuery, normalizationMode: 'normalizationMode' in query ? query.normalizationMode : NormalizationMode.Time, + comparisonSortField: + 'comparisonSortField' in query + ? query.comparisonSortField + : TopNComparisonFunctionSortField.ComparisonRank, + comparisonSortDirection: + 'comparisonSortDirection' in query ? query.comparisonSortDirection : 'asc', }, }), }, diff --git a/x-pack/plugins/profiling/public/views/settings/index.tsx b/x-pack/plugins/profiling/public/views/settings/index.tsx index afc32d42e6f3..d4ac35ff6357 100644 --- a/x-pack/plugins/profiling/public/views/settings/index.tsx +++ b/x-pack/plugins/profiling/public/views/settings/index.tsx @@ -5,13 +5,26 @@ * 2.0. */ -import { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiPanel, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; import { LazyField } from '@kbn/advanced-settings-plugin/public'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { profilingCo2PerKWH, profilingDatacenterPUE, - profilingPerCoreWatt, + profilingPervCPUWattX86, + profilingPervCPUWattArm64, + profilingAWSCostDiscountRate, + profilingCostPervCPUPerHour, } from '@kbn/observability-plugin/common'; import { useEditableSettings, useUiTracker } from '@kbn/observability-shared-plugin/public'; import { isEmpty } from 'lodash'; @@ -20,7 +33,13 @@ import { useProfilingDependencies } from '../../components/contexts/profiling_de import { ProfilingAppPageTemplate } from '../../components/profiling_app_page_template'; import { BottomBarActions } from './bottom_bar_actions'; -const settingKeys = [profilingCo2PerKWH, profilingDatacenterPUE, profilingPerCoreWatt]; +const co2Settings = [ + profilingCo2PerKWH, + profilingDatacenterPUE, + profilingPervCPUWattX86, + profilingPervCPUWattArm64, +]; +const costSettings = [profilingAWSCostDiscountRate, profilingCostPervCPUPerHour]; export function Settings() { const trackProfilingEvent = useUiTracker({ app: 'profiling' }); @@ -37,7 +56,7 @@ export function Settings() { saveAll, isSaving, cleanUnsavedChanges, - } = useEditableSettings('profiling', settingKeys); + } = useEditableSettings('profiling', [...co2Settings, ...costSettings]); async function handleSave() { try { @@ -71,33 +90,136 @@ export function Settings() { - - - - - {i18n.translate('xpack.profiling.settings.co2Sections', { - defaultMessage: 'CO2', - })} - - - - - {settingKeys.map((settingKey) => { - const editableConfig = settingsEditableConfig[settingKey]; - return ( - + {i18n.translate('xpack.profiling.settings.co2.subtitle.link', { + defaultMessage: 'regional carbon intensity', + })} + + ), + pue: ( + + {i18n.translate('xpack.profiling.settings.co2.subtitle.pue', { + defaultMessage: 'PUE', + })} + + ), + }} /> - ); - })} - - + ), + text: i18n.translate('xpack.profiling.settings.co2.text', { + defaultMessage: + 'For all other configurations, Universal Profiling uses the following default configurations. You can update these configurations as needed.', + }), + }, + settings: co2Settings, + }, + { + label: i18n.translate('xpack.profiling.settings.costSection', { + defaultMessage: 'Custom cost settings', + }), + description: { + title: ( + + {i18n.translate('xpack.profiling.settings.cost.subtitle.link', { + defaultMessage: 'AWS price list', + })} + + ), + }} + /> + ), + }, + settings: costSettings, + }, + ].map((item) => ( + <> + + + + {item.label} + + + + {item.description ? ( + <> + + + + + + + {item.description.title && ( + + {item.description.title} + + )} + {item.description.subtitle && ( + + {item.description.subtitle} + + )} + {item.description.text && ( + + + {item.description.text} + + + )} + + + + + + ) : null} + {item.settings.map((settingKey) => { + const editableConfig = settingsEditableConfig[settingKey]; + return ( + + ); + })} + + + + + ))} + {!isEmpty(unsavedChanges) && ( { const { timeFrom, timeTo, kuery } = request.query; - const useLegacyFlamegraphAPI = await ( - await context.core - ).uiSettings.client.get(profilingUseLegacyFlamegraphAPI); + + const core = await context.core; try { const esClient = await getClient(context); const flamegraph = await profilingDataAccess.services.fetchFlamechartData({ + core, esClient, rangeFromMs: timeFrom, rangeToMs: timeTo, kuery, - useLegacyFlamegraphAPI, }); return response.ok({ body: flamegraph }); diff --git a/x-pack/plugins/profiling/server/routes/functions.ts b/x-pack/plugins/profiling/server/routes/functions.ts index ecd8b3ee2af0..3510de4ccf98 100644 --- a/x-pack/plugins/profiling/server/routes/functions.ts +++ b/x-pack/plugins/profiling/server/routes/functions.ts @@ -37,9 +37,12 @@ export function registerTopNFunctionsSearchRoute({ }, async (context, request, response) => { try { + const core = await context.core; + const { timeFrom, timeTo, startIndex, endIndex, kuery }: QuerySchemaType = request.query; const esClient = await getClient(context); const topNFunctions = await profilingDataAccess.services.fetchFunction({ + core, esClient, rangeFromMs: timeFrom, rangeToMs: timeTo, diff --git a/x-pack/plugins/profiling/server/routes/search_stacktraces.ts b/x-pack/plugins/profiling/server/routes/search_stacktraces.ts index 84e0da898534..e93f71e84da0 100644 --- a/x-pack/plugins/profiling/server/routes/search_stacktraces.ts +++ b/x-pack/plugins/profiling/server/routes/search_stacktraces.ts @@ -12,12 +12,18 @@ export async function searchStackTraces({ client, filter, sampleSize, + durationSeconds, }: { client: ProfilingESClient; filter: ProjectTimeQuery; sampleSize: number; + durationSeconds: number; }) { - const response = await client.profilingStacktraces({ query: filter, sampleSize }); + const response = await client.profilingStacktraces({ + query: filter, + sampleSize, + durationSeconds, + }); return decodeStackTraceResponse(response); } diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index 7790bad3b23d..ea38a10d4889 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -129,10 +129,13 @@ export async function topNElasticSearchQuery({ kuery: stackTraceKuery, }); + const totalSeconds = timeTo - timeFrom; + return searchStackTraces({ client, filter: stackTraceFilter, sampleSize: targetSampleSize, + durationSeconds: totalSeconds, }); } ); diff --git a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts index f085a89b2f3d..1a32b0c4a676 100644 --- a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts +++ b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts @@ -37,6 +37,7 @@ export interface ProfilingESClient { profilingStacktraces({}: { query: QueryDslQueryContainer; sampleSize: number; + durationSeconds: number; }): Promise; profilingStatus(params?: { waitForResourcesCreated?: boolean }): Promise; getEsClient(): ElasticsearchClient; @@ -75,7 +76,7 @@ export function createProfilingEsClient({ return unwrapEsResponse(promise); }, - profilingStacktraces({ query, sampleSize }) { + profilingStacktraces({ query, sampleSize, durationSeconds }) { const controller = new AbortController(); const promise = withProfilingSpan('_profiling/stacktraces', () => { @@ -87,6 +88,7 @@ export function createProfilingEsClient({ body: { query, sample_size: sampleSize, + requested_duration: durationSeconds, }, }, { diff --git a/x-pack/plugins/profiling_data_access/common/profiling_es_client.ts b/x-pack/plugins/profiling_data_access/common/profiling_es_client.ts index ae25dfe57b3c..39c95aa26d93 100644 --- a/x-pack/plugins/profiling_data_access/common/profiling_es_client.ts +++ b/x-pack/plugins/profiling_data_access/common/profiling_es_client.ts @@ -22,11 +22,25 @@ export interface ProfilingESClient { profilingStacktraces({}: { query: QueryDslQueryContainer; sampleSize: number; + durationSeconds: number; + co2PerKWH?: number; + datacenterPUE?: number; + pervCPUWattX86?: number; + pervCPUWattArm64?: number; + awsCostDiscountRate?: number; + costPervCPUPerHour?: number; }): Promise; profilingStatus(params?: { waitForResourcesCreated?: boolean }): Promise; getEsClient(): ElasticsearchClient; profilingFlamegraph({}: { query: QueryDslQueryContainer; sampleSize: number; + durationSeconds: number; + co2PerKWH?: number; + datacenterPUE?: number; + pervCPUWattX86?: number; + pervCPUWattArm64?: number; + awsCostDiscountRate?: number; + costPervCPUPerHour?: number; }): Promise; } diff --git a/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts b/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts index 7c49c9514fee..669b444e18c2 100644 --- a/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts @@ -5,62 +5,52 @@ * 2.0. */ -import { ElasticsearchClient } from '@kbn/core/server'; -import { createBaseFlameGraph, createCalleeTree } from '@kbn/profiling-utils'; +import { CoreRequestHandlerContext, ElasticsearchClient } from '@kbn/core/server'; +import { + profilingAWSCostDiscountRate, + profilingCo2PerKWH, + profilingCostPervCPUPerHour, + profilingDatacenterPUE, + profilingPervCPUWattArm64, + profilingPervCPUWattX86, +} from '@kbn/observability-plugin/common'; +import { percentToFactor } from '../../utils/percent_to_factor'; import { kqlQuery } from '../../utils/query'; -import { withProfilingSpan } from '../../utils/with_profiling_span'; import { RegisterServicesParams } from '../register_services'; -import { searchStackTraces } from '../search_stack_traces'; export interface FetchFlamechartParams { esClient: ElasticsearchClient; + core: CoreRequestHandlerContext; rangeFromMs: number; rangeToMs: number; kuery: string; - useLegacyFlamegraphAPI?: boolean; } const targetSampleSize = 20000; // minimum number of samples to get statistically sound results export function createFetchFlamechart({ createProfilingEsClient }: RegisterServicesParams) { - return async ({ - esClient, - rangeFromMs, - rangeToMs, - kuery, - useLegacyFlamegraphAPI = false, - }: FetchFlamechartParams) => { + return async ({ core, esClient, rangeFromMs, rangeToMs, kuery }: FetchFlamechartParams) => { const rangeFromSecs = rangeFromMs / 1000; const rangeToSecs = rangeToMs / 1000; - const profilingEsClient = createProfilingEsClient({ esClient }); + const [ + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate, + costPervCPUPerHour, + ] = await Promise.all([ + core.uiSettings.client.get(profilingCo2PerKWH), + core.uiSettings.client.get(profilingDatacenterPUE), + core.uiSettings.client.get(profilingPervCPUWattX86), + core.uiSettings.client.get(profilingPervCPUWattArm64), + core.uiSettings.client.get(profilingAWSCostDiscountRate), + core.uiSettings.client.get(profilingCostPervCPUPerHour), + ]); + const profilingEsClient = createProfilingEsClient({ esClient }); const totalSeconds = rangeToSecs - rangeFromSecs; - // Use legacy stack traces API to fetch the flamegraph - if (useLegacyFlamegraphAPI) { - const { events, stackTraces, executables, stackFrames, totalFrames, samplingRate } = - await searchStackTraces({ - client: profilingEsClient, - rangeFrom: rangeFromSecs, - rangeTo: rangeToSecs, - kuery, - sampleSize: targetSampleSize, - }); - - return await withProfilingSpan('create_flamegraph', async () => { - const tree = createCalleeTree( - events, - stackTraces, - stackFrames, - executables, - totalFrames, - samplingRate - ); - - return createBaseFlameGraph(tree, samplingRate, totalSeconds); - }); - } - const flamegraph = await profilingEsClient.profilingFlamegraph({ query: { bool: { @@ -79,6 +69,13 @@ export function createFetchFlamechart({ createProfilingEsClient }: RegisterServi }, }, sampleSize: targetSampleSize, + durationSeconds: totalSeconds, + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate: percentToFactor(awsCostDiscountRate), + costPervCPUPerHour, }); return { ...flamegraph, TotalSeconds: totalSeconds }; }; diff --git a/x-pack/plugins/profiling_data_access/server/services/functions/index.ts b/x-pack/plugins/profiling_data_access/server/services/functions/index.ts index ed50b368ee92..8492562d9c77 100644 --- a/x-pack/plugins/profiling_data_access/server/services/functions/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/functions/index.ts @@ -4,14 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { ElasticsearchClient } from '@kbn/core/server'; +import { + profilingAWSCostDiscountRate, + profilingCo2PerKWH, + profilingCostPervCPUPerHour, + profilingDatacenterPUE, + profilingPervCPUWattArm64, + profilingPervCPUWattX86, +} from '@kbn/observability-plugin/common'; +import { CoreRequestHandlerContext, ElasticsearchClient } from '@kbn/core/server'; import { createTopNFunctions } from '@kbn/profiling-utils'; +import { percentToFactor } from '../../utils/percent_to_factor'; import { withProfilingSpan } from '../../utils/with_profiling_span'; import { RegisterServicesParams } from '../register_services'; import { searchStackTraces } from '../search_stack_traces'; export interface FetchFunctionsParams { + core: CoreRequestHandlerContext; esClient: ElasticsearchClient; rangeFromMs: number; rangeToMs: number; @@ -24,6 +33,7 @@ const targetSampleSize = 20000; // minimum number of samples to get statisticall export function createFetchFunctions({ createProfilingEsClient }: RegisterServicesParams) { return async ({ + core, esClient, rangeFromMs, rangeToMs, @@ -33,6 +43,23 @@ export function createFetchFunctions({ createProfilingEsClient }: RegisterServic }: FetchFunctionsParams) => { const rangeFromSecs = rangeFromMs / 1000; const rangeToSecs = rangeToMs / 1000; + const totalSeconds = rangeToSecs - rangeFromSecs; + + const [ + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate, + costPervCPUPerHour, + ] = await Promise.all([ + core.uiSettings.client.get(profilingCo2PerKWH), + core.uiSettings.client.get(profilingDatacenterPUE), + core.uiSettings.client.get(profilingPervCPUWattX86), + core.uiSettings.client.get(profilingPervCPUWattArm64), + core.uiSettings.client.get(profilingAWSCostDiscountRate), + core.uiSettings.client.get(profilingCostPervCPUPerHour), + ]); const profilingEsClient = createProfilingEsClient({ esClient }); @@ -43,6 +70,13 @@ export function createFetchFunctions({ createProfilingEsClient }: RegisterServic rangeTo: rangeToSecs, kuery, sampleSize: targetSampleSize, + durationSeconds: totalSeconds, + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate: percentToFactor(awsCostDiscountRate), + costPervCPUPerHour, } ); diff --git a/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts b/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts index 33cb1c6c8dc2..6da9187d7a2e 100644 --- a/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts @@ -15,12 +15,26 @@ export async function searchStackTraces({ rangeFrom, rangeTo, kuery, + durationSeconds, + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate, + costPervCPUPerHour, }: { client: ProfilingESClient; sampleSize: number; rangeFrom: number; rangeTo: number; kuery: string; + durationSeconds: number; + co2PerKWH: number; + datacenterPUE: number; + pervCPUWattX86: number; + pervCPUWattArm64: number; + awsCostDiscountRate: number; + costPervCPUPerHour: number; }) { const response = await client.profilingStacktraces({ query: { @@ -41,6 +55,13 @@ export async function searchStackTraces({ }, }, sampleSize, + durationSeconds, + co2PerKWH, + datacenterPUE, + pervCPUWattX86, + pervCPUWattArm64, + awsCostDiscountRate, + costPervCPUPerHour, }); return decodeStackTraceResponse(response); diff --git a/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts index 617e27a458b7..4e293031aa32 100644 --- a/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts +++ b/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts @@ -39,7 +39,17 @@ export function createProfilingEsClient({ return unwrapEsResponse(promise); }, - profilingStacktraces({ query, sampleSize }) { + profilingStacktraces({ + query, + sampleSize, + durationSeconds, + co2PerKWH, + datacenterPUE, + awsCostDiscountRate, + costPervCPUPerHour, + pervCPUWattArm64, + pervCPUWattX86, + }) { const controller = new AbortController(); const promise = withProfilingSpan('_profiling/stacktraces', () => { return esClient.transport.request( @@ -49,6 +59,13 @@ export function createProfilingEsClient({ body: { query, sample_size: sampleSize, + requested_duration: durationSeconds, + co2_per_kwh: co2PerKWH, + per_core_watt_x86: pervCPUWattX86, + per_core_watt_arm64: pervCPUWattArm64, + datacenter_pue: datacenterPUE, + aws_cost_factor: awsCostDiscountRate, + cost_per_core_hour: costPervCPUPerHour, }, }, { @@ -83,7 +100,17 @@ export function createProfilingEsClient({ getEsClient() { return esClient; }, - profilingFlamegraph({ query, sampleSize }) { + profilingFlamegraph({ + query, + sampleSize, + durationSeconds, + co2PerKWH, + datacenterPUE, + awsCostDiscountRate, + costPervCPUPerHour, + pervCPUWattArm64, + pervCPUWattX86, + }) { const controller = new AbortController(); const promise = withProfilingSpan('_profiling/flamegraph', () => { @@ -94,6 +121,13 @@ export function createProfilingEsClient({ body: { query, sample_size: sampleSize, + requested_duration: durationSeconds, + co2_per_kwh: co2PerKWH, + per_core_watt_x86: pervCPUWattX86, + per_core_watt_arm64: pervCPUWattArm64, + datacenter_pue: datacenterPUE, + aws_cost_factor: awsCostDiscountRate, + cost_per_core_hour: costPervCPUPerHour, }, }, { diff --git a/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.test.ts b/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.test.ts new file mode 100644 index 000000000000..1ebc52dec7c8 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { percentToFactor } from './percent_to_factor'; // Replace 'yourFile' with the actual file path + +describe('percentToFactor function', () => { + it('should convert 6% to factor 0.94', () => { + expect(percentToFactor(6)).toBe(0.94); + }); + + it('should convert 0% to factor 1', () => { + expect(percentToFactor(0)).toBe(1); + }); + + it('should convert 100% to factor 0', () => { + expect(percentToFactor(100)).toBe(0); + }); + + it('should handle negative input, convert -10% to factor 1.1', () => { + expect(percentToFactor(-10)).toBe(1.1); + }); + + it('should handle decimal input, convert 3.5% to factor 0.965', () => { + expect(percentToFactor(3.5)).toBe(0.965); + }); + + it('should handle large input, convert 1000% to factor -9', () => { + expect(percentToFactor(1000)).toBe(-9); + }); +}); diff --git a/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.ts b/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.ts new file mode 100644 index 000000000000..e9430e9a3a74 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/utils/percent_to_factor.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const percentToFactor = (percent: number) => 1 - percent / 100; diff --git a/x-pack/plugins/profiling_data_access/tsconfig.json b/x-pack/plugins/profiling_data_access/tsconfig.json index ccd0d3e54e81..456e83d4a9fa 100644 --- a/x-pack/plugins/profiling_data_access/tsconfig.json +++ b/x-pack/plugins/profiling_data_access/tsconfig.json @@ -21,5 +21,6 @@ "@kbn/fleet-plugin", "@kbn/cloud-plugin", "@kbn/spaces-plugin", + "@kbn/observability-plugin", ] } diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_setup_trust/confirm_modal.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_setup_trust/confirm_modal.tsx index 08ef4377338d..1d9e9f1900f0 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_setup_trust/confirm_modal.tsx +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_setup_trust/confirm_modal.tsx @@ -70,6 +70,9 @@ export const ConfirmTrustSetupModal = ({ closeModal, onSubmit }: ModalProps) => label={i18n.translate('xpack.remoteClusters.clusterWizard.trustStep.modal.checkbox', { defaultMessage: 'Yes, I have setup trust', })} + labelProps={{ + 'data-test-subj': 'remoteClusterTrustCheckboxLabel', + }} checked={hasSetupTrust} onChange={() => setHasSetupTrust(!hasSetupTrust)} data-test-subj="remoteClusterTrustCheckbox" diff --git a/x-pack/plugins/reporting/public/lib/default_status_context.tsx b/x-pack/plugins/reporting/public/lib/default_status_context.tsx new file mode 100644 index 000000000000..23609e7e0a6a --- /dev/null +++ b/x-pack/plugins/reporting/public/lib/default_status_context.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ClientConfigType } from '@kbn/reporting-public'; +import React, { createContext, FunctionComponent } from 'react'; +import { IlmPolicyStatusContextProvider } from './ilm_policy_status_context'; + +const PolicyStatusContext = createContext(undefined); + +interface PolicyStatusContextProviderProps { + config: ClientConfigType; +} + +export const PolicyStatusContextProvider: FunctionComponent = ({ + children, + ...props +}) => { + return props.config.statefulSettings.enabled ? ( + {children} + ) : ( + {children} + ); +}; diff --git a/x-pack/plugins/reporting/public/lib/reporting_api_client/hooks.ts b/x-pack/plugins/reporting/public/lib/reporting_api_client/hooks.ts index 5ede6e11ee78..6668e9efe881 100644 --- a/x-pack/plugins/reporting/public/lib/reporting_api_client/hooks.ts +++ b/x-pack/plugins/reporting/public/lib/reporting_api_client/hooks.ts @@ -13,5 +13,6 @@ export const useCheckIlmPolicyStatus = (): UseRequestResponse diff --git a/x-pack/plugins/reporting/public/management/default/report_listing_default.tsx b/x-pack/plugins/reporting/public/management/default/report_listing_default.tsx new file mode 100644 index 000000000000..a2b09ccd3c17 --- /dev/null +++ b/x-pack/plugins/reporting/public/management/default/report_listing_default.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; + +import { EuiPageHeader, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { ListingPropsInternal } from '..'; +import { ReportListingTable } from '../report_listing_table'; + +/** + * Used in non-stateful (Serverless) + * Does not render controls for features only applicable in Stateful + */ +export const ReportListingDefault: FC = (props) => { + const { apiClient, capabilities, config, navigateToUrl, toasts, urlService, ...listingProps } = + props; + return ( + <> + + } + description={ + + } + /> + + + + ); +}; diff --git a/x-pack/plugins/reporting/public/management/index.ts b/x-pack/plugins/reporting/public/management/index.ts index 4b9074267dd4..bdd6d0a9916b 100644 --- a/x-pack/plugins/reporting/public/management/index.ts +++ b/x-pack/plugins/reporting/public/management/index.ts @@ -8,20 +8,21 @@ import type { ApplicationStart, ToastsSetup } from '@kbn/core/public'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { ClientConfigType } from '@kbn/reporting-public'; -import type { UseIlmPolicyStatusReturn } from '../lib/ilm_policy_status_context'; import type { ReportingAPIClient } from '../lib/reporting_api_client'; import type { SharePluginSetup } from '../shared_imports'; export interface ListingProps { apiClient: ReportingAPIClient; - capabilities: ApplicationStart['capabilities']; license$: LicensingPluginStart['license$']; config: ClientConfigType; redirect: ApplicationStart['navigateToApp']; navigateToUrl: ApplicationStart['navigateToUrl']; toasts: ToastsSetup; urlService: SharePluginSetup['url']; - ilmPolicyContextValue: UseIlmPolicyStatusReturn; } +export type ListingPropsInternal = ListingProps & { + capabilities: ApplicationStart['capabilities']; +}; + export { ReportListing } from './report_listing'; diff --git a/x-pack/plugins/reporting/public/management/mount_management_section.tsx b/x-pack/plugins/reporting/public/management/mount_management_section.tsx index 60cd66d95278..575d9e7c8d7c 100644 --- a/x-pack/plugins/reporting/public/management/mount_management_section.tsx +++ b/x-pack/plugins/reporting/public/management/mount_management_section.tsx @@ -15,10 +15,10 @@ import { ILicense } from '@kbn/licensing-plugin/public'; import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import type { ClientConfigType } from '@kbn/reporting-public'; import { ReportListing } from '.'; -import { IlmPolicyStatusContextProvider } from '../lib/ilm_policy_status_context'; import { InternalApiClientProvider, ReportingAPIClient } from '../lib/reporting_api_client'; import type { ManagementAppMountParams, SharePluginSetup } from '../shared_imports'; import { KibanaContextProvider } from '../shared_imports'; +import { PolicyStatusContextProvider } from '../lib/default_status_context'; export async function mountManagementSection( coreSetup: CoreSetup, @@ -41,8 +41,9 @@ export async function mountManagementSection( }} > - + - + diff --git a/x-pack/plugins/reporting/public/management/report_listing.tsx b/x-pack/plugins/reporting/public/management/report_listing.tsx index 31976dd196a9..024d75b04ae1 100644 --- a/x-pack/plugins/reporting/public/management/report_listing.tsx +++ b/x-pack/plugins/reporting/public/management/report_listing.tsx @@ -5,529 +5,26 @@ * 2.0. */ -import { Component, Fragment, default as React } from 'react'; -import { Subscription } from 'rxjs'; - -import { - EuiBasicTable, - EuiBasicTableColumn, - EuiFlexGroup, - EuiFlexItem, - EuiIconTip, - EuiLink, - EuiLoadingSpinner, - EuiPageHeader, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { ILicense } from '@kbn/licensing-plugin/public'; -import { durationToNumber } from '@kbn/reporting-common'; +import React from 'react'; import { ListingProps as Props } from '.'; -import { REPORT_TABLE_ID, REPORT_TABLE_ROW_ID } from '../../common/constants'; -import { prettyPrintJobType } from '../../common/job_utils'; -import { Poller } from '../../common/poller'; -import { useIlmPolicyStatus } from '../lib/ilm_policy_status_context'; -import { Job } from '../lib/job'; -import { checkLicense } from '../lib/license_check'; import { useInternalApiClient } from '../lib/reporting_api_client'; import { useKibana } from '../shared_imports'; -import { - IlmPolicyLink, - MigrateIlmPolicyCallOut, - ReportDeleteButton, - ReportDiagnostic, - ReportInfoFlyout, - ReportStatusIndicator, -} from './components'; -import { guessAppIconTypeFromObjectType } from './utils'; import './report_listing.scss'; +import { ReportListingStateful } from './stateful/report_listing_stateful'; +import { ReportListingDefault } from './default/report_listing_default'; -type TableColumn = EuiBasicTableColumn; - -interface State { - page: number; - total: number; - jobs: Job[]; - selectedJobs: Job[]; - isLoading: boolean; - showLinks: boolean; - enableLinks: boolean; - badLicenseMessage: string; - selectedJob: undefined | Job; -} - -class ReportListingUi extends Component { - private isInitialJobsFetch: boolean; - private licenseSubscription?: Subscription; - private mounted?: boolean; - private poller?: Poller; - - constructor(props: Props) { - super(props); - - this.state = { - page: 0, - total: 0, - jobs: [], - selectedJobs: [], - isLoading: false, - showLinks: false, - enableLinks: false, - badLicenseMessage: '', - selectedJob: undefined, - }; - - this.isInitialJobsFetch = true; - } - - public render() { - const { - apiClient, - toasts, - ilmPolicyContextValue, - urlService, - navigateToUrl, - capabilities, - config, - } = this.props; - const ilmLocator = urlService.locators.get('ILM_LOCATOR_ID'); - const hasIlmPolicy = ilmPolicyContextValue.status !== 'policy-not-found'; - const showIlmPolicyLink = Boolean(ilmLocator && hasIlmPolicy); - return ( - <> - - } - description={ - - } - /> - - {config.statefulSettings.enabled ? : null} - - -
    {this.renderTable()}
    - - - - {capabilities?.management?.data?.index_lifecycle_management && ( - - {ilmPolicyContextValue.isLoading ? ( - - ) : ( - showIlmPolicyLink && ( - - ) - )} - - )} - - - - - - ); - } - - public componentWillUnmount() { - this.mounted = false; - this.poller?.stop(); - - if (this.licenseSubscription) { - this.licenseSubscription.unsubscribe(); - } - } - - public componentDidMount() { - this.mounted = true; - const { config, license$ } = this.props; - const pollFrequencyInMillis = durationToNumber(config.poll.jobsRefresh.interval); - this.poller = new Poller({ - functionToPoll: () => { - return this.fetchJobs(); - }, - pollFrequencyInMillis, - trailing: false, - continuePollingOnError: true, - pollFrequencyErrorMultiplier: config.poll.jobsRefresh.intervalErrorMultiplier, - }); - this.poller.start(); - this.licenseSubscription = license$.subscribe(this.licenseHandler); - } - - private licenseHandler = (license: ILicense) => { - const { - enableLinks, - showLinks, - message: badLicenseMessage, - } = checkLicense(license.check('reporting', 'basic')); - - this.setState({ - enableLinks, - showLinks, - badLicenseMessage, - }); - }; - - private onSelectionChange = (jobs: Job[]) => { - this.setState((current) => ({ ...current, selectedJobs: jobs })); - }; - - private removeJob = (job: Job) => { - const { jobs } = this.state; - const filtered = jobs.filter((j) => j.id !== job.id); - this.setState((current) => ({ ...current, jobs: filtered })); - }; - - private renderDeleteButton = () => { - const { selectedJobs } = this.state; - if (selectedJobs.length === 0) return undefined; - - const performDelete = async () => { - for (const job of selectedJobs) { - try { - await this.props.apiClient.deleteReport(job.id); - this.removeJob(job); - this.props.toasts.addSuccess( - i18n.translate('xpack.reporting.listing.table.deleteConfim', { - defaultMessage: `The {reportTitle} report was deleted`, - values: { - reportTitle: job.title, - }, - }) - ); - } catch (error) { - this.props.toasts.addDanger( - i18n.translate('xpack.reporting.listing.table.deleteFailedErrorMessage', { - defaultMessage: `The report was not deleted: {error}`, - values: { error }, - }) - ); - throw error; - } - } - }; - - return ( - - ); - }; - - private onTableChange = ({ page }: { page: { index: number } }) => { - const { index: pageIndex } = page; - this.setState(() => ({ page: pageIndex }), this.fetchJobs); - }; - - private fetchJobs = async () => { - // avoid page flicker when poller is updating table - only display loading screen on first load - if (this.isInitialJobsFetch) { - this.setState(() => ({ isLoading: true })); - } - - let jobs: Job[]; - let total: number; - try { - jobs = await this.props.apiClient.list(this.state.page); - total = await this.props.apiClient.total(); - this.isInitialJobsFetch = false; - } catch (fetchError) { - if (!this.licenseAllowsToShowThisPage()) { - this.props.toasts.addDanger(this.state.badLicenseMessage); - this.props.redirect('management'); - return; - } - - if (fetchError.message === 'Failed to fetch') { - this.props.toasts.addDanger( - fetchError.message || - i18n.translate('xpack.reporting.listing.table.requestFailedErrorMessage', { - defaultMessage: 'Request failed', - }) - ); - } - if (this.mounted) { - this.setState(() => ({ isLoading: false, jobs: [], total: 0 })); - } - return; - } - - if (this.mounted) { - this.setState(() => ({ - isLoading: false, - total, - jobs, - })); - } - }; - - private licenseAllowsToShowThisPage = () => { - return this.state.showLinks && this.state.enableLinks; - }; - - /** - * Widths like this are not the best, but the auto-layout does not play well with text in links. We can update - * this with something that works better on all screen sizes. This works for desktop, mobile fallback is provided on a - * per column basis. - */ - private readonly tableColumnWidths = { - type: '5%', - title: '30%', - status: '20%', - createdAt: '25%', - content: '10%', - actions: '10%', - }; - - private renderTable() { - const { tableColumnWidths } = this; - const tableColumns: TableColumn[] = [ - { - field: 'type', - width: tableColumnWidths.type, - name: i18n.translate('xpack.reporting.listing.tableColumns.typeTitle', { - defaultMessage: 'Type', - }), - render: (_type: string, job) => { - return ( -
    - -
    - ); - }, - mobileOptions: { - show: true, - render: (job) => { - return
    {job.objectType}
    ; - }, - }, - }, - { - field: 'title', - name: i18n.translate('xpack.reporting.listing.tableColumns.reportTitle', { - defaultMessage: 'Title', - }), - width: tableColumnWidths.title, - render: (objectTitle: string, job) => { - return ( -
    - this.setState({ selectedJob: job })} - > - {objectTitle || - i18n.translate('xpack.reporting.listing.table.noTitleLabel', { - defaultMessage: 'Untitled', - })} - -
    - ); - }, - mobileOptions: { - header: false, - width: '100%', // This is not recognized by EUI types but has an effect, leaving for now - } as unknown as { header: boolean }, - }, - { - field: 'status', - width: tableColumnWidths.status, - name: i18n.translate('xpack.reporting.listing.tableColumns.statusTitle', { - defaultMessage: 'Status', - }), - render: (_status: string, job) => { - return ( - - - - ); - }, - mobileOptions: { - show: false, - }, - }, - { - field: 'created_at', - width: tableColumnWidths.createdAt, - name: i18n.translate('xpack.reporting.listing.tableColumns.createdAtTitle', { - defaultMessage: 'Created at', - }), - render: (_createdAt: string, job) => ( -
    {job.getCreatedAtDate()}
    - ), - mobileOptions: { - show: false, - }, - }, - { - field: 'content', - width: tableColumnWidths.content, - name: i18n.translate('xpack.reporting.listing.tableColumns.content', { - defaultMessage: 'Content', - }), - render: (_status: string, job) => prettyPrintJobType(job.jobtype), - mobileOptions: { - show: false, - }, - }, - { - name: i18n.translate('xpack.reporting.listing.tableColumns.actionsTitle', { - defaultMessage: 'Actions', - }), - width: tableColumnWidths.actions, - actions: [ - { - isPrimary: true, - 'data-test-subj': 'reportDownloadLink', - type: 'icon', - icon: 'download', - name: i18n.translate('xpack.reporting.listing.table.downloadReportButtonLabel', { - defaultMessage: 'Download report', - }), - description: i18n.translate('xpack.reporting.listing.table.downloadReportDescription', { - defaultMessage: 'Download this report in a new tab.', - }), - onClick: (job) => this.props.apiClient.downloadReport(job.id), - enabled: (job) => job.isDownloadReady, - }, - { - name: i18n.translate( - 'xpack.reporting.listing.table.viewReportingInfoActionButtonLabel', - { - defaultMessage: 'View report info', - } - ), - description: i18n.translate( - 'xpack.reporting.listing.table.viewReportingInfoActionButtonDescription', - { - defaultMessage: 'View additional information about this report.', - } - ), - type: 'icon', - icon: 'iInCircle', - onClick: (job) => this.setState({ selectedJob: job }), - }, - { - name: i18n.translate('xpack.reporting.listing.table.openInKibanaAppLabel', { - defaultMessage: 'Open in Kibana', - }), - 'data-test-subj': 'reportOpenInKibanaApp', - description: i18n.translate( - 'xpack.reporting.listing.table.openInKibanaAppDescription', - { - defaultMessage: 'Open the Kibana app where this report was generated.', - } - ), - available: (job) => job.canLinkToKibanaApp, - type: 'icon', - icon: 'popout', - onClick: (job) => { - const href = this.props.apiClient.getKibanaAppHref(job); - window.open(href, '_blank'); - window.focus(); - }, - }, - ], - }, - ]; - - const pagination = { - pageIndex: this.state.page, - pageSize: 10, - totalItemCount: this.state.total, - showPerPageOptions: false, - }; - - const selection = { - itemId: 'id', - onSelectionChange: this.onSelectionChange, - }; - - return ( - - {this.state.selectedJobs.length > 0 && ( - - - {this.renderDeleteButton()} - - - - )} - ({ 'data-test-subj': REPORT_TABLE_ROW_ID })} - /> - {!!this.state.selectedJob && ( - this.setState({ selectedJob: undefined })} - job={this.state.selectedJob} - /> - )} - - ); - } -} - -export const ReportListing = ( - props: Omit< - Props, - 'ilmPolicyContextValue' | 'intl' | 'apiClient' | 'capabilities' | 'configAllowsImages' - > -) => { - const ilmPolicyStatusValue = useIlmPolicyStatus(); +export const ReportListing = (props: Props) => { const { apiClient } = useInternalApiClient(); const { services: { application: { capabilities }, }, } = useKibana(); - return ( - + return props.config.statefulSettings.enabled ? ( + + ) : ( + ); }; diff --git a/x-pack/plugins/reporting/public/management/report_listing_table.tsx b/x-pack/plugins/reporting/public/management/report_listing_table.tsx new file mode 100644 index 000000000000..c8dcbf77aba3 --- /dev/null +++ b/x-pack/plugins/reporting/public/management/report_listing_table.tsx @@ -0,0 +1,440 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Component, Fragment, default as React } from 'react'; +import { Subscription } from 'rxjs'; + +import { + EuiBasicTable, + EuiBasicTableColumn, + EuiFlexGroup, + EuiFlexItem, + EuiIconTip, + EuiLink, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ILicense } from '@kbn/licensing-plugin/public'; +import { durationToNumber } from '@kbn/reporting-common'; + +import { REPORT_TABLE_ID, REPORT_TABLE_ROW_ID } from '../../common/constants'; +import { prettyPrintJobType } from '../../common/job_utils'; +import { Poller } from '../../common/poller'; +import { Job } from '../lib/job'; +import { checkLicense } from '../lib/license_check'; +import { ReportDeleteButton, ReportInfoFlyout, ReportStatusIndicator } from './components'; +import { guessAppIconTypeFromObjectType } from './utils'; +import { ListingPropsInternal } from '.'; + +type TableColumn = EuiBasicTableColumn; + +interface State { + page: number; + total: number; + jobs: Job[]; + selectedJobs: Job[]; + isLoading: boolean; + showLinks: boolean; + enableLinks: boolean; + badLicenseMessage: string; + selectedJob: undefined | Job; +} + +export class ReportListingTable extends Component { + private isInitialJobsFetch: boolean; + private licenseSubscription?: Subscription; + private mounted?: boolean; + private poller?: Poller; + + constructor(props: ListingPropsInternal) { + super(props); + + this.state = { + page: 0, + total: 0, + jobs: [], + selectedJobs: [], + isLoading: false, + showLinks: false, + enableLinks: false, + badLicenseMessage: '', + selectedJob: undefined, + }; + + this.isInitialJobsFetch = true; + } + + public componentWillUnmount() { + this.mounted = false; + this.poller?.stop(); + + if (this.licenseSubscription) { + this.licenseSubscription.unsubscribe(); + } + } + + public componentDidMount() { + this.mounted = true; + const { config, license$ } = this.props; + const pollFrequencyInMillis = durationToNumber(config.poll.jobsRefresh.interval); + this.poller = new Poller({ + functionToPoll: () => { + return this.fetchJobs(); + }, + pollFrequencyInMillis, + trailing: false, + continuePollingOnError: true, + pollFrequencyErrorMultiplier: config.poll.jobsRefresh.intervalErrorMultiplier, + }); + this.poller.start(); + this.licenseSubscription = license$.subscribe(this.licenseHandler); + } + + private licenseHandler = (license: ILicense) => { + const { + enableLinks, + showLinks, + message: badLicenseMessage, + } = checkLicense(license.check('reporting', 'basic')); + + this.setState({ + enableLinks, + showLinks, + badLicenseMessage, + }); + }; + + private onSelectionChange = (jobs: Job[]) => { + this.setState((current) => ({ ...current, selectedJobs: jobs })); + }; + + private removeJob = (job: Job) => { + const { jobs } = this.state; + const filtered = jobs.filter((j) => j.id !== job.id); + this.setState((current) => ({ ...current, jobs: filtered })); + }; + + private renderDeleteButton = () => { + const { selectedJobs } = this.state; + if (selectedJobs.length === 0) return undefined; + + const performDelete = async () => { + for (const job of selectedJobs) { + try { + await this.props.apiClient.deleteReport(job.id); + this.removeJob(job); + this.props.toasts.addSuccess( + i18n.translate('xpack.reporting.listing.table.deleteConfim', { + defaultMessage: `The {reportTitle} report was deleted`, + values: { + reportTitle: job.title, + }, + }) + ); + } catch (error) { + this.props.toasts.addDanger( + i18n.translate('xpack.reporting.listing.table.deleteFailedErrorMessage', { + defaultMessage: `The report was not deleted: {error}`, + values: { error }, + }) + ); + throw error; + } + } + }; + + return ( + + ); + }; + + private onTableChange = ({ page }: { page: { index: number } }) => { + const { index: pageIndex } = page; + this.setState(() => ({ page: pageIndex }), this.fetchJobs); + }; + + private fetchJobs = async () => { + // avoid page flicker when poller is updating table - only display loading screen on first load + if (this.isInitialJobsFetch) { + this.setState(() => ({ isLoading: true })); + } + + let jobs: Job[]; + let total: number; + try { + jobs = await this.props.apiClient.list(this.state.page); + total = await this.props.apiClient.total(); + this.isInitialJobsFetch = false; + } catch (fetchError) { + if (!this.licenseAllowsToShowThisPage()) { + this.props.toasts.addDanger(this.state.badLicenseMessage); + this.props.redirect('management'); + return; + } + + if (fetchError.message === 'Failed to fetch') { + this.props.toasts.addDanger( + fetchError.message || + i18n.translate('xpack.reporting.listing.table.requestFailedErrorMessage', { + defaultMessage: 'Request failed', + }) + ); + } + if (this.mounted) { + this.setState(() => ({ isLoading: false, jobs: [], total: 0 })); + } + return; + } + + if (this.mounted) { + this.setState(() => ({ + isLoading: false, + total, + jobs, + })); + } + }; + + private licenseAllowsToShowThisPage = () => { + return this.state.showLinks && this.state.enableLinks; + }; + + /** + * Widths like this are not the best, but the auto-layout does not play well with text in links. We can update + * this with something that works better on all screen sizes. This works for desktop, mobile fallback is provided on a + * per column basis. + */ + private readonly tableColumnWidths = { + type: '5%', + title: '30%', + status: '20%', + createdAt: '25%', + content: '10%', + actions: '10%', + }; + + public render() { + const { tableColumnWidths } = this; + const tableColumns: TableColumn[] = [ + { + field: 'type', + width: tableColumnWidths.type, + name: i18n.translate('xpack.reporting.listing.tableColumns.typeTitle', { + defaultMessage: 'Type', + }), + render: (_type: string, job) => { + return ( +
    + +
    + ); + }, + mobileOptions: { + show: true, + render: (job) => { + return
    {job.objectType}
    ; + }, + }, + }, + { + field: 'title', + name: i18n.translate('xpack.reporting.listing.tableColumns.reportTitle', { + defaultMessage: 'Title', + }), + width: tableColumnWidths.title, + render: (objectTitle: string, job) => { + return ( +
    + this.setState({ selectedJob: job })} + > + {objectTitle || + i18n.translate('xpack.reporting.listing.table.noTitleLabel', { + defaultMessage: 'Untitled', + })} + +
    + ); + }, + mobileOptions: { + header: false, + width: '100%', // This is not recognized by EUI types but has an effect, leaving for now + } as unknown as { header: boolean }, + }, + { + field: 'status', + width: tableColumnWidths.status, + name: i18n.translate('xpack.reporting.listing.tableColumns.statusTitle', { + defaultMessage: 'Status', + }), + render: (_status: string, job) => { + return ( + + + + ); + }, + mobileOptions: { + show: false, + }, + }, + { + field: 'created_at', + width: tableColumnWidths.createdAt, + name: i18n.translate('xpack.reporting.listing.tableColumns.createdAtTitle', { + defaultMessage: 'Created at', + }), + render: (_createdAt: string, job) => ( +
    {job.getCreatedAtDate()}
    + ), + mobileOptions: { + show: false, + }, + }, + { + field: 'content', + width: tableColumnWidths.content, + name: i18n.translate('xpack.reporting.listing.tableColumns.content', { + defaultMessage: 'Content', + }), + render: (_status: string, job) => prettyPrintJobType(job.jobtype), + mobileOptions: { + show: false, + }, + }, + { + name: i18n.translate('xpack.reporting.listing.tableColumns.actionsTitle', { + defaultMessage: 'Actions', + }), + width: tableColumnWidths.actions, + actions: [ + { + isPrimary: true, + 'data-test-subj': 'reportDownloadLink', + type: 'icon', + icon: 'download', + name: i18n.translate('xpack.reporting.listing.table.downloadReportButtonLabel', { + defaultMessage: 'Download report', + }), + description: i18n.translate('xpack.reporting.listing.table.downloadReportDescription', { + defaultMessage: 'Download this report in a new tab.', + }), + onClick: (job) => this.props.apiClient.downloadReport(job.id), + enabled: (job) => job.isDownloadReady, + }, + { + name: i18n.translate( + 'xpack.reporting.listing.table.viewReportingInfoActionButtonLabel', + { + defaultMessage: 'View report info', + } + ), + description: i18n.translate( + 'xpack.reporting.listing.table.viewReportingInfoActionButtonDescription', + { + defaultMessage: 'View additional information about this report.', + } + ), + type: 'icon', + icon: 'iInCircle', + onClick: (job) => this.setState({ selectedJob: job }), + }, + { + name: i18n.translate('xpack.reporting.listing.table.openInKibanaAppLabel', { + defaultMessage: 'Open in Kibana', + }), + 'data-test-subj': 'reportOpenInKibanaApp', + description: i18n.translate( + 'xpack.reporting.listing.table.openInKibanaAppDescription', + { + defaultMessage: 'Open the Kibana app where this report was generated.', + } + ), + available: (job) => job.canLinkToKibanaApp, + type: 'icon', + icon: 'popout', + onClick: (job) => { + const href = this.props.apiClient.getKibanaAppHref(job); + window.open(href, '_blank'); + window.focus(); + }, + }, + ], + }, + ]; + + const pagination = { + pageIndex: this.state.page, + pageSize: 10, + totalItemCount: this.state.total, + showPerPageOptions: false, + }; + + const selection = { + itemId: 'id', + onSelectionChange: this.onSelectionChange, + }; + + return ( + + {this.state.selectedJobs.length > 0 && ( +
    + + {this.renderDeleteButton()} + + +
    + )} + ({ 'data-test-subj': REPORT_TABLE_ROW_ID })} + /> + {!!this.state.selectedJob && ( + this.setState({ selectedJob: undefined })} + job={this.state.selectedJob} + /> + )} +
    + ); + } +} diff --git a/x-pack/plugins/reporting/public/management/stateful/report_listing_stateful.tsx b/x-pack/plugins/reporting/public/management/stateful/report_listing_stateful.tsx new file mode 100644 index 000000000000..3e7a3c8cb10f --- /dev/null +++ b/x-pack/plugins/reporting/public/management/stateful/report_listing_stateful.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiLoadingSpinner, + EuiPageHeader, + EuiSpacer, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { ListingPropsInternal } from '..'; +import { useIlmPolicyStatus } from '../../lib/ilm_policy_status_context'; +import { IlmPolicyLink, MigrateIlmPolicyCallOut, ReportDiagnostic } from '../components'; +import { ReportListingTable } from '../report_listing_table'; + +/** + * Used in Stateful deployments only + * Renders controls for ILM and Screenshotting Diagnostics which are only applicable in Stateful + */ +export const ReportListingStateful: FC = (props) => { + const { apiClient, capabilities, config, navigateToUrl, toasts, urlService, ...listingProps } = + props; + const ilmLocator = urlService.locators.get('ILM_LOCATOR_ID'); + const ilmPolicyContextValue = useIlmPolicyStatus(); + const hasIlmPolicy = ilmPolicyContextValue?.status !== 'policy-not-found'; + const showIlmPolicyLink = Boolean(ilmLocator && hasIlmPolicy); + return ( + <> + + } + description={ + + } + /> + + + + + + + + + + {capabilities?.management?.data?.index_lifecycle_management && ( + + {ilmPolicyContextValue?.isLoading ? ( + + ) : ( + showIlmPolicyLink && ( + + ) + )} + + )} + + + + + + ); +}; diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts index 5bf73525c2dc..bf868199de4c 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.test.ts @@ -18,6 +18,7 @@ import { ReportingAPIClient } from '../lib/reporting_api_client'; import type { ReportingPublicPluginStartDependencies } from '../plugin'; import type { ActionContext } from './get_csv_panel_action'; import { ReportingCsvPanelAction } from './get_csv_panel_action'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; const core = coreMock.createSetup(); let apiClient: ReportingAPIClient; @@ -124,7 +125,7 @@ describe('GetCsvReportPanelAction', () => { createCopy: () => mockSearchSource, removeField: jest.fn(), setField: jest.fn(), - getField: jest.fn(), + getField: jest.fn((name) => (name === 'index' ? dataViewMock : undefined)), getSerializedFields: jest.fn().mockImplementation(() => ({ testData: 'testDataValue' })), } as unknown as SearchSource; context.embeddable.getSavedSearch = () => { diff --git a/x-pack/plugins/reporting/server/routes/common/jobs/get_job_routes.ts b/x-pack/plugins/reporting/server/routes/common/jobs/get_job_routes.ts index ddd226187adf..a88abae999be 100644 --- a/x-pack/plugins/reporting/server/routes/common/jobs/get_job_routes.ts +++ b/x-pack/plugins/reporting/server/routes/common/jobs/get_job_routes.ts @@ -5,12 +5,9 @@ * 2.0. */ -import { promisify } from 'util'; - import { schema, TypeOf } from '@kbn/config-schema'; import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server'; import { ALLOWED_JOB_CONTENT_TYPES } from '@kbn/reporting-common'; - import { getCounters } from '..'; import { ReportingCore } from '../../..'; import { getContentStream } from '../../../lib'; @@ -84,9 +81,12 @@ export const commonJobsRouteHandlerFactory = (reporting: ReportingCore) => { return jobManagementPreRouting(reporting, res, docId, user, counters, async (doc) => { const docIndex = doc.index; const stream = await getContentStream(reporting, { id: docId, index: docIndex }); - /** @note Overwriting existing content with an empty buffer to remove all the chunks. */ - await promisify(stream.end.bind(stream, '', 'utf8'))(); + await new Promise((resolve) => { + stream.end('', 'utf8', () => { + resolve(); + }); + }); await jobsQuery.delete(docIndex, docId); return res.ok({ diff --git a/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts b/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts index 9efe74a0c3aa..b87c6040e46b 100644 --- a/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts +++ b/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts @@ -206,11 +206,7 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory async delete(deleteIndex, id) { try { const { asInternalUser: elasticsearchClient } = await reportingCore.getEsClient(); - - // Using `wait_for` helps avoid users seeing recently-deleted reports temporarily flashing back in the - // job listing. - const query = { id, index: deleteIndex, refresh: 'wait_for' as const }; - + const query = { id, index: deleteIndex }; return await elasticsearchClient.delete(query, { meta: true }); } catch (error) { throw new Error( diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json index 53a4ab34eb19..4b784e29db10 100644 --- a/x-pack/plugins/reporting/tsconfig.json +++ b/x-pack/plugins/reporting/tsconfig.json @@ -50,6 +50,7 @@ "@kbn/reporting-mocks-server", "@kbn/core-http-request-handler-context-server", "@kbn/reporting-public", + "@kbn/discover-utils", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.test.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.test.ts index 4d25b41b6db0..e79caa639397 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.test.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.test.ts @@ -79,6 +79,13 @@ it('matches snapshot', () => { }, "kibana.alert.reason": Object { "array": false, + "multi_fields": Array [ + Object { + "flat_name": "kibana.alert.reason.text", + "name": "text", + "type": "match_only_text", + }, + ], "required": false, "type": "keyword", }, @@ -286,6 +293,11 @@ it('matches snapshot', () => { "required": true, "type": "keyword", }, + "kibana.alert.workflow_assignee_ids": Object { + "array": true, + "required": false, + "type": "keyword", + }, "kibana.alert.workflow_reason": Object { "array": false, "required": false, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index 47eeb6e46c40..f395ddb4b75f 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -22,6 +22,7 @@ import { ALERT_STATUS_ACTIVE, ALERT_CASE_IDS, MAX_CASES_PER_ALERT, + AlertConsumers, } from '@kbn/rule-data-utils'; import { @@ -80,6 +81,7 @@ export interface ConstructorOptions { esClient: ElasticsearchClient; ruleDataService: IRuleDataService; getRuleType: RuleTypeRegistry['get']; + getRuleList: RuleTypeRegistry['list']; getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; } @@ -153,6 +155,7 @@ export class AlertsClient { private readonly spaceId: string | undefined; private readonly ruleDataService: IRuleDataService; private readonly getRuleType: RuleTypeRegistry['get']; + private readonly getRuleList: RuleTypeRegistry['list']; private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; constructor(options: ConstructorOptions) { @@ -165,6 +168,7 @@ export class AlertsClient { this.spaceId = this.authorization.getSpaceId(); this.ruleDataService = options.ruleDataService; this.getRuleType = options.getRuleType; + this.getRuleList = options.getRuleList; this.getAlertIndicesAlias = options.getAlertIndicesAlias; } @@ -1076,19 +1080,31 @@ export class AlertsClient { } public async getBrowserFields({ + featureIds, indices, metaFields, allowNoIndex, }: { + featureIds: string[]; indices: string[]; metaFields: string[]; allowNoIndex: boolean; }): Promise<{ browserFields: BrowserFields; fields: FieldDescriptor[] }> { const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); + const ruleTypeList = this.getRuleList(); + const fieldsForAAD = new Set(); + for (const rule of ruleTypeList) { + if (featureIds.includes(rule.producer) && rule.hasFieldsForAAD) { + (rule.fieldsForAAD ?? []).forEach((f) => { + fieldsForAAD.add(f); + }); + } + } const { fields } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ pattern: indices, metaFields, fieldCapsOptions: { allow_no_indices: allowNoIndex }, + fields: [...fieldsForAAD, 'kibana.*'], }); return { @@ -1099,11 +1115,13 @@ export class AlertsClient { public async getAADFields({ ruleTypeId }: { ruleTypeId: string }) { const { producer, fieldsForAAD = [] } = this.getRuleType(ruleTypeId); + if (producer === AlertConsumers.SIEM) { + throw Boom.badRequest(`Security solution rule type is not supported`); + } const indices = await this.getAuthorizedAlertsIndices([producer]); - const o11yIndices = indices?.filter((index) => index.startsWith('.alerts-observability')) ?? []; const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); - const { fields } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ - pattern: o11yIndices, + const { fields = [] } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ + pattern: indices ?? [], metaFields: ['_id', '_index'], fieldCapsOptions: { allow_no_indices: true }, fields: [...fieldsForAAD, 'kibana.*'], diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts index 43966d120700..367ead5744d5 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts @@ -26,6 +26,7 @@ const alertsClientFactoryParams: AlertsClientFactoryProps = { esClient: {} as ElasticsearchClient, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; @@ -53,6 +54,7 @@ describe('AlertsClientFactory', () => { auditLogger, esClient: {}, ruleDataService: alertsClientFactoryParams.ruleDataService, + getRuleList: alertsClientFactoryParams.getRuleList, getRuleType: alertsClientFactoryParams.getRuleType, getAlertIndicesAlias: alertsClientFactoryParams.getAlertIndicesAlias, }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts index de0afb5a0b22..934074cc4a2e 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts @@ -23,6 +23,7 @@ export interface AlertsClientFactoryProps { securityPluginSetup: SecurityPluginSetup | undefined; ruleDataService: IRuleDataService | null; getRuleType: RuleTypeRegistry['get']; + getRuleList: RuleTypeRegistry['list']; getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; } @@ -36,6 +37,7 @@ export class AlertsClientFactory { private securityPluginSetup!: SecurityPluginSetup | undefined; private ruleDataService!: IRuleDataService | null; private getRuleType!: RuleTypeRegistry['get']; + private getRuleList!: RuleTypeRegistry['list']; private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; public initialize(options: AlertsClientFactoryProps) { @@ -53,6 +55,7 @@ export class AlertsClientFactory { this.securityPluginSetup = options.securityPluginSetup; this.ruleDataService = options.ruleDataService; this.getRuleType = options.getRuleType; + this.getRuleList = options.getRuleList; this.getAlertIndicesAlias = options.getAlertIndicesAlias; } @@ -66,6 +69,7 @@ export class AlertsClientFactory { esClient: this.esClient, ruleDataService: this.ruleDataService!, getRuleType: this.getRuleType, + getRuleList: this.getRuleList, getAlertIndicesAlias: this.getAlertIndicesAlias, }); } diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts index 4229ae23793f..28cd76ca6dff 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts @@ -31,6 +31,7 @@ const alertsClientParams: jest.Mocked = { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update_cases.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update_cases.test.ts index 4047a3ecadd2..544fab479f9d 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update_cases.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update_cases.test.ts @@ -37,6 +37,7 @@ describe('bulkUpdateCases', () => { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts index 37ad46a523a7..8ccae88dd83c 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts @@ -30,6 +30,7 @@ const alertsClientParams: jest.Mocked = { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts index fb1e0eef432e..4185fb7e83eb 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts @@ -31,6 +31,7 @@ const alertsClientParams: jest.Mocked = { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts new file mode 100644 index 000000000000..777b3d3e2674 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertsClient, ConstructorOptions } from '../alerts_client'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; + +const alertingAuthMock = alertingAuthorizationMock.create(); +const esClientMock = elasticsearchClientMock.createElasticsearchClient(); +const auditLogger = auditLoggerMock.create(); +const getRuleTypeMock = jest.fn(); +const alertsClientParams: jest.Mocked = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + getRuleType: getRuleTypeMock, + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn(), +}; + +const DEFAULT_SPACE = 'test_default_space_id'; + +beforeEach(() => { + jest.resetAllMocks(); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); +}); + +describe('getAADFields()', () => { + test('should throw an error when a rule type belong to security solution', async () => { + getRuleTypeMock.mockImplementation(() => ({ + producer: AlertConsumers.SIEM, + fieldsForAAD: [], + })); + const alertsClient = new AlertsClient(alertsClientParams); + + await expect( + alertsClient.getAADFields({ ruleTypeId: 'security-type' }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"Security solution rule type is not supported"`); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/remove_cases_from_alerts.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/remove_cases_from_alerts.test.ts index 2611200afd85..317de5d52e8e 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/remove_cases_from_alerts.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/remove_cases_from_alerts.test.ts @@ -32,6 +32,7 @@ describe('remove cases from alerts', () => { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; @@ -90,6 +91,7 @@ describe('remove cases from alerts', () => { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts index bca5e7d967f3..bd6a1b2695cd 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts @@ -30,6 +30,7 @@ const alertsClientParams: jest.Mocked = { auditLogger, ruleDataService: ruleDataServiceMock.create(), getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: jest.fn(), }; diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 6fba837a10c1..8cb6df23ae76 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -166,6 +166,7 @@ export class RuleRegistryPlugin securityPluginSetup: security, ruleDataService, getRuleType: plugins.alerting.getType, + getRuleList: plugins.alerting.listTypes, getAlertIndicesAlias: plugins.alerting.getAlertIndicesAlias, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts index 259ca0347874..995f992e0b80 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts @@ -53,6 +53,7 @@ export const getBrowserFieldsByFeatureId = (router: IRouter { expect(ruleDataClient.isWriteEnabled()).toBe(true); }); + test('sanitizes error before logging', async () => { + scopedClusterClient.bulk.mockResponseOnce({ + took: 486, + errors: true, + items: [ + { + create: { + _index: 'test', + _id: '3', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + { + create: { + _index: 'test', + _id: '4', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + { + create: { + _index: 'index1', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'. Preview of field's value: 'we don't want this field value to be echoed'", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, + ], + }); + const ruleDataClient = new RuleDataClient( + getRuleDataClientOptions({ isUsingDataStreams }) + ); + expect(ruleDataClient.isWriteEnabled()).toBe(true); + const writer = await ruleDataClient.getWriter(); + + // Previously, a delay between calling getWriter() and using a writer function + // would cause an Unhandled promise rejection if there were any errors getting a writer + // Adding this delay in the tests to ensure this does not pop up again. + await delay(); + + const bulkWriteResponse = await writer.bulk({}); + expect(bulkWriteResponse).toEqual({ + body: { + took: 486, + errors: true, + items: [ + { + create: { + _index: 'test', + _id: '3', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + { + create: { + _index: 'test', + _id: '4', + _version: 1, + result: 'created', + _shards: { total: 2, successful: 1, failed: 0 }, + status: 201, + _seq_no: 2, + _primary_term: 3, + }, + }, + { + create: { + _index: 'index1', + _id: '7', + status: 404, + error: { + type: 'mapper_parsing_exception', + reason: + "failed to parse field [process.command_line] of type [wildcard] in document with id 'f0c9805be95fedbc3c99c663f7f02cc15826c122'.", + caused_by: { + type: 'illegal_state_exception', + reason: "Can't get text on a START_OBJECT at 1:3845", + }, + }, + }, + }, + ], + }, + headers: { + 'x-elastic-product': 'Elasticsearch', + }, + meta: {}, + statusCode: 200, + warnings: [], + }); + + expect(logger.error).toHaveBeenNthCalledWith( + 1, + // @ts-expect-error + new errors.ResponseError(bulkWriteResponse) + ); + expect(ruleDataClient.isWriteEnabled()).toBe(true); + }); + test('waits until cluster client is ready before calling bulk', async () => { scopedClusterClient.bulk.mockResolvedValueOnce( elasticsearchClientMock.createSuccessTransportRequestPromise( diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts index b4d029f4bbe8..329c06042609 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { errors } from '@elastic/elasticsearch'; +import { errors, TransportResult } from '@elastic/elasticsearch'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Either, isLeft } from 'fp-ts/lib/Either'; @@ -14,6 +14,7 @@ import { Logger } from '@kbn/core/server'; import { IndexPatternsFetcher } from '@kbn/data-plugin/server'; import type { ESSearchRequest, ESSearchResponse } from '@kbn/es-types'; +import { sanitizeBulkErrorResponse } from '@kbn/alerting-plugin/server'; import { RuleDataWriteDisabledError, RuleDataWriterInitializationError, @@ -231,13 +232,20 @@ export class RuleDataClient implements IRuleDataClient { meta: true, }); + if (!response.body.errors) { + return response; + } + // TODO: #160572 - add support for version conflict errors, in case alert was updated // some other way between the time it was fetched and the time it was updated. - if (response.body.errors) { - const error = new errors.ResponseError(response); - this.options.logger.error(error); - } - return response; + // Redact part of reason message that echoes back value + const sanitizedResponse = sanitizeBulkErrorResponse(response) as TransportResult< + estypes.BulkResponse, + unknown + >; + const error = new errors.ResponseError(sanitizedResponse); + this.options.logger.error(error); + return sanitizedResponse; } else { this.options.logger.debug(`Writing is disabled, bulk() will not write any data.`); } diff --git a/x-pack/plugins/security/common/constants.ts b/x-pack/plugins/security/common/constants.ts index 9aff47c459a7..48a020210596 100644 --- a/x-pack/plugins/security/common/constants.ts +++ b/x-pack/plugins/security/common/constants.ts @@ -15,7 +15,6 @@ export const ALL_SPACES_ID = '*'; */ export const UNKNOWN_SPACE = '?'; -export const GLOBAL_RESOURCE = '*'; export const APPLICATION_PREFIX = 'kibana-'; /** diff --git a/x-pack/plugins/security/common/index.ts b/x-pack/plugins/security/common/index.ts index c547833949de..e30fff0a8e76 100644 --- a/x-pack/plugins/security/common/index.ts +++ b/x-pack/plugins/security/common/index.ts @@ -5,27 +5,40 @@ * 2.0. */ -export type { SecurityLicense, SecurityLicenseFeatures, LoginLayout } from './licensing'; export type { - AuthenticatedUser, GetUserProfileResponse, + ApiKey, + RestApiKey, + GetUserDisplayNameParams, + EditUser, + BuiltinESPrivileges, + RawKibanaPrivileges, + RoleMapping, + RoleTemplate, + StoredRoleTemplate, + InvalidRoleTemplate, + InlineRoleTemplate, +} from './model'; +export { getUserDisplayName, isRoleReserved } from './model'; + +// Re-export types from the plugin directly to enhance the developer experience for consumers of the Security plugin. +export type { + AuthenticatedUser, + UserRealm, + User, AuthenticationProvider, - PrivilegeDeprecationsService, - PrivilegeDeprecationsRolesByFeatureIdRequest, - PrivilegeDeprecationsRolesByFeatureIdResponse, Role, RoleIndexPrivilege, RoleKibanaPrivilege, + RoleRemoteIndexPrivilege, FeaturesPrivileges, - User, + LoginLayout, + SecurityLicenseFeatures, + SecurityLicense, UserProfile, UserProfileUserInfo, UserProfileWithSecurity, UserProfileData, UserProfileLabels, UserProfileUserInfoWithSecurity, - ApiKey, - UserRealm, - GetUserDisplayNameParams, -} from './model'; -export { getUserDisplayName } from './model'; +} from '@kbn/security-plugin-types-common'; diff --git a/x-pack/plugins/security/common/licensing/index.mock.ts b/x-pack/plugins/security/common/licensing/index.mock.ts index b947fa5b1ed2..7065deb939c1 100644 --- a/x-pack/plugins/security/common/licensing/index.mock.ts +++ b/x-pack/plugins/security/common/licensing/index.mock.ts @@ -9,9 +9,7 @@ import { Observable, of } from 'rxjs'; import type { LicenseType } from '@kbn/licensing-plugin/common/types'; import { LICENSE_TYPE } from '@kbn/licensing-plugin/common/types'; - -import type { SecurityLicenseFeatures } from './license_features'; -import type { SecurityLicense } from './license_service'; +import type { SecurityLicense, SecurityLicenseFeatures } from '@kbn/security-plugin-types-common'; export const licenseMock = { create: ( diff --git a/x-pack/plugins/security/common/licensing/index.ts b/x-pack/plugins/security/common/licensing/index.ts index 48329aeb9992..e36a22b5f8b6 100644 --- a/x-pack/plugins/security/common/licensing/index.ts +++ b/x-pack/plugins/security/common/licensing/index.ts @@ -5,7 +5,4 @@ * 2.0. */ -export type { SecurityLicense } from './license_service'; export { SecurityLicenseService } from './license_service'; - -export type { LoginLayout, SecurityLicenseFeatures } from './license_features'; diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index cbb658dde988..4372fa918e49 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -9,17 +9,7 @@ import type { Observable, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import type { ILicense, LicenseType } from '@kbn/licensing-plugin/common/types'; - -import type { SecurityLicenseFeatures } from './license_features'; - -export interface SecurityLicense { - isLicenseAvailable(): boolean; - isEnabled(): boolean; - getFeatures(): SecurityLicenseFeatures; - hasAtLeast(licenseType: LicenseType): boolean | undefined; - features$: Observable; -} - +import type { SecurityLicenseFeatures } from '@kbn/security-plugin-types-common'; interface SetupDeps { license$: Observable; } diff --git a/x-pack/plugins/security/common/login_state.ts b/x-pack/plugins/security/common/login_state.ts index fe2c6380db3e..b274883d0146 100644 --- a/x-pack/plugins/security/common/login_state.ts +++ b/x-pack/plugins/security/common/login_state.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { LoginLayout } from './licensing'; +import type { LoginLayout } from '@kbn/security-plugin-types-common'; export interface LoginSelectorProvider { type: string; diff --git a/x-pack/plugins/security/common/model/authenticated_user.mock.ts b/x-pack/plugins/security/common/model/authenticated_user.mock.ts index 84b300d5c982..6f691579b073 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.mock.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AuthenticatedUser } from './authenticated_user'; +import type { AuthenticatedUser } from '@kbn/security-plugin-types-common'; // We omit `roles` here since the original interface defines this field as `readonly string[]` that makes it hard to use // in various mocks that expect mutable string array. diff --git a/x-pack/plugins/security/common/model/authenticated_user.test.ts b/x-pack/plugins/security/common/model/authenticated_user.test.ts index 4c84a951bf72..9ed02c57841b 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.test.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.test.ts @@ -6,8 +6,8 @@ */ import { applicationServiceMock } from '@kbn/core/public/mocks'; +import type { AuthenticatedUser } from '@kbn/security-plugin-types-common'; -import type { AuthenticatedUser } from './authenticated_user'; import { canUserChangeDetails, canUserChangePassword, diff --git a/x-pack/plugins/security/common/model/authenticated_user.ts b/x-pack/plugins/security/common/model/authenticated_user.ts index fd78b250a5cc..02c1e0f3936d 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.ts @@ -6,64 +6,10 @@ */ import type { Capabilities } from '@kbn/core/types'; - -import type { AuthenticationProvider } from './authentication_provider'; -import type { User } from './user'; +import type { AuthenticatedUser } from '@kbn/security-plugin-types-common'; const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native']; -/** - * An Elasticsearch realm that was used to resolve and authenticate the user. - */ -export interface UserRealm { - /** - * Arbitrary name of the security realm. - */ - name: string; - - /** - * Type of the security realm (file, native, saml etc.). - */ - type: string; -} - -/** - * Represents the currently authenticated user. - */ -export interface AuthenticatedUser extends User { - /** - * The name and type of the Realm that has authenticated the user. - */ - authentication_realm: UserRealm; - - /** - * The name and type of the Realm where the user information were retrieved from. - */ - lookup_realm: UserRealm; - - /** - * The authentication provider that used to authenticate user. - */ - authentication_provider: AuthenticationProvider; - - /** - * The AuthenticationType used by ES to authenticate the user. - * - * @example "realm" | "api_key" | "token" | "anonymous" | "internal" - */ - authentication_type: string; - - /** - * Indicates whether user is authenticated via Elastic Cloud built-in SAML realm. - */ - elastic_cloud_user: boolean; - - /** - * User profile ID of this user. - */ - profile_uid?: string; -} - export function isUserAnonymous(user: Pick) { return user.authentication_provider.type === 'anonymous'; } diff --git a/x-pack/plugins/security/common/model/authentication_provider.ts b/x-pack/plugins/security/common/model/authentication_provider.ts index 9435c8ec55c9..4cdc49cf62ee 100644 --- a/x-pack/plugins/security/common/model/authentication_provider.ts +++ b/x-pack/plugins/security/common/model/authentication_provider.ts @@ -5,20 +5,6 @@ * 2.0. */ -/** - * Type and name tuple to identify provider used to authenticate user. - */ -export interface AuthenticationProvider { - /** - * Type of the Kibana authentication provider. - */ - type: string; - /** - * Name of the Kibana authentication provider (arbitrary string). - */ - name: string; -} - /** * Checks whether authentication provider with the specified type uses Kibana's native login form. * @param providerType Type of the authentication provider. diff --git a/x-pack/plugins/security/common/model/index.ts b/x-pack/plugins/security/common/model/index.ts index c8505a644503..006a0104e30d 100644 --- a/x-pack/plugins/security/common/model/index.ts +++ b/x-pack/plugins/security/common/model/index.ts @@ -13,40 +13,23 @@ export type { ApiKeyRoleDescriptors, CrossClusterApiKeyAccess, } from './api_key'; -export type { User, EditUser, GetUserDisplayNameParams } from './user'; -export type { - GetUserProfileResponse, - UserProfile, - UserProfileUserInfo, - UserProfileWithSecurity, - UserProfileData, - UserProfileLabels, - UserProfileUserInfoWithSecurity, -} from './user_profile'; +export type { EditUser, GetUserDisplayNameParams } from './user'; +export type { GetUserProfileResponse } from './user_profile'; export { getUserAvatarColor, getUserAvatarInitials, USER_AVATAR_MAX_INITIALS, } from './user_profile'; export { getUserDisplayName } from './user'; -export type { AuthenticatedUser, UserRealm } from './authenticated_user'; export { canUserChangePassword, canUserChangeDetails, isUserAnonymous, canUserHaveProfile, } from './authenticated_user'; -export type { AuthenticationProvider } from './authentication_provider'; export { shouldProviderUseLoginForm } from './authentication_provider'; export type { BuiltinESPrivileges } from './builtin_es_privileges'; export type { RawKibanaPrivileges, RawKibanaFeaturePrivileges } from './raw_kibana_privileges'; -export type { FeaturesPrivileges } from './features_privileges'; -export type { - Role, - RoleIndexPrivilege, - RoleRemoteIndexPrivilege, - RoleKibanaPrivilege, -} from './role'; export { copyRole, isRoleDeprecated, @@ -65,8 +48,3 @@ export type { RoleTemplate, RoleMapping, } from './role_mapping'; -export type { - PrivilegeDeprecationsRolesByFeatureIdRequest, - PrivilegeDeprecationsRolesByFeatureIdResponse, - PrivilegeDeprecationsService, -} from './deprecations'; diff --git a/x-pack/plugins/security/common/model/role.test.ts b/x-pack/plugins/security/common/model/role.test.ts index 0aa34fefc73e..b973115ed69b 100644 --- a/x-pack/plugins/security/common/model/role.test.ts +++ b/x-pack/plugins/security/common/model/role.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { Role } from '.'; +import type { Role } from '@kbn/security-plugin-types-common'; + import { copyRole, getExtendedRoleDeprecationNotice, diff --git a/x-pack/plugins/security/common/model/role.ts b/x-pack/plugins/security/common/model/role.ts index 17971905fc1e..1872f3bff2f5 100644 --- a/x-pack/plugins/security/common/model/role.ts +++ b/x-pack/plugins/security/common/model/role.ts @@ -8,48 +8,7 @@ import { cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; - -import type { FeaturesPrivileges } from './features_privileges'; - -export interface RoleIndexPrivilege { - names: string[]; - privileges: string[]; - field_security?: { - grant?: string[]; - except?: string[]; - }; - query?: string; -} - -export interface RoleRemoteIndexPrivilege extends RoleIndexPrivilege { - clusters: string[]; -} - -export interface RoleKibanaPrivilege { - spaces: string[]; - base: string[]; - feature: FeaturesPrivileges; - _reserved?: string[]; -} - -export interface Role { - name: string; - elasticsearch: { - cluster: string[]; - indices: RoleIndexPrivilege[]; - remote_indices?: RoleRemoteIndexPrivilege[]; - run_as: string[]; - }; - kibana: RoleKibanaPrivilege[]; - metadata?: { - [anyKey: string]: any; - }; - transient_metadata?: { - [anyKey: string]: any; - }; - _transform_error?: string[]; - _unrecognized_applications?: string[]; -} +import type { Role } from '@kbn/security-plugin-types-common'; /** * Returns whether given role is enabled or not diff --git a/x-pack/plugins/security/common/model/user.test.ts b/x-pack/plugins/security/common/model/user.test.ts index 80a2abcf40a0..b22344ea8e23 100644 --- a/x-pack/plugins/security/common/model/user.test.ts +++ b/x-pack/plugins/security/common/model/user.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { User } from './user'; +import type { User } from '@kbn/security-plugin-types-common'; + import { getUserDisplayName } from './user'; describe('#getUserDisplayName', () => { diff --git a/x-pack/plugins/security/common/model/user.ts b/x-pack/plugins/security/common/model/user.ts index 88bbf378c508..a04e9be77dfc 100644 --- a/x-pack/plugins/security/common/model/user.ts +++ b/x-pack/plugins/security/common/model/user.ts @@ -5,21 +5,7 @@ * 2.0. */ -/** - * A set of fields describing Kibana user. - */ -export interface User { - username: string; - email?: string; - full_name?: string; - roles: readonly string[]; - enabled: boolean; - metadata?: { - _reserved: boolean; - _deprecated?: boolean; - _deprecated_reason?: string; - }; -} +import type { User } from '@kbn/security-plugin-types-common'; export interface EditUser extends User { password?: string; diff --git a/x-pack/plugins/security/common/model/user_profile.mock.ts b/x-pack/plugins/security/common/model/user_profile.mock.ts index 7e72ce26e13c..519948b94f57 100644 --- a/x-pack/plugins/security/common/model/user_profile.mock.ts +++ b/x-pack/plugins/security/common/model/user_profile.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { UserProfile, UserProfileWithSecurity } from './user_profile'; +import type { UserProfile, UserProfileWithSecurity } from '@kbn/security-plugin-types-common'; function createUserProfileMock(userProfile: Partial = {}) { return { diff --git a/x-pack/plugins/security/common/model/user_profile.ts b/x-pack/plugins/security/common/model/user_profile.ts index 152b0d0266bb..0c9daba622e7 100644 --- a/x-pack/plugins/security/common/model/user_profile.ts +++ b/x-pack/plugins/security/common/model/user_profile.ts @@ -7,111 +7,16 @@ import { VISUALIZATION_COLORS } from '@elastic/eui'; +import type { + AuthenticatedUser, + UserProfileData, + UserProfileUserInfo, + UserProfileWithSecurity, +} from '@kbn/security-plugin-types-common'; import type { UserProfileAvatarData } from '@kbn/user-profile-components'; -import type { AuthenticatedUser } from './authenticated_user'; import { getUserDisplayName } from './user'; -/** - * IMPORTANT: - * - * The types in this file are duplicated at - * `packages/kbn-user-profile-components/src/user_profile.ts` - * - * When making changes please ensure to keep both files in sync. - */ - -/** - * Describes basic properties stored in user profile. - */ -export interface UserProfile { - /** - * Unique ID for of the user profile. - */ - uid: string; - - /** - * Indicates whether user profile is enabled or not. - */ - enabled: boolean; - - /** - * Information about the user that owns profile. - */ - user: UserProfileUserInfo; - - /** - * User specific data associated with the profile. - */ - data: Partial; -} - -/** - * Basic user information returned in user profile. - */ -export interface UserProfileUserInfo { - /** - * Username of the user. - */ - username: string; - /** - * Optional email of the user. - */ - email?: string; - /** - * Optional full name of the user. - */ - full_name?: string; -} - -/** - * Placeholder for data stored in user profile. - */ -export type UserProfileData = Record; - -/** - * Type of the user profile labels structure (currently - */ -export type UserProfileLabels = Record; - -/** - * Extended user information returned in user profile (both basic and security related properties). - */ -export interface UserProfileUserInfoWithSecurity extends UserProfileUserInfo { - /** - * List of the user roles. - */ - roles: readonly string[]; - /** - * Name of the Elasticsearch security realm that was used to authenticate user. - */ - realm_name: string; - /** - * Optional name of the security domain that Elasticsearch security realm that was - * used to authenticate user resides in (if any). - */ - realm_domain?: string; -} - -/** - * Describes all properties stored in user profile (both basic and security related properties). - */ -export interface UserProfileWithSecurity< - D extends UserProfileData = UserProfileData, - L extends UserProfileLabels = UserProfileLabels -> extends UserProfile { - /** - * Information about the user that owns profile. - */ - user: UserProfileUserInfoWithSecurity; - - /** - * User specific _searchable_ labels associated with the profile. Note that labels are considered - * security related field since it's going to be used to store user's space ID. - */ - labels: L; -} - /** * User profile enriched with session information. */ diff --git a/x-pack/plugins/security/common/types.ts b/x-pack/plugins/security/common/types.ts index 65616e58e65b..1fc47aad365d 100644 --- a/x-pack/plugins/security/common/types.ts +++ b/x-pack/plugins/security/common/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AuthenticationProvider } from './model'; +import type { AuthenticationProvider } from '@kbn/security-plugin-types-common'; export interface SessionInfo { expiresInMs: number | null; diff --git a/x-pack/plugins/security/public/account_management/account_management_app.tsx b/x-pack/plugins/security/public/account_management/account_management_app.tsx index a5b98d66d46f..59678a246abe 100644 --- a/x-pack/plugins/security/public/account_management/account_management_app.tsx +++ b/x-pack/plugins/security/public/account_management/account_management_app.tsx @@ -26,10 +26,10 @@ import { KibanaThemeProvider, toMountPoint, } from '@kbn/kibana-react-plugin/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { Router } from '@kbn/shared-ux-router'; import { UserProfilesKibanaProvider } from '@kbn/user-profile-components'; -import type { AuthenticationServiceSetup } from '../authentication'; import type { SecurityApiClients } from '../components'; import { AuthenticationProvider, SecurityApiClientsProvider } from '../components'; import type { BreadcrumbsChangeHandler } from '../components/breadcrumb'; diff --git a/x-pack/plugins/security/public/account_management/index.ts b/x-pack/plugins/security/public/account_management/index.ts index e1a4957aa71e..966de2cb05b8 100644 --- a/x-pack/plugins/security/public/account_management/index.ts +++ b/x-pack/plugins/security/public/account_management/index.ts @@ -7,8 +7,3 @@ export { accountManagementApp } from './account_management_app'; export { UserProfileAPIClient } from './user_profile/user_profile_api_client'; -export type { - UserProfileBulkGetParams, - UserProfileGetCurrentParams, - UserProfileSuggestParams, -} from './user_profile'; diff --git a/x-pack/plugins/security/public/account_management/user_profile/index.ts b/x-pack/plugins/security/public/account_management/user_profile/index.ts index ed34d7d4a433..3ce9e1919040 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/index.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/index.ts @@ -8,8 +8,3 @@ export { UserProfile } from './user_profile'; export type { UserProfileProps, UserProfileFormValues } from './user_profile'; -export type { - UserProfileGetCurrentParams, - UserProfileBulkGetParams, - UserProfileSuggestParams, -} from './user_profile_api_client'; diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx index 782a14700ad5..04ac8cc4fcfe 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.tsx @@ -138,7 +138,7 @@ const UserDetailsEditor: FunctionComponent = ({ user }) labelAppend={} fullWidth > - + = ({ user }) labelAppend={} fullWidth > - + ); @@ -189,6 +189,7 @@ const UserSettingsEditor: FunctionComponent = ({ = ({ user, data }) {formChanges.count > 0 ? ( - + ) : null} @@ -974,6 +979,7 @@ export const SaveChangesBottomBar: FunctionComponent = () => { 0 && !formik.isValid} color="success" diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts index 4760aa15ab0b..597b93236a2a 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts @@ -10,60 +10,17 @@ import type { Observable } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs'; import type { HttpStart } from '@kbn/core/public'; +import type { + UserProfileAPIClient as UserProfileAPIClientType, + UserProfileBulkGetParams, + UserProfileGetCurrentParams, + UserProfileSuggestParams, +} from '@kbn/security-plugin-types-public'; import type { UserProfileData } from '@kbn/user-profile-components'; import type { GetUserProfileResponse, UserProfile } from '../../../common'; -/** - * Parameters for the get user profile for the current user API. - */ -export interface UserProfileGetCurrentParams { - /** - * By default, get API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath: string; -} - -/** - * Parameters for the bulk get API. - */ -export interface UserProfileBulkGetParams { - /** - * List of user profile identifiers. - */ - uids: Set; - - /** - * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath?: string; -} - -/** - * Parameters for the suggest API. - */ -export interface UserProfileSuggestParams { - /** - * Query string used to match name-related fields in user profiles. The following fields are treated as - * name-related: username, full_name and email. - */ - name: string; - - /** - * Desired number of suggestions to return. The default value is 10. - */ - size?: number; - - /** - * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath?: string; -} - -export class UserProfileAPIClient { +export class UserProfileAPIClient implements UserProfileAPIClientType { private readonly internalDataUpdates$: Subject = new Subject(); /** diff --git a/x-pack/plugins/security/public/analytics/analytics_service.ts b/x-pack/plugins/security/public/analytics/analytics_service.ts index 33a72f24c487..8d4e173246ff 100644 --- a/x-pack/plugins/security/public/analytics/analytics_service.ts +++ b/x-pack/plugins/security/public/analytics/analytics_service.ts @@ -14,9 +14,9 @@ import type { HttpSetup, HttpStart, } from '@kbn/core/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { registerUserContext } from './register_user_context'; -import type { AuthenticationServiceSetup } from '..'; import type { SecurityLicense } from '../../common'; interface AnalyticsServiceSetupParams { diff --git a/x-pack/plugins/security/public/analytics/register_user_context.test.ts b/x-pack/plugins/security/public/analytics/register_user_context.test.ts index bc4e0dd09383..8ffbde29bb94 100644 --- a/x-pack/plugins/security/public/analytics/register_user_context.test.ts +++ b/x-pack/plugins/security/public/analytics/register_user_context.test.ts @@ -10,9 +10,9 @@ import { firstValueFrom } from 'rxjs'; import type { AnalyticsServiceSetup } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import { Sha256 } from '@kbn/crypto-browser'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { registerUserContext } from './register_user_context'; -import type { AuthenticationServiceSetup } from '..'; import { authenticationMock } from '../authentication/index.mock'; import { securityMock } from '../mocks'; diff --git a/x-pack/plugins/security/public/analytics/register_user_context.ts b/x-pack/plugins/security/public/analytics/register_user_context.ts index 19ecf0a6896f..e4464df8196a 100644 --- a/x-pack/plugins/security/public/analytics/register_user_context.ts +++ b/x-pack/plugins/security/public/analytics/register_user_context.ts @@ -9,8 +9,7 @@ import { catchError, from, map, of } from 'rxjs'; import type { AnalyticsServiceSetup } from '@kbn/core/public'; import { Sha256 } from '@kbn/crypto-browser'; - -import type { AuthenticationServiceSetup } from '..'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; interface UserIdContext { userId?: string; diff --git a/x-pack/plugins/security/public/authentication/authentication_service.ts b/x-pack/plugins/security/public/authentication/authentication_service.ts index 62c60587282e..dcc0588e4bf3 100644 --- a/x-pack/plugins/security/public/authentication/authentication_service.ts +++ b/x-pack/plugins/security/public/authentication/authentication_service.ts @@ -11,6 +11,7 @@ import type { HttpSetup, StartServicesAccessor, } from '@kbn/core/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { accessAgreementApp } from './access_agreement'; import { captureURLApp } from './capture_url'; @@ -18,7 +19,7 @@ import { loggedOutApp } from './logged_out'; import { loginApp } from './login'; import { logoutApp } from './logout'; import { overwrittenSessionApp } from './overwritten_session'; -import type { AuthenticatedUser } from '../../common/model'; +import type { AuthenticatedUser } from '../../common'; import type { ConfigType } from '../config'; import type { PluginStartDependencies } from '../plugin'; @@ -29,24 +30,6 @@ interface SetupParams { http: HttpSetup; getStartServices: StartServicesAccessor; } - -export interface AuthenticationServiceSetup { - /** - * Returns currently authenticated user and throws if current user isn't authenticated. - */ - getCurrentUser: () => Promise; - - /** - * Determines if API Keys are currently enabled. - */ - areAPIKeysEnabled: () => Promise; -} - -/** - * Start has the same contract as Setup for now. - */ -export type AuthenticationServiceStart = AuthenticationServiceSetup; - export class AuthenticationService { public setup({ application, diff --git a/x-pack/plugins/security/public/authentication/index.mock.ts b/x-pack/plugins/security/public/authentication/index.mock.ts index 092126e6cfee..cc1c098eb679 100644 --- a/x-pack/plugins/security/public/authentication/index.mock.ts +++ b/x-pack/plugins/security/public/authentication/index.mock.ts @@ -8,7 +8,7 @@ import type { AuthenticationServiceSetup, AuthenticationServiceStart, -} from './authentication_service'; +} from '@kbn/security-plugin-types-public'; export const authenticationMock = { createSetup: (): jest.Mocked => ({ diff --git a/x-pack/plugins/security/public/authentication/index.ts b/x-pack/plugins/security/public/authentication/index.ts index dd7cb006d879..701da42cf120 100644 --- a/x-pack/plugins/security/public/authentication/index.ts +++ b/x-pack/plugins/security/public/authentication/index.ts @@ -5,8 +5,4 @@ * 2.0. */ -export type { - AuthenticationServiceSetup, - AuthenticationServiceStart, -} from './authentication_service'; export { AuthenticationService } from './authentication_service'; diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts index ccd8377cbdd4..b0f3f1059dfb 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts @@ -7,8 +7,7 @@ import type { ApplicationSetup, AppMountParameters, StartServicesAccessor } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; - -import type { AuthenticationServiceSetup } from '../authentication_service'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx index 4720a829674e..6f39a2608e1c 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx @@ -12,9 +12,9 @@ import ReactDOM from 'react-dom'; import type { AppMountParameters, CoreStart, IBasePath } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { parseNext } from '../../../common/parse_next'; -import type { AuthenticationServiceSetup } from '../authentication_service'; import { AuthenticationStatePage } from '../components'; interface Props { diff --git a/x-pack/plugins/security/public/components/use_current_user.ts b/x-pack/plugins/security/public/components/use_current_user.ts index 924853fa8d86..fc86aa459f2f 100644 --- a/x-pack/plugins/security/public/components/use_current_user.ts +++ b/x-pack/plugins/security/public/components/use_current_user.ts @@ -9,9 +9,10 @@ import constate from 'constate'; import useAsync from 'react-use/lib/useAsync'; import useObservable from 'react-use/lib/useObservable'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; + import { useSecurityApiClients } from '.'; import type { UserProfileData } from '../../common'; -import type { AuthenticationServiceSetup } from '../authentication'; export interface AuthenticationProviderProps { authc: AuthenticationServiceSetup; diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index 209bc5ff576b..419042c4a288 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -6,29 +6,31 @@ */ import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; +import type { SecurityPluginSetup } from '@kbn/security-plugin-types-public'; import type { PluginSetupDependencies, PluginStartDependencies, - SecurityPluginSetup, SecurityPluginStart, } from './plugin'; import { SecurityPlugin } from './plugin'; -export type { SecurityPluginSetup, SecurityPluginStart }; -export type { AuthenticatedUser } from '../common/model'; -export type { SecurityLicense, SecurityLicenseFeatures } from '../common/licensing'; +export type { SecurityPluginStart, SecurityPluginSetup }; +export type { AuthenticatedUser, SecurityLicenseFeatures, SecurityLicense } from '../common'; export type { UiApi, ChangePasswordProps, PersonalInfoProps } from './ui_api'; -export type { UserMenuLink, SecurityNavControlServiceStart } from './nav_control'; + +export { ALL_SPACES_ID } from '../common/constants'; + +// Re-export types from the plugin directly to enhance the developer experience for consumers of the Security plugin. export type { + AuthenticationServiceStart, + AuthenticationServiceSetup, + SecurityNavControlServiceStart, + UserMenuLink, UserProfileBulkGetParams, UserProfileGetCurrentParams, UserProfileSuggestParams, -} from './account_management'; - -export type { AuthenticationServiceStart, AuthenticationServiceSetup } from './authentication'; - -export { ALL_SPACES_ID } from '../common/constants'; +} from '@kbn/security-plugin-types-public'; export const plugin: PluginInitializer< SecurityPluginSetup, diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts index be236b02e4c6..b3d1a3a3e9cb 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts @@ -6,11 +6,10 @@ */ import type { HttpStart } from '@kbn/core/public'; +import type { CreateAPIKeyParams, CreateAPIKeyResult } from '@kbn/security-plugin-types-server'; import type { ApiKeyToInvalidate } from '../../../common/model'; import type { - CreateAPIKeyParams, - CreateAPIKeyResult, GetAPIKeysResult, UpdateAPIKeyParams, UpdateAPIKeyResult, diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx index b1872a459d8b..dd47e7e198bc 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx @@ -38,7 +38,7 @@ import { UserAvatar, UserProfilesPopover } from '@kbn/user-profile-components'; import { ApiKeyFlyout } from './api_key_flyout'; import { ApiKeysEmptyPrompt } from './api_keys_empty_prompt'; import { InvalidateProvider } from './invalidate_provider'; -import type { ApiKey, AuthenticatedUser, RestApiKey } from '../../../../common/model'; +import type { ApiKey, AuthenticatedUser, RestApiKey } from '../../../../common'; import { Breadcrumb } from '../../../components/breadcrumb'; import { SelectableTokenField } from '../../../components/token_field'; import { useCapabilities } from '../../../components/use_capabilities'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx index ac7b067e3371..c15ea9d9e731 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx @@ -16,9 +16,9 @@ import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import type { RegisterManagementAppArgs } from '@kbn/management-plugin/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { Router } from '@kbn/shared-ux-router'; -import type { AuthenticationServiceSetup } from '../../authentication'; import type { BreadcrumbsChangeHandler } from '../../components/breadcrumb'; import { Breadcrumb, diff --git a/x-pack/plugins/security/public/management/management_service.test.ts b/x-pack/plugins/security/public/management/management_service.test.ts index 8591d4d6fd66..d1a21795ffbb 100644 --- a/x-pack/plugins/security/public/management/management_service.test.ts +++ b/x-pack/plugins/security/public/management/management_service.test.ts @@ -21,8 +21,8 @@ import { ManagementService } from './management_service'; import { roleMappingsManagementApp } from './role_mappings'; import { rolesManagementApp } from './roles'; import { usersManagementApp } from './users'; +import type { SecurityLicenseFeatures } from '../../common'; import { licenseMock } from '../../common/licensing/index.mock'; -import type { SecurityLicenseFeatures } from '../../common/licensing/license_features'; import { securityMock } from '../mocks'; const mockSection = createManagementSectionMock(); diff --git a/x-pack/plugins/security/public/management/management_service.ts b/x-pack/plugins/security/public/management/management_service.ts index 616cccd7f5c9..e8fda628c22f 100644 --- a/x-pack/plugins/security/public/management/management_service.ts +++ b/x-pack/plugins/security/public/management/management_service.ts @@ -13,13 +13,13 @@ import type { ManagementSection, ManagementSetup, } from '@kbn/management-plugin/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { apiKeysManagementApp } from './api_keys'; import { roleMappingsManagementApp } from './role_mappings'; import { rolesManagementApp } from './roles'; import { usersManagementApp } from './users'; -import type { SecurityLicense } from '../../common/licensing'; -import type { AuthenticationServiceSetup } from '../authentication'; +import type { SecurityLicense } from '../../common'; import type { PluginStartDependencies } from '../plugin'; export interface ManagementAppConfigType { diff --git a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx index 3eabf885d877..5e329b32c353 100644 --- a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx +++ b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Role } from '../../../common/model'; +import type { Role } from '../../../common'; import { isRoleAdmin, isRoleDeprecated, isRoleReserved, isRoleSystem } from '../../../common/model'; interface Props diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx index ce1b6b0d0efc..535ca02139c3 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx @@ -13,7 +13,7 @@ import { coreMock } from '@kbn/core/public/mocks'; import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import { DeleteProvider } from './delete_provider'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; import { roleMappingsAPIClientMock } from '../../index.mock'; describe('DeleteProvider', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx index c957ad82e63d..1eacafaa54f0 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx @@ -13,7 +13,7 @@ import type { NotificationsStart } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; import type { RoleMappingsAPIClient } from '../../role_mappings_api_client'; interface Props { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx index 017e5ec37a33..8ed7cee87e8c 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx @@ -20,7 +20,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { EditRoleMappingPage } from './edit_role_mapping_page'; import { JSONRuleEditor } from './rule_editor_panel/json_rule_editor'; import { VisualRuleEditor } from './rule_editor_panel/visual_rule_editor'; -import type { Role } from '../../../../common/model'; +import type { Role } from '../../../../common'; import { RoleComboBox } from '../../role_combo_box'; import type { RolesAPIClient } from '../../roles'; import { rolesAPIClientMock } from '../../roles/roles_api_client.mock'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx index 0d4c797a9452..c3dc778643de 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx @@ -26,7 +26,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { MappingInfoPanel } from './mapping_info_panel'; import { RuleEditorPanel } from './rule_editor_panel'; import { validateRoleMappingForSave } from './services/role_mapping_validation'; -import type { RoleMapping } from '../../../../common/model'; +import type { RoleMapping } from '../../../../common'; import type { RolesAPIClient } from '../../roles'; import { DeleteProvider, diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx index 8faf0fa99998..b494b228d8a7 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx @@ -12,7 +12,7 @@ import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { MappingInfoPanel } from './mapping_info_panel'; -import type { Role, RoleMapping } from '../../../../../common/model'; +import type { Role, RoleMapping } from '../../../../../common'; import type { RolesAPIClient } from '../../../roles'; import { rolesAPIClientMock } from '../../../roles/roles_api_client.mock'; import { RoleSelector } from '../role_selector'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx index 07c6b36d1949..9634b8415ae3 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx @@ -25,7 +25,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; import type { RolesAPIClient } from '../../../roles'; import { RoleSelector } from '../role_selector'; import { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx index 219e01512ed2..df0374b04f5a 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx @@ -14,7 +14,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { AddRoleTemplateButton } from './add_role_template_button'; import { RoleSelector } from './role_selector'; import { RoleTemplateEditor } from './role_template_editor'; -import type { Role, RoleMapping } from '../../../../../common/model'; +import type { Role, RoleMapping } from '../../../../../common'; import type { RolesAPIClient } from '../../../roles'; import { rolesAPIClientMock } from '../../../roles/roles_api_client.mock'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx index bf8b68ab7a92..8bc7aa852e2e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx @@ -14,7 +14,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { AddRoleTemplateButton } from './add_role_template_button'; import { RoleTemplateEditor } from './role_template_editor'; -import type { Role, RoleMapping } from '../../../../../common/model'; +import type { Role, RoleMapping } from '../../../../../common'; import { isRoleDeprecated } from '../../../../../common/model'; import { RoleComboBox } from '../../../role_combo_box'; import type { RolesAPIClient } from '../../../roles'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx index 4641e0fe13bd..68d2e81a74a6 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { RoleTemplateTypeSelect } from './role_template_type_select'; -import type { RoleTemplate } from '../../../../../common/model'; +import type { RoleTemplate } from '../../../../../common'; import { isInlineRoleTemplate, isInvalidRoleTemplate, diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx index ae11d2bb889b..964482fa8ee7 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import type { RoleTemplate } from '../../../../../common/model'; +import type { RoleTemplate } from '../../../../../common'; import { isInlineRoleTemplate, isStoredRoleTemplate } from '../services/role_template_type'; const templateTypeOptions = [ diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx index 1a5549ecd1e9..16111e8d535a 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx @@ -27,7 +27,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { JSONRuleEditor } from './json_rule_editor'; import { VisualRuleEditor } from './visual_rule_editor'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; import type { Rule } from '../../model'; import { generateRulesFromRaw } from '../../model'; import { VISUAL_MAX_RULE_DEPTH } from '../services/role_mapping_constants'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts index 7dfa891e8d1b..e1a5ae41a11d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts @@ -12,7 +12,7 @@ import { validateRoleMappingRoleTemplates, validateRoleMappingRules, } from './role_mapping_validation'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; describe('validateRoleMappingName', () => { it('requires a value', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts index 7340277158c8..4c07de0f0782 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; -import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMapping } from '../../../../../common'; import { generateRulesFromRaw } from '../../model'; interface ValidationResult { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts index 50c821541d07..59db5c4fb9d9 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts @@ -10,7 +10,7 @@ import { isInvalidRoleTemplate, isStoredRoleTemplate, } from './role_template_type'; -import type { RoleTemplate } from '../../../../../common/model'; +import type { RoleTemplate } from '../../../../../common'; describe('#isStoredRoleTemplate', () => { it('returns true for stored templates, false otherwise', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts index ce16c2516f17..97f464ce0494 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts @@ -10,7 +10,7 @@ import type { InvalidRoleTemplate, RoleTemplate, StoredRoleTemplate, -} from '../../../../../common/model'; +} from '../../../../../common'; export function isStoredRoleTemplate( roleMappingTemplate: RoleTemplate diff --git a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts index 2db57590042d..f583310156c4 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts @@ -8,7 +8,7 @@ import { FieldRule } from './field_rule'; import { generateRulesFromRaw } from './rule_builder'; import { RuleBuilderError } from './rule_builder_error'; -import type { RoleMapping } from '../../../../common/model'; +import type { RoleMapping } from '../../../../common'; describe('generateRulesFromRaw', () => { it('returns null for an empty rule set', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts index b248f63410a2..88082245decc 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts @@ -15,7 +15,7 @@ import type { FieldRuleValue } from './field_rule'; import { FieldRule } from './field_rule'; import type { Rule } from './rule'; import { RuleBuilderError } from './rule_builder_error'; -import type { RoleMapping } from '../../../../common/model'; +import type { RoleMapping } from '../../../../common'; interface RuleBuilderResult { /** The maximum rule depth within the parsed rule set. */ diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts b/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts index 5465bc24b7e3..bab0222222de 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts @@ -7,7 +7,7 @@ import type { HttpStart } from '@kbn/core/public'; -import type { RoleMapping } from '../../../common/model'; +import type { RoleMapping } from '../../../common'; export interface CheckRoleMappingFeaturesResponse { canManageRoleMappings: boolean; diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx index 0224512cdc21..b5905ec14796 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx @@ -32,7 +32,7 @@ import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { EmptyPrompt } from './empty_prompt'; -import type { Role, RoleMapping } from '../../../../common/model'; +import type { Role, RoleMapping } from '../../../../common'; import { DisabledBadge, EnabledBadge } from '../../badges'; import { EDIT_ROLE_MAPPING_PATH, diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx index 2f0910627be9..8e11a1929ca1 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx @@ -89,7 +89,7 @@ describe('roleMappingsManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Mappings Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":false} + Role Mappings Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":false}
    `); @@ -111,7 +111,7 @@ describe('roleMappingsManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Mappings Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":true} + Role Mappings Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":true}
    `); @@ -136,7 +136,7 @@ describe('roleMappingsManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Mapping Edit Page: {"action":"edit","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}},"readOnly":false} + Role Mapping Edit Page: {"action":"edit","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}},"readOnly":false}
    `); @@ -166,7 +166,7 @@ describe('roleMappingsManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Mapping Edit Page: {"action":"edit","name":"role@mapping","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@mapping","search":"","hash":""}},"readOnly":false} + Role Mapping Edit Page: {"action":"edit","name":"role@mapping","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@mapping","search":"","hash":""}},"readOnly":false}
    `); @@ -197,7 +197,7 @@ describe('roleMappingsManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Mapping Edit Page: {"action":"edit","name":"role@mapping","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@mapping","search":"","hash":""}},"readOnly":true} + Role Mapping Edit Page: {"action":"edit","name":"role@mapping","roleMappingsAPI":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"notifications":{"toasts":{}},"docLinks":{},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@mapping","search":"","hash":""}},"readOnly":true}
    `); diff --git a/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx b/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx index 558461a9b70d..d52f46d467c7 100644 --- a/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx +++ b/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx @@ -10,7 +10,7 @@ import React from 'react'; import type { ApplicationStart } from '@kbn/core/public'; -import type { Role } from '../../../common/model'; +import type { Role } from '../../../common'; import { getExtendedRoleDeprecationNotice, isRoleDeprecated } from '../../../common/model'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts index 1b68f556d599..559d479182c8 100644 --- a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts +++ b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts @@ -9,7 +9,7 @@ import type { KibanaFeature } from '@kbn/features-plugin/public'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import type { LicenseType } from '@kbn/licensing-plugin/server'; -import type { SecurityLicenseFeatures } from '../../../../common/licensing'; +import type { SecurityLicenseFeatures } from '../../../../common'; import { Actions } from '../../../../server/authorization'; import { privilegesFactory } from '../../../../server/authorization/privileges'; import { KibanaPrivileges } from '../model'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx index 2250846ac4a1..e3a1151c2bba 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx @@ -24,8 +24,8 @@ import { EditRolePage } from './edit_role_page'; import { SimplePrivilegeSection } from './privileges/kibana/simple_privilege_section'; import { SpaceAwarePrivilegeSection } from './privileges/kibana/space_aware_privilege_section'; import { TransformErrorSection } from './privileges/kibana/transform_error_section'; +import type { Role } from '../../../../common'; import { licenseMock } from '../../../../common/licensing/index.mock'; -import type { Role } from '../../../../common/model'; import { userAPIClientMock } from '../../users/index.mock'; import { createRawKibanaPrivileges } from '../__fixtures__/kibana_privileges'; import { indicesAPIClientMock, privilegesAPIClientMock, rolesAPIClientMock } from '../index.mock'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx index 8746be6ec908..37b618352043 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx @@ -48,13 +48,13 @@ import { ElasticsearchPrivileges, KibanaPrivilegesRegion } from './privileges'; import { ReservedRoleBadge } from './reserved_role_badge'; import type { RoleValidationResult } from './validate_role'; import { RoleValidator } from './validate_role'; -import type { SecurityLicense } from '../../../../common/licensing'; import type { BuiltinESPrivileges, RawKibanaPrivileges, Role, RoleIndexPrivilege, -} from '../../../../common/model'; + SecurityLicense, +} from '../../../../common'; import { isRoleDeprecated as checkIfRoleDeprecated, isRoleReadOnly as checkIfRoleReadOnly, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts b/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts index 170aa3f6e89f..da912650fee4 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RoleKibanaPrivilege } from '../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../common'; /** * Determines if the passed privilege spec defines global privileges. diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx index 23dcb3673192..81edde34b4d2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ClusterPrivileges } from './cluster_privileges'; -import type { Role } from '../../../../../../common/model'; +import type { Role } from '../../../../../../common'; test('it renders without crashing', () => { const role: Role = { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx index c5463c4458b1..8e8f4aa0a2cb 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx @@ -11,7 +11,7 @@ import React, { Component } from 'react'; import { i18n } from '@kbn/i18n'; -import type { Role } from '../../../../../../common/model'; +import type { Role } from '../../../../../../common'; import { isRoleReadOnly } from '../../../../../../common/model'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx index c389788d7994..99ce69621288 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx @@ -24,8 +24,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { ClusterPrivileges } from './cluster_privileges'; import { IndexPrivileges } from './index_privileges'; -import type { SecurityLicense } from '../../../../../../common/licensing'; -import type { BuiltinESPrivileges, Role } from '../../../../../../common/model'; +import type { BuiltinESPrivileges, Role, SecurityLicense } from '../../../../../../common'; import type { IndicesAPIClient } from '../../../indices_api_client'; import { CollapsiblePanel } from '../../collapsible_panel'; import type { RoleValidator } from '../../validate_role'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx index b43064a7d115..dcfd57f56464 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx @@ -27,7 +27,7 @@ import type { monaco } from '@kbn/monaco'; import type { Cluster } from '@kbn/remote-clusters-plugin/public'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../../../../common/model'; +import type { RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../../../../common'; import type { IndicesAPIClient } from '../../../indices_api_client'; import type { RoleValidator } from '../../validate_role'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx index dafb7bae8ee9..435e094999c2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx @@ -13,8 +13,7 @@ import type { Cluster } from '@kbn/remote-clusters-plugin/public'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { IndexPrivilegeForm } from './index_privilege_form'; -import type { SecurityLicense } from '../../../../../../common/licensing'; -import type { Role, RoleIndexPrivilege } from '../../../../../../common/model'; +import type { Role, RoleIndexPrivilege, SecurityLicense } from '../../../../../../common'; import { isRoleEnabled, isRoleReadOnly } from '../../../../../../common/model'; import type { IndicesAPIClient } from '../../../indices_api_client'; import type { RoleValidator } from '../../validate_role'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index 59418010b114..c487cdab96e2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -13,7 +13,7 @@ import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { getDisplayedFeaturePrivileges } from './__fixtures__'; import { FeatureTable } from './feature_table'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { createFeature, kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index 8d9573383b25..7734d415bf38 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -32,7 +32,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { ChangeAllPrivilegesControl } from './change_all_privileges'; import { FeatureTableExpandedRow } from './feature_table_expanded_row'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import type { KibanaPrivileges, SecuredFeature } from '../../../../model'; import { NO_PRIVILEGE_VALUE } from '../constants'; import { FeatureTableCell } from '../feature_table_cell'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx index 42a08b324436..80da1f409214 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { FeatureTableExpandedRow } from './feature_table_expanded_row'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx index 3047cb0f91f1..53e44aefbf1c 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx @@ -13,7 +13,7 @@ import { KibanaFeature } from '@kbn/features-plugin/public'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { SubFeatureForm } from './sub_feature_form'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { SecuredSubFeature } from '../../../../model'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx index ef6e4ca485d0..b12c4f91a3a7 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx @@ -16,7 +16,7 @@ import { KibanaPrivilegesRegion } from './kibana_privileges_region'; import { SimplePrivilegeSection } from './simple_privilege_section'; import { SpaceAwarePrivilegeSection } from './space_aware_privilege_section'; import { TransformErrorSection } from './transform_error_section'; -import type { Role } from '../../../../../../common/model'; +import type { Role } from '../../../../../../common'; import { KibanaPrivileges } from '../../../model'; import { RoleValidator } from '../../validate_role'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx index e45829d722cb..d7439b19b0d0 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx @@ -13,7 +13,7 @@ import type { Space, SpacesApiUi } from '@kbn/spaces-plugin/public'; import { SimplePrivilegeSection } from './simple_privilege_section'; import { SpaceAwarePrivilegeSection } from './space_aware_privilege_section'; import { TransformErrorSection } from './transform_error_section'; -import type { Role } from '../../../../../../common/model'; +import type { Role } from '../../../../../../common'; import type { KibanaPrivileges } from '../../../model'; import { CollapsiblePanel } from '../../collapsible_panel'; import type { RoleValidator } from '../../validate_role'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts index 901cd14e2403..dc2f03731c65 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts @@ -6,7 +6,7 @@ */ import { PrivilegeFormCalculator } from './privilege_form_calculator'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts index 796cfea92b43..d6afdaf6efaf 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import type { KibanaPrivileges, SubFeaturePrivilegeGroup } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts index f375263c960c..6d9cb86ace18 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts @@ -10,7 +10,7 @@ import type { ReactWrapper } from 'enzyme'; import { findTestSubject } from '@kbn/test-jest-helpers'; -import type { Role, RoleKibanaPrivilege } from '../../../../../../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../../common'; import { FeatureTableCell } from '../../feature_table_cell'; import { PrivilegeSummaryExpandedRow } from '../privilege_summary_expanded_row'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx index 7de3c66f8f4f..9f6aa8ed69ed 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx @@ -15,7 +15,7 @@ import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { PrivilegeSummary } from './privilege_summary'; import { PrivilegeSummaryTable } from './privilege_summary_table'; -import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx index d5a98510b026..5c6d03569b10 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx @@ -20,7 +20,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { Space, SpacesApiUi } from '@kbn/spaces-plugin/public'; import { PrivilegeSummaryTable } from './privilege_summary_table'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import type { KibanaPrivileges } from '../../../../model'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts index 856404408d55..f2869c11f13c 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts @@ -6,7 +6,7 @@ */ import { PrivilegeSummaryCalculator } from './privilege_summary_calculator'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts index 14e2241cdf83..053cd19c98d5 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common'; import type { KibanaPrivileges, PrimaryFeaturePrivilege, SecuredFeature } from '../../../../model'; import type { PrivilegeCollection } from '../../../../model/privilege_collection'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx index 7efe5bc8333f..22ec00d393c9 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx @@ -16,7 +16,7 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { getDisplayedFeaturePrivileges } from './__fixtures__'; import type { PrivilegeSummaryTableProps } from './privilege_summary_table'; import { PrivilegeSummaryTable } from './privilege_summary_table'; -import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../../../../common'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx index 4bddc6bad6fd..7dcbbe85d553 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx @@ -26,8 +26,8 @@ import type { EffectiveFeaturePrivileges } from './privilege_summary_calculator' import { PrivilegeSummaryCalculator } from './privilege_summary_calculator'; import { PrivilegeSummaryExpandedRow } from './privilege_summary_expanded_row'; import { SpaceColumnHeader } from './space_column_header'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common'; import { ALL_SPACES_ID } from '../../../../../../../common/constants'; -import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; import type { KibanaPrivileges, PrimaryFeaturePrivilege, SecuredFeature } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { FeatureTableCell } from '../feature_table_cell'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx index 61a7c024a282..4c1ebbbfffd3 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx @@ -15,7 +15,7 @@ import { getUiApi } from '@kbn/spaces-plugin/public/ui_api'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { SpaceColumnHeader } from './space_column_header'; -import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../../../../common'; import { SpacesPopoverList } from '../../../spaces_popover_list'; const spaces = [ diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx index 99a4cb0020ae..ca4a2d6011c5 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Space, SpacesApiUi } from '@kbn/spaces-plugin/public'; -import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../../../../common'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { SpacesPopoverList } from '../../../spaces_popover_list'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx index 85f8af876dae..e336d7596924 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx @@ -13,7 +13,7 @@ import { mountWithIntl, shallowWithIntl } from '@kbn/test-jest-helpers'; import { SimplePrivilegeSection } from './simple_privilege_section'; import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { KibanaPrivileges, SecuredFeature } from '../../../../model'; const buildProps = (customProps: any = {}) => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx index 786039ce0a23..2e8b395ea07a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx @@ -18,7 +18,7 @@ import React, { Component, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning'; -import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common'; import { copyRole } from '../../../../../../../common/model'; import type { KibanaPrivileges } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx index 4fdeff85fb00..d50ab4716092 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx @@ -13,7 +13,7 @@ import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { PrivilegeSpaceForm } from './privilege_space_form'; import { SpaceSelector } from './space_selector'; -import type { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; import { createFeature, kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { FeatureTable } from '../feature_table'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx index 05327142e210..c3c285a57418 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx @@ -32,8 +32,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { Space } from '@kbn/spaces-plugin/public'; import { SpaceSelector } from './space_selector'; +import type { FeaturesPrivileges, Role } from '../../../../../../../common'; import { ALL_SPACES_ID } from '../../../../../../../common/constants'; -import type { FeaturesPrivileges, Role } from '../../../../../../../common/model'; import { copyRole } from '../../../../../../../common/model'; import type { KibanaPrivileges } from '../../../../model'; import { CUSTOM_PRIVILEGE_VALUE } from '../constants'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx index 5c9220872d9b..6de312d03698 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx @@ -14,7 +14,7 @@ import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { PrivilegeDisplay } from './privilege_display'; import { PrivilegeSpaceTable } from './privilege_space_table'; -import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx index adfc8100aeb9..cbbbc96863bd 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx @@ -26,7 +26,7 @@ import type { Space } from '@kbn/spaces-plugin/public'; import { getSpaceColor } from '@kbn/spaces-plugin/public'; import { PrivilegeDisplay } from './privilege_display'; -import type { FeaturesPrivileges, Role } from '../../../../../../../common/model'; +import type { FeaturesPrivileges, Role } from '../../../../../../../common'; import { copyRole } from '../../../../../../../common/model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { CUSTOM_PRIVILEGE_VALUE } from '../constants'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx index 203156916957..1de6a8a952a5 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx @@ -24,8 +24,8 @@ import type { Space, SpacesApiUi } from '@kbn/spaces-plugin/public'; import { PrivilegeSpaceForm } from './privilege_space_form'; import { PrivilegeSpaceTable } from './privilege_space_table'; -import type { Role } from '../../../../../../../common/model'; -import { isRoleReserved } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common'; +import { isRoleReserved } from '../../../../../../../common'; import type { KibanaPrivileges } from '../../../../model'; import type { RoleValidator } from '../../../validate_role'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx index ac3c36c510bc..2b6efe0f0ab5 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx @@ -10,7 +10,7 @@ import { shallow } from 'enzyme'; import React from 'react'; import { ReservedRoleBadge } from './reserved_role_badge'; -import type { Role } from '../../../../common/model'; +import type { Role } from '../../../../common'; const reservedRole: Role = { name: '', diff --git a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx index 2eec303c8dc5..8f79bd2a5788 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx @@ -10,8 +10,8 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Role } from '../../../../common/model'; -import { isRoleReserved } from '../../../../common/model'; +import type { Role } from '../../../../common'; +import { isRoleReserved } from '../../../../common'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts index f2f2f9a10e52..f1acb67fef92 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts @@ -6,7 +6,7 @@ */ import { RoleValidator } from './validate_role'; -import type { Role } from '../../../../common/model'; +import type { Role } from '../../../../common'; let validator: RoleValidator; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts index ee3e85959e31..18728994a5e4 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts @@ -7,8 +7,8 @@ import { i18n } from '@kbn/i18n'; +import type { Role, RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../../common'; import { MAX_NAME_LENGTH, NAME_REGEX } from '../../../../common/constants'; -import type { Role, RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../../common/model'; interface RoleValidatorOptions { shouldValidate?: boolean; diff --git a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts index 5baaf7d08055..494f5a14b1e4 100644 --- a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts +++ b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts @@ -7,7 +7,7 @@ import { KibanaPrivilege } from './kibana_privilege'; import { KibanaPrivileges } from './kibana_privileges'; -import type { RoleKibanaPrivilege } from '../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../common'; import { kibanaFeatures } from '../__fixtures__/kibana_features'; import { createRawKibanaPrivileges } from '../__fixtures__/kibana_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts index 7e5151d6d67a..78b312c123a3 100644 --- a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts +++ b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts @@ -10,7 +10,7 @@ import type { KibanaFeature } from '@kbn/features-plugin/common'; import { KibanaPrivilege } from './kibana_privilege'; import { PrivilegeCollection } from './privilege_collection'; import { SecuredFeature } from './secured_feature'; -import type { RawKibanaPrivileges, RoleKibanaPrivilege } from '../../../../common/model'; +import type { RawKibanaPrivileges, RoleKibanaPrivilege } from '../../../../common'; import { isGlobalPrivilegeDefinition } from '../edit_role/privilege_utils'; function toBasePrivilege(entry: [string, string[]]): [string, KibanaPrivilege] { diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts index ac30132df8a8..e7f4839e56c5 100644 --- a/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts +++ b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts @@ -8,7 +8,7 @@ import { httpServiceMock } from '@kbn/core/public/mocks'; import { RolesAPIClient } from './roles_api_client'; -import type { Role } from '../../../common/model'; +import type { Role } from '../../../common'; describe('RolesAPIClient', () => { async function saveRole(role: Role) { diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.ts index 6d59976a82ad..3742569e9cc7 100644 --- a/x-pack/plugins/security/public/management/roles/roles_api_client.ts +++ b/x-pack/plugins/security/public/management/roles/roles_api_client.ts @@ -7,7 +7,7 @@ import type { HttpStart } from '@kbn/core/public'; -import type { Role, RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../common/model'; +import type { Role, RoleIndexPrivilege, RoleRemoteIndexPrivilege } from '../../../common'; import { copyRole } from '../../../common/model'; export class RolesAPIClient { diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx index 4c6962585976..6a6433038d63 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx @@ -30,7 +30,7 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import { ConfirmDelete } from './confirm_delete'; import { PermissionDenied } from './permission_denied'; -import type { Role } from '../../../../common/model'; +import type { Role } from '../../../../common'; import { getExtendedRoleDeprecationNotice, isRoleDeprecated, diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx index 5e9d5fcc5635..300f5e195b51 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx @@ -90,7 +90,7 @@ describe('rolesManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Roles Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":false} + Roles Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/","search":"","hash":""}},"readOnly":false}
    `); @@ -112,7 +112,7 @@ describe('rolesManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}} + Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}}
    `); @@ -139,7 +139,7 @@ describe('rolesManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Edit Page: {"action":"edit","roleName":"role@name","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@name","search":"","hash":""}}} + Role Edit Page: {"action":"edit","roleName":"role@name","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@name","search":"","hash":""}}}
    `); @@ -166,7 +166,7 @@ describe('rolesManagementApp', () => { expect(docTitle.reset).not.toHaveBeenCalled(); expect(container).toMatchInlineSnapshot(`
    - Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/clone/someRoleName","search":"","hash":""}}} + Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}}},"http":{"basePath":{"basePath":"","serverBasePath":"","assetsHrefBase":""},"anonymousPaths":{},"externalUrl":{},"staticAssets":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{},"roles":{"save":true}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/clone/someRoleName","search":"","hash":""}}}
    `); diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx index 52e86272fd50..a77586cdad59 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx @@ -15,7 +15,7 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl import type { RegisterManagementAppArgs } from '@kbn/management-plugin/public'; import { Route, Router } from '@kbn/shared-ux-router'; -import type { SecurityLicense } from '../../../common/licensing'; +import type { SecurityLicense } from '../../../common'; import { Breadcrumb, BreadcrumbsProvider, diff --git a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx index 4ab78b64bf9a..07a80d5c4633 100644 --- a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx +++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx @@ -13,7 +13,7 @@ import { coreMock } from '@kbn/core/public/mocks'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { ChangePasswordForm } from './change_password_form'; -import type { User } from '../../../../../common/model'; +import type { User } from '../../../../../common'; import { userAPIClientMock } from '../../index.mock'; function getCurrentPasswordField(wrapper: ReactWrapper) { diff --git a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx index d30eabc7f35e..c1bd329d349c 100644 --- a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx +++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx @@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { User } from '../../../../../common/model'; +import type { User } from '../../../../../common'; import type { UserAPIClient } from '../../user_api_client'; interface Props { diff --git a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx index 41c29ab77386..226ed7bc3345 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx @@ -27,8 +27,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { Role, User } from '../../../../common'; import { MAX_NAME_LENGTH, NAME_REGEX } from '../../../../common/constants'; -import type { Role, User } from '../../../../common/model'; import { isRoleDeprecated } from '../../../../common/model'; import { DocLink } from '../../../components/doc_link'; import type { ValidationErrors } from '../../../components/use_form'; diff --git a/x-pack/plugins/security/public/management/users/user_api_client.ts b/x-pack/plugins/security/public/management/users/user_api_client.ts index 071aa9e95171..1b3e8a986671 100644 --- a/x-pack/plugins/security/public/management/users/user_api_client.ts +++ b/x-pack/plugins/security/public/management/users/user_api_client.ts @@ -7,7 +7,7 @@ import type { HttpStart } from '@kbn/core/public'; -import type { EditUser, User } from '../../../common/model'; +import type { EditUser, User } from '../../../common'; const usersUrl = '/internal/security/users'; diff --git a/x-pack/plugins/security/public/management/users/user_utils.test.ts b/x-pack/plugins/security/public/management/users/user_utils.test.ts index a2d3fddf7725..00164b323ba7 100644 --- a/x-pack/plugins/security/public/management/users/user_utils.test.ts +++ b/x-pack/plugins/security/public/management/users/user_utils.test.ts @@ -6,7 +6,7 @@ */ import { getExtendedUserDeprecationNotice, isUserDeprecated, isUserReserved } from './user_utils'; -import type { User } from '../../../common/model'; +import type { User } from '../../../common'; describe('#isUserReserved', () => { it('returns false for a user with no metadata', () => { diff --git a/x-pack/plugins/security/public/management/users/user_utils.ts b/x-pack/plugins/security/public/management/users/user_utils.ts index bc7da560efcc..91a8f58439f6 100644 --- a/x-pack/plugins/security/public/management/users/user_utils.ts +++ b/x-pack/plugins/security/public/management/users/user_utils.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; -import type { User } from '../../../common/model'; +import type { User } from '../../../common'; export const isUserReserved = (user: User) => user.metadata?._reserved ?? false; diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx index dd7b68566a19..c384b133db61 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx @@ -15,7 +15,7 @@ import { coreMock, scopedHistoryMock } from '@kbn/core/public/mocks'; import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import { UsersGridPage } from './users_grid_page'; -import type { User } from '../../../../common/model'; +import type { User } from '../../../../common'; import { rolesAPIClientMock } from '../../roles/index.mock'; import { userAPIClientMock } from '../index.mock'; diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx index 35d54d437d76..071de4204670 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx @@ -26,7 +26,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { Role, User } from '../../../../common/model'; +import type { Role, User } from '../../../../common'; import { DeprecatedBadge, DisabledBadge, ReservedBadge } from '../../badges'; import { RoleTableDisplay } from '../../role_table_display'; import type { RolesAPIClient } from '../../roles'; diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index c44ff5e5ceb9..ffb7d1e5618d 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -17,9 +17,9 @@ import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import type { RegisterManagementAppArgs } from '@kbn/management-plugin/public'; +import type { AuthenticationServiceSetup } from '@kbn/security-plugin-types-public'; import { Route, Router, Routes } from '@kbn/shared-ux-router'; -import type { AuthenticationServiceSetup } from '../../authentication'; import type { BreadcrumbsChangeHandler } from '../../components/breadcrumb'; import { Breadcrumb, diff --git a/x-pack/plugins/security/public/nav_control/index.mock.ts b/x-pack/plugins/security/public/nav_control/index.mock.ts index 769007d0bc0c..2ca7212c49b8 100644 --- a/x-pack/plugins/security/public/nav_control/index.mock.ts +++ b/x-pack/plugins/security/public/nav_control/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { SecurityNavControlServiceStart } from './nav_control_service'; +import type { SecurityNavControlServiceStart } from '@kbn/security-plugin-types-public'; export const navControlServiceMock = { createStart: (): jest.Mocked => ({ diff --git a/x-pack/plugins/security/public/nav_control/index.ts b/x-pack/plugins/security/public/nav_control/index.ts index 95331b750407..c008a8f15d1f 100644 --- a/x-pack/plugins/security/public/nav_control/index.ts +++ b/x-pack/plugins/security/public/nav_control/index.ts @@ -5,6 +5,4 @@ * 2.0. */ -export type { SecurityNavControlServiceStart } from './nav_control_service'; export { SecurityNavControlService } from './nav_control_service'; -export type { UserMenuLink } from './nav_control_component'; diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx index b2f05f9c6d56..c043f837845d 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import type { EuiContextMenuPanelItemDescriptor, IconType } from '@elastic/eui'; +import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import { EuiContextMenu, EuiContextMenuItem, @@ -23,21 +23,12 @@ import type { Observable } from 'rxjs'; import type { BuildFlavor } from '@kbn/config/src/types'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { UserMenuLink } from '@kbn/security-plugin-types-public'; import { UserAvatar, type UserProfileAvatarData } from '@kbn/user-profile-components'; import { getUserDisplayName, isUserAnonymous } from '../../common/model'; import { useCurrentUser, useUserProfile } from '../components'; -export interface UserMenuLink { - label: string; - iconType: IconType; - href: string; - order?: number; - setAsProfile?: boolean; - /** Render a custom ReactNode instead of the default */ - content?: ReactNode; -} - type ContextMenuItem = EuiContextMenuPanelItemDescriptor & { content?: ReactNode }; interface ContextMenuProps { diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx index 0bcc3a58263f..bfea42ca97e9 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx @@ -17,12 +17,15 @@ import type { BuildFlavor } from '@kbn/config/src/types'; import type { CoreStart, CoreTheme } from '@kbn/core/public'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import type { + AuthenticationServiceSetup, + SecurityNavControlServiceStart, + UserMenuLink, +} from '@kbn/security-plugin-types-public'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; -import type { UserMenuLink } from './nav_control_component'; import { SecurityNavControl } from './nav_control_component'; -import type { SecurityLicense } from '../../common/licensing'; -import type { AuthenticationServiceSetup } from '../authentication'; +import type { SecurityLicense } from '../../common'; import type { SecurityApiClients } from '../components'; import { AuthenticationProvider, SecurityApiClientsProvider } from '../components'; @@ -37,18 +40,6 @@ interface StartDeps { authc: AuthenticationServiceSetup; } -export interface SecurityNavControlServiceStart { - /** - * Returns an Observable of the array of user menu links (the links that show up under the user's Avatar in the UI) registered by other plugins - */ - getUserMenuLinks$: () => Observable; - - /** - * Registers the provided user menu links to be displayed in the user menu (the links that show up under the user's Avatar in the UI). - */ - addUserMenuLinks: (newUserMenuLink: UserMenuLink[]) => void; -} - export class SecurityNavControlService { private securityLicense!: SecurityLicense; private logoutUrl!: string; diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx index eb5b2723f9ea..1927ebb21d8e 100644 --- a/x-pack/plugins/security/public/plugin.tsx +++ b/x-pack/plugins/security/public/plugin.tsx @@ -19,25 +19,28 @@ import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; import { i18n } from '@kbn/i18n'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; import type { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; +import type { + AuthenticationServiceSetup, + AuthenticationServiceStart, + SecurityPluginSetup, + SecurityPluginStart as SecurityPluginStartWithoutDeprecatedMembers, +} from '@kbn/security-plugin-types-public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { accountManagementApp, UserProfileAPIClient } from './account_management'; import { AnalyticsService } from './analytics'; import { AnonymousAccessService } from './anonymous_access'; -import type { AuthenticationServiceSetup, AuthenticationServiceStart } from './authentication'; import { AuthenticationService } from './authentication'; import type { SecurityApiClients } from './components'; import type { ConfigType } from './config'; import { ManagementService, UserAPIClient } from './management'; -import type { SecurityNavControlServiceStart } from './nav_control'; import { SecurityNavControlService } from './nav_control'; import { SecurityCheckupService } from './security_checkup'; import { SessionExpired, SessionTimeout, UnauthorizedResponseHttpInterceptor } from './session'; import type { UiApi } from './ui_api'; import { getUiApi } from './ui_api'; import { SecurityLicenseService } from '../common/licensing'; -import type { SecurityLicense } from '../common/licensing'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; @@ -230,34 +233,7 @@ function getLogoutUrl(http: HttpSetup) { return `${http.basePath.serverBasePath}/logout`; } -export interface SecurityPluginSetup { - /** - * Exposes authentication information about the currently logged in user. - */ - authc: AuthenticationServiceSetup; - /** - * Exposes information about the available security features under the current license. - */ - license: SecurityLicense; -} - -export interface SecurityPluginStart { - /** - * Exposes the ability to add custom links to the dropdown menu in the top right, where the user's Avatar is. - */ - navControlService: SecurityNavControlServiceStart; - /** - * Exposes authentication information about the currently logged in user. - */ - authc: AuthenticationServiceStart; - /** - * A set of methods to work with Kibana user profiles. - */ - userProfiles: Pick< - UserProfileAPIClient, - 'getCurrent' | 'bulkGet' | 'suggest' | 'update' | 'userProfile$' - >; - +export interface SecurityPluginStart extends SecurityPluginStartWithoutDeprecatedMembers { /** * Exposes UI components that will be loaded asynchronously. * @deprecated diff --git a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts index 7f3f0d57d449..202d1b2d578c 100644 --- a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts +++ b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts @@ -8,6 +8,7 @@ // @ts-ignore import fetchMock from 'fetch-mock/es5/client'; +import type { HttpSetup } from '@kbn/core/public'; import { applicationServiceMock } from '@kbn/core/public/mocks'; import { setup } from '@kbn/core-test-helpers-http-setup-browser'; @@ -30,7 +31,7 @@ const setupHttp = (basePath: string) => { const { http } = setup((injectedMetadata) => { injectedMetadata.getBasePath.mockReturnValue(basePath); }); - return http; + return http as HttpSetup; }; const tenant = ''; const application = applicationServiceMock.createStartContract(); diff --git a/x-pack/plugins/security/public/ui_api/change_password/change_password.tsx b/x-pack/plugins/security/public/ui_api/change_password/change_password.tsx index 65e98a39407f..1e5fc6ee88b2 100644 --- a/x-pack/plugins/security/public/ui_api/change_password/change_password.tsx +++ b/x-pack/plugins/security/public/ui_api/change_password/change_password.tsx @@ -12,7 +12,7 @@ import type { NotificationsStart } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { AuthenticatedUser } from '../../../common/model'; +import type { AuthenticatedUser } from '../../../common'; import { canUserChangePassword } from '../../../common/model'; import type { UserAPIClient } from '../../management/users'; import { ChangePasswordForm } from '../../management/users/components/change_password_form'; diff --git a/x-pack/plugins/security/public/ui_api/personal_info/personal_info.tsx b/x-pack/plugins/security/public/ui_api/personal_info/personal_info.tsx index e0d9bb78cf59..339c62232b49 100644 --- a/x-pack/plugins/security/public/ui_api/personal_info/personal_info.tsx +++ b/x-pack/plugins/security/public/ui_api/personal_info/personal_info.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { AuthenticatedUser } from '../../../common/model'; +import type { AuthenticatedUser } from '../../../common'; export interface PersonalInfoProps { user: AuthenticatedUser; diff --git a/x-pack/plugins/security/server/audit/audit_events.ts b/x-pack/plugins/security/server/audit/audit_events.ts index b0edfa991a13..a5e080787e17 100644 --- a/x-pack/plugins/security/server/audit/audit_events.ts +++ b/x-pack/plugins/security/server/audit/audit_events.ts @@ -5,120 +5,17 @@ * 2.0. */ -import type { EcsEvent, KibanaRequest, LogMeta } from '@kbn/core/server'; +import type { EcsEvent, KibanaRequest } from '@kbn/core/server'; +import type { AuditEvent } from '@kbn/security-plugin-types-server'; import type { ArrayElement } from '@kbn/utility-types'; -import type { AuthenticationProvider } from '../../common/model'; +import type { AuthenticationProvider } from '../../common'; import type { AuthenticationResult } from '../authentication/authentication_result'; import type { AuditAction, AddAuditEventParams as SavedObjectEventParams, } from '../saved_objects/saved_objects_security_extension'; -/** - * Audit kibana schema using ECS format - */ -export interface AuditKibana { - /** - * The ID of the space associated with this event. - */ - space_id?: string; - /** - * The ID of the user session associated with this event. Each login attempt - * results in a unique session id. - */ - session_id?: string; - /** - * Saved object that was created, changed, deleted or accessed as part of this event. - */ - saved_object?: { - type: string; - id: string; - }; - /** - * Name of authentication provider associated with a login event. - */ - authentication_provider?: string; - /** - * Type of authentication provider associated with a login event. - */ - authentication_type?: string; - /** - * Name of Elasticsearch realm that has authenticated the user. - */ - authentication_realm?: string; - /** - * Name of Elasticsearch realm where the user details were retrieved from. - */ - lookup_realm?: string; - /** - * Set of space IDs that a saved object was shared to. - */ - add_to_spaces?: readonly string[]; - /** - * Set of space IDs that a saved object was removed from. - */ - delete_from_spaces?: readonly string[]; - /** - * Set of space IDs that are not authorized for an action. - */ - unauthorized_spaces?: readonly string[]; - /** - * Set of types that are not authorized for an action. - */ - unauthorized_types?: readonly string[]; -} - -type EcsHttp = Required['http']; -type EcsRequest = Required['request']; - -/** - * Audit request schema using ECS format - */ -export interface AuditRequest extends EcsRequest { - /** - * HTTP request headers - */ - headers?: { - 'x-forwarded-for'?: string; - }; -} - -/** - * Audit http schema using ECS format - */ -export interface AuditHttp extends EcsHttp { - /** - * HTTP request details - */ - request?: AuditRequest; -} - -/** - * Audit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.12/index.html - * - * If you add additional fields to the schema ensure you update the Kibana Filebeat module: - * https://github.com/elastic/beats/tree/master/filebeat/module/kibana - * - * @public - */ -export interface AuditEvent extends LogMeta { - /** - * Log message - */ - message: string; - - /** - * Kibana specific fields - */ - kibana?: AuditKibana; - - /** - * Fields describing an HTTP request - */ - http?: AuditHttp; -} - export interface HttpRequestParams { request: KibanaRequest; } diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index cf90c7222e5a..773d5cdf1b8f 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -16,8 +16,8 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { AuditEvent } from '@kbn/security-plugin-types-server'; -import type { AuditEvent } from './audit_events'; import { AuditService, createLoggingConfig, diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts index 12180808ae47..89e0efa4113f 100644 --- a/x-pack/plugins/security/server/audit/audit_service.ts +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -14,80 +14,17 @@ import type { LoggerContextConfigInput, LoggingServiceSetup, } from '@kbn/core/server'; +import type { AuditEvent, AuditLogger, AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import type { AuditEvent } from './audit_events'; import { httpRequestEvent } from './audit_events'; -import type { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../common'; import type { ConfigType } from '../config'; import type { SecurityPluginSetup } from '../plugin'; export const ECS_VERSION = '1.6.0'; export const RECORD_USAGE_INTERVAL = 60 * 60 * 1000; // 1 hour -export interface AuditLogger { - /** - * Logs an {@link AuditEvent} and automatically adds meta data about the - * current user, space and correlation id. - * - * Guidelines around what events should be logged and how they should be - * structured can be found in: `/x-pack/plugins/security/README.md` - * - * @example - * ```typescript - * const auditLogger = securitySetup.audit.asScoped(request); - * auditLogger.log({ - * message: 'User is updating dashboard [id=123]', - * event: { - * action: 'saved_object_update', - * outcome: 'unknown' - * }, - * kibana: { - * saved_object: { type: 'dashboard', id: '123' } - * }, - * }); - * ``` - */ - log: (event: AuditEvent | undefined) => void; - - /** - * Indicates whether audit logging is enabled or not. - * - * Useful for skipping resource-intense operations that don't need to be performed when audit - * logging is disabled. - */ - readonly enabled: boolean; -} - -export interface AuditServiceSetup { - /** - * Creates an {@link AuditLogger} scoped to the current request. - * - * This audit logger logs events with all required user and session info and should be used for - * all user-initiated actions. - * - * @example - * ```typescript - * const auditLogger = securitySetup.audit.asScoped(request); - * auditLogger.log(event); - * ``` - */ - asScoped: (request: KibanaRequest) => AuditLogger; - - /** - * {@link AuditLogger} for background tasks only. - * - * This audit logger logs events without any user or session info and should never be used to log - * user-initiated actions. - * - * @example - * ```typescript - * securitySetup.audit.withoutRequest.log(event); - * ``` - */ - withoutRequest: AuditLogger; -} - interface AuditServiceSetupParams { license: SecurityLicense; config: ConfigType['audit']; diff --git a/x-pack/plugins/security/server/audit/index.ts b/x-pack/plugins/security/server/audit/index.ts index c21a9625ca6c..5755f9b55e9a 100644 --- a/x-pack/plugins/security/server/audit/index.ts +++ b/x-pack/plugins/security/server/audit/index.ts @@ -5,9 +5,7 @@ * 2.0. */ -export type { AuditServiceSetup, AuditLogger } from './audit_service'; export { AuditService } from './audit_service'; -export type { AuditEvent, AuditHttp, AuditKibana, AuditRequest } from './audit_events'; export { userLoginEvent, userLogoutEvent, diff --git a/x-pack/plugins/security/server/audit/mocks.ts b/x-pack/plugins/security/server/audit/mocks.ts index 6485818e7fc5..3544f098ece5 100644 --- a/x-pack/plugins/security/server/audit/mocks.ts +++ b/x-pack/plugins/security/server/audit/mocks.ts @@ -5,7 +5,9 @@ * 2.0. */ -import type { AuditLogger, AuditService } from './audit_service'; +import type { AuditLogger } from '@kbn/security-plugin-types-server'; + +import type { AuditService } from './audit_service'; export const auditLoggerMock = { create() { diff --git a/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts b/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts index da411cf5d8c9..8f0e58acf75a 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts @@ -16,8 +16,8 @@ import { import type { Logger } from '@kbn/logging'; import { APIKeys } from './api_keys'; +import type { SecurityLicense } from '../../../common'; import { ALL_SPACES_ID } from '../../../common/constants'; -import type { SecurityLicense } from '../../../common/licensing'; import { licenseMock } from '../../../common/licensing/index.mock'; const encodeToBase64 = (str: string) => Buffer.from(str).toString('base64'); diff --git a/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts b/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts index 4f3f802d576f..75f6d894e65e 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts @@ -9,33 +9,28 @@ import type { IClusterClient, KibanaRequest, Logger } from '@kbn/core/server'; import type { KibanaFeature } from '@kbn/features-plugin/server'; - -import { getFakeKibanaRequest } from './fake_kibana_request'; -import type { SecurityLicense } from '../../../common/licensing'; -import { transformPrivilegesToElasticsearchPrivileges, validateKibanaPrivileges } from '../../lib'; import type { + APIKeys as APIKeysType, CreateAPIKeyParams, CreateAPIKeyResult, - CreateCrossClusterAPIKeyParams, CreateRestAPIKeyParams, CreateRestAPIKeyWithKibanaPrivilegesParams, - UpdateAPIKeyParams, - UpdateAPIKeyResult, -} from '../../routes/api_keys'; + GrantAPIKeyResult, + InvalidateAPIKeyResult, + InvalidateAPIKeysParams, + ValidateAPIKeyParams, +} from '@kbn/security-plugin-types-server'; + +import { getFakeKibanaRequest } from './fake_kibana_request'; +import type { SecurityLicense } from '../../../common'; +import { transformPrivilegesToElasticsearchPrivileges, validateKibanaPrivileges } from '../../lib'; +import type { UpdateAPIKeyParams, UpdateAPIKeyResult } from '../../routes/api_keys'; import { BasicHTTPAuthorizationHeaderCredentials, HTTPAuthorizationHeader, } from '../http_authentication'; -export type { - CreateAPIKeyParams, - CreateAPIKeyResult, - CreateRestAPIKeyParams, - CreateRestAPIKeyWithKibanaPrivilegesParams, - CreateCrossClusterAPIKeyParams, - UpdateAPIKeyParams, - UpdateAPIKeyResult, -}; +export type { UpdateAPIKeyParams, UpdateAPIKeyResult }; /** * Represents the options to create an APIKey class instance that will be @@ -62,76 +57,10 @@ type GrantAPIKeyParams = access_token: string; }; -/** - * Represents the params for invalidating multiple API keys - */ -export interface InvalidateAPIKeysParams { - ids: string[]; -} - -export interface GrantAPIKeyResult { - /** - * Unique id for this API key - */ - id: string; - /** - * Name for this API key - */ - name: string; - /** - * Generated API key - */ - api_key: string; -} - -/** - * The return value when invalidating an API key in Elasticsearch. - */ -export interface InvalidateAPIKeyResult { - /** - * The IDs of the API keys that were invalidated as part of the request. - */ - invalidated_api_keys: string[]; - /** - * The IDs of the API keys that were already invalidated. - */ - previously_invalidated_api_keys: string[]; - /** - * The number of errors that were encountered when invalidating the API keys. - */ - error_count: number; - /** - * Details about these errors. This field is not present in the response when error_count is 0. - */ - error_details?: Array<{ - type?: string; - reason?: string; - caused_by?: { - type?: string; - reason?: string; - }; - }>; -} - -/** - * Represents the parameters for validating API Key credentials. - */ -export interface ValidateAPIKeyParams { - /** - * Unique id for this API key - */ - id: string; - - /** - * Generated API Key (secret) - */ - api_key: string; -} - /** * Class responsible for managing Elasticsearch API keys. */ -export class APIKeys { +export class APIKeys implements APIKeysType { private readonly logger: Logger; private readonly clusterClient: IClusterClient; private readonly license: SecurityLicense; diff --git a/x-pack/plugins/security/server/authentication/api_keys/index.ts b/x-pack/plugins/security/server/authentication/api_keys/index.ts index ae9e9c98c149..8d1aecc01216 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/index.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/index.ts @@ -5,15 +5,4 @@ * 2.0. */ -export type { - CreateAPIKeyParams, - CreateAPIKeyResult, - CreateRestAPIKeyParams, - CreateRestAPIKeyWithKibanaPrivilegesParams, - CreateCrossClusterAPIKeyParams, - InvalidateAPIKeyResult, - InvalidateAPIKeysParams, - ValidateAPIKeyParams, - GrantAPIKeyResult, -} from './api_keys'; export { APIKeys, CreateApiKeyValidationError } from './api_keys'; diff --git a/x-pack/plugins/security/server/authentication/authentication_service.test.ts b/x-pack/plugins/security/server/authentication/authentication_service.test.ts index 4e81f0e4a5f1..a779d30891b8 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.test.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.test.ts @@ -36,6 +36,7 @@ import { } from '@kbn/core/server/mocks'; import { customBrandingServiceMock } from '@kbn/core-custom-branding-server-mocks'; import type { UnauthorizedError } from '@kbn/es-errors'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { AuthenticationResult } from './authentication_result'; @@ -43,7 +44,6 @@ import { AuthenticationService } from './authentication_service'; import type { AuthenticatedUser, SecurityLicense } from '../../common'; import { licenseMock } from '../../common/licensing/index.mock'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; -import type { AuditServiceSetup } from '../audit'; import { auditServiceMock } from '../audit/mocks'; import type { ConfigType } from '../config'; import { ConfigSchema, createConfig } from '../config'; diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index a26ac8943ee7..d6f955b8b455 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -16,6 +16,10 @@ import type { LoggerFactory, } from '@kbn/core/server'; import type { KibanaFeature } from '@kbn/features-plugin/server'; +import type { + AuditServiceSetup, + AuthenticationServiceStart, +} from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { APIKeys } from './api_keys'; @@ -28,7 +32,6 @@ import { renderUnauthenticatedPage } from './unauthenticated_page'; import type { AuthenticatedUser, SecurityLicense } from '../../common'; import { NEXT_URL_QUERY_STRING_PARAMETER } from '../../common/constants'; import { shouldProviderUseLoginForm } from '../../common/model'; -import type { AuditServiceSetup } from '../audit'; import type { ConfigType } from '../config'; import { getDetailedErrorMessage, getErrorStatusCode } from '../errors'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; @@ -78,23 +81,6 @@ export interface InternalAuthenticationServiceStart extends AuthenticationServic getCurrentUser: (request: KibanaRequest) => AuthenticatedUser | null; } -/** - * Authentication services available on the security plugin's start contract. - */ -export interface AuthenticationServiceStart { - apiKeys: Pick< - APIKeys, - | 'areAPIKeysEnabled' - | 'areCrossClusterAPIKeysEnabled' - | 'create' - | 'invalidate' - | 'validate' - | 'grantAsInternalUser' - | 'invalidateAsInternalUser' - >; - getCurrentUser: (request: KibanaRequest) => AuthenticatedUser | null; -} - export class AuthenticationService { private license!: SecurityLicense; private authenticator?: Authenticator; diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index fbc31e588dc5..c2f621538098 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -18,6 +18,7 @@ import { httpServiceMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { AuditLogger } from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { AuthenticationResult } from './authentication_result'; @@ -38,7 +39,6 @@ import { import { licenseMock } from '../../common/licensing/index.mock'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { userProfileMock } from '../../common/model/user_profile.mock'; -import type { AuditLogger } from '../audit'; import { auditLoggerMock, auditServiceMock } from '../audit/mocks'; import { ConfigSchema, createConfig } from '../config'; import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock'; diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts index 032512cc5bf6..b352b13b9774 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.ts @@ -8,6 +8,7 @@ import type { IBasePath, IClusterClient, KibanaRequest, LoggerFactory } from '@kbn/core/server'; import { CoreKibanaRequest } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { AuthenticationResult } from './authentication_result'; @@ -40,7 +41,6 @@ import { SESSION_ERROR_REASON_HEADER, } from '../../common/constants'; import { shouldProviderUseLoginForm } from '../../common/model'; -import type { AuditServiceSetup } from '../audit'; import { accessAgreementAcknowledgedEvent, userLoginEvent, userLogoutEvent } from '../audit'; import type { ConfigType } from '../config'; import { getErrorStatusCode } from '../errors'; diff --git a/x-pack/plugins/security/server/authentication/index.ts b/x-pack/plugins/security/server/authentication/index.ts index e207b316922d..e3dabdae4d46 100644 --- a/x-pack/plugins/security/server/authentication/index.ts +++ b/x-pack/plugins/security/server/authentication/index.ts @@ -6,10 +6,7 @@ */ export { canRedirectRequest } from './can_redirect_request'; -export type { - AuthenticationServiceStart, - InternalAuthenticationServiceStart, -} from './authentication_service'; +export type { InternalAuthenticationServiceStart } from './authentication_service'; export { AuthenticationService } from './authentication_service'; export { AuthenticationResult } from './authentication_result'; export { DeauthenticationResult } from './deauthentication_result'; @@ -27,14 +24,3 @@ export { BasicHTTPAuthorizationHeaderCredentials, HTTPAuthorizationHeader, } from './http_authentication'; -export type { - CreateAPIKeyParams, - CreateAPIKeyResult, - CreateRestAPIKeyParams, - CreateRestAPIKeyWithKibanaPrivilegesParams, - CreateCrossClusterAPIKeyParams, - InvalidateAPIKeyResult, - InvalidateAPIKeysParams, - ValidateAPIKeyParams, - GrantAPIKeyResult, -} from './api_keys'; diff --git a/x-pack/plugins/security/server/authentication/providers/base.ts b/x-pack/plugins/security/server/authentication/providers/base.ts index ccf9ecba71f3..8d491a3446f1 100644 --- a/x-pack/plugins/security/server/authentication/providers/base.ts +++ b/x-pack/plugins/security/server/authentication/providers/base.ts @@ -15,7 +15,7 @@ import type { import { deepFreeze } from '@kbn/std'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { AuthenticatedUser } from '../../../common/model'; +import type { AuthenticatedUser } from '../../../common'; import type { AuthenticationInfo } from '../../elasticsearch'; import { AuthenticationResult } from '../authentication_result'; import type { DeauthenticationResult } from '../deauthentication_result'; diff --git a/x-pack/plugins/security/server/authorization/actions/actions.ts b/x-pack/plugins/security/server/authorization/actions/actions.ts index 073b616c4d77..3b5109c08e3b 100644 --- a/x-pack/plugins/security/server/authorization/actions/actions.ts +++ b/x-pack/plugins/security/server/authorization/actions/actions.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { Actions as ActionsType } from '@kbn/security-plugin-types-server'; + import { AlertingActions } from './alerting'; import { ApiActions } from './api'; import { AppActions } from './app'; @@ -17,7 +19,7 @@ import { UIActions } from './ui'; * application privileges, and are used to perform the authorization checks implemented * by the various `checkPrivilegesWithRequest` derivatives. */ -export class Actions { +export class Actions implements ActionsType { public readonly api: ApiActions; public readonly app: AppActions; public readonly cases: CasesActions; diff --git a/x-pack/plugins/security/server/authorization/actions/alerting.ts b/x-pack/plugins/security/server/authorization/actions/alerting.ts index 9e4b62338c6f..c1de9a1c65d2 100644 --- a/x-pack/plugins/security/server/authorization/actions/alerting.ts +++ b/x-pack/plugins/security/server/authorization/actions/alerting.ts @@ -7,7 +7,9 @@ import { isString } from 'lodash'; -export class AlertingActions { +import type { AlertingActions as AlertingActionsType } from '@kbn/security-plugin-types-server'; + +export class AlertingActions implements AlertingActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/api.ts b/x-pack/plugins/security/server/authorization/actions/api.ts index ac6f88dbff96..fec6296d8f63 100644 --- a/x-pack/plugins/security/server/authorization/actions/api.ts +++ b/x-pack/plugins/security/server/authorization/actions/api.ts @@ -7,7 +7,9 @@ import { isString } from 'lodash'; -export class ApiActions { +import type { ApiActions as ApiActionsType } from '@kbn/security-plugin-types-server'; + +export class ApiActions implements ApiActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/app.ts b/x-pack/plugins/security/server/authorization/actions/app.ts index c18b4f595249..1aa31b1c1a55 100644 --- a/x-pack/plugins/security/server/authorization/actions/app.ts +++ b/x-pack/plugins/security/server/authorization/actions/app.ts @@ -7,7 +7,9 @@ import { isString } from 'lodash'; -export class AppActions { +import type { AppActions as AppActionsType } from '@kbn/security-plugin-types-server'; + +export class AppActions implements AppActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/cases.ts b/x-pack/plugins/security/server/authorization/actions/cases.ts index ced07c03ebf8..8a0b22b92fc1 100644 --- a/x-pack/plugins/security/server/authorization/actions/cases.ts +++ b/x-pack/plugins/security/server/authorization/actions/cases.ts @@ -7,7 +7,9 @@ import { isString } from 'lodash'; -export class CasesActions { +import type { CasesActions as CasesActionsType } from '@kbn/security-plugin-types-server'; + +export class CasesActions implements CasesActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/saved_object.ts b/x-pack/plugins/security/server/authorization/actions/saved_object.ts index 2f7f043d2a47..05eaa95c0e3c 100644 --- a/x-pack/plugins/security/server/authorization/actions/saved_object.ts +++ b/x-pack/plugins/security/server/authorization/actions/saved_object.ts @@ -7,7 +7,9 @@ import { isString } from 'lodash'; -export class SavedObjectActions { +import type { SavedObjectActions as SavedObjectActionsType } from '@kbn/security-plugin-types-server'; + +export class SavedObjectActions implements SavedObjectActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/space.ts b/x-pack/plugins/security/server/authorization/actions/space.ts index 6f5a60e05e02..59cc4e41454a 100644 --- a/x-pack/plugins/security/server/authorization/actions/space.ts +++ b/x-pack/plugins/security/server/authorization/actions/space.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { SpaceActions as SpaceActionsType } from '@kbn/security-plugin-types-server'; -export class SpaceActions { +export class SpaceActions implements SpaceActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/actions/ui.ts b/x-pack/plugins/security/server/authorization/actions/ui.ts index 38af89d143c1..2c9986e1c8ce 100644 --- a/x-pack/plugins/security/server/authorization/actions/ui.ts +++ b/x-pack/plugins/security/server/authorization/actions/ui.ts @@ -9,8 +9,9 @@ import { isString } from 'lodash'; import type { Capabilities as UICapabilities } from '@kbn/core/server'; import { uiCapabilitiesRegex } from '@kbn/features-plugin/server'; +import type { UIActions as UIActionsType } from '@kbn/security-plugin-types-server'; -export class UIActions { +export class UIActions implements UIActionsType { private readonly prefix: string; constructor() { diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts index 2c1bc6a5523f..6956a91d8126 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.ts @@ -6,8 +6,7 @@ */ import type { HttpServiceSetup, Logger } from '@kbn/core/server'; - -import type { AuthorizationServiceSetup } from './authorization_service'; +import type { AuthorizationServiceSetup } from '@kbn/security-plugin-types-server'; export function initAPIAuthorization( http: HttpServiceSetup, diff --git a/x-pack/plugins/security/server/authorization/app_authorization.ts b/x-pack/plugins/security/server/authorization/app_authorization.ts index 08630efc6224..d37d2ec2f37a 100644 --- a/x-pack/plugins/security/server/authorization/app_authorization.ts +++ b/x-pack/plugins/security/server/authorization/app_authorization.ts @@ -7,8 +7,7 @@ import type { HttpServiceSetup, Logger } from '@kbn/core/server'; import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; - -import type { AuthorizationServiceSetup } from './authorization_service'; +import type { AuthorizationServiceSetup } from '@kbn/security-plugin-types-server'; class ProtectedApplications { private applications: Set | null = null; diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx index 10bee6309438..16f2ed3b446e 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.tsx +++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx @@ -25,34 +25,35 @@ import type { PluginSetupContract as FeaturesPluginSetup, PluginStartContract as FeaturesPluginStart, } from '@kbn/features-plugin/server'; +import type { + AuthorizationMode, + AuthorizationServiceSetup, + CheckPrivilegesDynamicallyWithRequest, + CheckSavedObjectsPrivilegesWithRequest, + CheckUserProfilesPrivileges, +} from '@kbn/security-plugin-types-server'; import { Actions } from './actions'; import { initAPIAuthorization } from './api_authorization'; import { initAppAuthorization } from './app_authorization'; import { checkPrivilegesFactory } from './check_privileges'; -import type { CheckPrivilegesDynamicallyWithRequest } from './check_privileges_dynamically'; import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; -import type { CheckSavedObjectsPrivilegesWithRequest } from './check_saved_objects_privileges'; import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; -import type { AuthorizationMode } from './mode'; import { authorizationModeFactory } from './mode'; import type { PrivilegesService } from './privileges'; import { privilegesFactory } from './privileges'; import { registerPrivilegesWithCluster } from './register_privileges_with_cluster'; import { ResetSessionPage } from './reset_session_page'; -import type { CheckPrivilegesWithRequest, CheckUserProfilesPrivileges } from './types'; import { validateFeaturePrivileges } from './validate_feature_privileges'; import { validateReservedPrivileges } from './validate_reserved_privileges'; +import type { AuthenticatedUser, SecurityLicense } from '../../common'; import { APPLICATION_PREFIX } from '../../common/constants'; -import type { SecurityLicense } from '../../common/licensing'; -import type { AuthenticatedUser } from '../../common/model'; import { canRedirectRequest } from '../authentication'; import type { OnlineStatusRetryScheduler } from '../elasticsearch'; import type { SpacesService } from '../plugin'; export { Actions } from './actions'; -export type { CheckSavedObjectsPrivileges } from './check_saved_objects_privileges'; interface AuthorizationServiceSetupParams { packageVersion: string; @@ -88,22 +89,6 @@ export interface AuthorizationServiceSetupInternal extends AuthorizationServiceS privileges: PrivilegesService; } -/** - * Authorization services available on the setup contract of the security plugin. - */ -export interface AuthorizationServiceSetup { - /** - * Actions are used to create the "actions" that are associated with Elasticsearch's - * application privileges, and are used to perform the authorization checks implemented - * by the various `checkPrivilegesWithRequest` derivatives. - */ - actions: Actions; - checkPrivilegesWithRequest: CheckPrivilegesWithRequest; - checkPrivilegesDynamicallyWithRequest: CheckPrivilegesDynamicallyWithRequest; - checkSavedObjectsPrivilegesWithRequest: CheckSavedObjectsPrivilegesWithRequest; - mode: AuthorizationMode; -} - export class AuthorizationService { private logger!: Logger; private applicationName!: string; diff --git a/x-pack/plugins/security/server/authorization/check_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_privileges.test.ts index e339645f76df..c4da8a95ae46 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges.test.ts @@ -8,10 +8,10 @@ import { uniq } from 'lodash'; import { elasticsearchServiceMock, httpServerMock } from '@kbn/core/server/mocks'; +import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; +import type { HasPrivilegesResponse } from '@kbn/security-plugin-types-server'; import { checkPrivilegesFactory } from './check_privileges'; -import type { HasPrivilegesResponse } from './types'; -import { GLOBAL_RESOURCE } from '../../common/constants'; const application = 'kibana-our_application'; diff --git a/x-pack/plugins/security/server/authorization/check_privileges.ts b/x-pack/plugins/security/server/authorization/check_privileges.ts index abc0b791dd49..310b79f36282 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges.ts @@ -9,8 +9,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/types'; import { pick, transform, uniq } from 'lodash'; import type { IClusterClient, KibanaRequest } from '@kbn/core/server'; - -import { ResourceSerializer } from './resource_serializer'; import type { CheckPrivileges, CheckPrivilegesOptions, @@ -21,9 +19,11 @@ import type { CheckUserProfilesPrivilegesResponse, HasPrivilegesResponse, HasPrivilegesResponseApplication, -} from './types'; +} from '@kbn/security-plugin-types-server'; +import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; + +import { ResourceSerializer } from './resource_serializer'; import { validateEsPrivilegeResponse } from './validate_es_response'; -import { GLOBAL_RESOURCE } from '../../common/constants'; interface CheckPrivilegesActions { login: string; diff --git a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts index 2d506a70610d..6b92f6cef748 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts @@ -6,9 +6,9 @@ */ import { httpServerMock } from '@kbn/core/server/mocks'; +import type { CheckPrivilegesOptions } from '@kbn/security-plugin-types-server'; import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; -import type { CheckPrivilegesOptions } from './types'; test(`checkPrivileges.atSpace when spaces is enabled`, async () => { const expectedResult = Symbol(); diff --git a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts index 22c2e53e9ab2..7e84dad2775a 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts @@ -6,23 +6,14 @@ */ import type { KibanaRequest } from '@kbn/core/server'; - import type { + CheckPrivilegesDynamicallyWithRequest, CheckPrivilegesOptions, CheckPrivilegesPayload, - CheckPrivilegesResponse, CheckPrivilegesWithRequest, -} from './types'; -import type { SpacesService } from '../plugin'; +} from '@kbn/security-plugin-types-server'; -export type CheckPrivilegesDynamically = ( - privileges: CheckPrivilegesPayload, - options?: CheckPrivilegesOptions -) => Promise; - -export type CheckPrivilegesDynamicallyWithRequest = ( - request: KibanaRequest -) => CheckPrivilegesDynamically; +import type { SpacesService } from '../plugin'; export function checkPrivilegesDynamicallyWithRequestFactory( checkPrivilegesWithRequest: CheckPrivilegesWithRequest, diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts index 0afcd4118ab8..3072df7d269e 100644 --- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts @@ -6,9 +6,12 @@ */ import { httpServerMock } from '@kbn/core/server/mocks'; +import type { + CheckPrivileges, + CheckPrivilegesWithRequest, +} from '@kbn/security-plugin-types-server'; import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; -import type { CheckPrivileges, CheckPrivilegesWithRequest } from './types'; import type { SpacesService } from '../plugin'; let mockCheckPrivileges: jest.Mocked; diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts index 0afa29fab3c5..2e27197d6c95 100644 --- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts +++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts @@ -6,20 +6,15 @@ */ import type { KibanaRequest } from '@kbn/core/server'; +import type { + CheckPrivilegesWithRequest, + CheckSavedObjectsPrivileges, + CheckSavedObjectsPrivilegesWithRequest, +} from '@kbn/security-plugin-types-server'; -import type { CheckPrivilegesResponse, CheckPrivilegesWithRequest } from './types'; import { ALL_SPACES_ID } from '../../common/constants'; import type { SpacesService } from '../plugin'; -export type CheckSavedObjectsPrivilegesWithRequest = ( - request: KibanaRequest -) => CheckSavedObjectsPrivileges; - -export type CheckSavedObjectsPrivileges = ( - actions: string | string[], - namespaceOrNamespaces?: string | Array -) => Promise; - function uniq(arr: T[]): T[] { return Array.from(new Set(arr)); } diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts index 8f56ba95883b..3d784f6c1cf3 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts @@ -7,12 +7,12 @@ import { httpServerMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { ElasticsearchFeature, KibanaFeature } from '@kbn/features-plugin/server'; +import type { CheckPrivilegesResponse } from '@kbn/security-plugin-types-server'; import { Actions } from './actions'; import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; import { authorizationMock } from './index.mock'; -import type { CheckPrivilegesResponse } from './types'; -import type { AuthenticatedUser } from '../../common/model'; +import type { AuthenticatedUser } from '../../common'; type MockAuthzOptions = | { rejectCheckPrivileges: any } diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts index 7283b955e906..cf2429a1d657 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts @@ -14,11 +14,13 @@ import type { FeatureElasticsearchPrivileges, KibanaFeature, } from '@kbn/features-plugin/server'; +import type { + AuthorizationServiceSetup, + CheckPrivilegesResponse, +} from '@kbn/security-plugin-types-server'; import type { RecursiveReadonly, RecursiveReadonlyArray } from '@kbn/utility-types'; -import type { AuthorizationServiceSetup } from './authorization_service'; -import type { CheckPrivilegesResponse } from './types'; -import type { AuthenticatedUser } from '../../common/model'; +import type { AuthenticatedUser } from '../../common'; export function disableUICapabilitiesFactory( request: KibanaRequest, diff --git a/x-pack/plugins/security/server/authorization/index.mock.ts b/x-pack/plugins/security/server/authorization/index.mock.ts index f66104818ae8..04c389f24fca 100644 --- a/x-pack/plugins/security/server/authorization/index.mock.ts +++ b/x-pack/plugins/security/server/authorization/index.mock.ts @@ -5,8 +5,9 @@ * 2.0. */ +import type { AuthorizationMode } from '@kbn/security-plugin-types-server'; + import { actionsMock } from './actions/actions.mock'; -import type { AuthorizationMode } from './mode'; export const authorizationMock = { create: ({ diff --git a/x-pack/plugins/security/server/authorization/index.ts b/x-pack/plugins/security/server/authorization/index.ts index 9e701e866767..2a93aeb07001 100644 --- a/x-pack/plugins/security/server/authorization/index.ts +++ b/x-pack/plugins/security/server/authorization/index.ts @@ -6,13 +6,8 @@ */ export { Actions } from './actions'; -export type { - AuthorizationServiceSetup, - AuthorizationServiceSetupInternal, -} from './authorization_service'; +export type { AuthorizationServiceSetupInternal } from './authorization_service'; export { AuthorizationService } from './authorization_service'; -export type { CheckSavedObjectsPrivileges } from './check_saved_objects_privileges'; -export type { CheckPrivilegesPayload } from './types'; export type { ElasticsearchRole } from './roles'; export { transformElasticsearchRoleToRole } from './roles'; export type { CasesSupportedOperations } from './privileges'; diff --git a/x-pack/plugins/security/server/authorization/mode.test.ts b/x-pack/plugins/security/server/authorization/mode.test.ts index 2df3d9ab6b5b..f44d023be873 100644 --- a/x-pack/plugins/security/server/authorization/mode.test.ts +++ b/x-pack/plugins/security/server/authorization/mode.test.ts @@ -8,9 +8,8 @@ import { httpServerMock } from '@kbn/core/server/mocks'; import { authorizationModeFactory } from './mode'; -import type { SecurityLicense } from '../../common/licensing'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../common'; import { licenseMock } from '../../common/licensing/index.mock'; -import type { SecurityLicenseFeatures } from '../../common/licensing/license_features'; describe(`#useRbacForRequest`, () => { let mockLicense: jest.Mocked; diff --git a/x-pack/plugins/security/server/authorization/mode.ts b/x-pack/plugins/security/server/authorization/mode.ts index d40d7fba3ca8..722ecd02875e 100644 --- a/x-pack/plugins/security/server/authorization/mode.ts +++ b/x-pack/plugins/security/server/authorization/mode.ts @@ -7,11 +7,7 @@ import type { KibanaRequest } from '@kbn/core/server'; -import type { SecurityLicense } from '../../common/licensing'; - -export interface AuthorizationMode { - useRbacForRequest(request: KibanaRequest): boolean; -} +import type { SecurityLicense } from '../../common'; export function authorizationModeFactory(license: SecurityLicense) { const useRbacForRequestCache = new WeakMap(); diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/__snapshots__/cases.test.ts.snap b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/__snapshots__/cases.test.ts.snap index fc31927e6cfb..1874a17515e1 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/__snapshots__/cases.test.ts.snap +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/__snapshots__/cases.test.ts.snap @@ -5,7 +5,6 @@ Array [ "cases:observability/pushCase", "cases:observability/createCase", "cases:observability/createComment", - "cases:observability/createConfiguration", "cases:observability/getCase", "cases:observability/getComment", "cases:observability/getTags", @@ -14,9 +13,10 @@ Array [ "cases:observability/findConfigurations", "cases:observability/updateCase", "cases:observability/updateComment", - "cases:observability/updateConfiguration", "cases:observability/deleteCase", "cases:observability/deleteComment", + "cases:observability/createConfiguration", + "cases:observability/updateConfiguration", ] `; @@ -24,7 +24,6 @@ exports[`cases feature_privilege_builder within feature grants create privileges Array [ "cases:securitySolution/createCase", "cases:securitySolution/createComment", - "cases:securitySolution/createConfiguration", ] `; @@ -52,10 +51,16 @@ Array [ ] `; +exports[`cases feature_privilege_builder within feature grants settings privileges under feature with id observability 1`] = ` +Array [ + "cases:observability/createConfiguration", + "cases:observability/updateConfiguration", +] +`; + exports[`cases feature_privilege_builder within feature grants update privileges under feature with id observability 1`] = ` Array [ "cases:observability/updateCase", "cases:observability/updateComment", - "cases:observability/updateConfiguration", ] `; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.test.ts index d4d49a5334f1..ad0563ef7a82 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.test.ts @@ -47,6 +47,7 @@ describe(`cases`, () => { ['read', 'observability'], ['update', 'observability'], ['delete', 'securitySolution'], + ['settings', 'observability'], ])('grants %s privileges under feature with id %s', (operation, featureID) => { const actions = new Actions(); const casesFeaturePrivilege = new FeaturePrivilegeCasesBuilder(actions); @@ -55,7 +56,6 @@ describe(`cases`, () => { cases: { [operation]: [featureID], }, - savedObject: { all: [], read: [], @@ -88,8 +88,8 @@ describe(`cases`, () => { update: ['obs'], delete: ['security'], read: ['obs'], + settings: ['security'], }, - savedObject: { all: [], read: [], @@ -113,7 +113,6 @@ describe(`cases`, () => { "cases:security/pushCase", "cases:security/createCase", "cases:security/createComment", - "cases:security/createConfiguration", "cases:security/getCase", "cases:security/getComment", "cases:security/getTags", @@ -122,9 +121,10 @@ describe(`cases`, () => { "cases:security/findConfigurations", "cases:security/updateCase", "cases:security/updateComment", - "cases:security/updateConfiguration", "cases:security/deleteCase", "cases:security/deleteComment", + "cases:security/createConfiguration", + "cases:security/updateConfiguration", "cases:obs/getCase", "cases:obs/getComment", "cases:obs/getTags", @@ -133,7 +133,6 @@ describe(`cases`, () => { "cases:obs/findConfigurations", "cases:obs/updateCase", "cases:obs/updateComment", - "cases:obs/updateConfiguration", ] `); }); @@ -147,7 +146,6 @@ describe(`cases`, () => { all: ['security', 'other-security'], read: ['obs', 'other-obs'], }, - savedObject: { all: [], read: [], @@ -171,7 +169,6 @@ describe(`cases`, () => { "cases:security/pushCase", "cases:security/createCase", "cases:security/createComment", - "cases:security/createConfiguration", "cases:security/getCase", "cases:security/getComment", "cases:security/getTags", @@ -180,13 +177,13 @@ describe(`cases`, () => { "cases:security/findConfigurations", "cases:security/updateCase", "cases:security/updateComment", - "cases:security/updateConfiguration", "cases:security/deleteCase", "cases:security/deleteComment", + "cases:security/createConfiguration", + "cases:security/updateConfiguration", "cases:other-security/pushCase", "cases:other-security/createCase", "cases:other-security/createComment", - "cases:other-security/createConfiguration", "cases:other-security/getCase", "cases:other-security/getComment", "cases:other-security/getTags", @@ -195,9 +192,10 @@ describe(`cases`, () => { "cases:other-security/findConfigurations", "cases:other-security/updateCase", "cases:other-security/updateComment", - "cases:other-security/updateConfiguration", "cases:other-security/deleteCase", "cases:other-security/deleteComment", + "cases:other-security/createConfiguration", + "cases:other-security/updateConfiguration", "cases:obs/getCase", "cases:obs/getComment", "cases:obs/getTags", diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts index 0f442c9d871e..b54ba77777dd 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/cases.ts @@ -13,11 +13,16 @@ import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export type CasesSupportedOperations = typeof allOperations[number]; -// if you add a value here you'll likely also need to make changes here: -// x-pack/plugins/cases/server/authorization/index.ts +/** + * If you add a new operation type (all, push, update, etc) you should also + * extend the mapping here x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts + * + * Also if you add a new operation (createCase, updateCase, etc) here you'll likely also need to make changes here: + * x-pack/plugins/cases/server/authorization/index.ts + */ const pushOperations = ['pushCase'] as const; -const createOperations = ['createCase', 'createComment', 'createConfiguration'] as const; +const createOperations = ['createCase', 'createComment'] as const; const readOperations = [ 'getCase', 'getComment', @@ -26,14 +31,16 @@ const readOperations = [ 'getUserActions', 'findConfigurations', ] as const; -const updateOperations = ['updateCase', 'updateComment', 'updateConfiguration'] as const; +const updateOperations = ['updateCase', 'updateComment'] as const; const deleteOperations = ['deleteCase', 'deleteComment'] as const; +const settingsOperations = ['createConfiguration', 'updateConfiguration'] as const; const allOperations = [ ...pushOperations, ...createOperations, ...readOperations, ...updateOperations, ...deleteOperations, + ...settingsOperations, ] as const; export class FeaturePrivilegeCasesBuilder extends BaseFeaturePrivilegeBuilder { @@ -57,6 +64,7 @@ export class FeaturePrivilegeCasesBuilder extends BaseFeaturePrivilegeBuilder { ...getCasesPrivilege(readOperations, privilegeDefinition.cases?.read), ...getCasesPrivilege(updateOperations, privilegeDefinition.cases?.update), ...getCasesPrivilege(deleteOperations, privilegeDefinition.cases?.delete), + ...getCasesPrivilege(settingsOperations, privilegeDefinition.cases?.settings), ]); } } diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.ts index e3e151052f05..51c61962c946 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.ts @@ -13,7 +13,7 @@ import type { } from '@kbn/features-plugin/server'; import { featurePrivilegeBuilderFactory } from './feature_privilege_builder'; -import type { SecurityLicense } from '../../../common/licensing'; +import type { SecurityLicense } from '../../../common'; import type { RawKibanaPrivileges } from '../../../common/model'; import type { Actions } from '../actions'; diff --git a/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts b/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts index 2febad56d701..6a46072712df 100644 --- a/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts +++ b/x-pack/plugins/security/server/authorization/roles/elasticsearch_role.ts @@ -7,12 +7,10 @@ import type { Logger } from '@kbn/core/server'; import type { KibanaFeature } from '@kbn/features-plugin/common'; +import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; -import { - GLOBAL_RESOURCE, - RESERVED_PRIVILEGES_APPLICATION_WILDCARD, -} from '../../../common/constants'; -import type { Role, RoleKibanaPrivilege } from '../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../common'; +import { RESERVED_PRIVILEGES_APPLICATION_WILDCARD } from '../../../common/constants'; import { getDetailedErrorMessage } from '../../errors'; import { PrivilegeSerializer } from '../privilege_serializer'; import { ResourceSerializer } from '../resource_serializer'; diff --git a/x-pack/plugins/security/server/authorization/validate_es_response.ts b/x-pack/plugins/security/server/authorization/validate_es_response.ts index 52b1777269f3..3eff39aedf14 100644 --- a/x-pack/plugins/security/server/authorization/validate_es_response.ts +++ b/x-pack/plugins/security/server/authorization/validate_es_response.ts @@ -6,8 +6,7 @@ */ import { schema } from '@kbn/config-schema'; - -import type { HasPrivilegesResponse } from './types'; +import type { HasPrivilegesResponse } from '@kbn/security-plugin-types-server'; const baseResponseSchema = schema.object({ username: schema.string(), diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index a5483b4e70ba..68e1c7c2a096 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -16,7 +16,7 @@ import { config as coreConfig } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; import { getLogsPath } from '@kbn/utils'; -import type { AuthenticationProvider } from '../common/model'; +import type { AuthenticationProvider } from '../common'; export type ConfigType = ReturnType; type RawConfigType = TypeOf; diff --git a/x-pack/plugins/security/server/deprecations/privilege_deprecations.ts b/x-pack/plugins/security/server/deprecations/privilege_deprecations.ts index c85f6b239d32..8075c258f323 100644 --- a/x-pack/plugins/security/server/deprecations/privilege_deprecations.ts +++ b/x-pack/plugins/security/server/deprecations/privilege_deprecations.ts @@ -8,12 +8,12 @@ import type { Logger } from '@kbn/core/server'; import type { KibanaFeature } from '@kbn/features-plugin/common'; import { i18n } from '@kbn/i18n'; - -import type { SecurityLicense } from '../../common/licensing'; import type { PrivilegeDeprecationsRolesByFeatureIdRequest, PrivilegeDeprecationsRolesByFeatureIdResponse, -} from '../../common/model'; +} from '@kbn/security-plugin-types-server'; + +import type { SecurityLicense } from '../../common'; import { transformElasticsearchRoleToRole } from '../authorization'; import type { AuthorizationServiceSetupInternal } from '../authorization'; import { getDetailedErrorMessage, getErrorStatusCode } from '../errors'; diff --git a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts index 1d9985fbc865..1dd56fdffec8 100644 --- a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts +++ b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts @@ -13,7 +13,7 @@ import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { nextTick } from '@kbn/test-jest-helpers'; import { ElasticsearchService } from './elasticsearch_service'; -import type { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../common'; import { licenseMock } from '../../common/licensing/index.mock'; describe('ElasticsearchService', () => { diff --git a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts index 88fe5caf2cac..2bc8a643275c 100644 --- a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts +++ b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts @@ -12,7 +12,7 @@ import { distinctUntilChanged, filter, map, shareReplay, tap } from 'rxjs/operat import type { Logger, StatusServiceSetup } from '@kbn/core/server'; import { ServiceStatusLevels } from '@kbn/core/server'; -import type { SecurityLicense } from '../../common/licensing'; +import type { SecurityLicense } from '../../common'; export interface ElasticsearchServiceSetupParams { readonly status: StatusServiceSetup; diff --git a/x-pack/plugins/security/server/elasticsearch/index.ts b/x-pack/plugins/security/server/elasticsearch/index.ts index 239802028b12..d955587ef073 100644 --- a/x-pack/plugins/security/server/elasticsearch/index.ts +++ b/x-pack/plugins/security/server/elasticsearch/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AuthenticatedUser } from '../../common/model'; +import type { AuthenticatedUser } from '../../common'; export type AuthenticationInfo = Omit< AuthenticatedUser, diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index 3d5cd022b4c9..d941532aa815 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -11,41 +11,73 @@ import type { PluginInitializer, PluginInitializerContext, } from '@kbn/core/server'; +import type { SecurityPluginStart } from '@kbn/security-plugin-types-server'; import type { RecursiveReadonly } from '@kbn/utility-types'; import { ConfigSchema } from './config'; import { securityConfigDeprecationProvider } from './config_deprecations'; -import type { PluginSetupDependencies, SecurityPluginSetup, SecurityPluginStart } from './plugin'; +import type { PluginSetupDependencies, SecurityPluginSetup } from './plugin'; // These exports are part of public Security plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. +export { HTTPAuthorizationHeader } from './authentication'; +export type { CasesSupportedOperations } from './authorization'; +export type { SecurityPluginSetup, SecurityPluginStart }; +export type { AuthenticatedUser } from '../common'; +export { ROUTE_TAG_CAN_REDIRECT } from './routes/tags'; + +// Re-export types from the plugin directly to enhance the developer experience for consumers of the Security plugin. export type { - CreateAPIKeyParams, + AuditEvent, + AuditHttp, + AuditKibana, + AuditRequest, + AuditLogger, + AuditServiceSetup, + APIKeys, + AuthenticationServiceStart, + InvalidateAPIKeyResult, + GrantAPIKeyResult, + ValidateAPIKeyParams, CreateAPIKeyResult, + InvalidateAPIKeysParams, + CreateAPIKeyParams, CreateRestAPIKeyParams, CreateRestAPIKeyWithKibanaPrivilegesParams, CreateCrossClusterAPIKeyParams, - InvalidateAPIKeysParams, - InvalidateAPIKeyResult, - GrantAPIKeyResult, - ValidateAPIKeyParams, - AuthenticationServiceStart, -} from './authentication'; -export { HTTPAuthorizationHeader } from './authentication'; -export type { CheckPrivilegesPayload, CasesSupportedOperations } from './authorization'; -export type AuthorizationServiceSetup = SecurityPluginStart['authz']; -export type { AuditLogger, AuditEvent, AuditHttp, AuditKibana, AuditRequest } from './audit'; -export type { SecurityPluginSetup, SecurityPluginStart }; -export type { AuthenticatedUser } from '../common/model'; -export { ROUTE_TAG_CAN_REDIRECT } from './routes/tags'; -export type { AuditServiceSetup } from './audit'; -export type { - UserProfileServiceStart, + Actions, + AlertingActions, + ApiActions, + AppActions, + CasesActions, + SavedObjectActions, + SpaceActions, + UIActions, + AuthorizationServiceSetup, + CheckPrivileges, + CheckPrivilegesPayload, + CheckUserProfilesPrivileges, + CheckPrivilegesDynamically, + CheckPrivilegesDynamicallyWithRequest, + CheckUserProfilesPrivilegesResponse, + CheckUserProfilesPrivilegesPayload, + CheckPrivilegesOptions, + CheckPrivilegesResponse, + CheckPrivilegesWithRequest, + CheckSavedObjectsPrivileges, + CheckSavedObjectsPrivilegesWithRequest, + ElasticsearchPrivilegesType, + KibanaPrivilegesType, + AuthorizationMode, + PrivilegeDeprecationsRolesByFeatureIdResponse, + PrivilegeDeprecationsService, + PrivilegeDeprecationsRolesByFeatureIdRequest, UserProfileBulkGetParams, UserProfileSuggestParams, UserProfileRequiredPrivileges, UserProfileGetCurrentParams, -} from './user_profile'; + UserProfileServiceStart, +} from '@kbn/security-plugin-types-server'; export const config: PluginConfigDescriptor> = { schema: ConfigSchema, diff --git a/x-pack/plugins/security/server/lib/index.ts b/x-pack/plugins/security/server/lib/index.ts index 715eeb0955da..496f60fdb098 100644 --- a/x-pack/plugins/security/server/lib/index.ts +++ b/x-pack/plugins/security/server/lib/index.ts @@ -5,8 +5,6 @@ * 2.0. */ -export type { ElasticsearchPrivilegesType, KibanaPrivilegesType } from './role_schema'; -export { elasticsearchRoleSchema, getKibanaRoleSchema } from './role_schema'; export { validateKibanaPrivileges, transformPrivilegesToElasticsearchPrivileges, diff --git a/x-pack/plugins/security/server/lib/role_utils.ts b/x-pack/plugins/security/server/lib/role_utils.ts index ff7a69029344..1df5254a38df 100644 --- a/x-pack/plugins/security/server/lib/role_utils.ts +++ b/x-pack/plugins/security/server/lib/role_utils.ts @@ -6,9 +6,10 @@ */ import type { KibanaFeature } from '@kbn/features-plugin/server'; +import type { KibanaPrivilegesType } from '@kbn/security-plugin-types-server'; +import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; -import type { KibanaPrivilegesType } from './role_schema'; -import { ALL_SPACES_ID, GLOBAL_RESOURCE } from '../../common/constants'; +import { ALL_SPACES_ID } from '../../common/constants'; import { PrivilegeSerializer } from '../authorization/privilege_serializer'; import { ResourceSerializer } from '../authorization/resource_serializer'; diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 341ab79e97e5..adfed1bad88e 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -23,6 +23,12 @@ import type { PluginStartContract as FeaturesPluginStart, } from '@kbn/features-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; +import type { + AuditServiceSetup, + AuthorizationServiceSetup, + SecurityPluginSetup as SecurityPluginSetupWithoutDeprecatedMembers, + SecurityPluginStart, +} from '@kbn/security-plugin-types-server'; import type { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import type { TaskManagerSetupContract, @@ -33,14 +39,10 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { AnalyticsService } from './analytics'; import type { AnonymousAccessServiceStart } from './anonymous_access'; import { AnonymousAccessService } from './anonymous_access'; -import type { AuditServiceSetup } from './audit'; import { AuditService } from './audit'; -import type { - AuthenticationServiceStart, - InternalAuthenticationServiceStart, -} from './authentication'; +import type { InternalAuthenticationServiceStart } from './authentication'; import { AuthenticationService } from './authentication'; -import type { AuthorizationServiceSetup, AuthorizationServiceSetupInternal } from './authorization'; +import type { AuthorizationServiceSetupInternal } from './authorization'; import { AuthorizationService } from './authorization'; import type { ConfigSchema, ConfigType } from './config'; import { createConfig } from './config'; @@ -56,11 +58,11 @@ import { SessionManagementService } from './session_management'; import { setupSpacesClient } from './spaces'; import { registerSecurityUsageCollector } from './usage_collector'; import { UserProfileService } from './user_profile'; -import type { UserProfileServiceStart, UserProfileServiceStartInternal } from './user_profile'; +import type { UserProfileServiceStartInternal } from './user_profile'; import { UserProfileSettingsClient } from './user_profile/user_profile_settings_client'; import type { UserSettingServiceStart } from './user_profile/user_setting_service'; import { UserSettingService } from './user_profile/user_setting_service'; -import type { AuthenticatedUser, PrivilegeDeprecationsService, SecurityLicense } from '../common'; +import type { AuthenticatedUser, SecurityLicense } from '../common'; import { SecurityLicenseService } from '../common/licensing'; export type SpacesService = Pick< @@ -71,7 +73,7 @@ export type SpacesService = Pick< /** * Describes public Security plugin contract returned at the `setup` stage. */ -export interface SecurityPluginSetup { +export interface SecurityPluginSetup extends SecurityPluginSetupWithoutDeprecatedMembers { /** * @deprecated Use `authc` methods from the `SecurityServiceStart` contract instead. */ @@ -80,36 +82,6 @@ export interface SecurityPluginSetup { * @deprecated Use `authz` methods from the `SecurityServiceStart` contract instead. */ authz: AuthorizationServiceSetup; - /** - * Exposes information about the available security features under the current license. - */ - license: SecurityLicense; - /** - * Exposes services for audit logging. - */ - audit: AuditServiceSetup; - /** - * Exposes services to access kibana roles per feature id with the GetDeprecationsContext - */ - privilegeDeprecationsService: PrivilegeDeprecationsService; -} - -/** - * Describes public Security plugin contract returned at the `start` stage. - */ -export interface SecurityPluginStart { - /** - * Authentication services to confirm the user is who they say they are. - */ - authc: AuthenticationServiceStart; - /** - * Authorization services to manage and access the permissions a particular user has. - */ - authz: AuthorizationServiceSetup; - /** - * User profiles services to retrieve user profiles. - */ - userProfiles: UserProfileServiceStart; } export interface PluginSetupDependencies { diff --git a/x-pack/plugins/security/server/routes/api_keys/create.ts b/x-pack/plugins/security/server/routes/api_keys/create.ts index ee69a80efa10..59d743e3726a 100644 --- a/x-pack/plugins/security/server/routes/api_keys/create.ts +++ b/x-pack/plugins/security/server/routes/api_keys/create.ts @@ -5,84 +5,18 @@ * 2.0. */ -import type { estypes } from '@elastic/elasticsearch'; - import { schema } from '@kbn/config-schema'; -import type { TypeOf } from '@kbn/config-schema'; +import { + crossClusterApiKeySchema, + getRestApiKeyWithKibanaPrivilegesSchema, + restApiKeySchema, +} from '@kbn/security-plugin-types-server'; import type { RouteDefinitionParams } from '..'; import { CreateApiKeyValidationError } from '../../authentication/api_keys'; import { wrapIntoCustomErrorResponse } from '../../errors'; -import { elasticsearchRoleSchema, getKibanaRoleSchema } from '../../lib'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -/** - * Response of Kibana Create API key endpoint. - */ -export type CreateAPIKeyResult = estypes.SecurityCreateApiKeyResponse; - -/** - * Request body of Kibana Create API key endpoint. - */ -export type CreateAPIKeyParams = - | CreateRestAPIKeyParams - | CreateRestAPIKeyWithKibanaPrivilegesParams - | CreateCrossClusterAPIKeyParams; - -export type CreateRestAPIKeyParams = TypeOf; -export type CreateRestAPIKeyWithKibanaPrivilegesParams = TypeOf< - ReturnType ->; -export type CreateCrossClusterAPIKeyParams = TypeOf; - -export const restApiKeySchema = schema.object({ - type: schema.maybe(schema.literal('rest')), - name: schema.string(), - expiration: schema.maybe(schema.string()), - role_descriptors: schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' }), { - defaultValue: {}, - }), - metadata: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}); - -export const getRestApiKeyWithKibanaPrivilegesSchema = ( - getBasePrivilegeNames: Parameters[0] -) => - restApiKeySchema.extends({ - role_descriptors: null, - kibana_role_descriptors: schema.recordOf( - schema.string(), - schema.object({ - elasticsearch: elasticsearchRoleSchema.extends({}, { unknowns: 'allow' }), - kibana: getKibanaRoleSchema(getBasePrivilegeNames), - }) - ), - }); - -export const crossClusterApiKeySchema = restApiKeySchema.extends({ - type: schema.literal('cross_cluster'), - role_descriptors: null, - access: schema.object( - { - search: schema.maybe( - schema.arrayOf( - schema.object({ - names: schema.arrayOf(schema.string()), - }) - ) - ), - replication: schema.maybe( - schema.arrayOf( - schema.object({ - names: schema.arrayOf(schema.string()), - }) - ) - ), - }, - { unknowns: 'allow' } - ), -}); - export function defineCreateApiKeyRoutes({ router, authz, diff --git a/x-pack/plugins/security/server/routes/api_keys/index.ts b/x-pack/plugins/security/server/routes/api_keys/index.ts index 9f086afcfd24..9855d94923c3 100644 --- a/x-pack/plugins/security/server/routes/api_keys/index.ts +++ b/x-pack/plugins/security/server/routes/api_keys/index.ts @@ -12,13 +12,6 @@ import { defineInvalidateApiKeysRoutes } from './invalidate'; import { defineUpdateApiKeyRoutes } from './update'; import type { RouteDefinitionParams } from '..'; -export type { - CreateAPIKeyParams, - CreateAPIKeyResult, - CreateRestAPIKeyParams, - CreateCrossClusterAPIKeyParams, - CreateRestAPIKeyWithKibanaPrivilegesParams, -} from './create'; export type { UpdateAPIKeyParams, UpdateAPIKeyResult, diff --git a/x-pack/plugins/security/server/routes/api_keys/update.ts b/x-pack/plugins/security/server/routes/api_keys/update.ts index 0a05ffe04820..ef999820c6ca 100644 --- a/x-pack/plugins/security/server/routes/api_keys/update.ts +++ b/x-pack/plugins/security/server/routes/api_keys/update.ts @@ -9,11 +9,11 @@ import type { estypes } from '@elastic/elasticsearch'; import { schema } from '@kbn/config-schema'; import type { TypeOf } from '@kbn/config-schema'; +import { elasticsearchRoleSchema, getKibanaRoleSchema } from '@kbn/security-plugin-types-server'; import type { RouteDefinitionParams } from '..'; import { UpdateApiKeyValidationError } from '../../authentication/api_keys/api_keys'; import { wrapIntoCustomErrorResponse } from '../../errors'; -import { elasticsearchRoleSchema, getKibanaRoleSchema } from '../../lib'; import { createLicensedRouteHandler } from '../licensed_route_handler'; /** diff --git a/x-pack/plugins/security/server/routes/authentication/common.test.ts b/x-pack/plugins/security/server/routes/authentication/common.test.ts index 44b56b73b220..6abf1b445b98 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.test.ts @@ -12,7 +12,7 @@ import { httpServerMock } from '@kbn/core/server/mocks'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import { defineCommonRoutes } from './common'; -import type { SecurityLicense, SecurityLicenseFeatures } from '../../../common/licensing'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../../common'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import type { InternalAuthenticationServiceStart } from '../../authentication'; import { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts index 5c8a07d15000..6bd8e5a4ec70 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/model/put_payload.ts @@ -7,13 +7,10 @@ import type { TypeOf } from '@kbn/config-schema'; import { schema } from '@kbn/config-schema'; +import { elasticsearchRoleSchema, getKibanaRoleSchema } from '@kbn/security-plugin-types-server'; import type { ElasticsearchRole } from '../../../../authorization'; -import { - elasticsearchRoleSchema, - getKibanaRoleSchema, - transformPrivilegesToElasticsearchPrivileges, -} from '../../../../lib'; +import { transformPrivilegesToElasticsearchPrivileges } from '../../../../lib'; export const transformPutPayloadToElasticsearchRole = ( rolePayload: RolePayloadSchemaType, diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts index 77e3bd51b5e8..18a07bce0a23 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts @@ -10,9 +10,9 @@ import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; import { KibanaFeature } from '@kbn/features-plugin/server'; import type { LicenseCheck } from '@kbn/licensing-plugin/server'; +import { GLOBAL_RESOURCE } from '@kbn/security-plugin-types-server'; import { definePutRolesRoutes } from './put'; -import { GLOBAL_RESOURCE } from '../../../../common/constants'; import { securityFeatureUsageServiceMock } from '../../../feature_usage/index.mock'; import { routeDefinitionParamsMock } from '../../index.mock'; diff --git a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts index 8329be6a9186..c518030a76f1 100644 --- a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts @@ -8,11 +8,11 @@ import type { RequestHandler, RouteConfig } from '@kbn/core/server'; import { kibanaResponseFactory } from '@kbn/core/server'; import { httpServerMock } from '@kbn/core/server/mocks'; +import type { CheckPrivileges } from '@kbn/security-plugin-types-server'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import { defineShareSavedObjectPermissionRoutes } from './share_saved_object_permissions'; import type { RouteDefinitionParams } from '../..'; -import type { CheckPrivileges } from '../../../authorization/types'; import type { SecurityRequestHandlerContext, SecurityRouter } from '../../../types'; import { routeDefinitionParamsMock } from '../../index.mock'; diff --git a/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts index c40f0b92b54a..3a7f89589c84 100644 --- a/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts +++ b/x-pack/plugins/security/server/routes/security_checkup/get_state.test.ts @@ -15,7 +15,7 @@ import { kibanaResponseFactory } from '@kbn/core/server'; import { httpServerMock } from '@kbn/core/server/mocks'; import { defineSecurityCheckupGetStateRoutes } from './get_state'; -import type { SecurityLicenseFeatures } from '../../../common/licensing'; +import type { SecurityLicenseFeatures } from '../../../common'; import { licenseMock } from '../../../common/licensing/index.mock'; import { routeDefinitionParamsMock, securityRequestHandlerContextMock } from '../index.mock'; diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts index 6190f03e6ed7..ef588ae1cfcf 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts @@ -16,8 +16,11 @@ import { httpResourcesMock, httpServerMock } from '@kbn/core/server/mocks'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { defineAccessAgreementRoutes } from './access_agreement'; -import type { SecurityLicense, SecurityLicenseFeatures } from '../../../common/licensing'; -import type { AuthenticationProvider } from '../../../common/model'; +import type { + AuthenticationProvider, + SecurityLicense, + SecurityLicenseFeatures, +} from '../../../common'; import type { ConfigType } from '../../config'; import type { Session } from '../../session_management'; import { sessionMock } from '../../session_management/session.mock'; diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts index b73b048d9f4d..086c0c785e6b 100644 --- a/x-pack/plugins/security/server/routes/views/login.test.ts +++ b/x-pack/plugins/security/server/routes/views/login.test.ts @@ -18,7 +18,7 @@ import { kibanaResponseFactory } from '@kbn/core/server'; import { coreMock, httpResourcesMock, httpServerMock } from '@kbn/core/server/mocks'; import { defineLoginRoutes } from './login'; -import type { SecurityLicense } from '../../../common/licensing'; +import type { SecurityLicense } from '../../../common'; import type { LoginSelectorProvider } from '../../../common/login_state'; import type { ConfigType } from '../../config'; import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; diff --git a/x-pack/plugins/security/server/saved_objects/ensure_authorized.test.ts b/x-pack/plugins/security/server/saved_objects/ensure_authorized.test.ts index 2c7799eae526..22c219a5668a 100644 --- a/x-pack/plugins/security/server/saved_objects/ensure_authorized.test.ts +++ b/x-pack/plugins/security/server/saved_objects/ensure_authorized.test.ts @@ -6,6 +6,10 @@ */ import type { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import type { + CheckPrivilegesResponse, + CheckSavedObjectsPrivileges, +} from '@kbn/security-plugin-types-server'; import type { EnsureAuthorizedResult } from './ensure_authorized'; import { @@ -13,9 +17,7 @@ import { getEnsureAuthorizedActionResult, isAuthorizedForObjectInAllSpaces, } from './ensure_authorized'; -import type { CheckSavedObjectsPrivileges } from '../authorization'; import { Actions } from '../authorization'; -import type { CheckPrivilegesResponse } from '../authorization/types'; describe('ensureAuthorized', () => { function setupDependencies() { diff --git a/x-pack/plugins/security/server/saved_objects/ensure_authorized.ts b/x-pack/plugins/security/server/saved_objects/ensure_authorized.ts index 79e15be65077..950cba3f103a 100644 --- a/x-pack/plugins/security/server/saved_objects/ensure_authorized.ts +++ b/x-pack/plugins/security/server/saved_objects/ensure_authorized.ts @@ -6,9 +6,11 @@ */ import type { SavedObjectsErrorHelpers } from '@kbn/core/server'; - -import type { Actions, CheckSavedObjectsPrivileges } from '../authorization'; -import type { CheckPrivilegesResponse } from '../authorization/types'; +import type { + Actions, + CheckPrivilegesResponse, + CheckSavedObjectsPrivileges, +} from '@kbn/security-plugin-types-server'; export interface EnsureAuthorizedDependencies { actions: Actions; diff --git a/x-pack/plugins/security/server/saved_objects/index.ts b/x-pack/plugins/security/server/saved_objects/index.ts index 6068ada7a372..3fa610485a28 100644 --- a/x-pack/plugins/security/server/saved_objects/index.ts +++ b/x-pack/plugins/security/server/saved_objects/index.ts @@ -7,9 +7,9 @@ import type { CoreSetup } from '@kbn/core/server'; import { SavedObjectsClient } from '@kbn/core/server'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import { SavedObjectsSecurityExtension } from './saved_objects_security_extension'; -import type { AuditServiceSetup } from '../audit'; import type { AuthorizationServiceSetupInternal } from '../authorization'; interface SetupSavedObjectsParams { diff --git a/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.test.ts b/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.test.ts index ff962c3421ce..42fd2f8eb0d9 100644 --- a/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.test.ts +++ b/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.test.ts @@ -19,6 +19,10 @@ import type { AuthorizeUpdateObject, BulkResolveError, } from '@kbn/core-saved-objects-server'; +import type { + CheckPrivilegesResponse, + CheckSavedObjectsPrivileges, +} from '@kbn/security-plugin-types-server'; import { AuditAction, @@ -26,9 +30,7 @@ import { SecurityAction, } from './saved_objects_security_extension'; import { auditLoggerMock } from '../audit/mocks'; -import type { CheckSavedObjectsPrivileges } from '../authorization'; import { Actions } from '../authorization'; -import type { CheckPrivilegesResponse } from '../authorization/types'; const checkAuthorizationSpy = jest.spyOn( SavedObjectsSecurityExtension.prototype as any, diff --git a/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.ts b/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.ts index 81b909da2c98..1eb934d2f2bd 100644 --- a/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.ts +++ b/x-pack/plugins/security/server/saved_objects/saved_objects_security_extension.ts @@ -42,13 +42,16 @@ import type { import type { AuthorizeObject } from '@kbn/core-saved-objects-server/src/extensions/security'; import { ALL_NAMESPACES_STRING, SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server'; import type { EcsEvent } from '@kbn/ecs'; +import type { + Actions, + AuditLogger, + CheckPrivilegesResponse, + CheckSavedObjectsPrivileges, +} from '@kbn/security-plugin-types-server'; import { isAuthorizedInAllSpaces } from './authorization_utils'; import { ALL_SPACES_ID, UNKNOWN_SPACE } from '../../common/constants'; -import type { AuditLogger } from '../audit'; import { savedObjectEvent } from '../audit'; -import type { Actions, CheckSavedObjectsPrivileges } from '../authorization'; -import type { CheckPrivilegesResponse } from '../authorization/types'; interface Params { actions: Actions; diff --git a/x-pack/plugins/security/server/session_management/session.test.ts b/x-pack/plugins/security/server/session_management/session.test.ts index 691b6db78b51..b6f9197606e1 100644 --- a/x-pack/plugins/security/server/session_management/session.test.ts +++ b/x-pack/plugins/security/server/session_management/session.test.ts @@ -9,6 +9,7 @@ import nodeCrypto from '@elastic/node-crypto'; import crypto from 'crypto'; import { httpServerMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import type { AuditLogger } from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { sessionCookieMock, sessionIndexMock, sessionMock } from './index.mock'; @@ -21,7 +22,6 @@ import { SessionUnexpectedError, } from './session_errors'; import type { SessionIndex } from './session_index'; -import type { AuditLogger } from '..'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { userSessionConcurrentLimitLogoutEvent } from '../audit'; import { auditLoggerMock, auditServiceMock } from '../audit/mocks'; diff --git a/x-pack/plugins/security/server/session_management/session.ts b/x-pack/plugins/security/server/session_management/session.ts index 38b3cc7d2443..afc917bde78b 100644 --- a/x-pack/plugins/security/server/session_management/session.ts +++ b/x-pack/plugins/security/server/session_management/session.ts @@ -11,6 +11,7 @@ import { createHash, randomBytes } from 'crypto'; import { promisify } from 'util'; import type { KibanaRequest, Logger } from '@kbn/core/server'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { SessionCookie } from './session_cookie'; @@ -21,7 +22,6 @@ import { SessionUnexpectedError, } from './session_errors'; import type { SessionIndex, SessionIndexValue } from './session_index'; -import type { AuditServiceSetup } from '..'; import type { AuthenticationProvider } from '../../common'; import { userSessionConcurrentLimitLogoutEvent } from '../audit'; import type { ConfigType } from '../config'; diff --git a/x-pack/plugins/security/server/session_management/session_index.test.ts b/x-pack/plugins/security/server/session_management/session_index.test.ts index 2a837a7be780..e1890273469e 100644 --- a/x-pack/plugins/security/server/session_management/session_index.test.ts +++ b/x-pack/plugins/security/server/session_management/session_index.test.ts @@ -16,6 +16,7 @@ import type { } from '@elastic/elasticsearch/lib/api/types'; import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import type { AuditLogger } from '@kbn/security-plugin-types-server'; import { getSessionIndexSettings, @@ -23,7 +24,6 @@ import { SessionIndex, } from './session_index'; import { sessionIndexMock } from './session_index.mock'; -import type { AuditLogger } from '../audit'; import { auditLoggerMock } from '../audit/mocks'; import { AnonymousAuthenticationProvider } from '../authentication'; import { ConfigSchema, createConfig } from '../config'; diff --git a/x-pack/plugins/security/server/session_management/session_index.ts b/x-pack/plugins/security/server/session_management/session_index.ts index 54f448d15138..700904d4676d 100644 --- a/x-pack/plugins/security/server/session_management/session_index.ts +++ b/x-pack/plugins/security/server/session_management/session_index.ts @@ -20,9 +20,9 @@ import type { import semver from 'semver'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { AuditLogger } from '@kbn/security-plugin-types-server'; -import type { AuthenticationProvider } from '../../common/model'; -import type { AuditLogger } from '../audit'; +import type { AuthenticationProvider } from '../../common'; import { sessionCleanupConcurrentLimitEvent, sessionCleanupEvent } from '../audit'; import { AnonymousAuthenticationProvider } from '../authentication'; import type { ConfigType } from '../config'; diff --git a/x-pack/plugins/security/server/session_management/session_management_service.test.ts b/x-pack/plugins/security/server/session_management/session_management_service.test.ts index 46bb0499f8e4..e59ba59600b2 100644 --- a/x-pack/plugins/security/server/session_management/session_management_service.test.ts +++ b/x-pack/plugins/security/server/session_management/session_management_service.test.ts @@ -8,6 +8,7 @@ import { Subject } from 'rxjs'; import { coreMock, elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { TaskManagerStartContract, TaskRunCreatorFunction, @@ -21,7 +22,6 @@ import { SESSION_INDEX_CLEANUP_TASK_NAME, SessionManagementService, } from './session_management_service'; -import type { AuditServiceSetup } from '../audit'; import { auditServiceMock } from '../audit/mocks'; import { ConfigSchema, createConfig } from '../config'; import type { OnlineStatusRetryScheduler } from '../elasticsearch'; diff --git a/x-pack/plugins/security/server/session_management/session_management_service.ts b/x-pack/plugins/security/server/session_management/session_management_service.ts index 4c3298f69bca..448f5f060500 100644 --- a/x-pack/plugins/security/server/session_management/session_management_service.ts +++ b/x-pack/plugins/security/server/session_management/session_management_service.ts @@ -10,6 +10,7 @@ import { switchMap } from 'rxjs'; import type { ElasticsearchClient, HttpServiceSetup, Logger } from '@kbn/core/server'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import type { AuditServiceSetup } from '@kbn/security-plugin-types-server'; import type { TaskManagerSetupContract, TaskManagerStartContract, @@ -18,7 +19,6 @@ import type { import { Session } from './session'; import { SessionCookie } from './session_cookie'; import { SessionIndex } from './session_index'; -import type { AuditServiceSetup } from '../audit'; import type { ConfigType } from '../config'; import type { OnlineStatusRetryScheduler } from '../elasticsearch'; diff --git a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts index f990bf8095a1..22b3492d26d7 100644 --- a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts @@ -10,20 +10,21 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { httpServerMock } from '@kbn/core/server/mocks'; import { savedObjectsExtensionsMock } from '@kbn/core-saved-objects-api-server-mocks'; import type { ISavedObjectsSecurityExtension } from '@kbn/core-saved-objects-server'; +import type { + AuditEvent, + AuditLogger, + AuthorizationServiceSetup, + CheckPrivilegesResponse, +} from '@kbn/security-plugin-types-server'; import type { GetAllSpacesPurpose, Space } from '@kbn/spaces-plugin/server'; import { spacesClientMock } from '@kbn/spaces-plugin/server/mocks'; import { deepFreeze } from '@kbn/std'; import { SecureSpacesClientWrapper } from './secure_spaces_client_wrapper'; -import type { AuditEvent, AuditLogger } from '../audit'; import { SpaceAuditAction } from '../audit'; import { auditLoggerMock } from '../audit/mocks'; -import type { - AuthorizationServiceSetup, - AuthorizationServiceSetupInternal, -} from '../authorization'; +import type { AuthorizationServiceSetupInternal } from '../authorization'; import { authorizationMock } from '../authorization/index.mock'; -import type { CheckPrivilegesResponse } from '../authorization/types'; interface Opts { securityEnabled?: boolean; diff --git a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts index 1e9e25b6b800..a4f57e067c09 100644 --- a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts +++ b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts @@ -10,6 +10,7 @@ import Boom from '@hapi/boom'; import type { KibanaRequest, SavedObjectsClient } from '@kbn/core/server'; import type { LegacyUrlAliasTarget } from '@kbn/core-saved-objects-common'; import type { ISavedObjectsSecurityExtension } from '@kbn/core-saved-objects-server'; +import type { AuditLogger, AuthorizationServiceSetup } from '@kbn/security-plugin-types-server'; import type { GetAllSpacesOptions, GetAllSpacesPurpose, @@ -18,9 +19,7 @@ import type { Space, } from '@kbn/spaces-plugin/server'; -import type { AuditLogger } from '../audit'; import { SpaceAuditAction, spaceAuditEvent } from '../audit'; -import type { AuthorizationServiceSetup } from '../authorization'; import type { SecurityPluginSetup } from '../plugin'; const PURPOSE_PRIVILEGE_MAP: Record< diff --git a/x-pack/plugins/security/server/spaces/setup_spaces_client.ts b/x-pack/plugins/security/server/spaces/setup_spaces_client.ts index 43351c575d39..6ca68a395fbc 100644 --- a/x-pack/plugins/security/server/spaces/setup_spaces_client.ts +++ b/x-pack/plugins/security/server/spaces/setup_spaces_client.ts @@ -6,11 +6,13 @@ */ import { SavedObjectsClient } from '@kbn/core/server'; +import type { + AuditServiceSetup, + AuthorizationServiceSetup, +} from '@kbn/security-plugin-types-server'; import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import { SecureSpacesClientWrapper } from './secure_spaces_client_wrapper'; -import type { AuditServiceSetup } from '../audit'; -import type { AuthorizationServiceSetup } from '../authorization'; import { SavedObjectsSecurityExtension } from '../saved_objects'; interface Deps { diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts index d120aae57a51..19378bfd8488 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -13,7 +13,7 @@ import { } from '@kbn/usage-collection-plugin/server/mocks'; import { registerSecurityUsageCollector } from './security_usage_collector'; -import type { SecurityLicenseFeatures } from '../../common/licensing'; +import type { SecurityLicenseFeatures } from '../../common'; import { licenseMock } from '../../common/licensing/index.mock'; import { ConfigSchema, createConfig } from '../config'; diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts index 585994339144..fc761fb13a50 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts @@ -7,7 +7,7 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; -import type { SecurityLicense } from '../../common/licensing'; +import type { SecurityLicense } from '../../common'; import type { ConfigType } from '../config'; interface Usage { diff --git a/x-pack/plugins/security/server/user_profile/index.ts b/x-pack/plugins/security/server/user_profile/index.ts index 9c6fd67458e6..a324c685bf7f 100644 --- a/x-pack/plugins/security/server/user_profile/index.ts +++ b/x-pack/plugins/security/server/user_profile/index.ts @@ -8,12 +8,7 @@ export { UserProfileService } from './user_profile_service'; export type { - UserProfileServiceStart, UserProfileServiceStartInternal, UserProfileServiceStartParams, - UserProfileSuggestParams, - UserProfileBulkGetParams, - UserProfileRequiredPrivileges, - UserProfileGetCurrentParams, } from './user_profile_service'; export type { UserProfileGrant } from './user_profile_grant'; diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.ts index 8ef87b60f9e1..b6e0912b804d 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.ts @@ -8,7 +8,15 @@ import type { SecurityActivateUserProfileRequest } from '@elastic/elasticsearch/lib/api/types'; import type { SecurityUserProfile } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { IClusterClient, KibanaRequest, Logger } from '@kbn/core/server'; +import type { IClusterClient, Logger } from '@kbn/core/server'; +import type { + CheckUserProfilesPrivilegesResponse, + UserProfileBulkGetParams, + UserProfileGetCurrentParams, + UserProfileRequiredPrivileges, + UserProfileServiceStart, + UserProfileSuggestParams, +} from '@kbn/security-plugin-types-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { UserProfileGrant } from './user_profile_grant'; @@ -16,11 +24,9 @@ import type { SecurityLicense, UserProfile, UserProfileData, - UserProfileLabels, UserProfileWithSecurity, } from '../../common'; import type { AuthorizationServiceSetupInternal } from '../authorization'; -import type { CheckUserProfilesPrivilegesResponse } from '../authorization/types'; import { getDetailedErrorMessage, getErrorStatusCode } from '../errors'; import { getPrintableSessionId, type Session } from '../session_management'; @@ -31,46 +37,6 @@ const MAX_SUGGESTIONS_COUNT = 100; const DEFAULT_SUGGESTIONS_COUNT = 10; const MIN_SUGGESTIONS_FOR_PRIVILEGES_CHECK = 10; -/** - * A set of methods to work with Kibana user profiles. - */ -export interface UserProfileServiceStart { - /** - * Retrieves a user profile for the current user extracted from the specified request. If the profile isn't available, - * e.g. for the anonymous users or users authenticated via authenticating proxies, the `null` value is returned. - * @param params Get current user profile operation parameters. - * @param params.request User request instance to get user profile for. - * @param params.dataPath By default Elasticsearch returns user information, but does not return any user data. The - * optional "dataPath" parameter can be used to return personal data for the requested user profiles. - */ - getCurrent( - params: UserProfileGetCurrentParams - ): Promise | null>; - - /** - * Retrieves multiple user profiles by their identifiers. - * @param params Bulk get operation parameters. - * @param params.uids List of user profile identifiers. - * @param params.dataPath By default Elasticsearch returns user information, but does not return any user data. The - * optional "dataPath" parameter can be used to return personal data for the requested user profiles. - */ - bulkGet( - params: UserProfileBulkGetParams - ): Promise>>; - - /** - * Suggests multiple user profiles by search criteria. - * @param params Suggest operation parameters. - * @param params.name Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email. - * @param params.size Desired number of suggestion to return. The default value is 10. - * @param params.dataPath By default, suggest API returns user information, but does not return any user data. The optional "dataPath" parameter can be used to return personal data for this user (within `kibana` namespace only). - * @param params.requiredPrivileges The set of the privileges that users associated with the suggested user profile should have in the specified space. If not specified, privileges check isn't performed and all matched profiles are returned irrespective to the privileges of the associated users. - */ - suggest( - params: UserProfileSuggestParams - ): Promise>>; -} - export interface UserProfileServiceStartInternal extends UserProfileServiceStart { /** * Activates user profile using provided user profile grant. @@ -96,94 +62,6 @@ export interface UserProfileServiceStartParams { session: PublicMethodsOf; } -/** - * The set of privileges that users associated with the suggested user profile should have for a specified space id. - */ -export interface UserProfileRequiredPrivileges { - /** - * The id of the Kibana Space. - */ - spaceId: string; - - /** - * The set of the Kibana specific application privileges. - */ - privileges: { kibana: string[] }; -} - -/** - * Parameters for the get user profile for the current user API. - */ -export interface UserProfileGetCurrentParams { - /** - * User request instance to get user profile for. - */ - request: KibanaRequest; - - /** - * By default, get API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath?: string; -} - -/** - * Parameters for the bulk get API. - */ -export interface UserProfileBulkGetParams { - /** - * List of user profile identifiers. - */ - uids: Set; - - /** - * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath?: string; -} - -/** - * Parameters for the suggest API. - */ -export interface UserProfileSuggestParams { - /** - * Query string used to match name-related fields in user profiles. The following fields are treated as - * name-related: username, full_name and email. - */ - name?: string; - - /** - * Extra search criteria to improve relevance of the suggestion result. A profile matching the - * specified hint is ranked higher in the response. But not-matching the hint does not exclude a - * profile from the response as long as it matches the `name` field query. - */ - hint?: { - /** - * A list of Profile UIDs to match against. - */ - uids: string[]; - }; - - /** - * Desired number of suggestion to return. The default value is 10. - */ - size?: number; - - /** - * By default, suggest API returns user information, but does not return any user data. The optional "dataPath" - * parameter can be used to return personal data for this user (within `kibana` namespace only). - */ - dataPath?: string; - - /** - * The set of the privileges that users associated with the suggested user profile should have in the specified space. - * If not specified, privileges check isn't performed and all matched profiles are returned irrespective to the - * privileges of the associated users. - */ - requiredPrivileges?: UserProfileRequiredPrivileges; -} - function parseUserProfile( rawUserProfile: SecurityUserProfile ): UserProfile { diff --git a/x-pack/plugins/security/server/user_profile/user_setting_service.ts b/x-pack/plugins/security/server/user_profile/user_setting_service.ts index 7c5ca3c1c7ef..f423d75e1a04 100644 --- a/x-pack/plugins/security/server/user_profile/user_setting_service.ts +++ b/x-pack/plugins/security/server/user_profile/user_setting_service.ts @@ -7,8 +7,10 @@ import type { KibanaRequest } from '@kbn/core-http-server'; import type { Logger } from '@kbn/logging'; - -import type { UserProfileGetCurrentParams, UserProfileServiceStart } from './user_profile_service'; +import type { + UserProfileGetCurrentParams, + UserProfileServiceStart, +} from '@kbn/security-plugin-types-server'; export interface UserSettingServiceStart { /** diff --git a/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts b/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts index 07e30826d8f0..d27887d5716f 100644 --- a/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts +++ b/x-pack/plugins/security/server/user_profile/user_settings_service.test.ts @@ -12,8 +12,8 @@ import { httpServerMock, loggingSystemMock, } from '@kbn/core/server/mocks'; +import type { UserProfileServiceStart } from '@kbn/security-plugin-types-server'; -import type { UserProfileServiceStart } from './user_profile_service'; import { UserProfileService } from './user_profile_service'; import { UserSettingService } from './user_setting_service'; import type { UserProfileWithSecurity } from '../../common'; diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index 2a055a61bbad..3a0f7062ec20 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -63,6 +63,9 @@ "@kbn/core-user-settings-server", "@kbn/remote-clusters-plugin", "@kbn/analytics-client", + "@kbn/security-plugin-types-common", + "@kbn/security-plugin-types-public", + "@kbn/security-plugin-types-server" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts new file mode 100644 index 000000000000..b74132faed03 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './set_alert_assignees_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts new file mode 100644 index 000000000000..ef668dc36d42 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/mocks.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './set_alert_assignees_route.mock'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts new file mode 100644 index 000000000000..f2b2be478ced --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { NonEmptyString } from '../model/rule_schema/common_attributes.gen'; + +export type AlertAssignees = z.infer; +export const AlertAssignees = z.object({ + /** + * A list of users ids to assign. + */ + add: z.array(NonEmptyString), + /** + * A list of users ids to unassign. + */ + remove: z.array(NonEmptyString), +}); + +/** + * A list of alerts ids. + */ +export type AlertIds = z.infer; +export const AlertIds = z.array(NonEmptyString).min(1); + +export type SetAlertAssigneesRequestBody = z.infer; +export const SetAlertAssigneesRequestBody = z.object({ + /** + * Details about the assignees to assign and unassign. + */ + assignees: AlertAssignees, + /** + * List of alerts ids to assign and unassign passed assignees. + */ + ids: AlertIds, +}); +export type SetAlertAssigneesRequestBodyInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts new file mode 100644 index 000000000000..9c41e2eae805 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.mock.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SetAlertAssigneesRequestBody } from './set_alert_assignees_route.gen'; + +export const getSetAlertAssigneesRequestMock = ( + assigneesToAdd: string[] = [], + assigneesToRemove: string[] = [], + ids: string[] = [] +): SetAlertAssigneesRequestBody => ({ + assignees: { add: assigneesToAdd, remove: assigneesToRemove }, + ids, +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml new file mode 100644 index 000000000000..6c3663402118 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.0 +info: + title: Assign alerts API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/assignees: + summary: Assigns users to alerts + post: + operationId: SetAlertAssignees + x-codegen-enabled: true + description: Assigns users to alerts. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - assignees + - ids + properties: + assignees: + $ref: '#/components/schemas/AlertAssignees' + description: Details about the assignees to assign and unassign. + ids: + $ref: '#/components/schemas/AlertIds' + description: List of alerts ids to assign and unassign passed assignees. + responses: + 200: + description: Indicates a successful call. + 400: + description: Invalid request. + +components: + schemas: + AlertAssignees: + type: object + required: + - add + - remove + properties: + add: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + description: A list of users ids to assign. + remove: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + description: A list of users ids to unassign. + + AlertIds: + type: array + items: + $ref: '../model/rule_schema/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + minItems: 1 + description: A list of alerts ids. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/index.ts index eadf1e48e9e3..56c6d4225f74 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +export * from './alert_assignees'; export * from './alert_tags'; export * from './fleet_integrations'; export * from './index_management'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.12.0/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.12.0/index.ts new file mode 100644 index 000000000000..da97667035a6 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.12.0/index.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; +import type { AlertWithCommonFields800 } from '@kbn/rule-registry-plugin/common/schemas/8.0.0'; +import type { + Ancestor890, + BaseFields890, + EqlBuildingBlockFields890, + EqlShellFields890, + NewTermsFields890, +} from '../8.9.0'; + +/* DO NOT MODIFY THIS SCHEMA TO ADD NEW FIELDS. These types represent the alerts that shipped in 8.12.0. +Any changes to these types should be bug fixes so the types more accurately represent the alerts from 8.12.0. +If you are adding new fields for a new release of Kibana, create a new sibling folder to this one +for the version to be released and add the field(s) to the schema in that folder. +Then, update `../index.ts` to import from the new folder that has the latest schemas, add the +new schemas to the union of all alert schemas, and re-export the new schemas as the `*Latest` schemas. +*/ + +export type { Ancestor890 as Ancestor8120 }; + +export interface BaseFields8120 extends BaseFields890 { + [ALERT_WORKFLOW_ASSIGNEE_IDS]: string[] | undefined; +} + +export interface WrappedFields8120 { + _id: string; + _index: string; + _source: T; +} + +export type GenericAlert8120 = AlertWithCommonFields800; + +export type EqlShellFields8120 = EqlShellFields890 & BaseFields8120; + +export type EqlBuildingBlockFields8120 = EqlBuildingBlockFields890 & BaseFields8120; + +export type NewTermsFields8120 = NewTermsFields890 & BaseFields8120; + +export type NewTermsAlert8120 = NewTermsFields890 & BaseFields8120; + +export type EqlBuildingBlockAlert8120 = AlertWithCommonFields800; + +export type EqlShellAlert8120 = AlertWithCommonFields800; + +export type DetectionAlert8120 = + | GenericAlert8120 + | EqlShellAlert8120 + | EqlBuildingBlockAlert8120 + | NewTermsAlert8120; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/index.ts index d3718c4f07db..742e5fd4ecfc 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/index.ts @@ -11,15 +11,16 @@ import type { DetectionAlert840 } from './8.4.0'; import type { DetectionAlert860 } from './8.6.0'; import type { DetectionAlert870 } from './8.7.0'; import type { DetectionAlert880 } from './8.8.0'; +import type { DetectionAlert890 } from './8.9.0'; import type { - Ancestor890, - BaseFields890, - DetectionAlert890, - EqlBuildingBlockFields890, - EqlShellFields890, - NewTermsFields890, - WrappedFields890, -} from './8.9.0'; + Ancestor8120, + BaseFields8120, + DetectionAlert8120, + EqlBuildingBlockFields8120, + EqlShellFields8120, + NewTermsFields8120, + WrappedFields8120, +} from './8.12.0'; // When new Alert schemas are created for new Kibana versions, add the DetectionAlert type from the new version // here, e.g. `export type DetectionAlert = DetectionAlert800 | DetectionAlert820` if a new schema is created in 8.2.0 @@ -29,14 +30,15 @@ export type DetectionAlert = | DetectionAlert860 | DetectionAlert870 | DetectionAlert880 - | DetectionAlert890; + | DetectionAlert890 + | DetectionAlert8120; export type { - Ancestor890 as AncestorLatest, - BaseFields890 as BaseFieldsLatest, - DetectionAlert890 as DetectionAlertLatest, - WrappedFields890 as WrappedFieldsLatest, - EqlBuildingBlockFields890 as EqlBuildingBlockFieldsLatest, - EqlShellFields890 as EqlShellFieldsLatest, - NewTermsFields890 as NewTermsFieldsLatest, + Ancestor8120 as AncestorLatest, + BaseFields8120 as BaseFieldsLatest, + DetectionAlert8120 as DetectionAlertLatest, + WrappedFields8120 as WrappedFieldsLatest, + EqlBuildingBlockFields8120 as EqlBuildingBlockFieldsLatest, + EqlShellFields8120 as EqlShellFieldsLatest, + NewTermsFields8120 as NewTermsFieldsLatest, }; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts index 10901049d476..eebcde55a030 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts @@ -6,7 +6,6 @@ */ import { z } from 'zod'; -import { requiredOptional } from '@kbn/zod-helpers'; /* * NOTICE: Do not edit this file manually. @@ -27,48 +26,42 @@ export const EcsMapping = z.object({}).catchall( ); export type OsqueryQuery = z.infer; -export const OsqueryQuery = z - .object({ - /** - * Query ID - */ - id: z.string(), - /** - * Query to execute - */ - query: z.string(), - ecs_mapping: EcsMapping.optional(), - /** - * Query version - */ - version: z.string().optional(), - platform: z.string().optional(), - removed: z.boolean().optional(), - snapshot: z.boolean().optional(), - }) - .transform(requiredOptional); +export const OsqueryQuery = z.object({ + /** + * Query ID + */ + id: z.string(), + /** + * Query to execute + */ + query: z.string(), + ecs_mapping: EcsMapping.optional(), + /** + * Query version + */ + version: z.string().optional(), + platform: z.string().optional(), + removed: z.boolean().optional(), + snapshot: z.boolean().optional(), +}); export type OsqueryParams = z.infer; -export const OsqueryParams = z - .object({ - query: z.string().optional(), - ecs_mapping: EcsMapping.optional(), - queries: z.array(OsqueryQuery).optional(), - pack_id: z.string().optional(), - saved_query_id: z.string().optional(), - }) - .transform(requiredOptional); +export const OsqueryParams = z.object({ + query: z.string().optional(), + ecs_mapping: EcsMapping.optional(), + queries: z.array(OsqueryQuery).optional(), + pack_id: z.string().optional(), + saved_query_id: z.string().optional(), +}); export type OsqueryParamsCamelCase = z.infer; -export const OsqueryParamsCamelCase = z - .object({ - query: z.string().optional(), - ecsMapping: EcsMapping.optional(), - queries: z.array(OsqueryQuery).optional(), - packId: z.string().optional(), - savedQueryId: z.string().optional(), - }) - .transform(requiredOptional); +export const OsqueryParamsCamelCase = z.object({ + query: z.string().optional(), + ecsMapping: EcsMapping.optional(), + queries: z.array(OsqueryQuery).optional(), + packId: z.string().optional(), + savedQueryId: z.string().optional(), +}); export type OsqueryResponseAction = z.infer; export const OsqueryResponseAction = z.object({ @@ -83,12 +76,10 @@ export const RuleResponseOsqueryAction = z.object({ }); export type EndpointParams = z.infer; -export const EndpointParams = z - .object({ - command: z.literal('isolate'), - comment: z.string().optional(), - }) - .transform(requiredOptional); +export const EndpointParams = z.object({ + command: z.literal('isolate'), + comment: z.string().optional(), +}); export type EndpointResponseAction = z.infer; export const EndpointResponseAction = z.object({ diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml index 6cc6f0c46465..9d27bb6e4a97 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml @@ -49,7 +49,6 @@ components: required: - id - query - x-modify: requiredOptional OsqueryParams: type: object @@ -66,7 +65,6 @@ components: type: string saved_query_id: type: string - x-modify: requiredOptional OsqueryParamsCamelCase: type: object @@ -83,7 +81,6 @@ components: type: string savedQueryId: type: string - x-modify: requiredOptional OsqueryResponseAction: type: object @@ -123,7 +120,6 @@ components: type: string required: - command - x-modify: requiredOptional EndpointResponseAction: type: object diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts index 79ad21ddfb00..4b9001dc35c0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts @@ -6,7 +6,7 @@ */ import { z } from 'zod'; -import { requiredOptional, isValidDateMath } from '@kbn/zod-helpers'; +import { isValidDateMath } from '@kbn/zod-helpers'; /* * NOTICE: Do not edit this file manually. @@ -94,14 +94,12 @@ export const RiskScore = z.number().int().min(0).max(100); */ export type RiskScoreMapping = z.infer; export const RiskScoreMapping = z.array( - z - .object({ - field: z.string(), - operator: z.literal('equals'), - value: z.string(), - risk_score: RiskScore.optional(), - }) - .transform(requiredOptional) + z.object({ + field: z.string(), + operator: z.literal('equals'), + value: z.string(), + risk_score: RiskScore.optional(), + }) ); /** diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml index ad2bfaf76c4c..047394c5843c 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml @@ -95,7 +95,6 @@ components: - field - operator - value - x-modify: requiredOptional description: Overrides generated alerts' risk_score with a value from the source event Severity: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts index 062c91335440..3dfc4a294965 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts @@ -25,8 +25,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", and 52 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -48,8 +48,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", and 52 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -61,8 +61,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -75,8 +75,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -90,8 +90,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -106,8 +106,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", and 36 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -123,8 +123,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 28 more"` + expect(stringifyZodError(result.error)).toEqual( + "type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'" ); }); @@ -141,9 +141,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"` - ); + expect(stringifyZodError(result.error)).toEqual('risk_score: Required'); }); test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { @@ -160,9 +158,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"` - ); + expect(stringifyZodError(result.error)).toEqual('risk_score: Required'); }); test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { @@ -180,9 +176,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"` - ); + expect(stringifyZodError(result.error)).toEqual('risk_score: Required'); }); test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => { @@ -222,9 +216,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", risk_score: Required, risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('risk_score: Required'); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => { @@ -390,8 +382,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"references.0: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", references.0: Expected string, received number, references.0: Expected string, received number, and 22 more"` + expect(stringifyZodError(result.error)).toEqual( + 'references.0: Expected string, received number' ); }); @@ -403,9 +395,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` - ); + expect(stringifyZodError(result.error)).toEqual('index.0: Expected string, received number'); }); test('saved_query type can have filters with it', () => { @@ -427,9 +417,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` - ); + expect(stringifyZodError(result.error)).toEqual('filters: Expected array, received string'); }); test('language validates with kuery', () => { @@ -462,8 +450,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 19 more"` + expect(stringifyZodError(result.error)).toEqual( + "language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up'" ); }); @@ -523,8 +511,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"tags.0: Expected string, received number, tags.1: Expected string, received number, tags.2: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", and 38 more"` + expect(stringifyZodError(result.error)).toEqual( + 'tags.0: Expected string, received number, tags.1: Expected string, received number, tags.2: Expected string, received number' ); }); @@ -551,9 +539,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"threat.0.framework: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", threat.0.framework: Required, threat.0.framework: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('threat.0.framework: Required'); }); test('You cannot send in an array of threat that are missing "tactic"', () => { @@ -575,9 +561,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"threat.0.tactic: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", threat.0.tactic: Required, threat.0.tactic: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('threat.0.tactic: Required'); }); test('You can send in an array of threat that are missing "technique"', () => { @@ -619,8 +603,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"false_positives.0: Expected string, received number, false_positives.1: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", false_positives.0: Expected string, received number, and 30 more"` + expect(stringifyZodError(result.error)).toEqual( + 'false_positives.0: Expected string, received number, false_positives.1: Expected string, received number' ); }); @@ -693,9 +677,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"meta: Expected object, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", meta: Expected object, received string, meta: Expected object, received string, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('meta: Expected object, received string'); }); test('You can omit the query string when filters are present', () => { @@ -730,8 +712,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', and 22 more"` + expect(stringifyZodError(result.error)).toEqual( + "severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk'" ); }); @@ -743,9 +725,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"actions.0.group: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.group: Required, actions.0.group: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('actions.0.group: Required'); }); test('You cannot send in an array of actions that are missing "id"', () => { @@ -756,9 +736,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"actions.0.id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.id: Required, actions.0.id: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('actions.0.id: Required'); }); test('You cannot send in an array of actions that are missing "action_type_id"', () => { @@ -769,9 +747,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"actions.0.action_type_id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.action_type_id: Required, actions.0.action_type_id: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('actions.0.action_type_id: Required'); }); test('You cannot send in an array of actions that are missing "params"', () => { @@ -782,9 +758,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"actions.0.params: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.params: Required, actions.0.params: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('actions.0.params: Required'); }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { @@ -802,9 +776,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"actions.0.action_type_id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.action_type_id: Required, actions.0.action_type_id: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('actions.0.action_type_id: Required'); }); describe('note', () => { @@ -840,9 +812,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"note: Expected string, received object, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", note: Expected string, received object, note: Expected string, received object, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('note: Expected string, received object'); }); test('empty name is not valid', () => { @@ -926,9 +896,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", saved_id: Required, type: Invalid literal value, expected \\"threshold\\", and 14 more"` - ); + expect(stringifyZodError(result.error)).toEqual('saved_id: Required'); }); test('threshold is required when type is threshold and will not validate without it', () => { @@ -936,9 +904,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 14 more"` - ); + expect(stringifyZodError(result.error)).toEqual('threshold: Required'); }); test('threshold rules fail validation if threshold is not greater than 0', () => { @@ -1016,8 +982,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"exceptions_list.0.list_id: Required, exceptions_list.0.type: Required, exceptions_list.0.namespace_type: Invalid enum value. Expected 'agnostic' | 'single', received 'not a namespace type', type: Invalid literal value, expected \\"eql\\", query: Required, and 43 more"` + expect(stringifyZodError(result.error)).toEqual( + "exceptions_list.0.list_id: Required, exceptions_list.0.type: Required, exceptions_list.0.namespace_type: Invalid enum value. Expected 'agnostic' | 'single', received 'not a namespace type'" ); }); @@ -1059,8 +1025,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 14 more"` + expect(stringifyZodError(result.error)).toEqual( + 'threat_query: Required, threat_mapping: Required, threat_index: Required' ); }); @@ -1130,8 +1096,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", data_view_id: Expected string, received number, data_view_id: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` + expect(stringifyZodError(result.error)).toEqual( + 'data_view_id: Expected string, received number' ); }); @@ -1195,9 +1161,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"investigation_fields.field_names: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields.field_names: Required, investigation_fields.field_names: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('investigation_fields.field_names: Required'); }); test('You can send in investigation_fields', () => { @@ -1232,8 +1196,8 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"investigation_fields.field_names.0: Expected string, received number, investigation_fields.field_names.1: Expected string, received number, investigation_fields.field_names.2: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", and 38 more"` + expect(stringifyZodError(result.error)).toEqual( + 'investigation_fields.field_names.0: Expected string, received number, investigation_fields.field_names.1: Expected string, received number, investigation_fields.field_names.2: Expected string, received number' ); }); @@ -1245,9 +1209,7 @@ describe('rules schema', () => { const result = RuleCreateProps.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"investigation_fields.field_names: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields.field_names: Required, investigation_fields.field_names: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toEqual('investigation_fields.field_names: Required'); }); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts index d1432e5a6735..e05aa65c4fa0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts @@ -41,7 +41,7 @@ describe('Rule response schema', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 15 more"` + `"type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -70,9 +70,7 @@ describe('Rule response schema', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", saved_id: Required, type: Invalid literal value, expected \\"threshold\\", and 14 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"saved_id: Required"`); }); test('it should validate a type of "timeline_id" if there is a "timeline_title" dependent', () => { @@ -103,7 +101,7 @@ describe('Rule response schema', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"exceptions_list: Expected array, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", exceptions_list: Expected array, received string, exceptions_list: Expected array, received string, and 22 more"` + `"exceptions_list: Expected array, received string"` ); }); }); @@ -239,7 +237,7 @@ describe('investigation_fields', () => { const result = RuleResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"investigation_fields: Expected object, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields: Expected object, received string, investigation_fields: Expected object, received string, and 22 more"` + `"investigation_fields: Expected object, received string"` ); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index ff99655a75e8..1051f59feac0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -131,20 +131,20 @@ export const BaseDefaultableFields = z.object({ export type BaseCreateProps = z.infer; export const BaseCreateProps = - BaseRequiredFields.and(BaseOptionalFields).and(BaseDefaultableFields); + BaseRequiredFields.merge(BaseOptionalFields).merge(BaseDefaultableFields); export type BasePatchProps = z.infer; export const BasePatchProps = BaseRequiredFields.partial() - .and(BaseOptionalFields) - .and(BaseDefaultableFields); + .merge(BaseOptionalFields) + .merge(BaseDefaultableFields); export type BaseResponseProps = z.infer; -export const BaseResponseProps = BaseRequiredFields.and(BaseOptionalFields).and( +export const BaseResponseProps = BaseRequiredFields.merge(BaseOptionalFields).merge( BaseDefaultableFields.required() ); -export type ResponseRequiredFields = z.infer; -export const ResponseRequiredFields = z.object({ +export type ResponseFields = z.infer; +export const ResponseFields = z.object({ id: RuleObjectId, rule_id: RuleSignatureId, immutable: IsRuleImmutable, @@ -156,22 +156,18 @@ export const ResponseRequiredFields = z.object({ related_integrations: RelatedIntegrationArray, required_fields: RequiredFieldArray, setup: SetupGuide, -}); - -export type ResponseOptionalFields = z.infer; -export const ResponseOptionalFields = z.object({ execution_summary: RuleExecutionSummary.optional(), }); export type SharedCreateProps = z.infer; -export const SharedCreateProps = BaseCreateProps.and( +export const SharedCreateProps = BaseCreateProps.merge( z.object({ rule_id: RuleSignatureId.optional(), }) ); export type SharedUpdateProps = z.infer; -export const SharedUpdateProps = BaseCreateProps.and( +export const SharedUpdateProps = BaseCreateProps.merge( z.object({ id: RuleObjectId.optional(), rule_id: RuleSignatureId.optional(), @@ -179,7 +175,7 @@ export const SharedUpdateProps = BaseCreateProps.and( ); export type SharedPatchProps = z.infer; -export const SharedPatchProps = BasePatchProps.and( +export const SharedPatchProps = BasePatchProps.merge( z.object({ id: RuleObjectId.optional(), rule_id: RuleSignatureId.optional(), @@ -187,8 +183,7 @@ export const SharedPatchProps = BasePatchProps.and( ); export type SharedResponseProps = z.infer; -export const SharedResponseProps = - BaseResponseProps.and(ResponseRequiredFields).and(ResponseOptionalFields); +export const SharedResponseProps = BaseResponseProps.merge(ResponseFields); export type EqlQueryLanguage = z.infer; export const EqlQueryLanguage = z.literal('eql'); @@ -220,25 +215,25 @@ export const EqlOptionalFields = z.object({ }); export type EqlRuleCreateFields = z.infer; -export const EqlRuleCreateFields = EqlRequiredFields.and(EqlOptionalFields); +export const EqlRuleCreateFields = EqlRequiredFields.merge(EqlOptionalFields); export type EqlRuleResponseFields = z.infer; -export const EqlRuleResponseFields = EqlRequiredFields.and(EqlOptionalFields); +export const EqlRuleResponseFields = EqlRequiredFields.merge(EqlOptionalFields); export type EqlRulePatchFields = z.infer; -export const EqlRulePatchFields = EqlRequiredFields.partial().and(EqlOptionalFields); +export const EqlRulePatchFields = EqlRequiredFields.partial().merge(EqlOptionalFields); export type EqlRule = z.infer; -export const EqlRule = SharedResponseProps.and(EqlRuleResponseFields); +export const EqlRule = SharedResponseProps.merge(EqlRuleResponseFields); export type EqlRuleCreateProps = z.infer; -export const EqlRuleCreateProps = SharedCreateProps.and(EqlRuleCreateFields); +export const EqlRuleCreateProps = SharedCreateProps.merge(EqlRuleCreateFields); export type EqlRuleUpdateProps = z.infer; -export const EqlRuleUpdateProps = SharedUpdateProps.and(EqlRuleCreateFields); +export const EqlRuleUpdateProps = SharedUpdateProps.merge(EqlRuleCreateFields); export type EqlRulePatchProps = z.infer; -export const EqlRulePatchProps = SharedPatchProps.and(EqlRulePatchFields); +export const EqlRulePatchProps = SharedPatchProps.merge(EqlRulePatchFields); export type QueryRuleRequiredFields = z.infer; export const QueryRuleRequiredFields = z.object({ @@ -265,31 +260,31 @@ export const QueryRuleDefaultableFields = z.object({ }); export type QueryRuleCreateFields = z.infer; -export const QueryRuleCreateFields = QueryRuleRequiredFields.and(QueryRuleOptionalFields).and( +export const QueryRuleCreateFields = QueryRuleRequiredFields.merge(QueryRuleOptionalFields).merge( QueryRuleDefaultableFields ); export type QueryRulePatchFields = z.infer; export const QueryRulePatchFields = QueryRuleRequiredFields.partial() - .and(QueryRuleOptionalFields) - .and(QueryRuleDefaultableFields); + .merge(QueryRuleOptionalFields) + .merge(QueryRuleDefaultableFields); export type QueryRuleResponseFields = z.infer; -export const QueryRuleResponseFields = QueryRuleRequiredFields.and(QueryRuleOptionalFields).and( +export const QueryRuleResponseFields = QueryRuleRequiredFields.merge(QueryRuleOptionalFields).merge( QueryRuleDefaultableFields.required() ); export type QueryRule = z.infer; -export const QueryRule = SharedResponseProps.and(QueryRuleResponseFields); +export const QueryRule = SharedResponseProps.merge(QueryRuleResponseFields); export type QueryRuleCreateProps = z.infer; -export const QueryRuleCreateProps = SharedCreateProps.and(QueryRuleCreateFields); +export const QueryRuleCreateProps = SharedCreateProps.merge(QueryRuleCreateFields); export type QueryRuleUpdateProps = z.infer; -export const QueryRuleUpdateProps = SharedUpdateProps.and(QueryRuleCreateFields); +export const QueryRuleUpdateProps = SharedUpdateProps.merge(QueryRuleCreateFields); export type QueryRulePatchProps = z.infer; -export const QueryRulePatchProps = SharedPatchProps.and(QueryRulePatchFields); +export const QueryRulePatchProps = SharedPatchProps.merge(QueryRulePatchFields); export type SavedQueryRuleRequiredFields = z.infer; export const SavedQueryRuleRequiredFields = z.object({ @@ -316,31 +311,31 @@ export const SavedQueryRuleDefaultableFields = z.object({ }); export type SavedQueryRuleCreateFields = z.infer; -export const SavedQueryRuleCreateFields = SavedQueryRuleRequiredFields.and( +export const SavedQueryRuleCreateFields = SavedQueryRuleRequiredFields.merge( SavedQueryRuleOptionalFields -).and(SavedQueryRuleDefaultableFields); +).merge(SavedQueryRuleDefaultableFields); export type SavedQueryRulePatchFields = z.infer; export const SavedQueryRulePatchFields = SavedQueryRuleRequiredFields.partial() - .and(SavedQueryRuleOptionalFields) - .and(SavedQueryRuleDefaultableFields); + .merge(SavedQueryRuleOptionalFields) + .merge(SavedQueryRuleDefaultableFields); export type SavedQueryRuleResponseFields = z.infer; -export const SavedQueryRuleResponseFields = SavedQueryRuleRequiredFields.and( +export const SavedQueryRuleResponseFields = SavedQueryRuleRequiredFields.merge( SavedQueryRuleOptionalFields -).and(SavedQueryRuleDefaultableFields.required()); +).merge(SavedQueryRuleDefaultableFields.required()); export type SavedQueryRule = z.infer; -export const SavedQueryRule = SharedResponseProps.and(SavedQueryRuleResponseFields); +export const SavedQueryRule = SharedResponseProps.merge(SavedQueryRuleResponseFields); export type SavedQueryRuleCreateProps = z.infer; -export const SavedQueryRuleCreateProps = SharedCreateProps.and(SavedQueryRuleCreateFields); +export const SavedQueryRuleCreateProps = SharedCreateProps.merge(SavedQueryRuleCreateFields); export type SavedQueryRuleUpdateProps = z.infer; -export const SavedQueryRuleUpdateProps = SharedUpdateProps.and(SavedQueryRuleCreateFields); +export const SavedQueryRuleUpdateProps = SharedUpdateProps.merge(SavedQueryRuleCreateFields); export type SavedQueryRulePatchProps = z.infer; -export const SavedQueryRulePatchProps = SharedPatchProps.and(SavedQueryRulePatchFields); +export const SavedQueryRulePatchProps = SharedPatchProps.merge(SavedQueryRulePatchFields); export type ThresholdRuleRequiredFields = z.infer; export const ThresholdRuleRequiredFields = z.object({ @@ -366,31 +361,31 @@ export const ThresholdRuleDefaultableFields = z.object({ }); export type ThresholdRuleCreateFields = z.infer; -export const ThresholdRuleCreateFields = ThresholdRuleRequiredFields.and( +export const ThresholdRuleCreateFields = ThresholdRuleRequiredFields.merge( ThresholdRuleOptionalFields -).and(ThresholdRuleDefaultableFields); +).merge(ThresholdRuleDefaultableFields); export type ThresholdRulePatchFields = z.infer; export const ThresholdRulePatchFields = ThresholdRuleRequiredFields.partial() - .and(ThresholdRuleOptionalFields) - .and(ThresholdRuleDefaultableFields); + .merge(ThresholdRuleOptionalFields) + .merge(ThresholdRuleDefaultableFields); export type ThresholdRuleResponseFields = z.infer; -export const ThresholdRuleResponseFields = ThresholdRuleRequiredFields.and( +export const ThresholdRuleResponseFields = ThresholdRuleRequiredFields.merge( ThresholdRuleOptionalFields -).and(ThresholdRuleDefaultableFields.required()); +).merge(ThresholdRuleDefaultableFields.required()); export type ThresholdRule = z.infer; -export const ThresholdRule = SharedResponseProps.and(ThresholdRuleResponseFields); +export const ThresholdRule = SharedResponseProps.merge(ThresholdRuleResponseFields); export type ThresholdRuleCreateProps = z.infer; -export const ThresholdRuleCreateProps = SharedCreateProps.and(ThresholdRuleCreateFields); +export const ThresholdRuleCreateProps = SharedCreateProps.merge(ThresholdRuleCreateFields); export type ThresholdRuleUpdateProps = z.infer; -export const ThresholdRuleUpdateProps = SharedUpdateProps.and(ThresholdRuleCreateFields); +export const ThresholdRuleUpdateProps = SharedUpdateProps.merge(ThresholdRuleCreateFields); export type ThresholdRulePatchProps = z.infer; -export const ThresholdRulePatchProps = SharedPatchProps.and(ThresholdRulePatchFields); +export const ThresholdRulePatchProps = SharedPatchProps.merge(ThresholdRulePatchFields); export type ThreatMatchRuleRequiredFields = z.infer; export const ThreatMatchRuleRequiredFields = z.object({ @@ -423,31 +418,31 @@ export const ThreatMatchRuleDefaultableFields = z.object({ }); export type ThreatMatchRuleCreateFields = z.infer; -export const ThreatMatchRuleCreateFields = ThreatMatchRuleRequiredFields.and( +export const ThreatMatchRuleCreateFields = ThreatMatchRuleRequiredFields.merge( ThreatMatchRuleOptionalFields -).and(ThreatMatchRuleDefaultableFields); +).merge(ThreatMatchRuleDefaultableFields); export type ThreatMatchRulePatchFields = z.infer; export const ThreatMatchRulePatchFields = ThreatMatchRuleRequiredFields.partial() - .and(ThreatMatchRuleOptionalFields) - .and(ThreatMatchRuleDefaultableFields); + .merge(ThreatMatchRuleOptionalFields) + .merge(ThreatMatchRuleDefaultableFields); export type ThreatMatchRuleResponseFields = z.infer; -export const ThreatMatchRuleResponseFields = ThreatMatchRuleRequiredFields.and( +export const ThreatMatchRuleResponseFields = ThreatMatchRuleRequiredFields.merge( ThreatMatchRuleOptionalFields -).and(ThreatMatchRuleDefaultableFields.required()); +).merge(ThreatMatchRuleDefaultableFields.required()); export type ThreatMatchRule = z.infer; -export const ThreatMatchRule = SharedResponseProps.and(ThreatMatchRuleResponseFields); +export const ThreatMatchRule = SharedResponseProps.merge(ThreatMatchRuleResponseFields); export type ThreatMatchRuleCreateProps = z.infer; -export const ThreatMatchRuleCreateProps = SharedCreateProps.and(ThreatMatchRuleCreateFields); +export const ThreatMatchRuleCreateProps = SharedCreateProps.merge(ThreatMatchRuleCreateFields); export type ThreatMatchRuleUpdateProps = z.infer; -export const ThreatMatchRuleUpdateProps = SharedUpdateProps.and(ThreatMatchRuleCreateFields); +export const ThreatMatchRuleUpdateProps = SharedUpdateProps.merge(ThreatMatchRuleCreateFields); export type ThreatMatchRulePatchProps = z.infer; -export const ThreatMatchRulePatchProps = SharedPatchProps.and(ThreatMatchRulePatchFields); +export const ThreatMatchRulePatchProps = SharedPatchProps.merge(ThreatMatchRulePatchFields); export type MachineLearningRuleRequiredFields = z.infer; export const MachineLearningRuleRequiredFields = z.object({ @@ -469,20 +464,20 @@ export type MachineLearningRuleCreateFields = z.infer; -export const MachineLearningRule = SharedResponseProps.and(MachineLearningRuleResponseFields); +export const MachineLearningRule = SharedResponseProps.merge(MachineLearningRuleResponseFields); export type MachineLearningRuleCreateProps = z.infer; -export const MachineLearningRuleCreateProps = SharedCreateProps.and( +export const MachineLearningRuleCreateProps = SharedCreateProps.merge( MachineLearningRuleCreateFields ); export type MachineLearningRuleUpdateProps = z.infer; -export const MachineLearningRuleUpdateProps = SharedUpdateProps.and( +export const MachineLearningRuleUpdateProps = SharedUpdateProps.merge( MachineLearningRuleCreateFields ); export type MachineLearningRulePatchProps = z.infer; -export const MachineLearningRulePatchProps = SharedPatchProps.and(MachineLearningRulePatchFields); +export const MachineLearningRulePatchProps = SharedPatchProps.merge(MachineLearningRulePatchFields); export type NewTermsRuleRequiredFields = z.infer; export const NewTermsRuleRequiredFields = z.object({ @@ -509,30 +504,30 @@ export const NewTermsRuleDefaultableFields = z.object({ export type NewTermsRulePatchFields = z.infer; export const NewTermsRulePatchFields = NewTermsRuleRequiredFields.partial() - .and(NewTermsRuleOptionalFields) - .and(NewTermsRuleDefaultableFields); + .merge(NewTermsRuleOptionalFields) + .merge(NewTermsRuleDefaultableFields); export type NewTermsRuleResponseFields = z.infer; -export const NewTermsRuleResponseFields = NewTermsRuleRequiredFields.and( +export const NewTermsRuleResponseFields = NewTermsRuleRequiredFields.merge( NewTermsRuleOptionalFields -).and(NewTermsRuleDefaultableFields.required()); +).merge(NewTermsRuleDefaultableFields.required()); export type NewTermsRuleCreateFields = z.infer; -export const NewTermsRuleCreateFields = NewTermsRuleRequiredFields.and( +export const NewTermsRuleCreateFields = NewTermsRuleRequiredFields.merge( NewTermsRuleOptionalFields -).and(NewTermsRuleDefaultableFields); +).merge(NewTermsRuleDefaultableFields); export type NewTermsRule = z.infer; -export const NewTermsRule = SharedResponseProps.and(NewTermsRuleResponseFields); +export const NewTermsRule = SharedResponseProps.merge(NewTermsRuleResponseFields); export type NewTermsRuleCreateProps = z.infer; -export const NewTermsRuleCreateProps = SharedCreateProps.and(NewTermsRuleCreateFields); +export const NewTermsRuleCreateProps = SharedCreateProps.merge(NewTermsRuleCreateFields); export type NewTermsRuleUpdateProps = z.infer; -export const NewTermsRuleUpdateProps = SharedUpdateProps.and(NewTermsRuleCreateFields); +export const NewTermsRuleUpdateProps = SharedUpdateProps.merge(NewTermsRuleCreateFields); export type NewTermsRulePatchProps = z.infer; -export const NewTermsRulePatchProps = SharedPatchProps.and(NewTermsRulePatchFields); +export const NewTermsRulePatchProps = SharedPatchProps.merge(NewTermsRulePatchFields); export type EsqlQueryLanguage = z.infer; export const EsqlQueryLanguage = z.literal('esql'); @@ -560,19 +555,19 @@ export type EsqlRuleCreateFields = z.infer; export const EsqlRuleCreateFields = EsqlRuleRequiredFields; export type EsqlRule = z.infer; -export const EsqlRule = SharedResponseProps.and(EsqlRuleResponseFields); +export const EsqlRule = SharedResponseProps.merge(EsqlRuleResponseFields); export type EsqlRuleCreateProps = z.infer; -export const EsqlRuleCreateProps = SharedCreateProps.and(EsqlRuleCreateFields); +export const EsqlRuleCreateProps = SharedCreateProps.merge(EsqlRuleCreateFields); export type EsqlRuleUpdateProps = z.infer; -export const EsqlRuleUpdateProps = SharedUpdateProps.and(EsqlRuleCreateFields); +export const EsqlRuleUpdateProps = SharedUpdateProps.merge(EsqlRuleCreateFields); export type EsqlRulePatchProps = z.infer; -export const EsqlRulePatchProps = SharedPatchProps.and(EsqlRulePatchFields.partial()); +export const EsqlRulePatchProps = SharedPatchProps.merge(EsqlRulePatchFields.partial()); export type TypeSpecificCreateProps = z.infer; -export const TypeSpecificCreateProps = z.union([ +export const TypeSpecificCreateProps = z.discriminatedUnion('type', [ EqlRuleCreateFields, QueryRuleCreateFields, SavedQueryRuleCreateFields, @@ -596,7 +591,7 @@ export const TypeSpecificPatchProps = z.union([ ]); export type TypeSpecificResponse = z.infer; -export const TypeSpecificResponse = z.union([ +export const TypeSpecificResponse = z.discriminatedUnion('type', [ EqlRuleResponseFields, QueryRuleResponseFields, SavedQueryRuleResponseFields, @@ -608,7 +603,7 @@ export const TypeSpecificResponse = z.union([ ]); export type RuleCreateProps = z.infer; -export const RuleCreateProps = z.union([ +export const RuleCreateProps = z.discriminatedUnion('type', [ EqlRuleCreateProps, QueryRuleCreateProps, SavedQueryRuleCreateProps, @@ -620,7 +615,7 @@ export const RuleCreateProps = z.union([ ]); export type RuleUpdateProps = z.infer; -export const RuleUpdateProps = z.union([ +export const RuleUpdateProps = z.discriminatedUnion('type', [ EqlRuleUpdateProps, QueryRuleUpdateProps, SavedQueryRuleUpdateProps, @@ -644,7 +639,7 @@ export const RulePatchProps = z.union([ ]); export type RuleResponse = z.infer; -export const RuleResponse = z.union([ +export const RuleResponse = z.discriminatedUnion('type', [ EqlRule, QueryRule, SavedQueryRule, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 955916b939e8..a916e7e4da22 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -7,6 +7,7 @@ components: x-codegen-enabled: true schemas: BaseRequiredFields: + x-inline: true type: object properties: name: @@ -24,6 +25,7 @@ components: - severity BaseOptionalFields: + x-inline: true type: object properties: # Field overrides @@ -73,6 +75,7 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' BaseDefaultableFields: + x-inline: true type: object properties: # Main attributes @@ -127,12 +130,14 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/ThreatArray' BaseCreateProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseRequiredFields' - $ref: '#/components/schemas/BaseOptionalFields' - $ref: '#/components/schemas/BaseDefaultableFields' BasePatchProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseRequiredFields' x-modify: partial @@ -140,13 +145,14 @@ components: - $ref: '#/components/schemas/BaseDefaultableFields' BaseResponseProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseRequiredFields' - $ref: '#/components/schemas/BaseOptionalFields' - $ref: '#/components/schemas/BaseDefaultableFields' x-modify: required - ResponseRequiredFields: + ResponseFields: type: object properties: id: @@ -179,6 +185,8 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RequiredFieldArray' setup: $ref: './common_attributes.schema.yaml#/components/schemas/SetupGuide' + execution_summary: + $ref: '../../rule_monitoring/model/execution_summary.schema.yaml#/components/schemas/RuleExecutionSummary' required: - id - rule_id @@ -192,13 +200,8 @@ components: - required_fields - setup - ResponseOptionalFields: - type: object - properties: - execution_summary: - $ref: '../../rule_monitoring/model/execution_summary.schema.yaml#/components/schemas/RuleExecutionSummary' - SharedCreateProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseCreateProps' - type: object @@ -207,6 +210,7 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' SharedUpdateProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseCreateProps' - type: object @@ -217,6 +221,7 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' SharedPatchProps: + x-inline: true allOf: - $ref: '#/components/schemas/BasePatchProps' - type: object @@ -227,10 +232,10 @@ components: $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' SharedResponseProps: + x-inline: true allOf: - $ref: '#/components/schemas/BaseResponseProps' - - $ref: '#/components/schemas/ResponseRequiredFields' - - $ref: '#/components/schemas/ResponseOptionalFields' + - $ref: '#/components/schemas/ResponseFields' ############ # EQL Rule # @@ -841,6 +846,8 @@ components: ########################## TypeSpecificCreateProps: + discriminator: + propertyName: type anyOf: - $ref: '#/components/schemas/EqlRuleCreateFields' - $ref: '#/components/schemas/QueryRuleCreateFields' @@ -863,6 +870,8 @@ components: - $ref: '#/components/schemas/EsqlRulePatchFields' TypeSpecificResponse: + discriminator: + propertyName: type anyOf: - $ref: '#/components/schemas/EqlRuleResponseFields' - $ref: '#/components/schemas/QueryRuleResponseFields' @@ -874,6 +883,8 @@ components: - $ref: '#/components/schemas/EsqlRuleResponseFields' RuleCreateProps: + discriminator: + propertyName: type anyOf: - $ref: '#/components/schemas/EqlRuleCreateProps' - $ref: '#/components/schemas/QueryRuleCreateProps' @@ -885,6 +896,8 @@ components: - $ref: '#/components/schemas/EsqlRuleCreateProps' RuleUpdateProps: + discriminator: + propertyName: type anyOf: - $ref: '#/components/schemas/EqlRuleUpdateProps' - $ref: '#/components/schemas/QueryRuleUpdateProps' @@ -907,6 +920,8 @@ components: - $ref: '#/components/schemas/EsqlRulePatchProps' RuleResponse: + discriminator: + propertyName: type anyOf: - $ref: '#/components/schemas/EqlRule' - $ref: '#/components/schemas/QueryRule' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts index bfbba49bb80e..44d302373944 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts @@ -107,3 +107,6 @@ export const alert_tags = t.type({ }); export type AlertTags = t.TypeOf; + +export const user_search_term = t.string; +export type UserSearchTerm = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml index 889d7321c0be..3a7a19611a14 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Prebuilt Rules Status API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/prepackaged/_status: get: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml index 158b8667bb61..3aeb1b04317f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Install Prebuilt Rules API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/prepackaged: put: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts index d11eea7b1671..6d3594335e49 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts @@ -105,35 +105,35 @@ export const BulkActionBase = z.object({ }); export type BulkDeleteRules = z.infer; -export const BulkDeleteRules = BulkActionBase.and( +export const BulkDeleteRules = BulkActionBase.merge( z.object({ action: z.literal('delete'), }) ); export type BulkDisableRules = z.infer; -export const BulkDisableRules = BulkActionBase.and( +export const BulkDisableRules = BulkActionBase.merge( z.object({ action: z.literal('disable'), }) ); export type BulkEnableRules = z.infer; -export const BulkEnableRules = BulkActionBase.and( +export const BulkEnableRules = BulkActionBase.merge( z.object({ action: z.literal('enable'), }) ); export type BulkExportRules = z.infer; -export const BulkExportRules = BulkActionBase.and( +export const BulkExportRules = BulkActionBase.merge( z.object({ action: z.literal('export'), }) ); export type BulkDuplicateRules = z.infer; -export const BulkDuplicateRules = BulkActionBase.and( +export const BulkDuplicateRules = BulkActionBase.merge( z.object({ action: z.literal('duplicate'), duplicate: z @@ -254,7 +254,7 @@ export const BulkActionEditPayload = z.union([ ]); export type BulkEditRules = z.infer; -export const BulkEditRules = BulkActionBase.and( +export const BulkEditRules = BulkActionBase.merge( z.object({ action: z.literal('edit'), /** diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml index 583782f086ae..10422772785e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Bulk Actions API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_bulk_action: post: @@ -169,6 +169,7 @@ components: type: string BulkActionBase: + x-inline: true type: object properties: query: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml index ee02ec47c59b..3b5d56f5b736 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Bulk Create API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_bulk_create: post: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts index 2e6cff31f8f7..52c7d5e097cc 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts @@ -27,7 +27,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, 0.type: Invalid literal value, expected \\"eql\\", and 52 more"` + `"0.type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -58,9 +58,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0.risk_score: Required"`); }); test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => { @@ -72,9 +70,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"1.risk_score: Required, 1.type: Invalid literal value, expected \\"eql\\", 1.language: Invalid literal value, expected \\"eql\\", 1.risk_score: Required, 1.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1.risk_score: Required"`); }); test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => { @@ -86,9 +82,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0.risk_score: Required"`); }); test('two array elements where both are invalid (risk_score) will not validate', () => { @@ -103,7 +97,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 49 more"` + `"0.risk_score: Required, 1.risk_score: Required"` ); }); @@ -130,7 +124,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', and 22 more"` + `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup'"` ); }); @@ -165,7 +159,7 @@ describe('Bulk create rules request schema', () => { const result = BulkCreateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.note: Expected string, received object, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.note: Expected string, received object, 0.note: Expected string, received object, and 22 more"` + `"0.note: Expected string, received object"` ); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml index 85bdb7027447..8438bb5b6005 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Bulk Delete API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_bulk_delete: delete: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml index eb4ea8a06fc8..7ba82e4ad367 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Bulk Patch API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_bulk_update: patch: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml index 5259a677bc1f..6f85e51c6a01 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Bulk Update API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_bulk_update: put: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts index 3fa69c6ad24d..f7e193856d0e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts @@ -28,7 +28,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, 0.type: Invalid literal value, expected \\"eql\\", and 52 more"` + `"0.type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -59,9 +59,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0.risk_score: Required"`); }); test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => { @@ -73,9 +71,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"1.risk_score: Required, 1.type: Invalid literal value, expected \\"eql\\", 1.language: Invalid literal value, expected \\"eql\\", 1.risk_score: Required, 1.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1.risk_score: Required"`); }); test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => { @@ -87,9 +83,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); - expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"` - ); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0.risk_score: Required"`); }); test('two array elements where both are invalid (risk_score) will not validate', () => { @@ -104,7 +98,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 49 more"` + `"0.risk_score: Required, 1.risk_score: Required"` ); }); @@ -131,7 +125,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', and 22 more"` + `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup'"` ); }); @@ -176,7 +170,7 @@ describe('Bulk update rules request schema', () => { const result = BulkUpdateRulesRequestBody.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.note: Expected string, received object, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.note: Expected string, received object, 0.note: Expected string, received object, and 22 more"` + `"0.note: Expected string, received object"` ); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts index 413d83f9fee0..2d4af1c18f6d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts @@ -46,7 +46,7 @@ describe('Bulk CRUD rules response schema', () => { const result = BulkCrudRulesResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.error: Required, 0: Unrecognized key(s) in object: 'author', 'created_at', 'updated_at', 'created_by', 'description', 'enabled', 'false_positives', 'from', 'immutable', 'references', 'revision', 'severity', 'severity_mapping', 'updated_by', 'tags', 'to', 'threat', 'version', 'output_index', 'max_signals', 'risk_score', 'risk_score_mapping', 'interval', 'exceptions_list', 'related_integrations', 'required_fields', 'setup', 'throttle', 'actions', 'building_block_type', 'note', 'license', 'outcome', 'alias_target_id', 'alias_purpose', 'timeline_id', 'timeline_title', 'meta', 'rule_name_override', 'timestamp_override', 'timestamp_override_fallback_disabled', 'namespace', 'investigation_fields', 'query', 'type', 'language', 'index', 'data_view_id', 'filters', 'saved_id', 'response_actions', 'alert_suppression', 0.name: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", and 24 more"` + `"0.name: Required, 0.error: Required, 0: Unrecognized key(s) in object: 'author', 'created_at', 'updated_at', 'created_by', 'description', 'enabled', 'false_positives', 'from', 'immutable', 'references', 'revision', 'severity', 'severity_mapping', 'updated_by', 'tags', 'to', 'threat', 'version', 'output_index', 'max_signals', 'risk_score', 'risk_score_mapping', 'interval', 'exceptions_list', 'related_integrations', 'required_fields', 'setup', 'throttle', 'actions', 'building_block_type', 'note', 'license', 'outcome', 'alias_target_id', 'alias_purpose', 'timeline_id', 'timeline_title', 'meta', 'rule_name_override', 'timestamp_override', 'timestamp_override_fallback_disabled', 'namespace', 'investigation_fields', 'query', 'type', 'language', 'index', 'data_view_id', 'filters', 'saved_id', 'response_actions', 'alert_suppression'"` ); }); @@ -59,7 +59,7 @@ describe('Bulk CRUD rules response schema', () => { const result = BulkCrudRulesResponse.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"0.error: Required, 0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, and 267 more"` + `"0.type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', 0.error: Required"` ); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml index f3e49fc95a04..4dff72dc216e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Create Rule API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules: post: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml index 66236f70b9b6..be55d0add832 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Delete Rule API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules: delete: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml index 98a76e3712b4..df2bdb114c2e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Patch Rule API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules: patch: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml index 8713e295e8f3..bcb4cc83381d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Read Rule API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules: get: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml index 7adaca37a243..e32a3cd52e68 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Update Rule API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules: put: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml index 5b36290ddf17..73c60f76e19a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Export Rules API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_export: summary: Exports rules to an `.ndjson` file diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml index 4fa1c14542ed..4a37d1f9f5bc 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Find Rules API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_find: get: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml index e158434354fd..ddc0f063747e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Import Rules API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/rules/_import: summary: Imports rules from an `.ndjson` file diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.test.ts index f53f67757ccd..3f364c6619db 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.test.ts @@ -22,7 +22,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, rule_id: Required, and 25 more"` + `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', and 1 more"` ); }); @@ -47,7 +47,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", and 24 more"` + `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -61,7 +61,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 23 more"` + `"name: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -76,7 +76,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 23 more"` + `"name: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql'"` ); }); @@ -330,7 +330,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` + `"index.0: Expected string, received number"` ); }); @@ -378,7 +378,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` + `"filters: Expected array, received string"` ); }); @@ -414,7 +414,7 @@ describe('RuleToImport', () => { expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 19 more"` + `"language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up'"` ); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts index 5c9514943ac4..9634d773b121 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts @@ -8,7 +8,7 @@ import * as z from 'zod'; import { BaseCreateProps, - ResponseRequiredFields, + ResponseFields, RuleSignatureId, TypeSpecificCreateProps, } from '../../model/rule_schema'; @@ -26,7 +26,7 @@ import { export type RuleToImport = z.infer; export type RuleToImportInput = z.input; export const RuleToImport = BaseCreateProps.and(TypeSpecificCreateProps).and( - ResponseRequiredFields.partial().extend({ + ResponseFields.partial().extend({ rule_id: RuleSignatureId, immutable: z.literal(false).default(false), }) diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml index b9e79f252a26..ae4ef41a9ff3 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Tags API endpoint - version: 2023-10-31 + version: '2023-10-31' paths: /api/detection_engine/tags: summary: Aggregates and returns rule tags diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts new file mode 100644 index 000000000000..b4775b77bf69 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './suggest_user_profiles_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts new file mode 100644 index 000000000000..f403501c52ea --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.gen.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type SuggestUserProfilesRequestQuery = z.infer; +export const SuggestUserProfilesRequestQuery = z.object({ + /** + * Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email + */ + searchTerm: z.string().optional(), +}); +export type SuggestUserProfilesRequestQueryInput = z.input; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml new file mode 100644 index 000000000000..babaedf1486f --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.0 +info: + title: Suggest user profiles API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/_find: + summary: Suggests user profiles based on provided search term + post: + operationId: SuggestUserProfiles + x-codegen-enabled: true + description: Suggests user profiles. + parameters: + - name: searchTerm + in: query + required: false + description: "Query string used to match name-related fields in user profiles. The following fields are treated as name-related: username, full_name and email" + schema: + type: string + responses: + 200: + description: Indicates a successful call. + 400: + description: Invalid request. diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts index c332f23f2702..269f041a25a1 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/common/response_actions.ts @@ -5,7 +5,9 @@ * 2.0. */ +import type { TypeOf } from '@kbn/config-schema'; import { schema } from '@kbn/config-schema'; +import { UploadActionRequestSchema } from '../..'; import { ExecuteActionRequestSchema } from '../execute_route'; import { EndpointActionGetFileSchema } from '../get_file_route'; import { KillOrSuspendProcessRequestSchema, NoParametersRequestSchema } from './base'; @@ -15,4 +17,7 @@ export const ResponseActionBodySchema = schema.oneOf([ KillOrSuspendProcessRequestSchema.body, EndpointActionGetFileSchema.body, ExecuteActionRequestSchema.body, + UploadActionRequestSchema.body, ]); + +export type ResponseActionsRequestBody = TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/execute.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/execute.gen.ts index dbd24eef454d..12a227048d33 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/execute.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/execute.gen.ts @@ -15,7 +15,7 @@ import { z } from 'zod'; import { BaseActionSchema, Command, Timeout } from '../model/schema/common.gen'; export type ExecuteActionRequestBody = z.infer; -export const ExecuteActionRequestBody = BaseActionSchema.and( +export const ExecuteActionRequestBody = BaseActionSchema.merge( z.object({ parameters: z.object({ command: Command, diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/file_upload.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/file_upload.gen.ts index 785a4a1097e0..4f40d187e7e3 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/file_upload.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/file_upload.gen.ts @@ -15,7 +15,7 @@ import { z } from 'zod'; import { BaseActionSchema } from '../model/schema/common.gen'; export type FileUploadActionRequestBody = z.infer; -export const FileUploadActionRequestBody = BaseActionSchema.and( +export const FileUploadActionRequestBody = BaseActionSchema.merge( z.object({ parameters: z.object({ overwrite: z.boolean().optional().default(false), diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/get_file.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/get_file.gen.ts index 648f1700a54c..1b1513af9b13 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/get_file.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/get_file.gen.ts @@ -15,7 +15,7 @@ import { z } from 'zod'; import { BaseActionSchema } from '../model/schema/common.gen'; export type GetFileActionRequestBody = z.infer; -export const GetFileActionRequestBody = BaseActionSchema.and( +export const GetFileActionRequestBody = BaseActionSchema.merge( z.object({ parameters: z.object({ path: z.string(), diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/get_processes_route.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/get_processes_route.ts index e68194411748..a9e56e52ba29 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/get_processes_route.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/get_processes_route.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { TypeOf } from '@kbn/config-schema'; import { NoParametersRequestSchema } from './common/base'; export const GetProcessesRouteRequestSchema = NoParametersRequestSchema; +export type GetProcessesRequestBody = TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/isolate_route.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/isolate_route.ts index a58364c2be24..0df0d8d91345 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/isolate_route.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/isolate_route.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { TypeOf } from '@kbn/config-schema'; import { NoParametersRequestSchema } from './common/base'; export const IsolateRouteRequestSchema = NoParametersRequestSchema; +export type IsolationRouteRequestBody = TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/list.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/actions/list.gen.ts index 32844921170b..cc365bd92173 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/list.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/list.gen.ts @@ -23,8 +23,8 @@ import { WithOutputs, } from '../model/schema/common.gen'; -export type ListRequestQuery = z.infer; -export const ListRequestQuery = z.object({ +export type EndpointActionListRequestQuery = z.infer; +export const EndpointActionListRequestQuery = z.object({ agentIds: AgentIds.optional(), commands: Commands.optional(), page: Page.optional(), diff --git a/x-pack/plugins/security_solution/common/api/endpoint/actions/list.schema.yaml b/x-pack/plugins/security_solution/common/api/endpoint/actions/list.schema.yaml index c07ad4eb253b..71382eda8db5 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/actions/list.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/endpoint/actions/list.schema.yaml @@ -13,7 +13,7 @@ paths: in: query required: true schema: - $ref: '#/components/schemas/ListRequestQuery' + $ref: '#/components/schemas/EndpointActionListRequestQuery' responses: '200': description: OK @@ -23,7 +23,7 @@ paths: $ref: '../model/schema/common.schema.yaml#/components/schemas/SuccessResponse' components: schemas: - ListRequestQuery: + EndpointActionListRequestQuery: type: object properties: agentIds: diff --git a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts index 986260c2e463..c5fc0f38f6b0 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts @@ -145,7 +145,7 @@ export const BaseActionSchema = z.object({ }); export type ProcessActionSchemas = z.infer; -export const ProcessActionSchemas = BaseActionSchema.and( +export const ProcessActionSchemas = BaseActionSchema.merge( z.object({ parameters: z.union([ z.object({ diff --git a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.schema.yaml b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.schema.yaml index 15d69f3639d1..8d7da5177533 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.schema.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Common Endpoint Attributes version: '2023-10-31' -paths: { } +paths: {} components: schemas: Id: @@ -145,6 +145,7 @@ components: description: Optional parameters object BaseActionSchema: + x-inline: true type: object properties: endpoint_ids: @@ -181,4 +182,3 @@ components: type: object properties: {} # Define properties for the success response if needed - diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts new file mode 100644 index 000000000000..378aaa309858 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type IdField = z.infer; +export const IdField = z.enum(['host.name', 'user.name']); +export type IdFieldEnum = typeof IdField.enum; +export const IdFieldEnum = IdField.enum; + +export type AssetCriticalityRecordIdParts = z.infer; +export const AssetCriticalityRecordIdParts = z.object({ + /** + * The ID value of the asset. + */ + id_value: z.string(), + /** + * The field representing the ID. + */ + id_field: IdField, +}); + +export type CreateAssetCriticalityRecord = z.infer; +export const CreateAssetCriticalityRecord = AssetCriticalityRecordIdParts.merge( + z.object({ + /** + * The criticality level of the asset. + */ + criticality_level: z.enum(['very_important', 'important', 'normal', 'not_important']), + }) +); + +export type AssetCriticalityRecord = z.infer; +export const AssetCriticalityRecord = CreateAssetCriticalityRecord.merge( + z.object({ + /** + * The time the record was created or updated. + */ + '@timestamp': z.string().datetime(), + }) +); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml new file mode 100644 index 000000000000..3271f990931e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml @@ -0,0 +1,66 @@ +openapi: 3.0.0 +info: + title: Asset Criticality Common Schema + description: Common schema for asset criticality + version: 1.0.0 +paths: { } +components: + parameters: + id_value: + name: id_value + in: query + required: true + schema: + type: string + description: The ID value of the asset. + id_field: + name: id_field + in: query + required: true + schema: + $ref: '#/components/schemas/IdField' + example: 'host.name' + description: The field representing the ID. + + schemas: + IdField: + type: string + enum: + - 'host.name' + - 'user.name' + AssetCriticalityRecordIdParts: + type: object + properties: + id_value: + type: string + description: The ID value of the asset. + id_field: + $ref: '#/components/schemas/IdField' + example: 'host.name' + description: The field representing the ID. + required: + - id_value + - id_field + CreateAssetCriticalityRecord: + allOf: + - $ref: '#/components/schemas/AssetCriticalityRecordIdParts' + - type: object + properties: + criticality_level: + type: string + enum: [very_important, important, normal, not_important] + description: The criticality level of the asset. + required: + - criticality_level + AssetCriticalityRecord: + allOf: + - $ref: '#/components/schemas/CreateAssetCriticalityRecord' + - type: object + properties: + "@timestamp": + type: string + format: 'date-time' + example: '2017-07-21T17:32:28Z' + description: The time the record was created or updated. + required: + - "@timestamp" diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml new file mode 100644 index 000000000000..198fe9a35339 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml @@ -0,0 +1,23 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Asset Criticality Create Record Schema +paths: + /internal/asset_criticality: + post: + summary: Create Criticality Record + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAssetCriticalityRecord' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/SingleAssetCriticality' + '400': + description: Invalid request \ No newline at end of file diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml new file mode 100644 index 000000000000..e8334c48205f --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Asset Criticality Delete Record Schema +paths: + /internal/asset_criticality: + delete: + summary: Delete Criticality Record + parameters: + - $ref: '#/components/parameters/id_value' + - $ref: '#/components/parameters/id_field' + responses: + '200': + description: Successful response + '400': + description: Invalid request \ No newline at end of file diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml new file mode 100644 index 000000000000..2aa88dcbc862 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml @@ -0,0 +1,22 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Asset Criticality Get Record Schema +paths: + /internal/asset_criticality: + get: + summary: Get Criticality Record + parameters: + - $ref: '#/components/parameters/id_value' + - $ref: '#/components/parameters/id_field' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/SingleAssetCriticality' + '400': + description: Invalid request + '404': + description: Criticality record not found \ No newline at end of file diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.gen.ts new file mode 100644 index 000000000000..6e034ae654f6 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.gen.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type AssetCriticalityStatusResponse = z.infer; +export const AssetCriticalityStatusResponse = z.object({ + asset_criticality_resources_installed: z.boolean().optional(), +}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml new file mode 100644 index 000000000000..976833fae070 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality_status.schema.yaml @@ -0,0 +1,25 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Asset Criticality Status Schema +paths: + /internal/asset_criticality/status: + get: + summary: Get Asset Criticality Status + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/AssetCriticalityStatusResponse' + '400': + description: Invalid request + +components: + schemas: + AssetCriticalityStatusResponse: + type: object + properties: + asset_criticality_resources_installed: + type: boolean diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts new file mode 100644 index 000000000000..d908c931ad1d --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './common.gen'; +export * from './get_asset_criticality_status.gen'; diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/calculation_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/calculation_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/calculation_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/calculation_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/common.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/common.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/common.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/engine_disable_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_disable_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/engine_disable_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_disable_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/engine_enable_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_enable_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/engine_enable_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_enable_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/engine_init_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_init_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/engine_init_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_init_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/engine_status_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_status_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/engine_status_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/engine_status_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_engine/preview_route_schema.yml b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/preview_route_schema.yml similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_engine/preview_route_schema.yml rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_engine/preview_route_schema.yml diff --git a/x-pack/plugins/security_solution/common/api/risk_score/create_index/create_index_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_index/create_index_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/create_index/create_index_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_index/create_index_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.test.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.test.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.test.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.test.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_prebuilt_saved_objects/create_prebuilt_saved_objects_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/create_stored_script/create_stored_script_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_stored_script/create_stored_script_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/create_stored_script/create_stored_script_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/create_stored_script/create_stored_script_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/delete_indices/delete_indices_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_indices/delete_indices_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/delete_indices/delete_indices_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_indices/delete_indices_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/delete_prebuilt_saved_objects/delete_prebuilt_saved_objects_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_prebuilt_saved_objects/delete_prebuilt_saved_objects_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/delete_prebuilt_saved_objects/delete_prebuilt_saved_objects_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_prebuilt_saved_objects/delete_prebuilt_saved_objects_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/delete_stored_script/delete_stored_script_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_stored_script/delete_stored_script_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/delete_stored_script/delete_stored_script_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/delete_stored_script/delete_stored_script_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/index.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/index.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/index.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/index_status/index_status_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/index_status/index_status_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/index_status/index_status_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/index_status/index_status_route.ts diff --git a/x-pack/plugins/security_solution/common/api/risk_score/install_modules/install_modules_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/install_modules/install_modules_route.ts similarity index 89% rename from x-pack/plugins/security_solution/common/api/risk_score/install_modules/install_modules_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/install_modules/install_modules_route.ts index a17f10d72486..3f721f1c859d 100644 --- a/x-pack/plugins/security_solution/common/api/risk_score/install_modules/install_modules_route.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/install_modules/install_modules_route.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { RiskScoreEntity } from '../../../search_strategy'; +import { RiskScoreEntity } from '../../../../search_strategy'; export const onboardingRiskScoreRequestBody = { body: schema.object({ diff --git a/x-pack/plugins/security_solution/common/api/risk_score/read_prebuilt_dev_tool_content/read_prebuilt_dev_tool_content_route.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/read_prebuilt_dev_tool_content/read_prebuilt_dev_tool_content_route.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/risk_score/read_prebuilt_dev_tool_content/read_prebuilt_dev_tool_content_route.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/risk_score/read_prebuilt_dev_tool_content/read_prebuilt_dev_tool_content_route.ts diff --git a/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts new file mode 100644 index 000000000000..1b7dc1d4c356 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/timeline/copy_timeline/copy_timeline_route.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; + +import { SavedTimelineRuntimeType } from '../model/api'; + +export const copyTimelineSchema = rt.type({ + timeline: SavedTimelineRuntimeType, + timelineIdToCopy: rt.string, +}); diff --git a/x-pack/plugins/security_solution/common/api/timeline/index.ts b/x-pack/plugins/security_solution/common/api/timeline/index.ts index 83748b596e5b..6229b07c53a9 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/index.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/index.ts @@ -20,3 +20,4 @@ export * from './persist_favorite/persist_favorite_route'; export * from './persist_note/persist_note_route'; export * from './pinned_events/pinned_events_route'; export * from './install_prepackaged_timelines/install_prepackaged_timelines'; +export * from './copy_timeline/copy_timeline_route'; diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index c423b2a4418b..5237772ef5e1 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -441,10 +441,16 @@ export const TimelineResponseType = runtimeTypes.type({ }), }); -export const TimelineErrorResponseType = runtimeTypes.type({ - status_code: runtimeTypes.number, - message: runtimeTypes.string, -}); +export const TimelineErrorResponseType = runtimeTypes.union([ + runtimeTypes.type({ + status_code: runtimeTypes.number, + message: runtimeTypes.string, + }), + runtimeTypes.type({ + statusCode: runtimeTypes.number, + message: runtimeTypes.string, + }), +]); export type TimelineErrorResponse = runtimeTypes.TypeOf; export type TimelineResponse = runtimeTypes.TypeOf; diff --git a/x-pack/plugins/security_solution/common/asset_criticality/index.ts b/x-pack/plugins/security_solution/common/asset_criticality/index.ts new file mode 100644 index 000000000000..af45b0f6a8ab --- /dev/null +++ b/x-pack/plugins/security_solution/common/asset_criticality/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './indices'; diff --git a/x-pack/plugins/security_solution/common/asset_criticality/indices.ts b/x-pack/plugins/security_solution/common/asset_criticality/indices.ts new file mode 100644 index 000000000000..0cea9cfdc1e0 --- /dev/null +++ b/x-pack/plugins/security_solution/common/asset_criticality/indices.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const indexBase = '.asset-criticality.asset-criticality'; + +export const getAssetCriticalityIndex = (namespace: string) => `${indexBase}-${namespace}`; diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index a7460bcd7034..87cda6a416ea 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -165,6 +165,10 @@ export const ENABLE_NEWS_FEED_SETTING = 'securitySolution:enableNewsFeed' as con /** This Kibana Advanced Setting allows users to enable/disable the Expandable Flyout */ export const ENABLE_EXPANDABLE_FLYOUT_SETTING = 'securitySolution:enableExpandableFlyout' as const; +/** This Kibana Advanced Setting allows users to enable/disable querying cold and frozen data tiers in analyzer */ +export const EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER = + 'securitySolution:excludeColdAndFrozenTiersInAnalyzer' as const; + /** This Kibana Advanced Setting enables the warnings for CCS read permissions */ export const ENABLE_CCS_READ_WARNING_SETTING = 'securitySolution:enableCcsWarning' as const; @@ -259,6 +263,10 @@ export const RISK_ENGINE_STATUS_URL = `${RISK_ENGINE_URL}/status`; export const RISK_ENGINE_INIT_URL = `${RISK_ENGINE_URL}/init`; export const RISK_ENGINE_ENABLE_URL = `${RISK_ENGINE_URL}/enable`; export const RISK_ENGINE_DISABLE_URL = `${RISK_ENGINE_URL}/disable`; +export const RISK_ENGINE_PRIVILEGES_URL = `${RISK_ENGINE_URL}/privileges`; + +export const ASSET_CRITICALITY_URL = `/internal/asset_criticality`; +export const ASSET_CRITICALITY_STATUS_URL = `${ASSET_CRITICALITY_URL}/status`; /** * Public Risk Score routes @@ -292,6 +300,7 @@ export const TIMELINE_DRAFT_URL = `${TIMELINE_URL}/_draft` as const; export const TIMELINE_EXPORT_URL = `${TIMELINE_URL}/_export` as const; export const TIMELINE_IMPORT_URL = `${TIMELINE_URL}/_import` as const; export const TIMELINE_PREPACKAGED_URL = `${TIMELINE_URL}/_prepackaged` as const; +export const TIMELINE_COPY_URL = `${TIMELINE_URL}/_copy` as const; export const NOTE_URL = '/api/note' as const; export const PINNED_EVENT_URL = '/api/pinned_event' as const; @@ -314,6 +323,10 @@ export const DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL = export const DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL = `${DETECTION_ENGINE_SIGNALS_URL}/finalize_migration` as const; export const DETECTION_ENGINE_ALERT_TAGS_URL = `${DETECTION_ENGINE_SIGNALS_URL}/tags` as const; +export const DETECTION_ENGINE_ALERT_ASSIGNEES_URL = + `${DETECTION_ENGINE_SIGNALS_URL}/assignees` as const; +export const DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL = + `${DETECTION_ENGINE_SIGNALS_URL}/_find` as const; export const ALERTS_AS_DATA_URL = '/internal/rac/alerts' as const; export const ALERTS_AS_DATA_FIND_URL = `${ALERTS_AS_DATA_URL}/find` as const; @@ -429,6 +442,7 @@ export const RULES_TABLE_MAX_PAGE_SIZE = 100; */ export const NEW_FEATURES_TOUR_STORAGE_KEYS = { RULE_MANAGEMENT_PAGE: 'securitySolution.rulesManagementPage.newFeaturesTour.v8.11', + TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour', }; export const RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY = @@ -445,13 +459,6 @@ export enum BulkActionsDryRunErrCode { ESQL_INDEX_PATTERN = 'ESQL_INDEX_PATTERN', } -export const RISKY_HOSTS_DOC_LINK = - 'https://www.elastic.co/guide/en/security/current/host-risk-score.html'; -export const RISKY_USERS_DOC_LINK = - 'https://www.elastic.co/guide/en/security/current/user-risk-score.html'; -export const DETECTION_ENTITY_DASHBOARD = - 'https://www.elastic.co/guide/en/security/current/detection-entity-dashboard.html'; - export const MAX_NUMBER_OF_NEW_TERMS_FIELDS = 3; export const BULK_ADD_TO_TIMELINE_LIMIT = 2000; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index b080981713de..689ad118c9ca 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -70,8 +70,14 @@ export const allowedExperimentalValues = Object.freeze({ * Enables top charts on Alerts Page */ alertsPageChartsEnabled: true, + /** + * Enables the alert type column in KPI visualizations on Alerts Page + */ alertTypeEnabled: false, - + /** + * Enables expandable flyout in create rule page, alert preview + */ + expandableFlyoutInCreateRuleEnabled: false, /* * Enables new Set of filters on the Alerts page. * @@ -114,6 +120,17 @@ export const allowedExperimentalValues = Object.freeze({ * This flag is used to disable the tour in cypress tests. */ disableTimelineSaveTour: false, + + /** + * Enables the risk engine privileges route + * and associated callout in the UI + */ + riskEnginePrivilegesRouteEnabled: true, + + /* + * Enables experimental Entity Analytics Asset Criticality feature + */ + entityAnalyticsAssetCriticalityEnabled: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/security_solution/common/risk_engine/constants.ts b/x-pack/plugins/security_solution/common/risk_engine/constants.ts index 2d4d20855989..46a5a99a7e21 100644 --- a/x-pack/plugins/security_solution/common/risk_engine/constants.ts +++ b/x-pack/plugins/security_solution/common/risk_engine/constants.ts @@ -6,3 +6,12 @@ */ export const MAX_SPACES_COUNT = 1; + +export const RISK_ENGINE_REQUIRED_ES_CLUSTER_PRIVILEGES = [ + 'manage_index_templates', + 'manage_transform', +]; + +export const RISK_ENGINE_REQUIRED_ES_INDEX_PRIVILEGES = Object.freeze({ + 'risk-score.risk-score-*': ['read', 'write'], +}); diff --git a/x-pack/plugins/security_solution/common/risk_engine/indices.ts b/x-pack/plugins/security_solution/common/risk_engine/indices.ts index e148985b3139..281b4495e0c4 100644 --- a/x-pack/plugins/security_solution/common/risk_engine/indices.ts +++ b/x-pack/plugins/security_solution/common/risk_engine/indices.ts @@ -13,3 +13,6 @@ export const latestRiskScoreIndexPattern = 'risk-score.risk-score-latest-*'; export const getRiskScoreLatestIndex = (spaceId = 'default') => `${riskScoreBaseIndexName}.risk-score-latest-${spaceId}`; + +export const getRiskScoreTimeSeriesIndex = (spaceId = 'default') => + `${riskScoreBaseIndexName}.risk-score-${spaceId}`; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts index 1214a17c8586..efbf12b3e5e9 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts @@ -103,11 +103,3 @@ export const EMPTY_SEVERITY_COUNT = { [RiskSeverity.moderate]: 0, [RiskSeverity.unknown]: 0, }; - -export const SEVERITY_UI_SORT_ORDER = [ - RiskSeverity.unknown, - RiskSeverity.low, - RiskSeverity.moderate, - RiskSeverity.high, - RiskSeverity.critical, -]; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts index 1bf6ef39097d..b5e0c62526a6 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score/common/index.ts @@ -7,7 +7,11 @@ import type { ESQuery } from '../../../../typed_json'; import { RISKY_HOSTS_INDEX_PREFIX, RISKY_USERS_INDEX_PREFIX } from '../../../../constants'; -import { RiskScoreEntity, getRiskScoreLatestIndex } from '../../../../risk_engine'; +import { + RiskScoreEntity, + getRiskScoreLatestIndex, + getRiskScoreTimeSeriesIndex, +} from '../../../../risk_engine'; export { RiskQueries } from '../../../../api/search_strategy'; /** @@ -30,7 +34,9 @@ export const getUserRiskIndex = ( isNewRiskScoreModuleInstalled: boolean ): string => { return isNewRiskScoreModuleInstalled - ? getRiskScoreLatestIndex(spaceId) + ? onlyLatest + ? getRiskScoreLatestIndex(spaceId) + : getRiskScoreTimeSeriesIndex(spaceId) : `${RISKY_USERS_INDEX_PREFIX}${onlyLatest ? 'latest_' : ''}${spaceId}`; }; diff --git a/x-pack/plugins/security_solution/common/test/ess_roles.json b/x-pack/plugins/security_solution/common/test/ess_roles.json index d21fe90e2de0..9bf9e1b64aee 100644 --- a/x-pack/plugins/security_solution/common/test/ess_roles.json +++ b/x-pack/plugins/security_solution/common/test/ess_roles.json @@ -132,5 +132,22 @@ "base": [] } ] + }, + "no_risk_engine_privileges": { + "name": "no_risk_engine_privileges", + "elasticsearch": { + "cluster": [], + "indices": [], + "run_as": [] + }, + "kibana": [ + { + "feature": { + "siem": ["read"] + }, + "spaces": ["*"], + "base": [] + } + ] } } diff --git a/x-pack/plugins/security_solution/common/test/index.ts b/x-pack/plugins/security_solution/common/test/index.ts index ac2fd661320c..277f54c78e6c 100644 --- a/x-pack/plugins/security_solution/common/test/index.ts +++ b/x-pack/plugins/security_solution/common/test/index.ts @@ -29,6 +29,7 @@ export enum ROLES { reader = 'reader', hunter = 'hunter', hunter_no_actions = 'hunter_no_actions', + no_risk_engine_privileges = 'no_risk_engine_privileges', } /** diff --git a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts index 134b659116ee..8435e6ec8984 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts @@ -8,6 +8,7 @@ import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import type { ColumnHeaderOptions, RowRenderer } from '../..'; +import type { RenderCellValueContext } from '../../../../public/detections/configurations/security_solution_detections/fetch_page_context'; import type { BrowserFields, TimelineNonEcsData } from '../../../search_strategy'; /** The following props are provided to the function called by `renderCellValue` */ @@ -28,4 +29,5 @@ export type CellValueElementProps = EuiDataGridCellValueElementProps & { truncate?: boolean; key?: string; closeCellPopover?: () => void; + context?: RenderCellValueContext; }; diff --git a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/alerts/user_assignment.md b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/alerts/user_assignment.md new file mode 100644 index 000000000000..a2b360423e5c --- /dev/null +++ b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/alerts/user_assignment.md @@ -0,0 +1,216 @@ +# Alert User Assignment + +This is a test plan for the Alert User Assignment feature + +Status: `in progress`. The current test plan covers functionality described in [Alert User Assignment](https://github.com/elastic/security-team/issues/2504) epic. + +## Useful information + +### Tickets + +- [Alert User Assignment](https://github.com/elastic/security-team/issues/2504) epic +- [Add test coverage for Alert User Assignment](https://github.com/elastic/kibana/issues/171307) +- [Write a test plan for Alert User Assignment](https://github.com/elastic/kibana/issues/171306) + +### Terminology + +- **Assignee**: The user assigned to an alert. + +- **Assignees field**: The alert's `kibana.alert.workflow_assignee_ids` field which contains an array of assignees IDs. These ids conrespond to [User Profiles](https://www.elastic.co/guide/en/elasticsearch/reference/current/user-profile.html) endpoint. + +- **Assignee's avatar**: The avatar of an assignee. Can be either user profile picture if uploaded by the user or initials of the user. + +- **Assignees count badge**: The badge with the number of assignees. + +### Assumptions + +- The feature is **NOT** available under the Basic license +- Assignees are stored as an array of users IDs in alert's `kibana.alert.workflow_assignee_ids` field +- There are multiple (five or more) available users which could be assigned to alerts +- User need to have editor or higher privileges to assign users to alerts +- Mixed states are not supported by the current version of User Profiles component +- "Displayed/Shown in UI" refers to "Alerts Table" and "Alert's Details Flyout" + +## Scenarios + +### Basic rendering + +#### **Scenario: No assignees** + +**Automation**: 2 e2e test + 2 unit test. + +```Gherkin +Given an alert doesn't have assignees +Then no assignees' (represented by avatars) should be displayed in UI +``` + +#### **Scenario: With assignees** + +**Automation**: 2 e2e test + 2 unit test. + +```Gherkin +Given an alert has assignees +Then assignees' (represented by avatars) for each assignee should be shown in UI +``` + +#### **Scenario: Many assignees (Badge)** + +**Automation**: 2 e2e test + 2 unit test. + +```Gherkin +Given an alert has more assignees than maximum number allowed to display +Then assignees count badge is displayed in UI +``` + +### Updating assignees (single alert) + +#### **Scenario: Add new assignees** + +**Automation**: 3 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given an alert +When user adds new assignees +Then assignees field should be updated +And newly added assignees should be present +``` + +#### **Scenario: Update assignees** + +**Automation**: 3 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given an alert with assignees +When user removes some of (or all) current assignees and adds new assignees +Then assignees field should be updated +And removed assignees should be absent +And newly added assignees should be present +``` + +#### **Scenario: Unassign alert** + +**Automation**: 2 e2e test + 1 unit test. + +```Gherkin +Given an alert with assignees +When user triggers "Unassign alert" action +Then assignees field should be updated +And assignees field should be empty +``` + +### Updating assignees (bulk actions) + +#### **Scenario: Add new assignees** + +**Automation**: 1 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given multiple alerts +When user adds new assignees +Then assignees fields of all involved alerts should be updated +And newly added assignees should be present +``` + +#### **Scenario: Update assignees** + +**Automation**: 1 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given multiple alerts with assignees +When user removes some of (or all) current assignees and adds new assignees +Then assignees fields of all involved alerts should be updated +And removed assignees should be absent +And newly added assignees should be present +``` + +#### **Scenario: Unassign alert** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given multiple alerts with assignees +When user triggers "Unassign alert" action +Then assignees fields of all involved alerts should be updated +And assignees fields should be empty +``` + +### Alerts filtering + +#### **Scenario: By one assignee** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given multiple alerts with and without assignees +When user filters by one of the assignees +Then only alerts with selected assignee in assignees field are displayed +``` + +#### **Scenario: By multiple assignees** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given multiple alerts with and without assignees +When user filters by multiple assignees +Then all alerts with either of selected assignees in assignees fields are displayed +``` + +#### **Scenario: "No assignees" option** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given filter by assignees UI is available +Then there should be an option to filter alerts to see those which are not assigned to anyone +``` + +#### **Scenario: By "No assignees"** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given multiple alerts with and without assignees +When user filters by "No assignees" option +Then all alerts with empty assignees fields are displayed +``` + +#### **Scenario: By assignee and alert status** + +**Automation**: 1 e2e test + 1 unit test. + +```Gherkin +Given multiple alerts with and without assignees +When user filters by one of the assignees +AND alert's status +Then only alerts with selected assignee in assignees field AND selected alert's status are displayed +``` + +### Authorization / RBAC + +#### **Scenario: Viewer role** + +**Automation**: 1 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given user has "viewer/readonly" role +Then there should not be a way to update assignees field for an alert +``` + +#### **Scenario: Serverless roles** + +**Automation**: 1 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given users 't1_analyst', 't2_analyst', 't3_analyst', 'rule_author', 'soc_manager', 'detections_admin', 'platform_engineer' roles +Then update assignees functionality should be available +``` + +#### **Scenario: Basic license** + +**Automation**: 1 e2e test + 1 unit test + 1 integration test. + +```Gherkin +Given user runs Kibana under the Basic license +Then update assignees functionality should not be available +``` diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index a13046b0bc59..5f0613c3e89b 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -26,6 +26,7 @@ "mappings:load": "node scripts/mappings/mappings_loader", "junit:transform": "node scripts/junit_transformer --pathPattern '../../../target/kibana-security-solution/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Security Solution Cypress' --writeInPlace", "openapi:generate": "node scripts/openapi/generate", - "openapi:generate:debug": "node --inspect-brk scripts/openapi/generate" + "openapi:generate:debug": "node --inspect-brk scripts/openapi/generate", + "openapi:bundle": "node scripts/openapi/bundle" } } \ No newline at end of file diff --git a/x-pack/plugins/security_solution/public/actions/constants.ts b/x-pack/plugins/security_solution/public/actions/constants.ts index 95e72e70ccba..c477d5c6fc9c 100644 --- a/x-pack/plugins/security_solution/public/actions/constants.ts +++ b/x-pack/plugins/security_solution/public/actions/constants.ts @@ -4,6 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + +import { FILTER_CELL_ACTION_TYPE, COPY_CELL_ACTION_TYPE } from '@kbn/cell-actions/constants'; + export enum SecurityCellActionsTrigger { DEFAULT = 'security-default-cellActions', DETAILS_FLYOUT = 'security-detailsFlyout-cellActions', @@ -26,3 +29,8 @@ export enum SecurityCellActionType { SHOW_TOP_N = 'security-cellAction-type-showTopN', TOGGLE_COLUMN = 'security-cellAction-type-toggleColumn', } + +export const DefaultCellActionTypes = { + FILTER: FILTER_CELL_ACTION_TYPE, + COPY: COPY_CELL_ACTION_TYPE, +} as const; diff --git a/x-pack/plugins/security_solution/public/actions/discover_in_timeline/vis_apply_filter.ts b/x-pack/plugins/security_solution/public/actions/discover_in_timeline/vis_apply_filter.ts deleted file mode 100644 index 8c3f9e0214a6..000000000000 --- a/x-pack/plugins/security_solution/public/actions/discover_in_timeline/vis_apply_filter.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createFilterAction } from '@kbn/unified-search-plugin/public'; -import type { History } from 'history'; -import type { SecurityAppStore } from '../../common/store'; -import type { StartServices } from '../../types'; -import { EsqlInTimelineTrigger, EsqlInTimelineAction } from '../constants'; - -const createDiscoverHistogramCustomFilterAction = ( - store: SecurityAppStore, - history: History, - services: StartServices -) => { - const histogramApplyFilter = createFilterAction( - services.customDataService.query.filterManager, - services.customDataService.query.timefilter.timefilter, - services.theme, - EsqlInTimelineAction.VIS_FILTER_ACTION, - EsqlInTimelineAction.VIS_FILTER_ACTION - ); - services.uiActions.registerAction(histogramApplyFilter); - - return histogramApplyFilter; -}; - -const createDiscoverHistogramCustomTrigger = ( - store: SecurityAppStore, - history: History, - services: StartServices -) => { - services.uiActions.registerTrigger({ - id: EsqlInTimelineTrigger.HISTOGRAM_TRIGGER, - }); -}; - -export const registerDiscoverHistogramActions = ( - store: SecurityAppStore, - history: History, - services: StartServices -) => { - createDiscoverHistogramCustomTrigger(store, history, services); - - const histogramApplyFilter = createDiscoverHistogramCustomFilterAction(store, history, services); - - services.uiActions.attachAction(EsqlInTimelineTrigger.HISTOGRAM_TRIGGER, histogramApplyFilter.id); -}; diff --git a/x-pack/plugins/security_solution/public/actions/filter/index.ts b/x-pack/plugins/security_solution/public/actions/filter/index.ts index 2759d5cc20d3..b2e492956ecd 100644 --- a/x-pack/plugins/security_solution/public/actions/filter/index.ts +++ b/x-pack/plugins/security_solution/public/actions/filter/index.ts @@ -9,7 +9,5 @@ export { createFilterInCellActionFactory } from './cell_action/filter_in'; export { createFilterOutCellActionFactory } from './cell_action/filter_out'; export { createFilterInDiscoverCellActionFactory } from './discover/filter_in'; export { createFilterOutDiscoverCellActionFactory } from './discover/filter_out'; -export { createTimelineHistogramFilterInLegendActionFactory } from './lens/filter_in_timeline'; -export { createFilterInHistogramLegendActionFactory } from './lens/filter_in'; -export { createTimelineHistogramFilterOutLegendActionFactory } from './lens/filter_out_timeline'; -export { createFilterOutHistogramLegendActionFactory } from './lens/filter_out'; +export { createFilterInLensAction } from './lens/filter_in'; +export { createFilterOutLensAction } from './lens/filter_out'; diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts new file mode 100644 index 000000000000..78a0a9d46ff2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { addFilterIn, addFilterOut } from '@kbn/cell-actions'; +import { + isValueSupportedByDefaultActions, + valueToArray, + filterOutNullableValues, +} from '@kbn/cell-actions/src/actions/utils'; +import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; +import type { CellValueContext } from '@kbn/embeddable-plugin/public'; +import { createAction } from '@kbn/ui-actions-plugin/public'; +import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations'; +import { i18n } from '@kbn/i18n'; +import { timelineSelectors } from '../../../timelines/store/timeline'; +import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { TimelineId } from '../../../../common/types'; +import { DefaultCellActionTypes } from '../../constants'; +import type { SecurityAppStore } from '../../../common/store'; +import type { StartServices } from '../../../types'; + +function isDataColumnsValid(data?: CellValueContext['data']): boolean { + return ( + !!data && + data.length > 0 && + data.every(({ columnMeta }) => columnMeta && fieldHasCellActions(columnMeta.field)) + ); +} + +export const createFilterLensAction = ({ + id, + order, + store, + services, + negate, +}: { + id: string; + order: number; + store: SecurityAppStore; + services: StartServices; + negate?: boolean; +}) => { + const { application, notifications, data: dataService, topValuesPopover } = services; + + let currentAppId: string | undefined; + application.currentAppId$.subscribe((appId) => { + currentAppId = appId; + }); + const getTimelineById = timelineSelectors.getTimelineByIdSelector(); + + return createAction({ + id, + order, + getIconType: () => (negate ? 'minusInCircle' : 'plusInCircle'), + getDisplayName: () => + negate + ? i18n.translate('xpack.securitySolution.actions.filterOutTimeline', { + defaultMessage: `Filter out`, + }) + : i18n.translate('xpack.securitySolution.actions.filterForTimeline', { + defaultMessage: `Filter for`, + }), + type: DefaultCellActionTypes.FILTER, + isCompatible: async ({ embeddable, data }) => + !isErrorEmbeddable(embeddable) && + isLensEmbeddable(embeddable) && + isDataColumnsValid(data) && + isInSecurityApp(currentAppId), + execute: async ({ data }) => { + const field = data[0]?.columnMeta?.field; + const rawValue = data[0]?.value; + const value = filterOutNullableValues(valueToArray(rawValue)); + + if (!isValueSupportedByDefaultActions(value)) { + notifications.toasts.addWarning({ + title: ACTION_INCOMPATIBLE_VALUE_WARNING, + }); + return; + } + if (!field) return; + + topValuesPopover.closePopover(); + + const addFilter = negate === true ? addFilterOut : addFilterIn; + + const timeline = getTimelineById(store.getState(), TimelineId.active); + // timeline is open add the filter to timeline, otherwise add filter to global filters + const filterManager = timeline?.show + ? timeline.filterManager + : dataService.query.filterManager; + + addFilter({ filterManager, fieldName: field, value }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in.ts index aee91a849d89..fae9175879c9 100644 --- a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in.ts +++ b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in.ts @@ -8,11 +8,11 @@ import type { SecurityAppStore } from '../../../common/store'; import type { StartServices } from '../../../types'; -import { createHistogramFilterLegendActionFactory } from './helpers'; +import { createFilterLensAction } from './create_action'; -export const HISTOGRAM_LEGEND_ACTION_FILTER_IN = 'histogramLegendActionFilterIn'; +export const ACTION_ID = 'embeddable_filterIn'; -export const createFilterInHistogramLegendActionFactory = ({ +export const createFilterInLensAction = ({ store, order, services, @@ -21,8 +21,8 @@ export const createFilterInHistogramLegendActionFactory = ({ order: number; services: StartServices; }) => - createHistogramFilterLegendActionFactory({ - id: HISTOGRAM_LEGEND_ACTION_FILTER_IN, + createFilterLensAction({ + id: ACTION_ID, order, store, services, diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in_timeline.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in_timeline.ts deleted file mode 100644 index 6721972f0bcf..000000000000 --- a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_in_timeline.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SecurityAppStore } from '../../../common/store'; - -import type { StartServices } from '../../../types'; -import { createHistogramFilterLegendActionFactory } from './helpers'; - -export const TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_IN = 'timelineHistogramLegendActionFilterIn'; - -export const createTimelineHistogramFilterInLegendActionFactory = ({ - store, - order, - services, -}: { - store: SecurityAppStore; - order: number; - services: StartServices; -}) => - createHistogramFilterLegendActionFactory({ - id: TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_IN, - order, - store, - services, - }); diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out.ts index 4e32a3bee1b1..2b629ac1be86 100644 --- a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out.ts +++ b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out.ts @@ -8,11 +8,11 @@ import type { SecurityAppStore } from '../../../common/store'; import type { StartServices } from '../../../types'; -import { createHistogramFilterLegendActionFactory } from './helpers'; +import { createFilterLensAction } from './create_action'; -export const HISTOGRAM_LEGEND_ACTION_FILTER_OUT = 'histogramLegendActionFilterOut'; +export const ACTION_ID = 'embeddable_filterOut'; -export const createFilterOutHistogramLegendActionFactory = ({ +export const createFilterOutLensAction = ({ store, order, services, @@ -21,8 +21,8 @@ export const createFilterOutHistogramLegendActionFactory = ({ order: number; services: StartServices; }) => - createHistogramFilterLegendActionFactory({ - id: HISTOGRAM_LEGEND_ACTION_FILTER_OUT, + createFilterLensAction({ + id: ACTION_ID, order, store, services, diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out_timeline.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out_timeline.ts deleted file mode 100644 index 1712c94c21b7..000000000000 --- a/x-pack/plugins/security_solution/public/actions/filter/lens/filter_out_timeline.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SecurityAppStore } from '../../../common/store'; - -import type { StartServices } from '../../../types'; -import { createHistogramFilterLegendActionFactory } from './helpers'; - -export const TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_OUT = 'timelineHistogramLegendActionFilterOut'; - -export const createTimelineHistogramFilterOutLegendActionFactory = ({ - store, - order, - services, -}: { - store: SecurityAppStore; - order: number; - services: StartServices; -}) => - createHistogramFilterLegendActionFactory({ - id: TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_OUT, - order, - store, - services, - negate: true, - }); diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/helpers.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/helpers.ts deleted file mode 100644 index d138561aab1b..000000000000 --- a/x-pack/plugins/security_solution/public/actions/filter/lens/helpers.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { addFilterIn, addFilterOut } from '@kbn/cell-actions'; -import { - isValueSupportedByDefaultActions, - valueToArray, - filterOutNullableValues, -} from '@kbn/cell-actions/src/actions/utils'; -import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; -import type { CellValueContext } from '@kbn/embeddable-plugin/public'; -import { createAction } from '@kbn/ui-actions-plugin/public'; -import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations'; -import { i18n } from '@kbn/i18n'; -import { KibanaServices } from '../../../common/lib/kibana'; -import { timelineSelectors } from '../../../timelines/store/timeline'; -import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils'; -import { TimelineId } from '../../../../common/types'; -import { SecurityCellActionType } from '../../constants'; -import type { SecurityAppStore } from '../../../common/store'; -import type { StartServices } from '../../../types'; -import { HISTOGRAM_LEGEND_ACTION_FILTER_IN } from './filter_in'; -import { HISTOGRAM_LEGEND_ACTION_FILTER_OUT } from './filter_out'; - -function isDataColumnsValid(data?: CellValueContext['data']): boolean { - return ( - !!data && - data.length > 0 && - data.every(({ columnMeta }) => columnMeta && fieldHasCellActions(columnMeta.field)) - ); -} - -export const createHistogramFilterLegendActionFactory = ({ - id, - order, - store, - services, - negate, -}: { - id: string; - order: number; - store: SecurityAppStore; - services: StartServices; - negate?: boolean; -}) => { - const { application: applicationService } = KibanaServices.get(); - let currentAppId: string | undefined; - applicationService.currentAppId$.subscribe((appId) => { - currentAppId = appId; - }); - const getTimelineById = timelineSelectors.getTimelineByIdSelector(); - const { notifications } = services; - const { filterManager } = services.data.query; - - return createAction({ - id, - order, - getIconType: () => (negate ? 'minusInCircle' : 'plusInCircle'), - getDisplayName: () => - negate - ? i18n.translate('xpack.securitySolution.actions.filterOutTimeline', { - defaultMessage: `Filter out`, - }) - : i18n.translate('xpack.securitySolution.actions.filterForTimeline', { - defaultMessage: `Filter for`, - }), - type: SecurityCellActionType.FILTER, - isCompatible: async ({ embeddable, data }) => - !isErrorEmbeddable(embeddable) && - isLensEmbeddable(embeddable) && - isDataColumnsValid(data) && - isInSecurityApp(currentAppId), - execute: async ({ data }) => { - const field = data[0]?.columnMeta?.field; - const rawValue = data[0]?.value; - const value = filterOutNullableValues(valueToArray(rawValue)); - - if (!isValueSupportedByDefaultActions(value)) { - notifications.toasts.addWarning({ - title: ACTION_INCOMPATIBLE_VALUE_WARNING, - }); - return; - } - - if (!field) return; - - const timeline = getTimelineById(store.getState(), TimelineId.active); - services.topValuesPopover.closePopover(); - - if (!negate) { - addFilterIn({ - filterManager: - id === HISTOGRAM_LEGEND_ACTION_FILTER_IN ? filterManager : timeline.filterManager, - fieldName: field, - value, - }); - } else { - addFilterOut({ - filterManager: - id === HISTOGRAM_LEGEND_ACTION_FILTER_OUT ? filterManager : timeline.filterManager, - fieldName: field, - value, - }); - } - }, - }); -}; diff --git a/x-pack/plugins/security_solution/public/actions/register.ts b/x-pack/plugins/security_solution/public/actions/register.ts index 5aa0794ae9c4..46f37f68f48d 100644 --- a/x-pack/plugins/security_solution/public/actions/register.ts +++ b/x-pack/plugins/security_solution/public/actions/register.ts @@ -13,12 +13,8 @@ import type { StartServices } from '../types'; import { createFilterInCellActionFactory, createFilterInDiscoverCellActionFactory, - createTimelineHistogramFilterInLegendActionFactory, - createFilterInHistogramLegendActionFactory, createFilterOutCellActionFactory, createFilterOutDiscoverCellActionFactory, - createFilterOutHistogramLegendActionFactory, - createTimelineHistogramFilterOutLegendActionFactory, } from './filter'; import { createAddToTimelineLensAction, @@ -41,7 +37,9 @@ import type { SecurityCellActions, } from './types'; import { enhanceActionWithTelemetry } from './telemetry'; -import { registerDiscoverHistogramActions } from './discover_in_timeline/vis_apply_filter'; +import { registerDiscoverHistogramActions } from './register_discover_histogram_actions'; +import { createFilterInLensAction } from './filter/lens/filter_in'; +import { createFilterOutLensAction } from './filter/lens/filter_out'; export const registerUIActions = ( store: SecurityAppStore, @@ -51,45 +49,24 @@ export const registerUIActions = ( registerLensEmbeddableActions(store, services); registerDiscoverCellActions(store, services); registerCellActions(store, history, services); + // TODO: Remove discover histogram actions when timeline esql tab is extracted from discover registerDiscoverHistogramActions(store, history, services); }; const registerLensEmbeddableActions = (store: SecurityAppStore, services: StartServices) => { const { uiActions } = services; + const filterInLegendActions = createFilterInLensAction({ store, order: 2, services }); + uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterInLegendActions); + + const filterOutLegendActions = createFilterOutLensAction({ store, order: 3, services }); + uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterOutLegendActions); + const addToTimelineAction = createAddToTimelineLensAction({ store, order: 4 }); uiActions.addTriggerAction(CELL_VALUE_TRIGGER, addToTimelineAction); const copyToClipboardAction = createCopyToClipboardLensAction({ order: 5 }); uiActions.addTriggerAction(CELL_VALUE_TRIGGER, copyToClipboardAction); - - const filterInTimelineLegendActions = createTimelineHistogramFilterInLegendActionFactory({ - store, - order: 0, - services, - }); - uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterInTimelineLegendActions); - - const filterOutTimelineLegendActions = createTimelineHistogramFilterOutLegendActionFactory({ - store, - order: 1, - services, - }); - uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterOutTimelineLegendActions); - - const filterInLegendActions = createFilterInHistogramLegendActionFactory({ - store, - order: 2, - services, - }); - uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterInLegendActions); - - const filterOutLegendActions = createFilterOutHistogramLegendActionFactory({ - store, - order: 3, - services, - }); - uiActions.addTriggerAction(CELL_VALUE_TRIGGER, filterOutLegendActions); }; const registerDiscoverCellActions = (store: SecurityAppStore, services: StartServices) => { diff --git a/x-pack/plugins/security_solution/public/actions/register_discover_histogram_actions.ts b/x-pack/plugins/security_solution/public/actions/register_discover_histogram_actions.ts new file mode 100644 index 000000000000..5235cef932e4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/actions/register_discover_histogram_actions.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createFilterAction } from '@kbn/unified-search-plugin/public'; +import type { History } from 'history'; +import type { SecurityAppStore } from '../common/store'; +import type { StartServices } from '../types'; +import { EsqlInTimelineTrigger, EsqlInTimelineAction } from './constants'; + +const createDiscoverHistogramCustomFilterAction = ( + store: SecurityAppStore, + history: History, + services: StartServices +) => { + const histogramApplyFilter = createFilterAction( + services.customDataService.query.filterManager, + services.customDataService.query.timefilter.timefilter, + services.theme, + EsqlInTimelineAction.VIS_FILTER_ACTION, + EsqlInTimelineAction.VIS_FILTER_ACTION + ); + services.uiActions.registerAction(histogramApplyFilter); + + return histogramApplyFilter; +}; + +const createDiscoverHistogramCustomTrigger = ( + store: SecurityAppStore, + history: History, + services: StartServices +) => { + services.uiActions.registerTrigger({ + id: EsqlInTimelineTrigger.HISTOGRAM_TRIGGER, + }); +}; + +export const registerDiscoverHistogramActions = ( + store: SecurityAppStore, + history: History, + services: StartServices +) => { + createDiscoverHistogramCustomTrigger(store, history, services); + + const histogramApplyFilter = createDiscoverHistogramCustomFilterAction(store, history, services); + + services.uiActions.attachAction(EsqlInTimelineTrigger.HISTOGRAM_TRIGGER, histogramApplyFilter.id); +}; diff --git a/x-pack/plugins/security_solution/public/app/index.tsx b/x-pack/plugins/security_solution/public/app/index.tsx index 6f0fc3eb8d01..3053590ae3d9 100644 --- a/x-pack/plugins/security_solution/public/app/index.tsx +++ b/x-pack/plugins/security_solution/public/app/index.tsx @@ -7,7 +7,6 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { SubscriptionTrackingProvider } from '@kbn/subscription-tracking'; import { SecurityApp } from './app'; import type { RenderAppProps } from './types'; import { AppRoutes } from './app_routes'; @@ -21,7 +20,6 @@ export const renderApp = ({ usageCollection, subPluginRoutes, theme$, - subscriptionTrackingServices, }: RenderAppProps): (() => void) => { const ApplicationUsageTrackingProvider = usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment; @@ -34,12 +32,7 @@ export const renderApp = ({ theme$={theme$} > - - - + , element diff --git a/x-pack/plugins/security_solution/public/app/routes.tsx b/x-pack/plugins/security_solution/public/app/routes.tsx index 73fe2615b0e5..307d8f4c3237 100644 --- a/x-pack/plugins/security_solution/public/app/routes.tsx +++ b/x-pack/plugins/security_solution/public/app/routes.tsx @@ -14,7 +14,7 @@ import type { AppLeaveHandler } from '@kbn/core/public'; import { APP_ID } from '../../common/constants'; import { RouteCapture } from '../common/components/endpoint/route_capture'; -import { useGetUserCasesPermissions, useKibana } from '../common/lib/kibana'; +import { useKibana } from '../common/lib/kibana'; import type { AppAction } from '../common/store/actions'; import { ManageRoutesSpy } from '../common/utils/route/manage_spy_routes'; import { NotFoundPage } from './404'; @@ -29,7 +29,7 @@ interface RouterProps { const PageRouterComponent: FC = ({ children, history, onAppLeave }) => { const { cases } = useKibana().services; const CasesContext = cases.ui.getCasesContext(); - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const dispatch = useDispatch<(action: AppAction) => void>(); useEffect(() => { return () => { diff --git a/x-pack/plugins/security_solution/public/app/types.ts b/x-pack/plugins/security_solution/public/app/types.ts index 66bab19c945f..578a4800f7f6 100644 --- a/x-pack/plugins/security_solution/public/app/types.ts +++ b/x-pack/plugins/security_solution/public/app/types.ts @@ -19,7 +19,6 @@ import type { RouteProps } from 'react-router-dom'; import type { AppMountParameters } from '@kbn/core/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import type { TableState } from '@kbn/securitysolution-data-table'; -import type { Services as SubscriptionTrackingServices } from '@kbn/subscription-tracking'; import type { ExploreReducer, ExploreState } from '../explore'; import type { StartServices } from '../types'; @@ -30,7 +29,6 @@ export interface RenderAppProps extends AppMountParameters { services: StartServices; store: Store; subPluginRoutes: RouteProps[]; - subscriptionTrackingServices: SubscriptionTrackingServices; usageCollection?: UsageCollectionSetup; } diff --git a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx index 5a3e4a3d1c21..6059ef63ae6f 100644 --- a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx @@ -12,13 +12,14 @@ import React, { useCallback } from 'react'; import { useDispatch } from 'react-redux'; import { useAssistantContext } from '@kbn/elastic-assistant/impl/assistant_context'; -import { useKibana, useToasts } from '../../common/lib/kibana'; +import { useBasePath, useKibana, useToasts } from '../../common/lib/kibana'; import type { Note } from '../../common/lib/note'; import { appActions } from '../../common/store/actions'; import { TimelineId } from '../../../common/types'; import { updateAndAssociateNode } from '../../timelines/components/notes/helpers'; import { timelineActions } from '../../timelines/store/timeline'; import * as i18n from './translations'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; interface Props { message: Message; @@ -26,8 +27,10 @@ interface Props { const CommentActionsComponent: React.FC = ({ message }) => { const toasts = useToasts(); + const basePath = useBasePath(); const { cases } = useKibana().services; const dispatch = useDispatch(); + const isModelEvaluationEnabled = useIsExperimentalFeatureEnabled('assistantModelEvaluation'); const { showAssistantOverlay } = useAssistantContext(); @@ -75,8 +78,39 @@ const CommentActionsComponent: React.FC = ({ message }) => { }); }, [content, selectCaseModal, showAssistantOverlay]); + // Note: This feature is behind the `isModelEvaluationEnabled` FF. If ever released, this URL should be configurable + // as APM data may not go to the same cluster where the Kibana instance is running + // Links to the experimental trace explorer page + // Note: There's a bug with URL params being rewritten, so must specify 'query' to filter on transaction id + // See: https://github.com/elastic/kibana/issues/171368 + const apmTraceLink = + message.traceData != null + ? `${basePath}/app/apm/traces/explorer/waterfall?comparisonEnabled=false&detailTab=timeline&environment=ENVIRONMENT_ALL&kuery=&query=transaction.id:%20${message.traceData.transactionId}&rangeFrom=now-1y/d&rangeTo=now&showCriticalPath=false&traceId=${message.traceData.traceId}&transactionId=${message.traceData.transactionId}&type=kql&waterfallItemId=` + : undefined; + + // Use this link for routing to the services/transactions view which provides a slightly different view + // const apmTraceLink = + // message.traceData != null + // ? `${basePath}/app/apm/services/kibana/transactions/view?kuery=&rangeFrom=now-1y&rangeTo=now&environment=ENVIRONMENT_ALL&serviceGroup=&comparisonEnabled=true&traceId=${message.traceData.traceId}&transactionId=${message.traceData.transactionId}&transactionName=POST%20/internal/elastic_assistant/actions/connector/?/_execute&transactionType=request&offset=1d&latencyAggregationType=avg` + // : undefined; + return ( + // APM Trace support is currently behind the Model Evaluation feature flag until wider testing is performed + {isModelEvaluationEnabled && apmTraceLink != null && ( + + + + + + )} + void; content?: string; + isError?: boolean; isFetching?: boolean; isLastComment: boolean; index: number; + connectorTypeTitle: string; reader?: ReadableStreamDefaultReader; regenerateMessage: () => void; transformMessage: (message: string) => ContentMessage; @@ -28,7 +30,9 @@ interface Props { export const StreamComment = ({ amendMessage, content, + connectorTypeTitle, index, + isError = false, isFetching = false, isLastComment, reader, @@ -38,7 +42,9 @@ export const StreamComment = ({ const { error, isLoading, isStreaming, pendingMessage, setComplete } = useStream({ amendMessage, content, + connectorTypeTitle, reader, + isError, }); const currentState = useRef({ isStreaming, pendingMessage, amendMessage }); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts index 9a63621021cc..54a5684d2044 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts @@ -5,9 +5,12 @@ * 2.0. */ import { getStreamObservable } from './stream_observable'; -// import { getReaderValue, mockUint8Arrays } from './mock'; +import { API_ERROR } from '../translations'; + import type { PromptObservableState } from './types'; import { Subject } from 'rxjs'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; describe('getStreamObservable', () => { const mockReader = { read: jest.fn(), @@ -21,47 +24,175 @@ describe('getStreamObservable', () => { beforeEach(() => { jest.clearAllMocks(); }); - - it('should emit loading state and chunks', (done) => { + it('should emit loading state and chunks for Bedrock', (done) => { const completeSubject = new Subject(); const expectedStates: PromptObservableState[] = [ { chunks: [], loading: true }, { - chunks: [ - { - id: '1', - object: 'chunk', - created: 1635633600000, - model: 'model-1', - choices: [ - { - index: 0, - delta: { role: 'role-1', content: 'content-1' }, - finish_reason: null, - }, - ], + // when i log the actual emit, chunks equal to message.split(''); test is wrong + chunks: ['My', ' new', ' message'], + message: 'My', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new message', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new message', + loading: false, + }, + ]; + + mockReader.read + .mockResolvedValueOnce({ + done: false, + value: encodeBedrockResponse('My'), + }) + .mockResolvedValueOnce({ + done: false, + value: encodeBedrockResponse(' new'), + }) + .mockResolvedValueOnce({ + done: false, + value: encodeBedrockResponse(' message'), + }) + .mockResolvedValue({ + done: true, + }); + + const source = getStreamObservable({ + connectorTypeTitle: 'Amazon Bedrock', + isError: false, + reader: typedReader, + setLoading, + }); + const emittedStates: PromptObservableState[] = []; + + source.subscribe({ + next: (state) => { + return emittedStates.push(state); + }, + complete: () => { + expect(emittedStates).toEqual(expectedStates); + done(); + + completeSubject.subscribe({ + next: () => { + expect(setLoading).toHaveBeenCalledWith(false); + expect(typedReader.cancel).toHaveBeenCalled(); + done(); }, - ], - message: 'content-1', + }); + }, + error: (err) => done(err), + }); + }); + it('should emit loading state and chunks for OpenAI', (done) => { + const chunk1 = `data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"My"}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" new"}}]}`; + const chunk2 = `\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" message"}}]}\ndata: [DONE]`; + const completeSubject = new Subject(); + const expectedStates: PromptObservableState[] = [ + { chunks: [], loading: true }, + { + // when i log the actual emit, chunks equal to message.split(''); test is wrong + chunks: ['My', ' new', ' message'], + message: 'My', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new message', loading: true, }, { - chunks: [ - { - id: '1', - object: 'chunk', - created: 1635633600000, - model: 'model-1', - choices: [ - { - index: 0, - delta: { role: 'role-1', content: 'content-1' }, - finish_reason: null, - }, - ], + chunks: ['My', ' new', ' message'], + message: 'My new message', + loading: false, + }, + ]; + + mockReader.read + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk1)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk2)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode('')), + }) + .mockResolvedValue({ + done: true, + }); + + const source = getStreamObservable({ + connectorTypeTitle: 'OpenAI', + isError: false, + reader: typedReader, + setLoading, + }); + const emittedStates: PromptObservableState[] = []; + + source.subscribe({ + next: (state) => { + return emittedStates.push(state); + }, + complete: () => { + expect(emittedStates).toEqual(expectedStates); + done(); + + completeSubject.subscribe({ + next: () => { + expect(setLoading).toHaveBeenCalledWith(false); + expect(typedReader.cancel).toHaveBeenCalled(); + done(); }, - ], - message: 'content-1', + }); + }, + error: (err) => done(err), + }); + }); + it('should emit loading state and chunks for partial response OpenAI', (done) => { + const chunk1 = `data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"My"}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" new"`; + const chunk2 = `}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" message"}}]}\ndata: [DONE]`; + const completeSubject = new Subject(); + const expectedStates: PromptObservableState[] = [ + { chunks: [], loading: true }, + { + // when i log the actual emit, chunks equal to message.split(''); test is wrong + chunks: ['My', ' new', ' message'], + message: 'My', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new message', + loading: true, + }, + { + chunks: ['My', ' new', ' message'], + message: 'My new message', loading: false, }, ]; @@ -69,23 +200,79 @@ describe('getStreamObservable', () => { mockReader.read .mockResolvedValueOnce({ done: false, - value: new Uint8Array( - new TextEncoder().encode(`data: ${JSON.stringify(expectedStates[1].chunks[0])}`) - ), + value: new Uint8Array(new TextEncoder().encode(chunk1)), }) .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode(``)), + value: new Uint8Array(new TextEncoder().encode(chunk2)), }) .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode('data: [DONE]\n')), + value: new Uint8Array(new TextEncoder().encode('')), + }) + .mockResolvedValue({ + done: true, + }); + + const source = getStreamObservable({ + connectorTypeTitle: 'OpenAI', + isError: false, + reader: typedReader, + setLoading, + }); + const emittedStates: PromptObservableState[] = []; + + source.subscribe({ + next: (state) => { + return emittedStates.push(state); + }, + complete: () => { + expect(emittedStates).toEqual(expectedStates); + done(); + + completeSubject.subscribe({ + next: () => { + expect(setLoading).toHaveBeenCalledWith(false); + expect(typedReader.cancel).toHaveBeenCalled(); + done(); + }, + }); + }, + error: (err) => done(err), + }); + }); + + it('should stream errors when reader contains errors', (done) => { + const completeSubject = new Subject(); + const expectedStates: PromptObservableState[] = [ + { chunks: [], loading: true }, + { + chunks: [`${API_ERROR}\n\nis an error`], + message: `${API_ERROR}\n\nis an error`, + loading: true, + }, + { + chunks: [`${API_ERROR}\n\nis an error`], + message: `${API_ERROR}\n\nis an error`, + loading: false, + }, + ]; + + mockReader.read + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(JSON.stringify({ message: 'is an error' }))), }) .mockResolvedValue({ done: true, }); - const source = getStreamObservable(typedReader, setLoading); + const source = getStreamObservable({ + connectorTypeTitle: 'OpenAI', + isError: true, + reader: typedReader, + setLoading, + }); const emittedStates: PromptObservableState[] = []; source.subscribe({ @@ -111,7 +298,12 @@ describe('getStreamObservable', () => { const error = new Error('Test Error'); // Simulate an error mockReader.read.mockRejectedValue(error); - const source = getStreamObservable(typedReader, setLoading); + const source = getStreamObservable({ + connectorTypeTitle: 'OpenAI', + isError: false, + reader: typedReader, + setLoading, + }); source.subscribe({ next: (state) => {}, @@ -130,3 +322,16 @@ describe('getStreamObservable', () => { }); }); }); + +function encodeBedrockResponse(completion: string) { + return new EventStreamCodec(toUtf8, fromUtf8).encode({ + headers: {}, + body: Uint8Array.from( + Buffer.from( + JSON.stringify({ + bytes: Buffer.from(JSON.stringify({ completion })).toString('base64'), + }) + ) + ), + }); +} diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts index 83f9b4cf8ead..ce7a38811f22 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts @@ -5,55 +5,76 @@ * 2.0. */ -import { concatMap, delay, finalize, Observable, of, scan, shareReplay, timestamp } from 'rxjs'; +import { concatMap, delay, finalize, Observable, of, scan, timestamp } from 'rxjs'; import type { Dispatch, SetStateAction } from 'react'; -import type { PromptObservableState, Chunk } from './types'; - +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; +import type { PromptObservableState } from './types'; +import { API_ERROR } from '../translations'; const MIN_DELAY = 35; + +interface StreamObservable { + connectorTypeTitle: string; + reader: ReadableStreamDefaultReader; + setLoading: Dispatch>; + isError: boolean; +} /** * Returns an Observable that reads data from a ReadableStream and emits values representing the state of the data processing. * * @param reader - The ReadableStreamDefaultReader used to read data from the stream. * @param setLoading - A function to update the loading state. + * @param isError - indicates whether the reader response is an error message or not * @returns {Observable} An Observable that emits PromptObservableState */ -export const getStreamObservable = ( - reader: ReadableStreamDefaultReader, - setLoading: Dispatch> -): Observable => +export const getStreamObservable = ({ + connectorTypeTitle, + isError, + reader, + setLoading, +}: StreamObservable): Observable => new Observable((observer) => { observer.next({ chunks: [], loading: true }); const decoder = new TextDecoder(); - const chunks: Chunk[] = []; - function read() { + const chunks: string[] = []; + // Initialize an empty string to store the OpenAI buffer. + let openAIBuffer: string = ''; + + // Initialize an empty Uint8Array to store the Bedrock concatenated buffer. + let bedrockBuffer: Uint8Array = new Uint8Array(0); + function readOpenAI() { reader .read() .then(({ done, value }: { done: boolean; value?: Uint8Array }) => { try { if (done) { + if (openAIBuffer) { + chunks.push(getOpenAIChunks([openAIBuffer])[0]); + } observer.next({ chunks, - message: getMessageFromChunks(chunks), + message: chunks.join(''), loading: false, }); observer.complete(); return; } - const nextChunks: Chunk[] = decoder - .decode(value) - .split('\n') - // every line starts with "data: ", we remove it and are left with stringified JSON or the string "[DONE]" - .map((str) => str.substring(6)) - // filter out empty lines and the "[DONE]" string - .filter((str) => !!str && str !== '[DONE]') - .map((line) => JSON.parse(line)); - - nextChunks.forEach((chunk) => { + const decoded = decoder.decode(value); + let nextChunks; + if (isError) { + nextChunks = [`${API_ERROR}\n\n${JSON.parse(decoded).message}`]; + } else { + const lines = decoded.split('\n'); + lines[0] = openAIBuffer + lines[0]; + openAIBuffer = lines.pop() || ''; + nextChunks = getOpenAIChunks(lines); + } + nextChunks.forEach((chunk: string) => { chunks.push(chunk); observer.next({ chunks, - message: getMessageFromChunks(chunks), + message: chunks.join(''), loading: true, }); }); @@ -61,20 +82,104 @@ export const getStreamObservable = ( observer.error(err); return; } - read(); + readOpenAI(); + }) + .catch((err) => { + observer.error(err); + }); + } + function readBedrock() { + reader + .read() + .then(({ done, value }: { done: boolean; value?: Uint8Array }) => { + try { + if (done) { + observer.next({ + chunks, + message: chunks.join(''), + loading: false, + }); + observer.complete(); + return; + } + + let content; + if (isError) { + content = `${API_ERROR}\n\n${JSON.parse(decoder.decode(value)).message}`; + chunks.push(content); + observer.next({ + chunks, + message: chunks.join(''), + loading: true, + }); + } else if (value != null) { + const chunk: Uint8Array = value; + + // Concatenate the current chunk to the existing buffer. + bedrockBuffer = concatChunks(bedrockBuffer, chunk); + // Get the length of the next message in the buffer. + let messageLength = getMessageLength(bedrockBuffer); + + // Initialize an array to store fully formed message chunks. + const buildChunks = []; + // Process the buffer until no complete messages are left. + while (bedrockBuffer.byteLength > 0 && bedrockBuffer.byteLength >= messageLength) { + // Extract a chunk of the specified length from the buffer. + const extractedChunk = bedrockBuffer.slice(0, messageLength); + // Add the extracted chunk to the array of fully formed message chunks. + buildChunks.push(extractedChunk); + // Remove the processed chunk from the buffer. + bedrockBuffer = bedrockBuffer.slice(messageLength); + // Get the length of the next message in the updated buffer. + messageLength = getMessageLength(bedrockBuffer); + } + + const awsDecoder = new EventStreamCodec(toUtf8, fromUtf8); + // Decode and parse each message chunk, extracting the 'completion' property. + buildChunks.forEach((bChunk) => { + const event = awsDecoder.decode(bChunk); + const body = JSON.parse( + Buffer.from(JSON.parse(decoder.decode(event.body)).bytes, 'base64').toString() + ); + content = body.completion; + chunks.push(content); + observer.next({ + chunks, + message: chunks.join(''), + loading: true, + }); + }); + } + } catch (err) { + observer.error(err); + return; + } + readBedrock(); }) .catch((err) => { observer.error(err); }); } - read(); + // this should never actually happen + function badConnector() { + observer.next({ + chunks: [ + `Invalid connector type - ${connectorTypeTitle} is not a supported GenAI connector.`, + ], + message: `Invalid connector type - ${connectorTypeTitle} is not a supported GenAI connector.`, + loading: false, + }); + observer.complete(); + } + + if (connectorTypeTitle === 'Amazon Bedrock') readBedrock(); + else if (connectorTypeTitle === 'OpenAI') readOpenAI(); + else badConnector(); + return () => { reader.cancel(); }; }).pipe( - // make sure the request is only triggered once, - // even with multiple subscribers - shareReplay(1), // append a timestamp of when each value was emitted timestamp(), // use the previous timestamp to calculate a target @@ -105,8 +210,55 @@ export const getStreamObservable = ( finalize(() => setLoading(false)) ); -function getMessageFromChunks(chunks: Chunk[]) { - return chunks.map((chunk) => chunk.choices[0]?.delta.content ?? '').join(''); +/** + * Parses an OpenAI response from a string. + * @param lines + * @returns {string[]} - Parsed string array from the OpenAI response. + */ +const getOpenAIChunks = (lines: string[]): string[] => { + const nextChunk = lines + .map((str) => str.substring(6)) + .filter((str) => !!str && str !== '[DONE]') + .map((line) => { + try { + const openaiResponse = JSON.parse(line); + return openaiResponse.choices[0]?.delta.content ?? ''; + } catch (err) { + return ''; + } + }); + return nextChunk; +}; + +/** + * Concatenates two Uint8Array buffers. + * + * @param {Uint8Array} a - First buffer. + * @param {Uint8Array} b - Second buffer. + * @returns {Uint8Array} - Concatenated buffer. + */ +function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array { + const newBuffer = new Uint8Array(a.length + b.length); + // Copy the contents of the first buffer to the new buffer. + newBuffer.set(a); + // Copy the contents of the second buffer to the new buffer starting from the end of the first buffer. + newBuffer.set(b, a.length); + return newBuffer; +} + +/** + * Gets the length of the next message from the buffer. + * + * @param {Uint8Array} buffer - Buffer containing the message. + * @returns {number} - Length of the next message. + */ +function getMessageLength(buffer: Uint8Array): number { + // If the buffer is empty, return 0. + if (buffer.byteLength === 0) return 0; + // Create a DataView to read the Uint32 value at the beginning of the buffer. + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + // Read and return the Uint32 value (message length). + return view.getUint32(0, false); } export const getPlaceholderObservable = () => new Observable(); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/types.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/types.ts index 3cf45852ddb1..80ef5e4ae6ed 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/types.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/types.ts @@ -6,20 +6,8 @@ */ export interface PromptObservableState { - chunks: Chunk[]; + chunks: string[]; message?: string; error?: string; loading: boolean; } -export interface ChunkChoice { - index: 0; - delta: { role: string; content: string }; - finish_reason: null | string; -} -export interface Chunk { - id: string; - object: string; - created: number; - model: string; - choices: ChunkChoice[]; -} diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.test.tsx b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.test.tsx index 4fbecfac870e..c4f99884aa04 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.test.tsx +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.test.tsx @@ -11,32 +11,22 @@ import { useStream } from './use_stream'; const amendMessage = jest.fn(); const reader = jest.fn(); const cancel = jest.fn(); -const exampleChunk = { - id: '1', - object: 'chunk', - created: 1635633600000, - model: 'model-1', - choices: [ - { - index: 0, - delta: { role: 'role-1', content: 'content-1' }, - finish_reason: null, - }, - ], -}; +const chunk1 = `data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"My"}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" new"}}]}`; +const chunk2 = `\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" message"}}]}\ndata: [DONE]`; + const readerComplete = { read: reader .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode(`data: ${JSON.stringify(exampleChunk)}`)), + value: new Uint8Array(new TextEncoder().encode(chunk1)), }) .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode(``)), + value: new Uint8Array(new TextEncoder().encode(chunk2)), }) .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode('data: [DONE]\n')), + value: new Uint8Array(new TextEncoder().encode('')), }) .mockResolvedValue({ done: true, @@ -46,7 +36,12 @@ const readerComplete = { closed: jest.fn().mockResolvedValue(true), } as unknown as ReadableStreamDefaultReader; -const defaultProps = { amendMessage, reader: readerComplete }; +const defaultProps = { + amendMessage, + reader: readerComplete, + isError: false, + connectorTypeTitle: 'OpenAI', +}; describe('useStream', () => { beforeEach(() => { jest.clearAllMocks(); @@ -69,7 +64,7 @@ describe('useStream', () => { error: undefined, isLoading: true, isStreaming: true, - pendingMessage: 'content-1', + pendingMessage: 'My', setComplete: expect.any(Function), }); }); @@ -79,7 +74,7 @@ describe('useStream', () => { error: undefined, isLoading: false, isStreaming: false, - pendingMessage: 'content-1', + pendingMessage: 'My new message', setComplete: expect.any(Function), }); }); @@ -104,7 +99,7 @@ describe('useStream', () => { .fn() .mockResolvedValueOnce({ done: false, - value: new Uint8Array(new TextEncoder().encode(`data: ${JSON.stringify(exampleChunk)}`)), + value: new Uint8Array(new TextEncoder().encode(`one chunk`)), }) .mockRejectedValue(new Error(errorMessage)), cancel, @@ -113,7 +108,7 @@ describe('useStream', () => { } as unknown as ReadableStreamDefaultReader; const { result, waitForNextUpdate } = renderHook(() => useStream({ - amendMessage, + ...defaultProps, reader: errorReader, }) ); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.tsx b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.tsx index 148338f2afaf..9271758a8558 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.tsx +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/use_stream.tsx @@ -7,12 +7,13 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import type { Subscription } from 'rxjs'; -import { share } from 'rxjs'; import { getPlaceholderObservable, getStreamObservable } from './stream_observable'; interface UseStreamProps { amendMessage: (message: string) => void; + isError: boolean; content?: string; + connectorTypeTitle: string; reader?: ReadableStreamDefaultReader; } interface UseStream { @@ -33,8 +34,15 @@ interface UseStream { * @param amendMessage - handles the amended message * @param content - the content of the message. If provided, the function will not use the reader to stream data. * @param reader - The readable stream reader used to stream data. If provided, the function will use this reader to stream data. + * @param isError - indicates whether the reader response is an error message or not */ -export const useStream = ({ amendMessage, content, reader }: UseStreamProps): UseStream => { +export const useStream = ({ + amendMessage, + content, + connectorTypeTitle, + reader, + isError, +}: UseStreamProps): UseStream => { const [pendingMessage, setPendingMessage] = useState(); const [loading, setLoading] = useState(false); const [error, setError] = useState(); @@ -42,9 +50,9 @@ export const useStream = ({ amendMessage, content, reader }: UseStreamProps): Us const observer$ = useMemo( () => content == null && reader != null - ? getStreamObservable(reader, setLoading) + ? getStreamObservable({ connectorTypeTitle, reader, setLoading, isError }) : getPlaceholderObservable(), - [content, reader] + [content, isError, reader, connectorTypeTitle] ); const onCompleteStream = useCallback(() => { subscription?.unsubscribe(); @@ -59,7 +67,7 @@ export const useStream = ({ amendMessage, content, reader }: UseStreamProps): Us } }, [complete, onCompleteStream]); useEffect(() => { - const newSubscription = observer$.pipe(share()).subscribe({ + const newSubscription = observer$.subscribe({ next: ({ message, loading: isLoading }) => { setLoading(isLoading); setPendingMessage(message); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/translations.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/translations.ts index 2b83d580ef2c..fbccef68f739 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/translations.ts @@ -20,3 +20,7 @@ export const AT = (timestamp: string) => export const YOU = i18n.translate('xpack.securitySolution.assistant.getComments.you', { defaultMessage: 'You', }); + +export const API_ERROR = i18n.translate('xpack.securitySolution.assistant.apiErrorTitle', { + defaultMessage: 'An error occurred sending your message.', +}); diff --git a/x-pack/plugins/security_solution/public/assistant/helpers.tsx b/x-pack/plugins/security_solution/public/assistant/helpers.tsx index beca67f55eeb..821bb927d503 100644 --- a/x-pack/plugins/security_solution/public/assistant/helpers.tsx +++ b/x-pack/plugins/security_solution/public/assistant/helpers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiIcon, EuiToolTip } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; import { analyzeMarkdown } from '@kbn/elastic-assistant'; import type { Conversation, CodeBlockDetails } from '@kbn/elastic-assistant'; import React from 'react'; @@ -13,7 +13,6 @@ import React from 'react'; import type { TimelineEventsDetailsItem } from '../../common/search_strategy'; import type { Rule } from '../detection_engine/rule_management/logic'; import { SendToTimelineButton } from './send_to_timeline'; -import { INVESTIGATE_IN_TIMELINE } from '../actions/add_to_timeline/constants'; export const LOCAL_STORAGE_KEY = `securityAssistant`; @@ -125,9 +124,7 @@ export const augmentMessageCodeBlocks = ( ]} keepDataView={true} > - - - + ) : null, }; diff --git a/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx b/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx index 3bd29dc53eda..114d5deb5f3e 100644 --- a/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx @@ -6,10 +6,11 @@ */ import React, { useCallback, useMemo } from 'react'; -import { EuiButton, EuiButtonEmpty } from '@elastic/eui'; +import { EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; import type { Filter } from '@kbn/es-query'; import { useDispatch } from 'react-redux'; +import { useAssistantContext } from '@kbn/elastic-assistant'; import { useDeepEqualSelector } from '../../common/hooks/use_selector'; import { sourcererSelectors } from '../../common/store'; import { sourcererActions } from '../../common/store/actions'; @@ -19,7 +20,10 @@ import type { TimeRange } from '../../common/store/inputs/model'; import { SourcererScopeName } from '../../common/store/sourcerer/model'; import { TimelineTabs, TimelineId } from '../../../common/types/timeline'; import { TimelineType } from '../../../common/api/timeline'; -import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../detections/components/alerts_table/translations'; +import { + ACTION_CANNOT_INVESTIGATE_IN_TIMELINE, + ACTION_INVESTIGATE_IN_TIMELINE, +} from '../../detections/components/alerts_table/translations'; import type { DataProvider } from '../../timelines/components/timeline/data_providers/data_provider'; import { useCreateTimeline } from '../../timelines/components/timeline/properties/use_create_timeline'; import { @@ -31,6 +35,7 @@ import { updateEqlOptions, } from '../../timelines/store/timeline/actions'; import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context'; +import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline'; export interface SendToTimelineButtonProps { asEmptyButton: boolean; @@ -51,7 +56,8 @@ export const SendToTimelineButton: React.FunctionComponent { const dispatch = useDispatch(); - + const { showAssistantOverlay } = useAssistantContext(); + const [isTimelineBottomBarVisible] = useShowTimeline(); const { discoverStateContainer } = useDiscoverInTimelineContext(); const getDataViewsSelector = useMemo( @@ -71,13 +77,15 @@ export const SendToTimelineButton: React.FunctionComponent { + // Hide the assistant overlay so timeline can be seen (noop if using assistant in timeline) + showAssistantOverlay({ showOverlay: false }); + if (dataProviders || filters) { // If esql, don't reset filters or mess with dataview & time range if (dataProviders?.[0]?.queryType === 'esql' || dataProviders?.[0]?.queryType === 'sql') { discoverStateContainer.current?.appState.update({ query: { - query: dataProviders[0].kqlQuery, - language: 'esql', + esql: dataProviders[0].kqlQuery, }, }); @@ -200,6 +208,7 @@ export const SendToTimelineButton: React.FunctionComponent - {children} + + <>{children} + ) : ( - {children} + + <>{children} + ); }; diff --git a/x-pack/plugins/security_solution/public/cases/links.ts b/x-pack/plugins/security_solution/public/cases/links.ts index 3017fa28816e..2d2f6d94b351 100644 --- a/x-pack/plugins/security_solution/public/cases/links.ts +++ b/x-pack/plugins/security_solution/public/cases/links.ts @@ -8,7 +8,7 @@ import { CREATE_CASES_CAPABILITY, READ_CASES_CAPABILITY, - UPDATE_CASES_CAPABILITY, + CASES_SETTINGS_CAPABILITY, } from '@kbn/cases-plugin/common'; import { getCasesDeepLinks } from '@kbn/cases-plugin/public'; import { CASES_FEATURE_ID, CASES_PATH, SecurityPageName } from '../../common/constants'; @@ -22,7 +22,7 @@ const casesLinks = getCasesDeepLinks({ capabilities: [`${CASES_FEATURE_ID}.${READ_CASES_CAPABILITY}`], }, [SecurityPageName.caseConfigure]: { - capabilities: [`${CASES_FEATURE_ID}.${UPDATE_CASES_CAPABILITY}`], + capabilities: [`${CASES_FEATURE_ID}.${CASES_SETTINGS_CAPABILITY}`], sideNavDisabled: true, }, [SecurityPageName.caseCreate]: { diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx index 041fd9378382..ab5b170e423c 100644 --- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx @@ -11,7 +11,7 @@ import type { CaseViewRefreshPropInterface } from '@kbn/cases-plugin/common'; import { CaseMetricsFeature } from '@kbn/cases-plugin/common'; import { useUiSetting$ } from '@kbn/kibana-react-plugin/public'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; -import { RightPanelKey } from '../../flyout/document_details/right'; +import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/right'; import { useTourContext } from '../../common/components/guided_onboarding_tour'; import { AlertsCasesTourSteps, @@ -21,7 +21,7 @@ import { TimelineId } from '../../../common/types/timeline'; import { getRuleDetailsUrl, useFormatUrl } from '../../common/components/link_to'; -import { useGetUserCasesPermissions, useKibana, useNavigation } from '../../common/lib/kibana'; +import { useKibana, useNavigation } from '../../common/lib/kibana'; import { APP_ID, CASES_PATH, @@ -56,7 +56,7 @@ const TimelineDetailsPanel = () => { const CaseContainerComponent: React.FC = () => { const { cases } = useKibana().services; const { getAppUrl, navigateTo } = useNavigation(); - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const dispatch = useDispatch(); const { formatUrl: detectionsFormatUrl, search: detectionsUrlSearch } = useFormatUrl( SecurityPageName.rules @@ -74,7 +74,7 @@ const CaseContainerComponent: React.FC = () => { if (isSecurityFlyoutEnabled) { openFlyout({ right: { - id: RightPanelKey, + id: DocumentDetailsRightPanelKey, params: { id: alertId, indexName: index, diff --git a/x-pack/plugins/security_solution/public/cases_test_utils.ts b/x-pack/plugins/security_solution/public/cases_test_utils.ts index d177934cb02e..dc70dcab33ea 100644 --- a/x-pack/plugins/security_solution/public/cases_test_utils.ts +++ b/x-pack/plugins/security_solution/public/cases_test_utils.ts @@ -5,34 +5,39 @@ * 2.0. */ -export const noCasesCapabilities = () => ({ +import type { CasesPermissions, CasesCapabilities } from '@kbn/cases-plugin/common'; + +export const noCasesCapabilities = (): CasesCapabilities => ({ create_cases: false, read_cases: false, update_cases: false, delete_cases: false, push_cases: false, - cases_connector: false, + cases_connectors: false, + cases_settings: false, }); -export const readCasesCapabilities = () => ({ +export const readCasesCapabilities = (): CasesCapabilities => ({ create_cases: false, read_cases: true, update_cases: false, delete_cases: false, push_cases: false, - cases_connector: true, + cases_connectors: true, + cases_settings: false, }); -export const allCasesCapabilities = () => ({ +export const allCasesCapabilities = (): CasesCapabilities => ({ create_cases: true, read_cases: true, update_cases: true, delete_cases: true, push_cases: true, - cases_connector: true, + cases_connectors: true, + cases_settings: true, }); -export const noCasesPermissions = () => ({ +export const noCasesPermissions = (): CasesPermissions => ({ all: false, create: false, read: false, @@ -40,9 +45,10 @@ export const noCasesPermissions = () => ({ delete: false, push: false, connectors: false, + settings: false, }); -export const readCasesPermissions = () => ({ +export const readCasesPermissions = (): CasesPermissions => ({ all: false, create: false, read: true, @@ -50,9 +56,10 @@ export const readCasesPermissions = () => ({ delete: false, push: false, connectors: true, + settings: false, }); -export const writeCasesPermissions = () => ({ +export const writeCasesPermissions = (): CasesPermissions => ({ all: false, create: true, read: false, @@ -60,9 +67,10 @@ export const writeCasesPermissions = () => ({ delete: true, push: true, connectors: true, + settings: true, }); -export const allCasesPermissions = () => ({ +export const allCasesPermissions = (): CasesPermissions => ({ all: true, create: true, read: true, @@ -70,4 +78,5 @@ export const allCasesPermissions = () => ({ delete: true, push: true, connectors: true, + settings: true, }); diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx index 83e2ee4a69ff..47d73a6d8262 100644 --- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx +++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/rounded_badge.tsx @@ -22,7 +22,8 @@ const RoundBadge = styled(EuiBadge)` margin: 0 5px 0 5px; padding: 7px 6px 4px 6px; user-select: none; - width: 34px; + width: 40px; + height: 40px; .euiBadge__content { position: relative; top: -1px; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.test.tsx b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.test.tsx new file mode 100644 index 000000000000..e9054a6817e1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.test.tsx @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { ASSIGNEES_APPLY_BUTTON_TEST_ID, ASSIGNEES_APPLY_PANEL_TEST_ID } from './test_ids'; +import { AssigneesApplyPanel } from './assignees_apply_panel'; + +import { useGetCurrentUserProfile } from '../user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../user_profiles/use_suggest_users'; +import { TestProviders } from '../../mock'; +import * as i18n from './translations'; +import { mockUserProfiles } from './mocks'; + +jest.mock('../user_profiles/use_get_current_user_profile'); +jest.mock('../user_profiles/use_bulk_get_user_profiles'); +jest.mock('../user_profiles/use_suggest_users'); + +const renderAssigneesApplyPanel = ( + { + assignedUserIds, + showUnassignedOption, + onSelectionChange, + onAssigneesApply, + }: { + assignedUserIds: string[]; + showUnassignedOption?: boolean; + onSelectionChange?: () => void; + onAssigneesApply?: () => void; + } = { assignedUserIds: [] } +) => { + const assignedProfiles = mockUserProfiles.filter((user) => assignedUserIds.includes(user.uid)); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: assignedProfiles, + }); + return render( + + + + ); +}; + +describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + }); + + it('should render component', () => { + const { getByTestId, queryByTestId } = renderAssigneesApplyPanel(); + + expect(getByTestId(ASSIGNEES_APPLY_PANEL_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should render apply button if `onAssigneesApply` callback provided', () => { + const { getByTestId } = renderAssigneesApplyPanel({ + assignedUserIds: [], + onAssigneesApply: jest.fn(), + }); + + expect(getByTestId(ASSIGNEES_APPLY_PANEL_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)).toBeInTheDocument(); + }); + + it('should render `no assignees` option', () => { + const { getByTestId } = renderAssigneesApplyPanel({ + assignedUserIds: [], + showUnassignedOption: true, + onAssigneesApply: jest.fn(), + }); + + const assigneesList = getByTestId('euiSelectableList'); + expect(assigneesList).toHaveTextContent(i18n.ASSIGNEES_NO_ASSIGNEES); + }); + + it('should call `onAssigneesApply` on apply button click', () => { + const onAssigneesApplyMock = jest.fn(); + const { getByText, getByTestId } = renderAssigneesApplyPanel({ + assignedUserIds: ['user-id-1'], + onAssigneesApply: onAssigneesApplyMock, + }); + + getByText(mockUserProfiles[1].user.full_name).click(); + getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID).click(); + + expect(onAssigneesApplyMock).toHaveBeenCalledTimes(1); + expect(onAssigneesApplyMock).toHaveBeenLastCalledWith(['user-id-2', 'user-id-1']); + }); + + it('should call `onSelectionChange` on user selection', () => { + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: [], + }); + + const onSelectionChangeMock = jest.fn(); + const { getByText } = renderAssigneesApplyPanel({ + assignedUserIds: [], + onSelectionChange: onSelectionChangeMock, + }); + + getByText('User 1').click(); + getByText('User 2').click(); + getByText('User 3').click(); + getByText('User 3').click(); + getByText('User 2').click(); + getByText('User 1').click(); + + expect(onSelectionChangeMock).toHaveBeenCalledTimes(6); + expect(onSelectionChangeMock.mock.calls).toEqual([ + [['user-id-1']], + [['user-id-2', 'user-id-1']], + [['user-id-3', 'user-id-2', 'user-id-1']], + [['user-id-2', 'user-id-1']], + [['user-id-1']], + [[]], + ]); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.tsx b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.tsx new file mode 100644 index 000000000000..a263b660b753 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_apply_panel.tsx @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isEqual } from 'lodash/fp'; +import type { FC } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; + +import { EuiButton } from '@elastic/eui'; +import { UserProfilesSelectable } from '@kbn/user-profile-components'; + +import { isEmpty } from 'lodash'; +import { useGetCurrentUserProfile } from '../user_profiles/use_get_current_user_profile'; +import * as i18n from './translations'; +import type { AssigneesIdsSelection, AssigneesProfilesSelection } from './types'; +import { NO_ASSIGNEES_VALUE } from './constants'; +import { useSuggestUsers } from '../user_profiles/use_suggest_users'; +import { useBulkGetUserProfiles } from '../user_profiles/use_bulk_get_user_profiles'; +import { bringCurrentUserToFrontAndSort, removeNoAssigneesSelection } from './utils'; +import { ASSIGNEES_APPLY_BUTTON_TEST_ID, ASSIGNEES_APPLY_PANEL_TEST_ID } from './test_ids'; + +export interface AssigneesApplyPanelProps { + /** + * Identifier of search field. + */ + searchInputId?: string; + + /** + * Ids of the users assigned to the alert + */ + assignedUserIds: AssigneesIdsSelection[]; + + /** + * Show "Unassigned" option if needed + */ + showUnassignedOption?: boolean; + + /** + * Callback to handle changing of the assignees selection + */ + onSelectionChange?: (users: AssigneesIdsSelection[]) => void; + + /** + * Callback to handle applying assignees. If provided will show "Apply assignees" button + */ + onAssigneesApply?: (selectedAssignees: AssigneesIdsSelection[]) => void; +} + +/** + * The popover to allow selection of users from a list + */ +export const AssigneesApplyPanel: FC = memo( + ({ + searchInputId, + assignedUserIds, + showUnassignedOption, + onSelectionChange, + onAssigneesApply, + }) => { + const { data: currentUserProfile } = useGetCurrentUserProfile(); + const existingIds = useMemo( + () => new Set(removeNoAssigneesSelection(assignedUserIds)), + [assignedUserIds] + ); + const { isLoading: isLoadingAssignedUsers, data: assignedUsers } = useBulkGetUserProfiles({ + uids: existingIds, + }); + + const [searchTerm, setSearchTerm] = useState(''); + const { isLoading: isLoadingSuggestedUsers, data: userProfiles } = useSuggestUsers({ + searchTerm, + }); + + const searchResultProfiles = useMemo(() => { + const sortedUsers = bringCurrentUserToFrontAndSort(currentUserProfile, userProfiles) ?? []; + + if (showUnassignedOption && isEmpty(searchTerm)) { + return [NO_ASSIGNEES_VALUE, ...sortedUsers]; + } + + return sortedUsers; + }, [currentUserProfile, searchTerm, showUnassignedOption, userProfiles]); + + const [selectedAssignees, setSelectedAssignees] = useState([]); + useEffect(() => { + if (isLoadingAssignedUsers || !assignedUsers) { + return; + } + const hasNoAssigneesSelection = assignedUserIds.find((uid) => uid === NO_ASSIGNEES_VALUE); + const newAssignees = + hasNoAssigneesSelection !== undefined + ? [NO_ASSIGNEES_VALUE, ...assignedUsers] + : assignedUsers; + setSelectedAssignees(newAssignees); + }, [assignedUserIds, assignedUsers, isLoadingAssignedUsers]); + + const handleSelectedAssignees = useCallback( + (newAssignees: AssigneesProfilesSelection[]) => { + if (!isEqual(newAssignees, selectedAssignees)) { + setSelectedAssignees(newAssignees); + onSelectionChange?.(newAssignees.map((assignee) => assignee?.uid ?? NO_ASSIGNEES_VALUE)); + } + }, + [onSelectionChange, selectedAssignees] + ); + + const handleApplyButtonClick = useCallback(() => { + const selectedIds = selectedAssignees.map((assignee) => assignee?.uid ?? NO_ASSIGNEES_VALUE); + onAssigneesApply?.(selectedIds); + }, [onAssigneesApply, selectedAssignees]); + + const selectedStatusMessage = useCallback( + (total: number) => i18n.ASSIGNEES_SELECTION_STATUS_MESSAGE(total), + [] + ); + + const isLoading = isLoadingAssignedUsers || isLoadingSuggestedUsers; + + return ( +
    + { + setSearchTerm(term); + }} + onChange={handleSelectedAssignees} + selectedStatusMessage={selectedStatusMessage} + options={searchResultProfiles} + selectedOptions={selectedAssignees} + isLoading={isLoading} + height={'full'} + singleSelection={false} + searchPlaceholder={i18n.ASSIGNEES_SEARCH_USERS} + clearButtonLabel={i18n.ASSIGNEES_CLEAR_FILTERS} + nullOptionLabel={i18n.ASSIGNEES_NO_ASSIGNEES} + /> + {onAssigneesApply && ( + + {i18n.ASSIGNEES_APPLY_BUTTON} + + )} +
    + ); + } +); + +AssigneesApplyPanel.displayName = 'AssigneesPanel'; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.test.tsx b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.test.tsx new file mode 100644 index 000000000000..d26cb35c1fc9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.test.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { ASSIGNEES_APPLY_PANEL_TEST_ID } from './test_ids'; +import { AssigneesPopover } from './assignees_popover'; + +import { useGetCurrentUserProfile } from '../user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../user_profiles/use_suggest_users'; +import { TestProviders } from '../../mock'; +import { mockUserProfiles } from './mocks'; +import { EuiButton } from '@elastic/eui'; + +jest.mock('../user_profiles/use_get_current_user_profile'); +jest.mock('../user_profiles/use_bulk_get_user_profiles'); +jest.mock('../user_profiles/use_suggest_users'); + +const MOCK_BUTTON_TEST_ID = 'mock-assignees-button'; + +const renderAssigneesPopover = ({ + assignedUserIds, + isPopoverOpen, +}: { + assignedUserIds: string[]; + isPopoverOpen: boolean; +}) => { + const assignedProfiles = mockUserProfiles.filter((user) => assignedUserIds.includes(user.uid)); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: assignedProfiles, + }); + return render( + + } + isPopoverOpen={isPopoverOpen} + closePopover={jest.fn()} + /> + + ); +}; + +describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + }); + + it('should render closed popover component', () => { + const { getByTestId, queryByTestId } = renderAssigneesPopover({ + assignedUserIds: [], + isPopoverOpen: false, + }); + + expect(getByTestId(MOCK_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ASSIGNEES_APPLY_PANEL_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should render opened popover component', () => { + const { getByTestId } = renderAssigneesPopover({ + assignedUserIds: [], + isPopoverOpen: true, + }); + + expect(getByTestId(MOCK_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_APPLY_PANEL_TEST_ID)).toBeInTheDocument(); + }); + + it('should render assignees', () => { + const { getByTestId } = renderAssigneesPopover({ + assignedUserIds: [], + isPopoverOpen: true, + }); + + const assigneesList = getByTestId('euiSelectableList'); + expect(assigneesList).toHaveTextContent('User 1'); + expect(assigneesList).toHaveTextContent('user1@test.com'); + expect(assigneesList).toHaveTextContent('User 2'); + expect(assigneesList).toHaveTextContent('user2@test.com'); + expect(assigneesList).toHaveTextContent('User 3'); + expect(assigneesList).toHaveTextContent('user3@test.com'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.tsx b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.tsx new file mode 100644 index 000000000000..b392855aaf6f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/assignees_popover.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC, ReactNode } from 'react'; +import React, { memo } from 'react'; + +import { EuiPopover, useGeneratedHtmlId } from '@elastic/eui'; + +import { ASSIGNEES_PANEL_WIDTH } from './constants'; +import { AssigneesApplyPanel } from './assignees_apply_panel'; +import type { AssigneesIdsSelection } from './types'; + +export interface AssigneesPopoverProps { + /** + * Ids of the users assigned to the alert + */ + assignedUserIds: AssigneesIdsSelection[]; + + /** + * Show "Unassigned" option if needed + */ + showUnassignedOption?: boolean; + + /** + * Triggering element for which to align the popover to + */ + button: NonNullable; + + /** + * Boolean to allow popover to be opened or closed + */ + isPopoverOpen: boolean; + + /** + * Callback to handle hiding of the popover + */ + closePopover: () => void; + + /** + * Callback to handle changing of the assignees selection + */ + onSelectionChange?: (users: AssigneesIdsSelection[]) => void; + + /** + * Callback to handle applying assignees + */ + onAssigneesApply?: (selectedAssignees: AssigneesIdsSelection[]) => void; +} + +/** + * The popover to allow selection of users from a list + */ +export const AssigneesPopover: FC = memo( + ({ + assignedUserIds, + showUnassignedOption, + button, + isPopoverOpen, + closePopover, + onSelectionChange, + onAssigneesApply, + }) => { + const searchInputId = useGeneratedHtmlId({ + prefix: 'searchInput', + }); + + return ( + + + + ); + } +); + +AssigneesPopover.displayName = 'AssigneesPopover'; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/constants.ts b/x-pack/plugins/security_solution/public/common/components/assignees/constants.ts new file mode 100644 index 000000000000..fe12bff429ea --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/constants.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const ASSIGNEES_PANEL_WIDTH = 400; + +export const NO_ASSIGNEES_VALUE = null; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/mocks.ts b/x-pack/plugins/security_solution/public/common/components/assignees/mocks.ts new file mode 100644 index 000000000000..a3e578eb4ae3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/mocks.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const mockUserProfiles = [ + { + uid: 'user-id-1', + enabled: true, + user: { username: 'user1', full_name: 'User 1', email: 'user1@test.com' }, + data: {}, + }, + { + uid: 'user-id-2', + enabled: true, + user: { username: 'user2', full_name: 'User 2', email: 'user2@test.com' }, + data: {}, + }, + { + uid: 'user-id-3', + enabled: true, + user: { username: 'user3', full_name: 'User 3', email: 'user3@test.com' }, + data: {}, + }, +]; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/test_ids.ts b/x-pack/plugins/security_solution/public/common/components/assignees/test_ids.ts new file mode 100644 index 000000000000..0842e8b5f3e9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/test_ids.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const PREFIX = 'securitySolutionAssignees'; + +/* Apply Panel */ +export const ASSIGNEES_APPLY_PANEL_TEST_ID = `${PREFIX}ApplyPanel`; +export const ASSIGNEES_APPLY_BUTTON_TEST_ID = `${PREFIX}ApplyButton`; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts b/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts new file mode 100644 index 000000000000..fdd22f50aa7c --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const ASSIGNEES_SELECTION_STATUS_MESSAGE = (total: number) => + i18n.translate('xpack.securitySolution.assignees.totalUsersAssigned', { + defaultMessage: '{total, plural, one {# filter} other {# filters}} selected', + values: { total }, + }); + +export const ASSIGNEES_APPLY_BUTTON = i18n.translate( + 'xpack.securitySolution.assignees.applyButtonTitle', + { + defaultMessage: 'Apply', + } +); + +export const ASSIGNEES_SEARCH_USERS = i18n.translate( + 'xpack.securitySolution.assignees.selectableSearchPlaceholder', + { + defaultMessage: 'Search users', + } +); + +export const ASSIGNEES_CLEAR_FILTERS = i18n.translate( + 'xpack.securitySolution.assignees.clearFilters', + { + defaultMessage: 'Clear filters', + } +); + +export const ASSIGNEES_NO_ASSIGNEES = i18n.translate( + 'xpack.securitySolution.assignees.noAssigneesLabel', + { + defaultMessage: 'No assignees', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/types.ts b/x-pack/plugins/security_solution/public/common/components/assignees/types.ts new file mode 100644 index 000000000000..3ee7b04dc23a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/types.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; + +export type AssigneesIdsSelection = string | null; +export type AssigneesProfilesSelection = UserProfileWithAvatar | null; diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/utils.test.tsx b/x-pack/plugins/security_solution/public/common/components/assignees/utils.test.tsx new file mode 100644 index 000000000000..0b75e90a91b3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/utils.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { NO_ASSIGNEES_VALUE } from './constants'; +import { mockUserProfiles } from './mocks'; +import { bringCurrentUserToFrontAndSort, removeNoAssigneesSelection } from './utils'; + +describe('utils', () => { + describe('removeNoAssigneesSelection', () => { + it('should return user ids if `no assignees` has not been passed', () => { + const assignees = ['user1', 'user2', 'user3']; + const ids = removeNoAssigneesSelection(assignees); + expect(ids).toEqual(assignees); + }); + + it('should return user ids and remove `no assignees`', () => { + const assignees = [NO_ASSIGNEES_VALUE, 'user1', 'user2', NO_ASSIGNEES_VALUE, 'user3']; + const ids = removeNoAssigneesSelection(assignees); + expect(ids).toEqual(['user1', 'user2', 'user3']); + }); + }); + + describe('bringCurrentUserToFrontAndSort', () => { + it('should return `undefined` if nothing has been passed', () => { + const sortedProfiles = bringCurrentUserToFrontAndSort(); + expect(sortedProfiles).toBeUndefined(); + }); + + it('should return passed profiles if current user is `undefined`', () => { + const sortedProfiles = bringCurrentUserToFrontAndSort(undefined, mockUserProfiles); + expect(sortedProfiles).toEqual(mockUserProfiles); + }); + + it('should return profiles with the current user on top', () => { + const currentUser = mockUserProfiles[1]; + const sortedProfiles = bringCurrentUserToFrontAndSort(currentUser, mockUserProfiles); + expect(sortedProfiles).toEqual([currentUser, mockUserProfiles[0], mockUserProfiles[2]]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/utils.ts b/x-pack/plugins/security_solution/public/common/components/assignees/utils.ts new file mode 100644 index 000000000000..9eae9503febd --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/assignees/utils.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { sortBy } from 'lodash'; + +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; + +import { NO_ASSIGNEES_VALUE } from './constants'; +import type { AssigneesIdsSelection } from './types'; + +const getSortField = (profile: UserProfileWithAvatar) => + profile.user?.full_name?.toLowerCase() ?? + profile.user?.email?.toLowerCase() ?? + profile.user?.username.toLowerCase(); + +const sortProfiles = (profiles?: UserProfileWithAvatar[]) => { + if (!profiles) { + return; + } + + return sortBy(profiles, getSortField); +}; + +const moveCurrentUserToBeginning = ( + currentUserProfile?: T, + profiles?: T[] +) => { + if (!profiles) { + return; + } + + if (!currentUserProfile) { + return profiles; + } + + const currentProfileIndex = profiles.find((profile) => profile.uid === currentUserProfile.uid); + + if (!currentProfileIndex) { + return profiles; + } + + const profilesWithoutCurrentUser = profiles.filter( + (profile) => profile.uid !== currentUserProfile.uid + ); + + return [currentUserProfile, ...profilesWithoutCurrentUser]; +}; + +export const bringCurrentUserToFrontAndSort = ( + currentUserProfile?: UserProfileWithAvatar, + profiles?: UserProfileWithAvatar[] +) => moveCurrentUserToBeginning(currentUserProfile, sortProfiles(profiles)); + +export const removeNoAssigneesSelection = (assignees: AssigneesIdsSelection[]): string[] => + assignees.filter((assignee): assignee is string => assignee !== NO_ASSIGNEES_VALUE); diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx index ca82da005c70..93a29b9ea443 100644 --- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx @@ -13,7 +13,7 @@ import { dataTableActions, TableId } from '@kbn/securitysolution-data-table'; import { useUiSetting$ } from '@kbn/kibana-react-plugin/public'; import { timelineActions } from '../../../../timelines/store/timeline'; import { ENABLE_EXPANDABLE_FLYOUT_SETTING } from '../../../../../common/constants'; -import { RightPanelKey } from '../../../../flyout/document_details/right'; +import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/right'; import type { SetEventsDeleted, SetEventsLoading, @@ -24,6 +24,7 @@ import { getMappedNonEcsValue } from '../../../../timelines/components/timeline/ import type { TimelineItem, TimelineNonEcsData } from '../../../../../common/search_strategy'; import type { ColumnHeaderOptions, OnRowSelected } from '../../../../../common/types/timeline'; import { TimelineId } from '../../../../../common/types'; +import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; type Props = EuiDataGridCellValueElementProps & { columnHeaders: ColumnHeaderOptions[]; @@ -73,6 +74,9 @@ const RowActionComponent = ({ const dispatch = useDispatch(); const [isSecurityFlyoutEnabled] = useUiSetting$(ENABLE_EXPANDABLE_FLYOUT_SETTING); + const isExpandableFlyoutInCreateRuleEnabled = useIsExperimentalFeatureEnabled( + 'expandableFlyoutInCreateRuleEnabled' + ); const columnValues = useMemo( () => @@ -89,6 +93,13 @@ const RowActionComponent = ({ [columnHeaders, timelineNonEcsData] ); + let showExpandableFlyout: boolean; + if (tableId === TableId.rulePreview) { + showExpandableFlyout = isSecurityFlyoutEnabled && isExpandableFlyoutInCreateRuleEnabled; + } else { + showExpandableFlyout = isSecurityFlyoutEnabled; + } + const handleOnEventDetailPanelOpened = useCallback(() => { const updatedExpandedDetail: ExpandedDetailType = { panelView: 'eventDetail', @@ -98,12 +109,10 @@ const RowActionComponent = ({ }, }; - // TODO remove when https://github.com/elastic/security-team/issues/7760 is merged - // excluding rule preview page as some sections in new flyout are not applicable when user is creating a new rule - if (isSecurityFlyoutEnabled && tableId !== TableId.rulePreview) { + if (showExpandableFlyout) { openFlyout({ right: { - id: RightPanelKey, + id: DocumentDetailsRightPanelKey, params: { id: eventId, indexName, @@ -133,7 +142,7 @@ const RowActionComponent = ({ }) ); } - }, [dispatch, eventId, indexName, isSecurityFlyoutEnabled, openFlyout, tabType, tableId]); + }, [dispatch, eventId, indexName, openFlyout, tabType, tableId, showExpandableFlyout]); const Action = controlColumn.rowCellRender; diff --git a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx index 8463097d98d0..fddf6a1afc6e 100644 --- a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx @@ -23,6 +23,7 @@ import { useKibana } from '../../lib/kibana'; import type { State } from '../../store'; import { createStore } from '../../store'; import { TimelineId } from '../../../../common/types'; +import * as timelineActions from '../../../timelines/store/timeline/actions'; import type { ComponentType, FC, PropsWithChildren } from 'react'; import React from 'react'; import type { DataView } from '@kbn/data-views-plugin/common'; @@ -35,6 +36,17 @@ let mockDiscoverStateContainerRef = { }; jest.mock('../../lib/kibana'); + +const mockDispatch = jest.fn(); + +jest.mock('react-redux', () => { + const actual = jest.requireActual('react-redux'); + return { + ...actual, + useDispatch: () => mockDispatch, + }; +}); + const mockState: State = { ...mockGlobalState, timeline: { @@ -239,7 +251,7 @@ describe('useDiscoverInTimelineActions', () => { }) ); }); - it('should send update request when savedSearchId is already available', async () => { + it('should initialize saved search when it is not set on the timeline model yet', async () => { const localMockState: State = { ...mockGlobalState, timeline: { @@ -262,22 +274,49 @@ describe('useDiscoverInTimelineActions', () => { await result.current.updateSavedSearch(savedSearchMock, TimelineId.active); }); - expect(startServicesMock.savedSearch.save).toHaveBeenNthCalledWith( + expect(mockDispatch).toHaveBeenNthCalledWith( 1, - expect.objectContaining({ - timeRestore: true, - timeRange: { - from: 'now-20d', - to: 'now', + timelineActions.initializeSavedSearch({ + id: TimelineId.active, + savedSearch: savedSearchMock, + }) + ); + }); + + it('should update saved search when it has changes', async () => { + const changedSavedSearchMock = { ...savedSearchMock, title: 'changed' }; + const localMockState: State = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + ...mockGlobalState.timeline.timelineById, + [TimelineId.active]: { + ...mockGlobalState.timeline.timelineById[TimelineId.active], + title: 'Active Timeline', + description: 'Active Timeline Description', + savedSearchId: 'saved_search_id', + savedSearch: savedSearchMock, + }, }, - tags: ['security-solution-default'], - id: 'saved_search_id', - }), - expect.objectContaining({ - copyOnSave: false, + }, + }; + + const LocalTestProvider = getTestProviderWithCustomState(localMockState); + const { result } = renderTestHook(LocalTestProvider); + await act(async () => { + await result.current.updateSavedSearch(changedSavedSearchMock, TimelineId.active); + }); + + expect(mockDispatch).toHaveBeenNthCalledWith( + 1, + timelineActions.updateSavedSearch({ + id: TimelineId.active, + savedSearch: changedSavedSearchMock, }) ); }); + it('should raise appropriate notification in case of any error in saving discover saved search', () => {}); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx index 2d676dbfb666..3479612b8e7b 100644 --- a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx @@ -7,14 +7,13 @@ import type { DiscoverStateContainer } from '@kbn/discover-plugin/public'; import type { SaveSavedSearchOptions } from '@kbn/saved-search-plugin/public'; +import { useMemo, useCallback, useRef } from 'react'; import type { RefObject } from 'react'; -import { useMemo, useCallback } from 'react'; import { useDispatch } from 'react-redux'; import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { DiscoverAppState } from '@kbn/discover-plugin/public/application/main/services/discover_app_state_container'; import type { TimeRange } from '@kbn/es-query'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { endTimelineSaving, startTimelineSaving } from '../../../timelines/store/timeline/actions'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { TimelineId } from '../../../../common/types'; import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline'; @@ -57,6 +56,10 @@ export const useDiscoverInTimelineActions = ( ); const { savedSearchId } = timeline; + // We're using a ref here to prevent a cyclic hook-dependency chain of updateSavedSearch + const timelineRef = useRef(timeline); + timelineRef.current = timeline; + const queryClient = useQueryClient(); const { mutateAsync: saveSavedSearch } = useMutation({ @@ -134,7 +137,7 @@ export const useDiscoverInTimelineActions = ( * */ const resetDiscoverAppState = useCallback(async () => { const defaultDiscoverAppState = await getDefaultDiscoverAppState(); - discoverStateContainer.current?.appState.set(defaultDiscoverAppState); + discoverStateContainer.current?.appState.replaceUrlState(defaultDiscoverAppState); discoverStateContainer.current?.globalState.set({ ...discoverStateContainer.current?.globalState.get(), time: defaultDiscoverTimeRange, @@ -177,60 +180,90 @@ export const useDiscoverInTimelineActions = ( * */ const updateSavedSearch = useCallback( async (savedSearch: SavedSearch, timelineId: string) => { - dispatch( - startTimelineSaving({ - id: timelineId, - }) - ); savedSearch.timeRestore = true; savedSearch.timeRange = savedSearch.timeRange ?? discoverDataService.query.timefilter.timefilter.getTime(); savedSearch.tags = ['security-solution-default']; + // If there is already a saved search, only update the local state if (savedSearchId) { savedSearch.id = savedSearchId; - } - try { - const response = await persistSavedSearch(savedSearch, { - onTitleDuplicate: () => {}, - copyOnSave: !savedSearchId, - }); - - if (!response || !response.id) { - throw new Error('Unknown Error occured'); + if (!timelineRef.current.savedSearch) { + dispatch( + timelineActions.initializeSavedSearch({ + id: TimelineId.active, + savedSearch, + }) + ); + } else { + dispatch( + timelineActions.updateSavedSearch({ + id: TimelineId.active, + savedSearch, + }) + ); } + } else { + // If no saved search exists. Create a new saved search instance and associate it with the timeline. + try { + dispatch( + timelineActions.startTimelineSaving({ + id: TimelineId.active, + }) + ); + const response = await persistSavedSearch(savedSearch, { + onTitleDuplicate: () => {}, + copyOnSave: !savedSearchId, + }); + + if (!response || !response.id) { + throw new Error('Unknown Error occured'); + } - if (!savedSearchId) { + if (!savedSearchId) { + dispatch( + timelineActions.updateSavedSearchId({ + id: TimelineId.active, + savedSearchId: response.id, + }) + ); + // Also save the timeline, this will only happen once, in case there is no saved search id yet + dispatch(timelineActions.saveTimeline({ id: TimelineId.active, saveAsNew: false })); + } + } catch (err) { + addError(DISCOVER_SEARCH_SAVE_ERROR_TITLE, { + title: DISCOVER_SEARCH_SAVE_ERROR_TITLE, + toastMessage: String(err), + }); dispatch( - timelineActions.updateSavedSearchId({ + timelineActions.endTimelineSaving({ id: TimelineId.active, - savedSearchId: response.id, }) ); - // Also save the timeline, this will only happen once, in case there is no saved search id yet - dispatch(timelineActions.saveTimeline({ id: TimelineId.active })); } - } catch (err) { - addError(DISCOVER_SEARCH_SAVE_ERROR_TITLE, { - title: DISCOVER_SEARCH_SAVE_ERROR_TITLE, - toastMessage: String(err), - }); - } finally { - dispatch( - endTimelineSaving({ - id: timelineId, - }) - ); } }, [persistSavedSearch, savedSearchId, addError, dispatch, discoverDataService] ); + const initializeLocalSavedSearch = useCallback( + async (savedSearch: SavedSearch, timelineId: string) => { + dispatch( + timelineActions.initializeSavedSearch({ + id: TimelineId.active, + savedSearch, + }) + ); + }, + [dispatch] + ); + const actions = useMemo( () => ({ resetDiscoverAppState, restoreDiscoverAppStateFromSavedSearch, updateSavedSearch, + initializeLocalSavedSearch, getAppStateFromSavedSearch, getDefaultDiscoverAppState, }), @@ -238,6 +271,7 @@ export const useDiscoverInTimelineActions = ( resetDiscoverAppState, restoreDiscoverAppStateFromSavedSearch, updateSavedSearch, + initializeLocalSavedSearch, getAppStateFromSavedSearch, getDefaultDiscoverAppState, ] diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx index 041ef14721b3..a1455f7e5cc0 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx @@ -7,14 +7,13 @@ import { noop, pick } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; -import type { DropResult } from '@hello-pangea/dnd'; +import type { DragStart, DropResult } from '@hello-pangea/dnd'; import { DragDropContext } from '@hello-pangea/dnd'; import { useDispatch } from 'react-redux'; import type { Dispatch } from 'redux'; import deepEqual from 'fast-deep-equal'; import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid'; -import type { BeforeCapture } from './drag_drop_context'; import type { BrowserFields } from '../../containers/source'; import { dragAndDropSelectors } from '../../store'; import { timelineSelectors } from '../../../timelines/store/timeline'; @@ -151,8 +150,9 @@ export const DragDropContextWrapperComponent: React.FC = ({ browserFields }, [activeTimelineDataProviders, browserFields, dataProviders, dispatch, onAddedToTimeline] ); + return ( - + {children} ); @@ -168,12 +168,12 @@ export const DragDropContextWrapper = React.memo( DragDropContextWrapper.displayName = 'DragDropContextWrapper'; -const onBeforeCapture = (before: BeforeCapture) => { - if (!draggableIsField(before)) { +const onBeforeDragStart = (start: DragStart) => { + if (!draggableIsField(start)) { document.body.classList.add(IS_DRAGGING_CLASS_NAME); } - if (draggableIsField(before)) { + if (draggableIsField(start)) { document.body.classList.add(IS_TIMELINE_FIELD_DRAGGING_CLASS_NAME); } }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx index edc72e92ff15..2718c3adf201 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx @@ -26,7 +26,7 @@ import { mockAlertDetailsData } from './__mocks__'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; import { TimelineTabs } from '../../../../common/types/timeline'; import { useInvestigationTimeEnrichment } from '../../containers/cti/event_enrichment'; -import { useGetUserCasesPermissions, useKibana } from '../../lib/kibana'; +import { useKibana } from '../../lib/kibana'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; @@ -44,14 +44,8 @@ jest.mock('../../../timelines/components/timeline/body/renderers', () => { }); jest.mock('../../lib/kibana'); -const originalKibanaLib = jest.requireActual('../../lib/kibana'); const useKibanaMock = useKibana as jest.Mocked; -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); - jest.mock('../../containers/cti/event_enrichment'); jest.mock('../../../detection_engine/rule_management/logic/use_rule_with_fallback', () => { diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx index 2ef1277884c1..b9b132763d6f 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx @@ -12,7 +12,6 @@ import { TestProviders } from '../../../mock'; import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; import { useKibana as mockUseKibana } from '../../../lib/kibana/__mocks__'; -import { useGetUserCasesPermissions } from '../../../lib/kibana'; import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { licenseService } from '../../../hooks/use_license'; import { noCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils'; @@ -20,12 +19,13 @@ import { Insights } from './insights'; import * as i18n from './translations'; const mockedUseKibana = mockUseKibana(); +const mockCanUseCases = jest.fn(); + jest.mock('../../../lib/kibana', () => { const original = jest.requireActual('../../../lib/kibana'); return { ...original, - useGetUserCasesPermissions: jest.fn(), useToasts: jest.fn().mockReturnValue({ addWarning: jest.fn() }), useKibana: () => ({ ...mockedUseKibana, @@ -35,12 +35,12 @@ jest.mock('../../../lib/kibana', () => { api: { getRelatedCases: jest.fn(), }, + helpers: { canUseCases: mockCanUseCases }, }, }, }), }; }); -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; jest.mock('../../../hooks/use_license', () => { const licenseServiceInstance = { @@ -94,7 +94,7 @@ const data: TimelineEventsDetailsItem[] = [ describe('Insights', () => { beforeEach(() => { - mockUseGetUserCasesPermissions.mockReturnValue(noCasesPermissions()); + mockCanUseCases.mockReturnValue(noCasesPermissions()); }); it('does not render when there is no content to show', () => { @@ -116,7 +116,7 @@ describe('Insights', () => { // It will show for all users that are able to read case data. // Enabling that permission, will show the case insight module which // is necessary to pass this test. - mockUseGetUserCasesPermissions.mockReturnValue(readCasesPermissions()); + mockCanUseCases.mockReturnValue(readCasesPermissions()); render( diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx index e4e4f317467e..60c89438aa12 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx @@ -11,12 +11,12 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { ALERT_SUPPRESSION_DOCS_COUNT } from '@kbn/rule-data-utils'; import { find } from 'lodash/fp'; +import { APP_ID } from '../../../../../common'; import * as i18n from './translations'; import type { BrowserFields } from '../../../containers/source'; import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; import { hasData } from './helpers'; -import { useGetUserCasesPermissions } from '../../../lib/kibana'; import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { useLicense } from '../../../hooks/use_license'; import { RelatedAlertsByProcessAncestry } from './related_alerts_by_process_ancestry'; @@ -24,6 +24,7 @@ import { RelatedCases } from './related_cases'; import { RelatedAlertsBySourceEvent } from './related_alerts_by_source_event'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { RelatedAlertsUpsell } from './related_alerts_upsell'; +import { useKibana } from '../../../lib/kibana'; const StyledInsightItem = euiStyled(EuiFlexItem)` border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; @@ -45,6 +46,7 @@ interface Props { */ export const Insights = React.memo( ({ browserFields, eventId, data, isReadOnly, scopeId }) => { + const { cases } = useKibana().services; const isRelatedAlertsByProcessAncestryEnabled = useIsExperimentalFeatureEnabled( 'insightsRelatedAlertsByProcessAncestry' ); @@ -83,7 +85,7 @@ export const Insights = React.memo( ); const hasAlertSuppressionField = hasData(alertSuppressionField); - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const hasCasesReadPermissions = userCasesPermissions.read; // Make sure that the alert has at least one of the associated fields diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx index 303e55ff66b9..10a9c872e391 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx @@ -6,17 +6,11 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiText } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { SubscriptionLink } from '@kbn/subscription-tracking'; -import type { SubscriptionContextData } from '@kbn/subscription-tracking'; import { INSIGHTS_UPSELL } from './translations'; - -const subscriptionContext: SubscriptionContextData = { - feature: 'alert-details-insights', - source: 'security__alert-details-flyout', -}; +import { useKibana } from '../../../lib/kibana'; const UpsellContainer = euiStyled.div` border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; @@ -29,6 +23,7 @@ const StyledIcon = euiStyled(EuiIcon)` `; export const RelatedAlertsUpsell = React.memo(() => { + const { application } = useKibana().services; return ( @@ -37,13 +32,15 @@ export const RelatedAlertsUpsell = React.memo(() => {
    - {INSIGHTS_UPSELL} - +
    diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_cases.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_cases.test.tsx index 8e6bc304e1a3..52a6d5eb1eb4 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_cases.test.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { TestProviders } from '../../../mock'; import { useKibana as mockUseKibana } from '../../../lib/kibana/__mocks__'; -import { useGetUserCasesPermissions } from '../../../lib/kibana'; import { RelatedCases } from './related_cases'; import { noCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils'; import { CASES_LOADING, CASES_COUNT } from './translations'; @@ -19,13 +18,14 @@ import { AlertsCasesTourSteps } from '../../guided_onboarding_tour/tour_config'; const mockedUseKibana = mockUseKibana(); const mockGetRelatedCases = jest.fn(); +const mockCanUseCases = jest.fn(); + jest.mock('../../guided_onboarding_tour'); jest.mock('../../../lib/kibana', () => { const original = jest.requireActual('../../../lib/kibana'); return { ...original, - useGetUserCasesPermissions: jest.fn(), useToasts: jest.fn().mockReturnValue({ addWarning: jest.fn() }), useKibana: () => ({ ...mockedUseKibana, @@ -35,6 +35,7 @@ jest.mock('../../../lib/kibana', () => { api: { getRelatedCases: mockGetRelatedCases, }, + helpers: { canUseCases: mockCanUseCases }, }, }, }), @@ -47,7 +48,7 @@ window.HTMLElement.prototype.scrollIntoView = scrollToMock; describe('Related Cases', () => { beforeEach(() => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions()); + mockCanUseCases.mockReturnValue(readCasesPermissions()); (useTourContext as jest.Mock).mockReturnValue({ activeStep: AlertsCasesTourSteps.viewCase, incrementStep: () => null, @@ -58,7 +59,7 @@ describe('Related Cases', () => { }); describe('When user does not have cases read permissions', () => { beforeEach(() => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(noCasesPermissions()); + mockCanUseCases.mockReturnValue(noCasesPermissions()); }); test('should not show related cases when user does not have permissions', async () => { await act(async () => { diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx index cef3117cf28c..903f1f7c548c 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx @@ -22,7 +22,6 @@ import { useTimelineEvents } from './use_timelines_events'; import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; import type { UseFieldBrowserOptionsProps } from '../../../timelines/components/fields_browser'; -import { useGetUserCasesPermissions } from '../../lib/kibana'; import { TableId } from '@kbn/securitysolution-data-table'; import { mount } from 'enzyme'; @@ -38,13 +37,6 @@ jest.mock('react-redux', () => { }; }); -const originalKibanaLib = jest.requireActual('../../lib/kibana'); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); - jest.mock('./use_timelines_events'); jest.mock('../../utils/normalize_time_range'); diff --git a/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx b/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx index ee47fca53543..d4652c4f5b62 100644 --- a/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exit_full_screen/index.tsx @@ -7,16 +7,11 @@ import { EuiButton, EuiWindowEvent } from '@elastic/eui'; import React, { useCallback } from 'react'; -import styled from 'styled-components'; import * as i18n from './translations'; export const EXIT_FULL_SCREEN_CLASS_NAME = 'exit-full-screen'; -const StyledEuiButton = styled(EuiButton)` - margin: ${({ theme }) => theme.eui.euiSizeS}; -`; - interface Props { fullScreen: boolean; setFullScreen: (fullScreen: boolean) => void; @@ -45,16 +40,17 @@ const ExitFullScreenComponent: React.FC = ({ fullScreen, setFullScreen }) return ( <> - {i18n.EXIT_FULL_SCREEN} - +
    ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/filter_group/constants.ts b/x-pack/plugins/security_solution/public/common/components/filter_group/constants.ts index 873355fa60a7..9eef5311b278 100644 --- a/x-pack/plugins/security_solution/public/common/components/filter_group/constants.ts +++ b/x-pack/plugins/security_solution/public/common/components/filter_group/constants.ts @@ -24,6 +24,7 @@ export const TEST_IDS = { EDIT: 'filter-group__context--edit', DISCARD: `filter-group__context--discard`, }, + FILTER_BY_ASSIGNEES_BUTTON: 'filter-popover-button-assignees', }; export const COMMON_OPTIONS_LIST_CONTROL_INPUTS: Partial = { diff --git a/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.test.tsx b/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.test.tsx new file mode 100644 index 000000000000..872d6f8e901a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.test.tsx @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { FilterByAssigneesPopover } from './filter_by_assignees'; +import { TEST_IDS } from './constants'; +import { TestProviders } from '../../mock'; +import type { AssigneesIdsSelection } from '../assignees/types'; + +import { useGetCurrentUserProfile } from '../user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../user_profiles/use_suggest_users'; +import { useLicense } from '../../hooks/use_license'; +import { useUpsellingMessage } from '../../hooks/use_upselling'; + +jest.mock('../user_profiles/use_get_current_user_profile'); +jest.mock('../user_profiles/use_bulk_get_user_profiles'); +jest.mock('../user_profiles/use_suggest_users'); +jest.mock('../../hooks/use_license'); +jest.mock('../../hooks/use_upselling'); + +const mockUserProfiles = [ + { + uid: 'user-id-1', + enabled: true, + user: { username: 'user1', full_name: 'User 1', email: 'user1@test.com' }, + data: {}, + }, + { + uid: 'user-id-2', + enabled: true, + user: { username: 'user2', full_name: 'User 2', email: 'user2@test.com' }, + data: {}, + }, + { + uid: 'user-id-3', + enabled: true, + user: { username: 'user3', full_name: 'User 3', email: 'user3@test.com' }, + data: {}, + }, +]; + +const renderFilterByAssigneesPopover = ( + alertAssignees: AssigneesIdsSelection[] = [], + onUsersChange = jest.fn() +) => + render( + + + + ); + +describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: [], + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => true }); + (useUpsellingMessage as jest.Mock).mockReturnValue('Go for Platinum!'); + }); + + it('should render closed popover component', () => { + const { getByTestId, queryByTestId } = renderFilterByAssigneesPopover(); + + expect(getByTestId(TEST_IDS.FILTER_BY_ASSIGNEES_BUTTON)).toBeInTheDocument(); + expect(queryByTestId('euiSelectableList')).not.toBeInTheDocument(); + }); + + it('should render opened popover component', () => { + const { getByTestId } = renderFilterByAssigneesPopover(); + + getByTestId(TEST_IDS.FILTER_BY_ASSIGNEES_BUTTON).click(); + expect(getByTestId('euiSelectableList')).toBeInTheDocument(); + }); + + it('should render assignees', () => { + const { getByTestId } = renderFilterByAssigneesPopover(); + + getByTestId(TEST_IDS.FILTER_BY_ASSIGNEES_BUTTON).click(); + + const assigneesList = getByTestId('euiSelectableList'); + expect(assigneesList).toHaveTextContent('User 1'); + expect(assigneesList).toHaveTextContent('user1@test.com'); + expect(assigneesList).toHaveTextContent('User 2'); + expect(assigneesList).toHaveTextContent('user2@test.com'); + expect(assigneesList).toHaveTextContent('User 3'); + expect(assigneesList).toHaveTextContent('user3@test.com'); + }); + + it('should call onUsersChange on closing the popover', () => { + const onUsersChangeMock = jest.fn(); + const { getByTestId, getByText } = renderFilterByAssigneesPopover([], onUsersChangeMock); + + getByTestId(TEST_IDS.FILTER_BY_ASSIGNEES_BUTTON).click(); + + getByText('User 1').click(); + getByText('User 2').click(); + getByText('User 3').click(); + getByText('User 3').click(); + getByText('User 2').click(); + getByText('User 1').click(); + + expect(onUsersChangeMock).toHaveBeenCalledTimes(6); + expect(onUsersChangeMock.mock.calls).toEqual([ + [['user-id-1']], + [['user-id-2', 'user-id-1']], + [['user-id-3', 'user-id-2', 'user-id-1']], + [['user-id-2', 'user-id-1']], + [['user-id-1']], + [[]], + ]); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.tsx b/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.tsx new file mode 100644 index 000000000000..fbef830dd1b8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/filter_group/filter_by_assignees.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { memo, useCallback, useState } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiFilterButton, EuiFilterGroup, EuiToolTip } from '@elastic/eui'; + +import { TEST_IDS } from './constants'; +import { AssigneesPopover } from '../assignees/assignees_popover'; +import type { AssigneesIdsSelection } from '../assignees/types'; +import { useLicense } from '../../hooks/use_license'; +import { useUpsellingMessage } from '../../hooks/use_upselling'; + +export interface FilterByAssigneesPopoverProps { + /** + * Ids of the users assigned to the alert + */ + assignedUserIds: AssigneesIdsSelection[]; + + /** + * Callback to handle changing of the assignees selection + */ + onSelectionChange?: (users: AssigneesIdsSelection[]) => void; +} + +/** + * The popover to filter alerts by assigned users + */ +export const FilterByAssigneesPopover: FC = memo( + ({ assignedUserIds, onSelectionChange }) => { + const isPlatinumPlus = useLicense().isPlatinumPlus(); + const upsellingMessage = useUpsellingMessage('alert_assignments'); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const togglePopover = useCallback(() => setIsPopoverOpen((value) => !value), []); + + const [selectedAssignees, setSelectedAssignees] = + useState(assignedUserIds); + const handleSelectionChange = useCallback( + (users: AssigneesIdsSelection[]) => { + setSelectedAssignees(users); + onSelectionChange?.(users); + }, + [onSelectionChange] + ); + + return ( + + + 0} + numActiveFilters={selectedAssignees.length} + > + {i18n.translate('xpack.securitySolution.filtersGroup.assignees.buttonTitle', { + defaultMessage: 'Assignees', + })} + + + } + isPopoverOpen={isPopoverOpen} + closePopover={togglePopover} + onSelectionChange={handleSelectionChange} + /> + + ); + } +); + +FilterByAssigneesPopover.displayName = 'FilterByAssigneesPopover'; diff --git a/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap index 00732ec7b82e..46c33d5102fe 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/header_section/__snapshots__/index.test.tsx.snap @@ -37,7 +37,7 @@ exports[`HeaderSection it renders 1`] = ` >

    = ({ stackHeader, subtitle, title, - titleSize = 'm', + titleSize = 'l', toggleQuery, toggleStatus = true, tooltip, @@ -173,7 +173,6 @@ const HeaderSectionComponent: React.FC = ({ {title} {tooltip && ( <> - {' '} void; queryId: string; showInspectButton?: boolean; - title: string | React.ReactElement | React.ReactNode; + title?: string | React.ReactElement | React.ReactNode; } const InspectButtonComponent: React.FC = ({ @@ -80,9 +80,6 @@ const InspectButtonComponent: React.FC = ({ className={BUTTON_CLASS} aria-label={i18n.INSPECT} data-test-subj="inspect-empty-button" - color="text" - iconSide="left" - iconType="inspect" isDisabled={isButtonDisabled} isLoading={loading} onClick={handleClick} diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx index 968899a1e84d..9d676016be25 100644 --- a/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx @@ -7,51 +7,22 @@ import React from 'react'; import { render } from '@testing-library/react'; import { LandingPageComponent } from '.'; -import { useKibana } from '../../lib/kibana'; -import { Router } from 'react-router-dom'; -import { createBrowserHistory } from 'history'; -import { TestProviders } from '../../mock/test_providers'; -jest.mock('../../lib/kibana', () => ({ - useKibana: jest.fn(), +const mockUseContractComponents = jest.fn(() => ({})); +jest.mock('../../hooks/use_contract_component', () => ({ + useContractComponents: () => mockUseContractComponents(), })); -jest.mock('react-use/lib/useObservable', () => jest.fn((component) => component)); - describe('LandingPageComponent', () => { - const mockGetComponent = jest.fn(); - const history = createBrowserHistory(); - const mockSecuritySolutionTemplateWrapper = jest - .fn() - .mockImplementation(({ children }) =>
    {children}
    ); - - const renderPage = () => - render( - - - , - { wrapper: TestProviders } - ); - - beforeAll(() => { - (useKibana as jest.Mock).mockReturnValue({ - services: { - securityLayout: { - getPluginWrapper: jest.fn().mockReturnValue(mockSecuritySolutionTemplateWrapper), - }, - getComponent$: mockGetComponent, - }, - }); - }); - beforeEach(() => { jest.clearAllMocks(); }); it('renders the get started component', () => { - mockGetComponent.mockReturnValue(
    ); - const { queryByTestId } = renderPage(); + const GetStarted = () =>
    ; + mockUseContractComponents.mockReturnValue({ GetStarted }); + const { queryByTestId } = render(); - expect(queryByTestId('get-started')).toBeInTheDocument(); + expect(queryByTestId('get-started-mock')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx index d8e1a9029e21..959827aec3ba 100644 --- a/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx @@ -6,13 +6,11 @@ */ import React, { memo } from 'react'; -import useObservable from 'react-use/lib/useObservable'; -import { useKibana } from '../../lib/kibana'; +import { useContractComponents } from '../../hooks/use_contract_component'; export const LandingPageComponent = memo(() => { - const { getComponent$ } = useKibana().services; - const GetStartedComponent = useObservable(getComponent$('getStarted')); - return <>{GetStartedComponent}; + const { GetStarted } = useContractComponents(); + return GetStarted ? : null; }); LandingPageComponent.displayName = 'LandingPageComponent'; diff --git a/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx index fe21d973c86b..08818172bca5 100644 --- a/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/query_bar/index.tsx @@ -167,7 +167,6 @@ export const QueryBar = memo( savedQuery={savedQuery} displayStyle={displayStyle} isDisabled={isDisabled} - hideTextBasedRunQueryLabel /> ); } diff --git a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.test.tsx index 7765c4dc0f79..afe1d0f20876 100644 --- a/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sessions_viewer/index.test.tsx @@ -11,21 +11,12 @@ import { TestProviders } from '../../mock'; import { TEST_ID, SessionsView, defaultSessionsFilter } from '.'; import type { EntityType } from '@kbn/timelines-plugin/common'; import type { SessionsComponentsProps } from './types'; -import { useGetUserCasesPermissions } from '../../lib/kibana'; import { TableId } from '@kbn/securitysolution-data-table'; import { licenseService } from '../../hooks/use_license'; import { mount } from 'enzyme'; import type { EventsViewerProps } from '../events_viewer'; jest.mock('../../lib/kibana'); - -const originalKibanaLib = jest.requireActual('../../lib/kibana'); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); - jest.mock('../../utils/normalize_time_range'); const startDate = '2022-03-22T22:10:56.794Z'; diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/alerts_sourcerer.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/alerts_sourcerer.test.tsx new file mode 100644 index 000000000000..da0bc5699882 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/alerts_sourcerer.test.tsx @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { Sourcerer } from '.'; +import { sourcererModel } from '../../store/sourcerer'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../mock'; +import { createStore } from '../../store'; +import { useSourcererDataView } from '../../containers/sourcerer'; +import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; + +const mockDispatch = jest.fn(); + +jest.mock('../../containers/sourcerer'); +jest.mock('../../containers/sourcerer/use_signal_helpers'); +const mockUseUpdateDataView = jest.fn().mockReturnValue(() => true); +jest.mock('./use_update_data_view', () => ({ + useUpdateDataView: () => mockUseUpdateDataView, +})); +jest.mock('react-redux', () => { + const original = jest.requireActual('react-redux'); + + return { + ...original, + useDispatch: () => mockDispatch, + }; +}); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + + return { + ...original, + toMountPoint: jest.fn(), + }; +}); + +const mockUpdateUrlParam = jest.fn(); +jest.mock('../../utils/global_query_string', () => { + const original = jest.requireActual('../../utils/global_query_string'); + + return { + ...original, + useUpdateUrlParam: () => mockUpdateUrlParam, + }; +}); + +let store: ReturnType; +const sourcererDataView = { + indicesExist: true, + loading: false, +}; +describe('sourcerer on alerts page or rules details page', () => { + const { storage } = createSecuritySolutionStorageMock(); + store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + const testProps = { + scope: sourcererModel.SourcererScopeName.detections, + }; + + const pollForSignalIndexMock = jest.fn(); + + beforeEach(async () => { + jest.clearAllMocks(); + + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + indicesExist: true, + }); + + render( + + + + ); + + fireEvent.click(screen.getByTestId('sourcerer-trigger')); + await waitFor(() => { + expect(screen.getByTestId('sourcerer-advanced-options-toggle')).toBeVisible(); + }); + fireEvent.click(screen.getByTestId('sourcerer-advanced-options-toggle')); + }); + + it('renders an alerts badge in sourcerer button', () => { + expect(screen.getByTestId('sourcerer-advanced-options-toggle')).toHaveTextContent( + /Advanced options/ + ); + }); + + it('renders a callout', () => { + expect(screen.getByTestId('sourcerer-callout')).toHaveTextContent( + 'Data view cannot be modified on this page' + ); + }); + + it('disable data view selector', () => { + expect(screen.getByTestId('sourcerer-select')).toBeDisabled(); + }); + + it('data view selector is default to Security Data View', () => { + expect(screen.getByTestId('sourcerer-select')).toHaveTextContent(/security data view/i); + }); + + it('renders an alert badge in data view selector', () => { + expect(screen.getByTestId('security-alerts-option-badge')).toHaveTextContent('Alerts'); + }); + + it('disable index pattern selector', () => { + expect(screen.getByTestId('sourcerer-combo-box')).toHaveAttribute('disabled'); + }); + + it('shows signal index as index pattern option', () => { + expect(screen.getByTestId('euiComboBoxPill')).toHaveTextContent('.siem-signals-spacename'); + }); + + it('does not render reset button', () => { + expect(screen.queryByTestId('sourcerer-reset')).toBeFalsy(); + }); + + it('does not render save button', () => { + expect(screen.queryByTestId('sourcerer-save')).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx index 87874da00ced..3556e3219657 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/helpers.tsx @@ -10,6 +10,7 @@ import type { EuiSuperSelectOption, EuiFormRowProps } from '@elastic/eui'; import { EuiIcon, EuiBadge, EuiButtonEmpty, EuiFormRow } from '@elastic/eui'; import styled, { css } from 'styled-components'; +import { euiThemeVars } from '@kbn/ui-theme'; import type { sourcererModel } from '../../store/sourcerer'; import * as i18n from './translations'; @@ -23,7 +24,7 @@ export const StyledFormRow = styled(EuiFormRow)` max-width: none; `; -export const StyledButton = styled(EuiButtonEmpty)` +export const StyledButtonEmpty = styled(EuiButtonEmpty)` &:enabled:focus, &:focus { background-color: transparent; @@ -43,7 +44,7 @@ export const PopoverContent = styled.div` `; export const StyledBadge = styled(EuiBadge)` - margin-left: 8px; + margin-left: ${euiThemeVars.euiSizeXS}; &, .euiBadge__text { cursor: pointer; diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx index ebda7e6748eb..f91ebef48d7a 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx @@ -8,9 +8,8 @@ import React from 'react'; import type { ReactWrapper } from 'enzyme'; import { mount } from 'enzyme'; -import { cloneDeep } from 'lodash'; -import { initialSourcererState, SourcererScopeName } from '../../store/sourcerer/model'; +import { SourcererScopeName } from '../../store/sourcerer/model'; import { Sourcerer } from '.'; import { sourcererActions, sourcererModel } from '../../store/sourcerer'; import { @@ -22,11 +21,9 @@ import { } from '../../mock'; import { createStore } from '../../store'; import type { EuiSuperSelectOption } from '@elastic/eui/src/components/form/super_select/super_select_control'; -import { waitFor } from '@testing-library/react'; +import { fireEvent, waitFor, render } from '@testing-library/react'; import { useSourcererDataView } from '../../containers/sourcerer'; import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers'; -import { TimelineId } from '../../../../common/types/timeline'; -import { TimelineType } from '../../../../common/api/timeline'; import { DEFAULT_INDEX_PATTERN } from '../../../../common/constants'; import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; @@ -93,6 +90,7 @@ const sourcererDataView = { describe('Sourcerer component', () => { const { storage } = createSecuritySolutionStorageMock(); const pollForSignalIndexMock = jest.fn(); + let wrapper: ReactWrapper; beforeEach(() => { jest.clearAllMocks(); store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); @@ -100,8 +98,12 @@ describe('Sourcerer component', () => { (useSignalHelpers as jest.Mock).mockReturnValue({ signalIndexNeedsInit: false }); }); + afterEach(() => { + if (wrapper && wrapper.exists()) wrapper.unmount(); + }); + it('renders data view title', () => { - const wrapper = mount( + wrapper = mount( @@ -117,7 +119,7 @@ describe('Sourcerer component', () => { ...defaultProps, showAlertsOnlyCheckbox: true, }; - const wrapper = mount( + wrapper = mount( @@ -129,7 +131,7 @@ describe('Sourcerer component', () => { }); it('renders tooltip', () => { - const wrapper = mount( + wrapper = mount( @@ -140,7 +142,7 @@ describe('Sourcerer component', () => { }); it('renders popover button inside tooltip', () => { - const wrapper = mount( + wrapper = mount( @@ -156,7 +158,7 @@ describe('Sourcerer component', () => { // Using props callback instead of simulating clicks, // because EuiSelectable uses a virtualized list, which isn't easily testable via test subjects it('Mounts with all options selected', () => { - const wrapper = mount( + wrapper = mount( @@ -206,7 +208,7 @@ describe('Sourcerer component', () => { kibanaObservable, storage ); - const wrapper = mount( + wrapper = mount( @@ -256,7 +258,7 @@ describe('Sourcerer component', () => { kibanaObservable, storage ); - const wrapper = mount( + wrapper = mount( @@ -305,7 +307,7 @@ describe('Sourcerer component', () => { }; store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const wrapper = mount( + wrapper = mount( @@ -318,7 +320,7 @@ describe('Sourcerer component', () => { optionsSelected: true, }); }); - it('Mounts with multiple options selected - timeline', () => { + it('Mounts with multiple options selected - timeline', async () => { const state2 = { ...mockGlobalState, sourcerer: { @@ -350,17 +352,22 @@ describe('Sourcerer component', () => { }; store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const wrapper = mount( + const { getByTestId, queryByTitle, queryAllByTestId } = render( ); - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - wrapper.find(`[data-test-subj="comboBoxInput"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, patternList.slice(0, 2))).toEqual({ - // should show every option except fakebeat-* - availableOptionCount: title.split(',').length - 2, - optionsSelected: true, + + fireEvent.click(getByTestId('timeline-sourcerer-trigger')); + await waitFor(() => { + for (const pattern of patternList.slice(0, 2)) { + expect(queryByTitle(pattern)).toBeInTheDocument(); + } + }); + + fireEvent.click(getByTestId('comboBoxInput')); + await waitFor(() => { + expect(queryAllByTestId('sourcerer-combo-option')).toHaveLength(title.split(',').length - 2); }); }); it('onSave dispatches setSelectedDataView', async () => { @@ -392,7 +399,7 @@ describe('Sourcerer component', () => { kibanaObservable, storage ); - const wrapper = mount( + wrapper = mount( @@ -450,7 +457,7 @@ describe('Sourcerer component', () => { storage ); - const wrapper = mount( + wrapper = mount( @@ -464,7 +471,7 @@ describe('Sourcerer component', () => { }); it('resets to default index pattern', async () => { - const wrapper = mount( + wrapper = mount( @@ -517,7 +524,7 @@ describe('Sourcerer component', () => { kibanaObservable, storage ); - const wrapper = mount( + wrapper = mount( @@ -526,7 +533,14 @@ describe('Sourcerer component', () => { wrapper.find('[data-test-subj="comboBoxClearButton"]').first().simulate('click'); expect(wrapper.find('[data-test-subj="sourcerer-save"]').first().prop('disabled')).toBeTruthy(); }); - it('Does display signals index on timeline sourcerer', () => { + it('Does display signals index on timeline sourcerer', async () => { + /* + * Since both enzyme and RTL share JSDOM when running these tests, + * and enzyme does not clears jsdom after each test, because of this + * `screen` of RTL does not work as expect, please avoid using screen + * till all the tests have been converted to RTL + * + * */ const state2 = { ...mockGlobalState, sourcerer: { @@ -559,16 +573,20 @@ describe('Sourcerer component', () => { }; store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const wrapper = mount( + const el = render( ); - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - wrapper.find(`[data-test-subj="comboBoxToggleListButton"]`).first().simulate('click'); - expect(wrapper.find(`[data-test-subj="sourcerer-combo-option"]`).at(0).text()).toEqual( - mockGlobalState.sourcerer.signalIndexName - ); + + fireEvent.click(el.getByTestId('timeline-sourcerer-trigger')); + fireEvent.click(el.getByTestId('comboBoxToggleListButton')); + + await waitFor(() => { + expect(el.queryAllByTestId('sourcerer-combo-option')[0].textContent).toBe( + mockGlobalState.sourcerer.signalIndexName + ); + }); }); it('Does not display signals index on default sourcerer', () => { const state2 = { @@ -603,7 +621,7 @@ describe('Sourcerer component', () => { }; store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const wrapper = mount( + wrapper = mount( @@ -677,617 +695,3 @@ describe('Sourcerer component', () => { expect(pollForSignalIndexMock).toHaveBeenCalledTimes(1); }); }); - -describe('sourcerer on alerts page or rules details page', () => { - let wrapper: ReactWrapper; - const { storage } = createSecuritySolutionStorageMock(); - store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const testProps = { - scope: sourcererModel.SourcererScopeName.detections, - }; - - beforeAll(() => { - wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); - wrapper.find(`[data-test-subj="sourcerer-advanced-options-toggle"]`).first().simulate('click'); - }); - - it('renders an alerts badge in sourcerer button', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-alerts-badge"]`).first().text()).toEqual( - 'Alerts' - ); - }); - - it('renders a callout', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-callout"]`).first().text()).toEqual( - 'Data view cannot be modified on this page' - ); - }); - - it('disable data view selector', () => { - expect( - wrapper.find(`[data-test-subj="sourcerer-select"]`).first().prop('disabled') - ).toBeTruthy(); - }); - - it('data view selector is default to Security Data View', () => { - expect( - wrapper.find(`[data-test-subj="sourcerer-select"]`).first().prop('valueOfSelected') - ).toEqual('security-solution'); - }); - - it('renders an alert badge in data view selector', () => { - expect(wrapper.find(`[data-test-subj="security-alerts-option-badge"]`).first().text()).toEqual( - 'Alerts' - ); - }); - - it('disable index pattern selector', () => { - expect( - wrapper.find(`[data-test-subj="sourcerer-combo-box"]`).first().prop('disabled') - ).toBeTruthy(); - }); - - it('shows signal index as index pattern option', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-combo-box"]`).first().prop('options')).toEqual([ - { disabled: false, label: '.siem-signals-spacename', value: '.siem-signals-spacename' }, - ]); - }); - - it('does not render reset button', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-reset"]`).exists()).toBeFalsy(); - }); - - it('does not render save button', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-save"]`).exists()).toBeFalsy(); - }); -}); - -describe('timeline sourcerer', () => { - let wrapper: ReactWrapper; - const { storage } = createSecuritySolutionStorageMock(); - store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - const testProps = { - scope: sourcererModel.SourcererScopeName.timeline, - }; - - beforeAll(() => { - (useSourcererDataView as jest.Mock).mockReturnValue(sourcererDataView); - wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - wrapper - .find( - `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-advanced-options-toggle"]` - ) - .first() - .simulate('click'); - }); - - it('renders "alerts only" checkbox, unchecked', () => { - wrapper - .find( - `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-alert-only-checkbox"]` - ) - .first() - .simulate('click'); - expect(wrapper.find(`[data-test-subj="sourcerer-alert-only-checkbox"]`).first().text()).toEqual( - 'Show only detection alerts' - ); - expect( - wrapper.find(`[data-test-subj="sourcerer-alert-only-checkbox"] input`).first().prop('checked') - ).toEqual(false); - }); - - it('data view selector is enabled', () => { - expect( - wrapper - .find(`[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-select"]`) - .first() - .prop('disabled') - ).toBeFalsy(); - }); - - it('data view selector is default to Security Default Data View', () => { - expect( - wrapper - .find(`[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-select"]`) - .first() - .prop('valueOfSelected') - ).toEqual('security-solution'); - }); - - it('index pattern selector is enabled', () => { - expect( - wrapper - .find( - `[data-test-subj="timeline-sourcerer-popover"] [data-test-subj="sourcerer-combo-box"]` - ) - .first() - .prop('disabled') - ).toBeFalsy(); - }); - - it('render reset button', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-reset"]`).exists()).toBeTruthy(); - }); - - it('render save button', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-save"]`).exists()).toBeTruthy(); - }); - - it('Checks box when only alerts index is selected in timeline', () => { - const state2 = { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - selectedDataViewId: id, - selectedPatterns: [`${mockGlobalState.sourcerer.signalIndexName}`], - }, - }, - }, - }; - - store = createStore( - state2, - SUB_PLUGINS_REDUCER, - - kibanaObservable, - storage - ); - - wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - expect( - wrapper.find(`[data-test-subj="sourcerer-alert-only-checkbox"] input`).first().prop('checked') - ).toEqual(true); - }); -}); - -describe('Sourcerer integration tests', () => { - const state = { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - kibanaDataViews: [ - mockGlobalState.sourcerer.defaultDataView, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'fakebeat-*,neatbeat-*', - patternList: ['fakebeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.default]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], - loading: false, - selectedDataViewId: id, - selectedPatterns: patternListNoSignals.slice(0, 2), - }, - }, - }, - }; - - const { storage } = createSecuritySolutionStorageMock(); - - beforeEach(() => { - (useSourcererDataView as jest.Mock).mockReturnValue(sourcererDataView); - store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - jest.clearAllMocks(); - }); - - it('Selects a different index pattern', async () => { - const wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); - wrapper.find(`button[data-test-subj="sourcerer-select"]`).first().simulate('click'); - - wrapper.find(`[data-test-subj="dataView-option-super"]`).first().simulate('click'); - expect(checkOptionsAndSelections(wrapper, ['fakebeat-*'])).toEqual({ - availableOptionCount: 0, - optionsSelected: true, - }); - wrapper.find(`button[data-test-subj="sourcerer-save"]`).first().simulate('click'); - - expect(mockDispatch).toHaveBeenCalledWith( - sourcererActions.setSelectedDataView({ - id: SourcererScopeName.default, - selectedDataViewId: '1234', - selectedPatterns: ['fakebeat-*'], - }) - ); - }); -}); - -describe('No data', () => { - const mockNoIndicesState = { - ...mockGlobalState, - sourcerer: { - ...initialSourcererState, - }, - }; - - const { storage } = createSecuritySolutionStorageMock(); - - beforeEach(() => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - ...sourcererDataView, - indicesExist: false, - }); - store = createStore(mockNoIndicesState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - jest.clearAllMocks(); - }); - - test('Hide sourcerer - default ', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="sourcerer-trigger"]`).exists()).toEqual(false); - }); - test('Hide sourcerer - detections ', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="sourcerer-trigger"]`).exists()).toEqual(false); - }); - test('Hide sourcerer - timeline ', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).exists()).toEqual(true); - }); -}); - -describe('Update available', () => { - const { storage } = createSecuritySolutionStorageMock(); - const state2 = { - ...mockGlobalState, - sourcerer: { - ...mockGlobalState.sourcerer, - kibanaDataViews: [ - mockGlobalState.sourcerer.defaultDataView, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'auditbeat-*', - patternList: ['auditbeat-*'], - }, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '12347', - title: 'packetbeat-*', - patternList: ['packetbeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - patternList, - selectedDataViewId: null, - selectedPatterns: ['myFakebeat-*'], - missingPatterns: ['myFakebeat-*'], - }, - }, - }, - }; - - let wrapper: ReactWrapper; - - beforeEach(() => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - ...sourcererDataView, - activePatterns: ['myFakebeat-*'], - }); - store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - wrapper = mount( - - - - ); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - - test('Show Update available label', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-badge"]`).exists()).toBeTruthy(); - }); - - test('Show correct tooltip', () => { - expect(wrapper.find(`[data-test-subj="sourcerer-tooltip"]`).prop('content')).toEqual( - 'myFakebeat-*' - ); - }); - - test('Show UpdateDefaultDataViewModal', () => { - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`UpdateDefaultDataViewModal`).prop('isShowing')).toEqual(true); - }); - - test('Show UpdateDefaultDataViewModal Callout', () => { - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-callout"]`).first().text()).toEqual( - 'This timeline uses a legacy data view selector' - ); - - expect( - wrapper.find(`[data-test-subj="sourcerer-current-patterns-message"]`).first().text() - ).toEqual('The active index patterns in this timeline are: myFakebeat-*'); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-message"]`).first().text()).toEqual( - "We have preserved your timeline by creating a temporary data view. If you'd like to modify your data, we can recreate your temporary data view with the new data view selector. You can also manually select a data view here." - ); - }); - - test('Show Add index pattern in UpdateDefaultDataViewModal', () => { - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`button[data-test-subj="sourcerer-update-data-view"]`).text()).toEqual( - 'Add index pattern' - ); - }); - - test('Set all the index patterns from legacy timeline to sourcerer, after clicking on "Add index pattern"', async () => { - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-update-data-view"]`).simulate('click'); - - await waitFor(() => wrapper.update()); - expect(mockDispatch).toHaveBeenCalledWith( - sourcererActions.setSelectedDataView({ - id: SourcererScopeName.timeline, - selectedDataViewId: 'security-solution', - selectedPatterns: ['myFakebeat-*'], - shouldValidateSelectedPatterns: false, - }) - ); - }); -}); - -describe('Update available for timeline template', () => { - const { storage } = createSecuritySolutionStorageMock(); - const state2 = { - ...mockGlobalState, - timeline: { - ...mockGlobalState.timeline, - timelineById: { - ...mockGlobalState.timeline.timelineById, - [TimelineId.active]: { - ...mockGlobalState.timeline.timelineById.test, - timelineType: TimelineType.template, - }, - }, - }, - sourcerer: { - ...mockGlobalState.sourcerer, - kibanaDataViews: [ - mockGlobalState.sourcerer.defaultDataView, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'auditbeat-*', - patternList: ['auditbeat-*'], - }, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '12347', - title: 'packetbeat-*', - patternList: ['packetbeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - patternList, - selectedDataViewId: null, - selectedPatterns: ['myFakebeat-*'], - missingPatterns: ['myFakebeat-*'], - }, - }, - }, - }; - - let wrapper: ReactWrapper; - - beforeEach(() => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - ...sourcererDataView, - activePatterns: ['myFakebeat-*'], - }); - store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - wrapper = mount( - - - - ); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - - test('Show UpdateDefaultDataViewModal CallOut', () => { - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-callout"]`).first().text()).toEqual( - 'This timeline template uses a legacy data view selector' - ); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-message"]`).first().text()).toEqual( - "We have preserved your timeline template by creating a temporary data view. If you'd like to modify your data, we can recreate your temporary data view with the new data view selector. You can also manually select a data view here." - ); - }); -}); - -describe('Missing index patterns', () => { - const { storage } = createSecuritySolutionStorageMock(); - const state2 = { - ...mockGlobalState, - timeline: { - ...mockGlobalState.timeline, - timelineById: { - ...mockGlobalState.timeline.timelineById, - [TimelineId.active]: { - ...mockGlobalState.timeline.timelineById.test, - timelineType: TimelineType.template, - }, - }, - }, - sourcerer: { - ...mockGlobalState.sourcerer, - kibanaDataViews: [ - mockGlobalState.sourcerer.defaultDataView, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '1234', - title: 'auditbeat-*', - patternList: ['auditbeat-*'], - }, - { - ...mockGlobalState.sourcerer.defaultDataView, - id: '12347', - title: 'packetbeat-*', - patternList: ['packetbeat-*'], - }, - ], - sourcererScopes: { - ...mockGlobalState.sourcerer.sourcererScopes, - [SourcererScopeName.timeline]: { - ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], - loading: false, - patternList, - selectedDataViewId: 'fake-data-view-id', - selectedPatterns: ['myFakebeat-*'], - missingPatterns: ['myFakebeat-*'], - }, - }, - }, - }; - - let wrapper: ReactWrapper; - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('Show UpdateDefaultDataViewModal CallOut for timeline', () => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - ...sourcererDataView, - activePatterns: ['myFakebeat-*'], - }); - const state3 = cloneDeep(state2); - state3.timeline.timelineById[TimelineId.active].timelineType = TimelineType.default; - store = createStore(state3, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - wrapper = mount( - - - - ); - - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-callout"]`).first().text()).toEqual( - 'This timeline is out of date with the Security Data View' - ); - - expect( - wrapper.find(`[data-test-subj="sourcerer-current-patterns-message"]`).first().text() - ).toEqual('The active index patterns in this timeline are: myFakebeat-*'); - - expect( - wrapper.find(`[data-test-subj="sourcerer-missing-patterns-callout"]`).first().text() - ).toEqual('Security Data View is missing the following index patterns: myFakebeat-*'); - - expect( - wrapper.find(`[data-test-subj="sourcerer-missing-patterns-message"]`).first().text() - ).toEqual( - "We have preserved your timeline by creating a temporary data view. If you'd like to modify your data, we can add the missing index patterns to the Security Data View. You can also manually select a data view here." - ); - }); - - test('Show UpdateDefaultDataViewModal CallOut for timeline template', () => { - (useSourcererDataView as jest.Mock).mockReturnValue({ - ...sourcererDataView, - activePatterns: ['myFakebeat-*'], - }); - store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - wrapper = mount( - - - - ); - - wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).first().simulate('click'); - - wrapper.find(`button[data-test-subj="sourcerer-deprecated-update"]`).first().simulate('click'); - - expect(wrapper.find(`[data-test-subj="sourcerer-deprecated-callout"]`).first().text()).toEqual( - 'This timeline template is out of date with the Security Data View' - ); - - expect( - wrapper.find(`[data-test-subj="sourcerer-current-patterns-message"]`).first().text() - ).toEqual('The active index patterns in this timeline template are: myFakebeat-*'); - - expect( - wrapper.find(`[data-test-subj="sourcerer-missing-patterns-callout"]`).first().text() - ).toEqual('Security Data View is missing the following index patterns: myFakebeat-*'); - - expect( - wrapper.find(`[data-test-subj="sourcerer-missing-patterns-message"]`).first().text() - ).toEqual( - "We have preserved your timeline template by creating a temporary data view. If you'd like to modify your data, we can add the missing index patterns to the Security Data View. You can also manually select a data view here." - ); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx index a0bb1f3f27ff..5a2f3050c159 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.tsx @@ -25,7 +25,7 @@ import { useDeepEqualSelector } from '../../hooks/use_selector'; import type { SourcererUrlState } from '../../store/sourcerer/model'; import { SourcererScopeName } from '../../store/sourcerer/model'; import { usePickIndexPatterns } from './use_pick_index_patterns'; -import { FormRow, PopoverContent, StyledButton, StyledFormRow } from './helpers'; +import { FormRow, PopoverContent, StyledButtonEmpty, StyledFormRow } from './helpers'; import { TemporarySourcerer } from './temporary'; import { useSourcererDataView } from '../../containers/sourcerer'; import { useUpdateDataView } from './use_update_data_view'; @@ -338,14 +338,14 @@ export const Sourcerer = React.memo(({ scope: scopeId } )} - {i18n.INDEX_PATTERNS_ADVANCED_OPTIONS_TITLE} - + {expandAdvancedOptions && } true); +jest.mock('./use_update_data_view', () => ({ + useUpdateDataView: () => mockUseUpdateDataView, +})); +jest.mock('react-redux', () => { + const original = jest.requireActual('react-redux'); + + return { + ...original, + useDispatch: () => mockDispatch, + }; +}); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + + return { + ...original, + toMountPoint: jest.fn(), + }; +}); + +const mockUpdateUrlParam = jest.fn(); +jest.mock('../../utils/global_query_string', () => { + const original = jest.requireActual('../../utils/global_query_string'); + + return { + ...original, + useUpdateUrlParam: () => mockUpdateUrlParam, + }; +}); + +const defaultProps = { + scope: sourcererModel.SourcererScopeName.default, +}; + +const checkOptionsAndSelections = (wrapper: ReactWrapper, patterns: string[]) => ({ + availableOptionCount: + wrapper.find('List').length > 0 ? wrapper.find('List').prop('itemCount') : 0, + optionsSelected: patterns.every((pattern) => + wrapper.find(`[data-test-subj="sourcerer-combo-box"] span[title="${pattern}"]`).first().exists() + ), +}); + +const { id, patternList } = mockGlobalState.sourcerer.defaultDataView; + +const patternListNoSignals = sortWithExcludesAtEnd( + patternList.filter((p) => p !== mockGlobalState.sourcerer.signalIndexName) +); +let store: ReturnType; +const sourcererDataView = { + indicesExist: true, + loading: false, +}; + +describe('No data', () => { + const mockNoIndicesState = { + ...mockGlobalState, + sourcerer: { + ...initialSourcererState, + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + const pollForSignalIndexMock = jest.fn(); + + beforeEach(() => { + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + indicesExist: false, + }); + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + store = createStore(mockNoIndicesState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + jest.clearAllMocks(); + }); + + test('Hide sourcerer - default ', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="sourcerer-trigger"]`).exists()).toEqual(false); + }); + test('Hide sourcerer - detections ', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="sourcerer-trigger"]`).exists()).toEqual(false); + }); + test('Hide sourcerer - timeline ', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="timeline-sourcerer-trigger"]`).exists()).toEqual(true); + }); +}); + +describe('Update available', () => { + const { storage } = createSecuritySolutionStorageMock(); + const state2 = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'auditbeat-*', + patternList: ['auditbeat-*'], + }, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '12347', + title: 'packetbeat-*', + patternList: ['packetbeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.timeline]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], + loading: false, + patternList, + selectedDataViewId: null, + selectedPatterns: ['myFakebeat-*'], + missingPatterns: ['myFakebeat-*'], + }, + }, + }, + }; + + const pollForSignalIndexMock = jest.fn(); + beforeEach(() => { + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + render( + + + + ); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + + test('Show Update available label', () => { + expect(screen.getByTestId('sourcerer-deprecated-badge')).toBeInTheDocument(); + }); + + test('Show correct tooltip', async () => { + fireEvent.mouseOver(screen.getByTestId('timeline-sourcerer-trigger')); + await waitFor(() => { + expect(screen.getByTestId('sourcerer-tooltip').textContent).toBe('myFakebeat-*'); + }); + }); + + test('Show UpdateDefaultDataViewModal', () => { + fireEvent.click(screen.queryAllByTestId('timeline-sourcerer-trigger')[0]); + + fireEvent.click(screen.queryAllByTestId('sourcerer-deprecated-update')[0]); + + expect(screen.getByTestId('sourcerer-update-data-view-modal')).toBeVisible(); + }); + + test('Show UpdateDefaultDataViewModal Callout', () => { + fireEvent.click(screen.queryAllByTestId('timeline-sourcerer-trigger')[0]); + + fireEvent.click(screen.queryAllByTestId('sourcerer-deprecated-update')[0]); + + expect(screen.queryAllByTestId('sourcerer-deprecated-callout')[0].textContent).toBe( + 'This timeline uses a legacy data view selector' + ); + + expect(screen.queryAllByTestId('sourcerer-current-patterns-message')[0].textContent).toBe( + 'The active index patterns in this timeline are: myFakebeat-*' + ); + + expect(screen.queryAllByTestId('sourcerer-deprecated-message')[0].textContent).toBe( + "We have preserved your timeline by creating a temporary data view. If you'd like to modify your data, we can recreate your temporary data view with the new data view selector. You can also manually select a data view here." + ); + }); + + test('Show Add index pattern in UpdateDefaultDataViewModal', () => { + fireEvent.click(screen.queryAllByTestId('timeline-sourcerer-trigger')[0]); + + fireEvent.click(screen.queryAllByTestId('sourcerer-deprecated-update')[0]); + + expect(screen.queryAllByTestId('sourcerer-update-data-view')[0].textContent).toBe( + 'Add index pattern' + ); + }); + + test('Set all the index patterns from legacy timeline to sourcerer, after clicking on "Add index pattern"', async () => { + fireEvent.click(screen.queryAllByTestId('timeline-sourcerer-trigger')[0]); + + fireEvent.click(screen.queryAllByTestId('sourcerer-deprecated-update')[0]); + + fireEvent.click(screen.queryAllByTestId('sourcerer-update-data-view')[0]); + + await waitFor(() => { + expect(mockDispatch).toHaveBeenCalledWith( + sourcererActions.setSelectedDataView({ + id: SourcererScopeName.timeline, + selectedDataViewId: 'security-solution', + selectedPatterns: ['myFakebeat-*'], + shouldValidateSelectedPatterns: false, + }) + ); + }); + }); +}); + +describe('Update available for timeline template', () => { + const { storage } = createSecuritySolutionStorageMock(); + const state2 = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + ...mockGlobalState.timeline.timelineById, + [TimelineId.active]: { + ...mockGlobalState.timeline.timelineById.test, + timelineType: TimelineType.template, + }, + }, + }, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'auditbeat-*', + patternList: ['auditbeat-*'], + }, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '12347', + title: 'packetbeat-*', + patternList: ['packetbeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.timeline]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], + loading: false, + patternList, + selectedDataViewId: null, + selectedPatterns: ['myFakebeat-*'], + missingPatterns: ['myFakebeat-*'], + }, + }, + }, + }; + + beforeEach(() => { + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + render( + + + + ); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + + test('Show UpdateDefaultDataViewModal CallOut', () => { + fireEvent.click(screen.getByTestId('timeline-sourcerer-trigger')); + fireEvent.click(screen.getByTestId('sourcerer-deprecated-update')); + + expect(screen.getByTestId('sourcerer-deprecated-callout')).toHaveTextContent( + 'This timeline template uses a legacy data view selector' + ); + + expect(screen.getByTestId('sourcerer-deprecated-message')).toHaveTextContent( + "We have preserved your timeline template by creating a temporary data view. If you'd like to modify your data, we can recreate your temporary data view with the new data view selector. You can also manually select a data view here." + ); + }); +}); + +describe('Missing index patterns', () => { + const { storage } = createSecuritySolutionStorageMock(); + const state2 = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + ...mockGlobalState.timeline.timelineById, + [TimelineId.active]: { + ...mockGlobalState.timeline.timelineById.test, + timelineType: TimelineType.template, + }, + }, + }, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'auditbeat-*', + patternList: ['auditbeat-*'], + }, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '12347', + title: 'packetbeat-*', + patternList: ['packetbeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.timeline]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], + loading: false, + patternList, + selectedDataViewId: 'fake-data-view-id', + selectedPatterns: ['myFakebeat-*'], + missingPatterns: ['myFakebeat-*'], + }, + }, + }, + }; + + beforeEach(() => { + const pollForSignalIndexMock = jest.fn(); + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('Show UpdateDefaultDataViewModal CallOut for timeline', async () => { + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + const state3 = cloneDeep(state2); + state3.timeline.timelineById[TimelineId.active].timelineType = TimelineType.default; + store = createStore(state3, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + render( + + + + ); + + fireEvent.click(screen.getByTestId('timeline-sourcerer-trigger')); + + fireEvent.click(screen.getByTestId('sourcerer-deprecated-update')); + + expect(screen.getByTestId('sourcerer-deprecated-callout').textContent).toBe( + 'This timeline is out of date with the Security Data View' + ); + expect(screen.getByTestId('sourcerer-current-patterns-message').textContent).toBe( + 'The active index patterns in this timeline are: myFakebeat-*' + ); + expect(screen.queryAllByTestId('sourcerer-missing-patterns-callout')[0].textContent).toBe( + 'Security Data View is missing the following index patterns: myFakebeat-*' + ); + expect(screen.queryAllByTestId('sourcerer-missing-patterns-message')[0].textContent).toBe( + "We have preserved your timeline by creating a temporary data view. If you'd like to modify your data, we can add the missing index patterns to the Security Data View. You can also manually select a data view here." + ); + }); + + test('Show UpdateDefaultDataViewModal CallOut for timeline template', async () => { + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + store = createStore(state2, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + + render( + + + + ); + + fireEvent.click(screen.getByTestId('timeline-sourcerer-trigger')); + + fireEvent.click(screen.getByTestId('sourcerer-deprecated-update')); + + await waitFor(() => { + expect(screen.queryAllByTestId('sourcerer-deprecated-callout')[0].textContent).toBe( + 'This timeline template is out of date with the Security Data View' + ); + + expect(screen.queryAllByTestId('sourcerer-current-patterns-message')[0].textContent).toBe( + 'The active index patterns in this timeline template are: myFakebeat-*' + ); + + expect(screen.queryAllByTestId('sourcerer-missing-patterns-callout')[0].textContent).toBe( + 'Security Data View is missing the following index patterns: myFakebeat-*' + ); + + expect(screen.queryAllByTestId('sourcerer-missing-patterns-message')[0].textContent).toBe( + "We have preserved your timeline template by creating a temporary data view. If you'd like to modify your data, we can add the missing index patterns to the Security Data View. You can also manually select a data view here." + ); + }); + }); +}); + +describe('Sourcerer integration tests', () => { + const state = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'fakebeat-*,neatbeat-*', + patternList: ['fakebeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.default]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], + loading: false, + selectedDataViewId: id, + selectedPatterns: patternListNoSignals.slice(0, 2), + }, + }, + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + + beforeEach(() => { + const pollForSignalIndexMock = jest.fn(); + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + jest.clearAllMocks(); + }); + + it('Selects a different index pattern', async () => { + const wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`button[data-test-subj="sourcerer-select"]`).first().simulate('click'); + + wrapper.find(`[data-test-subj="dataView-option-super"]`).first().simulate('click'); + expect(checkOptionsAndSelections(wrapper, ['fakebeat-*'])).toEqual({ + availableOptionCount: 0, + optionsSelected: true, + }); + wrapper.find(`button[data-test-subj="sourcerer-save"]`).first().simulate('click'); + + expect(mockDispatch).toHaveBeenCalledWith( + sourcererActions.setSelectedDataView({ + id: SourcererScopeName.default, + selectedDataViewId: '1234', + selectedPatterns: ['fakebeat-*'], + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/sourcerer_integration.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/sourcerer_integration.test.tsx new file mode 100644 index 000000000000..33eba9dac6b9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/sourcerer_integration.test.tsx @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { ReactWrapper } from 'enzyme'; +import { mount } from 'enzyme'; + +import { SourcererScopeName } from '../../store/sourcerer/model'; +import { Sourcerer } from '.'; +import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers'; +import { sourcererActions, sourcererModel } from '../../store/sourcerer'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../mock'; +import { createStore } from '../../store'; +import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; +import { useSourcererDataView } from '../../containers/sourcerer'; + +const mockDispatch = jest.fn(); + +jest.mock('../../containers/sourcerer'); +jest.mock('../../containers/sourcerer/use_signal_helpers'); +const mockUseUpdateDataView = jest.fn().mockReturnValue(() => true); +jest.mock('./use_update_data_view', () => ({ + useUpdateDataView: () => mockUseUpdateDataView, +})); +jest.mock('react-redux', () => { + const original = jest.requireActual('react-redux'); + + return { + ...original, + useDispatch: () => mockDispatch, + }; +}); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + + return { + ...original, + toMountPoint: jest.fn(), + }; +}); + +const mockUpdateUrlParam = jest.fn(); +jest.mock('../../utils/global_query_string', () => { + const original = jest.requireActual('../../utils/global_query_string'); + + return { + ...original, + useUpdateUrlParam: () => mockUpdateUrlParam, + }; +}); + +const defaultProps = { + scope: sourcererModel.SourcererScopeName.default, +}; + +const checkOptionsAndSelections = (wrapper: ReactWrapper, patterns: string[]) => ({ + availableOptionCount: + wrapper.find('List').length > 0 ? wrapper.find('List').prop('itemCount') : 0, + optionsSelected: patterns.every((pattern) => + wrapper.find(`[data-test-subj="sourcerer-combo-box"] span[title="${pattern}"]`).first().exists() + ), +}); + +const { id, patternList } = mockGlobalState.sourcerer.defaultDataView; +const patternListNoSignals = sortWithExcludesAtEnd( + patternList.filter((p) => p !== mockGlobalState.sourcerer.signalIndexName) +); +let store: ReturnType; +const sourcererDataView = { + indicesExist: true, + loading: false, +}; + +describe('Sourcerer integration tests', () => { + const state = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + kibanaDataViews: [ + mockGlobalState.sourcerer.defaultDataView, + { + ...mockGlobalState.sourcerer.defaultDataView, + id: '1234', + title: 'fakebeat-*,neatbeat-*', + patternList: ['fakebeat-*'], + }, + ], + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.default]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.default], + loading: false, + selectedDataViewId: id, + selectedPatterns: patternListNoSignals.slice(0, 2), + }, + }, + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + + beforeEach(() => { + const pollForSignalIndexMock = jest.fn(); + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + + (useSourcererDataView as jest.Mock).mockReturnValue({ + ...sourcererDataView, + activePatterns: ['myFakebeat-*'], + }); + store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + jest.clearAllMocks(); + }); + + it('Selects a different index pattern', async () => { + const wrapper = mount( + + + + ); + wrapper.find(`[data-test-subj="sourcerer-trigger"]`).first().simulate('click'); + wrapper.find(`button[data-test-subj="sourcerer-select"]`).first().simulate('click'); + + wrapper.find(`[data-test-subj="dataView-option-super"]`).first().simulate('click'); + expect(checkOptionsAndSelections(wrapper, ['fakebeat-*'])).toEqual({ + availableOptionCount: 0, + optionsSelected: true, + }); + wrapper.find(`button[data-test-subj="sourcerer-save"]`).first().simulate('click'); + + expect(mockDispatch).toHaveBeenCalledWith( + sourcererActions.setSelectedDataView({ + id: SourcererScopeName.default, + selectedDataViewId: '1234', + selectedPatterns: ['fakebeat-*'], + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx index 7653a0830b70..1c2c73abcc04 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx @@ -107,6 +107,7 @@ export const TemporarySourcererComp = React.memo( const timelineType = useDeepEqualSelector( (state) => (getTimeline(state, TimelineId.active) ?? timelineDefaults).timelineType ); + return ( <> ( )} {isModified === 'missingPatterns' && ( <> - {missingPatterns.join(', ')}, - }} - /> + + {missingPatterns.join(', ')}, + }} + /> + )} diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/timeline_sourcerer.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/timeline_sourcerer.test.tsx new file mode 100644 index 000000000000..6f57f5fc2d34 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/timeline_sourcerer.test.tsx @@ -0,0 +1,188 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { render, cleanup, fireEvent, screen, waitFor } from '@testing-library/react'; +import { SourcererScopeName } from '../../store/sourcerer/model'; +import { Sourcerer } from '.'; +import { sourcererModel } from '../../store/sourcerer'; +import { + createSecuritySolutionStorageMock, + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../mock'; +import { createStore } from '../../store'; +import { useSourcererDataView } from '../../containers/sourcerer'; +import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers'; + +const mockDispatch = jest.fn(); + +jest.mock('../../containers/sourcerer'); +jest.mock('../../containers/sourcerer/use_signal_helpers'); +const mockUseUpdateDataView = jest.fn().mockReturnValue(() => true); +jest.mock('./use_update_data_view', () => ({ + useUpdateDataView: () => mockUseUpdateDataView, +})); +jest.mock('react-redux', () => { + const original = jest.requireActual('react-redux'); + + return { + ...original, + useDispatch: () => mockDispatch, + }; +}); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + + return { + ...original, + toMountPoint: jest.fn(), + }; +}); + +const mockUpdateUrlParam = jest.fn(); +jest.mock('../../utils/global_query_string', () => { + const original = jest.requireActual('../../utils/global_query_string'); + + return { + ...original, + useUpdateUrlParam: () => mockUpdateUrlParam, + }; +}); + +const { id } = mockGlobalState.sourcerer.defaultDataView; + +let store: ReturnType; +const sourcererDataView = { + indicesExist: true, + loading: false, +}; + +describe('timeline sourcerer', () => { + const { storage } = createSecuritySolutionStorageMock(); + store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + const testProps = { + scope: sourcererModel.SourcererScopeName.timeline, + }; + + beforeEach(async () => { + const pollForSignalIndexMock = jest.fn(); + + (useSourcererDataView as jest.Mock).mockReturnValue(sourcererDataView); + + (useSignalHelpers as jest.Mock).mockReturnValue({ + pollForSignalIndex: pollForSignalIndexMock, + signalIndexNeedsInit: false, + }); + + render( + + + + ); + + fireEvent.click(screen.getByTestId('timeline-sourcerer-trigger')); + + await waitFor(() => { + fireEvent.click(screen.getByTestId(`sourcerer-advanced-options-toggle`)); + }); + }); + + afterEach(() => { + cleanup(); + }); + + it('renders "alerts only" checkbox, unchecked', async () => { + await waitFor(() => { + expect(screen.getByTestId('sourcerer-alert-only-checkbox').parentElement).toHaveTextContent( + 'Show only detection alerts' + ); + expect(screen.getByTestId('sourcerer-alert-only-checkbox')).not.toBeChecked(); + }); + + fireEvent.click(screen.getByTestId('sourcerer-alert-only-checkbox')); + + await waitFor(() => { + expect(screen.getByTestId('sourcerer-alert-only-checkbox')).toBeChecked(); + }); + }); + + it('data view selector is enabled', async () => { + await waitFor(() => { + expect(screen.getByTestId('sourcerer-select')).toBeEnabled(); + }); + }); + + it('data view selector is default to Security Default Data View', async () => { + await waitFor(() => { + expect(screen.getByTestId('security-option-super')).toHaveTextContent( + 'Security Default Data View' + ); + }); + }); + + it('index pattern selector is enabled', async () => { + await waitFor(() => { + expect(screen.getByTestId('sourcerer-combo-box')).toBeEnabled(); + }); + }); + + it('render reset button', async () => { + await waitFor(() => { + expect(screen.getByTestId('sourcerer-reset')).toBeVisible(); + }); + }); + + it('render save button', async () => { + await waitFor(() => { + expect(screen.getByTestId('sourcerer-save')).toBeVisible(); + }); + }); + + it('Checks box when only alerts index is selected in timeline', async () => { + cleanup(); + const state2 = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + sourcererScopes: { + ...mockGlobalState.sourcerer.sourcererScopes, + [SourcererScopeName.timeline]: { + ...mockGlobalState.sourcerer.sourcererScopes[SourcererScopeName.timeline], + loading: false, + selectedDataViewId: id, + selectedPatterns: [`${mockGlobalState.sourcerer.signalIndexName}`], + }, + }, + }, + }; + + store = createStore( + state2, + SUB_PLUGINS_REDUCER, + + kibanaObservable, + storage + ); + + render( + + + + ); + + fireEvent.click(screen.queryAllByTestId('timeline-sourcerer-trigger')[0]); + + await waitFor(() => { + expect(screen.getByTestId('sourcerer-alert-only-checkbox')).toBeChecked(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/trigger.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/trigger.tsx index e1c1e405bd52..5dc7ab852218 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/trigger.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/trigger.tsx @@ -7,9 +7,9 @@ import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; -import { EuiToolTip } from '@elastic/eui'; +import { EuiToolTip, EuiButton } from '@elastic/eui'; import * as i18n from './translations'; -import { getTooltipContent, StyledBadge, StyledButton } from './helpers'; +import { getTooltipContent, StyledBadge, StyledButtonEmpty } from './helpers'; import type { ModifiedTypes } from './use_pick_index_patterns'; interface Props { @@ -68,12 +68,17 @@ export const TriggerComponent: FC = ({ } }, [isModified]); + const Button = useMemo( + () => (isTimelineSourcerer ? EuiButton : StyledButtonEmpty), + [isTimelineSourcerer] + ); + const trigger = useMemo( () => ( - = ({ > {i18n.DATA_VIEW} {!disabled && badge} - + ), - [disabled, badge, isTimelineSourcerer, loading, onClick] + [disabled, badge, isTimelineSourcerer, loading, onClick, Button] ); const tooltipContent = useMemo( diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/utils.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/utils.tsx index 00c621959872..2e6653a18595 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/utils.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/utils.tsx @@ -43,28 +43,30 @@ export const CurrentPatternsMessage = ({ if (timelineType === TimelineType.template) { return ( + + {activePatterns.join(', ')}, + }} + /> + + ); + } + + return ( + {activePatterns.join(', ')}, }} /> - ); - } - - return ( - {activePatterns.join(', ')}, - }} - /> + ); }; @@ -147,25 +149,27 @@ export const DeprecatedMessage = ({ }) => { if (timelineType === TimelineType.template) { return ( + + {i18n.TOGGLE_TO_NEW_SOURCERER}, + }} + /> + + ); + } + return ( + {i18n.TOGGLE_TO_NEW_SOURCERER}, }} /> - ); - } - return ( - {i18n.TOGGLE_TO_NEW_SOURCERER}, - }} - /> + ); }; @@ -178,24 +182,26 @@ export const MissingPatternsMessage = ({ }) => { if (timelineType === TimelineType.template) { return ( + + {i18n.TOGGLE_TO_NEW_SOURCERER}, + }} + /> + + ); + } + return ( + {i18n.TOGGLE_TO_NEW_SOURCERER}, }} /> - ); - } - return ( - {i18n.TOGGLE_TO_NEW_SOURCERER}, - }} - /> + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.test.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.test.tsx new file mode 100644 index 000000000000..abd3db47ea38 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.test.tsx @@ -0,0 +1,189 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { TimelineItem } from '@kbn/timelines-plugin/common'; +import { act, fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../mock'; +import { useGetCurrentUserProfile } from '../../user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../../user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../../user_profiles/use_suggest_users'; + +import { BulkAlertAssigneesPanel } from './alert_bulk_assignees'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; +import { ASSIGNEES_APPLY_BUTTON_TEST_ID } from '../../assignees/test_ids'; + +jest.mock('../../user_profiles/use_get_current_user_profile'); +jest.mock('../../user_profiles/use_bulk_get_user_profiles'); +jest.mock('../../user_profiles/use_suggest_users'); + +const mockUserProfiles = [ + { uid: 'user-id-1', enabled: true, user: { username: 'user1' }, data: {} }, + { uid: 'user-id-2', enabled: true, user: { username: 'user2' }, data: {} }, +]; + +const mockSuggestedUserProfiles = [ + ...mockUserProfiles, + { uid: 'user-id-3', enabled: true, user: { username: 'user3' }, data: {} }, + { uid: 'user-id-4', enabled: true, user: { username: 'user4' }, data: {} }, +]; + +const mockAlertsWithAssignees = [ + { + _id: 'test-id', + data: [ + { + field: ALERT_WORKFLOW_ASSIGNEE_IDS, + value: ['user-id-1', 'user-id-2'], + }, + ], + ecs: { _id: 'test-id' }, + }, + { + _id: 'test-id', + data: [ + { + field: ALERT_WORKFLOW_ASSIGNEE_IDS, + value: ['user-id-1', 'user-id-2'], + }, + ], + ecs: { _id: 'test-id' }, + }, +]; + +(useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], +}); +(useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, +}); +(useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockSuggestedUserProfiles, +}); + +const renderAssigneesMenu = ( + items: TimelineItem[], + closePopover: () => void = jest.fn(), + onSubmit: () => Promise = jest.fn(), + setIsLoading: () => void = jest.fn() +) => { + return render( + + + + ); +}; + +describe('BulkAlertAssigneesPanel', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('it renders', () => { + const wrapper = renderAssigneesMenu(mockAlertsWithAssignees); + + expect(wrapper.getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(useSuggestUsers).toHaveBeenCalled(); + }); + + test('it calls expected functions on submit when nothing has changed', () => { + const mockedClosePopover = jest.fn(); + const mockedOnSubmit = jest.fn(); + const mockedSetIsLoading = jest.fn(); + + const wrapper = renderAssigneesMenu( + mockAlertsWithAssignees, + mockedClosePopover, + mockedOnSubmit, + mockedSetIsLoading + ); + + act(() => { + fireEvent.click(wrapper.getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)); + }); + expect(mockedClosePopover).toHaveBeenCalled(); + expect(mockedOnSubmit).not.toHaveBeenCalled(); + expect(mockedSetIsLoading).not.toHaveBeenCalled(); + }); + + test('it updates state correctly', () => { + const wrapper = renderAssigneesMenu(mockAlertsWithAssignees); + + const deselectUser = (userName: string, index: number) => { + expect(wrapper.getAllByRole('option')[index]).toHaveAttribute('title', userName); + expect(wrapper.getAllByRole('option')[index]).toBeChecked(); + act(() => { + fireEvent.click(wrapper.getByText(userName)); + }); + expect(wrapper.getAllByRole('option')[index]).toHaveAttribute('title', userName); + expect(wrapper.getAllByRole('option')[index]).not.toBeChecked(); + }; + + const selectUser = (userName: string, index = 0) => { + expect(wrapper.getAllByRole('option')[index]).toHaveAttribute('title', userName); + expect(wrapper.getAllByRole('option')[index]).not.toBeChecked(); + act(() => { + fireEvent.click(wrapper.getByText(userName)); + }); + expect(wrapper.getAllByRole('option')[index]).toHaveAttribute('title', userName); + expect(wrapper.getAllByRole('option')[index]).toBeChecked(); + }; + + deselectUser('user1', 0); + deselectUser('user2', 1); + selectUser('user3', 2); + selectUser('user4', 3); + }); + + test('it calls expected functions on submit when alerts have changed', () => { + const mockedClosePopover = jest.fn(); + const mockedOnSubmit = jest.fn(); + const mockedSetIsLoading = jest.fn(); + + const wrapper = renderAssigneesMenu( + mockAlertsWithAssignees, + mockedClosePopover, + mockedOnSubmit, + mockedSetIsLoading + ); + act(() => { + fireEvent.click(wrapper.getByText('user1')); + }); + act(() => { + fireEvent.click(wrapper.getByText('user2')); + }); + act(() => { + fireEvent.click(wrapper.getByText('user3')); + }); + act(() => { + fireEvent.click(wrapper.getByText('user4')); + }); + + act(() => { + fireEvent.click(wrapper.getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)); + }); + expect(mockedClosePopover).toHaveBeenCalled(); + expect(mockedOnSubmit).toHaveBeenCalled(); + expect(mockedOnSubmit).toHaveBeenCalledWith( + { + add: ['user-id-4', 'user-id-3'], + remove: ['user-id-1', 'user-id-2'], + }, + ['test-id', 'test-id'], + expect.anything(), // An anonymous callback defined in the onSubmit function + mockedSetIsLoading + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.tsx new file mode 100644 index 000000000000..9e312e6b366e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/alert_bulk_assignees.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { intersection } from 'lodash'; +import React, { memo, useCallback, useMemo } from 'react'; + +import type { TimelineItem } from '@kbn/timelines-plugin/common'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; + +import type { SetAlertAssigneesFunc } from './use_set_alert_assignees'; +import { AssigneesApplyPanel } from '../../assignees/assignees_apply_panel'; +import type { AssigneesIdsSelection } from '../../assignees/types'; +import { removeNoAssigneesSelection } from '../../assignees/utils'; + +interface BulkAlertAssigneesPanelComponentProps { + alertItems: TimelineItem[]; + setIsLoading: (isLoading: boolean) => void; + refresh?: () => void; + clearSelection?: () => void; + closePopoverMenu: () => void; + onSubmit: SetAlertAssigneesFunc; +} +const BulkAlertAssigneesPanelComponent: React.FC = ({ + alertItems, + refresh, + setIsLoading, + clearSelection, + closePopoverMenu, + onSubmit, +}) => { + const assignedUserIds = useMemo( + () => + intersection( + ...alertItems.map( + (item) => + item.data.find((data) => data.field === ALERT_WORKFLOW_ASSIGNEE_IDS)?.value ?? [] + ) + ), + [alertItems] + ); + + const onAssigneesApply = useCallback( + async (assigneesIds: AssigneesIdsSelection[]) => { + const updatedIds = removeNoAssigneesSelection(assigneesIds); + const assigneesToAddArray = updatedIds.filter((uid) => uid && !assignedUserIds.includes(uid)); + const assigneesToRemoveArray = assignedUserIds.filter( + (uid) => uid && !updatedIds.includes(uid) + ); + if (assigneesToAddArray.length === 0 && assigneesToRemoveArray.length === 0) { + closePopoverMenu(); + return; + } + + const ids = alertItems.map((item) => item._id); + const assignees = { + add: assigneesToAddArray, + remove: assigneesToRemoveArray, + }; + const onSuccess = () => { + if (refresh) refresh(); + if (clearSelection) clearSelection(); + }; + if (onSubmit != null) { + closePopoverMenu(); + await onSubmit(assignees, ids, onSuccess, setIsLoading); + } + }, + [alertItems, assignedUserIds, clearSelection, closePopoverMenu, onSubmit, refresh, setIsLoading] + ); + + return ( +
    + +
    + ); +}; + +export const BulkAlertAssigneesPanel = memo(BulkAlertAssigneesPanelComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/translations.ts b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/translations.ts index a99ad3cb76a4..8799911b6e30 100644 --- a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/translations.ts @@ -211,3 +211,31 @@ export const ALERT_TAGS_CONTEXT_MENU_ITEM_TOOLTIP_INFO = i18n.translate( defaultMessage: 'Change alert tag options in Kibana Advanced Settings.', } ); + +export const UPDATE_ALERT_ASSIGNEES_SUCCESS_TOAST = (totalAlerts: number) => + i18n.translate('xpack.securitySolution.bulkActions.updateAlertAssigneesSuccessToastMessage', { + values: { totalAlerts }, + defaultMessage: + 'Successfully updated assignees for {totalAlerts} {totalAlerts, plural, =1 {alert} other {alerts}}.', + }); + +export const UPDATE_ALERT_ASSIGNEES_FAILURE = i18n.translate( + 'xpack.securitySolution.bulkActions.updateAlertAssigneesFailedToastMessage', + { + defaultMessage: 'Failed to update alert assignees.', + } +); + +export const ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE = i18n.translate( + 'xpack.securitySolution.bulkActions.alertAssigneesContextMenuItemTitle', + { + defaultMessage: 'Assign alert', + } +); + +export const REMOVE_ALERT_ASSIGNEES_CONTEXT_MENU_TITLE = i18n.translate( + 'xpack.securitySolution.bulkActions.removeAlertAssignessContextMenuTitle', + { + defaultMessage: 'Unassign alert', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.test.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.test.tsx new file mode 100644 index 000000000000..7a6b9c87fa27 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.test.tsx @@ -0,0 +1,192 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; +import { TestProviders } from '@kbn/timelines-plugin/public/mock'; +import type { BulkActionsConfig } from '@kbn/triggers-actions-ui-plugin/public/types'; +import type { TimelineItem } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/bulk_actions/components/toolbar'; +import { act, fireEvent, render } from '@testing-library/react'; +import { renderHook } from '@testing-library/react-hooks'; + +import type { + UseBulkAlertAssigneesItemsProps, + UseBulkAlertAssigneesPanel, +} from './use_bulk_alert_assignees_items'; +import { useBulkAlertAssigneesItems } from './use_bulk_alert_assignees_items'; +import { useSetAlertAssignees } from './use_set_alert_assignees'; +import { useGetCurrentUserProfile } from '../../user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../../user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../../user_profiles/use_suggest_users'; +import { ASSIGNEES_APPLY_BUTTON_TEST_ID } from '../../assignees/test_ids'; +import { useAlertsPrivileges } from '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; +import { useLicense } from '../../../hooks/use_license'; + +jest.mock('./use_set_alert_assignees'); +jest.mock('../../user_profiles/use_get_current_user_profile'); +jest.mock('../../user_profiles/use_bulk_get_user_profiles'); +jest.mock('../../user_profiles/use_suggest_users'); +jest.mock('../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'); +jest.mock('../../../hooks/use_license'); + +const mockUserProfiles = [ + { uid: 'user-id-1', enabled: true, user: { username: 'fakeUser1' }, data: {} }, + { uid: 'user-id-2', enabled: true, user: { username: 'fakeUser2' }, data: {} }, +]; + +const defaultProps: UseBulkAlertAssigneesItemsProps = { + onAssigneesUpdate: () => {}, +}; + +const mockAssigneeItems = [ + { + _id: 'test-id', + data: [{ field: ALERT_WORKFLOW_ASSIGNEE_IDS, value: ['user-id-1', 'user-id-2'] }], + ecs: { _id: 'test-id', _index: 'test-index' }, + }, +]; + +const renderPanel = (panel: UseBulkAlertAssigneesPanel) => { + const content = panel.renderContent({ + closePopoverMenu: jest.fn(), + setIsBulkActionsLoading: jest.fn(), + alertItems: mockAssigneeItems, + }); + return render(content); +}; + +describe('useBulkAlertAssigneesItems', () => { + beforeEach(() => { + (useSetAlertAssignees as jest.Mock).mockReturnValue(jest.fn()); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + (useAlertsPrivileges as jest.Mock).mockReturnValue({ hasIndexWrite: true }); + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => true }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return two alert assignees action items and one panel', () => { + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + + expect(result.current.alertAssigneesItems.length).toEqual(2); + expect(result.current.alertAssigneesPanels.length).toEqual(1); + + expect(result.current.alertAssigneesItems[0]['data-test-subj']).toEqual( + 'alert-assignees-context-menu-item' + ); + expect(result.current.alertAssigneesItems[1]['data-test-subj']).toEqual( + 'remove-alert-assignees-menu-item' + ); + expect(result.current.alertAssigneesPanels[0]['data-test-subj']).toEqual( + 'alert-assignees-context-menu-panel' + ); + }); + + it('should still render alert assignees panel when useSetAlertAssignees is null', () => { + (useSetAlertAssignees as jest.Mock).mockReturnValue(null); + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + + expect(result.current.alertAssigneesPanels[0]['data-test-subj']).toEqual( + 'alert-assignees-context-menu-panel' + ); + const wrapper = renderPanel(result.current.alertAssigneesPanels[0]); + expect(wrapper.getByTestId('alert-assignees-selectable-menu')).toBeInTheDocument(); + }); + + it('should call setAlertAssignees on submit', () => { + const mockSetAlertAssignees = jest.fn(); + (useSetAlertAssignees as jest.Mock).mockReturnValue(mockSetAlertAssignees); + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + + const wrapper = renderPanel(result.current.alertAssigneesPanels[0]); + expect(wrapper.getByTestId('alert-assignees-selectable-menu')).toBeInTheDocument(); + act(() => { + fireEvent.click(wrapper.getByText('fakeUser2')); // Won't fire unless component assignees selection has been changed + }); + act(() => { + fireEvent.click(wrapper.getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID)); + }); + expect(mockSetAlertAssignees).toHaveBeenCalled(); + }); + + it('should call setAlertAssignees with the correct parameters on `Unassign alert` button click', () => { + const mockSetAlertAssignees = jest.fn(); + (useSetAlertAssignees as jest.Mock).mockReturnValue(mockSetAlertAssignees); + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + + const items: TimelineItem[] = [ + { + _id: 'alert1', + data: [{ field: ALERT_WORKFLOW_ASSIGNEE_IDS, value: ['user1', 'user2'] }], + ecs: { _id: 'alert1', _index: 'index1' }, + }, + { + _id: 'alert2', + data: [{ field: ALERT_WORKFLOW_ASSIGNEE_IDS, value: ['user1', 'user3'] }], + ecs: { _id: 'alert2', _index: 'index1' }, + }, + { + _id: 'alert3', + data: [], + ecs: { _id: 'alert3', _index: 'index1' }, + }, + ]; + + const setAlertLoadingMock = jest.fn(); + ( + result.current.alertAssigneesItems[1] as unknown as { onClick: BulkActionsConfig['onClick'] } + ).onClick?.(items, true, setAlertLoadingMock, jest.fn(), jest.fn()); + + expect(mockSetAlertAssignees).toHaveBeenCalled(); + expect(mockSetAlertAssignees).toHaveBeenCalledWith( + { add: [], remove: ['user1', 'user2', 'user3'] }, + ['alert1', 'alert2', 'alert3'], + expect.any(Function), + setAlertLoadingMock + ); + }); + + it('should return 0 items for the VIEWER role', () => { + (useAlertsPrivileges as jest.Mock).mockReturnValue({ hasIndexWrite: false }); + + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + expect(result.current.alertAssigneesItems.length).toEqual(0); + expect(result.current.alertAssigneesPanels.length).toEqual(0); + }); + + it('should return 0 items for the Basic license', () => { + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => false }); + + const { result } = renderHook(() => useBulkAlertAssigneesItems(defaultProps), { + wrapper: TestProviders, + }); + expect(result.current.alertAssigneesItems.length).toEqual(0); + expect(result.current.alertAssigneesPanels.length).toEqual(0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.tsx new file mode 100644 index 000000000000..46fed23c1214 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { union } from 'lodash'; +import React, { useCallback, useMemo } from 'react'; + +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; +import type { + BulkActionsConfig, + RenderContentPanelProps, +} from '@kbn/triggers-actions-ui-plugin/public/types'; + +import { useLicense } from '../../../hooks/use_license'; +import { useAlertsPrivileges } from '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; +import { ASSIGNEES_PANEL_WIDTH } from '../../assignees/constants'; +import { BulkAlertAssigneesPanel } from './alert_bulk_assignees'; +import * as i18n from './translations'; +import { useSetAlertAssignees } from './use_set_alert_assignees'; + +export interface UseBulkAlertAssigneesItemsProps { + onAssigneesUpdate?: () => void; +} + +export interface UseBulkAlertAssigneesPanel { + id: number; + title: JSX.Element; + 'data-test-subj': string; + renderContent: (props: RenderContentPanelProps) => JSX.Element; + width?: number; +} + +export const useBulkAlertAssigneesItems = ({ + onAssigneesUpdate, +}: UseBulkAlertAssigneesItemsProps) => { + const isPlatinumPlus = useLicense().isPlatinumPlus(); + + const { hasIndexWrite } = useAlertsPrivileges(); + const setAlertAssignees = useSetAlertAssignees(); + + const handleOnAlertAssigneesSubmit = useCallback( + async (assignees, ids, onSuccess, setIsLoading) => { + if (setAlertAssignees) { + await setAlertAssignees(assignees, ids, onSuccess, setIsLoading); + } + }, + [setAlertAssignees] + ); + + const onSuccess = useCallback(() => { + onAssigneesUpdate?.(); + }, [onAssigneesUpdate]); + + const onRemoveAllAssignees = useCallback['onClick']>( + async (items, _, setAlertLoading) => { + const ids: string[] = items.map((item) => item._id); + const assignedUserIds = union( + ...items.map( + (item) => + item.data.find((data) => data.field === ALERT_WORKFLOW_ASSIGNEE_IDS)?.value ?? [] + ) + ); + if (!assignedUserIds.length) { + return; + } + const assignees = { + add: [], + remove: assignedUserIds, + }; + if (setAlertAssignees) { + await setAlertAssignees(assignees, ids, onSuccess, setAlertLoading); + } + }, + [onSuccess, setAlertAssignees] + ); + + const alertAssigneesItems = useMemo( + () => + hasIndexWrite && isPlatinumPlus + ? [ + { + key: 'manage-alert-assignees', + 'data-test-subj': 'alert-assignees-context-menu-item', + name: i18n.ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE, + panel: 2, + label: i18n.ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE, + disableOnQuery: true, + }, + { + key: 'remove-all-alert-assignees', + 'data-test-subj': 'remove-alert-assignees-menu-item', + name: i18n.REMOVE_ALERT_ASSIGNEES_CONTEXT_MENU_TITLE, + label: i18n.REMOVE_ALERT_ASSIGNEES_CONTEXT_MENU_TITLE, + disableOnQuery: true, + onClick: onRemoveAllAssignees, + }, + ] + : [], + [hasIndexWrite, isPlatinumPlus, onRemoveAllAssignees] + ); + + const TitleContent = useMemo( + () => ( + + {i18n.ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE} + + ), + [] + ); + + const renderContent = useCallback( + ({ + alertItems, + refresh, + setIsBulkActionsLoading, + clearSelection, + closePopoverMenu, + }: RenderContentPanelProps) => ( + { + onSuccess(); + refresh?.(); + }} + setIsLoading={setIsBulkActionsLoading} + clearSelection={clearSelection} + closePopoverMenu={closePopoverMenu} + onSubmit={handleOnAlertAssigneesSubmit} + /> + ), + [handleOnAlertAssigneesSubmit, onSuccess] + ); + + const alertAssigneesPanels: UseBulkAlertAssigneesPanel[] = useMemo( + () => + hasIndexWrite && isPlatinumPlus + ? [ + { + id: 2, + title: TitleContent, + 'data-test-subj': 'alert-assignees-context-menu-panel', + renderContent, + width: ASSIGNEES_PANEL_WIDTH, + }, + ] + : [], + [TitleContent, hasIndexWrite, isPlatinumPlus, renderContent] + ); + + return { + alertAssigneesItems, + alertAssigneesPanels, + }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_set_alert_assignees.tsx b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_set_alert_assignees.tsx new file mode 100644 index 000000000000..43630cda420c --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions/use_set_alert_assignees.tsx @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreStart } from '@kbn/core/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useCallback, useEffect, useRef } from 'react'; +import type { AlertAssignees } from '../../../../../common/api/detection_engine'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import * as i18n from './translations'; +import { setAlertAssignees } from '../../../containers/alert_assignees/api'; + +export type SetAlertAssigneesFunc = ( + assignees: AlertAssignees, + ids: string[], + onSuccess: () => void, + setTableLoading: (param: boolean) => void +) => Promise; +export type ReturnSetAlertAssignees = SetAlertAssigneesFunc | null; + +/** + * Update alert assignees by query + * + * @param assignees to add and/or remove from a batch of alerts + * @param ids alert ids that will be used to create the update query. + * @param onSuccess a callback function that will be called on successful api response + * @param setTableLoading a function that sets the alert table in a loading state for bulk actions + + * + * @throws An error if response is not OK + */ +export const useSetAlertAssignees = (): ReturnSetAlertAssignees => { + const { http } = useKibana().services; + const { addSuccess, addError } = useAppToasts(); + const setAlertAssigneesRef = useRef(null); + + const onUpdateSuccess = useCallback( + (updated: number = 0) => addSuccess(i18n.UPDATE_ALERT_ASSIGNEES_SUCCESS_TOAST(updated)), + [addSuccess] + ); + + const onUpdateFailure = useCallback( + (error: Error) => { + addError(error.message, { title: i18n.UPDATE_ALERT_ASSIGNEES_FAILURE }); + }, + [addError] + ); + + useEffect(() => { + let ignore = false; + const abortCtrl = new AbortController(); + + const onSetAlertAssignees: SetAlertAssigneesFunc = async ( + assignees, + ids, + onSuccess, + setTableLoading + ) => { + try { + setTableLoading(true); + const response = await setAlertAssignees({ assignees, ids, signal: abortCtrl.signal }); + if (!ignore) { + onSuccess(); + setTableLoading(false); + onUpdateSuccess(response.updated); + } + } catch (error) { + if (!ignore) { + setTableLoading(false); + onUpdateFailure(error); + } + } + }; + + setAlertAssigneesRef.current = onSetAlertAssignees; + return (): void => { + ignore = true; + abortCtrl.abort(); + }; + }, [http, onUpdateFailure, onUpdateSuccess]); + + return setAlertAssigneesRef.current; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/__mocks__/api.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/__mocks__/api.ts new file mode 100644 index 000000000000..34a24bb4e00f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/__mocks__/api.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import { mockUserProfiles } from '../mock'; + +export const suggestUsers = async ({ + searchTerm, +}: { + searchTerm: string; +}): Promise => Promise.resolve(mockUserProfiles); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/api.test.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/api.test.ts new file mode 100644 index 000000000000..fbd2ee48c9eb --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/api.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock } from '@kbn/core/public/mocks'; + +import { mockUserProfiles } from './mock'; +import { suggestUsers } from './api'; +import { KibanaServices } from '../../lib/kibana'; +import { DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL } from '../../../../common/constants'; + +const mockKibanaServices = KibanaServices.get as jest.Mock; +jest.mock('../../lib/kibana'); + +const coreStartMock = coreMock.createStart({ basePath: '/mock' }); +mockKibanaServices.mockReturnValue(coreStartMock); +const fetchMock = coreStartMock.http.fetch; + +describe('Detections Alerts API', () => { + describe('suggestUsers', () => { + beforeEach(() => { + fetchMock.mockClear(); + fetchMock.mockResolvedValue(mockUserProfiles); + }); + + test('check parameter url', async () => { + await suggestUsers({ searchTerm: 'name1' }); + expect(fetchMock).toHaveBeenCalledWith( + DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL, + expect.objectContaining({ + method: 'GET', + version: '2023-10-31', + query: { searchTerm: 'name1' }, + }) + ); + }); + + test('happy path', async () => { + const alertsResp = await suggestUsers({ searchTerm: '' }); + expect(alertsResp).toEqual(mockUserProfiles); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/api.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/api.ts new file mode 100644 index 000000000000..22340d25e0a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/api.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; + +import type { SuggestUsersProps } from './types'; +import { DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL } from '../../../../common/constants'; +import { KibanaServices } from '../../lib/kibana'; + +/** + * Fetches suggested user profiles + */ +export const suggestUsers = async ({ + searchTerm, +}: SuggestUsersProps): Promise => { + return KibanaServices.get().http.fetch( + DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL, + { + method: 'GET', + version: '2023-10-31', + query: { searchTerm }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/mock.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/mock.ts new file mode 100644 index 000000000000..11d1535cc5a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/mock.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const mockCurrentUserProfile = { + uid: 'current-user', + enabled: true, + user: { username: 'current.user' }, + data: {}, +}; + +export const mockUserProfiles = [ + { uid: 'user-id-1', enabled: true, user: { username: 'user1' }, data: {} }, + { uid: 'user-id-2', enabled: true, user: { username: 'user2' }, data: {} }, +]; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/test_ids.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/test_ids.ts new file mode 100644 index 000000000000..6a2aa4e25916 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/test_ids.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const PREFIX = 'securitySolutionUsers'; + +/* Avatars */ +export const USER_AVATAR_ITEM_TEST_ID = (userName: string) => `${PREFIX}Avatar-${userName}`; +export const USERS_AVATARS_PANEL_TEST_ID = `${PREFIX}AvatarsPanel`; +export const USERS_AVATARS_COUNT_BADGE_TEST_ID = `${PREFIX}AvatarsCountBadge`; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/translations.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/translations.ts new file mode 100644 index 000000000000..6b749e45e399 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/translations.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const CURRENT_USER_PROFILE_FAILURE = i18n.translate( + 'xpack.securitySolution.userProfiles.fetchCurrentUserProfile.failure', + { defaultMessage: 'Failed to find current user' } +); + +export const USER_PROFILES_FAILURE = i18n.translate( + 'xpack.securitySolution.userProfiles.fetchUserProfiles.failure', + { + defaultMessage: 'Failed to find users', + } +); + +/** + * Used whenever we need to display a user name and for some reason it is not available + */ +export const UNKNOWN_USER_PROFILE_NAME = i18n.translate( + 'xpack.securitySolution.userProfiles.unknownUser.displayName', + { defaultMessage: 'Unknown' } +); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/types.ts b/x-pack/plugins/security_solution/public/common/components/user_profiles/types.ts new file mode 100644 index 000000000000..2d0586dd571a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface SuggestUsersProps { + searchTerm: string; +} diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.test.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.test.tsx new file mode 100644 index 000000000000..3861e6a6c8a6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { securityMock } from '@kbn/security-plugin/public/mocks'; + +import { mockUserProfiles } from './mock'; +import { useBulkGetUserProfiles } from './use_bulk_get_user_profiles'; +import { useKibana } from '../../lib/kibana'; +import { useAppToasts } from '../../hooks/use_app_toasts'; +import { useAppToastsMock } from '../../hooks/use_app_toasts.mock'; +import { createStartServicesMock } from '../../lib/kibana/kibana_react.mock'; +import { TestProviders } from '../../mock'; + +jest.mock('../../lib/kibana'); +jest.mock('../../hooks/use_app_toasts'); + +describe('useBulkGetUserProfiles hook', () => { + let appToastsMock: jest.Mocked>; + beforeEach(() => { + jest.clearAllMocks(); + appToastsMock = useAppToastsMock.create(); + (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + const security = securityMock.createStart(); + security.userProfiles.bulkGet.mockReturnValue(Promise.resolve(mockUserProfiles)); + (useKibana as jest.Mock).mockReturnValue({ + services: { + ...createStartServicesMock(), + security, + }, + }); + }); + + it('returns an array of userProfiles', async () => { + const userProfiles = useKibana().services.security.userProfiles; + const spyOnUserProfiles = jest.spyOn(userProfiles, 'bulkGet'); + const assigneesIds = new Set(['user1']); + const { result, waitForNextUpdate } = renderHook( + () => useBulkGetUserProfiles({ uids: assigneesIds }), + { + wrapper: TestProviders, + } + ); + await waitForNextUpdate(); + + expect(spyOnUserProfiles).toHaveBeenCalledTimes(1); + expect(result.current.isLoading).toEqual(false); + expect(result.current.data).toEqual(mockUserProfiles); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.tsx new file mode 100644 index 000000000000..b74e79716251 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { UserProfile } from '@kbn/security-plugin/common'; +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import { useQuery } from '@tanstack/react-query'; +import { useKibana } from '../../lib/kibana'; +import { useAppToasts } from '../../hooks/use_app_toasts'; +import { USER_PROFILES_FAILURE } from './translations'; + +export interface BulkGetUserProfilesArgs { + security: SecurityPluginStart; + uids: Set; +} + +export const bulkGetUserProfiles = async ({ + security, + uids, +}: BulkGetUserProfilesArgs): Promise => { + if (uids.size === 0) { + return []; + } + return security.userProfiles.bulkGet({ uids, dataPath: 'avatar' }); +}; + +export const useBulkGetUserProfiles = ({ uids }: { uids: Set }) => { + const { security } = useKibana().services; + const { addError } = useAppToasts(); + + return useQuery( + ['useBulkGetUserProfiles', ...uids], + async () => { + return bulkGetUserProfiles({ security, uids }); + }, + { + retry: false, + staleTime: Infinity, + onError: (e) => { + addError(e, { title: USER_PROFILES_FAILURE }); + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.test.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.test.tsx new file mode 100644 index 000000000000..84beb0a8b135 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.test.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { securityMock } from '@kbn/security-plugin/public/mocks'; + +import { mockCurrentUserProfile } from './mock'; +import { useGetCurrentUserProfile } from './use_get_current_user_profile'; +import { useKibana } from '../../lib/kibana'; +import { useAppToasts } from '../../hooks/use_app_toasts'; +import { useAppToastsMock } from '../../hooks/use_app_toasts.mock'; +import { createStartServicesMock } from '../../lib/kibana/kibana_react.mock'; +import { TestProviders } from '../../mock'; + +jest.mock('../../lib/kibana'); +jest.mock('../../hooks/use_app_toasts'); + +describe('useGetCurrentUserProfile hook', () => { + let appToastsMock: jest.Mocked>; + beforeEach(() => { + jest.clearAllMocks(); + appToastsMock = useAppToastsMock.create(); + (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + const security = securityMock.createStart(); + security.userProfiles.getCurrent.mockReturnValue(Promise.resolve(mockCurrentUserProfile)); + (useKibana as jest.Mock).mockReturnValue({ + services: { + ...createStartServicesMock(), + security, + }, + }); + }); + + it('returns current user', async () => { + const userProfiles = useKibana().services.security.userProfiles; + const spyOnUserProfiles = jest.spyOn(userProfiles, 'getCurrent'); + const { result, waitForNextUpdate } = renderHook(() => useGetCurrentUserProfile(), { + wrapper: TestProviders, + }); + await waitForNextUpdate(); + + expect(spyOnUserProfiles).toHaveBeenCalledTimes(1); + expect(result.current.isLoading).toEqual(false); + expect(result.current.data).toEqual(mockCurrentUserProfile); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.tsx new file mode 100644 index 000000000000..fbb4bb066040 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; + +import { CURRENT_USER_PROFILE_FAILURE } from './translations'; +import { useKibana } from '../../lib/kibana'; +import { useAppToasts } from '../../hooks/use_app_toasts'; + +export const getCurrentUserProfile = async ({ + security, +}: { + security: SecurityPluginStart; +}): Promise => { + return security.userProfiles.getCurrent({ dataPath: 'avatar' }); +}; + +/** + * Fetches current user profile using `userProfiles` service via `security.userProfiles.getCurrent()` + * + * NOTE: There is a similar hook `useCurrentUser` which fetches current authenticated user via `security.authc.getCurrentUser()` + */ +export const useGetCurrentUserProfile = () => { + const { security } = useKibana().services; + const { addError } = useAppToasts(); + + return useQuery( + ['useGetCurrentUserProfile'], + async () => { + return getCurrentUserProfile({ security }); + }, + { + retry: false, + staleTime: Infinity, + onError: (e) => { + addError(e, { title: CURRENT_USER_PROFILE_FAILURE }); + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.test.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.test.tsx new file mode 100644 index 000000000000..2cb727942ed5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.test.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useSuggestUsers } from './use_suggest_users'; + +import * as api from './api'; +import { mockUserProfiles } from './mock'; +import { useAppToasts } from '../../hooks/use_app_toasts'; +import { useAppToastsMock } from '../../hooks/use_app_toasts.mock'; +import { TestProviders } from '../../mock'; + +jest.mock('./api'); +jest.mock('../../hooks/use_app_toasts'); + +describe('useSuggestUsers hook', () => { + let appToastsMock: jest.Mocked>; + beforeEach(() => { + jest.clearAllMocks(); + appToastsMock = useAppToastsMock.create(); + (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + }); + + it('returns an array of userProfiles', async () => { + const spyOnUserProfiles = jest.spyOn(api, 'suggestUsers'); + const { result, waitForNextUpdate } = renderHook(() => useSuggestUsers({ searchTerm: '' }), { + wrapper: TestProviders, + }); + await waitForNextUpdate(); + expect(spyOnUserProfiles).toHaveBeenCalledTimes(1); + expect(result.current.isLoading).toEqual(false); + expect(result.current.data).toEqual(mockUserProfiles); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.tsx new file mode 100644 index 000000000000..a8a2338e51e9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/use_suggest_users.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; + +import { suggestUsers } from './api'; +import { USER_PROFILES_FAILURE } from './translations'; +import { useAppToasts } from '../../hooks/use_app_toasts'; + +export interface SuggestUserProfilesArgs { + searchTerm: string; +} + +export const bulkGetUserProfiles = async ({ + searchTerm, +}: { + searchTerm: string; +}): Promise => { + return suggestUsers({ searchTerm }); +}; + +export const useSuggestUsers = ({ searchTerm }: { searchTerm: string }) => { + const { addError } = useAppToasts(); + + return useQuery( + ['useSuggestUsers', searchTerm], + async () => { + return bulkGetUserProfiles({ searchTerm }); + }, + { + retry: false, + staleTime: Infinity, + onError: (e) => { + addError(e, { title: USER_PROFILES_FAILURE }); + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.test.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.test.tsx new file mode 100644 index 000000000000..725cb81aea3e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.test.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { UsersAvatarsPanel } from './users_avatars_panel'; + +import { TestProviders } from '../../mock'; +import { mockUserProfiles } from '../assignees/mocks'; +import { + USERS_AVATARS_COUNT_BADGE_TEST_ID, + USERS_AVATARS_PANEL_TEST_ID, + USER_AVATAR_ITEM_TEST_ID, +} from './test_ids'; + +const renderUsersAvatarsPanel = (userProfiles = [mockUserProfiles[0]], maxVisibleAvatars = 1) => + render( + + + + ); + +describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should render component', () => { + const { getByTestId } = renderUsersAvatarsPanel(); + + expect(getByTestId(USERS_AVATARS_PANEL_TEST_ID)).toBeInTheDocument(); + }); + + it('should render avatars for all assignees', () => { + const assignees = [mockUserProfiles[0], mockUserProfiles[1]]; + const { getByTestId, queryByTestId } = renderUsersAvatarsPanel(assignees, 2); + + expect(getByTestId(USER_AVATAR_ITEM_TEST_ID('user1'))).toBeInTheDocument(); + expect(getByTestId(USER_AVATAR_ITEM_TEST_ID('user2'))).toBeInTheDocument(); + + expect(queryByTestId(USERS_AVATARS_COUNT_BADGE_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should render badge with number of assignees if exceeds `maxVisibleAvatars`', () => { + const assignees = [mockUserProfiles[0], mockUserProfiles[1]]; + const { getByTestId, queryByTestId } = renderUsersAvatarsPanel(assignees, 1); + + expect(getByTestId(USERS_AVATARS_COUNT_BADGE_TEST_ID)).toBeInTheDocument(); + + expect(queryByTestId(USER_AVATAR_ITEM_TEST_ID('user1'))).not.toBeInTheDocument(); + expect(queryByTestId(USER_AVATAR_ITEM_TEST_ID('user2'))).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.tsx b/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.tsx new file mode 100644 index 000000000000..777ef04060f2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/user_profiles/users_avatars_panel.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { memo } from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiNotificationBadge, EuiToolTip } from '@elastic/eui'; +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import { UserAvatar } from '@kbn/user-profile-components'; + +import { UNKNOWN_USER_PROFILE_NAME } from './translations'; +import { + USERS_AVATARS_COUNT_BADGE_TEST_ID, + USERS_AVATARS_PANEL_TEST_ID, + USER_AVATAR_ITEM_TEST_ID, +} from './test_ids'; + +export type UserProfileOrUknown = UserProfileWithAvatar | undefined; + +export interface UsersAvatarsPanelProps { + /** + * The array of user profiles + */ + userProfiles: UserProfileOrUknown[]; + + /** + * Specifies how many avatars should be visible. + * If more assignees passed, then badge with number of assignees will be shown instead. + */ + maxVisibleAvatars?: number; +} + +/** + * Displays users avatars + */ +export const UsersAvatarsPanel: FC = memo( + ({ userProfiles, maxVisibleAvatars }) => { + if (maxVisibleAvatars && userProfiles.length > maxVisibleAvatars) { + return ( + ( +
    {user ? user.user.email ?? user.user.username : UNKNOWN_USER_PROFILE_NAME}
    + ))} + repositionOnScroll={true} + > + + {userProfiles.length} + +
    + ); + } + + return ( + + {userProfiles.map((user, index) => ( + + + + ))} + + ); + } +); + +UsersAvatarsPanel.displayName = 'UsersAvatarsPanel'; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.test.tsx index aa168343cdb9..924b1158593a 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.test.tsx @@ -101,6 +101,7 @@ describe('VisualizationActions', () => { .fn() .mockReturnValue({ open: mockGetCreateCaseFlyoutOpen }), }, + helpers: { canUseCases: jest.fn().mockReturnValue(allCasesPermissions()) }, }, application: { capabilities: { [CASES_FEATURE_ID]: allCasesCapabilities() }, diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.tsx index 0825aacfee41..5527e0eca44d 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/actions.tsx @@ -10,6 +10,7 @@ import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/publ import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; +import type { LensEmbeddableInput } from '@kbn/lens-plugin/public'; import { InputsModelId } from '../../store/inputs/constants'; import { useKibana } from '../../lib/kibana/kibana_react'; import { ModalInspectQuery } from '../inspect/modal'; @@ -18,6 +19,7 @@ import { useInspect } from '../inspect/use_inspect'; import { useLensAttributes } from './use_lens_attributes'; import { useAddToExistingCase } from './use_add_to_existing_case'; import { useAddToNewCase } from './use_add_to_new_case'; +import { useSaveToLibrary } from './use_save_to_library'; import type { VisualizationActionsProps } from './types'; import { ADD_TO_EXISTING_CASE, @@ -25,9 +27,11 @@ import { INSPECT, MORE_ACTIONS, OPEN_IN_LENS, + ADDED_TO_LIBRARY, } from './translations'; import { VISUALIZATION_ACTIONS_BUTTON_CLASS } from './utils'; import { SourcererScopeName } from '../../store/sourcerer/model'; +import { useAppToasts } from '../../hooks/use_app_toasts'; const Wrapper = styled.div` &.viz-actions { @@ -62,9 +66,19 @@ const VisualizationActionsComponent: React.FC = ({ }) => { const { lens } = useKibana().services; - const { canUseEditor, navigateToPrefilledEditor } = lens; + const { canUseEditor, navigateToPrefilledEditor, SaveModalComponent } = lens; const [isPopoverOpen, setPopover] = useState(false); const [isInspectModalOpen, setIsInspectModalOpen] = useState(false); + const [isSaveModalVisible, setIsSaveModalVisible] = useState(false); + const { addSuccess } = useAppToasts(); + const onSave = useCallback(() => { + setIsSaveModalVisible(false); + addSuccess(ADDED_TO_LIBRARY); + }, [addSuccess]); + const onClose = useCallback(() => { + setIsSaveModalVisible(false); + }, []); + const hasPermission = canUseEditor(); const onButtonClick = useCallback(() => { setPopover(!isPopoverOpen); @@ -116,6 +130,10 @@ const VisualizationActionsComponent: React.FC = ({ ); }, [attributes, navigateToPrefilledEditor, timerange]); + const { openSaveVisualizationFlyout, disableVisualizations } = useSaveToLibrary({ + attributes, + }); + const onOpenInspectModal = useCallback(() => { closePopover(); setIsInspectModalOpen(true); @@ -146,11 +164,6 @@ const VisualizationActionsComponent: React.FC = ({ queryId, }); - const disabledOpenInLens = useMemo( - () => !canUseEditor() || attributes == null, - [attributes, canUseEditor] - ); - const items = useMemo(() => { const context = {} as ActionExecutionContext; const extraActionsItems = @@ -197,11 +210,24 @@ const VisualizationActionsComponent: React.FC = ({ > {ADD_TO_EXISTING_CASE} , + ...(hasPermission + ? [ + + {ADDED_TO_LIBRARY} + , + ] + : []), {OPEN_IN_LENS} @@ -210,8 +236,9 @@ const VisualizationActionsComponent: React.FC = ({ : []), ]; }, [ + hasPermission, disableInspectButton, - disabledOpenInLens, + disableVisualizations, extraActions, handleInspectButtonClick, isAddToExistingCaseDisabled, @@ -219,6 +246,7 @@ const VisualizationActionsComponent: React.FC = ({ onAddToExistingCaseClicked, onAddToNewCaseClicked, onOpenInLens, + openSaveVisualizationFlyout, withDefaultActions, ]); @@ -261,6 +289,13 @@ const VisualizationActionsComponent: React.FC = ({ title={inspectTitle} /> )} + {isSaveModalVisible && hasPermission && ( + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.ts index a444d479d2ba..013a05c840fb 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/authentication.ts @@ -6,8 +6,8 @@ */ import { - AUTHENCICATION_FAILURE_CHART_LABEL, - AUTHENCICATION_SUCCESS_CHART_LABEL, + AUTHENTICATION_FAILURE_CHART_LABEL, + AUTHENTICATION_SUCCESS_CHART_LABEL, } from '../../translations'; import type { LensAttributes } from '../../types'; @@ -115,7 +115,7 @@ export const authenticationLensAttributes: LensAttributes = { }, }, '5417777d-d9d9-4268-9cdc-eb29b873bd65': { - label: AUTHENCICATION_SUCCESS_CHART_LABEL, + label: AUTHENTICATION_SUCCESS_CHART_LABEL, dataType: 'number', operationType: 'count', isBucketed: false, @@ -148,7 +148,7 @@ export const authenticationLensAttributes: LensAttributes = { }, }, 'a3bf9dc1-c8d2-42d6-9e60-31892a4c509e': { - label: AUTHENCICATION_FAILURE_CHART_LABEL, + label: AUTHENTICATION_FAILURE_CHART_LABEL, dataType: 'number', operationType: 'count', isBucketed: false, diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/__snapshots__/risk_score_summary.test.ts.snap b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/__snapshots__/risk_score_summary.test.ts.snap new file mode 100644 index 000000000000..225ff3ef8c7a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/__snapshots__/risk_score_summary.test.ts.snap @@ -0,0 +1,180 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getRiskScoreSummaryAttributes should render 1`] = ` +Object { + "description": "", + "references": Array [], + "state": Object { + "adHocDataViews": Object { + "2cc5663b-f062-43f8-8688-fc8166c2ca8e": Object { + "allowNoIndex": false, + "fieldAttrs": Object {}, + "fieldFormats": Object {}, + "id": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "name": "risk-score.risk-score-default", + "runtimeFieldMap": Object {}, + "sourceFilters": Array [], + "timeFieldName": "@timestamp", + "title": "risk-score.risk-score-default", + }, + }, + "datasourceStates": Object { + "formBased": Object { + "layers": Object { + "2cc5663b-f062-43f8-8688-fc8166c2ca8e": Object { + "columnOrder": Array [ + "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + ], + "columns": Object { + "2cc5663b-f062-43f8-8688-fc8166c2ca8e": Object { + "customLabel": true, + "dataType": "number", + "filter": Object { + "language": "kuery", + "query": "", + }, + "isBucketed": false, + "label": "Risk value", + "operationType": "last_value", + "params": Object { + "format": Object { + "id": "number", + "params": Object { + "compact": false, + "decimals": 0, + }, + }, + "sortField": "@timestamp", + }, + "reducedTimeRange": "", + "scale": "ratio", + "sourceField": "user.risk.calculated_score_norm", + "timeShift": "", + }, + }, + "ignoreGlobalFilters": false, + "incompleteColumns": Object {}, + "linkToLayers": Array [ + "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + ], + "sampling": 1, + }, + }, + }, + "indexpattern": Object { + "layers": Object {}, + }, + "textBased": Object { + "layers": Object {}, + }, + }, + "filters": Array [ + Object { + "meta": Object { + "alias": null, + "disabled": false, + "key": "host.id", + "negate": false, + "params": Object { + "query": "123", + }, + "type": "phrase", + }, + "query": Object { + "match_phrase": Object { + "host.id": "123", + }, + }, + }, + ], + "internalReferences": Array [ + Object { + "id": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "name": "indexpattern-datasource-layer-2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "type": "index-pattern", + }, + Object { + "id": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "name": "indexpattern-datasource-layer-2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "type": "index-pattern", + }, + ], + "query": Object { + "language": "kql", + "query": "host.name: *", + }, + "visualization": Object { + "layerId": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "layerType": "data", + "metricAccessor": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "palette": Object { + "name": "custom", + "params": Object { + "colorStops": Array [ + Object { + "color": "#98a2b3", + "stop": 0, + }, + Object { + "color": "#54B399", + "stop": 20, + }, + Object { + "color": "#D6BF57", + "stop": 40, + }, + Object { + "color": "#DA8B45", + "stop": 70, + }, + Object { + "color": "#E7664C", + "stop": 90, + }, + ], + "continuity": "above", + "maxSteps": 5, + "name": "custom", + "progression": "fixed", + "rangeMax": null, + "rangeMin": 0, + "rangeType": "number", + "reverse": false, + "steps": 3, + "stops": Array [ + Object { + "color": "#98a2b3", + "stop": 20, + }, + Object { + "color": "#54B399", + "stop": 40, + }, + Object { + "color": "#D6BF57", + "stop": 70, + }, + Object { + "color": "#DA8B45", + "stop": 90, + }, + Object { + "color": "#E7664C", + "stop": 100, + }, + ], + }, + "type": "palette", + }, + "subtitle": "Low", + "trendlineLayerId": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "trendlineLayerType": "metricTrendline", + "trendlineMetricAccessor": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + "trendlineTimeAccessor": "2cc5663b-f062-43f8-8688-fc8166c2ca8e", + }, + }, + "title": "Risk score summary", + "visualizationType": "lnsMetric", +} +`; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.test.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.test.ts new file mode 100644 index 000000000000..4e3aaa69129f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RiskScoreEntity } from '../../../../../../../common/risk_engine'; +import { renderHook } from '@testing-library/react-hooks'; +import { wrapper } from '../../../mocks'; +import { useLensAttributes } from '../../../use_lens_attributes'; +import { getRiskScoreSummaryAttributes } from './risk_score_summary'; +import { RiskSeverity } from '../../../../../../../common/search_strategy'; +import type { MetricVisualizationState } from '@kbn/lens-plugin/public'; + +jest.mock('../../../../../containers/sourcerer', () => ({ + useSourcererDataView: jest.fn().mockReturnValue({ + selectedPatterns: ['auditbeat-mytest-*'], + dataViewId: 'security-solution-my-test', + indicesExist: true, + }), +})); + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('2cc5663b-f062-43f8-8688-fc8166c2ca8e'), +})); + +describe('getRiskScoreSummaryAttributes', () => { + it('should render', () => { + const { result } = renderHook( + () => + useLensAttributes({ + lensAttributes: getRiskScoreSummaryAttributes({ + severity: RiskSeverity.low, + query: `user.name: test.user`, + spaceId: 'default', + riskEntity: RiskScoreEntity.user, + }), + }), + { wrapper } + ); + + expect(result?.current).toMatchSnapshot(); + }); + + it('renders the subtitle', () => { + const { result } = renderHook( + () => + useLensAttributes({ + lensAttributes: getRiskScoreSummaryAttributes({ + severity: RiskSeverity.low, + query: `user.name: test.user`, + spaceId: 'default', + riskEntity: RiskScoreEntity.user, + }), + }), + { wrapper } + ); + + expect((result?.current?.state.visualization as MetricVisualizationState).subtitle).toBe('Low'); + }); + + it('renders the query when applyGlobalQueriesAndFilters is false', () => { + const query = `test.field: test.user`; + + const { result } = renderHook( + () => + useLensAttributes({ + lensAttributes: getRiskScoreSummaryAttributes({ + severity: RiskSeverity.low, + query, + spaceId: 'default', + riskEntity: RiskScoreEntity.user, + }), + applyGlobalQueriesAndFilters: false, + }), + { wrapper } + ); + + expect(result?.current?.state.query.query).toBe(query); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.ts new file mode 100644 index 000000000000..728c6e177137 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary.ts @@ -0,0 +1,193 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { v4 as uuidv4 } from 'uuid'; +import { + SEVERITY_UI_SORT_ORDER, + RISK_SEVERITY_COLOUR, + RISK_SCORE_RANGES, +} from '../../../../../../entity_analytics/common/utils'; +import type { RiskSeverity } from '../../../../../../../common/search_strategy'; +import { RiskScoreEntity, RiskScoreFields } from '../../../../../../../common/search_strategy'; +import type { LensAttributes } from '../../../types'; + +interface GetRiskScoreSummaryAttributesProps { + query?: string; + spaceId?: string; + severity?: RiskSeverity; + riskEntity: RiskScoreEntity; +} + +export const getRiskScoreSummaryAttributes: ( + props: GetRiskScoreSummaryAttributesProps +) => LensAttributes = ({ spaceId, query, severity, riskEntity }) => { + const layerIds = [uuidv4(), uuidv4()]; + const internalReferenceId = uuidv4(); + const columnIds = [uuidv4(), uuidv4(), uuidv4()]; + const sourceField = + riskEntity === RiskScoreEntity.user + ? RiskScoreFields.userRiskScore + : RiskScoreFields.hostRiskScore; + + return { + title: 'Risk score summary', + description: '', + visualizationType: 'lnsMetric', + state: { + visualization: { + layerId: layerIds[0], + layerType: 'data', + metricAccessor: columnIds[0], + trendlineLayerId: layerIds[1], + trendlineLayerType: 'metricTrendline', + trendlineTimeAccessor: columnIds[1], + trendlineMetricAccessor: columnIds[2], + palette: { + type: 'palette', + name: 'custom', + params: { + steps: 3, + name: 'custom', + reverse: false, + rangeType: 'number', + rangeMin: 0, + rangeMax: null, + progression: 'fixed', + colorStops: SEVERITY_UI_SORT_ORDER.map((riskSeverity) => ({ + color: RISK_SEVERITY_COLOUR[riskSeverity], + stop: RISK_SCORE_RANGES[riskSeverity].start, + })), + stops: SEVERITY_UI_SORT_ORDER.map((riskSeverity) => ({ + color: RISK_SEVERITY_COLOUR[riskSeverity], + stop: RISK_SCORE_RANGES[riskSeverity].stop, + })), + continuity: 'above', + maxSteps: 5, + }, + }, + subtitle: severity, + }, + query: { + query: query ?? '', + language: 'kuery', + }, + filters: [], + datasourceStates: { + formBased: { + layers: { + [layerIds[0]]: { + columns: { + [columnIds[0]]: { + label: 'Risk', + dataType: 'number', + operationType: 'max', + isBucketed: false, + scale: 'ratio', + sourceField, + reducedTimeRange: '', + params: { + sortField: '@timestamp', + format: { + id: 'number', + params: { + decimals: 0, + compact: false, + }, + }, + emptyAsNull: true, + }, + customLabel: true, + }, + }, + columnOrder: [columnIds[0]], + incompleteColumns: {}, + }, + [layerIds[1]]: { + linkToLayers: [layerIds[0]], + columns: { + [columnIds[1]]: { + label: '@timestamp', + dataType: 'date', + operationType: 'date_histogram', + sourceField: RiskScoreFields.timestamp, + isBucketed: true, + scale: 'interval', + params: { + interval: 'auto', + includeEmptyRows: true, + dropPartials: false, + }, + }, + [columnIds[2]]: { + label: 'Risk value', + dataType: 'number', + operationType: 'last_value', + isBucketed: false, + scale: 'ratio', + sourceField, + filter: { + query: '', + language: 'kuery', + }, + timeShift: '', + reducedTimeRange: '', + params: { + sortField: '@timestamp', + format: { + id: 'number', + params: { + decimals: 0, + compact: false, + }, + }, + }, + customLabel: true, + }, + }, + columnOrder: [columnIds[1], columnIds[2]], + sampling: 1, + ignoreGlobalFilters: false, + incompleteColumns: {}, + }, + }, + }, + indexpattern: { + layers: {}, + }, + textBased: { + layers: {}, + }, + }, + internalReferences: [ + { + type: 'index-pattern', + id: internalReferenceId, + name: `indexpattern-datasource-layer-${layerIds[0]}`, + }, + { + type: 'index-pattern', + id: internalReferenceId, + name: `indexpattern-datasource-layer-${layerIds[1]}`, + }, + ], + adHocDataViews: { + [internalReferenceId]: { + id: internalReferenceId, + title: `risk-score.risk-score-${spaceId ?? 'default'}`, + timeFieldName: '@timestamp', + sourceFilters: [], + fieldFormats: {}, + runtimeFieldMap: {}, + fieldAttrs: {}, + allowNoIndex: false, + name: `risk-score.risk-score-${spaceId ?? 'default'}`, + }, + }, + }, + references: [], + }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx index df564277122c..fdaa006e15f5 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx @@ -14,7 +14,7 @@ import styled from 'styled-components'; import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import type { RangeFilterParams } from '@kbn/es-query'; import type { ClickTriggerEvent, MultiClickTriggerEvent } from '@kbn/charts-plugin/public'; -import type { XYState } from '@kbn/lens-plugin/public'; +import type { EmbeddableComponentProps, XYState } from '@kbn/lens-plugin/public'; import { setAbsoluteRangeDatePicker } from '../../store/inputs/actions'; import { useKibana } from '../../lib/kibana'; import { useLensAttributes } from './use_lens_attributes'; @@ -24,7 +24,7 @@ import { inputsSelectors } from '../../store'; import { useDeepEqualSelector } from '../../hooks/use_selector'; import { ModalInspectQuery } from '../inspect/modal'; import { InputsModelId } from '../../store/inputs/constants'; -import { getRequestsAndResponses, showLegendActionsByActionId } from './utils'; +import { getRequestsAndResponses } from './utils'; import { SourcererScopeName } from '../../store/sourcerer/model'; import { VisualizationActions } from './actions'; @@ -81,6 +81,7 @@ const LensEmbeddableComponent: React.FC = ({ timerange, width: wrapperWidth, withActions = true, + disableOnClickFilter = false, }) => { const style = useMemo( () => ({ @@ -185,9 +186,10 @@ const LensEmbeddableComponent: React.FC = ({ [onLoad] ); - const onFilterCallback = useCallback( - async (e: ClickTriggerEvent['data'] | MultiClickTriggerEvent['data']) => { - if (!isClickTriggerEvent(e) || preferredSeriesType !== 'area') { + const onFilterCallback = useCallback(() => { + const callback: EmbeddableComponentProps['onFilter'] = async (e) => { + if (!isClickTriggerEvent(e) || preferredSeriesType !== 'area' || disableOnClickFilter) { + e.preventDefault(); return; } // Update timerange when clicking on a dot in an area chart @@ -201,9 +203,14 @@ const LensEmbeddableComponent: React.FC = ({ range: [rangeFilter.gte, rangeFilter.lt], }); } - }, - [createFiltersFromValueClickAction, updateDateRange, preferredSeriesType] - ); + }; + return callback; + }, [ + createFiltersFromValueClickAction, + updateDateRange, + preferredSeriesType, + disableOnClickFilter, + ]); const adHocDataViews = useMemo( () => @@ -218,11 +225,6 @@ const LensEmbeddableComponent: React.FC = ({ [attributes?.state?.adHocDataViews] ); - const shouldShowLegendAction = useCallback( - (actionId: string) => showLegendActionsByActionId({ actionId, scopeId }), - [scopeId] - ); - if (!searchSessionId) { return null; } @@ -286,7 +288,6 @@ const LensEmbeddableComponent: React.FC = ({ showInspector={false} syncTooltips={false} syncCursor={false} - shouldShowLegendAction={shouldShowLegendAction} /> )} diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/translations.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/translations.ts index 8f21d61bc869..2e6e6d2b8f3e 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/translations.ts @@ -67,7 +67,7 @@ export const SUCCESS_CHART_LABEL = i18n.translate( } ); -export const AUTHENCICATION_SUCCESS_CHART_LABEL = i18n.translate( +export const AUTHENTICATION_SUCCESS_CHART_LABEL = i18n.translate( 'xpack.securitySolution.visualizationActions.userAuthentications.authentication.successChartLabel', { defaultMessage: 'Success', @@ -81,7 +81,7 @@ export const FAIL_CHART_LABEL = i18n.translate( } ); -export const AUTHENCICATION_FAILURE_CHART_LABEL = i18n.translate( +export const AUTHENTICATION_FAILURE_CHART_LABEL = i18n.translate( 'xpack.securitySolution.visualizationActions.userAuthentications.authentication.failureChartLabel', { defaultMessage: 'Failure', @@ -111,3 +111,10 @@ export const COUNT_OF = (field: string) => values: { field }, defaultMessage: 'Count of {field}', }); + +export const ADDED_TO_LIBRARY = i18n.translate( + 'xpack.securitySolution.visualizationActions.addedToLibrary', + { + defaultMessage: 'Added to library', + } +); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/types.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/types.ts index 854aff1860a2..6f513e445660 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/types.ts @@ -79,6 +79,10 @@ export interface LensEmbeddableComponentProps { timerange: { from: string; to: string }; width?: string | number; withActions?: boolean; + /** + * Disable the on click filter for the visualization. + */ + disableOnClickFilter?: boolean; } export enum RequestStatus { diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.test.tsx index 0de49b52d66f..273e4d89d1d7 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.test.tsx @@ -6,9 +6,13 @@ */ import { renderHook } from '@testing-library/react-hooks'; +import React from 'react'; +import { NavigationProvider } from '@kbn/security-solution-navigation'; import { useKibana } from '../../lib/kibana/kibana_react'; import { mockAttributes } from './mocks'; import { useActions } from './use_actions'; +import { coreMock } from '@kbn/core/public/mocks'; +import { TestProviders } from '../../mock'; jest.mock('./use_add_to_existing_case', () => { return { @@ -32,6 +36,12 @@ jest.mock('../../lib/kibana/kibana_react', () => { }; }); +const coreStart = coreMock.createStart(); +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); describe(`useActions`, () => { const mockNavigateToPrefilledEditor = jest.fn(); beforeAll(() => { @@ -39,6 +49,15 @@ describe(`useActions`, () => { services: { lens: { navigateToPrefilledEditor: mockNavigateToPrefilledEditor, + canUseEditor: jest.fn().mockReturnValue(true), + SaveModalComponent: jest + .fn() + .mockReturnValue(() =>
    ), + }, + notifications: { + toasts: { + addWarning: jest.fn(), + }, }, }, }); @@ -49,29 +68,34 @@ describe(`useActions`, () => { }); it('should render actions', () => { - const { result } = renderHook(() => - useActions({ - withActions: true, - attributes: mockAttributes, - timeRange: { - from: '2022-10-26T23:00:00.000Z', - to: '2022-11-03T15:16:50.053Z', - }, - inspectActionProps: { - onInspectActionClicked: jest.fn(), - isDisabled: false, - }, - }) + const { result } = renderHook( + () => + useActions({ + withActions: true, + attributes: mockAttributes, + timeRange: { + from: '2022-10-26T23:00:00.000Z', + to: '2022-11-03T15:16:50.053Z', + }, + inspectActionProps: { + onInspectActionClicked: jest.fn(), + isDisabled: false, + }, + }), + { + wrapper, + } ); - expect(result.current[0].id).toEqual('inspect'); expect(result.current[0].order).toEqual(4); expect(result.current[1].id).toEqual('addToNewCase'); expect(result.current[1].order).toEqual(3); expect(result.current[2].id).toEqual('addToExistingCase'); expect(result.current[2].order).toEqual(2); - expect(result.current[3].id).toEqual('openInLens'); + expect(result.current[3].id).toEqual('saveToLibrary'); expect(result.current[3].order).toEqual(1); + expect(result.current[4].id).toEqual('openInLens'); + expect(result.current[4].order).toEqual(0); }); it('should render extra actions if available', () => { @@ -92,31 +116,37 @@ describe(`useActions`, () => { order: 0, }, ]; - const { result } = renderHook(() => - useActions({ - withActions: true, - attributes: mockAttributes, - timeRange: { - from: '2022-10-26T23:00:00.000Z', - to: '2022-11-03T15:16:50.053Z', - }, - inspectActionProps: { - onInspectActionClicked: jest.fn(), - isDisabled: false, - }, - extraActions: mockExtraAction, - }) + const { result } = renderHook( + () => + useActions({ + withActions: true, + attributes: mockAttributes, + timeRange: { + from: '2022-10-26T23:00:00.000Z', + to: '2022-11-03T15:16:50.053Z', + }, + inspectActionProps: { + onInspectActionClicked: jest.fn(), + isDisabled: false, + }, + extraActions: mockExtraAction, + }), + { + wrapper, + } ); expect(result.current[0].id).toEqual('inspect'); - expect(result.current[0].order).toEqual(4); + expect(result.current[0].order).toEqual(5); expect(result.current[1].id).toEqual('addToNewCase'); - expect(result.current[1].order).toEqual(3); + expect(result.current[1].order).toEqual(4); expect(result.current[2].id).toEqual('addToExistingCase'); - expect(result.current[2].order).toEqual(2); - expect(result.current[3].id).toEqual('openInLens'); - expect(result.current[3].order).toEqual(1); - expect(result.current[4].id).toEqual('mockExtraAction'); - expect(result.current[4].order).toEqual(0); + expect(result.current[2].order).toEqual(3); + expect(result.current[3].id).toEqual('saveToLibrary'); + expect(result.current[3].order).toEqual(2); + expect(result.current[4].id).toEqual('openInLens'); + expect(result.current[4].order).toEqual(1); + expect(result.current[5].id).toEqual('mockExtraAction'); + expect(result.current[5].order).toEqual(0); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.ts index 08f8cd63f767..760d9e396584 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_actions.ts @@ -10,8 +10,14 @@ import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/publ import { useKibana } from '../../lib/kibana/kibana_react'; import { useAddToExistingCase } from './use_add_to_existing_case'; import { useAddToNewCase } from './use_add_to_new_case'; +import { useSaveToLibrary } from './use_save_to_library'; -import { ADD_TO_EXISTING_CASE, ADD_TO_NEW_CASE, OPEN_IN_LENS } from './translations'; +import { + ADDED_TO_LIBRARY, + ADD_TO_EXISTING_CASE, + ADD_TO_NEW_CASE, + OPEN_IN_LENS, +} from './translations'; import type { LensAttributes } from './types'; import { INSPECT } from '../inspect/translations'; @@ -36,6 +42,7 @@ export const useActions = ({ 'inspect', 'addToNewCase', 'addToExistingCase', + 'saveToLibrary', 'openInLens', ]); @@ -72,6 +79,7 @@ export const useActions = ({ lensAttributes: attributes, }); + const { openSaveVisualizationFlyout, disableVisualizations } = useSaveToLibrary({ attributes }); const actions = useMemo( () => defaultActions?.reduce((acc, action) => { @@ -106,6 +114,16 @@ export const useActions = ({ return [...acc, getOpenInLensAction({ callback: onOpenInLens })]; } + if (action === 'saveToLibrary') { + return [ + ...acc, + getSaveToLibraryAction({ + callback: openSaveVisualizationFlyout, + disabled: disableVisualizations, + }), + ]; + } + return acc; }, []), [ @@ -116,10 +134,18 @@ export const useActions = ({ onAddToNewCaseClicked, isAddToNewCaseDisabled, onOpenInLens, + openSaveVisualizationFlyout, + disableVisualizations, ] ); - const withExtraActions = actions.concat(extraActions ?? []); + const withExtraActions = actions.concat(extraActions ?? []).map((a, i, totalActions) => { + const order = Math.max(totalActions.length - (1 + i), 0); + return { + ...a, + order, + }; + }); return withExtraActions; }; @@ -141,11 +167,38 @@ const getOpenInLensAction = ({ callback }: { callback: () => void }): Action => async execute(context: ActionExecutionContext): Promise { callback(); }, + order: 0, + }; +}; + +const getSaveToLibraryAction = ({ + callback, + disabled, +}: { + callback: () => void; + disabled?: boolean; +}): Action => { + return { + id: 'saveToLibrary', + getDisplayName(context: ActionExecutionContext): string { + return ADDED_TO_LIBRARY; + }, + getIconType(context: ActionExecutionContext): string | undefined { + return 'save'; + }, + type: 'actionButton', + async isCompatible(context: ActionExecutionContext): Promise { + return true; + }, + async execute(context: ActionExecutionContext): Promise { + callback(); + }, + disabled, order: 1, }; }; -const getAddToNewCaseAction = ({ +const getAddToExistingCaseAction = ({ callback, disabled, }: { @@ -153,9 +206,9 @@ const getAddToNewCaseAction = ({ disabled?: boolean; }): Action => { return { - id: 'addToNewCase', + id: 'addToExistingCase', getDisplayName(context: ActionExecutionContext): string { - return ADD_TO_NEW_CASE; + return ADD_TO_EXISTING_CASE; }, getIconType(context: ActionExecutionContext): string | undefined { return 'casesApp'; @@ -168,11 +221,11 @@ const getAddToNewCaseAction = ({ callback(); }, disabled, - order: 3, + order: 2, }; }; -const getInspectAction = ({ +const getAddToNewCaseAction = ({ callback, disabled, }: { @@ -180,12 +233,12 @@ const getInspectAction = ({ disabled?: boolean; }): Action => { return { - id: 'inspect', + id: 'addToNewCase', getDisplayName(context: ActionExecutionContext): string { - return INSPECT; + return ADD_TO_NEW_CASE; }, getIconType(context: ActionExecutionContext): string | undefined { - return 'inspect'; + return 'casesApp'; }, type: 'actionButton', async isCompatible(context: ActionExecutionContext): Promise { @@ -195,11 +248,11 @@ const getInspectAction = ({ callback(); }, disabled, - order: 4, + order: 3, }; }; -const getAddToExistingCaseAction = ({ +const getInspectAction = ({ callback, disabled, }: { @@ -207,12 +260,12 @@ const getAddToExistingCaseAction = ({ disabled?: boolean; }): Action => { return { - id: 'addToExistingCase', + id: 'inspect', getDisplayName(context: ActionExecutionContext): string { - return ADD_TO_EXISTING_CASE; + return INSPECT; }, getIconType(context: ActionExecutionContext): string | undefined { - return 'casesApp'; + return 'inspect'; }, type: 'actionButton', async isCompatible(context: ActionExecutionContext): Promise { @@ -222,6 +275,6 @@ const getAddToExistingCaseAction = ({ callback(); }, disabled, - order: 2, + order: 4, }; }; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.test.tsx index 6118bc444142..cc03f80daf95 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.test.tsx @@ -8,7 +8,6 @@ import { renderHook } from '@testing-library/react-hooks'; import { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__'; import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric'; import { useAddToExistingCase } from './use_add_to_existing_case'; -import { useGetUserCasesPermissions } from '../../lib/kibana'; import { allCasesPermissions, readCasesPermissions, @@ -18,13 +17,13 @@ import { AttachmentType } from '@kbn/cases-plugin/common'; const mockedUseKibana = mockUseKibana(); const mockGetUseCasesAddToExistingCaseModal = jest.fn(); +const mockCanUseCases = jest.fn(); jest.mock('../../lib/kibana', () => { const original = jest.requireActual('../../lib/kibana'); return { ...original, - useGetUserCasesPermissions: jest.fn(), useKibana: () => ({ ...mockedUseKibana, services: { @@ -33,6 +32,7 @@ jest.mock('../../lib/kibana', () => { hooks: { useCasesAddToExistingCaseModal: mockGetUseCasesAddToExistingCaseModal, }, + helpers: { canUseCases: mockCanUseCases }, }, }, }), @@ -47,7 +47,7 @@ describe('useAddToExistingCase', () => { }; beforeEach(() => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions()); + mockCanUseCases.mockReturnValue(allCasesPermissions()); }); it('useCasesAddToExistingCaseModal with attachments', () => { @@ -68,7 +68,7 @@ describe('useAddToExistingCase', () => { }); it("disables the button if the user can't create but can read", () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions()); + mockCanUseCases.mockReturnValue(readCasesPermissions()); const { result } = renderHook(() => useAddToExistingCase({ @@ -81,7 +81,7 @@ describe('useAddToExistingCase', () => { }); it("disables the button if the user can't read but can create", () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(writeCasesPermissions()); + mockCanUseCases.mockReturnValue(writeCasesPermissions()); const { result } = renderHook(() => useAddToExistingCase({ diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.tsx index 9a9c239c65e9..8f28e9534e6a 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_existing_case.tsx @@ -8,7 +8,8 @@ import { useCallback, useMemo } from 'react'; import { AttachmentType, LENS_ATTACHMENT_TYPE } from '@kbn/cases-plugin/common'; import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public'; -import { useKibana, useGetUserCasesPermissions } from '../../lib/kibana'; +import { APP_ID } from '../../../../common'; +import { useKibana } from '../../lib/kibana'; import { ADD_TO_CASE_SUCCESS } from './translations'; import type { LensAttributes } from './types'; @@ -21,8 +22,8 @@ export const useAddToExistingCase = ({ lensAttributes: LensAttributes | null; timeRange: { from: string; to: string } | null; }) => { - const userCasesPermissions = useGetUserCasesPermissions(); const { cases } = useKibana().services; + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const attachments = useMemo(() => { return [ { diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.test.tsx index 29969d489a03..91347dc9fe07 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.test.tsx @@ -8,7 +8,6 @@ import { renderHook } from '@testing-library/react-hooks'; import { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__'; import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric'; import { useAddToNewCase } from './use_add_to_new_case'; -import { useGetUserCasesPermissions } from '../../lib/kibana'; import { allCasesPermissions, readCasesPermissions, @@ -20,13 +19,13 @@ jest.mock('../../lib/kibana/kibana_react'); const mockedUseKibana = mockUseKibana(); const mockGetUseCasesAddToNewCaseFlyout = jest.fn(); +const mockCanUseCases = jest.fn(); jest.mock('../../lib/kibana', () => { const original = jest.requireActual('../../lib/kibana'); return { ...original, - useGetUserCasesPermissions: jest.fn(), useKibana: () => ({ ...mockedUseKibana, services: { @@ -35,6 +34,7 @@ jest.mock('../../lib/kibana', () => { hooks: { useCasesAddToNewCaseFlyout: mockGetUseCasesAddToNewCaseFlyout, }, + helpers: { canUseCases: mockCanUseCases }, }, }, }), @@ -47,7 +47,7 @@ describe('useAddToNewCase', () => { to: '2022-03-07T15:59:59.999Z', }; beforeEach(() => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions()); + mockCanUseCases.mockReturnValue(allCasesPermissions()); }); it('useCasesAddToNewCaseFlyout with attachments', () => { @@ -64,7 +64,7 @@ describe('useAddToNewCase', () => { }); it("disables the button if the user can't create but can read", () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions()); + mockCanUseCases.mockReturnValue(readCasesPermissions()); const { result } = renderHook(() => useAddToNewCase({ @@ -76,7 +76,7 @@ describe('useAddToNewCase', () => { }); it("disables the button if the user can't read but can create", () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(writeCasesPermissions()); + mockCanUseCases.mockReturnValue(writeCasesPermissions()); const { result } = renderHook(() => useAddToNewCase({ diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.tsx index 6a395af34b44..68f730b376dc 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_add_to_new_case.tsx @@ -8,7 +8,8 @@ import { useCallback, useMemo } from 'react'; import { AttachmentType, LENS_ATTACHMENT_TYPE } from '@kbn/cases-plugin/common'; import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public'; -import { useKibana, useGetUserCasesPermissions } from '../../lib/kibana'; +import { APP_ID } from '../../../../common'; +import { useKibana } from '../../lib/kibana'; import { ADD_TO_CASE_SUCCESS } from './translations'; import type { LensAttributes } from './types'; @@ -20,8 +21,9 @@ export interface UseAddToNewCaseProps { } export const useAddToNewCase = ({ onClick, timeRange, lensAttributes }: UseAddToNewCaseProps) => { - const userCasesPermissions = useGetUserCasesPermissions(); const { cases } = useKibana().services; + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); + const attachments = useMemo(() => { return [ { diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_redirect_to_dashboard_from_lens.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_redirect_to_dashboard_from_lens.ts new file mode 100644 index 000000000000..1aebf72217c5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_redirect_to_dashboard_from_lens.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo, useCallback } from 'react'; +import { SecurityPageName } from '../../../../common'; +import { useNavigateTo } from '../../lib/kibana'; +import type { GetSecuritySolutionUrl } from '../link_to'; + +export const useRedirectToDashboardFromLens = ({ + getSecuritySolutionUrl, +}: { + getSecuritySolutionUrl: GetSecuritySolutionUrl; +}) => { + const { navigateTo } = useNavigateTo(); + + const dashboardListingUrl = useMemo( + () => + `${getSecuritySolutionUrl({ + deepLinkId: SecurityPageName.dashboards, + })}`, + [getSecuritySolutionUrl] + ); + + const getEditOrCreateDashboardPath = useCallback( + (id: string | null | undefined) => (id != null && id !== 'new' ? `${id}/edit` : `/create`), + [] + ); + const getEditOrCreateDashboardUrl = useCallback( + (id: string | null | undefined) => + `${getSecuritySolutionUrl({ + deepLinkId: SecurityPageName.dashboards, + path: getEditOrCreateDashboardPath(id), + })}`, + [getEditOrCreateDashboardPath, getSecuritySolutionUrl] + ); + + const redirectTo = useCallback( + (props) => { + if (props.destination === 'listing') { + navigateTo({ url: dashboardListingUrl }); + } + if (props.destination === 'dashboard') { + navigateTo({ url: getEditOrCreateDashboardUrl(props.id) }); + } + }, + [dashboardListingUrl, getEditOrCreateDashboardUrl, navigateTo] + ); + + return { + redirectTo, + getEditOrCreateDashboardPath, + getEditOrCreateDashboardUrl, + dashboardListingUrl, + }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_save_to_library.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_save_to_library.tsx new file mode 100644 index 000000000000..158b30979881 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_save_to_library.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import type { LensEmbeddableInput } from '@kbn/lens-plugin/public'; +import { unmountComponentAtNode } from 'react-dom'; +import type { SaveProps } from '@kbn/lens-plugin/public/plugin'; +import { useKibana } from '../../lib/kibana'; +import type { LensAttributes } from './types'; +import { useRedirectToDashboardFromLens } from './use_redirect_to_dashboard_from_lens'; +import { APP_UI_ID, SecurityPageName } from '../../../../common'; +import { useGetSecuritySolutionUrl } from '../link_to'; + +export const useSaveToLibrary = ({ + attributes, +}: { + attributes: LensAttributes | undefined | null; +}) => { + const { lens, theme, i18n } = useKibana().services; + const { SaveModalComponent, canUseEditor } = lens; + const getSecuritySolutionUrl = useGetSecuritySolutionUrl(); + const { redirectTo, getEditOrCreateDashboardPath } = useRedirectToDashboardFromLens({ + getSecuritySolutionUrl, + }); + + const openSaveVisualizationFlyout = useCallback(() => { + const targetDomElement = document.createElement('div'); + const mount = toMountPoint( + { + unmountComponentAtNode(targetDomElement); + }} + onClose={() => { + unmountComponentAtNode(targetDomElement); + }} + originatingApp={APP_UI_ID} + getOriginatingPath={(dashboardId) => + `${SecurityPageName.dashboards}/${getEditOrCreateDashboardPath(dashboardId)}` + } + redirectTo={redirectTo} + />, + { theme, i18n } + ); + + mount(targetDomElement); + }, [SaveModalComponent, attributes, getEditOrCreateDashboardPath, i18n, redirectTo, theme]); + + const disableVisualizations = useMemo( + () => !canUseEditor() || attributes == null, + [attributes, canUseEditor] + ); + + return { openSaveVisualizationFlyout, disableVisualizations }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts b/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts index 678cc16c915e..ef3aa936d293 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/utils.ts @@ -8,10 +8,6 @@ import type { Filter } from '@kbn/es-query'; import { SecurityPageName } from '../../../../common/constants'; -import { HISTOGRAM_LEGEND_ACTION_FILTER_IN } from '../../../actions/filter/lens/filter_in'; -import { TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_IN } from '../../../actions/filter/lens/filter_in_timeline'; -import { HISTOGRAM_LEGEND_ACTION_FILTER_OUT } from '../../../actions/filter/lens/filter_out'; -import { TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_OUT } from '../../../actions/filter/lens/filter_out_timeline'; import type { Request } from './types'; export const VISUALIZATION_ACTIONS_BUTTON_CLASS = 'histogram-actions-trigger'; @@ -199,28 +195,3 @@ export const parseVisualizationData = (data: string[]): T[] => return acc; } }, [] as T[]); - -export const showLegendActionsByActionId = ({ - actionId, - scopeId, -}: { - actionId: string; - scopeId: string; -}) => { - switch (actionId) { - /** We no longer use Lens' default filter in / out actions - * as extra custom actions needed after filters applied. - * For example: hide the topN panel after filters applied */ - case FILTER_IN_LEGEND_ACTION: - case FILTER_OUT_LEGEND_ACTION: - return false; - case HISTOGRAM_LEGEND_ACTION_FILTER_IN: - case HISTOGRAM_LEGEND_ACTION_FILTER_OUT: - return scopeId !== 'timeline'; - case TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_IN: - case TIMELINE_HISTOGRAM_LEGEND_ACTION_FILTER_OUT: - return scopeId === 'timeline'; - default: - return true; - } -}; diff --git a/x-pack/plugins/security_solution/public/common/containers/alert_assignees/api.ts b/x-pack/plugins/security_solution/public/common/containers/alert_assignees/api.ts new file mode 100644 index 000000000000..8652a51138d6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/alert_assignees/api.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { estypes } from '@elastic/elasticsearch'; +import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL } from '../../../../common/constants'; +import type { AlertAssignees } from '../../../../common/api/detection_engine'; +import { KibanaServices } from '../../lib/kibana'; + +export const setAlertAssignees = async ({ + assignees, + ids, + signal, +}: { + assignees: AlertAssignees; + ids: string[]; + signal: AbortSignal | undefined; +}): Promise => { + return KibanaServices.get().http.fetch( + DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + { + method: 'POST', + version: '2023-10-31', + body: JSON.stringify({ assignees, ids }), + signal, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/containers/alerts/use_alerts_by_ids.ts b/x-pack/plugins/security_solution/public/common/containers/alerts/use_alerts_by_ids.ts index cb853aa9488c..1ac9948818bc 100644 --- a/x-pack/plugins/security_solution/public/common/containers/alerts/use_alerts_by_ids.ts +++ b/x-pack/plugins/security_solution/public/common/containers/alerts/use_alerts_by_ids.ts @@ -17,6 +17,8 @@ interface UseAlertByIdsOptions { interface Hit { fields: Record; + _index: string; + _id: string; } interface UserAlertByIdsResult { @@ -25,6 +27,9 @@ interface UserAlertByIdsResult { data?: Hit[]; } +// It prevents recreating the array on every hook call +const ALL_FIELD = ['*']; + /** * Fetches the alert documents associated to the ids that are passed. * By default it fetches all fields but they can be limited by passing @@ -32,7 +37,7 @@ interface UserAlertByIdsResult { */ export const useAlertsByIds = ({ alertIds, - fields = ['*'], + fields = ALL_FIELD, }: UseAlertByIdsOptions): UserAlertByIdsResult => { const [initialQuery] = useState(() => generateAlertByIdsQuery(alertIds, fields)); diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts index c16f5ebb4bae..4d6ef73c643d 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useCallback, useEffect } from 'react'; +import { safeDecode } from '@kbn/rison'; import { useDispatch } from 'react-redux'; @@ -40,5 +41,23 @@ export const useInitTimelineFromUrlParam = () => { [dispatch] ); + useEffect(() => { + const listener = () => { + const timelineState = new URLSearchParams(window.location.search).get(URL_PARAM_KEY.timeline); + + if (!timelineState) { + return; + } + + const parsedState = safeDecode(timelineState) as TimelineUrl | null; + + onInitialize(parsedState); + }; + + // This is needed to initialize the timeline from the URL when the user clicks the back / forward buttons + window.addEventListener('popstate', listener); + return () => window.removeEventListener('popstate', listener); + }, [onInitialize]); + useInitializeUrlParam(URL_PARAM_KEY.timeline, onInitialize); }; diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_contract_component.ts b/x-pack/plugins/security_solution/public/common/hooks/use_contract_component.ts new file mode 100644 index 000000000000..2ebb46db35c8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/use_contract_component.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { useKibana } from '../lib/kibana'; + +export const useContractComponents = () => { + const { getComponents$ } = useKibana().services; + const components$ = useMemo(() => getComponents$(), [getComponents$]); + return useObservable(components$, {}); +}; diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts b/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts index 30d914f5ccc8..cf5616e0c33f 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/use_url_state.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { EXPANDABLE_FLYOUT_URL_KEY } from '@kbn/expandable-flyout'; import { useSyncGlobalQueryString } from '../utils/global_query_string'; import { useInitSearchBarFromUrlParams } from './search_bar/use_init_search_bar_url_params'; import { useInitTimerangeFromUrlParam } from './search_bar/use_init_timerange_url_params'; @@ -15,9 +16,6 @@ import { useQueryTimelineByIdOnUrlChange } from './timeline/use_query_timeline_b import { useInitFlyoutFromUrlParam } from './flyout/use_init_flyout_url_param'; import { useSyncFlyoutUrlParam } from './flyout/use_sync_flyout_url_param'; -// NOTE: the expandable flyout package url state is handled here: -// x-pack/plugins/security_solution/public/flyout/url/use_sync_flyout_state_with_url.tsx - export const useUrlState = () => { useSyncGlobalQueryString(); useInitSearchBarFromUrlParams(); @@ -30,14 +28,14 @@ export const useUrlState = () => { useSyncFlyoutUrlParam(); }; -export enum URL_PARAM_KEY { - appQuery = 'query', - eventFlyout = 'eventFlyout', - filters = 'filters', - savedQuery = 'savedQuery', - sourcerer = 'sourcerer', - timeline = 'timeline', - timerange = 'timerange', - pageFilter = 'pageFilters', - rulesTable = 'rulesTable', -} +export const URL_PARAM_KEY = { + appQuery: 'query', + eventFlyout: EXPANDABLE_FLYOUT_URL_KEY, + filters: 'filters', + savedQuery: 'savedQuery', + sourcerer: 'sourcerer', + timeline: 'timeline', + timerange: 'timerange', + pageFilter: 'pageFilters', + rulesTable: 'rulesTable', +} as const; diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts index 954f4fd0b74b..a0f59fb18f3f 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts @@ -95,7 +95,6 @@ export const useToasts = jest export const useCurrentUser = jest.fn(); export const withKibana = jest.fn(createWithKibanaMock()); export const KibanaContextProvider = jest.fn(createKibanaContextProviderMock()); -export const useGetUserCasesPermissions = jest.fn(); export const useAppUrl = jest.fn().mockReturnValue({ getAppUrl: jest .fn() diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts index 043d1a0ab36f..714049872ee5 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts @@ -12,9 +12,8 @@ import { i18n } from '@kbn/i18n'; import { camelCase, isArray, isObject } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import type { Capabilities } from '@kbn/core/public'; -import type { CasesPermissions } from '@kbn/cases-plugin/common'; import { useGetAppUrl, useNavigateTo, @@ -22,11 +21,7 @@ import { type GetAppUrl, type NavigateTo, } from '@kbn/security-solution-navigation'; -import { - CASES_FEATURE_ID, - DEFAULT_DATE_FORMAT, - DEFAULT_DATE_FORMAT_TZ, -} from '../../../../common/constants'; +import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../../../../common/constants'; import { errorToToaster, useStateToaster } from '../../components/toasters'; import type { StartServices } from '../../../types'; import { useUiSetting, useKibana } from './kibana_react'; @@ -153,44 +148,6 @@ export const useCurrentUser = (): AuthenticatedElasticUser | null => { return user; }; -export const useGetUserCasesPermissions = () => { - const [casesPermissions, setCasesPermissions] = useState({ - all: false, - create: false, - read: false, - update: false, - delete: false, - push: false, - connectors: false, - }); - const uiCapabilities = useKibana().services.application.capabilities; - const casesCapabilities = useKibana().services.cases.helpers.getUICapabilities( - uiCapabilities[CASES_FEATURE_ID] - ); - - useEffect(() => { - setCasesPermissions({ - all: casesCapabilities.all, - create: casesCapabilities.create, - read: casesCapabilities.read, - update: casesCapabilities.update, - delete: casesCapabilities.delete, - push: casesCapabilities.push, - connectors: casesCapabilities.connectors, - }); - }, [ - casesCapabilities.all, - casesCapabilities.create, - casesCapabilities.read, - casesCapabilities.update, - casesCapabilities.delete, - casesCapabilities.push, - casesCapabilities.connectors, - ]); - - return casesPermissions; -}; - export const useAppUrl = useGetAppUrl; export { useNavigateTo, useNavigation }; export type { GetAppUrl, NavigateTo }; diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts index 3d6d1a7034d2..ffbd26b97028 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts @@ -117,7 +117,7 @@ export const createStartServicesMock = ( const discover = discoverPluginMock.createStartContract(); const cases = mockCasesContract(); const dataViewServiceMock = dataViewPluginMocks.createStartContract(); - cases.helpers.getUICapabilities.mockReturnValue(noCasesPermissions()); + cases.helpers.canUseCases.mockReturnValue(noCasesPermissions()); const triggersActionsUi = triggersActionsUiMock.createStart(); const cloudExperiments = cloudExperimentsMock.createStartMock(); const guidedOnboarding = guidedOnboardingMock.createStart(); diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts index fff266b8a5cd..a3d67524935c 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/services.ts @@ -9,7 +9,7 @@ import type { CoreStart } from '@kbn/core/public'; import type { StartPlugins } from '../../../types'; type GlobalServices = Pick & - Pick; + Pick; export class KibanaServices { private static buildFlavor?: string; @@ -30,6 +30,7 @@ export class KibanaServices { uiSettings, notifications, expressions, + savedSearch, }: GlobalServices & { kibanaBranch: string; kibanaVersion: string; @@ -44,6 +45,7 @@ export class KibanaServices { unifiedSearch, notifications, expressions, + savedSearch, }; this.kibanaBranch = kibanaBranch; this.kibanaVersion = kibanaVersion; diff --git a/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts index 3fefc26076a1..80cf74a8f55b 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts @@ -233,7 +233,7 @@ export const convertToBuildEsQuery = ({ export const combineQueries = ({ config, - dataProviders, + dataProviders = [], indexPattern, browserFields, filters = [], diff --git a/x-pack/plugins/security_solution/public/common/lib/triggers_actions_ui/register_alerts_table_configuration.tsx b/x-pack/plugins/security_solution/public/common/lib/triggers_actions_ui/register_alerts_table_configuration.tsx index ff75b2583226..6db7a5c814f6 100644 --- a/x-pack/plugins/security_solution/public/common/lib/triggers_actions_ui/register_alerts_table_configuration.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/triggers_actions_ui/register_alerts_table_configuration.tsx @@ -23,6 +23,7 @@ import { import { getDataTablesInStorageByIds } from '../../../timelines/containers/local_storage'; import { getColumns } from '../../../detections/configurations/security_solution_detections'; import { getRenderCellValueHook } from '../../../detections/configurations/security_solution_detections/render_cell_value'; +import { useFetchPageContext } from '../../../detections/configurations/security_solution_detections/fetch_page_context'; import { SourcererScopeName } from '../../store/sourcerer/model'; const registerAlertsTableConfiguration = ( @@ -64,6 +65,7 @@ const registerAlertsTableConfiguration = ( sort, useFieldBrowserOptions: getUseTriggersActionsFieldBrowserOptions(SourcererScopeName.detections), showInspectButton: true, + useFetchPageContext, }); // register Alert Table on RuleDetails Page @@ -79,6 +81,7 @@ const registerAlertsTableConfiguration = ( sort, useFieldBrowserOptions: getUseTriggersActionsFieldBrowserOptions(SourcererScopeName.detections), showInspectButton: true, + useFetchPageContext, }); registerIfNotAlready(registry, { @@ -91,6 +94,7 @@ const registerAlertsTableConfiguration = ( useCellActions: getUseCellActionsHook(TableId.alertsOnCasePage), sort, showInspectButton: true, + useFetchPageContext, }); registerIfNotAlready(registry, { @@ -104,6 +108,7 @@ const registerAlertsTableConfiguration = ( usePersistentControls: getPersistentControlsHook(TableId.alertsRiskInputs), sort, showInspectButton: true, + useFetchPageContext, }); }; diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index a118dfc86545..f770a26405fe 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -372,6 +372,8 @@ export const mockGlobalState: State = { itemsPerPageOptions: [10, 25, 50, 100], savedSearchId: null, isDiscoverSavedSearchLoaded: false, + savedSearch: null, + isDataProviderVisible: true, }, }, insertTimeline: null, diff --git a/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx index 479174a92722..6fb3ca1ff0f5 100644 --- a/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx @@ -14,6 +14,8 @@ import type { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; import { I18nProvider } from '@kbn/i18n-react'; import { CellActionsProvider } from '@kbn/cell-actions'; +import { NavigationProvider } from '@kbn/security-solution-navigation'; +import { CASES_FEATURE_ID } from '../../../common'; import { createStore } from '../store'; import { mockGlobalState } from './global_state'; import { SUB_PLUGINS_REDUCER } from './utils'; @@ -39,11 +41,36 @@ const uiSettings = { const coreMock = { application: { getUrlForApp: () => {}, + capabilities: { [CASES_FEATURE_ID]: {} }, + }, + lens: { + EmbeddableComponent: () => , + }, + cases: { + helpers: { + getUICapabilities: () => ({}), + }, + hooks: { + useCasesAddToExistingCaseModal: () => {}, + useCasesAddToNewCaseFlyout: () => {}, + }, }, data: { query: { filterManager: {}, }, + search: { + session: React.createRef(), + }, + actions: { + createFiltersFromValueClickAction: () => {}, + }, + }, + settings: { + client: { + get: () => {}, + set: () => {}, + }, }, uiSettings, notifications: { @@ -78,13 +105,15 @@ export const StorybookProviders: React.FC = ({ children }) => { return ( - Promise.resolve([])}> - - ({ eui: euiLightVars, darkMode: false })}> - {children} - - - + + Promise.resolve([])}> + + ({ eui: euiLightVars, darkMode: false })}> + {children} + + + + ); diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index a6779272da76..03dc789a41ad 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -21,7 +21,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { Action } from '@kbn/ui-actions-plugin/public'; import { CellActionsProvider } from '@kbn/cell-actions'; import { ExpandableFlyoutProvider } from '@kbn/expandable-flyout'; -import { MockSubscriptionTrackingProvider } from '@kbn/subscription-tracking/mocks'; import { useKibana } from '../lib/kibana'; import { UpsellingProvider } from '../components/upselling_provider'; import { MockAssistantProvider } from './mock_assistant_provider'; @@ -76,29 +75,27 @@ export const TestProvidersComponent: React.FC = ({ return ( - - - - ({ eui: euiDarkVars, darkMode: true })}> - - - - - - Promise.resolve(cellActions)} - > - {children} - - - - - - - - - - + + + ({ eui: euiDarkVars, darkMode: true })}> + + + + + + Promise.resolve(cellActions)} + > + {children} + + + + + + + + + ); @@ -130,33 +127,31 @@ const TestProvidersWithPrivilegesComponent: React.FC = ({ return ( - - - ({ eui: euiDarkVars, darkMode: true })}> - - - - + ({ eui: euiDarkVars, darkMode: true })}> + + + + + Promise.resolve(cellActions)} > - Promise.resolve(cellActions)} - > - {children} - - - - - - - - + {children} + + + + + + + ); diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index ef6b4d265a5a..ba567b623ab5 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -2027,6 +2027,8 @@ export const mockTimelineModel: TimelineModel = { templateTimelineVersion: null, version: '1', savedSearchId: null, + savedSearch: null, + isDataProviderVisible: false, }; export const mockDataTableModel: DataTableModel = { @@ -2208,6 +2210,8 @@ export const defaultTimelineProps: CreateTimelineProps = { version: null, savedSearchId: null, isDiscoverSavedSearchLoaded: false, + savedSearch: null, + isDataProviderVisible: false, }, to: '2018-11-05T19:03:25.937Z', notes: null, diff --git a/x-pack/plugins/security_solution/public/common/utils/global_query_string/helpers.ts b/x-pack/plugins/security_solution/public/common/utils/global_query_string/helpers.ts index a5b3bb1c8d31..1be01959e2d0 100644 --- a/x-pack/plugins/security_solution/public/common/utils/global_query_string/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/utils/global_query_string/helpers.ts @@ -97,3 +97,10 @@ export const useReplaceUrlParams = (): ((params: Record { + // NOTE: This is a workaround to make sure that new history entry is created as a result of the user action. + // This is needed because of the way global url state is handled in the security app. + // (it defaults to replace the url params instead of pushing new history entry) + window.history.pushState({}, '', window.location.href); +}; diff --git a/x-pack/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx b/x-pack/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx index 30f9483169b1..07c87aec59da 100644 --- a/x-pack/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/common/utils/timeline/use_show_timeline.test.tsx @@ -83,7 +83,7 @@ describe('use show timeline', () => { }); it('hides timeline for blacklist routes', async () => { - mockUseLocation.mockReturnValueOnce({ pathname: '/rules/create' }); + mockUseLocation.mockReturnValueOnce({ pathname: '/rules/add_rules' }); await act(async () => { const { result, waitForNextUpdate } = renderHook(() => useShowTimeline()); await waitForNextUpdate(); diff --git a/x-pack/plugins/security_solution/public/contract_components.ts b/x-pack/plugins/security_solution/public/contract_components.ts index 91e341c4120f..3d1dee67eab9 100644 --- a/x-pack/plugins/security_solution/public/contract_components.ts +++ b/x-pack/plugins/security_solution/public/contract_components.ts @@ -5,17 +5,16 @@ * 2.0. */ -import { BehaviorSubject, map } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import type { Observable } from 'rxjs'; -export type ContractComponentName = 'getStarted' | 'dashboardsLandingCallout'; - -export type ContractComponents = Partial>; +export type ContractComponents = Partial<{ + GetStarted: React.ComponentType<{}>; + DashboardsLandingCallout: React.ComponentType<{}>; +}>; export type SetComponents = (components: ContractComponents) => void; -export type GetComponent$ = ( - name: ContractComponentName -) => Observable; +export type GetComponents$ = () => Observable; export class ContractComponentsService { private components$: BehaviorSubject; @@ -28,6 +27,5 @@ export class ContractComponentsService { this.components$.next(components); }; - public getComponent$: GetComponent$ = (name) => - this.components$.pipe(map((components) => components[name])); + public getComponents$ = () => this.components$.asObservable(); } diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx index 8723bfb69f32..52e6692de104 100644 --- a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.test.tsx @@ -28,11 +28,9 @@ jest.mock('@kbn/dashboard-plugin/public', () => ({ DashboardTopNav: jest.fn().mockReturnValue(), })); -const mockUseObservable = jest.fn(); - -jest.mock('react-use', () => ({ - ...jest.requireActual('react-use'), - useObservable: () => mockUseObservable(), +const mockUseContractComponents = jest.fn(() => ({})); +jest.mock('../../../common/hooks/use_contract_component', () => ({ + useContractComponents: () => mockUseContractComponents(), })); const DEFAULT_DASHBOARD_CAPABILITIES = { show: true, createNew: true }; @@ -216,11 +214,11 @@ describe('Dashboards landing', () => { }); it('should render callout when available', async () => { - const DummyComponent = () => ; - mockUseObservable.mockReturnValue(); + const DashboardsLandingCallout = () => ; + mockUseContractComponents.mockReturnValue({ DashboardsLandingCallout }); await renderDashboardLanding(); - expect(screen.queryByTestId('test')).toBeInTheDocument(); + expect(screen.queryByTestId('callout-test')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx index 10fb3c060548..affe83b0682c 100644 --- a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx @@ -17,11 +17,11 @@ import React, { useCallback, useMemo } from 'react'; import type { DashboardCapabilities } from '@kbn/dashboard-plugin/common/types'; import { DashboardListingTable, LEGACY_DASHBOARD_APP_ID } from '@kbn/dashboard-plugin/public'; import { LandingLinksImageCards } from '@kbn/security-solution-navigation/landing_links'; -import { useObservable } from 'react-use'; +import { useContractComponents } from '../../../common/hooks/use_contract_component'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../../../common/constants'; -import { useCapabilities, useKibana, useNavigateTo } from '../../../common/lib/kibana'; +import { useCapabilities, useNavigateTo } from '../../../common/lib/kibana'; import { useRootNavLink } from '../../../common/links/nav_links'; import { Title } from '../../../common/components/header_page/title'; import { LinkButton } from '../../../common/components/links/helpers'; @@ -83,8 +83,7 @@ const Header: React.FC<{ canCreateDashboard: boolean }> = ({ canCreateDashboard }; export const DashboardsLandingPage = () => { - const { getComponent$ } = useKibana().services; - const dashboardLandingCallout = useObservable(getComponent$('dashboardsLandingCallout')); + const { DashboardsLandingCallout } = useContractComponents(); const { links = [] } = useRootNavLink(SecurityPageName.dashboards) ?? {}; const urlState = useGlobalQueryString(); const { show: canReadDashboard, createNew: canCreateDashboard } = @@ -122,9 +121,9 @@ export const DashboardsLandingPage = () => {
    - {dashboardLandingCallout && ( + {DashboardsLandingCallout && ( <> - {dashboardLandingCallout} + )} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index df33b31a4cb6..e8a97e974431 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -404,6 +404,12 @@ const RuleDetailsPageComponent: React.FC = ({ ); }, [ruleId, lastExecutionStatus, lastExecutionDate, ruleLoading, isExistingRule, refreshRule]); + // Extract rule index if available on rule type + let ruleIndex: string[] | undefined; + if (rule != null && 'index' in rule && Array.isArray(rule.index)) { + ruleIndex = rule.index; + } + const ruleError = useMemo(() => { return ruleLoading ? ( @@ -411,12 +417,22 @@ const RuleDetailsPageComponent: React.FC = ({ ) : ( ); - }, [lastExecutionStatus, lastExecutionDate, lastExecutionMessage, ruleLoading]); + }, [ + lastExecutionStatus, + lastExecutionDate, + lastExecutionMessage, + ruleLoading, + rule?.immutable, + rule?.name, + ruleIndex, + ]); const updateDateRangeCallback = useCallback( ({ x }) => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx index dc762337f5e0..282d3fcc8439 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx @@ -25,6 +25,7 @@ import type { Threats, } from '@kbn/securitysolution-io-ts-alerting-types'; import { ALERT_RISK_SCORE } from '@kbn/rule-data-utils'; +import { requiredOptional } from '@kbn/zod-helpers'; import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import { SeverityBadge } from '../../../../detections/components/rules/severity_badge'; import { defaultToEmptyTag } from '../../../../common/components/empty_value'; @@ -333,7 +334,9 @@ const prepareAboutSectionListItems = ( ) : ( '' ), - description: , + description: ( + + ), }; }) ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/osquery/osquery_response_action_form_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/osquery/osquery_response_action_form_field.tsx index ada8c4a81e50..7898dfef3ea9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/osquery/osquery_response_action_form_field.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/osquery/osquery_response_action_form_field.tsx @@ -8,11 +8,13 @@ import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import React, { useCallback, useMemo } from 'react'; import { isEmpty, map } from 'lodash'; +import { useFormContext } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { useKibana } from '../../../common/lib/kibana'; export const ResponseActionFormField = React.memo(({ field }: { field: FieldHook }) => { - const { setErrors, clearErrors, value, setValue } = field; + const { clearErrors, value, setValue, path } = field; const { osquery } = useKibana().services; + const context = useFormContext(); const OsqueryForm = useMemo( () => osquery?.OsqueryResponseActionTypeForm, @@ -24,10 +26,11 @@ export const ResponseActionFormField = React.memo(({ field }: { field: FieldHook if (isEmpty(newErrors)) { clearErrors(); } else { - setErrors(map(newErrors, (error) => ({ message: error.message }))); + const errors = map(newErrors, (error) => ({ message: error.message })); + context.setFieldErrors(path, errors); } }, - [setErrors, clearErrors] + [clearErrors, context, path] ); // @ts-expect-error update types diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx index 23b8fe50be53..6f7521c3c1d6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx @@ -452,10 +452,11 @@ describe('alert actions', () => { templateTimelineVersion: null, version: null, savedSearchId: null, + savedSearch: null, isDiscoverSavedSearchLoaded: false, + isDataProviderVisible: false, }, to: '2018-11-05T19:03:25.937Z', - resolveTimelineConfig: undefined, ruleNote: '# this is some markdown documentation', ruleAuthor: ['elastic'], }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.test.tsx index 8807ccf0388d..b4b0a07fd7ab 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.test.tsx @@ -7,6 +7,7 @@ import type { ExistsFilter, Filter } from '@kbn/es-query'; import { + buildAlertAssigneesFilter, buildAlertsFilter, buildAlertStatusesFilter, buildAlertStatusFilter, @@ -158,6 +159,47 @@ describe('alerts default_config', () => { }); }); + describe('buildAlertAssigneesFilter', () => { + test('given an empty list of assignees ids will return an empty filter', () => { + const filters: Filter[] = buildAlertAssigneesFilter([]); + expect(filters).toHaveLength(0); + }); + + test('builds filter containing all assignees ids passed into function', () => { + const filters = buildAlertAssigneesFilter(['user-id-1', 'user-id-2', 'user-id-3']); + const expected = { + meta: { + alias: null, + disabled: false, + negate: false, + }, + query: { + bool: { + should: [ + { + term: { + 'kibana.alert.workflow_assignee_ids': 'user-id-1', + }, + }, + { + term: { + 'kibana.alert.workflow_assignee_ids': 'user-id-2', + }, + }, + { + term: { + 'kibana.alert.workflow_assignee_ids': 'user-id-3', + }, + }, + ], + }, + }, + }; + expect(filters).toHaveLength(1); + expect(filters[0]).toEqual(expected); + }); + }); + // TODO: move these tests to ../timelines/components/timeline/body/events/event_column_view.tsx // describe.skip('getAlertActions', () => { // let setEventsLoading: ({ eventIds, isLoading }: SetEventsLoadingProps) => void; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx index 1addd05eb8d9..6065e617c125 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx @@ -9,11 +9,13 @@ import { ALERT_BUILDING_BLOCK_TYPE, ALERT_WORKFLOW_STATUS, ALERT_RULE_RULE_ID, + ALERT_WORKFLOW_ASSIGNEE_IDS, } from '@kbn/rule-data-utils'; import type { Filter } from '@kbn/es-query'; import { tableDefaults } from '@kbn/securitysolution-data-table'; import type { SubsetDataTableModel } from '@kbn/securitysolution-data-table'; +import type { AssigneesIdsSelection } from '../../../common/components/assignees/types'; import type { Status } from '../../../../common/api/detection_engine'; import { getColumns, @@ -152,6 +154,36 @@ export const buildThreatMatchFilter = (showOnlyThreatIndicatorAlerts: boolean): ] : []; +export const buildAlertAssigneesFilter = (assigneesIds: AssigneesIdsSelection[]): Filter[] => { + if (!assigneesIds.length) { + return []; + } + const combinedQuery = { + bool: { + should: assigneesIds.map((id) => + id + ? { + term: { + [ALERT_WORKFLOW_ASSIGNEE_IDS]: id, + }, + } + : { bool: { must_not: { exists: { field: ALERT_WORKFLOW_ASSIGNEE_IDS } } } } + ), + }, + }; + + return [ + { + meta: { + alias: null, + negate: false, + disabled: false, + }, + query: combinedQuery, + }, + ]; +}; + export const getAlertsDefaultModel = (license?: LicenseService): SubsetDataTableModel => ({ ...tableDefaults, columns: getColumns(license), @@ -177,6 +209,7 @@ export const requiredFieldsForActions = [ '@timestamp', 'kibana.alert.workflow_status', 'kibana.alert.workflow_tags', + 'kibana.alert.workflow_assignee_ids', 'kibana.alert.group.id', 'kibana.alert.original_time', 'kibana.alert.building_block_type', diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx index 2b887808696b..b91db35cdeaa 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.test.tsx @@ -28,6 +28,10 @@ jest.mock('../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(true), })); +jest.mock('../../../../common/hooks/use_license', () => ({ + useLicense: jest.fn().mockReturnValue({ isPlatinumPlus: () => true }), +})); + const ecsRowData: Ecs = { _id: '1', agent: { type: ['blah'] }, @@ -74,17 +78,22 @@ jest.mock('../../../../common/lib/kibana', () => { application: { capabilities: { siem: { crud_alerts: true, read_alerts: true } }, }, - cases: mockCasesContract(), + cases: { + ...mockCasesContract(), + helpers: { + canUseCases: jest.fn().mockReturnValue({ + all: true, + create: true, + read: true, + update: true, + delete: true, + push: true, + }), + getRuleIdFromEvent: jest.fn(), + }, + }, }, }), - useGetUserCasesPermissions: jest.fn().mockReturnValue({ - all: true, - create: true, - read: true, - update: true, - delete: true, - push: true, - }), }; }); @@ -100,6 +109,7 @@ const markAsAcknowledgedButton = '[data-test-subj="acknowledged-alert-status"]'; const markAsClosedButton = '[data-test-subj="close-alert-status"]'; const addEndpointEventFilterButton = '[data-test-subj="add-event-filter-menu-item"]'; const applyAlertTagsButton = '[data-test-subj="alert-tags-context-menu-item"]'; +const applyAlertAssigneesButton = '[data-test-subj="alert-assignees-context-menu-item"]'; describe('Alert table context menu', () => { describe('Case actions', () => { @@ -299,4 +309,16 @@ describe('Alert table context menu', () => { expect(wrapper.find(applyAlertTagsButton).first().exists()).toEqual(true); }); }); + + describe('Assign alert action', () => { + test('it renders the assign alert action button', () => { + const wrapper = mount(, { + wrappingComponent: TestProviders, + }); + + wrapper.find(actionMenuButton).simulate('click'); + + expect(wrapper.find(applyAlertAssigneesButton).first().exists()).toEqual(true); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index 741039c09e0e..c5c5b95abbcc 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -50,6 +50,7 @@ import { isAlertFromEndpointAlert } from '../../../../common/utils/endpoint_aler import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; import type { AlertTableContextMenuItem } from '../types'; import { useAlertTagsActions } from './use_alert_tags_actions'; +import { useAlertAssigneesActions } from './use_alert_assignees_actions'; interface AlertContextMenuProps { ariaLabel?: string; @@ -224,6 +225,12 @@ const AlertContextMenuComponent: React.FC = ({ refetch: refetchAll, }); + const { alertAssigneesItems, alertAssigneesPanels } = useAlertAssigneesActions({ + closePopover, + ecsRowData, + refetch: refetchAll, + }); + const items: AlertTableContextMenuItem[] = useMemo( () => !isEvent && ruleId @@ -231,6 +238,7 @@ const AlertContextMenuComponent: React.FC = ({ ...addToCaseActionItems, ...statusActionItems, ...alertTagsItems, + ...alertAssigneesItems, ...exceptionActionItems, ...(agentId ? osqueryActionItems : []), ] @@ -250,6 +258,7 @@ const AlertContextMenuComponent: React.FC = ({ eventFilterActionItems, canCreateEndpointEventFilters, alertTagsItems, + alertAssigneesItems, ] ); @@ -260,8 +269,9 @@ const AlertContextMenuComponent: React.FC = ({ items, }, ...alertTagsPanels, + ...alertAssigneesPanels, ], - [alertTagsPanels, items] + [alertTagsPanels, alertAssigneesPanels, items] ); const osqueryFlyout = useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.test.tsx index de33379f48ab..cbe56a62c457 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.test.tsx @@ -12,7 +12,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useAddToCaseActions } from './use_add_to_case_actions'; import { TestProviders } from '../../../../common/mock'; -import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana'; +import { useKibana } from '../../../../common/lib/kibana'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour'; import { AlertsCasesTourSteps, @@ -20,6 +20,7 @@ import { } from '../../../../common/components/guided_onboarding_tour/tour_config'; import { CasesTourSteps } from '../../../../common/components/guided_onboarding_tour/cases_tour_steps'; import type { AlertTableContextMenuItem } from '../types'; +import { allCasesPermissions } from '../../../../cases_test_utils'; jest.mock('../../../../common/components/guided_onboarding_tour'); jest.mock('../../../../common/lib/kibana'); @@ -76,15 +77,6 @@ describe('useAddToCaseActions', () => { isTourShown: () => false, }); - (useGetUserCasesPermissions as jest.Mock).mockReturnValue({ - all: true, - create: true, - read: true, - update: true, - delete: true, - push: true, - }); - useKibanaMock.mockReturnValue({ services: { cases: { @@ -94,6 +86,7 @@ describe('useAddToCaseActions', () => { }, helpers: { getRuleIdFromEvent: () => null, + canUseCases: jest.fn().mockReturnValue(allCasesPermissions()), }, }, }, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx index 50e1e11268e5..de3c8782722f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx @@ -9,6 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import { AttachmentType } from '@kbn/cases-plugin/common'; import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { APP_ID } from '../../../../../common'; import { CasesTourSteps } from '../../../../common/components/guided_onboarding_tour/cases_tour_steps'; import { AlertsCasesTourSteps, @@ -16,7 +17,7 @@ import { SecurityStepId, } from '../../../../common/components/guided_onboarding_tour/tour_config'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour'; -import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana'; +import { useKibana } from '../../../../common/lib/kibana'; import type { TimelineNonEcsData } from '../../../../../common/search_strategy'; import { ADD_TO_EXISTING_CASE, ADD_TO_NEW_CASE } from '../translations'; import type { AlertTableContextMenuItem } from '../types'; @@ -29,7 +30,7 @@ export interface UseAddToCaseActions { onSuccess?: () => Promise; isActiveTimelines: boolean; isInDetections: boolean; - refetch: (() => void) | undefined; + refetch?: (() => void) | undefined; } export const useAddToCaseActions = ({ @@ -43,7 +44,7 @@ export const useAddToCaseActions = ({ refetch, }: UseAddToCaseActions) => { const { cases: casesUi } = useKibana().services; - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = casesUi.helpers.canUseCases([APP_ID]); const isAlert = useMemo(() => { return ecsData?.event?.kind?.includes('signal'); @@ -173,5 +174,6 @@ export const useAddToCaseActions = ({ return { addToCaseActionItems, handleAddToNewCaseClick, + handleAddToExistingCaseClick, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.test.tsx new file mode 100644 index 000000000000..52c196fa729f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.test.tsx @@ -0,0 +1,203 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TestProviders } from '@kbn/timelines-plugin/public/mock'; +import { renderHook } from '@testing-library/react-hooks'; +import type { UseAlertAssigneesActionsProps } from './use_alert_assignees_actions'; +import { useAlertAssigneesActions } from './use_alert_assignees_actions'; +import { useAlertsPrivileges } from '../../../containers/detection_engine/alerts/use_alerts_privileges'; +import type { AlertTableContextMenuItem } from '../types'; +import { render } from '@testing-library/react'; +import React from 'react'; +import type { EuiContextMenuPanelDescriptor } from '@elastic/eui'; +import { EuiPopover, EuiContextMenu } from '@elastic/eui'; +import { useSetAlertAssignees } from '../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'; +import { useGetCurrentUserProfile } from '../../../../common/components/user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../../../../common/components/user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../../../../common/components/user_profiles/use_suggest_users'; +import { useLicense } from '../../../../common/hooks/use_license'; + +jest.mock('../../../containers/detection_engine/alerts/use_alerts_privileges'); +jest.mock('../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'); +jest.mock('../../../../common/components/user_profiles/use_get_current_user_profile'); +jest.mock('../../../../common/components/user_profiles/use_bulk_get_user_profiles'); +jest.mock('../../../../common/components/user_profiles/use_suggest_users'); +jest.mock('../../../../common/hooks/use_license'); + +const mockUserProfiles = [ + { uid: 'user-id-1', enabled: true, user: { username: 'fakeUser1' }, data: {} }, + { uid: 'user-id-2', enabled: true, user: { username: 'fakeUser2' }, data: {} }, +]; + +const defaultProps: UseAlertAssigneesActionsProps = { + closePopover: jest.fn(), + ecsRowData: { + _id: '123', + kibana: { + alert: { + workflow_assignee_ids: [], + }, + }, + }, + refetch: jest.fn(), +}; + +const renderContextMenu = ( + items: AlertTableContextMenuItem[], + panels: EuiContextMenuPanelDescriptor[] +) => { + const panelsToRender = [{ id: 0, items }, ...panels]; + return render( + {}} + button={<>} + > + + + ); +}; + +describe('useAlertAssigneesActions', () => { + beforeEach(() => { + (useAlertsPrivileges as jest.Mock).mockReturnValue({ + hasIndexWrite: true, + }); + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => true }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should render alert assignees actions', () => { + const { result } = renderHook(() => useAlertAssigneesActions(defaultProps), { + wrapper: TestProviders, + }); + + expect(result.current.alertAssigneesItems.length).toEqual(2); + expect(result.current.alertAssigneesPanels.length).toEqual(1); + expect(result.current.alertAssigneesItems[0]['data-test-subj']).toEqual( + 'alert-assignees-context-menu-item' + ); + expect(result.current.alertAssigneesItems[1]['data-test-subj']).toEqual( + 'remove-alert-assignees-menu-item' + ); + + expect(result.current.alertAssigneesPanels[0].content).toMatchInlineSnapshot(` + + `); + }); + + it("should not render alert assignees actions if user doesn't have write permissions", () => { + (useAlertsPrivileges as jest.Mock).mockReturnValue({ + hasIndexWrite: false, + }); + const { result } = renderHook(() => useAlertAssigneesActions(defaultProps), { + wrapper: TestProviders, + }); + expect(result.current.alertAssigneesItems.length).toEqual(0); + }); + + it('should not render alert assignees actions within Basic license', () => { + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => false }); + const { result } = renderHook(() => useAlertAssigneesActions(defaultProps), { + wrapper: TestProviders, + }); + expect(result.current.alertAssigneesItems.length).toEqual(0); + }); + + it('should still render if workflow_assignee_ids field does not exist', () => { + const newProps = { + ...defaultProps, + ecsRowData: { + _id: '123', + }, + }; + const { result } = renderHook(() => useAlertAssigneesActions(newProps), { + wrapper: TestProviders, + }); + expect(result.current.alertAssigneesItems.length).toEqual(2); + expect(result.current.alertAssigneesPanels.length).toEqual(1); + expect(result.current.alertAssigneesPanels[0].content).toMatchInlineSnapshot(` + + `); + }); + + it('should render the nested panel', async () => { + (useSetAlertAssignees as jest.Mock).mockReturnValue(jest.fn()); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + + const { result } = renderHook(() => useAlertAssigneesActions(defaultProps), { + wrapper: TestProviders, + }); + const alertAssigneesItems = result.current.alertAssigneesItems; + const alertAssigneesPanels = result.current.alertAssigneesPanels; + const { getByTestId } = renderContextMenu(alertAssigneesItems, alertAssigneesPanels); + + expect(getByTestId('alert-assignees-selectable-menu')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.tsx new file mode 100644 index 000000000000..ff7e64a5e4dc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_alert_assignees_actions.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { noop } from 'lodash'; +import { useCallback, useMemo } from 'react'; + +import type { EuiContextMenuPanelDescriptor } from '@elastic/eui'; +import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; + +import { ASSIGNEES_PANEL_WIDTH } from '../../../../common/components/assignees/constants'; +import { useBulkAlertAssigneesItems } from '../../../../common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items'; +import { useAlertsPrivileges } from '../../../containers/detection_engine/alerts/use_alerts_privileges'; +import type { AlertTableContextMenuItem } from '../types'; + +export interface UseAlertAssigneesActionsProps { + closePopover: () => void; + ecsRowData: Ecs; + refetch?: () => void; +} + +export const useAlertAssigneesActions = ({ + closePopover, + ecsRowData, + refetch, +}: UseAlertAssigneesActionsProps) => { + const { hasIndexWrite } = useAlertsPrivileges(); + + const alertId = ecsRowData._id; + const alertAssigneeData = useMemo(() => { + return [ + { + _id: alertId, + _index: ecsRowData._index ?? '', + data: [ + { + field: ALERT_WORKFLOW_ASSIGNEE_IDS, + value: ecsRowData?.kibana?.alert.workflow_assignee_ids ?? [], + }, + ], + ecs: { + _id: alertId, + _index: ecsRowData._index ?? '', + }, + }, + ]; + }, [alertId, ecsRowData._index, ecsRowData?.kibana?.alert.workflow_assignee_ids]); + + const onAssigneesUpdate = useCallback(() => { + closePopover(); + if (refetch) { + refetch(); + } + }, [closePopover, refetch]); + + const { alertAssigneesItems, alertAssigneesPanels } = useBulkAlertAssigneesItems({ + onAssigneesUpdate, + }); + + const itemsToReturn: AlertTableContextMenuItem[] = useMemo( + () => + alertAssigneesItems.map((item) => ({ + name: item.name, + panel: item.panel, + 'data-test-subj': item['data-test-subj'], + key: item.key, + onClick: () => item.onClick?.(alertAssigneeData, false, noop, noop, noop), + })), + [alertAssigneeData, alertAssigneesItems] + ); + + const panelsToReturn: EuiContextMenuPanelDescriptor[] = useMemo( + () => + alertAssigneesPanels.map((panel) => { + const content = panel.renderContent({ + closePopoverMenu: closePopover, + setIsBulkActionsLoading: () => {}, + alertItems: alertAssigneeData, + refresh: onAssigneesUpdate, + }); + return { title: panel.title, content, id: panel.id, width: ASSIGNEES_PANEL_WIDTH }; + }), + [alertAssigneeData, alertAssigneesPanels, closePopover, onAssigneesUpdate] + ); + + return { + alertAssigneesItems: hasIndexWrite ? itemsToReturn : [], + alertAssigneesPanels: panelsToReturn, + }; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx index 6fe5693796cb..02d149860c1b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx @@ -18,6 +18,7 @@ import { useApi } from '@kbn/securitysolution-list-hooks'; import type { Filter } from '@kbn/es-query'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { createHistoryEntry } from '../../../../common/utils/global_query_string/helpers'; import { timelineDefaults } from '../../../../timelines/store/timeline/defaults'; import { useKibana } from '../../../../common/lib/kibana'; import { TimelineId } from '../../../../../common/types/timeline'; @@ -175,6 +176,8 @@ export const useInvestigateInTimeline = ({ ); const investigateInTimelineAlertClick = useCallback(async () => { + createHistoryEntry(); + startTransaction({ name: ALERTS_ACTIONS.INVESTIGATE_IN_TIMELINE }); if (onInvestigateInTimelineAlertClick) { onInvestigateInTimelineAlertClick(); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts index 5115bf0130e6..ae0c05d2bdb0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts @@ -95,6 +95,13 @@ export const ALERTS_HEADERS_RISK_SCORE = i18n.translate( } ); +export const ALERTS_HEADERS_ASSIGNEES = i18n.translate( + 'xpack.securitySolution.eventsViewer.alerts.defaultHeaders.assigneesTitle', + { + defaultMessage: 'Assignees', + } +); + export const ALERTS_HEADERS_THRESHOLD_COUNT = i18n.translate( 'xpack.securitySolution.eventsViewer.alerts.defaultHeaders.thresholdCount', { @@ -137,6 +144,13 @@ export const ACTION_INVESTIGATE_IN_TIMELINE = i18n.translate( } ); +export const ACTION_CANNOT_INVESTIGATE_IN_TIMELINE = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.actions.cannotInvestigateInTimelineTitle', + { + defaultMessage: 'Please navigate to a page with timeline to investigate', + } +); + export const ACTION_INVESTIGATE_IN_TIMELINE_ARIA_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.alerts.actions.investigateInTimelineAriaLabel', { diff --git a/x-pack/plugins/security_solution/public/detections/components/detection_page_filters/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/detection_page_filters/index.test.tsx index 984e19a87963..b099acb25453 100644 --- a/x-pack/plugins/security_solution/public/detections/components/detection_page_filters/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/detection_page_filters/index.test.tsx @@ -23,6 +23,35 @@ jest.mock('../../../common/components/filter_group'); jest.mock('../../../common/lib/kibana'); +const mockUserProfiles = [ + { + uid: 'user-id-1', + enabled: true, + user: { username: 'user1', full_name: 'User 1', email: 'user1@test.com' }, + data: {}, + }, + { + uid: 'user-id-2', + enabled: true, + user: { username: 'user2', full_name: 'User 2', email: 'user2@test.com' }, + data: {}, + }, + { + uid: 'user-id-3', + enabled: true, + user: { username: 'user3', full_name: 'User 3', email: 'user3@test.com' }, + data: {}, + }, +]; +jest.mock('../../../common/components/user_profiles/use_suggest_users', () => { + return { + useSuggestUsers: () => ({ + loading: false, + userProfiles: mockUserProfiles, + }), + }; +}); + const basicKibanaServicesMock = createStartServicesMock(); const getFieldByNameMock = jest.fn(() => true); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.tsx index a60c24378902..611480ddd8f2 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/eql_query_bar.tsx @@ -30,10 +30,32 @@ import { useKibana } from '../../../../common/lib/kibana'; const TextArea = styled(EuiTextArea)` display: block; - border: ${({ theme }) => theme.eui.euiBorderThin}; - border-bottom: 0; + border: 0; box-shadow: none; + border-radius: 0px; min-height: ${({ theme }) => theme.eui.euiFormControlHeight}; + &:focus { + box-shadow: none; + } +`; + +const StyledFormRow = styled(EuiFormRow)` + border: ${({ theme }) => theme.eui.euiBorderThin}; + border-radius: ${({ theme }) => theme.eui.euiBorderRadius}; + + .euiFormRow__labelWrapper { + background: ${({ theme }) => theme.eui.euiColorLightestShade}; + border-top-left-radius: ${({ theme }) => theme.eui.euiBorderRadius}; + border-top-right-radius: ${({ theme }) => theme.eui.euiBorderRadius}; + padding: 8px 10px; + margin-bottom: 0px; + label { + color: ${({ theme }) => theme.eui.euiTextSubduedColor}; + &.euiFormLabel-isInvalid { + color: ${({ theme }) => theme.eui.euiColorDangerText}; + } + } + } `; export interface FieldValueQueryBar { @@ -157,7 +179,7 @@ export const EqlQueryBar: FC = ({ ); return ( - = ({ )} - + ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/footer.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/footer.tsx index c9e74b6a9acf..7f7a6ab21a38 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/footer.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/eql_query_bar/footer.tsx @@ -14,7 +14,6 @@ import { EuiFlexItem, EuiFormRow, EuiLoadingSpinner, - EuiPanel, EuiPopover, EuiPopoverTitle, } from '@elastic/eui'; @@ -44,9 +43,11 @@ export interface Props { type SizeVoidFunc = (newSize: string) => void; -const Container = styled(EuiPanel)` +const Container = styled(EuiFlexGroup)` border-radius: 0; - background: ${({ theme }) => theme.eui.euiPageBackgroundColor}; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + background: ${({ theme }) => theme.eui.euiColorLightestShade}; padding: ${({ theme }) => theme.eui.euiSizeXS} ${({ theme }) => theme.eui.euiSizeS}; `; @@ -161,96 +162,113 @@ export const EqlQueryBarFooter: FC = ({ return ( - - - {errors.length > 0 && ( - - )} - {isLoading && } + + + + + {errors.length > 0 && ( + + )} + {isLoading && } + + - {!onOptionsChange && ( - - - - )} - {onOptionsChange && ( - <> - - - - - - } - isOpen={openEqlSettings} - closePopover={closeEqlSettingsHandler} - anchorPosition="downCenter" - ownFocus={false} - > - {i18n.EQL_SETTINGS_TITLE} -
    - {!isSizeOptionDisabled && ( - - + + {!onOptionsChange && ( + + + + )} + + {onOptionsChange && ( + <> + + + + + - - )} - - - - - - - - - -
    -
    -
    - - )} + {i18n.EQL_SETTINGS_TITLE} +
    + {!isSizeOptionDisabled && ( + + + + )} + + + + + + + + + +
    + + + + )} + +
    ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx index 4902ac0115fe..5998073d65cd 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx @@ -11,6 +11,10 @@ import { render } from '@testing-library/react'; import type { RuleExecutionStatus } from '../../../../../common/api/detection_engine/rule_monitoring'; import { RuleExecutionStatusEnum } from '../../../../../common/api/detection_engine/rule_monitoring'; import { RuleStatusFailedCallOut } from './rule_status_failed_callout'; +import { AssistantProvider } from '@kbn/elastic-assistant'; +import type { AssistantAvailability } from '@kbn/elastic-assistant'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { actionTypeRegistryMock } from '@kbn/triggers-actions-ui-plugin/public/application/action_type_registry.mock'; jest.mock('../../../../common/lib/kibana'); @@ -18,10 +22,50 @@ const TEST_ID = 'ruleStatusFailedCallOut'; const DATE = '2022-01-27T15:03:31.176Z'; const MESSAGE = 'This rule is attempting to query data but...'; +const actionTypeRegistry = actionTypeRegistryMock.create(); +const mockGetInitialConversations = jest.fn(() => ({})); +const mockGetComments = jest.fn(() => []); +const mockHttp = httpServiceMock.createStartContract({ basePath: '/test' }); +const mockAssistantAvailability: AssistantAvailability = { + hasAssistantPrivilege: false, + hasConnectorsAllPrivilege: true, + hasConnectorsReadPrivilege: true, + isAssistantEnabled: true, +}; +const ContextWrapper: React.FC = ({ children }) => ( + + {children} + +); + describe('RuleStatusFailedCallOut', () => { const renderWith = (status: RuleExecutionStatus | null | undefined) => render(); - + const renderWithAssistant = (status: RuleExecutionStatus | null | undefined) => + render( + + {' '} + + ); it('is hidden if status is undefined', () => { const result = renderWith(undefined); expect(result.queryByTestId(TEST_ID)).toBe(null); @@ -48,7 +92,7 @@ describe('RuleStatusFailedCallOut', () => { }); it('is visible if status is "partial failure"', () => { - const result = renderWith(RuleExecutionStatusEnum['partial failure']); + const result = renderWithAssistant(RuleExecutionStatusEnum['partial failure']); result.getByTestId(TEST_ID); result.getByText('Warning at'); result.getByText('Jan 27, 2022 @ 15:03:31.176'); @@ -56,7 +100,7 @@ describe('RuleStatusFailedCallOut', () => { }); it('is visible if status is "failed"', () => { - const result = renderWith(RuleExecutionStatusEnum.failed); + const result = renderWithAssistant(RuleExecutionStatusEnum.failed); result.getByTestId(TEST_ID); result.getByText('Rule failure at'); result.getByText('Jan 27, 2022 @ 15:03:31.176'); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx index b9e26dc16220..0d1777e26c55 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx @@ -5,28 +5,43 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback } from 'react'; -import { EuiCallOut, EuiCodeBlock } from '@elastic/eui'; +import { EuiButton, EuiCallOut, EuiCodeBlock } from '@elastic/eui'; +import { NewChat } from '@kbn/elastic-assistant'; import { FormattedDate } from '../../../../common/components/formatted_date'; import type { RuleExecutionStatus } from '../../../../../common/api/detection_engine/rule_monitoring'; import { RuleExecutionStatusEnum } from '../../../../../common/api/detection_engine/rule_monitoring'; import * as i18n from './translations'; +import * as i18nAssistant from '../../../pages/detection_engine/rules/translations'; +import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; interface RuleStatusFailedCallOutProps { + ruleName?: string | undefined; + dataSources?: string[] | undefined; date: string; message: string; status?: RuleExecutionStatus | null; } const RuleStatusFailedCallOutComponent: React.FC = ({ + ruleName, + dataSources, date, message, status, }) => { + const { hasAssistantPrivilege } = useAssistantAvailability(); const { shouldBeDisplayed, color, title } = getPropsByStatus(status); + const getPromptContext = useCallback( + async () => + ruleName != null && dataSources != null + ? `Rule name: ${ruleName}\nData sources: ${dataSources}\nError message: ${message}` + : `Error message: ${message}`, + [message, ruleName, dataSources] + ); if (!shouldBeDisplayed) { return null; } @@ -60,6 +75,21 @@ const RuleStatusFailedCallOutComponent: React.FC = > {message} + {hasAssistantPrivilege && ( + + + {i18n.ASK_ASSISTANT_ERROR_BUTTON} + + + )} ); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts index e2a1e566813a..3b760ac68e62 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts @@ -48,3 +48,31 @@ export const PARTIAL_FAILURE_CALLOUT_TITLE = i18n.translate( defaultMessage: 'Warning at', } ); + +export const ASK_ASSISTANT_ERROR_BUTTON = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.askAssistant', + { + defaultMessage: 'Ask Assistant', + } +); + +export const ASK_ASSISTANT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.askAssistantDesc', + { + defaultMessage: "Rule's execution failure message", + } +); + +export const ASK_ASSISTANT_USER_PROMPT = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.askAssistantUserPrompt', + { + defaultMessage: 'Can you explain this rule execution error and steps to fix?', + } +); + +export const ASK_ASSISTANT_TOOLTIP = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.askAssistantToolTip', + { + defaultMessage: 'Add this rule execution error as context', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.test.tsx index 3bee45e94712..9a490bec1ce2 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/preview_histogram.test.tsx @@ -23,7 +23,6 @@ import { usePreviewHistogram } from './use_preview_histogram'; import { PreviewHistogram } from './preview_histogram'; import { ALL_VALUES_ZEROS_TITLE } from '../../../../common/components/charts/translation'; -import { useGetUserCasesPermissions } from '../../../../common/lib/kibana'; import { useTimelineEvents } from '../../../../common/components/events_viewer/use_timelines_events'; import { TableId } from '@kbn/securitysolution-data-table'; import { createStore } from '../../../../common/store'; @@ -58,12 +57,7 @@ const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as j const getMockUseIsExperimentalFeatureEnabled = (mockMapping?: Partial) => (flag: keyof typeof allowedExperimentalValues) => mockMapping ? mockMapping?.[flag] : allowedExperimentalValues?.[flag]; -const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana'); -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); const mockUseFieldBrowserOptions = jest.fn(); jest.mock('../../../../timelines/components/fields_browser', () => ({ useFieldBrowserOptions: (props: UseFieldBrowserOptionsProps) => mockUseFieldBrowserOptions(props), diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx index 356938a6d54e..a3e7b942953f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx @@ -18,7 +18,7 @@ import { TimelineId } from '../../../../common/types/timeline'; import { TestProviders } from '../../../common/mock'; import { mockTimelines } from '../../../common/mock/mock_timelines_plugin'; import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock'; -import { useKibana, useGetUserCasesPermissions, useHttp } from '../../../common/lib/kibana'; +import { useKibana, useHttp } from '../../../common/lib/kibana'; import { mockCasesContract } from '@kbn/cases-plugin/public/mocks'; import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../common/components/user_privileges/user_privileges_context'; import { useUserPrivileges } from '../../../common/components/user_privileges'; @@ -37,7 +37,10 @@ import { getUserPrivilegesMockDefaultValue } from '../../../common/components/us import { allCasesPermissions } from '../../../cases_test_utils'; import { HostStatus } from '../../../../common/endpoint/types'; import { ENDPOINT_CAPABILITIES } from '../../../../common/endpoint/service/response_actions/constants'; -import { ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE } from '../../../common/components/toolbar/bulk_actions/translations'; +import { + ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE, + ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, +} from '../../../common/components/toolbar/bulk_actions/translations'; jest.mock('../../../common/components/user_privileges'); @@ -46,7 +49,6 @@ jest.mock('../user_info', () => ({ })); jest.mock('../../../common/lib/kibana'); -(useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions()); jest.mock('../../containers/detection_engine/alerts/use_alerts_privileges', () => ({ useAlertsPrivileges: jest.fn().mockReturnValue({ hasIndexWrite: true, hasKibanaCRUD: true }), @@ -59,6 +61,10 @@ jest.mock('../../../common/hooks/use_app_toasts', () => ({ }), })); +jest.mock('../../../common/hooks/use_license', () => ({ + useLicense: jest.fn().mockReturnValue({ isPlatinumPlus: () => true }), +})); + jest.mock('../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(true), })); @@ -119,7 +125,13 @@ describe('take action dropdown', () => { services: { ...mockStartServicesMock, timelines: { ...mockTimelines }, - cases: mockCasesContract(), + cases: { + ...mockCasesContract(), + helpers: { + canUseCases: jest.fn().mockReturnValue(allCasesPermissions()), + getRuleIdFromEvent: () => null, + }, + }, osquery: { isOsqueryAvailable: jest.fn().mockReturnValue(true), }, @@ -249,6 +261,13 @@ describe('take action dropdown', () => { ).toEqual(ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE); }); }); + test('should render "Assign alert"', async () => { + await waitFor(() => { + expect( + wrapper.find('[data-test-subj="alert-assignees-context-menu-item"]').first().text() + ).toEqual(ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE); + }); + }); }); describe('for Endpoint related actions', () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index 67175f05ece2..f8efc47d3bd1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -35,6 +35,7 @@ import { useKibana } from '../../../common/lib/kibana'; import { getOsqueryActionItem } from '../osquery/osquery_action_item'; import type { AlertTableContextMenuItem } from '../alerts_table/types'; import { useAlertTagsActions } from '../alerts_table/timeline_actions/use_alert_tags_actions'; +import { useAlertAssigneesActions } from '../alerts_table/timeline_actions/use_alert_assignees_actions'; interface ActionsData { alertStatus: Status; @@ -189,6 +190,20 @@ export const TakeActionDropdown = React.memo( refetch, }); + const onAssigneesUpdate = useCallback(() => { + if (refetch) { + refetch(); + } + if (refetchFlyoutData) { + refetchFlyoutData(); + } + }, [refetch, refetchFlyoutData]); + const { alertAssigneesItems, alertAssigneesPanels } = useAlertAssigneesActions({ + closePopover: closePopoverHandler, + ecsRowData: ecsData ?? { _id: actionsData.eventId }, + refetch: onAssigneesUpdate, + }); + const { investigateInTimelineActionItems } = useInvestigateInTimeline({ ecsRowData: ecsData, onInvestigateInTimelineAlertClick: closePopoverHandler, @@ -214,7 +229,12 @@ export const TakeActionDropdown = React.memo( const alertsActionItems = useMemo( () => !isEvent && actionsData.ruleId - ? [...statusActionItems, ...alertTagsItems, ...exceptionActionItems] + ? [ + ...statusActionItems, + ...alertTagsItems, + ...alertAssigneesItems, + ...exceptionActionItems, + ] : isEndpointEvent && canCreateEndpointEventFilters ? eventFilterActionItems : [], @@ -227,6 +247,7 @@ export const TakeActionDropdown = React.memo( isEvent, actionsData.ruleId, alertTagsItems, + alertAssigneesItems, ] ); @@ -271,6 +292,7 @@ export const TakeActionDropdown = React.memo( items, }, ...alertTagsPanels, + ...alertAssigneesPanels, ]; const takeActionButton = useMemo( diff --git a/x-pack/plugins/security_solution/public/detections/components/user_privileges/translations.ts b/x-pack/plugins/security_solution/public/detections/components/user_privileges/translations.ts index c2ae389a0c57..2771a8e48a04 100644 --- a/x-pack/plugins/security_solution/public/detections/components/user_privileges/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/user_privileges/translations.ts @@ -17,6 +17,6 @@ export const LISTS_PRIVILEGES_FETCH_FAILURE = i18n.translate( export const DETECTION_ENGINE_PRIVILEGES_FETCH_FAILURE = i18n.translate( 'xpack.securitySolution.containers.detectionEngine.alerts.detectionEnginePrivileges.errorFetching', { - defaultMessage: 'Failed to retreive detection engine privileges', + defaultMessage: 'Failed to retrieve detection engine privileges', } ); diff --git a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/columns.ts b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/columns.ts index 29c8cb4ec096..bfce84209644 100644 --- a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/columns.ts +++ b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/columns.ts @@ -28,6 +28,12 @@ const getBaseColumns = ( > => { const isPlatinumPlus = license?.isPlatinumPlus?.() ?? false; return [ + { + columnHeaderType: defaultColumnHeaderType, + displayAsText: i18n.ALERTS_HEADERS_ASSIGNEES, + id: 'kibana.alert.workflow_assignee_ids', + initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH, + }, { columnHeaderType: defaultColumnHeaderType, displayAsText: i18n.ALERTS_HEADERS_SEVERITY, diff --git a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/fetch_page_context.tsx b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/fetch_page_context.tsx new file mode 100644 index 000000000000..ebd8df15d92e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/fetch_page_context.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import type { PreFetchPageContext } from '@kbn/triggers-actions-ui-plugin/public/types'; +import { useBulkGetUserProfiles } from '../../../common/components/user_profiles/use_bulk_get_user_profiles'; + +export interface RenderCellValueContext { + profiles: UserProfileWithAvatar[] | undefined; + isLoading: boolean; +} + +// Add new columns names to this array to render the user's display name instead of profile_uid +export const profileUidColumns = [ + 'kibana.alert.workflow_assignee_ids', + 'kibana.alert.workflow_user', +]; + +export const useFetchPageContext: PreFetchPageContext = ({ + alerts, + columns, +}) => { + const uids = new Set(); + alerts.forEach((alert) => { + profileUidColumns.forEach((columnId) => { + if (columns.find((column) => column.id === columnId) != null) { + const userUids = alert[columnId]; + userUids?.forEach((uid) => uids.add(uid as string)); + } + }); + }); + const result = useBulkGetUserProfiles({ uids }); + const returnVal = useMemo( + () => ({ profiles: result.data, isLoading: result.isLoading }), + [result.data, result.isLoading] + ); + return returnVal; +}; diff --git a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx index 47be8b073934..84e14ad725e4 100644 --- a/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx +++ b/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections/render_cell_value.tsx @@ -33,6 +33,7 @@ import { SUPPRESSED_ALERT_TOOLTIP } from './translations'; import { VIEW_SELECTION } from '../../../../common/constants'; import { getAllFieldsByName } from '../../../common/containers/source'; import { eventRenderedViewColumns, getColumns } from './columns'; +import type { RenderCellValueContext } from './fetch_page_context'; /** * This implementation of `EuiDataGrid`'s `renderCellValue` @@ -95,7 +96,7 @@ export const getRenderCellValueHook = ({ scopeId: SourcererScopeName; tableId: TableId; }) => { - const useRenderCellValue: GetRenderCellValue = () => { + const useRenderCellValue: GetRenderCellValue = ({ context }) => { const { browserFields } = useSourcererDataView(scopeId); const browserFieldsByName = useMemo(() => getAllFieldsByName(browserFields), [browserFields]); const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []); @@ -173,10 +174,11 @@ export const getRenderCellValueHook = ({ scopeId={tableId} truncate={truncate} asPlainText={false} + context={context as RenderCellValueContext} /> ); }, - [browserFieldsByName, browserFields, columnHeaders] + [browserFieldsByName, columnHeaders, browserFields, context] ); return result; }; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts index 1f667cc42be1..3af1ddd6c0fc 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/translations.ts @@ -30,3 +30,8 @@ export const CASES_FROM_ALERTS_FAILURE = i18n.translate( 'xpack.securitySolution.endpoint.hostIsolation.casesFromAlerts.title', { defaultMessage: 'Failed to find associated cases' } ); + +export const USER_PROFILES_FAILURE = i18n.translate( + 'xpack.securitySolution.containers.detectionEngine.users.userProfiles.title', + { defaultMessage: 'Failed to find users' } +); diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_bulk_actions.tsx index 30e86f6185c3..d468f5b05d86 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_bulk_actions.tsx @@ -12,6 +12,7 @@ import { isEqual } from 'lodash'; import type { Filter } from '@kbn/es-query'; import { useCallback } from 'react'; import type { TableId } from '@kbn/securitysolution-data-table'; +import { useBulkAlertAssigneesItems } from '../../../common/components/toolbar/bulk_actions/use_bulk_alert_assignees_items'; import { useBulkAlertTagsItems } from '../../../common/components/toolbar/bulk_actions/use_bulk_alert_tags_items'; import type { inputsModel, State } from '../../../common/store'; import { useShallowEqualSelector } from '../../../common/hooks/use_selector'; @@ -93,7 +94,11 @@ export const getBulkActionHook = refetch: refetchGlobalQuery, }); - const items = [...alertActions, timelineAction, ...alertTagsItems]; + const { alertAssigneesItems, alertAssigneesPanels } = useBulkAlertAssigneesItems({ + onAssigneesUpdate: refetchGlobalQuery, + }); + + const items = [...alertActions, timelineAction, ...alertTagsItems, ...alertAssigneesItems]; - return [{ id: 0, items }, ...alertTagsPanels]; + return [{ id: 0, items }, ...alertTagsPanels, ...alertAssigneesPanels]; }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx index 1f1ce5618abf..f0ff67c39f0e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx @@ -23,7 +23,6 @@ import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; import { inputsSelectors } from '../../../common/store'; import { formatPageFilterSearchParam } from '../../../../common/utils/format_page_filter_search_param'; import { resolveFlyoutParams } from './utils'; -import { FLYOUT_URL_PARAM } from '../../../flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url'; export const AlertDetailsRedirect = () => { const { alertId } = useParams<{ alertId: string }>(); @@ -72,7 +71,7 @@ export const AlertDetailsRedirect = () => { const pageFiltersQuery = encode(formatPageFilterSearchParam([statusPageFilter])); - const currentFlyoutParams = searchParams.get(FLYOUT_URL_PARAM); + const currentFlyoutParams = searchParams.get(URL_PARAM_KEY.eventFlyout); const [isSecurityFlyoutEnabled] = useUiSetting$(ENABLE_EXPANDABLE_FLYOUT_SETTING); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx index c340c08ad726..aa196b174131 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.test.tsx @@ -33,6 +33,7 @@ import { FilterGroup } from '../../../common/components/filter_group'; import type { AlertsTableComponentProps } from '../../components/alerts_table/alerts_grouping'; import { getMockedFilterGroupWithCustomFilters } from '../../../common/components/filter_group/mocks'; import { TableId } from '@kbn/securitysolution-data-table'; +import { useUpsellingMessage } from '../../../common/hooks/use_upselling'; // Test will fail because we will to need to mock some core services to make the test work // For now let's forget about SiemSearchBar and QueryBar @@ -219,6 +220,7 @@ jest.mock('../../components/alerts_table/timeline_actions/use_add_bulk_to_timeli jest.mock('../../../common/components/visualization_actions/lens_embeddable'); jest.mock('../../../common/components/page/use_refetch_by_session'); +jest.mock('../../../common/hooks/use_upselling'); describe('DetectionEnginePageComponent', () => { beforeAll(() => { @@ -239,6 +241,7 @@ describe('DetectionEnginePageComponent', () => { (FilterGroup as jest.Mock).mockImplementation(() => { return ; }); + (useUpsellingMessage as jest.Mock).mockReturnValue('Go for Platinum!'); }); beforeEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index 8a8b269abf4e..2127e0c4f26a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -31,6 +31,9 @@ import { tableDefaults, TableId, } from '@kbn/securitysolution-data-table'; +import { isEqual } from 'lodash'; +import { FilterByAssigneesPopover } from '../../../common/components/filter_group/filter_by_assignees'; +import type { AssigneesIdsSelection } from '../../../common/components/assignees/types'; import { ALERTS_TABLE_REGISTRY_CONFIG_IDS } from '../../../../common/constants'; import { useDataTableFilters } from '../../../common/hooks/use_data_table_filters'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; @@ -62,6 +65,7 @@ import { showGlobalFilters, } from '../../../timelines/components/timeline/helpers'; import { + buildAlertAssigneesFilter, buildAlertStatusFilter, buildShowBuildingBlockFilter, buildThreatMatchFilter, @@ -135,6 +139,16 @@ const DetectionEnginePageComponent: React.FC = ({ const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } = useListsConfig(); + const [assignees, setAssignees] = useState([]); + const handleSelectedAssignees = useCallback( + (newAssignees: AssigneesIdsSelection[]) => { + if (!isEqual(newAssignees, assignees)) { + setAssignees(newAssignees); + } + }, + [assignees] + ); + const arePageFiltersEnabled = useIsExperimentalFeatureEnabled('alertsPageFiltersEnabled'); // when arePageFiltersEnabled === false @@ -176,8 +190,9 @@ const DetectionEnginePageComponent: React.FC = ({ ...filters, ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), + ...buildAlertAssigneesFilter(assignees), ]; - }, [showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filters]); + }, [assignees, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, filters]); const alertPageFilters = useMemo(() => { if (arePageFiltersEnabled) { @@ -247,8 +262,9 @@ const DetectionEnginePageComponent: React.FC = ({ ...buildShowBuildingBlockFilter(showBuildingBlockAlerts), ...buildThreatMatchFilter(showOnlyThreatIndicatorAlerts), ...(alertPageFilters ?? []), + ...buildAlertAssigneesFilter(assignees), ], - [showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, alertPageFilters] + [assignees, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, alertPageFilters] ); const { signalIndexNeedsInit, pollForSignalIndex } = useSignalHelpers(); @@ -363,16 +379,16 @@ const DetectionEnginePageComponent: React.FC = ({ /> ), [ - topLevelFilters, arePageFiltersEnabled, - statusFilter, + from, onFilterGroupChangedCallback, pageFiltersUpdateHandler, - showUpdating, - from, query, + showUpdating, + statusFilter, timelinesUi, to, + topLevelFilters, updatedAt, ] ); @@ -448,14 +464,24 @@ const DetectionEnginePageComponent: React.FC = ({ > - - {i18n.BUTTON_MANAGE_RULES} - + + + + + + + {i18n.BUTTON_MANAGE_RULES} + + + diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 3acccc3352a4..072649d52a6a 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -21,6 +21,7 @@ import type { import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { Filter } from '@kbn/es-query'; import type { ActionVariables } from '@kbn/triggers-actions-ui-plugin/public'; +import { requiredOptional } from '@kbn/zod-helpers'; import type { ResponseAction } from '../../../../../common/api/detection_engine/model/rule_response_actions'; import { normalizeThresholdField } from '../../../../../common/detection_engine/utils'; import { assertUnreachable } from '../../../../../common/utility_types'; @@ -253,7 +254,7 @@ export const getAboutStepsData = (rule: RuleResponse, detailsView: boolean): Abo tags, riskScore: { value: riskScore, - mapping: riskScoreMapping, + mapping: requiredOptional(riskScoreMapping), isMappingChecked: riskScoreMapping.length > 0, }, falsePositives, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts index 6b92583b1ddd..b4e373499146 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts @@ -11,6 +11,7 @@ import { RISK_ENGINE_ENABLE_URL, RISK_ENGINE_DISABLE_URL, RISK_ENGINE_INIT_URL, + RISK_ENGINE_PRIVILEGES_URL, } from '../../../common/constants'; import { KibanaServices } from '../../common/lib/kibana'; @@ -20,7 +21,8 @@ import type { GetRiskEngineStatusResponse, InitRiskEngineResponse, DisableRiskEngineResponse, -} from '../../../server/lib/entity_analytics/risk_engine/types'; + RiskEnginePrivilegesResponse, +} from '../../../server/lib/entity_analytics/types'; import type { RiskScorePreviewRequestSchema } from '../../../common/risk_engine/risk_score_preview/request_schema'; /** @@ -85,3 +87,13 @@ export const disableRiskEngine = async (): Promise => method: 'POST', }); }; + +/** + * Get risk engine privileges + */ +export const fetchRiskEnginePrivileges = async (): Promise => { + return KibanaServices.get().http.fetch(RISK_ENGINE_PRIVILEGES_URL, { + version: '1', + method: 'GET', + }); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts index 68b63300061b..8b3ca2d0ac2a 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts @@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status'; import type { EnableRiskEngineResponse, EnableDisableRiskEngineErrorResponse, -} from '../../../../server/lib/entity_analytics/risk_engine/types'; +} from '../../../../server/lib/entity_analytics/types'; export const DISABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'DISABLE_RISK_ENGINE']; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts index 40b3f1b4bddb..c4d5070014fc 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts @@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status'; import type { EnableRiskEngineResponse, EnableDisableRiskEngineErrorResponse, -} from '../../../../server/lib/entity_analytics/risk_engine/types'; +} from '../../../../server/lib/entity_analytics/types'; export const ENABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'ENABLE_RISK_ENGINE']; export const useEnableRiskEngineMutation = (options?: UseMutationOptions<{}>) => { diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts index 35b1071b62b8..1e2a695652ed 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts @@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status'; import type { InitRiskEngineResponse, InitRiskEngineError, -} from '../../../../server/lib/entity_analytics/risk_engine/types'; +} from '../../../../server/lib/entity_analytics/types'; export const INIT_RISK_ENGINE_STATUS_KEY = ['POST', 'INIT_RISK_ENGINE']; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_privileges.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_privileges.ts new file mode 100644 index 000000000000..2a3ffa40856c --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_privileges.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useQuery } from '@tanstack/react-query'; +import { fetchRiskEnginePrivileges } from '../api'; + +export const useRiskEnginePrivileges = () => { + return useQuery(['GET', 'FETCH_RISK_ENGINE_PRIVILEGES'], fetchRiskEnginePrivileges); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts b/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts new file mode 100644 index 000000000000..361d6d133a93 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/common/utils.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { euiLightVars } from '@kbn/ui-theme'; +import { RiskSeverity } from '../../../common/search_strategy'; +import { SEVERITY_COLOR } from '../../overview/components/detection_response/utils'; + +export const SEVERITY_UI_SORT_ORDER = [ + RiskSeverity.unknown, + RiskSeverity.low, + RiskSeverity.moderate, + RiskSeverity.high, + RiskSeverity.critical, +]; + +export const RISK_SEVERITY_COLOUR: { [k in RiskSeverity]: string } = { + [RiskSeverity.unknown]: euiLightVars.euiColorMediumShade, + [RiskSeverity.low]: SEVERITY_COLOR.low, + [RiskSeverity.moderate]: SEVERITY_COLOR.medium, + [RiskSeverity.high]: SEVERITY_COLOR.high, + [RiskSeverity.critical]: SEVERITY_COLOR.critical, +}; + +export const RISK_SCORE_RANGES = { + [RiskSeverity.unknown]: { start: 0, stop: 20 }, + [RiskSeverity.low]: { start: 20, stop: 40 }, + [RiskSeverity.moderate]: { start: 40, stop: 70 }, + [RiskSeverity.high]: { start: 70, stop: 90 }, + [RiskSeverity.critical]: { start: 90, stop: 100 }, +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/index.tsx new file mode 100644 index 000000000000..f26814431b36 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { RiskEnginePrivilegesCallOut } from './risk_engine_privileges_callout'; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/risk_engine_privileges_callout.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/risk_engine_privileges_callout.tsx new file mode 100644 index 000000000000..edb6bc11f721 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/risk_engine_privileges_callout.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { CallOutMessage } from '../../../common/components/callouts'; +import { CallOutSwitcher } from '../../../common/components/callouts'; +import { MissingPrivilegesCallOutBody, MISSING_PRIVILEGES_CALLOUT_TITLE } from './translations'; +import { useMissingPrivileges } from './use_missing_risk_engine_privileges'; + +export const RiskEnginePrivilegesCallOut = () => { + const privileges = useMissingPrivileges(); + + if (privileges.isLoading || privileges.hasAllRequiredPrivileges) { + return null; + } + + const message: CallOutMessage = { + type: 'primary', + id: `missing-risk-engine-privileges`, + title: MISSING_PRIVILEGES_CALLOUT_TITLE, + description: , + }; + + return ( + message && + ); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/translations.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/translations.tsx new file mode 100644 index 000000000000..ed58f50f2827 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/translations.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCode, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; +import { useKibana } from '../../../common/lib/kibana'; +import { CommaSeparatedValues } from '../../../detections/components/callouts/missing_privileges_callout/comma_separated_values'; +import type { MissingPrivileges } from './use_missing_risk_engine_privileges'; + +export const MISSING_PRIVILEGES_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.riskEngine.missingPrivilegesCallOut.messageTitle', + { + defaultMessage: 'Insufficient privileges', + } +); + +export const MissingPrivilegesCallOutBody: React.FC = ({ + indexPrivileges, + clusterPrivileges, +}) => { + const { docLinks } = useKibana().services; + + return ( + + + + + ), + }} + /> +

    + ), + indexPrivileges: + indexPrivileges.length > 0 ? ( + <> + +
      + {indexPrivileges.map(([index, missingPrivileges]) => ( +
    • {missingIndexPrivileges(index, missingPrivileges)}
    • + ))} +
    + + ) : null, + clusterPrivileges: + clusterPrivileges.length > 0 ? ( + <> + +
      + {clusterPrivileges.map((privilege) => ( +
    • {privilege}
    • + ))} +
    + + ) : null, + }} + /> + ); +}; + +const missingIndexPrivileges = (index: string, privileges: string[]) => ( + , + index: {index}, + }} + /> +); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/use_missing_risk_engine_privileges.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/use_missing_risk_engine_privileges.ts new file mode 100644 index 000000000000..adef9e3e4909 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_engine_privileges_callout/use_missing_risk_engine_privileges.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMemo } from 'react'; +import type { RiskEnginePrivilegesResponse } from '../../../../server/lib/entity_analytics/types'; +import { useRiskEnginePrivileges } from '../../api/hooks/use_risk_engine_privileges'; +import { + RISK_ENGINE_REQUIRED_ES_CLUSTER_PRIVILEGES, + RISK_ENGINE_REQUIRED_ES_INDEX_PRIVILEGES, +} from '../../../../common/risk_engine'; + +const getMissingIndexPrivileges = ( + privileges: RiskEnginePrivilegesResponse['privileges']['elasticsearch']['index'] +): MissingIndexPrivileges => { + const missingIndexPrivileges: MissingIndexPrivileges = []; + + for (const [indexName, requiredPrivileges] of Object.entries( + RISK_ENGINE_REQUIRED_ES_INDEX_PRIVILEGES + )) { + const missingPrivileges = requiredPrivileges.filter( + (privilege) => !privileges[indexName][privilege] + ); + + if (missingPrivileges.length) { + missingIndexPrivileges.push([indexName, missingPrivileges]); + } + } + + return missingIndexPrivileges; +}; + +export type MissingClusterPrivileges = string[]; +export type MissingIndexPrivileges = Array<[indexName: string, privileges: string[]]>; + +export interface MissingPrivileges { + clusterPrivileges: MissingClusterPrivileges; + indexPrivileges: MissingIndexPrivileges; +} + +export type MissingPrivilegesResponse = + | { isLoading: true } + | { isLoading: false; hasAllRequiredPrivileges: true } + | { isLoading: false; missingPrivileges: MissingPrivileges; hasAllRequiredPrivileges: false }; + +export const useMissingPrivileges = (): MissingPrivilegesResponse => { + const { data: privilegesResponse, isLoading } = useRiskEnginePrivileges(); + + return useMemo(() => { + if (isLoading || !privilegesResponse) { + return { + isLoading: true, + }; + } + + if (privilegesResponse.has_all_required) { + return { + isLoading: false, + hasAllRequiredPrivileges: true, + }; + } + + const { privileges } = privilegesResponse; + const missinIndexPrivileges = getMissingIndexPrivileges(privileges.elasticsearch.index); + const missingClusterPrivileges = RISK_ENGINE_REQUIRED_ES_CLUSTER_PRIVILEGES.filter( + (privilege) => !privileges.elasticsearch.cluster[privilege] + ); + + return { + isLoading: false, + hasAllRequiredPrivileges: false, + missingPrivileges: { + indexPrivileges: missinIndexPrivileges, + clusterPrivileges: missingClusterPrivileges, + }, + }; + }, [isLoading, privilegesResponse]); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx index bd0b0e262e3c..b5ccc1b8daa6 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx @@ -29,11 +29,8 @@ import { EuiAccordion, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - DETECTION_ENTITY_DASHBOARD, - RISKY_HOSTS_DOC_LINK, - RISKY_USERS_DOC_LINK, -} from '../../../common/constants'; +import { LinkAnchor } from '@kbn/security-solution-navigation/links'; +import { SecurityPageName } from '@kbn/security-solution-navigation'; import * as i18n from '../translations'; import { useRiskEngineStatus } from '../api/hooks/use_risk_engine_status'; import { useInitRiskEngineMutation } from '../api/hooks/use_init_risk_engine_mutation'; @@ -41,20 +38,8 @@ import { useEnableRiskEngineMutation } from '../api/hooks/use_enable_risk_engine import { useDisableRiskEngineMutation } from '../api/hooks/use_disable_risk_engine_mutation'; import { RiskEngineStatus, MAX_SPACES_COUNT } from '../../../common/risk_engine'; -const docsLinks = [ - { - link: DETECTION_ENTITY_DASHBOARD, - label: i18n.EA_DOCS_DASHBOARD, - }, - { - link: RISKY_HOSTS_DOC_LINK, - label: i18n.EA_DOCS_RISK_HOSTS, - }, - { - link: RISKY_USERS_DOC_LINK, - label: i18n.EA_DOCS_RISK_USERS, - }, -]; +import { RiskInformationFlyout } from '../../explore/components/risk_score/risk_information'; +import { useOnOpenCloseHandler } from '../../helper_hooks'; const MIN_WIDTH_TO_PREVENT_LABEL_FROM_MOVING = '50px'; @@ -209,6 +194,8 @@ export const RiskScoreEnableSection = () => { const closeModal = () => setIsModalVisible(false); const showModal = () => setIsModalVisible(true); + const [isFlyoutVisible, handleOnOpen, handleOnClose] = useOnOpenCloseHandler(); + const isLoading = initRiskEngineMutation.isLoading || enableRiskEngineMutation.isLoading || @@ -309,7 +296,11 @@ export const RiskScoreEnableSection = () => { )} {!isUpdateAvailable && ( - {isLoading && } + + {isLoading && ( + + )} + {
      - {docsLinks.map(({ link, label }) => ( -
    • - - {label} - - -
    • - ))} +
    • + {i18n.EA_DASHBOARD_LINK} + +
    • +
    • + + {i18n.EA_DOCS_ENTITY_RISK_SCORE} + + {isFlyoutVisible && } + +
    diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx index 4f2bacf97f02..7bc395d27975 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_management_page.tsx @@ -12,10 +12,16 @@ import { RiskScorePreviewSection } from '../components/risk_score_preview_sectio import { RiskScoreEnableSection } from '../components/risk_score_enable_section'; import { ENTITY_ANALYTICS_RISK_SCORE } from '../../app/translations'; import { BETA } from '../../common/translations'; +import { RiskEnginePrivilegesCallOut } from '../components/risk_engine_privileges_callout'; +import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; export const EntityAnalyticsManagementPage = () => { + const privilegesCalloutEnabled = useIsExperimentalFeatureEnabled( + 'riskEnginePrivilegesRouteEnabled' + ); return ( <> + {privilegesCalloutEnabled && } { - const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } = - useListsConfig(); - const hasEndpointExceptionCapability = useHasSecurityCapability(capability); - - return useMemo( - () => !listsConfigLoading && !needsListsConfiguration && hasEndpointExceptionCapability, - [hasEndpointExceptionCapability, listsConfigLoading, needsListsConfiguration] - ); +): boolean => { + return useHasSecurityCapability(capability); }; diff --git a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap index b9fd26239a82..cebd8a483aaf 100644 --- a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap @@ -105,7 +105,7 @@ exports[`Authentication Host Table Component rendering it renders the host authe class="euiFlexItem emotion-euiFlexItem-grow-1" >

    > => [ +const getTableColumns = (riskEntity?: RiskScoreEntity): Array> => [ { field: 'level', name: i18n.INFORMATION_LEVEL_HEADER, @@ -85,9 +85,7 @@ export const RiskInformationButtonIcon = ({ riskEntity }: { riskEntity: RiskScor } data-test-subj="open-risk-information-flyout-trigger" /> - {isFlyoutVisible && ( - - )} + {isFlyoutVisible && } ); }; @@ -100,20 +98,12 @@ export const RiskInformationButtonEmpty = ({ riskEntity }: { riskEntity: RiskSco {i18n.INFO_BUTTON_TEXT} - {isFlyoutVisible && ( - - )} + {isFlyoutVisible && } ); }; -const RiskInformationFlyout = ({ - handleOnClose, - riskEntity, -}: { - handleOnClose: () => void; - riskEntity: RiskScoreEntity; -}) => { +export const RiskInformationFlyout = ({ handleOnClose }: { handleOnClose: () => void }) => { const { euiTheme } = useEuiTheme(); const simpleFlyoutTitleId = useGeneratedHtmlId({ prefix: 'RiskInformation', @@ -157,15 +147,13 @@ const RiskInformationFlyout = ({

    ), @@ -176,15 +164,13 @@ const RiskInformationFlyout = ({ ), @@ -236,26 +222,22 @@ const RiskInformationFlyout = ({

    } /> diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_information/translations.ts b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_information/translations.ts index 112c6d37ca4a..20fa22bbc26f 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_information/translations.ts +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_information/translations.ts @@ -23,7 +23,7 @@ export const INFORMATION_ARIA_LABEL = i18n.translate( } ); -export const INFORMATION_RISK_HEADER = (riskEntity: RiskScoreEntity) => +export const INFORMATION_RISK_HEADER = (riskEntity?: RiskScoreEntity) => i18n.translate('xpack.securitySolution.riskInformation.riskHeader', { defaultMessage: '{riskEntity} risk score range', values: { diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_doc_link.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_doc_link.tsx index cae89799d2d1..a54bb9e62762 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_doc_link.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/risk_score_onboarding/risk_score_doc_link.tsx @@ -6,23 +6,36 @@ */ import { EuiLink } from '@elastic/eui'; -import React from 'react'; +import React, { useMemo } from 'react'; import { RiskScoreEntity } from '../../../../../common/search_strategy'; -import { RISKY_HOSTS_DOC_LINK, RISKY_USERS_DOC_LINK } from '../../../../../common/constants'; import { LEARN_MORE } from '../../../../overview/components/entity_analytics/risk_score/translations'; +import { useKibana } from '../../../../common/lib/kibana'; + +const useLearnMoreLinkForEntity = (riskScoreEntity?: RiskScoreEntity) => { + const { docLinks } = useKibana().services; + const entityAnalyticsLinks = docLinks.links.securitySolution.entityAnalytics; + return useMemo(() => { + if (!riskScoreEntity) { + return entityAnalyticsLinks.entityRiskScoring; + } + if (riskScoreEntity === RiskScoreEntity.user) { + return entityAnalyticsLinks.userRiskScore; + } + return entityAnalyticsLinks.hostRiskScore; + }, [riskScoreEntity, entityAnalyticsLinks]); +}; const RiskScoreDocLinkComponent = ({ riskScoreEntity, title, }: { - riskScoreEntity: RiskScoreEntity; + riskScoreEntity?: RiskScoreEntity; title?: string | React.ReactNode; }) => { - const docLink = - riskScoreEntity === RiskScoreEntity.user ? RISKY_USERS_DOC_LINK : RISKY_HOSTS_DOC_LINK; + const learnMoreLink = useLearnMoreLinkForEntity(riskScoreEntity); return ( - + {title ? title : LEARN_MORE(riskScoreEntity)} ); diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/common/index.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/common/index.tsx index b28898b384e0..9430690394b4 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/common/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/common/index.tsx @@ -12,17 +12,9 @@ import { EuiHealth, transparentize } from '@elastic/eui'; import styled, { css } from 'styled-components'; import { euiLightVars } from '@kbn/ui-theme'; +import { RISK_SEVERITY_COLOUR } from '../../../../../entity_analytics/common/utils'; import { WithHoverActions } from '../../../../../common/components/with_hover_actions'; -import { RiskSeverity } from '../../../../../../common/search_strategy'; -import { SEVERITY_COLOR } from '../../../../../overview/components/detection_response/utils'; - -export const RISK_SEVERITY_COLOUR: { [k in RiskSeverity]: string } = { - [RiskSeverity.unknown]: euiLightVars.euiColorMediumShade, - [RiskSeverity.low]: SEVERITY_COLOR.low, - [RiskSeverity.moderate]: SEVERITY_COLOR.medium, - [RiskSeverity.high]: SEVERITY_COLOR.high, - [RiskSeverity.critical]: SEVERITY_COLOR.critical, -}; +import type { RiskSeverity } from '../../../../../../common/search_strategy'; const RiskBadge = styled.div<{ $severity: RiskSeverity; $hideBackgroundColor: boolean }>` ${({ theme, $severity, $hideBackgroundColor }) => css` diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_badges.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_badges.tsx index f1ebae089759..53c7e270f2e3 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_badges.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_badges.tsx @@ -7,8 +7,9 @@ import { EuiFlexGroup, EuiNotificationBadge, EuiFlexItem } from '@elastic/eui'; import React from 'react'; +import { RISK_SEVERITY_COLOUR } from '../../../../entity_analytics/common/utils'; import type { RiskSeverity } from '../../../../../common/search_strategy'; -import { RiskScoreLevel, RISK_SEVERITY_COLOUR } from './common'; +import { RiskScoreLevel } from './common'; import type { SeverityCount } from './types'; export const SeverityBadges: React.FC<{ diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_bar.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_bar.tsx index d53693b6d8e6..847488869bcd 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_bar.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_bar.tsx @@ -9,8 +9,8 @@ import styled from 'styled-components'; import { EuiColorPaletteDisplay } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { RISK_SEVERITY_COLOUR } from '../../../../entity_analytics/common/utils'; import type { RiskSeverity } from '../../../../../common/search_strategy'; -import { RISK_SEVERITY_COLOUR } from './common'; import type { SeverityCount } from './types'; const StyledEuiColorPaletteDisplay = styled(EuiColorPaletteDisplay)` diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_filter_group.tsx b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_filter_group.tsx index 02ce5e01e887..1ca7020bc818 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_filter_group.tsx +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/severity/severity_filter_group.tsx @@ -16,8 +16,8 @@ import { useEuiTheme, } from '@elastic/eui'; +import { SEVERITY_UI_SORT_ORDER } from '../../../../entity_analytics/common/utils'; import type { RiskScoreEntity, RiskSeverity } from '../../../../../common/search_strategy'; -import { SEVERITY_UI_SORT_ORDER } from '../../../../../common/search_strategy'; import type { SeverityCount } from './types'; import { RiskScoreLevel } from './common'; import { ENTITY_RISK_LEVEL } from '../translations'; diff --git a/x-pack/plugins/security_solution/public/explore/components/risk_score/translations.ts b/x-pack/plugins/security_solution/public/explore/components/risk_score/translations.ts index 501de5719a63..d072607544d4 100644 --- a/x-pack/plugins/security_solution/public/explore/components/risk_score/translations.ts +++ b/x-pack/plugins/security_solution/public/explore/components/risk_score/translations.ts @@ -24,6 +24,14 @@ export const USERS = i18n.translate('xpack.securitySolution.riskScore.overview.u defaultMessage: 'Users', }); +export const ENTITY = i18n.translate('xpack.securitySolution.riskScore.overview.entityTitle', { + defaultMessage: 'Entity', +}); + +export const ENTITIES = i18n.translate('xpack.securitySolution.riskScore.overview.entities', { + defaultMessage: 'Entities', +}); + export const RISK_SCORE_TITLE = (riskEntity: RiskScoreEntity) => i18n.translate('xpack.securitySolution.riskScore.overview.riskScoreTitle', { defaultMessage: '{riskEntity} Risk Score', @@ -41,22 +49,26 @@ export const ENTITY_RISK_LEVEL = (riskEntity: RiskScoreEntity) => }); export const getRiskEntityTranslation = ( - riskEntity: RiskScoreEntity, + riskEntity?: RiskScoreEntity, lowercase = false, plural = false ) => { - if (lowercase) { - if (plural) { - return (riskEntity === RiskScoreEntity.host ? HOSTS : USERS).toLowerCase(); - } + const text = getRiskEntityTranslationText(riskEntity, plural); + return lowercase ? text.toLowerCase() : text; +}; - return (riskEntity === RiskScoreEntity.host ? HOST : USER).toLowerCase(); - } - if (plural) { - return riskEntity === RiskScoreEntity.host ? HOSTS : USERS; +export const getRiskEntityTranslationText = ( + riskEntity: RiskScoreEntity | undefined, + plural: boolean +) => { + switch (riskEntity) { + case RiskScoreEntity.host: + return plural ? HOSTS : HOST; + case RiskScoreEntity.user: + return plural ? USERS : USER; + default: + return plural ? ENTITIES : ENTITY; } - - return riskEntity === RiskScoreEntity.host ? HOST : USER; }; export const ALERTS = i18n.translate('xpack.securitySolution.riskScore.overview.alerts', { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx index 0684bf05b792..b4a97832e77c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx @@ -8,7 +8,7 @@ import type { FC } from 'react'; import React, { useCallback } from 'react'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; -import { RightPanelKey } from '../right'; +import { DocumentDetailsRightPanelKey } from '../right'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import { EndpointIsolateSuccess } from '../../../common/components/endpoint/host_isolation'; import { useHostIsolationTools } from '../../../timelines/components/side_panel/event_details/use_host_isolation_tools'; @@ -32,7 +32,7 @@ export const PanelContent: FC = () => { const showAlertDetails = useCallback( () => openRightPanel({ - id: RightPanelKey, + id: DocumentDetailsRightPanelKey, params: { id: eventId, indexName, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/index.tsx index ff02d7b78a11..b56282a54264 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/index.tsx @@ -11,7 +11,8 @@ import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; import { PanelContent } from './content'; import { PanelHeader } from './header'; -export const IsolateHostPanelKey: IsolateHostPanelProps['key'] = 'document-details-isolate-host'; +export const DocumentDetailsIsolateHostPanelKey: IsolateHostPanelProps['key'] = + 'document-details-isolate-host'; export interface IsolateHostPanelProps extends FlyoutPanelProps { key: 'document-details-isolate-host'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx index bdfb03639382..3f68ef15956e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx @@ -195,7 +195,7 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s const relatedUsersCount = useMemo( () => ( - + diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.test.tsx index 95b4e0a60059..7ba849e1fec1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.test.tsx @@ -18,6 +18,7 @@ jest.mock('../../shared/hooks/use_investigation_guide'); const NO_DATA_TEXT = "There's no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one."; +const PREVIEW_MESSAGE = 'Investigation guide is not available in alert preview.'; const renderInvestigationGuide = (context: LeftPanelContext = mockContextValue) => ( @@ -76,4 +77,15 @@ describe('', () => { const { getByTestId } = render(renderInvestigationGuide()); expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_TEXT); }); + + it('should render preview message when flyout is in preview', () => { + (useInvestigationGuide as jest.Mock).mockReturnValue({ + loading: false, + error: true, + }); + const { getByTestId } = render( + renderInvestigationGuide({ ...mockContextValue, isPreview: true }) + ); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(PREVIEW_MESSAGE); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx index bffe966b944b..d061cbb25c4c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx @@ -18,7 +18,7 @@ import { FlyoutLoading } from '../../../shared/components/flyout_loading'; * Renders a message saying the guide hasn't been set up or the full investigation guide. */ export const InvestigationGuide: React.FC = () => { - const { dataFormattedForFieldBrowser } = useLeftPanelContext(); + const { dataFormattedForFieldBrowser, isPreview } = useLeftPanelContext(); const { loading, error, basicAlertData, ruleNote } = useInvestigationGuide({ dataFormattedForFieldBrowser, @@ -26,7 +26,12 @@ export const InvestigationGuide: React.FC = () => { return (
    - {loading ? ( + {isPreview ? ( + + ) : loading ? ( ) : !error && basicAlertData.ruleId && ruleNote ? ( { const NO_DATA_MESSAGE = "There are no response actions defined for this event. To add some, edit the rule's settings and set up response actionsExternal link(opens in a new tab or window)."; +const PREVIEW_MESSAGE = 'Response is not available in alert preview.'; const defaultContextValue = { dataAsNestedObject: { @@ -139,4 +140,10 @@ describe('', () => { expect(wrapper.getByTestId(RESPONSE_DETAILS_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); + + it('should render preview message if flyout is in preview', () => { + const wrapper = renderResponseDetails({ ...defaultContextValue, isPreview: true }); + expect(wrapper.getByTestId(RESPONSE_DETAILS_TEST_ID)).toBeInTheDocument(); + expect(wrapper.getByTestId(RESPONSE_DETAILS_TEST_ID)).toHaveTextContent(PREVIEW_MESSAGE); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/response_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/response_details.tsx index 9e2ab547e9af..8caaad722505 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/response_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/response_details.tsx @@ -24,7 +24,7 @@ const ExtendedFlyoutWrapper = styled.div` * Automated response actions results, displayed in the document details expandable flyout left section under the Insights tab, Response tab */ export const ResponseDetails: React.FC = () => { - const { searchHit, dataAsNestedObject } = useLeftPanelContext(); + const { searchHit, dataAsNestedObject, isPreview } = useLeftPanelContext(); const endpointResponseActionsEnabled = useIsExperimentalFeatureEnabled( 'endpointResponseActionsEnabled' ); @@ -40,19 +40,28 @@ export const ResponseDetails: React.FC = () => { return (
    - -
    - -
    -
    - + {isPreview ? ( + + ) : ( + <> + +
    + +
    +
    + - - {endpointResponseActionsEnabled ? responseActionsView?.content : osqueryView?.content} - + + {endpointResponseActionsEnabled ? responseActionsView?.content : osqueryView?.content} + + + )}
    ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/test_ids.ts index b36f674892f5..1ac4fb1c5f26 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/test_ids.ts @@ -11,7 +11,6 @@ import { PREFIX } from '../../../shared/test_ids'; export const ANALYZER_GRAPH_TEST_ID = `${PREFIX}AnalyzerGraph` as const; export const SESSION_VIEW_TEST_ID = `${PREFIX}SessionView` as const; -export const SESSION_VIEW_ERROR_TEST_ID = `${PREFIX}SessionViewError` as const; /* Insights tab */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx index daa58fc4d037..1758bbc5b05d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx @@ -196,7 +196,7 @@ export const UserDetails: React.FC = ({ userName, timestamp, s const relatedHostsCount = useMemo( () => ( - + diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/context.tsx index 6dd0f65af492..52bf50946269 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/context.tsx @@ -8,6 +8,7 @@ import type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import React, { createContext, memo, useContext, useMemo } from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { TableId } from '@kbn/securitysolution-data-table'; import { useEventDetails } from '../shared/hooks/use_event_details'; import { FlyoutError } from '../../shared/components/flyout_error'; import { FlyoutLoading } from '../../shared/components/flyout_loading'; @@ -54,6 +55,10 @@ export interface LeftPanelContext { * Retrieves searchHit values for the provided field */ getFieldsData: GetFieldsData; + /** + * Boolean to indicate whether it is a preview flyout + */ + isPreview: boolean; } export const LeftPanelContext = createContext(undefined); @@ -97,6 +102,7 @@ export const LeftPanelProvider = memo( searchHit, investigationFields: maybeRule?.investigation_fields?.field_names ?? [], getFieldsData, + isPreview: scopeId === TableId.rulePreview, } : undefined, [ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx index a6e4e865adfa..049210326c01 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx @@ -16,7 +16,7 @@ import { tabs } from './tabs'; import { useLeftPanelContext } from './context'; export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response'; -export const LeftPanelKey: LeftPanelProps['key'] = 'document-details-left'; +export const DocumentDetailsLeftPanelKey: LeftPanelProps['key'] = 'document-details-left'; export const LeftPanelVisualizeTab: LeftPanelPaths = 'visualize'; export const LeftPanelInsightsTab: LeftPanelPaths = 'insights'; export const LeftPanelInvestigationTab: LeftPanelPaths = 'investigation'; @@ -45,7 +45,7 @@ export const LeftPanel: FC> = memo(({ path }) => { const setSelectedTabId = (tabId: LeftPanelTabsType[number]['id']) => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: tabId, }, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/mocks/mock_context.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/mocks/mock_context.ts index 4233a28c1164..4892d7d4dfa0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/mocks/mock_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/mocks/mock_context.ts @@ -25,4 +25,5 @@ export const mockContextValue: LeftPanelContext = { searchHit: mockSearchHit, dataAsNestedObject: mockDataAsNestedObject, investigationFields: [], + isPreview: false, }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx index 3e8c1f22de62..3964f87e9bde 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx @@ -5,13 +5,13 @@ * 2.0. */ -import React, { memo, useCallback, useState, useEffect } from 'react'; +import React, { memo, useCallback } from 'react'; import { EuiButtonGroup, EuiSpacer } from '@elastic/eui'; import type { EuiButtonGroupOptionProps } from '@elastic/eui/src/components/button/button_group/button_group'; -import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { INSIGHTS_TAB_BUTTON_GROUP_TEST_ID, INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID, @@ -20,7 +20,7 @@ import { INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID, } from './test_ids'; import { useLeftPanelContext } from '../context'; -import { LeftPanelKey, LeftPanelInsightsTab } from '..'; +import { DocumentDetailsLeftPanelKey, LeftPanelInsightsTab } from '..'; import { ENTITIES_TAB_ID, EntitiesDetails } from '../components/entities_details'; import { THREAT_INTELLIGENCE_TAB_ID, @@ -77,16 +77,13 @@ const insightsButtons: EuiButtonGroupOptionProps[] = [ */ export const InsightsTab: React.FC = memo(() => { const { eventId, indexName, scopeId } = useLeftPanelContext(); - const { panels, openLeftPanel } = useExpandableFlyoutContext(); - const [activeInsightsId, setActiveInsightsId] = useState( - panels.left?.path?.subTab ?? ENTITIES_TAB_ID - ); + const { openLeftPanel, panels } = useExpandableFlyoutContext(); + const activeInsightsId = panels.left?.path?.subTab ?? ENTITIES_TAB_ID; const onChangeCompressed = useCallback( (optionId: string) => { - setActiveInsightsId(optionId); openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: optionId, @@ -101,12 +98,6 @@ export const InsightsTab: React.FC = memo(() => { [eventId, indexName, scopeId, openLeftPanel] ); - useEffect(() => { - if (panels.left?.path?.subTab) { - setActiveInsightsId(panels.left?.path?.subTab); - } - }, [panels.left?.path?.subTab]); - return ( <> { startTransaction({ name: ALERTS_ACTIONS.OPEN_ANALYZER }); } openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelVisualizeTab, subTab: optionId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx index 6e4d9221421e..6f679df0c5e9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx @@ -34,6 +34,14 @@ const panelViewStyle = css` font-size: 90% !important; } text-overflow: ellipsis; + .euiFlexGroup { + flex-wrap: inherit; + } + + .euiFlexItem { + inline-size: inherit; + flex-basis: inherit; + } `; /** diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/index.tsx index db9f7bb5ba58..5bc4ebf31ab4 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/index.tsx @@ -13,7 +13,7 @@ import { panels } from './panels'; export type PreviewPanelPaths = 'rule-preview' | 'alert-reason-preview'; export const RulePreviewPanel: PreviewPanelPaths = 'rule-preview'; export const AlertReasonPreviewPanel: PreviewPanelPaths = 'alert-reason-preview'; -export const PreviewPanelKey: PreviewPanelProps['key'] = 'document-details-preview'; +export const DocumentDetailsPreviewPanelKey: PreviewPanelProps['key'] = 'document-details-preview'; export interface PreviewPanelProps extends FlyoutPanelProps { key: 'document-details-preview'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx index 5b27fd70781d..b8c2672af1dc 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx @@ -53,10 +53,10 @@ const panelContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, }; -const renderAnalyzerPreview = () => +const renderAnalyzerPreview = (context = panelContextValue) => render( - + @@ -117,7 +117,7 @@ describe('AnalyzerPreviewContainer', () => { ).toHaveTextContent(NO_ANALYZER_MESSAGE); }); - it('should navigate to left section Visualize tab when clicking on title', () => { + it('should navigate to analyzer in timeline when clicking on title', () => { (isInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true); (useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({ loading: false, @@ -136,4 +136,24 @@ describe('AnalyzerPreviewContainer', () => { getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)).click(); expect(investigateInTimelineAlertClick).toHaveBeenCalled(); }); + + it('should not navigate to analyzer when in preview and clicking on title', () => { + (isInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(true); + (useAlertPrevalenceFromProcessTree as jest.Mock).mockReturnValue({ + loading: false, + error: false, + alertIds: ['alertid'], + statsNodes: mock.mockStatsNodes, + }); + (useInvestigateInTimeline as jest.Mock).mockReturnValue({ + investigateInTimelineAlertClick: jest.fn(), + }); + + const { queryByTestId } = renderAnalyzerPreview({ ...panelContextValue, isPreview: true }); + expect( + queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + const { investigateInTimelineAlertClick } = useInvestigateInTimeline({}); + expect(investigateInTimelineAlertClick).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx index ac8e21d3fde0..843abeb7018e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx @@ -27,7 +27,7 @@ const timelineId = 'timeline-1'; * Analyzer preview under Overview, Visualizations. It shows a tree representation of analyzer. */ export const AnalyzerPreviewContainer: React.FC = () => { - const { dataAsNestedObject } = useRightPanelContext(); + const { dataAsNestedObject, isPreview } = useRightPanelContext(); // decide whether to show the analyzer preview or not const isEnabled = isInvestigateInResolverActionEnabled(dataAsNestedObject); @@ -64,17 +64,18 @@ export const AnalyzerPreviewContainer: React.FC = () => { /> ), iconType: 'timeline', - ...(isEnabled && { - link: { - callback: goToAnalyzerTab, - tooltip: ( - - ), - }, - }), + ...(isEnabled && + !isPreview && { + link: { + callback: goToAnalyzerTab, + tooltip: ( + + ), + }, + }), }} data-test-subj={ANALYZER_PREVIEW_TEST_ID} > diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.test.tsx new file mode 100644 index 000000000000..0753c6f613cb --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.test.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { ASSIGNEES_ADD_BUTTON_TEST_ID, ASSIGNEES_TITLE_TEST_ID } from './test_ids'; +import { Assignees } from './assignees'; + +import { useGetCurrentUserProfile } from '../../../../common/components/user_profiles/use_get_current_user_profile'; +import { useBulkGetUserProfiles } from '../../../../common/components/user_profiles/use_bulk_get_user_profiles'; +import { useSuggestUsers } from '../../../../common/components/user_profiles/use_suggest_users'; +import type { SetAlertAssigneesFunc } from '../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'; +import { useSetAlertAssignees } from '../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'; +import { TestProviders } from '../../../../common/mock'; +import { ASSIGNEES_APPLY_BUTTON_TEST_ID } from '../../../../common/components/assignees/test_ids'; +import { useLicense } from '../../../../common/hooks/use_license'; +import { useUpsellingMessage } from '../../../../common/hooks/use_upselling'; +import { + USERS_AVATARS_COUNT_BADGE_TEST_ID, + USERS_AVATARS_PANEL_TEST_ID, + USER_AVATAR_ITEM_TEST_ID, +} from '../../../../common/components/user_profiles/test_ids'; +import { useAlertsPrivileges } from '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; + +jest.mock('../../../../common/components/user_profiles/use_get_current_user_profile'); +jest.mock('../../../../common/components/user_profiles/use_bulk_get_user_profiles'); +jest.mock('../../../../common/components/user_profiles/use_suggest_users'); +jest.mock('../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'); +jest.mock('../../../../common/hooks/use_license'); +jest.mock('../../../../common/hooks/use_upselling'); +jest.mock('../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'); + +const mockUserProfiles = [ + { uid: 'user-id-1', enabled: true, user: { username: 'user1', full_name: 'User 1' }, data: {} }, + { uid: 'user-id-2', enabled: true, user: { username: 'user2', full_name: 'User 2' }, data: {} }, + { uid: 'user-id-3', enabled: true, user: { username: 'user3', full_name: 'User 3' }, data: {} }, +]; + +const renderAssignees = ( + eventId = 'event-1', + alertAssignees = ['user-id-1'], + onAssigneesUpdated = jest.fn() +) => { + const assignedProfiles = mockUserProfiles.filter((user) => alertAssignees.includes(user.uid)); + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: assignedProfiles, + }); + return render( + + + + ); +}; + +describe('', () => { + let setAlertAssigneesMock: jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + (useGetCurrentUserProfile as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles[0], + }); + (useSuggestUsers as jest.Mock).mockReturnValue({ + isLoading: false, + data: mockUserProfiles, + }); + (useAlertsPrivileges as jest.Mock).mockReturnValue({ hasIndexWrite: true }); + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => true }); + (useUpsellingMessage as jest.Mock).mockReturnValue('Go for Platinum!'); + + setAlertAssigneesMock = jest.fn().mockReturnValue(Promise.resolve()); + (useSetAlertAssignees as jest.Mock).mockReturnValue(setAlertAssigneesMock); + }); + + it('should render component', () => { + const { getByTestId } = renderAssignees(); + + expect(getByTestId(ASSIGNEES_TITLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(USERS_AVATARS_PANEL_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).not.toBeDisabled(); + }); + + it('should render assignees avatars', () => { + const assignees = ['user-id-1', 'user-id-2']; + const { getByTestId, queryByTestId } = renderAssignees('test-event', assignees); + + expect(getByTestId(USER_AVATAR_ITEM_TEST_ID('user1'))).toBeInTheDocument(); + expect(getByTestId(USER_AVATAR_ITEM_TEST_ID('user2'))).toBeInTheDocument(); + + expect(queryByTestId(USERS_AVATARS_COUNT_BADGE_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should render badge with assignees count in case there are more than two users assigned to an alert', () => { + const assignees = ['user-id-1', 'user-id-2', 'user-id-3']; + const { getByTestId, queryByTestId } = renderAssignees('test-event', assignees); + + const assigneesCountBadge = getByTestId(USERS_AVATARS_COUNT_BADGE_TEST_ID); + expect(assigneesCountBadge).toBeInTheDocument(); + expect(assigneesCountBadge).toHaveTextContent(`${assignees.length}`); + + expect(queryByTestId(USER_AVATAR_ITEM_TEST_ID('user1'))).not.toBeInTheDocument(); + expect(queryByTestId(USER_AVATAR_ITEM_TEST_ID('user2'))).not.toBeInTheDocument(); + expect(queryByTestId(USER_AVATAR_ITEM_TEST_ID('user3'))).not.toBeInTheDocument(); + }); + + it('should call assignees update functionality with the right arguments', () => { + const assignedProfiles = [mockUserProfiles[0], mockUserProfiles[1]]; + (useBulkGetUserProfiles as jest.Mock).mockReturnValue({ + isLoading: false, + data: assignedProfiles, + }); + + const assignees = assignedProfiles.map((assignee) => assignee.uid); + const { getByTestId, getByText } = renderAssignees('test-event', assignees); + + // Update assignees + getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID).click(); + getByText('User 1').click(); + getByText('User 3').click(); + + // Apply assignees + getByTestId(ASSIGNEES_APPLY_BUTTON_TEST_ID).click(); + + expect(setAlertAssigneesMock).toHaveBeenCalledWith( + { + add: ['user-id-3'], + remove: ['user-id-1'], + }, + ['test-event'], + expect.anything(), + expect.anything() + ); + }); + + it('should render add assignees button as disabled if user has readonly priviliges', () => { + (useAlertsPrivileges as jest.Mock).mockReturnValue({ hasIndexWrite: false }); + + const assignees = ['user-id-1', 'user-id-2']; + const { getByTestId } = renderAssignees('test-event', assignees); + + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).toBeDisabled(); + }); + + it('should render add assignees button as disabled within Basic license', () => { + (useLicense as jest.Mock).mockReturnValue({ isPlatinumPlus: () => false }); + + const assignees = ['user-id-1', 'user-id-2']; + const { getByTestId } = renderAssignees('test-event', assignees); + + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ASSIGNEES_ADD_BUTTON_TEST_ID)).toBeDisabled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.tsx new file mode 100644 index 000000000000..7544388a62f9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/assignees.tsx @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { noop } from 'lodash'; +import type { FC } from 'react'; +import React, { memo, useCallback, useMemo, useState } from 'react'; + +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiTitle, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { useUpsellingMessage } from '../../../../common/hooks/use_upselling'; +import { useLicense } from '../../../../common/hooks/use_license'; +import { useAlertsPrivileges } from '../../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; +import { useBulkGetUserProfiles } from '../../../../common/components/user_profiles/use_bulk_get_user_profiles'; +import { removeNoAssigneesSelection } from '../../../../common/components/assignees/utils'; +import type { AssigneesIdsSelection } from '../../../../common/components/assignees/types'; +import { AssigneesPopover } from '../../../../common/components/assignees/assignees_popover'; +import { UsersAvatarsPanel } from '../../../../common/components/user_profiles/users_avatars_panel'; +import { useSetAlertAssignees } from '../../../../common/components/toolbar/bulk_actions/use_set_alert_assignees'; +import { + ASSIGNEES_ADD_BUTTON_TEST_ID, + ASSIGNEES_HEADER_TEST_ID, + ASSIGNEES_TITLE_TEST_ID, +} from './test_ids'; + +const UpdateAssigneesButton: FC<{ + isDisabled: boolean; + toolTipMessage: string; + togglePopover: () => void; +}> = memo(({ togglePopover, isDisabled, toolTipMessage }) => ( + + + +)); +UpdateAssigneesButton.displayName = 'UpdateAssigneesButton'; + +export interface AssigneesProps { + /** + * Id of the document + */ + eventId: string; + + /** + * The array of ids of the users assigned to the alert + */ + assignedUserIds: string[]; + + /** + * Callback to handle the successful assignees update + */ + onAssigneesUpdated?: () => void; +} + +/** + * Document assignees details displayed in flyout right section header + */ +export const Assignees: FC = memo( + ({ eventId, assignedUserIds, onAssigneesUpdated }) => { + const isPlatinumPlus = useLicense().isPlatinumPlus(); + const upsellingMessage = useUpsellingMessage('alert_assignments'); + + const { hasIndexWrite } = useAlertsPrivileges(); + const setAlertAssignees = useSetAlertAssignees(); + + const uids = useMemo(() => new Set(assignedUserIds), [assignedUserIds]); + const { data: assignedUsers } = useBulkGetUserProfiles({ uids }); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const onSuccess = useCallback(() => { + if (onAssigneesUpdated) onAssigneesUpdated(); + }, [onAssigneesUpdated]); + + const togglePopover = useCallback(() => { + setIsPopoverOpen((value) => !value); + }, []); + + const onAssigneesApply = useCallback( + async (assigneesIds: AssigneesIdsSelection[]) => { + setIsPopoverOpen(false); + if (setAlertAssignees) { + const updatedIds = removeNoAssigneesSelection(assigneesIds); + const assigneesToAddArray = updatedIds.filter((uid) => !assignedUserIds.includes(uid)); + const assigneesToRemoveArray = assignedUserIds.filter((uid) => !updatedIds.includes(uid)); + + const assigneesToUpdate = { + add: assigneesToAddArray, + remove: assigneesToRemoveArray, + }; + + await setAlertAssignees(assigneesToUpdate, [eventId], onSuccess, noop); + } + }, + [assignedUserIds, eventId, onSuccess, setAlertAssignees] + ); + + return ( + + + +

    + +

    +
    +
    + {assignedUsers && ( + + + + )} + + + } + isPopoverOpen={isPopoverOpen} + closePopover={togglePopover} + onAssigneesApply={onAssigneesApply} + /> + +
    + ); + } +); + +Assignees.displayName = 'Assignees'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index 38a80490ea22..018f0c4949af 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -7,12 +7,13 @@ import React from 'react'; import { render } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; import { TestProviders } from '../../../../common/mock'; import { CorrelationsOverview } from './correlations_overview'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, @@ -182,7 +183,7 @@ describe('', () => { it('should navigate to the left section Insights tab when clicking on button', () => { const flyoutContextValue = { openLeftPanel: jest.fn(), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId } = render( @@ -196,7 +197,7 @@ describe('', () => { getByTestId(TITLE_LINK_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: CORRELATIONS_TAB_ID }, params: { id: panelContextValue.eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index a273257ba0fc..52e66fed55b5 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -22,7 +22,7 @@ import { RelatedCases } from './related_cases'; import { useShowRelatedCases } from '../../shared/hooks/use_show_related_cases'; import { CORRELATIONS_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; -import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; +import { DocumentDetailsLeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; /** @@ -43,7 +43,7 @@ export const CorrelationsOverview: React.FC = () => { const goToCorrelationsTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: CORRELATIONS_TAB_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.test.tsx index 2cf9276a1853..81d6993e805f 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { DESCRIPTION_TITLE_TEST_ID, @@ -18,7 +18,9 @@ import { RightPanelContext } from '../context'; import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { PreviewPanelKey } from '../../preview'; +import { DocumentDetailsPreviewPanelKey } from '../../preview'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/types'; +import { i18n } from '@kbn/i18n'; const ruleUuid = { category: 'kibana', @@ -46,7 +48,7 @@ const ruleName = { const flyoutContextValue = { openPreviewPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const panelContextValue = (dataFormattedForFieldBrowser: TimelineEventsDetailsItem[]) => ({ @@ -111,6 +113,15 @@ describe('', () => { expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toHaveAttribute('disabled'); }); + it('should render rule preview button as disabled if flyout is in preview', () => { + const { getByTestId } = renderDescription({ + ...panelContextValue([{ ...ruleUuid, values: [] }, ruleName, ruleDescription]), + isPreview: true, + }); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toHaveAttribute('disabled'); + }); + it('should open preview panel when clicking on button', () => { const panelContext = panelContextValue([ruleUuid, ruleDescription, ruleName]); @@ -119,18 +130,16 @@ describe('', () => { getByTestId(RULE_SUMMARY_BUTTON_TEST_ID).click(); expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ - id: PreviewPanelKey, + id: DocumentDetailsPreviewPanelKey, path: { tab: 'rule-preview' }, params: { id: panelContext.eventId, indexName: panelContext.indexName, scopeId: panelContext.scopeId, banner: { - title: ( - + title: i18n.translate( + 'xpack.securitySolution.flyout.right.about.description.rulePreviewTitle', + { defaultMessage: 'Preview rule details' } ), backgroundColor: 'warning', textColor: 'warning', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.tsx index 105d57ba4e7f..c612e2a6fb5a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/description.tsx @@ -20,14 +20,19 @@ import { DESCRIPTION_TITLE_TEST_ID, RULE_SUMMARY_BUTTON_TEST_ID, } from './test_ids'; -import { PreviewPanelKey, type PreviewPanelProps, RulePreviewPanel } from '../../preview'; +import { + DocumentDetailsPreviewPanelKey, + type PreviewPanelProps, + RulePreviewPanel, +} from '../../preview'; /** * Displays the description of a document. * If the document is an alert we show the rule description. If the document is of another type, we show -. */ export const Description: FC = () => { - const { dataFormattedForFieldBrowser, scopeId, eventId, indexName } = useRightPanelContext(); + const { dataFormattedForFieldBrowser, scopeId, eventId, indexName, isPreview } = + useRightPanelContext(); const { isAlert, ruleDescription, ruleName, ruleId } = useBasicDataFromDetailsData( dataFormattedForFieldBrowser ); @@ -35,18 +40,16 @@ export const Description: FC = () => { const openRulePreview = useCallback(() => { const PreviewPanelRulePreview: PreviewPanelProps['path'] = { tab: RulePreviewPanel }; openPreviewPanel({ - id: PreviewPanelKey, + id: DocumentDetailsPreviewPanelKey, path: PreviewPanelRulePreview, params: { id: eventId, indexName, scopeId, banner: { - title: ( - + title: i18n.translate( + 'xpack.securitySolution.flyout.right.about.description.rulePreviewTitle', + { defaultMessage: 'Preview rule details' } ), backgroundColor: 'warning', textColor: 'warning', @@ -71,7 +74,7 @@ export const Description: FC = () => { defaultMessage: 'Show rule summary', } )} - disabled={isEmpty(ruleName) || isEmpty(ruleId)} + disabled={isEmpty(ruleName) || isEmpty(ruleId) || isPreview} > { ), - [ruleName, openRulePreview, ruleId] + [ruleName, openRulePreview, ruleId, isPreview] ); const alertRuleDescription = @@ -98,7 +101,12 @@ export const Description: FC = () => { {isAlert ? ( - +
    { const goToEntitiesTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID, @@ -66,7 +66,7 @@ export const EntitiesOverview: React.FC = () => { data-test-subj={INSIGHTS_ENTITIES_TEST_ID} > {userName || hostName ? ( - + {userName && ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.test.tsx index ec7f85be212c..1e052aa17034 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { copyToClipboard } from '@elastic/eui'; import { RightPanelContext } from '../context'; @@ -17,7 +18,7 @@ import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; import { TestProvidersComponent } from '../../../../common/mock'; import { useGetAlertDetailsFlyoutLink } from '../../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link'; -import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url'; +import { URL_PARAM_KEY } from '../../../../common/hooks/use_url_state'; jest.mock('../../../../common/lib/kibana'); jest.mock('../hooks/use_assistant'); @@ -32,7 +33,7 @@ jest.mock('@elastic/eui', () => ({ })); const alertUrl = 'https://example.com/alert'; -const flyoutContextValue = {} as unknown as ExpandableFlyoutContext; +const flyoutContextValue = {} as unknown as ExpandableFlyoutContextValue; const mockContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, getFieldsData: jest.fn().mockImplementation(mockGetFieldsData), @@ -58,7 +59,7 @@ describe('', () => { describe('Share alert url action', () => { it('should render share button in the title and copy the the value to clipboard if document is an alert', () => { const syncedFlyoutState = 'flyoutState'; - const query = `?${FLYOUT_URL_PARAM}=${syncedFlyoutState}`; + const query = `?${URL_PARAM_KEY.eventFlyout}=${syncedFlyoutState}`; Object.defineProperty(window, 'location', { value: { @@ -73,7 +74,7 @@ describe('', () => { fireEvent.click(shareButton); expect(copyToClipboard).toHaveBeenCalledWith( - `${alertUrl}&${FLYOUT_URL_PARAM}=${syncedFlyoutState}` + `${alertUrl}&${URL_PARAM_KEY.eventFlyout}=${syncedFlyoutState}` ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx index 2862aed53501..52bcb514e7ca 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_actions.tsx @@ -10,8 +10,8 @@ import React, { memo } from 'react'; import { EuiButtonIcon, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { NewChatById } from '@kbn/elastic-assistant'; +import { URL_PARAM_KEY } from '../../../../common/hooks/use_url_state'; import { copyFunction } from '../../../shared/utils/copy_to_clipboard'; -import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url'; import { useGetAlertDetailsFlyoutLink } from '../../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link'; import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers'; import { useAssistant } from '../hooks/use_assistant'; @@ -39,7 +39,7 @@ export const HeaderActions: VFC = memo(() => { const modifier = (value: string) => { const query = new URLSearchParams(window.location.search); - return `${value}&${FLYOUT_URL_PARAM}=${query.get(FLYOUT_URL_PARAM)}`; + return `${value}&${URL_PARAM_KEY.eventFlyout}=${query.get(URL_PARAM_KEY.eventFlyout)}`; }; const { showAssistant, promptContextId } = useAssistant({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.test.tsx index f192a84211a4..9c3157f9d5d0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.test.tsx @@ -7,12 +7,14 @@ import React from 'react'; import { render } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; import { RISK_SCORE_VALUE_TEST_ID, SEVERITY_VALUE_TEST_ID, FLYOUT_HEADER_TITLE_TEST_ID, + STATUS_BUTTON_TEST_ID, } from './test_ids'; import { HeaderTitle } from './header_title'; import moment from 'moment-timezone'; @@ -27,7 +29,7 @@ moment.suppressDeprecationWarnings = true; moment.tz.setDefault('UTC'); const dateFormat = 'MMM D, YYYY @ HH:mm:ss.SSS'; -const flyoutContextValue = {} as unknown as ExpandableFlyoutContext; +const flyoutContextValue = {} as unknown as ExpandableFlyoutContextValue; const mockContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, getFieldsData: jest.fn().mockImplementation(mockGetFieldsData), @@ -56,6 +58,7 @@ describe('', () => { expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RISK_SCORE_VALUE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(SEVERITY_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(STATUS_BUTTON_TEST_ID)).toBeInTheDocument(); }); it('should render rule name in the title if document is an alert', () => { @@ -82,4 +85,32 @@ describe('', () => { expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('Event details'); }); + + it('should not render document status if document is not an alert', () => { + const contextValue = { + ...mockContextValue, + dataFormattedForFieldBrowser: [ + { + category: 'kibana', + field: 'kibana.alert.rule.name', + values: [], + originalValue: [], + isObjectArray: false, + }, + ], + } as unknown as RightPanelContext; + + const { queryByTestId } = renderHeader(contextValue); + expect(queryByTestId(STATUS_BUTTON_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should not render document status if flyout is open in preview', () => { + const contextValue = { + ...mockContextValue, + isPreview: true, + } as unknown as RightPanelContext; + + const { queryByTestId } = renderHeader(contextValue); + expect(queryByTestId(STATUS_BUTTON_TEST_ID)).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.tsx index d67253061d1d..0d8f58162673 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/header_title.tsx @@ -6,57 +6,74 @@ */ import type { FC } from 'react'; -import React, { memo, useMemo } from 'react'; +import React, { memo, useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { isEmpty } from 'lodash'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; import { DocumentStatus } from './status'; import { DocumentSeverity } from './severity'; import { RiskScore } from './risk_score'; +import { useRefetchByScope } from '../../../../timelines/components/side_panel/event_details/flyout/use_refetch_by_scope'; import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers'; import { useRightPanelContext } from '../context'; import { PreferenceFormattedDate } from '../../../../common/components/formatted_date'; import { RenderRuleName } from '../../../../timelines/components/timeline/body/renderers/formatted_field_helpers'; import { SIGNAL_RULE_NAME_FIELD_NAME } from '../../../../timelines/components/timeline/body/renderers/constants'; import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; +import { Assignees } from './assignees'; import { FlyoutTitle } from '../../../shared/components/flyout_title'; /** * Document details flyout right section header */ export const HeaderTitle: FC = memo(() => { - const { dataFormattedForFieldBrowser, eventId, scopeId } = useRightPanelContext(); + const { + dataFormattedForFieldBrowser, + eventId, + scopeId, + isPreview, + refetchFlyoutData, + getFieldsData, + } = useRightPanelContext(); const { isAlert, ruleName, timestamp, ruleId } = useBasicDataFromDetailsData( dataFormattedForFieldBrowser ); const ruleTitle = useMemo( - () => ( - + () => + isPreview ? ( - - ), - [ruleName, ruleId, eventId, scopeId] + ) : ( + + + + ), + [ruleName, ruleId, eventId, scopeId, isPreview] ); const eventTitle = ( -

    +

    { ); + const { refetch } = useRefetchByScope({ scopeId }); + const alertAssignees = useMemo( + () => (getFieldsData(ALERT_WORKFLOW_ASSIGNEE_IDS) as string[]) ?? [], + [getFieldsData] + ); + const onAssigneesUpdated = useCallback(() => { + refetch(); + refetchFlyoutData(); + }, [refetch, refetchFlyoutData]); + return ( <> {timestamp && } - {isAlert && !isEmpty(ruleName) ? ruleTitle : eventTitle} +
    + {isAlert && !isEmpty(ruleName) ? ruleTitle : eventTitle} +
    - - - - + + {isAlert && !isPreview && ( + + + + )} + {isAlert && !isPreview && ( + + + + )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx index 717cf9856651..806a43f9f549 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields.tsx @@ -15,6 +15,7 @@ import { convertHighlightedFieldsToTableRow } from '../../shared/utils/highlight import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback'; import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers'; import { HighlightedFieldsCell } from './highlighted_fields_cell'; +import { SecurityCellActionType } from '../../../../actions/constants'; import { CellActionsMode, SecurityCellActions, @@ -42,6 +43,10 @@ export interface HighlightedFieldsTableRow { * Maintain backwards compatibility // TODO remove when possible */ scopeId: string; + /** + * Boolean to indicate this field is shown in a preview + */ + isPreview: boolean; }; } @@ -71,6 +76,7 @@ const columns: Array> = [ field: string; values: string[] | null | undefined; scopeId: string; + isPreview: boolean; }) => ( > = [ visibleCellActions={6} sourcererScopeId={getSourcererScopeId(description.scopeId)} metadata={{ scopeId: description.scopeId }} + disabledActionTypes={ + description.isPreview + ? [SecurityCellActionType.FILTER, SecurityCellActionType.TOGGLE_COLUMN] + : [] + } > @@ -93,7 +104,7 @@ const columns: Array> = [ * Component that displays the highlighted fields in the right panel under the Investigation section. */ export const HighlightedFields: FC = () => { - const { dataFormattedForFieldBrowser, scopeId } = useRightPanelContext(); + const { dataFormattedForFieldBrowser, scopeId, isPreview } = useRightPanelContext(); const { ruleId } = useBasicDataFromDetailsData(dataFormattedForFieldBrowser); const { loading, rule: maybeRule } = useRuleWithFallback(ruleId); @@ -102,8 +113,8 @@ export const HighlightedFields: FC = () => { investigationFields: maybeRule?.investigation_fields?.field_names ?? [], }); const items = useMemo( - () => convertHighlightedFieldsToTableRow(highlightedFields, scopeId), - [highlightedFields, scopeId] + () => convertHighlightedFieldsToTableRow(highlightedFields, scopeId, isPreview), + [highlightedFields, scopeId, isPreview] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx index 6f4711651ffc..0112e06cb489 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx @@ -13,9 +13,10 @@ import { HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID, } from './test_ids'; import { HighlightedFieldsCell } from './highlighted_fields_cell'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { TestProviders } from '../../../../common/mock'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useGetEndpointDetails } from '../../../../management/hooks'; @@ -24,7 +25,7 @@ jest.mock('../../../../management/hooks'); const flyoutContextValue = { openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const panelContextValue = { eventId: 'event id', indexName: 'indexName', @@ -64,7 +65,7 @@ describe('', () => { getByTestId(HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: panelContextValue.eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx index 60c561116c38..6d7c5652eade 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx @@ -16,7 +16,7 @@ import { HOST_NAME_FIELD_NAME, USER_NAME_FIELD_NAME, } from '../../../../timelines/components/timeline/body/renderers/constants'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID, @@ -42,7 +42,7 @@ const LinkFieldCell: VFC = ({ value }) => { const goToInsightsEntities = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx index 25c25b87aa38..36fb3731943c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx @@ -21,8 +21,9 @@ import { import { RightPanelContext } from '../context'; import { mockContextValue } from '../mocks/mock_context'; import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; const hostName = 'host'; @@ -42,7 +43,7 @@ const panelContextValue = { const flyoutContextValue = { openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const mockUseGlobalTime = jest.fn().mockReturnValue({ from, to }); jest.mock('../../../../common/containers/use_global_time', () => { @@ -160,7 +161,7 @@ describe('', () => { getByTestId(ENTITIES_HOST_OVERVIEW_LINK_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: panelContextValue.eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx index fdc3edf96e9b..a1d42871a42e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.tsx @@ -49,7 +49,7 @@ import { ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID, } from './test_ids'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { RiskScoreDocTooltip } from '../../../../overview/components/common'; const HOST_ICON = 'storage'; @@ -70,7 +70,7 @@ export const HostEntityOverview: React.FC = ({ hostName const { openLeftPanel } = useExpandableFlyoutContext(); const goToEntitiesTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: eventId, @@ -156,7 +156,7 @@ export const HostEntityOverview: React.FC = ({ hostName return [ { title: ( - + {HOST_RISK_LEVEL} @@ -177,9 +177,14 @@ export const HostEntityOverview: React.FC = ({ hostName }, [hostRisk]); return ( - + - + @@ -207,7 +212,7 @@ export const HostEntityOverview: React.FC = ({ hostName /> ) : ( - + = ({ const colorDataTestSubj = `${dataTestSubj}Color`; return ( - + - - - + data-test-subj={iconDataTestSubj} + aria-label={i18n.translate( + 'xpack.securitySolution.flyout.right.insights.insightSummaryButtonIconAriaLabel', + { + defaultMessage: 'Insight summary row icon', + } + )} + color="text" + display="empty" + type={icon} + size="m" + /> render( @@ -97,6 +98,21 @@ describe('', () => { expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); + it('should render preview message when flyout is in preview', () => { + const { queryByTestId, getByTestId } = render( + + + + + + + + ); + + expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(PREVIEW_MESSAGE); + }); + it('should navigate to investigation guide when clicking on button', () => { (useInvestigationGuide as jest.Mock).mockReturnValue({ loading: false, @@ -109,7 +125,7 @@ describe('', () => { getByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID).click(); expect(mockFlyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInvestigationTab, }, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.tsx index d00310b360c2..427a9987de87 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; import { useRightPanelContext } from '../context'; -import { LeftPanelKey, LeftPanelInvestigationTab } from '../../left'; +import { DocumentDetailsLeftPanelKey, LeftPanelInvestigationTab } from '../../left'; import { INVESTIGATION_GUIDE_BUTTON_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID, @@ -24,7 +24,8 @@ import { */ export const InvestigationGuide: React.FC = () => { const { openLeftPanel } = useExpandableFlyoutContext(); - const { eventId, indexName, scopeId, dataFormattedForFieldBrowser } = useRightPanelContext(); + const { eventId, indexName, scopeId, dataFormattedForFieldBrowser, isPreview } = + useRightPanelContext(); const { loading, error, basicAlertData, ruleNote } = useInvestigationGuide({ dataFormattedForFieldBrowser, @@ -32,7 +33,7 @@ export const InvestigationGuide: React.FC = () => { const goToInvestigationsTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInvestigationTab, }, @@ -56,7 +57,12 @@ export const InvestigationGuide: React.FC = () => {

    - {loading ? ( + {isPreview ? ( + + ) : loading ? ( d.field !== 'kibana.alert.rule.type' diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx index 79fcf8997729..5bdca0ec3dfa 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx @@ -5,12 +5,13 @@ * 2.0. */ +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { render } from '@testing-library/react'; import { TestProviders } from '../../../../common/mock'; import { RightPanelContext } from '../context'; import { PREVALENCE_TEST_ID } from './test_ids'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import React from 'react'; import { PrevalenceOverview } from './prevalence_overview'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; @@ -35,7 +36,7 @@ const NO_DATA_MESSAGE = 'No prevalence data available.'; const flyoutContextValue = { openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const renderPrevalenceOverview = (contextValue: RightPanelContext = mockContextValue) => render( @@ -167,7 +168,7 @@ describe('', () => { getByTestId(TITLE_LINK_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: PREVALENCE_TAB_ID }, params: { id: 'eventId', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx index 674b9d662f46..c7249f66065d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx @@ -14,7 +14,7 @@ import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { PREVALENCE_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; -import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; +import { DocumentDetailsLeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; import { InsightsSummaryRow } from './insights_summary_row'; @@ -33,7 +33,7 @@ export const PrevalenceOverview: FC = () => { const goPrevalenceTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: PREVALENCE_TAB_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx index f407c33a1e21..9b459acbaf32 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx @@ -7,18 +7,20 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, REASON_TITLE_TEST_ID } from './test_ids'; import { Reason } from './reason'; import { RightPanelContext } from '../context'; import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; -import { PreviewPanelKey } from '../../preview'; +import { DocumentDetailsPreviewPanelKey } from '../../preview'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/types'; +import { i18n } from '@kbn/i18n'; const flyoutContextValue = { openPreviewPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const panelContextValue = { eventId: 'event id', @@ -82,18 +84,18 @@ describe('', () => { getByTestId(REASON_DETAILS_PREVIEW_BUTTON_TEST_ID).click(); expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ - id: PreviewPanelKey, + id: DocumentDetailsPreviewPanelKey, path: { tab: 'alert-reason-preview' }, params: { id: panelContextValue.eventId, indexName: panelContextValue.indexName, scopeId: panelContextValue.scopeId, banner: { - title: ( - + title: i18n.translate( + 'xpack.securitySolution.flyout.right.about.reason.alertReasonPreviewTitle', + { + defaultMessage: 'Preview alert reason', + } ), backgroundColor: 'warning', textColor: 'warning', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx index ca0de7118a06..96ec5b2b0232 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx @@ -13,7 +13,7 @@ import { ALERT_REASON } from '@kbn/rule-data-utils'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { getField } from '../../shared/utils'; -import { AlertReasonPreviewPanel, PreviewPanelKey } from '../../preview'; +import { AlertReasonPreviewPanel, DocumentDetailsPreviewPanelKey } from '../../preview'; import { REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, REASON_DETAILS_TEST_ID, @@ -34,18 +34,18 @@ export const Reason: FC = () => { const { openPreviewPanel } = useExpandableFlyoutContext(); const openRulePreview = useCallback(() => { openPreviewPanel({ - id: PreviewPanelKey, + id: DocumentDetailsPreviewPanelKey, path: { tab: AlertReasonPreviewPanel }, params: { id: eventId, indexName, scopeId, banner: { - title: ( - + title: i18n.translate( + 'xpack.securitySolution.flyout.right.about.reason.alertReasonPreviewTitle', + { + defaultMessage: 'Preview alert reason', + } ), backgroundColor: 'warning', textColor: 'warning', @@ -96,8 +96,13 @@ export const Reason: FC = () => {
    {isAlert ? ( - - + +
    { const goToResponseTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelResponseTab }, params: { id: eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.test.tsx index ebff6c0e704f..d521155ea163 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.test.tsx @@ -10,10 +10,13 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { RESPONSE_SECTION_CONTENT_TEST_ID, RESPONSE_SECTION_HEADER_TEST_ID } from './test_ids'; import { RightPanelContext } from '../context'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { ResponseSection } from './response_section'; -const flyoutContextValue = {} as unknown as ExpandableFlyoutContext; +const PREVIEW_MESSAGE = 'Response is not available in alert preview.'; + +const flyoutContextValue = {} as unknown as ExpandableFlyoutContextValue; const panelContextValue = {} as unknown as RightPanelContext; const renderResponseSection = () => @@ -47,4 +50,18 @@ describe('', () => { getByTestId(RESPONSE_SECTION_HEADER_TEST_ID).click(); expect(getByTestId(RESPONSE_SECTION_CONTENT_TEST_ID)).toBeInTheDocument(); }); + + it('should render preview message if flyout is in preview', () => { + const { getByTestId } = render( + + + + + + + + ); + getByTestId(RESPONSE_SECTION_HEADER_TEST_ID).click(); + expect(getByTestId(RESPONSE_SECTION_CONTENT_TEST_ID)).toHaveTextContent(PREVIEW_MESSAGE); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.tsx index 96a0b070020e..6b7ca6e28224 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/response_section.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { ResponseButton } from './response_button'; import { ExpandableSection } from './expandable_section'; +import { useRightPanelContext } from '../context'; import { RESPONSE_SECTION_TEST_ID } from './test_ids'; export interface ResponseSectionProps { /** @@ -22,6 +23,7 @@ export interface ResponseSectionProps { * Most bottom section of the overview tab. It contains a summary of the response tab. */ export const ResponseSection: VFC = ({ expanded = false }) => { + const { isPreview } = useRightPanelContext(); return ( = ({ expanded = false }) } data-test-subj={RESPONSE_SECTION_TEST_ID} > - + {isPreview ? ( + + ) : ( + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/risk_score.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/risk_score.tsx index 600234e98b30..a603cd9563d2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/risk_score.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/risk_score.tsx @@ -34,7 +34,7 @@ export const RiskScore: FC = memo(() => { } return ( - +

    diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.test.tsx index 775e195e764f..525ca03dbc04 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.test.tsx @@ -10,6 +10,7 @@ import { useProcessData } from '../hooks/use_process_data'; import { SessionPreview } from './session_preview'; import { TestProviders } from '../../../../common/mock'; import React from 'react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; @@ -17,7 +18,7 @@ jest.mock('../hooks/use_process_data'); const flyoutContextValue = { openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const panelContextValue = { eventId: 'event id', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.tsx index 63f07cb7ab1f..08c15480bb7e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview.tsx @@ -37,7 +37,7 @@ const ValueContainer: FC<{ text?: ReactElement }> = ({ text, children }) => ( * Renders session preview under Visualizations section in the flyout right EuiPanel */ export const SessionPreview: FC = () => { - const { eventId, scopeId } = useRightPanelContext(); + const { eventId, scopeId, isPreview } = useRightPanelContext(); const { processName, userName, startAt, ruleName, ruleId, workdir, command } = useProcessData(); const { euiTheme } = useEuiTheme(); @@ -100,13 +100,13 @@ export const SessionPreview: FC = () => { fieldType={'string'} isAggregatable={false} isDraggable={false} - linkValue={ruleId} + linkValue={!isPreview ? ruleId : null} value={ruleName} /> ) ); - }, [ruleName, ruleId, scopeId, eventId]); + }, [ruleName, ruleId, scopeId, eventId, isPreview]); const commandFragment = useMemo(() => { return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx index cfd5bcc52570..80d9c81a064e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx @@ -40,10 +40,10 @@ const sessionViewConfig = { sessionStartTime: 'sessionStartTime', }; -const renderSessionPreview = () => +const renderSessionPreview = (context = panelContextValue) => render( - + @@ -121,4 +121,31 @@ describe('SessionPreviewContainer', () => { ).not.toHaveTextContent(NO_DATA_MESSAGE); expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); }); + + it('should not render link to session viewer if flyout is open in preview', () => { + (useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig); + (useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true }); + + const { getByTestId, queryByTestId } = renderSessionPreview({ + ...panelContextValue, + isPreview: true, + }); + + expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).toBeInTheDocument(); + expect( + queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx index 10250e74c383..d0214b725a44 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx @@ -29,7 +29,7 @@ const timelineId = 'timeline-1'; * Checks if the SessionView component is available, if so render it or else render an error message */ export const SessionPreviewContainer: FC = () => { - const { dataAsNestedObject, getFieldsData } = useRightPanelContext(); + const { dataAsNestedObject, getFieldsData, isPreview } = useRightPanelContext(); // decide whether to show the session view or not const sessionViewConfig = useSessionPreview({ getFieldsData }); @@ -122,17 +122,18 @@ export const SessionPreviewContainer: FC = () => { /> ), iconType: 'timeline', - ...(isEnabled && { - link: { - callback: goToSessionViewTab, - tooltip: ( - - ), - }, - }), + ...(isEnabled && + !isPreview && { + link: { + callback: goToSessionViewTab, + tooltip: ( + + ), + }, + }), }} data-test-subj={SESSION_PREVIEW_TEST_ID} > diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/status.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/status.test.tsx index 0b52e0ef6766..1c9412deab05 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/status.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/status.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; import { DocumentStatus } from './status'; @@ -19,7 +20,7 @@ jest.mock('../../../../detections/components/alerts_table/timeline_actions/use_a const flyoutContextValue = { closeFlyout: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const renderStatus = (contextValue: RightPanelContext) => render( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index 28d76c040ebb..5b176a34014a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -19,6 +19,10 @@ export const RISK_SCORE_VALUE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}RiskScoreValue` export const SHARE_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}ShareButton` as const; export const CHAT_BUTTON_TEST_ID = 'newChatById' as const; +export const ASSIGNEES_HEADER_TEST_ID = `${FLYOUT_HEADER_TEST_ID}AssigneesHeader` as const; +export const ASSIGNEES_TITLE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}AssigneesTitle` as const; +export const ASSIGNEES_ADD_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}AssigneesAddButton` as const; + /* About section */ export const ABOUT_SECTION_TEST_ID = `${PREFIX}AboutSection` as const; @@ -97,8 +101,6 @@ export const ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}LastSeen` as const; export const ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}RiskLevel` as const; -export const TECHNICAL_PREVIEW_ICON_TEST_ID = - `${INSIGHTS_ENTITIES_TEST_ID}TechnicalPreviewIcon` as const; /* Threat intelligence */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx index 1b8a646f1d35..d752df3d9350 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx @@ -7,11 +7,12 @@ import React from 'react'; import { render } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; import { TestProviders } from '../../../../common/mock'; import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; @@ -147,7 +148,7 @@ describe('', () => { }); const flyoutContextValue = { openLeftPanel: jest.fn(), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId } = render( @@ -161,7 +162,7 @@ describe('', () => { getByTestId(TITLE_LINK_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: THREAT_INTELLIGENCE_TAB_ID }, params: { id: panelContextValue.eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx index ebaea597219a..d57fb1d6c0aa 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx @@ -15,7 +15,7 @@ import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligen import { InsightsSummaryRow } from './insights_summary_row'; import { useRightPanelContext } from '../context'; import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; -import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; +import { DocumentDetailsLeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; /** @@ -29,7 +29,7 @@ export const ThreatIntelligenceOverview: FC = () => { const goToThreatIntelligenceTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: THREAT_INTELLIGENCE_TAB_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx index 37b4666611ef..c8673f41376f 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx @@ -20,9 +20,10 @@ import { import { useObservedUserDetails } from '../../../../explore/users/containers/users/observed_details'; import { mockContextValue } from '../mocks/mock_context'; import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { RightPanelContext } from '../context'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; const userName = 'user'; @@ -42,7 +43,7 @@ const panelContextValue = { const flyoutContextValue = { openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; const mockUseGlobalTime = jest.fn().mockReturnValue({ from, to }); jest.mock('../../../../common/containers/use_global_time', () => { @@ -169,7 +170,7 @@ describe('', () => { getByTestId(ENTITIES_USER_OVERVIEW_LINK_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: panelContextValue.eventId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx index cd1a057b6fbc..313719ec1c0b 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.tsx @@ -19,7 +19,7 @@ import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; -import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; +import { LeftPanelInsightsTab, DocumentDetailsLeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useRightPanelContext } from '../context'; import type { DescriptionList } from '../../../../../common/utility_types'; @@ -70,7 +70,7 @@ export const UserEntityOverview: React.FC = ({ userName const { openLeftPanel } = useExpandableFlyoutContext(); const goToEntitiesTab = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, path: { tab: LeftPanelInsightsTab, subTab: ENTITIES_TAB_ID }, params: { id: eventId, @@ -155,7 +155,7 @@ export const UserEntityOverview: React.FC = ({ userName return [ { title: ( - + {USER_RISK_LEVEL} @@ -176,9 +176,14 @@ export const UserEntityOverview: React.FC = ({ userName }, [userRisk]); return ( - + - + @@ -206,7 +211,7 @@ export const UserEntityOverview: React.FC = ({ userName data-test-subj={ENTITIES_USER_OVERVIEW_LOADING_TEST_ID} /> ) : ( - + ({ @@ -40,7 +41,7 @@ describe('', () => { it('should render visualizations component', () => { const flyoutContextValue = { openLeftPanel: jest.fn(), - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId, getAllByRole } = render( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx index b46645aaf883..7311a030b217 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx @@ -8,6 +8,7 @@ import type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import React, { createContext, memo, useContext, useMemo } from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { TableId } from '@kbn/securitysolution-data-table'; import { useEventDetails } from '../shared/hooks/use_event_details'; import { FlyoutError } from '../../shared/components/flyout_error'; @@ -59,6 +60,10 @@ export interface RightPanelContext { * Retrieves searchHit values for the provided field */ getFieldsData: GetFieldsData; + /** + * Boolean to indicate whether it is a preview flyout + */ + isPreview: boolean; } export const RightPanelContext = createContext(undefined); @@ -104,6 +109,7 @@ export const RightPanelProvider = memo( investigationFields: maybeRule?.investigation_fields?.field_names ?? [], refetchFlyoutData, getFieldsData, + isPreview: scopeId === TableId.rulePreview, } : undefined, [ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/footer.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/footer.tsx index 49ad491efa4d..995beea63a70 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/footer.tsx @@ -15,10 +15,17 @@ import { useHostIsolationTools } from '../../../timelines/components/side_panel/ import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import { useUiSetting } from '../../../common/lib/kibana'; +interface PanelFooterProps { + /** + * Boolean that indicates whether flyout is in preview and action should be hidden + */ + isPreview: boolean; +} + /** * */ -export const PanelFooter: FC = () => { +export const PanelFooter: FC = ({ isPreview }) => { const { closeFlyout, openRightPanel } = useExpandableFlyoutContext(); const { eventId, @@ -48,7 +55,7 @@ export const PanelFooter: FC = () => { [eventId, indexName, openRightPanel, scopeId, showHostIsolationPanel] ); - return ( + return !isPreview ? ( { refetchFlyoutData={refetchFlyoutData} /> - ); + ) : null; }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx index 35470f21f808..08142a0ef08b 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx @@ -20,7 +20,7 @@ import { tabs } from './tabs'; import { PanelFooter } from './footer'; export type RightPanelPaths = 'overview' | 'table' | 'json'; -export const RightPanelKey: RightPanelProps['key'] = 'document-details-right'; +export const DocumentDetailsRightPanelKey: RightPanelProps['key'] = 'document-details-right'; export interface RightPanelProps extends FlyoutPanelProps { key: 'document-details-right'; @@ -37,7 +37,7 @@ export interface RightPanelProps extends FlyoutPanelProps { */ export const RightPanel: FC> = memo(({ path }) => { const { openRightPanel } = useExpandableFlyoutContext(); - const { eventId, getFieldsData, indexName, scopeId } = useRightPanelContext(); + const { eventId, getFieldsData, indexName, scopeId, isPreview } = useRightPanelContext(); // for 8.10, we only render the flyout in its expandable mode if the document viewed is of type signal const documentIsSignal = getField(getFieldsData('event.kind')) === EventKind.signal; @@ -51,7 +51,7 @@ export const RightPanel: FC> = memo(({ path }) => { const setSelectedTabId = (tabId: RightPanelTabsType[number]['id']) => { openRightPanel({ - id: RightPanelKey, + id: DocumentDetailsRightPanelKey, path: { tab: tabId, }, @@ -72,7 +72,7 @@ export const RightPanel: FC> = memo(({ path }) => { setSelectedTabId={setSelectedTabId} /> - + ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/mocks/mock_context.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/mocks/mock_context.ts index 2bb599a65759..086c272bee35 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/mocks/mock_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/mocks/mock_context.ts @@ -26,4 +26,5 @@ export const mockContextValue: RightPanelContext = { searchHit: mockSearchHit, investigationFields: [], refetchFlyoutData: jest.fn(), + isPreview: false, }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx index 12e36ea29e5a..d78784f16498 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx @@ -10,7 +10,7 @@ import React, { memo, useCallback } from 'react'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { HeaderActions } from './components/header_actions'; import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; -import { LeftPanelKey } from '../left'; +import { DocumentDetailsLeftPanelKey } from '../left'; import { useRightPanelContext } from './context'; interface PanelNavigationProps { @@ -26,7 +26,7 @@ export const PanelNavigation: FC = memo(({ flyoutIsExpanda const expandDetails = useCallback(() => { openLeftPanel({ - id: LeftPanelKey, + id: DocumentDetailsLeftPanelKey, params: { id: eventId, indexName, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx index 6d329811f722..313e8f952e1a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/tabs/json_tab.tsx @@ -23,7 +23,7 @@ const FLYOUT_FOOTER_HEIGHT = 72; * Json view displayed in the document details expandable flyout right section */ export const JsonTab: FC = memo(() => { - const { searchHit } = useRightPanelContext(); + const { searchHit, isPreview } = useRightPanelContext(); const jsonValue = JSON.stringify(searchHit, null, 2); const flexGroupElement = useRef(null); @@ -31,19 +31,20 @@ export const JsonTab: FC = memo(() => { useEffect(() => { const topPosition = flexGroupElement?.current?.getBoundingClientRect().top || 0; + const footerOffset = isPreview ? 0 : FLYOUT_FOOTER_HEIGHT; const height = window.innerHeight - topPosition - COPY_TO_CLIPBOARD_BUTTON_HEIGHT - FLYOUT_BODY_PADDING - - FLYOUT_FOOTER_HEIGHT; + footerOffset; if (height === 0) { return; } setEditorHeight(height); - }, [setEditorHeight]); + }, [setEditorHeight, isPreview]); return ( ; - -export const SecuritySolutionFlyoutCloseContext = createContext< - SecuritySolutionFlyoutCloseContextValue | undefined ->(undefined); - -/** - * Exposes the flyout close context value (returned from syncUrl) as a hook. - */ -export const useSecurityFlyoutUrlSync = () => { - const contextValue = useContext(SecuritySolutionFlyoutCloseContext); - - if (!contextValue) { - throw new Error('useSecurityFlyoutUrlSync can only be used inside respective provider'); - } - - return contextValue; -}; - -/** - * Provides urlSync hook return value as a context value, for reuse in other components. - * Main goal here is to avoid calling useSyncFlyoutStateWithUrl multiple times. - */ -export const SecuritySolutionFlyoutUrlSyncProvider: FC = ({ children }) => { - const [flyoutRef, handleFlyoutChangedOrClosed] = useSyncFlyoutStateWithUrl(); - - const value: SecuritySolutionFlyoutCloseContextValue = useMemo( - () => [flyoutRef, handleFlyoutChangedOrClosed], - [flyoutRef, handleFlyoutChangedOrClosed] - ); - - return ( - - {children} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/expandable_flyout_state_from_event_meta.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/expandable_flyout_state_from_event_meta.ts index 95e5c509f96d..d80d6f5983b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/expandable_flyout_state_from_event_meta.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/expandable_flyout_state_from_event_meta.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { ExpandableFlyoutContext } from '@kbn/expandable-flyout'; -import { RightPanelKey } from '../../../right'; +import { DocumentDetailsRightPanelKey } from '../../../right'; interface RedirectParams { index: string; @@ -19,14 +18,10 @@ interface RedirectParams { * This value can be used to open the flyout either by passing it directly to the flyout api (exposed via ref) or * by serializing it to the url & performing a redirect */ -export const expandableFlyoutStateFromEventMeta = ({ - index, - eventId, - scopeId, -}: RedirectParams): ExpandableFlyoutContext['panels'] => { +export const expandableFlyoutStateFromEventMeta = ({ index, eventId, scopeId }: RedirectParams) => { return { right: { - id: RightPanelKey, + id: DocumentDetailsRightPanelKey, params: { id: eventId, indexName: index, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.test.tsx deleted file mode 100644 index 984b2a2e223d..000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useSyncToUrl } from '@kbn/url-state'; -import { renderHook } from '@testing-library/react-hooks'; -import { useSyncFlyoutStateWithUrl } from './use_sync_flyout_state_with_url'; - -jest.mock('@kbn/url-state'); - -describe('useSyncFlyoutStateWithUrl', () => { - it('should return an array containing flyoutApi ref and handleFlyoutChanges function', () => { - const { result } = renderHook(() => useSyncFlyoutStateWithUrl()); - const [flyoutApi, handleFlyoutChanges] = result.current; - - expect(flyoutApi.current).toBeNull(); - expect(typeof handleFlyoutChanges).toBe('function'); - }); - - it('should open flyout when relevant url state is detected in the query string', () => { - jest.useFakeTimers(); - - jest.mocked(useSyncToUrl).mockImplementation((_urlKey, callback) => { - setTimeout(() => callback({ mocked: { flyout: 'state' } }), 0); - return jest.fn(); - }); - - const { result } = renderHook(() => useSyncFlyoutStateWithUrl()); - const [flyoutApi, handleFlyoutChanges] = result.current; - - const flyoutApiMock: ExpandableFlyoutApi = { - openFlyout: jest.fn(), - getState: () => ({ left: undefined, right: undefined, preview: [] }), - }; - - expect(typeof handleFlyoutChanges).toBe('function'); - expect(flyoutApi.current).toBeNull(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (flyoutApi as any).current = flyoutApiMock; - - jest.runOnlyPendingTimers(); - jest.useRealTimers(); - - expect(flyoutApiMock.openFlyout).toHaveBeenCalledTimes(1); - expect(flyoutApiMock.openFlyout).toHaveBeenCalledWith({ mocked: { flyout: 'state' } }); - }); - - it('should sync flyout state to url whenever handleFlyoutChanges is called by the consumer', () => { - const syncStateToUrl = jest.fn(); - jest.mocked(useSyncToUrl).mockImplementation((_urlKey, callback) => { - setTimeout(() => callback({ mocked: { flyout: 'state' } }), 0); - return syncStateToUrl; - }); - - const { result } = renderHook(() => useSyncFlyoutStateWithUrl()); - const [_flyoutApi, handleFlyoutChanges] = result.current; - - handleFlyoutChanges(); - - expect(syncStateToUrl).toHaveBeenCalledTimes(1); - expect(syncStateToUrl).toHaveBeenLastCalledWith(undefined); - - handleFlyoutChanges({ left: undefined, right: undefined, preview: [] }); - - expect(syncStateToUrl).toHaveBeenLastCalledWith({ - left: undefined, - right: undefined, - preview: undefined, - }); - expect(syncStateToUrl).toHaveBeenCalledTimes(2); - }); -}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.tsx deleted file mode 100644 index 97e2500f3f94..000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/url/use_sync_flyout_state_with_url.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useCallback, useRef } from 'react'; -import type { ExpandableFlyoutApi, ExpandableFlyoutContext } from '@kbn/expandable-flyout'; -import { useSyncToUrl } from '@kbn/url-state'; -import last from 'lodash/last'; -import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; - -export const FLYOUT_URL_PARAM = URL_PARAM_KEY.eventFlyout; - -type FlyoutState = Parameters[0]; - -/** - * Sync flyout state with the url and open it when relevant url state is detected in the query string - * @returns [ref, flyoutChangesHandler] - */ -export const useSyncFlyoutStateWithUrl = () => { - const flyoutApi = useRef(null); - - const handleRestoreFlyout = useCallback( - (state?: FlyoutState) => { - if (!state) { - return; - } - - flyoutApi.current?.openFlyout(state); - }, - [flyoutApi] - ); - - const syncStateToUrl = useSyncToUrl(FLYOUT_URL_PARAM, handleRestoreFlyout); - - // This should be bound to flyout changed and closed events. - // When flyout is closed, url state is cleared - const handleFlyoutChanges = useCallback( - (state?: ExpandableFlyoutContext['panels']) => { - if (!state) { - return syncStateToUrl(undefined); - } - - return syncStateToUrl({ - ...state, - preview: last(state.preview), - }); - }, - [syncStateToUrl] - ); - - return [flyoutApi, handleFlyoutChanges] as const; -}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.test.tsx index 00a25ed1885a..485742aef982 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.test.tsx @@ -7,13 +7,32 @@ import { renderHook } from '@testing-library/react-hooks'; -import { useGetUserCasesPermissions } from '../../../../common/lib/kibana'; +import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__'; import { useShowRelatedCases } from './use_show_related_cases'; -jest.mock('../../../../common/lib/kibana'); + +const mockedUseKibana = mockUseKibana(); +const mockCanUseCases = jest.fn(); + +jest.mock('../../../../common/lib/kibana/kibana_react', () => { + const original = jest.requireActual('../../../../common/lib/kibana/kibana_react'); + + return { + ...original, + useKibana: () => ({ + ...mockedUseKibana, + services: { + ...mockedUseKibana.services, + cases: { + helpers: { canUseCases: mockCanUseCases }, + }, + }, + }), + }; +}); describe('useShowRelatedCases', () => { it(`should return false if user doesn't have cases read privilege`, () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue({ + mockCanUseCases.mockReturnValue({ all: false, create: false, read: false, @@ -28,7 +47,7 @@ describe('useShowRelatedCases', () => { }); it('should return true if user has cases read privilege', () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue({ + mockCanUseCases.mockReturnValue({ all: false, create: false, read: true, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.ts index e469cc2ef155..7bc3429cd058 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_cases.ts @@ -5,12 +5,15 @@ * 2.0. */ -import { useGetUserCasesPermissions } from '../../../../common/lib/kibana'; +import { APP_ID } from '../../../../../common'; +import { useKibana } from '../../../../common/lib/kibana/kibana_react'; /** * Returns true if the user has read privileges for cases, false otherwise */ export const useShowRelatedCases = (): boolean => { - const userCasesPermissions = useGetUserCasesPermissions(); + const { cases } = useKibana().services; + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); + return userCasesPermissions.read; }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/mocks/mock_flyout_context.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/mocks/mock_flyout_context.ts index b579a6899460..419047bc30f7 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/mocks/mock_flyout_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/mocks/mock_flyout_context.ts @@ -5,14 +5,12 @@ * 2.0. */ -import type { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; -import type { State } from '@kbn/expandable-flyout/src/reducer'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; /** * Mock flyout context */ -export const mockFlyoutContextValue: ExpandableFlyoutContext = { - panels: {} as State, +export const mockFlyoutContextValue: ExpandableFlyoutContextValue = { openFlyout: jest.fn(), openRightPanel: jest.fn(), openLeftPanel: jest.fn(), @@ -22,4 +20,9 @@ export const mockFlyoutContextValue: ExpandableFlyoutContext = { closePreviewPanel: jest.fn(), previousPreviewPanel: jest.fn(), closeFlyout: jest.fn(), + panels: { + left: undefined, + right: undefined, + preview: [], + }, }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts index 399296687819..1565837f90fc 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.test.ts @@ -11,6 +11,7 @@ import { } from './highlighted_fields_helpers'; const scopeId = 'scopeId'; +const isPreview = false; describe('convertHighlightedFieldsToTableRow', () => { it('should convert highlighted fields to a table row', () => { @@ -19,13 +20,14 @@ describe('convertHighlightedFieldsToTableRow', () => { values: ['host-1'], }, }; - expect(convertHighlightedFieldsToTableRow(highlightedFields, scopeId)).toEqual([ + expect(convertHighlightedFieldsToTableRow(highlightedFields, scopeId, isPreview)).toEqual([ { field: 'host.name', description: { field: 'host.name', values: ['host-1'], scopeId: 'scopeId', + isPreview, }, }, ]); @@ -38,13 +40,14 @@ describe('convertHighlightedFieldsToTableRow', () => { values: ['host-1'], }, }; - expect(convertHighlightedFieldsToTableRow(highlightedFields, scopeId)).toEqual([ + expect(convertHighlightedFieldsToTableRow(highlightedFields, scopeId, isPreview)).toEqual([ { field: 'host.name-override', description: { field: 'host.name-override', values: ['host-1'], scopeId: 'scopeId', + isPreview, }, }, ]); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts index d41ff1b75f28..6cf1ec9291ef 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/highlighted_fields_helpers.ts @@ -16,7 +16,8 @@ import type { HighlightedFieldsTableRow } from '../../right/components/highlight */ export const convertHighlightedFieldsToTableRow = ( highlightedFields: UseHighlightedFieldsResult, - scopeId: string + scopeId: string, + isPreview: boolean ): HighlightedFieldsTableRow[] => { const fieldNames = Object.keys(highlightedFields); return fieldNames.map((fieldName) => { @@ -30,6 +31,7 @@ export const convertHighlightedFieldsToTableRow = ( field, values, scopeId, + isPreview, }, }; }); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.test.tsx new file mode 100644 index 000000000000..9df74c2d6084 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../../common/mock'; +import { ActionColumn } from './action_column'; +import { alertDataMock } from '../mocks'; + +describe('ActionColumn', () => { + it('renders', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-inputs-actions')).toBeInTheDocument(); + }); + + it('toggles the popover when button is clicked', () => { + const { getByRole } = render( + + + + ); + + fireEvent.click(getByRole('button')); + + expect(getByRole('dialog')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.tsx new file mode 100644 index 000000000000..35b25d69fffc --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/action_column.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButtonIcon, EuiContextMenu, EuiPopover } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useCallback, useMemo, useState } from 'react'; +import type { AlertRawData } from '../content'; +import { useRiskInputActionsPanels } from '../hooks/use_risk_input_actions_panels'; + +interface ActionColumnProps { + alert: AlertRawData; +} + +export const ActionColumn: React.FC = ({ alert }) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + const togglePopover = useCallback(() => setIsPopoverOpen((isOpen) => !isOpen), []); + const alerts = useMemo(() => [alert], [alert]); + const panels = useRiskInputActionsPanels(alerts, closePopover); + + return ( + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + panelPaddingSize="none" + anchorPosition="downLeft" + > + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.test.tsx new file mode 100644 index 000000000000..aeb244e537bd --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.test.tsx @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../../common/mock'; +import { alertDataMock } from '../mocks'; +import { RiskInputsUtilityBar } from './utility_bar'; + +describe('RiskInputsPanel', () => { + it('renders', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-input-utility-bar')).toBeInTheDocument(); + }); + + it('renders current page message when totalItemCount is 1', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-input-utility-bar')).toHaveTextContent('Showing 1 Risk input'); + }); + + it('renders current page message when totalItemCount is 20', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-input-utility-bar')).toHaveTextContent( + 'Showing 1-10 of 20 Risk input' + ); + }); + + it('renders current page message when totalItemCount is 20 and on the second page', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-input-utility-bar')).toHaveTextContent( + 'Showing 11-20 of 20 Risk inputs' + ); + }); + + it('renders selected risk input message', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-input-utility-bar')).toHaveTextContent('3 selected risk input'); + }); + + it('toggles the popover when button is clicked', () => { + const { getByRole } = render( + + + + ); + + fireEvent.click(getByRole('button')); + + expect(getByRole('dialog')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.tsx new file mode 100644 index 000000000000..40e3497a0494 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/components/utility_bar.tsx @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FunctionComponent } from 'react'; +import React, { useCallback, useState } from 'react'; +import type { Pagination } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiContextMenu, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiText, + useEuiTheme, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; +import { useRiskInputActionsPanels } from '../hooks/use_risk_input_actions_panels'; +import type { AlertRawData } from '../content'; + +interface Props { + selectedAlerts: AlertRawData[]; + pagination: Pagination; +} + +export const RiskInputsUtilityBar: FunctionComponent = React.memo( + ({ selectedAlerts, pagination }) => { + const { euiTheme } = useEuiTheme(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const togglePopover = useCallback(() => setIsPopoverOpen(!isPopoverOpen), [isPopoverOpen]); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + const panels = useRiskInputActionsPanels(selectedAlerts, closePopover); + const displayedCurrentPage = pagination.pageIndex + 1; + const pageSize = pagination.pageSize ?? 10; + const fromItem: number = pagination.pageIndex * pageSize + 1; + const toItem: number = Math.min(pagination.totalItemCount, pageSize * displayedCurrentPage); + + return ( + <> + + + + {pagination.totalItemCount <= 1 ? ( + + + + ), + }} + /> + ) : ( + {`${fromItem}-${toItem}`}, + totalInputs: pagination.totalItemCount, + riskInputs: ( + + + + ), + }} + /> + )} + + + + {selectedAlerts.length > 0 && ( + + + + } + > + + + )} + + + + ); + } +); + +RiskInputsUtilityBar.displayName = 'RiskInputsUtilityBar'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.test.tsx new file mode 100644 index 000000000000..93396e7dea03 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.test.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SimpleRiskInput } from '../../../../common/risk_engine'; +import { RiskCategories } from '../../../../common/risk_engine'; +import { fireEvent, render } from '@testing-library/react'; +import React from 'react'; +import { RiskInputsPanel } from '.'; +import { TestProviders } from '../../../common/mock'; +import { times } from 'lodash/fp'; +import { alertDataMock } from './mocks'; + +const mockUseAlertsByIds = jest.fn().mockReturnValue({ loading: false, data: [] }); + +jest.mock('../../../common/containers/alerts/use_alerts_by_ids', () => ({ + useAlertsByIds: () => mockUseAlertsByIds(), +})); + +const TEST_RISK_INPUT: SimpleRiskInput = { + id: '123', + index: '_test_index', + category: RiskCategories.category_1, + description: 'test description', + risk_score: 70, + timestamp: '2023-05-15T16:12:14.967Z', +}; + +describe('RiskInputsPanel', () => { + it('renders', () => { + mockUseAlertsByIds.mockReturnValue({ + loading: false, + error: false, + data: [alertDataMock], + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-inputs-panel')).toBeInTheDocument(); + expect(getByTestId('risk-input-table-description-cell')).toHaveTextContent( + 'Risk inputRule Name' + ); + }); + + it('paginates', () => { + const riskInputs = times((index) => ({ ...TEST_RISK_INPUT, id: index.toString() }), 11); + const alerts = times((index) => ({ ...alertDataMock, _id: index.toString() }), 11); + + mockUseAlertsByIds.mockReturnValue({ + loading: false, + error: false, + data: alerts, + }); + + const { getAllByTestId, getByLabelText } = render( + + + + ); + + expect(getAllByTestId('risk-input-table-description-cell')).toHaveLength(10); + + fireEvent.click(getByLabelText('Next page')); + + expect(getAllByTestId('risk-input-table-description-cell')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.tsx new file mode 100644 index 000000000000..544dca9df62a --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/content.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EuiBasicTableColumn, Pagination } from '@elastic/eui'; +import { useEuiBackgroundColor, EuiSpacer, EuiInMemoryTable, EuiTitle } from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { get } from 'lodash/fp'; +import { ALERT_RULE_NAME } from '@kbn/rule-data-utils'; +import type { RiskInputs } from '../../../../common/risk_engine'; +import { ActionColumn } from './components/action_column'; +import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; +import { RiskInputsUtilityBar } from './components/utility_bar'; +import { useAlertsByIds } from '../../../common/containers/alerts/use_alerts_by_ids'; +import { FlyoutBody } from '../../shared/components/flyout_body'; + +export interface RiskInputsPanelContentProps extends Record { + riskInputs: RiskInputs; +} + +export interface AlertRawData { + fields: Record; + _index: string; + _id: string; +} + +export const RiskInputsPanelContent = ({ riskInputs }: RiskInputsPanelContentProps) => { + const [selectedItems, setSelectedItems] = useState([]); + const alertIds = useMemo(() => riskInputs.map(({ id }) => id), [riskInputs]); + const { loading, data: alertsData } = useAlertsByIds({ alertIds }); + + const euiTableSelectionProps = useMemo( + () => ({ + onSelectionChange: (selected: AlertRawData[]) => { + setSelectedItems(selected); + }, + initialSelected: [], + selectable: () => true, + }), + [] + ); + + const columns: Array> = useMemo( + () => [ + { + name: ( + + ), + width: '80px', + render: (alert: AlertRawData) => { + return ; + }, + }, + { + field: 'fields.@timestamp', + name: ( + + ), + truncateText: false, + mobileOptions: { show: true }, + sortable: true, + width: '30%', + render: (timestamp: string) => , + }, + { + field: 'fields', + 'data-test-subj': 'risk-input-table-description-cell', + name: ( + + ), + truncateText: true, + mobileOptions: { show: true }, + sortable: true, + render: (fields: AlertRawData['fields']) => get(ALERT_RULE_NAME, fields), + }, + ], + [] + ); + + const [currentPage, setCurrentPage] = useState<{ + index: number; + size: number; + }>({ index: 0, size: 10 }); + + const onTableChange = useCallback(({ page }) => { + setCurrentPage(page); + }, []); + + const pagination: Pagination = useMemo( + () => ({ + totalItemCount: riskInputs.length, + pageIndex: currentPage.index, + pageSize: currentPage.size, + }), + [currentPage.index, currentPage.size, riskInputs.length] + ); + + return ( + <> + + +

    + +

    +
    + + {/* Temporary label. It will be replaced by a filter */} + +

    + +

    +
    + + + + +
    + + ); +}; + +RiskInputsPanelContent.displayName = 'RiskInputsPanelContent'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions.ts new file mode 100644 index 000000000000..6a8643c7fd9f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TableId } from '@kbn/securitysolution-data-table'; +import { useMemo } from 'react'; +import { get, noop } from 'lodash/fp'; +import { AttachmentType } from '@kbn/cases-plugin/common'; +import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public'; +import { ALERT_RULE_NAME, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; +import { useGlobalTime } from '../../../../common/containers/use_global_time'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; +import { useAddBulkToTimelineAction } from '../../../../detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline'; +import { useKibana } from '../../../../common/lib/kibana/kibana_react'; +import type { AlertRawData } from '../content'; + +/** + * The returned actions only support alerts risk inputs. + */ +export const useRiskInputActions = (alerts: AlertRawData[], closePopover: () => void) => { + const { from, to } = useGlobalTime(); + const timelineAction = useAddBulkToTimelineAction({ + localFilters: [], + from, + to, + scopeId: SourcererScopeName.detections, + tableId: TableId.riskInputs, + }); + + const { cases: casesService } = useKibana().services; + const createCaseFlyout = casesService?.hooks.useCasesAddToNewCaseFlyout({ onSuccess: noop }); + const selectCaseModal = casesService?.hooks.useCasesAddToExistingCaseModal(); + + const caseAttachments: CaseAttachmentsWithoutOwner = useMemo( + () => + alerts.map((alert: AlertRawData) => ({ + alertId: alert._id, + index: alert._index, + type: AttachmentType.alert, + rule: { + id: get(ALERT_RULE_UUID, alert.fields)[0], + name: get(ALERT_RULE_NAME, alert.fields)[0], + }, + })), + [alerts] + ); + + return useMemo( + () => ({ + addToExistingCase: () => { + closePopover(); + selectCaseModal.open({ getAttachments: () => caseAttachments }); + }, + addToNewCaseClick: () => { + closePopover(); + createCaseFlyout.open({ attachments: caseAttachments }); + }, + addToNewTimeline: () => { + closePopover(); + timelineAction.onClick( + alerts.map((alert: AlertRawData) => { + return { + _id: alert._id, + _index: alert._index, + data: [], + ecs: { + _id: alert._id, + _index: alert._index, + }, + }; + }), + false, + noop, + noop, + noop + ); + }, + }), + [alerts, caseAttachments, closePopover, createCaseFlyout, selectCaseModal, timelineAction] + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.test.tsx new file mode 100644 index 000000000000..49bad231f276 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.test.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EuiContextMenuPanelDescriptor } from '@elastic/eui'; +import { EuiContextMenu } from '@elastic/eui'; +import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; +import { render } from '@testing-library/react'; +import { renderHook } from '@testing-library/react-hooks'; +import React from 'react'; +import { TestProviders } from '../../../../common/mock'; +import { alertDataMock } from '../mocks'; +import { useRiskInputActionsPanels } from './use_risk_input_actions_panels'; + +const casesServiceMock = casesPluginMock.createStartContract(); +const mockCanUseCases = jest.fn().mockReturnValue({ + create: true, + read: true, +}); + +const mockedCasesServices = { + ...casesServiceMock, + helpers: { + ...casesServiceMock.helpers, + canUseCases: mockCanUseCases, + }, +}; + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + return { + ...original, + useKibana: () => ({ + ...original.useKibana(), + services: { + ...original.useKibana().services, + cases: mockedCasesServices, + }, + }), + }; +}); + +const TestMenu = ({ panels }: { panels: EuiContextMenuPanelDescriptor[] }) => ( + +); + +const customRender = (alerts = [alertDataMock]) => { + const { result } = renderHook(() => useRiskInputActionsPanels(alerts, () => {}), { + wrapper: TestProviders, + }); + + return render( + + + + ); +}; + +describe('useRiskInputActionsPanels', () => { + it('displays the rule name when only one alert is selected', () => { + const { getByTestId } = customRender(); + + expect(getByTestId('contextMenuPanelTitle')).toHaveTextContent('Risk input: Rule Name'); + }); + + it('displays number of selected alerts when more than one alert is selected', () => { + const { getByTestId } = customRender([alertDataMock, alertDataMock]); + + expect(getByTestId('contextMenuPanelTitle')).toHaveTextContent('2 selected'); + }); + + it('displays cases actions when user has cases permissions', () => { + const { container } = customRender(); + + expect(container).toHaveTextContent('Add to existing case'); + expect(container).toHaveTextContent('Add to new case'); + }); + + it('does NOT display cases actions when user has NO cases permissions', () => { + mockCanUseCases.mockReturnValue({ + create: false, + read: false, + }); + + const { container } = customRender(); + + expect(container).not.toHaveTextContent('Add to existing case'); + expect(container).not.toHaveTextContent('Add to new case'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.tsx new file mode 100644 index 000000000000..176b2a13db72 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/hooks/use_risk_input_actions_panels.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiTextTruncate } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { SECURITY_SOLUTION_OWNER } from '@kbn/cases-plugin/common'; +import type { CasesService } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/types'; +import { i18n } from '@kbn/i18n'; +import { get } from 'lodash/fp'; +import { ALERT_RULE_NAME } from '@kbn/rule-data-utils'; +import { useRiskInputActions } from './use_risk_input_actions'; +import type { AlertRawData } from '../content'; + +export const useRiskInputActionsPanels = (alerts: AlertRawData[], closePopover: () => void) => { + const { cases: casesService } = useKibana<{ cases?: CasesService }>().services; + const { addToExistingCase, addToNewCaseClick, addToNewTimeline } = useRiskInputActions( + alerts, + closePopover + ); + const userCasesPermissions = casesService?.helpers.canUseCases([SECURITY_SOLUTION_OWNER]); + const hasCasesPermissions = userCasesPermissions?.create && userCasesPermissions?.read; + + return useMemo(() => { + const timelinePanel = { + name: ( + + ), + + onClick: addToNewTimeline, + }; + const ruleName = get(['fields', ALERT_RULE_NAME], alerts[0]) ?? ['']; + const title = i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.riskInputs.actions.title', + { + defaultMessage: 'Risk input: {description}', + values: { + description: + alerts.length === 1 + ? ruleName[0] + : i18n.translate( + 'xpack.securitySolution.flyout.entityDetails.riskInputs.actions.titleDescription', + { + defaultMessage: '{quantity} selected', + values: { + quantity: alerts.length, + }, + } + ), + }, + } + ); + + return [ + { + title: ( + + ), + id: 0, + items: hasCasesPermissions + ? [ + timelinePanel, + { + name: ( + + ), + + onClick: addToNewCaseClick, + }, + + { + name: ( + + ), + + onClick: addToExistingCase, + }, + ] + : [timelinePanel], + }, + ]; + }, [addToExistingCase, addToNewCaseClick, addToNewTimeline, alerts, hasCasesPermissions]); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/index.tsx new file mode 100644 index 000000000000..386ec25bfeaf --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/index.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import type { RiskInputs } from '../../../../common/risk_engine'; +import { RiskInputsPanelContent } from './content'; + +export interface RiskInputsPanelProps extends Record { + riskInputs: RiskInputs; +} + +export interface RiskInputsExpandableFlyoutProps extends FlyoutPanelProps { + key: 'all-risk-inputs'; + params: RiskInputsPanelProps; +} + +export const RiskInputsPanelKey: RiskInputsExpandableFlyoutProps['key'] = 'all-risk-inputs'; + +export const RiskInputsPanel = ({ riskInputs }: RiskInputsPanelProps) => { + return ; +}; + +RiskInputsPanel.displayName = 'RiskInputsPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/mocks/index.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/mocks/index.ts new file mode 100644 index 000000000000..9e6f5db17034 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/risk_inputs_left/mocks/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ALERT_RULE_NAME, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; +import type { AlertRawData } from '../content'; + +export const alertDataMock: AlertRawData = { + _id: 'test-id', + _index: 'test-index', + fields: { + [ALERT_RULE_UUID]: ['2e051244-b3c6-4779-a241-e1b4f0beceb9'], + '@timestamp': ['2023-07-20T20:31:24.896Z'], + [ALERT_RULE_NAME]: ['Rule Name'], + }, +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.stories.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.stories.tsx new file mode 100644 index 000000000000..7c12607919cf --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.stories.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Story } from '@storybook/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; +import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import { StorybookProviders } from '../../../../common/mock/storybook_providers'; +import { mockRiskScoreState } from '../../../../timelines/components/side_panel/new_user_detail/__mocks__'; +import { RiskSummary } from './risk_summary'; + +export default { + component: RiskSummary, + title: 'Components/RiskSummary', +}; + +const flyoutContextValue = { + openLeftPanel: () => window.alert('openLeftPanel called'), + panels: {}, +} as unknown as ExpandableFlyoutContextValue; + +export const Default: Story = () => { + return ( + + +
    + +
    +
    +
    + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.test.tsx new file mode 100644 index 000000000000..774a7c8a8458 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.test.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../../common/mock'; +import { mockRiskScoreState } from '../../user_right/mocks'; +import { RiskSummary } from './risk_summary'; + +jest.mock('../../../../common/components/visualization_actions/visualization_embeddable'); + +describe('RiskSummary', () => { + it('renders risk summary table', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-summary-table')).toBeInTheDocument(); + expect(getByTestId('risk-summary-table')).toHaveTextContent('Inputs1'); + expect(getByTestId('risk-summary-table')).toHaveTextContent('CategoryAlerts'); + }); + + it('renders risk summary table when riskScoreData is empty', () => { + const { getByTestId } = render( + + + + ); + expect(getByTestId('risk-summary-table')).toBeInTheDocument(); + }); + + it('renders visualization embeddable', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('visualization-embeddable')).toBeInTheDocument(); + }); + + it('renders updated at', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('risk-summary-updatedAt')).toHaveTextContent('Updated Nov 8, 1989'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.tsx new file mode 100644 index 000000000000..763a6377a9d6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/risk_summary.tsx @@ -0,0 +1,254 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import type { EuiBasicTableColumn } from '@elastic/eui'; +import { + useEuiTheme, + EuiAccordion, + EuiTitle, + EuiSpacer, + EuiBasicTable, + EuiFlexGroup, + EuiFlexItem, + useEuiFontSize, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { i18n } from '@kbn/i18n'; +import { InspectButton, InspectButtonContainer } from '../../../../common/components/inspect'; +import { ONE_WEEK_IN_HOURS } from '../../../../timelines/components/side_panel/new_user_detail/constants'; +import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; +import { RiskScoreEntity } from '../../../../../common/risk_engine'; +import type { RiskScoreState } from '../../../../explore/containers/risk_score'; +import { VisualizationEmbeddable } from '../../../../common/components/visualization_actions/visualization_embeddable'; +import { getRiskScoreSummaryAttributes } from '../../../../common/components/visualization_actions/lens_attributes/common/risk_scores/risk_score_summary'; +import { ExpandablePanel } from '../../../shared/components/expandable_panel'; +import { RiskInputsPanelKey } from '../../risk_inputs_left'; + +export interface RiskSummaryProps { + riskScoreData: RiskScoreState; + queryId: string; +} + +interface TableItem { + category: string; + count: number; +} +const LENS_VISUALIZATION_HEIGHT = 126; // Static height in pixels specified by design +const LAST_30_DAYS = { from: 'now-30d', to: 'now' }; + +export const RiskSummary = React.memo(({ riskScoreData, queryId }: RiskSummaryProps) => { + const { data: userRisk } = riskScoreData; + const userRiskData = userRisk && userRisk.length > 0 ? userRisk[0] : undefined; + const { euiTheme } = useEuiTheme(); + + const { openLeftPanel } = useExpandableFlyoutContext(); + const openPanel = useCallback(() => { + openLeftPanel({ + id: RiskInputsPanelKey, + params: { + riskInputs: userRiskData?.user.risk.inputs, + }, + }); + }, [openLeftPanel, userRiskData?.user.risk.inputs]); + + const lensAttributes = useMemo(() => { + return getRiskScoreSummaryAttributes({ + severity: userRiskData?.user?.risk?.calculated_level, + query: `user.name: ${userRiskData?.user?.name}`, + spaceId: 'default', + riskEntity: RiskScoreEntity.user, + }); + }, [userRiskData]); + + const columns: Array> = useMemo( + () => [ + { + field: 'category', + name: ( + + ), + truncateText: false, + mobileOptions: { show: true }, + sortable: true, + }, + { + field: 'count', + name: ( + + ), + truncateText: false, + mobileOptions: { show: true }, + sortable: true, + dataType: 'number', + }, + ], + [] + ); + + const xsFontSize = useEuiFontSize('xxs').fontSize; + + const items: TableItem[] = useMemo( + () => [ + { + category: i18n.translate('xpack.securitySolution.flyout.entityDetails.alertsGroupLabel', { + defaultMessage: 'Alerts', + }), + count: userRiskData?.user.risk.inputs?.length ?? 0, + }, + ], + [userRiskData?.user.risk.inputs?.length] + ); + + return ( + +

    + +

    + + } + extraAction={ + + {userRiskData && ( + + ), + }} + /> + )} + + } + > + + + + ), + link: { + callback: openPanel, + tooltip: ( + + ), + }, + iconType: 'arrowStart', + }} + expand={{ + expandable: false, + }} + > + + +
    + {userRiskData && ( + + } + /> + )} +
    +
    + + +
    +
    + + } + /> +
    + +
    +
    +
    +
    +
    + +
    + ); +}); +RiskSummary.displayName = 'RiskSummary'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.stories.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.stories.tsx new file mode 100644 index 000000000000..b4555969dd41 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.stories.tsx @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { EuiFlyout } from '@elastic/eui'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; +import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import { StorybookProviders } from '../../../common/mock/storybook_providers'; +import { + mockManagedUser, + mockObservedUser, + mockRiskScoreState, +} from '../../../timelines/components/side_panel/new_user_detail/__mocks__'; +import { UserPanelContent } from './content'; + +const flyoutContextValue = { + openLeftPanel: () => window.alert('openLeftPanel called'), + panels: {}, +} as unknown as ExpandableFlyoutContextValue; + +storiesOf('Components/UserPanelContent', module) + .addDecorator((storyFn) => ( + + + {}}> + {storyFn()} + + + + )) + .add('default', () => ( + + )) + .add('integration disabled', () => ( + + )) + .add('no managed data', () => ( + + )) + .add('no observed data', () => ( + + )) + .add('loading', () => ( + + )); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx new file mode 100644 index 000000000000..ddba2093628e --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiHorizontalRule } from '@elastic/eui'; + +import React from 'react'; +import type { + ManagedUserData, + ObservedUserData, +} from '../../../timelines/components/side_panel/new_user_detail/types'; +import { ManagedUser } from '../../../timelines/components/side_panel/new_user_detail/managed_user'; +import { ObservedUser } from '../../../timelines/components/side_panel/new_user_detail/observed_user'; +import type { RiskScoreEntity } from '../../../../common/search_strategy'; +import type { RiskScoreState } from '../../../explore/containers/risk_score'; +import { RiskSummary } from '../shared/components/risk_summary'; +import { USER_PANEL_RISK_SCORE_QUERY_ID } from '.'; +import { FlyoutBody } from '../../shared/components/flyout_body'; + +interface UserPanelContentProps { + observedUser: ObservedUserData; + managedUser: ManagedUserData; + riskScoreState: RiskScoreState; + contextID: string; + scopeId: string; + isDraggable: boolean; +} + +export const UserPanelContent = ({ + observedUser, + managedUser, + riskScoreState, + contextID, + scopeId, + isDraggable, +}: UserPanelContentProps) => { + return ( + + {riskScoreState.isModuleEnabled && riskScoreState.data?.length !== 0 && ( + <> + + + + )} + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.test.tsx new file mode 100644 index 000000000000..e4e4186919b6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.test.tsx @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../common/mock'; +import { + mockManagedUser, + mockObservedUser, +} from '../../../timelines/components/side_panel/new_user_detail/__mocks__'; +import { UserPanelHeader } from './header'; + +const mockProps = { + userName: 'test', + managedUser: mockManagedUser, + observedUser: mockObservedUser, +}; + +jest.mock('../../../common/components/visualization_actions/visualization_embeddable'); + +describe('UserDetailsContent', () => { + it('renders', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('user-panel-header')).toBeInTheDocument(); + }); + + it('renders observed user date when it is bigger than managed user date', () => { + const futureDay = '2989-03-07T20:00:00.000Z'; + const { getByTestId } = render( + + + + ); + + expect(getByTestId('user-panel-header-lastSeen').textContent).toContain('Mar 7, 2989'); + }); + + it('renders managed user date when it is bigger than observed user date', () => { + const futureDay = '2989-03-07T20:00:00.000Z'; + const { getByTestId } = render( + + + + ); + + expect(getByTestId('user-panel-header-lastSeen').textContent).toContain('Mar 7, 2989'); + }); + + it('renders observed and managed badges when lastSeen is defined', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('user-panel-header-observed-badge')).toBeInTheDocument(); + expect(getByTestId('user-panel-header-managed-badge')).toBeInTheDocument(); + }); + + it('does not render observed badge when lastSeen date is undefined', () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('user-panel-header-observed-badge')).not.toBeInTheDocument(); + }); + + it('does not render managed badge when lastSeen date is undefined', () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('user-panel-header-managed-badge')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx new file mode 100644 index 000000000000..12acfd0d2815 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiSpacer, EuiBadge, EuiText, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React, { useMemo } from 'react'; +import { max } from 'lodash/fp'; +import { SecurityPageName } from '@kbn/security-solution-navigation'; +import { getUsersDetailsUrl } from '../../../common/components/link_to/redirect_to_users'; +import type { + ManagedUserData, + ObservedUserData, +} from '../../../timelines/components/side_panel/new_user_detail/types'; + +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; +import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; +import { FlyoutHeader } from '../../shared/components/flyout_header'; +import { FlyoutTitle } from '../../shared/components/flyout_title'; + +interface UserPanelHeaderProps { + userName: string; + observedUser: ObservedUserData; + managedUser: ManagedUserData; +} + +export const UserPanelHeader = ({ userName, observedUser, managedUser }: UserPanelHeaderProps) => { + const lastSeenDate = useMemo( + () => + max([observedUser.lastSeen, managedUser.lastSeen].map((el) => el.date && new Date(el.date))), + [managedUser.lastSeen, observedUser.lastSeen] + ); + + return ( + + + + + {lastSeenDate && } + + + + + + + + + + + + {observedUser.lastSeen.date && ( + + + + )} + + + {managedUser.lastSeen.date && ( + + + + )} + + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx new file mode 100644 index 000000000000..e06399305fe0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { TestProviders } from '../../../common/mock'; +import type { UserPanelProps } from '.'; +import { UserPanel } from '.'; +import { mockRiskScoreState } from './mocks'; + +import { + mockManagedUser, + mockObservedUser, +} from '../../../timelines/components/side_panel/new_user_detail/__mocks__'; + +const mockProps: UserPanelProps = { + userName: 'test', + contextID: 'test-user-panel', + scopeId: 'test-scope-id', + isDraggable: false, +}; + +jest.mock('../../../common/components/visualization_actions/visualization_embeddable'); + +const mockedUseRiskScore = jest.fn().mockReturnValue(mockRiskScoreState); +jest.mock('../../../explore/containers/risk_score', () => ({ + useRiskScore: () => mockedUseRiskScore(), +})); + +const mockedUseManagedUser = jest.fn().mockReturnValue(mockManagedUser); +const mockedUseObservedUser = jest.fn().mockReturnValue(mockObservedUser); + +jest.mock('../../../timelines/components/side_panel/new_user_detail/hooks', () => { + const originalModule = jest.requireActual( + '../../../timelines/components/side_panel/new_user_detail/hooks' + ); + return { + ...originalModule, + useManagedUser: () => mockedUseManagedUser(), + useObservedUser: () => mockedUseObservedUser(), + }; +}); + +describe('UserPanel', () => { + beforeEach(() => { + mockedUseRiskScore.mockReturnValue(mockRiskScoreState); + mockedUseManagedUser.mockReturnValue(mockManagedUser); + mockedUseObservedUser.mockReturnValue(mockObservedUser); + }); + + it('renders', () => { + const { getByTestId, queryByTestId } = render( + + + + ); + + expect(getByTestId('user-panel-header')).toBeInTheDocument(); + expect(queryByTestId('securitySolutionFlyoutLoading')).not.toBeInTheDocument(); + expect(getByTestId('securitySolutionFlyoutNavigationExpandDetailButton')).toBeInTheDocument(); + }); + + it('renders loading state when risk score is loading', () => { + mockedUseRiskScore.mockReturnValue({ + ...mockRiskScoreState, + data: undefined, + loading: true, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); + }); + + it('renders loading state when observed user is loading', () => { + mockedUseObservedUser.mockReturnValue({ + ...mockObservedUser, + isLoading: true, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); + }); + + it('renders loading state when managed user is loading', () => { + mockedUseManagedUser.mockReturnValue({ + ...mockManagedUser, + isLoading: true, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx new file mode 100644 index 000000000000..8f22560730bf --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { useQueryInspector } from '../../../common/components/page/manage_query'; +import { UsersType } from '../../../explore/users/store/model'; +import { getCriteriaFromUsersType } from '../../../common/components/ml/criteria/get_criteria_from_users_type'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; +import { + useManagedUser, + useObservedUser, +} from '../../../timelines/components/side_panel/new_user_detail/hooks'; +import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; +import { buildUserNamesFilter } from '../../../../common/search_strategy'; +import { useRiskScore } from '../../../explore/containers/risk_score'; +import { RiskScoreEntity } from '../../../../common/risk_engine'; +import { FlyoutLoading } from '../../shared/components/flyout_loading'; +import { RiskInputsPanelKey } from '../risk_inputs_left'; +import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; +import { UserPanelContent } from './content'; +import { UserPanelHeader } from './header'; + +export interface UserPanelProps extends Record { + contextID: string; + scopeId: string; + userName: string; + isDraggable?: boolean; +} + +export interface UserPanelExpandableFlyoutProps extends FlyoutPanelProps { + key: 'user-panel'; + params: UserPanelProps; +} + +export const UserPanelKey: UserPanelExpandableFlyoutProps['key'] = 'user-panel'; +export const USER_PANEL_RISK_SCORE_QUERY_ID = 'userPanelRiskScoreQuery'; +const FIRST_RECORD_PAGINATION = { + cursorStart: 0, + querySize: 1, +}; + +export const UserPanel = ({ contextID, scopeId, userName, isDraggable }: UserPanelProps) => { + const userNameFilterQuery = useMemo( + () => (userName ? buildUserNamesFilter([userName]) : undefined), + [userName] + ); + + const riskScoreState = useRiskScore({ + riskEntity: RiskScoreEntity.user, + filterQuery: userNameFilterQuery, + onlyLatest: false, + pagination: FIRST_RECORD_PAGINATION, + }); + + const { inspect, refetch, loading } = riskScoreState; + const { to, from, isInitializing, setQuery, deleteQuery } = useGlobalTime(); + + const observedUser = useObservedUser(userName); + const managedUser = useManagedUser(userName); + + const { data: userRisk } = riskScoreState; + const userRiskData = userRisk && userRisk.length > 0 ? userRisk[0] : undefined; + + useQueryInspector({ + deleteQuery, + inspect, + loading, + queryId: USER_PANEL_RISK_SCORE_QUERY_ID, + refetch, + setQuery, + }); + + const { openLeftPanel } = useExpandableFlyoutContext(); + const openPanel = useCallback(() => { + openLeftPanel({ + id: RiskInputsPanelKey, + params: { + riskInputs: userRiskData?.user.risk.inputs, + }, + }); + }, [openLeftPanel, userRiskData?.user.risk.inputs]); + + if (riskScoreState.loading || observedUser.isLoading || managedUser.isLoading) { + return ; + } + + return ( + + {({ isLoadingAnomaliesData, anomaliesData, jobNameById }) => { + const observedUserWithAnomalies = { + ...observedUser, + anomalies: { + isLoading: isLoadingAnomaliesData, + anomalies: anomaliesData, + jobNameById, + }, + }; + return ( + <> + + + + + ); + }} + + ); +}; + +UserPanel.displayName = 'UserPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts new file mode 100644 index 000000000000..bfd1a9a80219 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/mocks/index.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RiskScoreState } from '../../../../explore/containers/risk_score'; +import type { RiskScoreEntity, UserRiskScore } from '../../../../../common/search_strategy'; +import { RiskSeverity } from '../../../../../common/search_strategy'; +import { RiskCategories } from '../../../../../common/risk_engine'; + +const userRiskScore: UserRiskScore = { + '@timestamp': '626569200000', + user: { + name: 'test', + risk: { + rule_risks: [], + calculated_score_norm: 70, + multipliers: [], + calculated_level: RiskSeverity.high, + inputs: [ + { + id: '_id', + index: '_index', + category: RiskCategories.category_1, + description: 'Alert from Rule: My rule', + risk_score: 30, + timestamp: '2021-08-19T18:55:59.000Z', + }, + ], + }, + }, + alertsCount: 0, + oldestAlertTimestamp: '626569200000', +}; + +export const mockRiskScoreState: RiskScoreState = { + data: [userRiskScore], + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + refetch: () => {}, + totalCount: 0, + isModuleEnabled: true, + isAuthorized: true, + isDeprecated: false, + loading: false, +}; diff --git a/x-pack/plugins/security_solution/public/flyout/index.tsx b/x-pack/plugins/security_solution/public/flyout/index.tsx index a29654659c74..a9194a3a766c 100644 --- a/x-pack/plugins/security_solution/public/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/index.tsx @@ -12,29 +12,31 @@ import { ExpandableFlyoutProvider, } from '@kbn/expandable-flyout'; import type { IsolateHostPanelProps } from './document_details/isolate_host'; -import { IsolateHostPanel, IsolateHostPanelKey } from './document_details/isolate_host'; +import { + IsolateHostPanel, + DocumentDetailsIsolateHostPanelKey, +} from './document_details/isolate_host'; import { IsolateHostPanelProvider } from './document_details/isolate_host/context'; import type { RightPanelProps } from './document_details/right'; -import { RightPanel, RightPanelKey } from './document_details/right'; +import { RightPanel, DocumentDetailsRightPanelKey } from './document_details/right'; import { RightPanelProvider } from './document_details/right/context'; import type { LeftPanelProps } from './document_details/left'; -import { LeftPanel, LeftPanelKey } from './document_details/left'; +import { LeftPanel, DocumentDetailsLeftPanelKey } from './document_details/left'; import { LeftPanelProvider } from './document_details/left/context'; -import { - SecuritySolutionFlyoutUrlSyncProvider, - useSecurityFlyoutUrlSync, -} from './document_details/shared/context/url_sync'; import type { PreviewPanelProps } from './document_details/preview'; -import { PreviewPanel, PreviewPanelKey } from './document_details/preview'; +import { PreviewPanel, DocumentDetailsPreviewPanelKey } from './document_details/preview'; import { PreviewPanelProvider } from './document_details/preview/context'; - +import type { UserPanelExpandableFlyoutProps } from './entity_details/user_right'; +import { UserPanel, UserPanelKey } from './entity_details/user_right'; +import type { RiskInputsExpandableFlyoutProps } from './entity_details/risk_inputs_left'; +import { RiskInputsPanel, RiskInputsPanelKey } from './entity_details/risk_inputs_left'; /** * List of all panels that will be used within the document details expandable flyout. * This needs to be passed to the expandable flyout registeredPanels property. */ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] = [ { - key: RightPanelKey, + key: DocumentDetailsRightPanelKey, component: (props) => ( @@ -42,7 +44,7 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, { - key: LeftPanelKey, + key: DocumentDetailsLeftPanelKey, component: (props) => ( @@ -50,7 +52,7 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, { - key: PreviewPanelKey, + key: DocumentDetailsPreviewPanelKey, component: (props) => ( @@ -58,51 +60,34 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, { - key: IsolateHostPanelKey, + key: DocumentDetailsIsolateHostPanelKey, component: (props) => ( ), }, + { + key: UserPanelKey, + component: (props) => , + }, + { + key: RiskInputsPanelKey, + component: (props) => ( + + ), + }, ]; -const OuterProviders: FC = ({ children }) => { - return {children}; -}; - -const InnerProviders: FC = ({ children }) => { - const [flyoutRef, handleFlyoutChangedOrClosed] = useSecurityFlyoutUrlSync(); - - return ( - - {children} - - ); -}; - +// NOTE: provider below accepts "storage" prop, please take a look into component's JSDoc. export const SecuritySolutionFlyoutContextProvider: FC = ({ children }) => ( - - {children} - + {children} ); SecuritySolutionFlyoutContextProvider.displayName = 'SecuritySolutionFlyoutContextProvider'; -export const SecuritySolutionFlyout = memo(() => { - const [_flyoutRef, handleFlyoutChangedOrClosed] = useSecurityFlyoutUrlSync(); - - return ( - - ); -}); +export const SecuritySolutionFlyout = memo(() => ( + +)); SecuritySolutionFlyout.displayName = 'SecuritySolutionFlyout'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx index 208aa52cfeec..2f346e70b367 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx @@ -124,6 +124,7 @@ export const ExpandablePanel: React.FC = ({ {expandable && children && toggleIcon} diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx index cf8d82ff251a..e41bf0c347b4 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx @@ -7,6 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { EuiButtonIcon } from '@elastic/eui'; import { FlyoutNavigation } from './flyout_navigation'; @@ -21,7 +22,7 @@ export default { const flyoutContextValue = { closeLeftPanel: () => window.alert('close left panel'), panels: {}, -} as unknown as ExpandableFlyoutContext; +} as unknown as ExpandableFlyoutContextValue; export const Expand: Story = () => { return ( @@ -38,7 +39,7 @@ export const Collapse: Story = () => { { ...flyoutContextValue, panels: { left: {} }, - } as unknown as ExpandableFlyoutContext + } as unknown as ExpandableFlyoutContextValue } > diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx index 9972f0e90f35..7642dfcfd81e 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { act, render } from '@testing-library/react'; +import type { ExpandableFlyoutContextValue } from '@kbn/expandable-flyout/src/context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { TestProviders } from '../../../common/mock'; import { FlyoutNavigation } from './flyout_navigation'; @@ -24,7 +25,7 @@ describe('', () => { it('should render expand button', () => { const flyoutContextValue = { panels: {}, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId, queryByTestId } = render( @@ -47,7 +48,7 @@ describe('', () => { panels: { left: {}, }, - } as unknown as ExpandableFlyoutContext; + } as unknown as ExpandableFlyoutContextValue; const { getByTestId, queryByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx index 820b0ac5efcd..cc969988a16a 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx @@ -48,7 +48,7 @@ export const FlyoutNavigation: FC = memo( const { euiTheme } = useEuiTheme(); const { closeLeftPanel, panels } = useExpandableFlyoutContext(); - const isExpanded: boolean = panels.left != null; + const isExpanded: boolean = !!panels.left; const collapseDetails = useCallback(() => closeLeftPanel(), [closeLeftPanel]); const collapseButton = useMemo( diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx index 8668f727201d..1f2d0c128f41 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx @@ -9,46 +9,40 @@ import React from 'react'; import { render } from '@testing-library/react'; import { FlyoutTitle } from './flyout_title'; import { - FLYOUT_TITLE_TEST_ID, TITLE_HEADER_ICON_TEST_ID, + TITLE_HEADER_TEXT_TEST_ID, TITLE_LINK_ICON_TEST_ID, } from './test_ids'; const title = 'test title'; +const TEST_ID = 'test'; describe('', () => { it('should render title and icon', () => { const { getByTestId, queryByTestId } = render( - + ); - expect(getByTestId(FLYOUT_TITLE_TEST_ID)).toHaveTextContent(title); - expect( - getByTestId(FLYOUT_TITLE_TEST_ID).querySelector('[data-euiicon-type="warning"]') - ).toBeInTheDocument(); - expect(queryByTestId(TITLE_LINK_ICON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(TITLE_HEADER_TEXT_TEST_ID(TEST_ID))).toHaveTextContent(title); + expect(getByTestId(TITLE_HEADER_ICON_TEST_ID(TEST_ID))).toBeInTheDocument(); + expect(queryByTestId(TITLE_LINK_ICON_TEST_ID(TEST_ID))).not.toBeInTheDocument(); }); it('should not render icon if iconType is not passed', () => { - const { getByTestId, queryByTestId } = render(); + const { getByTestId, queryByTestId } = render( + + ); - expect(getByTestId(FLYOUT_TITLE_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(TITLE_HEADER_ICON_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(TITLE_LINK_ICON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(TITLE_HEADER_TEXT_TEST_ID(TEST_ID))).toBeInTheDocument(); + expect(queryByTestId(TITLE_HEADER_ICON_TEST_ID(TEST_ID))).not.toBeInTheDocument(); + expect(queryByTestId(TITLE_LINK_ICON_TEST_ID(TEST_ID))).not.toBeInTheDocument(); }); it('should render popout icon if title is a link', () => { - const { getByTestId } = render(); - - expect(getByTestId(FLYOUT_TITLE_TEST_ID)).toHaveTextContent(title); - expect(getByTestId(TITLE_LINK_ICON_TEST_ID)).toBeInTheDocument(); - expect( - getByTestId(FLYOUT_TITLE_TEST_ID).querySelector('[data-euiicon-type="popout"]') - ).toBeInTheDocument(); - }); + const { getByTestId } = render(); - it('should render title with custom data test subject', () => { - const { getByTestId } = render(); - expect(getByTestId('test-title')).toHaveTextContent(title); + expect(getByTestId(TITLE_HEADER_TEXT_TEST_ID(TEST_ID))).toHaveTextContent(title); + expect(getByTestId(TITLE_LINK_ICON_TEST_ID(TEST_ID))).toBeInTheDocument(); + expect(getByTestId(TITLE_LINK_ICON_TEST_ID(TEST_ID))).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx index d9e9d280d38c..8c2c12ab80e9 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx @@ -18,11 +18,6 @@ import { EuiTextColor, } from '@elastic/eui'; import { css } from '@emotion/react'; -import { - FLYOUT_TITLE_TEST_ID, - TITLE_HEADER_ICON_TEST_ID, - TITLE_LINK_ICON_TEST_ID, -} from './test_ids'; export interface FlyoutTitleProps { /** @@ -48,7 +43,7 @@ export interface FlyoutTitleProps { * Title component with optional icon to indicate the type of document, can be used for text or a link */ export const FlyoutTitle: FC = memo( - ({ title, iconType, isLink = false, 'data-test-subj': dataTestSubj = FLYOUT_TITLE_TEST_ID }) => { + ({ title, iconType, isLink = false, 'data-test-subj': dataTestSubj }) => { const { euiTheme } = useEuiTheme(); const titleIcon = useMemo(() => { @@ -57,23 +52,23 @@ export const FlyoutTitle: FC = memo( type={iconType} size="m" className="eui-alignBaseline" - data-test-subj={TITLE_HEADER_ICON_TEST_ID} + data-test-subj={`${dataTestSubj}Icon`} css={css` margin-right: ${euiTheme.size.xs}; `} /> ) : null; - }, [iconType, euiTheme.size.xs]); + }, [dataTestSubj, iconType, euiTheme.size.xs]); const titleComponent = useMemo(() => { return ( - + {title} ); - }, [title, isLink, euiTheme.colors.primaryText]); + }, [dataTestSubj, title, isLink, euiTheme.colors.primaryText]); const linkIcon = useMemo(() => { return ( @@ -83,19 +78,14 @@ export const FlyoutTitle: FC = memo( css={css` margin-bottom: ${euiTheme.size.xs}; `} - data-test-subj={TITLE_LINK_ICON_TEST_ID} + data-test-subj={`${dataTestSubj}LinkIcon`} /> ); - }, [euiTheme.size.xs]); + }, [dataTestSubj, euiTheme.size.xs]); return ( - +
    `${dataTestSubj}Icon`; +export const TITLE_HEADER_TEXT_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Text`; +export const TITLE_LINK_ICON_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}LinkIcon`; diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/criteria_conditions.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/criteria_conditions.tsx index ac7422619ee0..d872eee2d2ce 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/criteria_conditions.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/criteria_conditions.tsx @@ -17,6 +17,7 @@ import { OS_WINDOWS, CONDITION_AND, CONDITION_OPERATOR_TYPE_WILDCARD_MATCHES, + CONDITION_OPERATOR_TYPE_DOES_NOT_MATCH, CONDITION_OPERATOR_TYPE_NESTED, CONDITION_OPERATOR_TYPE_MATCH, CONDITION_OPERATOR_TYPE_MATCH_ANY, @@ -47,6 +48,7 @@ const OPERATOR_TYPE_LABELS_INCLUDED = Object.freeze({ const OPERATOR_TYPE_LABELS_EXCLUDED = Object.freeze({ [ListOperatorTypeEnum.MATCH_ANY]: CONDITION_OPERATOR_TYPE_NOT_MATCH_ANY, [ListOperatorTypeEnum.MATCH]: CONDITION_OPERATOR_TYPE_NOT_MATCH, + [ListOperatorTypeEnum.WILDCARD]: CONDITION_OPERATOR_TYPE_DOES_NOT_MATCH, }); const EuiFlexGroupNested = styled(EuiFlexGroup)` diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/translations.ts b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/translations.ts index 273cda46aa72..2024541091d5 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/translations.ts +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/translations.ts @@ -68,6 +68,13 @@ export const CONDITION_OPERATOR_TYPE_WILDCARD_MATCHES = i18n.translate( } ); +export const CONDITION_OPERATOR_TYPE_DOES_NOT_MATCH = i18n.translate( + 'xpack.securitySolution.artifactCard.conditions.wildcardDoesNotMatchOperator', + { + defaultMessage: 'DOES NOT MATCH', + } +); + export const CONDITION_OPERATOR_TYPE_NESTED = i18n.translate( 'xpack.securitySolution.artifactCard.conditions.nestedOperator', { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts index 00dc41b94ef4..a736e05c3314 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts @@ -26,8 +26,7 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/169689 -describe.skip('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts index 409358136632..b80632372601 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts @@ -22,8 +22,7 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/170674 -describe.skip('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts index 3d02bc14251d..75074b0d3f94 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts @@ -20,8 +20,7 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/169821 -describe.skip('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { beforeEach(() => { login(); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/reponse_actions_history.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/reponse_actions_history.cy.ts deleted file mode 100644 index 4efd03c01d05..000000000000 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/reponse_actions_history.cy.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ReturnTypeFromChainable } from '../../types'; -import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; -import { login } from '../../tasks/login'; -import { loadPage } from '../../tasks/common'; - -describe('Response actions history page', { tags: ['@ess', '@serverless'] }, () => { - let endpointData: ReturnTypeFromChainable; - // let actionData: ReturnTypeFromChainable; - - before(() => { - indexEndpointHosts({ numResponseActions: 11 }).then((indexEndpoints) => { - endpointData = indexEndpoints; - }); - }); - - beforeEach(() => { - login(); - }); - - after(() => { - if (endpointData) { - endpointData.cleanup(); - // @ts-expect-error ignore setting to undefined - endpointData = undefined; - } - }); - - it('retains expanded action details on page reload', () => { - loadPage(`/app/security/administration/response_actions_history`); - cy.getByTestSubj('response-actions-list-expand-button').eq(3).click(); // 4th row on 1st page - cy.getByTestSubj('response-actions-list-details-tray').should('exist'); - cy.url().should('include', 'withOutputs'); - - // navigate to page 2 - cy.getByTestSubj('pagination-button-1').click(); - cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); - - // reload with URL params on page 2 with existing URL - cy.reload(); - cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); - - // navigate to page 1 - cy.getByTestSubj('pagination-button-0').click(); - cy.getByTestSubj('response-actions-list-details-tray').should('exist'); - }); - - it('collapses expanded tray with a single click', () => { - loadPage(`/app/security/administration/response_actions_history`); - // 2nd row on 1st page - cy.getByTestSubj('response-actions-list-expand-button').eq(1).as('2nd-row'); - - // expand the row - cy.get('@2nd-row').click(); - cy.getByTestSubj('response-actions-list-details-tray').should('exist'); - cy.url().should('include', 'withOutputs'); - - // collapse the row - cy.intercept('GET', '/api/endpoint/action*').as('getResponses'); - cy.get('@2nd-row').click(); - // wait for the API response to come back - // and then see if the tray is actually closed - cy.wait('@getResponses', { timeout: 500 }).then(() => { - cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); - cy.url().should('not.include', 'withOutputs'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts new file mode 100644 index 000000000000..a36f7e3beaec --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_actions_history.cy.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ReturnTypeFromChainable } from '../../types'; +import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; +import { login } from '../../tasks/login'; +import { loadPage } from '../../tasks/common'; + +describe('Response actions history page', { tags: ['@ess', '@serverless'] }, () => { + let endpointData: ReturnTypeFromChainable; + + before(() => { + indexEndpointHosts({ numResponseActions: 11 }).then((indexEndpoints) => { + endpointData = indexEndpoints; + }); + }); + + beforeEach(() => { + login(); + }); + + after(() => { + if (endpointData) { + endpointData.cleanup(); + // @ts-expect-error ignore setting to undefined + endpointData = undefined; + } + }); + + it('retains expanded action details on page reload', () => { + loadPage(`/app/security/administration/response_actions_history`); + cy.getByTestSubj('response-actions-list-expand-button').eq(3).click(); // 4th row on 1st page + cy.getByTestSubj('response-actions-list-details-tray').should('exist'); + cy.url().should('include', 'withOutputs'); + + // navigate to page 2 + cy.getByTestSubj('pagination-button-1').click(); + cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); + + // reload with URL params on page 2 with existing URL + cy.reload(); + cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); + + // navigate to page 1 + cy.getByTestSubj('pagination-button-0').click(); + cy.getByTestSubj('response-actions-list-details-tray').should('exist'); + }); + + it('collapses expanded tray with a single click', () => { + loadPage(`/app/security/administration/response_actions_history`); + // 2nd row on 1st page + cy.getByTestSubj('response-actions-list-expand-button').eq(1).as('2nd-row'); + + // expand the row + cy.get('@2nd-row').click(); + cy.getByTestSubj('response-actions-list-details-tray').should('exist'); + cy.url().should('include', 'withOutputs'); + + // collapse the row + cy.intercept('GET', '/api/endpoint/action*').as('getResponses'); + cy.get('@2nd-row').click(); + // wait for the API response to come back + // and then see if the tray is actually closed + cy.wait('@getResponses', { timeout: 500 }).then(() => { + cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); + cy.url().should('not.include', 'withOutputs'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolate.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolate.cy.ts new file mode 100644 index 000000000000..44fdf9d63fb6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolate.cy.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PolicyData } from '../../../../../../common/endpoint/types'; +import type { CreateAndEnrollEndpointHostResponse } from '../../../../../../scripts/endpoint/common/endpoint_host_services'; +import { + openResponseConsoleFromEndpointList, + performCommandInputChecks, + submitCommand, + waitForCommandToBeExecuted, + waitForEndpointListPageToBeLoaded, +} from '../../../tasks/response_console'; +import type { IndexedFleetEndpointPolicyResponse } from '../../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; +import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../../tasks/fleet'; +import { + checkEndpointListForOnlyIsolatedHosts, + checkEndpointListForOnlyUnIsolatedHosts, +} from '../../../tasks/isolate'; + +import { login } from '../../../tasks/login'; +import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; +import { createEndpointHost } from '../../../tasks/create_endpoint_host'; +import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; + +describe('Response console', { tags: ['@ess', '@serverless'] }, () => { + let indexedPolicy: IndexedFleetEndpointPolicyResponse; + let policy: PolicyData; + let createdHost: CreateAndEnrollEndpointHostResponse; + + before(() => { + getEndpointIntegrationVersion().then((version) => + createAgentPolicyTask(version).then((data) => { + indexedPolicy = data; + policy = indexedPolicy.integrationPolicies[0]; + + return enableAllPolicyProtections(policy.id).then(() => { + // Create and enroll a new Endpoint host + return createEndpointHost(policy.policy_id).then((host) => { + createdHost = host as CreateAndEnrollEndpointHostResponse; + }); + }); + }) + ); + }); + + after(() => { + if (createdHost) { + cy.task('destroyEndpointHost', createdHost); + } + + if (indexedPolicy) { + cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); + } + + if (createdHost) { + deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); + } + }); + + describe('Host Isolation:', () => { + beforeEach(() => { + login(); + }); + + it('should isolate a host from response console', () => { + const command = 'isolate'; + waitForEndpointListPageToBeLoaded(createdHost.hostname); + checkEndpointListForOnlyUnIsolatedHosts(); + openResponseConsoleFromEndpointList(); + performCommandInputChecks(command); + submitCommand(); + waitForCommandToBeExecuted(command); + waitForEndpointListPageToBeLoaded(createdHost.hostname); + checkEndpointListForOnlyIsolatedHosts(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts deleted file mode 100644 index 5b0d198742ed..000000000000 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/isolation.cy.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { PolicyData } from '../../../../../../common/endpoint/types'; -import type { CreateAndEnrollEndpointHostResponse } from '../../../../../../scripts/endpoint/common/endpoint_host_services'; -import { - openResponseConsoleFromEndpointList, - performCommandInputChecks, - submitCommand, - waitForCommandToBeExecuted, - waitForEndpointListPageToBeLoaded, -} from '../../../tasks/response_console'; -import type { IndexedFleetEndpointPolicyResponse } from '../../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; -import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../../tasks/fleet'; -import { - checkEndpointListForOnlyIsolatedHosts, - checkEndpointListForOnlyUnIsolatedHosts, - isolateHostFromEndpointList, -} from '../../../tasks/isolate'; - -import { login } from '../../../tasks/login'; -import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; -import { createEndpointHost } from '../../../tasks/create_endpoint_host'; -import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; - -// Failing: See https://github.com/elastic/kibana/issues/170470 -describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { - beforeEach(() => { - login(); - }); - - describe('Host Isolation:', () => { - let indexedPolicy: IndexedFleetEndpointPolicyResponse; - let policy: PolicyData; - let createdHost: CreateAndEnrollEndpointHostResponse; - - before(() => { - getEndpointIntegrationVersion().then((version) => - createAgentPolicyTask(version).then((data) => { - indexedPolicy = data; - policy = indexedPolicy.integrationPolicies[0]; - - return enableAllPolicyProtections(policy.id).then(() => { - // Create and enroll a new Endpoint host - return createEndpointHost(policy.policy_id).then((host) => { - createdHost = host as CreateAndEnrollEndpointHostResponse; - }); - }); - }) - ); - }); - - after(() => { - if (createdHost) { - cy.task('destroyEndpointHost', createdHost); - } - - if (indexedPolicy) { - cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); - } - - if (createdHost) { - deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); - } - }); - - it('should release an isolated host from response console', () => { - const command = 'release'; - waitForEndpointListPageToBeLoaded(createdHost.hostname); - // isolate the host first - isolateHostFromEndpointList(); - checkEndpointListForOnlyIsolatedHosts(); - openResponseConsoleFromEndpointList(); - performCommandInputChecks(command); - submitCommand(); - waitForCommandToBeExecuted(command); - waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyUnIsolatedHosts(); - }); - - it('should isolate a host from response console', () => { - const command = 'isolate'; - waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyUnIsolatedHosts(); - openResponseConsoleFromEndpointList(); - performCommandInputChecks(command); - submitCommand(); - waitForCommandToBeExecuted(command); - waitForEndpointListPageToBeLoaded(createdHost.hostname); - checkEndpointListForOnlyIsolatedHosts(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts new file mode 100644 index 000000000000..8de8ca22ae8b --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PolicyData } from '../../../../../../common/endpoint/types'; +import type { CreateAndEnrollEndpointHostResponse } from '../../../../../../scripts/endpoint/common/endpoint_host_services'; +import { + openResponseConsoleFromEndpointList, + performCommandInputChecks, + submitCommand, + waitForCommandToBeExecuted, + waitForEndpointListPageToBeLoaded, +} from '../../../tasks/response_console'; +import type { IndexedFleetEndpointPolicyResponse } from '../../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; +import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../../tasks/fleet'; +import { + checkEndpointListForOnlyIsolatedHosts, + checkEndpointListForOnlyUnIsolatedHosts, + isolateHostActionViaAPI, +} from '../../../tasks/isolate'; + +import { login } from '../../../tasks/login'; +import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; +import { createEndpointHost } from '../../../tasks/create_endpoint_host'; +import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; + +describe('Response console', { tags: ['@ess', '@serverless'] }, () => { + let indexedPolicy: IndexedFleetEndpointPolicyResponse; + let policy: PolicyData; + let createdHost: CreateAndEnrollEndpointHostResponse; + + before(() => { + getEndpointIntegrationVersion().then((version) => + createAgentPolicyTask(version).then((data) => { + indexedPolicy = data; + policy = indexedPolicy.integrationPolicies[0]; + + return enableAllPolicyProtections(policy.id).then(() => { + // Create and enroll a new Endpoint host + return createEndpointHost(policy.policy_id).then((host) => { + createdHost = host as CreateAndEnrollEndpointHostResponse; + }); + }); + }) + ); + }); + + after(() => { + if (createdHost) { + cy.task('destroyEndpointHost', createdHost); + } + + if (indexedPolicy) { + cy.task('deleteIndexedFleetEndpointPolicies', indexedPolicy); + } + + if (createdHost) { + deleteAllLoadedEndpointData({ endpointAgentIds: [createdHost.agentId] }); + } + }); + + describe('Host Isolation:', () => { + beforeEach(() => { + login(); + }); + + it('should release an isolated host via response console', () => { + const command = 'release'; + waitForEndpointListPageToBeLoaded(createdHost.hostname); + // isolate the host first + isolateHostActionViaAPI(createdHost.agentId); + // verify and find the isolated host + checkEndpointListForOnlyIsolatedHosts(); + openResponseConsoleFromEndpointList(); + performCommandInputChecks(command); + submitCommand(); + waitForCommandToBeExecuted(command); + waitForEndpointListPageToBeLoaded(createdHost.hostname); + checkEndpointListForOnlyUnIsolatedHosts(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts index 9cd298535df2..a28d710091eb 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/endpoint_list_with_security_essentials.cy.ts @@ -15,7 +15,8 @@ import { visitEndpointList, } from '../../screens'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/171643 +describe.skip( 'When on the Endpoint List in Security Essentials PLI', { tags: ['@serverless'], diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts index 34aba3fcfccf..ed47855ac894 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts @@ -21,8 +21,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/170667 -describe.skip( +describe( 'Uninstall agent from host when agent tamper protection is disabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts index 8f45e3d70b5e..527566bed608 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts @@ -22,8 +22,7 @@ import { login } from '../../../tasks/login'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/170601 -describe.skip( +describe( 'Uninstall agent from host when agent tamper protection is enabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts index f5665d830eb4..0768c4a49ca3 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts @@ -23,8 +23,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -// FLAKY: https://github.com/elastic/kibana/issues/170604 -describe.skip( +describe( 'Uninstall agent from host changing agent policy when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/create_and_enroll_endpoint_host_ci.ts b/x-pack/plugins/security_solution/public/management/cypress/support/create_and_enroll_endpoint_host_ci.ts new file mode 100644 index 000000000000..df3a5cf6d38a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/support/create_and_enroll_endpoint_host_ci.ts @@ -0,0 +1,132 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kibanaPackageJson } from '@kbn/repo-info'; +import type { ToolingLog } from '@kbn/tooling-log'; +import type { KbnClient } from '@kbn/test/src/kbn_client'; +import { isFleetServerRunning } from '../../../../scripts/endpoint/common/fleet_server/fleet_server_services'; +import type { HostVm } from '../../../../scripts/endpoint/common/types'; +import type { BaseVmCreateOptions } from '../../../../scripts/endpoint/common/vm_services'; +import { createVm } from '../../../../scripts/endpoint/common/vm_services'; +import { + fetchAgentPolicyEnrollmentKey, + fetchFleetServerUrl, + getAgentDownloadUrl, + getAgentFileName, + getOrCreateDefaultAgentPolicy, + waitForHostToEnroll, +} from '../../../../scripts/endpoint/common/fleet_services'; +import type { DownloadedAgentInfo } from '../../../../scripts/endpoint/common/agent_downloads_service'; +import { + downloadAndStoreAgent, + isAgentDownloadFromDiskAvailable, +} from '../../../../scripts/endpoint/common/agent_downloads_service'; + +export interface CreateAndEnrollEndpointHostCIOptions + extends Pick { + kbnClient: KbnClient; + log: ToolingLog; + /** The fleet Agent Policy ID to use for enrolling the agent */ + agentPolicyId: string; + /** version of the Agent to install. Defaults to stack version */ + version?: string; + /** The name for the host. Will also be the name of the VM */ + hostname?: string; + /** If `version` should be exact, or if this is `true`, then the closest version will be used. Defaults to `false` */ + useClosestVersionMatch?: boolean; +} + +export interface CreateAndEnrollEndpointHostCIResponse { + hostname: string; + agentId: string; + hostVm: HostVm; +} + +/** + * Creates a new virtual machine (host) and enrolls that with Fleet + */ +export const createAndEnrollEndpointHostCI = async ({ + kbnClient, + log, + agentPolicyId, + cpus, + disk, + memory, + hostname, + version = kibanaPackageJson.version, + useClosestVersionMatch = true, +}: CreateAndEnrollEndpointHostCIOptions): Promise => { + const vmName = hostname ?? `test-host-${Math.random().toString().substring(2, 6)}`; + + const fileNameNoExtension = getAgentFileName(version); + const agentFileName = `${fileNameNoExtension}.tar.gz`; + let agentDownload: DownloadedAgentInfo | undefined; + + // Check if agent file is already on disk before downloading it again + agentDownload = isAgentDownloadFromDiskAvailable(agentFileName); + + // If it has not been already downloaded, it should be downloaded. + if (!agentDownload) { + log.warning( + `There is no agent installer for ${agentFileName} present on disk, trying to download it now.` + ); + const { url: agentUrl } = await getAgentDownloadUrl(version, useClosestVersionMatch, log); + agentDownload = await downloadAndStoreAgent(agentUrl, agentFileName); + } + + const hostVm = await createVm({ + type: 'vagrant', + name: vmName, + log, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + agentDownload: agentDownload!, + disk, + cpus, + memory, + }); + + if (!(await isFleetServerRunning(kbnClient))) { + throw new Error(`Fleet server does not seem to be running on this instance of kibana!`); + } + + const policyId = agentPolicyId || (await getOrCreateDefaultAgentPolicy({ kbnClient, log })).id; + const [fleetServerUrl, enrollmentToken] = await Promise.all([ + fetchFleetServerUrl(kbnClient), + fetchAgentPolicyEnrollmentKey(kbnClient, policyId), + ]); + + const agentEnrollCommand = [ + 'sudo', + + `./${fileNameNoExtension}/elastic-agent`, + + 'install', + + '--insecure', + + '--force', + + '--url', + fleetServerUrl, + + '--enrollment-token', + enrollmentToken, + ].join(' '); + + log.info(`Enrolling Elastic Agent with Fleet`); + log.verbose('Enrollment command:', agentEnrollCommand); + + await hostVm.exec(agentEnrollCommand); + + const { id: agentId } = await waitForHostToEnroll(kbnClient, log, hostVm.name, 240000); + + return { + hostname: hostVm.name, + agentId, + hostVm, + }; +}; diff --git a/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts b/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts index 99ea877053c9..299d210a6508 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/support/data_loaders.ts @@ -26,10 +26,7 @@ import { import type { DeleteAllEndpointDataResponse } from '../../../../scripts/endpoint/common/delete_all_endpoint_data'; import { deleteAllEndpointData } from '../../../../scripts/endpoint/common/delete_all_endpoint_data'; import { waitForEndpointToStreamData } from '../../../../scripts/endpoint/common/endpoint_metadata_services'; -import type { - CreateAndEnrollEndpointHostOptions, - CreateAndEnrollEndpointHostResponse, -} from '../../../../scripts/endpoint/common/endpoint_host_services'; +import type { CreateAndEnrollEndpointHostResponse } from '../../../../scripts/endpoint/common/endpoint_host_services'; import { createAndEnrollEndpointHost, destroyEndpointHost, @@ -66,6 +63,11 @@ import { indexFleetEndpointPolicy, } from '../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; import { cyLoadEndpointDataHandler } from './plugin_handlers/endpoint_data_loader'; +import type { + CreateAndEnrollEndpointHostCIOptions, + CreateAndEnrollEndpointHostCIResponse, +} from './create_and_enroll_endpoint_host_ci'; +import { createAndEnrollEndpointHostCI } from './create_and_enroll_endpoint_host_ci'; /** * Test Role/User loader for cypress. Checks to see if running in serverless and handles it as appropriate @@ -290,40 +292,48 @@ export const dataLoadersForRealEndpoints = ( on('task', { createEndpointHost: async ( - options: Omit - ): Promise => { + options: Omit + ): Promise => { const { kbnClient, log } = await stackServicesPromise; let retryAttempt = 0; - const attemptCreateEndpointHost = async (): Promise => { - try { - log.info(`Creating endpoint host, attempt ${retryAttempt}`); - const newHost = await createAndEnrollEndpointHost({ - useClosestVersionMatch: true, - ...options, - log, - kbnClient, - }); - await waitForEndpointToStreamData(kbnClient, newHost.agentId, 360000); - return newHost; - } catch (err) { - log.info(`Caught error when setting up the agent: ${err}`); - if (retryAttempt === 0 && err.agentId) { - retryAttempt++; - await destroyEndpointHost(kbnClient, { - hostname: err.hostname || '', // No hostname in CI env for vagrant - agentId: err.agentId, - }); - log.info(`Deleted endpoint host ${err.agentId} and retrying`); - return attemptCreateEndpointHost(); - } else { - log.info( - `${retryAttempt} attempts of creating endpoint host failed, reason for the last failure was ${err}` - ); - throw err; + const attemptCreateEndpointHost = + async (): Promise => { + try { + log.info(`Creating endpoint host, attempt ${retryAttempt}`); + const newHost = process.env.CI + ? await createAndEnrollEndpointHostCI({ + useClosestVersionMatch: true, + ...options, + log, + kbnClient, + }) + : await createAndEnrollEndpointHost({ + useClosestVersionMatch: true, + ...options, + log, + kbnClient, + }); + await waitForEndpointToStreamData(kbnClient, newHost.agentId, 360000); + return newHost; + } catch (err) { + log.info(`Caught error when setting up the agent: ${err}`); + if (retryAttempt === 0 && err.agentId) { + retryAttempt++; + await destroyEndpointHost(kbnClient, { + hostname: err.hostname || '', // No hostname in CI env for vagrant + agentId: err.agentId, + }); + log.info(`Deleted endpoint host ${err.agentId} and retrying`); + return attemptCreateEndpointHost(); + } else { + log.info( + `${retryAttempt} attempts of creating endpoint host failed, reason for the last failure was ${err}` + ); + throw err; + } } - } - }; + }; return attemptCreateEndpointHost(); }, diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts index 10aec51af291..20d57ba7a94b 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/isolate.ts @@ -7,9 +7,11 @@ /* eslint-disable cypress/no-unnecessary-waiting */ +import { API_VERSIONS } from '@kbn/fleet-plugin/common'; import { openAlertDetailsView } from '../screens/alerts'; import type { ActionDetails } from '../../../../common/endpoint/types'; import { loadPage } from './common'; +import { waitForActionToSucceed } from './response_actions'; const API_ENDPOINT_ACTION_PATH = '/api/endpoint/action/*'; export const interceptActionRequests = ( @@ -41,29 +43,6 @@ export const isolateHostWithComment = (comment: string, hostname: string): void cy.getByTestSubj('host_isolation_comment').type(comment); }; -export const isolateHostFromEndpointList = (index: number = 0): void => { - // open the action menu and click isolate action - cy.getByTestSubj('endpointTableRowActions').eq(index).click(); - cy.getByTestSubj('isolateLink').click(); - // isolation form, click confirm button - cy.getByTestSubj('hostIsolateConfirmButton').click(); - // return to endpoint details - cy.getByTestSubj('hostIsolateSuccessCompleteButton').click(); - // close details flyout - cy.getByTestSubj('euiFlyoutCloseButton').click(); - - // ensure the host is isolated, wait for 3 minutes for the host to be isolated - cy.wait(18000); - - cy.getByTestSubj('endpointListTable').within(() => { - cy.get('tbody tr') - .eq(index) - .within(() => { - cy.get('td').eq(1).should('contain.text', 'Isolated'); - }); - }); -}; - export const releaseHostWithComment = (comment: string, hostname: string): void => { cy.contains(`${hostname} is currently isolated.`); cy.getByTestSubj('endpointHostIsolationForm'); @@ -139,28 +118,46 @@ export const filterOutIsolatedHosts = (): void => { cy.getByTestSubj('querySubmitButton').click(); }; -const checkEndpointListForIsolatedHosts = (expectIsolated: boolean): void => { - const chainer = expectIsolated ? 'contain.text' : 'not.contain.text'; +const checkEndpointListForIsolationStatus = (expectIsolated: boolean): void => { + const chainer = expectIsolated ? 'contain' : 'not.contain'; cy.getByTestSubj('endpointListTable').within(() => { - cy.get('tbody tr').each(($tr) => { - cy.wrap($tr).within(() => { + cy.get('tbody tr') + .eq(0) + .within(() => { cy.get('td').eq(1).should(chainer, 'Isolated'); }); - }); }); }; export const checkEndpointListForOnlyUnIsolatedHosts = (): void => - checkEndpointListForIsolatedHosts(false); + checkEndpointListForIsolationStatus(false); export const checkEndpointListForOnlyIsolatedHosts = (): void => - checkEndpointListForIsolatedHosts(true); + checkEndpointListForIsolationStatus(true); + +export const isolateHostActionViaAPI = (agentId: string): void => { + cy.request({ + headers: { + 'kbn-xsrf': 'cypress-creds', + 'elastic-api-version': API_VERSIONS.public.v1, + }, + method: 'POST', + url: 'api/endpoint/action/isolate', + body: { + endpoint_ids: [agentId], + }, + }) + // verify action was successful + .then((response) => waitForActionToSucceed(response.body.data.id)) + .then((actionResponse) => { + expect(actionResponse.status).to.equal('successful'); + }); +}; export const checkEndpointIsolationStatus = ( endpointHostname: string, expectIsolated: boolean ): void => { - const chainer = expectIsolated ? 'contain.text' : 'not.contain.text'; - + const chainer = expectIsolated ? 'contain' : 'not.contain'; cy.contains(endpointHostname).parents('td').siblings('td').eq(0).should(chainer, 'Isolated'); }; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index 387f86c0dd16..126d637f07ed 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -139,6 +139,38 @@ export const waitForActionToComplete = ( }); }; +export const waitForActionToSucceed = ( + actionId: string, + timeout = 180000 +): Cypress.Chainable => { + let action: ActionDetails | undefined; + + return cy + .waitUntil( + () => { + return request({ + method: 'GET', + url: resolvePathVariables(ACTION_DETAILS_ROUTE, { action_id: actionId || 'undefined' }), + }).then((response) => { + if (response.body.data.isCompleted && response.body.data.status === 'successful') { + action = response.body.data; + return true; + } + + return false; + }); + }, + { timeout, interval: 2000 } + ) + .then(() => { + if (!action) { + throw new Error('Failed to retrieve successful action'); + } + + return action; + }); +}; + /** * Ensure user has the given `accessLevel` to the type of response action * @param accessLevel diff --git a/x-pack/plugins/security_solution/public/mocks.ts b/x-pack/plugins/security_solution/public/mocks.ts index 044e58192f2d..6564697c95f0 100644 --- a/x-pack/plugins/security_solution/public/mocks.ts +++ b/x-pack/plugins/security_solution/public/mocks.ts @@ -16,7 +16,7 @@ const upselling = new UpsellingService(); export const contractStartServicesMock: ContractStartServices = { extraRoutes$: of([]), - getComponent$: jest.fn(), + getComponents$: jest.fn(() => of({})), upselling, }; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/risk_score_donut_chart.tsx b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/risk_score_donut_chart.tsx index 2ee81c42949b..2bb850e0c312 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/risk_score_donut_chart.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/risk_score_donut_chart.tsx @@ -8,11 +8,11 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import { RISK_SEVERITY_COLOUR } from '../../../../entity_analytics/common/utils'; import type { SeverityCount } from '../../../../explore/components/risk_score/severity/types'; import { useRiskDonutChartData } from './use_risk_donut_chart_data'; import type { FillColor } from '../../../../common/components/charts/donutchart'; import { emptyDonutColor } from '../../../../common/components/charts/donutchart_empty'; -import { RISK_SEVERITY_COLOUR } from '../../../../explore/components/risk_score/severity/common'; import { DonutChart } from '../../../../common/components/charts/donutchart'; import { Legend } from '../../../../common/components/charts/legend'; import { ChartLabel } from '../../detection_response/alerts_by_status/chart_label'; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/use_risk_donut_chart_data.ts b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/use_risk_donut_chart_data.ts index 6ba4ad7c03d1..4b31142aef3c 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/use_risk_donut_chart_data.ts +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/common/use_risk_donut_chart_data.ts @@ -6,10 +6,10 @@ */ import { sum } from 'lodash/fp'; import { useMemo } from 'react'; +import { RISK_SEVERITY_COLOUR } from '../../../../entity_analytics/common/utils'; import type { LegendItem } from '../../../../common/components/charts/legend_item'; import type { SeverityCount } from '../../../../explore/components/risk_score/severity/types'; import type { DonutChartProps } from '../../../../common/components/charts/donutchart'; -import { RISK_SEVERITY_COLOUR } from '../../../../explore/components/risk_score/severity/common'; import type { RiskSeverity } from '../../../../../common/search_strategy'; const legendField = 'kibana.alert.severity'; diff --git a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/translations.ts b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/translations.ts index f2e3296133ff..22fe8a3d5282 100644 --- a/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/translations.ts +++ b/x-pack/plugins/security_solution/public/overview/components/entity_analytics/risk_score/translations.ts @@ -25,7 +25,7 @@ export const VIEW_ALL = i18n.translate( } ); -export const LEARN_MORE = (riskEntity: RiskScoreEntity) => +export const LEARN_MORE = (riskEntity?: RiskScoreEntity) => i18n.translate('xpack.securitySolution.entityAnalytics.riskDashboard.learnMore', { defaultMessage: 'Learn more about {riskEntity} risk', values: { diff --git a/x-pack/plugins/security_solution/public/overview/components/recent_cases/index.tsx b/x-pack/plugins/security_solution/public/overview/components/recent_cases/index.tsx index 5e75ed3643a7..134fac9ac729 100644 --- a/x-pack/plugins/security_solution/public/overview/components/recent_cases/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/recent_cases/index.tsx @@ -7,14 +7,14 @@ import React from 'react'; -import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana'; +import { useKibana } from '../../../common/lib/kibana'; import { APP_ID } from '../../../../common/constants'; const MAX_CASES_TO_SHOW = 3; const RecentCasesComponent = () => { const { cases } = useKibana().services; - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); return cases.ui.getRecentCases({ permissions: userCasesPermissions, diff --git a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.test.tsx b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.test.tsx index 692ffd0b44ec..8835fc0e48f2 100644 --- a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.test.tsx @@ -10,7 +10,7 @@ import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; import { TestProviders } from '../../../common/mock'; import { Sidebar } from './sidebar'; -import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana'; +import { useKibana } from '../../../common/lib/kibana'; import type { CaseUiClientMock } from '@kbn/cases-plugin/public/mocks'; import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; import { noCasesPermissions, readCasesPermissions } from '../../../cases_test_utils'; @@ -38,7 +38,7 @@ describe('Sidebar', () => { }); it('does not render the recently created cases section when the user does not have read permissions', async () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(noCasesPermissions()); + casesMock.helpers.canUseCases.mockReturnValue(noCasesPermissions()); await waitFor(() => mount( @@ -52,7 +52,7 @@ describe('Sidebar', () => { }); it('does render the recently created cases section when the user has read permissions', async () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions()); + casesMock.helpers.canUseCases.mockReturnValue(readCasesPermissions()); await waitFor(() => mount( diff --git a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx index 4f87ec1d8660..501e03a65cb0 100644 --- a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx @@ -8,7 +8,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { ENABLE_NEWS_FEED_SETTING, NEWS_FEED_URL_SETTING } from '../../../../common/constants'; +import { useKibana } from '../../../common/lib/kibana/kibana_react'; +import { + APP_ID, + ENABLE_NEWS_FEED_SETTING, + NEWS_FEED_URL_SETTING, +} from '../../../../common/constants'; import { Filters as RecentTimelinesFilters } from '../recent_timelines/filters'; import { StatefulRecentTimelines } from '../recent_timelines'; import { StatefulNewsFeed } from '../../../common/components/news_feed'; @@ -17,7 +22,6 @@ import { SidebarHeader } from '../../../common/components/sidebar_header'; import * as i18n from '../../pages/translations'; import { RecentCases } from '../recent_cases'; -import { useGetUserCasesPermissions } from '../../../common/lib/kibana'; const SidebarSpacerComponent = () => ( @@ -30,6 +34,7 @@ export const Sidebar = React.memo<{ recentTimelinesFilterBy: RecentTimelinesFilterMode; setRecentTimelinesFilterBy: (filterBy: RecentTimelinesFilterMode) => void; }>(({ recentTimelinesFilterBy, setRecentTimelinesFilterBy }) => { + const { cases } = useKibana().services; const recentTimelinesFilters = useMemo( () => ( diff --git a/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx index 5fbe5d80f99c..3e075d27ac76 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx @@ -30,14 +30,6 @@ jest.mock('../../common/lib/kibana', () => { return { ...original, KibanaServices: mockKibanaServices, - useGetUserCasesPermissions: () => ({ - all: false, - create: false, - read: true, - update: false, - delete: false, - push: false, - }), useKibana: jest.fn(), useUiSetting$: () => ['0,0.[000]'], }; @@ -80,6 +72,16 @@ describe('DataQuality', () => { hooks: { useCasesAddToNewCaseFlyout: jest.fn(), }, + helpers: { + canUseCases: jest.fn().mockReturnValue({ + all: false, + create: false, + read: true, + update: false, + delete: false, + push: false, + }), + }, }, configSettings: { ILMEnabled: true }, }, @@ -307,6 +309,16 @@ describe('DataQuality', () => { hooks: { useCasesAddToNewCaseFlyout: jest.fn(), }, + helpers: { + canUseCases: jest.fn().mockReturnValue({ + all: false, + create: false, + read: true, + update: false, + delete: false, + push: false, + }), + }, }, configSettings: { ILMEnabled: false }, }, diff --git a/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx b/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx index 0ef421977a40..0c318b38a466 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx @@ -38,15 +38,9 @@ import { HeaderPage } from '../../common/components/header_page'; import { LandingPageComponent } from '../../common/components/landing_page'; import { useLocalStorage } from '../../common/components/local_storage'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; -import { DEFAULT_BYTES_FORMAT, DEFAULT_NUMBER_FORMAT } from '../../../common/constants'; +import { APP_ID, DEFAULT_BYTES_FORMAT, DEFAULT_NUMBER_FORMAT } from '../../../common/constants'; import { useSourcererDataView } from '../../common/containers/sourcerer'; -import { - KibanaServices, - useGetUserCasesPermissions, - useKibana, - useToasts, - useUiSetting$, -} from '../../common/lib/kibana'; +import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../common/lib/kibana'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index'; import * as i18n from './translations'; @@ -141,9 +135,7 @@ const DataQualityComponent: React.FC = () => { const httpFetch = KibanaServices.get().http.fetch; const { baseTheme, theme } = useThemes(); const toasts = useToasts(); - const { - services: { telemetry }, - } = useKibana(); + const addSuccessToast = useCallback( (toast: { title: string }) => { toasts.addSuccess(toast); @@ -156,7 +148,7 @@ const DataQualityComponent: React.FC = () => { const [selectedOptions, setSelectedOptions] = useState(defaultOptions); const { indicesExist, loading: isSourcererLoading, selectedPatterns } = useSourcererDataView(); const { signalIndexName, loading: isSignalIndexNameLoading } = useSignalIndex(); - const { configSettings, cases } = useKibana().services; + const { configSettings, cases, telemetry } = useKibana().services; const isILMAvailable = configSettings.ILMEnabled; const [startDate, setStartTime] = useState(); @@ -210,7 +202,7 @@ const DataQualityComponent: React.FC = () => { key: LOCAL_STORAGE_KEY, }); - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const canUserCreateAndReadCases = useCallback( () => userCasesPermissions.create && userCasesPermissions.read, [userCasesPermissions.create, userCasesPermissions.read] diff --git a/x-pack/plugins/security_solution/public/overview/pages/detection_response.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/detection_response.test.tsx index 60ee2d02e6b2..2b5561f58cb5 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/detection_response.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/detection_response.test.tsx @@ -11,6 +11,7 @@ import { render } from '@testing-library/react'; import { DetectionResponse } from './detection_response'; import { TestProviders } from '../../common/mock'; import { noCasesPermissions, readCasesPermissions } from '../../cases_test_utils'; +import { useKibana as mockUseKibana } from '../../common/lib/kibana/__mocks__'; jest.mock('../components/detection_response/alerts_by_status', () => ({ AlertsByStatus: () =>
    , @@ -75,12 +76,24 @@ jest.mock('../../detections/containers/detection_engine/alerts/use_alerts_privil })); const defaultUseCasesPermissionsReturn = readCasesPermissions(); -const mockUseCasesPermissions = jest.fn(() => defaultUseCasesPermissionsReturn); -jest.mock('../../common/lib/kibana/hooks', () => { - const original = jest.requireActual('../../common/lib/kibana/hooks'); + +const mockedUseKibana = mockUseKibana(); +const mockCanUseCases = jest.fn(); + +jest.mock('../../common/lib/kibana', () => { + const original = jest.requireActual('../../common/lib/kibana'); + return { ...original, - useGetUserCasesPermissions: () => mockUseCasesPermissions(), + useKibana: () => ({ + ...mockedUseKibana, + services: { + ...mockedUseKibana.services, + cases: { + helpers: { canUseCases: mockCanUseCases }, + }, + }, + }), }; }); @@ -90,7 +103,7 @@ describe('DetectionResponse', () => { mockUseSourcererDataView.mockReturnValue(defaultUseSourcererReturn); mockUseAlertsPrivileges.mockReturnValue(defaultUseAlertsPrivilegesReturn); mockUseSignalIndex.mockReturnValue(defaultUseSignalIndexReturn); - mockUseCasesPermissions.mockReturnValue(defaultUseCasesPermissionsReturn); + mockCanUseCases.mockReturnValue(defaultUseCasesPermissionsReturn); }); it('should render default page', () => { @@ -197,7 +210,7 @@ describe('DetectionResponse', () => { }); it('should not render cases data sections if the user does not have cases read permission', () => { - mockUseCasesPermissions.mockReturnValue(noCasesPermissions()); + mockCanUseCases.mockReturnValue(noCasesPermissions()); const result = render( @@ -218,7 +231,7 @@ describe('DetectionResponse', () => { }); it('should render page permissions message if the user does not have read permission', () => { - mockUseCasesPermissions.mockReturnValue(noCasesPermissions()); + mockCanUseCases.mockReturnValue(noCasesPermissions()); mockUseAlertsPrivileges.mockReturnValue({ hasKibanaREAD: true, hasIndexRead: false, diff --git a/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx b/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx index 8bdc95fc69aa..77bbdbe8816e 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import type { DocLinks } from '@kbn/doc-links'; +import { APP_ID } from '../../../common'; import { InputsModelId } from '../../common/store/inputs/constants'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { SocTrends } from '../components/detection_response/soc_trends'; @@ -18,7 +19,6 @@ import { useSourcererDataView } from '../../common/containers/sourcerer'; import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index'; import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { HeaderPage } from '../../common/components/header_page'; -import { useGetUserCasesPermissions } from '../../common/lib/kibana'; import { LandingPageComponent } from '../../common/components/landing_page'; import { AlertsByStatus } from '../components/detection_response/alerts_by_status'; @@ -31,13 +31,16 @@ import { CasesByStatus } from '../components/detection_response/cases_by_status' import { NoPrivileges } from '../../common/components/no_privileges'; import { FiltersGlobal } from '../../common/components/filters_global'; import { useGlobalFilterQuery } from '../../common/hooks/use_global_filter_query'; +import { useKibana } from '../../common/lib/kibana'; const DetectionResponseComponent = () => { + const { cases } = useKibana().services; const { filterQuery } = useGlobalFilterQuery(); const { indicesExist, loading: isSourcererLoading, sourcererDataView } = useSourcererDataView(); const { signalIndexName } = useSignalIndex(); const { hasKibanaREAD, hasIndexRead } = useAlertsPrivileges(); - const canReadCases = useGetUserCasesPermissions().read; + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); + const canReadCases = userCasesPermissions.read; const canReadAlerts = hasKibanaREAD && hasIndexRead; const isSocTrendsEnabled = useIsExperimentalFeatureEnabled('socTrendsEnabled'); if (!canReadAlerts && !canReadCases) { diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index c07273e59ed4..e36dcd799172 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -235,11 +235,6 @@ export class Plugin implements IPlugin` @@ -386,52 +386,35 @@ const SchemaInformation = ({ <> - + {i18n.translate('xpack.securitySolution.resolver.graphControls.schemaSource', { defaultMessage: 'source', })} - + {sourceAndSchema?.dataSource ?? unknownSchemaValue} - - + + {i18n.translate('xpack.securitySolution.resolver.graphControls.schemaID', { defaultMessage: 'id', })} - + {sourceAndSchema?.schema.id ?? unknownSchemaValue} - - + + {i18n.translate('xpack.securitySolution.resolver.graphControls.schemaEdge', { defaultMessage: 'edge', })} - + {sourceAndSchema?.schema.parent ?? unknownSchemaValue} - +
    @@ -493,14 +476,12 @@ const NodeLegend = ({ <> - + - + {i18n.translate( 'xpack.securitySolution.resolver.graphControls.runningProcessCube', @@ -521,10 +499,7 @@ const NodeLegend = ({ )} - + - + {i18n.translate( 'xpack.securitySolution.resolver.graphControls.terminatedProcessCube', @@ -545,10 +517,7 @@ const NodeLegend = ({ )} - + - + {i18n.translate( 'xpack.securitySolution.resolver.graphControls.currentlyLoadingCube', @@ -569,10 +535,7 @@ const NodeLegend = ({ )} - + - + {i18n.translate('xpack.securitySolution.resolver.graphControls.errorCube', { defaultMessage: 'Error Process', diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/event_detail.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/event_detail.tsx index 64c94f76f86a..07ef565865d8 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/event_detail.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/event_detail.tsx @@ -11,18 +11,11 @@ import React, { memo, useMemo, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { EuiBreadcrumb } from '@elastic/eui'; -import { - EuiSpacer, - EuiText, - EuiDescriptionList, - EuiHorizontalRule, - EuiTextColor, - EuiTitle, -} from '@elastic/eui'; +import { EuiSpacer, EuiText, EuiHorizontalRule, EuiTextColor, EuiTitle } from '@elastic/eui'; import styled from 'styled-components'; import { useSelector } from 'react-redux'; import { StyledPanel } from '../styles'; -import { BoldCode, StyledTime } from './styles'; +import { StyledDescriptionList, BoldCode, StyledTime } from './styles'; import { GeneratedText } from '../generated_text'; import { CopyablePanelField } from './copyable_panel_field'; import { Breadcrumbs } from './breadcrumbs'; @@ -329,16 +322,6 @@ function EventDetailBreadcrumbs({ return ; } -const StyledDescriptionList = memo(styled(EuiDescriptionList)` - .euiDescriptionList__title { - word-break: normal; - } - .euiDescriptionList__title, - .euiDescriptionList__description { - overflow-wrap: break-word; - } -`); - // Also prevents horizontal scrollbars on long descriptive names const StyledDescriptiveName = memo(styled(EuiText)` padding-right: 1em; diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/node_detail.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/node_detail.tsx index ab762ec8a454..c258860e4f35 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/node_detail.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/node_detail.tsx @@ -35,6 +35,8 @@ const StyledCubeForProcess = styled(CubeForProcess)` position: relative; `; +const COLUMN_WIDTH = ['fit-content(10em)', 'auto']; + const nodeDetailError = i18n.translate('xpack.securitySolution.resolver.panel.nodeDetail.Error', { defaultMessage: 'Node details were unable to be retrieved', }); @@ -249,6 +251,7 @@ const NodeDetailView = memo(function ({
    - .c2 { - display: block; + .c3:active, +.c3:focus { + background: transparent; } -.c1 > span { +.c3 > span { padding: 0; } -.c3 { +.c4 { overflow: hidden; display: inline-block; text-overflow: ellipsis; + white-space: nowrap; } -.c0 { +.c5 { + white-space: nowrap; +} + +.c1 { + overflow-x: auto; +} + +.c2 { overflow: hidden; } +.c0 { + backgroundColor: #1d1e24; + color: #dfe5ef; + padding-inline: 12px; + border-radius: 0px; +} +
    - -
    -
    -
    -
    - + + +
    +
    +
    +
    + + Unsaved + +
    +
    +
    + +
    +

    diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.test.tsx new file mode 100644 index 000000000000..7203e74fe02c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.test.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { TestProviders, mockIndexNames, mockIndexPattern } from '../../../../common/mock'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; +import { allCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils'; +import { mockBrowserFields } from '../../../../common/containers/source/mock'; +import { TimelineActionMenu } from '.'; +import { TimelineId, TimelineTabs } from '../../../../../common/types'; +import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__'; + +const mockUseSourcererDataView: jest.Mock = useSourcererDataView as jest.Mock; +const mockedUseKibana = mockUseKibana(); +const mockCanUseCases = jest.fn(); + +jest.mock('../../../../common/containers/sourcerer'); + +jest.mock('../../../../common/lib/kibana/kibana_react', () => { + const original = jest.requireActual('../../../../common/lib/kibana/kibana_react'); + + return { + ...original, + useKibana: () => ({ + ...mockedUseKibana, + services: { + ...mockedUseKibana.services, + cases: { + ...mockedUseKibana.services.cases, + helpers: { canUseCases: mockCanUseCases }, + }, + }, + application: { + capabilities: { + navLinks: {}, + management: {}, + catalogue: {}, + actions: { show: true, crud: true }, + }, + }, + }), + }; +}); + +jest.mock('@kbn/i18n-react', () => { + const originalModule = jest.requireActual('@kbn/i18n-react'); + const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago'); + + return { + ...originalModule, + FormattedRelative, + }; +}); + +const sourcererDefaultValue = { + sourcererDefaultValue: mockBrowserFields, + indexPattern: mockIndexPattern, + loading: false, + selectedPatterns: mockIndexNames, +}; + +describe('Action menu', () => { + beforeEach(() => { + // Mocking these services is required for the header component to render. + mockUseSourcererDataView.mockImplementation(() => sourcererDefaultValue); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('AddToCaseButton', () => { + it('renders the button when the user has create and read permissions', () => { + mockCanUseCases.mockReturnValue(allCasesPermissions()); + + render( + + + + ); + + expect(screen.getByTestId('attach-timeline-case-button')).toBeInTheDocument(); + }); + + it('does not render the button when the user does not have create permissions', () => { + mockCanUseCases.mockReturnValue(readCasesPermissions()); + + render( + + + + ); + + expect(screen.queryByTestId('attach-timeline-case-button')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.tsx new file mode 100644 index 000000000000..04f7b2eb0a31 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/index.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { useKibana } from '../../../../common/lib/kibana/kibana_react'; +import { APP_ID } from '../../../../../common'; +import type { TimelineTabs } from '../../../../../common/types'; +import { InspectButton } from '../../../../common/components/inspect'; +import { InputsModelId } from '../../../../common/store/inputs/constants'; +import { AddToCaseButton } from '../add_to_case_button'; +import { NewTimelineAction } from './new_timeline'; +import { SaveTimelineButton } from './save_timeline_button'; +import { OpenTimelineAction } from './open_timeline'; + +interface TimelineActionMenuProps { + mode?: 'compact' | 'normal'; + timelineId: string; + isInspectButtonDisabled: boolean; + activeTab: TimelineTabs; +} + +const TimelineActionMenuComponent = ({ + mode = 'normal', + timelineId, + activeTab, + isInspectButtonDisabled, +}: TimelineActionMenuProps) => { + const { cases } = useKibana().services; + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); + + return ( + + + + + + + + {userCasesPermissions.create && userCasesPermissions.read ? ( + + + + ) : null} + + + + + + + + ); +}; + +export const TimelineActionMenu = React.memo(TimelineActionMenuComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/new_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/new_timeline.tsx new file mode 100644 index 000000000000..8fc65250c5b4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/new_timeline.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui'; +import React, { useMemo, useState, useCallback } from 'react'; +import { NewTimeline } from '../../timeline/properties/helpers'; +import { NewTemplateTimeline } from '../../timeline/properties/new_template_timeline'; +import * as i18n from './translations'; + +interface NewTimelineActionProps { + timelineId: string; +} + +const panelStyle = { + padding: 0, +}; + +export const NewTimelineAction = React.memo(({ timelineId }: NewTimelineActionProps) => { + const [isPopoverOpen, setPopover] = useState(false); + + const closePopover = useCallback(() => { + setPopover(false); + }, []); + + const togglePopover = useCallback(() => setPopover((prev) => !prev), []); + + const newTimelineActionbtn = useMemo(() => { + return ( + + {i18n.NEW_TIMELINE_BTN} + + ); + }, [togglePopover]); + + return ( + + + + + + + + + + + ); +}); + +NewTimelineAction.displayName = 'NewTimelineAction'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/open_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/open_timeline.tsx new file mode 100644 index 000000000000..f5a7a51dc75e --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/open_timeline.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButtonEmpty } from '@elastic/eui'; +import React, { useState, useCallback } from 'react'; +import { OpenTimelineModal } from '../../open_timeline/open_timeline_modal'; +import type { ActionTimelineToShow } from '../../open_timeline/types'; +import * as i18n from './translations'; + +const actionTimelineToHide: ActionTimelineToShow[] = ['createFrom']; + +export const OpenTimelineAction = React.memo(() => { + const [showTimelineModal, setShowTimelineModal] = useState(false); + const onCloseTimelineModal = useCallback(() => setShowTimelineModal(false), []); + const onOpenTimelineModal = useCallback(() => { + setShowTimelineModal(true); + }, []); + + return ( + <> + + {i18n.OPEN_TIMELINE_BTN} + + + {showTimelineModal ? ( + + ) : null} + + ); +}); + +OpenTimelineAction.displayName = 'OpenTimelineAction'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.test.tsx similarity index 83% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.test.tsx rename to x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.test.tsx index 7c0552659450..92bc0be3f54e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.test.tsx @@ -11,7 +11,7 @@ import type { SaveTimelineButtonProps } from './save_timeline_button'; import { SaveTimelineButton } from './save_timeline_button'; import { TestProviders } from '../../../../common/mock'; import { useUserPrivileges } from '../../../../common/components/user_privileges'; -import { getTimelineStatusByIdSelector } from '../../flyout/header/selectors'; +import { getTimelineStatusByIdSelector } from '../header/selectors'; import { TimelineStatus } from '../../../../../common/api/timeline'; const TEST_ID = { @@ -28,7 +28,7 @@ jest.mock('react-redux', () => { jest.mock('../../../../common/lib/kibana'); jest.mock('../../../../common/components/user_privileges'); -jest.mock('../../flyout/header/selectors', () => { +jest.mock('../header/selectors', () => { return { getTimelineStatusByIdSelector: jest.fn().mockReturnValue(() => ({ status: 'draft', @@ -64,7 +64,28 @@ describe('SaveTimelineButton', () => { expect(screen.getByRole('button')).toBeDisabled(); }); + it('should disable the save timeline button when the timeline is immutable', () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: true }, + }); + (getTimelineStatusByIdSelector as jest.Mock).mockReturnValue(() => ({ + status: TimelineStatus.immutable, + })); + render( + + + + ); + expect(screen.getByRole('button')).toBeDisabled(); + }); + describe('with draft timeline', () => { + beforeAll(() => { + (getTimelineStatusByIdSelector as jest.Mock).mockReturnValue(() => ({ + status: TimelineStatus.draft, + })); + }); + it('should not show the save modal if user does not have write access', async () => { (useUserPrivileges as jest.Mock).mockReturnValue({ kibanaSecuritySolutionsPrivileges: { crud: false }, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.tsx similarity index 86% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.tsx rename to x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.tsx index 7a025259a657..5f52f67185b5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_button.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_button.tsx @@ -8,27 +8,24 @@ import React, { useCallback, useMemo, useState } from 'react'; import { EuiButton, EuiToolTip, EuiTourStep, EuiCode, EuiText, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { getTimelineStatusByIdSelector } from '../../flyout/header/selectors'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { TimelineStatus } from '../../../../../common/api/timeline'; import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { useIsElementMounted } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/use_is_element_mounted'; import { useLocalStorage } from '../../../../common/components/local_storage'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { SaveTimelineModal } from './save_timeline_modal'; import * as timelineTranslations from './translations'; +import { getTimelineStatusByIdSelector } from '../header/selectors'; export interface SaveTimelineButtonProps { timelineId: string; } const SAVE_BUTTON_ELEMENT_ID = 'SAVE_BUTTON_ELEMENT_ID'; -const LOCAL_STORAGE_KEY = 'security.timelineFlyoutHeader.saveTimelineTourSeen'; +const LOCAL_STORAGE_KEY = 'security.timelineFlyoutHeader.saveTimelineTour'; export const SaveTimelineButton = React.memo(({ timelineId }) => { - const isTimelineSaveTourSaveTourDisabled = - useIsExperimentalFeatureEnabled('disableTimelineSaveTour'); const [showEditTimelineOverlay, setShowEditTimelineOverlay] = useState(false); const closeSaveTimeline = useCallback(() => { @@ -45,7 +42,7 @@ export const SaveTimelineButton = React.memo(({ timelin // TODO: User may have Crud privileges but they may not have access to timeline index. // Do we need to check that? const { - kibanaSecuritySolutionsPrivileges: { crud: canEditTimeline }, + kibanaSecuritySolutionsPrivileges: { crud: canEditTimelinePrivilege }, } = useUserPrivileges(); const getTimelineStatus = useMemo(() => getTimelineStatusByIdSelector(), []); const { @@ -56,27 +53,30 @@ export const SaveTimelineButton = React.memo(({ timelin } = useDeepEqualSelector((state) => getTimelineStatus(state, timelineId)); const isSaveButtonMounted = useIsElementMounted(SAVE_BUTTON_ELEMENT_ID); - const [hasSeenTimelineSaveTour, setHasSeenTimelineSaveTour] = useLocalStorage({ - defaultValue: false, + const [timelineTourStatus, setTimelineTourStatus] = useLocalStorage({ + defaultValue: { isTourActive: true }, key: LOCAL_STORAGE_KEY, + isInvalidDefault: (valueFromStorage) => { + return !valueFromStorage; + }, }); + + const canEditTimeline = canEditTimelinePrivilege && timelineStatus !== TimelineStatus.immutable; // Why are we checking for so many flags here? // The tour popup should only show when timeline is fully populated and all necessary // elements are visible on screen. If we would not check for all these flags, the tour // popup would show too early and in the wrong place in the DOM. // The last flag, checks if the tour has been dismissed before. const showTimelineSaveTour = - // The timeline save tour could be disabled on a plugin level - !isTimelineSaveTourSaveTourDisabled && canEditTimeline && isVisible && !isLoading && isSaveButtonMounted && - !hasSeenTimelineSaveTour; + timelineTourStatus?.isTourActive; const markTimelineSaveTourAsSeen = useCallback(() => { - setHasSeenTimelineSaveTour(true); - }, [setHasSeenTimelineSaveTour]); + setTimelineTourStatus({ isTourActive: false }); + }, [setTimelineTourStatus]); const isUnsaved = timelineStatus === TimelineStatus.draft; const tooltipContent = canEditTimeline ? null : timelineTranslations.CALL_OUT_UNAUTHORIZED_MSG; @@ -92,10 +92,11 @@ export const SaveTimelineButton = React.memo(({ timelin fill color="primary" onClick={openEditTimeline} + size="s" iconType="save" isLoading={isSaving} disabled={!canEditTimeline} - data-test-subj="save-timeline-btn" + data-test-subj="save-timeline-action-btn" id={SAVE_BUTTON_ELEMENT_ID} > {timelineTranslations.SAVE} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.test.tsx similarity index 93% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.test.tsx rename to x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.test.tsx index 8ee6bf807913..43cdb85da8c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.test.tsx @@ -18,7 +18,7 @@ jest.mock('../../../../common/hooks/use_selector', () => ({ useDeepEqualSelector: jest.fn(), })); -jest.mock('../properties/use_create_timeline', () => ({ +jest.mock('../../timeline/properties/use_create_timeline', () => ({ useCreateTimeline: jest.fn(), })); @@ -114,6 +114,13 @@ describe('EditTimelineModal', () => { }); expect(component.find('[data-test-subj="save-button"]').exists()).toEqual(true); }); + + test('Does not show save as new switch', () => { + const component = mount(, { + wrappingComponent: TestProviders, + }); + expect(component.find('[data-test-subj="save-as-new-switch"]').exists()).toEqual(false); + }); }); describe('update timeline', () => { @@ -192,6 +199,13 @@ describe('EditTimelineModal', () => { }); expect(component.find('[data-test-subj="save-button"]').exists()).toEqual(true); }); + + test('Show save as new switch', () => { + const component = mount(, { + wrappingComponent: TestProviders, + }); + expect(component.find('[data-test-subj="save-as-new-switch"]').exists()).toEqual(true); + }); }); describe('showWarning', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx similarity index 77% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.tsx rename to x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx index f38cb4784ec1..10154901f2db 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/save_timeline_modal.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx @@ -16,8 +16,10 @@ import { EuiSpacer, EuiProgress, EuiCallOut, + EuiSwitch, } from '@elastic/eui'; -import React, { useCallback, useEffect, useMemo } from 'react'; +import type { EuiSwitchEvent } from '@elastic/eui'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import usePrevious from 'react-use/lib/usePrevious'; @@ -26,13 +28,13 @@ import { TimelineId } from '../../../../../common/types/timeline'; import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; -import { NOTES_PANEL_WIDTH } from '../properties/notes_size'; -import { useCreateTimeline } from '../properties/use_create_timeline'; -import * as commonI18n from '../properties/translations'; +import * as commonI18n from '../../timeline/properties/translations'; import * as i18n from './translations'; -import { formSchema } from './schema'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { TIMELINE_ACTIONS } from '../../../../common/lib/apm/user_actions'; +import { useCreateTimeline } from '../../timeline/properties/use_create_timeline'; +import { NOTES_PANEL_WIDTH } from '../../timeline/properties/notes_size'; +import { formSchema } from './schema'; const CommonUseField = getUseField({ component: Field }); interface SaveTimelineModalProps { @@ -62,6 +64,7 @@ export const SaveTimelineModal = React.memo( getTimeline(state, timelineId) ) ); + const isUnsaved = status === TimelineStatus.draft; const prevIsSaving = usePrevious(isSaving); const dispatch = useDispatch(); // Resetting the timeline by replacing the active one with a new empty one @@ -69,6 +72,12 @@ export const SaveTimelineModal = React.memo( timelineId: TimelineId.active, timelineType: TimelineType.default, }); + const [saveAsNewTimeline, setSaveAsNewTimeline] = useState(false); + + const onSaveAsNewChanged = useCallback( + (e: EuiSwitchEvent) => setSaveAsNewTimeline(e.target.checked), + [] + ); const handleSubmit = useCallback( (titleAndDescription, isValid) => { @@ -79,12 +88,13 @@ export const SaveTimelineModal = React.memo( ...titleAndDescription, }) ); - dispatch(timelineActions.saveTimeline({ id: timelineId })); + + dispatch(timelineActions.saveTimeline({ id: timelineId, saveAsNew: saveAsNewTimeline })); } return Promise.resolve(); }, - [dispatch, timelineId] + [dispatch, timelineId, saveAsNewTimeline] ); const initialState = useMemo( @@ -232,30 +242,40 @@ export const SaveTimelineModal = React.memo( - - - - {closeModalText} - - - - - {saveButtonTitle} - - + + {!isUnsaved ? ( + + ) : null} + + + + {closeModalText} + + + + + {saveButtonTitle} + + + diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/schema.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/schema.ts similarity index 100% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/schema.ts rename to x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/schema.ts diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/translations.ts new file mode 100644 index 000000000000..09b022d82faf --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/translations.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { TimelineTypeLiteral } from '../../../../../common/api/timeline'; +import { TimelineType } from '../../../../../common/api/timeline'; + +export const NEW_TIMELINE_BTN = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.newTimelineBtn', + { + defaultMessage: 'New', + } +); + +export const NEW_TIMELINE = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.newTimeline', + { + defaultMessage: 'New Timeline', + } +); + +export const OPEN_TIMELINE_BTN = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.openTimelineBtn', + { + defaultMessage: 'Open', + } +); + +export const OPEN_TIMELINE_BTN_LABEL = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.openTimelineBtnLabel', + { + defaultMessage: 'Open Existing Timeline', + } +); + +export const SAVE_TIMELINE_BTN = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.saveTimelineBtn', + { + defaultMessage: 'Save', + } +); + +export const SAVE_TIMELINE_BTN_LABEL = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.saveTimelineBtnLabel', + { + defaultMessage: 'Save currently opened Timeline', + } +); + +export const NEW_TEMPLATE_TIMELINE = i18n.translate( + 'xpack.securitySolution.flyout.timeline.actionMenu.newTimelineTemplate', + { + defaultMessage: 'New Timeline template', + } +); + +export const CALL_OUT_UNAUTHORIZED_MSG = i18n.translate( + 'xpack.securitySolution.timeline.callOut.unauthorized.message.description', + { + defaultMessage: + 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.', + } +); + +export const CALL_OUT_IMMUTABLE = i18n.translate( + 'xpack.securitySolution.timeline.callOut.immutable.message.description', + { + defaultMessage: + 'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.', + } +); + +export const SAVE_TIMELINE = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.header', + { + defaultMessage: 'Save Timeline', + } +); + +export const SAVE_TIMELINE_TEMPLATE = i18n.translate( + 'xpack.securitySolution.timeline.saveTimelineTemplate.modal.header', + { + defaultMessage: 'Save Timeline Template', + } +); + +export const SAVE = i18n.translate('xpack.securitySolution.timeline.nameTimeline.save.title', { + defaultMessage: 'Save', +}); + +export const NAME_TIMELINE_TEMPLATE = i18n.translate( + 'xpack.securitySolution.timeline.nameTimelineTemplate.modal.header', + { + defaultMessage: 'Name Timeline Template', + } +); + +export const DISCARD_TIMELINE = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.discard.title', + { + defaultMessage: 'Discard Timeline', + } +); + +export const DISCARD_TIMELINE_TEMPLATE = i18n.translate( + 'xpack.securitySolution.timeline.saveTimelineTemplate.modal.discard.title', + { + defaultMessage: 'Discard Timeline Template', + } +); + +export const CLOSE_MODAL = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.close.title', + { + defaultMessage: 'Close', + } +); + +export const UNSAVED_TIMELINE_WARNING = (timelineType: TimelineTypeLiteral) => + i18n.translate('xpack.securitySolution.timeline.saveTimeline.modal.warning.title', { + values: { + timeline: timelineType === TimelineType.template ? 'timeline template' : 'timeline', + }, + defaultMessage: 'You have an unsaved {timeline}. Do you wish to save it?', + }); + +export const TIMELINE_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.titleAriaLabel', + { + defaultMessage: 'Title', + } +); + +export const TIMELINE_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.descriptionLabel', + { + defaultMessage: 'Description', + } +); + +export const OPTIONAL = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.optionalLabel', + { + defaultMessage: 'Optional', + } +); + +export const SAVE_TOUR_CLOSE = i18n.translate( + 'xpack.securitySolution.timeline.flyout.saveTour.closeButton', + { + defaultMessage: 'Close', + } +); + +export const TITLE = i18n.translate('xpack.securitySolution.timeline.saveTimeline.modal.title', { + defaultMessage: 'Title', +}); + +export const SAVE_TOUR_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.flyout.saveTour.title', + { + defaultMessage: 'Timeline changes now require manual saves', + } +); + +export const SAVE_AS_NEW = i18n.translate( + 'xpack.securitySolution.timeline.saveTimeline.modal.saveAsNew', + { + defaultMessage: 'Save as new timeline', + } +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_timeline_button/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_timeline_button/index.tsx index 74662e756320..69b71adb9fb6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_timeline_button/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_timeline_button/index.tsx @@ -70,13 +70,13 @@ const AddTimelineButtonComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.test.tsx index 0e002561c022..063d6da3f2d0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.test.tsx @@ -10,7 +10,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; -import { useKibana, useGetUserCasesPermissions } from '../../../../common/lib/kibana'; +import { useKibana } from '../../../../common/lib/kibana'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { mockTimelineModel, TestProviders } from '../../../../common/mock'; import { AddToCaseButton } from '.'; @@ -36,13 +36,6 @@ jest.mock('react-redux', () => { }); jest.mock('../../../../common/lib/kibana'); -const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana'); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); - jest.mock('../../../../common/hooks/use_selector'); const useKibanaMock = useKibana as jest.Mocked; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx index c25d48ad03dd..81e520368da6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx @@ -6,7 +6,7 @@ */ import { pick } from 'lodash/fp'; -import { EuiButton, EuiContextMenuPanel, EuiContextMenuItem, EuiPopover } from '@elastic/eui'; +import { EuiContextMenuPanel, EuiContextMenuItem, EuiPopover, EuiButtonEmpty } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; @@ -15,7 +15,7 @@ import { APP_ID, APP_UI_ID } from '../../../../../common/constants'; import { timelineSelectors } from '../../../store/timeline'; import { setInsertTimeline, showTimeline } from '../../../store/timeline/actions'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; -import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana'; +import { useKibana } from '../../../../common/lib/kibana'; import { TimelineId } from '../../../../../common/types/timeline'; import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; import { getCreateCaseUrl, getCaseDetailsUrl } from '../../../../common/components/link_to'; @@ -68,7 +68,7 @@ const AddToCaseButtonComponent: React.FC = ({ timelineId }) => { [dispatch, graphEventId, navigateToApp, savedObjectId, timelineId, timelineTitle] ); - const userCasesPermissions = useGetUserCasesPermissions(); + const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const handleButtonClick = useCallback(() => { setPopover((currentIsOpen) => !currentIsOpen); @@ -118,8 +118,7 @@ const AddToCaseButtonComponent: React.FC = ({ timelineId }) => { const button = useMemo( () => ( - = ({ timelineId }) => { disabled={timelineStatus === TimelineStatus.draft || timelineType !== TimelineType.default} > {i18n.ATTACH_TO_CASE} - + ), [handleButtonClick, timelineStatus, timelineType] ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx index 0b5286f1fedb..bc1617d3b9a5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx @@ -10,6 +10,7 @@ import { FlyoutHeaderPanel } from '../header'; interface FlyoutBottomBarProps { showTimelineHeaderPanel: boolean; + timelineId: string; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.test.tsx new file mode 100644 index 000000000000..18bf93d0ab6c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.test.tsx @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + kibanaObservable, + mockGlobalState, + SUB_PLUGINS_REDUCER, + TestProviders, +} from '../../../../common/mock'; +import React from 'react'; +import type { ActiveTimelinesProps } from './active_timelines'; +import { ActiveTimelines } from './active_timelines'; +import { TimelineId } from '../../../../../common/types'; +import { TimelineType } from '../../../../../common/api/timeline'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { createSecuritySolutionStorageMock } from '@kbn/timelines-plugin/public/mock/mock_local_storage'; +import { createStore } from '../../../../common/store'; + +const { storage } = createSecuritySolutionStorageMock(); + +const store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, kibanaObservable, storage); + +const TestComponent = (props: ActiveTimelinesProps) => { + return ( + + + + ); +}; + +describe('ActiveTimelines', () => { + describe('default timeline', () => { + it('should render timeline title as button when minimized', () => { + render( + + ); + + expect(screen.getByLabelText(/Open timeline timeline-test/).nodeName.toLowerCase()).toBe( + 'button' + ); + }); + + it('should render timeline title as text when maximized', () => { + render( + + ); + expect(screen.queryByLabelText(/Open timeline timeline-test/)).toBeFalsy(); + }); + + it('should maximized timeline when clicked on minimized timeline', async () => { + render( + + ); + + fireEvent.click(screen.getByLabelText(/Open timeline timeline-test/)); + + await waitFor(() => { + expect(store.getState().timeline.timelineById.test.show).toBe(true); + }); + }); + }); + + describe('template timeline', () => { + it('should render timeline template title as button when minimized', () => { + render( + + ); + + expect(screen.getByTestId(/timeline-title/)).toHaveTextContent(/Untitled template/); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx index e6df4e56386a..cbc38f4ccecb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, EuiHealth, EuiToolTip } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, EuiText } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { isEmpty } from 'lodash/fp'; import styled from 'styled-components'; -import { FormattedRelative } from '@kbn/i18n-react'; -import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; +import { TimelineType } from '../../../../../common/api/timeline'; import { TimelineEventsCountBadge } from '../../../../common/hooks/use_timeline_events_count'; import { ACTIVE_TIMELINE_BUTTON_CLASS_NAME, @@ -22,20 +21,18 @@ import { UNTITLED_TIMELINE, UNTITLED_TEMPLATE } from '../../timeline/properties/ import { timelineActions } from '../../../store/timeline'; import * as i18n from './translations'; -const EuiHealthStyled = styled(EuiHealth)` - display: block; -`; - -interface ActiveTimelinesProps { +export interface ActiveTimelinesProps { timelineId: string; - timelineStatus: TimelineStatus; timelineTitle: string; timelineType: TimelineType; isOpen: boolean; - updated?: number; } const StyledEuiButtonEmpty = styled(EuiButtonEmpty)` + &:active, + &:focus { + background: transparent; + } > span { padding: 0; } @@ -45,17 +42,17 @@ const TitleConatiner = styled(EuiFlexItem)` overflow: hidden; display: inline-block; text-overflow: ellipsis; + white-space: nowrap; `; const ActiveTimelinesComponent: React.FC = ({ timelineId, - timelineStatus, timelineType, timelineTitle, - updated, isOpen, }) => { const dispatch = useDispatch(); + const handleToggleOpen = useCallback(() => { dispatch(timelineActions.showTimeline({ id: timelineId, show: !isOpen })); focusActiveTimelineButton(); @@ -67,53 +64,47 @@ const ActiveTimelinesComponent: React.FC = ({ ? UNTITLED_TEMPLATE : UNTITLED_TIMELINE; - const tooltipContent = useMemo(() => { - if (timelineStatus === TimelineStatus.draft) { - return <>{i18n.UNSAVED}; - } + const titleContent = useMemo(() => { return ( - <> - {i18n.SAVED}{' '} - - - ); - }, [timelineStatus, updated]); - - return ( - - - - - - - {title} + + {isOpen ? ( + +

    {title}

    +
    + ) : ( + <>{title} + )} +
    {!isOpen && ( )}
    + ); + }, [isOpen, title]); + + if (isOpen) { + return <>{titleContent}; + } + + return ( + + {titleContent} ); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx deleted file mode 100644 index 79ef41a07057..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.test.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { render, screen } from '@testing-library/react'; - -import { useKibana, useGetUserCasesPermissions } from '../../../../common/lib/kibana'; -import { TestProviders, mockIndexNames, mockIndexPattern } from '../../../../common/mock'; -import { TimelineId } from '../../../../../common/types/timeline'; -import { useTimelineKpis } from '../../../containers/kpis'; -import { FlyoutHeader } from '.'; -import { useSourcererDataView } from '../../../../common/containers/sourcerer'; -import { mockBrowserFields } from '../../../../common/containers/source/mock'; -import { getEmptyValue } from '../../../../common/components/empty_value'; -import { allCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils'; - -const mockUseSourcererDataView: jest.Mock = useSourcererDataView as jest.Mock; -jest.mock('../../../../common/containers/sourcerer'); - -const mockUseTimelineKpis: jest.Mock = useTimelineKpis as jest.Mock; -jest.mock('../../../containers/kpis', () => ({ - useTimelineKpis: jest.fn(), -})); -const useKibanaMock = useKibana as jest.Mocked; -jest.mock('../../../../common/lib/kibana'); -jest.mock('@kbn/i18n-react', () => { - const originalModule = jest.requireActual('@kbn/i18n-react'); - const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago'); - - return { - ...originalModule, - FormattedRelative, - }; -}); -const mockUseTimelineKpiResponse = { - processCount: 1, - userCount: 1, - sourceIpCount: 1, - hostCount: 1, - destinationIpCount: 1, -}; - -const mockUseTimelineLargeKpiResponse = { - processCount: 1000, - userCount: 1000000, - sourceIpCount: 1000000000, - hostCount: 999, - destinationIpCount: 1, -}; -const defaultMocks = { - browserFields: mockBrowserFields, - indexPattern: mockIndexPattern, - loading: false, - selectedPatterns: mockIndexNames, -}; -describe('header', () => { - beforeEach(() => { - // Mocking these services is required for the header component to render. - mockUseSourcererDataView.mockImplementation(() => defaultMocks); - useKibanaMock().services.application.capabilities = { - navLinks: {}, - management: {}, - catalogue: {}, - actions: { show: true, crud: true }, - }; - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('AddToCaseButton', () => { - beforeEach(() => { - mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineKpiResponse]); - }); - - it('renders the button when the user has create and read permissions', () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions()); - - render( - - - - ); - - expect(screen.getByTestId('attach-timeline-case-button')).toBeInTheDocument(); - }); - - it('does not render the button when the user does not have create permissions', () => { - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(readCasesPermissions()); - - render( - - - - ); - - expect(screen.queryByTestId('attach-timeline-case-button')).not.toBeInTheDocument(); - }); - }); - - describe('Timeline KPIs', () => { - describe('when the data is not loading and the response contains data', () => { - beforeEach(() => { - mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineKpiResponse]); - }); - it('renders the component, labels and values successfully', () => { - render( - - - - ); - expect(screen.getByTestId('siem-timeline-kpis')).toBeInTheDocument(); - // label - expect(screen.getByText('Processes')).toBeInTheDocument(); - // value - expect(screen.getByTestId('siem-timeline-process-kpi').textContent).toContain('1'); - }); - }); - - describe('when the data is loading', () => { - beforeEach(() => { - mockUseTimelineKpis.mockReturnValue([true, mockUseTimelineKpiResponse]); - }); - it('renders a loading indicator for values', async () => { - render( - - - - ); - expect(screen.getAllByText('--')).not.toHaveLength(0); - }); - }); - - describe('when the response is null and timeline is blank', () => { - beforeEach(() => { - mockUseTimelineKpis.mockReturnValue([false, null]); - }); - it('renders labels and the default empty string', () => { - render( - - - - ); - expect(screen.getByText('Processes')).toBeInTheDocument(); - expect(screen.getAllByText(getEmptyValue())).not.toHaveLength(0); - }); - }); - - describe('when the response contains numbers larger than one thousand', () => { - beforeEach(() => { - mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineLargeKpiResponse]); - }); - it('formats the numbers correctly', () => { - render( - - - - ); - expect(screen.getByText('1k', { selector: '.euiTitle' })).toBeInTheDocument(); - expect(screen.getByText('1m', { selector: '.euiTitle' })).toBeInTheDocument(); - expect(screen.getByText('1b', { selector: '.euiTitle' })).toBeInTheDocument(); - expect(screen.getByText('999', { selector: '.euiTitle' })).toBeInTheDocument(); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index 985d373950cc..14158e884e1b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -5,70 +5,49 @@ * 2.0. */ -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiToolTip, - EuiButtonIcon, - EuiText, - EuiButtonEmpty, - useEuiTheme, - EuiTextColor, -} from '@elastic/eui'; -import { FormattedRelative } from '@kbn/i18n-react'; -import type { MouseEventHandler } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiToolTip, EuiButtonIcon } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { isEmpty, get, pick } from 'lodash/fp'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; -import { InputsModelId } from '../../../../common/store/inputs/constants'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { createHistoryEntry } from '../../../../common/utils/global_query_string/helpers'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; -import { TimelineTabs, TimelineId } from '../../../../../common/types/timeline'; -import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; -import type { State } from '../../../../common/store'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; -import { timelineDefaults } from '../../../store/timeline/defaults'; -import { AddToFavoritesButton } from '../../timeline/properties/helpers'; -import type { TimerangeInput } from '../../../../../common/search_strategy'; -import { AddToCaseButton } from '../add_to_case_button'; -import { AddTimelineButton } from '../add_timeline_button'; -import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana'; -import { InspectButton } from '../../../../common/components/inspect'; -import { useTimelineKpis } from '../../../containers/kpis'; +import type { State } from '../../../../common/store'; +import { useKibana } from '../../../../common/lib/kibana'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; -import type { TimelineModel } from '../../../store/timeline/model'; -import { - startSelector, - endSelector, -} from '../../../../common/components/super_date_picker/selectors'; import { focusActiveTimelineButton } from '../../timeline/helpers'; import { combineQueries } from '../../../../common/lib/kuery'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { ActiveTimelines } from './active_timelines'; import * as i18n from './translations'; -import * as commonI18n from '../../timeline/properties/translations'; -import { TimelineKPIs } from './kpis'; - -import { setActiveTabTimeline } from '../../../store/timeline/actions'; -import { useIsOverflow } from '../../../../common/hooks/use_is_overflow'; -import { SaveTimelineButton } from '../../timeline/header/save_timeline_button'; -import { TimelineSavePrompt } from '../../timeline/header/timeline_save_prompt'; - -interface FlyoutHeaderProps { - timelineId: string; -} +import { TimelineActionMenu } from '../action_menu'; +import { AddToFavoritesButton } from '../../timeline/properties/helpers'; +import { TimelineStatusInfo } from './timeline_status_info'; +import { timelineDefaults } from '../../../store/timeline/defaults'; interface FlyoutHeaderPanelProps { timelineId: string; } +const FlyoutHeaderPanelContentFlexGroupContainer = styled(EuiFlexGroup)` + overflow-x: auto; +`; + const ActiveTimelinesContainer = styled(EuiFlexItem)` overflow: hidden; `; +const TimelinePanel = euiStyled(EuiPanel)<{ $isOpen?: boolean }>` + backgroundColor: ${(props) => props.theme.eui.euiColorEmptyShade}; + color: ${(props) => props.theme.eui.euiTextColor}; + padding-inline: ${(props) => props.theme.eui.euiSizeM}; + border-radius: ${({ $isOpen, theme }) => ($isOpen ? theme.eui.euiBorderRadius : '0px')}; +`; + const FlyoutHeaderPanelComponent: React.FC = ({ timelineId }) => { const dispatch = useDispatch(); const { browserFields, indexPattern } = useSourcererDataView(SourcererScopeName.timeline); @@ -86,6 +65,7 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline show, filters, kqlMode, + changed = false, } = useDeepEqualSelector((state) => pick( [ @@ -99,6 +79,7 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline 'show', 'filters', 'kqlMode', + 'changed', ], getTimeline(state, timelineId) ?? timelineDefaults ) @@ -109,14 +90,15 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline ); const getKqlQueryTimeline = useMemo(() => timelineSelectors.getKqlFilterQuerySelector(), []); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const kqlQueryTimeline = useSelector((state: State) => getKqlQueryTimeline(state, timelineId)!); + + const kqlQueryTimeline = useSelector((state: State) => getKqlQueryTimeline(state, timelineId)); const kqlQueryExpression = isEmpty(dataProviders) && isEmpty(kqlQueryTimeline) && timelineType === 'template' ? ' ' - : kqlQueryTimeline; - const kqlQueryTest = useMemo( + : kqlQueryTimeline ?? ''; + + const kqlQueryObj = useMemo( () => ({ query: kqlQueryExpression, language: 'kuery' }), [kqlQueryExpression] ); @@ -129,55 +111,69 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline indexPattern, browserFields, filters: filters ? filters : [], - kqlQuery: kqlQueryTest, + kqlQuery: kqlQueryObj, kqlMode, }), - [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQueryTest] + [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQueryObj] ); const handleClose = useCallback(() => { + createHistoryEntry(); dispatch(timelineActions.showTimeline({ id: timelineId, show: false })); focusActiveTimelineButton(); }, [dispatch, timelineId]); - const { euiTheme } = useEuiTheme(); - return ( - - - - - - + + + + + + + + + + + + + + + + {show && ( - - - {(activeTab === TimelineTabs.query || activeTab === TimelineTabs.eql) && ( - - - - )} + + + = ({ timeline )} - - + + ); }; export const FlyoutHeaderPanel = React.memo(FlyoutHeaderPanelComponent); - -const StyledDiv = styled.div` - display: -webkit-box; - -webkit-line-clamp: 1; - -webkit-box-orient: vertical; - overflow: hidden; - word-break: break-word; -`; - -const ReadMoreButton = ({ - description, - onclick, -}: { - description: string; - onclick: MouseEventHandler; -}) => { - const [isOverflow, ref] = useIsOverflow(description); - return ( - <> - {description} - {isOverflow && ( - - {i18n.READ_MORE} - - )} - - ); -}; - -const StyledTimelineHeader = styled(EuiFlexGroup)` - ${({ theme }) => `margin: ${theme.eui.euiSizeXS} ${theme.eui.euiSizeS} 0 ${theme.eui.euiSizeS};`} - flex: 0; -`; - -const TimelineStatusInfoContainer = styled.span` - ${({ theme }) => `margin-left: ${theme.eui.euiSizeS};`} - white-space: nowrap; -`; - -const KpisContainer = styled.div` - ${({ theme }) => `margin-right: ${theme.eui.euiSizeM};`} -`; - -const RowFlexItem = styled(EuiFlexItem)` - flex-direction: row; - align-items: center; -`; - -const TimelineTitleContainer = styled.h3` - display: -webkit-box; - overflow: hidden; - -webkit-line-clamp: 1; - -webkit-box-orient: vertical; - word-break: break-word; -`; - -const TimelineNameComponent: React.FC = ({ timelineId }) => { - const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const { title, timelineType } = useDeepEqualSelector((state) => - pick(['title', 'timelineType'], getTimeline(state, timelineId) ?? timelineDefaults) - ); - const placeholder = useMemo( - () => - timelineType === TimelineType.template - ? commonI18n.UNTITLED_TEMPLATE - : commonI18n.UNTITLED_TIMELINE, - [timelineType] - ); - - const content = useMemo(() => title || placeholder, [title, placeholder]); - - return ( - - - {content} - - - ); -}; - -const TimelineName = React.memo(TimelineNameComponent); - -const TimelineDescriptionComponent: React.FC<{ timelineId: string; description?: string }> = ({ - timelineId, - description, -}) => { - const dispatch = useDispatch(); - - const onReadMore = useCallback(() => { - dispatch( - setActiveTabTimeline({ - id: timelineId, - activeTab: TimelineTabs.notes, - scrollToTop: true, - }) - ); - }, [dispatch, timelineId]); - - const hasDescription = !!description; - return hasDescription ? ( - - - - ) : null; -}; - -const TimelineDescription = React.memo(TimelineDescriptionComponent); - -const TimelineStatusInfoComponent = React.memo<{ - status: TimelineStatus; - updated?: number; - changed?: boolean; -}>(({ status, updated, changed }) => { - const isUnsaved = status === TimelineStatus.draft; - - let statusContent: React.ReactNode = null; - if (isUnsaved) { - statusContent = {i18n.UNSAVED}; - } else if (changed) { - statusContent = {i18n.UNSAVED_CHANGES}; - } else { - statusContent = ( - <> - {i18n.SAVED}{' '} - - - ); - } - return ( - - {statusContent} - - ); -}); -TimelineStatusInfoComponent.displayName = 'TimelineStatusInfoComponent'; - -const FlyoutHeaderComponent: React.FC = ({ timelineId }) => { - const { selectedPatterns, indexPattern, browserFields } = useSourcererDataView( - SourcererScopeName.timeline - ); - const getStartSelector = useMemo(() => startSelector(), []); - const getEndSelector = useMemo(() => endSelector(), []); - const isActive = useMemo(() => timelineId === TimelineId.active, [timelineId]); - const timerange: TimerangeInput = useDeepEqualSelector((state) => { - if (isActive) { - return { - from: getStartSelector(state.inputs.timeline), - to: getEndSelector(state.inputs.timeline), - interval: '', - }; - } else { - return { - from: getStartSelector(state.inputs.global), - to: getEndSelector(state.inputs.global), - interval: '', - }; - } - }); - const { uiSettings } = useKibana().services; - const esQueryConfig = useMemo(() => getEsQueryConfig(uiSettings), [uiSettings]); - const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const timeline: TimelineModel = useSelector( - (state: State) => getTimeline(state, timelineId) ?? timelineDefaults - ); - const { dataProviders, filters, timelineType, kqlMode, activeTab } = timeline; - const getKqlQueryTimeline = useMemo(() => timelineSelectors.getKqlFilterQuerySelector(), []); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const kqlQueryTimeline = useSelector((state: State) => getKqlQueryTimeline(state, timelineId)!); - - const kqlQueryExpression = - isEmpty(dataProviders) && isEmpty(kqlQueryTimeline) && timelineType === 'template' - ? ' ' - : kqlQueryTimeline; - const kqlQuery = useMemo( - () => ({ query: kqlQueryExpression, language: 'kuery' }), - [kqlQueryExpression] - ); - - const combinedQueries = useMemo( - () => - combineQueries({ - config: esQueryConfig, - dataProviders, - indexPattern, - browserFields, - filters: filters ? filters : [], - kqlQuery, - kqlMode, - }), - [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQuery] - ); - - const isBlankTimeline: boolean = useMemo( - () => - (isEmpty(dataProviders) && isEmpty(filters) && isEmpty(kqlQuery.query)) || - combinedQueries?.filterQuery === undefined, - [dataProviders, filters, kqlQuery, combinedQueries] - ); - - const [loading, kpis] = useTimelineKpis({ - defaultIndex: selectedPatterns, - timerange, - isBlankTimeline, - filterQuery: combinedQueries?.filterQuery ?? '', - }); - - const userCasesPermissions = useGetUserCasesPermissions(); - return ( - - - - - - - - - - - - - - - - - - - {activeTab === TimelineTabs.query ? ( - - ) : null} - - - - - - - - - {userCasesPermissions.create && userCasesPermissions.read && ( - - - - )} - - - - - - - ); -}; - -FlyoutHeaderComponent.displayName = 'FlyoutHeaderComponent'; - -export const FlyoutHeader = React.memo(FlyoutHeaderComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx deleted file mode 100644 index 4cb622ec801b..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/kpis.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { EuiStat, EuiFlexItem, EuiFlexGroup, EuiToolTip } from '@elastic/eui'; -import numeral from '@elastic/numeral'; -import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; -import { useUiSetting$ } from '../../../../common/lib/kibana'; -import type { TimelineKpiStrategyResponse } from '../../../../../common/search_strategy'; -import { getEmptyValue } from '../../../../common/components/empty_value'; -import * as i18n from './translations'; - -const NoWrapEuiStat = styled(EuiStat)` - & .euiStat__description { - white-space: nowrap; - } -`; - -export const TimelineKPIs = React.memo( - ({ kpis, isLoading }: { kpis: TimelineKpiStrategyResponse | null; isLoading: boolean }) => { - const kpiFormat = '0,0.[000]a'; - const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - const formattedKpis = useMemo(() => { - return { - process: kpis === null ? getEmptyValue() : numeral(kpis.processCount).format(kpiFormat), - user: kpis === null ? getEmptyValue() : numeral(kpis.userCount).format(kpiFormat), - host: kpis === null ? getEmptyValue() : numeral(kpis.hostCount).format(kpiFormat), - sourceIp: kpis === null ? getEmptyValue() : numeral(kpis.sourceIpCount).format(kpiFormat), - destinationIp: - kpis === null ? getEmptyValue() : numeral(kpis.destinationIpCount).format(kpiFormat), - }; - }, [kpis]); - const formattedKpiToolTips = useMemo(() => { - return { - process: numeral(kpis?.processCount).format(defaultNumberFormat), - user: numeral(kpis?.userCount).format(defaultNumberFormat), - host: numeral(kpis?.hostCount).format(defaultNumberFormat), - sourceIp: numeral(kpis?.sourceIpCount).format(defaultNumberFormat), - destinationIp: numeral(kpis?.destinationIpCount).format(defaultNumberFormat), - }; - }, [kpis, defaultNumberFormat]); - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -); - -TimelineKPIs.displayName = 'TimelineKPIs'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.test.tsx new file mode 100644 index 000000000000..f7fda862f793 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.test.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen, render } from '@testing-library/react'; +import type { TimelineStatusInfoProps } from './timeline_status_info'; +import { TimelineStatusInfo } from './timeline_status_info'; +import { TimelineStatus } from '../../../../../common/api/timeline'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; + +const TestComponent = (props: TimelineStatusInfoProps) => { + return ( + + + + ); +}; + +describe('TestComponent', () => { + it('should render the status correctly when timeline is unsaved', () => { + render(); + expect(screen.getByText('Unsaved')).toBeVisible(); + }); + + it('should render the status correctly when timeline has unsaved changes', () => { + render(); + expect(screen.getByText('Has unsaved changes')).toBeVisible(); + }); + + it('should render the status correctly when timeline is saved', () => { + const updatedTime = Date.now(); + render(); + expect(screen.getByText('Saved')).toBeVisible(); + }); + + it('should render the status correctly when timeline is saved some time ago', () => { + const updatedTime = Date.now() - 10000; + render(); + expect(screen.getByTestId('timeline-status')).toHaveTextContent(/Saved10 seconds ago/); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.tsx new file mode 100644 index 000000000000..ed164ddab47f --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/timeline_status_info.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiTextColor, EuiText } from '@elastic/eui'; +import { FormattedRelative } from '@kbn/i18n-react'; + +import styled from 'styled-components'; +import { TimelineStatus } from '../../../../../common/api/timeline'; +import * as i18n from './translations'; + +const NoWrapText = styled(EuiText)` + white-space: nowrap; +`; + +export interface TimelineStatusInfoProps { + status: TimelineStatus; + updated?: number; + changed?: boolean; +} + +export const TimelineStatusInfo = React.memo( + ({ status, updated, changed }) => { + const isUnsaved = status === TimelineStatus.draft; + + let statusContent: React.ReactNode = null; + if (isUnsaved || !updated) { + statusContent = {i18n.UNSAVED}; + } else if (changed) { + statusContent = {i18n.UNSAVED_CHANGES}; + } else { + statusContent = ( + <> + {i18n.SAVED} + + + ); + } + return ( + + {statusContent} + + ); + } +); +TimelineStatusInfo.displayName = 'TimelineStatusInfo'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts index 2a52d9407ad5..56036f899e61 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/translations.ts @@ -37,35 +37,6 @@ export const INSPECT_TIMELINE_TITLE = i18n.translate( } ); -export const PROCESS_KPI_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.kpis.processKpiTitle', - { - defaultMessage: 'Processes', - } -); - -export const HOST_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.hostKpiTitle', { - defaultMessage: 'Hosts', -}); - -export const SOURCE_IP_KPI_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.kpis.sourceIpKpiTitle', - { - defaultMessage: 'Source IPs', - } -); - -export const DESTINATION_IP_KPI_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.kpis.destinationKpiTitle', - { - defaultMessage: 'Destination IPs', - } -); - -export const USER_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.userKpiTitle', { - defaultMessage: 'Users', -}); - export const READ_MORE = i18n.translate('xpack.securitySolution.timeline.properties.readMore', { defaultMessage: 'Read More', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx deleted file mode 100644 index 4f8d311ad75e..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render, waitFor } from '@testing-library/react'; -import React from 'react'; - -import { TestProviders } from '../../../../common/mock'; -import { TimelineId } from '../../../../../common/types/timeline'; -import { Pane } from '.'; -import { useGetUserCasesPermissions } from '../../../../common/lib/kibana'; - -jest.mock('../../../../common/lib/kibana'); -const originalKibanaLib = jest.requireActual('../../../../common/lib/kibana'); -jest.mock('@kbn/i18n-react', () => { - const originalModule = jest.requireActual('@kbn/i18n-react'); - const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago'); - - return { - ...originalModule, - FormattedRelative, - }; -}); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); - -jest.mock('../../../../common/utils/normalize_time_range'); - -jest.mock('../../../../common/hooks/use_resolve_conflict', () => { - return { - useResolveConflict: jest.fn().mockImplementation(() => null), - }; -}); - -// FLAKY: https://github.com/elastic/kibana/issues/168026 -describe.skip('Pane', () => { - test('renders with display block by default', async () => { - const EmptyComponent = render( - - - - ); - - await waitFor(() => { - expect(EmptyComponent.getByTestId('flyout-pane')).toHaveStyle('display: block'); - }); - }); - - test.skip('renders with display none when visibility is set to false', async () => { - const EmptyComponent = render( - - - - ); - await waitFor(() => { - expect(EmptyComponent.getByTestId('timeline-flyout')).toHaveStyle('display: none'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.ts new file mode 100644 index 000000000000..7cfdf2a31aca --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { Pane } from './pane'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx deleted file mode 100644 index c8156c455d7e..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo, useRef } from 'react'; -import { css } from '@emotion/react'; -import { useEuiBackgroundColor, useEuiTheme } from '@elastic/eui'; - -import { StatefulTimeline } from '../../timeline'; -import type { TimelineId } from '../../../../../common/types/timeline'; -import * as i18n from './translations'; -import { defaultRowRenderers } from '../../timeline/body/renderers'; -import { DefaultCellRenderer } from '../../timeline/cell_rendering/default_cell_renderer'; -import { EuiPortal } from './custom_portal'; -interface FlyoutPaneComponentProps { - timelineId: TimelineId; - visible?: boolean; -} - -const FlyoutPaneComponent: React.FC = ({ - timelineId, - visible = true, -}) => { - const { euiTheme } = useEuiTheme(); - const ref = useRef(null); - const timeline = useMemo( - () => ( - - ), - [timelineId] - ); - - return ( -
    - -
    - {timeline} -
    -
    -
    - ); -}; - -export const Pane = React.memo(FlyoutPaneComponent); - -Pane.displayName = 'Pane'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/pane.styles.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/pane.styles.tsx new file mode 100644 index 000000000000..95bea7d742ca --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/pane.styles.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { css } from '@emotion/css'; +import { Global } from '@emotion/react'; +import { + useEuiTheme, + euiAnimFadeIn, + transparentize, + euiBackgroundColor, + euiCanAnimate, + euiAnimSlideInUp, +} from '@elastic/eui'; + +export const usePaneStyles = () => { + const EuiTheme = useEuiTheme(); + const { euiTheme } = EuiTheme; + return css` + // euiOverlayMask styles + position: fixed; + top: var(--euiFixedHeadersOffset, 0); + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background: ${transparentize(euiTheme.colors.ink, 0.5)}; + z-index: ${euiTheme.levels.flyout}; + + ${euiCanAnimate} { + animation: ${euiAnimFadeIn} ${euiTheme.animation.fast} ease-in; + } + + &.timeline-wrapper--hidden { + display: none; + } + + .timeline-flyout { + min-width: 150px; + height: inherit; + position: fixed; + top: var(--euiFixedHeadersOffset, 0); + right: 0; + bottom: 0; + left: 0; + background: ${euiBackgroundColor(EuiTheme, 'plain')}; + ${euiCanAnimate} { + animation: ${euiAnimSlideInUp(euiTheme.size.xxl)} ${euiTheme.animation.normal} + cubic-bezier(0.39, 0.575, 0.565, 1); + } + + .timeline-body { + height: 100%; + display: flex; + flex-direction: column; + } + } + + &:not(.timeline-wrapper--full-screen) .timeline-flyout { + margin: ${euiTheme.size.m}; + border-radius: ${euiTheme.border.radius.medium}; + + .timeline-template-badge { + border-radius: ${euiTheme.border.radius.medium} ${euiTheme.border.radius.medium} 0 0; // top corners only + } + } + `; +}; + +export const OverflowHiddenGlobalStyles = () => { + return
    , -
    + class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexEnd-stretch-row" + > +
    +
    , ] @@ -164,6 +229,10 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should padding: 0 12px 12px; } +.c2 .side-panel-flyout-footer { + background-color: transparent; +} +
    +
    +
    +
    +

    + Assignees: +

    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    @@ -255,15 +381,19 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should
    + class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexEnd-stretch-row" + > +
    +
    diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx index 82d41e0eafb3..18cef99f0cb2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx @@ -19,9 +19,13 @@ import { EuiSpacer, EuiCopy, } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; +import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; +import { TableId } from '@kbn/securitysolution-data-table'; +import type { GetFieldsData } from '../../../../common/hooks/use_get_fields_data'; +import { Assignees } from '../../../../flyout/document_details/right/components/assignees'; import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; import type { TimelineTabs } from '../../../../../common/types/timeline'; import type { BrowserFields } from '../../../../common/containers/source'; @@ -34,6 +38,7 @@ import { } from '../../../../common/components/event_details/translations'; import { PreferenceFormattedDate } from '../../../../common/components/formatted_date'; import { useGetAlertDetailsFlyoutLink } from './use_get_alert_details_flyout_link'; +import { useRefetchByScope } from './flyout/use_refetch_by_scope'; export type HandleOnEventClosed = () => void; interface Props { @@ -61,6 +66,9 @@ interface ExpandableEventTitleProps { ruleName?: string; timestamp: string; handleOnEventClosed?: HandleOnEventClosed; + scopeId: string; + refetchFlyoutData: () => Promise; + getFieldsData: GetFieldsData; } const StyledEuiFlexGroup = styled(EuiFlexGroup)` @@ -89,6 +97,9 @@ export const ExpandableEventTitle = React.memo( promptContextId, ruleName, timestamp, + scopeId, + refetchFlyoutData, + getFieldsData, }) => { const { hasAssistantPrivilege } = useAssistantAvailability(); const alertDetailsLink = useGetAlertDetailsFlyoutLink({ @@ -97,6 +108,16 @@ export const ExpandableEventTitle = React.memo( timestamp, }); + const { refetch } = useRefetchByScope({ scopeId }); + const alertAssignees = useMemo( + () => (getFieldsData(ALERT_WORKFLOW_ASSIGNEE_IDS) as string[]) ?? [], + [getFieldsData] + ); + const onAssigneesUpdated = useCallback(() => { + refetch(); + refetchFlyoutData(); + }, [refetch, refetchFlyoutData]); + return ( @@ -115,7 +136,7 @@ export const ExpandableEventTitle = React.memo( )} - + {handleOnEventClosed && ( ( )} + {scopeId !== TableId.rulePreview && ( + + + + )} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx index 91a2904287ff..5362af38c241 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx @@ -13,11 +13,7 @@ import { TimelineId } from '../../../../../../common/types/timeline'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { mockAlertDetailsData } from '../../../../../common/components/event_details/__mocks__'; import type { TimelineEventsDetailsItem } from '../../../../../../common/search_strategy'; -import { - KibanaServices, - useGetUserCasesPermissions, - useKibana, -} from '../../../../../common/lib/kibana'; +import { KibanaServices, useKibana } from '../../../../../common/lib/kibana'; import { coreMock } from '@kbn/core/public/mocks'; import { mockCasesContract } from '@kbn/cases-plugin/public/mocks'; @@ -70,12 +66,6 @@ jest.mock('../../../../../detections/components/user_info', () => ({ })); jest.mock('../../../../../common/lib/kibana'); -const originalKibanaLib = jest.requireActual('../../../../../common/lib/kibana'); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); jest.mock( '../../../../../detections/containers/detection_engine/alerts/use_alerts_privileges', diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx index ac5d5ee32797..97a7e9196ae4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx @@ -8,8 +8,6 @@ import React, { useCallback, useMemo, useState } from 'react'; import { EuiFlyoutFooter, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { find } from 'lodash/fp'; -import type { ConnectedProps } from 'react-redux'; -import { connect } from 'react-redux'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { isActiveTimeline } from '../../../../../helpers'; import { TakeActionDropdown } from '../../../../../detections/components/take_action_dropdown'; @@ -20,9 +18,9 @@ import { EventFiltersFlyout } from '../../../../../management/pages/event_filter import { useEventFilterModal } from '../../../../../detections/components/alerts_table/timeline_actions/use_event_filter_modal'; import { getFieldValue } from '../../../../../detections/components/host_isolation/helpers'; import type { Status } from '../../../../../../common/api/detection_engine'; -import type { inputsModel, State } from '../../../../../common/store'; -import { inputsSelectors } from '../../../../../common/store'; import { OsqueryFlyout } from '../../../../../detections/components/osquery/osquery_flyout'; +import { useRefetchByScope } from './use_refetch_by_scope'; + interface FlyoutFooterProps { detailsData: TimelineEventsDetailsItem[] | null; detailsEcsData: Ecs | null; @@ -43,173 +41,142 @@ interface AddExceptionModalWrapperData { ruleName: string; } -// eslint-disable-next-line react/display-name -export const FlyoutFooterComponent = React.memo( - ({ - detailsData, - detailsEcsData, - handleOnEventClosed, - isHostIsolationPanelOpen, - isReadOnly, - loadingEventDetails, - onAddIsolationStatusClick, - scopeId, - globalQuery, - timelineQuery, - refetchFlyoutData, - }: FlyoutFooterProps & PropsFromRedux) => { - const alertId = detailsEcsData?.kibana?.alert ? detailsEcsData?._id : null; - const ruleIndexRaw = useMemo( - () => - find({ category: 'signal', field: 'signal.rule.index' }, detailsData)?.values ?? - find({ category: 'kibana', field: 'kibana.alert.rule.parameters.index' }, detailsData) - ?.values, - [detailsData] - ); - const ruleIndex = useMemo( - (): string[] | undefined => (Array.isArray(ruleIndexRaw) ? ruleIndexRaw : undefined), - [ruleIndexRaw] - ); - const ruleDataViewIdRaw = useMemo( - () => - find({ category: 'signal', field: 'signal.rule.data_view_id' }, detailsData)?.values ?? - find( - { category: 'kibana', field: 'kibana.alert.rule.parameters.data_view_id' }, - detailsData - )?.values, - [detailsData] - ); - const ruleDataViewId = useMemo( - (): string | undefined => - Array.isArray(ruleDataViewIdRaw) ? ruleDataViewIdRaw[0] : undefined, - [ruleDataViewIdRaw] - ); - - const addExceptionModalWrapperData = useMemo( - () => - [ - { category: 'signal', field: 'signal.rule.id', name: 'ruleId' }, - { category: 'signal', field: 'signal.rule.rule_id', name: 'ruleRuleId' }, - { category: 'signal', field: 'signal.rule.name', name: 'ruleName' }, - { category: 'signal', field: 'kibana.alert.workflow_status', name: 'alertStatus' }, - { category: '_id', field: '_id', name: 'eventId' }, - ].reduce( - (acc, curr) => ({ - ...acc, - [curr.name]: getFieldValue({ category: curr.category, field: curr.field }, detailsData), - }), - {} as AddExceptionModalWrapperData - ), - [detailsData] - ); +export const FlyoutFooterComponent = ({ + detailsData, + detailsEcsData, + handleOnEventClosed, + isHostIsolationPanelOpen, + isReadOnly, + loadingEventDetails, + onAddIsolationStatusClick, + scopeId, + refetchFlyoutData, +}: FlyoutFooterProps) => { + const alertId = detailsEcsData?.kibana?.alert ? detailsEcsData?._id : null; + const ruleIndexRaw = useMemo( + () => + find({ category: 'signal', field: 'signal.rule.index' }, detailsData)?.values ?? + find({ category: 'kibana', field: 'kibana.alert.rule.parameters.index' }, detailsData) + ?.values, + [detailsData] + ); + const ruleIndex = useMemo( + (): string[] | undefined => (Array.isArray(ruleIndexRaw) ? ruleIndexRaw : undefined), + [ruleIndexRaw] + ); + const ruleDataViewIdRaw = useMemo( + () => + find({ category: 'signal', field: 'signal.rule.data_view_id' }, detailsData)?.values ?? + find({ category: 'kibana', field: 'kibana.alert.rule.parameters.data_view_id' }, detailsData) + ?.values, + [detailsData] + ); + const ruleDataViewId = useMemo( + (): string | undefined => (Array.isArray(ruleDataViewIdRaw) ? ruleDataViewIdRaw[0] : undefined), + [ruleDataViewIdRaw] + ); - const refetchQuery = (newQueries: inputsModel.GlobalQuery[]) => { - newQueries.forEach((q) => q.refetch && (q.refetch as inputsModel.Refetch)()); - }; + const addExceptionModalWrapperData = useMemo( + () => + [ + { category: 'signal', field: 'signal.rule.id', name: 'ruleId' }, + { category: 'signal', field: 'signal.rule.rule_id', name: 'ruleRuleId' }, + { category: 'signal', field: 'signal.rule.name', name: 'ruleName' }, + { category: 'signal', field: 'kibana.alert.workflow_status', name: 'alertStatus' }, + { category: '_id', field: '_id', name: 'eventId' }, + ].reduce( + (acc, curr) => ({ + ...acc, + [curr.name]: getFieldValue({ category: curr.category, field: curr.field }, detailsData), + }), + {} as AddExceptionModalWrapperData + ), + [detailsData] + ); - const refetchAll = useCallback(() => { - if (isActiveTimeline(scopeId)) { - refetchQuery([timelineQuery]); - } else { - refetchQuery(globalQuery); - } - }, [scopeId, timelineQuery, globalQuery]); + const { refetch: refetchAll } = useRefetchByScope({ scopeId }); - const { - exceptionFlyoutType, - openAddExceptionFlyout, - onAddExceptionTypeClick, - onAddExceptionCancel, - onAddExceptionConfirm, - } = useExceptionFlyout({ - refetch: refetchAll, - isActiveTimelines: isActiveTimeline(scopeId), - }); - const { closeAddEventFilterModal, isAddEventFilterModalOpen, onAddEventFilterClick } = - useEventFilterModal(); + const { + exceptionFlyoutType, + openAddExceptionFlyout, + onAddExceptionTypeClick, + onAddExceptionCancel, + onAddExceptionConfirm, + } = useExceptionFlyout({ + refetch: refetchAll, + isActiveTimelines: isActiveTimeline(scopeId), + }); + const { closeAddEventFilterModal, isAddEventFilterModalOpen, onAddEventFilterClick } = + useEventFilterModal(); - const [isOsqueryFlyoutOpenWithAgentId, setOsqueryFlyoutOpenWithAgentId] = useState< - null | string - >(null); + const [isOsqueryFlyoutOpenWithAgentId, setOsqueryFlyoutOpenWithAgentId] = useState( + null + ); - const closeOsqueryFlyout = useCallback(() => { - setOsqueryFlyoutOpenWithAgentId(null); - }, [setOsqueryFlyoutOpenWithAgentId]); + const closeOsqueryFlyout = useCallback(() => { + setOsqueryFlyoutOpenWithAgentId(null); + }, [setOsqueryFlyoutOpenWithAgentId]); - if (isReadOnly) { - return null; - } + if (isReadOnly) { + return null; + } - return ( - <> - - - - {detailsEcsData && ( - - )} - - - - {/* This is still wrong to do render flyout/modal inside of the flyout + return ( + <> + + + + {detailsEcsData && ( + + )} + + + + {/* This is still wrong to do render flyout/modal inside of the flyout We need to completely refactor the EventDetails component to be correct */} - {openAddExceptionFlyout && - addExceptionModalWrapperData.ruleId != null && - addExceptionModalWrapperData.ruleRuleId != null && - addExceptionModalWrapperData.eventId != null && ( - - )} - {isAddEventFilterModalOpen && detailsEcsData != null && ( - - )} - {isOsqueryFlyoutOpenWithAgentId && detailsEcsData != null && ( - )} - - ); - } -); - -const makeMapStateToProps = () => { - const getGlobalQueries = inputsSelectors.globalQuery(); - const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); - const mapStateToProps = (state: State, { scopeId }: FlyoutFooterProps) => { - return { - globalQuery: getGlobalQueries(state), - timelineQuery: getTimelineQuery(state, scopeId), - }; - }; - return mapStateToProps; + {isAddEventFilterModalOpen && detailsEcsData != null && ( + + )} + {isOsqueryFlyoutOpenWithAgentId && detailsEcsData != null && ( + + )} + + ); }; -const connector = connect(makeMapStateToProps); - -type PropsFromRedux = ConnectedProps; - -export const FlyoutFooter = connector(React.memo(FlyoutFooterComponent)); +export const FlyoutFooter = React.memo(FlyoutFooterComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx index 8b3d50d849c4..d5df4304a089 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx @@ -8,6 +8,7 @@ import { EuiFlyoutHeader } from '@elastic/eui'; import React from 'react'; +import type { GetFieldsData } from '../../../../../common/hooks/use_get_fields_data'; import { ExpandableEventTitle } from '../expandable_event'; import { BackToAlertDetailsLink } from './back_to_alert_details_link'; @@ -22,6 +23,9 @@ interface FlyoutHeaderComponentProps { ruleName: string; showAlertDetails: () => void; timestamp: string; + scopeId: string; + refetchFlyoutData: () => Promise; + getFieldsData: GetFieldsData; } const FlyoutHeaderContentComponent = ({ @@ -35,6 +39,9 @@ const FlyoutHeaderContentComponent = ({ ruleName, showAlertDetails, timestamp, + scopeId, + refetchFlyoutData, + getFieldsData, }: FlyoutHeaderComponentProps) => { return ( <> @@ -49,6 +56,9 @@ const FlyoutHeaderContentComponent = ({ promptContextId={promptContextId} ruleName={ruleName} timestamp={timestamp} + scopeId={scopeId} + refetchFlyoutData={refetchFlyoutData} + getFieldsData={getFieldsData} /> )} @@ -67,6 +77,9 @@ const FlyoutHeaderComponent = ({ ruleName, showAlertDetails, timestamp, + scopeId, + refetchFlyoutData, + getFieldsData, }: FlyoutHeaderComponentProps) => { return ( @@ -81,6 +94,9 @@ const FlyoutHeaderComponent = ({ ruleName={ruleName} showAlertDetails={showAlertDetails} timestamp={timestamp} + scopeId={scopeId} + refetchFlyoutData={refetchFlyoutData} + getFieldsData={getFieldsData} /> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/use_refetch_by_scope.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/use_refetch_by_scope.tsx new file mode 100644 index 000000000000..efb7c19ba687 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/use_refetch_by_scope.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; +import { isActiveTimeline } from '../../../../../helpers'; +import type { inputsModel } from '../../../../../common/store'; +import { inputsSelectors } from '../../../../../common/store'; + +export interface UseRefetchScopeQueryParams { + /** + * Scope ID + */ + scopeId: string; +} + +/** + * Hook to refetch data within specified scope + */ +export const useRefetchByScope = ({ scopeId }: UseRefetchScopeQueryParams) => { + const getGlobalQueries = inputsSelectors.globalQuery(); + const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector(); + const { globalQuery, timelineQuery } = useDeepEqualSelector((state) => ({ + globalQuery: getGlobalQueries(state), + timelineQuery: getTimelineQuery(state, scopeId), + })); + + const refetchQuery = (newQueries: inputsModel.GlobalQuery[]) => { + newQueries.forEach((q) => q.refetch && (q.refetch as inputsModel.Refetch)()); + }; + + const refetchAll = useCallback(() => { + if (isActiveTimeline(scopeId)) { + refetchQuery([timelineQuery]); + } else { + refetchQuery(globalQuery); + } + }, [scopeId, timelineQuery, globalQuery]); + + return { refetch: refetchAll }; +}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx index 10a536f69c8d..3f7702d490e9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx @@ -11,11 +11,7 @@ import '../../../../common/mock/match_media'; import { TestProviders } from '../../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { - KibanaServices, - useKibana, - useGetUserCasesPermissions, -} from '../../../../common/lib/kibana'; +import { KibanaServices, useKibana } from '../../../../common/lib/kibana'; import { mockBrowserFields, mockRuntimeMappings } from '../../../../common/containers/source/mock'; import { coreMock } from '@kbn/core/public/mocks'; import { mockCasesContext } from '@kbn/cases-plugin/public/mocks/mock_cases_context'; @@ -26,6 +22,7 @@ import { DEFAULT_PREVIEW_INDEX, ASSISTANT_FEATURE_ID, } from '../../../../../common/constants'; +import { useUpsellingMessage } from '../../../../common/hooks/use_upselling'; const ecsData: Ecs = { _id: '1', @@ -73,6 +70,18 @@ jest.mock( } ); +jest.mock('../../../../common/components/user_profiles/use_bulk_get_user_profiles', () => { + return { + useBulkGetUserProfiles: jest.fn().mockReturnValue({ isLoading: false, data: [] }), + }; +}); + +jest.mock('../../../../common/components/user_profiles/use_suggest_users', () => { + return { + useSuggestUsers: jest.fn().mockReturnValue({ isLoading: false, data: [] }), + }; +}); + jest.mock('../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(true), })); @@ -116,6 +125,7 @@ jest.mock('../../../../explore/containers/risk_score', () => { }), }; }); +jest.mock('../../../../common/hooks/use_upselling'); const defaultProps = { scopeId: TimelineId.test, @@ -156,6 +166,9 @@ describe('event details panel component', () => { ui: { getCasesContext: () => mockCasesContext, }, + cases: { + helpers: { canUseCases: jest.fn().mockReturnValue(allCasesPermissions()) }, + }, }, timelines: { getHoverActions: jest.fn().mockReturnValue({ @@ -168,11 +181,13 @@ describe('event details panel component', () => { }, }, }); - (useGetUserCasesPermissions as jest.Mock).mockReturnValue(allCasesPermissions()); + (useUpsellingMessage as jest.Mock).mockReturnValue('Go for Platinum!'); }); + afterEach(() => { jest.clearAllMocks(); }); + test('it renders the take action dropdown in the timeline version', () => { const wrapper = render( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx index 729b20e68cb1..20b6341db6d9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx @@ -6,12 +6,14 @@ */ import { useAssistantOverlay } from '@kbn/elastic-assistant'; -import { EuiSpacer, EuiFlyoutBody } from '@elastic/eui'; +import { EuiSpacer, EuiFlyoutBody, EuiPanel } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; +import styled from 'styled-components'; import deepEqual from 'fast-deep-equal'; import type { EntityType } from '@kbn/timelines-plugin/common'; +import { useGetFieldsData } from '../../../../common/hooks/use_get_fields_data'; import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; import { getRawData } from '../../../../assistant/helpers'; import type { BrowserFields } from '../../../../common/containers/source'; @@ -41,6 +43,12 @@ import { PROMPT_CONTEXTS, } from '../../../../assistant/content/prompt_contexts'; +const FlyoutFooterContainerPanel = styled(EuiPanel)` + .side-panel-flyout-footer { + background-color: transparent; + } +`; + interface EventDetailsPanelProps { browserFields: BrowserFields; entityType?: EntityType; @@ -87,6 +95,7 @@ const EventDetailsPanelComponent: React.FC = ({ skip: !expandedEvent.eventId, } ); + const getFieldsData = useGetFieldsData(rawEventData?.fields); const { isolateAction, @@ -130,6 +139,9 @@ const EventDetailsPanelComponent: React.FC = ({ showAlertDetails={showAlertDetails} timestamp={timestamp} promptContextId={promptContextId} + scopeId={scopeId} + refetchFlyoutData={refetchFlyoutData} + getFieldsData={getFieldsData} /> ) : ( = ({ timestamp={timestamp} handleOnEventClosed={handleOnEventClosed} promptContextId={promptContextId} + scopeId={scopeId} + refetchFlyoutData={refetchFlyoutData} + getFieldsData={getFieldsData} /> ), [ @@ -154,8 +169,11 @@ const EventDetailsPanelComponent: React.FC = ({ ruleName, showAlertDetails, timestamp, - handleOnEventClosed, promptContextId, + handleOnEventClosed, + scopeId, + refetchFlyoutData, + getFieldsData, ] ); @@ -254,17 +272,19 @@ const EventDetailsPanelComponent: React.FC = ({ <> {header} {body} - + + + ); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx index 8895d1307c89..5e62b7e03bac 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx @@ -30,6 +30,18 @@ jest.mock('../../../common/containers/use_search_strategy', () => ({ useSearchStrategy: jest.fn(), })); +jest.mock('../../../common/components/user_profiles/use_bulk_get_user_profiles', () => { + return { + useBulkGetUserProfiles: jest.fn().mockReturnValue({ isLoading: false, data: [] }), + }; +}); + +jest.mock('../../../common/components/user_profiles/use_suggest_users', () => { + return { + useSuggestUsers: jest.fn().mockReturnValue({ isLoading: false, data: [] }), + }; +}); + jest.mock('../../../assistant/use_assistant_availability'); const mockUseLocation = jest.fn().mockReturnValue({ pathname: '/test', search: '?' }); jest.mock('react-router-dom', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx index bf590a5d55cd..ad33fdfe1b73 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx @@ -23,7 +23,6 @@ import { EventDetailsPanel } from './event_details'; import { HostDetailsPanel } from './host_details'; import { NetworkDetailsPanel } from './network_details'; import { UserDetailsPanel } from './user_details'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; interface DetailsPanelProps { browserFields: BrowserFields; @@ -53,7 +52,6 @@ export const DetailsPanel = React.memo( isReadOnly, }: DetailsPanelProps) => { const dispatch = useDispatch(); - const isNewUserDetailsFlyoutEnable = useIsExperimentalFeatureEnabled('newUserDetailsFlyout'); const getScope = useMemo(() => { if (isTimelineScope(scopeId)) { return timelineSelectors.getTimelineByIdSelector(); @@ -142,9 +140,6 @@ export const DetailsPanel = React.memo( if (currentTabDetail?.panelView === 'userDetail' && currentTabDetail?.params?.userName) { flyoutUniqueKey = currentTabDetail.params.userName; - if (isNewUserDetailsFlyoutEnable) { - panelSize = 'm'; - } visiblePanel = ( ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.test.tsx index 9e0e60caf80d..a8e1744c0c04 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { fireEvent, render } from '@testing-library/react'; +import { render } from '@testing-library/react'; import React from 'react'; import { TestProviders } from '../../../../common/mock'; import { ManagedUser } from './managed_user'; @@ -29,19 +29,6 @@ describe('ManagedUser', () => { expect(getByTestId('managedUser-data')).toBeInTheDocument(); }); - it('updates the accordion button title when visibility toggles', () => { - const { getByTestId } = render( - - - - ); - const accordionButton = getByTestId('managedUser-accordion-button'); - - expect(accordionButton).toHaveTextContent('Show Azure AD data'); - fireEvent.click(accordionButton); - expect(accordionButton).toHaveTextContent('Hide Azure AD data'); - }); - it('renders the formatted date', () => { const { getByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx index a802b49e85ca..5cb8f2138e36 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/managed_user.tsx @@ -14,9 +14,10 @@ import { useEuiTheme, EuiEmptyPrompt, EuiCallOut, + useEuiFontSize, } from '@elastic/eui'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import * as i18n from './translations'; @@ -44,10 +45,6 @@ export const ManagedUser = ({ }) => { const { euiTheme } = useEuiTheme(); const managedItems = useManagedUserItems(managedUser.details); - const [isManagedDataToggleOpen, setManagedDataToggleOpen] = useState(false); - const onToggleManagedData = useCallback(() => { - setManagedDataToggleOpen((isOpen) => !isOpen); - }, [setManagedDataToggleOpen]); const managedUserTableColumns = useMemo( () => getManagedUserTableColumns(contextID, scopeId, isDraggable), [isDraggable, contextID, scopeId] @@ -59,40 +56,16 @@ export const ManagedUser = ({ [getAppUrl] ); - if (!managedUser.isLoading && !managedUser.isIntegrationEnabled) { - return ( - <> - -
    {i18n.MANAGED_DATA_TITLE}
    -
    - - - {i18n.NO_ACTIVE_INTEGRATION_TITLE}

    } - body={

    {i18n.NO_ACTIVE_INTEGRATION_TEXT}

    } - actions={ - - {i18n.ADD_EXTERNAL_INTEGRATION_BUTTON} - - } - /> - - - ); - } + const xsFontSize = useEuiFontSize('xxs').fontSize; return ( <> - -
    {i18n.MANAGED_DATA_TITLE}
    -
    - +
    {i18n.MANAGED_DATA_TITLE}
    + } - onToggle={onToggleManagedData} extraAction={ <> {managedUser.lastSeen.date && ( - - ), - }} - /> + + + ), + }} + /> + )} } @@ -138,16 +118,34 @@ export const ManagedUser = ({ } `} > - - {managedItems || managedUser.isLoading ? ( - + {!managedUser.isLoading && !managedUser.isIntegrationEnabled ? ( + + {i18n.NO_ACTIVE_INTEGRATION_TITLE}

    } + titleSize="s" + body={

    {i18n.NO_ACTIVE_INTEGRATION_TEXT}

    } + actions={ + + {i18n.ADD_EXTERNAL_INTEGRATION_BUTTON} + + } /> - ) : ( - <> + + ) : ( + <> + {managedItems || managedUser.isLoading ? ( + + ) : (

    {i18n.NO_AZURE_DATA_TEXT}

    - - )} - + )} + + )} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.test.tsx index f57eda9b1fb2..90934c533a2c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { fireEvent, render } from '@testing-library/react'; +import { render } from '@testing-library/react'; import React from 'react'; import { TestProviders } from '../../../../common/mock'; import { mockObservedUser } from './__mocks__'; @@ -29,19 +29,6 @@ describe('ObservedUser', () => { expect(getByTestId('observedUser-data')).toBeInTheDocument(); }); - it('updates the accordion button title when visibility toggles', () => { - const { getByTestId } = render( - - - - ); - const accordionButton = getByTestId('observedUser-accordion-button'); - - expect(accordionButton).toHaveTextContent('Show observed data'); - fireEvent.click(accordionButton); - expect(accordionButton).toHaveTextContent('Hide observed data'); - }); - it('renders the formatted date', () => { const { getByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx index 01335997813a..9a0891c24a92 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/observed_user.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import { EuiAccordion, EuiSpacer, EuiTitle, useEuiTheme, EuiPanel } from '@elastic/eui'; +import { EuiAccordion, EuiSpacer, EuiTitle, useEuiTheme, useEuiFontSize } from '@elastic/eui'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import * as i18n from './translations'; @@ -33,27 +33,21 @@ export const ObservedUser = ({ }) => { const { euiTheme } = useEuiTheme(); const observedItems = useObservedUserItems(observedUser); - const [isObservedDataToggleOpen, setObservedDataToggleOpen] = useState(false); - const onToggleObservedData = useCallback(() => { - setObservedDataToggleOpen((isOpen) => !isOpen); - }, [setObservedDataToggleOpen]); + const observedUserTableColumns = useMemo( () => getObservedUserTableColumns(contextID, scopeId, isDraggable), [contextID, scopeId, isDraggable] ); + const xsFontSize = useEuiFontSize('xxs').fontSize; return ( <> - -
    {i18n.OBSERVED_DATA_TITLE}
    -
    - +

    {i18n.OBSERVED_DATA_TITLE}

    + } - onToggle={onToggleObservedData} extraAction={ <> {observedUser.lastSeen.date && ( - - ), - }} - /> + + + ), + }} + /> + )} } @@ -101,19 +100,19 @@ export const ObservedUser = ({ } `} > - - - + + +
    diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts index 01563fcb9478..4671cf815162 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/translations.ts @@ -46,20 +46,6 @@ export const OBSERVED_DATA_TITLE = i18n.translate( } ); -export const HIDE_OBSERVED_DATA_BUTTON = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.hideObservedDataButton', - { - defaultMessage: 'Hide observed data', - } -); - -export const SHOW_OBSERVED_DATA_BUTTON = i18n.translate( - 'xpack.securitySolution.timeline.userDetails.showObservedDataButton', - { - defaultMessage: 'Show observed data', - } -); - export const HIDE_AZURE_DATA_BUTTON = i18n.translate( 'xpack.securitySolution.timeline.userDetails.hideManagedDataButton', { @@ -166,7 +152,7 @@ export const PHONE = i18n.translate('xpack.securitySolution.timeline.userDetails export const NO_ACTIVE_INTEGRATION_TITLE = i18n.translate( 'xpack.securitySolution.timeline.userDetails.noActiveIntegrationTitle', { - defaultMessage: 'You don’t have any active integrations', + defaultMessage: 'You don’t have any active asset repository integrations', } ); @@ -174,14 +160,14 @@ export const NO_ACTIVE_INTEGRATION_TEXT = i18n.translate( 'xpack.securitySolution.timeline.userDetails.noActiveIntegrationText', { defaultMessage: - 'External integrations can provide additional metadata and help you manage users.', + 'Additional metadata from integrations may help you to manage and identify risky entities.', } ); export const ADD_EXTERNAL_INTEGRATION_BUTTON = i18n.translate( 'xpack.securitySolution.timeline.userDetails.addExternalIntegrationButton', { - defaultMessage: 'Add external integrations', + defaultMessage: 'Add asset repository integrations', } ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.stories.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.stories.tsx deleted file mode 100644 index 1f82d21c6532..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.stories.tsx +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { EuiFlyout, EuiFlyoutBody } from '@elastic/eui'; -import { UserDetailsContentComponent } from './user_details_content'; -import { StorybookProviders } from '../../../../common/mock/storybook_providers'; -import { mockManagedUser, mockObservedUser, mockRiskScoreState } from './__mocks__'; - -storiesOf('UserDetailsContent', module) - .addDecorator((storyFn) => ( - - {}}> - {storyFn()} - - - )) - .add('default', () => ( - - )) - .add('integration disabled', () => ( - - )) - .add('no managed data', () => ( - - )) - .add('no observed data', () => ( - - )) - .add('loading', () => ( - - )); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.test.tsx deleted file mode 100644 index 2d984cc926e4..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.test.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render } from '@testing-library/react'; -import React from 'react'; -import { TestProviders } from '../../../../common/mock'; -import { mockManagedUser, mockObservedUser, mockRiskScoreState } from './__mocks__'; -import { UserDetailsContentComponent } from './user_details_content'; - -const mockProps = { - userName: 'test', - managedUser: mockManagedUser, - observedUser: mockObservedUser, - riskScoreState: mockRiskScoreState, - contextID: 'test-user-details', - scopeId: 'test-scope-id', - isDraggable: false, -}; - -describe('UserDetailsContentComponent', () => { - it('renders', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-content-header')).toBeInTheDocument(); - }); - - it('renders observed user date when it is bigger than managed user date', () => { - const futureDay = '2989-03-07T20:00:00.000Z'; - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-content-lastSeen').textContent).toContain('Mar 7, 2989'); - }); - - it('renders managed user date when it is bigger than observed user date', () => { - const futureDay = '2989-03-07T20:00:00.000Z'; - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-content-lastSeen').textContent).toContain('Mar 7, 2989'); - }); - - it('renders observed and managed badges when lastSeen is defined', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('user-details-content-observed-badge')).toBeInTheDocument(); - expect(getByTestId('user-details-content-managed-badge')).toBeInTheDocument(); - }); - - it('does not render observed badge when lastSeen date is undefined', () => { - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId('user-details-content-observed-badge')).not.toBeInTheDocument(); - }); - - it('does not render managed badge when lastSeen date is undefined', () => { - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId('user-details-content-managed-badge')).not.toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.tsx deleted file mode 100644 index 95ffb05a1688..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/user_details_content.tsx +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiSpacer, - EuiHorizontalRule, - EuiIcon, - EuiBadge, - EuiText, - EuiFlexItem, - EuiFlexGroup, - useEuiFontSize, - useEuiTheme, - euiTextBreakWord, - EuiProgress, -} from '@elastic/eui'; - -import React, { useMemo } from 'react'; -import { css } from '@emotion/react'; -import { max } from 'lodash'; -import * as i18n from './translations'; - -import { RiskScoreEntity } from '../../../../../common/search_strategy'; -import { UserDetailsLink } from '../../../../common/components/links'; -import { useGlobalTime } from '../../../../common/containers/use_global_time'; -import type { RiskScoreState } from '../../../../explore/containers/risk_score'; -import { useRiskScore } from '../../../../explore/containers/risk_score'; - -import { useManagedUser, useObservedUser } from './hooks'; -import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/anomaly_table_provider'; -import { getCriteriaFromUsersType } from '../../../../common/components/ml/criteria/get_criteria_from_users_type'; -import { UsersType } from '../../../../explore/users/store/model'; -import { PreferenceFormattedDate } from '../../../../common/components/formatted_date'; -import type { ManagedUserData, ObservedUserData } from './types'; -import { RiskScoreField } from './risk_score_field'; -import { ObservedUser } from './observed_user'; -import { ManagedUser } from './managed_user'; - -export const QUERY_ID = 'usersDetailsQuery'; - -interface UserDetailsContentComponentProps { - userName: string; - observedUser: ObservedUserData; - managedUser: ManagedUserData; - riskScoreState: RiskScoreState; - contextID: string; - scopeId: string; - isDraggable: boolean; -} - -/** - * This is a visual component. It doesn't access any external Context or API. - * It designed for unit testing the UI and previewing changes on storybook. - */ -export const UserDetailsContentComponent = ({ - userName, - observedUser, - managedUser, - riskScoreState, - contextID, - scopeId, - isDraggable, -}: UserDetailsContentComponentProps) => { - const { euiTheme } = useEuiTheme(); - const { fontSize: xlFontSize } = useEuiFontSize('xl'); - - const lastSeenDate = useMemo( - () => - max([observedUser.lastSeen, managedUser.lastSeen].map((el) => el.date && new Date(el.date))), - [managedUser.lastSeen, observedUser.lastSeen] - ); - - return ( - <> - - - - - {i18n.USER} - - - {observedUser.lastSeen.date && ( - - {i18n.OBSERVED_BADGE} - - )} - - - {managedUser.lastSeen.date && ( - - {i18n.MANAGED_BADGE} - - )} - - - - - {observedUser.lastSeen.isLoading || managedUser.lastSeen.isLoading ? ( - - ) : ( - - )} - - - - - {userName} - - - - - {i18n.LAST_SEEN} - {': '} - {lastSeenDate && } - - - - - - - - - - ); -}; - -export const UserDetailsContent = ({ - userName, - contextID, - scopeId, - isDraggable = false, -}: { - userName: string; - contextID: string; - scopeId: string; - isDraggable?: boolean; -}) => { - const { to, from, isInitializing } = useGlobalTime(); - const riskScoreState = useRiskScore({ - riskEntity: RiskScoreEntity.user, - }); - const observedUser = useObservedUser(userName); - const managedUser = useManagedUser(userName); - - return ( - - {({ isLoadingAnomaliesData, anomaliesData, jobNameById }) => ( - - )} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/index.tsx index 17a1e21ceebd..4eefc6aa44f8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/index.tsx @@ -6,13 +6,9 @@ */ import React from 'react'; -import { EuiFlyoutBody, EuiSpacer, EuiButtonIcon } from '@elastic/eui'; -import { css } from '@emotion/react'; import { UserDetailsFlyout } from './user_details_flyout'; import { UserDetailsSidePanel } from './user_details_side_panel'; import type { UserDetailsProps } from './types'; -import { UserDetailsContent } from '../new_user_detail/user_details_content'; -import * as i18n from './translations'; const UserDetailsPanelComponent = ({ contextID, @@ -21,40 +17,7 @@ const UserDetailsPanelComponent = ({ handleOnClose, isFlyoutView, isDraggable, - isNewUserDetailsFlyoutEnable, }: UserDetailsProps) => { - if (isNewUserDetailsFlyoutEnable) { - return isFlyoutView ? ( - - - - ) : ( -
    - - - - -
    - ); - } - return isFlyoutView ? ( ) : ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/types.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/types.ts index 96d17c57c08f..9e1fd0a6b149 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/user_details/types.ts @@ -12,5 +12,4 @@ export interface UserDetailsProps { handleOnClose: () => void; isFlyoutView?: boolean; isDraggable?: boolean; - isNewUserDetailsFlyoutEnable?: boolean; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/column_renderer.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/column_renderer.ts index a90aef7224a9..9770f2e6f5b6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/column_renderer.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/column_renderer.ts @@ -11,9 +11,14 @@ import type { Filter } from '@kbn/es-query'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import type { ColumnHeaderOptions, RowRenderer } from '../../../../../../common/types'; import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; +import type { RenderCellValueContext } from '../../../../../detections/configurations/security_solution_detections/fetch_page_context'; export interface ColumnRenderer { - isInstance: (columnName: string, data: TimelineNonEcsData[]) => boolean; + isInstance: ( + columnName: string, + data: TimelineNonEcsData[], + context?: RenderCellValueContext + ) => boolean; renderColumn: ({ className, columnName, @@ -28,6 +33,7 @@ export interface ColumnRenderer { truncate, values, key, + context, }: { asPlainText?: boolean; className?: string; @@ -44,5 +50,6 @@ export interface ColumnRenderer { truncate?: boolean; values: string[] | null | undefined; key?: string; + context?: RenderCellValueContext; }) => React.ReactNode; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/constants.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/constants.tsx index 9308204e6931..4c3c62b5a61f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/constants.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/constants.tsx @@ -17,6 +17,7 @@ export const REFERENCE_URL_FIELD_NAME = 'reference.url'; export const EVENT_URL_FIELD_NAME = 'event.url'; export const SIGNAL_RULE_NAME_FIELD_NAME = 'kibana.alert.rule.name'; export const SIGNAL_STATUS_FIELD_NAME = 'kibana.alert.workflow_status'; +export const SIGNAL_ASSIGNEE_IDS_FIELD_NAME = 'kibana.alert.workflow_assignee_ids'; export const AGENT_STATUS_FIELD_NAME = 'agent.status'; export const QUARANTINED_PATH_FIELD_NAME = 'quarantined.path'; export const REASON_FIELD_NAME = 'kibana.alert.reason'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.ts index f94c1c610553..c6cf20dfcff8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { RenderCellValueContext } from '../../../../../detections/configurations/security_solution_detections/fetch_page_context'; import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; import type { ColumnRenderer } from './column_renderer'; @@ -15,10 +16,11 @@ const unhandledColumnRenderer = (): never => { export const getColumnRenderer = ( columnName: string, columnRenderers: ColumnRenderer[], - data: TimelineNonEcsData[] + data: TimelineNonEcsData[], + context?: RenderCellValueContext ): ColumnRenderer => { const renderer = columnRenderers.find((columnRenderer) => - columnRenderer.isInstance(columnName, data) + columnRenderer.isInstance(columnName, data, context) ); return renderer != null ? renderer : unhandledColumnRenderer(); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts index 21493967010f..a8d8ee67a415 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts @@ -18,6 +18,7 @@ import { systemRowRenderers } from './system/generic_row_renderer'; import { threatMatchRowRenderer } from './cti/threat_match_row_renderer'; import { reasonColumnRenderer } from './reason_column_renderer'; import { eventSummaryColumnRenderer } from './event_summary_column_renderer'; +import { userProfileColumnRenderer } from './user_profile_renderer'; // The row renderers are order dependent and will return the first renderer // which returns true from its isInstance call. The bottom renderers which @@ -38,6 +39,7 @@ export const defaultRowRenderers: RowRenderer[] = [ export const columnRenderers: ColumnRenderer[] = [ reasonColumnRenderer, eventSummaryColumnRenderer, + userProfileColumnRenderer, plainColumnRenderer, emptyColumnRenderer, unknownColumnRenderer, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx index 58b2a8fbbbb9..083d0651fbab 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx @@ -9,9 +9,13 @@ import React, { useCallback, useContext, useMemo } from 'react'; import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import { isString } from 'lodash/fp'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { TableId } from '@kbn/securitysolution-data-table'; +import { UserPanelKey } from '../../../../../flyout/entity_details/user_right'; +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import type { ExpandedDetailType } from '../../../../../../common/types'; -import { getScopedActions } from '../../../../../helpers'; +import { getScopedActions, isTimelineScope } from '../../../../../helpers'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { DefaultDraggable } from '../../../../../common/components/draggables'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; @@ -48,9 +52,11 @@ const UserNameComponent: React.FC = ({ }) => { const dispatch = useDispatch(); const eventContext = useContext(StatefulEventContext); + const isNewUserDetailsFlyoutEnable = useIsExperimentalFeatureEnabled('newUserDetailsFlyout'); const userName = `${value}`; - const isInTimelineContext = userName && eventContext?.timelineID; + const { openRightPanel } = useExpandableFlyoutContext(); + const openUserDetailsSidePanel = useCallback( (e) => { e.preventDefault(); @@ -58,31 +64,55 @@ const UserNameComponent: React.FC = ({ if (onClick) { onClick(); } + if (eventContext && isInTimelineContext) { const { timelineID, tabType } = eventContext; - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'userDetail', - params: { - userName, - }, - }; - const scopedActions = getScopedActions(timelineID); - if (scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: timelineID, - tabType: tabType as TimelineTabs, - }) - ); - } - if (timelineID === TimelineId.active && tabType === TimelineTabs.query) { - activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail }); + if (isNewUserDetailsFlyoutEnable && !isTimelineScope(timelineID)) { + openRightPanel({ + id: UserPanelKey, + params: { + userName, + contextID: contextId, + scopeId: TableId.alertsOnAlertsPage, + isDraggable, + }, + }); + } else { + const updatedExpandedDetail: ExpandedDetailType = { + panelView: 'userDetail', + params: { + userName, + }, + }; + const scopedActions = getScopedActions(timelineID); + if (scopedActions) { + dispatch( + scopedActions.toggleDetailPanel({ + ...updatedExpandedDetail, + id: timelineID, + tabType: tabType as TimelineTabs, + }) + ); + } + + if (timelineID === TimelineId.active && tabType === TimelineTabs.query) { + activeTimeline.toggleExpandedDetail({ ...updatedExpandedDetail }); + } } } }, - [onClick, eventContext, isInTimelineContext, userName, dispatch] + [ + onClick, + eventContext, + isNewUserDetailsFlyoutEnable, + isInTimelineContext, + openRightPanel, + userName, + contextId, + isDraggable, + dispatch, + ] ); // The below is explicitly defined this way as the onClick takes precedence when it and the href are both defined diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_profile_renderer.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_profile_renderer.tsx new file mode 100644 index 000000000000..93be8036f0ce --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_profile_renderer.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiLoadingSpinner } from '@elastic/eui'; +import React from 'react'; + +import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { UsersAvatarsPanel } from '../../../../../common/components/user_profiles/users_avatars_panel'; +import type { ColumnHeaderOptions, RowRenderer } from '../../../../../../common/types'; +import type { ColumnRenderer } from './column_renderer'; +import { profileUidColumns } from '../../../../../detections/configurations/security_solution_detections/fetch_page_context'; +import type { RenderCellValueContext } from '../../../../../detections/configurations/security_solution_detections/fetch_page_context'; + +export const userProfileColumnRenderer: ColumnRenderer = { + isInstance: (columnName, _, context) => profileUidColumns.includes(columnName) && !!context, + renderColumn: ({ + columnName, + ecsData, + eventId, + field, + isDetails, + isDraggable = true, + linkValues, + rowRenderers = [], + scopeId, + truncate, + values, + context, + }: { + columnName: string; + ecsData?: Ecs; + eventId: string; + field: ColumnHeaderOptions; + isDetails?: boolean; + isDraggable?: boolean; + linkValues?: string[] | null | undefined; + rowRenderers?: RowRenderer[]; + scopeId: string; + truncate?: boolean; + values: string[] | undefined | null; + context?: RenderCellValueContext; + }) => { + // Show spinner if loading profiles or if there are no fetched profiles yet + // Do not show the loading spinner if context is not provided at all + if (context?.isLoading) { + return ; + } + + const userProfiles = + values?.map((uid) => context?.profiles?.find((user) => uid === user.uid)) ?? []; + + return ; + }, +}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx index 3487e2770ff4..33a47bc8c069 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx @@ -76,7 +76,7 @@ describe('DefaultCellRenderer', () => {
    ); - expect(getColumnRenderer).toBeCalledWith(header.id, columnRenderers, data); + expect(getColumnRenderer).toBeCalledWith(header.id, columnRenderers, data, undefined); }); test('if in tgrid expanded value, it invokes `renderColumn` with the expected arguments', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx index 551003923a15..9e5006267d32 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx @@ -33,6 +33,7 @@ export const DefaultCellRenderer: React.FC = ({ scopeId, truncate, asPlainText, + context, }) => { const asPlainTextDefault = useMemo(() => { return ( @@ -49,7 +50,7 @@ export const DefaultCellRenderer: React.FC = ({ : 'eui-displayInlineBlock eui-textTruncate'; return ( - {getColumnRenderer(header.id, columnRenderers, data).renderColumn({ + {getColumnRenderer(header.id, columnRenderers, data, context).renderColumn({ asPlainText: asPlainText ?? asPlainTextDefault, // we want to render value with links as plain text but keep other formatters like badge. Except rule name for non preview tables columnName: header.id, ecsData, @@ -62,6 +63,7 @@ export const DefaultCellRenderer: React.FC = ({ scopeId, truncate, values, + context, })} ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx index 59c9aa8e24c0..c712c1b5c8df 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx @@ -6,10 +6,12 @@ */ import { rgba } from 'polished'; -import React, { useMemo } from 'react'; +import { useDispatch } from 'react-redux'; +import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { v4 as uuidv4 } from 'uuid'; import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid'; +import { EuiToolTip, EuiSuperSelect, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; @@ -23,13 +25,16 @@ import { timelineSelectors } from '../../../store/timeline'; import { timelineDefaults } from '../../../store/timeline/defaults'; import * as i18n from './translations'; +import { options } from '../search_or_filter/helpers'; +import type { KqlMode } from '../../../store/timeline/model'; +import { updateKqlMode } from '../../../store/timeline/actions'; interface Props { timelineId: string; } const DropTargetDataProvidersContainer = styled.div` - padding: 2px 0 4px 0; + position: relative; .${IS_DRAGGING_CLASS_NAME} & .drop-target-data-providers { background: ${({ theme }) => rgba(theme.eui.euiColorSuccess, 0.1)}; @@ -49,12 +54,11 @@ const DropTargetDataProviders = styled.div` display: flex; flex-direction: column; justify-content: flex-start; - padding-bottom: 2px; position: relative; border: 0.2rem dashed ${({ theme }) => theme.eui.euiColorMediumShade}; border-radius: 5px; - padding: ${({ theme }) => theme.eui.euiSizeXS} 0; - margin: 2px 0 2px 0; + padding: ${({ theme }) => theme.eui.euiSizeS} 0; + margin: 0px 0 0px 0; max-height: 33vh; min-height: 100px; overflow: auto; @@ -84,7 +88,24 @@ const getDroppableId = (id: string): string => * the user to drop anything with a facet count into * the data pro section. */ + +const timelineSelectModeItemsClassName = 'timelineSelectModeItemsClassName'; + +const searchOrFilterPopoverClassName = 'searchOrFilterPopover'; +const searchOrFilterPopoverWidth = 350; + +const popoverProps = { + className: searchOrFilterPopoverClassName, + panelClassName: searchOrFilterPopoverClassName, + panelMinWidth: searchOrFilterPopoverWidth, +}; + +const CustomTooltipDiv = styled.div` + position: relative; +`; + export const DataProviders = React.memo(({ timelineId }) => { + const dispatch = useDispatch(); const { browserFields } = useSourcererDataView(SourcererScopeName.timeline); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); @@ -96,28 +117,65 @@ export const DataProviders = React.memo(({ timelineId }) => { ); const droppableId = useMemo(() => getDroppableId(timelineId), [timelineId]); + const kqlMode = useDeepEqualSelector( + (state) => (getTimeline(state, timelineId) ?? timelineDefaults).kqlMode + ); + + const handleChange = useCallback( + (mode: KqlMode) => { + dispatch(updateKqlMode({ id: timelineId, kqlMode: mode })); + }, + [timelineId, dispatch] + ); + return ( - - + - {dataProviders != null && dataProviders.length ? ( - - ) : ( - - - - )} - - + + + + + + + + + + + {dataProviders != null && dataProviders.length ? ( + + ) : ( + + + + )} + + + + + ); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx index 9de471e57836..5d581a505742 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx @@ -66,8 +66,10 @@ const getItemStyle = ( const DroppableContainer = styled.div` min-height: ${ROW_OF_DATA_PROVIDERS_HEIGHT}px; height: auto !important; + display: none; .${IS_DRAGGING_CLASS_NAME} &:hover { + display: flex; background-color: ${({ theme }) => rgba(theme.eui.euiColorSuccess, 0.2)} !important; } `; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/translations.ts index 18ca62a71c6d..8733e42d2496 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/translations.ts @@ -169,3 +169,10 @@ export const GROUP_AREA_ARIA_LABEL = (group: number) => values: { group }, defaultMessage: 'You are in group {group}', }); + +export const FILTER_OR_SEARCH_WITH_KQL = i18n.translate( + 'xpack.securitySolution.timeline.searchOrFilter.filterOrSearchWithKql', + { + defaultMessage: 'Filter or Search with KQL', + } +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/date_picker_lock/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/date_picker_lock/index.tsx index c3d3db91430e..4335e0b806a1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/date_picker_lock/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/date_picker_lock/index.tsx @@ -39,8 +39,10 @@ const TimelineDatePickerLockComponent = () => { props.theme.eui.euiSizeS}; width: 100%; `; -TimelineHeaderContainer.displayName = 'TimelineHeaderContainer'; +EqlTabHeaderContainer.displayName = 'EqlTabHeaderContainer'; const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` align-items: stretch; @@ -73,8 +73,7 @@ const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` padding: 0; &.euiFlyoutHeader { - ${({ theme }) => - `padding: 0 ${theme.eui.euiSizeM} ${theme.eui.euiSizeS} ${theme.eui.euiSizeS};`} + ${({ theme }) => `padding: ${theme.eui.euiSizeS} 0 0 0;`} } `; @@ -110,6 +109,7 @@ const FullWidthFlexGroup = styled(EuiFlexGroup)` `; const ScrollableFlexItem = styled(EuiFlexItem)` + ${({ theme }) => `margin: 0 ${theme.eui.euiSizeM};`} overflow: hidden; `; @@ -260,9 +260,11 @@ export const EqlTabContentComponent: React.FC = ({ hasBorder={false} > {timelineFullScreen && setTimelineFullScreen != null && ( = ({ setFullScreen={setTimelineFullScreen} /> )} - - - - - - {activeTab === TimelineTabs.eql && ( )} + + + + + + - - - + + + = ({ timelineId }) setDiscoverStateContainer, getAppStateFromSavedSearch, updateSavedSearch, + initializeLocalSavedSearch, restoreDiscoverAppStateFromSavedSearch, resetDiscoverAppState, getDefaultDiscoverAppState, @@ -170,11 +171,6 @@ export const DiscoverTabContent: FC = ({ timelineId }) const combinedDiscoverSavedSearchStateRef = useRef(); - const debouncedUpdateSavedSearch = useMemo( - () => debounce(updateSavedSearch, 300), - [updateSavedSearch] - ); - useEffect(() => { if (isFetching) return; if (!isDiscoverSavedSearchLoaded) return; @@ -187,11 +183,10 @@ export const DiscoverTabContent: FC = ({ timelineId }) if (!index) return; if (!latestState || combinedDiscoverSavedSearchStateRef.current === latestState) return; if (isEqualWith(latestState, savedSearchById, savedSearchComparator)) return; - debouncedUpdateSavedSearch(latestState, timelineId); + updateSavedSearch(latestState, timelineId); combinedDiscoverSavedSearchStateRef.current = latestState; }, [ getCombinedDiscoverSavedSearchState, - debouncedUpdateSavedSearch, savedSearchById, updateSavedSearch, isDiscoverSavedSearchLoaded, @@ -230,6 +225,7 @@ export const DiscoverTabContent: FC = ({ timelineId }) let savedSearchAppState; if (savedSearchId) { const localSavedSearch = await savedSearchService.get(savedSearchId); + initializeLocalSavedSearch(localSavedSearch, timelineId); savedSearchAppState = getAppStateFromSavedSearch(localSavedSearch); } @@ -238,8 +234,25 @@ export const DiscoverTabContent: FC = ({ timelineId }) const finalAppState = savedSearchAppState?.appState ?? discoverAppState ?? defaultDiscoverAppState; - stateContainer.appState.set(finalAppState); - await stateContainer.appState.replaceUrlState(finalAppState); + const urlAppState = stateContainer.appState.isEmptyURL() + ? undefined + : stateContainer.appState.getState(); + + const hasESQLURlState = urlAppState?.query && 'esql' in urlAppState.query; + + /* + * Url state should NOT apply if there is already a saved search being loaded + * */ + const shouldApplyESQLUrlState = !savedSearchAppState?.appState && hasESQLURlState; + + if (!shouldApplyESQLUrlState) { + /* + * If url state applies, it should be a no-op and there is no need to update the state container. + * Discover should automatically pick up url state + * */ + stateContainer.appState.set(finalAppState); + await stateContainer.appState.replaceUrlState(finalAppState); + } const unsubscribeState = stateContainer.appState.state$.subscribe({ next: setDiscoverAppState, @@ -282,6 +295,8 @@ export const DiscoverTabContent: FC = ({ timelineId }) savedSearchId, savedSearchService, getDefaultDiscoverAppState, + timelineId, + initializeLocalSavedSearch, ] ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.test.ts index 3b25737b2527..bc7cb3e2f8a0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.test.ts @@ -14,57 +14,32 @@ const customQuery = { query: '_id: *', }; -const firstDataViewMock = buildDataViewMock({ +const dataViewMock = buildDataViewMock({ name: 'first-data-view', fields: shallowMockedFields, }); -const secondDataViewMock = buildDataViewMock({ - name: 'second-data-view', - fields: shallowMockedFields, -}); - describe('savedSearchComparator', () => { - const firstMockSavedSearch = { + const mockSavedSearch = { id: 'first', title: 'first title', breakdownField: 'firstBreakdown Field', searchSource: createSearchSourceMock({ - index: firstDataViewMock, + index: dataViewMock, query: customQuery, }), }; - const secondMockSavedSearch = { - id: 'second', - title: 'second title', - breakdownField: 'second Breakdown Field', - searchSource: createSearchSourceMock({ - index: secondDataViewMock, - query: customQuery, - }), - }; it('should result true when saved search is same', () => { - const result = savedSearchComparator(firstMockSavedSearch, { ...firstMockSavedSearch }); + const result = savedSearchComparator(mockSavedSearch, { ...mockSavedSearch }); expect(result).toBe(true); }); - it('should return false index is different', () => { - const newMockedSavedSearch = { - ...firstMockSavedSearch, - searchSource: secondMockSavedSearch.searchSource, - }; - - const result = savedSearchComparator(firstMockSavedSearch, newMockedSavedSearch); - - expect(result).toBe(false); - }); - it('should return false when query is different', () => { const newMockedSavedSearch = { - ...firstMockSavedSearch, + ...mockSavedSearch, searchSource: createSearchSourceMock({ - index: firstDataViewMock, + index: dataViewMock, query: { ...customQuery, query: '*', @@ -72,17 +47,17 @@ describe('savedSearchComparator', () => { }), }; - const result = savedSearchComparator(firstMockSavedSearch, newMockedSavedSearch); + const result = savedSearchComparator(mockSavedSearch, newMockedSavedSearch); expect(result).toBe(false); }); it('should result false when title is different', () => { const newMockedSavedSearch = { - ...firstMockSavedSearch, + ...mockSavedSearch, title: 'new-title', }; - const result = savedSearchComparator(firstMockSavedSearch, newMockedSavedSearch); + const result = savedSearchComparator(mockSavedSearch, newMockedSavedSearch); expect(result).toBe(false); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.ts index 26340c12add5..1f908f5a5fe6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/utils/index.ts @@ -29,7 +29,6 @@ export const savedSearchComparator = ( 'sort', 'timeRange', 'fields.filter', - 'fields.index.id', 'fields.query', 'title', 'description', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/__snapshots__/index.test.tsx.snap deleted file mode 100644 index c5494c676118..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Header rendering renders correctly against snapshot 1`] = ` - - - - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx deleted file mode 100644 index 8ce39f9b535d..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.test.tsx +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; -import React from 'react'; - -import { coreMock } from '@kbn/core/public/mocks'; -import { mockIndexPattern } from '../../../../common/mock'; -import { TestProviders } from '../../../../common/mock/test_providers'; -import { FilterManager } from '@kbn/data-plugin/public'; -import { mockDataProviders } from '../data_providers/mock/mock_data_providers'; -import { useMountAppended } from '../../../../common/utils/use_mount_appended'; - -import { TimelineHeader } from '.'; -import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; -import { waitFor } from '@testing-library/react'; - -const mockUiSettingsForFilterManager = coreMock.createStart().uiSettings; - -jest.mock('../../../../common/lib/kibana'); - -describe('Header', () => { - const indexPattern = mockIndexPattern; - const mount = useMountAppended(); - const getWrapper = async (childrenComponent: JSX.Element) => { - const wrapper = mount(childrenComponent); - await waitFor(() => wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()); - return wrapper; - }; - const props = { - browserFields: {}, - dataProviders: mockDataProviders, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - indexPattern, - onDataProviderEdited: jest.fn(), - onDataProviderRemoved: jest.fn(), - onToggleDataProviderEnabled: jest.fn(), - onToggleDataProviderExcluded: jest.fn(), - onToggleDataProviderType: jest.fn(), - show: true, - showCallOutUnauthorizedMsg: false, - status: TimelineStatus.active, - timelineId: 'foo', - timelineType: TimelineType.default, - }; - - describe('rendering', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - - test('it renders the data providers when show is true', async () => { - const testProps = { ...props, show: true }; - const wrapper = await getWrapper( - - - - ); - - expect(wrapper.find('[data-test-subj="dataProviders"]').exists()).toEqual(true); - }); - - test('it renders the unauthorized call out providers', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: true, - }; - - const wrapper = await getWrapper( - - - - ); - - expect(wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()).toEqual(true); - }); - - test('it renders the unauthorized call out with correct icon', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: true, - }; - - const wrapper = await getWrapper( - - - - ); - - expect( - wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').first().prop('iconType') - ).toEqual('warning'); - }); - - test('it renders the unauthorized call out with correct message', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: true, - }; - - const wrapper = await getWrapper( - - - - ); - - expect( - wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').first().prop('title') - ).toEqual( - 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.' - ); - }); - - test('it renders the immutable timeline call out providers', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: false, - status: TimelineStatus.immutable, - }; - - const wrapper = await getWrapper( - - - - ); - - expect(wrapper.find('[data-test-subj="timelineImmutableCallOut"]').exists()).toEqual(true); - }); - - test('it renders the immutable timeline call out with correct icon', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: false, - status: TimelineStatus.immutable, - }; - - const wrapper = await getWrapper( - - - - ); - - expect( - wrapper.find('[data-test-subj="timelineImmutableCallOut"]').first().prop('iconType') - ).toEqual('warning'); - }); - - test('it renders the immutable timeline call out with correct message', async () => { - const testProps = { - ...props, - filterManager: new FilterManager(mockUiSettingsForFilterManager), - showCallOutUnauthorizedMsg: false, - status: TimelineStatus.immutable, - }; - - const wrapper = await getWrapper( - - - - ); - - expect( - wrapper.find('[data-test-subj="timelineImmutableCallOut"]').first().prop('title') - ).toEqual( - 'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.' - ); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx deleted file mode 100644 index 56936c1840ba..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiCallOut } from '@elastic/eui'; -import React from 'react'; -import type { FilterManager } from '@kbn/data-plugin/public'; - -import { DataProviders } from '../data_providers'; -import { StatefulSearchOrFilter } from '../search_or_filter'; - -import * as i18n from './translations'; -import type { TimelineStatusLiteralWithNull } from '../../../../../common/api/timeline'; -import { TimelineStatus } from '../../../../../common/api/timeline'; - -interface Props { - filterManager: FilterManager; - show: boolean; - showCallOutUnauthorizedMsg: boolean; - status: TimelineStatusLiteralWithNull; - timelineId: string; -} - -const TimelineHeaderComponent: React.FC = ({ - filterManager, - show, - showCallOutUnauthorizedMsg, - status, - timelineId, -}) => ( - <> - {showCallOutUnauthorizedMsg && ( - - )} - {status === TimelineStatus.immutable && ( - - )} - {show && } - - - -); - -export const TimelineHeader = React.memo(TimelineHeaderComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/timeline_save_prompt.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/timeline_save_prompt.tsx deleted file mode 100644 index fdf3e453c8f6..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/timeline_save_prompt.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useMemo } from 'react'; -import { useDispatch } from 'react-redux'; -import { useUserPrivileges } from '../../../../common/components/user_privileges'; - -import { TimelineId } from '../../../../../common/types/timeline'; -import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; -import { timelineActions } from '../../../store/timeline'; -import { getTimelineSaveModalByIdSelector } from './selectors'; -import { SaveTimelineModal } from './save_timeline_modal'; -import { TimelineStatus } from '../../../../../common/api/timeline'; - -interface TimelineSavePromptProps { - timelineId: string; -} - -/** - * Displays the edit timeline modal with a warning that unsaved changes might get lost. - * The modal is rendered based on a flag that is set in Redux, in other words, this component - * only renders the modal when the flag is triggered from outside this component. - */ -export const TimelineSavePrompt = React.memo(({ timelineId }) => { - const dispatch = useDispatch(); - const getTimelineSaveModal = useMemo(() => getTimelineSaveModalByIdSelector(), []); - const { showSaveModal: forceShow, status } = useDeepEqualSelector((state) => - getTimelineSaveModal(state, timelineId) - ); - const isUnsaved = status === TimelineStatus.draft; - - const closeSaveTimeline = useCallback(() => { - dispatch( - timelineActions.toggleModalSaveTimeline({ - id: TimelineId.active, - showModalSaveTimeline: false, - }) - ); - }, [dispatch]); - - const { - kibanaSecuritySolutionsPrivileges: { crud: hasKibanaCrud }, - } = useUserPrivileges(); - - return forceShow && hasKibanaCrud ? ( - - ) : null; -}); - -TimelineSavePrompt.displayName = 'TimelineSavePrompt'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/translations.ts deleted file mode 100644 index 83017597861a..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/translations.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import type { TimelineTypeLiteral } from '../../../../../common/api/timeline'; -import { TimelineType } from '../../../../../common/api/timeline'; - -export const CALL_OUT_UNAUTHORIZED_MSG = i18n.translate( - 'xpack.securitySolution.timeline.callOut.unauthorized.message.description', - { - defaultMessage: - 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.', - } -); - -export const CALL_OUT_IMMUTABLE = i18n.translate( - 'xpack.securitySolution.timeline.callOut.immutable.message.description', - { - defaultMessage: - 'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.', - } -); - -export const SAVE_TIMELINE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.header', - { - defaultMessage: 'Save Timeline', - } -); - -export const SAVE_TIMELINE_TEMPLATE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimelineTemplate.modal.header', - { - defaultMessage: 'Save Timeline Template', - } -); - -export const SAVE = i18n.translate('xpack.securitySolution.timeline.nameTimeline.save.title', { - defaultMessage: 'Save', -}); - -export const NAME_TIMELINE_TEMPLATE = i18n.translate( - 'xpack.securitySolution.timeline.nameTimelineTemplate.modal.header', - { - defaultMessage: 'Name Timeline Template', - } -); - -export const DISCARD_TIMELINE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.discard.title', - { - defaultMessage: 'Discard Timeline', - } -); - -export const DISCARD_TIMELINE_TEMPLATE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimelineTemplate.modal.discard.title', - { - defaultMessage: 'Discard Timeline Template', - } -); - -export const CLOSE_MODAL = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.close.title', - { - defaultMessage: 'Close', - } -); - -export const UNSAVED_TIMELINE_WARNING = (timelineType: TimelineTypeLiteral) => - i18n.translate('xpack.securitySolution.timeline.saveTimeline.modal.warning.title', { - values: { - timeline: timelineType === TimelineType.template ? 'timeline template' : 'timeline', - }, - defaultMessage: 'You have an unsaved {timeline}. Do you wish to save it?', - }); - -export const TITLE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.titleTitle', - { - defaultMessage: 'Title', - } -); - -export const TIMELINE_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.titleAriaLabel', - { - defaultMessage: 'Title', - } -); - -export const TIMELINE_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.descriptionLabel', - { - defaultMessage: 'Description', - } -); - -export const OPTIONAL = i18n.translate( - 'xpack.securitySolution.timeline.saveTimeline.modal.optionalLabel', - { - defaultMessage: 'Optional', - } -); - -export const SAVE_TOUR_CLOSE = i18n.translate( - 'xpack.securitySolution.timeline.flyout.saveTour.closeButton', - { - defaultMessage: 'Close', - } -); - -export const SAVE_TOUR_TITLE = i18n.translate( - 'xpack.securitySolution.timeline.flyout.saveTour.title', - { - defaultMessage: 'Timeline changes now require manual saves', - } -); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx index ce03812e58fc..7928a93dc488 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx @@ -32,7 +32,6 @@ import { defaultRowRenderers } from './body/renderers'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { createStore } from '../../../common/store'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; -import { useGetUserCasesPermissions } from '../../../common/lib/kibana'; jest.mock('../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -43,12 +42,6 @@ jest.mock('./tabs_content', () => ({ })); jest.mock('../../../common/lib/kibana'); -const originalKibanaLib = jest.requireActual('../../../common/lib/kibana'); - -// Restore the useGetUserCasesPermissions so the calling functions can receive a valid permissions object -// The returned permissions object will indicate that the user does not have permissions by default -const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; -mockUseGetUserCasesPermissions.mockImplementation(originalKibanaLib.useGetUserCasesPermissions); jest.mock('../../../common/utils/normalize_time_range'); jest.mock('@kbn/i18n-react', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx index 1bbeb32ae0e8..a78747e8cb32 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx @@ -17,7 +17,7 @@ import { timelineDefaults } from '../../store/timeline/defaults'; import { defaultHeaders } from './body/column_headers/default_headers'; import type { CellValueElementProps } from './cell_rendering'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; -import { FlyoutHeader, FlyoutHeaderPanel } from '../flyout/header'; +import { FlyoutHeaderPanel } from '../flyout/header'; import type { TimelineId, RowRenderer } from '../../../../common/types/timeline'; import { TimelineType } from '../../../../common/api/timeline'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; @@ -192,28 +192,31 @@ const StatefulTimelineComponent: React.FC = ({ ref={containerElement} > - {timelineType === TimelineType.template && ( - {i18n.TIMELINE_TEMPLATE} - )} - {resolveConflictComponent} - - - - - - +
    + {timelineType === TimelineType.template && ( + + {i18n.TIMELINE_TEMPLATE} + + )} + {resolveConflictComponent} + + + + + +
    ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.test.tsx new file mode 100644 index 000000000000..1d91e828524c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.test.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen, render } from '@testing-library/react'; +import { TestProviders } from '../../../../common/mock'; +import { useTimelineKpis } from '../../../containers/kpis'; +import { TimelineKpi } from '.'; +import { TimelineId } from '../../../../../common/types'; +import { getEmptyValue } from '../../../../common/components/empty_value'; + +jest.mock('../../../containers/kpis', () => ({ + useTimelineKpis: jest.fn(), +})); + +jest.mock('../../../../common/lib/kibana'); + +jest.mock('@kbn/i18n-react', () => { + const originalModule = jest.requireActual('@kbn/i18n-react'); + const FormattedRelative = jest.fn().mockImplementation(() => '20 hours ago'); + + return { + ...originalModule, + FormattedRelative, + }; +}); + +const mockUseTimelineKpis: jest.Mock = useTimelineKpis as jest.Mock; + +const mockUseTimelineKpiResponse = { + processCount: 1, + userCount: 1, + sourceIpCount: 1, + hostCount: 1, + destinationIpCount: 1, +}; + +const mockUseTimelineLargeKpiResponse = { + processCount: 1000, + userCount: 1000000, + sourceIpCount: 1000000000, + hostCount: 999, + destinationIpCount: 1, +}; + +describe('Timeline KPIs', () => { + describe('when the data is not loading and the response contains data', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineKpiResponse]); + }); + it('renders the component, labels and values successfully', () => { + render( + + + + ); + expect(screen.getByTestId('siem-timeline-kpis')).toBeInTheDocument(); + // label + expect(screen.getByText('Processes :')).toBeInTheDocument(); + // value + expect(screen.getByTestId('siem-timeline-process-kpi').textContent).toContain('1'); + }); + }); + + describe('when the response is null and timeline is blank', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, null]); + }); + it('renders labels and the default empty string', () => { + render( + + + + ); + expect(screen.getByText('Processes :')).toBeInTheDocument(); + expect(screen.getAllByText(getEmptyValue())).not.toHaveLength(0); + }); + }); + + describe('when the response contains numbers larger than one thousand', () => { + beforeEach(() => { + mockUseTimelineKpis.mockReturnValue([false, mockUseTimelineLargeKpiResponse]); + }); + it('formats the numbers correctly', () => { + render( + + + + ); + expect(screen.getByTitle('1k')).toBeInTheDocument(); + expect(screen.getByTitle('1m')).toBeInTheDocument(); + expect(screen.getByTitle('1b')).toBeInTheDocument(); + expect(screen.getByTitle('999')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.tsx new file mode 100644 index 000000000000..a0ebf4d5408f --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { TimelineKpisContainer as TimelineKpi } from './kpi_container'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx new file mode 100644 index 000000000000..31eb9ad5e5e5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { isEmpty, pick } from 'lodash/fp'; +import { useSelector } from 'react-redux'; +import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import type { TimerangeInput } from '@kbn/timelines-plugin/common'; +import { EuiPanel } from '@elastic/eui'; +import { TimelineId } from '../../../../../common/types'; +import { useSourcererDataView } from '../../../../common/containers/sourcerer'; +import type { State } from '../../../../common/store'; +import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; +import { TimelineKPIs } from './kpis'; +import { useTimelineKpis } from '../../../containers/kpis'; +import { useKibana } from '../../../../common/lib/kibana'; +import { timelineSelectors } from '../../../store/timeline'; +import { timelineDefaults } from '../../../store/timeline/defaults'; +import { combineQueries } from '../../../../common/lib/kuery'; +import { + endSelector, + startSelector, +} from '../../../../common/components/super_date_picker/selectors'; + +interface KpiExpandedProps { + timelineId: string; +} + +export const TimelineKpisContainer = ({ timelineId }: KpiExpandedProps) => { + const { browserFields, indexPattern, selectedPatterns } = useSourcererDataView( + SourcererScopeName.timeline + ); + + const { uiSettings } = useKibana().services; + const esQueryConfig = useMemo(() => getEsQueryConfig(uiSettings), [uiSettings]); + const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); + const { dataProviders, filters, kqlMode } = useDeepEqualSelector((state) => + pick( + ['dataProviders', 'filters', 'kqlMode'], + getTimeline(state, timelineId) ?? timelineDefaults + ) + ); + + const getKqlQueryTimeline = useMemo(() => timelineSelectors.getKqlFilterQuerySelector(), []); + + const kqlQueryTimeline = useSelector((state: State) => getKqlQueryTimeline(state, timelineId)); + + const kqlQueryExpression = kqlQueryTimeline ?? ' '; + + const kqlQuery = useMemo( + () => ({ query: kqlQueryExpression, language: 'kuery' }), + [kqlQueryExpression] + ); + + const isActive = useMemo(() => timelineId === TimelineId.active, [timelineId]); + const getStartSelector = useMemo(() => startSelector(), []); + const getEndSelector = useMemo(() => endSelector(), []); + + const timerange: TimerangeInput = useDeepEqualSelector((state) => { + if (isActive) { + return { + from: getStartSelector(state.inputs.timeline), + to: getEndSelector(state.inputs.timeline), + interval: '', + }; + } else { + return { + from: getStartSelector(state.inputs.global), + to: getEndSelector(state.inputs.global), + interval: '', + }; + } + }); + + const combinedQueries = useMemo( + () => + combineQueries({ + config: esQueryConfig, + dataProviders, + indexPattern, + browserFields, + filters: filters ? filters : [], + kqlQuery, + kqlMode, + }), + [browserFields, dataProviders, esQueryConfig, filters, indexPattern, kqlMode, kqlQuery] + ); + + const isBlankTimeline: boolean = useMemo( + () => + (isEmpty(dataProviders) && isEmpty(filters) && isEmpty(kqlQuery.query)) || + combinedQueries?.filterQuery === undefined, + [dataProviders, filters, kqlQuery, combinedQueries] + ); + + const [, kpis] = useTimelineKpis({ + defaultIndex: selectedPatterns, + timerange, + isBlankTimeline, + filterQuery: combinedQueries?.filterQuery ?? '', + }); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpis.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpis.tsx new file mode 100644 index 000000000000..9fde146b4ed4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpis.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +import { EuiFlexItem, EuiFlexGroup, EuiToolTip, EuiBadge } from '@elastic/eui'; +import numeral from '@elastic/numeral'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; +import { useUiSetting$ } from '../../../../common/lib/kibana'; +import type { TimelineKpiStrategyResponse } from '../../../../../common/search_strategy'; +import { getEmptyValue } from '../../../../common/components/empty_value'; +import * as i18n from './translations'; + +export const StatsContainer = styled.span` + font-size: ${euiThemeVars.euiFontSizeXS}; + font-weight: ${euiThemeVars.euiFontWeightSemiBold}; + padding-right: 16px; + .smallDot { + width: 3px !important; + display: inline-block; + } + .euiBadge__text { + text-align: center; + width: 100%; + } +`; + +export const TimelineKPIs = React.memo(({ kpis }: { kpis: TimelineKpiStrategyResponse | null }) => { + const kpiFormat = '0,0.[000]a'; + const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); + const formattedKpis = useMemo(() => { + return { + process: kpis === null ? getEmptyValue() : numeral(kpis.processCount).format(kpiFormat), + user: kpis === null ? getEmptyValue() : numeral(kpis.userCount).format(kpiFormat), + host: kpis === null ? getEmptyValue() : numeral(kpis.hostCount).format(kpiFormat), + sourceIp: kpis === null ? getEmptyValue() : numeral(kpis.sourceIpCount).format(kpiFormat), + destinationIp: + kpis === null ? getEmptyValue() : numeral(kpis.destinationIpCount).format(kpiFormat), + }; + }, [kpis]); + + const formattedKpiToolTips = useMemo(() => { + return { + process: numeral(kpis?.processCount).format(defaultNumberFormat), + user: numeral(kpis?.userCount).format(defaultNumberFormat), + host: numeral(kpis?.hostCount).format(defaultNumberFormat), + sourceIp: numeral(kpis?.sourceIpCount).format(defaultNumberFormat), + destinationIp: numeral(kpis?.destinationIpCount).format(defaultNumberFormat), + }; + }, [kpis, defaultNumberFormat]); + + return ( + + + + {`${i18n.PROCESS_KPI_TITLE} : `} + + + {formattedKpis.process} + + + + + + + {`${i18n.USER_KPI_TITLE} : `} + + + {formattedKpis.user} + + + + + + + {`${i18n.HOST_KPI_TITLE} : `} + + + {formattedKpis.host} + + + + + + + {`${i18n.SOURCE_IP_KPI_TITLE} : `} + + + {formattedKpis.sourceIp} + + + + + + + {`${i18n.DESTINATION_IP_KPI_TITLE} : `} + + + {formattedKpis.destinationIp} + + + + + + ); +}); + +TimelineKPIs.displayName = 'TimelineKPIs'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/translations.ts new file mode 100644 index 000000000000..177516ea4a68 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/translations.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const PROCESS_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.processKpiTitle', + { + defaultMessage: 'Processes', + } +); + +export const HOST_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.hostKpiTitle', { + defaultMessage: 'Hosts', +}); + +export const SOURCE_IP_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.sourceIpKpiTitle', + { + defaultMessage: 'Source IPs', + } +); + +export const DESTINATION_IP_KPI_TITLE = i18n.translate( + 'xpack.securitySolution.timeline.kpis.destinationKpiTitle', + { + defaultMessage: 'Destination IPs', + } +); + +export const USER_KPI_TITLE = i18n.translate('xpack.securitySolution.timeline.kpis.userKpiTitle', { + defaultMessage: 'Users', +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx index d43f92fc96e6..963713a2317a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx @@ -21,6 +21,7 @@ import React, { Fragment, useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import type { EuiTheme } from '@kbn/react-kibana-context-styled'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { timelineActions } from '../../../store/timeline'; @@ -51,6 +52,8 @@ const FullWidthFlexGroup = styled(EuiFlexGroup)` const ScrollableFlexItem = styled(EuiFlexItem)` overflow-x: hidden; overflow-y: auto; + padding-inline: ${({ theme }) => (theme as EuiTheme).eui.euiSizeM}; + padding-block: ${({ theme }) => (theme as EuiTheme).eui.euiSizeS}; `; const VerticalRule = styled.div` @@ -202,7 +205,6 @@ const NotesTabContentComponent: React.FC = ({ timelineId } <> {createdBy && ( <> -

    {CREATED_BY}

    @@ -218,13 +220,12 @@ const NotesTabContentComponent: React.FC = ({ timelineId } ); return ( - + - +

    {NOTES}

    - { const mockGetButton = jest.fn().mockReturnValue('<>'); const props: NewTimelineProps = { - closeGearMenu: jest.fn(), + onClick: jest.fn(), timelineId: 'mockTimelineId', title: 'mockTitle', }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx index 1ac4947b5ada..0330e3ed74d5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx @@ -27,9 +27,13 @@ NotesCountBadge.displayName = 'NotesCountBadge'; interface AddToFavoritesButtonProps { timelineId: string; + compact?: boolean; } -const AddToFavoritesButtonComponent: React.FC = ({ timelineId }) => { +const AddToFavoritesButtonComponent: React.FC = ({ + timelineId, + compact, +}) => { const dispatch = useDispatch(); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); @@ -48,7 +52,19 @@ const AddToFavoritesButtonComponent: React.FC = ({ ti [dispatch, timelineId, isFavorite] ); - return ( + const label = isFavorite ? i18n.REMOVE_FROM_FAVORITES : i18n.ADD_TO_FAVORITES; + + return compact ? ( + + ) : ( = ({ ti onClick={handleClick} data-test-subj={`timeline-favorite-${isFavorite ? 'filled' : 'empty'}-star`} disabled={disableFavoriteButton} + aria-label={label} + title={label} > - {isFavorite ? i18n.REMOVE_FROM_FAVORITES : i18n.ADD_TO_FAVORITES} + {label} ); }; @@ -66,18 +84,18 @@ AddToFavoritesButtonComponent.displayName = 'AddToFavoritesButtonComponent'; export const AddToFavoritesButton = React.memo(AddToFavoritesButtonComponent); export interface NewTimelineProps { - closeGearMenu?: () => void; + onClick?: () => void; outline?: boolean; timelineId: string; title?: string; } export const NewTimeline = React.memo( - ({ closeGearMenu, outline = false, timelineId, title = i18n.NEW_TIMELINE }) => { + ({ onClick, outline = false, timelineId, title = i18n.NEW_TIMELINE }) => { const { getButton } = useCreateTimelineButton({ timelineId, timelineType: TimelineType.default, - closeGearMenu, + onClick, }); const button = getButton({ outline, title }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx index ac69b86ec580..10ad06c17d5b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.test.tsx @@ -55,7 +55,7 @@ describe('NewTemplateTimeline', () => { wrapper = mount( - + ); }); @@ -92,7 +92,7 @@ describe('NewTemplateTimeline', () => { wrapper = mount( - + ); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.tsx index 4cdef0f843df..3d79fdbf031b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/new_template_timeline.tsx @@ -13,14 +13,14 @@ import { TimelineType } from '../../../../../common/api/timeline'; import { useCreateTimelineButton } from './use_create_timeline'; interface OwnProps { - closeGearMenu?: () => void; + onClick?: () => void; outline?: boolean; title?: string; timelineId?: string; } export const NewTemplateTimelineComponent: React.FC = ({ - closeGearMenu, + onClick, outline, title, timelineId = TimelineId.active, @@ -28,7 +28,7 @@ export const NewTemplateTimelineComponent: React.FC = ({ const { getButton } = useCreateTimelineButton({ timelineId, timelineType: TimelineType.template, - closeGearMenu, + onClick, }); const button = getButton({ outline, title }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx index 5fc94a2bf99c..0693901bf211 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx @@ -27,7 +27,7 @@ import { useDiscoverInTimelineContext } from '../../../../common/components/disc interface Props { timelineId?: string; timelineType: TimelineTypeLiteral; - closeGearMenu?: () => void; + onClick?: () => void; timeRange?: TimeRange; } @@ -35,7 +35,7 @@ interface Props { * Creates a new empty timeline at the given id. * Can be used to create new timelines or to reset timeline state. */ -export const useCreateTimeline = ({ timelineId, timelineType, closeGearMenu }: Props) => { +export const useCreateTimeline = ({ timelineId, timelineType, onClick }: Props) => { const dispatch = useDispatch(); const defaultDataViewSelector = useMemo(() => sourcererSelectors.defaultDataViewSelector(), []); const { id: dataViewId, patternList: selectedPatterns } = @@ -109,12 +109,12 @@ export const useCreateTimeline = ({ timelineId, timelineType, closeGearMenu }: P const handleCreateNewTimeline = useCallback( (options?: CreateNewTimelineOptions) => { createTimeline({ id: timelineId, show: true, timelineType, timeRange: options?.timeRange }); - if (typeof closeGearMenu === 'function') { - closeGearMenu(); + if (typeof onClick === 'function') { + onClick(); } resetDiscoverAppState(); }, - [createTimeline, timelineId, timelineType, closeGearMenu, resetDiscoverAppState] + [createTimeline, timelineId, timelineType, onClick, resetDiscoverAppState] ); return handleCreateNewTimeline; @@ -124,11 +124,11 @@ interface CreateNewTimelineOptions { timeRange?: TimeRange; } -export const useCreateTimelineButton = ({ timelineId, timelineType, closeGearMenu }: Props) => { +export const useCreateTimelineButton = ({ timelineId, timelineType, onClick }: Props) => { const handleCreateNewTimeline = useCreateTimeline({ timelineId, timelineType, - closeGearMenu, + onClick, }); const getButton = useCallback( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx index 4abc4919721b..e1e732b32e47 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx @@ -14,6 +14,7 @@ import deepEqual from 'fast-deep-equal'; import type { Filter, Query } from '@kbn/es-query'; import { FilterStateStore } from '@kbn/es-query'; import type { FilterManager, SavedQuery, SavedQueryTimeFilter } from '@kbn/data-plugin/public'; +import styled from '@emotion/styled'; import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; @@ -47,6 +48,42 @@ export interface QueryBarTimelineComponentProps { updateReduxTime: DispatchUpdateReduxTime; } +const SearchBarContainer = styled.div` + /* + * + * hide search bar default filters as they are disturbing the layout as shown below + * + * Filters are displayed with QueryBar so below is how is the layout with default filters. + * + * + * -------------------------------- + * -----------------| |------------ + * | DataViewPicker | QueryBar | Date | + * ------------------------------------------------------------- + * | Filters | + * -------------------------------- + * + * The tree under this component makes sure that default filters are not rendered and we can separately display + * them outside query component so that layout is as below: + * + * ----------------------------------------------------------- + * | DataViewPicker | QueryBar | Date | + * ----------------------------------------------------------- + * | Filters | + * ----------------------------------------------------------- + * + * */ + .uniSearchBar .filter-items-group { + display: none; + } + + .euiDataGrid__restrictBody & { + .kbnQueryBar { + display: flex; + } + } +`; + export const TIMELINE_FILTER_DROP_AREA = 'timeline-filter-drop-area'; const getNonDropAreaFilters = (filters: Filter[] = []) => @@ -265,22 +302,24 @@ export const QueryBarTimeline = memo( ); return ( - + + + ); } ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.test.tsx new file mode 100644 index 000000000000..44d2ee6cd6a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.test.tsx @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { coreMock } from '@kbn/core/public/mocks'; +import { mockIndexPattern } from '../../../../../common/mock'; +import { TestProviders } from '../../../../../common/mock/test_providers'; +import { FilterManager } from '@kbn/data-plugin/public'; +import { mockDataProviders } from '../../data_providers/mock/mock_data_providers'; +import { useMountAppended } from '../../../../../common/utils/use_mount_appended'; + +import { QueryTabHeader } from '.'; +import { TimelineStatus, TimelineType } from '../../../../../../common/api/timeline'; +import { waitFor } from '@testing-library/react'; +import { TimelineId } from '../../../../../../common/types'; + +const mockUiSettingsForFilterManager = coreMock.createStart().uiSettings; + +jest.mock('../../../../../common/lib/kibana'); + +describe('Header', () => { + const indexPattern = mockIndexPattern; + const mount = useMountAppended(); + const getWrapper = async (childrenComponent: JSX.Element) => { + const wrapper = mount(childrenComponent); + await waitFor(() => wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()); + return wrapper; + }; + const props = { + browserFields: {}, + dataProviders: mockDataProviders, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + indexPattern, + onDataProviderEdited: jest.fn(), + onDataProviderRemoved: jest.fn(), + onToggleDataProviderEnabled: jest.fn(), + onToggleDataProviderExcluded: jest.fn(), + onToggleDataProviderType: jest.fn(), + show: true, + showCallOutUnauthorizedMsg: false, + status: TimelineStatus.active, + timelineId: TimelineId.test, + timelineType: TimelineType.default, + }; + + describe('rendering', () => { + test('it renders the data providers when show is true', async () => { + const testProps = { ...props, show: true }; + const wrapper = await getWrapper( + + + + ); + + expect(wrapper.find('[data-test-subj="dataProviders"]').exists()).toEqual(true); + }); + + test('it renders the unauthorized call out providers', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: true, + }; + + const wrapper = await getWrapper( + + + + ); + + expect(wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').exists()).toEqual(true); + }); + + test('it renders the unauthorized call out with correct icon', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: true, + }; + + const wrapper = await getWrapper( + + + + ); + + expect( + wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').first().prop('iconType') + ).toEqual('warning'); + }); + + test('it renders the unauthorized call out with correct message', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: true, + }; + + const wrapper = await getWrapper( + + + + ); + + expect( + wrapper.find('[data-test-subj="timelineCallOutUnauthorized"]').first().prop('title') + ).toEqual( + 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.' + ); + }); + + test('it renders the immutable timeline call out providers', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: false, + status: TimelineStatus.immutable, + }; + + const wrapper = await getWrapper( + + + + ); + + expect(wrapper.find('[data-test-subj="timelineImmutableCallOut"]').exists()).toEqual(true); + }); + + test('it renders the immutable timeline call out with correct icon', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: false, + status: TimelineStatus.immutable, + }; + + const wrapper = await getWrapper( + + + + ); + + expect( + wrapper.find('[data-test-subj="timelineImmutableCallOut"]').first().prop('iconType') + ).toEqual('warning'); + }); + + test('it renders the immutable timeline call out with correct message', async () => { + const testProps = { + ...props, + filterManager: new FilterManager(mockUiSettingsForFilterManager), + showCallOutUnauthorizedMsg: false, + status: TimelineStatus.immutable, + }; + + const wrapper = await getWrapper( + + + + ); + + expect( + wrapper.find('[data-test-subj="timelineImmutableCallOut"]').first().prop('title') + ).toEqual( + 'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.' + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx new file mode 100644 index 000000000000..8d70c3e4d44c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import type { FilterManager } from '@kbn/data-plugin/public'; + +import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid'; +import styled from '@emotion/styled'; +import { euiThemeVars } from '@kbn/ui-theme'; + +import type { TimelineStatusLiteralWithNull } from '../../../../../../common/api/timeline'; +import { TimelineStatus, TimelineType } from '../../../../../../common/api/timeline'; +import { timelineSelectors } from '../../../../store/timeline'; +import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; +import { timelineDefaults } from '../../../../store/timeline/defaults'; +import * as i18n from './translations'; +import { StatefulSearchOrFilter } from '../../search_or_filter'; +import { DataProviders } from '../../data_providers'; + +interface Props { + filterManager: FilterManager; + show: boolean; + showCallOutUnauthorizedMsg: boolean; + status: TimelineStatusLiteralWithNull; + timelineId: string; +} + +const DataProvidersContainer = styled.div<{ $shouldShowQueryBuilder: boolean }>` + position: relative; + width: 100%; + transition: 0.5s ease-in-out; + overflow: hidden; + + ${(props) => + props.$shouldShowQueryBuilder + ? `display: block; max-height: 300px; visibility: visible; margin-block-start: 0px;` + : `display: block; max-height: 0px; visibility: hidden; margin-block-start:-${euiThemeVars.euiSizeS};`} + + .${IS_DRAGGING_CLASS_NAME} & { + display: block; + max-height: 300px; + visibility: visible; + margin-block-start: 0px; + } +`; + +const QueryTabHeaderComponent: React.FC = ({ + filterManager, + show, + showCallOutUnauthorizedMsg, + status, + timelineId, +}) => { + const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); + + const getIsDataProviderVisible = useMemo( + () => timelineSelectors.dataProviderVisibilitySelector(), + [] + ); + + const timelineType = useDeepEqualSelector( + (state) => (getTimeline(state, timelineId) ?? timelineDefaults).timelineType + ); + + const isDataProviderVisible = useDeepEqualSelector( + (state) => getIsDataProviderVisible(state, timelineId) ?? timelineDefaults.isDataProviderVisible + ); + + const shouldShowQueryBuilder = isDataProviderVisible || timelineType === TimelineType.template; + + return ( + + + + + {showCallOutUnauthorizedMsg && ( + + + + )} + {status === TimelineStatus.immutable && ( + + + + )} + {show ? ( + + + + ) : null} + + ); +}; + +export const QueryTabHeader = React.memo(QueryTabHeaderComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts similarity index 88% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/header/selectors.ts rename to x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts index 65deef339986..02668c18b308 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/selectors.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts @@ -7,7 +7,7 @@ import { createSelector } from 'reselect'; -import { timelineSelectors } from '../../../store/timeline'; +import { timelineSelectors } from '../../../../store/timeline'; export const getTimelineSaveModalByIdSelector = () => createSelector(timelineSelectors.selectTimeline, (timeline) => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/translations.ts new file mode 100644 index 000000000000..f90c46d69d23 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/translations.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const CALL_OUT_UNAUTHORIZED_MSG = i18n.translate( + 'xpack.securitySolution.timeline.callOut.unauthorized.message.description', + { + defaultMessage: + 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.', + } +); + +export const CALL_OUT_IMMUTABLE = i18n.translate( + 'xpack.securitySolution.timeline.callOut.immutable.message.description', + { + defaultMessage: + 'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.', + } +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index a5d941ca6456..390369eaf89e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -35,7 +35,7 @@ import { useKibana } from '../../../../common/lib/kibana'; import { defaultHeaders } from '../body/column_headers/default_headers'; import { StatefulBody } from '../body'; import { Footer, footerHeight } from '../footer'; -import { TimelineHeader } from '../header'; +import { QueryTabHeader } from './header'; import { calculateTotalPages } from '../helpers'; import { combineQueries } from '../../../../common/lib/kuery'; import { TimelineRefetch } from '../refetch_timeline'; @@ -46,7 +46,6 @@ import type { } from '../../../../../common/types/timeline'; import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline'; import { requiredFieldsForActions } from '../../../../detections/components/alerts_table/default_config'; -import { SuperDatePicker } from '../../../../common/components/super_date_picker'; import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; import type { inputsModel, State } from '../../../../common/store'; import { inputsSelectors } from '../../../../common/store'; @@ -55,22 +54,19 @@ import { timelineDefaults } from '../../../store/timeline/defaults'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { useTimelineEventsCountPortal } from '../../../../common/hooks/use_timeline_events_count'; import type { TimelineModel } from '../../../store/timeline/model'; -import { TimelineDatePickerLock } from '../date_picker_lock'; import { useTimelineFullScreen } from '../../../../common/containers/use_full_screen'; import { activeTimeline } from '../../../containers/active_timeline_context'; import { DetailsPanel } from '../../side_panel'; import { ExitFullScreen } from '../../../../common/components/exit_full_screen'; import { getDefaultControlColumn } from '../body/control_columns'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; -import { Sourcerer } from '../../../../common/components/sourcerer'; import { useLicense } from '../../../../common/hooks/use_license'; import { HeaderActions } from '../../../../common/components/header_actions/header_actions'; -const TimelineHeaderContainer = styled.div` - margin-top: 6px; +const QueryTabHeaderContainer = styled.div` width: 100%; `; -TimelineHeaderContainer.displayName = 'TimelineHeaderContainer'; +QueryTabHeaderContainer.displayName = 'TimelineHeaderContainer'; const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` align-items: stretch; @@ -79,8 +75,7 @@ const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` flex-direction: column; &.euiFlyoutHeader { - ${({ theme }) => - `padding: ${theme.eui.euiSizeM} ${theme.eui.euiSizeS} 0 ${theme.eui.euiSizeS};`} + ${({ theme }) => `padding: ${theme.eui.euiSizeS} 0 0 0;`} } `; @@ -320,10 +315,6 @@ export const QueryTabContentComponent: React.FC = ({ ); }, [loadingSourcerer, timelineId, isQueryLoading, dispatch]); - const isDatePickerDisabled = useMemo(() => { - return (combinedQueries && combinedQueries.kqlError != null) || false; - }, [combinedQueries]); - const leadingControlColumns = useMemo( () => getDefaultControlColumn(ACTION_BUTTON_COUNT).map((x) => ({ @@ -333,10 +324,15 @@ export const QueryTabContentComponent: React.FC = ({ [ACTION_BUTTON_COUNT] ); + // NOTE: The timeline is blank after browser FORWARD navigation (after using back button to navigate to + // the previous page from the timeline), yet we still see total count. This is because the timeline + // is not getting refreshed when using browser navigation. + const showEventsCountBadge = !isBlankTimeline && totalCount >= 0; + return ( <> - {totalCount >= 0 ? {totalCount} : null} + {showEventsCountBadge ? {totalCount} : null} = ({ data-test-subj={`${activeTab}-tab-flyout-header`} hasBorder={false} > - + {timelineFullScreen && setTimelineFullScreen != null && ( - + + + + + )} - - - - - + + + + - - {activeTab === TimelineTabs.query && ( - - )} - + {/* TODO: This is a temporary solution to hide the KPIs until lens components play nicely with timelines */} + {/* https://github.com/elastic/kibana/issues/17156 */} + {/* */} + {/* */} + {/* */} - - - - + obj != null && typeof obj === 'object' && Object.hasOwn(obj, 'getName'); + const StatefulSearchOrFilterComponent = React.memo( ({ dataProviders, @@ -48,7 +64,59 @@ const StatefulSearchOrFilterComponent = React.memo( toStr, updateKqlMode, updateReduxTime, + timelineType, }) => { + const dispatch = useDispatch(); + + const { addError } = useAppToasts(); + + const [dataView, setDataView] = useState(); + const { + services: { data }, + } = useKibana(); + + const { indexPattern } = useSourcererDataView(SourcererScopeName.timeline); + + const getIsDataProviderVisible = useMemo( + () => timelineSelectors.dataProviderVisibilitySelector(), + [] + ); + + const isDataProviderVisible = useDeepEqualSelector((state) => + getIsDataProviderVisible(state, timelineId) + ); + + useEffect(() => { + let dv: DataView; + if (isDataView(indexPattern)) { + setDataView(indexPattern); + } else if (!filterQuery) { + const createDataView = async () => { + try { + dv = await data.dataViews.create({ title: indexPattern.title }); + setDataView(dv); + } catch (error) { + addError(error, { title: i18n.ERROR_PROCESSING_INDEX_PATTERNS }); + } + }; + createDataView(); + } + return () => { + if (dv?.id) { + data.dataViews.clearInstanceCache(dv?.id); + } + }; + }, [data.dataViews, indexPattern, filterQuery, addError]); + + const arrDataView = useMemo(() => (dataView != null ? [dataView] : []), [dataView]); + + const onFiltersUpdated = useCallback( + (newFilters: Filter[]) => { + filterManager.setFilters(newFilters); + }, + [filterManager] + ); + const setFiltersInTimeline = useCallback( (newFilters: Filter[]) => setFilters({ @@ -67,26 +135,83 @@ const StatefulSearchOrFilterComponent = React.memo( [timelineId, setSavedQueryId] ); + const toggleDataProviderVisibility = useCallback(() => { + dispatch( + setDataProviderVisibility({ id: timelineId, isDataProviderVisible: !isDataProviderVisible }) + ); + }, [isDataProviderVisible, timelineId, dispatch]); + + useEffect(() => { + /* + * If there is a change in data providers + * - data provider has some data and it was hidden, + * * it must be made visible + * + * - data provider has no data and it was visible, + * * it must be hidden + * + * */ + if (dataProviders?.length > 0) { + dispatch(setDataProviderVisibility({ id: timelineId, isDataProviderVisible: true })); + } else if (dataProviders?.length === 0) { + dispatch(setDataProviderVisibility({ id: timelineId, isDataProviderVisible: false })); + } + }, [dataProviders, dispatch, timelineId]); + return ( - + + + + + + + + + {filters && filters.length > 0 ? ( + + + + + + ) : null} + ); }, (prevProps, nextProps) => { @@ -104,7 +229,8 @@ const StatefulSearchOrFilterComponent = React.memo( deepEqual(prevProps.filterQuery, nextProps.filterQuery) && deepEqual(prevProps.kqlMode, nextProps.kqlMode) && deepEqual(prevProps.savedQueryId, nextProps.savedQueryId) && - deepEqual(prevProps.timelineId, nextProps.timelineId) + deepEqual(prevProps.timelineId, nextProps.timelineId) && + prevProps.timelineType === nextProps.timelineType ); } ); @@ -135,8 +261,10 @@ const makeMapStateToProps = () => { to: input.timerange.to, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion toStr: input.timerange.toStr!, + timelineType: timeline.timelineType, }; }; + return mapStateToProps; }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx index 5ddfc4cd4962..d99c38057297 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx @@ -5,40 +5,29 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; -import React, { useCallback } from 'react'; -import styled, { createGlobalStyle } from 'styled-components'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; import type { Filter } from '@kbn/es-query'; import type { FilterManager } from '@kbn/data-plugin/public'; +import { TimelineType } from '../../../../../common/api/timeline'; +import { InputsModelId } from '../../../../common/store/inputs/constants'; import type { KqlMode } from '../../../store/timeline/model'; import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker'; +import { SuperDatePicker } from '../../../../common/components/super_date_picker'; import type { KueryFilterQuery } from '../../../../../common/types/timeline'; import type { DataProvider } from '../data_providers/data_provider'; import { QueryBarTimeline } from '../query_bar'; -import { EuiSuperSelect } from './super_select'; -import { options } from './helpers'; -import * as i18n from './translations'; - -const timelineSelectModeItemsClassName = 'timelineSelectModeItemsClassName'; -const searchOrFilterPopoverClassName = 'searchOrFilterPopover'; -const searchOrFilterPopoverWidth = '352px'; - -// SIDE EFFECT: the following creates a global class selector -const SearchOrFilterGlobalStyle = createGlobalStyle` - .${timelineSelectModeItemsClassName} { - width: 350px !important; - } - - .${searchOrFilterPopoverClassName}.euiPopover__panel { - width: ${searchOrFilterPopoverWidth} !important; - - .euiSuperSelect__listbox { - width: ${searchOrFilterPopoverWidth} !important; - } - } -`; +import { TimelineDatePickerLock } from '../date_picker_lock'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; +import { Sourcerer } from '../../../../common/components/sourcerer'; +import { + DATA_PROVIDER_HIDDEN_EMPTY, + DATA_PROVIDER_HIDDEN_POPULATED, + DATA_PROVIDER_VISIBLE, +} from './translations'; interface Props { dataProviders: DataProvider[]; @@ -58,11 +47,14 @@ interface Props { to: string; toStr: string; updateReduxTime: DispatchUpdateReduxTime; + isDataProviderVisible: boolean; + toggleDataProviderVisibility: () => void; + timelineType: TimelineType; } const SearchOrFilterContainer = styled.div` - ${({ theme }) => `margin-top: ${theme.eui.euiSizeXS};`} - user-select: none; // This should not be here, it makes the entire page inaccessible + overflow-x: auto; + overflow-y: hidden; `; SearchOrFilterContainer.displayName = 'SearchOrFilterContainer'; @@ -90,33 +82,41 @@ export const SearchOrFilter = React.memo( setSavedQueryId, to, toStr, - updateKqlMode, updateReduxTime, + isDataProviderVisible, + toggleDataProviderVisibility, + timelineType, }) => { - const handleChange = useCallback( - (mode: KqlMode) => updateKqlMode({ id: timelineId, kqlMode: mode }), - [timelineId, updateKqlMode] + const isDataProviderEmpty = useMemo(() => dataProviders?.length === 0, [dataProviders]); + + const dataProviderIconTooltipContent = useMemo(() => { + if (isDataProviderVisible) { + return DATA_PROVIDER_VISIBLE; + } + if (isDataProviderEmpty) { + return DATA_PROVIDER_HIDDEN_EMPTY; + } + return DATA_PROVIDER_HIDDEN_POPULATED; + }, [isDataProviderEmpty, isDataProviderVisible]); + + const buttonColor = useMemo( + () => (isDataProviderEmpty || isDataProviderVisible ? 'primary' : 'warning'), + [isDataProviderEmpty, isDataProviderVisible] ); return ( <> - - - - - - - + + + + + ( updateReduxTime={updateReduxTime} /> + { + /* + DataProvider toggle is not needed in template timeline because + it is always visible + */ + timelineType === TimelineType.default ? ( + + + + + + ) : null + } + + + + + + + - ); } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/translations.ts index 560a82a32968..f3577e350dc9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/translations.ts @@ -64,9 +64,30 @@ export const SEARCH_KQL_SELECTED_TEXT = i18n.translate( } ); -export const FILTER_OR_SEARCH_WITH_KQL = i18n.translate( - 'xpack.securitySolution.timeline.searchOrFilter.filterOrSearchWithKql', +export const DATA_PROVIDER_HIDDEN_POPULATED = i18n.translate( + 'xpack.securitySolution.timeline.searchOrFilter.dataProviderToggle.hiddenAndPopulated', { - defaultMessage: 'Filter or Search with KQL', + defaultMessage: 'Query Builder is hidden. Click here to see the existing Queries', + } +); + +export const DATA_PROVIDER_VISIBLE = i18n.translate( + 'xpack.securitySolution.timeline.searchOrFilter.dataProviderToggle.visible', + { + defaultMessage: 'Click here to hide Query builder', + } +); + +export const DATA_PROVIDER_HIDDEN_EMPTY = i18n.translate( + 'xpack.securitySolution.timeline.searchOrFilter.dataProviderToggle.hiddenAndEmpty', + { + defaultMessage: 'Click here to show the empty Query builder', + } +); + +export const ERROR_PROCESSING_INDEX_PATTERNS = i18n.translate( + 'xpack.securitySolution.timeline.searchOrFilter.errorProcessingDataView', + { + defaultMessage: 'Error processing Index Patterns', } ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx index b62e36e20b93..3f65e542ed30 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx @@ -276,6 +276,10 @@ const StyledEuiTab = styled(EuiTab)` } `; +const StyledEuiTabs = styled(EuiTabs)` + padding-inline: ${(props) => props.theme.eui.euiSizeM}; +`; + const TabsContentComponent: React.FC = ({ renderCellValue, rowRenderers, @@ -389,7 +393,7 @@ const TabsContentComponent: React.FC = ({ return ( <> {!timelineFullScreen && ( - + = ({ {i18n.SECURITY_ASSISTANT} )} - + )} { @@ -18,6 +20,7 @@ jest.mock('../../common/lib/kibana', () => { http: { fetch: jest.fn(), }, + savedSearch: jest.fn(), })), }, }; @@ -448,3 +451,119 @@ describe('cleanDraftTimeline', () => { }); }); }); + +describe('copyTimeline', () => { + const mockPostTimelineResponse = { + data: { + persistTimeline: { + timeline: { + ...timelineData, + savedObjectId: '9d5693e0-a42a-11ea-b8f4-c5434162742a', + version: 'WzMzMiwxXQ==', + }, + }, + }, + }; + + const saveSavedSearchMock = jest.fn(); + const postMock = jest.fn(); + const initialSavedSearchId = 'initialId'; + const newSavedSearchId = 'newId-230820349807209752'; + + const customQuery = { + language: 'kuery', + query: '_id: *', + }; + + const dataViewMock = buildDataViewMock({ + name: 'first-data-view', + fields: shallowMockedFields, + }); + + const mockSavedSearch = { + id: initialSavedSearchId, + title: 'first title', + breakdownField: 'firstBreakdown Field', + searchSource: createSearchSourceMock({ + index: dataViewMock, + query: customQuery, + }), + }; + + beforeAll(() => { + jest.resetAllMocks(); + jest.resetModules(); + + (KibanaServices.get as jest.Mock).mockReturnValue({ + http: { + post: postMock.mockReturnValue(mockPostTimelineResponse), + }, + savedSearch: { + save: saveSavedSearchMock.mockImplementation(() => newSavedSearchId), + }, + }); + }); + + it('creates a new saved search when a saved search object is passed', async () => { + await api.copyTimeline({ + timelineId: 'test', + timeline: { + ...timelineData, + savedSearchId: 'test', + }, + savedSearch: mockSavedSearch, + }); + + // 'id' should be removed + expect(saveSavedSearchMock).toHaveBeenCalled(); + expect(saveSavedSearchMock).not.toHaveBeenCalledWith( + expect.objectContaining({ + id: initialSavedSearchId, + }) + ); + + // The new saved search id is sent to the server + expect(postMock).toHaveBeenCalledWith( + TIMELINE_COPY_URL, + expect.objectContaining({ + body: expect.stringContaining(newSavedSearchId), + }) + ); + }); + + it('applies the timeline changes before sending the POST request', async () => { + const ridiculousTimelineTitle = 'Wow, what a weirt timeline title'; + await api.copyTimeline({ + timelineId: 'test', + timeline: { + ...timelineData, + title: ridiculousTimelineTitle, + savedSearchId: 'test', + }, + savedSearch: mockSavedSearch, + }); + + // The new saved search id is sent to the server + expect(postMock).toHaveBeenCalledWith( + TIMELINE_COPY_URL, + expect.objectContaining({ + body: expect.stringContaining(ridiculousTimelineTitle), + }) + ); + }); + + it('does not save a saved search for timelines without `savedSearchId`', async () => { + jest.clearAllMocks(); + + await api.copyTimeline({ + timelineId: 'test', + timeline: { + ...timelineData, + savedSearchId: null, + }, + savedSearch: mockSavedSearch, + }); + + expect(saveSavedSearchMock).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 72a75027e417..f39143bbfa76 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -11,6 +11,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { isEmpty } from 'lodash'; import { throwErrors } from '@kbn/cases-plugin/common'; +import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { TimelineResponse, @@ -41,6 +42,7 @@ import { TIMELINE_PREPACKAGED_URL, TIMELINE_RESOLVE_URL, TIMELINES_URL, + TIMELINE_COPY_URL, TIMELINE_FAVORITE_URL, } from '../../../common/constants'; @@ -61,6 +63,7 @@ interface RequestPostTimeline { interface RequestPatchTimeline extends RequestPostTimeline { timelineId: T; version: T; + savedSearch?: SavedSearch | null; } type RequestPersistTimeline = RequestPostTimeline & Partial>; @@ -130,6 +133,7 @@ const patchTimeline = async ({ timelineId, timeline, version, + savedSearch, }: RequestPatchTimeline): Promise => { let response = null; let requestBody = null; @@ -138,6 +142,19 @@ const patchTimeline = async ({ } catch (err) { return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); } + + try { + if (timeline.savedSearchId && savedSearch) { + const { savedSearch: savedSearchService } = KibanaServices.get(); + await savedSearchService.save(savedSearch, { + onTitleDuplicate: () => ({}), + copyOnSave: false, + }); + } + } catch (e) { + return Promise.reject(new Error(`Failed to copy saved search: ${timeline.savedSearchId}`)); + } + try { response = await KibanaServices.get().http.patch(TIMELINE_URL, { method: 'PATCH', @@ -153,10 +170,63 @@ const patchTimeline = async ({ return decodeTimelineResponse(response); }; +/** + * Creates a copy of the timeline with the given id. It will also apply changes to the original timeline + * which are passed as `timeline` here. + */ +export const copyTimeline = async ({ + timelineId, + timeline, + savedSearch, +}: RequestPersistTimeline): Promise => { + let response = null; + let requestBody = null; + let newSavedSearchId = null; + + try { + if (timeline.savedSearchId && savedSearch) { + const { savedSearch: savedSearchService } = KibanaServices.get(); + const savedSearchCopy = { ...savedSearch }; + // delete the id and change the title to make sure we can copy the saved search + delete savedSearchCopy.id; + newSavedSearchId = await savedSearchService.save(savedSearchCopy, { + onTitleDuplicate: () => ({}), + copyOnSave: false, + }); + } + } catch (e) { + return Promise.reject(new Error(`Failed to copy saved search: ${timeline.savedSearchId}`)); + } + + try { + requestBody = JSON.stringify({ + timeline: { ...timeline, savedSearchId: newSavedSearchId || timeline.savedSearchId }, + timelineIdToCopy: timelineId, + }); + } catch (err) { + return Promise.reject(new Error(`Failed to stringify query: ${JSON.stringify(err)}`)); + } + + try { + response = await KibanaServices.get().http.post(TIMELINE_COPY_URL, { + method: 'POST', + body: requestBody, + version: '1', + }); + } catch (err) { + // For Future developer + // We are not rejecting our promise here because we had issue with our RXJS epic + // the issue we were not able to pass the right object to it so we did manage the error in the success + return Promise.resolve(decodeTimelineErrorResponse(err.body)); + } + return decodeTimelineResponse(response); +}; + export const persistTimeline = async ({ timelineId, timeline, version, + savedSearch, }: RequestPersistTimeline): Promise => { try { if (isEmpty(timelineId) && timeline.status === TimelineStatus.draft && timeline) { @@ -187,6 +257,7 @@ export const persistTimeline = async ({ ...templateTimelineInfo, }, version: draftTimeline.data.persistTimeline.timeline.version ?? '', + savedSearch, }); } @@ -198,6 +269,7 @@ export const persistTimeline = async ({ timelineId: timelineId ?? '-1', timeline, version: version ?? '', + savedSearch, }); } catch (err) { if (err.status_code === 403 || err.body.status_code === 403) { diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts index bbf1a50664ac..8440a534ad45 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts @@ -7,6 +7,7 @@ import actionCreatorFactory from 'typescript-fsa'; import type { Filter } from '@kbn/es-query'; +import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { SessionViewConfig } from '../../../../common/types'; import type { @@ -46,7 +47,7 @@ export const setInsertTimeline = actionCreator('SET_INSER export const addProvider = actionCreator<{ id: string; providers: DataProvider[] }>('ADD_PROVIDER'); -export const saveTimeline = actionCreator<{ id: string }>('SAVE_TIMELINE'); +export const saveTimeline = actionCreator<{ id: string; saveAsNew: boolean }>('SAVE_TIMELINE'); export const createTimeline = actionCreator('CREATE_TIMELINE'); @@ -273,4 +274,19 @@ export const setIsDiscoverSavedSearchLoaded = actionCreator<{ isDiscoverSavedSearchLoaded: boolean; }>('SET_IS_DISCOVER_SAVED_SEARCH_LOADED'); +export const initializeSavedSearch = actionCreator<{ + id: string; + savedSearch: SavedSearch; +}>('INITIALIZE_SAVED_SEARCH'); + +export const updateSavedSearch = actionCreator<{ + id: string; + savedSearch: SavedSearch; +}>('UPDATE_SAVED_SEARCH'); + +export const setDataProviderVisibility = actionCreator<{ + id: string; + isDataProviderVisible: boolean; +}>('SET_DATA_PROVIDER_VISIBLITY'); + export const setChanged = actionCreator<{ id: string; changed: boolean }>('SET_CHANGED'); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts index 449a2aa2b13f..1df0a997a2d8 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts @@ -79,7 +79,9 @@ export const timelineDefaults: SubsetTimelineModel & isSelectAllChecked: false, filters: [], savedSearchId: null, + savedSearch: null, isDiscoverSavedSearchLoaded: false, + isDataProviderVisible: false, }; export const getTimelineManageDefaults = (id: string) => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts index 21551dacebc6..9a273bc6ca14 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts @@ -176,6 +176,8 @@ describe('Epic Timeline', () => { id: '11169110-fc22-11e9-8ca9-072f15ce2685', savedQueryId: 'my endgame timeline query', savedSearchId: null, + savedSearch: null, + isDataProviderVisible: true, }; expect( diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts index 7f1c878df692..7c072abce73e 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts @@ -29,13 +29,13 @@ import { takeUntil, } from 'rxjs/operators'; -import type { TimelineErrorResponse, ResponseTimeline } from '../../../../common/api/timeline'; +import type { TimelineErrorResponse, TimelineResponse } from '../../../../common/api/timeline'; import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; import { TimelineStatus, TimelineType } from '../../../../common/api/timeline'; import type { inputsModel } from '../../../common/store/inputs'; import { addError } from '../../../common/store/app/actions'; -import { persistTimeline } from '../../containers/api'; +import { copyTimeline, persistTimeline } from '../../containers/api'; import { ALL_TIMELINE_QUERY_ID } from '../../containers/all'; import * as i18n from '../../pages/translations'; @@ -50,13 +50,13 @@ import { setChanged, } from './actions'; import type { TimelineModel } from './model'; -import { epicPersistNote, timelineNoteActionsType } from './epic_note'; -import { epicPersistPinnedEvent, timelinePinnedEventActionsType } from './epic_pinned_event'; -import { epicPersistTimelineFavorite, timelineFavoriteActionsType } from './epic_favorite'; +import { epicPersistNote, isNoteAction } from './epic_note'; +import { epicPersistPinnedEvent, isPinnedEventAction } from './epic_pinned_event'; +import { epicPersistTimelineFavorite, isFavoriteTimelineAction } from './epic_favorite'; import { isNotNull } from './helpers'; import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue'; import { myEpicTimelineId } from './my_epic_timeline_id'; -import type { ActionTimeline, TimelineEpicDependencies } from './types'; +import type { TimelineEpicDependencies } from './types'; import type { TimelineInput } from '../../../../common/search_strategy'; const isItAtimelineAction = (timelineId: string | undefined) => @@ -133,25 +133,17 @@ export const createTimelineEpic = dispatcherTimelinePersistQueue.pipe( withLatestFrom(timeline$, notes$, timelineTimeRange$), concatMap(([objAction, timeline, notes, timelineTimeRange]) => { - const action: ActionTimeline = get('action', objAction); + const action: Action = get('action', objAction); const timelineId = myEpicTimelineId.getTimelineId(); const version = myEpicTimelineId.getTimelineVersion(); const templateTimelineId = myEpicTimelineId.getTemplateTimelineId(); const templateTimelineVersion = myEpicTimelineId.getTemplateTimelineVersion(); - if (timelineNoteActionsType.has(action.type)) { - return epicPersistNote( - action, - timeline, - notes, - action$, - timeline$, - notes$, - allTimelineQuery$ - ); - } else if (timelinePinnedEventActionsType.has(action.type)) { + if (isNoteAction(action)) { + return epicPersistNote(action, notes, action$, timeline$, notes$, allTimelineQuery$); + } else if (isPinnedEventAction(action)) { return epicPersistPinnedEvent(action, timeline, action$, timeline$, allTimelineQuery$); - } else if (timelineFavoriteActionsType.has(action.type)) { + } else if (isFavoriteTimelineAction(action)) { return epicPersistTimelineFavorite( action, timeline, @@ -159,23 +151,36 @@ export const createTimelineEpic = timeline$, allTimelineQuery$ ); - } else if (action.type === saveTimeline.type) { + } else if (isSaveTimelineAction(action)) { + const saveAction = action as unknown as ReturnType; + const savedSearch = timeline[action.payload.id].savedSearch; return from( - persistTimeline({ - timelineId, - version, - timeline: { - ...convertTimelineAsInput(timeline[action.payload.id], timelineTimeRange), - templateTimelineId, - templateTimelineVersion, - }, - }) + saveAction.payload.saveAsNew && timelineId + ? copyTimeline({ + timelineId, + timeline: { + ...convertTimelineAsInput(timeline[action.payload.id], timelineTimeRange), + templateTimelineId, + templateTimelineVersion, + }, + savedSearch, + }) + : persistTimeline({ + timelineId, + version, + timeline: { + ...convertTimelineAsInput(timeline[action.payload.id], timelineTimeRange), + templateTimelineId, + templateTimelineVersion, + }, + savedSearch, + }) ).pipe( withLatestFrom(timeline$, allTimelineQuery$, kibana$), - mergeMap(([result, recentTimeline, allTimelineQuery, kibana]) => { - const error = result as TimelineErrorResponse; - if (error.status_code != null) { - switch (error.status_code) { + mergeMap(([response, recentTimeline, allTimelineQuery, kibana]) => { + if (isTimelineErrorResponse(response)) { + const error = getErrorFromResponse(response); + switch (error?.errorCode) { // conflict case 409: kibana.notifications.toasts.addDanger({ @@ -186,7 +191,7 @@ export const createTimelineEpic = default: kibana.notifications.toasts.addDanger({ title: i18n.UPDATE_TIMELINE_ERROR_TITLE, - text: error.message ?? i18n.UPDATE_TIMELINE_ERROR_TEXT, + text: error?.message ?? i18n.UPDATE_TIMELINE_ERROR_TEXT, }); } return [ @@ -196,9 +201,8 @@ export const createTimelineEpic = ]; } - const savedTimeline = recentTimeline[action.payload.id]; - const response: ResponseTimeline = get('data.persistTimeline', result); - if (response == null) { + const unwrappedResponse = response.data.persistTimeline; + if (unwrappedResponse == null) { kibana.notifications.toasts.addDanger({ title: i18n.UPDATE_TIMELINE_ERROR_TITLE, text: i18n.UPDATE_TIMELINE_ERROR_TEXT, @@ -209,7 +213,15 @@ export const createTimelineEpic = }), ]; } - const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + + if (unwrappedResponse.code === 403) { + return [ + showCallOutUnauthorizedMsg(), + endTimelineSaving({ + id: action.payload.id, + }), + ]; + } if (allTimelineQuery.refetch != null) { (allTimelineQuery.refetch as inputsModel.Refetch)(); @@ -219,18 +231,19 @@ export const createTimelineEpic = updateTimeline({ id: action.payload.id, timeline: { - ...savedTimeline, - updated: response.timeline.updated ?? undefined, - savedObjectId: response.timeline.savedObjectId, - version: response.timeline.version, - status: response.timeline.status ?? TimelineStatus.active, - timelineType: response.timeline.timelineType ?? TimelineType.default, - templateTimelineId: response.timeline.templateTimelineId ?? null, - templateTimelineVersion: response.timeline.templateTimelineVersion ?? null, + ...recentTimeline[action.payload.id], + updated: unwrappedResponse.timeline.updated ?? undefined, + savedObjectId: unwrappedResponse.timeline.savedObjectId, + version: unwrappedResponse.timeline.version, + status: unwrappedResponse.timeline.status ?? TimelineStatus.active, + timelineType: unwrappedResponse.timeline.timelineType ?? TimelineType.default, + templateTimelineId: unwrappedResponse.timeline.templateTimelineId ?? null, + templateTimelineVersion: + unwrappedResponse.timeline.templateTimelineVersion ?? null, + savedSearchId: unwrappedResponse.timeline.savedSearchId ?? null, isSaving: false, }, }), - ...callOutMsg, setChanged({ id: action.payload.id, changed: false, @@ -238,7 +251,7 @@ export const createTimelineEpic = endTimelineSaving({ id: action.payload.id, }), - ].filter(Boolean); + ]; }), startWith(startTimelineSaving({ id: action.payload.id })), takeUntil( @@ -275,6 +288,10 @@ export const createTimelineEpic = ); }; +function isSaveTimelineAction(action: Action): action is ReturnType { + return action.type === saveTimeline.type; +} + const timelineInput: TimelineInput = { columns: null, dataProviders: null, @@ -389,3 +406,17 @@ const convertToString = (obj: unknown) => { return ''; } }; + +type PossibleResponse = TimelineResponse | TimelineErrorResponse; + +function isTimelineErrorResponse(response: PossibleResponse): response is TimelineErrorResponse { + return 'status_code' in response || 'statusCode' in response; +} + +function getErrorFromResponse(response: TimelineErrorResponse) { + if ('status_code' in response) { + return { errorCode: response.status_code, message: response.message }; + } else if ('statusCode' in response) { + return { errorCode: response.statusCode, message: response.message }; + } +} diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts index 430f7bc71aa5..ed4294207b30 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts @@ -32,6 +32,7 @@ import { setFilters, setSavedQueryId, setChanged, + updateSavedSearch, } from './actions'; /** @@ -59,6 +60,8 @@ const timelineChangedTypes = new Set([ updateSort.type, updateRange.type, upsertColumn.type, + + updateSavedSearch.type, ]); /** diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts index 990bb229761c..ff501fb4761d 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts @@ -22,16 +22,22 @@ import { } from './actions'; import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue'; import { myEpicTimelineId } from './my_epic_timeline_id'; -import type { ActionTimeline, TimelineById } from './types'; +import type { TimelineById } from './types'; import type { inputsModel } from '../../../common/store/inputs'; import type { ResponseFavoriteTimeline } from '../../../../common/api/timeline'; import { TimelineType } from '../../../../common/api/timeline'; import { persistFavorite } from '../../containers/api'; -export const timelineFavoriteActionsType = new Set([updateIsFavorite.type]); +type FavoriteTimelineAction = ReturnType; + +const timelineFavoriteActionsType = new Set([updateIsFavorite.type]); + +export function isFavoriteTimelineAction(action: Action): action is FavoriteTimelineAction { + return timelineFavoriteActionsType.has(action.type); +} export const epicPersistTimelineFavorite = ( - action: ActionTimeline, + action: FavoriteTimelineAction, timeline: TimelineById, action$: Observable, timeline$: Observable, @@ -108,7 +114,7 @@ export const createTimelineFavoriteEpic = (): Epic => (action$) => { return action$.pipe( - filter((action) => timelineFavoriteActionsType.has(action.type)), + filter(isFavoriteTimelineAction), mergeMap((action) => { dispatcherTimelinePersistQueue.next({ action }); return EMPTY; diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts index a9992d69c926..01e612302ca3 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts @@ -26,15 +26,20 @@ import { } from './actions'; import { myEpicTimelineId } from './my_epic_timeline_id'; import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue'; -import type { ActionTimeline, TimelineById } from './types'; +import type { TimelineById } from './types'; import { persistNote } from '../../containers/notes/api'; import type { ResponseNote } from '../../../../common/api/timeline'; -export const timelineNoteActionsType = new Set([addNote.type, addNoteToEvent.type]); +type NoteAction = ReturnType; + +const timelineNoteActionsType = new Set([addNote.type, addNoteToEvent.type]); + +export function isNoteAction(action: Action): action is NoteAction { + return timelineNoteActionsType.has(action.type); +} export const epicPersistNote = ( - action: ActionTimeline, - timeline: TimelineById, + action: NoteAction, notes: NotesById, action$: Observable, timeline$: Observable, @@ -47,7 +52,7 @@ export const epicPersistNote = ( noteId: null, version: null, note: { - eventId: action.payload.eventId, + eventId: 'eventId' in action.payload ? action.payload.eventId : undefined, note: getNote(action.payload.noteId, notes), timelineId: myEpicTimelineId.getTimelineId(), }, @@ -125,7 +130,7 @@ export const createTimelineNoteEpic = (): Epic => (action$) => action$.pipe( - filter((action) => timelineNoteActionsType.has(action.type)), + filter(isNoteAction), switchMap((action) => { dispatcherTimelinePersistQueue.next({ action }); return EMPTY; diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts index 9231eefb4619..b99de117e785 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts @@ -25,13 +25,19 @@ import { } from './actions'; import { myEpicTimelineId } from './my_epic_timeline_id'; import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue'; -import type { ActionTimeline, TimelineById } from './types'; +import type { TimelineById } from './types'; import { persistPinnedEvent } from '../../containers/pinned_event/api'; -export const timelinePinnedEventActionsType = new Set([pinEvent.type, unPinEvent.type]); +type PinnedEventAction = ReturnType; + +const timelinePinnedEventActionsType = new Set([pinEvent.type, unPinEvent.type]); + +export function isPinnedEventAction(action: Action): action is PinnedEventAction { + return timelinePinnedEventActionsType.has(action.type); +} export const epicPersistPinnedEvent = ( - action: ActionTimeline, + action: PinnedEventAction, timeline: TimelineById, action$: Observable, timeline$: Observable, @@ -129,7 +135,7 @@ export const createTimelinePinnedEventEpic = (): Epic => (action$) => action$.pipe( - filter((action) => timelinePinnedEventActionsType.has(action.type)), + filter(isPinnedEventAction), mergeMap((action) => { dispatcherTimelinePersistQueue.next({ action }); return EMPTY; diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts new file mode 100644 index 000000000000..e0ca1b6dc681 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts @@ -0,0 +1,1859 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { cloneDeep } from 'lodash/fp'; +import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; +import { TimelineTabs, TimelineId } from '../../../../common/types/timeline'; +import { TimelineType, TimelineStatus } from '../../../../common/api/timeline'; + +import type { + DataProvider, + DataProvidersAnd, +} from '../../components/timeline/data_providers/data_provider'; +import { + IS_OPERATOR, + DataProviderType, +} from '../../components/timeline/data_providers/data_provider'; +import { defaultColumnHeaderType } from '../../components/timeline/body/column_headers/default_headers'; +import { + DEFAULT_COLUMN_MIN_WIDTH, + RESIZED_COLUMN_MIN_WITH, +} from '../../components/timeline/body/constants'; +import { defaultHeaders } from '../../../common/mock'; + +import { + addNewTimeline, + addTimelineProviders, + addTimelineToStore, + applyDeltaToTimelineColumnWidth, + removeTimelineColumn, + removeTimelineProvider, + updateTimelineColumns, + updateTimelineItemsPerPage, + updateTimelinePerPageOptions, + updateTimelineProviderEnabled, + updateTimelineProviderExcluded, + updateTimelineProviderType, + updateTimelineProviders, + updateTimelineRange, + updateTimelineShowTimeline, + updateTimelineSort, + updateTimelineTitleAndDescription, + upsertTimelineColumn, + updateTimelineGraphEventId, +} from './helpers'; +import type { TimelineModel } from './model'; +import { timelineDefaults } from './defaults'; +import type { TimelineById } from './types'; +import { Direction } from '../../../../common/search_strategy'; +import type { FilterManager } from '@kbn/data-plugin/public'; + +jest.mock('../../../common/utils/normalize_time_range'); +jest.mock('../../../common/utils/default_date_settings', () => { + const actual = jest.requireActual('../../../common/utils/default_date_settings'); + return { + ...actual, + DEFAULT_FROM_MOMENT: new Date('2020-10-27T11:37:31.655Z'), + DEFAULT_TO_MOMENT: new Date('2020-10-28T11:37:31.655Z'), + }; +}); + +const mockFilterManager = {} as FilterManager; + +const basicDataProvider: DataProvider = { + and: [], + id: '123', + name: 'data provider 1', + enabled: true, + queryMatch: { + field: '', + value: '', + operator: IS_OPERATOR, + }, + excluded: false, + kqlQuery: '', +}; +const basicTimeline: TimelineModel = { + activeTab: TimelineTabs.query, + prevActiveTab: TimelineTabs.graph, + columns: [], + defaultColumns: [], + dataProviders: [{ ...basicDataProvider }], + dataViewId: null, + dateRange: { + start: '2020-07-07T08:20:18.966Z', + end: '2020-07-08T08:20:18.966Z', + }, + deletedEventIds: [], + description: '', + documentType: '', + eqlOptions: { + eventCategoryField: 'event.category', + tiebreakerField: '', + timestampField: '@timestamp', + }, + eventIdToNoteIds: {}, + excludedRowRendererIds: [], + expandedDetail: {}, + filterManager: mockFilterManager, + highlightedDropAndProviderId: '', + historyIds: [], + id: 'foo', + indexNames: [], + isFavorite: false, + isLive: false, + isLoading: false, + isSaving: false, + isSelectAllChecked: false, + itemsPerPage: 25, + itemsPerPageOptions: [10, 25, 50], + kqlMode: 'filter', + kqlQuery: { filterQuery: null }, + loadingEventIds: [], + noteIds: [], + pinnedEventIds: {}, + pinnedEventsSaveObject: {}, + queryFields: [], + savedObjectId: null, + selectAll: false, + selectedEventIds: {}, + sessionViewConfig: null, + show: true, + sort: [ + { + columnId: '@timestamp', + columnType: 'date', + esTypes: ['date'], + sortDirection: Direction.desc, + }, + ], + status: TimelineStatus.active, + templateTimelineId: null, + templateTimelineVersion: null, + timelineType: TimelineType.default, + title: '', + version: null, + savedSearchId: null, + savedSearch: null, + isDataProviderVisible: true, +}; +const timelineByIdMock: TimelineById = { + foo: { ...basicTimeline }, +}; + +const timelineByIdTemplateMock: TimelineById = { + foo: { + ...basicTimeline, + timelineType: TimelineType.template, + }, +}; + +const columnsMock: ColumnHeaderOptions[] = [ + defaultHeaders[0], + defaultHeaders[1], + defaultHeaders[2], +]; + +describe('Timeline', () => { + describe('#add saved object Timeline to store ', () => { + test('should return a timelineModel with default value and not just a timelineResult ', () => { + const update = addTimelineToStore({ + id: 'foo', + timeline: { + ...basicTimeline, + }, + timelineById: timelineByIdMock, + }); + + expect(update).toEqual({ + foo: { + ...basicTimeline, + show: true, + }, + }); + }); + + test('should override timerange if adding an immutable template', () => { + const update = addTimelineToStore({ + id: 'foo', + timeline: { + ...basicTimeline, + status: TimelineStatus.immutable, + timelineType: TimelineType.template, + }, + timelineById: timelineByIdMock, + }); + + expect(update).toEqual({ + foo: { + ...basicTimeline, + status: TimelineStatus.immutable, + timelineType: TimelineType.template, + dateRange: { + start: '2020-10-27T11:37:31.655Z', + end: '2020-10-28T11:37:31.655Z', + }, + show: true, + }, + }); + }); + + test('should contain existing filterManager', () => { + const update = addTimelineToStore({ + id: 'foo', + timeline: { + ...basicTimeline, + status: TimelineStatus.immutable, + timelineType: TimelineType.template, + }, + timelineById: timelineByIdMock, + }); + + expect(update.foo.filterManager).toEqual(mockFilterManager); + }); + }); + + describe('#addNewTimeline', () => { + test('should return a new reference and not the same reference', () => { + const update = addNewTimeline({ + id: 'bar', + columns: defaultHeaders, + dataViewId: null, + indexNames: [], + timelineById: timelineByIdMock, + timelineType: TimelineType.default, + savedSearchId: null, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should add a new timeline', () => { + const update = addNewTimeline({ + id: 'bar', + columns: timelineDefaults.columns, + dataViewId: null, + indexNames: [], + timelineById: timelineByIdMock, + timelineType: TimelineType.default, + savedSearchId: null, + }); + expect(update).toEqual({ + foo: basicTimeline, + bar: { ...timelineDefaults, id: 'bar' }, + }); + }); + + test('should add the specified columns to the timeline', () => { + const barWithEmptyColumns = { ...timelineDefaults, id: 'bar' }; + const barWithPopulatedColumns = { ...barWithEmptyColumns, columns: defaultHeaders }; + + const update = addNewTimeline({ + id: 'bar', + columns: defaultHeaders, + dataViewId: null, + indexNames: [], + timelineById: timelineByIdMock, + timelineType: TimelineType.default, + savedSearchId: null, + }); + expect(update).toEqual({ + foo: basicTimeline, + bar: barWithPopulatedColumns, + }); + }); + }); + + describe('#updateTimelineShowTimeline', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelineShowTimeline({ + id: 'foo', + show: false, + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should change show from true to false', () => { + const update = updateTimelineShowTimeline({ + id: 'foo', + show: false, // value we are changing from true to false + timelineById: timelineByIdMock, + }); + + expect(update).toEqual({ + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + show: false, + }, + }); + }); + }); + + describe('#upsertTimelineColumn', () => { + let timelineById: TimelineById = {}; + let columns: ColumnHeaderOptions[] = []; + let columnToAdd: ColumnHeaderOptions; + let mockWithExistingColumns: TimelineById; + + beforeEach(() => { + timelineById = cloneDeep(timelineByIdMock); + columns = cloneDeep(columnsMock); + columnToAdd = { + category: 'event', + columnHeaderType: defaultColumnHeaderType, + description: + 'The action captured by the event.\nThis describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer.', + example: 'user-password-change', + id: 'event.action', + type: 'keyword', + aggregatable: true, + initialWidth: DEFAULT_COLUMN_MIN_WIDTH, + }; + mockWithExistingColumns = { + ...timelineById, + foo: { + ...timelineById.foo, + columns, + }, + }; + }); + + test('should return a new reference and not the same reference', () => { + const update = upsertTimelineColumn({ + column: columnToAdd, + id: 'foo', + index: 0, + timelineById, + }); + + expect(update).not.toBe(timelineById); + }); + + test('should add a new column to an empty collection of columns', () => { + const expectedColumns = [columnToAdd]; + const update = upsertTimelineColumn({ + column: columnToAdd, + id: 'foo', + index: 0, + timelineById, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should add a new column to an existing collection of columns at the beginning of the collection', () => { + const expectedColumns = [columnToAdd, ...columns]; + + const update = upsertTimelineColumn({ + column: columnToAdd, + id: 'foo', + index: 0, + timelineById: mockWithExistingColumns, + }); + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should add a new column to an existing collection of columns in the middle of the collection', () => { + const expectedColumns = [columns[0], columnToAdd, columns[1], columns[2]]; + + const update = upsertTimelineColumn({ + column: columnToAdd, + id: 'foo', + index: 1, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should add a new column to an existing collection of columns at the end of the collection', () => { + const expectedColumns = [...columns, columnToAdd]; + + const update = upsertTimelineColumn({ + column: columnToAdd, + id: 'foo', + index: expectedColumns.length - 1, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + columns.forEach((column, i) => { + test(`should upsert (NOT add a new column) a column when already exists at the same index (${i})`, () => { + const update = upsertTimelineColumn({ + column, + id: 'foo', + index: i, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(columns); + }); + }); + + test('should allow the 1st column to be moved to the 2nd column', () => { + const expectedColumns = [columns[1], columns[0], columns[2]]; + + const update = upsertTimelineColumn({ + column: columns[0], + id: 'foo', + index: 1, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should allow the 1st column to be moved to the 3rd column', () => { + const expectedColumns = [columns[1], columns[2], columns[0]]; + + const update = upsertTimelineColumn({ + column: columns[0], + id: 'foo', + index: 2, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should allow the 2nd column to be moved to the 1st column', () => { + const expectedColumns = [columns[1], columns[0], columns[2]]; + + const update = upsertTimelineColumn({ + column: columns[1], + id: 'foo', + index: 0, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should allow the 2nd column to be moved to the 3rd column', () => { + const expectedColumns = [columns[0], columns[2], columns[1]]; + + const update = upsertTimelineColumn({ + column: columns[1], + id: 'foo', + index: 2, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should allow the 3rd column to be moved to the 1st column', () => { + const expectedColumns = [columns[2], columns[0], columns[1]]; + + const update = upsertTimelineColumn({ + column: columns[2], + id: 'foo', + index: 0, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should allow the 3rd column to be moved to the 2nd column', () => { + const expectedColumns = [columns[0], columns[2], columns[1]]; + + const update = upsertTimelineColumn({ + column: columns[2], + id: 'foo', + index: 1, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + }); + + describe('#addTimelineProvider', () => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + id: '567', + name: 'data provider 2', + }, + ]; + test('should return a new reference and not the same reference', () => { + const update = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should add a new timeline provider', () => { + const update = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + const addedDataProvider = [...basicTimeline.dataProviders].concat(providerToAdd); + expect(update.foo.dataProviders).toEqual(addedDataProvider); + }); + + test('should NOT add a new timeline provider if it already exists and the attributes "and" is empty', () => { + const update = addTimelineProviders({ + id: 'foo', + providers: [basicDataProvider], + timelineById: timelineByIdMock, + }); + expect(update).toEqual(timelineByIdMock); + }); + + test('should add a new timeline provider if it already exists and the attributes "and" is NOT empty', () => { + const myMockTimelineByIdMock = cloneDeep(timelineByIdMock); + myMockTimelineByIdMock.foo.dataProviders[0].and = [ + { + ...basicDataProvider, + id: '456', + name: 'and data provider 1', + }, + ]; + const providers = [{ ...basicDataProvider }]; + const update = addTimelineProviders({ + id: 'foo', + providers, + timelineById: myMockTimelineByIdMock, + }); + expect(update.foo.dataProviders[1]).toEqual(providers[0]); + }); + + test('should UPSERT an existing timeline provider if it already exists', () => { + const update = addTimelineProviders({ + id: 'foo', + providers: [ + { + ...basicDataProvider, + name: 'my name changed', + }, + ], + timelineById: timelineByIdMock, + }); + expect(update.foo.dataProviders[0].name).toEqual('my name changed'); + }); + }); + + describe('#removeTimelineColumn', () => { + let mockWithExistingColumns: TimelineById; + beforeEach(() => { + mockWithExistingColumns = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + columns: columnsMock, + }, + }; + }); + test('should return a new reference and not the same reference', () => { + const update = removeTimelineColumn({ + id: 'foo', + columnId: columnsMock[0].id, + timelineById: mockWithExistingColumns, + }); + + expect(update).not.toBe(timelineByIdMock); + }); + + test('should remove just the first column when the id matches', () => { + const expectedColumns = [columnsMock[1], columnsMock[2]]; + + const update = removeTimelineColumn({ + id: 'foo', + columnId: columnsMock[0].id, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should remove just the last column when the id matches', () => { + const expectedColumns = [columnsMock[0], columnsMock[1]]; + + const update = removeTimelineColumn({ + id: 'foo', + columnId: columnsMock[2].id, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should remove just the middle column when the id matches', () => { + const expectedColumns = [columnsMock[0], columnsMock[2]]; + + const update = removeTimelineColumn({ + id: 'foo', + columnId: columnsMock[1].id, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should not modify the columns if the id to remove was not found', () => { + const expectedColumns = cloneDeep(columnsMock); + + const update = removeTimelineColumn({ + id: 'foo', + columnId: 'does.not.exist', + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + }); + + describe('#applyDeltaToColumnWidth', () => { + let mockWithExistingColumns: TimelineById; + beforeEach(() => { + mockWithExistingColumns = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + columns: columnsMock, + }, + }; + }); + test('should return a new reference and not the same reference', () => { + const delta = 50; + const update = applyDeltaToTimelineColumnWidth({ + id: 'foo', + columnId: columnsMock[0].id, + delta, + timelineById: mockWithExistingColumns, + }); + + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update initialWidth with the specified delta when the delta is positive', () => { + const aDateColumn = columnsMock[0]; + const delta = 50; + const expectedToHaveNewWidth = { + ...aDateColumn, + initialWidth: Number(aDateColumn.initialWidth) + 50, + }; + const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; + + const update = applyDeltaToTimelineColumnWidth({ + id: 'foo', + columnId: aDateColumn.id, + delta, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should update initialWidth with the specified delta when the delta is negative, and the resulting width is greater than the min column width', () => { + const aDateColumn = columnsMock[0]; + const delta = 50 * -1; // the result will still be above the min column size + const expectedToHaveNewWidth = { + ...aDateColumn, + initialWidth: Number(aDateColumn.initialWidth) - 50, + }; + const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; + + const update = applyDeltaToTimelineColumnWidth({ + id: 'foo', + columnId: aDateColumn.id, + delta, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + + test('should set initialWidth to `RESIZED_COLUMN_MIN_WITH` when the requested delta results in a column that is too small ', () => { + const aDateColumn = columnsMock[0]; + const delta = (Number(aDateColumn.initialWidth) - 5) * -1; // the requested delta would result in a width of just 5 pixels, which is too small + const expectedToHaveNewWidth = { + ...aDateColumn, + initialWidth: RESIZED_COLUMN_MIN_WITH, // we expect the minimum + }; + const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; + + const update = applyDeltaToTimelineColumnWidth({ + id: 'foo', + columnId: aDateColumn.id, + delta, + timelineById: mockWithExistingColumns, + }); + + expect(update.foo.columns).toEqual(expectedColumns); + }); + }); + + describe('#addAndProviderToTimelineProvider', () => { + test('should add a new and provider to an existing timeline provider', () => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + id: '567', + name: 'data provider 2', + queryMatch: { + field: 'handsome', + value: 'xavier', + operator: IS_OPERATOR, + }, + }, + ]; + + const newTimeline = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + + newTimeline.foo.highlightedDropAndProviderId = '567'; + + const andProviderToAdd: DataProvider[] = [ + { + ...basicDataProvider, + id: '568', + name: 'And Data Provider', + queryMatch: { + field: 'smart', + value: 'steph', + operator: IS_OPERATOR, + }, + }, + ]; + + const update = addTimelineProviders({ + id: 'foo', + providers: andProviderToAdd, + timelineById: newTimeline, + }); + const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); + const addedAndDataProvider = update.foo.dataProviders[indexProvider].and[0]; + const { and, ...expectedResult } = andProviderToAdd[0]; + expect(addedAndDataProvider).toEqual(expectedResult); + newTimeline.foo.highlightedDropAndProviderId = ''; + }); + + test('should add another and provider because it is not a duplicate', () => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: '568', + name: 'And Data Provider', + queryMatch: { + field: 'smart', + value: 'xavier', + operator: IS_OPERATOR, + }, + }, + ], + id: '567', + queryMatch: { + field: 'handsome', + value: 'steph', + operator: IS_OPERATOR, + }, + }, + ]; + + const newTimeline = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + + newTimeline.foo.highlightedDropAndProviderId = '567'; + + const andProviderToAdd: DataProvider[] = [ + { + ...basicDataProvider, + id: '569', + name: 'And Data Provider', + queryMatch: { + field: 'happy', + value: 'andrewG', + operator: IS_OPERATOR, + }, + }, + ]; + // temporary, we will have to decouple DataProvider & DataProvidersAnd + // that's bigger a refactor than just fixing a bug + // @ts-expect-error + delete andProviderToAdd[0].and; + const update = addTimelineProviders({ + id: 'foo', + providers: andProviderToAdd, + timelineById: newTimeline, + }); + + expect(update.foo.dataProviders[1].and[1]).toEqual(andProviderToAdd[0]); + newTimeline.foo.highlightedDropAndProviderId = ''; + }); + + test('should NOT add another and provider because it is a duplicate', () => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: '568', + name: 'And Data Provider', + queryMatch: { + field: 'smart', + value: 'xavier', + operator: IS_OPERATOR, + }, + }, + ], + id: '567', + queryMatch: { + field: 'handsome', + value: 'steph', + operator: IS_OPERATOR, + }, + }, + ]; + + const newTimeline = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + + newTimeline.foo.highlightedDropAndProviderId = '567'; + + const andProviderToAdd: DataProvider[] = [ + { + ...basicDataProvider, + id: '569', + name: 'And Data Provider', + queryMatch: { + field: 'smart', + value: 'xavier', + operator: IS_OPERATOR, + }, + }, + ]; + const update = addTimelineProviders({ + id: 'foo', + providers: andProviderToAdd, + timelineById: newTimeline, + }); + + expect(update).toEqual(newTimeline); + newTimeline.foo.highlightedDropAndProviderId = ''; + }); + }); + + describe('#updateTimelineColumns', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelineColumns({ + id: 'foo', + columns: columnsMock, + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update a timeline with new columns', () => { + const update = updateTimelineColumns({ + id: 'foo', + columns: columnsMock, + timelineById: timelineByIdMock, + }); + expect(update.foo.columns).toEqual([...columnsMock]); + }); + }); + + describe('#updateTimelineTitleAndDescription', () => { + const newTitle = 'a new title'; + const newDescription = 'breathing room'; + + test('should return a new reference and not the same reference', () => { + const update = updateTimelineTitleAndDescription({ + id: 'foo', + description: '', + title: newTitle, + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update the timeline title and description', () => { + const update = updateTimelineTitleAndDescription({ + id: 'foo', + description: newDescription, + title: newTitle, + timelineById: timelineByIdMock, + }); + expect(update.foo.title).toEqual(newTitle); + expect(update.foo.description).toEqual(newDescription); + }); + + test('should always trim all leading whitespace', () => { + const update = updateTimelineTitleAndDescription({ + id: 'foo', + description: ' breathing room ', + title: ' room at the back ', + timelineById: timelineByIdMock, + }); + expect(update.foo.title).toEqual('room at the back'); + expect(update.foo.description).toEqual('breathing room'); + }); + }); + + describe('#updateTimelineProviders', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelineProviders({ + id: 'foo', + providers: [ + { + ...basicDataProvider, + id: '567', + name: 'data provider 2', + }, + ], + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should add update a timeline with new providers BBB', () => { + const providerToAdd: DataProvider = { + ...basicDataProvider, + id: '567', + name: 'data provider 2', + }; + const update = updateTimelineProviders({ + id: 'foo', + providers: [providerToAdd], + timelineById: timelineByIdMock, + }); + expect(update.foo.dataProviders).toEqual([providerToAdd]); + }); + }); + + describe('#updateTimelineRange', () => { + let update: TimelineById; + beforeAll(() => { + update = updateTimelineRange({ + id: 'foo', + start: '2020-07-07T08:20:18.966Z', + end: '2020-07-08T08:20:18.966Z', + timelineById: timelineByIdMock, + }); + }); + test('should return a new reference and not the same reference', () => { + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update the timeline range', () => { + expect(update.foo.dateRange).toEqual({ + start: '2020-07-07T08:20:18.966Z', + end: '2020-07-08T08:20:18.966Z', + }); + }); + }); + + describe('#updateTimelineSort', () => { + let update: TimelineById; + beforeAll(() => { + update = updateTimelineSort({ + id: 'foo', + sort: [ + { + columnId: 'some column', + columnType: 'text', + esTypes: ['keyword'], + sortDirection: Direction.desc, + }, + ], + timelineById: timelineByIdMock, + }); + }); + test('should return a new reference and not the same reference', () => { + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update the sort attribute', () => { + expect(update.foo.sort).toEqual([ + { + columnId: 'some column', + columnType: 'text', + esTypes: ['keyword'], + sortDirection: Direction.desc, + }, + ]); + }); + }); + + describe('#updateTimelineProviderEnabled', () => { + test('should return a new reference and not the same reference', () => { + const update: TimelineById = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '123', + enabled: false, // value we are updating from true to false + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should return a new reference for data provider and not the same reference of data provider', () => { + const update: TimelineById = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '123', + enabled: false, // value we are updating from true to false + timelineById: timelineByIdMock, + }); + expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); + }); + + test('should update the timeline provider enabled from true to false', () => { + const update: TimelineById = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '123', + enabled: false, // value we are updating from true to false + timelineById: timelineByIdMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + enabled: false, + }, + ], + }, + }; + expect(update).toEqual(expected); + }); + + test('should update only one data provider and not two data providers', () => { + const multiDataProvider = [...basicTimeline.dataProviders].concat({ + ...basicDataProvider, + id: '456', + }); + const multiDataProviderMock = { + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + const update = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '123', + enabled: false, // value we are updating from true to false + timelineById: multiDataProviderMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + enabled: false, + }, + { + ...basicDataProvider, + id: '456', + }, + ], + }, + }; + expect(update).toEqual(expected); + }); + }); + + describe('#updateTimelineAndProviderEnabled', () => { + let timelineByIdwithAndMock: TimelineById = timelineByIdMock; + let update: TimelineById; + beforeEach(() => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: '568', + name: 'And Data Provider', + }, + ], + id: '567', + }, + ]; + + timelineByIdwithAndMock = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + + update = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '567', + enabled: false, // value we are updating from true to false + timelineById: timelineByIdwithAndMock, + andProviderId: '568', + }); + }); + + test('should return a new reference and not the same reference', () => { + expect(update).not.toBe(timelineByIdwithAndMock); + }); + + test('should return a new reference for and data provider and not the same reference of data and provider', () => { + expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); + }); + + test('should update the timeline and provider enabled from true to false', () => { + const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); + expect(update.foo.dataProviders[indexProvider].and[0].enabled).toEqual(false); + }); + + test('should update only one and data provider and not two and data providers ahhhh', () => { + const indexProvider = timelineByIdwithAndMock.foo.dataProviders.findIndex( + (i) => i.id === '567' + ); + const multiAndDataProvider = timelineByIdwithAndMock.foo.dataProviders[ + indexProvider + ].and.concat({ + id: '456', + name: 'new and data provider', + enabled: true, + queryMatch: { + field: '', + value: '', + operator: IS_OPERATOR, + }, + + excluded: false, + kqlQuery: '', + }); + const multiAndDataProviderMock = timelineByIdwithAndMock; + multiAndDataProviderMock.foo.dataProviders[indexProvider].and = multiAndDataProvider; + update = updateTimelineProviderEnabled({ + id: 'foo', + providerId: '567', + enabled: false, // value we are updating from true to false + timelineById: multiAndDataProviderMock, + andProviderId: '568', + }); + const oldAndProvider = update.foo.dataProviders[indexProvider].and.find( + (i) => i.id === '568' + ); + const newAndProvider = update.foo.dataProviders[indexProvider].and.find( + (i) => i.id === '456' + ); + expect(oldAndProvider?.enabled).toEqual(false); + expect(newAndProvider?.enabled).toEqual(true); + }); + }); + + describe('#updateTimelineProviderExcluded', () => { + let update: TimelineById; + beforeAll(() => { + update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '123', + excluded: true, // value we are updating from false to true + timelineById: timelineByIdMock, + }); + }); + test('should return a new reference and not the same reference', () => { + expect(update).not.toBe(timelineByIdMock); + }); + + test('should return a new reference for data provider and not the same reference of data provider', () => { + expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); + }); + + test('should update the timeline provider excluded from true to false', () => { + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + excluded: true, + }, + ], + }, + }; + expect(update).toEqual(expected); + }); + + test('should update only one data provider and not two data providers', () => { + const multiDataProvider = basicTimeline.dataProviders.concat({ + ...basicDataProvider, + id: '456', + }); + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '123', + excluded: true, // value we are updating from false to true + timelineById: multiDataProviderMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + excluded: true, // value we are updating from false to true + }, + { + ...basicDataProvider, + id: '456', + }, + ], + }, + }; + expect(update).toEqual(expected); + }); + }); + + describe('#updateTimelineProviderType', () => { + test('should return the same reference if run on timelineType default', () => { + const update = updateTimelineProviderType({ + id: 'foo', + providerId: '123', + type: DataProviderType.template, // value we are updating from default to template + timelineById: timelineByIdMock, + }); + expect(update).toBe(timelineByIdMock); + }); + + test('should return a new reference and not the same reference', () => { + const update = updateTimelineProviderType({ + id: 'foo', + providerId: '123', + type: DataProviderType.template, // value we are updating from default to template + timelineById: timelineByIdTemplateMock, + }); + expect(update).not.toBe(timelineByIdTemplateMock); + }); + + test('should return a new reference for data provider and not the same reference of data provider', () => { + const update = updateTimelineProviderType({ + id: 'foo', + providerId: '123', + type: DataProviderType.template, // value we are updating from default to template + timelineById: timelineByIdTemplateMock, + }); + expect(update.foo.dataProviders).not.toBe(timelineByIdTemplateMock.foo.dataProviders); + }); + + test('should update the timeline provider type from default to template', () => { + const update = updateTimelineProviderType({ + id: 'foo', + providerId: '123', + type: DataProviderType.template, + timelineById: timelineByIdTemplateMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + name: '', + queryMatch: { + field: '', + value: '{}', + operator: IS_OPERATOR, + }, + type: DataProviderType.template, + }, + ], + timelineType: TimelineType.template, + }, + }; + + expect(update).toEqual(expected); + }); + test('should update only one data provider and not two data providers AHH', () => { + const multiDataProvider = [ + ...timelineByIdTemplateMock.foo.dataProviders, + { + ...basicDataProvider, + id: '456', + type: DataProviderType.template, + }, + ]; + + const multiDataProviderMock = { + ...timelineByIdTemplateMock, + foo: { + ...timelineByIdTemplateMock.foo, + dataProviders: multiDataProvider, + }, + }; + const update = updateTimelineProviderType({ + id: 'foo', + providerId: '123', + type: DataProviderType.template, // value we are updating from default to template + timelineById: multiDataProviderMock, + }); + const expected = [ + { + ...basicDataProvider, + name: '', + type: DataProviderType.template, + queryMatch: { + field: '', + value: '{}', + operator: IS_OPERATOR, + }, + }, + { + ...basicDataProvider, + id: '456', + type: DataProviderType.template, + }, + ]; + expect(update.foo.dataProviders).toEqual(expected); + }); + }); + + describe('#updateTimelineAndProviderExcluded', () => { + let timelineByIdwithAndMock: TimelineById = timelineByIdMock; + beforeEach(() => { + const providerToAdd: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: '568', + name: 'And Data Provider', + }, + ], + id: '567', + }, + ]; + + timelineByIdwithAndMock = addTimelineProviders({ + id: 'foo', + providers: providerToAdd, + timelineById: timelineByIdMock, + }); + }); + + test('should return a new reference and not the same reference', () => { + const update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '567', + excluded: true, // value we are updating from true to false + timelineById: timelineByIdwithAndMock, + andProviderId: '568', + }); + expect(update).not.toBe(timelineByIdwithAndMock); + }); + + test('should return a new reference for and data provider and not the same reference of data and provider', () => { + const update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '567', + excluded: true, // value we are updating from false to true + timelineById: timelineByIdwithAndMock, + andProviderId: '568', + }); + expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); + }); + + test('should update the timeline and provider excluded from true to false', () => { + const update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '567', + excluded: true, // value we are updating from true to false + timelineById: timelineByIdwithAndMock, + andProviderId: '568', + }); + const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); + expect(update.foo.dataProviders[indexProvider].and[0].enabled).toEqual(true); + }); + + test('should update only one and data provider and not two and data providers', () => { + const indexProvider = timelineByIdwithAndMock.foo.dataProviders.findIndex( + (i) => i.id === '567' + ); + const multiAndDataProvider = timelineByIdwithAndMock.foo.dataProviders[ + indexProvider + ].and.concat({ + ...basicDataProvider, + id: '456', + name: 'new and data provider', + }); + const multiAndDataProviderMock = timelineByIdwithAndMock; + multiAndDataProviderMock.foo.dataProviders[indexProvider].and = multiAndDataProvider; + const update = updateTimelineProviderExcluded({ + id: 'foo', + providerId: '567', + excluded: true, // value we are updating from true to false + timelineById: multiAndDataProviderMock, + andProviderId: '568', + }); + const oldAndProvider = update.foo.dataProviders[indexProvider].and.find( + (i) => i.id === '568' + ); + const newAndProvider = update.foo.dataProviders[indexProvider].and.find( + (i) => i.id === '456' + ); + expect(oldAndProvider?.excluded).toEqual(true); + expect(newAndProvider?.excluded).toEqual(false); + }); + }); + + describe('#updateTimelineItemsPerPage', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelineItemsPerPage({ + id: 'foo', + itemsPerPage: 10, // value we are updating from 5 to 10 + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update the items per page from 25 to 50', () => { + const update = updateTimelineItemsPerPage({ + id: 'foo', + itemsPerPage: 50, // value we are updating from 25 to 50 + timelineById: timelineByIdMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + itemsPerPage: 50, + }, + }; + expect(update).toEqual(expected); + }); + }); + + describe('#updateTimelinePerPageOptions', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelinePerPageOptions({ + id: 'foo', + itemsPerPageOptions: [100, 200, 300], // value we are updating from [5, 10, 20] + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should update the items per page options from [10, 25, 50] to [100, 200, 300]', () => { + const update = updateTimelinePerPageOptions({ + id: 'foo', + itemsPerPageOptions: [100, 200, 300], // value we are updating from [10, 25, 50] + timelineById: timelineByIdMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + itemsPerPageOptions: [100, 200, 300], // updated + }, + }; + expect(update).toEqual(expected); + }); + }); + + describe('#removeTimelineProvider', () => { + test('should return a new reference and not the same reference', () => { + const update = removeTimelineProvider({ + id: 'foo', + providerId: '123', + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should remove a timeline provider', () => { + const update = removeTimelineProvider({ + id: 'foo', + providerId: '123', + timelineById: timelineByIdMock, + }); + expect(update.foo.dataProviders).toEqual([]); + }); + + test('should remove only one data provider and not two data providers', () => { + const multiDataProvider = basicTimeline.dataProviders.concat({ + ...basicDataProvider, + id: '456', + name: 'data provider 2', + }); + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + const update = removeTimelineProvider({ + id: 'foo', + providerId: '123', + timelineById: multiDataProviderMock, + }); + const expected: TimelineById = { + foo: { + ...basicTimeline, + dataProviders: [ + { + ...basicDataProvider, + id: '456', + name: 'data provider 2', + }, + ], + }, + }; + expect(update).toEqual(expected); + }); + + test('should remove only first provider and not nested andProvider', () => { + const dataProviders: DataProvider[] = [ + { + ...basicDataProvider, + id: '111', + }, + { + ...basicDataProvider, + id: '222', + name: 'data provider 2', + }, + { + ...basicDataProvider, + id: '333', + name: 'data provider 3', + }, + ]; + + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders, + }, + }; + const andDataProvider: DataProvidersAnd = { + ...basicDataProvider, + id: '211', + name: 'And Data Provider', + }; + + const nestedMultiAndDataProviderMock = multiDataProviderMock; + multiDataProviderMock.foo.dataProviders[1].and = [andDataProvider]; + + const update = removeTimelineProvider({ + id: 'foo', + providerId: '222', + timelineById: nestedMultiAndDataProviderMock, + }); + expect(update.foo.dataProviders).toEqual([ + nestedMultiAndDataProviderMock.foo.dataProviders[0], + { ...andDataProvider, and: [] }, + nestedMultiAndDataProviderMock.foo.dataProviders[2], + ]); + }); + + test('should remove only the first provider and keep multiple nested andProviders', () => { + const multiDataProvider: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + name: 'root', + queryMatch: { + field: 'user.name', + value: 'root', + operator: ':', + }, + }, + { + ...basicDataProvider, + id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + name: 'success', + queryMatch: { + field: 'auditd.result', + value: 'success', + operator: ':', + }, + }, + ], + id: 'hosts-table-hostName-suricata-iowa', + name: 'suricata-iowa', + queryMatch: { + field: 'host.name', + value: 'suricata-iowa', + operator: ':', + }, + }, + ]; + + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + + const update = removeTimelineProvider({ + id: 'foo', + providerId: 'hosts-table-hostName-suricata-iowa', + timelineById: multiDataProviderMock, + }); + + expect(update.foo.dataProviders).toEqual([ + { + ...basicDataProvider, + id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + name: 'root', + queryMatch: { + field: 'user.name', + value: 'root', + operator: ':', + }, + and: [ + { + ...basicDataProvider, + id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + name: 'success', + queryMatch: { + field: 'auditd.result', + value: 'success', + operator: ':', + }, + }, + ], + }, + ]); + }); + test('should remove only the first AND provider when the first AND is deleted, and there are multiple andProviders', () => { + const multiDataProvider: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + name: 'root', + queryMatch: { + field: 'user.name', + value: 'root', + operator: ':', + }, + }, + { + ...basicDataProvider, + id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + name: 'success', + queryMatch: { + field: 'auditd.result', + value: 'success', + operator: ':', + }, + }, + ], + id: 'hosts-table-hostName-suricata-iowa', + name: 'suricata-iowa', + queryMatch: { + field: 'host.name', + value: 'suricata-iowa', + operator: ':', + }, + }, + ]; + + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + + const update = removeTimelineProvider({ + andProviderId: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + id: 'foo', + providerId: 'hosts-table-hostName-suricata-iowa', + timelineById: multiDataProviderMock, + }); + + expect(update.foo.dataProviders).toEqual([ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + name: 'success', + queryMatch: { + field: 'auditd.result', + value: 'success', + operator: ':', + }, + }, + ], + id: 'hosts-table-hostName-suricata-iowa', + name: 'suricata-iowa', + queryMatch: { + field: 'host.name', + value: 'suricata-iowa', + operator: ':', + }, + }, + ]); + }); + + test('should remove only the second AND provider when the second AND is deleted, and there are multiple andProviders', () => { + const multiDataProvider: DataProvider[] = [ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + name: 'root', + queryMatch: { + field: 'user.name', + value: 'root', + operator: ':', + }, + }, + { + ...basicDataProvider, + id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + name: 'success', + queryMatch: { + field: 'auditd.result', + value: 'success', + operator: ':', + }, + }, + ], + id: 'hosts-table-hostName-suricata-iowa', + name: 'suricata-iowa', + queryMatch: { + field: 'host.name', + value: 'suricata-iowa', + operator: ':', + }, + }, + ]; + + const multiDataProviderMock = { + ...timelineByIdMock, + foo: { + ...timelineByIdMock.foo, + dataProviders: multiDataProvider, + }, + }; + + const update = removeTimelineProvider({ + andProviderId: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', + id: 'foo', + providerId: 'hosts-table-hostName-suricata-iowa', + timelineById: multiDataProviderMock, + }); + + expect(update.foo.dataProviders).toEqual([ + { + ...basicDataProvider, + and: [ + { + ...basicDataProvider, + id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', + name: 'root', + queryMatch: { + field: 'user.name', + value: 'root', + operator: ':', + }, + }, + ], + id: 'hosts-table-hostName-suricata-iowa', + name: 'suricata-iowa', + queryMatch: { + field: 'host.name', + value: 'suricata-iowa', + operator: ':', + }, + }, + ]); + }); + }); + + describe('#updateGraphEventId', () => { + test('should return a new reference and not the same reference', () => { + const update = updateTimelineGraphEventId({ + id: 'foo', + graphEventId: '123', + timelineById: timelineByIdMock, + }); + expect(update).not.toBe(timelineByIdMock); + }); + + test('should empty graphEventId', () => { + const update = updateTimelineGraphEventId({ + id: 'foo', + graphEventId: '', + timelineById: timelineByIdMock, + }); + expect(update.foo.graphEventId).toEqual(''); + }); + + test('should empty graphEventId and not change activeTab and prevActiveTab because TimelineId !== TimelineId.active', () => { + const update = updateTimelineGraphEventId({ + id: 'foo', + graphEventId: '', + timelineById: timelineByIdMock, + }); + expect(update.foo.graphEventId).toEqual(''); + expect(update.foo.activeTab).toEqual(timelineByIdMock.foo.activeTab); + expect(update.foo.prevActiveTab).toEqual(timelineByIdMock.foo.prevActiveTab); + }); + + test('should empty graphEventId and return to the previous tab if TimelineId === TimelineId.active', () => { + const mock = cloneDeep(timelineByIdMock); + mock[TimelineId.active] = { + ...timelineByIdMock.foo, + activeTab: TimelineTabs.graph, + prevActiveTab: TimelineTabs.eql, + }; + delete mock.foo; + + const update = updateTimelineGraphEventId({ + id: TimelineId.active, + graphEventId: '', + timelineById: mock, + }); + + expect(update[TimelineId.active].graphEventId).toEqual(''); + expect(update[TimelineId.active].activeTab).toEqual(TimelineTabs.eql); + expect(update[TimelineId.active].prevActiveTab).toEqual(TimelineTabs.graph); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts index 81a19dde1cea..47e15be86e2a 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts @@ -7,6 +7,7 @@ import type { FilterManager } from '@kbn/data-plugin/public'; import type { Filter } from '@kbn/es-query'; +import type { SavedSearch } from '@kbn/saved-search-plugin/common'; import type { ExpandedDetailTimeline, SessionViewConfig } from '../../../../common/types'; import type { EqlOptionsSelected, @@ -135,7 +136,10 @@ export interface TimelineModel { selectAll: boolean; /* discover saved search Id */ savedSearchId: string | null; + /* local saved search object, it's not sent to the server */ + savedSearch: SavedSearch | null; isDiscoverSavedSearchLoaded?: boolean; + isDataProviderVisible: boolean; /** used to mark the timeline as unsaved in the UI */ changed?: boolean; } @@ -192,7 +196,9 @@ export type SubsetTimelineModel = Readonly< | 'filters' | 'filterManager' | 'savedSearchId' + | 'savedSearch' | 'isDiscoverSavedSearchLoaded' + | 'isDataProviderVisible' | 'changed' > >; diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts deleted file mode 100644 index 980573f0c73c..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.test.ts +++ /dev/null @@ -1,1857 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { cloneDeep } from 'lodash/fp'; -import type { ColumnHeaderOptions } from '../../../../common/types/timeline'; -import { TimelineTabs, TimelineId } from '../../../../common/types/timeline'; -import { TimelineType, TimelineStatus } from '../../../../common/api/timeline'; - -import type { - DataProvider, - DataProvidersAnd, -} from '../../components/timeline/data_providers/data_provider'; -import { - IS_OPERATOR, - DataProviderType, -} from '../../components/timeline/data_providers/data_provider'; -import { defaultColumnHeaderType } from '../../components/timeline/body/column_headers/default_headers'; -import { - DEFAULT_COLUMN_MIN_WIDTH, - RESIZED_COLUMN_MIN_WITH, -} from '../../components/timeline/body/constants'; -import { defaultHeaders } from '../../../common/mock'; - -import { - addNewTimeline, - addTimelineProviders, - addTimelineToStore, - applyDeltaToTimelineColumnWidth, - removeTimelineColumn, - removeTimelineProvider, - updateTimelineColumns, - updateTimelineItemsPerPage, - updateTimelinePerPageOptions, - updateTimelineProviderEnabled, - updateTimelineProviderExcluded, - updateTimelineProviderType, - updateTimelineProviders, - updateTimelineRange, - updateTimelineShowTimeline, - updateTimelineSort, - updateTimelineTitleAndDescription, - upsertTimelineColumn, - updateTimelineGraphEventId, -} from './helpers'; -import type { TimelineModel } from './model'; -import { timelineDefaults } from './defaults'; -import type { TimelineById } from './types'; -import { Direction } from '../../../../common/search_strategy'; -import type { FilterManager } from '@kbn/data-plugin/public'; - -jest.mock('../../../common/utils/normalize_time_range'); -jest.mock('../../../common/utils/default_date_settings', () => { - const actual = jest.requireActual('../../../common/utils/default_date_settings'); - return { - ...actual, - DEFAULT_FROM_MOMENT: new Date('2020-10-27T11:37:31.655Z'), - DEFAULT_TO_MOMENT: new Date('2020-10-28T11:37:31.655Z'), - }; -}); - -const mockFilterManager = {} as FilterManager; - -const basicDataProvider: DataProvider = { - and: [], - id: '123', - name: 'data provider 1', - enabled: true, - queryMatch: { - field: '', - value: '', - operator: IS_OPERATOR, - }, - excluded: false, - kqlQuery: '', -}; -const basicTimeline: TimelineModel = { - activeTab: TimelineTabs.query, - prevActiveTab: TimelineTabs.graph, - columns: [], - defaultColumns: [], - dataProviders: [{ ...basicDataProvider }], - dataViewId: null, - dateRange: { - start: '2020-07-07T08:20:18.966Z', - end: '2020-07-08T08:20:18.966Z', - }, - deletedEventIds: [], - description: '', - documentType: '', - eqlOptions: { - eventCategoryField: 'event.category', - tiebreakerField: '', - timestampField: '@timestamp', - }, - eventIdToNoteIds: {}, - excludedRowRendererIds: [], - expandedDetail: {}, - filterManager: mockFilterManager, - highlightedDropAndProviderId: '', - historyIds: [], - id: 'foo', - indexNames: [], - isFavorite: false, - isLive: false, - isLoading: false, - isSaving: false, - isSelectAllChecked: false, - itemsPerPage: 25, - itemsPerPageOptions: [10, 25, 50], - kqlMode: 'filter', - kqlQuery: { filterQuery: null }, - loadingEventIds: [], - noteIds: [], - pinnedEventIds: {}, - pinnedEventsSaveObject: {}, - queryFields: [], - savedObjectId: null, - selectAll: false, - selectedEventIds: {}, - sessionViewConfig: null, - show: true, - sort: [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - ], - status: TimelineStatus.active, - templateTimelineId: null, - templateTimelineVersion: null, - timelineType: TimelineType.default, - title: '', - version: null, - savedSearchId: null, -}; -const timelineByIdMock: TimelineById = { - foo: { ...basicTimeline }, -}; - -const timelineByIdTemplateMock: TimelineById = { - foo: { - ...basicTimeline, - timelineType: TimelineType.template, - }, -}; - -const columnsMock: ColumnHeaderOptions[] = [ - defaultHeaders[0], - defaultHeaders[1], - defaultHeaders[2], -]; - -describe('Timeline', () => { - describe('#add saved object Timeline to store ', () => { - test('should return a timelineModel with default value and not just a timelineResult ', () => { - const update = addTimelineToStore({ - id: 'foo', - timeline: { - ...basicTimeline, - }, - timelineById: timelineByIdMock, - }); - - expect(update).toEqual({ - foo: { - ...basicTimeline, - show: true, - }, - }); - }); - - test('should override timerange if adding an immutable template', () => { - const update = addTimelineToStore({ - id: 'foo', - timeline: { - ...basicTimeline, - status: TimelineStatus.immutable, - timelineType: TimelineType.template, - }, - timelineById: timelineByIdMock, - }); - - expect(update).toEqual({ - foo: { - ...basicTimeline, - status: TimelineStatus.immutable, - timelineType: TimelineType.template, - dateRange: { - start: '2020-10-27T11:37:31.655Z', - end: '2020-10-28T11:37:31.655Z', - }, - show: true, - }, - }); - }); - - test('should contain existing filterManager', () => { - const update = addTimelineToStore({ - id: 'foo', - timeline: { - ...basicTimeline, - status: TimelineStatus.immutable, - timelineType: TimelineType.template, - }, - timelineById: timelineByIdMock, - }); - - expect(update.foo.filterManager).toEqual(mockFilterManager); - }); - }); - - describe('#addNewTimeline', () => { - test('should return a new reference and not the same reference', () => { - const update = addNewTimeline({ - id: 'bar', - columns: defaultHeaders, - dataViewId: null, - indexNames: [], - timelineById: timelineByIdMock, - timelineType: TimelineType.default, - savedSearchId: null, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should add a new timeline', () => { - const update = addNewTimeline({ - id: 'bar', - columns: timelineDefaults.columns, - dataViewId: null, - indexNames: [], - timelineById: timelineByIdMock, - timelineType: TimelineType.default, - savedSearchId: null, - }); - expect(update).toEqual({ - foo: basicTimeline, - bar: { ...timelineDefaults, id: 'bar' }, - }); - }); - - test('should add the specified columns to the timeline', () => { - const barWithEmptyColumns = { ...timelineDefaults, id: 'bar' }; - const barWithPopulatedColumns = { ...barWithEmptyColumns, columns: defaultHeaders }; - - const update = addNewTimeline({ - id: 'bar', - columns: defaultHeaders, - dataViewId: null, - indexNames: [], - timelineById: timelineByIdMock, - timelineType: TimelineType.default, - savedSearchId: null, - }); - expect(update).toEqual({ - foo: basicTimeline, - bar: barWithPopulatedColumns, - }); - }); - }); - - describe('#updateTimelineShowTimeline', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelineShowTimeline({ - id: 'foo', - show: false, - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should change show from true to false', () => { - const update = updateTimelineShowTimeline({ - id: 'foo', - show: false, // value we are changing from true to false - timelineById: timelineByIdMock, - }); - - expect(update).toEqual({ - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - show: false, - }, - }); - }); - }); - - describe('#upsertTimelineColumn', () => { - let timelineById: TimelineById = {}; - let columns: ColumnHeaderOptions[] = []; - let columnToAdd: ColumnHeaderOptions; - let mockWithExistingColumns: TimelineById; - - beforeEach(() => { - timelineById = cloneDeep(timelineByIdMock); - columns = cloneDeep(columnsMock); - columnToAdd = { - category: 'event', - columnHeaderType: defaultColumnHeaderType, - description: - 'The action captured by the event.\nThis describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer.', - example: 'user-password-change', - id: 'event.action', - type: 'keyword', - aggregatable: true, - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, - }; - mockWithExistingColumns = { - ...timelineById, - foo: { - ...timelineById.foo, - columns, - }, - }; - }); - - test('should return a new reference and not the same reference', () => { - const update = upsertTimelineColumn({ - column: columnToAdd, - id: 'foo', - index: 0, - timelineById, - }); - - expect(update).not.toBe(timelineById); - }); - - test('should add a new column to an empty collection of columns', () => { - const expectedColumns = [columnToAdd]; - const update = upsertTimelineColumn({ - column: columnToAdd, - id: 'foo', - index: 0, - timelineById, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should add a new column to an existing collection of columns at the beginning of the collection', () => { - const expectedColumns = [columnToAdd, ...columns]; - - const update = upsertTimelineColumn({ - column: columnToAdd, - id: 'foo', - index: 0, - timelineById: mockWithExistingColumns, - }); - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should add a new column to an existing collection of columns in the middle of the collection', () => { - const expectedColumns = [columns[0], columnToAdd, columns[1], columns[2]]; - - const update = upsertTimelineColumn({ - column: columnToAdd, - id: 'foo', - index: 1, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should add a new column to an existing collection of columns at the end of the collection', () => { - const expectedColumns = [...columns, columnToAdd]; - - const update = upsertTimelineColumn({ - column: columnToAdd, - id: 'foo', - index: expectedColumns.length - 1, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - columns.forEach((column, i) => { - test(`should upsert (NOT add a new column) a column when already exists at the same index (${i})`, () => { - const update = upsertTimelineColumn({ - column, - id: 'foo', - index: i, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(columns); - }); - }); - - test('should allow the 1st column to be moved to the 2nd column', () => { - const expectedColumns = [columns[1], columns[0], columns[2]]; - - const update = upsertTimelineColumn({ - column: columns[0], - id: 'foo', - index: 1, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should allow the 1st column to be moved to the 3rd column', () => { - const expectedColumns = [columns[1], columns[2], columns[0]]; - - const update = upsertTimelineColumn({ - column: columns[0], - id: 'foo', - index: 2, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should allow the 2nd column to be moved to the 1st column', () => { - const expectedColumns = [columns[1], columns[0], columns[2]]; - - const update = upsertTimelineColumn({ - column: columns[1], - id: 'foo', - index: 0, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should allow the 2nd column to be moved to the 3rd column', () => { - const expectedColumns = [columns[0], columns[2], columns[1]]; - - const update = upsertTimelineColumn({ - column: columns[1], - id: 'foo', - index: 2, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should allow the 3rd column to be moved to the 1st column', () => { - const expectedColumns = [columns[2], columns[0], columns[1]]; - - const update = upsertTimelineColumn({ - column: columns[2], - id: 'foo', - index: 0, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should allow the 3rd column to be moved to the 2nd column', () => { - const expectedColumns = [columns[0], columns[2], columns[1]]; - - const update = upsertTimelineColumn({ - column: columns[2], - id: 'foo', - index: 1, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - }); - - describe('#addTimelineProvider', () => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - id: '567', - name: 'data provider 2', - }, - ]; - test('should return a new reference and not the same reference', () => { - const update = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should add a new timeline provider', () => { - const update = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - const addedDataProvider = [...basicTimeline.dataProviders].concat(providerToAdd); - expect(update.foo.dataProviders).toEqual(addedDataProvider); - }); - - test('should NOT add a new timeline provider if it already exists and the attributes "and" is empty', () => { - const update = addTimelineProviders({ - id: 'foo', - providers: [basicDataProvider], - timelineById: timelineByIdMock, - }); - expect(update).toEqual(timelineByIdMock); - }); - - test('should add a new timeline provider if it already exists and the attributes "and" is NOT empty', () => { - const myMockTimelineByIdMock = cloneDeep(timelineByIdMock); - myMockTimelineByIdMock.foo.dataProviders[0].and = [ - { - ...basicDataProvider, - id: '456', - name: 'and data provider 1', - }, - ]; - const providers = [{ ...basicDataProvider }]; - const update = addTimelineProviders({ - id: 'foo', - providers, - timelineById: myMockTimelineByIdMock, - }); - expect(update.foo.dataProviders[1]).toEqual(providers[0]); - }); - - test('should UPSERT an existing timeline provider if it already exists', () => { - const update = addTimelineProviders({ - id: 'foo', - providers: [ - { - ...basicDataProvider, - name: 'my name changed', - }, - ], - timelineById: timelineByIdMock, - }); - expect(update.foo.dataProviders[0].name).toEqual('my name changed'); - }); - }); - - describe('#removeTimelineColumn', () => { - let mockWithExistingColumns: TimelineById; - beforeEach(() => { - mockWithExistingColumns = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - columns: columnsMock, - }, - }; - }); - test('should return a new reference and not the same reference', () => { - const update = removeTimelineColumn({ - id: 'foo', - columnId: columnsMock[0].id, - timelineById: mockWithExistingColumns, - }); - - expect(update).not.toBe(timelineByIdMock); - }); - - test('should remove just the first column when the id matches', () => { - const expectedColumns = [columnsMock[1], columnsMock[2]]; - - const update = removeTimelineColumn({ - id: 'foo', - columnId: columnsMock[0].id, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should remove just the last column when the id matches', () => { - const expectedColumns = [columnsMock[0], columnsMock[1]]; - - const update = removeTimelineColumn({ - id: 'foo', - columnId: columnsMock[2].id, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should remove just the middle column when the id matches', () => { - const expectedColumns = [columnsMock[0], columnsMock[2]]; - - const update = removeTimelineColumn({ - id: 'foo', - columnId: columnsMock[1].id, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should not modify the columns if the id to remove was not found', () => { - const expectedColumns = cloneDeep(columnsMock); - - const update = removeTimelineColumn({ - id: 'foo', - columnId: 'does.not.exist', - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - }); - - describe('#applyDeltaToColumnWidth', () => { - let mockWithExistingColumns: TimelineById; - beforeEach(() => { - mockWithExistingColumns = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - columns: columnsMock, - }, - }; - }); - test('should return a new reference and not the same reference', () => { - const delta = 50; - const update = applyDeltaToTimelineColumnWidth({ - id: 'foo', - columnId: columnsMock[0].id, - delta, - timelineById: mockWithExistingColumns, - }); - - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update initialWidth with the specified delta when the delta is positive', () => { - const aDateColumn = columnsMock[0]; - const delta = 50; - const expectedToHaveNewWidth = { - ...aDateColumn, - initialWidth: Number(aDateColumn.initialWidth) + 50, - }; - const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; - - const update = applyDeltaToTimelineColumnWidth({ - id: 'foo', - columnId: aDateColumn.id, - delta, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should update initialWidth with the specified delta when the delta is negative, and the resulting width is greater than the min column width', () => { - const aDateColumn = columnsMock[0]; - const delta = 50 * -1; // the result will still be above the min column size - const expectedToHaveNewWidth = { - ...aDateColumn, - initialWidth: Number(aDateColumn.initialWidth) - 50, - }; - const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; - - const update = applyDeltaToTimelineColumnWidth({ - id: 'foo', - columnId: aDateColumn.id, - delta, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - - test('should set initialWidth to `RESIZED_COLUMN_MIN_WITH` when the requested delta results in a column that is too small ', () => { - const aDateColumn = columnsMock[0]; - const delta = (Number(aDateColumn.initialWidth) - 5) * -1; // the requested delta would result in a width of just 5 pixels, which is too small - const expectedToHaveNewWidth = { - ...aDateColumn, - initialWidth: RESIZED_COLUMN_MIN_WITH, // we expect the minimum - }; - const expectedColumns = [expectedToHaveNewWidth, columnsMock[1], columnsMock[2]]; - - const update = applyDeltaToTimelineColumnWidth({ - id: 'foo', - columnId: aDateColumn.id, - delta, - timelineById: mockWithExistingColumns, - }); - - expect(update.foo.columns).toEqual(expectedColumns); - }); - }); - - describe('#addAndProviderToTimelineProvider', () => { - test('should add a new and provider to an existing timeline provider', () => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - id: '567', - name: 'data provider 2', - queryMatch: { - field: 'handsome', - value: 'xavier', - operator: IS_OPERATOR, - }, - }, - ]; - - const newTimeline = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - - newTimeline.foo.highlightedDropAndProviderId = '567'; - - const andProviderToAdd: DataProvider[] = [ - { - ...basicDataProvider, - id: '568', - name: 'And Data Provider', - queryMatch: { - field: 'smart', - value: 'steph', - operator: IS_OPERATOR, - }, - }, - ]; - - const update = addTimelineProviders({ - id: 'foo', - providers: andProviderToAdd, - timelineById: newTimeline, - }); - const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); - const addedAndDataProvider = update.foo.dataProviders[indexProvider].and[0]; - const { and, ...expectedResult } = andProviderToAdd[0]; - expect(addedAndDataProvider).toEqual(expectedResult); - newTimeline.foo.highlightedDropAndProviderId = ''; - }); - - test('should add another and provider because it is not a duplicate', () => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: '568', - name: 'And Data Provider', - queryMatch: { - field: 'smart', - value: 'xavier', - operator: IS_OPERATOR, - }, - }, - ], - id: '567', - queryMatch: { - field: 'handsome', - value: 'steph', - operator: IS_OPERATOR, - }, - }, - ]; - - const newTimeline = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - - newTimeline.foo.highlightedDropAndProviderId = '567'; - - const andProviderToAdd: DataProvider[] = [ - { - ...basicDataProvider, - id: '569', - name: 'And Data Provider', - queryMatch: { - field: 'happy', - value: 'andrewG', - operator: IS_OPERATOR, - }, - }, - ]; - // temporary, we will have to decouple DataProvider & DataProvidersAnd - // that's bigger a refactor than just fixing a bug - // @ts-expect-error - delete andProviderToAdd[0].and; - const update = addTimelineProviders({ - id: 'foo', - providers: andProviderToAdd, - timelineById: newTimeline, - }); - - expect(update.foo.dataProviders[1].and[1]).toEqual(andProviderToAdd[0]); - newTimeline.foo.highlightedDropAndProviderId = ''; - }); - - test('should NOT add another and provider because it is a duplicate', () => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: '568', - name: 'And Data Provider', - queryMatch: { - field: 'smart', - value: 'xavier', - operator: IS_OPERATOR, - }, - }, - ], - id: '567', - queryMatch: { - field: 'handsome', - value: 'steph', - operator: IS_OPERATOR, - }, - }, - ]; - - const newTimeline = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - - newTimeline.foo.highlightedDropAndProviderId = '567'; - - const andProviderToAdd: DataProvider[] = [ - { - ...basicDataProvider, - id: '569', - name: 'And Data Provider', - queryMatch: { - field: 'smart', - value: 'xavier', - operator: IS_OPERATOR, - }, - }, - ]; - const update = addTimelineProviders({ - id: 'foo', - providers: andProviderToAdd, - timelineById: newTimeline, - }); - - expect(update).toEqual(newTimeline); - newTimeline.foo.highlightedDropAndProviderId = ''; - }); - }); - - describe('#updateTimelineColumns', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelineColumns({ - id: 'foo', - columns: columnsMock, - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update a timeline with new columns', () => { - const update = updateTimelineColumns({ - id: 'foo', - columns: columnsMock, - timelineById: timelineByIdMock, - }); - expect(update.foo.columns).toEqual([...columnsMock]); - }); - }); - - describe('#updateTimelineTitleAndDescription', () => { - const newTitle = 'a new title'; - const newDescription = 'breathing room'; - - test('should return a new reference and not the same reference', () => { - const update = updateTimelineTitleAndDescription({ - id: 'foo', - description: '', - title: newTitle, - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update the timeline title and description', () => { - const update = updateTimelineTitleAndDescription({ - id: 'foo', - description: newDescription, - title: newTitle, - timelineById: timelineByIdMock, - }); - expect(update.foo.title).toEqual(newTitle); - expect(update.foo.description).toEqual(newDescription); - }); - - test('should always trim all leading whitespace', () => { - const update = updateTimelineTitleAndDescription({ - id: 'foo', - description: ' breathing room ', - title: ' room at the back ', - timelineById: timelineByIdMock, - }); - expect(update.foo.title).toEqual('room at the back'); - expect(update.foo.description).toEqual('breathing room'); - }); - }); - - describe('#updateTimelineProviders', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelineProviders({ - id: 'foo', - providers: [ - { - ...basicDataProvider, - id: '567', - name: 'data provider 2', - }, - ], - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should add update a timeline with new providers BBB', () => { - const providerToAdd: DataProvider = { - ...basicDataProvider, - id: '567', - name: 'data provider 2', - }; - const update = updateTimelineProviders({ - id: 'foo', - providers: [providerToAdd], - timelineById: timelineByIdMock, - }); - expect(update.foo.dataProviders).toEqual([providerToAdd]); - }); - }); - - describe('#updateTimelineRange', () => { - let update: TimelineById; - beforeAll(() => { - update = updateTimelineRange({ - id: 'foo', - start: '2020-07-07T08:20:18.966Z', - end: '2020-07-08T08:20:18.966Z', - timelineById: timelineByIdMock, - }); - }); - test('should return a new reference and not the same reference', () => { - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update the timeline range', () => { - expect(update.foo.dateRange).toEqual({ - start: '2020-07-07T08:20:18.966Z', - end: '2020-07-08T08:20:18.966Z', - }); - }); - }); - - describe('#updateTimelineSort', () => { - let update: TimelineById; - beforeAll(() => { - update = updateTimelineSort({ - id: 'foo', - sort: [ - { - columnId: 'some column', - columnType: 'text', - esTypes: ['keyword'], - sortDirection: Direction.desc, - }, - ], - timelineById: timelineByIdMock, - }); - }); - test('should return a new reference and not the same reference', () => { - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update the sort attribute', () => { - expect(update.foo.sort).toEqual([ - { - columnId: 'some column', - columnType: 'text', - esTypes: ['keyword'], - sortDirection: Direction.desc, - }, - ]); - }); - }); - - describe('#updateTimelineProviderEnabled', () => { - test('should return a new reference and not the same reference', () => { - const update: TimelineById = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '123', - enabled: false, // value we are updating from true to false - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should return a new reference for data provider and not the same reference of data provider', () => { - const update: TimelineById = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '123', - enabled: false, // value we are updating from true to false - timelineById: timelineByIdMock, - }); - expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); - }); - - test('should update the timeline provider enabled from true to false', () => { - const update: TimelineById = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '123', - enabled: false, // value we are updating from true to false - timelineById: timelineByIdMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - enabled: false, - }, - ], - }, - }; - expect(update).toEqual(expected); - }); - - test('should update only one data provider and not two data providers', () => { - const multiDataProvider = [...basicTimeline.dataProviders].concat({ - ...basicDataProvider, - id: '456', - }); - const multiDataProviderMock = { - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - const update = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '123', - enabled: false, // value we are updating from true to false - timelineById: multiDataProviderMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - enabled: false, - }, - { - ...basicDataProvider, - id: '456', - }, - ], - }, - }; - expect(update).toEqual(expected); - }); - }); - - describe('#updateTimelineAndProviderEnabled', () => { - let timelineByIdwithAndMock: TimelineById = timelineByIdMock; - let update: TimelineById; - beforeEach(() => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: '568', - name: 'And Data Provider', - }, - ], - id: '567', - }, - ]; - - timelineByIdwithAndMock = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - - update = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '567', - enabled: false, // value we are updating from true to false - timelineById: timelineByIdwithAndMock, - andProviderId: '568', - }); - }); - - test('should return a new reference and not the same reference', () => { - expect(update).not.toBe(timelineByIdwithAndMock); - }); - - test('should return a new reference for and data provider and not the same reference of data and provider', () => { - expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); - }); - - test('should update the timeline and provider enabled from true to false', () => { - const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); - expect(update.foo.dataProviders[indexProvider].and[0].enabled).toEqual(false); - }); - - test('should update only one and data provider and not two and data providers ahhhh', () => { - const indexProvider = timelineByIdwithAndMock.foo.dataProviders.findIndex( - (i) => i.id === '567' - ); - const multiAndDataProvider = timelineByIdwithAndMock.foo.dataProviders[ - indexProvider - ].and.concat({ - id: '456', - name: 'new and data provider', - enabled: true, - queryMatch: { - field: '', - value: '', - operator: IS_OPERATOR, - }, - - excluded: false, - kqlQuery: '', - }); - const multiAndDataProviderMock = timelineByIdwithAndMock; - multiAndDataProviderMock.foo.dataProviders[indexProvider].and = multiAndDataProvider; - update = updateTimelineProviderEnabled({ - id: 'foo', - providerId: '567', - enabled: false, // value we are updating from true to false - timelineById: multiAndDataProviderMock, - andProviderId: '568', - }); - const oldAndProvider = update.foo.dataProviders[indexProvider].and.find( - (i) => i.id === '568' - ); - const newAndProvider = update.foo.dataProviders[indexProvider].and.find( - (i) => i.id === '456' - ); - expect(oldAndProvider?.enabled).toEqual(false); - expect(newAndProvider?.enabled).toEqual(true); - }); - }); - - describe('#updateTimelineProviderExcluded', () => { - let update: TimelineById; - beforeAll(() => { - update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '123', - excluded: true, // value we are updating from false to true - timelineById: timelineByIdMock, - }); - }); - test('should return a new reference and not the same reference', () => { - expect(update).not.toBe(timelineByIdMock); - }); - - test('should return a new reference for data provider and not the same reference of data provider', () => { - expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); - }); - - test('should update the timeline provider excluded from true to false', () => { - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - excluded: true, - }, - ], - }, - }; - expect(update).toEqual(expected); - }); - - test('should update only one data provider and not two data providers', () => { - const multiDataProvider = basicTimeline.dataProviders.concat({ - ...basicDataProvider, - id: '456', - }); - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '123', - excluded: true, // value we are updating from false to true - timelineById: multiDataProviderMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - excluded: true, // value we are updating from false to true - }, - { - ...basicDataProvider, - id: '456', - }, - ], - }, - }; - expect(update).toEqual(expected); - }); - }); - - describe('#updateTimelineProviderType', () => { - test('should return the same reference if run on timelineType default', () => { - const update = updateTimelineProviderType({ - id: 'foo', - providerId: '123', - type: DataProviderType.template, // value we are updating from default to template - timelineById: timelineByIdMock, - }); - expect(update).toBe(timelineByIdMock); - }); - - test('should return a new reference and not the same reference', () => { - const update = updateTimelineProviderType({ - id: 'foo', - providerId: '123', - type: DataProviderType.template, // value we are updating from default to template - timelineById: timelineByIdTemplateMock, - }); - expect(update).not.toBe(timelineByIdTemplateMock); - }); - - test('should return a new reference for data provider and not the same reference of data provider', () => { - const update = updateTimelineProviderType({ - id: 'foo', - providerId: '123', - type: DataProviderType.template, // value we are updating from default to template - timelineById: timelineByIdTemplateMock, - }); - expect(update.foo.dataProviders).not.toBe(timelineByIdTemplateMock.foo.dataProviders); - }); - - test('should update the timeline provider type from default to template', () => { - const update = updateTimelineProviderType({ - id: 'foo', - providerId: '123', - type: DataProviderType.template, - timelineById: timelineByIdTemplateMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - name: '', - queryMatch: { - field: '', - value: '{}', - operator: IS_OPERATOR, - }, - type: DataProviderType.template, - }, - ], - timelineType: TimelineType.template, - }, - }; - - expect(update).toEqual(expected); - }); - test('should update only one data provider and not two data providers AHH', () => { - const multiDataProvider = [ - ...timelineByIdTemplateMock.foo.dataProviders, - { - ...basicDataProvider, - id: '456', - type: DataProviderType.template, - }, - ]; - - const multiDataProviderMock = { - ...timelineByIdTemplateMock, - foo: { - ...timelineByIdTemplateMock.foo, - dataProviders: multiDataProvider, - }, - }; - const update = updateTimelineProviderType({ - id: 'foo', - providerId: '123', - type: DataProviderType.template, // value we are updating from default to template - timelineById: multiDataProviderMock, - }); - const expected = [ - { - ...basicDataProvider, - name: '', - type: DataProviderType.template, - queryMatch: { - field: '', - value: '{}', - operator: IS_OPERATOR, - }, - }, - { - ...basicDataProvider, - id: '456', - type: DataProviderType.template, - }, - ]; - expect(update.foo.dataProviders).toEqual(expected); - }); - }); - - describe('#updateTimelineAndProviderExcluded', () => { - let timelineByIdwithAndMock: TimelineById = timelineByIdMock; - beforeEach(() => { - const providerToAdd: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: '568', - name: 'And Data Provider', - }, - ], - id: '567', - }, - ]; - - timelineByIdwithAndMock = addTimelineProviders({ - id: 'foo', - providers: providerToAdd, - timelineById: timelineByIdMock, - }); - }); - - test('should return a new reference and not the same reference', () => { - const update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '567', - excluded: true, // value we are updating from true to false - timelineById: timelineByIdwithAndMock, - andProviderId: '568', - }); - expect(update).not.toBe(timelineByIdwithAndMock); - }); - - test('should return a new reference for and data provider and not the same reference of data and provider', () => { - const update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '567', - excluded: true, // value we are updating from false to true - timelineById: timelineByIdwithAndMock, - andProviderId: '568', - }); - expect(update.foo.dataProviders).not.toBe(basicTimeline.dataProviders); - }); - - test('should update the timeline and provider excluded from true to false', () => { - const update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '567', - excluded: true, // value we are updating from true to false - timelineById: timelineByIdwithAndMock, - andProviderId: '568', - }); - const indexProvider = update.foo.dataProviders.findIndex((i) => i.id === '567'); - expect(update.foo.dataProviders[indexProvider].and[0].enabled).toEqual(true); - }); - - test('should update only one and data provider and not two and data providers', () => { - const indexProvider = timelineByIdwithAndMock.foo.dataProviders.findIndex( - (i) => i.id === '567' - ); - const multiAndDataProvider = timelineByIdwithAndMock.foo.dataProviders[ - indexProvider - ].and.concat({ - ...basicDataProvider, - id: '456', - name: 'new and data provider', - }); - const multiAndDataProviderMock = timelineByIdwithAndMock; - multiAndDataProviderMock.foo.dataProviders[indexProvider].and = multiAndDataProvider; - const update = updateTimelineProviderExcluded({ - id: 'foo', - providerId: '567', - excluded: true, // value we are updating from true to false - timelineById: multiAndDataProviderMock, - andProviderId: '568', - }); - const oldAndProvider = update.foo.dataProviders[indexProvider].and.find( - (i) => i.id === '568' - ); - const newAndProvider = update.foo.dataProviders[indexProvider].and.find( - (i) => i.id === '456' - ); - expect(oldAndProvider?.excluded).toEqual(true); - expect(newAndProvider?.excluded).toEqual(false); - }); - }); - - describe('#updateTimelineItemsPerPage', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelineItemsPerPage({ - id: 'foo', - itemsPerPage: 10, // value we are updating from 5 to 10 - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update the items per page from 25 to 50', () => { - const update = updateTimelineItemsPerPage({ - id: 'foo', - itemsPerPage: 50, // value we are updating from 25 to 50 - timelineById: timelineByIdMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - itemsPerPage: 50, - }, - }; - expect(update).toEqual(expected); - }); - }); - - describe('#updateTimelinePerPageOptions', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelinePerPageOptions({ - id: 'foo', - itemsPerPageOptions: [100, 200, 300], // value we are updating from [5, 10, 20] - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should update the items per page options from [10, 25, 50] to [100, 200, 300]', () => { - const update = updateTimelinePerPageOptions({ - id: 'foo', - itemsPerPageOptions: [100, 200, 300], // value we are updating from [10, 25, 50] - timelineById: timelineByIdMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - itemsPerPageOptions: [100, 200, 300], // updated - }, - }; - expect(update).toEqual(expected); - }); - }); - - describe('#removeTimelineProvider', () => { - test('should return a new reference and not the same reference', () => { - const update = removeTimelineProvider({ - id: 'foo', - providerId: '123', - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should remove a timeline provider', () => { - const update = removeTimelineProvider({ - id: 'foo', - providerId: '123', - timelineById: timelineByIdMock, - }); - expect(update.foo.dataProviders).toEqual([]); - }); - - test('should remove only one data provider and not two data providers', () => { - const multiDataProvider = basicTimeline.dataProviders.concat({ - ...basicDataProvider, - id: '456', - name: 'data provider 2', - }); - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - const update = removeTimelineProvider({ - id: 'foo', - providerId: '123', - timelineById: multiDataProviderMock, - }); - const expected: TimelineById = { - foo: { - ...basicTimeline, - dataProviders: [ - { - ...basicDataProvider, - id: '456', - name: 'data provider 2', - }, - ], - }, - }; - expect(update).toEqual(expected); - }); - - test('should remove only first provider and not nested andProvider', () => { - const dataProviders: DataProvider[] = [ - { - ...basicDataProvider, - id: '111', - }, - { - ...basicDataProvider, - id: '222', - name: 'data provider 2', - }, - { - ...basicDataProvider, - id: '333', - name: 'data provider 3', - }, - ]; - - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders, - }, - }; - const andDataProvider: DataProvidersAnd = { - ...basicDataProvider, - id: '211', - name: 'And Data Provider', - }; - - const nestedMultiAndDataProviderMock = multiDataProviderMock; - multiDataProviderMock.foo.dataProviders[1].and = [andDataProvider]; - - const update = removeTimelineProvider({ - id: 'foo', - providerId: '222', - timelineById: nestedMultiAndDataProviderMock, - }); - expect(update.foo.dataProviders).toEqual([ - nestedMultiAndDataProviderMock.foo.dataProviders[0], - { ...andDataProvider, and: [] }, - nestedMultiAndDataProviderMock.foo.dataProviders[2], - ]); - }); - - test('should remove only the first provider and keep multiple nested andProviders', () => { - const multiDataProvider: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - name: 'root', - queryMatch: { - field: 'user.name', - value: 'root', - operator: ':', - }, - }, - { - ...basicDataProvider, - id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - name: 'success', - queryMatch: { - field: 'auditd.result', - value: 'success', - operator: ':', - }, - }, - ], - id: 'hosts-table-hostName-suricata-iowa', - name: 'suricata-iowa', - queryMatch: { - field: 'host.name', - value: 'suricata-iowa', - operator: ':', - }, - }, - ]; - - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - - const update = removeTimelineProvider({ - id: 'foo', - providerId: 'hosts-table-hostName-suricata-iowa', - timelineById: multiDataProviderMock, - }); - - expect(update.foo.dataProviders).toEqual([ - { - ...basicDataProvider, - id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - name: 'root', - queryMatch: { - field: 'user.name', - value: 'root', - operator: ':', - }, - and: [ - { - ...basicDataProvider, - id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - name: 'success', - queryMatch: { - field: 'auditd.result', - value: 'success', - operator: ':', - }, - }, - ], - }, - ]); - }); - test('should remove only the first AND provider when the first AND is deleted, and there are multiple andProviders', () => { - const multiDataProvider: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - name: 'root', - queryMatch: { - field: 'user.name', - value: 'root', - operator: ':', - }, - }, - { - ...basicDataProvider, - id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - name: 'success', - queryMatch: { - field: 'auditd.result', - value: 'success', - operator: ':', - }, - }, - ], - id: 'hosts-table-hostName-suricata-iowa', - name: 'suricata-iowa', - queryMatch: { - field: 'host.name', - value: 'suricata-iowa', - operator: ':', - }, - }, - ]; - - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - - const update = removeTimelineProvider({ - andProviderId: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - id: 'foo', - providerId: 'hosts-table-hostName-suricata-iowa', - timelineById: multiDataProviderMock, - }); - - expect(update.foo.dataProviders).toEqual([ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - name: 'success', - queryMatch: { - field: 'auditd.result', - value: 'success', - operator: ':', - }, - }, - ], - id: 'hosts-table-hostName-suricata-iowa', - name: 'suricata-iowa', - queryMatch: { - field: 'host.name', - value: 'suricata-iowa', - operator: ':', - }, - }, - ]); - }); - - test('should remove only the second AND provider when the second AND is deleted, and there are multiple andProviders', () => { - const multiDataProvider: DataProvider[] = [ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - name: 'root', - queryMatch: { - field: 'user.name', - value: 'root', - operator: ':', - }, - }, - { - ...basicDataProvider, - id: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - name: 'success', - queryMatch: { - field: 'auditd.result', - value: 'success', - operator: ':', - }, - }, - ], - id: 'hosts-table-hostName-suricata-iowa', - name: 'suricata-iowa', - queryMatch: { - field: 'host.name', - value: 'suricata-iowa', - operator: ':', - }, - }, - ]; - - const multiDataProviderMock = { - ...timelineByIdMock, - foo: { - ...timelineByIdMock.foo, - dataProviders: multiDataProvider, - }, - }; - - const update = removeTimelineProvider({ - andProviderId: 'executed-yioH7GoB9v5HJNSHKnp5-auditd_result-success', - id: 'foo', - providerId: 'hosts-table-hostName-suricata-iowa', - timelineById: multiDataProviderMock, - }); - - expect(update.foo.dataProviders).toEqual([ - { - ...basicDataProvider, - and: [ - { - ...basicDataProvider, - id: 'socket_closed-MSoH7GoB9v5HJNSHRYj1-user_name-root', - name: 'root', - queryMatch: { - field: 'user.name', - value: 'root', - operator: ':', - }, - }, - ], - id: 'hosts-table-hostName-suricata-iowa', - name: 'suricata-iowa', - queryMatch: { - field: 'host.name', - value: 'suricata-iowa', - operator: ':', - }, - }, - ]); - }); - }); - - describe('#updateGraphEventId', () => { - test('should return a new reference and not the same reference', () => { - const update = updateTimelineGraphEventId({ - id: 'foo', - graphEventId: '123', - timelineById: timelineByIdMock, - }); - expect(update).not.toBe(timelineByIdMock); - }); - - test('should empty graphEventId', () => { - const update = updateTimelineGraphEventId({ - id: 'foo', - graphEventId: '', - timelineById: timelineByIdMock, - }); - expect(update.foo.graphEventId).toEqual(''); - }); - - test('should empty graphEventId and not change activeTab and prevActiveTab because TimelineId !== TimelineId.active', () => { - const update = updateTimelineGraphEventId({ - id: 'foo', - graphEventId: '', - timelineById: timelineByIdMock, - }); - expect(update.foo.graphEventId).toEqual(''); - expect(update.foo.activeTab).toEqual(timelineByIdMock.foo.activeTab); - expect(update.foo.prevActiveTab).toEqual(timelineByIdMock.foo.prevActiveTab); - }); - - test('should empty graphEventId and return to the previous tab if TimelineId === TimelineId.active', () => { - const mock = cloneDeep(timelineByIdMock); - mock[TimelineId.active] = { - ...timelineByIdMock.foo, - activeTab: TimelineTabs.graph, - prevActiveTab: TimelineTabs.eql, - }; - delete mock.foo; - - const update = updateTimelineGraphEventId({ - id: TimelineId.active, - graphEventId: '', - timelineById: mock, - }); - - expect(update[TimelineId.active].graphEventId).toEqual(''); - expect(update[TimelineId.active].activeTab).toEqual(TimelineTabs.eql); - expect(update[TimelineId.active].prevActiveTab).toEqual(TimelineTabs.graph); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts index 7da0d41fe895..6947b207874a 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts @@ -58,7 +58,10 @@ import { clearEventsDeleted, clearEventsLoading, updateSavedSearchId, + updateSavedSearch, + initializeSavedSearch, setIsDiscoverSavedSearchLoaded, + setDataProviderVisibility, setChanged, } from './actions'; @@ -520,6 +523,26 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState) }, }, })) + .case(initializeSavedSearch, (state, { id, savedSearch }) => ({ + ...state, + timelineById: { + ...state.timelineById, + [id]: { + ...state.timelineById[id], + savedSearch, + }, + }, + })) + .case(updateSavedSearch, (state, { id, savedSearch }) => ({ + ...state, + timelineById: { + ...state.timelineById, + [id]: { + ...state.timelineById[id], + savedSearch, + }, + }, + })) .case(setIsDiscoverSavedSearchLoaded, (state, { id, isDiscoverSavedSearchLoaded }) => ({ ...state, timelineById: { @@ -530,6 +553,18 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState) }, }, })) + .case(setDataProviderVisibility, (state, { id, isDataProviderVisible }) => { + return { + ...state, + timelineById: { + ...state.timelineById, + [id]: { + ...state.timelineById[id], + isDataProviderVisible, + }, + }, + }; + }) .case(setChanged, (state, { id, changed }) => ({ ...state, timelineById: { diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts index a62af5f4f589..d4078373aaff 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts @@ -54,3 +54,6 @@ export const getKqlFilterKuerySelector = () => ? timeline.kqlQuery.filterQuery.kuery : null ); + +export const dataProviderVisibilitySelector = () => + createSelector(selectTimeline, (timeline) => timeline.isDataProviderVisible); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts index 365196a22844..cd55fb83335d 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type { Action } from 'redux'; import type { Observable } from 'rxjs'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -40,14 +39,6 @@ export interface TimelineState { insertTimeline: InsertTimeline | null; } -export interface ActionTimeline extends Action { - payload: { - id: string; - eventId: string; - noteId: string; - }; -} - export interface TimelineEpicDependencies { timelineByIdSelector: (state: State) => TimelineById; timelineTimeRangeSelector: (state: State) => inputsModel.TimeRange; diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 0dcd00d3db78..16a75ce10526 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -81,7 +81,7 @@ import type { BreadcrumbsNav } from './common/breadcrumbs/types'; import type { TopValuesPopoverService } from './app/components/top_values_popover/top_values_popover_service'; import type { ExperimentalFeatures } from '../common/experimental_features'; import type { DeepLinksFormatter } from './common/links/deep_links'; -import type { SetComponents, GetComponent$ } from './contract_components'; +import type { SetComponents, GetComponents$ } from './contract_components'; import type { ConfigSettings } from '../common/config_settings'; export interface SetupPlugins { @@ -147,7 +147,7 @@ export interface StartPluginsDependencies extends StartPlugins { export interface ContractStartServices { extraRoutes$: Observable; - getComponent$: GetComponent$; + getComponents$: GetComponents$; upselling: UpsellingService; } diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader.js b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader.js new file mode 100644 index 000000000000..050be8e0cf07 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../src/setup_node_env'); +require('./agent_downloader_cli').cli(); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/agent_downloader.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/agent_downloader.ts new file mode 100644 index 000000000000..ab1da6a3f208 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/agent_downloader.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ok } from 'assert'; +import type { RunFn } from '@kbn/dev-cli-runner'; +import type { ToolingLog } from '@kbn/tooling-log'; +import { getAgentDownloadUrl, getAgentFileName } from '../common/fleet_services'; +import { downloadAndStoreAgent } from '../common/agent_downloads_service'; + +const downloadAndStoreElasticAgent = async ( + version: string, + closestMatch: boolean, + log: ToolingLog +) => { + const downloadUrlResponse = await getAgentDownloadUrl(version, closestMatch, log); + const fileNameNoExtension = getAgentFileName(version); + const agentFile = `${fileNameNoExtension}.tar.gz`; + await downloadAndStoreAgent(downloadUrlResponse.url, agentFile); +}; + +export const agentDownloaderRunner: RunFn = async (cliContext) => { + ok(cliContext.flags.version, 'version argument is required'); + await downloadAndStoreElasticAgent( + cliContext.flags.version as string, + cliContext.flags.closestMatch as boolean, + cliContext.log + ); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/index.ts new file mode 100644 index 000000000000..7cc6988b63de --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_downloader_cli/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { run } from '@kbn/dev-cli-runner'; +import { agentDownloaderRunner } from './agent_downloader'; + +export const cli = () => { + run( + agentDownloaderRunner, + + // Options + { + description: `Elastic Agent downloader`, + flags: { + string: ['version'], + boolean: ['closestMatch'], + default: { + closestMatch: true, + }, + help: ` + --version Required. Elastic agent version to be downloaded. + --closestMatch Optional. Use closest elastic agent version to match with. + `, + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/agent_downloads_service.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/agent_downloads_service.ts index 34f473a85446..410ddd65cf84 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/agent_downloads_service.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/agent_downloads_service.ts @@ -64,8 +64,10 @@ class AgentDownloadStorage extends SettingsStorage } } - public getPathsForUrl(agentDownloadUrl: string): DownloadedAgentInfo { - const filename = agentDownloadUrl.replace(/^https?:\/\//gi, '').replace(/\//g, '#'); + public getPathsForUrl(agentDownloadUrl: string, agentFileName?: string): DownloadedAgentInfo { + const filename = agentFileName + ? agentFileName + : agentDownloadUrl.replace(/^https?:\/\//gi, '').replace(/\//g, '#'); const directory = this.downloadsDirFullPath; const fullFilePath = this.buildPath(join(this.downloadsDirName, filename)); @@ -76,14 +78,17 @@ class AgentDownloadStorage extends SettingsStorage }; } - public async downloadAndStore(agentDownloadUrl: string): Promise { + public async downloadAndStore( + agentDownloadUrl: string, + agentFileName?: string + ): Promise { this.log.debug(`Downloading and storing: ${agentDownloadUrl}`); // TODO: should we add "retry" attempts to file downloads? await this.ensureExists(); - const newDownloadInfo = this.getPathsForUrl(agentDownloadUrl); + const newDownloadInfo = this.getPathsForUrl(agentDownloadUrl, agentFileName); // If download is already present on disk, then just return that info. No need to re-download it if (fs.existsSync(newDownloadInfo.fullFilePath)) { @@ -154,6 +159,18 @@ class AgentDownloadStorage extends SettingsStorage return response; } + + public isAgentDownloadFromDiskAvailable(filename: string): DownloadedAgentInfo | undefined { + if (fs.existsSync(join(this.downloadsDirFullPath, filename))) { + return { + filename, + /** The local directory where downloads are stored */ + directory: this.downloadsDirFullPath, + /** The full local file path and name */ + fullFilePath: join(this.downloadsDirFullPath, filename), + }; + } + } } const handleProcessInterruptions = async ( @@ -203,11 +220,16 @@ export interface DownloadAndStoreAgentResponse extends DownloadedAgentInfo { * already exists on disk, then no download is actually done - the information about the cached * version is returned instead * @param agentDownloadUrl + * @param agentFileName */ export const downloadAndStoreAgent = async ( - agentDownloadUrl: string + agentDownloadUrl: string, + agentFileName?: string ): Promise => { - const downloadedAgent = await agentDownloadsClient.downloadAndStore(agentDownloadUrl); + const downloadedAgent = await agentDownloadsClient.downloadAndStore( + agentDownloadUrl, + agentFileName + ); return { url: agentDownloadUrl, @@ -221,3 +243,9 @@ export const downloadAndStoreAgent = async ( export const cleanupDownloads = async (): ReturnType => { return agentDownloadsClient.cleanupDownloads(); }; + +export const isAgentDownloadFromDiskAvailable = ( + fileName: string +): DownloadedAgentInfo | undefined => { + return agentDownloadsClient.isAgentDownloadFromDiskAvailable(fileName); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts index 26ca9d647439..6477bfc3bebe 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts @@ -373,6 +373,16 @@ export const getAgentVersionMatchingCurrentStack = async ( return version; }; +// Generates a file name using system arch and an agent version. +export const getAgentFileName = (agentVersion: string): string => { + const downloadArch = + { arm64: 'arm64', x64: 'x86_64' }[process.arch as string] ?? + `UNSUPPORTED_ARCHITECTURE_${process.arch}`; + const fileName = `elastic-agent-${agentVersion}-linux-${downloadArch}`; + + return fileName; +}; + interface ElasticArtifactSearchResponse { manifest: { 'last-update-time': string; @@ -414,11 +424,9 @@ export const getAgentDownloadUrl = async ( log?: ToolingLog ): Promise => { const agentVersion = closestMatch ? await getLatestAgentDownloadVersion(version, log) : version; - const downloadArch = - { arm64: 'arm64', x64: 'x86_64' }[process.arch as string] ?? - `UNSUPPORTED_ARCHITECTURE_${process.arch}`; - const fileNameNoExtension = `elastic-agent-${agentVersion}-linux-${downloadArch}`; - const agentFile = `${fileNameNoExtension}.tar.gz`; + + const fileNameWithoutExtension = getAgentFileName(agentVersion); + const agentFile = `${fileNameWithoutExtension}.tar.gz`; const artifactSearchUrl = `https://artifacts-api.elastic.co/v1/search/${agentVersion}/${agentFile}`; log?.verbose(`Retrieving elastic agent download URL from:\n ${artifactSearchUrl}`); @@ -444,7 +452,7 @@ export const getAgentDownloadUrl = async ( return { url: searchResult.packages[agentFile].url, fileName: agentFile, - dirName: fileNameNoExtension, + dirName: fileNameWithoutExtension, }; }; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/vagrant/Vagrantfile b/x-pack/plugins/security_solution/scripts/endpoint/common/vagrant/Vagrantfile index fd33efaeab62..b058d17ad076 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/vagrant/Vagrantfile +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/vagrant/Vagrantfile @@ -5,6 +5,7 @@ hostname = ENV["VMNAME"] || 'ubuntu' cachedAgentSource = ENV["CACHED_AGENT_SOURCE"] || '' cachedAgentFilename = ENV["CACHED_AGENT_FILENAME"] || '' +agentDestinationFolder = ENV["AGENT_DESTINATION_FOLDER"] || '' Vagrant.configure("2") do |config| config.vm.hostname = hostname @@ -29,6 +30,7 @@ Vagrant.configure("2") do |config| end config.vm.provision "file", source: cachedAgentSource, destination: "~/#{cachedAgentFilename}" - config.vm.provision "shell", inline: "tar -zxf #{cachedAgentFilename} && rm -f #{cachedAgentFilename}" + config.vm.provision "shell", inline: "mkdir #{agentDestinationFolder}" + config.vm.provision "shell", inline: "tar -zxf #{cachedAgentFilename} --directory #{agentDestinationFolder} --strip-components=1 && rm -f #{cachedAgentFilename}" config.vm.provision "shell", inline: "sudo apt-get install unzip" end diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/vm_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/vm_services.ts index a0efd908f80d..17c74b1bf6fc 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/vm_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/vm_services.ts @@ -249,6 +249,7 @@ const createVagrantVm = async ({ VMNAME: name, CACHED_AGENT_SOURCE: agentFullFilePath, CACHED_AGENT_FILENAME: agentFileName, + AGENT_DESTINATION_FOLDER: agentFileName.replace('.tar.gz', ''), }, // Only `pipe` STDERR to parent process stdio: ['inherit', 'inherit', 'pipe'], diff --git a/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts b/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts index d9033c75d485..725baa689cd2 100644 --- a/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts +++ b/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts @@ -16,6 +16,7 @@ import * as t from 'io-ts'; import { isLeft } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import globby from 'globby'; +import del from 'del'; /** * Updates the `name` and `classname` attributes of each testcase. @@ -195,6 +196,9 @@ ${boilerplate} if ('error' in maybeValidationResult) { logError(maybeValidationResult.error); + // Sending broken XML to Failed Test Reporter will cause a job to fail + await del(path); + log.warning(`${path} file was deleted.`); // If there is an error, continue trying to process other files. continue; } @@ -203,9 +207,11 @@ ${boilerplate} const { processed, hadTestCases } = isReportAlreadyProcessed(reportJson); if (hadTestCases === false) { - log.warning(`${path} had no test cases. Skipping it. + log.warning(`${path} had no test cases. ${boilerplate} `); + await del(path); + log.warning(`${path} file was deleted.`); // If there is an error, continue trying to process other files. continue; } @@ -222,6 +228,9 @@ ${boilerplate} if ('error' in maybeSpecFilePath) { logError(maybeSpecFilePath.error); + // Sending broken XML to Failed Test Reporter will cause a job to fail + await del(path); + log.warning(`${path} file was deleted.`); // If there is an error, continue trying to process other files. continue; } diff --git a/x-pack/plugins/security_solution/scripts/openapi/bundle.js b/x-pack/plugins/security_solution/scripts/openapi/bundle.js new file mode 100644 index 000000000000..6cfa1507ea9e --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/openapi/bundle.js @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../src/setup_node_env'); +const { bundle } = require('@kbn/openapi-bundler'); +const { resolve } = require('path'); + +const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); + +bundle({ + rootDir: SECURITY_SOLUTION_ROOT, + sourceGlob: './common/api/**/*.schema.yaml', + outputFilePath: './target/openapi/security_solution.bundled.schema.yaml', +}); diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts b/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts index cc3972cba0b2..de5cb675a42e 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/get_ftr_config.ts @@ -171,17 +171,6 @@ export const getFTRConfig = ({ } } - // Serverless Specific - if (vars.serverless) { - log.info(`Serverless mode detected`); - - vars.esTestCluster.serverArgs.push( - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.entity_id=http://host.docker.internal:${kibanaPort}`, - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.logout=http://host.docker.internal:${kibanaPort}/logout`, - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.acs=http://host.docker.internal:${kibanaPort}/api/security/saml/callback` - ); - } - if (specFileFTRConfig?.productTypes) { if (vars.serverless) { vars.kbnTestServer.serverArgs.push( diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts index a64f4027f456..22b51692eb33 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/parallel_serverless.ts @@ -148,7 +148,8 @@ async function resetCredentials( apiKey: string ): Promise { log.info(`${runnerId} : Reseting credentials`); - try { + + const fetchResetCredentialsStatusAttempt = async (attemptNum: number) => { const response = await axios.post( `${BASE_ENV_URL}/api/v1/serverless/projects/security/${projectId}/_reset-credentials`, {}, @@ -158,13 +159,27 @@ async function resetCredentials( }, } ); + log.info('Credentials have ben reset'); return { password: response.data.password, username: response.data.username, }; - } catch (error) { - throw new Error(`${error.message}`); - } + }; + + const retryOptions = { + onFailedAttempt: (error: Error | AxiosError) => { + if (error instanceof AxiosError && error.code === 'ENOTFOUND') { + log.info('Project is not reachable. A retry will be triggered soon..'); + } else { + log.info(error); + } + }, + retries: 100, + factor: 2, + maxTimeout: 20000, + }; + + return pRetry(fetchResetCredentialsStatusAttempt, retryOptions); } // Wait until Project is initialized @@ -180,7 +195,7 @@ function waitForProjectInitialized(projectId: string, apiKey: string): Promise { if (error instanceof AxiosError && error.code === 'ENOTFOUND') { - log.info('Project is not reachable. Retrying in 20s...'); + log.info('Project is not reachable. A retry will be triggered soon...'); } else { log.info(error); } @@ -239,7 +254,7 @@ function waitForKibanaAvailable(kbUrl: string, auth: string, runnerId: string): }, }); if (response.data.status.overall.level !== 'available') { - throw new Error(`${runnerId}: Kibana is not available. Retrying in 20s...`); + throw new Error(`${runnerId}: Kibana is not available. A retry will be triggered soon...`); } else { log.info(`${runnerId}: Kibana status overall is ${response.data.status.overall.level}.`); } @@ -247,7 +262,9 @@ function waitForKibanaAvailable(kbUrl: string, auth: string, runnerId: string): const retryOptions = { onFailedAttempt: (error: Error | AxiosError) => { if (error instanceof AxiosError && error.code === 'ENOTFOUND') { - log.info(`${runnerId}: The Kibana URL is not yet reachable. Retrying in 20s...`); + log.info( + `${runnerId}: The Kibana URL is not yet reachable. A retry will be triggered soon...` + ); } else { log.info(`${runnerId}: ${error}`); } @@ -264,17 +281,11 @@ function waitForEsAccess(esUrl: string, auth: string, runnerId: string): Promise const fetchEsAccessAttempt = async (attemptNum: number) => { log.info(`Retry number ${attemptNum} to check if can be accessed.`); - const response = await axios.get(`${esUrl}`, { + await axios.get(`${esUrl}`, { headers: { Authorization: `Basic ${auth}`, }, }); - - if (response.status !== 200) { - throw new Error('Cannot access. Retrying in 20s...'); - } else { - log.info('Access performed successfully'); - } }; const retryOptions = { onFailedAttempt: (error: Error | AxiosError) => { @@ -302,19 +313,14 @@ function waitForKibanaLogin(kbUrl: string, credentials: Credentials): Promise { log.info(`Retry number ${attemptNum} to check if login can be performed.`); - const response = await axios.post(`${kbUrl}/internal/security/login`, body, { + axios.post(`${kbUrl}/internal/security/login`, body, { headers: API_HEADERS, }); - if (response.status !== 200) { - throw new Error('Cannot login. Retrying in 20s...'); - } else { - log.info('Login can be performed successfully'); - } }; const retryOptions = { onFailedAttempt: (error: Error | AxiosError) => { if (error instanceof AxiosError && error.code === 'ENOTFOUND') { - log.info('Project is not reachable. Retrying login in 20s...'); + log.info('Project is not reachable. A retry will be triggered soon...'); } else { log.info(error); } diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index 36c46300f9f3..855cec11ab16 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -30,6 +30,7 @@ export const createMockConfig = (): ConfigType => { settings: getDefaultConfigSettings(), experimentalFeatures: parseExperimentalConfigValue(enableExperimental).features, enabled: true, + enableUiSettingsValidations: false, }; }; diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index 766aca8b5c8b..adc8fbfb1174 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -114,6 +114,7 @@ export const configSchema = schema.object({ */ prebuiltRulesPackageVersion: schema.maybe(schema.string()), enabled: schema.boolean({ defaultValue: true }), + enableUiSettingsValidations: schema.boolean({ defaultValue: false }), /** * The Max number of Bytes allowed for the `upload` endpoint response action @@ -140,6 +141,7 @@ export type ConfigSchema = TypeOf; export type ConfigType = Omit & { experimentalFeatures: ExperimentalFeatures; settings: ConfigSettings; + enableUiSettingsValidations: boolean; }; export const createConfig = (context: PluginInitializerContext): ConfigType => { diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/base_actions_provider.ts b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/base_actions_provider.ts new file mode 100644 index 000000000000..906402b877e0 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/base_actions_provider.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { CasesClient } from '@kbn/cases-plugin/server'; +import type { Logger } from '@kbn/logging'; +import type { EndpointAppContext } from '../../types'; +import type { ResponseActionsProvider } from './types'; +import type { + ActionDetails, + GetProcessesActionOutputContent, + KillOrSuspendProcessRequestBody, + KillProcessActionOutputContent, + ResponseActionExecuteOutputContent, + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters, + ResponseActionParametersWithPidOrEntityId, + ResponseActionsExecuteParameters, + ResponseActionUploadOutputContent, + ResponseActionUploadParameters, + SuspendProcessActionOutputContent, +} from '../../../../common/endpoint/types'; +import type { + IsolationRouteRequestBody, + ExecuteActionRequestBody, + GetProcessesRequestBody, + ResponseActionGetFileRequestBody, + UploadActionApiRequestBody, +} from '../../../../common/api/endpoint'; + +export interface BaseActionsProviderOptions { + endpointContext: EndpointAppContext; + esClient: ElasticsearchClient; + casesClient?: CasesClient; + /** Username that will be stored along with the action's ES documents */ + username: string; +} + +export abstract class BaseResponseActionsClient implements ResponseActionsProvider { + protected readonly log: Logger; + + constructor(protected readonly options: BaseActionsProviderOptions) { + this.log = options.endpointContext.logFactory.get(this.constructor.name ?? 'ActionsProvider'); + } + + // TODO:PT implement a generic way to update cases without relying on the Attachments being endpoint agents + // protected async updateCases(): Promise { + // throw new Error('Method not yet implemented'); + // } + + public abstract isolate(options: IsolationRouteRequestBody): Promise; + + public abstract release(options: IsolationRouteRequestBody): Promise; + + public abstract killProcess( + options: KillOrSuspendProcessRequestBody + ): Promise< + ActionDetails + >; + + public abstract suspendProcess( + options: KillOrSuspendProcessRequestBody + ): Promise< + ActionDetails + >; + + public abstract runningProcesses( + options: GetProcessesRequestBody + ): Promise>; + + public abstract getFile( + options: ResponseActionGetFileRequestBody + ): Promise>; + + public abstract execute( + options: ExecuteActionRequestBody + ): Promise>; + + public abstract upload( + options: UploadActionApiRequestBody + ): Promise>; +} diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/types.ts b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/types.ts new file mode 100644 index 000000000000..5578128cf424 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/types.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ActionDetails, + KillOrSuspendProcessRequestBody, + KillProcessActionOutputContent, + ResponseActionParametersWithPidOrEntityId, + SuspendProcessActionOutputContent, + GetProcessesActionOutputContent, + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters, + ResponseActionExecuteOutputContent, + ResponseActionsExecuteParameters, + ResponseActionUploadOutputContent, + ResponseActionUploadParameters, +} from '../../../../common/endpoint/types'; +import type { + IsolationRouteRequestBody, + GetProcessesRequestBody, + ResponseActionGetFileRequestBody, + ExecuteActionRequestBody, + UploadActionApiRequestBody, +} from '../../../../common/api/endpoint'; + +/** + * The interface required for a Response Actions provider + */ +export interface ResponseActionsProvider { + isolate: (options: IsolationRouteRequestBody) => Promise; + + release: (options: IsolationRouteRequestBody) => Promise; + + killProcess: ( + options: KillOrSuspendProcessRequestBody + ) => Promise< + ActionDetails + >; + + suspendProcess: ( + options: KillOrSuspendProcessRequestBody + ) => Promise< + ActionDetails + >; + + runningProcesses: ( + options: GetProcessesRequestBody + ) => Promise>; + + getFile: ( + options: ResponseActionGetFileRequestBody + ) => Promise>; + + execute: ( + options: ExecuteActionRequestBody + ) => Promise>; + + upload: ( + options: UploadActionApiRequestBody + ) => Promise>; +} diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.test.ts deleted file mode 100644 index d8cda7554a08..000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.test.ts +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HttpApiTestSetupMock } from '../../mocks'; -import { createHttpApiTestSetupMock } from '../../mocks'; -import type { UploadActionApiRequestBody } from '../../../../common/api/endpoint'; -import type { getActionFileUploadHandler } from './file_upload_handler'; -import { registerActionFileUploadRoute } from './file_upload_handler'; -import { UPLOAD_ROUTE } from '../../../../common/endpoint/constants'; -import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks'; -import { EndpointAuthorizationError } from '../../errors'; -import type { HapiReadableStream } from '../../../types'; -import { createHapiReadableStreamMock } from '../../services/actions/mocks'; -import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; -import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; -import type { ActionDetails } from '../../../../common/endpoint/types'; -import { omit } from 'lodash'; -import type { FleetToHostFileClientInterface } from '@kbn/fleet-plugin/server'; - -describe('Upload response action create API handler', () => { - type UploadHttpApiTestSetupMock = HttpApiTestSetupMock; - - let testSetup: UploadHttpApiTestSetupMock; - let httpRequestMock: ReturnType; - let httpHandlerContextMock: UploadHttpApiTestSetupMock['httpHandlerContextMock']; - let httpResponseMock: UploadHttpApiTestSetupMock['httpResponseMock']; - - let fleetFilesClientMock: jest.Mocked; - - beforeEach(async () => { - testSetup = createHttpApiTestSetupMock(); - - ({ httpHandlerContextMock, httpResponseMock } = testSetup); - httpRequestMock = testSetup.createRequestMock(); - - fleetFilesClientMock = - (await testSetup.endpointAppContextMock.service.getFleetToHostFilesClient()) as jest.Mocked; - }); - - describe('registerActionFileUploadRoute()', () => { - it('should register the route', () => { - registerActionFileUploadRoute(testSetup.routerMock, testSetup.endpointAppContextMock); - - expect( - testSetup.getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31') - ).toBeDefined(); - }); - - it('should NOT register route if feature flag is false', () => { - // @ts-expect-error - testSetup.endpointAppContextMock.experimentalFeatures.responseActionUploadEnabled = false; - registerActionFileUploadRoute(testSetup.routerMock, testSetup.endpointAppContextMock); - - expect(() => - testSetup.getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31') - ).toThrow('No routes registered for [POST /api/endpoint/action/upload]'); - }); - - it('should use maxUploadResponseActionFileBytes config value', () => { - // @ts-expect-error - testSetup.endpointAppContextMock.serverConfig.maxUploadResponseActionFileBytes = 999; - registerActionFileUploadRoute(testSetup.routerMock, testSetup.endpointAppContextMock); - - expect( - testSetup.getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31').routeConfig - ?.options?.body - ).toEqual({ - accepts: ['multipart/form-data'], - maxBytes: 999, - output: 'stream', - }); - }); - - it('should error if user has no authz to api', async () => { - ( - (await httpHandlerContextMock.securitySolution).getEndpointAuthz as jest.Mock - ).mockResolvedValue(getEndpointAuthzInitialStateMock({ canWriteFileOperations: false })); - registerActionFileUploadRoute(testSetup.routerMock, testSetup.endpointAppContextMock); - await testSetup - .getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31') - .routeHandler(httpHandlerContextMock, httpRequestMock, httpResponseMock); - - expect(httpResponseMock.forbidden).toHaveBeenCalledWith({ - body: expect.any(EndpointAuthorizationError), - }); - }); - }); - - describe('route request handler', () => { - let callHandler: () => ReturnType>; - let fileContent: HapiReadableStream; - let createdUploadAction: ActionDetails; - - beforeEach(() => { - fileContent = createHapiReadableStreamMock(); - - const reqBody: UploadActionApiRequestBody = { - file: fileContent, - endpoint_ids: ['123-456'], - parameters: { - overwrite: true, - }, - }; - - httpRequestMock = testSetup.createRequestMock({ body: reqBody }); - registerActionFileUploadRoute(testSetup.routerMock, testSetup.endpointAppContextMock); - - createdUploadAction = new EndpointActionGenerator('seed').generateActionDetails({ - command: 'upload', - }); - - ( - testSetup.endpointAppContextMock.service.getActionCreateService().createAction as jest.Mock - ).mockResolvedValue(createdUploadAction); - - (testSetup.endpointAppContextMock.service.getEndpointMetadataService as jest.Mock) = jest - .fn() - .mockReturnValue({ - getMetadataForEndpoints: jest.fn().mockResolvedValue([ - { - elastic: { - agent: { - id: '123-456', - }, - }, - }, - ]), - }); - - const handler: ReturnType = - testSetup.getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31').routeHandler; - - callHandler = () => handler(httpHandlerContextMock, httpRequestMock, httpResponseMock); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should create a file', async () => { - await callHandler(); - - expect(fleetFilesClientMock.create).toHaveBeenCalledWith(fileContent, ['123-456']); - }); - - it('should create the action using parameters with stored file info', async () => { - await callHandler(); - - const createActionMock = testSetup.endpointAppContextMock.service.getActionCreateService() - .createAction as jest.Mock; - - expect(createActionMock).toHaveBeenCalledWith( - { - command: 'upload', - endpoint_ids: ['123-456'], - parameters: { - file_id: '123-456-789', - file_name: 'foo.txt', - file_sha256: '96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3', - file_size: 45632, - overwrite: true, - }, - user: undefined, - }, - ['123-456'] - ); - }); - - it('should delete file if creation of Action fails', async () => { - const createActionMock = testSetup.endpointAppContextMock.service.getActionCreateService() - .createAction as jest.Mock; - createActionMock.mockImplementation(async () => { - throw new CustomHttpRequestError('oh oh'); - }); - await callHandler(); - - expect(fleetFilesClientMock.delete).toHaveBeenCalledWith('123-456-789'); - }); - - it('should update file with action id', async () => { - await callHandler(); - - expect(fleetFilesClientMock.update).toHaveBeenCalledWith('123-456-789', { actionId: '123' }); - }); - - it('should return expected response on success', async () => { - await callHandler(); - - expect(httpResponseMock.ok).toHaveBeenCalledWith({ - body: { - action: createdUploadAction.action, - data: omit(createdUploadAction, 'action'), - }, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.ts deleted file mode 100644 index 3b51bb48a010..000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_upload_handler.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { RequestHandler } from '@kbn/core/server'; -import type { UploadActionApiRequestBody } from '../../../../common/api/endpoint'; -import { UploadActionRequestSchema } from '../../../../common/api/endpoint'; -import type { ResponseActionsApiCommandNames } from '../../../../common/endpoint/service/response_actions/constants'; -import type { - ResponseActionUploadParameters, - ResponseActionUploadOutputContent, - HostMetadata, -} from '../../../../common/endpoint/types'; -import { UPLOAD_ROUTE } from '../../../../common/endpoint/constants'; -import { withEndpointAuthz } from '../with_endpoint_authz'; -import type { - SecuritySolutionPluginRouter, - SecuritySolutionRequestHandlerContext, - HapiReadableStream, -} from '../../../types'; -import type { EndpointAppContext } from '../../types'; -import { errorHandler } from '../error_handler'; -import { updateCases } from '../../services/actions/create/update_cases'; - -export const registerActionFileUploadRoute = ( - router: SecuritySolutionPluginRouter, - endpointContext: EndpointAppContext -) => { - if (!endpointContext.experimentalFeatures.responseActionUploadEnabled) { - return; - } - - const logger = endpointContext.logFactory.get('uploadAction'); - - router.versioned - .post({ - access: 'public', - path: UPLOAD_ROUTE, - options: { - authRequired: true, - tags: ['access:securitySolution'], - body: { - accepts: ['multipart/form-data'], - output: 'stream', - maxBytes: endpointContext.serverConfig.maxUploadResponseActionFileBytes, - }, - }, - }) - .addVersion( - { - version: '2023-10-31', - validate: { - request: UploadActionRequestSchema, - }, - }, - withEndpointAuthz( - { all: ['canWriteFileOperations'] }, - logger, - getActionFileUploadHandler(endpointContext) - ) - ); -}; - -export const getActionFileUploadHandler = ( - endpointContext: EndpointAppContext -): RequestHandler< - never, - never, - UploadActionApiRequestBody, - SecuritySolutionRequestHandlerContext -> => { - const logger = endpointContext.logFactory.get('uploadAction'); - - return async (context, req, res) => { - const fleetFiles = await endpointContext.service.getFleetToHostFilesClient(); - const user = endpointContext.service.security?.authc.getCurrentUser(req); - const fileStream = req.body.file as HapiReadableStream; - const { file: _, parameters: userParams, ...actionPayload } = req.body; - const uploadParameters: ResponseActionUploadParameters = { - ...userParams, - file_id: '', - file_name: '', - file_sha256: '', - file_size: 0, - }; - - try { - const createdFile = await fleetFiles.create(fileStream, actionPayload.endpoint_ids); - - uploadParameters.file_id = createdFile.id; - uploadParameters.file_name = createdFile.name; - uploadParameters.file_sha256 = createdFile.sha256; - uploadParameters.file_size = createdFile.size; - } catch (err) { - return errorHandler(logger, res, err); - } - - const createActionPayload = { - ...actionPayload, - parameters: uploadParameters, - command: 'upload' as ResponseActionsApiCommandNames, - user, - }; - - const esClient = (await context.core).elasticsearch.client.asInternalUser; - const endpointData = await endpointContext.service - .getEndpointMetadataService() - .getMetadataForEndpoints(esClient, [...new Set(createActionPayload.endpoint_ids)]); - const agentIds = endpointData.map((endpoint: HostMetadata) => endpoint.elastic.agent.id); - - try { - const casesClient = await endpointContext.service.getCasesClient(req); - const { action: actionId, ...data } = await endpointContext.service - .getActionCreateService() - .createAction( - createActionPayload, - agentIds - ); - - // Update the file meta to include the action id, and if any errors (unlikely), - // then just log them and still allow api to return success since the action has - // already been created and potentially dispatched to Endpoint. Action ID is not - // needed by the Endpoint or fleet-server's API, so no need to fail here - try { - await fleetFiles.update(uploadParameters.file_id, { actionId: data.id }); - } catch (e) { - logger.warn(`Attempt to update File meta with Action ID failed: ${e.message}`, e); - } - - // update cases - await updateCases({ casesClient, createActionPayload, endpointData }); - - return res.ok({ - body: { - action: actionId, - data, - }, - }); - } catch (err) { - if (uploadParameters.file_id) { - // Try to delete the created file since creating the action threw an error - try { - await fleetFiles.delete(uploadParameters.file_id); - } catch (e) { - logger.error( - `Attempt to clean up file (after action creation was unsuccessful) failed; ${e.message}`, - e - ); - } - } - - return errorHandler(logger, res, err); - } - }; -}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts index dd10093cc343..8f7682c83daa 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts @@ -34,6 +34,7 @@ import { UNISOLATE_HOST_ROUTE, GET_FILE_ROUTE, EXECUTE_ROUTE, + UPLOAD_ROUTE, } from '../../../../common/endpoint/constants'; import type { ActionDetails, @@ -46,7 +47,9 @@ import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data' import type { EndpointAuthz } from '../../../../common/endpoint/types/authz'; import type { SecuritySolutionRequestHandlerContextMock } from '../../../lib/detection_engine/routes/__mocks__/request_context'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; +import type { HttpApiTestSetupMock } from '../../mocks'; import { + createHttpApiTestSetupMock, createMockEndpointAppContext, createMockEndpointAppContextServiceSetupContract, createMockEndpointAppContextServiceStartContract, @@ -59,6 +62,13 @@ import * as ActionDetailsService from '../../services/actions/action_details_by_ import { CaseStatuses } from '@kbn/cases-components'; import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks'; import { actionCreateService } from '../../services/actions'; +import type { UploadActionApiRequestBody } from '../../../../common/api/endpoint'; +import type { FleetToHostFileClientInterface } from '@kbn/fleet-plugin/server'; +import type { HapiReadableStream, SecuritySolutionRequestHandlerContext } from '../../../types'; +import { createHapiReadableStreamMock } from '../../services/actions/mocks'; +import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { omit } from 'lodash'; interface CallRouteInterface { body?: ResponseActionRequestBody; @@ -827,26 +837,26 @@ describe('Response actions', () => { }); it('handles errors', async () => { - const errMessage = 'Uh oh!'; - await callRoute( - UNISOLATE_HOST_ROUTE_V2, - { - body: { endpoint_ids: ['XYZ'] }, - version: '2023-10-31', - indexErrorResponse: { - statusCode: 500, - body: { - result: errMessage, + const expectedError = new Error('Uh oh!'); + + await expect( + callRoute( + UNISOLATE_HOST_ROUTE_V2, + { + body: { endpoint_ids: ['XYZ'] }, + version: '2023-10-31', + indexErrorResponse: { + statusCode: 500, + body: { + result: expectedError.message, + }, }, }, - }, - { endpointDsExists: true } - ); + { endpointDsExists: true } + ) + ).rejects.toEqual(expectedError); expect(mockResponse.ok).not.toBeCalled(); - const response = mockResponse.customError.mock.calls[0][0]; - expect(response.statusCode).toEqual(500); - expect((response.body as Error).message).toEqual(errMessage); }); }); @@ -1001,4 +1011,140 @@ describe('Response actions', () => { }); }); }); + + describe('Upload response action handler', () => { + type UploadHttpApiTestSetupMock = HttpApiTestSetupMock< + never, + never, + UploadActionApiRequestBody + >; + type UploadRequestHandler = RequestHandler< + never, + never, + UploadActionApiRequestBody, + SecuritySolutionRequestHandlerContext + >; + + let testSetup: UploadHttpApiTestSetupMock; + let httpRequestMock: ReturnType; + let httpHandlerContextMock: UploadHttpApiTestSetupMock['httpHandlerContextMock']; + let httpResponseMock: UploadHttpApiTestSetupMock['httpResponseMock']; + let fleetFilesClientMock: jest.Mocked; + let callHandler: () => ReturnType; + let fileContent: HapiReadableStream; + let createdUploadAction: ActionDetails; + + beforeEach(async () => { + testSetup = createHttpApiTestSetupMock(); + + ({ httpHandlerContextMock, httpResponseMock } = testSetup); + httpRequestMock = testSetup.createRequestMock(); + + fleetFilesClientMock = + (await testSetup.endpointAppContextMock.service.getFleetToHostFilesClient()) as jest.Mocked; + + fileContent = createHapiReadableStreamMock(); + + const reqBody: UploadActionApiRequestBody = { + file: fileContent, + endpoint_ids: ['123-456'], + parameters: { + overwrite: true, + }, + }; + + httpRequestMock = testSetup.createRequestMock({ body: reqBody }); + registerResponseActionRoutes(testSetup.routerMock, testSetup.endpointAppContextMock); + + createdUploadAction = new EndpointActionGenerator('seed').generateActionDetails({ + command: 'upload', + }); + + ( + testSetup.endpointAppContextMock.service.getActionCreateService().createAction as jest.Mock + ).mockResolvedValue(createdUploadAction); + + (testSetup.endpointAppContextMock.service.getEndpointMetadataService as jest.Mock) = jest + .fn() + .mockReturnValue({ + getMetadataForEndpoints: jest.fn().mockResolvedValue([ + { + elastic: { + agent: { + id: '123-456', + }, + }, + }, + ]), + }); + + const handler = testSetup.getRegisteredVersionedRoute('post', UPLOAD_ROUTE, '2023-10-31') + .routeHandler as UploadRequestHandler; + + callHandler = () => handler(httpHandlerContextMock, httpRequestMock, httpResponseMock); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should create a file', async () => { + await callHandler(); + + expect(fleetFilesClientMock.create).toHaveBeenCalledWith(fileContent, ['123-456']); + }); + + it('should create the action using parameters with stored file info', async () => { + await callHandler(); + + const createActionMock = testSetup.endpointAppContextMock.service.getActionCreateService() + .createAction as jest.Mock; + + expect(createActionMock).toHaveBeenCalledWith( + { + command: 'upload', + endpoint_ids: ['123-456'], + parameters: { + file_id: '123-456-789', + file_name: 'foo.txt', + file_sha256: '96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3', + file_size: 45632, + overwrite: true, + }, + user: { username: 'unknown' }, + }, + ['123-456'] + ); + }); + + it('should delete file if creation of Action fails', async () => { + const createActionMock = testSetup.endpointAppContextMock.service.getActionCreateService() + .createAction as jest.Mock; + createActionMock.mockImplementation(async () => { + throw new CustomHttpRequestError('oh oh'); + }); + await callHandler(); + + expect(fleetFilesClientMock.delete).toHaveBeenCalledWith('123-456-789'); + }); + + it('should update file with action id', async () => { + await callHandler(); + + expect(fleetFilesClientMock.update).toHaveBeenCalledWith('123-456-789', { + actionId: '123', + }); + }); + + it('should return expected response on success', async () => { + await callHandler(); + + expect(httpResponseMock.ok).toHaveBeenCalledWith({ + body: { + action: createdUploadAction.action, + data: omit(createdUploadAction, 'action'), + }, + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts index 3b98efa12cd9..c8669869833f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts @@ -7,9 +7,14 @@ import type { RequestHandler } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; +import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { EndpointActionsClient } from '../../services/actions/clients'; import type { - ResponseActionBodySchema, NoParametersRequestSchema, + ResponseActionsRequestBody, + ExecuteActionRequestBody, + ResponseActionGetFileRequestBody, + UploadActionApiRequestBody, } from '../../../../common/api/endpoint'; import { ExecuteActionRequestSchema, @@ -19,6 +24,7 @@ import { SuspendProcessRouteRequestSchema, UnisolateRouteRequestSchema, GetProcessesRouteRequestSchema, + UploadActionRequestSchema, } from '../../../../common/api/endpoint'; import { @@ -31,13 +37,14 @@ import { UNISOLATE_HOST_ROUTE, GET_FILE_ROUTE, EXECUTE_ROUTE, + UPLOAD_ROUTE, } from '../../../../common/endpoint/constants'; import type { EndpointActionDataParameterTypes, ResponseActionParametersWithPidOrEntityId, ResponseActionsExecuteParameters, ActionDetails, - HostMetadata, + KillOrSuspendProcessRequestBody, } from '../../../../common/endpoint/types'; import type { ResponseActionsApiCommandNames } from '../../../../common/endpoint/service/response_actions/constants'; import type { @@ -46,8 +53,7 @@ import type { } from '../../../types'; import type { EndpointAppContext } from '../../types'; import { withEndpointAuthz } from '../with_endpoint_authz'; -import { registerActionFileUploadRoute } from './file_upload_handler'; -import { updateCases } from '../../services/actions/create/update_cases'; +import { errorHandler } from '../error_handler'; export function registerResponseActionRoutes( router: SecuritySolutionPluginRouter, @@ -243,7 +249,33 @@ export function registerResponseActionRoutes( ) ); - registerActionFileUploadRoute(router, endpointContext); + router.versioned + .post({ + access: 'public', + path: UPLOAD_ROUTE, + options: { + authRequired: true, + tags: ['access:securitySolution'], + body: { + accepts: ['multipart/form-data'], + output: 'stream', + maxBytes: endpointContext.serverConfig.maxUploadResponseActionFileBytes, + }, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: { + request: UploadActionRequestSchema, + }, + }, + withEndpointAuthz( + { all: ['canWriteFileOperations'] }, + logger, + responseActionRequestHandler(endpointContext, 'upload') + ) + ); } function responseActionRequestHandler( @@ -252,43 +284,76 @@ function responseActionRequestHandler, + ResponseActionsRequestBody, SecuritySolutionRequestHandlerContext > { + const logger = endpointContext.logFactory.get('responseActionsHandler'); + return async (context, req, res) => { const user = endpointContext.service.security?.authc.getCurrentUser(req); const esClient = (await context.core).elasticsearch.client.asInternalUser; - - let action: ActionDetails; + const casesClient = await endpointContext.service.getCasesClient(req); + const actionsClient = new EndpointActionsClient({ + esClient, + casesClient, + endpointContext, + username: user?.username ?? 'unknown', + }); try { - const createActionPayload = { ...req.body, command, user }; - const endpointData = await endpointContext.service - .getEndpointMetadataService() - .getMetadataForEndpoints(esClient, [...new Set(createActionPayload.endpoint_ids)]); - const agentIds = endpointData.map((endpoint: HostMetadata) => endpoint.elastic.agent.id); + let action: ActionDetails; - action = await endpointContext.service - .getActionCreateService() - .createAction(createActionPayload, agentIds); + switch (command) { + case 'isolate': + action = await actionsClient.isolate(req.body); + break; - // update cases - const casesClient = await endpointContext.service.getCasesClient(req); - await updateCases({ casesClient, createActionPayload, endpointData }); - } catch (err) { - return res.customError({ - statusCode: 500, - body: err, + case 'unisolate': + action = await actionsClient.release(req.body); + break; + + case 'running-processes': + action = await actionsClient.runningProcesses(req.body); + break; + + case 'execute': + action = await actionsClient.execute(req.body as ExecuteActionRequestBody); + break; + + case 'suspend-process': + action = await actionsClient.suspendProcess(req.body as KillOrSuspendProcessRequestBody); + break; + + case 'kill-process': + action = await actionsClient.killProcess(req.body as KillOrSuspendProcessRequestBody); + break; + + case 'get-file': + action = await actionsClient.getFile(req.body as ResponseActionGetFileRequestBody); + break; + + case 'upload': + action = await actionsClient.upload(req.body as UploadActionApiRequestBody); + break; + + default: + throw new CustomHttpRequestError( + `No handler found for response action command: [${command}]`, + 501 + ); + } + + const { action: actionId, ...data } = action; + + return res.ok({ + body: { + action: actionId, + data, + }, }); + } catch (err) { + return errorHandler(logger, res, err); } - - const { action: actionId, ...data } = action; - return res.ok({ - body: { - action: actionId, - data, - }, - }); }; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/entity/handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/entity/handler.ts index 33e655b49d21..a605226ddfb9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/entity/handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/entity/handler.ts @@ -7,9 +7,11 @@ import type { RequestHandler } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; +import { EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER } from '../../../../../common/constants'; import type { validateEntities } from '../../../../../common/endpoint/schema/resolver'; import type { ResolverEntityIndex } from '../../../../../common/endpoint/types'; import { resolverEntity } from './utils/build_resolver_entity'; +import { createSharedFilters } from '../utils/shared_filters'; /** * This is used to get an 'entity_id' which is an internal-to-Resolver concept, from an `_id`, which @@ -22,6 +24,10 @@ export function handleEntities(): RequestHandler(EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER); + const queryResponse = await esClient.asCurrentUser.search({ ignore_unavailable: true, index: indices, @@ -31,6 +37,7 @@ export function handleEntities(): RequestHandler(EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER); const eventsQuery = new EventsQuery({ pagination: PaginationBuilder.createBuilder(limit, afterEvent), indexPatterns: body.indexPatterns, timeRange: body.timeRange, + shouldExcludeColdAndFrozenTiers, }); const results = await eventsQuery.search(eventsClient, body, alertsClient); return res.ok({ diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/events.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/events.ts index bd0642702fc1..3b8d95fa1aa9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/events.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/queries/events.ts @@ -24,8 +24,9 @@ export class EventsQuery extends BaseResolverQuery { timeRange, isInternalRequest, pagination, + shouldExcludeColdAndFrozenTiers, }: ResolverQueryParams & { pagination: PaginationBuilder }) { - super({ indexPatterns, timeRange, isInternalRequest }); + super({ indexPatterns, timeRange, isInternalRequest, shouldExcludeColdAndFrozenTiers }); this.pagination = pagination; } @@ -36,6 +37,7 @@ export class EventsQuery extends BaseResolverQuery { filter: [ ...filters, ...this.getRangeFilter(), + ...this.getColdAndFrozenTierFilter(), { term: { 'event.kind': 'event' }, }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts index b4931da5ae16..48c99cd8ed11 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts @@ -11,6 +11,7 @@ import type { RequestHandler } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/server'; +import { EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER } from '../../../../../common/constants'; import type { ConfigType } from '../../../../config'; import type { validateTree } from '../../../../../common/endpoint/schema/resolver'; @@ -30,6 +31,9 @@ export function handleTree( const license = await firstValueFrom(licensing.license$); const hasAccessToInsightsRelatedByProcessAncestry = insightsRelatedAlertsByProcessAncestry && license.hasAtLeast('platinum'); + const shouldExcludeColdAndFrozenTiers = await ( + await context.core + ).uiSettings.client.get(EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER); if (hasAccessToInsightsRelatedByProcessAncestry) { featureUsageService.notifyUsage('ALERTS_BY_PROCESS_ANCESTRY'); @@ -39,7 +43,7 @@ export function handleTree( ? await ruleRegistry.getRacClientWithRequest(req) : undefined; const fetcher = new Fetcher(client, alertsClient); - const body = await fetcher.tree(req.body); + const body = await fetcher.tree({ ...req.body, shouldExcludeColdAndFrozenTiers }); return res.ok({ body, }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/base.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/base.ts index 256f2b58b686..34e8c463dc77 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/base.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/base.ts @@ -7,14 +7,16 @@ import type { JsonValue } from '@kbn/utility-types'; import type { ResolverSchema } from '../../../../../../common/endpoint/types'; +import { createSharedFilters } from '../../utils/shared_filters'; import type { TimeRange } from '../utils'; import { resolverFields } from '../utils'; export interface ResolverQueryParams { readonly schema?: ResolverSchema; readonly indexPatterns: string | string[]; - readonly timeRange: TimeRange | undefined; readonly isInternalRequest?: boolean; + readonly shouldExcludeColdAndFrozenTiers?: boolean; + readonly timeRange: TimeRange | undefined; readonly resolverFields?: JsonValue[]; getRangeFilter?: () => Array<{ range: { '@timestamp': { gte: string; lte: string; format: string } }; @@ -24,11 +26,18 @@ export interface ResolverQueryParams { export class BaseResolverQuery implements ResolverQueryParams { readonly schema: ResolverSchema; readonly indexPatterns: string | string[]; - readonly timeRange: TimeRange | undefined; readonly isInternalRequest?: boolean; + readonly shouldExcludeColdAndFrozenTiers?: boolean; + readonly timeRange: TimeRange | undefined; readonly resolverFields?: JsonValue[]; - constructor({ schema, indexPatterns, timeRange, isInternalRequest }: ResolverQueryParams) { + constructor({ + schema, + indexPatterns, + timeRange, + isInternalRequest, + shouldExcludeColdAndFrozenTiers, + }: ResolverQueryParams) { const schemaOrDefault = schema ? schema : { @@ -40,6 +49,13 @@ export class BaseResolverQuery implements ResolverQueryParams { this.indexPatterns = indexPatterns; this.timeRange = timeRange; this.isInternalRequest = isInternalRequest; + this.shouldExcludeColdAndFrozenTiers = shouldExcludeColdAndFrozenTiers; + } + + getColdAndFrozenTierFilter() { + return createSharedFilters({ + excludeColdAndFrozenTiers: !!this.shouldExcludeColdAndFrozenTiers, + }); } getRangeFilter() { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/descendants.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/descendants.ts index daa3a513821d..aa6547506b36 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/descendants.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/descendants.ts @@ -20,8 +20,14 @@ import { BaseResolverQuery } from './base'; export class DescendantsQuery extends BaseResolverQuery { declare readonly resolverFields: JsonValue[]; - constructor({ schema, indexPatterns, timeRange, isInternalRequest }: ResolverQueryParams) { - super({ schema, indexPatterns, timeRange, isInternalRequest }); + constructor({ + schema, + indexPatterns, + timeRange, + isInternalRequest, + shouldExcludeColdAndFrozenTiers, + }: ResolverQueryParams) { + super({ schema, indexPatterns, timeRange, isInternalRequest, shouldExcludeColdAndFrozenTiers }); } private query(nodes: NodeID[], size: number): JsonObject { @@ -37,6 +43,7 @@ export class DescendantsQuery extends BaseResolverQuery { bool: { filter: [ ...this.getRangeFilter(), + ...this.getColdAndFrozenTierFilter(), { terms: { [this.schema.parent]: nodes }, }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/lifecycle.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/lifecycle.ts index 26f917a3008d..84ebd8b4ae53 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/lifecycle.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/queries/lifecycle.ts @@ -18,8 +18,14 @@ import { BaseResolverQuery } from './base'; */ export class LifecycleQuery extends BaseResolverQuery { declare readonly resolverFields: JsonValue[]; - constructor({ schema, indexPatterns, timeRange, isInternalRequest }: ResolverQueryParams) { - super({ schema, indexPatterns, timeRange, isInternalRequest }); + constructor({ + schema, + indexPatterns, + timeRange, + isInternalRequest, + shouldExcludeColdAndFrozenTiers, + }: ResolverQueryParams) { + super({ schema, indexPatterns, timeRange, isInternalRequest, shouldExcludeColdAndFrozenTiers }); } private query(nodes: NodeID[]): JsonObject { @@ -34,6 +40,7 @@ export class LifecycleQuery extends BaseResolverQuery { query: { bool: { filter: [ + ...this.getColdAndFrozenTierFilter(), ...this.getRangeFilter(), { terms: { [this.schema.id]: nodes }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/utils/fetch.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/utils/fetch.ts index 85b5bbd8a277..42757767b944 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/utils/fetch.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/utils/fetch.ts @@ -38,6 +38,7 @@ export interface TreeOptions { nodes: NodeID[]; indexPatterns: string[]; includeHits?: boolean; + shouldExcludeColdAndFrozenTiers?: boolean; } export type TreeResponse = Promise< @@ -53,6 +54,7 @@ export type TreeResponse = Promise< */ export class Fetcher { private alertsClient?: AlertsClient; + constructor(private readonly client: IScopedClusterClient, alertsClient?: AlertsClient) { this.alertsClient = alertsClient; } @@ -168,6 +170,7 @@ export class Fetcher { indexPatterns: options.indexPatterns, timeRange: options.timeRange, isInternalRequest, + shouldExcludeColdAndFrozenTiers: !!options.shouldExcludeColdAndFrozenTiers, }); let nodes = options.nodes; @@ -218,6 +221,7 @@ export class Fetcher { indexPatterns: options.indexPatterns, timeRange: options.timeRange, isInternalRequest, + shouldExcludeColdAndFrozenTiers: !!options.shouldExcludeColdAndFrozenTiers, }); let nodes: NodeID[] = options.nodes; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/shared_filters.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/shared_filters.ts new file mode 100644 index 000000000000..105e70608258 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/utils/shared_filters.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface SharedFiltersOptions { + excludeColdAndFrozenTiers: boolean; +} + +export const createSharedFilters = ({ excludeColdAndFrozenTiers }: SharedFiltersOptions) => { + const filters = []; + + if (excludeColdAndFrozenTiers) { + filters.push({ + bool: { + must_not: { + terms: { + _tier: ['data_frozen', 'data_cold'], + }, + }, + }, + }); + } + + return filters; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts new file mode 100644 index 000000000000..2b5813fa6c90 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/endpoint_actions_client.ts @@ -0,0 +1,215 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { HapiReadableStream } from '../../../../types'; +import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; +import { updateCases } from '../create/update_cases'; +import type { CreateActionPayload } from '../create/types'; +import type { + ExecuteActionRequestBody, + GetProcessesRequestBody, + IsolationRouteRequestBody, + ResponseActionGetFileRequestBody, + UploadActionApiRequestBody, + ResponseActionsRequestBody, +} from '../../../../../common/api/endpoint'; +import { BaseResponseActionsClient } from '../../../lib/response_actions/base_actions_provider'; +import type { + ActionDetails, + HostMetadata, + GetProcessesActionOutputContent, + KillOrSuspendProcessRequestBody, + KillProcessActionOutputContent, + ResponseActionExecuteOutputContent, + ResponseActionGetFileOutputContent, + ResponseActionGetFileParameters, + ResponseActionParametersWithPidOrEntityId, + ResponseActionsExecuteParameters, + ResponseActionUploadOutputContent, + ResponseActionUploadParameters, + SuspendProcessActionOutputContent, + HostMetadataInterface, + ImmutableObject, +} from '../../../../../common/endpoint/types'; + +export class EndpointActionsClient extends BaseResponseActionsClient { + private async checkAgentIds(ids: string[]): Promise<{ + valid: string[]; + invalid: string[]; + allValid: boolean; + hosts: HostMetadata[]; + }> { + const foundEndpointHosts = await this.options.endpointContext.service + .getEndpointMetadataService() + .getMetadataForEndpoints(this.options.esClient, [...new Set(ids)]); + const validIds = foundEndpointHosts.map((endpoint: HostMetadata) => endpoint.elastic.agent.id); + const invalidIds = ids.filter((id) => !validIds.includes(id)); + + if (invalidIds.length) { + this.log.debug(`The following agent ids are not valid: ${JSON.stringify(invalidIds)}`); + } + + return { + valid: validIds, + invalid: invalidIds, + allValid: invalidIds.length === 0, + hosts: foundEndpointHosts, + }; + } + + private async handleResponseAction< + TOptions extends ResponseActionsRequestBody = ResponseActionsRequestBody, + TResponse extends ActionDetails = ActionDetails + >(command: ResponseActionsApiCommandNames, options: TOptions): Promise { + const agentIds = await this.checkAgentIds(options.endpoint_ids); + const createPayload: CreateActionPayload = { + ...options, + command, + user: { username: this.options.username }, + }; + + const response = await this.options.endpointContext.service + .getActionCreateService() + .createAction(createPayload, agentIds.valid); + + await this.updateCases(createPayload, agentIds.hosts); + + return response as TResponse; + } + + protected async updateCases( + createActionPayload: CreateActionPayload, + endpointData: Array> + ): Promise { + return updateCases({ + casesClient: this.options.casesClient, + createActionPayload, + endpointData, + }); + } + + async isolate(options: IsolationRouteRequestBody): Promise { + return this.handleResponseAction('isolate', options); + } + + async release(options: IsolationRouteRequestBody): Promise { + return this.handleResponseAction( + 'unisolate', + options + ); + } + + async killProcess( + options: KillOrSuspendProcessRequestBody + ): Promise< + ActionDetails + > { + return this.handleResponseAction< + KillOrSuspendProcessRequestBody, + ActionDetails + >('kill-process', options); + } + + async suspendProcess( + options: KillOrSuspendProcessRequestBody + ): Promise< + ActionDetails + > { + return this.handleResponseAction< + KillOrSuspendProcessRequestBody, + ActionDetails + >('suspend-process', options); + } + + async runningProcesses( + options: GetProcessesRequestBody + ): Promise> { + return this.handleResponseAction< + GetProcessesRequestBody, + ActionDetails + >('running-processes', options); + } + + async getFile( + options: ResponseActionGetFileRequestBody + ): Promise> { + return this.handleResponseAction< + ResponseActionGetFileRequestBody, + ActionDetails + >('get-file', options); + } + + async execute( + options: ExecuteActionRequestBody + ): Promise> { + return this.handleResponseAction< + ExecuteActionRequestBody, + ActionDetails + >('execute', options); + } + + async upload( + options: UploadActionApiRequestBody + ): Promise> { + const fleetFiles = await this.options.endpointContext.service.getFleetToHostFilesClient(); + const fileStream = options.file as HapiReadableStream; + const { file: _, parameters: userParams, ...actionPayload } = options; + const uploadParameters: ResponseActionUploadParameters = { + ...userParams, + file_id: '', + file_name: '', + file_sha256: '', + file_size: 0, + }; + + const createdFile = await fleetFiles.create(fileStream, actionPayload.endpoint_ids); + + uploadParameters.file_id = createdFile.id; + uploadParameters.file_name = createdFile.name; + uploadParameters.file_sha256 = createdFile.sha256; + uploadParameters.file_size = createdFile.size; + + const createFileActionOptions = { + ...actionPayload, + parameters: uploadParameters, + command: 'upload' as ResponseActionsApiCommandNames, + }; + + try { + const createdAction = await this.handleResponseAction< + typeof createFileActionOptions, + ActionDetails + >('upload', createFileActionOptions); + + // Update the file meta to include the action id, and if any errors (unlikely), + // then just log them and still allow api to return success since the action has + // already been created and potentially dispatched to Endpoint. Action ID is not + // needed by the Endpoint or fleet-server's API, so no need to fail here + try { + await fleetFiles.update(uploadParameters.file_id, { actionId: createdAction.id }); + } catch (e) { + this.log.warn(`Attempt to update File meta with Action ID failed: ${e.message}`, e); + } + + return createdAction; + } catch (err) { + if (uploadParameters.file_id) { + // Try to delete the created file since creating the action threw an error + try { + await fleetFiles.delete(uploadParameters.file_id); + } catch (e) { + this.log.error( + `Attempt to clean up file id [${uploadParameters.file_id}] (after action creation was unsuccessful) failed; ${e.message}`, + e + ); + } + } + + throw err; + } + } +} diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/index.ts new file mode 100644 index 000000000000..83a11352dfe9 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { EndpointActionsClient } from './endpoint_actions_client'; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts index aef5082bbb4a..f8a10b18d594 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/create/types.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type { AuthenticationServiceStart } from '@kbn/security-plugin/server'; import type { LicenseType } from '@kbn/licensing-plugin/server'; import type { TypeOf } from '@kbn/config-schema'; import type { ResponseActionBodySchema } from '../../../../../common/api/endpoint'; @@ -17,7 +16,7 @@ import type { ResponseActionsApiCommandNames } from '../../../../../common/endpo export type CreateActionPayload = TypeOf & { command: ResponseActionsApiCommandNames; - user?: ReturnType; + user?: { username: string } | null | undefined; rule_id?: string; rule_name?: string; error?: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts index e41014650554..95a8687324d1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts @@ -6,6 +6,7 @@ */ import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; +import { requiredOptional } from '@kbn/zod-helpers'; import { DEFAULT_MAX_SIGNALS } from '../../../../../../../common/constants'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import type { @@ -123,7 +124,7 @@ const extractDiffableCommonFields = ( severity: rule.severity, severity_mapping: rule.severity_mapping ?? [], risk_score: rule.risk_score, - risk_score_mapping: rule.risk_score_mapping ?? [], + risk_score_mapping: rule.risk_score_mapping?.map((mapping) => requiredOptional(mapping)) ?? [], // About -> Advanced settings references: rule.references ?? [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index 0ec1d5580f40..06ccf0a2b97f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -17,7 +17,7 @@ describe('Prebuilt rule asset schema', () => { const result = PrebuiltRuleAsset.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, rule_id: Required, and 26 more"` + `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', and 2 more"` ); }); @@ -40,7 +40,7 @@ describe('Prebuilt rule asset schema', () => { const result = PrebuiltRuleAsset.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"name: Required, description: Required, risk_score: Required, severity: Required, version: Required, and 25 more"` + `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', and 1 more"` ); }); @@ -177,7 +177,7 @@ describe('Prebuilt rule asset schema', () => { const result = PrebuiltRuleAsset.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` + `"index.0: Expected string, received number"` ); }); @@ -201,7 +201,7 @@ describe('Prebuilt rule asset schema', () => { const result = PrebuiltRuleAsset.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 20 more"` + `"filters: Expected array, received string"` ); }); @@ -236,7 +236,7 @@ describe('Prebuilt rule asset schema', () => { const result = PrebuiltRuleAsset.safeParse(payload); expectParseError(result); expect(stringifyZodError(result.error)).toMatchInlineSnapshot( - `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 19 more"` + `"language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up'"` ); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts index f65d788945de..cb0b48b8e3f0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts @@ -35,6 +35,8 @@ import type { import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks'; import type { EndpointAuthz } from '../../../../../common/endpoint/types/authz'; import { riskEngineDataClientMock } from '../../../entity_analytics/risk_engine/risk_engine_data_client.mock'; +import { riskScoreDataClientMock } from '../../../entity_analytics/risk_score/risk_score_data_client.mock'; +import { assetCriticalityDataClientMock } from '../../../entity_analytics/asset_criticality/asset_criticality_data_client.mock'; export const createMockClients = () => { const core = coreMock.createRequestHandlerContext(); @@ -63,6 +65,8 @@ export const createMockClients = () => { detectionEngineHealthClient: detectionEngineHealthClientMock.create(), ruleExecutionLog: ruleExecutionLogMock.forRoutes.create(), riskEngineDataClient: riskEngineDataClientMock.create(), + riskScoreDataClient: riskScoreDataClientMock.create(), + assetCriticalityDataClient: assetCriticalityDataClientMock.create(), }; }; @@ -142,6 +146,8 @@ const createSecuritySolutionRequestContextMock = ( throw new Error('Not implemented'); }), getRiskEngineDataClient: jest.fn(() => clients.riskEngineDataClient), + getRiskScoreDataClient: jest.fn(() => clients.riskScoreDataClient), + getAssetCriticalityDataClient: jest.fn(() => clients.assetCriticalityDataClient), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 78d8eecc109f..2f6ea38b40b8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -506,6 +506,11 @@ export const getSignalsMigrationStatusRequest = () => query: getSignalsMigrationStatusSchemaMock(), }); +export const getMockUserProfiles = () => [ + { uid: 'default-test-assignee-id-1', enabled: true, user: { username: 'user1' }, data: {} }, + { uid: 'default-test-assignee-id-2', enabled: true, user: { username: 'user2' }, data: {} }, +]; + /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/helpers.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/helpers.ts index a557586a008f..41a5ddfae2be 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AlertTags } from '../../../../../common/api/detection_engine'; +import type { AlertTags, AlertAssignees } from '../../../../../common/api/detection_engine'; import * as i18n from './translations'; export const validateAlertTagsArrays = (tags: AlertTags, ids: string[]) => { @@ -20,3 +20,13 @@ export const validateAlertTagsArrays = (tags: AlertTags, ids: string[]) => { } return validationErrors; }; + +export const validateAlertAssigneesArrays = (assignees: AlertAssignees) => { + const validationErrors = []; + const { add: assigneesToAdd, remove: assigneesToRemove } = assignees; + const duplicates = assigneesToAdd.filter((assignee) => assigneesToRemove.includes(assignee)); + if (duplicates.length) { + validationErrors.push(i18n.ALERT_ASSIGNEES_VALIDATION_ERROR(JSON.stringify(duplicates))); + } + return validationErrors; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts new file mode 100644 index 000000000000..dfc0603598a0 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.test.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSetAlertAssigneesRequestMock } from '../../../../../common/api/detection_engine/alert_assignees/mocks'; +import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL } from '../../../../../common/constants'; +import { requestContextMock, serverMock, requestMock } from '../__mocks__'; +import { getSuccessfulSignalUpdateResponse } from '../__mocks__/request_responses'; +import { setAlertAssigneesRoute } from './set_alert_assignees_route'; + +describe('setAlertAssigneesRoute', () => { + let server: ReturnType; + let request: ReturnType; + let { context } = requestContextMock.createTools(); + + beforeEach(() => { + server = serverMock.create(); + ({ context } = requestContextMock.createTools()); + setAlertAssigneesRoute(server.router); + }); + + describe('happy path', () => { + test('returns 200 when adding/removing empty arrays of assignees', async () => { + request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: getSetAlertAssigneesRequestMock(['assignee-id-1'], ['assignee-id-2'], ['alert-id']), + }); + + context.core.elasticsearch.client.asCurrentUser.bulk.mockResponse({ + errors: false, + took: 0, + items: [{ update: { result: 'updated', status: 200, _index: 'test-index' } }], + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + }); + }); + + describe('validation', () => { + test('returns 400 if duplicate assignees are in both the add and remove arrays', async () => { + request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: getSetAlertAssigneesRequestMock(['assignee-id-1'], ['assignee-id-1'], ['test-id']), + }); + + context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockResponse( + getSuccessfulSignalUpdateResponse() + ); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockRejectedValue( + new Error('Test error') + ); + + expect(response.body).toEqual({ + message: [ + `Duplicate assignees [\"assignee-id-1\"] were found in the add and remove parameters.`, + ], + status_code: 400, + }); + }); + + test('rejects if no alert ids are provided', async () => { + request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: getSetAlertAssigneesRequestMock(['assignee-id-1'], ['assignee-id-2']), + }); + + const result = server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'ids: Array must contain at least 1 element(s)' + ); + }); + + test('rejects if empty string provided as an alert id', async () => { + request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: getSetAlertAssigneesRequestMock(['assignee-id-1'], ['assignee-id-2'], ['']), + }); + + const result = server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'ids.0: String must contain at least 1 character(s), ids.0: Invalid' + ); + }); + }); + + describe('500s', () => { + test('returns 500 if asCurrentUser throws error', async () => { + request = requestMock.create({ + method: 'post', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: getSetAlertAssigneesRequestMock(['assignee-id-1'], ['assignee-id-2'], ['test-id']), + }); + + context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockRejectedValue( + new Error('Test error') + ); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.body).toEqual({ + message: 'Test error', + status_code: 500, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts new file mode 100644 index 000000000000..f15342a36f46 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { transformError } from '@kbn/securitysolution-es-utils'; +import { uniq } from 'lodash/fp'; +import { SetAlertAssigneesRequestBody } from '../../../../../common/api/detection_engine/alert_assignees'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { + DEFAULT_ALERTS_INDEX, + DETECTION_ENGINE_ALERT_ASSIGNEES_URL, +} from '../../../../../common/constants'; +import { buildSiemResponse } from '../utils'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { validateAlertAssigneesArrays } from './helpers'; + +export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => { + router.versioned + .post({ + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + access: 'public', + options: { + tags: ['access:securitySolution'], + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: { + request: { + body: buildRouteValidationWithZod(SetAlertAssigneesRequestBody), + }, + }, + }, + async (context, request, response) => { + const { assignees, ids } = request.body; + const core = await context.core; + const securitySolution = await context.securitySolution; + const esClient = core.elasticsearch.client.asCurrentUser; + const siemResponse = buildSiemResponse(response); + const validationErrors = validateAlertAssigneesArrays(assignees); + const spaceId = securitySolution?.getSpaceId() ?? 'default'; + + if (validationErrors.length) { + return siemResponse.error({ statusCode: 400, body: validationErrors }); + } + + const assigneesToAdd = uniq(assignees.add); + const assigneesToRemove = uniq(assignees.remove); + + const painlessScript = { + params: { assigneesToAdd, assigneesToRemove }, + source: `List newAssigneesArray = []; + if (ctx._source["kibana.alert.workflow_assignee_ids"] != null) { + for (assignee in ctx._source["kibana.alert.workflow_assignee_ids"]) { + if (!params.assigneesToRemove.contains(assignee)) { + newAssigneesArray.add(assignee); + } + } + for (assignee in params.assigneesToAdd) { + if (!newAssigneesArray.contains(assignee)) { + newAssigneesArray.add(assignee) + } + } + ctx._source["kibana.alert.workflow_assignee_ids"] = newAssigneesArray; + } else { + ctx._source["kibana.alert.workflow_assignee_ids"] = params.assigneesToAdd; + } + `, + lang: 'painless', + }; + + const bulkUpdateRequest = []; + for (const id of ids) { + bulkUpdateRequest.push( + { + update: { + _index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`, + _id: id, + }, + }, + { + script: painlessScript, + } + ); + } + + try { + const body = await esClient.updateByQuery({ + index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`, + refresh: true, + body: { + script: painlessScript, + query: { + bool: { + filter: { terms: { _id: ids } }, + }, + }, + }, + }); + return response.ok({ body }); + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/translations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/translations.ts index 715537fee47a..e6b4e25e641e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/translations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/translations.ts @@ -20,3 +20,10 @@ export const NO_IDS_VALIDATION_ERROR = i18n.translate( defaultMessage: 'No alert ids were provided', } ); + +export const ALERT_ASSIGNEES_VALIDATION_ERROR = (duplicates: string) => + i18n.translate('xpack.securitySolution.api.alertAssignees.validationError', { + values: { duplicates }, + defaultMessage: + 'Duplicate assignees { duplicates } were found in the add and remove parameters.', + }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.test.ts new file mode 100644 index 000000000000..bd36547a5c96 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.test.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { securityMock } from '@kbn/security-plugin/server/mocks'; + +import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL } from '../../../../../common/constants'; +import { requestContextMock, serverMock, requestMock } from '../__mocks__'; +import { getMockUserProfiles } from '../__mocks__/request_responses'; +import { suggestUserProfilesRoute } from './suggest_user_profiles_route'; + +describe('suggestUserProfilesRoute', () => { + let server: ReturnType; + let { context } = requestContextMock.createTools(); + let mockSecurityStart: ReturnType; + let getStartServicesMock: jest.Mock; + + beforeEach(() => { + server = serverMock.create(); + ({ context } = requestContextMock.createTools()); + mockSecurityStart = securityMock.createStart(); + mockSecurityStart.userProfiles.suggest.mockResolvedValue(getMockUserProfiles()); + }); + + const buildRequest = () => { + return requestMock.create({ + method: 'get', + path: DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + body: { searchTerm: '' }, + }); + }; + + describe('normal status codes', () => { + beforeEach(() => { + getStartServicesMock = jest.fn().mockResolvedValue([{}, { security: mockSecurityStart }]); + suggestUserProfilesRoute(server.router, getStartServicesMock); + }); + + it('returns 200 when doing a normal request', async () => { + const request = buildRequest(); + const response = await server.inject(request, requestContextMock.convertContext(context)); + expect(response.status).toEqual(200); + }); + + test('returns the payload when doing a normal request', async () => { + const request = buildRequest(); + const response = await server.inject(request, requestContextMock.convertContext(context)); + const expectedBody = getMockUserProfiles(); + expect(response.status).toEqual(200); + expect(response.body).toEqual(expectedBody); + }); + + test('returns 500 if `security.userProfiles.suggest` throws error', async () => { + mockSecurityStart.userProfiles.suggest.mockRejectedValue(new Error('something went wrong')); + const request = buildRequest(); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(500); + expect(response.body.message).toEqual('something went wrong'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts new file mode 100644 index 000000000000..fcb42d2ead7e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IKibanaResponse, StartServicesAccessor } from '@kbn/core/server'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL } from '../../../../../common/constants'; +import { buildSiemResponse } from '../utils'; +import type { StartPlugins } from '../../../../plugin'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { SuggestUserProfilesRequestQuery } from '../../../../../common/api/detection_engine/users'; + +export const suggestUserProfilesRoute = ( + router: SecuritySolutionPluginRouter, + getStartServices: StartServicesAccessor +) => { + router.versioned + .get({ + path: DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL, + access: 'public', + options: { + tags: ['access:securitySolution'], + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: { + request: { + query: buildRouteValidationWithZod(SuggestUserProfilesRequestQuery), + }, + }, + }, + async (context, request, response): Promise> => { + const { searchTerm } = request.query; + const siemResponse = buildSiemResponse(response); + const [_, { security }] = await getStartServices(); + const securitySolution = await context.securitySolution; + const spaceId = securitySolution.getSpaceId(); + + try { + const users = await security.userProfiles.suggest({ + name: searchTerm, + dataPath: 'avatar', + requiredPrivileges: { + spaceId, + privileges: { + kibana: [security.authz.actions.login], + }, + }, + }); + + return response.ok({ body: users }); + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index a1d74b144550..f45f005c7c34 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -237,7 +237,7 @@ describe('Create rule route', () => { }); const result = await server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "saved_query", saved_id: Required, type: Invalid literal value, expected "threshold", and 18 more' + 'response_actions.0.action_type_id: Invalid literal value, expected ".osquery", response_actions.0.params.command: Invalid literal value, expected "isolate"' ); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index f95b10fa6154..6bdafa76fd9b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -284,7 +284,7 @@ describe('Update rule route', () => { }); const result = await server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "saved_query", saved_id: Required, type: Invalid literal value, expected "threshold", and 18 more' + `response_actions.0.action_type_id: Invalid literal value, expected \".osquery\", response_actions.0.params.command: Invalid literal value, expected \"isolate\"` ); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts index be9561598fd0..b6cffd47a494 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/import/create_rules_stream_from_ndjson.test.ts @@ -283,7 +283,7 @@ describe('create_rules_stream_from_ndjson', () => { immutable: false, }); expect(resultOrError[1].message).toContain( - 'name: Required, description: Required, risk_score: Required, severity: Required, rule_id: Required, and 25 more' + `name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid discriminator value. Expected 'eql' | 'query' | 'saved_query' | 'threshold' | 'threat_match' | 'machine_learning' | 'new_terms' | 'esql', and 1 more` ); expect(resultOrError[2]).toEqual({ rule_id: 'rule-2', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts index a513e8468d57..8fa275c7ba59 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts @@ -95,7 +95,7 @@ describe('validate', () => { delete ruleAlert.name; expect(() => { transformValidate(ruleAlert); - }).toThrowError('Invalid input'); + }).toThrowError('Required'); }); }); @@ -113,8 +113,7 @@ describe('validate', () => { const validatedOrError = transformValidateBulkError('rule-1', ruleAlert); const expected: BulkError = { error: { - message: - 'name: Required, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", name: Required, name: Required, and 22 more', + message: 'name: Required', status_code: 500, }, rule_id: 'rule-1', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/osquery_response_action.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/osquery_response_action.ts index c8dfa113af6a..5852e6f964c7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/osquery_response_action.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/osquery_response_action.ts @@ -7,6 +7,7 @@ import { each, map, some, uniq } from 'lodash'; import { containsDynamicQuery } from '@kbn/osquery-plugin/common/utils/replace_params_query'; +import { requiredOptional } from '@kbn/zod-helpers'; import type { ResponseActionAlerts } from './types'; import type { SetupPlugins } from '../../../plugin_contract'; import type { RuleResponseOsqueryAction } from '../../../../common/api/detection_engine/model/rule_response_actions'; @@ -32,7 +33,7 @@ export const osqueryResponseAction = ( return osqueryCreateActionService.create({ ...rest, - queries, + queries: requiredOptional(queries), ecs_mapping: ecsMapping, saved_query_id: savedQueryId, agent_ids: agentIds, @@ -43,7 +44,7 @@ export const osqueryResponseAction = ( return osqueryCreateActionService.create( { ...rest, - queries, + queries: requiredOptional(queries), ecs_mapping: ecsMapping, saved_query_id: savedQueryId, agent_ids: alert.agent?.id ? [alert.agent.id] : [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts index 6a522193558a..8d134ad21539 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/es_results.ts @@ -52,6 +52,7 @@ import { ALERT_STATUS_ACTIVE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, EVENT_KIND, @@ -322,6 +323,7 @@ export const sampleAlertDocAADNoSortId = ( }, [ALERT_URL]: 'http://example.com/docID', [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], }, fields: { someKey: ['someValue'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts index a9ae0d1d5569..4cf64c60de22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts @@ -19,6 +19,7 @@ import { ALERT_STATUS_ACTIVE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, EVENT_ACTION, @@ -233,6 +234,7 @@ describe('buildAlert', () => { [ALERT_URL]: expectedAlertUrl, [ALERT_UUID]: alertUuid, [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], }; expect(alert).toEqual(expected); }); @@ -426,6 +428,7 @@ describe('buildAlert', () => { [ALERT_URL]: expectedAlertUrl, [ALERT_UUID]: alertUuid, [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], }; expect(alert).toEqual(expected); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts index 2309833a947f..846c714a9c09 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts @@ -36,6 +36,7 @@ import { ALERT_STATUS_ACTIVE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, EVENT_KIND, @@ -43,6 +44,7 @@ import { TIMESTAMP, } from '@kbn/rule-data-utils'; import { flattenWithPrefix } from '@kbn/securitysolution-rules'; +import { requiredOptional } from '@kbn/zod-helpers'; import { createHash } from 'crypto'; @@ -229,7 +231,7 @@ export const buildAlert = ( [ALERT_RULE_NAMESPACE_FIELD]: params.namespace, [ALERT_RULE_NOTE]: params.note, [ALERT_RULE_REFERENCES]: params.references, - [ALERT_RULE_RISK_SCORE_MAPPING]: params.riskScoreMapping, + [ALERT_RULE_RISK_SCORE_MAPPING]: requiredOptional(params.riskScoreMapping), [ALERT_RULE_RULE_ID]: params.ruleId, [ALERT_RULE_RULE_NAME_OVERRIDE]: params.ruleNameOverride, [ALERT_RULE_SEVERITY_MAPPING]: params.severityMapping, @@ -248,6 +250,7 @@ export const buildAlert = ( [ALERT_URL]: alertUrl, [ALERT_UUID]: alertUuid, [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], ...flattenWithPrefix(ALERT_RULE_META, params.meta), // These fields don't exist in the mappings, but leaving here for now to limit changes to the alert building logic 'kibana.alert.rule.risk_score': params.riskScore, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts index 50df9b714c3c..fb1aa57fdb82 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_bulk_body.ts @@ -7,6 +7,7 @@ import { flattenWithPrefix } from '@kbn/securitysolution-rules'; import type * as estypes from '@elastic/elasticsearch/lib/api/types'; +import { requiredOptional } from '@kbn/zod-helpers'; import type { BaseHit, SearchTypes } from '../../../../../../common/detection_engine/types'; import type { ConfigType } from '../../../../../config'; @@ -92,7 +93,7 @@ export const buildBulkBody = ( riskScoreOverride: buildRiskScoreFromMapping({ eventSource: mergedDoc._source ?? {}, riskScore: completeRule.ruleParams.riskScore, - riskScoreMapping: completeRule.ruleParams.riskScoreMapping, + riskScoreMapping: requiredOptional(completeRule.ruleParams.riskScoreMapping), }).riskScore, } : undefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/__mocks__/alerts.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/__mocks__/alerts.ts index 9ffdc8eafd7f..e19e7ad1bc0e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/__mocks__/alerts.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/enrichments/__mocks__/alerts.ts @@ -40,6 +40,7 @@ import { ALERT_STATUS_ACTIVE, ALERT_URL, ALERT_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, EVENT_KIND, @@ -96,6 +97,7 @@ export const createAlert = ( [ALERT_STATUS]: ALERT_STATUS_ACTIVE, [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], [ALERT_DEPTH]: 1, [ALERT_REASON]: 'reasonable reason', [ALERT_SEVERITY]: 'high', diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts new file mode 100644 index 000000000000..eaf3e9a3ec22 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.mock.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AssetCriticalityDataClient } from './asset_criticality_data_client'; + +const createAssetCriticalityDataClientMock = () => + ({ + doesIndexExist: jest.fn(), + getStatus: jest.fn(), + init: jest.fn(), + } as unknown as jest.Mocked); + +export const assetCriticalityDataClientMock = { create: createAssetCriticalityDataClientMock }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts new file mode 100644 index 000000000000..c06586516d68 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { AssetCriticalityDataClient } from './asset_criticality_data_client'; + +import { createOrUpdateIndex } from '../utils/create_or_update_index'; + +jest.mock('../utils/create_or_update_index', () => ({ + createOrUpdateIndex: jest.fn(), +})); + +describe('AssetCriticalityDataClient', () => { + const esClientInternal = elasticsearchServiceMock.createScopedClusterClient().asInternalUser; + const logger = loggingSystemMock.createLogger(); + describe('init', () => { + it('ensures the index is available and up to date', async () => { + const assetCriticalityDataClient = new AssetCriticalityDataClient({ + esClient: esClientInternal, + logger, + namespace: 'default', + }); + + await assetCriticalityDataClient.init(); + + expect(createOrUpdateIndex).toHaveBeenCalledWith({ + esClient: esClientInternal, + logger, + options: { + index: '.asset-criticality.asset-criticality-default', + mappings: { + dynamic: 'strict', + properties: { + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + criticality_level: { + type: 'keyword', + }, + '@timestamp': { + type: 'date', + ignore_malformed: false, + }, + updated_at: { + type: 'date', + }, + }, + }, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts new file mode 100644 index 000000000000..6bb003df0fa8 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger, ElasticsearchClient } from '@kbn/core/server'; +import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; +import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics/asset_criticality'; +import { createOrUpdateIndex } from '../utils/create_or_update_index'; +import { getAssetCriticalityIndex } from '../../../../common/asset_criticality'; +import { assetCriticalityFieldMap } from './configurations'; + +interface AssetCriticalityClientOpts { + logger: Logger; + esClient: ElasticsearchClient; + namespace: string; +} + +interface AssetCriticalityUpsert { + idField: AssetCriticalityRecord['id_field']; + idValue: AssetCriticalityRecord['id_value']; + criticalityLevel: AssetCriticalityRecord['criticality_level']; +} + +type AssetCriticalityIdParts = Pick; + +const createId = ({ idField, idValue }: AssetCriticalityIdParts) => `${idField}:${idValue}`; +export class AssetCriticalityDataClient { + constructor(private readonly options: AssetCriticalityClientOpts) {} + /** + * It will create idex for asset criticality, + * or update mappings if index exists + */ + public async init() { + await createOrUpdateIndex({ + esClient: this.options.esClient, + logger: this.options.logger, + options: { + index: this.getIndex(), + mappings: mappingFromFieldMap(assetCriticalityFieldMap, 'strict'), + }, + }); + } + + private getIndex() { + return getAssetCriticalityIndex(this.options.namespace); + } + + public async doesIndexExist() { + try { + const result = await this.options.esClient.indices.exists({ + index: this.getIndex(), + }); + return result; + } catch (e) { + return false; + } + } + + public async getStatus() { + const isAssetCriticalityResourcesInstalled = await this.doesIndexExist(); + + return { + isAssetCriticalityResourcesInstalled, + }; + } + + public async get(idParts: AssetCriticalityIdParts): Promise { + const id = createId(idParts); + + try { + const body = await this.options.esClient.get({ + id, + index: this.getIndex(), + }); + + return body._source; + } catch (err) { + if (err.statusCode === 404) { + return undefined; + } else { + throw err; + } + } + } + + public async upsert(record: AssetCriticalityUpsert): Promise { + const id = createId(record); + const doc = { + id_field: record.idField, + id_value: record.idValue, + criticality_level: record.criticalityLevel, + '@timestamp': new Date().toISOString(), + }; + + await this.options.esClient.update({ + id, + index: this.getIndex(), + body: { + doc, + doc_as_upsert: true, + }, + }); + + return doc; + } + + public async delete(idParts: AssetCriticalityIdParts) { + await this.options.esClient.delete({ + id: createId(idParts), + index: this.getIndex(), + }); + } +} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.test.ts new file mode 100644 index 000000000000..b0afd8e35952 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { requestContextMock } from '../../detection_engine/routes/__mocks__'; +import { AssetCriticalityDataClient } from './asset_criticality_data_client'; +import { checkAndInitAssetCriticalityResources } from './check_and_init_asset_criticality_resources'; + +describe('checkAndInitAssetCriticalityResources', () => { + const logger = loggingSystemMock.createLogger(); + const { context } = requestContextMock.createTools(); + const doesIndexExist = jest.spyOn(AssetCriticalityDataClient.prototype, 'doesIndexExist'); + const initAssetCriticality = jest.spyOn(AssetCriticalityDataClient.prototype, 'init'); + + beforeEach(() => { + doesIndexExist.mockImplementation(() => Promise.resolve(false)); + initAssetCriticality.mockImplementation(() => Promise.resolve()); + }); + + afterEach(() => { + doesIndexExist.mockReset(); + initAssetCriticality.mockReset(); + }); + + it('should initialise asset criticality resources if they do not exist', async () => { + await checkAndInitAssetCriticalityResources(requestContextMock.convertContext(context), logger); + + expect(initAssetCriticality).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith('Asset criticality resources installed'); + }); + + it('should not initialise asset criticality resources if they already exist', async () => { + doesIndexExist.mockImplementationOnce(() => Promise.resolve(true)); + await checkAndInitAssetCriticalityResources(requestContextMock.convertContext(context), logger); + + expect(initAssetCriticality).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.ts new file mode 100644 index 000000000000..08843c90a173 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/check_and_init_asset_criticality_resources.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import { AssetCriticalityDataClient } from './asset_criticality_data_client'; +import type { SecuritySolutionRequestHandlerContext } from '../../../types'; + +/** + * As internal user we check for existence of asset crititcality resources + * and initialise it if it does not exist + * @param context + * @param logger + */ +export const checkAndInitAssetCriticalityResources = async ( + context: SecuritySolutionRequestHandlerContext, + logger: Logger +) => { + const securityContext = await context.securitySolution; + const coreContext = await context.core; + const esClient = coreContext.elasticsearch.client.asInternalUser; + + const assetCriticalityDataClient = new AssetCriticalityDataClient({ + esClient, + logger, + namespace: securityContext.getSpaceId(), + }); + + const doesIndexExist = await assetCriticalityDataClient.doesIndexExist(); + + if (!doesIndexExist) { + logger.info('Asset criticality resources are not installed, initialising...'); + await assetCriticalityDataClient.init(); + logger.info('Asset criticality resources installed'); + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts new file mode 100644 index 000000000000..c1b309c3a2f4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/configurations.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { FieldMap } from '@kbn/alerts-as-data-utils'; + +export const assetCriticalityFieldMap: FieldMap = { + '@timestamp': { + type: 'date', + array: false, + required: false, + }, + id_field: { + type: 'keyword', + array: false, + required: false, + }, + id_value: { + type: 'keyword', + array: false, + required: false, + }, + criticality_level: { + type: 'keyword', + array: false, + required: false, + }, + updated_at: { + type: 'date', + array: false, + required: false, + }, +} as const; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts new file mode 100644 index 000000000000..1dae71a02f56 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { AssetCriticalityRecordIdParts } from '../../../../../common/api/entity_analytics/asset_criticality'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; +export const assetCriticalityDeleteRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .delete({ + access: 'internal', + path: ASSET_CRITICALITY_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts), + }, + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + await assetCriticalityClient.delete({ + idField: request.query.id_field, + idValue: request.query.id_value, + }); + + return response.ok(); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts new file mode 100644 index 000000000000..dce278756ce2 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { AssetCriticalityRecordIdParts } from '../../../../../common/api/entity_analytics/asset_criticality'; +export const assetCriticalityGetRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { + router.versioned + .get({ + access: 'internal', + path: ASSET_CRITICALITY_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts), + }, + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const record = await assetCriticalityClient.get({ + idField: request.query.id_field, + idValue: request.query.id_value, + }); + + if (!record) { + return response.notFound(); + } + + return response.ok({ body: record }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/index.ts new file mode 100644 index 000000000000..8a5f62ccff07 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { assetCriticalityStatusRoute } from './status'; +export { assetCriticalityUpsertRoute } from './upsert'; +export { assetCriticalityGetRoute } from './get'; +export { assetCriticalityDeleteRoute } from './delete'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts new file mode 100644 index 000000000000..cb5625c57f1e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import type { AssetCriticalityStatusResponse } from '../../../../../common/api/entity_analytics/asset_criticality'; +import { ASSET_CRITICALITY_STATUS_URL, APP_ID } from '../../../../../common/constants'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; + +export const assetCriticalityStatusRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .get({ + access: 'internal', + path: ASSET_CRITICALITY_STATUS_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion({ version: '1', validate: {} }, async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + + const result = await assetCriticalityClient.getStatus(); + const body: AssetCriticalityStatusResponse = { + asset_criticality_resources_installed: result.isAssetCriticalityResourcesInstalled, + }; + return response.ok({ + body, + }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts new file mode 100644 index 000000000000..65f71bb3bfe4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { CreateAssetCriticalityRecord } from '../../../../../common/api/entity_analytics/asset_criticality'; +export const assetCriticalityUpsertRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .post({ + access: 'internal', + path: ASSET_CRITICALITY_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: buildRouteValidationWithZod(CreateAssetCriticalityRecord), + }, + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + + const assetCriticalityRecord = { + idField: request.body.id_field, + idValue: request.body.id_value, + criticalityLevel: request.body.criticality_level, + }; + + const result = await assetCriticalityClient.upsert(assetCriticalityRecord); + + return response.ok({ + body: result, + }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts deleted file mode 100644 index 35547187e4dd..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { FieldMap } from '@kbn/alerts-as-data-utils'; -import type { IdentifierType } from '../../../../common/risk_engine'; -import { RiskScoreEntity, riskScoreBaseIndexName } from '../../../../common/risk_engine'; -import type { IIndexPatternString } from './utils/create_datastream'; - -const commonRiskFields: FieldMap = { - id_field: { - type: 'keyword', - array: false, - required: false, - }, - id_value: { - type: 'keyword', - array: false, - required: false, - }, - calculated_level: { - type: 'keyword', - array: false, - required: false, - }, - calculated_score: { - type: 'float', - array: false, - required: false, - }, - calculated_score_norm: { - type: 'float', - array: false, - required: false, - }, - category_1_score: { - type: 'float', - array: false, - required: false, - }, - category_1_count: { - type: 'long', - array: false, - required: false, - }, - inputs: { - type: 'object', - array: true, - required: false, - }, - 'inputs.id': { - type: 'keyword', - array: false, - required: false, - }, - 'inputs.index': { - type: 'keyword', - array: false, - required: false, - }, - 'inputs.category': { - type: 'keyword', - array: false, - required: false, - }, - 'inputs.description': { - type: 'keyword', - array: false, - required: false, - }, - 'inputs.risk_score': { - type: 'float', - array: false, - required: false, - }, - 'inputs.timestamp': { - type: 'date', - array: false, - required: false, - }, - notes: { - type: 'keyword', - array: false, - required: false, - }, -}; - -const buildIdentityRiskFields = (identifierType: IdentifierType): FieldMap => - Object.keys(commonRiskFields).reduce((fieldMap, key) => { - const identifierKey = `${identifierType}.risk.${key}`; - fieldMap[identifierKey] = commonRiskFields[key]; - return fieldMap; - }, {} as FieldMap); - -export const riskScoreFieldMap: FieldMap = { - '@timestamp': { - type: 'date', - array: false, - required: false, - }, - 'host.name': { - type: 'keyword', - array: false, - required: false, - }, - 'host.risk': { - type: 'object', - array: false, - required: false, - }, - ...buildIdentityRiskFields(RiskScoreEntity.host), - 'user.name': { - type: 'keyword', - array: false, - required: false, - }, - 'user.risk': { - type: 'object', - array: false, - required: false, - }, - ...buildIdentityRiskFields(RiskScoreEntity.user), -} as const; - -export const mappingComponentName = '.risk-score-mappings'; -export const totalFieldsLimit = 1000; - -export const getIndexPatternDataStream = (namespace: string): IIndexPatternString => ({ - template: `.${riskScoreBaseIndexName}.${riskScoreBaseIndexName}-${namespace}-index-template`, - alias: `${riskScoreBaseIndexName}.${riskScoreBaseIndexName}-${namespace}`, -}); - -export const getTransformOptions = ({ dest, source }: { dest: string; source: string[] }) => ({ - dest: { - index: dest, - }, - frequency: '1h', - latest: { - sort: '@timestamp', - unique_key: [`host.name`, `user.name`], - }, - source: { - index: source, - }, - sync: { - time: { - delay: '2s', - field: '@timestamp', - }, - }, -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_user_risk_engine_privileges.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_user_risk_engine_privileges.ts new file mode 100644 index 000000000000..d399b628c4ad --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_user_risk_engine_privileges.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core/server'; +import type { SecurityPluginStart } from '@kbn/security-plugin/server'; +import type { RiskEnginePrivilegesResponse } from '../types'; +import { + RISK_ENGINE_REQUIRED_ES_CLUSTER_PRIVILEGES, + RISK_ENGINE_REQUIRED_ES_INDEX_PRIVILEGES, +} from '../../../../common/risk_engine'; + +const groupPrivilegesByName = ( + privileges: Array<{ + privilege: PrivilegeName; + authorized: boolean; + }> +): Record => { + return privileges.reduce>((acc, { privilege, authorized }) => { + acc[privilege] = authorized; + return acc; + }, {}); +}; + +export async function getUserRiskEnginePrivileges( + request: KibanaRequest, + security: SecurityPluginStart +): Promise { + const checkPrivileges = security.authz.checkPrivilegesDynamicallyWithRequest(request); + const { privileges, hasAllRequested } = await checkPrivileges({ + elasticsearch: { + cluster: RISK_ENGINE_REQUIRED_ES_CLUSTER_PRIVILEGES, + index: RISK_ENGINE_REQUIRED_ES_INDEX_PRIVILEGES, + }, + }); + + const clusterPrivilegesByPrivilege = groupPrivilegesByName(privileges.elasticsearch.cluster); + + const indexPrivilegesByIndex = Object.entries(privileges.elasticsearch.index).reduce< + Record> + >((acc, [index, indexPrivileges]) => { + acc[index] = groupPrivilegesByName(indexPrivileges); + return acc; + }, {}); + + return { + privileges: { + elasticsearch: { + cluster: clusterPrivilegesByPrivilege, + index: indexPrivilegesByIndex, + }, + }, + has_all_required: hasAllRequested, + }; +} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts deleted file mode 100644 index 09836ff94fe2..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { AfterKey, AfterKeys, IdentifierType } from '../../../../common/risk_engine'; -import type { CalculateAndPersistScoresResponse } from './types'; - -export const getFieldForIdentifierAgg = (identifierType: IdentifierType): string => - identifierType === 'host' ? 'host.name' : 'user.name'; - -export const getAfterKeyForIdentifierType = ({ - afterKeys, - identifierType, -}: { - afterKeys: AfterKeys; - identifierType: IdentifierType; -}): AfterKey | undefined => afterKeys[identifierType]; - -export const isRiskScoreCalculationComplete = ( - result: CalculateAndPersistScoresResponse -): boolean => - Object.keys(result.after_keys.host ?? {}).length === 0 && - Object.keys(result.after_keys.user ?? {}).length === 0; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts index 53c7291aa497..a8d7b7a9c763 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts @@ -13,11 +13,8 @@ const createRiskEngineDataClientMock = () => disableRiskEngine: jest.fn(), enableRiskEngine: jest.fn(), getConfiguration: jest.fn(), - getRiskInputsIndex: jest.fn(), getStatus: jest.fn(), - getWriter: jest.fn(), init: jest.fn(), - initializeResources: jest.fn(), } as unknown as jest.Mocked); export const riskEngineDataClientMock = { create: createRiskEngineDataClientMock }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts index 619952859fc0..a155a320cb60 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts @@ -5,10 +5,6 @@ * 2.0. */ -import { - createOrUpdateComponentTemplate, - createOrUpdateIndexTemplate, -} from '@kbn/alerting-plugin/server'; import { loggingSystemMock, elasticsearchServiceMock, @@ -17,11 +13,11 @@ import { import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import type { SavedObject } from '@kbn/core/server'; import { RiskEngineDataClient } from './risk_engine_data_client'; -import type { RiskEngineConfiguration } from './types'; -import { createDataStream } from './utils/create_datastream'; +import { RiskScoreDataClient } from '../risk_score/risk_score_data_client'; +import type { RiskEngineConfiguration } from '../types'; import * as savedObjectConfig from './utils/saved_object_configuration'; -import * as transforms from './utils/transforms'; -import { createIndex } from './utils/create_index'; +import * as transforms from '../utils/transforms'; +import { riskScoreDataClientMock } from '../risk_score/risk_score_data_client.mock'; const getSavedObjectConfiguration = (attributes = {}) => ({ page: 1, @@ -47,32 +43,17 @@ const getSavedObjectConfiguration = (attributes = {}) => ({ ], }); -const transformsMock = { - count: 1, - transforms: [ - { - id: 'ml_hostriskscore_pivot_transform_default', - dest: { index: '' }, - source: { index: '' }, - }, - ], -}; - jest.mock('@kbn/alerting-plugin/server', () => ({ createOrUpdateComponentTemplate: jest.fn(), createOrUpdateIndexTemplate: jest.fn(), })); -jest.mock('./utils/create_datastream', () => ({ +jest.mock('../utils/create_datastream', () => ({ createDataStream: jest.fn(), })); -jest.mock('../../risk_score/transform/helpers/transforms', () => ({ - createAndStartTransform: jest.fn(), -})); - -jest.mock('./utils/create_index', () => ({ - createIndex: jest.fn(), +jest.mock('../utils/create_or_update_index', () => ({ + createOrUpdateIndex: jest.fn(), })); jest.spyOn(transforms, 'createTransform').mockResolvedValue(Promise.resolve()); @@ -87,7 +68,6 @@ describe('RiskEngineDataClient', () => { let mockSavedObjectClient: ReturnType; let logger: ReturnType; const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; - const totalFieldsLimit = 1000; beforeEach(() => { logger = loggingSystemMock.createLogger(); @@ -106,484 +86,6 @@ describe('RiskEngineDataClient', () => { jest.clearAllMocks(); }); - describe('getWriter', () => { - it('should return a writer object', async () => { - const writer = await riskEngineDataClient.getWriter({ namespace: 'default' }); - expect(writer).toBeDefined(); - expect(typeof writer?.bulk).toBe('function'); - }); - - it('should cache and return the same writer for the same namespace', async () => { - const writer1 = await riskEngineDataClient.getWriter({ namespace: 'default' }); - const writer2 = await riskEngineDataClient.getWriter({ namespace: 'default' }); - const writer3 = await riskEngineDataClient.getWriter({ namespace: 'space-1' }); - - expect(writer1).toEqual(writer2); - expect(writer2).not.toEqual(writer3); - }); - }); - - describe('initializeResources success', () => { - it('should initialize risk engine resources', async () => { - await riskEngineDataClient.initializeResources({ namespace: 'default' }); - - expect(createOrUpdateComponentTemplate).toHaveBeenCalledWith( - expect.objectContaining({ - logger, - esClient, - template: expect.objectContaining({ - name: '.risk-score-mappings', - _meta: { - managed: true, - }, - }), - totalFieldsLimit: 1000, - }) - ); - expect((createOrUpdateComponentTemplate as jest.Mock).mock.lastCall[0].template.template) - .toMatchInlineSnapshot(` - Object { - "mappings": Object { - "dynamic": "strict", - "properties": Object { - "@timestamp": Object { - "ignore_malformed": false, - "type": "date", - }, - "host": Object { - "properties": Object { - "name": Object { - "type": "keyword", - }, - "risk": Object { - "properties": Object { - "calculated_level": Object { - "type": "keyword", - }, - "calculated_score": Object { - "type": "float", - }, - "calculated_score_norm": Object { - "type": "float", - }, - "category_1_count": Object { - "type": "long", - }, - "category_1_score": Object { - "type": "float", - }, - "id_field": Object { - "type": "keyword", - }, - "id_value": Object { - "type": "keyword", - }, - "inputs": Object { - "properties": Object { - "category": Object { - "type": "keyword", - }, - "description": Object { - "type": "keyword", - }, - "id": Object { - "type": "keyword", - }, - "index": Object { - "type": "keyword", - }, - "risk_score": Object { - "type": "float", - }, - "timestamp": Object { - "type": "date", - }, - }, - "type": "object", - }, - "notes": Object { - "type": "keyword", - }, - }, - "type": "object", - }, - }, - }, - "user": Object { - "properties": Object { - "name": Object { - "type": "keyword", - }, - "risk": Object { - "properties": Object { - "calculated_level": Object { - "type": "keyword", - }, - "calculated_score": Object { - "type": "float", - }, - "calculated_score_norm": Object { - "type": "float", - }, - "category_1_count": Object { - "type": "long", - }, - "category_1_score": Object { - "type": "float", - }, - "id_field": Object { - "type": "keyword", - }, - "id_value": Object { - "type": "keyword", - }, - "inputs": Object { - "properties": Object { - "category": Object { - "type": "keyword", - }, - "description": Object { - "type": "keyword", - }, - "id": Object { - "type": "keyword", - }, - "index": Object { - "type": "keyword", - }, - "risk_score": Object { - "type": "float", - }, - "timestamp": Object { - "type": "date", - }, - }, - "type": "object", - }, - "notes": Object { - "type": "keyword", - }, - }, - "type": "object", - }, - }, - }, - }, - }, - "settings": Object {}, - } - `); - - expect(createOrUpdateIndexTemplate).toHaveBeenCalledWith({ - logger, - esClient, - template: { - name: '.risk-score.risk-score-default-index-template', - body: { - data_stream: { hidden: true }, - index_patterns: ['risk-score.risk-score-default'], - composed_of: ['.risk-score-mappings'], - template: { - lifecycle: {}, - settings: { - 'index.mapping.total_fields.limit': totalFieldsLimit, - }, - mappings: { - dynamic: false, - _meta: { - kibana: { - version: '8.9.0', - }, - managed: true, - namespace: 'default', - }, - }, - }, - _meta: { - kibana: { - version: '8.9.0', - }, - managed: true, - namespace: 'default', - }, - }, - }, - }); - - expect(createDataStream).toHaveBeenCalledWith({ - logger, - esClient, - totalFieldsLimit, - indexPatterns: { - template: `.risk-score.risk-score-default-index-template`, - alias: `risk-score.risk-score-default`, - }, - }); - - expect(createIndex).toHaveBeenCalledWith({ - logger, - esClient, - options: { - index: `risk-score.risk-score-latest-default`, - mappings: { - dynamic: 'strict', - properties: { - '@timestamp': { - ignore_malformed: false, - type: 'date', - }, - host: { - properties: { - name: { - type: 'keyword', - }, - risk: { - properties: { - calculated_level: { - type: 'keyword', - }, - calculated_score: { - type: 'float', - }, - calculated_score_norm: { - type: 'float', - }, - category_1_count: { - type: 'long', - }, - category_1_score: { - type: 'float', - }, - id_field: { - type: 'keyword', - }, - id_value: { - type: 'keyword', - }, - inputs: { - properties: { - category: { - type: 'keyword', - }, - description: { - type: 'keyword', - }, - id: { - type: 'keyword', - }, - index: { - type: 'keyword', - }, - risk_score: { - type: 'float', - }, - timestamp: { - type: 'date', - }, - }, - type: 'object', - }, - notes: { - type: 'keyword', - }, - }, - type: 'object', - }, - }, - }, - user: { - properties: { - name: { - type: 'keyword', - }, - risk: { - properties: { - calculated_level: { - type: 'keyword', - }, - calculated_score: { - type: 'float', - }, - calculated_score_norm: { - type: 'float', - }, - category_1_count: { - type: 'long', - }, - category_1_score: { - type: 'float', - }, - id_field: { - type: 'keyword', - }, - id_value: { - type: 'keyword', - }, - inputs: { - properties: { - category: { - type: 'keyword', - }, - description: { - type: 'keyword', - }, - id: { - type: 'keyword', - }, - index: { - type: 'keyword', - }, - risk_score: { - type: 'float', - }, - timestamp: { - type: 'date', - }, - }, - type: 'object', - }, - notes: { - type: 'keyword', - }, - }, - type: 'object', - }, - }, - }, - }, - }, - }, - }); - - expect(transforms.createTransform).toHaveBeenCalledWith({ - logger, - esClient, - transform: { - dest: { - index: 'risk-score.risk-score-latest-default', - }, - frequency: '1h', - latest: { - sort: '@timestamp', - unique_key: ['host.name', 'user.name'], - }, - source: { - index: ['risk-score.risk-score-default'], - }, - sync: { - time: { - delay: '2s', - field: '@timestamp', - }, - }, - transform_id: 'risk_score_latest_transform_default', - }, - }); - }); - }); - - describe('initializeResources error', () => { - it('should handle errors during initialization', async () => { - const error = new Error('There error'); - (createOrUpdateIndexTemplate as jest.Mock).mockRejectedValueOnce(error); - - try { - await riskEngineDataClient.initializeResources({ namespace: 'default' }); - } catch (e) { - expect(logger.error).toHaveBeenCalledWith( - `Error initializing risk engine resources: ${error.message}` - ); - } - }); - }); - - describe('getStatus', () => { - it('should return initial status', async () => { - const status = await riskEngineDataClient.getStatus({ - namespace: 'default', - }); - expect(status).toEqual({ - isMaxAmountOfRiskEnginesReached: false, - riskEngineStatus: 'NOT_INSTALLED', - legacyRiskEngineStatus: 'NOT_INSTALLED', - }); - }); - - describe('saved object exists and transforms not', () => { - beforeEach(() => { - mockSavedObjectClient.find.mockResolvedValue(getSavedObjectConfiguration()); - }); - - it('should return status with enabled true', async () => { - mockSavedObjectClient.find.mockResolvedValue( - getSavedObjectConfiguration({ - enabled: true, - }) - ); - - const status = await riskEngineDataClient.getStatus({ - namespace: 'default', - }); - expect(status).toEqual({ - isMaxAmountOfRiskEnginesReached: true, - riskEngineStatus: 'ENABLED', - legacyRiskEngineStatus: 'NOT_INSTALLED', - }); - }); - - it('should return status with enabled false', async () => { - mockSavedObjectClient.find.mockResolvedValue(getSavedObjectConfiguration()); - - const status = await riskEngineDataClient.getStatus({ - namespace: 'default', - }); - expect(status).toEqual({ - isMaxAmountOfRiskEnginesReached: false, - riskEngineStatus: 'DISABLED', - legacyRiskEngineStatus: 'NOT_INSTALLED', - }); - }); - }); - - describe('legacy transforms', () => { - it('should fetch transforms', async () => { - await riskEngineDataClient.getStatus({ - namespace: 'default', - }); - - expect(esClient.transform.getTransform).toHaveBeenCalledTimes(4); - expect(esClient.transform.getTransform).toHaveBeenNthCalledWith(1, { - transform_id: 'ml_hostriskscore_pivot_transform_default', - }); - expect(esClient.transform.getTransform).toHaveBeenNthCalledWith(2, { - transform_id: 'ml_hostriskscore_latest_transform_default', - }); - expect(esClient.transform.getTransform).toHaveBeenNthCalledWith(3, { - transform_id: 'ml_userriskscore_pivot_transform_default', - }); - expect(esClient.transform.getTransform).toHaveBeenNthCalledWith(4, { - transform_id: 'ml_userriskscore_latest_transform_default', - }); - }); - - it('should return that legacy transform enabled if at least on transform exist', async () => { - esClient.transform.getTransform.mockResolvedValueOnce(transformsMock); - - const status = await riskEngineDataClient.getStatus({ - namespace: 'default', - }); - - expect(status).toEqual({ - isMaxAmountOfRiskEnginesReached: false, - riskEngineStatus: 'NOT_INSTALLED', - legacyRiskEngineStatus: 'ENABLED', - }); - - esClient.transform.getTransformStats.mockReset(); - }); - }); - }); - describe('#getConfiguration', () => { it('retrieves configuration from the saved object', async () => { mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); @@ -703,10 +205,7 @@ describe('RiskEngineDataClient', () => { describe('init', () => { let mockTaskManagerStart: ReturnType; - const initializeResourcesMock = jest.spyOn( - RiskEngineDataClient.prototype, - 'initializeResources' - ); + const initRiskScore = jest.spyOn(RiskScoreDataClient.prototype, 'init'); const enableRiskEngineMock = jest.spyOn(RiskEngineDataClient.prototype, 'enableRiskEngine'); const disableLegacyRiskEngineMock = jest.spyOn( @@ -717,7 +216,7 @@ describe('RiskEngineDataClient', () => { mockTaskManagerStart = taskManagerMock.createStart(); disableLegacyRiskEngineMock.mockImplementation(() => Promise.resolve(true)); - initializeResourcesMock.mockImplementation(() => { + initRiskScore.mockImplementation(() => { return Promise.resolve(); }); @@ -731,7 +230,7 @@ describe('RiskEngineDataClient', () => { }); afterEach(() => { - initializeResourcesMock.mockReset(); + initRiskScore.mockReset(); enableRiskEngineMock.mockReset(); disableLegacyRiskEngineMock.mockReset(); }); @@ -740,6 +239,7 @@ describe('RiskEngineDataClient', () => { const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); expect(initResult).toEqual({ @@ -758,6 +258,7 @@ describe('RiskEngineDataClient', () => { const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); expect(initResult).toEqual({ @@ -777,6 +278,7 @@ describe('RiskEngineDataClient', () => { const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); expect(initResult).toEqual({ @@ -789,17 +291,19 @@ describe('RiskEngineDataClient', () => { }); it('should catch error for initializeResources and stop', async () => { - initializeResourcesMock.mockImplementationOnce(() => { - throw new Error('Error initializeResourcesMock'); + const riskScoreDataClient = riskScoreDataClientMock.create(); + riskScoreDataClient.init.mockImplementationOnce(() => { + throw new Error('Error riskScoreDataClient'); }); const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient, }); expect(initResult).toEqual({ - errors: ['Error initializeResourcesMock'], + errors: ['Error riskScoreDataClient'], legacyRiskEngineDisabled: true, riskEngineConfigurationCreated: false, riskEngineEnabled: false, @@ -815,6 +319,7 @@ describe('RiskEngineDataClient', () => { const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); expect(initResult).toEqual({ @@ -834,6 +339,7 @@ describe('RiskEngineDataClient', () => { const initResult = await riskEngineDataClient.init({ namespace: 'default', taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); expect(initResult).toEqual({ diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts index ea564ffe2395..e649fa24b213 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts @@ -5,58 +5,29 @@ * 2.0. */ -import type { Metadata } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { ClusterPutComponentTemplateRequest } from '@elastic/elasticsearch/lib/api/types'; -import { - createOrUpdateComponentTemplate, - createOrUpdateIndexTemplate, -} from '@kbn/alerting-plugin/server'; -import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; -import { DEFAULT_NAMESPACE_STRING } from '@kbn/core-saved-objects-utils-server'; import type { Logger, ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; - -import { - riskScoreFieldMap, - getIndexPatternDataStream, - totalFieldsLimit, - mappingComponentName, - getTransformOptions, -} from './configurations'; -import { createDataStream } from './utils/create_datastream'; -import type { RiskEngineDataWriter as Writer } from './risk_engine_data_writer'; -import { RiskEngineDataWriter } from './risk_engine_data_writer'; import type { InitRiskEngineResult } from '../../../../common/risk_engine'; import { RiskEngineStatus, - getRiskScoreLatestIndex, MAX_SPACES_COUNT, RiskScoreEntity, } from '../../../../common/risk_engine'; -import { - getLegacyTransforms, - getLatestTransformId, - removeLegacyTransforms, - createTransform, -} from './utils/transforms'; +import { removeLegacyTransforms, getLegacyTransforms } from '../utils/transforms'; import { updateSavedObjectAttribute, getConfiguration, initSavedObjects, getEnabledRiskEngineAmount, } from './utils/saved_object_configuration'; -import { getRiskInputsIndex } from './get_risk_inputs_index'; -import { removeRiskScoringTask, startRiskScoringTask } from './tasks'; -import { createIndex } from './utils/create_index'; import { bulkDeleteSavedObjects } from '../../risk_score/prebuilt_saved_objects/helpers/bulk_delete_saved_objects'; +import type { RiskScoreDataClient } from '../risk_score/risk_score_data_client'; +import { removeRiskScoringTask, startRiskScoringTask } from '../risk_score/tasks'; interface InitOpts { namespace: string; taskManager: TaskManagerStartContract; -} - -interface InitializeRiskEngineResourcesOpts { - namespace?: string; + riskScoreDataClient: RiskScoreDataClient; } interface RiskEngineDataClientOpts { @@ -68,10 +39,9 @@ interface RiskEngineDataClientOpts { } export class RiskEngineDataClient { - private writerCache: Map = new Map(); constructor(private readonly options: RiskEngineDataClientOpts) {} - public async init({ namespace, taskManager }: InitOpts) { + public async init({ namespace, taskManager, riskScoreDataClient }: InitOpts) { const result: InitRiskEngineResult = { legacyRiskEngineDisabled: false, riskEngineResourcesInstalled: false, @@ -88,7 +58,7 @@ export class RiskEngineDataClient { } try { - await this.initializeResources({ namespace }); + await riskScoreDataClient.init(); result.riskEngineResourcesInstalled = true; } catch (e) { result.errors.push(e.message); @@ -106,6 +76,7 @@ export class RiskEngineDataClient { return result; } + // should be the last step, after all resources are installed try { await this.enableRiskEngine({ taskManager }); result.riskEngineEnabled = true; @@ -117,39 +88,11 @@ export class RiskEngineDataClient { return result; } - public async getWriter({ namespace }: { namespace: string }): Promise { - if (this.writerCache.get(namespace)) { - return this.writerCache.get(namespace) as Writer; - } - const indexPatterns = getIndexPatternDataStream(namespace); - await this.initializeWriter(namespace, indexPatterns.alias); - return this.writerCache.get(namespace) as Writer; - } - - private async initializeWriter(namespace: string, index: string): Promise { - const writer = new RiskEngineDataWriter({ - esClient: this.options.esClient, - namespace, - index, - logger: this.options.logger, - }); - - this.writerCache.set(namespace, writer); - return writer; - } - public getConfiguration = () => getConfiguration({ savedObjectsClient: this.options.soClient, }); - public getRiskInputsIndex = ({ dataViewId }: { dataViewId: string }) => - getRiskInputsIndex({ - dataViewId, - logger: this.options.logger, - soClient: this.options.soClient, - }); - public async getStatus({ namespace }: { namespace: string }) { const riskEngineStatus = await this.getCurrentStatus(); const legacyRiskEngineStatus = await this.getLegacyStatus({ namespace }); @@ -258,96 +201,4 @@ export class RiskEngineDataClient { return RiskEngineStatus.ENABLED; } - - public async initializeResources({ - namespace = DEFAULT_NAMESPACE_STRING, - }: InitializeRiskEngineResourcesOpts) { - try { - const esClient = this.options.esClient; - - const indexPatterns = getIndexPatternDataStream(namespace); - - const indexMetadata: Metadata = { - kibana: { - version: this.options.kibanaVersion, - }, - managed: true, - namespace, - }; - - await Promise.all([ - createOrUpdateComponentTemplate({ - logger: this.options.logger, - esClient, - template: { - name: mappingComponentName, - _meta: { - managed: true, - }, - template: { - settings: {}, - mappings: mappingFromFieldMap(riskScoreFieldMap, 'strict'), - }, - } as ClusterPutComponentTemplateRequest, - totalFieldsLimit, - }), - ]); - - await createOrUpdateIndexTemplate({ - logger: this.options.logger, - esClient, - template: { - name: indexPatterns.template, - body: { - data_stream: { hidden: true }, - index_patterns: [indexPatterns.alias], - composed_of: [mappingComponentName], - template: { - lifecycle: {}, - settings: { - 'index.mapping.total_fields.limit': totalFieldsLimit, - }, - mappings: { - dynamic: false, - _meta: indexMetadata, - }, - }, - _meta: indexMetadata, - }, - }, - }); - - await createDataStream({ - logger: this.options.logger, - esClient, - totalFieldsLimit, - indexPatterns, - }); - - await createIndex({ - esClient, - logger: this.options.logger, - options: { - index: getRiskScoreLatestIndex(namespace), - mappings: mappingFromFieldMap(riskScoreFieldMap, 'strict'), - }, - }); - - const transformId = getLatestTransformId(namespace); - await createTransform({ - esClient, - logger: this.options.logger, - transform: { - transform_id: transformId, - ...getTransformOptions({ - dest: getRiskScoreLatestIndex(namespace), - source: [indexPatterns.alias], - }), - }, - }); - } catch (error) { - this.options.logger.error(`Error initializing risk engine resources: ${error.message}`); - throw error; - } - } } diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.test.ts new file mode 100644 index 000000000000..eb7ae66c2c3d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { riskEngineDisableRoute } from './disable'; + +import { RISK_ENGINE_DISABLE_URL } from '../../../../../common/constants'; +import { + serverMock, + requestContextMock, + requestMock, +} from '../../../detection_engine/routes/__mocks__'; +import { riskEngineDataClientMock } from '../risk_engine_data_client.mock'; + +describe('risk score disable route', () => { + let server: ReturnType; + let context: ReturnType; + let mockTaskManagerStart: ReturnType; + let mockRiskEngineDataClient: ReturnType; + let getStartServicesMock: jest.Mock; + + beforeEach(() => { + jest.resetAllMocks(); + + server = serverMock.create(); + const { clients } = requestContextMock.createTools(); + mockRiskEngineDataClient = riskEngineDataClientMock.create(); + context = requestContextMock.convertContext( + requestContextMock.create({ + ...clients, + riskEngineDataClient: mockRiskEngineDataClient, + }) + ); + mockTaskManagerStart = taskManagerMock.createStart(); + }); + + const buildRequest = () => { + return requestMock.create({ + method: 'post', + path: RISK_ENGINE_DISABLE_URL, + body: {}, + }); + }; + + describe('when task manager is available', () => { + beforeEach(() => { + getStartServicesMock = jest + .fn() + .mockResolvedValue([{}, { taskManager: mockTaskManagerStart }]); + riskEngineDisableRoute(server.router, getStartServicesMock); + }); + + it('invokes the risk score data client', async () => { + const request = buildRequest(); + await server.inject(request, context); + + expect(mockRiskEngineDataClient.disableRiskEngine).toHaveBeenCalled(); + }); + + it('returns a 200 when disabling is successful', async () => { + // @ts-expect-error response is not used in the route nor this test + mockRiskEngineDataClient.disableRiskEngine.mockResolvedValue({ enabled: false }); + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(200); + }); + + it('returns a 500 if disabling fails', async () => { + mockRiskEngineDataClient.disableRiskEngine.mockRejectedValue( + new Error('something went wrong') + ); + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(500); + expect(response.body.message).toEqual('something went wrong'); + }); + }); + + describe('when task manager is unavailable', () => { + beforeEach(() => { + getStartServicesMock = jest.fn().mockResolvedValueOnce([{}, { taskManager: undefined }]); + riskEngineDisableRoute(server.router, getStartServicesMock); + }); + + it('returns a 400 response', async () => { + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(400); + expect(response.body).toEqual({ + message: + 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.', + status_code: 400, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/disable.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.test.ts new file mode 100644 index 000000000000..02ccf01dc616 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { riskEngineEnableRoute } from './enable'; + +import { RISK_ENGINE_ENABLE_URL } from '../../../../../common/constants'; +import { + serverMock, + requestContextMock, + requestMock, +} from '../../../detection_engine/routes/__mocks__'; +import { riskEngineDataClientMock } from '../risk_engine_data_client.mock'; + +describe('risk score enable route', () => { + let server: ReturnType; + let context: ReturnType; + let mockTaskManagerStart: ReturnType; + let mockRiskEngineDataClient: ReturnType; + let getStartServicesMock: jest.Mock; + + beforeEach(() => { + jest.resetAllMocks(); + + server = serverMock.create(); + const { clients } = requestContextMock.createTools(); + mockRiskEngineDataClient = riskEngineDataClientMock.create(); + context = requestContextMock.convertContext( + requestContextMock.create({ + ...clients, + riskEngineDataClient: mockRiskEngineDataClient, + }) + ); + mockTaskManagerStart = taskManagerMock.createStart(); + }); + + const buildRequest = () => { + return requestMock.create({ + method: 'post', + path: RISK_ENGINE_ENABLE_URL, + body: {}, + }); + }; + + describe('when task manager is available', () => { + beforeEach(() => { + getStartServicesMock = jest + .fn() + .mockResolvedValue([{}, { taskManager: mockTaskManagerStart }]); + riskEngineEnableRoute(server.router, getStartServicesMock); + }); + + it('invokes the risk score service', async () => { + const request = buildRequest(); + await server.inject(request, context); + + expect(mockRiskEngineDataClient.enableRiskEngine).toHaveBeenCalled(); + }); + + it('returns a 200 when enablement is successful', async () => { + // @ts-expect-error response is not used in the route nor this test + mockRiskEngineDataClient.enableRiskEngine.mockResolvedValue({ enabled: true }); + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(200); + }); + + it('returns a 500 if enabling fails', async () => { + mockRiskEngineDataClient.enableRiskEngine.mockRejectedValue( + new Error('something went wrong') + ); + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(500); + expect(response.body.message).toEqual('something went wrong'); + }); + }); + + describe('when task manager is unavailable', () => { + beforeEach(() => { + getStartServicesMock = jest.fn().mockResolvedValueOnce([{}, { taskManager: undefined }]); + riskEngineEnableRoute(server.router, getStartServicesMock); + }); + + it('returns a 400 response', async () => { + const request = buildRequest(); + const response = await server.inject(request, context); + + expect(response.status).toEqual(400); + expect(response.body).toEqual({ + message: + 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.', + status_code: 400, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/enable.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts index 1c37efc508f0..7e16ed57946e 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -export { riskScorePreviewRoute } from './risk_score_preview_route'; -export { riskEngineInitRoute } from './risk_engine_init_route'; -export { riskEngineEnableRoute } from './risk_engine_enable_route'; -export { riskEngineDisableRoute } from './risk_engine_disable_route'; -export { riskEngineStatusRoute } from './risk_engine_status_route'; +export { riskEngineInitRoute } from './init'; +export { riskEngineEnableRoute } from './enable'; +export { riskEngineDisableRoute } from './disable'; +export { riskEngineStatusRoute } from './status'; +export { riskEnginePrivilegesRoute } from './privileges'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/init.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/init.ts new file mode 100644 index 000000000000..a76af277949f --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/init.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { StartServicesAccessor } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { RISK_ENGINE_INIT_URL, APP_ID } from '../../../../../common/constants'; +import type { StartPlugins } from '../../../../plugin'; +import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import type { InitRiskEngineResultResponse } from '../../types'; + +export const riskEngineInitRoute = ( + router: SecuritySolutionPluginRouter, + getStartServices: StartServicesAccessor +) => { + router.versioned + .post({ + access: 'internal', + path: RISK_ENGINE_INIT_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion({ version: '1', validate: {} }, async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + const securitySolution = await context.securitySolution; + const [_, { taskManager }] = await getStartServices(); + const riskEngineDataClient = securitySolution.getRiskEngineDataClient(); + const riskScoreDataClient = securitySolution.getRiskScoreDataClient(); + const spaceId = securitySolution.getSpaceId(); + + try { + if (!taskManager) { + return siemResponse.error({ + statusCode: 400, + body: TASK_MANAGER_UNAVAILABLE_ERROR, + }); + } + + const initResult = await riskEngineDataClient.init({ + taskManager, + namespace: spaceId, + riskScoreDataClient, + }); + + const initResultResponse: InitRiskEngineResultResponse = { + risk_engine_enabled: initResult.riskEngineEnabled, + risk_engine_resources_installed: initResult.riskEngineResourcesInstalled, + risk_engine_configuration_created: initResult.riskEngineConfigurationCreated, + legacy_risk_engine_disabled: initResult.legacyRiskEngineDisabled, + errors: initResult.errors, + }; + + if ( + !initResult.riskEngineEnabled || + !initResult.riskEngineResourcesInstalled || + !initResult.riskEngineConfigurationCreated + ) { + return siemResponse.error({ + statusCode: 400, + body: { + message: initResultResponse.errors.join('\n'), + full_error: initResultResponse, + }, + bypassErrorFormat: true, + }); + } + return response.ok({ body: { result: initResultResponse } }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/privileges.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/privileges.ts new file mode 100644 index 000000000000..d035119ec0f1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/privileges.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import type { StartServicesAccessor } from '@kbn/core/server'; +import { RISK_ENGINE_PRIVILEGES_URL, APP_ID } from '../../../../../common/constants'; + +import type { StartPlugins } from '../../../../plugin'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { getUserRiskEnginePrivileges } from '../get_user_risk_engine_privileges'; + +export const riskEnginePrivilegesRoute = ( + router: SecuritySolutionPluginRouter, + getStartServices: StartServicesAccessor +) => { + router.versioned + .get({ + access: 'internal', + path: RISK_ENGINE_PRIVILEGES_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion({ version: '1', validate: false }, async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + + const [_, { security }] = await getStartServices(); + const body = await getUserRiskEnginePrivileges(request, security); + + try { + return response.ok({ + body, + }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: error.message, + }); + } + }); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts deleted file mode 100644 index 23e58896199a..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; -import { riskEngineDisableRoute } from './risk_engine_disable_route'; - -import { RISK_ENGINE_DISABLE_URL } from '../../../../../common/constants'; -import { - serverMock, - requestContextMock, - requestMock, -} from '../../../detection_engine/routes/__mocks__'; -import { riskEngineDataClientMock } from '../risk_engine_data_client.mock'; - -describe('risk score disable route', () => { - let server: ReturnType; - let context: ReturnType; - let mockTaskManagerStart: ReturnType; - let mockRiskEngineDataClient: ReturnType; - let getStartServicesMock: jest.Mock; - - beforeEach(() => { - jest.resetAllMocks(); - - server = serverMock.create(); - const { clients } = requestContextMock.createTools(); - mockRiskEngineDataClient = riskEngineDataClientMock.create(); - context = requestContextMock.convertContext( - requestContextMock.create({ - ...clients, - riskEngineDataClient: mockRiskEngineDataClient, - }) - ); - mockTaskManagerStart = taskManagerMock.createStart(); - }); - - const buildRequest = () => { - return requestMock.create({ - method: 'post', - path: RISK_ENGINE_DISABLE_URL, - body: {}, - }); - }; - - describe('when task manager is available', () => { - beforeEach(() => { - getStartServicesMock = jest - .fn() - .mockResolvedValue([{}, { taskManager: mockTaskManagerStart }]); - riskEngineDisableRoute(server.router, getStartServicesMock); - }); - - it('invokes the risk score data client', async () => { - const request = buildRequest(); - await server.inject(request, context); - - expect(mockRiskEngineDataClient.disableRiskEngine).toHaveBeenCalled(); - }); - - it('returns a 200 when disabling is successful', async () => { - // @ts-expect-error response is not used in the route nor this test - mockRiskEngineDataClient.disableRiskEngine.mockResolvedValue({ enabled: false }); - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(200); - }); - - it('returns a 500 if disabling fails', async () => { - mockRiskEngineDataClient.disableRiskEngine.mockRejectedValue( - new Error('something went wrong') - ); - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(500); - expect(response.body.message).toEqual('something went wrong'); - }); - }); - - describe('when task manager is unavailable', () => { - beforeEach(() => { - getStartServicesMock = jest.fn().mockResolvedValueOnce([{}, { taskManager: undefined }]); - riskEngineDisableRoute(server.router, getStartServicesMock); - }); - - it('returns a 400 response', async () => { - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(400); - expect(response.body).toEqual({ - message: - 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.', - status_code: 400, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts deleted file mode 100644 index 79a6c88c4fad..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; -import { riskEngineEnableRoute } from './risk_engine_enable_route'; - -import { RISK_ENGINE_ENABLE_URL } from '../../../../../common/constants'; -import { - serverMock, - requestContextMock, - requestMock, -} from '../../../detection_engine/routes/__mocks__'; -import { riskEngineDataClientMock } from '../risk_engine_data_client.mock'; - -describe('risk score enable route', () => { - let server: ReturnType; - let context: ReturnType; - let mockTaskManagerStart: ReturnType; - let mockRiskEngineDataClient: ReturnType; - let getStartServicesMock: jest.Mock; - - beforeEach(() => { - jest.resetAllMocks(); - - server = serverMock.create(); - const { clients } = requestContextMock.createTools(); - mockRiskEngineDataClient = riskEngineDataClientMock.create(); - context = requestContextMock.convertContext( - requestContextMock.create({ - ...clients, - riskEngineDataClient: mockRiskEngineDataClient, - }) - ); - mockTaskManagerStart = taskManagerMock.createStart(); - }); - - const buildRequest = () => { - return requestMock.create({ - method: 'post', - path: RISK_ENGINE_ENABLE_URL, - body: {}, - }); - }; - - describe('when task manager is available', () => { - beforeEach(() => { - getStartServicesMock = jest - .fn() - .mockResolvedValue([{}, { taskManager: mockTaskManagerStart }]); - riskEngineEnableRoute(server.router, getStartServicesMock); - }); - - it('invokes the risk score service', async () => { - const request = buildRequest(); - await server.inject(request, context); - - expect(mockRiskEngineDataClient.enableRiskEngine).toHaveBeenCalled(); - }); - - it('returns a 200 when enablement is successful', async () => { - // @ts-expect-error response is not used in the route nor this test - mockRiskEngineDataClient.enableRiskEngine.mockResolvedValue({ enabled: true }); - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(200); - }); - - it('returns a 500 if enabling fails', async () => { - mockRiskEngineDataClient.enableRiskEngine.mockRejectedValue( - new Error('something went wrong') - ); - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(500); - expect(response.body.message).toEqual('something went wrong'); - }); - }); - - describe('when task manager is unavailable', () => { - beforeEach(() => { - getStartServicesMock = jest.fn().mockResolvedValueOnce([{}, { taskManager: undefined }]); - riskEngineEnableRoute(server.router, getStartServicesMock); - }); - - it('returns a 400 response', async () => { - const request = buildRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(400); - expect(response.body).toEqual({ - message: - 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.', - status_code: 400, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts deleted file mode 100644 index e5b719dfbc42..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { StartServicesAccessor } from '@kbn/core/server'; -import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; -import { transformError } from '@kbn/securitysolution-es-utils'; -import { RISK_ENGINE_INIT_URL, APP_ID } from '../../../../../common/constants'; -import type { StartPlugins } from '../../../../plugin'; -import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; - -export const riskEngineInitRoute = ( - router: SecuritySolutionPluginRouter, - getStartServices: StartServicesAccessor -) => { - router.versioned - .post({ - access: 'internal', - path: RISK_ENGINE_INIT_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion({ version: '1', validate: {} }, async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - const securitySolution = await context.securitySolution; - const [_, { taskManager }] = await getStartServices(); - const riskEngineDataClient = securitySolution.getRiskEngineDataClient(); - const spaceId = securitySolution.getSpaceId(); - - try { - if (!taskManager) { - return siemResponse.error({ - statusCode: 400, - body: TASK_MANAGER_UNAVAILABLE_ERROR, - }); - } - - const initResult = await riskEngineDataClient.init({ - taskManager, - namespace: spaceId, - }); - - const initResultResponse = { - risk_engine_enabled: initResult.riskEngineEnabled, - risk_engine_resources_installed: initResult.riskEngineResourcesInstalled, - risk_engine_configuration_created: initResult.riskEngineConfigurationCreated, - legacy_risk_engine_disabled: initResult.legacyRiskEngineDisabled, - errors: initResult.errors, - }; - - if ( - !initResult.riskEngineEnabled || - !initResult.riskEngineResourcesInstalled || - !initResult.riskEngineConfigurationCreated - ) { - return siemResponse.error({ - statusCode: 400, - body: { - message: initResultResponse.errors.join('\n'), - full_error: initResultResponse, - }, - bypassErrorFormat: true, - }); - } - return response.ok({ body: { result: initResultResponse } }); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - }); -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts deleted file mode 100644 index 7cf7b5304a01..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { riskScoreCalculationRoute } from './risk_score_calculation_route'; - -import { loggerMock } from '@kbn/logging-mocks'; - -import { RISK_SCORE_CALCULATION_URL } from '../../../../../common/constants'; -import { - serverMock, - requestContextMock, - requestMock, -} from '../../../detection_engine/routes/__mocks__'; -import { riskScoreServiceFactory } from '../risk_score_service'; -import { riskScoreServiceMock } from '../risk_score_service.mock'; -import { getRiskInputsIndex } from '../get_risk_inputs_index'; -import { calculateAndPersistRiskScoresMock } from '../calculate_and_persist_risk_scores.mock'; - -jest.mock('../get_risk_inputs_index'); -jest.mock('../risk_score_service'); - -describe('risk score calculation route', () => { - let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); - let logger: ReturnType; - let mockRiskScoreService: ReturnType; - - beforeEach(() => { - jest.resetAllMocks(); - - server = serverMock.create(); - logger = loggerMock.create(); - ({ clients, context } = requestContextMock.createTools()); - mockRiskScoreService = riskScoreServiceMock.create(); - - (getRiskInputsIndex as jest.Mock).mockResolvedValue({ - index: 'default-dataview-index', - runtimeMappings: {}, - }); - clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); - (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); - - riskScoreCalculationRoute(server.router, logger); - }); - - const buildRequest = (overrides: object = {}) => { - const defaults = { - data_view_id: 'default-dataview-id', - range: { start: 'now-30d', end: 'now' }, - identifier_type: 'host', - }; - - return requestMock.create({ - method: 'post', - path: RISK_SCORE_CALCULATION_URL, - body: { ...defaults, ...overrides }, - }); - }; - - it('should return 200 when risk score calculation is successful', async () => { - mockRiskScoreService.calculateAndPersistScores.mockResolvedValue( - calculateAndPersistRiskScoresMock.buildResponse() - ); - const request = buildRequest(); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - }); - - describe('parameters', () => { - it('accepts a parameter for the dataview', async () => { - const request = buildRequest({ data_view_id: 'custom-dataview-id' }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(getRiskInputsIndex).toHaveBeenCalledWith( - expect.objectContaining({ dataViewId: 'custom-dataview-id' }) - ); - }); - - it('accepts a parameter for the range', async () => { - const request = buildRequest({ range: { start: 'now-30d', end: 'now-20d' } }); - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateAndPersistScores).toHaveBeenCalledWith( - expect.objectContaining({ range: { start: 'now-30d', end: 'now-20d' } }) - ); - }); - }); - - describe('validation', () => { - describe('required parameters', () => { - it('requires a parameter for the dataview', async () => { - const request = buildRequest({ data_view_id: undefined }); - const result = await server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "data_view_id"' - ); - }); - - it('requires a parameter for the date range', async () => { - const request = buildRequest({ range: undefined }); - const result = await server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "range"' - ); - }); - - it('requires a parameter for the identifier type', async () => { - const request = buildRequest({ identifier_type: undefined }); - const result = await server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "identifier_type"' - ); - }); - }); - - it('uses an unknown dataview as index pattern', async () => { - const request = buildRequest({ data_view_id: 'unknown-dataview' }); - (getRiskInputsIndex as jest.Mock).mockResolvedValue({ - index: 'unknown-dataview', - runtimeMappings: {}, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateAndPersistScores).toHaveBeenCalledWith( - expect.objectContaining({ index: 'unknown-dataview', runtimeMappings: {} }) - ); - }); - - it('rejects an invalid date range', async () => { - const request = buildRequest({ range: 'bad range' }); - const result = await server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "bad range" supplied to "range"' - ); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts deleted file mode 100644 index cfbd80afb0d5..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Logger } from '@kbn/core/server'; -import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; -import { transformError } from '@kbn/securitysolution-es-utils'; -import { - APP_ID, - DEFAULT_RISK_SCORE_PAGE_SIZE, - RISK_SCORE_CALCULATION_URL, -} from '../../../../../common/constants'; -import { riskScoreCalculationRequestSchema } from '../../../../../common/risk_engine/risk_score_calculation/request_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { riskScoreServiceFactory } from '../risk_score_service'; -import { getRiskInputsIndex } from '../get_risk_inputs_index'; - -export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { - router.versioned - .post({ - path: RISK_SCORE_CALCULATION_URL, - access: 'internal', - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion( - { - version: '1', - validate: { request: { body: buildRouteValidation(riskScoreCalculationRequestSchema) } }, - }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - const securityContext = await context.securitySolution; - const coreContext = await context.core; - const esClient = coreContext.elasticsearch.client.asCurrentUser; - const soClient = coreContext.savedObjects.client; - const spaceId = securityContext.getSpaceId(); - const riskEngineDataClient = securityContext.getRiskEngineDataClient(); - - const riskScoreService = riskScoreServiceFactory({ - esClient, - logger, - riskEngineDataClient, - spaceId, - }); - - const { - after_keys: userAfterKeys, - data_view_id: dataViewId, - debug, - page_size: userPageSize, - identifier_type: identifierType, - filter, - range, - weights, - } = request.body; - - try { - const { index, runtimeMappings } = await getRiskInputsIndex({ - dataViewId, - logger, - soClient, - }); - - const afterKeys = userAfterKeys ?? {}; - const pageSize = userPageSize ?? DEFAULT_RISK_SCORE_PAGE_SIZE; - - const result = await riskScoreService.calculateAndPersistScores({ - afterKeys, - debug, - pageSize, - identifierType, - index, - filter, - range, - runtimeMappings, - weights, - }); - - return response.ok({ body: result }); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - } - ); -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts deleted file mode 100644 index ba87e94c3ccc..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { loggerMock } from '@kbn/logging-mocks'; - -import { RISK_SCORE_PREVIEW_URL } from '../../../../../common/constants'; -import { RiskCategories, RiskWeightTypes } from '../../../../../common/risk_engine'; -import { - serverMock, - requestContextMock, - requestMock, -} from '../../../detection_engine/routes/__mocks__'; -import { getRiskInputsIndex } from '../get_risk_inputs_index'; -import { riskScoreServiceFactory } from '../risk_score_service'; -import { riskScoreServiceMock } from '../risk_score_service.mock'; -import { riskScorePreviewRoute } from './risk_score_preview_route'; - -jest.mock('../risk_score_service'); -jest.mock('../get_risk_inputs_index'); - -describe('POST risk_engine/preview route', () => { - let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); - let logger: ReturnType; - let mockRiskScoreService: ReturnType; - - beforeEach(() => { - jest.resetAllMocks(); - - server = serverMock.create(); - logger = loggerMock.create(); - ({ clients, context } = requestContextMock.createTools()); - mockRiskScoreService = riskScoreServiceMock.create(); - (getRiskInputsIndex as jest.Mock).mockImplementationOnce( - async ({ dataViewId }: { dataViewId: string }) => ({ - index: dataViewId, - runtimeMappings: {}, - }) - ); - - clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); - (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); - - riskScorePreviewRoute(server.router, logger); - }); - - const buildRequest = (body: object = {}) => - requestMock.create({ - method: 'get', - path: RISK_SCORE_PREVIEW_URL, - body: { - data_view_id: 'default-dataview-id', - ...body, - }, - }); - - describe('parameters', () => { - describe('index / dataview', () => { - it('requires a parameter for the dataview', async () => { - const request = buildRequest({ data_view_id: undefined }); - const result = await server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "data_view_id"' - ); - }); - - it('respects the provided dataview', async () => { - const request = buildRequest({ data_view_id: 'custom-dataview-id' }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ index: 'custom-dataview-id' }) - ); - }); - - it('uses an unknown dataview as index pattern', async () => { - const request = buildRequest({ data_view_id: 'unknown-dataview' }); - (getRiskInputsIndex as jest.Mock).mockResolvedValue({ - index: 'unknown-dataview', - runtimeMappings: {}, - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ index: 'unknown-dataview', runtimeMappings: {} }) - ); - }); - }); - - describe('date range', () => { - it('defaults to the last 15 days of data', async () => { - const request = buildRequest(); - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ range: { start: 'now-15d', end: 'now' } }) - ); - }); - - it('respects the provided range if provided', async () => { - const request = buildRequest({ range: { start: 'now-30d', end: 'now-20d' } }); - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ range: { start: 'now-30d', end: 'now-20d' } }) - ); - }); - - it('rejects an invalid date range', async () => { - const request = buildRequest({ - range: { end: 'now' }, - }); - - const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - expect.stringContaining('Invalid value "undefined" supplied to "range,start"') - ); - }); - }); - - describe('data filter', () => { - it('respects the provided filter if provided', async () => { - const request = buildRequest({ - filter: { - bool: { - filter: [ - { - ids: { - values: '1', - }, - }, - ], - }, - }, - }); - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ - filter: { - bool: { - filter: [ - { - ids: { - values: '1', - }, - }, - ], - }, - }, - }) - ); - }); - }); - - describe('weights', () => { - it('uses the specified weights when provided', async () => { - const request = buildRequest({ - weights: [ - { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, - host: 0.1, - user: 0.2, - }, - ], - }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ - weights: [ - { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, - host: 0.1, - user: 0.2, - }, - ], - }) - ); - }); - - it('rejects weight values outside the 0-1 range', async () => { - const request = buildRequest({ - weights: [ - { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, - host: 1.1, - }, - ], - }); - - const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - expect.stringContaining('Invalid value "1.1" supplied to "weights,host"') - ); - }); - - it('rejects unknown weight types', async () => { - const request = buildRequest({ - weights: [ - { - type: 'something new', - host: 1.1, - }, - ], - }); - - const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "{"type":"something new","host":1.1}" supplied to "weights"' - ); - }); - }); - - describe('pagination', () => { - it('respects the provided after_key', async () => { - const afterKey = { 'host.name': 'hi mom' }; - const request = buildRequest({ after_keys: { host: afterKey } }); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - expect(response.status).toEqual(200); - expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( - expect.objectContaining({ afterKeys: { host: afterKey } }) - ); - }); - - it('rejects an invalid after_key', async () => { - const request = buildRequest({ - after_keys: { - bad: 'key', - }, - }); - - const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('invalid keys "bad"'); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts deleted file mode 100644 index 05f80c526a92..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Logger } from '@kbn/core/server'; -import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; -import { transformError } from '@kbn/securitysolution-es-utils'; - -import { - APP_ID, - DEFAULT_RISK_SCORE_PAGE_SIZE, - RISK_SCORE_PREVIEW_URL, -} from '../../../../../common/constants'; -import { riskScorePreviewRequestSchema } from '../../../../../common/risk_engine/risk_score_preview/request_schema'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import { riskScoreServiceFactory } from '../risk_score_service'; -import { getRiskInputsIndex } from '../get_risk_inputs_index'; - -export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { - router.versioned - .post({ - access: 'internal', - path: RISK_SCORE_PREVIEW_URL, - options: { - tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], - }, - }) - .addVersion( - { - version: '1', - validate: { request: { body: buildRouteValidation(riskScorePreviewRequestSchema) } }, - }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - const securityContext = await context.securitySolution; - const coreContext = await context.core; - const esClient = coreContext.elasticsearch.client.asCurrentUser; - const soClient = coreContext.savedObjects.client; - const spaceId = securityContext.getSpaceId(); - const riskEngineDataClient = securityContext.getRiskEngineDataClient(); - - const riskScoreService = riskScoreServiceFactory({ - esClient, - logger, - riskEngineDataClient, - spaceId, - }); - - const { - after_keys: userAfterKeys, - data_view_id: dataViewId, - debug, - page_size: userPageSize, - identifier_type: identifierType, - filter, - range: userRange, - weights, - } = request.body; - - try { - const { index, runtimeMappings } = await getRiskInputsIndex({ - dataViewId, - logger, - soClient, - }); - - const afterKeys = userAfterKeys ?? {}; - const range = userRange ?? { start: 'now-15d', end: 'now' }; - const pageSize = userPageSize ?? DEFAULT_RISK_SCORE_PAGE_SIZE; - - const result = await riskScoreService.calculateScores({ - afterKeys, - debug, - filter, - identifierType, - index, - pageSize, - range, - runtimeMappings, - weights, - }); - - return response.ok({ body: result }); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - } - ); -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/status.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/status.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml index c51bf19ebd2b..d9840840ea2f 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml @@ -93,6 +93,16 @@ paths: application/json: schema: $ref: '#/components/schemas/RiskEngineDisableResponse' + /engine/privileges: + get: + summary: Check if the user has access to the risk engine + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/RiskEnginePrivilegesResponse' components: @@ -436,4 +446,25 @@ components: type: boolean error: type: string - \ No newline at end of file + RiskEnginePrivilegesResponse: + type: object + properties: + privileges: + type: object + properties: + elasticsearch: + type: object + properties: + cluster: + type: object + additionalProperties: + type: boolean + index: + type: object + additionalProperties: + type: object + additionalProperties: + type: boolean + has_all_required: + description: If true then the user has full access to the risk engine + type: boolean diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts deleted file mode 100644 index f5aeaf4f5642..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { MappingRuntimeFields, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; -import type { - AfterKey, - AfterKeys, - IdentifierType, - RiskWeights, - Range, - RiskEngineStatus, - RiskScore, -} from '../../../../common/risk_engine'; - -export interface CalculateScoresParams { - afterKeys: AfterKeys; - debug?: boolean; - index: string; - filter?: unknown; - identifierType?: IdentifierType; - pageSize: number; - range: { start: string; end: string }; - runtimeMappings: MappingRuntimeFields; - weights?: RiskWeights; -} - -export interface CalculateAndPersistScoresParams { - afterKeys: AfterKeys; - debug?: boolean; - index: string; - filter?: unknown; - identifierType: IdentifierType; - pageSize: number; - range: Range; - runtimeMappings: MappingRuntimeFields; - weights?: RiskWeights; -} - -export interface CalculateAndPersistScoresResponse { - after_keys: AfterKeys; - errors: string[]; - scores_written: number; -} - -export interface CalculateScoresResponse { - debug?: { - request: unknown; - response: unknown; - }; - after_keys: AfterKeys; - scores: { - host?: RiskScore[]; - user?: RiskScore[]; - }; -} - -export interface GetRiskEngineStatusResponse { - legacy_risk_engine_status: RiskEngineStatus; - risk_engine_status: RiskEngineStatus; - is_max_amount_of_risk_engines_reached: boolean; -} - -interface InitRiskEngineResultResponse { - risk_engine_enabled: boolean; - risk_engine_resources_installed: boolean; - risk_engine_configuration_created: boolean; - legacy_risk_engine_disabled: boolean; - errors: string[]; -} - -export interface InitRiskEngineResponse { - result: InitRiskEngineResultResponse; -} - -export interface InitRiskEngineError { - body: { - message: string; - full_error: InitRiskEngineResultResponse | undefined; - }; -} - -export interface EnableDisableRiskEngineErrorResponse { - body: { - message: string; - full_error: string; - }; -} - -export interface EnableRiskEngineResponse { - success: boolean; -} - -export interface DisableRiskEngineResponse { - success: boolean; -} - -export interface CalculateRiskScoreAggregations { - user?: { - after_key: AfterKey; - buckets: RiskScoreBucket[]; - }; - host?: { - after_key: AfterKey; - buckets: RiskScoreBucket[]; - }; -} - -export interface RiskScoreBucket { - key: { [identifierField: string]: string }; - doc_count: number; - risk_details: { - value: { - score: number; - normalized_score: number; - notes: string[]; - level: string; - category_1_score: number; - category_1_count: number; - }; - }; - inputs: SearchResponse; -} - -export interface RiskEngineConfiguration { - dataViewId: string; - enabled: boolean; - filter: unknown; - identifierType: IdentifierType | undefined; - interval: string; - pageSize: number; - range: Range; -} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_datastream.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_datastream.ts deleted file mode 100644 index fee229fa942f..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_datastream.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -// This file is a copy of x-pack/plugins/alerting/server/alerts_service/lib/create_concrete_write_index.ts -// original function create index instead of datastream, and their have plan to use datastream in the future -// so we probably should remove this file and use the original when datastream will be supported - -import type { IndicesSimulateIndexTemplateResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { Logger, ElasticsearchClient } from '@kbn/core/server'; -import { get } from 'lodash'; -import { retryTransientEsErrors } from './retry_transient_es_errors'; - -export interface IIndexPatternString { - template: string; - alias: string; -} - -interface ConcreteIndexInfo { - index: string; - alias: string; - isWriteIndex: boolean; -} - -interface UpdateIndexMappingsOpts { - logger: Logger; - esClient: ElasticsearchClient; - totalFieldsLimit: number; - concreteIndices: ConcreteIndexInfo[]; -} - -interface UpdateIndexOpts { - logger: Logger; - esClient: ElasticsearchClient; - totalFieldsLimit: number; - concreteIndexInfo: ConcreteIndexInfo; -} - -const updateTotalFieldLimitSetting = async ({ - logger, - esClient, - totalFieldsLimit, - concreteIndexInfo, -}: UpdateIndexOpts) => { - const { index, alias } = concreteIndexInfo; - try { - await retryTransientEsErrors( - () => - esClient.indices.putSettings({ - index, - body: { 'index.mapping.total_fields.limit': totalFieldsLimit }, - }), - { logger } - ); - } catch (err) { - logger.error( - `Failed to PUT index.mapping.total_fields.limit settings for alias ${alias}: ${err.message}` - ); - throw err; - } -}; - -// This will update the mappings of backing indices but *not* the settings. This -// is due to the fact settings can be classed as dynamic and static, and static -// updates will fail on an index that isn't closed. New settings *will* be applied as part -// of the ILM policy rollovers. More info: https://github.com/elastic/kibana/pull/113389#issuecomment-940152654 -const updateUnderlyingMapping = async ({ - logger, - esClient, - concreteIndexInfo, -}: UpdateIndexOpts) => { - const { index, alias } = concreteIndexInfo; - let simulatedIndexMapping: IndicesSimulateIndexTemplateResponse; - try { - simulatedIndexMapping = await retryTransientEsErrors( - () => esClient.indices.simulateIndexTemplate({ name: index }), - { logger } - ); - } catch (err) { - logger.error( - `Ignored PUT mappings for alias ${alias}; error generating simulated mappings: ${err.message}` - ); - return; - } - - const simulatedMapping = get(simulatedIndexMapping, ['template', 'mappings']); - - if (simulatedMapping == null) { - logger.error(`Ignored PUT mappings for alias ${alias}; simulated mappings were empty`); - return; - } - - try { - await retryTransientEsErrors( - () => esClient.indices.putMapping({ index, body: simulatedMapping }), - { logger } - ); - } catch (err) { - logger.error(`Failed to PUT mapping for alias ${alias}: ${err.message}`); - throw err; - } -}; -/** - * Updates the underlying mapping for any existing concrete indices - */ -const updateIndexMappings = async ({ - logger, - esClient, - totalFieldsLimit, - concreteIndices, -}: UpdateIndexMappingsOpts) => { - logger.debug(`Updating underlying mappings for ${concreteIndices.length} indices.`); - - // Update total field limit setting of found indices - // Other index setting changes are not updated at this time - await Promise.all( - concreteIndices.map((index) => - updateTotalFieldLimitSetting({ logger, esClient, totalFieldsLimit, concreteIndexInfo: index }) - ) - ); - - // Update mappings of the found indices. - await Promise.all( - concreteIndices.map((index) => - updateUnderlyingMapping({ logger, esClient, totalFieldsLimit, concreteIndexInfo: index }) - ) - ); -}; - -interface CreateConcreteWriteIndexOpts { - logger: Logger; - esClient: ElasticsearchClient; - totalFieldsLimit: number; - indexPatterns: IIndexPatternString; -} -/** - * Create a data stream - */ -export const createDataStream = async ({ - logger, - esClient, - indexPatterns, - totalFieldsLimit, -}: CreateConcreteWriteIndexOpts) => { - logger.info(`Creating data stream - ${indexPatterns.alias}`); - - // check if a datastream already exists - let dataStreams: ConcreteIndexInfo[] = []; - try { - // Specify both the index pattern for the backing indices and their aliases - // The alias prevents the request from finding other namespaces that could match the -* pattern - const response = await retryTransientEsErrors( - () => esClient.indices.getDataStream({ name: indexPatterns.alias, expand_wildcards: 'all' }), - { logger } - ); - - dataStreams = response.data_streams.map((dataStream) => ({ - index: dataStream.name, - alias: dataStream.name, - isWriteIndex: true, - })); - - logger.debug( - `Found ${dataStreams.length} concrete indices for ${indexPatterns.alias} - ${JSON.stringify( - dataStreams - )}` - ); - } catch (error) { - // 404 is expected if no datastream have been created - if (error.statusCode !== 404) { - logger.error( - `Error fetching concrete indices for ${indexPatterns.alias} pattern - ${error.message}` - ); - throw error; - } - } - - const dataStreamsExist = dataStreams.length > 0; - - // if a concrete write datastream already exists, update the underlying mapping - if (dataStreams.length > 0) { - await updateIndexMappings({ logger, esClient, totalFieldsLimit, concreteIndices: dataStreams }); - } - - // check if a concrete write datastream already exists - if (!dataStreamsExist) { - try { - await retryTransientEsErrors( - () => - esClient.indices.createDataStream({ - name: indexPatterns.alias, - }), - { logger } - ); - } catch (error) { - logger.error(`Error creating datastream - ${error.message}`); - throw error; - } - } -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_index.ts deleted file mode 100644 index b1aefedc90ce..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { ElasticsearchClient, Logger } from '@kbn/core/server'; -import { transformError } from '@kbn/securitysolution-es-utils'; -import type { - IndicesCreateRequest, - IndicesCreateResponse, -} from '@elastic/elasticsearch/lib/api/types'; - -export const createIndex = async ({ - esClient, - logger, - options, -}: { - esClient: ElasticsearchClient; - logger: Logger; - options: IndicesCreateRequest; -}): Promise => { - try { - const isIndexExist = await esClient.indices.exists({ - index: options.index, - }); - if (isIndexExist) { - logger.info(`${options.index} already exist`); - return; - } - - return esClient.indices.create(options); - } catch (err) { - const error = transformError(err); - const fullErrorMessage = `Failed to create index: ${options.index}: ${error.message}`; - logger.error(fullErrorMessage); - throw new Error(fullErrorMessage); - } -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts index e39f2f73e5df..d5a6451cb207 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts @@ -7,7 +7,7 @@ import type { SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; import { getAlertsIndex } from '../../../../../common/utils/risk_score_modules'; -import type { RiskEngineConfiguration } from '../types'; +import type { RiskEngineConfiguration } from '../../types'; import { riskEngineConfigurationTypeName } from '../saved_object'; export interface SavedObjectsClientArg { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.mock.ts similarity index 89% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.mock.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.mock.ts index e76c9a5a7955..093e1b823511 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { CalculateAndPersistScoresResponse } from './types'; +import type { CalculateAndPersistScoresResponse } from '../types'; const buildResponseMock = ( overrides: Partial = {} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.test.ts similarity index 96% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.test.ts index cc9a51a6d53c..1aa38395baf1 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.test.ts @@ -41,7 +41,7 @@ describe('calculateAndPersistRiskScores', () => { range: { start: 'now - 15d', end: 'now' }, spaceId: 'default', // @ts-expect-error not relevant for this test - riskEngineDataClient: { getWriter: jest.fn() }, + riskScoreDataClient: { getWriter: jest.fn() }, runtimeMappings: {}, }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts similarity index 79% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts index ba5b4fc7d5cf..77258d313034 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_and_persist_risk_scores.ts @@ -7,8 +7,8 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; -import type { RiskEngineDataClient } from './risk_engine_data_client'; -import type { CalculateAndPersistScoresParams, CalculateAndPersistScoresResponse } from './types'; +import type { RiskScoreDataClient } from './risk_score_data_client'; +import type { CalculateAndPersistScoresParams, CalculateAndPersistScoresResponse } from '../types'; import { calculateRiskScores } from './calculate_risk_scores'; export const calculateAndPersistRiskScores = async ( @@ -16,11 +16,11 @@ export const calculateAndPersistRiskScores = async ( esClient: ElasticsearchClient; logger: Logger; spaceId: string; - riskEngineDataClient: RiskEngineDataClient; + riskScoreDataClient: RiskScoreDataClient; } ): Promise => { - const { riskEngineDataClient, spaceId, ...rest } = params; - const writer = await riskEngineDataClient.getWriter({ + const { riskScoreDataClient, spaceId, ...rest } = params; + const writer = await riskScoreDataClient.getWriter({ namespace: spaceId, }); const { after_keys: afterKeys, scores } = await calculateRiskScores(rest); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts index c81d1336c162..4b0d298ca420 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.mock.ts @@ -14,7 +14,7 @@ import type { CalculateRiskScoreAggregations, CalculateScoresResponse, RiskScoreBucket, -} from './types'; +} from '../types'; const buildRiskScoreBucketMock = (overrides: Partial = {}): RiskScoreBucket => ({ key: { 'user.name': 'username' }, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts index ecacf9502025..996adec9c490 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts @@ -38,7 +38,7 @@ import type { CalculateScoresParams, CalculateScoresResponse, RiskScoreBucket, -} from './types'; +} from '../types'; const bucketToResponse = ({ bucket, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/configurations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/configurations.ts new file mode 100644 index 000000000000..4ed053329224 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/configurations.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { FieldMap } from '@kbn/alerts-as-data-utils'; +import type { IdentifierType } from '../../../../common/risk_engine'; +import { RiskScoreEntity, riskScoreBaseIndexName } from '../../../../common/risk_engine'; +import type { IIndexPatternString } from '../utils/create_datastream'; + +const commonRiskFields: FieldMap = { + id_field: { + type: 'keyword', + array: false, + required: false, + }, + id_value: { + type: 'keyword', + array: false, + required: false, + }, + calculated_level: { + type: 'keyword', + array: false, + required: false, + }, + calculated_score: { + type: 'float', + array: false, + required: false, + }, + calculated_score_norm: { + type: 'float', + array: false, + required: false, + }, + category_1_score: { + type: 'float', + array: false, + required: false, + }, + category_1_count: { + type: 'long', + array: false, + required: false, + }, + inputs: { + type: 'object', + array: true, + required: false, + }, + 'inputs.id': { + type: 'keyword', + array: false, + required: false, + }, + 'inputs.index': { + type: 'keyword', + array: false, + required: false, + }, + 'inputs.category': { + type: 'keyword', + array: false, + required: false, + }, + 'inputs.description': { + type: 'keyword', + array: false, + required: false, + }, + 'inputs.risk_score': { + type: 'float', + array: false, + required: false, + }, + 'inputs.timestamp': { + type: 'date', + array: false, + required: false, + }, + notes: { + type: 'keyword', + array: false, + required: false, + }, +}; + +const buildIdentityRiskFields = (identifierType: IdentifierType): FieldMap => + Object.keys(commonRiskFields).reduce((fieldMap, key) => { + const identifierKey = `${identifierType}.risk.${key}`; + fieldMap[identifierKey] = commonRiskFields[key]; + return fieldMap; + }, {} as FieldMap); + +export const riskScoreFieldMap: FieldMap = { + '@timestamp': { + type: 'date', + array: false, + required: false, + }, + 'host.name': { + type: 'keyword', + array: false, + required: false, + }, + 'host.risk': { + type: 'object', + array: false, + required: false, + }, + ...buildIdentityRiskFields(RiskScoreEntity.host), + 'user.name': { + type: 'keyword', + array: false, + required: false, + }, + 'user.risk': { + type: 'object', + array: false, + required: false, + }, + ...buildIdentityRiskFields(RiskScoreEntity.user), +} as const; + +export const mappingComponentName = '.risk-score-mappings'; +export const totalFieldsLimit = 1000; + +export const getIndexPatternDataStream = (namespace: string): IIndexPatternString => ({ + template: `.${riskScoreBaseIndexName}.${riskScoreBaseIndexName}-${namespace}-index-template`, + alias: `${riskScoreBaseIndexName}.${riskScoreBaseIndexName}-${namespace}`, +}); + +export const getTransformOptions = ({ dest, source }: { dest: string; source: string[] }) => ({ + dest: { + index: dest, + }, + frequency: '1h', + latest: { + sort: '@timestamp', + unique_key: [`host.name`, `user.name`], + }, + source: { + index: source, + }, + sync: { + time: { + delay: '2s', + field: '@timestamp', + }, + }, +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.mock.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.mock.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.mock.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/get_risk_inputs_index.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/helpers.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/helpers.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/helpers.ts new file mode 100644 index 000000000000..617b2c5a03c1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/helpers.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AfterKey, AfterKeys, IdentifierType } from '../../../../common/risk_engine'; +import type { CalculateAndPersistScoresResponse } from '../types'; + +export const getFieldForIdentifierAgg = (identifierType: IdentifierType): string => + identifierType === 'host' ? 'host.name' : 'user.name'; + +export const getAfterKeyForIdentifierType = ({ + afterKeys, + identifierType, +}: { + afterKeys: AfterKeys; + identifierType: IdentifierType; +}): AfterKey | undefined => afterKeys[identifierType]; + +export const isRiskScoreCalculationComplete = ( + result: CalculateAndPersistScoresResponse +): boolean => + Object.keys(result.after_keys.host ?? {}).length === 0 && + Object.keys(result.after_keys.user ?? {}).length === 0; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_engine_data_writer.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.mock.ts new file mode 100644 index 000000000000..0277e9fc91a0 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.mock.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RiskScoreDataClient } from './risk_score_data_client'; + +const createRiskScoreDataClientMock = () => + ({ + getWriter: jest.fn(), + init: jest.fn(), + getRiskInputsIndex: jest.fn(), + } as unknown as jest.Mocked); + +export const riskScoreDataClientMock = { create: createRiskScoreDataClientMock }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.test.ts new file mode 100644 index 000000000000..022d8e92d457 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.test.ts @@ -0,0 +1,455 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + createOrUpdateComponentTemplate, + createOrUpdateIndexTemplate, +} from '@kbn/alerting-plugin/server'; +import { + loggingSystemMock, + elasticsearchServiceMock, + savedObjectsClientMock, +} from '@kbn/core/server/mocks'; + +import { RiskScoreDataClient } from './risk_score_data_client'; + +import { createDataStream } from '../utils/create_datastream'; + +import * as transforms from '../utils/transforms'; +import { createOrUpdateIndex } from '../utils/create_or_update_index'; + +jest.mock('@kbn/alerting-plugin/server', () => ({ + createOrUpdateComponentTemplate: jest.fn(), + createOrUpdateIndexTemplate: jest.fn(), +})); + +jest.mock('../utils/create_datastream', () => ({ + createDataStream: jest.fn(), +})); + +jest.mock('../utils/create_or_update_index', () => ({ + createOrUpdateIndex: jest.fn(), +})); + +jest.spyOn(transforms, 'createTransform').mockResolvedValue(Promise.resolve()); +jest.spyOn(transforms, 'startTransform').mockResolvedValue(Promise.resolve()); + +describe('RiskScoreDataClient', () => { + let riskScoreDataClient: RiskScoreDataClient; + let mockSavedObjectClient: ReturnType; + let logger: ReturnType; + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + const totalFieldsLimit = 1000; + + beforeEach(() => { + logger = loggingSystemMock.createLogger(); + mockSavedObjectClient = savedObjectsClientMock.create(); + const options = { + logger, + kibanaVersion: '8.9.0', + esClient, + soClient: mockSavedObjectClient, + namespace: 'default', + }; + riskScoreDataClient = new RiskScoreDataClient(options); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('getWriter', () => { + it('should return a writer object', async () => { + const writer = await riskScoreDataClient.getWriter({ namespace: 'default' }); + expect(writer).toBeDefined(); + expect(typeof writer?.bulk).toBe('function'); + }); + + it('should cache and return the same writer for the same namespace', async () => { + const writer1 = await riskScoreDataClient.getWriter({ namespace: 'default' }); + const writer2 = await riskScoreDataClient.getWriter({ namespace: 'default' }); + const writer3 = await riskScoreDataClient.getWriter({ namespace: 'space-1' }); + + expect(writer1).toEqual(writer2); + expect(writer2).not.toEqual(writer3); + }); + }); + + describe('init success', () => { + it('should initialize risk engine resources', async () => { + await riskScoreDataClient.init(); + + expect(createOrUpdateComponentTemplate).toHaveBeenCalledWith( + expect.objectContaining({ + logger, + esClient, + template: expect.objectContaining({ + name: '.risk-score-mappings', + _meta: { + managed: true, + }, + }), + totalFieldsLimit: 1000, + }) + ); + expect((createOrUpdateComponentTemplate as jest.Mock).mock.lastCall[0].template.template) + .toMatchInlineSnapshot(` + Object { + "mappings": Object { + "dynamic": "strict", + "properties": Object { + "@timestamp": Object { + "ignore_malformed": false, + "type": "date", + }, + "host": Object { + "properties": Object { + "name": Object { + "type": "keyword", + }, + "risk": Object { + "properties": Object { + "calculated_level": Object { + "type": "keyword", + }, + "calculated_score": Object { + "type": "float", + }, + "calculated_score_norm": Object { + "type": "float", + }, + "category_1_count": Object { + "type": "long", + }, + "category_1_score": Object { + "type": "float", + }, + "id_field": Object { + "type": "keyword", + }, + "id_value": Object { + "type": "keyword", + }, + "inputs": Object { + "properties": Object { + "category": Object { + "type": "keyword", + }, + "description": Object { + "type": "keyword", + }, + "id": Object { + "type": "keyword", + }, + "index": Object { + "type": "keyword", + }, + "risk_score": Object { + "type": "float", + }, + "timestamp": Object { + "type": "date", + }, + }, + "type": "object", + }, + "notes": Object { + "type": "keyword", + }, + }, + "type": "object", + }, + }, + }, + "user": Object { + "properties": Object { + "name": Object { + "type": "keyword", + }, + "risk": Object { + "properties": Object { + "calculated_level": Object { + "type": "keyword", + }, + "calculated_score": Object { + "type": "float", + }, + "calculated_score_norm": Object { + "type": "float", + }, + "category_1_count": Object { + "type": "long", + }, + "category_1_score": Object { + "type": "float", + }, + "id_field": Object { + "type": "keyword", + }, + "id_value": Object { + "type": "keyword", + }, + "inputs": Object { + "properties": Object { + "category": Object { + "type": "keyword", + }, + "description": Object { + "type": "keyword", + }, + "id": Object { + "type": "keyword", + }, + "index": Object { + "type": "keyword", + }, + "risk_score": Object { + "type": "float", + }, + "timestamp": Object { + "type": "date", + }, + }, + "type": "object", + }, + "notes": Object { + "type": "keyword", + }, + }, + "type": "object", + }, + }, + }, + }, + }, + "settings": Object {}, + } + `); + + expect(createOrUpdateIndexTemplate).toHaveBeenCalledWith({ + logger, + esClient, + template: { + name: '.risk-score.risk-score-default-index-template', + body: { + data_stream: { hidden: true }, + index_patterns: ['risk-score.risk-score-default'], + composed_of: ['.risk-score-mappings'], + template: { + lifecycle: {}, + settings: { + 'index.mapping.total_fields.limit': totalFieldsLimit, + }, + mappings: { + dynamic: false, + _meta: { + kibana: { + version: '8.9.0', + }, + managed: true, + namespace: 'default', + }, + }, + }, + _meta: { + kibana: { + version: '8.9.0', + }, + managed: true, + namespace: 'default', + }, + }, + }, + }); + + expect(createDataStream).toHaveBeenCalledWith({ + logger, + esClient, + totalFieldsLimit, + indexPatterns: { + template: `.risk-score.risk-score-default-index-template`, + alias: `risk-score.risk-score-default`, + }, + }); + + expect(createOrUpdateIndex).toHaveBeenCalledWith({ + logger, + esClient, + options: { + index: `risk-score.risk-score-latest-default`, + mappings: { + dynamic: 'strict', + properties: { + '@timestamp': { + ignore_malformed: false, + type: 'date', + }, + host: { + properties: { + name: { + type: 'keyword', + }, + risk: { + properties: { + calculated_level: { + type: 'keyword', + }, + calculated_score: { + type: 'float', + }, + calculated_score_norm: { + type: 'float', + }, + category_1_count: { + type: 'long', + }, + category_1_score: { + type: 'float', + }, + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + inputs: { + properties: { + category: { + type: 'keyword', + }, + description: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + index: { + type: 'keyword', + }, + risk_score: { + type: 'float', + }, + timestamp: { + type: 'date', + }, + }, + type: 'object', + }, + notes: { + type: 'keyword', + }, + }, + type: 'object', + }, + }, + }, + user: { + properties: { + name: { + type: 'keyword', + }, + risk: { + properties: { + calculated_level: { + type: 'keyword', + }, + calculated_score: { + type: 'float', + }, + calculated_score_norm: { + type: 'float', + }, + category_1_count: { + type: 'long', + }, + category_1_score: { + type: 'float', + }, + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + inputs: { + properties: { + category: { + type: 'keyword', + }, + description: { + type: 'keyword', + }, + id: { + type: 'keyword', + }, + index: { + type: 'keyword', + }, + risk_score: { + type: 'float', + }, + timestamp: { + type: 'date', + }, + }, + type: 'object', + }, + notes: { + type: 'keyword', + }, + }, + type: 'object', + }, + }, + }, + }, + }, + }, + }); + + expect(transforms.createTransform).toHaveBeenCalledWith({ + logger, + esClient, + transform: { + dest: { + index: 'risk-score.risk-score-latest-default', + }, + frequency: '1h', + latest: { + sort: '@timestamp', + unique_key: ['host.name', 'user.name'], + }, + source: { + index: ['risk-score.risk-score-default'], + }, + sync: { + time: { + delay: '2s', + field: '@timestamp', + }, + }, + transform_id: 'risk_score_latest_transform_default', + }, + }); + }); + }); + + describe('init error', () => { + it('should handle errors during initialization', async () => { + const error = new Error('There error'); + (createOrUpdateIndexTemplate as jest.Mock).mockRejectedValueOnce(error); + + try { + await riskScoreDataClient.init(); + } catch (e) { + expect(logger.error).toHaveBeenCalledWith( + `Error initializing risk engine resources: ${error.message}` + ); + } + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.ts new file mode 100644 index 000000000000..0b8cea72d25c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_data_client.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Metadata } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { ClusterPutComponentTemplateRequest } from '@elastic/elasticsearch/lib/api/types'; +import { + createOrUpdateComponentTemplate, + createOrUpdateIndexTemplate, +} from '@kbn/alerting-plugin/server'; +import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; +import type { Logger, ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; + +import { + riskScoreFieldMap, + getIndexPatternDataStream, + totalFieldsLimit, + mappingComponentName, + getTransformOptions, +} from './configurations'; +import { createDataStream } from '../utils/create_datastream'; +import type { RiskEngineDataWriter as Writer } from './risk_engine_data_writer'; +import { RiskEngineDataWriter } from './risk_engine_data_writer'; +import { getRiskScoreLatestIndex } from '../../../../common/risk_engine'; +import { getLatestTransformId, createTransform } from '../utils/transforms'; +import { getRiskInputsIndex } from './get_risk_inputs_index'; + +import { createOrUpdateIndex } from '../utils/create_or_update_index'; + +interface RiskScoringDataClientOpts { + logger: Logger; + kibanaVersion: string; + esClient: ElasticsearchClient; + namespace: string; + soClient: SavedObjectsClientContract; +} + +export class RiskScoreDataClient { + private writerCache: Map = new Map(); + constructor(private readonly options: RiskScoringDataClientOpts) {} + + public async getWriter({ namespace }: { namespace: string }): Promise { + if (this.writerCache.get(namespace)) { + return this.writerCache.get(namespace) as Writer; + } + const indexPatterns = getIndexPatternDataStream(namespace); + await this.initializeWriter(namespace, indexPatterns.alias); + return this.writerCache.get(namespace) as Writer; + } + + private async initializeWriter(namespace: string, index: string): Promise { + const writer = new RiskEngineDataWriter({ + esClient: this.options.esClient, + namespace, + index, + logger: this.options.logger, + }); + + this.writerCache.set(namespace, writer); + return writer; + } + + public getRiskInputsIndex = ({ dataViewId }: { dataViewId: string }) => + getRiskInputsIndex({ + dataViewId, + logger: this.options.logger, + soClient: this.options.soClient, + }); + + public async init() { + const namespace = this.options.namespace; + + try { + const esClient = this.options.esClient; + + const indexPatterns = getIndexPatternDataStream(namespace); + + const indexMetadata: Metadata = { + kibana: { + version: this.options.kibanaVersion, + }, + managed: true, + namespace, + }; + + await Promise.all([ + createOrUpdateComponentTemplate({ + logger: this.options.logger, + esClient, + template: { + name: mappingComponentName, + _meta: { + managed: true, + }, + template: { + settings: {}, + mappings: mappingFromFieldMap(riskScoreFieldMap, 'strict'), + }, + } as ClusterPutComponentTemplateRequest, + totalFieldsLimit, + }), + ]); + + await createOrUpdateIndexTemplate({ + logger: this.options.logger, + esClient, + template: { + name: indexPatterns.template, + body: { + data_stream: { hidden: true }, + index_patterns: [indexPatterns.alias], + composed_of: [mappingComponentName], + template: { + lifecycle: {}, + settings: { + 'index.mapping.total_fields.limit': totalFieldsLimit, + }, + mappings: { + dynamic: false, + _meta: indexMetadata, + }, + }, + _meta: indexMetadata, + }, + }, + }); + + await createDataStream({ + logger: this.options.logger, + esClient, + totalFieldsLimit, + indexPatterns, + }); + + await createOrUpdateIndex({ + esClient, + logger: this.options.logger, + options: { + index: getRiskScoreLatestIndex(namespace), + mappings: mappingFromFieldMap(riskScoreFieldMap, 'strict'), + }, + }); + + const transformId = getLatestTransformId(namespace); + await createTransform({ + esClient, + logger: this.options.logger, + transform: { + transform_id: transformId, + ...getTransformOptions({ + dest: getRiskScoreLatestIndex(namespace), + source: [indexPatterns.alias], + }), + }, + }); + } catch (error) { + this.options.logger.error(`Error initializing risk engine resources: ${error.message}`); + throw error; + } + } +} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.mock.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.mock.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts similarity index 81% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts index ecc731696f14..a89835c6c732 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_score_service.ts @@ -12,12 +12,13 @@ import type { CalculateScoresParams, CalculateScoresResponse, RiskEngineConfiguration, -} from './types'; +} from '../types'; import { calculateRiskScores } from './calculate_risk_scores'; import { calculateAndPersistRiskScores } from './calculate_and_persist_risk_scores'; -import type { RiskEngineDataClient } from './risk_engine_data_client'; +import type { RiskEngineDataClient } from '../risk_engine/risk_engine_data_client'; +import type { RiskScoreDataClient } from './risk_score_data_client'; import type { RiskInputsIndexResponse } from './get_risk_inputs_index'; -import { scheduleLatestTransformNow } from './utils/transforms'; +import { scheduleLatestTransformNow } from '../utils/transforms'; export interface RiskScoreService { calculateScores: (params: CalculateScoresParams) => Promise; @@ -33,6 +34,7 @@ export interface RiskScoreServiceFactoryParams { esClient: ElasticsearchClient; logger: Logger; riskEngineDataClient: RiskEngineDataClient; + riskScoreDataClient: RiskScoreDataClient; spaceId: string; } @@ -40,12 +42,13 @@ export const riskScoreServiceFactory = ({ esClient, logger, riskEngineDataClient, + riskScoreDataClient, spaceId, }: RiskScoreServiceFactoryParams): RiskScoreService => ({ calculateScores: (params) => calculateRiskScores({ ...params, esClient, logger }), calculateAndPersistScores: (params) => - calculateAndPersistRiskScores({ ...params, esClient, logger, riskEngineDataClient, spaceId }), + calculateAndPersistRiskScores({ ...params, esClient, logger, riskScoreDataClient, spaceId }), getConfiguration: async () => riskEngineDataClient.getConfiguration(), - getRiskInputsIndex: async (params) => riskEngineDataClient.getRiskInputsIndex(params), + getRiskInputsIndex: async (params) => riskScoreDataClient.getRiskInputsIndex(params), scheduleLatestTransformNow: () => scheduleLatestTransformNow({ namespace: spaceId, esClient }), }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts new file mode 100644 index 000000000000..0a62695dfd68 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.test.ts @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { riskScoreCalculationRoute } from './calculation'; + +import { loggerMock } from '@kbn/logging-mocks'; + +import { RISK_SCORE_CALCULATION_URL } from '../../../../../common/constants'; +import { + serverMock, + requestContextMock, + requestMock, +} from '../../../detection_engine/routes/__mocks__'; +import { riskScoreServiceFactory } from '../risk_score_service'; +import { riskScoreServiceMock } from '../risk_score_service.mock'; +import { getRiskInputsIndex } from '../get_risk_inputs_index'; +import { calculateAndPersistRiskScoresMock } from '../calculate_and_persist_risk_scores.mock'; + +jest.mock('../get_risk_inputs_index'); +jest.mock('../risk_score_service'); + +describe('risk score calculation route', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + let logger: ReturnType; + let mockRiskScoreService: ReturnType; + + beforeEach(() => { + jest.resetAllMocks(); + + server = serverMock.create(); + logger = loggerMock.create(); + ({ clients, context } = requestContextMock.createTools()); + mockRiskScoreService = riskScoreServiceMock.create(); + + (getRiskInputsIndex as jest.Mock).mockResolvedValue({ + index: 'default-dataview-index', + runtimeMappings: {}, + }); + clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); + (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); + + riskScoreCalculationRoute(server.router, logger); + }); + + const buildRequest = (overrides: object = {}) => { + const defaults = { + data_view_id: 'default-dataview-id', + range: { start: 'now-30d', end: 'now' }, + identifier_type: 'host', + }; + + return requestMock.create({ + method: 'post', + path: RISK_SCORE_CALCULATION_URL, + body: { ...defaults, ...overrides }, + }); + }; + + it('should return 200 when risk score calculation is successful', async () => { + mockRiskScoreService.calculateAndPersistScores.mockResolvedValue( + calculateAndPersistRiskScoresMock.buildResponse() + ); + const request = buildRequest(); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + }); + + describe('parameters', () => { + it('accepts a parameter for the dataview', async () => { + const request = buildRequest({ data_view_id: 'custom-dataview-id' }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(getRiskInputsIndex).toHaveBeenCalledWith( + expect.objectContaining({ dataViewId: 'custom-dataview-id' }) + ); + }); + + it('accepts a parameter for the range', async () => { + const request = buildRequest({ range: { start: 'now-30d', end: 'now-20d' } }); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateAndPersistScores).toHaveBeenCalledWith( + expect.objectContaining({ range: { start: 'now-30d', end: 'now-20d' } }) + ); + }); + }); + + describe('validation', () => { + describe('required parameters', () => { + it('requires a parameter for the dataview', async () => { + const request = buildRequest({ data_view_id: undefined }); + const result = await server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "undefined" supplied to "data_view_id"' + ); + }); + + it('requires a parameter for the date range', async () => { + const request = buildRequest({ range: undefined }); + const result = await server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "undefined" supplied to "range"' + ); + }); + + it('requires a parameter for the identifier type', async () => { + const request = buildRequest({ identifier_type: undefined }); + const result = await server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "undefined" supplied to "identifier_type"' + ); + }); + }); + + it('uses an unknown dataview as index pattern', async () => { + const request = buildRequest({ data_view_id: 'unknown-dataview' }); + (getRiskInputsIndex as jest.Mock).mockResolvedValue({ + index: 'unknown-dataview', + runtimeMappings: {}, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateAndPersistScores).toHaveBeenCalledWith( + expect.objectContaining({ index: 'unknown-dataview', runtimeMappings: {} }) + ); + }); + + it('rejects an invalid date range', async () => { + const request = buildRequest({ range: 'bad range' }); + const result = await server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "bad range" supplied to "range"' + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts new file mode 100644 index 000000000000..bb77d999aef4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { + APP_ID, + DEFAULT_RISK_SCORE_PAGE_SIZE, + RISK_SCORE_CALCULATION_URL, +} from '../../../../../common/constants'; +import { riskScoreCalculationRequestSchema } from '../../../../../common/risk_engine/risk_score_calculation/request_schema'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { riskScoreServiceFactory } from '../risk_score_service'; +import { getRiskInputsIndex } from '../get_risk_inputs_index'; + +export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { + router.versioned + .post({ + path: RISK_SCORE_CALCULATION_URL, + access: 'internal', + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: '1', + validate: { request: { body: buildRouteValidation(riskScoreCalculationRequestSchema) } }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + const securityContext = await context.securitySolution; + const coreContext = await context.core; + const esClient = coreContext.elasticsearch.client.asCurrentUser; + const soClient = coreContext.savedObjects.client; + const spaceId = securityContext.getSpaceId(); + const riskEngineDataClient = securityContext.getRiskEngineDataClient(); + const riskScoreDataClient = securityContext.getRiskScoreDataClient(); + + const riskScoreService = riskScoreServiceFactory({ + esClient, + logger, + riskEngineDataClient, + riskScoreDataClient, + spaceId, + }); + + const { + after_keys: userAfterKeys, + data_view_id: dataViewId, + debug, + page_size: userPageSize, + identifier_type: identifierType, + filter, + range, + weights, + } = request.body; + + try { + const { index, runtimeMappings } = await getRiskInputsIndex({ + dataViewId, + logger, + soClient, + }); + + const afterKeys = userAfterKeys ?? {}; + const pageSize = userPageSize ?? DEFAULT_RISK_SCORE_PAGE_SIZE; + + const result = await riskScoreService.calculateAndPersistScores({ + afterKeys, + debug, + pageSize, + identifierType, + index, + filter, + range, + runtimeMappings, + weights, + }); + + return response.ok({ body: result }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/index.ts new file mode 100644 index 000000000000..56d769899641 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { riskScorePreviewRoute } from './preview'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts new file mode 100644 index 000000000000..09f6335077c8 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts @@ -0,0 +1,257 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggerMock } from '@kbn/logging-mocks'; + +import { RISK_SCORE_PREVIEW_URL } from '../../../../../common/constants'; +import { RiskCategories, RiskWeightTypes } from '../../../../../common/risk_engine'; +import { + serverMock, + requestContextMock, + requestMock, +} from '../../../detection_engine/routes/__mocks__'; +import { getRiskInputsIndex } from '../get_risk_inputs_index'; +import { riskScoreServiceFactory } from '../risk_score_service'; +import { riskScoreServiceMock } from '../risk_score_service.mock'; +import { riskScorePreviewRoute } from './preview'; + +jest.mock('../risk_score_service'); +jest.mock('../get_risk_inputs_index'); + +describe('POST risk_engine/preview route', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + let logger: ReturnType; + let mockRiskScoreService: ReturnType; + + beforeEach(() => { + jest.resetAllMocks(); + + server = serverMock.create(); + logger = loggerMock.create(); + ({ clients, context } = requestContextMock.createTools()); + mockRiskScoreService = riskScoreServiceMock.create(); + (getRiskInputsIndex as jest.Mock).mockImplementationOnce( + async ({ dataViewId }: { dataViewId: string }) => ({ + index: dataViewId, + runtimeMappings: {}, + }) + ); + + clients.appClient.getAlertsIndex.mockReturnValue('default-alerts-index'); + (riskScoreServiceFactory as jest.Mock).mockReturnValue(mockRiskScoreService); + + riskScorePreviewRoute(server.router, logger); + }); + + const buildRequest = (body: object = {}) => + requestMock.create({ + method: 'get', + path: RISK_SCORE_PREVIEW_URL, + body: { + data_view_id: 'default-dataview-id', + ...body, + }, + }); + + describe('parameters', () => { + describe('index / dataview', () => { + it('requires a parameter for the dataview', async () => { + const request = buildRequest({ data_view_id: undefined }); + const result = await server.validate(request); + + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "undefined" supplied to "data_view_id"' + ); + }); + + it('respects the provided dataview', async () => { + const request = buildRequest({ data_view_id: 'custom-dataview-id' }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ index: 'custom-dataview-id' }) + ); + }); + + it('uses an unknown dataview as index pattern', async () => { + const request = buildRequest({ data_view_id: 'unknown-dataview' }); + (getRiskInputsIndex as jest.Mock).mockResolvedValue({ + index: 'unknown-dataview', + runtimeMappings: {}, + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ index: 'unknown-dataview', runtimeMappings: {} }) + ); + }); + }); + + describe('date range', () => { + it('defaults to the last 15 days of data', async () => { + const request = buildRequest(); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ range: { start: 'now-15d', end: 'now' } }) + ); + }); + + it('respects the provided range if provided', async () => { + const request = buildRequest({ range: { start: 'now-30d', end: 'now-20d' } }); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ range: { start: 'now-30d', end: 'now-20d' } }) + ); + }); + + it('rejects an invalid date range', async () => { + const request = buildRequest({ + range: { end: 'now' }, + }); + + const result = await server.validate(request); + expect(result.badRequest).toHaveBeenCalledWith( + expect.stringContaining('Invalid value "undefined" supplied to "range,start"') + ); + }); + }); + + describe('data filter', () => { + it('respects the provided filter if provided', async () => { + const request = buildRequest({ + filter: { + bool: { + filter: [ + { + ids: { + values: '1', + }, + }, + ], + }, + }, + }); + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ + filter: { + bool: { + filter: [ + { + ids: { + values: '1', + }, + }, + ], + }, + }, + }) + ); + }); + }); + + describe('weights', () => { + it('uses the specified weights when provided', async () => { + const request = buildRequest({ + weights: [ + { + type: RiskWeightTypes.riskCategory, + value: RiskCategories.category_1, + host: 0.1, + user: 0.2, + }, + ], + }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ + weights: [ + { + type: RiskWeightTypes.riskCategory, + value: RiskCategories.category_1, + host: 0.1, + user: 0.2, + }, + ], + }) + ); + }); + + it('rejects weight values outside the 0-1 range', async () => { + const request = buildRequest({ + weights: [ + { + type: RiskWeightTypes.riskCategory, + value: RiskCategories.category_1, + host: 1.1, + }, + ], + }); + + const result = await server.validate(request); + expect(result.badRequest).toHaveBeenCalledWith( + expect.stringContaining('Invalid value "1.1" supplied to "weights,host"') + ); + }); + + it('rejects unknown weight types', async () => { + const request = buildRequest({ + weights: [ + { + type: 'something new', + host: 1.1, + }, + ], + }); + + const result = await server.validate(request); + expect(result.badRequest).toHaveBeenCalledWith( + 'Invalid value "{"type":"something new","host":1.1}" supplied to "weights"' + ); + }); + }); + + describe('pagination', () => { + it('respects the provided after_key', async () => { + const afterKey = { 'host.name': 'hi mom' }; + const request = buildRequest({ after_keys: { host: afterKey } }); + + const response = await server.inject(request, requestContextMock.convertContext(context)); + + expect(response.status).toEqual(200); + expect(mockRiskScoreService.calculateScores).toHaveBeenCalledWith( + expect.objectContaining({ afterKeys: { host: afterKey } }) + ); + }); + + it('rejects an invalid after_key', async () => { + const request = buildRequest({ + after_keys: { + bad: 'key', + }, + }); + + const result = await server.validate(request); + expect(result.badRequest).toHaveBeenCalledWith('invalid keys "bad"'); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts new file mode 100644 index 000000000000..eaf54cf5e5de --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; + +import { + APP_ID, + DEFAULT_RISK_SCORE_PAGE_SIZE, + RISK_SCORE_PREVIEW_URL, +} from '../../../../../common/constants'; +import { riskScorePreviewRequestSchema } from '../../../../../common/risk_engine/risk_score_preview/request_schema'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { riskScoreServiceFactory } from '../risk_score_service'; +import { getRiskInputsIndex } from '../get_risk_inputs_index'; + +export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { + router.versioned + .post({ + access: 'internal', + path: RISK_SCORE_PREVIEW_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: '1', + validate: { request: { body: buildRouteValidation(riskScorePreviewRequestSchema) } }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + const securityContext = await context.securitySolution; + const coreContext = await context.core; + const esClient = coreContext.elasticsearch.client.asCurrentUser; + const soClient = coreContext.savedObjects.client; + const spaceId = securityContext.getSpaceId(); + const riskEngineDataClient = securityContext.getRiskEngineDataClient(); + const riskScoreDataClient = securityContext.getRiskScoreDataClient(); + + const riskScoreService = riskScoreServiceFactory({ + esClient, + logger, + riskEngineDataClient, + riskScoreDataClient, + spaceId, + }); + + const { + after_keys: userAfterKeys, + data_view_id: dataViewId, + debug, + page_size: userPageSize, + identifier_type: identifierType, + filter, + range: userRange, + weights, + } = request.body; + + try { + const { index, runtimeMappings } = await getRiskInputsIndex({ + dataViewId, + logger, + soClient, + }); + + const afterKeys = userAfterKeys ?? {}; + const range = userRange ?? { start: 'now-15d', end: 'now' }; + const pageSize = userPageSize ?? DEFAULT_RISK_SCORE_PAGE_SIZE; + + const result = await riskScoreService.calculateScores({ + afterKeys, + debug, + filter, + identifierType, + index, + pageSize, + range, + runtimeMappings, + weights, + }); + + return response.ok({ body: result }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/constants.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/constants.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/helpers.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/helpers.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/helpers.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/helpers.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/index.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/index.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/index.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.mock.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.mock.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.mock.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts similarity index 99% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts index 627c92dfb6d5..45562ac8d38a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts @@ -14,7 +14,7 @@ import type { AnalyticsServiceSetup } from '@kbn/core/public'; import type { RiskScoreService } from '../risk_score_service'; import { riskScoreServiceMock } from '../risk_score_service.mock'; import { riskScoringTaskMock } from './risk_scoring_task.mock'; -import { riskEngineDataClientMock } from '../risk_engine_data_client.mock'; +import { riskEngineDataClientMock } from '../../risk_engine/risk_engine_data_client.mock'; import { registerRiskScoringTask, startRiskScoringTask, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts similarity index 96% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts index 525f2247b63b..61a733907fb3 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts @@ -21,7 +21,8 @@ import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import type { AfterKeys, IdentifierType } from '../../../../../common/risk_engine'; import type { StartPlugins } from '../../../../plugin'; import { type RiskScoreService, riskScoreServiceFactory } from '../risk_score_service'; -import { RiskEngineDataClient } from '../risk_engine_data_client'; +import { RiskEngineDataClient } from '../../risk_engine/risk_engine_data_client'; +import { RiskScoreDataClient } from '../risk_score_data_client'; import { isRiskScoreCalculationComplete } from '../helpers'; import { defaultState, @@ -77,11 +78,19 @@ export const registerRiskScoringTask = ({ namespace, soClient, }); + const riskScoreDataClient = new RiskScoreDataClient({ + logger, + kibanaVersion, + esClient, + namespace, + soClient, + }); return riskScoreServiceFactory({ esClient, logger, riskEngineDataClient, + riskScoreDataClient, spaceId: namespace, }); }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/state.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/state.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/state.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/state.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts new file mode 100644 index 000000000000..5968b00c28b1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/types.ts @@ -0,0 +1,146 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { MappingRuntimeFields, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import type { + AfterKey, + AfterKeys, + IdentifierType, + RiskWeights, + Range, + RiskEngineStatus, + RiskScore, +} from '../../../common/risk_engine'; + +export interface CalculateScoresParams { + afterKeys: AfterKeys; + debug?: boolean; + index: string; + filter?: unknown; + identifierType?: IdentifierType; + pageSize: number; + range: { start: string; end: string }; + runtimeMappings: MappingRuntimeFields; + weights?: RiskWeights; +} + +export interface CalculateAndPersistScoresParams { + afterKeys: AfterKeys; + debug?: boolean; + index: string; + filter?: unknown; + identifierType: IdentifierType; + pageSize: number; + range: Range; + runtimeMappings: MappingRuntimeFields; + weights?: RiskWeights; +} + +export interface CalculateAndPersistScoresResponse { + after_keys: AfterKeys; + errors: string[]; + scores_written: number; +} + +export interface CalculateScoresResponse { + debug?: { + request: unknown; + response: unknown; + }; + after_keys: AfterKeys; + scores: { + host?: RiskScore[]; + user?: RiskScore[]; + }; +} + +export interface GetRiskEngineStatusResponse { + legacy_risk_engine_status: RiskEngineStatus; + risk_engine_status: RiskEngineStatus; + is_max_amount_of_risk_engines_reached: boolean; +} + +export interface InitRiskEngineResultResponse { + risk_engine_enabled: boolean; + risk_engine_resources_installed: boolean; + risk_engine_configuration_created: boolean; + legacy_risk_engine_disabled: boolean; + errors: string[]; +} + +export interface InitRiskEngineResponse { + result: InitRiskEngineResultResponse; +} + +export interface InitRiskEngineError { + body: { + message: string; + full_error: InitRiskEngineResultResponse | undefined; + }; +} + +export interface EnableDisableRiskEngineErrorResponse { + body: { + message: string; + full_error: string; + }; +} + +export interface EnableRiskEngineResponse { + success: boolean; +} + +export interface DisableRiskEngineResponse { + success: boolean; +} + +export interface RiskEnginePrivilegesResponse { + privileges: { + elasticsearch: { + cluster: Record; + index: Record>; + }; + }; + has_all_required: boolean; +} + +export interface CalculateRiskScoreAggregations { + user?: { + after_key: AfterKey; + buckets: RiskScoreBucket[]; + }; + host?: { + after_key: AfterKey; + buckets: RiskScoreBucket[]; + }; +} + +export interface RiskScoreBucket { + key: { [identifierField: string]: string }; + doc_count: number; + risk_details: { + value: { + score: number; + normalized_score: number; + notes: string[]; + level: string; + category_1_score: number; + category_1_count: number; + }; + }; + inputs: SearchResponse; +} + +export interface RiskEngineConfiguration { + dataViewId: string; + enabled: boolean; + filter: unknown; + identifierType: IdentifierType | undefined; + interval: string; + pageSize: number; + range: Range; +} diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_datastream.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_datastream.ts new file mode 100644 index 000000000000..3ca4572d945e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_datastream.ts @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// This file is a copy of x-pack/plugins/alerting/server/alerts_service/lib/create_concrete_write_index.ts +// original function create index instead of datastream, and their have plan to use datastream in the future +// so we probably should remove this file and use the original when datastream will be supported + +import { get } from 'lodash'; +import type { IndicesSimulateIndexTemplateResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { Logger, ElasticsearchClient } from '@kbn/core/server'; +import { retryTransientEsErrors } from './retry_transient_es_errors'; + +export interface IIndexPatternString { + template: string; + alias: string; +} + +interface CreateConcreteWriteIndexOpts { + logger: Logger; + esClient: ElasticsearchClient; + totalFieldsLimit: number; + indexPatterns: IIndexPatternString; +} + +interface UpdateIndexMappingsOpts { + logger: Logger; + esClient: ElasticsearchClient; + totalFieldsLimit?: number; + indices: string[]; +} + +interface UpdateIndexOpts { + logger: Logger; + esClient: ElasticsearchClient; + totalFieldsLimit?: number; + index: string; +} + +const updateTotalFieldLimitSetting = async ({ + logger, + esClient, + totalFieldsLimit, + index, +}: UpdateIndexOpts) => { + try { + await retryTransientEsErrors( + () => + esClient.indices.putSettings({ + index, + body: { 'index.mapping.total_fields.limit': totalFieldsLimit }, + }), + { logger } + ); + } catch (err) { + logger.error( + `Failed to PUT index.mapping.total_fields.limit settings for index ${index}: ${err.message}` + ); + throw err; + } +}; + +// This will update the mappings of indices but *not* the settings. This +// is due to the fact settings can be classed as dynamic and static, and static +// updates will fail on an index that isn't closed. New settings *will* be applied as part +// of the ILM policy rollovers. More info: https://github.com/elastic/kibana/pull/113389#issuecomment-940152654 +const updateUnderlyingMapping = async ({ logger, esClient, index }: UpdateIndexOpts) => { + let simulatedIndexMapping: IndicesSimulateIndexTemplateResponse; + try { + simulatedIndexMapping = await retryTransientEsErrors( + () => esClient.indices.simulateIndexTemplate({ name: index }), + { logger } + ); + } catch (err) { + logger.error( + `Ignored PUT mappings for index ${index}; error generating simulated mappings: ${err.message}` + ); + return; + } + + const simulatedMapping = get(simulatedIndexMapping, ['template', 'mappings']); + + if (simulatedMapping == null) { + logger.error(`Ignored PUT mappings for index ${index}; simulated mappings were empty`); + return; + } + + try { + await retryTransientEsErrors( + () => esClient.indices.putMapping({ index, body: simulatedMapping }), + { logger } + ); + logger.info(`Update mappings for ${index}`); + } catch (err) { + logger.error(`Failed to PUT mapping for index ${index}: ${err.message}`); + throw err; + } +}; +/** + * Updates the underlying mapping for any existing concrete indices + */ +export const updateIndexMappings = async ({ + logger, + esClient, + totalFieldsLimit, + indices, +}: UpdateIndexMappingsOpts) => { + logger.info(`Updating underlying mappings for ${indices.length} indices.`); + + if (totalFieldsLimit) { + // Update total field limit setting of found indices + // Other index setting changes are not updated at this time + await Promise.all( + indices.map((index) => + updateTotalFieldLimitSetting({ logger, esClient, totalFieldsLimit, index }) + ) + ); + } + + // Update mappings of the found indices. + await Promise.all(indices.map((index) => updateUnderlyingMapping({ logger, esClient, index }))); +}; + +/** + * Create a data stream + */ +export const createDataStream = async ({ + logger, + esClient, + indexPatterns, + totalFieldsLimit, +}: CreateConcreteWriteIndexOpts) => { + logger.info(`Creating data stream - ${indexPatterns.alias}`); + + // check if a datastream already exists + let dataStreams: string[] = []; + try { + // Specify both the index pattern for the backing indices and their aliases + // The alias prevents the request from finding other namespaces that could match the -* pattern + const response = await retryTransientEsErrors( + () => esClient.indices.getDataStream({ name: indexPatterns.alias, expand_wildcards: 'all' }), + { logger } + ); + + dataStreams = response.data_streams.map((dataStream) => dataStream.name); + + logger.debug( + `Found ${dataStreams.length} concrete indices for ${indexPatterns.alias} - ${JSON.stringify( + dataStreams + )}` + ); + } catch (error) { + // 404 is expected if no datastream have been created + if (error.statusCode !== 404) { + logger.error( + `Error fetching concrete indices for ${indexPatterns.alias} pattern - ${error.message}` + ); + throw error; + } + } + + const dataStreamsExist = dataStreams.length > 0; + + // if a concrete write datastream already exists, update the underlying mapping + if (dataStreams.length > 0) { + await updateIndexMappings({ logger, esClient, totalFieldsLimit, indices: dataStreams }); + } + + // check if a concrete write datastream already exists + if (!dataStreamsExist) { + try { + await retryTransientEsErrors( + () => + esClient.indices.createDataStream({ + name: indexPatterns.alias, + }), + { logger } + ); + } catch (error) { + logger.error(`Error creating datastream - ${error.message}`); + throw error; + } + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts new file mode 100644 index 000000000000..f9525e14ac6c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import type { + IndicesCreateRequest, + IndicesCreateResponse, +} from '@elastic/elasticsearch/lib/api/types'; +import { retryTransientEsErrors } from './retry_transient_es_errors'; + +/** + * It's check for index existatnce, and create index + * or update existing index mappings + */ +export const createOrUpdateIndex = async ({ + esClient, + logger, + options, +}: { + esClient: ElasticsearchClient; + logger: Logger; + options: IndicesCreateRequest; +}): Promise => { + try { + const isIndexExist = await esClient.indices.exists({ + index: options.index, + }); + if (isIndexExist) { + const response = await esClient.indices.get({ + index: options.index, + }); + const indices = Object.keys(response ?? {}); + logger.info(`${options.index} already exist`); + if (options.mappings) { + await Promise.all( + indices.map(async (index) => { + try { + await retryTransientEsErrors( + () => esClient.indices.putMapping({ index, body: options.mappings }), + { logger } + ); + logger.info(`Update mappings for ${index}`); + } catch (err) { + logger.error(`Failed to PUT mapping for index ${index}: ${err.message}`); + } + }) + ); + } + } else { + return esClient.indices.create(options); + } + } catch (err) { + const error = transformError(err); + const fullErrorMessage = `Failed to create index: ${options.index}: ${error.message}`; + logger.error(fullErrorMessage); + throw new Error(fullErrorMessage); + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/retry_transient_es_errors.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/utils/retry_transient_es_errors.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/retry_transient_es_errors.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/utils/retry_transient_es_errors.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/transforms.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.test.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/utils/transforms.test.ts diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/transforms.ts similarity index 97% rename from x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts rename to x-pack/plugins/security_solution/server/lib/entity_analytics/utils/transforms.ts index b78ea9ccfa64..d1a544233339 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/transforms.ts @@ -14,11 +14,11 @@ import type { TransformPutTransformRequest, TransformGetTransformStatsTransformStats, } from '@elastic/elasticsearch/lib/api/types'; -import { RiskScoreEntity } from '../../../../../common/search_strategy'; +import { RiskScoreEntity } from '../../../../common/search_strategy'; import { getRiskScorePivotTransformId, getRiskScoreLatestTransformId, -} from '../../../../../common/utils/risk_score_modules'; +} from '../../../../common/utils/risk_score_modules'; export const getLegacyTransforms = async ({ namespace, diff --git a/x-pack/plugins/security_solution/server/lib/framework/types.ts b/x-pack/plugins/security_solution/server/lib/framework/types.ts index 8909bb616013..ef6df370c03c 100644 --- a/x-pack/plugins/security_solution/server/lib/framework/types.ts +++ b/x-pack/plugins/security_solution/server/lib/framework/types.ts @@ -6,7 +6,7 @@ */ import type { KibanaRequest, RequestHandlerContext } from '@kbn/core/server'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; export const internalFrameworkRequest = Symbol('internalFrameworkRequest'); diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts b/x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts index 77e47f215713..79eef256f8e9 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts @@ -11,7 +11,7 @@ import { APP_ID, RISK_SCORE_INDEX_STATUS_API_URL } from '../../../../common/cons import type { SecuritySolutionPluginRouter } from '../../../types'; import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../detection_engine/routes/utils'; -import { indexStatusRequestQuery } from '../../../../common/api/risk_score'; +import { indexStatusRequestQuery } from '../../../../common/api/entity_analytics/risk_score'; export const getRiskScoreIndexStatusRoute = (router: SecuritySolutionPluginRouter) => { router.versioned diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/indices/create_index_route.ts b/x-pack/plugins/security_solution/server/lib/risk_score/indices/create_index_route.ts index 22987cf563d0..ef4aacf251ff 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/indices/create_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/indices/create_index_route.ts @@ -12,7 +12,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { RISK_SCORE_CREATE_INDEX } from '../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { createIndex } from './lib/create_index'; -import { createEsIndexRequestBody } from '../../../../common/api/risk_score'; +import { createEsIndexRequestBody } from '../../../../common/api/entity_analytics/risk_score'; export const createEsIndexRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { router.versioned diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/indices/delete_indices_route.ts b/x-pack/plugins/security_solution/server/lib/risk_score/indices/delete_indices_route.ts index 326963992a70..407e9e0a8f3e 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/indices/delete_indices_route.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/indices/delete_indices_route.ts @@ -10,7 +10,7 @@ import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { RISK_SCORE_DELETE_INDICES } from '../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { deleteEsIndices } from './lib/delete_indices'; -import { deleteIndicesRequestBody } from '../../../../common/api/risk_score'; +import { deleteIndicesRequestBody } from '../../../../common/api/entity_analytics/risk_score'; export const deleteEsIndicesRoute = (router: SecuritySolutionPluginRouter) => { router.versioned diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/indices/lib/create_index.ts b/x-pack/plugins/security_solution/server/lib/risk_score/indices/lib/create_index.ts index 48d3c333dff0..4104c97812e0 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/indices/lib/create_index.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/indices/lib/create_index.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; -import type { CreateEsIndexRequestBody } from '../../../../../common/api/risk_score'; +import type { CreateEsIndexRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const createIndex = async ({ esClient, diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/onboarding/routes/install_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/risk_score/onboarding/routes/install_risk_scores.ts index f8afbbfae936..627a9afd4e87 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/onboarding/routes/install_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/onboarding/routes/install_risk_scores.ts @@ -16,7 +16,7 @@ import type { SetupPlugins } from '../../../../plugin'; import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { installRiskScoreModule } from '../helpers/install_risk_score_module'; -import { onboardingRiskScoreRequestBody } from '../../../../../common/api/risk_score'; +import { onboardingRiskScoreRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const installRiskScoresRoute = ( router: SecuritySolutionPluginRouter, diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts index 70edd32eee58..df819487e13b 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/routes/read_prebuilt_dev_tool_content_route.ts @@ -14,7 +14,7 @@ import { DEV_TOOL_PREBUILT_CONTENT } from '../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { consoleMappings } from '../console_mappings'; -import { readConsoleRequestBody } from '../../../../../common/api/risk_score'; +import { readConsoleRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; import { RiskScoreEntity } from '../../../../../common/search_strategy'; import { getView } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/schema.test.ts b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/schema.test.ts index bf02aae37e5c..d5856c31a512 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/schema.test.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_dev_tool_content/schema.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { readConsoleRequestBody } from '../../../../common/api/risk_score'; +import { readConsoleRequestBody } from '../../../../common/api/entity_analytics/risk_score'; describe('ReadConsoleRequestSchema', () => { it('should throw error', () => { diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/create_prebuilt_saved_objects.ts b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/create_prebuilt_saved_objects.ts index ce65983161da..568489155707 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/create_prebuilt_saved_objects.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/create_prebuilt_saved_objects.ts @@ -16,7 +16,7 @@ import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../timeline/utils/common'; import { bulkCreateSavedObjects } from '../helpers/bulk_create_saved_objects'; -import { createPrebuiltSavedObjectsRequestBody } from '../../../../../common/api/risk_score'; +import { createPrebuiltSavedObjectsRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const createPrebuiltSavedObjectsRoute = ( router: SecuritySolutionPluginRouter, diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/delete_prebuilt_saved_objects.ts b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/delete_prebuilt_saved_objects.ts index 9f2138b3c608..c78d1f292afe 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/delete_prebuilt_saved_objects.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/routes/delete_prebuilt_saved_objects.ts @@ -16,7 +16,7 @@ import { buildSiemResponse } from '../../../detection_engine/routes/utils'; import { buildFrameworkRequest } from '../../../timeline/utils/common'; import { bulkDeleteSavedObjects } from '../helpers/bulk_delete_saved_objects'; -import { deletePrebuiltSavedObjectsRequestBody } from '../../../../../common/api/risk_score'; +import { deletePrebuiltSavedObjectsRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const deletePrebuiltSavedObjectsRoute = ( router: SecuritySolutionPluginRouter, diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts index e5909892071c..573d1d30bcd2 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts @@ -8,7 +8,7 @@ import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; -import { createStoredScriptRequestBody } from '../../../../common/api/risk_score'; +import { createStoredScriptRequestBody } from '../../../../common/api/entity_analytics/risk_score'; import { RISK_SCORE_CREATE_STORED_SCRIPT } from '../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { createStoredScript } from './lib/create_script'; diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts index 7f579b28802e..0d7ef94be263 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts @@ -10,7 +10,7 @@ import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { RISK_SCORE_DELETE_STORED_SCRIPT } from '../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { deleteStoredScript } from './lib/delete_script'; -import { deleteStoredScriptRequestBody } from '../../../../common/api/risk_score'; +import { deleteStoredScriptRequestBody } from '../../../../common/api/entity_analytics/risk_score'; export const deleteStoredScriptRoute = (router: SecuritySolutionPluginRouter) => { router.versioned diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/create_script.ts b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/create_script.ts index fc56a3e04926..d6c2e5211625 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/create_script.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/create_script.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; -import type { CreateStoredScriptRequestBody } from '../../../../../common/api/risk_score'; +import type { CreateStoredScriptRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const createStoredScript = async ({ esClient, diff --git a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/delete_script.ts b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/delete_script.ts index b6113b5f9f31..bbbf8e9582ff 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/delete_script.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/lib/delete_script.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; -import type { DeleteStoredScriptRequestBody } from '../../../../../common/api/risk_score'; +import type { DeleteStoredScriptRequestBody } from '../../../../../common/api/entity_analytics/risk_score'; export const deleteStoredScript = async ({ client, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/__mocks__/index.ts b/x-pack/plugins/security_solution/server/lib/telemetry/__mocks__/index.ts index f5718895fff2..4af8d3a9e435 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/__mocks__/index.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import type { ConcreteTaskInstance } from '@kbn/task-manager-plugin/server'; import { TaskStatus } from '@kbn/task-manager-plugin/server'; import type { TelemetryEventsSender } from '../sender'; -import type { TelemetryReceiver } from '../receiver'; +import type { ITelemetryReceiver, TelemetryReceiver } from '../receiver'; import type { SecurityTelemetryTaskConfig } from '../task'; import type { PackagePolicy } from '@kbn/fleet-plugin/common/types/models/package_policy'; import { stubEndpointAlertResponse, stubProcessTree, stubFetchTimelineEvents } from './timeline'; @@ -71,7 +71,7 @@ export const stubLicenseInfo: ESLicense = { export const createMockTelemetryReceiver = ( diagnosticsAlert?: unknown, emptyTimelineTree?: boolean -): jest.Mocked => { +): jest.Mocked => { const processTreeResponse = emptyTimelineTree ? Promise.resolve([]) : Promise.resolve(Promise.resolve(stubProcessTree())); @@ -82,18 +82,18 @@ export const createMockTelemetryReceiver = ( fetchLicenseInfo: jest.fn().mockReturnValue(stubLicenseInfo), copyLicenseFields: jest.fn(), fetchFleetAgents: jest.fn(), + openPointInTime: jest.fn(), + getAlertsIndex: jest.fn().mockReturnValue('alerts-*'), fetchDiagnosticAlerts: jest.fn().mockReturnValue(diagnosticsAlert ?? jest.fn()), fetchEndpointMetrics: jest.fn().mockReturnValue(stubEndpointMetricsResponse), fetchEndpointPolicyResponses: jest.fn(), - fetchPrebuiltRuleAlerts: jest.fn().mockReturnValue(prebuiltRuleAlertsResponse), + fetchPrebuiltRuleAlertsBatch: jest.fn().mockReturnValue(prebuiltRuleAlertsResponse), fetchDetectionRulesPackageVersion: jest.fn(), fetchTrustedApplications: jest.fn(), fetchEndpointList: jest.fn(), fetchDetectionRules: jest.fn().mockReturnValue({ body: null }), fetchEndpointMetadata: jest.fn(), - fetchTimelineEndpointAlerts: jest - .fn() - .mockReturnValue(Promise.resolve(stubEndpointAlertResponse())), + fetchTimelineAlerts: jest.fn().mockReturnValue(Promise.resolve(stubEndpointAlertResponse())), buildProcessTree: jest.fn().mockReturnValue(processTreeResponse), fetchTimelineEvents: jest.fn().mockReturnValue(Promise.resolve(stubFetchTimelineEvents())), fetchValueListMetaData: jest.fn(), diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts index 1404f8dba94e..8e50e4590a72 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/constants.ts @@ -9,6 +9,8 @@ export const TELEMETRY_CHANNEL_LISTS = 'security-lists-v2'; export const TELEMETRY_CHANNEL_ENDPOINT_META = 'endpoint-metadata'; +export const TELEMETRY_CHANNEL_ENDPOINT_ALERTS = 'alerts-endpoint'; + export const TELEMETRY_CHANNEL_DETECTION_ALERTS = 'alerts-detections'; export const TELEMETRY_CHANNEL_TIMELINE = 'alerts-timeline'; @@ -25,6 +27,8 @@ export const INSIGHTS_CHANNEL = 'security-insights-v1'; export const TASK_METRICS_CHANNEL = 'task-metrics'; +export const DEFAULT_DIAGNOSTIC_INDEX = '.logs-endpoint.diagnostic.collection-*' as const; + export const DEFAULT_ADVANCED_POLICY_CONFIG_SETTINGS = { linux: { advanced: { diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/index.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/index.test.ts index d61a3e920681..5ccbb0f53a33 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/index.test.ts @@ -279,6 +279,25 @@ describe('Security Telemetry filters', () => { }); }); + it('copies over github integration fields', () => { + const event = { + not_event: 'much data, much wow', + github: { + org: 'elastic', + repo: 'kibana', + team: 'elastic/security-data-analytics', + sensitive: 'i contain sensitive data', + }, + }; + expect(copyAllowlistedFields(prebuiltRuleAllowlistFields, event)).toStrictEqual({ + github: { + org: 'elastic', + repo: 'kibana', + team: 'elastic/security-data-analytics', + }, + }); + }); + it('copies over process/parent fields', () => { const event = { not_event: 'much data, much wow', diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/prebuilt_rules_alerts.ts b/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/prebuilt_rules_alerts.ts index c08c66a57224..a7e797227d24 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/prebuilt_rules_alerts.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/filterlists/prebuilt_rules_alerts.ts @@ -350,6 +350,14 @@ export const prebuiltRuleAllowlistFields: AllowlistFields = { original_file_name: true, }, }, + github: { + org: true, + team: true, + repo: true, + category: true, + permission: true, + repository_public: true, + }, // Google/GCP google_workspace: { actor: { diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts index f5d6bc41ee34..3bd6a0d595a7 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts @@ -11,17 +11,25 @@ import type { PackagePolicy } from '@kbn/fleet-plugin/common/types/models/packag import { merge, set } from 'lodash'; import type { Logger } from '@kbn/core/server'; import { sha256 } from 'js-sha256'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { copyAllowlistedFields, filterList } from './filterlists'; -import type { PolicyConfig, PolicyData } from '../../../common/endpoint/types'; +import type { PolicyConfig, PolicyData, SafeEndpointEvent } from '../../../common/endpoint/types'; +import type { ITelemetryReceiver } from './receiver'; import type { - ExceptionListItem, + EnhancedAlertEvent, ESClusterInfo, ESLicense, + ExceptionListItem, + ExtraInfo, ListTemplate, + TaskMetric, TelemetryEvent, + TimeFrame, + TimelineResult, + TimelineTelemetryEvent, ValueListResponse, - TaskMetric, } from './types'; +import type { TaskExecutionPeriod } from './task'; import { LIST_DETECTION_RULE_EXCEPTION, LIST_ENDPOINT_EXCEPTION, @@ -30,6 +38,7 @@ import { DEFAULT_ADVANCED_POLICY_CONFIG_SETTINGS, } from './constants'; import { tagsToEffectScope } from '../../../common/endpoint/service/trusted_apps/mapping'; +import { resolverEntity } from '../../endpoint/routes/resolver/entity/utils/build_resolver_entity'; /** * Determines the when the last run was in order to execute to. @@ -345,3 +354,114 @@ export const processK8sUsernames = (clusterId: string, event: TelemetryEvent): T return event; }; + +export const ranges = ( + taskExecutionPeriod: TaskExecutionPeriod, + defaultIntervalInHours: number = 3 +) => { + const rangeFrom = taskExecutionPeriod.last ?? `now-${defaultIntervalInHours}h`; + const rangeTo = taskExecutionPeriod.current; + + return { rangeFrom, rangeTo }; +}; + +export class TelemetryTimelineFetcher { + startTime: number; + private receiver: ITelemetryReceiver; + private extraInfo: Promise; + private timeFrame: TimeFrame; + + constructor(receiver: ITelemetryReceiver) { + this.receiver = receiver; + this.startTime = Date.now(); + this.extraInfo = this.lookupExtraInfo(); + this.timeFrame = this.calculateTimeFrame(); + } + + async fetchTimeline(event: estypes.SearchHit): Promise { + const eventId = event._source ? event._source['event.id'] : 'unknown'; + const alertUUID = event._source ? event._source['kibana.alert.uuid'] : 'unknown'; + + const entities = resolverEntity([event]); + + // Build Tree + const tree = await this.receiver.buildProcessTree( + entities[0].id, + entities[0].schema, + this.timeFrame.startOfDay, + this.timeFrame.endOfDay + ); + + const nodeIds = Array.isArray(tree) ? tree.map((node) => node?.id.toString()) : []; + + const eventsStore = await this.fetchEventLineage(nodeIds); + + const telemetryTimeline: TimelineTelemetryEvent[] = Array.isArray(tree) + ? tree.map((node) => { + return { + ...node, + event: eventsStore.get(node.id.toString()), + }; + }) + : []; + + let record; + if (telemetryTimeline.length >= 1) { + const { clusterInfo, licenseInfo } = await this.extraInfo; + record = { + '@timestamp': moment().toISOString(), + version: clusterInfo.version?.number, + cluster_name: clusterInfo.cluster_name, + cluster_uuid: clusterInfo.cluster_uuid, + license_uuid: licenseInfo?.uid, + alert_id: alertUUID, + event_id: eventId, + timeline: telemetryTimeline, + }; + } + + const result: TimelineResult = { + nodes: nodeIds.length, + events: eventsStore.size, + timeline: record, + }; + + return result; + } + + private async fetchEventLineage(nodeIds: string[]): Promise> { + const timelineEvents = await this.receiver.fetchTimelineEvents(nodeIds); + const eventsStore = new Map(); + for (const event of timelineEvents.hits.hits) { + const doc = event._source; + + if (doc !== null && doc !== undefined) { + const entityId = doc?.process?.entity_id?.toString(); + if (entityId !== null && entityId !== undefined) eventsStore.set(entityId, doc); + } + } + return eventsStore; + } + + private async lookupExtraInfo(): Promise { + const [clusterInfoPromise, licenseInfoPromise] = await Promise.allSettled([ + this.receiver.fetchClusterInfo(), + this.receiver.fetchLicenseInfo(), + ]); + + const clusterInfo: ESClusterInfo = + clusterInfoPromise.status === 'fulfilled' ? clusterInfoPromise.value : ({} as ESClusterInfo); + + const licenseInfo: ESLicense | undefined = + licenseInfoPromise.status === 'fulfilled' ? licenseInfoPromise.value : ({} as ESLicense); + + return { clusterInfo, licenseInfo }; + } + + private calculateTimeFrame(): TimeFrame { + const now = moment(); + const startOfDay = now.startOf('day').toISOString(); + const endOfDay = now.endOf('day').toISOString(); + return { startOfDay, endOfDay }; + } +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts index c699f6a1e969..80b90deba6ef 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -18,7 +18,7 @@ import type { SearchRequest, SearchResponse, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; +import { ENDPOINT_ARTIFACT_LISTS } from '@kbn/securitysolution-list-constants'; import { EQL_RULE_TYPE_ID, INDICATOR_RULE_TYPE_ID, @@ -43,6 +43,7 @@ import type { PackageService, } from '@kbn/fleet-plugin/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; +import moment from 'moment'; import type { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; import { exceptionListItemToTelemetryEntry, @@ -70,6 +71,7 @@ import type { import { telemetryConfiguration } from './configuration'; import { ENDPOINT_METRICS_INDEX } from '../../../common/constants'; import { PREBUILT_RULES_PACKAGE_NAME } from '../../../common/detection_engine/constants'; +import { DEFAULT_DIAGNOSTIC_INDEX } from './constants'; export interface ITelemetryReceiver { start( @@ -83,6 +85,14 @@ export interface ITelemetryReceiver { getClusterInfo(): ESClusterInfo | undefined; + fetchClusterInfo(): Promise; + + fetchLicenseInfo(): Promise; + + openPointInTime(indexPattern: string): Promise; + + closePointInTime(pitId: string): Promise; + fetchDetectionRulesPackageVersion(): Promise; fetchFleetAgents(): Promise< @@ -149,9 +159,15 @@ export interface ITelemetryReceiver { per_page: number; }>; - fetchClusterInfo(): Promise; - - fetchLicenseInfo(): Promise; + fetchPrebuiltRuleAlertsBatch( + pitId: string, + searchAfterValue: SortResults | undefined + ): Promise<{ + moreToFetch: boolean; + newPitId: string; + searchAfter: SortResults | undefined; + alerts: TelemetryEvent[]; + }>; copyLicenseFields(lic: ESLicense): { issuer?: string | undefined; @@ -161,9 +177,11 @@ export interface ITelemetryReceiver { type: string; }; - fetchPrebuiltRuleAlerts(): Promise<{ events: TelemetryEvent[]; count: number }>; - - fetchTimelineEndpointAlerts(interval: number): Promise>>; + fetchTimelineAlerts( + index: string, + rangeFrom: string, + rangeTo: string + ): Promise>>; buildProcessTree( entityId: string, @@ -177,6 +195,8 @@ export interface ITelemetryReceiver { ): Promise>>; fetchValueListMetaData(interval: number): Promise; + + getAlertsIndex(): string | undefined; } export class TelemetryReceiver implements ITelemetryReceiver { @@ -224,6 +244,10 @@ export class TelemetryReceiver implements ITelemetryReceiver { return this.clusterInfo; } + public getAlertsIndex(): string | undefined { + return this.alertsIndex; + } + public async fetchDetectionRulesPackageVersion(): Promise { return this.packageService?.asInternalUser.getInstallation(PREBUILT_RULES_PACKAGE_NAME); } @@ -396,7 +420,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { const query = { expand_wildcards: ['open' as const, 'hidden' as const], - index: '.logs-endpoint.diagnostic.collection-*', + index: `${DEFAULT_DIAGNOSTIC_INDEX}-*`, ignore_unavailable: true, size: telemetryConfiguration.telemetry_max_buffer_size, body: { @@ -439,11 +463,12 @@ export class TelemetryReceiver implements ITelemetryReceiver { // Ensure list is created if it does not exist await this.exceptionListClient.createTrustedAppsList(); + const timeFrom = moment.utc().subtract(1, 'day').valueOf(); const results = await this.exceptionListClient.findExceptionListItem({ - listId: ENDPOINT_TRUSTED_APPS_LIST_ID, + listId: ENDPOINT_ARTIFACT_LISTS.trustedApps.id, page: 1, perPage: 10_000, - filter: undefined, + filter: `exception-list-agnostic.attributes.created_at >= ${timeFrom}`, namespaceType: 'agnostic', sortField: 'name', sortOrder: 'asc', @@ -465,11 +490,12 @@ export class TelemetryReceiver implements ITelemetryReceiver { // Ensure list is created if it does not exist await this.exceptionListClient.createEndpointList(); + const timeFrom = moment.utc().subtract(1, 'day').valueOf(); const results = await this.exceptionListClient.findExceptionListItem({ listId, page: 1, perPage: this.maxRecords, - filter: undefined, + filter: `exception-list-agnostic.attributes.created_at >= ${timeFrom}`, namespaceType: 'agnostic', sortField: 'name', sortOrder: 'asc', @@ -545,9 +571,14 @@ export class TelemetryReceiver implements ITelemetryReceiver { // Ensure list is created if it does not exist await this.exceptionListClient.createTrustedAppsList(); + const timeFrom = `exception-list.attributes.created_at >= ${moment + .utc() + .subtract(24, 'hours') + .valueOf()}`; + const results = await this.exceptionListClient?.findExceptionListsItem({ listId: [listId], - filter: [], + filter: [timeFrom], perPage: this.maxRecords, page: 1, sortField: 'exception-list.created_at', @@ -563,141 +594,191 @@ export class TelemetryReceiver implements ITelemetryReceiver { }; } - /** - * Fetch an overview of detection rule alerts over the last 3 hours. - * Filters out custom rules and endpoint rules. - * @returns total of alerts by rules - */ - public async fetchPrebuiltRuleAlerts() { + public async fetchPrebuiltRuleAlertsBatch( + pitId: string, + searchAfterValue: SortResults | undefined + ) { if (this.esClient === undefined || this.esClient === null) { - throw Error('elasticsearch client is unavailable: cannot retrieve pre-built rule alerts'); + throw Error('es client is unavailable: cannot retrieve pre-built rule alert batches'); } - const query: SearchRequest = { - expand_wildcards: ['open' as const, 'hidden' as const], - index: `${this.alertsIndex}*`, - ignore_unavailable: true, - body: { - size: 1_000, - _source: { - exclude: ['message', 'kibana.alert.rule.note', 'kibana.alert.rule.parameters.note'], - }, - query: { - bool: { - filter: [ - { - bool: { - should: [ - { - bool: { - must_not: { - bool: { - should: [ - { - match_phrase: { - 'kibana.alert.rule.name': 'Malware Prevention Alert', - }, + let newPitId = pitId; + let fetchMore = true; + let searchAfter: SortResults | undefined = searchAfterValue; + const query: ESSearchRequest = { + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + must_not: { + bool: { + should: [ + { + match_phrase: { + 'kibana.alert.rule.name': 'Malware Prevention Alert', }, - ], - }, + }, + ], }, }, }, - { - bool: { - must_not: { - bool: { - should: [ - { - match_phrase: { - 'kibana.alert.rule.name': 'Malware Detection Alert', - }, + }, + { + bool: { + must_not: { + bool: { + should: [ + { + match_phrase: { + 'kibana.alert.rule.name': 'Malware Detection Alert', }, - ], - }, + }, + ], }, }, }, - { - bool: { - must_not: { - bool: { - should: [ - { - match_phrase: { - 'kibana.alert.rule.name': 'Ransomware Prevention Alert', - }, + }, + { + bool: { + must_not: { + bool: { + should: [ + { + match_phrase: { + 'kibana.alert.rule.name': 'Ransomware Prevention Alert', }, - ], - }, + }, + ], }, }, }, - { - bool: { - must_not: { - bool: { - should: [ - { - match_phrase: { - 'kibana.alert.rule.name': 'Ransomware Detection Alert', - }, + }, + { + bool: { + must_not: { + bool: { + should: [ + { + match_phrase: { + 'kibana.alert.rule.name': 'Ransomware Detection Alert', }, - ], - }, + }, + ], }, }, }, - ], - }, + }, + ], }, - { - bool: { - should: [ - { - match_phrase: { - 'kibana.alert.rule.parameters.immutable': 'true', - }, + }, + { + bool: { + should: [ + { + match_phrase: { + 'kibana.alert.rule.parameters.immutable': 'true', }, - ], - }, - }, - { - range: { - '@timestamp': { - gte: 'now-1h', - lte: 'now', }, + ], + }, + }, + { + range: { + '@timestamp': { + gte: 'now-1h', + lte: 'now', }, }, - ], - }, - }, - aggs: { - prebuilt_rule_alert_count: { - cardinality: { - field: 'event.id', }, - }, + ], }, }, + track_total_hits: false, + sort: [ + { '@timestamp': { order: 'asc', format: 'strict_date_optional_time_nanos' } }, + { _shard_doc: 'desc' }, + ] as unknown as string[], + pit: { id: pitId }, + search_after: searchAfter, + size: 1_000, }; - const response = await this.esClient.search(query, { meta: true }); - tlog(this.logger, `received prebuilt alerts: (${response.body.hits.hits.length})`); + let response = null; + try { + response = await this.esClient.search(query); + const numOfHits = response?.hits.hits.length; + + if (numOfHits > 0) { + const lastHit = response?.hits.hits[numOfHits - 1]; + searchAfter = lastHit?.sort; + } + + fetchMore = numOfHits > 0 && numOfHits < 1_000; + } catch (e) { + tlog(this.logger, e); + fetchMore = false; + } + + if (response == null) { + return { + moreToFetch: false, + newPitId: pitId, + searchAfter, + alerts: [] as TelemetryEvent[], + }; + } - const telemetryEvents: TelemetryEvent[] = response.body.hits.hits.flatMap((h) => + const alerts: TelemetryEvent[] = response.hits.hits.flatMap((h) => h._source != null ? ([h._source] as TelemetryEvent[]) : [] ); - const aggregations = response.body?.aggregations as unknown as { - prebuilt_rule_alert_count: { value: number }; + if (response?.pit_id != null) { + newPitId = response?.pit_id; + } + + tlog(this.logger, `Prebuilt rule alerts to return: ${alerts.length}`); + + return { + moreToFetch: fetchMore, + newPitId, + searchAfter, + alerts, }; + } + + public async openPointInTime(indexPattern: string) { + if (this.esClient === undefined || this.esClient === null) { + throw Error('es client is unavailable: cannot retrieve pre-built rule alert batches'); + } + + const keepAlive = '5m'; + const pitId: OpenPointInTimeResponse['id'] = ( + await this.esClient.openPointInTime({ + index: `${indexPattern}*`, + keep_alive: keepAlive, + }) + ).id; + + return pitId; + } + + public async closePointInTime(pitId: string) { + if (this.esClient === undefined || this.esClient === null) { + throw Error('es client is unavailable: cannot retrieve pre-built rule alert batches'); + } - return { events: telemetryEvents, count: aggregations?.prebuilt_rule_alert_count.value ?? 0 }; + try { + await this.esClient.closePointInTime({ id: pitId }); + } catch (error) { + tlog(this.logger, `Error trying to close point in time: "${pitId}". Error is: "${error}"`); + } } - public async fetchTimelineEndpointAlerts(interval: number) { + async fetchTimelineAlerts(index: string, rangeFrom: string, rangeTo: string) { if (this.esClient === undefined || this.esClient === null) { throw Error('elasticsearch client is unavailable: cannot retrieve cluster infomation'); } @@ -708,7 +789,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { // create and assign an initial point in time let pitId: OpenPointInTimeResponse['id'] = ( await this.esClient.openPointInTime({ - index: `${this.alertsIndex}*`, + index: `${index}*`, keep_alive: keepAlive, }) ).id; @@ -746,8 +827,8 @@ export class TelemetryReceiver implements ITelemetryReceiver { { range: { '@timestamp': { - gte: `now-${interval}h`, - lte: 'now', + gte: rangeFrom, + lte: rangeTo, }, }, }, @@ -807,7 +888,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { } tlog(this.logger, `Timeline alerts to return: ${alertsToReturn.length}`); - return alertsToReturn; + return alertsToReturn || []; } public async buildProcessTree( diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 39af813916cd..041d9b67720d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -397,7 +397,7 @@ export class TelemetryEventsSender implements ITelemetryEventsSender { 'X-Elastic-Stack-Version': clusterVersionNumber ? clusterVersionNumber : '8.0.0', ...(licenseId ? { 'X-Elastic-License-ID': licenseId } : {}), }, - timeout: 5000, + timeout: 10000, }); this.telemetryUsageCounter?.incrementCounter({ counterName: createUsageCounterLabel(usageLabelPrefix.concat(['payloads', channel])), diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts index 4562cbb725cb..00da024b0049 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/detection_rule.ts @@ -11,7 +11,13 @@ import { TELEMETRY_CHANNEL_LISTS, TASK_METRICS_CHANNEL, } from '../constants'; -import { batchTelemetryRecords, templateExceptionList, tlog, createTaskMetric } from '../helpers'; +import { + batchTelemetryRecords, + templateExceptionList, + tlog, + createTaskMetric, + createUsageCounterLabel, +} from '../helpers'; import type { ITelemetryEventsSender } from '../sender'; import type { ITelemetryReceiver } from '../receiver'; import type { ExceptionListItem, ESClusterInfo, ESLicense, RuleSearchResult } from '../types'; @@ -31,8 +37,18 @@ export function createTelemetryDetectionRuleListsTaskConfig(maxTelemetryBatch: n sender: ITelemetryEventsSender, taskExecutionPeriod: TaskExecutionPeriod ) => { + const usageCollector = sender.getTelemetryUsageCluster(); + + const usageLabelPrefix: string[] = ['security_telemetry', 'detection-rules']; + const startTime = Date.now(); const taskName = 'Security Solution Detection Rule Lists Telemetry'; + + tlog( + logger, + `Running task: ${taskId} [last: ${taskExecutionPeriod.last} - current: ${taskExecutionPeriod.current}]` + ); + try { const [clusterInfoPromise, licenseInfoPromise] = await Promise.allSettled([ receiver.fetchClusterInfo(), @@ -98,6 +114,13 @@ export function createTelemetryDetectionRuleListsTaskConfig(maxTelemetryBatch: n LIST_DETECTION_RULE_EXCEPTION ); tlog(logger, `Detection rule exception json length ${detectionRuleExceptionsJson.length}`); + + usageCollector?.incrementCounter({ + counterName: createUsageCounterLabel(usageLabelPrefix), + counterType: 'detection_rule_count', + incrementBy: detectionRuleExceptionsJson.length, + }); + const batches = batchTelemetryRecords(detectionRuleExceptionsJson, maxTelemetryBatch); for (const batch of batches) { await sender.sendOnDemand(TELEMETRY_CHANNEL_LISTS, batch); @@ -105,7 +128,7 @@ export function createTelemetryDetectionRuleListsTaskConfig(maxTelemetryBatch: n await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, true, startTime), ]); - return detectionRuleExceptions.length; + return detectionRuleExceptionsJson.length; } catch (err) { await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, false, startTime, err.message), diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts index a83326334c9d..223e732f946e 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.test.ts @@ -37,15 +37,10 @@ describe('diagnostics telemetry task test', () => { mockTelemetryEventsSender, testTaskExecutionPeriod ); - expect(mockTelemetryReceiver.fetchDiagnosticAlerts).toHaveBeenCalledWith( testTaskExecutionPeriod.last, testTaskExecutionPeriod.current ); - - expect(mockTelemetryEventsSender.queueTelemetryEvents).toHaveBeenCalledWith( - testDiagnosticsAlerts.hits.hits.flatMap((doc) => [doc._source]) - ); - expect(mockTelemetryEventsSender.sendOnDemand).toBeCalledTimes(1); + expect(mockTelemetryEventsSender.sendOnDemand).toBeCalledTimes(2); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts index 5c4604289eb5..290c5cfc44a6 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/diagnostic.ts @@ -11,7 +11,7 @@ import type { ITelemetryEventsSender } from '../sender'; import type { TelemetryEvent } from '../types'; import type { ITelemetryReceiver } from '../receiver'; import type { TaskExecutionPeriod } from '../task'; -import { TASK_METRICS_CHANNEL } from '../constants'; +import { TELEMETRY_CHANNEL_ENDPOINT_ALERTS, TASK_METRICS_CHANNEL } from '../constants'; export function createTelemetryDiagnosticsTaskConfig() { return { @@ -49,14 +49,15 @@ export function createTelemetryDiagnosticsTaskConfig() { return 0; } tlog(logger, `Received ${hits.length} diagnostic alerts`); - const diagAlerts: TelemetryEvent[] = hits.flatMap((h) => + const alerts: TelemetryEvent[] = hits.flatMap((h) => h._source != null ? [h._source] : [] ); - sender.queueTelemetryEvents(diagAlerts); + + await sender.sendOnDemand(TELEMETRY_CHANNEL_ENDPOINT_ALERTS, alerts); await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, true, startTime), ]); - return diagAlerts.length; + return alerts.length; } catch (err) { await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, false, startTime, err.message), diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts index e25b3690ee88..d237757616f3 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/index.ts @@ -12,6 +12,7 @@ import { createTelemetrySecurityListTaskConfig } from './security_lists'; import { createTelemetryDetectionRuleListsTaskConfig } from './detection_rule'; import { createTelemetryPrebuiltRuleAlertsTaskConfig } from './prebuilt_rule_alerts'; import { createTelemetryTimelineTaskConfig } from './timelines'; +import { createTelemetryDiagnosticTimelineTaskConfig } from './timelines_diagnostic'; import { createTelemetryConfigurationTaskConfig } from './configuration'; import { telemetryConfiguration } from '../configuration'; import { createTelemetryFilterListArtifactTaskConfig } from './filterlists'; @@ -26,6 +27,7 @@ export function createTelemetryTaskConfigs(): SecurityTelemetryTaskConfig[] { ), createTelemetryPrebuiltRuleAlertsTaskConfig(telemetryConfiguration.max_detection_alerts_batch), createTelemetryTimelineTaskConfig(), + createTelemetryDiagnosticTimelineTaskConfig(), createTelemetryConfigurationTaskConfig(), createTelemetryFilterListArtifactTaskConfig(), ]; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.test.ts index de5219a7f1fa..479ceabd65a3 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.test.ts @@ -42,11 +42,7 @@ describe('security telemetry - detection rule alerts task test', () => { testTaskExecutionPeriod ); expect(mockTelemetryReceiver.fetchDetectionRulesPackageVersion).toHaveBeenCalled(); - expect(mockTelemetryReceiver.fetchPrebuiltRuleAlerts).toHaveBeenCalled(); - expect(mockTelemetryEventsSender.getTelemetryUsageCluster).toHaveBeenCalled(); - expect(mockTelemetryEventsSender.getTelemetryUsageCluster()?.incrementCounter).toBeCalledTimes( - 1 - ); + expect(mockTelemetryReceiver.fetchPrebuiltRuleAlertsBatch).toHaveBeenCalled(); expect(mockTelemetryEventsSender.sendOnDemand).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.ts index 0fdc6cf32a69..0765d1d5bbda 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/prebuilt_rule_alerts.ts @@ -6,6 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; +import type { SortResults } from '@elastic/elasticsearch/lib/api/types'; import type { ITelemetryEventsSender } from '../sender'; import type { ITelemetryReceiver } from '../receiver'; import type { ESClusterInfo, ESLicense, TelemetryEvent } from '../types'; @@ -15,12 +16,14 @@ import { batchTelemetryRecords, createTaskMetric, processK8sUsernames, tlog } fr import { copyAllowlistedFields, filterList } from '../filterlists'; export function createTelemetryPrebuiltRuleAlertsTaskConfig(maxTelemetryBatch: number) { + const taskVersion = '1.2.0'; + return { type: 'security:telemetry-prebuilt-rule-alerts', title: 'Security Solution - Prebuilt Rule and Elastic ML Alerts Telemetry', interval: '1h', - timeout: '5m', - version: '1.0.0', + timeout: '15m', + version: taskVersion, runTask: async ( taskId: string, logger: Logger, @@ -47,53 +50,62 @@ export function createTelemetryPrebuiltRuleAlertsTaskConfig(maxTelemetryBatch: n : ({} as ESLicense | undefined); const packageInfo = packageVersion.status === 'fulfilled' ? packageVersion.value : undefined; + const index = receiver.getAlertsIndex(); - const { events: telemetryEvents, count: totalPrebuiltAlertCount } = - await receiver.fetchPrebuiltRuleAlerts(); - - sender.getTelemetryUsageCluster()?.incrementCounter({ - counterName: 'telemetry_prebuilt_rule_alerts', - counterType: 'prebuilt_alert_count', - incrementBy: totalPrebuiltAlertCount, - }); - - if (telemetryEvents.length === 0) { - tlog(logger, 'no prebuilt rule alerts retrieved'); - await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ - createTaskMetric(taskName, true, startTime), - ]); + if (index === undefined) { + tlog(logger, `alerts index is not ready yet, skipping telemetry task`); return 0; } - const processedAlerts = telemetryEvents.map( - (event: TelemetryEvent): TelemetryEvent => - copyAllowlistedFields(filterList.prebuiltRulesAlerts, event) - ); - - const sanitizedAlerts = processedAlerts.map( - (event: TelemetryEvent): TelemetryEvent => - processK8sUsernames(clusterInfo?.cluster_uuid, event) - ); - - const enrichedAlerts = sanitizedAlerts.map( - (event: TelemetryEvent): TelemetryEvent => ({ - ...event, - licence_id: licenseInfo?.uid, - cluster_uuid: clusterInfo?.cluster_uuid, - cluster_name: clusterInfo?.cluster_name, - package_version: packageInfo?.version, - }) - ); - - tlog(logger, `sending ${enrichedAlerts.length} elastic prebuilt alerts`); - const batches = batchTelemetryRecords(enrichedAlerts, maxTelemetryBatch); - for (const batch of batches) { - await sender.sendOnDemand(TELEMETRY_CHANNEL_DETECTION_ALERTS, batch); + let fetchMore = true; + let searchAfterValue: SortResults | undefined; + let pitId = await receiver.openPointInTime(index); + + while (fetchMore) { + const { moreToFetch, newPitId, searchAfter, alerts } = + await receiver.fetchPrebuiltRuleAlertsBatch(pitId, searchAfterValue); + + if (alerts.length === 0) { + return 0; + } + + fetchMore = moreToFetch; + searchAfterValue = searchAfter; + pitId = newPitId; + + const processedAlerts = alerts.map( + (event: TelemetryEvent): TelemetryEvent => + copyAllowlistedFields(filterList.prebuiltRulesAlerts, event) + ); + + const sanitizedAlerts = processedAlerts.map( + (event: TelemetryEvent): TelemetryEvent => + processK8sUsernames(clusterInfo?.cluster_uuid, event) + ); + + const enrichedAlerts = sanitizedAlerts.map( + (event: TelemetryEvent): TelemetryEvent => ({ + ...event, + licence_id: licenseInfo?.uid, + cluster_uuid: clusterInfo?.cluster_uuid, + cluster_name: clusterInfo?.cluster_name, + package_version: packageInfo?.version, + task_version: taskVersion, + }) + ); + + tlog(logger, `sending ${enrichedAlerts.length} elastic prebuilt alerts`); + const batches = batchTelemetryRecords(enrichedAlerts, maxTelemetryBatch); + + const promises = batches.map(async (batch) => { + sender.sendOnDemand(TELEMETRY_CHANNEL_DETECTION_ALERTS, batch); + }); + + await Promise.all(promises); } - await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ - createTaskMetric(taskName, true, startTime), - ]); - return enrichedAlerts.length; + + await receiver.closePointInTime(pitId); + return 0; } catch (err) { logger.error('could not complete prebuilt alerts telemetry task'); await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts index 04312e8843e2..863d66d55c4e 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/security_lists.ts @@ -6,10 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; -import { - ENDPOINT_LIST_ID, - ENDPOINT_EVENT_FILTERS_LIST_ID, -} from '@kbn/securitysolution-list-constants'; +import { ENDPOINT_LIST_ID, ENDPOINT_ARTIFACT_LISTS } from '@kbn/securitysolution-list-constants'; import { LIST_ENDPOINT_EXCEPTION, LIST_ENDPOINT_EVENT_FILTER, @@ -23,6 +20,8 @@ import { templateExceptionList, createTaskMetric, formatValueListMetaData, + createUsageCounterLabel, + tlog, } from '../helpers'; import type { ITelemetryEventsSender } from '../sender'; import type { ITelemetryReceiver } from '../receiver'; @@ -42,10 +41,16 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) sender: ITelemetryEventsSender, taskExecutionPeriod: TaskExecutionPeriod ) => { + const usageCollector = sender.getTelemetryUsageCluster(); + + const usageLabelPrefix: string[] = ['security_telemetry', 'lists']; + const startTime = Date.now(); const taskName = 'Security Solution Lists Telemetry'; try { - let count = 0; + let trustedApplicationsCount = 0; + let endpointExceptionsCount = 0; + let endpointEventFiltersCount = 0; const [clusterInfoPromise, licenseInfoPromise] = await Promise.allSettled([ receiver.fetchClusterInfo(), @@ -71,7 +76,14 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) licenseInfo, LIST_TRUSTED_APPLICATION ); - count += trustedAppsJson.length; + trustedApplicationsCount = trustedAppsJson.length; + tlog(logger, `Trusted Apps: ${trustedApplicationsCount}`); + + usageCollector?.incrementCounter({ + counterName: createUsageCounterLabel(usageLabelPrefix), + counterType: 'trusted_apps_count', + incrementBy: trustedApplicationsCount, + }); const batches = batchTelemetryRecords(trustedAppsJson, maxTelemetryBatch); for (const batch of batches) { @@ -89,7 +101,14 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) licenseInfo, LIST_ENDPOINT_EXCEPTION ); - count += epExceptionsJson.length; + endpointExceptionsCount = epExceptionsJson.length; + tlog(logger, `EP Exceptions: ${endpointExceptionsCount}`); + + usageCollector?.incrementCounter({ + counterName: createUsageCounterLabel(usageLabelPrefix), + counterType: 'endpoint_exceptions_count', + incrementBy: endpointExceptionsCount, + }); const batches = batchTelemetryRecords(epExceptionsJson, maxTelemetryBatch); for (const batch of batches) { @@ -99,7 +118,7 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) // Lists Telemetry: Endpoint Event Filters - const epFilters = await receiver.fetchEndpointList(ENDPOINT_EVENT_FILTERS_LIST_ID); + const epFilters = await receiver.fetchEndpointList(ENDPOINT_ARTIFACT_LISTS.eventFilters.id); if (epFilters?.data) { const epFiltersJson = templateExceptionList( epFilters.data, @@ -107,7 +126,14 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) licenseInfo, LIST_ENDPOINT_EVENT_FILTER ); - count += epFiltersJson.length; + endpointEventFiltersCount = epFiltersJson.length; + tlog(logger, `EP Event Filters: ${endpointEventFiltersCount}`); + + usageCollector?.incrementCounter({ + counterName: createUsageCounterLabel(usageLabelPrefix), + counterType: 'endpoint_event_filters_count', + incrementBy: endpointEventFiltersCount, + }); const batches = batchTelemetryRecords(epFiltersJson, maxTelemetryBatch); for (const batch of batches) { @@ -130,7 +156,7 @@ export function createTelemetrySecurityListTaskConfig(maxTelemetryBatch: number) await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, true, startTime), ]); - return count; + return trustedApplicationsCount + endpointExceptionsCount + endpointEventFiltersCount; } catch (err) { await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ createTaskMetric(taskName, false, startTime, err.message), diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/tasks.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/tasks.test.ts index f91de7fe5b19..75da7e5084ab 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/tasks.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/tasks.test.ts @@ -52,8 +52,8 @@ describe('security telemetry - ', () => { expect(taskConfig.interval).toEqual('24h'); }); - test('timelines task is set to 3h', async () => { + test('timelines task is set to 1h', async () => { const taskConfig = createTelemetryTimelineTaskConfig(); - expect(taskConfig.interval).toEqual('3h'); + expect(taskConfig.interval).toEqual('1h'); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.test.ts index 16794dfa3f68..930ef076edd3 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.test.ts @@ -35,7 +35,7 @@ describe('timeline telemetry task test', () => { expect(mockTelemetryReceiver.buildProcessTree).toHaveBeenCalled(); expect(mockTelemetryReceiver.fetchTimelineEvents).toHaveBeenCalled(); - expect(mockTelemetryReceiver.fetchTimelineEndpointAlerts).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineAlerts).toHaveBeenCalled(); expect(mockTelemetryEventsSender.getTelemetryUsageCluster).toHaveBeenCalled(); expect(mockTelemetryEventsSender.sendOnDemand).toHaveBeenCalled(); }); @@ -59,6 +59,6 @@ describe('timeline telemetry task test', () => { expect(mockTelemetryReceiver.buildProcessTree).toHaveBeenCalled(); expect(mockTelemetryReceiver.fetchTimelineEvents).toHaveBeenCalled(); - expect(mockTelemetryReceiver.fetchTimelineEndpointAlerts).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineAlerts).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.ts index bd50ffcd9281..7e0c41e57eec 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines.ts @@ -5,29 +5,22 @@ * 2.0. */ -import moment from 'moment'; import type { Logger } from '@kbn/core/server'; -import type { SafeEndpointEvent } from '../../../../common/endpoint/types'; import type { ITelemetryEventsSender } from '../sender'; import type { ITelemetryReceiver } from '../receiver'; import type { TaskExecutionPeriod } from '../task'; -import type { - ESClusterInfo, - ESLicense, - TimelineTelemetryTemplate, - TimelineTelemetryEvent, -} from '../types'; import { TELEMETRY_CHANNEL_TIMELINE, TASK_METRICS_CHANNEL } from '../constants'; -import { resolverEntity } from '../../../endpoint/routes/resolver/entity/utils/build_resolver_entity'; -import { tlog, createTaskMetric } from '../helpers'; +import { createTaskMetric, ranges, TelemetryTimelineFetcher, tlog } from '../helpers'; export function createTelemetryTimelineTaskConfig() { + const taskName = 'Security Solution Timeline telemetry'; + return { type: 'security:telemetry-timelines', - title: 'Security Solution Timeline telemetry', - interval: '3h', - timeout: '10m', - version: '1.0.0', + title: taskName, + interval: '1h', + timeout: '15m', + version: '1.0.1', runTask: async ( taskId: string, logger: Logger, @@ -35,142 +28,59 @@ export function createTelemetryTimelineTaskConfig() { sender: ITelemetryEventsSender, taskExecutionPeriod: TaskExecutionPeriod ) => { - const startTime = Date.now(); - const taskName = 'Security Solution Timeline telemetry'; - try { - let counter = 0; - - tlog(logger, `Running task: ${taskId}`); - - const [clusterInfoPromise, licenseInfoPromise] = await Promise.allSettled([ - receiver.fetchClusterInfo(), - receiver.fetchLicenseInfo(), - ]); - - const clusterInfo = - clusterInfoPromise.status === 'fulfilled' - ? clusterInfoPromise.value - : ({} as ESClusterInfo); - - const licenseInfo = - licenseInfoPromise.status === 'fulfilled' - ? licenseInfoPromise.value - : ({} as ESLicense | undefined); + tlog( + logger, + `Running task: ${taskId} [last: ${taskExecutionPeriod.last} - current: ${taskExecutionPeriod.current}]` + ); - const now = moment(); - const startOfDay = now.startOf('day').toISOString(); - const endOfDay = now.endOf('day').toISOString(); + const fetcher = new TelemetryTimelineFetcher(receiver); - const baseDocument = { - version: clusterInfo.version?.number, - cluster_name: clusterInfo.cluster_name, - cluster_uuid: clusterInfo.cluster_uuid, - license_uuid: licenseInfo?.uid, - }; - - // Fetch EP Alerts + try { + let counter = 0; - const endpointAlerts = await receiver.fetchTimelineEndpointAlerts(3); + const { rangeFrom, rangeTo } = ranges(taskExecutionPeriod); - // No EP Alerts -> Nothing to do - if (endpointAlerts.length === 0 || endpointAlerts.length === undefined) { - tlog(logger, 'no endpoint alerts received. exiting telemetry task.'); - await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ - createTaskMetric(taskName, true, startTime), - ]); - return counter; + const alertsIndex = receiver.getAlertsIndex(); + if (!alertsIndex) { + throw Error('alerts index is not ready yet, skipping telemetry task'); } + const alerts = await receiver.fetchTimelineAlerts(alertsIndex, rangeFrom, rangeTo); - // Build process tree for each EP Alert recieved - - for (const alert of endpointAlerts) { - const eventId = alert._source ? alert._source['event.id'] : 'unknown'; - const alertUUID = alert._source ? alert._source['kibana.alert.uuid'] : 'unknown'; + tlog(logger, `found ${alerts.length} alerts to process`); - const entities = resolverEntity([alert]); - - // Build Tree - - const tree = await receiver.buildProcessTree( - entities[0].id, - entities[0].schema, - startOfDay, - endOfDay - ); - - const nodeIds = [] as string[]; - if (Array.isArray(tree)) { - for (const node of tree) { - const nodeId = node?.id.toString(); - nodeIds.push(nodeId); - } - } + for (const alert of alerts) { + const result = await fetcher.fetchTimeline(alert); sender.getTelemetryUsageCluster()?.incrementCounter({ counterName: 'telemetry_timeline', counterType: 'timeline_node_count', - incrementBy: nodeIds.length, + incrementBy: result.nodes, }); - // Fetch event lineage - - const timelineEvents = await receiver.fetchTimelineEvents(nodeIds); - const eventsStore = new Map(); - for (const event of timelineEvents.hits.hits) { - const doc = event._source; - - if (doc !== null && doc !== undefined) { - const entityId = doc?.process?.entity_id?.toString(); - if (entityId !== null && entityId !== undefined) eventsStore.set(entityId, doc); - } - } - sender.getTelemetryUsageCluster()?.incrementCounter({ counterName: 'telemetry_timeline', counterType: 'timeline_event_count', - incrementBy: eventsStore.size, + incrementBy: result.events, }); - // Create telemetry record - - const telemetryTimeline: TimelineTelemetryEvent[] = []; - if (Array.isArray(tree)) { - for (const node of tree) { - const id = node.id.toString(); - const event = eventsStore.get(id); - - const timelineTelemetryEvent: TimelineTelemetryEvent = { - ...node, - event, - }; - - telemetryTimeline.push(timelineTelemetryEvent); - } - } - - if (telemetryTimeline.length >= 1) { - const record: TimelineTelemetryTemplate = { - '@timestamp': moment().toISOString(), - ...baseDocument, - alert_id: alertUUID, - event_id: eventId, - timeline: telemetryTimeline, - }; - - sender.sendOnDemand(TELEMETRY_CHANNEL_TIMELINE, [record]); + if (result.timeline) { + sender.sendOnDemand(TELEMETRY_CHANNEL_TIMELINE, [result.timeline]); counter += 1; } else { tlog(logger, 'no events in timeline'); } } - tlog(logger, `sent ${counter} timelines. concluding timeline task.`); + + tlog(logger, `sent ${counter} timelines. Concluding timeline task.`); + await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ - createTaskMetric(taskName, true, startTime), + createTaskMetric(taskName, true, fetcher.startTime), ]); + return counter; } catch (err) { await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ - createTaskMetric(taskName, false, startTime, err.message), + createTaskMetric(taskName, false, fetcher.startTime, err.message), ]); return 0; } diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.test.ts new file mode 100644 index 000000000000..887e0789e775 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { createTelemetryDiagnosticTimelineTaskConfig } from './timelines_diagnostic'; +import { createMockTelemetryEventsSender, createMockTelemetryReceiver } from '../__mocks__'; + +describe('timeline telemetry diagnostic task test', () => { + let logger: ReturnType; + + beforeEach(() => { + logger = loggingSystemMock.createLogger(); + }); + + test('timeline telemetry task should be correctly set up', async () => { + const testTaskExecutionPeriod = { + last: undefined, + current: new Date().toISOString(), + }; + const mockTelemetryEventsSender = createMockTelemetryEventsSender(); + const mockTelemetryReceiver = createMockTelemetryReceiver(); + const telemetryTelemetryDiagnosticTaskConfig = createTelemetryDiagnosticTimelineTaskConfig(); + + await telemetryTelemetryDiagnosticTaskConfig.runTask( + 'test-timeline-diagnostic-task-id', + logger, + mockTelemetryReceiver, + mockTelemetryEventsSender, + testTaskExecutionPeriod + ); + + expect(mockTelemetryReceiver.buildProcessTree).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineEvents).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineAlerts).toHaveBeenCalled(); + expect(mockTelemetryEventsSender.getTelemetryUsageCluster).toHaveBeenCalled(); + expect(mockTelemetryEventsSender.sendOnDemand).toHaveBeenCalled(); + }); + + test('if no timeline events received it should not send a telemetry record', async () => { + const testTaskExecutionPeriod = { + last: undefined, + current: new Date().toISOString(), + }; + const mockTelemetryEventsSender = createMockTelemetryEventsSender(); + const mockTelemetryReceiver = createMockTelemetryReceiver(null, true); + const telemetryTelemetryDiagnosticTaskConfig = createTelemetryDiagnosticTimelineTaskConfig(); + + await telemetryTelemetryDiagnosticTaskConfig.runTask( + 'test-timeline-diagnostic-task-id', + logger, + mockTelemetryReceiver, + mockTelemetryEventsSender, + testTaskExecutionPeriod + ); + + expect(mockTelemetryReceiver.buildProcessTree).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineEvents).toHaveBeenCalled(); + expect(mockTelemetryReceiver.fetchTimelineAlerts).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts new file mode 100644 index 000000000000..7148848984b0 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/timelines_diagnostic.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger } from '@kbn/core/server'; +import type { ITelemetryEventsSender } from '../sender'; +import type { ITelemetryReceiver } from '../receiver'; +import type { TaskExecutionPeriod } from '../task'; +import { + DEFAULT_DIAGNOSTIC_INDEX, + TELEMETRY_CHANNEL_TIMELINE, + TASK_METRICS_CHANNEL, +} from '../constants'; +import { createTaskMetric, ranges, TelemetryTimelineFetcher, tlog } from '../helpers'; + +export function createTelemetryDiagnosticTimelineTaskConfig() { + const taskName = 'Security Solution Diagnostic Timeline telemetry'; + + return { + type: 'security:telemetry-diagnostic-timelines', + title: taskName, + interval: '1h', + timeout: '15m', + version: '1.0.0', + runTask: async ( + taskId: string, + logger: Logger, + receiver: ITelemetryReceiver, + sender: ITelemetryEventsSender, + taskExecutionPeriod: TaskExecutionPeriod + ) => { + tlog( + logger, + `Running task: ${taskId} [last: ${taskExecutionPeriod.last} - current: ${taskExecutionPeriod.current}]` + ); + + const fetcher = new TelemetryTimelineFetcher(receiver); + + try { + let counter = 0; + + const { rangeFrom, rangeTo } = ranges(taskExecutionPeriod); + + const alerts = await receiver.fetchTimelineAlerts( + DEFAULT_DIAGNOSTIC_INDEX, + rangeFrom, + rangeTo + ); + + tlog(logger, `found ${alerts.length} alerts to process`); + + for (const alert of alerts) { + const result = await fetcher.fetchTimeline(alert); + + sender.getTelemetryUsageCluster()?.incrementCounter({ + counterName: 'telemetry_timeline_diagnostic', + counterType: 'timeline_diagnostic_node_count', + incrementBy: result.nodes, + }); + + sender.getTelemetryUsageCluster()?.incrementCounter({ + counterName: 'telemetry_timeline_diagnostic', + counterType: 'timeline_diagnostic_event_count', + incrementBy: result.events, + }); + + if (result.timeline) { + sender.sendOnDemand(TELEMETRY_CHANNEL_TIMELINE, [result.timeline]); + counter += 1; + } else { + tlog(logger, 'no events in timeline'); + } + } + + tlog(logger, `sent ${counter} timelines. Concluding timeline task.`); + + await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ + createTaskMetric(taskName, true, fetcher.startTime), + ]); + + return counter; + } catch (err) { + await sender.sendOnDemand(TASK_METRICS_CHANNEL, [ + createTaskMetric(taskName, false, fetcher.startTime, err.message), + ]); + return 0; + } + }, + }; +} diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts index df3b571714b2..433c1c01cf0b 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/types.ts @@ -457,3 +457,19 @@ export interface ValueListResponse { exceptionListMetricsResponse: ValueListExceptionListResponseAggregation; indicatorMatchMetricsResponse: ValueListIndicatorMatchResponseAggregation; } + +export interface ExtraInfo { + clusterInfo: ESClusterInfo; + licenseInfo: ESLicense | undefined; +} + +export interface TimeFrame { + startOfDay: string; + endOfDay: string; +} + +export interface TimelineResult { + nodes: number; + events: number; + timeline: TimelineTelemetryTemplate | undefined; +} diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts new file mode 100644 index 000000000000..33a0b6f09d3e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/index.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SetupPlugins } from '../../../plugin'; +import type { SecuritySolutionPluginRouter } from '../../../types'; +import type { ConfigType } from '../../..'; +import { + createTimelinesRoute, + deleteTimelinesRoute, + exportTimelinesRoute, + getTimelineRoute, + getTimelinesRoute, + importTimelinesRoute, + patchTimelinesRoute, + persistFavoriteRoute, + resolveTimelineRoute, + copyTimelineRoute, +} from './timelines'; +import { getDraftTimelinesRoute } from './draft_timelines/get_draft_timelines'; +import { cleanDraftTimelinesRoute } from './draft_timelines/clean_draft_timelines'; +import { installPrepackedTimelinesRoute } from './prepackaged_timelines/install_prepackaged_timelines'; + +import { persistNoteRoute, deleteNoteRoute } from './notes'; + +import { persistPinnedEventRoute } from './pinned_events'; + +export function registerTimelineRoutes( + router: SecuritySolutionPluginRouter, + config: ConfigType, + security: SetupPlugins['security'] +) { + createTimelinesRoute(router, config, security); + patchTimelinesRoute(router, config, security); + + importTimelinesRoute(router, config, security); + exportTimelinesRoute(router, config, security); + getDraftTimelinesRoute(router, config, security); + getTimelineRoute(router, config, security); + resolveTimelineRoute(router, config, security); + getTimelinesRoute(router, config, security); + cleanDraftTimelinesRoute(router, config, security); + deleteTimelinesRoute(router, config, security); + persistFavoriteRoute(router, config, security); + copyTimelineRoute(router, config, security); + + installPrepackedTimelinesRoute(router, config, security); + + persistNoteRoute(router, config, security); + deleteNoteRoute(router, config, security); + persistPinnedEventRoute(router, config, security); +} diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts new file mode 100644 index 000000000000..3a55b4fef808 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/copy_timeline/index.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithExcess } from '../../../../../utils/build_validation/route_validation'; +import type { ConfigType } from '../../../../..'; +import { copyTimelineSchema } from '../../../../../../common/api/timeline'; +import { copyTimeline } from '../../../saved_object/timelines'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import type { SetupPlugins } from '../../../../../plugin'; +import { TIMELINE_COPY_URL } from '../../../../../../common/constants'; +import { buildSiemResponse } from '../../../../detection_engine/routes/utils'; + +import { buildFrameworkRequest } from '../../../utils/common'; + +export const copyTimelineRoute = async ( + router: SecuritySolutionPluginRouter, + _: ConfigType, + security: SetupPlugins['security'] +) => { + router.versioned + .post({ + path: TIMELINE_COPY_URL, + options: { + tags: ['access:securitySolution'], + }, + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { body: buildRouteValidationWithExcess(copyTimelineSchema) }, + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + + try { + const frameworkRequest = await buildFrameworkRequest(context, security, request); + const { timeline, timelineIdToCopy } = request.body; + const copiedTimeline = await copyTimeline(frameworkRequest, timeline, timelineIdToCopy); + + return response.ok({ + body: { data: { persistTimeline: copiedTimeline } }, + }); + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/index.ts index ba20633a6514..1f26af72a22e 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/index.ts @@ -13,3 +13,4 @@ export { importTimelinesRoute } from './import_timelines'; export { patchTimelinesRoute } from './patch_timelines'; export { persistFavoriteRoute } from './persist_favorite'; export { resolveTimelineRoute } from './resolve_timeline'; +export { copyTimelineRoute } from './copy_timeline'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.test.ts index 527c46598e92..1fbc51871447 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import type { Note } from '../../../../../common/api/timeline'; import { pickSavedNote } from './saved_object'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts index 7169938e335d..8527b0970f4f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts @@ -14,7 +14,7 @@ import { map, fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import type { SavedObjectsFindOptions } from '@kbn/core/server'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { getUserDisplayName } from '@kbn/user-profile-components'; import { UNAUTHENTICATED_USER } from '../../../../../common/constants'; import type { diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts index 6dad7e61f0b2..96f2aa3d1c26 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/pinned_events/index.ts @@ -12,7 +12,7 @@ import { map, fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import type { SavedObjectsFindOptions } from '@kbn/core/server'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { UNAUTHENTICATED_USER } from '../../../../../common/constants'; import type { BarePinnedEvent, diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts index 67ff65217616..9cefecda1ed2 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.test.ts @@ -7,6 +7,7 @@ import type { FrameworkRequest } from '../../../framework'; import { mockGetTimelineValue, mockSavedObject } from '../../__mocks__/import_timelines'; +import { mockTimeline } from '../../__mocks__/create_timelines'; import { convertStringToBase64, @@ -15,10 +16,11 @@ import { getDraftTimeline, resolveTimelineOrNull, updatePartialSavedTimeline, + copyTimeline, } from '.'; import { convertSavedObjectToSavedTimeline } from './convert_saved_object_to_savedtimeline'; -import { getNotesByTimelineId } from '../notes/saved_object'; -import { getAllPinnedEventsByTimelineId } from '../pinned_events'; +import { getNotesByTimelineId, persistNote } from '../notes/saved_object'; +import { getAllPinnedEventsByTimelineId, persistPinnedEventOnTimeline } from '../pinned_events'; import { TimelineType } from '../../../../../common/api/timeline'; import type { AllTimelinesResponse, @@ -40,10 +42,12 @@ jest.mock('./convert_saved_object_to_savedtimeline', () => ({ jest.mock('../notes/saved_object', () => ({ getNotesByTimelineId: jest.fn().mockResolvedValue([]), + persistNote: jest.fn(), })); jest.mock('../pinned_events', () => ({ getAllPinnedEventsByTimelineId: jest.fn().mockResolvedValue([]), + persistPinnedEventOnTimeline: jest.fn(), })); describe('saved_object', () => { @@ -462,4 +466,95 @@ describe('saved_object', () => { }); }); }); + + describe('Copy timeline', () => { + let mockFindSavedObject: jest.Mock; + let mockRequest: FrameworkRequest; + let createSavedObject: jest.Mock; + + beforeEach(() => { + mockFindSavedObject = jest.fn().mockResolvedValue({ saved_objects: [], total: 0 }); + createSavedObject = jest.fn().mockResolvedValue({ + id: '1', + version: '2323r23', + attributes: { + ...mockGetTimelineValue, + kqlQuery: null, + }, + }); + mockRequest = { + user: { + username: 'username', + }, + context: { + core: { + savedObjects: { + client: { + find: mockFindSavedObject, + create: createSavedObject, + get: jest.fn(async () => ({ + ...mockResolvedSavedObject.saved_object, + })), + }, + }, + }, + }, + } as unknown as FrameworkRequest; + }); + + afterEach(() => { + mockFindSavedObject.mockClear(); + (getNotesByTimelineId as jest.Mock).mockClear(); + (persistNote as jest.Mock).mockClear(); + (getAllPinnedEventsByTimelineId as jest.Mock).mockClear(); + }); + + it('should resolve all associated saved objects and copy those', async () => { + const note = { + notedId: 'theNoteId', + timelineId: 'original_id', + version: '23d23f', + note: 'test note', + }; + (getNotesByTimelineId as jest.Mock).mockResolvedValue([note]); + const pinnedEvent = { + timelineId: 'original_id', + eventId: 'randomEventId', + }; + (getAllPinnedEventsByTimelineId as jest.Mock).mockResolvedValue([pinnedEvent]); + + const originalId = 'original_id'; + const res = await copyTimeline( + mockRequest, + mockTimeline as unknown as SavedTimeline, + originalId + ); + + // Resolves objects by the correct timeline id + expect(getNotesByTimelineId).toHaveBeenCalledWith(mockRequest, originalId); + expect(getAllPinnedEventsByTimelineId).toHaveBeenCalledWith(mockRequest, originalId); + + // Notes are created with the new timeline id and a copy of the original node + expect(persistNote).toHaveBeenCalledWith( + expect.objectContaining({ + noteId: null, + note: expect.objectContaining({ + ...note, + timelineId: mockResolvedTimeline.savedObjectId, + }), + overrideOwner: false, + }) + ); + + // Pinned events are created with the new timeline id and the correct event id + expect(persistPinnedEventOnTimeline).toHaveBeenCalledWith( + mockRequest, + null, + pinnedEvent.eventId, + mockResolvedTimeline.savedObjectId + ); + + expect(res.timeline.savedObjectId).toBe(mockResolvedTimeline.savedObjectId); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts index e966a2d9f9f3..9cdc9189b16f 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/index.ts @@ -586,6 +586,63 @@ export const deleteTimeline = async (request: FrameworkRequest, timelineIds: str ); }; +export const copyTimeline = async ( + request: FrameworkRequest, + timeline: SavedTimeline, + timelineId: string +): Promise => { + const savedObjectsClient = (await request.context.core).savedObjects.client; + + // Fetch all objects that need to be copied + const [notes, pinnedEvents] = await Promise.all([ + note.getNotesByTimelineId(request, timelineId), + pinnedEvent.getAllPinnedEventsByTimelineId(request, timelineId), + ]); + + const isImmutable = timeline.status === TimelineStatus.immutable; + const userInfo = isImmutable ? ({ username: 'Elastic' } as AuthenticatedUser) : request.user; + + const timelineResponse = await createTimeline({ + savedObjectsClient, + timeline, + timelineId: null, + userInfo, + }); + + const newTimelineId = timelineResponse.timeline.savedObjectId; + + const copiedNotes = Promise.all( + notes.map((_note) => { + return note.persistNote({ + request, + noteId: null, + note: { + ..._note, + timelineId: newTimelineId, + }, + overrideOwner: false, + }); + }) + ); + + const copiedPinnedEvents = pinnedEvents.map((_pinnedEvent) => { + return pinnedEvent.persistPinnedEventOnTimeline( + request, + null, + _pinnedEvent.eventId, + newTimelineId + ); + }); + + await Promise.all([copiedNotes, copiedPinnedEvents]); + + return { + code: 200, + message: 'success', + timeline: await getSavedTimeline(request, newTimelineId), + }; +}; + const resolveBasicSavedTimeline = async (request: FrameworkRequest, timelineId: string) => { const savedObjectsClient = (await request.context.core).savedObjects.client; const { saved_object: savedObject, ...resolveAttributes } = diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.test.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.test.ts index 98bc33fee375..db32de9dc65c 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.test.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import type { SavedTimeline, Note } from '../../../../../common/api/timeline'; import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline'; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts index bc0c9075887b..90467a456824 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/saved_object/timelines/pick_saved_timeline.ts @@ -6,7 +6,7 @@ */ import { isEmpty } from 'lodash/fp'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; +import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { getUserDisplayName } from '@kbn/user-profile-components'; import { UNAUTHENTICATED_USER } from '../../../../../common/constants'; import type { SavedTimelineWithSavedObjectId } from '../../../../../common/api/timeline'; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 66f22e0c44be..ec01a2800dff 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -107,7 +107,7 @@ import { } from '../common/endpoint/constants'; import { AppFeaturesService } from './lib/app_features_service/app_features_service'; -import { registerRiskScoringTask } from './lib/entity_analytics/risk_engine/tasks/risk_scoring_task'; +import { registerRiskScoringTask } from './lib/entity_analytics/risk_score/tasks/risk_scoring_task'; import { registerProtectionUpdatesNoteRoutes } from './endpoint/routes/protection_updates_note'; import { latestRiskScoreIndexPattern, allRiskScoreIndexPattern } from '../common/risk_engine'; import { isEndpointPackageV2 } from '../common/endpoint/utils/package_v2'; @@ -170,7 +170,7 @@ export class Plugin implements ISecuritySolutionPlugin { const experimentalFeatures = config.experimentalFeatures; initSavedObjects(core.savedObjects); - initUiSettings(core.uiSettings, experimentalFeatures); + initUiSettings(core.uiSettings, experimentalFeatures, config.enableUiSettingsValidations); appFeaturesService.init(plugins.features); events.forEach((eventConfig) => core.analytics.registerEventType(eventConfig)); diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index fde473d2a253..3deaaa103caa 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -26,6 +26,8 @@ import type { Immutable } from '../common/endpoint/types'; import type { EndpointAuthz } from '../common/endpoint/types/authz'; import type { EndpointAppContextService } from './endpoint/endpoint_app_context_services'; import { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client'; +import { RiskScoreDataClient } from './lib/entity_analytics/risk_score/risk_score_data_client'; +import { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality/asset_criticality_data_client'; export interface IRequestContextFactory { create( @@ -141,6 +143,24 @@ export class RequestContextFactory implements IRequestContextFactory { namespace: getSpaceId(), }) ), + getRiskScoreDataClient: memoize( + () => + new RiskScoreDataClient({ + logger: options.logger, + kibanaVersion: options.kibanaVersion, + esClient: coreContext.elasticsearch.client.asCurrentUser, + soClient: coreContext.savedObjects.client, + namespace: getSpaceId(), + }) + ), + getAssetCriticalityDataClient: memoize( + () => + new AssetCriticalityDataClient({ + logger: options.logger, + esClient: coreContext.elasticsearch.client.asCurrentUser, + namespace: getSpaceId(), + }) + ), }; } } diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index b5b6a5c205e9..afe48a8d8856 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -29,28 +29,10 @@ import { querySignalsRoute } from '../lib/detection_engine/routes/signals/query_ import { setSignalsStatusRoute } from '../lib/detection_engine/routes/signals/open_close_signals_route'; import { deleteIndexRoute } from '../lib/detection_engine/routes/index/delete_index_route'; import { readPrivilegesRoute } from '../lib/detection_engine/routes/privileges/read_privileges_route'; -import { - createTimelinesRoute, - deleteTimelinesRoute, - exportTimelinesRoute, - getTimelineRoute, - getTimelinesRoute, - importTimelinesRoute, - patchTimelinesRoute, - persistFavoriteRoute, - resolveTimelineRoute, -} from '../lib/timeline/routes/timelines'; -import { getDraftTimelinesRoute } from '../lib/timeline/routes/draft_timelines/get_draft_timelines'; -import { cleanDraftTimelinesRoute } from '../lib/timeline/routes/draft_timelines/clean_draft_timelines'; - -import { persistNoteRoute, deleteNoteRoute } from '../lib/timeline/routes/notes'; - -import { persistPinnedEventRoute } from '../lib/timeline/routes/pinned_events'; import type { SetupPlugins, StartPlugins } from '../plugin'; import type { ConfigType } from '../config'; import type { ITelemetryEventsSender } from '../lib/telemetry/sender'; -import { installPrepackedTimelinesRoute } from '../lib/timeline/routes/prepackaged_timelines/install_prepackaged_timelines'; import type { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps, @@ -74,14 +56,24 @@ import { registerManageExceptionsRoutes } from '../lib/exceptions/api/register_r import { registerDashboardsRoutes } from '../lib/dashboards/routes'; import { registerTagsRoutes } from '../lib/tags/routes'; import { setAlertTagsRoute } from '../lib/detection_engine/routes/signals/set_alert_tags_route'; +import { setAlertAssigneesRoute } from '../lib/detection_engine/routes/signals/set_alert_assignees_route'; +import { suggestUserProfilesRoute } from '../lib/detection_engine/routes/users/suggest_user_profiles_route'; import { - riskScorePreviewRoute, riskEngineDisableRoute, riskEngineInitRoute, riskEngineEnableRoute, riskEngineStatusRoute, + riskEnginePrivilegesRoute, } from '../lib/entity_analytics/risk_engine/routes'; -import { riskScoreCalculationRoute } from '../lib/entity_analytics/risk_engine/routes/risk_score_calculation_route'; +import { registerTimelineRoutes } from '../lib/timeline/routes'; +import { riskScoreCalculationRoute } from '../lib/entity_analytics/risk_score/routes/calculation'; +import { riskScorePreviewRoute } from '../lib/entity_analytics/risk_score/routes/preview'; +import { + assetCriticalityStatusRoute, + assetCriticalityUpsertRoute, + assetCriticalityGetRoute, + assetCriticalityDeleteRoute, +} from '../lib/entity_analytics/asset_criticality/routes'; export const initRoutes = ( router: SecuritySolutionPluginRouter, @@ -120,35 +112,20 @@ export const initRoutes = ( registerResolverRoutes(router, getStartServices, config); - createTimelinesRoute(router, config, security); - patchTimelinesRoute(router, config, security); - - importTimelinesRoute(router, config, security); - exportTimelinesRoute(router, config, security); - getDraftTimelinesRoute(router, config, security); - getTimelineRoute(router, config, security); - resolveTimelineRoute(router, config, security); - getTimelinesRoute(router, config, security); - cleanDraftTimelinesRoute(router, config, security); - deleteTimelinesRoute(router, config, security); - persistFavoriteRoute(router, config, security); - - installPrepackedTimelinesRoute(router, config, security); - - persistNoteRoute(router, config, security); - deleteNoteRoute(router, config, security); - persistPinnedEventRoute(router, config, security); + registerTimelineRoutes(router, config, security); // Detection Engine Signals routes that have the REST endpoints of /api/detection_engine/signals // POST /api/detection_engine/signals/status // Example usage can be found in security_solution/server/lib/detection_engine/scripts/signals setSignalsStatusRoute(router, logger, security, telemetrySender); setAlertTagsRoute(router); + setAlertAssigneesRoute(router); querySignalsRoute(router, ruleDataClient); getSignalsMigrationStatusRoute(router); createSignalsMigrationRoute(router, security); finalizeSignalsMigrationRoute(router, ruleDataService, security); deleteSignalsMigrationRoute(router, security); + suggestUserProfilesRoute(router, getStartServices); // Detection Engine index routes that have the REST endpoints of /api/detection_engine/index // All REST index creation, policy management for spaces @@ -187,5 +164,14 @@ export const initRoutes = ( riskEngineInitRoute(router, getStartServices); riskEngineEnableRoute(router, getStartServices); riskEngineDisableRoute(router, getStartServices); + if (config.experimentalFeatures.riskEnginePrivilegesRouteEnabled) { + riskEnginePrivilegesRoute(router, getStartServices); + } + } + if (config.experimentalFeatures.entityAnalyticsAssetCriticalityEnabled) { + assetCriticalityStatusRoute(router, logger); + assetCriticalityUpsertRoute(router, logger); + assetCriticalityGetRoute(router, logger); + assetCriticalityDeleteRoute(router, logger); } }; diff --git a/x-pack/plugins/security_solution/server/types.ts b/x-pack/plugins/security_solution/server/types.ts index c979cc25c172..a44572ae07ea 100644 --- a/x-pack/plugins/security_solution/server/types.ts +++ b/x-pack/plugins/security_solution/server/types.ts @@ -30,7 +30,8 @@ import type { FrameworkRequest } from './lib/framework'; import type { EndpointAuthz } from '../common/endpoint/types/authz'; import type { EndpointInternalFleetServicesInterface } from './endpoint/services/fleet'; import type { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client'; - +import type { RiskScoreDataClient } from './lib/entity_analytics/risk_score/risk_score_data_client'; +import type { AssetCriticalityDataClient } from './lib/entity_analytics/asset_criticality/asset_criticality_data_client'; export { AppClient }; export interface SecuritySolutionApiRequestHandlerContext { @@ -48,6 +49,8 @@ export interface SecuritySolutionApiRequestHandlerContext { getExceptionListClient: () => ExceptionListClient | null; getInternalFleetServices: () => EndpointInternalFleetServicesInterface; getRiskEngineDataClient: () => RiskEngineDataClient; + getRiskScoreDataClient: () => RiskScoreDataClient; + getAssetCriticalityDataClient: () => AssetCriticalityDataClient; } export type SecuritySolutionRequestHandlerContext = CustomRequestHandlerContext<{ diff --git a/x-pack/plugins/security_solution/server/ui_settings.ts b/x-pack/plugins/security_solution/server/ui_settings.ts index 6a41844e9e03..ac610c14d7f8 100644 --- a/x-pack/plugins/security_solution/server/ui_settings.ts +++ b/x-pack/plugins/security_solution/server/ui_settings.ts @@ -37,6 +37,7 @@ import { DEFAULT_ALERT_TAGS_KEY, DEFAULT_ALERT_TAGS_VALUE, ENABLE_EXPANDABLE_FLYOUT_SETTING, + EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER, } from '../common/constants'; import type { ExperimentalFeatures } from '../common/experimental_features'; import { LogLevelSetting } from '../common/api/detection_engine/rule_monitoring'; @@ -57,7 +58,8 @@ const orderSettings = (settings: SettingsConfig): SettingsConfig => { export const initUiSettings = ( uiSettings: CoreSetup['uiSettings'], - experimentalFeatures: ExperimentalFeatures + experimentalFeatures: ExperimentalFeatures, + validationsEnabled: boolean ) => { const securityUiSettings: Record> = { [DEFAULT_APP_REFRESH_INTERVAL]: { @@ -115,7 +117,9 @@ export const initUiSettings = ( }), category: [APP_ID], requiresPageReload: true, - schema: schema.arrayOf(schema.string()), + schema: validationsEnabled + ? schema.arrayOf(schema.string(), { maxSize: 50 }) + : schema.arrayOf(schema.string()), }, [DEFAULT_THREAT_INDEX_KEY]: { name: i18n.translate('xpack.securitySolution.uiSettings.defaultThreatIndexLabel', { @@ -132,7 +136,9 @@ export const initUiSettings = ( ), category: [APP_ID], requiresPageReload: true, - schema: schema.arrayOf(schema.string()), + schema: validationsEnabled + ? schema.arrayOf(schema.string(), { maxSize: 10 }) + : schema.arrayOf(schema.string()), }, [DEFAULT_ANOMALY_SCORE]: { name: i18n.translate('xpack.securitySolution.uiSettings.defaultAnomalyScoreLabel', { @@ -149,7 +155,7 @@ export const initUiSettings = ( ), category: [APP_ID], requiresPageReload: true, - schema: schema.number(), + schema: validationsEnabled ? schema.number({ max: 100, min: 0 }) : schema.number(), }, [ENABLE_NEWS_FEED_SETTING]: { name: i18n.translate('xpack.securitySolution.uiSettings.enableNewsFeedLabel', { @@ -180,6 +186,26 @@ export const initUiSettings = ( requiresPageReload: true, schema: schema.boolean(), }, + [EXCLUDE_COLD_AND_FROZEN_TIERS_IN_ANALYZER]: { + name: i18n.translate( + 'xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzer', + { + defaultMessage: 'Exclude cold and frozen tiers in Analyzer', + } + ), + value: false, + description: i18n.translate( + 'xpack.securitySolution.uiSettings.excludeColdAndFrozenTiersInAnalyzerDescription', + { + defaultMessage: + '

    When enabled, cold and frozen tiers will be skipped in analyzer queries

    ', + } + ), + type: 'boolean', + category: [APP_ID], + requiresPageReload: true, + schema: schema.boolean(), + }, [DEFAULT_RULES_TABLE_REFRESH_SETTING]: { name: i18n.translate('xpack.securitySolution.uiSettings.rulesTableRefresh', { defaultMessage: 'Rules auto refresh', diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 4d2b16e355c6..517e827aaf17 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -15,7 +15,11 @@ "public/**/*.json", "../../../typings/**/*" ], - "exclude": ["target/**/*", "**/cypress/**", "public/management/cypress.config.ts"], + "exclude": [ + "target/**/*", + "**/cypress/**", + "public/management/cypress.config.ts" + ], "kbn_references": [ "@kbn/core", { @@ -149,7 +153,6 @@ "@kbn/analytics-client", "@kbn/security-solution-side-nav", "@kbn/ecs", - "@kbn/url-state", "@kbn/ml-anomaly-utils", "@kbn/discover-plugin", "@kbn/field-formats-plugin", @@ -170,14 +173,15 @@ "@kbn/security-solution-features", "@kbn/content-management-plugin", "@kbn/discover-utils", - "@kbn/subscription-tracking", "@kbn/core-application-common", "@kbn/openapi-generator", + "@kbn/openapi-bundler", "@kbn/es", "@kbn/react-kibana-mount", + "@kbn/react-kibana-context-styled", "@kbn/unified-doc-viewer-plugin", "@kbn/shared-ux-error-boundary", "@kbn/zod-helpers", - "@kbn/core-http-common", + "@kbn/core-http-common" ] } diff --git a/x-pack/plugins/security_solution_ess/public/plugin.ts b/x-pack/plugins/security_solution_ess/public/plugin.ts index 7857c0ffa553..68b902a95dc8 100644 --- a/x-pack/plugins/security_solution_ess/public/plugin.ts +++ b/x-pack/plugins/security_solution_ess/public/plugin.ts @@ -45,7 +45,7 @@ export class SecuritySolutionEssPlugin }); securitySolution.setComponents({ - getStarted: getSecurityGetStartedComponent(services), + GetStarted: getSecurityGetStartedComponent(services), }); subscribeBreadcrumbs(services); diff --git a/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx b/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx index 05af48c28039..41cd10e5e360 100644 --- a/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx +++ b/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx @@ -16,7 +16,10 @@ import type { } from '@kbn/security-solution-upselling/service'; import type { ILicense, LicenseType } from '@kbn/licensing-plugin/public'; import React, { lazy } from 'react'; -import { UPGRADE_INVESTIGATION_GUIDE } from '@kbn/security-solution-upselling/messages'; +import { + UPGRADE_ALERT_ASSIGNMENTS, + UPGRADE_INVESTIGATION_GUIDE, +} from '@kbn/security-solution-upselling/messages'; import type { Services } from '../common/services'; import { withServicesProvider } from '../common/services'; const EntityAnalyticsUpsellingLazy = lazy( @@ -107,4 +110,9 @@ export const upsellingMessages: UpsellingMessages = [ minimumLicenseRequired: 'platinum', message: UPGRADE_INVESTIGATION_GUIDE('Platinum'), }, + { + id: 'alert_assignments', + minimumLicenseRequired: 'platinum', + message: UPGRADE_ALERT_ASSIGNMENTS('Platinum'), + }, ]; diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.test.ts b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.test.ts index 5b3502225e76..74979b0549b9 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.test.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.test.ts @@ -119,7 +119,7 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLink1.id, title: link1.title, - path: [chromeNavLink1.id], + path: chromeNavLink1.id, deepLink: chromeNavLink1, }, ]); @@ -132,7 +132,7 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLink3.id, title: chromeNavLink3.title, - path: [chromeNavLink3.id], + path: chromeNavLink3.id, deepLink: chromeNavLink3, }, ]); @@ -145,13 +145,13 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLink1.id, title: link1.title, - path: [chromeNavLink1.id], + path: chromeNavLink1.id, deepLink: chromeNavLink1, children: [ { id: chromeNavLink2.id, title: link2.title, - path: [chromeNavLink1.id, chromeNavLink2.id], + path: [chromeNavLink1.id, chromeNavLink2.id].join('.'), deepLink: chromeNavLink2, }, ], @@ -173,24 +173,24 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLinkTest.id, title: link1.title, - path: [chromeNavLinkTest.id], + path: chromeNavLinkTest.id, deepLink: chromeNavLinkTest, children: [ { id: chromeNavLinkMl1.id, title: chromeNavLinkMl1.title, - path: [chromeNavLinkTest.id, chromeNavLinkMl1.id], + path: [chromeNavLinkTest.id, chromeNavLinkMl1.id].join('.'), deepLink: chromeNavLinkMl1, }, { id: defaultNavCategory1.id, title: defaultNavCategory1.title, - path: [chromeNavLinkTest.id, defaultNavCategory1.id], + path: [chromeNavLinkTest.id, defaultNavCategory1.id].join('.'), children: [ { id: chromeNavLinkMl2.id, title: 'Overridden ML SubLink 2', - path: [chromeNavLinkTest.id, defaultNavCategory1.id, chromeNavLinkMl2.id], + path: [chromeNavLinkTest.id, defaultNavCategory1.id, chromeNavLinkMl2.id].join('.'), deepLink: chromeNavLinkMl2, }, ], @@ -208,7 +208,7 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLink2.id, title: link2.title, - path: [chromeNavLink2.id], + path: chromeNavLink2.id, deepLink: chromeNavLink2, }, ]); @@ -230,14 +230,14 @@ describe('formatChromeProjectNavNodes', () => { { id: chromeNavLinkTest.id, title: link1.title, - path: [chromeNavLinkTest.id], + path: chromeNavLinkTest.id, deepLink: chromeNavLinkTest, breadcrumbStatus: 'hidden', }, { id: chromeNavLink2.id, title: link2.title, - path: [chromeNavLink2.id], + path: chromeNavLink2.id, deepLink: chromeNavLink2, }, ]); diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.ts b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.ts index 0dc8a1140aaa..b787aeb92736 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/chrome_navigation_tree.ts @@ -19,7 +19,7 @@ import { isBreadcrumbHidden } from './utils'; export const getFormatChromeProjectNavNodes = (services: Services) => { const formatChromeProjectNavNodes = ( projectNavLinks: ProjectNavigationLink[], - path: string[] = [] + path?: string ): ChromeProjectNavigationNode[] => { const { chrome } = services; @@ -31,7 +31,7 @@ export const getFormatChromeProjectNavNodes = (services: Services) => { const link: ChromeProjectNavigationNode = { id: navLinkId, title, - path: [...path, navLinkId], + path: path ? [path, navLinkId].join('.') : navLinkId, deepLink: chrome.navLinks.get(navLinkId), ...(isBreadcrumbHidden(id) && { breadcrumbStatus: 'hidden' }), }; @@ -63,7 +63,7 @@ export const getFormatChromeProjectNavNodes = (services: Services) => { const processDefaultNav = ( children: NodeDefinition[], - path: string[] + path: string ): ChromeProjectNavigationNode[] => { const { chrome } = services; return children.reduce((navNodes, node) => { @@ -80,7 +80,7 @@ export const getFormatChromeProjectNavNodes = (services: Services) => { const navNode: ChromeProjectNavigationNode = { id, title: node.title || '', - path: [...path, id], + path: [path, id].join('.'), breadcrumbStatus: node.breadcrumbStatus, getIsActive: node.getIsActive, }; diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/project_navigation/project_navigation.tsx b/x-pack/plugins/security_solution_serverless/public/navigation/project_navigation/project_navigation.tsx index b26700eb8e4b..2532589d1c99 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/project_navigation/project_navigation.tsx +++ b/x-pack/plugins/security_solution_serverless/public/navigation/project_navigation/project_navigation.tsx @@ -13,7 +13,7 @@ import type { import { SolutionSideNavPanelContent } from '@kbn/security-solution-side-nav/panel'; import useObservable from 'react-use/lib/useObservable'; import { useKibana } from '../../common/services'; -import type { ProjectNavigationLink, ProjectPageName } from '../links/types'; +import type { ProjectNavigationLink } from '../links/types'; import { useFormattedSideNavItems } from '../side_navigation/use_side_nav_items'; import { CATEGORIES, FOOTER_CATEGORIES } from '../categories'; import { formatNavigationTree } from '../navigation_tree/navigation_tree'; @@ -21,8 +21,7 @@ import { formatNavigationTree } from '../navigation_tree/navigation_tree'; const getPanelContentProvider = ( projectNavLinks: ProjectNavigationLink[] ): React.FC => - React.memo(function PanelContentProvider({ selectedNode: { path }, closePanel }) { - const linkId = path[path.length - 1] as ProjectPageName; + React.memo(function PanelContentProvider({ selectedNode: { id: linkId }, closePanel }) { const currentPanelItem = projectNavLinks.find((item) => item.id === linkId); const { title = '', links = [], categories } = currentPanelItem ?? {}; diff --git a/x-pack/plugins/security_solution_serverless/public/plugin.ts b/x-pack/plugins/security_solution_serverless/public/plugin.ts index e7e58c42bcaa..77fcbc19d6e2 100644 --- a/x-pack/plugins/security_solution_serverless/public/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/public/plugin.ts @@ -69,8 +69,8 @@ export class SecuritySolutionServerlessPlugin registerUpsellings(securitySolution.getUpselling(), productTypes, services); securitySolution.setComponents({ - getStarted: getSecurityGetStartedComponent(services, productTypes), - dashboardsLandingCallout: getDashboardsLandingCallout(services), + GetStarted: getSecurityGetStartedComponent(services, productTypes), + DashboardsLandingCallout: getDashboardsLandingCallout(services), }); startNavigation(services); diff --git a/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task.ts b/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task.ts index 1a9501424ba0..0dde94b40987 100644 --- a/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task.ts +++ b/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task.ts @@ -205,14 +205,17 @@ const indexHasDataInDateRange = async ( cloudSecuritySolution: CloudSecuritySolutions, searchFrom: Date ) => { - const response = await esClient.search({ - index: METERING_CONFIGS[cloudSecuritySolution].index, - size: 1, - _source: false, - query: getSearchQueryByCloudSecuritySolution(cloudSecuritySolution, searchFrom), - }); + const response = await esClient.search( + { + index: METERING_CONFIGS[cloudSecuritySolution].index, + size: 1, + _source: false, + query: getSearchQueryByCloudSecuritySolution(cloudSecuritySolution, searchFrom), + }, + { ignore: [404] } + ); - return response.hits.hits.length > 0; + return response.hits?.hits.length > 0; }; const getSearchStartDate = (lastSuccessfulReport: Date): Date => { diff --git a/x-pack/plugins/serverless_search/common/doc_links.ts b/x-pack/plugins/serverless_search/common/doc_links.ts index 6d97c6aed5be..c3cfecd7dfc6 100644 --- a/x-pack/plugins/serverless_search/common/doc_links.ts +++ b/x-pack/plugins/serverless_search/common/doc_links.ts @@ -18,6 +18,7 @@ class ESDocLinks { public metadata: string = ''; public roleDescriptors: string = ''; public securityApis: string = ''; + public ingestionPipelines: string = ''; // Client links public elasticsearchClients: string = ''; // go @@ -59,6 +60,7 @@ class ESDocLinks { this.metadata = newDocLinks.security.mappingRoles; this.roleDescriptors = newDocLinks.serverlessSecurity.apiKeyPrivileges; this.securityApis = newDocLinks.apis.securityApis; + this.ingestionPipelines = newDocLinks.ingest.pipelines; // Client links this.elasticsearchClients = newDocLinks.serverlessClients.clientLib; diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 0ac92bc19746..a9000e754247 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -15,6 +15,7 @@ "requiredPlugins": [ "cloud", "console", + "dataViews", "dashboard", "devTools", "discover", diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/basic_setup_form.tsx b/x-pack/plugins/serverless_search/public/application/components/api_key/basic_setup_form.tsx index a130e08654bc..c6ec0469168f 100644 --- a/x-pack/plugins/serverless_search/public/application/components/api_key/basic_setup_form.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/basic_setup_form.tsx @@ -72,7 +72,13 @@ export const BasicSetupForm: React.FC = ({ defaultMessage: 'User', })} > - {}} /> + {}} + /> = ({ }) => { return (
    - + {i18n.translate('xpack.serverlessSearch.apiKey.metadataLinkLabel', { defaultMessage: 'Learn how to structure role metadata', })} diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx b/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx index a92224b2b45d..aefc7971d0a4 100644 --- a/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx @@ -24,7 +24,11 @@ export const SecurityPrivilegesForm: React.FC = ({ }) => { return (
    - + {i18n.translate('xpack.serverlessSearch.apiKey.roleDescriptorsLinkLabel', { defaultMessage: 'Learn how to structure role descriptors', })} diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/api_key_panel.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/api_key_panel.tsx index dd42310a05cd..eb1f4aba2ec2 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/api_key_panel.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/api_key_panel.tsx @@ -58,6 +58,7 @@ export const ApiKeyPanel: React.FC = ({ connector }) => { = ({ connecto = ({ connecto = ( - + {i18n.translate('xpack.serverlessSearch.connectors.runWithDockerLink', { defaultMessage: 'Run with Docker', })} @@ -73,6 +79,7 @@ export const ConnectorLinkElasticsearch: React.FC

    - {i18n.translate('xpack.serverlessSearch.connectors.variablesTitle', { - defaultMessage: 'Variables for your ', - })} - elastic/connectors/config.yml + elastic/connectors/config.yml }} + />

    diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_overview.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_overview.tsx index adf652316773..d141ae51c25c 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_overview.tsx @@ -71,6 +71,7 @@ export const ConnectorOverview: React.FC = ({ connector { name: nameLabel, render: (name: string, connector: Connector) => ( navigateToUrl(generatePath(EDIT_CONNECTOR_PATH, { id: connector.id }))} > {name || connector.id} @@ -235,6 +236,7 @@ export const ConnectorsTable: React.FC = () => {
    setFilter(e.currentTarget.value as Filter)} options={filterOptions} /> @@ -294,6 +296,7 @@ const DeleteConnectorModalAction: React.FC<{ connector: Connector }> = ({ connec )} setModalIsOpen(true)} iconType="trash" diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx index 7e9ebb631fc4..a2e4b96176dc 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx @@ -97,6 +97,7 @@ export const DeleteConnectorModal: React.FC = ({ )} > setInputConnectorName(e.target.value)} value={inputConnectorName} /> diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx index f979f7dff283..78d47421420e 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx @@ -72,7 +72,12 @@ export const EditConnector: React.FC = () => { } actions={ - navigateToUrl(`./`)}> + navigateToUrl(`./`)} + > {i18n.translate('xpack.serverlessSearch.connectors.goBack', { defaultMessage: 'Go back', })} @@ -107,6 +112,7 @@ export const EditConnector: React.FC = () => { id={'connectorMenu'} button={ = ({ connector }) = defaultMessage: 'Description', })} labelAppend={ - setIsEditing(true)}> + setIsEditing(true)} + > {EDIT_LABEL} } > {isEditing ? ( setNewDescription(event.target.value)} value={newDescription || ''} /> @@ -102,6 +107,7 @@ export const EditDescription: React.FC = ({ connector }) = `} > mutate(newDescription)} @@ -119,6 +125,7 @@ export const EditDescription: React.FC = ({ connector }) = `} > { diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx index bba3dbec5376..e8073796c7c9 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx @@ -80,6 +80,7 @@ export const EditName: React.FC = ({ connector }) => { `} > = ({ connector }) => { defaultMessage: 'Name', })} - setNewName(event.target.value)} value={newName} /> + setNewName(event.target.value)} + value={newName} + /> @@ -108,6 +113,7 @@ export const EditName: React.FC = ({ connector }) => { `} > = ({ connector }) => { `} > { diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/empty_connectors_prompt.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/empty_connectors_prompt.tsx index a997c8086225..abb0ad64242d 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/empty_connectors_prompt.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/empty_connectors_prompt.tsx @@ -90,7 +90,10 @@ export const EmptyConnectorsPrompt: React.FC = () => { defaultMessage="Deploy connector code on your own infrastructure by running from {source}, or using {docker}" values={{ source: ( - + {i18n.translate( 'xpack.serverlessSearch.connectorsEmpty.sourceLabel', { defaultMessage: 'source' } @@ -98,7 +101,10 @@ export const EmptyConnectorsPrompt: React.FC = () => { ), docker: ( - + {i18n.translate( 'xpack.serverlessSearch.connectorsEmpty.dockerLabel', { defaultMessage: 'Docker' } @@ -157,7 +163,11 @@ export const EmptyConnectorsPrompt: React.FC = () => {
    - + {i18n.translate('xpack.serverlessSearch.connectorsEmpty.createConnector', { defaultMessage: 'Create connector', })} diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors_ingestion.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors_ingestion.tsx new file mode 100644 index 000000000000..ede574abba12 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/application/components/connectors_ingestion.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiSpacer, + EuiText, + EuiLink, + EuiIcon, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { GithubLink } from '@kbn/search-api-panels'; + +import React from 'react'; +import { useCreateConnector } from '../hooks/api/use_create_connector'; + +export const ConnectorIngestionPanel: React.FC<{ assetBasePath: string }> = ({ assetBasePath }) => { + const { createConnector } = useCreateConnector(); + return ( + + + +
    + {i18n.translate( + 'xpack.serverlessSearch.ingestData.alternativeOptions.connectorsTitle', + { + defaultMessage: 'Connectors', + } + )} +
    +
    + + +

    + {i18n.translate( + 'xpack.serverlessSearch.ingestData.alternativeOptions.connectorsDescription', + { + defaultMessage: + 'Sync third-party data sources to Elasticsearch, by deploying open code Elastic connectors on your own infrastructure. ', + } + )} +

    +
    +
    + + + createConnector()} + > + {i18n.translate( + 'xpack.serverlessSearch.ingestData.alternativeOptions.setupConnectorLabel', + { + defaultMessage: 'Set up a connector', + } + )} + + + + + + + + + + + + + + {i18n.translate( + 'xpack.serverlessSearch.ingestData.alternativeOptions.connectorDockerLabel', + { + defaultMessage: 'Docker', + } + )} + + + + + + + +
    + ); +}; diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx index ebd7afc288d2..fd774f3dd491 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx @@ -56,7 +56,11 @@ export const ConnectorsOverview = () => {
    - + {i18n.translate('xpack.serverlessSearch.connectorsPythonLink', { defaultMessage: 'elastic/connectors', })} @@ -67,6 +71,7 @@ export const ConnectorsOverview = () => { { defaultMessage="Sync third-party data sources to Elasticsearch, by deploying Elastic connectors on your own infrastructure. {learnMoreLink}" values={{ learnMoreLink: ( - + {LEARN_MORE_LABEL} ), diff --git a/x-pack/plugins/serverless_search/public/application/components/index_mappings_docs_link.tsx b/x-pack/plugins/serverless_search/public/application/components/index_mappings_docs_link.tsx index fc1699beffa8..9949b40e3c63 100644 --- a/x-pack/plugins/serverless_search/public/application/components/index_mappings_docs_link.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/index_mappings_docs_link.tsx @@ -51,7 +51,12 @@ const IndexMappingsDocsLink: FunctionComponent<{ docLinks: CoreStart['docLinks']

    - + `using System; using Elastic.Clients.Elasticsearch.Serverless; -using Elastic.Clients.Elasticsearch.QueryDsl; +using Elastic.Clients.Elasticsearch.Serverless.QueryDsl; var client = new ElasticsearchClient("${cloudId}", new ApiKey("${apiKey}"));`, testConnection: `var info = await client.InfoAsync();`, diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx index 207917013c7e..444ba50d0800 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx @@ -83,6 +83,10 @@ describe('', () => { const { getByRole } = render(); expect(getByRole('heading', { name: 'Build your first search query' })).toBeDefined(); }); + test('transform data', () => { + const { getByRole } = render(); + expect(getByRole('heading', { name: 'Transform and enrich your data' })).toBeDefined(); + }); test("what's next?", () => { const { getByRole } = render(); expect(getByRole('heading', { name: 'Do more with your data' })).toBeDefined(); diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.tsx index cb32a66cea20..ffabf061dc27 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.tsx @@ -13,6 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, + EuiLink, EuiPageTemplate, EuiPanel, EuiSpacer, @@ -21,6 +22,7 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { WelcomeBanner, IngestData, @@ -39,8 +41,8 @@ import type { } from '@kbn/search-api-panels'; import { useLocation } from 'react-router-dom'; import { docLinks } from '../../../common/doc_links'; -import { PLUGIN_ID } from '../../../common'; import { useKibanaServices } from '../hooks/use_kibana'; +import { useAssetBasePath } from '../hooks/use_asset_base_path'; import { API_KEY_PLACEHOLDER, CLOUD_ID_PLACEHOLDER, @@ -52,6 +54,9 @@ import { LanguageGrid } from './languages/language_grid'; import './overview.scss'; import { ApiKeyPanel } from './api_key/api_key'; import { ConnectorsCallout } from './connectors_callout'; +import { ConnectorIngestionPanel } from './connectors_ingestion'; +import { PipelineButtonOverview } from './pipeline_button_overview'; +import { PipelinePanel } from './pipeline_panel'; export const ElasticsearchOverview = () => { const [selectedLanguage, setSelectedLanguage] = useState(javaDefinition); @@ -64,7 +69,7 @@ export const ElasticsearchOverview = () => { cloudId: cloud?.cloudId ?? CLOUD_ID_PLACEHOLDER, }; }, [cloud]); - const assetBasePath = http.basePath.prepend(`/plugins/${PLUGIN_ID}/assets`); + const assetBasePath = useAssetBasePath(); const codeSnippetArguments: LanguageDefinitionSnippetArguments = { url: elasticsearchURL, apiKey: clientApiKey, @@ -302,6 +307,7 @@ export const ElasticsearchOverview = () => { docLinks={docLinks} application={application} sharePlugin={share} + additionalIngestionPanel={} /> { })} /> + + + {i18n.translate( + 'xpack.serverlessSearch.pipeline.description.ingestPipelinesLink.link', + { + defaultMessage: 'ingest pipelines', + } + )} + + ), + }} + /> + } + leftPanelContent={} + links={[]} + title={i18n.translate('xpack.serverlessSearch.pipeline.title', { + defaultMessage: 'Transform and enrich your data', + })} + children={} + /> + { {cloud.usersAndRolesUrl && ( - + {i18n.translate('xpack.serverlessSearch.overview.footer.links.inviteUsers', { defaultMessage: 'Invite more users', })} @@ -452,14 +498,22 @@ const OverviewFooter = () => { )} - + {i18n.translate('xpack.serverlessSearch.overview.footer.links.community', { defaultMessage: 'Join our community', })} - + {i18n.translate('xpack.serverlessSearch.overview.footer.links.feedback', { defaultMessage: 'Give feedback', })} diff --git a/x-pack/plugins/serverless_search/public/application/components/pipeline_button_overview.tsx b/x-pack/plugins/serverless_search/public/application/components/pipeline_button_overview.tsx new file mode 100644 index 000000000000..dd33faad7f6f --- /dev/null +++ b/x-pack/plugins/serverless_search/public/application/components/pipeline_button_overview.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiSpacer, EuiText, EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { useKibanaServices } from '../hooks/use_kibana'; + +export const PipelineButtonOverview: React.FC = () => { + const { + application: { navigateToUrl }, + } = useKibanaServices(); + + return ( + <> + + navigateToUrl('/app/management/ingest/ingest_pipelines/create')} + data-test-subj="create-a-pipeline-button" + > + + {i18n.translate('xpack.serverlessSearch.pipeline.description.createButtonLabel', { + defaultMessage: 'Create a pipeline', + })} + + + + ); +}; diff --git a/x-pack/plugins/serverless_search/public/application/components/pipeline_panel.tsx b/x-pack/plugins/serverless_search/public/application/components/pipeline_panel.tsx new file mode 100644 index 000000000000..f5b11247b339 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/application/components/pipeline_panel.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { + EuiThemeProvider, + EuiPanel, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiSpacer, + EuiText, + EuiImage, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { useAssetBasePath } from '../hooks/use_asset_base_path'; + +export const PipelinePanel: React.FC = () => { + const assetBasePath = useAssetBasePath(); + + return ( + + + + + + + + + + +

    + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.dataEnrichment.title', + { + defaultMessage: 'Enrich Data', + } + )} +

    +
    + + +

    + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.dataEnrichment.description', + { + defaultMessage: + 'Add information from external sources or apply transformations to your documents for more contextual, insightful search.', + } + )} +

    +
    +
    +
    +
    + + + + + + + +

    + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.extAndStandard.title', + { + defaultMessage: 'Extract and standardize', + } + )} +

    +
    + + + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.extAndStandard.description', + { + defaultMessage: + 'Parse information from your documents to ensure they conform to a standardized format.', + } + )} + +
    +
    +
    + + + + + + + +

    + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.anonymization.title', + { + defaultMessage: 'Anonymize data', + } + )} +

    +
    + + + {i18n.translate( + 'xpack.serverlessSearch.pipeline.overview.anonymization.description', + { + defaultMessage: + 'Remove sensitive information from documents before indexing.', + } + )} + +
    +
    +
    +
    +
    +
    + ); +}; diff --git a/x-pack/plugins/serverless_search/public/assets/cluster.svg b/x-pack/plugins/serverless_search/public/assets/cluster.svg new file mode 100644 index 000000000000..99d4d0a73137 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/assets/cluster.svg @@ -0,0 +1,4 @@ + + + + diff --git a/x-pack/plugins/serverless_search/public/assets/cut.svg b/x-pack/plugins/serverless_search/public/assets/cut.svg new file mode 100644 index 000000000000..58d33d453d71 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/assets/cut.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/x-pack/plugins/serverless_search/public/assets/reporter.svg b/x-pack/plugins/serverless_search/public/assets/reporter.svg new file mode 100644 index 000000000000..bfd2a2afe869 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/assets/reporter.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts index 2651d6a2f38d..98f60c803972 100644 --- a/x-pack/plugins/serverless_search/server/plugin.ts +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -11,9 +11,11 @@ import type { PluginInitializerContext, Plugin, CoreSetup, + CoreStart, } from '@kbn/core/server'; import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import { SEARCH_PROJECT_SETTINGS } from '@kbn/serverless-search-settings'; +import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { registerApiKeyRoutes } from './routes/api_key_routes'; import { registerIndicesRoutes } from './routes/indices_routes'; @@ -51,6 +53,27 @@ export class ServerlessSearchPlugin this.config = initializerContext.config.get(); this.logger = initializerContext.logger.get(); } + private async createDefaultDataView(core: CoreStart, dataViews: DataViewsServerPluginStart) { + const dataViewsService = await dataViews.dataViewsServiceFactory( + core.savedObjects.createInternalRepository(), + core.elasticsearch.client.asInternalUser, + undefined, + true + ); + const dataViewExists = await dataViewsService.get('default_all_data_id').catch(() => false); + if (!dataViewExists) { + const defaultDataViewExists = await dataViewsService.defaultDataViewExists(); + if (!defaultDataViewExists) { + await dataViewsService.createAndSave({ + allowNoIndex: false, + name: 'default:all-data', + title: '*', + id: 'default_all_data_id', + }); + } + } + return; + } public setup( { getStartServices, http }: CoreSetup, @@ -75,7 +98,8 @@ export class ServerlessSearchPlugin return {}; } - public start() { + public start(core: CoreStart, { dataViews }: StartDependencies) { + this.createDefaultDataView(core, dataViews); return {}; } diff --git a/x-pack/plugins/serverless_search/server/types.ts b/x-pack/plugins/serverless_search/server/types.ts index c2eee3d0078a..3cbd26ad2dd5 100644 --- a/x-pack/plugins/serverless_search/server/types.ts +++ b/x-pack/plugins/serverless_search/server/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import type { ServerlessPluginSetup } from '@kbn/serverless/server'; @@ -14,6 +15,7 @@ export interface ServerlessSearchPluginSetup {} export interface ServerlessSearchPluginStart {} export interface StartDependencies { + dataViews: DataViewsServerPluginStart; security: SecurityPluginStart; } export interface SetupDependencies { diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json index c07cff77aa19..f58828f69569 100644 --- a/x-pack/plugins/serverless_search/tsconfig.json +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -35,6 +35,7 @@ "@kbn/react-kibana-context-theme", "@kbn/search-connectors", "@kbn/shared-ux-router", + "@kbn/data-views-plugin", "@kbn/kibana-utils-plugin", "@kbn/index-management-plugin", ] diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index 18accecb36dd..4eaa905f9852 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { v4 as uuidv4 } from 'uuid'; import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'; import { EuiEmptyPrompt, @@ -98,6 +99,7 @@ export const SessionView = ({ const [currentJumpToCursor, setCurrentJumpToCursor] = useState(jumpToCursor); const [currentJumpToEntityId, setCurrentJumpToEntityId] = useState(jumpToEntityId); const [currentJumpToOutputEntityId, setCurrentJumpToOutputEntityId] = useState(''); + const sessionViewId = useMemo(() => `session-view-uuid-${uuidv4()}`, []); const styles = useStyles({ height, isFullScreen }); @@ -399,7 +401,7 @@ export const SessionView = ({ {(EuiResizablePanel, EuiResizableButton, { togglePanel }) => { detailPanelCollapseFn.current = () => { - togglePanel?.('session-detail-panel', { direction: 'left' }); + togglePanel?.(sessionViewId, { direction: 'left' }); }; return ( @@ -458,7 +460,7 @@ export const SessionView = ({ = { ruleDataService: ruleDataServiceMock.create(), esClient: esClientMock, getRuleType: jest.fn(), + getRuleList: jest.fn(), getAlertIndicesAlias: getAlertIndicesAliasMock, }; diff --git a/x-pack/plugins/stack_alerts/public/rule_types/components/index_select_popover.tsx b/x-pack/plugins/stack_alerts/public/rule_types/components/index_select_popover.tsx index c3923e08bbd7..84017dd96bba 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/components/index_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/components/index_select_popover.tsx @@ -108,7 +108,7 @@ export const IndexSelectPopover: React.FunctionComponent = ({ index && index.length > 0 ? renderIndices(index) : i18n.translate('xpack.stackAlerts.components.ui.alertParams.indexPlaceholder', { - defaultMessage: 'Select an index', + defaultMessage: 'Select indices and a time field', }) } isActive={indexPopoverOpen} diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx index 7a9bb590af73..f1e91ba63dc6 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx @@ -197,7 +197,7 @@ export const EsQueryExpression: React.FC<
    diff --git a/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx index be3f1b6f25c9..5fc0d8921629 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx @@ -167,7 +167,7 @@ export const IndexThresholdRuleTypeExpression: React.FunctionComponent<
    @@ -203,6 +203,16 @@ export const IndexThresholdRuleTypeExpression: React.FunctionComponent< setRuleParams('timeField', updatedTimeField) } /> + + +
    + +
    +
    + setRuleParams('termSize', selectedTermSize)} /> - - -
    - -
    -
    - - - -
    - -
    -
    + + + } helpText={i18n.translate('xpack.stackAlerts.threshold.ui.filterKQLHelpText', { defaultMessage: 'Use a KQL expression to limit the scope of your alerts.', })} diff --git a/x-pack/plugins/stack_connectors/common/bedrock/constants.ts b/x-pack/plugins/stack_connectors/common/bedrock/constants.ts index 807109119404..cf0f758a4b06 100644 --- a/x-pack/plugins/stack_connectors/common/bedrock/constants.ts +++ b/x-pack/plugins/stack_connectors/common/bedrock/constants.ts @@ -17,6 +17,8 @@ export const BEDROCK_CONNECTOR_ID = '.bedrock'; export enum SUB_ACTION { RUN = 'run', INVOKE_AI = 'invokeAI', + INVOKE_STREAM = 'invokeStream', + DASHBOARD = 'getDashboard', TEST = 'test', } diff --git a/x-pack/plugins/stack_connectors/common/bedrock/schema.ts b/x-pack/plugins/stack_connectors/common/bedrock/schema.ts index 64699253c709..057780a80356 100644 --- a/x-pack/plugins/stack_connectors/common/bedrock/schema.ts +++ b/x-pack/plugins/stack_connectors/common/bedrock/schema.ts @@ -38,6 +38,11 @@ export const InvokeAIActionResponseSchema = schema.object({ message: schema.string(), }); +export const StreamActionParamsSchema = schema.object({ + body: schema.string(), + model: schema.maybe(schema.string()), +}); + export const RunActionResponseSchema = schema.object( { completion: schema.string(), @@ -45,3 +50,14 @@ export const RunActionResponseSchema = schema.object( }, { unknowns: 'ignore' } ); + +export const StreamingResponseSchema = schema.any(); + +// Run action schema +export const DashboardActionParamsSchema = schema.object({ + dashboardId: schema.string(), +}); + +export const DashboardActionResponseSchema = schema.object({ + available: schema.boolean(), +}); diff --git a/x-pack/plugins/stack_connectors/common/bedrock/types.ts b/x-pack/plugins/stack_connectors/common/bedrock/types.ts index c6fad07cdba3..bd27c5ed0402 100644 --- a/x-pack/plugins/stack_connectors/common/bedrock/types.ts +++ b/x-pack/plugins/stack_connectors/common/bedrock/types.ts @@ -8,11 +8,15 @@ import { TypeOf } from '@kbn/config-schema'; import { ConfigSchema, + DashboardActionParamsSchema, + DashboardActionResponseSchema, SecretsSchema, RunActionParamsSchema, RunActionResponseSchema, InvokeAIActionParamsSchema, InvokeAIActionResponseSchema, + StreamActionParamsSchema, + StreamingResponseSchema, } from './schema'; export type Config = TypeOf; @@ -21,3 +25,7 @@ export type RunActionParams = TypeOf; export type InvokeAIActionParams = TypeOf; export type InvokeAIActionResponse = TypeOf; export type RunActionResponse = TypeOf; +export type StreamActionParams = TypeOf; +export type StreamingResponse = TypeOf; +export type DashboardActionParams = TypeOf; +export type DashboardActionResponse = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/experimental_features.ts b/x-pack/plugins/stack_connectors/common/experimental_features.ts index b7f1fe2c1b87..4ac02dd9f06d 100644 --- a/x-pack/plugins/stack_connectors/common/experimental_features.ts +++ b/x-pack/plugins/stack_connectors/common/experimental_features.ts @@ -12,7 +12,7 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues; * This object is then used to validate and parse the value entered. */ export const allowedExperimentalValues = Object.freeze({ - isMustacheAutocompleteOn: true, + isMustacheAutocompleteOn: false, sentinelOneConnectorOn: false, }); diff --git a/x-pack/plugins/stack_connectors/common/openai/constants.ts b/x-pack/plugins/stack_connectors/common/openai/constants.ts index db01f52d762c..5cf6ecb659f8 100644 --- a/x-pack/plugins/stack_connectors/common/openai/constants.ts +++ b/x-pack/plugins/stack_connectors/common/openai/constants.ts @@ -17,6 +17,7 @@ export const OPENAI_CONNECTOR_ID = '.gen-ai'; export enum SUB_ACTION { RUN = 'run', INVOKE_AI = 'invokeAI', + INVOKE_STREAM = 'invokeStream', STREAM = 'stream', DASHBOARD = 'getDashboard', TEST = 'test', diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx index 361caed6882c..673d6dee8306 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx @@ -57,5 +57,6 @@ export function getConnectorType(): BedrockConnector { }, actionConnectorFields: lazy(() => import('./connector')), actionParamsFields: lazy(() => import('./params')), + actionReadOnlyExtraComponent: lazy(() => import('./dashboard_link')), }; } diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx index 063d0e39d7ef..9af22b79ff55 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx @@ -8,13 +8,17 @@ import React from 'react'; import BedrockConnectorFields from './connector'; import { ConnectorFormTestProvider } from '../lib/test_utils'; -import { act, render, waitFor } from '@testing-library/react'; +import { act, fireEvent, render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import { DEFAULT_BEDROCK_MODEL } from '../../../common/bedrock/constants'; +import { useGetDashboard } from '../lib/gen_ai/use_get_dashboard'; jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); +jest.mock('../lib/gen_ai/use_get_dashboard'); + const useKibanaMock = useKibana as jest.Mocked; +const mockDashboard = useGetDashboard as jest.Mock; const bedrockConnector = { actionTypeId: '.bedrock', name: 'bedrock', @@ -36,6 +40,9 @@ describe('BedrockConnectorFields renders', () => { beforeEach(() => { jest.clearAllMocks(); useKibanaMock().services.application.navigateToUrl = navigateToUrl; + mockDashboard.mockImplementation(({ connectorId }) => ({ + dashboardUrl: `https://dashboardurl.com/${connectorId}`, + })); }); test('Bedrock connector fields are rendered', async () => { const { getAllByTestId } = render( @@ -58,6 +65,49 @@ describe('BedrockConnectorFields renders', () => { expect(getAllByTestId('bedrock-api-model-doc')[0]).toBeInTheDocument(); }); + describe('Dashboard link', () => { + it('Does not render if isEdit is false and dashboardUrl is defined', async () => { + const { queryByTestId } = render( + + {}} + /> + + ); + expect(queryByTestId('link-gen-ai-token-dashboard')).not.toBeInTheDocument(); + }); + it('Does not render if isEdit is true and dashboardUrl is null', async () => { + mockDashboard.mockImplementation((id: string) => ({ + dashboardUrl: null, + })); + const { queryByTestId } = render( + + {}} /> + + ); + expect(queryByTestId('link-gen-ai-token-dashboard')).not.toBeInTheDocument(); + }); + it('Renders if isEdit is true and dashboardUrl is defined', async () => { + const { getByTestId } = render( + + {}} /> + + ); + expect(getByTestId('link-gen-ai-token-dashboard')).toBeInTheDocument(); + }); + it('On click triggers redirect with correct saved object id', async () => { + const { getByTestId } = render( + + {}} /> + + ); + fireEvent.click(getByTestId('link-gen-ai-token-dashboard')); + expect(navigateToUrl).toHaveBeenCalledWith(`https://dashboardurl.com/123`); + }); + }); + describe('Validation', () => { const onSubmit = jest.fn(); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx index c99574aaf5c4..82927bea6ac7 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx @@ -10,16 +10,23 @@ import { ActionConnectorFieldsProps, SimpleConnectorForm, } from '@kbn/triggers-actions-ui-plugin/public'; +import { useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import DashboardLink from './dashboard_link'; +import { BEDROCK } from './translations'; import { bedrockConfig, bedrockSecrets } from './constants'; const BedrockConnectorFields: React.FC = ({ readOnly, isEdit }) => { + const [{ id, name }] = useFormData(); return ( - + <> + + {isEdit && } + ); }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/dashboard_link.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/dashboard_link.tsx new file mode 100644 index 000000000000..e9541c3f6759 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/dashboard_link.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { EuiLink } from '@elastic/eui'; +import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; +import * as i18n from './translations'; +import { useGetDashboard } from '../lib/gen_ai/use_get_dashboard'; + +interface Props { + connectorId: string; + connectorName: string; + selectedProvider?: string; +} +// tested from ./connector.test.tsx +export const DashboardLink: React.FC = ({ + connectorId, + connectorName, + selectedProvider = 'Bedrock', +}) => { + const { dashboardUrl } = useGetDashboard({ connectorId, selectedProvider }); + const { + services: { + application: { navigateToUrl }, + }, + } = useKibana(); + const onClick = useCallback( + (e) => { + e.preventDefault(); + if (dashboardUrl) { + navigateToUrl(dashboardUrl); + } + }, + [dashboardUrl, navigateToUrl] + ); + return dashboardUrl != null ? ( + // href gives us right click -> open in new tab + // onclick prevents page reload + // eslint-disable-next-line @elastic/eui/href-or-on-click + + {i18n.USAGE_DASHBOARD_LINK(selectedProvider, connectorName)} + + ) : null; +}; + +// eslint-disable-next-line import/no-default-export +export { DashboardLink as default }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts index 6906f691ffca..90c593fa602d 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts @@ -97,3 +97,9 @@ export const BODY_DESCRIPTION = i18n.translate( export const MODEL = i18n.translate('xpack.stackConnectors.components.bedrock.model', { defaultMessage: 'Model', }); + +export const USAGE_DASHBOARD_LINK = (apiProvider: string, connectorName: string) => + i18n.translate('xpack.stackConnectors.components.genAi.dashboardLink', { + values: { apiProvider, connectorName }, + defaultMessage: 'View {apiProvider} Usage Dashboard for "{ connectorName }" Connector', + }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.test.ts new file mode 100644 index 000000000000..c48ca17eaced --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { getDashboard } from './api'; +import { SUB_ACTION } from '../../../../common/openai/constants'; +const response = { + available: true, +}; + +describe('Gen AI Dashboard API', () => { + const http = httpServiceMock.createStartContract(); + + beforeEach(() => jest.resetAllMocks()); + describe('getDashboard', () => { + test('should call get dashboard API', async () => { + const abortCtrl = new AbortController(); + http.post.mockResolvedValueOnce(response); + const res = await getDashboard({ + http, + signal: abortCtrl.signal, + connectorId: 'te/st', + dashboardId: 'cool-dashboard', + }); + + expect(res).toEqual(response); + expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { + body: `{"params":{"subAction":"${SUB_ACTION.DASHBOARD}","subActionParams":{"dashboardId":"cool-dashboard"}}}`, + signal: abortCtrl.signal, + }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.ts new file mode 100644 index 000000000000..07780e8d368f --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/api.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HttpSetup } from '@kbn/core-http-browser'; +import { ActionTypeExecutorResult, BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; +import { SUB_ACTION } from '../../../../common/openai/constants'; +import { ConnectorExecutorResult, rewriteResponseToCamelCase } from '../rewrite_response_body'; + +export async function getDashboard({ + http, + signal, + dashboardId, + connectorId, +}: { + http: HttpSetup; + signal: AbortSignal; + connectorId: string; + dashboardId: string; +}): Promise> { + const res = await http.post>( + `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, + { + body: JSON.stringify({ + params: { subAction: SUB_ACTION.DASHBOARD, subActionParams: { dashboardId } }, + }), + signal, + } + ); + return rewriteResponseToCamelCase(res); +} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/translations.ts new file mode 100644 index 000000000000..78c79863a23a --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/translations.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const GET_DASHBOARD_API_ERROR = (apiProvider: string) => + i18n.translate('xpack.stackConnectors.components.genAi.error.dashboardApiError', { + values: { apiProvider }, + defaultMessage: 'Error finding {apiProvider} Token Usage Dashboard.', + }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts new file mode 100644 index 000000000000..8ca9b97292fa --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useGetDashboard } from './use_get_dashboard'; +import { getDashboard } from './api'; +import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; + +jest.mock('./api'); +const mockToasts = { addDanger: jest.fn() }; +const mockSpace = { + id: 'space', + name: 'space', + disabledFeatures: [], +}; +const mockHttp = jest.fn(); +const mockGetRedirectUrl = jest.fn(); +jest.mock('@kbn/triggers-actions-ui-plugin/public'); +const connectorId = '123'; + +const mockServices = { + http: mockHttp, + notifications: { toasts: mockToasts }, + dashboard: { + locator: { + getRedirectUrl: mockGetRedirectUrl.mockImplementation( + ({ dashboardId }) => `http://localhost:5601/app/dashboards#/view/${dashboardId}` + ), + }, + }, + spaces: { + getActiveSpace: jest.fn().mockResolvedValue(mockSpace), + }, +}; +const mockDashboard = getDashboard as jest.Mock; +const mockKibana = useKibana as jest.Mock; + +const defaultArgs = { connectorId, selectedProvider: 'OpenAI' }; + +describe('useGetDashboard', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockDashboard.mockResolvedValue({ data: { available: true } }); + mockKibana.mockReturnValue({ + services: mockServices, + }); + }); + + it.each([ + ['Azure OpenAI', 'openai'], + ['OpenAI', 'openai'], + ['Bedrock', 'bedrock'], + ])( + 'fetches the %p dashboard and sets the dashboard URL with %p', + async (selectedProvider, urlKey) => { + const { result, waitForNextUpdate } = renderHook(() => + useGetDashboard({ ...defaultArgs, selectedProvider }) + ); + await waitForNextUpdate(); + expect(mockDashboard).toHaveBeenCalledWith( + expect.objectContaining({ + connectorId, + dashboardId: `generative-ai-token-usage-${urlKey}-space`, + }) + ); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ + query: { + language: 'kuery', + query: `kibana.saved_objects: { id : ${connectorId} }`, + }, + dashboardId: `generative-ai-token-usage-${urlKey}-space`, + }); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe( + `http://localhost:5601/app/dashboards#/view/generative-ai-token-usage-${urlKey}-space` + ); + } + ); + + it('handles the case where the dashboard is not available.', async () => { + mockDashboard.mockResolvedValue({ data: { available: false } }); + const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); + await waitForNextUpdate(); + expect(mockDashboard).toHaveBeenCalledWith( + expect.objectContaining({ + connectorId, + dashboardId: 'generative-ai-token-usage-openai-space', + }) + ); + expect(mockGetRedirectUrl).not.toHaveBeenCalled(); + + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); + + it('handles the case where the spaces API is not available.', async () => { + mockKibana.mockReturnValue({ + services: { ...mockServices, spaces: null }, + }); + + const { result } = renderHook(() => useGetDashboard(defaultArgs)); + expect(mockDashboard).not.toHaveBeenCalled(); + expect(mockGetRedirectUrl).not.toHaveBeenCalled(); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); + + it('handles the case where connectorId is empty string', async () => { + const { result, waitForNextUpdate } = renderHook(() => + useGetDashboard({ ...defaultArgs, connectorId: '' }) + ); + await waitForNextUpdate(); + expect(mockDashboard).not.toHaveBeenCalled(); + expect(mockGetRedirectUrl).not.toHaveBeenCalled(); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); + + it('handles the case where the dashboard locator is not available.', async () => { + mockKibana.mockReturnValue({ + services: { ...mockServices, dashboard: {} }, + }); + const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); + await waitForNextUpdate(); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); + + it('correctly handles errors and displays the appropriate toast messages.', async () => { + mockDashboard.mockRejectedValue(new Error('Error fetching dashboard')); + const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); + await waitForNextUpdate(); + expect(result.current.isLoading).toBe(false); + expect(mockToasts.addDanger).toHaveBeenCalledWith({ + title: 'Error finding OpenAI Token Usage Dashboard.', + text: 'Error fetching dashboard', + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.ts similarity index 81% rename from x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.ts rename to x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.ts index 557cf2e331ca..dd1f6596d920 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/gen_ai/use_get_dashboard.ts @@ -7,20 +7,20 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; -import { getDashboardId } from './constants'; + import { getDashboard } from './api'; import * as i18n from './translations'; interface Props { connectorId: string; + selectedProvider: string; } export interface UseGetDashboard { dashboardUrl: string | null; isLoading: boolean; } - -export const useGetDashboard = ({ connectorId }: Props): UseGetDashboard => { +export const useGetDashboard = ({ connectorId, selectedProvider }: Props): UseGetDashboard => { const { dashboard, http, @@ -84,7 +84,7 @@ export const useGetDashboard = ({ connectorId }: Props): UseGetDashboard => { if (res.status && res.status === 'error') { toasts.addDanger({ - title: i18n.GET_DASHBOARD_API_ERROR, + title: i18n.GET_DASHBOARD_API_ERROR(selectedProvider), text: `${res.serviceMessage ?? res.message}`, }); } @@ -94,7 +94,7 @@ export const useGetDashboard = ({ connectorId }: Props): UseGetDashboard => { setDashboardCheckComplete(true); setIsLoading(false); toasts.addDanger({ - title: i18n.GET_DASHBOARD_API_ERROR, + title: i18n.GET_DASHBOARD_API_ERROR(selectedProvider), text: error.message, }); } @@ -103,7 +103,7 @@ export const useGetDashboard = ({ connectorId }: Props): UseGetDashboard => { if (spaceId != null && connectorId.length > 0 && !dashboardCheckComplete) { abortCtrl.current.abort(); - fetchData(getDashboardId(spaceId)); + fetchData(getDashboardId(selectedProvider, spaceId)); } return () => { @@ -111,10 +111,24 @@ export const useGetDashboard = ({ connectorId }: Props): UseGetDashboard => { setIsLoading(false); abortCtrl.current.abort(); }; - }, [connectorId, dashboardCheckComplete, dashboardUrl, http, setUrl, spaceId, toasts]); + }, [ + connectorId, + dashboardCheckComplete, + dashboardUrl, + http, + selectedProvider, + setUrl, + spaceId, + toasts, + ]); return { isLoading, dashboardUrl, }; }; + +const getDashboardId = (selectedProvider: string, spaceId: string): string => + `generative-ai-token-usage-${ + selectedProvider.toLowerCase().includes('openai') ? 'openai' : 'bedrock' + }-${spaceId}`; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/helpers.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/helpers.ts index f3e71b0e9fc7..65019f06bf3f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/helpers.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/helpers.ts @@ -16,6 +16,8 @@ import { AppInfo, Choice, RESTApiError } from './types'; export const DEFAULT_CORRELATION_ID = '{{rule.id}}:{{alert.id}}'; +export const ACTION_GROUP_RECOVERED = 'recovered'; + export const choicesToEuiOptions = (choices: Choice[]): EuiSelectOption[] => choices.map((choice) => ({ value: choice.value, text: choice.label })); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts index f55a82b4ce00..a6f7cd65dfe4 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts @@ -56,6 +56,13 @@ export const TITLE_REQUIRED = i18n.translate( } ); +export const CORRELATION_ID_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.serviceNow.requiredCorrelationIdTextField', + { + defaultMessage: 'Correlation id is required.', + } +); + export const INCIDENT = i18n.translate('xpack.stackConnectors.components.serviceNow.title', { defaultMessage: 'Incident', }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/api.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/openai/api.test.ts deleted file mode 100644 index 5ab342a22828..000000000000 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/api.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { getDashboard } from './api'; -import { SUB_ACTION } from '../../../common/openai/constants'; -const response = { - available: true, -}; - -describe('Gen AI Dashboard API', () => { - const http = httpServiceMock.createStartContract(); - - beforeEach(() => jest.resetAllMocks()); - describe('getDashboard', () => { - test('should call get dashboard API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(response); - const res = await getDashboard({ - http, - signal: abortCtrl.signal, - connectorId: 'te/st', - dashboardId: 'cool-dashboard', - }); - - expect(res).toEqual(response); - expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { - body: `{"params":{"subAction":"${SUB_ACTION.DASHBOARD}","subActionParams":{"dashboardId":"cool-dashboard"}}}`, - signal: abortCtrl.signal, - }); - }); - }); -}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/api.ts b/x-pack/plugins/stack_connectors/public/connector_types/openai/api.ts deleted file mode 100644 index 97b0608bb725..000000000000 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/api.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { HttpSetup } from '@kbn/core-http-browser'; -import { ActionTypeExecutorResult, BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; -import { SUB_ACTION } from '../../../common/openai/constants'; -import { ConnectorExecutorResult, rewriteResponseToCamelCase } from '../lib/rewrite_response_body'; - -export async function getDashboard({ - http, - signal, - dashboardId, - connectorId, -}: { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; - dashboardId: string; -}): Promise> { - const res = await http.post>( - `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, - { - body: JSON.stringify({ - params: { subAction: SUB_ACTION.DASHBOARD, subActionParams: { dashboardId } }, - }), - signal, - } - ); - return rewriteResponseToCamelCase(res); -} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx index e88c3fa11615..c434455076d1 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/connector.test.tsx @@ -12,10 +12,10 @@ import { act, fireEvent, render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { DEFAULT_OPENAI_MODEL, OpenAiProviderType } from '../../../common/openai/constants'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; -import { useGetDashboard } from './use_get_dashboard'; +import { useGetDashboard } from '../lib/gen_ai/use_get_dashboard'; jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); -jest.mock('./use_get_dashboard'); +jest.mock('../lib/gen_ai/use_get_dashboard'); const useKibanaMock = useKibana as jest.Mocked; const mockDashboard = useGetDashboard as jest.Mock; @@ -101,7 +101,7 @@ describe('ConnectorFields renders', () => { })); const { queryByTestId } = render( - {}} /> + {}} /> ); expect(queryByTestId('link-gen-ai-token-dashboard')).not.toBeInTheDocument(); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/constants.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/constants.tsx index 4df722ecfae0..7231a41209f8 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/constants.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/constants.tsx @@ -154,5 +154,3 @@ export const providerOptions = [ label: i18n.AZURE_AI, }, ]; - -export const getDashboardId = (spaceId: string): string => `generative-ai-token-usage-${spaceId}`; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/dashboard_link.tsx b/x-pack/plugins/stack_connectors/public/connector_types/openai/dashboard_link.tsx index b7d6ef972372..85c1a9a1955b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/dashboard_link.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/dashboard_link.tsx @@ -9,7 +9,7 @@ import React, { useCallback } from 'react'; import { EuiLink } from '@elastic/eui'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from './translations'; -import { useGetDashboard } from './use_get_dashboard'; +import { useGetDashboard } from '../lib/gen_ai/use_get_dashboard'; interface Props { connectorId: string; @@ -20,9 +20,9 @@ interface Props { export const DashboardLink: React.FC = ({ connectorId, connectorName, - selectedProvider = '', + selectedProvider = 'OpenAI', }) => { - const { dashboardUrl } = useGetDashboard({ connectorId }); + const { dashboardUrl } = useGetDashboard({ connectorId, selectedProvider }); const { services: { application: { navigateToUrl }, @@ -38,7 +38,10 @@ export const DashboardLink: React.FC = ({ [dashboardUrl, navigateToUrl] ); return dashboardUrl != null ? ( - + // href gives us right click -> open in new tab + // onclick prevents page reload + // eslint-disable-next-line @elastic/eui/href-or-on-click + {i18n.USAGE_DASHBOARD_LINK(selectedProvider, connectorName)} ) : null; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts index f6cfa4a91cf6..4c72866c6ece 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/openai/translations.ts @@ -100,10 +100,3 @@ export const USAGE_DASHBOARD_LINK = (apiProvider: string, connectorName: string) values: { apiProvider, connectorName }, defaultMessage: 'View {apiProvider} Usage Dashboard for "{ connectorName }" Connector', }); - -export const GET_DASHBOARD_API_ERROR = i18n.translate( - 'xpack.stackConnectors.components.genAi.error.dashboardApiError', - { - defaultMessage: 'Error finding OpenAI Token Usage Dashboard.', - } -); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.test.ts deleted file mode 100644 index 8e78c522712b..000000000000 --- a/x-pack/plugins/stack_connectors/public/connector_types/openai/use_get_dashboard.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { useGetDashboard } from './use_get_dashboard'; -import { getDashboard } from './api'; -import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; - -jest.mock('./api'); -const mockToasts = { addDanger: jest.fn() }; -const mockSpace = { - id: 'space', - name: 'space', - disabledFeatures: [], -}; -const mockHttp = jest.fn(); -const mockGetRedirectUrl = jest.fn(); -jest.mock('@kbn/triggers-actions-ui-plugin/public'); -const connectorId = '123'; - -const mockServices = { - http: mockHttp, - notifications: { toasts: mockToasts }, - dashboard: { - locator: { - getRedirectUrl: mockGetRedirectUrl.mockImplementation( - ({ dashboardId }) => `http://localhost:5601/app/dashboards#/view/${dashboardId}` - ), - }, - }, - spaces: { - getActiveSpace: jest.fn().mockResolvedValue(mockSpace), - }, -}; -const mockDashboard = getDashboard as jest.Mock; -const mockKibana = useKibana as jest.Mock; - -describe('useGetDashboard_function', () => { - beforeEach(() => { - jest.clearAllMocks(); - mockDashboard.mockResolvedValue({ data: { available: true } }); - mockKibana.mockReturnValue({ - services: mockServices, - }); - }); - - it('fetches the dashboard and sets the dashboard URL', async () => { - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard({ connectorId })); - await waitForNextUpdate(); - expect(mockDashboard).toHaveBeenCalledWith( - expect.objectContaining({ - connectorId, - dashboardId: 'generative-ai-token-usage-space', - }) - ); - expect(mockGetRedirectUrl).toHaveBeenCalledWith({ - query: { - language: 'kuery', - query: `kibana.saved_objects: { id : ${connectorId} }`, - }, - dashboardId: 'generative-ai-token-usage-space', - }); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe( - 'http://localhost:5601/app/dashboards#/view/generative-ai-token-usage-space' - ); - }); - - it('handles the case where the dashboard is not available.', async () => { - mockDashboard.mockResolvedValue({ data: { available: false } }); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard({ connectorId })); - await waitForNextUpdate(); - expect(mockDashboard).toHaveBeenCalledWith( - expect.objectContaining({ - connectorId, - dashboardId: 'generative-ai-token-usage-space', - }) - ); - expect(mockGetRedirectUrl).not.toHaveBeenCalled(); - - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); - }); - - it('handles the case where the spaces API is not available.', async () => { - mockKibana.mockReturnValue({ - services: { ...mockServices, spaces: null }, - }); - - const { result } = renderHook(() => useGetDashboard({ connectorId })); - expect(mockDashboard).not.toHaveBeenCalled(); - expect(mockGetRedirectUrl).not.toHaveBeenCalled(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); - }); - - it('handles the case where connectorId is empty string', async () => { - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard({ connectorId: '' })); - await waitForNextUpdate(); - expect(mockDashboard).not.toHaveBeenCalled(); - expect(mockGetRedirectUrl).not.toHaveBeenCalled(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); - }); - - it('handles the case where the dashboard locator is not available.', async () => { - mockKibana.mockReturnValue({ - services: { ...mockServices, dashboard: {} }, - }); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard({ connectorId })); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); - }); - - it('correctly handles errors and displays the appropriate toast messages.', async () => { - mockDashboard.mockRejectedValue(new Error('Error fetching dashboard')); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard({ connectorId })); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(false); - expect(mockToasts.addDanger).toHaveBeenCalledWith({ - title: 'Error finding OpenAI Token Usage Dashboard.', - text: 'Error fetching dashboard', - }); - }); -}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.test.tsx new file mode 100644 index 000000000000..10c78d4029d9 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.test.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen, render } from '@testing-library/react'; +import { LinksList } from './links_list'; +import userEvent from '@testing-library/user-event'; + +describe('LinksList', () => { + const editAction = jest.fn(); + + const options = { + index: 0, + errors: { + links: [], + }, + editAction, + links: [], + }; + + beforeEach(() => jest.clearAllMocks()); + + it('the list is empty by default', () => { + render(); + + expect(screen.queryByTestId('linksListItemRow')).not.toBeInTheDocument(); + }); + + it('clicking add button calls editAction with correct params', async () => { + render(); + + userEvent.click(await screen.findByTestId('pagerDutyAddLinkButton')); + + expect(editAction).toHaveBeenCalledWith('links', [{ href: '', text: '' }], 0); + }); + + it('clicking remove link button calls editAction with correct params', async () => { + render( + + ); + + expect(await screen.findAllByTestId('linksListItemRow', { exact: false })).toHaveLength(3); + + userEvent.click((await screen.findAllByTestId('pagerDutyRemoveLinkButton'))[1]); + + expect(editAction).toHaveBeenCalledWith( + 'links', + [ + { href: '1', text: 'foobar' }, + { href: '3', text: 'foobar' }, + ], + 0 + ); + }); + + it('editing a link href field calls editAction with correct params', async () => { + render(); + + expect(await screen.findByTestId('linksListItemRow', { exact: false })).toBeInTheDocument(); + + userEvent.paste(await screen.findByTestId('linksHrefInput'), 'newHref'); + + expect(editAction).toHaveBeenCalledWith('links', [{ href: 'newHref', text: 'foobar' }], 0); + }); + + it('editing a link text field calls editAction with correct params', async () => { + render(); + + expect(await screen.findByTestId('linksListItemRow', { exact: false })).toBeInTheDocument(); + + userEvent.paste(await screen.findByTestId('linksTextInput'), 'newText'); + + expect(editAction).toHaveBeenCalledWith('links', [{ href: 'foobar', text: 'newText' }], 0); + }); + + it('correctly displays error messages', async () => { + render(); + + expect(await screen.findByText('FoobarError')); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.tsx new file mode 100644 index 000000000000..941105b6f97b --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/links_list.tsx @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiButton, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { + ActionParamsProps, + TextFieldWithMessageVariables, +} from '@kbn/triggers-actions-ui-plugin/public'; +import { PagerDutyActionParams } from '../types'; +import { OPTIONAL_LABEL } from './translations'; + +type LinksListProps = Pick< + ActionParamsProps, + 'index' | 'editAction' | 'errors' | 'messageVariables' +> & + Pick; + +export const LinksList: React.FC = ({ + editAction, + errors, + index, + links, + messageVariables, +}) => { + const areLinksInvalid = Array.isArray(errors.links) && errors.links.length > 0; + + return ( + + {OPTIONAL_LABEL} + + } + isInvalid={areLinksInvalid} + error={errors.links} + fullWidth + > + + {links && + links.map((link, currentLinkIndex) => ( + + + + + + { + const newLinks = [...links]; + newLinks[currentLinkIndex] = { text: link.text, href: value }; + editAction('links', newLinks, actionIndex); + }} + messageVariables={messageVariables} + paramsProperty={'linksHref'} + inputTargetValue={link.href} + /> + + + + + { + const newLinks = [...links]; + newLinks[currentLinkIndex] = { href: link.href, text: value }; + editAction('links', newLinks, actionIndex); + }} + messageVariables={messageVariables} + paramsProperty={'linksText'} + inputTargetValue={link.text} + /> + + + + { + links.splice(currentLinkIndex, 1); + editAction('links', links, index); + }} + iconType="minusInCircle" + css={{ marginTop: 28 }} + data-test-subj="pagerDutyRemoveLinkButton" + /> + + + + ))} + +
    + + editAction( + 'links', + links ? [...links, { href: '', text: '' }] : [{ href: '', text: '' }], + index + ) + } + data-test-subj="pagerDutyAddLinkButton" + > + {i18n.translate('xpack.stackConnectors.components.pagerDuty.addLinkButtonLabel', { + defaultMessage: 'Add Link', + })} + +
    +
    +
    +
    + ); +}; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.test.tsx index 311d4bfac867..4df68dee1588 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.test.tsx @@ -43,6 +43,8 @@ describe('pagerduty action params validation', () => { component: 'test', group: 'group', class: 'test class', + customDetails: '{}', + links: [], }; expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ @@ -50,6 +52,8 @@ describe('pagerduty action params validation', () => { dedupKey: [], summary: [], timestamp: [], + links: [], + customDetails: [], }, }); }); @@ -74,6 +78,142 @@ describe('pagerduty action params validation', () => { dedupKey: [], summary: [], timestamp: expect.arrayContaining(expected), + links: [], + customDetails: [], + }, + }); + }); + + test('action params validation fails when customDetails are not valid JSON', async () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + customDetails: '{foo:bar}', + links: [], + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + dedupKey: [], + summary: [], + timestamp: [], + links: [], + customDetails: ['Custom details must be a valid JSON.'], + }, + }); + }); + + test('action params validation does not fail when customDetails are not JSON but have mustache templates inside', async () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + customDetails: '{"details": {{alert.flapping}}}', + links: [], + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + dedupKey: [], + summary: [], + timestamp: [], + links: [], + customDetails: [], + }, + }); + }); + + test('action params validation fails when a link is missing the href field', async () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + customDetails: '{}', + links: [{ href: '', text: 'foobar' }], + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + dedupKey: [], + summary: [], + timestamp: [], + links: ['Link properties cannot be empty.'], + customDetails: [], + }, + }); + }); + + test('action params validation fails when a link is missing the text field', async () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + customDetails: '{}', + links: [{ href: 'foobar', text: '' }], + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + dedupKey: [], + summary: [], + timestamp: [], + links: ['Link properties cannot be empty.'], + customDetails: [], + }, + }); + }); + + test('action params validation does not throw the same error multiple times for links', async () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: new Date().toISOString(), + component: 'test', + group: 'group', + class: 'test class', + customDetails: '{}', + links: [ + { href: 'foobar', text: '' }, + { href: '', text: 'foobar' }, + { href: '', text: '' }, + ], + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + dedupKey: [], + summary: [], + timestamp: [], + links: ['Link properties cannot be empty.'], + customDetails: [], }, }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.tsx index 0dd1513ac55a..b02665eec66b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty.tsx @@ -50,6 +50,8 @@ export function getConnectorType(): ConnectorTypeModel< summary: new Array(), timestamp: new Array(), dedupKey: new Array(), + links: new Array(), + customDetails: new Array(), }; const validationResult = { errors }; if ( @@ -79,6 +81,31 @@ export function getConnectorType(): ConnectorTypeModel< ); } } + if (Array.isArray(actionParams.links)) { + actionParams.links.forEach(({ href, text }) => { + if ((!href || !text) && errors.links.length === 0) { + errors.links.push( + i18n.translate('xpack.stackConnectors.components.pagerDuty.error.invalidLink', { + defaultMessage: 'Link properties cannot be empty.', + }) + ); + } + }); + } + if (actionParams.customDetails?.length && !hasMustacheTokens(actionParams.customDetails)) { + try { + JSON.parse(actionParams.customDetails); + } catch { + errors.customDetails.push( + i18n.translate( + 'xpack.stackConnectors.components.pagerDuty.error.invalidCustomDetails', + { + defaultMessage: 'Custom details must be a valid JSON.', + } + ) + ); + } + } return validationResult; }, actionConnectorFields: lazy(() => import('./pagerduty_connectors')), diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_connectors.tsx index 13139306ea78..3766c01f5152 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_connectors.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiLink } from '@elastic/eui'; +import { EuiLink, EuiText } from '@elastic/eui'; import { isEmpty } from 'lodash'; import { FormattedMessage } from '@kbn/i18n-react'; import { FieldConfig, UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; @@ -21,6 +21,11 @@ const { emptyField, urlField } = fieldValidators; const getApiURLConfig = (): FieldConfig => ({ label: i18n.API_URL_LABEL, + labelAppend: ( + + {i18n.OPTIONAL_LABEL} + + ), validations: [ { validator: (args) => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.test.tsx index 19f47166b272..aa1e6be9bebe 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.test.tsx @@ -11,7 +11,7 @@ import { EventActionOptions, SeverityActionOptions } from '../types'; import PagerDutyParamsFields from './pagerduty_params'; describe('PagerDutyParamsFields renders', () => { - test('all params fields is rendered', () => { + test('all params fields are rendered', () => { const actionParams = { eventAction: EventActionOptions.TRIGGER, dedupKey: 'test', @@ -22,6 +22,11 @@ describe('PagerDutyParamsFields renders', () => { component: 'test', group: 'group', class: 'test class', + customDetails: '{"foo":"bar"}', + links: [ + { href: 'foo', text: 'bar' }, + { href: 'foo', text: 'bar' }, + ], }; const wrapper = mountWithIntl( @@ -55,6 +60,9 @@ describe('PagerDutyParamsFields renders', () => { expect(wrapper.find('[data-test-subj="sourceInput"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="summaryInput"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="dedupKeyAddVariableButton"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="customDetailsJsonEditor"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="linksList"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="pagerDutyAddLinkButton"]').length > 0).toBeTruthy(); }); test('params select fields do not auto set values eventActionSelect', () => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.tsx index 970ef6ae1ecb..08d92a0f4ad3 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/pagerduty_params.tsx @@ -6,12 +6,25 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect, EuiSpacer } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSelect, + EuiSpacer, + EuiText, + useEuiTheme, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isUndefined } from 'lodash'; -import type { ActionParamsProps } from '@kbn/triggers-actions-ui-plugin/public'; +import { + ActionParamsProps, + JsonEditorWithMessageVariables, +} from '@kbn/triggers-actions-ui-plugin/public'; import { TextFieldWithMessageVariables } from '@kbn/triggers-actions-ui-plugin/public'; import { PagerDutyActionParams } from '../types'; +import { LinksList } from './links_list'; +import { OPTIONAL_LABEL } from './translations'; const PagerDutyParamsFields: React.FunctionComponent> = ({ actionParams, @@ -20,8 +33,20 @@ const PagerDutyParamsFields: React.FunctionComponent { - const { eventAction, dedupKey, summary, source, severity, timestamp, component, group } = - actionParams; + const { euiTheme } = useEuiTheme(); + + const { + eventAction, + dedupKey, + summary, + source, + severity, + timestamp, + component, + group, + customDetails, + links, + } = actionParams; const severityOptions = [ { value: 'critical', @@ -125,26 +150,24 @@ const PagerDutyParamsFields: React.FunctionComponent
    - + + {OPTIONAL_LABEL} + + ) } > - {isTriggerPagerDutyEvent ? ( + {isTriggerPagerDutyEvent && ( <> + {OPTIONAL_LABEL} + + } > + {OPTIONAL_LABEL} + + } > + {OPTIONAL_LABEL} + + } > + {OPTIONAL_LABEL} + + } > + {OPTIONAL_LABEL} + + } > + {OPTIONAL_LABEL} + + } > + + {OPTIONAL_LABEL} + + } + > + { + editAction('customDetails', json, index); + }} + onBlur={() => { + if (!customDetails) { + editAction('customDetails', '', index); + } + }} + data-test-subj="customDetailsJsonEditor" + /> + + - ) : null} + )} ); }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/translations.ts index 2a5020f69855..3f542217a637 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/pagerduty/translations.ts @@ -31,7 +31,7 @@ export const INTEGRATION_KEY_REQUIRED = i18n.translate( export const API_URL_LABEL = i18n.translate( 'xpack.stackConnectors.components.pagerDuty.apiUrlTextFieldLabel', { - defaultMessage: 'API URL (optional)', + defaultMessage: 'API URL', } ); @@ -48,3 +48,10 @@ export const INTEGRATION_KEY_LABEL = i18n.translate( defaultMessage: 'Integration key', } ); + +export const OPTIONAL_LABEL = i18n.translate( + 'xpack.stackConnectors.components.pagerDuty.optionalLabel', + { + defaultMessage: 'Optional', + } +); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.test.tsx index ea7497bde283..107ccab01e60 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.test.tsx @@ -35,7 +35,25 @@ describe('servicenow action params validation', () => { }; expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ - errors: { ['subActionParams.incident.short_description']: [] }, + errors: { + ['subActionParams.incident.correlation_id']: [], + ['subActionParams.incident.short_description']: [], + }, + }); + }); + + test(`${SERVICENOW_ITSM_CONNECTOR_TYPE_ID}: action params validation succeeds for closeIncident subAction`, async () => { + const connectorTypeModel = connectorTypeRegistry.get(SERVICENOW_ITSM_CONNECTOR_TYPE_ID); + const actionParams = { + subAction: 'closeIncident', + subActionParams: { incident: { correlation_id: '{{test}}{{rule_id}}' } }, + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + ['subActionParams.incident.correlation_id']: [], + ['subActionParams.incident.short_description']: [], + }, }); }); @@ -47,8 +65,24 @@ describe('servicenow action params validation', () => { expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ errors: { + ['subActionParams.incident.correlation_id']: [], ['subActionParams.incident.short_description']: ['Short description is required.'], }, }); }); + + test(`${SERVICENOW_ITSM_CONNECTOR_TYPE_ID}: params validation fails when correlation_id is not valid and subAction is closeIncident`, async () => { + const connectorTypeModel = connectorTypeRegistry.get(SERVICENOW_ITSM_CONNECTOR_TYPE_ID); + const actionParams = { + subAction: 'closeIncident', + subActionParams: { incident: { correlation_id: '' } }, + }; + + expect(await connectorTypeModel.validateParams(actionParams)).toEqual({ + errors: { + ['subActionParams.incident.correlation_id']: ['Correlation id is required.'], + ['subActionParams.incident.short_description']: [], + }, + }); + }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.tsx b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.tsx index 23e0aba04e01..dfa6eb5c4398 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm.tsx @@ -13,7 +13,11 @@ import type { } from '@kbn/triggers-actions-ui-plugin/public'; import { ServiceNowConfig, ServiceNowSecrets } from '../lib/servicenow/types'; import { ServiceNowITSMActionParams } from './types'; -import { getConnectorDescriptiveTitle, getSelectedConnectorIcon } from '../lib/servicenow/helpers'; +import { + DEFAULT_CORRELATION_ID, + getConnectorDescriptiveTitle, + getSelectedConnectorIcon, +} from '../lib/servicenow/helpers'; export const SERVICENOW_ITSM_DESC = i18n.translate( 'xpack.stackConnectors.components.serviceNowITSM.selectMessageText', @@ -46,6 +50,7 @@ export function getServiceNowITSMConnectorType(): ConnectorTypeModel< const translations = await import('../lib/servicenow/translations'); const errors = { 'subActionParams.incident.short_description': new Array(), + 'subActionParams.incident.correlation_id': new Array(), }; const validationResult = { errors, @@ -53,10 +58,20 @@ export function getServiceNowITSMConnectorType(): ConnectorTypeModel< if ( actionParams.subActionParams && actionParams.subActionParams.incident && + actionParams.subAction !== 'closeIncident' && !actionParams.subActionParams.incident.short_description?.length ) { errors['subActionParams.incident.short_description'].push(translations.TITLE_REQUIRED); } + + if ( + actionParams.subAction === 'closeIncident' && + !actionParams?.subActionParams?.incident?.correlation_id?.length + ) { + errors['subActionParams.incident.correlation_id'].push( + translations.CORRELATION_ID_REQUIRED + ); + } return validationResult; }, actionParamsFields: lazy(() => import('./servicenow_itsm_params')), @@ -64,5 +79,18 @@ export function getServiceNowITSMConnectorType(): ConnectorTypeModel< getText: getConnectorDescriptiveTitle, getComponent: getSelectedConnectorIcon, }, + defaultActionParams: { + subAction: 'pushToService', + subActionParams: { + incident: { correlation_id: DEFAULT_CORRELATION_ID }, + comments: [], + }, + }, + defaultRecoveredActionParams: { + subAction: 'closeIncident', + subActionParams: { + incident: { correlation_id: DEFAULT_CORRELATION_ID }, + }, + }, }; } diff --git a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.test.tsx index 5925724b7b8a..a9d303ee4f20 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.test.tsx @@ -14,6 +14,7 @@ import { useGetChoices } from '../lib/servicenow/use_get_choices'; import ServiceNowITSMParamsFields from './servicenow_itsm_params'; import { Choice } from '../lib/servicenow/types'; import { merge } from 'lodash'; +import { ACTION_GROUP_RECOVERED } from '../lib/servicenow/helpers'; jest.mock('../lib/servicenow/use_get_choices'); jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); @@ -151,14 +152,11 @@ describe('ServiceNowITSMParamsFields renders', () => { expect(title.prop('isInvalid')).toBeTruthy(); }); - test('When subActionParams is undefined, set to default', () => { - const { subActionParams, ...newParams } = actionParams; - - const newProps = { - ...defaultProps, - actionParams: newParams, - }; - mountWithIntl(); + test('Resets fields when connector changes', () => { + const wrapper = mountWithIntl(); + expect(editAction.mock.calls.length).toEqual(0); + wrapper.setProps({ actionConnector: { ...connector, id: '1234' } }); + expect(editAction.mock.calls.length).toEqual(1); expect(editAction.mock.calls[0][1]).toEqual({ incident: { correlation_id: '{{rule.id}}:{{alert.id}}', @@ -167,27 +165,17 @@ describe('ServiceNowITSMParamsFields renders', () => { }); }); - test('When subAction is undefined, set to default', () => { - const { subAction, ...newParams } = actionParams; - + test('Resets fields when connector changes and action group is recovered', () => { const newProps = { ...defaultProps, - actionParams: newParams, + selectedActionGroupId: ACTION_GROUP_RECOVERED, }; - mountWithIntl(); - expect(editAction.mock.calls[0][1]).toEqual('pushToService'); - }); - - test('Resets fields when connector changes', () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); expect(editAction.mock.calls.length).toEqual(0); wrapper.setProps({ actionConnector: { ...connector, id: '1234' } }); expect(editAction.mock.calls.length).toEqual(1); expect(editAction.mock.calls[0][1]).toEqual({ - incident: { - correlation_id: '{{rule.id}}:{{alert.id}}', - }, - comments: [], + incident: { correlation_id: '{{rule.id}}:{{alert.id}}' }, }); }); @@ -299,5 +287,57 @@ describe('ServiceNowITSMParamsFields renders', () => { expect(comments.simulate('change', changeEvent)); expect(editAction.mock.calls[0][1].comments.length).toEqual(1); }); + + test('shows only correlation_id field when actionGroup is recovered', () => { + const newProps = { + ...defaultProps, + selectedActionGroupId: 'recovered', + }; + const wrapper = mountWithIntl(); + expect(wrapper.find('input[data-test-subj="correlation_idInput"]').exists()).toBeTruthy(); + expect(wrapper.find('input[data-test-subj="short_descriptionInput"]').exists()).toBeFalsy(); + }); + + test('A short description change triggers editAction', () => { + const wrapper = mountWithIntl( + + ); + + const shortDescriptionField = wrapper.find('input[data-test-subj="short_descriptionInput"]'); + shortDescriptionField.simulate('change', { + target: { value: 'new updated short description' }, + }); + + expect(editAction.mock.calls[0][1]).toEqual({ + incident: { short_description: 'new updated short description' }, + comments: [], + }); + }); + + test('A correlation_id field change triggers edit action correctly when actionGroup is recovered', () => { + const wrapper = mountWithIntl( + + ); + const correlationIdField = wrapper.find('input[data-test-subj="correlation_idInput"]'); + + correlationIdField.simulate('change', { + target: { value: 'updated correlation id' }, + }); + + expect(editAction.mock.calls[0][1]).toEqual({ + incident: { correlation_id: 'updated correlation id' }, + }); + }); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.tsx index 9da2069bc29f..7c0c72db2b50 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/servicenow_itsm/servicenow_itsm_params.tsx @@ -25,7 +25,11 @@ import { import { Choice, Fields } from '../lib/servicenow/types'; import { ServiceNowITSMActionParams } from './types'; import { useGetChoices } from '../lib/servicenow/use_get_choices'; -import { choicesToEuiOptions, DEFAULT_CORRELATION_ID } from '../lib/servicenow/helpers'; +import { + ACTION_GROUP_RECOVERED, + choicesToEuiOptions, + DEFAULT_CORRELATION_ID, +} from '../lib/servicenow/helpers'; import * as i18n from '../lib/servicenow/translations'; @@ -39,11 +43,50 @@ const defaultFields: Fields = { priority: [], }; +const CorrelationIdField: React.FunctionComponent< + Pick, 'index' | 'messageVariables'> & { + correlationId: string | null; + editSubActionProperty: (key: string, value: any) => void; + } +> = ({ index, messageVariables, correlationId, editSubActionProperty }) => { + const { docLinks } = useKibana().services; + return ( + + +
    + } + > + + + ); +}; + const ServiceNowParamsFields: React.FunctionComponent< ActionParamsProps -> = ({ actionConnector, actionParams, editAction, index, errors, messageVariables }) => { +> = (props) => { + const { + actionConnector, + actionParams, + editAction, + index, + errors, + messageVariables, + selectedActionGroupId, + } = props; const { - docLinks, http, notifications: { toasts }, } = useKibana().services; @@ -56,9 +99,9 @@ const ServiceNowParamsFields: React.FunctionComponent< actionParams.subActionParams ?? ({ incident: {}, - comments: [], + comments: selectedActionGroupId !== ACTION_GROUP_RECOVERED ? [] : undefined, } as unknown as ServiceNowITSMActionParams['subActionParams']), - [actionParams.subActionParams] + [actionParams.subActionParams, selectedActionGroupId] ); const [choices, setChoices] = useState(defaultFields); @@ -122,23 +165,16 @@ const ServiceNowParamsFields: React.FunctionComponent< useEffect(() => { if (actionConnector != null && actionConnectorRef.current !== actionConnector.id) { actionConnectorRef.current = actionConnector.id; - editAction( - 'subActionParams', - { - incident: { correlation_id: DEFAULT_CORRELATION_ID }, - comments: [], - }, - index - ); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [actionConnector]); + if (selectedActionGroupId === ACTION_GROUP_RECOVERED) { + editAction( + 'subActionParams', + { incident: { correlation_id: DEFAULT_CORRELATION_ID } }, + index + ); + + return; + } - useEffect(() => { - if (!actionParams.subAction) { - editAction('subAction', 'pushToService', index); - } - if (!actionParams.subActionParams) { editAction( 'subActionParams', { @@ -149,7 +185,7 @@ const ServiceNowParamsFields: React.FunctionComponent< ); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [actionParams]); + }, [actionConnector]); return ( <> @@ -157,173 +193,170 @@ const ServiceNowParamsFields: React.FunctionComponent<

    {i18n.INCIDENT}

    - - editSubActionProperty('urgency', e.target.value)} - /> - - - - - - editSubActionProperty('severity', e.target.value)} - /> - - - - - editSubActionProperty('impact', e.target.value)} - /> - - - - - - - + {selectedActionGroupId !== ACTION_GROUP_RECOVERED ? ( + <> + { - editAction( - 'subActionParams', - { - incident: { ...incident, category: e.target.value, subcategory: null }, - comments, - }, - index - ); - }} + options={urgencyOptions} + value={incident.urgency ?? ''} + onChange={(e) => editSubActionProperty('urgency', e.target.value)} /> - - - {subcategoryOptions?.length > 0 ? ( - - editSubActionProperty('subcategory', e.target.value)} - /> - - ) : null} - - - - {!isDeprecatedActionConnector && ( - <> + - - -
    - } - > - + editSubActionProperty('severity', e.target.value)} + /> + + + + + editSubActionProperty('impact', e.target.value)} + /> + + + + + + + + { + editAction( + 'subActionParams', + { + incident: { ...incident, category: e.target.value, subcategory: null }, + comments, + }, + index + ); + }} /> - + {subcategoryOptions?.length > 0 ? ( + + editSubActionProperty('subcategory', e.target.value)} + /> + + ) : null} + + + + {!isDeprecatedActionConnector && ( + <> + + + + + + + + + + + + + )} + + + 0 && + incident.short_description !== undefined + } + label={i18n.SHORT_DESCRIPTION_LABEL} + > + + 0 ? comments[0].comment : undefined} + label={i18n.COMMENTS_LABEL} + /> + ) : ( + )} - - - 0 && - incident.short_description !== undefined - } - label={i18n.SHORT_DESCRIPTION_LABEL} - > - - - - - - - 0 ? comments[0].comment : undefined} - label={i18n.COMMENTS_LABEL} - /> ); }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/types.ts b/x-pack/plugins/stack_connectors/public/connector_types/types.ts index 72319df375e1..eb0cb9927dce 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/types.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/types.ts @@ -39,6 +39,8 @@ export interface PagerDutyActionParams { component?: string; group?: string; class?: string; + customDetails?: string; + links?: Array<{ href: string; text: string }>; } export interface IndexActionParams { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index dcd3d70f9b4f..a3fd59e0ccc0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -4,12 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import aws from 'aws4'; +import { PassThrough, Transform } from 'stream'; import { BedrockConnector } from './bedrock'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { RunActionResponseSchema } from '../../../common/bedrock/schema'; +import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/bedrock/schema'; import { BEDROCK_CONNECTOR_ID, DEFAULT_BEDROCK_MODEL, @@ -17,12 +18,12 @@ import { DEFAULT_TOKEN_LIMIT, } from '../../../common/bedrock/constants'; import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; +import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { AxiosError } from 'axios'; +jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); -jest.mock('aws4', () => ({ - sign: () => ({ signed: true }), -})); - +// @ts-ignore +const mockSigner = jest.spyOn(aws, 'sign').mockReturnValue({ signed: true }); describe('BedrockConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; @@ -35,32 +36,49 @@ describe('BedrockConnector', () => { }, }; beforeEach(() => { + jest.clearAllMocks(); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); }); - describe('Bedrock', () => { - const connector = new BedrockConnector({ - configurationUtilities: actionsConfigMock.create(), - connector: { id: '1', type: BEDROCK_CONNECTOR_ID }, - config: { - apiUrl: DEFAULT_BEDROCK_URL, - defaultModel: DEFAULT_BEDROCK_MODEL, - }, - secrets: { accessKey: '123', secret: 'secret' }, - logger: loggingSystemMock.createLogger(), - services: actionsMock.createServices(), - }); + const connector = new BedrockConnector({ + configurationUtilities: actionsConfigMock.create(), + connector: { id: '1', type: BEDROCK_CONNECTOR_ID }, + config: { + apiUrl: DEFAULT_BEDROCK_URL, + defaultModel: DEFAULT_BEDROCK_MODEL, + }, + secrets: { accessKey: '123', secret: 'secret' }, + logger: loggingSystemMock.createLogger(), + services: actionsMock.createServices(), + }); + describe('Bedrock', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; - jest.clearAllMocks(); }); describe('runApi', () => { + it('the aws signature has non-streaming headers', async () => { + await connector.runApi({ body: DEFAULT_BODY }); + + expect(mockSigner).toHaveBeenCalledWith( + { + body: '{"prompt":"\\n\\nHuman: Hello world! \\n\\nAssistant:","max_tokens_to_sample":8191,"stop_sequences":["\\n\\nHuman:"]}', + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + }, + host: 'bedrock.us-east-1.amazonaws.com', + path: '/model/anthropic.claude-v2/invoke', + service: 'bedrock', + }, + { accessKeyId: '123', secretAccessKey: 'secret' } + ); + }); it('the Bedrock API call is successful with correct parameters', async () => { const response = await connector.runApi({ body: DEFAULT_BODY }); expect(mockRequest).toBeCalledTimes(1); @@ -83,6 +101,117 @@ describe('BedrockConnector', () => { }); }); + describe('invokeStream', () => { + let stream; + beforeEach(() => { + stream = createStreamMock(); + stream.write(new Uint8Array([1, 2, 3])); + mockRequest = jest.fn().mockResolvedValue({ ...mockResponse, data: stream.transform }); + // @ts-ignore + connector.request = mockRequest; + }); + + const aiAssistantBody = { + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }; + + it('the aws signature has streaming headers', async () => { + await connector.invokeStream(aiAssistantBody); + + expect(mockSigner).toHaveBeenCalledWith( + { + body: JSON.stringify({ + prompt: '\n\nHuman:Hello world \n\nAssistant:', + max_tokens_to_sample: DEFAULT_TOKEN_LIMIT, + temperature: 0.5, + stop_sequences: ['\n\nHuman:'], + }), + headers: { + accept: 'application/vnd.amazon.eventstream', + 'Content-Type': 'application/json', + 'x-amzn-bedrock-accept': '*/*', + }, + host: 'bedrock.us-east-1.amazonaws.com', + path: '/model/anthropic.claude-v2/invoke-with-response-stream', + service: 'bedrock', + }, + { accessKeyId: '123', secretAccessKey: 'secret' } + ); + }); + + it('the API call is successful with correct request parameters', async () => { + await connector.invokeStream(aiAssistantBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + prompt: '\n\nHuman:Hello world \n\nAssistant:', + max_tokens_to_sample: DEFAULT_TOKEN_LIMIT, + temperature: 0.5, + stop_sequences: ['\n\nHuman:'], + }), + }); + }); + + it('formats messages from user, assistant, and system', async () => { + await connector.invokeStream({ + messages: [ + { + role: 'user', + content: 'Hello world', + }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, + ], + }); + expect(mockRequest).toHaveBeenCalledWith({ + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + prompt: + '\n\nHuman:Hello world\n\nHuman:Be a good chatbot\n\nAssistant:Hi, I am a good chatbot\n\nHuman:What is 2+2? \n\nAssistant:', + max_tokens_to_sample: DEFAULT_TOKEN_LIMIT, + temperature: 0.5, + stop_sequences: ['\n\nHuman:'], + }), + }); + }); + + it('responds with a readable stream', async () => { + const response = await connector.invokeStream(aiAssistantBody); + expect(response instanceof PassThrough).toEqual(true); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.invokeStream(aiAssistantBody)).rejects.toThrow('API Error'); + }); + }); + describe('invokeAI', () => { const aiAssistantBody = { messages: [ @@ -112,7 +241,7 @@ describe('BedrockConnector', () => { expect(response.message).toEqual(mockResponseString); }); - it('Properly formats messages from user, assistant, and system', async () => { + it('formats messages from user, assistant, and system', async () => { const response = await connector.invokeAI({ messages: [ { @@ -209,4 +338,90 @@ describe('BedrockConnector', () => { }); }); }); + + describe('Token dashboard', () => { + const mockGenAi = initDashboard as jest.Mock; + beforeEach(() => { + // @ts-ignore + connector.esClient.transport.request = mockRequest; + mockRequest.mockResolvedValue({ has_all_requested: true }); + mockGenAi.mockResolvedValue({ success: true }); + jest.clearAllMocks(); + }); + it('the create dashboard API call returns available: true when user has correct permissions', async () => { + const response = await connector.getDashboard({ dashboardId: '123' }); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: ['.kibana-event-log-*'], + allow_restricted_indices: true, + privileges: ['read'], + }, + ], + }, + }); + expect(response).toEqual({ available: true }); + }); + it('the create dashboard API call returns available: false when user has correct permissions', async () => { + mockRequest.mockResolvedValue({ has_all_requested: false }); + const response = await connector.getDashboard({ dashboardId: '123' }); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: ['.kibana-event-log-*'], + allow_restricted_indices: true, + privileges: ['read'], + }, + ], + }, + }); + expect(response).toEqual({ available: false }); + }); + + it('the create dashboard API call returns available: false when init dashboard fails', async () => { + mockGenAi.mockResolvedValue({ success: false }); + const response = await connector.getDashboard({ dashboardId: '123' }); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: ['.kibana-event-log-*'], + allow_restricted_indices: true, + privileges: ['read'], + }, + ], + }, + }); + expect(response).toEqual({ available: false }); + }); + }); }); + +function createStreamMock() { + const transform: Transform = new Transform({}); + + return { + write: (data: Uint8Array) => { + transform.push(data); + }, + fail: () => { + transform.emit('error', new Error('Stream failed')); + transform.end(); + }, + transform, + complete: () => { + transform.end(); + }, + }; +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index ea0c72420b41..a5fda6a05afa 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -8,10 +8,14 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import aws from 'aws4'; import type { AxiosError } from 'axios'; +import { IncomingMessage } from 'http'; +import { PassThrough } from 'stream'; +import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { RunActionParamsSchema, RunActionResponseSchema, InvokeAIActionParamsSchema, + StreamingResponseSchema, } from '../../../common/bedrock/schema'; import type { Config, @@ -20,8 +24,15 @@ import type { RunActionResponse, InvokeAIActionParams, InvokeAIActionResponse, + StreamActionParams, } from '../../../common/bedrock/types'; import { SUB_ACTION, DEFAULT_TOKEN_LIMIT } from '../../../common/bedrock/constants'; +import { + DashboardActionParams, + DashboardActionResponse, + StreamingResponse, +} from '../../../common/bedrock/types'; +import { DashboardActionParamsSchema } from '../../../common/bedrock/schema'; interface SignedRequest { host: string; @@ -50,17 +61,28 @@ export class BedrockConnector extends SubActionConnector { schema: RunActionParamsSchema, }); + this.registerSubAction({ + name: SUB_ACTION.DASHBOARD, + method: 'getDashboard', + schema: DashboardActionParamsSchema, + }); + this.registerSubAction({ name: SUB_ACTION.TEST, method: 'runApi', schema: RunActionParamsSchema, }); - this.registerSubAction({ name: SUB_ACTION.INVOKE_AI, method: 'invokeAI', schema: InvokeAIActionParamsSchema, }); + + this.registerSubAction({ + name: SUB_ACTION.INVOKE_STREAM, + method: 'invokeStream', + schema: InvokeAIActionParamsSchema, + }); } protected getResponseErrorMessage(error: AxiosError<{ message?: string }>): string { @@ -82,15 +104,21 @@ export class BedrockConnector extends SubActionConnector { * @param body The request body to be signed. * @param path The path of the request URL. */ - private signRequest(body: string, path: string) { + private signRequest(body: string, path: string, stream: boolean) { const { host } = new URL(this.url); return aws.sign( { host, - headers: { - 'Content-Type': 'application/json', - Accept: '*/*', - }, + headers: stream + ? { + accept: 'application/vnd.amazon.eventstream', + 'Content-Type': 'application/json', + 'x-amzn-bedrock-accept': '*/*', + } + : { + 'Content-Type': 'application/json', + Accept: '*/*', + }, body, path, // Despite AWS docs, this value does not always get inferred. We need to always send it @@ -103,6 +131,42 @@ export class BedrockConnector extends SubActionConnector { ) as SignedRequest; } + /** + * retrieves a dashboard from the Kibana server and checks if the + * user has the necessary privileges to access it. + * @param dashboardId The ID of the dashboard to retrieve. + */ + public async getDashboard({ + dashboardId, + }: DashboardActionParams): Promise { + const privilege = (await this.esClient.transport.request({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: ['.kibana-event-log-*'], + allow_restricted_indices: true, + privileges: ['read'], + }, + ], + }, + })) as { has_all_requested: boolean }; + + if (!privilege?.has_all_requested) { + return { available: false }; + } + + const response = await initDashboard({ + logger: this.logger, + savedObjectsClient: this.savedObjectsClient, + dashboardId, + genAIProvider: 'Bedrock', + }); + + return { available: response.success }; + } + /** * responsible for making a POST request to the external API endpoint and returning the response data * @param body The stringified request body to be sent in the POST request. @@ -110,11 +174,11 @@ export class BedrockConnector extends SubActionConnector { */ public async runApi({ body, model: reqModel }: RunActionParams): Promise { // set model on per request basis - const model = reqModel ? reqModel : this.model; - const signed = this.signRequest(body, `/model/${model}/invoke`); + const path = `/model/${reqModel ?? this.model}/invoke`; + const signed = this.signRequest(body, path, false); const response = await this.request({ ...signed, - url: `${this.url}/model/${model}/invoke`, + url: `${this.url}${path}`, method: 'post', responseSchema: RunActionResponseSchema, data: body, @@ -125,33 +189,81 @@ export class BedrockConnector extends SubActionConnector { } /** - * takes in an array of messages and a model as input, and returns a promise that resolves to a string. - * The method combines the messages into a single prompt formatted for bedrock,sends a request to the - * runApi method with the prompt and model, and returns the trimmed completion from the response. - * @param messages An array of message objects, where each object has a role (string) and content (string) property. + * NOT INTENDED TO BE CALLED DIRECTLY + * call invokeStream instead + * responsible for making a POST request to a specified URL with a given request body. + * The response is then processed based on whether it is a streaming response or a regular response. + * @param body The stringified request body to be sent in the POST request. + * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. + */ + private async streamApi({ + body, + model: reqModel, + }: StreamActionParams): Promise { + // set model on per request basis + const path = `/model/${reqModel ?? this.model}/invoke-with-response-stream`; + const signed = this.signRequest(body, path, true); + + const response = await this.request({ + ...signed, + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + }); + + return response.data.pipe(new PassThrough()); + } + + /** + * takes in an array of messages and a model as inputs. It calls the streamApi method to make a + * request to the Bedrock API with the formatted messages and model. It then returns a Transform stream + * that pipes the response from the API through the transformToString function, + * which parses the proprietary response into a string of the response text alone + * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ + public async invokeStream({ messages, model }: InvokeAIActionParams): Promise { + const res = (await this.streamApi({ + body: JSON.stringify(formatBedrockBody({ messages })), + model, + })) as unknown as IncomingMessage; + return res; + } + + /** + * Deprecated. Use invokeStream instead. + * TODO: remove once streaming work is implemented in langchain mode for security solution + * tracked here: https://github.com/elastic/security-team/issues/7363 + */ public async invokeAI({ messages, model, }: InvokeAIActionParams): Promise { - const combinedMessages = messages.reduce((acc: string, message) => { - const { role, content } = message; - // Bedrock only has Assistant and Human, so 'system' and 'user' will be converted to Human - const bedrockRole = role === 'assistant' ? '\n\nAssistant:' : '\n\nHuman:'; - return `${acc}${bedrockRole}${content}`; - }, ''); - - const req = { - // end prompt in "Assistant:" to avoid the model starting its message with "Assistant:" - prompt: `${combinedMessages} \n\nAssistant:`, - max_tokens_to_sample: DEFAULT_TOKEN_LIMIT, - temperature: 0.5, - // prevent model from talking to itself - stop_sequences: ['\n\nHuman:'], - }; - - const res = await this.runApi({ body: JSON.stringify(req), model }); + const res = await this.runApi({ body: JSON.stringify(formatBedrockBody({ messages })), model }); return { message: res.completion.trim() }; } } + +const formatBedrockBody = ({ + messages, +}: { + messages: Array<{ role: string; content: string }>; +}) => { + const combinedMessages = messages.reduce((acc: string, message) => { + const { role, content } = message; + // Bedrock only has Assistant and Human, so 'system' and 'user' will be converted to Human + const bedrockRole = role === 'assistant' ? '\n\nAssistant:' : '\n\nHuman:'; + return `${acc}${bedrockRole}${content}`; + }, ''); + + return { + // end prompt in "Assistant:" to avoid the model starting its message with "Assistant:" + prompt: `${combinedMessages} \n\nAssistant:`, + max_tokens_to_sample: DEFAULT_TOKEN_LIMIT, + temperature: 0.5, + // prevent model from talking to itself + stop_sequences: ['\n\nHuman:'], + }; +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.test.ts new file mode 100644 index 000000000000..ff23c96014d8 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { initDashboard } from './create_gen_ai_dashboard'; +import { getDashboard } from './gen_ai_dashboard'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { Logger } from '@kbn/logging'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('12345'), +})); + +const logger = loggingSystemMock.create().get() as jest.Mocked; +const dashboardId = 'test-dashboard-id'; + +const savedObjectsClient = savedObjectsClientMock.create(); +const defaultArgs = { logger, savedObjectsClient, dashboardId, genAIProvider: 'OpenAI' as const }; +describe('createDashboard', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('fetches the Gen Ai Dashboard saved object', async () => { + const result = await initDashboard(defaultArgs); + expect(result.success).toBe(true); + expect(logger.error).not.toHaveBeenCalled(); + expect(savedObjectsClient.get).toHaveBeenCalledWith('dashboard', dashboardId); + }); + + it('creates the Gen Ai Dashboard saved object when the dashboard saved object does not exist', async () => { + const soClient = { + ...savedObjectsClient, + get: jest.fn().mockRejectedValue({ + output: { + statusCode: 404, + payload: { + statusCode: 404, + error: 'Not Found', + message: 'Saved object [dashboard/generative-ai-token-usage-default] not found', + }, + headers: {}, + }, + }), + }; + const result = await initDashboard({ ...defaultArgs, savedObjectsClient: soClient }); + + expect(soClient.get).toHaveBeenCalledWith('dashboard', dashboardId); + expect(soClient.create).toHaveBeenCalledWith( + 'dashboard', + getDashboard(defaultArgs.genAIProvider, dashboardId).attributes, + { overwrite: true, id: dashboardId } + ); + expect(result.success).toBe(true); + }); + + it('handles an error when fetching the dashboard saved object', async () => { + const soClient = { + ...savedObjectsClient, + get: jest.fn().mockRejectedValue({ + output: { + statusCode: 500, + payload: { + statusCode: 500, + error: 'Internal Server Error', + message: 'Error happened', + }, + headers: {}, + }, + }), + }; + const result = await initDashboard({ ...defaultArgs, savedObjectsClient: soClient }); + expect(result.success).toBe(false); + expect(result.error?.message).toBe('Internal Server Error: Error happened'); + expect(result.error?.statusCode).toBe(500); + expect(soClient.get).toHaveBeenCalledWith('dashboard', dashboardId); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts new file mode 100644 index 000000000000..665d4258d54d --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; + +import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import { Logger } from '@kbn/logging'; +import { getDashboard } from './gen_ai_dashboard'; + +export interface OutputError { + message: string; + statusCode: number; +} + +export const initDashboard = async ({ + logger, + savedObjectsClient, + dashboardId, + genAIProvider, +}: { + logger: Logger; + savedObjectsClient: SavedObjectsClientContract; + dashboardId: string; + genAIProvider: 'OpenAI' | 'Bedrock'; +}): Promise<{ + success: boolean; + error?: OutputError; +}> => { + try { + await savedObjectsClient.get('dashboard', dashboardId); + return { + success: true, + }; + } catch (error) { + // if 404, does not yet exist. do not error, continue to create + if (error.output.statusCode !== 404) { + return { + success: false, + error: { + message: `${error.output.payload.error}${ + error.output.payload.message ? `: ${error.output.payload.message}` : '' + }`, + statusCode: error.output.statusCode, + }, + }; + } + } + + try { + await savedObjectsClient.create( + 'dashboard', + getDashboard(genAIProvider, dashboardId).attributes, + { + overwrite: true, + id: dashboardId, + } + ); + logger.info(`Successfully created Generative AI Dashboard ${dashboardId}`); + return { success: true }; + } catch (error) { + return { + success: false, + error: { message: error.message, statusCode: error.output.statusCode }, + }; + } +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts new file mode 100644 index 000000000000..9fd492e1559c --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts @@ -0,0 +1,424 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import { v4 as uuidv4 } from 'uuid'; +import { SavedObject } from '@kbn/core-saved-objects-common/src/server_types'; +import { OPENAI_TITLE, OPENAI_CONNECTOR_ID } from '../../../../common/openai/constants'; +import { BEDROCK_TITLE, BEDROCK_CONNECTOR_ID } from '../../../../common/bedrock/constants'; + +const getDashboardTitle = (title: string) => `${title} Token Usage`; + +export const getDashboard = ( + genAIProvider: 'OpenAI' | 'Bedrock', + dashboardId: string +): SavedObject => { + const attributes = + genAIProvider === 'OpenAI' + ? { + provider: OPENAI_TITLE, + dashboardTitle: getDashboardTitle(OPENAI_TITLE), + actionTypeId: OPENAI_CONNECTOR_ID, + } + : { + provider: BEDROCK_TITLE, + dashboardTitle: getDashboardTitle(BEDROCK_TITLE), + actionTypeId: BEDROCK_CONNECTOR_ID, + }; + + const ids: Record = { + genAiSavedObjectId: dashboardId, + tokens: uuidv4(), + totalTokens: uuidv4(), + tag: uuidv4(), + }; + return { + attributes: { + description: `Displays ${attributes.provider} token consumption per Kibana user`, + kibanaSavedObjectMeta: { + searchSourceJSON: `{"query":{"query":"kibana.saved_objects: { type_id : \\"${attributes.actionTypeId}\\" } ","language":"kuery"},"filter":[]}`, + }, + optionsJSON: + '{"useMargins":true,"syncColors":false,"syncCursor":true,"syncTooltips":false,"hidePanelTitles":false}', + panelsJSON: JSON.stringify([ + { + version: '8.9.0', + type: 'visualization', + gridData: { + x: 0, + y: 0, + w: 48, + h: 4, + i: '1c425103-57a6-4598-a092-03b8d550b440', + }, + panelIndex: '1c425103-57a6-4598-a092-03b8d550b440', + embeddableConfig: { + savedVis: { + id: '', + title: '', + description: '', + type: 'markdown', + params: { + fontSize: 12, + openLinksInNewTab: false, + markdown: + // TODO: update with better copy and link to the docs page for the Gen AI connector before 8.9 release! + 'The data powering this dashboard requires special index permissions. To access the dashboard data, contact a Kibana admin to set up a "read only" role for non-admin users who may want to view this dashboard. ', + }, + uiState: {}, + data: { + aggs: [], + searchSource: { + query: { + query: '', + language: 'kuery', + }, + filter: [], + }, + }, + }, + hidePanelTitles: false, + enhancements: {}, + }, + title: 'Permissions note', + }, + { + version: '8.9.0', + type: 'lens', + gridData: { + x: 0, + y: 0, + w: 48, + h: 20, + i: '1e45fe29-05d3-4dbd-a0bb-fc3bc5ee3d6d', + }, + panelIndex: '1e45fe29-05d3-4dbd-a0bb-fc3bc5ee3d6d', + embeddableConfig: { + attributes: { + title: '', + description: '', + visualizationType: 'lnsXY', + type: 'lens', + references: [], + state: { + visualization: { + title: 'Empty XY chart', + legend: { + isVisible: true, + position: 'right', + }, + valueLabels: 'hide', + preferredSeriesType: 'bar_stacked', + layers: [ + { + layerId: '475e8ca0-e78e-454a-8597-a5492f70dce3', + accessors: [ + '0f9814ec-0964-4efa-93a3-c7f173df2483', + 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + ], + position: 'top', + seriesType: 'bar_stacked', + showGridlines: false, + layerType: 'data', + xAccessor: '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', + yConfig: [ + { + forAccessor: '0f9814ec-0964-4efa-93a3-c7f173df2483', + color: '#9170b8', + }, + { + forAccessor: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + color: '#3383cd', + }, + ], + }, + ], + labelsOrientation: { + x: 0, + yLeft: 0, + yRight: 0, + }, + yTitle: `Sum of ${attributes.provider} Completion + Prompt Tokens`, + axisTitlesVisibilitySettings: { + x: true, + yLeft: true, + yRight: true, + }, + }, + query: { + query: `kibana.saved_objects:{ type_id: "${attributes.actionTypeId}" }`, + language: 'kuery', + }, + filters: [], + datasourceStates: { + formBased: { + layers: { + '475e8ca0-e78e-454a-8597-a5492f70dce3': { + columns: { + '0f9814ec-0964-4efa-93a3-c7f173df2483': { + label: `${attributes.provider} Completion Tokens`, + dataType: 'number', + operationType: 'sum', + sourceField: 'kibana.action.execution.gen_ai.usage.completion_tokens', + isBucketed: false, + scale: 'ratio', + params: { + emptyAsNull: true, + }, + customLabel: true, + }, + '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519': { + label: 'user.name', + dataType: 'string', + operationType: 'terms', + scale: 'ordinal', + sourceField: 'user.name', + isBucketed: true, + params: { + size: 10000, + orderBy: { + type: 'custom', + }, + orderDirection: 'desc', + otherBucket: true, + missingBucket: false, + parentFormat: { + id: 'terms', + }, + include: [], + exclude: [], + includeIsRegex: false, + excludeIsRegex: false, + orderAgg: { + label: 'Sum of kibana.action.execution.openai.usage.total_tokens', + dataType: 'number', + operationType: 'sum', + sourceField: 'kibana.action.execution.gen_ai.usage.total_tokens', + isBucketed: false, + scale: 'ratio', + params: { + emptyAsNull: true, + }, + }, + secondaryFields: [], + }, + customLabel: true, + }, + 'b0e390e4-d754-4eb4-9fcc-4347dadda394': { + label: `${attributes.provider} Prompt Tokens`, + dataType: 'number', + operationType: 'sum', + sourceField: 'kibana.action.execution.gen_ai.usage.prompt_tokens', + isBucketed: false, + scale: 'ratio', + params: { + emptyAsNull: true, + }, + customLabel: true, + }, + }, + columnOrder: [ + '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', + '0f9814ec-0964-4efa-93a3-c7f173df2483', + 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + ], + sampling: 1, + incompleteColumns: {}, + }, + }, + }, + textBased: { + layers: {}, + }, + }, + internalReferences: [ + { + type: 'index-pattern', + id: ids.tokens, + name: 'indexpattern-datasource-layer-475e8ca0-e78e-454a-8597-a5492f70dce3', + }, + ], + adHocDataViews: { + [ids.tokens]: { + id: ids.tokens, + title: '.kibana-event-log-*', + timeFieldName: '@timestamp', + sourceFilters: [], + fieldFormats: {}, + runtimeFieldMap: { + 'kibana.action.execution.gen_ai.usage.completion_tokens': { + type: 'long', + }, + 'kibana.action.execution.gen_ai.usage.prompt_tokens': { + type: 'long', + }, + }, + fieldAttrs: {}, + allowNoIndex: false, + name: 'Event Log', + }, + }, + }, + }, + hidePanelTitles: false, + enhancements: {}, + }, + title: 'Prompt + Completion Tokens per User', + }, + { + version: '8.9.0', + type: 'lens', + gridData: { + x: 0, + y: 20, + w: 48, + h: 20, + i: '80f745c6-a18b-492b-bacf-4a2499a2f95d', + }, + panelIndex: '80f745c6-a18b-492b-bacf-4a2499a2f95d', + embeddableConfig: { + attributes: { + title: '', + description: '', + visualizationType: 'lnsXY', + type: 'lens', + references: [], + state: { + visualization: { + title: 'Empty XY chart', + legend: { + isVisible: true, + position: 'right', + }, + valueLabels: 'hide', + preferredSeriesType: 'bar_stacked', + layers: [ + { + layerId: '475e8ca0-e78e-454a-8597-a5492f70dce3', + accessors: ['b0e390e4-d754-4eb4-9fcc-4347dadda394'], + position: 'top', + seriesType: 'bar_stacked', + showGridlines: false, + layerType: 'data', + xAccessor: '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', + yConfig: [ + { + forAccessor: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + color: '#332182', + }, + ], + }, + ], + }, + query: { + query: `kibana.saved_objects: { type_id : "${attributes.actionTypeId}" } `, + language: 'kuery', + }, + filters: [], + datasourceStates: { + formBased: { + layers: { + '475e8ca0-e78e-454a-8597-a5492f70dce3': { + columns: { + '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519': { + label: 'user.name', + dataType: 'string', + operationType: 'terms', + scale: 'ordinal', + sourceField: 'user.name', + isBucketed: true, + params: { + size: 10000, + orderBy: { + type: 'column', + columnId: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + }, + orderDirection: 'desc', + otherBucket: true, + missingBucket: false, + parentFormat: { + id: 'terms', + }, + include: [], + exclude: [], + includeIsRegex: false, + excludeIsRegex: false, + }, + customLabel: true, + }, + 'b0e390e4-d754-4eb4-9fcc-4347dadda394': { + label: `Sum of ${attributes.provider} Total Tokens`, + dataType: 'number', + operationType: 'sum', + sourceField: 'kibana.action.execution.gen_ai.usage.total_tokens', + isBucketed: false, + scale: 'ratio', + params: { + emptyAsNull: true, + }, + customLabel: true, + }, + }, + columnOrder: [ + '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', + 'b0e390e4-d754-4eb4-9fcc-4347dadda394', + ], + sampling: 1, + incompleteColumns: {}, + }, + }, + }, + textBased: { + layers: {}, + }, + }, + internalReferences: [ + { + type: 'index-pattern', + id: ids.totalTokens, + name: 'indexpattern-datasource-layer-475e8ca0-e78e-454a-8597-a5492f70dce3', + }, + ], + adHocDataViews: { + [ids.totalTokens]: { + id: ids.totalTokens, + title: '.kibana-event-log-*', + timeFieldName: '@timestamp', + sourceFilters: [], + fieldFormats: {}, + runtimeFieldMap: { + 'kibana.action.execution.gen_ai.usage.total_tokens': { + type: 'long', + }, + }, + fieldAttrs: {}, + allowNoIndex: false, + name: 'Event Log', + }, + }, + }, + }, + hidePanelTitles: false, + enhancements: {}, + }, + title: 'Total Tokens per User', + }, + ]), + timeRestore: false, + title: attributes.dashboardTitle, + version: 1, + }, + coreMigrationVersion: '8.8.0', + created_at: '2023-06-01T19:00:04.629Z', + id: ids.genAiSavedObjectId, + managed: false, + type: 'dashboard', + typeMigrationVersion: '8.7.0', + updated_at: '2023-06-01T19:00:04.629Z', + references: [], + }; +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.test.ts index ce7439bc05df..fefe78df7357 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.test.ts @@ -356,6 +356,84 @@ describe('api', () => { }); }); + describe('close incident', () => { + test('it closes an incident with incidentId', async () => { + const res = await api.closeIncident({ + externalService, + params: { + incident: { + externalId: apiParams.incident.externalId, + correlation_id: null, + }, + }, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it closes an incident with correlation_id', async () => { + const res = await api.closeIncident({ + externalService, + params: { + incident: { + externalId: null, + correlation_id: apiParams.incident.correlation_id, + }, + }, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it calls closeIncident correctly', async () => { + await api.closeIncident({ + externalService, + params: { + incident: { + externalId: apiParams.incident.externalId, + correlation_id: null, + }, + }, + logger: mockedLogger, + }); + + expect(externalService.closeIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + correlationId: null, + }); + }); + + test('it calls closeIncident correctly with correlation_id', async () => { + await api.closeIncident({ + externalService, + params: { + incident: { + externalId: null, + correlation_id: apiParams.incident.correlation_id, + }, + }, + logger: mockedLogger, + }); + + expect(externalService.closeIncident).toHaveBeenCalledWith({ + incidentId: null, + correlationId: 'ruleId', + }); + }); + }); + describe('getFields', () => { test('it returns the fields correctly', async () => { const res = await api.getFields({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.ts index 88cdfd069cf1..931f7936bff6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/api.ts @@ -16,6 +16,8 @@ import { Incident, PushToServiceApiHandlerArgs, PushToServiceResponse, + CloseIncidentApiHandlerArgs, + ExternalServiceIncidentResponse, } from './types'; const handshakeHandler = async ({ externalService, params }: HandshakeApiHandlerArgs) => {}; @@ -74,6 +76,20 @@ const pushToServiceHandler = async ({ return res; }; +const closeIncidentHandler = async ({ + externalService, + params, +}: CloseIncidentApiHandlerArgs): Promise => { + const { externalId, correlation_id: correlationId } = params.incident; + + const res = await externalService.closeIncident({ + correlationId, + incidentId: externalId, + }); + + return res; +}; + const getFieldsHandler = async ({ externalService, }: GetCommonFieldsHandlerArgs): Promise => { @@ -95,4 +111,5 @@ export const api: ExternalServiceAPI = { getIncident: getIncidentHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, + closeIncident: closeIncidentHandler, }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/mocks.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/mocks.ts index 1043fe62af1e..410a5f58ab00 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/mocks.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/mocks.ts @@ -91,6 +91,16 @@ const createMock = (): jest.Mocked => { description: 'description from servicenow', }) ), + getIncidentByCorrelationId: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + short_description: 'title from servicenow', + description: 'description from servicenow', + }) + ), createIncident: jest.fn().mockImplementation(() => Promise.resolve({ id: 'incident-1', @@ -107,6 +117,14 @@ const createMock = (): jest.Mocked => { url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', }) ), + closeIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }) + ), findIncidents: jest.fn(), getApplicationInformation: jest.fn().mockImplementation(() => Promise.resolve({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/schema.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/schema.ts index 5f5ea6ab0ff9..568d9b01e67e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/schema.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/schema.ts @@ -115,6 +115,13 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ externalId: schema.string(), }); +export const ExecutorSubActionCloseIncidentParamsSchema = schema.object({ + incident: schema.object({ + externalId: schema.nullable(schema.string()), + correlation_id: schema.nullable(schema.string({ defaultValue: DEFAULT_ALERTS_GROUPING_KEY })), + }), +}); + // Reserved for future implementation export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); @@ -144,6 +151,10 @@ export const ExecutorParamsSchemaITSM = schema.oneOf([ subAction: schema.literal('getChoices'), subActionParams: ExecutorSubActionGetChoicesParamsSchema, }), + schema.object({ + subAction: schema.literal('closeIncident'), + subActionParams: ExecutorSubActionCloseIncidentParamsSchema, + }), ]); // Executor parameters for ServiceNow Security Incident Response (SIR) diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index 28ee0e248c2b..fcdd0f31b6ec 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import axios, { AxiosResponse } from 'axios'; +import axios, { AxiosError, AxiosResponse } from 'axios'; import { createExternalService } from './service'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; @@ -17,7 +17,10 @@ import { serviceNowCommonFields, serviceNowChoices } from './mocks'; import { snExternalServiceConfig } from './config'; const logger = loggingSystemMock.create().get() as jest.Mocked; -jest.mock('axios'); +jest.mock('axios', () => ({ + create: jest.fn(), + AxiosError: jest.requireActual('axios').AxiosError, +})); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { const originalUtils = jest.requireActual('@kbn/actions-plugin/server/lib/axios_utils'); return { @@ -73,7 +76,7 @@ const mockImportIncident = (update: boolean) => })); const mockIncidentResponse = (update: boolean) => - requestMock.mockImplementation(() => ({ + requestMock.mockImplementationOnce(() => ({ data: { result: { sys_id: '1', @@ -85,6 +88,19 @@ const mockIncidentResponse = (update: boolean) => }, })); +const mockCorrelationIdIncidentResponse = () => + requestMock.mockImplementationOnce(() => ({ + data: { + result: [ + { + sys_id: '1', + number: 'INC01', + sys_updated_on: '2020-03-10 12:24:20', + }, + ], + }, + })); + const createIncident = async (service: ExternalService) => { // Get application version mockApplicationVersion(); @@ -112,6 +128,35 @@ const updateIncident = async (service: ExternalService) => { }); }; +const closeIncident = async ({ + service, + incidentId, + correlationId, +}: { + service: ExternalService; + incidentId: string | null; + correlationId: string | null; +}) => { + // Get incident response + if (incidentId) { + mockIncidentResponse(false); + } else if (correlationId) { + // get incident by correlationId response + mockCorrelationIdIncidentResponse(); + } + // Get application version + mockApplicationVersion(); + // Import set api response + mockImportIncident(true); + // Get incident response + mockIncidentResponse(true); + + return await service.closeIncident({ + incidentId: incidentId ?? null, + correlationId: correlationId ?? null, + }); +}; + const expectImportedIncident = (update: boolean) => { expect(requestMock).toHaveBeenNthCalledWith(1, { axios, @@ -439,7 +484,7 @@ describe('ServiceNow service', () => { throw new Error('An error has occurred'); }); await expect(service.getIncident('1')).rejects.toThrow( - 'Unable to get incident with id 1. Error: An error has occurred' + '[Action][ServiceNow]: Unable to get incident with id 1. Error: An error has occurred Reason: unknown: errorResponse was null' ); }); @@ -455,6 +500,88 @@ describe('ServiceNow service', () => { }); }); + describe('getIncidentByCorrelationId', () => { + test('it returns the incident correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { result: [{ sys_id: '1', number: 'INC01' }] }, + })); + const res = await service.getIncidentByCorrelationId('custom_correlation_id'); + expect(res).toEqual({ sys_id: '1', number: 'INC01' }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { result: [{ sys_id: '1', number: 'INC01' }] }, + })); + + await service.getIncidentByCorrelationId('custom_correlation_id'); + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', + method: 'get', + }); + }); + + test('it should return null if response is empty', async () => { + requestMock.mockImplementation(() => ({ + data: { result: [] }, + })); + + const res = await service.getIncidentByCorrelationId('custom_correlation_id'); + + expect(requestMock).toHaveBeenCalledTimes(1); + expect(res).toBe(null); + }); + + test('it should call request with correct arguments when table changes', async () => { + service = createExternalService({ + credentials: { + config: { apiUrl: 'https://example.com/', isOAuth: false }, + secrets: { username: 'admin', password: 'admin' }, + }, + logger, + configurationUtilities, + serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, + axiosInstance: axios, + }); + + requestMock.mockImplementation(() => ({ + data: { result: [{ sys_id: '1', number: 'INC01' }] }, + })); + + await service.getIncidentByCorrelationId('custom_correlation_id'); + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/sn_si_incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', + method: 'get', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementationOnce(() => { + throw new Error('An error has occurred'); + }); + await expect(service.getIncidentByCorrelationId('custom_correlation_id')).rejects.toThrow( + '[Action][ServiceNow]: Unable to get incident by correlation ID custom_correlation_id. Error: An error has occurred Reason: unknown: errorResponse was null' + ); + }); + + test('it should throw an error when instance is not alive', async () => { + requestMock.mockImplementationOnce(() => ({ + status: 200, + data: {}, + request: { connection: { servername: 'Developer instance' } }, + })); + await expect(service.getIncident('1')).rejects.toThrow( + 'There is an issue with your Service Now Instance. Please check Developer instance.' + ); + }); + }); + describe('createIncident', () => { // new connectors describe('import set table', () => { @@ -574,6 +701,8 @@ describe('ServiceNow service', () => { test('it creates the incident correctly', async () => { mockIncidentResponse(false); + mockIncidentResponse(false); + const res = await service.createIncident({ incident: { short_description: 'title', description: 'desc' } as ServiceNowITSMIncident, }); @@ -608,6 +737,7 @@ describe('ServiceNow service', () => { axiosInstance: axios, }); + mockIncidentResponse(false); mockIncidentResponse(false); const res = await service.createIncident({ @@ -749,6 +879,8 @@ describe('ServiceNow service', () => { test('it updates the incident correctly', async () => { mockIncidentResponse(true); + mockIncidentResponse(true); + const res = await service.updateIncident({ incidentId: '1', incident: { short_description: 'title', description: 'desc' } as ServiceNowITSMIncident, @@ -785,6 +917,7 @@ describe('ServiceNow service', () => { }); mockIncidentResponse(false); + mockIncidentResponse(true); const res = await service.updateIncident({ incidentId: '1', @@ -805,6 +938,311 @@ describe('ServiceNow service', () => { }); }); + describe('closeIncident', () => { + // new connectors + describe('import set table', () => { + test('it closes the incident correctly with incident id', async () => { + const res = await closeIncident({ service, incidentId: '1', correlationId: null }); + + expect(res).toEqual({ + title: 'INC01', + id: '1', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://example.com/nav_to.do?uri=incident.do?sys_id=1', + }); + }); + + test('it should call request with correct arguments with incidentId', async () => { + const res = await closeIncident({ service, incidentId: '1', correlationId: null }); + expect(requestMock).toHaveBeenCalledTimes(4); + + expect(requestMock).toHaveBeenNthCalledWith(1, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/incident/1', + method: 'get', + }); + + expect(requestMock).toHaveBeenNthCalledWith(2, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', + method: 'get', + }); + + expect(requestMock).toHaveBeenNthCalledWith(3, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/import/x_elas2_inc_int_elastic_incident', + method: 'post', + data: { + elastic_incident_id: '1', + u_close_code: 'Closed/Resolved by Caller', + u_state: '7', + u_close_notes: 'Closed by Caller', + }, + }); + + expect(requestMock).toHaveBeenNthCalledWith(4, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/incident/1', + method: 'get', + }); + + expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); + }); + + test('it closes the incident correctly with correlation id', async () => { + const res = await closeIncident({ + service, + incidentId: null, + correlationId: 'custom_correlation_id', + }); + + expect(res).toEqual({ + title: 'INC01', + id: '1', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://example.com/nav_to.do?uri=incident.do?sys_id=1', + }); + }); + + test('it should call request with correct arguments with correlationId', async () => { + const res = await closeIncident({ + service, + incidentId: null, + correlationId: 'custom_correlation_id', + }); + + expect(requestMock).toHaveBeenCalledTimes(4); + + expect(requestMock).toHaveBeenNthCalledWith(1, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', + method: 'get', + }); + + expect(requestMock).toHaveBeenNthCalledWith(2, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', + method: 'get', + }); + + expect(requestMock).toHaveBeenNthCalledWith(3, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/import/x_elas2_inc_int_elastic_incident', + method: 'post', + data: { + elastic_incident_id: '1', + u_close_code: 'Closed/Resolved by Caller', + u_state: '7', + u_close_notes: 'Closed by Caller', + }, + }); + + expect(requestMock).toHaveBeenNthCalledWith(4, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/incident/1', + method: 'get', + }); + + expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); + }); + + test('it should throw an error when the incidentId and correlation Id are null', async () => { + await expect( + service.closeIncident({ incidentId: null, correlationId: null }) + ).rejects.toThrow( + '[Action][ServiceNow]: Unable to close incident. Error: No correlationId or incidentId found. Reason: unknown: errorResponse was null' + ); + }); + + test('it should throw an error when the no incidents found with given incidentId ', async () => { + const axiosError = { + message: 'Request failed with status code 404', + response: { status: 404 }, + } as AxiosError; + + requestMock.mockImplementation(() => { + throw axiosError; + }); + + const res = await service.closeIncident({ + incidentId: 'xyz', + correlationId: null, + }); + + expect(requestMock).toHaveBeenCalledTimes(1); + expect(logger.warn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "[ServiceNow][CloseIncident] No incident found with incidentId: xyz.", + ] + `); + expect(res).toBeNull(); + }); + + test('it should log warning if found incident is closed', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + result: { + sys_id: '1', + number: 'INC01', + state: '7', + sys_created_on: '2020-03-10 12:24:20', + }, + }, + })); + + await service.closeIncident({ incidentId: '1', correlationId: null }); + + expect(requestMock).toHaveBeenCalledTimes(1); + expect(logger.warn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "[ServiceNow][CloseIncident] Incident with correlation_id: null or incidentId: 1 is closed.", + ] + `); + }); + + test('it should return null if found incident with correlation id is null', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + result: [], + }, + })); + + const res = await service.closeIncident({ + incidentId: null, + correlationId: 'bar', + }); + + expect(requestMock).toHaveBeenCalledTimes(1); + expect(logger.warn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "[ServiceNow][CloseIncident] No incident found with correlation_id: bar or incidentId: null.", + ] + `); + expect(res).toBeNull(); + }); + + test('it should throw an error when instance is not alive', async () => { + mockIncidentResponse(false); + requestMock.mockImplementation(() => ({ + status: 200, + data: {}, + request: { connection: { servername: 'Developer instance' } }, + })); + await expect( + service.closeIncident({ + incidentId: '1', + correlationId: null, + }) + ).rejects.toThrow( + 'There is an issue with your Service Now Instance. Please check Developer instance.' + ); + }); + }); + + // old connectors + describe('table API', () => { + beforeEach(() => { + service = createExternalService({ + credentials: { + config: { apiUrl: 'https://example.com/', isOAuth: false }, + secrets: { username: 'admin', password: 'admin' }, + }, + logger, + configurationUtilities, + serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, + axiosInstance: axios, + }); + }); + + test('it closes the incident correctly', async () => { + mockIncidentResponse(false); + mockImportIncident(true); + mockIncidentResponse(true); + + const res = await service.closeIncident({ + incidentId: '1', + correlationId: null, + }); + + expect(res).toEqual({ + title: 'INC01', + id: '1', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://example.com/nav_to.do?uri=incident.do?sys_id=1', + }); + }); + + test('it should call request with correct arguments when table changes', async () => { + service = createExternalService({ + credentials: { + config: { apiUrl: 'https://example.com/', isOAuth: false }, + secrets: { username: 'admin', password: 'admin' }, + }, + logger, + configurationUtilities, + serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, + axiosInstance: axios, + }); + + mockIncidentResponse(false); + mockIncidentResponse(true); + mockIncidentResponse(true); + + const res = await service.closeIncident({ + incidentId: '1', + correlationId: null, + }); + + expect(requestMock).toHaveBeenNthCalledWith(1, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/sn_si_incident/1', + method: 'get', + }); + + expect(requestMock).toHaveBeenNthCalledWith(2, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/sn_si_incident/1', + method: 'patch', + data: { + close_code: 'Closed/Resolved by Caller', + state: '7', + close_notes: 'Closed by Caller', + }, + }); + + expect(requestMock).toHaveBeenNthCalledWith(3, { + axios, + logger, + configurationUtilities, + url: 'https://example.com/api/now/v2/table/sn_si_incident/1', + method: 'get', + }); + + expect(res?.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); + }); + }); + }); + describe('getFields', () => { test('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => ({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts index 3f1b7cd7cdc6..906c47c962d8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts @@ -17,6 +17,7 @@ import { ServiceNowIncident, GetApplicationInfoResponse, ServiceFactory, + ExternalServiceParamsClose, } from './types'; import * as i18n from './translations'; @@ -75,6 +76,10 @@ export const createExternalService: ServiceFactory = ({ return `${urlWithoutTrailingSlash}/nav_to.do?uri=${table}.do?sys_id=${id}`; }; + const getIncidentByCorrelationIdUrl = (correlationId: string) => { + return `${tableApiIncidentUrl}?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=${correlationId}`; + }; + const getChoicesURL = (fields: string[]) => { const elements = fields .slice(1) @@ -169,6 +174,7 @@ export const createExternalService: ServiceFactory = ({ params, configurationUtilities, }); + checkInstance(res); return res.data.result.length > 0 ? { ...res.data.result } : undefined; } catch (error) { @@ -249,6 +255,87 @@ export const createExternalService: ServiceFactory = ({ } }; + const getIncidentByCorrelationId = async ( + correlationId: string + ): Promise => { + try { + const res = await request({ + axios: axiosInstance, + url: getIncidentByCorrelationIdUrl(correlationId), + method: 'get', + logger, + configurationUtilities, + }); + + checkInstance(res); + + const foundIncident = res.data.result[0] ?? null; + + return foundIncident; + } catch (error) { + throw createServiceError(error, `Unable to get incident by correlation ID ${correlationId}`); + } + }; + + const closeIncident = async (params: ExternalServiceParamsClose) => { + try { + const { correlationId, incidentId } = params; + let incidentToBeClosed = null; + + if (correlationId == null && incidentId == null) { + throw new Error('No correlationId or incidentId found.'); + } + + if (incidentId) { + incidentToBeClosed = await getIncident(incidentId); + } else if (correlationId) { + incidentToBeClosed = await getIncidentByCorrelationId(correlationId); + } + + if (incidentToBeClosed === null) { + logger.warn( + `[ServiceNow][CloseIncident] No incident found with correlation_id: ${correlationId} or incidentId: ${incidentId}.` + ); + + return null; + } + + if (incidentToBeClosed.state === '7') { + logger.warn( + `[ServiceNow][CloseIncident] Incident with correlation_id: ${correlationId} or incidentId: ${incidentId} is closed.` + ); + + return { + title: incidentToBeClosed.number, + id: incidentToBeClosed.sys_id, + pushedDate: getPushedDate(incidentToBeClosed.sys_updated_on), + url: getIncidentViewURL(incidentToBeClosed.sys_id), + }; + } + + const closedIncident = await updateIncident({ + incidentId: incidentToBeClosed.sys_id, + incident: { + state: '7', // used for "closed" status in serviceNow + close_code: 'Closed/Resolved by Caller', + close_notes: 'Closed by Caller', + }, + }); + + return closedIncident; + } catch (error) { + if (error?.response?.status === 404) { + logger.warn( + `[ServiceNow][CloseIncident] No incident found with incidentId: ${params.incidentId}.` + ); + + return null; + } + + throw createServiceError(error, 'Unable to close incident'); + } + }; + const getFields = async () => { try { const res = await request({ @@ -292,5 +379,7 @@ export const createExternalService: ServiceFactory = ({ checkInstance, getApplicationInformation, checkIfApplicationIsInstalled, + closeIncident, + getIncidentByCorrelationId, }; }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts index dbd17e67d950..86d037c324e4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts @@ -26,6 +26,7 @@ import { ExecutorParamsSchemaITOM, ExecutorSubActionAddEventParamsSchema, ExternalIncidentServiceConfigurationBaseSchema, + ExecutorSubActionCloseIncidentParamsSchema, } from './schema'; import { SNProductsConfigValue } from '../../../../common/servicenow_config'; @@ -104,17 +105,26 @@ export interface ExternalServiceParamsUpdate { incident: PartialIncident & Record; } +export interface ExternalServiceParamsClose { + incidentId: string | null; + correlationId: string | null; +} + export interface ExternalService { getChoices: (fields: string[]) => Promise; getIncident: (id: string) => Promise; getFields: () => Promise; createIncident: (params: ExternalServiceParamsCreate) => Promise; updateIncident: (params: ExternalServiceParamsUpdate) => Promise; + closeIncident: ( + params: ExternalServiceParamsClose + ) => Promise; findIncidents: (params?: Record) => Promise; getUrl: () => string; checkInstance: (res: AxiosResponse) => void; getApplicationInformation: () => Promise; checkIfApplicationIsInstalled: () => Promise; + getIncidentByCorrelationId: (correlationId: string) => Promise; } export type PushToServiceApiParams = ExecutorSubActionPushParams; @@ -134,6 +144,10 @@ export type ExecutorSubActionHandshakeParams = TypeOf< typeof ExecutorSubActionHandshakeParamsSchema >; +export type ExecutorSubActionCloseIncidentParams = TypeOf< + typeof ExecutorSubActionCloseIncidentParamsSchema +>; + export type ServiceNowITSMIncident = Omit< TypeOf['incident'], 'externalId' @@ -155,6 +169,10 @@ export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs params: ExecutorSubActionGetIncidentParams; } +export interface CloseIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: ExecutorSubActionCloseIncidentParams; +} + export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { params: ExecutorSubActionHandshakeParams; } @@ -199,6 +217,9 @@ export interface ExternalServiceAPI { handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; + closeIncident: ( + args: CloseIncidentApiHandlerArgs + ) => Promise; } export interface ExternalServiceCommentResponse { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.test.ts index 79ca4a662608..f151affe8a59 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.test.ts @@ -28,6 +28,7 @@ jest.mock('@kbn/actions-plugin/server/lib/get_oauth_jwt_access_token', () => ({ jest.mock('axios', () => ({ create: jest.fn(), AxiosHeaders: jest.requireActual('axios').AxiosHeaders, + AxiosError: jest.requireActual('axios').AxiosError, })); const createAxiosInstanceMock = axios.create as jest.Mock; const axiosInstanceMock = { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.ts index 2e6ba5327ed2..44171d1a1194 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import axios, { AxiosHeaders, AxiosInstance, AxiosResponse } from 'axios'; +import axios, { AxiosError, AxiosHeaders, AxiosInstance, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { addTimeZoneToDate, getErrorMessage } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -42,14 +42,22 @@ const createErrorMessage = (errorResponse?: ServiceNowError): string => { : 'unknown: no error in error response'; }; -export const createServiceError = (error: ResponseError, message: string) => - new Error( +export const createServiceError = (error: ResponseError, message: string): AxiosError => { + const serviceError = new AxiosError( getErrorMessage( i18n.SERVICENOW, `${message}. Error: ${error.message} Reason: ${createErrorMessage(error.response?.data)}` ) ); + serviceError.code = error.code; + serviceError.config = error.config; + serviceError.request = error.request; + serviceError.response = error.response; + + return serviceError; +}; + export const getPushedDate = (timestamp?: string) => { if (timestamp != null) { return new Date(addTimeZoneToDate(timestamp)).toISOString(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.test.ts deleted file mode 100644 index 490f7f7cfc23..000000000000 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { initDashboard } from './create_dashboard'; -import { getDashboard } from './dashboard'; -import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; -import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; -import { Logger } from '@kbn/logging'; - -jest.mock('uuid', () => ({ - v4: jest.fn().mockReturnValue('12345'), -})); - -const logger = loggingSystemMock.create().get() as jest.Mocked; - -const savedObjectsClient = savedObjectsClientMock.create(); -describe('createDashboard', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it('fetches the Gen Ai Dashboard saved object', async () => { - const dashboardId = 'test-dashboard-id'; - const result = await initDashboard({ logger, savedObjectsClient, dashboardId }); - expect(result.success).toBe(true); - expect(logger.error).not.toHaveBeenCalled(); - expect(savedObjectsClient.get).toHaveBeenCalledWith('dashboard', dashboardId); - }); - - it('creates the Gen Ai Dashboard saved object when the dashboard saved object does not exist', async () => { - const dashboardId = 'test-dashboard-id'; - const soClient = { - ...savedObjectsClient, - get: jest.fn().mockRejectedValue({ - output: { - statusCode: 404, - payload: { - statusCode: 404, - error: 'Not Found', - message: 'Saved object [dashboard/generative-ai-token-usage-default] not found', - }, - headers: {}, - }, - }), - }; - const result = await initDashboard({ logger, savedObjectsClient: soClient, dashboardId }); - - expect(soClient.get).toHaveBeenCalledWith('dashboard', dashboardId); - expect(soClient.create).toHaveBeenCalledWith( - 'dashboard', - getDashboard(dashboardId).attributes, - { overwrite: true, id: dashboardId } - ); - expect(result.success).toBe(true); - }); - - it('handles an error when fetching the dashboard saved object', async () => { - const soClient = { - ...savedObjectsClient, - get: jest.fn().mockRejectedValue({ - output: { - statusCode: 500, - payload: { - statusCode: 500, - error: 'Internal Server Error', - message: 'Error happened', - }, - headers: {}, - }, - }), - }; - const dashboardId = 'test-dashboard-id'; - const result = await initDashboard({ logger, savedObjectsClient: soClient, dashboardId }); - expect(result.success).toBe(false); - expect(result.error?.message).toBe('Internal Server Error: Error happened'); - expect(result.error?.statusCode).toBe(500); - expect(soClient.get).toHaveBeenCalledWith('dashboard', dashboardId); - }); -}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.ts deleted file mode 100644 index 80c3bc8cc7f2..000000000000 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/create_dashboard.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; - -import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; -import { Logger } from '@kbn/logging'; -import { getDashboard } from './dashboard'; - -export interface OutputError { - message: string; - statusCode: number; -} - -export const initDashboard = async ({ - logger, - savedObjectsClient, - dashboardId, -}: { - logger: Logger; - savedObjectsClient: SavedObjectsClientContract; - dashboardId: string; -}): Promise<{ - success: boolean; - error?: OutputError; -}> => { - try { - await savedObjectsClient.get('dashboard', dashboardId); - return { - success: true, - }; - } catch (error) { - // if 404, does not yet exist. do not error, continue to create - if (error.output.statusCode !== 404) { - return { - success: false, - error: { - message: `${error.output.payload.error}${ - error.output.payload.message ? `: ${error.output.payload.message}` : '' - }`, - statusCode: error.output.statusCode, - }, - }; - } - } - - try { - await savedObjectsClient.create( - 'dashboard', - getDashboard(dashboardId).attributes, - { - overwrite: true, - id: dashboardId, - } - ); - logger.info(`Successfully created Gen Ai Dashboard ${dashboardId}`); - return { success: true }; - } catch (error) { - return { - success: false, - error: { message: error.message, statusCode: error.output.statusCode }, - }; - } -}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/dashboard.ts deleted file mode 100644 index 8503ef9bf59f..000000000000 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/dashboard.ts +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; -import { v4 as uuidv4 } from 'uuid'; -import { SavedObject } from '@kbn/core-saved-objects-common/src/server_types'; - -export const dashboardTitle = `OpenAI Token Usage`; - -export const getDashboard = (dashboardId: string): SavedObject => { - const ids: Record = { - genAiSavedObjectId: dashboardId, - tokens: uuidv4(), - totalTokens: uuidv4(), - tag: uuidv4(), - }; - return { - attributes: { - description: 'Displays OpenAI token consumption per Kibana user', - kibanaSavedObjectMeta: { - searchSourceJSON: - '{"query":{"query":"kibana.saved_objects: { type_id : \\".gen-ai\\" } ","language":"kuery"},"filter":[]}', - }, - optionsJSON: - '{"useMargins":true,"syncColors":false,"syncCursor":true,"syncTooltips":false,"hidePanelTitles":false}', - panelsJSON: JSON.stringify([ - { - version: '8.9.0', - type: 'visualization', - gridData: { - x: 0, - y: 0, - w: 48, - h: 4, - i: '1c425103-57a6-4598-a092-03b8d550b440', - }, - panelIndex: '1c425103-57a6-4598-a092-03b8d550b440', - embeddableConfig: { - savedVis: { - id: '', - title: '', - description: '', - type: 'markdown', - params: { - fontSize: 12, - openLinksInNewTab: false, - markdown: - // TODO: update with better copy and link to the docs page for the Gen AI connector before 8.9 release! - 'The data powering this dashboard requires special index permissions. To access the dashboard data, contact a Kibana admin to set up a "read only" role for non-admin users who may want to view this dashboard. ', - }, - uiState: {}, - data: { - aggs: [], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - filter: [], - }, - }, - }, - hidePanelTitles: false, - enhancements: {}, - }, - title: 'Permissions note', - }, - { - version: '8.9.0', - type: 'lens', - gridData: { - x: 0, - y: 0, - w: 48, - h: 20, - i: '1e45fe29-05d3-4dbd-a0bb-fc3bc5ee3d6d', - }, - panelIndex: '1e45fe29-05d3-4dbd-a0bb-fc3bc5ee3d6d', - embeddableConfig: { - attributes: { - title: '', - description: '', - visualizationType: 'lnsXY', - type: 'lens', - references: [], - state: { - visualization: { - title: 'Empty XY chart', - legend: { - isVisible: true, - position: 'right', - }, - valueLabels: 'hide', - preferredSeriesType: 'bar_stacked', - layers: [ - { - layerId: '475e8ca0-e78e-454a-8597-a5492f70dce3', - accessors: [ - '0f9814ec-0964-4efa-93a3-c7f173df2483', - 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - ], - position: 'top', - seriesType: 'bar_stacked', - showGridlines: false, - layerType: 'data', - xAccessor: '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', - yConfig: [ - { - forAccessor: '0f9814ec-0964-4efa-93a3-c7f173df2483', - color: '#9170b8', - }, - { - forAccessor: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - color: '#3383cd', - }, - ], - }, - ], - labelsOrientation: { - x: 0, - yLeft: 0, - yRight: 0, - }, - yTitle: 'Sum of OpenAI Completion + Prompt Tokens', - axisTitlesVisibilitySettings: { - x: true, - yLeft: true, - yRight: true, - }, - }, - query: { - query: 'kibana.saved_objects:{ type_id: ".gen-ai" }', - language: 'kuery', - }, - filters: [], - datasourceStates: { - formBased: { - layers: { - '475e8ca0-e78e-454a-8597-a5492f70dce3': { - columns: { - '0f9814ec-0964-4efa-93a3-c7f173df2483': { - label: 'OpenAI Completion Tokens', - dataType: 'number', - operationType: 'sum', - sourceField: 'kibana.action.execution.gen_ai.usage.completion_tokens', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: true, - }, - customLabel: true, - }, - '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519': { - label: 'user.name', - dataType: 'string', - operationType: 'terms', - scale: 'ordinal', - sourceField: 'user.name', - isBucketed: true, - params: { - size: 10000, - orderBy: { - type: 'custom', - }, - orderDirection: 'desc', - otherBucket: true, - missingBucket: false, - parentFormat: { - id: 'terms', - }, - include: [], - exclude: [], - includeIsRegex: false, - excludeIsRegex: false, - orderAgg: { - label: 'Sum of kibana.action.execution.openai.usage.total_tokens', - dataType: 'number', - operationType: 'sum', - sourceField: 'kibana.action.execution.gen_ai.usage.total_tokens', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: true, - }, - }, - secondaryFields: [], - }, - customLabel: true, - }, - 'b0e390e4-d754-4eb4-9fcc-4347dadda394': { - label: 'OpenAI Prompt Tokens', - dataType: 'number', - operationType: 'sum', - sourceField: 'kibana.action.execution.gen_ai.usage.prompt_tokens', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: true, - }, - customLabel: true, - }, - }, - columnOrder: [ - '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', - '0f9814ec-0964-4efa-93a3-c7f173df2483', - 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - ], - sampling: 1, - incompleteColumns: {}, - }, - }, - }, - textBased: { - layers: {}, - }, - }, - internalReferences: [ - { - type: 'index-pattern', - id: ids.tokens, - name: 'indexpattern-datasource-layer-475e8ca0-e78e-454a-8597-a5492f70dce3', - }, - ], - adHocDataViews: { - [ids.tokens]: { - id: ids.tokens, - title: '.kibana-event-log-*', - timeFieldName: '@timestamp', - sourceFilters: [], - fieldFormats: {}, - runtimeFieldMap: { - 'kibana.action.execution.gen_ai.usage.completion_tokens': { - type: 'long', - }, - 'kibana.action.execution.gen_ai.usage.prompt_tokens': { - type: 'long', - }, - }, - fieldAttrs: {}, - allowNoIndex: false, - name: 'Event Log', - }, - }, - }, - }, - hidePanelTitles: false, - enhancements: {}, - }, - title: 'Prompt + Completion Tokens per User', - }, - { - version: '8.9.0', - type: 'lens', - gridData: { - x: 0, - y: 20, - w: 48, - h: 20, - i: '80f745c6-a18b-492b-bacf-4a2499a2f95d', - }, - panelIndex: '80f745c6-a18b-492b-bacf-4a2499a2f95d', - embeddableConfig: { - attributes: { - title: '', - description: '', - visualizationType: 'lnsXY', - type: 'lens', - references: [], - state: { - visualization: { - title: 'Empty XY chart', - legend: { - isVisible: true, - position: 'right', - }, - valueLabels: 'hide', - preferredSeriesType: 'bar_stacked', - layers: [ - { - layerId: '475e8ca0-e78e-454a-8597-a5492f70dce3', - accessors: ['b0e390e4-d754-4eb4-9fcc-4347dadda394'], - position: 'top', - seriesType: 'bar_stacked', - showGridlines: false, - layerType: 'data', - xAccessor: '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', - yConfig: [ - { - forAccessor: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - color: '#332182', - }, - ], - }, - ], - }, - query: { - query: 'kibana.saved_objects: { type_id : ".gen-ai" } ', - language: 'kuery', - }, - filters: [], - datasourceStates: { - formBased: { - layers: { - '475e8ca0-e78e-454a-8597-a5492f70dce3': { - columns: { - '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519': { - label: 'user.name', - dataType: 'string', - operationType: 'terms', - scale: 'ordinal', - sourceField: 'user.name', - isBucketed: true, - params: { - size: 10000, - orderBy: { - type: 'column', - columnId: 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - }, - orderDirection: 'desc', - otherBucket: true, - missingBucket: false, - parentFormat: { - id: 'terms', - }, - include: [], - exclude: [], - includeIsRegex: false, - excludeIsRegex: false, - }, - customLabel: true, - }, - 'b0e390e4-d754-4eb4-9fcc-4347dadda394': { - label: 'Sum of OpenAI Total Tokens', - dataType: 'number', - operationType: 'sum', - sourceField: 'kibana.action.execution.gen_ai.usage.total_tokens', - isBucketed: false, - scale: 'ratio', - params: { - emptyAsNull: true, - }, - customLabel: true, - }, - }, - columnOrder: [ - '5352fcb2-7b8e-4b5a-bce9-73a7f3b2b519', - 'b0e390e4-d754-4eb4-9fcc-4347dadda394', - ], - sampling: 1, - incompleteColumns: {}, - }, - }, - }, - textBased: { - layers: {}, - }, - }, - internalReferences: [ - { - type: 'index-pattern', - id: ids.totalTokens, - name: 'indexpattern-datasource-layer-475e8ca0-e78e-454a-8597-a5492f70dce3', - }, - ], - adHocDataViews: { - [ids.totalTokens]: { - id: ids.totalTokens, - title: '.kibana-event-log-*', - timeFieldName: '@timestamp', - sourceFilters: [], - fieldFormats: {}, - runtimeFieldMap: { - 'kibana.action.execution.gen_ai.usage.total_tokens': { - type: 'long', - }, - }, - fieldAttrs: {}, - allowNoIndex: false, - name: 'Event Log', - }, - }, - }, - }, - hidePanelTitles: false, - enhancements: {}, - }, - title: 'Total Tokens per User', - }, - ]), - timeRestore: false, - title: dashboardTitle, - version: 1, - }, - coreMigrationVersion: '8.8.0', - created_at: '2023-06-01T19:00:04.629Z', - id: ids.genAiSavedObjectId, - managed: false, - type: 'dashboard', - typeMigrationVersion: '8.7.0', - updated_at: '2023-06-01T19:00:04.629Z', - references: [], - }; -}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index e214047a5c6d..da7d3ef05f35 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -16,8 +16,9 @@ import { import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/openai/schema'; -import { initDashboard } from './create_dashboard'; -jest.mock('./create_dashboard'); +import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; +import { PassThrough, Transform } from 'stream'; +jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); describe('OpenAIConnector', () => { let mockRequest: jest.Mock; @@ -33,6 +34,9 @@ describe('OpenAIConnector', () => { role: 'assistant', content: mockResponseString, }, + delta: { + content: mockResponseString, + }, finish_reason: 'stop', index: 0, }, @@ -268,6 +272,56 @@ describe('OpenAIConnector', () => { }); }); + describe('invokeStream', () => { + const mockStream = ( + dataToStream: string[] = [ + 'data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"My"}}]}\ndata: {"object":"chat.completion.chunk","choices":[{"delta":{"content":" new"}}]}', + ] + ) => { + const streamMock = createStreamMock(); + dataToStream.forEach((chunk) => { + streamMock.write(chunk); + }); + streamMock.complete(); + mockRequest = jest.fn().mockResolvedValue({ ...mockResponse, data: streamMock.transform }); + return mockRequest; + }; + beforeEach(() => { + // @ts-ignore + connector.request = mockStream(); + }); + + it('the API call is successful with correct request parameters', async () => { + await connector.invokeStream(sampleOpenAiBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), + headers: { + Authorization: 'Bearer 123', + 'content-type': 'application/json', + }, + }); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.invokeStream(sampleOpenAiBody)).rejects.toThrow('API Error'); + }); + + it('responds with a readable stream', async () => { + // @ts-ignore + connector.request = mockStream(); + const response = await connector.invokeStream(sampleOpenAiBody); + expect(response instanceof PassThrough).toEqual(true); + }); + }); + describe('invokeAI', () => { it('the API call is successful with correct parameters', async () => { const response = await connector.invokeAI(sampleOpenAiBody); @@ -598,3 +652,21 @@ describe('OpenAIConnector', () => { }); }); }); + +function createStreamMock() { + const transform: Transform = new Transform({}); + + return { + write: (data: string) => { + transform.push(data); + }, + fail: () => { + transform.emit('error', new Error('Stream failed')); + transform.end(); + }, + transform, + complete: () => { + transform.end(); + }, + }; +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts index 7680cae94db9..88ad3a0d3da7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts @@ -7,6 +7,8 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; +import { IncomingMessage } from 'http'; +import { PassThrough } from 'stream'; import { RunActionParamsSchema, RunActionResponseSchema, @@ -29,7 +31,7 @@ import { InvokeAIActionParams, InvokeAIActionResponse, } from '../../../common/openai/types'; -import { initDashboard } from './create_dashboard'; +import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { getAxiosOptions, getRequestWithStreamOption, @@ -82,6 +84,12 @@ export class OpenAIConnector extends SubActionConnector { method: 'invokeAI', schema: InvokeAIActionParamsSchema, }); + + this.registerSubAction({ + name: SUB_ACTION.INVOKE_STREAM, + method: 'invokeStream', + schema: InvokeAIActionParamsSchema, + }); } protected getResponseErrorMessage(error: AxiosError<{ error?: { message?: string } }>): string { @@ -179,15 +187,31 @@ export class OpenAIConnector extends SubActionConnector { logger: this.logger, savedObjectsClient: this.savedObjectsClient, dashboardId, + genAIProvider: 'OpenAI', }); return { available: response.success }; } /** - * takes an array of messages and a model as input and returns a promise that resolves to a string. - * Sends the stringified input to the runApi method. Returns the trimmed completion from the response. - * @param body An object containing array of message objects, and possible other OpenAI properties + * Responsible for invoking the streamApi method with the provided body and + * stream parameters set to true. It then returns a Transform stream that processes + * the response from the streamApi method and returns the response string alone. + * @param body - the OpenAI Invoke request body + */ + public async invokeStream(body: InvokeAIActionParams): Promise { + const res = (await this.streamApi({ + body: JSON.stringify(body), + stream: true, + })) as unknown as IncomingMessage; + + return res.pipe(new PassThrough()); + } + + /** + * Deprecated. Use invokeStream instead. + * TODO: remove once streaming work is implemented in langchain mode for security solution + * tracked here: https://github.com/elastic/security-team/issues/7363 */ public async invokeAI(body: InvokeAIActionParams): Promise { const res = await this.runApi({ body: JSON.stringify(body) }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.test.ts index 876658e3f0ac..a4cb190a8558 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.test.ts @@ -23,6 +23,7 @@ jest.mock('./api', () => ({ getIncident: jest.fn(), handshake: jest.fn(), pushToService: jest.fn(), + closeIncident: jest.fn(), }, })); @@ -75,6 +76,33 @@ describe('ServiceNow', () => { 'work_notes' ); }); + + test('calls closeIncident sub action correctly', async () => { + const actionId = 'some-action-id'; + const executorOptions = { + actionId, + config, + secrets, + params: { + subAction: 'closeIncident', + subActionParams: { + incident: { + correlationId: 'custom_correlation_id', + externalId: null, + }, + }, + }, + services, + logger: mockedLogger, + } as unknown as ServiceNowConnectorTypeExecutorOptions< + ServiceNowPublicConfigurationType, + ExecutorParams + >; + await connectorType.executor(executorOptions); + expect( + (api.closeIncident as jest.Mock).mock.calls[0][0].params.incident.correlationId + ).toBe('custom_correlation_id'); + }); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts index ccfdb7810a04..0322b0e34184 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts @@ -41,6 +41,7 @@ import { ServiceNowExecutorResultData, ServiceNowPublicConfigurationType, ServiceNowSecretConfigurationType, + ExecutorSubActionCloseIncidentParams, } from '../lib/servicenow/types'; import { ServiceNowITSMConnectorTypeId, @@ -102,7 +103,13 @@ export function getServiceNowITSMConnectorType(): ServiceNowConnectorType< } // action executor -const supportedSubActions: string[] = ['getFields', 'pushToService', 'getChoices', 'getIncident']; +const supportedSubActions: string[] = [ + 'getFields', + 'pushToService', + 'getChoices', + 'getIncident', + 'closeIncident', +]; async function executor( { actionTypeId, @@ -173,5 +180,14 @@ async function executor( }); } + if (subAction === 'closeIncident') { + const closeIncidentParams = subActionParams as ExecutorSubActionCloseIncidentParams; + data = await api.closeIncident({ + externalService, + params: closeIncidentParams, + logger, + }); + } + return { status: 'ok', data: data ?? {}, actionId }; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index dce1d08bceb1..1c068dc60489 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -17,7 +17,10 @@ import { serviceNowCommonFields, serviceNowChoices } from '../lib/servicenow/moc import { snExternalServiceConfig } from '../lib/servicenow/config'; const logger = loggingSystemMock.create().get() as jest.Mocked; -jest.mock('axios'); +jest.mock('axios', () => ({ + create: jest.fn(), + AxiosError: jest.requireActual('axios').AxiosError, +})); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { const originalUtils = jest.requireActual('@kbn/actions-plugin/server/lib/axios_utils'); return { diff --git a/x-pack/plugins/synthetics/common/constants/monitor_defaults.ts b/x-pack/plugins/synthetics/common/constants/monitor_defaults.ts index e722801c12c1..b46e839807be 100644 --- a/x-pack/plugins/synthetics/common/constants/monitor_defaults.ts +++ b/x-pack/plugins/synthetics/common/constants/monitor_defaults.ts @@ -10,7 +10,7 @@ import { BrowserAdvancedFields, BrowserSimpleFields, CommonFields, - DataStream, + MonitorTypeEnum, FormMonitorType, HTTPAdvancedFields, HTTPMethod, @@ -129,7 +129,7 @@ export const ALLOWED_SCHEDULES_IN_MINUTES = [ ]; export const DEFAULT_COMMON_FIELDS: CommonFields = { - [ConfigKey.MONITOR_TYPE]: DataStream.HTTP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.HTTP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP, [ConfigKey.ENABLED]: true, [ConfigKey.ALERT_CONFIG]: { status: { enabled: true }, tls: { enabled: true } }, @@ -171,7 +171,7 @@ export const DEFAULT_BROWSER_SIMPLE_FIELDS: BrowserSimpleFields = { file_name: '', }, }, - [ConfigKey.MONITOR_TYPE]: DataStream.BROWSER, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.BROWSER, [ConfigKey.PORT]: null, [ConfigKey.SCHEDULE]: { unit: ScheduleUnit.MINUTES, @@ -192,7 +192,7 @@ export const DEFAULT_HTTP_SIMPLE_FIELDS: HTTPSimpleFields = { }, [ConfigKey.URLS]: '', [ConfigKey.MAX_REDIRECTS]: '0', - [ConfigKey.MONITOR_TYPE]: DataStream.HTTP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.HTTP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.HTTP, [ConfigKey.PORT]: null, }; @@ -224,7 +224,7 @@ export const DEFAULT_HTTP_ADVANCED_FIELDS: HTTPAdvancedFields = { export const DEFAULT_ICMP_SIMPLE_FIELDS: ICMPSimpleFields = { ...DEFAULT_COMMON_FIELDS, [ConfigKey.HOSTS]: '', - [ConfigKey.MONITOR_TYPE]: DataStream.ICMP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.ICMP, [ConfigKey.WAIT]: '1', [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.ICMP, }; @@ -236,7 +236,7 @@ export const DEFAULT_TCP_SIMPLE_FIELDS: TCPSimpleFields = { }, [ConfigKey.HOSTS]: '', [ConfigKey.URLS]: '', - [ConfigKey.MONITOR_TYPE]: DataStream.TCP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.TCP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.TCP, [ConfigKey.PORT]: null, }; @@ -267,21 +267,21 @@ export const DEFAULT_TLS_FIELDS: TLSFields = { }; export const DEFAULT_FIELDS: MonitorDefaults = { - [DataStream.HTTP]: { + [MonitorTypeEnum.HTTP]: { ...DEFAULT_HTTP_SIMPLE_FIELDS, ...DEFAULT_HTTP_ADVANCED_FIELDS, ...DEFAULT_TLS_FIELDS, }, - [DataStream.TCP]: { + [MonitorTypeEnum.TCP]: { ...DEFAULT_TCP_SIMPLE_FIELDS, ...DEFAULT_TCP_ADVANCED_FIELDS, ...DEFAULT_TLS_FIELDS, }, - [DataStream.ICMP]: { + [MonitorTypeEnum.ICMP]: { ...DEFAULT_ICMP_SIMPLE_FIELDS, ...DEFAULT_ICMP_ADVANCED_FIELDS, }, - [DataStream.BROWSER]: { + [MonitorTypeEnum.BROWSER]: { ...DEFAULT_BROWSER_SIMPLE_FIELDS, ...DEFAULT_BROWSER_ADVANCED_FIELDS, ...DEFAULT_TLS_FIELDS, diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts index 5cbf2efbe62f..428f8ffe043b 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts @@ -8,15 +8,14 @@ import * as t from 'io-ts'; import { tEnum } from '../../utils/t_enum'; -export enum DataStream { +export enum MonitorTypeEnum { HTTP = 'http', TCP = 'tcp', ICMP = 'icmp', BROWSER = 'browser', } -export const DataStreamCodec = tEnum('DataStream', DataStream); -export type DataStreamType = t.TypeOf; +export const MonitorTypeCodec = tEnum('MonitorType', MonitorTypeEnum); export enum HTTPMethod { GET = 'GET', @@ -26,9 +25,6 @@ export enum HTTPMethod { HEAD = 'HEAD', } -export const HTTPMethodCodec = tEnum('HTTPMethod', HTTPMethod); -export type HTTPMethodType = t.TypeOf; - export enum ResponseBodyIndexPolicy { ALWAYS = 'always', NEVER = 'never', @@ -39,7 +35,6 @@ export const ResponseBodyIndexPolicyCodec = tEnum( 'ResponseBodyIndexPolicy', ResponseBodyIndexPolicy ); -export type ResponseBodyIndexPolicyType = t.TypeOf; export enum MonacoEditorLangId { JSON = 'xjson', @@ -48,12 +43,6 @@ export enum MonacoEditorLangId { JAVASCRIPT = 'javascript', } -export const MonacoEditorLangIdCodec = tEnum( - 'MonacoEditorLangId', - MonacoEditorLangId -); -export type MonacoEditorLangIdType = t.TypeOf; - export enum CodeEditorMode { FORM = 'form', JSON = 'json', @@ -62,7 +51,6 @@ export enum CodeEditorMode { } export const CodeEditorModeCodec = tEnum('CodeEditorMode', CodeEditorMode); -export type CodeEditorModeType = t.TypeOf; export enum ContentType { JSON = 'application/json', @@ -71,16 +59,12 @@ export enum ContentType { FORM = 'application/x-www-form-urlencoded', } -export const ContentTypeCodec = tEnum('ContentType', ContentType); -export type ContentTypeType = t.TypeOf; - export enum ScheduleUnit { MINUTES = 'm', SECONDS = 's', } export const ScheduleUnitCodec = tEnum('ScheduleUnit', ScheduleUnit); -export type ScheduleUnitType = t.TypeOf; export enum VerificationMode { CERTIFICATE = 'certificate', @@ -90,7 +74,6 @@ export enum VerificationMode { } export const VerificationModeCodec = tEnum('VerificationMode', VerificationMode); -export type VerificationModeType = t.TypeOf; export enum TLSVersion { ONE_ZERO = 'TLSv1.0', @@ -100,7 +83,6 @@ export enum TLSVersion { } export const TLSVersionCodec = tEnum('TLSVersion', TLSVersion); -export type TLSVersionType = t.TypeOf; export enum ScreenshotOption { ON = 'on', @@ -109,7 +91,6 @@ export enum ScreenshotOption { } export const ScreenshotOptionCodec = tEnum('ScreenshotOption', ScreenshotOption); -export type ScreenshotOptionType = t.TypeOf; export enum SourceType { UI = 'ui', @@ -133,7 +114,6 @@ export enum Mode { ALL = 'all', } export const ModeCodec = tEnum('Mode', Mode); -export type ModeType = t.TypeOf; export const ResponseCheckJSONCodec = t.interface({ description: t.string, diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts index 27c55ade654c..d5cae36999aa 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts @@ -11,8 +11,8 @@ import { secretKeys } from '../../constants/monitor_management'; import { ConfigKey } from './config_key'; import { MonitorServiceLocationCodec, ServiceLocationErrors } from './locations'; import { - DataStream, - DataStreamCodec, + MonitorTypeEnum, + MonitorTypeCodec, FormMonitorTypeCodec, ModeCodec, ResponseBodyIndexPolicyCodec, @@ -55,7 +55,7 @@ export const CommonFieldsCodec = t.intersection([ t.interface({ [ConfigKey.NAME]: t.string, [ConfigKey.NAMESPACE]: t.string, - [ConfigKey.MONITOR_TYPE]: DataStreamCodec, + [ConfigKey.MONITOR_TYPE]: MonitorTypeCodec, [ConfigKey.ENABLED]: t.boolean, [ConfigKey.SCHEDULE]: ScheduleCodec, [ConfigKey.APM_SERVICE_NAME]: t.string, @@ -350,10 +350,10 @@ export const EncryptedSyntheticsSavedMonitorCodec = t.intersection([ ]); export const MonitorDefaultsCodec = t.interface({ - [DataStream.HTTP]: HTTPFieldsCodec, - [DataStream.TCP]: TCPFieldsCodec, - [DataStream.ICMP]: ICMPSimpleFieldsCodec, - [DataStream.BROWSER]: BrowserFieldsCodec, + [MonitorTypeEnum.HTTP]: HTTPFieldsCodec, + [MonitorTypeEnum.TCP]: TCPFieldsCodec, + [MonitorTypeEnum.ICMP]: ICMPSimpleFieldsCodec, + [MonitorTypeEnum.BROWSER]: BrowserFieldsCodec, }); export const MonitorManagementListResultCodec = t.type({ diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_inspect.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_inspect.tsx index 32b930ddfee2..6fa6bf7d320e 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_inspect.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_inspect.tsx @@ -27,7 +27,7 @@ import { import { ClientPluginsStart } from '../../../../../plugin'; import { useSyntheticsSettingsContext } from '../../../contexts'; import { LoadingState } from '../../monitors_page/overview/overview/monitor_detail_flyout'; -import { DataStream, MonitorFields } from '../../../../../../common/runtime_types'; +import { MonitorTypeEnum, MonitorFields } from '../../../../../../common/runtime_types'; import { inspectMonitorAPI, MonitorInspectResponse } from '../../../state/monitor_management/api'; interface InspectorProps { @@ -159,7 +159,7 @@ const formatContent = (result: MonitorInspectResponse) => { const currentInput = result.privateConfig?.inputs.find((input) => input.enabled); const compiledConfig = currentInput?.streams.find((stream) => - Object.values(DataStream).includes(stream.data_stream.dataset as DataStream) + Object.values(MonitorTypeEnum).includes(stream.data_stream.dataset as MonitorTypeEnum) )?.compiled_stream; return JSON.stringify( diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_type_badge.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_type_badge.tsx index 5664d30761a9..49c7bde90de5 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_type_badge.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/monitor_type_badge.tsx @@ -12,7 +12,7 @@ import { EncryptedSyntheticsMonitor, ConfigKey, FormMonitorType, - DataStream, + MonitorTypeEnum, } from '../../../../../../common/runtime_types'; export function MonitorTypeBadge({ @@ -55,7 +55,7 @@ function getMonitorTypeBadgeTitle(monitor: EncryptedSyntheticsMonitor) { } switch (monitor?.type) { - case DataStream.BROWSER: + case MonitorTypeEnum.BROWSER: return 'Journey'; default: return monitor?.type?.toUpperCase(); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/view_document.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/view_document.tsx index 8f03ab6190af..e9d6e4e650b4 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/view_document.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/view_document.tsx @@ -6,13 +6,9 @@ */ import { EuiButtonIcon, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; +import { UnifiedDocViewer, useEsDocSearch } from '@kbn/unified-doc-viewer-plugin/public'; import React, { useState, MouseEvent } from 'react'; -import { useUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; import { i18n } from '@kbn/i18n'; -import { useFetcher } from '@kbn/observability-shared-plugin/public'; -import { DataTableRecord } from '@kbn/discover-utils/src/types'; import { useDateFormat } from '../../../../../hooks/use_date_format'; import { LoadingState } from '../../monitors_page/overview/overview/monitor_detail_flyout'; import { useSyntheticsDataView } from '../../../contexts/synthetics_data_view_context'; @@ -20,35 +16,12 @@ import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants'; import { Ping } from '../../../../../../common/runtime_types'; export const ViewDocument = ({ ping }: { ping: Ping }) => { - const { data } = useUnifiedDocViewerServices(); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); const dataView = useSyntheticsDataView(); const formatter = useDateFormat(); - const { data: hit } = useFetcher>(async () => { - if (!dataView?.id || !isFlyoutVisible) return; - const response = await data.search - .search({ - params: { - index: SYNTHETICS_INDEX_PATTERN, - body: { - query: { - ids: { - values: [ping.docId], - }, - }, - fields: ['*'], - _source: false, - }, - }, - }) - .toPromise(); - const docs = response?.rawResponse?.hits?.hits ?? []; - if (docs.length > 0) { - return buildDataTableRecord(docs[0], dataView); - } - }, [data, dataView, ping.docId, isFlyoutVisible]); + const [, hit] = useEsDocSearch({ id: ping.docId, index: SYNTHETICS_INDEX_PATTERN, dataView }); return ( <> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/use_simple_monitor.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/use_simple_monitor.ts index 070bb39d9d96..d014891f5346 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/use_simple_monitor.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/use_simple_monitor.ts @@ -16,7 +16,7 @@ import { createGettingStartedMonitor, UpsertMonitorResponse } from '../../state' import { DEFAULT_FIELDS } from '../../../../../common/constants/monitor_defaults'; import { ConfigKey } from '../../../../../common/constants/monitor_management'; import { - DataStream, + MonitorTypeEnum, EncryptedSyntheticsSavedMonitor, ServiceLocationErrors, } from '../../../../../common/runtime_types'; @@ -47,7 +47,7 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData 'source.inline.script': `step('Go to ${urls}', async () => { await page.goto('${urls}'); });`, - [ConfigKey.MONITOR_TYPE]: DataStream.BROWSER, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.BROWSER, [ConfigKey.NAME]: urls, [ConfigKey.LOCATIONS]: locations, [ConfigKey.URLS]: urls, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.test.tsx index 90652b609db6..f4d2b3d0e3ed 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ConfigKey, DataStream, FormMonitorType, SyntheticsMonitor } from '../types'; +import { ConfigKey, MonitorTypeEnum, FormMonitorType, SyntheticsMonitor } from '../types'; import { DEFAULT_FIELDS, PROFILE_VALUES_ENUM, PROFILES_MAP } from '../constants'; import { formatDefaultFormValues } from './defaults'; @@ -128,13 +128,13 @@ describe('defaults', () => { }); it.each([ - [DataStream.HTTP, true], - [DataStream.HTTP, false], - [DataStream.TCP, true], - [DataStream.TCP, false], + [MonitorTypeEnum.HTTP, true], + [MonitorTypeEnum.HTTP, false], + [MonitorTypeEnum.TCP, true], + [MonitorTypeEnum.TCP, false], ])('correctly formats isTLSEnabled', (formType, isTLSEnabled) => { const monitor = { - ...DEFAULT_FIELDS[formType as DataStream], + ...DEFAULT_FIELDS[formType as MonitorTypeEnum], [ConfigKey.FORM_MONITOR_TYPE]: formType as unknown as FormMonitorType, [ConfigKey.TLS_CERTIFICATE_AUTHORITIES]: 'mockCA', [ConfigKey.METADATA]: { @@ -149,10 +149,10 @@ describe('defaults', () => { }); it.each([ - [DataStream.HTTP, FormMonitorType.HTTP], - [DataStream.TCP, FormMonitorType.TCP], - [DataStream.ICMP, FormMonitorType.ICMP], - [DataStream.BROWSER, FormMonitorType.MULTISTEP], + [MonitorTypeEnum.HTTP, FormMonitorType.HTTP], + [MonitorTypeEnum.TCP, FormMonitorType.TCP], + [MonitorTypeEnum.ICMP, FormMonitorType.ICMP], + [MonitorTypeEnum.BROWSER, FormMonitorType.MULTISTEP], ])( 'correctly formats legacy uptime monitors to include ConfigKey.FORM_MONITOR_TYPE', (dataStream, formType) => { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.tsx index ba63d7c1d75a..f24117f10166 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/defaults.tsx @@ -9,7 +9,7 @@ import { DEFAULT_FIELDS } from '../constants'; import { ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, SyntheticsMonitor, BrowserFields, @@ -22,7 +22,7 @@ export const getDefaultFormFields = ( const kibanaNamespace = formatKibanaNamespace(spaceId); return { [FormMonitorType.MULTISTEP]: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], 'source.inline': { type: 'recorder', script: '', @@ -32,24 +32,24 @@ export const getDefaultFormFields = ( [ConfigKey.NAMESPACE]: kibanaNamespace, }, [FormMonitorType.SINGLE]: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.SINGLE, [ConfigKey.NAMESPACE]: kibanaNamespace, }, [FormMonitorType.HTTP]: { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], isTLSEnabled: false, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.HTTP, [ConfigKey.NAMESPACE]: kibanaNamespace, }, [FormMonitorType.TCP]: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], isTLSEnabled: false, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.TCP, [ConfigKey.NAMESPACE]: kibanaNamespace, }, [FormMonitorType.ICMP]: { - ...DEFAULT_FIELDS[DataStream.ICMP], + ...DEFAULT_FIELDS[MonitorTypeEnum.ICMP], [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.ICMP, [ConfigKey.NAMESPACE]: kibanaNamespace, }, @@ -68,9 +68,9 @@ export const formatDefaultFormValues = (monitor?: SyntheticsMonitor) => { // handle default monitor types from Uptime, which don't contain `ConfigKey.FORM_MONITOR_TYPE` if (!formMonitorType) { formMonitorType = - monitorType === DataStream.BROWSER + monitorType === MonitorTypeEnum.BROWSER ? FormMonitorType.MULTISTEP - : (monitorType as Omit as FormMonitorType); + : (monitorType as Omit as FormMonitorType); monitorWithFormMonitorType[ConfigKey.FORM_MONITOR_TYPE] = formMonitorType; } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx index ddc1c27d6e7e..b80c4ccb773b 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx @@ -64,7 +64,7 @@ import { getDocLinks } from '../../../../../kibana_services'; import { useMonitorName } from '../../../hooks/use_monitor_name'; import { ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, HTTPMethod, ScreenshotOption, @@ -869,7 +869,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ validation: () => ({ validate: { validResponseStatusCheck: (value) => { - const validateFn = validate[DataStream.HTTP][ConfigKey.RESPONSE_STATUS_CHECK]; + const validateFn = validate[MonitorTypeEnum.HTTP][ConfigKey.RESPONSE_STATUS_CHECK]; if (validateFn) { return !validateFn({ [ConfigKey.RESPONSE_STATUS_CHECK]: value, @@ -1049,7 +1049,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ validation: () => ({ validate: { validParams: (value) => { - const validateFn = validate[DataStream.BROWSER][ConfigKey.PARAMS]; + const validateFn = validate[MonitorTypeEnum.BROWSER][ConfigKey.PARAMS]; if (validateFn) { return validateFn({ [ConfigKey.PARAMS]: value, @@ -1335,7 +1335,7 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ validation: () => ({ validate: { validPlaywrightOptions: (value) => { - const validateFn = validate[DataStream.BROWSER][ConfigKey.PLAYWRIGHT_OPTIONS]; + const validateFn = validate[MonitorTypeEnum.BROWSER][ConfigKey.PLAYWRIGHT_OPTIONS]; if (validateFn) { return validateFn({ [ConfigKey.PLAYWRIGHT_OPTIONS]: value, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.test.tsx index 3b6a815771c7..56f6093f5a43 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.test.tsx @@ -6,7 +6,7 @@ */ import { format, ALLOWED_FIELDS } from './formatter'; -import { DataStream } from '../../../../../../common/runtime_types'; +import { MonitorTypeEnum } from '../../../../../../common/runtime_types'; import { DEFAULT_FIELDS, PROFILE_VALUES_ENUM, @@ -112,7 +112,7 @@ describe('format', () => { it.each([[true], [false]])('correctly formats form fields to monitor type', (enabled) => { formValues.enabled = enabled; expect(format(formValues)).toEqual({ - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: false, }, @@ -245,7 +245,7 @@ describe('format', () => { }, }; expect(format(browserFormFields)).toEqual({ - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], __ui: { script_source: { file_name: fileName, @@ -314,7 +314,7 @@ describe('format', () => { }, }) ).toEqual({ - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: isTLSEnabled, }, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.ts index 62f0919cb687..d6ec887f324c 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/formatter.ts @@ -5,11 +5,11 @@ * 2.0. */ import { get, pick } from 'lodash'; -import { ConfigKey, DataStream, FormMonitorType, MonitorFields } from '../types'; +import { ConfigKey, MonitorTypeEnum, FormMonitorType, MonitorFields } from '../types'; import { DEFAULT_FIELDS } from '../constants'; export const serializeNestedFormField = (fields: Record) => { - const monitorType = fields[ConfigKey.MONITOR_TYPE] as DataStream; + const monitorType = fields[ConfigKey.MONITOR_TYPE] as MonitorTypeEnum; const monitorFields: Record = {}; const defaults = DEFAULT_FIELDS[monitorType] as MonitorFields; Object.keys(defaults).map((key) => { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.test.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.test.ts index 4b4e524c9f3b..0cbbfa5d9131 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.test.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.test.ts @@ -7,7 +7,7 @@ import { ConfigKey, - DataStream, + MonitorTypeEnum, HTTPFields, BrowserFields, MonitorFields, @@ -32,7 +32,7 @@ describe('[Monitor Management] validation', () => { }; it('should return false for all valid props', () => { - const validators = validate[DataStream.HTTP]; + const validators = validate[MonitorTypeEnum.HTTP]; const keysToValidate = [ ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, @@ -52,7 +52,7 @@ describe('[Monitor Management] validation', () => { describe.each([[ConfigKey.SOURCE_INLINE, 'step(() => {});']])('Browser', (configKey, value) => { const browserProps: Partial = { ...commonPropsValid, - [ConfigKey.MONITOR_TYPE]: DataStream.BROWSER, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.BROWSER, [ConfigKey.TIMEOUT]: null, [ConfigKey.URLS]: null, [ConfigKey.PORT]: null, @@ -60,7 +60,7 @@ describe('[Monitor Management] validation', () => { }; it('should return false for all valid props', () => { - const validators = validate[DataStream.BROWSER]; + const validators = validate[MonitorTypeEnum.BROWSER]; const keysToValidate = [ConfigKey.SCHEDULE, ConfigKey.TIMEOUT, configKey]; const validatorFns = keysToValidate.map((key) => validators[key]); const result = validatorFns.map((fn) => fn?.(browserProps as Partial) ?? true); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.tsx index 332ee8e6fbc5..c22a89f63fa1 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/validation.tsx @@ -6,7 +6,7 @@ */ import { ConfigKey, - DataStream, + MonitorTypeEnum, ScheduleUnit, MonitorFields, Validator, @@ -87,7 +87,7 @@ const validateCommon: ValidationLibrary = { const { number, unit } = schedule as MonitorFields[ConfigKey.SCHEDULE]; // Timeout is not currently supported by browser monitors - if (monitorType === DataStream.BROWSER) { + if (monitorType === MonitorTypeEnum.BROWSER) { return false; } @@ -163,11 +163,11 @@ const validateBrowser: ValidationLibrary = { params ? !validJSONFormat(params) : false, }; -export type ValidateDictionary = Record; +export type ValidateDictionary = Record; export const validate: ValidateDictionary = { - [DataStream.HTTP]: validateHTTP, - [DataStream.TCP]: validateTCP, - [DataStream.ICMP]: validateICMP, - [DataStream.BROWSER]: validateBrowser, + [MonitorTypeEnum.HTTP]: validateHTTP, + [MonitorTypeEnum.TCP]: validateTCP, + [MonitorTypeEnum.ICMP]: validateICMP, + [MonitorTypeEnum.BROWSER]: validateBrowser, }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx index 7b78a45ccea2..5f8d264585f6 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx @@ -28,7 +28,7 @@ import { useSelectedLocation } from '../hooks/use_selected_location'; import { getErrorDetailsUrl } from '../monitor_errors/errors_list'; import { ConfigKey, - DataStream, + MonitorTypeEnum, EncryptedSyntheticsSavedMonitor, Ping, SyntheticsJourneyApiResponse, @@ -122,7 +122,7 @@ export const LastTestRunComponent = ({ - {monitor?.type === DataStream.BROWSER ? ( + {monitor?.type === MonitorTypeEnum.BROWSER ? ( diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table.tsx index de83a03ac492..c61242fa2373 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/test_runs_table.tsx @@ -38,7 +38,7 @@ import { getTestRunDetailRelativeLink, TestDetailsLink, } from '../../common/links/test_details_link'; -import { ConfigKey, DataStream, Ping } from '../../../../../../common/runtime_types'; +import { ConfigKey, MonitorTypeEnum, Ping } from '../../../../../../common/runtime_types'; import { formatTestDuration } from '../../../utils/monitor_test_result/test_time_formats'; import { sortPings } from '../../../utils/monitor_test_result/sort_pings'; import { selectPingsError } from '../../../state'; @@ -93,7 +93,7 @@ export const TestRunsTable = ({ const selectedLocation = useSelectedLocation(); const isTabletOrGreater = useIsWithinMinBreakpoint('s'); - const isBrowserMonitor = monitor?.[ConfigKey.MONITOR_TYPE] === DataStream.BROWSER; + const isBrowserMonitor = monitor?.[ConfigKey.MONITOR_TYPE] === MonitorTypeEnum.BROWSER; const { expandedRows, setExpandedRows } = useExpandedPingList(pings); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/filters/filter_fields.ts b/x-pack/plugins/synthetics/public/apps/synthetics/utils/filters/filter_fields.ts index 778b39e2c37c..40ef046a6579 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/filters/filter_fields.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/filters/filter_fields.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { invert } from 'lodash'; -import { DataStream, ServiceLocations } from '../../../../../common/runtime_types'; +import { MonitorTypeEnum, ServiceLocations } from '../../../../../common/runtime_types'; import { MonitorFilterState } from '../../state'; export type SyntheticsMonitorFilterField = keyof Omit< @@ -43,7 +43,7 @@ export function getSyntheticsFilterDisplayValues( switch (field) { case 'monitorTypes': return values.map(({ label, count }: { label: string; count: number }) => ({ - label: monitorTypeKeyLabelMap[label as DataStream] ?? label, + label: monitorTypeKeyLabelMap[label as MonitorTypeEnum] ?? label, count, })); case 'schedules': @@ -88,9 +88,9 @@ export const valueToLabelWithEmptyCount = (value?: string | string[]): LabelWith return value ? [{ label: value, count: 0 }] : []; }; -export const monitorTypeKeyLabelMap: Record = { - [DataStream.BROWSER]: 'Journey / Page', - [DataStream.HTTP]: 'HTTP', - [DataStream.TCP]: 'TCP', - [DataStream.ICMP]: 'ICMP', +export const monitorTypeKeyLabelMap: Record = { + [MonitorTypeEnum.BROWSER]: 'Journey / Page', + [MonitorTypeEnum.HTTP]: 'HTTP', + [MonitorTypeEnum.TCP]: 'TCP', + [MonitorTypeEnum.ICMP]: 'ICMP', }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts index a57dcf8d7584..abfc08919b33 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts @@ -8,7 +8,7 @@ import { SyntheticsAppState } from '../../../state/root_reducer'; import { ConfigKey, - DataStream, + MonitorTypeEnum, DEFAULT_THROTTLING, LocationStatus, ScheduleUnit, @@ -227,7 +227,7 @@ function getMonitorDetailsMockSlice() { check_group: '051aba1c-0b74-11ed-9f0e-ba4e6fa109d5', id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', timespan: { lt: '2022-07-24T17:24:06.094Z', gte: '2022-07-24T17:14:06.094Z' }, - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, status: 'up', }, url: { @@ -293,7 +293,7 @@ function getMonitorDetailsMockSlice() { check_group: '051aba1c-0b74-11ed-9f0e-ba4e6fa109d5', id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', timespan: { lt: '2022-07-24T17:24:06.094Z', gte: '2022-07-24T17:14:06.094Z' }, - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, status: 'up', }, url: { @@ -348,7 +348,7 @@ function getMonitorDetailsMockSlice() { id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', check_group: '9eb87e53-0b72-11ed-b34f-aa618b4334ae', timespan: { lt: '2022-07-24T17:14:05.020Z', gte: '2022-07-24T17:04:05.020Z' }, - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, status: 'up', }, url: { @@ -403,7 +403,7 @@ function getMonitorDetailsMockSlice() { timespan: { lt: '2022-07-24T17:11:49.702Z', gte: '2022-07-24T17:01:49.702Z' }, check_group: '4e00ac5a-0b72-11ed-a97e-5203642c687d', id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, status: 'up', }, url: { @@ -436,7 +436,7 @@ function getMonitorDetailsMockSlice() { syntheticsMonitor: { id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', config_id: '4afd3980-0b72-11ed-9c10-b57918ea89d6', - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, enabled: true, schedule: { unit: ScheduleUnit.MINUTES, number: '10' }, 'service.name': '', diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.test.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.test.ts index 7d75a9644004..c882f88e3115 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.test.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.test.ts @@ -12,7 +12,7 @@ import { CodeEditorMode, CommonFields, ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, HTTPAdvancedFields, HTTPFields, @@ -53,7 +53,7 @@ describe('validateMonitor', () => { testSchedule = { number: '5', unit: ScheduleUnit.MINUTES }; testTags = ['tag1', 'tag2']; testCommonFields = { - [ConfigKey.MONITOR_TYPE]: DataStream.ICMP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.ICMP, [ConfigKey.NAME]: 'test-monitor-name', [ConfigKey.CONFIG_ID]: 'test-monitor-id', [ConfigKey.MONITOR_QUERY_ID]: '', @@ -90,7 +90,7 @@ describe('validateMonitor', () => { ...testCommonFields, [ConfigKey.HOSTS]: 'test-hosts', [ConfigKey.WAIT]: '', - [ConfigKey.MONITOR_TYPE]: DataStream.ICMP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.ICMP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.ICMP, }; @@ -122,7 +122,7 @@ describe('validateMonitor', () => { ...testTCPSimpleFields, ...testTCPAdvancedFields, ...testTLSFields, - [ConfigKey.MONITOR_TYPE]: DataStream.TCP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.TCP, }; testHTTPSimpleFields = { @@ -153,7 +153,7 @@ describe('validateMonitor', () => { ...testHTTPSimpleFields, ...testHTTPAdvancedFields, ...testTLSFields, - [ConfigKey.MONITOR_TYPE]: DataStream.HTTP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.HTTP, }; testBrowserSimpleFields = { @@ -190,7 +190,7 @@ describe('validateMonitor', () => { testBrowserFields = { ...testBrowserSimpleFields, ...testBrowserAdvancedFields, - [ConfigKey.MONITOR_TYPE]: DataStream.BROWSER, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.BROWSER, }; }); @@ -207,7 +207,7 @@ describe('validateMonitor', () => { expect(result).toMatchObject({ valid: false, reason: 'Monitor type is invalid', - details: expect.stringMatching(/(?=.*invalid)(?=.*DataStream)/i), + details: 'Invalid value "undefined" supplied to "MonitorType"', }); }); @@ -223,7 +223,7 @@ describe('validateMonitor', () => { expect(result).toMatchObject({ valid: false, reason: 'Monitor type is invalid', - details: expect.stringMatching(/(?=.*invalid)(?=.*non-HTTP)(?=.*DataStream)/i), + details: 'Invalid value "non-HTTP" supplied to "MonitorType"', }); }); @@ -318,7 +318,7 @@ describe('validateMonitor', () => { expect(result.details).toEqual(expect.stringContaining(ConfigKey.HOSTS)); expect(result).toMatchObject({ valid: false, - reason: `Monitor is not a valid monitor of type ${DataStream.ICMP}`, + reason: `Monitor is not a valid monitor of type ${MonitorTypeEnum.ICMP}`, payload: testMonitor, }); }); @@ -337,7 +337,7 @@ describe('validateMonitor', () => { expect(result.details).toEqual(expect.stringContaining(ConfigKey.NAME)); expect(result).toMatchObject({ valid: false, - reason: `Monitor is not a valid monitor of type ${DataStream.TCP}`, + reason: `Monitor is not a valid monitor of type ${MonitorTypeEnum.TCP}`, payload: testMonitor, }); }); @@ -356,7 +356,7 @@ describe('validateMonitor', () => { expect(result.details).toEqual(expect.stringContaining(ConfigKey.URLS)); expect(result).toMatchObject({ valid: false, - reason: `Monitor is not a valid monitor of type ${DataStream.HTTP}`, + reason: `Monitor is not a valid monitor of type ${MonitorTypeEnum.HTTP}`, payload: testMonitor, }); }); @@ -375,7 +375,7 @@ describe('validateMonitor', () => { expect(result.details).toEqual(expect.stringContaining(ConfigKey.SOURCE_INLINE)); expect(result).toMatchObject({ valid: false, - reason: `Monitor is not a valid monitor of type ${DataStream.BROWSER}`, + reason: `Monitor is not a valid monitor of type ${MonitorTypeEnum.BROWSER}`, payload: testMonitor, }); }); diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.ts index 8b983c0c8f93..cc6c34bf1020 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/monitor_validation.ts @@ -15,8 +15,8 @@ import { ProjectMonitorCodec, ProjectMonitor, ConfigKey, - DataStream, - DataStreamCodec, + MonitorTypeEnum, + MonitorTypeCodec, HTTPFieldsCodec, MonitorFields, TCPFieldsCodec, @@ -33,11 +33,11 @@ type MonitorCodecType = | typeof HTTPFieldsCodec | typeof BrowserFieldsCodec; -const monitorTypeToCodecMap: Record = { - [DataStream.ICMP]: ICMPFieldsCodec, - [DataStream.TCP]: TCPFieldsCodec, - [DataStream.HTTP]: HTTPFieldsCodec, - [DataStream.BROWSER]: BrowserFieldsCodec, +const monitorTypeToCodecMap: Record = { + [MonitorTypeEnum.ICMP]: ICMPFieldsCodec, + [MonitorTypeEnum.TCP]: TCPFieldsCodec, + [MonitorTypeEnum.HTTP]: HTTPFieldsCodec, + [MonitorTypeEnum.BROWSER]: BrowserFieldsCodec, }; export interface ValidationResult { @@ -55,7 +55,7 @@ export interface ValidationResult { export function validateMonitor(monitorFields: MonitorFields): ValidationResult { const { [ConfigKey.MONITOR_TYPE]: monitorType } = monitorFields; - const decodedType = DataStreamCodec.decode(monitorType); + const decodedType = MonitorTypeCodec.decode(monitorType); if (isLeft(decodedType)) { return { diff --git a/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts b/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts index 097367de05ca..299ab62f0902 100644 --- a/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts +++ b/x-pack/plugins/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts @@ -11,7 +11,7 @@ import { SavedObject } from '@kbn/core/server'; import { SyntheticsMonitor, ConfigKey, - DataStream, + MonitorTypeEnum, ScheduleUnit, SourceType, } from '../../../common/runtime_types/monitor_management'; @@ -44,8 +44,8 @@ const testConfig: SavedObject = { updated_at: '2011-10-05T14:48:00.000Z', id, attributes: { - ...DEFAULT_FIELDS[DataStream.BROWSER], - [ConfigKey.MONITOR_TYPE]: DataStream.HTTP, + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.HTTP, [ConfigKey.LOCATIONS]: [ { id: 'us_central', diff --git a/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.test.ts index 666b0af1979c..748611c9e2f5 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ConfigKey, DataStream } from '../../../../common/runtime_types'; +import { ConfigKey, MonitorTypeEnum } from '../../../../common/runtime_types'; import { formatSyntheticsPolicy } from './format_synthetics_policy'; import { PROFILE_VALUES_ENUM, PROFILES_MAP } from '../../../../common/constants/monitor_defaults'; @@ -13,7 +13,7 @@ describe('formatSyntheticsPolicy', () => { it('formats browser policy', () => { const { formattedPolicy } = formatSyntheticsPolicy( testNewPolicy, - DataStream.BROWSER, + MonitorTypeEnum.BROWSER, browserConfig, gParams ); @@ -468,7 +468,7 @@ describe('formatSyntheticsPolicy', () => { it.each([true, false])('formats http policy', (isTLSEnabled) => { const { formattedPolicy } = formatSyntheticsPolicy( testNewPolicy, - DataStream.HTTP, + MonitorTypeEnum.HTTP, { ...httpPolicy, [ConfigKey.METADATA]: { is_tls_enabled: isTLSEnabled }, diff --git a/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.ts b/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.ts index f37174734228..78cbc2d4a079 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/formatters/private_formatters/format_synthetics_policy.ts @@ -9,7 +9,7 @@ import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { cloneDeep } from 'lodash'; import { processorsFormatter } from './processors_formatter'; import { LegacyConfigKey } from '../../../../common/constants/monitor_management'; -import { ConfigKey, DataStream, MonitorFields } from '../../../../common/runtime_types'; +import { ConfigKey, MonitorTypeEnum, MonitorFields } from '../../../../common/runtime_types'; import { throttlingFormatter } from './browser_formatters'; import { replaceStringWithParams } from '../formatting_utils'; import { syntheticsPolicyFormatters } from './formatters'; @@ -28,7 +28,7 @@ export interface ProcessorFields { export const formatSyntheticsPolicy = ( newPolicy: NewPackagePolicy, - monitorType: DataStream, + monitorType: MonitorTypeEnum, config: Partial, params: Record, isLegacy?: boolean diff --git a/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/convert_to_data_stream.ts b/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/convert_to_data_stream.ts index 78842274d02e..69ba8ddb6def 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/convert_to_data_stream.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/convert_to_data_stream.ts @@ -6,10 +6,10 @@ */ import { DEFAULT_NAMESPACE_STRING } from '../../../../common/constants/monitor_defaults'; -import { DataStream, MonitorFields } from '../../../../common/runtime_types'; +import { MonitorTypeEnum, MonitorFields } from '../../../../common/runtime_types'; export interface DataStreamConfig { - type: DataStream; + type: MonitorTypeEnum; id: string; schedule: string; enabled: boolean; @@ -19,7 +19,7 @@ export interface DataStreamConfig { streams: [ { data_stream: { - dataset: DataStream; + dataset: MonitorTypeEnum; type: 'synthetics'; }; } & Partial diff --git a/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/format_configs.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/format_configs.test.ts index 78756c04174b..979db50dee6d 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/format_configs.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/formatters/public_formatters/format_configs.test.ts @@ -15,7 +15,7 @@ import { import { loggerMock } from '@kbn/logging-mocks'; import { ConfigKey, - DataStream, + MonitorTypeEnum, CodeEditorMode, MonitorFields, ResponseBodyIndexPolicy, @@ -25,7 +25,7 @@ import { } from '../../../../common/runtime_types'; const testHTTPConfig: Partial = { - type: 'http' as DataStream, + type: 'http' as MonitorTypeEnum, enabled: true, schedule: { number: '3', unit: 'm' as ScheduleUnit }, 'service.name': '', @@ -62,7 +62,7 @@ const testHTTPConfig: Partial = { }; const testBrowserConfig: Partial = { - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, enabled: true, schedule: { number: '3', unit: ScheduleUnit.MINUTES }, 'service.name': 'APM Service', diff --git a/x-pack/plugins/synthetics/server/synthetics_service/private_location/synthetics_private_location.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/private_location/synthetics_private_location.test.ts index 44e70d3a2a95..837006f5f6c3 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/private_location/synthetics_private_location.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/private_location/synthetics_private_location.test.ts @@ -7,7 +7,7 @@ import { SavedObjectsClientContract } from '@kbn/core/server'; import { loggerMock } from '@kbn/logging-mocks'; import { - DataStream, + MonitorTypeEnum, MonitorFields, ScheduleUnit, SourceType, @@ -160,7 +160,7 @@ describe('SyntheticsPrivateLocation', () => { it('formats monitors stream properly', () => { const test = formatSyntheticsPolicy( testMonitorPolicy, - DataStream.BROWSER, + MonitorTypeEnum.BROWSER, dummyBrowserConfig, {} ); @@ -260,7 +260,7 @@ const dummyBrowserConfig: Partial & { fields: Record; fields_under_root: boolean; } = { - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, enabled: true, schedule: { unit: ScheduleUnit.MINUTES, number: '10' }, 'service.name': 'test service', diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.test.ts index 2a4a2ec5fd1d..ea60d8408add 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.test.ts @@ -6,7 +6,7 @@ */ import { - DataStream, + MonitorTypeEnum, ScreenshotOption, Locations, LocationStatus, @@ -89,7 +89,7 @@ describe('browser normalizers', () => { locations: ['us_central', 'us_east'], tags: ['tag3', 'tag4'], ignoreHTTPSErrors: false, - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, hash: testHash, }, { @@ -105,7 +105,7 @@ describe('browser normalizers', () => { privateLocations: ['Germany'], tags: ['tag3', 'tag4'], ignoreHTTPSErrors: false, - type: DataStream.BROWSER, + type: MonitorTypeEnum.BROWSER, hash: testHash, }, ]; @@ -122,7 +122,7 @@ describe('browser normalizers', () => { expect(actual).toEqual([ { normalizedFields: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], journey_id: 'test-id-1', ignore_https_errors: true, origin: 'project', @@ -170,7 +170,7 @@ describe('browser normalizers', () => { }, { normalizedFields: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], journey_id: 'test-id-2', ignore_https_errors: false, origin: 'project', @@ -228,7 +228,7 @@ describe('browser normalizers', () => { }, { normalizedFields: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], journey_id: 'test-id-3', ignore_https_errors: false, origin: 'project', @@ -305,7 +305,7 @@ describe('browser normalizers', () => { expect(actual).toEqual([ { normalizedFields: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], journey_id: 'test-id-1', ignore_https_errors: true, origin: 'project', @@ -375,7 +375,7 @@ describe('browser normalizers', () => { expect(actual).toEqual([ { normalizedFields: { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], journey_id: 'test-id-1', ignore_https_errors: true, origin: 'project', diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.ts index 0e3196d46d6f..203dacc0e73e 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/browser_monitor.ts @@ -8,7 +8,7 @@ import { BrowserFields, ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, ProjectMonitor, ThrottlingConfig, @@ -35,7 +35,7 @@ export const getNormalizeBrowserFields = ({ namespace, version, }: NormalizedProjectProps): NormalizerResult => { - const defaultFields = DEFAULT_FIELDS[DataStream.BROWSER]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.BROWSER]; const { errors, normalizedFields: commonFields } = getNormalizeCommonFields({ locations, @@ -50,7 +50,7 @@ export const getNormalizeBrowserFields = ({ const normalizedFields = { ...commonFields, - [ConfigKey.MONITOR_TYPE]: DataStream.BROWSER, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.BROWSER, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.MULTISTEP, [ConfigKey.SOURCE_PROJECT_CONTENT]: monitor.content || defaultFields[ConfigKey.SOURCE_PROJECT_CONTENT], @@ -80,7 +80,7 @@ export const getNormalizeBrowserFields = ({ export const normalizeThrottling = ( monitorThrottling: ProjectMonitor['throttling'] ): ThrottlingConfig => { - const defaultFields = DEFAULT_FIELDS[DataStream.BROWSER]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.BROWSER]; let throttling = defaultFields[ConfigKey.THROTTLING_CONFIG]; if (typeof monitorThrottling === 'boolean' && !monitorThrottling) { diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/common_fields.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/common_fields.ts index ff0b03ad7601..e7aeb6a41577 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/common_fields.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/common_fields.ts @@ -14,7 +14,7 @@ import { BrowserFields, ConfigKey, CommonFields, - DataStream, + MonitorTypeEnum, Locations, ProjectMonitor, ScheduleUnit, @@ -298,7 +298,7 @@ export const flattenAndFormatObject = (obj: Record, prefix = '' }, {}); export const normalizeYamlConfig = (monitor: NormalizedProjectProps['monitor']) => { - const defaultFields = DEFAULT_FIELDS[monitor.type as DataStream]; + const defaultFields = DEFAULT_FIELDS[monitor.type as MonitorTypeEnum]; const supportedKeys = Object.keys(defaultFields); const flattenedConfig = flattenAndFormatObject(monitor, '', supportedKeys); const { diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.test.ts index 9fc021883549..efd77695abeb 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import { omit } from 'lodash'; -import { DataStream, Locations, LocationStatus } from '../../../../common/runtime_types'; +import { MonitorTypeEnum, Locations, LocationStatus } from '../../../../common/runtime_types'; import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { normalizeProjectMonitors } from '.'; import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; @@ -138,7 +138,7 @@ describe('http normalizers', () => { }, ], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: true, }, @@ -195,7 +195,7 @@ describe('http normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: true, }, @@ -278,7 +278,7 @@ describe('http normalizers', () => { }, ], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: true, }, @@ -335,7 +335,7 @@ describe('http normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], __ui: { is_tls_enabled: false, }, diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.ts index c79db2433cb8..113b75924b1c 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/http_monitor.ts @@ -9,7 +9,7 @@ import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { CodeEditorMode, ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, HTTPFields, TLSVersion, @@ -34,7 +34,7 @@ export const getNormalizeHTTPFields = ({ namespace, version, }: NormalizedProjectProps): NormalizerResult => { - const defaultFields = DEFAULT_FIELDS[DataStream.HTTP]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.HTTP]; const errors = []; const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor); const { errors: commonErrors, normalizedFields: commonFields } = getNormalizeCommonFields({ @@ -61,7 +61,7 @@ export const getNormalizeHTTPFields = ({ const normalizedFields = { ...yamlConfig, ...commonFields, - [ConfigKey.MONITOR_TYPE]: DataStream.HTTP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.HTTP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.HTTP, [ConfigKey.URLS]: getOptionalArrayField(monitor.urls) || defaultFields[ConfigKey.URLS], [ConfigKey.MAX_REDIRECTS]: formatMaxRedirects(monitor[ConfigKey.MAX_REDIRECTS]), @@ -78,7 +78,7 @@ export const getNormalizeHTTPFields = ({ ? (getOptionalListField(get(monitor, ConfigKey.TLS_VERSION)) as TLSVersion[]) : defaultFields[ConfigKey.TLS_VERSION], [ConfigKey.METADATA]: { - ...DEFAULT_FIELDS[DataStream.HTTP][ConfigKey.METADATA], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP][ConfigKey.METADATA], is_tls_enabled: getHasTLSFields(monitor), }, }; @@ -118,7 +118,7 @@ export const formatMaxRedirects = (value?: string | number): string => { return `${value}`; } - const defaultFields = DEFAULT_FIELDS[DataStream.HTTP]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.HTTP]; return value ?? defaultFields[ConfigKey.MAX_REDIRECTS]; }; diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.test.ts index 437025da4f78..acb9dc03abc7 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DataStream, Locations, LocationStatus } from '../../../../common/runtime_types'; +import { MonitorTypeEnum, Locations, LocationStatus } from '../../../../common/runtime_types'; import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { normalizeProjectMonitors } from '.'; import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; @@ -99,7 +99,7 @@ describe('icmp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.ICMP], + ...DEFAULT_FIELDS[MonitorTypeEnum.ICMP], config_id: '', custom_heartbeat_id: 'Cloudflare-DNS-test-project-id-test-space', enabled: true, @@ -139,7 +139,7 @@ describe('icmp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.ICMP], + ...DEFAULT_FIELDS[MonitorTypeEnum.ICMP], config_id: '', custom_heartbeat_id: 'Cloudflare-DNS-2-test-project-id-test-space', enabled: true, @@ -192,7 +192,7 @@ describe('icmp normalizers', () => { }, ], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.ICMP], + ...DEFAULT_FIELDS[MonitorTypeEnum.ICMP], config_id: '', custom_heartbeat_id: 'Cloudflare-DNS-3-test-project-id-test-space', enabled: true, diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.ts index b907c983d534..8dcb062eb56f 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/icmp_monitor.ts @@ -8,7 +8,7 @@ import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, ICMPFields, } from '../../../../common/runtime_types/monitor_management'; @@ -32,7 +32,7 @@ export const getNormalizeICMPFields = ({ namespace, version, }: NormalizedProjectProps): NormalizerResult => { - const defaultFields = DEFAULT_FIELDS[DataStream.ICMP]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.ICMP]; const errors = []; const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor); @@ -61,7 +61,7 @@ export const getNormalizeICMPFields = ({ const normalizedFields = { ...yamlConfig, ...commonFields, - [ConfigKey.MONITOR_TYPE]: DataStream.ICMP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.ICMP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.ICMP, [ConfigKey.HOSTS]: getOptionalArrayField(monitor[ConfigKey.HOSTS]) || defaultFields[ConfigKey.HOSTS], diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/index.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/index.ts index 0bdb318731f3..e73d7da56483 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/index.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/index.ts @@ -5,7 +5,7 @@ * 2.0. */ import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; -import { DataStream, Locations, ProjectMonitor } from '../../../../common/runtime_types'; +import { MonitorTypeEnum, Locations, ProjectMonitor } from '../../../../common/runtime_types'; import { getNormalizeBrowserFields } from './browser_monitor'; import { getNormalizeICMPFields } from './icmp_monitor'; import { getNormalizeTCPFields } from './tcp_monitor'; @@ -14,19 +14,19 @@ import { NormalizedProjectProps } from './common_fields'; export const normalizeProjectMonitor = (props: NormalizedProjectProps) => { const { monitor } = props; - const type = monitor.type || DataStream.BROWSER; + const type = monitor.type || MonitorTypeEnum.BROWSER; switch (type) { - case DataStream.BROWSER: + case MonitorTypeEnum.BROWSER: return getNormalizeBrowserFields(props); - case DataStream.HTTP: + case MonitorTypeEnum.HTTP: return getNormalizeHTTPFields(props); - case DataStream.TCP: + case MonitorTypeEnum.TCP: return getNormalizeTCPFields(props); - case DataStream.ICMP: + case MonitorTypeEnum.ICMP: return getNormalizeICMPFields(props); default: throw new Error(`Unsupported monitor type ${monitor.type}`); diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.test.ts index 26435e3841ec..0b9e1488992d 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import { omit } from 'lodash'; -import { DataStream, Locations, LocationStatus } from '../../../../common/runtime_types'; +import { MonitorTypeEnum, Locations, LocationStatus } from '../../../../common/runtime_types'; import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { normalizeProjectMonitors } from '.'; import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; @@ -101,7 +101,7 @@ describe('tcp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: true, }, @@ -155,7 +155,7 @@ describe('tcp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: true, }, @@ -222,7 +222,7 @@ describe('tcp normalizers', () => { }, ], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: false, }, @@ -289,7 +289,7 @@ describe('tcp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: true, }, @@ -343,7 +343,7 @@ describe('tcp normalizers', () => { { errors: [], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: true, }, @@ -410,7 +410,7 @@ describe('tcp normalizers', () => { }, ], normalizedFields: { - ...DEFAULT_FIELDS[DataStream.TCP], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP], __ui: { is_tls_enabled: false, }, diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.ts index 9626937d98a7..5162d3900519 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/normalizers/tcp_monitor.ts @@ -8,7 +8,7 @@ import { get } from 'lodash'; import { DEFAULT_FIELDS } from '../../../../common/constants/monitor_defaults'; import { ConfigKey, - DataStream, + MonitorTypeEnum, FormMonitorType, TCPFields, TLSVersion, @@ -33,7 +33,7 @@ export const getNormalizeTCPFields = ({ namespace, version, }: NormalizedProjectProps): NormalizerResult => { - const defaultFields = DEFAULT_FIELDS[DataStream.TCP]; + const defaultFields = DEFAULT_FIELDS[MonitorTypeEnum.TCP]; const errors = []; const { yamlConfig, unsupportedKeys } = normalizeYamlConfig(monitor); @@ -62,7 +62,7 @@ export const getNormalizeTCPFields = ({ const normalizedFields = { ...yamlConfig, ...commonFields, - [ConfigKey.MONITOR_TYPE]: DataStream.TCP, + [ConfigKey.MONITOR_TYPE]: MonitorTypeEnum.TCP, [ConfigKey.FORM_MONITOR_TYPE]: FormMonitorType.TCP, [ConfigKey.HOSTS]: getOptionalArrayField(monitor[ConfigKey.HOSTS]) || defaultFields[ConfigKey.HOSTS], @@ -70,7 +70,7 @@ export const getNormalizeTCPFields = ({ ? (getOptionalListField(get(monitor, ConfigKey.TLS_VERSION)) as TLSVersion[]) : defaultFields[ConfigKey.TLS_VERSION], [ConfigKey.METADATA]: { - ...DEFAULT_FIELDS[DataStream.TCP][ConfigKey.METADATA], + ...DEFAULT_FIELDS[MonitorTypeEnum.TCP][ConfigKey.METADATA], is_tls_enabled: getHasTLSFields(monitor), }, }; diff --git a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.test.ts b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.test.ts index 79a8a658ef46..8684f31f9cd5 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.test.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.test.ts @@ -9,7 +9,7 @@ import { savedObjectsClientMock, savedObjectsServiceMock } from '@kbn/core/serve import { ProjectMonitorFormatter } from './project_monitor_formatter'; import { ConfigKey, - DataStream, + MonitorTypeEnum, Locations, LocationStatus, PrivateLocation, @@ -353,7 +353,7 @@ describe('ProjectMonitorFormatter', () => { const payloadData = [ { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], __ui: { script_source: { file_name: '', @@ -403,7 +403,7 @@ const payloadData = [ hash: 'lleklrkelkj', }, { - ...DEFAULT_FIELDS[DataStream.BROWSER], + ...DEFAULT_FIELDS[MonitorTypeEnum.BROWSER], __ui: { script_source: { file_name: '', diff --git a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts index 1602a7d29f12..fd37aa678ce6 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/synthetics_service.ts @@ -423,49 +423,48 @@ export class SyntheticsService { }; for await (const result of finder.find()) { - if (result.saved_objects.length === 0) { - return; - } - try { - if (!output) { - output = await this.getOutput(); + if (result.saved_objects.length > 0) { + try { if (!output) { - sendErrorTelemetryEvents(service.logger, service.server.telemetry, { - reason: 'API key is not valid.', - message: 'Failed to push configs. API key is not valid.', - type: 'invalidApiKey', - stackVersion: service.server.stackVersion, - }); - return; + output = await this.getOutput(); + if (!output) { + sendErrorTelemetryEvents(service.logger, service.server.telemetry, { + reason: 'API key is not valid.', + message: 'Failed to push configs. API key is not valid.', + type: 'invalidApiKey', + stackVersion: service.server.stackVersion, + }); + return; + } } - } - const monitors = result.saved_objects.filter(({ error }) => !error); - const formattedConfigs = this.normalizeConfigs(monitors, paramsBySpace); + const monitors = result.saved_objects.filter(({ error }) => !error); + const formattedConfigs = this.normalizeConfigs(monitors, paramsBySpace); - this.logger.debug( - `${formattedConfigs.length} monitors will be pushed to synthetics service.` - ); + this.logger.debug( + `${formattedConfigs.length} monitors will be pushed to synthetics service.` + ); - formattedConfigs.forEach((monitor) => { - monitor.locations.forEach((location) => { - if (location.isServiceManaged) { - bucketsByLocation[location.id]?.push(monitor); - } + formattedConfigs.forEach((monitor) => { + monitor.locations.forEach((location) => { + if (location.isServiceManaged) { + bucketsByLocation[location.id]?.push(monitor); + } + }); }); - }); - await syncAllLocations(PER_PAGE); - } catch (e) { - sendErrorTelemetryEvents(service.logger, service.server.telemetry, { - reason: 'Failed to push configs to service', - message: e?.message, - type: 'pushConfigsError', - code: e?.code, - status: e.status, - stackVersion: service.server.stackVersion, - }); - this.logger.error(e); + await syncAllLocations(PER_PAGE); + } catch (e) { + sendErrorTelemetryEvents(service.logger, service.server.telemetry, { + reason: 'Failed to push configs to service', + message: e?.message, + type: 'pushConfigsError', + code: e?.code, + status: e.status, + stackVersion: service.server.stackVersion, + }); + this.logger.error(e); + } } } diff --git a/x-pack/plugins/synthetics/tsconfig.json b/x-pack/plugins/synthetics/tsconfig.json index 4492a20771d8..2fff5e08016f 100644 --- a/x-pack/plugins/synthetics/tsconfig.json +++ b/x-pack/plugins/synthetics/tsconfig.json @@ -78,7 +78,6 @@ "@kbn/shared-ux-page-kibana-template", "@kbn/observability-ai-assistant-plugin", "@kbn/unified-doc-viewer-plugin", - "@kbn/discover-utils", "@kbn/shared-ux-link-redirect-app" ], "exclude": [ diff --git a/x-pack/plugins/task_manager/server/config.test.ts b/x-pack/plugins/task_manager/server/config.test.ts index c196a334931b..9d85c216546f 100644 --- a/x-pack/plugins/task_manager/server/config.test.ts +++ b/x-pack/plugins/task_manager/server/config.test.ts @@ -13,6 +13,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "claim_strategy": "default", "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -72,6 +73,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "claim_strategy": "default", "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -129,6 +131,7 @@ describe('config validation', () => { expect(configSchema.validate(config)).toMatchInlineSnapshot(` Object { "allow_reading_invalid_state": true, + "claim_strategy": "default", "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -244,4 +247,13 @@ describe('config validation', () => { configSchema.validate(config); }).not.toThrowError(); }); + + test('the claim strategy is validated', () => { + const config = { claim_strategy: 'invalid-strategy' }; + expect(() => { + configSchema.validate(config); + }).toThrowErrorMatchingInlineSnapshot( + `"The claim strategy is invalid: Unknown task claiming strategy (invalid-strategy)"` + ); + }); }); diff --git a/x-pack/plugins/task_manager/server/config.ts b/x-pack/plugins/task_manager/server/config.ts index 490d25a7bdfb..3be8b341c939 100644 --- a/x-pack/plugins/task_manager/server/config.ts +++ b/x-pack/plugins/task_manager/server/config.ts @@ -6,6 +6,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { getTaskClaimer } from './task_claimers'; export const MAX_WORKERS_LIMIT = 100; export const DEFAULT_MAX_WORKERS = 10; @@ -25,6 +26,8 @@ export const DEFAULT_METRICS_RESET_INTERVAL = 30 * 1000; // 30 seconds // At the default poll interval of 3sec, this averages over the last 15sec. export const DEFAULT_WORKER_UTILIZATION_RUNNING_AVERAGE_WINDOW = 5; +export const CLAIM_STRATEGY_DEFAULT = 'default'; + export const taskExecutionFailureThresholdSchema = schema.object( { error_threshold: schema.number({ @@ -152,6 +155,7 @@ export const configSchema = schema.object( max: 100, min: 1, }), + claim_strategy: schema.string({ defaultValue: CLAIM_STRATEGY_DEFAULT }), }, { validate: (config) => { @@ -162,6 +166,11 @@ export const configSchema = schema.object( ) { return `The specified monitored_stats_required_freshness (${config.monitored_stats_required_freshness}) is invalid, as it is below the poll_interval (${config.poll_interval})`; } + try { + getTaskClaimer(config.claim_strategy); + } catch (err) { + return `The claim strategy is invalid: ${err.message}`; + } }, } ); diff --git a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts index 39a9afb0f0d1..6ae1d00a6224 100644 --- a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts @@ -85,6 +85,7 @@ describe('EphemeralTaskLifecycle', () => { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', ...config, }, elasticsearchAndSOAvailability$, diff --git a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts index f034feb15446..2fd4ceb74ca7 100644 --- a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts +++ b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts @@ -80,6 +80,7 @@ describe('managed configuration', () => { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }); logger = context.logger.get('taskManager'); diff --git a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts index 6c9a9efeb558..228d94ed87da 100644 --- a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts +++ b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts @@ -57,6 +57,7 @@ const config = { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }; const getStatsWithTimestamp = ({ diff --git a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts index e457797d5ae1..5becffa4e302 100644 --- a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts +++ b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts @@ -73,6 +73,7 @@ const config: TaskManagerConfig = { }, version_conflict_threshold: 80, worker_utilization_running_average_window: 5, + claim_strategy: 'default', }; describe('createAggregator', () => { diff --git a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts index 689c9c882bee..543707bf940b 100644 --- a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts @@ -53,6 +53,7 @@ describe('Configuration Statistics Aggregator', () => { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }; const managedConfig = { diff --git a/x-pack/plugins/task_manager/server/monitoring/monitoring_stats_stream.test.ts b/x-pack/plugins/task_manager/server/monitoring/monitoring_stats_stream.test.ts index daf3f2baf085..7dc3460d9838 100644 --- a/x-pack/plugins/task_manager/server/monitoring/monitoring_stats_stream.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/monitoring_stats_stream.test.ts @@ -58,6 +58,7 @@ describe('createMonitoringStatsStream', () => { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }; it('returns the initial config used to configure Task Manager', async () => { diff --git a/x-pack/plugins/task_manager/server/plugin.test.ts b/x-pack/plugins/task_manager/server/plugin.test.ts index 1e7215d6d7a1..5e178db3b99a 100644 --- a/x-pack/plugins/task_manager/server/plugin.test.ts +++ b/x-pack/plugins/task_manager/server/plugin.test.ts @@ -78,6 +78,7 @@ const pluginInitializerContextParams = { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }; describe('TaskManagerPlugin', () => { diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts index 79b153f42a88..24898d3c9938 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts @@ -83,6 +83,7 @@ describe('TaskPollingLifecycle', () => { max_attempts: 20, }, metrics_reset_interval: 3000, + claim_strategy: 'default', }, taskStore: mockTaskStore, logger: taskManagerLogger, diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.ts index e7509df01cfc..2024277ea94e 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.ts @@ -41,7 +41,8 @@ import { identifyEsError, isEsCannotExecuteScriptError } from './lib/identify_es import { BufferedTaskStore } from './buffered_task_store'; import { TaskTypeDictionary } from './task_type_dictionary'; import { delayOnClaimConflicts } from './polling'; -import { TaskClaiming, ClaimOwnershipResult } from './queries/task_claiming'; +import { TaskClaiming } from './queries/task_claiming'; +import { ClaimOwnershipResult } from './task_claimers'; export interface ITaskEventEmitter { get events(): Observable; @@ -132,6 +133,7 @@ export class TaskPollingLifecycle implements ITaskEventEmitter ({ CONCURRENCY_ALLOW_LIST_BY_TASK_TYPE: [ @@ -82,6 +66,23 @@ describe('TaskClaiming', () => { .mockImplementation(() => mockApmTrans as any); }); + test(`should throw an error when invalid strategy specified`, () => { + const definitions = new TaskTypeDictionary(mockLogger()); + + expect(() => { + new TaskClaiming({ + logger: taskManagerLogger, + strategy: 'non-default', + definitions, + excludedTaskTypes: [], + unusedTypes: [], + taskStore: taskStoreMock.create({ taskManagerId: '' }), + maxAttempts: 2, + getCapacity: () => 10, + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unknown task claiming strategy (non-default)"`); + }); + test(`should log when a certain task type is skipped due to having a zero concurency configuration`, () => { const definitions = new TaskTypeDictionary(mockLogger()); definitions.registerTaskDefinitions({ @@ -117,6 +118,7 @@ describe('TaskClaiming', () => { new TaskClaiming({ logger: taskManagerLogger, + strategy: 'default', definitions, excludedTaskTypes: [], unusedTypes: [], @@ -130,1220 +132,4 @@ describe('TaskClaiming', () => { `"Task Manager will never claim tasks of the following types as their \\"maxConcurrency\\" is set to 0: limitedToZero, anotherLimitedToZero"` ); }); - - describe('claimAvailableTasks', () => { - function initialiseTestClaiming({ - storeOpts = {}, - taskClaimingOpts = {}, - hits = [generateFakeTasks(1)], - versionConflicts = 2, - excludedTaskTypes = [], - unusedTaskTypes = [], - }: { - storeOpts: Partial; - taskClaimingOpts: Partial; - hits?: ConcreteTaskInstance[][]; - versionConflicts?: number; - excludedTaskTypes?: string[]; - unusedTaskTypes?: string[]; - }) { - const definitions = storeOpts.definitions ?? taskDefinitions; - const store = taskStoreMock.create({ taskManagerId: storeOpts.taskManagerId }); - store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); - - if (hits.length === 1) { - store.fetch.mockResolvedValue({ docs: hits[0] }); - store.updateByQuery.mockResolvedValue({ - updated: hits[0].length, - version_conflicts: versionConflicts, - total: hits[0].length, - }); - } else { - for (const docs of hits) { - store.fetch.mockResolvedValueOnce({ docs }); - store.updateByQuery.mockResolvedValueOnce({ - updated: docs.length, - version_conflicts: versionConflicts, - total: docs.length, - }); - } - } - - const taskClaiming = new TaskClaiming({ - logger: taskManagerLogger, - definitions, - taskStore: store, - excludedTaskTypes, - unusedTypes: unusedTaskTypes, - maxAttempts: taskClaimingOpts.maxAttempts ?? 2, - getCapacity: taskClaimingOpts.getCapacity ?? (() => 10), - ...taskClaimingOpts, - }); - - return { taskClaiming, store }; - } - - async function testClaimAvailableTasks({ - storeOpts = {}, - taskClaimingOpts = {}, - claimingOpts, - hits = [generateFakeTasks(1)], - versionConflicts = 2, - excludedTaskTypes = [], - unusedTaskTypes = [], - }: { - storeOpts: Partial; - taskClaimingOpts: Partial; - claimingOpts: Omit; - hits?: ConcreteTaskInstance[][]; - versionConflicts?: number; - excludedTaskTypes?: string[]; - unusedTaskTypes?: string[]; - }) { - const getCapacity = taskClaimingOpts.getCapacity ?? (() => 10); - const { taskClaiming, store } = initialiseTestClaiming({ - storeOpts, - taskClaimingOpts, - excludedTaskTypes, - unusedTaskTypes, - hits, - versionConflicts, - }); - - const results = await getAllAsPromise(taskClaiming.claimAvailableTasks(claimingOpts)); - - expect(apm.startTransaction).toHaveBeenCalledWith( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - expect(mockApmTrans.end).toHaveBeenCalledWith('success'); - - expect(store.updateByQuery.mock.calls[0][1]).toMatchObject({ - max_docs: getCapacity(), - }); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: getCapacity() }); - return results.map((result, index) => ({ - result, - args: { - search: store.fetch.mock.calls[index][0] as SearchOpts & { - query: MustNotCondition; - }, - updateByQuery: store.updateByQuery.mock.calls[index] as [ - UpdateByQuerySearchOpts, - UpdateByQueryOpts - ], - }, - })); - } - - test('makes calls to APM as expected when markAvailableTasksAsClaimed throws error', async () => { - const maxAttempts = _.random(2, 43); - const customMaxAttempts = _.random(44, 100); - - const definitions = new TaskTypeDictionary(mockLogger()); - definitions.registerTaskDefinitions({ - foo: { - title: 'foo', - createTaskRunner: jest.fn(), - }, - bar: { - title: 'bar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - }); - - const { taskClaiming, store } = initialiseTestClaiming({ - storeOpts: { - definitions, - }, - taskClaimingOpts: { - maxAttempts, - }, - }); - - store.updateByQuery.mockRejectedValue(new Error('Oh no')); - - await expect( - getAllAsPromise( - taskClaiming.claimAvailableTasks({ - claimOwnershipUntil: new Date(), - }) - ) - ).rejects.toMatchInlineSnapshot(`[Error: Oh no]`); - - expect(apm.startTransaction).toHaveBeenCalledWith( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - expect(mockApmTrans.end).toHaveBeenCalledWith('failure'); - }); - - test('it filters claimed tasks down by supported types, maxAttempts, status, and runAt', async () => { - const maxAttempts = _.random(2, 43); - const customMaxAttempts = _.random(44, 100); - - const definitions = new TaskTypeDictionary(mockLogger()); - definitions.registerTaskDefinitions({ - foo: { - title: 'foo', - createTaskRunner: jest.fn(), - }, - bar: { - title: 'bar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - foobar: { - title: 'foobar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - }); - - const [ - { - args: { - updateByQuery: [{ query, sort }], - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - definitions, - }, - taskClaimingOpts: { - maxAttempts, - }, - claimingOpts: { - claimOwnershipUntil: new Date(), - }, - excludedTaskTypes: ['foobar'], - }); - expect(query).toMatchObject({ - bool: { - must: [ - { - bool: { - must: [ - { - term: { - 'task.enabled': true, - }, - }, - ], - }, - }, - { - bool: { - should: [ - { - bool: { - must: [ - { term: { 'task.status': 'idle' } }, - { range: { 'task.runAt': { lte: 'now' } } }, - ], - }, - }, - { - bool: { - must: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - }, - }, - { range: { 'task.retryAt': { lte: 'now' } } }, - ], - }, - }, - ], - }, - }, - ], - filter: [ - { - bool: { - must_not: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - must: { range: { 'task.retryAt': { gt: 'now' } } }, - }, - }, - ], - }, - }, - ], - }, - }); - expect(sort).toMatchObject([ - { - _script: { - type: 'number', - order: 'asc', - script: { - lang: 'painless', - source: ` -if (doc['task.retryAt'].size()!=0) { - return doc['task.retryAt'].value.toInstant().toEpochMilli(); -} -if (doc['task.runAt'].size()!=0) { - return doc['task.runAt'].value.toInstant().toEpochMilli(); -} - `, - }, - }, - }, - ]); - }); - - test('it should claim in batches partitioned by maxConcurrency', async () => { - const maxAttempts = _.random(2, 43); - const definitions = new TaskTypeDictionary(mockLogger()); - const taskManagerId = uuidv1(); - const fieldUpdates = { - ownerId: taskManagerId, - retryAt: new Date(Date.now()), - }; - definitions.registerTaskDefinitions({ - unlimited: { - title: 'unlimited', - createTaskRunner: jest.fn(), - }, - limitedToZero: { - title: 'limitedToZero', - maxConcurrency: 0, - createTaskRunner: jest.fn(), - }, - anotherUnlimited: { - title: 'anotherUnlimited', - createTaskRunner: jest.fn(), - }, - finalUnlimited: { - title: 'finalUnlimited', - createTaskRunner: jest.fn(), - }, - limitedToOne: { - title: 'limitedToOne', - maxConcurrency: 1, - createTaskRunner: jest.fn(), - }, - anotherLimitedToOne: { - title: 'anotherLimitedToOne', - maxConcurrency: 1, - createTaskRunner: jest.fn(), - }, - limitedToTwo: { - title: 'limitedToTwo', - maxConcurrency: 2, - createTaskRunner: jest.fn(), - }, - }); - const results = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - definitions, - }, - taskClaimingOpts: { - maxAttempts, - getCapacity: (type) => { - switch (type) { - case 'limitedToOne': - case 'anotherLimitedToOne': - return 1; - case 'limitedToTwo': - return 2; - default: - return 10; - } - }, - }, - claimingOpts: { - claimOwnershipUntil: new Date(), - }, - }); - - expect(results.length).toEqual(4); - - expect(results[0].args.updateByQuery[1].max_docs).toEqual(10); - expect(results[0].args.updateByQuery[0].script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['unlimited', 'anotherUnlimited', 'finalUnlimited'], - skippedTaskTypes: [ - 'limitedToZero', - 'limitedToOne', - 'anotherLimitedToOne', - 'limitedToTwo', - ], - unusedTaskTypes: [], - taskMaxAttempts: { - unlimited: maxAttempts, - }, - }, - }); - - expect(results[1].args.updateByQuery[1].max_docs).toEqual(1); - expect(results[1].args.updateByQuery[0].script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['limitedToOne'], - skippedTaskTypes: [ - 'unlimited', - 'limitedToZero', - 'anotherUnlimited', - 'finalUnlimited', - 'anotherLimitedToOne', - 'limitedToTwo', - ], - taskMaxAttempts: { - limitedToOne: maxAttempts, - }, - }, - }); - - expect(results[2].args.updateByQuery[1].max_docs).toEqual(1); - expect(results[2].args.updateByQuery[0].script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['anotherLimitedToOne'], - skippedTaskTypes: [ - 'unlimited', - 'limitedToZero', - 'anotherUnlimited', - 'finalUnlimited', - 'limitedToOne', - 'limitedToTwo', - ], - taskMaxAttempts: { - anotherLimitedToOne: maxAttempts, - }, - }, - }); - - expect(results[3].args.updateByQuery[1].max_docs).toEqual(2); - expect(results[3].args.updateByQuery[0].script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['limitedToTwo'], - skippedTaskTypes: [ - 'unlimited', - 'limitedToZero', - 'anotherUnlimited', - 'finalUnlimited', - 'limitedToOne', - 'anotherLimitedToOne', - ], - taskMaxAttempts: { - limitedToTwo: maxAttempts, - }, - }, - }); - }); - - test('it should reduce the available capacity from batch to batch', async () => { - const maxAttempts = _.random(2, 43); - const definitions = new TaskTypeDictionary(mockLogger()); - const taskManagerId = uuidv1(); - definitions.registerTaskDefinitions({ - unlimited: { - title: 'unlimited', - createTaskRunner: jest.fn(), - }, - limitedToFive: { - title: 'limitedToFive', - maxConcurrency: 5, - createTaskRunner: jest.fn(), - }, - limitedToTwo: { - title: 'limitedToTwo', - maxConcurrency: 2, - createTaskRunner: jest.fn(), - }, - }); - const results = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - definitions, - }, - taskClaimingOpts: { - maxAttempts, - getCapacity: (type) => { - switch (type) { - case 'limitedToTwo': - return 2; - case 'limitedToFive': - return 5; - default: - return 10; - } - }, - }, - hits: [ - [ - // 7 returned by unlimited query - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - mockInstance({ - taskType: 'unlimited', - }), - ], - // 2 returned by limitedToFive query - [ - mockInstance({ - taskType: 'limitedToFive', - }), - mockInstance({ - taskType: 'limitedToFive', - }), - ], - // 1 reterned by limitedToTwo query - [ - mockInstance({ - taskType: 'limitedToTwo', - }), - ], - ], - claimingOpts: { - claimOwnershipUntil: new Date(), - }, - }); - - expect(results.length).toEqual(3); - - expect(results[0].args.updateByQuery[1].max_docs).toEqual(10); - - // only capacity for 3, even though 5 are allowed - expect(results[1].args.updateByQuery[1].max_docs).toEqual(3); - - // only capacity for 1, even though 2 are allowed - expect(results[2].args.updateByQuery[1].max_docs).toEqual(1); - }); - - test('it shuffles the types claimed in batches to ensure no type starves another', async () => { - const maxAttempts = _.random(2, 43); - const definitions = new TaskTypeDictionary(mockLogger()); - const taskManagerId = uuidv1(); - definitions.registerTaskDefinitions({ - unlimited: { - title: 'unlimited', - createTaskRunner: jest.fn(), - }, - anotherUnlimited: { - title: 'anotherUnlimited', - createTaskRunner: jest.fn(), - }, - finalUnlimited: { - title: 'finalUnlimited', - createTaskRunner: jest.fn(), - }, - limitedToOne: { - title: 'limitedToOne', - maxConcurrency: 1, - createTaskRunner: jest.fn(), - }, - anotherLimitedToOne: { - title: 'anotherLimitedToOne', - maxConcurrency: 1, - createTaskRunner: jest.fn(), - }, - limitedToTwo: { - title: 'limitedToTwo', - maxConcurrency: 2, - createTaskRunner: jest.fn(), - }, - }); - - const { taskClaiming, store } = initialiseTestClaiming({ - storeOpts: { - taskManagerId, - definitions, - }, - taskClaimingOpts: { - maxAttempts, - getCapacity: (type) => { - switch (type) { - case 'limitedToOne': - case 'anotherLimitedToOne': - return 1; - case 'limitedToTwo': - return 2; - default: - return 10; - } - }, - }, - }); - - async function getUpdateByQueryScriptParams() { - return ( - await getAllAsPromise( - taskClaiming.claimAvailableTasks({ - claimOwnershipUntil: new Date(), - }) - ) - ).map( - (result, index) => - ( - store.updateByQuery.mock.calls[index][0] as { - query: MustNotCondition; - size: number; - sort: string | string[]; - script: { - params: { - [claimableTaskTypes: string]: string[]; - }; - }; - } - ).script.params.claimableTaskTypes - ); - } - - const firstCycle = await getUpdateByQueryScriptParams(); - store.updateByQuery.mockClear(); - const secondCycle = await getUpdateByQueryScriptParams(); - - expect(firstCycle.length).toEqual(4); - expect(secondCycle.length).toEqual(4); - expect(firstCycle).not.toMatchObject(secondCycle); - }); - - test('it passes any unusedTaskTypes to script', async () => { - const maxAttempts = _.random(2, 43); - const customMaxAttempts = _.random(44, 100); - const taskManagerId = uuidv1(); - const fieldUpdates = { - ownerId: taskManagerId, - retryAt: new Date(Date.now()), - }; - const definitions = new TaskTypeDictionary(mockLogger()); - definitions.registerTaskDefinitions({ - foo: { - title: 'foo', - createTaskRunner: jest.fn(), - }, - bar: { - title: 'bar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - foobar: { - title: 'foobar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - }); - - const [ - { - args: { - updateByQuery: [{ query, script }], - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - definitions, - taskManagerId, - }, - taskClaimingOpts: { - maxAttempts, - }, - claimingOpts: { - claimOwnershipUntil: new Date(), - }, - excludedTaskTypes: ['foobar'], - unusedTaskTypes: ['barfoo'], - }); - expect(query).toMatchObject({ - bool: { - must: [ - { - bool: { - must: [ - { - term: { - 'task.enabled': true, - }, - }, - ], - }, - }, - { - bool: { - should: [ - { - bool: { - must: [ - { term: { 'task.status': 'idle' } }, - { range: { 'task.runAt': { lte: 'now' } } }, - ], - }, - }, - { - bool: { - must: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - }, - }, - { range: { 'task.retryAt': { lte: 'now' } } }, - ], - }, - }, - ], - }, - }, - ], - filter: [ - { - bool: { - must_not: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - must: { range: { 'task.retryAt': { gt: 'now' } } }, - }, - }, - ], - }, - }, - ], - }, - }); - expect(script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['foo', 'bar'], - skippedTaskTypes: ['foobar'], - unusedTaskTypes: ['barfoo'], - taskMaxAttempts: { - bar: customMaxAttempts, - foo: maxAttempts, - }, - }, - }); - }); - - test('it claims tasks by setting their ownerId, status and retryAt', async () => { - const taskManagerId = uuidv1(); - const claimOwnershipUntil = new Date(Date.now()); - const fieldUpdates = { - ownerId: taskManagerId, - retryAt: claimOwnershipUntil, - }; - const [ - { - args: { - updateByQuery: [{ script }], - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - }, - taskClaimingOpts: {}, - claimingOpts: { - claimOwnershipUntil, - }, - }); - expect(script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['report', 'dernstraight', 'yawn'], - skippedTaskTypes: [], - taskMaxAttempts: { - dernstraight: 2, - report: 2, - yawn: 2, - }, - }, - }); - }); - - test('it filters out running tasks', async () => { - const taskManagerId = uuidv1(); - const claimOwnershipUntil = new Date(Date.now()); - const runAt = new Date(); - const tasks = [ - mockInstance({ - id: 'aaa', - runAt, - taskType: 'yawn', - schedule: undefined, - attempts: 0, - status: TaskStatus.Claiming, - params: { hello: 'world' }, - state: { baby: 'Henhen' }, - user: 'jimbo', - scope: ['reporting'], - ownerId: taskManagerId, - }), - ]; - const [ - { - result: { docs }, - args: { - search: { query }, - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - }, - taskClaimingOpts: {}, - claimingOpts: { - claimOwnershipUntil, - }, - hits: [tasks], - }); - - expect(query).toMatchObject({ - bool: { - must: [ - { - term: { - 'task.ownerId': taskManagerId, - }, - }, - { term: { 'task.status': 'claiming' } }, - { - bool: { - should: [ - { - term: { - 'task.taskType': 'report', - }, - }, - { - term: { - 'task.taskType': 'dernstraight', - }, - }, - { - term: { - 'task.taskType': 'yawn', - }, - }, - ], - }, - }, - ], - }, - }); - - expect(docs).toMatchObject([ - { - attempts: 0, - id: 'aaa', - schedule: undefined, - params: { hello: 'world' }, - runAt, - scope: ['reporting'], - state: { baby: 'Henhen' }, - status: 'claiming', - taskType: 'yawn', - user: 'jimbo', - ownerId: taskManagerId, - }, - ]); - }); - - test('it returns task objects', async () => { - const taskManagerId = uuidv1(); - const claimOwnershipUntil = new Date(Date.now()); - const runAt = new Date(); - const tasks = [ - mockInstance({ - id: 'aaa', - runAt, - taskType: 'yawn', - schedule: undefined, - attempts: 0, - status: TaskStatus.Claiming, - params: { hello: 'world' }, - state: { baby: 'Henhen' }, - user: 'jimbo', - scope: ['reporting'], - ownerId: taskManagerId, - }), - mockInstance({ - id: 'bbb', - runAt, - taskType: 'yawn', - schedule: { interval: '5m' }, - attempts: 2, - status: TaskStatus.Claiming, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - }), - ]; - const [ - { - result: { docs }, - args: { - search: { query }, - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - }, - taskClaimingOpts: {}, - claimingOpts: { - claimOwnershipUntil, - }, - hits: [tasks], - }); - - expect(query).toMatchObject({ - bool: { - must: [ - { - term: { - 'task.ownerId': taskManagerId, - }, - }, - { term: { 'task.status': 'claiming' } }, - { - bool: { - should: [ - { - term: { - 'task.taskType': 'report', - }, - }, - { - term: { - 'task.taskType': 'dernstraight', - }, - }, - { - term: { - 'task.taskType': 'yawn', - }, - }, - ], - }, - }, - ], - }, - }); - - expect(docs).toMatchObject([ - { - attempts: 0, - id: 'aaa', - schedule: undefined, - params: { hello: 'world' }, - runAt, - scope: ['reporting'], - state: { baby: 'Henhen' }, - status: 'claiming', - taskType: 'yawn', - user: 'jimbo', - ownerId: taskManagerId, - }, - { - attempts: 2, - id: 'bbb', - schedule: { interval: '5m' }, - params: { shazm: 1 }, - runAt, - scope: ['reporting', 'ceo'], - state: { henry: 'The 8th' }, - status: 'claiming', - taskType: 'yawn', - user: 'dabo', - ownerId: taskManagerId, - }, - ]); - }); - - test('it returns version_conflicts that do not include conflicts that were proceeded against', async () => { - const taskManagerId = uuidv1(); - const claimOwnershipUntil = new Date(Date.now()); - const runAt = new Date(); - const tasks = [ - mockInstance({ - runAt, - taskType: 'foo', - schedule: undefined, - attempts: 0, - status: TaskStatus.Claiming, - params: { hello: 'world' }, - state: { baby: 'Henhen' }, - user: 'jimbo', - scope: ['reporting'], - ownerId: taskManagerId, - }), - mockInstance({ - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: TaskStatus.Claiming, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - }), - ]; - const maxDocs = 10; - const [ - { - result: { - stats: { tasksUpdated, tasksConflicted, tasksClaimed }, - }, - }, - ] = await testClaimAvailableTasks({ - storeOpts: { - taskManagerId, - }, - taskClaimingOpts: { getCapacity: () => maxDocs }, - claimingOpts: { - claimOwnershipUntil, - }, - hits: [tasks], - // assume there were 20 version conflists, but thanks to `conflicts="proceed"` - // we proceeded to claim tasks - versionConflicts: 20, - }); - - expect(tasksUpdated).toEqual(2); - // ensure we only count conflicts that *may* have counted against max_docs, no more than that - expect(tasksConflicted).toEqual(10 - tasksUpdated!); - expect(tasksClaimed).toEqual(2); - }); - }); - - describe('task events', () => { - function generateTasks(taskManagerId: string) { - const runAt = new Date(); - const tasks = [ - { - id: 'claimed-by-id', - runAt, - taskType: 'foo', - schedule: undefined, - attempts: 0, - status: TaskStatus.Claiming, - params: { hello: 'world' }, - state: { baby: 'Henhen' }, - user: 'jimbo', - scope: ['reporting'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - traceparent: 'parent', - }, - { - id: 'claimed-by-schedule', - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: TaskStatus.Claiming, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - traceparent: 'newParent', - }, - { - id: 'already-running', - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: TaskStatus.Running, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - traceparent: '', - }, - ]; - - return { taskManagerId, runAt, tasks }; - } - - function instantiateStoreWithMockedApiResponses({ - taskManagerId = uuidv4(), - definitions = taskDefinitions, - getCapacity = () => 10, - tasksClaimed, - }: Partial> & { - taskManagerId?: string; - tasksClaimed?: ConcreteTaskInstance[][]; - } = {}) { - const { runAt, tasks: generatedTasks } = generateTasks(taskManagerId); - const taskCycles = tasksClaimed ?? [generatedTasks]; - - const taskStore = taskStoreMock.create({ taskManagerId }); - taskStore.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); - for (const docs of taskCycles) { - taskStore.fetch.mockResolvedValueOnce({ docs }); - taskStore.updateByQuery.mockResolvedValueOnce({ - updated: docs.length, - version_conflicts: 0, - total: docs.length, - }); - } - - taskStore.fetch.mockResolvedValue({ docs: [] }); - taskStore.updateByQuery.mockResolvedValue({ - updated: 0, - version_conflicts: 0, - total: 0, - }); - - const taskClaiming = new TaskClaiming({ - logger: taskManagerLogger, - definitions, - excludedTaskTypes: [], - unusedTypes: [], - taskStore, - maxAttempts: 2, - getCapacity, - }); - - return { taskManagerId, runAt, taskClaiming }; - } - - test('emits an event when a task is succesfully by scheduling', async () => { - const { taskManagerId, runAt, taskClaiming } = instantiateStoreWithMockedApiResponses(); - - const promise = taskClaiming.events - .pipe( - filter( - (event: TaskEvent) => event.id === 'claimed-by-schedule' - ), - take(1) - ) - .toPromise(); - - await getFirstAsPromise( - taskClaiming.claimAvailableTasks({ - claimOwnershipUntil: new Date(), - }) - ); - - const event = await promise; - expect(event).toMatchObject( - asTaskClaimEvent( - 'claimed-by-schedule', - asOk({ - id: 'claimed-by-schedule', - runAt, - taskType: 'bar', - schedule: { interval: '5m' }, - attempts: 2, - status: 'claiming' as TaskStatus, - params: { shazm: 1 }, - state: { henry: 'The 8th' }, - user: 'dabo', - scope: ['reporting', 'ceo'], - ownerId: taskManagerId, - startedAt: null, - retryAt: null, - scheduledAt: new Date(), - traceparent: 'newParent', - }) - ) - ); - }); - }); }); - -function generateFakeTasks(count: number = 1) { - return _.times(count, (index) => mockInstance({ id: `task:id-${index}` })); -} - -function mockInstance(instance: Partial = {}) { - return Object.assign( - { - id: uuidv4(), - taskType: 'bar', - sequenceNumber: 32, - primaryTerm: 32, - runAt: new Date(), - scheduledAt: new Date(), - startedAt: null, - retryAt: null, - attempts: 0, - params: {}, - scope: ['reporting'], - state: {}, - status: 'idle', - user: 'example', - ownerId: null, - traceparent: '', - }, - instance - ); -} - -function getFirstAsPromise(obs$: Observable): Promise { - return new Promise((resolve, reject) => { - obs$.subscribe(resolve, reject); - }); -} -function getAllAsPromise(obs$: Observable): Promise { - return new Promise((resolve, reject) => { - obs$.pipe(toArray()).subscribe(resolve, reject); - }); -} diff --git a/x-pack/plugins/task_manager/server/queries/task_claiming.ts b/x-pack/plugins/task_manager/server/queries/task_claiming.ts index 60237338fb09..1e31bb5a2ed6 100644 --- a/x-pack/plugins/task_manager/server/queries/task_claiming.ts +++ b/x-pack/plugins/task_manager/server/queries/task_claiming.ts @@ -8,41 +8,30 @@ /* * This module contains helpers for managing the task manager storage layer. */ -import apm from 'elastic-apm-node'; -import minimatch from 'minimatch'; -import { Subject, Observable, from, of } from 'rxjs'; -import { map, mergeScan } from 'rxjs/operators'; -import { groupBy, pick, isPlainObject } from 'lodash'; +import { Subject, Observable, of } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { groupBy, isPlainObject } from 'lodash'; import { Logger } from '@kbn/core/server'; import { asOk, asErr, Result } from '../lib/result_type'; import { ConcreteTaskInstance } from '../task'; -import { TaskClaim, asTaskClaimEvent, startTaskTimer, TaskTiming } from '../task_events'; -import { shouldBeOneOf, mustBeAllOf, filterDownBy, matchesClauses } from './query_clauses'; +import { TaskClaim } from '../task_events'; -import { - updateFieldsAndMarkAsFailed, - IdleTaskWithExpiredRunAt, - InactiveTasks, - RunningOrClaimingTaskWithExpiredRetryAt, - SortByRunAtAndRetryAt, - tasksClaimedByOwner, - tasksOfType, - EnabledTask, -} from './mark_available_tasks_as_claimed'; import { TaskTypeDictionary } from '../task_type_dictionary'; -import { - correctVersionConflictsForContinuation, - TaskStore, - UpdateByQueryResult, - SearchOpts, -} from '../task_store'; +import { TaskStore, UpdateByQueryResult } from '../task_store'; import { FillPoolResult } from '../lib/fill_pool'; -import { TASK_MANAGER_TRANSACTION_TYPE } from '../task_running'; +import { + TaskClaimerOpts, + TaskClaimerFn, + ClaimOwnershipResult, + getTaskClaimer, +} from '../task_claimers'; +export type { ClaimOwnershipResult } from '../task_claimers'; export interface TaskClaimingOpts { logger: Logger; + strategy: string; definitions: TaskTypeDictionary; unusedTypes: string[]; taskStore: TaskStore; @@ -67,31 +56,25 @@ export interface FetchResult { docs: ConcreteTaskInstance[]; } -export interface ClaimOwnershipResult { - stats: { - tasksUpdated: number; - tasksConflicted: number; - tasksClaimed: number; - }; - docs: ConcreteTaskInstance[]; - timing?: TaskTiming; +export function isClaimOwnershipResult(result: unknown): result is ClaimOwnershipResult { + return ( + isPlainObject((result as ClaimOwnershipResult).stats) && + Array.isArray((result as ClaimOwnershipResult).docs) + ); } -export const isClaimOwnershipResult = (result: unknown): result is ClaimOwnershipResult => - isPlainObject((result as ClaimOwnershipResult).stats) && - Array.isArray((result as ClaimOwnershipResult).docs); -enum BatchConcurrency { +export enum BatchConcurrency { Unlimited, Limited, } -type TaskClaimingBatches = Array; -interface TaskClaimingBatch { +export type TaskClaimingBatches = Array; +export interface TaskClaimingBatch { concurrency: Concurrency; tasksTypes: TaskType; } -type UnlimitedBatch = TaskClaimingBatch>; -type LimitedBatch = TaskClaimingBatch; +export type UnlimitedBatch = TaskClaimingBatch>; +export type LimitedBatch = TaskClaimingBatch; export const TASK_MANAGER_MARK_AS_CLAIMED = 'mark-available-tasks-as-claimed'; @@ -108,6 +91,7 @@ export class TaskClaiming { private readonly taskMaxAttempts: Record; private readonly excludedTaskTypes: string[]; private readonly unusedTypes: string[]; + private readonly taskClaimer: TaskClaimerFn; /** * Constructs a new TaskStore. @@ -120,12 +104,12 @@ export class TaskClaiming { this.maxAttempts = opts.maxAttempts; this.taskStore = opts.taskStore; this.getCapacity = opts.getCapacity; - this.logger = opts.logger; + this.logger = opts.logger.get('taskClaiming'); this.taskClaimingBatchesByType = this.partitionIntoClaimingBatches(this.definitions); this.taskMaxAttempts = Object.fromEntries(this.normalizeMaxAttempts(this.definitions)); this.excludedTaskTypes = opts.excludedTaskTypes; this.unusedTypes = opts.unusedTypes; - + this.taskClaimer = getTaskClaimer(opts.strategy); this.events$ = new Subject(); } @@ -177,224 +161,43 @@ export class TaskClaiming { return this.events$; } - private emitEvents = (events: TaskClaim[]) => { - events.forEach((event) => this.events$.next(event)); - }; - public claimAvailableTasksIfCapacityIsAvailable( claimingOptions: Omit ): Observable> { if (this.getCapacity()) { - return this.claimAvailableTasks(claimingOptions).pipe( - map((claimResult) => asOk(claimResult)) - ); + const opts: TaskClaimerOpts = { + batches: this.getClaimingBatches(), + claimOwnershipUntil: claimingOptions.claimOwnershipUntil, + taskStore: this.taskStore, + events$: this.events$, + getCapacity: this.getCapacity, + unusedTypes: this.unusedTypes, + definitions: this.definitions, + taskMaxAttempts: this.taskMaxAttempts, + excludedTaskTypes: this.excludedTaskTypes, + }; + return this.taskClaimer(opts).pipe(map((claimResult) => asOk(claimResult))); } this.logger.debug( `[Task Ownership]: Task Manager has skipped Claiming Ownership of available tasks at it has ran out Available Workers.` ); return of(asErr(FillPoolResult.NoAvailableWorkers)); } - - public claimAvailableTasks({ - claimOwnershipUntil, - }: Omit): Observable { - const initialCapacity = this.getCapacity(); - return from(this.getClaimingBatches()).pipe( - mergeScan( - (accumulatedResult, batch) => { - const stopTaskTimer = startTaskTimer(); - const capacity = Math.min( - initialCapacity - accumulatedResult.stats.tasksClaimed, - isLimited(batch) ? this.getCapacity(batch.tasksTypes) : this.getCapacity() - ); - // if we have no more capacity, short circuit here - if (capacity <= 0) { - return of(accumulatedResult); - } - return from( - this.executeClaimAvailableTasks({ - claimOwnershipUntil, - size: capacity, - taskTypes: isLimited(batch) ? new Set([batch.tasksTypes]) : batch.tasksTypes, - }).then((result) => { - const { stats, docs } = accumulateClaimOwnershipResults(accumulatedResult, result); - stats.tasksConflicted = correctVersionConflictsForContinuation( - stats.tasksClaimed, - stats.tasksConflicted, - initialCapacity - ); - return { stats, docs, timing: stopTaskTimer() }; - }) - ); - }, - // initialise the accumulation with no results - accumulateClaimOwnershipResults(), - // only run one batch at a time - 1 - ) - ); - } - - private executeClaimAvailableTasks = async ({ - claimOwnershipUntil, - size, - taskTypes, - }: OwnershipClaimingOpts): Promise => { - const { updated: tasksUpdated, version_conflicts: tasksConflicted } = - await this.markAvailableTasksAsClaimed({ - claimOwnershipUntil, - size, - taskTypes, - }); - - const docs = tasksUpdated > 0 ? await this.sweepForClaimedTasks(taskTypes, size) : []; - - this.emitEvents(docs.map((doc) => asTaskClaimEvent(doc.id, asOk(doc)))); - - const stats = { - tasksUpdated, - tasksConflicted, - tasksClaimed: docs.length, - }; - - return { - stats, - docs, - }; - }; - - private isTaskTypeExcluded(taskType: string) { - for (const excludedType of this.excludedTaskTypes) { - if (minimatch(taskType, excludedType)) { - return true; - } - } - - return false; - } - - private async markAvailableTasksAsClaimed({ - claimOwnershipUntil, - size, - taskTypes, - }: OwnershipClaimingOpts): Promise { - const { taskTypesToSkip = [], taskTypesToClaim = [] } = groupBy( - this.definitions.getAllTypes(), - (type) => - taskTypes.has(type) && !this.isTaskTypeExcluded(type) - ? 'taskTypesToClaim' - : 'taskTypesToSkip' - ); - const queryForScheduledTasks = mustBeAllOf( - // Task must be enabled - EnabledTask, - // Either a task with idle status and runAt <= now or - // status running or claiming with a retryAt <= now. - shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt) - ); - - const sort: NonNullable = [SortByRunAtAndRetryAt]; - const query = matchesClauses(queryForScheduledTasks, filterDownBy(InactiveTasks)); - const script = updateFieldsAndMarkAsFailed({ - fieldUpdates: { - ownerId: this.taskStore.taskManagerId, - retryAt: claimOwnershipUntil, - }, - claimableTaskTypes: taskTypesToClaim, - skippedTaskTypes: taskTypesToSkip, - unusedTaskTypes: this.unusedTypes, - taskMaxAttempts: pick(this.taskMaxAttempts, taskTypesToClaim), - }); - - const apmTrans = apm.startTransaction( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - - try { - const result = await this.taskStore.updateByQuery( - { - query, - script, - sort, - }, - { - max_docs: size, - } - ); - apmTrans.end('success'); - return result; - } catch (err) { - apmTrans.end('failure'); - throw err; - } - } - - /** - * Fetches tasks from the index, which are owned by the current Kibana instance - */ - private async sweepForClaimedTasks( - taskTypes: Set, - size: number - ): Promise { - const claimedTasksQuery = tasksClaimedByOwner( - this.taskStore.taskManagerId, - tasksOfType([...taskTypes]) - ); - const { docs } = await this.taskStore.fetch({ - query: claimedTasksQuery, - size, - sort: SortByRunAtAndRetryAt, - seq_no_primary_term: true, - }); - - return docs; - } } -const emptyClaimOwnershipResult = () => { - return { - stats: { - tasksUpdated: 0, - tasksConflicted: 0, - tasksClaimed: 0, - tasksRejected: 0, - }, - docs: [], - }; -}; - -function accumulateClaimOwnershipResults( - prev: ClaimOwnershipResult = emptyClaimOwnershipResult(), - next?: ClaimOwnershipResult -) { - if (next) { - const { stats, docs, timing } = next; - const res = { - stats: { - tasksUpdated: stats.tasksUpdated + prev.stats.tasksUpdated, - tasksConflicted: stats.tasksConflicted + prev.stats.tasksConflicted, - tasksClaimed: stats.tasksClaimed + prev.stats.tasksClaimed, - }, - docs, - timing, - }; - return res; - } - return prev; -} - -function isLimited( +export function isLimited( batch: TaskClaimingBatch ): batch is LimitedBatch { return batch.concurrency === BatchConcurrency.Limited; } + function asLimited(tasksType: string): LimitedBatch { return { concurrency: BatchConcurrency.Limited, tasksTypes: tasksType, }; } + function asUnlimited(tasksTypes: Set): UnlimitedBatch { return { concurrency: BatchConcurrency.Unlimited, diff --git a/x-pack/plugins/task_manager/server/task_claimers/README.md b/x-pack/plugins/task_manager/server/task_claimers/README.md new file mode 100644 index 000000000000..0c92f02031d2 --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/README.md @@ -0,0 +1,20 @@ +task_claimers +======================================================================== + +This directory contains code that claims the next tasks to run. + +The code is structured to support multiple strategies, but currently +only supports a `default` strategy. + + +`default` task claiming strategy +------------------------------------------------------------------------ +This has been the strategy for task manager for ... ever? The basic +idea: + +- Run an update by query, for number of available workers, to "mark" + task documents as claimed, by setting task state to `claiming`. + We can do some limited per-task logic in that update script. + +- A search is then run on the documents updated from the update by + query. diff --git a/x-pack/plugins/task_manager/server/task_claimers/index.test.ts b/x-pack/plugins/task_manager/server/task_claimers/index.test.ts new file mode 100644 index 000000000000..be26f0d2f9ef --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/index.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getTaskClaimer } from '.'; +import { claimAvailableTasksDefault } from './strategy_default'; + +describe('task_claimers/index', () => { + describe('getTaskClaimer()', () => { + test('returns expected result for default', () => { + const taskClaimer = getTaskClaimer('default'); + expect(taskClaimer).toBe(claimAvailableTasksDefault); + }); + + test('throws error for unsupported parameter', () => { + expect(() => getTaskClaimer('not-supported')).toThrowErrorMatchingInlineSnapshot( + `"Unknown task claiming strategy (not-supported)"` + ); + }); + }); +}); diff --git a/x-pack/plugins/task_manager/server/task_claimers/index.ts b/x-pack/plugins/task_manager/server/task_claimers/index.ts new file mode 100644 index 000000000000..8074197a147b --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/index.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Subject, Observable } from 'rxjs'; + +import { TaskStore } from '../task_store'; +import { TaskClaim, TaskTiming } from '../task_events'; +import { TaskTypeDictionary } from '../task_type_dictionary'; +import { TaskClaimingBatches } from '../queries/task_claiming'; +import { ConcreteTaskInstance } from '../task'; +import { claimAvailableTasksDefault } from './strategy_default'; +import { CLAIM_STRATEGY_DEFAULT } from '../config'; + +export interface TaskClaimerOpts { + getCapacity: (taskType?: string | undefined) => number; + claimOwnershipUntil: Date; + batches: TaskClaimingBatches; + events$: Subject; + taskStore: TaskStore; + definitions: TaskTypeDictionary; + unusedTypes: string[]; + excludedTaskTypes: string[]; + taskMaxAttempts: Record; +} + +export interface ClaimOwnershipResult { + stats: { + tasksUpdated: number; + tasksConflicted: number; + tasksClaimed: number; + }; + docs: ConcreteTaskInstance[]; + timing?: TaskTiming; +} + +export type TaskClaimerFn = (opts: TaskClaimerOpts) => Observable; + +export function getTaskClaimer(strategy: string): TaskClaimerFn { + switch (strategy) { + case CLAIM_STRATEGY_DEFAULT: + return claimAvailableTasksDefault; + } + throw new Error(`Unknown task claiming strategy (${strategy})`); +} diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_default.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_default.test.ts new file mode 100644 index 000000000000..c89ecdf66921 --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_default.test.ts @@ -0,0 +1,1318 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import _ from 'lodash'; +import { v1 as uuidv1, v4 as uuidv4 } from 'uuid'; +import { filter, take, toArray } from 'rxjs/operators'; + +import { TaskStatus, ConcreteTaskInstance } from '../task'; +import { SearchOpts, StoreOpts, UpdateByQueryOpts, UpdateByQuerySearchOpts } from '../task_store'; +import { asTaskClaimEvent, TaskEvent } from '../task_events'; +import { asOk, isOk, unwrap } from '../lib/result_type'; +import { TaskTypeDictionary } from '../task_type_dictionary'; +import type { MustNotCondition } from '../queries/query_clauses'; +import { mockLogger } from '../test_utils'; +import { + TaskClaiming, + OwnershipClaimingOpts, + TaskClaimingOpts, + TASK_MANAGER_MARK_AS_CLAIMED, +} from '../queries/task_claiming'; +import { Observable } from 'rxjs'; +import { taskStoreMock } from '../task_store.mock'; +import apm from 'elastic-apm-node'; +import { TASK_MANAGER_TRANSACTION_TYPE } from '../task_running'; +import { ClaimOwnershipResult } from '.'; +import { FillPoolResult } from '../lib/fill_pool'; + +jest.mock('../constants', () => ({ + CONCURRENCY_ALLOW_LIST_BY_TASK_TYPE: [ + 'limitedToZero', + 'limitedToOne', + 'anotherLimitedToZero', + 'anotherLimitedToOne', + 'limitedToTwo', + 'limitedToFive', + ], +})); + +const taskManagerLogger = mockLogger(); + +beforeEach(() => jest.clearAllMocks()); + +const mockedDate = new Date('2019-02-12T21:01:22.479Z'); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(global as any).Date = class Date { + constructor() { + return mockedDate; + } + static now() { + return mockedDate.getTime(); + } +}; + +const taskDefinitions = new TaskTypeDictionary(taskManagerLogger); +taskDefinitions.registerTaskDefinitions({ + report: { + title: 'report', + createTaskRunner: jest.fn(), + }, + dernstraight: { + title: 'dernstraight', + createTaskRunner: jest.fn(), + }, + yawn: { + title: 'yawn', + createTaskRunner: jest.fn(), + }, +}); + +const mockApmTrans = { + end: jest.fn(), +}; + +describe('TaskClaiming', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest + .spyOn(apm, 'startTransaction') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .mockImplementation(() => mockApmTrans as any); + }); + + describe('claimAvailableTasks', () => { + function initialiseTestClaiming({ + storeOpts = {}, + taskClaimingOpts = {}, + hits = [generateFakeTasks(1)], + versionConflicts = 2, + excludedTaskTypes = [], + unusedTaskTypes = [], + }: { + storeOpts: Partial; + taskClaimingOpts: Partial; + hits?: ConcreteTaskInstance[][]; + versionConflicts?: number; + excludedTaskTypes?: string[]; + unusedTaskTypes?: string[]; + }) { + const definitions = storeOpts.definitions ?? taskDefinitions; + const store = taskStoreMock.create({ taskManagerId: storeOpts.taskManagerId }); + store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); + + if (hits.length === 1) { + store.fetch.mockResolvedValue({ docs: hits[0] }); + store.updateByQuery.mockResolvedValue({ + updated: hits[0].length, + version_conflicts: versionConflicts, + total: hits[0].length, + }); + } else { + for (const docs of hits) { + store.fetch.mockResolvedValueOnce({ docs }); + store.updateByQuery.mockResolvedValueOnce({ + updated: docs.length, + version_conflicts: versionConflicts, + total: docs.length, + }); + } + } + + const taskClaiming = new TaskClaiming({ + logger: taskManagerLogger, + strategy: 'default', + definitions, + taskStore: store, + excludedTaskTypes, + unusedTypes: unusedTaskTypes, + maxAttempts: taskClaimingOpts.maxAttempts ?? 2, + getCapacity: taskClaimingOpts.getCapacity ?? (() => 10), + ...taskClaimingOpts, + }); + + return { taskClaiming, store }; + } + + async function testClaimAvailableTasks({ + storeOpts = {}, + taskClaimingOpts = {}, + claimingOpts, + hits = [generateFakeTasks(1)], + versionConflicts = 2, + excludedTaskTypes = [], + unusedTaskTypes = [], + }: { + storeOpts: Partial; + taskClaimingOpts: Partial; + claimingOpts: Omit; + hits?: ConcreteTaskInstance[][]; + versionConflicts?: number; + excludedTaskTypes?: string[]; + unusedTaskTypes?: string[]; + }) { + const getCapacity = taskClaimingOpts.getCapacity ?? (() => 10); + const { taskClaiming, store } = initialiseTestClaiming({ + storeOpts, + taskClaimingOpts, + excludedTaskTypes, + unusedTaskTypes, + hits, + versionConflicts, + }); + + const resultsOrErr = await getAllAsPromise( + taskClaiming.claimAvailableTasksIfCapacityIsAvailable(claimingOpts) + ); + for (const resultOrErr of resultsOrErr) { + if (!isOk(resultOrErr)) { + expect(resultOrErr).toBe(undefined); + } + } + + const results = resultsOrErr.map((resultOrErr) => { + if (!isOk(resultOrErr)) { + expect(resultOrErr).toBe(undefined); + } + return unwrap(resultOrErr) as ClaimOwnershipResult; + }); + + expect(apm.startTransaction).toHaveBeenCalledWith( + TASK_MANAGER_MARK_AS_CLAIMED, + TASK_MANAGER_TRANSACTION_TYPE + ); + expect(mockApmTrans.end).toHaveBeenCalledWith('success'); + + expect(store.updateByQuery.mock.calls[0][1]).toMatchObject({ + max_docs: getCapacity(), + }); + expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: getCapacity() }); + return results.map((result, index) => ({ + result, + args: { + search: store.fetch.mock.calls[index][0] as SearchOpts & { + query: MustNotCondition; + }, + updateByQuery: store.updateByQuery.mock.calls[index] as [ + UpdateByQuerySearchOpts, + UpdateByQueryOpts + ], + }, + })); + } + + test('makes calls to APM as expected when markAvailableTasksAsClaimed throws error', async () => { + const maxAttempts = _.random(2, 43); + const customMaxAttempts = _.random(44, 100); + + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + }); + + const { taskClaiming, store } = initialiseTestClaiming({ + storeOpts: { + definitions, + }, + taskClaimingOpts: { + maxAttempts, + }, + }); + + store.updateByQuery.mockRejectedValue(new Error('Oh no')); + + await expect( + getAllAsPromise( + taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ + claimOwnershipUntil: new Date(), + }) + ) + ).rejects.toMatchInlineSnapshot(`[Error: Oh no]`); + + expect(apm.startTransaction).toHaveBeenCalledWith( + TASK_MANAGER_MARK_AS_CLAIMED, + TASK_MANAGER_TRANSACTION_TYPE + ); + expect(mockApmTrans.end).toHaveBeenCalledWith('failure'); + }); + + test('it filters claimed tasks down by supported types, maxAttempts, status, and runAt', async () => { + const maxAttempts = _.random(2, 43); + const customMaxAttempts = _.random(44, 100); + + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + foobar: { + title: 'foobar', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + }); + + const [ + { + args: { + updateByQuery: [{ query, sort }], + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + definitions, + }, + taskClaimingOpts: { + maxAttempts, + }, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + excludedTaskTypes: ['foobar'], + }); + expect(query).toMatchObject({ + bool: { + must: [ + { + bool: { + must: [ + { + term: { + 'task.enabled': true, + }, + }, + ], + }, + }, + { + bool: { + should: [ + { + bool: { + must: [ + { term: { 'task.status': 'idle' } }, + { range: { 'task.runAt': { lte: 'now' } } }, + ], + }, + }, + { + bool: { + must: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }, + { range: { 'task.retryAt': { lte: 'now' } } }, + ], + }, + }, + ], + }, + }, + ], + filter: [ + { + bool: { + must_not: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + must: { range: { 'task.retryAt': { gt: 'now' } } }, + }, + }, + ], + }, + }, + ], + }, + }); + expect(sort).toMatchObject([ + { + _script: { + type: 'number', + order: 'asc', + script: { + lang: 'painless', + source: ` +if (doc['task.retryAt'].size()!=0) { + return doc['task.retryAt'].value.toInstant().toEpochMilli(); +} +if (doc['task.runAt'].size()!=0) { + return doc['task.runAt'].value.toInstant().toEpochMilli(); +} + `, + }, + }, + }, + ]); + }); + + test('it should claim in batches partitioned by maxConcurrency', async () => { + const maxAttempts = _.random(2, 43); + const definitions = new TaskTypeDictionary(mockLogger()); + const taskManagerId = uuidv1(); + const fieldUpdates = { + ownerId: taskManagerId, + retryAt: new Date(Date.now()), + }; + definitions.registerTaskDefinitions({ + unlimited: { + title: 'unlimited', + createTaskRunner: jest.fn(), + }, + limitedToZero: { + title: 'limitedToZero', + maxConcurrency: 0, + createTaskRunner: jest.fn(), + }, + anotherUnlimited: { + title: 'anotherUnlimited', + createTaskRunner: jest.fn(), + }, + finalUnlimited: { + title: 'finalUnlimited', + createTaskRunner: jest.fn(), + }, + limitedToOne: { + title: 'limitedToOne', + maxConcurrency: 1, + createTaskRunner: jest.fn(), + }, + anotherLimitedToOne: { + title: 'anotherLimitedToOne', + maxConcurrency: 1, + createTaskRunner: jest.fn(), + }, + limitedToTwo: { + title: 'limitedToTwo', + maxConcurrency: 2, + createTaskRunner: jest.fn(), + }, + }); + const results = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: { + maxAttempts, + getCapacity: (type) => { + switch (type) { + case 'limitedToOne': + case 'anotherLimitedToOne': + return 1; + case 'limitedToTwo': + return 2; + default: + return 10; + } + }, + }, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(results.length).toEqual(4); + + expect(results[0].args.updateByQuery[1].max_docs).toEqual(10); + expect(results[0].args.updateByQuery[0].script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['unlimited', 'anotherUnlimited', 'finalUnlimited'], + skippedTaskTypes: [ + 'limitedToZero', + 'limitedToOne', + 'anotherLimitedToOne', + 'limitedToTwo', + ], + unusedTaskTypes: [], + taskMaxAttempts: { + unlimited: maxAttempts, + }, + }, + }); + + expect(results[1].args.updateByQuery[1].max_docs).toEqual(1); + expect(results[1].args.updateByQuery[0].script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['limitedToOne'], + skippedTaskTypes: [ + 'unlimited', + 'limitedToZero', + 'anotherUnlimited', + 'finalUnlimited', + 'anotherLimitedToOne', + 'limitedToTwo', + ], + taskMaxAttempts: { + limitedToOne: maxAttempts, + }, + }, + }); + + expect(results[2].args.updateByQuery[1].max_docs).toEqual(1); + expect(results[2].args.updateByQuery[0].script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['anotherLimitedToOne'], + skippedTaskTypes: [ + 'unlimited', + 'limitedToZero', + 'anotherUnlimited', + 'finalUnlimited', + 'limitedToOne', + 'limitedToTwo', + ], + taskMaxAttempts: { + anotherLimitedToOne: maxAttempts, + }, + }, + }); + + expect(results[3].args.updateByQuery[1].max_docs).toEqual(2); + expect(results[3].args.updateByQuery[0].script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['limitedToTwo'], + skippedTaskTypes: [ + 'unlimited', + 'limitedToZero', + 'anotherUnlimited', + 'finalUnlimited', + 'limitedToOne', + 'anotherLimitedToOne', + ], + taskMaxAttempts: { + limitedToTwo: maxAttempts, + }, + }, + }); + }); + + test('it should reduce the available capacity from batch to batch', async () => { + const maxAttempts = _.random(2, 43); + const definitions = new TaskTypeDictionary(mockLogger()); + const taskManagerId = uuidv1(); + definitions.registerTaskDefinitions({ + unlimited: { + title: 'unlimited', + createTaskRunner: jest.fn(), + }, + limitedToFive: { + title: 'limitedToFive', + maxConcurrency: 5, + createTaskRunner: jest.fn(), + }, + limitedToTwo: { + title: 'limitedToTwo', + maxConcurrency: 2, + createTaskRunner: jest.fn(), + }, + }); + const results = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: { + maxAttempts, + getCapacity: (type) => { + switch (type) { + case 'limitedToTwo': + return 2; + case 'limitedToFive': + return 5; + default: + return 10; + } + }, + }, + hits: [ + [ + // 7 returned by unlimited query + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + mockInstance({ + taskType: 'unlimited', + }), + ], + // 2 returned by limitedToFive query + [ + mockInstance({ + taskType: 'limitedToFive', + }), + mockInstance({ + taskType: 'limitedToFive', + }), + ], + // 1 reterned by limitedToTwo query + [ + mockInstance({ + taskType: 'limitedToTwo', + }), + ], + ], + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(results.length).toEqual(3); + + expect(results[0].args.updateByQuery[1].max_docs).toEqual(10); + + // only capacity for 3, even though 5 are allowed + expect(results[1].args.updateByQuery[1].max_docs).toEqual(3); + + // only capacity for 1, even though 2 are allowed + expect(results[2].args.updateByQuery[1].max_docs).toEqual(1); + }); + + test('it shuffles the types claimed in batches to ensure no type starves another', async () => { + const maxAttempts = _.random(2, 43); + const definitions = new TaskTypeDictionary(mockLogger()); + const taskManagerId = uuidv1(); + definitions.registerTaskDefinitions({ + unlimited: { + title: 'unlimited', + createTaskRunner: jest.fn(), + }, + anotherUnlimited: { + title: 'anotherUnlimited', + createTaskRunner: jest.fn(), + }, + finalUnlimited: { + title: 'finalUnlimited', + createTaskRunner: jest.fn(), + }, + limitedToOne: { + title: 'limitedToOne', + maxConcurrency: 1, + createTaskRunner: jest.fn(), + }, + anotherLimitedToOne: { + title: 'anotherLimitedToOne', + maxConcurrency: 1, + createTaskRunner: jest.fn(), + }, + limitedToTwo: { + title: 'limitedToTwo', + maxConcurrency: 2, + createTaskRunner: jest.fn(), + }, + }); + + const { taskClaiming, store } = initialiseTestClaiming({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: { + maxAttempts, + getCapacity: (type) => { + switch (type) { + case 'limitedToOne': + case 'anotherLimitedToOne': + return 1; + case 'limitedToTwo': + return 2; + default: + return 10; + } + }, + }, + }); + + async function getUpdateByQueryScriptParams() { + return ( + await getAllAsPromise( + taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ + claimOwnershipUntil: new Date(), + }) + ) + ).map( + (result, index) => + ( + store.updateByQuery.mock.calls[index][0] as { + query: MustNotCondition; + size: number; + sort: string | string[]; + script: { + params: { + [claimableTaskTypes: string]: string[]; + }; + }; + } + ).script.params.claimableTaskTypes + ); + } + + const firstCycle = await getUpdateByQueryScriptParams(); + store.updateByQuery.mockClear(); + const secondCycle = await getUpdateByQueryScriptParams(); + + expect(firstCycle.length).toEqual(4); + expect(secondCycle.length).toEqual(4); + expect(firstCycle).not.toMatchObject(secondCycle); + }); + + test('it passes any unusedTaskTypes to script', async () => { + const maxAttempts = _.random(2, 43); + const customMaxAttempts = _.random(44, 100); + const taskManagerId = uuidv1(); + const fieldUpdates = { + ownerId: taskManagerId, + retryAt: new Date(Date.now()), + }; + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + foobar: { + title: 'foobar', + maxAttempts: customMaxAttempts, + createTaskRunner: jest.fn(), + }, + }); + + const [ + { + args: { + updateByQuery: [{ query, script }], + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + definitions, + taskManagerId, + }, + taskClaimingOpts: { + maxAttempts, + }, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + excludedTaskTypes: ['foobar'], + unusedTaskTypes: ['barfoo'], + }); + expect(query).toMatchObject({ + bool: { + must: [ + { + bool: { + must: [ + { + term: { + 'task.enabled': true, + }, + }, + ], + }, + }, + { + bool: { + should: [ + { + bool: { + must: [ + { term: { 'task.status': 'idle' } }, + { range: { 'task.runAt': { lte: 'now' } } }, + ], + }, + }, + { + bool: { + must: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }, + { range: { 'task.retryAt': { lte: 'now' } } }, + ], + }, + }, + ], + }, + }, + ], + filter: [ + { + bool: { + must_not: [ + { + bool: { + should: [ + { term: { 'task.status': 'running' } }, + { term: { 'task.status': 'claiming' } }, + ], + must: { range: { 'task.retryAt': { gt: 'now' } } }, + }, + }, + ], + }, + }, + ], + }, + }); + expect(script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['foo', 'bar'], + skippedTaskTypes: ['foobar'], + unusedTaskTypes: ['barfoo'], + taskMaxAttempts: { + bar: customMaxAttempts, + foo: maxAttempts, + }, + }, + }); + }); + + test('it claims tasks by setting their ownerId, status and retryAt', async () => { + const taskManagerId = uuidv1(); + const claimOwnershipUntil = new Date(Date.now()); + const fieldUpdates = { + ownerId: taskManagerId, + retryAt: claimOwnershipUntil, + }; + const [ + { + args: { + updateByQuery: [{ script }], + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil, + }, + }); + expect(script).toMatchObject({ + source: expect.any(String), + lang: 'painless', + params: { + fieldUpdates, + claimableTaskTypes: ['report', 'dernstraight', 'yawn'], + skippedTaskTypes: [], + taskMaxAttempts: { + dernstraight: 2, + report: 2, + yawn: 2, + }, + }, + }); + }); + + test('it filters out running tasks', async () => { + const taskManagerId = uuidv1(); + const claimOwnershipUntil = new Date(Date.now()); + const runAt = new Date(); + const tasks = [ + mockInstance({ + id: 'aaa', + runAt, + taskType: 'yawn', + schedule: undefined, + attempts: 0, + status: TaskStatus.Claiming, + params: { hello: 'world' }, + state: { baby: 'Henhen' }, + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + }), + ]; + const [ + { + result: { docs }, + args: { + search: { query }, + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil, + }, + hits: [tasks], + }); + + expect(query).toMatchObject({ + bool: { + must: [ + { + term: { + 'task.ownerId': taskManagerId, + }, + }, + { term: { 'task.status': 'claiming' } }, + { + bool: { + should: [ + { + term: { + 'task.taskType': 'report', + }, + }, + { + term: { + 'task.taskType': 'dernstraight', + }, + }, + { + term: { + 'task.taskType': 'yawn', + }, + }, + ], + }, + }, + ], + }, + }); + + expect(docs).toMatchObject([ + { + attempts: 0, + id: 'aaa', + schedule: undefined, + params: { hello: 'world' }, + runAt, + scope: ['reporting'], + state: { baby: 'Henhen' }, + status: 'claiming', + taskType: 'yawn', + user: 'jimbo', + ownerId: taskManagerId, + }, + ]); + }); + + test('it returns task objects', async () => { + const taskManagerId = uuidv1(); + const claimOwnershipUntil = new Date(Date.now()); + const runAt = new Date(); + const tasks = [ + mockInstance({ + id: 'aaa', + runAt, + taskType: 'yawn', + schedule: undefined, + attempts: 0, + status: TaskStatus.Claiming, + params: { hello: 'world' }, + state: { baby: 'Henhen' }, + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + }), + mockInstance({ + id: 'bbb', + runAt, + taskType: 'yawn', + schedule: { interval: '5m' }, + attempts: 2, + status: TaskStatus.Claiming, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + }), + ]; + const [ + { + result: { docs }, + args: { + search: { query }, + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil, + }, + hits: [tasks], + }); + + expect(query).toMatchObject({ + bool: { + must: [ + { + term: { + 'task.ownerId': taskManagerId, + }, + }, + { term: { 'task.status': 'claiming' } }, + { + bool: { + should: [ + { + term: { + 'task.taskType': 'report', + }, + }, + { + term: { + 'task.taskType': 'dernstraight', + }, + }, + { + term: { + 'task.taskType': 'yawn', + }, + }, + ], + }, + }, + ], + }, + }); + + expect(docs).toMatchObject([ + { + attempts: 0, + id: 'aaa', + schedule: undefined, + params: { hello: 'world' }, + runAt, + scope: ['reporting'], + state: { baby: 'Henhen' }, + status: 'claiming', + taskType: 'yawn', + user: 'jimbo', + ownerId: taskManagerId, + }, + { + attempts: 2, + id: 'bbb', + schedule: { interval: '5m' }, + params: { shazm: 1 }, + runAt, + scope: ['reporting', 'ceo'], + state: { henry: 'The 8th' }, + status: 'claiming', + taskType: 'yawn', + user: 'dabo', + ownerId: taskManagerId, + }, + ]); + }); + + test('it returns version_conflicts that do not include conflicts that were proceeded against', async () => { + const taskManagerId = uuidv1(); + const claimOwnershipUntil = new Date(Date.now()); + const runAt = new Date(); + const tasks = [ + mockInstance({ + runAt, + taskType: 'foo', + schedule: undefined, + attempts: 0, + status: TaskStatus.Claiming, + params: { hello: 'world' }, + state: { baby: 'Henhen' }, + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + }), + mockInstance({ + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: TaskStatus.Claiming, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + }), + ]; + const maxDocs = 10; + const [ + { + result: { + stats: { tasksUpdated, tasksConflicted, tasksClaimed }, + }, + }, + ] = await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + }, + taskClaimingOpts: { getCapacity: () => maxDocs }, + claimingOpts: { + claimOwnershipUntil, + }, + hits: [tasks], + // assume there were 20 version conflists, but thanks to `conflicts="proceed"` + // we proceeded to claim tasks + versionConflicts: 20, + }); + + expect(tasksUpdated).toEqual(2); + // ensure we only count conflicts that *may* have counted against max_docs, no more than that + expect(tasksConflicted).toEqual(10 - tasksUpdated!); + expect(tasksClaimed).toEqual(2); + }); + }); + + describe('task events', () => { + function generateTasks(taskManagerId: string) { + const runAt = new Date(); + const tasks = [ + { + id: 'claimed-by-id', + runAt, + taskType: 'foo', + schedule: undefined, + attempts: 0, + status: TaskStatus.Claiming, + params: { hello: 'world' }, + state: { baby: 'Henhen' }, + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + traceparent: 'parent', + }, + { + id: 'claimed-by-schedule', + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: TaskStatus.Claiming, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + traceparent: 'newParent', + }, + { + id: 'already-running', + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: TaskStatus.Running, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + traceparent: '', + }, + ]; + + return { taskManagerId, runAt, tasks }; + } + + function instantiateStoreWithMockedApiResponses({ + taskManagerId = uuidv4(), + definitions = taskDefinitions, + getCapacity = () => 10, + tasksClaimed, + }: Partial> & { + taskManagerId?: string; + tasksClaimed?: ConcreteTaskInstance[][]; + } = {}) { + const { runAt, tasks: generatedTasks } = generateTasks(taskManagerId); + const taskCycles = tasksClaimed ?? [generatedTasks]; + + const taskStore = taskStoreMock.create({ taskManagerId }); + taskStore.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); + for (const docs of taskCycles) { + taskStore.fetch.mockResolvedValueOnce({ docs }); + taskStore.updateByQuery.mockResolvedValueOnce({ + updated: docs.length, + version_conflicts: 0, + total: docs.length, + }); + } + + taskStore.fetch.mockResolvedValue({ docs: [] }); + taskStore.updateByQuery.mockResolvedValue({ + updated: 0, + version_conflicts: 0, + total: 0, + }); + + const taskClaiming = new TaskClaiming({ + logger: taskManagerLogger, + strategy: 'default', + definitions, + excludedTaskTypes: [], + unusedTypes: [], + taskStore, + maxAttempts: 2, + getCapacity, + }); + + return { taskManagerId, runAt, taskClaiming }; + } + + test('emits an event when a task is succesfully by scheduling', async () => { + const { taskManagerId, runAt, taskClaiming } = instantiateStoreWithMockedApiResponses(); + + const promise = taskClaiming.events + .pipe( + filter( + (event: TaskEvent) => event.id === 'claimed-by-schedule' + ), + take(1) + ) + .toPromise(); + + await getFirstAsPromise( + taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ + claimOwnershipUntil: new Date(), + }) + ); + + const event = await promise; + expect(event).toMatchObject( + asTaskClaimEvent( + 'claimed-by-schedule', + asOk({ + id: 'claimed-by-schedule', + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: 'claiming' as TaskStatus, + params: { shazm: 1 }, + state: { henry: 'The 8th' }, + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + startedAt: null, + retryAt: null, + scheduledAt: new Date(), + traceparent: 'newParent', + }) + ) + ); + }); + }); +}); + +function generateFakeTasks(count: number = 1) { + return _.times(count, (index) => mockInstance({ id: `task:id-${index}` })); +} + +function mockInstance(instance: Partial = {}) { + return Object.assign( + { + id: uuidv4(), + taskType: 'bar', + sequenceNumber: 32, + primaryTerm: 32, + runAt: new Date(), + scheduledAt: new Date(), + startedAt: null, + retryAt: null, + attempts: 0, + params: {}, + scope: ['reporting'], + state: {}, + status: 'idle', + user: 'example', + ownerId: null, + traceparent: '', + }, + instance + ); +} + +function getFirstAsPromise(obs$: Observable): Promise { + return new Promise((resolve, reject) => { + obs$.subscribe(resolve, reject); + }); +} +function getAllAsPromise(obs$: Observable): Promise { + return new Promise((resolve, reject) => { + obs$.pipe(toArray()).subscribe(resolve, reject); + }); +} diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_default.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_default.ts new file mode 100644 index 000000000000..0d9ccb2ef723 --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_default.ts @@ -0,0 +1,255 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * This module contains helpers for managing the task manager storage layer. + */ +import apm from 'elastic-apm-node'; +import minimatch from 'minimatch'; +import { Subject, Observable, from, of } from 'rxjs'; +import { mergeScan } from 'rxjs/operators'; +import { groupBy, pick } from 'lodash'; + +import { asOk } from '../lib/result_type'; +import { TaskTypeDictionary } from '../task_type_dictionary'; +import { TaskClaimerOpts, ClaimOwnershipResult } from '.'; +import { ConcreteTaskInstance } from '../task'; +import { TASK_MANAGER_TRANSACTION_TYPE } from '../task_running'; +import { isLimited, TASK_MANAGER_MARK_AS_CLAIMED } from '../queries/task_claiming'; +import { TaskClaim, asTaskClaimEvent, startTaskTimer } from '../task_events'; +import { shouldBeOneOf, mustBeAllOf, filterDownBy, matchesClauses } from '../queries/query_clauses'; + +import { + updateFieldsAndMarkAsFailed, + IdleTaskWithExpiredRunAt, + InactiveTasks, + RunningOrClaimingTaskWithExpiredRetryAt, + SortByRunAtAndRetryAt, + tasksClaimedByOwner, + tasksOfType, + EnabledTask, +} from '../queries/mark_available_tasks_as_claimed'; + +import { + correctVersionConflictsForContinuation, + TaskStore, + UpdateByQueryResult, + SearchOpts, +} from '../task_store'; + +interface OwnershipClaimingOpts { + claimOwnershipUntil: Date; + size: number; + taskTypes: Set; + taskStore: TaskStore; + events$: Subject; + definitions: TaskTypeDictionary; + unusedTypes: string[]; + excludedTaskTypes: string[]; + taskMaxAttempts: Record; +} + +export function claimAvailableTasksDefault( + opts: TaskClaimerOpts +): Observable { + const { getCapacity, claimOwnershipUntil, batches, events$, taskStore } = opts; + const { definitions, unusedTypes, excludedTaskTypes, taskMaxAttempts } = opts; + const initialCapacity = getCapacity(); + return from(batches).pipe( + mergeScan( + (accumulatedResult, batch) => { + const stopTaskTimer = startTaskTimer(); + const capacity = Math.min( + initialCapacity - accumulatedResult.stats.tasksClaimed, + isLimited(batch) ? getCapacity(batch.tasksTypes) : getCapacity() + ); + // if we have no more capacity, short circuit here + if (capacity <= 0) { + return of(accumulatedResult); + } + return from( + executeClaimAvailableTasks({ + claimOwnershipUntil, + size: capacity, + events$, + taskTypes: isLimited(batch) ? new Set([batch.tasksTypes]) : batch.tasksTypes, + taskStore, + definitions, + unusedTypes, + excludedTaskTypes, + taskMaxAttempts, + }).then((result) => { + const { stats, docs } = accumulateClaimOwnershipResults(accumulatedResult, result); + stats.tasksConflicted = correctVersionConflictsForContinuation( + stats.tasksClaimed, + stats.tasksConflicted, + initialCapacity + ); + return { stats, docs, timing: stopTaskTimer() }; + }) + ); + }, + // initialise the accumulation with no results + accumulateClaimOwnershipResults(), + // only run one batch at a time + 1 + ) + ); +} + +async function executeClaimAvailableTasks( + opts: OwnershipClaimingOpts +): Promise { + const { taskStore, size, taskTypes, events$ } = opts; + const { updated: tasksUpdated, version_conflicts: tasksConflicted } = + await markAvailableTasksAsClaimed(opts); + + const docs = tasksUpdated > 0 ? await sweepForClaimedTasks(taskStore, taskTypes, size) : []; + + emitEvents( + events$, + docs.map((doc) => asTaskClaimEvent(doc.id, asOk(doc))) + ); + + const stats = { + tasksUpdated, + tasksConflicted, + tasksClaimed: docs.length, + }; + + return { + stats, + docs, + }; +} + +function emitEvents(events$: Subject, events: TaskClaim[]) { + events.forEach((event) => events$.next(event)); +} + +function isTaskTypeExcluded(excludedTaskTypes: string[], taskType: string) { + for (const excludedType of excludedTaskTypes) { + if (minimatch(taskType, excludedType)) { + return true; + } + } + + return false; +} + +async function markAvailableTasksAsClaimed({ + definitions, + excludedTaskTypes, + taskStore, + claimOwnershipUntil, + size, + taskTypes, + unusedTypes, + taskMaxAttempts, +}: OwnershipClaimingOpts): Promise { + const { taskTypesToSkip = [], taskTypesToClaim = [] } = groupBy( + definitions.getAllTypes(), + (type) => + taskTypes.has(type) && !isTaskTypeExcluded(excludedTaskTypes, type) + ? 'taskTypesToClaim' + : 'taskTypesToSkip' + ); + const queryForScheduledTasks = mustBeAllOf( + // Task must be enabled + EnabledTask, + // Either a task with idle status and runAt <= now or + // status running or claiming with a retryAt <= now. + shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt) + ); + + const sort: NonNullable = [SortByRunAtAndRetryAt]; + const query = matchesClauses(queryForScheduledTasks, filterDownBy(InactiveTasks)); + const script = updateFieldsAndMarkAsFailed({ + fieldUpdates: { + ownerId: taskStore.taskManagerId, + retryAt: claimOwnershipUntil, + }, + claimableTaskTypes: taskTypesToClaim, + skippedTaskTypes: taskTypesToSkip, + unusedTaskTypes: unusedTypes, + taskMaxAttempts: pick(taskMaxAttempts, taskTypesToClaim), + }); + + const apmTrans = apm.startTransaction( + TASK_MANAGER_MARK_AS_CLAIMED, + TASK_MANAGER_TRANSACTION_TYPE + ); + + try { + const result = await taskStore.updateByQuery( + { + query, + script, + sort, + }, + { + max_docs: size, + } + ); + apmTrans.end('success'); + return result; + } catch (err) { + apmTrans.end('failure'); + throw err; + } +} + +async function sweepForClaimedTasks( + taskStore: TaskStore, + taskTypes: Set, + size: number +): Promise { + const claimedTasksQuery = tasksClaimedByOwner( + taskStore.taskManagerId, + tasksOfType([...taskTypes]) + ); + const { docs } = await taskStore.fetch({ + query: claimedTasksQuery, + size, + sort: SortByRunAtAndRetryAt, + seq_no_primary_term: true, + }); + + return docs; +} + +function emptyClaimOwnershipResult() { + return { + stats: { + tasksUpdated: 0, + tasksConflicted: 0, + tasksClaimed: 0, + tasksRejected: 0, + }, + docs: [], + }; +} + +function accumulateClaimOwnershipResults( + prev: ClaimOwnershipResult = emptyClaimOwnershipResult(), + next?: ClaimOwnershipResult +) { + if (next) { + const { stats, docs, timing } = next; + const res = { + stats: { + tasksUpdated: stats.tasksUpdated + prev.stats.tasksUpdated, + tasksConflicted: stats.tasksConflicted + prev.stats.tasksConflicted, + tasksClaimed: stats.tasksClaimed + prev.stats.tasksClaimed, + }, + docs, + timing, + }; + return res; + } + return prev; +} diff --git a/x-pack/plugins/task_manager/server/task_pool.test.ts b/x-pack/plugins/task_manager/server/task_pool.test.ts index 10e440184ab2..5fb1325da3df 100644 --- a/x-pack/plugins/task_manager/server/task_pool.test.ts +++ b/x-pack/plugins/task_manager/server/task_pool.test.ts @@ -392,6 +392,43 @@ describe('TaskPool', () => { expect(shouldNotRun).not.toHaveBeenCalled(); }); + // This test is from https://github.com/elastic/kibana/issues/172116 + // It's not clear how to reproduce the actual error, but it is easy to + // reproduce with the wacky test below. It does log the exact error + // from that issue, without the corresponding fix in task_pool.ts + test('works when available workers is 0 but there are tasks to run', async () => { + const logger = loggingSystemMock.create().get(); + const pool = new TaskPool({ + maxWorkers$: of(2), + logger, + }); + + const shouldRun = mockRun(); + + const taskId = uuidv4(); + const task1 = mockTask({ id: taskId, run: shouldRun }); + + // we need to alternate the values of `availableWorkers`. First it + // should be 0, then 1, then 0, then 1, etc. This will cause task_pool.run + // to partition tasks (0 to run, everything as leftover), then at the + // end of run(), to check if it should recurse, it should be > 0. + let awValue = 1; + Object.defineProperty(pool, 'availableWorkers', { + get() { + return ++awValue % 2; + }, + }); + + const result = await pool.run([task1]); + expect(result).toBe(TaskPoolRunResult.RanOutOfCapacity); + + expect((logger as jest.Mocked).warn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "task pool run attempts exceeded 3; assuming ran out of capacity; availableWorkers: 0, tasksToRun: 0, leftOverTasks: 1, maxWorkers: 2, occupiedWorkers: 0, workerLoad: 0", + ] + `); + }); + function mockRun() { return jest.fn(async () => { await sleep(0); diff --git a/x-pack/plugins/task_manager/server/task_pool.ts b/x-pack/plugins/task_manager/server/task_pool.ts index 11b79b6d570d..a3a047cd735c 100644 --- a/x-pack/plugins/task_manager/server/task_pool.ts +++ b/x-pack/plugins/task_manager/server/task_pool.ts @@ -34,6 +34,7 @@ export enum TaskPoolRunResult { } const VERSION_CONFLICT_MESSAGE = 'Task has been claimed by another Kibana service'; +const MAX_RUN_ATTEMPTS = 3; /** * Runs tasks in batches, taking costs into account. @@ -107,8 +108,27 @@ export class TaskPool { * @param {TaskRunner[]} tasks * @returns {Promise} */ - public run = async (tasks: TaskRunner[]): Promise => { - const [tasksToRun, leftOverTasks] = partitionListByCount(tasks, this.availableWorkers); + public async run(tasks: TaskRunner[], attempt = 1): Promise { + // Note `this.availableWorkers` is a getter with side effects, so we just want + // to call it once for this bit of the code. + const availableWorkers = this.availableWorkers; + const [tasksToRun, leftOverTasks] = partitionListByCount(tasks, availableWorkers); + + if (attempt > MAX_RUN_ATTEMPTS) { + const stats = [ + `availableWorkers: ${availableWorkers}`, + `tasksToRun: ${tasksToRun.length}`, + `leftOverTasks: ${leftOverTasks.length}`, + `maxWorkers: ${this.maxWorkers}`, + `occupiedWorkers: ${this.occupiedWorkers}`, + `workerLoad: ${this.workerLoad}`, + ].join(', '); + this.logger.warn( + `task pool run attempts exceeded ${MAX_RUN_ATTEMPTS}; assuming ran out of capacity; ${stats}` + ); + return TaskPoolRunResult.RanOutOfCapacity; + } + if (tasksToRun.length) { await Promise.all( tasksToRun @@ -144,14 +164,14 @@ export class TaskPool { if (leftOverTasks.length) { if (this.availableWorkers) { - return this.run(leftOverTasks); + return this.run(leftOverTasks, attempt + 1); } return TaskPoolRunResult.RanOutOfCapacity; } else if (!this.availableWorkers) { return TaskPoolRunResult.RunningAtCapacity; } return TaskPoolRunResult.RunningAllClaimedTasks; - }; + } public cancelRunningTasks() { this.logger.debug('Cancelling running tasks.'); diff --git a/x-pack/plugins/threat_intelligence/cypress/e2e/block_list.cy.ts b/x-pack/plugins/threat_intelligence/cypress/e2e/block_list.cy.ts index 63f58acf9948..a6ce796d4f3f 100644 --- a/x-pack/plugins/threat_intelligence/cypress/e2e/block_list.cy.ts +++ b/x-pack/plugins/threat_intelligence/cypress/e2e/block_list.cy.ts @@ -35,7 +35,8 @@ const FIRST_BLOCK_LIST_NEW_DESCRIPTION = 'the first description'; const SECOND_BLOCK_LIST_NEW_NAME = 'second blocklist entry'; const SECOND_BLOCK_LIST_NEW_DESCRIPTION = 'the second description'; -describe('Block list with invalid indicators', { tags: '@ess' }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/171783 +describe.skip('Block list with invalid indicators', { tags: '@ess' }, () => { beforeEach(() => { esArchiverLoad('threat_intelligence/invalid_indicators_data'); login(); diff --git a/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts b/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts index cbb95e9a610f..6ad05c047257 100644 --- a/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts +++ b/x-pack/plugins/threat_intelligence/cypress/e2e/indicators.cy.ts @@ -56,7 +56,11 @@ const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; const URL_WITH_CONTRADICTORY_FILTERS = '/app/security/threat_intelligence/indicators?indicators=(filterQuery:(language:kuery,query:%27%27),filters:!((%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:file),type:phrase),query:(match_phrase:(threat.indicator.type:file))),(%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:url),type:phrase),query:(match_phrase:(threat.indicator.type:url)))),timeRange:(from:now/d,to:now/d))'; -describe('Invalid Indicators', { tags: '@ess' }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/171779 +// FLAKY: https://github.com/elastic/kibana/issues/171778 +// FLAKY: https://github.com/elastic/kibana/issues/171785 +// FLAKY: https://github.com/elastic/kibana/issues/171786 +describe.skip('Invalid Indicators', { tags: '@ess' }, () => { describe('verify the grid loads even with missing fields', () => { beforeEach(() => { esArchiverLoad('threat_intelligence/invalid_indicators_data'); @@ -132,7 +136,9 @@ describe('Invalid Indicators', { tags: '@ess' }, () => { }); }); -describe('Indicators', () => { +// FLAKY: https://github.com/elastic/kibana/issues/171781 +// FLAKY: https://github.com/elastic/kibana/issues/171780 +describe.skip('Indicators', () => { before(() => { esArchiverLoad('threat_intelligence/indicators_data'); }); diff --git a/x-pack/plugins/threat_intelligence/public/components/paywall.tsx b/x-pack/plugins/threat_intelligence/public/components/paywall.tsx index a01ca32a0694..8a010550e8a6 100644 --- a/x-pack/plugins/threat_intelligence/public/components/paywall.tsx +++ b/x-pack/plugins/threat_intelligence/public/components/paywall.tsx @@ -6,17 +6,21 @@ */ import React, { VFC } from 'react'; -import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { + EuiButton, + EuiButtonEmpty, + EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { SubscriptionButtonEmpty } from '@kbn/subscription-tracking'; -import type { SubscriptionContextData } from '@kbn/subscription-tracking'; - -const subscriptionContext: SubscriptionContextData = { - feature: 'threat-intelligence', - source: 'security__threat-intelligence', -}; +import { useKibana } from '../hooks/use_kibana'; export const Paywall: VFC = () => { + const { + services: { application }, + } = useKibana(); return ( } @@ -52,12 +56,18 @@ export const Paywall: VFC = () => {
    - + + application.navigateToApp('management', { + path: 'stack/license_management/home', + }) + } + > - +
    diff --git a/x-pack/plugins/threat_intelligence/public/mocks/story_providers.tsx b/x-pack/plugins/threat_intelligence/public/mocks/story_providers.tsx index d13c3f561e74..249a9d05afbc 100644 --- a/x-pack/plugins/threat_intelligence/public/mocks/story_providers.tsx +++ b/x-pack/plugins/threat_intelligence/public/mocks/story_providers.tsx @@ -12,7 +12,6 @@ import { CoreStart, IUiSettingsClient } from '@kbn/core/public'; import { TimelinesUIStart } from '@kbn/timelines-plugin/public'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; -import { MockSubscriptionTrackingProvider } from '@kbn/subscription-tracking/mocks'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import { mockIndicatorsFiltersContext } from './mock_indicators_filters_context'; @@ -108,9 +107,7 @@ export const StoryProvidersComponent: VFC = ({ - - {children} - + {children} diff --git a/x-pack/plugins/threat_intelligence/public/mocks/test_providers.tsx b/x-pack/plugins/threat_intelligence/public/mocks/test_providers.tsx index 12c42052ee26..37360284b6aa 100644 --- a/x-pack/plugins/threat_intelligence/public/mocks/test_providers.tsx +++ b/x-pack/plugins/threat_intelligence/public/mocks/test_providers.tsx @@ -17,7 +17,6 @@ import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks import { createTGridMocks } from '@kbn/timelines-plugin/public/mock'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; -import { MockSubscriptionTrackingProvider } from '@kbn/subscription-tracking/mocks'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; @@ -142,13 +141,11 @@ export const TestProvidersComponent: FC = ({ children }) => ( - - - - {children} - - - + + + {children} + + diff --git a/x-pack/plugins/threat_intelligence/public/plugin.tsx b/x-pack/plugins/threat_intelligence/public/plugin.tsx index e30e9f92c0a5..49f6b3b7724b 100755 --- a/x-pack/plugins/threat_intelligence/public/plugin.tsx +++ b/x-pack/plugins/threat_intelligence/public/plugin.tsx @@ -11,7 +11,6 @@ import { Provider as ReduxStoreProvider } from 'react-redux'; import React, { Suspense } from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { ExternalReferenceAttachmentType } from '@kbn/cases-plugin/public/client/attachment_framework/types'; -import { SubscriptionTrackingProvider } from '@kbn/subscription-tracking'; import { generateAttachmentType } from './modules/cases/utils/attachments'; import { KibanaContextProvider } from './hooks/use_kibana'; import { @@ -44,16 +43,11 @@ export const createApp = - - - }> - - - - + + }> + + + diff --git a/x-pack/plugins/threat_intelligence/tsconfig.json b/x-pack/plugins/threat_intelligence/tsconfig.json index 661186c943b5..2e390483ab22 100644 --- a/x-pack/plugins/threat_intelligence/tsconfig.json +++ b/x-pack/plugins/threat_intelligence/tsconfig.json @@ -32,8 +32,7 @@ "@kbn/utility-types", "@kbn/ui-theme", "@kbn/securitysolution-io-ts-list-types", - "@kbn/core-ui-settings-browser", - "@kbn/subscription-tracking" + "@kbn/core-ui-settings-browser" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/transform/common/api_schemas/delete_transforms.ts b/x-pack/plugins/transform/common/api_schemas/delete_transforms.ts index e12c144b60af..7da139c7b5bd 100644 --- a/x-pack/plugins/transform/common/api_schemas/delete_transforms.ts +++ b/x-pack/plugins/transform/common/api_schemas/delete_transforms.ts @@ -6,6 +6,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import type { DeleteDataViewApiResponseSchema } from '@kbn/ml-data-view-utils/types/api_delete_response_schema'; import { transformStateSchema, ResponseStatus } from './common'; @@ -29,7 +30,7 @@ export type DeleteTransformsRequestSchema = TypeOf { @@ -48,10 +50,16 @@ export const useCreateTransform = () => { } const mutation = useMutation({ - mutationFn: ({ transformId, transformConfig }: CreateTransformArgs) => { + mutationFn: ({ + transformId, + transformConfig, + createDataView = false, + timeFieldName, + }: CreateTransformArgs) => { return http.put( addInternalBasePath(`transforms/${transformId}`), { + query: { createDataView, timeFieldName }, body: JSON.stringify(transformConfig), version: '1', } diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index f88ef1e39d44..9f2cf91b088b 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -146,7 +146,7 @@ export const useDeleteTransforms = () => { } if (status.destDataViewDeleted?.error) { - const error = status.destDataViewDeleted.error.reason; + const error = extractErrorMessage(status.destDataViewDeleted.error); toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage', diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index 471146f583dc..61403df03509 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -17,7 +17,7 @@ import { getFieldType, getDataGridSchemaFromKibanaFieldType, getDataGridSchemaFromESFieldType, - getFieldsFromKibanaIndexPattern, + getFieldsFromKibanaDataView, showDataGridColumnChartErrorMessageToast, useDataGrid, useRenderCellValue, @@ -140,7 +140,7 @@ export const useIndexData = ( allPopulatedFields = [...new Set(docs.map(Object.keys).flat(1))]; } - const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); + const allDataViewFields = getFieldsFromKibanaDataView(dataView); return allPopulatedFields.filter((d) => allDataViewFields.includes(d)).sort(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [dataViewFieldsData, populatedFields]); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 3c78757a6f25..07eb6e536ade 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -28,9 +28,6 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; -import { DuplicateDataViewError } from '@kbn/data-plugin/public'; -import type { RuntimeField } from '@kbn/data-views-plugin/common'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; import { getErrorMessage } from '../../../../../../common/utils/errors'; @@ -44,7 +41,7 @@ import { PutTransformsLatestRequestSchema, PutTransformsPivotRequestSchema, } from '../../../../../../common/api_schemas/transforms'; -import { isContinuousTransform, isLatestTransform } from '../../../../../../common/types/transform'; +import { isContinuousTransform } from '../../../../../../common/types/transform'; import { TransformAlertFlyout } from '../../../../../alerting/transform_alerting_flyout'; export interface StepDetailsExposedState { @@ -87,8 +84,7 @@ export const StepCreateForm: FC = React.memo( const [discoverLink, setDiscoverLink] = useState(); const toastNotifications = useToastNotifications(); - const { application, data, i18n: i18nStart, share, theme } = useAppDependencies(); - const dataViews = data.dataViews; + const { application, i18n: i18nStart, share, theme } = useAppDependencies(); const isDiscoverAvailable = application.capabilities.discover?.show ?? false; useEffect(() => { @@ -128,13 +124,13 @@ export const StepCreateForm: FC = React.memo( setLoading(true); createTransform( - { transformId, transformConfig }, + { transformId, transformConfig, createDataView, timeFieldName }, { onError: () => setCreated(false), - onSuccess: () => { + onSuccess: (resp) => { setCreated(true); - if (createDataView) { - createKibanaDataView(); + if (resp.dataViewsCreated.length === 1) { + setDataViewId(resp.dataViewsCreated[0].id); } if (startAfterCreation) { startTransform(); @@ -155,57 +151,6 @@ export const StepCreateForm: FC = React.memo( }); } - const createKibanaDataView = async () => { - setLoading(true); - const dataViewName = transformConfig.dest.index; - const runtimeMappings = transformConfig.source.runtime_mappings as Record< - string, - RuntimeField - >; - - try { - const newDataView = await dataViews.createAndSave( - { - title: dataViewName, - timeFieldName, - ...(isPopulatedObject(runtimeMappings) && isLatestTransform(transformConfig) - ? { runtimeFieldMap: runtimeMappings } - : {}), - allowNoIndex: true, - }, - false, - true - ); - - setDataViewId(newDataView.id); - setLoading(false); - return true; - } catch (e) { - if (e instanceof DuplicateDataViewError) { - toastNotifications.addDanger( - i18n.translate('xpack.transform.stepCreateForm.duplicateDataViewErrorMessage', { - defaultMessage: - 'An error occurred creating the Kibana data view {dataViewName}: The data view already exists.', - values: { dataViewName }, - }) - ); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.createDataViewErrorMessage', { - defaultMessage: 'An error occurred creating the Kibana data view {dataViewName}:', - values: { dataViewName }, - }), - text: toMountPoint(, { - theme, - i18n: i18nStart, - }), - }); - setLoading(false); - return false; - } - } - }; - const isBatchTransform = typeof transformConfig.sync === 'undefined'; useEffect(() => { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 0d93a31f9e3f..865614400b6e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -21,12 +21,13 @@ import { EuiSelect, EuiSpacer, EuiCallOut, - EuiText, EuiTextArea, } from '@elastic/eui'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { toMountPoint } from '@kbn/react-kibana-mount'; +import { CreateDataViewForm } from '@kbn/ml-data-view-utils/components/create_data_view_form_row'; +import { DestinationIndexForm } from '@kbn/ml-creation-wizard-utils/components/destination_index_form'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; @@ -46,7 +47,6 @@ import { useGetTransformsPreview, } from '../../../../hooks'; import { SearchItems } from '../../../../hooks/use_search_items'; -import { StepDetailsTimeField } from './step_details_time_field'; import { getTransformConfigQuery, getPreviewTransformRequestBody, @@ -88,6 +88,9 @@ export const StepDetailsForm: FC = React.memo( const [destinationIndex, setDestinationIndex] = useState( defaults.destinationIndex ); + const [destIndexSameAsId, setDestIndexSameAsId] = useState( + destinationIndex !== undefined && destinationIndex === transformId + ); const [destinationIngestPipeline, setDestinationIngestPipeline] = useState( defaults.destinationIngestPipeline ); @@ -378,6 +381,13 @@ export const StepDetailsForm: FC = React.memo( /* eslint-enable react-hooks/exhaustive-deps */ ]); + useEffect(() => { + if (destIndexSameAsId === true && !transformIdEmpty && transformIdValid) { + setDestinationIndex(transformId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [destIndexSameAsId, transformId]); + return (
    @@ -439,51 +449,31 @@ export const StepDetailsForm: FC = React.memo( /> - - {i18n.translate('xpack.transform.stepDetailsForm.destinationIndexInvalidError', { - defaultMessage: 'Invalid destination index name.', - })} -
    - - {i18n.translate( - 'xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink', - { - defaultMessage: 'Learn more about index name limitations.', - } - )} - - , - ] - } - > - setDestinationIndex(e.target.value)} - aria-label={i18n.translate( - 'xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel', - { - defaultMessage: 'Choose a unique destination index name.', - } - )} - isInvalid={!indexNameEmpty && !indexNameValid} - data-test-subj="transformDestinationIndexInput" - /> -
    + } + )} + isJobCreated={transformIdExists} + onDestinationIndexChange={setDestinationIndex} + setDestIndexSameAsId={setDestIndexSameAsId} + switchLabel={i18n.translate( + 'xpack.transform.stepDetailsForm.destinationIndexFormSwitchLabel', + { + defaultMessage: 'Use transform ID as destination index name', + } + )} + /> {ingestPipelineNames.length > 0 && ( = React.memo( ) : null} - - {i18n.translate('xpack.transform.stepDetailsForm.dataViewPermissionWarning', { - defaultMessage: 'You need permission to create data views.', - })} - , - ] - : []), - ...(createDataView && dataViewTitleExists - ? [ - i18n.translate('xpack.transform.stepDetailsForm.dataViewTitleError', { - defaultMessage: 'A data view with this title already exists.', - }), - ] - : []), - ]} - > - setCreateDataView(!createDataView)} - data-test-subj="transformCreateDataViewSwitch" - /> - - {createDataView && !dataViewTitleExists && dataViewAvailableTimeFields.length > 0 && ( - - )} + {/* Continuous mode */} ) => void; -} - -export const StepDetailsTimeField: FC = ({ - dataViewAvailableTimeFields, - dataViewTimeField, - onTimeFieldChanged, -}) => { - const noTimeFieldLabel = i18n.translate( - 'xpack.transform.stepDetailsForm.noTimeFieldOptionLabel', - { - defaultMessage: "I don't want to use the time field option", - } - ); - - const noTimeFieldOption = { - text: noTimeFieldLabel, - value: undefined, - }; - - const disabledDividerOption = { - disabled: true, - text: '───', - value: '', - }; - - return ( - - } - helpText={ - - } - > - ({ text })), - disabledDividerOption, - noTimeFieldOption, - ]} - value={dataViewTimeField} - onChange={onTimeFieldChanged} - data-test-subj="transformDataViewTimeFieldSelect" - /> - - ); -}; diff --git a/x-pack/plugins/transform/readme.md b/x-pack/plugins/transform/readme.md index 8c25f2ddd8ac..e86d92340bf0 100644 --- a/x-pack/plugins/transform/readme.md +++ b/x-pack/plugins/transform/readme.md @@ -151,4 +151,4 @@ With PATH_TO_CONFIG and other options as follows. node scripts/functional_tests_server --config test/accessibility/config.ts node scripts/functional_test_runner.js --config test/accessibility/config.ts --grep=transform - Transform accessibility tests are located in `x-pack/test/accessibility/apps`. + Transform accessibility tests are located in `x-pack/test/accessibility/apps/group2`. diff --git a/x-pack/plugins/transform/server/routes/api/delete_transforms/delete_transforms.ts b/x-pack/plugins/transform/server/routes/api/delete_transforms/delete_transforms.ts index 00c0f4b40acf..7a93d3b0fde6 100644 --- a/x-pack/plugins/transform/server/routes/api/delete_transforms/delete_transforms.ts +++ b/x-pack/plugins/transform/server/routes/api/delete_transforms/delete_transforms.ts @@ -7,6 +7,8 @@ import type { KibanaResponseFactory, RequestHandlerContext } from '@kbn/core/server'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; +import { deleteDataViewFn } from '@kbn/ml-data-view-utils/actions/delete'; +import type { DeleteDataViewApiResponseSchema } from '@kbn/ml-data-view-utils/types/api_delete_response_schema'; import { TRANSFORM_ACTIONS } from '../../../../common/types/transform'; import { TRANSFORM_STATE } from '../../../../common/constants'; @@ -18,15 +20,6 @@ import type { import { isRequestTimeout, fillResultsWithTimeouts } from '../../utils/error_utils'; -async function getDataViewId(indexName: string, dataViewsService: DataViewsService) { - const dv = (await dataViewsService.find(indexName)).find(({ title }) => title === indexName); - return dv?.id; -} - -async function deleteDestDataViewById(dataViewId: string, dataViewsService: DataViewsService) { - return await dataViewsService.delete(dataViewId); -} - export async function deleteTransforms( reqBody: DeleteTransformsRequestSchema, ctx: RequestHandlerContext, @@ -50,7 +43,7 @@ export async function deleteTransforms( const transformDeleted: ResponseStatus = { success: false }; const destIndexDeleted: ResponseStatus = { success: false }; - const destDataViewDeleted: ResponseStatus = { + let destDataViewDeleted: DeleteDataViewApiResponseSchema = { success: false, }; const transformId = transformInfo.id; @@ -84,15 +77,10 @@ export async function deleteTransforms( // Delete the data view if there's a data view that matches the name of dest index if (destinationIndex && deleteDestDataView) { - try { - const dataViewId = await getDataViewId(destinationIndex, dataViewsService); - if (dataViewId) { - await deleteDestDataViewById(dataViewId, dataViewsService); - destDataViewDeleted.success = true; - } - } catch (deleteDestDataViewError) { - destDataViewDeleted.error = deleteDestDataViewError.meta.body.error; - } + destDataViewDeleted = await deleteDataViewFn({ + dataViewsService, + dataViewName: destinationIndex, + }); } try { diff --git a/x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts b/x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts index d7d8614efb7c..f6be9e18893f 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts @@ -5,6 +5,11 @@ * 2.0. */ +import { + dataViewCreateQuerySchema, + type DataViewCreateQuerySchema, +} from '@kbn/ml-data-view-utils/schemas/api_create_query_schema'; + import { transformIdParamSchema, type TransformIdParamSchema, @@ -17,9 +22,11 @@ import { addInternalBasePath } from '../../../../common/constants'; import type { RouteDependencies } from '../../../types'; -import { routeHandler } from './route_handler'; +import { routeHandlerFactory } from './route_handler_factory'; + +export function registerRoute(routeDependencies: RouteDependencies) { + const { router, license } = routeDependencies; -export function registerRoute({ router, license }: RouteDependencies) { /** * @apiGroup Transforms * @@ -28,6 +35,7 @@ export function registerRoute({ router, license }: RouteDependencies) { * @apiDescription Creates a transform * * @apiSchema (params) transformIdParamSchema + * @apiSchema (query) transformIdParamSchema * @apiSchema (body) putTransformsRequestSchema */ router.versioned @@ -35,18 +43,21 @@ export function registerRoute({ router, license }: RouteDependencies) { path: addInternalBasePath('transforms/{transformId}'), access: 'internal', }) - .addVersion( + .addVersion( { version: '1', validate: { request: { params: transformIdParamSchema, + query: dataViewCreateQuerySchema, body: putTransformsRequestSchema, }, }, }, - license.guardApiRoute( - routeHandler - ) + license.guardApiRoute< + TransformIdParamSchema, + DataViewCreateQuerySchema, + PutTransformsRequestSchema + >(routeHandlerFactory(routeDependencies)) ); } diff --git a/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler.ts b/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler.ts deleted file mode 100644 index 87f9dab13b87..000000000000 --- a/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { RequestHandler } from '@kbn/core/server'; - -import type { TransformIdParamSchema } from '../../../../common/api_schemas/common'; -import type { - PutTransformsRequestSchema, - PutTransformsResponseSchema, -} from '../../../../common/api_schemas/transforms'; - -import type { TransformRequestHandlerContext } from '../../../services/license'; - -import { wrapEsError } from '../../utils/error_utils'; - -export const routeHandler: RequestHandler< - TransformIdParamSchema, - undefined, - PutTransformsRequestSchema, - TransformRequestHandlerContext -> = async (ctx, req, res) => { - const { transformId } = req.params; - - const response: PutTransformsResponseSchema = { - transformsCreated: [], - errors: [], - }; - - const esClient = (await ctx.core).elasticsearch.client; - - try { - const resp = await esClient.asCurrentUser.transform.putTransform({ - // @ts-expect-error @elastic/elasticsearch group_by is expected to be optional in TransformPivot - body: req.body, - transform_id: transformId, - }); - - if (resp.acknowledged) { - response.transformsCreated.push({ transform: transformId }); - } else { - response.errors.push({ - id: transformId, - error: wrapEsError(resp), - }); - } - } catch (e) { - response.errors.push({ - id: transformId, - error: wrapEsError(e), - }); - } - - return res.ok({ body: response }); -}; diff --git a/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler_factory.ts b/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler_factory.ts new file mode 100644 index 000000000000..8ca98efe3cb5 --- /dev/null +++ b/x-pack/plugins/transform/server/routes/api/transforms_create/route_handler_factory.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RequestHandler } from '@kbn/core/server'; +import type { RuntimeField } from '@kbn/data-views-plugin/common'; +import type { DataViewCreateQuerySchema } from '@kbn/ml-data-view-utils/schemas/api_create_query_schema'; +import { createDataViewFn } from '@kbn/ml-data-view-utils/actions/create'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + +import type { TransformIdParamSchema } from '../../../../common/api_schemas/common'; +import type { + PutTransformsRequestSchema, + PutTransformsResponseSchema, +} from '../../../../common/api_schemas/transforms'; +import { isLatestTransform } from '../../../../common/types/transform'; + +import type { RouteDependencies } from '../../../types'; +import type { TransformRequestHandlerContext } from '../../../services/license'; + +import { wrapEsError } from '../../utils/error_utils'; + +export const routeHandlerFactory: ( + routeDependencies: RouteDependencies +) => RequestHandler< + TransformIdParamSchema, + DataViewCreateQuerySchema, + PutTransformsRequestSchema, + TransformRequestHandlerContext +> = (routeDependencies) => async (ctx, req, res) => { + const { coreStart, dataViews } = routeDependencies; + const { transformId } = req.params; + const { createDataView, timeFieldName } = req.query; + + const response: PutTransformsResponseSchema = { + dataViewsCreated: [], + dataViewsErrors: [], + transformsCreated: [], + errors: [], + }; + + const esClient = (await ctx.core).elasticsearch.client; + + try { + const resp = await esClient.asCurrentUser.transform.putTransform({ + // @ts-expect-error @elastic/elasticsearch group_by is expected to be optional in TransformPivot + body: req.body, + transform_id: transformId, + }); + + if (resp.acknowledged) { + response.transformsCreated.push({ transform: transformId }); + } else { + response.errors.push({ + id: transformId, + error: wrapEsError(resp), + }); + } + } catch (e) { + response.errors.push({ + id: transformId, + error: wrapEsError(e), + }); + } + + if (createDataView) { + const { savedObjects, elasticsearch } = coreStart; + const dataViewsService = await dataViews.dataViewsServiceFactory( + savedObjects.getScopedClient(req), + elasticsearch.client.asScoped(req).asCurrentUser, + req + ); + + const runtimeMappings = req.body.source.runtime_mappings as Record; + + const { dataViewsCreated, dataViewsErrors } = await createDataViewFn({ + dataViewsService, + dataViewName: req.body.dest.index, + // Adding runtime mappings for transforms of type latest only here + // since only they will want to replicate the source index mapping. + // Pivot type transforms have index mappings that cannot be + // inferred from the source index. + runtimeMappings: + isPopulatedObject(runtimeMappings) && isLatestTransform(req.body) ? runtimeMappings : {}, + timeFieldName, + errorFallbackId: transformId, + }); + + response.dataViewsCreated = dataViewsCreated; + response.dataViewsErrors = dataViewsErrors; + } + + return res.ok({ body: response }); +}; diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index d58a875eec9c..b927516b7ee5 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -69,7 +69,9 @@ "@kbn/content-management-plugin", "@kbn/react-kibana-mount", "@kbn/core-plugins-server", - "@kbn/data-view-editor-plugin" + "@kbn/data-view-editor-plugin", + "@kbn/ml-data-view-utils", + "@kbn/ml-creation-wizard-utils" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index bfb2b2bdfd68..3df35d750c47 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -2051,7 +2051,6 @@ "data.search.esErrorTitle": "Impossible d’extraire les résultats de recherche", "data.search.esql.help": "Interroge Elasticsearch avec ES|QL.", "data.search.esql.query.help": "Une recherche ES|QL.", - "data.search.esql.timezone.help": "Fuseau horaire à utiliser pour les opérations de date. Les formats ISO8601 et les décalages UTC valides fonctionnent.", "data.search.essql.count.help": "Nombre de documents à récupérer. Pour de meilleures performances, utilisez un ensemble de données plus petit.", "data.search.essql.help": "Interroge Elasticsearch avec Elasticsearch SQL.", "data.search.essql.locale.help": "Le paramètre régional à utiliser.", @@ -4937,7 +4936,6 @@ "management.settings.categoryNames.visualizationsLabel": "Visualisations", "management.settings.changeImageLinkText": "Modifier l'image", "management.settings.customSettingTooltip": "Paramètre personnalisé", - "management.settings.field.codeEditorSyntaxErrorMessage": "Syntaxe JSON non valide", "management.settings.field.customSettingAriaLabel": "Paramètre personnalisé", "management.settings.field.imageChangeErrorMessage": "Impossible d’enregistrer l'image", "management.settings.field.invalidIconLabel": "Non valide", @@ -5309,7 +5307,6 @@ "savedSearch.kibana_context.savedSearchId.help": "Spécifier l'ID de recherche enregistrée à utiliser pour les requêtes et les filtres", "savedSearch.kibana_context.timeRange.help": "Spécifier le filtre de plage temporelle Kibana", "searchApiPanels.welcomeBanner.header.greeting.customTitle": "Bonjour {name} !", - "searchApiPanels.welcomeBanner.ingestData.clientDocLink": "Référence d’API {languageName}", "searchApiPanels.welcomeBanner.installClient.clientDocLink": "Documentation du client {languageName}", "searchApiPanels.welcomeBanner.selectClient.description": "Elastic construit et assure la maintenance des clients dans plusieurs langues populaires et notre communauté a contribué à beaucoup d'autres. Sélectionnez votre client linguistique favori or explorez la {console} pour commencer.", "searchApiPanels.welcomeBanner.codeBox.copyButtonLabel": "Copier", @@ -5317,22 +5314,7 @@ "searchApiPanels.welcomeBanner.header.description": "Configurez votre client de langage de programmation, ingérez des données, et vous serez prêt à commencer vos recherches en quelques minutes.", "searchApiPanels.welcomeBanner.header.greeting.defaultTitle": "Bonjour !", "searchApiPanels.welcomeBanner.header.title": "Lancez-vous avec Elasticsearch", - "searchApiPanels.welcomeBanner.ingestData.beatsDescription": "Des agents légers conçus pour le transfert de données pour Elasticsearch. Utilisez Beats pour envoyer des données opérationnelles depuis vos serveurs.", - "searchApiPanels.welcomeBanner.ingestData.beatsLink": "Beats", - "searchApiPanels.welcomeBanner.ingestData.beatsTitle": "Beats", - "searchApiPanels.welcomeBanner.ingestData.connectorsDescription": "Des intégrations spécialisées pour synchroniser des données de sources tierces avec Elasticsearch. Utilisez des connecteurs Elastic pour synchroniser du contenu d’une plage de bases de données et de stockage d’objets.", - "searchApiPanels.welcomeBanner.ingestData.connectorsPythonLink": "connecteurs-python", - "searchApiPanels.welcomeBanner.ingestData.connectorsTitle": "Client de connecteur", "searchApiPanels.welcomeBanner.ingestData.description": "Ajoutez des données à votre flux de données ou à votre index pour les rendre interrogeables. Choisissez une méthode d’ingestion qui correspond à votre application et à votre workflow.", - "searchApiPanels.welcomeBanner.ingestData.ingestApiDescription": "La façon la plus flexible d’indexer des données, ce qui vous donne un contrôle total sur vos options de personnalisation et d’optimisation.", - "searchApiPanels.welcomeBanner.ingestData.ingestApiLabel": "Ingérer via une API", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationDescription": "Des outils d’ingestion spécialisés optimisés pour transformer des données et les transférer à Elasticsearch.", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationLabel": "Ingérer via l’intégration", - "searchApiPanels.welcomeBanner.ingestData.ingestLegendLabel": "Sélectionner une méthode d'ingestion", - "searchApiPanels.welcomeBanner.ingestData.integrationsLink": "À propos des intégrations", - "searchApiPanels.welcomeBanner.ingestData.logstashDescription": "Ajoutez des données à votre flux de données ou à votre index pour les rendre interrogeables. Choisissez une méthode d’ingestion qui correspond à votre application et à votre workflow.", - "searchApiPanels.welcomeBanner.ingestData.logstashLink": "Logstash", - "searchApiPanels.welcomeBanner.ingestData.logstashTitle": "Logstash", "searchApiPanels.welcomeBanner.ingestData.title": "Ingérer des données", "searchApiPanels.welcomeBanner.installClient.description": "Elastic construit et assure la maintenance des clients dans plusieurs langues populaires et notre communauté a contribué à beaucoup d'autres. Installez votre client de langage favori pour commencer.", "searchApiPanels.welcomeBanner.installClient.title": "Installer un client", @@ -8257,7 +8239,6 @@ "xpack.apm.serviceOveriew.errorsTableOccurrences": "{occurrences} occ.", "xpack.apm.serviceOverview.embeddedMap.error.toastDescription": "L'usine incorporable ayant l'ID \"{embeddableFactoryId}\" est introuvable.", "xpack.apm.serviceOverview.embeddedMap.subtitle": "Carte affichant le nombre total de {currentMap} en fonction du pays et de la région", - "xpack.apm.serviceOverview.mobileCallOutText": "Il s'agit d'un service mobile, qui est actuellement disponible en tant que version d'évaluation technique. Vous pouvez nous aider à améliorer l'expérience en nous envoyant des commentaires. {feedbackLink}.", "xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, one {1 environnement} many {# environnements} other {# environnements}}", "xpack.apm.settings.agentKeys.apiKeysDisabledErrorDescription": "Contactez votre administrateur système et reportez-vous à {link} pour activer les clés d'API.", "xpack.apm.settings.agentKeys.copyAgentKeyField.title": "Clé \"{name}\" créée", @@ -8685,7 +8666,6 @@ "xpack.apm.dashboard.addDashboard.useContextFilterLabel.tooltip": "L'activation de cette option applique des filtres au tableau de bord en fonction du service et de l'environnement choisis.", "xpack.apm.data_view.creation_failed": "Une erreur s'est produite lors de la création de la vue de données", "xpack.apm.dataView.alreadyExistsInActiveSpace": "La vue de données existe déjà dans l'espace actif", - "xpack.apm.dataView.alreadyExistsInAnotherSpace": "La vue de données existe déjà dans un autre espace mais elle n'est pas disponible dans cet espace", "xpack.apm.dataView.autoCreateDisabled": "La création automatique des vues de données a été désactivée via l'option de configuration \"autoCreateApmDataView\"", "xpack.apm.dataView.noApmData": "Aucune donnée APM", "xpack.apm.dependecyOperationDetailView.header.backLinkLabel": "Toutes les opérations", @@ -9023,7 +9003,6 @@ "xpack.apm.mobile.filters.device": "Appareil", "xpack.apm.mobile.filters.nct": "NCT", "xpack.apm.mobile.filters.osVersion": "Version du système d'exploitation", - "xpack.apm.mobile.location.metrics.crashes": "La plupart des pannes", "xpack.apm.mobile.location.metrics.http.requests.title": "Le plus utilisé dans", "xpack.apm.mobile.location.metrics.launches": "La plupart des lancements", "xpack.apm.mobile.location.metrics.sessions": "La plupart des sessions", @@ -9408,8 +9387,6 @@ "xpack.apm.serviceOverview.latencyColumnP95Label": "Latence (95e)", "xpack.apm.serviceOverview.latencyColumnP99Label": "Latence (99e)", "xpack.apm.serviceOverview.loadingText": "Chargement…", - "xpack.apm.serviceOverview.mobileCallOutLink": "Donner un retour", - "xpack.apm.serviceOverview.mobileCallOutTitle": "APM mobile", "xpack.apm.serviceOverview.mostUsedTitle": "Le plus utilisé", "xpack.apm.serviceOverview.noResultsText": "Aucune instance trouvée", "xpack.apm.serviceOverview.throughtputChartTitle": "Rendement", @@ -11658,7 +11635,6 @@ "xpack.cases.server.viewCaseInKibana": "Pour plus de détails, afficher ce cas dans Kibana", "xpack.cases.settings.syncAlertsSwitchLabelOff": "Désactivé", "xpack.cases.settings.syncAlertsSwitchLabelOn": "Activé", - "xpack.cases.severity.all": "Toutes les sévérités", "xpack.cases.severity.critical": "Critique", "xpack.cases.severity.high": "Élevé", "xpack.cases.severity.low": "Bas", @@ -12100,11 +12076,6 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "Utilisez notre intégration {integrationFullName} (KSPM) pour détecter les erreurs de configuration de sécurité dans vos clusters Kubernetes.", "xpack.csp.cloudPosturePage.packageNotInstalledRenderer.promptDescription": "Détectez et corrigez les risques de configuration potentiels dans votre infrastructure cloud, comme les compartiments S3 accessibles au public, avec nos solutions de gestion du niveau de sécurité Kubernetes et de gestion du niveau de sécurité du cloud. {learnMore}", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} résultats en échec et {passed} ayant réussi", - "xpack.csp.dashboard.benchmarkSection.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.lastEvaluatedTitle": "Dernière évaluation {dateFromNow}", - "xpack.csp.dashboard.risksTable.clusterCardViewAllButtonTitle": "Afficher tous les échecs des résultats pour ce {postureAsset}", - "xpack.csp.dashboard.summarySection.postureScorePanelTitle": "Score de sécurité {type} global", "xpack.csp.eksIntegration.docsLink": "Lisez {docs} pour en savoir plus", "xpack.csp.findings..bottomBarLabel": "Voici les {maxItems} premiers résultats correspondant à votre recherche. Veuillez l'affiner pour en voir davantage.", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "Affichage de {pageStart}-{pageEnd} sur {total} {type}", @@ -12221,7 +12192,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "Vulnérabilités", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "Vulnérabilités", "xpack.csp.compactFormattedNumber.naTitle": "S. O.", - "xpack.csp.complianceScoreChart.counterLink.failedFindingsTooltip": "Échec des résultats", "xpack.csp.complianceScoreChart.counterLink.passedFindingsTooltip": "Réussite des résultats", "xpack.csp.createDetectionRuleButton": "Créer une règle de détection", "xpack.csp.createPackagePolicy.customAssetsTab.cloudNativeVulnerabilityManagementTitleLabel": "Gestion des vulnérabilités natives du cloud ", @@ -12241,13 +12211,7 @@ "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "Gestion du niveau de sécurité du cloud", "xpack.csp.cspmIntegration.integration.shortNameTitle": "CSPM", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterPrefixTitle": "Afficher tous les résultats pour ", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.accountNameTitle": "Nom du compte", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.clusterNameTitle": "Nom du cluster", "xpack.csp.dashboard.benchmarkSection.columnsHeader.complianceByCisSectionTitle": "Conformité par section CIS", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.postureScoreTitle": "Score du niveau", - "xpack.csp.dashboard.benchmarkSection.defaultClusterTitle": "ID", - "xpack.csp.dashboard.benchmarkSection.manageRulesButton": "Gérer les règles", "xpack.csp.dashboard.cspPageTemplate.pageTitle": "Niveau de sécurité du cloud", "xpack.csp.dashboard.risksTable.cisSectionColumnLabel": "Section CIS", "xpack.csp.dashboard.risksTable.complianceColumnLabel": "Conformité", @@ -12860,7 +12824,6 @@ "xpack.dataVisualizer.table.expandRowScreenMsg": "Développer la ligne", "xpack.dataVisualizer.title": "Charger un fichier", "xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.calloutDescription": "Sélectionnez un connecteur ci-dessus ou depuis {link} pour continuer", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactText": "Anecdotes : Surveillez les logs de serveur Kibana pour visualiser la progression et {funFacts} pour afficher les résultats dans Discover une fois l'opération terminée. Cette opération prendra (plusieurs) minutes, selon la quantité de données. Si vous fermez cette fenêtre, vous interromprez l'évaluation.", "xpack.elasticAssistant.assistant.settings.knowledgeBasedSettings.knowledgeBaseDescription": "Configurez ELSER dans {machineLearning} pour commencer. {seeDocs}", "xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.knowledgeBaseInstalledDescription": "Initialisé sur \"{kbIndexPattern}\"", "xpack.elasticAssistant.assistant.technicalPreview.tooltipContent": "Les réponses des systèmes d'IA ne sont pas toujours tout à fait exactes. Pour en savoir plus sur la fonctionnalité d'assistant et son utilisation, consultez {documentationLink}.", @@ -12988,7 +12951,6 @@ "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationPromptLabel": "Invite d'évaluation", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeDescription": "Type d'évaluation à effectuer, par exemple \"correctness\" \"esql-validator\" ou \"custom\", et fournit votre propre invite d'évaluation", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeLabel": "Type d'évaluation", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetDescription": "Exemple d'ensemble de données à évaluer. Tableau avec des objets aux propriétés \"input\" (entrée) et \"references\" (références)", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetLabel": "Ensemble de données", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactDiscoverLinkText": "cliquez ici", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorModelDescription": "Modèle avec lequel effectuer l'évaluation finale", @@ -13151,7 +13113,6 @@ "xpack.enterpriseSearch.content.index.connector.syncRules.flyout.errorTitle": "{ids} {idsLength, plural, one {règle} many {règles} other {règles}} de synchronisation {idsLength, plural, one {est} many {sont} other {sont}} non valide(s).", "xpack.enterpriseSearch.content.index.pipelines.copyCustomizeCallout.description": "Votre index utilise notre pipeline d'ingestion par défaut {defaultPipeline}. Copiez ce pipeline dans une configuration spécifique à l'index pour déverrouiller la possibilité de créer des pipelines d'ingestion et d'inférence personnalisés.", "xpack.enterpriseSearch.content.index.pipelines.ingestFlyout.modalBodyAPIText": "{apiIndex} Les modifications apportées aux paramètres ci-dessous sont uniquement fournies à titre indicatif. Ces paramètres ne seront pas conservés dans votre index ou pipeline.", - "xpack.enterpriseSearch.content.indices.callout.text": "Vos index Elasticsearch sont maintenant au premier plan dans Search. Vous pouvez créer des index et lancer directement des expériences de recherche avec ces index. Pour en savoir plus sur l'utilisation des index de Elasticsearch dans Search {docLink}", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.description": "D'abord, générez une clé d'API Elasticsearch. Cette clé {apiKeyName} permet d'activer les autorisations de lecture et d'écriture du connecteur pour qu'il puisse indexer les documents dans l'index {indexName} créé. Enregistrez cette clé en lieu sûr, car vous en aurez besoin pour configurer votre connecteur.", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.connectorConnected": "Votre connecteur {name} s’est bien connecté à Search.", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.description.secondParagraph": "Le référentiel de connecteurs contient plusieurs {link}. Utilisez notre cadre pour accélérer le développement de connecteurs pour des sources de données personnalisées.", @@ -14367,8 +14328,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "Terminé", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "Générer une clé", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "Créer une clé d'API d'analyse", - "xpack.enterpriseSearch.content.callout.dismissButton": "Rejeter", - "xpack.enterpriseSearch.content.callout.title": "Présentation des index Elasticsearch dans Search", "xpack.enterpriseSearch.content.cannotConnect.body": "En savoir plus.", "xpack.enterpriseSearch.content.cannotConnect.title": "Impossible de se connecter à Enterprise Search", "xpack.enterpriseSearch.content.crawler.authentication": "Authentification", @@ -14470,7 +14429,6 @@ "xpack.enterpriseSearch.content.index.syncButton.label": "Sync", "xpack.enterpriseSearch.content.index.syncButton.syncing.label": "Synchronisation en cours", "xpack.enterpriseSearch.content.index.syncButton.waitingForSync.label": "En attente de la synchronisation", - "xpack.enterpriseSearch.content.indices.callout.docLink": "lire la documentation", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.button.label": "Générer une clé API", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.cancelButton.label": "Annuler", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.confirmButton.label": "Générer une clé API", @@ -14604,16 +14562,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.createErrors": "Erreur lors de la création d'un pipeline", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.esDocs.link": "Découvrir comment ajouter un modèle entraîné", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.imageAlt": "Illustration d'absence de modèles de Machine Learning", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.chooseExistingLabel": "Nouveau ou existant", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.description": "Créez ou réutilisez un pipeline enfant qui servira de processeur dans votre pipeline principal.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionDeployTrainedModel": "Pour effectuer des tâches de traitement du langage naturel dans votre cluster, vous devez déployer un modèle entraîné approprié.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionUsePipelines": "Les pipelines que vous créez sont enregistrés pour être utilisés ailleurs dans votre déploiement Elastic.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink": "Découvrez l'importation et l'utilisation des modèles de ML dans Search", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.emptyValueError": "Champ obligatoire.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel": "Choisir", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel": "Pipeline existant", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.model": "Modèle", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel": "Nouveau pipeline", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.placeholder": "Effectuez une sélection", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceFields": "Champs sources", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipelineLabel": "Sélectionner un pipeline d'inférence existant", @@ -14623,11 +14574,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.invalidPipelineName": "Le nom doit contenir uniquement des lettres, des chiffres, des traits de soulignement et des traits d'union.", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.placeholder": "Sélectionner un modèle", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.redactedValue": "Ce modèle n'est pas disponible dans l'espace Kibana", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.modelLabel": "Sélectionner un modèle de ML entraîné", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.nameLabel": "Nom", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.namePlaceholder": "Saisir un nom unique pour ce pipeline", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.pipelineNameExistsError": "Ce nom est déjà utilisé par un autre pipeline.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.title": "Créer ou sélectionner un pipeline", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel": "Sélectionner un modèle de ML entraîné", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions": "Actions", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions.deleteMapping": "Supprimer ce mapping", @@ -14664,15 +14613,6 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.subtitle.result": "Résultat", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.title": "Tester les résultats de votre pipeline", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.useJsonFormat": "Utilisez ce format JSON pour ajouter votre propre tableau de documents", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.description": "Vous devez mettre à jour manuellement vos mappings d'index avant de pouvoir débuter l'indexation des documents à l'aide du pipeline.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.descriptionNoAction": "Vos mappings d'index sont automatiquement mis à jour pour inclure les champs de sortie d'inférence sélectionnés.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.docsLink": "En savoir plus", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappings": "Mappings de champs", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappingsRequired": "Mappings de champs requis", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.presentInMapping": "Assurez-vous que les champs de sortie d'inférence sélectionnés sont présent dans le mapping.", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.required": "Obligatoire", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.title": "Mettez à jour vos mappings d'index", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.titleNoAction": "Consultez les mises à jour des mappings d'index", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.title": "Ajouter un pipeline d'inférence", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.apiIndexSubtitle": "Les pipelines d'ingestion optimisent votre index pour les applications de recherche. Si vous souhaitez utiliser ces pipelines dans votre index basé sur des API, vous devrez les référencer explicitement dans vos requêtes d'API.", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.customBadge": "Personnalisé", @@ -14753,7 +14693,6 @@ "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.fields.title": "Champs", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.review.title": "Révision", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.test.title": "Test (facultatif)", - "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.updateMappings.title": "Mappings", "xpack.enterpriseSearch.content.integrations.dropbox": "Dropbox", "xpack.enterpriseSearch.content.integrations.dropboxDescription": "Effectuez des recherches dans vos fichiers et dossiers stockés sur Dropbox.", "xpack.enterpriseSearch.content.integrations.dropboxPaper": "Dropbox Paper", @@ -15305,9 +15244,7 @@ "xpack.enterpriseSearch.index.header.more.incrementalSync": "Contenu progressif", "xpack.enterpriseSearch.inferencePipelineCard.action.delete": "Supprimer un pipeline", "xpack.enterpriseSearch.inferencePipelineCard.action.detach": "Détacher le pipeline", - "xpack.enterpriseSearch.inferencePipelineCard.action.title": "Actions", "xpack.enterpriseSearch.inferencePipelineCard.action.view": "Afficher dans Gestion de la Suite", - "xpack.enterpriseSearch.inferencePipelineCard.actionButton": "Actions", "xpack.enterpriseSearch.inferencePipelineCard.deleteConfirm.title": "Supprimer le pipeline", "xpack.enterpriseSearch.inferencePipelineCard.modelState.deploymentFailed": "Échec du déploiement", "xpack.enterpriseSearch.inferencePipelineCard.modelState.notDeployed": "Non démarré", @@ -15325,7 +15262,6 @@ "xpack.enterpriseSearch.ingestSelector.method.connectors.description": "Extraire, transformer, indexer et synchroniser des données issues d'une source de données tiers.", "xpack.enterpriseSearch.ingestSelector.method.crawler": "Robot d'indexation", "xpack.enterpriseSearch.ingestSelector.method.crawler.description": "Découvrir, extraire et indexer du contenu interrogeable provenant de sites web et de bases de connaissances.", - "xpack.enterpriseSearch.ingestSelector.startButton": "Début", "xpack.enterpriseSearch.inlineEditableTable.newRowButtonLabel": "Nouvelle ligne", "xpack.enterpriseSearch.integrations.apiDescription": "Ajouter la recherche à votre application avec les API robustes d'Elasticsearch.", "xpack.enterpriseSearch.integrations.apiName": "API", @@ -17102,7 +17038,6 @@ "xpack.fleet.agentActivityFlyout.inProgressTitle": "En cours", "xpack.fleet.agentActivityFlyout.noActivityDescription": "Le fil d'activités s'affichera ici au fur et à mesure que les agents seront réaffectés, mis à niveau ou désenregistrés.", "xpack.fleet.agentActivityFlyout.noActivityText": "Aucune activité à afficher", - "xpack.fleet.agentActivityFlyout.reviewErrorLogs": "Vérifier les logs d'erreur", "xpack.fleet.agentActivityFlyout.scheduledDescription": "Planifié pour ", "xpack.fleet.agentActivityFlyout.title": "Activité des agents", "xpack.fleet.agentActivityFlyout.todayTitle": "Aujourd'hui", @@ -17911,7 +17846,6 @@ "xpack.fleet.initializationErrorMessageTitle": "Initialisation de Fleet impossible", "xpack.fleet.integrations.customInputsLink": "entrées personnalisées", "xpack.fleet.integrations.discussForumLink": "forum", - "xpack.fleet.integrations.endpointsButton": "Points de terminaison", "xpack.fleet.integrations.installPackage.uploadedTooltip": "Cette intégration a été installée par le biais d'un chargement et ne peut pas être réinstallée automatiquement. Veuillez la charger à nouveau pour la réinstaller.", "xpack.fleet.integrations.integrationSaved": "Paramètres de l'intégration enregistrés", "xpack.fleet.integrations.integrationSavedError": "Erreur lors de l’enregistrement des paramètres de l'intégration", @@ -18640,9 +18574,7 @@ "xpack.grokDebugger.unknownErrorTitle": "Un problème est survenu", "xpack.idxMgmt.badgeAriaLabel": "{label}. Sélectionnez pour filtrer selon cet élément.", "xpack.idxMgmt.clearCacheIndicesAction.indexCacheClearedMessage": "Le cache de l'index {indexNames} a été effacé.", - "xpack.idxMgmt.clearCacheIndicesAction.successMessage": "Le cache a bien été effacé : [{indexNames}]", "xpack.idxMgmt.closeIndicesAction.indexClosedMessage": "L'index {indexNames} a été fermé.", - "xpack.idxMgmt.closeIndicesAction.successfullyClosedIndicesMessage": "Fermeture réussie : [{indexNames}]", "xpack.idxMgmt.componentTemplateDetails.summaryTab.notInUseDescription": "{createLink} un modèle d'index ou {editLink}-en un existant.", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaDescription": "Informations arbitraires sur le modèle stockées dans l'état du cluster. {learnMoreLink}", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaHelpText": "Utiliser le format JSON : {code}", @@ -18661,7 +18593,6 @@ "xpack.idxMgmt.deleteDataStreamsConfirmationModal.multipleErrorsNotificationMessageText": "Erreur lors de la suppression de {count} flux de données", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.successDeleteMultipleNotificationMessageText": "{numSuccesses, plural, one {# flux de données} many {# flux de données} other {# flux de données}} supprimé", "xpack.idxMgmt.deleteIndicesAction.indexDeletedMessage": "L'index {indexNames} a été supprimé.", - "xpack.idxMgmt.deleteIndicesAction.successfullyDeletedIndicesMessage": "Suppression réussie : [{indexNames}]", "xpack.idxMgmt.deleteTemplatesModal.confirmButtonLabel": "Supprimer {numTemplatesToDelete, plural, one {modèle} many {modèles} other {modèles}}", "xpack.idxMgmt.deleteTemplatesModal.deleteDescription": "Vous êtes sur le point de supprimer {numTemplatesToDelete, plural, one {ce modèle} many {ces modèles} other {ces modèles}} :", "xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "Supprimer {numTemplatesToDelete, plural, one {modèle} many {# modèles} other {# modèles}}", @@ -18679,9 +18610,7 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryHelpText": "Valeur par défaut : requête {code}.", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type} correspond à un nombre, une date ou une plage d'adresses IP.", "xpack.idxMgmt.flushIndicesAction.indexFlushedMessage": "L'index {indexNames} a été vidé.", - "xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "Vidage effectué avec succès : [{indexNames}]", "xpack.idxMgmt.forceMergeIndicesAction.indexForcemergedMessage": "L'index {indexNames} a fait l'objet d'une fusion forcée.", - "xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "Fusion forcée effectué avec succès : [{indexNames}]", "xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "Utiliser le format JSON : {code}", "xpack.idxMgmt.formWizard.stepSettings.settingsEditorHelpText": "Utiliser le format JSON : {code}", "xpack.idxMgmt.goToDiscover.showIndexToolTip": "Afficher {indexName} dans Discover", @@ -18778,9 +18707,7 @@ "xpack.idxMgmt.mappingsEditor.sourceFieldDescription": "Le champ _source contient le corps du document JSON d'origine qui a été fourni au moment de l'indexation. Vous pouvez nettoyer des champs individuels en définissant ceux à inclure ou exclure du champ _source. {docsLink}", "xpack.idxMgmt.mappingsEditor.typeField.documentationLinkLabel": "Documentation de {typeName}", "xpack.idxMgmt.openIndicesAction.indexOpenedMessage": "L'index {indexNames} a été ouvert.", - "xpack.idxMgmt.openIndicesAction.successfullyOpenedIndicesMessage": "Ouverture réussie : [{indexNames}]", "xpack.idxMgmt.refreshIndicesAction.indexRefreshedMessage": "L'index {indexNames} a été actualisé.", - "xpack.idxMgmt.refreshIndicesAction.successfullyRefreshedIndicesMessage": "Actualisation réussie : [{indexNames}]", "xpack.idxMgmt.templateDetails.summaryTab.indexPatternsDescriptionListTitle": "{numIndexPatterns, plural, one {Modèle} many {Modèles d''indexation manquants} other {Modèles}} d'index", "xpack.idxMgmt.templateForm.stepLogistics.dataStreamDescription": "Le modèle crée des flux de données au lieu d'index. {docsLink}", "xpack.idxMgmt.templateForm.stepLogistics.fieldIndexPatternsHelpText": "Les espaces et les caractères {invalidCharactersList} ne sont pas autorisés.", @@ -20348,62 +20275,58 @@ "xpack.infra.appName": "Logs Infra", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "documentation", "xpack.infra.assetDetails.flyout.AlertsPageLinkLabel": "Afficher tout", - "xpack.infra.assetDetails.formulas.cpuUsage": "Utilisation CPU", - "xpack.infra.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", - "xpack.infra.assetDetails.formulas.cpuUsage.irqLabel": "irq", - "xpack.infra.assetDetails.formulas.cpuUsage.niceLabel": "nice", - "xpack.infra.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", - "xpack.infra.assetDetails.formulas.cpuUsage.stealLabel": "steal", - "xpack.infra.assetDetails.formulas.cpuUsage.systemLabel": "system", - "xpack.infra.assetDetails.formulas.cpuUsage.userLabel": "utilisateur", - "xpack.infra.assetDetails.formulas.diskIORead": "Entrées et sorties par seconde en lecture sur le disque", - "xpack.infra.assetDetails.formulas.diskIOWrite": "Entrées et sorties par seconde en écriture sur le disque", - "xpack.infra.assetDetails.formulas.diskReadThroughput": "Rendement de lecture du disque", - "xpack.infra.assetDetails.formulas.diskSpaceAvailability": "Disponibilité de l'espace disque", - "xpack.infra.assetDetails.formulas.diskSpaceAvailable": "Espace disque disponible", - "xpack.infra.assetDetails.formulas.diskUsage": "Utilisation du disque", - "xpack.infra.assetDetails.formulas.diskWriteThroughput": "Rendement d’écriture du disque", - "xpack.infra.assetDetails.formulas.hostCount.hostsLabel": "Hôtes", - "xpack.infra.assetDetails.formulas.kubernetes.capacity": "Capacité", - "xpack.infra.assetDetails.formulas.kubernetes.used": "Utilisé", - "xpack.infra.assetDetails.formulas.load15m": "Charge (15 min)", - "xpack.infra.assetDetails.formulas.load1m": "Charge (1 min)", - "xpack.infra.assetDetails.formulas.load5m": "Charge (5 min)", - "xpack.infra.assetDetails.formulas.logRate": "Taux de log", - "xpack.infra.assetDetails.formulas.memoryFree": "Sans mémoire", - "xpack.infra.assetDetails.formulas.memoryUsage": "Utilisation mémoire", - "xpack.infra.assetDetails.formulas.metric.label.cache": "cache", - "xpack.infra.assetDetails.formulas.metric.label.free": "gratuit", - "xpack.infra.assetDetails.formulas.metric.label.used": "utilisé", - "xpack.infra.assetDetails.formulas.normalizedLoad1m": "Charge normalisée", - "xpack.infra.assetDetails.formulas.rx": "Réseau entrant (RX)", - "xpack.infra.assetDetails.formulas.tx": "Réseau sortant (TX)", + "xpack.metricsData.assetDetails.formulas.cpuUsage": "Utilisation CPU", + "xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", + "xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice", + "xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal", + "xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "system", + "xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "utilisateur", + "xpack.metricsData.assetDetails.formulas.diskIORead": "Entrées et sorties par seconde en lecture sur le disque", + "xpack.metricsData.assetDetails.formulas.diskIOWrite": "Entrées et sorties par seconde en écriture sur le disque", + "xpack.metricsData.assetDetails.formulas.diskReadThroughput": "Rendement de lecture du disque", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "Disponibilité de l'espace disque", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "Espace disque disponible", + "xpack.metricsData.assetDetails.formulas.diskUsage": "Utilisation du disque", + "xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "Rendement d’écriture du disque", + "xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "Hôtes", + "xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "Capacité", + "xpack.metricsData.assetDetails.formulas.kubernetes.used": "Utilisé", + "xpack.metricsData.assetDetails.formulas.load15m": "Charge (15 min)", + "xpack.metricsData.assetDetails.formulas.load1m": "Charge (1 min)", + "xpack.metricsData.assetDetails.formulas.load5m": "Charge (5 min)", + "xpack.metricsData.assetDetails.formulas.logRate": "Taux de log", + "xpack.metricsData.assetDetails.formulas.memoryFree": "Sans mémoire", + "xpack.metricsData.assetDetails.formulas.memoryUsage": "Utilisation mémoire", + "xpack.metricsData.assetDetails.formulas.metric.label.cache": "cache", + "xpack.metricsData.assetDetails.formulas.metric.label.free": "gratuit", + "xpack.metricsData.assetDetails.formulas.metric.label.used": "utilisé", + "xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "Charge normalisée", + "xpack.metricsData.assetDetails.formulas.rx": "Réseau entrant (RX)", + "xpack.metricsData.assetDetails.formulas.tx": "Réseau sortant (TX)", + "xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "Entrées et sorties par seconde (IOPS) sur le disque", + "xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "Rendement du disque", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.available": "Disponible", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "Utilisé", + "xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "Utilisation du disque par point de montage", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "Capacité CPU du nœud", + "xpack.metricsData.assetDetails.metricsCharts.load": "Charge", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "Cache", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "Gratuit", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "Lire", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "Utilisé", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "Écrire", + "xpack.metricsData.assetDetails.metricsCharts.network": "Réseau", + "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "Entrant (RX)", + "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "Sortant (TX)", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "Capacité du disque du nœud", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "Capacité de mémoire du nœud", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "Capacité de pod du nœud", + "xpack.metricsData.assetDetails.overview.kpi.subtitle.average": "Moyenne", "xpack.infra.assetDetails.header.return": "Renvoyer", "xpack.infra.assetDetails.metadata.tooltip.documentationLink": "host.name", "xpack.infra.assetDetails.metadata.tooltip.metadata": "Métadonnées", - "xpack.infra.assetDetails.metricsCharts.cpuUsage": "Utilisation CPU", - "xpack.infra.assetDetails.metricsCharts.diskIOPS": "Entrées et sorties par seconde (IOPS) sur le disque", - "xpack.infra.assetDetails.metricsCharts.diskThroughput": "Rendement du disque", - "xpack.infra.assetDetails.metricsCharts.diskUsage": "Utilisation du disque", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.available": "Disponible", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.used": "Utilisé", - "xpack.infra.assetDetails.metricsCharts.diskUsageByMountingPoint": "Utilisation du disque par point de montage", - "xpack.infra.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "Capacité CPU du nœud", - "xpack.infra.assetDetails.metricsCharts.load": "Charge", - "xpack.infra.assetDetails.metricsCharts.logRate": "Taux de log", - "xpack.infra.assetDetails.metricsCharts.memoryUsage": "Utilisation mémoire", - "xpack.infra.assetDetails.metricsCharts.metric.label.cache": "Cache", - "xpack.infra.assetDetails.metricsCharts.metric.label.free": "Gratuit", - "xpack.infra.assetDetails.metricsCharts.metric.label.read": "Lire", - "xpack.infra.assetDetails.metricsCharts.metric.label.used": "Utilisé", - "xpack.infra.assetDetails.metricsCharts.metric.label.write": "Écrire", - "xpack.infra.assetDetails.metricsCharts.network": "Réseau", - "xpack.infra.assetDetails.metricsCharts.network.label.rx": "Entrant (RX)", - "xpack.infra.assetDetails.metricsCharts.network.label.tx": "Sortant (TX)", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeDiskCapacity": "Capacité du disque du nœud", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeMemoryCapacity": "Capacité de mémoire du nœud", - "xpack.infra.assetDetails.metricsCharts.nginx.nodePodCapacity": "Capacité de pod du nœud", - "xpack.infra.assetDetails.metricsCharts.normalizedLoad1m": "Charge normalisée", "xpack.infra.assetDetails.overview.alertsSectionTitle": "Alertes", "xpack.infra.assetDetails.overview.kubernetesMetricsSectionTitle": "Aperçu Kubernetes", "xpack.infra.assetDetails.overview.metadataSectionTitle": "Métadonnées", @@ -20416,11 +20339,6 @@ "xpack.infra.assetDetailsEmbeddable.displayName": "Détails de ressource", "xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton": "Afficher tout", "xpack.infra.assetDetailsEmbeddable.notApplicableLabel": "S. O.", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "Utilisation CPU", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskUsage.title": "Utilisation du disque", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "Utilisation mémoire", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "Charge normalisée", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "Moyenne", "xpack.infra.assetDetailsEmbeddable.overview.metadataCloudProviderHeading": "Fournisseur cloud", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostIpHeading": "IP de l'hôte", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostOsVersionHeading": "Version de l'OS de l'hôte", @@ -20538,19 +20456,7 @@ "xpack.infra.hostsViewPage.tabs.logs.textFieldPlaceholder": "Rechercher les entrées de logs...", "xpack.infra.hostsViewPage.tabs.logs.title": "Logs", "xpack.infra.hostsViewPage.tabs.metricsCharts.actions.openInLines": "Ouvrir dans Lens", - "xpack.infra.hostsViewPage.tabs.metricsCharts.cpuUsage": "Utilisation CPU", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIORead": "Entrées et sorties par seconde en lecture sur le disque", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIOWrite": "Entrées et sorties par seconde en écriture sur le disque", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskReadThroughput": "Rendement de lecture du disque", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskSpaceAvailable": "Espace disque disponible", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskUsage": "Utilisation du disque", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskWriteThroughput": "Rendement d’écriture du disque", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryFree": "Sans mémoire", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryUsage": "Utilisation mémoire", - "xpack.infra.hostsViewPage.tabs.metricsCharts.normalizedLoad1m": "Charge normalisée", - "xpack.infra.hostsViewPage.tabs.metricsCharts.rx": "Réseau entrant (RX)", "xpack.infra.hostsViewPage.tabs.metricsCharts.title": "Indicateurs", - "xpack.infra.hostsViewPage.tabs.metricsCharts.tx": "Réseau sortant (TX)", "xpack.infra.hostsViewPage.tooltip.whatAreTheseMetricsLink": "Que sont ces indicateurs ?", "xpack.infra.hostsViewPage.tooltip.whyAmISeeingDottedLines": "Pourquoi des lignes pointillées apparaissent-elles ?", "xpack.infra.infra.assetDetails.alerts.createAlertLink": "Créer une règle", @@ -22352,7 +22258,6 @@ "xpack.lens.config.configFlyoutCallout": "ES|QL propose actuellement des options de configuration limitées", "xpack.lens.config.editLabel": "Modifier la configuration", "xpack.lens.config.editLinkLabel": "Modifier dans Lens", - "xpack.lens.config.editVisualizationLabel": "Modifier la visualisation", "xpack.lens.config.experimentalLabel": "Version d'évaluation technique", "xpack.lens.configPanel.addLayerButton": "Ajouter un calque", "xpack.lens.configPanel.experimentalLabel": "Version d'évaluation technique", @@ -23511,8 +23416,6 @@ "xpack.maps.blendedVectorLayer.clusteredLayerName": "{displayName} en cluster", "xpack.maps.common.esSpatialRelation.clusterFilterLabel": "intersecte le cluster {gridId}", "xpack.maps.deleteLayerConfirmModal.multiLayerWarning": "Le retrait de ce calque retire également {numChildren} {numChildren, plural, one {calque imbriqué} many {les calques} other {les calques}}.", - "xpack.maps.distanceSource.requestDescription": "Obtenir des indicateurs de la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", - "xpack.maps.distanceSource.requestName": "{leftSourceName} à distance de la requête de liaison", "xpack.maps.embeddable.boundsFilterLabel": "{geoFieldsLabel} dans les limites de la carte", "xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage": "Conversion de la géométrie {geometryType} en geojson impossible ; non pris en charge", "xpack.maps.es_geo_utils.distanceFilterAlias": "dans un rayon de {distanceKm} km de {pointLabel}", @@ -23526,10 +23429,6 @@ "xpack.maps.esSearch.topHitsEntitiesCountMsg": "{entityCount} entités trouvées.", "xpack.maps.esSearch.topHitsResultsTrimmedMsg": "Résultats limités aux {entityCount} premières entités sur environ {totalEntities}.", "xpack.maps.esSearch.topHitsSizeMsg": "Affichage des {topHitsSize} premiers documents par entité.", - "xpack.maps.esSearchSource.requestDescription": "Obtenir des documents de la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", - "xpack.maps.esSearchSource.requestName": "Requête de documents de {layerName}", - "xpack.maps.esSearchSource.topHits.requestDescription": "Obtenir les premiers résultats de la vue de données : {dataViewName} ; entités : {entitiesFieldName} ; champ géospatial : {geoFieldName}", - "xpack.maps.esSearchSource.topHits.requestName": "Requête des premiers résultats de {layerName}", "xpack.maps.fileUpload.trimmedResultsMsg": "Résultats limités à {numFeatures} fonctionnalités, {previewCoverage} % du fichier.", "xpack.maps.filterByMapExtentMenuItem.displayName": "Filtrer {containerLabel} selon les limites de la carte", "xpack.maps.filterByMapExtentMenuItem.displayNameTooltip": "Quand vous vous déplacez sur la carte ou que vous zoomez, le {containerLabel} se met à jour pour afficher uniquement les données visibles dans les limites de la carte.", @@ -23552,7 +23451,6 @@ "xpack.maps.mask.maskLabel": "Masquer {hideNoun}", "xpack.maps.mask.whenJoinMetric": "{whenLabel} l'indicateur de jonction", "xpack.maps.maskLegend.is": "{aggLabel} est", - "xpack.maps.pewPew.requestName": "Requête de chemins de {layerName}", "xpack.maps.scalingDocs.clustersDetails": "Affichez les clusters lorsque les résultats dépassent {maxResultWindow} documents. Affichez les documents lorsqu'il y a moins de {maxResultWindow} résultats.", "xpack.maps.scalingDocs.limitDetails": "Affichez les fonctionnalités des {maxResultWindow} premiers documents.", "xpack.maps.scalingDocs.maxResultWindow": "Contrainte {maxResultWindow} fournie par le paramètre d'index {link}.", @@ -23568,15 +23466,8 @@ "xpack.maps.source.emsTileSourceDescription": "Service de fond de carte de {host}", "xpack.maps.source.esAggSource.topTermLabel": "{fieldLabel} principal", "xpack.maps.source.esGeoGrid.groupBy.termsDescription": "Créez un suivi pour les {maxTermsTracks} termes principaux. Le suivi est tronqué lorsque le nombre d'éléments dépasse la limite.", - "xpack.maps.source.esGeoLine.entityRequestDescription": "Obtenir des entités au sein de la mémoire tampon de la carte depuis la vue de données  : {dataViewName} ; entités : {splitFieldName}", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestDescription": "Obtenir des suivis de la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", - "xpack.maps.source.esGeoLine.trackRequestDescription": "Obtenir des pistes pour des entités {numEntities} depuis la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", "xpack.maps.source.esGeoLineDisabledReason": "{title} requiert une licence Gold.", - "xpack.maps.source.esGrid.compositeInspector.requestName": "Requête composite de {layerName} {bucketsName} ({requestCount})", - "xpack.maps.source.esGrid.compositeInspectorDescription": "Obtenir {bucketsName} de la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", "xpack.maps.source.esGrid.compositePaginationErrorMessage": "{layerName} génère trop de requêtes. Réduisez \"Résolution de la grille\" et/ou réduisez le nombre d'indicateurs de premier terme.", - "xpack.maps.source.esGrid.inspector.requestDescription": "Obtenir {bucketsName} de la vue de données : {dataViewName} ; champ géospatial : {geoFieldName}", - "xpack.maps.source.esGrid.inspector.requestName": "Requête de {layerName} {bucketsName}", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "Paramètre de résolution de grille non reconnu : {resolution}", "xpack.maps.source.esJoin.countLabel": "Nombre de {indexPatternLabel}", "xpack.maps.source.esSearch.clusterScalingLabel": "Afficher les clusters lorsque les résultats dépassent {maxResultWindow}", @@ -23587,15 +23478,12 @@ "xpack.maps.source.esSource.noGeoFieldErrorMessage": "La vue de données \"{indexPatternLabel}\" ne contient plus le champ géographique \"{geoField}\"", "xpack.maps.source.esSource.stylePropsMetaRequestName": "{layerName} - Métadonnées", "xpack.maps.source.MVTSingleLayerVectorSourceEditor.urlHelpMessage": "URL du service de cartographie vectoriel .mvt. Par exemple, {url}", - "xpack.maps.source.pewPew.inspectorDescription": "Obtenir des chemins depuis la vue de données : {dataViewName} ; source : {sourceFieldName} ; destination : {destFieldName}", "xpack.maps.spatialJoin.wizardForm.withinExpressionValue": "{distance} {units} de fonctionnalités de calque", "xpack.maps.spatialJoinExpression.noDataViewTitle": "Impossible de charger la vue de données {dataViewId}.", "xpack.maps.spatialJoinExpression.value": "fonctionnalités de {geoField}", "xpack.maps.style.fieldSelect.OriginLabel": "Champs de {fieldOrigin}", "xpack.maps.termJoinExpression.topTerms": "{size} principal", "xpack.maps.termJoinExpression.value": "termes {topTerms} de {term}", - "xpack.maps.termSource.requestDescription": "Obtenir des indicateurs depuis la vue de données : {dataViewName} ; champ de terme : {termFieldName}", - "xpack.maps.termSource.requestName": "Requête de liaison de terme de {leftSourceName}", "xpack.maps.tiles.resultsCompleteMsg": "{countPrefix}{count} documents trouvés.", "xpack.maps.tiles.resultsTrimmedMsg": "Les résultats sont limités à {countPrefix}{count} documents.", "xpack.maps.tooltip.pageNumerText": "{pageNumber} de {total}", @@ -24035,8 +23923,6 @@ "xpack.maps.source.esGeoLine.sortFieldPlaceholder": "Sélectionner le champ de tri", "xpack.maps.source.esGeoLine.splitFieldLabel": "Entité", "xpack.maps.source.esGeoLine.splitFieldPlaceholder": "Sélectionner un champ d'entité", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestName": "Requêtes de piste \"{layerName}\" (séries temporelles)", - "xpack.maps.source.esGeoLine.trackRequestName": "Requêtes de piste \"{layerName}\" (termes)", "xpack.maps.source.esGeoLine.trackSettingsLabel": "Pistes", "xpack.maps.source.esGeoLineDescription": "Créer des lignes à partir de points", "xpack.maps.source.esGeoLineTitle": "Pistes", @@ -24079,7 +23965,6 @@ "xpack.maps.source.esSearch.useMVTVectorTiles": "Utiliser les tuiles vectorielles", "xpack.maps.source.esSearchDescription": "Points, lignes et polygones d'Elasticsearch", "xpack.maps.source.esSearchTitle": "Documents", - "xpack.maps.source.esSource.stylePropsMetaRequestDescription": "Recherche Elasticsearch récupérant les métadonnées de champ utilisées pour le calcul des champs de symbolisation.", "xpack.maps.source.esTopHitsSearch.sortFieldLabel": "Champ de tri", "xpack.maps.source.esTopHitsSearch.sortOrderLabel": "Ordre de tri", "xpack.maps.source.geofieldLabel": "Champ géospatial", @@ -24384,7 +24269,6 @@ "xpack.ml.dataframe.analytics.create.analyticsProgressErrorMessage": "Une erreur s'est produite lors de la récupération des statistiques de progression pour la tâche d'analyse {jobId}", "xpack.ml.dataframe.analytics.create.configDetails.includedFieldsAndMoreDescription": "{includedFields} ... (et {extraCount} de plus)", "xpack.ml.dataframe.analytics.create.createDataViewSuccessMessage": "La vue de donnée Kibana {dataViewName} a été créée.", - "xpack.ml.dataframe.analytics.create.dataViewExistsError": "Une vue de données avec le titre {title} existe déjà.", "xpack.ml.dataframe.analytics.create.dependentVariableMaxDistictValuesError": "Non valide. {message}", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.description": "Fournissez les liens des résultats des analyses aux tableaux de bord Kibana, à Discover ou à d'autres pages Web. {learnMoreLink}", "xpack.ml.dataframe.analytics.create.duplicateDataViewErrorMessageError": "La vue de données {dataViewName} existe déjà.", @@ -25262,8 +25146,6 @@ "xpack.ml.dataframe.analytics.create.configDetails.standardizationEnabled": "Normalisation activée", "xpack.ml.dataframe.analytics.create.configDetails.trainingPercent": "Pourcentage d'entraînement", "xpack.ml.dataframe.analytics.create.createDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana :", - "xpack.ml.dataframe.analytics.create.createDataViewLabel": "Créer une vue de données", - "xpack.ml.dataframe.analytics.create.dataViewPermissionWarning": "Vous devez disposer d'une autorisation pour pouvoir créer des vues de données.", "xpack.ml.dataframe.analytics.create.dependentVariableClassificationPlaceholder": "Sélectionnez le champ numérique, de catégorie ou booléen sur lequel vous souhaitez effectuer une prédiction.", "xpack.ml.dataframe.analytics.create.dependentVariableInputAriaLabel": "Entrez le champ à utiliser comme variable dépendante.", "xpack.ml.dataframe.analytics.create.dependentVariableLabel": "Variable dépendante", @@ -25271,18 +25153,11 @@ "xpack.ml.dataframe.analytics.create.dependentVariableOptionsNoNumericalFields": "Aucun champ numérique n'a été trouvé pour cette vue de données.", "xpack.ml.dataframe.analytics.create.dependentVariableRegressionPlaceholder": "Sélectionnez le champ numérique sur lequel vous souhaitez effectuer une prédiction.", "xpack.ml.dataframe.analytics.create.destinationIndexHelpText": "Un index portant ce nom existe déjà. Notez que l'exécution de cette tâche d'analyse modifiera cet index de destination.", - "xpack.ml.dataframe.analytics.create.destinationIndexInputAriaLabel": "Choisissez un nom d'index de destination unique.", - "xpack.ml.dataframe.analytics.create.destinationIndexInvalidError": "Nom d'index de destination non valide.", - "xpack.ml.dataframe.analytics.create.destinationIndexLabel": "Index de destination", "xpack.ml.dataframe.analytics.create.destinationIndexNotCreatedForDataFrameAnalyticsJob": "Aucun index de destination n’a encore été créé.", - "xpack.ml.dataframe.analytics.create.DestIndexSameAsIdLabel": "Index de destination identique à l'ID de tâche", "xpack.ml.dataframe.analytics.create.detailsDetails.editButtonText": "Modifier", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrls.title": "URL personnalisées", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.learnMoreLinkText": "En savoir plus", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSectionButton": "Paramètres supplémentaires", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldHelpText": "Sélectionnez un champ temporel principal à utiliser avec le filtre temporel global.", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldLabel": "Champ temporel pour la vue de données Kibana", - "xpack.ml.dataframe.analytics.create.detailsStep.noTimeFieldOptionLabel": "Je ne souhaite pas utiliser l'option de champ temporel", "xpack.ml.dataframe.analytics.create.downsampleFactorInputAriaLabel": "Fraction de données utilisée pour calculer les dérivés de la fonction de perte pour l'entraînement de l'arborescence.", "xpack.ml.dataframe.analytics.create.downsampleFactorLabel": "Facteur de sous-échantillonnage", "xpack.ml.dataframe.analytics.create.downsampleFactorText": "Fraction de données utilisée pour calculer les dérivés de la fonction de perte pour l'entraînement de l'arborescence. Doit être compris entre 0 et 1.", @@ -25369,9 +25244,8 @@ "xpack.ml.dataFrame.analytics.create.searchSelection.CcsErrorCallOutTitle": "Les vues de données utilisant la recherche inter-clusters ne sont pas prises en charge.", "xpack.ml.dataFrame.analytics.create.searchSelection.errorGettingDataViewTitle": "Erreur lors du chargement de la vue de données utilisée par la recherche enregistrée", "xpack.ml.dataFrame.analytics.create.searchSelection.notFoundLabel": "Aucun recherche enregistrée ni aucun index correspondants n'ont été trouvés.", - "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern": "Vue de données", + "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.dataView": "Vue de données", "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.search": "Recherche enregistrée", - "xpack.ml.dataframe.analytics.create.shouldCreateDataViewMessage": "Vous ne pourrez peut-être pas visualiser les résultats de la tâche si aucune vue de données n'est créée pour l'index de destination.", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitInputAriaLabel": "Les arbres de décision dépassant cette profondeur sont pénalisés dans les calculs de perte.", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitLabel": "Limite de profondeur d'arborescence non stricte", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitText": "Les arbres de décision dépassant cette profondeur sont pénalisés dans les calculs de perte. Doit être supérieur ou égal à 0. ", @@ -25586,7 +25460,6 @@ "xpack.ml.dataframe.analyticsMap.noJobSelectedLabel": "Aucun ID d'analyse sélectionné", "xpack.ml.dataframe.analyticsMap.title": "Mapping pour l’analyse", "xpack.ml.dataframe.analyticsSourceSelection.title": "Nouvelle tâche d'analyse / Sélectionner une vue de données source", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "Découvrez les limitations relatives aux noms d'index.", "xpack.ml.dataFrameAnalytics.analyticsMap.docTitle": "Mapping d'analyse", "xpack.ml.dataFrameAnalytics.createJob.docTitle": "Créer une tâche", "xpack.ml.dataFrameAnalytics.exploration.docTitle": "Explorateur de résultats", @@ -29258,7 +29131,6 @@ "xpack.observability.customThreshold.rule.alertFlyout.customEquationTooltip": "Ceci est compatible avec des calculs de base (A + B / C) et la logique booléenne (A < B ? A : B).", "xpack.observability.customThreshold.rule.alertFlyout.dataViewError.noTimestamp": "La vue de données sélectionnée ne dispose pas de champ d'horodatage. Veuillez sélectionner une autre vue de données.", "xpack.observability.customThreshold.rule.alertFlyout.defineTextQueryPrompt": "Définir le filtre de recherche (facultatif)", - "xpack.observability.customThreshold.rule.alertFlyout.error.aggregationRequired": "L'agrégation est requise.", "xpack.observability.customThreshold.rule.alertFlyout.error.equation.invalidCharacters": "Le champ d'équation prend en charge uniquement les caractères suivants : A-Z, +, -, /, *, (, ), ?, !, &, :, |, >, <, =", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidFilterQuery": "La requête de filtre n'est pas valide.", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidSearchConfiguration": "La vue de données est requise.", @@ -29440,9 +29312,6 @@ "xpack.observability.profilingDatacenterPUEUiSettingDescription": "L'indicateur d'efficacité énergétique (PUE) des centres de données mesure l'efficacité de l'utilisation de l'énergie par les centres de données. La valeur par défaut de 1,7 correspond au PUE moyen sur site d'un centre de données selon l'enquête {uptimeLink} \n

    \n Vous pouvez également utiliser le PUE qui correspond à votre fournisseur cloud : \n
      \n
    • AWS : 1,135
    • \n
    • Google Cloud : 1,1
    • \n
    • Azure : 1,185
    • \n
    \n ", "xpack.observability.profilingDatacenterPUEUiSettingDescription.uptimeLink": "Uptime Institute", "xpack.observability.profilingDatacenterPUEUiSettingName": "PUE des centres de données", - "xpack.observability.profilingPerCoreWattUiSettingDescription": "Consommation d'énergie moyenne amortie par cœur (avec une utilisation du CPU à 100 %).", - "xpack.observability.profilingPerCoreWattUiSettingName": "Watts par cœur", - "xpack.observability.profilingUseLegacyFlamegraphAPI": "Utiliser l'API héritée flame-graph dans Universal Profiling", "xpack.observability.resources.documentation": "Documentation", "xpack.observability.resources.forum": "Forum de discussion", "xpack.observability.resources.quick_start": "Vidéos de démarrage rapide", @@ -30363,7 +30232,6 @@ "xpack.profiling.notAvailableLabel": "S. O.", "xpack.profiling.privilegesWarningDescription": "Des problèmes de privilèges empêchent la vérification du statut d'Universal Profiling. Si vous rencontrez des problèmes ou si les données ne chargent pas, n'hésitez pas à faire appel à votre administrateur.", "xpack.profiling.privilegesWarningTitle": "Limitation des privilèges utilisateur", - "xpack.profiling.settings.co2Sections": "CO2", "xpack.profiling.settings.save.error": "Une erreur s'est produite lors de l'enregistrement des paramètres", "xpack.profiling.settings.saveButton": "Enregistrer les modifications", "xpack.profiling.settings.title": "Paramètres avancés", @@ -32382,12 +32250,7 @@ "xpack.securitySolution.responseActionsList.list.recordRange": "Affichage de {range} sur {total} {recordsLabel}", "xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, one {action de réponse} many {actions de réponse} other {actions de réponse}}", "xpack.securitySolution.riskInformation.howCalculatedText": "Le dispositif Entity Risk s'exécute toutes les heures afin de regrouper les alertes \"Open\" et \"Acknowledged\" des 30 derniers jours et attribue un score de risque à l'hôte ou à l'utilisateur. Il agrège ensuite les scores de risque individuels et les normalise dans une fourchette de 0 à 100 à l'aide de {riemannZetaLink} .", - "xpack.securitySolution.riskInformation.learnMore": "En savoir plus sur les risques {riskEntity}.", "xpack.securitySolution.riskInformation.riskHeader": "Plage de scores de risque de {riskEntity}", - "xpack.securitySolution.riskInformation.riskScoreFieldLabel": "Score de risque de {riskEntity}", - "xpack.securitySolution.riskInformation.riskScoreFieldText": "Le champ {riskScoreField} représente le risque normalisé du {riskEntity} sous la forme d'une valeur numérique unique. Vous pouvez utiliser cette valeur comme indicateur relatif du risque dans les playbooks de triage et de réponse.", - "xpack.securitySolution.riskInformation.riskScoreLevelLabel": "Niveau de risque {riskEntity}", - "xpack.securitySolution.riskInformation.riskScoreLevelText": "Le champ {riskLevelField} représente l'un des six niveaux de risque de {riskEntity}, sur la base d'indicateurs de risque prédéfinis.", "xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "Impossible de supprimer {totalCount, plural, =1 {pipeline} one {pipelines} many {pipelines} other {pipelines}} d'ingestion", "xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "Impossible de supprimer {totalCount, plural, =1 {Transformer} one {Transformations} many {Transformations} other {Transformations}}", "xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "Impossible de démarrer {totalCount, plural, =1 {Transformer} one {Transformations} many {Transformations} other {Transformations}}", @@ -36741,7 +36604,7 @@ "xpack.securitySolution.timeline.saveTimeline.modal.header": "Enregistrer la chronologie", "xpack.securitySolution.timeline.saveTimeline.modal.optionalLabel": "Facultatif", "xpack.securitySolution.timeline.saveTimeline.modal.titleAriaLabel": "Titre", - "xpack.securitySolution.timeline.saveTimeline.modal.titleTitle": "Titre", + "xpack.securitySolution.timeline.saveTimeline.modal.title": "Titre", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.discard.title": "Abandonner le modèle de chronologie", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.header": "Enregistrer le modèle de chronologie", "xpack.securitySolution.timeline.searchOrFilter.filterDescription": "Les événements des fournisseurs de données ci-dessus sont filtrés par le KQL adjacent", @@ -36789,7 +36652,6 @@ "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "Vu en premier", "xpack.securitySolution.timeline.userDetails.fullNameLabel": "Nom complet", "xpack.securitySolution.timeline.userDetails.hideManagedDataButton": "Masquer les données Azure AD", - "xpack.securitySolution.timeline.userDetails.hideObservedDataButton": "Masquer les données observées", "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "Système d'exploitation", "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "Adresses IP", "xpack.securitySolution.timeline.userDetails.lastNameLabel": "Nom", @@ -36808,7 +36670,6 @@ "xpack.securitySolution.timeline.userDetails.phoneLabel": "Téléphone", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "Score de risque", "xpack.securitySolution.timeline.userDetails.showManagedDataButton": "Afficher les données Azure AD", - "xpack.securitySolution.timeline.userDetails.showObservedDataButton": "Afficher les données observées", "xpack.securitySolution.timeline.userDetails.userIdLabel": "ID utilisateur", "xpack.securitySolution.timeline.userDetails.userLabel": "Utilisateur", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "Valeurs", @@ -38753,7 +38614,6 @@ "xpack.stackConnectors.components.genAi.defaultModelTextFieldLabel": "Modèle par défaut", "xpack.stackConnectors.components.genAi.defaultModelTooltipContent": "Si une requête ne comprend pas de modèle, le modèle par défaut est utilisé.", "xpack.stackConnectors.components.genAi.documentation": "documentation", - "xpack.stackConnectors.components.genAi.error.dashboardApiError": "Une erreur s'est produite lors de la recherche du tableau de bord de l'utilisation des tokens d'OpenAI.", "xpack.stackConnectors.components.genAi.error.requiredApiProviderText": "Un fournisseur d’API est nécessaire.", "xpack.stackConnectors.components.genAi.error.requiredGenerativeAiBodyText": "Le corps est requis.", "xpack.stackConnectors.components.genAi.openAi": "OpenAI", @@ -38846,7 +38706,6 @@ "xpack.stackConnectors.components.pagerDuty.componentTextFieldLabel": "Composant (facultatif)", "xpack.stackConnectors.components.pagerDuty.connectorTypeTitle": "Envoyer à PagerDuty", "xpack.stackConnectors.components.pagerDuty.dedupKeyTextFieldLabel": "DedupKey (facultatif)", - "xpack.stackConnectors.components.pagerDuty.dedupKeyTextRequiredFieldLabel": "DedupKey", "xpack.stackConnectors.components.pagerDuty.error.requiredDedupKeyText": "DedupKey est requis lors de la résolution ou de la reconnaissance d'un incident.", "xpack.stackConnectors.components.pagerDuty.error.requiredRoutingKeyText": "Une clé d'intégration / clé de routage est requise.", "xpack.stackConnectors.components.pagerDuty.error.requiredSummaryText": "Le résumé est requis.", @@ -40449,9 +40308,7 @@ "xpack.transform.forceDeleteTransformMessage": "Supprimer {count} {count, plural, one {transformation} many {transformations} other {transformations}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, one {Cette transformation} many {Au moins l''une de ces transformations} other {Au moins l''une de ces transformations}} est préconfigurée par Elastic. Le fait de {action} {count, plural, one {la} many {les} other {les}} avec une heure de fin spécifique peut avoir un impact sur d'autres éléments du produit.", "xpack.transform.multiTransformActionsMenu.transformsCount": "Sélection effectuée de {count} {count, plural, one {transformation} many {transformations} other {transformations}}", - "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} :", "xpack.transform.stepCreateForm.createTransformErrorMessage": "Une erreur s'est produite lors de la création de la transformation {transformId} :", - "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} : La vue de données existe déjà.", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "Requête non valide : {queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "Par exemple, {example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "Par exemple, {example}", @@ -40614,7 +40471,6 @@ "xpack.transform.stepCreateForm.createAlertRuleDescription": "Ouvre un assistant pour créer une règle d'alerte permettant de monitorer l'intégrité de la transformation.", "xpack.transform.stepCreateForm.createAndStartTransformButton": "Créer et démarrer", "xpack.transform.stepCreateForm.createAndStartTransformDescription": "Crée et démarre la transformation. Une transformation permet d'augmenter la charge de recherche et d'indexation dans votre cluster. Néanmoins, arrêtez la transformation en cas de charge excessive. Une fois la transformation commencée, vous pourrez choisir entre différentes options pour continuer à l’explorer.", - "xpack.transform.stepCreateForm.createDataViewLabel": "Créer une vue de données Kibana", "xpack.transform.stepCreateForm.createTransformButton": "Créer", "xpack.transform.stepCreateForm.createTransformDescription": "Crée la transformation sans la démarrer. Vous pourrez démarrer la transformation ultérieurement en revenant à la liste de transformations.", "xpack.transform.stepCreateForm.creatingDataViewMessage": "Création de la vue de données Kibana...", @@ -40700,15 +40556,7 @@ "xpack.transform.stepDetailsForm.continuousModeDelayLabel": "Retard", "xpack.transform.stepDetailsForm.continuousModeError": "Le mode continu n'est pas disponible pour les index sans champ de date.", "xpack.transform.stepDetailsForm.createIndexAPI": "API de création d'index", - "xpack.transform.stepDetailsForm.dataViewPermissionWarning": "Vous devez disposer d'une autorisation pour pouvoir créer des vues de données.", - "xpack.transform.stepDetailsForm.dataViewTimeFieldHelpText": "Sélectionnez un champ temporel principal à utiliser avec le filtre temporel global.", - "xpack.transform.stepDetailsForm.dataViewTimeFieldLabel": "Champ temporel pour la vue de données Kibana", - "xpack.transform.stepDetailsForm.dataViewTitleError": "Une vue de données avec ce titre existe déjà.", "xpack.transform.stepDetailsForm.destinationIndexHelpText": "Un index portant ce nom existe déjà. Notez que l'exécution de cette transformation modifiera cet index de destination.", - "xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel": "Choisissez un nom d'index de destination unique.", - "xpack.transform.stepDetailsForm.destinationIndexInvalidError": "Nom d'index de destination non valide.", - "xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink": "Découvrez les limitations relatives aux noms d'index.", - "xpack.transform.stepDetailsForm.destinationIndexLabel": "Index de destination", "xpack.transform.stepDetailsForm.destinationIngestPipelineAriaLabel": "Sélectionner un pipeline d'ingestion (facultatif)", "xpack.transform.stepDetailsForm.destinationIngestPipelineComboBoxPlaceholder": "Sélectionner un pipeline d'ingestion (facultatif)", "xpack.transform.stepDetailsForm.destinationIngestPipelineLabel": "Pipeline d'ingestion de destination", @@ -40727,7 +40575,6 @@ "xpack.transform.stepDetailsForm.maxPageSearchSizeHelpText": "La taille de page initiale à utiliser pour l'agrégation imbriquée de chaque point de contrôle.", "xpack.transform.stepDetailsForm.maxPageSearchSizeLabel": "Taille maximale de recherche de pages", "xpack.transform.stepDetailsForm.missingBucketCheckboxHelpTextLink": "En savoir plus", - "xpack.transform.stepDetailsForm.noTimeFieldOptionLabel": "Je ne souhaite pas utiliser l'option de champ temporel", "xpack.transform.stepDetailsForm.numFailureRetriesAriaLabel": "Choisissez un nombre maximum de tentatives.", "xpack.transform.stepDetailsForm.NumFailureRetriesError": "Le nombre de tentatives doit être compris entre 0 et 100, ou égal à -1 pour des tentatives infinies.", "xpack.transform.stepDetailsForm.retentionPolicyDateFieldHelpText": "Sélectionnez le champ de date pouvant être utilisé pour identifier les documents obsolètes dans l'index de destination.", @@ -43070,7 +42917,6 @@ "cloud.deploymentDetails.cloudIDLabel": "Identifiant du cloud", "cloud.deploymentDetails.createManageApiKeysButtonLabel": "Créer et gérer des clés d'API", "cloud.deploymentDetails.elasticEndpointLabel": "Point de terminaison Elastic", - "cloud.deploymentDetails.helpMenuLinks.endpoints": "Points de terminaison", "cloud.deploymentDetails.learnMoreButtonLabel": "En savoir plus", "cloud.deploymentDetails.modal.closeButtonLabel": "Fermer", "cloud.deploymentDetails.modal.learnMoreButtonLabel": "En savoir plus", @@ -43309,10 +43155,10 @@ "randomSampling.ui.sliderControl.performanceLabel": "Performances", "reporting.commonExportTypesHelpers.missingJobHeadersErrorMessage": "Les en-têtes de tâche sont manquants", "reporting.commonExportTypesHelpers.failedToDecryptReportJobDataErrorMessage": "Impossible de déchiffrer les données de la tâche de reporting. Veuillez vous assurer que {encryptionKey} est défini et générez à nouveau ce rapport. {err}", - "reactPackages.mountPointPortal.errorMessage": "Erreur lors du rendu du contenu du portail.", "reporting.common.browserCouldNotLaunchErrorMessage": "Impossible de générer des captures d'écran, car le navigateur ne s’est pas lancé. Consultez les logs de serveur pour en savoir plus.", "reporting.common.cloud.insufficientSystemMemoryError": "Impossible de générer ce rapport en raison d’un manque de mémoire.", "reporting.common.pdfWorkerOutOfMemoryErrorMessage": "Impossible de générer un PDF en raison d’un manque de mémoire. Essayez de réduire la taille du PDF et relancez ce rapport.", + "reactPackages.mountPointPortal.errorMessage": "Erreur lors du rendu du contenu du portail.", "savedObjectsFinder.advancedSettings.listingLimitText": "Nombre d'objets à récupérer pour les pages de listing", "savedObjectsFinder.advancedSettings.listingLimitTitle": "Limite de listing d’objets", "savedObjectsFinder.advancedSettings.perPageText": "Nombre d'objets à afficher par page dans la boîte de dialogue de chargement", @@ -43508,7 +43354,6 @@ "unifiedDocViewer.sourceViewer.errorMessageTitle": "Une erreur s'est produite.", "unifiedDocViewer.sourceViewer.refresh": "Actualiser", "utils.filename.pathWarning": "Le chemin est peut-être incorrectement formé ; vérifiez la valeur", - "utils.filename.wildcardWarning": "l'utilisation de caractères génériques dans les chemins de fichier peut affecter les performances du point de terminaison", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.description": "Active la bibliothèque de graphiques héritée pour les graphiques de jauge dans Visualize.", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.name": "Bibliothèque de graphiques héritée pour les jauges", "visTypeGauge.controls.gaugeOptions.alignmentLabel": "Alignement", @@ -43661,7 +43506,6 @@ "xpack.cloudDataMigration.upgrade.text": "Effectuer la mise à niveau vers les versions plus récentes beaucoup plus facilement", "xpack.cloudLinks.deploymentLinkLabel": "Gérer ce déploiement", "xpack.cloudLinks.helpMenuLinks.documentation": "Documentation", - "xpack.cloudLinks.helpMenuLinks.endpoints": "Points de terminaison", "xpack.cloudLinks.helpMenuLinks.giveFeedback": "Donner un retour", "xpack.cloudLinks.helpMenuLinks.support": "Support technique", "xpack.cloudLinks.setupGuide": "Guides de configuration", @@ -43777,4 +43621,4 @@ "xpack.serverlessObservability.nav.projectSettings": "Paramètres de projet", "xpack.serverlessObservability.nav.visualizations": "Visualisations" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3819e84db48e..1cfddbd685c8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2065,7 +2065,6 @@ "data.search.esErrorTitle": "検索結果を取得できません", "data.search.esql.help": "ES|QLを使用してElasticsearchを照会します。", "data.search.esql.query.help": "ES|QLクエリ。", - "data.search.esql.timezone.help": "日付操作の際に使用するタイムゾーンです。有効なISO8601フォーマットとUTCオフセットの両方が機能します。", "data.search.essql.count.help": "取得するドキュメント数です。パフォーマンスを向上させるには、小さなデータセットを使用します。", "data.search.essql.help": "Elasticsearch SQLを使用してElasticsearchを照会します。", "data.search.essql.locale.help": "使用するロケール。", @@ -4952,7 +4951,6 @@ "management.settings.categoryNames.visualizationsLabel": "ビジュアライゼーション", "management.settings.changeImageLinkText": "画像を変更", "management.settings.customSettingTooltip": "カスタム設定", - "management.settings.field.codeEditorSyntaxErrorMessage": "無効な JSON 構文", "management.settings.field.customSettingAriaLabel": "カスタム設定", "management.settings.field.imageChangeErrorMessage": "画像を保存できませんでした", "management.settings.field.invalidIconLabel": "無効", @@ -5324,7 +5322,6 @@ "savedSearch.kibana_context.savedSearchId.help": "クエリとフィルターに使用する保存検索ID を指定します。", "savedSearch.kibana_context.timeRange.help": "Kibana 時間範囲フィルターを指定します", "searchApiPanels.welcomeBanner.header.greeting.customTitle": "{name}様", - "searchApiPanels.welcomeBanner.ingestData.clientDocLink": "{languageName}APIリファレンス", "searchApiPanels.welcomeBanner.installClient.clientDocLink": "{languageName}クライアントドキュメント", "searchApiPanels.welcomeBanner.selectClient.description": "Elasticは複数の一般的な言語でクライアントを構築および保守します。Elasticのコミュニティはさらに多くを提供しています。お気に入りの言語クライアントを選択するか、{console}を起動して開始します。", "searchApiPanels.welcomeBanner.codeBox.copyButtonLabel": "コピー", @@ -5332,22 +5329,7 @@ "searchApiPanels.welcomeBanner.header.description": "プログラミング言語のクライアントを設定し、データを取り込めば、数分で検索を開始できます。", "searchApiPanels.welcomeBanner.header.greeting.defaultTitle": "こんにちは。", "searchApiPanels.welcomeBanner.header.title": "Elasticsearchをはじめよう", - "searchApiPanels.welcomeBanner.ingestData.beatsDescription": "Elasticsearch向けの軽量の、専用データ転送機能。Beatsを使用して、サーバーから運用データを送信します。", - "searchApiPanels.welcomeBanner.ingestData.beatsLink": "ビート", - "searchApiPanels.welcomeBanner.ingestData.beatsTitle": "ビート", - "searchApiPanels.welcomeBanner.ingestData.connectorsDescription": "サードパーティのソースからElasticsearchにデータを同期するための特別な統合。Elasticコネクターを使って、さまざまなデータベースやオブジェクトストアからコンテンツを同期できます。", - "searchApiPanels.welcomeBanner.ingestData.connectorsPythonLink": "connectors-python", - "searchApiPanels.welcomeBanner.ingestData.connectorsTitle": "コネクタークライアント", "searchApiPanels.welcomeBanner.ingestData.description": "データストリームやインデックスにデータを追加して、データを検索可能にします。アプリケーションとワークフローに合ったインジェスト方法を選択します。", - "searchApiPanels.welcomeBanner.ingestData.ingestApiDescription": "データをインデックス化する最も柔軟な方法で、カスタマイズや最適化オプションを完全に制御できます。", - "searchApiPanels.welcomeBanner.ingestData.ingestApiLabel": "API経由でインジェスト", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationDescription": "データを変換してElasticsearchに送信するために最適化された専用のインジェストツール。", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationLabel": "統合経由でインジェスト", - "searchApiPanels.welcomeBanner.ingestData.ingestLegendLabel": "インジェスチョン方法を選択", - "searchApiPanels.welcomeBanner.ingestData.integrationsLink": "統合について", - "searchApiPanels.welcomeBanner.ingestData.logstashDescription": "データストリームやインデックスにデータを追加して、データを検索可能にします。アプリケーションとワークフローに合ったインジェスト方法を選択します。", - "searchApiPanels.welcomeBanner.ingestData.logstashLink": "Logstash", - "searchApiPanels.welcomeBanner.ingestData.logstashTitle": "Logstash", "searchApiPanels.welcomeBanner.ingestData.title": "データをインジェスト", "searchApiPanels.welcomeBanner.installClient.description": "Elasticは複数の一般的な言語でクライアントを構築および保守します。Elasticのコミュニティはさらに多くを提供しています。開始するには、お気に入りの言語クライアントをインストールします。", "searchApiPanels.welcomeBanner.installClient.title": "クライアントをインスト-ル", @@ -8272,7 +8254,6 @@ "xpack.apm.serviceOveriew.errorsTableOccurrences": "{occurrences}件。", "xpack.apm.serviceOverview.embeddedMap.error.toastDescription": "id {embeddableFactoryId}の埋め込み可能ファクトリが見つかりました。", "xpack.apm.serviceOverview.embeddedMap.subtitle": "国と地域別に基づく{currentMap}の総数を示した地図", - "xpack.apm.serviceOverview.mobileCallOutText": "これはモバイルサービスであり、現在はテクニカルプレビューとしてリリースされています。フィードバックを送信して、エクスペリエンスの改善にご協力ください。{feedbackLink}", "xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, other {#個の環境}}", "xpack.apm.settings.agentKeys.apiKeysDisabledErrorDescription": "システム管理者に連絡し、{link}を伝えてAPIキーを有効にしてください。", "xpack.apm.settings.agentKeys.copyAgentKeyField.title": "\"{name}\"キーを作成しました", @@ -8700,7 +8681,6 @@ "xpack.apm.dashboard.addDashboard.useContextFilterLabel.tooltip": "このオプションを有効にすると、選択したサービスと環境に基づいてダッシュボードにフィルターが適用されます。", "xpack.apm.data_view.creation_failed": "データビューの作成中にエラーが発生しました", "xpack.apm.dataView.alreadyExistsInActiveSpace": "アクティブなスペースにはすでにデータビューが存在します", - "xpack.apm.dataView.alreadyExistsInAnotherSpace": "データビューはすでに別のスペースに存在しますが、このスペースでは使用できません", "xpack.apm.dataView.autoCreateDisabled": "データビューの自動作成は、「autoCreateApmDataView」構成オプションによって無効化されています", "xpack.apm.dataView.noApmData": "APMデータがありません", "xpack.apm.dependecyOperationDetailView.header.backLinkLabel": "すべての演算", @@ -9038,7 +9018,6 @@ "xpack.apm.mobile.filters.device": "デバイス", "xpack.apm.mobile.filters.nct": "NCT", "xpack.apm.mobile.filters.osVersion": "OSバージョン", - "xpack.apm.mobile.location.metrics.crashes": "最も多いクラッシュ", "xpack.apm.mobile.location.metrics.http.requests.title": "最も使用されている", "xpack.apm.mobile.location.metrics.launches": "最も多い起動", "xpack.apm.mobile.location.metrics.sessions": "最も多いセッション", @@ -9422,8 +9401,6 @@ "xpack.apm.serviceOverview.latencyColumnP95Label": "レイテンシ(95 番目)", "xpack.apm.serviceOverview.latencyColumnP99Label": "レイテンシ(99 番目)", "xpack.apm.serviceOverview.loadingText": "読み込み中…", - "xpack.apm.serviceOverview.mobileCallOutLink": "フィードバックを作成する", - "xpack.apm.serviceOverview.mobileCallOutTitle": "モバイルAPM", "xpack.apm.serviceOverview.mostUsedTitle": "最も使用されている", "xpack.apm.serviceOverview.noResultsText": "インスタンスが見つかりません", "xpack.apm.serviceOverview.throughtputChartTitle": "スループット", @@ -11672,7 +11649,6 @@ "xpack.cases.server.viewCaseInKibana": "詳細については、Kibanaでこのケースを確認してください", "xpack.cases.settings.syncAlertsSwitchLabelOff": "オフ", "xpack.cases.settings.syncAlertsSwitchLabelOn": "オン", - "xpack.cases.severity.all": "すべての重要度", "xpack.cases.severity.critical": "重大", "xpack.cases.severity.high": "高", "xpack.cases.severity.low": "低", @@ -12114,11 +12090,6 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "{integrationFullName}(CSPM)統合を使用して、Kubernetesクラスターの構成エラーを検出します。", "xpack.csp.cloudPosturePage.packageNotInstalledRenderer.promptDescription": "クラウドおよびKubernetesセキュリティ態勢管理ソリューションを利用して、クラウドインフラの構成リスク(誰でもアクセス可能なS3バケットなど)の可能性を検出し、修正します。{learnMore}", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed}が失敗し、{passed}が調査結果に合格しました", - "xpack.csp.dashboard.benchmarkSection.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.lastEvaluatedTitle": "前回評価:{dateFromNow}", - "xpack.csp.dashboard.risksTable.clusterCardViewAllButtonTitle": "この{postureAsset}の失敗した調査結果をすべて表示", - "xpack.csp.dashboard.summarySection.postureScorePanelTitle": "全体的な{type}態勢スコア", "xpack.csp.eksIntegration.docsLink": "詳細は{docs}をご覧ください", "xpack.csp.findings..bottomBarLabel": "これらは検索条件に一致した初めの{maxItems}件の調査結果です。他の結果を表示するには検索条件を絞ってください。", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "{total} {type}ページ中{pageStart}-{pageEnd}ページを表示中", @@ -12235,7 +12206,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "脆弱性", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "脆弱性", "xpack.csp.compactFormattedNumber.naTitle": "N/A", - "xpack.csp.complianceScoreChart.counterLink.failedFindingsTooltip": "失敗した調査結果", "xpack.csp.complianceScoreChart.counterLink.passedFindingsTooltip": "合格した調査結果", "xpack.csp.createDetectionRuleButton": "検出ルールを作成", "xpack.csp.createPackagePolicy.customAssetsTab.cloudNativeVulnerabilityManagementTitleLabel": "Cloud Native Vulnerability Management ", @@ -12255,13 +12225,7 @@ "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "クラウドセキュリティ態勢管理", "xpack.csp.cspmIntegration.integration.shortNameTitle": "CSPM", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterPrefixTitle": "すべての調査結果を表示 ", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.accountNameTitle": "アカウント名", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.clusterNameTitle": "クラスター名", "xpack.csp.dashboard.benchmarkSection.columnsHeader.complianceByCisSectionTitle": "CISセクション別のコンプライアンス", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.postureScoreTitle": "態勢スコア", - "xpack.csp.dashboard.benchmarkSection.defaultClusterTitle": "ID", - "xpack.csp.dashboard.benchmarkSection.manageRulesButton": "ルールの管理", "xpack.csp.dashboard.cspPageTemplate.pageTitle": "クラウドセキュリティ態勢", "xpack.csp.dashboard.risksTable.cisSectionColumnLabel": "CISセクション", "xpack.csp.dashboard.risksTable.complianceColumnLabel": "コンプライアンス", @@ -12873,7 +12837,6 @@ "xpack.dataVisualizer.table.expandRowScreenMsg": "行を展開", "xpack.dataVisualizer.title": "ファイルをアップロード", "xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.calloutDescription": "上または{link}からコネクターを選択して続行します。", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactText": "興味深い事実:Kibanaサーバーのログで進行状況を確認し、完了したら{funFacts}でDiscoverに結果を表示します。データセットによっては(何分も)かかります。このダイアログを閉じると評価はキャンセルされます!", "xpack.elasticAssistant.assistant.settings.knowledgeBasedSettings.knowledgeBaseDescription": "始めるには、{machineLearning}でELSERを設定してください。{seeDocs}", "xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.knowledgeBaseInstalledDescription": "`{kbIndexPattern}`に初期化しました", "xpack.elasticAssistant.assistant.technicalPreview.tooltipContent": "AIシステムからの応答は、必ずしも完全に正確であるとは限りません。アシスタント機能とその使用方法の詳細については、{documentationLink}を参照してください。", @@ -13001,7 +12964,6 @@ "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationPromptLabel": "評価プロンプト", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeDescription": "実行する評価のタイプ(例:\"correctness\" \"esql-validator\"、または\"custom\")。独自の評価プロンプトを指定します", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeLabel": "評価タイプ", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetDescription": "評価するサンプルデータセット。\"input\"プロパティと\"references\"プロパティを含むオブジェクトの配列", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetLabel": "データセット", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactDiscoverLinkText": "ここをクリック", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorModelDescription": "で最終評価を実行するモデル", @@ -13164,7 +13126,6 @@ "xpack.enterpriseSearch.content.index.connector.syncRules.flyout.errorTitle": "同期{idsLength, plural, other {ルール}}{ids}{idsLength, plural, other {あります}}無効です。", "xpack.enterpriseSearch.content.index.pipelines.copyCustomizeCallout.description": "インデックスはデフォルトインジェストパイプライン\"{defaultPipeline}\"を使用しています。パイプラインをインデックス固有の構成にコピーし、カスタムインジェストと推論パイプラインを作成できるようにします。", "xpack.enterpriseSearch.content.index.pipelines.ingestFlyout.modalBodyAPIText": "{apiIndex}以下の設定に行われた変更は参照専用です。これらの設定は、インデックスまたはパイプラインまで永続しません。", - "xpack.enterpriseSearch.content.indices.callout.text": "Elasticsearchインデックスは、現在、Searchの中心です。直接そのインデックスを使用して、新しいインデックスを作成し、検索エクスペリエンスを構築できます。SearchでのElasticsearchの使用方法の詳細については、{docLink}をご覧ください", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.description": "まず、Elasticsearch APIキーを生成します。この{apiKeyName}は、コネクターがドキュメントを作成された{indexName}インデックスにインデックスするための読み書き権限を有効にします。キーは安全な場所に保管してください。コネクターを構成するときに必要になります。", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.connectorConnected": "コネクター{name}は、正常にSearchに接続されました。", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.description.secondParagraph": "コネクターリポジトリには複数の{link}が含まれています。当社のフレームワークを使用すると、カスタムデータソース用のコネクターの開発を加速できます。", @@ -14380,8 +14341,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "完了", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "キーを生成", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "分析APIキーを作成", - "xpack.enterpriseSearch.content.callout.dismissButton": "閉じる", - "xpack.enterpriseSearch.content.callout.title": "SearchでのElasticsearchインデックスの概要", "xpack.enterpriseSearch.content.cannotConnect.body": "詳細。", "xpack.enterpriseSearch.content.cannotConnect.title": "エンタープライズ サーチに接続できません", "xpack.enterpriseSearch.content.crawler.authentication": "認証", @@ -14483,7 +14442,6 @@ "xpack.enterpriseSearch.content.index.syncButton.label": "同期", "xpack.enterpriseSearch.content.index.syncButton.syncing.label": "同期中", "xpack.enterpriseSearch.content.index.syncButton.waitingForSync.label": "同期を待機しています", - "xpack.enterpriseSearch.content.indices.callout.docLink": "ドキュメントを読む", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.button.label": "APIキーを生成", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.cancelButton.label": "キャンセル", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.confirmButton.label": "APIキーを生成", @@ -14617,16 +14575,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.createErrors": "パイプラインの作成エラー", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.esDocs.link": "学習されたモデルの追加方法の詳細", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.imageAlt": "機械学習モデル例がありません", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.chooseExistingLabel": "新規または既存", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.description": "メインパイプラインでプロセッサーとして使用される子パイプラインを作成または再利用します。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionDeployTrainedModel": "クラスターで自然言語処理タスクを実行するには、適切な学習済みモデルをデプロイする必要があります。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionUsePipelines": "作成するパイプラインはElasticデプロイの場所で使用されるために保存されます。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink": "SearchでのMLモデルのインポートと使用の詳細", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.emptyValueError": "フィールドが必要です。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel": "選択", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel": "既存のパイプライン", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.model": "モデル", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel": "新しいパイプライン", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.placeholder": "1 つ選択してください", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceFields": "ソースフィールド", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipelineLabel": "既存の推論パイプラインを選択", @@ -14636,11 +14587,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.invalidPipelineName": "名前には文字、数字、アンダースコア、ハイフンのみ使用する必要があります。", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.placeholder": "モデルを選択", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.redactedValue": "このモデルはKibanaスペースで使用できません", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.modelLabel": "学習済みMLモデルを選択", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.nameLabel": "名前", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.namePlaceholder": "このパイプラインの一意の名前を入力", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.pipelineNameExistsError": "名前はすでに別のパイプラインで使用されています。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.title": "パイプラインを作成または入力", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel": "学習済みMLモデルを選択", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions": "アクション", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions.deleteMapping": "このマッピングを削除", @@ -14677,15 +14626,6 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.subtitle.result": "結果", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.title": "パイプライン結果をテスト", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.useJsonFormat": "このJSON形式を使用して、独自のドキュメントの配列を追加します", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.description": "パイプラインを通してドキュメントのインデックス作成を開始する前に、インデックスマッピングを手動で更新する必要があります。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.descriptionNoAction": "インデックスマッピングは、選択した推論出力フィールドを含むように自動的に更新されます。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.docsLink": "詳細", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappings": "フィールドマッピング", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappingsRequired": "必要なフィールドマッピング", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.presentInMapping": "選択した推論出力フィールドがマッピングに存在することを確認します。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.required": "必須", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.title": "インデックスマッピングを更新", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.titleNoAction": "インデックスマッピングの更新をレビュー", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.title": "推論パイプラインの追加", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.apiIndexSubtitle": "インジェストパイプラインは、検索アプリケーションのインデックスを最適化します。APIベースのインデックスでこれらのパイプラインを使用する場合は、APIリクエストで明示的に参照する必要があります。", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.customBadge": "カスタム", @@ -14766,7 +14706,6 @@ "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.fields.title": "フィールド", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.review.title": "見直し", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.test.title": "テスト(任意)", - "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.updateMappings.title": "マッピング", "xpack.enterpriseSearch.content.integrations.dropbox": "Dropbox", "xpack.enterpriseSearch.content.integrations.dropboxDescription": "Dropboxに保存されたファイルとフォルダーを検索します。", "xpack.enterpriseSearch.content.integrations.dropboxPaper": "Dropbox Paper", @@ -15318,9 +15257,7 @@ "xpack.enterpriseSearch.index.header.more.incrementalSync": "増分コンテンツ", "xpack.enterpriseSearch.inferencePipelineCard.action.delete": "パイプラインを削除", "xpack.enterpriseSearch.inferencePipelineCard.action.detach": "パイプラインのデタッチ", - "xpack.enterpriseSearch.inferencePipelineCard.action.title": "アクション", "xpack.enterpriseSearch.inferencePipelineCard.action.view": "スタック管理で表示", - "xpack.enterpriseSearch.inferencePipelineCard.actionButton": "アクション", "xpack.enterpriseSearch.inferencePipelineCard.deleteConfirm.title": "パイプラインを削除", "xpack.enterpriseSearch.inferencePipelineCard.modelState.deploymentFailed": "デプロイが失敗しました", "xpack.enterpriseSearch.inferencePipelineCard.modelState.notDeployed": "未開始", @@ -15338,7 +15275,6 @@ "xpack.enterpriseSearch.ingestSelector.method.connectors.description": "サードパーティのデータソースからデータを抽出、変換、インデックス化、同期します。", "xpack.enterpriseSearch.ingestSelector.method.crawler": "Webクローラー", "xpack.enterpriseSearch.ingestSelector.method.crawler.description": "Webサイトやナレッジベースから検索可能なコンテンツを検出、抽出、インデックス化します。", - "xpack.enterpriseSearch.ingestSelector.startButton": "開始", "xpack.enterpriseSearch.inlineEditableTable.newRowButtonLabel": "新しい行", "xpack.enterpriseSearch.integrations.apiDescription": "Elasticsearchの堅牢なAPIを使用して、検索をアプリケーションに追加します。", "xpack.enterpriseSearch.integrations.apiName": "API", @@ -17115,7 +17051,6 @@ "xpack.fleet.agentActivityFlyout.inProgressTitle": "進行中", "xpack.fleet.agentActivityFlyout.noActivityDescription": "エージェントが再割り当て、アップグレード、または登録解除されたときに、アクティビティフィードがここに表示されます。", "xpack.fleet.agentActivityFlyout.noActivityText": "表示するアクティビティがありません", - "xpack.fleet.agentActivityFlyout.reviewErrorLogs": "エラーログを確認", "xpack.fleet.agentActivityFlyout.scheduledDescription": "スケジュール済み ", "xpack.fleet.agentActivityFlyout.title": "エージェントアクティビティ", "xpack.fleet.agentActivityFlyout.todayTitle": "今日", @@ -17924,7 +17859,6 @@ "xpack.fleet.initializationErrorMessageTitle": "Fleet を初期化できません", "xpack.fleet.integrations.customInputsLink": "カスタム入力", "xpack.fleet.integrations.discussForumLink": "フォーラム", - "xpack.fleet.integrations.endpointsButton": "エンドポイント", "xpack.fleet.integrations.installPackage.uploadedTooltip": "この統合はアップロードによってインストールされたため、自動的に再インストールできません。再インストールするには、もう一度アップロードしてください。", "xpack.fleet.integrations.integrationSaved": "統合設定が保存されました", "xpack.fleet.integrations.integrationSavedError": "統合設定の保存エラー", @@ -18653,9 +18587,7 @@ "xpack.grokDebugger.unknownErrorTitle": "問題が発生しました", "xpack.idxMgmt.badgeAriaLabel": "{label}。選択すると、これをフィルタリングします。", "xpack.idxMgmt.clearCacheIndicesAction.indexCacheClearedMessage": "インデックス{indexNames}のキャッシュがクリアされました。", - "xpack.idxMgmt.clearCacheIndicesAction.successMessage": "キャッシュが削除されました:[{indexNames}]", "xpack.idxMgmt.closeIndicesAction.indexClosedMessage": "インデックス{indexNames}は閉じられました。", - "xpack.idxMgmt.closeIndicesAction.successfullyClosedIndicesMessage": "[{indexNames}] がクローズされました", "xpack.idxMgmt.componentTemplateDetails.summaryTab.notInUseDescription": "インデックステンプレートを{createLink}するか、既存のテンプレートを{editLink}してください。", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaDescription": "クラスター状態に格納された、テンプレートに関する任意の情報。{learnMoreLink}", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaHelpText": "JSONフォーマットを使用:{code}", @@ -18674,7 +18606,6 @@ "xpack.idxMgmt.deleteDataStreamsConfirmationModal.multipleErrorsNotificationMessageText": "{count}データストリームの削除エラー", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.successDeleteMultipleNotificationMessageText": "{numSuccesses, plural, other {#個のデータストリーム}}が削除されました", "xpack.idxMgmt.deleteIndicesAction.indexDeletedMessage": "インデックス{indexNames}が削除されました。", - "xpack.idxMgmt.deleteIndicesAction.successfullyDeletedIndicesMessage": "[{indexNames}] が削除されました", "xpack.idxMgmt.deleteTemplatesModal.confirmButtonLabel": "{numTemplatesToDelete, plural, other {テンプレート}}削除", "xpack.idxMgmt.deleteTemplatesModal.deleteDescription": "{numTemplatesToDelete, plural, other {これらのテンプレート}}を削除しようとしています:", "xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "{numTemplatesToDelete, plural, other {#個のテンプレート}}削除", @@ -18692,9 +18623,7 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryHelpText": "デフォルトは{code}クエリです。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type}は、番号、日付、またはIPアドレスの範囲と一致します。", "xpack.idxMgmt.flushIndicesAction.indexFlushedMessage": "インデックス{indexNames}がフラッシュされました。", - "xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "[{indexNames}]がフラッシュされました", "xpack.idxMgmt.forceMergeIndicesAction.indexForcemergedMessage": "インデックス{indexNames}は強制的にマージされました。", - "xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "[{indexNames}]が強制結合されました", "xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "JSONフォーマットを使用:{code}", "xpack.idxMgmt.formWizard.stepSettings.settingsEditorHelpText": "JSONフォーマットを使用:{code}", "xpack.idxMgmt.goToDiscover.showIndexToolTip": "Discoverで{indexName}を表示", @@ -18791,9 +18720,7 @@ "xpack.idxMgmt.mappingsEditor.sourceFieldDescription": "_source フィールドには、インデックスの時点で指定された元の JSON ドキュメント本文が含まれています。_sourceフィールドに含めるか除外するフィールドを定義することで、_sourceフィールドから個別のフィールドを削除することができます。{docsLink}", "xpack.idxMgmt.mappingsEditor.typeField.documentationLinkLabel": "{typeName} ドキュメント", "xpack.idxMgmt.openIndicesAction.indexOpenedMessage": "インデックス{indexNames}は開かれました。", - "xpack.idxMgmt.openIndicesAction.successfullyOpenedIndicesMessage": "[{indexNames}] が開かれました", "xpack.idxMgmt.refreshIndicesAction.indexRefreshedMessage": "インデックス{indexNames}は更新されました。", - "xpack.idxMgmt.refreshIndicesAction.successfullyRefreshedIndicesMessage": "[{indexNames}] が更新されました", "xpack.idxMgmt.templateDetails.summaryTab.indexPatternsDescriptionListTitle": "インデックス{numIndexPatterns, plural, other {パターン}}", "xpack.idxMgmt.templateForm.stepLogistics.dataStreamDescription": "テンプレートは、インデックスではなく、データストリームを作成します。{docsLink}", "xpack.idxMgmt.templateForm.stepLogistics.fieldIndexPatternsHelpText": "スペースと{invalidCharactersList}文字は使用できません。", @@ -20361,62 +20288,59 @@ "xpack.infra.appName": "インフラログ", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "ドキュメンテーション", "xpack.infra.assetDetails.flyout.AlertsPageLinkLabel": "すべて表示", - "xpack.infra.assetDetails.formulas.cpuUsage": "CPU使用状況", - "xpack.infra.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", - "xpack.infra.assetDetails.formulas.cpuUsage.irqLabel": "irq", - "xpack.infra.assetDetails.formulas.cpuUsage.niceLabel": "nice", - "xpack.infra.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", - "xpack.infra.assetDetails.formulas.cpuUsage.stealLabel": "steal", - "xpack.infra.assetDetails.formulas.cpuUsage.systemLabel": "システム", - "xpack.infra.assetDetails.formulas.cpuUsage.userLabel": "ユーザー", - "xpack.infra.assetDetails.formulas.diskIORead": "ディスク読み取りIOPS", - "xpack.infra.assetDetails.formulas.diskIOWrite": "ディスク書き込みIOPS", - "xpack.infra.assetDetails.formulas.diskReadThroughput": "ディスク読み取りスループット", - "xpack.infra.assetDetails.formulas.diskSpaceAvailability": "空きディスク容量", - "xpack.infra.assetDetails.formulas.diskSpaceAvailable": "空きディスク容量", - "xpack.infra.assetDetails.formulas.diskUsage": "ディスク使用量", - "xpack.infra.assetDetails.formulas.diskWriteThroughput": "ディスク書き込みスループット", - "xpack.infra.assetDetails.formulas.hostCount.hostsLabel": "ホスト", - "xpack.infra.assetDetails.formulas.kubernetes.capacity": "容量", - "xpack.infra.assetDetails.formulas.kubernetes.used": "使用中", - "xpack.infra.assetDetails.formulas.load15m": "読み込み(15m)", - "xpack.infra.assetDetails.formulas.load1m": "読み込み(1m)", - "xpack.infra.assetDetails.formulas.load5m": "読み込み(5m)", - "xpack.infra.assetDetails.formulas.logRate": "ログレート", - "xpack.infra.assetDetails.formulas.memoryFree": "空きメモリー", - "xpack.infra.assetDetails.formulas.memoryUsage": "メモリー使用状況", - "xpack.infra.assetDetails.formulas.metric.label.cache": "キャッシュ", - "xpack.infra.assetDetails.formulas.metric.label.free": "空き", - "xpack.infra.assetDetails.formulas.metric.label.used": "使用中", - "xpack.infra.assetDetails.formulas.normalizedLoad1m": "正規化された負荷", - "xpack.infra.assetDetails.formulas.rx": "ネットワーク受信(RX)", - "xpack.infra.assetDetails.formulas.tx": "ネットワーク送信(TX)", + "xpack.metricsData.assetDetails.formulas.cpuUsage": "CPU使用状況", + "xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", + "xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice", + "xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal", + "xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "システム", + "xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "ユーザー", + "xpack.metricsData.assetDetails.formulas.diskIORead": "ディスク読み取りIOPS", + "xpack.metricsData.assetDetails.formulas.diskIOWrite": "ディスク書き込みIOPS", + "xpack.metricsData.assetDetails.formulas.diskReadThroughput": "ディスク読み取りスループット", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "空きディスク容量", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "空きディスク容量", + "xpack.metricsData.assetDetails.formulas.diskUsage": "ディスク使用量", + "xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "ディスク書き込みスループット", + "xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "ホスト", + "xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "容量", + "xpack.metricsData.assetDetails.formulas.kubernetes.used": "使用中", + "xpack.metricsData.assetDetails.formulas.load15m": "読み込み(15m)", + "xpack.metricsData.assetDetails.formulas.load1m": "読み込み(1m)", + "xpack.metricsData.assetDetails.formulas.load5m": "読み込み(5m)", + "xpack.metricsData.assetDetails.formulas.logRate": "ログレート", + "xpack.metricsData.assetDetails.formulas.memoryFree": "空きメモリー", + "xpack.metricsData.assetDetails.formulas.memoryUsage": "メモリー使用状況", + "xpack.metricsData.assetDetails.formulas.metric.label.cache": "キャッシュ", + "xpack.metricsData.assetDetails.formulas.metric.label.free": "空き", + "xpack.metricsData.assetDetails.formulas.metric.label.used": "使用中", + "xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "正規化された負荷", + "xpack.metricsData.assetDetails.formulas.rx": "ネットワーク受信(RX)", + "xpack.metricsData.assetDetails.formulas.tx": "ネットワーク送信(TX)", + "xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "Disk IOPS", + "xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "Disk Throughput", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage": "ディスク使用量", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.available": "利用可能", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "使用中", + "xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "マウントポイント別ディスク使用量", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "ノード CPU 処理能力", + "xpack.metricsData.assetDetails.metricsCharts.load": "読み込み", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "キャッシュ", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "空き", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "読み取り", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "使用中", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "書き込み", + "xpack.metricsData.assetDetails.metricsCharts.network": "ネットワーク", + "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "受信(RX)", + "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "送信(TX)", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "ノードディスク容量", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "ノードメモリー容量", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "ノードポッド容量", + "xpack.metricsData.assetDetails.overview.kpi.subtitle.average": "平均", "xpack.infra.assetDetails.header.return": "戻る", "xpack.infra.assetDetails.metadata.tooltip.documentationLink": "host.name", "xpack.infra.assetDetails.metadata.tooltip.metadata": "メタデータ", - "xpack.infra.assetDetails.metricsCharts.cpuUsage": "CPU使用状況", - "xpack.infra.assetDetails.metricsCharts.diskIOPS": "Disk IOPS", - "xpack.infra.assetDetails.metricsCharts.diskThroughput": "Disk Throughput", - "xpack.infra.assetDetails.metricsCharts.diskUsage": "ディスク使用量", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.available": "利用可能", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.used": "使用中", - "xpack.infra.assetDetails.metricsCharts.diskUsageByMountingPoint": "マウントポイント別ディスク使用量", - "xpack.infra.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "ノード CPU 処理能力", - "xpack.infra.assetDetails.metricsCharts.load": "読み込み", - "xpack.infra.assetDetails.metricsCharts.logRate": "ログレート", - "xpack.infra.assetDetails.metricsCharts.memoryUsage": "メモリー使用状況", - "xpack.infra.assetDetails.metricsCharts.metric.label.cache": "キャッシュ", - "xpack.infra.assetDetails.metricsCharts.metric.label.free": "空き", - "xpack.infra.assetDetails.metricsCharts.metric.label.read": "読み取り", - "xpack.infra.assetDetails.metricsCharts.metric.label.used": "使用中", - "xpack.infra.assetDetails.metricsCharts.metric.label.write": "書き込み", - "xpack.infra.assetDetails.metricsCharts.network": "ネットワーク", - "xpack.infra.assetDetails.metricsCharts.network.label.rx": "受信(RX)", - "xpack.infra.assetDetails.metricsCharts.network.label.tx": "送信(TX)", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeDiskCapacity": "ノードディスク容量", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeMemoryCapacity": "ノードメモリー容量", - "xpack.infra.assetDetails.metricsCharts.nginx.nodePodCapacity": "ノードポッド容量", - "xpack.infra.assetDetails.metricsCharts.normalizedLoad1m": "正規化された負荷", "xpack.infra.assetDetails.overview.alertsSectionTitle": "アラート", "xpack.infra.assetDetails.overview.kubernetesMetricsSectionTitle": "Kubernetes概要", "xpack.infra.assetDetails.overview.metadataSectionTitle": "メタデータ", @@ -20429,11 +20353,6 @@ "xpack.infra.assetDetailsEmbeddable.displayName": "アセット詳細", "xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton": "すべて表示", "xpack.infra.assetDetailsEmbeddable.notApplicableLabel": "N/A", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "CPU使用状況", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskUsage.title": "ディスク使用量", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "メモリー使用状況", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "正規化された負荷", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "平均", "xpack.infra.assetDetailsEmbeddable.overview.metadataCloudProviderHeading": "クラウドプロバイダー", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostIpHeading": "ホスト IP", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostOsVersionHeading": "ホストOSバージョン", @@ -20551,19 +20470,7 @@ "xpack.infra.hostsViewPage.tabs.logs.textFieldPlaceholder": "ログエントリーを検索...", "xpack.infra.hostsViewPage.tabs.logs.title": "ログ", "xpack.infra.hostsViewPage.tabs.metricsCharts.actions.openInLines": "Lensで開く", - "xpack.infra.hostsViewPage.tabs.metricsCharts.cpuUsage": "CPU使用状況", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIORead": "ディスク読み取りIOPS", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIOWrite": "ディスク書き込みIOPS", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskReadThroughput": "ディスク読み取りスループット", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskSpaceAvailable": "空きディスク容量", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskUsage": "ディスク使用量", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskWriteThroughput": "ディスク書き込みスループット", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryFree": "空きメモリー", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryUsage": "メモリー使用状況", - "xpack.infra.hostsViewPage.tabs.metricsCharts.normalizedLoad1m": "正規化された負荷", - "xpack.infra.hostsViewPage.tabs.metricsCharts.rx": "ネットワーク受信(RX)", "xpack.infra.hostsViewPage.tabs.metricsCharts.title": "メトリック", - "xpack.infra.hostsViewPage.tabs.metricsCharts.tx": "ネットワーク送信(TX)", "xpack.infra.hostsViewPage.tooltip.whatAreTheseMetricsLink": "これらのメトリックは何か。", "xpack.infra.hostsViewPage.tooltip.whyAmISeeingDottedLines": "点線が表示されている理由", "xpack.infra.infra.assetDetails.alerts.createAlertLink": "ルールを作成", @@ -22366,7 +22273,6 @@ "xpack.lens.config.configFlyoutCallout": "現在、ES|QLでは、構成オプションは限られています。", "xpack.lens.config.editLabel": "構成の編集", "xpack.lens.config.editLinkLabel": "Lensで編集", - "xpack.lens.config.editVisualizationLabel": "ビジュアライゼーションを編集", "xpack.lens.config.experimentalLabel": "テクニカルプレビュー", "xpack.lens.configPanel.addLayerButton": "レイヤーを追加", "xpack.lens.configPanel.experimentalLabel": "テクニカルプレビュー", @@ -23525,8 +23431,6 @@ "xpack.maps.blendedVectorLayer.clusteredLayerName": "クラスター化された{displayName}", "xpack.maps.common.esSpatialRelation.clusterFilterLabel": "クラスター{gridId}と交差します", "xpack.maps.deleteLayerConfirmModal.multiLayerWarning": "このレイヤーを削除すと、{numChildren}個のネストされた{numChildren, plural, other {レイヤー}}も削除されます。", - "xpack.maps.distanceSource.requestDescription": "データビューからメトリックを取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", - "xpack.maps.distanceSource.requestName": "距離結合リクエスト内の{leftSourceName}", "xpack.maps.embeddable.boundsFilterLabel": "マップ境界内の{geoFieldsLabel}", "xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage": "{geometryType} ジオメトリから Geojson に変換できません。サポートされていません", "xpack.maps.es_geo_utils.distanceFilterAlias": "{pointLabel}の{distanceKm}km以内", @@ -23540,10 +23444,6 @@ "xpack.maps.esSearch.topHitsEntitiesCountMsg": "{entityCount}エンティティが見つかりました。", "xpack.maps.esSearch.topHitsResultsTrimmedMsg": "結果は~{totalEntities}の{entityCount}エンティティに制限されています。", "xpack.maps.esSearch.topHitsSizeMsg": "エンティティごとに上位の{topHitsSize}ドキュメントを表示しています。", - "xpack.maps.esSearchSource.requestDescription": "データビューからドキュメントを取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", - "xpack.maps.esSearchSource.requestName": "{layerName}ドキュメントリクエスト", - "xpack.maps.esSearchSource.topHits.requestDescription": "データビューから上位の一致を取得します:{dataViewName}、表現:{entitiesFieldName}、地理空間フィールド:{geoFieldName}", - "xpack.maps.esSearchSource.topHits.requestName": "{layerName}の上位の一致リクエスト", "xpack.maps.fileUpload.trimmedResultsMsg": "結果は{numFeatures}機能、ファイルの{previewCoverage}%に制限されています。", "xpack.maps.filterByMapExtentMenuItem.displayName": "マップ境界で{containerLabel}をフィルター", "xpack.maps.filterByMapExtentMenuItem.displayNameTooltip": "マップをズームおよびパンすると、{containerLabel}が更新され、マップ境界に表示されるデータのみが表示されます。", @@ -23566,7 +23466,6 @@ "xpack.maps.mask.maskLabel": "{hideNoun}を非表示", "xpack.maps.mask.whenJoinMetric": "{whenLabel}結合メトリック", "xpack.maps.maskLegend.is": "{aggLabel}は", - "xpack.maps.pewPew.requestName": "{layerName}パスリクエスト", "xpack.maps.scalingDocs.clustersDetails": "結果が{maxResultWindow}ドキュメントを超えたときにクラスターを表示します。結果が{maxResultWindow}未満のときにドキュメントを表示します。", "xpack.maps.scalingDocs.limitDetails": "最初の{maxResultWindow}ドキュメントから特徴量を表示します。", "xpack.maps.scalingDocs.maxResultWindow": "{link}のインデックス設定によって提供される{maxResultWindow}制約。", @@ -23582,15 +23481,8 @@ "xpack.maps.source.emsTileSourceDescription": "{host}からのベースマップサービス", "xpack.maps.source.esAggSource.topTermLabel": "上位{fieldLabel}", "xpack.maps.source.esGeoGrid.groupBy.termsDescription": "上位{maxTermsTracks}語句のトラックを作成します。ポイント数が上限を超えると、トラックは切り捨てられます。", - "xpack.maps.source.esGeoLine.entityRequestDescription": "データビューからマップバッファー内の表現を取得します:{dataViewName}、表現:{splitFieldName}", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestDescription": "データビューからトラックを取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", - "xpack.maps.source.esGeoLine.trackRequestDescription": "データビューから{numEntities}個の表現のトラックを取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", "xpack.maps.source.esGeoLineDisabledReason": "{title}には Gold ライセンスが必要です。", - "xpack.maps.source.esGrid.compositeInspector.requestName": "{layerName} {bucketsName}複合リクエスト({requestCount})", - "xpack.maps.source.esGrid.compositeInspectorDescription": "データビューから{bucketsName}を取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", "xpack.maps.source.esGrid.compositePaginationErrorMessage": "{layerName}はリクエスト過多の原因になります。「グリッド解像度」を下げるか、またはトップ用語「メトリック」の数を減らしてください。", - "xpack.maps.source.esGrid.inspector.requestDescription": "データビューから{bucketsName}を取得します:{dataViewName}、地理空間フィールド:{geoFieldName}", - "xpack.maps.source.esGrid.inspector.requestName": "{layerName} {bucketsName}リクエスト", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "グリッド解像度パラメーターが認識されません: {resolution}", "xpack.maps.source.esJoin.countLabel": "{indexPatternLabel}のカウント", "xpack.maps.source.esSearch.clusterScalingLabel": "結果が{maxResultWindow}を超えたらクラスターを表示", @@ -23601,15 +23493,12 @@ "xpack.maps.source.esSource.noGeoFieldErrorMessage": "データビュー\"{indexPatternLabel}\"には現在ジオフィールド\"{geoField}\"が含まれていません", "xpack.maps.source.esSource.stylePropsMetaRequestName": "{layerName} - メタデータ", "xpack.maps.source.MVTSingleLayerVectorSourceEditor.urlHelpMessage": ".mvtベクトルタイルサービスのURL。例:{url}", - "xpack.maps.source.pewPew.inspectorDescription": "データビューからパスを取得します:{dataViewName}、ソース:{sourceFieldName}、デスティネーション:{destFieldName}", "xpack.maps.spatialJoin.wizardForm.withinExpressionValue": "レイヤー特徴量の{distance} {units}", "xpack.maps.spatialJoinExpression.noDataViewTitle": "データビュー{dataViewId}を読み込めません。", "xpack.maps.spatialJoinExpression.value": "{geoField}からの特徴量", "xpack.maps.style.fieldSelect.OriginLabel": "{fieldOrigin}からのフィールド", "xpack.maps.termJoinExpression.topTerms": "上位{size}", "xpack.maps.termJoinExpression.value": "{term}からの{topTerms}用語", - "xpack.maps.termSource.requestDescription": "データビューからメトリックを取得します:{dataViewName}、用語フィールド:{termFieldName}", - "xpack.maps.termSource.requestName": "{leftSourceName}用語結合リクエスト", "xpack.maps.tiles.resultsCompleteMsg": "{countPrefix}{count}件のドキュメントが見つかりました。", "xpack.maps.tiles.resultsTrimmedMsg": "結果は{countPrefix}{count}ドキュメントに制限されています。", "xpack.maps.tooltip.pageNumerText": "{pageNumber} / {total}", @@ -24049,8 +23938,6 @@ "xpack.maps.source.esGeoLine.sortFieldPlaceholder": "ソートフィールドを選択", "xpack.maps.source.esGeoLine.splitFieldLabel": "エンティティ", "xpack.maps.source.esGeoLine.splitFieldPlaceholder": "エンティティフィールドを選択", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestName": "'{layerName}'トラックリクエスト(時系列)", - "xpack.maps.source.esGeoLine.trackRequestName": "'{layerName}'トラックリクエスト(用語)", "xpack.maps.source.esGeoLine.trackSettingsLabel": "追跡", "xpack.maps.source.esGeoLineDescription": "ポイントから線を作成", "xpack.maps.source.esGeoLineTitle": "追跡", @@ -24093,7 +23980,6 @@ "xpack.maps.source.esSearch.useMVTVectorTiles": "ベクトルタイルを使用", "xpack.maps.source.esSearchDescription": "Elasticsearch の点、線、多角形", "xpack.maps.source.esSearchTitle": "ドキュメント", - "xpack.maps.source.esSource.stylePropsMetaRequestDescription": "シンボル化バンドを計算するために使用されるフィールドメタデータを取得するElasticsearchリクエスト。", "xpack.maps.source.esTopHitsSearch.sortFieldLabel": "並べ替えフィールド", "xpack.maps.source.esTopHitsSearch.sortOrderLabel": "並べ替え順", "xpack.maps.source.geofieldLabel": "地理空間フィールド", @@ -24397,7 +24283,6 @@ "xpack.ml.dataframe.analytics.create.analyticsProgressErrorMessage": "分析ジョブ{jobId}の進行状況統計の取得中にエラーが発生しました", "xpack.ml.dataframe.analytics.create.configDetails.includedFieldsAndMoreDescription": "{includedFields} ...(およびその他{extraCount})", "xpack.ml.dataframe.analytics.create.createDataViewSuccessMessage": "Kibanaデータビュー{dataViewName}が作成されました。", - "xpack.ml.dataframe.analytics.create.dataViewExistsError": "{title}というタイトルのデータビューはすでに存在します。", "xpack.ml.dataframe.analytics.create.dependentVariableMaxDistictValuesError": "無効です。{message}", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.description": "分析ジョブ結果からKibanaのダッシュボード、Discover、その他のWebページへのリンクを提供します。{learnMoreLink}", "xpack.ml.dataframe.analytics.create.duplicateDataViewErrorMessageError": "データビュー{dataViewName}はすでに存在します。", @@ -25261,8 +25146,6 @@ "xpack.ml.dataframe.analytics.create.configDetails.standardizationEnabled": "標準化が有効です", "xpack.ml.dataframe.analytics.create.configDetails.trainingPercent": "トレーニングパーセンテージ", "xpack.ml.dataframe.analytics.create.createDataViewErrorMessage": "Kibanaデータビューの作成中にエラーが発生しました。", - "xpack.ml.dataframe.analytics.create.createDataViewLabel": "データビューを作成", - "xpack.ml.dataframe.analytics.create.dataViewPermissionWarning": "データビューを作成する権限が必要です。", "xpack.ml.dataframe.analytics.create.dependentVariableClassificationPlaceholder": "予測する数値、カテゴリ、ブール値フィールドを選択します。", "xpack.ml.dataframe.analytics.create.dependentVariableInputAriaLabel": "従属変数として使用するフィールドを入力してください。", "xpack.ml.dataframe.analytics.create.dependentVariableLabel": "従属変数", @@ -25270,18 +25153,11 @@ "xpack.ml.dataframe.analytics.create.dependentVariableOptionsNoNumericalFields": "このデータビューの数値型フィールドが見つかりませんでした。", "xpack.ml.dataframe.analytics.create.dependentVariableRegressionPlaceholder": "予測する数値フィールドを選択します。", "xpack.ml.dataframe.analytics.create.destinationIndexHelpText": "この名前のインデックスがすでに存在します。この分析ジョブを実行すると、デスティネーションインデックスが変更されます。", - "xpack.ml.dataframe.analytics.create.destinationIndexInputAriaLabel": "固有の宛先インデックス名を選択してください。", - "xpack.ml.dataframe.analytics.create.destinationIndexInvalidError": "無効なデスティネーションインデックス名。", - "xpack.ml.dataframe.analytics.create.destinationIndexLabel": "デスティネーションインデックス", "xpack.ml.dataframe.analytics.create.destinationIndexNotCreatedForDataFrameAnalyticsJob": "デスティネーションインデックスはまだ作成されていません。", - "xpack.ml.dataframe.analytics.create.DestIndexSameAsIdLabel": "ジョブIDと同じデスティネーションインデックス", "xpack.ml.dataframe.analytics.create.detailsDetails.editButtonText": "編集", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrls.title": "カスタムURL", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.learnMoreLinkText": "詳細", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSectionButton": "追加設定", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldHelpText": "グローバル時間フィルターで使用するためのプライマリ時間フィールドを選択してください。", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldLabel": "Kibanaインデックスパターンデータビューの時間フィールド", - "xpack.ml.dataframe.analytics.create.detailsStep.noTimeFieldOptionLabel": "時間フィールドオプションを使用しない", "xpack.ml.dataframe.analytics.create.downsampleFactorInputAriaLabel": "ツリー学習の損失関数の導関数を計算するために使用されるデータの比率。", "xpack.ml.dataframe.analytics.create.downsampleFactorLabel": "ダウンサンプリング係数", "xpack.ml.dataframe.analytics.create.downsampleFactorText": "ツリー学習の損失関数の導関数を計算するために使用されるデータの比率。0~1の範囲でなければなりません。", @@ -25368,9 +25244,8 @@ "xpack.ml.dataFrame.analytics.create.searchSelection.CcsErrorCallOutTitle": "クラスター横断検索を使用するデータビューはサポートされていません。", "xpack.ml.dataFrame.analytics.create.searchSelection.errorGettingDataViewTitle": "保存された検索で使用されているデータビューの読み込みエラー", "xpack.ml.dataFrame.analytics.create.searchSelection.notFoundLabel": "一致インデックスまたは保存した検索が見つかりません。", - "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern": "データビュー", + "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.dataView": "データビュー", "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.search": "保存検索", - "xpack.ml.dataframe.analytics.create.shouldCreateDataViewMessage": "デスティネーションインデックスのデータビューが作成されていない場合は、ジョブ結果を表示できないことがあります。", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitInputAriaLabel": "この深さを超える決定木は、損失計算でペナルティがあります。", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitLabel": "ソフトツリー深さ上限値", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitText": "この深さを超える決定木は、損失計算でペナルティがあります。0以上でなければなりません。", @@ -25585,7 +25460,6 @@ "xpack.ml.dataframe.analyticsMap.noJobSelectedLabel": "分析IDが選択されていません", "xpack.ml.dataframe.analyticsMap.title": "分析のマップ", "xpack.ml.dataframe.analyticsSourceSelection.title": "新しい分析ジョブ/ソースデータビューを選択", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "インデックス名の制限に関する詳細。", "xpack.ml.dataFrameAnalytics.analyticsMap.docTitle": "分析マップ", "xpack.ml.dataFrameAnalytics.createJob.docTitle": "ジョブの作成", "xpack.ml.dataFrameAnalytics.exploration.docTitle": "結果エクスプローラー", @@ -29257,7 +29131,6 @@ "xpack.observability.customThreshold.rule.alertFlyout.customEquationTooltip": "これは基本的な数学ロジック(A + B / C)とブールロジック(A < B ?A :B)をサポートします。", "xpack.observability.customThreshold.rule.alertFlyout.dataViewError.noTimestamp": "選択したデータビューにタイムスタンプフィールドがありません。他のデータビューを選択してください。", "xpack.observability.customThreshold.rule.alertFlyout.defineTextQueryPrompt": "クエリフィルターを定義(任意)", - "xpack.observability.customThreshold.rule.alertFlyout.error.aggregationRequired": "集約が必要です。", "xpack.observability.customThreshold.rule.alertFlyout.error.equation.invalidCharacters": "等式フィールドでは次の文字のみを使用できます:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidFilterQuery": "フィルタークエリは無効です。", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidSearchConfiguration": "データビューが必要です。", @@ -29439,9 +29312,6 @@ "xpack.observability.profilingDatacenterPUEUiSettingDescription": "データセンターの電力使用効率(PUE)は、データセンターがいかに効率的にエネルギーを使用しているかを測定します。デフォルトは、{uptimeLink}調査によるオンプレミスデータセンターの平均PUEである1.7です \n

    \n また、クラウドプロバイダーに対応するPUEを使用することもできます。 \n
      \n
    • AWS:1.135
    • \n
    • GCP:1.1
    • \n
    • Azure:1.185
    • \n
    \n ", "xpack.observability.profilingDatacenterPUEUiSettingDescription.uptimeLink": "Uptime Institute", "xpack.observability.profilingDatacenterPUEUiSettingName": "データセンターPUE", - "xpack.observability.profilingPerCoreWattUiSettingDescription": "コア単位の平均償却消費電力(CPU使用率100%に基づく)。", - "xpack.observability.profilingPerCoreWattUiSettingName": "コア単位のワット数", - "xpack.observability.profilingUseLegacyFlamegraphAPI": "ユニバーサルプロファイリングでレガシーFlamegraph APIを使用", "xpack.observability.resources.documentation": "ドキュメント", "xpack.observability.resources.forum": "ディスカッションフォーラム", "xpack.observability.resources.quick_start": "クイックスタートビデオ", @@ -30362,7 +30232,6 @@ "xpack.profiling.notAvailableLabel": "N/A", "xpack.profiling.privilegesWarningDescription": "特権の問題により、ユニバーサルプロファイリングのステータスを確認できませんでした。問題が発生した場合、またはデータの読み込みに失敗した場合は、管理者にお問い合わせください。", "xpack.profiling.privilegesWarningTitle": "ユーザー特権の制限", - "xpack.profiling.settings.co2Sections": "CO2", "xpack.profiling.settings.save.error": "設定の保存中にエラーが発生しました", "xpack.profiling.settings.saveButton": "変更を保存", "xpack.profiling.settings.title": "高度な設定", @@ -32380,12 +32249,7 @@ "xpack.securitySolution.responseActionsList.list.recordRange": "{total} {recordsLabel}件中{range}を表示中", "xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, other {対応アクション}}", "xpack.securitySolution.riskInformation.howCalculatedText": "エンティティリスクエンジンは、過去30日間の\"オープン\"および\"確認済み\"アラートを集約し、ホストまたはユーザーにリスクスコアを割り当てるために1時間ごとに実行されます。次に、個々のリスクスコアを集約し、{riemannZetaLink}を使用して0~100の範囲に正規化します。", - "xpack.securitySolution.riskInformation.learnMore": "{riskEntity}リスクの詳細", "xpack.securitySolution.riskInformation.riskHeader": "{riskEntity}リスクスコア範囲", - "xpack.securitySolution.riskInformation.riskScoreFieldLabel": "{riskEntity}リスクスコア", - "xpack.securitySolution.riskInformation.riskScoreFieldText": "{riskScoreField}フィールドは{riskEntity}の正規化されたリスクを1つの数値として表します。この値は、トリアージとレスポンスのプレイブックでリスクの相対的な指標として使用できます。", - "xpack.securitySolution.riskInformation.riskScoreLevelLabel": "{riskEntity}リスクレベル", - "xpack.securitySolution.riskInformation.riskScoreLevelText": "{riskLevelField}フィールドは、定義済みのリスクメトリックに基づく{riskEntity}の6つのリスクレベルのうちの1つを表します。", "xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "インジェスト{totalCount, plural, =1 {パイプライン} other {パイプライン}}を削除できませんでした", "xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "{totalCount, plural, =1 {変換} other {変換}}の削除に失敗しました", "xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "{totalCount, plural, =1 {変換} other {変換}}の開始に失敗しました", @@ -36739,7 +36603,7 @@ "xpack.securitySolution.timeline.saveTimeline.modal.header": "タイムラインを保存", "xpack.securitySolution.timeline.saveTimeline.modal.optionalLabel": "オプション", "xpack.securitySolution.timeline.saveTimeline.modal.titleAriaLabel": "タイトル", - "xpack.securitySolution.timeline.saveTimeline.modal.titleTitle": "タイトル", + "xpack.securitySolution.timeline.saveTimeline.modal.title": "タイトル", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.discard.title": "タイムラインテンプレートを破棄", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.header": "タイムラインテンプレートを保存", "xpack.securitySolution.timeline.searchOrFilter.filterDescription": "上のデータプロバイダーからのイベントは、隣接の KQL でフィルターされます", @@ -36787,7 +36651,6 @@ "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "初回の認識", "xpack.securitySolution.timeline.userDetails.fullNameLabel": "フルネーム", "xpack.securitySolution.timeline.userDetails.hideManagedDataButton": "Azure ADデータを非表示", - "xpack.securitySolution.timeline.userDetails.hideObservedDataButton": "観測されたデータを非表示", "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "オペレーティングシステム", "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "IP アドレス", "xpack.securitySolution.timeline.userDetails.lastNameLabel": "姓", @@ -36806,7 +36669,6 @@ "xpack.securitySolution.timeline.userDetails.phoneLabel": "電話", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "リスクスコア", "xpack.securitySolution.timeline.userDetails.showManagedDataButton": "Azure ADデータを表示", - "xpack.securitySolution.timeline.userDetails.showObservedDataButton": "観測されたデータを表示", "xpack.securitySolution.timeline.userDetails.userIdLabel": "ユーザーID", "xpack.securitySolution.timeline.userDetails.userLabel": "ユーザー", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "値", @@ -38751,7 +38613,6 @@ "xpack.stackConnectors.components.genAi.defaultModelTextFieldLabel": "デフォルトモデル", "xpack.stackConnectors.components.genAi.defaultModelTooltipContent": "リクエストにモデルが含まれていない場合、デフォルトが使われます。", "xpack.stackConnectors.components.genAi.documentation": "ドキュメンテーション", - "xpack.stackConnectors.components.genAi.error.dashboardApiError": "OpenAIトークン使用状況ダッシュボードの検索エラー。", "xpack.stackConnectors.components.genAi.error.requiredApiProviderText": "APIプロバイダーは必須です。", "xpack.stackConnectors.components.genAi.error.requiredGenerativeAiBodyText": "本文が必要です。", "xpack.stackConnectors.components.genAi.openAi": "OpenAI", @@ -38844,7 +38705,6 @@ "xpack.stackConnectors.components.pagerDuty.componentTextFieldLabel": "コンポーネント(任意)", "xpack.stackConnectors.components.pagerDuty.connectorTypeTitle": "PagerDuty に送信", "xpack.stackConnectors.components.pagerDuty.dedupKeyTextFieldLabel": "DedupKey(任意)", - "xpack.stackConnectors.components.pagerDuty.dedupKeyTextRequiredFieldLabel": "DedupKey", "xpack.stackConnectors.components.pagerDuty.error.requiredDedupKeyText": "インシデントを解決または確認するときには、DedupKeyが必要です。", "xpack.stackConnectors.components.pagerDuty.error.requiredRoutingKeyText": "統合キー/ルーティングキーが必要です。", "xpack.stackConnectors.components.pagerDuty.error.requiredSummaryText": "概要が必要です。", @@ -40447,9 +40307,7 @@ "xpack.transform.forceDeleteTransformMessage": "{count}{count, plural, other {変換}}の削除", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {これらの変換のうちの少なくとも1個の変換}}はElasticによってあらかじめ構成されています。{count, plural, other {それらを}}{action}すると、製品の他の部分に影響する可能性があります。", "xpack.transform.multiTransformActionsMenu.transformsCount": "{count}個の{count, plural, other {変換}}を選択済み", - "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:", "xpack.transform.stepCreateForm.createTransformErrorMessage": "変換 {transformId} の取得中にエラーが発生しました。", - "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:データビューはすでに存在します。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "無効なクエリ:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例: {example}.", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例: {example}.", @@ -40612,7 +40470,6 @@ "xpack.transform.stepCreateForm.createAlertRuleDescription": "ウィザードを開き、トランスフォームの正常性を監視するアラートルールを作成します。", "xpack.transform.stepCreateForm.createAndStartTransformButton": "作成して開始", "xpack.transform.stepCreateForm.createAndStartTransformDescription": "トランスフォームを作成して開始します。トランスフォームは、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合はトランスフォームを停止してください。トランスフォームの開始後、トランスフォームの閲覧を続けるオプションが提供されます。", - "xpack.transform.stepCreateForm.createDataViewLabel": "Kibanaデータビューを作成", "xpack.transform.stepCreateForm.createTransformButton": "作成", "xpack.transform.stepCreateForm.createTransformDescription": "開始せずにトランスフォームを作成します。トランスフォームは後ほどトランスフォームリストに戻って開始できます。", "xpack.transform.stepCreateForm.creatingDataViewMessage": "Kibanaデータビューを作成しています...", @@ -40698,15 +40555,7 @@ "xpack.transform.stepDetailsForm.continuousModeDelayLabel": "遅延", "xpack.transform.stepDetailsForm.continuousModeError": "日付フィールドがないインデックスでは、連続モードを使用できません。", "xpack.transform.stepDetailsForm.createIndexAPI": "インデックスAPIの作成", - "xpack.transform.stepDetailsForm.dataViewPermissionWarning": "データビューを作成する権限が必要です。", - "xpack.transform.stepDetailsForm.dataViewTimeFieldHelpText": "グローバル時間フィルターで使用するためのプライマリ時間フィールドを選択してください。", - "xpack.transform.stepDetailsForm.dataViewTimeFieldLabel": "Kibanaインデックスパターンデータビューの時間フィールド", - "xpack.transform.stepDetailsForm.dataViewTitleError": "このタイトルのデータビューはすでに存在します。", "xpack.transform.stepDetailsForm.destinationIndexHelpText": "この名前のインデックスがすでに存在します。このトランスフォームを実行すると、デスティネーションインデックスが変更されます。", - "xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel": "固有の宛先インデックス名を選択してください。", - "xpack.transform.stepDetailsForm.destinationIndexInvalidError": "無効なデスティネーションインデックス名。", - "xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink": "インデックス名の制限に関する詳細。", - "xpack.transform.stepDetailsForm.destinationIndexLabel": "デスティネーションインデックス", "xpack.transform.stepDetailsForm.destinationIngestPipelineAriaLabel": "インジェストパイプラインを選択(任意)", "xpack.transform.stepDetailsForm.destinationIngestPipelineComboBoxPlaceholder": "インジェストパイプラインを選択(任意)", "xpack.transform.stepDetailsForm.destinationIngestPipelineLabel": "デスティネーションインジェストパイプライン", @@ -40725,7 +40574,6 @@ "xpack.transform.stepDetailsForm.maxPageSearchSizeHelpText": "各チェックポイントの複合集計で使用する、初期ページサイズ。", "xpack.transform.stepDetailsForm.maxPageSearchSizeLabel": "最大ページ検索サイズ", "xpack.transform.stepDetailsForm.missingBucketCheckboxHelpTextLink": "詳細", - "xpack.transform.stepDetailsForm.noTimeFieldOptionLabel": "時間フィールドオプションを使用しない", "xpack.transform.stepDetailsForm.numFailureRetriesAriaLabel": "最大再試行回数を選択します。", "xpack.transform.stepDetailsForm.NumFailureRetriesError": "再試行回数は0~100の範囲でなければなりません。-1を指定すると、再試行回数が無制限に設定されます。", "xpack.transform.stepDetailsForm.retentionPolicyDateFieldHelpText": "デスティネーションインデックスで古いドキュメントを特定するために使用できる日付フィールドを選択します。", @@ -43060,7 +42908,6 @@ "cloud.deploymentDetails.cloudIDLabel": "クラウドID", "cloud.deploymentDetails.createManageApiKeysButtonLabel": "APIキーの作成と管理", "cloud.deploymentDetails.elasticEndpointLabel": "Elastic Endpoint", - "cloud.deploymentDetails.helpMenuLinks.endpoints": "エンドポイント", "cloud.deploymentDetails.learnMoreButtonLabel": "詳細", "cloud.deploymentDetails.modal.closeButtonLabel": "閉じる", "cloud.deploymentDetails.modal.learnMoreButtonLabel": "詳細", @@ -43299,10 +43146,10 @@ "randomSampling.ui.sliderControl.performanceLabel": "パフォーマンス", "reporting.commonExportTypesHelpers.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました。{encryptionKey} が設定されていることを確認してこのレポートを再生成してください。{err}", "reporting.commonExportTypesHelpers.missingJobHeadersErrorMessage": "ジョブヘッダーがありません", - "reactPackages.mountPointPortal.errorMessage": "ポータルコンテンツのレンダリングエラー", "reporting.common.browserCouldNotLaunchErrorMessage": "ブラウザーが起動していないため、スクリーンショットを生成できません。詳細については、サーバーログを参照してください。", "reporting.common.cloud.insufficientSystemMemoryError": "メモリ不足のため、このレポートを生成できません。", "reporting.common.pdfWorkerOutOfMemoryErrorMessage": "メモリ不足のため、PDFを生成できません。PDFのサイズを小さくして、このレポートを再試行してください。", + "reactPackages.mountPointPortal.errorMessage": "ポータルコンテンツのレンダリングエラー", "savedObjectsFinder.advancedSettings.listingLimitText": "一覧ページ用に取得するオブジェクトの数です", "savedObjectsFinder.advancedSettings.listingLimitTitle": "オブジェクト取得制限", "savedObjectsFinder.advancedSettings.perPageText": "読み込みダイアログで表示されるページごとのオブジェクトの数です", @@ -43498,7 +43345,6 @@ "unifiedDocViewer.sourceViewer.errorMessageTitle": "エラーが発生しました", "unifiedDocViewer.sourceViewer.refresh": "更新", "utils.filename.pathWarning": "パスの形式が正しくない可能性があります。値を検証してください", - "utils.filename.wildcardWarning": "ファイルパスでワイルドカードを使用すると、エンドポイントのパフォーマンスに影響する可能性があります", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.description": "Visualizeでゲージグラフのレガシーグラフライブラリを有効にします。", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.name": "ゲージグラフのレガシーグラフライブラリ", "visTypeGauge.controls.gaugeOptions.alignmentLabel": "アラインメント", @@ -43651,7 +43497,6 @@ "xpack.cloudDataMigration.upgrade.text": "新しいバージョンへのアップグレードがより簡単に", "xpack.cloudLinks.deploymentLinkLabel": "このデプロイの管理", "xpack.cloudLinks.helpMenuLinks.documentation": "ドキュメント", - "xpack.cloudLinks.helpMenuLinks.endpoints": "エンドポイント", "xpack.cloudLinks.helpMenuLinks.giveFeedback": "フィードバックを作成する", "xpack.cloudLinks.helpMenuLinks.support": "サポート", "xpack.cloudLinks.setupGuide": "セットアップガイド", @@ -43767,4 +43612,4 @@ "xpack.serverlessObservability.nav.projectSettings": "プロジェクト設定", "xpack.serverlessObservability.nav.visualizations": "ビジュアライゼーション" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 5f86f2816eee..1a982d69b36c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2065,7 +2065,6 @@ "data.search.esErrorTitle": "无法检索搜索结果", "data.search.esql.help": "使用 ES|QL 查询 Elasticsearch。", "data.search.esql.query.help": "ES|QL 查询。", - "data.search.esql.timezone.help": "要用于日期操作的时区。有效的 ISO8601 格式和 UTC 偏移均适用。", "data.search.essql.count.help": "要检索的文档数目。要获取更佳的性能,请使用较小的数据集。", "data.search.essql.help": "使用 Elasticsearch SQL 查询 Elasticsearch。", "data.search.essql.locale.help": "要使用的区域设置。", @@ -4951,7 +4950,6 @@ "management.settings.categoryNames.visualizationsLabel": "可视化", "management.settings.changeImageLinkText": "更改图片", "management.settings.customSettingTooltip": "定制设置", - "management.settings.field.codeEditorSyntaxErrorMessage": "JSON 语法无效", "management.settings.field.customSettingAriaLabel": "定制设置", "management.settings.field.imageChangeErrorMessage": "图片无法保存", "management.settings.field.invalidIconLabel": "无效", @@ -5323,7 +5321,6 @@ "savedSearch.kibana_context.savedSearchId.help": "指定要用于查询和筛选的已保存搜索 ID", "savedSearch.kibana_context.timeRange.help": "指定 Kibana 时间范围筛选", "searchApiPanels.welcomeBanner.header.greeting.customTitle": "{name}您好!", - "searchApiPanels.welcomeBanner.ingestData.clientDocLink": "{languageName} API 参考", "searchApiPanels.welcomeBanner.installClient.clientDocLink": "{languageName} 客户端文档", "searchApiPanels.welcomeBanner.selectClient.description": "Elastic 以几种流行语言构建和维护客户端,我们的社区也做出了许多贡献。选择您常用的语言客户端或深入分析 {console} 以开始使用。", "searchApiPanels.welcomeBanner.codeBox.copyButtonLabel": "复制", @@ -5331,22 +5328,7 @@ "searchApiPanels.welcomeBanner.header.description": "设置您的编程语言客户端,采集一些数据,如此即可在数分钟内开始搜索。", "searchApiPanels.welcomeBanner.header.greeting.defaultTitle": "您好!", "searchApiPanels.welcomeBanner.header.title": "Elasticsearch 入门", - "searchApiPanels.welcomeBanner.ingestData.beatsDescription": "用于 Elasticsearch 的轻量级、单一用途数据采集器。使用 Beats 从您的服务器发送运营数据。", - "searchApiPanels.welcomeBanner.ingestData.beatsLink": "Beats", - "searchApiPanels.welcomeBanner.ingestData.beatsTitle": "Beats", - "searchApiPanels.welcomeBanner.ingestData.connectorsDescription": "用于将数据从第三方源同步到 Elasticsearch 的专用集成。使用 Elastic 连接器同步来自一系列数据库和对象存储的内容。", - "searchApiPanels.welcomeBanner.ingestData.connectorsPythonLink": "connectors-python", - "searchApiPanels.welcomeBanner.ingestData.connectorsTitle": "连接器客户端", "searchApiPanels.welcomeBanner.ingestData.description": "将数据添加到数据流或索引,使其可进行搜索。选择适合您的应用程序和工作流的集成方法。", - "searchApiPanels.welcomeBanner.ingestData.ingestApiDescription": "最灵活的数据索引方法,允许您全面控制定制和优化选项。", - "searchApiPanels.welcomeBanner.ingestData.ingestApiLabel": "通过 API 采集", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationDescription": "针对转换数据并将其传输到 Elasticsearch 而优化的专用采集工具。", - "searchApiPanels.welcomeBanner.ingestData.ingestIntegrationLabel": "通过集成采集", - "searchApiPanels.welcomeBanner.ingestData.ingestLegendLabel": "选择采集方法", - "searchApiPanels.welcomeBanner.ingestData.integrationsLink": "关于集成", - "searchApiPanels.welcomeBanner.ingestData.logstashDescription": "将数据添加到数据流或索引,使其可进行搜索。选择适合您的应用程序和工作流的集成方法。", - "searchApiPanels.welcomeBanner.ingestData.logstashLink": "Logstash", - "searchApiPanels.welcomeBanner.ingestData.logstashTitle": "Logstash", "searchApiPanels.welcomeBanner.ingestData.title": "采集数据", "searchApiPanels.welcomeBanner.installClient.description": "Elastic 以几种流行语言构建和维护客户端,我们的社区也做出了许多贡献。安装您常用的语言客户端以开始使用。", "searchApiPanels.welcomeBanner.installClient.title": "安装客户端", @@ -8271,7 +8253,6 @@ "xpack.apm.serviceOveriew.errorsTableOccurrences": "{occurrences} 次", "xpack.apm.serviceOverview.embeddedMap.error.toastDescription": "未找到 ID 为“{embeddableFactoryId}”的可嵌入工厂。", "xpack.apm.serviceOverview.embeddedMap.subtitle": "根据国家和区域显示 {currentMap} 总数的地图", - "xpack.apm.serviceOverview.mobileCallOutText": "这是一项移动服务,它当前以技术预览的形式发布。您可以通过提供反馈来帮助我们改进体验。{feedbackLink}。", "xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, other {# 个环境}}", "xpack.apm.settings.agentKeys.apiKeysDisabledErrorDescription": "请联系您的系统管理员并参阅{link}以启用 API 密钥。", "xpack.apm.settings.agentKeys.copyAgentKeyField.title": "已创建“{name}”密钥", @@ -8699,7 +8680,6 @@ "xpack.apm.dashboard.addDashboard.useContextFilterLabel.tooltip": "启用此选项会根据您选择的服务和环境,将筛选应用于仪表板。", "xpack.apm.data_view.creation_failed": "创建数据视图时出错", "xpack.apm.dataView.alreadyExistsInActiveSpace": "活动工作区中已存在数据视图", - "xpack.apm.dataView.alreadyExistsInAnotherSpace": "数据视图已在另一工作区中存在,但在此工作区中不可用", "xpack.apm.dataView.autoCreateDisabled": "已通过“autoCreateApmDataView”配置选项禁止自动创建数据视图", "xpack.apm.dataView.noApmData": "无 APM 数据", "xpack.apm.dependecyOperationDetailView.header.backLinkLabel": "所有操作", @@ -9037,7 +9017,6 @@ "xpack.apm.mobile.filters.device": "设备", "xpack.apm.mobile.filters.nct": "NCT", "xpack.apm.mobile.filters.osVersion": "操作系统版本", - "xpack.apm.mobile.location.metrics.crashes": "大多数崩溃", "xpack.apm.mobile.location.metrics.http.requests.title": "最常用于", "xpack.apm.mobile.location.metrics.launches": "大多数启动", "xpack.apm.mobile.location.metrics.sessions": "大多数会话", @@ -9422,8 +9401,6 @@ "xpack.apm.serviceOverview.latencyColumnP95Label": "延迟(第 95 个)", "xpack.apm.serviceOverview.latencyColumnP99Label": "延迟(第 99 个)", "xpack.apm.serviceOverview.loadingText": "正在加载……", - "xpack.apm.serviceOverview.mobileCallOutLink": "反馈", - "xpack.apm.serviceOverview.mobileCallOutTitle": "移动 APM", "xpack.apm.serviceOverview.mostUsedTitle": "最常用", "xpack.apm.serviceOverview.noResultsText": "未找到实例", "xpack.apm.serviceOverview.throughtputChartTitle": "吞吐量", @@ -11672,7 +11649,6 @@ "xpack.cases.server.viewCaseInKibana": "有关详细信息,请在 Kibana 中查看此案例", "xpack.cases.settings.syncAlertsSwitchLabelOff": "关闭", "xpack.cases.settings.syncAlertsSwitchLabelOn": "开启", - "xpack.cases.severity.all": "所有严重性", "xpack.cases.severity.critical": "紧急", "xpack.cases.severity.high": "高", "xpack.cases.severity.low": "低", @@ -12114,11 +12090,6 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "使用我们的 {integrationFullName} (KSPM) 集成可在您的 Kubernetes 集群中检测安全配置错误。", "xpack.csp.cloudPosturePage.packageNotInstalledRenderer.promptDescription": "使用我们的云和 Kubernetes 安全态势管理解决方案,在您的云基础设施中检测并缓解潜在的配置风险,如可公开访问的 S3 存储桶。{learnMore}", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} 个失败和 {passed} 个通过的结果", - "xpack.csp.dashboard.benchmarkSection.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterTitle": "{title} - {assetId}", - "xpack.csp.dashboard.benchmarkSection.lastEvaluatedTitle": "上次评估于 {dateFromNow}", - "xpack.csp.dashboard.risksTable.clusterCardViewAllButtonTitle": "查看此 {postureAsset} 的所有失败结果", - "xpack.csp.dashboard.summarySection.postureScorePanelTitle": "总体 {type} 态势分数", "xpack.csp.eksIntegration.docsLink": "请参阅 {docs} 了解更多详情", "xpack.csp.findings..bottomBarLabel": "这些是匹配您的搜索的前 {maxItems} 个结果,请优化搜索以查看其他结果。", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "正在显示第 {pageStart}-{pageEnd} 个 {type}(共 {total} 个)", @@ -12235,7 +12206,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "漏洞", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "漏洞", "xpack.csp.compactFormattedNumber.naTitle": "不可用", - "xpack.csp.complianceScoreChart.counterLink.failedFindingsTooltip": "失败的结果", "xpack.csp.complianceScoreChart.counterLink.passedFindingsTooltip": "通过的结果", "xpack.csp.createDetectionRuleButton": "创建检测规则", "xpack.csp.createPackagePolicy.customAssetsTab.cloudNativeVulnerabilityManagementTitleLabel": "云原生漏洞管理 ", @@ -12255,13 +12225,7 @@ "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "云安全态势管理", "xpack.csp.cspmIntegration.integration.shortNameTitle": "CSPM", - "xpack.csp.dashboard.benchmarkSection.clusterTitleTooltip.clusterPrefixTitle": "显示以下所有结果 ", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.accountNameTitle": "帐户名称", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.clusterNameTitle": "集群名称", "xpack.csp.dashboard.benchmarkSection.columnsHeader.complianceByCisSectionTitle": "合规性(按 CIS 部分)", - "xpack.csp.dashboard.benchmarkSection.columnsHeader.postureScoreTitle": "态势分数", - "xpack.csp.dashboard.benchmarkSection.defaultClusterTitle": "ID", - "xpack.csp.dashboard.benchmarkSection.manageRulesButton": "管理规则", "xpack.csp.dashboard.cspPageTemplate.pageTitle": "云安全态势", "xpack.csp.dashboard.risksTable.cisSectionColumnLabel": "CIS 部分", "xpack.csp.dashboard.risksTable.complianceColumnLabel": "合规性", @@ -12873,7 +12837,6 @@ "xpack.dataVisualizer.table.expandRowScreenMsg": "展开行", "xpack.dataVisualizer.title": "上传文件", "xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.calloutDescription": "在上方或从 {link} 中选择连接器以继续", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactText": "有趣的事实:一旦完成,请查看 Kibana 服务器日志以了解进度,并 {funFacts} 以在 Discover 中查看结果。将花费(许多)分钟,具体取决于数据集,而且,关闭此对话框将取消评估!", "xpack.elasticAssistant.assistant.settings.knowledgeBasedSettings.knowledgeBaseDescription": "在 {machineLearning} 中配置 ELSER 以开始。{seeDocs}", "xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.knowledgeBaseInstalledDescription": "已初始化为 `{kbIndexPattern}`", "xpack.elasticAssistant.assistant.technicalPreview.tooltipContent": "来自 AI 系统的响应可能不会始终完全准确。有关辅助功能及其用法的详细信息,请参阅 {documentationLink}。", @@ -13001,7 +12964,6 @@ "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationPromptLabel": "评估提示", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeDescription": "要执行的评估类型,如“正确性”、“esql 验证器”或“定制”,并提供您自己的评估提示", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeLabel": "评估类型", - "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetDescription": "要评估的样例数据集。具有“input”和“references”属性的对象数组", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetLabel": "数据集", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorFunFactDiscoverLinkText": "单击此处", "xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorModelDescription": "要执行最后评估的模型", @@ -13164,7 +13126,6 @@ "xpack.enterpriseSearch.content.index.connector.syncRules.flyout.errorTitle": "同步{idsLength, plural, other {规则}} {ids}{idsLength, plural, other {有}}无效。", "xpack.enterpriseSearch.content.index.pipelines.copyCustomizeCallout.description": "您的索引正使用默认采集管道 {defaultPipeline}。将该管道复制到特定于索引的配置中,以解锁创建定制采集和推理管道的功能。", "xpack.enterpriseSearch.content.index.pipelines.ingestFlyout.modalBodyAPIText": "{apiIndex}对以下设置所做的更改仅供参考。这些设置不会持续用于您的索引或管道。", - "xpack.enterpriseSearch.content.indices.callout.text": "您的 Elasticsearch 索引如今在 Search 中位于前排和中心位置。您可以创建新索引,直接通过它们构建搜索体验。有关如何在 Search 中使用 Elasticsearch 索引的详情,{docLink}", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.description": "首先,生成一个 Elasticsearch API 密钥。此 {apiKeyName} 密钥将为连接器启用读取和写入权限,以便将文档索引到已创建的 {indexName} 索引。请将该密钥保存到安全位置,因为您需要它来配置连接器。", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.connectorConnected": "您的连接器 {name} 已成功连接到 Search。", "xpack.enterpriseSearch.content.indices.configurationConnector.connectorPackage.description.secondParagraph": "连接器存储库包含几个 {link}。使用我们的框架可加速为定制数据源开发连接器。", @@ -14380,8 +14341,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "完成", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "生成密钥", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "创建分析 API 密钥", - "xpack.enterpriseSearch.content.callout.dismissButton": "关闭", - "xpack.enterpriseSearch.content.callout.title": "在 Search 中引入 Elasticsearch 索引", "xpack.enterpriseSearch.content.cannotConnect.body": "更多信息。", "xpack.enterpriseSearch.content.cannotConnect.title": "无法连接到 Enterprise Search", "xpack.enterpriseSearch.content.crawler.authentication": "身份验证", @@ -14463,18 +14422,18 @@ "xpack.enterpriseSearch.content.index.pipelines.settings.reduceWhitespaceLabel": "减少空白", "xpack.enterpriseSearch.content.index.pipelines.settings.runMlInferenceDescrition": "使用兼容的已训练 ML 模型增强您的数据", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedBody": "您可以在单线程配置中启动模型以用于测试,或调整性能以用于生产环境。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedTitle": "您的 ELSER v2 模型已部署,但尚未启动。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedTitle": "您的 ELSER 模型已部署,但尚未启动。", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingBody": "同时,您可以继续使用其他上传的模型来创建管道。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingTitle": "您的 ELSER v2 模型正在部署。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingTitle": "您的 ELSER 模型正在部署。", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.dismissButton": "关闭 ELSER 对外调用", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.learnMoreLink": "了解详情", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedBody": "在您的定制推理管道中体验 ELSER v2 的强大功能。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedBody": "在您的定制推理管道中体验 ELSER 的强大功能。", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedBody": "此单线程配置非常适合测试您的定制推理管道,但应微调性能以用于生产。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitle": "您的 ELSER v2 模型已通过单线程方式启动。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitleCompact": "您的 ELSER v2 模型正通过单线程方式运行。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitle": "您的 ELSER v2 模型已启动。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitleCompact": "您的 ELSER v2 模型正在运行。", - "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title": "通过 ELSER v2 改进您的结果", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitle": "您的 ELSER 模型已通过单线程方式启动。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitleCompact": "您的 ELSER 模型正通过单线程方式运行。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitle": "您的 ELSER 模型已启动。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitleCompact": "您的 ELSER 模型正在运行。", + "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title": "通过 ELSER 改进您的结果", "xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.titleBadge": "新建", "xpack.enterpriseSearch.content.index.searchApplication.createSearchApplication": "创建搜索应用程序", "xpack.enterpriseSearch.content.index.searchEngines.createEngineDisabledTooltip": "无法从隐藏索引创建搜索应用程序。", @@ -14483,7 +14442,6 @@ "xpack.enterpriseSearch.content.index.syncButton.label": "同步", "xpack.enterpriseSearch.content.index.syncButton.syncing.label": "正在同步", "xpack.enterpriseSearch.content.index.syncButton.waitingForSync.label": "等待同步", - "xpack.enterpriseSearch.content.indices.callout.docLink": "阅读文档", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.button.label": "生成 API 密钥", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.cancelButton.label": "取消", "xpack.enterpriseSearch.content.indices.configurationConnector.apiKey.confirmModal.confirmButton.label": "生成 API 密钥", @@ -14617,16 +14575,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.createErrors": "创建管道时出错", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.esDocs.link": "了解如何添加已训练模型", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.noModels.imageAlt": "无 Machine Learning 模型图示", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.chooseExistingLabel": "新建或现有", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.description": "构建或重复使用将在您的主管道中用作处理器的子管道。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionDeployTrainedModel": "要在集群中执行自然语言处理任务,必须部署适当的已训练模型。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.descriptionUsePipelines": "将保存您创建的管道,以便在 Elastic 部署中的其他位置使用。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink": "详细了解如何在 Search 中导入并使用 ML 模型", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.emptyValueError": "“字段”必填。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel": "选择", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel": "现有管道", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.model": "模型", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel": "新建管道", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.placeholder": "选择一个", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceFields": "源字段", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipelineLabel": "选择现有推理管道", @@ -14636,11 +14587,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.invalidPipelineName": "名称必须仅包含字母、数字、下划线和连字符。", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.placeholder": "选择模型", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.redactedValue": "此模型在 Kibana 工作区不可用", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.modelLabel": "选择已训练 ML 模型", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.nameLabel": "名称", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.namePlaceholder": "为此管道输入唯一名称", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.pipelineNameExistsError": "名称已由其他管道使用。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.title": "创建或选择管道", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel": "选择已训练 ML 模型", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions": "操作", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.fields.actions.deleteMapping": "删除此映射", @@ -14677,15 +14626,6 @@ "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.subtitle.result": "结果", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.title": "测试管道结果", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.test.useJsonFormat": "使用此 JSON 格式添加您自己的文档系列", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.description": "您必须先手动更新索引映射,然后才能开始通过管道索引文档。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.descriptionNoAction": "您的索引映射会自动进行更新,以包括选定的推理输出字段。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.docsLink": "了解详情", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappings": "字段映射", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.fieldMappingsRequired": "必填字段映射", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.presentInMapping": "确保映射中存在选定推理输出字段。", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.required": "必需", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.title": "更新索引映射", - "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.updateMappings.titleNoAction": "查看索引映射更新", "xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.title": "添加推理管道", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.apiIndexSubtitle": "采集管道将针对搜索应用程序优化您的索引。如果希望在基于 API 的索引中使用这些管道,您需要在 API 请求中显式引用它们。", "xpack.enterpriseSearch.content.indices.pipelines.ingestionPipeline.customBadge": "定制", @@ -14744,9 +14684,9 @@ "xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.startModelButton.label": "以单线程方式启动", "xpack.enterpriseSearch.content.indices.pipelines.textExpansionCallOut.viewModelsButton": "查看详情", "xpack.enterpriseSearch.content.indices.pipelines.textExpansionCreateError.mlNotificationsLink": "Machine Learning 通知", - "xpack.enterpriseSearch.content.indices.pipelines.textExpansionCreateError.title": "ELSER v2 部署出错", - "xpack.enterpriseSearch.content.indices.pipelines.textExpansionFetchError.title": "提取 ELSER v2 模型时出错", - "xpack.enterpriseSearch.content.indices.pipelines.textExpansionStartError.title": "启动 ELSER v2 部署时出错", + "xpack.enterpriseSearch.content.indices.pipelines.textExpansionCreateError.title": "ELSER 部署出错", + "xpack.enterpriseSearch.content.indices.pipelines.textExpansionFetchError.title": "提取 ELSER 模型时出错", + "xpack.enterpriseSearch.content.indices.pipelines.textExpansionStartError.title": "启动 ELSER 部署时出错", "xpack.enterpriseSearch.content.indices.searchIndex.convertConnector.buttonLabel": "转换连接器", "xpack.enterpriseSearch.content.indices.selectConnector.allConnectorsLabel": "所有连接器", "xpack.enterpriseSearch.content.indices.selectConnector.callout.description.connectorsClient": "连接器客户端", @@ -14766,7 +14706,6 @@ "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.fields.title": "字段", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.review.title": "复查", "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.test.title": "测试(可选)", - "xpack.enterpriseSearch.content.indices.transforms.addInferencePipelineModal.steps.updateMappings.title": "映射", "xpack.enterpriseSearch.content.integrations.dropbox": "Dropbox", "xpack.enterpriseSearch.content.integrations.dropboxDescription": "搜索存储在 Dropbox 上的文件和文件夹。", "xpack.enterpriseSearch.content.integrations.dropboxPaper": "Dropbox Paper", @@ -15318,9 +15257,7 @@ "xpack.enterpriseSearch.index.header.more.incrementalSync": "增量内容", "xpack.enterpriseSearch.inferencePipelineCard.action.delete": "删除管道", "xpack.enterpriseSearch.inferencePipelineCard.action.detach": "分离管道", - "xpack.enterpriseSearch.inferencePipelineCard.action.title": "操作", "xpack.enterpriseSearch.inferencePipelineCard.action.view": "在 Stack Management 中查看", - "xpack.enterpriseSearch.inferencePipelineCard.actionButton": "操作", "xpack.enterpriseSearch.inferencePipelineCard.deleteConfirm.title": "删除管道", "xpack.enterpriseSearch.inferencePipelineCard.modelState.deploymentFailed": "部署失败", "xpack.enterpriseSearch.inferencePipelineCard.modelState.notDeployed": "未开始", @@ -15338,7 +15275,6 @@ "xpack.enterpriseSearch.ingestSelector.method.connectors.description": "提取、转换、索引和同步来自第三方数据源的数据。", "xpack.enterpriseSearch.ingestSelector.method.crawler": "网络爬虫", "xpack.enterpriseSearch.ingestSelector.method.crawler.description": "发现、提取和索引网站和知识库中的可搜索内容。", - "xpack.enterpriseSearch.ingestSelector.startButton": "启动", "xpack.enterpriseSearch.inlineEditableTable.newRowButtonLabel": "新行", "xpack.enterpriseSearch.integrations.apiDescription": "通过 Elasticsearch 稳健的 API 将搜索功能添加到您的应用程序。", "xpack.enterpriseSearch.integrations.apiName": "API", @@ -17115,7 +17051,6 @@ "xpack.fleet.agentActivityFlyout.inProgressTitle": "进行中", "xpack.fleet.agentActivityFlyout.noActivityDescription": "重新分配、升级或取消注册代理时,活动源将在此处显示。", "xpack.fleet.agentActivityFlyout.noActivityText": "没有可显示的活动", - "xpack.fleet.agentActivityFlyout.reviewErrorLogs": "查看错误日志", "xpack.fleet.agentActivityFlyout.scheduledDescription": "计划进行 ", "xpack.fleet.agentActivityFlyout.title": "代理活动", "xpack.fleet.agentActivityFlyout.todayTitle": "今日", @@ -17924,7 +17859,6 @@ "xpack.fleet.initializationErrorMessageTitle": "无法初始化 Fleet", "xpack.fleet.integrations.customInputsLink": "定制输入", "xpack.fleet.integrations.discussForumLink": "论坛", - "xpack.fleet.integrations.endpointsButton": "终端", "xpack.fleet.integrations.installPackage.uploadedTooltip": "此集成通过上传进行安装,因此无法自动重新安装。请再次将其上传,以便重新安装。", "xpack.fleet.integrations.integrationSaved": "已保存集成设置", "xpack.fleet.integrations.integrationSavedError": "保存集成设置时出错", @@ -18653,9 +18587,7 @@ "xpack.grokDebugger.unknownErrorTitle": "出问题了", "xpack.idxMgmt.badgeAriaLabel": "{label}。选择以基于其进行筛选。", "xpack.idxMgmt.clearCacheIndicesAction.indexCacheClearedMessage": "已清除索引 {indexNames} 的缓存。", - "xpack.idxMgmt.clearCacheIndicesAction.successMessage": "已成功清除缓存:[{indexNames}]", "xpack.idxMgmt.closeIndicesAction.indexClosedMessage": "索引 {indexNames} 已关闭。", - "xpack.idxMgmt.closeIndicesAction.successfullyClosedIndicesMessage": "已成功关闭:[{indexNames}]", "xpack.idxMgmt.componentTemplateDetails.summaryTab.notInUseDescription": "{createLink}索引模板或{editLink}现有索引模板。", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaDescription": "有关模板的任意信息,以集群状态存储。{learnMoreLink}", "xpack.idxMgmt.componentTemplateForm.stepLogistics.metaHelpText": "使用 JSON 格式:{code}", @@ -18674,7 +18606,6 @@ "xpack.idxMgmt.deleteDataStreamsConfirmationModal.multipleErrorsNotificationMessageText": "删除 {count} 个数据流时出错", "xpack.idxMgmt.deleteDataStreamsConfirmationModal.successDeleteMultipleNotificationMessageText": "已删除 {numSuccesses, plural, other {# 个数据流}}", "xpack.idxMgmt.deleteIndicesAction.indexDeletedMessage": "索引 {indexNames} 已删除。", - "xpack.idxMgmt.deleteIndicesAction.successfullyDeletedIndicesMessage": "已成功删除:[{indexNames}]", "xpack.idxMgmt.deleteTemplatesModal.confirmButtonLabel": "删除 {numTemplatesToDelete, plural, other {模板}}", "xpack.idxMgmt.deleteTemplatesModal.deleteDescription": "您即将删除{numTemplatesToDelete, plural, other {以下模板}}:", "xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "删除 {numTemplatesToDelete, plural, other {# 个模板}}", @@ -18692,9 +18623,7 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryHelpText": "默认为:{code} 查询。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type} 匹配一个数字、日期或 IP 地址范围。", "xpack.idxMgmt.flushIndicesAction.indexFlushedMessage": "索引 {indexNames} 已清空。", - "xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "已成功清空:[{indexNames}]", "xpack.idxMgmt.forceMergeIndicesAction.indexForcemergedMessage": "已强制合并索引 {indexNames}。", - "xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "已成功强制合并:[{indexNames}]", "xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "使用 JSON 格式:{code}", "xpack.idxMgmt.formWizard.stepSettings.settingsEditorHelpText": "使用 JSON 格式:{code}", "xpack.idxMgmt.goToDiscover.showIndexToolTip": "在 Discover 中显示 {indexName}", @@ -18791,9 +18720,7 @@ "xpack.idxMgmt.mappingsEditor.sourceFieldDescription": "_source 字段包含在索引时提供的原始 JSON 文档正文。单个字段可通过定义哪些字段可以在 _source 字段中包括或排除来进行修剪。{docsLink}", "xpack.idxMgmt.mappingsEditor.typeField.documentationLinkLabel": "{typeName} 文档", "xpack.idxMgmt.openIndicesAction.indexOpenedMessage": "索引 {indexNames} 已打开。", - "xpack.idxMgmt.openIndicesAction.successfullyOpenedIndicesMessage": "已成功打开:[{indexNames}]", "xpack.idxMgmt.refreshIndicesAction.indexRefreshedMessage": "索引 {indexNames} 已刷新。", - "xpack.idxMgmt.refreshIndicesAction.successfullyRefreshedIndicesMessage": "已成功刷新:[{indexNames}]", "xpack.idxMgmt.templateDetails.summaryTab.indexPatternsDescriptionListTitle": "索引{numIndexPatterns, plural, other {模式}}", "xpack.idxMgmt.templateForm.stepLogistics.dataStreamDescription": "该模板创建数据流,而非索引。{docsLink}", "xpack.idxMgmt.templateForm.stepLogistics.fieldIndexPatternsHelpText": "不允许使用空格和字符 {invalidCharactersList}。", @@ -20361,62 +20288,58 @@ "xpack.infra.appName": "基础架构日志", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "文档", "xpack.infra.assetDetails.flyout.AlertsPageLinkLabel": "全部显示", - "xpack.infra.assetDetails.formulas.cpuUsage": "CPU 使用率", - "xpack.infra.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", - "xpack.infra.assetDetails.formulas.cpuUsage.irqLabel": "irq", - "xpack.infra.assetDetails.formulas.cpuUsage.niceLabel": "nice", - "xpack.infra.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", - "xpack.infra.assetDetails.formulas.cpuUsage.stealLabel": "steal", - "xpack.infra.assetDetails.formulas.cpuUsage.systemLabel": "system", - "xpack.infra.assetDetails.formulas.cpuUsage.userLabel": "用户", - "xpack.infra.assetDetails.formulas.diskIORead": "磁盘读取 IOPS", - "xpack.infra.assetDetails.formulas.diskIOWrite": "磁盘写入 IOPS", - "xpack.infra.assetDetails.formulas.diskReadThroughput": "磁盘读取吞吐量", - "xpack.infra.assetDetails.formulas.diskSpaceAvailability": "磁盘空间可用性", - "xpack.infra.assetDetails.formulas.diskSpaceAvailable": "可用磁盘空间", - "xpack.infra.assetDetails.formulas.diskUsage": "磁盘使用率", - "xpack.infra.assetDetails.formulas.diskWriteThroughput": "磁盘写入吞吐量", - "xpack.infra.assetDetails.formulas.hostCount.hostsLabel": "主机", - "xpack.infra.assetDetails.formulas.kubernetes.capacity": "容量", - "xpack.infra.assetDetails.formulas.kubernetes.used": "已使用", - "xpack.infra.assetDetails.formulas.load15m": "负载(15 分钟)", - "xpack.infra.assetDetails.formulas.load1m": "负载(1 分钟)", - "xpack.infra.assetDetails.formulas.load5m": "负载(5 分钟)", - "xpack.infra.assetDetails.formulas.logRate": "日志速率", - "xpack.infra.assetDetails.formulas.memoryFree": "可用内存", - "xpack.infra.assetDetails.formulas.memoryUsage": "内存利用率", - "xpack.infra.assetDetails.formulas.metric.label.cache": "缓存", - "xpack.infra.assetDetails.formulas.metric.label.free": "可用", - "xpack.infra.assetDetails.formulas.metric.label.used": "已使用", - "xpack.infra.assetDetails.formulas.normalizedLoad1m": "标准化负载", - "xpack.infra.assetDetails.formulas.rx": "网络入站数据 (RX)", - "xpack.infra.assetDetails.formulas.tx": "网络出站数据 (TX)", + "xpack.metricsData.assetDetails.formulas.cpuUsage": "CPU 使用率", + "xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait", + "xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice", + "xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel": "softirq", + "xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal", + "xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "system", + "xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "用户", + "xpack.metricsData.assetDetails.formulas.diskIORead": "磁盘读取 IOPS", + "xpack.metricsData.assetDetails.formulas.diskIOWrite": "磁盘写入 IOPS", + "xpack.metricsData.assetDetails.formulas.diskReadThroughput": "磁盘读取吞吐量", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "磁盘空间可用性", + "xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "可用磁盘空间", + "xpack.metricsData.assetDetails.formulas.diskUsage": "磁盘使用率", + "xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "磁盘写入吞吐量", + "xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "主机", + "xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "容量", + "xpack.metricsData.assetDetails.formulas.kubernetes.used": "已使用", + "xpack.metricsData.assetDetails.formulas.load15m": "负载(15 分钟)", + "xpack.metricsData.assetDetails.formulas.load1m": "负载(1 分钟)", + "xpack.metricsData.assetDetails.formulas.load5m": "负载(5 分钟)", + "xpack.metricsData.assetDetails.formulas.logRate": "日志速率", + "xpack.metricsData.assetDetails.formulas.memoryFree": "可用内存", + "xpack.metricsData.assetDetails.formulas.memoryUsage": "内存利用率", + "xpack.metricsData.assetDetails.formulas.metric.label.cache": "缓存", + "xpack.metricsData.assetDetails.formulas.metric.label.free": "可用", + "xpack.metricsData.assetDetails.formulas.metric.label.used": "已使用", + "xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "标准化负载", + "xpack.metricsData.assetDetails.formulas.rx": "网络入站数据 (RX)", + "xpack.metricsData.assetDetails.formulas.tx": "网络出站数据 (TX)", + "xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "磁盘 IOPS", + "xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "磁盘吞吐量", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.available": "可用", + "xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "已使用", + "xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "磁盘使用率(按装载点)", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "节点 CPU 容量", + "xpack.metricsData.assetDetails.metricsCharts.load": "加载", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "缓存", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "可用", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "读取", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "已使用", + "xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "写入", + "xpack.metricsData.assetDetails.metricsCharts.network": "网络", + "xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "入站 (RX)", + "xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "出站 (TX)", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "节点磁盘容量", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "节点内存容量", + "xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "节点 Pod 容量", + "xpack.metricsData.assetDetails.overview.kpi.subtitle.average": "平均值", "xpack.infra.assetDetails.header.return": "返回", "xpack.infra.assetDetails.metadata.tooltip.documentationLink": "host.name", "xpack.infra.assetDetails.metadata.tooltip.metadata": "元数据", - "xpack.infra.assetDetails.metricsCharts.cpuUsage": "CPU 使用率", - "xpack.infra.assetDetails.metricsCharts.diskIOPS": "磁盘 IOPS", - "xpack.infra.assetDetails.metricsCharts.diskThroughput": "磁盘吞吐量", - "xpack.infra.assetDetails.metricsCharts.diskUsage": "磁盘使用率", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.available": "可用", - "xpack.infra.assetDetails.metricsCharts.diskUsage.label.used": "已使用", - "xpack.infra.assetDetails.metricsCharts.diskUsageByMountingPoint": "磁盘使用率(按装载点)", - "xpack.infra.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "节点 CPU 容量", - "xpack.infra.assetDetails.metricsCharts.load": "加载", - "xpack.infra.assetDetails.metricsCharts.logRate": "日志速率", - "xpack.infra.assetDetails.metricsCharts.memoryUsage": "内存利用率", - "xpack.infra.assetDetails.metricsCharts.metric.label.cache": "缓存", - "xpack.infra.assetDetails.metricsCharts.metric.label.free": "可用", - "xpack.infra.assetDetails.metricsCharts.metric.label.read": "读取", - "xpack.infra.assetDetails.metricsCharts.metric.label.used": "已使用", - "xpack.infra.assetDetails.metricsCharts.metric.label.write": "写入", - "xpack.infra.assetDetails.metricsCharts.network": "网络", - "xpack.infra.assetDetails.metricsCharts.network.label.rx": "入站 (RX)", - "xpack.infra.assetDetails.metricsCharts.network.label.tx": "出站 (TX)", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeDiskCapacity": "节点磁盘容量", - "xpack.infra.assetDetails.metricsCharts.nginx.nodeMemoryCapacity": "节点内存容量", - "xpack.infra.assetDetails.metricsCharts.nginx.nodePodCapacity": "节点 Pod 容量", - "xpack.infra.assetDetails.metricsCharts.normalizedLoad1m": "标准化负载", "xpack.infra.assetDetails.overview.alertsSectionTitle": "告警", "xpack.infra.assetDetails.overview.kubernetesMetricsSectionTitle": "Kubernetes 概览", "xpack.infra.assetDetails.overview.metadataSectionTitle": "元数据", @@ -20429,11 +20352,6 @@ "xpack.infra.assetDetailsEmbeddable.displayName": "资产详情", "xpack.infra.assetDetailsEmbeddable.metadataSummary.showAllMetadataButton": "全部显示", "xpack.infra.assetDetailsEmbeddable.notApplicableLabel": "不可用", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.cpuUsage.title": "CPU 使用率", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.diskUsage.title": "磁盘使用率", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.memoryUsage.title": "内存利用率", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.normalizedLoad1m.title": "标准化负载", - "xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average": "平均值", "xpack.infra.assetDetailsEmbeddable.overview.metadataCloudProviderHeading": "云服务提供商", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostIpHeading": "主机 IP", "xpack.infra.assetDetailsEmbeddable.overview.metadataHostOsVersionHeading": "主机操作系统版本", @@ -20551,19 +20469,7 @@ "xpack.infra.hostsViewPage.tabs.logs.textFieldPlaceholder": "搜索日志条目......", "xpack.infra.hostsViewPage.tabs.logs.title": "日志", "xpack.infra.hostsViewPage.tabs.metricsCharts.actions.openInLines": "在 Lens 中打开", - "xpack.infra.hostsViewPage.tabs.metricsCharts.cpuUsage": "CPU 使用率", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIORead": "磁盘读取 IOPS", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskIOWrite": "磁盘写入 IOPS", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskReadThroughput": "磁盘读取吞吐量", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskSpaceAvailable": "可用磁盘空间", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskUsage": "磁盘使用率", - "xpack.infra.hostsViewPage.tabs.metricsCharts.diskWriteThroughput": "磁盘写入吞吐量", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryFree": "可用内存", - "xpack.infra.hostsViewPage.tabs.metricsCharts.memoryUsage": "内存利用率", - "xpack.infra.hostsViewPage.tabs.metricsCharts.normalizedLoad1m": "标准化负载", - "xpack.infra.hostsViewPage.tabs.metricsCharts.rx": "网络入站数据 (RX)", "xpack.infra.hostsViewPage.tabs.metricsCharts.title": "指标", - "xpack.infra.hostsViewPage.tabs.metricsCharts.tx": "网络出站数据 (TX)", "xpack.infra.hostsViewPage.tooltip.whatAreTheseMetricsLink": "这些指标是什么?", "xpack.infra.hostsViewPage.tooltip.whyAmISeeingDottedLines": "为什么我看到的是虚线?", "xpack.infra.infra.assetDetails.alerts.createAlertLink": "创建规则", @@ -22366,7 +22272,6 @@ "xpack.lens.config.configFlyoutCallout": "ES|QL 当前提供的配置选项数量有限", "xpack.lens.config.editLabel": "编辑配置", "xpack.lens.config.editLinkLabel": "在 Lens 中编辑", - "xpack.lens.config.editVisualizationLabel": "编辑可视化", "xpack.lens.config.experimentalLabel": "技术预览", "xpack.lens.configPanel.addLayerButton": "添加图层", "xpack.lens.configPanel.experimentalLabel": "技术预览", @@ -23525,8 +23430,6 @@ "xpack.maps.blendedVectorLayer.clusteredLayerName": "集群 {displayName}", "xpack.maps.common.esSpatialRelation.clusterFilterLabel": "相交集群 {gridId}", "xpack.maps.deleteLayerConfirmModal.multiLayerWarning": "移除此图层还会移除 {numChildren} 个嵌套{numChildren, plural, other {图层}}。", - "xpack.maps.distanceSource.requestDescription": "获取指标的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", - "xpack.maps.distanceSource.requestName": "距离联接请求内的 {leftSourceName}", "xpack.maps.embeddable.boundsFilterLabel": "地图边界内的 {geoFieldsLabel}", "xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage": "无法将 {geometryType} 几何图形转换成 geojson,不支持", "xpack.maps.es_geo_utils.distanceFilterAlias": "{pointLabel} {distanceKm}km 内", @@ -23540,10 +23443,6 @@ "xpack.maps.esSearch.topHitsEntitiesCountMsg": "找到 {entityCount} 个实体。", "xpack.maps.esSearch.topHitsResultsTrimmedMsg": "结果限制为 ~{totalEntities} 个实体中的前 {entityCount} 个。", "xpack.maps.esSearch.topHitsSizeMsg": "显示每个实体排名前 {topHitsSize} 的文档。", - "xpack.maps.esSearchSource.requestDescription": "获取文档的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", - "xpack.maps.esSearchSource.requestName": "{layerName} 文档请求", - "xpack.maps.esSearchSource.topHits.requestDescription": "获取最高命中结果的数据视图:{dataViewName}、实体:{entitiesFieldName}、地理空间字段:{geoFieldName}", - "xpack.maps.esSearchSource.topHits.requestName": "{layerName} 最高命中结果请求", "xpack.maps.fileUpload.trimmedResultsMsg": "结果仅限于 {numFeatures} 个特征、{previewCoverage}% 的文件。", "xpack.maps.filterByMapExtentMenuItem.displayName": "按地图边界筛选 {containerLabel}", "xpack.maps.filterByMapExtentMenuItem.displayNameTooltip": "当您缩放和平移地图时,{containerLabel} 会进行更新以仅显示在地图边界中可见的数据。", @@ -23566,7 +23465,6 @@ "xpack.maps.mask.maskLabel": "隐藏 {hideNoun}", "xpack.maps.mask.whenJoinMetric": "{whenLabel} 联接指标", "xpack.maps.maskLegend.is": "{aggLabel} 为", - "xpack.maps.pewPew.requestName": "{layerName} 路径请求", "xpack.maps.scalingDocs.clustersDetails": "结果超过 {maxResultWindow} 个文档时显示集群。结果数小于 {maxResultWindow} 时显示文档。", "xpack.maps.scalingDocs.limitDetails": "显示前 {maxResultWindow} 个文档中的特征。", "xpack.maps.scalingDocs.maxResultWindow": "{link} 索引设置提供的 {maxResultWindow} 限制。", @@ -23582,15 +23480,8 @@ "xpack.maps.source.emsTileSourceDescription": "来自 {host} 的基础地图服务", "xpack.maps.source.esAggSource.topTermLabel": "排名靠前 {fieldLabel}", "xpack.maps.source.esGeoGrid.groupBy.termsDescription": "为排名前 {maxTermsTracks} 的词创建轨迹。点数超出限制时,会截短轨迹。", - "xpack.maps.source.esGeoLine.entityRequestDescription": "获取地图缓冲内实体的数据视图:{dataViewName}、实体:{splitFieldName}", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestDescription": "获取轨迹的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", - "xpack.maps.source.esGeoLine.trackRequestDescription": "获取 {numEntities} 个实体的轨迹的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", "xpack.maps.source.esGeoLineDisabledReason": "{title} 需要黄金级许可证。", - "xpack.maps.source.esGrid.compositeInspector.requestName": "{layerName} {bucketsName} 组合请求 ({requestCount})", - "xpack.maps.source.esGrid.compositeInspectorDescription": "获取 {bucketsName} 的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", "xpack.maps.source.esGrid.compositePaginationErrorMessage": "{layerName} 正导致过多的请求。降低“网格分辨率”和/或减少热门词“指标”的数量。", - "xpack.maps.source.esGrid.inspector.requestDescription": "获取 {bucketsName} 的数据视图:{dataViewName}、地理空间字段:{geoFieldName}", - "xpack.maps.source.esGrid.inspector.requestName": "{layerName} {bucketsName} 请求", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "无法识别网格分辨率参数:{resolution}", "xpack.maps.source.esJoin.countLabel": "{indexPatternLabel} 的计数", "xpack.maps.source.esSearch.clusterScalingLabel": "结果超过 {maxResultWindow} 个时显示集群", @@ -23601,15 +23492,12 @@ "xpack.maps.source.esSource.noGeoFieldErrorMessage": "数据视图“{indexPatternLabel}”不再包含地理字段“{geoField}”", "xpack.maps.source.esSource.stylePropsMetaRequestName": "{layerName} - 元数据", "xpack.maps.source.MVTSingleLayerVectorSourceEditor.urlHelpMessage": ".mvt 矢量磁帖服务的 URL。例如 {url}", - "xpack.maps.source.pewPew.inspectorDescription": "获取路径的数据视图:{dataViewName}、源:{sourceFieldName}、目标:{destFieldName}", "xpack.maps.spatialJoin.wizardForm.withinExpressionValue": "图层特征的 {distance} {units}", "xpack.maps.spatialJoinExpression.noDataViewTitle": "无法加载数据视图 {dataViewId}。", "xpack.maps.spatialJoinExpression.value": "{geoField} 中的特征", "xpack.maps.style.fieldSelect.OriginLabel": "来自 {fieldOrigin} 的字段", "xpack.maps.termJoinExpression.topTerms": "排名靠前 {size}", "xpack.maps.termJoinExpression.value": "来自 {term} 的 {topTerms} 词", - "xpack.maps.termSource.requestDescription": "获取指标的数据视图:{dataViewName}、词字段:{termFieldName}", - "xpack.maps.termSource.requestName": "{leftSourceName} 词联接请求", "xpack.maps.tiles.resultsCompleteMsg": "找到 {countPrefix}{count} 个文档。", "xpack.maps.tiles.resultsTrimmedMsg": "结果仅限为 {countPrefix}{count} 个文档。", "xpack.maps.tooltip.pageNumerText": "{total} 的 {pageNumber}", @@ -24049,8 +23937,6 @@ "xpack.maps.source.esGeoLine.sortFieldPlaceholder": "选择排序字段", "xpack.maps.source.esGeoLine.splitFieldLabel": "实体", "xpack.maps.source.esGeoLine.splitFieldPlaceholder": "选择实体字段", - "xpack.maps.source.esGeoLine.timeSeriesTrackRequestName": "“{layerName}”轨迹请求(时间序列)", - "xpack.maps.source.esGeoLine.trackRequestName": "“{layerName}”轨迹请求(词)", "xpack.maps.source.esGeoLine.trackSettingsLabel": "轨迹", "xpack.maps.source.esGeoLineDescription": "从点创建线", "xpack.maps.source.esGeoLineTitle": "轨迹", @@ -24093,7 +23979,6 @@ "xpack.maps.source.esSearch.useMVTVectorTiles": "使用矢量磁贴", "xpack.maps.source.esSearchDescription": "Elasticsearch 的点、线和多边形", "xpack.maps.source.esSearchTitle": "文档", - "xpack.maps.source.esSource.stylePropsMetaRequestDescription": "检索用于计算符号化带的字段元数据的 Elasticsearch 请求。", "xpack.maps.source.esTopHitsSearch.sortFieldLabel": "排序字段", "xpack.maps.source.esTopHitsSearch.sortOrderLabel": "排序顺序", "xpack.maps.source.geofieldLabel": "地理空间字段", @@ -24396,7 +24281,6 @@ "xpack.ml.dataframe.analytics.create.analyticsProgressErrorMessage": "获取分析作业 {jobId} 的进度统计时发生错误", "xpack.ml.dataframe.analytics.create.configDetails.includedFieldsAndMoreDescription": "{includedFields}......(及另外 {extraCount} 个)", "xpack.ml.dataframe.analytics.create.createDataViewSuccessMessage": "已创建 Kibana 数据视图 {dataViewName}。", - "xpack.ml.dataframe.analytics.create.dataViewExistsError": "名为 {title} 的数据视图已存在。", "xpack.ml.dataframe.analytics.create.dependentVariableMaxDistictValuesError": "无效。{message}", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.description": "提供分析作业结果到 Kibana 仪表板、Discover 或其他网页的链接。{learnMoreLink}", "xpack.ml.dataframe.analytics.create.duplicateDataViewErrorMessageError": "数据视图 {dataViewName} 已存在。", @@ -25260,8 +25144,6 @@ "xpack.ml.dataframe.analytics.create.configDetails.standardizationEnabled": "标准化已启用", "xpack.ml.dataframe.analytics.create.configDetails.trainingPercent": "训练百分比", "xpack.ml.dataframe.analytics.create.createDataViewErrorMessage": "创建 Kibana 数据视图时发生错误:", - "xpack.ml.dataframe.analytics.create.createDataViewLabel": "创建数据视图", - "xpack.ml.dataframe.analytics.create.dataViewPermissionWarning": "您需要权限以创建数据视图。", "xpack.ml.dataframe.analytics.create.dependentVariableClassificationPlaceholder": "选择要预测的数值、类别或布尔值字段。", "xpack.ml.dataframe.analytics.create.dependentVariableInputAriaLabel": "输入要用作因变量的字段。", "xpack.ml.dataframe.analytics.create.dependentVariableLabel": "因变量", @@ -25269,18 +25151,11 @@ "xpack.ml.dataframe.analytics.create.dependentVariableOptionsNoNumericalFields": "没有为此数据视图找到任何数值类型字段。", "xpack.ml.dataframe.analytics.create.dependentVariableRegressionPlaceholder": "选择要预测的数值字段。", "xpack.ml.dataframe.analytics.create.destinationIndexHelpText": "已存在具有此名称的索引。请注意,运行此分析作业将会修改此目标索引。", - "xpack.ml.dataframe.analytics.create.destinationIndexInputAriaLabel": "选择唯一目标索引名称。", - "xpack.ml.dataframe.analytics.create.destinationIndexInvalidError": "目标索引名称无效。", - "xpack.ml.dataframe.analytics.create.destinationIndexLabel": "目标索引", "xpack.ml.dataframe.analytics.create.destinationIndexNotCreatedForDataFrameAnalyticsJob": "尚未创建目标索引。", - "xpack.ml.dataframe.analytics.create.DestIndexSameAsIdLabel": "目标索引与作业 ID 相同", "xpack.ml.dataframe.analytics.create.detailsDetails.editButtonText": "编辑", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrls.title": "定制 URL", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSection.customUrlsSelection.learnMoreLinkText": "了解详情", "xpack.ml.dataframe.analytics.create.detailsStep.additionalSectionButton": "其他设置", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldHelpText": "选择用于全局时间筛选的主要时间字段。", - "xpack.ml.dataframe.analytics.create.detailsStep.dataViewTimeFieldLabel": "Kibana 数据视图的时间字段", - "xpack.ml.dataframe.analytics.create.detailsStep.noTimeFieldOptionLabel": "我不想使用时间字段选项", "xpack.ml.dataframe.analytics.create.downsampleFactorInputAriaLabel": "用于为树训练计算损失函数导数的数据比例。", "xpack.ml.dataframe.analytics.create.downsampleFactorLabel": "降采样因子", "xpack.ml.dataframe.analytics.create.downsampleFactorText": "用于为树训练计算损失函数导数的数据比例。必须介于 0 和 1 之间。", @@ -25367,9 +25242,8 @@ "xpack.ml.dataFrame.analytics.create.searchSelection.CcsErrorCallOutTitle": "不支持使用跨集群搜索的数据视图。", "xpack.ml.dataFrame.analytics.create.searchSelection.errorGettingDataViewTitle": "加载已保存搜索所使用的数据视图时出错", "xpack.ml.dataFrame.analytics.create.searchSelection.notFoundLabel": "未找到匹配的索引或已保存搜索。", - "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.indexPattern": "数据视图", + "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.dataView": "数据视图", "xpack.ml.dataFrame.analytics.create.searchSelection.savedObjectType.search": "已保存搜索", - "xpack.ml.dataframe.analytics.create.shouldCreateDataViewMessage": "如果没有为目标索引创建数据视图,则可能无法查看作业结果。", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitInputAriaLabel": "超过此深度的决策树将在损失计算中被罚分。", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitLabel": "软性树深度限制", "xpack.ml.dataframe.analytics.create.softTreeDepthLimitText": "超过此深度的决策树将在损失计算中被罚分。必须大于或等于 0。", @@ -25584,7 +25458,6 @@ "xpack.ml.dataframe.analyticsMap.noJobSelectedLabel": "未选择分析 ID", "xpack.ml.dataframe.analyticsMap.title": "用于分析的地图", "xpack.ml.dataframe.analyticsSourceSelection.title": "新分析作业/选择源数据视图", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "详细了解索引名称限制。", "xpack.ml.dataFrameAnalytics.analyticsMap.docTitle": "分析地图", "xpack.ml.dataFrameAnalytics.createJob.docTitle": "创建作业", "xpack.ml.dataFrameAnalytics.exploration.docTitle": "结果浏览器", @@ -29255,7 +29128,6 @@ "xpack.observability.customThreshold.rule.alertFlyout.customEquationTooltip": "这支持基本数学 (A + B / C) 和布尔逻辑 (A < B ?A :B)。", "xpack.observability.customThreshold.rule.alertFlyout.dataViewError.noTimestamp": "选定数据视图没有时间戳字段,请选择其他数据视图。", "xpack.observability.customThreshold.rule.alertFlyout.defineTextQueryPrompt": "定义查询筛选(可选)", - "xpack.observability.customThreshold.rule.alertFlyout.error.aggregationRequired": "“聚合”必填。", "xpack.observability.customThreshold.rule.alertFlyout.error.equation.invalidCharacters": "方程字段仅支持以下字符:A-Z、+、-、/、*、(、)、?、!、&、:、|、>、<、=", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidFilterQuery": "筛选查询无效。", "xpack.observability.customThreshold.rule.alertFlyout.error.invalidSearchConfiguration": "需要数据视图。", @@ -29437,9 +29309,6 @@ "xpack.observability.profilingDatacenterPUEUiSettingDescription": "数据中心电源使用效率 (PUE) 衡量数据中心的能源利用效率。根据 {uptimeLink} 调查,本地数据中心的平均 PUE 默认为 1.7 \n

    \n 您还可以使用与您的云服务提供商对应的 PUE: \n
      \n
    • AWS:1.135
    • \n
    • GCP:1.1
    • \n
    • Azure:1.185
    • \n
    \n ", "xpack.observability.profilingDatacenterPUEUiSettingDescription.uptimeLink": "正常运行时间协会", "xpack.observability.profilingDatacenterPUEUiSettingName": "数据中心 PUE", - "xpack.observability.profilingPerCoreWattUiSettingDescription": "平均分摊每核功耗(基于 100% 的 CPU 利用率)。", - "xpack.observability.profilingPerCoreWattUiSettingName": "每核功耗(瓦)", - "xpack.observability.profilingUseLegacyFlamegraphAPI": "在 Universal Profiling 中使用旧版 Flamegraph API", "xpack.observability.resources.documentation": "文档", "xpack.observability.resources.forum": "讨论论坛", "xpack.observability.resources.quick_start": "快速入门视频", @@ -30360,7 +30229,6 @@ "xpack.profiling.notAvailableLabel": "不可用", "xpack.profiling.privilegesWarningDescription": "由于权限问题,无法查看 Universal Profiling 状态。如果遇到任何问题或无法加载数据,请联系管理员获取帮助。", "xpack.profiling.privilegesWarningTitle": "用户权限限制", - "xpack.profiling.settings.co2Sections": "CO2", "xpack.profiling.settings.save.error": "保存设置时出错", "xpack.profiling.settings.saveButton": "保存更改", "xpack.profiling.settings.title": "高级设置", @@ -32376,12 +32244,7 @@ "xpack.securitySolution.responseActionsList.list.recordRange": "正在显示第 {range} 个(共 {total} 个){recordsLabel}", "xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, other {响应操作}}", "xpack.securitySolution.riskInformation.howCalculatedText": "实体风险引擎每小时运行一次,以聚合过去 30 天出现的“未结”和“已确认”告警,并为主机或用户分配风险分数。然后,它会聚合各个风险分数并使用 {riemannZetaLink} 将其标准化为 0-100 范围。", - "xpack.securitySolution.riskInformation.learnMore": "详细了解 {riskEntity} 风险", "xpack.securitySolution.riskInformation.riskHeader": "{riskEntity} 风险分数范围", - "xpack.securitySolution.riskInformation.riskScoreFieldLabel": "{riskEntity} 风险分数", - "xpack.securitySolution.riskInformation.riskScoreFieldText": "{riskScoreField} 字段以单个数字值表示 {riskEntity} 的标准化风险。您可以在分类和响应 playbook 中将此值用作相对风险指标。", - "xpack.securitySolution.riskInformation.riskScoreLevelLabel": "{riskEntity} 风险级别", - "xpack.securitySolution.riskInformation.riskScoreLevelText": "{riskLevelField} 字段根据预定义的风险指标表示 {riskEntity} 的六个风险级别之一。", "xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "无法删除采集{totalCount, plural, =1 {管道} other {管道}}", "xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "无法删除{totalCount, plural, =1 {转换} other {转换}}", "xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "无法启动{totalCount, plural, =1 {转换} other {转换}}", @@ -36735,7 +36598,7 @@ "xpack.securitySolution.timeline.saveTimeline.modal.header": "保存时间线", "xpack.securitySolution.timeline.saveTimeline.modal.optionalLabel": "可选", "xpack.securitySolution.timeline.saveTimeline.modal.titleAriaLabel": "标题", - "xpack.securitySolution.timeline.saveTimeline.modal.titleTitle": "标题", + "xpack.securitySolution.timeline.saveTimeline.modal.title": "标题", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.discard.title": "丢弃时间线模板", "xpack.securitySolution.timeline.saveTimelineTemplate.modal.header": "保存时间线模板", "xpack.securitySolution.timeline.searchOrFilter.filterDescription": "上述数据提供程序的事件按相邻 KQL 进行筛选", @@ -36783,7 +36646,6 @@ "xpack.securitySolution.timeline.userDetails.firstSeenLabel": "首次看到时间", "xpack.securitySolution.timeline.userDetails.fullNameLabel": "全名", "xpack.securitySolution.timeline.userDetails.hideManagedDataButton": "隐藏 Azure AD 数据", - "xpack.securitySolution.timeline.userDetails.hideObservedDataButton": "隐藏观察数据", "xpack.securitySolution.timeline.userDetails.hostOsNameLabel": "操作系统", "xpack.securitySolution.timeline.userDetails.ipAddressesLabel": "IP 地址", "xpack.securitySolution.timeline.userDetails.lastNameLabel": "姓氏", @@ -36802,7 +36664,6 @@ "xpack.securitySolution.timeline.userDetails.phoneLabel": "电话", "xpack.securitySolution.timeline.userDetails.riskScoreLabel": "风险分数", "xpack.securitySolution.timeline.userDetails.showManagedDataButton": "显示 Azure AD 数据", - "xpack.securitySolution.timeline.userDetails.showObservedDataButton": "显示观察数据", "xpack.securitySolution.timeline.userDetails.userIdLabel": "用户 ID", "xpack.securitySolution.timeline.userDetails.userLabel": "用户", "xpack.securitySolution.timeline.userDetails.valuesColumnTitle": "值", @@ -38745,7 +38606,6 @@ "xpack.stackConnectors.components.genAi.defaultModelTextFieldLabel": "默认模型", "xpack.stackConnectors.components.genAi.defaultModelTooltipContent": "如果请求不包含模型,它将使用默认值。", "xpack.stackConnectors.components.genAi.documentation": "文档", - "xpack.stackConnectors.components.genAi.error.dashboardApiError": "查找 OpenAI 令牌使用情况仪表板时出错。", "xpack.stackConnectors.components.genAi.error.requiredApiProviderText": "“API 提供商”必填。", "xpack.stackConnectors.components.genAi.error.requiredGenerativeAiBodyText": "“正文”必填。", "xpack.stackConnectors.components.genAi.openAi": "OpenAI", @@ -38838,7 +38698,6 @@ "xpack.stackConnectors.components.pagerDuty.componentTextFieldLabel": "组件(可选)", "xpack.stackConnectors.components.pagerDuty.connectorTypeTitle": "发送到 PagerDuty", "xpack.stackConnectors.components.pagerDuty.dedupKeyTextFieldLabel": "DedupKey(可选)", - "xpack.stackConnectors.components.pagerDuty.dedupKeyTextRequiredFieldLabel": "DedupKey", "xpack.stackConnectors.components.pagerDuty.error.requiredDedupKeyText": "解决或确认事件时需要 DedupKey。", "xpack.stackConnectors.components.pagerDuty.error.requiredRoutingKeyText": "需要集成密钥/路由密钥。", "xpack.stackConnectors.components.pagerDuty.error.requiredSummaryText": "“摘要”必填。", @@ -40441,9 +40300,7 @@ "xpack.transform.forceDeleteTransformMessage": "删除 {count} {count, plural, other {转换}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {至少一个此类转换}}由 Elastic 预配置;{action} {count, plural, other {这些转换}}可能会影响该产品的其他部分。", "xpack.transform.multiTransformActionsMenu.transformsCount": "已选定 {count} 个{count, plural, other {转换}}", - "xpack.transform.stepCreateForm.createDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:", "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建转换 {transformId} 时出错:", - "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:数据视图已存在。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "无效查询:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例如,{example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例如,{example}", @@ -40606,7 +40463,6 @@ "xpack.transform.stepCreateForm.createAlertRuleDescription": "打开向导以创建用于监测转换运行状况的告警规则。", "xpack.transform.stepCreateForm.createAndStartTransformButton": "创建并启动", "xpack.transform.stepCreateForm.createAndStartTransformDescription": "创建并启动转换。转换将增加集群的搜索和索引负荷。如果负荷超载,请停止转换。转换启动后,系统将为您提供继续浏览转换的选项。", - "xpack.transform.stepCreateForm.createDataViewLabel": "创建 Kibana 数据视图", "xpack.transform.stepCreateForm.createTransformButton": "创建", "xpack.transform.stepCreateForm.createTransformDescription": "在不启动转换的情况下创建转换。您之后能够通过返回到转换列表,来启动转换。", "xpack.transform.stepCreateForm.creatingDataViewMessage": "正在创建 Kibana 数据视图......", @@ -40692,15 +40548,7 @@ "xpack.transform.stepDetailsForm.continuousModeDelayLabel": "延迟", "xpack.transform.stepDetailsForm.continuousModeError": "连续模式不可用于没有日期字段的索引。", "xpack.transform.stepDetailsForm.createIndexAPI": "创建索引 API", - "xpack.transform.stepDetailsForm.dataViewPermissionWarning": "您需要权限以创建数据视图。", - "xpack.transform.stepDetailsForm.dataViewTimeFieldHelpText": "选择用于全局时间筛选的主要时间字段。", - "xpack.transform.stepDetailsForm.dataViewTimeFieldLabel": "Kibana 数据视图的时间字段", - "xpack.transform.stepDetailsForm.dataViewTitleError": "具有此名称的数据视图已存在。", "xpack.transform.stepDetailsForm.destinationIndexHelpText": "已存在具有此名称的索引。请注意,运行此转换将会修改此目标索引。", - "xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel": "选择唯一目标索引名称。", - "xpack.transform.stepDetailsForm.destinationIndexInvalidError": "目标索引名称无效。", - "xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink": "详细了解索引名称限制。", - "xpack.transform.stepDetailsForm.destinationIndexLabel": "目标索引", "xpack.transform.stepDetailsForm.destinationIngestPipelineAriaLabel": "选择采集管道(可选)", "xpack.transform.stepDetailsForm.destinationIngestPipelineComboBoxPlaceholder": "选择采集管道(可选)", "xpack.transform.stepDetailsForm.destinationIngestPipelineLabel": "目标采集管道", @@ -40719,7 +40567,6 @@ "xpack.transform.stepDetailsForm.maxPageSearchSizeHelpText": "用于每个检查点的组合聚合的初始页面大小。", "xpack.transform.stepDetailsForm.maxPageSearchSizeLabel": "最大页面搜索大小", "xpack.transform.stepDetailsForm.missingBucketCheckboxHelpTextLink": "了解详情", - "xpack.transform.stepDetailsForm.noTimeFieldOptionLabel": "我不想使用时间字段选项", "xpack.transform.stepDetailsForm.numFailureRetriesAriaLabel": "选择最大重试次数。", "xpack.transform.stepDetailsForm.NumFailureRetriesError": "重试次数需要介于 0 和 100 之间,或为 -1(表示无限重试)。", "xpack.transform.stepDetailsForm.retentionPolicyDateFieldHelpText": "选择可用于从目标索引中识别出日期文档的日期字段。", @@ -43054,7 +42901,6 @@ "cloud.deploymentDetails.cloudIDLabel": "云 ID", "cloud.deploymentDetails.createManageApiKeysButtonLabel": "创建和管理 API 密钥", "cloud.deploymentDetails.elasticEndpointLabel": "Elastic 终端", - "cloud.deploymentDetails.helpMenuLinks.endpoints": "终端", "cloud.deploymentDetails.learnMoreButtonLabel": "了解详情", "cloud.deploymentDetails.modal.closeButtonLabel": "关闭", "cloud.deploymentDetails.modal.learnMoreButtonLabel": "了解详情", @@ -43293,10 +43139,10 @@ "randomSampling.ui.sliderControl.performanceLabel": "性能", "reporting.commonExportTypesHelpers.missingJobHeadersErrorMessage": "作业标头缺失", "reporting.commonExportTypesHelpers.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", - "reactPackages.mountPointPortal.errorMessage": "呈现门户内容时出错", "reporting.common.browserCouldNotLaunchErrorMessage": "无法生成屏幕截图,因为浏览器未启动。有关更多信息,请查看服务器日志。", "reporting.common.cloud.insufficientSystemMemoryError": "由于内存不足,无法生成此报告。", "reporting.common.pdfWorkerOutOfMemoryErrorMessage": "由于内存不足,无法生成 PDF。尝试生成更小的 PDF,然后重试此报告。", + "reactPackages.mountPointPortal.errorMessage": "呈现门户内容时出错", "savedObjectsFinder.advancedSettings.listingLimitText": "要为列表页面提取的对象数目", "savedObjectsFinder.advancedSettings.listingLimitTitle": "对象列表限制", "savedObjectsFinder.advancedSettings.perPageText": "加载对话框中每页要显示的对象数目", @@ -43492,7 +43338,6 @@ "unifiedDocViewer.sourceViewer.errorMessageTitle": "发生错误", "unifiedDocViewer.sourceViewer.refresh": "刷新", "utils.filename.pathWarning": "路径的格式可能不正确;请验证值", - "utils.filename.wildcardWarning": "在文件路径中使用通配符可能会影响终端性能", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.description": "在 Visualize 中启用仪表盘图表的旧版图表库。", "visTypeGauge.advancedSettings.visualization.legacyGaugeChartsLibrary.name": "仪表盘旧版图表库", "visTypeGauge.controls.gaugeOptions.alignmentLabel": "对齐方式", @@ -43645,7 +43490,6 @@ "xpack.cloudDataMigration.upgrade.text": "更轻松地升级到较新版本", "xpack.cloudLinks.deploymentLinkLabel": "管理此部署", "xpack.cloudLinks.helpMenuLinks.documentation": "文档", - "xpack.cloudLinks.helpMenuLinks.endpoints": "终端", "xpack.cloudLinks.helpMenuLinks.giveFeedback": "反馈", "xpack.cloudLinks.helpMenuLinks.support": "支持", "xpack.cloudLinks.setupGuide": "设置指南", @@ -43761,4 +43605,4 @@ "xpack.serverlessObservability.nav.projectSettings": "项目设置", "xpack.serverlessObservability.nav.visualizations": "可视化" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.ts deleted file mode 100644 index ef1bdee1d549..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AlertConsumers } from '@kbn/rule-data-utils'; -import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; -import { act, renderHook } from '@testing-library/react-hooks'; -import { useAlertDataView, UserAlertDataView } from './use_alert_data_view'; - -const mockUseKibanaReturnValue = createStartServicesMock(); - -jest.mock('@kbn/kibana-react-plugin/public', () => ({ - __esModule: true, - useKibana: jest.fn(() => ({ - services: mockUseKibanaReturnValue, - })), -})); - -describe('useAlertDataView', () => { - const observabilityAlertFeatureIds: ValidFeatureId[] = [ - AlertConsumers.APM, - AlertConsumers.INFRASTRUCTURE, - AlertConsumers.LOGS, - AlertConsumers.UPTIME, - ]; - - beforeEach(() => { - mockUseKibanaReturnValue.http.get = jest.fn().mockReturnValue({ - index_name: [ - '.alerts-observability.uptime.alerts-*', - '.alerts-observability.metrics.alerts-*', - '.alerts-observability.logs.alerts-*', - '.alerts-observability.apm.alerts-*', - ], - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('initially is loading and does not have data', async () => { - await act(async () => { - const mockedAsyncDataView = { - loading: true, - error: undefined, - }; - - const { result, waitForNextUpdate } = renderHook(() => - useAlertDataView(observabilityAlertFeatureIds) - ); - - await waitForNextUpdate(); - - expect(result.current).toEqual(mockedAsyncDataView); - }); - }); - - it('returns dataView for the provided featureIds', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useAlertDataView(observabilityAlertFeatureIds) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toMatchInlineSnapshot(` - Object { - "error": undefined, - "loading": false, - "value": Array [ - Object { - "fieldFormatMap": Object {}, - "fields": Array [], - "title": ".alerts-observability.uptime.alerts-*,.alerts-observability.metrics.alerts-*,.alerts-observability.logs.alerts-*,.alerts-observability.apm.alerts-*", - }, - ], - } - `); - }); - }); - - it('returns error with no data when error happens', async () => { - const error = new Error('http error'); - mockUseKibanaReturnValue.http.get = jest.fn().mockImplementation(async () => { - throw error; - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useAlertDataView(observabilityAlertFeatureIds) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toMatchInlineSnapshot(` - Object { - "error": [Error: http error], - "loading": false, - "value": undefined, - } - `); - }); - }); -}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.tsx new file mode 100644 index 000000000000..e37808a05d9b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.test.tsx @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AlertConsumers } from '@kbn/rule-data-utils'; +import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; +import type { ValidFeatureId } from '@kbn/rule-data-utils'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useAlertDataView } from './use_alert_data_view'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; + +const mockUseKibanaReturnValue = createStartServicesMock(); + +jest.mock('@kbn/kibana-react-plugin/public', () => ({ + __esModule: true, + useKibana: jest.fn(() => ({ + services: mockUseKibanaReturnValue, + })), +})); + +jest.mock('../lib/rule_api/alert_index', () => ({ + fetchAlertIndexNames: jest.fn(), +})); + +const { fetchAlertIndexNames } = jest.requireMock('../lib/rule_api/alert_index'); + +jest.mock('../lib/rule_api/alert_fields', () => ({ + fetchAlertFields: jest.fn(), +})); +const { fetchAlertFields } = jest.requireMock('../lib/rule_api/alert_fields'); + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + cacheTime: 0, + }, + }, +}); +const wrapper = ({ children }: { children: Node }) => ( + {children} +); + +describe('useAlertDataView', () => { + const observabilityAlertFeatureIds: ValidFeatureId[] = [ + AlertConsumers.APM, + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.LOGS, + AlertConsumers.UPTIME, + ]; + + beforeEach(() => { + fetchAlertIndexNames.mockResolvedValue([ + '.alerts-observability.uptime.alerts-*', + '.alerts-observability.metrics.alerts-*', + '.alerts-observability.logs.alerts-*', + '.alerts-observability.apm.alerts-*', + ]); + fetchAlertFields.mockResolvedValue([{ data: ' fields' }]); + }); + + afterEach(() => { + queryClient.clear(); + jest.clearAllMocks(); + }); + + it('initially is loading and does not have data', async () => { + await act(async () => { + const mockedAsyncDataView = { + loading: true, + dataview: undefined, + }; + + const { result, waitForNextUpdate } = renderHook( + () => useAlertDataView(observabilityAlertFeatureIds), + { + wrapper, + } + ); + + await waitForNextUpdate(); + + expect(result.current).toEqual(mockedAsyncDataView); + }); + }); + + it('fetch index names + fields for the provided o11y featureIds', async () => { + await act(async () => { + const { waitForNextUpdate } = renderHook( + () => useAlertDataView(observabilityAlertFeatureIds), + { + wrapper, + } + ); + + await waitForNextUpdate(); + await waitForNextUpdate(); + + expect(fetchAlertIndexNames).toHaveBeenCalledTimes(1); + expect(fetchAlertFields).toHaveBeenCalledTimes(1); + }); + }); + + it('only fetch index names for security featureId', async () => { + await act(async () => { + const { waitForNextUpdate } = renderHook(() => useAlertDataView([AlertConsumers.SIEM]), { + wrapper, + }); + + await waitForNextUpdate(); + await waitForNextUpdate(); + + expect(fetchAlertIndexNames).toHaveBeenCalledTimes(1); + expect(fetchAlertFields).toHaveBeenCalledTimes(0); + }); + }); + + it('Do not fetch anything if security and o11y featureIds are mix together', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook( + () => useAlertDataView([AlertConsumers.SIEM, AlertConsumers.LOGS]), + { + wrapper, + } + ); + + await waitForNextUpdate(); + + expect(fetchAlertIndexNames).toHaveBeenCalledTimes(0); + expect(fetchAlertFields).toHaveBeenCalledTimes(0); + expect(result.current).toEqual({ + loading: false, + dataview: undefined, + }); + }); + }); + + it('if fetch throw error return no data', async () => { + fetchAlertIndexNames.mockRejectedValue('error'); + + await act(async () => { + const { result, waitForNextUpdate } = renderHook( + () => useAlertDataView(observabilityAlertFeatureIds), + { + wrapper, + } + ); + + await waitForNextUpdate(); + await waitForNextUpdate(); + + expect(result.current).toEqual({ + loading: false, + dataview: undefined, + }); + }); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.ts index 15608192e7dd..7b72e5898d56 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_alert_data_view.ts @@ -5,72 +5,158 @@ * 2.0. */ -import { DataView, FieldSpec } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; +import { DataView } from '@kbn/data-views-plugin/common'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; -import useAsync from 'react-use/lib/useAsync'; -import { useMemo } from 'react'; +import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; +import { useEffect, useMemo, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { TriggersAndActionsUiServices } from '../..'; +import { fetchAlertIndexNames } from '../lib/rule_api/alert_index'; +import { fetchAlertFields } from '../lib/rule_api/alert_fields'; export interface UserAlertDataView { - value?: DataView[]; + dataviews?: DataView[]; loading: boolean; - error?: Error; } export function useAlertDataView(featureIds: ValidFeatureId[]): UserAlertDataView { - const { http } = useKibana().services; + const { + http, + data: dataService, + notifications: { toasts }, + } = useKibana().services; + const [dataviews, setDataviews] = useState(undefined); const features = featureIds.sort().join(','); + const isOnlySecurity = featureIds.length === 1 && featureIds.includes(AlertConsumers.SIEM); - const indexNames = useAsync(async () => { - const { index_name: indexNamesStr } = await http.get<{ index_name: string[] }>( - `${BASE_RAC_ALERTS_API_PATH}/index`, - { - query: { features }, - } - ); + const hasSecurityAndO11yFeatureIds = + featureIds.length > 1 && featureIds.includes(AlertConsumers.SIEM); - return indexNamesStr; - }, [features]); + const hasNoSecuritySolution = + featureIds.length > 0 && !isOnlySecurity && !hasSecurityAndO11yFeatureIds; - const fields = useAsync(async () => { - const { fields: alertFields } = await http.get<{ fields: FieldSpec[] }>( - `${BASE_RAC_ALERTS_API_PATH}/browser_fields`, - { - query: { featureIds }, - } - ); - return alertFields; - }, [features]); + const queryIndexNameFn = () => { + return fetchAlertIndexNames({ http, features }); + }; - const dataview = useMemo( - () => - !fields.loading && - !indexNames.loading && - fields.error === undefined && - indexNames.error === undefined - ? ([ - { - title: (indexNames.value ?? []).join(','), - fieldFormatMap: {}, - fields: (fields.value ?? [])?.map((field) => { - return { - ...field, - ...(field.esTypes && field.esTypes.includes('flattened') - ? { type: 'string' } - : {}), - }; - }), - }, - ] as unknown as DataView[]) - : undefined, - [fields, indexNames] - ); + const queryAlertFieldsFn = () => { + return fetchAlertFields({ http, featureIds }); + }; - return { - value: dataview, - loading: fields.loading || indexNames.loading, - error: fields.error ? fields.error : indexNames.error, + const onErrorFn = () => { + toasts.addDanger( + i18n.translate('xpack.triggersActionsUI.useAlertDataView.useAlertDataMessage', { + defaultMessage: 'Unable to load alert data view', + }) + ); }; + + const { + data: indexNames, + isSuccess: isIndexNameSuccess, + isInitialLoading: isIndexNameInitialLoading, + isLoading: isIndexNameLoading, + } = useQuery({ + queryKey: ['loadAlertIndexNames', features], + queryFn: queryIndexNameFn, + onError: onErrorFn, + refetchOnWindowFocus: false, + enabled: featureIds.length > 0 && !hasSecurityAndO11yFeatureIds, + }); + + const { + data: alertFields, + isSuccess: isAlertFieldsSuccess, + isInitialLoading: isAlertFieldsInitialLoading, + isLoading: isAlertFieldsLoading, + } = useQuery({ + queryKey: ['loadAlertFields', features], + queryFn: queryAlertFieldsFn, + onError: onErrorFn, + refetchOnWindowFocus: false, + enabled: hasNoSecuritySolution, + }); + + useEffect(() => { + return () => { + dataviews?.map((dv) => { + dataService.dataViews.clearInstanceCache(dv.id); + }); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dataviews]); + + // FUTURE ENGINEER this useEffect is for security solution user since + // we are using the user privilege to access the security alert index + useEffect(() => { + async function createDataView() { + const localDataview = await dataService.dataViews.create({ + title: (indexNames ?? []).join(','), + allowNoIndex: true, + }); + setDataviews([localDataview]); + } + + if (isOnlySecurity && isIndexNameSuccess) { + createDataView(); + } + }, [dataService.dataViews, indexNames, isIndexNameSuccess, isOnlySecurity]); + + // FUTURE ENGINEER this useEffect is for o11y and stack solution user since + // we are using the kibana user privilege to access the alert index + useEffect(() => { + if ( + indexNames && + alertFields && + !isOnlySecurity && + isAlertFieldsSuccess && + isIndexNameSuccess + ) { + setDataviews([ + { + title: (indexNames ?? []).join(','), + fieldFormatMap: {}, + fields: (alertFields ?? [])?.map((field) => { + return { + ...field, + ...(field.esTypes && field.esTypes.includes('flattened') ? { type: 'string' } : {}), + }; + }), + }, + ] as unknown as DataView[]); + } + }, [ + alertFields, + dataService.dataViews, + indexNames, + isIndexNameSuccess, + isOnlySecurity, + isAlertFieldsSuccess, + ]); + + return useMemo( + () => ({ + dataviews, + loading: + featureIds.length === 0 || hasSecurityAndO11yFeatureIds + ? false + : isOnlySecurity + ? isIndexNameInitialLoading || isIndexNameLoading + : isIndexNameInitialLoading || + isIndexNameLoading || + isAlertFieldsInitialLoading || + isAlertFieldsLoading, + }), + [ + dataviews, + featureIds.length, + hasSecurityAndO11yFeatureIds, + isOnlySecurity, + isIndexNameInitialLoading, + isIndexNameLoading, + isAlertFieldsInitialLoading, + isAlertFieldsLoading, + ] + ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types_query.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types_query.ts index 4892341e5738..ab11bb4f1845 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types_query.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types_query.ts @@ -13,6 +13,7 @@ import { RuleType, RuleTypeIndex } from '../../types'; interface UseLoadRuleTypesQueryProps { filteredRuleTypes: string[]; + enabled?: boolean; } const getFilteredIndex = (data: Array>, filteredRuleTypes: string[]) => { @@ -32,7 +33,7 @@ const getFilteredIndex = (data: Array>, filteredRuleTyp }; export const useLoadRuleTypesQuery = (props: UseLoadRuleTypesQueryProps) => { - const { filteredRuleTypes } = props; + const { filteredRuleTypes, enabled = true } = props; const { http, notifications: { toasts }, @@ -55,6 +56,7 @@ export const useLoadRuleTypesQuery = (props: UseLoadRuleTypesQueryProps) => { queryFn, onError: onErrorFn, refetchOnWindowFocus: false, + enabled, }); const filteredIndex = data ? getFilteredIndex(data, filteredRuleTypes) : new Map(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts index 7fa2e3f0dfd0..1ad710691011 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts @@ -8,21 +8,67 @@ import { DataViewField } from '@kbn/data-views-plugin/common'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import useAsync from 'react-use/lib/useAsync'; -import type { AsyncState } from 'react-use/lib/useAsync'; +import { HttpSetup } from '@kbn/core/public'; +import { useQuery } from '@tanstack/react-query'; +import { i18n } from '@kbn/i18n'; +import { useMemo } from 'react'; import { TriggersAndActionsUiServices } from '../..'; -export function useRuleAADFields(ruleTypeId?: string): AsyncState { - const { http } = useKibana().services; +const EMPTY_AAD_FIELDS: DataViewField[] = []; - const aadFields = useAsync(async () => { - if (!ruleTypeId) return []; - const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { - query: { ruleTypeId }, - }); +async function fetchAadFields({ + http, + ruleTypeId, +}: { + http: HttpSetup; + ruleTypeId?: string; +}): Promise { + if (!ruleTypeId) return EMPTY_AAD_FIELDS; + const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { + query: { ruleTypeId }, + }); + + return fields; +} + +export function useRuleAADFields(ruleTypeId?: string): { + aadFields: DataViewField[]; + loading: boolean; +} { + const { + http, + notifications: { toasts }, + } = useKibana().services; + + const queryAadFieldsFn = () => { + return fetchAadFields({ http, ruleTypeId }); + }; + + const onErrorFn = () => { + toasts.addDanger( + i18n.translate('xpack.triggersActionsUI.useRuleAADFields.errorMessage', { + defaultMessage: 'Unable to load alert fields per rule type', + }) + ); + }; - return fields; + const { + data: aadFields = EMPTY_AAD_FIELDS, + isInitialLoading, + isLoading, + } = useQuery({ + queryKey: ['loadAlertAadFieldsPerRuleType', ruleTypeId], + queryFn: queryAadFieldsFn, + onError: onErrorFn, + refetchOnWindowFocus: false, + enabled: ruleTypeId !== undefined, }); - return aadFields; + return useMemo( + () => ({ + aadFields, + loading: ruleTypeId === undefined ? false : isInitialLoading || isLoading, + }), + [aadFields, isInitialLoading, isLoading, ruleTypeId] + ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts new file mode 100644 index 000000000000..7be5b3eec0e6 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ValidFeatureId } from '@kbn/rule-data-utils'; +import { HttpSetup } from '@kbn/core/public'; +import { FieldSpec } from '@kbn/data-views-plugin/common'; +import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; + +export async function fetchAlertFields({ + http, + featureIds, +}: { + http: HttpSetup; + featureIds: ValidFeatureId[]; +}): Promise { + const { fields: alertFields = [] } = await http.get<{ fields: FieldSpec[] }>( + `${BASE_RAC_ALERTS_API_PATH}/browser_fields`, + { + query: { featureIds }, + } + ); + return alertFields; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.ts new file mode 100644 index 000000000000..8ac678664168 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; +import { HttpSetup } from '@kbn/core/public'; + +export async function fetchAlertIndexNames({ + http, + features, +}: { + http: HttpSetup; + features: string; +}): Promise { + const { index_name: indexNamesStr = [] } = await http.get<{ index_name: string[] }>( + `${BASE_RAC_ALERTS_API_PATH}/index`, + { + query: { features }, + } + ); + return indexNamesStr; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/clone.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/clone.test.ts index cc9b1ddab021..54e987d18c91 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/clone.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/clone.test.ts @@ -75,7 +75,6 @@ describe('cloneRule', () => { "level": "info", "message": "alert ", }, - "useAlertDataForTemplate": undefined, "uuid": "123456", }, ], diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts index da0cd8419e07..64949d9014c5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts @@ -22,7 +22,7 @@ const transformAction: RewriteRequestCase = ({ id, params, actionTypeId, - useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' ? { useAlertDataForTemplate } : {}), ...(frequency ? { frequency: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts index a2ab9c5b4dc3..2304ee8c4893 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/create.ts @@ -38,7 +38,9 @@ const rewriteBodyRequest: RewriteResponseCase = ({ summary: frequency!.summary, }, alerts_filter: alertsFilter, - use_alert_data_for_template: useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' + ? { use_alert_data_for_template: useAlertDataForTemplate } + : {}), }) ), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts index 0d6371cfa1fd..52158bfa2f03 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/update.ts @@ -28,7 +28,9 @@ const rewriteBodyRequest: RewriteResponseCase = ({ actions, ... summary: frequency!.summary, }, alerts_filter: alertsFilter, - use_alert_data_for_template: useAlertDataForTemplate, + ...(typeof useAlertDataForTemplate !== 'undefined' + ? { use_alert_data_for_template: useAlertDataForTemplate } + : {}), ...(uuid && { uuid }), }) ), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index 83ad089c8e69..dfe48ef86612 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -8,7 +8,7 @@ import React, { Suspense, useEffect, useState, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ValidFeatureId, AlertConsumers } from '@kbn/rule-data-utils'; +import { ValidFeatureId } from '@kbn/rule-data-utils'; import { EuiFlexGroup, EuiFlexItem, @@ -428,8 +428,7 @@ export const ActionTypeForm = ({ setActionGroupIdByIndex && !actionItem.frequency?.summary; - const showActionAlertsFilter = - hasFieldsForAAD || producerId === AlertConsumers.SIEM || hasAlertsMappings; + const showActionAlertsFilter = hasFieldsForAAD; const accordionContent = checkEnabledResult.isEnabled ? ( <> @@ -550,6 +549,7 @@ export const ActionTypeForm = ({ actionParams={actionItem.params as any} errors={actionParamsErrors.errors} index={index} + selectedActionGroupId={selectedActionGroup?.id} editAction={(key: string, value: RuleActionParam, i: number) => { setWarning( validateParamsForWarnings( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx index 077be38b5616..10e2a8493d71 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx @@ -9,12 +9,14 @@ import React, { useCallback, useState } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { Query, TimeRange } from '@kbn/es-query'; import { SuggestionsAbstraction } from '@kbn/unified-search-plugin/public/typeahead/suggestions_component'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { NO_INDEX_PATTERNS } from './constants'; import { SEARCH_BAR_PLACEHOLDER } from './translations'; import { AlertsSearchBarProps, QueryLanguageType } from './types'; import { useAlertDataView } from '../../hooks/use_alert_data_view'; import { TriggersAndActionsUiServices } from '../../..'; import { useRuleAADFields } from '../../hooks/use_rule_aad_fields'; +import { useLoadRuleTypesQuery } from '../../hooks/use_load_rule_types_query'; const SA_ALERTS = { type: 'alerts', fields: {} } as SuggestionsAbstraction; @@ -44,15 +46,22 @@ export function AlertsSearchBar({ } = useKibana().services; const [queryLanguage, setQueryLanguage] = useState('kuery'); - const { value: dataView, loading, error } = useAlertDataView(featureIds); - const { - value: aadFields, - loading: fieldsLoading, - error: fieldsError, - } = useRuleAADFields(ruleTypeId); + const { dataviews, loading } = useAlertDataView(featureIds ?? []); + const { aadFields, loading: fieldsLoading } = useRuleAADFields(ruleTypeId); const indexPatterns = - ruleTypeId && aadFields?.length ? [{ title: ruleTypeId, fields: aadFields }] : dataView; + ruleTypeId && aadFields?.length ? [{ title: ruleTypeId, fields: aadFields }] : dataviews; + + const ruleType = useLoadRuleTypesQuery({ + filteredRuleTypes: ruleTypeId !== undefined ? [ruleTypeId] : [], + enabled: ruleTypeId !== undefined, + }); + + const isSecurity = + (featureIds && featureIds.length === 1 && featureIds.includes(AlertConsumers.SIEM)) || + (ruleType && + ruleTypeId && + ruleType.ruleTypesState.data.get(ruleTypeId)?.producer === AlertConsumers.SIEM); const onSearchQuerySubmit = useCallback( ({ dateRange, query: nextQuery }: { dateRange: TimeRange; query?: Query }) => { @@ -86,9 +95,7 @@ export function AlertsSearchBar({ appName={appName} disableQueryLanguageSwitcher={disableQueryLanguageSwitcher} // @ts-expect-error - DataView fields prop and SearchBar indexPatterns props are overly broad - indexPatterns={ - loading || error || fieldsLoading || fieldsError ? NO_INDEX_PATTERNS : indexPatterns - } + indexPatterns={loading || fieldsLoading ? NO_INDEX_PATTERNS : indexPatterns} placeholder={placeholder} query={{ query: query ?? '', language: queryLanguage }} filters={filters} @@ -105,7 +112,7 @@ export function AlertsSearchBar({ showSubmitButton={showSubmitButton} submitOnBlur={submitOnBlur} onQueryChange={onSearchQueryChange} - suggestionsAbstraction={SA_ALERTS} + suggestionsAbstraction={isSecurity ? undefined : SA_ALERTS} /> ); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx index 2c98853b3c4e..4d46f8b4741c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx @@ -159,6 +159,11 @@ const AlertsTable: React.FunctionComponent = (props: AlertsTab options: props.alertsTableConfiguration.useActionsColumn, }); + const renderCellContext = props.alertsTableConfiguration.useFetchPageContext?.({ + alerts, + columns: props.columns, + }); + const { isBulkActionsColumnActive, getBulkActionsLeadingControlColumn, @@ -373,9 +378,10 @@ const AlertsTable: React.FunctionComponent = (props: AlertsTab props.alertsTableConfiguration?.getRenderCellValue ? props.alertsTableConfiguration?.getRenderCellValue({ setFlyoutAlert: handleFlyoutAlert, + context: renderCellContext, }) : basicRenderCellValue, - [handleFlyoutAlert, props.alertsTableConfiguration] + [handleFlyoutAlert, props.alertsTableConfiguration, renderCellContext] )(); const handleRenderCellValue = useCallback( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/bulk_actions.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/bulk_actions.test.tsx index 71bd02d60126..7ba49502a38e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/bulk_actions.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/bulk_actions.test.tsx @@ -392,6 +392,10 @@ describe('AlertsTable.BulkActions', () => { field: 'kibana.alert.workflow_tags', value: [], }, + { + field: 'kibana.alert.workflow_assignee_ids', + value: [], + }, ], ecs: { _id: 'alert0', @@ -639,6 +643,10 @@ describe('AlertsTable.BulkActions', () => { field: 'kibana.alert.workflow_tags', value: [], }, + { + field: 'kibana.alert.workflow_assignee_ids', + value: [], + }, ], ecs: { _id: 'alert1', @@ -867,6 +875,10 @@ describe('AlertsTable.BulkActions', () => { field: 'kibana.alert.workflow_tags', value: [], }, + { + field: 'kibana.alert.workflow_assignee_ids', + value: [], + }, ], ecs: { _id: 'alert0', @@ -893,6 +905,10 @@ describe('AlertsTable.BulkActions', () => { field: 'kibana.alert.workflow_tags', value: [], }, + { + field: 'kibana.alert.workflow_assignee_ids', + value: [], + }, ], ecs: { _id: 'alert1', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/components/toolbar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/components/toolbar.tsx index f75dbc43c1fe..ef3ba30e1208 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/components/toolbar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/bulk_actions/components/toolbar.tsx @@ -13,6 +13,7 @@ import { ALERT_CASE_IDS, ALERT_RULE_NAME, ALERT_RULE_UUID, + ALERT_WORKFLOW_ASSIGNEE_IDS, ALERT_WORKFLOW_TAGS, } from '@kbn/rule-data-utils'; import { @@ -64,6 +65,7 @@ const selectedIdsToTimelineItemMapper = ( { field: ALERT_RULE_UUID, value: alert[ALERT_RULE_UUID] }, { field: ALERT_CASE_IDS, value: alert[ALERT_CASE_IDS] ?? [] }, { field: ALERT_WORKFLOW_TAGS, value: alert[ALERT_WORKFLOW_TAGS] ?? [] }, + { field: ALERT_WORKFLOW_ASSIGNEE_IDS, value: alert[ALERT_WORKFLOW_ASSIGNEE_IDS] ?? [] }, ], ecs: { _id: alert._id, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx index de2eb91b74c8..aab0b5891fc7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.tsx @@ -305,6 +305,7 @@ const RuleAdd = ({ hideGrouping={hideGrouping} hideInterval={hideInterval} onChangeMetaData={onChangeMetaData} + selectedConsumer={selectedConsumer} setConsumer={setSelectedConsumer} useRuleProducer={useRuleProducer} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx index 59d3c4f1f8c3..f528ce4b45aa 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx @@ -262,6 +262,7 @@ describe('rule_form', () => { ruleTypesOverwrite?: RuleType[]; ruleTypeModelOverwrite?: RuleTypeModel; useRuleProducer?: boolean; + selectedConsumer?: RuleCreationValidConsumer | null; }) { const { showRulesList = false, @@ -273,6 +274,7 @@ describe('rule_form', () => { ruleTypesOverwrite, ruleTypeModelOverwrite, useRuleProducer = false, + selectedConsumer, } = options || {}; const mocks = coreMock.createSetup(); @@ -325,7 +327,11 @@ describe('rule_form', () => { enabledInLicense: false, }, ]; - useLoadRuleTypes.mockReturnValue({ ruleTypes }); + const ruleTypeIndex = ruleTypes.reduce((acc, item) => { + acc.set(item.id, item); + return acc; + }, new Map()); + useLoadRuleTypes.mockReturnValue({ ruleTypes, ruleTypeIndex }); const [ { application: { capabilities }, @@ -377,7 +383,7 @@ describe('rule_form', () => { minimumScheduleInterval: { value: '1m', enforce: enforceMinimum }, }} dispatch={() => {}} - errors={{ name: [], 'schedule.interval': [], ruleTypeId: [] }} + errors={{ name: [], 'schedule.interval': [], ruleTypeId: [], actionConnectors: [] }} operation="create" actionTypeRegistry={actionTypeRegistry} ruleTypeRegistry={ruleTypeRegistry} @@ -386,6 +392,7 @@ describe('rule_form', () => { validConsumers={validConsumers} setConsumer={mockSetConsumer} useRuleProducer={useRuleProducer} + selectedConsumer={selectedConsumer} /> ); @@ -666,6 +673,361 @@ describe('rule_form', () => { expect(wrapper.find('[data-test-subj="ruleFormConsumerSelect"]').exists()).toBeFalsy(); }); + + it('Do not show alert query in action when multi consumer rule type does not have a consumer selected', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'alerts', + ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: true, + hasAlertsMappings: true, + }, + ], + ruleTypeModelOverwrite: { + id: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(false); + }); + + it('Do not show alert query in action when we do not have hasFieldsForAAD or hasAlertsMappings or belong to security', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'alerts', + ruleTypeId: 'my-rule-type', + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: 'my-rule-type', + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: false, + hasAlertsMappings: false, + }, + ], + ruleTypeModelOverwrite: { + id: 'my-rule-type', + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(false); + }); + + it('Show alert query in action when rule type hasFieldsForAAD', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'alerts', + ruleTypeId: 'my-rule-type', + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: 'my-rule-type', + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: true, + hasAlertsMappings: false, + }, + ], + ruleTypeModelOverwrite: { + id: 'my-rule-type', + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(true); + }); + + it('Show alert query in action when rule type hasAlertsMappings', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'alerts', + ruleTypeId: 'my-rule-type', + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: 'my-rule-type', + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: false, + hasAlertsMappings: true, + }, + ], + ruleTypeModelOverwrite: { + id: 'my-rule-type', + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(true); + }); + + it('Show alert query in action when rule type is from security solution', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'siem', + ruleTypeId: 'my-rule-type', + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: 'my-rule-type', + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: 'siem', + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: false, + hasAlertsMappings: false, + }, + ], + ruleTypeModelOverwrite: { + id: 'my-rule-type', + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(true); + }); + + it('show alert query in action when multi consumer rule type does not have a consumer selected', async () => { + await setup({ + initialRuleOverwrite: { + name: 'Simple rule', + consumer: 'alerts', + ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + schedule: { + interval: '1h', + }, + }, + ruleTypesOverwrite: [ + { + id: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + name: 'Threshold Rule', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + enabledInLicense: true, + defaultActionGroupId: 'threshold.fired', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + infrastructure: { read: true, all: true }, + logs: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + hasFieldsForAAD: true, + hasAlertsMappings: true, + }, + ], + ruleTypeModelOverwrite: { + id: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + iconClass: 'test', + description: 'test', + documentationUrl: null, + validate: (): ValidationResult => { + return { errors: {} }; + }, + ruleParamsExpression: TestExpression, + requiresAppContext: false, + }, + selectedConsumer: 'logs', + }); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(ActionForm).props().hasFieldsForAAD).toEqual(true); + }); }); describe('rule_form create rule non ruleing consumer and producer', () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index c321ba5a01d7..84552c2ba8e4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -153,6 +153,7 @@ interface RuleFormProps> { hideGrouping?: boolean; hideInterval?: boolean; connectorFeatureId?: string; + selectedConsumer?: RuleCreationValidConsumer | null; validConsumers?: RuleCreationValidConsumer[]; onChangeMetaData: (metadata: MetaData) => void; useRuleProducer?: boolean; @@ -176,6 +177,7 @@ export const RuleForm = ({ hideGrouping = false, hideInterval, connectorFeatureId = AlertingConnectorFeatureId, + selectedConsumer, validConsumers, onChangeMetaData, useRuleProducer, @@ -643,6 +645,23 @@ export const RuleForm = ({ } }; + const hasFieldsForAAD = useMemo(() => { + const hasAlertHasData = selectedRuleType + ? selectedRuleType.hasFieldsForAAD || + selectedRuleType.producer === AlertConsumers.SIEM || + selectedRuleType.hasAlertsMappings + : false; + + if (MULTI_CONSUMER_RULE_TYPE_IDS.includes(rule?.ruleTypeId ?? '')) { + return ( + (validConsumers || VALID_CONSUMERS).includes( + selectedConsumer as RuleCreationValidConsumer + ) && hasAlertHasData + ); + } + return hasAlertHasData; + }, [rule?.ruleTypeId, selectedConsumer, selectedRuleType, validConsumers]); + const ruleTypeDetails = ( <> @@ -820,8 +839,12 @@ export const RuleForm = ({ defaultActionGroupId={defaultActionGroupId} hasAlertsMappings={selectedRuleType.hasAlertsMappings} featureId={connectorFeatureId} - producerId={selectedRuleType.producer} - hasFieldsForAAD={selectedRuleType.hasFieldsForAAD} + producerId={ + MULTI_CONSUMER_RULE_TYPE_IDS.includes(rule.ruleTypeId) + ? selectedConsumer ?? rule.consumer + : selectedRuleType.producer + } + hasFieldsForAAD={hasFieldsForAAD} ruleTypeId={rule.ruleTypeId} isActionGroupDisabledForActionType={(actionGroupId: string, actionTypeId: string) => isActionGroupDisabledForActionType(selectedRuleType, actionGroupId, actionTypeId) @@ -897,8 +920,16 @@ export const RuleForm = ({ + + + } > = lazy( () => import('../application/sections/alerts_search_bar/alerts_search_bar') ); +const queryClient = new QueryClient(); + export const getAlertsSearchBarLazy = (props: AlertsSearchBarProps) => ( }> - + + + ); diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index bc0ce10d461e..4b04e2095461 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -224,6 +224,7 @@ export interface ActionParamsProps { actionConnector?: ActionConnector; isLoading?: boolean; isDisabled?: boolean; + selectedActionGroupId?: string; showEmailSubjectAndMessage?: boolean; executionMode?: ActionConnectorMode; onBlur?: (field?: string) => void; @@ -575,12 +576,22 @@ export type AlertsTableProps = { } & Partial>; // TODO We need to create generic type between our plugin, right now we have different one because of the old alerts table -export type GetRenderCellValue = ({ +export type GetRenderCellValue = ({ setFlyoutAlert, + context, }: { setFlyoutAlert?: (data: unknown) => void; + context?: T; }) => (props: unknown) => React.ReactNode; +export type PreFetchPageContext = ({ + alerts, + columns, +}: { + alerts: Alerts; + columns: EuiDataGridColumn[]; +}) => T; + export type AlertTableFlyoutComponent = | React.FunctionComponent | React.LazyExoticComponent> @@ -699,6 +710,7 @@ export interface AlertsTableConfigurationRegistry { }; useFieldBrowserOptions?: UseFieldBrowserOptions; showInspectButton?: boolean; + useFetchPageContext?: PreFetchPageContext; } export interface AlertsTableConfigurationRegistryWithActions diff --git a/x-pack/plugins/ux/public/components/app/rum_dashboard/ux_overview_fetchers.ts b/x-pack/plugins/ux/public/components/app/rum_dashboard/ux_overview_fetchers.ts index 4df3c8c1e847..46ab3ddff252 100644 --- a/x-pack/plugins/ux/public/components/app/rum_dashboard/ux_overview_fetchers.ts +++ b/x-pack/plugins/ux/public/components/app/rum_dashboard/ux_overview_fetchers.ts @@ -39,7 +39,7 @@ async function getCoreWebVitalsResponse({ dataStartPlugin, }: WithDataPlugin) { const dataViewResponse = await callApmApi( - 'GET /internal/apm/data_view/title', + 'GET /internal/apm/data_view/index_pattern', { signal: null, } @@ -47,7 +47,7 @@ async function getCoreWebVitalsResponse({ return await esQuery>(dataStartPlugin, { params: { - index: dataViewResponse.apmDataViewTitle, + index: dataViewResponse.apmDataViewIndexPattern, ...coreWebVitalsQuery(absoluteTime.start, absoluteTime.end, undefined, { serviceName: serviceName ? [serviceName] : undefined, }), @@ -83,7 +83,7 @@ export async function hasRumData( params: WithDataPlugin ): Promise { const dataViewResponse = await callApmApi( - 'GET /internal/apm/data_view/title', + 'GET /internal/apm/data_view/index_pattern', { signal: null, } @@ -93,7 +93,7 @@ export async function hasRumData( params.dataStartPlugin, { params: { - index: dataViewResponse.apmDataViewTitle, + index: dataViewResponse.apmDataViewIndexPattern, ...hasRumDataQuery({ start: params?.absoluteTime?.start, end: params?.absoluteTime?.end, @@ -102,7 +102,10 @@ export async function hasRumData( } ); - return formatHasRumResult(esQueryResponse, dataViewResponse.apmDataViewTitle); + return formatHasRumResult( + esQueryResponse, + dataViewResponse.apmDataViewIndexPattern + ); } async function esQuery( diff --git a/x-pack/plugins/ux/public/hooks/use_dynamic_data_view.ts b/x-pack/plugins/ux/public/hooks/use_dynamic_data_view.ts index 81fb2f966966..d051e07d0057 100644 --- a/x-pack/plugins/ux/public/hooks/use_dynamic_data_view.ts +++ b/x-pack/plugins/ux/public/hooks/use_dynamic_data_view.ts @@ -9,13 +9,13 @@ import { useFetcher } from './use_fetcher'; export function useDynamicDataViewTitle() { const { data, status } = useFetcher((callApmApi) => { - return callApmApi('GET /internal/apm/data_view/title', { + return callApmApi('GET /internal/apm/data_view/index_pattern', { isCachable: true, }); }, []); return { - dataViewTitle: data?.apmDataViewTitle, + dataViewTitle: data?.apmDataViewIndexPattern, status, }; } diff --git a/x-pack/test/accessibility/apps/grok_debugger.ts b/x-pack/test/accessibility/apps/grok_debugger.ts deleted file mode 100644 index 8ee9114c7da0..000000000000 --- a/x-pack/test/accessibility/apps/grok_debugger.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['common', 'security']); - const a11y = getService('a11y'); - const grokDebugger = getService('grokDebugger'); - - // Fixes:https://github.com/elastic/kibana/issues/62102 - describe('Dev tools grok debugger', () => { - before(async () => { - await PageObjects.common.navigateToApp('grokDebugger'); - await grokDebugger.assertExists(); - }); - - it('Dev tools grok debugger set input', async () => { - await grokDebugger.setEventInput('SegerCommaBob'); - await a11y.testAppSnapshot(); - }); - - it('Dev tools grok debugger set pattern', async () => { - await grokDebugger.setPatternInput('%{USERNAME:u}'); - await a11y.testAppSnapshot(); - }); - - it('Dev tools grok debugger simulate', async () => { - await grokDebugger.clickSimulate(); - await a11y.testAppSnapshot(); - }); - }); -} diff --git a/x-pack/test/accessibility/apps/advanced_settings.ts b/x-pack/test/accessibility/apps/group1/advanced_settings.ts similarity index 97% rename from x-pack/test/accessibility/apps/advanced_settings.ts rename to x-pack/test/accessibility/apps/group1/advanced_settings.ts index 6c931f0a0e5a..44899932302b 100644 --- a/x-pack/test/accessibility/apps/advanced_settings.ts +++ b/x-pack/test/accessibility/apps/group1/advanced_settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header']); diff --git a/x-pack/test/accessibility/apps/group1/config.ts b/x-pack/test/accessibility/apps/group1/config.ts new file mode 100644 index 000000000000..8e5510141abf --- /dev/null +++ b/x-pack/test/accessibility/apps/group1/config.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from '../../services'; +import { pageObjects } from '../../page_objects'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../functional/config.base.js') + ); + + return { + ...functionalConfig.getAll(), + + testFiles: [require.resolve('.')], + + pageObjects, + services, + + junit: { + reportName: 'X-Pack Accessibility Tests - Group 1', + }, + }; +} diff --git a/x-pack/test/accessibility/apps/dashboard_controls.ts b/x-pack/test/accessibility/apps/group1/dashboard_controls.ts similarity index 98% rename from x-pack/test/accessibility/apps/dashboard_controls.ts rename to x-pack/test/accessibility/apps/group1/dashboard_controls.ts index 74f7288ccce9..dd45b6867434 100644 --- a/x-pack/test/accessibility/apps/dashboard_controls.ts +++ b/x-pack/test/accessibility/apps/group1/dashboard_controls.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/dashboard_panel_options.ts b/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts similarity index 97% rename from x-pack/test/accessibility/apps/dashboard_panel_options.ts rename to x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts index 4e4dc3b218d7..5f12f3600c29 100644 --- a/x-pack/test/accessibility/apps/dashboard_panel_options.ts +++ b/x-pack/test/accessibility/apps/group1/dashboard_panel_options.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; -import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import type { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/group1/grok_debugger.ts b/x-pack/test/accessibility/apps/group1/grok_debugger.ts new file mode 100644 index 000000000000..da630c6bed7b --- /dev/null +++ b/x-pack/test/accessibility/apps/group1/grok_debugger.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'security']); + const a11y = getService('a11y'); + const grokDebugger = getService('grokDebugger'); + + // Fixes:https://github.com/elastic/kibana/issues/62102 + describe('Dev tools grok debugger', () => { + before(async () => { + await PageObjects.common.navigateToApp('grokDebugger'); + await grokDebugger.assertExists(); + }); + + it('Dev tools grok debugger set input', async () => { + await grokDebugger.setEventInput('SegerCommaBob'); + await a11y.testAppSnapshot(); + }); + + it('Dev tools grok debugger set pattern', async () => { + await grokDebugger.setPatternInput('%{USERNAME:u}'); + await a11y.testAppSnapshot(); + }); + + it('Dev tools grok debugger simulate', async () => { + await grokDebugger.clickSimulate(); + await a11y.testAppSnapshot(); + }); + }); +} diff --git a/x-pack/test/accessibility/apps/helpers.ts b/x-pack/test/accessibility/apps/group1/helpers.ts similarity index 100% rename from x-pack/test/accessibility/apps/helpers.ts rename to x-pack/test/accessibility/apps/group1/helpers.ts diff --git a/x-pack/test/accessibility/apps/home.ts b/x-pack/test/accessibility/apps/group1/home.ts similarity index 97% rename from x-pack/test/accessibility/apps/home.ts rename to x-pack/test/accessibility/apps/group1/home.ts index 544a32843f7f..800312bb4de5 100644 --- a/x-pack/test/accessibility/apps/home.ts +++ b/x-pack/test/accessibility/apps/group1/home.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const { common, home } = getPageObjects(['common', 'home']); diff --git a/x-pack/test/accessibility/apps/group1/index.ts b/x-pack/test/accessibility/apps/group1/index.ts new file mode 100644 index 000000000000..d8cd2e76c42d --- /dev/null +++ b/x-pack/test/accessibility/apps/group1/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('X-Pack Accessibility Tests - Group 1', function () { + loadTestFile(require.resolve('./login_page')); + loadTestFile(require.resolve('./kibana_overview')); + loadTestFile(require.resolve('./home')); + loadTestFile(require.resolve('./management')); + loadTestFile(require.resolve('./grok_debugger')); + loadTestFile(require.resolve('./search_profiler')); + loadTestFile(require.resolve('./painless_lab')); + loadTestFile(require.resolve('./uptime')); + loadTestFile(require.resolve('./spaces')); + loadTestFile(require.resolve('./advanced_settings')); + loadTestFile(require.resolve('./dashboard_panel_options')); + loadTestFile(require.resolve('./dashboard_controls')); + loadTestFile(require.resolve('./users')); + loadTestFile(require.resolve('./roles')); + loadTestFile(require.resolve('./ingest_node_pipelines')); + loadTestFile(require.resolve('./index_lifecycle_management')); + }); +}; diff --git a/x-pack/test/accessibility/apps/index_lifecycle_management.ts b/x-pack/test/accessibility/apps/group1/index_lifecycle_management.ts similarity index 98% rename from x-pack/test/accessibility/apps/index_lifecycle_management.ts rename to x-pack/test/accessibility/apps/group1/index_lifecycle_management.ts index fc3ec1ff5cf8..b994c4193e49 100644 --- a/x-pack/test/accessibility/apps/index_lifecycle_management.ts +++ b/x-pack/test/accessibility/apps/group1/index_lifecycle_management.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; const REPO_NAME = 'test'; const POLICY_NAME = 'ilm-a11y-test'; diff --git a/x-pack/test/accessibility/apps/ingest_node_pipelines.ts b/x-pack/test/accessibility/apps/group1/ingest_node_pipelines.ts similarity index 100% rename from x-pack/test/accessibility/apps/ingest_node_pipelines.ts rename to x-pack/test/accessibility/apps/group1/ingest_node_pipelines.ts diff --git a/x-pack/test/accessibility/apps/kibana_overview.ts b/x-pack/test/accessibility/apps/group1/kibana_overview.ts similarity index 93% rename from x-pack/test/accessibility/apps/kibana_overview.ts rename to x-pack/test/accessibility/apps/group1/kibana_overview.ts index 373044c4bffc..fe1bc55cd4c0 100644 --- a/x-pack/test/accessibility/apps/kibana_overview.ts +++ b/x-pack/test/accessibility/apps/group1/kibana_overview.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'home']); diff --git a/x-pack/test/accessibility/apps/login_page.ts b/x-pack/test/accessibility/apps/group1/login_page.ts similarity index 97% rename from x-pack/test/accessibility/apps/login_page.ts rename to x-pack/test/accessibility/apps/group1/login_page.ts index 3993d9ffcd72..32cb825f86b3 100644 --- a/x-pack/test/accessibility/apps/login_page.ts +++ b/x-pack/test/accessibility/apps/group1/login_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/management.ts b/x-pack/test/accessibility/apps/group1/management.ts similarity index 97% rename from x-pack/test/accessibility/apps/management.ts rename to x-pack/test/accessibility/apps/group1/management.ts index 2021642c2aa2..82c7baf8e830 100644 --- a/x-pack/test/accessibility/apps/management.ts +++ b/x-pack/test/accessibility/apps/group1/management.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ diff --git a/x-pack/test/accessibility/apps/group1/painless_lab.ts b/x-pack/test/accessibility/apps/group1/painless_lab.ts new file mode 100644 index 000000000000..522ffa9c7b23 --- /dev/null +++ b/x-pack/test/accessibility/apps/group1/painless_lab.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'security']); + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const a11y = getService('a11y'); + const retry = getService('retry'); + + describe('Accessibility Painless Lab Editor Accessibility', () => { + before(async () => { + await PageObjects.common.navigateToApp('painlessLab'); + }); + + it('renders the page without a11y errors', async () => { + await PageObjects.common.navigateToApp('painlessLab'); + await a11y.testAppSnapshot(); + }); + + it('click on the output button', async () => { + const painlessTabsOutput = await find.byCssSelector( + '[data-test-subj="painlessTabs"] #output' + ); + await painlessTabsOutput.click(); + await a11y.testAppSnapshot(); + }); + + it('click on the parameters button', async () => { + const painlessTabsParameters = await find.byCssSelector( + '[data-test-subj="painlessTabs"] #parameters' + ); + await painlessTabsParameters.click(); + await a11y.testAppSnapshot(); + }); + + it('click on the context button', async () => { + const painlessTabsContext = await find.byCssSelector( + '[data-test-subj="painlessTabs"] #context' + ); + await painlessTabsContext.click(); + await a11y.testAppSnapshot(); + }); + + it('click on the Basic button', async () => { + await testSubjects.click('painlessContextDropDown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + await testSubjects.click('basicButtonDropdown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + }); + + it('click on the Filter button', async () => { + await testSubjects.click('painlessContextDropDown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + await testSubjects.click('filterButtonDropdown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + }); + + it('click on the Score button', async () => { + await testSubjects.click('painlessContextDropDown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + await testSubjects.click('scoreButtonDropdown'); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + }); + }); +} diff --git a/x-pack/test/accessibility/apps/roles.ts b/x-pack/test/accessibility/apps/group1/roles.ts similarity index 98% rename from x-pack/test/accessibility/apps/roles.ts rename to x-pack/test/accessibility/apps/group1/roles.ts index 5369dced427f..cf798bcb853f 100644 --- a/x-pack/test/accessibility/apps/roles.ts +++ b/x-pack/test/accessibility/apps/group1/roles.ts @@ -7,7 +7,7 @@ // a11y tests for spaces, space selection and spacce creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['security', 'settings']); diff --git a/x-pack/test/accessibility/apps/group1/search_profiler.ts b/x-pack/test/accessibility/apps/group1/search_profiler.ts new file mode 100644 index 000000000000..522c5e4cf730 --- /dev/null +++ b/x-pack/test/accessibility/apps/group1/search_profiler.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'security']); + const testSubjects = getService('testSubjects'); + const aceEditor = getService('aceEditor'); + const a11y = getService('a11y'); + const esArchiver = getService('esArchiver'); + + describe('Search Profiler Editor Accessibility', () => { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); + await PageObjects.common.navigateToApp('searchProfiler'); + await a11y.testAppSnapshot(); + expect(await testSubjects.exists('searchProfilerEditor')).to.be(true); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); + }); + + it('input the JSON in the aceeditor', async () => { + const input = { + query: { + bool: { + should: [ + { + match: { + name: 'fred', + }, + }, + { + terms: { + name: ['sue', 'sally'], + }, + }, + ], + }, + }, + aggs: { + stats: { + stats: { + field: 'price', + }, + }, + }, + }; + + await aceEditor.setValue('searchProfilerEditor', JSON.stringify(input)); + await a11y.testAppSnapshot(); + }); + + it('click on the profile button', async () => { + await testSubjects.click('profileButton'); + await a11y.testAppSnapshot(); + }); + + it('click on the dropdown link', async () => { + const viewShardDetailslink = await testSubjects.findAll('viewShardDetails'); + await viewShardDetailslink[0].click(); + await a11y.testAppSnapshot(); + }); + + it('close the flyout', async () => { + await testSubjects.click('euiFlyoutCloseButton'); + await a11y.testAppSnapshot(); + }); + + it('click on the open-close shard details link', async () => { + const openShardDetailslink = await testSubjects.findAll('openCloseShardDetails'); + await openShardDetailslink[0].click(); + await a11y.testAppSnapshot(); + }); + + it('click on the Aggregation Profile link', async () => { + await testSubjects.click('aggregationProfileTab'); + await a11y.testAppSnapshot(); + }); + }); +} diff --git a/x-pack/test/accessibility/apps/spaces.ts b/x-pack/test/accessibility/apps/group1/spaces.ts similarity index 98% rename from x-pack/test/accessibility/apps/spaces.ts rename to x-pack/test/accessibility/apps/group1/spaces.ts index 622b1b3cefd6..33616c3576b1 100644 --- a/x-pack/test/accessibility/apps/spaces.ts +++ b/x-pack/test/accessibility/apps/group1/spaces.ts @@ -7,7 +7,7 @@ // a11y tests for spaces, space selection and space creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'spaceSelector', 'home', 'header', 'security']); diff --git a/x-pack/test/accessibility/apps/uptime.ts b/x-pack/test/accessibility/apps/group1/uptime.ts similarity index 91% rename from x-pack/test/accessibility/apps/uptime.ts rename to x-pack/test/accessibility/apps/group1/uptime.ts index 49243c37fe73..3818ddb1061a 100644 --- a/x-pack/test/accessibility/apps/uptime.ts +++ b/x-pack/test/accessibility/apps/group1/uptime.ts @@ -6,8 +6,8 @@ */ import moment from 'moment'; -import { FtrProviderContext } from '../ftr_provider_context'; -import { makeChecks } from '../../api_integration/apis/uptime/rest/helper/make_checks'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { makeChecks } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; const A11Y_TEST_MONITOR_ID = 'a11yTestMonitor'; @@ -19,7 +19,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const es = getService('es'); const toasts = getService('toasts'); - describe('uptime Accessibility', () => { + // github.com/elastic/kibana/issues/153601 + describe.skip('uptime Accessibility', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/uptime/blank'); await makeChecks(es, A11Y_TEST_MONITOR_ID, 150, 1, 1000, { diff --git a/x-pack/test/accessibility/apps/users.ts b/x-pack/test/accessibility/apps/group1/users.ts similarity index 98% rename from x-pack/test/accessibility/apps/users.ts rename to x-pack/test/accessibility/apps/group1/users.ts index 6057b4d45bb0..e26e6a6f6a54 100644 --- a/x-pack/test/accessibility/apps/users.ts +++ b/x-pack/test/accessibility/apps/group1/users.ts @@ -7,7 +7,7 @@ // a11y tests for spaces, space selection and spacce creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['security', 'settings']); diff --git a/x-pack/test/accessibility/apps/group2/config.ts b/x-pack/test/accessibility/apps/group2/config.ts new file mode 100644 index 000000000000..27cf620bc05c --- /dev/null +++ b/x-pack/test/accessibility/apps/group2/config.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from '../../services'; +import { pageObjects } from '../../page_objects'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../functional/config.base.js') + ); + + return { + ...functionalConfig.getAll(), + + testFiles: [require.resolve('.')], + + pageObjects, + services, + + junit: { + reportName: 'X-Pack Accessibility Tests - Group 2', + }, + }; +} diff --git a/x-pack/test/accessibility/apps/group2/index.ts b/x-pack/test/accessibility/apps/group2/index.ts new file mode 100644 index 000000000000..2c6bf4e58a08 --- /dev/null +++ b/x-pack/test/accessibility/apps/group2/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('X-Pack Accessibility Tests - Group 2', function () { + loadTestFile(require.resolve('./ml')); + loadTestFile(require.resolve('./ml_anomaly_detection')); + loadTestFile(require.resolve('./transform')); + loadTestFile(require.resolve('./lens')); + }); +}; diff --git a/x-pack/test/accessibility/apps/lens.ts b/x-pack/test/accessibility/apps/group2/lens.ts similarity index 98% rename from x-pack/test/accessibility/apps/lens.ts rename to x-pack/test/accessibility/apps/group2/lens.ts index 1153d61d1fc6..860138fc7770 100644 --- a/x-pack/test/accessibility/apps/lens.ts +++ b/x-pack/test/accessibility/apps/group2/lens.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'visualize', 'timePicker', 'home', 'lens']); @@ -25,11 +25,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { - await PageObjects.common.navigateToApp('visualize'); - await listingTable.searchForItemWithName(lensChartName); - await listingTable.checkListingSelectAllCheckbox(); - await listingTable.clickDeleteSelected(); - await PageObjects.common.clickConfirmOnModal(); await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.importExport.unload( 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' @@ -173,6 +168,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('saves lens chart', async () => { await PageObjects.lens.save(lensChartName); await a11y.testAppSnapshot(); + // delete newly created Lens + await PageObjects.common.navigateToApp('visualize'); + await listingTable.searchForItemWithName(lensChartName); + await listingTable.checkListingSelectAllCheckbox(); + await listingTable.clickDeleteSelected(); + await PageObjects.common.clickConfirmOnModal(); }); }); } diff --git a/x-pack/test/accessibility/apps/ml.ts b/x-pack/test/accessibility/apps/group2/ml.ts similarity index 92% rename from x-pack/test/accessibility/apps/ml.ts rename to x-pack/test/accessibility/apps/group2/ml.ts index dd2fad6de05d..af9664b5e258 100644 --- a/x-pack/test/accessibility/apps/ml.ts +++ b/x-pack/test/accessibility/apps/group2/ml.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const a11y = getService('a11y'); @@ -50,10 +50,10 @@ export default function ({ getService }: FtrProviderContext) { describe('with data loaded', function () { const dfaOutlierResultsJobId = 'iph_outlier_a11y'; - const ecIndexPattern = 'ft_module_sample_ecommerce'; - const ihpIndexPattern = 'ft_ihp_outlier'; - const egsIndexPattern = 'ft_egs_regression'; - const bmIndexPattern = 'ft_bank_marketing'; + const ecIndexName = 'ft_module_sample_ecommerce'; + const ihpIndexName = 'ft_ihp_outlier'; + const egsIndexName = 'ft_egs_regression'; + const bmIndexName = 'ft_bank_marketing'; const ecExpectedTotalCount = '287'; const dfaOutlierJobType = 'outlier_detection'; @@ -68,7 +68,7 @@ export default function ({ getService }: FtrProviderContext) { const dfaClassificationJobTrainingPercent = 30; const uploadFilePath = require.resolve( - '../../functional/apps/ml/data_visualizer/files_to_import/artificial_server_log' + '../../../functional/apps/ml/data_visualizer/files_to_import/artificial_server_log' ); before(async () => { @@ -78,10 +78,10 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); - await ml.testResources.createIndexPatternIfNeeded(ihpIndexPattern); - await ml.testResources.createIndexPatternIfNeeded(egsIndexPattern); - await ml.testResources.createIndexPatternIfNeeded(bmIndexPattern); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await ml.testResources.createDataViewIfNeeded(ihpIndexName); + await ml.testResources.createDataViewIfNeeded(egsIndexName); + await ml.testResources.createDataViewIfNeeded(bmIndexName); + await ml.testResources.createDataViewIfNeeded(ecIndexName, 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunDFAJob( @@ -93,10 +93,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.cleanMlIndices(); await ml.api.deleteIndices(`user-${dfaOutlierResultsJobId}`); - await ml.testResources.deleteIndexPatternByTitle(ihpIndexPattern); - await ml.testResources.deleteIndexPatternByTitle(egsIndexPattern); - await ml.testResources.deleteIndexPatternByTitle(bmIndexPattern); - await ml.testResources.deleteIndexPatternByTitle(ecIndexPattern); + await ml.testResources.deleteDataViewByTitle(ihpIndexName); + await ml.testResources.deleteDataViewByTitle(egsIndexName); + await ml.testResources.deleteDataViewByTitle(bmIndexName); + await ml.testResources.deleteDataViewByTitle(ecIndexName); await esArchiver.unload('x-pack/test/functional/es_archives/ml/ihp_outlier'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/egs_regression'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/bm_classification'); @@ -134,7 +134,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep( 'job creation selects the source data and loads the DFA job wizard page' ); - await ml.jobSourceSelection.selectSourceForAnalyticsJob(ihpIndexPattern); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(ihpIndexName); await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); await a11y.testAppSnapshot(); }); @@ -180,7 +180,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataFrameAnalytics(); await ml.dataFrameAnalytics.startAnalyticsCreation(); - await ml.jobSourceSelection.selectSourceForAnalyticsJob(egsIndexPattern); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(egsIndexName); await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); await ml.testExecution.logTestStep('selects the regression job type'); await ml.dataFrameAnalyticsCreation.assertJobTypeSelectExists(); @@ -227,7 +227,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataFrameAnalytics(); await ml.dataFrameAnalytics.startAnalyticsCreation(); - await ml.jobSourceSelection.selectSourceForAnalyticsJob(bmIndexPattern); + await ml.jobSourceSelection.selectSourceForAnalyticsJob(bmIndexName); await ml.dataFrameAnalyticsCreation.assertConfigurationStepActive(); await ml.testExecution.logTestStep('selects the classification job type'); await ml.dataFrameAnalyticsCreation.assertJobTypeSelectExists(); @@ -275,12 +275,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('index data visualizer select index pattern page', async () => { - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await a11y.testAppSnapshot(); }); it('index data visualizer page for selected index', async () => { - await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexPattern); + await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexName); await ml.testExecution.logTestStep('should display the time range step'); await ml.dataVisualizerIndexBased.assertTimeRangeSelectorSectionExists(); diff --git a/x-pack/test/accessibility/apps/ml_anomaly_detection.ts b/x-pack/test/accessibility/apps/group2/ml_anomaly_detection.ts similarity index 95% rename from x-pack/test/accessibility/apps/ml_anomaly_detection.ts rename to x-pack/test/accessibility/apps/group2/ml_anomaly_detection.ts index c8cff8616f23..33c7db9eb0b2 100644 --- a/x-pack/test/accessibility/apps/ml_anomaly_detection.ts +++ b/x-pack/test/accessibility/apps/group2/ml_anomaly_detection.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; interface Detector { identifier: string; @@ -65,10 +65,10 @@ export default function ({ getService }: FtrProviderContext) { const eventDescription = 'calendar_event_a11y'; const filterId = 'filter_a11y'; const filterItems = ['filter_item_a11y']; - const fqIndexPattern = 'ft_farequote'; - const ecIndexPattern = 'ft_module_sample_ecommerce'; + const fqIndexName = 'ft_farequote'; + const ecIndexName = 'ft_module_sample_ecommerce'; - const categorizationIndexPattern = 'ft_categorization_small'; + const categorizationIndexName = 'ft_categorization_small'; const adJobAggAndFieldIdentifier = 'Mean(responsetime)'; const adJobBucketSpan = '30m'; @@ -87,12 +87,12 @@ export default function ({ getService }: FtrProviderContext) { const advancedJobTestData = { suiteTitle: 'with multiple metric detectors and custom datafeed settings', - jobSource: ecIndexPattern, + jobSource: ecIndexName, jobId: `ec_advanced_1_${Date.now()}`, get jobIdClone(): string { return `${this.jobId}_clone`; }, - jobDescription: `Create advanced job from ${ecIndexPattern} dataset with multiple metric detectors and custom datafeed settings`, + jobDescription: `Create advanced job from ${ecIndexName} dataset with multiple metric detectors and custom datafeed settings`, jobGroups: ['automated', 'ecommerce', 'advanced'], get jobGroupsClone(): string[] { return [...this.jobGroups, 'clone']; @@ -149,7 +149,7 @@ export default function ({ getService }: FtrProviderContext) { }; const populationJobTestData = { suiteTitle: 'population job', - jobSource: ecIndexPattern, + jobSource: ecIndexName, jobId: `ec_population_1_${Date.now()}`, get jobIdClone(): string { return `${this.jobId}_clone`; @@ -201,12 +201,9 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/categorization_small' ); - await ml.testResources.createIndexPatternIfNeeded(fqIndexPattern, '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); - await ml.testResources.createIndexPatternIfNeeded( - 'ft_categorization_small', - '@timestamp' - ); + await ml.testResources.createDataViewIfNeeded(fqIndexName, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(ecIndexName, 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_categorization_small', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob( @@ -238,9 +235,9 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.deleteCalendar(calendarId); await ml.api.deleteFilter(filterId); - await ml.testResources.deleteIndexPatternByTitle(fqIndexPattern); - await ml.testResources.deleteIndexPatternByTitle(ecIndexPattern); - await ml.testResources.deleteIndexPatternByTitle(categorizationIndexPattern); + await ml.testResources.deleteDataViewByTitle(fqIndexName); + await ml.testResources.deleteDataViewByTitle(ecIndexName); + await ml.testResources.deleteDataViewByTitle(categorizationIndexName); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/module_sample_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/categorization_small'); @@ -259,7 +256,7 @@ export default function ({ getService }: FtrProviderContext) { }); it('anomaly detection create job select type page', async () => { - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(fqIndexPattern); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(fqIndexName); await a11y.testAppSnapshot(); }); @@ -308,7 +305,7 @@ export default function ({ getService }: FtrProviderContext) { // as the other steps have already been tested for the single metric job await ml.navigation.navigateToAnomalyDetection(); await ml.jobManagement.navigateToNewJobSourceSelection(); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(fqIndexPattern); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(fqIndexName); await ml.jobTypeSelection.selectMultiMetricJob(); await ml.testExecution.logTestStep('job creation set the time range'); await ml.jobWizardCommon.clickUseFullDataButton( @@ -442,7 +439,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToJobManagement(); await ml.jobManagement.navigateToNewJobSourceSelection(); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(ecIndexPattern); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(ecIndexName); await ml.testExecution.logTestStep('job creation loads the population job wizard page'); await ml.jobTypeSelection.selectPopulationJob(); @@ -509,9 +506,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToJobManagement(); await ml.jobManagement.navigateToNewJobSourceSelection(); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob( - categorizationIndexPattern - ); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(categorizationIndexName); await ml.testExecution.logTestStep( 'job creation loads the categorization job wizard page' @@ -566,7 +561,7 @@ export default function ({ getService }: FtrProviderContext) { it('anomaly detection create job from data recognizer module open wizard', async () => { await ml.navigation.navigateToJobManagement(); await ml.jobManagement.navigateToNewJobSourceSelection(); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(ecIndexPattern); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(ecIndexName); await ml.testExecution.logTestStep( `job creation loads the data recognizer job wizard page for the ${adRecognizerJobModuleId} module` ); diff --git a/x-pack/test/accessibility/apps/transform.ts b/x-pack/test/accessibility/apps/group2/transform.ts similarity index 87% rename from x-pack/test/accessibility/apps/transform.ts rename to x-pack/test/accessibility/apps/group2/transform.ts index 9d5257195681..dac3f8545001 100644 --- a/x-pack/test/accessibility/apps/transform.ts +++ b/x-pack/test/accessibility/apps/group2/transform.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const a11y = getService('a11y'); @@ -42,7 +42,7 @@ export default function ({ getService }: FtrProviderContext) { }); describe('with data loaded', function () { - const ecIndexPattern = 'ft_ecommerce'; + const ecIndexName = 'ft_ecommerce'; const pivotGroupByEntries = [ { @@ -85,7 +85,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await transform.testResources.createDataViewIfNeeded(ecIndexName, 'order_date'); await transform.testResources.setKibanaTimeZoneToUTC(); }); @@ -93,9 +93,9 @@ export default function ({ getService }: FtrProviderContext) { await transform.api.cleanTransformIndices(); await transform.api.deleteIndices(pivotTransformDestinationIndex); await transform.api.deleteIndices(latestTransformDestinationIndex); - await transform.testResources.deleteIndexPatternByTitle(pivotTransformDestinationIndex); - await transform.testResources.deleteIndexPatternByTitle(latestTransformDestinationIndex); - await transform.testResources.deleteIndexPatternByTitle(ecIndexPattern); + await transform.testResources.deleteDataViewByTitle(pivotTransformDestinationIndex); + await transform.testResources.deleteDataViewByTitle(latestTransformDestinationIndex); + await transform.testResources.deleteDataViewByTitle(ecIndexName); await esArchiver.unload('x-pack/test/functional/es_archives/ml/ecommerce'); await transform.testResources.resetKibanaTimeZone(); }); @@ -110,7 +110,7 @@ export default function ({ getService }: FtrProviderContext) { await transform.testExecution.logTestStep( 'transform creation selects the source data and loads the Transform wizard page' ); - await transform.sourceSelection.selectSource(ecIndexPattern); + await transform.sourceSelection.selectSource(ecIndexName); await transform.testExecution.logTestStep( `sets the date picker to the default '15 minutes ago'` @@ -164,8 +164,16 @@ export default function ({ getService }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionInputExists(); await transform.wizard.setTransformDescription(pivotTransformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); + await transform.wizard.assertDestinationIndexValue(pivotTransformId); await transform.wizard.setDestinationIndex(pivotTransformDestinationIndex); await a11y.testAppSnapshot(); @@ -201,7 +209,7 @@ export default function ({ getService }: FtrProviderContext) { await transform.testExecution.logTestStep( 'selects the source data and loads the Transform wizard page' ); - await transform.sourceSelection.selectSource(ecIndexPattern); + await transform.sourceSelection.selectSource(ecIndexName); await transform.testExecution.logTestStep( `sets the date picker to the default '15 minutes ago'` @@ -250,8 +258,16 @@ export default function ({ getService }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionInputExists(); await transform.wizard.setTransformDescription(latestTransformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); + await transform.wizard.assertDestinationIndexValue(latestTransformId); await transform.wizard.setDestinationIndex(latestTransformDestinationIndex); await a11y.testAppSnapshot(); diff --git a/x-pack/test/accessibility/apps/canvas.ts b/x-pack/test/accessibility/apps/group3/canvas.ts similarity index 96% rename from x-pack/test/accessibility/apps/canvas.ts rename to x-pack/test/accessibility/apps/group3/canvas.ts index f3dfa9305fb9..fb6cc672e2ff 100644 --- a/x-pack/test/accessibility/apps/canvas.ts +++ b/x-pack/test/accessibility/apps/group3/canvas.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/group3/config.ts b/x-pack/test/accessibility/apps/group3/config.ts new file mode 100644 index 000000000000..94f6c862b539 --- /dev/null +++ b/x-pack/test/accessibility/apps/group3/config.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from '../../services'; +import { pageObjects } from '../../page_objects'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../functional/config.base.js') + ); + + return { + ...functionalConfig.getAll(), + + testFiles: [require.resolve('.')], + + pageObjects, + services, + + junit: { + reportName: 'X-Pack Accessibility Tests - Group 3', + }, + }; +} diff --git a/x-pack/test/accessibility/apps/cross_cluster_replication.ts b/x-pack/test/accessibility/apps/group3/cross_cluster_replication.ts similarity index 95% rename from x-pack/test/accessibility/apps/cross_cluster_replication.ts rename to x-pack/test/accessibility/apps/group3/cross_cluster_replication.ts index bc81770de9f4..db5d70ac26d0 100644 --- a/x-pack/test/accessibility/apps/cross_cluster_replication.ts +++ b/x-pack/test/accessibility/apps/group3/cross_cluster_replication.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ @@ -20,7 +20,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const es = getService('es'); const retry = getService('retry'); - describe('cross cluster replication - a11y tests', async () => { + // github.com/elastic/kibana/issues/153599 + describe.skip('cross cluster replication - a11y tests', async () => { before(async () => { await PageObjects.common.navigateToApp('crossClusterReplication'); }); diff --git a/x-pack/test/accessibility/apps/enterprise_search.ts b/x-pack/test/accessibility/apps/group3/enterprise_search.ts similarity index 98% rename from x-pack/test/accessibility/apps/enterprise_search.ts rename to x-pack/test/accessibility/apps/group3/enterprise_search.ts index b610130d99e0..a7b7724e4318 100644 --- a/x-pack/test/accessibility/apps/enterprise_search.ts +++ b/x-pack/test/accessibility/apps/group3/enterprise_search.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/graph.ts b/x-pack/test/accessibility/apps/group3/graph.ts similarity index 98% rename from x-pack/test/accessibility/apps/graph.ts rename to x-pack/test/accessibility/apps/group3/graph.ts index 03ca3b2afbfe..839ea50ce277 100644 --- a/x-pack/test/accessibility/apps/graph.ts +++ b/x-pack/test/accessibility/apps/group3/graph.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/group3/grok_debugger.ts b/x-pack/test/accessibility/apps/group3/grok_debugger.ts new file mode 100644 index 000000000000..da630c6bed7b --- /dev/null +++ b/x-pack/test/accessibility/apps/group3/grok_debugger.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'security']); + const a11y = getService('a11y'); + const grokDebugger = getService('grokDebugger'); + + // Fixes:https://github.com/elastic/kibana/issues/62102 + describe('Dev tools grok debugger', () => { + before(async () => { + await PageObjects.common.navigateToApp('grokDebugger'); + await grokDebugger.assertExists(); + }); + + it('Dev tools grok debugger set input', async () => { + await grokDebugger.setEventInput('SegerCommaBob'); + await a11y.testAppSnapshot(); + }); + + it('Dev tools grok debugger set pattern', async () => { + await grokDebugger.setPatternInput('%{USERNAME:u}'); + await a11y.testAppSnapshot(); + }); + + it('Dev tools grok debugger simulate', async () => { + await grokDebugger.clickSimulate(); + await a11y.testAppSnapshot(); + }); + }); +} diff --git a/x-pack/test/accessibility/apps/group3/index.ts b/x-pack/test/accessibility/apps/group3/index.ts new file mode 100644 index 000000000000..d295c2a17a4f --- /dev/null +++ b/x-pack/test/accessibility/apps/group3/index.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('X-Pack Accessibility Tests - Group 3', function () { + loadTestFile(require.resolve('./upgrade_assistant')); + loadTestFile(require.resolve('./canvas')); + loadTestFile(require.resolve('./maps')); + loadTestFile(require.resolve('./graph')); + loadTestFile(require.resolve('./security_solution')); + loadTestFile(require.resolve('./ml_embeddables_in_dashboard')); + loadTestFile(require.resolve('./rules_connectors')); + // Please make sure that the remote clusters, snapshot and restore and + // CCR tests stay in that order. Their execution fails if rearranged. + loadTestFile(require.resolve('./remote_clusters')); + loadTestFile(require.resolve('./snapshot_and_restore')); + loadTestFile(require.resolve('./cross_cluster_replication')); + loadTestFile(require.resolve('./reporting')); + loadTestFile(require.resolve('./enterprise_search')); + + // loadTestFile(require.resolve('./license_management')); + // loadTestFile(require.resolve('./tags')); + // loadTestFile(require.resolve('./search_sessions')); + // loadTestFile(require.resolve('./stack_monitoring')); + // loadTestFile(require.resolve('./watcher')); + // loadTestFile(require.resolve('./rollup_jobs')); + // loadTestFile(require.resolve('./observability')); + }); +}; diff --git a/x-pack/test/accessibility/apps/license_management.ts b/x-pack/test/accessibility/apps/group3/license_management.ts similarity index 95% rename from x-pack/test/accessibility/apps/license_management.ts rename to x-pack/test/accessibility/apps/group3/license_management.ts index 7693ebb197ff..a71ac90f54ce 100644 --- a/x-pack/test/accessibility/apps/license_management.ts +++ b/x-pack/test/accessibility/apps/group3/license_management.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['licenseManagement', 'common']); diff --git a/x-pack/test/accessibility/apps/maps.ts b/x-pack/test/accessibility/apps/group3/maps.ts similarity index 98% rename from x-pack/test/accessibility/apps/maps.ts rename to x-pack/test/accessibility/apps/group3/maps.ts index af74466fb8f2..2f69696b5824 100644 --- a/x-pack/test/accessibility/apps/maps.ts +++ b/x-pack/test/accessibility/apps/group3/maps.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts b/x-pack/test/accessibility/apps/group3/ml_embeddables_in_dashboard.ts similarity index 96% rename from x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts rename to x-pack/test/accessibility/apps/group3/ml_embeddables_in_dashboard.ts index 8f8bc67304c0..c3278b39096c 100644 --- a/x-pack/test/accessibility/apps/ml_embeddables_in_dashboard.ts +++ b/x-pack/test/accessibility/apps/group3/ml_embeddables_in_dashboard.ts @@ -6,7 +6,7 @@ */ import { Datafeed, Job } from '@kbn/ml-plugin/common/types/anomaly_detection_jobs'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; // @ts-expect-error not full interface const JOB_CONFIG: Job = { @@ -66,7 +66,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.securityCommon.createMlUsers(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); diff --git a/x-pack/test/accessibility/apps/observability.ts b/x-pack/test/accessibility/apps/group3/observability.ts similarity index 95% rename from x-pack/test/accessibility/apps/observability.ts rename to x-pack/test/accessibility/apps/group3/observability.ts index ead89c913d1e..1d24c1c17be2 100644 --- a/x-pack/test/accessibility/apps/observability.ts +++ b/x-pack/test/accessibility/apps/group3/observability.ts @@ -6,7 +6,7 @@ */ // a11y tests for spaces, space selection and space creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'infraHome']); diff --git a/x-pack/test/accessibility/apps/remote_clusters.ts b/x-pack/test/accessibility/apps/group3/remote_clusters.ts similarity index 99% rename from x-pack/test/accessibility/apps/remote_clusters.ts rename to x-pack/test/accessibility/apps/group3/remote_clusters.ts index deb0e4a090b8..4b509c88f052 100644 --- a/x-pack/test/accessibility/apps/remote_clusters.ts +++ b/x-pack/test/accessibility/apps/group3/remote_clusters.ts @@ -6,7 +6,7 @@ */ import { ClusterPayloadEs } from '@kbn/remote-clusters-plugin/common/lib'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; const emptyPrompt = 'remoteClusterListEmptyPrompt'; const createButton = 'remoteClusterEmptyPromptCreateButton'; diff --git a/x-pack/test/accessibility/apps/group3/reporting.ts b/x-pack/test/accessibility/apps/group3/reporting.ts new file mode 100644 index 000000000000..45959e42b383 --- /dev/null +++ b/x-pack/test/accessibility/apps/group3/reporting.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const { common } = getPageObjects(['common']); + const retry = getService('retry'); + const a11y = getService('a11y'); + const testSubjects = getService('testSubjects'); + const reporting = getService('reporting'); + const security = getService('security'); + const log = getService('log'); + + describe('Reporting Accessibility', () => { + const createReportingUser = async () => { + await security.user.create(reporting.REPORTING_USER_USERNAME, { + password: reporting.REPORTING_USER_PASSWORD, + roles: ['reporting_user', 'data_analyst', 'kibana_user'], // Deprecated: using built-in `reporting_user` role grants all Reporting privileges + full_name: 'a reporting user', + }); + }; + + const deleteReportingUser = async () => { + await security.user.delete(reporting.REPORTING_USER_USERNAME); + }; + + before(async () => { + await reporting.initEcommerce(); + await createReportingUser(); + await reporting.loginReportingUser(); + }); + + after(async () => { + await reporting.teardownLogs(); + await deleteReportingUser(); + }); + + beforeEach(async () => { + // Add one report + const { body } = await reporting.generateCsv( + { + title: 'CSV Report', + browserTimezone: 'UTC', + objectType: 'search', + version: '7.15.0', + searchSource: { + version: true, + query: { query: '', language: 'kuery' }, + index: '5193f870-d861-11e9-a311-0fa548c5f953', + fields: ['*'], + }, + }, + reporting.REPORTING_USER_USERNAME, + reporting.REPORTING_USER_PASSWORD + ); + + log.info(`Queued report job: ${body.path}`); + + await retry.waitFor('Reporting app', async () => { + await common.navigateToApp('reporting'); + return testSubjects.exists('reportingPageHeader'); + }); + }); + + afterEach(async () => { + await reporting.deleteAllReports(); + }); + + it('List reports view', async () => { + await retry.waitForWithTimeout('A reporting list item', 5000, () => { + return testSubjects.exists('reportingListItemObjectTitle'); + }); + await retry.try(async () => { + await a11y.testAppSnapshot(); + }); + }); + }); +} diff --git a/x-pack/test/accessibility/apps/rollup_jobs.ts b/x-pack/test/accessibility/apps/group3/rollup_jobs.ts similarity index 98% rename from x-pack/test/accessibility/apps/rollup_jobs.ts rename to x-pack/test/accessibility/apps/group3/rollup_jobs.ts index 2acf48d5f049..5581a11955e1 100644 --- a/x-pack/test/accessibility/apps/rollup_jobs.ts +++ b/x-pack/test/accessibility/apps/group3/rollup_jobs.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'rollup']); diff --git a/x-pack/test/accessibility/apps/rules_connectors.ts b/x-pack/test/accessibility/apps/group3/rules_connectors.ts similarity index 98% rename from x-pack/test/accessibility/apps/rules_connectors.ts rename to x-pack/test/accessibility/apps/group3/rules_connectors.ts index bc1779371728..bf46735a84fd 100644 --- a/x-pack/test/accessibility/apps/rules_connectors.ts +++ b/x-pack/test/accessibility/apps/group3/rules_connectors.ts @@ -7,7 +7,7 @@ // a11y tests for rules, logs and connectors page -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['settings', 'common']); diff --git a/x-pack/test/accessibility/apps/search_sessions.ts b/x-pack/test/accessibility/apps/group3/search_sessions.ts similarity index 98% rename from x-pack/test/accessibility/apps/search_sessions.ts rename to x-pack/test/accessibility/apps/group3/search_sessions.ts index 5a4ca433e3d2..c400d1726322 100644 --- a/x-pack/test/accessibility/apps/search_sessions.ts +++ b/x-pack/test/accessibility/apps/group3/search_sessions.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['searchSessionsManagement']); diff --git a/x-pack/test/accessibility/apps/security_solution.ts b/x-pack/test/accessibility/apps/group3/security_solution.ts similarity index 98% rename from x-pack/test/accessibility/apps/security_solution.ts rename to x-pack/test/accessibility/apps/group3/security_solution.ts index ba7d22fd2d39..7257f88be8a7 100644 --- a/x-pack/test/accessibility/apps/security_solution.ts +++ b/x-pack/test/accessibility/apps/group3/security_solution.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const a11y = getService('a11y'); diff --git a/x-pack/test/accessibility/apps/snapshot_and_restore.ts b/x-pack/test/accessibility/apps/group3/snapshot_and_restore.ts similarity index 98% rename from x-pack/test/accessibility/apps/snapshot_and_restore.ts rename to x-pack/test/accessibility/apps/group3/snapshot_and_restore.ts index c5f0f52c9c9f..4c3e5121f983 100644 --- a/x-pack/test/accessibility/apps/snapshot_and_restore.ts +++ b/x-pack/test/accessibility/apps/group3/snapshot_and_restore.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'snapshotRestore']); diff --git a/x-pack/test/accessibility/apps/stack_monitoring.ts b/x-pack/test/accessibility/apps/group3/stack_monitoring.ts similarity index 97% rename from x-pack/test/accessibility/apps/stack_monitoring.ts rename to x-pack/test/accessibility/apps/group3/stack_monitoring.ts index 87bd4d64d1fb..64eaa652e702 100644 --- a/x-pack/test/accessibility/apps/stack_monitoring.ts +++ b/x-pack/test/accessibility/apps/group3/stack_monitoring.ts @@ -7,7 +7,7 @@ // a11y tests for stack monitoring import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'spaceSelector', 'home', 'header', 'security']); diff --git a/x-pack/test/accessibility/apps/tags.ts b/x-pack/test/accessibility/apps/group3/tags.ts similarity index 98% rename from x-pack/test/accessibility/apps/tags.ts rename to x-pack/test/accessibility/apps/group3/tags.ts index 0c0f836cfc89..f885e8ba77c0 100644 --- a/x-pack/test/accessibility/apps/tags.ts +++ b/x-pack/test/accessibility/apps/group3/tags.ts @@ -7,7 +7,7 @@ // a11y tests for spaces, space selection and space creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'home', 'tagManagement']); diff --git a/x-pack/test/accessibility/apps/upgrade_assistant.ts b/x-pack/test/accessibility/apps/group3/upgrade_assistant.ts similarity index 99% rename from x-pack/test/accessibility/apps/upgrade_assistant.ts rename to x-pack/test/accessibility/apps/group3/upgrade_assistant.ts index 47582893e771..02f823ef6a67 100644 --- a/x-pack/test/accessibility/apps/upgrade_assistant.ts +++ b/x-pack/test/accessibility/apps/group3/upgrade_assistant.ts @@ -11,7 +11,7 @@ */ import type { IndicesCreateRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; const translogSettingsIndexDeprecation: IndicesCreateRequest = { index: 'deprecated_settings', diff --git a/x-pack/test/accessibility/apps/watcher.ts b/x-pack/test/accessibility/apps/group3/watcher.ts similarity index 95% rename from x-pack/test/accessibility/apps/watcher.ts rename to x-pack/test/accessibility/apps/group3/watcher.ts index 85a11db0122a..72b4e87e5066 100644 --- a/x-pack/test/accessibility/apps/watcher.ts +++ b/x-pack/test/accessibility/apps/group3/watcher.ts @@ -7,7 +7,7 @@ // a11y tests for spaces, space selection and space creation and feature controls -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'home', 'header', 'watcher', 'security']); diff --git a/x-pack/test/accessibility/apps/painless_lab.ts b/x-pack/test/accessibility/apps/painless_lab.ts deleted file mode 100644 index a0a4712dbe4e..000000000000 --- a/x-pack/test/accessibility/apps/painless_lab.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['common', 'security']); - const testSubjects = getService('testSubjects'); - const find = getService('find'); - const a11y = getService('a11y'); - const retry = getService('retry'); - - describe('Accessibility Painless Lab Editor Accessibility', () => { - before(async () => { - await PageObjects.common.navigateToApp('painlessLab'); - }); - - it('renders the page without a11y errors', async () => { - await PageObjects.common.navigateToApp('painlessLab'); - await a11y.testAppSnapshot(); - }); - - it('click on the output button', async () => { - const painlessTabsOutput = await find.byCssSelector( - '[data-test-subj="painlessTabs"] #output' - ); - await painlessTabsOutput.click(); - await a11y.testAppSnapshot(); - }); - - it('click on the parameters button', async () => { - const painlessTabsParameters = await find.byCssSelector( - '[data-test-subj="painlessTabs"] #parameters' - ); - await painlessTabsParameters.click(); - await a11y.testAppSnapshot(); - }); - - it('click on the context button', async () => { - const painlessTabsContext = await find.byCssSelector( - '[data-test-subj="painlessTabs"] #context' - ); - await painlessTabsContext.click(); - await a11y.testAppSnapshot(); - }); - - it('click on the Basic button', async () => { - await testSubjects.click('painlessContextDropDown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - await testSubjects.click('basicButtonDropdown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - }); - - it('click on the Filter button', async () => { - await testSubjects.click('painlessContextDropDown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - await testSubjects.click('filterButtonDropdown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - }); - - it('click on the Score button', async () => { - await testSubjects.click('painlessContextDropDown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - await testSubjects.click('scoreButtonDropdown'); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - }); - }); -} diff --git a/x-pack/test/accessibility/apps/reporting.ts b/x-pack/test/accessibility/apps/reporting.ts deleted file mode 100644 index f1ac0770c958..000000000000 --- a/x-pack/test/accessibility/apps/reporting.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const { common } = getPageObjects(['common']); - const retry = getService('retry'); - const a11y = getService('a11y'); - const testSubjects = getService('testSubjects'); - const reporting = getService('reporting'); - const security = getService('security'); - const log = getService('log'); - - describe('Reporting Accessibility', () => { - const createReportingUser = async () => { - await security.user.create(reporting.REPORTING_USER_USERNAME, { - password: reporting.REPORTING_USER_PASSWORD, - roles: ['reporting_user', 'data_analyst', 'kibana_user'], // Deprecated: using built-in `reporting_user` role grants all Reporting privileges - full_name: 'a reporting user', - }); - }; - - const deleteReportingUser = async () => { - await security.user.delete(reporting.REPORTING_USER_USERNAME); - }; - - before(async () => { - await reporting.initEcommerce(); - await createReportingUser(); - await reporting.loginReportingUser(); - }); - - after(async () => { - await reporting.teardownLogs(); - await deleteReportingUser(); - }); - - beforeEach(async () => { - // Add one report - const { body } = await reporting.generateCsv( - { - title: 'CSV Report', - browserTimezone: 'UTC', - objectType: 'search', - version: '7.15.0', - searchSource: { - version: true, - query: { query: '', language: 'kuery' }, - index: '5193f870-d861-11e9-a311-0fa548c5f953', - fields: ['*'], - }, - }, - reporting.REPORTING_USER_USERNAME, - reporting.REPORTING_USER_PASSWORD - ); - - log.info(`Queued report job: ${body.path}`); - - await retry.waitFor('Reporting app', async () => { - await common.navigateToApp('reporting'); - return testSubjects.exists('reportingPageHeader'); - }); - }); - - afterEach(async () => { - await reporting.deleteAllReports(); - }); - - it('List reports view', async () => { - await retry.waitForWithTimeout('A reporting list item', 5000, () => { - return testSubjects.exists('reportingListItemObjectTitle'); - }); - await retry.try(async () => { - await a11y.testAppSnapshot(); - }); - }); - }); -} diff --git a/x-pack/test/accessibility/apps/search_profiler.ts b/x-pack/test/accessibility/apps/search_profiler.ts deleted file mode 100644 index 30043f8f4157..000000000000 --- a/x-pack/test/accessibility/apps/search_profiler.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['common', 'security']); - const testSubjects = getService('testSubjects'); - const aceEditor = getService('aceEditor'); - const a11y = getService('a11y'); - const esArchiver = getService('esArchiver'); - - describe('Search Profiler Editor Accessibility', () => { - before(async () => { - await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await PageObjects.common.navigateToApp('searchProfiler'); - await a11y.testAppSnapshot(); - expect(await testSubjects.exists('searchProfilerEditor')).to.be(true); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); - }); - - it('input the JSON in the aceeditor', async () => { - const input = { - query: { - bool: { - should: [ - { - match: { - name: 'fred', - }, - }, - { - terms: { - name: ['sue', 'sally'], - }, - }, - ], - }, - }, - aggs: { - stats: { - stats: { - field: 'price', - }, - }, - }, - }; - - await aceEditor.setValue('searchProfilerEditor', JSON.stringify(input)); - await a11y.testAppSnapshot(); - }); - - it('click on the profile button', async () => { - await testSubjects.click('profileButton'); - await a11y.testAppSnapshot(); - }); - - it('click on the dropdown link', async () => { - const viewShardDetailslink = await testSubjects.findAll('viewShardDetails'); - await viewShardDetailslink[0].click(); - await a11y.testAppSnapshot(); - }); - - it('close the flyout', async () => { - await testSubjects.click('euiFlyoutCloseButton'); - await a11y.testAppSnapshot(); - }); - - it('click on the open-close shard details link', async () => { - const openShardDetailslink = await testSubjects.findAll('openCloseShardDetails'); - await openShardDetailslink[0].click(); - await a11y.testAppSnapshot(); - }); - - it('click on the Aggregation Profile link', async () => { - await testSubjects.click('aggregationProfileTab'); - await a11y.testAppSnapshot(); - }); - }); -} diff --git a/x-pack/test/accessibility/config.ts b/x-pack/test/accessibility/config.ts deleted file mode 100644 index ece39104293a..000000000000 --- a/x-pack/test/accessibility/config.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrConfigProviderContext } from '@kbn/test'; -import { services } from './services'; -import { pageObjects } from './page_objects'; - -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js')); - - return { - ...functionalConfig.getAll(), - - testFiles: [ - require.resolve('./apps/login_page'), - require.resolve('./apps/kibana_overview'), - require.resolve('./apps/home'), - require.resolve('./apps/management'), - require.resolve('./apps/grok_debugger'), - require.resolve('./apps/search_profiler'), - require.resolve('./apps/painless_lab'), - // https://github.com/elastic/kibana/issues/153601 - // require.resolve('./apps/uptime'), - require.resolve('./apps/spaces'), - require.resolve('./apps/advanced_settings'), - require.resolve('./apps/dashboard_panel_options'), - require.resolve('./apps/dashboard_controls'), - require.resolve('./apps/users'), - require.resolve('./apps/roles'), - require.resolve('./apps/ingest_node_pipelines'), - require.resolve('./apps/index_lifecycle_management'), - require.resolve('./apps/ml'), - require.resolve('./apps/ml_anomaly_detection'), - require.resolve('./apps/transform'), - require.resolve('./apps/lens'), - require.resolve('./apps/upgrade_assistant'), - require.resolve('./apps/canvas'), - require.resolve('./apps/maps'), - require.resolve('./apps/graph'), - require.resolve('./apps/security_solution'), - require.resolve('./apps/ml_embeddables_in_dashboard'), - require.resolve('./apps/rules_connectors'), - // Please make sure that the remote clusters, snapshot and restore and - // CCR tests stay in that order. Their execution fails if rearranged. - require.resolve('./apps/remote_clusters'), - require.resolve('./apps/snapshot_and_restore'), - // https://github.com/elastic/kibana/issues/153599 - // require.resolve('./apps/cross_cluster_replication'), - require.resolve('./apps/reporting'), - require.resolve('./apps/enterprise_search'), - // require.resolve('./apps/license_management'), - // require.resolve('./apps/tags'), - // require.resolve('./apps/search_sessions'), - // require.resolve('./apps/stack_monitoring'), - // require.resolve('./apps/watcher'), - // require.resolve('./apps/rollup_jobs'), - // require.resolve('./apps/observability'), - ], - - pageObjects, - services, - - junit: { - reportName: 'X-Pack Accessibility Tests', - }, - }; -} diff --git a/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts index bfa8c5cb0736..29e77feb5eda 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts @@ -7,6 +7,8 @@ import http from 'http'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; import { ProxyArgs, Simulator } from './simulator'; export class BedrockSimulator extends Simulator { @@ -27,6 +29,10 @@ export class BedrockSimulator extends Simulator { return BedrockSimulator.sendErrorResponse(response); } + if (request.url === '/model/anthropic.claude-v2/invoke-with-response-stream') { + return BedrockSimulator.sendStreamResponse(response); + } + return BedrockSimulator.sendResponse(response); } @@ -36,6 +42,14 @@ export class BedrockSimulator extends Simulator { response.end(JSON.stringify(bedrockSuccessResponse, null, 4)); } + private static sendStreamResponse(response: http.ServerResponse) { + response.statusCode = 200; + response.setHeader('Content-Type', 'application/octet-stream'); + response.setHeader('Transfer-Encoding', 'chunked'); + response.write(encodeBedrockResponse('Hello world, what a unique string!')); + response.end(); + } + private static sendErrorResponse(response: http.ServerResponse) { response.statusCode = 422; response.setHeader('Content-Type', 'application/json;charset=UTF-8'); @@ -52,3 +66,20 @@ export const bedrockFailedResponse = { message: 'Malformed input request: extraneous key [ooooo] is not permitted, please reformat your input and try again.', }; + +function encodeBedrockResponse(completion: string) { + return new EventStreamCodec(toUtf8, fromUtf8).encode({ + headers: { + ':event-type': { type: 'string', value: 'chunk' }, + ':content-type': { type: 'string', value: 'application/json' }, + ':message-type': { type: 'string', value: 'event' }, + }, + body: Uint8Array.from( + Buffer.from( + JSON.stringify({ + bytes: Buffer.from(JSON.stringify({ completion })).toString('base64'), + }) + ) + ), + }); +} diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts index b38b4b0ee672..90998bc55623 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_fired.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import moment from 'moment'; import { cleanup, generate } from '@kbn/infra-forge'; import { @@ -16,7 +15,6 @@ import { FIRED_ACTIONS_ID } from '@kbn/observability-plugin/server/lib/rules/cus import expect from '@kbn/expect'; import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils'; import { createIndexConnector, createRule } from '../helpers/alerting_api_helper'; -import { createDataView, deleteDataView } from '../helpers/data_view'; import { waitForAlertInIndex, waitForDocumentInIndex, @@ -38,8 +36,19 @@ export default function ({ getService }: FtrProviderContext) { // DATE_VIEW should match the index template: // x-pack/packages/kbn-infra-forge/src/data_sources/composable/template.json const DATE_VIEW = 'kbn-data-forge-fake_hosts'; - const DATE_VIEW_NAME = 'data-view-name'; + const DATE_VIEW_NAME = 'ad-hoc-data-view-name'; const DATA_VIEW_ID = 'data-view-id'; + const MOCKED_AD_HOC_DATA_VIEW = { + id: DATA_VIEW_ID, + title: DATE_VIEW, + timeFieldName: '@timestamp', + sourceFilters: [], + fieldFormats: {}, + runtimeFieldMap: {}, + allowNoIndex: false, + name: DATE_VIEW_NAME, + allowHidden: false, + }; let infraDataIndex: string; let actionId: string; let ruleId: string; @@ -48,12 +57,6 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { infraDataIndex = await generate({ esClient, lookback: 'now-15m', logger }); - await createDataView({ - supertest, - name: DATE_VIEW_NAME, - id: DATA_VIEW_ID, - title: DATE_VIEW, - }); }); after(async () => { @@ -67,10 +70,6 @@ export default function ({ getService }: FtrProviderContext) { index: '.kibana-event-log-*', query: { term: { 'kibana.alert.rule.consumer': 'logs' } }, }); - await deleteDataView({ - supertest, - id: DATA_VIEW_ID, - }); await esDeleteAllIndices([ALERT_ACTION_INDEX, infraDataIndex]); await cleanup({ esClient, logger }); }); @@ -92,7 +91,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.5], timeSize: 5, @@ -109,7 +107,7 @@ export default function ({ getService }: FtrProviderContext) { query: '', language: 'kuery', }, - index: DATA_VIEW_ID, + index: MOCKED_AD_HOC_DATA_VIEW, }, }, actions: [ @@ -159,7 +157,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -189,7 +187,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>', threshold: [0.5], timeSize: 5, @@ -199,7 +196,10 @@ export default function ({ getService }: FtrProviderContext) { ], alertOnNoData: true, alertOnGroupDisappear: true, - searchConfiguration: { index: 'data-view-id', query: { query: '', language: 'kuery' } }, + searchConfiguration: { + index: MOCKED_AD_HOC_DATA_VIEW, + query: { query: '', language: 'kuery' }, + }, }); }); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_no_data.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_no_data.ts index f02eb9568f68..ae3689fbb49e 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_no_data.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_pct_no_data.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import moment from 'moment'; import { Aggregators, @@ -85,7 +84,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.5], timeSize: 5, @@ -151,7 +149,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -181,7 +179,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>', threshold: [0.5], timeSize: 5, diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_us_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_us_fired.ts index 9929491ea4e0..2020c3633087 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_us_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/avg_us_fired.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import moment from 'moment'; import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; import { format } from 'url'; @@ -98,7 +97,7 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, + aggType: 'custom', comparator: Comparator.GT, threshold: [7500000], timeSize: 5, @@ -164,7 +163,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts index 71f0a1bed860..059da333f029 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts @@ -11,7 +11,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import moment from 'moment'; import { cleanup, generate } from '@kbn/infra-forge'; import { @@ -97,7 +96,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.9], timeSize: 1, @@ -165,7 +163,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -195,7 +193,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.9], timeSize: 1, diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts index c2ca213bae98..361ca1d05b22 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/documents_count_fired.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import moment from 'moment'; import { cleanup, generate } from '@kbn/infra-forge'; import { @@ -92,9 +91,8 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, - comparator: Comparator.GT, - threshold: [2], + comparator: Comparator.OUTSIDE_RANGE, + threshold: [1, 2], timeSize: 1, timeUnit: 'm', metrics: [{ name: 'A', filter: '', aggType: Aggregators.COUNT }], @@ -156,7 +154,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -188,9 +186,8 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', - comparator: '>', - threshold: [2], + comparator: Comparator.OUTSIDE_RANGE, + threshold: [1, 2], timeSize: 1, timeUnit: 'm', metrics: [{ name: 'A', filter: '', aggType: 'count' }], @@ -214,7 +211,7 @@ export default function ({ getService }: FtrProviderContext) { `https://localhost:5601/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)` ); expect(resp.hits.hits[0]._source?.reason).eql( - `Document count is 3, above the threshold of 2. (duration: 1 min, data view: ${DATE_VIEW_NAME})` + `Document count is 3, not between the threshold of 1 and 2. (duration: 1 min, data view: ${DATE_VIEW_NAME})` ); expect(resp.hits.hits[0]._source?.value).eql('3'); }); diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts index 74144e8e7c72..ee9585e8a892 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule/group_by_fired.ts @@ -7,7 +7,6 @@ import moment from 'moment'; import { cleanup, generate } from '@kbn/infra-forge'; -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -91,7 +90,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT_OR_EQ, threshold: [0.2], timeSize: 1, @@ -160,7 +158,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'logs'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -214,7 +212,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>=', threshold: [0.2], timeSize: 1, diff --git a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule_data_view.ts b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule_data_view.ts index 0cbb1044f887..6071a6702343 100644 --- a/x-pack/test/alerting_api_integration/observability/custom_threshold_rule_data_view.ts +++ b/x-pack/test/alerting_api_integration/observability/custom_threshold_rule_data_view.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -74,7 +73,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [7500000], timeSize: 5, diff --git a/x-pack/test/alerting_api_integration/observability/helpers/alerting_api_helper.ts b/x-pack/test/alerting_api_integration/observability/helpers/alerting_api_helper.ts index d56b91dda551..57b5721701a4 100644 --- a/x-pack/test/alerting_api_integration/observability/helpers/alerting_api_helper.ts +++ b/x-pack/test/alerting_api_integration/observability/helpers/alerting_api_helper.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { ThresholdParams } from '@kbn/observability-plugin/common/custom_threshold_rule/types'; import type { SuperTest, Test } from 'supertest'; +import expect from '@kbn/expect'; +import { ThresholdParams } from '@kbn/observability-plugin/common/custom_threshold_rule/types'; export async function createIndexConnector({ supertest, @@ -64,5 +65,8 @@ export async function createRule({ rule_type_id: ruleTypeId, actions, }); + if (body.statusCode) { + expect(body.statusCode).eql(200, body.message); + } return body; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts index 375eeaaffc44..b7cf41d07e82 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts @@ -102,7 +102,6 @@ export default function createAlertTests({ getService }: FtrProviderContext) { group: 'default', params: {}, uuid: response.body.actions[0].uuid, - use_alert_data_for_template: false, }, ], enabled: true, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 67053bef7801..2e765d32ea9c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -12,6 +12,9 @@ import { bedrockSuccessResponse, } from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; import { DEFAULT_TOKEN_LIMIT } from '@kbn/stack-connectors-plugin/common/bedrock/constants'; +import { PassThrough } from 'stream'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; @@ -30,7 +33,9 @@ const defaultConfig = { export default function bedrockTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const objectRemover = new ObjectRemover(supertest); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const configService = getService('config'); + const retry = getService('retry'); const createConnector = async (apiUrl: string, spaceId?: string) => { const result = await supertest .post(`${getUrlPrefix(spaceId ?? 'default')}/api/actions/connector`) @@ -407,6 +412,104 @@ export default function bedrockTest({ getService }: FtrProviderContext) { data: { message: bedrockSuccessResponse.completion }, }); }); + + it('should invoke stream with assistant AI body argument formatted to bedrock expectations', async () => { + await new Promise((resolve, reject) => { + const passThrough = new PassThrough(); + + supertest + .post(`/internal/elastic_assistant/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .on('error', reject) + .send({ + params: { + subAction: 'invokeStream', + subActionParams: { + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }, + }, + assistantLangChain: false, + }) + .pipe(passThrough); + const responseBuffer: Uint8Array[] = []; + passThrough.on('data', (chunk) => { + responseBuffer.push(chunk); + }); + + passThrough.on('end', () => { + const parsed = parseBedrockBuffer(responseBuffer); + expect(parsed).to.eql('Hello world, what a unique string!'); + resolve(); + }); + }); + }); + + describe('Token tracking dashboard', () => { + const dashboardId = 'specific-dashboard-id-default'; + + it('should not create a dashboard when user does not have kibana event log permissions', async () => { + const { body } = await supertestWithoutAuth + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .auth('global_read', 'global_read-password') + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'getDashboard', + subActionParams: { + dashboardId, + }, + }, + }) + .expect(200); + + // check dashboard has not been created + await supertest + .get(`/api/saved_objects/dashboard/${dashboardId}`) + .set('kbn-xsrf', 'foo') + .expect(404); + expect(body).to.eql({ + status: 'ok', + connector_id: bedrockActionId, + data: { available: false }, + }); + }); + + it('should create a dashboard when user has correct permissions', async () => { + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'getDashboard', + subActionParams: { + dashboardId, + }, + }, + }) + .expect(200); + + // check dashboard has been created + await retry.try(async () => + supertest + .get(`/api/saved_objects/dashboard/${dashboardId}`) + .set('kbn-xsrf', 'foo') + .expect(200) + ); + + objectRemover.add('default', dashboardId, 'dashboard', 'saved_objects'); + + expect(body).to.eql({ + status: 'ok', + connector_id: bedrockActionId, + data: { available: true }, + }); + }); + }); }); }); @@ -479,3 +582,46 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); }); } + +const parseBedrockBuffer = (chunks: Uint8Array[]): string => { + let bedrockBuffer: Uint8Array = new Uint8Array(0); + + return chunks + .map((chunk) => { + bedrockBuffer = concatChunks(bedrockBuffer, chunk); + let messageLength = getMessageLength(bedrockBuffer); + const buildChunks = []; + while (bedrockBuffer.byteLength > 0 && bedrockBuffer.byteLength >= messageLength) { + const extractedChunk = bedrockBuffer.slice(0, messageLength); + buildChunks.push(extractedChunk); + bedrockBuffer = bedrockBuffer.slice(messageLength); + messageLength = getMessageLength(bedrockBuffer); + } + + const awsDecoder = new EventStreamCodec(toUtf8, fromUtf8); + + return buildChunks + .map((bChunk) => { + const event = awsDecoder.decode(bChunk); + const body = JSON.parse( + Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString() + ); + return body.completion; + }) + .join(''); + }) + .join(''); +}; + +function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array { + const newBuffer = new Uint8Array(a.length + b.length); + newBuffer.set(a); + newBuffer.set(b, a.length); + return newBuffer; +} + +function getMessageLength(buffer: Uint8Array): number { + if (buffer.byteLength === 0) return 0; + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + return view.getUint32(0, false); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index f13f9f839349..a0a906f0fa2a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -313,7 +313,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { data: genAiSuccessResponse, }); }); - describe('OpenAI dashboard', () => { + describe('Token tracking dashboard', () => { const dashboardId = 'specific-dashboard-id-default'; it('should not create a dashboard when user does not have kibana event log permissions', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts index 96f0694ef794..352559731351 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts @@ -466,7 +466,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [getChoices]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subAction]: expected value to equal [getChoices]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -484,7 +484,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.incident.short_description]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [getChoices]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.incident.short_description]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [getChoices]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -507,7 +507,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.incident.short_description]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [getChoices]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.incident.short_description]: expected value of type [string] but got [undefined]\n- [4.subAction]: expected value to equal [getChoices]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -534,7 +534,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [getChoices]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [getChoices]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -561,7 +561,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [getChoices]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [4.subAction]: expected value to equal [getChoices]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -583,7 +583,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subActionParams.fields]: expected value of type [array] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getFields]\n- [1.subAction]: expected value to equal [getIncident]\n- [2.subAction]: expected value to equal [handshake]\n- [3.subAction]: expected value to equal [pushToService]\n- [4.subActionParams.fields]: expected value of type [array] but got [undefined]\n- [5.subAction]: expected value to equal [closeIncident]', }); }); }); @@ -716,6 +716,32 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }); }); }); + + describe('closeIncident', () => { + it('should close the incident', async () => { + const { body: result } = await supertest + .post(`/api/actions/connector/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'closeIncident', + subActionParams: { + incident: { + correlation_id: 'custom_correlation_id', + }, + }, + }, + }) + .expect(200); + + expect(proxyHaveBeenCalled).to.equal(true); + expect(result).to.eql({ + status: 'ok', + connector_id: simulatedActionId, + data: {}, + }); + }); + }); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts index 1a2a69cd95d6..245425e0bbfe 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts @@ -38,16 +38,6 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./unmute_instance')); loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./update_api_key')); - loadTestFile(require.resolve('./alerts')); - loadTestFile(require.resolve('./event_log')); - loadTestFile(require.resolve('./mustache_templates')); - loadTestFile(require.resolve('./health')); - loadTestFile(require.resolve('./excluded')); - loadTestFile(require.resolve('./snooze')); - loadTestFile(require.resolve('./unsnooze')); - loadTestFile(require.resolve('./global_execution_log')); - loadTestFile(require.resolve('./get_global_execution_kpi')); - loadTestFile(require.resolve('./get_action_error_log')); }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts index ffd11e3fabd3..c948791e5ea4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts @@ -116,7 +116,6 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { params: {}, connector_type_id: 'test.noop', uuid: response.body.rules[0].actions[0].uuid, - use_alert_data_for_template: false, }, ]); expect(response.statusCode).to.eql(200); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/create_maintenance_window.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/create_maintenance_window.ts index cf0e2a3dcf6a..05a16cf99284 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/create_maintenance_window.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/create_maintenance_window.ts @@ -25,6 +25,32 @@ export default function createMaintenanceWindowTests({ getService }: FtrProvider tzid: 'UTC', freq: 2, // weekly }, + scoped_query: { + kql: "_id: '1234'", + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'kibana.alert.action_group', + field: 'kibana.alert.action_group', + params: { + query: 'test', + }, + type: 'phrase', + }, + $state: { + store: 'appState', + }, + query: { + match_phrase: { + 'kibana.alert.action_group': 'test', + }, + }, + }, + ], + }, }; afterEach(() => objectRemover.removeAll()); @@ -69,6 +95,7 @@ export default function createMaintenanceWindowTests({ getService }: FtrProvider expect(response.body.r_rule.dtstart).to.eql(createParams.r_rule.dtstart); expect(response.body.events.length).to.be.greaterThan(0); expect(response.body.status).to.eql('running'); + expect(response.body.scoped_query.kql).to.eql("_id: '1234'"); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -102,5 +129,19 @@ export default function createMaintenanceWindowTests({ getService }: FtrProvider }) .expect(400); }); + + it('should throw if creating maintenance window with invalid scoped query', async () => { + await supertest + .post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`) + .set('kbn-xsrf', 'foo') + .send({ + ...createParams, + scoped_query: { + kql: 'invalid_kql:', + filters: [], + }, + }) + .expect(400); + }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/update_maintenance_window.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/update_maintenance_window.ts index c5d38a1c2a05..8d26f316cb84 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/update_maintenance_window.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/maintenance_window/update_maintenance_window.ts @@ -16,6 +16,33 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const scopedQuery = { + kql: "_id: '1234'", + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'kibana.alert.action_group', + field: 'kibana.alert.action_group', + params: { + query: 'test', + }, + type: 'phrase', + }, + $state: { + store: 'appState', + }, + query: { + match_phrase: { + 'kibana.alert.action_group': 'test', + }, + }, + }, + ], + }; + describe('updateMaintenanceWindow', () => { const objectRemover = new ObjectRemover(supertest); const createParams = { @@ -26,6 +53,7 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider tzid: 'UTC', freq: 2, // weekly }, + scoped_query: scopedQuery, }; afterEach(() => objectRemover.removeAll()); @@ -82,6 +110,7 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider expect(response.body.r_rule.dtstart).to.eql(createParams.r_rule.dtstart); expect(response.body.events.length).to.be.greaterThan(0); expect(response.body.status).to.eql('running'); + expect(response.body.scoped_query.kql).to.eql("_id: '1234'"); break; default: throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); @@ -156,6 +185,7 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider until: moment.utc().add(1, 'week').toISOString(), }, category_ids: ['management'], + scoped_query: scopedQuery, }) .expect(200); @@ -183,6 +213,7 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider ...createParams, r_rule: updatedRRule, category_ids: null, + scoped_query: null, }) .expect(200); @@ -194,6 +225,7 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider expect(response.body.data[0].id).to.eql(createdMaintenanceWindow.id); expect(response.body.data[0].r_rule).to.eql(updatedRRule); expect(response.body.data[0].category_ids).to.eql(null); + expect(response.body.data[0].scoped_query).to.eql(null); }); it('should throw if updating maintenance window with invalid category ids', async () => { @@ -230,5 +262,46 @@ export default function updateMaintenanceWindowTests({ getService }: FtrProvider .send({ category_ids: ['something-else'] }) .expect(400); }); + + it('should throw if updating maintenance window with invalid scoped query', async () => { + const { body: createdMaintenanceWindow } = await supertest + .post(`${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window`) + .set('kbn-xsrf', 'foo') + .send({ + title: 'test-maintenance-window', + duration: 60 * 60 * 1000, // 1 hr + r_rule: { + dtstart: new Date().toISOString(), + tzid: 'UTC', + freq: 2, // weekly + count: 1, + }, + scoped_query: scopedQuery, + }) + .expect(200); + + objectRemover.add( + 'space1', + createdMaintenanceWindow.id, + 'rules/maintenance_window', + 'alerting', + true + ); + + await supertest + .post( + `${getUrlPrefix('space1')}/internal/alerting/rules/maintenance_window/${ + createdMaintenanceWindow.id + }` + ) + .set('kbn-xsrf', 'foo') + .send({ + scoped_query: { + kql: 'invalid_kql:', + filters: [], + }, + }) + .expect(400); + }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/config.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/config.ts new file mode 100644 index 000000000000..f999da061b90 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/config.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig('security_and_spaces', { + disabledPlugins: [], + license: 'trial', + ssl: true, + enableActionsProxy: true, + publicBaseUrl: true, + testFiles: [require.resolve('./tests')], + useDedicatedTaskRunner: true, +}); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/config_non_dedicated_task_runner.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/config_non_dedicated_task_runner.ts new file mode 100644 index 000000000000..7aed7501bc01 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/config_non_dedicated_task_runner.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig('security_and_spaces', { + disabledPlugins: [], + license: 'trial', + ssl: true, + enableActionsProxy: true, + publicBaseUrl: true, + testFiles: [require.resolve('./tests')], + useDedicatedTaskRunner: false, +}); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/alerts.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/event_log.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/excluded.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/excluded.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/excluded.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/excluded.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_action_error_log.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_action_error_log.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_action_error_log.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_global_execution_kpi.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_global_execution_kpi.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_global_execution_kpi.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_global_execution_kpi.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_rule_execution_kpi.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_rule_execution_kpi.ts similarity index 97% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_rule_execution_kpi.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_rule_execution_kpi.ts index 2303fc616d8d..3eb6a8c61d00 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/get_rule_execution_kpi.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/get_rule_execution_kpi.ts @@ -17,7 +17,8 @@ export default function getRuleExecutionKpiTests({ getService }: FtrProviderCont const retry = getService('retry'); - describe('getRuleExecutionKpi', () => { + // failing on CI, this file wasn't loaded in any config + describe.skip('getRuleExecutionKpi', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/global_execution_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/global_execution_log.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/global_execution_log.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/global_execution_log.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/health.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/health.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/health.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/health.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/index.ts new file mode 100644 index 000000000000..8eb5a0c2006b --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { setupSpacesAndUsers, tearDown } from '../../../setup'; + +// eslint-disable-next-line import/no-default-export +export default function alertingTests({ loadTestFile, getService }: FtrProviderContext) { + describe('Alerts', () => { + describe('alerts', () => { + before(async () => { + await setupSpacesAndUsers(getService); + }); + + after(async () => { + await tearDown(getService); + }); + + loadTestFile(require.resolve('./alerts')); + loadTestFile(require.resolve('./event_log')); + loadTestFile(require.resolve('./mustache_templates')); + loadTestFile(require.resolve('./health')); + loadTestFile(require.resolve('./excluded')); + loadTestFile(require.resolve('./snooze')); + loadTestFile(require.resolve('./unsnooze')); + loadTestFile(require.resolve('./global_execution_log')); + loadTestFile(require.resolve('./get_global_execution_kpi')); + loadTestFile(require.resolve('./get_action_error_log')); + loadTestFile(require.resolve('./get_rule_execution_kpi')); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mustache_templates.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/mustache_templates.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mustache_templates.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/mustache_templates.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/snooze.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/snooze.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unsnooze.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts similarity index 100% rename from x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unsnooze.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/index.ts new file mode 100644 index 000000000000..3fa3bbd08789 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function alertingApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('alerting api integration security and spaces enabled - Group 4', function () { + loadTestFile(require.resolve('./alerting')); + }); +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts index 0577425103a8..eb9f90cb41f2 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts @@ -78,7 +78,6 @@ export default function createAlertTests({ getService }: FtrProviderContext) { group: 'default', params: {}, uuid: response.body.actions[0].uuid, - use_alert_data_for_template: false, }, ], enabled: true, @@ -182,7 +181,6 @@ export default function createAlertTests({ getService }: FtrProviderContext) { group: 'default', params: {}, uuid: response.body.actions[0].uuid, - use_alert_data_for_template: false, }, { id: 'my-slack1', @@ -192,7 +190,6 @@ export default function createAlertTests({ getService }: FtrProviderContext) { message: 'something important happened!', }, uuid: response.body.actions[1].uuid, - use_alert_data_for_template: false, }, { id: 'system-connector-test.system-action', @@ -200,7 +197,6 @@ export default function createAlertTests({ getService }: FtrProviderContext) { connector_type_id: 'test.system-action', params: {}, uuid: response.body.actions[2].uuid, - use_alert_data_for_template: false, }, ], enabled: true, diff --git a/x-pack/test/api_integration/apis/aiops/log_rate_analysis_full_analysis.ts b/x-pack/test/api_integration/apis/aiops/log_rate_analysis_full_analysis.ts index 3168dfdfc5ec..352282b4ba41 100644 --- a/x-pack/test/api_integration/apis/aiops/log_rate_analysis_full_analysis.ts +++ b/x-pack/test/api_integration/apis/aiops/log_rate_analysis_full_analysis.ts @@ -86,9 +86,14 @@ export default ({ getService }: FtrProviderContext) => { const groupActions = getGroupActions(data, apiVersion); const groups = groupActions.flatMap((d) => d.payload); - expect(orderBy(groups, ['docCount'], ['desc'])).to.eql( - orderBy(testData.expected.groups, ['docCount'], ['desc']), - 'Grouping result does not match expected values.' + const actualGroups = orderBy(groups, ['docCount'], ['desc']); + const expectedGroups = orderBy(testData.expected.groups, ['docCount'], ['desc']); + + expect(actualGroups).to.eql( + expectedGroups, + `Grouping result does not match expected values. Expected ${JSON.stringify( + expectedGroups + )}, got ${JSON.stringify(actualGroups)}` ); const groupHistogramActions = getGroupHistogramActions(data, apiVersion); diff --git a/x-pack/test/api_integration/apis/aiops/test_data.ts b/x-pack/test/api_integration/apis/aiops/test_data.ts index 291779ed6c7b..3c1793ab9efe 100644 --- a/x-pack/test/api_integration/apis/aiops/test_data.ts +++ b/x-pack/test/api_integration/apis/aiops/test_data.ts @@ -12,6 +12,8 @@ import { significantTerms as artificialLogSignificantTerms } from '@kbn/aiops-pl import { significantLogPatterns as artificialLogSignificantLogPatterns } from '@kbn/aiops-plugin/common/__mocks__/artificial_logs/significant_log_patterns'; import { finalSignificantItemGroups as artificialLogsSignificantItemGroups } from '@kbn/aiops-plugin/common/__mocks__/artificial_logs/final_significant_item_groups'; import { finalSignificantItemGroupsTextfield as artificialLogsSignificantItemGroupsTextfield } from '@kbn/aiops-plugin/common/__mocks__/artificial_logs/final_significant_item_groups_textfield'; +import { topTerms } from '@kbn/aiops-plugin/common/__mocks__/artificial_logs/top_terms'; +import { topTermsGroups } from '@kbn/aiops-plugin/common/__mocks__/artificial_logs/top_terms_groups'; import type { AiopsLogRateAnalysisSchema, @@ -39,9 +41,9 @@ export const getLogRateAnalysisTestData = (): Array, expected: { - chunksLength: 35, + chunksLength: 36, chunksLengthGroupOnly: 5, - actionsLength: 34, + actionsLength: 35, actionsLengthGroupOnly: 4, noIndexChunksLength: 4, noIndexActionsLength: 3, @@ -78,14 +80,14 @@ export const getLogRateAnalysisTestData = (): Array(): Array, expected: { - chunksLength: 27, + chunksLength: 28, chunksLengthGroupOnly: 11, - actionsLength: 26, + actionsLength: 27, actionsLengthGroupOnly: 10, noIndexChunksLength: 4, noIndexActionsLength: 3, @@ -104,6 +106,60 @@ export const getLogRateAnalysisTestData = (): Array, + expected: { + chunksLength: 62, + chunksLengthGroupOnly: 32, + actionsLength: 61, + actionsLengthGroupOnly: 31, + noIndexChunksLength: 4, + noIndexActionsLength: 3, + significantItems: topTerms, + groups: topTermsGroups, + histogramLength: 20, + }, + }, + { + testName: 'artificial_logs_with_dip_zerodocsfallback', + dataGenerator: 'artificial_logs_with_dip_zerodocsfallback', + requestBody: { + start: 0, + end: 1768855600010, + searchQuery: '{"match_all":{}}', + timeFieldName: '@timestamp', + index: 'artificial_logs_with_dip_zerodocsfallback', + baselineMin: 1768855600000, + baselineMax: 1768855600010, + deviationMin: 1668855600000, + deviationMax: 1668924000000, + grouping: true, + } as AiopsLogRateAnalysisSchema, + expected: { + chunksLength: 62, + chunksLengthGroupOnly: 32, + actionsLength: 61, + actionsLengthGroupOnly: 31, + noIndexChunksLength: 4, + noIndexActionsLength: 3, + significantItems: topTerms, + groups: topTermsGroups, + histogramLength: 20, + }, + }, { testName: 'artificial_logs_with_spike_textfield', dataGenerator: 'artificial_logs_with_spike_textfield', @@ -120,9 +176,9 @@ export const getLogRateAnalysisTestData = (): Array, expected: { - chunksLength: 30, + chunksLength: 31, chunksLengthGroupOnly: 11, - actionsLength: 29, + actionsLength: 30, actionsLengthGroupOnly: 10, noIndexChunksLength: 4, noIndexActionsLength: 3, @@ -132,14 +188,14 @@ export const getLogRateAnalysisTestData = (): Array(): Array, expected: { - chunksLength: 27, + chunksLength: 28, chunksLengthGroupOnly: 11, - actionsLength: 26, + actionsLength: 27, actionsLengthGroupOnly: 10, noIndexChunksLength: 4, noIndexActionsLength: 3, @@ -174,9 +230,9 @@ export const getLogRateAnalysisTestData = (): Array, expected: { - chunksLength: 30, + chunksLength: 31, chunksLengthGroupOnly: 11, - actionsLength: 29, + actionsLength: 30, actionsLengthGroupOnly: 10, noIndexChunksLength: 4, noIndexActionsLength: 3, diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/assets.ts b/x-pack/test/api_integration/apis/asset_manager/tests/assets.ts new file mode 100644 index 000000000000..dc140d3cea76 --- /dev/null +++ b/x-pack/test/api_integration/apis/asset_manager/tests/assets.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { ASSETS_ENDPOINT } from './constants'; +import { FtrProviderContext } from '../types'; +import { generateHostsData, generateServicesData } from './helpers'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const synthtraceApm = getService('apmSynthtraceEsClient'); + const synthtraceInfra = getService('infraSynthtraceEsClient'); + + describe('GET /assets', () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + + beforeEach(async () => { + await synthtraceApm.clean(); + await synthtraceInfra.clean(); + }); + + it('should return all assets', async () => { + await Promise.all([ + synthtraceInfra.index(generateHostsData({ from, to, count: 5 })), + synthtraceApm.index(generateServicesData({ from, to, count: 5 })), + ]); + + const response = await supertest + .get(ASSETS_ENDPOINT) + .query({ + from, + to, + }) + .expect(200); + + expect(response.body).to.have.property('assets'); + expect(response.body.assets.length).to.equal(10); + }); + + it('supports only hosts and services', async () => { + await supertest + .get(ASSETS_ENDPOINT) + .query({ + from, + to, + stringFilters: JSON.stringify({ kind: ['host', 'service'] }), + }) + .expect(200); + + await supertest + .get(ASSETS_ENDPOINT) + .query({ + from, + to, + stringFilters: JSON.stringify({ kind: ['container', 'host'] }), + }) + .expect(400); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts b/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts index 721fda8345c0..8983b139d946 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts @@ -7,6 +7,7 @@ import type { AssetWithoutTimestamp } from '@kbn/assetManager-plugin/common/types_api'; import type { WriteSamplesPostBody } from '@kbn/assetManager-plugin/server'; +import { apm, infra, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { SuperTest, Test } from 'supertest'; @@ -43,3 +44,61 @@ export async function viewSampleAssetDocs(supertest: KibanaSupertest) { expect(response.body).to.have.property('results'); return response.body.results as AssetWithoutTimestamp[]; } + +export function generateServicesData({ + from, + to, + count = 1, +}: { + from: string; + to: string; + count: number; +}) { + const range = timerange(from, to); + + const services = Array(count) + .fill(0) + .map((_, idx) => + apm + .service({ + name: `service-${idx}`, + environment: 'production', + agentName: 'nodejs', + }) + .instance(`my-host-${idx}`) + ); + + return range + .interval('1m') + .rate(1) + .generator((timestamp, index) => + services.map((service) => + service + .transaction({ transactionName: 'GET /foo' }) + .timestamp(timestamp) + .duration(500) + .success() + ) + ); +} + +export function generateHostsData({ + from, + to, + count = 1, +}: { + from: string; + to: string; + count: number; +}) { + const range = timerange(from, to); + + const hosts = Array(count) + .fill(0) + .map((_, idx) => infra.host(`my-host-${idx}`)); + + return range + .interval('1m') + .rate(1) + .generator((timestamp, index) => hosts.map((host) => host.metrics().timestamp(timestamp))); +} diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/hosts.ts b/x-pack/test/api_integration/apis/asset_manager/tests/hosts.ts index 2459a2d2fb7b..ac5d3302c9e4 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/hosts.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/hosts.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { timerange, infra } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { Asset } from '@kbn/assetManager-plugin/common/types_api'; import { ASSETS_ENDPOINT } from './constants'; import { FtrProviderContext } from '../types'; +import { generateHostsData } from './helpers'; const HOSTS_ASSETS_ENDPOINT = `${ASSETS_ENDPOINT}/hosts`; @@ -87,16 +87,3 @@ export default function ({ getService }: FtrProviderContext) { }); }); } - -function generateHostsData({ from, to, count = 1 }: { from: string; to: string; count: number }) { - const range = timerange(from, to); - - const hosts = Array(count) - .fill(0) - .map((_, idx) => infra.host(`my-host-${idx}`)); - - return range - .interval('1m') - .rate(1) - .generator((timestamp, index) => hosts.map((host) => host.metrics().timestamp(timestamp))); -} diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/index.ts b/x-pack/test/api_integration/apis/asset_manager/tests/index.ts index e2ea53990b21..8f8295db4dd0 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/index.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/index.ts @@ -12,6 +12,8 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./containers')); loadTestFile(require.resolve('./hosts')); loadTestFile(require.resolve('./services')); + loadTestFile(require.resolve('./pods')); loadTestFile(require.resolve('./sample_assets')); + loadTestFile(require.resolve('./assets')); }); } diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/pods.ts b/x-pack/test/api_integration/apis/asset_manager/tests/pods.ts new file mode 100644 index 000000000000..eb88049b6511 --- /dev/null +++ b/x-pack/test/api_integration/apis/asset_manager/tests/pods.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { timerange, infra } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { Asset } from '@kbn/assetManager-plugin/common/types_api'; +import * as routePaths from '@kbn/assetManager-plugin/common/constants_routes'; +import { FtrProviderContext } from '../types'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const synthtrace = getService('infraSynthtraceEsClient'); + + describe(`GET ${routePaths.GET_PODS}`, () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + + beforeEach(async () => { + await synthtrace.clean(); + }); + + it('should return pod assets', async () => { + await synthtrace.index(generatePodsData({ from, to, count: 5 })); + + const response = await supertest + .get(routePaths.GET_PODS) + .query({ + from, + to, + }) + .expect(200); + + expect(response.body).to.have.property('pods'); + expect(response.body.pods.length).to.equal(5); + }); + + it('should return a specific pod asset by EAN', async () => { + await synthtrace.index(generatePodsData({ from, to, count: 5 })); + const testEan = 'pod:pod-uid-1'; + + const response = await supertest + .get(routePaths.GET_PODS) + .query({ + from, + to, + stringFilters: JSON.stringify({ ean: testEan }), + }) + .expect(200); + + expect(response.body).to.have.property('pods'); + expect(response.body.pods.length).to.equal(1); + expect(response.body.pods[0]['asset.ean']).to.equal(testEan); + }); + + it('should return a filtered list of pods assets by ID wildcard pattern', async () => { + await synthtrace.index(generatePodsData({ from, to, count: 15 })); + const testIdPattern = '*id-1*'; + + const response = await supertest + .get(routePaths.GET_PODS) + .query({ + from, + to, + stringFilters: JSON.stringify({ id: testIdPattern }), + }) + .expect(200); + + expect(response.body).to.have.property('pods'); + expect(response.body.pods.length).to.equal(6); + + const ids = response.body.pods.map((result: Asset) => result['asset.id'][0]); + + expect(ids).to.eql([ + 'pod-uid-1', + 'pod-uid-10', + 'pod-uid-11', + 'pod-uid-12', + 'pod-uid-13', + 'pod-uid-14', + ]); + }); + }); +} + +function generatePodsData({ from, to, count = 1 }: { from: string; to: string; count: number }) { + const range = timerange(from, to); + + const pods = Array(count) + .fill(0) + .map((_, idx) => infra.pod(`pod-uid-${idx}`, `node-name-${idx}`)); + + return range + .interval('1m') + .rate(1) + .generator((timestamp) => pods.map((pod) => pod.metrics().timestamp(timestamp))); +} diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/services.ts b/x-pack/test/api_integration/apis/asset_manager/tests/services.ts index dc00a025021c..ae92a646b3b2 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/services.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/services.ts @@ -6,10 +6,10 @@ */ import { omit } from 'lodash'; -import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { ASSETS_ENDPOINT } from './constants'; import { FtrProviderContext } from '../types'; +import { generateServicesData } from './helpers'; const SERVICES_ASSETS_ENDPOINT = `${ASSETS_ENDPOINT}/services`; @@ -39,7 +39,7 @@ export default function ({ getService }: FtrProviderContext) { expect(response.body.services.length).to.equal(2); }); - it('should return services running on specified host', async () => { + it('should return specific service', async () => { const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); const to = new Date().toISOString(); await synthtrace.index(generateServicesData({ from, to, count: 5 })); @@ -49,7 +49,7 @@ export default function ({ getService }: FtrProviderContext) { .query({ from, to, - parent: 'host:my-host-1', + stringFilters: JSON.stringify({ ean: 'service:service-4' }), }) .expect(200); @@ -57,49 +57,38 @@ export default function ({ getService }: FtrProviderContext) { expect(response.body.services.length).to.equal(1); expect(omit(response.body.services[0], ['@timestamp'])).to.eql({ 'asset.kind': 'service', - 'asset.id': 'service-1', - 'asset.ean': 'service:service-1', + 'asset.id': 'service-4', + 'asset.ean': 'service:service-4', 'asset.references': [], 'asset.parents': [], 'service.environment': 'production', }); }); - }); -} -function generateServicesData({ - from, - to, - count = 1, -}: { - from: string; - to: string; - count: number; -}) { - const range = timerange(from, to); + it('should return services running on specified host', async () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + await synthtrace.index(generateServicesData({ from, to, count: 5 })); - const services = Array(count) - .fill(0) - .map((_, idx) => - apm - .service({ - name: `service-${idx}`, - environment: 'production', - agentName: 'nodejs', + const response = await supertest + .get(SERVICES_ASSETS_ENDPOINT) + .query({ + from, + to, + stringFilters: JSON.stringify({ parentEan: 'host:my-host-1' }), }) - .instance(`my-host-${idx}`) - ); + .expect(200); - return range - .interval('1m') - .rate(1) - .generator((timestamp, index) => - services.map((service) => - service - .transaction({ transactionName: 'GET /foo' }) - .timestamp(timestamp) - .duration(500) - .success() - ) - ); + expect(response.body).to.have.property('services'); + expect(response.body.services.length).to.equal(1); + expect(omit(response.body.services[0], ['@timestamp'])).to.eql({ + 'asset.kind': 'service', + 'asset.id': 'service-1', + 'asset.ean': 'service:service-1', + 'asset.references': [], + 'asset.parents': [], + 'service.environment': 'production', + }); + }); + }); } diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/mock_data.ts b/x-pack/test/api_integration/apis/cloud_security_posture/mock_data.ts index 4ebfacb4d10c..b4daf5172b16 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/mock_data.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/mock_data.ts @@ -24,6 +24,10 @@ export const findingsMockData = [ type: 'process', }, cluster_id: 'Upper case cluster id', + event: { + ingested: '2023-08-19T18:20:41Z', + created: '2023-08-19T18:17:15.609124281Z', + }, }, { resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, @@ -40,6 +44,10 @@ export const findingsMockData = [ type: 'process', }, cluster_id: 'Another Upper case cluster id', + event: { + ingested: '2023-08-19T18:20:41Z', + created: '2023-08-19T18:17:15.609124281Z', + }, }, ]; diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts index 6a3f8fbbfeda..06f80adf4603 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts @@ -247,8 +247,8 @@ export default function (providerContext: FtrProviderContext) { `expected unprivileged but got ${res.cspm.status} instead` ); expect(res.vuln_mgmt.status).to.eql( - 'not-installed', - `expected not-installed but got ${res.vuln_mgmt.status} instead` + 'unprivileged', + `expected unprivileged but got ${res.vuln_mgmt.status} instead` ); assertIndexStatus(res.indicesDetails, LATEST_FINDINGS_INDEX_DEFAULT_NS, 'unprivileged'); diff --git a/x-pack/test/api_integration/apis/grok_debugger/config.ts b/x-pack/test/api_integration/apis/grok_debugger/config.ts new file mode 100644 index 000000000000..5f335f116fef --- /dev/null +++ b/x-pack/test/api_integration/apis/grok_debugger/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts')); + + return { + ...baseIntegrationTestsConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/api_integration/apis/grok_debugger/grok_debugger.ts b/x-pack/test/api_integration/apis/grok_debugger/grok_debugger.ts new file mode 100644 index 000000000000..d7e47d7c62e0 --- /dev/null +++ b/x-pack/test/api_integration/apis/grok_debugger/grok_debugger.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +const API_BASE_PATH = '/api/grokdebugger'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('Grok Debugger Routes', function () { + describe('Simulate', () => { + it('should simulate a valid pattern', async () => { + const rawEvent = '55.3.244.1 GET /index.html 15824 0.043'; + const pattern = + '%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}'; + const requestBody = { rawEvent, pattern }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set('kbn-xsrf', 'xxx') + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + const expectedStructuredEvent = { + duration: '0.043', + request: '/index.html', + method: 'GET', + bytes: '15824', + client: '55.3.244.1', + }; + + expect(body.structuredEvent).to.eql(expectedStructuredEvent); + expect(body.error).to.be.empty(); + }); + + it('should return error response for invalid pattern', async () => { + const rawEvent = '55.3.244.1 GET /index.html 15824 0.043'; + const invalidPattern = 'test'; + const requestBody = { rawEvent, pattern: invalidPattern }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set('kbn-xsrf', 'xxx') + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + expect(body.error).to.eql('Provided Grok patterns do not match data in the input'); + expect(body.structuredEvent).to.be.empty(); + }); + + it('should simulate with a valid custom pattern', async () => { + const rawEvent = + 'Jan 1 06:25:43 mailserver14 postfix/cleanup[21403]: BEF25A72965: message-id=<20130101142543.5828399CCAF@mailserver14.example.com>'; + const pattern = '%{SYSLOGBASE} %{POSTFIX_QUEUEID:queue_id}: %{MSG:syslog_message}'; + const customPatterns = { + MSG: 'message-id=<%{GREEDYDATA}>', + POSTFIX_QUEUEID: '[0-9A-F]{10,11}', + }; + const requestBody = { rawEvent, pattern, customPatterns }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set('kbn-xsrf', 'xxx') + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + const expectedStructuredEvent = { + pid: '21403', + program: 'postfix/cleanup', + logsource: 'mailserver14', + syslog_message: 'message-id=<20130101142543.5828399CCAF@mailserver14.example.com>', + queue_id: 'BEF25A72965', + timestamp: 'Jan 1 06:25:43', + }; + + expect(body.structuredEvent).to.eql(expectedStructuredEvent); + expect(body.error).to.be.empty(); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/grok_debugger/index.ts b/x-pack/test/api_integration/apis/grok_debugger/index.ts new file mode 100644 index 000000000000..1c5a3993caa3 --- /dev/null +++ b/x-pack/test/api_integration/apis/grok_debugger/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Grok Debugger', () => { + loadTestFile(require.resolve('./grok_debugger')); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.helpers.ts b/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.helpers.ts deleted file mode 100644 index 8dabd89bf7c2..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.helpers.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH } from './constants'; - -export const registerHelpers = ({ supertest }: { supertest: any }) => { - const getNodesPlugins = () => supertest.get(`${API_BASE_PATH}/nodes/plugins`); - - return { - getNodesPlugins, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.ts b/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.ts index e885b677aaff..72ca2d8fee5b 100644 --- a/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.ts +++ b/x-pack/test/api_integration/apis/management/index_management/cluster_nodes.ts @@ -8,12 +8,10 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { registerHelpers } from './cluster_nodes.helpers'; +import { clusterNodesApi } from './lib/cluster_nodes.api'; export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - - const { getNodesPlugins } = registerHelpers({ supertest }); + const { getNodesPlugins } = clusterNodesApi(getService); describe('nodes', () => { it('should fetch the nodes plugins', async () => { diff --git a/x-pack/test/api_integration/apis/management/index_management/component_templates.ts b/x-pack/test/api_integration/apis/management/index_management/component_templates.ts index 01e7ae46ce8f..f41dedccb126 100644 --- a/x-pack/test/api_integration/apis/management/index_management/component_templates.ts +++ b/x-pack/test/api_integration/apis/management/index_management/component_templates.ts @@ -8,26 +8,35 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -// @ts-ignore -import { initElasticsearchHelpers } from './lib'; -// @ts-ignore +import { componentTemplatesApi } from './lib/component_templates.api'; +import { componentTemplateHelpers } from './lib/component_template.helpers'; import { API_BASE_PATH } from './constants'; +const CACHE_TEMPLATES = true; + export default function ({ getService }: FtrProviderContext) { + const log = getService('log'); const supertest = getService('supertest'); const { createComponentTemplate, - createIndexTemplate, - cleanUpIndexTemplates, - cleanUpComponentTemplates, + getAllComponentTemplates, + getOneComponentTemplate, + updateComponentTemplate, deleteComponentTemplate, + getComponentTemplateDatastreams, + } = componentTemplatesApi(getService); + const { + addDatastream, + addIndexTemplate, + addComponentTemplate, + removeComponentTemplate, cleanupDatastreams, - createDatastream, - } = initElasticsearchHelpers(getService); + cleanUpIndexTemplates, + cleanUpComponentTemplates, + } = componentTemplateHelpers(getService); - // FLAKY: https://github.com/elastic/kibana/issues/170999 - describe.skip('Component templates', function () { + describe('Component templates', function () { after(async () => { await cleanUpIndexTemplates(); await cleanUpComponentTemplates(); @@ -63,20 +72,16 @@ export default function ({ getService }: FtrProviderContext) { // Create component template to verify GET requests before(async () => { try { - await createComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, true); + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); } catch (err) { - // eslint-disable-next-line no-console - console.log('[Setup error] Error creating component template'); + log.debug('[Setup error] Error creating component template'); throw err; } }); describe('all component templates', () => { it('should return an array of component templates', async () => { - const { body: componentTemplates } = await supertest - .get(`${API_BASE_PATH}/component_templates`) - .set('kbn-xsrf', 'xxx') - .expect(200); + const { body: componentTemplates } = await getAllComponentTemplates().expect(200); const testComponentTemplate = componentTemplates.find( ({ name }: { name: string }) => name === COMPONENT_NAME @@ -95,9 +100,7 @@ export default function ({ getService }: FtrProviderContext) { describe('one component template', () => { it('should return a single component template', async () => { - const uri = `${API_BASE_PATH}/component_templates/${COMPONENT_NAME}`; - - const { body } = await supertest.get(uri).set('kbn-xsrf', 'xxx').expect(200); + const { body } = await getOneComponentTemplate(COMPONENT_NAME).expect(200); expect(body).to.eql({ name: COMPONENT_NAME, @@ -118,53 +121,48 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { // Clean up any component templates created in test cases await Promise.all( - [COMPONENT_NAME, REQUIRED_FIELDS_COMPONENT_NAME].map(deleteComponentTemplate) + [COMPONENT_NAME, REQUIRED_FIELDS_COMPONENT_NAME].map(removeComponentTemplate) ).catch((err) => { - // eslint-disable-next-line no-console - console.log(`[Cleanup error] Error deleting component templates: ${err.message}`); + log.debug(`[Cleanup error] Error deleting component templates: ${err.message}`); throw err; }); }); it('should create a component template', async () => { - const { body } = await supertest - .post(`${API_BASE_PATH}/component_templates`) - .set('kbn-xsrf', 'xxx') - .send({ - name: COMPONENT_NAME, - version: 1, - template: { - settings: { - number_of_shards: 1, - }, - aliases: { - alias1: {}, - }, - mappings: { - properties: { - host_name: { - type: 'keyword', - }, + const { body } = await createComponentTemplate(COMPONENT_NAME, { + version: 1, + template: { + settings: { + number_of_shards: 1, + }, + aliases: { + alias1: {}, + }, + mappings: { + properties: { + host_name: { + type: 'keyword', }, }, - lifecycle: { - enabled: true, - data_retention: '2d', - }, }, - _meta: { - description: 'set number of shards to one', - serialization: { - class: 'MyComponentTemplate', - id: 10, - }, + lifecycle: { + // @ts-expect-error @elastic/elasticsearch enabled prop is still not in the ES types + enabled: true, + data_retention: '2d', }, - _kbnMeta: { - usedBy: [], - isManaged: false, + }, + _meta: { + description: 'set number of shards to one', + serialization: { + class: 'MyComponentTemplate', + id: 10, }, - }) - .expect(200); + }, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(200); expect(body).to.eql({ acknowledged: true, @@ -172,19 +170,14 @@ export default function ({ getService }: FtrProviderContext) { }); it('should create a component template with only required fields', async () => { - const { body } = await supertest - .post(`${API_BASE_PATH}/component_templates`) - .set('kbn-xsrf', 'xxx') + const { body } = await createComponentTemplate(REQUIRED_FIELDS_COMPONENT_NAME, { // Excludes version and _meta fields - .send({ - name: REQUIRED_FIELDS_COMPONENT_NAME, - template: {}, - _kbnMeta: { - usedBy: [], - isManaged: false, - }, - }) - .expect(200); + template: {}, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(200); expect(body).to.eql({ acknowledged: true, @@ -192,18 +185,13 @@ export default function ({ getService }: FtrProviderContext) { }); it('should not allow creation of a component template with the same name of an existing one', async () => { - const { body } = await supertest - .post(`${API_BASE_PATH}/component_templates`) - .set('kbn-xsrf', 'xxx') - .send({ - name: COMPONENT_NAME, - template: {}, - _kbnMeta: { - usedBy: [], - isManaged: false, - }, - }) - .expect(409); + const { body } = await createComponentTemplate(COMPONENT_NAME, { + template: {}, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(409); expect(body).to.eql({ statusCode: 409, @@ -242,30 +230,22 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { // Create component template that can be used to test PUT request try { - await createComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, true); + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); } catch (err) { - // eslint-disable-next-line no-console - console.log('[Setup error] Error creating component template'); + log.debug('[Setup error] Error creating component template'); throw err; } }); it('should allow an existing component template to be updated', async () => { - const uri = `${API_BASE_PATH}/component_templates/${COMPONENT_NAME}`; - - const { body } = await supertest - .put(uri) - .set('kbn-xsrf', 'xxx') - .send({ - ...COMPONENT, - name: COMPONENT_NAME, - version: 1, - _kbnMeta: { - usedBy: [], - isManaged: false, - }, - }) - .expect(200); + const { body } = await updateComponentTemplate(COMPONENT_NAME, { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(200); expect(body).to.eql({ acknowledged: true, @@ -273,21 +253,14 @@ export default function ({ getService }: FtrProviderContext) { }); it('should not allow a non-existing component template to be updated', async () => { - const uri = `${API_BASE_PATH}/component_templates/component_does_not_exist`; - - const { body } = await supertest - .put(uri) - .set('kbn-xsrf', 'xxx') - .send({ - ...COMPONENT, - name: 'component_does_not_exist', - version: 1, - _kbnMeta: { - usedBy: [], - isManaged: false, - }, - }) - .expect(404); + const { body } = await updateComponentTemplate('component_does_not_exist', { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(404); expect(body).to.eql({ statusCode: 404, @@ -329,20 +302,17 @@ export default function ({ getService }: FtrProviderContext) { // Create several component templates that can be used to test deletion await Promise.all( [componentTemplateA, componentTemplateB, componentTemplateC, componentTemplateD].map( - (template) => createComponentTemplate(template, false) + (template) => addComponentTemplate(template, !CACHE_TEMPLATES) ) ).catch((err) => { - // eslint-disable-next-line no-console - console.log(`[Setup error] Error creating component templates: ${err.message}`); + log.debug(`[Setup error] Error creating component templates: ${err.message}`); throw err; }); }); it('should delete a component template', async () => { const { name } = componentTemplateA; - const uri = `${API_BASE_PATH}/component_templates/${name}`; - - const { body } = await supertest.delete(uri).set('kbn-xsrf', 'xxx').expect(200); + const { body } = await deleteComponentTemplate(name).expect(200); expect(body).to.eql({ itemsDeleted: [name], @@ -354,11 +324,11 @@ export default function ({ getService }: FtrProviderContext) { const { name: componentTemplate1Name } = componentTemplateB; const { name: componentTemplate2Name } = componentTemplateC; - const uri = `${API_BASE_PATH}/component_templates/${componentTemplate1Name},${componentTemplate2Name}`; - const { body: { itemsDeleted, errors }, - } = await supertest.delete(uri).set('kbn-xsrf', 'xxx').expect(200); + } = await deleteComponentTemplate( + `${componentTemplate1Name},${componentTemplate2Name}` + ).expect(200); expect(errors).to.eql([]); @@ -372,9 +342,9 @@ export default function ({ getService }: FtrProviderContext) { const COMPONENT_DOES_NOT_EXIST = 'component_does_not_exist'; const { name: componentTemplateName } = componentTemplateD; - const uri = `${API_BASE_PATH}/component_templates/${componentTemplateName},${COMPONENT_DOES_NOT_EXIST}`; - - const { body } = await supertest.delete(uri).set('kbn-xsrf', 'xxx').expect(200); + const { body } = await deleteComponentTemplate( + `${componentTemplateName},${COMPONENT_DOES_NOT_EXIST}` + ).expect(200); expect(body.itemsDeleted).to.eql([componentTemplateName]); expect(body.errors[0].name).to.eql(COMPONENT_DOES_NOT_EXIST); @@ -442,20 +412,17 @@ export default function ({ getService }: FtrProviderContext) { // Create component template to verify GET requests before(async () => { try { - await createComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, true); - await createIndexTemplate({ body: TEMPLATE, name: TEMPLATE_NAME }, true); + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); + await addIndexTemplate({ body: TEMPLATE, name: TEMPLATE_NAME }, CACHE_TEMPLATES); } catch (err) { - // eslint-disable-next-line no-console - console.log('[Setup error] Error creating component template'); + log.debug('[Setup error] Error creating component template'); throw err; } }); describe('without datastreams', () => { it('should return no datastreams', async () => { - const uri = `${API_BASE_PATH}/component_templates/${COMPONENT_NAME}/datastreams`; - - const { body } = await supertest.get(uri).set('kbn-xsrf', 'xxx').expect(200); + const { body } = await getComponentTemplateDatastreams(COMPONENT_NAME).expect(200); expect(body).to.eql({ data_streams: [] }); }); @@ -463,12 +430,10 @@ export default function ({ getService }: FtrProviderContext) { describe('with datastreams', () => { before(async () => { - await createDatastream(DATASTREAM_NAME); + await addDatastream(DATASTREAM_NAME, CACHE_TEMPLATES); }); it('should return datastreams', async () => { - const uri = `${API_BASE_PATH}/component_templates/${COMPONENT_NAME}/datastreams`; - - const { body } = await supertest.get(uri).set('kbn-xsrf', 'xxx').expect(200); + const { body } = await getComponentTemplateDatastreams(COMPONENT_NAME).expect(200); expect(body).to.eql({ data_streams: ['logs-test-component-template-default'] }); }); diff --git a/x-pack/test/api_integration/apis/management/index_management/data_streams.ts b/x-pack/test/api_integration/apis/management/index_management/data_streams.ts index 6ed1ec9ed1c4..791e23149aff 100644 --- a/x-pack/test/api_integration/apis/management/index_management/data_streams.ts +++ b/x-pack/test/api_integration/apis/management/index_management/data_streams.ts @@ -9,85 +9,21 @@ import expect from '@kbn/expect'; import { DataStream } from '@kbn/index-management-plugin/common'; import { FtrProviderContext } from '../../../ftr_provider_context'; -// @ts-ignore import { API_BASE_PATH } from './constants'; +import { datastreamsHelpers } from './lib/datastreams.helpers'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const es = getService('es'); - - const createDataStream = async (name: string) => { - // A data stream requires an index template before it can be created. - await es.indices.putIndexTemplate({ - name, - body: { - // We need to match the names of backing indices with this template. - index_patterns: [name + '*'], - template: { - mappings: { - properties: { - '@timestamp': { - type: 'date', - }, - }, - }, - lifecycle: { - // @ts-expect-error @elastic/elasticsearch enabled prop is not typed yet - enabled: true, - }, - }, - data_stream: {}, - }, - }); - await es.indices.createDataStream({ name }); - }; - - const updateIndexTemplateMappings = async (name: string, mappings: any) => { - await es.indices.putIndexTemplate({ - name, - body: { - // We need to match the names of backing indices with this template. - index_patterns: [name + '*'], - template: { - mappings, - }, - data_stream: {}, - }, - }); - }; - - const getDatastream = async (name: string) => { - const { - data_streams: [datastream], - } = await es.indices.getDataStream({ name }); - return datastream; - }; - - const getMapping = async (name: string) => { - const res = await es.indices.getMapping({ index: name }); - - return Object.values(res)[0]!.mappings; - }; - - const deleteComposableIndexTemplate = async (name: string) => { - await es.indices.deleteIndexTemplate({ name }); - }; - - const deleteDataStream = async (name: string) => { - await es.indices.deleteDataStream({ name }); - await deleteComposableIndexTemplate(name); - }; - - const assertDataStreamStorageSizeExists = (storageSize: string, storageSizeBytes: number) => { - // Storage size of a document doesn't look like it would be deterministic (could vary depending - // on how ES, Lucene, and the file system interact), so we'll just assert its presence and - // type. - expect(storageSize).to.be.ok(); - expect(typeof storageSize).to.be('string'); - expect(storageSizeBytes).to.be.ok(); - expect(typeof storageSizeBytes).to.be('number'); - }; + const { + createDataStream, + deleteDataStream, + assertDataStreamStorageSizeExists, + deleteComposableIndexTemplate, + updateIndexTemplateMappings, + getMapping, + getDatastream, + } = datastreamsHelpers(getService); describe('Data streams', function () { describe('Get', () => { diff --git a/x-pack/test/api_integration/apis/management/index_management/index.js b/x-pack/test/api_integration/apis/management/index_management/index.js deleted file mode 100644 index ae74d0fdcd91..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/index.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export default function ({ loadTestFile }) { - describe('index management', () => { - loadTestFile(require.resolve('./indices')); - loadTestFile(require.resolve('./mapping')); - loadTestFile(require.resolve('./settings')); - loadTestFile(require.resolve('./stats')); - loadTestFile(require.resolve('./data_streams')); - loadTestFile(require.resolve('./templates')); - loadTestFile(require.resolve('./component_templates')); - loadTestFile(require.resolve('./cluster_nodes')); - loadTestFile(require.resolve('./index_details')); - loadTestFile(require.resolve('./create_enrich_policy')); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/index.ts b/x-pack/test/api_integration/apis/management/index_management/index.ts new file mode 100644 index 000000000000..e8de9c10f8db --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('index management', () => { + loadTestFile(require.resolve('./indices')); + loadTestFile(require.resolve('./mapping')); + loadTestFile(require.resolve('./settings')); + loadTestFile(require.resolve('./stats')); + loadTestFile(require.resolve('./data_streams')); + loadTestFile(require.resolve('./templates')); + loadTestFile(require.resolve('./component_templates')); + loadTestFile(require.resolve('./cluster_nodes')); + loadTestFile(require.resolve('./index_details')); + loadTestFile(require.resolve('./create_enrich_policy')); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/indices.helpers.js b/x-pack/test/api_integration/apis/management/index_management/indices.helpers.js deleted file mode 100644 index 368272858ea2..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/indices.helpers.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH } from './constants'; - -export const registerHelpers = ({ supertest }) => { - const executeActionOnIndices = (index, urlParam, args) => { - const indices = Array.isArray(index) ? index : [index]; - - return supertest - .post(`${API_BASE_PATH}/indices/${urlParam}`) - .set('kbn-xsrf', 'xxx') - .send({ indices, ...args }); - }; - - const closeIndex = (index) => executeActionOnIndices(index, 'close'); - - const openIndex = (index) => executeActionOnIndices(index, 'open'); - - const deleteIndex = (index) => executeActionOnIndices(index, 'delete'); - - const flushIndex = (index) => executeActionOnIndices(index, 'flush'); - - const refreshIndex = (index) => executeActionOnIndices(index, 'refresh'); - - const forceMerge = (index, args) => executeActionOnIndices(index, 'forcemerge', args); - - const unfreeze = (index) => executeActionOnIndices(index, 'unfreeze'); - - const clearCache = (index) => executeActionOnIndices(index, 'clear_cache'); - - const list = () => supertest.get(`${API_BASE_PATH}/indices`); - - const reload = (indexNames) => - supertest.post(`${API_BASE_PATH}/indices/reload`).set('kbn-xsrf', 'xxx').send({ indexNames }); - - return { - closeIndex, - openIndex, - deleteIndex, - flushIndex, - refreshIndex, - forceMerge, - unfreeze, - list, - reload, - clearCache, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/indices.js b/x-pack/test/api_integration/apis/management/index_management/indices.js deleted file mode 100644 index 8d012f7a02d4..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/indices.js +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { initElasticsearchHelpers } from './lib'; -import { registerHelpers } from './indices.helpers'; -import { sortedExpectedIndexKeys } from './constants'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - - const { - createIndex, - catIndex, - indexStats, - cleanUp: cleanUpEsResources, - } = initElasticsearchHelpers(getService); - - const { - closeIndex, - openIndex, - deleteIndex, - flushIndex, - refreshIndex, - forceMerge, - unfreeze, - list, - reload, - clearCache, - } = registerHelpers({ supertest }); - - describe('indices', () => { - after(() => Promise.all([cleanUpEsResources()])); - - describe('clear cache', () => { - it('should clear the cache on a single index', async () => { - const index = await createIndex(); - await clearCache(index).expect(200); - }); - }); - - describe('close', function () { - // The Cloud backend disallows users from closing indices. - this.tags(['skipCloud']); - - it('should close an index', async () => { - const index = await createIndex(); - - // Make sure the index is open - const { - body: [cat1], - } = await catIndex(index); - expect(cat1.status).to.be('open'); - - await closeIndex(index).expect(200); - - // Make sure the index has been closed - const { - body: [cat2], - } = await catIndex(index); - expect(cat2.status).to.be('close'); - }); - }); - - describe('open', function () { - // The Cloud backend disallows users from closing indices, so there's no point testing - // the open behavior. - this.tags(['skipCloud']); - - it('should open an index', async () => { - const index = await createIndex(); - - await closeIndex(index); - - // Make sure the index is closed - const { - body: [cat1], - } = await catIndex(index); - expect(cat1.status).to.be('close'); - - await openIndex(index).expect(200); - - // Make sure the index is opened - const { - body: [cat2], - } = await catIndex(index); - expect(cat2.status).to.be('open'); - }); - }); - - describe('delete', () => { - it('should delete an index', async () => { - const index = await createIndex(); - - const { body: indices1 } = await catIndex(undefined, 'i'); - expect(indices1.map((index) => index.i)).to.contain(index); - - await deleteIndex([index]).expect(200); - - const { body: indices2 } = await catIndex(undefined, 'i'); - expect(indices2.map((index) => index.i)).not.to.contain(index); - }); - - it('should require index or indices to be provided', async () => { - const { body } = await deleteIndex().expect(400); - expect(body.message).to.contain('expected value of type [string]'); - }); - }); - - describe('flush', () => { - it('should flush an index', async () => { - const index = await createIndex(); - - const { - body: { indices: indices1 }, - } = await indexStats(index, 'flush'); - expect(indices1[index].total.flush.total).to.be(0); - - await flushIndex(index).expect(200); - - const { - body: { indices: indices2 }, - } = await indexStats(index, 'flush'); - expect(indices2[index].total.flush.total).to.be(1); - }); - }); - - describe('refresh', () => { - it('should refresh an index', async () => { - const index = await createIndex(); - - const { - body: { indices: indices1 }, - } = await indexStats(index, 'refresh'); - const previousRefreshes = indices1[index].total.refresh.total; - - await refreshIndex(index).expect(200); - - const { - body: { indices: indices2 }, - } = await indexStats(index, 'refresh'); - expect(indices2[index].total.refresh.total).to.be(previousRefreshes + 1); - }); - }); - - describe('forcemerge', () => { - it('should force merge an index', async () => { - const index = await createIndex(); - await forceMerge(index).expect(200); - }); - - it('should allow to define the number of segments', async () => { - const index = await createIndex(); - await forceMerge(index, { maxNumSegments: 1 }).expect(200); - }); - }); - - describe('unfreeze', () => { - it('should unfreeze an index', async () => { - const index = await createIndex(); - - // Even if the index is already unfrozen, calling the unfreeze api - // will have no effect on it and will return a 200. - await unfreeze(index).expect(200); - const { - body: [cat2], - } = await catIndex(index, 'sth'); - expect(cat2.sth).to.be('false'); - }); - }); - - describe('list', function () { - this.tags(['skipCloud']); - - it('should list all the indices with the expected properties and data enrichers', async function () { - // Create an index that we can assert against - await createIndex('test_index'); - - // Verify indices request - const { body: indices } = await list().expect(200); - - // Find the "test_index" created to verify expected keys - const indexCreated = indices.find((index) => index.name === 'test_index'); - - const sortedReceivedKeys = Object.keys(indexCreated).sort(); - - expect(sortedReceivedKeys).to.eql(sortedExpectedIndexKeys); - }); - }); - - describe('reload', function () { - describe('(not on Cloud)', function () { - this.tags(['skipCloud']); - - it('should list all the indices with the expected properties and data enrichers', async function () { - // create an index to assert against, otherwise the test is flaky - await createIndex('reload-test-index'); - const { body } = await reload().expect(200); - - const indexCreated = body.find((index) => index.name === 'reload-test-index'); - const sortedReceivedKeys = Object.keys(indexCreated).sort(); - expect(sortedReceivedKeys).to.eql(sortedExpectedIndexKeys); - expect(body.length > 1).to.be(true); // to contrast it with the next test - }); - }); - - it('should allow reloading only certain indices', async () => { - const index = await createIndex(); - const { body } = await reload([index]); - - expect(body.length === 1).to.be(true); - expect(body[0].name).to.be(index); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/indices.ts b/x-pack/test/api_integration/apis/management/index_management/indices.ts new file mode 100644 index 000000000000..aa2ff5966c4d --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/indices.ts @@ -0,0 +1,208 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { sortedExpectedIndexKeys } from './constants'; +import { indicesApi } from './lib/indices.api'; +import { indicesHelpers } from './lib/indices.helpers'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const { createIndex, deleteAllIndices, catIndex, indexStats } = indicesHelpers(getService); + + const { + closeIndex, + openIndex, + deleteIndex, + flushIndex, + refreshIndex, + forceMerge, + unfreeze, + list, + reload, + clearCache, + } = indicesApi(getService); + + describe('indices', () => { + after(async () => await deleteAllIndices()); + + describe('clear cache', () => { + it('should clear the cache on a single index', async () => { + const index = await createIndex(); + await clearCache(index).expect(200); + }); + }); + + describe('close', function () { + it('should close an index', async () => { + const index = await createIndex(); + + // Make sure the index is open + const { + body: [cat1], + } = await catIndex(index); + expect(cat1.status).to.be('open'); + + await closeIndex(index).expect(200); + + // Make sure the index has been closed + const { + body: [cat2], + } = await catIndex(index); + expect(cat2.status).to.be('close'); + }); + }); + + describe('open', function () { + it('should open an index', async () => { + const index = await createIndex(); + + await closeIndex(index); + + // Make sure the index is closed + const { + body: [cat1], + } = await catIndex(index); + expect(cat1.status).to.be('close'); + + await openIndex(index).expect(200); + + // Make sure the index is opened + const { + body: [cat2], + } = await catIndex(index); + expect(cat2.status).to.be('open'); + }); + }); + + describe('delete', () => { + it('should delete an index', async () => { + const index = await createIndex(); + + const { body: indices1 } = await catIndex(undefined, 'i'); + expect(indices1.map((indexItem) => indexItem.i)).to.contain(index); + + await deleteIndex(index).expect(200); + + const { body: indices2 } = await catIndex(undefined, 'i'); + expect(indices2.map((indexItem) => indexItem.i)).not.to.contain(index); + }); + + it('should require index or indices to be provided', async () => { + const { body } = await deleteIndex().expect(400); + expect(body.message).to.contain('expected value of type [string]'); + }); + }); + + describe('flush', () => { + it('should flush an index', async () => { + const index = await createIndex(); + + const { + body: { indices: indices1 }, + } = await indexStats(index, 'flush'); + // @ts-ignore + expect(indices1[index].total.flush.total).to.be(0); + + await flushIndex(index).expect(200); + + const { + body: { indices: indices2 }, + } = await indexStats(index, 'flush'); + // @ts-ignore + expect(indices2[index].total.flush.total).to.be(1); + }); + }); + + describe('refresh', () => { + it('should refresh an index', async () => { + const index = await createIndex(); + + const { + body: { indices: indices1 }, + } = await indexStats(index, 'refresh'); + // @ts-ignore + const previousRefreshes = indices1[index].total.refresh.total; + + await refreshIndex(index).expect(200); + + const { + body: { indices: indices2 }, + } = await indexStats(index, 'refresh'); + // @ts-ignore + expect(indices2[index].total.refresh.total).to.be(previousRefreshes + 1); + }); + }); + + describe('forcemerge', () => { + it('should force merge an index', async () => { + const index = await createIndex(); + await forceMerge(index).expect(200); + }); + + it('should allow to define the number of segments', async () => { + const index = await createIndex(); + await forceMerge(index, { maxNumSegments: 1 }).expect(200); + }); + }); + + describe('unfreeze', () => { + it('should unfreeze an index', async () => { + const index = await createIndex(); + + // Even if the index is already unfrozen, calling the unfreeze api + // will have no effect on it and will return a 200. + await unfreeze(index).expect(200); + const { + body: [cat2], + } = await catIndex(index, 'sth'); + expect(cat2.sth).to.be('false'); + }); + }); + + describe('list', function () { + it('should list all the indices with the expected properties and data enrichers', async function () { + // Create an index that we can assert against + await createIndex('test_index'); + + // Verify indices request + const { body: indices } = await list().expect(200); + + // Find the "test_index" created to verify expected keys + const indexCreated = indices.find((index: { name: string }) => index.name === 'test_index'); + + const sortedReceivedKeys = Object.keys(indexCreated).sort(); + + expect(sortedReceivedKeys).to.eql(sortedExpectedIndexKeys); + }); + }); + + describe('reload', function () { + it('should list all the indices with the expected properties and data enrichers', async function () { + // create an index to assert against, otherwise the test is flaky + await createIndex('reload-test-index'); + const { body } = await reload().expect(200); + + const indexCreated = body.find( + (index: { name: string }) => index.name === 'reload-test-index' + ); + const sortedReceivedKeys = Object.keys(indexCreated).sort(); + expect(sortedReceivedKeys).to.eql(sortedExpectedIndexKeys); + expect(body.length > 1).to.be(true); // to contrast it with the next test + }); + + it('should allow reloading only certain indices', async () => { + const index = await createIndex(); + const { body } = await reload([index]); + + expect(body.length === 1).to.be(true); + expect(body[0].name).to.be(index); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/cluster_nodes.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/cluster_nodes.api.ts new file mode 100644 index 000000000000..c0bca06cd0e9 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/cluster_nodes.api.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function clusterNodesApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + + const getNodesPlugins = () => + supertest + .get(`${API_BASE_PATH}/nodes/plugins`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + return { + getNodesPlugins, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/component_template.helpers.ts b/x-pack/test/api_integration/apis/management/index_management/lib/component_template.helpers.ts new file mode 100644 index 000000000000..9d609e8a277d --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/component_template.helpers.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function componentTemplateHelpers(getService: FtrProviderContext['getService']) { + const log = getService('log'); + const es = getService('es'); + + let componentTemplatesCreated: string[] = []; + let indexTemplatesCreated: string[] = []; + let datastreamCreated: string[] = []; + + const removeComponentTemplate = (name: string) => es.cluster.deleteComponentTemplate({ name }); + + const removeDatastream = (datastream: string) => + es.indices.deleteDataStream({ name: datastream }); + + const removeIndexTemplate = (name: string) => + es.indices.deleteIndexTemplate({ name }, { meta: true }); + + const addComponentTemplate = (componentTemplate: any, shouldCacheTemplate: boolean) => { + if (shouldCacheTemplate) { + componentTemplatesCreated.push(componentTemplate.name); + } + + return es.cluster.putComponentTemplate(componentTemplate, { meta: true }); + }; + + const addIndexTemplate = (indexTemplate: any, shouldCacheTemplate: boolean) => { + if (shouldCacheTemplate) { + indexTemplatesCreated.push(indexTemplate.name); + } + + return es.indices.putIndexTemplate(indexTemplate, { meta: true }); + }; + + const addDatastream = (datastream: string, shouldCacheTemplate: boolean) => { + if (shouldCacheTemplate) { + datastreamCreated.push(datastream); + } + + return es.indices.createDataStream({ name: datastream }); + }; + + const cleanUpComponentTemplates = () => + Promise.all(componentTemplatesCreated.map(removeComponentTemplate)) + .then(() => { + componentTemplatesCreated = []; + }) + .catch((err) => { + log.debug(`[Cleanup error] Error deleting ES resources: ${err.message}`); + }); + + const cleanUpIndexTemplates = () => + Promise.all(indexTemplatesCreated.map(removeIndexTemplate)) + .then(() => { + indexTemplatesCreated = []; + }) + .catch((err) => { + log.debug(`[Cleanup error] Error deleting ES resources: ${err.message}`); + }); + + const cleanupDatastreams = () => + Promise.all(datastreamCreated.map(removeDatastream)) + .then(() => { + datastreamCreated = []; + }) + .catch((err) => { + log.debug(`[Cleanup error] Error deleting ES resources: ${err.message}`); + }); + + return { + addDatastream, + addIndexTemplate, + addComponentTemplate, + + removeDatastream, + removeIndexTemplate, + removeComponentTemplate, + + cleanupDatastreams, + cleanUpIndexTemplates, + cleanUpComponentTemplates, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/component_templates.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/component_templates.api.ts new file mode 100644 index 000000000000..60f604159e33 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/component_templates.api.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ClusterPutComponentTemplateRequest } from '@elastic/elasticsearch/lib/api/types'; + +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +type Options = Partial | { _kbnMeta: Record }; + +export function componentTemplatesApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + + const createComponentTemplate = (name: string, options: Options) => + supertest + .post(`${API_BASE_PATH}/component_templates`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({ name, ...options }); + + const getAllComponentTemplates = () => + supertest + .get(`${API_BASE_PATH}/component_templates`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + const getOneComponentTemplate = (name: string) => + supertest + .get(`${API_BASE_PATH}/component_templates/${name}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + const updateComponentTemplate = (name: string, options: Options) => + supertest + .put(`${API_BASE_PATH}/component_templates/${name}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({ + name, + ...options, + }); + + const deleteComponentTemplate = (name: string) => + supertest + .delete(`${API_BASE_PATH}/component_templates/${name}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + const getComponentTemplateDatastreams = (name: string) => + supertest + .get(`${API_BASE_PATH}/component_templates/${name}/datastreams`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + return { + createComponentTemplate, + getAllComponentTemplates, + getOneComponentTemplate, + updateComponentTemplate, + deleteComponentTemplate, + getComponentTemplateDatastreams, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/datastreams.helpers.ts b/x-pack/test/api_integration/apis/management/index_management/lib/datastreams.helpers.ts new file mode 100644 index 000000000000..65e2d733dd69 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/datastreams.helpers.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function datastreamsHelpers(getService: FtrProviderContext['getService']) { + const es = getService('es'); + + const createDataStream = async (name: string) => { + // A data stream requires an index template before it can be created. + await es.indices.putIndexTemplate({ + name, + body: { + // We need to match the names of backing indices with this template. + index_patterns: [name + '*'], + template: { + mappings: { + properties: { + '@timestamp': { + type: 'date', + }, + }, + }, + lifecycle: { + // @ts-expect-error @elastic/elasticsearch enabled prop is not typed yet + enabled: true, + }, + }, + data_stream: {}, + }, + }); + + await es.indices.createDataStream({ name }); + }; + + const updateIndexTemplateMappings = async (name: string, mappings: any) => { + await es.indices.putIndexTemplate({ + name, + body: { + // We need to match the names of backing indices with this template. + index_patterns: [name + '*'], + template: { + mappings, + }, + data_stream: {}, + }, + }); + }; + + const getDatastream = async (name: string) => { + const { + data_streams: [datastream], + } = await es.indices.getDataStream({ name }); + return datastream; + }; + + const getMapping = async (name: string) => { + const res = await es.indices.getMapping({ index: name }); + + return Object.values(res)[0]!.mappings; + }; + + const deleteComposableIndexTemplate = async (name: string) => { + await es.indices.deleteIndexTemplate({ name }); + }; + + const deleteDataStream = async (name: string) => { + await es.indices.deleteDataStream({ name }); + await deleteComposableIndexTemplate(name); + }; + + const assertDataStreamStorageSizeExists = (storageSize: string, storageSizeBytes: number) => { + // Storage size of a document doesn't look like it would be deterministic (could vary depending + // on how ES, Lucene, and the file system interact), so we'll just assert its presence and + // type. + expect(storageSize).to.be.ok(); + expect(typeof storageSize).to.be('string'); + expect(storageSizeBytes).to.be.ok(); + expect(typeof storageSizeBytes).to.be('number'); + }; + + return { + createDataStream, + updateIndexTemplateMappings, + getDatastream, + getMapping, + deleteComposableIndexTemplate, + deleteDataStream, + assertDataStreamStorageSizeExists, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/elasticsearch.js b/x-pack/test/api_integration/apis/management/index_management/lib/elasticsearch.js deleted file mode 100644 index d71085439e86..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/lib/elasticsearch.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getRandomString } from './random'; - -/** - * Helpers to create and delete indices on the Elasticsearch instance - * during our tests. - * @param {ElasticsearchClient} es The Elasticsearch client instance - */ -export const initElasticsearchHelpers = (getService) => { - const es = getService('es'); - const esDeleteAllIndices = getService('esDeleteAllIndices'); - - let indicesCreated = []; - let datastreamCreated = []; - let indexTemplatesCreated = []; - let componentTemplatesCreated = []; - - const createDatastream = (datastream) => { - datastreamCreated.push(datastream); - return es.indices.createDataStream({ name: datastream }); - }; - - const deleteDatastream = (datastream) => { - return es.indices.deleteDataStream({ name: datastream }); - }; - - const cleanupDatastreams = () => - Promise.all(datastreamCreated.map(deleteDatastream)) - .then(() => { - datastreamCreated = []; - }) - .catch((err) => { - // eslint-disable-next-line no-console - console.log(`[Cleanup error] Error deleting ES resources: ${err.message}`); - }); - - const createIndex = (index = getRandomString(), body) => { - indicesCreated.push(index); - return es.indices.create({ index, body }).then(() => index); - }; - - const deleteAllIndices = async () => { - await esDeleteAllIndices(indicesCreated); - indicesCreated = []; - }; - - const catIndex = (index, h) => es.cat.indices({ index, format: 'json', h }, { meta: true }); - - const indexStats = (index, metric) => es.indices.stats({ index, metric }, { meta: true }); - - const cleanUp = () => deleteAllIndices(); - - const catTemplate = (name) => es.cat.templates({ name, format: 'json' }, { meta: true }); - - const createIndexTemplate = (indexTemplate, shouldCacheTemplate) => { - if (shouldCacheTemplate) { - indexTemplatesCreated.push(indexTemplate.name); - } - - return es.indices.putIndexTemplate(indexTemplate, { meta: true }); - }; - - const deleteIndexTemplate = (indexTemplateName) => { - return es.indices.deleteIndexTemplate({ name: indexTemplateName }, { meta: true }); - }; - - const createComponentTemplate = (componentTemplate, shouldCacheTemplate) => { - if (shouldCacheTemplate) { - componentTemplatesCreated.push(componentTemplate.name); - } - - return es.cluster.putComponentTemplate(componentTemplate, { meta: true }); - }; - - const deleteComponentTemplate = (componentTemplateName) => { - return es.cluster.deleteComponentTemplate({ name: componentTemplateName }, { meta: true }); - }; - - const cleanUpComponentTemplates = () => - Promise.all(componentTemplatesCreated.map(deleteComponentTemplate)) - .then(() => { - componentTemplatesCreated = []; - }) - .catch((err) => { - // eslint-disable-next-line no-console - console.log(`[Cleanup error] Error deleting ES resources: ${err.message}`); - }); - - const cleanUpIndexTemplates = () => - Promise.all(indexTemplatesCreated.map(deleteIndexTemplate)) - .then(() => { - indexTemplatesCreated = []; - }) - .catch((err) => { - // eslint-disable-next-line no-console - console.log(`[Cleanup error] Error deleting ES resources: ${err.message}`); - }); - - return { - createIndex, - deleteAllIndices, - catIndex, - indexStats, - createDatastream, - deleteDatastream, - cleanupDatastreams, - cleanUp, - catTemplate, - createIndexTemplate, - deleteIndexTemplate, - cleanUpIndexTemplates, - createComponentTemplate, - deleteComponentTemplate, - cleanUpComponentTemplates, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/index.js b/x-pack/test/api_integration/apis/management/index_management/lib/index.js deleted file mode 100644 index f2079a44a634..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/lib/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { initElasticsearchHelpers } from './elasticsearch'; - -export { getRandomString } from './random'; - -export { wait } from './utils'; diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/index.ts b/x-pack/test/api_integration/apis/management/index_management/lib/index.ts new file mode 100644 index 000000000000..224b32aba5ef --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getRandomString } from './random'; diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/indices.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/indices.api.ts new file mode 100644 index 000000000000..d75d3ec0527b --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/indices.api.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function indicesApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + const executeActionOnIndices = ({ + index, + urlParam, + args, + }: { + index?: string | string[]; + urlParam: string; + args?: any; + }) => { + const indices = Array.isArray(index) ? index : [index]; + + return supertest + .post(`${API_BASE_PATH}/indices/${urlParam}`) + .set('kbn-xsrf', 'xxx') + .send({ indices, ...args }); + }; + + const closeIndex = (index: string) => executeActionOnIndices({ index, urlParam: 'close' }); + + const openIndex = (index: string) => executeActionOnIndices({ index, urlParam: 'open' }); + + const deleteIndex = (index?: string) => executeActionOnIndices({ index, urlParam: 'delete' }); + + const flushIndex = (index: string) => executeActionOnIndices({ index, urlParam: 'flush' }); + + const refreshIndex = (index: string) => executeActionOnIndices({ index, urlParam: 'refresh' }); + + const forceMerge = (index: string, args?: { maxNumSegments: number }) => + executeActionOnIndices({ index, urlParam: 'forcemerge', args }); + + const unfreeze = (index: string) => executeActionOnIndices({ index, urlParam: 'unfreeze' }); + + const clearCache = (index: string) => executeActionOnIndices({ index, urlParam: 'clear_cache' }); + + const list = () => supertest.get(`${API_BASE_PATH}/indices`); + + const reload = (indexNames?: string[]) => + supertest.post(`${API_BASE_PATH}/indices/reload`).set('kbn-xsrf', 'xxx').send({ indexNames }); + + return { + closeIndex, + openIndex, + deleteIndex, + flushIndex, + refreshIndex, + forceMerge, + unfreeze, + list, + reload, + clearCache, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/indices.helpers.ts b/x-pack/test/api_integration/apis/management/index_management/lib/indices.helpers.ts new file mode 100644 index 000000000000..139e813d84ff --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/indices.helpers.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getRandomString } from './random'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function indicesHelpers(getService: FtrProviderContext['getService']) { + const es = getService('es'); + const esDeleteAllIndices = getService('esDeleteAllIndices'); + + let indicesCreated: string[] = []; + + const createIndex = async (index: string = getRandomString(), mappings?: any) => { + indicesCreated.push(index); + await es.indices.create({ index, mappings }); + return index; + }; + + const deleteAllIndices = async () => { + await esDeleteAllIndices(indicesCreated); + indicesCreated = []; + }; + + const catIndex = (index?: string, h?: any) => + es.cat.indices({ index, format: 'json', h }, { meta: true }); + + const indexStats = (index: string, metric: string) => + es.indices.stats({ index, metric }, { meta: true }); + + return { createIndex, deleteAllIndices, catIndex, indexStats }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/mappings.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/mappings.api.ts new file mode 100644 index 000000000000..f032f2893e31 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/mappings.api.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function mappingsApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + + const getMapping = (index: string) => + supertest + .get(`${API_BASE_PATH}/mapping/${index}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + return { + getMapping, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/random.js b/x-pack/test/api_integration/apis/management/index_management/lib/random.ts similarity index 100% rename from x-pack/test/api_integration/apis/management/index_management/lib/random.js rename to x-pack/test/api_integration/apis/management/index_management/lib/random.ts diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/settings.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/settings.api.ts new file mode 100644 index 000000000000..67b3c275775c --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/settings.api.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IndexSettings } from '@kbn/index-management-plugin/common'; + +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function settingsApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + + const getIndexSettings = (index: string) => + supertest + .get(`${API_BASE_PATH}/settings/${index}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx'); + + const updateIndexSettings = (index: string, settings: IndexSettings) => + supertest + .put(`${API_BASE_PATH}/settings/${index}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send(settings); + + return { + getIndexSettings, + updateIndexSettings, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts b/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts new file mode 100644 index 000000000000..6e8fbffbe041 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/templates.api.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TemplateDeserialized, TemplateSerialized } from '@kbn/index-management-plugin/common'; +import { API_BASE_PATH } from '../constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export function templatesApi(getService: FtrProviderContext['getService']) { + const supertest = getService('supertest'); + let templatesCreated: Array<{ name: string; isLegacy?: boolean }> = []; + + const getAllTemplates = () => supertest.get(`${API_BASE_PATH}/index_templates`); + + const getOneTemplate = (name: string, isLegacy: boolean = false) => + supertest.get(`${API_BASE_PATH}/index_templates/${name}?legacy=${isLegacy}`); + + const createTemplate = (template: TemplateDeserialized) => { + templatesCreated.push({ name: template.name, isLegacy: template._kbnMeta.isLegacy }); + return supertest.post(`${API_BASE_PATH}/index_templates`).set('kbn-xsrf', 'xxx').send(template); + }; + + const deleteTemplates = (templates: Array<{ name: string; isLegacy?: boolean }>) => + supertest + .post(`${API_BASE_PATH}/delete_index_templates`) + .set('kbn-xsrf', 'xxx') + .send({ templates }); + + const updateTemplate = (payload: TemplateDeserialized, templateName: string) => + supertest + .put(`${API_BASE_PATH}/index_templates/${templateName}`) + .set('kbn-xsrf', 'xxx') + .send(payload); + + // Delete all templates created during tests + const cleanUpTemplates = async () => { + try { + await deleteTemplates(templatesCreated); + templatesCreated = []; + } catch (e) { + // Silently swallow errors + } + }; + + const simulateTemplate = (payload: TemplateSerialized) => + supertest + .post(`${API_BASE_PATH}/index_templates/simulate`) + .set('kbn-xsrf', 'xxx') + .send(payload); + + return { + getAllTemplates, + getOneTemplate, + createTemplate, + updateTemplate, + deleteTemplates, + cleanUpTemplates, + simulateTemplate, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/templates.helpers.ts b/x-pack/test/api_integration/apis/management/index_management/lib/templates.helpers.ts new file mode 100644 index 000000000000..2ea61cd79cb5 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/lib/templates.helpers.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TemplateDeserialized, TemplateSerialized } from '@kbn/index-management-plugin/common'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { INDEX_PATTERNS } from '../constants'; + +const templateMock = { + settings: { + number_of_shards: 1, + }, + mappings: { + _source: { + enabled: false, + }, + properties: { + host_name: { + type: 'keyword', + }, + created_at: { + type: 'date', + format: 'EEE MMM dd HH:mm:ss Z yyyy', + }, + }, + }, + aliases: { + alias1: {}, + }, +}; +export function templatesHelpers(getService: FtrProviderContext['getService']) { + const es = getService('es'); + + const catTemplate = (name: string) => es.cat.templates({ name, format: 'json' }, { meta: true }); + + const getTemplatePayload = ( + name: string, + indexPatterns: string[] = INDEX_PATTERNS, + isLegacy: boolean = false + ) => { + const baseTemplate: TemplateDeserialized = { + name, + indexPatterns, + version: 1, + template: { ...templateMock }, + _kbnMeta: { + isLegacy, + type: 'default', + hasDatastream: false, + }, + }; + + if (isLegacy) { + baseTemplate.order = 1; + } else { + baseTemplate.priority = 1; + } + + return baseTemplate; + }; + + const getSerializedTemplate = (indexPatterns: string[] = INDEX_PATTERNS): TemplateSerialized => { + return { + index_patterns: indexPatterns, + template: { ...templateMock }, + }; + }; + + return { + catTemplate, + getTemplatePayload, + getSerializedTemplate, + }; +} diff --git a/x-pack/test/api_integration/apis/management/index_management/lib/utils.js b/x-pack/test/api_integration/apis/management/index_management/lib/utils.js deleted file mode 100644 index aeae936e44cb..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/lib/utils.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const wait = (time = 1000) => new Promise((resolve) => setTimeout(resolve, time)); diff --git a/x-pack/test/api_integration/apis/management/index_management/mapping.helpers.js b/x-pack/test/api_integration/apis/management/index_management/mapping.helpers.js deleted file mode 100644 index abb790cf2f55..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/mapping.helpers.js +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH } from './constants'; - -export const registerHelpers = ({ supertest }) => { - const getIndexMapping = (indexName) => supertest.get(`${API_BASE_PATH}/mapping/${indexName}`); - - return { - getIndexMapping, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/mapping.js b/x-pack/test/api_integration/apis/management/index_management/mapping.js deleted file mode 100644 index c18bc4c16352..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/mapping.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { initElasticsearchHelpers } from './lib'; -import { registerHelpers } from './mapping.helpers'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - - const { createIndex, cleanUp: cleanUpEsResources } = initElasticsearchHelpers(getService); - - const { getIndexMapping } = registerHelpers({ supertest }); - - describe('mapping', () => { - after(() => Promise.all([cleanUpEsResources()])); - - it('should fetch the index mapping', async () => { - const mappings = { - properties: { - total: { type: 'long' }, - tag: { type: 'keyword' }, - createdAt: { type: 'date' }, - }, - }; - const index = await createIndex(undefined, { mappings }); - - const { body } = await getIndexMapping(index).expect(200); - - expect(body.mappings).to.eql(mappings); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/mapping.ts b/x-pack/test/api_integration/apis/management/index_management/mapping.ts new file mode 100644 index 000000000000..5e3ebea13adc --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/mapping.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { mappingsApi } from './lib/mappings.api'; +import { indicesHelpers } from './lib/indices.helpers'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const log = getService('log'); + + const { getMapping } = mappingsApi(getService); + const { createIndex, deleteAllIndices } = indicesHelpers(getService); + + describe('mappings', () => { + let indexName: string; + + const mappings = { + properties: { + total: { type: 'long' }, + tag: { type: 'keyword' }, + createdAt: { type: 'date' }, + }, + }; + + after(async () => await deleteAllIndices()); + + before(async () => { + log.debug('Creating index'); + try { + indexName = await createIndex(undefined, mappings); + } catch (err) { + log.debug('[Setup error] Error creating index'); + throw err; + } + }); + + after(async () => { + try { + await deleteAllIndices(); + } catch (err) { + log.debug('[Cleanup error] Error deleting index'); + throw err; + } + }); + + it('should get the index mappings', async () => { + const { body } = await getMapping(indexName).expect(200); + + expect(body.mappings).to.eql(mappings); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/settings.helpers.js b/x-pack/test/api_integration/apis/management/index_management/settings.helpers.js deleted file mode 100644 index 58573b1572fa..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/settings.helpers.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH } from './constants'; - -export const registerHelpers = ({ supertest }) => { - const getIndexSettings = (indexName) => supertest.get(`${API_BASE_PATH}/settings/${indexName}`); - - const updateIndexSettings = (indexName, settings) => - supertest.put(`${API_BASE_PATH}/settings/${indexName}`).set('kbn-xsrf', 'xxx').send(settings); - - return { - getIndexSettings, - updateIndexSettings, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/settings.js b/x-pack/test/api_integration/apis/management/index_management/settings.js deleted file mode 100644 index 44ee80aaec7a..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/settings.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { initElasticsearchHelpers } from './lib'; -import { registerHelpers } from './settings.helpers'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - - const { createIndex, cleanUp: cleanUpEsResources } = initElasticsearchHelpers(getService); - - const { getIndexSettings, updateIndexSettings } = registerHelpers({ supertest }); - - describe('settings', () => { - after(() => Promise.all([cleanUpEsResources()])); - - it('should fetch an index settings', async () => { - const index = await createIndex(); - - const { body } = await getIndexSettings(index).expect(200); - - // Verify we fetch the corret index settings - expect(body.settings.index.provided_name).to.be(index); - - const expectedSettings = [ - 'max_inner_result_window', - 'unassigned', - 'max_terms_count', - 'lifecycle', - 'routing_partition_size', - 'max_docvalue_fields_search', - 'merge', - 'max_refresh_listeners', - 'max_regex_length', - 'load_fixed_bitset_filters_eagerly', - 'number_of_routing_shards', - 'write', - 'verified_before_close', - 'mapping', - 'source_only', - 'soft_deletes', - 'max_script_fields', - 'query', - 'format', - 'frozen', - 'sort', - 'priority', - 'codec', - 'max_rescore_window', - 'analyze', - 'gc_deletes', - 'max_ngram_diff', - 'translog', - 'auto_expand_replicas', - 'requests', - 'data_path', - 'highlight', - 'routing', - 'search', - 'fielddata', - 'default_pipeline', - 'max_slices_per_scroll', - 'shard', - 'xpack', - 'percolator', - 'allocation', - 'refresh_interval', - 'indexing', - 'compound_format', - 'blocks', - 'max_result_window', - 'store', - 'queries', - 'warmer', - 'max_shingle_diff', - 'query_string', - ]; - - // Make sure none of the settings have been removed from ES API - expectedSettings.forEach((setting) => { - try { - expect(body.defaults.index.hasOwnProperty(setting)).to.be(true); - } catch { - throw new Error(`Expected setting "${setting}" not found.`); - } - }); - }); - - it('should update an index settings', async () => { - const index = await createIndex(); - - const { body: body1 } = await getIndexSettings(index); - expect(body1.settings.index.number_of_replicas).to.be('1'); - - const settings = { - index: { - number_of_replicas: 2, - }, - }; - await updateIndexSettings(index, settings); - - const { body: body2 } = await getIndexSettings(index); - expect(body2.settings.index.number_of_replicas).to.be('2'); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/settings.ts b/x-pack/test/api_integration/apis/management/index_management/settings.ts new file mode 100644 index 000000000000..573a0374e9c2 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/settings.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { indicesHelpers } from './lib/indices.helpers'; +import { settingsApi } from './lib/settings.api'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const { createIndex, deleteAllIndices } = indicesHelpers(getService); + const { getIndexSettings, updateIndexSettings } = settingsApi(getService); + + describe('settings', () => { + after(async () => await deleteAllIndices()); + + it('should fetch an index settings', async () => { + const index = await createIndex(); + + const { body } = await getIndexSettings(index).expect(200); + + // Verify we fetch the corret index settings + expect(body.settings.index.provided_name).to.be(index); + + const expectedSettings = [ + 'max_inner_result_window', + 'unassigned', + 'max_terms_count', + 'lifecycle', + 'routing_partition_size', + 'max_docvalue_fields_search', + 'merge', + 'max_refresh_listeners', + 'max_regex_length', + 'load_fixed_bitset_filters_eagerly', + 'number_of_routing_shards', + 'write', + 'verified_before_close', + 'mapping', + 'source_only', + 'soft_deletes', + 'max_script_fields', + 'query', + 'format', + 'frozen', + 'sort', + 'priority', + 'codec', + 'max_rescore_window', + 'analyze', + 'gc_deletes', + 'max_ngram_diff', + 'translog', + 'auto_expand_replicas', + 'requests', + 'data_path', + 'highlight', + 'routing', + 'search', + 'fielddata', + 'default_pipeline', + 'max_slices_per_scroll', + 'shard', + 'xpack', + 'percolator', + 'allocation', + 'refresh_interval', + 'indexing', + 'compound_format', + 'blocks', + 'max_result_window', + 'store', + 'queries', + 'warmer', + 'max_shingle_diff', + 'query_string', + ]; + + // Make sure none of the settings have been removed from ES API + expectedSettings.forEach((setting) => { + try { + expect(body.defaults.index.hasOwnProperty(setting)).to.be(true); + } catch { + throw new Error(`Expected setting "${setting}" not found.`); + } + }); + }); + + it('should update an index settings', async () => { + const index = await createIndex(); + + const { body: body1 } = await getIndexSettings(index); + expect(body1.settings.index.number_of_replicas).to.be('1'); + + const settings = { + index: { + number_of_replicas: 2, + }, + }; + await updateIndexSettings(index, settings); + + const { body: body2 } = await getIndexSettings(index); + expect(body2.settings.index.number_of_replicas).to.be('2'); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/stats.helpers.js b/x-pack/test/api_integration/apis/management/index_management/stats.helpers.js deleted file mode 100644 index b00242d49282..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/stats.helpers.js +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH } from './constants'; - -export const registerHelpers = ({ supertest }) => { - const getIndexStats = (indexName) => supertest.get(`${API_BASE_PATH}/stats/${indexName}`); - - return { - getIndexStats, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/stats.js b/x-pack/test/api_integration/apis/management/index_management/stats.js deleted file mode 100644 index c673f1046171..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/stats.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { initElasticsearchHelpers } from './lib'; -import { registerHelpers } from './stats.helpers'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - - const { createIndex, cleanUp: cleanUpEsResources } = initElasticsearchHelpers(getService); - - const { getIndexStats } = registerHelpers({ supertest }); - - describe('stats', () => { - after(() => Promise.all([cleanUpEsResources()])); - - it('should fetch the index stats', async () => { - const index = await createIndex(); - - const { body } = await getIndexStats(index).expect(200); - - const expectedStats = [ - 'docs', - 'store', - 'indexing', - 'get', - 'search', - 'merges', - 'refresh', - 'flush', - 'warmer', - 'query_cache', - 'fielddata', - 'completion', - 'segments', - 'translog', - 'request_cache', - 'recovery', - ]; - - // Make sure none of the stats have been removed from ES API - expectedStats.forEach((stat) => { - try { - expect(body.stats.total.hasOwnProperty(stat)).to.be(true); - } catch { - throw new Error(`Expected stat "${stat}" not found.`); - } - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/stats.ts b/x-pack/test/api_integration/apis/management/index_management/stats.ts new file mode 100644 index 000000000000..28ef3083e3a4 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/stats.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { indicesHelpers } from './lib/indices.helpers'; +import { API_BASE_PATH } from './constants'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + const { createIndex, deleteAllIndices } = indicesHelpers(getService); + + const getIndexStats = (indexName: string) => supertest.get(`${API_BASE_PATH}/stats/${indexName}`); + + describe('stats', () => { + after(async () => await deleteAllIndices()); + + it('should fetch the index stats', async () => { + const index = await createIndex(); + + const { body } = await getIndexStats(index).expect(200); + + const expectedStats = [ + 'docs', + 'store', + 'indexing', + 'get', + 'search', + 'merges', + 'refresh', + 'flush', + 'warmer', + 'query_cache', + 'fielddata', + 'completion', + 'segments', + 'translog', + 'request_cache', + 'recovery', + ]; + + // Make sure none of the stats have been removed from ES API + expectedStats.forEach((stat) => { + try { + expect(body.stats.total.hasOwnProperty(stat)).to.be(true); + } catch { + throw new Error(`Expected stat "${stat}" not found.`); + } + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/management/index_management/templates.helpers.js b/x-pack/test/api_integration/apis/management/index_management/templates.helpers.js deleted file mode 100644 index d775dfcbdf10..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/templates.helpers.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { API_BASE_PATH, INDEX_PATTERNS } from './constants'; - -export const registerHelpers = ({ supertest }) => { - let templatesCreated = []; - - const getAllTemplates = () => supertest.get(`${API_BASE_PATH}/index_templates`); - - const getOneTemplate = (name, isLegacy = false) => - supertest.get(`${API_BASE_PATH}/index_templates/${name}?legacy=${isLegacy}`); - - const getTemplatePayload = ( - name, - indexPatterns = INDEX_PATTERNS, - isLegacy = false, - type = 'default' - ) => { - const baseTemplate = { - name, - indexPatterns, - version: 1, - template: { - settings: { - number_of_shards: 1, - index: { - lifecycle: { - name: 'my_policy', - }, - }, - }, - mappings: { - _source: { - enabled: false, - }, - properties: { - host_name: { - type: 'keyword', - }, - created_at: { - type: 'date', - format: 'EEE MMM dd HH:mm:ss Z yyyy', - }, - }, - }, - aliases: { - alias1: {}, - }, - }, - _kbnMeta: { - isLegacy, - type, - }, - }; - - if (isLegacy) { - baseTemplate.order = 1; - } else { - baseTemplate.priority = 1; - } - - return baseTemplate; - }; - - const createTemplate = (template) => { - templatesCreated.push({ name: template.name, isLegacy: template._kbnMeta.isLegacy }); - return supertest.post(`${API_BASE_PATH}/index_templates`).set('kbn-xsrf', 'xxx').send(template); - }; - - const deleteTemplates = (templates) => - supertest - .post(`${API_BASE_PATH}/delete_index_templates`) - .set('kbn-xsrf', 'xxx') - .send({ templates }); - - const updateTemplate = (payload, templateName) => - supertest - .put(`${API_BASE_PATH}/index_templates/${templateName}`) - .set('kbn-xsrf', 'xxx') - .send(payload); - - // Delete all templates created during tests - const cleanUpTemplates = async () => { - try { - await deleteTemplates(templatesCreated); - templatesCreated = []; - } catch (e) { - // Silently swallow errors - } - }; - - return { - getAllTemplates, - getOneTemplate, - getTemplatePayload, - createTemplate, - updateTemplate, - deleteTemplates, - cleanUpTemplates, - }; -}; diff --git a/x-pack/test/api_integration/apis/management/index_management/templates.js b/x-pack/test/api_integration/apis/management/index_management/templates.js deleted file mode 100644 index bb4007852b03..000000000000 --- a/x-pack/test/api_integration/apis/management/index_management/templates.js +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { initElasticsearchHelpers, getRandomString } from './lib'; -import { registerHelpers } from './templates.helpers'; - -export default function ({ getService }) { - const supertest = getService('supertest'); - - const { cleanUp: cleanUpEsResources, catTemplate } = initElasticsearchHelpers(getService); - - const { - getAllTemplates, - getOneTemplate, - createTemplate, - getTemplatePayload, - deleteTemplates, - updateTemplate, - cleanUpTemplates, - } = registerHelpers({ supertest }); - - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/170980 - describe.skip('index templates', () => { - after(() => Promise.all([cleanUpEsResources(), cleanUpTemplates()])); - - describe('get all', () => { - const indexTemplate = getTemplatePayload(`template-${getRandomString()}`, [ - getRandomString(), - ]); - const legacyTemplate = getTemplatePayload( - `template-${getRandomString()}`, - [getRandomString()], - true - ); - const tmpTemplate = getTemplatePayload(`template-${getRandomString()}`, [getRandomString()]); - const indexTemplateWithLifecycle = { - ...tmpTemplate, - dataStream: {}, - template: { - ...tmpTemplate.template, - lifecycle: { - enabled: true, - data_retention: '10d', - }, - }, - }; - - beforeEach(async () => { - const res1 = await createTemplate(indexTemplate); - if (res1.status !== 200) { - throw new Error(res1.body.message); - } - - const res2 = await createTemplate(legacyTemplate); - if (res2.status !== 200) { - throw new Error(res2.body.message); - } - - const res3 = await createTemplate(indexTemplateWithLifecycle); - if (res3.status !== 200) { - throw new Error(res3.body.message); - } - }); - - it('should list all the index templates with the expected parameters', async () => { - const { body: allTemplates } = await getAllTemplates().expect(200); - - // Index templates (composable) - const indexTemplateFound = allTemplates.templates.find( - (template) => template.name === indexTemplate.name - ); - - if (!indexTemplateFound) { - throw new Error( - `Index template "${indexTemplate.name}" not found in ${JSON.stringify( - allTemplates.templates, - null, - 2 - )}` - ); - } - - const expectedKeys = [ - 'name', - 'indexPatterns', - 'hasSettings', - 'hasAliases', - 'hasMappings', - 'ilmPolicy', - 'priority', - 'composedOf', - 'version', - '_kbnMeta', - ].sort(); - - expect(Object.keys(indexTemplateFound).sort()).to.eql(expectedKeys); - - // Legacy index templates - const legacyTemplateFound = allTemplates.legacyTemplates.find( - (template) => template.name === legacyTemplate.name - ); - - if (!legacyTemplateFound) { - throw new Error( - `Legacy template "${legacyTemplate.name}" not found in ${JSON.stringify( - allTemplates.legacyTemplates, - null, - 2 - )}` - ); - } - - const expectedLegacyKeys = [ - 'name', - 'indexPatterns', - 'hasSettings', - 'hasAliases', - 'hasMappings', - 'ilmPolicy', - 'order', - 'version', - '_kbnMeta', - ].sort(); - - expect(Object.keys(legacyTemplateFound).sort()).to.eql(expectedLegacyKeys); - - // Index template with lifecycle - const templateWithLifecycle = allTemplates.templates.find( - (template) => template.name === indexTemplateWithLifecycle.name - ); - - if (!templateWithLifecycle) { - throw new Error( - `Index template with lifecycle "${ - indexTemplateWithLifecycle.name - }" not found in ${JSON.stringify(allTemplates.templates, null, 2)}` - ); - } - - const expectedWithLifecycleKeys = [ - 'name', - 'indexPatterns', - 'lifecycle', - 'hasSettings', - 'hasAliases', - 'hasMappings', - 'ilmPolicy', - 'priority', - 'composedOf', - 'dataStream', - 'version', - '_kbnMeta', - ].sort(); - - expect(Object.keys(templateWithLifecycle).sort()).to.eql(expectedWithLifecycleKeys); - }); - }); - - describe('get one', () => { - const templateName = `template-${getRandomString()}`; - - it('should return an index template with the expected parameters', async () => { - const template = getTemplatePayload(templateName, [getRandomString()]); - await createTemplate(template).expect(200); - - const { body } = await getOneTemplate(templateName).expect(200); - const expectedKeys = [ - 'name', - 'indexPatterns', - 'template', - 'composedOf', - 'ilmPolicy', - 'priority', - 'version', - '_kbnMeta', - ].sort(); - const expectedTemplateKeys = ['aliases', 'mappings', 'settings'].sort(); - - expect(body.name).to.equal(templateName); - expect(Object.keys(body).sort()).to.eql(expectedKeys); - expect(Object.keys(body.template).sort()).to.eql(expectedTemplateKeys); - }); - - it('should return a legacy index template with the expected parameters', async () => { - const legacyTemplate = getTemplatePayload(templateName, [getRandomString()], true); - await createTemplate(legacyTemplate).expect(200); - - const { body } = await getOneTemplate(templateName, true).expect(200); - const expectedKeys = [ - 'name', - 'indexPatterns', - 'template', - 'ilmPolicy', - 'order', - 'version', - '_kbnMeta', - ].sort(); - const expectedTemplateKeys = ['aliases', 'mappings', 'settings'].sort(); - - expect(body.name).to.equal(templateName); - expect(Object.keys(body).sort()).to.eql(expectedKeys); - expect(Object.keys(body.template).sort()).to.eql(expectedTemplateKeys); - }); - }); - - describe('create', () => { - it('should create an index template', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()]); - - await createTemplate(payload).expect(200); - }); - - it('should create a legacy index template', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()], true); - - await createTemplate(payload).expect(200); - }); - - it('should throw a 409 conflict when trying to create 2 templates with the same name', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()], true); - - await createTemplate(payload); - - await createTemplate(payload).expect(409); - }); - - it('should validate the request payload', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()], true); - - delete payload.indexPatterns; // index patterns are required - - const { body } = await createTemplate(payload); - expect(body.message).to.contain( - '[request body.indexPatterns]: expected value of type [array] ' - ); - }); - - it('should parse the ES error and return the cause', async () => { - const templateName = `template-create-parse-es-error}`; - const payload = getTemplatePayload(templateName, ['create-parse-es-error']); - const runtime = { - myRuntimeField: { - type: 'boolean', - script: { - source: 'emit("hello with error', // error in script - }, - }, - }; - payload.template.mappings = { ...payload.template.mappings, runtime }; - const { body } = await createTemplate(payload).expect(400); - - expect(body.attributes).an('object'); - expect(body.attributes.error.reason).contain('template after composition is invalid'); - // one of the item of the cause array should point to our script - expect(body.attributes.causes.join(',')).contain('"hello with error'); - }); - }); - - describe('update', () => { - it('should update an index template', async () => { - const templateName = `template-${getRandomString()}`; - const indexTemplate = getTemplatePayload(templateName, [getRandomString()]); - - await createTemplate(indexTemplate).expect(200); - - let { body: catTemplateResponse } = await catTemplate(templateName); - - const { name, version } = indexTemplate; - - expect( - catTemplateResponse.find(({ name: templateName }) => templateName === name).version - ).to.equal(version.toString()); - - // Update template with new version - const updatedVersion = 2; - await updateTemplate({ ...indexTemplate, version: updatedVersion }, templateName).expect( - 200 - ); - - ({ body: catTemplateResponse } = await catTemplate(templateName)); - - expect( - catTemplateResponse.find(({ name: templateName }) => templateName === name).version - ).to.equal(updatedVersion.toString()); - }); - - it('should update a legacy index template', async () => { - const templateName = `template-${getRandomString()}`; - const legacyIndexTemplate = getTemplatePayload(templateName, [getRandomString()], true); - - await createTemplate(legacyIndexTemplate).expect(200); - - let { body: catTemplateResponse } = await catTemplate(templateName); - - const { name, version } = legacyIndexTemplate; - - expect( - catTemplateResponse.find(({ name: templateName }) => templateName === name).version - ).to.equal(version.toString()); - - // Update template with new version - const updatedVersion = 2; - await updateTemplate( - { ...legacyIndexTemplate, version: updatedVersion }, - templateName - ).expect(200); - - ({ body: catTemplateResponse } = await catTemplate(templateName)); - - expect( - catTemplateResponse.find(({ name: templateName }) => templateName === name).version - ).to.equal(updatedVersion.toString()); - }); - - it('should parse the ES error and return the cause', async () => { - const templateName = `template-update-parse-es-error}`; - const payload = getTemplatePayload(templateName, ['update-parse-es-error']); - const runtime = { - myRuntimeField: { - type: 'keyword', - script: { - source: 'emit("hello")', - }, - }, - }; - - // Add runtime field - payload.template.mappings = { ...payload.template.mappings, runtime }; - - await createTemplate(payload).expect(200); - - // Update template with an error in the runtime field script - payload.template.mappings.runtime.myRuntimeField.script = 'emit("hello with error'; - const { body } = await updateTemplate(payload, templateName).expect(400); - - expect(body.attributes).an('object'); - // one of the item of the cause array should point to our script - expect(body.attributes.causes.join(',')).contain('"hello with error'); - }); - }); - - describe('delete', () => { - it('should delete an index template', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()]); - - const { status: createStatus, body: createBody } = await createTemplate(payload); - if (createStatus !== 200) { - throw new Error(`Error creating template: ${createStatus} ${createBody.message}`); - } - - let { body: catTemplateResponse } = await catTemplate(templateName); - - expect( - catTemplateResponse.find((template) => template.name === payload.name).name - ).to.equal(templateName); - - const { status: deleteStatus, body: deleteBody } = await deleteTemplates([ - { name: templateName }, - ]); - if (deleteStatus !== 200) { - throw new Error(`Error deleting template: ${deleteBody.message}`); - } - - expect(deleteBody.errors).to.be.empty; - expect(deleteBody.templatesDeleted[0]).to.equal(templateName); - - ({ body: catTemplateResponse } = await catTemplate(templateName)); - - expect(catTemplateResponse.find((template) => template.name === payload.name)).to.equal( - undefined - ); - }); - - it('should delete a legacy index template', async () => { - const templateName = `template-${getRandomString()}`; - const payload = getTemplatePayload(templateName, [getRandomString()], true); - - await createTemplate(payload).expect(200); - - let { body: catTemplateResponse } = await catTemplate(templateName); - - expect( - catTemplateResponse.find((template) => template.name === payload.name).name - ).to.equal(templateName); - - const { body } = await deleteTemplates([ - { name: templateName, isLegacy: payload._kbnMeta.isLegacy }, - ]).expect(200); - - expect(body.errors).to.be.empty; - expect(body.templatesDeleted[0]).to.equal(templateName); - - ({ body: catTemplateResponse } = await catTemplate(templateName)); - - expect(catTemplateResponse.find((template) => template.name === payload.name)).to.equal( - undefined - ); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/management/index_management/templates.ts b/x-pack/test/api_integration/apis/management/index_management/templates.ts new file mode 100644 index 000000000000..a3b2ce50e04b --- /dev/null +++ b/x-pack/test/api_integration/apis/management/index_management/templates.ts @@ -0,0 +1,429 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { TemplateDeserialized } from '@kbn/index-management-plugin/common'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { templatesApi } from './lib/templates.api'; +import { templatesHelpers } from './lib/templates.helpers'; +import { getRandomString } from './lib/random'; + +export default function ({ getService }: FtrProviderContext) { + const log = getService('log'); + const { catTemplate, getTemplatePayload, getSerializedTemplate } = templatesHelpers(getService); + const { + getAllTemplates, + getOneTemplate, + createTemplate, + deleteTemplates, + updateTemplate, + cleanUpTemplates, + simulateTemplate, + } = templatesApi(getService); + + describe('index templates', () => { + after(async () => await cleanUpTemplates()); + + describe('get all', () => { + const indexTemplate = getTemplatePayload(`template-${getRandomString()}`, [ + getRandomString(), + ]); + const legacyTemplate = getTemplatePayload( + `template-${getRandomString()}`, + [getRandomString()], + true + ); + const tmpTemplate = getTemplatePayload(`template-${getRandomString()}`, [getRandomString()]); + const indexTemplateWithDSL = { + ...tmpTemplate, + dataStream: {}, + template: { + ...tmpTemplate.template, + lifecycle: { + enabled: true, + data_retention: '10d', + }, + }, + }; + const tmpTemplate2 = getTemplatePayload(`template-${getRandomString()}`, [getRandomString()]); + const indexTemplateWithILM = { + ...tmpTemplate2, + template: { + ...tmpTemplate2.template, + settings: { + ...tmpTemplate2.template?.settings, + index: { + lifecycle: { + name: 'my_policy', + }, + }, + }, + }, + }; + + beforeEach(async () => { + try { + await createTemplate(indexTemplate); + await createTemplate(legacyTemplate); + await createTemplate(indexTemplateWithDSL); + await createTemplate(indexTemplateWithILM); + } catch (err) { + log.debug('[Setup error] Error creating index template'); + throw err; + } + }); + + it('should list all the index templates with the expected parameters', async () => { + const { body: allTemplates } = await getAllTemplates().expect(200); + + // Index templates (composable) + const indexTemplateFound = allTemplates.templates.find( + (template: TemplateDeserialized) => template.name === indexTemplate.name + ); + + expect(indexTemplateFound).to.be.ok(); + + const expectedKeys = [ + 'name', + 'indexPatterns', + 'hasSettings', + 'hasAliases', + 'hasMappings', + 'priority', + 'composedOf', + 'version', + '_kbnMeta', + ].sort(); + + expect(Object.keys(indexTemplateFound).sort()).to.eql(expectedKeys); + + // Legacy index templates + const legacyTemplateFound = allTemplates.legacyTemplates.find( + (template: TemplateDeserialized) => template.name === legacyTemplate.name + ); + + expect(legacyTemplateFound).to.be.ok(); + + const expectedLegacyKeys = [ + 'name', + 'indexPatterns', + 'hasSettings', + 'hasAliases', + 'hasMappings', + 'order', + 'version', + '_kbnMeta', + 'composedOf', + ].sort(); + + expect(Object.keys(legacyTemplateFound).sort()).to.eql(expectedLegacyKeys); + + // Index template with DSL + const templateWithDSL = allTemplates.templates.find( + (template: TemplateDeserialized) => template.name === indexTemplateWithDSL.name + ); + + expect(templateWithDSL).to.be.ok(); + + const expectedWithDSLKeys = [ + 'name', + 'indexPatterns', + 'lifecycle', + 'hasSettings', + 'hasAliases', + 'hasMappings', + 'priority', + 'composedOf', + 'dataStream', + 'version', + '_kbnMeta', + ].sort(); + + expect(Object.keys(templateWithDSL).sort()).to.eql(expectedWithDSLKeys); + + // Index template with ILM + const templateWithILM = allTemplates.templates.find( + (template: TemplateDeserialized) => template.name === indexTemplateWithILM.name + ); + + expect(templateWithILM).to.be.ok(); + + const expectedWithILMKeys = [ + 'name', + 'indexPatterns', + 'ilmPolicy', + 'hasSettings', + 'hasAliases', + 'hasMappings', + 'priority', + 'composedOf', + 'version', + '_kbnMeta', + ].sort(); + + expect(Object.keys(templateWithILM).sort()).to.eql(expectedWithILMKeys); + }); + }); + + describe('get one', () => { + const templateName = `template-${getRandomString()}`; + + it('should return an index template with the expected parameters', async () => { + const template = getTemplatePayload(templateName, [getRandomString()]); + await createTemplate(template).expect(200); + + const { body } = await getOneTemplate(templateName).expect(200); + const expectedKeys = [ + 'name', + 'indexPatterns', + 'template', + 'composedOf', + 'priority', + 'version', + '_kbnMeta', + ].sort(); + const expectedTemplateKeys = ['aliases', 'mappings', 'settings'].sort(); + + expect(body.name).to.equal(templateName); + expect(Object.keys(body).sort()).to.eql(expectedKeys); + expect(Object.keys(body.template).sort()).to.eql(expectedTemplateKeys); + }); + + it('should return a legacy index template with the expected parameters', async () => { + const legacyTemplate = getTemplatePayload(templateName, [getRandomString()], true); + await createTemplate(legacyTemplate).expect(200); + + const { body } = await getOneTemplate(templateName, true).expect(200); + const expectedKeys = [ + 'name', + 'indexPatterns', + 'template', + 'order', + 'version', + '_kbnMeta', + 'composedOf', + ].sort(); + const expectedTemplateKeys = ['aliases', 'mappings', 'settings'].sort(); + + expect(body.name).to.equal(templateName); + expect(Object.keys(body).sort()).to.eql(expectedKeys); + expect(Object.keys(body.template).sort()).to.eql(expectedTemplateKeys); + }); + }); + + describe('create', () => { + it('should create an index template', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()]); + + await createTemplate(payload).expect(200); + }); + + it('should create a legacy index template', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()], true); + + await createTemplate(payload).expect(200); + }); + + it('should throw a 409 conflict when trying to create 2 templates with the same name', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()]); + + await createTemplate(payload); + + await createTemplate(payload).expect(409); + }); + + it('should validate the request payload', async () => { + const templateName = `template-${getRandomString()}`; + // need to cast as any to avoid errors after deleting index patterns + const payload = getTemplatePayload(templateName, [getRandomString()]) as any; + + delete payload.indexPatterns; // index patterns are required + + const { body } = await createTemplate(payload); + expect(body.message).to.contain( + '[request body.indexPatterns]: expected value of type [array] ' + ); + }); + + it('should parse the ES error and return the cause', async () => { + const templateName = `template-create-parse-es-error}`; + const payload = getTemplatePayload(templateName, ['create-parse-es-error']); + const runtime = { + myRuntimeField: { + type: 'boolean', + script: { + source: 'emit("hello with error', // error in script + }, + }, + }; + payload.template!.mappings = { ...payload.template!.mappings, runtime }; + const { body } = await createTemplate(payload).expect(400); + + expect(body.attributes).an('object'); + expect(body.attributes.error.reason).contain('template after composition is invalid'); + // one of the item of the cause array should point to our script + expect(body.attributes.causes.join(',')).contain('"hello with error'); + }); + }); + + describe('update', () => { + it('should update an index template', async () => { + const templateName = `template-${getRandomString()}`; + const indexTemplate = getTemplatePayload(templateName, [getRandomString()]); + + await createTemplate(indexTemplate).expect(200); + + let { body: catTemplateResponse } = await catTemplate(templateName); + + const { name, version } = indexTemplate; + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(version?.toString()); + + // Update template with new version + const updatedVersion = 2; + await updateTemplate({ ...indexTemplate, version: updatedVersion }, templateName).expect( + 200 + ); + + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(updatedVersion.toString()); + }); + + it('should update a legacy index template', async () => { + const templateName = `template-${getRandomString()}`; + const legacyIndexTemplate = getTemplatePayload(templateName, [getRandomString()], true); + + await createTemplate(legacyIndexTemplate).expect(200); + + let { body: catTemplateResponse } = await catTemplate(templateName); + + const { name, version } = legacyIndexTemplate; + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(version?.toString()); + + // Update template with new version + const updatedVersion = 2; + await updateTemplate( + { ...legacyIndexTemplate, version: updatedVersion }, + templateName + ).expect(200); + + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(updatedVersion.toString()); + }); + + it('should parse the ES error and return the cause', async () => { + const templateName = `template-update-parse-es-error`; + const payload = getTemplatePayload(templateName, ['update-parse-es-error']); + const runtime = { + myRuntimeField: { + type: 'keyword', + script: { + source: 'emit("hello")', + }, + }, + }; + + // Add runtime field + payload.template!.mappings = { ...payload.template!.mappings, runtime }; + + await createTemplate(payload).expect(200); + + // Update template with an error in the runtime field script + payload.template!.mappings.runtime.myRuntimeField.script = 'emit("hello with error'; + const { body } = await updateTemplate(payload, templateName).expect(400); + + expect(body.attributes).an('object'); + // one of the item of the cause array should point to our script + expect(body.attributes.causes.join(',')).contain('"hello with error'); + }); + }); + + describe('delete', () => { + it('should delete an index template', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()]); + + const { status: createStatus, body: createBody } = await createTemplate(payload); + if (createStatus !== 200) { + throw new Error(`Error creating template: ${createStatus} ${createBody.message}`); + } + + let { body: catTemplateResponse } = await catTemplate(templateName); + + expect( + catTemplateResponse.find((template) => template.name === payload.name)?.name + ).to.equal(templateName); + + const { status: deleteStatus, body: deleteBody } = await deleteTemplates([ + { name: templateName }, + ]); + if (deleteStatus !== 200) { + throw new Error(`Error deleting template: ${deleteBody.message}`); + } + + expect(deleteBody.errors).to.be.empty(); + expect(deleteBody.templatesDeleted[0]).to.equal(templateName); + + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect(catTemplateResponse.find((template) => template.name === payload.name)).to.equal( + undefined + ); + }); + + it('should delete a legacy index template', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()], true); + + await createTemplate(payload).expect(200); + + let { body: catTemplateResponse } = await catTemplate(templateName); + + expect( + catTemplateResponse.find((template) => template.name === payload.name)?.name + ).to.equal(templateName); + + const { body } = await deleteTemplates([ + { name: templateName, isLegacy: payload._kbnMeta.isLegacy }, + ]).expect(200); + + expect(body.errors).to.be.empty(); + expect(body.templatesDeleted[0]).to.equal(templateName); + + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect(catTemplateResponse.find((template) => template.name === payload.name)).to.equal( + undefined + ); + }); + }); + + describe('simulate', () => { + it('should simulate an index template', async () => { + const payload = getSerializedTemplate([getRandomString()]); + + const { body } = await simulateTemplate(payload).expect(200); + expect(body.template).to.be.ok(); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/maps/migrations.js b/x-pack/test/api_integration/apis/maps/migrations.js index 1295dac5bbb4..30301a80577b 100644 --- a/x-pack/test/api_integration/apis/maps/migrations.js +++ b/x-pack/test/api_integration/apis/maps/migrations.js @@ -75,7 +75,7 @@ export default function ({ getService }) { try { panels = JSON.parse(resp.body.attributes.panelsJSON); } catch (error) { - throw 'Unable to parse panelsJSON from dashboard saved object'; + throw new Error('Unable to parse panelsJSON from dashboard saved object'); } expect(panels.length).to.be(1); expect(panels[0].type).to.be('map'); diff --git a/x-pack/test/api_integration/apis/ml/data_frame_analytics/create_job.ts b/x-pack/test/api_integration/apis/ml/data_frame_analytics/create_job.ts index 84e4f03cdc13..b344579645bf 100644 --- a/x-pack/test/api_integration/apis/ml/data_frame_analytics/create_job.ts +++ b/x-pack/test/api_integration/apis/ml/data_frame_analytics/create_job.ts @@ -6,7 +6,10 @@ */ import expect from '@kbn/expect'; -import type { DataFrameAnalyticsConfig } from '@kbn/ml-data-frame-analytics-utils'; +import { + type DataFrameAnalyticsConfig, + ANALYSIS_CONFIG_TYPE, +} from '@kbn/ml-data-frame-analytics-utils'; import { DeepPartial } from '@kbn/ml-plugin/common/types/common'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { USER } from '../../../../functional/services/ml/security_common'; @@ -35,8 +38,9 @@ export default ({ getService }: FtrProviderContext) => { max_num_threads: 1, // default value }; - const jobTypes = ['classification', 'regression', 'outlier_detection']; - const jobAnalyses: any = { + const jobTypes = Object.values(ANALYSIS_CONFIG_TYPE); + type JobType = typeof jobTypes[number]; + const jobAnalyses = { classification: { dependent_variable: 'y', training_percent: 20, @@ -53,7 +57,7 @@ export default ({ getService }: FtrProviderContext) => { const testJobConfigs: Array<{ jobId: string; - jobType: string; + jobType: JobType; config: DeepPartial; }> = ['Test classification job', 'Test regression job', 'Test outlier detection job'].map( (description, idx) => { @@ -100,12 +104,55 @@ export default ({ getService }: FtrProviderContext) => { expect(body).not.to.be(undefined); - expect(body.description).to.eql(requestBody.description); - expect(body.allow_lazy_start).to.eql(requestBody.allow_lazy_start); - expect(body.model_memory_limit).to.eql(requestBody.model_memory_limit); - expect(body.max_num_threads).to.eql(requestBody.max_num_threads); + expect(body.dataFrameAnalyticsJobsCreated).to.have.length( + 1, + `Expected dataFrameAnalyticsJobsCreated length to be 1, got ${body.dataFrameAnalyticsJobsCreated}.` + ); + expect(body.dataFrameAnalyticsJobsErrors).to.have.length( + 0, + `Expected dataFrameAnalyticsJobsErrors length to be 0, got ${body.dataFrameAnalyticsJobsErrors}.` + ); + expect(body.dataViewsCreated).to.have.length( + 0, + `Expected dataViewsCreated length to be 0, got ${body.dataViewsCreated}.` + ); + expect(body.dataViewsErrors).to.have.length( + 0, + `Expected dataViewsErrors length to be 0, got ${body.dataViewsErrors}.` + ); + }); + + it(`should create ${testConfig.jobType} job and data view with given config`, async () => { + const analyticsId = `${testConfig.jobId}_with_data_view`; + const requestBody = testConfig.config; + + const { body, status } = await supertest + .put( + `/internal/ml/data_frame/analytics/${analyticsId}?createDataView=true&timeFieldName=@timestamp` + ) + .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) + .set(getCommonRequestHeader('1')) + .send(requestBody); + ml.api.assertResponseStatusCode(200, status, body); + + expect(body).not.to.be(undefined); - expect(Object.keys(body.analysis)).to.eql(Object.keys(requestBody.analysis!)); + expect(body.dataFrameAnalyticsJobsCreated).to.have.length( + 1, + `Expected dataFrameAnalyticsJobsCreated length to be 1, got ${body.dataFrameAnalyticsJobsCreated}.` + ); + expect(body.dataFrameAnalyticsJobsErrors).to.have.length( + 0, + `Expected dataFrameAnalyticsJobsErrors length to be 0, got ${body.dataFrameAnalyticsJobsErrors}.` + ); + expect(body.dataViewsCreated).to.have.length( + 1, + `Expected dataViewsCreated length to be 1, got ${body.dataViewsCreated}.` + ); + expect(body.dataViewsErrors).to.have.length( + 0, + `Expected dataViewsErrors length to be 0, got ${body.dataViewsErrors}.` + ); }); }); diff --git a/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts b/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts index f0e69eddb981..f7e3d1666634 100644 --- a/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts +++ b/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts @@ -42,8 +42,8 @@ export default ({ getService }: FtrProviderContext) => { const testJobConfigs: Array> = [ 'Test delete job only', 'Test delete job and target index', - 'Test delete job and index pattern', - 'Test delete job, target index, and index pattern', + 'Test delete job and data view', + 'Test delete job, target index, and data view', ].map((description, idx) => { const analyticsId = `${jobId}_${idx + 1}`; return { @@ -148,71 +148,71 @@ export default ({ getService }: FtrProviderContext) => { expect(body.analyticsJobDeleted.success).to.eql(true); expect(body.destIndexDeleted.success).to.eql(true); - expect(body.destIndexPatternDeleted.success).to.eql(false); + expect(body.destDataViewDeleted.success).to.eql(false); await ml.api.waitForDataFrameAnalyticsJobNotToExist(analyticsId); await ml.api.assertIndicesNotToExist(destinationIndex); }); }); - describe('with deleteDestIndexPattern setting', function () { + describe('with deleteDestDataView setting', function () { const analyticsId = `${jobId}_3`; const destinationIndex = generateDestinationIndex(analyticsId); before(async () => { - // Mimic real job by creating index pattern after job is created - await ml.testResources.createIndexPatternIfNeeded(destinationIndex); + // Mimic real job by creating data view after job is created + await ml.testResources.createDataViewIfNeeded(destinationIndex); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle(destinationIndex); + await ml.testResources.deleteDataViewByTitle(destinationIndex); }); - it('should delete job and index pattern by id', async () => { + it('should delete job and data view by id', async () => { const { body, status } = await supertest .delete(`/internal/ml/data_frame/analytics/${analyticsId}`) - .query({ deleteDestIndexPattern: true }) + .query({ deleteDestDataView: true }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); expect(body.analyticsJobDeleted.success).to.eql(true); expect(body.destIndexDeleted.success).to.eql(false); - expect(body.destIndexPatternDeleted.success).to.eql(true); + expect(body.destDataViewDeleted.success).to.eql(true); await ml.api.waitForDataFrameAnalyticsJobNotToExist(analyticsId); - await ml.testResources.assertIndexPatternNotExist(destinationIndex); + await ml.testResources.assertDataViewNotExist(destinationIndex); }); }); - describe('with deleteDestIndex & deleteDestIndexPattern setting', function () { + describe('with deleteDestIndex & deleteDestDataView setting', function () { const analyticsId = `${jobId}_4`; const destinationIndex = generateDestinationIndex(analyticsId); before(async () => { - // Mimic real job by creating target index & index pattern after DFA job is created + // Mimic real job by creating target index & data view after DFA job is created await ml.api.createIndex(destinationIndex); await ml.api.assertIndicesExist(destinationIndex); - await ml.testResources.createIndexPatternIfNeeded(destinationIndex); + await ml.testResources.createDataViewIfNeeded(destinationIndex); }); after(async () => { await ml.api.deleteIndices(destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(destinationIndex); + await ml.testResources.deleteDataViewByTitle(destinationIndex); }); - it('should delete job, target index, and index pattern by id', async () => { + it('should delete job, target index, and data view by id', async () => { const { body, status } = await supertest .delete(`/internal/ml/data_frame/analytics/${analyticsId}`) - .query({ deleteDestIndex: true, deleteDestIndexPattern: true }) + .query({ deleteDestIndex: true, deleteDestDataView: true }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); expect(body.analyticsJobDeleted.success).to.eql(true); expect(body.destIndexDeleted.success).to.eql(true); - expect(body.destIndexPatternDeleted.success).to.eql(true); + expect(body.destDataViewDeleted.success).to.eql(true); await ml.api.waitForDataFrameAnalyticsJobNotToExist(analyticsId); await ml.api.assertIndicesNotToExist(destinationIndex); - await ml.testResources.assertIndexPatternNotExist(destinationIndex); + await ml.testResources.assertDataViewNotExist(destinationIndex); }); }); }); diff --git a/x-pack/test/api_integration/apis/ml/data_frame_analytics/get.ts b/x-pack/test/api_integration/apis/ml/data_frame_analytics/get.ts index 464014f99648..2459f81b188b 100644 --- a/x-pack/test/api_integration/apis/ml/data_frame_analytics/get.ts +++ b/x-pack/test/api_integration/apis/ml/data_frame_analytics/get.ts @@ -273,9 +273,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body.elements.length).to.eql(0); expect(body.details).to.eql({}); - expect(body.error).to.eql(`No known job with id '${jobId}_fake'`); - - expect(body).to.have.keys('elements', 'details', 'error'); + expect(body).to.have.keys('elements', 'details'); }); }); diff --git a/x-pack/test/api_integration/apis/ml/data_frame_analytics/get_spaces.ts b/x-pack/test/api_integration/apis/ml/data_frame_analytics/get_spaces.ts index e294ddb51d7e..4b981b14a381 100644 --- a/x-pack/test/api_integration/apis/ml/data_frame_analytics/get_spaces.ts +++ b/x-pack/test/api_integration/apis/ml/data_frame_analytics/get_spaces.ts @@ -207,7 +207,6 @@ export default ({ getService }: FtrProviderContext) => { `Expected 0 map elements, got ${body.elements.length}` ); expect(body.details).to.eql({}); - expect(body.error).to.eql(`No known job with id '${jobIdSpace1}'`); }); }); }); diff --git a/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts b/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts index 4f759a1c5a93..eff763fbcfcd 100644 --- a/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts +++ b/x-pack/test/api_integration/apis/ml/jobs/close_jobs.ts @@ -46,12 +46,12 @@ export default ({ getService }: FtrProviderContext) => { describe('close_jobs', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); beforeEach(async () => { diff --git a/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts b/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts index f45f7052b65c..610d5be81278 100644 --- a/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts +++ b/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts @@ -83,13 +83,13 @@ export default ({ getService }: FtrProviderContext) => { describe('jobs_exist', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); }); after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('sets up jobs', async () => { diff --git a/x-pack/test/api_integration/apis/ml/jobs/reset.ts b/x-pack/test/api_integration/apis/ml/jobs/reset.ts index 0b69097a907e..2e193816efb9 100644 --- a/x-pack/test/api_integration/apis/ml/jobs/reset.ts +++ b/x-pack/test/api_integration/apis/ml/jobs/reset.ts @@ -55,12 +55,12 @@ export default ({ getService }: FtrProviderContext) => { describe('reset_jobs', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); beforeEach(async () => { diff --git a/x-pack/test/api_integration/apis/ml/modules/jobs_exist.ts b/x-pack/test/api_integration/apis/ml/modules/jobs_exist.ts index 0f59baa11d13..22176a6e5c7f 100644 --- a/x-pack/test/api_integration/apis/ml/modules/jobs_exist.ts +++ b/x-pack/test/api_integration/apis/ml/modules/jobs_exist.ts @@ -39,12 +39,12 @@ export default ({ getService }: FtrProviderContext) => { await ml.testResources.setKibanaTimeZoneToUTC(); await esArchiver.loadIfNeeded(sourceDataArchive); // create data view in default space - await ml.testResources.createIndexPatternIfNeeded( + await ml.testResources.createDataViewIfNeeded( moduleInfo.dataView.name, moduleInfo.dataView.timeField ); // create data view in idSpace1 - await ml.testResources.createIndexPatternIfNeeded( + await ml.testResources.createDataViewIfNeeded( moduleInfo.dataView.name, moduleInfo.dataView.timeField, idSpace1 @@ -57,8 +57,8 @@ export default ({ getService }: FtrProviderContext) => { after(async () => { // delete all data views in all spaces - await ml.testResources.deleteIndexPatternByTitle(moduleInfo.dataView.name); - await ml.testResources.deleteIndexPatternByTitle(moduleInfo.dataView.name, idSpace1); + await ml.testResources.deleteDataViewByTitle(moduleInfo.dataView.name); + await ml.testResources.deleteDataViewByTitle(moduleInfo.dataView.name, idSpace1); }); it('should find jobs installed by module without prefix', async () => { diff --git a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts index 1eb327c897b0..27d6d048e3f8 100644 --- a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts @@ -710,7 +710,7 @@ export default ({ getService }: FtrProviderContext) => { describe('sets up module data', function () { before(async () => { await esArchiver.loadIfNeeded(testData.sourceDataArchive); - await ml.testResources.createIndexPatternIfNeeded( + await ml.testResources.createDataViewIfNeeded( testData.indexPattern.name, testData.indexPattern.timeField ); @@ -730,7 +730,7 @@ export default ({ getService }: FtrProviderContext) => { await ml.api.deleteAnomalyDetectionJobES(job.jobId); } await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle(testData.indexPattern.name); + await ml.testResources.deleteDataViewByTitle(testData.indexPattern.name); }); it(testData.testTitleSuffix, async () => { @@ -864,7 +864,7 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.loadIfNeeded(testData.sourceDataArchive!); } if (testData.hasOwnProperty('indexPattern')) { - await ml.testResources.createIndexPatternIfNeeded( + await ml.testResources.createDataViewIfNeeded( testData.indexPattern!.name as string, testData.indexPattern!.timeField as string ); @@ -874,7 +874,7 @@ export default ({ getService }: FtrProviderContext) => { after(async () => { await ml.api.cleanMlIndices(); if (testData.hasOwnProperty('indexPattern')) { - await ml.testResources.deleteIndexPatternByTitle(testData.indexPattern!.name); + await ml.testResources.deleteDataViewByTitle(testData.indexPattern!.name); } }); diff --git a/x-pack/test/api_integration/apis/ml/results/get_categorizer_stats.ts b/x-pack/test/api_integration/apis/ml/results/get_categorizer_stats.ts index 9c0add9e6be9..87154beb07ef 100644 --- a/x-pack/test/api_integration/apis/ml/results/get_categorizer_stats.ts +++ b/x-pack/test/api_integration/apis/ml/results/get_categorizer_stats.ts @@ -60,7 +60,7 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_logs'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_logs'); await ml.api.cleanMlIndices(); }); diff --git a/x-pack/test/api_integration/apis/ml/results/get_stopped_partitions.ts b/x-pack/test/api_integration/apis/ml/results/get_stopped_partitions.ts index d72214128232..3dc4686102c3 100644 --- a/x-pack/test/api_integration/apis/ml/results/get_stopped_partitions.ts +++ b/x-pack/test/api_integration/apis/ml/results/get_stopped_partitions.ts @@ -96,7 +96,7 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_logs'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_logs'); await ml.api.cleanMlIndices(); }); diff --git a/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts b/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts index ab9650541464..9a0c4546a2e7 100644 --- a/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts +++ b/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts @@ -10,11 +10,10 @@ import { FtrProviderContext } from '../../ftr_provider_context'; const API_BASE_PATH = '/api/searchprofiler'; -// Flaky https://github.com/elastic/kibana/issues/97954 export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - describe.skip('Profile', () => { + describe('Profile', () => { it('should return profile results for a valid index', async () => { const payload = { index: '_all', @@ -46,7 +45,7 @@ export default function ({ getService }: FtrProviderContext) { }; const { body } = await supertest - .post(`${API_BASE_PATH}/execute`) + .post(`${API_BASE_PATH}/profile`) .set('kbn-xsrf', 'xxx') .set('Content-Type', 'application/json;charset=UTF-8') .send(payloadWithInvalidIndex) diff --git a/x-pack/test/api_integration/apis/security/privileges.ts b/x-pack/test/api_integration/apis/security/privileges.ts index 81cceb6561bd..04a417748534 100644 --- a/x-pack/test/api_integration/apis/security/privileges.ts +++ b/x-pack/test/api_integration/apis/security/privileges.ts @@ -22,8 +22,22 @@ export default function ({ getService }: FtrProviderContext) { savedObjectsTagging: ['all', 'read', 'minimal_all', 'minimal_read'], canvas: ['all', 'read', 'minimal_all', 'minimal_read'], maps: ['all', 'read', 'minimal_all', 'minimal_read'], - generalCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], - observabilityCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], + generalCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], + observabilityCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], observabilityAIAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], slo: ['all', 'read', 'minimal_all', 'minimal_read'], fleetv2: ['all', 'read', 'minimal_all', 'minimal_read'], @@ -57,7 +71,14 @@ export default function ({ getService }: FtrProviderContext) { ], uptime: ['all', 'read', 'minimal_all', 'minimal_read', 'elastic_managed_locations_enabled'], securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], - securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], + securitySolutionCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'], logs: ['all', 'read', 'minimal_all', 'minimal_read'], apm: ['all', 'read', 'minimal_all', 'minimal_read'], diff --git a/x-pack/test/api_integration/apis/security/privileges_basic.ts b/x-pack/test/api_integration/apis/security/privileges_basic.ts index 174ac2a3c8f6..2773adfe070e 100644 --- a/x-pack/test/api_integration/apis/security/privileges_basic.ts +++ b/x-pack/test/api_integration/apis/security/privileges_basic.ts @@ -98,8 +98,22 @@ export default function ({ getService }: FtrProviderContext) { savedObjectsTagging: ['all', 'read', 'minimal_all', 'minimal_read'], canvas: ['all', 'read', 'minimal_all', 'minimal_read'], maps: ['all', 'read', 'minimal_all', 'minimal_read'], - generalCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], - observabilityCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], + generalCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], + observabilityCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], observabilityAIAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], slo: ['all', 'read', 'minimal_all', 'minimal_read'], fleetv2: ['all', 'read', 'minimal_all', 'minimal_read'], @@ -139,7 +153,14 @@ export default function ({ getService }: FtrProviderContext) { 'minimal_read', ], securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], - securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], + securitySolutionCases: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'cases_delete', + 'cases_settings', + ], infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'], logs: ['all', 'read', 'minimal_all', 'minimal_read'], apm: ['all', 'read', 'minimal_all', 'minimal_read'], diff --git a/x-pack/test/api_integration/apis/synthetics/add_monitor.ts b/x-pack/test/api_integration/apis/synthetics/add_monitor.ts index db98633941ee..72e872de27f9 100644 --- a/x-pack/test/api_integration/apis/synthetics/add_monitor.ts +++ b/x-pack/test/api_integration/apis/synthetics/add_monitor.ts @@ -9,7 +9,11 @@ import moment from 'moment/moment'; import { v4 as uuidv4 } from 'uuid'; import { omit } from 'lodash'; import { secretKeys } from '@kbn/synthetics-plugin/common/constants/monitor_management'; -import { ConfigKey, DataStream, HTTPFields } from '@kbn/synthetics-plugin/common/runtime_types'; +import { + ConfigKey, + MonitorTypeEnum, + HTTPFields, +} from '@kbn/synthetics-plugin/common/runtime_types'; import { formatKibanaNamespace } from '@kbn/synthetics-plugin/common/formatters'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; import { DEFAULT_FIELDS } from '@kbn/synthetics-plugin/common/constants/monitor_defaults'; @@ -124,7 +128,7 @@ export default function ({ getService }: FtrProviderContext) { expect(apiResponse.body).eql( omit( { - ...DEFAULT_FIELDS[DataStream.HTTP], + ...DEFAULT_FIELDS[MonitorTypeEnum.HTTP], ...newMonitor, [ConfigKey.MONITOR_QUERY_ID]: apiResponse.body.id, [ConfigKey.CONFIG_ID]: apiResponse.body.id, diff --git a/x-pack/test/api_integration/apis/transform/delete_transforms.ts b/x-pack/test/api_integration/apis/transform/delete_transforms.ts index faf18e5d610e..a064fd28b214 100644 --- a/x-pack/test/api_integration/apis/transform/delete_transforms.ts +++ b/x-pack/test/api_integration/apis/transform/delete_transforms.ts @@ -232,12 +232,12 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await createTransform(transformId); await transform.api.createIndices(destinationIndex); - await transform.testResources.createIndexPatternIfNeeded(destinationIndex); + await transform.testResources.createDataViewIfNeeded(destinationIndex); }); after(async () => { await transform.api.deleteIndices(destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(destinationIndex); + await transform.testResources.deleteDataViewByTitle(destinationIndex); }); it('should delete transform and destination index pattern', async () => { @@ -261,7 +261,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body[transformId].destDataViewDeleted.success).to.eql(true); await transform.api.waitForTransformNotToExist(transformId); await transform.api.waitForIndicesToExist(destinationIndex); - await transform.testResources.assertIndexPatternNotExist(destinationIndex); + await transform.testResources.assertDataViewNotExist(destinationIndex); }); }); @@ -272,12 +272,12 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await createTransform(transformId); await transform.api.createIndices(destinationIndex); - await transform.testResources.createIndexPatternIfNeeded(destinationIndex); + await transform.testResources.createDataViewIfNeeded(destinationIndex); }); after(async () => { await transform.api.deleteIndices(destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(destinationIndex); + await transform.testResources.deleteDataViewByTitle(destinationIndex); }); it('should delete transform, destination index, & destination index pattern', async () => { @@ -301,7 +301,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body[transformId].destDataViewDeleted.success).to.eql(true); await transform.api.waitForTransformNotToExist(transformId); await transform.api.waitForIndicesNotToExist(destinationIndex); - await transform.testResources.assertIndexPatternNotExist(destinationIndex); + await transform.testResources.assertDataViewNotExist(destinationIndex); }); }); }); diff --git a/x-pack/test/api_integration/apis/transform/transforms_create.ts b/x-pack/test/api_integration/apis/transform/transforms_create.ts index e82f1d4fdfdd..a41a7f3c5709 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_create.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_create.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; import { USER } from '../../../functional/services/transform/security_common'; -import { generateTransformConfig } from './common'; +import { generateTransformConfig, generateDestIndex } from './common'; export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); @@ -27,8 +27,102 @@ export default ({ getService }: FtrProviderContext) => { await transform.api.cleanTransformIndices(); }); + it('should create a transform', async () => { + const transformId = 'test_transform_id_create'; + + const { body, status } = await supertest + .put(`/internal/transform/transforms/${transformId}`) + .auth( + USER.TRANSFORM_POWERUSER, + transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) + ) + .set(getCommonRequestHeader('1')) + .send({ + ...generateTransformConfig(transformId), + }); + + transform.api.assertResponseStatusCode(200, status, body); + + expect(body).to.eql({ + dataViewsCreated: [], + dataViewsErrors: [], + errors: [], + transformsCreated: [ + { + transform: transformId, + }, + ], + }); + }); + + it('should create a transform with data view', async () => { + const transformId = 'test_transform_id_create_with_data_view'; + const destinationIndex = generateDestIndex(transformId); + + const { body, status } = await supertest + .put(`/internal/transform/transforms/${transformId}?createDataView=true`) + .auth( + USER.TRANSFORM_POWERUSER, + transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) + ) + .set(getCommonRequestHeader('1')) + .send({ + ...generateTransformConfig(transformId), + }); + + transform.api.assertResponseStatusCode(200, status, body); + + // The data view id will be returned as a non-deterministic uuid + // so we cannot assert the actual id returned. We'll just assert + // that a data view has been created a no errors were returned. + expect(body.dataViewsCreated.length).to.be(1); + expect(body.dataViewsErrors.length).to.be(0); + expect(body.errors.length).to.be(0); + expect(body.transformsCreated).to.eql([ + { + transform: transformId, + }, + ]); + + await transform.testResources.deleteDataViewByTitle(destinationIndex); + }); + + it('should create a transform with data view and time field', async () => { + const transformId = 'test_transform_id_create_with_data_view_and_time_field'; + const destinationIndex = generateDestIndex(transformId); + + const { body, status } = await supertest + .put( + `/internal/transform/transforms/${transformId}?createDataView=true&timeFieldName=@timestamp` + ) + .auth( + USER.TRANSFORM_POWERUSER, + transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) + ) + .set(getCommonRequestHeader('1')) + .send({ + ...generateTransformConfig(transformId), + }); + + transform.api.assertResponseStatusCode(200, status, body); + + // The data view id will be returned as a non-deterministic uuid + // so we cannot assert the actual id returned. We'll just assert + // that a data view has been created a no errors were returned. + expect(body.dataViewsCreated.length).to.be(1); + expect(body.dataViewsErrors.length).to.be(0); + expect(body.errors.length).to.be(0); + expect(body.transformsCreated).to.eql([ + { + transform: transformId, + }, + ]); + + await transform.testResources.deleteDataViewByTitle(destinationIndex); + }); + it('should not allow pivot and latest configs in same transform', async () => { - const transformId = 'test_transform_id'; + const transformId = 'test_transform_id_fail'; const { body, status } = await supertest .put(`/internal/transform/transforms/${transformId}`) @@ -50,7 +144,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should ensure if pivot or latest is provided', async () => { - const transformId = 'test_transform_id'; + const transformId = 'test_transform_id_fail'; const { pivot, ...config } = generateTransformConfig(transformId); diff --git a/x-pack/test/api_integration/apis/watcher/watcher.ts b/x-pack/test/api_integration/apis/watcher/watcher.ts index 734b6c8c6212..a5d26c98dfe7 100644 --- a/x-pack/test/api_integration/apis/watcher/watcher.ts +++ b/x-pack/test/api_integration/apis/watcher/watcher.ts @@ -17,7 +17,7 @@ export default function ({ getService }: FtrProviderContext) { describe('watcher', () => { before(async () => { try { - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); } catch (error) { log.debug('[Setup error] Error creating index pattern'); throw error; @@ -26,7 +26,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { try { - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); } catch (error) { log.debug('[Cleanup error] Error deleting index pattern'); throw error; diff --git a/x-pack/test/api_integration/services/index.ts b/x-pack/test/api_integration/services/index.ts index 6ef3e393a86e..1f8d4576d908 100644 --- a/x-pack/test/api_integration/services/index.ts +++ b/x-pack/test/api_integration/services/index.ts @@ -21,6 +21,7 @@ import { MachineLearningProvider } from './ml'; import { IngestManagerProvider } from '../../common/services/ingest_manager'; import { TransformProvider } from './transform'; import { IngestPipelinesProvider } from './ingest_pipelines'; +import { IndexManagementProvider } from './index_management'; export const services = { ...commonServices, @@ -37,4 +38,5 @@ export const services = { ingestManager: IngestManagerProvider, transform: TransformProvider, ingestPipelines: IngestPipelinesProvider, + indexManagement: IndexManagementProvider, }; diff --git a/x-pack/test/api_integration/services/index_management.ts b/x-pack/test/api_integration/services/index_management.ts new file mode 100644 index 000000000000..dc78a8469687 --- /dev/null +++ b/x-pack/test/api_integration/services/index_management.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; +import { indicesApi } from '../apis/management/index_management/lib/indices.api'; +import { mappingsApi } from '../apis/management/index_management/lib/mappings.api'; +import { indicesHelpers } from '../apis/management/index_management/lib/indices.helpers'; +import { templatesApi } from '../apis/management/index_management/lib/templates.api'; +import { templatesHelpers } from '../apis/management/index_management/lib/templates.helpers'; +import { componentTemplatesApi } from '../apis/management/index_management/lib/component_templates.api'; +import { componentTemplateHelpers } from '../apis/management/index_management/lib/component_template.helpers'; +import { settingsApi } from '../apis/management/index_management/lib/settings.api'; +import { clusterNodesApi } from '../apis/management/index_management/lib/cluster_nodes.api'; +import { datastreamsHelpers } from '../apis/management/index_management/lib/datastreams.helpers'; + +export function IndexManagementProvider({ getService }: FtrProviderContext) { + return { + indices: { + api: indicesApi(getService), + helpers: indicesHelpers(getService), + }, + componentTemplates: { + api: componentTemplatesApi(getService), + helpers: componentTemplateHelpers(getService), + }, + clusterNodes: { + api: clusterNodesApi(getService), + }, + datastreams: { + helpers: datastreamsHelpers(getService), + }, + mappings: { + api: mappingsApi(getService), + }, + templates: { + api: templatesApi(getService), + helpers: templatesHelpers(getService), + }, + settings: { + api: settingsApi(getService), + }, + }; +} diff --git a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts index ac16abff4098..4fe7ae4a62e7 100644 --- a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts +++ b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts @@ -20,6 +20,7 @@ export function createApmApiClient(st: supertest.SuperTest) { options: { type?: 'form-data'; endpoint: TEndpoint; + spaceId?: string; } & APIClientRequestParamsOf & { params?: { query?: { _inspect?: boolean } } } ): Promise> => { const { endpoint, type } = options; @@ -27,7 +28,8 @@ export function createApmApiClient(st: supertest.SuperTest) { const params = 'params' in options ? (options.params as Record) : {}; const { method, pathname, version } = formatRequest(endpoint, params.path); - const url = format({ pathname, query: params?.query }); + const pathnameWithSpaceId = options.spaceId ? `/s/${options.spaceId}${pathname}` : pathname; + const url = format({ pathname: pathnameWithSpaceId, query: params?.query }); const headers: Record = { 'kbn-xsrf': 'foo', diff --git a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts index a49e698c86c6..dcc8fc76044c 100644 --- a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts +++ b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts @@ -8,7 +8,7 @@ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; import expect from '@kbn/expect'; -import { APM_STATIC_DATA_VIEW_ID } from '@kbn/apm-plugin/common/data_view_constants'; +import { getDataViewId } from '@kbn/apm-plugin/common/data_view_constants'; import { DataView } from '@kbn/data-views-plugin/common'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import request from 'superagent'; @@ -20,28 +20,33 @@ export default function ApiTest({ getService }: FtrProviderContext) { const apmApiClient = getService('apmApiClient'); const supertest = getService('supertest'); const synthtrace = getService('synthtraceEsClient'); + const logger = getService('log'); const dataViewPattern = 'traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*'; - function createDataViewWithWriteUser() { + function createDataViewWithWriteUser({ spaceId }: { spaceId: string }) { return apmApiClient.writeUser({ endpoint: 'POST /internal/apm/data_view/static', + spaceId, }); } - function createDataViewWithReadUser() { - return apmApiClient.readUser({ endpoint: 'POST /internal/apm/data_view/static' }); + function createDataViewWithReadUser({ spaceId }: { spaceId: string }) { + return apmApiClient.readUser({ + endpoint: 'POST /internal/apm/data_view/static', + spaceId, + }); } - function deleteDataView() { + function deleteDataView(spaceId: string) { return supertest - .delete(`/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}?force=true`) + .delete(`/s/${spaceId}/api/saved_objects/index-pattern/${getDataViewId(spaceId)}?force=true`) .set('kbn-xsrf', 'foo'); } - function getDataView({ space }: { space: string }) { - const spacePrefix = space !== 'default' ? `/s/${space}` : ''; + function getDataView({ spaceId }: { spaceId: string }) { + const spacePrefix = spaceId !== 'default' ? `/s/${spaceId}` : ''; return supertest.get( - `${spacePrefix}/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}` + `${spacePrefix}/api/saved_objects/index-pattern/${getDataViewId(spaceId)}` ); } @@ -56,7 +61,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('no mappings exist', { config: 'basic', archives: [] }, () => { let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; before(async () => { - response = await createDataViewWithWriteUser(); + response = await createDataViewWithWriteUser({ spaceId: 'default' }); }); it('does not create data view', async () => { @@ -68,10 +73,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('cannot fetch data view', async () => { - const res = await getDataView({ space: 'default' }); + const res = await getDataView({ spaceId: 'default' }); expect(res.status).to.be(404); expect(res.body.message).to.eql( - 'Saved object [index-pattern/apm_static_index_pattern_id] not found' + 'Saved object [index-pattern/apm_static_data_view_id_default] not found' ); }); }); @@ -86,14 +91,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); afterEach(async () => { - await deleteDataView(); + try { + await Promise.all([deleteDataView('default'), deleteDataView('foo')]); + } catch (e) { + logger.error(`Could not delete data views ${e.message}`); + } }); describe('when creating data view with write user', () => { let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; before(async () => { - response = await createDataViewWithWriteUser(); + response = await createDataViewWithWriteUser({ spaceId: 'default' }); }); it('successfully creates the apm data view', async () => { @@ -102,7 +111,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { // @ts-expect-error const dataView = response.body.dataView as DataView; - expect(dataView.id).to.be('apm_static_index_pattern_id'); + expect(dataView.id).to.be('apm_static_data_view_id_default'); expect(dataView.name).to.be('APM'); expect(dataView.title).to.be('traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*'); }); @@ -112,8 +121,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { let dataViewResponse: request.Response; before(async () => { - await createDataViewWithWriteUser(); - dataViewResponse = await getDataView({ space: 'default' }); + await createDataViewWithWriteUser({ spaceId: 'default' }); + dataViewResponse = await getDataView({ spaceId: 'default' }); }); it('return 200', () => { @@ -121,7 +130,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('has correct id', () => { - expect(dataViewResponse.body.id).to.be('apm_static_index_pattern_id'); + expect(dataViewResponse.body.id).to.be('apm_static_data_view_id_default'); }); it('has correct title', () => { @@ -170,7 +179,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('when creating data view via read user', () => { it('throws an error', async () => { try { - await createDataViewWithReadUser(); + await createDataViewWithReadUser({ spaceId: 'default' }); } catch (e) { const err = e as ApmApiError; const responseBody = err.res.body; @@ -184,30 +193,44 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('when creating data view twice', () => { it('returns 200 response with reason, if data view already exists', async () => { - await createDataViewWithWriteUser(); - const res = await createDataViewWithWriteUser(); + await createDataViewWithWriteUser({ spaceId: 'default' }); + const res = await createDataViewWithWriteUser({ spaceId: 'default' }); expect(res.status).to.be(200); expect(res.body).to.eql({ created: false, - reason: 'Dataview already exists in the active space', + reason: 'Dataview already exists in the active space and does not need to be updated', }); }); }); describe('when creating data view in "default" space', async () => { - it('can be retrieved from the "default space"', async () => { - await createDataViewWithWriteUser(); - const res = await getDataView({ space: 'default' }); - expect(res.body.id).to.eql('apm_static_index_pattern_id'); - expect(res.body.namespaces).to.eql(['*', 'default']); + it('can be retrieved from the "default" space', async () => { + await createDataViewWithWriteUser({ spaceId: 'default' }); + const res = await getDataView({ spaceId: 'default' }); + expect(res.body.id).to.eql('apm_static_data_view_id_default'); + expect(res.body.namespaces).to.eql(['default']); }); + it('cannot be retrieved from the "foo" space', async () => { + await createDataViewWithWriteUser({ spaceId: 'default' }); + const res = await getDataView({ spaceId: 'foo' }); + expect(res.body.statusCode).to.be(404); + }); + }); + + describe('when creating data view in "foo" space', async () => { it('can be retrieved from the "foo" space', async () => { - await createDataViewWithWriteUser(); - const res = await getDataView({ space: 'foo' }); - expect(res.body.id).to.eql('apm_static_index_pattern_id'); - expect(res.body.namespaces).to.eql(['*', 'default']); + await createDataViewWithWriteUser({ spaceId: 'foo' }); + const res = await getDataView({ spaceId: 'foo' }); + expect(res.body.id).to.eql('apm_static_data_view_id_foo'); + expect(res.body.namespaces).to.eql(['foo']); + }); + + it('cannot be retrieved from the "default" space', async () => { + await createDataViewWithWriteUser({ spaceId: 'foo' }); + const res = await getDataView({ spaceId: 'default' }); + expect(res.body.statusCode).to.be(404); }); }); }); diff --git a/x-pack/test/apm_api_integration/tests/mobile/crashes/crash_group_list.spec.ts b/x-pack/test/apm_api_integration/tests/mobile/crashes/crash_group_list.spec.ts new file mode 100644 index 000000000000..d55967ac7092 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/mobile/crashes/crash_group_list.spec.ts @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { + APIClientRequestParamsOf, + APIReturnType, +} from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { RecursivePartial } from '@kbn/apm-plugin/typings/common'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +type ErrorGroups = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics'>['errorGroups']; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const serviceName = 'synth-swift'; + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + async function callApi( + overrides?: RecursivePartial< + APIClientRequestParamsOf<'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics'>['params'] + > + ) { + return await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/mobile-services/{serviceName}/crashes/groups/main_statistics', + params: { + path: { serviceName, ...overrides?.path }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + environment: 'ENVIRONMENT_ALL', + kuery: '', + ...overrides?.query, + }, + }, + }); + } + + registry.when('when data is not loaded', { config: 'basic', archives: [] }, () => { + it('handles empty state', async () => { + const response = await callApi(); + expect(response.status).to.be(200); + expect(response.body.errorGroups).to.empty(); + }); + }); + + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + describe('errors group', () => { + const appleTransaction = { + name: 'GET /apple 🍎 ', + successRate: 75, + failureRate: 25, + }; + + const bananaTransaction = { + name: 'GET /banana 🍌', + successRate: 50, + failureRate: 50, + }; + + before(async () => { + const serviceInstance = apm + .service({ name: serviceName, environment: 'production', agentName: 'swift' }) + .instance('instance-a'); + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(appleTransaction.successRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: appleTransaction.name }) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(appleTransaction.failureRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: appleTransaction.name }) + .errors( + serviceInstance + .crash({ + message: 'crash 1', + }) + .timestamp(timestamp) + ) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + timerange(start, end) + .interval('1m') + .rate(bananaTransaction.successRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: bananaTransaction.name }) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(bananaTransaction.failureRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: bananaTransaction.name }) + .errors( + serviceInstance + .crash({ + message: 'crash 2', + }) + .timestamp(timestamp) + ) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]); + }); + + after(() => synthtraceEsClient.clean()); + + describe('returns the correct data', () => { + let errorGroups: ErrorGroups; + before(async () => { + const response = await callApi(); + errorGroups = response.body.errorGroups; + }); + it('returns correct number of crashes', () => { + expect(errorGroups.length).to.equal(2); + expect(errorGroups.map((error) => error.name).sort()).to.eql(['crash 1', 'crash 2']); + }); + + it('returns correct occurrences', () => { + const numberOfBuckets = 15; + expect(errorGroups.map((error) => error.occurrences).sort()).to.eql([ + appleTransaction.failureRate * numberOfBuckets, + bananaTransaction.failureRate * numberOfBuckets, + ]); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/mobile/crashes/distribution.spec.ts b/x-pack/test/apm_api_integration/tests/mobile/crashes/distribution.spec.ts new file mode 100644 index 000000000000..b3a553bf980c --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/mobile/crashes/distribution.spec.ts @@ -0,0 +1,202 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { first, last, sumBy } from 'lodash'; +import { isFiniteNumber } from '@kbn/apm-plugin/common/utils/is_finite_number'; +import { + APIClientRequestParamsOf, + APIReturnType, +} from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { RecursivePartial } from '@kbn/apm-plugin/typings/common'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { config, generateData } from './generate_data'; + +type ErrorsDistribution = + APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/crashes/distribution'>; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const serviceName = 'synth-swift'; + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + async function callApi( + overrides?: RecursivePartial< + APIClientRequestParamsOf<'GET /internal/apm/mobile-services/{serviceName}/crashes/distribution'>['params'] + > + ) { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/mobile-services/{serviceName}/crashes/distribution', + params: { + path: { + serviceName, + ...overrides?.path, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + environment: 'ENVIRONMENT_ALL', + kuery: '', + ...overrides?.query, + }, + }, + }); + return response; + } + + registry.when('when data is not loaded', { config: 'basic', archives: [] }, () => { + it('handles the empty state', async () => { + const response = await callApi(); + expect(response.status).to.be(200); + expect(response.body.currentPeriod.length).to.be(0); + expect(response.body.previousPeriod.length).to.be(0); + }); + }); + + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + describe('errors distribution', () => { + const { appleTransaction, bananaTransaction } = config; + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('without comparison', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi(); + errorsDistribution = response.body; + }); + + it('displays combined number of occurrences', () => { + const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); + const numberOfBuckets = 15; + expect(countSum).to.equal( + (appleTransaction.failureRate + bananaTransaction.failureRate) * numberOfBuckets + ); + }); + + describe('displays correct start in errors distribution chart', () => { + let errorsDistributionWithComparison: ErrorsDistribution; + before(async () => { + const responseWithComparison = await callApi({ + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + offset: '15m', + }, + }); + errorsDistributionWithComparison = responseWithComparison.body; + }); + it('has same start time when comparison is enabled', () => { + expect(first(errorsDistribution.currentPeriod)?.x).to.equal( + first(errorsDistributionWithComparison.currentPeriod)?.x + ); + }); + }); + }); + + describe('displays occurrences for type "apple transaction" only', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + query: { kuery: `error.exception.type:"${appleTransaction.name}"` }, + }); + errorsDistribution = response.body; + }); + it('displays combined number of occurrences', () => { + const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); + const numberOfBuckets = 15; + expect(countSum).to.equal(appleTransaction.failureRate * numberOfBuckets); + }); + }); + + describe('with comparison', () => { + describe('when data is returned', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const fiveMinutes = 5 * 60 * 1000; + const response = await callApi({ + query: { + start: new Date(end - fiveMinutes).toISOString(), + end: new Date(end).toISOString(), + offset: '5m', + }, + }); + errorsDistribution = response.body; + }); + it('returns some data', () => { + const hasCurrentPeriodData = errorsDistribution.currentPeriod.some(({ y }) => + isFiniteNumber(y) + ); + + const hasPreviousPeriodData = errorsDistribution.previousPeriod.some(({ y }) => + isFiniteNumber(y) + ); + + expect(hasCurrentPeriodData).to.equal(true); + expect(hasPreviousPeriodData).to.equal(true); + }); + + it('has same start time for both periods', () => { + expect(first(errorsDistribution.currentPeriod)?.x).to.equal( + first(errorsDistribution.previousPeriod)?.x + ); + }); + + it('has same end time for both periods', () => { + expect(last(errorsDistribution.currentPeriod)?.x).to.equal( + last(errorsDistribution.previousPeriod)?.x + ); + }); + + it('returns same number of buckets for both periods', () => { + expect(errorsDistribution.currentPeriod.length).to.equal( + errorsDistribution.previousPeriod.length + ); + }); + }); + + describe('when no data is returned', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + query: { + start: '2021-01-03T00:00:00.000Z', + end: '2021-01-03T00:15:00.000Z', + offset: '1d', + }, + }); + errorsDistribution = response.body; + }); + + it('has same start time for both periods', () => { + expect(first(errorsDistribution.currentPeriod)?.x).to.equal( + first(errorsDistribution.previousPeriod)?.x + ); + }); + + it('has same end time for both periods', () => { + expect(last(errorsDistribution.currentPeriod)?.x).to.equal( + last(errorsDistribution.previousPeriod)?.x + ); + }); + + it('returns same number of buckets for both periods', () => { + expect(errorsDistribution.currentPeriod.length).to.equal( + errorsDistribution.previousPeriod.length + ); + }); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/mobile/crashes/generate_data.ts b/x-pack/test/apm_api_integration/tests/mobile/crashes/generate_data.ts new file mode 100644 index 000000000000..606d97fb9ce0 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/mobile/crashes/generate_data.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; + +export const config = { + appleTransaction: { + name: 'GET /apple 🍎 ', + successRate: 75, + failureRate: 25, + }, + bananaTransaction: { + name: 'GET /banana 🍌', + successRate: 50, + failureRate: 50, + }, +}; + +export async function generateData({ + synthtraceEsClient, + serviceName, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + serviceName: string; + start: number; + end: number; +}) { + const servicesSwiftProdInstance = apm + .service({ name: serviceName, environment: 'production', agentName: 'swift' }) + .instance('instance-a'); + + const interval = '1m'; + + const { bananaTransaction, appleTransaction } = config; + + const documents = [appleTransaction, bananaTransaction].flatMap((transaction, index) => { + return [ + timerange(start, end) + .interval(interval) + .rate(transaction.successRate) + .generator((timestamp) => + servicesSwiftProdInstance + .transaction({ transactionName: transaction.name }) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval(interval) + .rate(transaction.failureRate) + .generator((timestamp) => + servicesSwiftProdInstance + .transaction({ transactionName: transaction.name }) + .errors( + servicesSwiftProdInstance + .crash({ + message: `Error ${index}`, + type: transaction.name, + }) + .timestamp(timestamp) + ) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]; + }); + + await synthtraceEsClient.index(documents); +} diff --git a/x-pack/test/apm_api_integration/tests/mobile/errors/generate_data.ts b/x-pack/test/apm_api_integration/tests/mobile/errors/generate_data.ts new file mode 100644 index 000000000000..663849f274ad --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/mobile/errors/generate_data.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; + +export const config = { + appleTransaction: { + name: 'GET /apple 🍎 ', + successRate: 75, + failureRate: 25, + }, + bananaTransaction: { + name: 'GET /banana 🍌', + successRate: 50, + failureRate: 50, + }, +}; + +export async function generateData({ + synthtraceEsClient, + serviceName, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + serviceName: string; + start: number; + end: number; +}) { + const serviceGoProdInstance = apm + .service({ name: serviceName, environment: 'production', agentName: 'swift' }) + .instance('instance-a'); + + const interval = '1m'; + + const { bananaTransaction, appleTransaction } = config; + + const documents = [appleTransaction, bananaTransaction].flatMap((transaction, index) => { + return [ + timerange(start, end) + .interval(interval) + .rate(transaction.successRate) + .generator((timestamp) => + serviceGoProdInstance + .transaction({ transactionName: transaction.name }) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval(interval) + .rate(transaction.failureRate) + .generator((timestamp) => + serviceGoProdInstance + .transaction({ transactionName: transaction.name }) + .errors( + serviceGoProdInstance + .error({ message: `Error ${index}`, type: transaction.name }) + .timestamp(timestamp) + ) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]; + }); + + await synthtraceEsClient.index(documents); +} diff --git a/x-pack/test/apm_api_integration/tests/mobile/errors/group_id_samples.spec.ts b/x-pack/test/apm_api_integration/tests/mobile/errors/group_id_samples.spec.ts new file mode 100644 index 000000000000..07e4d5f7ca02 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/mobile/errors/group_id_samples.spec.ts @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { timerange } from '@kbn/apm-synthtrace-client'; +import { service } from '@kbn/apm-synthtrace-client/src/lib/apm/service'; +import { orderBy } from 'lodash'; +import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { getErrorGroupingKey } from '@kbn/apm-synthtrace-client/src/lib/apm/instance'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import { config, generateData } from './generate_data'; + +type ErrorGroupSamples = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples'>; + +type ErrorSampleDetails = + APIReturnType<'GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}'>; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + + const serviceName = 'synth-go'; + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + async function callErrorGroupSamplesApi({ groupId }: { groupId: string }) { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services/{serviceName}/errors/{groupId}/samples', + params: { + path: { + serviceName, + groupId, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + environment: 'ENVIRONMENT_ALL', + kuery: '', + }, + }, + }); + return response; + } + + async function callErrorSampleDetailsApi(errorId: string) { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}', + params: { + path: { + serviceName, + groupId: 'foo', + errorId, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + environment: 'ENVIRONMENT_ALL', + kuery: '', + }, + }, + }); + return response; + } + + registry.when('when data is not loaded', { config: 'basic', archives: [] }, () => { + it('handles the empty state', async () => { + const response = await callErrorGroupSamplesApi({ groupId: 'foo' }); + expect(response.status).to.be(200); + expect(response.body.occurrencesCount).to.be(0); + }); + }); + + registry.when('when samples data is loaded', { config: 'basic', archives: [] }, () => { + const { bananaTransaction } = config; + describe('error group id', () => { + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('return correct data', () => { + let errorsSamplesResponse: ErrorGroupSamples; + before(async () => { + const response = await callErrorGroupSamplesApi({ + groupId: '98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + }); + errorsSamplesResponse = response.body; + }); + + it('displays correct number of occurrences', () => { + const numberOfBuckets = 15; + expect(errorsSamplesResponse.occurrencesCount).to.equal( + bananaTransaction.failureRate * numberOfBuckets + ); + }); + }); + }); + }); + + registry.when('when error sample data is loaded', { config: 'basic', archives: [] }, () => { + describe('error sample id', () => { + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('return correct data', () => { + let errorSampleDetailsResponse: ErrorSampleDetails; + before(async () => { + const errorsSamplesResponse = await callErrorGroupSamplesApi({ + groupId: '98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + }); + + const errorId = errorsSamplesResponse.body.errorSampleIds[0]; + + const response = await callErrorSampleDetailsApi(errorId); + errorSampleDetailsResponse = response.body; + }); + + it('displays correct error grouping_key', () => { + expect(errorSampleDetailsResponse.error.error.grouping_key).to.equal( + '98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03' + ); + }); + + it('displays correct error message', () => { + expect(errorSampleDetailsResponse.error.error.exception?.[0].message).to.equal('Error 1'); + }); + }); + }); + + describe('with sampled and unsampled transactions', () => { + let errorGroupSamplesResponse: ErrorGroupSamples; + + before(async () => { + const instance = service(serviceName, 'production', 'go').instance('a'); + const errorMessage = 'Error 1'; + const groupId = getErrorGroupingKey(errorMessage); + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('15m') + .rate(1) + .generator((timestamp) => { + return [ + instance + .transaction('GET /api/foo') + .duration(100) + .timestamp(timestamp) + .sample(false) + .errors( + instance.error({ message: errorMessage }).timestamp(timestamp), + instance.error({ message: errorMessage }).timestamp(timestamp + 1) + ), + instance + .transaction('GET /api/foo') + .duration(100) + .timestamp(timestamp) + .sample(true) + .errors(instance.error({ message: errorMessage }).timestamp(timestamp)), + ]; + }), + ]); + + errorGroupSamplesResponse = (await callErrorGroupSamplesApi({ groupId })).body; + }); + + after(() => synthtraceEsClient.clean()); + + it('returns the errors in the correct order (sampled first, then unsampled)', () => { + const idsOfErrors = errorGroupSamplesResponse.errorSampleIds.map((id) => parseInt(id, 10)); + + // this checks whether the order of indexing is different from the order that is returned + // if it is not, scoring/sorting is broken + expect(errorGroupSamplesResponse.errorSampleIds.length).to.be(3); + expect(idsOfErrors).to.not.eql(orderBy(idsOfErrors)); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts b/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts index c07d6dc6c0f5..b37d68fe936a 100644 --- a/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts @@ -7,6 +7,8 @@ import expect from '@kbn/expect'; import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { ApmDocumentType } from '@kbn/apm-plugin/common/document_type'; +import { RollupInterval } from '@kbn/apm-plugin/common/rollup'; import { FtrProviderContext } from '../../common/ftr_provider_context'; export default function ApiTest({ getService }: FtrProviderContext) { @@ -29,6 +31,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { end: new Date(end).toISOString(), kuery: '', environment: 'production', + documentType: ApmDocumentType.TransactionMetric, + rollupInterval: RollupInterval.OneMinute, }, }, }); diff --git a/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts b/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts index 9648e8982756..3f46aa016811 100644 --- a/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts +++ b/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts @@ -68,13 +68,13 @@ export class FixturePlugin implements Plugin { }); }); + it('filter by multiple status', async () => { + const openCase = await createCase(supertest, postCaseReq); + const toCloseCase = await createCase(supertest, postCaseReq); + const closedCases = await updateCase({ + supertest, + params: { + cases: [ + { + id: toCloseCase.id, + version: toCloseCase.version, + status: CaseStatuses.closed, + }, + ], + }, + }); + + const cases = await findCases({ + supertest, + query: { status: [CaseStatuses.closed, CaseStatuses.open] }, + }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 2, + cases: [openCase, closedCases[0]], + count_open_cases: 1, + count_closed_cases: 1, + }); + }); + it('filters by severity', async () => { await createCase(supertest, postCaseReq); const theCase = await createCase(supertest, postCaseReq); @@ -194,6 +224,26 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('filters by multiple severities', async () => { + const lowSeverityCase = await createCase(supertest, postCaseReq); + const criticalSeverityCase = await createCase(supertest, { + ...postCaseReq, + severity: CaseSeverity.CRITICAL, + }); + + const cases = await findCases({ + supertest, + query: { severity: [CaseSeverity.LOW, CaseSeverity.CRITICAL] }, + }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 2, + cases: [lowSeverityCase, criticalSeverityCase], + count_open_cases: 2, + }); + }); + it('filters by a single category', async () => { await createCase(supertest, postCaseReq); const foobarCategory = await createCase(supertest, { ...postCaseReq, category: 'foobar' }); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/find_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/find_cases.ts index a8bfb21c253c..34a77e1083c4 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/find_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/find_cases.ts @@ -7,7 +7,6 @@ import expect from '@kbn/expect'; import { Cookie } from 'tough-cookie'; -import { User } from '@kbn/cases-plugin/common/types/domain'; import { UserProfile } from '@kbn/security-plugin/common'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -20,7 +19,6 @@ import { loginUsers, } from '../../../../common/lib/api'; import { secOnlySpacesAll, superUser } from '../../../../common/lib/authentication/users'; -import { getUserInfo } from '../../../../common/lib/authentication'; import { createUsersAndRoles, deleteUsersAndRoles } from '../../../../common/lib/authentication'; import { securitySolutionOnlyAllSpacesRole } from '../../../../common/lib/authentication/roles'; @@ -31,7 +29,6 @@ export default ({ getService }: FtrProviderContext): void => { const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('find_cases', () => { - const secOnlyInfo: User = getUserInfo(secOnlySpacesAll); let cookies: Cookie[]; let suggestedSecUsers: UserProfile[]; let superUserHeaders: { Cookie: string }; @@ -62,7 +59,7 @@ export default ({ getService }: FtrProviderContext): void => { suggestedSecUsers = await suggestUserProfiles({ supertest: supertestWithoutAuth, req: { - name: secOnlyInfo.username!, + name: 'all_spaces', owners: ['securitySolutionFixture'], size: 1, }, diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/internal/suggest_user_profiles.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/internal/suggest_user_profiles.ts index db3f529863f0..e8e7023c0693 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/internal/suggest_user_profiles.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/internal/suggest_user_profiles.ts @@ -58,6 +58,30 @@ export default function ({ getService }: FtrProviderContext) { `); }); + it('find a user who only has read privilege for cases', async () => { + const profiles = await suggestUserProfiles({ + supertest: supertestWithoutAuth, + req: { + name: 'read', + owners: ['securitySolutionFixture'], + }, + auth: { user: superUser, space: 'space1' }, + }); + + expectSnapshot(profiles.map(({ user, data }) => ({ user, data }))).toMatchInline(` + Array [ + Object { + "data": Object {}, + "user": Object { + "email": "sec_only_read@elastic.co", + "full_name": "sec only_read", + "username": "sec_only_read", + }, + }, + ] + `); + }); + it('does not find a user who does not have access to the default space', async () => { const profiles = await suggestUserProfiles({ supertest: supertestWithoutAuth, @@ -85,6 +109,14 @@ export default function ({ getService }: FtrProviderContext) { expect(profiles.filter(({ user }) => user.username === obsOnly.username)).to.be.empty(); expectSnapshot(profiles.map(({ user, data }) => ({ user, data }))).toMatchInline(` Array [ + Object { + "data": Object {}, + "user": Object { + "email": "sec_only_read@elastic.co", + "full_name": "sec only_read", + "username": "sec_only_read", + }, + }, Object { "data": Object {}, "user": Object { @@ -105,19 +137,6 @@ export default function ({ getService }: FtrProviderContext) { `); }); - it('does not find a user who does not have update privileges to cases', async () => { - const profiles = await suggestUserProfiles({ - supertest: supertestWithoutAuth, - req: { - name: 'read', - owners: ['securitySolutionFixture'], - }, - auth: { user: superUser, space: 'space1' }, - }); - - expect(profiles).to.be.empty(); - }); - it('fails with a 403 because the user making the request does not have the appropriate api kibana endpoint privileges', async () => { await suggestUserProfiles({ supertest: supertestWithoutAuth, @@ -186,9 +205,9 @@ export default function ({ getService }: FtrProviderContext) { Object { "data": Object {}, "user": Object { - "email": "sec_only_no_delete@elastic.co", - "full_name": "sec only_no_delete", - "username": "sec_only_no_delete", + "email": "sec_only_read@elastic.co", + "full_name": "sec only_read", + "username": "sec_only_read", }, }, ] @@ -242,7 +261,7 @@ export default function ({ getService }: FtrProviderContext) { await deleteUsersAndRoles(getService, users, roles); }); - it('finds 3 profiles when searching for the name sec when a user has both security and observability privileges', async () => { + it('finds 4 profiles when searching for the name sec when a user has both security and observability privileges', async () => { const profiles = await suggestUserProfiles({ supertest: supertestWithoutAuth, req: { @@ -254,6 +273,14 @@ export default function ({ getService }: FtrProviderContext) { expectSnapshot(profiles.map(({ user, data }) => ({ user, data }))).toMatchInline(` Array [ + Object { + "data": Object {}, + "user": Object { + "email": "sec_only_read@elastic.co", + "full_name": "sec only_read", + "username": "sec_only_read", + }, + }, Object { "data": Object {}, "user": Object { diff --git a/x-pack/test/cloud_security_posture_api/config.ts b/x-pack/test/cloud_security_posture_api/config.ts index a206fd563cc0..e7a34bafe9fb 100644 --- a/x-pack/test/cloud_security_posture_api/config.ts +++ b/x-pack/test/cloud_security_posture_api/config.ts @@ -17,6 +17,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('./telemetry/telemetry.ts'), require.resolve('./routes/vulnerabilities_dashboard.ts'), + require.resolve('./routes/stats.ts'), ], junit: { reportName: 'X-Pack Cloud Security Posture API Tests', diff --git a/x-pack/test/cloud_security_posture_api/routes/mocks/benchmark_score_mock.ts b/x-pack/test/cloud_security_posture_api/routes/mocks/benchmark_score_mock.ts new file mode 100644 index 000000000000..f24c960783e5 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/routes/mocks/benchmark_score_mock.ts @@ -0,0 +1,300 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getBenchmarkScoreMockData = (postureType: string) => [ + { + total_findings: 1, + policy_template: postureType, + '@timestamp': '2023-11-22T16:10:55.229268215Z', + score_by_cluster_id: { + 'Another Upper case account id': { + total_findings: 1, + passed_findings: 1, + failed_findings: 0, + }, + 'Upper case cluster id': { + total_findings: 1, + passed_findings: 1, + failed_findings: 0, + }, + }, + score_by_benchmark_id: { + cis_aws: { + v1_5_0: { + total_findings: 1, + passed_findings: 1, + failed_findings: 0, + }, + }, + cis_k8s: { + v1_0_0: { + total_findings: 1, + passed_findings: 1, + failed_findings: 0, + }, + }, + }, + passed_findings: 1, + failed_findings: 0, + }, +]; + +export const cspmComplianceDashboardDataMockV1 = { + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + resourcesEvaluated: 1, + }, + groupedFindingsEvaluation: [ + { + name: 'Another upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + clusters: [ + { + meta: { + clusterId: 'Another Upper case account id', + assetIdentifierId: 'Another Upper case account id', + benchmark: { + name: 'CIS AWS2', + id: 'cis_aws', + posture_type: 'cspm', + version: 'v1.5.0', + }, + cloud: { + account: { + id: 'Another Upper case account id', + }, + }, + }, + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + }, + groupedFindingsEvaluation: [ + { + name: 'Another upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], +}; + +export const cspmComplianceDashboardDataMockV2 = { + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + resourcesEvaluated: 1, + }, + groupedFindingsEvaluation: [ + { + name: 'Another upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + benchmarks: [ + { + meta: { + benchmarkId: 'cis_aws', + benchmarkVersion: 'v1.5.0', + benchmarkName: 'CIS AWS2', + assetCount: 1, + }, + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + }, + groupedFindingsEvaluation: [ + { + name: 'Another upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], +}; + +export const kspmComplianceDashboardDataMockV1 = { + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + resourcesEvaluated: 1, + }, + groupedFindingsEvaluation: [ + { + name: 'Upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + clusters: [ + { + meta: { + clusterId: 'Upper case cluster id', + assetIdentifierId: 'Upper case cluster id', + benchmark: { + name: 'CIS Kubernetes V1.23', + id: 'cis_k8s', + posture_type: 'kspm', + version: 'v1.0.0', + }, + cluster: { + id: 'Upper case cluster id', + }, + }, + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + }, + groupedFindingsEvaluation: [ + { + name: 'Upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], +}; + +export const kspmComplianceDashboardDataMockV2 = { + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + resourcesEvaluated: 1, + }, + groupedFindingsEvaluation: [ + { + name: 'Upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + benchmarks: [ + { + meta: { + benchmarkId: 'cis_k8s', + benchmarkVersion: 'v1.0.0', + benchmarkName: 'CIS Kubernetes V1.23', + assetCount: 1, + }, + stats: { + totalFailed: 0, + totalPassed: 1, + totalFindings: 1, + postureScore: 100, + }, + groupedFindingsEvaluation: [ + { + name: 'Upper case section', + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], + }, + ], + trend: [ + { + totalFindings: 1, + totalFailed: 0, + totalPassed: 1, + postureScore: 100, + }, + ], +}; diff --git a/x-pack/test/cloud_security_posture_api/routes/mocks/findings_mock.ts b/x-pack/test/cloud_security_posture_api/routes/mocks/findings_mock.ts new file mode 100644 index 000000000000..92ca03b1e478 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/routes/mocks/findings_mock.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import Chance from 'chance'; + +const chance = new Chance(); + +export const findingsMockData = [ + { + '@timestamp': '2023-06-29T02:08:44.993Z', + resource: { + id: chance.guid(), + name: `kubelet`, + sub_type: 'lower case sub type', + type: 'k8s_resource_type', + }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + name: 'Upper case rule name', + section: 'Upper case section', + benchmark: { + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + }, + }, + orchestrator: { + cluster: { id: 'Upper case cluster id' }, + }, + }, + { + '@timestamp': '2023-06-29T02:08:44.993Z', + resource: { + id: chance.guid(), + name: `Pod`, + sub_type: 'Upper case sub type', + type: 'cloud_resource_type', + }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + name: 'lower case rule name', + section: 'Another upper case section', + benchmark: { + id: 'cis_aws', + posture_type: 'cspm', + name: 'CIS AWS2', + version: 'v1.5.0', + }, + }, + cloud: { + account: { id: 'Another Upper case account id' }, + }, + }, +]; diff --git a/x-pack/test/cloud_security_posture_api/routes/stats.ts b/x-pack/test/cloud_security_posture_api/routes/stats.ts new file mode 100644 index 000000000000..92dac0d6b027 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/routes/stats.ts @@ -0,0 +1,229 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { + BENCHMARK_SCORE_INDEX_DEFAULT_NS, + LATEST_FINDINGS_INDEX_DEFAULT_NS, +} from '@kbn/cloud-security-posture-plugin/common/constants'; +import { + BenchmarkData, + Cluster, + ComplianceDashboardData, + ComplianceDashboardDataV2, + PostureTrend, +} from '@kbn/cloud-security-posture-plugin/common/types'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; +import { + getBenchmarkScoreMockData, + kspmComplianceDashboardDataMockV1, + kspmComplianceDashboardDataMockV2, + cspmComplianceDashboardDataMockV1, + cspmComplianceDashboardDataMockV2, +} from './mocks/benchmark_score_mock'; +import { findingsMockData } from './mocks/findings_mock'; + +const removeRealtimeCalculatedFields = (trends: PostureTrend[]) => { + return trends.map((trend: PostureTrend) => { + const { timestamp, ...rest } = trend; + return rest; + }); +}; + +const removeRealtimeClusterFields = (clusters: Cluster[]) => + clusters.flatMap((cluster) => { + const clusterWithoutTrend = { + ...cluster, + trend: removeRealtimeCalculatedFields(cluster.trend), + }; + const { lastUpdate, ...clusterWithoutTime } = clusterWithoutTrend.meta; + + return { ...clusterWithoutTrend, meta: clusterWithoutTime }; + }); + +const removeRealtimeBenchmarkFields = (benchmarks: BenchmarkData[]) => + benchmarks.flatMap((benchmark) => ({ + ...benchmark, + trend: removeRealtimeCalculatedFields(benchmark.trend), + })); + +// eslint-disable-next-line import/no-default-export +export default function (providerContext: FtrProviderContext) { + const { getService } = providerContext; + + const kibanaHttpClient = getService('supertest'); + + const retry = getService('retry'); + const es = getService('es'); + const supertest = getService('supertest'); + const log = getService('log'); + + /** + * required before indexing findings + */ + const waitForPluginInitialized = (): Promise => + retry.try(async () => { + log.debug('Check CSP plugin is initialized'); + const response = await supertest + .get('/internal/cloud_security_posture/status?check=init') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .expect(200); + expect(response.body).to.eql({ isPluginInitialized: true }); + log.debug('CSP plugin is initialized'); + }); + + const index = { + addFindings: async (findingsMock: T[]) => { + await Promise.all( + findingsMock.map((findingsDoc) => + es.index({ + index: LATEST_FINDINGS_INDEX_DEFAULT_NS, + body: { ...findingsDoc, '@timestamp': new Date().toISOString() }, + refresh: true, + }) + ) + ); + }, + + addScores: async (scoresMock: T[]) => { + await Promise.all( + scoresMock.map((scoreDoc) => + es.index({ + index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, + body: { ...scoreDoc, '@timestamp': new Date().toISOString() }, + refresh: true, + }) + ) + ); + }, + + removeFindings: async () => { + const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); + + if (indexExists) { + es.deleteByQuery({ + index: LATEST_FINDINGS_INDEX_DEFAULT_NS, + query: { match_all: {} }, + refresh: true, + }); + } + }, + + removeScores: async () => { + const indexExists = await es.indices.exists({ index: BENCHMARK_SCORE_INDEX_DEFAULT_NS }); + + if (indexExists) { + es.deleteByQuery({ + index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, + query: { match_all: {} }, + refresh: true, + }); + } + }, + + deleteFindingsIndex: async () => { + const indexExists = await es.indices.exists({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); + + if (indexExists) { + await es.indices.delete({ index: LATEST_FINDINGS_INDEX_DEFAULT_NS }); + } + }, + }; + + describe('GET /internal/cloud_security_posture/stats', () => { + describe('CSPM Compliance Dashboard Stats API', async () => { + beforeEach(async () => { + await index.removeFindings(); + await index.removeScores(); + + await waitForPluginInitialized(); + await index.addScores(getBenchmarkScoreMockData('cspm')); + await index.addFindings([findingsMockData[1]]); + }); + + it('should return CSPM cluster V1 ', async () => { + const { body: res }: { body: ComplianceDashboardData } = await kibanaHttpClient + .get(`/internal/cloud_security_posture/stats/cspm`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set('kbn-xsrf', 'xxxx') + .expect(200); + const resClusters = removeRealtimeClusterFields(res.clusters); + const trends = removeRealtimeCalculatedFields(res.trend); + + expect({ + ...res, + clusters: resClusters, + trend: trends, + }).to.eql(cspmComplianceDashboardDataMockV1); + }); + + it('should return CSPM benchmarks V2 ', async () => { + const { body: res }: { body: ComplianceDashboardDataV2 } = await kibanaHttpClient + .get(`/internal/cloud_security_posture/stats/cspm`) + .set(ELASTIC_HTTP_VERSION_HEADER, '2') + .set('kbn-xsrf', 'xxxx') + .expect(200); + + const resBenchmarks = removeRealtimeBenchmarkFields(res.benchmarks); + + const trends = removeRealtimeCalculatedFields(res.trend); + + expect({ + ...res, + benchmarks: resBenchmarks, + trend: trends, + }).to.eql(cspmComplianceDashboardDataMockV2); + }); + }); + + describe('KSPM Compliance Dashboard Stats API', async () => { + beforeEach(async () => { + await index.removeFindings(); + await index.removeScores(); + + await waitForPluginInitialized(); + await index.addScores(getBenchmarkScoreMockData('kspm')); + await index.addFindings([findingsMockData[0]]); + }); + + it('should return KSPM clusters V1 ', async () => { + const { body: res }: { body: ComplianceDashboardData } = await kibanaHttpClient + .get(`/internal/cloud_security_posture/stats/kspm`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set('kbn-xsrf', 'xxxx') + .expect(200); + + const resClusters = removeRealtimeClusterFields(res.clusters); + const trends = removeRealtimeCalculatedFields(res.trend); + + expect({ + ...res, + clusters: resClusters, + trend: trends, + }).to.eql(kspmComplianceDashboardDataMockV1); + }); + + it('should return KSPM benchmarks V2 ', async () => { + const { body: res }: { body: ComplianceDashboardDataV2 } = await kibanaHttpClient + .get(`/internal/cloud_security_posture/stats/kspm`) + .set(ELASTIC_HTTP_VERSION_HEADER, '2') + .set('kbn-xsrf', 'xxxx') + .expect(200); + + const resBenchmarks = removeRealtimeBenchmarkFields(res.benchmarks); + + const trends = removeRealtimeCalculatedFields(res.trend); + + expect({ + ...res, + benchmarks: resBenchmarks, + trend: trends, + }).to.eql(kspmComplianceDashboardDataMockV2); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/mocks/vulnerabilities_latest_mock.ts b/x-pack/test/cloud_security_posture_functional/mocks/vulnerabilities_latest_mock.ts index 813c72743e7f..f0ffd4aebb38 100644 --- a/x-pack/test/cloud_security_posture_functional/mocks/vulnerabilities_latest_mock.ts +++ b/x-pack/test/cloud_security_posture_functional/mocks/vulnerabilities_latest_mock.ts @@ -83,7 +83,7 @@ export const vulnerabilitiesLatestMock = [ id: '704479110758', }, }, - '@timestamp': '2023-06-29T02:08:44.993Z', + '@timestamp': (Date.now() - 249200000).toString(), cloudbeat: { commit_sha: '4d990caa0c9c1594441da6bf24a685599aeb2bd5', commit_time: '2023-05-15T14:48:10Z', @@ -189,7 +189,7 @@ export const vulnerabilitiesLatestMock = [ id: '704479110758', }, }, - '@timestamp': '2023-06-29T02:08:16.535Z', + '@timestamp': (Date.now() - 249200000).toString(), ecs: { version: '8.6.0', }, diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts index 49f4ab0a6d12..c711c2300e1b 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts @@ -410,6 +410,50 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider }, }); + const groupSelector = (testSubj = 'group-selector-dropdown') => ({ + async getElement() { + return await testSubjects.find(testSubj); + }, + async setValue(value: string) { + const contextMenu = await testSubjects.find('groupByContextMenu'); + const menuItems = await contextMenu.findAllByCssSelector('button.euiContextMenuItem'); + const menuItemsOptions = await Promise.all(menuItems.map((item) => item.getVisibleText())); + const menuItemValueIndex = menuItemsOptions.findIndex((item) => item === value); + await menuItems[menuItemValueIndex].click(); + return await testSubjects.missingOrFail('is-loading-grouping-table', { timeout: 5000 }); + }, + async openDropDown() { + const element = await this.getElement(); + await element.click(); + }, + }); + + const findingsGrouping = async (testSubj = 'cloudSecurityGrouping') => ({ + async getElement() { + return await testSubjects.find(testSubj); + }, + async getGroupCount() { + const element = await this.getElement(); + const groupCount = await element.findByTestSubject('group-count'); + return await groupCount.getVisibleText(); + }, + async getUnitCount() { + const element = await this.getElement(); + const unitCount = await element.findByTestSubject('unit-count'); + return await unitCount.getVisibleText(); + }, + async getRowAtIndex(rowIndex: number) { + const element = await this.getElement(); + const row = await element.findAllByTestSubject('grouping-accordion'); + return await row[rowIndex]; + }, + }); + const isLatestFindingsTableThere = async () => { + const table = await testSubjects.findAll('docTable'); + const trueOrFalse = table.length > 0 ? true : false; + return trueOrFalse; + }; + return { navigateToLatestFindingsPage, navigateToVulnerabilities, @@ -426,5 +470,9 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider misconfigurationsFlyout, toastMessage, detectionRuleApi, + groupSelector, + findingsGrouping, + createDataTableObject, + isLatestFindingsTableThere, }; } diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings.ts b/x-pack/test/cloud_security_posture_functional/pages/findings.ts index 69c1fd6949f5..bf45dddebc0b 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings.ts @@ -13,16 +13,16 @@ import type { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const queryBar = getService('queryBar'); const filterBar = getService('filterBar'); - const comboBox = getService('comboBox'); const retry = getService('retry'); const pageObjects = getPageObjects(['common', 'findings', 'header']); const chance = new Chance(); + const timeFiveHoursAgo = (Date.now() - 18000000).toString(); // We need to use a dataset for the tests to run // We intentionally make some fields start with a capital letter to test that the query bar is case-insensitive/case-sensitive const data = [ { - '@timestamp': '1695819664234', + '@timestamp': timeFiveHoursAgo, resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -39,7 +39,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Upper case cluster id', }, { - '@timestamp': '1695819673242', + '@timestamp': timeFiveHoursAgo, resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -56,7 +56,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Another Upper case cluster id', }, { - '@timestamp': '1695819676242', + '@timestamp': timeFiveHoursAgo, resource: { id: chance.guid(), name: `process`, sub_type: 'another lower case type' }, result: { evaluation: 'passed' }, rule: { @@ -73,7 +73,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'lower case cluster id', }, { - '@timestamp': '1695819680202', + '@timestamp': timeFiveHoursAgo, resource: { id: chance.guid(), name: `process`, sub_type: 'Upper case type again' }, result: { evaluation: 'failed' }, rule: { @@ -94,24 +94,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const ruleName1 = data[0].rule.name; const ruleName2 = data[1].rule.name; - const resourceId1 = data[0].resource.id; - const ruleSection1 = data[0].rule.section; - - const benchMarkName = data[0].rule.benchmark.name; - describe('Findings Page', function () { this.tags(['cloud_security_posture_findings']); let findings: typeof pageObjects.findings; let latestFindingsTable: typeof findings.latestFindingsTable; - let findingsByResourceTable: typeof findings.findingsByResourceTable; - let resourceFindingsTable: typeof findings.resourceFindingsTable; let distributionBar: typeof findings.distributionBar; before(async () => { findings = pageObjects.findings; latestFindingsTable = findings.latestFindingsTable; - findingsByResourceTable = findings.findingsByResourceTable; - resourceFindingsTable = findings.resourceFindingsTable; distributionBar = findings.distributionBar; // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization @@ -122,7 +113,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await findings.index.add(data); await findings.navigateToLatestFindingsPage(); - await retry.waitFor( 'Findings table to be loaded', async () => (await latestFindingsTable.getRowsCount()) === data.length @@ -219,19 +209,5 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); }); - - describe('GroupBy', () => { - it('groups findings by resource', async () => { - await comboBox.set('findings_group_by_selector', 'Resource'); - expect( - await findingsByResourceTable.hasColumnValue('Applicable Benchmark', benchMarkName) - ).to.be(true); - }); - - it('navigates to resource findings page from resource id link', async () => { - await findingsByResourceTable.clickResourceIdLink(resourceId1, ruleSection1); - expect(await resourceFindingsTable.hasColumnValue('Rule Name', ruleName1)).to.be(true); - }); - }); }); } diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts index f346fc3d5c28..9b60c77c3ec1 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_alerts.ts @@ -19,6 +19,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // We need to use a dataset for the tests to run const data = [ { + '@timestamp': new Date().toISOString(), resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -40,7 +41,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Upper case cluster id', }, { - '@timestamp': '2023-09-10T14:01:00.000Z', + '@timestamp': new Date(Date.now() - 60 * 60 * 1000).toISOString(), resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -62,7 +63,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Another Upper case cluster id', }, { - '@timestamp': '2023-09-10T14:02:00.000Z', + '@timestamp': new Date(Date.now() - 60 * 60 * 1000).toISOString(), resource: { id: chance.guid(), name: `process`, sub_type: 'another lower case type' }, result: { evaluation: 'passed' }, rule: { @@ -84,7 +85,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'lower case cluster id', }, { - '@timestamp': '2023-09-10T14:03:00.000Z', + '@timestamp': new Date(Date.now() - 60 * 60 * 1000).toISOString(), resource: { id: chance.guid(), name: `process`, sub_type: 'Upper case type again' }, result: { evaluation: 'failed' }, rule: { diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts new file mode 100644 index 000000000000..2939f3eed926 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts @@ -0,0 +1,438 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import Chance from 'chance'; +import { asyncForEach } from '@kbn/std'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const queryBar = getService('queryBar'); + const filterBar = getService('filterBar'); + const pageObjects = getPageObjects(['common', 'findings', 'header']); + const chance = new Chance(); + + const cspmResourceId = chance.guid(); + const cspmResourceName = 'gcp-resource'; + const cspmResourceSubType = 'gcp-monitoring'; + + // We need to use a dataset for the tests to run + // We intentionally make some fields start with a capital letter to test that the query bar is case-insensitive/case-sensitive + const data = [ + { + '@timestamp': new Date().toISOString(), + resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, + result: { evaluation: 'failed' }, + orchestrator: { + cluster: { + id: '1', + name: 'Cluster 1', + }, + }, + rule: { + name: 'Upper case rule name', + section: 'Upper case section', + benchmark: { + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + }, + type: 'process', + }, + }, + { + '@timestamp': new Date().toISOString(), + resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, + result: { evaluation: 'passed' }, + orchestrator: { + cluster: { + id: '1', + name: 'Cluster 2', + }, + }, + rule: { + name: 'lower case rule name', + section: 'Another upper case section', + benchmark: { + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + }, + type: 'process', + }, + }, + { + '@timestamp': new Date().toISOString(), + resource: { id: cspmResourceId, name: cspmResourceName, sub_type: cspmResourceSubType }, + result: { evaluation: 'passed' }, + cloud: { + account: { + id: '1', + name: 'Account 1', + }, + }, + rule: { + name: 'Another upper case rule name', + section: 'lower case section', + benchmark: { + id: 'cis_gcp', + posture_type: 'cspm', + name: 'CIS Google Cloud Platform Foundation', + version: 'v2.0.0', + }, + type: 'process', + }, + }, + { + '@timestamp': new Date().toISOString(), + resource: { id: cspmResourceId, name: cspmResourceName, sub_type: cspmResourceSubType }, + result: { evaluation: 'failed' }, + cloud: { + account: { + id: '2', + name: 'Account 2', + }, + }, + rule: { + name: 'some lower case rule name', + section: 'another lower case section', + benchmark: { + id: 'cis_gcp', + posture_type: 'cspm', + name: 'CIS Google Cloud Platform Foundation', + version: 'v2.0.0', + }, + type: 'process', + }, + }, + ]; + + const ruleName1 = data[0].rule.name; + + describe('Findings Page - Grouping', function () { + this.tags(['cloud_security_posture_findings_grouping']); + let findings: typeof pageObjects.findings; + // let groupSelector: ReturnType; + + before(async () => { + findings = pageObjects.findings; + + // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization + await findings.waitForPluginInitialized(); + + // Prepare mocked findings + await findings.index.remove(); + await findings.index.add(data); + + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.openDropDown(); + await groupSelector.setValue('None'); + await findings.index.remove(); + }); + + describe('Default Grouping', async () => { + it('groups findings by resource and sort by compliance score desc', async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.openDropDown(); + await groupSelector.setValue('Resource'); + + const grouping = await findings.findingsGrouping(); + + const resourceOrder = [ + { + resourceName: 'kubelet', + resourceId: data[0].resource.id, + resourceSubType: data[0].resource.sub_type, + findingsCount: '1', + complianceScore: '0%', + }, + { + resourceName: cspmResourceName, + resourceId: cspmResourceId, + resourceSubType: cspmResourceSubType, + findingsCount: '2', + complianceScore: '50%', + }, + { + resourceName: 'Pod', + resourceId: data[1].resource.id, + resourceSubType: data[1].resource.sub_type, + findingsCount: '1', + complianceScore: '100%', + }, + ]; + + await asyncForEach( + resourceOrder, + async ( + { resourceName, resourceId, resourceSubType, findingsCount, complianceScore }, + index + ) => { + const groupRow = await grouping.getRowAtIndex(index); + expect(await groupRow.getVisibleText()).to.contain(resourceName); + expect(await groupRow.getVisibleText()).to.contain(resourceId); + expect(await groupRow.getVisibleText()).to.contain(resourceSubType); + expect( + await ( + await groupRow.findByTestSubject('cloudSecurityFindingsComplianceScore') + ).getVisibleText() + ).to.be(complianceScore); + expect( + await (await groupRow.findByTestSubject('findings_grouping_counter')).getVisibleText() + ).to.be(findingsCount); + } + ); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('3 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('4 findings'); + }); + it('groups findings by rule name and sort by compliance score desc', async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.openDropDown(); + await groupSelector.setValue('Rule name'); + + const grouping = await findings.findingsGrouping(); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('4 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('4 findings'); + + const ruleNameOrder = [ + { + ruleName: 'Upper case rule name', + findingsCount: '1', + complianceScore: '0%', + benchmarkName: data[0].rule.benchmark.name, + }, + { + ruleName: 'some lower case rule name', + findingsCount: '1', + complianceScore: '0%', + benchmarkName: data[3].rule.benchmark.name, + }, + { + ruleName: 'Another upper case rule name', + findingsCount: '1', + complianceScore: '100%', + benchmarkName: data[2].rule.benchmark.name, + }, + { + ruleName: 'lower case rule name', + findingsCount: '1', + complianceScore: '100%', + benchmarkName: data[1].rule.benchmark.name, + }, + ]; + + await asyncForEach( + ruleNameOrder, + async ({ ruleName, benchmarkName, findingsCount, complianceScore }, index) => { + const groupRow = await grouping.getRowAtIndex(index); + expect(await groupRow.getVisibleText()).to.contain(ruleName); + expect(await groupRow.getVisibleText()).to.contain(benchmarkName); + expect( + await ( + await groupRow.findByTestSubject('cloudSecurityFindingsComplianceScore') + ).getVisibleText() + ).to.be(complianceScore); + expect( + await (await groupRow.findByTestSubject('findings_grouping_counter')).getVisibleText() + ).to.be(findingsCount); + } + ); + }); + it('groups findings by cloud account and sort by compliance score desc', async () => { + const groupSelector = await findings.groupSelector(); + + await groupSelector.setValue('Cloud account'); + + const grouping = await findings.findingsGrouping(); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('3 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('4 findings'); + + const cloudNameOrder = [ + { + cloudName: 'Account 2', + findingsCount: '1', + complianceScore: '0%', + benchmarkName: data[3].rule.benchmark.name, + }, + { + cloudName: 'Account 1', + findingsCount: '1', + complianceScore: '100%', + benchmarkName: data[2].rule.benchmark.name, + }, + { + cloudName: 'No cloud account', + findingsCount: '2', + complianceScore: '50%', + benchmarkName: data[0].rule.benchmark.name, + }, + ]; + + await asyncForEach( + cloudNameOrder, + async ({ cloudName, complianceScore, findingsCount, benchmarkName }, index) => { + const groupRow = await grouping.getRowAtIndex(index); + expect(await groupRow.getVisibleText()).to.contain(cloudName); + + if (cloudName !== 'No cloud account') { + expect(await groupRow.getVisibleText()).to.contain(benchmarkName); + } + + expect( + await ( + await groupRow.findByTestSubject('cloudSecurityFindingsComplianceScore') + ).getVisibleText() + ).to.be(complianceScore); + expect( + await (await groupRow.findByTestSubject('findings_grouping_counter')).getVisibleText() + ).to.be(findingsCount); + } + ); + }); + it('groups findings by Kubernetes cluster and sort by compliance score desc', async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.setValue('Kubernetes cluster'); + + const grouping = await findings.findingsGrouping(); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('3 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('4 findings'); + + const kubernetesOrder = [ + { + clusterName: 'Cluster 1', + findingsCount: '1', + complianceScore: '0%', + benchmarkName: data[0].rule.benchmark.name, + }, + { + clusterName: 'Cluster 2', + findingsCount: '1', + complianceScore: '100%', + benchmarkName: data[1].rule.benchmark.name, + }, + { + clusterName: 'No Kubernetes cluster', + findingsCount: '2', + complianceScore: '50%', + }, + ]; + + await asyncForEach( + kubernetesOrder, + async ({ clusterName, complianceScore, findingsCount, benchmarkName }, index) => { + const groupRow = await grouping.getRowAtIndex(index); + expect(await groupRow.getVisibleText()).to.contain(clusterName); + if (clusterName !== 'No Kubernetes cluster') { + expect(await groupRow.getVisibleText()).to.contain(benchmarkName); + } + expect( + await ( + await groupRow.findByTestSubject('cloudSecurityFindingsComplianceScore') + ).getVisibleText() + ).to.be(complianceScore); + expect( + await (await groupRow.findByTestSubject('findings_grouping_counter')).getVisibleText() + ).to.be(findingsCount); + } + ); + }); + }); + describe('SearchBar', () => { + it('add filter', async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.setValue('Resource'); + + // Filter bar uses the field's customLabel in the DataView + await filterBar.addFilter({ field: 'Rule Name', operation: 'is', value: ruleName1 }); + expect(await filterBar.hasFilter('rule.name', ruleName1)).to.be(true); + + const grouping = await findings.findingsGrouping(); + + const groupRow = await grouping.getRowAtIndex(0); + expect(await groupRow.getVisibleText()).to.contain(data[0].resource.name); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('1 group'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('1 finding'); + }); + + it('remove filter', async () => { + await filterBar.removeFilter('rule.name'); + + expect(await filterBar.hasFilter('rule.name', ruleName1)).to.be(false); + + const grouping = await findings.findingsGrouping(); + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('3 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('4 findings'); + }); + + it('set search query', async () => { + await queryBar.setQuery(ruleName1); + await queryBar.submitQuery(); + + const grouping = await findings.findingsGrouping(); + + const groupRow = await grouping.getRowAtIndex(0); + expect(await groupRow.getVisibleText()).to.contain(data[0].resource.name); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('1 group'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('1 finding'); + + await queryBar.setQuery(''); + await queryBar.submitQuery(); + + expect(await grouping.getGroupCount()).to.be('3 groups'); + expect(await grouping.getUnitCount()).to.be('4 findings'); + }); + }); + + describe('Group table', async () => { + it('shows findings table when expanding', async () => { + const grouping = await findings.findingsGrouping(); + const firstRow = await grouping.getRowAtIndex(0); + await (await firstRow.findByCssSelector('button')).click(); + const latestFindingsTable = findings.createDataTableObject('latest_findings_table'); + expect(await latestFindingsTable.getRowsCount()).to.be(1); + expect(await latestFindingsTable.hasColumnValue('rule.name', data[0].rule.name)).to.be( + true + ); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts new file mode 100644 index 000000000000..9586387c028e --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_old_data.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import Chance from 'chance'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['common', 'findings', 'header']); + const chance = new Chance(); + const hoursToMillisecond = (hours: number) => hours * 60 * 60 * 1000; + + const dataOldKspm = [ + { + '@timestamp': (Date.now() - hoursToMillisecond(27)).toString(), + resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + name: 'Upper case rule name', + section: 'Upper case section', + benchmark: { + id: 'cis_k8s', + posture_type: 'kspm', + name: 'CIS Kubernetes V1.23', + version: 'v1.0.0', + }, + type: 'process', + }, + cluster_id: 'Upper case cluster id', + }, + ]; + + const dataOldCspm = [ + { + '@timestamp': (Date.now() - hoursToMillisecond(27)).toString(), + resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, + result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, + rule: { + name: 'Upper case rule name', + section: 'Upper case section', + benchmark: { + id: 'cis_aws', + posture_type: 'cspm', + name: 'CIS AWS V1.23', + version: 'v1.0.0', + }, + type: 'process', + }, + cluster_id: 'Upper case cluster id', + }, + ]; + + describe('Old Data', function () { + this.tags(['cloud_security_posture_findings']); + let findings: typeof pageObjects.findings; + + before(async () => { + findings = pageObjects.findings; + + // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization + await findings.waitForPluginInitialized(); + }); + + after(async () => { + await findings.index.remove(); + }); + + describe('Findings page with old data', () => { + it('returns no Findings KSPM', async () => { + // Prepare mocked findings + await findings.index.remove(); + await findings.index.add(dataOldKspm); + + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + expect(await findings.isLatestFindingsTableThere()).to.be(false); + }); + it('returns no Findings CSPM', async () => { + // Prepare mocked findings + await findings.index.remove(); + await findings.index.add(dataOldCspm); + + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + expect(await findings.isLatestFindingsTableThere()).to.be(false); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/index.ts b/x-pack/test/cloud_security_posture_functional/pages/index.ts index 9d4e17ec0c88..9da8cbbeeed5 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/index.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/index.ts @@ -12,9 +12,11 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Cloud Security Posture', function () { loadTestFile(require.resolve('./findings_onboarding')); loadTestFile(require.resolve('./findings')); + loadTestFile(require.resolve('./findings_grouping')); loadTestFile(require.resolve('./findings_alerts')); loadTestFile(require.resolve('./compliance_dashboard')); loadTestFile(require.resolve('./vulnerability_dashboard')); loadTestFile(require.resolve('./cis_integration')); + loadTestFile(require.resolve('./findings_old_data')); }); } diff --git a/x-pack/test/dataset_quality_api_integration/basic/config.ts b/x-pack/test/dataset_quality_api_integration/basic/config.ts new file mode 100644 index 000000000000..614f052c9c77 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/basic/config.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { configs } from '../configs'; + +// eslint-disable-next-line import/no-default-export +export default configs.basic; diff --git a/x-pack/test/dataset_quality_api_integration/common/config.ts b/x-pack/test/dataset_quality_api_integration/common/config.ts new file mode 100644 index 000000000000..e10ad4273fe7 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/common/config.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + DatasetQualityUsername, + DATASET_QUALITY_TEST_PASSWORD, +} from '@kbn/dataset-quality-plugin/server/test_helpers/create_dataset_quality_users/authentication'; +import { createDatasetQualityUsers } from '@kbn/dataset-quality-plugin/server/test_helpers/create_dataset_quality_users'; +import { FtrConfigProviderContext } from '@kbn/test'; +import supertest from 'supertest'; +import { format, UrlObject } from 'url'; +import { createLogger, LogLevel, LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import { + FtrProviderContext, + InheritedFtrProviderContext, + InheritedServices, +} from './ftr_provider_context'; +import { createDatasetQualityApiClient } from './dataset_quality_api_supertest'; +import { RegistryProvider } from './registry'; +import { DatasetQualityFtrConfigName } from '../configs'; + +export interface DatasetQualityFtrConfig { + name: DatasetQualityFtrConfigName; + license: 'basic'; + kibanaConfig?: Record; +} + +async function getDatasetQualityApiClient({ + kibanaServer, + username, +}: { + kibanaServer: UrlObject; + username: DatasetQualityUsername | 'elastic'; +}) { + const url = format({ + ...kibanaServer, + auth: `${username}:${DATASET_QUALITY_TEST_PASSWORD}`, + }); + + return createDatasetQualityApiClient(supertest(url)); +} + +export type CreateTestConfig = ReturnType; + +export type DatasetQualityApiClientKey = + | 'noAccessUser' + | 'readUser' + | 'adminUser' + | 'writeUser' + | 'datasetQualityLogsUser'; + +export type DatasetQualityApiClient = Record< + DatasetQualityApiClientKey, + Awaited> +>; + +export interface CreateTest { + testFiles: string[]; + servers: any; + servicesRequiredForTestAnalysis: string[]; + services: InheritedServices & { + datasetQualityFtrConfig: () => DatasetQualityFtrConfig; + registry: ({ getService }: FtrProviderContext) => ReturnType; + logSynthtraceEsClient: ( + context: InheritedFtrProviderContext + ) => Promise; + datasetQualityApiClient: (context: InheritedFtrProviderContext) => DatasetQualityApiClient; + }; + junit: { reportName: string }; + esTestCluster: any; + kbnTestServer: any; +} + +export function createTestConfig( + config: DatasetQualityFtrConfig +): ({ readConfigFile }: FtrConfigProviderContext) => Promise { + const { license, name, kibanaConfig } = config; + + return async ({ readConfigFile }: FtrConfigProviderContext) => { + const xPackAPITestsConfig = await readConfigFile( + require.resolve('../../api_integration/config.ts') + ); + + const services = xPackAPITestsConfig.get('services'); + const servers = xPackAPITestsConfig.get('servers'); + const kibanaServer = servers.kibana as UrlObject; + const kibanaServerUrl = format(kibanaServer); + const esServer = servers.elasticsearch as UrlObject; + + return { + testFiles: [require.resolve('../tests')], + servers, + servicesRequiredForTestAnalysis: ['datasetQualityFtrConfig', 'registry'], + services: { + ...services, + datasetQualityFtrConfig: () => config, + registry: RegistryProvider, + logSynthtraceEsClient: (context: InheritedFtrProviderContext) => + new LogsSynthtraceEsClient({ + client: context.getService('es'), + logger: createLogger(LogLevel.info), + refreshAfterIndex: true, + }), + datasetQualityApiClient: async (_: InheritedFtrProviderContext) => { + const { username, password } = servers.kibana; + const esUrl = format(esServer); + + // Creates DatasetQuality users + await createDatasetQualityUsers({ + elasticsearch: { node: esUrl, username, password }, + kibana: { hostname: kibanaServerUrl }, + }); + + return { + noAccessUser: await getDatasetQualityApiClient({ + kibanaServer, + username: DatasetQualityUsername.noAccessUser, + }), + readUser: await getDatasetQualityApiClient({ + kibanaServer, + username: DatasetQualityUsername.viewerUser, + }), + adminUser: await getDatasetQualityApiClient({ + kibanaServer, + username: 'elastic', + }), + writeUser: await getDatasetQualityApiClient({ + kibanaServer, + username: DatasetQualityUsername.editorUser, + }), + datasetQualityLogsUser: await getDatasetQualityApiClient({ + kibanaServer, + username: DatasetQualityUsername.datasetQualityLogsUser, + }), + }; + }, + }, + junit: { + reportName: `Dataset quality API Integration tests (${name})`, + }, + esTestCluster: { + ...xPackAPITestsConfig.get('esTestCluster'), + license, + }, + kbnTestServer: { + ...xPackAPITestsConfig.get('kbnTestServer'), + serverArgs: [ + ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), + ...(kibanaConfig + ? Object.entries(kibanaConfig).map(([key, value]) => + Array.isArray(value) ? `--${key}=${JSON.stringify(value)}` : `--${key}=${value}` + ) + : []), + ], + }, + }; + }; +} + +export type DatasetQualityServices = Awaited>['services']; diff --git a/x-pack/test/dataset_quality_api_integration/common/dataset_quality_api_supertest.ts b/x-pack/test/dataset_quality_api_integration/common/dataset_quality_api_supertest.ts new file mode 100644 index 000000000000..79818e970a2a --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/common/dataset_quality_api_supertest.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { format } from 'url'; +import supertest from 'supertest'; +import request from 'superagent'; +import type { APIEndpoint } from '@kbn/dataset-quality-plugin/server/routes'; +import { formatRequest } from '@kbn/server-route-repository'; +import type { APIClientRequestParamsOf, APIReturnType } from '@kbn/dataset-quality-plugin/common'; + +export function createDatasetQualityApiClient(st: supertest.SuperTest) { + return async ( + options: { + type?: 'form-data'; + endpoint: TEndpoint; + } & APIClientRequestParamsOf & { params?: { query?: { _inspect?: boolean } } } + ): Promise> => { + const { endpoint, type } = options; + + const params = 'params' in options ? (options.params as Record) : {}; + + const { method, pathname, version } = formatRequest(endpoint, params.path); + const url = format({ pathname, query: params?.query }); + + const headers: Record = { 'kbn-xsrf': 'foo' }; + + if (version) { + headers['Elastic-Api-Version'] = version; + } + + let res: request.Response; + if (type === 'form-data') { + const fields: Array<[string, any]> = Object.entries(params.body); + const formDataRequest = st[method](url) + .set(headers) + .set('Content-type', 'multipart/form-data'); + + for (const field of fields) { + formDataRequest.field(field[0], field[1]); + } + + res = await formDataRequest; + } else if (params.body) { + res = await st[method](url).send(params.body).set(headers); + } else { + res = await st[method](url).set(headers); + } + + // supertest doesn't throw on http errors + if (res?.status !== 200) { + throw new DatasetQualityApiError(res, endpoint); + } + + return res; + }; +} + +type ApiErrorResponse = Omit & { + body: { + statusCode: number; + error: string; + message: string; + attributes: object; + }; +}; + +export type DatasetQualityApiSupertest = ReturnType; + +export class DatasetQualityApiError extends Error { + res: ApiErrorResponse; + + constructor(res: request.Response, endpoint: string) { + super( + `Unhandled DatasetQualityApiError. + Status: "${res.status}" + Endpoint: "${endpoint}" + Body: ${JSON.stringify(res.body)} + ` + ); + + this.res = res; + } +} + +export interface SupertestReturnType { + status: number; + body: APIReturnType; +} diff --git a/x-pack/test/dataset_quality_api_integration/common/ftr_provider_context.ts b/x-pack/test/dataset_quality_api_integration/common/ftr_provider_context.ts new file mode 100644 index 000000000000..69de63c48402 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/common/ftr_provider_context.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { GenericFtrProviderContext } from '@kbn/test'; +import { FtrProviderContext as InheritedFtrProviderContext } from '../../api_integration/ftr_provider_context'; +import { DatasetQualityServices } from './config'; + +export type InheritedServices = InheritedFtrProviderContext extends GenericFtrProviderContext< + infer TServices, + {} +> + ? TServices + : {}; + +export type { InheritedFtrProviderContext }; +export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/test/dataset_quality_api_integration/common/registry.ts b/x-pack/test/dataset_quality_api_integration/common/registry.ts new file mode 100644 index 000000000000..355824916f87 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/common/registry.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { castArray, groupBy } from 'lodash'; +import callsites from 'callsites'; +import { FtrProviderContext } from './ftr_provider_context'; +import { DatasetQualityFtrConfigName } from '../configs'; +import { joinByKey, maybe } from '../utils'; + +interface RunCondition { + config: DatasetQualityFtrConfigName; +} + +export function RegistryProvider({ getService }: FtrProviderContext) { + const datasetQualityFtrConfig = getService('datasetQualityFtrConfig'); + + const callbacks: Array< + RunCondition & { + runs: Array<{ + cb: () => void; + }>; + } + > = []; + + let running: boolean = false; + + function when( + title: string, + conditions: RunCondition | RunCondition[], + callback: (condition: RunCondition) => void, + skip?: boolean + ) { + const allConditions = castArray(conditions); + + if (!allConditions.length) { + throw new Error('At least one condition should be defined'); + } + + if (running) { + throw new Error("Can't add tests when running"); + } + + const frame = maybe(callsites()[1]); + + const file = frame?.getFileName(); + + if (!file) { + throw new Error('Could not infer file for suite'); + } + + allConditions.forEach((matchedCondition) => { + callbacks.push({ + ...matchedCondition, + runs: [ + { + cb: () => { + const suite: ReturnType = (skip ? describe.skip : describe)( + title, + () => { + callback(matchedCondition); + } + ) as any; + + suite.file = file; + suite.eachTest((test) => { + test.file = file; + }); + }, + }, + ], + }); + }); + } + + when.skip = ( + title: string, + conditions: RunCondition | RunCondition[], + callback: (condition: RunCondition) => void + ) => { + when(title, conditions, callback, true); + }; + + const registry = { + when, + run: () => { + running = true; + + const groups = joinByKey(callbacks, ['config'], (a, b) => ({ + ...a, + ...b, + runs: a.runs.concat(b.runs), + })); + + callbacks.length = 0; + + const byConfig = groupBy(groups, 'config'); + + Object.keys(byConfig).forEach((config) => { + const groupsForConfig = byConfig[config]; + + // register suites for other configs, but skip them so tests are marked as such + // and their snapshots are not marked as obsolete + (config === datasetQualityFtrConfig.name ? describe : describe.skip)(config, () => { + groupsForConfig.forEach((group) => { + const { runs } = group; + + runs.forEach((run) => { + run.cb(); + }); + }); + }); + }); + + running = false; + }, + }; + + return registry; +} diff --git a/x-pack/test/dataset_quality_api_integration/configs/index.ts b/x-pack/test/dataset_quality_api_integration/configs/index.ts new file mode 100644 index 000000000000..db4447b0bcfe --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/configs/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mapValues } from 'lodash'; +import { createTestConfig, CreateTestConfig } from '../common/config'; + +export const datasetQualityDebugLogger = { + name: 'plugins.datasetQuality', + level: 'debug', + appenders: ['console'], +}; + +const datasetQualityFtrConfigs = { + basic: { + license: 'basic' as const, + kibanaConfig: { + 'logging.loggers': [datasetQualityDebugLogger], + }, + }, +}; + +export type DatasetQualityFtrConfigName = keyof typeof datasetQualityFtrConfigs; + +export const configs: Record = mapValues( + datasetQualityFtrConfigs, + (value, key) => { + return createTestConfig({ + name: key as DatasetQualityFtrConfigName, + ...value, + }); + } +); diff --git a/x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts new file mode 100644 index 000000000000..6d11326bf213 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { log, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { DatasetQualityApiClientKey } from '../common/config'; +import { DatasetQualityApiError } from '../common/dataset_quality_api_supertest'; +import { FtrProviderContext } from '../common/ftr_provider_context'; +import { expectToReject } from '../utils'; +import { cleanLogIndexTemplate, addIntegrationToLogIndexTemplate } from './es_utils'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const synthtrace = getService('logSynthtraceEsClient'); + const datasetQualityApiClient = getService('datasetQualityApiClient'); + const es = getService('es'); + + async function callApiAs(user: DatasetQualityApiClientKey) { + return await datasetQualityApiClient[user]({ + endpoint: 'GET /internal/dataset_quality/data_streams/stats', + params: { + query: { + type: 'logs', + }, + }, + }); + } + + registry.when('Api Key privileges check', { config: 'basic' }, () => { + describe('when missing required privileges', () => { + it('fails with a 500 error', async () => { + const err = await expectToReject( + async () => await callApiAs('readUser') + ); + + expect(err.res.status).to.be(500); + expect(err.res.body.message).to.contain('unauthorized'); + }); + }); + + describe('when required privileges are set', () => { + describe('and uncategorized datastreams', () => { + const integration = 'my-custom-integration'; + + before(async () => { + await addIntegrationToLogIndexTemplate({ esClient: es, name: integration }); + + await synthtrace.index([ + timerange('2023-11-20T15:00:00.000Z', '2023-11-20T15:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log.create().message('This is a log message').timestamp(timestamp).defaults({ + 'log.file.path': '/my-service.log', + }) + ), + ]); + }); + + it('returns stats correctly', async () => { + const stats = await callApiAs('datasetQualityLogsUser'); + + expect(stats.body.dataStreamsStats.length).to.be(1); + expect(stats.body.dataStreamsStats[0].integration).to.be(integration); + expect(stats.body.dataStreamsStats[0].size).not.empty(); + expect(stats.body.dataStreamsStats[0].size_bytes).greaterThan(0); + expect(stats.body.dataStreamsStats[0].last_activity).greaterThan(0); + }); + + after(async () => { + await synthtrace.clean(); + await cleanLogIndexTemplate({ esClient: es }); + }); + }); + + describe('and categorized datastreams', () => { + before(async () => { + await synthtrace.index([ + timerange('2023-11-20T15:00:00.000Z', '2023-11-20T15:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log.create().message('This is a log message').timestamp(timestamp).defaults({ + 'log.file.path': '/my-service.log', + }) + ), + ]); + }); + + it('returns stats correctly', async () => { + const stats = await callApiAs('datasetQualityLogsUser'); + + expect(stats.body.dataStreamsStats.length).to.be(1); + expect(stats.body.dataStreamsStats[0].integration).not.ok(); + expect(stats.body.dataStreamsStats[0].size).not.empty(); + expect(stats.body.dataStreamsStats[0].size_bytes).greaterThan(0); + expect(stats.body.dataStreamsStats[0].last_activity).greaterThan(0); + }); + + after(async () => { + await synthtrace.clean(); + }); + }); + }); + }); +} diff --git a/x-pack/test/dataset_quality_api_integration/tests/es_utils.ts b/x-pack/test/dataset_quality_api_integration/tests/es_utils.ts new file mode 100644 index 000000000000..607522089952 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/tests/es_utils.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Client } from '@elastic/elasticsearch'; + +export async function addIntegrationToLogIndexTemplate({ + esClient, + name, + managedBy = 'fleet', +}: { + esClient: Client; + name: string; + managedBy?: string; +}) { + const { index_templates: indexTemplates } = await esClient.indices.getIndexTemplate({ + name: 'logs', + }); + + await esClient.indices.putIndexTemplate({ + name: 'logs', + body: { + ...indexTemplates[0].index_template, + _meta: { + ...indexTemplates[0].index_template._meta, + package: { + name, + }, + managed_by: managedBy, + }, + }, + }); +} + +export async function cleanLogIndexTemplate({ esClient }: { esClient: Client }) { + const { index_templates: indexTemplates } = await esClient.indices.getIndexTemplate({ + name: 'logs', + }); + + await esClient.indices.putIndexTemplate({ + name: 'logs', + body: { + ...indexTemplates[0].index_template, + _meta: { + ...indexTemplates[0].index_template._meta, + package: undefined, + managed_by: undefined, + }, + }, + }); +} diff --git a/x-pack/test/dataset_quality_api_integration/tests/index.ts b/x-pack/test/dataset_quality_api_integration/tests/index.ts new file mode 100644 index 000000000000..9aacc0892334 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/tests/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import globby from 'globby'; +import path from 'path'; +import { FtrProviderContext } from '../common/ftr_provider_context'; + +const cwd = path.join(__dirname); +const envGrepFiles = process.env.DATASET_QUALITY_TEST_GREP_FILES as string; + +function getGlobPattern() { + try { + const envGrepFilesParsed = JSON.parse(envGrepFiles as string) as string[]; + return envGrepFilesParsed.map((pattern) => `**/${pattern}**`); + } catch (e) { + // ignore + } + return '**/*.spec.ts'; +} + +export default function datasetQualityApiIntegrationTests({ + getService, + loadTestFile, +}: FtrProviderContext) { + const registry = getService('registry'); + + describe('Dataset quality API tests', function () { + const filePattern = getGlobPattern(); + const tests = globby.sync(filePattern, { cwd }); + + if (envGrepFiles) { + // eslint-disable-next-line no-console + console.log( + `\nCommand "--grep-files=${filePattern}" matched ${tests.length} file(s):\n${tests + .map((name) => ` - ${name}`) + .join('\n')}\n` + ); + } + + tests.forEach((testName) => { + describe(testName, () => { + loadTestFile(require.resolve(`./${testName}`)); + registry.run(); + }); + }); + }); +} diff --git a/x-pack/test/dataset_quality_api_integration/utils/expect_to_reject.ts b/x-pack/test/dataset_quality_api_integration/utils/expect_to_reject.ts new file mode 100644 index 000000000000..ae352c31d71a --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/utils/expect_to_reject.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export async function expectToReject(fn: () => Promise): Promise { + let res: any; + try { + res = await fn(); + } catch (e) { + return e; + } + + throw new Error(`expectToReject resolved: "${JSON.stringify(res)}"`); +} diff --git a/x-pack/test/dataset_quality_api_integration/utils/index.ts b/x-pack/test/dataset_quality_api_integration/utils/index.ts new file mode 100644 index 000000000000..ae42a0d359d0 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/utils/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { joinByKey } from './join_by_key'; +export { maybe } from './maybe'; +export { expectToReject } from './expect_to_reject'; diff --git a/x-pack/test/dataset_quality_api_integration/utils/join_by_key.ts b/x-pack/test/dataset_quality_api_integration/utils/join_by_key.ts new file mode 100644 index 000000000000..0a74a2b94f39 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/utils/join_by_key.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UnionToIntersection, ValuesType } from 'utility-types'; +import { isEqual, pull, merge, castArray } from 'lodash'; + +/** + * Joins a list of records by a given key. Key can be any type of value, from + * strings to plain objects, as long as it is present in all records. `isEqual` + * is used for comparing keys. + * + * UnionToIntersection is needed to get all keys of union types, see below for + * example. + * + */ + +export type JoinedReturnType< + T extends Record, + U extends UnionToIntersection +> = Array< + Partial & { + [k in keyof T]: T[k]; + } +>; + +type ArrayOrSingle = T | T[]; + +export function joinByKey< + T extends Record, + U extends UnionToIntersection, + V extends ArrayOrSingle +>(items: T[], key: V): JoinedReturnType; + +export function joinByKey< + T extends Record, + U extends UnionToIntersection, + V extends ArrayOrSingle, + W extends JoinedReturnType, + X extends (a: T, b: T) => ValuesType +>(items: T[], key: V, mergeFn: X): W; + +export function joinByKey( + items: Array>, + key: string | string[], + mergeFn: Function = (a: Record, b: Record) => merge({}, a, b) +) { + const keys = castArray(key); + return items.reduce>>((prev, current) => { + let item = prev.find((prevItem) => keys.every((k) => isEqual(prevItem[k], current[k]))); + + if (!item) { + item = { ...current }; + prev.push(item); + } else { + pull(prev, item).push(mergeFn(item, current)); + } + + return prev; + }, []); +} diff --git a/x-pack/test/dataset_quality_api_integration/utils/maybe.ts b/x-pack/test/dataset_quality_api_integration/utils/maybe.ts new file mode 100644 index 000000000000..f73dbe09d6ad --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/utils/maybe.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function maybe(value: T): T | null | undefined { + return value; +} diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts deleted file mode 100644 index fbbef2098464..000000000000 --- a/x-pack/test/detection_engine_api_integration/basic/tests/create_rules.ts +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { RuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; - -import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createSignalsIndex, - deleteAllRules, - getSimpleRule, - getSimpleRuleOutput, - getSimpleRuleOutputWithoutRuleId, - getSimpleRuleWithoutRuleId, - removeServerGeneratedProperties, - removeServerGeneratedPropertiesIncludingRuleId, - getSimpleMlRule, - deleteAllAlerts, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - const log = getService('log'); - const es = getService('es'); - - describe('create_rules', () => { - describe('creating rules', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - it('should create a single rule with a rule_id', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(getSimpleRule()) - .expect(200); - - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getSimpleRuleOutput()); - }); - - it('should create a single rule without an input index', async () => { - const rule: RuleCreateProps = { - name: 'Simple Rule Query', - description: 'Simple Rule Query', - enabled: true, - risk_score: 1, - rule_id: 'rule-1', - severity: 'high', - type: 'query', - query: 'user.name: root or user.name: admin', - }; - const expected = { - actions: [], - author: [], - created_by: 'elastic', - description: 'Simple Rule Query', - enabled: true, - false_positives: [], - from: 'now-6m', - immutable: false, - interval: '5m', - rule_id: 'rule-1', - language: 'kuery', - output_index: '', - max_signals: 100, - risk_score: 1, - risk_score_mapping: [], - name: 'Simple Rule Query', - query: 'user.name: root or user.name: admin', - references: [], - related_integrations: [], - required_fields: [], - setup: '', - severity: 'high', - severity_mapping: [], - updated_by: 'elastic', - tags: [], - to: 'now', - type: 'query', - threat: [], - exceptions_list: [], - version: 1, - revision: 0, - }; - - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(rule) - .expect(200); - - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(expected); - }); - - it('should create a single rule without a rule_id', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(getSimpleRuleWithoutRuleId()) - .expect(200); - - const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); - expect(bodyToCompare).to.eql(getSimpleRuleOutputWithoutRuleId()); - }); - - it('should give a 403 when trying to create a single Machine Learning rule since the license is basic', async () => { - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(getSimpleMlRule()) - .expect(403); - - const bodyToCompare = removeServerGeneratedProperties(body); - expect(bodyToCompare).to.eql({ - message: 'Your license does not support machine learning. Please upgrade your license.', - status_code: 403, - }); - }); - - it('should cause a 409 conflict if we attempt to create the same rule_id twice', async () => { - await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(getSimpleRule()) - .expect(200); - - const { body } = await supertest - .post(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send(getSimpleRule()) - .expect(409); - - expect(body).to.eql({ - message: 'rule_id: "rule-1" already exists', - status_code: 409, - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/index.ts b/x-pack/test/detection_engine_api_integration/basic/tests/index.ts index 315a06043684..5b3449707d38 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/index.ts @@ -10,7 +10,6 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { describe('detection engine api basic license', function () { - loadTestFile(require.resolve('./create_rules')); loadTestFile(require.resolve('./create_rules_bulk')); loadTestFile(require.resolve('./delete_rules')); loadTestFile(require.resolve('./delete_rules_bulk')); @@ -22,8 +21,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./update_rules_bulk')); loadTestFile(require.resolve('./patch_rules_bulk')); loadTestFile(require.resolve('./patch_rules')); - loadTestFile(require.resolve('./query_signals')); - loadTestFile(require.resolve('./open_close_signals')); loadTestFile(require.resolve('./import_timelines')); loadTestFile(require.resolve('./coverage_overview')); }); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/open_close_signals.ts b/x-pack/test/detection_engine_api_integration/basic/tests/open_close_signals.ts deleted file mode 100644 index cc1216e80dd8..000000000000 --- a/x-pack/test/detection_engine_api_integration/basic/tests/open_close_signals.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - DETECTION_ENGINE_SIGNALS_STATUS_URL, - DETECTION_ENGINE_QUERY_SIGNALS_URL, -} from '@kbn/security-solution-plugin/common/constants'; -import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createSignalsIndex, - setSignalStatus, - getQuerySignalIds, - deleteAllRules, - createRule, - waitForSignalsToBePresent, - getSignalsByIds, - waitForRuleSuccess, - getRuleForSignalTesting, - deleteAllAlerts, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - describe('open_close_signals', () => { - describe('tests with auditbeat data', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - beforeEach(async () => { - await deleteAllRules(supertest, log); - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - it('should be able to execute and get 10 signals', async () => { - const rule = { - ...getRuleForSignalTesting(['auditbeat-*']), - query: 'process.executable: "/usr/bin/sudo"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 10, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - expect(signalsOpen.hits.hits.length).equal(10); - }); - - it('should be have set the signals in an open state initially', async () => { - const rule = { - ...getRuleForSignalTesting(['auditbeat-*']), - query: 'process.executable: "/usr/bin/sudo"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 10, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const everySignalOpen = signalsOpen.hits.hits.every( - (hit) => hit._source?.[ALERT_WORKFLOW_STATUS] === 'open' - ); - expect(everySignalOpen).to.eql(true); - }); - - it('should be able to get a count of 10 closed signals when closing 10', async () => { - const rule = { - ...getRuleForSignalTesting(['auditbeat-*']), - query: 'process.executable: "/usr/bin/sudo"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 10, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const signalIds = signalsOpen.hits.hits.map((signal) => signal._id); - - // set all of the signals to the state of closed. There is no reason to use a waitUntil here - // as this route intentionally has a waitFor within it and should only return when the query has - // the data. - await supertest - .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) - .set('kbn-xsrf', 'true') - .send(setSignalStatus({ signalIds, status: 'closed' })) - .expect(200); - - const { body: signalsClosed }: { body: estypes.SearchResponse } = - await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(getQuerySignalIds(signalIds)) - .expect(200); - expect(signalsClosed.hits.hits.length).to.equal(10); - }); - - // Test is failing after changing refresh to false - it.skip('should be able close 10 signals immediately and they all should be closed', async () => { - const rule = { - ...getRuleForSignalTesting(['auditbeat-*']), - query: 'process.executable: "/usr/bin/sudo"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 10, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const signalIds = signalsOpen.hits.hits.map((signal) => signal._id); - - // set all of the signals to the state of closed. There is no reason to use a waitUntil here - // as this route intentionally has a waitFor within it and should only return when the query has - // the data. - await supertest - .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) - .set('kbn-xsrf', 'true') - .send(setSignalStatus({ signalIds, status: 'closed' })) - .expect(200); - - const { body: signalsClosed }: { body: estypes.SearchResponse } = - await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(getQuerySignalIds(signalIds)) - .expect(200); - - const everySignalClosed = signalsClosed.hits.hits.every( - (hit) => hit._source?.[ALERT_WORKFLOW_STATUS] === 'closed' - ); - expect(everySignalClosed).to.eql(true); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts b/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts deleted file mode 100644 index 2acd4ffab10b..000000000000 --- a/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { - DETECTION_ENGINE_QUERY_SIGNALS_URL, - ALERTS_AS_DATA_FIND_URL, -} from '@kbn/security-solution-plugin/common/constants'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { getSignalStatus, createSignalsIndex, deleteAllAlerts } from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - describe('query_signals_route and find_alerts_route', () => { - describe('validation checks', () => { - // This fails and should be investigated or removed if it no longer applies - it.skip('should not give errors when querying and the signals index does exist and is empty', async () => { - await createSignalsIndex(supertest, log); - const { body } = await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(getSignalStatus()) - .expect(200); - - // remove any server generated items that are indeterministic - delete body.took; - - expect(body).to.eql({ - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - statuses: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - }); - - await deleteAllAlerts(supertest, log, es); - }); - }); - - describe('backwards compatibility', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/endpoint/resolver/signals'); - await createSignalsIndex(supertest, log); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals'); - await deleteAllAlerts(supertest, log, es); - }); - - it('should be able to filter old signals on host.os.name.caseless using runtime field', async () => { - const query = { - query: { - bool: { - should: [{ match_phrase: { 'host.os.name.caseless': 'windows' } }], - }, - }, - }; - const { body } = await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(query) - .expect(200); - expect(body.hits.total.value).to.eql(3); - }); - - it('should be able to filter old signals using field aliases', async () => { - const query = { - query: { - bool: { - should: [{ match_phrase: { 'kibana.alert.workflow_status': 'open' } }], - }, - }, - }; - const { body } = await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(query) - .expect(200); - expect(body.hits.total.value).to.eql(3); - }); - }); - - describe('runtime fields', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/endpoint/resolver/signals'); - await createSignalsIndex(supertest, log); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals'); - await deleteAllAlerts(supertest, log, es); - }); - - it('should be able to filter using a runtime field defined in the request', async () => { - const query = { - query: { - bool: { - should: [{ match_phrase: { signal_status_querytime: 'open' } }], - }, - }, - runtime_mappings: { - signal_status_querytime: { - type: 'keyword', - script: { - source: `emit(doc['signal.status'].value)`, - }, - }, - }, - }; - const { body } = await supertest - .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) - .set('kbn-xsrf', 'true') - .send(query) - .expect(200); - expect(body.hits.total.value).to.eql(3); - }); - }); - - describe('find_alerts_route', () => { - describe('validation checks', () => { - // This fails and should be investigated or removed if it no longer applies - it.skip('should not give errors when querying and the signals index does exist and is empty', async () => { - await createSignalsIndex(supertest, log); - const { body } = await supertest - .post(ALERTS_AS_DATA_FIND_URL) - .set('kbn-xsrf', 'true') - .send({ ...getSignalStatus(), index: '.siem-signals-default' }) - .expect(200); - - // remove any server generated items that are indeterministic - delete body.took; - - expect(body).to.eql({ - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - statuses: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, - }, - }); - - await deleteAllAlerts(supertest, log, es); - }); - - it('should not give errors when executing security solution histogram aggs', async () => { - await createSignalsIndex(supertest, log); - await supertest - .post(ALERTS_AS_DATA_FIND_URL) - .set('kbn-xsrf', 'true') - .send({ - index: '.siem-signals-default', - aggs: { - alertsByGrouping: { - terms: { - field: 'event.category', - missing: 'All others', - order: { _count: 'desc' }, - size: 10, - }, - aggs: { - alerts: { - date_histogram: { - field: '@timestamp', - fixed_interval: '2699999ms', - min_doc_count: 0, - extended_bounds: { - min: '2021-08-17T04:00:00.000Z', - max: '2021-08-18T03:59:59.999Z', - }, - }, - }, - }, - }, - }, - query: { - bool: { - filter: [ - { - bool: { - must: [], - filter: [ - { - match_phrase: { - 'kibana.alert.rule.uuid': 'c76f1a10-ffb6-11eb-8914-9b237bf6808c', - }, - }, - { term: { 'kibana.alert.workflow_status': 'open' } }, - ], - should: [], - must_not: [{ exists: { field: 'kibana.alert.building_block_type' } }], - }, - }, - { - range: { - '@timestamp': { - gte: '2021-08-17T04:00:00.000Z', - lte: '2021-08-18T03:59:59.999Z', - }, - }, - }, - ], - }, - }, - }) - .expect(200); - - await deleteAllAlerts(supertest, log, es); - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts index 6404da38cdde..982557130717 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts @@ -447,7 +447,7 @@ export default ({ getService }: FtrProviderContext): void => { .expect(400); expect(body.message).to.eql( - '[request body]: 0.investigation_fields: Expected object, received array, 0.type: Invalid literal value, expected "eql", 0.language: Invalid literal value, expected "eql", 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, and 22 more' + '[request body]: 0.investigation_fields: Expected object, received array' ); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts index 44d912f3271c..d3e83305ad11 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts @@ -14,7 +14,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { // action migration code. We are monitoring legacy action telemetry to clean up once we see their // existence being near 0. - loadTestFile(require.resolve('./check_privileges')); loadTestFile(require.resolve('./create_rules_bulk')); loadTestFile(require.resolve('./delete_rules')); loadTestFile(require.resolve('./delete_rules_bulk')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/ignore_fields.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/ignore_fields.ts deleted file mode 100644 index 829224b9c608..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/ignore_fields.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getEqlRuleForSignalTesting, - getSignalsById, - waitForRuleSuccess, - waitForSignalsToBePresent, -} from '../../utils'; - -interface Ignore { - normal_constant?: string; - small_field?: string; - testing_ignored?: string; - testing_regex?: string; -} - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext): void => { - /** - * See the config file (detection_engine_api_integration/common/config.ts) for which field values were added to be ignored - * for testing. The values should be in the config around the area of: - * --xpack.securitySolution.alertIgnoreFields=[testing.ignore_1,/[testingRegex] - * meaning that the ignore fields values should be the array: ["testing.ignore_1", "/[testingRegex]/"] - * - * This test exercises the ability to be able to ignore particular values within the fields API and merge strategies. - * These values can be defined in your kibana.yml file as "xpack.securitySolution.alertIgnoreFields". This is useful - * for users that find bugs or regressions within query languages or bugs within the merge strategies - * where one or more fields are causing problems and they need to turn disable that particular field. - * - * Ref: - * https://github.com/elastic/kibana/issues/110802 - * https://github.com/elastic/elasticsearch/issues/77152 - * - * Files ref: - * server/lib/detection_engine/signals/source_fields_merging/utils/is_ignored.ts - * server/lib/detection_engine/signals/source_fields_merging/utils/is_eql_bug_77152.ts - */ - describe('ignore_fields', () => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/ignore_fields'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/ignore_fields'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - it('should ignore the field of "testing_ignored"', async () => { - const rule = getEqlRuleForSignalTesting(['ignore_fields']); - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((hit) => (hit._source as Ignore).testing_ignored) - .sort(); - - // Value should be "undefined for all records" - expect(hits).to.eql([undefined, undefined, undefined, undefined]); - }); - - it('should ignore the field of "testing_regex"', async () => { - const rule = getEqlRuleForSignalTesting(['ignore_fields']); - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => (hit._source as Ignore).testing_regex).sort(); - - // Value should be "undefined for all records" - expect(hits).to.eql([undefined, undefined, undefined, undefined]); - }); - - it('should have the field of "normal_constant"', async () => { - const rule = getEqlRuleForSignalTesting(['ignore_fields']); - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((hit) => (hit._source as Ignore).normal_constant) - .sort(); - - // Value should be "constant_value for all records" - expect(hits).to.eql(['constant_value', 'constant_value', 'constant_value', 'constant_value']); - }); - - // TODO: Remove this test once https://github.com/elastic/elasticsearch/issues/77152 is fixed - it('should ignore the field of "_ignored" when using EQL and index the data', async () => { - const rule = getEqlRuleForSignalTesting(['ignore_fields']); - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => (hit._source as Ignore).small_field).sort(); - - // We just test a constant value to ensure this did not blow up on us and did index data. - expect(hits).to.eql([ - '1 indexed', - '2 large not indexed', - '3 large not indexed', - '4 large not indexed', - ]); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_export_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_export_rules.ts index 8943a4b67c99..aee267db951d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_export_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_export_rules.ts @@ -26,8 +26,8 @@ import { deleteAllRules, deleteAllAlerts, getSimpleRule, + deleteAllExceptions, } from '../../utils'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution'; // This test was meant to be more full flow, ensuring that diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts index c92591e8f3f7..6517c46bddca 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/import_rules.ts @@ -38,8 +38,8 @@ import { createRule, getRule, getRuleSOById, + deleteAllExceptions, } from '../../utils'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution'; const getImportRuleBuffer = (connectorId: string) => { @@ -411,11 +411,7 @@ export default ({ getService }: FtrProviderContext): void => { expect(body.errors[0]).to.eql({ rule_id: '(unknown id)', - error: { - message: - 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", saved_id: Required, and 14 more', - status_code: 400, - }, + error: { status_code: 400, message: 'threshold: Required' }, }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts index ae0bfaa8940e..70b50d7f5aef 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts @@ -25,10 +25,5 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./perform_bulk_action')); loadTestFile(require.resolve('./perform_bulk_action_dry_run')); loadTestFile(require.resolve('./patch_rules')); - loadTestFile(require.resolve('./read_privileges')); - loadTestFile(require.resolve('./timestamps')); - loadTestFile(require.resolve('./runtime')); - loadTestFile(require.resolve('./throttle')); - loadTestFile(require.resolve('./ignore_fields')); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts index 2529e794089a..d14d82edbba5 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts @@ -23,7 +23,6 @@ import { getCreateExceptionListDetectionSchemaMock } from '@kbn/lists-plugin/com import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { WebhookAuthType } from '@kbn/stack-connectors-plugin/common/webhook/constants'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; import { binaryToString, createLegacyRuleAction, @@ -44,6 +43,7 @@ import { createRuleThroughAlertingEndpoint, getRuleSavedObjectWithLegacyInvestigationFields, getRuleSavedObjectWithLegacyInvestigationFieldsEmptyArray, + deleteAllExceptions, } from '../../utils'; import { FtrProviderContext } from '../../common/ftr_provider_context'; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/runtime.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/runtime.ts deleted file mode 100644 index 83c988c5ff9f..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/runtime.ts +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { performance } from 'perf_hooks'; - -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getRuleForSignalTesting, - getSignalsById, - waitForRuleSuccess, - waitForSignalsToBePresent, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - interface Runtime { - name: string; - hostname: string; - } - - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/138923 - describe('Tests involving runtime fields of source indexes and the signals index', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/runtime'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/runtime'); - }); - - describe('Regular runtime field mappings', () => { - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - it('should execute a rule to completion and not timeout when there are a lot of runtime fields', async () => { - const rule = getRuleForSignalTesting(['runtime']); - const { id } = await createRule(supertest, log, rule); - const start = performance.now(); - await waitForRuleSuccess({ supertest, log, id }); - const end = performance.now(); - expect(end - start).to.be.lessThan(10000); - }); - - it('should copy normal non-runtime data set from the source index into the signals index in the same position when the target is ECS compatible', async () => { - const rule = getRuleForSignalTesting(['runtime']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((signal) => (signal._source?.host as Runtime).name) - .sort(); - expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']); - }); - - it('should copy "runtime mapping" data from a source index into the signals index in the same position when the target is ECS compatible', async () => { - const rule = getRuleForSignalTesting(['runtime']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((signal) => (signal._source?.host as Runtime).hostname) - .sort(); - expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']); - }); - }); - - describe('Runtime field mappings that have conflicts within them', () => { - beforeEach(async () => { - await createSignalsIndex(supertest, log); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields' - ); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields' - ); - }); - - /** - * Note, this test shows that we do not shadow or overwrite runtime fields on-top of regular fields as we reduced - * risk with overwriting fields in the strategy we are currently using in detection engine. If you swap, change the strategies - * because we decide to overwrite "_source" values with "fields", then expect to change this test. - */ - it('should NOT copy normal non-runtime data set from the source index into the signals index in the same position when the target is ECS compatible', async () => { - const rule = getRuleForSignalTesting(['runtime_conflicting_fields']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((signal) => signal._source?.host as Array<{ name: string }>) - .map((host) => { - // sort the inner array elements first - return host.sort((a, b) => a.name.localeCompare(b.name)); - }) - .sort((aArray, bArray) => { - // since these are all unique, using just the first element should give us stability - return aArray[0].name.localeCompare(bArray[0].name); - }); - expect(hits).to.eql([ - [ - { - name: 'host name 1_1', - }, - { - name: 'host name 1_2', - }, - ], - [ - { - name: 'host name 2_1', - }, - { - name: 'host name 2_2', - }, - ], - [ - { - name: 'host name 3_1', - }, - { - name: 'host name 3_2', - }, - ], - [ - { - name: 'host name 4_1', - }, - { - name: 'host name 4_2', - }, - ], - ]); - }); - - /** - * Note, this test shows that we do NOT shadow or overwrite runtime fields on-top of regular fields when we detect those - * fields as arrays of objects since the objects are flattened in "fields" and we detect something already there so we skip - * this shadowed runtime data as it is ambiguous of where we would put it in the array. - */ - it('should NOT copy "runtime mapping" data from a source index into the signals index in the same position when the target is ECS compatible', async () => { - const rule = getRuleForSignalTesting(['runtime_conflicting_fields']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map( - (signal) => (signal._source?.host as Runtime).hostname - ); - expect(hits).to.eql([undefined, undefined, undefined, undefined]); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts deleted file mode 100644 index ef27b7c7ff4b..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/timestamps.ts +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { orderBy } from 'lodash'; -import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; -import { - EqlRuleCreateProps, - QueryRuleCreateProps, -} from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_ORIGINAL_TIME } from '@kbn/security-solution-plugin/common/field_maps/field_names'; - -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - createRule, - waitForRuleSuccess, - waitForSignalsToBePresent, - getOpenSignals, - getRuleForSignalTesting, - getSignalsByIds, - getEqlRuleForSignalTesting, - waitForRulePartialFailure, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); - const log = getService('log'); - - /** - * Tests around timestamps within signals such as the copying of timestamps correctly into - * the "signal.original_time" field, ensuring that timestamp overrides operate, and ensuring that - * partial errors happen correctly - */ - describe('timestamp tests', () => { - describe('Signals generated from events with a timestamp in seconds is converted correctly into the forced ISO8601 format when copying', () => { - beforeEach(async () => { - await createSignalsIndex(supertest, log); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds' - ); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_5' - ); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds' - ); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_5' - ); - }); - - describe('KQL query', () => { - it('should convert the @timestamp which is epoch_seconds into the correct ISO format', async () => { - const rule = getRuleForSignalTesting(['timestamp_in_seconds']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) - .sort(); - expect(hits).to.eql(['2021-06-02T23:33:15.000Z']); - }); - - it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfakeindex-5']), - timestamp_override: 'event.ingested', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) - .sort(); - expect(hits).to.eql(['2020-12-16T15:16:18.000Z']); - }); - }); - - describe('EQL query', () => { - it('should convert the @timestamp which is epoch_seconds into the correct ISO format for EQL', async () => { - const rule = getEqlRuleForSignalTesting(['timestamp_in_seconds']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) - .sort(); - expect(hits).to.eql(['2021-06-02T23:33:15.000Z']); - }); - - it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['myfakeindex-5']), - timestamp_override: 'event.ingested', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsByIds(supertest, log, [id]); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) - .sort(); - expect(hits).to.eql(['2020-12-16T15:16:18.000Z']); - }); - }); - }); - - /** - * Here we test the functionality of timestamp overrides. If the rule specifies a timestamp override, - * then the documents will be queried and sorted using the timestamp override field. - * If no timestamp override field exists in the indices but one was provided to the rule, - * the rule's query will additionally search for events using the `@timestamp` field - */ - describe('Signals generated from events with timestamp override field', async () => { - beforeEach(async () => { - await deleteAllAlerts(supertest, log, es); - await createSignalsIndex(supertest, log); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_1' - ); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_2' - ); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' - ); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_4' - ); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_1' - ); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_2' - ); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' - ); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_4' - ); - }); - - describe('KQL', () => { - it('should generate signals with event.ingested, @timestamp and (event.ingested + timestamp)', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfa*']), - timestamp_override: 'event.ingested', - }; - - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 3, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id], 3); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(3); - }); - - it('should generate 2 signals with event.ingested when timestamp fallback is disabled', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfa*']), - rule_id: 'rule-without-timestamp-fallback', - timestamp_override: 'event.ingested', - timestamp_override_fallback_disabled: true, - }; - - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 2, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id], 2); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(2); - }); - - it('should generate 2 signals with @timestamp', async () => { - const rule: QueryRuleCreateProps = getRuleForSignalTesting(['myfa*']); - - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 2, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id]); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(2); - }); - - it('should generate 2 signals when timestamp override does not exist', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfa*']), - timestamp_override: 'event.fakeingestfield', - }; - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 2, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id, id]); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(2); - }); - - it('should not generate any signals when timestamp override does not exist and timestamp fallback is disabled', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfa*']), - rule_id: 'rule-without-timestamp-fallback', - timestamp_override: 'event.fakeingestfield', - timestamp_override_fallback_disabled: true, - }; - - const createdRule = await createRule(supertest, log, rule); - const signalsOpen = await getOpenSignals( - supertest, - log, - es, - createdRule, - RuleExecutionStatusEnum['partial failure'] - ); - expect(signalsOpen.hits.hits.length).eql(0); - }); - - /** - * We should not use the timestamp override as the "original_time" as that can cause - * confusion if you have both a timestamp and an override in the source event. Instead the "original_time" - * field should only be overridden by the "timestamp" since when we generate a signal - * and we add a new timestamp to the signal. - */ - it('should NOT use the timestamp override as the "original_time"', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['myfakeindex-2']), - timestamp_override: 'event.ingested', - }; - const { id } = await createRule(supertest, log, rule); - - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id, id]); - const hits = signalsResponse.hits.hits - .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) - .sort(); - expect(hits).to.eql([undefined]); - }); - }); - - describe('EQL', () => { - it('should generate 2 signals with @timestamp', async () => { - const rule: EqlRuleCreateProps = getEqlRuleForSignalTesting(['myfa*']); - - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 2, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id]); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(2); - }); - - it('should generate 2 signals when timestamp override does not exist', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['myfa*']), - timestamp_override: 'event.fakeingestfield', - }; - const { id } = await createRule(supertest, log, rule); - - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 2, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id, id]); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - const signalsOrderedByEventId = orderBy(signals, 'signal.parent.id', 'asc'); - - expect(signalsOrderedByEventId.length).equal(2); - }); - - it('should not generate any signals when timestamp override does not exist and timestamp fallback is disabled', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['myfa*']), - timestamp_override: 'event.fakeingestfield', - timestamp_override_fallback_disabled: true, - }; - const createdRule = await createRule(supertest, log, rule); - const signalsOpen = await getOpenSignals( - supertest, - log, - es, - createdRule, - RuleExecutionStatusEnum['partial failure'] - ); - expect(signalsOpen.hits.hits.length).eql(0); - }); - }); - }); - - describe('Signals generated from events with timestamp override field and ensures search_after continues to work when documents are missing timestamp override field', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - describe('KQL', () => { - /** - * This represents our worst case scenario where this field is not mapped on any index - * We want to check that our logic continues to function within the constraints of search after - * Elasticsearch returns java's long.MAX_VALUE for unmapped date fields - * Javascript does not support numbers this large, but without passing in a number of this size - * The search_after will continue to return the same results and not iterate to the next set - * So to circumvent this limitation of javascript we return the stringified version of Java's - * Long.MAX_VALUE so that search_after does not enter into an infinite loop. - * - * ref: https://github.com/elastic/elasticsearch/issues/28806#issuecomment-369303620 - */ - it('should generate 200 signals when timestamp override does not exist', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), - timestamp_override: 'event.fakeingested', - max_signals: 200, - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRulePartialFailure({ - supertest, - log, - id, - }); - await waitForSignalsToBePresent(supertest, log, 200, [id]); - const signalsResponse = await getSignalsByIds(supertest, log, [id], 200); - const signals = signalsResponse.hits.hits.map((hit) => hit._source); - - expect(signals.length).equal(200); - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts index d88ed8a898f9..afb0205ce458 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts @@ -566,8 +566,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: - '[request body]: type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", saved_id: Required, and 14 more', + message: '[request body]: threshold: Required', statusCode: 400, }); }); @@ -957,7 +956,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(400); expect(body.message).to.eql( - '[request body]: investigation_fields: Expected object, received array, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, and 22 more' + '[request body]: investigation_fields: Expected object, received array' ); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts index a3defbb6d1c8..569069cee306 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts @@ -854,7 +854,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(400); expect(body.message).to.eql( - '[request body]: 0.investigation_fields: Expected object, received array, 0.type: Invalid literal value, expected "eql", 0.language: Invalid literal value, expected "eql", 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, and 22 more' + '[request body]: 0.investigation_fields: Expected object, received array' ); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/config.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/config.ts deleted file mode 100644 index 2430b8f2148d..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/config.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrConfigProviderContext } from '@kbn/test'; - -// eslint-disable-next-line import/no-default-export -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../config.base.ts')); - - return { - ...functionalConfig.getAll(), - testFiles: [require.resolve('.')], - }; -} diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/index.ts deleted file mode 100644 index 9394e81017ab..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('detection engine api security and spaces enabled - Group 4', function () { - loadTestFile(require.resolve('./telemetry')); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/index.ts deleted file mode 100644 index 4e180f73dc74..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('Detection rule type telemetry', function () { - loadTestFile(require.resolve('./usage_collector/all_types')); - loadTestFile(require.resolve('./usage_collector/detection_rules')); - loadTestFile(require.resolve('./usage_collector/detection_rule_status')); - - loadTestFile(require.resolve('./task_based/all_types')); - loadTestFile(require.resolve('./task_based/detection_rules')); - loadTestFile(require.resolve('./task_based/security_lists')); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/all_types.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/all_types.ts deleted file mode 100644 index 576f00b56372..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/all_types.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getSecurityTelemetryStats, - removeTimeFieldsFromTelemetryStats, -} from '../../../../utils'; -import { deleteAllExceptions } from '../../../../../lists_api_integration/utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const retry = getService('retry'); - const es = getService('es'); - - describe('All task telemetry types generically', async () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await deleteAllExceptions(supertest, log); - }); - - it('should only have task metric values when no rules are running', async () => { - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats).to.eql({ - detection_rules: [ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ], - security_lists: [ - [ - { - name: 'Security Solution Lists Telemetry', - passed: true, - }, - ], - ], - endpoints: [ - [ - { - name: 'Security Solution Telemetry Endpoint Metrics and Info task', - passed: true, - }, - ], - ], - diagnostics: [ - [ - { - name: 'Security Solution Telemetry Diagnostics task', - passed: true, - }, - ], - ], - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts deleted file mode 100644 index 684fc752c152..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/detection_rules.ts +++ /dev/null @@ -1,908 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable @typescript-eslint/naming-convention */ - -import expect from '@kbn/expect'; -import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; -import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common'; -import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getRule, - getRuleForSignalTesting, - installMockPrebuiltRules, - getSecurityTelemetryStats, - createExceptionList, - createExceptionListItem, - removeTimeFieldsFromTelemetryStats, -} from '../../../../utils'; -import { deleteAllExceptions } from '../../../../../lists_api_integration/utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const es = getService('es'); - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const retry = getService('retry'); - - describe('Detection rule task telemetry', async () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await deleteAllExceptions(supertest, log); - }); - - describe('custom rules should never show any detection_rules telemetry data for each list type', () => { - it('should NOT give telemetry/stats for an exception list of type "detection"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'detection', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // Create the rule with the exception added to it - await createRule(supertest, log, { - ...rule, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }); - - // Get the stats and ensure they're empty - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats.detection_rules).to.eql([ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ]); - }); - }); - - it('should NOT give telemetry/stats for an exception list of type "endpoint"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // Create the rule with the exception added to it - await createRule(supertest, log, { - ...rule, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }); - - // Get the stats and ensure they're empty - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats.detection_rules).to.eql([ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ]); - }); - }); - - it('should NOT give telemetry/stats for an exception list of type "endpoint_trusted_apps"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_trusted_apps', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // Create the rule with the exception added to it - await createRule(supertest, log, { - ...rule, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }); - - // Get the stats and ensure they're empty - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats.detection_rules).to.eql([ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ]); - }); - }); - - it('should NOT give telemetry/stats for an exception list of type "endpoint_events"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_events', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // Create the rule with the exception added to it - await createRule(supertest, log, { - ...rule, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }); - - // Get the stats and ensure they're empty - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats.detection_rules).to.eql([ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ]); - }); - }); - - it('should NOT give telemetry/stats for an exception list of type "endpoint_host_isolation_exceptions"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_host_isolation_exceptions', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // Create the rule with the exception added to it - await createRule(supertest, log, { - ...rule, - exceptions_list: [ - { - id, - list_id, - namespace_type, - type, - }, - ], - }); - - // Get the stats and ensure they're empty - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - expect(stats.detection_rules).to.eql([ - [ - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ], - ]); - }); - }); - }); - - describe('pre-built/immutable/elastic rules should show detection_rules telemetry data for each list type', () => { - beforeEach(async () => { - // install prepackaged rules to get immutable rules for testing - await installMockPrebuiltRules(supertest, es); - }); - - it('should return mutating types such as "id", "@timestamp", etc... for list of type "detection"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'detection', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule using "PATCH" endpoint - const { exceptions_list } = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - expect(stats.detection_rules).length(2); - const detectionRule = stats.detection_rules[0][0]; - expect(detectionRule['@timestamp']).to.be.a('string'); - expect(detectionRule.cluster_uuid).to.be.a('string'); - expect(detectionRule.cluster_name).to.be.a('string'); - expect(detectionRule.license_id).to.be.a('string'); - expect(detectionRule.detection_rule.created_at).to.be.a('string'); - expect(detectionRule.detection_rule.id).to.be.a('string'); - }); - }); - - it('should give telemetry/stats for an exception list of type "detection"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'detection', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - - it('should give telemetry/stats for an exception list of type "endpoint"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - - it('should give telemetry/stats for an exception list of type "endpoint_trusted_apps"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_trusted_apps', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - - it('should give telemetry/stats for an exception list of type "endpoint_events"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_events', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - - it('should give telemetry/stats for an exception list of type "endpoint_host_isolation_exceptions"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'endpoint_host_isolation_exceptions', - }); - - // add 1 item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - }); - - describe('pre-built/immutable/elastic rules should show detection_rules telemetry data for multiple list items and types', () => { - beforeEach(async () => { - // install prepackaged rules to get immutable rules for testing - await installMockPrebuiltRules(supertest, es); - }); - - it('should give telemetry/stats for 2 exception lists to the type of "detection"', async () => { - // create an exception list container of type "detection" - const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { - description: 'description', - list_id: '123', - name: 'test list', - type: 'detection', - }); - - // add 1st item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description 1', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something 1', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add 2nd item to the exception list - await createExceptionListItem(supertest, log, { - description: 'endpoint description 2', - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something 2', - }, - ], - list_id: '123', - name: 'endpoint_list', - os_types: [], - type: 'simple', - }); - - // add the exception list to the pre-built/immutable/elastic rule - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - await supertest - .patch(DETECTION_ENGINE_RULES_URL) - .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') - .send({ - rule_id: ELASTIC_SECURITY_RULE_ID, - exceptions_list: [ - ...immutableRule.exceptions_list, - { - id, - list_id, - namespace_type, - type, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getSecurityTelemetryStats(supertest, log); - removeTimeFieldsFromTelemetryStats(stats); - const detectionRules = stats.detection_rules - .flat() - .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)) - .sort((obj1: { entries: { name: number } }, obj2: { entries: { name: number } }) => { - return obj1?.entries?.name - obj2?.entries?.name; - }); - - expect(detectionRules).to.eql([ - { - created_at: detectionRules[0].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something 2', - }, - ], - id: detectionRules[0].id, - name: 'endpoint description 2', - os_types: [], - rule_version: detectionRules[0].rule_version, - }, - { - created_at: detectionRules[1].created_at, - entries: [ - { - field: 'keyword', - operator: 'included', - type: 'match', - value: 'something 1', - }, - ], - id: detectionRules[1].id, - name: 'endpoint description 1', - os_types: [], - rule_version: detectionRules[1].rule_version, - }, - { - name: 'Security Solution Detection Rule Lists Telemetry', - passed: true, - }, - ]); - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/all_types.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/all_types.ts deleted file mode 100644 index 503fcc3c1a5d..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/all_types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; -import type { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { createSignalsIndex, deleteAllRules, deleteAllAlerts, getStats } from '../../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const retry = getService('retry'); - const es = getService('es'); - - describe('Detection rule telemetry', async () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - it('should have initialized empty/zero values when no rules are running', async () => { - await retry.try(async () => { - const stats = await getStats(supertest, log); - expect(stats).to.eql(getInitialDetectionMetrics()); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts deleted file mode 100644 index 652d13fd32a5..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import type { - ThreatMatchRuleCreateProps, - ThresholdRuleCreateProps, -} from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; -import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common'; -import { RulesTypeUsage } from '@kbn/security-solution-plugin/server/usage/detections/rules/types'; -import type { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - createLegacyRuleAction, - createNewAction, - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getEqlRuleForSignalTesting, - getRule, - getRuleForSignalTesting, - getRuleWithWebHookAction, - getSimpleMlRule, - getSimpleRule, - getSimpleThreatMatch, - getStats, - getThresholdRuleForSignalTesting, - installMockPrebuiltRules, - waitForRuleSuccess, - waitForSignalsToBePresent, - updateRule, - deleteAllEventLogExecutionEvents, - getRuleSavedObjectWithLegacyInvestigationFields, - getRuleSavedObjectWithLegacyInvestigationFieldsEmptyArray, - createRuleThroughAlertingEndpoint, -} from '../../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const retry = getService('retry'); - const es = getService('es'); - - describe('Detection rule telemetry', async () => { - before(async () => { - // Just in case other tests do not clean up the event logs, let us clear them now and here only once. - await deleteAllEventLogExecutionEvents(es, log); - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - await deleteAllEventLogExecutionEvents(es, log); - }); - - describe('"kql" rule type', () => { - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule = getRuleForSignalTesting(['telemetry']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getRuleForSignalTesting(['telemetry']); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - notifications_disabled: 1, - disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - notifications_disabled: 1, - disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule = getRuleForSignalTesting(['telemetry']); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); - const { id } = await createRule(supertest, log, ruleToCreate); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - disabled: 1, - legacy_notifications_disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - legacy_notifications_disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule = getRuleForSignalTesting(['telemetry']); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - describe('legacy investigation fields', () => { - beforeEach(async () => { - await deleteAllRules(supertest, log); - await createRuleThroughAlertingEndpoint( - supertest, - getRuleSavedObjectWithLegacyInvestigationFields() - ); - await createRuleThroughAlertingEndpoint( - supertest, - getRuleSavedObjectWithLegacyInvestigationFieldsEmptyArray() - ); - await createRule(supertest, log, { - ...getSimpleRule('rule-with-investigation-field'), - name: 'Test investigation fields object', - investigation_fields: { field_names: ['host.name'] }, - }); - }); - - afterEach(async () => { - await deleteAllRules(supertest, log); - }); - - it('should show "legacy_investigation_fields" to be greater than 0 when a rule has "investigation_fields" set to array or empty array', async () => { - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - alerts: 0, - enabled: 0, - disabled: 3, - legacy_investigation_fields: 2, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - alerts: 0, - enabled: 0, - disabled: 3, - legacy_investigation_fields: 2, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - }); - }); - - describe('"eql" rule type', () => { - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry']); - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry']); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - notifications_disabled: 1, - disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - notifications_disabled: 1, - disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry']); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); - const { id } = await createRule(supertest, log, ruleToCreate); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - disabled: 1, - legacy_notifications_disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - legacy_notifications_disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule = getEqlRuleForSignalTesting(['telemetry']); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - }); - - describe('"threshold" rule type', () => { - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), - threshold: { - field: 'keyword', - value: 1, - }, - }; - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry']), - threshold: { - field: 'keyword', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), - threshold: { - field: 'keyword', - value: 1, - }, - }; - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - notifications_disabled: 1, - disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - notifications_disabled: 1, - disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry']), - threshold: { - field: 'keyword', - value: 1, - }, - }; - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); - const { id } = await createRule(supertest, log, ruleToCreate); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), - threshold: { - field: 'keyword', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - disabled: 1, - legacy_notifications_disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - legacy_notifications_disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry']), - threshold: { - field: 'keyword', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - }); - - // Note: We don't actually find signals with these tests as we don't have a good way of signal finding with ML rules. - describe('"ml" rule type', () => { - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule = getSimpleMlRule(); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule = getSimpleMlRule('rule-1', true); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - enabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getSimpleMlRule(); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - notifications_disabled: 1, - disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - notifications_disabled: 1, - disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule = getSimpleMlRule('rule-1', true); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - enabled: 1, - notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getSimpleMlRule(); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - disabled: 1, - legacy_notifications_disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - legacy_notifications_disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule = getSimpleMlRule('rule-1', true); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, - enabled: 1, - legacy_notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - legacy_notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - }); - - describe('"indicator_match/threat_match" rule type', () => { - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { - const rule = getSimpleThreatMatch(); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { - const rule: ThreatMatchRuleCreateProps = { - ...getSimpleThreatMatch('rule-1', true), - index: ['telemetry'], - threat_index: ['telemetry'], - threat_mapping: [ - { - entries: [ - { - field: 'keyword', - value: 'keyword', - type: 'mapping', - }, - ], - }, - ], - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_notifications_disabled: 0, - legacy_notifications_enabled: 0, - legacy_investigation_fields: 0, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getSimpleThreatMatch(); - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); - await createRule(supertest, log, ruleToCreate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - notifications_disabled: 1, - disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - notifications_disabled: 1, - disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThreatMatchRuleCreateProps = { - ...getSimpleThreatMatch('rule-1', true), - index: ['telemetry'], - threat_index: ['telemetry'], - threat_mapping: [ - { - entries: [ - { - field: 'keyword', - value: 'keyword', - type: 'mapping', - }, - ], - }, - ], - }; - const hookAction = await createNewAction(supertest, log); - const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); - const { id } = await createRule(supertest, log, ruleToCreate); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - enabled: 1, - alerts: 4, - notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { - const rule = getSimpleThreatMatch(); - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - disabled: 1, - legacy_notifications_disabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, - legacy_notifications_disabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { - const rule: ThreatMatchRuleCreateProps = { - ...getSimpleThreatMatch('rule-1', true), - index: ['telemetry'], - threat_index: ['telemetry'], - threat_mapping: [ - { - entries: [ - { - field: 'keyword', - value: 'keyword', - type: 'mapping', - }, - ], - }, - ], - }; - const { id } = await createRule(supertest, log, rule); - const hookAction = await createNewAction(supertest, log); - await createLegacyRuleAction(supertest, id, hookAction.id); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: RulesTypeUsage = { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - alerts: 4, - enabled: 1, - legacy_notifications_enabled: 1, - }, - }; - expect(stats.detection_rules.detection_rule_usage).to.eql(expected); - }); - }); - }); - - describe('"pre-packaged"/"immutable" rules', async () => { - it('should show stats for totals for in-active pre-packaged rules', async () => { - await installMockPrebuiltRules(supertest, es); - await retry.try(async () => { - const stats = await getStats(supertest, log); - expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0); - expect(stats.detection_rules.detection_rule_usage.elastic_total.disabled).above(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled - ).to.eql(0); - expect(stats.detection_rules.detection_rule_detail.length).above(0); - expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql({ - enabled: 0, - disabled: 0, - alerts: 0, - cases: 0, - legacy_notifications_enabled: 0, - legacy_notifications_disabled: 0, - notifications_enabled: 0, - notifications_disabled: 0, - legacy_investigation_fields: 0, - }); - }); - }); - - it('should show stats for the detection_rule_details for a specific pre-packaged rule', async () => { - await installMockPrebuiltRules(supertest, es); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const foundRule = stats.detection_rules.detection_rule_detail.find( - (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID - ); - if (foundRule == null) { - throw new Error('Found rule should not be null. Please change this end to end test.'); - } - const { - created_on: createdOn, - updated_on: updatedOn, - rule_id: ruleId, - rule_version: ruleVersion, - ...omittedFields - } = foundRule; - expect(omittedFields).to.eql({ - rule_name: 'A rule with an exception list', - rule_type: 'query', - enabled: true, - elastic_rule: true, - alert_count_daily: 0, - cases_count_total: 0, - has_legacy_notification: false, - has_notification: false, - has_legacy_investigation_field: false, - }); - }); - }); - - it('should show "notifications_disabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - await installMockPrebuiltRules(supertest, es); - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - const hookAction = await createNewAction(supertest, log); - const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); - const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, false, newRuleToUpdate); - await updateRule(supertest, log, ruleToUpdate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id - const foundRule = stats.detection_rules.detection_rule_detail.find( - (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID - ); - if (foundRule == null) { - throw new Error('Found rule should not be null. Please change this end to end test.'); - } - const { - created_on: createdOn, - updated_on: updatedOn, - rule_id: ruleId, - rule_version: ruleVersion, - ...omittedFields - } = foundRule; - expect(omittedFields).to.eql({ - rule_name: 'Simple Rule Query', - rule_type: 'query', - enabled: false, - elastic_rule: true, - alert_count_daily: 0, - cases_count_total: 0, - has_notification: true, - has_legacy_notification: false, - has_legacy_investigation_field: false, - }); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled - ).to.eql(1); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled - ).to.eql(0); - expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( - getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total - ); - }); - }); - - it('should show "notifications_enabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - await installMockPrebuiltRules(supertest, es); - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - const hookAction = await createNewAction(supertest, log); - const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); - const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, true, newRuleToUpdate); - await updateRule(supertest, log, ruleToUpdate); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id - const foundRule = stats.detection_rules.detection_rule_detail.find( - (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID - ); - if (foundRule == null) { - throw new Error('Found rule should not be null. Please change this end to end test.'); - } - const { - created_on: createdOn, - updated_on: updatedOn, - rule_id: ruleId, - rule_version: ruleVersion, - ...omittedFields - } = foundRule; - expect(omittedFields).to.eql({ - rule_name: 'Simple Rule Query', - rule_type: 'query', - enabled: true, - elastic_rule: true, - alert_count_daily: 0, - cases_count_total: 0, - has_notification: true, - has_legacy_notification: false, - has_legacy_investigation_field: false, - }); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled - ).to.eql(1); - expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( - getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total - ); - }); - }); - - it('should show "legacy_notifications_disabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { - await installMockPrebuiltRules(supertest, es); - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - const hookAction = await createNewAction(supertest, log); - const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, false); - await updateRule(supertest, log, newRuleToUpdate); - await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id - const foundRule = stats.detection_rules.detection_rule_detail.find( - (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID - ); - if (foundRule == null) { - throw new Error('Found rule should not be null. Please change this end to end test.'); - } - const { - created_on: createdOn, - updated_on: updatedOn, - rule_id: ruleId, - rule_version: ruleVersion, - ...omittedFields - } = foundRule; - expect(omittedFields).to.eql({ - rule_name: 'Simple Rule Query', - rule_type: 'query', - enabled: false, - elastic_rule: true, - alert_count_daily: 0, - cases_count_total: 0, - has_notification: false, - has_legacy_notification: true, - has_legacy_investigation_field: false, - }); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled - ).to.eql(1); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled - ).to.eql(0); - expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( - getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total - ); - }); - }); - - it('should show "legacy_notifications_enabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { - await installMockPrebuiltRules(supertest, es); - const immutableRule = await getRule(supertest, log, ELASTIC_SECURITY_RULE_ID); - const hookAction = await createNewAction(supertest, log); - const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, true); - await updateRule(supertest, log, newRuleToUpdate); - await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id - const foundRule = stats.detection_rules.detection_rule_detail.find( - (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID - ); - if (foundRule == null) { - throw new Error('Found rule should not be null. Please change this end to end test.'); - } - const { - created_on: createdOn, - updated_on: updatedOn, - rule_id: ruleId, - rule_version: ruleVersion, - ...omittedFields - } = foundRule; - expect(omittedFields).to.eql({ - rule_name: 'Simple Rule Query', - rule_type: 'query', - enabled: true, - elastic_rule: true, - alert_count_daily: 0, - cases_count_total: 0, - has_notification: false, - has_legacy_notification: true, - has_legacy_investigation_field: false, - }); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled - ).to.eql(1); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled - ).to.eql(0); - expect( - stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled - ).to.eql(0); - expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( - getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total - ); - }); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/config.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/config.ts deleted file mode 100644 index 2430b8f2148d..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/config.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrConfigProviderContext } from '@kbn/test'; - -// eslint-disable-next-line import/no-default-export -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../config.base.ts')); - - return { - ...functionalConfig.getAll(), - testFiles: [require.resolve('.')], - }; -} diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/index.ts deleted file mode 100644 index ac107392d4b5..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('detection engine api security and spaces enabled - Group 5', function () { - loadTestFile(require.resolve('./keyword_family')); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts deleted file mode 100644 index 44c25e51ba11..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/const_keyword.ts +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { - EqlRuleCreateProps, - ThresholdRuleCreateProps, -} from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; - -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getEqlRuleForSignalTesting, - getRuleForSignalTesting, - getSignalsById, - getThresholdRuleForSignalTesting, - waitForRuleSuccess, - waitForSignalsToBePresent, -} from '../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - describe('Rule detects against a keyword of event.dataset', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/const_keyword'); - }); - - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/rule_keyword_family/const_keyword' - ); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - describe('"kql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset" and have 4 signals', async () => { - const rule = { - ...getRuleForSignalTesting(['const_keyword']), - query: 'event.dataset: "dataset_name_1"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - expect(signalsOpen.hits.hits.length).to.eql(4); - }); - - it('should copy the dataset_name_1 from the index into the signal', async () => { - const rule = { - ...getRuleForSignalTesting(['const_keyword']), - query: 'event.dataset: "dataset_name_1"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"eql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset" and have 4 signals', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['const_keyword']), - query: 'any where event.dataset=="dataset_name_1"', - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - expect(signalsOpen.hits.hits.length).to.eql(4); - }); - - it('should copy the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['const_keyword']), - query: 'any where event.dataset=="dataset_name_1"', - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"threshold" rule type', async () => { - it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['const_keyword']), - threshold: { - field: 'event.dataset', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) - .sort(); - expect(hits).to.eql([ - { - count: 4, - from: '2020-10-27T05:00:53.000Z', - terms: [ - { - field: 'event.dataset', - value: 'dataset_name_1', - }, - ], - }, - ]); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/index.ts deleted file mode 100644 index 1ecb06fbed4e..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('Detection keyword family data types', function () { - loadTestFile(require.resolve('./keyword')); - loadTestFile(require.resolve('./const_keyword')); - loadTestFile(require.resolve('./keyword_mixed_with_const')); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts deleted file mode 100644 index 39d62da77a1a..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword.ts +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { - EqlRuleCreateProps, - QueryRuleCreateProps, - ThresholdRuleCreateProps, -} from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getEqlRuleForSignalTesting, - getRuleForSignalTesting, - getSignalsById, - getThresholdRuleForSignalTesting, - waitForRuleSuccess, - waitForSignalsToBePresent, -} from '../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - describe('Rule detects against a keyword of event.dataset', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - describe('"kql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['keyword']), - query: 'event.dataset: "dataset_name_1"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"eql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['keyword']), - query: 'any where event.dataset=="dataset_name_1"', - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"threshold" rule type', async () => { - it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['keyword']), - threshold: { - field: 'event.dataset', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) - .sort(); - expect(hits).to.eql([ - { - count: 4, - from: '2020-10-28T05:00:53.000Z', - terms: [ - { - field: 'event.dataset', - value: 'dataset_name_1', - }, - ], - }, - ]); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts deleted file mode 100644 index 50bbd7efde9f..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/keyword_mixed_with_const.ts +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { - EqlRuleCreateProps, - ThresholdRuleCreateProps, -} from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; - -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllRules, - deleteAllAlerts, - getEqlRuleForSignalTesting, - getRuleForSignalTesting, - getSignalsById, - waitForRuleSuccess, - waitForSignalsToBePresent, -} from '../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const log = getService('log'); - const es = getService('es'); - - describe('Rule detects against a keyword and constant_keyword of event.dataset', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/const_keyword'); - await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); - }); - - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/rule_keyword_family/const_keyword' - ); - await esArchiver.unload('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); - }); - - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - describe('"kql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset" and have 8 signals, 4 from each index', async () => { - const rule = { - ...getRuleForSignalTesting(['keyword', 'const_keyword']), - query: 'event.dataset: "dataset_name_1"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 8, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - expect(signalsOpen.hits.hits.length).to.eql(8); - }); - - it('should copy the dataset_name_1 from the index into the signal', async () => { - const rule = { - ...getRuleForSignalTesting(['keyword', 'const_keyword']), - query: 'event.dataset: "dataset_name_1"', - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 8, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"eql" rule type', () => { - it('should detect the "dataset_name_1" from "event.dataset" and have 8 signals, 4 from each index', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['keyword', 'const_keyword']), - query: 'any where event.dataset=="dataset_name_1"', - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 8, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - expect(signalsOpen.hits.hits.length).to.eql(8); - }); - - it('should copy the "dataset_name_1" from "event.dataset"', async () => { - const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['keyword', 'const_keyword']), - query: 'any where event.dataset=="dataset_name_1"', - }; - - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 8, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); - expect(hits).to.eql([ - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - 'dataset_name_1', - ]); - }); - }); - - describe('"threshold" rule type', async () => { - it('should detect the "dataset_name_1" from "event.dataset"', async () => { - const rule: ThresholdRuleCreateProps = { - ...getRuleForSignalTesting(['keyword', 'const_keyword']), - rule_id: 'threshold-rule', - type: 'threshold', - language: 'kuery', - query: '*:*', - threshold: { - field: 'event.dataset', - value: 1, - }, - }; - const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 1, [id]); - const signalsOpen = await getSignalsById(supertest, log, id); - const hits = signalsOpen.hits.hits - .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) - .sort(); - expect(hits).to.eql([ - { - count: 8, - from: '2020-10-27T05:00:53.000Z', - terms: [ - { - field: 'event.dataset', - value: 'dataset_name_1', - }, - ], - }, - ]); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/config.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/config.ts deleted file mode 100644 index 2430b8f2148d..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/config.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrConfigProviderContext } from '@kbn/test'; - -// eslint-disable-next-line import/no-default-export -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../config.base.ts')); - - return { - ...functionalConfig.getAll(), - testFiles: [require.resolve('.')], - }; -} diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/index.ts deleted file mode 100644 index e6cb1328c29b..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('detection engine api security and spaces enabled - rule execution logic', function () { - loadTestFile(require.resolve('./eql')); - loadTestFile(require.resolve('./esql')); - loadTestFile(require.resolve('./machine_learning')); - loadTestFile(require.resolve('./new_terms')); - loadTestFile(require.resolve('./saved_query')); - loadTestFile(require.resolve('./threat_match')); - loadTestFile(require.resolve('./threshold')); - loadTestFile(require.resolve('./non_ecs_fields')); - - loadTestFile(require.resolve('./query')); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/mocks/new_terms.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/mocks/new_terms.ts deleted file mode 100644 index 15c63546a4be..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/mocks/new_terms.ts +++ /dev/null @@ -1,1409 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const largeArraysBuckets = [ - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-0', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-1', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-2', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-3', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-4', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-5', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-6', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-7', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-8', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-0', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-1', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-2', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-3', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-4', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-5', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-6', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-7', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-8', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-9', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-10', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-11', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-12', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-13', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-14', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-15', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-16', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-17', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-18', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, - { - key: { - large_array_20: 'value-of-20-19', - large_array_10: 'value-of-10-9', - }, - doc_count: 1, - }, -]; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/new_terms.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/new_terms.ts deleted file mode 100644 index 144d5e9bf51b..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/new_terms.ts +++ /dev/null @@ -1,1039 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { v4 as uuidv4 } from 'uuid'; - -import { NewTermsRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { orderBy } from 'lodash'; -import { getCreateNewTermsRulesSchemaMock } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema/mocks'; - -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; -import { - createRule, - deleteAllRules, - deleteAllAlerts, - getOpenSignals, - getPreviewAlerts, - previewRule, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { previewRuleWithExceptionEntries } from '../../utils/preview_rule_with_exception_entries'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; -import { dataGeneratorFactory } from '../../utils/data_generator'; - -import { removeRandomValuedProperties } from './utils'; - -const historicalWindowStart = '2022-10-13T05:00:04.000Z'; -const ruleExecutionStart = '2022-10-19T05:00:04.000Z'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); - const log = getService('log'); - const { indexEnhancedDocuments } = dataGeneratorFactory({ - es, - index: 'new_terms', - log, - }); - - /** - * indexes 2 sets of documents: - * - documents in historical window - * - documents in rule execution window - * @returns id of documents - */ - const newTermsTestExecutionSetup = async ({ - historicalDocuments, - ruleExecutionDocuments, - }: { - historicalDocuments: Array>; - ruleExecutionDocuments: Array>; - }) => { - const testId = uuidv4(); - - await indexEnhancedDocuments({ - interval: [historicalWindowStart, ruleExecutionStart], - id: testId, - documents: historicalDocuments, - }); - - await indexEnhancedDocuments({ - id: testId, - documents: ruleExecutionDocuments, - }); - - return testId; - }; - - describe('New terms type rules', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/new_terms'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/new_terms'); - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - // First test creates a real rule - remaining tests use preview API - - // This test also tests that alerts are NOT created for terms that are not new: the host name - // suricata-sensor-san-francisco appears in a document at 2019-02-19T20:42:08.230Z, but also appears - // in earlier documents so is not new. An alert should not be generated for that term. - it('should generate 1 alert with 1 selected field', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.name'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', - }; - - const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); - - expect(alerts.hits.hits.length).eql(1); - expect(removeRandomValuedProperties(alerts.hits.hits[0]._source)).eql({ - 'kibana.alert.new_terms': ['zeek-newyork-sha-aa8df15'], - 'kibana.alert.rule.category': 'New Terms Rule', - 'kibana.alert.rule.consumer': 'siem', - 'kibana.alert.rule.name': 'Query with a rule id', - 'kibana.alert.rule.producer': 'siem', - 'kibana.alert.rule.rule_type_id': 'siem.newTermsRule', - 'kibana.space_ids': ['default'], - 'kibana.alert.rule.tags': [], - agent: { - ephemeral_id: '7cc2091a-72f1-4c63-843b-fdeb622f9c69', - hostname: 'zeek-newyork-sha-aa8df15', - id: '4b4462ef-93d2-409c-87a6-299d942e5047', - type: 'auditbeat', - version: '8.0.0', - }, - cloud: { instance: { id: '139865230' }, provider: 'digitalocean', region: 'nyc1' }, - ecs: { version: '1.0.0-beta2' }, - host: { - architecture: 'x86_64', - hostname: 'zeek-newyork-sha-aa8df15', - id: '3729d06ce9964aa98549f41cbd99334d', - ip: ['157.230.208.30', '10.10.0.6', 'fe80::24ce:f7ff:fede:a571'], - mac: ['26:ce:f7:de:a5:71'], - name: 'zeek-newyork-sha-aa8df15', - os: { - codename: 'cosmic', - family: 'debian', - kernel: '4.18.0-10-generic', - name: 'Ubuntu', - platform: 'ubuntu', - version: '18.10 (Cosmic Cuttlefish)', - }, - }, - message: - 'Login by user root (UID: 0) on pts/0 (PID: 20638) from 8.42.77.171 (IP: 8.42.77.171)', - process: { pid: 20638 }, - service: { type: 'system' }, - source: { ip: '8.42.77.171' }, - user: { id: 0, name: 'root', terminal: 'pts/0' }, - 'event.action': 'user_login', - 'event.category': 'authentication', - 'event.dataset': 'login', - 'event.kind': 'signal', - 'event.module': 'system', - 'event.origin': '/var/log/wtmp', - 'event.outcome': 'success', - 'event.type': 'authentication_success', - 'kibana.alert.original_time': '2019-02-19T20:42:08.230Z', - 'kibana.alert.ancestors': [ - { - id: 'x07wJ2oB9v5HJNSHhyxi', - type: 'event', - index: 'auditbeat-8.0.0-2019.02.19-000001', - depth: 0, - }, - ], - 'kibana.alert.status': 'active', - 'kibana.alert.workflow_status': 'open', - 'kibana.alert.workflow_tags': [], - 'kibana.alert.depth': 1, - 'kibana.alert.reason': - 'authentication event with source 8.42.77.171 by root on zeek-newyork-sha-aa8df15 created high alert Query with a rule id.', - 'kibana.alert.severity': 'high', - 'kibana.alert.risk_score': 55, - 'kibana.alert.rule.parameters': { - description: 'Detecting root and admin users', - risk_score: 55, - severity: 'high', - author: [], - false_positives: [], - from: '2019-02-19T20:42:00.000Z', - rule_id: 'rule-1', - max_signals: 100, - risk_score_mapping: [], - severity_mapping: [], - threat: [], - to: 'now', - references: [], - version: 1, - exceptions_list: [], - immutable: false, - related_integrations: [], - required_fields: [], - setup: '', - type: 'new_terms', - query: '*', - new_terms_fields: ['host.name'], - history_window_start: '2019-01-19T20:42:00.000Z', - index: ['auditbeat-*'], - language: 'kuery', - }, - 'kibana.alert.rule.actions': [], - 'kibana.alert.rule.author': [], - 'kibana.alert.rule.created_by': 'elastic', - 'kibana.alert.rule.description': 'Detecting root and admin users', - 'kibana.alert.rule.enabled': true, - 'kibana.alert.rule.exceptions_list': [], - 'kibana.alert.rule.false_positives': [], - 'kibana.alert.rule.from': '2019-02-19T20:42:00.000Z', - 'kibana.alert.rule.immutable': false, - 'kibana.alert.rule.indices': ['auditbeat-*'], - 'kibana.alert.rule.interval': '5m', - 'kibana.alert.rule.max_signals': 100, - 'kibana.alert.rule.references': [], - 'kibana.alert.rule.revision': 0, - 'kibana.alert.rule.risk_score_mapping': [], - 'kibana.alert.rule.rule_id': 'rule-1', - 'kibana.alert.rule.severity_mapping': [], - 'kibana.alert.rule.threat': [], - 'kibana.alert.rule.to': 'now', - 'kibana.alert.rule.type': 'new_terms', - 'kibana.alert.rule.updated_by': 'elastic', - 'kibana.alert.rule.version': 1, - 'kibana.alert.rule.risk_score': 55, - 'kibana.alert.rule.severity': 'high', - 'kibana.alert.original_event.action': 'user_login', - 'kibana.alert.original_event.category': 'authentication', - 'kibana.alert.original_event.dataset': 'login', - 'kibana.alert.original_event.kind': 'event', - 'kibana.alert.original_event.module': 'system', - 'kibana.alert.original_event.origin': '/var/log/wtmp', - 'kibana.alert.original_event.outcome': 'success', - 'kibana.alert.original_event.type': 'authentication_success', - }); - }); - - it('generates max signals warning when circuit breaker is exceeded', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['process.pid'], - from: '2018-02-19T20:42:00.000Z', - // Set the history_window_start close to 'from' so we should alert on all terms in the time range - history_window_start: '2018-02-19T20:41:59.000Z', - }; - const { logs } = await previewRule({ supertest, rule }); - - expect(logs[0].warnings).contain(getMaxSignalsWarning()); - }); - - it("doesn't generate max signals warning when circuit breaker is met but not exceeded", async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.ip'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', - max_signals: 3, - }; - const { logs } = await previewRule({ supertest, rule }); - - expect(logs[0].warnings).not.contain(getMaxSignalsWarning()); - }); - - it('should generate 3 alerts when 1 document has 3 new values', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.ip'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(3); - const previewAlertsOrderedByHostIp = orderBy( - previewAlerts, - '_source.kibana.alert.new_terms', - 'asc' - ); - expect(previewAlertsOrderedByHostIp[0]._source?.['kibana.alert.new_terms']).eql([ - '10.10.0.6', - ]); - expect(previewAlertsOrderedByHostIp[1]._source?.['kibana.alert.new_terms']).eql([ - '157.230.208.30', - ]); - expect(previewAlertsOrderedByHostIp[2]._source?.['kibana.alert.new_terms']).eql([ - 'fe80::24ce:f7ff:fede:a571', - ]); - }); - - it('should generate 3 alerts when 1 document has 3 new values for multiple fields', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.name', 'host.ip'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(3); - - const newTerms = orderBy( - previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), - ['0', '1'] - ); - - expect(newTerms).eql([ - ['zeek-newyork-sha-aa8df15', '10.10.0.6'], - ['zeek-newyork-sha-aa8df15', '157.230.208.30'], - ['zeek-newyork-sha-aa8df15', 'fe80::24ce:f7ff:fede:a571'], - ]); - }); - - it('should generate 1 alert for unique combination of existing terms', async () => { - // historical window documents - const historicalDocuments = [ - { - host: { name: 'host-0', ip: '127.0.0.1' }, - }, - { - host: { name: 'host-1', ip: '127.0.0.2' }, - }, - ]; - - // rule execution documents - const ruleExecutionDocuments = [ - { - host: { name: 'host-0', ip: '127.0.0.2' }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - // ensure there are no alerts for single new terms fields, it means values are not new - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.ip'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - // shouldn't be terms for 'host.ip' - const hostIpPreview = await previewRule({ - supertest, - rule: { ...rule, new_terms_fields: ['host.ip'] }, - }); - const hostIpPreviewAlerts = await getPreviewAlerts({ - es, - previewId: hostIpPreview.previewId, - }); - expect(hostIpPreviewAlerts.length).eql(0); - - // shouldn't be terms for 'host.name' - const hostNamePreview = await previewRule({ - supertest, - rule: { ...rule, new_terms_fields: ['host.name'] }, - }); - const hostNamePreviewAlerts = await getPreviewAlerts({ - es, - previewId: hostNamePreview.previewId, - }); - expect(hostNamePreviewAlerts.length).eql(0); - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(1); - - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); - }); - - it('should generate 5 alerts, 1 for each new unique combination in 2 fields', async () => { - const historicalDocuments = [ - { - 'source.ip': ['192.168.1.1'], - tags: ['tag-1', 'tag-2'], - }, - { - 'source.ip': ['192.168.1.1'], - tags: ['tag-1'], - }, - ]; - - const ruleExecutionDocuments = [ - { - 'source.ip': ['192.168.1.1', '192.168.1.2'], - tags: ['tag-new-1', 'tag-2', 'tag-new-3'], - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['source.ip', 'tags'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(5); - - const newTerms = orderBy( - previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), - ['0', '1'] - ); - - expect(newTerms).eql([ - ['192.168.1.1', 'tag-new-1'], - ['192.168.1.1', 'tag-new-3'], - ['192.168.1.2', 'tag-2'], - ['192.168.1.2', 'tag-new-1'], - ['192.168.1.2', 'tag-new-3'], - ]); - }); - - it('should generate 1 alert for unique combination of terms, one of which is a number', async () => { - const historicalDocuments = [ - { user: { name: 'user-0', id: 0 } }, - { user: { name: 'user-1', id: 1 } }, - ]; - const ruleExecutionDocuments = [{ user: { name: 'user-0', id: 1 } }]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['user.name', 'user.id'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', '1']); - }); - - it('should generate 1 alert for unique combination of terms, one of which is a boolean', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['user.name', 'user.enabled'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', false]); - }); - - it('should generate alerts for every term when history window is small', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.name'], - from: '2019-02-19T20:42:00.000Z', - // Set the history_window_start close to 'from' so we should alert on all terms in the time range - history_window_start: '2019-02-19T20:41:59.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(5); - const hostNames = previewAlerts - .map((signal) => signal._source?.['kibana.alert.new_terms']) - .sort(); - expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); - expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); - expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); - expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); - expect(hostNames[4]).eql(['zeek-sensor-san-francisco']); - }); - - // github.com/elastic/kibana/issues/149920 - it('should generate 1 alert for new terms if query has wildcard in field path', async () => { - // historical window documents - const historicalDocuments = [ - { - host: { name: 'host-0', ip: '127.0.0.1' }, - }, - { - host: { name: 'host-1', ip: '127.0.0.2' }, - }, - ]; - - // rule execution documents - const ruleExecutionDocuments = [ - { - host: { name: 'host-0', ip: '127.0.0.2' }, - }, - { - host: { name: 'host-1', ip: '127.0.0.1' }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.ip'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}" and host.n*: host-0`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(1); - - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); - }); - describe('null values', () => { - it('should not generate alerts with null values for single field', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['possibly_null_field'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(0); - }); - - it('should not generate alerts with null values for multiple fields', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['possibly_null_field', 'host.name'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(0); - }); - }); - - describe('large arrays values', () => { - it('should generate alerts for unique values in large array for single field from a single document', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['large_array_20'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 100 }); - - expect(previewAlerts.length).eql(20); - }); - - // There is a limit in ES for a number of emitted values in runtime field (100) - // This test ensures rule run doesn't fail if processed fields in runtime script generates 100 values, hard limit for ES - // For this test case: large_array_10 & large_array_5 have 100 unique combination in total - it('should generate alerts for array fields that have 100 unique combination of values in runtime field', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['large_array_10', 'large_array_5'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - expect(previewAlerts.length).eql(100); - }); - - // There is a limit in ES for a number of emitted values in runtime field (100) - // This test ensures rule run doesn't fail if processed fields in runtime script generates 200 values - // In case of this test case: large_array_10 & large_array_20 have 200 unique combination in total - // Rule run should not fail and should generate alerts - it('should generate alert for array fields that have more than 200 unique combination of values in runtime field', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['large_array_10', 'large_array_20'], - from: '2020-10-19T05:00:04.000Z', - history_window_start: '2020-10-13T05:00:04.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - expect(previewAlerts.length).eql(100); - }); - - it('should not miss alerts if rule execution value combinations number is greater than 100', async () => { - // historical window documents - // 100 combinations for 127.0.0.1 x host-0, host-1, ..., host-100 - const historicalDocuments = [ - { - host: { - name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - ip: ['127.0.0.1'], - }, - }, - ]; - - // rule execution documents - // 100 old combinations for 127.0.0.1 x host-0, host-1, ..., host-99 - // 10 new combinations 127.0.0.1 x a-0, a-1, ..., a-9 - const ruleExecutionDocuments = [ - { - host: { - name: [ - ...Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - ...Array.from(Array(10)).map((_, i) => `a-${i}`), - ], - ip: ['127.0.0.1'], - }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.ip'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - // 10 alerts (with host.names a-[0-9]) should be generated - expect(previewAlerts.length).eql(10); - }); - - it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size', async () => { - // historical window documents - // number of combinations is 50,000 - const historicalDocuments = [ - { - host: { - name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - user: { - name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), - }, - }, - ]; - - // rule execution documents - // number of combinations is 50,000 + new one - const ruleExecutionDocuments = [ - { - host: { - name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - user: { - name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), - }, - }, - { - host: { - name: 'host-140', - domain: 'domain-9999', - }, - user: { - name: 'user-9999', - }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.domain', 'user.name'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - // only 1 alert should be generated - expect(previewAlerts.length).eql(1); - }); - - it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size spread over multiple pages', async () => { - // historical window documents - // number of combinations is 50,000 - const historicalDocuments = [ - { - host: { - name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - user: { - name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), - }, - }, - ]; - - // rule execution documents - // number of combinations is 50,000 + 4 new ones - const ruleExecutionDocuments = [ - { - host: { - name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - user: { - name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), - }, - }, - { - host: { - name: 'host-102', - domain: 'domain-9999', - }, - user: { - name: 'user-9999', - }, - }, - { - host: { - name: 'host-140', - domain: 'domain-9999', - }, - user: { - name: 'user-9999', - }, - }, - { - host: { - name: 'host-133', - domain: 'domain-9999', - }, - user: { - name: 'user-9999', - }, - }, - { - host: { - name: 'host-132', - domain: 'domain-9999', - }, - user: { - name: 'user-9999', - }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.domain', 'user.name'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - // only 4 alerts should be generated - expect(previewAlerts.length).eql(4); - }); - - it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have more than 100', async () => { - // historical window documents - // number of combinations 400: [a, b] x domain-100, domain-101, ..., domain-299 - const historicalDocuments = [ - { - host: { - name: ['a', 'b'], - domain: Array.from(Array(200)).map((_, i) => `domain-${100 + i}`), - }, - }, - ]; - - // rule execution documents - // number of combinations 101: [a] x domain-100, domain-101, ..., domain-199 + b x domain-201 - // no new combination of values emitted - const ruleExecutionDocuments = [ - { - host: { - name: 'a', - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - }, - { - host: { - name: 'b', - domain: 'domain-201', - }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.domain'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - expect(previewAlerts.length).eql(0); - }); - - it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have precisely 100', async () => { - // historical window documents - // number of combinations 400: [a, b] x domain-100, domain-101, ..., domain-299 - const historicalDocuments = [ - { - host: { - name: ['a', 'b'], - domain: Array.from(Array(200)).map((_, i) => `domain-${100 + i}`), - }, - }, - ]; - - // rule execution documents - // number of combinations 100: [a] x domain-100, domain-101, ..., domain-199 - // no new combination of values emitted - const ruleExecutionDocuments = [ - { - host: { - name: 'a', - domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), - }, - }, - ]; - - const testId = await newTermsTestExecutionSetup({ - historicalDocuments, - ruleExecutionDocuments, - }); - - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - index: ['new_terms'], - new_terms_fields: ['host.name', 'host.domain'], - from: ruleExecutionStart, - history_window_start: historicalWindowStart, - query: `id: "${testId}"`, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - - expect(previewAlerts.length).eql(0); - }); - }); - - describe('timestamp override and fallback', () => { - before(async () => { - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' - ); - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' - ); - }); - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' - ); - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' - ); - }); - - it('should generate the correct alerts', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - // myfakeindex-3 does not have event.ingested mapped so we can test if the runtime field - // 'kibana.combined_timestamp' handles unmapped fields properly - index: ['timestamp-fallback-test', 'myfakeindex-3'], - new_terms_fields: ['host.name'], - from: '2020-12-16T16:00:00.000Z', - // Set the history_window_start close to 'from' so we should alert on all terms in the time range - history_window_start: '2020-12-16T15:59:00.000Z', - timestamp_override: 'event.ingested', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(2); - const hostNames = previewAlerts - .map((signal) => signal._source?.['kibana.alert.new_terms']) - .sort(); - expect(hostNames[0]).eql(['host-3']); - expect(hostNames[1]).eql(['host-4']); - }); - }); - - describe('with exceptions', async () => { - afterEach(async () => { - await deleteAllExceptions(supertest, log); - }); - - it('should apply exceptions', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.name'], - from: '2019-02-19T20:42:00.000Z', - // Set the history_window_start close to 'from' so we should alert on all terms in the time range - history_window_start: '2019-02-19T20:41:59.000Z', - }; - - const { previewId } = await previewRuleWithExceptionEntries({ - supertest, - log, - rule, - entries: [ - [ - { - field: 'host.name', - operator: 'included', - type: 'match', - value: 'zeek-sensor-san-francisco', - }, - ], - ], - }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts.length).eql(4); - const hostNames = previewAlerts - .map((signal) => signal._source?.['kibana.alert.new_terms']) - .sort(); - expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); - expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); - expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); - expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); - }); - }); - - it('should work for max signals > 100', async () => { - const maxSignals = 200; - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['process.pid'], - from: '2018-02-19T20:42:00.000Z', - // Set the history_window_start close to 'from' so we should alert on all terms in the time range - history_window_start: '2018-02-19T20:41:59.000Z', - max_signals: maxSignals, - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxSignals * 2 }); - - expect(previewAlerts.length).eql(maxSignals); - const processPids = previewAlerts - .map((signal) => signal._source?.['kibana.alert.new_terms']) - .sort(); - expect(processPids[0]).eql([1]); - }); - - describe('alerts should be be enriched', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/entity/risks'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/entity/risks'); - }); - - it('should be enriched with host risk score', async () => { - const rule: NewTermsRuleCreateProps = { - ...getCreateNewTermsRulesSchemaMock('rule-1', true), - new_terms_fields: ['host.name'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', - }; - - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - - expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).to.eql('Low'); - expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).to.eql(23); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/saved_query.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/saved_query.ts deleted file mode 100644 index ed7173133f9f..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/saved_query.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; -import { flattenWithPrefix } from '@kbn/securitysolution-rules'; - -import { SavedQueryRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { - ALERT_ANCESTORS, - ALERT_DEPTH, - ALERT_ORIGINAL_TIME, - ALERT_ORIGINAL_EVENT, -} from '@kbn/security-solution-plugin/common/field_maps/field_names'; -import { - createRule, - deleteAllRules, - deleteAllAlerts, - getOpenSignals, - getRuleForSignalTesting, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -/** - * Specific _id to use for some of the tests. If the archiver changes and you see errors - * here, update this to a new value of a chosen auditbeat record and update the tests values. - */ -const ID = 'BhbXBmkBR346wHgn4PeZ'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); - const log = getService('log'); - - describe('Saved query type rules', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); - - // First test creates a real rule - remaining tests use preview API - it('should query and get back expected signal structure using a saved query rule', async () => { - const rule: SavedQueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), - type: 'saved_query', - query: `_id:${ID}`, - saved_id: 'doesnt-exist', - }; - const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); - const signal = alerts.hits.hits[0]._source; - expect(signal).eql({ - ...signal, - [ALERT_ANCESTORS]: [ - { - id: 'BhbXBmkBR346wHgn4PeZ', - type: 'event', - index: 'auditbeat-8.0.0-2019.02.19-000001', - depth: 0, - }, - ], - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_DEPTH]: 1, - [ALERT_ORIGINAL_TIME]: '2019-02-19T17:40:03.790Z', - ...flattenWithPrefix(ALERT_ORIGINAL_EVENT, { - action: 'socket_closed', - dataset: 'socket', - kind: 'event', - module: 'system', - }), - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threshold.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threshold.ts deleted file mode 100644 index 36f41da15e1e..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threshold.ts +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { - ALERT_REASON, - ALERT_RULE_UUID, - ALERT_WORKFLOW_STATUS, - EVENT_KIND, -} from '@kbn/rule-data-utils'; - -import { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { Ancestor } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/types'; -import { - ALERT_ANCESTORS, - ALERT_DEPTH, - ALERT_ORIGINAL_TIME, - ALERT_THRESHOLD_RESULT, -} from '@kbn/security-solution-plugin/common/field_maps/field_names'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; -import { - createRule, - getOpenSignals, - getPreviewAlerts, - getThresholdRuleForSignalTesting, - previewRule, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); - const es = getService('es'); - const log = getService('log'); - - describe('Threshold type rules', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - }); - - // First test creates a real rule - remaining tests use preview API - it('generates 1 signal from Threshold rules when threshold is met', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: ['host.id'], - value: 700, - }, - }; - const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); - expect(alerts.hits.hits.length).eql(1); - const fullSignal = alerts.hits.hits[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); - } - const eventIds = (fullSignal?.[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); - expect(fullSignal).eql({ - ...fullSignal, - 'host.id': '8cc95778cce5407c809480e8e32ad76b', - [EVENT_KIND]: 'signal', - [ALERT_ANCESTORS]: [ - { - depth: 0, - id: eventIds[0], - index: 'auditbeat-*', - type: 'event', - }, - ], - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_REASON]: 'event created high alert Signal Testing Query.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], - [ALERT_DEPTH]: 1, - [ALERT_THRESHOLD_RESULT]: { - terms: [ - { - field: 'host.id', - value: '8cc95778cce5407c809480e8e32ad76b', - }, - ], - count: 788, - from: '2019-02-19T07:12:05.332Z', - }, - }); - }); - - it('generates max signals warning when circuit breaker is exceeded', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 1, // This value generates 7 alerts with the current esArchive - }, - max_signals: 5, - }; - const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).contain(getMaxSignalsWarning()); - }); - - it("doesn't generate max signals warning when circuit breaker is met but not exceeded", async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 1, // This value generates 7 alerts with the current esArchive - }, - max_signals: 7, - }; - const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).not.contain(getMaxSignalsWarning()); - }); - - it('generates 2 signals from Threshold rules when threshold is met', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 100, - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(2); - }); - - it('applies the provided query before bucketing ', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - query: 'host.id:"2ab45fc1c41e4c84bbd02202a7e5761f"', - threshold: { - field: 'process.name', - value: 21, - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); - }); - - it('generates no signals from Threshold rules when threshold is met and cardinality is not met', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 100, - cardinality: [ - { - field: 'destination.ip', - value: 100, - }, - ], - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(0); - }); - - it('generates no signals from Threshold rules when cardinality is met and threshold is not met', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 1000, - cardinality: [ - { - field: 'destination.ip', - value: 5, - }, - ], - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(0); - }); - - it('generates signals from Threshold rules when threshold and cardinality are both met', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.id', - value: 100, - cardinality: [ - { - field: 'destination.ip', - value: 5, - }, - ], - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); - const fullSignal = previewAlerts[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); - } - const eventIds = (fullSignal?.[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); - expect(fullSignal).eql({ - ...fullSignal, - 'host.id': '8cc95778cce5407c809480e8e32ad76b', - [EVENT_KIND]: 'signal', - [ALERT_ANCESTORS]: [ - { - depth: 0, - id: eventIds[0], - index: 'auditbeat-*', - type: 'event', - }, - ], - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_REASON]: `event created high alert Signal Testing Query.`, - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], - [ALERT_DEPTH]: 1, - [ALERT_THRESHOLD_RESULT]: { - terms: [ - { - field: 'host.id', - value: '8cc95778cce5407c809480e8e32ad76b', - }, - ], - cardinality: [ - { - field: 'destination.ip', - value: 7, - }, - ], - count: 788, - from: '2019-02-19T07:12:05.332Z', - }, - }); - }); - - it('should not generate signals if only one field meets the threshold requirement', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: ['host.id', 'process.name'], - value: 22, - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(0); - }); - - it('generates signals from Threshold rules when bucketing by multiple fields', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: ['host.id', 'process.name', 'event.module'], - value: 21, - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); - const fullSignal = previewAlerts[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); - } - const eventIds = (fullSignal[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); - expect(fullSignal).eql({ - ...fullSignal, - 'event.module': 'system', - 'host.id': '2ab45fc1c41e4c84bbd02202a7e5761f', - 'process.name': 'sshd', - [EVENT_KIND]: 'signal', - [ALERT_ANCESTORS]: [ - { - depth: 0, - id: eventIds[0], - index: 'auditbeat-*', - type: 'event', - }, - ], - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_REASON]: `event with process sshd, created high alert Signal Testing Query.`, - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], - [ALERT_DEPTH]: 1, - [ALERT_THRESHOLD_RESULT]: { - terms: [ - { - field: 'host.id', - value: '2ab45fc1c41e4c84bbd02202a7e5761f', - }, - { - field: 'process.name', - value: 'sshd', - }, - { - field: 'event.module', - value: 'system', - }, - ], - count: 21, - from: '2019-02-19T20:22:03.561Z', - }, - }); - }); - - // https://github.com/elastic/kibana/issues/149920 - it('generates 1 alert when threshold is met and rule query has wildcard in field name', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - query: 'agent.ty*:auditbeat', // this query should match all documents from index and we will receive 1 alert, similarly to "generates 1 signal from Threshold rules when threshold is met" test case - threshold: { - field: ['host.id'], - value: 700, - }, - }; - const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); - expect(alerts.hits.hits.length).eql(1); - }); - - describe('Timestamp override and fallback', async () => { - before(async () => { - await esArchiver.load( - 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' - ); - }); - - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' - ); - }); - - it('applies timestamp override when using single field', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['timestamp-fallback-test']), - threshold: { - field: 'host.name', - value: 1, - }, - timestamp_override: 'event.ingested', - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(4); - - for (const hit of previewAlerts) { - const originalTime = hit._source?.[ALERT_ORIGINAL_TIME]; - const hostName = hit._source?.['host.name']; - if (hostName === 'host-1') { - expect(originalTime).eql('2020-12-16T15:15:18.570Z'); - } else if (hostName === 'host-2') { - expect(originalTime).eql('2020-12-16T15:16:18.570Z'); - } else if (hostName === 'host-3') { - expect(originalTime).eql('2020-12-16T16:15:18.570Z'); - } else { - expect(originalTime).eql('2020-12-16T16:16:18.570Z'); - } - } - }); - - it('applies timestamp override when using multiple fields', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['timestamp-fallback-test']), - threshold: { - field: ['host.name', 'source.ip'], - value: 1, - }, - timestamp_override: 'event.ingested', - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(4); - - for (const hit of previewAlerts) { - const originalTime = hit._source?.[ALERT_ORIGINAL_TIME]; - const hostName = hit._source?.['host.name']; - if (hostName === 'host-1') { - expect(originalTime).eql('2020-12-16T15:15:18.570Z'); - } else if (hostName === 'host-2') { - expect(originalTime).eql('2020-12-16T15:16:18.570Z'); - } else if (hostName === 'host-3') { - expect(originalTime).eql('2020-12-16T16:15:18.570Z'); - } else { - expect(originalTime).eql('2020-12-16T16:16:18.570Z'); - } - } - }); - }); - - describe('with host risk index', async () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/entity/risks'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/entity/risks'); - }); - - it('should be enriched with host risk score', async () => { - const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['auditbeat-*']), - threshold: { - field: 'host.name', - value: 100, - }, - }; - const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, sort: ['host.name'] }); - - expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).to.eql('Low'); - expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).to.eql(20); - expect(previewAlerts[1]?._source?.host?.risk?.calculated_level).to.eql('Critical'); - expect(previewAlerts[1]?._source?.host?.risk?.calculated_score_norm).to.eql(96); - }); - }); - }); -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/utils.ts deleted file mode 100644 index 8530c085e1a5..000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_LAST_DETECTED, ALERT_START } from '@kbn/rule-data-utils'; - -export const removeRandomValuedProperties = (alert: DetectionAlert | undefined) => { - if (!alert) { - return undefined; - } - const { - 'kibana.version': version, - 'kibana.alert.rule.execution.uuid': execUuid, - 'kibana.alert.rule.uuid': uuid, - '@timestamp': timestamp, - 'kibana.alert.rule.created_at': createdAt, - 'kibana.alert.rule.updated_at': updatedAt, - 'kibana.alert.uuid': alertUuid, - [ALERT_START]: alertStart, - [ALERT_LAST_DETECTED]: lastDetected, - ...restOfAlert - } = alert; - return restOfAlert; -}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts index 002bf3ddda8a..f3fb8671906c 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/import_rules.ts @@ -27,8 +27,8 @@ import { getWebHookAction, removeServerGeneratedProperties, ruleToNdjson, + deleteAllExceptions, } from '../../utils'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution'; const getImportRuleBuffer = (connectorId: string) => { diff --git a/x-pack/test/detection_engine_api_integration/utils/create_new_action.ts b/x-pack/test/detection_engine_api_integration/utils/create_new_action.ts deleted file mode 100644 index d5093d8d5d39..000000000000 --- a/x-pack/test/detection_engine_api_integration/utils/create_new_action.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ToolingLog } from '@kbn/tooling-log'; -import type SuperTest from 'supertest'; - -import { getWebHookAction } from './get_web_hook_action'; - -/** - * Helper to cut down on the noise in some of the tests. This - * creates a new action and expects a 200 and does not do any retries. - * @param supertest The supertest deps - */ -export const createNewAction = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -) => { - const response = await supertest - .post('/api/actions/action') - .set('kbn-xsrf', 'true') - .send(getWebHookAction()); - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" when creating a new action. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - return response.body; -}; diff --git a/x-pack/test/detection_engine_api_integration/utils/delete_all_exceptions.ts b/x-pack/test/detection_engine_api_integration/utils/delete_all_exceptions.ts new file mode 100644 index 000000000000..aed98bc61561 --- /dev/null +++ b/x-pack/test/detection_engine_api_integration/utils/delete_all_exceptions.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Should be deleted once all all the remaining tests in this folder get moved to the new /security_solution_api_integration folder + +import type SuperTest from 'supertest'; + +import type { ExceptionList, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; + +import { ToolingLog } from '@kbn/tooling-log'; +import { countDownTest } from './count_down_test'; + +/** + * Remove all exceptions from both the "single" and "agnostic" spaces. + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest handle + */ +export const deleteAllExceptions = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + await deleteAllExceptionsByType(supertest, log, 'single'); + await deleteAllExceptionsByType(supertest, log, 'agnostic'); +}; + +/** + * Remove all exceptions by a given type such as "agnostic" or "single". + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest handle + */ +export const deleteAllExceptionsByType = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + type: NamespaceType +): Promise => { + await countDownTest( + async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find?per_page=9999&namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + const ids: string[] = body.data.map((exception: ExceptionList) => exception.id); + for await (const id of ids) { + await supertest + .delete(`${EXCEPTION_LIST_URL}?id=${id}&namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + } + const { body: finalCheck } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find?namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + return { + passed: finalCheck.data.length === 0, + }; + }, + `deleteAllExceptions by type: "${type}"`, + log, + 50, + 1000 + ); +}; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_detection_metrics_from_body.ts b/x-pack/test/detection_engine_api_integration/utils/get_detection_metrics_from_body.ts deleted file mode 100644 index 92e17ba61fe0..000000000000 --- a/x-pack/test/detection_engine_api_integration/utils/get_detection_metrics_from_body.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; -import type { RiskEngineMetrics } from '@kbn/security-solution-plugin/server/usage/risk_engine/types'; - -/** - * Given a body this will return the detection metrics from it. - * @param body The Stats body - * @returns Detection metrics - */ -export const getDetectionMetricsFromBody = ( - body: Array<{ - stats: { - stack_stats: { - kibana: { plugins: { security_solution: { detectionMetrics: DetectionMetrics } } }; - }; - }; - }> -): DetectionMetrics => { - return body[0].stats.stack_stats.kibana.plugins.security_solution.detectionMetrics; -}; - -/** - * Given a body this will return the risk engine metrics from it. - * @param body The Stats body - * @returns Detection metrics - */ -export const getRiskEngineMetricsFromBody = ( - body: Array<{ - stats: { - stack_stats: { - kibana: { plugins: { security_solution: { riskEngineMetrics: {} } } }; - }; - }; - }> -): RiskEngineMetrics => { - return body[0].stats.stack_stats.kibana.plugins.security_solution.riskEngineMetrics; -}; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_signal_status.ts b/x-pack/test/detection_engine_api_integration/utils/get_signal_status.ts deleted file mode 100644 index d3c922c30ccc..000000000000 --- a/x-pack/test/detection_engine_api_integration/utils/get_signal_status.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const getSignalStatus = () => ({ - aggs: { statuses: { terms: { field: 'kibana.alert.workflow_status', size: 10 } } }, -}); diff --git a/x-pack/test/detection_engine_api_integration/utils/get_stats.ts b/x-pack/test/detection_engine_api_integration/utils/get_stats.ts deleted file mode 100644 index d042bdc4d53f..000000000000 --- a/x-pack/test/detection_engine_api_integration/utils/get_stats.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ToolingLog } from '@kbn/tooling-log'; -import type SuperTest from 'supertest'; -import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; -import type { RiskEngineMetrics } from '@kbn/security-solution-plugin/server/usage/risk_engine/types'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; - -import { getStatsUrl } from './get_stats_url'; -import { - getDetectionMetricsFromBody, - getRiskEngineMetricsFromBody, -} from './get_detection_metrics_from_body'; - -/** - * Gets the stats from the stats endpoint. - * @param supertest The supertest agent. - * @returns The detection metrics - */ -export const getStats = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - const response = await supertest - .post(getStatsUrl()) - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ unencrypted: true, refreshCache: true }); - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" when getting the stats for detections. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - - return getDetectionMetricsFromBody(response.body); -}; - -/** - * Gets the stats from the stats endpoint. - * @param supertest The supertest agent. - * @returns The detection metrics - */ -export const getRiskEngineStats = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - const response = await supertest - .post(getStatsUrl()) - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ unencrypted: true, refreshCache: true }); - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" when getting the stats for risk engine. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - - return getRiskEngineMetricsFromBody(response.body); -}; diff --git a/x-pack/test/detection_engine_api_integration/utils/index.ts b/x-pack/test/detection_engine_api_integration/utils/index.ts index 1c62f3dc2c12..1b18044d9544 100644 --- a/x-pack/test/detection_engine_api_integration/utils/index.ts +++ b/x-pack/test/detection_engine_api_integration/utils/index.ts @@ -13,9 +13,7 @@ export * from './create_container_with_entries'; export * from './create_exception_list'; export * from './create_exception_list_item'; export * from './create_legacy_rule_action'; -export * from './create_new_action'; export * from './create_rule'; -export * from './create_rule_with_auth'; export * from './create_rule_with_exception_entries'; export * from './create_rule_saved_object'; export * from './create_signals_index'; @@ -26,12 +24,10 @@ export * from './delete_all_alerts'; export * from './delete_all_timelines'; export * from './delete_exception_list'; export * from './delete_rule'; -export * from './downgrade_immutable_rule'; export * from './finalize_signals_migration'; export * from './find_immutable_rule_by_id'; export * from './get_complex_rule'; export * from './get_complex_rule_output'; -export * from './get_detection_metrics_from_body'; export * from './get_eql_rule_for_signal_testing'; export * from './get_event_log_execute_complete_by_id'; export * from './get_legacy_action_notification_so'; @@ -48,8 +44,6 @@ export * from './get_rule_for_signal_testing_with_timestamp_override'; export * from './get_rule_with_web_hook_action'; export * from './get_rule_with_legacy_investigation_fields'; export * from './get_saved_query_rule_for_signal_testing'; -export * from './get_security_telemetry_stats'; -export * from './get_signal_status'; export * from './get_signals_by_id'; export * from './get_signals_by_ids'; export * from './get_signals_by_rule_ids'; @@ -63,9 +57,6 @@ export * from './get_simple_rule_output_without_rule_id'; export * from './get_simple_rule_update'; export * from './get_simple_rule_without_rule_id'; export * from './get_simple_saved_query_rule'; -export * from './get_simple_threat_match'; -export * from './get_stats'; -export * from './get_stats_url'; export * from './get_threat_match_rule_for_signal_testing'; export * from './get_threshold_rule_for_signal_testing'; export * from './get_slack_action'; @@ -77,7 +68,6 @@ export * from './preview_rule_with_exception_entries'; export * from './preview_rule'; export * from './refresh_index'; export * from './route_with_namespace'; -export * from './remove_time_fields_from_telemetry_stats'; export * from './remove_server_generated_properties'; export * from './remove_server_generated_properties_including_rule_id'; export * from './resolve_simple_rule_output'; @@ -96,3 +86,4 @@ export * from './prebuilt_rules/delete_all_prebuilt_rule_assets'; export * from './prebuilt_rules/install_mock_prebuilt_rules'; export * from './prebuilt_rules/install_prebuilt_rules_and_timelines'; export * from './get_legacy_action_so'; +export * from './delete_all_exceptions'; diff --git a/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts b/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts index 3d48d6695719..3e2e26e347dd 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/upgrade.ts @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import semver from 'semver'; +import moment from 'moment'; import { AGENTS_INDEX, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { setupFleetAndAgents } from './services'; @@ -1474,13 +1475,14 @@ export default function (providerContext: FtrProviderContext) { }, }, }); + const today = new Date(Date.now()); await supertest .post(`/api/fleet/agents/bulk_upgrade`) .set('kbn-xsrf', 'xxx') .send({ version: fleetServerVersion, agents: ['agent1', 'agent2'], - start_time: new Date(Date.now()).toISOString(), + start_time: today.toISOString(), }) .expect(200); @@ -1498,10 +1500,8 @@ export default function (providerContext: FtrProviderContext) { 'minimum_execution_duration', 'expiration' ); - // calculate 1 month from now - const today = new Date(); - const nextMonthUnixTime = today.setMonth(today.getMonth() + 1); - const nextMonth = new Date(nextMonthUnixTime).toISOString().slice(0, 10); + // add 30 days from now + const nextMonth = moment(today).add(30, 'days').toISOString().slice(0, 10); expect(action.expiration).contain(`${nextMonth}`); expect(action.agents).contain('agent1'); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_dynamic_template_metric.ts b/x-pack/test/fleet_api_integration/apis/epm/install_dynamic_template_metric.ts index cc2bb4ebd858..9bcf3fc673ea 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_dynamic_template_metric.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_dynamic_template_metric.ts @@ -24,14 +24,14 @@ export default function (providerContext: FtrProviderContext) { setupFleetAndAgents(providerContext); after(async () => { - await deletePackage('istio', '0.3.3'); + await deletePackage('no_tsdb_to_tsdb', '0.2.0'); }); it('should install with metric_type added as time_series_metric', async function () { - const templateName = 'metrics-istio.istiod_metrics@package'; + const templateName = 'metrics-no_tsdb_to_tsdb.test@package'; await supertest - .post(`/api/fleet/epm/packages/istio/0.3.3`) + .post(`/api/fleet/epm/packages/no_tsdb_to_tsdb/0.2.0`) .set('kbn-xsrf', 'xxxx') .send({ force: true }) .expect(200); @@ -46,7 +46,7 @@ export default function (providerContext: FtrProviderContext) { const template = resp.component_templates[0].component_template; const dynamicTemplates = template.template.mappings.dynamic_templates; - const mappingName = 'istio.istiod.metrics.*.counter'; + const mappingName = 'test.metrics.*.counter'; const counter = dynamicTemplates.find((tmpl: any) => Object.keys(tmpl)[0] === mappingName); expect(counter[mappingName].mapping.time_series_metric).to.eql('counter'); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts b/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts index 7649237f0ab4..5192b8a4e914 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts @@ -16,10 +16,11 @@ export default function (providerContext: FtrProviderContext) { const pkgName = 'error_handling'; const goodPackageVersion = '0.1.0'; const badPackageVersion = '0.2.0'; + const goodUpgradePackageVersion = '0.3.0'; const kibanaServer = getService('kibanaServer'); - const installPackage = async (pkg: string, version: string) => { - await supertest + const installPackage = (pkg: string, version: string) => { + return supertest .post(`/api/fleet/epm/packages/${pkg}/${version}`) .set('kbn-xsrf', 'xxxx') .send({ force: true }); @@ -45,28 +46,46 @@ export default function (providerContext: FtrProviderContext) { afterEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await uninstallPackage(pkgName, goodPackageVersion); + await uninstallPackage(pkgName, goodUpgradePackageVersion); }); it('on a fresh install, it should uninstall a broken package during rollback', async function () { - await supertest - .post(`/api/fleet/epm/packages/${pkgName}/${badPackageVersion}`) - .set('kbn-xsrf', 'xxxx') - .expect(422); // the broken package contains a broken visualization triggering a 422 from Kibana + // the broken package contains a broken visualization triggering a 422 from Kibana + await installPackage(pkgName, badPackageVersion).expect(422); const pkgInfoResponse = await getPackageInfo(pkgName, badPackageVersion); expect(JSON.parse(pkgInfoResponse.text).item.status).to.be('not_installed'); + expect(pkgInfoResponse.body.item.savedObject).to.be(undefined); }); it('on an upgrade, it should fall back to the previous good version during rollback', async function () { await installPackage(pkgName, goodPackageVersion); - await supertest - .post(`/api/fleet/epm/packages/${pkgName}/${badPackageVersion}`) - .set('kbn-xsrf', 'xxxx') - .expect(422); // the broken package contains a broken visualization triggering a 422 from Kibana + // the broken package contains a broken visualization triggering a 422 from Kibana + await installPackage(pkgName, badPackageVersion).expect(422); const goodPkgInfoResponse = await getPackageInfo(pkgName, goodPackageVersion); expect(JSON.parse(goodPkgInfoResponse.text).item.status).to.be('installed'); expect(JSON.parse(goodPkgInfoResponse.text).item.version).to.be('0.1.0'); + const latestInstallFailedAttempts = + goodPkgInfoResponse.body.item.savedObject.attributes.latest_install_failed_attempts; + expect(latestInstallFailedAttempts).to.have.length(1); + expect(latestInstallFailedAttempts[0].target_version).to.be('0.2.0'); + expect(latestInstallFailedAttempts[0].error.message).to.contain( + 'Document "sample_visualization" belongs to a more recent version of Kibana [12.7.0]' + ); + }); + + it('on a succesfull upgrade, it should clear previous upgrade errors', async function () { + await installPackage(pkgName, goodPackageVersion); + await installPackage(pkgName, badPackageVersion).expect(422); + await installPackage(pkgName, goodUpgradePackageVersion).expect(200); + + const goodPkgInfoResponse = await getPackageInfo(pkgName, goodUpgradePackageVersion); + expect(JSON.parse(goodPkgInfoResponse.text).item.status).to.be('installed'); + expect(JSON.parse(goodPkgInfoResponse.text).item.version).to.be('0.3.0'); + const latestInstallFailedAttempts = + goodPkgInfoResponse.body.item.savedObject.attributes.latest_install_failed_attempts; + expect(latestInstallFailedAttempts).to.have.length(0); }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts index aaf31e54798d..55d85aead477 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -786,6 +786,7 @@ const expectAssetsInstalled = ({ install_status: 'installed', install_started_at: res.attributes.install_started_at, install_source: 'registry', + latest_install_failed_attempts: [], install_format_schema_version: FLEET_INSTALL_FORMAT_VERSION, verification_status: 'unknown', verification_key_id: null, diff --git a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts index 75040c8400d0..eaea702cc6c8 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/update_assets.ts @@ -516,6 +516,7 @@ export default function (providerContext: FtrProviderContext) { install_started_at: res.attributes.install_started_at, install_source: 'registry', install_format_schema_version: FLEET_INSTALL_FORMAT_VERSION, + latest_install_failed_attempts: [], verification_status: 'unknown', verification_key_id: null, }); diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/docs/README.md b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/docs/README.md new file mode 100644 index 000000000000..260499f4b007 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/docs/README.md @@ -0,0 +1,3 @@ +This package should install without errors. + +Version 0.2.0 of this package should fail during installation. We need this good version to test rollback. \ No newline at end of file diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/img/logo_overrides_64_color.svg b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/img/logo_overrides_64_color.svg new file mode 100644 index 000000000000..b03007a76ffc --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/img/logo_overrides_64_color.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/kibana/visualization/sample_visualization.json b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/kibana/visualization/sample_visualization.json new file mode 100644 index 000000000000..01afe600853e --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/kibana/visualization/sample_visualization.json @@ -0,0 +1,14 @@ +{ + "attributes": { + "description": "sample visualization", + "title": "sample vis title", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"extended_bounds\":{},\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1},\"schema\":\"segment\",\"type\":\"date_histogram\"},{\"enabled\":true,\"id\":\"3\",\"params\":{\"customLabel\":\"Log Level\",\"field\":\"log.level\",\"order\":\"desc\",\"orderBy\":\"1\",\"size\":5},\"schema\":\"group\",\"type\":\"terms\"}],\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"@timestamp per day\"},\"type\":\"category\"}],\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"legendPosition\":\"right\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"histogram\",\"valueAxis\":\"ValueAxis-1\"}],\"times\":[],\"type\":\"histogram\",\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"Count\"},\"type\":\"value\"}]},\"title\":\"Log levels over time [Logs Kafka] ECS\",\"type\":\"histogram\"}" + }, + "id": "sample_visualization", + "type": "visualization", + "migrationVersion": { + "visualization": "7.7.0" + } +} diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/manifest.yml new file mode 100644 index 000000000000..883e4234886e --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/error_handling/0.3.0/manifest.yml @@ -0,0 +1,22 @@ +format_version: 1.0.0 +name: error_handling +title: Error handling +description: tests error handling and rollback +version: 0.3.0 +categories: [] +release: beta +type: integration +license: basic +owner: + github: elastic/fleet + +requirement: + elasticsearch: + versions: '>7.7.0' + kibana: + versions: '>7.7.0' + +icons: + - src: '/img/logo_overrides_64_color.svg' + size: '16x16' + type: 'image/svg+xml' diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/no_tsdb_to_tsdb/0.2.0/data_stream/test/fields/fields.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/no_tsdb_to_tsdb/0.2.0/data_stream/test/fields/fields.yml index e1fd2db653ef..6cc90f2148d1 100644 --- a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/no_tsdb_to_tsdb/0.2.0/data_stream/test/fields/fields.yml +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/no_tsdb_to_tsdb/0.2.0/data_stream/test/fields/fields.yml @@ -20,3 +20,10 @@ - name: 'some_metric_field' type: integer metric_type: gauge +- name: test.metrics.*.counter + type: object + object_type: double + object_type_mapping_type: "*" + metric_type: counter + description: > + Istiod counter metric diff --git a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts index 5f6558df992c..bd44a6be9427 100644 --- a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts @@ -1132,6 +1132,23 @@ export default function (providerContext: FtrProviderContext) { // @ts-ignore _source unknown type expect(secret._source.value).to.equal('pass'); }); + + it('should create service_token secret correctly', async function () { + const res = await supertest + .post(`/api/fleet/outputs`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Remote Elasticsearch With Service Token Secret', + type: 'remote_elasticsearch', + hosts: ['https://remote-es:9200'], + secrets: { service_token: 'token' }, + }); + + const secretId = res.body.item.secrets.service_token.id; + const secret = await getSecretById(secretId); + // @ts-ignore _source unknown type + expect(secret._source.value).to.equal('token'); + }); }); describe('DELETE /outputs/{outputId}', () => { diff --git a/x-pack/test/functional/apps/aiops/change_point_detection.ts b/x-pack/test/functional/apps/aiops/change_point_detection.ts index f643de514c0c..787d1b31df11 100644 --- a/x-pack/test/functional/apps/aiops/change_point_detection.ts +++ b/x-pack/test/functional/apps/aiops/change_point_detection.ts @@ -19,20 +19,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('change point detection', async function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it(`loads the change point detection page`, async () => { // Start navigation from the base of the ML app. await ml.navigation.navigateToMl(); await elasticChart.setNewChartUiDebugFlag(true); - await aiops.changePointDetectionPage.navigateToIndexPatternSelection(); + await aiops.changePointDetectionPage.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForChangePointDetection('ft_ecommerce'); await aiops.changePointDetectionPage.assertChangePointDetectionPageExists(); }); @@ -66,15 +66,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await aiops.changePointDetectionPage.getTable(0).waitForTableToLoad(); const result = await aiops.changePointDetectionPage.getTable(0).parseTable(); // the aggregation may return different results (+-1) - expect(result.length).to.be.above(5); + expect(result.length).to.be.above(4); // assert asc sorting by p_value is applied - expect(parseFloat(result[0].pValue)).to.be.lessThan(parseFloat(result[4].pValue)); + expect(parseFloat(result[0].pValue)).to.be.lessThan(parseFloat(result[3].pValue)); }); it('allows change point selection for detailed view', async () => { await aiops.changePointDetectionPage.getTable(0).selectAllRows(); await aiops.changePointDetectionPage.viewSelected(); - await aiops.changePointDetectionPage.assertDetailedView(6); + await aiops.changePointDetectionPage.assertDetailedView(5); await aiops.changePointDetectionPage.closeFlyout(); // deselect await aiops.changePointDetectionPage.getTable(0).selectAllRows(); diff --git a/x-pack/test/functional/apps/aiops/log_pattern_analysis.ts b/x-pack/test/functional/apps/aiops/log_pattern_analysis.ts index 921d02c8c0c6..6ea8a1d4abc3 100644 --- a/x-pack/test/functional/apps/aiops/log_pattern_analysis.ts +++ b/x-pack/test/functional/apps/aiops/log_pattern_analysis.ts @@ -36,20 +36,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await ml.testResources.createIndexPatternIfNeeded('logstash-*', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('logstash-*', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('logstash-*'); + await ml.testResources.deleteDataViewByTitle('logstash-*'); }); it(`loads the log pattern analysis page and filters in patterns in discover`, async () => { // Start navigation from the base of the ML app. await ml.navigation.navigateToMl(); await elasticChart.setNewChartUiDebugFlag(true); - await aiops.logPatternAnalysisPage.navigateToIndexPatternSelection(); + await aiops.logPatternAnalysisPage.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForLogPatternAnalysisDetection('logstash-*'); await aiops.logPatternAnalysisPage.assertLogPatternAnalysisPageExists(); @@ -76,7 +76,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // Start navigation from the base of the ML app. await ml.navigation.navigateToMl(); await elasticChart.setNewChartUiDebugFlag(true); - await aiops.logPatternAnalysisPage.navigateToIndexPatternSelection(); + await aiops.logPatternAnalysisPage.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForLogPatternAnalysisDetection('logstash-*'); await aiops.logPatternAnalysisPage.assertLogPatternAnalysisPageExists(); diff --git a/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts b/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts index 9845cf0a5180..403bbe6382f6 100644 --- a/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts +++ b/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts @@ -36,13 +36,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await ml.testResources.createIndexPatternIfNeeded('logstash-*', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('logstash-*', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle('logstash-*'); + await ml.testResources.deleteDataViewByTitle('logstash-*'); }); it(`loads the log pattern analysis flyout and shows patterns in discover`, async () => { diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis.ts index 8e33b4b1c8e4..f613349078b4 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis.ts @@ -15,6 +15,7 @@ import { logRateAnalysisTestData } from './log_rate_analysis_test_data'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'console', 'header', 'home', 'security']); + const browser = getService('browser'); const elasticChart = getService('elasticChart'); const aiops = getService('aiops'); @@ -28,7 +29,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await aiops.logRateAnalysisPage.navigateToIndexPatternSelection(); + await aiops.logRateAnalysisPage.navigateToDataViewSelection(); await ml.testExecution.logTestStep(`${testData.suiteTitle} loads the log rate analysis page`); await ml.jobSourceSelection.selectSourceForLogRateAnalysis(testData.sourceIndexOrSavedSearch); @@ -147,7 +148,19 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await aiops.logRateAnalysisPage.clickRerunAnalysisButton(true); } - await aiops.logRateAnalysisPage.assertAnalysisComplete(testData.analysisType); + // Wait for the analysis to finish + await aiops.logRateAnalysisPage.assertAnalysisComplete( + testData.analysisType, + testData.dataGenerator + ); + + // At this stage the baseline and deviation brush position should be stored in + // the url state and a full browser refresh should restore the analysis. + await browser.refresh(); + await aiops.logRateAnalysisPage.assertAnalysisComplete( + testData.analysisType, + testData.dataGenerator + ); // The group switch should be disabled by default await aiops.logRateAnalysisPage.assertLogRateAnalysisResultsGroupSwitchExists(false); @@ -160,8 +173,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const analysisGroupsTable = await aiops.logRateAnalysisResultsGroupsTable.parseAnalysisTable(); - expect(orderBy(analysisGroupsTable, 'group')).to.be.eql( - orderBy(testData.expected.analysisGroupsTable, 'group') + + const actualAnalysisGroupsTable = orderBy(analysisGroupsTable, 'group'); + const expectedAnalysisGroupsTable = orderBy(testData.expected.analysisGroupsTable, 'group'); + + expect(actualAnalysisGroupsTable).to.be.eql( + expectedAnalysisGroupsTable, + `Expected analysis groups table to be ${JSON.stringify( + expectedAnalysisGroupsTable + )}, got ${JSON.stringify(actualAnalysisGroupsTable)}` ); await ml.testExecution.logTestStep('expand table row'); @@ -170,8 +190,18 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { if (!isTestDataExpectedWithSampleProbability(testData.expected)) { const analysisTable = await aiops.logRateAnalysisResultsTable.parseAnalysisTable(); - expect(orderBy(analysisTable, ['fieldName', 'fieldValue'])).to.be.eql( - orderBy(testData.expected.analysisTable, ['fieldName', 'fieldValue']) + + const actualAnalysisTable = orderBy(analysisTable, ['fieldName', 'fieldValue']); + const expectedAnalysisTable = orderBy(testData.expected.analysisTable, [ + 'fieldName', + 'fieldValue', + ]); + + expect(actualAnalysisTable).to.be.eql( + expectedAnalysisTable, + `Expected analysis table results to be ${JSON.stringify( + expectedAnalysisTable + )}, got ${JSON.stringify(actualAnalysisTable)}` ); } @@ -199,8 +229,18 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { if (!isTestDataExpectedWithSampleProbability(testData.expected)) { const filteredAnalysisGroupsTable = await aiops.logRateAnalysisResultsGroupsTable.parseAnalysisTable(); - expect(orderBy(filteredAnalysisGroupsTable, 'group')).to.be.eql( - orderBy(testData.expected.filteredAnalysisGroupsTable, 'group') + + const actualFilteredAnalysisGroupsTable = orderBy(filteredAnalysisGroupsTable, 'group'); + const expectedFilteredAnalysisGroupsTable = orderBy( + testData.expected.filteredAnalysisGroupsTable, + 'group' + ); + + expect(actualFilteredAnalysisGroupsTable).to.be.eql( + expectedFilteredAnalysisGroupsTable, + `Expected filtered analysis groups table to be ${JSON.stringify( + expectedFilteredAnalysisGroupsTable + )}, got ${JSON.stringify(actualFilteredAnalysisGroupsTable)}` ); } } @@ -234,7 +274,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { await aiops.logRateAnalysisDataGenerator.generateData(testData.dataGenerator); - await ml.testResources.createIndexPatternIfNeeded( + await ml.testResources.createDataViewIfNeeded( testData.sourceIndexOrSavedSearch, '@timestamp' ); @@ -260,7 +300,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await elasticChart.setNewChartUiDebugFlag(false); if (testData.dataGenerator !== 'kibana_sample_data_logs') { - await ml.testResources.deleteIndexPatternByTitle(testData.sourceIndexOrSavedSearch); + await ml.testResources.deleteDataViewByTitle(testData.sourceIndexOrSavedSearch); } await aiops.logRateAnalysisDataGenerator.removeGeneratedData(testData.dataGenerator); }); diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table.ts new file mode 100644 index 000000000000..6780cab5cb20 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisGroupsTable = [ + { + group: 'response_code: 500url: home.php', + docCount: '792', + }, + { + group: 'url: login.phpresponse_code: 500', + docCount: '790', + }, + { + docCount: '636', + group: 'user: Peterurl: home.php', + }, + { + docCount: '632', + group: 'user: Peterurl: login.php', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield.ts new file mode 100644 index 000000000000..2f20ab790038 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisGroupsTableTextfield = [ + { + group: 'message: an unexpected error occuredurl: home.phpresponse_code: 500', + docCount: '634', + }, + { + group: 'message: an unexpected error occuredurl: login.phpresponse_code: 500', + docCount: '632', + }, + { + docCount: '636', + group: 'user: Peterurl: home.php', + }, + { + docCount: '632', + group: 'user: Peterurl: login.php', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield_zerodocsfallback.ts new file mode 100644 index 000000000000..4c9308f6c0ae --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_textfield_zerodocsfallback.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisGroupsTableTextfieldZerodocsfallback = [ + { + group: + 'message: an unexpected error occuredurl: home.phpuser: Maryresponse_code: 500version: v1.0.0', + docCount: '29', + }, + { + group: + 'message: an unexpected error occuredurl: home.phpuser: Paulresponse_code: 500version: v1.0.0', + docCount: '29', + }, + { + group: + 'message: an unexpected error occuredurl: login.phpuser: Paulresponse_code: 500version: v1.0.0', + docCount: '29', + }, + { + group: + 'url: home.phpuser: Paulresponse_code: 500message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterresponse_code: 200url: home.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterresponse_code: 200url: login.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterresponse_code: 404url: home.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterresponse_code: 404url: login.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterurl: user.phpresponse_code: 200message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, + { + group: + 'user: Peterurl: user.phpresponse_code: 404message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '30', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_zerodocsfallback.ts new file mode 100644 index 000000000000..cd749df4f292 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_groups_table_zerodocsfallback.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisGroupsTableZerodocsfallback = [ + { group: 'response_code: 500url: home.phpuser: Maryversion: v1.0.0', docCount: '47' }, + { group: 'response_code: 500url: home.phpuser: Paulversion: v1.0.0', docCount: '59' }, + { group: 'response_code: 500url: login.phpuser: Maryversion: v1.0.0', docCount: '35' }, + { group: 'response_code: 500url: login.phpuser: Paulversion: v1.0.0', docCount: '39' }, + { group: 'user: Peterurl: home.phpresponse_code: 200version: v1.0.0', docCount: '30' }, + { group: 'user: Peterurl: home.phpresponse_code: 404version: v1.0.0', docCount: '30' }, + { group: 'user: Peterurl: login.phpresponse_code: 200version: v1.0.0', docCount: '30' }, + { group: 'user: Peterurl: login.phpresponse_code: 404version: v1.0.0', docCount: '30' }, + { group: 'user: Peterurl: user.phpresponse_code: 200version: v1.0.0', docCount: '30' }, + { group: 'user: Peterurl: user.phpresponse_code: 404version: v1.0.0', docCount: '30' }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table.ts new file mode 100644 index 000000000000..797a9b091148 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisTable = [ + { + fieldName: 'url', + fieldValue: 'home.php', + impact: 'Low', + logRate: 'Chart type:bar chart', + pValue: '0.00974', + }, + { + fieldName: 'user', + fieldValue: 'Peter', + impact: 'High', + logRate: 'Chart type:bar chart', + pValue: '2.63e-21', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield.ts new file mode 100644 index 000000000000..be77ef870d53 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisTableTextfield = [ + { + fieldName: 'message', + fieldValue: 'an unexpected error occured', + logRate: 'Chart type:bar chart', + pValue: '0.00000100', + impact: 'Medium', + }, + { + fieldName: 'response_code', + fieldValue: '500', + logRate: 'Chart type:bar chart', + pValue: '3.61e-12', + impact: 'High', + }, + { + fieldName: 'url', + fieldValue: 'home.php', + impact: 'Low', + logRate: 'Chart type:bar chart', + pValue: '0.00974', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield_zerodocsfallback.ts new file mode 100644 index 000000000000..75c624a67321 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_textfield_zerodocsfallback.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisTableTextfieldZerodocsfallback = [ + { + fieldName: 'message', + fieldValue: 'Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'response_code', + fieldValue: '500', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'url', + fieldValue: 'home.php', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'user', + fieldValue: 'Paul', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'version', + fieldValue: 'v1.0.0', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_zerodocsfallback.ts new file mode 100644 index 000000000000..3d4f806db8f4 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/analysis_table_zerodocsfallback.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const analysisTableZerodocsfallback = [ + { + fieldName: 'response_code', + fieldValue: '500', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'url', + fieldValue: 'home.php', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'user', + fieldValue: 'Paul', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, + { + fieldName: 'version', + fieldValue: 'v1.0.0', + logRate: 'Chart type:bar chart', + pValue: '1.00', + impact: '', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table.ts new file mode 100644 index 000000000000..97b1e2ce7169 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filteredAnalysisGroupsTable = [ + { group: '* url: home.phpresponse_code: 500', docCount: '792' }, + { group: '* url: login.phpresponse_code: 500', docCount: '790' }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield.ts new file mode 100644 index 000000000000..41c5efe2cb21 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filteredAnalysisGroupsTableTextfield = [ + { + group: '* url: home.phpmessage: an unexpected error occuredresponse_code: 500', + docCount: '634', + }, + { + group: '* url: login.phpmessage: an unexpected error occuredresponse_code: 500', + docCount: '632', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield_zerodocsfallback.ts new file mode 100644 index 000000000000..9ec9f0e19f89 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_textfield_zerodocsfallback.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filteredAnalysisGroupsTableTextfieldZerodocsfallback = [ + { + group: 'message: an unexpected error occuredurl: home.phpresponse_code: 500version: v1.0.0', + docCount: '58', + }, + { + group: 'message: an unexpected error occuredurl: login.phpresponse_code: 500version: v1.0.0', + docCount: '58', + }, + { + group: + 'response_code: 200url: home.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '46', + }, + { + group: + 'response_code: 200url: login.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '35', + }, + { + group: + 'response_code: 404url: home.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '63', + }, + { + group: + 'response_code: 404url: login.phpmessage: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '40', + }, + { + group: + 'url: home.phpresponse_code: 500message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '48', + }, + { + group: + 'url: user.phpresponse_code: 200message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '40', + }, + { + group: + 'url: user.phpresponse_code: 404message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '51', + }, + { + group: + 'url: user.phpresponse_code: 500message: Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200version: v1.0.0', + docCount: '41', + }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_zerodocsfallback.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_zerodocsfallback.ts new file mode 100644 index 000000000000..eaeb04b9c020 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/__mocks__/filtered_analysis_groups_table_zerodocsfallback.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const filteredAnalysisGroupsTableZerodocsfallback = [ + { group: 'url: home.phpresponse_code: 200version: v1.0.0', docCount: '46' }, + { group: 'url: home.phpresponse_code: 404version: v1.0.0', docCount: '63' }, + { group: 'url: home.phpresponse_code: 500version: v1.0.0', docCount: '106' }, + { group: 'url: login.phpresponse_code: 200version: v1.0.0', docCount: '35' }, + { group: 'url: login.phpresponse_code: 404version: v1.0.0', docCount: '40' }, + { group: 'url: login.phpresponse_code: 500version: v1.0.0', docCount: '74' }, + { group: 'url: user.phpresponse_code: 200version: v1.0.0', docCount: '40' }, + { group: 'url: user.phpresponse_code: 404version: v1.0.0', docCount: '51' }, + { group: 'url: user.phpresponse_code: 500version: v1.0.0', docCount: '41' }, +]; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts new file mode 100644 index 000000000000..6afbaab85642 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LogRateAnalysisType } from '@kbn/aiops-utils'; + +import type { TestData } from '../../types'; + +import type { LogRateAnalysisDataGenerator } from '../../../../services/aiops/log_rate_analysis_data_generator'; + +import { analysisGroupsTableTextfieldZerodocsfallback } from './__mocks__/analysis_groups_table_textfield_zerodocsfallback'; +import { analysisGroupsTableZerodocsfallback } from './__mocks__/analysis_groups_table_zerodocsfallback'; +import { analysisGroupsTableTextfield } from './__mocks__/analysis_groups_table_textfield'; +import { analysisGroupsTable } from './__mocks__/analysis_groups_table'; +import { filteredAnalysisGroupsTableTextfieldZerodocsfallback } from './__mocks__/filtered_analysis_groups_table_textfield_zerodocsfallback'; +import { filteredAnalysisGroupsTableZerodocsfallback } from './__mocks__/filtered_analysis_groups_table_zerodocsfallback'; +import { filteredAnalysisGroupsTableTextfield } from './__mocks__/filtered_analysis_groups_table_textfield'; +import { filteredAnalysisGroupsTable } from './__mocks__/filtered_analysis_groups_table'; +import { analysisTableTextfieldZerodocsfallback } from './__mocks__/analysis_table_textfield_zerodocsfallback'; +import { analysisTableZerodocsfallback } from './__mocks__/analysis_table_zerodocsfallback'; +import { analysisTableTextfield } from './__mocks__/analysis_table_textfield'; +import { analysisTable } from './__mocks__/analysis_table'; + +const REFERENCE_TS = 1669018354793; +const DAY_MS = 86400000; + +const DEVIATION_TS = REFERENCE_TS - DAY_MS * 2; +const BASELINE_TS = DEVIATION_TS - DAY_MS * 1; + +interface GetArtificialLogDataViewTestDataOptions { + analysisType: LogRateAnalysisType; + textField: boolean; + zeroDocsFallback: boolean; +} + +export const getArtificialLogDataViewTestData = ({ + analysisType, + textField, + zeroDocsFallback, +}: GetArtificialLogDataViewTestDataOptions): TestData => { + function getAnalysisGroupsTable() { + if (zeroDocsFallback) { + return textField + ? analysisGroupsTableTextfieldZerodocsfallback + : analysisGroupsTableZerodocsfallback; + } + return textField ? analysisGroupsTableTextfield : analysisGroupsTable; + } + + function getFilteredAnalysisGroupsTable() { + if (zeroDocsFallback) { + return textField + ? filteredAnalysisGroupsTableTextfieldZerodocsfallback + : filteredAnalysisGroupsTableZerodocsfallback; + } + + return textField ? filteredAnalysisGroupsTableTextfield : filteredAnalysisGroupsTable; + } + + function getAnalysisTable() { + if (zeroDocsFallback) { + return textField ? analysisTableTextfieldZerodocsfallback : analysisTableZerodocsfallback; + } + + return textField ? analysisTableTextfield : analysisTable; + } + + function getFieldSelectorPopover() { + if (zeroDocsFallback) { + return [...(textField ? ['message'] : []), 'response_code', 'url', 'user', 'version']; + } + return [...(textField ? ['message'] : []), 'response_code', 'url', 'user']; + } + + function getSuiteTitle() { + return `artificial logs with ${analysisType} and ${ + textField ? 'text field' : 'no text field' + } and ${zeroDocsFallback ? 'zero docs fallback' : 'no zero docs fallback'}`; + } + + function getDataGenerator(): LogRateAnalysisDataGenerator { + return `artificial_logs_with_${analysisType}${textField ? '_textfield' : ''}${ + zeroDocsFallback ? '_zerodocsfallback' : '' + }`; + } + + function getBrushBaselineTargetTimestamp() { + if (analysisType === 'dip' && zeroDocsFallback) { + return DEVIATION_TS; + } + + return zeroDocsFallback ? BASELINE_TS - DAY_MS / 2 : BASELINE_TS + DAY_MS / 2; + } + + function getBrushDeviationTargetTimestamp() { + if (analysisType === 'dip' && zeroDocsFallback) { + return DEVIATION_TS + DAY_MS * 1.5; + } + + return zeroDocsFallback ? DEVIATION_TS : DEVIATION_TS + DAY_MS / 2; + } + + return { + suiteTitle: getSuiteTitle(), + analysisType, + dataGenerator: getDataGenerator(), + isSavedSearch: false, + sourceIndexOrSavedSearch: getDataGenerator(), + brushBaselineTargetTimestamp: getBrushBaselineTargetTimestamp(), + brushDeviationTargetTimestamp: getBrushDeviationTargetTimestamp(), + brushIntervalFactor: zeroDocsFallback ? 1 : 10, + chartClickCoordinates: [-200, 30], + fieldSelectorSearch: 'user', + fieldSelectorApplyAvailable: true, + expected: { + totalDocCountFormatted: zeroDocsFallback ? '9,482' : '8,400', + analysisGroupsTable: getAnalysisGroupsTable(), + filteredAnalysisGroupsTable: getFilteredAnalysisGroupsTable(), + analysisTable: getAnalysisTable(), + fieldSelectorPopover: getFieldSelectorPopover(), + }, + }; +}; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts new file mode 100644 index 000000000000..be019193f2ef --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LOG_RATE_ANALYSIS_TYPE } from '@kbn/aiops-utils'; + +import type { TestData } from '../../types'; + +export const farequoteDataViewTestData: TestData = { + suiteTitle: 'farequote with spike', + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + dataGenerator: 'farequote_with_spike', + isSavedSearch: false, + sourceIndexOrSavedSearch: 'ft_farequote', + brushDeviationTargetTimestamp: 1455033600000, + brushIntervalFactor: 1, + chartClickCoordinates: [0, 0], + fieldSelectorSearch: 'airline', + fieldSelectorApplyAvailable: false, + expected: { + totalDocCountFormatted: '86,374', + sampleProbabilityFormatted: '0.5', + fieldSelectorPopover: ['airline', 'custom_field.keyword'], + }, +}; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts new file mode 100644 index 000000000000..653889c1eb0c --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LOG_RATE_ANALYSIS_TYPE } from '@kbn/aiops-utils'; + +import type { TestData } from '../../types'; + +export const farequoteDataViewTestDataWithQuery: TestData = { + suiteTitle: 'farequote with spike', + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + dataGenerator: 'farequote_with_spike', + isSavedSearch: false, + sourceIndexOrSavedSearch: 'ft_farequote', + brushDeviationTargetTimestamp: 1455033600000, + brushIntervalFactor: 1, + chartClickCoordinates: [0, 0], + fieldSelectorSearch: 'airline', + fieldSelectorApplyAvailable: false, + query: 'NOT airline:("SWR" OR "ACA" OR "AWE" OR "BAW" OR "JAL" OR "JBU" OR "JZA" OR "KLM")', + expected: { + totalDocCountFormatted: '48,799', + analysisGroupsTable: [ + { + docCount: '297', + group: '* airline: AAL', + }, + { + docCount: '100', + group: '* custom_field.keyword: deviation* airline: UAL', + }, + ], + analysisTable: [ + { + fieldName: 'airline', + fieldValue: 'AAL', + logRate: 'Chart type:bar chart', + pValue: '1.18e-8', + impact: 'High', + }, + ], + fieldSelectorPopover: ['airline', 'custom_field.keyword'], + }, +}; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts new file mode 100644 index 000000000000..2d85fe1e6421 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LOG_RATE_ANALYSIS_TYPE } from '@kbn/aiops-utils'; + +import type { TestData } from '../../types'; + +export const kibanaLogsDataViewTestData: TestData = { + suiteTitle: 'kibana sample data logs', + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + dataGenerator: 'kibana_sample_data_logs', + isSavedSearch: false, + sourceIndexOrSavedSearch: 'kibana_sample_data_logs', + brushIntervalFactor: 1, + chartClickCoordinates: [235, 0], + fieldSelectorSearch: 'referer', + fieldSelectorApplyAvailable: true, + action: { + type: 'LogPatternAnalysis', + tableRowId: '1064853178', + expected: { + queryBar: + 'clientip:30.156.16.164 AND host.keyword:elastic-elastic-elastic.org AND ip:30.156.16.163 AND response.keyword:404 AND machine.os.keyword:win xp AND geo.dest:IN AND geo.srcdest:US\\:IN', + totalDocCount: 100, + }, + }, + expected: { + totalDocCountFormatted: '14,074', + analysisGroupsTable: [ + { + group: + '* clientip: 30.156.16.164* host.keyword: elastic-elastic-elastic.org* ip: 30.156.16.163* referer: http://www.elastic-elastic-elastic.com/success/timothy-l-kopra* response.keyword: 404Showing 5 out of 8 items. 8 items unique to this group.', + docCount: '100', + }, + ], + filteredAnalysisGroupsTable: [ + { + group: + '* clientip: 30.156.16.164* host.keyword: elastic-elastic-elastic.org* ip: 30.156.16.163* response.keyword: 404* machine.os.keyword: win xpShowing 5 out of 7 items. 7 items unique to this group.', + docCount: '100', + }, + ], + analysisTable: [ + { + fieldName: 'clientip', + fieldValue: '30.156.16.164', + logRate: 'Chart type:bar chart', + pValue: '3.10e-13', + impact: 'High', + }, + { + fieldName: 'geo.dest', + fieldValue: 'IN', + logRate: 'Chart type:bar chart', + pValue: '0.000716', + impact: 'Medium', + }, + { + fieldName: 'geo.srcdest', + fieldValue: 'US:IN', + logRate: 'Chart type:bar chart', + pValue: '0.000716', + impact: 'Medium', + }, + { + fieldName: 'host.keyword', + fieldValue: 'elastic-elastic-elastic.org', + logRate: 'Chart type:bar chart', + pValue: '7.14e-9', + impact: 'High', + }, + { + fieldName: 'ip', + fieldValue: '30.156.16.163', + logRate: 'Chart type:bar chart', + pValue: '3.28e-13', + impact: 'High', + }, + { + fieldName: 'machine.os.keyword', + fieldValue: 'win xp', + logRate: 'Chart type:bar chart', + pValue: '0.0000997', + impact: 'Medium', + }, + { + fieldName: 'referer', + fieldValue: 'http://www.elastic-elastic-elastic.com/success/timothy-l-kopra', + logRate: 'Chart type:bar chart', + pValue: '4.74e-13', + impact: 'High', + }, + { + fieldName: 'response.keyword', + fieldValue: '404', + logRate: 'Chart type:bar chart', + pValue: '0.00000604', + impact: 'Medium', + }, + ], + fieldSelectorPopover: [ + 'clientip', + 'geo.dest', + 'geo.srcdest', + 'host.keyword', + 'ip', + 'machine.os.keyword', + 'referer', + 'response.keyword', + ], + }, +}; diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis_test_data.ts index 3fb1e00b9520..c3f33ff2aa5b 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis_test_data.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis_test_data.ts @@ -5,289 +5,57 @@ * 2.0. */ -import { LOG_RATE_ANALYSIS_TYPE, type LogRateAnalysisType } from '@kbn/aiops-utils'; +import { LOG_RATE_ANALYSIS_TYPE } from '@kbn/aiops-utils'; -import type { TestData } from './types'; - -export const kibanaLogsDataViewTestData: TestData = { - suiteTitle: 'kibana sample data logs', - analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, - dataGenerator: 'kibana_sample_data_logs', - isSavedSearch: false, - sourceIndexOrSavedSearch: 'kibana_sample_data_logs', - brushIntervalFactor: 1, - chartClickCoordinates: [235, 0], - fieldSelectorSearch: 'referer', - fieldSelectorApplyAvailable: true, - action: { - type: 'LogPatternAnalysis', - tableRowId: '1064853178', - expected: { - queryBar: - 'clientip:30.156.16.164 AND host.keyword:elastic-elastic-elastic.org AND ip:30.156.16.163 AND response.keyword:404 AND machine.os.keyword:win xp AND geo.dest:IN AND geo.srcdest:US\\:IN', - totalDocCount: 100, - }, - }, - expected: { - totalDocCountFormatted: '14,074', - analysisGroupsTable: [ - { - group: - '* clientip: 30.156.16.164* host.keyword: elastic-elastic-elastic.org* ip: 30.156.16.163* referer: http://www.elastic-elastic-elastic.com/success/timothy-l-kopra* response.keyword: 404Showing 5 out of 8 items. 8 items unique to this group.', - docCount: '100', - }, - ], - filteredAnalysisGroupsTable: [ - { - group: - '* clientip: 30.156.16.164* host.keyword: elastic-elastic-elastic.org* ip: 30.156.16.163* response.keyword: 404* machine.os.keyword: win xpShowing 5 out of 7 items. 7 items unique to this group.', - docCount: '100', - }, - ], - analysisTable: [ - { - fieldName: 'clientip', - fieldValue: '30.156.16.164', - logRate: 'Chart type:bar chart', - pValue: '3.10e-13', - impact: 'High', - }, - { - fieldName: 'geo.dest', - fieldValue: 'IN', - logRate: 'Chart type:bar chart', - pValue: '0.000716', - impact: 'Medium', - }, - { - fieldName: 'geo.srcdest', - fieldValue: 'US:IN', - logRate: 'Chart type:bar chart', - pValue: '0.000716', - impact: 'Medium', - }, - { - fieldName: 'host.keyword', - fieldValue: 'elastic-elastic-elastic.org', - logRate: 'Chart type:bar chart', - pValue: '7.14e-9', - impact: 'High', - }, - { - fieldName: 'ip', - fieldValue: '30.156.16.163', - logRate: 'Chart type:bar chart', - pValue: '3.28e-13', - impact: 'High', - }, - { - fieldName: 'machine.os.keyword', - fieldValue: 'win xp', - logRate: 'Chart type:bar chart', - pValue: '0.0000997', - impact: 'Medium', - }, - { - fieldName: 'referer', - fieldValue: 'http://www.elastic-elastic-elastic.com/success/timothy-l-kopra', - logRate: 'Chart type:bar chart', - pValue: '4.74e-13', - impact: 'High', - }, - { - fieldName: 'response.keyword', - fieldValue: '404', - logRate: 'Chart type:bar chart', - pValue: '0.00000604', - impact: 'Medium', - }, - ], - fieldSelectorPopover: [ - 'clientip', - 'geo.dest', - 'geo.srcdest', - 'host.keyword', - 'ip', - 'machine.os.keyword', - 'referer', - 'response.keyword', - ], - }, -}; - -export const farequoteDataViewTestData: TestData = { - suiteTitle: 'farequote with spike', - analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, - dataGenerator: 'farequote_with_spike', - isSavedSearch: false, - sourceIndexOrSavedSearch: 'ft_farequote', - brushDeviationTargetTimestamp: 1455033600000, - brushIntervalFactor: 1, - chartClickCoordinates: [0, 0], - fieldSelectorSearch: 'airline', - fieldSelectorApplyAvailable: false, - expected: { - totalDocCountFormatted: '86,374', - sampleProbabilityFormatted: '0.5', - fieldSelectorPopover: ['airline', 'custom_field.keyword'], - }, -}; - -export const farequoteDataViewTestDataWithQuery: TestData = { - suiteTitle: 'farequote with spike', - analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, - dataGenerator: 'farequote_with_spike', - isSavedSearch: false, - sourceIndexOrSavedSearch: 'ft_farequote', - brushDeviationTargetTimestamp: 1455033600000, - brushIntervalFactor: 1, - chartClickCoordinates: [0, 0], - fieldSelectorSearch: 'airline', - fieldSelectorApplyAvailable: false, - query: 'NOT airline:("SWR" OR "ACA" OR "AWE" OR "BAW" OR "JAL" OR "JBU" OR "JZA" OR "KLM")', - expected: { - totalDocCountFormatted: '48,799', - analysisGroupsTable: [ - { - docCount: '297', - group: '* airline: AAL', - }, - { - docCount: '100', - group: '* custom_field.keyword: deviation* airline: UAL', - }, - ], - analysisTable: [ - { - fieldName: 'airline', - fieldValue: 'AAL', - logRate: 'Chart type:bar chart', - pValue: '1.18e-8', - impact: 'High', - }, - ], - fieldSelectorPopover: ['airline', 'custom_field.keyword'], - }, -}; +import { kibanaLogsDataViewTestData } from './log_rate_analysis/test_data/kibana_logs_data_view_test_data'; +import { farequoteDataViewTestData } from './log_rate_analysis/test_data/farequote_data_view_test_data'; +import { farequoteDataViewTestDataWithQuery } from './log_rate_analysis/test_data/farequote_data_view_test_data_with_query'; +import { getArtificialLogDataViewTestData } from './log_rate_analysis/test_data/artificial_log_data_view_test_data'; -const REFERENCE_TS = 1669018354793; -const DAY_MS = 86400000; - -const DEVIATION_TS = REFERENCE_TS - DAY_MS * 2; -const BASELINE_TS = DEVIATION_TS - DAY_MS * 1; - -const getArtificialLogDataViewTestData = ( - analysisType: LogRateAnalysisType, - textField: boolean -): TestData => ({ - suiteTitle: `artificial logs with ${analysisType} and ${ - textField ? 'text field' : 'no text field' - }`, - analysisType, - dataGenerator: `artificial_logs_with_${analysisType}_${textField ? 'textfield' : 'notextfield'}`, - isSavedSearch: false, - sourceIndexOrSavedSearch: `artificial_logs_with_${analysisType}_${ - textField ? 'textfield' : 'notextfield' - }`, - brushBaselineTargetTimestamp: BASELINE_TS + DAY_MS / 2, - brushDeviationTargetTimestamp: DEVIATION_TS + DAY_MS / 2, - brushIntervalFactor: 10, - chartClickCoordinates: [-200, 30], - fieldSelectorSearch: 'user', - fieldSelectorApplyAvailable: true, - expected: { - totalDocCountFormatted: '8,400', - analysisGroupsTable: [ - textField - ? { - group: 'message: an unexpected error occuredurl: home.phpresponse_code: 500', - docCount: '634', - } - : { - group: 'response_code: 500url: home.php', - docCount: '792', - }, - textField - ? { - group: 'message: an unexpected error occuredurl: login.phpresponse_code: 500', - docCount: '632', - } - : { - group: 'url: login.phpresponse_code: 500', - docCount: '790', - }, - { - docCount: '636', - group: 'user: Peterurl: home.php', - }, - { - docCount: '632', - group: 'user: Peterurl: login.php', - }, - ], - filteredAnalysisGroupsTable: textField - ? [ - { - group: '* url: home.phpmessage: an unexpected error occuredresponse_code: 500', - docCount: '634', - }, - { - group: '* url: login.phpmessage: an unexpected error occuredresponse_code: 500', - docCount: '632', - }, - ] - : [ - { group: '* url: home.phpresponse_code: 500', docCount: '792' }, - { group: '* url: login.phpresponse_code: 500', docCount: '790' }, - ], - analysisTable: [ - ...(textField - ? [ - { - fieldName: 'message', - fieldValue: 'an unexpected error occured', - logRate: 'Chart type:bar chart', - pValue: '0.00000100', - impact: 'Medium', - }, - { - fieldName: 'response_code', - fieldValue: '500', - logRate: 'Chart type:bar chart', - pValue: '3.61e-12', - impact: 'High', - }, - ] - : []), - { - fieldName: 'url', - fieldValue: 'home.php', - impact: 'Low', - logRate: 'Chart type:bar chart', - pValue: '0.00974', - }, - ...(textField - ? [] - : [ - { - fieldName: 'user', - fieldValue: 'Peter', - impact: 'High', - logRate: 'Chart type:bar chart', - pValue: '2.63e-21', - }, - ]), - ], - fieldSelectorPopover: [...(textField ? ['message'] : []), 'response_code', 'url', 'user'], - }, -}); +import type { TestData } from './types'; export const logRateAnalysisTestData: TestData[] = [ kibanaLogsDataViewTestData, farequoteDataViewTestData, farequoteDataViewTestDataWithQuery, - getArtificialLogDataViewTestData(LOG_RATE_ANALYSIS_TYPE.SPIKE, false), - getArtificialLogDataViewTestData(LOG_RATE_ANALYSIS_TYPE.SPIKE, true), - getArtificialLogDataViewTestData(LOG_RATE_ANALYSIS_TYPE.DIP, false), - getArtificialLogDataViewTestData(LOG_RATE_ANALYSIS_TYPE.DIP, true), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + textField: false, + zeroDocsFallback: false, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + textField: true, + zeroDocsFallback: false, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.DIP, + textField: false, + zeroDocsFallback: false, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.DIP, + textField: true, + zeroDocsFallback: false, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + textField: true, + zeroDocsFallback: true, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE, + textField: false, + zeroDocsFallback: true, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.DIP, + textField: true, + zeroDocsFallback: true, + }), + getArtificialLogDataViewTestData({ + analysisType: LOG_RATE_ANALYSIS_TYPE.DIP, + textField: false, + zeroDocsFallback: true, + }), ]; diff --git a/x-pack/test/functional/apps/aiops/types.ts b/x-pack/test/functional/apps/aiops/types.ts index 45f376cb670e..72a72b1d2bb3 100644 --- a/x-pack/test/functional/apps/aiops/types.ts +++ b/x-pack/test/functional/apps/aiops/types.ts @@ -8,7 +8,7 @@ import type { LogRateAnalysisType } from '@kbn/aiops-utils'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { LogRateAnalysisDataGenerator } from '../../services/aiops/log_rate_analysis_data_generator'; +import type { LogRateAnalysisDataGenerator } from '../../services/aiops/log_rate_analysis_data_generator'; interface TestDataTableActionLogPatternAnalysis { type: 'LogPatternAnalysis'; diff --git a/x-pack/test/functional/apps/discover/visualize_field.ts b/x-pack/test/functional/apps/discover/visualize_field.ts index a61a2abba187..428ef13c3486 100644 --- a/x-pack/test/functional/apps/discover/visualize_field.ts +++ b/x-pack/test/functional/apps/discover/visualize_field.ts @@ -255,5 +255,76 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const data = await PageObjects.lens.getCurrentChartDebugStateForVizType('xyVisChart'); assertMatchesExpectedData(data!); }); + + it('should allow editing the query in the dashboard', async () => { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await monacoEditor.setCodeEditorValue('from logstash-* | limit 10'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('TextBasedLangEditor-expand'); + // save the visualization + await testSubjects.click('unifiedHistogramSaveVisualization'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.lens.saveModal('TextBasedChart1', false, false, false, 'new'); + await testSubjects.existOrFail('embeddablePanelHeading-TextBasedChart1'); + await elasticChart.setNewChartUiDebugFlag(true); + await PageObjects.header.waitUntilLoadingHasFinished(); + // open the inline editing flyout + await testSubjects.click('embeddablePanelToggleMenuIcon'); + await testSubjects.click('embeddablePanelAction-ACTION_CONFIGURE_IN_LENS'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // change the query + await monacoEditor.setCodeEditorValue('from logstash-* | stats maxB = max(bytes)'); + await testSubjects.click('TextBasedLangEditor-run-query-button'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect((await PageObjects.lens.getMetricVisualizationData()).length).to.be.equal(1); + + // change the query to display a datatabler + await monacoEditor.setCodeEditorValue('from logstash-* | limit 10'); + await testSubjects.click('TextBasedLangEditor-run-query-button'); + await PageObjects.lens.waitForVisualization(); + expect(await testSubjects.exists('lnsDataTable')).to.be(true); + + await PageObjects.lens.removeDimension('lnsDatatable_metrics'); + await PageObjects.lens.removeDimension('lnsDatatable_metrics'); + await PageObjects.lens.removeDimension('lnsDatatable_metrics'); + await PageObjects.lens.removeDimension('lnsDatatable_metrics'); + + await PageObjects.lens.configureTextBasedLanguagesDimension({ + dimension: 'lnsDatatable_metrics > lns-empty-dimension', + field: 'bytes', + keepOpen: true, + }); + await testSubjects.click('lns-indexPattern-dimensionContainerBack'); + // click donut from suggestions + await testSubjects.click('lensSuggestionsPanelToggleButton'); + await testSubjects.click('lnsSuggestion-donut'); + expect(await testSubjects.exists('partitionVisChart')).to.be(true); + }); + + it('should default title when saving chart in Discover (even when modal is closed and reopened)', async () => { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await monacoEditor.setCodeEditorValue( + 'from logstash-* | stats averageB = avg(bytes) by extension' + ); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.chooseLensChart('Bar vertical stacked'); + await testSubjects.click('TextBasedLangEditor-expand'); + await testSubjects.click('unifiedHistogramSaveVisualization'); + await PageObjects.header.waitUntilLoadingHasFinished(); + let title = await testSubjects.getAttribute('savedObjectTitle', 'value'); + expect(title).to.equal('Bar vertical stacked'); + await testSubjects.click('saveCancelButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('unifiedHistogramSaveVisualization'); + await PageObjects.header.waitUntilLoadingHasFinished(); + title = await testSubjects.getAttribute('savedObjectTitle', 'value'); + expect(title).to.equal('Bar vertical stacked'); + }); }); } diff --git a/x-pack/test/functional/apps/index_management/create_enrich_policy/create_enrich_policy.ts b/x-pack/test/functional/apps/index_management/create_enrich_policy/create_enrich_policy.ts index 6017c202d161..3d0a1e562e45 100644 --- a/x-pack/test/functional/apps/index_management/create_enrich_policy/create_enrich_policy.ts +++ b/x-pack/test/functional/apps/index_management/create_enrich_policy/create_enrich_policy.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { @@ -24,8 +23,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { await log.debug('Creating test index'); try { - await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] }); - await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] }); await es.indices.create({ index: INDEX_NAME, body: { diff --git a/x-pack/test/functional/apps/index_management/home_page.ts b/x-pack/test/functional/apps/index_management/home_page.ts index 485a09ef7638..265707ec6da8 100644 --- a/x-pack/test/functional/apps/index_management/home_page.ts +++ b/x-pack/test/functional/apps/index_management/home_page.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants'; import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { @@ -16,7 +15,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const retry = getService('retry'); const security = getService('security'); - const es = getService('es'); describe('Home page', function () { before(async () => { @@ -96,10 +94,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('Enrich policies', () => { - before(async () => { - await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] }); - await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] }); - }); it('renders the enrich policies tab', async () => { // Navigate to the component templates tab await pageObjects.indexManagement.changeTabs('enrich_policiesTab'); diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 27cc61ca0c27..6637b7d42d22 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -146,7 +146,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '0.8%' }, { metric: 'normalizedLoad1m', value: '1.4%' }, { metric: 'memoryUsage', value: '18.0%' }, - { metric: 'diskSpaceUsage', value: '17.5%' }, + { metric: 'diskUsage', value: '17.5%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.tryForTime(3 * 1000, async () => { diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index 3a5b5a0156d5..f06ac57e893c 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -192,7 +192,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '13.9%' }, { metric: 'normalizedLoad1m', value: '18.8%' }, { metric: 'memoryUsage', value: '94.9%' }, - { metric: 'diskSpaceUsage', value: 'N/A' }, + { metric: 'diskUsage', value: 'N/A' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.try(async () => { @@ -397,7 +397,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '0.8%' }, { metric: 'normalizedLoad1m', value: '0.3%' }, { metric: 'memoryUsage', value: '16.8%' }, - { metric: 'diskSpaceUsage', value: '17.1%' }, + { metric: 'diskUsage', value: '17.1%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.try(async () => { @@ -552,7 +552,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '0.8%' }, { metric: 'normalizedLoad1m', value: '0.2%' }, { metric: 'memoryUsage', value: '16.3%' }, - { metric: 'diskSpaceUsage', value: '16.9%' }, + { metric: 'diskUsage', value: '16.9%' }, ].map(async ({ metric, value }) => { await retry.try(async () => { const tileValue = await pageObjects.infraHostsView.getKPITileValue(metric); diff --git a/x-pack/test/functional/apps/infra/index.ts b/x-pack/test/functional/apps/infra/index.ts index e34b074f8829..5ad5c004c30c 100644 --- a/x-pack/test/functional/apps/infra/index.ts +++ b/x-pack/test/functional/apps/infra/index.ts @@ -29,6 +29,7 @@ export default ({ loadTestFile }: FtrProviderContext) => { loadTestFile(require.resolve('./logs/log_stream_date_nano')); loadTestFile(require.resolve('./logs/link_to')); loadTestFile(require.resolve('./logs/log_stream')); + loadTestFile(require.resolve('./logs/ml_job_id_formats/tests')); }); }); }; diff --git a/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/assert_id_formats.ts b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/assert_id_formats.ts new file mode 100644 index 000000000000..fb89001425d9 --- /dev/null +++ b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/assert_id_formats.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { IdFormat } from '@kbn/infra-plugin/common/http_api/latest'; + +const rateHashedPattern = /logs-[0-9a-fA-F]{32,}-log-entry-rate/; +const rateLegacyPattern = /kibana-logs-ui-.*-.*-log-entry-rate/; +const categoriesCountHashedPattern = /logs-[0-9a-fA-F]{32,}-log-entry-categories-count/; +const categoriesCountLegacyPattern = /kibana-logs-ui-.*-.*-log-entry-categories-count/; + +export function assertIdFormats( + url: string, + expected: { + 'log-entry-rate': IdFormat | undefined; + 'log-entry-categories-count': IdFormat | undefined; + } +) { + const idFormats = extractIdFormats(url); + expect(idFormats).to.eql(expected); +} + +function extractIdFormats(url: string) { + let rateFormat; + if (rateHashedPattern.test(url)) { + rateFormat = 'hashed'; + } else if (rateLegacyPattern.test(url)) { + rateFormat = 'legacy'; + } + + let categoriesCountFormat; + if (categoriesCountHashedPattern.test(url)) { + categoriesCountFormat = 'hashed'; + } else if (categoriesCountLegacyPattern.test(url)) { + categoriesCountFormat = 'legacy'; + } + + return { + 'log-entry-rate': rateFormat, + 'log-entry-categories-count': categoriesCountFormat, + }; +} diff --git a/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_configs.ts b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_configs.ts new file mode 100644 index 000000000000..facd1a059d3f --- /dev/null +++ b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_configs.ts @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { setupModuleBodySchema } from '@kbn/ml-plugin/server/routes/schemas/modules'; + +export interface MlJob { + jobId: string; + module: 'logs_ui_analysis' | 'logs_ui_categories'; + config: TypeOf; +} + +const rateConfig = { + prefix: '', + start: Date.now(), + indexPatternName: 'filebeat-*', + startDatafeed: true, + useDedicatedIndex: true, + jobOverrides: [ + { + job_id: 'log-entry-rate', + analysis_config: { + bucket_span: '900000ms', + }, + data_description: { + time_field: '@timestamp', + }, + custom_settings: { + logs_source_config: { + indexPattern: 'filebeat-*', + timestampField: '@timestamp', + bucketSpan: 900000, + }, + }, + }, + ], + datafeedOverrides: [ + { + job_id: 'log-entry-rate', + runtime_mappings: {}, + }, + ], +}; + +const categoriesCountConfig = { + prefix: '', + start: Date.now(), + indexPatternName: 'filebeat-*', + startDatafeed: true, + useDedicatedIndex: true, + jobOverrides: [ + { + job_id: 'log-entry-categories-count', + analysis_config: { + bucket_span: '900000ms', + }, + data_description: { + time_field: '@timestamp', + }, + custom_settings: { + logs_source_config: { + indexPattern: 'filebeat-*', + timestampField: '@timestamp', + bucketSpan: 900000, + datasetFilter: { + type: 'includeAll', + }, + }, + }, + }, + ], + datafeedOverrides: [ + { + job_id: 'log-entry-categories-count', + runtime_mappings: {}, + }, + ], + query: { + bool: { + filter: [ + { + exists: { + field: 'message', + }, + }, + ], + }, + }, +}; + +export const hashedRateJob: MlJob = { + jobId: 'logs-11558ee526445db2b42eb3d6b4af58d0-log-entry-rate', + module: 'logs_ui_analysis', + config: { + ...rateConfig, + prefix: 'logs-11558ee526445db2b42eb3d6b4af58d0-', + }, +}; + +export const hashedCategoriesCountJob: MlJob = { + jobId: 'logs-11558ee526445db2b42eb3d6b4af58d0-log-entry-categories-count', + module: 'logs_ui_categories', + config: { + ...categoriesCountConfig, + prefix: 'logs-11558ee526445db2b42eb3d6b4af58d0-', + }, +}; + +export const legacyRateJob: MlJob = { + jobId: 'kibana-logs-ui-default-default-log-entry-rate', + module: 'logs_ui_analysis', + config: { + ...rateConfig, + prefix: 'kibana-logs-ui-default-default-', + }, +}; + +export const legacyCategoriesCountJob: MlJob = { + jobId: 'kibana-logs-ui-default-default-log-entry-categories-count', + module: 'logs_ui_categories', + config: { + ...categoriesCountConfig, + prefix: 'kibana-logs-ui-default-default-', + }, +}; diff --git a/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_helper.ts b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_helper.ts new file mode 100644 index 000000000000..7c6dcc9b5575 --- /dev/null +++ b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/ml_job_helper.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MlApi } from '../../../../services/ml/api'; +import { MlJob } from './ml_job_configs'; + +export function createMlJobHelper(ml: MlApi) { + async function createMlJobs(jobs: MlJob[]) { + for (const mlJob of jobs) { + await ml.setupModule(mlJob.module, mlJob.config, 'default'); + await ml.waitForAnomalyDetectionJobToExist(mlJob.jobId); + } + } + + async function deleteMlJobs(jobs: MlJob[]) { + for (const mlJob of jobs) { + await ml.deleteAnomalyDetectionJobES(mlJob.jobId); + await ml.waitForAnomalyDetectionJobNotToExist(mlJob.jobId); + } + } + + return { createMlJobs, deleteMlJobs }; +} + +export type MlJobHelper = ReturnType; diff --git a/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/request_tracker.ts b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/request_tracker.ts new file mode 100644 index 000000000000..fe7fb5a49b15 --- /dev/null +++ b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/request_tracker.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Browser } from '../../../../../../../test/functional/services/common/browser'; +import { CommonPageObject } from '../../../../../../../test/functional/page_objects/common_page'; + +type PerformanceResourceTimingWithHttpStatus = PerformanceResourceTiming & { + responseStatus: number; +}; + +export interface RequestLogEntry { + url: string; + timestamp: number; + status: number; +} + +declare global { + interface Window { + ftrLogsUiAnomalies?: { + requests: RequestLogEntry[]; + observer: PerformanceObserver; + }; + } +} + +export function createRequestTracker(browser: Browser, common: CommonPageObject) { + async function install() { + await browser.execute(() => { + function handleTimings(entryList: PerformanceObserverEntryList) { + const entries = entryList.getEntriesByType( + 'resource' + ) as PerformanceResourceTimingWithHttpStatus[]; + + entries + .filter((entry) => entry.initiatorType === 'fetch') + .forEach((entry) => { + if (window.ftrLogsUiAnomalies) { + window.ftrLogsUiAnomalies.requests.push({ + url: entry.name, + timestamp: entry.startTime, + status: entry.responseStatus, + }); + } else { + throw new Error('Request tracker not installed'); + } + }); + } + + const observer = new PerformanceObserver(handleTimings); + observer.observe({ type: 'resource', buffered: true }); + + window.ftrLogsUiAnomalies = { + observer, + requests: [], + }; + }); + } + + async function getRequests(pattern: RegExp, timeToWait: number = 0) { + if (timeToWait > 0) { + await common.sleep(timeToWait); + } + + // Passing RegExp to the browser doesn't seem to serialize well + // so we pass a string, but .toString returns it like /pattern/ which + // when we compile it in the browser gets escaped to /\/pattern\// + // thus we remove the surrounding slashes + const patternString = pattern.toString(); + const trimmedPattern = patternString.substring(1, patternString.length - 1); + + return await browser.execute((browserPattern: string) => { + const regExp = new RegExp(browserPattern); + if (window.ftrLogsUiAnomalies) { + const entries = window.ftrLogsUiAnomalies.requests.filter((entry) => + regExp.test(entry.url) + ); + entries.sort((a, b) => a.timestamp - b.timestamp); + return entries; + } else { + throw new Error('Request tracker not installed'); + } + }, trimmedPattern); + } + + async function uninstall() { + await browser.execute(() => { + if (window.ftrLogsUiAnomalies) { + window.ftrLogsUiAnomalies.observer.disconnect(); + delete window.ftrLogsUiAnomalies; + } else { + throw new Error('Request tracker not installed'); + } + }); + } + + return { install, getRequests, uninstall }; +} diff --git a/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/tests.ts b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/tests.ts new file mode 100644 index 000000000000..06ea712c7ccc --- /dev/null +++ b/x-pack/test/functional/apps/infra/logs/ml_job_id_formats/tests.ts @@ -0,0 +1,322 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { assertIdFormats } from './assert_id_formats'; +import { createMlJobHelper, MlJobHelper } from './ml_job_helper'; +import { createRequestTracker } from './request_tracker'; +import { + hashedRateJob, + hashedCategoriesCountJob, + legacyRateJob, + legacyCategoriesCountJob, +} from './ml_job_configs'; + +const anomalyDetectorsPattern = + /anomaly_detectors\/.*-log-entry-(rate|categories-count)\/results\/overall_buckets/; + +export default ({ getService, getPageObjects }: FtrProviderContext) => { + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const pageObjects = getPageObjects(['common']); + const logsUi = getService('logsUi'); + const ml = getService('ml'); + const requestTracker = createRequestTracker(browser, pageObjects.common); + let mlJobHelper: MlJobHelper; + + // Disabled until https://github.com/elastic/kibana/issues/171913 is addressed + describe.skip('ML job ID formats', function () { + this.beforeAll(async () => { + // Access to ml.api has to happen inside a test or test hook + mlJobHelper = createMlJobHelper(ml.api); + await esArchiver.load('x-pack/test/functional/es_archives/infra/simple_logs'); + }); + + this.afterAll(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/infra/simple_logs'); + }); + + describe('hashed format', () => { + // The hashed format always takes priority. If, for some reason, the same job exists + // in both formats, only the hashed format job will be used. + + it('loads rate job in the hashed ID format', async () => { + await mlJobHelper.createMlJobs([hashedRateJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'hashed', + 'log-entry-categories-count': undefined, + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedRateJob]); + }); + + it('loads category count job in the hashed ID format', async () => { + await mlJobHelper.createMlJobs([hashedCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': undefined, + 'log-entry-categories-count': 'hashed', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedCategoriesCountJob]); + }); + + it('loads rate and category count job in the hashed ID format', async () => { + await mlJobHelper.createMlJobs([hashedRateJob, hashedCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'hashed', + 'log-entry-categories-count': 'hashed', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedRateJob, hashedCategoriesCountJob]); + }); + }); + + describe('legacy format', () => { + it('loads rate job in the legacy ID format', async () => { + await mlJobHelper.createMlJobs([legacyRateJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'legacy', + 'log-entry-categories-count': undefined, + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([legacyRateJob]); + }); + + it('loads category count job in the legacy ID format', async () => { + await mlJobHelper.createMlJobs([legacyCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': undefined, + 'log-entry-categories-count': 'legacy', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([legacyCategoriesCountJob]); + }); + + it('loads rate and category count job in the legacy ID format', async () => { + await mlJobHelper.createMlJobs([legacyRateJob, legacyCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'legacy', + 'log-entry-categories-count': 'legacy', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([legacyRateJob, legacyCategoriesCountJob]); + }); + }); + + describe('mixed formats', () => { + it('loads rate job in the hashed format and category count job in the legacy format', async () => { + await mlJobHelper.createMlJobs([hashedRateJob, legacyCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'hashed', + 'log-entry-categories-count': 'legacy', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedRateJob, legacyCategoriesCountJob]); + }); + + it('loads rate job in the legacy format and category count job in the hashed format', async () => { + await mlJobHelper.createMlJobs([legacyRateJob, hashedCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + assertIdFormats(requests[0].url, { + 'log-entry-rate': 'legacy', + 'log-entry-categories-count': 'hashed', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([legacyRateJob, hashedCategoriesCountJob]); + }); + }); + + describe('creation and recreation', () => { + it('create first ML job', async () => { + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getSetupScreen()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.startJobSetup(); + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getSetupFlyout()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.startRateJobCreation(); + await retry.waitFor( + 'Create ML job button is enabled', + async () => await logsUi.logEntryRatePage.canCreateJob() + ); + + await logsUi.logEntryRatePage.createJob(); + await retry.waitFor( + 'ML job created', + async () => await logsUi.logEntryRatePage.jobCreationDone() + ); + + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + + assertIdFormats(requests[requests.length - 1].url, { + 'log-entry-rate': 'hashed', + 'log-entry-categories-count': undefined, + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedRateJob]); + }); + + it('create second ML job', async () => { + await mlJobHelper.createMlJobs([legacyRateJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.manageMlJobs(); + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getSetupFlyout()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.startCategoriesCountJobCreation(); + await retry.waitFor( + 'Create ML job button is enabled', + async () => await logsUi.logEntryRatePage.canCreateJob() + ); + + await logsUi.logEntryRatePage.createJob(); + await retry.waitFor( + 'ML job created', + async () => await logsUi.logEntryRatePage.jobCreationDone() + ); + + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + + assertIdFormats(requests[requests.length - 1].url, { + 'log-entry-rate': 'legacy', + 'log-entry-categories-count': 'hashed', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([legacyRateJob, hashedCategoriesCountJob]); + }); + + it('migrate legacy job', async () => { + await mlJobHelper.createMlJobs([legacyRateJob, hashedCategoriesCountJob]); + await logsUi.logEntryRatePage.navigateTo(); + await requestTracker.install(); + + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getResultsScreen()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.manageMlJobs(); + await retry.try(async () => { + expect(await logsUi.logEntryRatePage.getSetupFlyout()).to.be.ok(); + }); + + await logsUi.logEntryRatePage.startRateJobCreation(); + await retry.waitFor( + 'Recreate ML job button is enabled', + async () => await logsUi.logEntryRatePage.canRecreateJob() + ); + + await logsUi.logEntryRatePage.recreateJob(); + await retry.waitFor( + 'ML job recreated', + async () => await logsUi.logEntryRatePage.jobCreationDone() + ); + + const requests = await requestTracker.getRequests(anomalyDetectorsPattern, 2000); + expect(requests).not.to.be.empty(); + + assertIdFormats(requests[requests.length - 1].url, { + 'log-entry-rate': 'hashed', + 'log-entry-categories-count': 'hashed', + }); + + await requestTracker.uninstall(); + await mlJobHelper.deleteMlJobs([hashedRateJob, hashedCategoriesCountJob]); + }); + }); + }); +}; diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index a824106c6f61..e4cfdaae3d22 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -169,7 +169,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '13.9%' }, { metric: 'normalizedLoad1m', value: '18.8%' }, { metric: 'memoryUsage', value: '94.9%' }, - { metric: 'diskSpaceUsage', value: 'N/A' }, + { metric: 'diskUsage', value: 'N/A' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.tryForTime(3 * 1000, async () => { @@ -366,7 +366,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'cpuUsage', value: '99.6%' }, { metric: 'normalizedLoad1m', value: '1,300.3%' }, { metric: 'memoryUsage', value: '42.2%' }, - { metric: 'diskSpaceUsage', value: '36.0%' }, + { metric: 'diskUsage', value: '36.0%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.tryForTime(3 * 1000, async () => { diff --git a/x-pack/test/functional/apps/maps/group1/blended_vector_layer.js b/x-pack/test/functional/apps/maps/group1/blended_vector_layer.js index 28a68edf0e75..d142513dfd4a 100644 --- a/x-pack/test/functional/apps/maps/group1/blended_vector_layer.js +++ b/x-pack/test/functional/apps/maps/group1/blended_vector_layer.js @@ -13,6 +13,9 @@ export default function ({ getPageObjects, getService }) { const security = getService('security'); describe('blended vector layer', () => { + const LOAD_DOCUMENTS_REQUEST_NAME = 'load layer features (logstash-*)'; + const LOAD_CLUSTERS_REQUEST_NAME = 'load layer features (Clustered logstash-*)'; + before(async () => { await security.testUser.setRoles(['test_logstash_reader', 'global_maps_all']); await PageObjects.maps.loadSavedMap('blended document example'); @@ -27,20 +30,26 @@ export default function ({ getPageObjects, getService }) { }); it('should request documents when zoomed to smaller regions showing less data', async () => { - const { rawResponse: response } = await PageObjects.maps.getResponse(); + const { rawResponse: response } = await PageObjects.maps.getResponse( + LOAD_DOCUMENTS_REQUEST_NAME + ); // Allow a range of hits to account for variances in browser window size. expect(response.hits.hits.length).to.be.within(5, 12); }); it('should request clusters when zoomed to larger regions showing lots of data', async () => { await PageObjects.maps.setView(20, -90, 2); - const { rawResponse: response } = await PageObjects.maps.getResponse(); + const { rawResponse: response } = await PageObjects.maps.getResponse( + LOAD_CLUSTERS_REQUEST_NAME + ); expect(response.aggregations.gridSplit.buckets.length).to.equal(15); }); it('should request documents when query narrows data', async () => { await PageObjects.maps.setAndSubmitQuery('bytes > 19000'); - const { rawResponse: response } = await PageObjects.maps.getResponse(); + const { rawResponse: response } = await PageObjects.maps.getResponse( + LOAD_DOCUMENTS_REQUEST_NAME + ); expect(response.hits.hits.length).to.equal(75); }); }); diff --git a/x-pack/test/functional/apps/maps/group2/embeddable/dashboard.js b/x-pack/test/functional/apps/maps/group2/embeddable/dashboard.js index 2750bf3a7f68..bdc681e06eec 100644 --- a/x-pack/test/functional/apps/maps/group2/embeddable/dashboard.js +++ b/x-pack/test/functional/apps/maps/group2/embeddable/dashboard.js @@ -77,7 +77,7 @@ export default function ({ getPageObjects, getService }) { await retry.try(async () => { const joinExampleRequestNames = await inspector.getRequestNames(); expect(joinExampleRequestNames).to.equal( - 'geo_shapes* documents request,geo_shapes* term join request' + 'load layer features (geo_shapes*),load join metrics (geo_shapes*)' ); }); await inspector.close(); @@ -88,7 +88,7 @@ export default function ({ getPageObjects, getService }) { await inspector.close(); expect(singleExampleRequest).to.be(true); - expect(selectedExampleRequest).to.equal('logstash-* grid request'); + expect(selectedExampleRequest).to.equal('load layer features (logstash-*)'); }); it('should apply container state (time, query, filters) to embeddable when loaded', async () => { @@ -120,7 +120,7 @@ export default function ({ getPageObjects, getService }) { const { rawResponse: joinResponse } = await PageObjects.maps.getResponseFromDashboardPanel( 'join example', - 'geo_shapes* term join request' + 'load join metrics (geo_shapes*)' ); expect(joinResponse.aggregations.join.buckets.length).to.equal(1); }); diff --git a/x-pack/test/functional/apps/maps/group4/joins.js b/x-pack/test/functional/apps/maps/group4/joins.js index bf1304e3f347..74e68cb12c11 100644 --- a/x-pack/test/functional/apps/maps/group4/joins.js +++ b/x-pack/test/functional/apps/maps/group4/joins.js @@ -39,7 +39,7 @@ export default function ({ getPageObjects, getService }) { it('should re-fetch join with refresh timer', async () => { async function getRequestTimestamp() { - await PageObjects.maps.openInspectorRequest('geo_shapes* term join request'); + await PageObjects.maps.openInspectorRequest('load join metrics (geo_shapes*)'); const requestStats = await inspector.getTableData(); const requestTimestamp = PageObjects.maps.getInspectorStatRowHit( requestStats, @@ -122,7 +122,7 @@ export default function ({ getPageObjects, getService }) { it('should not apply query to source and apply query to join', async () => { const { rawResponse: joinResponse } = await PageObjects.maps.getResponse( - 'geo_shapes* term join request' + 'load join metrics (geo_shapes*)' ); expect(joinResponse.aggregations.join.buckets.length).to.equal(2); }); @@ -139,7 +139,7 @@ export default function ({ getPageObjects, getService }) { it('should apply query to join request', async () => { const { rawResponse: joinResponse } = await PageObjects.maps.getResponse( - 'geo_shapes* term join request' + 'load join metrics (geo_shapes*)' ); expect(joinResponse.aggregations.join.buckets.length).to.equal(1); }); diff --git a/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js b/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js index 081a1a41a93d..55e504e207d4 100644 --- a/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js +++ b/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js @@ -53,7 +53,7 @@ export default function ({ getPageObjects, getService }) { index: 'logstash-*', gridPrecision: '8', renderAs: 'grid', - requestBody: `(aggs:(max_of_bytes:(max:(field:bytes))),fields:!((field:'@timestamp',format:date_time),(field:'relatedContent.article:modified_time',format:date_time),(field:'relatedContent.article:published_time',format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((range:('@timestamp':(format:strict_date_optional_time,gte:'2015-09-20T00:00:00.000Z',lte:'2015-09-20T01:00:00.000Z')))),must:!(),must_not:!(),should:!())),runtime_mappings:())`, + requestBody: `(aggs:(max_of_bytes:(max:(field:bytes))),fields:!((field:'@timestamp',format:date_time),(field:'relatedContent.article:modified_time',format:date_time),(field:'relatedContent.article:published_time',format:date_time),(field:utc_time,format:date_time)),query:(bool:(filter:!((range:('@timestamp':(format:strict_date_optional_time,gte:'2015-09-20T00:00:00.000Z',lte:'2015-09-20T01:00:00.000Z'))),(exists:(field:geo.coordinates))),must:!(),must_not:!(),should:!())),runtime_mappings:())`, }); //Should correctly load meta for style-rule (sigma is set to 1, opacity to 1) diff --git a/x-pack/test/functional/apps/maps/group4/mvt_scaling.js b/x-pack/test/functional/apps/maps/group4/mvt_scaling.js index cd779392ba82..e624ab39dee1 100644 --- a/x-pack/test/functional/apps/maps/group4/mvt_scaling.js +++ b/x-pack/test/functional/apps/maps/group4/mvt_scaling.js @@ -55,7 +55,7 @@ export default function ({ getPageObjects, getService }) { hasLabels: 'false', index: 'geo_shapes*', requestBody: - '(fields:!(prop1),query:(bool:(filter:!(),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10001)', + '(fields:!(prop1),query:(bool:(filter:!((exists:(field:geometry))),must:!(),must_not:!(),should:!())),runtime_mappings:(),size:10001)', }); }); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_charts_dashboard_embeddables.ts b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_charts_dashboard_embeddables.ts index 9927f37a6c8f..19b48858b115 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_charts_dashboard_embeddables.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_charts_dashboard_embeddables.ts @@ -40,7 +40,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); await PageObjects.common.setTime({ from, to }); @@ -48,7 +48,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); await PageObjects.common.unsetTime(); }); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_embeddables_migration.ts b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_embeddables_migration.ts index 2760c3c13655..8e942d8e1e4b 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_embeddables_migration.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/anomaly_embeddables_migration.ts @@ -70,7 +70,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -85,7 +85,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/map_to_ml.ts b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/map_to_ml.ts index 3ce45876f77b..f77c46de6341 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/map_to_ml.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/map_to_ml.ts @@ -36,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.securityUI.loginAsMlPowerUser(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await kibanaServer.importExport.load(dashboardArchive); await browser.setWindowSize(1920, 1080); }); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/advanced_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/advanced_job.ts index 2c9c9cb7a6b9..db5be20f2e97 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/advanced_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/advanced_job.ts @@ -199,8 +199,8 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/categorization_small'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); - await ml.testResources.createIndexPatternIfNeeded('ft_categorization_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_categorization_small', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -209,8 +209,8 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); - await ml.testResources.deleteIndexPatternByTitle('ft_categorization_small'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_categorization_small'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/categorization_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/categorization_job.ts index b1939d75d05c..cbdc873286f0 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/categorization_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/categorization_job.ts @@ -86,7 +86,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/categorization_small'); - await ml.testResources.createIndexPatternIfNeeded('ft_categorization_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_categorization_small', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -95,7 +95,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_categorization_small'); + await ml.testResources.deleteDataViewByTitle('ft_categorization_small'); }); it('job creation loads the categorization wizard for the source data', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_jobs_to_advanced_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_jobs_to_advanced_job.ts index 49383315df1f..4ca0079a0e43 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_jobs_to_advanced_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_jobs_to_advanced_job.ts @@ -209,8 +209,8 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/categorization_small'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); - await ml.testResources.createIndexPatternIfNeeded('ft_categorization_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_categorization_small', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -220,8 +220,8 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); - await ml.testResources.deleteIndexPatternByTitle('ft_categorization_small'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_categorization_small'); }); describe('from multi-metric job creation wizard', function () { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_single_metric_job_to_multi_metric.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_single_metric_job_to_multi_metric.ts index c46944003003..ba90e58524bc 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_single_metric_job_to_multi_metric.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/convert_single_metric_job_to_multi_metric.ts @@ -16,16 +16,16 @@ export default function ({ getService }: FtrProviderContext) { const calendarId = `wizard-test-calendar_${Date.now()}`; const remoteName = 'ftr-remote:'; - const indexPatternName = 'ft_farequote'; - const indexPatternString = config.get('esTestCluster.ccs') - ? remoteName + indexPatternName - : indexPatternName; + const esIndexPatternName = 'ft_farequote'; + const esIndexPatternString = config.get('esTestCluster.ccs') + ? remoteName + esIndexPatternName + : esIndexPatternName; describe('single metric job conversion to multi-metric job', function () { this.tags(['ml']); before(async () => { await esNode.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternString, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(esIndexPatternString, '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -34,7 +34,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle(indexPatternString); + await ml.testResources.deleteDataViewByTitle(esIndexPatternString); }); const jobId = `fq_single_to_multi_${Date.now()}`; @@ -59,7 +59,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobManagement.navigateToNewJobSourceSelection(); await ml.testExecution.logTestStep('loads the job type selection page'); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(indexPatternString); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(esIndexPatternString); await ml.testExecution.logTestStep('loads the single metric job wizard page'); await ml.jobTypeSelection.selectSingleMetricJob(); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/custom_urls.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/custom_urls.ts index dd8b72c3504a..5a557d227094 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/custom_urls.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/custom_urls.ts @@ -69,7 +69,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); testDashboardId = await ml.testResources.createMLTestDashboardIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -80,7 +80,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.testResources.deleteMLTestDashboard(); await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('opens the custom URLs tab in the edit job flyout', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/date_nanos_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/date_nanos_job.ts index d63f6af6c048..864d89b2b08f 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/date_nanos_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/date_nanos_job.ts @@ -94,17 +94,14 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/event_rate_nanos'); - await ml.testResources.createIndexPatternIfNeeded( - 'ft_event_rate_gen_trend_nanos', - '@timestamp' - ); + await ml.testResources.createDataViewIfNeeded('ft_event_rate_gen_trend_nanos', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_event_rate_gen_trend_nanos'); + await ml.testResources.deleteDataViewByTitle('ft_event_rate_gen_trend_nanos'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/delete_job_and_delete_annotations.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/delete_job_and_delete_annotations.ts index 13ab18934f94..ebfc468ff86d 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/delete_job_and_delete_annotations.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/delete_job_and_delete_annotations.ts @@ -20,10 +20,10 @@ export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); const remoteName = 'ftr-remote:'; - const indexPatternName = 'ft_farequote'; - const indexPatternString = config.get('esTestCluster.ccs') - ? remoteName + indexPatternName - : indexPatternName; + const esIndexPatternName = 'ft_farequote'; + const esIndexPatternString = config.get('esTestCluster.ccs') + ? remoteName + esIndexPatternName + : esIndexPatternName; const testSetupJobConfigs = [SINGLE_METRIC_JOB_CONFIG, MULTI_METRIC_JOB_CONFIG]; @@ -64,7 +64,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esNode.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternString, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(esIndexPatternString, '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -72,7 +72,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle(indexPatternString); + await ml.testResources.deleteDataViewByTitle(esIndexPatternString); }); for (const { suiteTitle, jobId, deleteAnnotations, expectedAnnotations } of testConfigs) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/geo_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/geo_job.ts index daed44cce85f..35d6d40cdbe2 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/geo_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/geo_job.ts @@ -84,7 +84,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -93,7 +93,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it('job creation loads the geo wizard for the source data', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/multi_metric_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/multi_metric_job.ts index 9bbfdef22ce5..fa2e5d11eca0 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/multi_metric_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/multi_metric_job.ts @@ -84,7 +84,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -93,7 +93,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('job creation loads the multi metric wizard for the source data', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/population_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/population_job.ts index ea02186c45b7..5451ea16d8e4 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/population_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/population_job.ts @@ -98,7 +98,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -107,7 +107,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it('job creation loads the population wizard for the source data', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/saved_search_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/saved_search_job.ts index 7d9c528d763d..b8493e2daa1b 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/saved_search_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/saved_search_job.ts @@ -269,7 +269,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.createSavedSearchFarequoteFilterIfNeeded(); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); @@ -283,7 +283,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job.ts index b1575f0fa57b..7ce5d1838a1a 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job.ts @@ -75,10 +75,10 @@ export default function ({ getService }: FtrProviderContext) { const calendarId = `wizard-test-calendar_${Date.now()}`; const remoteName = 'ftr-remote:'; - const indexPatternName = 'ft_farequote'; - const indexPatternString = config.get('esTestCluster.ccs') - ? remoteName + indexPatternName - : indexPatternName; + const esIndexPatternName = 'ft_farequote'; + const esIndexPatternString = config.get('esTestCluster.ccs') + ? remoteName + esIndexPatternName + : esIndexPatternName; const fieldStatsEntries = [ { @@ -92,7 +92,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esNode.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternString, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(esIndexPatternString, '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createCalendar(calendarId); @@ -101,7 +101,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle(indexPatternString); + await ml.testResources.deleteDataViewByTitle(esIndexPatternString); }); it('job creation loads the single metric wizard for the source data', async () => { @@ -113,7 +113,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.jobManagement.navigateToNewJobSourceSelection(); await ml.testExecution.logTestStep('job creation loads the job type selection page'); - await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(indexPatternString); + await ml.jobSourceSelection.selectSourceForAnomalyDetectionJob(esIndexPatternString); await ml.testExecution.logTestStep('job creation loads the single metric job wizard page'); await ml.jobTypeSelection.selectSingleMetricJob(); @@ -230,7 +230,7 @@ export default function ({ getService }: FtrProviderContext) { it('job cloning creates a temporary data view and opens the single metric wizard if a matching data view does not exist', async () => { await ml.testExecution.logTestStep('delete data view used by job'); - await ml.testResources.deleteIndexPatternByTitle(indexPatternString); + await ml.testResources.deleteDataViewByTitle(esIndexPatternString); // Refresh page to ensure page has correct cache of data views await browser.refresh(); @@ -244,7 +244,7 @@ export default function ({ getService }: FtrProviderContext) { it('job cloning opens the existing job in the single metric wizard', async () => { await ml.testExecution.logTestStep('recreate data view used by job'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternString, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(esIndexPatternString, '@timestamp'); await ml.navigation.navigateToMl(); await ml.navigation.navigateToJobManagement(); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job_without_datafeed_start.ts b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job_without_datafeed_start.ts index 4cdea1a726fe..7d1724fbd018 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job_without_datafeed_start.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_jobs/single_metric_job_without_datafeed_start.ts @@ -60,7 +60,7 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['ml']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -68,7 +68,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('job creation loads the single metric wizard for the source data', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/aggregated_scripted_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/aggregated_scripted_job.ts index 66261321ccb8..4d9fd0bbead8 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/aggregated_scripted_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/aggregated_scripted_job.ts @@ -364,16 +364,16 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); }); after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); }); for (const testData of supportedTestSuites) { describe(testData.suiteTitle, function () { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/annotations.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/annotations.ts index 05e38d565e96..ab1177d2dbc8 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/annotations.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/annotations.ts @@ -32,7 +32,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); const JOB_CONFIG = ml.commonConfig.getADFqSingleMetricJobConfig(jobId); @@ -47,7 +47,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); describe('creating', function () { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts index 29cc28993d6c..a6e867676d10 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts @@ -76,7 +76,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.createMLTestDashboardIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -85,7 +85,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await ml.testResources.deleteMLTestDashboard(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/forecasts.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/forecasts.ts index 93ec331230a8..3a60e8fca97c 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/forecasts.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/forecasts.ts @@ -45,7 +45,7 @@ export default function ({ getService }: FtrProviderContext) { describe('with single metric job', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); @@ -54,7 +54,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('opens a job from job list link', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/single_metric_viewer.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/single_metric_viewer.ts index 809ebf204e2a..1779589a5a0c 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/single_metric_viewer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/single_metric_viewer.ts @@ -46,7 +46,7 @@ export default function ({ getService }: FtrProviderContext) { describe('with single metric job', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); @@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('opens a job from job list link', async () => { @@ -134,7 +134,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob(jobConfig, datafeedConfig); await ml.securityUI.loginAsMlPowerUser(); @@ -142,7 +142,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it('opens a job from job list link', async () => { diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts index 6dd953a84e4d..d04237195118 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts @@ -17,7 +17,7 @@ import { const testDiscoverCustomUrl: DiscoverUrlConfig = { label: 'Show data', - indexPattern: 'ft_bank_marketing', + indexName: 'ft_bank_marketing', queryEntityFieldNames: ['day'], timeRange: TIME_RANGE_TYPE.AUTO, }; @@ -43,7 +43,7 @@ export default function ({ getService }: FtrProviderContext) { let testDashboardId: string | null = null; before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/bm_classification'); - await ml.testResources.createIndexPatternIfNeeded('ft_bank_marketing'); + await ml.testResources.createDataViewIfNeeded('ft_bank_marketing'); await ml.testResources.setKibanaTimeZoneToUTC(); testDashboardId = await ml.testResources.createMLTestDashboardIfNeeded(); @@ -52,7 +52,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_bank_marketing'); + await ml.testResources.deleteDataViewByTitle('ft_bank_marketing'); }); const jobId = `bm_1_${Date.now()}`; @@ -76,7 +76,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'y', trainingPercent: 20, modelMemory: '60mb', - createIndexPattern: true, + createDataView: true, fieldStatsEntries: [ { fieldName: 'age', @@ -201,7 +201,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -314,6 +314,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -336,18 +340,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts index 1444c13192e5..307678384d47 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation_saved_search.ts @@ -18,7 +18,7 @@ export default function ({ getService }: FtrProviderContext) { describe.skip('classification saved search creation', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote_small', '@timestamp'); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); // Need to use the saved searches with filters that match multiple airlines @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + await ml.testResources.deleteDataViewByTitle('ft_farequote_small'); }); const dateNow = Date.now(); @@ -93,7 +93,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'airline', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { fieldStatsValues: { airline: ['AAL', 'AWE', 'ASA', 'ACA', 'AMX'] } as Record< string, @@ -193,7 +193,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'airline', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { fieldStatsValues: { airline: ['AAL', 'AWE', 'ASA', 'ACA', 'AMX'] } as Record< string, @@ -293,7 +293,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'airline', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { fieldStatsValues: { airline: ['AAL', 'ASA'], @@ -385,7 +385,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'airline', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { fieldStatsValues: { airline: ['ASA', 'FFT'] } as Record, source: 'ft_farequote_small', @@ -463,7 +463,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -576,6 +576,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -590,18 +594,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts index 19baea2c48c1..da62f44fb305 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts @@ -19,7 +19,7 @@ export default function ({ getService }: FtrProviderContext) { const testDataList: Array<{ suiteTitle: string; archive: string; - indexPattern: { name: string; timeField: string }; + dataView: { name: string; timeField: string }; job: DeepPartial; }> = (() => { const timestamp = Date.now(); @@ -28,7 +28,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'classification job supported by the form', archive: 'x-pack/test/functional/es_archives/ml/bm_classification', - indexPattern: { name: 'ft_bank_marketing', timeField: '@timestamp' }, + dataView: { name: 'ft_bank_marketing', timeField: '@timestamp' }, job: { id: `bm_1_${timestamp}`, description: @@ -63,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'outlier detection job supported by the form', archive: 'x-pack/test/functional/es_archives/ml/ihp_outlier', - indexPattern: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, + dataView: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, job: { id: `ihp_1_${timestamp}`, description: 'This is the job description', @@ -92,7 +92,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'regression job supported by the form', archive: 'x-pack/test/functional/es_archives/ml/egs_regression', - indexPattern: { name: 'ft_egs_regression', timeField: '@timestamp' }, + dataView: { name: 'ft_egs_regression', timeField: '@timestamp' }, job: { id: `egs_1_${timestamp}`, description: 'This is the job description', @@ -141,9 +141,9 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded(testData.archive); - await ml.testResources.createIndexPatternIfNeeded( - testData.indexPattern.name, - testData.indexPattern.timeField + await ml.testResources.createDataViewIfNeeded( + testData.dataView.name, + testData.dataView.timeField ); await ml.api.createDataFrameAnalyticsJob(testData.job as DataFrameAnalyticsConfig); @@ -157,9 +157,9 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.deleteIndices(cloneDestIndex); await ml.api.deleteIndices(testData.job.dest!.index as string); - await ml.testResources.deleteIndexPatternByTitle(testData.job.dest!.index as string); - await ml.testResources.deleteIndexPatternByTitle(cloneDestIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.indexPattern.name); + await ml.testResources.deleteDataViewByTitle(testData.job.dest!.index as string); + await ml.testResources.deleteDataViewByTitle(cloneDestIndex); + await ml.testResources.deleteDataViewByTitle(testData.dataView.name); }); it('opens the existing job in the data frame analytics job wizard', async () => { diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/custom_urls.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/custom_urls.ts index a5dad1827d27..dac2d1ae1fa3 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/custom_urls.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/custom_urls.ts @@ -15,7 +15,7 @@ import { const testDiscoverCustomUrl: DiscoverUrlConfig = { label: 'Show data', - indexPattern: 'ft_farequote', + indexName: 'ft_farequote', queryEntityFieldNames: ['airline'], timeRange: TIME_RANGE_TYPE.AUTO, }; @@ -70,7 +70,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); await ml.api.createAndRunDFAJob(dfaJobConfig); @@ -79,7 +79,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); await ml.api.deleteIndices('user-farequote_small'); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); describe('run custom urls', function () { diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts index 8b4514add92c..c639b16dbb89 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts @@ -17,7 +17,7 @@ import { const testDiscoverCustomUrl: DiscoverUrlConfig = { label: 'Show data', - indexPattern: 'ft_ihp_outlier', + indexName: 'ft_ihp_outlier', queryEntityFieldNames: ['SaleType'], timeRange: TIME_RANGE_TYPE.AUTO, }; @@ -44,7 +44,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier'); testDashboardId = await ml.testResources.createMLTestDashboardIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -53,7 +53,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'); + await ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'); }); const jobId = `ihp_1_${Date.now()}`; @@ -83,7 +83,7 @@ export default function ({ getService }: FtrProviderContext) { }, }, modelMemory: '5mb', - createIndexPattern: true, + createDataView: true, advancedEditorContent: [ '{', ' "description": "Outlier detection job based on ft_ihp_outlier dataset with runtime fields",', @@ -192,7 +192,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -305,6 +305,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -322,18 +326,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts index a6f68a8eafd0..93478ebbb766 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation_saved_search.ts @@ -16,7 +16,7 @@ export default function ({ getService }: FtrProviderContext) { describe('outlier detection saved search creation', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote_small', '@timestamp'); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded( @@ -31,7 +31,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + await ml.testResources.deleteDataViewByTitle('ft_farequote_small'); }); const dateNow = Date.now(); @@ -63,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) { }, }, modelMemory: '1mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', histogramCharts: [ @@ -140,7 +140,7 @@ export default function ({ getService }: FtrProviderContext) { }, }, modelMemory: '65mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', histogramCharts: [ @@ -217,7 +217,7 @@ export default function ({ getService }: FtrProviderContext) { }, }, modelMemory: '65mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', histogramCharts: [ @@ -295,7 +295,7 @@ export default function ({ getService }: FtrProviderContext) { }, }, modelMemory: '65mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', histogramCharts: [ @@ -362,7 +362,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -452,6 +452,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -461,18 +465,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts index b4ed75c35043..6978452afdc3 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { const testDiscoverCustomUrl: DiscoverUrlConfig = { label: 'Show data', - indexPattern: 'ft_egs_regression', + indexName: 'ft_egs_regression', queryEntityFieldNames: ['stabf'], timeRange: TIME_RANGE_TYPE.AUTO, }; @@ -57,7 +57,7 @@ export default function ({ getService }: FtrProviderContext) { let testDashboardId: string | null = null; before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/egs_regression'); - await ml.testResources.createIndexPatternIfNeeded('ft_egs_regression'); + await ml.testResources.createDataViewIfNeeded('ft_egs_regression'); await ml.testResources.setKibanaTimeZoneToUTC(); testDashboardId = await ml.testResources.createMLTestDashboardIfNeeded(); @@ -66,7 +66,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_egs_regression'); + await ml.testResources.deleteDataViewByTitle('ft_egs_regression'); }); const jobId = `egs_1_${Date.now()}`; @@ -90,7 +90,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'stab', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, advancedEditorContent: [ '{', ' "description": "Regression job based on ft_egs_regression dataset with runtime fields",', @@ -197,7 +197,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -320,6 +320,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -337,18 +341,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts index 043f546dea69..fb5702e98ac1 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation_saved_search.ts @@ -16,7 +16,7 @@ export default function ({ getService }: FtrProviderContext) { describe('regression saved search creation', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote_small'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote_small', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote_small', '@timestamp'); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded('ft_farequote_small'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded('ft_farequote_small'); await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded( @@ -31,7 +31,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote_small'); + await ml.testResources.deleteDataViewByTitle('ft_farequote_small'); }); const dateNow = Date.now(); @@ -73,7 +73,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'responsetime', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], @@ -161,7 +161,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'responsetime', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], @@ -249,7 +249,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'responsetime', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], @@ -331,7 +331,7 @@ export default function ({ getService }: FtrProviderContext) { dependentVariable: 'responsetime', trainingPercent: 20, modelMemory: '20mb', - createIndexPattern: true, + createDataView: true, expected: { source: 'ft_farequote_small', runtimeFieldsEditorContent: ['{', ' "uppercase_airline": {', ' "type": "keyword",'], @@ -401,7 +401,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await ml.api.deleteIndices(testData.destinationIndex); - await ml.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await ml.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the data frame analytics wizard', async () => { @@ -487,6 +487,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertDestIndexInputExists(); await ml.dataFrameAnalyticsCreation.setDestIndex(testData.destinationIndex); + await ml.testExecution.logTestStep('displays the create data view switch'); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchExists(); + await ml.dataFrameAnalyticsCreation.assertCreateDataViewSwitchCheckState(true); + await ml.testExecution.logTestStep('continues to the validation step'); await ml.dataFrameAnalyticsCreation.continueToValidationStep(); @@ -496,18 +500,12 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); - - await ml.testExecution.logTestStep('sets the create data view switch'); - await ml.dataFrameAnalyticsCreation.assertCreateIndexPatternSwitchExists(); - await ml.dataFrameAnalyticsCreation.setCreateIndexPatternSwitchState( - testData.createIndexPattern - ); }); it('runs the analytics job and displays it correctly in the job list', async () => { await ml.testExecution.logTestStep('creates and starts the analytics job'); await ml.dataFrameAnalyticsCreation.assertCreateButtonExists(); - await ml.dataFrameAnalyticsCreation.assertStartJobCheckboxCheckState(true); + await ml.dataFrameAnalyticsCreation.assertStartJobSwitchCheckState(true); await ml.dataFrameAnalyticsCreation.createAnalyticsJob(testData.jobId); await ml.testExecution.logTestStep('finishes analytics processing'); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/results_view_content.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/results_view_content.ts index 77cae02f3cfc..7ccf329222a5 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/results_view_content.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/results_view_content.ts @@ -18,7 +18,7 @@ export default function ({ getService }: FtrProviderContext) { const testDataList: Array<{ suiteTitle: string; archive: string; - indexPattern: { name: string; timeField: string }; + dataView: { name: string; timeField: string }; job: DeepPartial; sortBy: { column: string; @@ -38,7 +38,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'binary classification job', archive: 'x-pack/test/functional/es_archives/ml/ihp_outlier', - indexPattern: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, + dataView: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, job: { id: `ihp_fi_binary_${timestamp}`, description: @@ -107,7 +107,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'multi class classification job', archive: 'x-pack/test/functional/es_archives/ml/ihp_outlier', - indexPattern: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, + dataView: { name: 'ft_ihp_outlier', timeField: '@timestamp' }, job: { id: `ihp_fi_multi_${timestamp}`, description: @@ -178,7 +178,7 @@ export default function ({ getService }: FtrProviderContext) { { suiteTitle: 'regression job', archive: 'x-pack/test/functional/es_archives/ml/egs_regression', - indexPattern: { name: 'ft_egs_regression', timeField: '@timestamp' }, + dataView: { name: 'ft_egs_regression', timeField: '@timestamp' }, job: { id: `egs_fi_reg_${timestamp}`, description: 'This is the job description', @@ -252,9 +252,9 @@ export default function ({ getService }: FtrProviderContext) { await ml.securityUI.loginAsMlPowerUser(); for (const testData of testDataList) { await esArchiver.loadIfNeeded(testData.archive); - await ml.testResources.createIndexPatternIfNeeded( - testData.indexPattern.name, - testData.indexPattern.timeField + await ml.testResources.createDataViewIfNeeded( + testData.dataView.name, + testData.dataView.timeField ); await ml.api.createAndRunDFAJob(testData.job as DataFrameAnalyticsConfig); } @@ -263,7 +263,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); for (const testData of testDataList) { - await ml.testResources.deleteIndexPatternByTitle(testData.indexPattern.name); + await ml.testResources.deleteDataViewByTitle(testData.dataView.name); } }); @@ -273,13 +273,13 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataFrameAnalytics(); await ml.dataFrameAnalyticsTable.waitForAnalyticsToLoad(); - await ml.testResources.createIndexPatternIfNeeded(testData.job.dest!.index as string); + await ml.testResources.createDataViewIfNeeded(testData.job.dest!.index as string); await ml.dataFrameAnalyticsTable.openResultsView(testData.job.id as string); }); after(async () => { await ml.api.deleteIndices(testData.job.dest!.index as string); - await ml.testResources.deleteIndexPatternByTitle(testData.job.dest!.index as string); + await ml.testResources.deleteDataViewByTitle(testData.job.dest!.index as string); }); it('should display the total feature importance in the results view', async () => { diff --git a/x-pack/test/functional/apps/ml/data_visualizer/data_drift.ts b/x-pack/test/functional/apps/ml/data_visualizer/data_drift.ts index 5195997c3ba3..bec899910441 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/data_drift.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/data_drift.ts @@ -84,10 +84,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('data drift', async function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -97,10 +97,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload('x-pack/test/functional/es_archives/ml/ihp_outlier'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await Promise.all([ - ml.testResources.deleteIndexPatternByTitle('ft_fare*'), - ml.testResources.deleteIndexPatternByTitle('ft_fare*,ft_fareq*'), - ml.testResources.deleteIndexPatternByTitle('ft_farequote'), - ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'), + ml.testResources.deleteDataViewByTitle('ft_fare*'), + ml.testResources.deleteDataViewByTitle('ft_fare*,ft_fareq*'), + ml.testResources.deleteDataViewByTitle('ft_farequote'), + ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'), ]); }); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer.ts index 073023ed6b5d..f0185fc37100 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer.ts @@ -26,7 +26,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the index data visualizer page` @@ -147,8 +147,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/module_sample_logs'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_module_sample_logs', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_module_sample_logs', '@timestamp'); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); @@ -159,8 +159,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { after(async () => { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_logs'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_logs'); }); describe('with farequote', function () { @@ -223,7 +223,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the index data visualizer page` diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_actions_panel.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_actions_panel.ts index c7e00f8ed5b5..6f259a8120d2 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_actions_panel.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_actions_panel.ts @@ -14,7 +14,7 @@ export default function ({ getService }: FtrProviderContext) { describe('index based actions panel on trial license', function () { this.tags(['ml']); - const indexPatternName = 'ft_farequote'; + const esIndexName = 'ft_farequote'; const advancedJobWizardDatafeedQuery = JSON.stringify( { @@ -33,7 +33,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternName, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(esIndexName, '@timestamp'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -42,7 +42,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle(indexPatternName); + await ml.testResources.deleteDataViewByTitle(esIndexName); }); describe('create advanced job action', function () { @@ -52,10 +52,10 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToDataVisualizer(); await ml.testExecution.logTestStep('loads the saved search selection page'); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep('loads the index data visualizer page'); - await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(indexPatternName); + await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(esIndexName); }); it('opens the advanced job wizard', async () => { @@ -84,7 +84,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToDataVisualizer(); await ml.testExecution.logTestStep('loads the saved search selection page'); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep('loads the index data visualizer page'); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(savedSearch); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_data_view_management.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_data_view_management.ts index 6f15f5a33274..28611dbcb8a1 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_data_view_management.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_data_view_management.ts @@ -118,7 +118,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the index data visualizer page` @@ -182,12 +182,12 @@ export default function ({ getService }: FtrProviderContext) { }); beforeEach(async () => { - await ml.testResources.createIndexPatternIfNeeded(indexPatternTitle, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(indexPatternTitle, '@timestamp'); await navigateToIndexDataVisualizer(originalTestData); }); afterEach(async () => { - await ml.testResources.deleteIndexPatternByTitle(indexPatternTitle); + await ml.testResources.deleteDataViewByTitle(indexPatternTitle); }); it(`adds new field`, async () => { diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts index be8c06028685..4be111e00bc8 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts @@ -54,7 +54,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the index data visualizer page` @@ -91,7 +91,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the saved search selection page` ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep( `${testData.suiteTitle} loads the index data visualizer page` @@ -124,7 +124,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('data visualizer with pinned global filters', function () { before(async function () { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); @@ -133,7 +133,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async function () { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); describe(`with ${farequoteDataViewTestData.suiteTitle}`, function () { diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_dashboard.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_dashboard.ts index 47c6e7725686..7d38012c3651 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_dashboard.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_dashboard.ts @@ -115,7 +115,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('field statistics in Dashboard', function () { before(async function () { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); await ml.securityUI.loginAsMlPowerUser(); }); @@ -123,7 +123,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async function () { await ml.testResources.clearAdvancedSettingProperty(SHOW_FIELD_STATISTICS); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); runTests(farequoteLuceneFiltersSearchTestData); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts index c0c7a47414ce..34a8d59cc214 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts @@ -96,8 +96,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async function () { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/module_sample_logs'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_module_sample_logs', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_module_sample_logs', '@timestamp'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); @@ -109,8 +109,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async function () { await ml.testResources.clearAdvancedSettingProperty(SHOW_FIELD_STATISTICS); await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_logs'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_logs'); }); describe('when enabled', function () { diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_random_sampler.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_random_sampler.ts index ce74bbfb8884..e5fee365ff08 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_random_sampler.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_random_sampler.ts @@ -17,7 +17,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.navigation.navigateToDataVisualizer(); await ml.testExecution.logTestStep(`loads the saved search selection page`); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep(`loads the index data visualizer page`); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(sourceIndexOrSavedSearch); @@ -28,8 +28,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/module_sample_logs'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_module_sample_logs', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_module_sample_logs', '@timestamp'); await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -40,8 +40,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { after(async () => { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_logs'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_logs'); await browser.removeLocalStorageItem('dataVisualizer.randomSamplerPreference'); }); diff --git a/x-pack/test/functional/apps/ml/permissions/full_ml_access.ts b/x-pack/test/functional/apps/ml/permissions/full_ml_access.ts index 1c289dd66f0e..b986d29c7fee 100644 --- a/x-pack/test/functional/apps/ml/permissions/full_ml_access.ts +++ b/x-pack/test/functional/apps/ml/permissions/full_ml_access.ts @@ -132,9 +132,9 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier', '@timestamp'); + await ml.testResources.createDataViewIfNeeded(ecIndexPattern, 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob( @@ -170,9 +170,9 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.deleteCalendar(calendarId); await ml.api.deleteFilter(filterId); await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'); - await ml.testResources.deleteIndexPatternByTitle(ecIndexPattern); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'); + await ml.testResources.deleteDataViewByTitle(ecIndexPattern); }); for (const testUser of testUsers) { @@ -387,7 +387,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.testExecution.logTestStep( 'should load an index into the data visualizer page' ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexPattern); await ml.testExecution.logTestStep('should display the time range step'); diff --git a/x-pack/test/functional/apps/ml/permissions/read_ml_access.ts b/x-pack/test/functional/apps/ml/permissions/read_ml_access.ts index 960c3a6a4b0b..7ffdf2286439 100644 --- a/x-pack/test/functional/apps/ml/permissions/read_ml_access.ts +++ b/x-pack/test/functional/apps/ml/permissions/read_ml_access.ts @@ -138,9 +138,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier', '@timestamp'); + await ml.testResources.createDataViewIfNeeded(ecIndexPattern, 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.api.createAndRunAnomalyDetectionLookbackJob( @@ -176,9 +176,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.api.deleteCalendar(calendarId); await ml.api.deleteFilter(filterId); await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'); - await ml.testResources.deleteIndexPatternByTitle(ecIndexPattern); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'); + await ml.testResources.deleteDataViewByTitle(ecIndexPattern); }); for (const testUser of testUsers) { @@ -378,7 +378,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.testExecution.logTestStep( 'should load an index into the data visualizer page' ); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexPattern); await ml.testExecution.logTestStep('should display the time range step'); diff --git a/x-pack/test/functional/apps/ml/short_tests/model_management/model_list.ts b/x-pack/test/functional/apps/ml/short_tests/model_management/model_list.ts index 5a50a34b4ee1..ebcdfbeb4b17 100644 --- a/x-pack/test/functional/apps/ml/short_tests/model_management/model_list.ts +++ b/x-pack/test/functional/apps/ml/short_tests/model_management/model_list.ts @@ -120,7 +120,7 @@ export default function ({ getService }: FtrProviderContext) { // Need to delete index before ingest pipeline, else it will give error await ml.api.deleteIngestPipeline(modelWithPipelineAndDestIndex.modelId); - await ml.testResources.deleteIndexPatternByTitle( + await ml.testResources.deleteDataViewByTitle( modelWithPipelineAndDestIndexExpectedValues.dataViewTitle ); }); diff --git a/x-pack/test/functional/apps/ml/short_tests/notifications/notification_list.ts b/x-pack/test/functional/apps/ml/short_tests/notifications/notification_list.ts index 062b2809c375..e4511615a51a 100644 --- a/x-pack/test/functional/apps/ml/short_tests/notifications/notification_list.ts +++ b/x-pack/test/functional/apps/ml/short_tests/notifications/notification_list.ts @@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Notifications list', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -54,7 +54,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await spacesService.delete(idSpace1); await ml.api.cleanMlIndices(); await ml.testResources.cleanMLSavedObjects(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('displays a generic notification indicator', async () => { diff --git a/x-pack/test/functional/apps/ml/short_tests/settings/calendar_creation.ts b/x-pack/test/functional/apps/ml/short_tests/settings/calendar_creation.ts index 91121528d477..32fe57b44275 100644 --- a/x-pack/test/functional/apps/ml/short_tests/settings/calendar_creation.ts +++ b/x-pack/test/functional/apps/ml/short_tests/settings/calendar_creation.ts @@ -18,7 +18,7 @@ export default function ({ getService }: FtrProviderContext) { describe('calendar creation', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await asyncForEach(jobConfigs, async (jobConfig) => { // @ts-expect-error not full interface @@ -30,7 +30,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); afterEach(async () => { diff --git a/x-pack/test/functional/apps/ml/short_tests/settings/calendar_edit.ts b/x-pack/test/functional/apps/ml/short_tests/settings/calendar_edit.ts index 9f68ccc8a119..f7c1497b2b56 100644 --- a/x-pack/test/functional/apps/ml/short_tests/settings/calendar_edit.ts +++ b/x-pack/test/functional/apps/ml/short_tests/settings/calendar_edit.ts @@ -24,7 +24,7 @@ export default function ({ getService }: FtrProviderContext) { describe('calendar edit', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await asyncForEach(jobConfigs, async (jobConfig) => { // @ts-expect-error not full interface @@ -43,7 +43,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); afterEach(async () => { diff --git a/x-pack/test/functional/apps/ml/stack_management_jobs/export_jobs.ts b/x-pack/test/functional/apps/ml/stack_management_jobs/export_jobs.ts index 6976b4db4eda..0ddb7da85c52 100644 --- a/x-pack/test/functional/apps/ml/stack_management_jobs/export_jobs.ts +++ b/x-pack/test/functional/apps/ml/stack_management_jobs/export_jobs.ts @@ -257,16 +257,16 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await ml.api.cleanMlIndices(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/bm_classification'); - await ml.testResources.createIndexPatternIfNeeded('ft_bank_marketing', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_bank_marketing', '@timestamp'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier', '@timestamp'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/egs_regression'); - await ml.testResources.createIndexPatternIfNeeded('ft_egs_regression', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_egs_regression', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -289,10 +289,10 @@ export default function ({ getService }: FtrProviderContext) { 'anomaly_detection_jobs', 'data_frame_analytics_jobs', ]); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_bank_marketing'); - await ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'); - await ml.testResources.deleteIndexPatternByTitle('ft_egs_regression'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_bank_marketing'); + await ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'); + await ml.testResources.deleteDataViewByTitle('ft_egs_regression'); }); it('opens export flyout and exports anomaly detector jobs', async () => { diff --git a/x-pack/test/functional/apps/ml/stack_management_jobs/import_jobs.ts b/x-pack/test/functional/apps/ml/stack_management_jobs/import_jobs.ts index b4782e37596e..8a3fa058fe25 100644 --- a/x-pack/test/functional/apps/ml/stack_management_jobs/import_jobs.ts +++ b/x-pack/test/functional/apps/ml/stack_management_jobs/import_jobs.ts @@ -36,8 +36,8 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.cleanMlIndices(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/bm_classification'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_bank_marketing', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_bank_marketing', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -47,8 +47,8 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await ml.api.cleanMlIndices(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_bank_marketing'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_bank_marketing'); }); for (const testData of testDataListPositive) { diff --git a/x-pack/test/functional/apps/ml/stack_management_jobs/manage_spaces.ts b/x-pack/test/functional/apps/ml/stack_management_jobs/manage_spaces.ts index 55b2bdfa1206..06ec8e19b10c 100644 --- a/x-pack/test/functional/apps/ml/stack_management_jobs/manage_spaces.ts +++ b/x-pack/test/functional/apps/ml/stack_management_jobs/manage_spaces.ts @@ -111,8 +111,8 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -137,8 +137,8 @@ export default function ({ getService }: FtrProviderContext) { } await ml.api.cleanMlIndices(); await ml.testResources.cleanMLSavedObjects([spaceIds.idSpace1]); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_ihp_outlier'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_ihp_outlier'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/ml/stack_management_jobs/synchronize.ts b/x-pack/test/functional/apps/ml/stack_management_jobs/synchronize.ts index 317a71ae79a0..42a462d25981 100644 --- a/x-pack/test/functional/apps/ml/stack_management_jobs/synchronize.ts +++ b/x-pack/test/functional/apps/ml/stack_management_jobs/synchronize.ts @@ -24,7 +24,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); @@ -40,7 +40,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.deleteDataFrameAnalyticsJobES(dfaJobId); } await ml.testResources.cleanMLSavedObjects(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); }); it('should have nothing to sync initially', async () => { diff --git a/x-pack/test/functional/apps/transform/actions/deleting.ts b/x-pack/test/functional/apps/transform/actions/deleting.ts index 80a00e0b09df..911c656e9fd5 100644 --- a/x-pack/test/functional/apps/transform/actions/deleting.ts +++ b/x-pack/test/functional/apps/transform/actions/deleting.ts @@ -65,7 +65,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); for (const testData of testDataList) { await transform.api.createAndRunTransform( @@ -80,11 +80,11 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { for (const testData of testDataList) { - await transform.testResources.deleteIndexPatternByTitle(testData.originalConfig.dest.index); + await transform.testResources.deleteDataViewByTitle(testData.originalConfig.dest.index); await transform.api.deleteIndices(testData.originalConfig.dest.index); } await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/transform/actions/reauthorizing.ts b/x-pack/test/functional/apps/transform/actions/reauthorizing.ts index 9f731f6947cb..f256e902eac9 100644 --- a/x-pack/test/functional/apps/transform/actions/reauthorizing.ts +++ b/x-pack/test/functional/apps/transform/actions/reauthorizing.ts @@ -138,7 +138,7 @@ export default function ({ getService }: FtrProviderContext) { ); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); for (const testData of testDataList) { await transform.api.createTransform(testData.originalConfig.id, testData.originalConfig, { @@ -157,12 +157,12 @@ export default function ({ getService }: FtrProviderContext) { await transform.securityCommon.clearAllTransformApiKeys(); for (const testData of testDataList) { - await transform.testResources.deleteIndexPatternByTitle(testData.originalConfig.dest.index); + await transform.testResources.deleteDataViewByTitle(testData.originalConfig.dest.index); await transform.api.deleteIndices(testData.originalConfig.dest.index); } await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/transform/actions/resetting.ts b/x-pack/test/functional/apps/transform/actions/resetting.ts index c6e5180dfa8f..b62772f63454 100644 --- a/x-pack/test/functional/apps/transform/actions/resetting.ts +++ b/x-pack/test/functional/apps/transform/actions/resetting.ts @@ -67,7 +67,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); for (const testData of testDataList) { await transform.api.createAndRunTransform( @@ -82,11 +82,11 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { for (const testData of testDataList) { - await transform.testResources.deleteIndexPatternByTitle(testData.originalConfig.dest.index); + await transform.testResources.deleteDataViewByTitle(testData.originalConfig.dest.index); await transform.api.deleteIndices(testData.originalConfig.dest.index); } await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/transform/actions/starting.ts b/x-pack/test/functional/apps/transform/actions/starting.ts index 2cccd4525856..2ecd345ac0e1 100644 --- a/x-pack/test/functional/apps/transform/actions/starting.ts +++ b/x-pack/test/functional/apps/transform/actions/starting.ts @@ -110,7 +110,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); for (const testData of testDataList) { if ( @@ -135,12 +135,12 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { for (const testData of testDataList) { - await transform.testResources.deleteIndexPatternByTitle(testData.originalConfig.dest.index); + await transform.testResources.deleteDataViewByTitle(testData.originalConfig.dest.index); await transform.api.deleteIndices(testData.originalConfig.dest.index); } await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts b/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts index e56d06e15a62..24a3874eddec 100644 --- a/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts +++ b/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts @@ -36,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); const DEFAULT_NUM_FAILURE_RETRIES = '5'; @@ -326,7 +326,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { await transform.api.deleteIndices(testData.destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the wizard for the source data', async () => { @@ -440,9 +440,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionValue(''); await transform.wizard.setTransformDescription(testData.transformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); - await transform.wizard.assertDestinationIndexValue(''); + await transform.wizard.assertDestinationIndexValue(testData.transformId); await transform.wizard.setDestinationIndex(testData.destinationIndex); await transform.testExecution.logTestStep('displays the create data view switch'); diff --git a/x-pack/test/functional/apps/transform/creation/index_pattern/creation_index_pattern.ts b/x-pack/test/functional/apps/transform/creation/index_pattern/creation_index_pattern.ts index 69406c583042..9e5c1e4f1b08 100644 --- a/x-pack/test/functional/apps/transform/creation/index_pattern/creation_index_pattern.ts +++ b/x-pack/test/functional/apps/transform/creation/index_pattern/creation_index_pattern.ts @@ -25,7 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('creation_index_pattern', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await transform.testResources.setKibanaTimeZoneToUTC(); await transform.securityUI.loginAsTransformPowerUser(); @@ -33,7 +33,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); await transform.securityUI.logout(); }); @@ -509,7 +509,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await transform.api.deleteIndices(testData.destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the wizard for the source data', async () => { @@ -727,9 +727,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionValue(''); await transform.wizard.setTransformDescription(testData.transformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); - await transform.wizard.assertDestinationIndexValue(''); + await transform.wizard.assertDestinationIndexValue(testData.transformId); await transform.wizard.setDestinationIndex(testData.destinationIndex); await transform.testExecution.logTestStep('displays the create data view switch'); diff --git a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts index 3f0adc578389..bbdf53b3eda5 100644 --- a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts +++ b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts @@ -37,7 +37,7 @@ export default function ({ getService }: FtrProviderContext) { describe('creation with runtime mappings', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await transform.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await transform.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await transform.testResources.setKibanaTimeZoneToUTC(); await transform.securityUI.loginAsTransformPowerUser(); @@ -45,7 +45,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_farequote'); + await transform.testResources.deleteDataViewByTitle('ft_farequote'); }); const histogramCharts: HistogramCharts = [ @@ -254,7 +254,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await transform.api.deleteIndices(testData.destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the wizard for the source data', async () => { @@ -406,9 +406,16 @@ export default function ({ getService }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionValue(''); await transform.wizard.setTransformDescription(testData.transformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); - await transform.wizard.assertDestinationIndexValue(''); + await transform.wizard.assertDestinationIndexValue(testData.transformId); await transform.wizard.setDestinationIndex(testData.destinationIndex); await transform.testExecution.logTestStep('displays the create data view switch'); diff --git a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_saved_search.ts b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_saved_search.ts index c976be55a788..c85a1a88b429 100644 --- a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_saved_search.ts +++ b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_saved_search.ts @@ -23,7 +23,7 @@ export default function ({ getService }: FtrProviderContext) { describe('creation_saved_search', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await transform.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await transform.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); await transform.testResources.createSavedSearchFarequoteFilterIfNeeded(); await transform.testResources.setKibanaTimeZoneToUTC(); @@ -33,7 +33,7 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { await transform.api.cleanTransformIndices(); await transform.testResources.deleteSavedSearches(); - await transform.testResources.deleteIndexPatternByTitle('ft_farequote'); + await transform.testResources.deleteDataViewByTitle('ft_farequote'); }); const testDataList: Array = [ @@ -121,7 +121,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await transform.api.deleteIndices(testData.destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('loads the wizard for the source data', async () => { @@ -239,9 +239,16 @@ export default function ({ getService }: FtrProviderContext) { await transform.wizard.assertTransformDescriptionValue(''); await transform.wizard.setTransformDescription(testData.transformDescription); - await transform.testExecution.logTestStep('inputs the destination index'); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); - await transform.wizard.assertDestinationIndexValue(''); + await transform.wizard.assertDestinationIndexValue(testData.transformId); await transform.wizard.setDestinationIndex(testData.destinationIndex); await transform.testExecution.logTestStep('displays the create data view switch'); diff --git a/x-pack/test/functional/apps/transform/edit_clone/cloning.ts b/x-pack/test/functional/apps/transform/edit_clone/cloning.ts index caa6552024e1..3146548b8bbc 100644 --- a/x-pack/test/functional/apps/transform/edit_clone/cloning.ts +++ b/x-pack/test/functional/apps/transform/edit_clone/cloning.ts @@ -199,7 +199,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await transform.api.createAndRunTransform( transformConfigWithPivot.id, transformConfigWithPivot @@ -223,17 +223,17 @@ export default function ({ getService }: FtrProviderContext) { }); after(async () => { - await transform.testResources.deleteIndexPatternByTitle(transformConfigWithPivot.dest.index); - await transform.testResources.deleteIndexPatternByTitle( + await transform.testResources.deleteDataViewByTitle(transformConfigWithPivot.dest.index); + await transform.testResources.deleteDataViewByTitle( transformConfigWithRuntimeMapping.dest.index ); - await transform.testResources.deleteIndexPatternByTitle(transformConfigWithLatest.dest.index); + await transform.testResources.deleteDataViewByTitle(transformConfigWithLatest.dest.index); await transform.api.deleteIndices(transformConfigWithPivot.dest.index); await transform.api.deleteIndices(transformConfigWithRuntimeMapping.dest.index); await transform.api.deleteIndices(transformConfigWithLatest.dest.index); await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); const testDataList: TestData[] = [ @@ -397,7 +397,7 @@ export default function ({ getService }: FtrProviderContext) { describe(`${testData.suiteTitle}`, function () { after(async () => { await transform.api.deleteIndices(testData.destinationIndex); - await transform.testResources.deleteIndexPatternByTitle(testData.destinationIndex); + await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); }); it('opens the existing transform in the wizard', async () => { @@ -517,9 +517,16 @@ export default function ({ getService }: FtrProviderContext) { ); await transform.wizard.setTransformDescription(testData.transformDescription); + await transform.testExecution.logTestStep( + 'should default the set destination index to job id switch to true' + ); + await transform.wizard.assertDestIndexSameAsIdSwitchExists(); + await transform.wizard.assertDestIndexSameAsIdCheckState(true); + await transform.testExecution.logTestStep('should input the destination index'); + await transform.wizard.setDestIndexSameAsIdCheckState(false); await transform.wizard.assertDestinationIndexInputExists(); - await transform.wizard.assertDestinationIndexValue(''); + await transform.wizard.assertDestinationIndexValue(testData.transformId); await transform.wizard.setDestinationIndex(testData.destinationIndex); await transform.testExecution.logTestStep('should display the create data view switch'); diff --git a/x-pack/test/functional/apps/transform/edit_clone/editing.ts b/x-pack/test/functional/apps/transform/edit_clone/editing.ts index 10cacc361779..1a8394ca9a66 100644 --- a/x-pack/test/functional/apps/transform/edit_clone/editing.ts +++ b/x-pack/test/functional/apps/transform/edit_clone/editing.ts @@ -27,7 +27,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await transform.api.createAndRunTransform( transformConfigWithPivot.id, @@ -43,12 +43,12 @@ export default function ({ getService }: FtrProviderContext) { }); after(async () => { - await transform.testResources.deleteIndexPatternByTitle(transformConfigWithPivot.dest.index); + await transform.testResources.deleteDataViewByTitle(transformConfigWithPivot.dest.index); await transform.api.deleteIndices(transformConfigWithPivot.dest.index); - await transform.testResources.deleteIndexPatternByTitle(transformConfigWithLatest.dest.index); + await transform.testResources.deleteDataViewByTitle(transformConfigWithLatest.dest.index); await transform.api.deleteIndices(transformConfigWithLatest.dest.index); await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); const testDataList = [ diff --git a/x-pack/test/functional/apps/transform/permissions/full_transform_access.ts b/x-pack/test/functional/apps/transform/permissions/full_transform_access.ts index 2e7779767eac..0d745a512399 100644 --- a/x-pack/test/functional/apps/transform/permissions/full_transform_access.ts +++ b/x-pack/test/functional/apps/transform/permissions/full_transform_access.ts @@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await transform.api.createAndRunTransform( transformConfigWithPivot.id, @@ -67,12 +67,10 @@ export default function ({ getService }: FtrProviderContext) { }); after(async () => { - await transform.testResources.deleteIndexPatternByTitle( - transformConfigWithPivot.dest.index - ); + await transform.testResources.deleteDataViewByTitle(transformConfigWithPivot.dest.index); await transform.api.deleteIndices(transformConfigWithPivot.dest.index); await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it('should display elements in the Transform list page correctly', async () => { diff --git a/x-pack/test/functional/apps/transform/permissions/read_transform_access.ts b/x-pack/test/functional/apps/transform/permissions/read_transform_access.ts index 4e715d4f0746..02cfcfdfba00 100644 --- a/x-pack/test/functional/apps/transform/permissions/read_transform_access.ts +++ b/x-pack/test/functional/apps/transform/permissions/read_transform_access.ts @@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await transform.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await transform.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await transform.api.createAndRunTransform( transformConfigWithPivot.id, @@ -67,12 +67,10 @@ export default function ({ getService }: FtrProviderContext) { }); after(async () => { - await transform.testResources.deleteIndexPatternByTitle( - transformConfigWithPivot.dest.index - ); + await transform.testResources.deleteDataViewByTitle(transformConfigWithPivot.dest.index); await transform.api.deleteIndices(transformConfigWithPivot.dest.index); await transform.api.cleanTransformIndices(); - await transform.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await transform.testResources.deleteDataViewByTitle('ft_ecommerce'); }); it('should display elements in the Transform list page correctly', async () => { diff --git a/x-pack/test/functional/apps/user_profiles/config.ts b/x-pack/test/functional/apps/user_profiles/config.ts new file mode 100644 index 000000000000..d0d07ff20028 --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/functional/apps/user_profiles/index.ts b/x-pack/test/functional/apps/user_profiles/index.ts new file mode 100644 index 000000000000..5932e2729bf4 --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('User Profiles page', function () { + loadTestFile(require.resolve('./user_profiles')); + }); +}; diff --git a/x-pack/test/functional/apps/user_profiles/user_profiles.ts b/x-pack/test/functional/apps/user_profiles/user_profiles.ts new file mode 100644 index 000000000000..a9f2f7a51950 --- /dev/null +++ b/x-pack/test/functional/apps/user_profiles/user_profiles.ts @@ -0,0 +1,160 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects }: FtrProviderContext) => { + const pageObjects = getPageObjects(['common', 'userProfiles', 'settings']); + + describe('User Profile Page', async () => { + before(async () => {}); + + describe('Details', async () => { + before(async () => { + await pageObjects.common.navigateToApp('security_account'); + }); + + it('should set the full name', async () => { + await pageObjects.userProfiles.setFullNameInputField('Test User 2'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + let toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + + await pageObjects.userProfiles.setFullNameInputField('test user'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + }); + + it('should set the email', async () => { + await pageObjects.userProfiles.setEmailInputField('test@test.com'); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + let toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + + await pageObjects.userProfiles.setEmailInputField('', true); + + await pageObjects.userProfiles.saveUserProfileChanges(); + + toast = await pageObjects.common.closeToast(); + + expect(toast).to.be('Profile updated'); + }); + }); + + describe('Change Password', async () => { + before(async () => { + await pageObjects.common.navigateToApp('security_account'); + }); + + it('should set the current password and enter a new password, then submit', async () => { + const changePasswordButton = await pageObjects.userProfiles.getChangePasswordButton(); + await changePasswordButton.click(); + + await pageObjects.userProfiles.setCurrentPasswordField('changeme'); + await pageObjects.userProfiles.setNewPasswordField('changeme2'); + await pageObjects.userProfiles.setConfirmPasswordField('changeme2'); + + const submitButton = await pageObjects.userProfiles.getChangePasswordFormSubmitButton(); + await submitButton.click(); + + const initialToast = await pageObjects.common.closeToast(); + + expect(initialToast).to.be('Password successfully changed'); + + await changePasswordButton.click(); + + await pageObjects.userProfiles.setCurrentPasswordField('changeme2'); + await pageObjects.userProfiles.setNewPasswordField('changeme'); + await pageObjects.userProfiles.setConfirmPasswordField('changeme'); + + await submitButton.click(); + + const resetToast = await pageObjects.common.closeToast(); + + expect(resetToast).to.be('Password successfully changed'); + }); + }); + + describe('Theme', async () => { + it('should change theme based on the User Profile Theme control with default Adv. Settings value (light)', async () => { + await pageObjects.common.navigateToApp('security_account'); + + const themeKeyPadMenu = await pageObjects.userProfiles.getThemeKeypadMenu(); + expect(themeKeyPadMenu).not.to.be(null); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + const spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8light'); + }); + + it('should change theme based on the User Profile Theme control with default Adv. Settings value set to dark', async () => { + await pageObjects.common.navigateToUrl('management', 'kibana/settings', { + basePath: '', + ensureCurrentUrl: false, + shouldLoginIfPrompted: false, + shouldUseHashForSubUrl: false, + }); + + let advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox( + 'theme:darkMode' + ); + expect(advancedSetting).to.be(null); + + await pageObjects.settings.toggleAdvancedSettingCheckbox('theme:darkMode', true); + advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox('theme:darkMode'); + expect(advancedSetting).to.be('true'); + + await pageObjects.common.navigateToApp('security_account'); + + let spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8dark'); + + await pageObjects.common.navigateToUrl('management', 'kibana/settings', { + basePath: '', + ensureCurrentUrl: false, + shouldLoginIfPrompted: false, + shouldUseHashForSubUrl: false, + }); + + await pageObjects.settings.toggleAdvancedSettingCheckbox('theme:darkMode', false); + advancedSetting = await pageObjects.settings.getAdvancedSettingCheckbox('theme:darkMode'); + expect(advancedSetting).to.be(null); + }); + }); + }); +}; diff --git a/x-pack/test/functional/es_archives/rule_keyword_family/const_keyword/mappings.json b/x-pack/test/functional/es_archives/rule_keyword_family/const_keyword/mappings.json index 7e3d74f84014..8622a0f62cd5 100644 --- a/x-pack/test/functional/es_archives/rule_keyword_family/const_keyword/mappings.json +++ b/x-pack/test/functional/es_archives/rule_keyword_family/const_keyword/mappings.json @@ -39,7 +39,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/rule_keyword_family/keyword/mappings.json b/x-pack/test/functional/es_archives/rule_keyword_family/keyword/mappings.json index 9d5274a00227..233b1148f04b 100644 --- a/x-pack/test/functional/es_archives/rule_keyword_family/keyword/mappings.json +++ b/x-pack/test/functional/es_archives/rule_keyword_family/keyword/mappings.json @@ -25,7 +25,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/data.json b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/data.json new file mode 100644 index 000000000000..dc677dd5bf81 --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/data.json @@ -0,0 +1,422 @@ +{ + "type": "doc", + "value": { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "index": ".alerts-security.alerts-default", + "source": { + "@timestamp": "2023-04-27T11:03:57.906Z", + "Endpoint": { + "capabilities": [ + "isolation", + "kill_process", + "suspend_process", + "running_processes", + "get_file", + "execute" + ], + "configuration": { + "isolation": true + }, + "policy": { + "applied": { + "endpoint_policy_version": 3, + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "With Eventing", + "status": "success", + "version": 5 + } + }, + "state": { + "isolation": true + }, + "status": "enrolled" + }, + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb", + "type": "endpoint", + "version": "8.8.0" + }, + "data_stream": { + "dataset": "endpoint.alerts", + "namespace": "default", + "type": "logs" + }, + "dll": [ + { + "Ext": { + "compile_time": 1534424710, + "malware_classification": { + "identifier": "Whitelisted", + "score": 0, + "threshold": 0, + "version": "3.0.0" + }, + "mapped_address": 5362483200, + "mapped_size": 0 + }, + "code_signature": { + "subject_name": "Cybereason Inc", + "trusted": true + }, + "hash": { + "md5": "1f2d082566b0fc5f2c238a5180db7451", + "sha1": "ca85243c0af6a6471bdaa560685c51eefd6dbc0d", + "sha256": "8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2" + }, + "path": "C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe", + "pe": { + "architecture": "x64" + } + } + ], + "ecs": { + "version": "1.4.0" + }, + "elastic": { + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb" + } + }, + "event.action": "creation", + "event.agent_id_status": "auth_metadata_missing", + "event.category": "malware", + "event.code": "malicious_file", + "event.dataset": "endpoint", + "event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "event.ingested": "2023-04-27T10:58:03Z", + "event.kind": "signal", + "event.module": "endpoint", + "event.sequence": 5826, + "event.type": "creation", + "file": { + "Ext": { + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "malware_classification": { + "identifier": "endpointpe", + "score": 1, + "threshold": 0.66, + "version": "3.0.33" + }, + "quarantine_message": "fake quarantine message", + "quarantine_result": true, + "temp_file_path": "C:/temp/fake_malware.exe" + }, + "accessed": 1682752652103, + "created": 1682752652103, + "hash": { + "md5": "fake file md5", + "sha1": "fake file sha1", + "sha256": "fake file sha256" + }, + "mtime": 1682752652103, + "name": "fake_malware.exe", + "owner": "SYSTEM", + "path": "C:/fake_malware.exe", + "size": 3456 + }, + "user": { + "name": "user1" + }, + "host": { + "architecture": "wtnozeqvub", + "hostname": "Host-fwarau82er", + "id": "4260adf9-5e63-445d-92c6-e03359bcd342", + "ip": [ + "10.249.37.72", + "10.150.39.243", + "10.186.17.170" + ], + "mac": [ + "f5-f-97-dc-20-67", + "b5-56-ca-98-81-ca", + "22-86-39-4c-87-33" + ], + "name": "Host-fwarau82er", + "os": { + "Ext": { + "variant": "Darwin" + }, + "family": "Darwin", + "full": "macOS Monterey", + "name": "macOS", + "platform": "macOS", + "version": "12.6.1" + } + }, + "kibana.alert.ancestors": [ + { + "depth": 0, + "id": "vT9cwocBh3b8EMpD8lsi", + "index": ".ds-logs-endpoint.alerts-default-2023.04.27-000001", + "type": "event" + } + ], + "kibana.alert.depth": 1, + "kibana.alert.last_detected": "2023-04-27T11:03:57.993Z", + "kibana.alert.original_event.action": "creation", + "kibana.alert.original_event.agent_id_status": "auth_metadata_missing", + "kibana.alert.original_event.category": "malware", + "kibana.alert.original_event.code": "malicious_file", + "kibana.alert.original_event.dataset": "endpoint", + "kibana.alert.original_event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "kibana.alert.original_event.ingested": "2023-04-27T10:58:03Z", + "kibana.alert.original_event.kind": "alert", + "kibana.alert.original_event.module": "endpoint", + "kibana.alert.original_event.sequence": 5826, + "kibana.alert.original_event.type": "creation", + "kibana.alert.original_time": "2023-04-29T07:17:32.103Z", + "kibana.alert.reason": "malware event with process malware writer, file fake_malware.exe, on Host-fwarau82er created medium alert Endpoint Security.", + "kibana.alert.risk_score": 47, + "kibana.alert.rule.actions": [ + ], + "kibana.alert.rule.author": [ + "Elastic" + ], + "kibana.alert.rule.category": "Custom Query Rule", + "kibana.alert.rule.consumer": "siem", + "kibana.alert.rule.created_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.created_by": "elastic", + "kibana.alert.rule.description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "kibana.alert.rule.enabled": true, + "kibana.alert.rule.exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "kibana.alert.rule.execution.uuid": "ebf843ff-e0e1-47f8-9ed2-cc8066afbcef", + "kibana.alert.rule.false_positives": [ + ], + "kibana.alert.rule.from": "now-10m", + "kibana.alert.rule.immutable": true, + "kibana.alert.rule.indices": [ + "logs-endpoint.alerts-*" + ], + "kibana.alert.rule.interval": "5m", + "kibana.alert.rule.license": "Elastic License v2", + "kibana.alert.rule.max_signals": 10000, + "kibana.alert.rule.name": "Endpoint Security", + "kibana.alert.rule.parameters": { + "author": [ + "Elastic" + ], + "description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "false_positives": [ + ], + "from": "now-10m", + "immutable": true, + "index": [ + "logs-endpoint.alerts-*" + ], + "language": "kuery", + "license": "Elastic License v2", + "max_signals": 10000, + "query": "event.kind:alert and event.module:(endpoint and not endgame)\n", + "references": [ + ], + "related_integrations": [ + { + "package": "endpoint", + "version": "^8.2.0" + } + ], + "required_fields": [ + { + "ecs": true, + "name": "event.kind", + "type": "keyword" + }, + { + "ecs": true, + "name": "event.module", + "type": "keyword" + } + ], + "risk_score": 47, + "risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "rule_name_override": "message", + "setup": "", + "severity": "medium", + "severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "threat": [ + ], + "timestamp_override": "event.ingested", + "to": "now", + "type": "query", + "version": 101 + }, + "kibana.alert.rule.producer": "siem", + "kibana.alert.rule.references": [ + ], + "kibana.alert.rule.revision": 0, + "kibana.alert.rule.risk_score": 47, + "kibana.alert.rule.risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "kibana.alert.rule.rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "kibana.alert.rule.rule_name_override": "message", + "kibana.alert.rule.rule_type_id": "siem.queryRule", + "kibana.alert.rule.severity": "medium", + "kibana.alert.rule.severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "kibana.alert.rule.tags": [ + "Elastic", + "Endpoint Security" + ], + "kibana.alert.rule.threat": [ + ], + "kibana.alert.rule.timestamp_override": "event.ingested", + "kibana.alert.rule.to": "now", + "kibana.alert.rule.type": "query", + "kibana.alert.rule.updated_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.updated_by": "elastic", + "kibana.alert.rule.uuid": "7015a3e2-e4ea-11ed-8c11-49608884878f", + "kibana.alert.rule.version": 101, + "kibana.alert.severity": "medium", + "kibana.alert.start": "2023-04-27T11:03:57.993Z", + "kibana.alert.status": "active", + "kibana.alert.url": "http://localhost:5601/app/security/alerts/redirect/eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1?index=.alerts-security.alerts-default×tamp=2023-04-27T11:03:57.906Z", + "kibana.alert.uuid": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "kibana.alert.workflow_status": "open", + "kibana.space_ids": [ + "default" + ], + "kibana.version": "8.8.0", + "process": { + "Ext": { + "ancestry": [ + "qa5jgw1wr7", + "5k1hclygc6" + ], + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "token": { + "domain": "NT AUTHORITY", + "integrity_level": 16384, + "integrity_level_name": "system", + "privileges": [ + { + "description": "Replace a process level token", + "enabled": false, + "name": "SeAssignPrimaryTokenPrivilege" + } + ], + "sid": "S-1-5-18", + "type": "tokenPrimary", + "user": "SYSTEM" + }, + "user": "SYSTEM" + }, + "entity_id": "nqh8ts6ves", + "entry_leader": { + "entity_id": "jnm38bel0w", + "name": "fake entry", + "pid": 791 + }, + "executable": "C:/malware.exe", + "group_leader": { + "entity_id": "jnm38bel0w", + "name": "fake leader", + "pid": 848 + }, + "hash": { + "md5": "fake md5", + "sha1": "fake sha1", + "sha256": "fake sha256" + }, + "name": "malware writer", + "parent": { + "entity_id": "qa5jgw1wr7", + "pid": 1 + }, + "pid": 2, + "session_leader": { + "entity_id": "jnm38bel0w", + "name": "fake session", + "pid": 909 + }, + "start": 1682752652103, + "uptime": 0 + } + } + } +} diff --git a/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/mappings.json b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/mappings.json new file mode 100644 index 000000000000..f5a6e53cc4d6 --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0/mappings.json @@ -0,0 +1,7900 @@ +{ + "type": "index", + "value": { + "aliases": { + ".alerts-security.alerts-default": { + "is_write_index": true + }, + ".siem-signals-default": { + "is_write_index": false + } + }, + "index": ".internal.alerts-security.alerts-default-000001", + "mappings": { + "_meta": { + "kibana": { + "version": "8.8.0" + }, + "managed": true, + "namespace": "default" + }, + "dynamic": "false", + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "properties": { + "build": { + "properties": { + "original": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "origin": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "target": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "container": { + "properties": { + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "hash": { + "properties": { + "all": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "memory": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "device": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "manufacturer": { + "ignore_above": 1024, + "type": "keyword" + }, + "model": { + "properties": { + "identifier": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ecs": { + "properties": { + "version": { + "type": "keyword" + } + } + }, + "email": { + "properties": { + "attachments": { + "properties": { + "file": { + "properties": { + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + } + } + } + }, + "type": "nested" + }, + "bcc": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "cc": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "content_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "delivery_timestamp": { + "type": "date" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "from": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "local_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message_id": { + "type": "wildcard" + }, + "origination_timestamp": { + "type": "date" + }, + "reply_to": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "sender": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "subject": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "to": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x_mailer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "type": "match_only_text" + }, + "stack_trace": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "type": "keyword" + }, + "agent_id_status": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "faas": { + "properties": { + "coldstart": { + "type": "boolean" + }, + "execution": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trigger": { + "properties": { + "request_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "boot": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pid_ns_ino": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "static_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "static_score": { + "type": "float" + }, + "static_score_norm": { + "type": "float" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + } + } + }, + "http": { + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + } + } + }, + "bytes": { + "type": "long" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + } + } + }, + "bytes": { + "type": "long" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kibana": { + "properties": { + "alert": { + "properties": { + "action_group": { + "type": "keyword" + }, + "ancestors": { + "properties": { + "depth": { + "type": "long" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "rule": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "building_block_type": { + "type": "keyword" + }, + "case_ids": { + "type": "keyword" + }, + "depth": { + "type": "long" + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "end": { + "type": "date" + }, + "flapping": { + "type": "boolean" + }, + "flapping_history": { + "type": "boolean" + }, + "group": { + "properties": { + "id": { + "type": "keyword" + }, + "index": { + "type": "integer" + } + } + }, + "instance": { + "properties": { + "id": { + "type": "keyword" + } + } + }, + "last_detected": { + "type": "date" + }, + "maintenance_window_ids": { + "type": "keyword" + }, + "new_terms": { + "type": "keyword" + }, + "original_event": { + "properties": { + "action": { + "type": "keyword" + }, + "agent_id_status": { + "type": "keyword" + }, + "category": { + "type": "keyword" + }, + "code": { + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "type": "keyword" + }, + "duration": { + "type": "keyword" + }, + "end": { + "type": "date" + }, + "hash": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "type": "keyword" + }, + "module": { + "type": "keyword" + }, + "original": { + "type": "keyword" + }, + "outcome": { + "type": "keyword" + }, + "provider": { + "type": "keyword" + }, + "reason": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "url": { + "type": "keyword" + } + } + }, + "original_time": { + "type": "date" + }, + "reason": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "rule": { + "properties": { + "author": { + "type": "keyword" + }, + "building_block_type": { + "type": "keyword" + }, + "category": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "enabled": { + "type": "keyword" + }, + "exceptions_list": { + "type": "object" + }, + "execution": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "false_positives": { + "type": "keyword" + }, + "from": { + "type": "keyword" + }, + "immutable": { + "type": "keyword" + }, + "interval": { + "type": "keyword" + }, + "license": { + "type": "keyword" + }, + "max_signals": { + "type": "long" + }, + "name": { + "type": "keyword" + }, + "note": { + "type": "keyword" + }, + "parameters": { + "ignore_above": 4096, + "type": "flattened" + }, + "producer": { + "type": "keyword" + }, + "references": { + "type": "keyword" + }, + "revision": { + "type": "long" + }, + "rule_id": { + "type": "keyword" + }, + "rule_name_override": { + "type": "keyword" + }, + "rule_type_id": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + } + } + } + } + } + } + }, + "timeline_id": { + "type": "keyword" + }, + "timeline_title": { + "type": "keyword" + }, + "timestamp_override": { + "type": "keyword" + }, + "to": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + }, + "uuid": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "severity": { + "type": "keyword" + }, + "start": { + "type": "date" + }, + "status": { + "type": "keyword" + }, + "suppression": { + "properties": { + "docs_count": { + "type": "long" + }, + "end": { + "type": "date" + }, + "start": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "system_status": { + "type": "keyword" + }, + "threshold_result": { + "properties": { + "cardinality": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "long" + } + } + }, + "count": { + "type": "long" + }, + "from": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "time_range": { + "format": "epoch_millis||strict_date_optional_time", + "type": "date_range" + }, + "url": { + "ignore_above": 2048, + "index": false, + "type": "keyword" + }, + "uuid": { + "type": "keyword" + }, + "workflow_reason": { + "type": "keyword" + }, + "workflow_status": { + "type": "keyword" + }, + "workflow_user": { + "type": "keyword" + } + } + }, + "space_ids": { + "type": "keyword" + }, + "version": { + "type": "version" + } + } + }, + "labels": { + "type": "object" + }, + "log": { + "properties": { + "file": { + "properties": { + "path": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "syslog": { + "properties": { + "appname": { + "ignore_above": 1024, + "type": "keyword" + }, + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "msgid": { + "ignore_above": 1024, + "type": "keyword" + }, + "priority": { + "type": "long" + }, + "procid": { + "ignore_above": 1024, + "type": "keyword" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "structured_data": { + "type": "flattened" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "message": { + "type": "match_only_text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "orchestrator": { + "properties": { + "api_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "cluster": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "end": { + "type": "date" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "entry_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "attested_groups": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "attested_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "entry_meta": { + "properties": { + "source": { + "properties": { + "ip": { + "type": "ip" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "session_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "start": { + "type": "date" + } + } + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "env_vars": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "group_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "io": { + "properties": { + "bytes_skipped": { + "properties": { + "length": { + "type": "long" + }, + "offset": { + "type": "long" + } + } + }, + "max_bytes_per_process_exceeded": { + "type": "boolean" + }, + "text": { + "type": "wildcard" + }, + "total_bytes_captured": { + "type": "long" + }, + "total_bytes_skipped": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "end": { + "type": "date" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "previous": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "session_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "session_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "start": { + "type": "date" + } + } + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + }, + "columns": { + "type": "long" + }, + "rows": { + "type": "long" + } + } + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "hosts": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "origin": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "signal": { + "properties": { + "ancestors": { + "properties": { + "depth": { + "path": "kibana.alert.ancestors.depth", + "type": "alias" + }, + "id": { + "path": "kibana.alert.ancestors.id", + "type": "alias" + }, + "index": { + "path": "kibana.alert.ancestors.index", + "type": "alias" + }, + "type": { + "path": "kibana.alert.ancestors.type", + "type": "alias" + } + } + }, + "depth": { + "path": "kibana.alert.depth", + "type": "alias" + }, + "group": { + "properties": { + "id": { + "path": "kibana.alert.group.id", + "type": "alias" + }, + "index": { + "path": "kibana.alert.group.index", + "type": "alias" + } + } + }, + "original_event": { + "properties": { + "action": { + "path": "kibana.alert.original_event.action", + "type": "alias" + }, + "category": { + "path": "kibana.alert.original_event.category", + "type": "alias" + }, + "code": { + "path": "kibana.alert.original_event.code", + "type": "alias" + }, + "created": { + "path": "kibana.alert.original_event.created", + "type": "alias" + }, + "dataset": { + "path": "kibana.alert.original_event.dataset", + "type": "alias" + }, + "duration": { + "path": "kibana.alert.original_event.duration", + "type": "alias" + }, + "end": { + "path": "kibana.alert.original_event.end", + "type": "alias" + }, + "hash": { + "path": "kibana.alert.original_event.hash", + "type": "alias" + }, + "id": { + "path": "kibana.alert.original_event.id", + "type": "alias" + }, + "kind": { + "path": "kibana.alert.original_event.kind", + "type": "alias" + }, + "module": { + "path": "kibana.alert.original_event.module", + "type": "alias" + }, + "outcome": { + "path": "kibana.alert.original_event.outcome", + "type": "alias" + }, + "provider": { + "path": "kibana.alert.original_event.provider", + "type": "alias" + }, + "reason": { + "path": "kibana.alert.original_event.reason", + "type": "alias" + }, + "risk_score": { + "path": "kibana.alert.original_event.risk_score", + "type": "alias" + }, + "risk_score_norm": { + "path": "kibana.alert.original_event.risk_score_norm", + "type": "alias" + }, + "sequence": { + "path": "kibana.alert.original_event.sequence", + "type": "alias" + }, + "severity": { + "path": "kibana.alert.original_event.severity", + "type": "alias" + }, + "start": { + "path": "kibana.alert.original_event.start", + "type": "alias" + }, + "timezone": { + "path": "kibana.alert.original_event.timezone", + "type": "alias" + }, + "type": { + "path": "kibana.alert.original_event.type", + "type": "alias" + } + } + }, + "original_time": { + "path": "kibana.alert.original_time", + "type": "alias" + }, + "reason": { + "path": "kibana.alert.reason", + "type": "alias" + }, + "rule": { + "properties": { + "author": { + "path": "kibana.alert.rule.author", + "type": "alias" + }, + "building_block_type": { + "path": "kibana.alert.building_block_type", + "type": "alias" + }, + "created_at": { + "path": "kibana.alert.rule.created_at", + "type": "alias" + }, + "created_by": { + "path": "kibana.alert.rule.created_by", + "type": "alias" + }, + "description": { + "path": "kibana.alert.rule.description", + "type": "alias" + }, + "enabled": { + "path": "kibana.alert.rule.enabled", + "type": "alias" + }, + "false_positives": { + "path": "kibana.alert.rule.false_positives", + "type": "alias" + }, + "from": { + "path": "kibana.alert.rule.from", + "type": "alias" + }, + "id": { + "path": "kibana.alert.rule.uuid", + "type": "alias" + }, + "immutable": { + "path": "kibana.alert.rule.immutable", + "type": "alias" + }, + "interval": { + "path": "kibana.alert.rule.interval", + "type": "alias" + }, + "license": { + "path": "kibana.alert.rule.license", + "type": "alias" + }, + "max_signals": { + "path": "kibana.alert.rule.max_signals", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.name", + "type": "alias" + }, + "note": { + "path": "kibana.alert.rule.note", + "type": "alias" + }, + "references": { + "path": "kibana.alert.rule.references", + "type": "alias" + }, + "risk_score": { + "path": "kibana.alert.risk_score", + "type": "alias" + }, + "rule_id": { + "path": "kibana.alert.rule.rule_id", + "type": "alias" + }, + "rule_name_override": { + "path": "kibana.alert.rule.rule_name_override", + "type": "alias" + }, + "severity": { + "path": "kibana.alert.severity", + "type": "alias" + }, + "tags": { + "path": "kibana.alert.rule.tags", + "type": "alias" + }, + "threat": { + "properties": { + "framework": { + "path": "kibana.alert.rule.threat.framework", + "type": "alias" + }, + "tactic": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.tactic.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.tactic.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.tactic.reference", + "type": "alias" + } + } + }, + "technique": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.technique.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.technique.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.technique.reference", + "type": "alias" + }, + "subtechnique": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.technique.subtechnique.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.technique.subtechnique.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.technique.subtechnique.reference", + "type": "alias" + } + } + } + } + } + } + }, + "timeline_id": { + "path": "kibana.alert.rule.timeline_id", + "type": "alias" + }, + "timeline_title": { + "path": "kibana.alert.rule.timeline_title", + "type": "alias" + }, + "timestamp_override": { + "path": "kibana.alert.rule.timestamp_override", + "type": "alias" + }, + "to": { + "path": "kibana.alert.rule.to", + "type": "alias" + }, + "type": { + "path": "kibana.alert.rule.type", + "type": "alias" + }, + "updated_at": { + "path": "kibana.alert.rule.updated_at", + "type": "alias" + }, + "updated_by": { + "path": "kibana.alert.rule.updated_by", + "type": "alias" + }, + "version": { + "path": "kibana.alert.rule.version", + "type": "alias" + } + } + }, + "status": { + "path": "kibana.alert.workflow_status", + "type": "alias" + }, + "threshold_result": { + "properties": { + "cardinality": { + "properties": { + "field": { + "path": "kibana.alert.threshold_result.cardinality.field", + "type": "alias" + }, + "value": { + "path": "kibana.alert.threshold_result.cardinality.value", + "type": "alias" + } + } + }, + "count": { + "path": "kibana.alert.threshold_result.count", + "type": "alias" + }, + "from": { + "path": "kibana.alert.threshold_result.from", + "type": "alias" + }, + "terms": { + "properties": { + "field": { + "path": "kibana.alert.threshold_result.terms.field", + "type": "alias" + }, + "value": { + "path": "kibana.alert.threshold_result.terms.value", + "type": "alias" + } + } + } + } + } + } + }, + "source": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tags": { + "type": "keyword" + }, + "threat": { + "properties": { + "enrichments": { + "properties": { + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlp_version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "modified_at": { + "type": "date" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "matched": { + "properties": { + "atomic": { + "ignore_above": 1024, + "type": "keyword" + }, + "field": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "index": { + "ignore_above": 1024, + "type": "keyword" + }, + "occurred": { + "type": "date" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + }, + "type": "nested" + }, + "feed": { + "properties": { + "dashboard_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlp_version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "modified_at": { + "type": "date" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "software": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platforms": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "properties": { + "changes": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "effective": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "static_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "static_score": { + "type": "float" + }, + "static_score_norm": { + "type": "float" + } + } + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "user_agent": { + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "hidden": "true", + "mapping": { + "total_fields": { + "limit": "2500" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/data.json b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/data.json new file mode 100644 index 000000000000..a56ba3832c67 --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/data.json @@ -0,0 +1,1268 @@ +{ + "type": "doc", + "value": { + "id": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "index": ".alerts-security.alerts-default", + "source": { + "@timestamp": "2023-04-27T11:03:57.906Z", + "Endpoint": { + "capabilities": [ + "isolation", + "kill_process", + "suspend_process", + "running_processes", + "get_file", + "execute" + ], + "configuration": { + "isolation": true + }, + "policy": { + "applied": { + "endpoint_policy_version": 3, + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "With Eventing", + "status": "success", + "version": 5 + } + }, + "state": { + "isolation": true + }, + "status": "enrolled" + }, + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb", + "type": "endpoint", + "version": "8.8.0" + }, + "data_stream": { + "dataset": "endpoint.alerts", + "namespace": "default", + "type": "logs" + }, + "dll": [ + { + "Ext": { + "compile_time": 1534424710, + "malware_classification": { + "identifier": "Whitelisted", + "score": 0, + "threshold": 0, + "version": "3.0.0" + }, + "mapped_address": 5362483200, + "mapped_size": 0 + }, + "code_signature": { + "subject_name": "Cybereason Inc", + "trusted": true + }, + "hash": { + "md5": "1f2d082566b0fc5f2c238a5180db7451", + "sha1": "ca85243c0af6a6471bdaa560685c51eefd6dbc0d", + "sha256": "8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2" + }, + "path": "C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe", + "pe": { + "architecture": "x64" + } + } + ], + "ecs": { + "version": "1.4.0" + }, + "elastic": { + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb" + } + }, + "event.action": "creation", + "event.agent_id_status": "auth_metadata_missing", + "event.category": "malware", + "event.code": "malicious_file", + "event.dataset": "endpoint", + "event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "event.ingested": "2023-04-27T10:58:03Z", + "event.kind": "signal", + "event.module": "endpoint", + "event.sequence": 5826, + "event.type": "creation", + "file": { + "Ext": { + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "malware_classification": { + "identifier": "endpointpe", + "score": 1, + "threshold": 0.66, + "version": "3.0.33" + }, + "quarantine_message": "fake quarantine message", + "quarantine_result": true, + "temp_file_path": "C:/temp/fake_malware.exe" + }, + "accessed": 1682752652103, + "created": 1682752652103, + "hash": { + "md5": "fake file md5", + "sha1": "fake file sha1", + "sha256": "fake file sha256" + }, + "mtime": 1682752652103, + "name": "fake_malware.exe", + "owner": "SYSTEM", + "path": "C:/fake_malware.exe", + "size": 3456 + }, + "user": { + "name": "user1" + }, + "host": { + "architecture": "wtnozeqvub", + "hostname": "Host-fwarau82er", + "id": "4260adf9-5e63-445d-92c6-e03359bcd342", + "ip": [ + "10.249.37.72", + "10.150.39.243", + "10.186.17.170" + ], + "mac": [ + "f5-f-97-dc-20-67", + "b5-56-ca-98-81-ca", + "22-86-39-4c-87-33" + ], + "name": "Host-fwarau82er", + "os": { + "Ext": { + "variant": "Darwin" + }, + "family": "Darwin", + "full": "macOS Monterey", + "name": "macOS", + "platform": "macOS", + "version": "12.6.1" + } + }, + "kibana.alert.ancestors": [ + { + "depth": 0, + "id": "vT9cwocBh3b8EMpD8lsi", + "index": ".ds-logs-endpoint.alerts-default-2023.04.27-000001", + "type": "event" + } + ], + "kibana.alert.depth": 1, + "kibana.alert.last_detected": "2023-04-27T11:03:57.993Z", + "kibana.alert.original_event.action": "creation", + "kibana.alert.original_event.agent_id_status": "auth_metadata_missing", + "kibana.alert.original_event.category": "malware", + "kibana.alert.original_event.code": "malicious_file", + "kibana.alert.original_event.dataset": "endpoint", + "kibana.alert.original_event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "kibana.alert.original_event.ingested": "2023-04-27T10:58:03Z", + "kibana.alert.original_event.kind": "alert", + "kibana.alert.original_event.module": "endpoint", + "kibana.alert.original_event.sequence": 5826, + "kibana.alert.original_event.type": "creation", + "kibana.alert.original_time": "2023-04-29T07:17:32.103Z", + "kibana.alert.reason": "malware event with process malware writer, file fake_malware.exe, on Host-fwarau82er created medium alert Endpoint Security.", + "kibana.alert.risk_score": 47, + "kibana.alert.rule.actions": [ + ], + "kibana.alert.rule.author": [ + "Elastic" + ], + "kibana.alert.rule.category": "Custom Query Rule", + "kibana.alert.rule.consumer": "siem", + "kibana.alert.rule.created_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.created_by": "elastic", + "kibana.alert.rule.description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "kibana.alert.rule.enabled": true, + "kibana.alert.rule.exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "kibana.alert.rule.execution.uuid": "ebf843ff-e0e1-47f8-9ed2-cc8066afbcef", + "kibana.alert.rule.false_positives": [ + ], + "kibana.alert.rule.from": "now-10m", + "kibana.alert.rule.immutable": true, + "kibana.alert.rule.indices": [ + "logs-endpoint.alerts-*" + ], + "kibana.alert.rule.interval": "5m", + "kibana.alert.rule.license": "Elastic License v2", + "kibana.alert.rule.max_signals": 10000, + "kibana.alert.rule.name": "Endpoint Security", + "kibana.alert.rule.parameters": { + "author": [ + "Elastic" + ], + "description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "false_positives": [ + ], + "from": "now-10m", + "immutable": true, + "index": [ + "logs-endpoint.alerts-*" + ], + "language": "kuery", + "license": "Elastic License v2", + "max_signals": 10000, + "query": "event.kind:alert and event.module:(endpoint and not endgame)\n", + "references": [ + ], + "related_integrations": [ + { + "package": "endpoint", + "version": "^8.2.0" + } + ], + "required_fields": [ + { + "ecs": true, + "name": "event.kind", + "type": "keyword" + }, + { + "ecs": true, + "name": "event.module", + "type": "keyword" + } + ], + "risk_score": 47, + "risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "rule_name_override": "message", + "setup": "", + "severity": "medium", + "severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "threat": [ + ], + "timestamp_override": "event.ingested", + "to": "now", + "type": "query", + "version": 101 + }, + "kibana.alert.rule.producer": "siem", + "kibana.alert.rule.references": [ + ], + "kibana.alert.rule.revision": 0, + "kibana.alert.rule.risk_score": 47, + "kibana.alert.rule.risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "kibana.alert.rule.rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "kibana.alert.rule.rule_name_override": "message", + "kibana.alert.rule.rule_type_id": "siem.queryRule", + "kibana.alert.rule.severity": "medium", + "kibana.alert.rule.severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "kibana.alert.rule.tags": [ + "Elastic", + "Endpoint Security" + ], + "kibana.alert.rule.threat": [ + ], + "kibana.alert.rule.timestamp_override": "event.ingested", + "kibana.alert.rule.to": "now", + "kibana.alert.rule.type": "query", + "kibana.alert.rule.updated_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.updated_by": "elastic", + "kibana.alert.rule.uuid": "7015a3e2-e4ea-11ed-8c11-49608884878f", + "kibana.alert.rule.version": 101, + "kibana.alert.severity": "medium", + "kibana.alert.start": "2023-04-27T11:03:57.993Z", + "kibana.alert.status": "active", + "kibana.alert.url": "http://localhost:5601/app/security/alerts/redirect/eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1?index=.alerts-security.alerts-default×tamp=2023-04-27T11:03:57.906Z", + "kibana.alert.uuid": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "kibana.alert.workflow_status": "open", + "kibana.space_ids": [ + "default" + ], + "kibana.version": "8.8.0", + "process": { + "Ext": { + "ancestry": [ + "qa5jgw1wr7", + "5k1hclygc6" + ], + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "token": { + "domain": "NT AUTHORITY", + "integrity_level": 16384, + "integrity_level_name": "system", + "privileges": [ + { + "description": "Replace a process level token", + "enabled": false, + "name": "SeAssignPrimaryTokenPrivilege" + } + ], + "sid": "S-1-5-18", + "type": "tokenPrimary", + "user": "SYSTEM" + }, + "user": "SYSTEM" + }, + "entity_id": "nqh8ts6ves", + "entry_leader": { + "entity_id": "jnm38bel0w", + "name": "fake entry", + "pid": 791 + }, + "executable": "C:/malware.exe", + "group_leader": { + "entity_id": "jnm38bel0w", + "name": "fake leader", + "pid": 848 + }, + "hash": { + "md5": "fake md5", + "sha1": "fake sha1", + "sha256": "fake sha256" + }, + "name": "malware writer", + "parent": { + "entity_id": "qa5jgw1wr7", + "pid": 1 + }, + "pid": 2, + "session_leader": { + "entity_id": "jnm38bel0w", + "name": "fake session", + "pid": 909 + }, + "start": 1682752652103, + "uptime": 0 + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "170865e675eda76202f0095b23869d8d0726df4c91a343876df38b566bf1e57d", + "index": ".alerts-security.alerts-default", + "source": { + "@timestamp": "2023-04-27T11:03:57.906Z", + "Endpoint": { + "capabilities": [ + "isolation", + "kill_process", + "suspend_process", + "running_processes", + "get_file", + "execute" + ], + "configuration": { + "isolation": true + }, + "policy": { + "applied": { + "endpoint_policy_version": 3, + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "With Eventing", + "status": "success", + "version": 5 + } + }, + "state": { + "isolation": true + }, + "status": "enrolled" + }, + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb", + "type": "endpoint", + "version": "8.8.0" + }, + "data_stream": { + "dataset": "endpoint.alerts", + "namespace": "default", + "type": "logs" + }, + "dll": [ + { + "Ext": { + "compile_time": 1534424710, + "malware_classification": { + "identifier": "Whitelisted", + "score": 0, + "threshold": 0, + "version": "3.0.0" + }, + "mapped_address": 5362483200, + "mapped_size": 0 + }, + "code_signature": { + "subject_name": "Cybereason Inc", + "trusted": true + }, + "hash": { + "md5": "1f2d082566b0fc5f2c238a5180db7451", + "sha1": "ca85243c0af6a6471bdaa560685c51eefd6dbc0d", + "sha256": "8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2" + }, + "path": "C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe", + "pe": { + "architecture": "x64" + } + } + ], + "ecs": { + "version": "1.4.0" + }, + "elastic": { + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb" + } + }, + "event.action": "creation", + "event.agent_id_status": "auth_metadata_missing", + "event.category": "malware", + "event.code": "malicious_file", + "event.dataset": "endpoint", + "event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "event.ingested": "2023-04-27T10:58:03Z", + "event.kind": "signal", + "event.module": "endpoint", + "event.sequence": 5826, + "event.type": "creation", + "file": { + "Ext": { + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "malware_classification": { + "identifier": "endpointpe", + "score": 1, + "threshold": 0.66, + "version": "3.0.33" + }, + "quarantine_message": "fake quarantine message", + "quarantine_result": true, + "temp_file_path": "C:/temp/fake_malware.exe" + }, + "accessed": 1682752652103, + "created": 1682752652103, + "hash": { + "md5": "fake file md5", + "sha1": "fake file sha1", + "sha256": "fake file sha256" + }, + "mtime": 1682752652103, + "name": "fake_malware.exe", + "owner": "SYSTEM", + "path": "C:/fake_malware.exe", + "size": 3456 + }, + "user": { + "name": "user1" + }, + "host": { + "architecture": "wtnozeqvub", + "hostname": "Host-fwarau82er", + "id": "4260adf9-5e63-445d-92c6-e03359bcd342", + "ip": [ + "10.249.37.72", + "10.150.39.243", + "10.186.17.170" + ], + "mac": [ + "f5-f-97-dc-20-67", + "b5-56-ca-98-81-ca", + "22-86-39-4c-87-33" + ], + "name": "Host-fwarau82er", + "os": { + "Ext": { + "variant": "Darwin" + }, + "family": "Darwin", + "full": "macOS Monterey", + "name": "macOS", + "platform": "macOS", + "version": "12.6.1" + } + }, + "kibana.alert.ancestors": [ + { + "depth": 0, + "id": "vT9cwocBh3b8EMpD8lsi", + "index": ".ds-logs-endpoint.alerts-default-2023.04.27-000001", + "type": "event" + } + ], + "kibana.alert.depth": 1, + "kibana.alert.last_detected": "2023-04-27T11:03:57.993Z", + "kibana.alert.original_event.action": "creation", + "kibana.alert.original_event.agent_id_status": "auth_metadata_missing", + "kibana.alert.original_event.category": "malware", + "kibana.alert.original_event.code": "malicious_file", + "kibana.alert.original_event.dataset": "endpoint", + "kibana.alert.original_event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "kibana.alert.original_event.ingested": "2023-04-27T10:58:03Z", + "kibana.alert.original_event.kind": "alert", + "kibana.alert.original_event.module": "endpoint", + "kibana.alert.original_event.sequence": 5826, + "kibana.alert.original_event.type": "creation", + "kibana.alert.original_time": "2023-04-29T07:17:32.103Z", + "kibana.alert.reason": "malware event with process malware writer, file fake_malware.exe, on Host-fwarau82er created medium alert Endpoint Security.", + "kibana.alert.risk_score": 47, + "kibana.alert.rule.actions": [ + ], + "kibana.alert.rule.author": [ + "Elastic" + ], + "kibana.alert.rule.category": "Custom Query Rule", + "kibana.alert.rule.consumer": "siem", + "kibana.alert.rule.created_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.created_by": "elastic", + "kibana.alert.rule.description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "kibana.alert.rule.enabled": true, + "kibana.alert.rule.exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "kibana.alert.rule.execution.uuid": "ebf843ff-e0e1-47f8-9ed2-cc8066afbcef", + "kibana.alert.rule.false_positives": [ + ], + "kibana.alert.rule.from": "now-10m", + "kibana.alert.rule.immutable": true, + "kibana.alert.rule.indices": [ + "logs-endpoint.alerts-*" + ], + "kibana.alert.rule.interval": "5m", + "kibana.alert.rule.license": "Elastic License v2", + "kibana.alert.rule.max_signals": 10000, + "kibana.alert.rule.name": "Endpoint Security", + "kibana.alert.rule.parameters": { + "author": [ + "Elastic" + ], + "description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "false_positives": [ + ], + "from": "now-10m", + "immutable": true, + "index": [ + "logs-endpoint.alerts-*" + ], + "language": "kuery", + "license": "Elastic License v2", + "max_signals": 10000, + "query": "event.kind:alert and event.module:(endpoint and not endgame)\n", + "references": [ + ], + "related_integrations": [ + { + "package": "endpoint", + "version": "^8.2.0" + } + ], + "required_fields": [ + { + "ecs": true, + "name": "event.kind", + "type": "keyword" + }, + { + "ecs": true, + "name": "event.module", + "type": "keyword" + } + ], + "risk_score": 47, + "risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "rule_name_override": "message", + "setup": "", + "severity": "medium", + "severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "threat": [ + ], + "timestamp_override": "event.ingested", + "to": "now", + "type": "query", + "version": 101 + }, + "kibana.alert.rule.producer": "siem", + "kibana.alert.rule.references": [ + ], + "kibana.alert.rule.revision": 0, + "kibana.alert.rule.risk_score": 47, + "kibana.alert.rule.risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "kibana.alert.rule.rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "kibana.alert.rule.rule_name_override": "message", + "kibana.alert.rule.rule_type_id": "siem.queryRule", + "kibana.alert.rule.severity": "medium", + "kibana.alert.rule.severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "kibana.alert.rule.tags": [ + "Elastic", + "Endpoint Security" + ], + "kibana.alert.rule.threat": [ + ], + "kibana.alert.rule.timestamp_override": "event.ingested", + "kibana.alert.rule.to": "now", + "kibana.alert.rule.type": "query", + "kibana.alert.rule.updated_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.updated_by": "elastic", + "kibana.alert.rule.uuid": "7015a3e2-e4ea-11ed-8c11-49608884878f", + "kibana.alert.rule.version": 101, + "kibana.alert.severity": "medium", + "kibana.alert.start": "2023-04-27T11:03:57.993Z", + "kibana.alert.status": "active", + "kibana.alert.url": "http://localhost:5601/app/security/alerts/redirect/eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1?index=.alerts-security.alerts-default×tamp=2023-04-27T11:03:57.906Z", + "kibana.alert.uuid": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "kibana.alert.workflow_status": "open", + "kibana.space_ids": [ + "default" + ], + "kibana.version": "8.8.0", + "process": { + "Ext": { + "ancestry": [ + "qa5jgw1wr7", + "5k1hclygc6" + ], + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "token": { + "domain": "NT AUTHORITY", + "integrity_level": 16384, + "integrity_level_name": "system", + "privileges": [ + { + "description": "Replace a process level token", + "enabled": false, + "name": "SeAssignPrimaryTokenPrivilege" + } + ], + "sid": "S-1-5-18", + "type": "tokenPrimary", + "user": "SYSTEM" + }, + "user": "SYSTEM" + }, + "entity_id": "nqh8ts6ves", + "entry_leader": { + "entity_id": "jnm38bel0w", + "name": "fake entry", + "pid": 791 + }, + "executable": "C:/malware.exe", + "group_leader": { + "entity_id": "jnm38bel0w", + "name": "fake leader", + "pid": 848 + }, + "hash": { + "md5": "fake md5", + "sha1": "fake sha1", + "sha256": "fake sha256" + }, + "name": "malware writer", + "parent": { + "entity_id": "qa5jgw1wr7", + "pid": 1 + }, + "pid": 2, + "session_leader": { + "entity_id": "jnm38bel0w", + "name": "fake session", + "pid": 909 + }, + "start": 1682752652103, + "uptime": 0 + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "f3bbdf17847c703e37dca942dc6c1db69eb8af18a74c1f52b6d0bd76c6b3b135", + "index": ".alerts-security.alerts-default", + "source": { + "@timestamp": "2023-04-27T11:03:57.906Z", + "Endpoint": { + "capabilities": [ + "isolation", + "kill_process", + "suspend_process", + "running_processes", + "get_file", + "execute" + ], + "configuration": { + "isolation": true + }, + "policy": { + "applied": { + "endpoint_policy_version": 3, + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "With Eventing", + "status": "success", + "version": 5 + } + }, + "state": { + "isolation": true + }, + "status": "enrolled" + }, + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb", + "type": "endpoint", + "version": "8.8.0" + }, + "data_stream": { + "dataset": "endpoint.alerts", + "namespace": "default", + "type": "logs" + }, + "dll": [ + { + "Ext": { + "compile_time": 1534424710, + "malware_classification": { + "identifier": "Whitelisted", + "score": 0, + "threshold": 0, + "version": "3.0.0" + }, + "mapped_address": 5362483200, + "mapped_size": 0 + }, + "code_signature": { + "subject_name": "Cybereason Inc", + "trusted": true + }, + "hash": { + "md5": "1f2d082566b0fc5f2c238a5180db7451", + "sha1": "ca85243c0af6a6471bdaa560685c51eefd6dbc0d", + "sha256": "8ad40c90a611d36eb8f9eb24fa04f7dbca713db383ff55a03aa0f382e92061a2" + }, + "path": "C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe", + "pe": { + "architecture": "x64" + } + } + ], + "ecs": { + "version": "1.4.0" + }, + "elastic": { + "agent": { + "id": "b563ce99-e373-4a1f-a5fe-97e956140aeb" + } + }, + "event.action": "creation", + "event.agent_id_status": "auth_metadata_missing", + "event.category": "malware", + "event.code": "malicious_file", + "event.dataset": "endpoint", + "event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "event.ingested": "2023-04-27T10:58:03Z", + "event.kind": "signal", + "event.module": "endpoint", + "event.sequence": 5826, + "event.type": "creation", + "file": { + "Ext": { + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "malware_classification": { + "identifier": "endpointpe", + "score": 1, + "threshold": 0.66, + "version": "3.0.33" + }, + "quarantine_message": "fake quarantine message", + "quarantine_result": true, + "temp_file_path": "C:/temp/fake_malware.exe" + }, + "accessed": 1682752652103, + "created": 1682752652103, + "hash": { + "md5": "fake file md5", + "sha1": "fake file sha1", + "sha256": "fake file sha256" + }, + "mtime": 1682752652103, + "name": "fake_malware.exe", + "owner": "SYSTEM", + "path": "C:/fake_malware.exe", + "size": 3456 + }, + "user": { + "name": "user1" + }, + "host": { + "architecture": "wtnozeqvub", + "hostname": "Host-fwarau82er", + "id": "4260adf9-5e63-445d-92c6-e03359bcd342", + "ip": [ + "10.249.37.72", + "10.150.39.243", + "10.186.17.170" + ], + "mac": [ + "f5-f-97-dc-20-67", + "b5-56-ca-98-81-ca", + "22-86-39-4c-87-33" + ], + "name": "Host-fwarau82er", + "os": { + "Ext": { + "variant": "Darwin" + }, + "family": "Darwin", + "full": "macOS Monterey", + "name": "macOS", + "platform": "macOS", + "version": "12.6.1" + } + }, + "kibana.alert.ancestors": [ + { + "depth": 0, + "id": "vT9cwocBh3b8EMpD8lsi", + "index": ".ds-logs-endpoint.alerts-default-2023.04.27-000001", + "type": "event" + } + ], + "kibana.alert.depth": 1, + "kibana.alert.last_detected": "2023-04-27T11:03:57.993Z", + "kibana.alert.original_event.action": "creation", + "kibana.alert.original_event.agent_id_status": "auth_metadata_missing", + "kibana.alert.original_event.category": "malware", + "kibana.alert.original_event.code": "malicious_file", + "kibana.alert.original_event.dataset": "endpoint", + "kibana.alert.original_event.id": "b28993d4-8b8a-4f0f-9f54-84a89bad66ae", + "kibana.alert.original_event.ingested": "2023-04-27T10:58:03Z", + "kibana.alert.original_event.kind": "alert", + "kibana.alert.original_event.module": "endpoint", + "kibana.alert.original_event.sequence": 5826, + "kibana.alert.original_event.type": "creation", + "kibana.alert.original_time": "2023-04-29T07:17:32.103Z", + "kibana.alert.reason": "malware event with process malware writer, file fake_malware.exe, on Host-fwarau82er created medium alert Endpoint Security.", + "kibana.alert.risk_score": 47, + "kibana.alert.rule.actions": [ + ], + "kibana.alert.rule.author": [ + "Elastic" + ], + "kibana.alert.rule.category": "Custom Query Rule", + "kibana.alert.rule.consumer": "siem", + "kibana.alert.rule.created_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.created_by": "elastic", + "kibana.alert.rule.description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "kibana.alert.rule.enabled": true, + "kibana.alert.rule.exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "kibana.alert.rule.execution.uuid": "ebf843ff-e0e1-47f8-9ed2-cc8066afbcef", + "kibana.alert.rule.false_positives": [ + ], + "kibana.alert.rule.from": "now-10m", + "kibana.alert.rule.immutable": true, + "kibana.alert.rule.indices": [ + "logs-endpoint.alerts-*" + ], + "kibana.alert.rule.interval": "5m", + "kibana.alert.rule.license": "Elastic License v2", + "kibana.alert.rule.max_signals": 10000, + "kibana.alert.rule.name": "Endpoint Security", + "kibana.alert.rule.parameters": { + "author": [ + "Elastic" + ], + "description": "Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to immediately begin investigating your Endpoint alerts.", + "exceptions_list": [ + { + "id": "endpoint_list", + "list_id": "endpoint_list", + "namespace_type": "agnostic", + "type": "endpoint" + } + ], + "false_positives": [ + ], + "from": "now-10m", + "immutable": true, + "index": [ + "logs-endpoint.alerts-*" + ], + "language": "kuery", + "license": "Elastic License v2", + "max_signals": 10000, + "query": "event.kind:alert and event.module:(endpoint and not endgame)\n", + "references": [ + ], + "related_integrations": [ + { + "package": "endpoint", + "version": "^8.2.0" + } + ], + "required_fields": [ + { + "ecs": true, + "name": "event.kind", + "type": "keyword" + }, + { + "ecs": true, + "name": "event.module", + "type": "keyword" + } + ], + "risk_score": 47, + "risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "rule_name_override": "message", + "setup": "", + "severity": "medium", + "severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "threat": [ + ], + "timestamp_override": "event.ingested", + "to": "now", + "type": "query", + "version": 101 + }, + "kibana.alert.rule.producer": "siem", + "kibana.alert.rule.references": [ + ], + "kibana.alert.rule.revision": 0, + "kibana.alert.rule.risk_score": 47, + "kibana.alert.rule.risk_score_mapping": [ + { + "field": "event.risk_score", + "operator": "equals", + "value": "" + } + ], + "kibana.alert.rule.rule_id": "9a1a2dae-0b5f-4c3d-8305-a268d404c306", + "kibana.alert.rule.rule_name_override": "message", + "kibana.alert.rule.rule_type_id": "siem.queryRule", + "kibana.alert.rule.severity": "medium", + "kibana.alert.rule.severity_mapping": [ + { + "field": "event.severity", + "operator": "equals", + "severity": "low", + "value": "21" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "medium", + "value": "47" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "high", + "value": "73" + }, + { + "field": "event.severity", + "operator": "equals", + "severity": "critical", + "value": "99" + } + ], + "kibana.alert.rule.tags": [ + "Elastic", + "Endpoint Security" + ], + "kibana.alert.rule.threat": [ + ], + "kibana.alert.rule.timestamp_override": "event.ingested", + "kibana.alert.rule.to": "now", + "kibana.alert.rule.type": "query", + "kibana.alert.rule.updated_at": "2023-04-27T10:58:27.546Z", + "kibana.alert.rule.updated_by": "elastic", + "kibana.alert.rule.uuid": "7015a3e2-e4ea-11ed-8c11-49608884878f", + "kibana.alert.rule.version": 101, + "kibana.alert.severity": "medium", + "kibana.alert.start": "2023-04-27T11:03:57.993Z", + "kibana.alert.status": "active", + "kibana.alert.url": "http://localhost:5601/app/security/alerts/redirect/eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1?index=.alerts-security.alerts-default×tamp=2023-04-27T11:03:57.906Z", + "kibana.alert.uuid": "eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1", + "kibana.alert.workflow_status": "open", + "kibana.space_ids": [ + "default" + ], + "kibana.version": "8.8.0", + "process": { + "Ext": { + "ancestry": [ + "qa5jgw1wr7", + "5k1hclygc6" + ], + "code_signature": [ + { + "subject_name": "bad signer", + "trusted": false + } + ], + "token": { + "domain": "NT AUTHORITY", + "integrity_level": 16384, + "integrity_level_name": "system", + "privileges": [ + { + "description": "Replace a process level token", + "enabled": false, + "name": "SeAssignPrimaryTokenPrivilege" + } + ], + "sid": "S-1-5-18", + "type": "tokenPrimary", + "user": "SYSTEM" + }, + "user": "SYSTEM" + }, + "entity_id": "nqh8ts6ves", + "entry_leader": { + "entity_id": "jnm38bel0w", + "name": "fake entry", + "pid": 791 + }, + "executable": "C:/malware.exe", + "group_leader": { + "entity_id": "jnm38bel0w", + "name": "fake leader", + "pid": 848 + }, + "hash": { + "md5": "fake md5", + "sha1": "fake sha1", + "sha256": "fake sha256" + }, + "name": "malware writer", + "parent": { + "entity_id": "qa5jgw1wr7", + "pid": 1 + }, + "pid": 2, + "session_leader": { + "entity_id": "jnm38bel0w", + "name": "fake session", + "pid": 909 + }, + "start": 1682752652103, + "uptime": 0 + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/mappings.json b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/mappings.json new file mode 100644 index 000000000000..f5a6e53cc4d6 --- /dev/null +++ b/x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs/mappings.json @@ -0,0 +1,7900 @@ +{ + "type": "index", + "value": { + "aliases": { + ".alerts-security.alerts-default": { + "is_write_index": true + }, + ".siem-signals-default": { + "is_write_index": false + } + }, + "index": ".internal.alerts-security.alerts-default-000001", + "mappings": { + "_meta": { + "kibana": { + "version": "8.8.0" + }, + "managed": true, + "namespace": "default" + }, + "dynamic": "false", + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "properties": { + "build": { + "properties": { + "original": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "origin": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "target": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "container": { + "properties": { + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "hash": { + "properties": { + "all": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "memory": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "device": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "manufacturer": { + "ignore_above": 1024, + "type": "keyword" + }, + "model": { + "properties": { + "identifier": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ecs": { + "properties": { + "version": { + "type": "keyword" + } + } + }, + "email": { + "properties": { + "attachments": { + "properties": { + "file": { + "properties": { + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + } + } + } + }, + "type": "nested" + }, + "bcc": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "cc": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "content_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "delivery_timestamp": { + "type": "date" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "from": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "local_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message_id": { + "type": "wildcard" + }, + "origination_timestamp": { + "type": "date" + }, + "reply_to": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "sender": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "subject": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "to": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x_mailer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "type": "match_only_text" + }, + "stack_trace": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "type": "keyword" + }, + "agent_id_status": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reason": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "faas": { + "properties": { + "coldstart": { + "type": "boolean" + }, + "execution": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trigger": { + "properties": { + "request_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "boot": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "cpu": { + "properties": { + "usage": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "disk": { + "properties": { + "read": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "write": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "network": { + "properties": { + "egress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + }, + "ingress": { + "properties": { + "bytes": { + "type": "long" + }, + "packets": { + "type": "long" + } + } + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pid_ns_ino": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "static_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "static_score": { + "type": "float" + }, + "static_score_norm": { + "type": "float" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + } + } + }, + "http": { + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + } + } + }, + "bytes": { + "type": "long" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + } + } + }, + "bytes": { + "type": "long" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kibana": { + "properties": { + "alert": { + "properties": { + "action_group": { + "type": "keyword" + }, + "ancestors": { + "properties": { + "depth": { + "type": "long" + }, + "id": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "rule": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + } + }, + "building_block_type": { + "type": "keyword" + }, + "case_ids": { + "type": "keyword" + }, + "depth": { + "type": "long" + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "end": { + "type": "date" + }, + "flapping": { + "type": "boolean" + }, + "flapping_history": { + "type": "boolean" + }, + "group": { + "properties": { + "id": { + "type": "keyword" + }, + "index": { + "type": "integer" + } + } + }, + "instance": { + "properties": { + "id": { + "type": "keyword" + } + } + }, + "last_detected": { + "type": "date" + }, + "maintenance_window_ids": { + "type": "keyword" + }, + "new_terms": { + "type": "keyword" + }, + "original_event": { + "properties": { + "action": { + "type": "keyword" + }, + "agent_id_status": { + "type": "keyword" + }, + "category": { + "type": "keyword" + }, + "code": { + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "type": "keyword" + }, + "duration": { + "type": "keyword" + }, + "end": { + "type": "date" + }, + "hash": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "type": "keyword" + }, + "module": { + "type": "keyword" + }, + "original": { + "type": "keyword" + }, + "outcome": { + "type": "keyword" + }, + "provider": { + "type": "keyword" + }, + "reason": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "url": { + "type": "keyword" + } + } + }, + "original_time": { + "type": "date" + }, + "reason": { + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "rule": { + "properties": { + "author": { + "type": "keyword" + }, + "building_block_type": { + "type": "keyword" + }, + "category": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "created_by": { + "type": "keyword" + }, + "description": { + "type": "keyword" + }, + "enabled": { + "type": "keyword" + }, + "exceptions_list": { + "type": "object" + }, + "execution": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "false_positives": { + "type": "keyword" + }, + "from": { + "type": "keyword" + }, + "immutable": { + "type": "keyword" + }, + "interval": { + "type": "keyword" + }, + "license": { + "type": "keyword" + }, + "max_signals": { + "type": "long" + }, + "name": { + "type": "keyword" + }, + "note": { + "type": "keyword" + }, + "parameters": { + "ignore_above": 4096, + "type": "flattened" + }, + "producer": { + "type": "keyword" + }, + "references": { + "type": "keyword" + }, + "revision": { + "type": "long" + }, + "rule_id": { + "type": "keyword" + }, + "rule_name_override": { + "type": "keyword" + }, + "rule_type_id": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "reference": { + "type": "keyword" + } + } + } + } + } + } + }, + "timeline_id": { + "type": "keyword" + }, + "timeline_title": { + "type": "keyword" + }, + "timestamp_override": { + "type": "keyword" + }, + "to": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + }, + "updated_by": { + "type": "keyword" + }, + "uuid": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + }, + "severity": { + "type": "keyword" + }, + "start": { + "type": "date" + }, + "status": { + "type": "keyword" + }, + "suppression": { + "properties": { + "docs_count": { + "type": "long" + }, + "end": { + "type": "date" + }, + "start": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "system_status": { + "type": "keyword" + }, + "threshold_result": { + "properties": { + "cardinality": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "long" + } + } + }, + "count": { + "type": "long" + }, + "from": { + "type": "date" + }, + "terms": { + "properties": { + "field": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + } + } + } + }, + "time_range": { + "format": "epoch_millis||strict_date_optional_time", + "type": "date_range" + }, + "url": { + "ignore_above": 2048, + "index": false, + "type": "keyword" + }, + "uuid": { + "type": "keyword" + }, + "workflow_reason": { + "type": "keyword" + }, + "workflow_status": { + "type": "keyword" + }, + "workflow_user": { + "type": "keyword" + } + } + }, + "space_ids": { + "type": "keyword" + }, + "version": { + "type": "version" + } + } + }, + "labels": { + "type": "object" + }, + "log": { + "properties": { + "file": { + "properties": { + "path": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "syslog": { + "properties": { + "appname": { + "ignore_above": 1024, + "type": "keyword" + }, + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "msgid": { + "ignore_above": 1024, + "type": "keyword" + }, + "priority": { + "type": "long" + }, + "procid": { + "ignore_above": 1024, + "type": "keyword" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "structured_data": { + "type": "flattened" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "message": { + "type": "match_only_text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "orchestrator": { + "properties": { + "api_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "cluster": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "end": { + "type": "date" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "entry_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "attested_groups": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "attested_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "entry_meta": { + "properties": { + "source": { + "properties": { + "ip": { + "type": "ip" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "session_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "start": { + "type": "date" + } + } + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "env_vars": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "group_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "io": { + "properties": { + "bytes_skipped": { + "properties": { + "length": { + "type": "long" + }, + "offset": { + "type": "long" + } + } + }, + "max_bytes_per_process_exceeded": { + "type": "boolean" + }, + "text": { + "type": "wildcard" + }, + "total_bytes_captured": { + "type": "long" + }, + "total_bytes_skipped": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "end": { + "type": "date" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "previous": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "session_leader": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "command_line": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interactive": { + "type": "boolean" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "session_leader": { + "properties": { + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "pid": { + "type": "long" + }, + "start": { + "type": "date" + } + } + }, + "start": { + "type": "date" + } + } + }, + "pid": { + "type": "long" + }, + "real_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "real_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "same_as_process": { + "type": "boolean" + }, + "saved_group": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "saved_user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + } + } + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "start": { + "type": "date" + }, + "supplemental_groups": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "tty": { + "properties": { + "char_device": { + "properties": { + "major": { + "type": "long" + }, + "minor": { + "type": "long" + } + } + }, + "columns": { + "type": "long" + }, + "rows": { + "type": "long" + } + } + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "working_directory": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "hosts": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "origin": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "signal": { + "properties": { + "ancestors": { + "properties": { + "depth": { + "path": "kibana.alert.ancestors.depth", + "type": "alias" + }, + "id": { + "path": "kibana.alert.ancestors.id", + "type": "alias" + }, + "index": { + "path": "kibana.alert.ancestors.index", + "type": "alias" + }, + "type": { + "path": "kibana.alert.ancestors.type", + "type": "alias" + } + } + }, + "depth": { + "path": "kibana.alert.depth", + "type": "alias" + }, + "group": { + "properties": { + "id": { + "path": "kibana.alert.group.id", + "type": "alias" + }, + "index": { + "path": "kibana.alert.group.index", + "type": "alias" + } + } + }, + "original_event": { + "properties": { + "action": { + "path": "kibana.alert.original_event.action", + "type": "alias" + }, + "category": { + "path": "kibana.alert.original_event.category", + "type": "alias" + }, + "code": { + "path": "kibana.alert.original_event.code", + "type": "alias" + }, + "created": { + "path": "kibana.alert.original_event.created", + "type": "alias" + }, + "dataset": { + "path": "kibana.alert.original_event.dataset", + "type": "alias" + }, + "duration": { + "path": "kibana.alert.original_event.duration", + "type": "alias" + }, + "end": { + "path": "kibana.alert.original_event.end", + "type": "alias" + }, + "hash": { + "path": "kibana.alert.original_event.hash", + "type": "alias" + }, + "id": { + "path": "kibana.alert.original_event.id", + "type": "alias" + }, + "kind": { + "path": "kibana.alert.original_event.kind", + "type": "alias" + }, + "module": { + "path": "kibana.alert.original_event.module", + "type": "alias" + }, + "outcome": { + "path": "kibana.alert.original_event.outcome", + "type": "alias" + }, + "provider": { + "path": "kibana.alert.original_event.provider", + "type": "alias" + }, + "reason": { + "path": "kibana.alert.original_event.reason", + "type": "alias" + }, + "risk_score": { + "path": "kibana.alert.original_event.risk_score", + "type": "alias" + }, + "risk_score_norm": { + "path": "kibana.alert.original_event.risk_score_norm", + "type": "alias" + }, + "sequence": { + "path": "kibana.alert.original_event.sequence", + "type": "alias" + }, + "severity": { + "path": "kibana.alert.original_event.severity", + "type": "alias" + }, + "start": { + "path": "kibana.alert.original_event.start", + "type": "alias" + }, + "timezone": { + "path": "kibana.alert.original_event.timezone", + "type": "alias" + }, + "type": { + "path": "kibana.alert.original_event.type", + "type": "alias" + } + } + }, + "original_time": { + "path": "kibana.alert.original_time", + "type": "alias" + }, + "reason": { + "path": "kibana.alert.reason", + "type": "alias" + }, + "rule": { + "properties": { + "author": { + "path": "kibana.alert.rule.author", + "type": "alias" + }, + "building_block_type": { + "path": "kibana.alert.building_block_type", + "type": "alias" + }, + "created_at": { + "path": "kibana.alert.rule.created_at", + "type": "alias" + }, + "created_by": { + "path": "kibana.alert.rule.created_by", + "type": "alias" + }, + "description": { + "path": "kibana.alert.rule.description", + "type": "alias" + }, + "enabled": { + "path": "kibana.alert.rule.enabled", + "type": "alias" + }, + "false_positives": { + "path": "kibana.alert.rule.false_positives", + "type": "alias" + }, + "from": { + "path": "kibana.alert.rule.from", + "type": "alias" + }, + "id": { + "path": "kibana.alert.rule.uuid", + "type": "alias" + }, + "immutable": { + "path": "kibana.alert.rule.immutable", + "type": "alias" + }, + "interval": { + "path": "kibana.alert.rule.interval", + "type": "alias" + }, + "license": { + "path": "kibana.alert.rule.license", + "type": "alias" + }, + "max_signals": { + "path": "kibana.alert.rule.max_signals", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.name", + "type": "alias" + }, + "note": { + "path": "kibana.alert.rule.note", + "type": "alias" + }, + "references": { + "path": "kibana.alert.rule.references", + "type": "alias" + }, + "risk_score": { + "path": "kibana.alert.risk_score", + "type": "alias" + }, + "rule_id": { + "path": "kibana.alert.rule.rule_id", + "type": "alias" + }, + "rule_name_override": { + "path": "kibana.alert.rule.rule_name_override", + "type": "alias" + }, + "severity": { + "path": "kibana.alert.severity", + "type": "alias" + }, + "tags": { + "path": "kibana.alert.rule.tags", + "type": "alias" + }, + "threat": { + "properties": { + "framework": { + "path": "kibana.alert.rule.threat.framework", + "type": "alias" + }, + "tactic": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.tactic.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.tactic.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.tactic.reference", + "type": "alias" + } + } + }, + "technique": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.technique.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.technique.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.technique.reference", + "type": "alias" + }, + "subtechnique": { + "properties": { + "id": { + "path": "kibana.alert.rule.threat.technique.subtechnique.id", + "type": "alias" + }, + "name": { + "path": "kibana.alert.rule.threat.technique.subtechnique.name", + "type": "alias" + }, + "reference": { + "path": "kibana.alert.rule.threat.technique.subtechnique.reference", + "type": "alias" + } + } + } + } + } + } + }, + "timeline_id": { + "path": "kibana.alert.rule.timeline_id", + "type": "alias" + }, + "timeline_title": { + "path": "kibana.alert.rule.timeline_title", + "type": "alias" + }, + "timestamp_override": { + "path": "kibana.alert.rule.timestamp_override", + "type": "alias" + }, + "to": { + "path": "kibana.alert.rule.to", + "type": "alias" + }, + "type": { + "path": "kibana.alert.rule.type", + "type": "alias" + }, + "updated_at": { + "path": "kibana.alert.rule.updated_at", + "type": "alias" + }, + "updated_by": { + "path": "kibana.alert.rule.updated_by", + "type": "alias" + }, + "version": { + "path": "kibana.alert.rule.version", + "type": "alias" + } + } + }, + "status": { + "path": "kibana.alert.workflow_status", + "type": "alias" + }, + "threshold_result": { + "properties": { + "cardinality": { + "properties": { + "field": { + "path": "kibana.alert.threshold_result.cardinality.field", + "type": "alias" + }, + "value": { + "path": "kibana.alert.threshold_result.cardinality.value", + "type": "alias" + } + } + }, + "count": { + "path": "kibana.alert.threshold_result.count", + "type": "alias" + }, + "from": { + "path": "kibana.alert.threshold_result.from", + "type": "alias" + }, + "terms": { + "properties": { + "field": { + "path": "kibana.alert.threshold_result.terms.field", + "type": "alias" + }, + "value": { + "path": "kibana.alert.threshold_result.terms.value", + "type": "alias" + } + } + } + } + } + } + }, + "source": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tags": { + "type": "keyword" + }, + "threat": { + "properties": { + "enrichments": { + "properties": { + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlp_version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "modified_at": { + "type": "date" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "matched": { + "properties": { + "atomic": { + "ignore_above": 1024, + "type": "keyword" + }, + "field": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "index": { + "ignore_above": 1024, + "type": "keyword" + }, + "occurred": { + "type": "date" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + }, + "type": "nested" + }, + "feed": { + "properties": { + "dashboard_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "digest_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "exists": { + "type": "boolean" + }, + "signing_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "team_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "elf": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "byte_order": { + "ignore_above": 1024, + "type": "keyword" + }, + "cpu_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "creation_date": { + "type": "date" + }, + "exports": { + "type": "flattened" + }, + "header": { + "properties": { + "abi_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "entrypoint": { + "type": "long" + }, + "object_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "os_abi": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "imports": { + "type": "flattened" + }, + "sections": { + "properties": { + "chi2": { + "type": "long" + }, + "entropy": { + "type": "long" + }, + "flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_offset": { + "ignore_above": 1024, + "type": "keyword" + }, + "physical_size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "virtual_address": { + "type": "long" + }, + "virtual_size": { + "type": "long" + } + }, + "type": "nested" + }, + "segments": { + "properties": { + "sections": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "nested" + }, + "shared_libraries": { + "ignore_above": 1024, + "type": "keyword" + }, + "telfhash": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fork_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha384": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + }, + "ssdeep": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlsh": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "imphash": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "pehash": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "postal_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + }, + "tlp_version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "modified_at": { + "type": "date" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "type": "wildcard" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "software": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platforms": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "x509": { + "properties": { + "alternative_names": { + "ignore_above": 1024, + "type": "keyword" + }, + "issuer": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "public_key_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "signature_algorithm": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "properties": { + "common_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country": { + "ignore_above": 1024, + "type": "keyword" + }, + "distinguished_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "locality": { + "ignore_above": 1024, + "type": "keyword" + }, + "organization": { + "ignore_above": 1024, + "type": "keyword" + }, + "organizational_unit": { + "ignore_above": 1024, + "type": "keyword" + }, + "state_or_province": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version_number": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "type": "wildcard" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "type": "wildcard" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "properties": { + "changes": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "effective": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "risk": { + "properties": { + "calculated_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "calculated_score": { + "type": "float" + }, + "calculated_score_norm": { + "type": "float" + }, + "static_level": { + "ignore_above": 1024, + "type": "keyword" + }, + "static_score": { + "type": "float" + }, + "static_score_norm": { + "type": "float" + } + } + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + }, + "target": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "roles": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "user_agent": { + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "type": "match_only_text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "hidden": "true", + "mapping": { + "total_fields": { + "limit": "2500" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/es_archives/security_solution/ignore_fields/mappings.json b/x-pack/test/functional/es_archives/security_solution/ignore_fields/mappings.json index e2c8ca3c2bc8..3c2cbeac06cc 100644 --- a/x-pack/test/functional/es_archives/security_solution/ignore_fields/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/ignore_fields/mappings.json @@ -32,7 +32,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/security_solution/runtime/mappings.json b/x-pack/test/functional/es_archives/security_solution/runtime/mappings.json index fd3f30f2a212..e0adb6cb5574 100644 --- a/x-pack/test/functional/es_archives/security_solution/runtime/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/runtime/mappings.json @@ -7027,7 +7027,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1", "mapping": { diff --git a/x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields/mappings.json b/x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields/mappings.json index 2e34eae159a7..ed15855be8e3 100644 --- a/x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields/mappings.json @@ -108,7 +108,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds/mappings.json b/x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds/mappings.json index fd8880fe0bc4..056d6467f510 100644 --- a/x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds/mappings.json @@ -13,7 +13,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/security_solution/timestamp_override_5/mappings.json b/x-pack/test/functional/es_archives/security_solution/timestamp_override_5/mappings.json index a9735aaeca8e..fd6f02966837 100644 --- a/x-pack/test/functional/es_archives/security_solution/timestamp_override_5/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/timestamp_override_5/mappings.json @@ -30,7 +30,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/es_archives/security_solution/timestamp_override_6/mappings.json b/x-pack/test/functional/es_archives/security_solution/timestamp_override_6/mappings.json index e3d8afd7a5b3..b1b35d6e1a23 100644 --- a/x-pack/test/functional/es_archives/security_solution/timestamp_override_6/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/timestamp_override_6/mappings.json @@ -20,7 +20,6 @@ }, "settings": { "index": { - "refresh_interval": "1s", "number_of_replicas": "1", "number_of_shards": "1" } diff --git a/x-pack/test/functional/page_objects/asset_details.ts b/x-pack/test/functional/page_objects/asset_details.ts index d51341c0fef4..ef4e8967e692 100644 --- a/x-pack/test/functional/page_objects/asset_details.ts +++ b/x-pack/test/functional/page_objects/asset_details.ts @@ -37,14 +37,9 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) { }, async getAssetDetailsMetricsCharts() { - const container = await testSubjects.find('infraAssetDetailsMetricsChartGrid'); - return container.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricsChart"]'); - }, - - async getAssetDetailsNginxMetricsCharts() { - const container = await testSubjects.find('infraAssetDetailsNginxMetricsChartGrid'); + const container = await testSubjects.find('infraAssetDetailsHostMetricsChartGrid'); return container.findAllByCssSelector( - '[data-test-subj*="infraAssetDetailsNginxMetricsChart"]' + '[data-test-subj*="infraAssetDetailsHostMetricsChart"]' ); }, diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index a8ac0895ed25..75f86f764595 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -48,6 +48,7 @@ import { StatusPageObject } from './status_page'; import { TagManagementPageObject } from './tag_management_page'; import { UpgradeAssistantPageObject } from './upgrade_assistant_page'; import { UptimePageObject } from './uptime_page'; +import { UserProfilePageProvider } from './user_profile_page'; import { WatcherPageObject } from './watcher_page'; // just like services, PageObjects are defined as a map of @@ -95,5 +96,6 @@ export const pageObjects = { tagManagement: TagManagementPageObject, upgradeAssistant: UpgradeAssistantPageObject, uptime: UptimePageObject, + userProfiles: UserProfilePageProvider, watcher: WatcherPageObject, }; diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 45b451721b2c..927e8710017e 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -1377,13 +1377,16 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * * @param title - title for the new lens. If left undefined, the panel will be created by value * @param redirectToOrigin - whether to redirect back to the dashboard after saving the panel + * @param ignoreTimeFilter - whether time range has to be changed */ async createAndAddLensFromDashboard({ title, redirectToOrigin, + ignoreTimeFilter, }: { title?: string; redirectToOrigin?: boolean; + ignoreTimeFilter?: boolean; }) { log.debug(`createAndAddLens${title}`); const inViewMode = await PageObjects.dashboard.getIsInViewMode(); @@ -1391,7 +1394,11 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await PageObjects.dashboard.switchToEditMode(); } await dashboardAddPanel.clickCreateNewLink(); - await this.goToTimeRange(); + + if (!ignoreTimeFilter) { + await this.goToTimeRange(); + } + await this.configureDimension({ dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', operation: 'average', diff --git a/x-pack/test/functional/page_objects/remote_clusters_page.ts b/x-pack/test/functional/page_objects/remote_clusters_page.ts index b9f24dd1854d..253ba3a27ff0 100644 --- a/x-pack/test/functional/page_objects/remote_clusters_page.ts +++ b/x-pack/test/functional/page_objects/remote_clusters_page.ts @@ -35,7 +35,7 @@ export function RemoteClustersPageProvider({ getService }: FtrProviderContext) { // Complete trust setup await testSubjects.click('setupTrustDoneButton'); - await testSubjects.setCheckbox('remoteClusterTrustCheckbox', 'check'); + await testSubjects.setCheckbox('remoteClusterTrustCheckboxLabel', 'check'); await testSubjects.click('remoteClusterTrustSubmitButton'); }, async getRemoteClustersList() { diff --git a/x-pack/test/functional/page_objects/security_page.ts b/x-pack/test/functional/page_objects/security_page.ts index bb127df565cc..b80219544ef5 100644 --- a/x-pack/test/functional/page_objects/security_page.ts +++ b/x-pack/test/functional/page_objects/security_page.ts @@ -6,7 +6,7 @@ */ import { adminTestUser } from '@kbn/test'; -import { AuthenticatedUser, Role } from '@kbn/security-plugin/common/model'; +import { AuthenticatedUser, Role } from '@kbn/security-plugin/common'; import type { UserFormValues } from '@kbn/security-plugin/public/management/users/edit_user/user_form'; import { Key } from 'selenium-webdriver'; import { FtrService } from '../ftr_provider_context'; diff --git a/x-pack/test/functional/page_objects/user_profile_page.ts b/x-pack/test/functional/page_objects/user_profile_page.ts new file mode 100644 index 000000000000..3380c10e2067 --- /dev/null +++ b/x-pack/test/functional/page_objects/user_profile_page.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export function UserProfilePageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const browser = getService('browser'); + const retry = getService('retry'); + + const getThemeTag = async (): Promise => { + return await browser.execute('return __kbnThemeTag__'); + }; + + const getSaveProfileChangesButton = async () => { + return await testSubjects.find('saveProfileChangesButton'); + }; + + const getReloadWindowButton = async () => { + return await testSubjects.find('windowReloadButton'); + }; + + const getThemeKeypadButton = async (option: string) => { + option = option[0].toUpperCase() + option.substring(1).toLowerCase(); + return await testSubjects.find(`themeKeyPadItem${option}`); + }; + + const saveUserProfileChanges = async (): Promise => { + let saveProfileChangesButton; + await retry.try(async () => { + saveProfileChangesButton = await getSaveProfileChangesButton(); + expect(saveProfileChangesButton).not.to.be(null); + await saveProfileChangesButton.click(); + }); + }; + + const changeUserProfileTheme = async (theme: string): Promise => { + const themeModeButton = await getThemeKeypadButton(theme); + expect(themeModeButton).not.to.be(null); + await themeModeButton.click(); + + await saveUserProfileChanges(); + + let reloadWindowButton; + await retry.try(async () => { + reloadWindowButton = await getReloadWindowButton(); + expect(reloadWindowButton).not.to.be(null); + await reloadWindowButton.click(); + }); + }; + + return { + async getThemeKeypadMenu() { + return await find.byCssSelector('.euiKeyPadMenu'); + }, + + async setFullNameInputField(newFullName: string) { + return await testSubjects.setValue('userProfileFullName', newFullName); + }, + + async setEmailInputField(newEmailAddress: string, clearWithKeyboard: boolean = false) { + return await testSubjects.setValue('userProfileEmail', newEmailAddress, { + clearWithKeyboard, + }); + }, + + async getChangePasswordButton() { + return await testSubjects.find('openChangePasswordForm'); + }, + + async setCurrentPasswordField(currentPassword: string) { + return await testSubjects.setValue( + 'editUserChangePasswordCurrentPasswordInput', + currentPassword + ); + }, + + async setNewPasswordField(newPassword: string) { + return await testSubjects.setValue('editUserChangePasswordNewPasswordInput', newPassword); + }, + + async setConfirmPasswordField(newPassword: string) { + return await testSubjects.setValue('editUserChangePasswordConfirmPasswordInput', newPassword); + }, + + async getChangePasswordFormSubmitButton() { + return await testSubjects.find('changePasswordFormSubmitButton'); + }, + getThemeTag, + saveUserProfileChanges, + changeUserProfileTheme, + }; +} diff --git a/x-pack/test/functional/services/aiops/change_point_detection_page.ts b/x-pack/test/functional/services/aiops/change_point_detection_page.ts index 4f83137df472..b4950763194c 100644 --- a/x-pack/test/functional/services/aiops/change_point_detection_page.ts +++ b/x-pack/test/functional/services/aiops/change_point_detection_page.ts @@ -26,7 +26,7 @@ export function ChangePointDetectionPageProvider( const dashboardPage = getPageObject('dashboard'); return { - async navigateToIndexPatternSelection() { + async navigateToDataViewSelection() { await testSubjects.click('mlMainTab changePointDetection'); await testSubjects.existOrFail('mlPageSourceSelection'); }, diff --git a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts index 59c786833a53..661881a28838 100644 --- a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts @@ -21,7 +21,7 @@ export function LogPatternAnalysisPageProvider({ getService, getPageObject }: Ft }); }, - async navigateToIndexPatternSelection() { + async navigateToDataViewSelection() { await testSubjects.click('mlMainTab logCategorization'); await testSubjects.existOrFail('mlPageSourceSelection'); }, diff --git a/x-pack/test/functional/services/aiops/log_rate_analysis_data_generator.ts b/x-pack/test/functional/services/aiops/log_rate_analysis_data_generator.ts index 48028b2ddbd1..7e1ead80b4ff 100644 --- a/x-pack/test/functional/services/aiops/log_rate_analysis_data_generator.ts +++ b/x-pack/test/functional/services/aiops/log_rate_analysis_data_generator.ts @@ -14,9 +14,15 @@ import { FtrProviderContext } from '../../ftr_provider_context'; const LOG_RATE_ANALYSYS_DATA_GENERATOR = { KIBANA_SAMPLE_DATA_LOGS: 'kibana_sample_data_logs', FAREQUOTE_WITH_SPIKE: 'farequote_with_spike', - ARTIFICIAL_LOGS_WITH_SPIKE_NOTEXTFIELD: 'artificial_logs_with_spike_notextfield', + ARTIFICIAL_LOGS_WITH_SPIKE_ZERODOCSFALLBACK: 'artificial_logs_with_spike_zerodocsfallback', + ARTIFICIAL_LOGS_WITH_SPIKE_TEXTFIELD_ZERODOCSFALLBACK: + 'artificial_logs_with_spike_textfield_zerodocsfallback', + ARTIFICIAL_LOGS_WITH_DIP_ZERODOCSFALLBACK: 'artificial_logs_with_dip_zerodocsfallback', + ARTIFICIAL_LOGS_WITH_DIP_TEXTFIELD_ZERODOCSFALLBACK: + 'artificial_logs_with_dip_textfield_zerodocsfallback', + ARTIFICIAL_LOGS_WITH_SPIKE: 'artificial_logs_with_spike', ARTIFICIAL_LOGS_WITH_SPIKE_TEXTFIELD: 'artificial_logs_with_spike_textfield', - ARTIFICIAL_LOGS_WITH_DIP_NOTEXTFIELD: 'artificial_logs_with_dip_notextfield', + ARTIFICIAL_LOGS_WITH_DIP: 'artificial_logs_with_dip', ARTIFICIAL_LOGS_WITH_DIP_TEXTFIELD: 'artificial_logs_with_dip_textfield', } as const; export type LogRateAnalysisDataGenerator = @@ -38,7 +44,7 @@ const DAY_MS = 86400000; const DEVIATION_TS = REFERENCE_TS - DAY_MS * 2; const BASELINE_TS = DEVIATION_TS - DAY_MS * 1; -function getMessage(timestamp: number, user: string, url: string, responseCode: string) { +function getTextFieldMessage(timestamp: number, user: string, url: string, responseCode: string) { const date = new Date(timestamp); return `${user} [${date.toLocaleString('en-US')}] "GET /${url} HTTP/1.1" ${responseCode}`; } @@ -46,12 +52,37 @@ function getMessage(timestamp: number, user: string, url: string, responseCode: function getArtificialLogsWithDeviation( index: string, deviationType: string, - includeTextField = false + includeTextField = false, + includeGaps = false ) { const bulkBody: estypes.BulkRequest['body'] = []; const action = { index: { _index: index } }; let tsOffset = 0; + if (includeGaps) { + const earliestDoc: GeneratedDoc = { + user: 'Peter', + response_code: '200', + url: 'login.php', + version: 'v1.0.0', + '@timestamp': BASELINE_TS - DAY_MS, + should_ignore_this_field: 'should_ignore_this_field', + }; + bulkBody.push(action); + bulkBody.push(earliestDoc); + + const latestDoc: GeneratedDoc = { + user: 'Peter', + response_code: '200', + url: 'login.php', + version: 'v1.0.0', + '@timestamp': DEVIATION_TS + 2 * DAY_MS, + should_ignore_this_field: 'should_ignore_this_field', + }; + bulkBody.push(action); + bulkBody.push(latestDoc); + } + // Creates docs evenly spread across baseline and deviation time frame [BASELINE_TS, DEVIATION_TS].forEach((ts) => { ['Peter', 'Paul', 'Mary'].forEach((user) => { @@ -66,8 +97,32 @@ function getArtificialLogsWithDeviation( ) ) { tsOffset = 0; - [...Array(100)].forEach(() => { - tsOffset += Math.round(DAY_MS / 100); + + let docCount = 100; + let responseCodeFactor = 1; + + if (includeGaps) { + if (responseCode === '404') { + responseCodeFactor = 2; + } else if (responseCode === '500') { + responseCodeFactor = 3; + } + + if (url === 'user.php') { + responseCodeFactor *= 2; + } else if (url === 'home.php') { + responseCodeFactor *= 3; + } + + if (user === 'Paul') { + docCount = 40 * responseCodeFactor; + } else if (user === 'Mary') { + docCount = 25 * responseCodeFactor; + } + } + + [...Array(docCount)].forEach(() => { + tsOffset += Math.round(DAY_MS / docCount); const timestamp = ts + tsOffset; const doc: GeneratedDoc = { user, @@ -79,7 +134,7 @@ function getArtificialLogsWithDeviation( }; if (includeTextField) { - doc.message = getMessage(timestamp, user, url, responseCode); + doc.message = getTextFieldMessage(timestamp, user, url, responseCode); } bulkBody.push(action); @@ -116,7 +171,7 @@ function getArtificialLogsWithDeviation( }; if (includeTextField) { - doc.message = getMessage(timestamp, 'Peter', url, responseCode); + doc.message = getTextFieldMessage(timestamp, 'Peter', url, responseCode); } bulkBody.push(action); @@ -204,10 +259,14 @@ export function LogRateAnalysisDataGeneratorProvider({ getService }: FtrProvider }); break; - case 'artificial_logs_with_spike_notextfield': + case 'artificial_logs_with_spike': case 'artificial_logs_with_spike_textfield': - case 'artificial_logs_with_dip_notextfield': + case 'artificial_logs_with_dip': case 'artificial_logs_with_dip_textfield': + case 'artificial_logs_with_spike_zerodocsfallback': + case 'artificial_logs_with_spike_textfield_zerodocsfallback': + case 'artificial_logs_with_dip_zerodocsfallback': + case 'artificial_logs_with_dip_textfield_zerodocsfallback': try { const indexExists = await es.indices.exists({ index: dataGenerator, @@ -238,12 +297,26 @@ export function LogRateAnalysisDataGeneratorProvider({ getService }: FtrProvider }); const dataGeneratorOptions = dataGenerator.split('_'); - const deviationType = dataGeneratorOptions[3] ?? LOG_RATE_ANALYSIS_TYPE.SPIKE; - const textField = dataGeneratorOptions[4] === 'textfield' ?? false; + + let deviationType = dataGeneratorOptions.includes(LOG_RATE_ANALYSIS_TYPE.SPIKE) + ? LOG_RATE_ANALYSIS_TYPE.SPIKE + : LOG_RATE_ANALYSIS_TYPE.DIP; + + const textField = dataGeneratorOptions.includes('textfield'); + const zeroDocsFallback = dataGeneratorOptions.includes('zerodocsfallback'); + + if (zeroDocsFallback) { + deviationType = LOG_RATE_ANALYSIS_TYPE.SPIKE; + } await es.bulk({ refresh: 'wait_for', - body: getArtificialLogsWithDeviation(dataGenerator, deviationType, textField), + body: getArtificialLogsWithDeviation( + dataGenerator, + deviationType, + textField, + zeroDocsFallback + ), }); break; @@ -262,10 +335,14 @@ export function LogRateAnalysisDataGeneratorProvider({ getService }: FtrProvider await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); break; - case 'artificial_logs_with_spike_notextfield': + case 'artificial_logs_with_spike': case 'artificial_logs_with_spike_textfield': - case 'artificial_logs_with_dip_notextfield': + case 'artificial_logs_with_dip': case 'artificial_logs_with_dip_textfield': + case 'artificial_logs_with_spike_zerodocsfallback': + case 'artificial_logs_with_spike_textfield_zerodocsfallback': + case 'artificial_logs_with_dip_zerodocsfallback': + case 'artificial_logs_with_dip_textfield_zerodocsfallback': try { await es.indices.delete({ index: dataGenerator, diff --git a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts index 510a056ca5c4..a8733fb2114a 100644 --- a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts @@ -11,6 +11,8 @@ import type { LogRateAnalysisType } from '@kbn/aiops-utils'; import type { FtrProviderContext } from '../../ftr_provider_context'; +import type { LogRateAnalysisDataGenerator } from './log_rate_analysis_data_generator'; + export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrProviderContext) { const browser = getService('browser'); const elasticChart = getService('elasticChart'); @@ -241,7 +243,12 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr }); }, - async assertAnalysisComplete(analisysType: LogRateAnalysisType) { + async assertAnalysisComplete( + analysisType: LogRateAnalysisType, + dataGenerator: LogRateAnalysisDataGenerator + ) { + const dataGeneratorParts = dataGenerator.split('_'); + const zeroDocsFallback = dataGeneratorParts.includes('zerodocsfallback'); await retry.tryForTime(30 * 1000, async () => { await testSubjects.existOrFail('aiopsAnalysisComplete'); const currentProgressTitle = await testSubjects.getVisibleText('aiopsAnalysisComplete'); @@ -251,11 +258,22 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr const currentAnalysisTypeCalloutTitle = await testSubjects.getVisibleText( 'aiopsAnalysisTypeCalloutTitle' ); - expect(currentAnalysisTypeCalloutTitle).to.be(`Analysis type: Log rate ${analisysType}`); + + if (zeroDocsFallback && analysisType === 'spike') { + expect(currentAnalysisTypeCalloutTitle).to.be( + 'Analysis type: Top items for deviation time range' + ); + } else if (zeroDocsFallback && analysisType === 'dip') { + expect(currentAnalysisTypeCalloutTitle).to.be( + 'Analysis type: Top items for baseline time range' + ); + } else { + expect(currentAnalysisTypeCalloutTitle).to.be(`Analysis type: Log rate ${analysisType}`); + } }); }, - async navigateToIndexPatternSelection() { + async navigateToDataViewSelection() { await testSubjects.click('mlMainTab logRateAnalysis'); await testSubjects.existOrFail('mlPageSourceSelection'); }, diff --git a/x-pack/test/functional/services/cases/list.ts b/x-pack/test/functional/services/cases/list.ts index ef3e61acf521..77e250cf838d 100644 --- a/x-pack/test/functional/services/cases/list.ts +++ b/x-pack/test/functional/services/cases/list.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CaseSeverityWithAll } from '@kbn/cases-plugin/common/ui'; import { CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -136,7 +135,7 @@ export function CasesTableServiceProvider( async filterByTag(tag: string) { await common.clickAndValidate( - 'options-filter-popover-button-Tags', + 'options-filter-popover-button-tags', `options-filter-popover-item-${tag}` ); @@ -145,7 +144,7 @@ export function CasesTableServiceProvider( async filterByCategory(category: string) { await common.clickAndValidate( - 'options-filter-popover-button-Categories', + 'options-filter-popover-button-category', `options-filter-popover-item-${category}` ); @@ -153,14 +152,28 @@ export function CasesTableServiceProvider( }, async filterByStatus(status: CaseStatuses) { - await common.clickAndValidate('case-status-filter', `case-status-filter-${status}`); + await common.clickAndValidate( + 'options-filter-popover-button-status', + `options-filter-popover-item-${status}` + ); + + await testSubjects.click(`options-filter-popover-item-${status}`); + // to close the popup + await testSubjects.click('options-filter-popover-button-status'); - await testSubjects.click(`case-status-filter-${status}`); + await testSubjects.missingOrFail(`options-filter-popover-item-${status}`, { + timeout: 5000, + }); }, - async filterBySeverity(severity: CaseSeverityWithAll) { - await common.clickAndValidate('case-severity-filter', `case-severity-filter-${severity}`); - await testSubjects.click(`case-severity-filter-${severity}`); + async filterBySeverity(severity: CaseSeverity) { + await common.clickAndValidate( + 'options-filter-popover-button-severity', + `options-filter-popover-item-${severity}` + ); + await testSubjects.click(`options-filter-popover-item-${severity}`); + // to close the popup + await testSubjects.click('options-filter-popover-button-severity'); }, async filterByAssignee(assignee: string) { @@ -172,11 +185,11 @@ export function CasesTableServiceProvider( async filterByOwner(owner: string) { await common.clickAndValidate( - 'solution-filter-popover-button', - `solution-filter-popover-item-${owner}` + 'options-filter-popover-button-owner', + `options-filter-popover-item-${owner}` ); - await testSubjects.click(`solution-filter-popover-item-${owner}`); + await testSubjects.click(`options-filter-popover-item-${owner}`); }, async refreshTable() { diff --git a/x-pack/test/functional/services/logs_ui/log_entry_rate.ts b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts index 6be84edeb194..bf58d74a06c4 100644 --- a/x-pack/test/functional/services/logs_ui/log_entry_rate.ts +++ b/x-pack/test/functional/services/logs_ui/log_entry_rate.ts @@ -21,8 +21,60 @@ export function LogEntryRatePageProvider({ getPageObjects, getService }: FtrProv return await testSubjects.find('logEntryRateSetupPage'); }, + async getResultsScreen(): Promise { + return await testSubjects.find('logEntryRateResultsPage'); + }, + async getNoDataScreen() { return await testSubjects.find('noDataPage'); }, + + async startJobSetup() { + await testSubjects.click('infraLogEntryRateSetupContentMlSetupButton'); + }, + + async manageMlJobs() { + await testSubjects.click('infraManageJobsButtonManageMlJobsButton'); + }, + + async getSetupFlyout(): Promise { + return await testSubjects.find('infraLogAnalysisSetupFlyout'); + }, + + async startRateJobCreation() { + const buttons = await testSubjects.findAll('infraCreateJobButtonButton'); + await buttons[0].click(); + }, + + async startCategoriesCountJobCreation() { + const buttons = await testSubjects.findAll('infraCreateJobButtonButton'); + await buttons[1].click(); + }, + + async canCreateJob() { + const createJobButton = await testSubjects.find('infraCreateMLJobsButtonCreateMlJobButton'); + const disabled = await createJobButton.getAttribute('disabled'); + return disabled !== 'true'; + }, + + async createJob() { + await testSubjects.click('infraCreateMLJobsButtonCreateMlJobButton'); + }, + + async canRecreateJob() { + const createJobButton = await testSubjects.find( + 'infraRecreateMLJobsButtonRecreateMlJobsButton' + ); + const disabled = await createJobButton.getAttribute('disabled'); + return disabled !== 'true'; + }, + + async recreateJob() { + await testSubjects.click('infraRecreateMLJobsButtonRecreateMlJobsButton'); + }, + + async jobCreationDone() { + return await testSubjects.exists('infraProcessStepViewResultsButton'); + }, }; } diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts index beedbb145dce..50d7738abf73 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts @@ -259,13 +259,13 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( async assertDestIndexInputExists() { await retry.tryForTime(4000, async () => { - await testSubjects.existOrFail('mlAnalyticsCreateJobFlyoutDestinationIndexInput'); + await testSubjects.existOrFail('mlCreationWizardUtilsDestinationIndexInput'); }); }, async assertDestIndexValue(expectedValue: string) { const actualDestIndex = await testSubjects.getAttribute( - 'mlAnalyticsCreateJobFlyoutDestinationIndexInput', + 'mlCreationWizardUtilsDestinationIndexInput', 'value' ); expect(actualDestIndex).to.eql( @@ -275,13 +275,9 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( }, async setDestIndex(destIndex: string) { - await mlCommonUI.setValueWithChecks( - 'mlAnalyticsCreateJobFlyoutDestinationIndexInput', - destIndex, - { - clearWithKeyboard: true, - } - ); + await mlCommonUI.setValueWithChecks('mlCreationWizardUtilsDestinationIndexInput', destIndex, { + clearWithKeyboard: true, + }); await this.assertDestIndexValue(destIndex); }, @@ -623,31 +619,40 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( }); }, - async assertCreateIndexPatternSwitchExists() { - await testSubjects.existOrFail(`mlAnalyticsCreateJobWizardCreateIndexPatternCheckbox`, { - allowHidden: true, - }); - }, - - async getCreateIndexPatternSwitchCheckState(): Promise { - const state = await testSubjects.getAttribute( - 'mlAnalyticsCreateJobWizardCreateIndexPatternCheckbox', - 'checked' - ); - return state === 'true'; + async assertCreateDataViewSwitchExists() { + await testSubjects.existOrFail(`mlCreateDataViewSwitch`, { allowHidden: true }); }, - async assertCreateIndexPatternSwitchCheckState(expectedCheckState: boolean) { - const actualCheckState = await this.getCreateIndexPatternSwitchCheckState(); + async assertCreateDataViewSwitchCheckState(expectedCheckState: boolean) { + const actualCheckState = + (await testSubjects.getAttribute('mlCreateDataViewSwitch', 'aria-checked')) === 'true'; expect(actualCheckState).to.eql( expectedCheckState, `Create data view switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, + async assertDataViewTimeFieldInputExists() { + await testSubjects.existOrFail(`mlDataViewTimeFieldSelect`); + }, + + async assertDataViewTimeFieldValue(expectedValue: string) { + const actualValue = await testSubjects.getAttribute(`mlDataViewTimeFieldSelect`, 'value'); + expect(actualValue).to.eql( + expectedValue, + `Data view time field should be ${expectedValue}, got ${actualValue}` + ); + }, + + async setDataViewTimeField(fieldName: string) { + const selectControl = await testSubjects.find('mlDataViewTimeFieldSelect'); + await selectControl.type(fieldName); + await this.assertDataViewTimeFieldValue(fieldName); + }, + async getDestIndexSameAsIdSwitchCheckState(): Promise { const state = await testSubjects.getAttribute( - 'mlAnalyticsCreateJobWizardDestIndexSameAsIdSwitch', + 'mlCreationWizardUtilsJobIdAsDestIndexNameSwitch', 'aria-checked' ); return state === 'true'; @@ -662,35 +667,32 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( }, async assertDestIndexSameAsIdSwitchExists() { - await testSubjects.existOrFail(`mlAnalyticsCreateJobWizardDestIndexSameAsIdSwitch`, { + await testSubjects.existOrFail(`mlCreationWizardUtilsJobIdAsDestIndexNameSwitch`, { allowHidden: true, }); }, async setDestIndexSameAsIdCheckState(checkState: boolean) { if ((await this.getDestIndexSameAsIdSwitchCheckState()) !== checkState) { - await testSubjects.click('mlAnalyticsCreateJobWizardDestIndexSameAsIdSwitch'); + await testSubjects.click('mlCreationWizardUtilsJobIdAsDestIndexNameSwitch'); } await this.assertDestIndexSameAsIdCheckState(checkState); }, - async setCreateIndexPatternSwitchState(checkState: boolean) { - if ((await this.getCreateIndexPatternSwitchCheckState()) !== checkState) { - await testSubjects.click('mlAnalyticsCreateJobWizardCreateIndexPatternCheckbox'); - } - await this.assertCreateIndexPatternSwitchCheckState(checkState); + async assertStartJobSwitchExists() { + await testSubjects.existOrFail('mlAnalyticsCreateJobWizardStartJobSwitch'); }, - async assertStartJobCheckboxExists() { - await testSubjects.existOrFail('mlAnalyticsCreateJobWizardStartJobCheckbox'); + async getStartJobSwitchCheckState(): Promise { + const state = await testSubjects.getAttribute( + 'mlAnalyticsCreateJobWizardStartJobSwitch', + 'aria-checked' + ); + return state === 'true'; }, - async assertStartJobCheckboxCheckState(expectedCheckState: boolean) { - const actualCheckState = - (await testSubjects.getAttribute( - 'mlAnalyticsCreateJobWizardStartJobCheckbox', - 'checked' - )) === 'true'; + async assertStartJobSwitchCheckState(expectedCheckState: boolean) { + const actualCheckState = await this.getStartJobSwitchCheckState(); expect(actualCheckState).to.eql( expectedCheckState, `Start job check state should be ${expectedCheckState} (got ${actualCheckState})` @@ -755,7 +757,6 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( async assertCreationCalloutMessagesExist() { await testSubjects.existOrFail('analyticsWizardCreationCallout_0'); await testSubjects.existOrFail('analyticsWizardCreationCallout_1'); - await testSubjects.existOrFail('analyticsWizardCreationCallout_2'); }, async navigateToJobManagementPage() { diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_edit.ts b/x-pack/test/functional/services/ml/data_frame_analytics_edit.ts index a58820ae393b..e05be8d8c768 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_edit.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_edit.ts @@ -18,7 +18,7 @@ import { MlCustomUrls } from './custom_urls'; export interface DiscoverUrlConfig { label: string; - indexPattern: string; + indexName: string; queryEntityFieldNames: string[]; timeRange: TimeRangeType; timeRangeInterval?: string; @@ -98,7 +98,7 @@ export function MachineLearningDataFrameAnalyticsEditProvider( ); await mlCommonUI.selectSelectValueByVisibleText( 'mlJobCustomUrlDiscoverIndexPatternInput', - customUrl.indexPattern + customUrl.indexName ); await customUrls.setCustomUrlQueryEntityFieldNames(customUrl.queryEntityFieldNames); if (addTimerange) { diff --git a/x-pack/test/functional/services/ml/data_visualizer.ts b/x-pack/test/functional/services/ml/data_visualizer.ts index 3571f9193e6b..cccdeaf07e4f 100644 --- a/x-pack/test/functional/services/ml/data_visualizer.ts +++ b/x-pack/test/functional/services/ml/data_visualizer.ts @@ -55,7 +55,7 @@ export function MachineLearningDataVisualizerProvider({ getService }: FtrProvide ); }, - async navigateToIndexPatternSelection() { + async navigateToDataViewSelection() { await testSubjects.click('mlDataVisualizerSelectIndexButton'); await testSubjects.existOrFail('mlPageSourceSelection'); }, diff --git a/x-pack/test/functional/services/ml/test_resources.ts b/x-pack/test/functional/services/ml/test_resources.ts index 22f43a08f1e7..5035b6844b9c 100644 --- a/x-pack/test/functional/services/ml/test_resources.ts +++ b/x-pack/test/functional/services/ml/test_resources.ts @@ -120,7 +120,7 @@ export function MachineLearningTestResourcesProvider( return savedObjectIds; }, - async getIndexPatternId(title: string, space?: string): Promise { + async getDataViewId(title: string, space?: string): Promise { return this.getSavedObjectIdByTitle(title, SavedObjectType.INDEX_PATTERN, space); }, @@ -136,11 +136,7 @@ export function MachineLearningTestResourcesProvider( return this.getSavedObjectIdByTitle(title, SavedObjectType.DASHBOARD); }, - async createIndexPattern( - title: string, - timeFieldName?: string, - space?: string - ): Promise { + async createDataView(title: string, timeFieldName?: string, space?: string): Promise { log.debug( `Creating index pattern with title '${title}'${ timeFieldName !== undefined ? ` and time field '${timeFieldName}'` : '' @@ -153,7 +149,7 @@ export function MachineLearningTestResourcesProvider( .send({ attributes: { title, timeFieldName } }); mlApi.assertResponseStatusCode(200, status, createResponse); - await this.assertIndexPatternExistByTitle(title, space); + await this.assertDataViewExistByTitle(title, space); log.debug(` > Created with id '${createResponse.id}'`); return createResponse.id; @@ -172,21 +168,21 @@ export function MachineLearningTestResourcesProvider( return createResponse; }, - async createIndexPatternIfNeeded( + async createDataViewIfNeeded( title: string, timeFieldName?: string, space?: string ): Promise { - const indexPatternId = await this.getIndexPatternId(title, space); - if (indexPatternId !== undefined) { + const dataViewId = await this.getDataViewId(title, space); + if (dataViewId !== undefined) { log.debug(`Index pattern with title '${title}' already exists. Nothing to create.`); - return indexPatternId; + return dataViewId; } else { - return await this.createIndexPattern(title, timeFieldName, space); + return await this.createDataView(title, timeFieldName, space); } }, - async assertIndexPatternNotExist(title: string) { + async assertDataViewNotExist(title: string) { await this.assertSavedObjectNotExistsByTitle(title, SavedObjectType.INDEX_PATTERN); }, @@ -218,7 +214,7 @@ export function MachineLearningTestResourcesProvider( return createResponse.id; }, - async createSavedSearchIfNeeded(savedSearch: any, indexPatternTitle: string): Promise { + async createSavedSearchIfNeeded(savedSearch: any, dataViewTitle: string): Promise { const title = savedSearch.requestBody.attributes.title; const savedSearchId = await this.getSavedSearchId(title); if (savedSearchId !== undefined) { @@ -227,24 +223,24 @@ export function MachineLearningTestResourcesProvider( } else { const body = await this.updateSavedSearchRequestBody( savedSearch.requestBody, - indexPatternTitle + dataViewTitle ); return await this.createSavedSearch(title, body); } }, - async updateSavedSearchRequestBody(body: object, indexPatternTitle: string): Promise { - const indexPatternId = await this.getIndexPatternId(indexPatternTitle); - if (indexPatternId === undefined) { + async updateSavedSearchRequestBody(body: object, dataViewTitle: string): Promise { + const dataViewId = await this.getDataViewId(dataViewTitle); + if (dataViewId === undefined) { throw new Error( - `Index pattern '${indexPatternTitle}' to base saved search on does not exist. ` + `Index pattern '${dataViewTitle}' to base saved search on does not exist. ` ); } // inject index pattern id const updatedBody = JSON.parse(JSON.stringify(body), (_key, value) => { if (value === 'INDEX_PATTERN_ID_PLACEHOLDER') { - return indexPatternId; + return dataViewId; } else { return value; } @@ -258,8 +254,8 @@ export function MachineLearningTestResourcesProvider( return updatedBody; }, - async createSavedSearchFarequoteFilterIfNeeded(indexPatternTitle: string = 'ft_farequote') { - await this.createSavedSearchIfNeeded(savedSearches.farequoteFilter, indexPatternTitle); + async createSavedSearchFarequoteFilterIfNeeded(dataViewTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteFilter, dataViewTitle); }, async createMLTestDashboardIfNeeded(): Promise { @@ -281,48 +277,37 @@ export function MachineLearningTestResourcesProvider( } }, - async createSavedSearchFarequoteLuceneIfNeeded(indexPatternTitle: string = 'ft_farequote') { - await this.createSavedSearchIfNeeded(savedSearches.farequoteLucene, indexPatternTitle); + async createSavedSearchFarequoteLuceneIfNeeded(dataViewTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteLucene, dataViewTitle); }, - async createSavedSearchFarequoteKueryIfNeeded(indexPatternTitle: string = 'ft_farequote') { - await this.createSavedSearchIfNeeded(savedSearches.farequoteKuery, indexPatternTitle); + async createSavedSearchFarequoteKueryIfNeeded(dataViewTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteKuery, dataViewTitle); }, async createSavedSearchFarequoteFilterAndLuceneIfNeeded( - indexPatternTitle: string = 'ft_farequote' + dataViewTitle: string = 'ft_farequote' ) { - await this.createSavedSearchIfNeeded( - savedSearches.farequoteFilterAndLucene, - indexPatternTitle - ); + await this.createSavedSearchIfNeeded(savedSearches.farequoteFilterAndLucene, dataViewTitle); }, - async createSavedSearchFarequoteFilterAndKueryIfNeeded( - indexPatternTitle: string = 'ft_farequote' - ) { - await this.createSavedSearchIfNeeded( - savedSearches.farequoteFilterAndKuery, - indexPatternTitle - ); + async createSavedSearchFarequoteFilterAndKueryIfNeeded(dataViewTitle: string = 'ft_farequote') { + await this.createSavedSearchIfNeeded(savedSearches.farequoteFilterAndKuery, dataViewTitle); }, async createSavedSearchFarequoteFilterTwoAndLuceneIfNeeded( - indexPatternTitle: string = 'ft_farequote' + dataViewTitle: string = 'ft_farequote' ) { await this.createSavedSearchIfNeeded( savedSearches.farequoteFilterTwoAndLucene, - indexPatternTitle + dataViewTitle ); }, async createSavedSearchFarequoteFilterTwoAndKueryIfNeeded( - indexPatternTitle: string = 'ft_farequote' + dataViewTitle: string = 'ft_farequote' ) { - await this.createSavedSearchIfNeeded( - savedSearches.farequoteFilterTwoAndKuery, - indexPatternTitle - ); + await this.createSavedSearchIfNeeded(savedSearches.farequoteFilterTwoAndKuery, dataViewTitle); }, async deleteSavedObjectById( @@ -349,19 +334,19 @@ export function MachineLearningTestResourcesProvider( } }, - async deleteIndexPatternByTitle(title: string, space?: string) { + async deleteDataViewByTitle(title: string, space?: string) { log.debug(`Deleting index pattern with title '${title}'...`); - const indexPatternId = await this.getIndexPatternId(title, space); - if (indexPatternId === undefined) { + const dataViewId = await this.getDataViewId(title, space); + if (dataViewId === undefined) { log.debug(`Index pattern with title '${title}' does not exists. Nothing to delete.`); return; } else { - await this.deleteIndexPatternById(indexPatternId, space); + await this.deleteDataViewById(dataViewId, space); } }, - async deleteIndexPatternById(id: string, space?: string) { + async deleteDataViewById(id: string, space?: string) { await this.deleteSavedObjectById(id, SavedObjectType.INDEX_PATTERN, false, space); }, @@ -485,11 +470,11 @@ export function MachineLearningTestResourcesProvider( ); }, - async assertIndexPatternExistByTitle(title: string, space?: string) { + async assertDataViewExistByTitle(title: string, space?: string) { await this.assertSavedObjectExistsByTitle(title, SavedObjectType.INDEX_PATTERN, space); }, - async assertIndexPatternExistById(id: string) { + async assertDataViewExistById(id: string) { await this.assertSavedObjectExistsById(id, SavedObjectType.INDEX_PATTERN); }, diff --git a/x-pack/test/functional/services/observability/users.ts b/x-pack/test/functional/services/observability/users.ts index ba67ce8602f5..0e2915190d12 100644 --- a/x-pack/test/functional/services/observability/users.ts +++ b/x-pack/test/functional/services/observability/users.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Role } from '@kbn/security-plugin/common/model'; +import { Role } from '@kbn/security-plugin/common'; import { FtrProviderContext } from '../../ftr_provider_context'; type CreateRolePayload = Pick; diff --git a/x-pack/test/functional/services/transform/wizard.ts b/x-pack/test/functional/services/transform/wizard.ts index 46b9bfadcdd0..5e00904ab8a2 100644 --- a/x-pack/test/functional/services/transform/wizard.ts +++ b/x-pack/test/functional/services/transform/wizard.ts @@ -700,13 +700,42 @@ export function TransformWizardProvider({ getService, getPageObjects }: FtrProvi await this.assertTransformDescriptionValue(transformDescription); }, + async getDestIndexSameAsIdSwitchCheckState(): Promise { + const state = await testSubjects.getAttribute( + 'mlCreationWizardUtilsJobIdAsDestIndexNameSwitch', + 'aria-checked' + ); + return state === 'true'; + }, + + async assertDestIndexSameAsIdCheckState(expectedCheckState: boolean) { + const actualCheckState = await this.getDestIndexSameAsIdSwitchCheckState(); + expect(actualCheckState).to.eql( + expectedCheckState, + `Destination index same as job id check state should be '${expectedCheckState}' (got '${actualCheckState}')` + ); + }, + + async assertDestIndexSameAsIdSwitchExists() { + await testSubjects.existOrFail(`mlCreationWizardUtilsJobIdAsDestIndexNameSwitch`, { + allowHidden: true, + }); + }, + + async setDestIndexSameAsIdCheckState(checkState: boolean) { + if ((await this.getDestIndexSameAsIdSwitchCheckState()) !== checkState) { + await testSubjects.click('mlCreationWizardUtilsJobIdAsDestIndexNameSwitch'); + } + await this.assertDestIndexSameAsIdCheckState(checkState); + }, + async assertDestinationIndexInputExists() { - await testSubjects.existOrFail('transformDestinationIndexInput'); + await testSubjects.existOrFail('mlCreationWizardUtilsDestinationIndexInput'); }, async assertDestinationIndexValue(expectedValue: string) { const actualDestinationIndex = await testSubjects.getAttribute( - 'transformDestinationIndexInput', + 'mlCreationWizardUtilsDestinationIndexInput', 'value' ); expect(actualDestinationIndex).to.eql( @@ -716,20 +745,23 @@ export function TransformWizardProvider({ getService, getPageObjects }: FtrProvi }, async setDestinationIndex(destinationIndex: string) { - await ml.commonUI.setValueWithChecks('transformDestinationIndexInput', destinationIndex, { - clearWithKeyboard: true, - }); + await ml.commonUI.setValueWithChecks( + 'mlCreationWizardUtilsDestinationIndexInput', + destinationIndex, + { + clearWithKeyboard: true, + } + ); await this.assertDestinationIndexValue(destinationIndex); }, async assertCreateDataViewSwitchExists() { - await testSubjects.existOrFail(`transformCreateDataViewSwitch`, { allowHidden: true }); + await testSubjects.existOrFail(`mlCreateDataViewSwitch`, { allowHidden: true }); }, async assertCreateDataViewSwitchCheckState(expectedCheckState: boolean) { const actualCheckState = - (await testSubjects.getAttribute('transformCreateDataViewSwitch', 'aria-checked')) === - 'true'; + (await testSubjects.getAttribute('mlCreateDataViewSwitch', 'aria-checked')) === 'true'; expect(actualCheckState).to.eql( expectedCheckState, `Create data view switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` @@ -737,14 +769,11 @@ export function TransformWizardProvider({ getService, getPageObjects }: FtrProvi }, async assertDataViewTimeFieldInputExists() { - await testSubjects.existOrFail(`transformDataViewTimeFieldSelect`); + await testSubjects.existOrFail(`mlDataViewTimeFieldSelect`); }, async assertDataViewTimeFieldValue(expectedValue: string) { - const actualValue = await testSubjects.getAttribute( - `transformDataViewTimeFieldSelect`, - 'value' - ); + const actualValue = await testSubjects.getAttribute(`mlDataViewTimeFieldSelect`, 'value'); expect(actualValue).to.eql( expectedValue, `Data view time field should be ${expectedValue}, got ${actualValue}` @@ -752,7 +781,7 @@ export function TransformWizardProvider({ getService, getPageObjects }: FtrProvi }, async setDataViewTimeField(fieldName: string) { - const selectControl = await testSubjects.find('transformDataViewTimeFieldSelect'); + const selectControl = await testSubjects.find('mlDataViewTimeFieldSelect'); await selectControl.type(fieldName); await this.assertDataViewTimeFieldValue(fieldName); }, diff --git a/x-pack/test/functional_basic/apps/ml/data_visualizer/group1/index.ts b/x-pack/test/functional_basic/apps/ml/data_visualizer/group1/index.ts index 37295dda128a..cf8f8ed7db84 100644 --- a/x-pack/test/functional_basic/apps/ml/data_visualizer/group1/index.ts +++ b/x-pack/test/functional_basic/apps/ml/data_visualizer/group1/index.ts @@ -25,8 +25,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/module_sample_ecommerce'); diff --git a/x-pack/test/functional_basic/apps/ml/data_visualizer/group2/index.ts b/x-pack/test/functional_basic/apps/ml/data_visualizer/group2/index.ts index e1ed6d554a39..c4205e1bffd6 100644 --- a/x-pack/test/functional_basic/apps/ml/data_visualizer/group2/index.ts +++ b/x-pack/test/functional_basic/apps/ml/data_visualizer/group2/index.ts @@ -25,8 +25,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/module_sample_ecommerce'); diff --git a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts index 18a5dfaec2d6..d2e77f952285 100644 --- a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts +++ b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts @@ -25,8 +25,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/module_sample_ecommerce'); diff --git a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index_data_visualizer_actions_panel.ts b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index_data_visualizer_actions_panel.ts index f8e2c83a1afd..62cbc2e41e36 100644 --- a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index_data_visualizer_actions_panel.ts +++ b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index_data_visualizer_actions_panel.ts @@ -20,7 +20,7 @@ export default function ({ getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); - await ml.testResources.createIndexPatternIfNeeded(indexPatternName, '@timestamp'); + await ml.testResources.createDataViewIfNeeded(indexPatternName, '@timestamp'); await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -34,7 +34,7 @@ export default function ({ getService }: FtrProviderContext) { await ml.navigation.navigateToDataVisualizer(); await ml.testExecution.logTestStep('loads the saved search selection page'); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.testExecution.logTestStep('loads the index data visualizer page'); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(savedSearch); diff --git a/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts b/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts index 0ff4eca82a5c..49b477f9e110 100644 --- a/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts +++ b/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await ml.testResources.createDataViewIfNeeded(ecIndexPattern, 'order_date'); await ml.securityUI.loginAs(testUser.user); }); @@ -105,7 +105,7 @@ export default function ({ getService }: FtrProviderContext) { it('should display elements on Index Data Visualizer page correctly', async () => { await ml.testExecution.logTestStep('should load an index into the data visualizer page'); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexPattern); await ml.testExecution.logTestStep('should display the time range step'); diff --git a/x-pack/test/functional_basic/apps/ml/permissions/index.ts b/x-pack/test/functional_basic/apps/ml/permissions/index.ts index 53e78b4d08c1..8e72bb7bf51e 100644 --- a/x-pack/test/functional_basic/apps/ml/permissions/index.ts +++ b/x-pack/test/functional_basic/apps/ml/permissions/index.ts @@ -25,8 +25,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.testResources.deleteSavedSearches(); - await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); - await ml.testResources.deleteIndexPatternByTitle('ft_module_sample_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + await ml.testResources.deleteDataViewByTitle('ft_module_sample_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/module_sample_ecommerce'); diff --git a/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts b/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts index c7a3f13d23ed..60554e8b1604 100644 --- a/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts +++ b/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); - await ml.testResources.createIndexPatternIfNeeded(ecIndexPattern, 'order_date'); + await ml.testResources.createDataViewIfNeeded(ecIndexPattern, 'order_date'); await ml.securityUI.loginAs(testUser.user); }); @@ -105,7 +105,7 @@ export default function ({ getService }: FtrProviderContext) { it('should display elements on Index Data Visualizer page correctly', async () => { await ml.testExecution.logTestStep('should load an index into the data visualizer page'); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(ecIndexPattern); await ml.testExecution.logTestStep('should display the time range step'); diff --git a/x-pack/test/functional_cloud/tests/cloud_links.ts b/x-pack/test/functional_cloud/tests/cloud_links.ts index 94f67401c98f..6125b52135b9 100644 --- a/x-pack/test/functional_cloud/tests/cloud_links.ts +++ b/x-pack/test/functional_cloud/tests/cloud_links.ts @@ -48,11 +48,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('A button to open a modal to view the CloudID and ES endpoint is added', async () => { - await PageObjects.common.clickAndValidate('helpMenuButton', 'endpointsHelpLink'); - expect(await find.byCssSelector('[data-test-subj="endpointsHelpLink"]')).to.not.be(null); + await PageObjects.common.clickAndValidate('helpMenuButton', 'connectionDetailsHelpLink'); + expect(await find.byCssSelector('[data-test-subj="connectionDetailsHelpLink"]')).to.not.be( + null + ); // Open the modal - await PageObjects.common.clickAndValidate('endpointsHelpLink', 'deploymentDetailsModal'); + await PageObjects.common.clickAndValidate( + 'connectionDetailsHelpLink', + 'deploymentDetailsModal' + ); const esEndpointInput = await find.byCssSelector( '[data-test-subj="deploymentDetailsEsEndpoint"]' diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts index 5ac08acfbc6e..cb9dffb54888 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts @@ -288,7 +288,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { it('renders different solutions', async () => { await openModal(); - await testSubjects.existOrFail('solution-filter-popover-button'); + await testSubjects.existOrFail('options-filter-popover-button-owner'); for (const [, currentCaseId] of createdCases.entries()) { await testSubjects.existOrFail(`cases-table-row-${currentCaseId}`); diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group2/list_view.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group2/list_view.ts index c1d2b2a9d7c0..32a1ef6125b7 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group2/list_view.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group2/list_view.ts @@ -7,7 +7,6 @@ import expect from '@kbn/expect'; import { CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; -import { SeverityAll } from '@kbn/cases-plugin/common/ui'; import { UserProfile } from '@kbn/user-profile-components'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { @@ -444,6 +443,25 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await cases.casesTable.validateCasesTableHasNthRows(1); }); + it('filter multiple status', async () => { + await cases.casesTable.changeStatus(CaseStatuses['in-progress'], 0); + await cases.casesTable.refreshTable(); + await cases.casesTable.changeStatus(CaseStatuses.closed, 1); + await cases.casesTable.refreshTable(); + + // by default filter by all + await cases.casesTable.validateCasesTableHasNthRows(4); + + await cases.casesTable.filterByStatus(CaseStatuses.open); + await cases.casesTable.validateCasesTableHasNthRows(2); + + await cases.casesTable.filterByStatus(CaseStatuses['in-progress']); + await cases.casesTable.validateCasesTableHasNthRows(3); + + await cases.casesTable.filterByStatus(CaseStatuses.closed); + await cases.casesTable.validateCasesTableHasNthRows(4); + }); + it('persists status filters', async () => { await cases.casesTable.changeStatus(CaseStatuses.closed, 0); await testSubjects.existOrFail(`case-status-badge-${CaseStatuses.closed}`); @@ -451,6 +469,18 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await testSubjects.existOrFail(`case-status-badge-${CaseStatuses.closed}`); }); + it('persists multiple status filters', async () => { + await cases.casesTable.changeStatus(CaseStatuses['in-progress'], 0); + await cases.casesTable.changeStatus(CaseStatuses.closed, 1); + await cases.casesTable.filterByStatus(CaseStatuses['in-progress']); + await cases.casesTable.filterByStatus(CaseStatuses.closed); + await cases.casesTable.validateCasesTableHasNthRows(2); + await browser.refresh(); + await testSubjects.existOrFail(`case-status-badge-${CaseStatuses['in-progress']}`); + await testSubjects.existOrFail(`case-status-badge-${CaseStatuses.closed}`); + await cases.casesTable.validateCasesTableHasNthRows(2); + }); + it('persists severity filters', async () => { await cases.casesTable.changeSeverity(CaseSeverity.MEDIUM, 0); await testSubjects.existOrFail(`case-table-column-severity-${CaseSeverity.MEDIUM}`); @@ -458,6 +488,18 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await testSubjects.existOrFail(`case-table-column-severity-${CaseSeverity.MEDIUM}`); }); + it('persists multiple severity filters', async () => { + await cases.casesTable.changeSeverity(CaseSeverity.HIGH, 0); + await cases.casesTable.changeSeverity(CaseSeverity.MEDIUM, 1); + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); + await cases.casesTable.filterBySeverity(CaseSeverity.MEDIUM); + await cases.casesTable.validateCasesTableHasNthRows(2); + await browser.refresh(); + await testSubjects.existOrFail(`case-table-column-severity-${CaseSeverity.HIGH}`); + await testSubjects.existOrFail(`case-table-column-severity-${CaseSeverity.MEDIUM}`); + await cases.casesTable.validateCasesTableHasNthRows(2); + }); + describe('assignees filtering', () => { it('filters cases by the first cases all user assignee', async () => { await cases.casesTable.filterByAssignee('all'); @@ -529,21 +571,41 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { // by default filter by all await cases.casesTable.validateCasesTableHasNthRows(5); - // low await cases.casesTable.filterBySeverity(CaseSeverity.LOW); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.LOW); - // high await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); - // critical await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); await cases.casesTable.validateCasesTableHasNthRows(1); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); + + await cases.casesTable.validateCasesTableHasNthRows(5); + }); - // back to all - await cases.casesTable.filterBySeverity(SeverityAll); + it('filter multiple severities', async () => { + // by default filter by all await cases.casesTable.validateCasesTableHasNthRows(5); + + await cases.casesTable.filterBySeverity(CaseSeverity.LOW); + await cases.casesTable.validateCasesTableHasNthRows(2); + + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); + await cases.casesTable.validateCasesTableHasNthRows(4); + + await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); + await cases.casesTable.validateCasesTableHasNthRows(5); + + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.LOW); + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); + await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts index de7a2e42fda0..037e33267dfd 100644 --- a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts @@ -70,7 +70,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('anomaly detection alert', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); await ml.testResources.setKibanaTimeZoneToUTC(); await ml.securityUI.loginAsMlPowerUser(); diff --git a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/index.ts b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/index.ts index ef104c74b820..7a898b63c3f2 100644 --- a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/index.ts @@ -23,7 +23,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { // NOTE: Logout needs to happen before anything else to avoid flaky behavior await ml.securityUI.logout(); - await ml.testResources.deleteIndexPatternByTitle('ft_ecommerce'); + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); await esArchiver.unload('x-pack/test/functional/es_archives/ml/ecommerce'); await ml.securityCommon.cleanMlUsers(); await ml.securityCommon.cleanMlRoles(); diff --git a/x-pack/test/functional_with_es_ssl/plugins/cases/public/application.tsx b/x-pack/test/functional_with_es_ssl/plugins/cases/public/application.tsx index 851134d346d9..af4fb983124e 100644 --- a/x-pack/test/functional_with_es_ssl/plugins/cases/public/application.tsx +++ b/x-pack/test/functional_with_es_ssl/plugins/cases/public/application.tsx @@ -43,6 +43,7 @@ const permissions = { delete: true, push: true, connectors: true, + settings: true, }; const attachments = [{ type: AttachmentType.user as const, comment: 'test' }]; diff --git a/x-pack/test/lists_api_integration/common/config.ts b/x-pack/test/lists_api_integration/common/config.ts deleted file mode 100644 index 62663ae3915b..000000000000 --- a/x-pack/test/lists_api_integration/common/config.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CA_CERT_PATH } from '@kbn/dev-utils'; -import { FtrConfigProviderContext } from '@kbn/test'; -import { services } from './services'; - -interface CreateTestConfigOptions { - license: string; - disabledPlugins?: string[]; - ssl?: boolean; -} - -export function createTestConfig(name: string, options: CreateTestConfigOptions) { - const { license = 'trial', disabledPlugins = [], ssl = false } = options; - - return async ({ readConfigFile }: FtrConfigProviderContext) => { - const xPackApiIntegrationTestsConfig = await readConfigFile( - require.resolve('../../api_integration/config.ts') - ); - const servers = { - ...xPackApiIntegrationTestsConfig.get('servers'), - elasticsearch: { - ...xPackApiIntegrationTestsConfig.get('servers.elasticsearch'), - protocol: ssl ? 'https' : 'http', - }, - }; - - return { - testFiles: [require.resolve(`../${name}/tests/`)], - servers, - services, - junit: { - reportName: 'X-Pack Lists Integration Tests', - }, - esTestCluster: { - ...xPackApiIntegrationTestsConfig.get('esTestCluster'), - license, - ssl, - serverArgs: [ - `xpack.license.self_generated.type=${license}`, - `xpack.security.enabled=${!disabledPlugins.includes('security')}`, - ], - }, - kbnTestServer: { - ...xPackApiIntegrationTestsConfig.get('kbnTestServer'), - serverArgs: [ - ...xPackApiIntegrationTestsConfig.get('kbnTestServer.serverArgs'), - ...disabledPlugins - .filter((k) => k !== 'security') - .map((key) => `--xpack.${key}.enabled=false`), - ...(ssl - ? [ - `--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, - `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, - ] - : []), - ], - }, - }; - }; -} diff --git a/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts b/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts deleted file mode 100644 index aa56557c09df..000000000000 --- a/x-pack/test/lists_api_integration/common/ftr_provider_context.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { GenericFtrProviderContext } from '@kbn/test'; - -import { services } from './services'; - -export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/test/lists_api_integration/common/services.ts b/x-pack/test/lists_api_integration/common/services.ts deleted file mode 100644 index 7e415338c405..000000000000 --- a/x-pack/test/lists_api_integration/common/services.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { services } from '../../api_integration/services'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/config.ts b/x-pack/test/lists_api_integration/security_and_spaces/config.ts deleted file mode 100644 index 8b7e43945c8a..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/config.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createTestConfig } from '../common/config'; - -// eslint-disable-next-line import/no-default-export -export default createTestConfig('security_and_spaces', { - disabledPlugins: [], - license: 'trial', - ssl: true, -}); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists_index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists_index.ts deleted file mode 100644 index ab549f27c4d2..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists_index.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; -import { getTemplateExists, getIndexTemplateExists } from '@kbn/securitysolution-es-utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -import { createLegacyListsIndices, deleteListsIndex } from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const log = getService('log'); - const es = getService('es'); - - describe('create_list_index_route', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - - it('should create lists data streams', async () => { - const { body: fetchedIndices } = await supertest - .get(LIST_INDEX) - .set('kbn-xsrf', 'true') - .expect(404); - - expect(fetchedIndices).to.eql({ - message: 'data stream .lists-default and data stream .items-default does not exist', - status_code: 404, - }); - - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); - - const { body } = await supertest.get(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); - - expect(body).to.eql({ list_index: true, list_item_index: true }); - }); - - it('should migrate lists indices to data streams and remove old legacy templates', async () => { - // create legacy indices - await createLegacyListsIndices(es); - - await supertest - .get(LIST_INDEX) - .set('kbn-xsrf', 'true') - // data stream does not exist - .expect(404); - - // confirm that legacy templates are in use - const legacyListsTemplateExists = await getTemplateExists(es, '.lists-default'); - const legacyItemsTemplateExists = await getTemplateExists(es, '.items-default'); - const nonLegacyListsTemplateExists = await getIndexTemplateExists(es, '.lists-default'); - const nonLegacyItemsTemplateExists = await getIndexTemplateExists(es, '.items-default'); - - expect(legacyListsTemplateExists).to.equal(true); - expect(legacyItemsTemplateExists).to.equal(true); - expect(nonLegacyListsTemplateExists).to.equal(false); - expect(nonLegacyItemsTemplateExists).to.equal(false); - - // migrates old indices to data streams - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); - - const { body } = await supertest.get(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); - - const legacyListsTemplateExistsPostMigration = await getTemplateExists(es, '.lists-default'); - const legacyItemsTemplateExistsPostMigration = await getTemplateExists(es, '.items-default'); - const newListsTemplateExists = await getIndexTemplateExists(es, '.lists-default'); - const newItemsTemplateExists = await getIndexTemplateExists(es, '.items-default'); - - expect(legacyListsTemplateExistsPostMigration).to.equal(false); - expect(legacyItemsTemplateExistsPostMigration).to.equal(false); - expect(newListsTemplateExists).to.equal(true); - expect(newItemsTemplateExists).to.equal(true); - - expect(body).to.eql({ list_index: true, list_item_index: true }); - }); - }); -}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts deleted file mode 100644 index 89ae216adc86..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import type { ListSchema, ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; -import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; -import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { getImportListItemAsBuffer } from '@kbn/lists-plugin/common/schemas/request/import_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -import { - createListsIndex, - deleteListsIndex, - removeListServerGeneratedProperties, - removeListItemServerGeneratedProperties, - waitFor, - createListsIndices, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext): void => { - const supertest = getService('supertest'); - const log = getService('log'); - const es = getService('es'); - - describe('import_list_items', () => { - describe('importing list items without an index', () => { - it('should not import a list item if the index does not exist yet', async () => { - const { body } = await supertest - .post(`${LIST_ITEM_URL}/_import?type=ip`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') - .expect('Content-Type', 'application/json; charset=utf-8') - .expect(400); - - expect(body).to.eql({ - status_code: 400, - message: - 'To import a list item, the data steam must exist first. Data stream ".lists-default" does not exist', - }); - }); - }); - - describe('importing lists with an index', () => { - beforeEach(async () => { - await createListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - - it('should set the response content types to be expected when importing two items', async () => { - await supertest - .post(`${LIST_ITEM_URL}/_import?type=ip`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') - .expect('Content-Type', 'application/json; charset=utf-8') - .expect(200); - }); - - it('should report that it imported a simple list successfully', async () => { - const { body } = await supertest - .post(`${LIST_ITEM_URL}/_import?type=ip`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') - .expect('Content-Type', 'application/json; charset=utf-8') - .expect(200); - - const bodyToCompare = removeListServerGeneratedProperties(body); - const outputtedList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), - name: 'list_items.txt', - description: 'File uploaded from file system of list_items.txt', - }; - expect(bodyToCompare).to.eql(outputtedList); - }); - - it('should be able to read imported list items back out correctly', async () => { - await supertest - .post(`${LIST_ITEM_URL}/_import?type=ip`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') - .expect(200); - - // Although we try to be aggressive with waitFor in the lists code base, there is still not guarantees - // that we will have the data just yet so we have to do a waitFor here for when it shows up - await waitFor( - async () => { - const { status } = await supertest - .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) - .send(); - return status !== 404; - }, - `${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`, - log - ); - const { body } = await supertest - .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) - .send() - .expect(200); - - const bodyToCompare = removeListItemServerGeneratedProperties(body[0]); - const outputtedList: Partial = { - ...getListItemResponseMockWithoutAutoGeneratedValues(), - list_id: 'list_items.txt', - }; - expect(bodyToCompare).to.eql(outputtedList); - }); - - describe('legacy index (before migration to data streams)', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - - it('should import list to legacy index and migrate it', async () => { - // create legacy indices - await createListsIndices(es); - - const { body } = await supertest - .post(`${LIST_ITEM_URL}/_import?type=ip`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') - .expect('Content-Type', 'application/json; charset=utf-8') - .expect(200); - - const bodyToCompare = removeListServerGeneratedProperties(body); - const outputtedList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), - name: 'list_items.txt', - description: 'File uploaded from file system of list_items.txt', - }; - expect(bodyToCompare).to.eql(outputtedList); - }); - }); - }); - }); -}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts deleted file mode 100644 index 79217043b36b..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ loadTestFile }: FtrProviderContext): void => { - describe('lists api security and spaces enabled', function () { - loadTestFile(require.resolve('./create_lists')); - loadTestFile(require.resolve('./create_lists_index')); - loadTestFile(require.resolve('./create_list_items')); - loadTestFile(require.resolve('./patch_lists')); - loadTestFile(require.resolve('./patch_list_items')); - loadTestFile(require.resolve('./read_lists')); - loadTestFile(require.resolve('./read_list_items')); - loadTestFile(require.resolve('./update_lists')); - loadTestFile(require.resolve('./update_list_items')); - loadTestFile(require.resolve('./delete_lists')); - loadTestFile(require.resolve('./delete_list_items')); - loadTestFile(require.resolve('./duplicate_exception_list')); - loadTestFile(require.resolve('./find_lists')); - loadTestFile(require.resolve('./find_list_items')); - loadTestFile(require.resolve('./find_lists_by_size')); - loadTestFile(require.resolve('./get_exception_filter')); - loadTestFile(require.resolve('./import_exceptions')); - loadTestFile(require.resolve('./import_list_items')); - loadTestFile(require.resolve('./export_list_items')); - loadTestFile(require.resolve('./export_exception_list')); - loadTestFile(require.resolve('./create_exception_lists')); - loadTestFile(require.resolve('./create_exception_list_items')); - loadTestFile(require.resolve('./read_exception_lists')); - loadTestFile(require.resolve('./read_exception_list_items')); - loadTestFile(require.resolve('./update_exception_lists')); - loadTestFile(require.resolve('./update_exception_list_items')); - loadTestFile(require.resolve('./delete_exception_lists')); - loadTestFile(require.resolve('./delete_exception_list_items')); - loadTestFile(require.resolve('./find_exception_lists')); - loadTestFile(require.resolve('./find_exception_list_items')); - loadTestFile(require.resolve('./read_list_privileges')); - loadTestFile(require.resolve('./summary_exception_lists')); - }); -}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_list_items.ts deleted file mode 100644 index 0827b5813b6c..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_list_items.ts +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import type { - PatchListItemSchema, - CreateListItemSchema, - ListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; -import { LIST_URL, LIST_ITEM_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; -import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; -import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; -import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { getUpdateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -import { - createListsIndex, - deleteListsIndex, - removeListItemServerGeneratedProperties, - createListsIndices, - createListBypassingChecks, - createListItemBypassingChecks, -} from '../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const log = getService('log'); - const retry = getService('retry'); - const es = getService('es'); - - describe('patch_list_items', () => { - describe('patch list items', () => { - beforeEach(async () => { - await createListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - - it('should patch a single list item property of value using an id', async () => { - const listItemId = getCreateMinimalListItemSchemaMock().id as string; - // create a simple list - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // create a simple list item - await supertest - .post(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListItemSchemaMock()) - .expect(200); - - // patch a simple list item's value - const patchListItemPayload: PatchListItemSchema = { - id: listItemId, - value: '192.168.0.2', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchListItemPayload); - - const outputListItem: Partial = { - ...getListItemResponseMockWithoutAutoGeneratedValues(), - value: '192.168.0.2', - }; - const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(outputListItem); - - await retry.waitFor('updates should be persistent', async () => { - const { body: listItemBody } = await supertest - .get(LIST_ITEM_URL) - .query({ id: getCreateMinimalListItemSchemaMock().id }) - .set('kbn-xsrf', 'true'); - - expect(removeListItemServerGeneratedProperties(listItemBody)).to.eql(outputListItem); - return true; - }); - }); - - it('should patch a single list item of value using an auto-generated id of both list and list item', async () => { - const { id, ...listNoId } = getCreateMinimalListSchemaMock(); - // create a simple list with no id which will use an auto-generated id - const { body: createListBody } = await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(listNoId) - .expect(200); - - // create a simple list item also with an auto-generated id using the list's auto-generated id - const listItem: CreateListItemSchema = { - ...getCreateMinimalListItemSchemaMock(), - list_id: createListBody.id, - }; - const { body: createListItemBody } = await supertest - .post(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(listItem) - .expect(200); - - // patch a simple list item's value - const patchListItemPayload: PatchListItemSchema = { - id: createListItemBody.id, - value: '192.168.0.2', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchListItemPayload) - .expect(200); - - const outputListItem: Partial = { - ...getListItemResponseMockWithoutAutoGeneratedValues(), - value: '192.168.0.2', - }; - const bodyToCompare = { - ...removeListItemServerGeneratedProperties(body), - list_id: outputListItem.list_id, - }; - expect(bodyToCompare).to.eql(outputListItem); - - await retry.waitFor('updates should be persistent', async () => { - const { body: listItemBody } = await supertest - .get(LIST_ITEM_URL) - .query({ id: createListItemBody.id }) - .set('kbn-xsrf', 'true'); - const listItemBodyToCompare = { - ...removeListItemServerGeneratedProperties(listItemBody), - list_id: outputListItem.list_id, - }; - expect(listItemBodyToCompare).to.eql(outputListItem); - return true; - }); - }); - - it('should not remove unspecified in patch payload meta property', async () => { - const listItemId = getCreateMinimalListItemSchemaMock().id as string; - // create a simple list - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // create a simple list item - await supertest - .post(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send({ ...getCreateMinimalListItemSchemaMock(), meta: { test: true } }) - .expect(200); - - // patch a simple list item's value - const patchListItemPayload: PatchListItemSchema = { - id: listItemId, - value: '192.168.0.2', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchListItemPayload); - - expect(body.meta).to.eql({ test: true }); - - await retry.waitFor('updates should be persistent', async () => { - const { body: listItemBody } = await supertest - .get(LIST_ITEM_URL) - .query({ id: getCreateMinimalListItemSchemaMock().id }) - .set('kbn-xsrf', 'true'); - - expect(listItemBody.meta).to.eql({ test: true }); - return true; - }); - }); - - it('should give a 404 if it is given a fake id', async () => { - // create a simple list - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // create a simple list item - await supertest - .post(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListItemSchemaMock()) - .expect(200); - - // patch a simple list item's value - const patchListItemPayload: PatchListItemSchema = { - ...getUpdateMinimalListItemSchemaMock(), - id: 'some-other-id', - value: '192.168.0.2', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchListItemPayload) - .expect(404); - - expect(body).to.eql({ - status_code: 404, - message: 'list item id: "some-other-id" not found', - }); - }); - - describe('legacy list items index (list created before migration to data stream)', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - it('should patch list item that was created in legacy index and migrated through LIST_INDEX request', async () => { - const listId = 'random-list'; - const listItemId = 'random-list-item'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); - // migrates old indices to data streams - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); - - const patchPayload: PatchListItemSchema = { - id: listItemId, - value: 'new one', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchPayload) - .expect(200); - - expect(body.value).to.be('new one'); - }); - - it('should patch list item that was created in legacy index and not yet migrated', async () => { - const listId = 'random-list'; - const listItemId = 'random-list-item'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); - - const patchPayload: PatchListItemSchema = { - id: listItemId, - value: 'new one', - }; - - const { body } = await supertest - .patch(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(patchPayload) - .expect(200); - - expect(body.value).to.be('new one'); - }); - }); - }); - }); -}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_lists.ts deleted file mode 100644 index 87076851bd34..000000000000 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/patch_lists.ts +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import type { PatchListSchema, ListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { LIST_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; - -import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { getUpdateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_schema.mock'; -import { - createListsIndex, - deleteListsIndex, - removeListServerGeneratedProperties, - createListsIndices, - createListBypassingChecks, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const log = getService('log'); - const retry = getService('retry'); - const es = getService('es'); - - describe('patch_lists', () => { - describe('patch lists', () => { - beforeEach(async () => { - await createListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - - it('should patch a single list property of name using an id', async () => { - const listId = getCreateMinimalListSchemaMock().id as string; - // create a simple list - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // patch a simple list's name - const patchedListPayload: PatchListSchema = { - id: listId, - name: 'some other name', - }; - - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchedListPayload) - .expect(200); - - const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), - name: 'some other name', - version: 2, - }; - const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(outputList); - - await retry.waitFor('patches should be persistent', async () => { - const { body: list } = await supertest - .get(LIST_URL) - .query({ id: listId }) - .set('kbn-xsrf', 'true') - .expect(200); - - expect(list.name).to.be('some other name'); - return true; - }); - }); - - it('should patch a single list property of name using an auto-generated id', async () => { - const { id, ...listNoId } = getCreateMinimalListSchemaMock(); - // create a simple list with no id which will use an auto-generated id - const { body: createListBody } = await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(listNoId) - .expect(200); - - // patch a simple list's name - const patchedListPayload: PatchListSchema = { - id: createListBody.id, - name: 'some other name', - }; - - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchedListPayload) - .expect(200); - - const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), - name: 'some other name', - version: 2, - }; - const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(outputList); - - await retry.waitFor('patches should be persistent', async () => { - const { body: list } = await supertest - .get(LIST_URL) - .query({ id: createListBody.id }) - .set('kbn-xsrf', 'true'); - - expect(list.name).to.be('some other name'); - return true; - }); - }); - - it('should not remove unspecified fields in payload', async () => { - const listId = getCreateMinimalListSchemaMock().id as string; - // create a simple list - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // patch a simple list's name - const patchedListPayload: PatchListSchema = { - id: listId, - name: 'some other name', - }; - - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchedListPayload) - .expect(200); - - const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), - name: 'some other name', - version: 2, - }; - const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(outputList); - - await retry.waitFor('patches should be persistent', async () => { - const { body: list } = await supertest - .get(LIST_URL) - .query({ id: getUpdateMinimalListSchemaMock().id }) - .set('kbn-xsrf', 'true'); - - const persistentBodyToCompare = removeListServerGeneratedProperties(list); - - expect(persistentBodyToCompare).to.eql(outputList); - return true; - }); - }); - - it('should change the version of a list when it patches a property', async () => { - // create a simple list - const { body: createdList } = await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); - - // patch a simple list property of name and description - const patchPayload: PatchListSchema = { - id: createdList.id, - name: 'some other name', - description: 'some other description', - }; - - const { body: patchedList } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchPayload); - - expect(createdList.version).to.be(1); - expect(patchedList.version).to.be(2); - - await retry.waitFor('patches should be persistent', async () => { - const { body: list } = await supertest - .get(LIST_URL) - .query({ id: patchedList.id }) - .set('kbn-xsrf', 'true'); - - expect(list.version).to.be(2); - return true; - }); - }); - - it('should give a 404 if it is given a fake id', async () => { - const simpleList: PatchListSchema = { - ...getUpdateMinimalListSchemaMock(), - id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', - }; - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(simpleList) - .expect(404); - - expect(body).to.eql({ - status_code: 404, - message: 'list id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" not found', - }); - }); - - describe('legacy list index (list created before migration to data stream)', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - it('should update list container that was created in legacy index and migrated through LIST_INDEX request', async () => { - const listId = 'random-list'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - - // migrates old indices to data streams - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); - - // patch a simple list's name - const patchPayload: PatchListSchema = { - id: listId, - name: 'some other name', - }; - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchPayload) - .expect(200); - - expect(body.name).to.be('some other name'); - }); - - it('should update list container that was created in legacy index and not yet migrated', async () => { - const listId = 'random-list'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - - // patch a simple list's name - const patchPayload: PatchListSchema = { - id: listId, - name: 'some other name', - }; - const { body } = await supertest - .patch(LIST_URL) - .set('kbn-xsrf', 'true') - .send(patchPayload) - .expect(200); - - expect(body.name).to.be('some other name'); - }); - }); - }); - }); -}; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts deleted file mode 100644 index 780042a293dc..000000000000 --- a/x-pack/test/lists_api_integration/utils.ts +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type SuperTest from 'supertest'; -import { v4 as uuidv4 } from 'uuid'; - -import type { - Type, - ListSchema, - ListItemSchema, - ExceptionListSchema, - ExceptionListItemSchema, - ExceptionList, - NamespaceType, -} from '@kbn/securitysolution-io-ts-list-types'; -import { - EXCEPTION_LIST_URL, - LIST_INDEX, - LIST_ITEM_URL, -} from '@kbn/securitysolution-list-constants'; -import { - setPolicy, - setTemplate, - setIndexTemplate, - createBootstrapIndex, -} from '@kbn/securitysolution-es-utils'; -import { Client } from '@elastic/elasticsearch'; -import { ToolingLog } from '@kbn/tooling-log'; -import { getImportListItemAsBuffer } from '@kbn/lists-plugin/common/schemas/request/import_list_item_schema.mock'; -import { encodeHitVersion } from '@kbn/securitysolution-es-utils'; - -import { countDownTest } from '../detection_engine_api_integration/utils'; - -/** - * Creates the lists and lists items index for use inside of beforeEach blocks of tests - * This will retry 50 times before giving up and hopefully still not interfere with other tests - * @param supertest The supertest client library - */ -export const createListsIndex = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - return countDownTest( - async () => { - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').send(); - return { - passed: true, - }; - }, - 'createListsIndex', - log - ); -}; - -/** - * Deletes the lists index for use inside of afterEach blocks of tests - * @param supertest The supertest client library - */ -export const deleteListsIndex = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - return countDownTest( - async () => { - await supertest.delete(LIST_INDEX).set('kbn-xsrf', 'true').send(); - return { - passed: true, - }; - }, - 'deleteListsIndex', - log - ); -}; - -/** - * Creates the exception lists and lists items index for use inside of beforeEach blocks of tests - * This will retry 50 times before giving up and hopefully still not interfere with other tests - * @param supertest The supertest client library - */ -export const createExceptionListsIndex = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - return countDownTest( - async () => { - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').send(); - return { - passed: true, - }; - }, - 'createListsIndex', - log - ); -}; - -/** - * This will remove server generated properties such as date times, etc... - * @param list List to pass in to remove typical server generated properties - */ -export const removeListServerGeneratedProperties = ( - list: Partial -): Partial => { - /* eslint-disable-next-line @typescript-eslint/naming-convention */ - const { created_at, updated_at, id, tie_breaker_id, _version, '@timestamp': _t, ...props } = list; - return props; -}; - -/** - * This will remove server generated properties such as date times, etc... - * @param list List to pass in to remove typical server generated properties - */ -export const removeListItemServerGeneratedProperties = ( - list: Partial -): Partial => { - /* eslint-disable-next-line @typescript-eslint/naming-convention */ - const { created_at, updated_at, id, tie_breaker_id, _version, '@timestamp': _t, ...props } = list; - return props; -}; - -/** - * This will remove server generated properties such as date times, etc... - * @param list List to pass in to remove typical server generated properties - */ -export const removeExceptionListItemServerGeneratedProperties = ( - list: Partial -): Partial => { - /* eslint-disable-next-line @typescript-eslint/naming-convention */ - const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; - return removedProperties; -}; - -/** - * This will remove server generated properties such as date times, etc... - * @param list List to pass in to remove typical server generated properties - */ -export const removeExceptionListServerGeneratedProperties = ( - list: Partial -): Partial => { - /* eslint-disable-next-line @typescript-eslint/naming-convention */ - const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; - return removedProperties; -}; - -// Similar to ReactJs's waitFor from here: https://testing-library.com/docs/dom-testing-library/api-async#waitfor -export const waitFor = async ( - functionToTest: () => Promise, - functionName: string, - log: ToolingLog, - maxTimeout: number = 800000, - timeoutWait: number = 250 -) => { - await new Promise(async (resolve, reject) => { - try { - let found = false; - let numberOfTries = 0; - const maxTries = Math.floor(maxTimeout / timeoutWait); - - while (!found && numberOfTries < maxTries) { - const itPasses = await functionToTest(); - - if (itPasses) { - found = true; - } else { - log.debug(`Try number ${numberOfTries} out of ${maxTries} for function ${functionName}`); - numberOfTries++; - } - - await new Promise((resolveTimeout) => setTimeout(resolveTimeout, timeoutWait)); - } - - if (found) { - resolve(); - } else { - reject(new Error(`timed out waiting for function ${functionName} condition to be true`)); - } - } catch (error) { - reject(error); - } - }); -}; - -/** - * Useful for export_api testing to convert from a multi-part binary back to a string - * @param res Response - * @param callback Callback - */ -export const binaryToString = (res: any, callback: any): void => { - res.setEncoding('binary'); - res.data = ''; - res.on('data', (chunk: any) => { - res.data += chunk; - }); - res.on('end', () => { - callback(null, Buffer.from(res.data)); - }); -}; - -/** - * Remove all exceptions from both the "single" and "agnostic" spaces. - * This will retry 50 times before giving up and hopefully still not interfere with other tests - * @param supertest The supertest handle - */ -export const deleteAllExceptions = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - await deleteAllExceptionsByType(supertest, log, 'single'); - await deleteAllExceptionsByType(supertest, log, 'agnostic'); -}; - -/** - * Remove all exceptions by a given type such as "agnostic" or "single". - * This will retry 50 times before giving up and hopefully still not interfere with other tests - * @param supertest The supertest handle - */ -export const deleteAllExceptionsByType = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - type: NamespaceType -): Promise => { - await countDownTest( - async () => { - const { body } = await supertest - .get(`${EXCEPTION_LIST_URL}/_find?per_page=9999&namespace_type=${type}`) - .set('kbn-xsrf', 'true') - .send(); - const ids: string[] = body.data.map((exception: ExceptionList) => exception.id); - for await (const id of ids) { - await supertest - .delete(`${EXCEPTION_LIST_URL}?id=${id}&namespace_type=${type}`) - .set('kbn-xsrf', 'true') - .send(); - } - const { body: finalCheck } = await supertest - .get(`${EXCEPTION_LIST_URL}/_find?namespace_type=${type}`) - .set('kbn-xsrf', 'true') - .send(); - return { - passed: finalCheck.data.length === 0, - }; - }, - `deleteAllExceptions by type: "${type}"`, - log, - 50, - 1000 - ); -}; - -/** - * Convenience function for quickly importing a given type and contents and then - * waiting to ensure they're there before continuing - * @param supertest The super test agent - * @param type The type to import as - * @param contents The contents of the import - * @param fileName filename to import as - * @param testValues Optional test values in case you're using CIDR or range based lists - */ -export const importFile = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - type: Type, - contents: string[], - fileName: string, - testValues?: string[] -): Promise => { - const response = await supertest - .post(`${LIST_ITEM_URL}/_import?type=${type}`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(contents), fileName) - .expect('Content-Type', 'application/json; charset=utf-8'); - - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" When importing a file (importFile). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - - // although we have pushed the list and its items, it is async so we - // have to wait for the contents before continuing - const testValuesOrContents = testValues ?? contents; - await waitForListItems(supertest, log, testValuesOrContents, fileName); -}; - -/** - * Convenience function for quickly importing a given type and contents and then - * waiting to ensure they're there before continuing. This specifically checks tokens - * from text file - * @param supertest The super test agent - * @param type The type to import as - * @param contents The contents of the import - * @param fileName filename to import as - */ -export const importTextFile = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - type: Type, - contents: string[], - fileName: string -): Promise => { - const response = await supertest - .post(`${LIST_ITEM_URL}/_import?type=${type}`) - .set('kbn-xsrf', 'true') - .attach('file', getImportListItemAsBuffer(contents), fileName) - .expect('Content-Type', 'application/json; charset=utf-8'); - - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" when importing a text file (importTextFile). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - - // although we have pushed the list and its items, it is async so we - // have to wait for the contents before continuing - await waitForTextListItems(supertest, log, contents, fileName); -}; - -/** - * Convenience function for waiting for a particular file uploaded - * and a particular item value to be available before continuing. - * @param supertest The super test agent - * @param fileName The filename imported - * @param itemValue The item value to wait for - */ -export const waitForListItem = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - itemValue: string, - fileName: string -): Promise => { - await waitFor( - async () => { - const { status, body } = await supertest - .get(`${LIST_ITEM_URL}?list_id=${fileName}&value=${itemValue}`) - .send(); - if (status !== 200) { - log.debug( - `Did not get an expected 200 "ok" when waiting for a list item (waitForListItem) yet. Retrying until we get a 200 "ok". body: ${JSON.stringify( - body - )}, status: ${JSON.stringify(status)}` - ); - } - return status === 200; - }, - `waitForListItem fileName: "${fileName}" itemValue: "${itemValue}"`, - log - ); -}; - -/** - * Convenience function for waiting for a particular file uploaded - * and particular item values to be available before continuing. - * @param supertest The super test agent - * @param fileName The filename imported - * @param itemValue The item value to wait for - */ -export const waitForListItems = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - itemValues: string[], - fileName: string -): Promise => { - await Promise.all(itemValues.map((item) => waitForListItem(supertest, log, item, fileName))); -}; - -/** - * Convenience function for waiting for a particular file uploaded - * and a particular item value to be available before continuing. - * @param supertest The super test agent - * @param fileName The filename imported - * @param itemValue The item value to wait for - */ -export const waitForTextListItem = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - itemValue: string, - fileName: string -): Promise => { - const tokens = itemValue.split(' '); - await waitFor( - async () => { - const promises = await Promise.all( - tokens.map(async (token) => { - const { status, body } = await supertest - .get(`${LIST_ITEM_URL}?list_id=${fileName}&value=${token}`) - .send(); - if (status !== 200) { - log.error( - `Did not get an expected 200 "ok" when waiting for a text list item (waitForTextListItem) yet. Retrying until we get a 200 "ok". body: ${JSON.stringify( - body - )}, status: ${JSON.stringify(status)}` - ); - } - return status === 200; - }) - ); - return promises.every((one) => one); - }, - `waitForTextListItem fileName: "${fileName}" itemValue: "${itemValue}"`, - log - ); -}; - -/** - * Convenience function for waiting for a particular file uploaded - * and particular item values to be available before continuing. This works - * specifically with text types and does tokenization to ensure all words are uploaded - * @param supertest The super test agent - * @param fileName The filename imported - * @param itemValue The item value to wait for - */ -export const waitForTextListItems = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog, - itemValues: string[], - fileName: string -): Promise => { - await Promise.all(itemValues.map((item) => waitForTextListItem(supertest, log, item, fileName))); -}; - -const testPolicy = { - policy: { - phases: { - hot: { - min_age: '0ms', - actions: { - rollover: { - max_size: '50gb', - }, - }, - }, - }, - }, -}; - -const listsMappings = { - dynamic: 'strict', - properties: { - name: { - type: 'keyword', - }, - deserializer: { - type: 'keyword', - }, - serializer: { - type: 'keyword', - }, - description: { - type: 'keyword', - }, - type: { - type: 'keyword', - }, - tie_breaker_id: { - type: 'keyword', - }, - meta: { - enabled: 'false', - type: 'object', - }, - created_at: { - type: 'date', - }, - updated_at: { - type: 'date', - }, - created_by: { - type: 'keyword', - }, - updated_by: { - type: 'keyword', - }, - version: { - type: 'keyword', - }, - immutable: { - type: 'boolean', - }, - }, -}; - -const itemsMappings = { - dynamic: 'strict', - properties: { - tie_breaker_id: { - type: 'keyword', - }, - list_id: { - type: 'keyword', - }, - deserializer: { - type: 'keyword', - }, - serializer: { - type: 'keyword', - }, - meta: { - enabled: 'false', - type: 'object', - }, - created_at: { - type: 'date', - }, - updated_at: { - type: 'date', - }, - created_by: { - type: 'keyword', - }, - updated_by: { - type: 'keyword', - }, - ip: { - type: 'ip', - }, - keyword: { - type: 'keyword', - }, - }, -}; - -/** - * Convenience function for creating legacy index templates to - * test out logic updating to new index templates - * @param es es client - */ -export const createLegacyListsIndices = async (es: Client) => { - await setPolicy(es, '.lists-default', testPolicy); - await setPolicy(es, '.items-default', testPolicy); - await setTemplate(es, '.lists-default', { - index_patterns: [`.lists-default-*`], - mappings: listsMappings, - settings: { - index: { - lifecycle: { - name: '.lists-default', - rollover_alias: '.lists-default', - }, - }, - }, - }); - await setTemplate(es, '.items-default', { - index_patterns: [`.items-default-*`], - mappings: itemsMappings, - settings: { - index: { - lifecycle: { - name: '.items-default', - rollover_alias: '.items-default', - }, - }, - }, - }); - await createBootstrapIndex(es, '.lists-default'); - await createBootstrapIndex(es, '.items-default'); -}; - -/** - * Utility to create list indices, before they were migrated to data streams - * @param es ES client - */ -export const createListsIndices = async (es: Client) => { - await setPolicy(es, '.lists-default', testPolicy); - await setPolicy(es, '.items-default', testPolicy); - await setIndexTemplate(es, '.lists-default', { - index_patterns: [`.lists-default-*`], - template: { - mappings: listsMappings, - settings: { - index: { - lifecycle: { - name: '.lists-default', - rollover_alias: '.lists-default', - }, - }, - mapping: { - total_fields: { - limit: 10000, - }, - }, - }, - }, - }); - await setIndexTemplate(es, '.items-default', { - index_patterns: [`.items-default-*`], - template: { - mappings: itemsMappings, - settings: { - index: { - lifecycle: { - name: '.items-default', - rollover_alias: '.items-default', - }, - }, - mapping: { - total_fields: { - limit: 10000, - }, - }, - }, - }, - }); - await createBootstrapIndex(es, '.lists-default'); - await createBootstrapIndex(es, '.items-default'); -}; - -/** - * utility to create list directly by using ES, bypassing all checks - * useful, to create list in legacy indices - */ -export const createListBypassingChecks = async ({ es, id }: { es: Client; id: string }) => { - const createdAt = new Date().toISOString(); - const body = { - created_at: createdAt, - created_by: 'mock-user', - description: 'mock-description', - name: 'mock-name', - tie_breaker_id: uuidv4(), - type: 'keyword', - updated_at: createdAt, - updated_by: 'mock-user', - immutable: false, - version: 1, - }; - - const response = await es.create({ - body, - id, - index: '.lists-default', - refresh: 'wait_for', - }); - - return { - _version: encodeHitVersion(response), - id: response._id, - ...body, - }; -}; - -/** - * utility to create list item directly by using ES, bypassing all checks - * useful, to create list item in legacy indices - * supports keyword only - */ -export const createListItemBypassingChecks = async ({ - es, - listId, - id, - value, -}: { - es: Client; - listId: string; - id: string; - value: string; -}) => { - const createdAt = new Date().toISOString(); - const body = { - created_at: createdAt, - created_by: 'mock-user', - tie_breaker_id: uuidv4(), - updated_at: createdAt, - updated_by: 'mock-user', - list_id: listId, - keyword: value, - }; - - const response = await es.create({ - body, - id, - index: '.items-default', - refresh: 'wait_for', - }); - - return { - _version: encodeHitVersion(response), - id: response._id, - ...body, - }; -}; diff --git a/x-pack/test/observability_onboarding_api_integration/common/config.ts b/x-pack/test/observability_onboarding_api_integration/common/config.ts index 32d51a6388b0..55b98b2eaa23 100644 --- a/x-pack/test/observability_onboarding_api_integration/common/config.ts +++ b/x-pack/test/observability_onboarding_api_integration/common/config.ts @@ -13,6 +13,7 @@ import { createObservabilityOnboardingUsers } from '@kbn/observability-onboardin import { FtrConfigProviderContext } from '@kbn/test'; import supertest from 'supertest'; import { format, UrlObject } from 'url'; +import { createLogger, LogLevel, LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; import { ObservabilityOnboardingFtrConfigName } from '../configs'; import { FtrProviderContext, @@ -64,6 +65,9 @@ export interface CreateTest { services: InheritedServices & { observabilityOnboardingFtrConfig: () => ObservabilityOnboardingFtrConfig; registry: ({ getService }: FtrProviderContext) => ReturnType; + logSynthtraceEsClient: ( + context: InheritedFtrProviderContext + ) => Promise; observabilityOnboardingApiClient: ( context: InheritedFtrProviderContext ) => ObservabilityOnboardingApiClient; @@ -97,6 +101,12 @@ export function createTestConfig( ...services, observabilityOnboardingFtrConfig: () => config, registry: RegistryProvider, + logSynthtraceEsClient: (context: InheritedFtrProviderContext) => + new LogsSynthtraceEsClient({ + client: context.getService('es'), + logger: createLogger(LogLevel.info), + refreshAfterIndex: true, + }), observabilityOnboardingApiClient: async (_: InheritedFtrProviderContext) => { const { username, password } = servers.kibana; const esUrl = format(esServer); diff --git a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/es_utils.ts b/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/es_utils.ts deleted file mode 100644 index 33207ed6cdd8..000000000000 --- a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/es_utils.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export function createLogDoc({ - time, - logFilepath, - serviceName, - namespace, - datasetName, - message, - agentId, -}: { - time: number; - logFilepath: string; - serviceName?: string; - namespace: string; - datasetName: string; - message: string; - agentId?: string; -}) { - return { - input: { - type: 'log', - }, - '@timestamp': new Date(time).toISOString(), - log: { - file: { - path: logFilepath, - }, - }, - ...(serviceName - ? { - service: { - name: serviceName, - }, - } - : {}), - data_stream: { - namespace, - type: 'logs', - dataset: datasetName, - }, - message, - event: { - dataset: datasetName, - }, - ...(agentId - ? { - agent: { - id: agentId, - }, - } - : {}), - }; -} diff --git a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts b/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts index 7311f116736a..0a7802e9682c 100644 --- a/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts +++ b/x-pack/test/observability_onboarding_api_integration/tests/flow/progress/progress.spec.ts @@ -5,17 +5,17 @@ * 2.0. */ +import { log, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; import { ObservabilityOnboardingApiClientKey } from '../../../common/config'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { ObservabilityOnboardingApiError } from '../../../common/observability_onboarding_api_supertest'; import { expectToReject } from '../../../common/utils/expect_to_reject'; -import { createLogDoc } from './es_utils'; export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); const observabilityOnboardingApiClient = getService('observabilityOnboardingApiClient'); - const es = getService('es'); + const synthtrace = getService('logSynthtraceEsClient'); async function callApi({ onboardingId, @@ -141,24 +141,24 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('with a different agentId', () => { describe('and onboarding type is logFiles', () => { before(async () => { - await es.indices.createDataStream({ - name: `logs-${datasetName}-${namespace}`, - }); - - const doc = createLogDoc({ - time: new Date('06/28/2023').getTime(), - logFilepath: '/my-service.log', - serviceName: 'my-service', - namespace, - datasetName, - message: 'This is a log message', - agentId: 'another-agent-id', - }); - - await es.bulk({ - body: [{ create: { _index: `logs-${datasetName}-${namespace}` } }, doc], - refresh: 'wait_for', - }); + await synthtrace.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(datasetName) + .namespace(namespace) + .service('my-service') + .defaults({ + 'agent.id': 'another-agent-id', + 'log.file.path': '/my-service.log', + }) + ), + ]); }); it('should return log-ingest as incomplete', async () => { @@ -173,9 +173,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await es.indices.deleteDataStream({ - name: `logs-${datasetName}-${namespace}`, - }); + await synthtrace.clean(); }); }); @@ -211,23 +209,23 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }); - await es.indices.createDataStream({ - name: `logs-system.syslog-${namespace}`, - }); - - const doc = createLogDoc({ - time: new Date('06/28/2023').getTime(), - logFilepath: '/var/log/system.log', - namespace, - datasetName: 'system.syslog', - message: 'This is a system log message', - agentId: 'another-agent-id', - }); - - await es.bulk({ - body: [{ create: { _index: `logs-system.syslog-${namespace}` } }, doc], - refresh: 'wait_for', - }); + await synthtrace.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a system log message') + .timestamp(timestamp) + .dataset('system.syslog') + .namespace(namespace) + .defaults({ + 'agent.id': 'another-agent-id', + 'log.file.path': '/var/log/system.log', + }) + ), + ]); }); it('should return log-ingest as incomplete', async () => { @@ -242,9 +240,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await es.indices.deleteDataStream({ - name: `logs-system.syslog-${namespace}`, - }); + await synthtrace.clean(); }); }); }); @@ -252,24 +248,24 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('with the expected agentId', () => { describe('and onboarding type is logFiles', () => { before(async () => { - await es.indices.createDataStream({ - name: `logs-${datasetName}-${namespace}`, - }); - - const doc = createLogDoc({ - time: new Date('06/28/2023').getTime(), - logFilepath: '/my-service.log', - serviceName: 'my-service', - namespace, - datasetName, - message: 'This is a log message', - agentId, - }); - - await es.bulk({ - body: [{ create: { _index: `logs-${datasetName}-${namespace}` } }, doc], - refresh: 'wait_for', - }); + await synthtrace.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(datasetName) + .namespace(namespace) + .service('my-service') + .defaults({ + 'agent.id': agentId, + 'log.file.path': '/my-service.log', + }) + ), + ]); }); it('should return log-ingest as complete', async () => { @@ -284,9 +280,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await es.indices.deleteDataStream({ - name: `logs-${datasetName}-${namespace}`, - }); + await synthtrace.clean(); }); }); @@ -322,23 +316,23 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }); - await es.indices.createDataStream({ - name: `logs-system.syslog-${namespace}`, - }); - - const doc = createLogDoc({ - time: new Date('06/28/2023').getTime(), - logFilepath: '/var/log/system.log', - namespace, - datasetName: 'system.syslog', - message: 'This is a system log message', - agentId, - }); - - await es.bulk({ - body: [{ create: { _index: `logs-system.syslog-${namespace}` } }, doc], - refresh: 'wait_for', - }); + await synthtrace.index([ + timerange('2023-11-20T10:00:00.000Z', '2023-11-20T10:01:00.000Z') + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a system log message') + .timestamp(timestamp) + .dataset('system.syslog') + .namespace(namespace) + .defaults({ + 'agent.id': agentId, + 'log.file.path': '/var/log/system.log', + }) + ), + ]); }); it('should return log-ingest as complete', async () => { @@ -353,9 +347,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); after(async () => { - await es.indices.deleteDataStream({ - name: `logs-system.syslog-${namespace}`, - }); + await synthtrace.clean(); }); }); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index 7e48895a9060..2217310e4e6a 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -145,6 +145,7 @@ export default function ({ getService }: FtrProviderContext) { 'security:endpoint-meta-telemetry', 'security:telemetry-configuration', 'security:telemetry-detection-rules', + 'security:telemetry-diagnostic-timelines', 'security:telemetry-filterlist-artifact', 'security:telemetry-lists', 'security:telemetry-prebuilt-rule-alerts', diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts index 94cbdbce7749..fcf67163b2bb 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts @@ -45,9 +45,14 @@ export default ({ getService }: FtrProviderContext) => { 'logs', 'uptime', ]); - expect(Object.keys(resp.browserFields)).toEqual( - expect.arrayContaining(['base', 'event', 'kibana']) - ); + expect(Object.keys(resp.browserFields)).toEqual([ + 'base', + 'cloud', + 'container', + 'host', + 'kibana', + 'orchestrator', + ]); }); it(`${superUser.username} should be able to get browser fields for o11y featureIds`, async () => { @@ -57,21 +62,14 @@ export default ({ getService }: FtrProviderContext) => { 'logs', 'uptime', ]); - expect(Object.keys(resp.browserFields)).toEqual( - expect.arrayContaining([ - 'base', - 'agent', - 'anomaly', - 'ecs', - 'error', - 'event', - 'kibana', - 'monitor', - 'observer', - 'tls', - 'url', - ]) - ); + expect(Object.keys(resp.browserFields)).toEqual([ + 'base', + 'cloud', + 'container', + 'host', + 'kibana', + 'orchestrator', + ]); }); it(`${superUser.username} should NOT be able to get browser fields for siem featureId`, async () => { diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/__snapshots__/create_rule.snap b/x-pack/test/rule_registry/spaces_only/tests/trial/__snapshots__/create_rule.snap index a66368fe5a8e..bc4b903dee43 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/__snapshots__/create_rule.snap +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/__snapshots__/create_rule.snap @@ -26,6 +26,9 @@ Object { "kibana.alert.reason": Array [ "Failed transactions is 50% in the last 5 mins for service: opbeans-go, env: Not defined, type: request. Alert when > 30%.", ], + "kibana.alert.reason.text": Array [ + "Failed transactions is 50% in the last 5 mins for service: opbeans-go, env: Not defined, type: request. Alert when > 30%.", + ], "kibana.alert.rule.category": Array [ "Failed transaction rate threshold", ], @@ -109,6 +112,9 @@ Object { "kibana.alert.reason": Array [ "Failed transactions is 50% in the last 5 mins for service: opbeans-go, env: Not defined, type: request. Alert when > 30%.", ], + "kibana.alert.reason.text": Array [ + "Failed transactions is 50% in the last 5 mins for service: opbeans-go, env: Not defined, type: request. Alert when > 30%.", + ], "kibana.alert.rule.category": Array [ "Failed transaction rate threshold", ], diff --git a/x-pack/test/scalability/apis/api.telemetry.cluster_stats.1600_dataviews.json b/x-pack/test/scalability/apis/api.telemetry.cluster_stats.1600_dataviews.json index 485208916d48..de436beed460 100644 --- a/x-pack/test/scalability/apis/api.telemetry.cluster_stats.1600_dataviews.json +++ b/x-pack/test/scalability/apis/api.telemetry.cluster_stats.1600_dataviews.json @@ -20,9 +20,7 @@ }, "testData": { "esArchives": [], - "kbnArchives": [ - "x-pack/test/scalability/fixtures/kbn_archiver/1600-dataviews.json" - ] + "kbnArchives": ["x-pack/test/scalability/fixtures/kbn_archiver/1600-dataviews.json"] }, "streams": [ { diff --git a/x-pack/test/scalability/apis/api.telemetry.cluster_stats.no_cache.1600_dataviews.json b/x-pack/test/scalability/apis/api.telemetry.cluster_stats.no_cache.1600_dataviews.json index 2a3095447e8b..b9a690027c57 100644 --- a/x-pack/test/scalability/apis/api.telemetry.cluster_stats.no_cache.1600_dataviews.json +++ b/x-pack/test/scalability/apis/api.telemetry.cluster_stats.no_cache.1600_dataviews.json @@ -25,9 +25,7 @@ }, "testData": { "esArchives": [], - "kbnArchives": [ - "x-pack/test/scalability/fixtures/kbn_archiver/1600-dataviews.json" - ] + "kbnArchives": ["x-pack/test/scalability/fixtures/kbn_archiver/1600-dataviews.json"] }, "streams": [ { diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/generate_anomaly_alerts.ts b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/generate_anomaly_alerts.ts index cec6ed8528a1..8d93f1349cae 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/generate_anomaly_alerts.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/generate_anomaly_alerts.ts @@ -78,7 +78,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('anomaly detection alert', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); - await ml.testResources.createIndexPatternIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); const { job, datafeed } = createTestJobAndDatafeed(); diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/geographic_data.ts b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/geographic_data.ts index e79539d01bbb..c6db2071f235 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/geographic_data.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/geographic_data.ts @@ -101,7 +101,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep('open index in data visualizer'); await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataVisualizer(); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(LOGS_INDEX_PATTERN); await ml.testExecution.logTestStep('set data visualizer options'); diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts index c6affe8bf3c3..7dcc26758ed4 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts @@ -60,7 +60,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep('open index in data visualizer'); await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataVisualizer(); - await ml.dataVisualizer.navigateToIndexPatternSelection(); + await ml.dataVisualizer.navigateToDataViewSelection(); await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer(LOGS_INDEX_PATTERN); await ml.testExecution.logTestStep('set data visualizer options'); diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/classification.ts b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/classification.ts index 3dc766e428b5..f49750a993d0 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/classification.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/classification.ts @@ -40,12 +40,12 @@ export default function ({ getService }: FtrProviderContext) { describe('classification job', function () { before(async () => { await ml.api.createAndRunDFAJob(classificationJobConfig as DataFrameAnalyticsConfig); - await ml.testResources.createIndexPatternIfNeeded(classificationJobConfig.dest!.index!); + await ml.testResources.createDataViewIfNeeded(classificationJobConfig.dest!.index!); }); after(async () => { await ml.api.deleteDataFrameAnalyticsJobES(classificationJobConfig.id as string); - await ml.testResources.deleteIndexPatternByTitle(classificationJobConfig.dest!.index!); + await ml.testResources.deleteDataViewByTitle(classificationJobConfig.dest!.index!); await ml.api.deleteIndices(classificationJobConfig.dest!.index!); await ml.api.cleanMlIndices(); }); diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/outlier_detection.ts b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/outlier_detection.ts index 73e3a22d28c9..88e6091cd008 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/outlier_detection.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/outlier_detection.ts @@ -49,19 +49,19 @@ export default function ({ getService }: FtrProviderContext) { describe('outlier detection job', function () { before(async () => { await transform.api.createAndRunTransform(transformConfig.id, transformConfig); - await ml.testResources.createIndexPatternIfNeeded(transformConfig.dest.index); + await ml.testResources.createDataViewIfNeeded(transformConfig.dest.index); await ml.api.createAndRunDFAJob(outlierJobConfig as DataFrameAnalyticsConfig); - await ml.testResources.createIndexPatternIfNeeded(outlierJobConfig.dest!.index!); + await ml.testResources.createDataViewIfNeeded(outlierJobConfig.dest!.index!); }); after(async () => { - await ml.testResources.deleteIndexPatternByTitle(transformConfig.dest.index); + await ml.testResources.deleteDataViewByTitle(transformConfig.dest.index); await transform.api.deleteIndices(transformConfig.dest.index); await transform.api.cleanTransformIndices(); await ml.api.deleteDataFrameAnalyticsJobES(outlierJobConfig.id as string); - await ml.testResources.deleteIndexPatternByTitle(outlierJobConfig.dest!.index!); + await ml.testResources.deleteDataViewByTitle(outlierJobConfig.dest!.index!); await ml.api.deleteIndices(outlierJobConfig.dest!.index!); await ml.api.cleanMlIndices(); }); diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/regression.ts b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/regression.ts index edf8c8d971a6..3dc79e031a8b 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/regression.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/data_frame_analytics/regression.ts @@ -41,12 +41,12 @@ export default function ({ getService }: FtrProviderContext) { describe('regression job', function () { before(async () => { await ml.api.createAndRunDFAJob(regressionJobConfig as DataFrameAnalyticsConfig); - await ml.testResources.createIndexPatternIfNeeded(regressionJobConfig.dest!.index!); + await ml.testResources.createDataViewIfNeeded(regressionJobConfig.dest!.index!); }); after(async () => { await ml.api.deleteDataFrameAnalyticsJobES(regressionJobConfig.id as string); - await ml.testResources.deleteIndexPatternByTitle(regressionJobConfig.dest!.index!); + await ml.testResources.deleteDataViewByTitle(regressionJobConfig.dest!.index!); await ml.api.deleteIndices(regressionJobConfig.dest!.index!); await ml.api.cleanMlIndices(); }); diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index_threshold_rule.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index_threshold_rule.ts index 9ca11a5a2dc4..582bc02bd560 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index_threshold_rule.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_alerting/index_threshold_rule.ts @@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'rule-types-index-threshold-conditions', screenshotDirectories, 1400, - 1024 + 1300 ); await testSubjects.scrollIntoView('selectIndexExpression'); @@ -67,7 +67,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'rule-types-index-threshold-example-aggregation', screenshotDirectories, 1400, - 1024 + 1300 ); await ofComboBox.type('bytes'); const ofOptionsString = await comboBox.getOptionsList('availablefieldsOptionsComboBox'); @@ -103,7 +103,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'rule-types-index-threshold-example-threshold', screenshotDirectories, 1400, - 1024 + 1300 ); await testSubjects.setValue('intervalInput', '4'); diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_connectors/pagerduty_connector.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_connectors/pagerduty_connector.ts index ddaa7291acaa..3851c94a22f8 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_connectors/pagerduty_connector.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_connectors/pagerduty_connector.ts @@ -30,7 +30,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('create-connector-flyout-save-test-btn'); await testSubjects.click('toastCloseButton'); await testSubjects.setValue('eventActionSelect', 'trigger'); - await commonScreenshots.takeScreenshot('pagerduty-trigger-test', screenshotDirectories); + await commonScreenshots.takeScreenshot( + 'pagerduty-trigger-test', + screenshotDirectories, + 1400, + 1600 + ); await testSubjects.setValue('eventActionSelect', 'resolve'); await commonScreenshots.takeScreenshot('pagerduty-resolve-test', screenshotDirectories); await testSubjects.setValue('eventActionSelect', 'acknowledge'); diff --git a/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts b/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts index 567b5e5317f7..1f2dc1ab4377 100644 --- a/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts +++ b/x-pack/test/security_api_integration/tests/login_selector/basic_functionality.ts @@ -10,7 +10,7 @@ import { readFileSync } from 'fs'; import url from 'url'; import { CA_CERT_PATH } from '@kbn/dev-utils'; import expect from '@kbn/expect'; -import type { AuthenticationProvider } from '@kbn/security-plugin/common/model'; +import type { AuthenticationProvider } from '@kbn/security-plugin/common'; import { getStateAndNonce } from '@kbn/security-api-integration-helpers/oidc/oidc_tools'; import { getMutualAuthenticationResponseToken, diff --git a/x-pack/test/security_api_integration/tests/session_concurrent_limit/global_limit.ts b/x-pack/test/security_api_integration/tests/session_concurrent_limit/global_limit.ts index 56e1f91a1ef1..b0d65147b054 100644 --- a/x-pack/test/security_api_integration/tests/session_concurrent_limit/global_limit.ts +++ b/x-pack/test/security_api_integration/tests/session_concurrent_limit/global_limit.ts @@ -8,7 +8,7 @@ import { parse as parseCookie, Cookie } from 'tough-cookie'; import expect from '@kbn/expect'; import { adminTestUser } from '@kbn/test'; -import type { AuthenticationProvider } from '@kbn/security-plugin/common/model'; +import type { AuthenticationProvider } from '@kbn/security-plugin/common'; import { getSAMLRequestId, getSAMLResponse, diff --git a/x-pack/test/security_api_integration/tests/session_invalidate/invalidate.ts b/x-pack/test/security_api_integration/tests/session_invalidate/invalidate.ts index 0f79624c830e..b97808d535f7 100644 --- a/x-pack/test/security_api_integration/tests/session_invalidate/invalidate.ts +++ b/x-pack/test/security_api_integration/tests/session_invalidate/invalidate.ts @@ -8,7 +8,7 @@ import { parse as parseCookie, Cookie } from 'tough-cookie'; import expect from '@kbn/expect'; import { adminTestUser } from '@kbn/test'; -import type { AuthenticationProvider } from '@kbn/security-plugin/common/model'; +import type { AuthenticationProvider } from '@kbn/security-plugin/common'; import { getSAMLRequestId, getSAMLResponse, diff --git a/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts b/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts index 09e5e7998750..8186cdbded72 100644 --- a/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts +++ b/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts @@ -9,7 +9,7 @@ import { parse as parseCookie, Cookie } from 'tough-cookie'; import { setTimeout as setTimeoutAsync } from 'timers/promises'; import expect from '@kbn/expect'; import { adminTestUser } from '@kbn/test'; -import type { AuthenticationProvider } from '@kbn/security-plugin/common/model'; +import type { AuthenticationProvider } from '@kbn/security-plugin/common'; import { getSAMLRequestId, getSAMLResponse, diff --git a/x-pack/test/security_solution_api_integration/config/ess/config.base.basic.ts b/x-pack/test/security_solution_api_integration/config/ess/config.base.basic.ts new file mode 100644 index 000000000000..15104fe97292 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/config/ess/config.base.basic.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from './config.base'; + +export default createTestConfig({ + license: 'basic', + ssl: true, +}); diff --git a/x-pack/test/security_solution_api_integration/config/serverless/config.base.essentials.ts b/x-pack/test/security_solution_api_integration/config/serverless/config.base.essentials.ts new file mode 100644 index 000000000000..377d970d3451 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/config/serverless/config.base.essentials.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrConfigProviderContext } from '@kbn/test'; +export interface CreateTestConfigOptions { + testFiles: string[]; + junit: { reportName: string }; + kbnTestServerArgs?: string[]; + kbnTestServerEnv?: Record; +} +import { services } from '../../../../test_serverless/api_integration/services'; + +export function createTestConfig(options: CreateTestConfigOptions) { + return async ({ readConfigFile }: FtrConfigProviderContext) => { + const svlSharedConfig = await readConfigFile( + require.resolve('../../../../test_serverless/shared/config.base.ts') + ); + return { + ...svlSharedConfig.getAll(), + services: { + ...services, + }, + kbnTestServer: { + ...svlSharedConfig.get('kbnTestServer'), + serverArgs: [ + ...svlSharedConfig.get('kbnTestServer.serverArgs'), + '--serverless=security', + `--xpack.securitySolutionServerless.productTypes=${JSON.stringify([ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + ])}`, + ...(options.kbnTestServerArgs || []), + ], + env: { + ...svlSharedConfig.get('kbnTestServer.env'), + ...options.kbnTestServerEnv, + }, + }, + testFiles: options.testFiles, + junit: options.junit, + + mochaOpts: { + ...svlSharedConfig.get('mochaOpts'), + grep: '/^(?!.*@brokenInServerless).*@serverless.*/', + }, + }; + }; +} diff --git a/x-pack/test/security_solution_api_integration/config/serverless/config.base.ts b/x-pack/test/security_solution_api_integration/config/serverless/config.base.ts index 6238282722cf..374538e593ef 100644 --- a/x-pack/test/security_solution_api_integration/config/serverless/config.base.ts +++ b/x-pack/test/security_solution_api_integration/config/serverless/config.base.ts @@ -11,15 +11,18 @@ export interface CreateTestConfigOptions { kbnTestServerArgs?: string[]; kbnTestServerEnv?: Record; } +import { services } from '../../../../test_serverless/api_integration/services'; export function createTestConfig(options: CreateTestConfigOptions) { return async ({ readConfigFile }: FtrConfigProviderContext) => { const svlSharedConfig = await readConfigFile( require.resolve('../../../../test_serverless/shared/config.base.ts') ); - return { ...svlSharedConfig.getAll(), + services: { + ...services, + }, kbnTestServer: { ...svlSharedConfig.get('kbnTestServer'), serverArgs: [ diff --git a/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/data.json b/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/data.json new file mode 100644 index 000000000000..80ccf200301c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/data.json @@ -0,0 +1,418 @@ +{ + "type": "doc", + "value": { + "id": "978783", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.595350Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978783/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "domain should match the auditbeat hosts' data's source.ip", + "domain": "159.89.119.67", + "first_seen": "2021-01-26T11:09:04.000Z", + "provider": "geenensp", + "type": "url", + "url": { + "full": "http://159.89.119.67:59600/bin.sh", + "scheme": "http" + } + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": false, + "tags": null, + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "978784", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.616763Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978782/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "this should not match the auditbeat hosts data", + "ip": "125.46.136.106", + "first_seen": "2021-01-26T11:06:03.000Z", + "provider": "geenensp", + "type": "ip" + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": true, + "tags": [ + "32-bit", + "elf", + "mips" + ], + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "978785", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.616763Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978782/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "this should match auditbeat/hosts on both port and ip", + "ip": "45.115.45.3", + "port": 57324, + "first_seen": "2021-01-26T11:06:03.000Z", + "provider": "geenensp", + "type": "url" + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": true, + "tags": [ + "32-bit", + "elf", + "mips" + ], + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "978787", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.616763Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978782/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "this should match auditbeat/hosts on ip", + "ip": "45.115.45.3", + "first_seen": "2021-01-26T11:06:03.000Z", + "provider": "other_provider", + "type": "ip" + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": true, + "tags": [ + "32-bit", + "elf", + "mips" + ], + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "978766", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.595350Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978783/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "domain should match the auditbeat hosts' data's source.ip", + "domain": "172.16.0.0", + "ip": "8.8.8.8", + "port": 777, + "first_seen": "2021-01-26T11:09:04.000Z", + "provider": "geenensp", + "type": "url", + "url": { + "full": "http://159.89.119.67:59600/bin.sh", + "scheme": "http" + } + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": false, + "tags": null, + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "978767", + "index": "filebeat-8.0.0-2021.01.26-000001", + "source": { + "@timestamp": "2021-01-26T11:09:05.529Z", + "agent": { + "ephemeral_id": "b7b56c3e-1f27-4c69-96f4-aa9ca47888d0", + "id": "69acb5f0-1e79-4cfe-a4dc-e0dbf229ff51", + "name": "MacBook-Pro-de-Gloria.local", + "type": "filebeat", + "version": "8.0.0" + }, + "ecs": { + "version": "1.6.0" + }, + "event": { + "category": "threat", + "created": "2021-01-26T11:09:05.529Z", + "dataset": "ti_abusech.malware", + "ingested": "2021-01-26T11:09:06.595350Z", + "kind": "enrichment", + "module": "threatintel", + "reference": "https://urlhaus.abuse.ch/url/978783/", + "type": "indicator" + }, + "fileset": { + "name": "abuseurl" + }, + "input": { + "type": "httpjson" + }, + "service": { + "type": "threatintel" + }, + "tags": [ + "threatintel-abuseurls", + "forwarded" + ], + "threat": { + "indicator": { + "description": "domain should match the auditbeat hosts' data's source.ip", + "domain": "172.16.0.0", + "ip": "9.9.9.9", + "port": 123, + "first_seen": "2021-01-26T11:09:04.000Z", + "provider": "geenensp", + "type": "url", + "url": { + "full": "http://159.89.119.67:59600/bin.sh", + "scheme": "http" + } + } + }, + "threatintel": { + "abuseurl": { + "blacklists": { + "spamhaus_dbl": "not listed", + "surbl": "not listed" + }, + "larted": false, + "tags": null, + "threat": "malware_download", + "url_status": "online" + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/mappings.json b/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/mappings.json new file mode 100644 index 000000000000..eda2430daef9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/es_archive/serverless/filebeat/threat_intel/mappings.json @@ -0,0 +1,240 @@ +{ + "type": "index", + "value": { + "aliases": {}, + "index": "filebeat-8.0.0-2021.01.26-000001", + "mappings": { + "_meta": { + "beat": "filebeat", + "version": "7.0.0" + }, + "properties": { + "@timestamp": { + "type": "date" + }, + "@version": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "indicator": { + "properties": { + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "confidence": { + "ignore_above": 1024, + "type": "keyword" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "type": "wildcard" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "first_seen": { + "type": "date" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "last_seen": { + "type": "date" + }, + "marking": { + "properties": { + "tlp": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "matched": { + "properties": { + "atomic": { + "ignore_above": 1024, + "type": "keyword" + }, + "field": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner_stats": { + "type": "long" + }, + "sightings": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "subtechnique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "mapping": { + "total_fields": { + "limit": "10000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "refresh_interval": "5s" + } + } + } +} diff --git a/x-pack/test/security_solution_api_integration/ftr_provider_context_with_spaces.d.ts b/x-pack/test/security_solution_api_integration/ftr_provider_context_with_spaces.d.ts new file mode 100644 index 000000000000..f6f4e00f0b4a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/ftr_provider_context_with_spaces.d.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { GenericFtrProviderContext } from '@kbn/test'; + +import { SpacesServiceProvider } from '../common/services/spaces'; +import { services as serverlessServices } from '../../test_serverless/api_integration/services'; + +const services = { + ...serverlessServices, + spaces: SpacesServiceProvider, +}; +export type FtrProviderContextWithSpaces = GenericFtrProviderContext; diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json index 5f9dc14546a9..05299d0db6b9 100644 --- a/x-pack/test/security_solution_api_integration/package.json +++ b/x-pack/test/security_solution_api_integration/package.json @@ -7,8 +7,12 @@ "scripts": { "initialize-server:dr:default": "node ./scripts/index.js server detections_response default_license", "run-tests:dr:default": "node ./scripts/index.js runner detections_response default_license", + "initialize-server:dr:basicEssentials": "node ./scripts/index.js server detections_response basic_essentials_license", + "run-tests:dr:basicEssentials": "node ./scripts/index.js runner detections_response basic_essentials_license", "initialize-server:ea:default": "node ./scripts/index.js server entity_analytics default_license", "run-tests:ea:default": "node ./scripts/index.js runner entity_analytics default_license", + "initialize-server:lists:default": "node ./scripts/index.js server lists_and_exception_lists default_license", + "run-tests:lists:default": "node ./scripts/index.js runner lists_and_exception_lists default_license", "exception_workflows:server:serverless": "npm run initialize-server:dr:default exceptions/workflows serverless", "exception_workflows:runner:serverless": "npm run run-tests:dr:default exceptions/workflows serverless serverlessEnv", "exception_workflows:qa:serverless": "npm run run-tests:dr:default exceptions/workflows serverless qaEnv", @@ -83,6 +87,36 @@ "prebuilt_rules_update_prebuilt_rules_package:runner:serverless": "npm run run-tests:dr:default prebuilt_rules/update_prebuilt_rules_package serverless serverlessEnv", "prebuilt_rules_update_prebuilt_rules_package:qa:serverless": "npm run run-tests:dr:default prebuilt_rules/update_prebuilt_rules_package serverless qaEnv", "prebuilt_rules_update_prebuilt_rules_package:server:ess": "npm run initialize-server:dr:default prebuilt_rules/update_prebuilt_rules_package ess", - "prebuilt_rules_update_prebuilt_rules_package:runner:ess": "npm run run-tests:dr:default prebuilt_rules/update_prebuilt_rules_package ess essEnvs" + "prebuilt_rules_update_prebuilt_rules_package:runner:ess": "npm run run-tests:dr:default prebuilt_rules/update_prebuilt_rules_package ess essEnvs", + "rule_execution_logic:server:serverless": "npm run initialize-server:dr:default rule_execution_logic serverless", + "rule_execution_logic:runner:serverless": "npm run run-tests:dr:default rule_execution_logic serverless serverlessEnv", + "rule_execution_logic:qa:serverless": "npm run run-tests:dr:default rule_execution_logic serverless qaEnv", + "rule_execution_logic:server:ess": "npm run initialize-server:dr:default rule_execution_logic ess", + "rule_execution_logic:runner:ess": "npm run run-tests:dr:default rule_execution_logic ess essEnv", + "user_roles:server:serverless": "npm run initialize-server:dr:default user_roles serverless", + "user_roles:runner:serverless": "npm run run-tests:dr:default user_roles serverless serverlessEnv", + "user_roles:qa:serverless": "npm run run-tests:dr:default user_roles serverless qaEnv", + "user_roles:server:ess": "npm run initialize-server:dr:default user_roles ess", + "user_roles:runner:ess": "npm run run-tests:dr:default user_roles ess essEnv", + "telemetry:server:serverless": "npm run initialize-server:dr:default telemetry serverless", + "telemetry:runner:serverless": "npm run run-tests:dr:default telemetry serverless serverlessEnv", + "telemetry:qa:serverless": "npm run run-tests:dr:default telemetry serverless qaEnv", + "telemetry:server:ess": "npm run initialize-server:dr:default telemetry ess", + "telemetry:runner:ess": "npm run run-tests:dr:default telemetry ess essEnv", + "detection_engine_basicessentionals:server:serverless": "npm run initialize-server:dr:basicEssentials detection_engine serverless", + "detection_engine_basicessentionals:runner:serverless": "npm run run-tests:dr:basicEssentials detection_engine serverless serverlessEnv", + "detection_engine_basicessentionals:qa:serverless": "npm run run-tests:dr:basicEssentials detection_engine serverless qaEnv", + "detection_engine_basicessentionals:server:ess": "npm run initialize-server:dr:basicEssentials detection_engine ess", + "detection_engine_basicessentionals:runner:ess": "npm run run-tests:dr:basicEssentials detection_engine ess essEnv", + "exception_lists_items:server:serverless": "npm run initialize-server:lists:default exception_lists_items serverless", + "exception_lists_items:runner:serverless": "npm run run-tests:lists:default exception_lists_items serverless serverlessEnv", + "exception_lists_items:qa:serverless": "npm run run-tests:lists:default exception_lists_items serverless qaEnv", + "exception_lists_items:server:ess": "npm run initialize-server:lists:default exception_lists_items ess", + "exception_lists_items:runner:ess": "npm run run-tests:lists:default exception_lists_items ess essEnv", + "lists_items:server:serverless": "npm run initialize-server:lists:default lists_items serverless", + "lists_items:runner:serverless": "npm run run-tests:lists:default lists_items serverless serverlessEnv", + "lists_items:qa:serverless": "npm run run-tests:lists:default lists_items serverless qaEnv", + "lists_items:server:ess": "npm run initialize-server:lists:default lists_items ess", + "lists_items:runner:ess": "npm run run-tests:lists:default lists_items ess essEnv" } } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/open_close_alerts.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/open_close_alerts.ts new file mode 100644 index 000000000000..4af66d1da4a9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/open_close_alerts.ts @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + DETECTION_ENGINE_SIGNALS_STATUS_URL, + DETECTION_ENGINE_QUERY_SIGNALS_URL, +} from '@kbn/security-solution-plugin/common/constants'; +import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { + createAlertsIndex, + setAlertStatus, + getQueryAlertIds, + deleteAllRules, + createRule, + waitForAlertsToBePresent, + getAlertsByIds, + waitForRuleSuccess, + getRuleForAlertTesting, + deleteAllAlerts, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditbeatHost = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess @serverless open_close_alerts', () => { + describe('tests with auditbeat data', () => { + before(async () => { + await esArchiver.load(auditbeatHost); + }); + + after(async () => { + await esArchiver.unload(auditbeatHost); + }); + + beforeEach(async () => { + await deleteAllRules(supertest, log); + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should be able to execute and get 10 alerts', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + expect(alertsOpen.hits.hits.length).equal(10); + }); + + it('should be have set the alerts in an open state initially', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const everyAlertOpen = alertsOpen.hits.hits.every( + (hit) => hit._source?.[ALERT_WORKFLOW_STATUS] === 'open' + ); + expect(everyAlertOpen).to.eql(true); + }); + + it('should be able to get a count of 10 closed alerts when closing 10', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const alertIds = alertsOpen.hits.hits.map((alert) => alert._id); + + // set all of the alerts to the state of closed. There is no reason to use a waitUntil here + // as this route intentionally has a waitFor within it and should only return when the query has + // the data. + await supertest + .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) + .set('kbn-xsrf', 'true') + .send(setAlertStatus({ alertIds, status: 'closed' })) + .expect(200); + + const { body: alertsClosed }: { body: estypes.SearchResponse } = + await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + expect(alertsClosed.hits.hits.length).to.equal(10); + }); + + // Test is failing after changing refresh to false + it.skip('should be able close 10 alerts immediately and they all should be closed', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const alertIds = alertsOpen.hits.hits.map((alert) => alert._id); + + // set all of the alerts to the state of closed. There is no reason to use a waitUntil here + // as this route intentionally has a waitFor within it and should only return when the query has + // the data. + await supertest + .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) + .set('kbn-xsrf', 'true') + .send(setAlertStatus({ alertIds, status: 'closed' })) + .expect(200); + + const { body: alertsClosed }: { body: estypes.SearchResponse } = + await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + const everyAlertClosed = alertsClosed.hits.hits.every( + (hit) => hit._source?.[ALERT_WORKFLOW_STATUS] === 'closed' + ); + expect(everyAlertClosed).to.eql(true); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts.ts new file mode 100644 index 000000000000..3b372597cffd --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts.ts @@ -0,0 +1,186 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { + DETECTION_ENGINE_QUERY_SIGNALS_URL, + ALERTS_AS_DATA_FIND_URL, +} from '@kbn/security-solution-plugin/common/constants'; +import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common'; +import { getAlertStatus, createAlertsIndex, deleteAllAlerts } from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess @serverless query_signals_route and find_alerts_route', () => { + describe('validation checks', () => { + // This fails and should be investigated or removed if it no longer applies + it.skip('should not give errors when querying and the alerts index does exist and is empty', async () => { + await createAlertsIndex(supertest, log); + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getAlertStatus()) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql({ + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + statuses: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + }); + + await deleteAllAlerts(supertest, log, es); + }); + }); + + describe('runtime fields', () => { + before(async () => { + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs', + { + useCreate: true, + docsOnly: true, + } + ); + await createAlertsIndex(supertest, log); + }); + after(async () => { + // await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals'); + await deleteAllAlerts(supertest, log, es); + }); + + it('should be able to filter using a runtime field defined in the request', async () => { + const query = { + query: { + bool: { + should: [{ match_phrase: { signal_status_querytime: 'open' } }], + }, + }, + runtime_mappings: { + signal_status_querytime: { + type: 'keyword', + script: { + source: `emit(doc['signal.status'].value)`, + }, + }, + }, + }; + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(3); + }); + }); + + describe('find_alerts_route', () => { + describe('validation checks', () => { + // This fails and should be investigated or removed if it no longer applies + it.skip('should not give errors when querying and the alerts index does exist and is empty', async () => { + await createAlertsIndex(supertest, log); + const { body } = await supertest + .post(ALERTS_AS_DATA_FIND_URL) + .set('kbn-xsrf', 'true') + .send({ ...getAlertStatus(), index: '.siem-signals-default' }) + .expect(200); + + // remove any server generated items that are indeterministic + delete body.took; + + expect(body).to.eql({ + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, + hits: { total: { value: 0, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + statuses: { doc_count_error_upper_bound: 0, sum_other_doc_count: 0, buckets: [] }, + }, + }); + + await deleteAllAlerts(supertest, log, es); + }); + + it('should not give errors when executing security solution histogram aggs', async () => { + await createAlertsIndex(supertest, log); + await supertest + .post(ALERTS_AS_DATA_FIND_URL) + .set('kbn-xsrf', 'true') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send({ + index: '.siem-signals-default', + aggs: { + alertsByGrouping: { + terms: { + field: 'event.category', + missing: 'All others', + order: { _count: 'desc' }, + size: 10, + }, + aggs: { + alerts: { + date_histogram: { + field: '@timestamp', + fixed_interval: '2699999ms', + min_doc_count: 0, + extended_bounds: { + min: '2021-08-17T04:00:00.000Z', + max: '2021-08-18T03:59:59.999Z', + }, + }, + }, + }, + }, + }, + query: { + bool: { + filter: [ + { + bool: { + must: [], + filter: [ + { + match_phrase: { + 'kibana.alert.rule.uuid': 'c76f1a10-ffb6-11eb-8914-9b237bf6808c', + }, + }, + { term: { 'kibana.alert.workflow_status': 'open' } }, + ], + should: [], + must_not: [{ exists: { field: 'kibana.alert.building_block_type' } }], + }, + }, + { + range: { + '@timestamp': { + gte: '2021-08-17T04:00:00.000Z', + lte: '2021-08-18T03:59:59.999Z', + }, + }, + }, + ], + }, + }, + }) + .expect(200); + + await deleteAllAlerts(supertest, log, es); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts_backword_compatibility.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts_backword_compatibility.ts new file mode 100644 index 000000000000..76f85dd32397 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/alerts/query_alerts_backword_compatibility.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '@kbn/security-solution-plugin/common/constants'; +import { createAlertsIndex, deleteAllAlerts } from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess query_alerts_backword_compatibility', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/endpoint/resolver/signals'); + await createAlertsIndex(supertest, log); + }); + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals'); + await deleteAllAlerts(supertest, log, es); + }); + + it('should be able to filter old alerts on host.os.name.caseless using runtime field', async () => { + const query = { + query: { + bool: { + should: [{ match_phrase: { 'host.os.name.caseless': 'windows' } }], + }, + }, + }; + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(3); + }); + + it('should be able to filter old alerts using field aliases', async () => { + const query = { + query: { + bool: { + should: [{ match_phrase: { 'kibana.alert.workflow_status': 'open' } }], + }, + }, + }; + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(3); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/ess.config.ts new file mode 100644 index 000000000000..b980aef5f783 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.basic') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine ESS - Basic Integration Tests', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/serverless.config.ts new file mode 100644 index 000000000000..8a4199ccfb44 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/configs/serverless.config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base.essentials'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine Serverless - Essentials Integration Tests', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/index.ts new file mode 100644 index 000000000000..296cec0e0644 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Detection Engine Basic and Essentials API', function () { + loadTestFile(require.resolve('./rules/create_rules')); + loadTestFile(require.resolve('./rules/create_ml_rules_privileges')); + loadTestFile(require.resolve('./alerts/open_close_alerts')); + loadTestFile(require.resolve('./alerts/query_alerts')); + loadTestFile(require.resolve('./alerts/query_alerts_backword_compatibility')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_ml_rules_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_ml_rules_privileges.ts new file mode 100644 index 000000000000..0b4bcea421c7 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_ml_rules_privileges.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; + +import { + createAlertsIndex, + deleteAllRules, + removeServerGeneratedProperties, + getSimpleMlRule, + deleteAllAlerts, + updateUsername, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + // TODO: add a new service + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditbeatPath = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('create_ml_rules', () => { + describe('Creating Machine Learning rules', () => { + before(async () => { + await esArchiver.load(auditbeatPath); + }); + + after(async () => { + await esArchiver.unload(auditbeatPath); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('@ess should give a 403 when trying to create a single Machine Learning rule since the license is basic', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleMlRule()) + .expect(403); + + const bodyToCompare = removeServerGeneratedProperties(body); + expect(bodyToCompare).toEqual({ + message: 'Your license does not support machine learning. Please upgrade your license.', + status_code: 403, + }); + }); + it('@serverless should give a 200 when trying to create a single Machine Learning rule since the license is essentials', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleMlRule()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + const expectedRule = updateUsername(getSimpleMlRule(), ELASTICSEARCH_USERNAME); + expect(bodyToCompare).toEqual(expect.objectContaining(expectedRule)); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_rules.ts new file mode 100644 index 000000000000..6a3fff87611d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/basic_essentials_license/detection_engine/rules/create_rules.ts @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { RuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; + +import { + createAlertsIndex, + deleteAllRules, + getSimpleRule, + getSimpleRuleOutputWithoutRuleId, + getSimpleRuleWithoutRuleId, + removeServerGeneratedProperties, + removeServerGeneratedPropertiesIncludingRuleId, + deleteAllAlerts, + updateUsername, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + // TODO: add a new service + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditbeatPath = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess @serverless create_rules', () => { + describe('creating rules', () => { + before(async () => { + await esArchiver.load(auditbeatPath); + }); + + after(async () => { + await esArchiver.unload(auditbeatPath); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should create a single rule with a rule_id', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleRule()) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + const expectedRule = updateUsername(bodyToCompare, ELASTICSEARCH_USERNAME); + + expect(bodyToCompare).to.eql(expectedRule); + }); + + it('should create a single rule without an input index', async () => { + const rule: RuleCreateProps = { + name: 'Simple Rule Query', + description: 'Simple Rule Query', + enabled: true, + risk_score: 1, + rule_id: 'rule-1', + severity: 'high', + type: 'query', + query: 'user.name: root or user.name: admin', + }; + + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(rule) + .expect(200); + + const bodyToCompare = removeServerGeneratedProperties(body); + const expectedRule = updateUsername(bodyToCompare, ELASTICSEARCH_USERNAME); + + expect(bodyToCompare).to.eql(expectedRule); + }); + + it('should create a single rule without a rule_id', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleRuleWithoutRuleId()) + .expect(200); + + const bodyToCompare = removeServerGeneratedPropertiesIncludingRuleId(body); + const expectedRule = updateUsername( + getSimpleRuleOutputWithoutRuleId(), + ELASTICSEARCH_USERNAME + ); + + expect(bodyToCompare).to.eql(expectedRule); + }); + + it('should cause a 409 conflict if we attempt to create the same rule_id twice', async () => { + await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleRule()) + .expect(200); + + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .send(getSimpleRule()) + .expect(409); + + expect(body).to.eql({ + message: 'rule_id: "rule-1" already exists', + status_code: 409, + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/add_actions.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/add_actions.ts index 8046eb89e0a2..1e4b1692cf9f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/add_actions.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/add_actions.ts @@ -6,7 +6,7 @@ */ import expect from 'expect'; - +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { deleteAllRules, @@ -55,7 +55,7 @@ export default ({ getService }: FtrProviderContext) => { const { body } = await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .send( getCustomQueryRuleParams({ actions: [ruleAction], @@ -74,7 +74,7 @@ export default ({ getService }: FtrProviderContext) => { } = await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .send( getCustomQueryRuleParams({ index: ['logs-test'], @@ -108,7 +108,7 @@ export default ({ getService }: FtrProviderContext) => { } = await supertest .post(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .send( getCustomQueryRuleParams({ index: ['logs-test'], diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/check_privileges.ts similarity index 89% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/check_privileges.ts index 3a016fe68618..cbcd75074b57 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/check_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/check_privileges.ts @@ -9,19 +9,22 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; import { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; + import { - createSignalsIndex, + createAlertsIndex, deleteAllRules, waitForRulePartialFailure, - getRuleForSignalTesting, + getRuleForAlertTesting, createRuleWithAuth, - getThresholdRuleForSignalTesting, + getThresholdRuleForAlertTesting, deleteAllAlerts, } from '../../utils'; -import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution'; +import { + createUserAndRole, + deleteUserAndRole, +} from '../../../../../common/services/security_solution'; -// eslint-disable-next-line import/no-default-export +import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -29,11 +32,11 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const es = getService('es'); - describe('check_privileges', () => { + describe('@ess @serverless @brokenInServerless check_privileges', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alias'); - await createSignalsIndex(supertest, log); + await createAlertsIndex(supertest, log); }); after(async () => { @@ -60,7 +63,7 @@ export default ({ getService }: FtrProviderContext) => { indexTestCases.forEach((index) => { it(`for KQL rule with index param: ${index}`, async () => { const rule = { - ...getRuleForSignalTesting(index), + ...getRuleForAlertTesting(index), query: 'process.executable: "/usr/bin/sudo"', }; await createUserAndRole(getService, ROLES.detections_admin); @@ -96,7 +99,7 @@ export default ({ getService }: FtrProviderContext) => { thresholdIndexTestCases.forEach((index) => { it(`for threshold rule with index param: ${index}`, async () => { const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(index), + ...getThresholdRuleForAlertTesting(index), threshold: { field: [], value: 700, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts index cec8d1cca41b..e508918b0538 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts @@ -16,7 +16,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...functionalConfig.getAll(), testFiles: [require.resolve('..')], junit: { - reportName: 'Detection Engine ESS/Actions API Integration Tests', + reportName: 'Detection Engine ESS - Actions API Integration Tests', }, }; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts index 66edc0eef7f3..ea876833ea83 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts @@ -10,6 +10,6 @@ import { createTestConfig } from '../../../../../config/serverless/config.base'; export default createTestConfig({ testFiles: [require.resolve('..')], junit: { - reportName: 'Detection Engine Serverless/Actions API Integration Tests', + reportName: 'Detection Engine Serverless - Actions API Integration Tests', }, }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/index.ts index 5c26d445eb15..4eb7f7eac697 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/index.ts @@ -11,5 +11,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./add_actions')); loadTestFile(require.resolve('./update_actions')); loadTestFile(require.resolve('./migrations')); + loadTestFile(require.resolve('./throttle')); + loadTestFile(require.resolve('./check_privileges')); }); } diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/throttle.ts similarity index 78% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/throttle.ts index 34984d4ea0dc..ee5d81b9f29f 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/throttle.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/throttle.ts @@ -13,20 +13,24 @@ import { NOTIFICATION_THROTTLE_NO_ACTIONS, NOTIFICATION_THROTTLE_RULE, } from '@kbn/security-solution-plugin/common/constants'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { - createSignalsIndex, + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; +import { + createAlertsIndex, deleteAllRules, deleteAllAlerts, getWebHookAction, getRuleWithWebHookAction, createRule, getSimpleRule, - getRule, + fetchRule, updateRule, } from '../../utils'; -// eslint-disable-next-line import/no-default-export +import { FtrProviderContext } from '../../../../ftr_provider_context'; + export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); @@ -45,10 +49,10 @@ export default ({ getService }: FtrProviderContext) => { * https://www.elastic.co/guide/en/kibana/current/mute-all-alerts-api.html * https://www.elastic.co/guide/en/security/current/rules-api-create.html */ - describe('throttle', () => { + describe('@ess @serverless throttle', () => { describe('adding actions', () => { beforeEach(async () => { - await createSignalsIndex(supertest, log); + await createAlertsIndex(supertest, log); }); afterEach(async () => { @@ -62,13 +66,17 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); const rule = await createRule(supertest, log, getRuleWithWebHookAction(hookAction.id)); const { body: { mute_all: muteAll, notify_when: notifyWhen, actions }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(actions.length).to.eql(1); expect(actions[0].frequency).to.eql({ @@ -87,7 +95,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -97,6 +107,7 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -107,7 +118,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -120,7 +133,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -140,6 +155,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -150,7 +167,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen, actions }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(actions.length).to.eql(1); expect(actions[0].frequency).to.eql({ @@ -169,7 +188,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -179,6 +200,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -189,7 +212,9 @@ export default ({ getService }: FtrProviderContext) => { const rule = await createRule(supertest, log, ruleWithThrottle); const { body: { mute_all: muteAll, notify_when: notifyWhen, actions }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(actions.length).to.eql(1); expect(actions[0].frequency).to.eql({ @@ -207,11 +232,13 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); const rule = await createRule(supertest, log, getRuleWithWebHookAction(hookAction.id)); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); @@ -221,7 +248,7 @@ export default ({ getService }: FtrProviderContext) => { throttle: NOTIFICATION_THROTTLE_NO_ACTIONS, }; const rule = await createRule(supertest, log, ruleWithThrottle); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); @@ -232,7 +259,7 @@ export default ({ getService }: FtrProviderContext) => { throttle: NOTIFICATION_THROTTLE_RULE, }; const rule = await createRule(supertest, log, ruleWithThrottle); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); @@ -241,6 +268,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -248,9 +277,11 @@ export default ({ getService }: FtrProviderContext) => { await supertest .post(`/api/alerting/rule/${rule.id}/_mute_all`) .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send() .expect(204); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); }); @@ -261,13 +292,15 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); const ruleWithWebHookAction = getRuleWithWebHookAction(hookAction.id); await createRule(supertest, log, ruleWithWebHookAction); ruleWithWebHookAction.name = 'some other name'; - const updated = await updateRule(supertest, log, ruleWithWebHookAction); + const updated = await updateRule(supertest, ruleWithWebHookAction); expect(updated.throttle).to.eql(undefined); }); @@ -276,16 +309,20 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); const ruleWithWebHookAction = getRuleWithWebHookAction(hookAction.id); await createRule(supertest, log, ruleWithWebHookAction); ruleWithWebHookAction.name = 'some other name'; - const updated = await updateRule(supertest, log, ruleWithWebHookAction); + const updated = await updateRule(supertest, ruleWithWebHookAction); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${updated.id}`); + } = await supertest + .get(`/api/alerting/rule/${updated.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -296,13 +333,15 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); const ruleWithWebHookAction = getRuleWithWebHookAction(hookAction.id); await createRule(supertest, log, ruleWithWebHookAction); ruleWithWebHookAction.actions = []; - const updated = await updateRule(supertest, log, ruleWithWebHookAction); + const updated = await updateRule(supertest, ruleWithWebHookAction); expect(updated.throttle).to.eql(undefined); }); }); @@ -313,6 +352,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -322,10 +363,11 @@ export default ({ getService }: FtrProviderContext) => { await supertest .patch(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send({ rule_id: rule.rule_id, name: 'some other name' }) .expect(200); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); @@ -334,6 +376,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -343,12 +387,15 @@ export default ({ getService }: FtrProviderContext) => { await supertest .patch(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send({ rule_id: rule.rule_id, name: 'some other name' }) .expect(200); const { body: { mute_all: muteAll, notify_when: notifyWhen }, - } = await supertest.get(`/api/alerting/rule/${rule.id}`); + } = await supertest + .get(`/api/alerting/rule/${rule.id}`) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); expect(muteAll).to.eql(false); expect(notifyWhen).to.eql(null); }); @@ -359,6 +406,8 @@ export default ({ getService }: FtrProviderContext) => { const { body: hookAction } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(getWebHookAction()) .expect(200); @@ -368,10 +417,11 @@ export default ({ getService }: FtrProviderContext) => { await supertest .patch(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send({ rule_id: rule.rule_id, actions: [] }) .expect(200); - const readRule = await getRule(supertest, log, rule.rule_id); + const readRule = await fetchRule(supertest, { ruleId: rule.rule_id }); expect(readRule.throttle).to.eql(undefined); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/alerts_compatibility.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/alerts_compatibility.ts index 9e4a9d05771d..1194a1f8df86 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/alerts_compatibility.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/alerts_compatibility.ts @@ -36,7 +36,7 @@ import { waitFor, waitForRuleSuccess, waitForAlertsToBePresent, - removeRandomValuedProperties, + removeRandomValuedPropertiesFromAlert, } from '../../utils'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -231,11 +231,11 @@ export default ({ getService }: FtrProviderContext) => { expect(signalsOpen.hits.hits.length).greaterThan(0); const hit = signalsOpen.hits.hits[0]; expect(hit._source?.kibana).to.eql(undefined); - const source = removeRandomValuedProperties(hit._source); + const source = removeRandomValuedPropertiesFromAlert(hit._source); expect(source).to.eql({ 'kibana.alert.rule.category': 'Custom Query Rule', 'kibana.alert.rule.consumer': 'siem', - 'kibana.alert.rule.name': 'Signal Testing Query', + 'kibana.alert.rule.name': 'Alert Testing Query', 'kibana.alert.rule.producer': 'siem', 'kibana.alert.rule.rule_type_id': 'siem.queryRule', 'kibana.space_ids': ['default'], @@ -320,9 +320,10 @@ export default ({ getService }: FtrProviderContext) => { 'kibana.alert.status': 'active', 'kibana.alert.workflow_status': 'open', 'kibana.alert.workflow_tags': [], + 'kibana.alert.workflow_assignee_ids': [], 'kibana.alert.depth': 2, 'kibana.alert.reason': - 'event on security-linux-1 created high alert Signal Testing Query.', + 'event on security-linux-1 created high alert Alert Testing Query.', 'kibana.alert.severity': 'high', 'kibana.alert.risk_score': 1, 'kibana.alert.rule.parameters': { @@ -393,11 +394,11 @@ export default ({ getService }: FtrProviderContext) => { expect(signalsOpen.hits.hits.length).greaterThan(0); const hit = signalsOpen.hits.hits[0]; expect(hit._source?.kibana).to.eql(undefined); - const source = removeRandomValuedProperties(hit._source); + const source = removeRandomValuedPropertiesFromAlert(hit._source); expect(source).to.eql({ 'kibana.alert.rule.category': 'Custom Query Rule', 'kibana.alert.rule.consumer': 'siem', - 'kibana.alert.rule.name': 'Signal Testing Query', + 'kibana.alert.rule.name': 'Alert Testing Query', 'kibana.alert.rule.producer': 'siem', 'kibana.alert.rule.rule_type_id': 'siem.queryRule', 'kibana.space_ids': ['default'], @@ -482,9 +483,10 @@ export default ({ getService }: FtrProviderContext) => { 'kibana.alert.status': 'active', 'kibana.alert.workflow_status': 'open', 'kibana.alert.workflow_tags': [], + 'kibana.alert.workflow_assignee_ids': [], 'kibana.alert.depth': 2, 'kibana.alert.reason': - 'event on security-linux-1 created high alert Signal Testing Query.', + 'event on security-linux-1 created high alert Alert Testing Query.', 'kibana.alert.severity': 'high', 'kibana.alert.risk_score': 1, 'kibana.alert.rule.parameters': { diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts new file mode 100644 index 000000000000..b520b505e040 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments.ts @@ -0,0 +1,519 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import { + DETECTION_ENGINE_ALERT_ASSIGNEES_URL, + DETECTION_ENGINE_QUERY_SIGNALS_URL, +} from '@kbn/security-solution-plugin/common/constants'; +import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +import { + createAlertsIndex, + createRule, + deleteAllAlerts, + deleteAllRules, + getAlertsByIds, + getQueryAlertIds, + getRuleForAlertTesting, + setAlertAssignees, + waitForAlertsToBePresent, + waitForRuleSuccess, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess @serverless Alert User Assignment - ESS & Serverless', () => { + describe('validation checks', () => { + it('should give errors when no alert ids are provided', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send(setAlertAssignees({ assigneesToAdd: [], assigneesToRemove: [], ids: [] })) + .expect(400); + + expect(body).to.eql({ + error: 'Bad Request', + message: '[request body]: ids: Array must contain at least 1 element(s)', + statusCode: 400, + }); + }); + + it('should give errors when empty alert ids are provided', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send(setAlertAssignees({ assigneesToAdd: [], assigneesToRemove: [], ids: ['123', ''] })) + .expect(400); + + expect(body).to.eql({ + error: 'Bad Request', + message: + '[request body]: ids.1: String must contain at least 1 character(s), ids.1: Invalid', + statusCode: 400, + }); + }); + + it('should give errors when duplicate assignees exist in both add and remove', async () => { + const { body } = await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['test-1'], + assigneesToRemove: ['test-1'], + ids: ['123'], + }) + ) + .expect(400); + + expect(body).to.eql({ + message: ['Duplicate assignees ["test-1"] were found in the add and remove parameters.'], + status_code: 400, + }); + }); + }); + + describe('tests with auditbeat data', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + }); + + beforeEach(async () => { + await deleteAllRules(supertest, log); + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + }); + + describe('updating assignees', () => { + it('should add new assignees to single alert', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + const alertId = alertIds[0]; + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1'], + assigneesToRemove: [], + ids: [alertId], + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds([alertId])) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql(['user-1']); + }); + }); + + it('should add new assignees to multiple alerts', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-2', 'user-3'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-2', + 'user-3', + ]); + }); + }); + + it('should update assignees for single alert', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + const alertId = alertIds[0]; + + // Assign users + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: [alertId], + }) + ) + .expect(200); + + // Update assignees + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-3'], + assigneesToRemove: ['user-2'], + ids: [alertId], + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds([alertId])) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-3', + ]); + }); + }); + + it('should update assignees for multiple alerts', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + // Assign users + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + // Update assignees + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-3'], + assigneesToRemove: ['user-2'], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-3', + ]); + }); + }); + + it('should add assignee once to the alert even if same assignee was passed multiple times', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-1', 'user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-2', + ]); + }); + }); + + it('should remove assignee once to the alert even if same assignee was passed multiple times', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: [], + assigneesToRemove: ['user-2', 'user-2'], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql(['user-1']); + }); + }); + + it('should not update assignees if both `add` and `remove` are empty', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: [], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-2', + ]); + }); + }); + + it('should not update assignees when adding user which is assigned to alert', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-2', + ]); + }); + }); + + it('should not update assignees when removing user which is not assigned to alert', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1', 'user-2'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + + await supertest + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .send( + setAlertAssignees({ + assigneesToAdd: [], + assigneesToRemove: ['user-3'], + ids: alertIds, + }) + ) + .expect(200); + + const { body }: { body: estypes.SearchResponse } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(getQueryAlertIds(alertIds)) + .expect(200); + + body.hits.hits.map((alert) => { + expect(alert._source?.['kibana.alert.workflow_assignee_ids']).to.eql([ + 'user-1', + 'user-2', + ]); + }); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_ess.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_ess.ts new file mode 100644 index 000000000000..527d02295f6a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_ess.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; + +import { + createUserAndRole, + deleteUserAndRole, +} from '../../../../../../common/services/security_solution'; +import { + createAlertsIndex, + createRule, + deleteAllAlerts, + deleteAllRules, + getAlertsByIds, + getRuleForAlertTesting, + setAlertAssignees, + waitForAlertsToBePresent, + waitForRuleSuccess, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess Alert User Assignment - ESS', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + }); + + beforeEach(async () => { + await deleteAllRules(supertest, log); + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + }); + + describe('authorization / RBAC', () => { + it('should not allow viewer user to assign alerts', async () => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + const userAndRole = ROLES.reader; + await createUserAndRole(getService, userAndRole); + + // Try to set all of the alerts to the state of closed. + // This should not be possible with the given user. + await supertestWithoutAuth + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .auth(userAndRole, 'changeme') // each user has the same password + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(403); + + await deleteUserAndRole(getService, userAndRole); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_serverless.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_serverless.ts new file mode 100644 index 000000000000..dd41574c5694 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/assignments_serverless.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; + +import { + createAlertsIndex, + createRule, + deleteAllAlerts, + deleteAllRules, + getAlertsByIds, + getRuleForAlertTesting, + setAlertAssignees, + waitForAlertsToBePresent, + waitForRuleSuccess, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@serverless Alert User Assignment - Serverless', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + }); + + beforeEach(async () => { + await deleteAllRules(supertest, log); + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + }); + + describe('authorization / RBAC', () => { + const successfulAssignWithRole = async (userAndRole: ROLES) => { + const rule = { + ...getRuleForAlertTesting(['auditbeat-*']), + query: 'process.executable: "/usr/bin/sudo"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 10, [id]); + const alerts = await getAlertsByIds(supertest, log, [id]); + const alertIds = alerts.hits.hits.map((alert) => alert._id); + + // Try to set all of the alerts to the state of closed. + // This should not be possible with the given user. + await supertestWithoutAuth + .post(DETECTION_ENGINE_ALERT_ASSIGNEES_URL) + .set('kbn-xsrf', 'true') + .auth(userAndRole, 'changeme') // each user has the same password + .send( + setAlertAssignees({ + assigneesToAdd: ['user-1'], + assigneesToRemove: [], + ids: alertIds, + }) + ) + .expect(200); + }; + + it('should allow `ROLES.t1_analyst` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.t1_analyst); + }); + + it('should allow `ROLES.t2_analyst` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.t2_analyst); + }); + + it('should allow `ROLES.t3_analyst` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.t3_analyst); + }); + + it('should allow `ROLES.detections_admin` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.detections_admin); + }); + + it('should allow `ROLES.platform_engineer` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.platform_engineer); + }); + + it('should allow `ROLES.rule_author` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.rule_author); + }); + + it('should allow `ROLES.soc_manager` to assign alerts', async () => { + await successfulAssignWithRole(ROLES.soc_manager); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/index.ts new file mode 100644 index 000000000000..401f92ea9dcf --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/assignments/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Alert assignments API', function () { + loadTestFile(require.resolve('./assignments')); + loadTestFile(require.resolve('./assignments_ess')); + loadTestFile(require.resolve('./assignments_serverless')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts index 7482e1bac558..85e2e602a892 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/alerts/index.ts @@ -14,5 +14,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./migrations')); loadTestFile(require.resolve('./open_close_alerts')); loadTestFile(require.resolve('./set_alert_tags')); + loadTestFile(require.resolve('./assignments')); }); } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/date.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/date.ts index 3ccad9a60e94..c3cedb6daf88 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/date.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/date.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/double.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/double.ts index 20efdb98b631..9f2673b8542a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/double.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/double.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/float.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/float.ts index 25d7d2e83c77..850276622cc6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/float.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/float.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/integer.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/integer.ts index 5df611948611..fe26c4a2d729 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/integer.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/integer.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip.ts index 9e73771d11f0..ca09070e4676 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip_array.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip_array.ts index 12c4eb6d5536..0c2808ee252a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip_array.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips/ip_array.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword.ts index 11289a31b124..9d4b1bfd80a1 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword_array.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword_array.ts index 58f41321e7a8..284d20adfc3e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword_array.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/keyword/keyword_array.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/long/long.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/long/long.ts index 69803854e930..497f24ec217a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/long/long.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/long/long.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text.ts index df7a42dc88de..8713cc8ce859 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text.ts @@ -13,7 +13,7 @@ import { deleteListsIndex, importFile, importTextFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text_array.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text_array.ts index 915d353281f6..8c4a265a182b 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text_array.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/text/text_array.ts @@ -12,7 +12,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../../lists_api_integration/utils'; +} from '../../../../../lists_and_exception_lists/utils'; import { createRule, createRuleWithExceptionEntries, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_endpoint_exceptions.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_endpoint_exceptions.ts index 1c647fe52810..0d908b744912 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_endpoint_exceptions.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_endpoint_exceptions.ts @@ -24,7 +24,7 @@ import { createListsIndex, deleteAllExceptions, deleteListsIndex, -} from '../../../../../../lists_api_integration/utils'; +} from '../../../../lists_and_exception_lists/utils'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_rule_exceptions.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_rule_exceptions.ts index 3607cba64151..1f1e4d91d4a0 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_rule_exceptions.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/create_rule_exceptions.ts @@ -31,7 +31,7 @@ import { import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties, -} from '../../../../../../lists_api_integration/utils'; +} from '../../../../lists_and_exception_lists/utils'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; const getRuleExceptionItemMock = (): CreateRuleExceptionListItemSchema => ({ diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/find_rule_exception_references.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/find_rule_exception_references.ts index a2f996539f19..87f9c4a17914 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/find_rule_exception_references.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/find_rule_exception_references.ts @@ -30,7 +30,7 @@ import { deleteAllAlerts, createAlertsIndex, } from '../../../utils'; -import { deleteAllExceptions } from '../../../../../../lists_api_integration/utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_add_edit_comments.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_add_edit_comments.ts index 3ce0aa0bed87..8e36816213cf 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_add_edit_comments.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_add_edit_comments.ts @@ -18,7 +18,7 @@ import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/c import { ROLES } from '@kbn/security-solution-plugin/common/test'; import { getUpdateMinimalExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_exception_list_item_schema.mock'; import { UpdateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { deleteAllExceptions } from '../../../../../../lists_api_integration/utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; import { createUserAndRole, deleteUserAndRole, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_rule_exceptions_workflows.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_rule_exceptions_workflows.ts index f62501b026c2..870df90d3e47 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_rule_exceptions_workflows.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/role_based_rule_exceptions_workflows.ts @@ -60,7 +60,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../lists_api_integration/utils'; +} from '../../../../lists_and_exception_lists/utils'; import { createUserAndRole, deleteUserAndRole, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/rule_exception_synchronizations.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/rule_exception_synchronizations.ts index d89055f698ce..7bbfcf565942 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/rule_exception_synchronizations.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/rule_exception_synchronizations.ts @@ -30,7 +30,7 @@ import { deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../../../../lists_api_integration/utils'; +} from '../../../../lists_and_exception_lists/utils'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; export default ({ getService }: FtrProviderContext) => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/bundled_prebuilt_rules_package/install_latest_bundled_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/bundled_prebuilt_rules_package/install_latest_bundled_prebuilt_rules.ts index bd306b0d6565..60e0399df53f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/bundled_prebuilt_rules_package/install_latest_bundled_prebuilt_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/prebuilt_rules/bundled_prebuilt_rules_package/install_latest_bundled_prebuilt_rules.ts @@ -23,12 +23,13 @@ export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + // FLAKY: https://github.com/elastic/kibana/issues/171380 /* This test simulates an air-gapped environment in which the user doesn't have access to EPR. /* We first download the package from the registry as done during build time, and then /* attempt to install it from the local file system. The API response from EPM provides /* us with the information of whether the package was installed from the registry or /* from a package that was bundled with Kibana */ - describe('@ess @serverless @skipInQA install_bundled_prebuilt_rules', () => { + describe.skip('@ess @serverless @skipInQA install_bundled_prebuilt_rules', () => { beforeEach(async () => { await deleteAllRules(supertest, log); await deleteAllPrebuiltRuleAssets(es); @@ -66,7 +67,7 @@ export default ({ getService }: FtrProviderContext): void => { expect(bundledInstallResponse._meta.install_source).toBe('bundled'); // Refresh ES indices to avoid race conditions between write and reading of indeces - // See implementation utility function at x-pack/test/detection_engine_api_integration/utils/prebuilt_rules/install_prebuilt_rules_fleet_package.ts + // See implementation utility function at x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/prebuilt_rules/install_prebuilt_rules_fleet_package.ts await es.indices.refresh({ index: ALL_SAVED_OBJECT_INDICES }); // Verify that status is updated after package installation diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts index a887f07cb2cf..49ed77a4dc48 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts @@ -431,8 +431,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).toEqual({ error: 'Bad Request', - message: - '[request body]: type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", saved_id: Required, and 14 more', + message: '[request body]: threshold: Required', statusCode: 400, }); }); @@ -541,7 +540,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(400); expect(body.message).toBe( - '[request body]: investigation_fields: Expected object, received array, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, and 22 more' + '[request body]: investigation_fields: Expected object, received array' ); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/ess.config.ts new file mode 100644 index 000000000000..bbf6c6c0e3f7 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.trial') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine API Integration Tests - ESS - Rule Execution Logic', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/serverless.config.ts new file mode 100644 index 000000000000..7bcb663699d6 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/configs/serverless.config.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine API Integration Tests - Serverless - Rule Execution Logic', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.alertIgnoreFields=${JSON.stringify([ + 'testing_ignored.constant', + '/testing_regex*/', + ])}`, // See tests within the file "ignore_fields.ts" which use these values in "alertIgnoreFields" + ], +}); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/README.md b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/README.md similarity index 100% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/README.md rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/README.md diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/eql.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/eql.ts similarity index 79% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/eql.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/eql.ts index b0469c90d8e4..db5a924b48a0 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/eql.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/eql.ts @@ -11,6 +11,7 @@ import { ALERT_RULE_UUID, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, + ALERT_WORKFLOW_ASSIGNEE_IDS, EVENT_KIND, } from '@kbn/rule-data-utils'; import { flattenWithPrefix } from '@kbn/securitysolution-rules'; @@ -27,35 +28,40 @@ import { ALERT_ORIGINAL_EVENT_CATEGORY, ALERT_GROUP_ID, } from '@kbn/security-solution-plugin/common/field_maps/field_names'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; import { createRule, deleteAllRules, deleteAllAlerts, - getEqlRuleForSignalTesting, - getOpenSignals, + getEqlRuleForAlertTesting, + getOpenAlerts, getPreviewAlerts, previewRule, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const es = getService('es'); const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditPath = dataPathBuilder.getPath('auditbeat/hosts'); - describe('EQL type rules', () => { + describe('@ess @serverless EQL type rules', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.load(auditPath); await esArchiver.load( 'x-pack/test/functional/es_archives/security_solution/timestamp_override_6' ); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.unload(auditPath); await esArchiver.unload( 'x-pack/test/functional/es_archives/security_solution/timestamp_override_6' ); @@ -64,21 +70,21 @@ export default ({ getService }: FtrProviderContext) => { }); // First test creates a real rule - remaining tests use preview API - it('generates a correctly formatted signal from EQL non-sequence queries', async () => { + it('generates a correctly formatted alert from EQL non-sequence queries', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); expect(alerts.hits.hits.length).eql(1); - const fullSignal = alerts.hits.hits[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = alerts.hits.hits[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal).eql({ - ...fullSignal, + expect(fullAlert).eql({ + ...fullAlert, agent: { ephemeral_id: '0010d67a-14f7-41da-be30-489fea735967', hostname: 'suricata-zeek-sensor-toronto', @@ -145,11 +151,12 @@ export default ({ getService }: FtrProviderContext) => { }, }, [ALERT_REASON]: - 'configuration event on suricata-zeek-sensor-toronto created high alert Signal Testing Query.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], + 'configuration event on suricata-zeek-sensor-toronto created high alert Alert Testing Query.', + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], [ALERT_DEPTH]: 1, [ALERT_ANCESTORS]: [ { @@ -167,41 +174,41 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('generates up to max_signals for non-sequence EQL queries', async () => { - const maxSignals = 200; + it('generates up to max_alerts for non-sequence EQL queries', async () => { + const maxAlerts = 200; const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), - max_signals: maxSignals, + ...getEqlRuleForAlertTesting(['auditbeat-*']), + max_signals: maxAlerts, }; const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxSignals * 2 }); - expect(previewAlerts.length).eql(maxSignals); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxAlerts * 2 }); + expect(previewAlerts.length).eql(maxAlerts); }); - it('generates max signals warning when circuit breaker is hit', async () => { + it('generates max alerts warning when circuit breaker is hit', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), }; const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).contain(getMaxSignalsWarning()); + expect(logs[0].warnings).contain(getMaxAlertsWarning()); }); it('uses the provided event_category_override', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'config_change where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', event_category_override: 'auditd.message_type', }; const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); expect(previewAlerts.length).eql(1); - const fullSignal = previewAlerts[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = previewAlerts[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal).eql({ - ...fullSignal, + expect(fullAlert).eql({ + ...fullAlert, auditd: { data: { audit_enabled: '1', @@ -236,9 +243,9 @@ export default ({ getService }: FtrProviderContext) => { }, }, [ALERT_REASON]: - 'configuration event on suricata-zeek-sensor-toronto created high alert Signal Testing Query.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], + 'configuration event on suricata-zeek-sensor-toronto created high alert Alert Testing Query.', + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_DEPTH]: 1, [ALERT_ANCESTORS]: [ @@ -259,7 +266,7 @@ export default ({ getService }: FtrProviderContext) => { it('uses the provided timestamp_field', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['fake.index.1']), + ...getEqlRuleForAlertTesting(['fake.index.1']), query: 'any where true', timestamp_field: 'created_at', }; @@ -273,7 +280,7 @@ export default ({ getService }: FtrProviderContext) => { it('uses the provided tiebreaker_field', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['fake.index.1']), + ...getEqlRuleForAlertTesting(['fake.index.1']), query: 'any where true', tiebreaker_field: 'locale', }; @@ -285,9 +292,9 @@ export default ({ getService }: FtrProviderContext) => { expect(createdAtHits).to.eql(['es', 'pt', 'ua']); }); - it('generates building block signals from EQL sequences in the expected form', async () => { + it('generates building block alerts from EQL sequences in the expected form', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'sequence by host.name [anomoly where true] [any where true]', // TODO: spelling }; const { previewId } = await previewRule({ supertest, rule }); @@ -298,13 +305,13 @@ export default ({ getService }: FtrProviderContext) => { get(alert._source, ALERT_ORIGINAL_EVENT_CATEGORY) === 'anomoly' ); expect(buildingBlock).not.eql(undefined); - const fullSignal = buildingBlock?._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = buildingBlock?._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal).eql({ - ...fullSignal, + expect(fullAlert).eql({ + ...fullAlert, agent: { ephemeral_id: '1b4978a0-48be-49b1-ac96-323425b389ab', hostname: 'zeek-sensor-amsterdam', @@ -409,10 +416,10 @@ export default ({ getService }: FtrProviderContext) => { }, }, [ALERT_REASON]: - 'anomoly event with process bro, by root on zeek-sensor-amsterdam created high alert Signal Testing Query.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], - [ALERT_GROUP_ID]: fullSignal[ALERT_GROUP_ID], - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], + 'anomoly event with process bro, by root on zeek-sensor-amsterdam created high alert Alert Testing Query.', + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_GROUP_ID]: fullAlert[ALERT_GROUP_ID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_DEPTH]: 1, [ALERT_ANCESTORS]: [ @@ -431,9 +438,9 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('generates shell signals from EQL sequences in the expected form', async () => { + it('generates shell alerts from EQL sequences in the expected form', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'sequence by host.name [anomoly where true] [any where true]', }; const { previewId } = await previewRule({ supertest, rule }); @@ -480,7 +487,7 @@ export default ({ getService }: FtrProviderContext) => { [ALERT_DEPTH]: 2, [ALERT_GROUP_ID]: source[ALERT_GROUP_ID], [ALERT_REASON]: - 'event by root on zeek-sensor-amsterdam created high alert Signal Testing Query.', + 'event by root on zeek-sensor-amsterdam created high alert Alert Testing Query.', [ALERT_RULE_UUID]: source[ALERT_RULE_UUID], [ALERT_ANCESTORS]: [ { @@ -513,28 +520,28 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('generates up to max_signals with an EQL rule', async () => { - const maxSignals = 200; + it('generates up to max_alerts with an EQL rule', async () => { + const maxAlerts = 200; const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'sequence by host.name [any where true] [any where true]', - max_signals: maxSignals, + max_signals: maxAlerts, }; const { previewId } = await previewRule({ supertest, rule }); - const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxSignals * 5 }); - // For EQL rules, max_signals is the maximum number of detected sequences: each sequence has a building block - // alert for each event in the sequence, so max_signals=200 results in 400 building blocks in addition to + const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxAlerts * 5 }); + // For EQL rules, max_alerts is the maximum number of detected sequences: each sequence has a building block + // alert for each event in the sequence, so max_alerts=200 results in 400 building blocks in addition to // 200 regular alerts - expect(previewAlerts.length).eql(maxSignals * 3); - const shellSignals = previewAlerts.filter((alert) => alert._source?.[ALERT_DEPTH] === 2); + expect(previewAlerts.length).eql(maxAlerts * 3); + const shellAlerts = previewAlerts.filter((alert) => alert._source?.[ALERT_DEPTH] === 2); const buildingBlocks = previewAlerts.filter((alert) => alert._source?.[ALERT_DEPTH] === 1); - expect(shellSignals.length).eql(maxSignals); - expect(buildingBlocks.length).eql(maxSignals * 2); + expect(shellAlerts.length).eql(maxAlerts); + expect(buildingBlocks.length).eql(maxAlerts * 2); }); - it('generates signals when an index name contains special characters to encode', async () => { + it('generates alerts when an index name contains special characters to encode', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*', '']), + ...getEqlRuleForAlertTesting(['auditbeat-*', '']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; const { previewId } = await previewRule({ supertest, rule }); @@ -544,7 +551,7 @@ export default ({ getService }: FtrProviderContext) => { it('uses the provided filters', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'any where true', filters: [ { @@ -599,18 +606,18 @@ export default ({ getService }: FtrProviderContext) => { it('should be enriched with host risk score', async () => { const rule: EqlRuleCreateProps = { - ...getEqlRuleForSignalTesting(['auditbeat-*']), + ...getEqlRuleForAlertTesting(['auditbeat-*']), query: 'configuration where agent.id=="a1d7b39c-f898-4dbe-a761-efb61939302d"', }; const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); expect(previewAlerts.length).eql(1); - const fullSignal = previewAlerts[0]._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = previewAlerts[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal?.host?.risk?.calculated_level).to.eql('Critical'); - expect(fullSignal?.host?.risk?.calculated_score_norm).to.eql(96); + expect(fullAlert?.host?.risk?.calculated_level).to.eql('Critical'); + expect(fullAlert?.host?.risk?.calculated_score_norm).to.eql(96); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/esql.ts similarity index 96% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/esql.ts index 51db00fc1ed6..cb0f31ad2546 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/esql.ts @@ -13,23 +13,22 @@ import { EsqlRuleCreateProps } from '@kbn/security-solution-plugin/common/api/de import { getCreateEsqlRulesSchemaMock } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema/mocks'; import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; import { deleteAllRules, deleteAllAlerts, getPreviewAlerts, previewRule, createRule, - getOpenSignals as getOpenAlerts, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { previewRuleWithExceptionEntries } from '../../utils/preview_rule_with_exception_entries'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; -import { dataGeneratorFactory } from '../../utils/data_generator'; -import { removeRandomValuedProperties } from './utils'; -import { patchRule } from '../../utils/patch_rule'; - -// eslint-disable-next-line import/no-default-export + getOpenAlerts, + dataGeneratorFactory, + previewRuleWithExceptionEntries, + removeRandomValuedPropertiesFromAlert, + patchRule, +} from '../../../utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -47,7 +46,7 @@ export default ({ getService }: FtrProviderContext) => { */ const internalIdPipe = (id: string) => `| where id=="${id}"`; - describe('ES|QL rule type', () => { + describe('@ess ES|QL rule type', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/security_solution/ecs_compliant'); }); @@ -84,7 +83,7 @@ export default ({ getService }: FtrProviderContext) => { const alerts = await getOpenAlerts(supertest, log, es, createdRule); expect(alerts.hits.hits.length).toBe(1); - expect(removeRandomValuedProperties(alerts.hits.hits[0]._source)).toEqual({ + expect(removeRandomValuedPropertiesFromAlert(alerts.hits.hits[0]._source)).toEqual({ 'kibana.alert.rule.parameters': { description: 'Detecting root and admin users', risk_score: 55, @@ -152,6 +151,7 @@ export default ({ getService }: FtrProviderContext) => { 'kibana.alert.rule.updated_by': 'elastic', 'kibana.alert.rule.version': 1, 'kibana.alert.workflow_tags': [], + 'kibana.alert.workflow_assignee_ids': [], 'kibana.alert.rule.risk_score': 55, 'kibana.alert.rule.severity': 'high', }); @@ -602,8 +602,8 @@ export default ({ getService }: FtrProviderContext) => { }); }); - describe('max signals', () => { - it('generates max signals warning when circuit breaker is exceeded', async () => { + describe('max alerts', () => { + it('generates max alerts warning when circuit breaker is exceeded', async () => { const id = uuidv4(); const rule: EsqlRuleCreateProps = { ...getCreateEsqlRulesSchemaMock('rule-1', true), @@ -629,7 +629,7 @@ export default ({ getService }: FtrProviderContext) => { timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), }); - expect(logs[0].warnings).toEqual(expect.arrayContaining([getMaxSignalsWarning()])); + expect(logs[0].warnings).toEqual(expect.arrayContaining([getMaxAlertsWarning()])); const previewAlerts = await getPreviewAlerts({ es, @@ -640,7 +640,7 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).toBe(100); }); - it("doesn't generate max signals warning when circuit breaker is met but not exceeded", async () => { + it("doesn't generate max alerts warning when circuit breaker is met but not exceeded", async () => { const id = uuidv4(); const rule: EsqlRuleCreateProps = { ...getCreateEsqlRulesSchemaMock('rule-1', true), @@ -665,7 +665,7 @@ export default ({ getService }: FtrProviderContext) => { rule, timeframeEnd: new Date('2020-10-28T06:30:00.000Z'), }); - expect(logs[0].warnings).not.toEqual(expect.arrayContaining([getMaxSignalsWarning()])); + expect(logs[0].warnings).not.toEqual(expect.arrayContaining([getMaxAlertsWarning()])); const previewAlerts = await getPreviewAlerts({ es, @@ -676,7 +676,7 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).toBe(100); }); - it('should work for max signals > 100', async () => { + it('should work for max alerts > 100', async () => { const id = uuidv4(); const rule: EsqlRuleCreateProps = { ...getCreateEsqlRulesSchemaMock('rule-1', true), diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/index.ts new file mode 100644 index 000000000000..36a249304c7e --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Execution logic', function () { + loadTestFile(require.resolve('./eql')); + loadTestFile(require.resolve('./esql')); + loadTestFile(require.resolve('./machine_learning')); + loadTestFile(require.resolve('./new_terms')); + loadTestFile(require.resolve('./saved_query')); + loadTestFile(require.resolve('./threat_match')); + loadTestFile(require.resolve('./threshold')); + loadTestFile(require.resolve('./non_ecs_fields')); + loadTestFile(require.resolve('./query')); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/machine_learning.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/machine_learning.ts similarity index 80% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/machine_learning.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/machine_learning.ts index 792fcb30b664..d58227377f11 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/machine_learning.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/machine_learning.ts @@ -15,6 +15,7 @@ import { ALERT_UUID, ALERT_WORKFLOW_STATUS, ALERT_WORKFLOW_TAGS, + ALERT_WORKFLOW_ASSIGNEE_IDS, SPACE_IDS, VERSION, } from '@kbn/rule-data-utils'; @@ -24,33 +25,38 @@ import { ALERT_DEPTH, ALERT_ORIGINAL_TIME, } from '@kbn/security-solution-plugin/common/field_maps/field_names'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; import { expect } from 'expect'; import { createListsIndex, deleteAllExceptions, deleteListsIndex, importFile, -} from '../../../lists_api_integration/utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +} from '../../../../lists_and_exception_lists/utils'; import { createRule, deleteAllRules, deleteAllAlerts, executeSetupModuleRequest, forceStartDatafeeds, - getOpenSignals, + getOpenAlerts, getPreviewAlerts, previewRule, previewRuleWithExceptionEntries, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const es = getService('es'); const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditPath = dataPathBuilder.getPath('auditbeat/hosts'); const siemModule = 'security_linux_v3'; const mlJobId = 'v3_linux_anomalous_network_activity'; @@ -66,17 +72,18 @@ export default ({ getService }: FtrProviderContext) => { rule_id: 'ml-rule-id', }; - describe('Machine learning type rules', () => { + // FLAKY: https://github.com/elastic/kibana/issues/171426 + describe.skip('@ess @serverless Machine learning type rules', () => { before(async () => { // Order is critical here: auditbeat data must be loaded before attempting to start the ML job, // as the job looks for certain indices on start - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.load(auditPath); await executeSetupModuleRequest({ module: siemModule, rspCode: 200, supertest }); await forceStartDatafeeds({ jobId: mlJobId, rspCode: 200, supertest }); await esArchiver.load('x-pack/test/functional/es_archives/security_solution/anomalies'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.unload(auditPath); await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/anomalies'); await deleteAllAlerts(supertest, log, es); await deleteAllRules(supertest, log); @@ -85,11 +92,11 @@ export default ({ getService }: FtrProviderContext) => { // First test creates a real rule - remaining tests use preview API it('should create 1 alert from ML rule when record meets anomaly_threshold', async () => { const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); expect(alerts.hits.hits.length).toBe(1); - const signal = alerts.hits.hits[0]; + const alert = alerts.hits.hits[0]; - expect(signal._source).toEqual( + expect(alert._source).toEqual( expect.objectContaining({ '@timestamp': expect.any(String), [ALERT_RULE_EXECUTION_UUID]: expect.any(String), @@ -119,6 +126,7 @@ export default ({ getService }: FtrProviderContext) => { [ALERT_ANCESTORS]: expect.any(Array), [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], [ALERT_STATUS]: 'active', [SPACE_IDS]: ['default'], [ALERT_SEVERITY]: 'critical', @@ -160,23 +168,23 @@ export default ({ getService }: FtrProviderContext) => { ); }); - it('generates max signals warning when circuit breaker is exceeded', async () => { + it('@skipInQA generates max alerts warning when circuit breaker is exceeded', async () => { const { logs } = await previewRule({ supertest, rule: { ...rule, anomaly_threshold: 1, max_signals: 5 }, // This threshold generates 10 alerts with the current esArchive }); - expect(logs[0].warnings).toContain(getMaxSignalsWarning()); + expect(logs[0].warnings).toContain(getMaxAlertsWarning()); }); - it("doesn't generate max signals warning when circuit breaker is met, but not exceeded", async () => { + it("doesn't generate max alerts warning when circuit breaker is met, but not exceeded", async () => { const { logs } = await previewRule({ supertest, rule: { ...rule, anomaly_threshold: 1, max_signals: 10 }, }); - expect(logs[0].warnings).not.toContain(getMaxSignalsWarning()); + expect(logs[0].warnings).not.toContain(getMaxAlertsWarning()); }); - it('should create 7 alerts from ML rule when records meet anomaly_threshold', async () => { + it('@skipInQA should create 7 alerts from ML rule when records meet anomaly_threshold', async () => { const { previewId } = await previewRule({ supertest, rule: { ...rule, anomaly_threshold: 20 }, @@ -189,7 +197,7 @@ export default ({ getService }: FtrProviderContext) => { afterEach(async () => { await deleteAllExceptions(supertest, log); }); - it('generates no signals when an exception is added for an ML rule', async () => { + it('generates no alerts when an exception is added for an ML rule', async () => { const { previewId } = await previewRuleWithExceptionEntries({ supertest, log, @@ -220,7 +228,7 @@ export default ({ getService }: FtrProviderContext) => { await deleteAllExceptions(supertest, log); }); - it('generates no signals when a value list exception is added for an ML rule', async () => { + it('generates no alerts when a value list exception is added for an ML rule', async () => { const valueListId = 'value-list-id'; await importFile(supertest, log, 'keyword', ['mothra'], valueListId); const { previewId } = await previewRuleWithExceptionEntries({ @@ -255,14 +263,14 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.unload('x-pack/test/functional/es_archives/entity/risks'); }); - it('should be enriched with host risk score', async () => { + it('@skipInQA should be enriched with host risk score', async () => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); expect(previewAlerts.length).toBe(1); - const fullSignal = previewAlerts[0]._source; + const fullAlert = previewAlerts[0]._source; - expect(fullSignal?.host?.risk?.calculated_level).toBe('Low'); - expect(fullSignal?.host?.risk?.calculated_score_norm).toBe(1); + expect(fullAlert?.host?.risk?.calculated_level).toBe('Low'); + expect(fullAlert?.host?.risk?.calculated_score_norm).toBe(1); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/new_terms.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/new_terms.ts new file mode 100644 index 000000000000..8a47aeaa89bd --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/new_terms.ts @@ -0,0 +1,1044 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { v4 as uuidv4 } from 'uuid'; + +import { NewTermsRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { orderBy } from 'lodash'; +import { getCreateNewTermsRulesSchemaMock } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema/mocks'; + +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { + createRule, + deleteAllRules, + deleteAllAlerts, + getOpenAlerts, + getPreviewAlerts, + previewRule, + dataGeneratorFactory, + previewRuleWithExceptionEntries, + removeRandomValuedPropertiesFromAlert, +} from '../../../utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +const historicalWindowStart = '2022-10-13T05:00:04.000Z'; +const ruleExecutionStart = '2022-10-19T05:00:04.000Z'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + const { indexEnhancedDocuments } = dataGeneratorFactory({ + es, + index: 'new_terms', + log, + }); + // TODO: add a new service + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + /** + * indexes 2 sets of documents: + * - documents in historical window + * - documents in rule execution window + * @returns id of documents + */ + const newTermsTestExecutionSetup = async ({ + historicalDocuments, + ruleExecutionDocuments, + }: { + historicalDocuments: Array>; + ruleExecutionDocuments: Array>; + }) => { + const testId = uuidv4(); + + await indexEnhancedDocuments({ + interval: [historicalWindowStart, ruleExecutionStart], + id: testId, + documents: historicalDocuments, + }); + + await indexEnhancedDocuments({ + id: testId, + documents: ruleExecutionDocuments, + }); + + return testId; + }; + + describe('@ess @serverless New terms type rules', () => { + before(async () => { + await esArchiver.load(path); + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/new_terms'); + }); + + after(async () => { + await esArchiver.unload(path); + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/new_terms'); + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + // First test creates a real rule - remaining tests use preview API + + // This test also tests that alerts are NOT created for terms that are not new: the host name + // suricata-sensor-san-francisco appears in a document at 2019-02-19T20:42:08.230Z, but also appears + // in earlier documents so is not new. An alert should not be generated for that term. + it('should generate 1 alert with 1 selected field', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.name'], + from: '2019-02-19T20:42:00.000Z', + history_window_start: '2019-01-19T20:42:00.000Z', + }; + + const createdRule = await createRule(supertest, log, rule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); + + expect(alerts.hits.hits.length).eql(1); + expect(removeRandomValuedPropertiesFromAlert(alerts.hits.hits[0]._source)).eql({ + 'kibana.alert.new_terms': ['zeek-newyork-sha-aa8df15'], + 'kibana.alert.rule.category': 'New Terms Rule', + 'kibana.alert.rule.consumer': 'siem', + 'kibana.alert.rule.name': 'Query with a rule id', + 'kibana.alert.rule.producer': 'siem', + 'kibana.alert.rule.rule_type_id': 'siem.newTermsRule', + 'kibana.space_ids': ['default'], + 'kibana.alert.rule.tags': [], + agent: { + ephemeral_id: '7cc2091a-72f1-4c63-843b-fdeb622f9c69', + hostname: 'zeek-newyork-sha-aa8df15', + id: '4b4462ef-93d2-409c-87a6-299d942e5047', + type: 'auditbeat', + version: '8.0.0', + }, + cloud: { instance: { id: '139865230' }, provider: 'digitalocean', region: 'nyc1' }, + ecs: { version: '1.0.0-beta2' }, + host: { + architecture: 'x86_64', + hostname: 'zeek-newyork-sha-aa8df15', + id: '3729d06ce9964aa98549f41cbd99334d', + ip: ['157.230.208.30', '10.10.0.6', 'fe80::24ce:f7ff:fede:a571'], + mac: ['26:ce:f7:de:a5:71'], + name: 'zeek-newyork-sha-aa8df15', + os: { + codename: 'cosmic', + family: 'debian', + kernel: '4.18.0-10-generic', + name: 'Ubuntu', + platform: 'ubuntu', + version: '18.10 (Cosmic Cuttlefish)', + }, + }, + message: + 'Login by user root (UID: 0) on pts/0 (PID: 20638) from 8.42.77.171 (IP: 8.42.77.171)', + process: { pid: 20638 }, + service: { type: 'system' }, + source: { ip: '8.42.77.171' }, + user: { id: 0, name: 'root', terminal: 'pts/0' }, + 'event.action': 'user_login', + 'event.category': 'authentication', + 'event.dataset': 'login', + 'event.kind': 'signal', + 'event.module': 'system', + 'event.origin': '/var/log/wtmp', + 'event.outcome': 'success', + 'event.type': 'authentication_success', + 'kibana.alert.original_time': '2019-02-19T20:42:08.230Z', + 'kibana.alert.ancestors': [ + { + id: 'x07wJ2oB9v5HJNSHhyxi', + type: 'event', + index: 'auditbeat-8.0.0-2019.02.19-000001', + depth: 0, + }, + ], + 'kibana.alert.status': 'active', + 'kibana.alert.workflow_status': 'open', + 'kibana.alert.workflow_tags': [], + 'kibana.alert.workflow_assignee_ids': [], + 'kibana.alert.depth': 1, + 'kibana.alert.reason': + 'authentication event with source 8.42.77.171 by root on zeek-newyork-sha-aa8df15 created high alert Query with a rule id.', + 'kibana.alert.severity': 'high', + 'kibana.alert.risk_score': 55, + 'kibana.alert.rule.parameters': { + description: 'Detecting root and admin users', + risk_score: 55, + severity: 'high', + author: [], + false_positives: [], + from: '2019-02-19T20:42:00.000Z', + rule_id: 'rule-1', + max_signals: 100, + risk_score_mapping: [], + severity_mapping: [], + threat: [], + to: 'now', + references: [], + version: 1, + exceptions_list: [], + immutable: false, + related_integrations: [], + required_fields: [], + setup: '', + type: 'new_terms', + query: '*', + new_terms_fields: ['host.name'], + history_window_start: '2019-01-19T20:42:00.000Z', + index: ['auditbeat-*'], + language: 'kuery', + }, + 'kibana.alert.rule.actions': [], + 'kibana.alert.rule.author': [], + 'kibana.alert.rule.created_by': ELASTICSEARCH_USERNAME, + 'kibana.alert.rule.description': 'Detecting root and admin users', + 'kibana.alert.rule.enabled': true, + 'kibana.alert.rule.exceptions_list': [], + 'kibana.alert.rule.false_positives': [], + 'kibana.alert.rule.from': '2019-02-19T20:42:00.000Z', + 'kibana.alert.rule.immutable': false, + 'kibana.alert.rule.indices': ['auditbeat-*'], + 'kibana.alert.rule.interval': '5m', + 'kibana.alert.rule.max_signals': 100, + 'kibana.alert.rule.references': [], + 'kibana.alert.rule.revision': 0, + 'kibana.alert.rule.risk_score_mapping': [], + 'kibana.alert.rule.rule_id': 'rule-1', + 'kibana.alert.rule.severity_mapping': [], + 'kibana.alert.rule.threat': [], + 'kibana.alert.rule.to': 'now', + 'kibana.alert.rule.type': 'new_terms', + 'kibana.alert.rule.updated_by': ELASTICSEARCH_USERNAME, + 'kibana.alert.rule.version': 1, + 'kibana.alert.rule.risk_score': 55, + 'kibana.alert.rule.severity': 'high', + 'kibana.alert.original_event.action': 'user_login', + 'kibana.alert.original_event.category': 'authentication', + 'kibana.alert.original_event.dataset': 'login', + 'kibana.alert.original_event.kind': 'event', + 'kibana.alert.original_event.module': 'system', + 'kibana.alert.original_event.origin': '/var/log/wtmp', + 'kibana.alert.original_event.outcome': 'success', + 'kibana.alert.original_event.type': 'authentication_success', + }); + }); + + it('generates max alerts warning when circuit breaker is exceeded', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['process.pid'], + from: '2018-02-19T20:42:00.000Z', + // Set the history_window_start close to 'from' so we should alert on all terms in the time range + history_window_start: '2018-02-19T20:41:59.000Z', + }; + const { logs } = await previewRule({ supertest, rule }); + + expect(logs[0].warnings).contain(getMaxAlertsWarning()); + }); + + it("doesn't generate max alerts warning when circuit breaker is met but not exceeded", async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.ip'], + from: '2019-02-19T20:42:00.000Z', + history_window_start: '2019-01-19T20:42:00.000Z', + max_signals: 3, + }; + const { logs } = await previewRule({ supertest, rule }); + + expect(logs[0].warnings).not.contain(getMaxAlertsWarning()); + }); + + it('should generate 3 alerts when 1 document has 3 new values', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.ip'], + from: '2019-02-19T20:42:00.000Z', + history_window_start: '2019-01-19T20:42:00.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(3); + const previewAlertsOrderedByHostIp = orderBy( + previewAlerts, + '_source.kibana.alert.new_terms', + 'asc' + ); + expect(previewAlertsOrderedByHostIp[0]._source?.['kibana.alert.new_terms']).eql([ + '10.10.0.6', + ]); + expect(previewAlertsOrderedByHostIp[1]._source?.['kibana.alert.new_terms']).eql([ + '157.230.208.30', + ]); + expect(previewAlertsOrderedByHostIp[2]._source?.['kibana.alert.new_terms']).eql([ + 'fe80::24ce:f7ff:fede:a571', + ]); + }); + + it('should generate 3 alerts when 1 document has 3 new values for multiple fields', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.name', 'host.ip'], + from: '2019-02-19T20:42:00.000Z', + history_window_start: '2019-01-19T20:42:00.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(3); + + const newTerms = orderBy( + previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), + ['0', '1'] + ); + + expect(newTerms).eql([ + ['zeek-newyork-sha-aa8df15', '10.10.0.6'], + ['zeek-newyork-sha-aa8df15', '157.230.208.30'], + ['zeek-newyork-sha-aa8df15', 'fe80::24ce:f7ff:fede:a571'], + ]); + }); + + it('should generate 1 alert for unique combination of existing terms', async () => { + // historical window documents + const historicalDocuments = [ + { + host: { name: 'host-0', ip: '127.0.0.1' }, + }, + { + host: { name: 'host-1', ip: '127.0.0.2' }, + }, + ]; + + // rule execution documents + const ruleExecutionDocuments = [ + { + host: { name: 'host-0', ip: '127.0.0.2' }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + // ensure there are no alerts for single new terms fields, it means values are not new + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.ip'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + // shouldn't be terms for 'host.ip' + const hostIpPreview = await previewRule({ + supertest, + rule: { ...rule, new_terms_fields: ['host.ip'] }, + }); + const hostIpPreviewAlerts = await getPreviewAlerts({ + es, + previewId: hostIpPreview.previewId, + }); + expect(hostIpPreviewAlerts.length).eql(0); + + // shouldn't be terms for 'host.name' + const hostNamePreview = await previewRule({ + supertest, + rule: { ...rule, new_terms_fields: ['host.name'] }, + }); + const hostNamePreviewAlerts = await getPreviewAlerts({ + es, + previewId: hostNamePreview.previewId, + }); + expect(hostNamePreviewAlerts.length).eql(0); + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(1); + + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); + }); + + it('should generate 5 alerts, 1 for each new unique combination in 2 fields', async () => { + const historicalDocuments = [ + { + 'source.ip': ['192.168.1.1'], + tags: ['tag-1', 'tag-2'], + }, + { + 'source.ip': ['192.168.1.1'], + tags: ['tag-1'], + }, + ]; + + const ruleExecutionDocuments = [ + { + 'source.ip': ['192.168.1.1', '192.168.1.2'], + tags: ['tag-new-1', 'tag-2', 'tag-new-3'], + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['source.ip', 'tags'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(5); + + const newTerms = orderBy( + previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), + ['0', '1'] + ); + + expect(newTerms).eql([ + ['192.168.1.1', 'tag-new-1'], + ['192.168.1.1', 'tag-new-3'], + ['192.168.1.2', 'tag-2'], + ['192.168.1.2', 'tag-new-1'], + ['192.168.1.2', 'tag-new-3'], + ]); + }); + + it('should generate 1 alert for unique combination of terms, one of which is a number', async () => { + const historicalDocuments = [ + { user: { name: 'user-0', id: 0 } }, + { user: { name: 'user-1', id: 1 } }, + ]; + const ruleExecutionDocuments = [{ user: { name: 'user-0', id: 1 } }]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['user.name', 'user.id'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(1); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', '1']); + }); + + it('should generate 1 alert for unique combination of terms, one of which is a boolean', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['user.name', 'user.enabled'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(1); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', false]); + }); + + it('should generate alerts for every term when history window is small', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.name'], + from: '2019-02-19T20:42:00.000Z', + // Set the history_window_start close to 'from' so we should alert on all terms in the time range + history_window_start: '2019-02-19T20:41:59.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(5); + const hostNames = previewAlerts + .map((signal) => signal._source?.['kibana.alert.new_terms']) + .sort(); + expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); + expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); + expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); + expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); + expect(hostNames[4]).eql(['zeek-sensor-san-francisco']); + }); + + // github.com/elastic/kibana/issues/149920 + it('should generate 1 alert for new terms if query has wildcard in field path', async () => { + // historical window documents + const historicalDocuments = [ + { + host: { name: 'host-0', ip: '127.0.0.1' }, + }, + { + host: { name: 'host-1', ip: '127.0.0.2' }, + }, + ]; + + // rule execution documents + const ruleExecutionDocuments = [ + { + host: { name: 'host-0', ip: '127.0.0.2' }, + }, + { + host: { name: 'host-1', ip: '127.0.0.1' }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.ip'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}" and host.n*: host-0`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(1); + + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); + }); + describe('null values', () => { + it('should not generate alerts with null values for single field', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['possibly_null_field'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(0); + }); + + it('should not generate alerts with null values for multiple fields', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['possibly_null_field', 'host.name'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(0); + }); + }); + + describe('large arrays values', () => { + it('should generate alerts for unique values in large array for single field from a single document', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['large_array_20'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 100 }); + + expect(previewAlerts.length).eql(20); + }); + + // There is a limit in ES for a number of emitted values in runtime field (100) + // This test ensures rule run doesn't fail if processed fields in runtime script generates 100 values, hard limit for ES + // For this test case: large_array_10 & large_array_5 have 100 unique combination in total + it('should generate alerts for array fields that have 100 unique combination of values in runtime field', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['large_array_10', 'large_array_5'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + expect(previewAlerts.length).eql(100); + }); + + // There is a limit in ES for a number of emitted values in runtime field (100) + // This test ensures rule run doesn't fail if processed fields in runtime script generates 200 values + // In case of this test case: large_array_10 & large_array_20 have 200 unique combination in total + // Rule run should not fail and should generate alerts + it('should generate alert for array fields that have more than 200 unique combination of values in runtime field', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['large_array_10', 'large_array_20'], + from: '2020-10-19T05:00:04.000Z', + history_window_start: '2020-10-13T05:00:04.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + expect(previewAlerts.length).eql(100); + }); + + it('should not miss alerts if rule execution value combinations number is greater than 100', async () => { + // historical window documents + // 100 combinations for 127.0.0.1 x host-0, host-1, ..., host-100 + const historicalDocuments = [ + { + host: { + name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + ip: ['127.0.0.1'], + }, + }, + ]; + + // rule execution documents + // 100 old combinations for 127.0.0.1 x host-0, host-1, ..., host-99 + // 10 new combinations 127.0.0.1 x a-0, a-1, ..., a-9 + const ruleExecutionDocuments = [ + { + host: { + name: [ + ...Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + ...Array.from(Array(10)).map((_, i) => `a-${i}`), + ], + ip: ['127.0.0.1'], + }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.ip'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + // 10 alerts (with host.names a-[0-9]) should be generated + expect(previewAlerts.length).eql(10); + }); + + it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size', async () => { + // historical window documents + // number of combinations is 50,000 + const historicalDocuments = [ + { + host: { + name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + user: { + name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), + }, + }, + ]; + + // rule execution documents + // number of combinations is 50,000 + new one + const ruleExecutionDocuments = [ + { + host: { + name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + user: { + name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), + }, + }, + { + host: { + name: 'host-140', + domain: 'domain-9999', + }, + user: { + name: 'user-9999', + }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.domain', 'user.name'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + // only 1 alert should be generated + expect(previewAlerts.length).eql(1); + }); + + it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size spread over multiple pages', async () => { + // historical window documents + // number of combinations is 50,000 + const historicalDocuments = [ + { + host: { + name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + user: { + name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), + }, + }, + ]; + + // rule execution documents + // number of combinations is 50,000 + 4 new ones + const ruleExecutionDocuments = [ + { + host: { + name: Array.from(Array(100)).map((_, i) => `host-${100 + i}`), + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + user: { + name: Array.from(Array(5)).map((_, i) => `user-${100 + i}`), + }, + }, + { + host: { + name: 'host-102', + domain: 'domain-9999', + }, + user: { + name: 'user-9999', + }, + }, + { + host: { + name: 'host-140', + domain: 'domain-9999', + }, + user: { + name: 'user-9999', + }, + }, + { + host: { + name: 'host-133', + domain: 'domain-9999', + }, + user: { + name: 'user-9999', + }, + }, + { + host: { + name: 'host-132', + domain: 'domain-9999', + }, + user: { + name: 'user-9999', + }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.domain', 'user.name'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + // only 4 alerts should be generated + expect(previewAlerts.length).eql(4); + }); + + it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have more than 100', async () => { + // historical window documents + // number of combinations 400: [a, b] x domain-100, domain-101, ..., domain-299 + const historicalDocuments = [ + { + host: { + name: ['a', 'b'], + domain: Array.from(Array(200)).map((_, i) => `domain-${100 + i}`), + }, + }, + ]; + + // rule execution documents + // number of combinations 101: [a] x domain-100, domain-101, ..., domain-199 + b x domain-201 + // no new combination of values emitted + const ruleExecutionDocuments = [ + { + host: { + name: 'a', + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + }, + { + host: { + name: 'b', + domain: 'domain-201', + }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.domain'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + expect(previewAlerts.length).eql(0); + }); + + it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have precisely 100', async () => { + // historical window documents + // number of combinations 400: [a, b] x domain-100, domain-101, ..., domain-299 + const historicalDocuments = [ + { + host: { + name: ['a', 'b'], + domain: Array.from(Array(200)).map((_, i) => `domain-${100 + i}`), + }, + }, + ]; + + // rule execution documents + // number of combinations 100: [a] x domain-100, domain-101, ..., domain-199 + // no new combination of values emitted + const ruleExecutionDocuments = [ + { + host: { + name: 'a', + domain: Array.from(Array(100)).map((_, i) => `domain-${100 + i}`), + }, + }, + ]; + + const testId = await newTermsTestExecutionSetup({ + historicalDocuments, + ruleExecutionDocuments, + }); + + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + index: ['new_terms'], + new_terms_fields: ['host.name', 'host.domain'], + from: ruleExecutionStart, + history_window_start: historicalWindowStart, + query: `id: "${testId}"`, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); + + expect(previewAlerts.length).eql(0); + }); + }); + + describe('timestamp override and fallback', () => { + before(async () => { + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' + ); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' + ); + }); + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' + ); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' + ); + }); + + it('should generate the correct alerts', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + // myfakeindex-3 does not have event.ingested mapped so we can test if the runtime field + // 'kibana.combined_timestamp' handles unmapped fields properly + index: ['timestamp-fallback-test', 'myfakeindex-3'], + new_terms_fields: ['host.name'], + from: '2020-12-16T16:00:00.000Z', + // Set the history_window_start close to 'from' so we should alert on all terms in the time range + history_window_start: '2020-12-16T15:59:00.000Z', + timestamp_override: 'event.ingested', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(2); + const hostNames = previewAlerts + .map((signal) => signal._source?.['kibana.alert.new_terms']) + .sort(); + expect(hostNames[0]).eql(['host-3']); + expect(hostNames[1]).eql(['host-4']); + }); + }); + + describe('with exceptions', async () => { + afterEach(async () => { + await deleteAllExceptions(supertest, log); + }); + + it('should apply exceptions', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.name'], + from: '2019-02-19T20:42:00.000Z', + // Set the history_window_start close to 'from' so we should alert on all terms in the time range + history_window_start: '2019-02-19T20:41:59.000Z', + }; + + const { previewId } = await previewRuleWithExceptionEntries({ + supertest, + log, + rule, + entries: [ + [ + { + field: 'host.name', + operator: 'included', + type: 'match', + value: 'zeek-sensor-san-francisco', + }, + ], + ], + }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts.length).eql(4); + const hostNames = previewAlerts + .map((signal) => signal._source?.['kibana.alert.new_terms']) + .sort(); + expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); + expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); + expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); + expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); + }); + }); + + it('should work for max alerts > 100', async () => { + const maxAlerts = 200; + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['process.pid'], + from: '2018-02-19T20:42:00.000Z', + // Set the history_window_start close to 'from' so we should alert on all terms in the time range + history_window_start: '2018-02-19T20:41:59.000Z', + max_signals: maxAlerts, + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxAlerts * 2 }); + + expect(previewAlerts.length).eql(maxAlerts); + const processPids = previewAlerts + .map((signal) => signal._source?.['kibana.alert.new_terms']) + .sort(); + expect(processPids[0]).eql([1]); + }); + + describe('alerts should be be enriched', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/entity/risks'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/entity/risks'); + }); + + it('should be enriched with host risk score', async () => { + const rule: NewTermsRuleCreateProps = { + ...getCreateNewTermsRulesSchemaMock('rule-1', true), + new_terms_fields: ['host.name'], + from: '2019-02-19T20:42:00.000Z', + history_window_start: '2019-01-19T20:42:00.000Z', + }; + + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + + expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).to.eql('Low'); + expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).to.eql(23); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/non_ecs_fields.ts similarity index 96% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/non_ecs_fields.ts index 20d2f8e1dc57..e452ffcfaf34 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/non_ecs_fields.ts @@ -10,18 +10,18 @@ import { deleteAllRules, deleteAllAlerts, getPreviewAlerts, - getRuleForSignalTesting, + getRuleForAlertTesting, previewRule, -} from '../../utils'; -import { dataGeneratorFactory, enhanceDocument } from '../../utils/data_generator'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; + dataGeneratorFactory, + enhanceDocument, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; const getQueryRule = (docIdToQuery: string) => ({ - ...getRuleForSignalTesting(['ecs_non_compliant']), + ...getRuleForAlertTesting(['ecs_non_compliant']), query: `id: "${docIdToQuery}"`, }); -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -56,7 +56,7 @@ export default ({ getService }: FtrProviderContext) => { }; }; - describe('Non ECS fields in alert document source', () => { + describe('@ess @serverless Non ECS fields in alert document source', () => { before(async () => { await esArchiver.load( 'x-pack/test/functional/es_archives/security_solution/ecs_non_compliant' diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/query.ts similarity index 92% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/query.ts index 4c38edaf0cd2..19c02fe389fe 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/query.ts @@ -42,29 +42,32 @@ import { import { DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_URL, - DETECTION_ENGINE_SIGNALS_STATUS_URL, + DETECTION_ENGINE_SIGNALS_STATUS_URL as DETECTION_ENGINE_ALERTS_STATUS_URL, } from '@kbn/security-solution-plugin/common/constants'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; -import { deleteAllExceptions } from '../../../lists_api_integration/utils'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import moment from 'moment'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; import { createExceptionList, createExceptionListItem, createRule, deleteAllRules, deleteAllAlerts, - getOpenSignals, + getOpenAlerts, getPreviewAlerts, - getRuleForSignalTesting, + getRuleForAlertTesting, getSimpleRule, previewRule, - setSignalStatus, + setAlertStatus, getRuleSOById, + patchRule, createRuleThroughAlertingEndpoint, getRuleSavedObjectWithLegacyInvestigationFields, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { dataGeneratorFactory } from '../../utils/data_generator'; -import { patchRule } from '../../utils/patch_rule'; + dataGeneratorFactory, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; /** * Specific _id to use for some of the tests. If the archiver changes and you see errors @@ -75,22 +78,29 @@ const ID = 'BhbXBmkBR346wHgn4PeZ'; /** * Test coverage: * [x] - Happy path generating 1 alert - * [x] - Rule type respects max signals + * [x] - Rule type respects max alerts * [x] - Alerts on alerts */ -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const es = getService('es'); const log = getService('log'); const esDeleteAllIndices = getService('esDeleteAllIndices'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const auditbeatPath = dataPathBuilder.getPath('auditbeat/hosts'); - describe('Query type rules', () => { + describe('@ess @serverless Query type rules', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); - await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/8.1.0'); + await esArchiver.load(auditbeatPath); + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/8.8.0', { + useCreate: true, + docsOnly: true, + }); await esArchiver.load('x-pack/test/functional/es_archives/signals/severity_risk_overrides'); }); @@ -99,8 +109,7 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); - await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/alerts/8.1.0'); + await esArchiver.unload(auditbeatPath); await esArchiver.unload('x-pack/test/functional/es_archives/signals/severity_risk_overrides'); await deleteAllAlerts(supertest, log, es, ['.preview.alerts-security.alerts-*']); await deleteAllRules(supertest, log); @@ -109,48 +118,48 @@ export default ({ getService }: FtrProviderContext) => { // First test creates a real rule - most remaining tests use preview API it('should have the specific audit record for _id or none of these tests below will pass', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); expect(alerts.hits.hits.length).greaterThan(0); expect(alerts.hits.hits[0]._source?.['kibana.alert.ancestors'][0].id).eql(ID); }); - it('generates max signals warning when circuit breaker is hit', async () => { + it('generates max alerts warning when circuit breaker is hit', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), }; const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).contain(getMaxSignalsWarning()); + expect(logs[0].warnings).contain(getMaxAlertsWarning()); }); - it("doesn't generate max signals warning when circuit breaker is met but not exceeded", async () => { + it("doesn't generate max alerts warning when circuit breaker is met but not exceeded", async () => { const rule = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: 'process.executable: "/usr/bin/sudo"', max_signals: 10, }; const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).not.contain(getMaxSignalsWarning()); + expect(logs[0].warnings).not.contain(getMaxAlertsWarning()); }); it('should abide by max_signals > 100', async () => { - const maxSignals = 200; + const maxAlerts = 200; const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), - max_signals: maxSignals, + ...getRuleForAlertTesting(['auditbeat-*']), + max_signals: maxAlerts, }; const { previewId } = await previewRule({ supertest, rule }); // Search for 2x max_signals to make sure we aren't making more than max_signals - const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxSignals * 2 }); - expect(previewAlerts.length).equal(maxSignals); + const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxAlerts * 2 }); + expect(previewAlerts.length).equal(maxAlerts); }); - it('should have recorded the rule_id within the signal', async () => { + it('should have recorded the rule_id within the alert', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; const { previewId } = await previewRule({ supertest, rule }); @@ -158,17 +167,17 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts[0]._source?.[ALERT_RULE_RULE_ID]).eql(getSimpleRule().rule_id); }); - it('should query and get back expected signal structure using a basic KQL query', async () => { + it('should query and get back expected alert structure using a basic KQL query', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - const signal = previewAlerts[0]._source; + const alert = previewAlerts[0]._source; - expect(signal).eql({ - ...signal, + expect(alert).eql({ + ...alert, [ALERT_ANCESTORS]: [ { id: 'BhbXBmkBR346wHgn4PeZ', @@ -189,11 +198,11 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should query and get back expected signal structure when it is a signal on a signal', async () => { - const alertId = '30a75fe46d3dbdfab55982036f77a8d60e2d1112e96f277c3b8c22f9bb57817a'; + it('should query and get back expected alert structure when it is a alert on a alert', async () => { + const alertId = 'eabbdefc23da981f2b74ab58b82622a97bb9878caa11bc914e2adfacc94780f1'; const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting([`.alerts-security.alerts-default*`]), - rule_id: 'signal-on-signal', + ...getRuleForAlertTesting([`.alerts-security.alerts-default*`]), + rule_id: 'alert-on-alert', query: `_id:${alertId}`, }; @@ -202,43 +211,44 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).to.eql(1); - const signal = previewAlerts[0]._source; + const alert = previewAlerts[0]._source; - if (!signal) { - return expect(signal).to.be.ok(); + if (!alert) { + return expect(alert).to.be.ok(); } - - expect(signal).eql({ - ...signal, - [ALERT_ANCESTORS]: [ - { - id: 'ahEToH8BK09aFtXZFVMq', - type: 'event', - index: 'events-index-000001', - depth: 0, - }, - { - rule: '031d5c00-a72f-11ec-a8a3-7b1c8077fc3e', - id: '30a75fe46d3dbdfab55982036f77a8d60e2d1112e96f277c3b8c22f9bb57817a', - type: 'signal', - index: '.internal.alerts-security.alerts-default-000001', - depth: 1, - }, - ], - [ALERT_WORKFLOW_STATUS]: 'open', - [ALERT_DEPTH]: 2, - [ALERT_ORIGINAL_TIME]: '2022-03-19T02:48:12.634Z', - ...flattenWithPrefix(ALERT_ORIGINAL_EVENT, { - agent_id_status: 'verified', - ingested: '2022-03-19T02:47:57.376Z', - dataset: 'elastic_agent.filebeat', - }), - }); + const date = moment(); + const formattedDate = date.format('YYYY.MM.DD'); + const alertAncestorIndex = isServerless + ? `.ds-.alerts-security.alerts-default-${formattedDate}-000001` + : '.internal.alerts-security.alerts-default-000001'; + expect(alert[ALERT_ANCESTORS]).eql([ + { + id: 'vT9cwocBh3b8EMpD8lsi', + type: 'event', + index: '.ds-logs-endpoint.alerts-default-2023.04.27-000001', + depth: 0, + }, + { + rule: '7015a3e2-e4ea-11ed-8c11-49608884878f', + id: alertId, + type: 'signal', + index: alertAncestorIndex, + depth: 1, + }, + ]); + expect(alert[ALERT_WORKFLOW_STATUS]).eql('open'); + expect(alert[ALERT_DEPTH]).eql(2); + + expect(alert[ALERT_ORIGINAL_TIME]).eql('2023-04-27T11:03:57.906Z'); + expect(alert[`${ALERT_ORIGINAL_EVENT}.agent_id_status`]).eql('auth_metadata_missing'); + expect(alert[`${ALERT_ORIGINAL_EVENT}.ingested`]).eql('2023-04-27T10:58:03Z'); + expect(alert[`${ALERT_ORIGINAL_EVENT}.dataset`]).eql('endpoint'); + expect(alert[`${ALERT_ORIGINAL_EVENT}.ingested`]).eql('2023-04-27T10:58:03Z'); }); it('should not have risk score fields without risk indices', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; const { previewId } = await previewRule({ supertest, rule }); @@ -258,7 +268,7 @@ export default ({ getService }: FtrProviderContext) => { it('should have host and user risk score fields', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; const { previewId } = await previewRule({ supertest, rule }); @@ -273,11 +283,11 @@ export default ({ getService }: FtrProviderContext) => { /** * Here we test the functionality of Severity and Risk Score overrides (also called "mappings" * in the code). If the rule specifies a mapping, then the final Severity or Risk Score - * value of the signal will be taken from the mapped field of the source event. + * value of the alert will be taken from the mapped field of the source event. */ it('should get default severity and risk score if there is no mapping', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['signal_overrides']), + ...getRuleForAlertTesting(['signal_overrides']), severity: 'medium', risk_score: 75, }; @@ -297,7 +307,7 @@ export default ({ getService }: FtrProviderContext) => { it('should get overridden severity if the rule has a mapping for it', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['signal_overrides']), + ...getRuleForAlertTesting(['signal_overrides']), severity: 'medium', severity_mapping: [ { field: 'my_severity', operator: 'equals', value: 'sev_900', severity: 'high' }, @@ -334,7 +344,7 @@ export default ({ getService }: FtrProviderContext) => { it('should get overridden risk score if the rule has a mapping for it', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['signal_overrides']), + ...getRuleForAlertTesting(['signal_overrides']), severity: 'medium', risk_score: 75, risk_score_mapping: [ @@ -369,7 +379,7 @@ export default ({ getService }: FtrProviderContext) => { it('should get overridden severity and risk score if the rule has both mappings', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['signal_overrides']), + ...getRuleForAlertTesting(['signal_overrides']), severity: 'medium', severity_mapping: [ { field: 'my_severity', operator: 'equals', value: 'sev_900', severity: 'high' }, @@ -409,26 +419,26 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should generate signals with name_override field', async () => { + it('should generate alerts with name_override field', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `event.action:boot`, rule_name_override: 'event.action', }; const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - const fullSignal = previewAlerts[0]; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = previewAlerts[0]; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } expect(previewAlerts[0]._source?.['kibana.alert.rule.name']).to.eql('boot'); }); - it('should not generate duplicate signals', async () => { + it('should not generate duplicate alerts', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID}`, }; @@ -448,7 +458,7 @@ export default ({ getService }: FtrProviderContext) => { it('should generate only 1 alert per host name when grouping by host name', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: "host-0"`, alert_suppression: { group_by: ['host.name'], @@ -481,7 +491,7 @@ export default ({ getService }: FtrProviderContext) => { it('should generate multiple alerts when multiple host names are found', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: *`, alert_suppression: { group_by: ['host.name'], @@ -521,7 +531,7 @@ export default ({ getService }: FtrProviderContext) => { it('should generate alerts when using multiple group by fields', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: *`, alert_suppression: { group_by: ['host.name', 'source.ip'], @@ -564,7 +574,7 @@ export default ({ getService }: FtrProviderContext) => { it('should not count documents that were covered by previous alerts', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: *`, alert_suppression: { group_by: ['host.name', 'source.ip'], @@ -632,7 +642,7 @@ export default ({ getService }: FtrProviderContext) => { // so we expect 2 groups to be created from the single document it('should generate multiple alerts for a single doc in multiple groups', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `*:*`, alert_suppression: { group_by: ['destination.ip'], @@ -689,7 +699,7 @@ export default ({ getService }: FtrProviderContext) => { // The last alert, with null for destination.ip, should be found by the first rule run but not duplicated // by the second run. const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `*:*`, alert_suppression: { group_by: ['destination.ip'], @@ -760,7 +770,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([firstDocument, firstDocument]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), rule_id: 'rule-2', query: `id:${id}`, alert_suppression: { @@ -772,7 +782,7 @@ export default ({ getService }: FtrProviderContext) => { }, }; const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); expect(alerts.hits.hits.length).eql(1); expect(alerts.hits.hits[0]._source).to.eql({ ...alerts.hits.hits[0]._source, @@ -802,7 +812,7 @@ export default ({ getService }: FtrProviderContext) => { await patchRule(supertest, log, { id: createdRule.id, enabled: false }); await patchRule(supertest, log, { id: createdRule.id, enabled: true }); const afterTimestamp = new Date(); - const secondAlerts = await getOpenSignals( + const secondAlerts = await getOpenAlerts( supertest, log, es, @@ -841,7 +851,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([firstDocument, firstDocument]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), rule_id: 'rule-2', query: `id:${id}`, alert_suppression: { @@ -853,15 +863,15 @@ export default ({ getService }: FtrProviderContext) => { }, }; const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals(supertest, log, es, createdRule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); // Close the alert. Subsequent rule executions should ignore this closed alert // for suppression purposes. const alertIds = alerts.hits.hits.map((alert) => alert._id); await supertest - .post(DETECTION_ENGINE_SIGNALS_STATUS_URL) + .post(DETECTION_ENGINE_ALERTS_STATUS_URL) .set('kbn-xsrf', 'true') - .send(setSignalStatus({ signalIds: alertIds, status: 'closed' })) + .send(setAlertStatus({ alertIds, status: 'closed' })) .expect(200); const secondTimestamp = new Date().toISOString(); @@ -878,7 +888,7 @@ export default ({ getService }: FtrProviderContext) => { await patchRule(supertest, log, { id: createdRule.id, enabled: false }); await patchRule(supertest, log, { id: createdRule.id, enabled: true }); const afterTimestamp = new Date(); - const secondAlerts = await getOpenSignals( + const secondAlerts = await getOpenAlerts( supertest, log, es, @@ -922,7 +932,7 @@ export default ({ getService }: FtrProviderContext) => { it('should generate an alert per rule run when duration is less than rule interval', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: "host-0"`, alert_suppression: { group_by: ['host.name'], @@ -981,7 +991,7 @@ export default ({ getService }: FtrProviderContext) => { it('should update an existing alert in the time window', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: "host-0"`, alert_suppression: { group_by: ['host.name'], @@ -1025,7 +1035,7 @@ export default ({ getService }: FtrProviderContext) => { it('should update the correct alerts based on group_by field-value pair', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: *`, alert_suppression: { group_by: ['host.name'], @@ -1099,7 +1109,7 @@ export default ({ getService }: FtrProviderContext) => { it('should update the correct alerts based on group_by field-value pair even when value is null', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: *`, alert_suppression: { group_by: ['destination.ip'], // Only 1 document populates destination.ip @@ -1162,7 +1172,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([docWithoutOverride, docWithOverride]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1226,7 +1236,7 @@ export default ({ getService }: FtrProviderContext) => { ); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1313,7 +1323,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([firstDoc, secondDoc, thirdDoc]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1383,7 +1393,7 @@ export default ({ getService }: FtrProviderContext) => { it('should be enriched with host risk score', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['suppression-data']), + ...getRuleForAlertTesting(['suppression-data']), query: `host.name: "host-0"`, alert_suppression: { group_by: ['host.name'], @@ -1474,7 +1484,7 @@ export default ({ getService }: FtrProviderContext) => { ]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1545,7 +1555,7 @@ export default ({ getService }: FtrProviderContext) => { ]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1600,7 +1610,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([firstDoc, firstDoc]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1654,7 +1664,7 @@ export default ({ getService }: FtrProviderContext) => { await indexListOfDocuments([firstDoc, firstDoc]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1752,7 +1762,7 @@ export default ({ getService }: FtrProviderContext) => { ]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name', 'agent.version'], @@ -1831,7 +1841,7 @@ export default ({ getService }: FtrProviderContext) => { ]); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name', 'agent.version'], @@ -1898,7 +1908,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should create suppressed alerts for single host.name when rule configure with suppress', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -1965,7 +1975,7 @@ export default ({ getService }: FtrProviderContext) => { it('should create unsuppressed alerts for single host.name', async () => { const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], @@ -2076,7 +2086,7 @@ export default ({ getService }: FtrProviderContext) => { }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID} or _id:GBbXBmkBR346wHgn5_eR or _id:x10zJ2oE9v5HJNSHhyxi`, exceptions_list: [{ id, list_id: listId, type, namespace_type: namespaceType }], }; @@ -2119,7 +2129,7 @@ export default ({ getService }: FtrProviderContext) => { }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['auditbeat-*']), + ...getRuleForAlertTesting(['auditbeat-*']), query: `_id:${ID} or _id:GBbXBmkBR346wHgn5_eR or _id:x10zJ2oE9v5HJNSHhyxi`, exceptions_list: [{ id, list_id: listId, type, namespace_type: namespaceType }], }; @@ -2157,7 +2167,7 @@ export default ({ getService }: FtrProviderContext) => { await indexEnhancedDocuments({ documents: [firstDoc, firstDoc, secondDoc], id }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id} AND agent.n*: test-1`, from: 'now-1h', interval: '1h', @@ -2188,7 +2198,7 @@ export default ({ getService }: FtrProviderContext) => { await indexEnhancedDocuments({ documents: [firstDoc, firstDoc, secondDoc], id }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id} AND NOT agent.na*: "test-1"`, from: 'now-1h', interval: '1h', @@ -2215,7 +2225,7 @@ export default ({ getService }: FtrProviderContext) => { await indexEnhancedDocuments({ documents: [firstDoc, secondDoc, thirdDoc], id }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id} AND agent*: "test-1"`, from: 'now-1h', interval: '1h', @@ -2249,7 +2259,7 @@ export default ({ getService }: FtrProviderContext) => { await indexEnhancedDocuments({ documents: [firstDoc, secondDoc, thirdDoc], id }); const rule: QueryRuleCreateProps = { - ...getRuleForSignalTesting(['ecs_compliant']), + ...getRuleForAlertTesting(['ecs_compliant']), query: `id:${id} AND agent.\\*: test-1`, from: 'now-1h', interval: '1h', @@ -2276,7 +2286,8 @@ export default ({ getService }: FtrProviderContext) => { }); }); - describe('legacy investigation_fields', () => { + // TODO: Ask YARA + describe('@brokenInServerless legacy investigation_fields', () => { let ruleWithLegacyInvestigationField: Rule; beforeEach(async () => { @@ -2317,7 +2328,7 @@ export default ({ getService }: FtrProviderContext) => { .set('elastic-api-version', '2023-10-31') .expect(200); - const alertsAfterEnable = await getOpenSignals(supertest, log, es, ruleBody, 'succeeded'); + const alertsAfterEnable = await getOpenAlerts(supertest, log, es, ruleBody, 'succeeded'); expect(alertsAfterEnable.hits.hits.length > 0).eql(true); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/saved_query.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/saved_query.ts new file mode 100644 index 000000000000..e387a2f840c4 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/saved_query.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; +import { flattenWithPrefix } from '@kbn/securitysolution-rules'; + +import { SavedQueryRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { + ALERT_ANCESTORS, + ALERT_DEPTH, + ALERT_ORIGINAL_TIME, + ALERT_ORIGINAL_EVENT, +} from '@kbn/security-solution-plugin/common/field_maps/field_names'; +import { + createRule, + deleteAllRules, + deleteAllAlerts, + getOpenAlerts, + getRuleForAlertTesting, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +/** + * Specific _id to use for some of the tests. If the archiver changes and you see errors + * here, update this to a new value of a chosen auditbeat record and update the tests values. + */ +const ID = 'BhbXBmkBR346wHgn4PeZ'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess @serverless Saved query type rules', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + // First test creates a real rule - remaining tests use preview API + it('should query and get back expected alert structure using a saved query rule', async () => { + const rule: SavedQueryRuleCreateProps = { + ...getRuleForAlertTesting(['auditbeat-*']), + type: 'saved_query', + query: `_id:${ID}`, + saved_id: 'doesnt-exist', + }; + const createdRule = await createRule(supertest, log, rule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); + const alert = alerts.hits.hits[0]._source; + expect(alert).eql({ + ...alert, + [ALERT_ANCESTORS]: [ + { + id: 'BhbXBmkBR346wHgn4PeZ', + type: 'event', + index: 'auditbeat-8.0.0-2019.02.19-000001', + depth: 0, + }, + ], + [ALERT_WORKFLOW_STATUS]: 'open', + [ALERT_DEPTH]: 1, + [ALERT_ORIGINAL_TIME]: '2019-02-19T17:40:03.790Z', + ...flattenWithPrefix(ALERT_ORIGINAL_EVENT, { + action: 'socket_closed', + dataset: 'socket', + kind: 'event', + module: 'system', + }), + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threat_match.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threat_match.ts similarity index 91% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threat_match.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threat_match.ts index efed9c26375e..9b6c525b5e35 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/threat_match.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threat_match.ts @@ -18,6 +18,7 @@ import { SPACE_IDS, VERSION, ALERT_WORKFLOW_TAGS, + ALERT_WORKFLOW_ASSIGNEE_IDS, } from '@kbn/rule-data-utils'; import { flattenWithPrefix } from '@kbn/securitysolution-rules'; import { ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; @@ -35,16 +36,18 @@ import { ALERT_ORIGINAL_TIME, } from '@kbn/security-solution-plugin/common/field_maps/field_names'; import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; -import { getMaxSignalsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; import { previewRule, - getOpenSignals, + getOpenAlerts, getPreviewAlerts, deleteAllAlerts, deleteAllRules, createRule, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + const format = (value: unknown): string => JSON.stringify(value, null, 2); // Asserts that each expected value is included in the subject, independent of @@ -108,8 +111,8 @@ const createThreatMatchRule = ({ threat_index, threat_mapping, threat_filters: [], - threat_indicator_path, ...override, + threat_indicator_path, }); function alertsAreTheSame(alertsA: any[], alertsB: any[]): void { @@ -130,6 +133,7 @@ function alertsAreTheSame(alertsA: any[], alertsB: any[]): void { 'kibana.alert.start', 'kibana.alert.reason', 'kibana.alert.uuid', + 'kibana.alert.url', ]); }; @@ -138,37 +142,40 @@ function alertsAreTheSame(alertsA: any[], alertsB: any[]): void { expect(sort(alertsA.map(mapAlert))).to.eql(sort(alertsB.map(mapAlert))); } - -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); const es = getService('es'); const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const audibeatHostsPath = dataPathBuilder.getPath('auditbeat/hosts'); + const threatIntelPath = dataPathBuilder.getPath('filebeat/threat_intel'); /** * Specific api integration tests for threat matching rule type */ // FLAKY: https://github.com/elastic/kibana/issues/155304 - describe('Threat match type rules', () => { + describe('@ess @serverless Threat match type rules', () => { before(async () => { - // await deleteSignalsIndex(supertest, log); - // await deleteAllAlerts(supertest, log); - await esArchiver.load('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.load(audibeatHostsPath); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/auditbeat/hosts'); + await esArchiver.unload(audibeatHostsPath); await deleteAllAlerts(supertest, log, es); await deleteAllRules(supertest, log); }); // First 2 test creates a real rule - remaining tests use preview API - it('should be able to execute and get all signals when doing a specific query (terms query)', async () => { + it('should be able to execute and get all alerts when doing a specific query (terms query)', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule(); const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals( + const alerts = await getOpenAlerts( supertest, log, es, @@ -178,16 +185,15 @@ export default ({ getService }: FtrProviderContext) => { ); expect(alerts.hits.hits.length).equal(88); const fullSource = alerts.hits.hits.find( - (signal) => - (signal._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' + (alert) => (alert._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' ); - const fullSignal = fullSource?._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = fullSource?._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal).eql({ - ...fullSignal, - '@timestamp': fullSignal['@timestamp'], + expect(fullAlert).eql({ + ...fullAlert, + '@timestamp': fullAlert['@timestamp'], agent: { ephemeral_id: '1b4978a0-48be-49b1-ac96-323425b389ab', hostname: 'zeek-sensor-amsterdam', @@ -281,25 +287,26 @@ export default ({ getService }: FtrProviderContext) => { [ALERT_ORIGINAL_EVENT_ACTION]: 'error', [ALERT_ORIGINAL_EVENT_CATEGORY]: 'user-login', [ALERT_ORIGINAL_EVENT_MODULE]: 'auditd', - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], [ALERT_REASON]: 'user-login event with source 46.101.47.213 by root on zeek-sensor-amsterdam created high alert Query with a rule id.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], [ALERT_STATUS]: 'active', - [ALERT_UUID]: fullSignal[ALERT_UUID], + [ALERT_UUID]: fullAlert[ALERT_UUID], [ALERT_WORKFLOW_STATUS]: 'open', [ALERT_WORKFLOW_TAGS]: [], + [ALERT_WORKFLOW_ASSIGNEE_IDS]: [], [SPACE_IDS]: ['default'], - [VERSION]: fullSignal[VERSION], + [VERSION]: fullAlert[VERSION], threat: { - enrichments: get(fullSignal, 'threat.enrichments'), + enrichments: get(fullAlert, 'threat.enrichments'), }, ...flattenWithPrefix(ALERT_RULE_NAMESPACE, { actions: [], author: [], category: 'Indicator Match Rule', consumer: 'siem', - created_by: 'elastic', + created_by: ELASTICSEARCH_USERNAME, description: 'Detecting root and admin users', enabled: true, exceptions_list: [], @@ -320,14 +327,14 @@ export default ({ getService }: FtrProviderContext) => { threat: [], to: 'now', type: 'threat_match', - updated_at: fullSignal[ALERT_RULE_UPDATED_AT], - updated_by: 'elastic', - uuid: fullSignal[ALERT_RULE_UUID], + updated_at: fullAlert[ALERT_RULE_UPDATED_AT], + updated_by: ELASTICSEARCH_USERNAME, + uuid: fullAlert[ALERT_RULE_UUID], version: 1, }), }); }); - it('should be able to execute and get all signals when doing a specific query (match query)', async () => { + it('should be able to execute and get all alerts when doing a specific query (match query)', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ threat_mapping: [ // We match host.name against host.name @@ -349,7 +356,7 @@ export default ({ getService }: FtrProviderContext) => { }); const createdRule = await createRule(supertest, log, rule); - const alerts = await getOpenSignals( + const alerts = await getOpenAlerts( supertest, log, es, @@ -359,16 +366,15 @@ export default ({ getService }: FtrProviderContext) => { ); expect(alerts.hits.hits.length).equal(88); const fullSource = alerts.hits.hits.find( - (signal) => - (signal._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' + (alert) => (alert._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' ); - const fullSignal = fullSource?._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = fullSource?._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal).eql({ - ...fullSignal, - '@timestamp': fullSignal['@timestamp'], + expect(fullAlert).eql({ + ...fullAlert, + '@timestamp': fullAlert['@timestamp'], agent: { ephemeral_id: '1b4978a0-48be-49b1-ac96-323425b389ab', hostname: 'zeek-sensor-amsterdam', @@ -462,24 +468,24 @@ export default ({ getService }: FtrProviderContext) => { [ALERT_ORIGINAL_EVENT_ACTION]: 'error', [ALERT_ORIGINAL_EVENT_CATEGORY]: 'user-login', [ALERT_ORIGINAL_EVENT_MODULE]: 'auditd', - [ALERT_ORIGINAL_TIME]: fullSignal[ALERT_ORIGINAL_TIME], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], [ALERT_REASON]: 'user-login event with source 46.101.47.213 by root on zeek-sensor-amsterdam created high alert Query with a rule id.', - [ALERT_RULE_UUID]: fullSignal[ALERT_RULE_UUID], + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], [ALERT_STATUS]: 'active', - [ALERT_UUID]: fullSignal[ALERT_UUID], + [ALERT_UUID]: fullAlert[ALERT_UUID], [ALERT_WORKFLOW_STATUS]: 'open', [SPACE_IDS]: ['default'], - [VERSION]: fullSignal[VERSION], + [VERSION]: fullAlert[VERSION], threat: { - enrichments: get(fullSignal, 'threat.enrichments'), + enrichments: get(fullAlert, 'threat.enrichments'), }, ...flattenWithPrefix(ALERT_RULE_NAMESPACE, { actions: [], author: [], category: 'Indicator Match Rule', consumer: 'siem', - created_by: 'elastic', + created_by: ELASTICSEARCH_USERNAME, description: 'Detecting root and admin users', enabled: true, exceptions_list: [], @@ -500,18 +506,18 @@ export default ({ getService }: FtrProviderContext) => { threat: [], to: 'now', type: 'threat_match', - updated_at: fullSignal[ALERT_RULE_UPDATED_AT], - updated_by: 'elastic', - uuid: fullSignal[ALERT_RULE_UUID], + updated_at: fullAlert[ALERT_RULE_UPDATED_AT], + updated_by: ELASTICSEARCH_USERNAME, + uuid: fullAlert[ALERT_RULE_UUID], version: 1, }), }); }); - it('generates max signals warning when circuit breaker is hit', async () => { + it('generates max alerts warning when circuit breaker is hit', async () => { const rule: ThreatMatchRuleCreateProps = { ...createThreatMatchRule(), max_signals: 87 }; // Query generates 88 alerts with current esArchive const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).contain(getMaxSignalsWarning()); + expect(logs[0].warnings).contain(getMaxAlertsWarning()); }); it('terms and match should have the same alerts with pagination', async () => { @@ -552,7 +558,7 @@ export default ({ getService }: FtrProviderContext) => { const createdRuleTerm = await createRule(supertest, log, termRule); const createdRuleMatch = await createRule(supertest, log, matchRule); - const alertsTerm = await getOpenSignals( + const alertsTerm = await getOpenAlerts( supertest, log, es, @@ -560,7 +566,7 @@ export default ({ getService }: FtrProviderContext) => { RuleExecutionStatusEnum.succeeded, 100 ); - const alertsMatch = await getOpenSignals( + const alertsMatch = await getOpenAlerts( supertest, log, es, @@ -593,7 +599,7 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).equal(0); }); - it('should return 0 signals when using an AND and one of the clauses does not have data', async () => { + it('should return 0 alerts when using an AND and one of the clauses does not have data', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ threat_mapping: [ { @@ -618,7 +624,7 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).equal(0); }); - it('should return 0 signals when using an AND and one of the clauses has a made up value that does not exist', async () => { + it('should return 0 alerts when using an AND and one of the clauses has a made up value that does not exist', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ threat_mapping: [ { @@ -661,14 +667,14 @@ export default ({ getService }: FtrProviderContext) => { describe('indicator enrichment: threat-first search', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/filebeat/threat_intel'); + await esArchiver.load(threatIntelPath); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/threat_intel'); + await esArchiver.unload(threatIntelPath); }); - it('enriches signals with the single indicator that matched', async () => { + it('enriches alerts with the single indicator that matched', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ threat_mapping: [ { @@ -744,9 +750,9 @@ export default ({ getService }: FtrProviderContext) => { ]); }); - it('enriches signals with multiple indicators if several matched', async () => { + it('enriches alerts with multiple indicators if several matched', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ - query: 'NOT source.port:35326', // specify query to have signals more than treat indicators, but only 1 will match + query: 'NOT source.port:35326', // specify query to have alerts more than treat indicators, but only 1 will match threat_query: 'threat.indicator.ip: *', threat_index: ['filebeat-*'], // Mimics indicators from the filebeat MISP module threat_mapping: [ @@ -811,7 +817,7 @@ export default ({ getService }: FtrProviderContext) => { it('adds a single indicator that matched multiple fields', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ - query: 'NOT source.port:35326', // specify query to have signals more than treat indicators, but only 1 will match + query: 'NOT source.port:35326', // specify query to have alerts more than treat indicators, but only 1 will match threat_query: 'threat.indicator.port: 57324 or threat.indicator.ip:45.115.45.3', // narrow our query to a single indicator threat_index: ['filebeat-*'], // Mimics indicators from the filebeat MISP module threat_mapping: [ @@ -907,7 +913,7 @@ export default ({ getService }: FtrProviderContext) => { ]); }); - it('generates multiple signals with multiple matches', async () => { + it('generates multiple alerts with multiple matches', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ threat_query: '*:*', threat_index: ['filebeat-*'], // Mimics indicators from the filebeat MISP module @@ -1032,7 +1038,7 @@ export default ({ getService }: FtrProviderContext) => { }); // https://github.com/elastic/kibana/issues/149920 - // generates same number of alerts similarly to "enriches signals with the single indicator that matches" test + // generates same number of alerts similarly to "enriches alerts with the single indicator that matches" test it('generates alerts with single match if queries contain field path wildcards', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ // still matches all documents as default *:* @@ -1060,14 +1066,14 @@ export default ({ getService }: FtrProviderContext) => { describe('indicator enrichment: event-first search', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/filebeat/threat_intel'); + await esArchiver.load(threatIntelPath); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/filebeat/threat_intel'); + await esArchiver.unload(threatIntelPath); }); - it('enriches signals with the single indicator that matched', async () => { + it('enriches alerts with the single indicator that matched', async () => { const termRule: ThreatMatchRuleCreateProps = createThreatMatchRule({ query: 'destination.ip:159.89.119.67', threat_query: 'threat.indicator.domain: *', // narrow things down to indicators with a domain @@ -1168,7 +1174,7 @@ export default ({ getService }: FtrProviderContext) => { alertsAreTheSame(termPreviewAlerts, matchPrevieAlerts); }); - it('enriches signals with multiple indicators if several matched', async () => { + it('enriches alerts with multiple indicators if several matched', async () => { const termRule: ThreatMatchRuleCreateProps = createThreatMatchRule({ query: 'source.port: 57324', // narrow our query to a single record that matches two indicatorsthreat_query: 'threat.indicator.ip: *', threat_query: 'threat.indicator.ip: *', @@ -1408,7 +1414,7 @@ export default ({ getService }: FtrProviderContext) => { ); }); - it('generates multiple signals with multiple matches', async () => { + it('generates multiple alerts with multiple matches', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ query: '(source.port:57324 and source.ip:45.115.45.3) or destination.ip:159.89.119.67', // narrow our query to a single record that matches two indicators threat_query: '*:*', @@ -1534,7 +1540,7 @@ export default ({ getService }: FtrProviderContext) => { }); // https://github.com/elastic/kibana/issues/149920 - // creates same number of alerts similarly to "generates multiple signals with multiple matches" test + // creates same number of alerts similarly to "generates multiple alerts with multiple matches" test it('generates alerts with multiple matches if queries contain field path wildcards', async () => { const rule: ThreatMatchRuleCreateProps = createThreatMatchRule({ // source.po* matches port source.port field @@ -1605,16 +1611,16 @@ export default ({ getService }: FtrProviderContext) => { const previewAlerts = await getPreviewAlerts({ es, previewId, size: 100 }); expect(previewAlerts.length).equal(88); const fullSource = previewAlerts.find( - (signal) => - (signal._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' + (alert) => + (alert._source?.[ALERT_ANCESTORS] as Ancestor[])[0].id === '7yJ-B2kBR346wHgnhlMn' ); - const fullSignal = fullSource?._source; - if (!fullSignal) { - return expect(fullSignal).to.be.ok(); + const fullAlert = fullSource?._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); } - expect(fullSignal?.host?.risk?.calculated_level).to.eql('Critical'); - expect(fullSignal?.host?.risk?.calculated_score_norm).to.eql(70); + expect(fullAlert?.host?.risk?.calculated_level).to.eql('Critical'); + expect(fullAlert?.host?.risk?.calculated_score_norm).to.eql(70); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threshold.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threshold.ts new file mode 100644 index 000000000000..81203c3d48a2 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/execution_logic/threshold.ts @@ -0,0 +1,432 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { + ALERT_REASON, + ALERT_RULE_UUID, + ALERT_WORKFLOW_STATUS, + EVENT_KIND, +} from '@kbn/rule-data-utils'; + +import { ThresholdRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { Ancestor } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/types'; +import { + ALERT_ANCESTORS, + ALERT_DEPTH, + ALERT_ORIGINAL_TIME, + ALERT_THRESHOLD_RESULT, +} from '@kbn/security-solution-plugin/common/field_maps/field_names'; +import { getMaxSignalsWarning as getMaxAlertsWarning } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/utils'; +import { + createRule, + getOpenAlerts, + getPreviewAlerts, + getThresholdRuleForAlertTesting, + previewRule, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + + describe('@ess @serverless Threshold type rules', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + }); + + // First test creates a real rule - remaining tests use preview API + it('generates 1 alert from Threshold rules when threshold is met', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: ['host.id'], + value: 700, + }, + }; + const createdRule = await createRule(supertest, log, rule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); + expect(alerts.hits.hits.length).eql(1); + const fullAlert = alerts.hits.hits[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); + } + const eventIds = (fullAlert?.[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); + expect(fullAlert).eql({ + ...fullAlert, + 'host.id': '8cc95778cce5407c809480e8e32ad76b', + [EVENT_KIND]: 'signal', + [ALERT_ANCESTORS]: [ + { + depth: 0, + id: eventIds[0], + index: 'auditbeat-*', + type: 'event', + }, + ], + [ALERT_WORKFLOW_STATUS]: 'open', + [ALERT_REASON]: 'event created high alert Alert Testing Query.', + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], + [ALERT_DEPTH]: 1, + [ALERT_THRESHOLD_RESULT]: { + terms: [ + { + field: 'host.id', + value: '8cc95778cce5407c809480e8e32ad76b', + }, + ], + count: 788, + from: '2019-02-19T07:12:05.332Z', + }, + }); + }); + + it('generates max alerts warning when circuit breaker is exceeded', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 1, // This value generates 7 alerts with the current esArchive + }, + max_signals: 5, + }; + const { logs } = await previewRule({ supertest, rule }); + expect(logs[0].warnings).contain(getMaxAlertsWarning()); + }); + + it("doesn't generate max alerts warning when circuit breaker is met but not exceeded", async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 1, // This value generates 7 alerts with the current esArchive + }, + max_signals: 7, + }; + const { logs } = await previewRule({ supertest, rule }); + expect(logs[0].warnings).not.contain(getMaxAlertsWarning()); + }); + + it('generates 2 alerts from Threshold rules when threshold is met', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 100, + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(2); + }); + + it('applies the provided query before bucketing ', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + query: 'host.id:"2ab45fc1c41e4c84bbd02202a7e5761f"', + threshold: { + field: 'process.name', + value: 21, + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(1); + }); + + it('generates no alerts from Threshold rules when threshold is met and cardinality is not met', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 100, + cardinality: [ + { + field: 'destination.ip', + value: 100, + }, + ], + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(0); + }); + + it('generates no alerts from Threshold rules when cardinality is met and threshold is not met', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 1000, + cardinality: [ + { + field: 'destination.ip', + value: 5, + }, + ], + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(0); + }); + + it('generates alerts from Threshold rules when threshold and cardinality are both met', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.id', + value: 100, + cardinality: [ + { + field: 'destination.ip', + value: 5, + }, + ], + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(1); + const fullAlert = previewAlerts[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); + } + const eventIds = (fullAlert?.[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); + expect(fullAlert).eql({ + ...fullAlert, + 'host.id': '8cc95778cce5407c809480e8e32ad76b', + [EVENT_KIND]: 'signal', + [ALERT_ANCESTORS]: [ + { + depth: 0, + id: eventIds[0], + index: 'auditbeat-*', + type: 'event', + }, + ], + [ALERT_WORKFLOW_STATUS]: 'open', + [ALERT_REASON]: `event created high alert Alert Testing Query.`, + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], + [ALERT_DEPTH]: 1, + [ALERT_THRESHOLD_RESULT]: { + terms: [ + { + field: 'host.id', + value: '8cc95778cce5407c809480e8e32ad76b', + }, + ], + cardinality: [ + { + field: 'destination.ip', + value: 7, + }, + ], + count: 788, + from: '2019-02-19T07:12:05.332Z', + }, + }); + }); + + it('should not generate alerts if only one field meets the threshold requirement', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: ['host.id', 'process.name'], + value: 22, + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(0); + }); + + it('generates alerts from Threshold rules when bucketing by multiple fields', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: ['host.id', 'process.name', 'event.module'], + value: 21, + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(1); + const fullAlert = previewAlerts[0]._source; + if (!fullAlert) { + return expect(fullAlert).to.be.ok(); + } + const eventIds = (fullAlert[ALERT_ANCESTORS] as Ancestor[]).map((event) => event.id); + expect(fullAlert).eql({ + ...fullAlert, + 'event.module': 'system', + 'host.id': '2ab45fc1c41e4c84bbd02202a7e5761f', + 'process.name': 'sshd', + [EVENT_KIND]: 'signal', + [ALERT_ANCESTORS]: [ + { + depth: 0, + id: eventIds[0], + index: 'auditbeat-*', + type: 'event', + }, + ], + [ALERT_WORKFLOW_STATUS]: 'open', + [ALERT_REASON]: `event with process sshd, created high alert Alert Testing Query.`, + [ALERT_RULE_UUID]: fullAlert[ALERT_RULE_UUID], + [ALERT_ORIGINAL_TIME]: fullAlert[ALERT_ORIGINAL_TIME], + [ALERT_DEPTH]: 1, + [ALERT_THRESHOLD_RESULT]: { + terms: [ + { + field: 'host.id', + value: '2ab45fc1c41e4c84bbd02202a7e5761f', + }, + { + field: 'process.name', + value: 'sshd', + }, + { + field: 'event.module', + value: 'system', + }, + ], + count: 21, + from: '2019-02-19T20:22:03.561Z', + }, + }); + }); + + // https://github.com/elastic/kibana/issues/149920 + it('generates 1 alert when threshold is met and rule query has wildcard in field name', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + query: 'agent.ty*:auditbeat', // this query should match all documents from index and we will receive 1 alert, similarly to "generates 1 alert from Threshold rules when threshold is met" test case + threshold: { + field: ['host.id'], + value: 700, + }, + }; + const createdRule = await createRule(supertest, log, rule); + const alerts = await getOpenAlerts(supertest, log, es, createdRule); + expect(alerts.hits.hits.length).eql(1); + }); + + describe('Timestamp override and fallback', async () => { + before(async () => { + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' + ); + }); + + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_fallback' + ); + }); + + it('applies timestamp override when using single field', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['timestamp-fallback-test']), + threshold: { + field: 'host.name', + value: 1, + }, + timestamp_override: 'event.ingested', + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(4); + + for (const hit of previewAlerts) { + const originalTime = hit._source?.[ALERT_ORIGINAL_TIME]; + const hostName = hit._source?.['host.name']; + if (hostName === 'host-1') { + expect(originalTime).eql('2020-12-16T15:15:18.570Z'); + } else if (hostName === 'host-2') { + expect(originalTime).eql('2020-12-16T15:16:18.570Z'); + } else if (hostName === 'host-3') { + expect(originalTime).eql('2020-12-16T16:15:18.570Z'); + } else { + expect(originalTime).eql('2020-12-16T16:16:18.570Z'); + } + } + }); + + it('applies timestamp override when using multiple fields', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['timestamp-fallback-test']), + threshold: { + field: ['host.name', 'source.ip'], + value: 1, + }, + timestamp_override: 'event.ingested', + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).eql(4); + + for (const hit of previewAlerts) { + const originalTime = hit._source?.[ALERT_ORIGINAL_TIME]; + const hostName = hit._source?.['host.name']; + if (hostName === 'host-1') { + expect(originalTime).eql('2020-12-16T15:15:18.570Z'); + } else if (hostName === 'host-2') { + expect(originalTime).eql('2020-12-16T15:16:18.570Z'); + } else if (hostName === 'host-3') { + expect(originalTime).eql('2020-12-16T16:15:18.570Z'); + } else { + expect(originalTime).eql('2020-12-16T16:16:18.570Z'); + } + } + }); + }); + + describe('with host risk index', async () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/entity/risks'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/entity/risks'); + }); + + it('should be enriched with host risk score', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['auditbeat-*']), + threshold: { + field: 'host.name', + value: 100, + }, + }; + const { previewId } = await previewRule({ supertest, rule }); + const previewAlerts = await getPreviewAlerts({ es, previewId, sort: ['host.name'] }); + + expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).to.eql('Low'); + expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).to.eql(20); + expect(previewAlerts[1]?._source?.host?.risk?.calculated_level).to.eql('Critical'); + expect(previewAlerts[1]?._source?.host?.risk?.calculated_score_norm).to.eql(96); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/ignore_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/ignore_fields.ts new file mode 100644 index 000000000000..6ddee1846067 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/ignore_fields.ts @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + getAlertsById, + waitForRuleSuccess, + waitForAlertsToBePresent, +} from '../../utils'; + +interface Ignore { + normal_constant?: string; + small_field?: string; + testing_ignored?: string; + testing_regex?: string; +} + +import { FtrProviderContext } from '../../../../ftr_provider_context'; +export default ({ getService }: FtrProviderContext): void => { + /** + * See the config file (config.ts) for which field values were added to be ignored + * for testing. The values should be in the config around the area of: + * --xpack.securitySolution.alertIgnoreFields=[testing.ignore_1,/[testingRegex] + * meaning that the ignore fields values should be the array: ["testing.ignore_1", "/[testingRegex]/"] + * + * This test exercises the ability to be able to ignore particular values within the fields API and merge strategies. + * These values can be defined in your kibana.yml file as "xpack.securitySolution.alertIgnoreFields". This is useful + * for users that find bugs or regressions within query languages or bugs within the merge strategies + * where one or more fields are causing problems and they need to turn disable that particular field. + * + * Ref: + * https://github.com/elastic/kibana/issues/110802 + * https://github.com/elastic/elasticsearch/issues/77152 + * + * Files ref: + * server/lib/detection_engine/signals/source_fields_merging/utils/is_ignored.ts + * server/lib/detection_engine/signals/source_fields_merging/utils/is_eql_bug_77152.ts + */ + describe('@ess @serverless ignore_fields', () => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/ignore_fields'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/ignore_fields'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('@skipInQA should ignore the field of "testing_ignored"', async () => { + const rule = getEqlRuleForAlertTesting(['ignore_fields']); + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((hit) => (hit._source as Ignore).testing_ignored) + .sort(); + + // Value should be "undefined for all records" + expect(hits).to.eql([undefined, undefined, undefined, undefined]); + }); + + it('@skipInQA should ignore the field of "testing_regex"', async () => { + const rule = getEqlRuleForAlertTesting(['ignore_fields']); + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => (hit._source as Ignore).testing_regex).sort(); + + // Value should be "undefined for all records" + expect(hits).to.eql([undefined, undefined, undefined, undefined]); + }); + + it('should have the field of "normal_constant"', async () => { + const rule = getEqlRuleForAlertTesting(['ignore_fields']); + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((hit) => (hit._source as Ignore).normal_constant) + .sort(); + + // Value should be "constant_value for all records" + expect(hits).to.eql(['constant_value', 'constant_value', 'constant_value', 'constant_value']); + }); + + // TODO: Remove this test once https://github.com/elastic/elasticsearch/issues/77152 is fixed + it('should ignore the field of "_ignored" when using EQL and index the data', async () => { + const rule = getEqlRuleForAlertTesting(['ignore_fields']); + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => (hit._source as Ignore).small_field).sort(); + + // We just test a constant value to ensure this did not blow up on us and did index data. + expect(hits).to.eql([ + '1 indexed', + '2 large not indexed', + '3 large not indexed', + '4 large not indexed', + ]); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/index.ts new file mode 100644 index 000000000000..b497472e0b57 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Rule execution logic API', function () { + loadTestFile(require.resolve('./keyword_family')); + loadTestFile(require.resolve('./ignore_fields')); + loadTestFile(require.resolve('./runtime')); + loadTestFile(require.resolve('./execution_logic')); + loadTestFile(require.resolve('./timestamps')); + }); +} diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/README.md b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/README.md similarity index 100% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group5/keyword_family/README.md rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/README.md diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/const_keyword.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/const_keyword.ts new file mode 100644 index 000000000000..0e3d01dc1ca2 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/const_keyword.ts @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { + EqlRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; + +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + getRuleForAlertTesting, + getAlertsById, + getThresholdRuleForAlertTesting, + waitForRuleSuccess, + waitForAlertsToBePresent, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess @serverless Rule detects against a keyword of event.dataset', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/const_keyword'); + }); + + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/rule_keyword_family/const_keyword' + ); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + describe('"kql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset" and have 4 alerts', async () => { + const rule = { + ...getRuleForAlertTesting(['const_keyword']), + query: 'event.dataset: "dataset_name_1"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + expect(alertsOpen.hits.hits.length).to.eql(4); + }); + + it('should copy the dataset_name_1 from the index into the alert', async () => { + const rule = { + ...getRuleForAlertTesting(['const_keyword']), + query: 'event.dataset: "dataset_name_1"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"eql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset" and have 4 alerts', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['const_keyword']), + query: 'any where event.dataset=="dataset_name_1"', + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + expect(alertsOpen.hits.hits.length).to.eql(4); + }); + + it('should copy the "dataset_name_1" from "event.dataset"', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['const_keyword']), + query: 'any where event.dataset=="dataset_name_1"', + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"threshold" rule type', async () => { + it('should detect the "dataset_name_1" from "event.dataset"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['const_keyword']), + threshold: { + field: 'event.dataset', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) + .sort(); + expect(hits).to.eql([ + { + count: 4, + from: '2020-10-27T05:00:53.000Z', + terms: [ + { + field: 'event.dataset', + value: 'dataset_name_1', + }, + ], + }, + ]); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/index.ts new file mode 100644 index 000000000000..7244085b6eff --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Detection keyword family data types', function () { + loadTestFile(require.resolve('./keyword')); + loadTestFile(require.resolve('./const_keyword')); + loadTestFile(require.resolve('./keyword_mixed_with_const')); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword.ts new file mode 100644 index 000000000000..5a4dbf092942 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { + EqlRuleCreateProps, + QueryRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + getRuleForAlertTesting, + getAlertsById, + getThresholdRuleForAlertTesting, + waitForRuleSuccess, + waitForAlertsToBePresent, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + describe('Rule detects against a keyword of event.dataset', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + describe('@ess @serverless "kql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset"', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['keyword']), + query: 'event.dataset: "dataset_name_1"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"eql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset"', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['keyword']), + query: 'any where event.dataset=="dataset_name_1"', + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"threshold" rule type', async () => { + it('should detect the "dataset_name_1" from "event.dataset"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['keyword']), + threshold: { + field: 'event.dataset', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) + .sort(); + expect(hits).to.eql([ + { + count: 4, + from: '2020-10-28T05:00:53.000Z', + terms: [ + { + field: 'event.dataset', + value: 'dataset_name_1', + }, + ], + }, + ]); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword_mixed_with_const.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword_mixed_with_const.ts new file mode 100644 index 000000000000..1353c0b6ca5e --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/keyword_family/keyword_mixed_with_const.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { + EqlRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ALERT_THRESHOLD_RESULT } from '@kbn/security-solution-plugin/common/field_maps/field_names'; + +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + getRuleForAlertTesting, + getAlertsById, + waitForRuleSuccess, + waitForAlertsToBePresent, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess @serverless Rule detects against a keyword and constant_keyword of event.dataset', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/const_keyword'); + await esArchiver.load('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); + }); + + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/rule_keyword_family/const_keyword' + ); + await esArchiver.unload('x-pack/test/functional/es_archives/rule_keyword_family/keyword'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + describe('"kql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset" and have 8 alerts, 4 from each index', async () => { + const rule = { + ...getRuleForAlertTesting(['keyword', 'const_keyword']), + query: 'event.dataset: "dataset_name_1"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 8, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + expect(alertsOpen.hits.hits.length).to.eql(8); + }); + + it('should copy the dataset_name_1 from the index into the alert', async () => { + const rule = { + ...getRuleForAlertTesting(['keyword', 'const_keyword']), + query: 'event.dataset: "dataset_name_1"', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 8, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"eql" rule type', () => { + it('should detect the "dataset_name_1" from "event.dataset" and have 8 alerts, 4 from each index', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['keyword', 'const_keyword']), + query: 'any where event.dataset=="dataset_name_1"', + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 8, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + expect(alertsOpen.hits.hits.length).to.eql(8); + }); + + it('should copy the "dataset_name_1" from "event.dataset"', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['keyword', 'const_keyword']), + query: 'any where event.dataset=="dataset_name_1"', + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 8, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.['event.dataset']).sort(); + expect(hits).to.eql([ + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + 'dataset_name_1', + ]); + }); + }); + + describe('"threshold" rule type', async () => { + it('should detect the "dataset_name_1" from "event.dataset"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getRuleForAlertTesting(['keyword', 'const_keyword']), + rule_id: 'threshold-rule', + type: 'threshold', + language: 'kuery', + query: '*:*', + threshold: { + field: 'event.dataset', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((hit) => hit._source?.[ALERT_THRESHOLD_RESULT] ?? null) + .sort(); + expect(hits).to.eql([ + { + count: 8, + from: '2020-10-27T05:00:53.000Z', + terms: [ + { + field: 'event.dataset', + value: 'dataset_name_1', + }, + ], + }, + ]); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/runtime.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/runtime.ts new file mode 100644 index 000000000000..030f2eafd6a1 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/runtime.ts @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { performance } from 'perf_hooks'; + +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getRuleForAlertTesting, + getAlertsById, + waitForRuleSuccess, + waitForAlertsToBePresent, +} from '../../utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const es = getService('es'); + + interface Runtime { + name: string; + hostname: string; + } + + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/138923 + describe('@ess @serverless Tests involving runtime fields of source indexes and the alerts index', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/runtime'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/runtime'); + }); + + describe('Regular runtime field mappings', () => { + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should execute a rule to completion and not timeout when there are a lot of runtime fields', async () => { + const rule = getRuleForAlertTesting(['runtime']); + const { id } = await createRule(supertest, log, rule); + const start = performance.now(); + await waitForRuleSuccess({ supertest, log, id }); + const end = performance.now(); + expect(end - start).to.be.lessThan(10000); + }); + + it('should copy normal non-runtime data set from the source index into the alerts index in the same position when the target is ECS compatible', async () => { + const rule = getRuleForAlertTesting(['runtime']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((alert) => (alert._source?.host as Runtime).name) + .sort(); + expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']); + }); + + it('should copy "runtime mapping" data from a source index into the alerts index in the same position when the target is ECS compatible', async () => { + const rule = getRuleForAlertTesting(['runtime']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((alert) => (alert._source?.host as Runtime).hostname) + .sort(); + expect(hits).to.eql(['host name 1', 'host name 2', 'host name 3', 'host name 4']); + }); + }); + + describe('Runtime field mappings that have conflicts within them', () => { + beforeEach(async () => { + await createAlertsIndex(supertest, log); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields' + ); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/runtime_conflicting_fields' + ); + }); + + /** + * Note, this test shows that we do not shadow or overwrite runtime fields on-top of regular fields as we reduced + * risk with overwriting fields in the strategy we are currently using in detection engine. If you swap, change the strategies + * because we decide to overwrite "_source" values with "fields", then expect to change this test. + */ + it('should NOT copy normal non-runtime data set from the source index into the alerts index in the same position when the target is ECS compatible', async () => { + const rule = getRuleForAlertTesting(['runtime_conflicting_fields']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits + .map((alert) => alert._source?.host as Array<{ name: string }>) + .map((host) => { + // sort the inner array elements first + return host.sort((a, b) => a.name.localeCompare(b.name)); + }) + .sort((aArray, bArray) => { + // since these are all unique, using just the first element should give us stability + return aArray[0].name.localeCompare(bArray[0].name); + }); + expect(hits).to.eql([ + [ + { + name: 'host name 1_1', + }, + { + name: 'host name 1_2', + }, + ], + [ + { + name: 'host name 2_1', + }, + { + name: 'host name 2_2', + }, + ], + [ + { + name: 'host name 3_1', + }, + { + name: 'host name 3_2', + }, + ], + [ + { + name: 'host name 4_1', + }, + { + name: 'host name 4_2', + }, + ], + ]); + }); + + /** + * Note, this test shows that we do NOT shadow or overwrite runtime fields on-top of regular fields when we detect those + * fields as arrays of objects since the objects are flattened in "fields" and we detect something already there so we skip + * this shadowed runtime data as it is ambiguous of where we would put it in the array. + */ + it('should NOT copy "runtime mapping" data from a source index into the alerts index in the same position when the target is ECS compatible', async () => { + const rule = getRuleForAlertTesting(['runtime_conflicting_fields']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + const alertsOpen = await getAlertsById(supertest, log, id); + const hits = alertsOpen.hits.hits.map((alert) => (alert._source?.host as Runtime).hostname); + expect(hits).to.eql([undefined, undefined, undefined, undefined]); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/timestamps.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/timestamps.ts new file mode 100644 index 000000000000..d7c645c11508 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_execution_logic/timestamps.ts @@ -0,0 +1,398 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { orderBy } from 'lodash'; +import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; +import { + EqlRuleCreateProps, + QueryRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ALERT_ORIGINAL_TIME } from '@kbn/security-solution-plugin/common/field_maps/field_names'; + +import { + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + createRule, + waitForRuleSuccess, + waitForAlertsToBePresent, + getOpenAlerts, + getRuleForAlertTesting, + getAlertsByIds, + getEqlRuleForAlertTesting, + waitForRulePartialFailure, +} from '../../utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { EsArchivePathBuilder } from '../../../../es_archive_path_builder'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + // TODO: add a new service + const config = getService('config'); + const isServerless = config.get('serverless'); + const dataPathBuilder = new EsArchivePathBuilder(isServerless); + const path = dataPathBuilder.getPath('auditbeat/hosts'); + /** + * Tests around timestamps within alerts such as the copying of timestamps correctly into + * the "signal.original_time" field, ensuring that timestamp overrides operate, and ensuring that + * partial errors happen correctly + */ + describe('@ess @serverless timestamp tests', () => { + describe('alerts generated from events with a timestamp in seconds is converted correctly into the forced ISO8601 format when copying', () => { + beforeEach(async () => { + await createAlertsIndex(supertest, log); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds' + ); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_5' + ); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_in_seconds' + ); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_5' + ); + }); + + describe('KQL query', () => { + it('should convert the @timestamp which is epoch_seconds into the correct ISO format', async () => { + const rule = getRuleForAlertTesting(['timestamp_in_seconds']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]).sort(); + expect(hits).to.eql(['2021-06-02T23:33:15.000Z']); + }); + + it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfakeindex-5']), + timestamp_override: 'event.ingested', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]).sort(); + expect(hits).to.eql(['2020-12-16T15:16:18.000Z']); + }); + }); + + describe('EQL query', () => { + it('should convert the @timestamp which is epoch_seconds into the correct ISO format for EQL', async () => { + const rule = getEqlRuleForAlertTesting(['timestamp_in_seconds']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]).sort(); + expect(hits).to.eql(['2021-06-02T23:33:15.000Z']); + }); + + it('should still use the @timestamp field even with an override field. It should never use the override field', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['myfakeindex-5']), + timestamp_override: 'event.ingested', + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsOpen = await getAlertsByIds(supertest, log, [id]); + const hits = alertsOpen.hits.hits.map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]).sort(); + expect(hits).to.eql(['2020-12-16T15:16:18.000Z']); + }); + }); + }); + + /** + * Here we test the functionality of timestamp overrides. If the rule specifies a timestamp override, + * then the documents will be queried and sorted using the timestamp override field. + * If no timestamp override field exists in the indices but one was provided to the rule, + * the rule's query will additionally search for events using the `@timestamp` field + */ + describe('alerts generated from events with timestamp override field', async () => { + beforeEach(async () => { + await deleteAllAlerts(supertest, log, es); + await createAlertsIndex(supertest, log); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_1' + ); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_2' + ); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' + ); + await esArchiver.load( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_4' + ); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_1' + ); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_2' + ); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_3' + ); + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/timestamp_override_4' + ); + }); + + describe('KQL', () => { + it('should generate alerts with event.ingested, @timestamp and (event.ingested + timestamp)', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfa*']), + timestamp_override: 'event.ingested', + }; + + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 3, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id], 3); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(3); + }); + + it('should generate 2 alerts with event.ingested when timestamp fallback is disabled', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfa*']), + rule_id: 'rule-without-timestamp-fallback', + timestamp_override: 'event.ingested', + timestamp_override_fallback_disabled: true, + }; + + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 2, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id], 2); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(2); + }); + + it('should generate 2 alerts with @timestamp', async () => { + const rule: QueryRuleCreateProps = getRuleForAlertTesting(['myfa*']); + + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 2, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id]); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(2); + }); + + it('should generate 2 alerts when timestamp override does not exist', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfa*']), + timestamp_override: 'event.fakeingestfield', + }; + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 2, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id, id]); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(2); + }); + + it('should not generate any alerts when timestamp override does not exist and timestamp fallback is disabled', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfa*']), + rule_id: 'rule-without-timestamp-fallback', + timestamp_override: 'event.fakeingestfield', + timestamp_override_fallback_disabled: true, + }; + + const createdRule = await createRule(supertest, log, rule); + const alertsOpen = await getOpenAlerts( + supertest, + log, + es, + createdRule, + RuleExecutionStatusEnum['partial failure'] + ); + expect(alertsOpen.hits.hits.length).eql(0); + }); + + /** + * We should not use the timestamp override as the "original_time" as that can cause + * confusion if you have both a timestamp and an override in the source event. Instead the "original_time" + * field should only be overridden by the "timestamp" since when we generate a alert + * and we add a new timestamp to the alert. + */ + it('should NOT use the timestamp override as the "original_time"', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['myfakeindex-2']), + timestamp_override: 'event.ingested', + }; + const { id } = await createRule(supertest, log, rule); + + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 1, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id, id]); + const hits = alertsResponse.hits.hits + .map((hit) => hit._source?.[ALERT_ORIGINAL_TIME]) + .sort(); + expect(hits).to.eql([undefined]); + }); + }); + + describe('EQL', () => { + it('should generate 2 alerts with @timestamp', async () => { + const rule: EqlRuleCreateProps = getEqlRuleForAlertTesting(['myfa*']); + + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 2, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id]); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(2); + }); + + it('should generate 2 alerts when timestamp override does not exist', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['myfa*']), + timestamp_override: 'event.fakeingestfield', + }; + const { id } = await createRule(supertest, log, rule); + + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 2, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id, id]); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + const alertsOrderedByEventId = orderBy(alerts, 'alert.parent.id', 'asc'); + + expect(alertsOrderedByEventId.length).equal(2); + }); + + it('should not generate any alerts when timestamp override does not exist and timestamp fallback is disabled', async () => { + const rule: EqlRuleCreateProps = { + ...getEqlRuleForAlertTesting(['myfa*']), + timestamp_override: 'event.fakeingestfield', + timestamp_override_fallback_disabled: true, + }; + const createdRule = await createRule(supertest, log, rule); + const alertsOpen = await getOpenAlerts( + supertest, + log, + es, + createdRule, + RuleExecutionStatusEnum['partial failure'] + ); + expect(alertsOpen.hits.hits.length).eql(0); + }); + }); + }); + + describe('alerts generated from events with timestamp override field and ensures search_after continues to work when documents are missing timestamp override field', () => { + before(async () => { + await esArchiver.load(path); + }); + + after(async () => { + await esArchiver.unload(path); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + describe('KQL', () => { + /** + * This represents our worst case scenario where this field is not mapped on any index + * We want to check that our logic continues to function within the constraints of search after + * Elasticsearch returns java's long.MAX_VALUE for unmapped date fields + * Javascript does not support numbers this large, but without passing in a number of this size + * The search_after will continue to return the same results and not iterate to the next set + * So to circumvent this limitation of javascript we return the stringified version of Java's + * Long.MAX_VALUE so that search_after does not enter into an infinite loop. + * + * ref: https://github.com/elastic/elasticsearch/issues/28806#issuecomment-369303620 + */ + it('should generate 200 alerts when timestamp override does not exist', async () => { + const rule: QueryRuleCreateProps = { + ...getRuleForAlertTesting(['auditbeat-*']), + timestamp_override: 'event.fakeingested', + max_signals: 200, + }; + + const { id } = await createRule(supertest, log, rule); + await waitForRulePartialFailure({ + supertest, + log, + id, + }); + await waitForAlertsToBePresent(supertest, log, 200, [id]); + const alertsResponse = await getAlertsByIds(supertest, log, [id], 200); + const alerts = alertsResponse.hits.hits.map((hit) => hit._source); + + expect(alerts.length).equal(200); + }); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/README.md b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/README.md similarity index 100% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/README.md rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/README.md diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/ess.config.ts new file mode 100644 index 000000000000..787542036e08 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.trial') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine API Integration Tests - ESS - Telemetry', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/serverless.config.ts new file mode 100644 index 000000000000..99bd2458c69a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/configs/serverless.config.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine API Integration Tests - Serverless - Telemetry', + }, + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify(['previewTelemetryUrlEnabled'])}`, + ], +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/index.ts new file mode 100644 index 000000000000..5fef7869ba7c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Detection rule type telemetry', function () { + loadTestFile(require.resolve('./usage_collector/all_types')); + loadTestFile(require.resolve('./usage_collector/detection_rules')); + loadTestFile(require.resolve('./usage_collector/detection_rule_status')); + loadTestFile(require.resolve('./usage_collector/detection_rules_legacy_action')); + + loadTestFile(require.resolve('./task_based/all_types')); + loadTestFile(require.resolve('./task_based/detection_rules')); + loadTestFile(require.resolve('./task_based/security_lists')); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/all_types.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/all_types.ts new file mode 100644 index 000000000000..59da2429f01e --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/all_types.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getSecurityTelemetryStats, + removeTimeFieldsFromTelemetryStats, +} from '../../../utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const retry = getService('retry'); + const es = getService('es'); + + describe('@ess @serverless All task telemetry types generically', async () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await deleteAllExceptions(supertest, log); + }); + + it('@skipInQA should only have task metric values when no rules are running', async () => { + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats).to.eql({ + detection_rules: [ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ], + security_lists: [ + [ + { + name: 'Security Solution Lists Telemetry', + passed: true, + }, + ], + ], + endpoints: [ + [ + { + name: 'Security Solution Telemetry Endpoint Metrics and Info task', + passed: true, + }, + ], + ], + diagnostics: [ + [ + { + name: 'Security Solution Telemetry Diagnostics task', + passed: true, + }, + ], + ], + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/detection_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/detection_rules.ts new file mode 100644 index 000000000000..1298e9aeb9ea --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/detection_rules.ts @@ -0,0 +1,909 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +import expect from '@kbn/expect'; +import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common'; +import { + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + fetchRule, + getRuleForAlertTesting, + installMockPrebuiltRules, + getSecurityTelemetryStats, + createExceptionList, + createExceptionListItem, + removeTimeFieldsFromTelemetryStats, +} from '../../../utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const es = getService('es'); + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const retry = getService('retry'); + + describe('@ess @serverless Detection rule task telemetry', async () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await deleteAllExceptions(supertest, log); + }); + + describe('custom rules should never show any detection_rules telemetry data for each list type', () => { + it('@skipInQA should NOT give telemetry/stats for an exception list of type "detection"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'detection', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // Create the rule with the exception added to it + await createRule(supertest, log, { + ...rule, + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }); + + // Get the stats and ensure they're empty + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats.detection_rules).to.eql([ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ]); + }); + }); + + it('@skipInQA should NOT give telemetry/stats for an exception list of type "endpoint"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // Create the rule with the exception added to it + await createRule(supertest, log, { + ...rule, + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }); + + // Get the stats and ensure they're empty + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats.detection_rules).to.eql([ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ]); + }); + }); + + it('@skipInQA should NOT give telemetry/stats for an exception list of type "endpoint_trusted_apps"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_trusted_apps', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // Create the rule with the exception added to it + await createRule(supertest, log, { + ...rule, + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }); + + // Get the stats and ensure they're empty + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats.detection_rules).to.eql([ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ]); + }); + }); + + it('@skipInQA should NOT give telemetry/stats for an exception list of type "endpoint_events"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_events', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // Create the rule with the exception added to it + await createRule(supertest, log, { + ...rule, + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }); + + // Get the stats and ensure they're empty + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats.detection_rules).to.eql([ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ]); + }); + }); + + it('@skipInQA should NOT give telemetry/stats for an exception list of type "endpoint_host_isolation_exceptions"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_host_isolation_exceptions', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // Create the rule with the exception added to it + await createRule(supertest, log, { + ...rule, + exceptions_list: [ + { + id, + list_id, + namespace_type, + type, + }, + ], + }); + + // Get the stats and ensure they're empty + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + expect(stats.detection_rules).to.eql([ + [ + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ], + ]); + }); + }); + }); + + describe('@skipInQA pre-built/immutable/elastic rules should show detection_rules telemetry data for each list type', () => { + beforeEach(async () => { + // install prepackaged rules to get immutable rules for testing + await installMockPrebuiltRules(supertest, es); + }); + + it('should return mutating types such as "id", "@timestamp", etc... for list of type "detection"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'detection', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule using "PATCH" endpoint + const { exceptions_list } = await fetchRule(supertest, { + ruleId: ELASTIC_SECURITY_RULE_ID, + }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + expect(stats.detection_rules).length(2); + const detectionRule = stats.detection_rules[0][0]; + expect(detectionRule['@timestamp']).to.be.a('string'); + expect(detectionRule.cluster_uuid).to.be.a('string'); + expect(detectionRule.cluster_name).to.be.a('string'); + expect(detectionRule.license_id).to.be.a('string'); + expect(detectionRule.detection_rule.created_at).to.be.a('string'); + expect(detectionRule.detection_rule.id).to.be.a('string'); + }); + }); + + it('should give telemetry/stats for an exception list of type "detection"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'detection', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + + it('should give telemetry/stats for an exception list of type "endpoint"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + + it('should give telemetry/stats for an exception list of type "endpoint_trusted_apps"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_trusted_apps', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + + it('should give telemetry/stats for an exception list of type "endpoint_events"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_events', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + + it('should give telemetry/stats for an exception list of type "endpoint_host_isolation_exceptions"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'endpoint_host_isolation_exceptions', + }); + + // add 1 item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + }); + + describe('@skipInQA pre-built/immutable/elastic rules should show detection_rules telemetry data for multiple list items and types', () => { + beforeEach(async () => { + // install prepackaged rules to get immutable rules for testing + await installMockPrebuiltRules(supertest, es); + }); + + it('should give telemetry/stats for 2 exception lists to the type of "detection"', async () => { + // create an exception list container of type "detection" + const { id, list_id, namespace_type, type } = await createExceptionList(supertest, log, { + description: 'description', + list_id: '123', + name: 'test list', + type: 'detection', + }); + + // add 1st item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description 1', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something 1', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add 2nd item to the exception list + await createExceptionListItem(supertest, log, { + description: 'endpoint description 2', + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something 2', + }, + ], + list_id: '123', + name: 'endpoint_list', + os_types: [], + type: 'simple', + }); + + // add the exception list to the pre-built/immutable/elastic rule + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + await supertest + .patch(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send({ + rule_id: ELASTIC_SECURITY_RULE_ID, + exceptions_list: [ + ...immutableRule.exceptions_list, + { + id, + list_id, + namespace_type, + type, + }, + ], + }) + .expect(200); + + await retry.try(async () => { + const stats = await getSecurityTelemetryStats(supertest, log); + removeTimeFieldsFromTelemetryStats(stats); + const detectionRules = stats.detection_rules + .flat() + .map((obj: any) => (obj.passed != null ? obj : obj.detection_rule)) + .sort((obj1: { entries: { name: number } }, obj2: { entries: { name: number } }) => { + return obj1?.entries?.name - obj2?.entries?.name; + }); + + expect(detectionRules).to.eql([ + { + created_at: detectionRules[0].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something 2', + }, + ], + id: detectionRules[0].id, + name: 'endpoint description 2', + os_types: [], + rule_version: detectionRules[0].rule_version, + }, + { + created_at: detectionRules[1].created_at, + entries: [ + { + field: 'keyword', + operator: 'included', + type: 'match', + value: 'something 1', + }, + ], + id: detectionRules[1].id, + name: 'endpoint description 1', + os_types: [], + rule_version: detectionRules[1].rule_version, + }, + { + name: 'Security Solution Detection Rule Lists Telemetry', + passed: true, + }, + ]); + }); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/security_lists.ts similarity index 97% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/security_lists.ts index 50661a537472..3a4e8cb4c3ea 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/task_based/security_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/task_based/security_lists.ts @@ -11,19 +11,18 @@ import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID, } from '@kbn/securitysolution-list-constants'; -import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { - createSignalsIndex, + createAlertsIndex, deleteAllRules, deleteAllAlerts, getSecurityTelemetryStats, createExceptionListItem, createExceptionList, removeTimeFieldsFromTelemetryStats, -} from '../../../../utils'; -import { deleteAllExceptions } from '../../../../../lists_api_integration/utils'; +} from '../../../utils'; +import { deleteAllExceptions } from '../../../../lists_and_exception_lists/utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -32,7 +31,7 @@ export default ({ getService }: FtrProviderContext) => { const es = getService('es'); // Failing: See https://github.com/elastic/kibana/issues/164334 - describe.skip('Security lists task telemetry', async () => { + describe.skip('@ess @serverless Security lists task telemetry', async () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); }); @@ -42,7 +41,7 @@ export default ({ getService }: FtrProviderContext) => { }); beforeEach(async () => { - await createSignalsIndex(supertest, log); + await createAlertsIndex(supertest, log); // Calling stats endpoint once like this guarantees that the trusted applications and exceptions lists are created for us. await getSecurityTelemetryStats(supertest, log); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/all_types.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/all_types.ts new file mode 100644 index 000000000000..93e16cefa19f --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/all_types.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; + +import { createAlertsIndex, deleteAllRules, deleteAllAlerts, getStats } from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const retry = getService('retry'); + const es = getService('es'); + + describe('@ess @serverless @skipInQA Detection rule telemetry', async () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + }); + + it('should have initialized empty/zero values when no rules are running', async () => { + await retry.try(async () => { + const stats = await getStats(supertest, log); + expect(stats).to.eql(getInitialDetectionMetrics()); + }); + }); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rule_status.ts similarity index 96% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rule_status.ts index 233244ff5a05..6007c3d37c6d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rule_status.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rule_status.ts @@ -22,21 +22,20 @@ import { } from '@kbn/security-solution-plugin/server/usage/detections/rules/get_initial_usage'; import { createRule, - createSignalsIndex, + createAlertsIndex, deleteAllRules, deleteAllAlerts, - getEqlRuleForSignalTesting, - getRuleForSignalTesting, + getEqlRuleForAlertTesting, + getRuleForAlertTesting, getSimpleThreatMatch, getStats, - getThresholdRuleForSignalTesting, + getThresholdRuleForAlertTesting, waitForRuleSuccess, - waitForSignalsToBePresent, + waitForAlertsToBePresent, deleteAllEventLogExecutionEvents, -} from '../../../../utils'; -import type { FtrProviderContext } from '../../../../common/ftr_provider_context'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); @@ -46,7 +45,8 @@ export default ({ getService }: FtrProviderContext) => { // Note: We don't actually find signals well with ML tests at the moment so there are not tests for ML rule type for telemetry // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/132856 - describe('Detection rule status telemetry', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/171442 + describe.skip('@ess @serverless Detection rule status telemetry', async () => { before(async () => { // Just in case other tests do not clean up the event logs, let us clear them now and here only once. await deleteAllEventLogExecutionEvents(es, log); @@ -58,7 +58,7 @@ export default ({ getService }: FtrProviderContext) => { }); beforeEach(async () => { - await createSignalsIndex(supertest, log); + await createAlertsIndex(supertest, log); }); afterEach(async () => { @@ -67,13 +67,14 @@ export default ({ getService }: FtrProviderContext) => { await deleteAllEventLogExecutionEvents(es, log); }); - describe('"kql" rule type', () => { + // FLAKY: https://github.com/elastic/kibana/issues/171438 + describe.skip('"kql" rule type', () => { let stats: DetectionMetrics | undefined; before(async () => { - const rule = getRuleForSignalTesting(['telemetry']); + const rule = getRuleForAlertTesting(['telemetry']); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); + await waitForAlertsToBePresent(supertest, log, 4, [id]); // get the stats for all the tests where we at least have the expected "query" to reduce chances of flake by checking that at least one custom rule passed await retry.try(async () => { stats = await getStats(supertest, log); @@ -120,7 +121,7 @@ export default ({ getService }: FtrProviderContext) => { expect(stats?.detection_rules.detection_rule_usage).to.eql(expectedRuleUsage); }); - it('should have zero values for "detection_rule_status.all_rules" rules that are not query based', () => { + it('@skipInQA should have zero values for "detection_rule_status.all_rules" rules that are not query based', () => { expect(stats?.detection_rules.detection_rule_status.all_rules.eql).to.eql( getInitialSingleEventMetric() ); @@ -172,7 +173,7 @@ export default ({ getService }: FtrProviderContext) => { ); }); - it('should have non zero values for "index_duration"', () => { + it('@skipInQA should have non zero values for "index_duration"', () => { expect( stats?.detection_rules.detection_rule_status.custom_rules.query.index_duration.max ).to.be.above(1); @@ -205,11 +206,11 @@ export default ({ getService }: FtrProviderContext) => { ).to.be.above(1); }); - it('should have non zero values for "succeeded"', () => { + it('@skipInQA should have non zero values for "succeeded"', () => { expect(stats?.detection_rules.detection_rule_status.custom_rules.query.succeeded).to.eql(1); }); - it('should have non zero values for "succeeded", "index_duration", "search_duration" and "enrichment_duration"', () => { + it('@skipInQA should have non zero values for "succeeded", "index_duration", "search_duration" and "enrichment_duration"', () => { expect( stats?.detection_rules.detection_rule_status.custom_rules.query.index_duration.max ).to.be.above(1); @@ -257,10 +258,10 @@ export default ({ getService }: FtrProviderContext) => { describe('"eql" rule type', () => { let stats: DetectionMetrics | undefined; before(async () => { - const rule = getEqlRuleForSignalTesting(['telemetry']); + const rule = getEqlRuleForAlertTesting(['telemetry']); const { id } = await createRule(supertest, log, rule); await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); + await waitForAlertsToBePresent(supertest, log, 4, [id]); // get the stats for all the tests where we at least have the expected "query" to reduce chances of flake by checking that at least one custom rule passed await retry.try(async () => { stats = await getStats(supertest, log); @@ -445,7 +446,7 @@ export default ({ getService }: FtrProviderContext) => { let stats: DetectionMetrics | undefined; before(async () => { const rule: ThresholdRuleCreateProps = { - ...getThresholdRuleForSignalTesting(['telemetry']), + ...getThresholdRuleForAlertTesting(['telemetry']), threshold: { field: 'keyword', value: 1, @@ -453,7 +454,7 @@ export default ({ getService }: FtrProviderContext) => { }; const { id } = await createRule(supertest, log, rule); await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); + await waitForAlertsToBePresent(supertest, log, 4, [id]); // get the stats for all the tests where we at least have the expected "query" to reduce chances of flake by checking that at least one custom rule passed await retry.try(async () => { stats = await getStats(supertest, log); @@ -662,7 +663,7 @@ export default ({ getService }: FtrProviderContext) => { }; const { id } = await createRule(supertest, log, rule); await waitForRuleSuccess({ supertest, log, id }); - await waitForSignalsToBePresent(supertest, log, 4, [id]); + await waitForAlertsToBePresent(supertest, log, 4, [id]); // get the stats for all the tests where we at least have the expected "query" to reduce chances of flake by checking that at least one custom rule passed await retry.try(async () => { stats = await getStats(supertest, log); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules.ts new file mode 100644 index 000000000000..b81ced41b251 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules.ts @@ -0,0 +1,1337 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; +import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common'; +import { RulesTypeUsage } from '@kbn/security-solution-plugin/server/usage/detections/rules/types'; +import { + createLegacyRuleAction, + createWebHookRuleAction, + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + fetchRule, + getRuleForAlertTesting, + getRuleWithWebHookAction, + getSimpleMlRule, + getSimpleRule, + getSimpleThreatMatch, + getStats, + getThresholdRuleForAlertTesting, + installMockPrebuiltRules, + waitForRuleSuccess, + waitForAlertsToBePresent, + updateRule, + deleteAllEventLogExecutionEvents, + getRuleSavedObjectWithLegacyInvestigationFields, + getRuleSavedObjectWithLegacyInvestigationFieldsEmptyArray, + createRuleThroughAlertingEndpoint, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const retry = getService('retry'); + const es = getService('es'); + + describe('@ess @serverless Detection rule telemetry', async () => { + before(async () => { + // Just in case other tests do not clean up the event logs, let us clear them now and here only once. + await deleteAllEventLogExecutionEvents(es, log); + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await deleteAllEventLogExecutionEvents(es, log); + }); + + describe('"kql" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + describe('@brokenInServerless legacy investigation fields', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await createRuleThroughAlertingEndpoint( + supertest, + getRuleSavedObjectWithLegacyInvestigationFields() + ); + await createRuleThroughAlertingEndpoint( + supertest, + getRuleSavedObjectWithLegacyInvestigationFieldsEmptyArray() + ); + await createRule(supertest, log, { + ...getSimpleRule('rule-with-investigation-field'), + name: 'Test investigation fields object', + investigation_fields: { field_names: ['host.name'] }, + }); + }); + + afterEach(async () => { + await deleteAllRules(supertest, log); + }); + + it('should show "legacy_investigation_fields" to be greater than 0 when a rule has "investigation_fields" set to array or empty array', async () => { + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + alerts: 0, + enabled: 0, + disabled: 3, + legacy_investigation_fields: 2, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 0, + enabled: 0, + disabled: 3, + legacy_investigation_fields: 2, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + }); + + describe('"eql" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry'], 'rule-1', false); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry']); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry']); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"threshold" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + // Note: We don't actually find signals with these tests as we don't have a good way of signal finding with ML rules. + describe('"ml" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getSimpleMlRule(); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getSimpleMlRule('rule-1', true); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + enabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleMlRule(); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getSimpleMlRule('rule-1', true); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + enabled: 1, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleMlRule(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getSimpleMlRule('rule-1', true); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"indicator_match/threat_match" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getSimpleThreatMatch(); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule: ThreatMatchRuleCreateProps = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + legacy_investigation_fields: 0, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleThreatMatch(); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThreatMatchRuleCreateProps = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], + }; + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleThreatMatch(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThreatMatchRuleCreateProps = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"pre-packaged"/"immutable" rules', async () => { + it('@skipInQA should show stats for totals for in-active pre-packaged rules', async () => { + await installMockPrebuiltRules(supertest, es); + await retry.try(async () => { + const stats = await getStats(supertest, log); + expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0); + expect(stats.detection_rules.detection_rule_usage.elastic_total.disabled).above(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_detail.length).above(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql({ + enabled: 0, + disabled: 0, + alerts: 0, + cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_investigation_fields: 0, + }); + }); + }); + + it('@skipInQA should show stats for the detection_rule_details for a specific pre-packaged rule', async () => { + await installMockPrebuiltRules(supertest, es); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'A rule with an exception list', + rule_type: 'query', + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_legacy_notification: false, + has_notification: false, + has_legacy_investigation_field: false, + }); + }); + }); + + it('@skipInQA should show "notifications_disabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); + const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, false, newRuleToUpdate); + await updateRule(supertest, ruleToUpdate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: false, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: true, + has_legacy_notification: false, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('@skipInQA should show "notifications_enabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); + const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, true, newRuleToUpdate); + await updateRule(supertest, ruleToUpdate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: true, + has_legacy_notification: false, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(1); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_disabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, false); + await updateRule(supertest, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: false, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('@brokenInServerless should show "legacy_notifications_enabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, true); + await updateRule(supertest, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules_legacy_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules_legacy_action.ts new file mode 100644 index 000000000000..b0e40253bb8c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry/usage_collector/detection_rules_legacy_action.ts @@ -0,0 +1,512 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { getInitialDetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/get_initial_usage'; +import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common'; +import { RulesTypeUsage } from '@kbn/security-solution-plugin/server/usage/detections/rules/types'; +import { + createLegacyRuleAction, + createWebHookRuleAction, + createRule, + createAlertsIndex, + deleteAllRules, + deleteAllAlerts, + getEqlRuleForAlertTesting, + fetchRule, + getRuleForAlertTesting, + getRuleWithWebHookAction, + getSimpleMlRule, + getSimpleRule, + getSimpleThreatMatch, + getStats, + getThresholdRuleForAlertTesting, + installMockPrebuiltRules, + waitForRuleSuccess, + waitForAlertsToBePresent, + updateRule, + deleteAllEventLogExecutionEvents, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const log = getService('log'); + const retry = getService('retry'); + const es = getService('es'); + + describe('@ess Detection rule legacy actions telemetry', async () => { + before(async () => { + // Just in case other tests do not clean up the event logs, let us clear them now and here only once. + await deleteAllEventLogExecutionEvents(es, log); + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/telemetry'); + }); + + beforeEach(async () => { + await createAlertsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); + await deleteAllEventLogExecutionEvents(es, log); + }); + + describe('"kql" rule type', () => { + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const hookAction = await createWebHookRuleAction(supertest); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getRuleForAlertTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"eql" rule type', () => { + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getEqlRuleForAlertTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"threshold" rule type', () => { + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThresholdRuleCreateProps = { + ...getThresholdRuleForAlertTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + // Note: We don't actually find signals with these tests as we don't have a good way of signal finding with ML rules. + describe('"ml" rule type', () => { + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleMlRule(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getSimpleMlRule('rule-1', true); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.machine_learning, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"indicator_match/threat_match" rule type', () => { + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleThreatMatch(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThreatMatchRuleCreateProps = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createWebHookRuleAction(supertest); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccess({ supertest, log, id }); + await waitForAlertsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: RulesTypeUsage = { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }; + expect(stats.detection_rules.detection_rule_usage).to.eql(expected); + }); + }); + }); + + describe('"pre-packaged"/"immutable" rules', async () => { + it('should show "legacy_notifications_disabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, false); + await updateRule(supertest, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: false, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + await installMockPrebuiltRules(supertest, es); + const immutableRule = await fetchRule(supertest, { ruleId: ELASTIC_SECURITY_RULE_ID }); + const hookAction = await createWebHookRuleAction(supertest); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, true); + await updateRule(supertest, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === ELASTIC_SECURITY_RULE_ID + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + rule_version: ruleVersion, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, + has_legacy_investigation_field: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/ess.config.ts new file mode 100644 index 000000000000..59e01e74c719 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.trial') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine ESS - User roles API Integration Tests', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/serverless.config.ts new file mode 100644 index 000000000000..d8e9843c3eb9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/configs/serverless.config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine Serverless - User roles API Integration Tests', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/index.ts new file mode 100644 index 000000000000..7c1d0fe7cc75 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Detection User Roles APIs', function () { + loadTestFile(require.resolve('./read_privileges')); + }); +}; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/read_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/read_privileges.ts similarity index 98% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/read_privileges.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/read_privileges.ts index b95c6771367f..ee55d4ebfb33 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/read_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/user_roles/read_privileges.ts @@ -9,15 +9,17 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_PRIVILEGES_URL } from '@kbn/security-solution-plugin/common/constants'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { createUserAndRole, deleteUserAndRole } from '../../../common/services/security_solution'; +import { + createUserAndRole, + deleteUserAndRole, +} from '../../../../../common/services/security_solution'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('read_privileges', () => { + describe('@ess @serverless @brokenInServerless read_privileges', () => { it('should return expected privileges for elastic admin', async () => { const { body } = await supertest.get(DETECTION_ENGINE_PRIVILEGES_URL).send().expect(200); expect(body).to.eql({ diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_action.ts deleted file mode 100644 index 1ddce1f07114..000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_action.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RuleAction } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import type SuperTest from 'supertest'; - -import { getWebHookAction } from './get_web_hook_action'; - -/** - * Helper to cut down on the noise in some of the tests. This - * creates a new action and expects a 200 and does not do any retries. - * - * @param supertest The supertest deps - */ -export const createWebHookRuleAction = async ( - supertest: SuperTest.SuperTest -): Promise => { - return ( - await supertest - .post('/api/actions/action') - .set('kbn-xsrf', 'true') - .set('x-elastic-internal-origin', 'foo') - .send(getWebHookAction()) - .expect(200) - ).body; -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_webhook_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_webhook_action.ts new file mode 100644 index 000000000000..79ea9738372f --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/create_new_webhook_action.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common'; +import { RuleAction } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import type SuperTest from 'supertest'; + +import { getWebHookAction } from './get_web_hook_action'; + +/** + * Helper to cut down on the noise in some of the tests. This + * creates a new action and expects a 200 and does not do any retries. + * + * @param supertest The supertest deps + */ +export const createWebHookRuleAction = async ( + supertest: SuperTest.SuperTest +): Promise => { + return ( + await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'foo') + .send(getWebHookAction()) + .expect(200) + ).body; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/index.ts index f91323f94de5..9accb2b08928 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/index.ts @@ -6,5 +6,5 @@ */ export * from './get_slack_action'; export * from './get_web_hook_action'; -export * from './create_new_action'; +export * from './create_new_webhook_action'; export * from './legacy_actions'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/alert_assignees.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/alert_assignees.ts new file mode 100644 index 000000000000..59c70d5d6bd9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/alert_assignees.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AlertIds } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { SetAlertAssigneesRequestBody } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +export const setAlertAssignees = ({ + assigneesToAdd, + assigneesToRemove, + ids, +}: { + assigneesToAdd: string[]; + assigneesToRemove: string[]; + ids: AlertIds; +}): SetAlertAssigneesRequestBody => ({ + assignees: { + add: assigneesToAdd, + remove: assigneesToRemove, + }, + ids, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alert_status.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alert_status.ts new file mode 100644 index 000000000000..212aefd4593f --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alert_status.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getAlertStatus = () => ({ + aggs: { statuses: { terms: { field: 'kibana.alert.workflow_status', size: 10 } } }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_preview_alerts.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_preview_alerts.ts new file mode 100644 index 000000000000..744027c3fd4e --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_preview_alerts.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Client } from '@elastic/elasticsearch'; +import { ALERT_RULE_UUID } from '@kbn/rule-data-utils'; +import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { RiskEnrichmentFields } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/utils/enrichments/types'; +import { refreshIndex } from '../refresh_index'; + +/** + * Refresh an index, making changes available to search. + * Useful for tests where we want to ensure that a rule does NOT create alerts, e.g. testing exceptions. + * @param es The ElasticSearch handle + */ +export const getPreviewAlerts = async ({ + es, + previewId, + size, + sort, +}: { + es: Client; + previewId: string; + size?: number; + sort?: string[]; +}) => { + const index = '.preview.alerts-security.alerts-*'; + await refreshIndex(es, index); + const query = { + bool: { + filter: { + term: { + [ALERT_RULE_UUID]: previewId, + }, + }, + }, + }; + const result = await es.search({ + index, + size, + query, + sort, + }); + return result.hits.hits; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/index.ts index ce29837b34f6..867f85653ef4 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/index.ts @@ -14,9 +14,12 @@ export * from './get_open_alerts'; export * from './get_alerts_by_ids'; export * from './get_query_alerts_ids'; export * from './get_alerts_by_id'; -export * from './remove_random_valued_properties'; +export * from './remove_random_valued_properties_from_alert'; export * from './set_alert_status'; export * from './get_alert_status_empty_response'; export * from './get_query_alert_ids'; export * from './set_alert_tags'; +export * from './get_preview_alerts'; +export * from './get_alert_status'; +export * from './alert_assignees'; export * from './migrations'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties.ts deleted file mode 100644 index 8530c085e1a5..000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { ALERT_LAST_DETECTED, ALERT_START } from '@kbn/rule-data-utils'; - -export const removeRandomValuedProperties = (alert: DetectionAlert | undefined) => { - if (!alert) { - return undefined; - } - const { - 'kibana.version': version, - 'kibana.alert.rule.execution.uuid': execUuid, - 'kibana.alert.rule.uuid': uuid, - '@timestamp': timestamp, - 'kibana.alert.rule.created_at': createdAt, - 'kibana.alert.rule.updated_at': updatedAt, - 'kibana.alert.uuid': alertUuid, - [ALERT_START]: alertStart, - [ALERT_LAST_DETECTED]: lastDetected, - ...restOfAlert - } = alert; - return restOfAlert; -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties_from_alert.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties_from_alert.ts new file mode 100644 index 000000000000..3161fe1a61a6 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/remove_random_valued_properties_from_alert.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DetectionAlert } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ALERT_LAST_DETECTED, ALERT_START } from '@kbn/rule-data-utils'; + +export const removeRandomValuedPropertiesFromAlert = (alert: DetectionAlert | undefined) => { + if (!alert) { + return undefined; + } + const { + 'kibana.version': version, + 'kibana.alert.rule.execution.uuid': execUuid, + 'kibana.alert.rule.uuid': uuid, + '@timestamp': timestamp, + 'kibana.alert.rule.created_at': createdAt, + 'kibana.alert.rule.updated_at': updatedAt, + 'kibana.alert.uuid': alertUuid, + 'kibana.alert.url': alertURL, + [ALERT_START]: alertStart, + [ALERT_LAST_DETECTED]: lastDetected, + ...restOfAlert + } = alert; + return restOfAlert; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/delete_all_event_log_execution_events.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/delete_all_event_log_execution_events.ts new file mode 100644 index 000000000000..998033d18548 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/delete_all_event_log_execution_events.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ToolingLog } from '@kbn/tooling-log'; +import type { Client } from '@elastic/elasticsearch'; + +import { countDownES } from '../count_down_es'; + +/** + * Remove all .kibana-event-log-* documents with an execution.uuid + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param es The ElasticSearch handle + * @param log The tooling logger + */ +export const deleteAllEventLogExecutionEvents = async ( + es: Client, + log: ToolingLog +): Promise => { + return countDownES( + async () => { + return es.deleteByQuery( + { + index: '.kibana-event-log-*', + q: '_exists_:kibana.alert.rule.execution.uuid', + wait_for_completion: true, + refresh: true, + body: {}, + }, + { meta: true } + ); + }, + 'deleteAllEventLogExecutionEvents', + log + ); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/index.ts new file mode 100644 index 000000000000..c10ed51052bc --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/event_log/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export * from './delete_all_event_log_execution_events'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_detection_metrics_from_body.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_detection_metrics_from_body.ts new file mode 100644 index 000000000000..20febd5e9180 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_detection_metrics_from_body.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; + +/** + * Given a body this will return the detection metrics from it. + * @param body The Stats body + * @returns Detection metrics + */ +export const getDetectionMetricsFromBody = ( + body: Array<{ + stats: { + stack_stats: { + kibana: { plugins: { security_solution: { detectionMetrics: DetectionMetrics } } }; + }; + }; + }> +): DetectionMetrics => { + return body[0].stats.stack_stats.kibana.plugins.security_solution.detectionMetrics; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_stats.ts new file mode 100644 index 000000000000..9415f6900a54 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_stats.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ToolingLog } from '@kbn/tooling-log'; +import type SuperTest from 'supertest'; +import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; + +import { getStatsUrl } from './get_stats_url'; +import { getDetectionMetricsFromBody } from './get_detection_metrics_from_body'; + +/** + * Gets the stats from the stats endpoint. + * @param supertest The supertest agent. + * @returns The detection metrics + */ +export const getStats = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + const response = await supertest + .post(getStatsUrl()) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send({ unencrypted: true, refreshCache: true }); + if (response.status !== 200) { + log.error( + `Did not get an expected 200 "ok" when getting the stats for detections. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( + response.body + )}, status: ${JSON.stringify(response.status)}` + ); + } + + return getDetectionMetricsFromBody(response.body); +}; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_stats_url.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_stats_url.ts similarity index 100% rename from x-pack/test/detection_engine_api_integration/utils/get_stats_url.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/get_stats_url.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts index 9af5821d08ac..0b7c66f57cb2 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts @@ -9,12 +9,11 @@ export * from './exception_list_and_item'; export * from './alerts'; export * from './actions'; export * from './data_generator'; +export * from './telemetry'; +export * from './event_log'; +export * from './machine_learning'; -export * from './rules/get_rule_so_by_id'; -export * from './rules/create_rule_saved_object'; -export * from './rules/get_rule_with_legacy_investigation_fields'; export * from './get_index_name_from_load'; - export * from './count_down_test'; export * from './count_down_es'; export * from './update_username'; @@ -22,3 +21,6 @@ export * from './refresh_index'; export * from './wait_for'; export * from './route_with_namespace'; export * from './wait_for_index_to_populate'; +export * from './get_stats'; +export * from './get_detection_metrics_from_body'; +export * from './get_stats_url'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/index.ts new file mode 100644 index 000000000000..6d6870b7ac92 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export * from './machine_learning_setup'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/machine_learning_setup.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/machine_learning_setup.ts new file mode 100644 index 000000000000..d7c7e6387c73 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/machine_learning/machine_learning_setup.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; +import { getCommonRequestHeader } from '../../../../../functional/services/ml/common_api'; + +export const executeSetupModuleRequest = async ({ + module, + rspCode, + supertest, +}: { + module: string; + rspCode: number; + supertest: SuperTest.SuperTest; +}) => { + const { body } = await supertest + .post(`/internal/ml/modules/setup/${module}`) + .set(getCommonRequestHeader('1')) + .send({ + prefix: '', + groups: ['auditbeat'], + indexPatternName: 'auditbeat-*', + startDatafeed: false, + useDedicatedIndex: true, + applyToAllSpaces: true, + }) + .expect(rspCode); + + return body; +}; + +export const forceStartDatafeeds = async ({ + jobId, + rspCode, + supertest, +}: { + jobId: string; + rspCode: number; + supertest: SuperTest.SuperTest; +}) => { + const { body } = await supertest + .post(`/internal/ml/jobs/force_start_datafeeds`) + .set(getCommonRequestHeader('1')) + .send({ + datafeedIds: [`datafeed-${jobId}`], + start: new Date().getUTCMilliseconds(), + }) + .expect(rspCode); + + return body; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_legacy_rule_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_legacy_rule_action.ts new file mode 100644 index 000000000000..8e0cb59d5ee9 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_legacy_rule_action.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; + +import { UPDATE_OR_CREATE_LEGACY_ACTIONS } from '@kbn/security-solution-plugin/common/constants'; + +export const createLegacyRuleAction = async ( + supertest: SuperTest.SuperTest, + alertId: string, + connectorId: string +): Promise => + supertest + .post(UPDATE_OR_CREATE_LEGACY_ACTIONS) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '1') + .query({ alert_id: alertId }) + .send({ + name: 'Legacy notification with one action', + interval: '1h', + actions: [ + { + id: connectorId, + group: 'default', + params: { + message: 'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts', + }, + actionTypeId: '.slack', + }, + ], + }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule.ts index cd3fb09ced4e..ac6e44b2aab8 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; import type { @@ -35,7 +36,7 @@ export const createRule = async ( const response = await supertest .post(route) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '2023-10-31') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .send(rule); if (response.status === 409) { if (rule.rule_id != null) { diff --git a/x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule_with_auth.ts similarity index 100% rename from x-pack/test/detection_engine_api_integration/utils/create_rule_with_auth.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/create_rule_with_auth.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing.ts index d6d51ebb52d0..5649031185fe 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing.ts @@ -19,7 +19,7 @@ export const getRuleForAlertTesting = ( ruleId = 'rule-1', enabled = true ): QueryRuleCreateProps => ({ - name: 'Signal Testing Query', + name: 'Alert Testing Query', description: 'Tests a simple query', enabled, risk_score: 1, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing_with_timestamp_override.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing_with_timestamp_override.ts new file mode 100644 index 000000000000..86fc55bd2965 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_rule_for_alert_testing_with_timestamp_override.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +export const getRuleForAlertTestingWithTimestampOverride = ( + index: string[], + ruleId = 'rule-1', + enabled = true, + timestampOverride = 'event.ingested' +): QueryRuleCreateProps => ({ + name: 'Alert Testing Query', + description: 'Tests a simple query', + enabled, + risk_score: 1, + rule_id: ruleId, + severity: 'high', + index, + type: 'query', + query: '*:*', + timestamp_override: timestampOverride, + from: '1900-01-01T00:00:00.000Z', +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_ml_rule.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_ml_rule.ts new file mode 100644 index 000000000000..a8fe28d54f24 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_ml_rule.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +/** + * This is a representative ML rule payload as expected by the server + * @param ruleId The rule id + * @param enabled Set to tru to enable it, by default it is off + */ +export const getSimpleMlRule = (ruleId = 'rule-1', enabled = false): RuleCreateProps => ({ + name: 'Simple ML Rule', + description: 'Simple Machine Learning Rule', + enabled, + anomaly_threshold: 44, + risk_score: 1, + rule_id: ruleId, + severity: 'high', + machine_learning_job_id: ['some_job_id'], + type: 'machine_learning', +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_output_without_rule_id.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_output_without_rule_id.ts new file mode 100644 index 000000000000..56b5ab66773b --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_output_without_rule_id.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSimpleRuleOutput } from './get_simple_rule_output'; +import { RuleWithoutServerGeneratedProperties } from './remove_server_generated_properties'; + +/** + * This is the typical output of a simple rule that Kibana will output with all the defaults except + * for all the server generated properties such as created_by. Useful for testing end to end tests. + */ +export const getSimpleRuleOutputWithoutRuleId = ( + ruleId = 'rule-1' +): Omit => { + const rule = getSimpleRuleOutput(ruleId); + const { rule_id: rId, ...ruleWithoutRuleId } = rule; + return ruleWithoutRuleId; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_without_rule_id.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_without_rule_id.ts new file mode 100644 index 000000000000..ad6ab7803ec2 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_rule_without_rule_id.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { getSimpleRule } from './get_simple_rule'; + +/** + * This is a typical simple rule for testing that is easy for most basic testing + */ +export const getSimpleRuleWithoutRuleId = (): RuleCreateProps => { + const simpleRule = getSimpleRule(); + // eslint-disable-next-line @typescript-eslint/naming-convention + const { rule_id, ...ruleWithoutId } = simpleRule; + return ruleWithoutId; +}; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_threat_match.ts similarity index 100% rename from x-pack/test/detection_engine_api_integration/utils/get_simple_threat_match.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/get_simple_threat_match.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/index.ts index 3e22a15665fc..04c4cb778ef4 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/index.ts @@ -31,6 +31,16 @@ export * from './get_saved_query_rule_for_alert_testing'; export * from './get_rule_so_by_id'; export * from './create_rule_saved_object'; export * from './get_rule_with_legacy_investigation_fields'; +export * from './create_rule_with_auth'; +export * from './preview_rule'; +export * from './preview_rule_with_exception_entries'; +export * from './patch_rule'; export * from './generate_event'; +export * from './create_legacy_rule_action'; +export * from './get_simple_threat_match'; +export * from './get_simple_ml_rule'; +export * from './remove_server_generated_properties_including_rule_id'; +export * from './get_simple_rule_output_without_rule_id'; +export * from './get_simple_rule_without_rule_id'; export * from './prebuilt_rules'; diff --git a/x-pack/test/detection_engine_api_integration/utils/patch_rule.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/patch_rule.ts similarity index 100% rename from x-pack/test/detection_engine_api_integration/utils/patch_rule.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/patch_rule.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule.ts new file mode 100644 index 000000000000..ec060c407640 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; +import type { + RuleCreateProps, + PreviewRulesSchema, + RulePreviewLogs, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; + +import { DETECTION_ENGINE_RULES_PREVIEW } from '@kbn/security-solution-plugin/common/constants'; + +/** + * Runs the preview for a rule. Any generated alerts will be written to .preview.alerts. + * This is much faster than actually running the rule, and can also quickly simulate multiple + * consecutive rule runs, e.g. for ensuring that rule state is properly handled across runs. + * @param supertest The supertest deps + * @param rule The rule to create + */ +export const previewRule = async ({ + supertest, + rule, + invocationCount = 1, + timeframeEnd = new Date(), +}: { + supertest: SuperTest.SuperTest; + rule: RuleCreateProps; + invocationCount?: number; + timeframeEnd?: Date; +}): Promise<{ + previewId: string; + logs: RulePreviewLogs[]; + isAborted: boolean; +}> => { + const previewRequest: PreviewRulesSchema = { + ...rule, + invocationCount, + timeframeEnd: timeframeEnd.toISOString(), + }; + const response = await supertest + .post(DETECTION_ENGINE_RULES_PREVIEW) + .set('kbn-xsrf', 'true') + .set('elastic-api-version', '2023-10-31') + .send(previewRequest) + .expect(200); + return response.body; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule_with_exception_entries.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule_with_exception_entries.ts new file mode 100644 index 000000000000..fb5d480bbbff --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/preview_rule_with_exception_entries.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ToolingLog } from '@kbn/tooling-log'; +import type SuperTest from 'supertest'; +import type { NonEmptyEntriesArray, OsTypeArray } from '@kbn/securitysolution-io-ts-list-types'; +import type { RuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +import { + createContainerWithEntries, + createContainerWithEndpointEntries, +} from '../exception_list_and_item'; +import { previewRule } from './preview_rule'; + +/** + * Convenience testing function where you can pass in just the entries and you will + * get a rule created with the entries added to an exception list and exception list item + * all auto-created at once. + * @param supertest super test agent + * @param rule The rule to create and attach an exception list to + * @param entries The entries to create the rule and exception list from + * @param endpointEntries The endpoint entries to create the rule and exception list from + * @param osTypes The os types to optionally add or not to add to the container + */ +export const previewRuleWithExceptionEntries = async ({ + supertest, + log, + rule, + entries, + endpointEntries, + invocationCount, + timeframeEnd, +}: { + supertest: SuperTest.SuperTest; + log: ToolingLog; + rule: RuleCreateProps; + entries: NonEmptyEntriesArray[]; + endpointEntries?: Array<{ + entries: NonEmptyEntriesArray; + osTypes: OsTypeArray | undefined; + }>; + invocationCount?: number; + timeframeEnd?: Date; +}) => { + const maybeExceptionList = await createContainerWithEntries(supertest, log, entries); + const maybeEndpointList = await createContainerWithEndpointEntries( + supertest, + log, + endpointEntries ?? [] + ); + + return previewRule({ + supertest, + rule: { + ...rule, + exceptions_list: [...maybeExceptionList, ...maybeEndpointList], + }, + invocationCount, + timeframeEnd, + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/remove_server_generated_properties_including_rule_id.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/remove_server_generated_properties_including_rule_id.ts new file mode 100644 index 000000000000..1b57b5663ec2 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/rules/remove_server_generated_properties_including_rule_id.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine'; + +import { removeServerGeneratedProperties } from './remove_server_generated_properties'; + +/** + * This will remove server generated properties such as date times, etc... including the rule_id + * @param rule Rule to pass in to remove typical server generated properties + */ +export const removeServerGeneratedPropertiesIncludingRuleId = ( + rule: RuleResponse +): Partial => { + const ruleWithRemovedProperties = removeServerGeneratedProperties(rule); + // eslint-disable-next-line @typescript-eslint/naming-convention + const { rule_id, ...additionalRuledIdRemoved } = ruleWithRemovedProperties; + return additionalRuledIdRemoved; +}; diff --git a/x-pack/test/detection_engine_api_integration/utils/get_security_telemetry_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/get_security_telemetry_stats.ts similarity index 86% rename from x-pack/test/detection_engine_api_integration/utils/get_security_telemetry_stats.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/get_security_telemetry_stats.ts index 7eb00b7ff313..462cdecbb498 100644 --- a/x-pack/test/detection_engine_api_integration/utils/get_security_telemetry_stats.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/get_security_telemetry_stats.ts @@ -9,6 +9,10 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; import { SECURITY_TELEMETRY_URL } from '@kbn/security-solution-plugin/common/constants'; +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; /** * Gets the stats from the stats endpoint within specifically the security_solutions application. @@ -23,7 +27,8 @@ export const getSecurityTelemetryStats = async ( const response = await supertest .get(SECURITY_TELEMETRY_URL) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '1') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send({ unencrypted: true, refreshCache: true }); if (response.status !== 200) { log.error( diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/index.ts new file mode 100644 index 000000000000..c784edd7f618 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export * from './get_security_telemetry_stats'; +export * from './remove_time_fields_from_telemetry_stats'; diff --git a/x-pack/test/detection_engine_api_integration/utils/remove_time_fields_from_telemetry_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts similarity index 100% rename from x-pack/test/detection_engine_api_integration/utils/remove_time_fields_from_telemetry_stats.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/telemetry/remove_time_fields_from_telemetry_stats.ts diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/wait_for_index_to_populate.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/wait_for_index_to_populate.ts index 74e3e8a25376..ceba42efd179 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/wait_for_index_to_populate.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/wait_for_index_to_populate.ts @@ -7,7 +7,7 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type { Client } from '@elastic/elasticsearch'; -import { waitFor } from '../../../../detection_engine_api_integration/utils/wait_for'; +import { waitFor } from './wait_for'; /** * Waits for the given index to contain documents diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/asset_criticality.ts new file mode 100644 index 000000000000..de5f64aaaa3a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/asset_criticality.ts @@ -0,0 +1,205 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { + cleanRiskEngine, + cleanAssetCriticality, + assetCriticalityRouteHelpersFactory, + getAssetCriticalityDoc, + getAssetCriticalityIndex, +} from '../../utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const es = getService('es'); + const kibanaServer = getService('kibanaServer'); + const log = getService('log'); + const supertest = getService('supertest'); + const assetCriticalityRoutes = assetCriticalityRouteHelpersFactory(supertest); + + describe('@ess @serverless @skipInQA asset_criticality Asset Criticality APIs', () => { + beforeEach(async () => { + await cleanRiskEngine({ kibanaServer, es, log }); + await cleanAssetCriticality({ log, es }); + }); + + afterEach(async () => { + await cleanRiskEngine({ kibanaServer, es, log }); + await cleanAssetCriticality({ log, es }); + }); + + describe('initialisation of resources', () => { + it('should has index installed on status api call', async () => { + let assetCriticalityIndexExist; + + try { + assetCriticalityIndexExist = await es.indices.exists({ + index: getAssetCriticalityIndex(), + }); + } catch (e) { + assetCriticalityIndexExist = false; + } + + expect(assetCriticalityIndexExist).to.eql(false); + + const statusResponse = await assetCriticalityRoutes.status(); + + expect(statusResponse.body).to.eql({ + asset_criticality_resources_installed: true, + }); + + const assetCriticalityIndexResult = await es.indices.get({ + index: getAssetCriticalityIndex(), + }); + + expect( + assetCriticalityIndexResult['.asset-criticality.asset-criticality-default']?.mappings + ).to.eql({ + dynamic: 'strict', + properties: { + '@timestamp': { + type: 'date', + }, + criticality_level: { + type: 'keyword', + }, + id_field: { + type: 'keyword', + }, + id_value: { + type: 'keyword', + }, + updated_at: { + type: 'date', + }, + }, + }); + }); + }); + + describe('create', () => { + it('should correctly create asset criticality', async () => { + const assetCriticality = { + id_field: 'host.name', + id_value: 'host-01', + criticality_level: 'important', + }; + + const { body: result } = await assetCriticalityRoutes.upsert(assetCriticality); + + expect(result.id_field).to.eql('host.name'); + expect(result.id_value).to.eql('host-01'); + expect(result.criticality_level).to.eql('important'); + expect(result['@timestamp']).to.be.a('string'); + + const doc = await getAssetCriticalityDoc({ idField: 'host.name', idValue: 'host-01', es }); + + expect(doc).to.eql(result); + }); + + it('should return 400 if criticality is invalid', async () => { + const assetCriticality = { + id_field: 'host.name', + id_value: 'host-01', + criticality_level: 'invalid', + }; + + await assetCriticalityRoutes.upsert(assetCriticality, { + expectStatusCode: 400, + }); + }); + + it('should return 400 if id_field is invalid', async () => { + const assetCriticality = { + id_field: 'invalid', + id_value: 'host-01', + criticality_level: 'important', + }; + + await assetCriticalityRoutes.upsert(assetCriticality, { + expectStatusCode: 400, + }); + }); + }); + + describe('read', () => { + it('should correctly get asset criticality', async () => { + const assetCriticality = { + id_field: 'host.name', + id_value: 'host-02', + criticality_level: 'important', + }; + + await assetCriticalityRoutes.upsert(assetCriticality); + + const { body: result } = await assetCriticalityRoutes.get('host.name', 'host-02'); + + expect(result.id_field).to.eql('host.name'); + expect(result.id_value).to.eql('host-02'); + expect(result.criticality_level).to.eql('important'); + expect(result['@timestamp']).to.be.a('string'); + }); + + it('should return a 400 if id_field is invalid', async () => { + await assetCriticalityRoutes.get('invalid', 'host-02', { + expectStatusCode: 400, + }); + }); + }); + + describe('update', () => { + it('should correctly update asset criticality', async () => { + const assetCriticality = { + id_field: 'host.name', + id_value: 'host-01', + criticality_level: 'important', + }; + + const { body: createdDoc } = await assetCriticalityRoutes.upsert(assetCriticality); + const updatedAssetCriticality = { + id_field: 'host.name', + id_value: 'host-01', + criticality_level: 'very_important', + }; + + const { body: updatedDoc } = await assetCriticalityRoutes.upsert(updatedAssetCriticality); + + expect(updatedDoc.id_field).to.eql('host.name'); + expect(updatedDoc.id_value).to.eql('host-01'); + expect(updatedDoc.criticality_level).to.eql('very_important'); + expect(updatedDoc['@timestamp']).to.be.a('string'); + expect(updatedDoc['@timestamp']).to.not.eql(createdDoc['@timestamp']); + + const doc = await getAssetCriticalityDoc({ idField: 'host.name', idValue: 'host-01', es }); + + expect(doc).to.eql(updatedDoc); + }); + }); + + describe('delete', () => { + it('should correctly delete asset criticality', async () => { + const assetCriticality = { + id_field: 'host.name', + id_value: 'delete-me', + criticality_level: 'important', + }; + + await assetCriticalityRoutes.upsert(assetCriticality); + + await assetCriticalityRoutes.delete('host.name', 'delete-me'); + const doc = await getAssetCriticalityDoc({ + idField: 'host.name', + idValue: 'delete-me', + es, + }); + + expect(doc).to.eql(undefined); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts index bb4e078746d5..97686465c807 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts @@ -13,6 +13,15 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...functionalConfig.getAll(), + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'entityAnalyticsAssetCriticalityEnabled', + ])}`, + ], + }, testFiles: [require.resolve('..')], junit: { reportName: 'Entity Analytics API Integration Tests - ESS - Risk Engine', diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts index e28df5b9c350..ccbbcd9dc8cb 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts @@ -8,6 +8,11 @@ import { createTestConfig } from '../../../../../config/serverless/config.base'; export default createTestConfig({ + kbnTestServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'entityAnalyticsAssetCriticalityEnabled', + ])}`, + ], testFiles: [require.resolve('..')], junit: { reportName: 'Entity Analytics API Integration Tests - Serverless - Risk Engine', diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts index 878725cd32f9..a01e8ba9de52 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts @@ -15,5 +15,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./risk_scoring_task/task_execution')); loadTestFile(require.resolve('./risk_scoring_task/task_execution_nondefault_spaces')); loadTestFile(require.resolve('./telemetry_usage')); + loadTestFile(require.resolve('./risk_engine_privileges')); + loadTestFile(require.resolve('./asset_criticality')); }); } diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_engine_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_engine_privileges.ts new file mode 100644 index 000000000000..aa6a604dc0c3 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_engine_privileges.ts @@ -0,0 +1,222 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import expect from '@kbn/expect'; +import { riskEngineRouteHelpersFactoryNoAuth } from '../../utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +const USER_PASSWORD = 'changeme'; +const ROLES = [ + { + name: 'security_feature_read', + privileges: { + kibana: [ + { + feature: { + siem: ['read'], + }, + spaces: ['default'], + }, + ], + }, + }, + { + name: 'cluster_manage_index_templates', + privileges: { + elasticsearch: { + cluster: ['manage_index_templates'], + }, + }, + }, + { + name: 'cluster_manage_transform', + privileges: { + elasticsearch: { + cluster: ['manage_transform'], + }, + }, + }, + { + name: 'risk_score_index_read', + privileges: { + elasticsearch: { + indices: [ + { + names: ['risk-score.risk-score-*'], + privileges: ['read'], + }, + ], + }, + }, + }, + { + name: 'risk_score_index_write', + privileges: { + elasticsearch: { + indices: [ + { + names: ['risk-score.risk-score-*'], + privileges: ['write'], + }, + ], + }, + }, + }, +]; + +const ALL_ROLE_NAMES = ROLES.map((role) => role.name); + +const allRolesExcept = (role: string) => ALL_ROLE_NAMES.filter((r) => r !== role); + +const USERNAME_TO_ROLES = { + no_cluster_manage_index_templates: allRolesExcept('cluster_manage_index_templates'), + no_cluster_manage_transform: allRolesExcept('cluster_manage_transform'), + no_risk_score_index_read: allRolesExcept('risk_score_index_read'), + no_risk_score_index_write: allRolesExcept('risk_score_index_write'), + all: ALL_ROLE_NAMES, +}; + +export default ({ getService }: FtrProviderContext) => { + describe('@ess privileges_apis', () => { + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const riskEngineRoutesNoAuth = riskEngineRouteHelpersFactoryNoAuth(supertestWithoutAuth); + const security = getService('security'); + + const createRole = async ({ name, privileges }: { name: string; privileges: any }) => { + return await security.role.create(name, privileges); + }; + + const createUser = async ({ + username, + password, + roles, + }: { + username: string; + password: string; + roles: string[]; + }) => { + return await security.user.create(username, { + password, + roles, + full_name: username.replace('_', ' '), + email: `${username}@elastic.co`, + }); + }; + + async function createPrivilegeTestUsers() { + const rolePromises = ROLES.map((role) => createRole(role)); + + await Promise.all(rolePromises); + const userPromises = Object.entries(USERNAME_TO_ROLES).map(([username, roles]) => + createUser({ username, roles, password: USER_PASSWORD }) + ); + + return Promise.all(userPromises); + } + + const getPrivilegesForUsername = async (username: string) => + riskEngineRoutesNoAuth.privilegesForUser({ + username, + password: USER_PASSWORD, + }); + before(async () => { + await createPrivilegeTestUsers(); + }); + + describe('Risk engine privileges API', () => { + it('should return has_all_required true for user with all risk engine privileges', async () => { + const { body } = await getPrivilegesForUsername('all'); + expect(body.has_all_required).to.eql(true); + expect(body.privileges).to.eql({ + elasticsearch: { + cluster: { + manage_index_templates: true, + manage_transform: true, + }, + index: { + 'risk-score.risk-score-*': { + read: true, + write: true, + }, + }, + }, + }); + }); + it('should return has_all_required false for user with no write access to risk indices', async () => { + const { body } = await getPrivilegesForUsername('no_risk_score_index_write'); + expect(body.has_all_required).to.eql(false); + expect(body.privileges).to.eql({ + elasticsearch: { + cluster: { + manage_index_templates: true, + manage_transform: true, + }, + index: { + 'risk-score.risk-score-*': { + read: true, + write: false, + }, + }, + }, + }); + }); + it('should return has_all_required false for user with no read access to risk indices', async () => { + const { body } = await getPrivilegesForUsername('no_risk_score_index_read'); + expect(body.has_all_required).to.eql(false); + expect(body.privileges).to.eql({ + elasticsearch: { + cluster: { + manage_index_templates: true, + manage_transform: true, + }, + index: { + 'risk-score.risk-score-*': { + read: false, + write: true, + }, + }, + }, + }); + }); + it('should return has_all_required false for user with no cluster manage transform privilege', async () => { + const { body } = await getPrivilegesForUsername('no_cluster_manage_transform'); + expect(body.has_all_required).to.eql(false); + expect(body.privileges).to.eql({ + elasticsearch: { + cluster: { + manage_index_templates: true, + manage_transform: false, + }, + index: { + 'risk-score.risk-score-*': { + read: true, + write: true, + }, + }, + }, + }); + }); + it('should return has_all_required false for user with no cluster manage index templates privilege', async () => { + const { body } = await getPrivilegesForUsername('no_cluster_manage_index_templates'); + expect(body.has_all_required).to.eql(false); + expect(body.privileges).to.eql({ + elasticsearch: { + cluster: { + manage_index_templates: false, + manage_transform: true, + }, + index: { + 'risk-score.risk-score-*': { + read: true, + write: true, + }, + }, + }, + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts deleted file mode 100644 index 922a5d9d25b7..000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { GenericFtrProviderContext } from '@kbn/test'; - -import { SpacesServiceProvider } from '../../../../../../common/services/spaces'; -import { services as serverlessServices } from '../../../../../../../test_serverless/api_integration/services'; - -const services = { - ...serverlessServices, - spaces: SpacesServiceProvider, -}; -export type FtrProviderContextWithSpaces = GenericFtrProviderContext; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts index 53c70bc90efb..7ebfb568e8cd 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts @@ -179,7 +179,8 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('with some alerts containing hosts and others containing users', () => { + // FLAKY: https://github.com/elastic/kibana/issues/171132 + describe.skip('with some alerts containing hosts and others containing users', () => { let hostId: string; let userId: string; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts index cf9bf98f88d9..d869fae2f3f9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts @@ -23,7 +23,7 @@ import { deleteRiskScoreIndices, } from '../../../utils'; -import { FtrProviderContextWithSpaces } from './ftr_provider_context_with_spaces'; +import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; export default ({ getService }: FtrProviderContextWithSpaces): void => { const supertest = getService('supertest'); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts new file mode 100644 index 000000000000..9318bc7d7799 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import SuperTest from 'supertest'; +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; +import { + ASSET_CRITICALITY_STATUS_URL, + ASSET_CRITICALITY_URL, +} from '@kbn/security-solution-plugin/common/constants'; +import type { Client } from '@elastic/elasticsearch'; +import type { ToolingLog } from '@kbn/tooling-log'; +import querystring from 'querystring'; +import { routeWithNamespace } from '../../detections_response/utils'; + +export const getAssetCriticalityIndex = (namespace?: string) => + `.asset-criticality.asset-criticality-${namespace ?? 'default'}`; + +export const cleanAssetCriticality = async ({ + log, + es, + namespace = 'default', +}: { + log: ToolingLog; + es: Client; + namespace?: string; +}) => { + try { + await Promise.allSettled([ + es.indices.delete({ + index: [getAssetCriticalityIndex(namespace)], + }), + ]); + } catch (e) { + log.warning(`Error deleting asset criticality index: ${e.message}`); + } +}; + +export const getAssetCriticalityDoc = async (opts: { + es: Client; + idField: string; + idValue: string; +}) => { + const { es, idField, idValue } = opts; + try { + const doc = await es.get({ + index: getAssetCriticalityIndex(), + id: `${idField}:${idValue}`, + }); + + return doc._source; + } catch (e) { + return undefined; + } +}; + +export const assetCriticalityRouteHelpersFactory = ( + supertest: SuperTest.SuperTest, + namespace?: string +) => ({ + status: async () => + await supertest + .get(routeWithNamespace(ASSET_CRITICALITY_STATUS_URL, namespace)) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send() + .expect(200), + upsert: async ( + body: Record, + { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } + ) => + await supertest + .post(routeWithNamespace(ASSET_CRITICALITY_URL, namespace)) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(body) + .expect(expectStatusCode), + delete: async (idField: string, idValue: string) => { + const qs = querystring.stringify({ id_field: idField, id_value: idValue }); + const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`; + return supertest + .delete(route) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .expect(200); + }, + get: async ( + idField: string, + idValue: string, + { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } + ) => { + const qs = querystring.stringify({ id_field: idField, id_value: idValue }); + const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`; + return supertest + .get(route) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .expect(expectStatusCode); + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_metrics_from_body.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_metrics_from_body.ts new file mode 100644 index 000000000000..c8ec19e44840 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_metrics_from_body.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { RiskEngineMetrics } from '@kbn/security-solution-plugin/server/usage/risk_engine/types'; + +/** + * Given a body this will return the risk engine metrics from it. + * @param body The Stats body + * @returns Detection metrics + */ +export const getRiskEngineMetricsFromBody = ( + body: Array<{ + stats: { + stack_stats: { + kibana: { plugins: { security_solution: { riskEngineMetrics: {} } } }; + }; + }; + }> +): RiskEngineMetrics => { + return body[0].stats.stack_stats.kibana.plugins.security_solution.riskEngineMetrics; +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts index c5343372ce99..5629e0da9a89 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts @@ -7,44 +7,14 @@ import type { ToolingLog } from '@kbn/tooling-log'; import type SuperTest from 'supertest'; -import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types'; import type { RiskEngineMetrics } from '@kbn/security-solution-plugin/server/usage/risk_engine/types'; import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; -import { getStatsUrl } from '../../../../detection_engine_api_integration/utils/get_stats_url'; -import { - getDetectionMetricsFromBody, - getRiskEngineMetricsFromBody, -} from '../../../../detection_engine_api_integration/utils/get_detection_metrics_from_body'; - -/** - * Gets the stats from the stats endpoint. - * @param supertest The supertest agent. - * @returns The detection metrics - */ -export const getStats = async ( - supertest: SuperTest.SuperTest, - log: ToolingLog -): Promise => { - const response = await supertest - .post(getStatsUrl()) - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ unencrypted: true, refreshCache: true }); - if (response.status !== 200) { - log.error( - `Did not get an expected 200 "ok" when getting the stats for detections. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( - response.body - )}, status: ${JSON.stringify(response.status)}` - ); - } - - return getDetectionMetricsFromBody(response.body); -}; +import { getStatsUrl } from '../../detections_response/utils/get_stats_url'; +import { getRiskEngineMetricsFromBody } from './get_risk_engine_metrics_from_body'; /** * Gets the stats from the stats endpoint. diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts index 00eb2adafd2e..dacdf5052c91 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts @@ -6,3 +6,4 @@ */ export * from './risk_engine'; export * from './get_risk_engine_stats'; +export * from './asset_criticality'; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts index 48c7763d7a9d..103577482a77 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts @@ -21,6 +21,7 @@ import { RISK_ENGINE_DISABLE_URL, RISK_ENGINE_ENABLE_URL, RISK_ENGINE_STATUS_URL, + RISK_ENGINE_PRIVILEGES_URL, } from '@kbn/security-solution-plugin/common/constants'; import { createRule, @@ -504,6 +505,20 @@ export const riskEngineRouteHelpersFactory = ( .expect(200), }); +export const riskEngineRouteHelpersFactoryNoAuth = ( + supertestWithoutAuth: SuperTest.SuperTest, + namespace?: string +) => ({ + privilegesForUser: async ({ username, password }: { username: string; password: string }) => + await supertestWithoutAuth + .get(RISK_ENGINE_PRIVILEGES_URL) + .auth(username, password) + .set('elastic-api-version', '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send() + .expect(200), +}); + export const installLegacyRiskScore = async ({ supertest, }: { diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/ess.config.ts new file mode 100644 index 000000000000..366e0b956e37 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.trial') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine ESS - Execption Lists and Items Integration Tests APIS', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/serverless.config.ts new file mode 100644 index 000000000000..bb1410030e0d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/configs/serverless.config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine Serverless - Execption Lists and Items Integration Tests APIS', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/index.ts new file mode 100644 index 000000000000..b490143ff28b --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Exception Lists and Items API', function () { + loadTestFile(require.resolve('./items')); + loadTestFile(require.resolve('./lists')); + }); +} diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/create_exception_list_items.ts similarity index 92% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/create_exception_list_items.ts index ab4eb4d802fc..ad7c413a3c6a 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/create_exception_list_items.ts @@ -15,21 +15,21 @@ import { getCreateExceptionListItemMinimalSchemaMock, getCreateExceptionListItemMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { removeListItemServerGeneratedProperties, removeExceptionListItemServerGeneratedProperties, -} from '../../utils'; + deleteAllExceptions, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -import { deleteAllExceptions } from '../../utils'; - -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('create_exception_list_items', () => { + describe('@ess @serverless create_exception_list_items', () => { describe('validation errors', () => { it('should give a 404 error that the exception list must exist first before being able to add a list item to the exception list', async () => { const { body } = await supertest @@ -64,7 +64,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should create a match any exception item with multiple case sensitive values', async () => { @@ -93,7 +95,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql({ - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), entries, }); }); @@ -113,7 +115,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeListItemServerGeneratedProperties(body); const outputList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), item_id: body.item_id, }; expect(bodyToCompare).to.eql(outputList); @@ -163,7 +165,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); expect(bodyToCompare).to.eql({ - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), expire_time: datetime, }); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/delete_exception_list_items.ts similarity index 88% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/delete_exception_list_items.ts index 1a97ac6db4cb..4d3b2be7de27 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/delete_exception_list_items.ts @@ -15,16 +15,21 @@ import { getCreateExceptionListItemMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; +import { + deleteAllExceptions, + removeExceptionListItemServerGeneratedProperties, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('delete_exception_list_items', () => { + describe('@ess @serverless delete_exception_list_items', () => { describe('delete exception list items', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -56,7 +61,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should delete a single exception list item using an auto generated id', async () => { @@ -80,7 +87,7 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .expect(200); const outputtedList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), item_id: body.item_id, }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/find_exception_list_items.ts similarity index 90% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/find_exception_list_items.ts index 909930d71347..3fcbd476b754 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/find_exception_list_items.ts @@ -17,16 +17,21 @@ import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListDetectionSchemaMock, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; +import { + deleteAllExceptions, + removeExceptionListItemServerGeneratedProperties, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('find_exception_list_items', () => { + describe('@ess @serverless find_exception_list_items', () => { describe('find exception list items', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -104,7 +109,7 @@ export default ({ getService }: FtrProviderContext): void => { data: [ { comments: [], - created_by: 'elastic', + created_by: ELASTICSEARCH_USERNAME, description: 'some description', entries: [ { @@ -121,7 +126,7 @@ export default ({ getService }: FtrProviderContext): void => { os_types: ['windows'], tags: [], type: 'simple', - updated_by: 'elastic', + updated_by: ELASTICSEARCH_USERNAME, }, ], page: 1, @@ -171,7 +176,9 @@ export default ({ getService }: FtrProviderContext): void => { body.data = [removeExceptionListItemServerGeneratedProperties(body.data[0])]; expect(body).to.eql({ - data: [getExceptionListItemResponseMockWithoutAutoGeneratedValues()], + data: [ + getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + ], page: 1, per_page: 20, total: 1, diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/index.ts new file mode 100644 index 000000000000..df84a7a9ee3d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Lists API', function () { + loadTestFile(require.resolve('./create_exception_list_items')); + loadTestFile(require.resolve('./read_exception_list_items')); + loadTestFile(require.resolve('./update_exception_list_items')); + loadTestFile(require.resolve('./delete_exception_list_items')); + loadTestFile(require.resolve('./find_exception_list_items')); + }); +} diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/read_exception_list_items.ts similarity index 89% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/read_exception_list_items.ts index 42783a461ce7..a2cffa490194 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/read_exception_list_items.ts @@ -15,16 +15,20 @@ import { getCreateExceptionListItemMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; +import { + deleteAllExceptions, + removeExceptionListItemServerGeneratedProperties, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('read_exception_list_items', () => { + describe('@ess @serverless read_exception_list_items', () => { describe('reading exception list items', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -45,7 +49,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single exception list item using id', async () => { @@ -69,7 +75,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single list item with an auto-generated id', async () => { @@ -92,7 +100,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputtedList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), item_id: body.item_id, }; @@ -120,7 +128,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputtedList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), item_id: body.item_id, }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/update_exception_list_items.ts similarity index 97% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/update_exception_list_items.ts index cfb01154be85..6e0a1daa024e 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/items/update_exception_list_items.ts @@ -19,20 +19,21 @@ import { } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { getUpdateMinimalExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_exception_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties, removeExceptionListServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('update_exception_list_items', () => { + describe('@ess @serverless update_exception_list_items', () => { describe('update exception list items', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -252,7 +253,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', }; @@ -292,7 +293,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', item_id: body.item_id, }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/create_exception_lists.ts similarity index 86% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/create_exception_lists.ts index a3c71a8be2fc..da066b078b0c 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/create_exception_lists.ts @@ -14,16 +14,17 @@ import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('create_exception_lists', () => { + describe('@ess @serverless create_exception_lists', () => { describe('creating exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -37,7 +38,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should create a simple exception list without a list_id', async () => { @@ -49,7 +52,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeExceptionListServerGeneratedProperties(body); const outputtedList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), list_id: bodyToCompare.list_id, }; expect(bodyToCompare).to.eql(outputtedList); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/delete_exception_lists.ts similarity index 89% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/delete_exception_lists.ts index 5361bcb82f6a..ae109897fb13 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/delete_exception_lists.ts @@ -14,16 +14,18 @@ import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('delete_exception_lists', () => { + describe('@ess @serverless delete_exception_lists', () => { describe('delete exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -46,7 +48,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should delete a single exception list using an auto generated id', async () => { @@ -64,7 +68,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputtedList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), list_id: body.list_id, }; const bodyToCompare = removeExceptionListServerGeneratedProperties(body); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/duplicate_exception_list.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/duplicate_exception_list.ts similarity index 93% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/duplicate_exception_list.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/duplicate_exception_list.ts index 54e7a89042b0..14a4dcfb65ec 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/duplicate_exception_list.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/duplicate_exception_list.ts @@ -15,16 +15,18 @@ import { import { getExceptionResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListDetectionSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('duplicate_exception_lists', () => { + describe('@ess @serverless duplicate_exception_lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); }); @@ -48,7 +50,7 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeExceptionListServerGeneratedProperties(body); expect(bodyToCompare).to.eql({ - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), type: 'detection', list_id: body.list_id, name: `${getCreateExceptionListDetectionSchemaMock().name} [Duplicate]`, @@ -89,7 +91,7 @@ export default ({ getService }: FtrProviderContext) => { const listBodyToCompare = removeExceptionListServerGeneratedProperties(listBody); expect(listBodyToCompare).to.eql({ - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), type: 'detection', list_id: listBody.list_id, name: `${getCreateExceptionListDetectionSchemaMock().name} [Duplicate]`, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_exception_list.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/export_exception_list.ts similarity index 97% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/export_exception_list.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/export_exception_list.ts index bfde054eb8f1..726ec6269508 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_exception_list.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/export_exception_list.ts @@ -11,20 +11,19 @@ import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysoluti import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { removeExceptionListServerGeneratedProperties, removeExceptionListItemServerGeneratedProperties, binaryToString, deleteAllExceptions, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - describe('export_exception_list_route', () => { + describe('@ess @serverless export_exception_list_route', () => { describe('exporting exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/find_exception_lists.ts similarity index 87% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/find_exception_lists.ts index 349a44c50694..cb405b7b7d64 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/find_exception_lists.ts @@ -10,16 +10,17 @@ import expect from '@kbn/expect'; import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('find_exception_lists', () => { + describe('@ess @serverless find_exception_lists', () => { describe('find exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -57,7 +58,7 @@ export default ({ getService }: FtrProviderContext): void => { body.data = [removeExceptionListServerGeneratedProperties(body.data[0])]; expect(body).to.eql({ - data: [getExceptionResponseMockWithoutAutoGeneratedValues()], + data: [getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME)], page: 1, per_page: 20, total: 1, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/get_exception_filter.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/get_exception_filter.ts similarity index 92% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/get_exception_filter.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/get_exception_filter.ts index 913ce14db1f0..633262ca1baa 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/get_exception_filter.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/get_exception_filter.ts @@ -6,7 +6,10 @@ */ import expect from '@kbn/expect'; - +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; import { INTERNAL_EXCEPTION_FILTER, EXCEPTION_LIST_URL, @@ -18,16 +21,16 @@ import { } from '@kbn/lists-plugin/common/schemas/request/get_exception_filter_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMockWithoutId } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListDetectionSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { createListsIndex, deleteListsIndex } from '../../utils'; +import { createListsIndex, deleteListsIndex } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - describe('get_exception_filter', () => { + describe('@ess @serverless get_exception_filter', () => { describe('get exception filter', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -41,7 +44,8 @@ export default ({ getService }: FtrProviderContext): void => { const { body } = await supertest .post(`${INTERNAL_EXCEPTION_FILTER}`) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send(getExceptionFilterFromExceptionItemsSchemaMock()) .expect(200); @@ -122,7 +126,8 @@ export default ({ getService }: FtrProviderContext): void => { const { body } = await supertest .post(`${INTERNAL_EXCEPTION_FILTER}`) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send(getExceptionFilterFromExceptionIdsSchemaMock()) .expect(200); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_exceptions.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/import_exceptions.ts similarity index 99% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/import_exceptions.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/import_exceptions.ts index 8736ad75eeb6..bc191618914d 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_exceptions.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/import_exceptions.ts @@ -14,15 +14,15 @@ import { getImportExceptionsListItemSchemaMock, getImportExceptionsListSchemaMock, } from '@kbn/lists-plugin/common/schemas/request/import_exceptions_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions } from '../../utils'; +import { deleteAllExceptions } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - describe('import_exceptions', () => { + describe('@ess @serverless import_exceptions', () => { beforeEach(async () => { await deleteAllExceptions(supertest, log); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/index.ts new file mode 100644 index 000000000000..0e27b93b93b6 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Lists API', function () { + loadTestFile(require.resolve('./duplicate_exception_list')); + loadTestFile(require.resolve('./get_exception_filter')); + loadTestFile(require.resolve('./import_exceptions')); + loadTestFile(require.resolve('./export_exception_list')); + loadTestFile(require.resolve('./create_exception_lists')); + loadTestFile(require.resolve('./read_exception_lists')); + loadTestFile(require.resolve('./update_exception_lists')); + loadTestFile(require.resolve('./delete_exception_lists')); + loadTestFile(require.resolve('./find_exception_lists')); + loadTestFile(require.resolve('./summary_exception_lists')); + }); +} diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/read_exception_lists.ts similarity index 87% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/read_exception_lists.ts index 31293e97cb07..b2061928e175 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/read_exception_lists.ts @@ -14,16 +14,18 @@ import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListMinimalSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('read_exception_lists', () => { + describe('@ess @serverless read_exception_lists', () => { describe('reading exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -43,7 +45,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single exception list using id', async () => { @@ -60,7 +64,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeExceptionListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single list with an auto-generated list_id', async () => { @@ -77,7 +83,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputtedList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), list_id: body.list_id, }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/summary_exception_lists.ts similarity index 95% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/summary_exception_lists.ts index d5848e7ee44b..2c0c9780714f 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/summary_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/summary_exception_lists.ts @@ -12,18 +12,18 @@ import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysoluti import { LIST_ID } from '@kbn/lists-plugin/common/constants.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { createListsIndex, deleteListsIndex, deleteAllExceptions } from '../../utils'; +import { createListsIndex, deleteListsIndex, deleteAllExceptions } from '../../../utils'; interface SummaryResponseType { body: ExceptionListSummarySchema; } -// eslint-disable-next-line import/no-default-export +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); - describe('summary_exception_lists', () => { + describe('@ess @serverless summary_exception_lists', () => { describe('summary exception lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/update_exception_lists.ts similarity index 94% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/update_exception_lists.ts index d4c5cd422e77..1a5aed16b128 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/exception_lists_items/lists/update_exception_lists.ts @@ -15,16 +15,18 @@ import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { getUpdateMinimalExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_exception_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('update_exception_lists', () => { + describe('@ess @serverless update_exception_lists', () => { describe('update exception lists', () => { afterEach(async () => { await deleteAllExceptions(supertest, log); @@ -51,7 +53,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', version: 2, }; @@ -84,7 +86,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', list_id: body.list_id, version: 2, @@ -116,7 +118,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getExceptionResponseMockWithoutAutoGeneratedValues(), + ...getExceptionResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', description: 'some other description', version: 2, diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/ess.config.ts new file mode 100644 index 000000000000..522c44b41d85 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/ess.config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile( + require.resolve('../../../../../config/ess/config.base.trial') + ); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine ESS - Lists and Items Integration Tests APIS', + }, + }; +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/serverless.config.ts new file mode 100644 index 000000000000..7e324d6e2983 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/configs/serverless.config.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../../../../config/serverless/config.base'; + +export default createTestConfig({ + testFiles: [require.resolve('..')], + junit: { + reportName: 'Detection Engine Serverless - Lists and Items Integration Tests APIS', + }, +}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/index.ts new file mode 100644 index 000000000000..9422d4b2315f --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Lists and Items API', function () { + loadTestFile(require.resolve('./items')); + loadTestFile(require.resolve('./lists')); + }); +} diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/create_list_items.ts similarity index 86% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/create_list_items.ts index 40be89af0284..f174fdff3f77 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/create_list_items.ts @@ -16,20 +16,21 @@ import { getCreateMinimalListItemSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - import { createListsIndex, deleteListsIndex, removeListItemServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('create_list_items', () => { + describe('@ess @serverless create_list_items', () => { describe('validation errors', () => { it('should give a 404 error that the list must exist first before being able to add a list item', async () => { const { body } = await supertest @@ -68,7 +69,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should create a simple list item without an id', async () => { @@ -85,7 +88,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should cause a 409 conflict if we attempt to create the same list item twice', async () => { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/delete_list_items.ts similarity index 85% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/delete_list_items.ts index d317e647174f..f17d950a10dc 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/delete_list_items.ts @@ -11,20 +11,21 @@ import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListItemServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('delete_list_items', () => { + describe('@ess @serverless delete_list_items', () => { describe('deleting list items', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -56,7 +57,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should delete a single list using an auto generated id', async () => { @@ -81,7 +84,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should return an error if the id does not exist when trying to delete it', async () => { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/export_list_items.ts similarity index 95% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/export_list_items.ts index fe471e2794b4..b9c99a49af93 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/export_list_items.ts @@ -11,16 +11,16 @@ import { LIST_ITEM_URL, LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { LIST_ID, NAME } from '@kbn/lists-plugin/common/constants.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { createListsIndex, deleteListsIndex, binaryToString } from '../../utils'; +import { createListsIndex, deleteListsIndex, binaryToString } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - describe('export_list_items', () => { + describe('@ess @serverless export_list_items', () => { describe('exporting lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/find_list_items.ts similarity index 92% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/find_list_items.ts index c4ecce7d4d0e..0c8aa8aa50fa 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/find_list_items.ts @@ -12,20 +12,22 @@ import { LIST_ITEM_ID, LIST_ID } from '@kbn/lists-plugin/common/constants.mock'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListItemServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('find_list_items', () => { + describe('@ess @serverless find_list_items', () => { describe('find list items', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -107,7 +109,7 @@ export default ({ getService }: FtrProviderContext): void => { // cursor is a constant changing value so we have to delete it as well. delete body.cursor; expect(body).to.eql({ - data: [getListItemResponseMockWithoutAutoGeneratedValues()], + data: [getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME)], page: 1, per_page: 20, total: 1, diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items.ts new file mode 100644 index 000000000000..99a96ae9052b --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { ListSchema, ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; +import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; +import { getImportListItemAsBuffer } from '@kbn/lists-plugin/common/schemas/request/import_list_item_schema.mock'; + +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, + removeListItemServerGeneratedProperties, + waitFor, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + + describe('@ess @serverless import_list_items', () => { + describe('importing list items without an index', () => { + it('should not import a list item if the index does not exist yet', async () => { + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(400); + + expect(body).to.eql({ + status_code: 400, + message: + 'To import a list item, the data steam must exist first. Data stream ".lists-default" does not exist', + }); + }); + }); + + describe('importing lists with an index', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should set the response content types to be expected when importing two items', async () => { + await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('should report that it imported a simple list successfully', async () => { + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + + const bodyToCompare = removeListServerGeneratedProperties(body); + const outputtedList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + name: 'list_items.txt', + description: 'File uploaded from file system of list_items.txt', + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should be able to read imported list items back out correctly', async () => { + await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect(200); + + // Although we try to be aggressive with waitFor in the lists code base, there is still not guarantees + // that we will have the data just yet so we have to do a waitFor here for when it shows up + await waitFor( + async () => { + const { status } = await supertest + .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) + .send(); + return status !== 404; + }, + `${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`, + log + ); + const { body } = await supertest + .get(`${LIST_ITEM_URL}?list_id=list_items.txt&value=127.0.0.1`) + .send() + .expect(200); + + const bodyToCompare = removeListItemServerGeneratedProperties(body[0]); + const outputtedList: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + list_id: 'list_items.txt', + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items_migrations.ts new file mode 100644 index 000000000000..cd614bd07e35 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/import_list_items_migrations.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { ListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; +import { getImportListItemAsBuffer } from '@kbn/lists-plugin/common/schemas/request/import_list_item_schema.mock'; + +import { + deleteListsIndex, + removeListServerGeneratedProperties, + createListsIndices, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + + describe('@ess import_list_items_migrations', () => { + describe('import list to legacy index and migrate it', () => { + describe('legacy index (before migration to data streams)', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should import list to legacy index and migrate it', async () => { + // create legacy indices + await createListsIndices(es); + + const { body } = await supertest + .post(`${LIST_ITEM_URL}/_import?type=ip`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(['127.0.0.1', '127.0.0.2']), 'list_items.txt') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + + const bodyToCompare = removeListServerGeneratedProperties(body); + const outputtedList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + name: 'list_items.txt', + description: 'File uploaded from file system of list_items.txt', + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/index.ts new file mode 100644 index 000000000000..d89f7ca5566d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Lists API', function () { + loadTestFile(require.resolve('./create_list_items')); + loadTestFile(require.resolve('./patch_list_items')); + loadTestFile(require.resolve('./patch_list_items_migrations')); + loadTestFile(require.resolve('./read_list_items')); + loadTestFile(require.resolve('./update_list_items')); + loadTestFile(require.resolve('./update_list_items_migrations')); + loadTestFile(require.resolve('./delete_list_items')); + loadTestFile(require.resolve('./find_list_items')); + loadTestFile(require.resolve('./import_list_items')); + loadTestFile(require.resolve('./import_list_items_migrations')); + loadTestFile(require.resolve('./export_list_items')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items.ts new file mode 100644 index 000000000000..01a9d332ba35 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items.ts @@ -0,0 +1,221 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { + PatchListItemSchema, + CreateListItemSchema, + ListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; +import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; +import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; +import { getUpdateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_item_schema.mock'; + +import { + createListsIndex, + deleteListsIndex, + removeListItemServerGeneratedProperties, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const retry = getService('retry'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + + describe('@ess @serverless patch_list_items', () => { + describe('patch list items', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should patch a single list item property of value using an id', async () => { + const listItemId = getCreateMinimalListItemSchemaMock().id as string; + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a simple list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // patch a simple list item's value + const patchListItemPayload: PatchListItemSchema = { + id: listItemId, + value: '192.168.0.2', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchListItemPayload); + + const outputListItem: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + value: '192.168.0.2', + }; + const bodyToCompare = removeListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputListItem); + + await retry.waitFor('updates should be persistent', async () => { + const { body: listItemBody } = await supertest + .get(LIST_ITEM_URL) + .query({ id: getCreateMinimalListItemSchemaMock().id }) + .set('kbn-xsrf', 'true'); + + expect(removeListItemServerGeneratedProperties(listItemBody)).to.eql(outputListItem); + return true; + }); + }); + + it('should patch a single list item of value using an auto-generated id of both list and list item', async () => { + const { id, ...listNoId } = getCreateMinimalListSchemaMock(); + // create a simple list with no id which will use an auto-generated id + const { body: createListBody } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(200); + + // create a simple list item also with an auto-generated id using the list's auto-generated id + const listItem: CreateListItemSchema = { + ...getCreateMinimalListItemSchemaMock(), + list_id: createListBody.id, + }; + const { body: createListItemBody } = await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(listItem) + .expect(200); + + // patch a simple list item's value + const patchListItemPayload: PatchListItemSchema = { + id: createListItemBody.id, + value: '192.168.0.2', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchListItemPayload) + .expect(200); + + const outputListItem: Partial = { + ...getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + value: '192.168.0.2', + }; + const bodyToCompare = { + ...removeListItemServerGeneratedProperties(body), + list_id: outputListItem.list_id, + }; + expect(bodyToCompare).to.eql(outputListItem); + + await retry.waitFor('updates should be persistent', async () => { + const { body: listItemBody } = await supertest + .get(LIST_ITEM_URL) + .query({ id: createListItemBody.id }) + .set('kbn-xsrf', 'true'); + const listItemBodyToCompare = { + ...removeListItemServerGeneratedProperties(listItemBody), + list_id: outputListItem.list_id, + }; + expect(listItemBodyToCompare).to.eql(outputListItem); + return true; + }); + }); + + it('should not remove unspecified in patch payload meta property', async () => { + const listItemId = getCreateMinimalListItemSchemaMock().id as string; + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a simple list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send({ ...getCreateMinimalListItemSchemaMock(), meta: { test: true } }) + .expect(200); + + // patch a simple list item's value + const patchListItemPayload: PatchListItemSchema = { + id: listItemId, + value: '192.168.0.2', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchListItemPayload); + + expect(body.meta).to.eql({ test: true }); + + await retry.waitFor('updates should be persistent', async () => { + const { body: listItemBody } = await supertest + .get(LIST_ITEM_URL) + .query({ id: getCreateMinimalListItemSchemaMock().id }) + .set('kbn-xsrf', 'true'); + + expect(listItemBody.meta).to.eql({ test: true }); + return true; + }); + }); + + it('should give a 404 if it is given a fake id', async () => { + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // create a simple list item + await supertest + .post(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListItemSchemaMock()) + .expect(200); + + // patch a simple list item's value + const patchListItemPayload: PatchListItemSchema = { + ...getUpdateMinimalListItemSchemaMock(), + id: 'some-other-id', + value: '192.168.0.2', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchListItemPayload) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list item id: "some-other-id" not found', + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items_migrations.ts new file mode 100644 index 000000000000..8e0ee81414fa --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/patch_list_items_migrations.ts @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { PatchListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; + +import { + createListsIndex, + deleteListsIndex, + createListsIndices, + createListBypassingChecks, + createListItemBypassingChecks, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess patch_list_items_migrations', () => { + describe('patch list items', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + describe('legacy list items index (list created before migration to data stream)', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + it('should patch list item that was created in legacy index and migrated through LIST_INDEX request', async () => { + const listId = 'random-list'; + const listItemId = 'random-list-item'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); + // migrates old indices to data streams + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); + + const patchPayload: PatchListItemSchema = { + id: listItemId, + value: 'new one', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchPayload) + .expect(200); + + expect(body.value).to.be('new one'); + }); + + it('should patch list item that was created in legacy index and not yet migrated', async () => { + const listId = 'random-list'; + const listItemId = 'random-list-item'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); + + const patchPayload: PatchListItemSchema = { + id: listItemId, + value: 'new one', + }; + + const { body } = await supertest + .patch(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(patchPayload) + .expect(200); + + expect(body.value).to.be('new one'); + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/read_list_items.ts similarity index 85% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/read_list_items.ts index dc99e9d4d180..b0005ccb3fc0 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/read_list_items.ts @@ -11,20 +11,22 @@ import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListItemServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('read_list_items', () => { + describe('@ess @serverless read_list_items', () => { describe('reading list items', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -53,7 +55,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single list item with an auto-generated list id', async () => { @@ -75,7 +79,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListItemServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListItemResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should return 404 if given a fake id', async () => { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items.ts similarity index 80% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items.ts index e2bcddeb2484..90d246d14186 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items.ts @@ -12,30 +12,27 @@ import type { CreateListItemSchema, ListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { LIST_URL, LIST_ITEM_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getUpdateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_item_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListItemServerGeneratedProperties, - createListsIndices, - createListBypassingChecks, - createListItemBypassingChecks, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); const retry = getService('retry'); - const es = getService('es'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('update_list_items', () => { + describe('@ess @serverless update_list_items', () => { describe('update list items', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -72,7 +69,7 @@ export default ({ getService }: FtrProviderContext) => { .send(updatedListItem); const outputListItem: Partial = { - ...getListItemResponseMockWithoutAutoGeneratedValues(), + ...getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), value: '192.168.0.2', }; const bodyToCompare = removeListItemServerGeneratedProperties(body); @@ -122,7 +119,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputListItem: Partial = { - ...getListItemResponseMockWithoutAutoGeneratedValues(), + ...getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), value: '192.168.0.2', }; const bodyToCompare = { @@ -305,63 +302,6 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); }); }); - - describe('legacy list items index (list created before migration to data stream)', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - it('should update list item that was created in legacy index and migrated through LIST_INDEX request', async () => { - const listId = 'random-list'; - const listItemId = 'random-list-item'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); - // migrates old indices to data streams - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); - - const updatedListItem: UpdateListItemSchema = { - id: listItemId, - value: 'new one', - }; - - const { body } = await supertest - .put(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(updatedListItem) - .expect(200); - - expect(body.value).to.be('new one'); - }); - - it('should update list item that was created in legacy index and not yet migrated', async () => { - const listId = 'random-list'; - const listItemId = 'random-list-item'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); - - const updatedListItem: UpdateListItemSchema = { - id: listItemId, - value: 'new one', - }; - - const { body } = await supertest - .put(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(updatedListItem) - .expect(200); - - expect(body.value).to.be('new one'); - }); - }); }); }); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items_migrations.ts new file mode 100644 index 000000000000..06296ed60589 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/items/update_list_items_migrations.ts @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { UpdateListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; + +import { + createListsIndex, + deleteListsIndex, + createListsIndices, + createListBypassingChecks, + createListItemBypassingChecks, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess update_list_items_migrations', () => { + describe('update list items', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + describe('legacy list items index (list created before migration to data stream)', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + it('should update list item that was created in legacy index and migrated through LIST_INDEX request', async () => { + const listId = 'random-list'; + const listItemId = 'random-list-item'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); + // migrates old indices to data streams + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); + + const updatedListItem: UpdateListItemSchema = { + id: listItemId, + value: 'new one', + }; + + const { body } = await supertest + .put(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedListItem) + .expect(200); + + expect(body.value).to.be('new one'); + }); + + it('should update list item that was created in legacy index and not yet migrated', async () => { + const listId = 'random-list'; + const listItemId = 'random-list-item'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + await createListItemBypassingChecks({ es, listId, id: listItemId, value: 'random' }); + + const updatedListItem: UpdateListItemSchema = { + id: listItemId, + value: 'new one', + }; + + const { body } = await supertest + .put(LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedListItem) + .expect(200); + + expect(body.value).to.be('new one'); + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists.ts similarity index 81% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists.ts index b64f9d4206db..8cd7517c9efe 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists.ts @@ -13,20 +13,22 @@ import { getCreateMinimalListSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('create_lists', () => { + describe('@ess @serverless create_lists', () => { describe('creating lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -44,7 +46,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should create a simple list without a list_id', async () => { @@ -55,7 +59,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should cause a 409 conflict if we attempt to create the same list_id twice', async () => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index.ts new file mode 100644 index 000000000000..bb9167f4ba8a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; + +import { deleteListsIndex } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless create_list_index_route', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should create lists data streams', async () => { + const { body: fetchedIndices } = await supertest + .get(LIST_INDEX) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(fetchedIndices).to.eql({ + message: 'data stream .lists-default and data stream .items-default does not exist', + status_code: 404, + }); + + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); + + const { body } = await supertest.get(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); + + expect(body).to.eql({ list_index: true, list_item_index: true }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index_migrations.ts new file mode 100644 index 000000000000..4cd8b1afd74a --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/create_lists_index_migrations.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { getTemplateExists, getIndexTemplateExists } from '@kbn/securitysolution-es-utils'; + +import { createLegacyListsIndices, deleteListsIndex } from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess create_list_index_route_migrations', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should migrate lists indices to data streams and remove old legacy templates', async () => { + // create legacy indices + await createLegacyListsIndices(es); + + await supertest + .get(LIST_INDEX) + .set('kbn-xsrf', 'true') + // data stream does not exist + .expect(404); + + // confirm that legacy templates are in use + const legacyListsTemplateExists = await getTemplateExists(es, '.lists-default'); + const legacyItemsTemplateExists = await getTemplateExists(es, '.items-default'); + const nonLegacyListsTemplateExists = await getIndexTemplateExists(es, '.lists-default'); + const nonLegacyItemsTemplateExists = await getIndexTemplateExists(es, '.items-default'); + + expect(legacyListsTemplateExists).to.equal(true); + expect(legacyItemsTemplateExists).to.equal(true); + expect(nonLegacyListsTemplateExists).to.equal(false); + expect(nonLegacyItemsTemplateExists).to.equal(false); + + // migrates old indices to data streams + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); + + const { body } = await supertest.get(LIST_INDEX).set('kbn-xsrf', 'true').expect(200); + + const legacyListsTemplateExistsPostMigration = await getTemplateExists(es, '.lists-default'); + const legacyItemsTemplateExistsPostMigration = await getTemplateExists(es, '.items-default'); + const newListsTemplateExists = await getIndexTemplateExists(es, '.lists-default'); + const newItemsTemplateExists = await getIndexTemplateExists(es, '.items-default'); + + expect(legacyListsTemplateExistsPostMigration).to.equal(false); + expect(legacyItemsTemplateExistsPostMigration).to.equal(false); + expect(newListsTemplateExists).to.equal(true); + expect(newItemsTemplateExists).to.equal(true); + + expect(body).to.eql({ list_index: true, list_item_index: true }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/delete_lists.ts similarity index 92% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/delete_lists.ts index 1e9b4911c309..87b54d9a2e99 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/delete_lists.ts @@ -27,15 +27,16 @@ import { deleteAllExceptions, deleteListsIndex, removeListServerGeneratedProperties, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('delete_lists', () => { + describe('@ess @serverless delete_lists', () => { describe('deleting lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -60,7 +61,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should delete a single list with a list id containing non-alphanumeric characters', async () => { @@ -82,7 +85,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should delete a single list using an auto generated id', async () => { @@ -100,7 +105,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should return an error if the id does not exist when trying to delete it', async () => { @@ -252,7 +259,9 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true'); const bodyToCompare = removeListServerGeneratedProperties(deleteListBody.body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); await supertest .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists.ts similarity index 86% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists.ts index ffb13b66c8db..3c47ad92eb82 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists.ts @@ -10,20 +10,22 @@ import expect from '@kbn/expect'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('find_lists', () => { + describe('@ess @serverless find_lists', () => { describe('find lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -68,7 +70,7 @@ export default ({ getService }: FtrProviderContext): void => { // cursor is a constant changing value so we have to delete it as well. delete body.cursor; expect(body).to.eql({ - data: [getListResponseMockWithoutAutoGeneratedValues()], + data: [getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME)], page: 1, per_page: 20, total: 1, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists_by_size.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists_by_size.ts similarity index 79% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists_by_size.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists_by_size.ts index 0d348f5c6342..813293ed1e7c 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists_by_size.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/find_lists_by_size.ts @@ -6,24 +6,29 @@ */ import expect from '@kbn/expect'; - +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; import { LIST_URL, INTERNAL_FIND_LISTS_BY_SIZE } from '@kbn/securitysolution-list-constants'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('find_lists_by_size', () => { + describe('@ess @serverless find_lists_by_size', () => { describe('find lists by size', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -37,7 +42,8 @@ export default ({ getService }: FtrProviderContext): void => { const { body } = await supertest .get(`${INTERNAL_FIND_LISTS_BY_SIZE}`) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send() .expect(200); @@ -66,7 +72,8 @@ export default ({ getService }: FtrProviderContext): void => { const { body } = await supertest .get(`${INTERNAL_FIND_LISTS_BY_SIZE}`) .set('kbn-xsrf', 'true') - .set('elastic-api-version', '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send() .expect(200); @@ -75,10 +82,10 @@ export default ({ getService }: FtrProviderContext): void => { // cursor is a constant changing value so we have to delete it as well. delete body.cursor; expect(body).to.eql({ - smallLists: [getListResponseMockWithoutAutoGeneratedValues()], + smallLists: [getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME)], largeLists: [ { - ...getListResponseMockWithoutAutoGeneratedValues(), + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), type: 'text', }, ], diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/index.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/index.ts new file mode 100644 index 000000000000..c661171dfedb --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Lists API', function () { + loadTestFile(require.resolve('./create_lists')); + loadTestFile(require.resolve('./create_lists_index')); + loadTestFile(require.resolve('./create_lists_index_migrations')); + loadTestFile(require.resolve('./patch_lists')); + loadTestFile(require.resolve('./patch_lists_migrations')); + loadTestFile(require.resolve('./read_lists')); + loadTestFile(require.resolve('./update_lists')); + loadTestFile(require.resolve('./update_lists_migrations')); + loadTestFile(require.resolve('./delete_lists')); + loadTestFile(require.resolve('./find_lists')); + loadTestFile(require.resolve('./find_lists_by_size')); + }); +} diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists.ts new file mode 100644 index 000000000000..2586dcb23ab4 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists.ts @@ -0,0 +1,215 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { PatchListSchema, ListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; + +import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; +import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; +import { getUpdateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_schema.mock'; +import { + createListsIndex, + deleteListsIndex, + removeListServerGeneratedProperties, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const retry = getService('retry'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); + + describe('@ess @serverless patch_lists', () => { + describe('patch lists', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + it('should patch a single list property of name using an id', async () => { + const listId = getCreateMinimalListSchemaMock().id as string; + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // patch a simple list's name + const patchedListPayload: PatchListSchema = { + id: listId, + name: 'some other name', + }; + + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchedListPayload) + .expect(200); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + + await retry.waitFor('patches should be persistent', async () => { + const { body: list } = await supertest + .get(LIST_URL) + .query({ id: listId }) + .set('kbn-xsrf', 'true') + .expect(200); + + expect(list.name).to.be('some other name'); + return true; + }); + }); + + it('should patch a single list property of name using an auto-generated id', async () => { + const { id, ...listNoId } = getCreateMinimalListSchemaMock(); + // create a simple list with no id which will use an auto-generated id + const { body: createListBody } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(200); + + // patch a simple list's name + const patchedListPayload: PatchListSchema = { + id: createListBody.id, + name: 'some other name', + }; + + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchedListPayload) + .expect(200); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + + await retry.waitFor('patches should be persistent', async () => { + const { body: list } = await supertest + .get(LIST_URL) + .query({ id: createListBody.id }) + .set('kbn-xsrf', 'true'); + + expect(list.name).to.be('some other name'); + return true; + }); + }); + + it('should not remove unspecified fields in payload', async () => { + const listId = getCreateMinimalListSchemaMock().id as string; + // create a simple list + await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // patch a simple list's name + const patchedListPayload: PatchListSchema = { + id: listId, + name: 'some other name', + }; + + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchedListPayload) + .expect(200); + + const outputList: Partial = { + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + + await retry.waitFor('patches should be persistent', async () => { + const { body: list } = await supertest + .get(LIST_URL) + .query({ id: getUpdateMinimalListSchemaMock().id }) + .set('kbn-xsrf', 'true'); + + const persistentBodyToCompare = removeListServerGeneratedProperties(list); + + expect(persistentBodyToCompare).to.eql(outputList); + return true; + }); + }); + + it('should change the version of a list when it patches a property', async () => { + // create a simple list + const { body: createdList } = await supertest + .post(LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateMinimalListSchemaMock()) + .expect(200); + + // patch a simple list property of name and description + const patchPayload: PatchListSchema = { + id: createdList.id, + name: 'some other name', + description: 'some other description', + }; + + const { body: patchedList } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchPayload); + + expect(createdList.version).to.be(1); + expect(patchedList.version).to.be(2); + + await retry.waitFor('patches should be persistent', async () => { + const { body: list } = await supertest + .get(LIST_URL) + .query({ id: patchedList.id }) + .set('kbn-xsrf', 'true'); + + expect(list.version).to.be(2); + return true; + }); + }); + + it('should give a 404 if it is given a fake id', async () => { + const simpleList: PatchListSchema = { + ...getUpdateMinimalListSchemaMock(), + id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(simpleList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'list id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" not found', + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists_migrations.ts new file mode 100644 index 000000000000..d131dc4ba05b --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/patch_lists_migrations.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { PatchListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; + +import { + createListsIndex, + deleteListsIndex, + createListsIndices, + createListBypassingChecks, +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess patch_lists_migrations', () => { + describe('patch lists', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + describe('legacy list index (list created before migration to data stream)', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + it('should update list container that was created in legacy index and migrated through LIST_INDEX request', async () => { + const listId = 'random-list'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + + // migrates old indices to data streams + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); + + // patch a simple list's name + const patchPayload: PatchListSchema = { + id: listId, + name: 'some other name', + }; + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchPayload) + .expect(200); + + expect(body.name).to.be('some other name'); + }); + + it('should update list container that was created in legacy index and not yet migrated', async () => { + const listId = 'random-list'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + + // patch a simple list's name + const patchPayload: PatchListSchema = { + id: listId, + name: 'some other name', + }; + const { body } = await supertest + .patch(LIST_URL) + .set('kbn-xsrf', 'true') + .send(patchPayload) + .expect(200); + + expect(body.name).to.be('some other name'); + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_list_privileges.ts similarity index 91% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_list_privileges.ts index 9af6143b2152..85e4309d048a 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_list_privileges.ts @@ -9,16 +9,15 @@ import expect from '@kbn/expect'; import { LIST_PRIVILEGES_URL } from '@kbn/securitysolution-list-constants'; import { getReadPrivilegeMock } from '@kbn/lists-plugin/server/routes/list_privileges/read_list_privileges_route.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { FtrProviderContextWithSpaces } from '../../../../../ftr_provider_context_with_spaces'; -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { +export default ({ getService }: FtrProviderContextWithSpaces) => { const supertest = getService('supertest'); const security = getService('security'); const spacesService = getService('spaces'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('read_list_privileges', () => { + describe('@ess @serverless read_list_privileges', () => { const space1Id = 'space_1'; const user1 = { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_lists.ts similarity index 83% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_lists.ts index 162b57501c47..025725fe0157 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/read_lists.ts @@ -13,20 +13,21 @@ import { getCreateMinimalListSchemaMockWithoutId, } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createListsIndex, deleteListsIndex, removeListServerGeneratedProperties, -} from '../../utils'; +} from '../../../utils'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('read_lists', () => { + describe('@ess @serverless read_lists', () => { describe('reading lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -50,7 +51,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should be able to read a single list with an auto-generated list id', async () => { @@ -67,7 +70,9 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const bodyToCompare = removeListServerGeneratedProperties(body); - expect(bodyToCompare).to.eql(getListResponseMockWithoutAutoGeneratedValues()); + expect(bodyToCompare).to.eql( + getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME) + ); }); it('should return 404 if given a fake id', async () => { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists.ts similarity index 79% rename from x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts rename to x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists.ts index d9fc0bbe38bd..28084f54d2ab 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { UpdateListSchema, ListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { LIST_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_schema.mock'; @@ -17,19 +17,18 @@ import { createListsIndex, deleteListsIndex, removeListServerGeneratedProperties, - createListsIndices, - createListBypassingChecks, -} from '../../utils'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); const retry = getService('retry'); - const es = getService('es'); + const config = getService('config'); + const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); - describe('update_lists', () => { + describe('@ess @serverless update_lists', () => { describe('update lists', () => { beforeEach(async () => { await createListsIndex(supertest, log); @@ -60,7 +59,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', version: 2, }; @@ -90,7 +89,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', version: 2, }; @@ -189,7 +188,7 @@ export default ({ getService }: FtrProviderContext) => { const { body } = await supertest.put(LIST_URL).set('kbn-xsrf', 'true').send(updatedList); const outputList: Partial = { - ...getListResponseMockWithoutAutoGeneratedValues(), + ...getListResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME), name: 'some other name', description: 'some other description', version: 2, @@ -280,61 +279,6 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); }); }); - - describe('legacy list index (list created before migration to data stream)', () => { - beforeEach(async () => { - await deleteListsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteListsIndex(supertest, log); - }); - it('should update list container that was created in legacy index and migrated through LIST_INDEX request', async () => { - const listId = 'random-list'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - - // migrates old indices to data streams - await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); - - // update a simple list's name - const updatedList: UpdateListSchema = { - ...getUpdateMinimalListSchemaMock(), - id: listId, - name: 'some other name', - }; - const { body } = await supertest - .put(LIST_URL) - .set('kbn-xsrf', 'true') - .send(updatedList) - .expect(200); - - expect(body.name).to.be('some other name'); - }); - - it('should update list container that was created in legacy index and not yet migrated', async () => { - const listId = 'random-list'; - // create legacy indices - await createListsIndices(es); - // create a simple list - await createListBypassingChecks({ es, id: listId }); - - // update a simple list's name - const updatedList: UpdateListSchema = { - ...getUpdateMinimalListSchemaMock(), - id: listId, - name: 'some other name', - }; - const { body } = await supertest - .put(LIST_URL) - .set('kbn-xsrf', 'true') - .send(updatedList) - .expect(200); - expect(body.name).to.be('some other name'); - }); - }); }); }); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists_migrations.ts new file mode 100644 index 000000000000..3acffe061f2c --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/default_license/lists_items/lists/update_lists_migrations.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import type { UpdateListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL, LIST_INDEX } from '@kbn/securitysolution-list-constants'; + +import { getUpdateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/update_list_schema.mock'; +import { + createListsIndex, + deleteListsIndex, + createListsIndices, + createListBypassingChecks, +} from '../../../utils'; + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const log = getService('log'); + const es = getService('es'); + + describe('@ess update_lists_migrations', () => { + describe('update lists', () => { + beforeEach(async () => { + await createListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + + describe('legacy list index (list created before migration to data stream)', () => { + beforeEach(async () => { + await deleteListsIndex(supertest, log); + }); + + afterEach(async () => { + await deleteListsIndex(supertest, log); + }); + it('should update list container that was created in legacy index and migrated through LIST_INDEX request', async () => { + const listId = 'random-list'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + + // migrates old indices to data streams + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true'); + + // update a simple list's name + const updatedList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + id: listId, + name: 'some other name', + }; + const { body } = await supertest + .put(LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + expect(body.name).to.be('some other name'); + }); + + it('should update list container that was created in legacy index and not yet migrated', async () => { + const listId = 'random-list'; + // create legacy indices + await createListsIndices(es); + // create a simple list + await createListBypassingChecks({ es, id: listId }); + + // update a simple list's name + const updatedList: UpdateListSchema = { + ...getUpdateMinimalListSchemaMock(), + id: listId, + name: 'some other name', + }; + const { body } = await supertest + .put(LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + expect(body.name).to.be('some other name'); + }); + }); + }); + }); +}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/utils.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/utils.ts new file mode 100644 index 000000000000..be05bb5a4751 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/utils.ts @@ -0,0 +1,686 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; +import { v4 as uuidv4 } from 'uuid'; + +import type { + Type, + ListSchema, + ListItemSchema, + ExceptionListSchema, + ExceptionListItemSchema, + ExceptionList, + NamespaceType, +} from '@kbn/securitysolution-io-ts-list-types'; +import { + EXCEPTION_LIST_URL, + LIST_INDEX, + LIST_ITEM_URL, +} from '@kbn/securitysolution-list-constants'; +import { + setPolicy, + setTemplate, + setIndexTemplate, + createBootstrapIndex, +} from '@kbn/securitysolution-es-utils'; +import { Client } from '@elastic/elasticsearch'; +import { ToolingLog } from '@kbn/tooling-log'; +import { getImportListItemAsBuffer } from '@kbn/lists-plugin/common/schemas/request/import_list_item_schema.mock'; +import { encodeHitVersion } from '@kbn/securitysolution-es-utils'; + +import { countDownTest } from '../detections_response/utils'; + +/** + * Creates the lists and lists items index for use inside of beforeEach blocks of tests + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest client library + */ +export const createListsIndex = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + return countDownTest( + async () => { + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').send(); + return { + passed: true, + }; + }, + 'createListsIndex', + log + ); +}; + +/** + * Deletes the lists index for use inside of afterEach blocks of tests + * @param supertest The supertest client library + */ +export const deleteListsIndex = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + return countDownTest( + async () => { + await supertest.delete(LIST_INDEX).set('kbn-xsrf', 'true').send(); + return { + passed: true, + }; + }, + 'deleteListsIndex', + log + ); +}; + +/** + * Creates the exception lists and lists items index for use inside of beforeEach blocks of tests + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest client library + */ +export const createExceptionListsIndex = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + return countDownTest( + async () => { + await supertest.post(LIST_INDEX).set('kbn-xsrf', 'true').send(); + return { + passed: true, + }; + }, + 'createListsIndex', + log + ); +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeListServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, '@timestamp': _t, ...props } = list; + return props; +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeListItemServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, '@timestamp': _t, ...props } = list; + return props; +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeExceptionListItemServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; + return removedProperties; +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeExceptionListServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; + return removedProperties; +}; + +// Similar to ReactJs's waitFor from here: https://testing-library.com/docs/dom-testing-library/api-async#waitfor +export const waitFor = async ( + functionToTest: () => Promise, + functionName: string, + log: ToolingLog, + maxTimeout: number = 800000, + timeoutWait: number = 250 +) => { + await new Promise(async (resolve, reject) => { + try { + let found = false; + let numberOfTries = 0; + const maxTries = Math.floor(maxTimeout / timeoutWait); + + while (!found && numberOfTries < maxTries) { + const itPasses = await functionToTest(); + + if (itPasses) { + found = true; + } else { + log.debug(`Try number ${numberOfTries} out of ${maxTries} for function ${functionName}`); + numberOfTries++; + } + + await new Promise((resolveTimeout) => setTimeout(resolveTimeout, timeoutWait)); + } + + if (found) { + resolve(); + } else { + reject(new Error(`timed out waiting for function ${functionName} condition to be true`)); + } + } catch (error) { + reject(error); + } + }); +}; + +/** + * Useful for export_api testing to convert from a multi-part binary back to a string + * @param res Response + * @param callback Callback + */ +export const binaryToString = (res: any, callback: any): void => { + res.setEncoding('binary'); + res.data = ''; + res.on('data', (chunk: any) => { + res.data += chunk; + }); + res.on('end', () => { + callback(null, Buffer.from(res.data)); + }); +}; + +/** + * Remove all exceptions from both the "single" and "agnostic" spaces. + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest handle + */ +export const deleteAllExceptions = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog +): Promise => { + await deleteAllExceptionsByType(supertest, log, 'single'); + await deleteAllExceptionsByType(supertest, log, 'agnostic'); +}; + +/** + * Remove all exceptions by a given type such as "agnostic" or "single". + * This will retry 50 times before giving up and hopefully still not interfere with other tests + * @param supertest The supertest handle + */ +export const deleteAllExceptionsByType = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + type: NamespaceType +): Promise => { + await countDownTest( + async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find?per_page=9999&namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + const ids: string[] = body.data.map((exception: ExceptionList) => exception.id); + for await (const id of ids) { + await supertest + .delete(`${EXCEPTION_LIST_URL}?id=${id}&namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + } + const { body: finalCheck } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find?namespace_type=${type}`) + .set('kbn-xsrf', 'true') + .send(); + return { + passed: finalCheck.data.length === 0, + }; + }, + `deleteAllExceptions by type: "${type}"`, + log, + 50, + 1000 + ); +}; + +/** + * Convenience function for quickly importing a given type and contents and then + * waiting to ensure they're there before continuing + * @param supertest The super test agent + * @param type The type to import as + * @param contents The contents of the import + * @param fileName filename to import as + * @param testValues Optional test values in case you're using CIDR or range based lists + */ +export const importFile = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + type: Type, + contents: string[], + fileName: string, + testValues?: string[] +): Promise => { + const response = await supertest + .post(`${LIST_ITEM_URL}/_import?type=${type}`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(contents), fileName) + .expect('Content-Type', 'application/json; charset=utf-8'); + + if (response.status !== 200) { + log.error( + `Did not get an expected 200 "ok" When importing a file (importFile). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( + response.body + )}, status: ${JSON.stringify(response.status)}` + ); + } + + // although we have pushed the list and its items, it is async so we + // have to wait for the contents before continuing + const testValuesOrContents = testValues ?? contents; + await waitForListItems(supertest, log, testValuesOrContents, fileName); +}; + +/** + * Convenience function for quickly importing a given type and contents and then + * waiting to ensure they're there before continuing. This specifically checks tokens + * from text file + * @param supertest The super test agent + * @param type The type to import as + * @param contents The contents of the import + * @param fileName filename to import as + */ +export const importTextFile = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + type: Type, + contents: string[], + fileName: string +): Promise => { + const response = await supertest + .post(`${LIST_ITEM_URL}/_import?type=${type}`) + .set('kbn-xsrf', 'true') + .attach('file', getImportListItemAsBuffer(contents), fileName) + .expect('Content-Type', 'application/json; charset=utf-8'); + + if (response.status !== 200) { + log.error( + `Did not get an expected 200 "ok" when importing a text file (importTextFile). CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify( + response.body + )}, status: ${JSON.stringify(response.status)}` + ); + } + + // although we have pushed the list and its items, it is async so we + // have to wait for the contents before continuing + await waitForTextListItems(supertest, log, contents, fileName); +}; + +/** + * Convenience function for waiting for a particular file uploaded + * and a particular item value to be available before continuing. + * @param supertest The super test agent + * @param fileName The filename imported + * @param itemValue The item value to wait for + */ +export const waitForListItem = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + itemValue: string, + fileName: string +): Promise => { + await waitFor( + async () => { + const { status, body } = await supertest + .get(`${LIST_ITEM_URL}?list_id=${fileName}&value=${itemValue}`) + .send(); + if (status !== 200) { + log.debug( + `Did not get an expected 200 "ok" when waiting for a list item (waitForListItem) yet. Retrying until we get a 200 "ok". body: ${JSON.stringify( + body + )}, status: ${JSON.stringify(status)}` + ); + } + return status === 200; + }, + `waitForListItem fileName: "${fileName}" itemValue: "${itemValue}"`, + log + ); +}; + +/** + * Convenience function for waiting for a particular file uploaded + * and particular item values to be available before continuing. + * @param supertest The super test agent + * @param fileName The filename imported + * @param itemValue The item value to wait for + */ +export const waitForListItems = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + itemValues: string[], + fileName: string +): Promise => { + await Promise.all(itemValues.map((item) => waitForListItem(supertest, log, item, fileName))); +}; + +/** + * Convenience function for waiting for a particular file uploaded + * and a particular item value to be available before continuing. + * @param supertest The super test agent + * @param fileName The filename imported + * @param itemValue The item value to wait for + */ +export const waitForTextListItem = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + itemValue: string, + fileName: string +): Promise => { + const tokens = itemValue.split(' '); + await waitFor( + async () => { + const promises = await Promise.all( + tokens.map(async (token) => { + const { status, body } = await supertest + .get(`${LIST_ITEM_URL}?list_id=${fileName}&value=${token}`) + .send(); + if (status !== 200) { + log.error( + `Did not get an expected 200 "ok" when waiting for a text list item (waitForTextListItem) yet. Retrying until we get a 200 "ok". body: ${JSON.stringify( + body + )}, status: ${JSON.stringify(status)}` + ); + } + return status === 200; + }) + ); + return promises.every((one) => one); + }, + `waitForTextListItem fileName: "${fileName}" itemValue: "${itemValue}"`, + log + ); +}; + +/** + * Convenience function for waiting for a particular file uploaded + * and particular item values to be available before continuing. This works + * specifically with text types and does tokenization to ensure all words are uploaded + * @param supertest The super test agent + * @param fileName The filename imported + * @param itemValue The item value to wait for + */ +export const waitForTextListItems = async ( + supertest: SuperTest.SuperTest, + log: ToolingLog, + itemValues: string[], + fileName: string +): Promise => { + await Promise.all(itemValues.map((item) => waitForTextListItem(supertest, log, item, fileName))); +}; + +const testPolicy = { + policy: { + phases: { + hot: { + min_age: '0ms', + actions: { + rollover: { + max_size: '50gb', + }, + }, + }, + }, + }, +}; + +const listsMappings = { + dynamic: 'strict', + properties: { + name: { + type: 'keyword', + }, + deserializer: { + type: 'keyword', + }, + serializer: { + type: 'keyword', + }, + description: { + type: 'keyword', + }, + type: { + type: 'keyword', + }, + tie_breaker_id: { + type: 'keyword', + }, + meta: { + enabled: 'false', + type: 'object', + }, + created_at: { + type: 'date', + }, + updated_at: { + type: 'date', + }, + created_by: { + type: 'keyword', + }, + updated_by: { + type: 'keyword', + }, + version: { + type: 'keyword', + }, + immutable: { + type: 'boolean', + }, + }, +}; + +const itemsMappings = { + dynamic: 'strict', + properties: { + tie_breaker_id: { + type: 'keyword', + }, + list_id: { + type: 'keyword', + }, + deserializer: { + type: 'keyword', + }, + serializer: { + type: 'keyword', + }, + meta: { + enabled: 'false', + type: 'object', + }, + created_at: { + type: 'date', + }, + updated_at: { + type: 'date', + }, + created_by: { + type: 'keyword', + }, + updated_by: { + type: 'keyword', + }, + ip: { + type: 'ip', + }, + keyword: { + type: 'keyword', + }, + }, +}; + +/** + * Convenience function for creating legacy index templates to + * test out logic updating to new index templates + * @param es es client + */ +export const createLegacyListsIndices = async (es: Client) => { + await setPolicy(es, '.lists-default', testPolicy); + await setPolicy(es, '.items-default', testPolicy); + await setTemplate(es, '.lists-default', { + index_patterns: [`.lists-default-*`], + mappings: listsMappings, + settings: { + index: { + lifecycle: { + name: '.lists-default', + rollover_alias: '.lists-default', + }, + }, + }, + }); + await setTemplate(es, '.items-default', { + index_patterns: [`.items-default-*`], + mappings: itemsMappings, + settings: { + index: { + lifecycle: { + name: '.items-default', + rollover_alias: '.items-default', + }, + }, + }, + }); + await createBootstrapIndex(es, '.lists-default'); + await createBootstrapIndex(es, '.items-default'); +}; + +/** + * Utility to create list indices, before they were migrated to data streams + * @param es ES client + */ +export const createListsIndices = async (es: Client) => { + await setPolicy(es, '.lists-default', testPolicy); + await setPolicy(es, '.items-default', testPolicy); + await setIndexTemplate(es, '.lists-default', { + index_patterns: [`.lists-default-*`], + template: { + mappings: listsMappings, + settings: { + index: { + lifecycle: { + name: '.lists-default', + rollover_alias: '.lists-default', + }, + }, + mapping: { + total_fields: { + limit: 10000, + }, + }, + }, + }, + }); + await setIndexTemplate(es, '.items-default', { + index_patterns: [`.items-default-*`], + template: { + mappings: itemsMappings, + settings: { + index: { + lifecycle: { + name: '.items-default', + rollover_alias: '.items-default', + }, + }, + mapping: { + total_fields: { + limit: 10000, + }, + }, + }, + }, + }); + await createBootstrapIndex(es, '.lists-default'); + await createBootstrapIndex(es, '.items-default'); +}; + +/** + * utility to create list directly by using ES, bypassing all checks + * useful, to create list in legacy indices + */ +export const createListBypassingChecks = async ({ es, id }: { es: Client; id: string }) => { + const createdAt = new Date().toISOString(); + const body = { + created_at: createdAt, + created_by: 'mock-user', + description: 'mock-description', + name: 'mock-name', + tie_breaker_id: uuidv4(), + type: 'keyword', + updated_at: createdAt, + updated_by: 'mock-user', + immutable: false, + version: 1, + }; + + const response = await es.create({ + body, + id, + index: '.lists-default', + refresh: 'wait_for', + }); + + return { + _version: encodeHitVersion(response), + id: response._id, + ...body, + }; +}; + +/** + * utility to create list item directly by using ES, bypassing all checks + * useful, to create list item in legacy indices + * supports keyword only + */ +export const createListItemBypassingChecks = async ({ + es, + listId, + id, + value, +}: { + es: Client; + listId: string; + id: string; + value: string; +}) => { + const createdAt = new Date().toISOString(); + const body = { + created_at: createdAt, + created_by: 'mock-user', + tie_breaker_id: uuidv4(), + updated_at: createdAt, + updated_by: 'mock-user', + list_id: listId, + keyword: value, + }; + + const response = await es.create({ + body, + id, + index: '.items-default', + refresh: 'wait_for', + }); + + return { + _version: encodeHitVersion(response), + id: response._id, + ...body, + }; +}; diff --git a/x-pack/test/security_solution_api_integration/tsconfig.json b/x-pack/test/security_solution_api_integration/tsconfig.json index 4dfd3ef6ba30..6b1ca69f6aed 100644 --- a/x-pack/test/security_solution_api_integration/tsconfig.json +++ b/x-pack/test/security_solution_api_integration/tsconfig.json @@ -30,9 +30,12 @@ "@kbn/core-saved-objects-server", "@kbn/core", "@kbn/alerting-plugin", + "@kbn/securitysolution-ecs", + "@kbn/securitysolution-rules", "@kbn/core-http-common", "@kbn/securitysolution-ecs", "@kbn/fleet-plugin", "@kbn/repo-info", + "@kbn/securitysolution-es-utils", ] } diff --git a/x-pack/test/security_solution_cypress/config.ts b/x-pack/test/security_solution_cypress/config.ts index 99390aa5142a..fb34362f7fb9 100644 --- a/x-pack/test/security_solution_cypress/config.ts +++ b/x-pack/test/security_solution_cypress/config.ts @@ -46,7 +46,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { '--xpack.ruleRegistry.unsafe.legacyMultiTenancy.enabled=true', `--xpack.securitySolution.enableExperimental=${JSON.stringify([ 'chartEmbeddablesEnabled', - 'disableTimelineSaveTour', ])}`, // mock cloud to enable the guided onboarding tour in e2e tests '--xpack.cloud.id=test', diff --git a/x-pack/test/security_solution_cypress/cypress/README.md b/x-pack/test/security_solution_cypress/cypress/README.md index 8940d6c86e73..88786aed7ff5 100644 --- a/x-pack/test/security_solution_cypress/cypress/README.md +++ b/x-pack/test/security_solution_cypress/cypress/README.md @@ -62,19 +62,25 @@ Run the tests with the following yarn scripts from `x-pack/test/security_solutio | cypress | Runs the default Cypress command | | cypress:open:ess | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a local kibana and ES instance. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. | | cypress:open:serverless | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a mocked serverless environment. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. | -| cypress:run:ess | Runs all tests tagged as ESS placed in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | +| cypress:run:ess | Runs all tests tagged as ESS placed in the `e2e` directory excluding `investigations`,`explore` and `detection_response/rule_management` directories in headless mode | | cypress:run:cases:ess | Runs all tests under `explore/cases` in the `e2e` directory related to the Cases area team in headless mode | | cypress:ess | Runs all ESS tests with the specified configuration in headless mode and produces a report using `cypress-multi-reporters` | +| cypress:rule_management:run:ess | Runs all tests tagged as ESS in the `e2e/detection_response/rule_management` excluding `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | +| cypress:rule_management:prebuilt_rules:run:ess | Runs all tests tagged as ESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | | cypress:run:respops:ess | Runs all tests related to the Response Ops area team, specifically tests in `detection_alerts`, `detection_rules`, and `exceptions` directories in headless mode | -| cypress:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | -| cypress:investigations:run:ess | Runs all tests tagged as ESS in the `e2e/investigations` directory in headless mode | +| cypress:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e` directory excluding `investigations`, `explore` and `rule_management` directories in headless mode | +| cypress:rule_management:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management` excluding `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | +| cypress:rule_management:prebuilt_rules:run:serverless | Runs all tests tagged as ESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | +| cypress:investigations:run:ess | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode | | cypress:explore:run:ess | Runs all tests tagged as ESS in the `e2e/explore` directory in headless mode | | cypress:investigations:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode | | cypress:explore:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode | | cypress:open:qa:serverless | Opens the Cypress UI with all tests in the `e2e` directory tagged as SERVERLESS. This also creates an MKI project in console.qa enviornment. The kibana instance will reload when you make code changes. This is the recommended way to debug tests in QA. Follow the readme in order to learn about the known limitations. | -| cypress:run:qa:serverless | Runs all tests tagged as SERVERLESS placed in the `e2e` directory excluding `investigations` and `explore` directories in headless mode using the QA environment and real MKI projects.| +| cypress:run:qa:serverless | Runs all tests tagged as SERVERLESS placed in the `e2e` directory excluding `investigations`, `explore` and `rule_management` directories in headless mode using the QA environment and real MKI projects.| | cypress:run:qa:serverless:explore | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode using the QA environment and real MKI prorjects. | | cypress:run:qa:serverless:investigations | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:rule_management | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management` directory, excluding `e2e/detection_response/rule_management/prebuilt_rules` in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:rule_management:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode using the QA environment and reak MKI projects. | | junit:merge | Merges individual test reports into a single report and moves the report to the `junit` directory | Please note that all the headless mode commands do not open the Cypress UI and are typically used in CI/CD environments. The scripts that open the Cypress UI are useful for development and debugging. @@ -94,7 +100,7 @@ Below you can find the folder structure used on our Cypress tests. Cypress convention starting version 10 (previously known as integration). Contains the specs that are going to be executed. -### e2e/explore and e2e/investigations +### Area teams folders These directories contain tests which are run in their own Buildkite pipeline. @@ -103,7 +109,8 @@ If you belong to one of the teams listed in the table, please add new e2e specs | Directory | Area team | | -- | -- | | `e2e/explore` | Threat Hunting Explore | -| `e2e/investigations | Threat Hunting Investigations | +| `e2e/investigations` | Threat Hunting Investigations | +| `e2e/detection_response/rule_management` | Detection Rule Management | ### fixtures/ @@ -203,6 +210,8 @@ Run the tests with the following yarn scripts from `x-pack/test/security_solutio | cypress:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | | cypress:investigations:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode | | cypress:explore:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode | +| cypress:rule_management:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management` excluding `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | +| cypress:rule_management:prebuilt_rules:run:serverless | Runs all tests tagged as ESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode | Please note that all the headless mode commands do not open the Cypress UI and are typically used in CI/CD environments. The scripts that open the Cypress UI are useful for development and debugging. @@ -248,6 +257,8 @@ Run the tests with the following yarn scripts from `x-pack/test/security_solutio | cypress:run:qa:serverless | Runs all tests tagged as SERVERLESS placed in the `e2e` directory excluding `investigations` and `explore` directories in headless mode using the QA environment and real MKI projects.| | cypress:run:qa:serverless:explore | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode using the QA environment and real MKI prorjects. | | cypress:run:qa:serverless:investigations | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:rule_management | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management` directory, excluding `e2e/detection_response/rule_management/prebuilt_rules` in headless mode using the QA environment and reak MKI projects. | +| cypress:run:qa:serverless:rule_management:prebuilt_rules | Runs all tests tagged as SERVERLESS in the `e2e/detection_response/rule_management/prebuilt_rules` directory in headless mode using the QA environment and reak MKI projects. | Please note that all the headless mode commands do not open the Cypress UI and are typically used in CI/CD environments. The scripts that open the Cypress UI are useful for development and debugging. diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts index 2ec99abb00db..1b03577e778b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts @@ -30,14 +30,15 @@ import { openFirstAlert, } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login } from '../../../tasks/login'; import { visit } from '../../../tasks/navigation'; import { ALERTS_URL } from '../../../urls/navigation'; -describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/169091 +describe.skip('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { before(() => { cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); }); @@ -246,7 +247,7 @@ describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { deleteAlertsAndRules(); createRule(getNewRule()); login(ROLES.reader); - visit(ALERTS_URL, { role: ROLES.reader }); + visit(ALERTS_URL); waitForAlertsToPopulate(); }); it('should not allow users to change a single alert status', () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts index 162c63ad3ce4..4fb4d50e7c6d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts @@ -13,7 +13,7 @@ import { updateAlertTags, } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { login } from '../../../tasks/login'; import { visitWithTimeRange } from '../../../tasks/navigation'; import { ALERTS_URL } from '../../../urls/navigation'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts index bbdba453351b..8ffb094f94e5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts @@ -25,7 +25,7 @@ import { const loadPageAsPlatformEngineerUser = (url: string) => { login(ROLES.soc_manager); - visit(url, { role: ROLES.soc_manager }); + visit(url); waitForPageTitleToBeShown(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments.cy.ts new file mode 100644 index 000000000000..83595c1f81e9 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments.cy.ts @@ -0,0 +1,368 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { getNewRule } from '../../../../objects/rule'; +import { + closeAlertFlyout, + closeAlerts, + expandFirstAlert, + selectFirstPageAlerts, + selectNumberOfAlerts, + selectPageFilterValue, +} from '../../../../tasks/alerts'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + alertDetailsFlyoutShowsAssignees, + alertDetailsFlyoutShowsAssigneesBadge, + alertsTableShowsAssigneesBadgeForAlert, + alertsTableShowsAssigneesForAlert, + updateAssigneesForAlert, + checkEmptyAssigneesStateInAlertDetailsFlyout, + checkEmptyAssigneesStateInAlertsTable, + removeAllAssigneesForAlert, + bulkUpdateAssignees, + alertsTableShowsAssigneesForAllAlerts, + bulkRemoveAllAssignees, + filterByAssignees, + NO_ASSIGNEES, + clearAssigneesFilter, + updateAssigneesViaAddButtonInFlyout, + updateAssigneesViaTakeActionButtonInFlyout, + removeAllAssigneesViaTakeActionButtonInFlyout, + loadPageAs, +} from '../../../../tasks/alert_assignments'; +import { ALERTS_COUNT } from '../../../../screens/alerts'; + +describe('Alert user assignment - ESS & Serverless', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); + + // Login into accounts so that they got activated and visible in user profiles list + login(ROLES.t1_analyst); + login(ROLES.t2_analyst); + login(ROLES.t3_analyst); + login(ROLES.soc_manager); + login(ROLES.detections_admin); + login(ROLES.platform_engineer); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_multiple'); + }); + + beforeEach(() => { + loadPageAs(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'new custom rule' })); + waitForAlertsToPopulate(); + }); + + context('Basic rendering', () => { + it('alert with no assignees in alerts table', () => { + checkEmptyAssigneesStateInAlertsTable(); + }); + + it(`alert with no assignees in alert's details flyout`, () => { + expandFirstAlert(); + checkEmptyAssigneesStateInAlertDetailsFlyout(); + }); + + it('alert with some assignees in alerts table', () => { + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesForAlert(users); + alertsTableShowsAssigneesForAlert(users); + }); + + it(`alert with some assignees in alert's details flyout`, () => { + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesForAlert(users); + expandFirstAlert(); + alertDetailsFlyoutShowsAssignees(users); + }); + + it('alert with many assignees (collapsed into badge) in alerts table', () => { + const users = [ + ROLES.t1_analyst, + ROLES.t2_analyst, + ROLES.t3_analyst, + ROLES.soc_manager, + ROLES.detections_admin, + ]; + updateAssigneesForAlert(users); + alertsTableShowsAssigneesBadgeForAlert(users); + }); + + it(`alert with many assignees (collapsed into badge) in alert's details flyout`, () => { + const users = [ROLES.detections_admin, ROLES.t1_analyst, ROLES.t2_analyst]; + updateAssigneesForAlert(users); + expandFirstAlert(); + alertDetailsFlyoutShowsAssigneesBadge(users); + }); + }); + + context('Updating assignees (single alert)', () => { + it('adding new assignees via `More actions` in alerts table', () => { + // Assign users + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesForAlert(users); + + // Assignees should appear in the alerts table + alertsTableShowsAssigneesForAlert(users); + + // Assignees should appear in the alert's details flyout + expandFirstAlert(); + alertDetailsFlyoutShowsAssignees(users); + }); + + it('adding new assignees via add button in flyout', () => { + expandFirstAlert(); + + // Assign users + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesViaAddButtonInFlyout(users); + + // Assignees should appear in the alert's details flyout + alertDetailsFlyoutShowsAssignees(users); + + // Assignees should appear in the alerts table + closeAlertFlyout(); + alertsTableShowsAssigneesForAlert(users); + }); + + it('adding new assignees via `Take action` button in flyout', () => { + expandFirstAlert(); + + // Assign users + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesViaTakeActionButtonInFlyout(users); + + // Assignees should appear in the alert's details flyout + alertDetailsFlyoutShowsAssignees(users); + + // Assignees should appear in the alerts table + closeAlertFlyout(); + alertsTableShowsAssigneesForAlert(users); + }); + + it('updating assignees via `More actions` in alerts table', () => { + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesForAlert(initialAssignees); + alertsTableShowsAssigneesForAlert(initialAssignees); + + // Update assignees + const updatedAssignees = [ROLES.t1_analyst, ROLES.t2_analyst]; + updateAssigneesForAlert(updatedAssignees); + + const expectedAssignees = [ROLES.detections_admin, ROLES.t2_analyst]; + + // Expected assignees should appear in the alerts table + alertsTableShowsAssigneesForAlert(expectedAssignees); + + // Expected assignees should appear in the alert's details flyout + expandFirstAlert(); + alertDetailsFlyoutShowsAssignees(expectedAssignees); + }); + + it('updating assignees via add button in flyout', () => { + expandFirstAlert(); + + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesViaAddButtonInFlyout(initialAssignees); + alertDetailsFlyoutShowsAssignees(initialAssignees); + + // Update assignees + const updatedAssignees = [ROLES.t1_analyst, ROLES.t2_analyst]; + updateAssigneesViaAddButtonInFlyout(updatedAssignees); + + const expectedAssignees = [ROLES.detections_admin, ROLES.t2_analyst]; + + // Expected assignees should appear in the alert's details flyout + alertDetailsFlyoutShowsAssignees(expectedAssignees); + + // Expected assignees should appear in the alerts table + closeAlertFlyout(); + alertsTableShowsAssigneesForAlert(expectedAssignees); + }); + + it('updating assignees via `Take action` button in flyout', () => { + expandFirstAlert(); + + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesViaTakeActionButtonInFlyout(initialAssignees); + alertDetailsFlyoutShowsAssignees(initialAssignees); + + // Update assignees + const updatedAssignees = [ROLES.t1_analyst, ROLES.t2_analyst]; + updateAssigneesViaTakeActionButtonInFlyout(updatedAssignees); + + const expectedAssignees = [ROLES.detections_admin, ROLES.t2_analyst]; + + // Expected assignees should appear in the alert's details flyout + alertDetailsFlyoutShowsAssignees(expectedAssignees); + + // Expected assignees should appear in the alerts table + closeAlertFlyout(); + alertsTableShowsAssigneesForAlert(expectedAssignees); + }); + + it('removing all assignees via `More actions` in alerts table', () => { + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesForAlert(initialAssignees); + alertsTableShowsAssigneesForAlert(initialAssignees); + + removeAllAssigneesForAlert(); + + // Alert should not show any assignee in alerts table or in details flyout + checkEmptyAssigneesStateInAlertsTable(); + expandFirstAlert(); + checkEmptyAssigneesStateInAlertDetailsFlyout(); + }); + + it('removing all assignees via `Take action` button in flyout', () => { + expandFirstAlert(); + + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + updateAssigneesViaTakeActionButtonInFlyout(initialAssignees); + alertDetailsFlyoutShowsAssignees(initialAssignees); + + removeAllAssigneesViaTakeActionButtonInFlyout(); + + // Alert should not show any assignee in alerts table or in details flyout + checkEmptyAssigneesStateInAlertDetailsFlyout(); + closeAlertFlyout(); + checkEmptyAssigneesStateInAlertsTable(); + }); + }); + + context('Updating assignees (bulk actions)', () => { + it('adding new assignees should be reflected in UI (alerts table and details flyout)', () => { + selectFirstPageAlerts(); + + // Assign users + const users = [ROLES.detections_admin, ROLES.t1_analyst]; + bulkUpdateAssignees(users); + + // Assignees should appear in the alerts table + alertsTableShowsAssigneesForAllAlerts(users); + }); + + it('updating assignees should be reflected in UI (alerts table and details flyout)', () => { + selectFirstPageAlerts(); + + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + bulkUpdateAssignees(initialAssignees); + alertsTableShowsAssigneesForAllAlerts(initialAssignees); + + // Update assignees + selectFirstPageAlerts(); + const updatedAssignees = [ROLES.t1_analyst, ROLES.t2_analyst]; + bulkUpdateAssignees(updatedAssignees); + + const expectedAssignees = [ROLES.detections_admin, ROLES.t2_analyst]; + + // Expected assignees should appear in the alerts table + alertsTableShowsAssigneesForAllAlerts(expectedAssignees); + }); + + it('removing all assignees should be reflected in UI (alerts table and details flyout)', () => { + selectFirstPageAlerts(); + + // Initially assigned users + const initialAssignees = [ROLES.detections_admin, ROLES.t1_analyst]; + bulkUpdateAssignees(initialAssignees); + alertsTableShowsAssigneesForAllAlerts(initialAssignees); + + // Unassign alert + selectFirstPageAlerts(); + bulkRemoveAllAssignees(); + + // Alerts should not have assignees + checkEmptyAssigneesStateInAlertsTable(); + }); + }); + + context('Alerts filtering', () => { + it('by `No assignees` option', () => { + const totalNumberOfAlerts = 5; + const numberOfSelectedAlerts = 2; + selectNumberOfAlerts(numberOfSelectedAlerts); + bulkUpdateAssignees([ROLES.t1_analyst]); + + filterByAssignees([NO_ASSIGNEES]); + + const expectedNumberOfAlerts = totalNumberOfAlerts - numberOfSelectedAlerts; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + }); + + it('by one assignee', () => { + const numberOfSelectedAlerts = 2; + selectNumberOfAlerts(numberOfSelectedAlerts); + bulkUpdateAssignees([ROLES.t1_analyst]); + + filterByAssignees([ROLES.t1_analyst]); + + cy.get(ALERTS_COUNT).contains(numberOfSelectedAlerts); + }); + + it('by multiple assignees', () => { + const numberOfSelectedAlerts1 = 1; + selectNumberOfAlerts(numberOfSelectedAlerts1); + bulkUpdateAssignees([ROLES.t1_analyst]); + + filterByAssignees([NO_ASSIGNEES]); + + const numberOfSelectedAlerts2 = 2; + selectNumberOfAlerts(numberOfSelectedAlerts2); + bulkUpdateAssignees([ROLES.detections_admin]); + + clearAssigneesFilter(); + + cy.get(ALERTS_COUNT).contains(5); + + filterByAssignees([ROLES.t1_analyst, ROLES.detections_admin]); + + const expectedNumberOfAlerts = numberOfSelectedAlerts1 + numberOfSelectedAlerts2; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + }); + + it('by assignee and alert status', () => { + const totalNumberOfAlerts = 5; + const numberOfAssignedAlerts = 3; + selectNumberOfAlerts(numberOfAssignedAlerts); + bulkUpdateAssignees([ROLES.t1_analyst]); + + filterByAssignees([ROLES.t1_analyst]); + + const numberOfClosedAlerts = 1; + selectNumberOfAlerts(numberOfClosedAlerts); + closeAlerts(); + + const expectedNumberOfAllerts1 = numberOfAssignedAlerts - numberOfClosedAlerts; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAllerts1); + + clearAssigneesFilter(); + + const expectedNumberOfAllerts2 = totalNumberOfAlerts - numberOfClosedAlerts; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAllerts2); + + filterByAssignees([ROLES.t1_analyst]); + selectPageFilterValue(0, 'closed'); + cy.get(ALERTS_COUNT).contains(numberOfClosedAlerts); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess.cy.ts new file mode 100644 index 000000000000..bdaaedab7f0b --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess.cy.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { getNewRule } from '../../../../objects/rule'; +import { expandFirstAlert } from '../../../../tasks/alerts'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + alertsTableMoreActionsAreNotAvailable, + cannotAddAssigneesViaDetailsFlyout, + loadPageAs, +} from '../../../../tasks/alert_assignments'; + +describe('Alert user assignment - ESS', { tags: ['@ess'] }, () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_multiple'); + }); + + beforeEach(() => { + loadPageAs(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'new custom rule' })); + waitForAlertsToPopulate(); + }); + + it('viewer/reader should not be able to update assignees', () => { + // Login as a reader + loadPageAs(ALERTS_URL, ROLES.reader); + waitForAlertsToPopulate(); + + // Check alerts table + alertsTableMoreActionsAreNotAvailable(); + + // Check alert's details flyout + expandFirstAlert(); + cannotAddAssigneesViaDetailsFlyout(); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess_basic.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess_basic.cy.ts new file mode 100644 index 000000000000..34bab70e43b0 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_ess_basic.cy.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { login } from '../../../../tasks/login'; +import { getNewRule } from '../../../../objects/rule'; +import { expandFirstAlert } from '../../../../tasks/alerts'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + asigneesMenuItemsAreNotAvailable, + cannotAddAssigneesViaDetailsFlyout, + loadPageAs, +} from '../../../../tasks/alert_assignments'; + +describe('Alert user assignment - Basic License', { tags: ['@ess'] }, () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); + login(); + cy.request({ + method: 'POST', + url: '/api/license/start_basic?acknowledge=true', + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + }, + }).then(({ body }) => { + cy.log(`body: ${JSON.stringify(body)}`); + expect(body).contains({ + acknowledged: true, + basic_was_started: true, + }); + }); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_multiple'); + }); + + beforeEach(() => { + loadPageAs(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'new custom rule' })); + waitForAlertsToPopulate(); + }); + + it('user with Basic license should not be able to update assignees', () => { + // Check alerts table + asigneesMenuItemsAreNotAvailable(); + + // Check alert's details flyout + expandFirstAlert(); + cannotAddAssigneesViaDetailsFlyout(); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_complete.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_complete.cy.ts new file mode 100644 index 000000000000..ff9f3801644a --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_complete.cy.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { getNewRule } from '../../../../objects/rule'; +import { refreshAlertPageFilter, selectFirstPageAlerts } from '../../../../tasks/alerts'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + alertsTableShowsAssigneesForAlert, + updateAssigneesForAlert, + bulkRemoveAllAssignees, + loadPageAs, +} from '../../../../tasks/alert_assignments'; + +describe( + 'Alert user assignment - Serverless Complete', + { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [ + { product_line: 'security', product_tier: 'complete' }, + { product_line: 'endpoint', product_tier: 'complete' }, + ], + }, + }, + }, + () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); + + // Login into accounts so that they got activated and visible in user profiles list + login(ROLES.t1_analyst); + login(ROLES.t2_analyst); + login(ROLES.t3_analyst); + login(ROLES.soc_manager); + login(ROLES.detections_admin); + login(ROLES.platform_engineer); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_multiple'); + }); + + beforeEach(() => { + loadPageAs(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'new custom rule' })); + waitForAlertsToPopulate(); + }); + + context('Authorization / RBAC', () => { + it('users with editing privileges should be able to update assignees', () => { + const editors = [ + ROLES.t1_analyst, + ROLES.t2_analyst, + ROLES.t3_analyst, + ROLES.rule_author, + ROLES.soc_manager, + ROLES.detections_admin, + ROLES.platform_engineer, + ]; + editors.forEach((role) => { + loadPageAs(ALERTS_URL, role); + waitForAlertsToPopulate(); + + // Unassign alert + selectFirstPageAlerts(); + bulkRemoveAllAssignees(); + refreshAlertPageFilter(); + + updateAssigneesForAlert([role]); + + // Assignees should appear in the alerts table + alertsTableShowsAssigneesForAlert([role]); + }); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_essentials.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_essentials.cy.ts new file mode 100644 index 000000000000..53436e0102f0 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/assignments/assignments_serverless_essentials.cy.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { getNewRule } from '../../../../objects/rule'; +import { refreshAlertPageFilter, selectFirstPageAlerts } from '../../../../tasks/alerts'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + alertsTableShowsAssigneesForAlert, + updateAssigneesForAlert, + bulkRemoveAllAssignees, + loadPageAs, +} from '../../../../tasks/alert_assignments'; + +describe( + 'Alert user assignment - Serverless Essentials', + { + tags: ['@serverless'], + env: { + ftrConfig: { + productTypes: [ + { product_line: 'security', product_tier: 'essentials' }, + { product_line: 'endpoint', product_tier: 'essentials' }, + ], + }, + }, + }, + () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); + + // Login into accounts so that they got activated and visible in user profiles list + login(ROLES.t1_analyst); + login(ROLES.t2_analyst); + login(ROLES.t3_analyst); + login(ROLES.soc_manager); + login(ROLES.detections_admin); + login(ROLES.platform_engineer); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_multiple'); + }); + + beforeEach(() => { + loadPageAs(ALERTS_URL); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: 'new custom rule' })); + waitForAlertsToPopulate(); + }); + + context('Authorization / RBAC', () => { + it('users with editing privileges should be able to update assignees', () => { + const editors = [ + ROLES.t1_analyst, + ROLES.t2_analyst, + ROLES.t3_analyst, + ROLES.rule_author, + ROLES.soc_manager, + ROLES.detections_admin, + ROLES.platform_engineer, + ]; + editors.forEach((role) => { + loadPageAs(ALERTS_URL, role); + waitForAlertsToPopulate(); + + // Unassign alert + selectFirstPageAlerts(); + bulkRemoveAllAssignees(); + refreshAlertPageFilter(); + + updateAssigneesForAlert([role]); + + // Assignees should appear in the alerts table + alertsTableShowsAssigneesForAlert([role]); + }); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts index 3e75f8b4a28b..4dffc5f322ad 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts @@ -25,13 +25,13 @@ import { ruleDetailsUrl } from '../../../urls/rule_details'; const loadPageAsReadOnlyUser = (url: string) => { login(ROLES.t1_analyst); - visit(url, { role: ROLES.t1_analyst }); + visit(url); waitForPageTitleToBeShown(); }; const loadPageAsPlatformEngineer = (url: string) => { login(ROLES.platform_engineer); - visit(url, { role: ROLES.platform_engineer }); + visit(url); waitForPageTitleToBeShown(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts index 98080cb3b47e..3053f8e5c569 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts @@ -10,7 +10,11 @@ import { getSimpleCustomQueryRule } from '../../../objects/rule'; import { goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; import { deleteIndex, waitForNewDocumentToBeIndexed } from '../../../tasks/api_calls/elasticsearch'; -import { deleteAlertsAndRules, deleteConnectors, deleteDataView } from '../../../tasks/common'; +import { + deleteAlertsAndRules, + deleteConnectors, + deleteDataView, +} from '../../../tasks/api_calls/common'; import { createAndEnableRule, fillAboutRuleAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_complete.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_complete.cy.ts index 23421b218bcb..13c35a3cce6c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_complete.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_complete.cy.ts @@ -18,7 +18,7 @@ import { import { createRule } from '../../../tasks/api_calls/rules'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { goToActionsStepTab } from '../../../tasks/create_new_rule'; import { login } from '../../../tasks/login'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_essentials.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_essentials.cy.ts index 83503ea98738..d36cdc7137de 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_essentials.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions_pli_essentials.cy.ts @@ -18,7 +18,7 @@ import { import { createRule } from '../../../tasks/api_calls/rules'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { goToActionsStepTab } from '../../../tasks/create_new_rule'; import { login } from '../../../tasks/login'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/common_flows.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/common_flows.cy.ts index e8780d8696d2..9628f03f2d10 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/common_flows.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/common_flows.cy.ts @@ -19,7 +19,7 @@ import { } from '../../../screens/create_new_rule'; import { RULE_NAME_HEADER } from '../../../screens/rule_details'; import { createTimeline } from '../../../tasks/api_calls/timelines'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { createAndEnableRule, expandAdvancedSettings, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts index e4bb4b2bfba8..5e41440f48f4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts @@ -8,7 +8,7 @@ import { getNewRule } from '../../../objects/rule'; import { RULE_NAME_HEADER } from '../../../screens/rule_details'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { fillScheduleRuleAndContinue, fillAboutRuleMinimumAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts index d13a676e8425..7a6d1fa889e5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts @@ -52,7 +52,11 @@ import { getRulesManagementTableRows, goToRuleDetailsOf, } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules, deleteDataView, postDataView } from '../../../tasks/common'; +import { + deleteAlertsAndRules, + deleteDataView, + postDataView, +} from '../../../tasks/api_calls/common'; import { createAndEnableRule, createRuleWithoutEnabling, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts index 03ba3db7f25f..f55a51d8e4f6 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts @@ -24,7 +24,7 @@ import { import { editFirstRule, goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; import { createSavedQuery, deleteSavedQueries } from '../../../tasks/api_calls/saved_queries'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { createAndEnableRule, fillAboutRuleAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/esql_rule_ess.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/esql_rule_ess.cy.ts index 2fa97e4f76e4..0e10557bcaf0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/esql_rule_ess.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/esql_rule_ess.cy.ts @@ -18,7 +18,7 @@ import { ESQL_TYPE, ESQL_QUERY_BAR } from '../../../screens/create_new_rule'; import { getDetails, goBackToRulesTable } from '../../../tasks/rule_details'; import { expectNumberOfRules } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { fillAboutRuleAndContinue, fillDefineEsqlRuleAndContinue, @@ -85,7 +85,8 @@ describe('Detection ES|QL rules, creation', { tags: ['@ess'] }, () => { }); }); - describe('ES|QL query validation', () => { + // FLAKY: https://github.com/elastic/kibana/issues/172074 + describe.skip('ES|QL query validation', () => { beforeEach(() => { login(); visit(CREATE_RULE_URL); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts index b89546066185..0966ae270911 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts @@ -43,7 +43,7 @@ import { import { getDetails, waitForTheRuleToBeExecuted } from '../../../tasks/rule_details'; import { expectNumberOfRules, goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { createAndEnableRule, fillAboutRuleAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts index 6dbe81076c91..2b83c938b947 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts @@ -111,7 +111,7 @@ import { import { CREATE_RULE_URL } from '../../../urls/navigation'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; import { openRuleManagementPageViaBreadcrumbs } from '../../../tasks/rules_management'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts index 8b8c6fe4e145..570f19f3f72e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts @@ -45,7 +45,7 @@ import { import { getDetails, waitForTheRuleToBeExecuted } from '../../../tasks/rule_details'; import { expectNumberOfRules, goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { createAndEnableRule, fillAboutRuleAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts index 585cd9187f3e..9bb9f569c4dd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts @@ -47,7 +47,7 @@ import { TIMESTAMP_OVERRIDE_DETAILS, } from '../../../screens/rule_details'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { expectNumberOfRules, goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; import { createAndEnableRule, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts index 503b40f56830..62fdb9121c9c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts @@ -45,7 +45,7 @@ import { import { getDetails, waitForTheRuleToBeExecuted } from '../../../tasks/rule_details'; import { expectNumberOfRules, goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { createAndEnableRule, fillAboutRuleAndContinue, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/esql_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/esql_rule.cy.ts deleted file mode 100644 index 93100216692a..000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/esql_rule.cy.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getEsqlRule } from '../../../objects/rule'; - -import { - ESQL_QUERY_DETAILS, - DEFINITION_DETAILS, - RULE_NAME_HEADER, - RULE_TYPE_DETAILS, -} from '../../../screens/rule_details'; - -import { createRule } from '../../../tasks/api_calls/rules'; - -import { getDetails } from '../../../tasks/rule_details'; -import { deleteAlertsAndRules } from '../../../tasks/common'; - -import { login } from '../../../tasks/login'; -import { visit } from '../../../tasks/navigation'; - -import { ruleDetailsUrl } from '../../../urls/rule_details'; - -describe('Detection ES|QL rules, details view', { tags: ['@ess'] }, () => { - const rule = getEsqlRule(); - - beforeEach(() => { - deleteAlertsAndRules(); - login(); - }); - - it('displays ES|QL rule specific fields', function () { - createRule(getEsqlRule()).then((createdRule) => { - visit(ruleDetailsUrl(createdRule.body.id)); - - cy.get(RULE_NAME_HEADER).should('contain', `${rule.name}`); - - cy.get(DEFINITION_DETAILS).within(() => { - getDetails(ESQL_QUERY_DETAILS).should('have.text', rule.query); - - getDetails(RULE_TYPE_DETAILS).contains('ES|QL'); - // ensures ES|QL rule in technical preview - getDetails(RULE_TYPE_DETAILS).contains('Technical Preview'); - }); - }); - }); -}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/custom_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/custom_query_rule.cy.ts index ca6d6c56adcf..e9497851d4cb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/custom_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/custom_query_rule.cy.ts @@ -42,7 +42,7 @@ import { } from '../../../screens/rule_details'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules, deleteConnectors } from '../../../tasks/common'; +import { deleteAlertsAndRules, deleteConnectors } from '../../../tasks/api_calls/common'; import { addEmailConnectorAndRuleAction } from '../../../tasks/common/rule_actions'; import { fillAboutRule, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/esql_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/esql_rule.cy.ts index eb16d89a6af8..20d48b211995 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/esql_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit/esql_rule.cy.ts @@ -15,7 +15,7 @@ import { createRule } from '../../../tasks/api_calls/rules'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; import { getDetails } from '../../../tasks/rule_details'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { clearEsqlQueryBar, fillEsqlQueryBar, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts index 244637126ecc..f89a01dff1be 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts @@ -33,7 +33,7 @@ describe('All rules - read only', { tags: ['@ess', '@serverless', '@skipInServer beforeEach(() => { login(ROLES.t1_analyst); - visitRulesManagementTable(ROLES.t1_analyst); + visitRulesManagementTable(); cy.get(RULE_NAME).should('have.text', getNewRule().name); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_authorization.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_authorization.cy.ts similarity index 93% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_authorization.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_authorization.cy.ts index e0078dd54e7e..a60d6d6fe56d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_authorization.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_authorization.cy.ts @@ -12,14 +12,14 @@ import { } from '@kbn/security-solution-plugin/common/constants'; import { ROLES } from '@kbn/security-solution-plugin/common/test'; -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { createAndInstallMockedPrebuiltRules, installPrebuiltRuleAssets, preventPrebuiltRulesPackageInstallation, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { visit } from '../../../tasks/navigation'; -import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { visit } from '../../../../tasks/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../../urls/rules_management'; import { ADD_ELASTIC_RULES_BTN, getInstallSingleRuleButtonByRuleId, @@ -31,8 +31,8 @@ import { RULES_UPDATES_TAB, RULE_CHECKBOX, UPGRADE_ALL_RULES_BUTTON, -} from '../../../screens/alerts_detection_rules'; -import { login } from '../../../tasks/login'; +} from '../../../../screens/alerts_detection_rules'; +import { login } from '../../../../tasks/login'; // Rule to test update const RULE_1_ID = 'rule_1'; @@ -57,12 +57,12 @@ const RULE_2 = createRuleAssetSavedObject({ const loadPageAsReadOnlyUser = (url: string) => { login(ROLES.t1_analyst); - visit(url, { role: ROLES.t1_analyst }); + visit(url); }; const loginPageAsWriteAuthorizedUser = (url: string) => { login(ROLES.t3_analyst); - visit(url, { role: ROLES.t3_analyst }); + visit(url); }; describe( diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_error_handling.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_error_handling.cy.ts similarity index 94% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_error_handling.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_error_handling.cy.ts index 7e288910ccb6..db84d92e4ddb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_update_error_handling.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_update_error_handling.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { getInstallSingleRuleButtonByRuleId, getUpgradeSingleRuleButtonByRuleId, @@ -14,14 +14,14 @@ import { SELECT_ALL_RULES_ON_PAGE_CHECKBOX, UPGRADE_ALL_RULES_BUTTON, UPGRADE_SELECTED_RULES_BUTTON, -} from '../../../screens/alerts_detection_rules'; -import { selectRulesByName } from '../../../tasks/alerts_detection_rules'; +} from '../../../../screens/alerts_detection_rules'; +import { selectRulesByName } from '../../../../tasks/alerts_detection_rules'; import { installPrebuiltRuleAssets, createAndInstallMockedPrebuiltRules, preventPrebuiltRulesPackageInstallation, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { login } from '../../../tasks/login'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { login } from '../../../../tasks/login'; import { clickAddElasticRulesButton, assertInstallationRequestIsComplete, @@ -33,8 +33,8 @@ import { assertRulesPresentInAddPrebuiltRulesTable, assertRuleUpgradeFailureToastShown, assertRulesPresentInRuleUpdatesTable, -} from '../../../tasks/prebuilt_rules'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +} from '../../../../tasks/prebuilt_rules'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; describe( 'Detection rules, Prebuilt Rules Installation and Update - Error handling', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_via_fleet.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_via_fleet.cy.ts similarity index 90% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_via_fleet.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_via_fleet.cy.ts index 630bd099a1d0..762e79bb2700 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_via_fleet.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_via_fleet.cy.ts @@ -8,12 +8,13 @@ import type { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common'; import type { Rule } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common'; -import { INSTALL_ALL_RULES_BUTTON, TOASTER } from '../../../screens/alerts_detection_rules'; -import { getRuleAssets } from '../../../tasks/api_calls/prebuilt_rules'; -import { login } from '../../../tasks/login'; -import { clickAddElasticRulesButton } from '../../../tasks/prebuilt_rules'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +import { resetRulesTableState } from '../../../../tasks/common'; +import { INSTALL_ALL_RULES_BUTTON, TOASTER } from '../../../../screens/alerts_detection_rules'; +import { getRuleAssets } from '../../../../tasks/api_calls/prebuilt_rules'; +import { login } from '../../../../tasks/login'; +import { clickAddElasticRulesButton } from '../../../../tasks/prebuilt_rules'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; describe( 'Detection rules, Prebuilt Rules Installation and Update workflow', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_workflow.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_workflow.cy.ts similarity index 85% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_workflow.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_workflow.cy.ts index 15e77fad28d0..523d0ec0ad4e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/install_workflow.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/install_workflow.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common'; -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { resetRulesTableState } from '../../../../tasks/common'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { getInstallSingleRuleButtonByRuleId, GO_BACK_TO_RULES_TABLE_BUTTON, @@ -16,18 +16,19 @@ import { RULE_CHECKBOX, SELECT_ALL_RULES_ON_PAGE_CHECKBOX, TOASTER, -} from '../../../screens/alerts_detection_rules'; -import { selectRulesByName } from '../../../tasks/alerts_detection_rules'; -import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../../../screens/breadcrumbs'; -import { installPrebuiltRuleAssets } from '../../../tasks/api_calls/prebuilt_rules'; -import { login } from '../../../tasks/login'; +} from '../../../../screens/alerts_detection_rules'; +import { selectRulesByName } from '../../../../tasks/alerts_detection_rules'; +import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../../../../screens/breadcrumbs'; +import { installPrebuiltRuleAssets } from '../../../../tasks/api_calls/prebuilt_rules'; +import { login } from '../../../../tasks/login'; import { assertInstallationRequestIsComplete, assertRuleInstallationSuccessToastShown, assertRulesPresentInInstalledRulesTable, clickAddElasticRulesButton, -} from '../../../tasks/prebuilt_rules'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +} from '../../../../tasks/prebuilt_rules'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; describe( 'Detection rules, Prebuilt Rules Installation and Update workflow', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/management.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/management.cy.ts similarity index 91% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/management.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/management.cy.ts index d5a3f3bb8532..15e020b5e066 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/management.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/management.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { COLLAPSED_ACTION_BTN, ELASTIC_RULES_BTN, @@ -15,7 +15,7 @@ import { RULE_SWITCH, SELECT_ALL_RULES_ON_PAGE_CHECKBOX, INSTALL_ALL_RULES_BUTTON, -} from '../../../screens/alerts_detection_rules'; +} from '../../../../screens/alerts_detection_rules'; import { deleteFirstRule, disableAutoRefresh, @@ -24,21 +24,24 @@ import { selectRulesByName, waitForPrebuiltDetectionRulesToBeLoaded, waitForRuleToUpdate, -} from '../../../tasks/alerts_detection_rules'; +} from '../../../../tasks/alerts_detection_rules'; import { deleteSelectedRules, disableSelectedRules, enableSelectedRules, -} from '../../../tasks/rules_bulk_actions'; +} from '../../../../tasks/rules_bulk_actions'; import { createAndInstallMockedPrebuiltRules, getAvailablePrebuiltRulesCount, preventPrebuiltRulesPackageInstallation, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { deleteAlertsAndRules, deletePrebuiltRulesAssets } from '../../../tasks/common'; -import { login } from '../../../tasks/login'; -import { visit } from '../../../tasks/navigation'; -import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { + deleteAlertsAndRules, + deletePrebuiltRulesAssets, +} from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { visit } from '../../../../tasks/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../../urls/rules_management'; const rules = Array.from(Array(5)).map((_, i) => { return createRuleAssetSavedObject({ diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/notifications.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/notifications.cy.ts similarity index 93% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/notifications.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/notifications.cy.ts index 180c435c1021..4812efc740ae 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/notifications.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/notifications.cy.ts @@ -5,25 +5,25 @@ * 2.0. */ -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { ADD_ELASTIC_RULES_BTN, ADD_ELASTIC_RULES_EMPTY_PROMPT_BTN, RULES_UPDATES_TAB, -} from '../../../screens/alerts_detection_rules'; -import { deleteFirstRule } from '../../../tasks/alerts_detection_rules'; +} from '../../../../screens/alerts_detection_rules'; +import { deleteFirstRule } from '../../../../tasks/alerts_detection_rules'; +import { + deleteAlertsAndRules, + deletePrebuiltRulesAssets, +} from '../../../../tasks/api_calls/common'; import { installAllPrebuiltRulesRequest, installPrebuiltRuleAssets, createAndInstallMockedPrebuiltRules, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { - resetRulesTableState, - deleteAlertsAndRules, - deletePrebuiltRulesAssets, -} from '../../../tasks/common'; -import { login } from '../../../tasks/login'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { resetRulesTableState } from '../../../../tasks/common'; +import { login } from '../../../../tasks/login'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; const RULE_1 = createRuleAssetSavedObject({ name: 'Test rule 1', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts similarity index 97% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_preview.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts index 0b49fe4bb1de..81f37b7760df 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts @@ -12,27 +12,22 @@ import type { PrebuiltRuleAsset } from '@kbn/security-solution-plugin/server/lib import type { Threshold } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema'; import { AlertSuppression } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema'; -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { INSTALL_PREBUILT_RULE_BUTTON, INSTALL_PREBUILT_RULE_PREVIEW, UPDATE_PREBUILT_RULE_PREVIEW, UPDATE_PREBUILT_RULE_BUTTON, -} from '../../../screens/alerts_detection_rules'; -import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../../../screens/breadcrumbs'; +} from '../../../../screens/alerts_detection_rules'; +import { RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../../../../screens/breadcrumbs'; import { installPrebuiltRuleAssets, createAndInstallMockedPrebuiltRules, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { createSavedQuery, deleteSavedQueries } from '../../../tasks/api_calls/saved_queries'; -import { fetchMachineLearningModules } from '../../../tasks/api_calls/machine_learning'; -import { - resetRulesTableState, - deleteAlertsAndRules, - postDataView, - deleteDataView, -} from '../../../tasks/common'; -import { login } from '../../../tasks/login'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { createSavedQuery, deleteSavedQueries } from '../../../../tasks/api_calls/saved_queries'; +import { fetchMachineLearningModules } from '../../../../tasks/api_calls/machine_learning'; +import { resetRulesTableState } from '../../../../tasks/common'; +import { login } from '../../../../tasks/login'; import { assertRuleInstallationSuccessToastShown, assertRulesNotPresentInAddPrebuiltRulesTable, @@ -41,7 +36,7 @@ import { assertRuleUpgradeSuccessToastShown, clickAddElasticRulesButton, clickRuleUpdatesTab, -} from '../../../tasks/prebuilt_rules'; +} from '../../../../tasks/prebuilt_rules'; import { assertAlertSuppressionPropertiesShown, assertCommonPropertiesShown, @@ -60,8 +55,13 @@ import { closeRulePreview, openRuleInstallPreview, openRuleUpdatePreview, -} from '../../../tasks/prebuilt_rules_preview'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +} from '../../../../tasks/prebuilt_rules_preview'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; +import { + deleteAlertsAndRules, + deleteDataView, + postDataView, +} from '../../../../tasks/api_calls/common'; const TEST_ENV_TAGS = ['@ess', '@serverless']; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/update_workflow.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/update_workflow.ts similarity index 88% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/update_workflow.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/update_workflow.ts index 2e38b4782b43..d858280dd529 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/update_workflow.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/update_workflow.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { getUpgradeSingleRuleButtonByRuleId, NO_RULES_AVAILABLE_FOR_UPGRADE_MESSAGE, @@ -13,21 +13,22 @@ import { SELECT_ALL_RULES_ON_PAGE_CHECKBOX, UPGRADE_ALL_RULES_BUTTON, UPGRADE_SELECTED_RULES_BUTTON, -} from '../../../screens/alerts_detection_rules'; -import { selectRulesByName } from '../../../tasks/alerts_detection_rules'; +} from '../../../../screens/alerts_detection_rules'; +import { selectRulesByName } from '../../../../tasks/alerts_detection_rules'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { installPrebuiltRuleAssets, createAndInstallMockedPrebuiltRules, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common'; -import { login } from '../../../tasks/login'; +} from '../../../../tasks/api_calls/prebuilt_rules'; +import { resetRulesTableState } from '../../../../tasks/common'; +import { login } from '../../../../tasks/login'; import { assertRulesNotPresentInRuleUpdatesTable, assertRuleUpgradeSuccessToastShown, assertUpgradeRequestIsComplete, clickRuleUpdatesTab, -} from '../../../tasks/prebuilt_rules'; -import { visitRulesManagementTable } from '../../../tasks/rules_management'; +} from '../../../../tasks/prebuilt_rules'; +import { visitRulesManagementTable } from '../../../../tasks/rules_management'; describe( 'Detection rules, Prebuilt Rules Installation and Update workflow', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts index 1376e486790b..51aa3f406b8e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts @@ -26,14 +26,14 @@ import { disableRelatedIntegrations, enableRelatedIntegrations, } from '../../../../tasks/api_calls/kibana_advanced_settings'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../tasks/rules_management'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; import { installIntegrations, PackagePolicyWithoutAgentPolicyId, -} from '../../../../tasks/integrations'; +} from '../../../../tasks/api_calls/integrations'; import { disableAutoRefresh, openIntegrationsPopover, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts index fd6b28fbe57e..dd053ab958aa 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { deleteAlertsAndRules } from '../../../../../tasks/api_calls/common'; import { goToRuleDetailsOf, expectManagementTableRules, @@ -21,7 +22,7 @@ import { login } from '../../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../../tasks/rules_management'; import { createRule } from '../../../../../tasks/api_calls/rules'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../../../tasks/common'; +import { resetRulesTableState } from '../../../../../tasks/common'; import { getNewRule } from '../../../../../objects/rule'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts index 920c03529c11..94b6804b3119 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { deleteAlertsAndRules } from '../../../../../tasks/api_calls/common'; import { MODAL_CONFIRMATION_BTN, MODAL_CONFIRMATION_BODY, @@ -79,7 +80,7 @@ import { login } from '../../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../../tasks/rules_management'; import { createRule } from '../../../../../tasks/api_calls/rules'; import { loadPrepackagedTimelineTemplates } from '../../../../../tasks/api_calls/timelines'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../../../tasks/common'; +import { resetRulesTableState } from '../../../../../tasks/common'; import { getEqlRule, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts index ac6c723dbc0c..9a4d3cdc1b1d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts @@ -20,7 +20,7 @@ import { } from '../../../../../screens/rules_bulk_actions'; import { actionFormSelector } from '../../../../../screens/common/rule_actions'; -import { deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common'; +import { deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/api_calls/common'; import type { RuleActionCustomFrequency } from '../../../../../tasks/common/rule_actions'; import { addSlackRuleAction, @@ -148,7 +148,7 @@ describe( context('Restricted action privileges', () => { it("User with no privileges can't add rule actions", () => { login(ROLES.hunter_no_actions); - visitRulesManagementTable(ROLES.hunter_no_actions); + visitRulesManagementTable(); expectManagementTableRules([ ruleNameToAssert, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts index 21adb447d2ce..3b9ddf73ad3c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts @@ -39,7 +39,11 @@ import { login } from '../../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../../tasks/rules_management'; import { createRule } from '../../../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules, deleteDataView, postDataView } from '../../../../../tasks/common'; +import { + deleteAlertsAndRules, + deleteDataView, + postDataView, +} from '../../../../../tasks/api_calls/common'; import { getEqlRule, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/deletion/rule_delete.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/deletion/rule_delete.cy.ts index 0896438e275e..4c9168744920 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/deletion/rule_delete.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/deletion/rule_delete.cy.ts @@ -18,7 +18,7 @@ import { } from '../../../../../tasks/alerts_detection_rules'; import { deleteSelectedRules } from '../../../../../tasks/rules_bulk_actions'; import { createRule, findAllRules } from '../../../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../../tasks/api_calls/common'; import { login } from '../../../../../tasks/login'; describe('Rule deletion', { tags: ['@ess', '@serverless'] }, () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts index 0fb3d6f08613..0cfcc4371449 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts @@ -7,6 +7,7 @@ import path from 'path'; +import { deleteAlertsAndRules } from '../../../../../tasks/api_calls/common'; import { expectedExportedRule, getNewRule } from '../../../../../objects/rule'; import { TOASTER_BODY, @@ -29,7 +30,7 @@ import { } from '../../../../../tasks/api_calls/exceptions'; import { getExceptionList } from '../../../../../objects/exception'; import { createRule } from '../../../../../tasks/api_calls/rules'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../../../tasks/common'; +import { resetRulesTableState } from '../../../../../tasks/common'; import { login } from '../../../../../tasks/login'; import { visit } from '../../../../../tasks/navigation'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts index 197ad5a9a82f..4b8fe5b5312b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts @@ -11,7 +11,7 @@ import { importRules, importRulesWithOverwriteAll, } from '../../../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../../tasks/api_calls/common'; import { deleteExceptionList } from '../../../../../tasks/api_calls/exceptions'; import { login } from '../../../../../tasks/login'; import { visit } from '../../../../../tasks/navigation'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts index 025aff9510d9..7e753d42b6b6 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts @@ -9,7 +9,7 @@ import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/comm import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine'; import { createRule, snoozeRule as snoozeRuleViaAPI } from '../../../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common'; +import { deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/api_calls/common'; import { login } from '../../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../../tasks/rules_management'; import { getNewRule } from '../../../../../objects/rule'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/common_flows.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/common_flows.cy.ts similarity index 88% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/common_flows.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/common_flows.cy.ts index 5e5af0e6ad4a..0610786fc1b8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_details/common_flows.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/common_flows.cy.ts @@ -5,17 +5,17 @@ * 2.0. */ -import { deleteRuleFromDetailsPage } from '../../../tasks/alerts_detection_rules'; +import { deleteRuleFromDetailsPage } from '../../../../tasks/alerts_detection_rules'; import { CUSTOM_RULES_BTN, RULES_MANAGEMENT_TABLE, RULES_ROW, -} from '../../../screens/alerts_detection_rules'; -import { createRule } from '../../../tasks/api_calls/rules'; -import { getDetails } from '../../../tasks/rule_details'; -import { ruleFields } from '../../../data/detection_engine'; -import { getTimeline } from '../../../objects/timeline'; -import { getExistingRule, getNewRule } from '../../../objects/rule'; +} from '../../../../screens/alerts_detection_rules'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { getDetails } from '../../../../tasks/rule_details'; +import { ruleFields } from '../../../../data/detection_engine'; +import { getTimeline } from '../../../../objects/timeline'; +import { getExistingRule, getNewRule } from '../../../../objects/rule'; import { ABOUT_DETAILS, @@ -42,13 +42,13 @@ import { THREAT_TACTIC, THREAT_TECHNIQUE, TIMELINE_TEMPLATE_DETAILS, -} from '../../../screens/rule_details'; +} from '../../../../screens/rule_details'; -import { createTimeline } from '../../../tasks/api_calls/timelines'; -import { deleteAlertsAndRules, deleteConnectors } from '../../../tasks/common'; -import { login } from '../../../tasks/login'; -import { visit } from '../../../tasks/navigation'; -import { ruleDetailsUrl } from '../../../urls/rule_details'; +import { createTimeline } from '../../../../tasks/api_calls/timelines'; +import { deleteAlertsAndRules, deleteConnectors } from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { visit } from '../../../../tasks/navigation'; +import { ruleDetailsUrl } from '../../../../urls/rule_details'; // This test is meant to test all common aspects of the rule details page that should function // the same regardless of rule type. For any rule type specific functionalities, please include diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/esql_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/esql_rule.cy.ts new file mode 100644 index 000000000000..c59b7db55c74 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/esql_rule.cy.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getEsqlRule } from '../../../../objects/rule'; + +import { + ESQL_QUERY_DETAILS, + DEFINITION_DETAILS, + RULE_NAME_HEADER, + RULE_TYPE_DETAILS, +} from '../../../../screens/rule_details'; + +import { createRule } from '../../../../tasks/api_calls/rules'; + +import { getDetails } from '../../../../tasks/rule_details'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; + +import { login } from '../../../../tasks/login'; +import { visit } from '../../../../tasks/navigation'; + +import { ruleDetailsUrl } from '../../../../urls/rule_details'; + +describe('Detection ES|QL rules, details view', { tags: ['@ess'] }, () => { + const rule = getEsqlRule(); + + beforeEach(() => { + deleteAlertsAndRules(); + login(); + }); + + it('displays ES|QL rule specific fields', function () { + createRule(getEsqlRule()).then((createdRule) => { + visit(ruleDetailsUrl(createdRule.body.id)); + + cy.get(RULE_NAME_HEADER).should('contain', `${rule.name}`); + + cy.get(DEFINITION_DETAILS).within(() => { + getDetails(ESQL_QUERY_DETAILS).should('have.text', rule.query); + + getDetails(RULE_TYPE_DETAILS).contains('ES|QL'); + // ensures ES|QL rule in technical preview + getDetails(RULE_TYPE_DETAILS).contains('Technical Preview'); + }); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts index b76b862c70d0..117fc0eee632 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { resetRulesTableState, deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { resetRulesTableState } from '../../../../tasks/common'; import { login } from '../../../../tasks/login'; import { visitRulesManagementTable } from '../../../../tasks/rules_management'; import { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts index cf81271c1ad3..ace4406b1c22 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts @@ -8,7 +8,7 @@ import { getNewRule } from '../../../../objects/rule'; import { RULES_MONITORING_TAB, RULE_NAME } from '../../../../screens/alerts_detection_rules'; import { createRule } from '../../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; import { RULES_MANAGEMENT_URL } from '../../../../urls/rules_management'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts index b31bd620400a..6014f1c83b9a 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts @@ -12,6 +12,7 @@ import { SELECT_ALL_RULES_ON_PAGE_CHECKBOX, } from '../../../../screens/alerts_detection_rules'; import { + disableAutoRefresh, selectRulesByName, unselectRulesByName, waitForPrebuiltDetectionRulesToBeLoaded, @@ -43,6 +44,7 @@ describe( createAndInstallMockedPrebuiltRules([RULE_1, RULE_2]); visit(RULES_MANAGEMENT_URL); waitForPrebuiltDetectionRulesToBeLoaded(); + disableAutoRefresh(); }); it('should correctly update the selection label when rules are individually selected and unselected', () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts index 2fd13f8b6696..6838532d5593 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts @@ -19,9 +19,9 @@ import { refreshPage } from '../../../tasks/security_header'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { createField } from '../../../tasks/create_runtime_field'; import { openAlertsFieldBrowser } from '../../../tasks/alerts'; -import { deleteRuntimeField } from '../../../tasks/sourcerer'; import { GET_DATA_GRID_HEADER } from '../../../screens/common/data_grid'; import { GET_TIMELINE_HEADER } from '../../../screens/timeline'; +import { deleteRuntimeField } from '../../../tasks/api_calls/sourcerer'; const alertRunTimeField = 'field.name.alert.page'; const timelineRuntimeField = 'field.name.timeline'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts index dbf5a5975f66..d27444e3d9a8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts @@ -26,7 +26,7 @@ import { resetSourcerer, saveSourcerer, } from '../../../tasks/sourcerer'; -import { postDataView } from '../../../tasks/common'; +import { postDataView } from '../../../tasks/api_calls/common'; import { SOURCERER } from '../../../screens/sourcerer'; const siemDataViewTitle = 'Security Default Data View'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts index 52b8ccee8215..e26756924b88 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts @@ -5,31 +5,24 @@ * 2.0. */ -import { loginWithUser } from '../../../tasks/login'; -import { visitWithUser } from '../../../tasks/navigation'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; import { hostsUrl } from '../../../urls/navigation'; -import { postDataView } from '../../../tasks/common'; -import { - createUsersAndRoles, - secReadCasesAll, - secReadCasesAllUser, -} from '../../../tasks/privileges'; +import { postDataView } from '../../../tasks/api_calls/common'; import { TOASTER } from '../../../screens/configure_cases'; +import { visit } from '../../../tasks/navigation'; +import { login } from '../../../tasks/login'; -const usersToCreate = [secReadCasesAllUser]; -const rolesToCreate = [secReadCasesAll]; const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; -describe('Sourcerer permissions', { tags: ['@ess', '@skipInServerless'] }, () => { +describe('Sourcerer permissions', { tags: ['@ess', '@brokenInServerless'] }, () => { before(() => { dataViews.forEach((dataView: string) => postDataView(dataView)); - createUsersAndRoles(usersToCreate, rolesToCreate); }); - it(`role(s) ${secReadCasesAllUser.roles.join()} shows error when user does not have permissions`, () => { - loginWithUser(secReadCasesAllUser); - visitWithUser(hostsUrl('allHosts'), secReadCasesAllUser); + it(`role Hunter No actions shows error when user does not have permissions`, () => { + login(ROLES.hunter_no_actions); + visit(hostsUrl('allHosts')); cy.get(TOASTER).should('have.text', 'Write role required to generate data'); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts index ddc1f939c08f..94ed3c97e591 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts @@ -16,7 +16,7 @@ describe('value list permissions', { tags: ['@ess', '@skipInServerless'] }, () = describe('user with restricted access role', () => { it('Does not allow a t1 analyst user to upload a value list', () => { login(ROLES.t1_analyst); - visit(RULES_MANAGEMENT_URL, { role: ROLES.t1_analyst }); + visit(RULES_MANAGEMENT_URL); cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled'); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts index fe8d51cae795..60b93650048d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts @@ -17,7 +17,7 @@ import { import { ENRICHED_DATA_ROW } from '../../screens/alerts_details'; import { createRule } from '../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../tasks/common'; +import { deleteAlertsAndRules } from '../../tasks/api_calls/common'; import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; import { expandFirstAlert, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page_privileges_callout.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page_privileges_callout.ts new file mode 100644 index 000000000000..0072b653a3e7 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page_privileges_callout.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { RISK_ENGINE_PRIVILEGES_URL } from '@kbn/security-solution-plugin/common/constants'; +import { + RISK_SCORE_PRIVILEGES_CALLOUT, + RISK_SCORE_STATUS_LOADING, +} from '../../screens/entity_analytics_management'; + +import { login } from '../../tasks/login'; +import { visit } from '../../tasks/navigation'; +import { ENTITY_ANALYTICS_MANAGEMENT_URL } from '../../urls/navigation'; + +const loadPageAsUserWithNoPrivileges = () => { + login(ROLES.no_risk_engine_privileges); + visit(ENTITY_ANALYTICS_MANAGEMENT_URL); +}; + +// this test suite doesn't run on serverless because it requires a custom role +describe( + 'Entity analytics management page - Risk Engine Privileges Callout', + { + tags: ['@ess'], + }, + () => { + it('should not show the callout for superuser', () => { + cy.intercept(RISK_ENGINE_PRIVILEGES_URL).as('getPrivileges'); + login(); + visit(ENTITY_ANALYTICS_MANAGEMENT_URL); + cy.wait('@getPrivileges', { timeout: 15000 }); + cy.get(RISK_SCORE_STATUS_LOADING).should('not.exist'); + cy.get(RISK_SCORE_PRIVILEGES_CALLOUT).should('not.exist'); + }); + + it('should show the callout for user without risk engine privileges', () => { + cy.intercept(RISK_ENGINE_PRIVILEGES_URL).as('getPrivileges'); + loadPageAsUserWithNoPrivileges(); + cy.get(RISK_SCORE_STATUS_LOADING).should('not.exist'); + cy.wait('@getPrivileges', { timeout: 15000 }); + cy.get(RISK_SCORE_PRIVILEGES_CALLOUT); + cy.get(RISK_SCORE_PRIVILEGES_CALLOUT).should( + 'contain', + 'Missing read, write privileges for the risk-score.risk-score-* index.' + ); + cy.get(RISK_SCORE_PRIVILEGES_CALLOUT).should('contain', 'manage_index_templates'); + cy.get(RISK_SCORE_PRIVILEGES_CALLOUT).should('contain', 'manage_transform'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts index 8914b0c98076..c4b605b85dcb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { expandFirstAlert, goToClosedAlertsOnRuleDetailsPage, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts index ee10a2e702b0..8dccaa04bdc8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts @@ -26,7 +26,7 @@ import { import { login } from '../../../../tasks/login'; import { goToExceptionsTab, visitRuleDetailsPage } from '../../../../tasks/rule_details'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { ADD_AND_BTN, ENTRY_DELETE_BTN, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts index 986bcb107124..93e79ba9fa53 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts @@ -10,7 +10,7 @@ import { goToClosedAlertsOnRuleDetailsPage, waitForAlerts, } from '../../../../tasks/alerts'; -import { deleteAlertsAndRules, postDataView } from '../../../../tasks/common'; +import { deleteAlertsAndRules, postDataView } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visitRuleDetailsPage } from '../../../../tasks/rule_details'; import { createRule } from '../../../../tasks/api_calls/rules'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts index 3c613f32d2c7..72c18b27a9b2 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts @@ -47,7 +47,7 @@ import { FIELD_INPUT_PARENT, } from '../../../screens/exceptions'; -import { deleteAlertsAndRules, reload } from '../../../tasks/common'; +import { reload } from '../../../tasks/common'; import { createExceptionList, createExceptionListItem, @@ -55,6 +55,7 @@ import { deleteExceptionList, } from '../../../tasks/api_calls/exceptions'; import { getExceptionList } from '../../../objects/exception'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; // TODO: https://github.com/elastic/kibana/issues/161539 // Test Skipped until we fix the Flyout rerendering issue diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/match_any.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/match_any.cy.ts index f18b056c4e25..282e8d3c8122 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/match_any.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/match_any.cy.ts @@ -26,7 +26,7 @@ import { submitNewExceptionItem, } from '../../../tasks/exceptions'; import { CONFIRM_BTN } from '../../../screens/exceptions'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { ALERTS_COUNT } from '../../../screens/alerts'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts index 136038f641ec..511343abc8a7 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts @@ -25,7 +25,7 @@ import { EXCEPTION_ITEM_VIEWER_CONTAINER, } from '../../../screens/exceptions'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; describe( 'Add multiple conditions and validate the generated exceptions', diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts index 8ec40a0e3643..e75c0eb8d81b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts @@ -30,7 +30,7 @@ import { deleteAlertsAndRules, deleteEndpointExceptionList, deleteExceptionLists, -} from '../../../tasks/common'; +} from '../../../tasks/api_calls/common'; import { NO_EXCEPTIONS_EXIST_PROMPT, EXCEPTION_ITEM_VIEWER_CONTAINER, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts index 6cc022873aea..a06b76455dfb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts @@ -37,7 +37,7 @@ import { submitEditedExceptionItem, submitNewExceptionItem, } from '../../../tasks/exceptions'; -import { deleteAlertsAndRules, deleteExceptionLists } from '../../../tasks/common'; +import { deleteAlertsAndRules, deleteExceptionLists } from '../../../tasks/api_calls/common'; import { NO_EXCEPTIONS_EXIST_PROMPT, EXCEPTION_ITEM_VIEWER_CONTAINER, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts index 79f6638e6c0f..a4f0daa190e4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts @@ -28,7 +28,7 @@ import { waitForTheRuleToBeExecuted, } from '../../../tasks/rule_details'; -import { postDataView, deleteAlertsAndRules } from '../../../tasks/common'; +import { postDataView, deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { NO_EXCEPTIONS_EXIST_PROMPT, EXCEPTION_ITEM_VIEWER_CONTAINER, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts index 935668db1a5a..5cb1ac70818c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts @@ -13,7 +13,7 @@ import { login } from '../../../tasks/login'; import { visitRulesManagementTable } from '../../../tasks/rules_management'; import { goToExceptionsTab, goToAlertsTab } from '../../../tasks/rule_details'; import { goToRuleDetailsOf } from '../../../tasks/alerts_detection_rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { NO_EXCEPTIONS_EXIST_PROMPT, EXCEPTION_ITEM_VIEWER_CONTAINER, @@ -55,7 +55,7 @@ describe('Exceptions viewer read only', { tags: ['@ess'] }, () => { }); login(ROLES.t1_analyst); - visitRulesManagementTable(ROLES.t1_analyst); + visitRulesManagementTable(); goToRuleDetailsOf('Test exceptions rule'); goToExceptionsTab(); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts index 9f64fac5f151..dd21e8571673 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts @@ -40,30 +40,28 @@ import { findSharedExceptionListItemsByName, } from '../../../tasks/exceptions_table'; import { visitRuleDetailsPage } from '../../../tasks/rule_details'; -import { deleteEndpointExceptionList, deleteExceptionLists } from '../../../tasks/common'; +import { + deleteAlertsAndRules, + deleteEndpointExceptionList, + deleteExceptionLists, +} from '../../../tasks/api_calls/common'; -// https://github.com/elastic/kibana/issues/171235 -// FLAKY: https://github.com/elastic/kibana/issues/171242 -describe.skip('Add, edit and delete exception', { tags: ['@ess', '@serverless'] }, () => { +describe('Manage exceptions', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); + deleteAlertsAndRules(); deleteExceptionLists(); deleteEndpointExceptionList(); - cy.task('esArchiverLoad', { archiveName: 'exceptions' }); createRule(getNewRule()).as('createdRule'); visit(EXCEPTIONS_URL); }); - afterEach(() => { - cy.task('esArchiverUnload', 'exceptions'); - }); - const exceptionName = 'My item name'; const exceptionNameEdited = 'My item name edited'; const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; const EXCEPTION_LIST_NAME = 'Newly created list'; - describe('Add, Edit and delete Exception item', () => { + describe('Add, edit and delete exception item', () => { it('should create exception item from Shared Exception List page and linked to a Rule', () => { // Click on "Create shared exception list" button on the header // Click on "Create exception item" diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts index af8edaa017b8..a4c251617b5f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { deleteAlertsAndRules, deleteExceptionLists } from '../../../../tasks/common'; +import { deleteAlertsAndRules, deleteExceptionLists } from '../../../../tasks/api_calls/common'; import { createRule } from '../../../../tasks/api_calls/rules'; import { getExceptionList } from '../../../../objects/exception'; import { assertNumberOfExceptionItemsExists } from '../../../../tasks/exceptions'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts index b115508e2b59..8a7ee172aed3 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts @@ -32,7 +32,7 @@ describe('Shared exception lists - read only', { tags: ['@ess', '@skipInServerle createExceptionList(getExceptionList(), getExceptionList().list_id); login(ROLES.t1_analyst); - visit(EXCEPTIONS_URL, { role: ROLES.t1_analyst }); + visit(EXCEPTIONS_URL); // Using cy.contains because we do not care about the exact text, // just checking number of lists shown diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts index a105040361a4..6b40e1d33618 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts @@ -20,7 +20,7 @@ import { LOADING_INDICATOR } from '../../../screens/security_header'; const loadDetectionsPage = (role: SecurityRoleName) => { login(role); - visit(ALERTS_URL, { role }); + visit(ALERTS_URL); waitForAlertsToPopulate(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts index e040c9873098..c0a2295887a1 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts @@ -17,7 +17,7 @@ import { DESCRIPTION_INPUT, ADD_COMMENT_INPUT } from '../../../screens/create_ne import { getCase1 } from '../../../objects/case'; import { getTimeline } from '../../../objects/timeline'; import { createTimeline } from '../../../tasks/api_calls/timelines'; -import { deleteTimelines } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; import { createCase } from '../../../tasks/api_calls/cases'; describe('attach timeline to case', { tags: ['@ess', '@serverless'] }, () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts index aaa785cc8f39..31c2068b49db 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts @@ -10,7 +10,7 @@ import { getServiceNowConnector, getServiceNowITSMHealthResponse } from '../../. import { SERVICE_NOW_MAPPING } from '../../../screens/configure_cases'; import { goToEditExternalConnection } from '../../../tasks/all_cases'; -import { deleteAllCasesItems, deleteConnectors } from '../../../tasks/common'; +import { deleteAllCasesItems, deleteConnectors } from '../../../tasks/api_calls/common'; import { addServiceNowConnector, openAddNewConnectorOption, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts index ef24d84ee762..8891a835b1fd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts @@ -13,7 +13,7 @@ import { ALL_CASES_COMMENTS_COUNT, ALL_CASES_IN_PROGRESS_CASES_STATS, ALL_CASES_NAME, - ALL_CASES_OPEN_CASES_COUNT, + ALL_CASES_STATUS_FILTER, ALL_CASES_OPEN_CASES_STATS, ALL_CASES_OPENED_ON, ALL_CASES_PAGE_TITLE, @@ -34,7 +34,7 @@ import { CASES_METRIC, UNEXPECTED_METRICS, } from '../../../screens/case_details'; -import { TIMELINE_DESCRIPTION, TIMELINE_QUERY, TIMELINE_TITLE } from '../../../screens/timeline'; +import { TIMELINE_QUERY, TIMELINE_TITLE } from '../../../screens/timeline'; import { OVERVIEW_CASE_DESCRIPTION, OVERVIEW_CASE_NAME } from '../../../screens/overview'; @@ -84,7 +84,7 @@ describe('Cases', { tags: ['@ess', '@serverless'] }, () => { cy.get(ALL_CASES_OPEN_CASES_STATS).should('have.text', '1'); cy.get(ALL_CASES_CLOSED_CASES_STATS).should('have.text', '0'); cy.get(ALL_CASES_IN_PROGRESS_CASES_STATS).should('have.text', '0'); - cy.get(ALL_CASES_OPEN_CASES_COUNT).should('have.text', 'Open (1)'); + cy.get(ALL_CASES_STATUS_FILTER).should('have.text', 'Status1'); cy.get(ALL_CASES_TAGS_COUNT).should('have.text', 'Tags2'); cy.get(ALL_CASES_NAME).should('have.text', this.mycase.name); (this.mycase as TestCase).tags.forEach((CaseTag) => { @@ -123,7 +123,6 @@ describe('Cases', { tags: ['@ess', '@serverless'] }, () => { openCaseTimeline(); cy.get(TIMELINE_TITLE).contains(this.mycase.timeline.title); - cy.get(TIMELINE_DESCRIPTION).contains(this.mycase.timeline.description); cy.get(TIMELINE_QUERY).should('have.text', this.mycase.timeline.query); visitWithTimeRange(OVERVIEW_URL); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts index f1cdbc0d7af9..7768a892d5d0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts @@ -9,7 +9,7 @@ import type { TestCaseWithoutTimeline } from '../../../objects/case'; import { ALL_CASES_CREATE_NEW_CASE_BTN, ALL_CASES_NAME } from '../../../screens/all_cases'; import { goToCreateNewCase } from '../../../tasks/all_cases'; -import { deleteAllCasesItems } from '../../../tasks/common'; +import { deleteAllCasesItems } from '../../../tasks/api_calls/common'; import { backToCases, @@ -18,7 +18,7 @@ import { filterStatusOpen, } from '../../../tasks/create_new_case'; import { login, loginWithUser } from '../../../tasks/login'; -import { visitWithUser } from '../../../tasks/navigation'; +import { visit } from '../../../tasks/navigation'; import { createUsersAndRoles, deleteUsersAndRoles, @@ -66,7 +66,7 @@ describe('Cases privileges', { tags: ['@ess'] }, () => { for (const user of [secAllUser, secReadCasesAllUser, secAllCasesNoDeleteUser]) { it(`User ${user.username} with role(s) ${user.roles.join()} can create a case`, () => { loginWithUser(user); - visitWithUser(CASES_URL, user); + visit(CASES_URL); goToCreateNewCase(); fillCasesMandatoryfields(testCase); createCase(); @@ -80,7 +80,7 @@ describe('Cases privileges', { tags: ['@ess'] }, () => { for (const user of [secAllCasesOnlyReadDeleteUser]) { it(`User ${user.username} with role(s) ${user.roles.join()} cannot create a case`, () => { loginWithUser(user); - visitWithUser(CASES_URL, user); + visit(CASES_URL); cy.get(ALL_CASES_CREATE_NEW_CASE_BTN).should('not.exist'); }); } diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts index 7bb492d51d25..e849e0408c07 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts @@ -11,7 +11,7 @@ import { visitWithTimeRange } from '../../../tasks/navigation'; import { ALERTS_URL, ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { ANOMALIES_TABLE, @@ -169,8 +169,7 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); }); - // FLAKY: https://github.com/elastic/kibana/issues/168490 - it.skip('filters by risk level', () => { + it('filters by risk level', () => { openRiskTableFilterAndSelectTheLowOption(); cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts index a9615f27984e..516b776a86e3 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts @@ -21,7 +21,7 @@ import { openKibanaNavigation, } from '../../../tasks/kibana_navigation'; import { ALERTS_PAGE } from '../../../screens/kibana_navigation'; -import { postDataView } from '../../../tasks/common'; +import { postDataView } from '../../../tasks/api_calls/common'; import { navigateToAlertsPageInServerless } from '../../../tasks/serverless/navigation'; describe('ESS - pinned filters', { tags: ['@ess'] }, () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts index 0a211a58feba..f61cf9943f5e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts @@ -35,6 +35,7 @@ import { kqlSearch } from '../../../tasks/security_header'; import { hostsUrl } from '../../../urls/navigation'; import { resetFields } from '../../../tasks/timeline'; +import { DATA_GRID_EMPTY_STATE } from '../../../screens/events_viewer'; const defaultHeadersInDefaultEcsCategory = [ { id: '@timestamp' }, @@ -118,12 +119,10 @@ describe('Events Viewer', { tags: ['@ess', '@serverless'] }, () => { it('filters the events by applying filter criteria from the search bar at the top of the page', () => { const filterInput = 'aa7ca589f1b8220002f2fc61c64cfbf1'; // this will never match real data - cy.get(SERVER_SIDE_EVENT_COUNT) - .invoke('text') - .then((initialNumberOfEvents) => { - kqlSearch(`${filterInput}{enter}`); - cy.get(SERVER_SIDE_EVENT_COUNT).should('not.have.text', initialNumberOfEvents); - }); + cy.get(SERVER_SIDE_EVENT_COUNT).should('exist'); + kqlSearch(`${filterInput}{enter}`); + cy.get(SERVER_SIDE_EVENT_COUNT).should('not.exist'); + cy.get(DATA_GRID_EMPTY_STATE).should('exist'); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/inspect/inspect_button.cy.ts similarity index 85% rename from x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/inspect/inspect_button.cy.ts index 30a3704879f3..86309e80fd7e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/inspect/inspect_button.cy.ts @@ -9,17 +9,18 @@ import { INSPECT_BUTTONS_IN_SECURITY, INSPECT_MODAL, INSPECT_MODAL_INDEX_PATTERN, -} from '../../screens/inspect'; +} from '../../../screens/inspect'; import { closesModal, openLensVisualizationsInspectModal, openTab, openTableInspectModal, -} from '../../tasks/inspect'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; -import { postDataView, waitForWelcomePanelToBeLoaded } from '../../tasks/common'; -import { selectDataView } from '../../tasks/sourcerer'; +} from '../../../tasks/inspect'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; +import { waitForWelcomePanelToBeLoaded } from '../../../tasks/common'; +import { selectDataView } from '../../../tasks/sourcerer'; +import { postDataView } from '../../../tasks/api_calls/common'; const DATA_VIEW = 'auditbeat-*'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/ml/ml_conditional_links.cy.ts similarity index 98% rename from x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/ml/ml_conditional_links.cy.ts index 061f17032c54..c90f8bea96fd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/ml/ml_conditional_links.cy.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { KQL_INPUT } from '../../screens/security_header'; +import { KQL_INPUT } from '../../../screens/security_header'; -import { login } from '../../tasks/login'; -import { visit } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; import { mlHostMultiHostKqlQuery, @@ -24,7 +24,7 @@ import { mlNetworkNullKqlQuery, mlNetworkSingleIpKqlQuery, mlNetworkSingleIpNullKqlQuery, -} from '../../urls/ml_conditional_links'; +} from '../../../urls/ml_conditional_links'; describe('ml conditional links', { tags: ['@ess', '@brokenInServerless'] }, () => { beforeEach(() => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/navigation/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts similarity index 96% rename from x-pack/test/security_solution_cypress/cypress/e2e/navigation/navigation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts index 788ff1d9eac0..906dcd0548b3 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/navigation/navigation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts @@ -30,12 +30,12 @@ import { EXPLORE, SETTINGS, ENTITY_ANALYTICS, -} from '../../screens/security_header'; -import * as ServerlessHeaders from '../../screens/serverless_security_header'; +} from '../../../screens/security_header'; +import * as ServerlessHeaders from '../../../screens/serverless_security_header'; -import { login } from '../../tasks/login'; -import { visit, visitGetStartedPage, visitWithTimeRange } from '../../tasks/navigation'; -import { navigateFromHeaderTo } from '../../tasks/security_header'; +import { login } from '../../../tasks/login'; +import { visit, visitGetStartedPage, visitWithTimeRange } from '../../../tasks/navigation'; +import { navigateFromHeaderTo } from '../../../tasks/security_header'; import { ALERTS_URL, @@ -71,12 +71,12 @@ import { ASSETS_URL, FLEET_URL, CLOUD_DEFEND_URL, -} from '../../urls/navigation'; -import { RULES_MANAGEMENT_URL } from '../../urls/rules_management'; +} from '../../../urls/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; import { openKibanaNavigation, navigateFromKibanaCollapsibleTo, -} from '../../tasks/kibana_navigation'; +} from '../../../tasks/kibana_navigation'; import { CASES_PAGE, ALERTS_PAGE, @@ -86,7 +86,7 @@ import { TIMELINES_PAGE, FINDINGS_PAGE, THREAT_INTELLIGENCE_PAGE, -} from '../../screens/kibana_navigation'; +} from '../../../screens/kibana_navigation'; describe('top-level navigation common to all pages in the Security app', { tags: '@ess' }, () => { beforeEach(() => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/navigation/search_bar.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/search_bar.cy.ts similarity index 76% rename from x-pack/test/security_solution_cypress/cypress/e2e/navigation/search_bar.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/search_bar.cy.ts index a92e5aa1d93d..14afab3600f5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/navigation/search_bar.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/search_bar.cy.ts @@ -5,23 +5,23 @@ * 2.0. */ -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; import { openAddFilterPopover, fillAddFilterForm, openKqlQueryBar, fillKqlQueryBar, -} from '../../tasks/search_bar'; +} from '../../../tasks/search_bar'; import { AUTO_SUGGEST_AGENT_NAME, AUTO_SUGGEST_HOST_NAME_VALUE, GLOBAL_SEARCH_BAR_FILTER_ITEM, -} from '../../screens/search_bar'; -import { getHostIpFilter } from '../../objects/filter'; +} from '../../../screens/search_bar'; +import { getHostIpFilter } from '../../../objects/filter'; -import { hostsUrl } from '../../urls/navigation'; -import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; +import { hostsUrl } from '../../../urls/navigation'; +import { waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; describe('SearchBar', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/compatibility.cy.ts similarity index 85% rename from x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/compatibility.cy.ts index 856f11227275..fa11642abc17 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/compatibility.cy.ts @@ -5,18 +5,18 @@ * 2.0. */ -import { login } from '../../tasks/login'; -import { visit } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; -import { ALERTS_URL, CREATE_RULE_URL } from '../../urls/navigation'; -import { RULES_MANAGEMENT_URL } from '../../urls/rules_management'; -import { ABSOLUTE_DATE_RANGE } from '../../urls/state'; +import { ALERTS_URL, CREATE_RULE_URL } from '../../../urls/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +import { ABSOLUTE_DATE_RANGE } from '../../../urls/state'; import { DATE_PICKER_START_DATE_POPOVER_BUTTON, GET_DATE_PICKER_END_DATE_POPOVER_BUTTON, -} from '../../screens/date_picker'; -import { ruleDetailsUrl } from '../../urls/rule_details'; -import { editRuleUrl } from '../../urls/edit_rule'; +} from '../../../screens/date_picker'; +import { ruleDetailsUrl } from '../../../urls/rule_details'; +import { editRuleUrl } from '../../../urls/edit_rule'; const LEGACY_DETECTIONS_URL_1 = '/app/siem#/detections'; const LEGACY_DETECTIONS_URL_2 = '/app/security/detections'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/not_found.cy.ts similarity index 85% rename from x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/not_found.cy.ts index 329e0b33144b..9c27440a9786 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/not_found.cy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; import { ALERTS_URL, @@ -16,12 +16,12 @@ import { TIMELINES_URL, EXCEPTIONS_URL, CREATE_RULE_URL, -} from '../../urls/navigation'; -import { RULES_MANAGEMENT_URL } from '../../urls/rules_management'; +} from '../../../urls/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; -import { NOT_FOUND } from '../../screens/common/page'; -import { ruleDetailsUrl } from '../../urls/rule_details'; -import { editRuleUrl } from '../../urls/edit_rule'; +import { NOT_FOUND } from '../../../screens/common/page'; +import { ruleDetailsUrl } from '../../../urls/rule_details'; +import { editRuleUrl } from '../../../urls/edit_rule'; const mockRuleId = '5a4a0460-d822-11eb-8962-bfd4aff0a9b3'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/state.cy.ts similarity index 92% rename from x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/state.cy.ts index 9e2e09ec7908..e24998fd9f30 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/urls/state.cy.ts @@ -11,9 +11,9 @@ import { GET_LOCAL_DATE_PICKER_END_DATE_POPOVER_BUTTON, DATE_PICKER_START_DATE_POPOVER_BUTTON, GET_LOCAL_DATE_PICKER_START_DATE_POPOVER_BUTTON, -} from '../../screens/date_picker'; -import { HOSTS_NAMES } from '../../screens/hosts/all_hosts'; -import { ANOMALIES_TAB } from '../../screens/hosts/main'; +} from '../../../screens/date_picker'; +import { HOSTS_NAMES } from '../../../screens/hosts/all_hosts'; +import { ANOMALIES_TAB } from '../../../screens/hosts/main'; import { BREADCRUMBS, EXPLORE_PANEL_BTN, @@ -22,39 +22,38 @@ import { NETWORK, LOADING_INDICATOR, openNavigationPanel, -} from '../../screens/security_header'; -import { TIMELINE_DATE_PICKER_CONTAINER, TIMELINE_TITLE } from '../../screens/timeline'; +} from '../../../screens/security_header'; +import { TIMELINE_DATE_PICKER_CONTAINER, TIMELINE_TITLE } from '../../../screens/timeline'; -import { login } from '../../tasks/login'; -import { visit, visitWithTimeRange } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visit, visitWithTimeRange } from '../../../tasks/navigation'; import { updateDates, setStartDate, setEndDate, updateTimelineDates, -} from '../../tasks/date_picker'; -import { openFirstHostDetails, waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; -import { openAllHosts } from '../../tasks/hosts/main'; +} from '../../../tasks/date_picker'; +import { openFirstHostDetails, waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; +import { openAllHosts } from '../../../tasks/hosts/main'; -import { waitForIpsTableToBeLoaded } from '../../tasks/network/flows'; +import { waitForIpsTableToBeLoaded } from '../../../tasks/network/flows'; import { clearSearchBar, kqlSearch, navigateFromHeaderTo, saveQuery, -} from '../../tasks/security_header'; -import { openTimelineUsingToggle } from '../../tasks/security_main'; -import { addNameToTimelineAndSave, closeTimeline, populateTimeline } from '../../tasks/timeline'; +} from '../../../tasks/security_header'; +import { openTimelineUsingToggle } from '../../../tasks/security_main'; +import { addNameToTimelineAndSave, closeTimeline, populateTimeline } from '../../../tasks/timeline'; -import { hostsUrl } from '../../urls/navigation'; -import { ABSOLUTE_DATE_RANGE } from '../../urls/state'; +import { hostsUrl } from '../../../urls/navigation'; +import { ABSOLUTE_DATE_RANGE } from '../../../urls/state'; -import { getTimeline } from '../../objects/timeline'; -import { TIMELINE } from '../../screens/create_new_case'; +import { getTimeline } from '../../../objects/timeline'; import { GLOBAL_SEARCH_BAR_FILTER_ITEM_AT, GLOBAL_SEARCH_BAR_PINNED_FILTER, -} from '../../screens/search_bar'; +} from '../../../screens/search_bar'; const ABSOLUTE_DATE = { endTime: 'Aug 1, 2019 @ 20:33:29.186', @@ -308,7 +307,6 @@ describe('url state', { tags: ['@ess', '@brokenInServerless'] }, () => { visitWithTimeRange(`/app/security/timelines?timeline=(id:'${timelineId}',isOpen:!t)`); cy.get(DATE_PICKER_APPLY_BUTTON_TIMELINE).should('exist'); cy.get(DATE_PICKER_APPLY_BUTTON_TIMELINE).should('not.have.text', 'Updating'); - cy.get(TIMELINE).should('be.visible'); cy.get(TIMELINE_TITLE).should('be.visible'); cy.get(TIMELINE_TITLE).should('have.text', getTimeline().title); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts index 426193bbf72b..448687ae956c 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts @@ -37,7 +37,7 @@ describe( selectAlertsHistogram(); }); - it('Filter in/out should add a filter to KQL bar', function () { + it('Filter in should add a filter to KQL bar', function () { const expectedNumberOfAlerts = 1; clickAlertsHistogramLegend(); clickAlertsHistogramLegendFilterFor(ruleConfigs.name); @@ -46,7 +46,9 @@ describe( `kibana.alert.rule.name: ${ruleConfigs.name}` ); cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alert`); + }); + it('Filter out should add a filter to KQL bar', function () { clickAlertsHistogramLegend(); clickAlertsHistogramLegendFilterOut(ruleConfigs.name); cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should( diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts index 9ab0d0756942..7e5e19b464c4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts @@ -25,7 +25,7 @@ import { openTable, } from '../../../tasks/alerts_details'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login } from '../../../tasks/login'; import { visit, visitWithTimeRange } from '../../../tasks/navigation'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_table_api_calls.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_table_api_calls.cy.ts new file mode 100644 index 000000000000..3ef2c0dd21b6 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_table_api_calls.cy.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getNewRule } from '../../../objects/rule'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; +import { ALERTS_URL } from '../../../urls/navigation'; + +/* + * + * Alert table is third party component which cannot be easily tested by jest. + * This test main checks if Alert Table does not call api/lists/index more than once. + * + * */ + +describe('Alert Table API calls', { tags: ['@ess', '@serverless'] }, () => { + let callCount: number = 0; + + beforeEach(() => { + callCount = 0; + login(); + createRule(getNewRule()); + // intercept all calls to `api/lists/index` + // and count how many times it was called + cy.intercept('GET', '/api/lists/index', (req) => { + req.on('response', (res) => { + if (res.statusCode === 200) { + callCount += 1; + } + }); + }); + + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + it('should call `api/lists/index` only once', () => { + cy.get('[data-test-subj="alertsTable"]').then(() => { + expect(callCount, 'number of times lists index api is called').to.equal(1); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts index f06fad0cd43e..2dc4a360134b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts @@ -32,7 +32,7 @@ import { parseAlertsCountToInt, } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login } from '../../../tasks/login'; import { visit } from '../../../tasks/navigation'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts index dd29284f6c0c..1097a8357167 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts @@ -51,7 +51,7 @@ import { import { TOASTER } from '../../../screens/alerts_detection_rules'; import { setEndDate, setStartDate } from '../../../tasks/date_picker'; import { fillAddFilterForm, openAddFilterPopover } from '../../../tasks/search_bar'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; const customFilters = [ { @@ -107,7 +107,8 @@ const assertFilterControlsWithFilterObject = ( }); }; -describe(`Detections : Page Filters`, { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/171890 +describe.skip(`Detections : Page Filters`, { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { deleteAlertsAndRules(); createRule(getNewRule({ rule_id: 'custom_rule_filters' })); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts index 9e1ace19972a..3868625e9b33 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts @@ -9,10 +9,7 @@ import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON, DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT, } from '../../../../screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB, - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { openGraphAnalyzerTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; @@ -41,17 +38,15 @@ describe.skip( it('should display analyzer graph and node list under visualize', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) - .should('be.visible') - .and('have.text', 'Visualize'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); + .should('have.text', 'Visualize') + .and('have.class', 'euiTab-isSelected'); cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON) - .should('be.visible') - .and('have.text', 'Analyzer Graph'); + .should('have.text', 'Analyzer Graph') + .and('have.class', 'euiButtonGroupButton-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT).should('be.visible'); - cy.get(ANALYZER_NODE).first().should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT).should('exist'); + cy.get(ANALYZER_NODE).first().should('exist'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts index a0e080e71ce1..fe89d50dd520 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts @@ -20,10 +20,7 @@ import { CORRELATIONS_SOURCE_SECTION_TITLE, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON, } from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { openCorrelationsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_correlations_tab'; import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; @@ -50,24 +47,15 @@ describe('Expandable flyout left panel correlations', { tags: ['@ess', '@serverl }); it('should render correlations details correctly', () => { - cy.log('link the alert to a new case'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).scrollIntoView(); - - cy.log('should render the Insights header'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) + .should('have.text', 'Insights') + .and('have.class', 'euiTab-isSelected'); - cy.log('should render the inner tab switch'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); - - cy.log('should render correlations tab activator / button'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON) - .should('be.visible') - .and('have.text', 'Correlations'); - - cy.log('should render all the correlations sections'); + .should('have.text', 'Correlations') + .and('have.class', 'euiButtonGroupButton-isSelected'); - cy.log('suppressed alerts'); + // cy.log('suppressed alerts'); // TODO get proper data to test suppressed alerts // cy.get(CORRELATIONS_SUPPRESSED_ALERTS_TITLE).scrollIntoView(); @@ -78,38 +66,42 @@ describe('Expandable flyout left panel correlations', { tags: ['@ess', '@serverl cy.log('related cases'); - cy.get(CORRELATIONS_CASES_SECTION_TITLE).scrollIntoView(); - cy.get(CORRELATIONS_CASES_SECTION_TITLE) - .should('be.visible') - .and('contain.text', '1 related case'); - cy.get(CORRELATIONS_CASES_SECTION_TABLE).should('be.visible'); + cy.get(CORRELATIONS_CASES_SECTION_TITLE).should('contain.text', '1 related case'); + cy.get(CORRELATIONS_CASES_SECTION_TABLE) + .should('contain.text', 'case') + .and('contain.text', 'open'); cy.log('related alerts by source event'); - cy.get(CORRELATIONS_SOURCE_SECTION_TITLE).scrollIntoView(); - cy.get(CORRELATIONS_SOURCE_SECTION_TITLE) - .should('be.visible') - .and('contain.text', '1 alert related by source event'); - cy.get(CORRELATIONS_SOURCE_SECTION_TABLE).should('be.visible'); - cy.get(CORRELATIONS_SOURCE_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should('be.visible'); + cy.get(CORRELATIONS_SOURCE_SECTION_TITLE).should( + 'contain.text', + '1 alert related by source event' + ); + cy.get(CORRELATIONS_SOURCE_SECTION_TABLE).should('exist'); + cy.get(CORRELATIONS_SOURCE_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should( + 'contain.text', + 'Investigate in timeline' + ); cy.log('related alerts by session'); - cy.get(CORRELATIONS_SESSION_SECTION_TITLE).scrollIntoView(); - cy.get(CORRELATIONS_SESSION_SECTION_TITLE) - .should('be.visible') - .and('contain.text', '1 alert related by session'); - cy.get(CORRELATIONS_SESSION_SECTION_TABLE).should('be.visible'); - cy.get(CORRELATIONS_SESSION_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should('be.visible'); + cy.get(CORRELATIONS_SESSION_SECTION_TITLE).should('contain.text', '1 alert related by session'); + cy.get(CORRELATIONS_SESSION_SECTION_TABLE).should('exist'); + cy.get(CORRELATIONS_SESSION_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should( + 'contain.text', + 'Investigate in timeline' + ); cy.log('related alerts by ancestry'); - cy.get(CORRELATIONS_ANCESTRY_SECTION_TITLE).scrollIntoView(); - cy.get(CORRELATIONS_ANCESTRY_SECTION_TITLE) - .should('be.visible') - .and('contain.text', '1 alert related by ancestry'); - cy.get(CORRELATIONS_ANCESTRY_SECTION_TABLE).scrollIntoView(); - cy.get(CORRELATIONS_ANCESTRY_SECTION_TABLE).should('be.visible'); - cy.get(CORRELATIONS_ANCESTRY_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should('be.visible'); + cy.get(CORRELATIONS_ANCESTRY_SECTION_TITLE).should( + 'contain.text', + '1 alert related by ancestry' + ); + cy.get(CORRELATIONS_ANCESTRY_SECTION_TABLE).should('exist'); + cy.get(CORRELATIONS_ANCESTRY_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).should( + 'contain.text', + 'Investigate in timeline' + ); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts index 06bba72700c2..567a60752398 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts @@ -8,12 +8,13 @@ import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_RIGHT_SECTION, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_RIGHT_SECTION, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE, } from '../../../../screens/expandable_flyout/alert_details_left_panel_entities_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { openEntitiesTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_entities_tab'; import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; @@ -42,20 +43,32 @@ describe( it('should display host details and user details under Insights Entities', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) - .should('be.visible') - .and('have.text', 'Insights'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + .should('have.text', 'Insights') + .and('have.class', 'euiTab-isSelected'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON) - .should('be.visible') - .and('have.text', 'Entities'); + .should('have.text', 'Entities') + .and('have.class', 'euiButtonGroupButton-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE).should( + 'contain.text', + 'test' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_RIGHT_SECTION).should( + 'contain.text', + 'Related hosts: 0' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('exist'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE).should( + 'contain.text', + 'siem-kibana' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_RIGHT_SECTION).should( + 'contain.text', + 'Related users: 0' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('exist'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts index 36bd13e5c103..c4e4cf553535 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts @@ -35,10 +35,13 @@ describe( it('should display investigation guide', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB) - .should('be.visible') - .and('have.text', 'Investigation'); + .should('have.text', 'Investigation') + .and('have.class', 'euiTab-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should( + 'contain.text', + 'test markdown' + ); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts index 38fd4ffb7496..44f48f7f74d0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts @@ -9,10 +9,7 @@ import { openPrevalenceTab } from '../../../../tasks/expandable_flyout/alert_det import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; -import { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_ALERT_COUNT_CELL, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_BUTTON, @@ -21,7 +18,6 @@ import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_DOC_COUNT_CELL, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_PREVALENCE_CELL, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_PREVALENCE_CELL, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_DATE_PICKER, } from '../../../../screens/expandable_flyout/alert_details_left_panel_prevalence_tab'; import { login } from '../../../../tasks/login'; @@ -48,18 +44,18 @@ describe( it('should display prevalence tab', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) - .should('be.visible') - .and('have.text', 'Insights'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + .should('have.text', 'Insights') + .and('have.class', 'euiTab-isSelected'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_BUTTON) - .should('be.visible') - .and('have.text', 'Prevalence'); + .should('have.text', 'Prevalence') + .and('have.class', 'euiButtonGroupButton-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_DATE_PICKER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_DATE_PICKER).should( + 'contain.text', + 'Last 30 days' + ); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE).should('be.visible'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_TYPE_CELL) .should('contain.text', 'host.os.name') .and('contain.text', 'host.name') diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts index 8948480911c9..e4c2baba4e87 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts @@ -5,7 +5,10 @@ * 2.0. */ -import { DOCUMENT_DETAILS_FLYOUT_RESPONSE_EMPTY } from '../../../../screens/expandable_flyout/alert_details_left_panel_response_tab'; +import { + DOCUMENT_DETAILS_FLYOUT_RESPONSE_DETAILS, + DOCUMENT_DETAILS_FLYOUT_RESPONSE_EMPTY, +} from '../../../../screens/expandable_flyout/alert_details_left_panel_response_tab'; import { openResponseTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_response_tab'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; @@ -15,6 +18,7 @@ import { createRule } from '../../../../tasks/api_calls/rules'; import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { DOCUMENT_DETAILS_FLYOUT_RESPONSE_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; describe( 'Alert details expandable flyout left panel investigation', @@ -31,7 +35,16 @@ describe( }); it('should display empty response message', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_RESPONSE_EMPTY).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RESPONSE_TAB) + .should('have.text', 'Response') + .and('have.class', 'euiTab-isSelected'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_RESPONSE_DETAILS).should('contain.text', 'Responses'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_RESPONSE_EMPTY).and( + 'contain.text', + "There are no response actions defined for this event. To add some, edit the rule's settings and set up response actions(opens in a new tab or window)." + ); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts index cbe17d55271e..0c37aa9b835b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts @@ -6,10 +6,7 @@ */ import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_session_view_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB, - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; import { login } from '../../../../tasks/login'; @@ -35,14 +32,12 @@ describe.skip( it('should display session view under visualize', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) - .should('be.visible') - .and('have.text', 'Visualize'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); + .and('have.text', 'Visualize') + .and('have.class', 'euiTab-isSelected'); cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON) - .should('be.visible') - .and('have.text', 'Session View'); + .should('have.text', 'Session View') + .and('have.class', 'euiButtonGroupButton-isSelected'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts index 85338d85ed73..17080cbd32ae 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts @@ -16,10 +16,7 @@ import { visit } from '../../../../tasks/navigation'; import { ALERTS_URL } from '../../../../urls/navigation'; import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; import { openThreatIntelligenceTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab'; describe( @@ -39,16 +36,14 @@ describe( it('should serialize its state to url', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) - .should('be.visible') - .and('have.text', 'Insights'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + .should('have.text', 'Insights') + .and('have.class', 'euiTab-isSelected'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON) - .should('be.visible') - .and('have.text', 'Threat intelligence'); + .should('have.text', 'Threat intelligence') + .and('have.class', 'euiButtonGroupButton-isSelected'); - cy.get(INDICATOR_MATCH_ENRICHMENT_SECTION).should('be.visible'); + cy.get(INDICATOR_MATCH_ENRICHMENT_SECTION).should('exist'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts index 09d90627d8b1..89596877fb3e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_alert_reason_preview.cy.ts @@ -32,8 +32,15 @@ describe( describe('alert reason preview', () => { it('should display alert reason preview', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_ALERT_REASON_PREVIEW_CONTAINER) + .should('contain.text', 'Alert reason') + .and('contain.text', 'process') + .and('contain.text', 'zsh') + .and('contain.text', '80') + .and('contain.text', 'test') + .and('contain.text', 'siem-kibana') + .and('contain.text', 'high') + .and('contain.text', rule.name); }); }); } diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts index 13c98358ec3e..82ce99029290 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts @@ -7,12 +7,9 @@ import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; import { - DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION, - DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_HEADER, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE, DOCUMENT_DETAILS_FLYOUT_CREATED_BY, DOCUMENT_DETAILS_FLYOUT_UPDATED_BY, - DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_BODY, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER, @@ -20,6 +17,7 @@ import { DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT, DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER, + DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER_LINK, } from '../../../../screens/expandable_flyout/alert_details_preview_panel_rule_preview'; import { toggleRulePreviewAboutSection, @@ -53,48 +51,75 @@ describe( it('should display rule preview and its sub sections', () => { cy.log('rule preview panel'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_HEADER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_BODY).should('be.visible'); - cy.log('title'); cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).should('contain.text', rule.name); cy.get(DOCUMENT_DETAILS_FLYOUT_CREATED_BY).should('be.visible'); cy.get(DOCUMENT_DETAILS_FLYOUT_UPDATED_BY).should('be.visible'); cy.log('about'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'About'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER).should( + 'contain.text', + 'About' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT) + .should('contain.text', 'Severity') + .and('contain.text', 'High') + .and('contain.text', 'Risk score') + .and('contain.text', '17'); + toggleRulePreviewAboutSection(); cy.log('definition'); toggleRulePreviewDefinitionSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'Definition'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER).should( + 'contain.text', + 'Definition' + ); cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT).should( - 'be.visible' + 'contain.text', + 'Index patterns' + ); + // @ts-ignore + rule.index.forEach((index: string) => + cy + .get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT) + .should('contain.text', index) ); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT) + .should('contain.text', 'Custom query') + .and('contain.text', rule.query); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT) + .should('contain.text', 'Rule type') + .and('contain.text', rule.type); + toggleRulePreviewDefinitionSection(); cy.log('schedule'); toggleRulePreviewScheduleSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'Schedule'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT).should('be.visible'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER).should( + 'contain.text', + 'Schedule' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT) + .should('contain.text', 'Runs every') + .and('contain.text', rule.interval); + toggleRulePreviewScheduleSection(); cy.log('footer'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER_LINK).should( + 'contain.text', + 'Show rule details' + ); }); }); } diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts index d89cc4ad4eb5..aaa8806362d0 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts @@ -30,6 +30,8 @@ import { DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED, DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND, DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON, + DOCUMENT_DETAILS_FLYOUT_HEADER_ICON, + DOCUMENT_DETAILS_FLYOUT_HEADER_LINK_ICON, DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE, DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE, DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE, @@ -49,174 +51,165 @@ import { openTakeActionButtonAndSelectItem, selectTakeActionItem, } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; import { createRule } from '../../../../tasks/api_calls/rules'; import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { TOASTER } from '../../../../screens/alerts_detection_rules'; -// FLAKY: https://github.com/elastic/kibana/issues/171002 -describe.skip( - 'Alert details expandable flyout right panel', - { tags: ['@ess', '@serverless'] }, - () => { - const rule = getNewRule(); - - beforeEach(() => { - deleteAlertsAndRules(); - login(); - createRule(rule); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - }); - - it('should display header and footer basics', () => { - expandFirstAlertExpandableFlyout(); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('have.text', rule.name); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS).should('have.text', 'open'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE).should('have.text', 'Risk score:'); - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE) - .should('be.visible') - .and('have.text', rule.risk_score); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE) - .should('be.visible') - .and('have.text', upperFirst(rule.severity)); - - cy.log('Verify all 3 tabs are visible'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB) - .should('have.text', 'Overview') - .and('have.class', 'euiTab-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB) - .should('have.text', 'Table') - .and('not.have.class', 'euiTab-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB) - .should('have.text', 'JSON') - .and('not.have.class', 'euiTab-isSelected'); - - cy.log('Verify the expand/collapse button is visible and functionality works'); - - expandDocumentDetailsExpandableFlyoutLeftSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON).should( - 'have.text', - 'Collapse details' - ); +describe('Alert details expandable flyout right panel', { tags: ['@ess', '@serverless'] }, () => { + const rule = getNewRule(); + + beforeEach(() => { + deleteAlertsAndRules(); + login(); + createRule(rule); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + it('should display header and footer basics', () => { + expandFirstAlertExpandableFlyout(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_ICON).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('have.text', rule.name); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_LINK_ICON).should('exist'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS).should('have.text', 'open'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE).should('have.text', 'Risk score:'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE) + .should('be.visible') + .and('have.text', rule.risk_score); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE) + .should('be.visible') + .and('have.text', upperFirst(rule.severity)); + + cy.log('Verify all 3 tabs are visible'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB) + .should('have.text', 'Overview') + .and('have.class', 'euiTab-isSelected'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB) + .should('have.text', 'Table') + .and('not.have.class', 'euiTab-isSelected'); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB) + .should('have.text', 'JSON') + .and('not.have.class', 'euiTab-isSelected'); + + cy.log('Verify the expand/collapse button is visible and functionality works'); + + expandDocumentDetailsExpandableFlyoutLeftSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON).should('have.text', 'Collapse details'); + + collapseDocumentDetailsExpandableFlyoutLeftSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON).should('have.text', 'Expand details'); + + cy.log('Verify the take action button is visible on all tabs'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + + openTableTab(); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).should('have.class', 'euiTab-isSelected'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + + openJsonTab(); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).should('have.class', 'euiTab-isSelected'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + }); + + // TODO this will change when add to existing case is improved + // https://github.com/elastic/security-team/issues/6298 + it('should add to existing case', () => { + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); + fillOutFormToCreateNewCase(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE); + + cy.get(EXISTING_CASE_SELECT_BUTTON).contains('Select').click(); - collapseDocumentDetailsExpandableFlyoutLeftSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON).should('have.text', 'Expand details'); + cy.get(VIEW_CASE_TOASTER_LINK).should('contain.text', 'View case'); + }); - cy.log('Verify the take action button is visible on all tabs'); + // TODO this will change when add to new case is improved + // https://github.com/elastic/security-team/issues/6298 + it('should add to new case', () => { + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); + fillOutFormToCreateNewCase(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + cy.get(VIEW_CASE_TOASTER_LINK).should('contain.text', 'View case'); + }); - openTableTab(); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).should('have.class', 'euiTab-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); - - openJsonTab(); - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).should('have.class', 'euiTab-isSelected'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); - }); - - // TODO this will change when add to existing case is improved - // https://github.com/elastic/security-team/issues/6298 - it('should add to existing case', () => { - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); - fillOutFormToCreateNewCase(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE); - - cy.get(EXISTING_CASE_SELECT_BUTTON).should('be.visible').contains('Select').click(); - - cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); - }); - - // TODO this will change when add to new case is improved - // https://github.com/elastic/security-team/issues/6298 - it('should add to new case', () => { - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); - fillOutFormToCreateNewCase(); - - cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); - }); - - it('should mark as acknowledged', () => { - cy.get(ALERT_CHECKBOX).should('have.length', 1); - - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED); - - // TODO figure out how to verify the toasts pops up - // cy.get(KIBANA_TOAST) - // .should('be.visible') - // .and('have.text', 'Successfully marked 1 alert as acknowledged.'); - cy.get(EMPTY_ALERT_TABLE).should('exist'); - }); - - it('should mark as closed', () => { - cy.get(ALERT_CHECKBOX).should('have.length', 1); - - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED); - - // TODO figure out how to verify the toasts pops up - // cy.get(KIBANA_TOAST).should('be.visible').and('have.text', 'Successfully closed 1 alert.'); - cy.get(EMPTY_ALERT_TABLE).should('exist'); - }); - - // these actions are now grouped together as we're not really testing their functionality but just the existence of the option in the dropdown - it('should test other action within take action dropdown', () => { - expandFirstAlertExpandableFlyout(); - - cy.log('should add endpoint exception'); - - // TODO figure out why this option is disabled in Cypress but not running the app locally - // https://github.com/elastic/security-team/issues/6300 - openTakeActionButton(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION).should('be.disabled'); - - cy.log('should add rule exception'); - - // TODO this isn't fully testing the add rule exception yet - // https://github.com/elastic/security-team/issues/6301 - selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER).should('exist'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON) - .should('be.visible') - .click(); - - // cy.log('should isolate host'); - - // TODO figure out why isolate host isn't showing up in the dropdown - // https://github.com/elastic/security-team/issues/6302 - // openTakeActionButton(); - // cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible'); - - cy.log('should respond'); - - // TODO this will change when respond is improved - // https://github.com/elastic/security-team/issues/6303 - openTakeActionButton(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND).should('be.disabled'); - - cy.log('should investigate in timeline'); - - selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION) - .first() - .within(() => - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY).should('exist') - ); - }); - } -); + it('should mark as acknowledged', () => { + cy.get(ALERT_CHECKBOX).should('have.length', 1); + + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED); + + cy.get(TOASTER).should('have.text', 'Successfully marked 1 alert as acknowledged.'); + cy.get(EMPTY_ALERT_TABLE).should('exist'); + }); + + it('should mark as closed', () => { + cy.get(ALERT_CHECKBOX).should('have.length', 1); + + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED); + + cy.get(TOASTER).should('have.text', 'Successfully closed 1 alert.'); + cy.get(EMPTY_ALERT_TABLE).should('exist'); + }); + + // these actions are now grouped together as we're not really testing their functionality but just the existence of the option in the dropdown + it('should test other action within take action dropdown', () => { + expandFirstAlertExpandableFlyout(); + + cy.log('should add endpoint exception'); + + // TODO figure out why this option is disabled in Cypress but not running the app locally + // https://github.com/elastic/security-team/issues/6300 + openTakeActionButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION).should('be.disabled'); + + cy.log('should add rule exception'); + + // TODO this isn't fully testing the add rule exception yet + // https://github.com/elastic/security-team/issues/6301 + selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON) + .should('be.visible') + .click(); + + // cy.log('should isolate host'); + + // TODO figure out why isolate host isn't showing up in the dropdown + // https://github.com/elastic/security-team/issues/6302 + // openTakeActionButton(); + // cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible'); + + cy.log('should respond'); + + // TODO this will change when respond is improved + // https://github.com/elastic/security-team/issues/6303 + openTakeActionButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND).should('be.disabled'); + + cy.log('should investigate in timeline'); + + selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION) + .first() + .within(() => + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY).should('exist') + ); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts index a7bb39381ad9..f41dba6dd100 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts @@ -7,7 +7,10 @@ import { openJsonTab } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; -import { DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT } from '../../../../screens/expandable_flyout/alert_details_right_panel_json_tab'; +import { + DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT, + DOCUMENT_DETAILS_FLYOUT_JSON_TAB_COPY_TO_CLIPBOARD_BUTTON, +} from '../../../../screens/expandable_flyout/alert_details_right_panel_json_tab'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; import { createRule } from '../../../../tasks/api_calls/rules'; @@ -29,7 +32,13 @@ describe( }); it('should display the json component', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB_COPY_TO_CLIPBOARD_BUTTON).should( + 'have.text', + 'Copy to clipboard' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT) + .should('contain.text', '_index') + .and('contain.text', '_id'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index 33bcb93caacf..fb2af6a16b02 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { collapseDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { createNewCaseFromExpandableFlyout, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts index 9f10b73065ba..c855beca9fdb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts @@ -12,6 +12,7 @@ import { PROVIDER_BADGE } from '../../../../screens/timeline'; import { removeKqlFilter } from '../../../../tasks/search_bar'; import { COLUMN_HEADER, FILTER_BADGE, TIMESTAMP_COLUMN } from '../../../../screens/alerts'; import { + DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_HOST_OS_BUILD_ROW, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_COPY_TO_CLIPBOARD, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_CELL, @@ -19,13 +20,12 @@ import { } from '../../../../screens/expandable_flyout/alert_details_right_panel_table_tab'; import { addToTimelineTableTabTable, - clearFilterTableTabTable, filterInTableTabTable, filterOutTableTabTable, filterTableTabTable, toggleColumnTableTabTable, } from '../../../../tasks/expandable_flyout/alert_details_right_panel_table_tab'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; import { createRule } from '../../../../tasks/api_calls/rules'; @@ -48,11 +48,23 @@ describe( }); it('should display and filter the table', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW) + .should('be.visible') + .and('contain.text', '@timestamp'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW) + .should('be.visible') + .and('contain.text', '_id'); + + // this entry is the last one of the first page of the table and should not be visible + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_HOST_OS_BUILD_ROW) + .should('not.be.visible') + .and('contain.text', 'host.os.build'); + filterTableTabTable('timestamp'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); - clearFilterTableTabTable(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW) + .should('be.visible') + .and('contain.text', '@timestamp'); }); it('should test cell actions', () => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts index 5e46dea3ee24..0cd12d9381ad 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts @@ -26,27 +26,27 @@ describe('Expandable flyout state sync', { tags: ['@ess', '@serverless'] }, () = }); it('should test flyout url sync', () => { - cy.url().should('not.include', 'eventFlyout'); + cy.url().should('not.include', 'rightPanel'); expandFirstAlertExpandableFlyout(); cy.log('should serialize its state to url'); - cy.url().should('include', 'eventFlyout'); - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('be.visible').and('have.text', rule.name); + cy.url().should('include', 'rightPanel'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('have.text', rule.name); cy.log('should reopen the flyout after browser refresh'); cy.reload(); waitForAlertsToPopulate(); - cy.url().should('include', 'eventFlyout'); - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('be.visible').and('have.text', rule.name); + cy.url().should('include', 'rightPanel'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('have.text', rule.name); cy.log('should clear the url state when flyout is closed'); closeFlyout(); - cy.url().should('not.include', 'eventFlyout'); + cy.url().should('not.include', 'rightPanel'); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts index 0570557d33f2..8095921c6df8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts @@ -7,8 +7,12 @@ import { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings'; import { getNewRule } from '../../../objects/rule'; -import { PROVIDER_BADGE, QUERY_TAB_BUTTON, TIMELINE_TITLE } from '../../../screens/timeline'; -import { FILTER_BADGE } from '../../../screens/alerts'; +import { + PROVIDER_BADGE, + QUERY_TAB_BUTTON, + TIMELINE_FILTER_BADGE, + TIMELINE_TITLE, +} from '../../../screens/timeline'; import { expandFirstAlert, investigateFirstAlertInTimeline } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; @@ -80,7 +84,7 @@ describe('Investigate in timeline', { tags: ['@ess', '@serverless'] }, () => { cy.get(QUERY_TAB_BUTTON).should('contain.text', alertCount); // The correct filter is applied to the timeline query - cy.get(FILTER_BADGE).should( + cy.get(TIMELINE_FILTER_BADGE).should( 'have.text', ' {"bool":{"must":[{"term":{"process.args":"-zsh"}},{"term":{"process.args":"unique"}}]}}' ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts index 98d76d984512..b90413cdfe75 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts @@ -12,7 +12,7 @@ import { ALERTS_URL } from '../../../urls/navigation'; import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts'; import { TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline'; import { selectAlertsHistogram } from '../../../tasks/alerts'; -import { deleteTimelines } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; import { createTimeline } from '../../../tasks/api_calls/timelines'; import { getTimeline } from '../../../objects/timeline'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts index e19e4ca043b3..eb3881f8123a 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts @@ -31,7 +31,7 @@ import { import { QUERY_TAB_BUTTON, TIMELINE_DATA_PROVIDERS_CONTAINER } from '../../../screens/timeline'; import { waitForAlerts } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; -import { deleteAlertsAndRules } from '../../../tasks/common'; +import { deleteAlertsAndRules } from '../../../tasks/api_calls/common'; import { investigateDashboardItemInTimeline } from '../../../tasks/dashboards/common'; import { waitToNavigateAwayFrom } from '../../../tasks/kibana_navigation'; import { login } from '../../../tasks/login'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts index b3ed43ffe9d8..9054684c53e8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts @@ -26,7 +26,7 @@ import { TIMELINES_FAVORITE, } from '../../../screens/timelines'; import { createTimeline } from '../../../tasks/api_calls/timelines'; -import { deleteTimelines } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; import { login } from '../../../tasks/login'; import { visit } from '../../../tasks/navigation'; @@ -111,7 +111,6 @@ describe('Timeline Templates', { tags: ['@ess', '@serverless'] }, () => { addNameToTimelineAndSave('Test'); cy.wait('@timeline', { timeout: 100000 }); cy.get(TIMELINE_FLYOUT_WRAPPER).should('have.css', 'visibility', 'visible'); - cy.get(TIMELINE_DESCRIPTION).should('have.text', getTimeline().description); cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts index a50dbe08b063..96b30a29d23d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts @@ -21,7 +21,7 @@ import { addEqlToTimeline, saveTimeline } from '../../../tasks/timeline'; import { TIMELINES_URL } from '../../../urls/navigation'; import { EQL_QUERY_VALIDATION_ERROR } from '../../../screens/create_new_rule'; -import { deleteTimelines } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; describe('Correlation tab', { tags: ['@ess', '@serverless'] }, () => { const eql = 'any where process.name == "zsh"'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts index 1b69b314daf7..a40479fdab26 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts @@ -12,19 +12,19 @@ import { LOCKED_ICON, NOTES_TEXT, PIN_EVENT, - TIMELINE_DESCRIPTION, TIMELINE_FILTER, TIMELINE_FLYOUT_WRAPPER, TIMELINE_QUERY, TIMELINE_PANEL, TIMELINE_STATUS, TIMELINE_TAB_CONTENT_GRAPHS_NOTES, - TIMELINE_SAVE_MODAL_OPEN_BUTTON, - SAVE_TIMELINE_BTN_TOOLTIP, + SAVE_TIMELINE_ACTION_BTN, + SAVE_TIMELINE_TOOLTIP, } from '../../../screens/timeline'; +import { ROWS } from '../../../screens/timelines'; import { createTimelineTemplate } from '../../../tasks/api_calls/timelines'; -import { deleteTimelines } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; import { login } from '../../../tasks/login'; import { visit, visitWithTimeRange } from '../../../tasks/navigation'; import { openTimelineUsingToggle } from '../../../tasks/security_main'; @@ -42,11 +42,14 @@ import { pinFirstEvent, populateTimeline, addNameToTimelineAndSave, + addNameToTimelineAndSaveAsNew, } from '../../../tasks/timeline'; +import { createTimeline } from '../../../tasks/timelines'; -import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL } from '../../../urls/navigation'; +import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL, TIMELINES_URL } from '../../../urls/navigation'; -describe('Create a timeline from a template', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/172304 +describe.skip('Create a timeline from a template', { tags: ['@ess', '@serverless'] }, () => { before(() => { deleteTimelines(); login(); @@ -62,9 +65,7 @@ describe('Create a timeline from a template', { tags: ['@ess', '@serverless'] }, selectCustomTemplates(); expandEventAction(); clickingOnCreateTimelineFormTemplateBtn(); - cy.get(TIMELINE_FLYOUT_WRAPPER).should('have.css', 'visibility', 'visible'); - cy.get(TIMELINE_DESCRIPTION).should('have.text', getTimeline().description); cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query); closeTimeline(); }); @@ -75,7 +76,7 @@ describe('Timelines', (): void => { deleteTimelines(); }); - describe('Toggle create timeline from plus icon', () => { + describe('Toggle create timeline from "New" btn', () => { context('Privileges: CRUD', { tags: '@ess' }, () => { beforeEach(() => { login(); @@ -83,6 +84,7 @@ describe('Timelines', (): void => { }); it('toggle create timeline ', () => { + openTimelineUsingToggle(); createNewTimeline(); addNameAndDescriptionToTimeline(getTimeline()); cy.get(TIMELINE_PANEL).should('be.visible'); @@ -92,16 +94,17 @@ describe('Timelines', (): void => { context('Privileges: READ', { tags: '@ess' }, () => { beforeEach(() => { login(ROLES.t1_analyst); - visitWithTimeRange(OVERVIEW_URL, { role: ROLES.t1_analyst }); + visitWithTimeRange(OVERVIEW_URL); }); it('should not be able to create/update timeline ', () => { + openTimelineUsingToggle(); createNewTimeline(); cy.get(TIMELINE_PANEL).should('be.visible'); - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).should('be.disabled'); - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).first().realHover(); - cy.get(SAVE_TIMELINE_BTN_TOOLTIP).should('be.visible'); - cy.get(SAVE_TIMELINE_BTN_TOOLTIP).should( + cy.get(SAVE_TIMELINE_ACTION_BTN).should('be.disabled'); + cy.get(SAVE_TIMELINE_ACTION_BTN).first().realHover(); + cy.get(SAVE_TIMELINE_TOOLTIP).should('be.visible'); + cy.get(SAVE_TIMELINE_TOOLTIP).should( 'have.text', 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.' ); @@ -148,10 +151,12 @@ describe('Timelines', (): void => { } ); - describe('shows the different timeline states', () => { + // FLAKY: https://github.com/elastic/kibana/issues/172031 + describe.skip('shows the different timeline states', () => { before(() => { login(); visitWithTimeRange(OVERVIEW_URL); + openTimelineUsingToggle(); createNewTimeline(); }); @@ -178,4 +183,28 @@ describe('Timelines', (): void => { .should('match', /^Has unsaved changes/); }); }); + + describe('saves timeline as new', () => { + before(() => { + deleteTimelines(); + login(); + visitWithTimeRange(TIMELINES_URL); + }); + + it('should save timelines as new', { tags: ['@ess', '@serverless'] }, () => { + cy.get(ROWS).should('have.length', '0'); + + createTimeline(); + addNameToTimelineAndSave('First'); + addNameToTimelineAndSaveAsNew('Second'); + closeTimeline(); + + cy.get(ROWS).should('have.length', '2'); + cy.get(ROWS) + .first() + .invoke('text') + .should('match', /Second/); + cy.get(ROWS).last().invoke('text').should('match', /First/); + }); + }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts index 3ba7e607bbfb..1dd9c5cdcf1f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts @@ -6,20 +6,15 @@ */ import { TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON } from '../../../screens/security_main'; -import { CREATE_NEW_TIMELINE, TIMELINE_FLYOUT_HEADER } from '../../../screens/timeline'; +import { TIMELINE_FLYOUT_HEADER } from '../../../screens/timeline'; import { waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; import { login } from '../../../tasks/login'; import { visitWithTimeRange } from '../../../tasks/navigation'; import { closeTimelineUsingCloseButton, - closeTimelineUsingToggle, openTimelineUsingToggle, } from '../../../tasks/security_main'; -import { - closeCreateTimelineOptionsPopover, - openCreateTimelineOptionsPopover, -} from '../../../tasks/timeline'; import { hostsUrl } from '../../../urls/navigation'; @@ -33,7 +28,7 @@ describe('timeline flyout button', () => { it('toggles open the timeline', { tags: ['@ess', '@serverless'] }, () => { openTimelineUsingToggle(); cy.get(TIMELINE_FLYOUT_HEADER).should('have.css', 'visibility', 'visible'); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); }); it( @@ -41,7 +36,7 @@ describe('timeline flyout button', () => { { tags: ['@ess', '@serverless'] }, () => { openTimelineUsingToggle(); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).should('have.focus'); } @@ -69,18 +64,6 @@ describe('timeline flyout button', () => { } ); - it( - 'the `(+)` button popover menu owns focus when open', - { tags: ['@ess', '@serverless'] }, - () => { - openCreateTimelineOptionsPopover(); - cy.get(CREATE_NEW_TIMELINE).focus(); - cy.get(CREATE_NEW_TIMELINE).should('have.focus'); - closeCreateTimelineOptionsPopover(); - cy.get(CREATE_NEW_TIMELINE).should('not.exist'); - } - ); - it( 'should render the global search dropdown when the input is focused', { tags: ['@ess'] }, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts index 372a0a317897..e1dc67863112 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts @@ -7,11 +7,7 @@ import { getTimeline } from '../../../objects/timeline'; -import { - TIMELINE_DESCRIPTION, - TIMELINE_TITLE, - OPEN_TIMELINE_MODAL, -} from '../../../screens/timeline'; +import { TIMELINE_TITLE, OPEN_TIMELINE_MODAL } from '../../../screens/timeline'; import { TIMELINES_DESCRIPTION, TIMELINES_PINNED_EVENT_COUNT, @@ -69,7 +65,6 @@ describe('Open timeline', { tags: ['@serverless', '@ess'] }, () => { cy.get(TIMELINES_NOTES_COUNT).last().should('have.text', '1'); cy.get(TIMELINES_FAVORITE).last().should('exist'); cy.get(TIMELINE_TITLE).should('have.text', getTimeline().title); - cy.get(TIMELINE_DESCRIPTION).should('have.text', getTimeline().description); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts index f16f7120dd0f..dcf847224067 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts @@ -24,7 +24,8 @@ import { hostsUrl } from '../../../urls/navigation'; // Flaky on serverless const defaultPageSize = 25; -describe('Pagination', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/169413 +describe.skip('Pagination', { tags: ['@ess', '@serverless'] }, () => { before(() => { cy.task('esArchiverLoad', { archiveName: 'timeline' }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts index ba20f89defef..80d4a9780c6e 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts @@ -16,7 +16,8 @@ import { TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP, TIMELINE_ROW_RENDERERS_MODAL_CLOSE_BUTTON, } from '../../../screens/timeline'; -import { deleteTimelines, waitForWelcomePanelToBeLoaded } from '../../../tasks/common'; +import { deleteTimelines } from '../../../tasks/api_calls/common'; +import { waitForWelcomePanelToBeLoaded } from '../../../tasks/common'; import { waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; import { login } from '../../../tasks/login'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts index 00b3726bfec2..a7b4191d8b47 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts @@ -22,6 +22,7 @@ import { changeTimelineQueryLanguage, executeTimelineKQL, executeTimelineSearch, + showDataProviderQueryBuilder, } from '../../../tasks/timeline'; import { waitForTimelinesPanelToBeLoaded } from '../../../tasks/timelines'; @@ -52,7 +53,8 @@ describe('Timeline search and filters', { tags: ['@ess', '@serverless'] }, () => }); }); - describe('Update kqlMode for timeline', () => { + // FLAKY: https://github.com/elastic/kibana/issues/169882 + describe.skip('Update kqlMode for timeline', () => { beforeEach(() => { login(); visit(TIMELINES_URL); @@ -60,6 +62,7 @@ describe('Timeline search and filters', { tags: ['@ess', '@serverless'] }, () => openTimelineUsingToggle(); cy.intercept('PATCH', '/api/timeline').as('update'); cy.get(LOADING_INDICATOR).should('not.exist'); + showDataProviderQueryBuilder(); cy.get(TIMELINE_SEARCH_OR_FILTER).click(); cy.get(TIMELINE_SEARCH_OR_FILTER).should('exist'); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts index 5c7d1dafa667..fd52a80ed9ff 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts @@ -20,17 +20,26 @@ import { } from '../../../tasks/kibana_navigation'; import { login } from '../../../tasks/login'; import { visitWithTimeRange } from '../../../tasks/navigation'; -import { closeTimelineUsingToggle } from '../../../tasks/security_main'; +import { + closeTimelineUsingCloseButton, + openTimelineUsingToggle, +} from '../../../tasks/security_main'; +import { + navigateToHostsUsingBreadcrumb, + navigateToExploreUsingBreadcrumb, + navigateToAlertsPageInServerless, + navigateToDiscoverPageInServerless, + navigateToExplorePageInServerless, +} from '../../../tasks/serverless/navigation'; import { addNameToTimelineAndSave, createNewTimeline, populateTimeline, } from '../../../tasks/timeline'; -import { hostsUrl, MANAGE_URL } from '../../../urls/navigation'; - -// https://github.com/elastic/kibana/issues/169021 +import { EXPLORE_URL, hostsUrl, MANAGE_URL } from '../../../urls/navigation'; -describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/169588 +describe.skip('Save Timeline Prompts', { tags: ['@ess'] }, () => { before(() => { login(); /* @@ -47,6 +56,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ beforeEach(() => { login(); visitWithTimeRange(hostsUrl('allHosts')); + openTimelineUsingToggle(); createNewTimeline(); }); @@ -58,7 +68,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('Changed & unsaved timeline should prompt when user navigates away from security solution', () => { populateTimeline(); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); openKibanaNavigation(); navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); @@ -67,7 +77,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('Changed & unsaved timeline should NOT prompt when user navigates away within security solution where timelines are enabled', () => { populateTimeline(); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); // navigate to any other page in security solution openKibanaNavigation(); cy.get(CASES_PAGE).click(); @@ -85,7 +95,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('Changed & saved timeline should NOT prompt when user navigates away out of security solution', () => { populateTimeline(); addNameToTimelineAndSave('Test'); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); openKibanaNavigation(); navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); @@ -94,7 +104,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('Changed & saved timeline should NOT prompt when user navigates within security solution where timelines are disabled', () => { populateTimeline(); addNameToTimelineAndSave('Test'); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); openKibanaNavigation(); cy.get(MANAGE_PAGE).click(); cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); @@ -102,7 +112,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('When user navigates to the page where timeline is present, Timeline save modal should not exists.', () => { populateTimeline(); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); openKibanaNavigation(); cy.get(MANAGE_PAGE).click(); cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); @@ -118,7 +128,7 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ it('Changed and unsaved timeline should NOT prompt when user navigates from the page where timeline is disabled', () => { populateTimeline(); - closeTimelineUsingToggle(); + closeTimelineUsingCloseButton(); openKibanaNavigation(); cy.get(MANAGE_PAGE).click(); cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); @@ -133,3 +143,91 @@ describe('Save Timeline Prompts', { tags: ['@ess', '@serverless', '@brokenInServ cy.url().should('not.contain', MANAGE_URL); }); }); + +// In serverless it is not possible to use the navigation menu without closing the timeline +describe('Save Timeline Prompts', { tags: ['@serverless'] }, () => { + before(() => { + login(); + /* + * When timeline changes are pending, chrome would popup with + * a confirm dialog stating that `you can lose unsaved changed. + * Below changes will disable that. + * + * */ + cy.window().then((win) => { + win.onbeforeunload = null; + }); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(hostsUrl('allHosts')); + openTimelineUsingToggle(); + createNewTimeline(); + }); + + it('unchanged & unsaved timeline should NOT prompt when it is closed and navigate to any page', () => { + closeTimelineUsingCloseButton(); + + navigateToAlertsPageInServerless(); // security page with timelines enabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + navigateToExplorePageInServerless(); // security page with timelines disabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + navigateToDiscoverPageInServerless(); // external page + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + }); + + it('Changed & unsaved timeline should prompt when it is closed and navigate to Security page without timeline', () => { + populateTimeline(); + closeTimelineUsingCloseButton(); + + navigateToAlertsPageInServerless(); // security page with timelines enabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + navigateToExplorePageInServerless(); // security page with timelines disabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + }); + + it('Changed & unsaved timeline should prompt when it is closed and navigate to external page', () => { + populateTimeline(); + closeTimelineUsingCloseButton(); + + navigateToDiscoverPageInServerless(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + }); + + it('Changed & saved timeline should NOT prompt when it is closed', () => { + populateTimeline(); + addNameToTimelineAndSave('Test'); + closeTimelineUsingCloseButton(); + + navigateToAlertsPageInServerless(); // security page with timelines enabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + navigateToExplorePageInServerless(); // security page with timelines disabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + navigateToDiscoverPageInServerless(); // external page + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + }); + + it('Changed & unsaved timeline should NOT prompt when navigate to page with timeline using breadcrumbs', () => { + populateTimeline(); + navigateToHostsUsingBreadcrumb(); // hosts has timelines enabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + }); + + it('Changed & unsaved timeline should NOT prompt when navigate to page without timeline using breadcrumbs', () => { + populateTimeline(); + navigateToExploreUsingBreadcrumb(); // explore has timelines disabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + cy.url().should('contain', EXPLORE_URL); + }); + + it('Changed & saved timeline should NOT prompt when user navigates within security solution where timelines are disabled', () => { + populateTimeline(); + addNameToTimelineAndSave('Test'); + navigateToExploreUsingBreadcrumb(); // explore has timelines disabled + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/objects/exception.ts b/x-pack/test/security_solution_cypress/cypress/objects/exception.ts index 6e754d837dcf..6865784ae5ba 100644 --- a/x-pack/test/security_solution_cypress/cypress/objects/exception.ts +++ b/x-pack/test/security_solution_cypress/cypress/objects/exception.ts @@ -6,6 +6,7 @@ */ import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ELASTICSEARCH_USERNAME } from '../env_var_names_constants'; export interface Exception { field: string; @@ -61,5 +62,15 @@ export const expectedExportedExceptionList = ( exceptionListResponse: Cypress.Response ): string => { const jsonRule = exceptionListResponse.body; - return `{"_version":"${jsonRule._version}","created_at":"${jsonRule.created_at}","created_by":"system_indices_superuser","description":"${jsonRule.description}","id":"${jsonRule.id}","immutable":false,"list_id":"${jsonRule.list_id}","name":"${jsonRule.name}","namespace_type":"single","os_types":[],"tags":[],"tie_breaker_id":"${jsonRule.tie_breaker_id}","type":"${jsonRule.type}","updated_at":"${jsonRule.updated_at}","updated_by":"system_indices_superuser","version":1}\n{"exported_exception_list_count":1,"exported_exception_list_item_count":0,"missing_exception_list_item_count":0,"missing_exception_list_items":[],"missing_exception_lists":[],"missing_exception_lists_count":0}\n`; + return `{"_version":"${jsonRule._version}","created_at":"${ + jsonRule.created_at + }","created_by":"${Cypress.env(ELASTICSEARCH_USERNAME)}","description":"${ + jsonRule.description + }","id":"${jsonRule.id}","immutable":false,"list_id":"${jsonRule.list_id}","name":"${ + jsonRule.name + }","namespace_type":"single","os_types":[],"tags":[],"tie_breaker_id":"${ + jsonRule.tie_breaker_id + }","type":"${jsonRule.type}","updated_at":"${jsonRule.updated_at}","updated_by":"${Cypress.env( + ELASTICSEARCH_USERNAME + )}","version":1}\n{"exported_exception_list_count":1,"exported_exception_list_item_count":0,"missing_exception_list_item_count":0,"missing_exception_list_items":[],"missing_exception_lists":[],"missing_exception_lists_count":0}\n`; }; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts index f616b63e45e1..cfcd52372dae 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts @@ -33,6 +33,8 @@ export const ALERT_SEVERITY = '[data-test-subj="formatted-field-kibana.alert.sev export const ALERT_DATA_GRID = '[data-test-subj="euiDataGridBody"]'; +export const ALERT_DATA_GRID_ROW = `${ALERT_DATA_GRID} .euiDataGridRow`; + export const ALERTS_COUNT = '[data-test-subj="toolbar-alerts-count"]'; export const CLOSE_ALERT_BTN = '[data-test-subj="close-alert-status"]'; @@ -140,10 +142,8 @@ export const SELECT_HISTOGRAM = '[data-test-subj="chart-select-trend"]'; export const LEGEND_ACTIONS = { ADD_TO_TIMELINE: (ruleName: string) => `[data-test-subj="legend-${ruleName}-embeddable_addToTimeline"]`, - FILTER_FOR: (ruleName: string) => - `[data-test-subj="legend-${ruleName}-histogramLegendActionFilterIn"]`, - FILTER_OUT: (ruleName: string) => - `[data-test-subj="legend-${ruleName}-histogramLegendActionFilterOut"]`, + FILTER_FOR: (ruleName: string) => `[data-test-subj="legend-${ruleName}-embeddable_filterIn"]`, + FILTER_OUT: (ruleName: string) => `[data-test-subj="legend-${ruleName}-embeddable_filterOut"]`, COPY: (ruleName: string) => `[data-test-subj="legend-${ruleName}-embeddable_copyToClipboard"]`, }; @@ -182,3 +182,36 @@ export const ALERT_RENDERER_HOST_NAME = '[data-test-subj="alertFieldBadge"] [data-test-subj="render-content-host.name"]'; export const HOVER_ACTIONS_CONTAINER = getDataTestSubjectSelector('hover-actions-container'); + +export const ALERT_USERS_PROFILES_SELECTABLE_MENU_ITEM = '.euiSelectableListItem'; +export const ALERT_USERS_PROFILES_CLEAR_SEARCH_BUTTON = '[data-test-subj="clearSearchButton"]'; + +export const ALERT_ASSIGN_CONTEXT_MENU_ITEM = + '[data-test-subj="alert-assignees-context-menu-item"]'; + +export const ALERT_UNASSIGN_CONTEXT_MENU_ITEM = + '[data-test-subj="remove-alert-assignees-menu-item"]'; + +export const ALERT_ASSIGNEES_SELECT_PANEL = + '[data-test-subj="securitySolutionAssigneesApplyPanel"]'; + +export const ALERT_ASSIGNEES_UPDATE_BUTTON = + '[data-test-subj="securitySolutionAssigneesApplyButton"]'; + +export const ALERT_USER_AVATAR = (assignee: string) => + `[data-test-subj="securitySolutionUsersAvatar-${assignee}"][title='${assignee}']`; + +export const ALERT_AVATARS_PANEL = '[data-test-subj="securitySolutionUsersAvatarsPanel"]'; + +export const ALERT_ASIGNEES_COLUMN = + '[data-test-subj="dataGridRowCell"][data-gridcell-column-id="kibana.alert.workflow_assignee_ids"]'; + +export const ALERT_ASSIGNEES_COUNT_BADGE = + '[data-test-subj="securitySolutionUsersAvatarsCountBadge"]'; + +export const FILTER_BY_ASSIGNEES_BUTTON = '[data-test-subj="filter-popover-button-assignees"]'; + +export const ALERT_DETAILS_ASSIGN_BUTTON = + '[data-test-subj="securitySolutionFlyoutHeaderAssigneesAddButton"]'; + +export const ALERT_DETAILS_TAKE_ACTION_BUTTON = '[data-test-subj="take-action-dropdown-btn"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts b/x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts index 8109bc31e07a..8dbc850fb017 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts @@ -23,9 +23,9 @@ export const ALL_CASES_NOT_PUSHED = '[data-test-subj="case-table-column-external export const ALL_CASES_NUMBER_OF_ALERTS = '[data-test-subj="case-table-column-alertsCount"]'; -export const ALL_CASES_OPEN_CASES_COUNT = '[data-test-subj="case-status-filter"]'; +export const ALL_CASES_STATUS_FILTER = '[data-test-subj="options-filter-popover-button-status"]'; -export const ALL_CASES_OPEN_FILTER = '[data-test-subj="case-status-filter-open"]'; +export const ALL_CASES_OPEN_FILTER = '[data-test-subj="options-filter-popover-item-open"]'; export const ALL_CASES_OPEN_CASES_STATS = '[data-test-subj="openStatsHeader"] .euiDescriptionList__description'; @@ -43,6 +43,6 @@ export const ALL_CASES_TAGS = (tag: string) => { return `[data-test-subj="case-table-column-tags-${tag}"]`; }; -export const ALL_CASES_TAGS_COUNT = '[data-test-subj="options-filter-popover-button-Tags"]'; +export const ALL_CASES_TAGS_COUNT = '[data-test-subj="options-filter-popover-button-tags"]'; export const EDIT_EXTERNAL_CONNECTION = '[data-test-subj="configure-case-button"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts index ad7e26d209d5..f28c7692a77a 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts @@ -21,6 +21,6 @@ export const SUBMIT_BTN = '[data-test-subj="create-case-submit"]'; export const TAGS_INPUT = '[data-test-subj="caseTags"] [data-test-subj="comboBoxSearchInput"]'; -export const TIMELINE = '[data-test-subj="timeline"]'; +export const TIMELINE = '[data-test-subj="selectable-input"] [data-test-subj="timeline"]'; export const TITLE_INPUT = '[data-test-subj="caseTitle"] [data-test-subj="input"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts index ebdabcb67bb1..2c025efcbe79 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts @@ -33,4 +33,9 @@ export const RISK_SCORE_UPDATE_BUTTON = '[data-test-subj="risk-score-update-butt export const RISK_SCORE_STATUS = '[data-test-subj="risk-score-status"]'; +export const RISK_SCORE_STATUS_LOADING = '[data-test-subj="risk-score-status-loading"]'; + +export const RISK_SCORE_PRIVILEGES_CALLOUT = + '[data-test-subj="callout-missing-risk-engine-privileges"]'; + export const RISK_SCORE_SWITCH = '[data-test-subj="risk-score-switch"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/events_viewer.ts b/x-pack/test/security_solution_cypress/cypress/screens/events_viewer.ts new file mode 100644 index 000000000000..d488eb411ec3 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/screens/events_viewer.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DATA_GRID_EMPTY_STATE = '[data-test-subj="tGridEmptyState"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts index 5b8c8255dffe..7edd12dcf1ed 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts @@ -5,10 +5,6 @@ * 2.0. */ -import { - INSIGHTS_TAB_BUTTON_GROUP_TEST_ID, - VISUALIZE_TAB_BUTTON_GROUP_TEST_ID, -} from '@kbn/security-solution-plugin/public/flyout/document_details/left/tabs/test_ids'; import { INSIGHTS_TAB_TEST_ID, INVESTIGATION_TAB_TEST_ID, @@ -25,9 +21,3 @@ export const DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB = getDataTestSubjectSelector(INVESTIGATION_TAB_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_RESPONSE_TAB = getDataTestSubjectSelector(RESPONSE_TAB_TEST_ID); -export const DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP = getDataTestSubjectSelector( - VISUALIZE_TAB_BUTTON_GROUP_TEST_ID -); -export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP = getDataTestSubjectSelector( - INSIGHTS_TAB_BUTTON_GROUP_TEST_ID -); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts index 0cda5fb1c87e..8d4bb411c9e3 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts @@ -6,23 +6,33 @@ */ import { - ENTITIES_DETAILS_TEST_ID, HOST_DETAILS_TEST_ID, USER_DETAILS_TEST_ID, } from '@kbn/security-solution-plugin/public/flyout/document_details/left/components/test_ids'; import { INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/document_details/left/tabs/test_ids'; -import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/shared/components/test_ids'; +import { + EXPANDABLE_PANEL_CONTENT_TEST_ID, + EXPANDABLE_PANEL_HEADER_RIGHT_SECTION_TEST_ID, + EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, +} from '@kbn/security-solution-plugin/public/flyout/shared/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON = getDataTestSubjectSelector( INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID ); - -export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT = - getDataTestSubjectSelector(ENTITIES_DETAILS_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE = getDataTestSubjectSelector( + EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(USER_DETAILS_TEST_ID) +); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_RIGHT_SECTION = + getDataTestSubjectSelector(EXPANDABLE_PANEL_HEADER_RIGHT_SECTION_TEST_ID(USER_DETAILS_TEST_ID)); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS = getDataTestSubjectSelector( EXPANDABLE_PANEL_CONTENT_TEST_ID(USER_DETAILS_TEST_ID) ); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE = getDataTestSubjectSelector( + EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(HOST_DETAILS_TEST_ID) +); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_RIGHT_SECTION = + getDataTestSubjectSelector(EXPANDABLE_PANEL_HEADER_RIGHT_SECTION_TEST_ID(HOST_DETAILS_TEST_ID)); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS = getDataTestSubjectSelector( EXPANDABLE_PANEL_CONTENT_TEST_ID(HOST_DETAILS_TEST_ID) ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts index 0efc48511c9b..fe7f7d2fc9e8 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts @@ -10,7 +10,6 @@ import { PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, - PREVALENCE_DETAILS_TABLE_TEST_ID, PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_DATE_PICKER_TEST_ID, @@ -23,9 +22,6 @@ export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_BUTTON = getDataTes ); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_DATE_PICKER = getDataTestSubjectSelector(PREVALENCE_DETAILS_DATE_PICKER_TEST_ID); -export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE = getDataTestSubjectSelector( - PREVALENCE_DETAILS_TABLE_TEST_ID -); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_TYPE_CELL = getDataTestSubjectSelector(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_NAME_CELL = diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts index 90d051aec1b5..e808a3c07a7d 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts @@ -9,7 +9,6 @@ import { RULE_PREVIEW_TITLE_TEST_ID, RULE_PREVIEW_RULE_CREATED_BY_TEST_ID, RULE_PREVIEW_RULE_UPDATED_BY_TEST_ID, - RULE_PREVIEW_BODY_TEST_ID, RULE_PREVIEW_ABOUT_HEADER_TEST_ID, RULE_PREVIEW_ABOUT_CONTENT_TEST_ID, RULE_PREVIEW_DEFINITION_HEADER_TEST_ID, @@ -17,46 +16,35 @@ import { RULE_PREVIEW_SCHEDULE_HEADER_TEST_ID, RULE_PREVIEW_SCHEDULE_CONTENT_TEST_ID, RULE_PREVIEW_FOOTER_TEST_ID, + RULE_PREVIEW_NAVIGATE_TO_RULE_TEST_ID, } from '@kbn/security-solution-plugin/public/flyout/document_details/preview/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION = - getDataTestSubjectSelector('previewSection'); - -export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_HEADER = - getDataTestSubjectSelector('previewSectionHeader'); - export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE = getDataTestSubjectSelector( RULE_PREVIEW_TITLE_TEST_ID ); - export const DOCUMENT_DETAILS_FLYOUT_CREATED_BY = getDataTestSubjectSelector( RULE_PREVIEW_RULE_CREATED_BY_TEST_ID ); - export const DOCUMENT_DETAILS_FLYOUT_UPDATED_BY = getDataTestSubjectSelector( RULE_PREVIEW_RULE_UPDATED_BY_TEST_ID ); - -export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_BODY = - getDataTestSubjectSelector(RULE_PREVIEW_BODY_TEST_ID); - export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER = getDataTestSubjectSelector( RULE_PREVIEW_ABOUT_HEADER_TEST_ID ); export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT = getDataTestSubjectSelector(RULE_PREVIEW_ABOUT_CONTENT_TEST_ID); - export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER = getDataTestSubjectSelector(RULE_PREVIEW_DEFINITION_HEADER_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT = getDataTestSubjectSelector(RULE_PREVIEW_DEFINITION_CONTENT_TEST_ID); - export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER = getDataTestSubjectSelector(RULE_PREVIEW_SCHEDULE_HEADER_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT = getDataTestSubjectSelector(RULE_PREVIEW_SCHEDULE_CONTENT_TEST_ID); - export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER = getDataTestSubjectSelector( RULE_PREVIEW_FOOTER_TEST_ID ); +export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER_LINK = getDataTestSubjectSelector( + RULE_PREVIEW_NAVIGATE_TO_RULE_TEST_ID +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts index de2a25749d6a..afe87189acd3 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts @@ -17,10 +17,13 @@ import { SEVERITY_VALUE_TEST_ID, STATUS_BUTTON_TEST_ID, FLYOUT_HEADER_TITLE_TEST_ID, + ASSIGNEES_HEADER_TEST_ID, } from '@kbn/security-solution-plugin/public/flyout/document_details/right/components/test_ids'; import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID, + TITLE_HEADER_TEXT_TEST_ID, + TITLE_LINK_ICON_TEST_ID, } from '@kbn/security-solution-plugin/public/flyout/shared/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; @@ -28,8 +31,14 @@ export const DOCUMENT_DETAILS_FLYOUT_BODY = getDataTestSubjectSelector(FLYOUT_BO /* Header */ +export const DOCUMENT_DETAILS_FLYOUT_HEADER_ICON = getDataTestSubjectSelector( + TITLE_LINK_ICON_TEST_ID(FLYOUT_HEADER_TITLE_TEST_ID) +); export const DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE = getDataTestSubjectSelector( - FLYOUT_HEADER_TITLE_TEST_ID + TITLE_HEADER_TEXT_TEST_ID(FLYOUT_HEADER_TITLE_TEST_ID) +); +export const DOCUMENT_DETAILS_FLYOUT_HEADER_LINK_ICON = getDataTestSubjectSelector( + TITLE_LINK_ICON_TEST_ID(FLYOUT_HEADER_TITLE_TEST_ID) ); export const DOCUMENT_DETAILS_FLYOUT_CLOSE_BUTTON = getDataTestSubjectSelector('euiFlyoutCloseButton'); @@ -51,6 +60,8 @@ export const DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE = getDataTestSubjectSelector(RISK_SCORE_VALUE_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE = getDataTestSubjectSelector(SEVERITY_VALUE_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_HEADER_ASSIGNEES = + getDataTestSubjectSelector(ASSIGNEES_HEADER_TEST_ID); /* Footer */ diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts index e53d1af68d45..66549fea944c 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts @@ -5,11 +5,14 @@ * 2.0. */ -import { JSON_TAB_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/document_details/right/tabs/test_ids'; -import { RIGHT_SECTION_TEST_ID } from '@kbn/expandable-flyout/src/components/test_ids'; +import { + JSON_TAB_CONTENT_TEST_ID, + JSON_TAB_COPY_TO_CLIPBOARD_BUTTON_TEST_ID, +} from '@kbn/security-solution-plugin/public/flyout/document_details/right/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -export const DOCUMENT_DETAILS_FLYOUT_RIGHT_PANEL_CONTENT = - getDataTestSubjectSelector(RIGHT_SECTION_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_JSON_TAB_COPY_TO_CLIPBOARD_BUTTON = getDataTestSubjectSelector( + JSON_TAB_COPY_TO_CLIPBOARD_BUTTON_TEST_ID +); export const DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT = getDataTestSubjectSelector(JSON_TAB_CONTENT_TEST_ID); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts index 771180e1be13..18c0bd9029ff 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts @@ -5,15 +5,9 @@ * 2.0. */ -import { TABLE_TAB_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/document_details/right/tabs/test_ids'; import { getClassSelector, getDataTestSubjectSelector } from '../../helpers/common'; -export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT = - getDataTestSubjectSelector(TABLE_TAB_CONTENT_TEST_ID); - export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_FILTER = getClassSelector('euiFieldSearch'); -export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CLEAR_FILTER = - getDataTestSubjectSelector('clearSearchButton'); export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW = getDataTestSubjectSelector( 'event-fields-table-row-@timestamp' ); @@ -22,6 +16,9 @@ export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_CELL = export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW = getDataTestSubjectSelector( 'event-fields-table-row-_id' ); +export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_HOST_OS_BUILD_ROW = getDataTestSubjectSelector( + 'event-fields-table-row-host.os.build' +); const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_ACTIONS = 'actionItem-security-detailsFlyout-cellActions-'; export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_FILTER_IN = getDataTestSubjectSelector( diff --git a/x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts index fd962a5e5bb9..5e516a54fd3b 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts @@ -25,7 +25,8 @@ export const INSPECT_MODAL = '[data-test-subj="modal-inspect-euiModal"]'; export const INSPECT_QUERY = '[data-test-subj="events-viewer-panel"] [data-test-subj="inspect-icon-button"]'; -export const SERVER_SIDE_EVENT_COUNT = '[data-test-subj="server-side-event-count"]'; +export const SERVER_SIDE_EVENT_COUNT = + '[data-test-subj="events-viewer-panel"] [data-test-subj="server-side-event-count"]'; export const EVENT_VIEWER_CHECKBOX = '[data-test-subj="dataGridHeaderCell-checkbox-control-column"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_breadcrumbs.ts b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_breadcrumbs.ts new file mode 100644 index 000000000000..8cc1be861383 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_breadcrumbs.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const EXPLORE_BREADCRUMB = + '[data-test-subj*="breadcrumb-deepLinkId-securitySolutionUI:explore"]'; +export const HOSTS_BREADCRUMB = + '[data-test-subj*="breadcrumb-deepLinkId-securitySolutionUI:hosts"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts index 755c31d116a6..35ed8f63b216 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts @@ -29,7 +29,7 @@ export const CORRELATION_EVENT_TABLE_CELL = export const CLOSE_TIMELINE_BTN = '[data-test-subj="close-timeline"]'; -export const COMBO_BOX = '.euiComboBoxOption__content'; +export const COMBO_BOX = 'button.euiFilterSelectItem[role="option"]'; export const COMBO_BOX_INPUT = '[data-test-subj="comboBoxInput"]'; @@ -222,7 +222,7 @@ export const TIMELINE_FLYOUT_BODY = '[data-test-subj="query-tab-flyout-body"]'; export const TIMELINE_HEADER = '[data-test-subj="timeline-hide-show-container"]'; -export const TIMELINE_INSPECT_BUTTON = `${TIMELINE_FLYOUT} [data-test-subj="inspect-icon-button"]`; +export const TIMELINE_INSPECT_BUTTON = `${TIMELINE_FLYOUT} [data-test-subj="inspect-empty-button"]`; export const TIMELINE_PANEL = `[data-test-subj="timeline-flyout-header-panel"]`; @@ -261,6 +261,8 @@ export const TIMELINE_SAVE_MODAL = '[data-test-subj="save-timeline-modal"]'; export const TIMELINE_EDIT_MODAL_SAVE_BUTTON = '[data-test-subj="save-button"]'; +export const TIMELINE_EDIT_MODAL_SAVE_AS_NEW_SWITCH = '[data-test-subj="save-as-new-switch"]'; + export const TIMELINE_EXIT_FULL_SCREEN_BUTTON = '[data-test-subj="exit-full-screen"]'; export const TIMELINE_FLYOUT_WRAPPER = '[data-test-subj="flyout-pane"]'; @@ -354,3 +356,14 @@ export const OPEN_TIMELINE_MODAL_SEARCH_BAR = `${OPEN_TIMELINE_MODAL} ${getData export const OPEN_TIMELINE_MODAL_TIMELINE_NAMES = `${OPEN_TIMELINE_MODAL} ${getDataTestSubjectSelectorStartWith( 'timeline-title-' )}`; + +export const TIMELINE_FILTER_BADGE = `[data-test-subj^='timeline-filters-container'] [data-test-subj^="filter-badge"]`; + +export const NEW_TIMELINE_ACTION = getDataTestSubjectSelector('new-timeline-action'); + +export const SAVE_TIMELINE_ACTION = getDataTestSubjectSelector('save-timeline-action'); +export const SAVE_TIMELINE_ACTION_BTN = getDataTestSubjectSelector('save-timeline-action-btn'); + +export const SAVE_TIMELINE_TOOLTIP = getDataTestSubjectSelector('save-timeline-btn-tooltip'); + +export const TOGGLE_DATA_PROVIDER_BTN = getDataTestSubjectSelector('toggle-data-provider'); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts b/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts index b7d12bca8b74..a90faeb6e80f 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts @@ -59,3 +59,5 @@ export const TIMELINES_OVERVIEW_ONLY_FAVORITES = `${TIMELINES_OVERVIEW} [data-te export const TIMELINES_OVERVIEW_SEARCH = `${TIMELINES_OVERVIEW} [data-test-subj="search-bar"]`; export const TIMELINES_OVERVIEW_TABLE = `${TIMELINES_OVERVIEW} [data-test-subj="timelines-table"]`; + +export const ROWS = '.euiTableRow'; diff --git a/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts b/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts index e1dc4c952eac..02ebebb6c10e 100644 --- a/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts +++ b/x-pack/test/security_solution_cypress/cypress/support/setup_users.ts @@ -6,7 +6,7 @@ */ import { Role } from '@kbn/security-plugin/common'; -import { rootRequest } from '../tasks/common'; +import { rootRequest } from '../tasks/api_calls/common'; /** * Utility function creates roles and corresponding users per each role with names diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alert_assignments.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alert_assignments.ts new file mode 100644 index 000000000000..c0adfbf1d78f --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alert_assignments.ts @@ -0,0 +1,236 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; +import { + ALERTS_TABLE_ROW_LOADER, + ALERT_AVATARS_PANEL, + ALERT_ASSIGNEES_SELECT_PANEL, + ALERT_ASSIGN_CONTEXT_MENU_ITEM, + ALERT_ASSIGNEES_UPDATE_BUTTON, + ALERT_USER_AVATAR, + ALERT_DATA_GRID_ROW, + ALERT_DETAILS_ASSIGN_BUTTON, + ALERT_DETAILS_TAKE_ACTION_BUTTON, + ALERT_UNASSIGN_CONTEXT_MENU_ITEM, + ALERT_USERS_PROFILES_CLEAR_SEARCH_BUTTON, + ALERT_USERS_PROFILES_SELECTABLE_MENU_ITEM, + ALERT_ASIGNEES_COLUMN, + ALERT_ASSIGNEES_COUNT_BADGE, + FILTER_BY_ASSIGNEES_BUTTON, + TAKE_ACTION_POPOVER_BTN, + TIMELINE_CONTEXT_MENU_BTN, +} from '../screens/alerts'; +import { PAGE_TITLE } from '../screens/common/page'; +import { DOCUMENT_DETAILS_FLYOUT_HEADER_ASSIGNEES } from '../screens/expandable_flyout/alert_details_right_panel'; +import { selectFirstPageAlerts } from './alerts'; +import { login } from './login'; +import { visitWithTimeRange } from './navigation'; + +export const NO_ASSIGNEES = 'No assignees'; + +export const waitForAssigneesToPopulatePopover = () => { + cy.waitUntil( + () => { + cy.log('Waiting for assignees to appear in popover'); + return cy.root().then(($el) => { + const $updateButton = $el.find(ALERT_ASSIGNEES_UPDATE_BUTTON); + return !$updateButton.prop('disabled'); + }); + }, + { interval: 500, timeout: 12000 } + ); +}; + +export const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +export const loadPageAs = (url: string, role?: SecurityRoleName) => { + login(role); + visitWithTimeRange(url); + waitForPageTitleToBeShown(); +}; + +export const openAlertAssigningActionMenu = (alertIndex = 0) => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).eq(alertIndex).click(); + cy.get(ALERT_ASSIGN_CONTEXT_MENU_ITEM).click(); +}; + +export const openAlertAssigningBulkActionMenu = () => { + cy.get(TAKE_ACTION_POPOVER_BTN).click(); + cy.get(ALERT_ASSIGN_CONTEXT_MENU_ITEM).click(); +}; + +export const updateAlertAssignees = () => { + cy.get(ALERT_ASSIGNEES_UPDATE_BUTTON).click(); +}; + +export const checkEmptyAssigneesStateInAlertsTable = () => { + cy.get(ALERT_DATA_GRID_ROW) + .its('length') + .then((count) => { + cy.get(ALERT_ASIGNEES_COLUMN).should('have.length', count); + }); + cy.get(ALERT_ASIGNEES_COLUMN).each(($column) => { + cy.wrap($column).within(() => { + cy.get(ALERT_AVATARS_PANEL).children().should('have.length', 0); + }); + }); +}; + +export const checkEmptyAssigneesStateInAlertDetailsFlyout = () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_ASSIGNEES).within(() => { + cy.get(ALERT_AVATARS_PANEL).children().should('have.length', 0); + }); +}; + +export const alertsTableMoreActionsAreNotAvailable = () => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).should('not.exist'); +}; + +export const asigneesMenuItemsAreNotAvailable = (alertIndex = 0) => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).eq(alertIndex).click(); + cy.get(ALERT_ASSIGN_CONTEXT_MENU_ITEM).should('not.exist'); + cy.get(ALERT_UNASSIGN_CONTEXT_MENU_ITEM).should('not.exist'); +}; + +export const asigneesBulkMenuItemsAreNotAvailable = () => { + selectFirstPageAlerts(); + cy.get(TAKE_ACTION_POPOVER_BTN).click(); + cy.get(ALERT_ASSIGN_CONTEXT_MENU_ITEM).should('not.exist'); + cy.get(ALERT_UNASSIGN_CONTEXT_MENU_ITEM).should('not.exist'); +}; + +export const cannotAddAssigneesViaDetailsFlyout = () => { + cy.get(ALERT_DETAILS_ASSIGN_BUTTON).should('be.disabled'); +}; + +export const alertsTableShowsAssigneesForAlert = (users: SecurityRoleName[], alertIndex = 0) => { + cy.get(ALERT_ASIGNEES_COLUMN) + .eq(alertIndex) + .within(() => { + users.forEach((user) => cy.get(`.euiAvatar${ALERT_USER_AVATAR(user)}`).should('exist')); + }); +}; + +export const alertsTableShowsAssigneesForAllAlerts = (users: SecurityRoleName[]) => { + cy.get(ALERT_ASIGNEES_COLUMN).each(($column) => { + cy.wrap($column).within(() => { + users.forEach((user) => cy.get(`.euiAvatar${ALERT_USER_AVATAR(user)}`).should('exist')); + }); + }); +}; + +export const alertsTableShowsAssigneesBadgeForAlert = ( + users: SecurityRoleName[], + alertIndex = 0 +) => { + cy.get(ALERT_ASIGNEES_COLUMN) + .eq(alertIndex) + .within(() => { + cy.get(ALERT_ASSIGNEES_COUNT_BADGE).contains(users.length); + users.forEach((user) => cy.get(`.euiAvatar${ALERT_USER_AVATAR(user)}`).should('not.exist')); + }); +}; + +export const alertDetailsFlyoutShowsAssignees = (users: SecurityRoleName[]) => { + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_ASSIGNEES).within(() => { + users.forEach((user) => cy.get(`.euiAvatar${ALERT_USER_AVATAR(user)}`).should('exist')); + }); +}; + +export const alertDetailsFlyoutShowsAssigneesBadge = (users: SecurityRoleName[]) => { + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_ASSIGNEES).within(() => { + cy.get(ALERT_ASSIGNEES_COUNT_BADGE).contains(users.length); + users.forEach((user) => cy.get(`.euiAvatar${ALERT_USER_AVATAR(user)}`).should('not.exist')); + }); +}; + +export const selectAlertAssignee = (assignee: string) => { + cy.get(ALERT_ASSIGNEES_SELECT_PANEL).within(() => { + if (assignee === NO_ASSIGNEES) { + cy.get(ALERT_USERS_PROFILES_SELECTABLE_MENU_ITEM).contains(assignee).click(); + return; + } + cy.get('input').type(assignee); + cy.get(ALERT_USERS_PROFILES_SELECTABLE_MENU_ITEM).contains(assignee).click(); + cy.get(ALERT_USERS_PROFILES_CLEAR_SEARCH_BUTTON).click(); + }); +}; + +/** + * This will update assignees for selected alert + * @param users The list of assugnees to update. If assignee is not assigned yet it will be assigned, otherwise it will be unassigned + * @param alertIndex The index of the alert in the alerts table + */ +export const updateAssigneesForAlert = (users: SecurityRoleName[], alertIndex = 0) => { + openAlertAssigningActionMenu(alertIndex); + waitForAssigneesToPopulatePopover(); + users.forEach((user) => selectAlertAssignee(user)); + updateAlertAssignees(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const updateAssigneesViaAddButtonInFlyout = (users: SecurityRoleName[]) => { + cy.get(ALERT_DETAILS_ASSIGN_BUTTON).click(); + waitForAssigneesToPopulatePopover(); + users.forEach((user) => selectAlertAssignee(user)); + updateAlertAssignees(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const updateAssigneesViaTakeActionButtonInFlyout = (users: SecurityRoleName[]) => { + cy.get(ALERT_DETAILS_TAKE_ACTION_BUTTON).click(); + cy.get(ALERT_ASSIGN_CONTEXT_MENU_ITEM).click(); + waitForAssigneesToPopulatePopover(); + users.forEach((user) => selectAlertAssignee(user)); + updateAlertAssignees(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const bulkUpdateAssignees = (users: SecurityRoleName[]) => { + openAlertAssigningBulkActionMenu(); + waitForAssigneesToPopulatePopover(); + users.forEach((user) => selectAlertAssignee(user)); + updateAlertAssignees(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const removeAllAssigneesForAlert = (alertIndex = 0) => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).eq(alertIndex).click(); + cy.get(ALERT_UNASSIGN_CONTEXT_MENU_ITEM).click(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const removeAllAssigneesViaTakeActionButtonInFlyout = () => { + cy.get(ALERT_DETAILS_TAKE_ACTION_BUTTON).click(); + cy.get(ALERT_UNASSIGN_CONTEXT_MENU_ITEM).click(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const bulkRemoveAllAssignees = () => { + cy.get(TAKE_ACTION_POPOVER_BTN).click(); + cy.get(ALERT_UNASSIGN_CONTEXT_MENU_ITEM).click(); + cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist'); +}; + +export const filterByAssignees = (users: Array) => { + cy.get(FILTER_BY_ASSIGNEES_BUTTON).scrollIntoView(); + cy.get(FILTER_BY_ASSIGNEES_BUTTON).click(); + users.forEach((user) => selectAlertAssignee(user)); + cy.get(FILTER_BY_ASSIGNEES_BUTTON).click(); +}; + +export const clearAssigneesFilter = () => { + cy.get(FILTER_BY_ASSIGNEES_BUTTON).scrollIntoView(); + cy.get(FILTER_BY_ASSIGNEES_BUTTON).click(); + cy.get(ALERT_ASSIGNEES_SELECT_PANEL).within(() => { + cy.contains('Clear filters').click(); + }); + cy.get(FILTER_BY_ASSIGNEES_BUTTON).click(); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/alerts.ts index 43d9952b9b37..3b9c0612a072 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/alerts.ts @@ -9,7 +9,7 @@ import { RuleObjectId, RuleSignatureId, } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const DEFAULT_ALERTS_INDEX_PATTERN = '.alerts-security.alerts-*'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts new file mode 100644 index 000000000000..775b4c5a8964 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/common.ts @@ -0,0 +1,264 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DATA_VIEW_PATH, INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { ELASTICSEARCH_PASSWORD, ELASTICSEARCH_USERNAME } from '../../env_var_names_constants'; +import { deleteAllDocuments } from './elasticsearch'; +import { DEFAULT_ALERTS_INDEX_PATTERN } from './alerts'; + +export const API_AUTH = Object.freeze({ + user: Cypress.env(ELASTICSEARCH_USERNAME), + pass: Cypress.env(ELASTICSEARCH_PASSWORD), +}); + +export const API_HEADERS = Object.freeze({ + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + [ELASTIC_HTTP_VERSION_HEADER]: [INITIAL_REST_VERSION], +}); + +export const rootRequest = ({ + headers: optionHeaders, + ...restOptions +}: Partial): Cypress.Chainable> => + cy.request({ + auth: API_AUTH, + headers: { + ...API_HEADERS, + ...(optionHeaders || {}), + }, + ...restOptions, + }); + +export const deleteAlertsAndRules = () => { + cy.log('Delete all alerts and rules'); + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + + rootRequest({ + method: 'POST', + url: '/api/detection_engine/rules/_bulk_action', + body: { + query: '', + action: 'delete', + }, + failOnStatusCode: false, + timeout: 300000, + }); + + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'alert', + }, + }, + ], + }, + }, + }, + }); + + deleteAllDocuments(`.lists-*,.items-*,${DEFAULT_ALERTS_INDEX_PATTERN}`); +}; + +export const deleteExceptionLists = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'exception-list', + }, + }, + ], + }, + }, + }, + }); +}; + +export const deleteEndpointExceptionList = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'exception-list-agnostic', + }, + }, + ], + }, + }, + }, + }); +}; + +export const deleteTimelines = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'siem-ui-timeline', + }, + }, + ], + }, + }, + }, + }); +}; + +export const deleteAlertsIndex = () => { + rootRequest({ + method: 'POST', + url: '/api/index_management/indices/delete', + body: { indices: ['.internal.alerts-security.alerts-default-000001'] }, + failOnStatusCode: false, + }); +}; + +export const deleteAllCasesItems = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_alerting_cases_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + term: { + type: 'cases', + }, + }, + { + term: { + type: 'cases-configure', + }, + }, + { + term: { + type: 'cases-comments', + }, + }, + { + term: { + type: 'cases-user-action', + }, + }, + { + term: { + type: 'cases-connector-mappings', + }, + }, + ], + }, + }, + ], + }, + }, + }, + }); +}; + +export const deleteConnectors = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_alerting_cases_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'action', + }, + }, + ], + }, + }, + }, + }); +}; + +export const deletePrebuiltRulesAssets = () => { + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + rootRequest({ + method: 'POST', + url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, + body: { + query: { + bool: { + filter: [ + { + match: { + type: 'security-rule', + }, + }, + ], + }, + }, + }, + }); +}; + +export const postDataView = (indexPattern: string, name?: string, id?: string) => { + rootRequest({ + method: 'POST', + url: DATA_VIEW_PATH, + body: { + data_view: { + id: id || indexPattern, + name: name || indexPattern, + fieldAttrs: '{}', + title: indexPattern, + timeFieldName: '@timestamp', + }, + }, + failOnStatusCode: false, + }); +}; + +export const deleteDataView = (dataViewId: string) => { + rootRequest({ + method: 'POST', + url: 'api/content_management/rpc/delete', + body: { + contentTypeId: 'index-pattern', + id: dataViewId, + options: { force: true }, + version: 1, + }, + failOnStatusCode: false, + }); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts index d94049f14c8a..6dc3622f72a0 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts @@ -4,17 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const deleteIndex = (index: string) => { rootRequest({ method: 'DELETE', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); }; @@ -23,11 +18,6 @@ export const deleteDataStream = (dataStreamName: string) => { rootRequest({ method: 'DELETE', url: `${Cypress.env('ELASTICSEARCH_URL')}/_data_stream/${dataStreamName}`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); }; @@ -40,11 +30,6 @@ export const deleteAllDocuments = (target: string) => { url: `${Cypress.env( 'ELASTICSEARCH_URL' )}/${target}/_delete_by_query?conflicts=proceed&scroll_size=10000&refresh`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, body: { query: { match_all: {}, @@ -57,11 +42,6 @@ export const createIndex = (indexName: string, properties: Record({ method: 'GET', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }).then((response) => { if (response.status !== 200) { @@ -110,11 +80,6 @@ export const refreshIndex = (index: string) => { rootRequest({ method: 'POST', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_refresh`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }).then((response) => { if (response.status !== 200) { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts index 8b7d85b7ebf4..4e0afa7416da 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts @@ -13,17 +13,12 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { ENDPOINT_LIST_ITEM_URL, ENDPOINT_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ExceptionList, ExceptionListItem, RuleExceptionItem } from '../../objects/exception'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const createEndpointExceptionList = () => rootRequest({ method: 'POST', url: ENDPOINT_LIST_URL, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); export const createEndpointExceptionListItem = (item: CreateEndpointListItemSchema) => @@ -31,11 +26,6 @@ export const createEndpointExceptionListItem = (item: CreateEndpointListItemSche method: 'POST', url: ENDPOINT_LIST_ITEM_URL, body: item, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); export const createExceptionList = ( @@ -51,11 +41,6 @@ export const createExceptionList = ( name: exceptionList.name, type: exceptionList.type, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); @@ -88,11 +73,6 @@ export const createExceptionListItem = ( ], expire_time: exceptionListItem?.expire_time, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); @@ -103,11 +83,6 @@ export const createRuleExceptionItem = (ruleId: string, exceptionListItems: Rule body: { items: exceptionListItems, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); @@ -122,11 +97,6 @@ export const updateExceptionListItem = ( item_id: exceptionListItemId, ...exceptionListItemUpdate, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); @@ -134,10 +104,5 @@ export const deleteExceptionList = (listId: string, namespaceType: string) => rootRequest({ method: 'DELETE', url: `/api/exception_lists?list_id=${listId}&namespace_type=${namespaceType}`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts index 5295b033fc7c..d77361c95ebd 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { rootRequest } from '../common'; +import { rootRequest } from './common'; /** * Deletes all existing Fleet packages, package policies and agent policies. @@ -25,21 +25,11 @@ const deleteAgentPolicies = () => { return rootRequest<{ items: Array<{ id: string }> }>({ method: 'GET', url: 'api/fleet/agent_policies', - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }).then((response) => { response.body.items.forEach((item: { id: string }) => { rootRequest({ method: 'POST', url: `api/fleet/agent_policies/delete`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, body: { agentPolicyId: item.id, }, @@ -52,20 +42,10 @@ const deletePackagePolicies = () => { return rootRequest<{ items: Array<{ id: string }> }>({ method: 'GET', url: 'api/fleet/package_policies', - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }).then((response) => { rootRequest({ method: 'POST', url: `api/fleet/package_policies/delete`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, body: { packagePolicyIds: response.body.items.map((item: { id: string }) => item.id), }, @@ -77,22 +57,12 @@ const deletePackages = () => { return rootRequest<{ items: Array<{ status: string; name: string; version: string }> }>({ method: 'GET', url: 'api/fleet/epm/packages', - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }).then((response) => { response.body.items.forEach((item) => { if (item.status === 'installed') { rootRequest({ method: 'DELETE', url: `api/fleet/epm/packages/${item.name}/${item.version}`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); } }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/integrations.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/integrations.ts similarity index 83% rename from x-pack/test/security_solution_cypress/cypress/tasks/integrations.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/integrations.ts index eeef97682b9c..4e212d4b8eb3 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/integrations.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/integrations.ts @@ -56,11 +56,6 @@ export function installIntegrations({ packages, force: true, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); // Install agent and package policies @@ -68,11 +63,6 @@ export function installIntegrations({ method: 'POST', url: `${AGENT_POLICY_API_ROUTES.CREATE_PATTERN}?sys_monitoring=true`, body: agentPolicy, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }).then((response) => { const packagePolicyWithAgentPolicyId: PackagePolicy = { ...packagePolicy, @@ -83,11 +73,6 @@ export function installIntegrations({ method: 'POST', url: PACKAGE_POLICY_API_ROUTES.CREATE_PATTERN, body: packagePolicyWithAgentPolicyId, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); }); } diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts index 2c982adad527..27d5063ce30d 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts @@ -7,14 +7,13 @@ import { SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID } from '@kbn/management-settings-ids'; import { ENABLE_EXPANDABLE_FLYOUT_SETTING } from '@kbn/security-solution-plugin/common/constants'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const setKibanaSetting = (key: string, value: boolean | number | string) => { rootRequest({ method: 'POST', url: 'internal/kibana/settings', body: { changes: { [key]: value } }, - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/machine_learning.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/machine_learning.ts index afb468876c5f..f03d6edadbc1 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/machine_learning.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/machine_learning.ts @@ -7,17 +7,12 @@ import { ML_INTERNAL_BASE_PATH } from '@kbn/ml-plugin/common/constants/app'; import type { Module } from '@kbn/ml-plugin/common/types/modules'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const fetchMachineLearningModules = () => { return rootRequest({ method: 'GET', url: `${ML_INTERNAL_BASE_PATH}/modules/get_module`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': 1, - }, failOnStatusCode: false, }); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts index d1addc040790..21f718dc355d 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts @@ -17,5 +17,9 @@ export const addNoteToTimeline = ( version: null, note: { note, timelineId }, }, - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'elastic-api-version': '2023-10-31', + }, }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts index 98b9a884e683..273491ebd2ef 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts @@ -13,17 +13,12 @@ import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common/d import type { PrePackagedRulesStatusResponse } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; import { getPrebuiltRuleWithExceptionsMock } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks'; import { createRuleAssetSavedObject } from '../../helpers/rules'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const getPrebuiltRulesStatus = () => { return rootRequest({ method: 'GET', url: 'api/detection_engine/rules/prepackaged/_status', - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); }; @@ -43,14 +38,12 @@ export const installAllPrebuiltRulesRequest = () => rootRequest({ method: 'POST', url: PERFORM_RULE_INSTALLATION_URL, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '1', - }, body: { mode: 'ALL_RULES', }, + headers: { + 'elastic-api-version': '1', + }, }); /* Install specific prebuilt rules. Should be available as security-rule saved objects @@ -63,11 +56,6 @@ export const installSpecificPrebuiltRulesRequest = (rules: Array({ method: 'POST', url: PERFORM_RULE_INSTALLATION_URL, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '1', - }, body: { mode: 'SPECIFIC_RULES', rules: rules.map((rule) => ({ @@ -75,6 +63,9 @@ export const installSpecificPrebuiltRulesRequest = (rules: Array { @@ -128,8 +119,6 @@ export const createNewRuleAsset = ({ method: 'PUT', url, headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', 'Content-Type': 'application/json', }, failOnStatusCode: false, @@ -182,7 +171,7 @@ export const bulkCreateRuleAssets = ({ return rootRequest({ method: 'POST', url, - headers: { 'kbn-xsrf': 'cypress-creds', 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json' }, failOnStatusCode: false, body: bulkIndexRequestBody, }).then((response) => response.status === 200); @@ -197,8 +186,6 @@ export const getRuleAssets = (index: string | undefined = '.kibana_security_solu method: 'GET', url, headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', 'Content-Type': 'application/json', }, failOnStatusCode: false, diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts index 254d93cac507..5f89e57ff81c 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts @@ -16,16 +16,11 @@ import type { } from '@kbn/security-solution-plugin/common/api/detection_engine'; import type { FetchRulesResponse } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; import { internalAlertingSnoozeRule } from '../../urls/routes'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const findAllRules = () => { return rootRequest({ url: DETECTION_ENGINE_RULES_URL_FIND, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); }; @@ -36,11 +31,6 @@ export const createRule = ( method: 'POST', url: DETECTION_ENGINE_RULES_URL, body: rule, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); }; @@ -52,7 +42,7 @@ export const createRule = ( * @param duration Snooze duration in milliseconds, -1 for indefinite */ export const snoozeRule = (id: string, duration: number): Cypress.Chainable => - cy.request({ + rootRequest({ method: 'POST', url: internalAlertingSnoozeRule(id), body: { @@ -61,7 +51,6 @@ export const snoozeRule = (id: string, duration: number): Cypress.Chainable => rRule: { dtstart: new Date().toISOString(), count: 1, tzid: moment().format('zz') }, }, }, - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -69,11 +58,6 @@ export const deleteCustomRule = (ruleId = '1') => { rootRequest({ method: 'DELETE', url: `api/detection_engine/rules?rule_id=${ruleId}`, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, failOnStatusCode: false, }); }; @@ -89,10 +73,7 @@ export const importRule = (ndjsonPath: string) => { url: 'api/detection_engine/rules/_import', method: 'POST', headers: { - 'kbn-xsrf': 'cypress-creds', 'content-type': 'multipart/form-data', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', }, body: formdata, }) @@ -108,10 +89,7 @@ export const waitForRulesToFinishExecution = (ruleIds: string[], afterDate?: Dat method: 'GET', url: DETECTION_ENGINE_RULES_URL_FIND, headers: { - 'kbn-xsrf': 'cypress-creds', 'content-type': 'multipart/form-data', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', }, }).then((response) => { const areAllRulesFinished = ruleIds.every((ruleId) => diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts index 88049b20d6d5..0ec356e83727 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { SavedQuery } from '@kbn/data-plugin/public'; import { SAVED_QUERY_BASE_URL } from '@kbn/data-plugin/common/constants'; -import { rootRequest } from '../common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { rootRequest } from './common'; export const createSavedQuery = ( title: string, @@ -37,9 +37,7 @@ export const createSavedQuery = ( ], }, headers: { - 'kbn-xsrf': 'cypress-creds', [ELASTIC_HTTP_VERSION_HEADER]: '1', - 'x-elastic-internal-origin': 'security-solution', }, }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/sourcerer.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/sourcerer.ts new file mode 100644 index 000000000000..a266678ee95d --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/sourcerer.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { rootRequest } from './common'; + +export const deleteRuntimeField = (dataView: string, fieldName: string) => { + const deleteRuntimeFieldPath = `/api/data_views/data_view/${dataView}/runtime_field/${fieldName}`; + + rootRequest({ + url: deleteRuntimeFieldPath, + method: 'DELETE', + failOnStatusCode: false, + }); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts index 9b6a0c98db40..620a105a2b98 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts @@ -7,7 +7,7 @@ import type { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; import type { CompleteTimeline } from '../../objects/timeline'; -import { rootRequest } from '../common'; +import { rootRequest } from './common'; export const createTimeline = (timeline: CompleteTimeline) => rootRequest({ @@ -56,11 +56,6 @@ export const createTimeline = (timeline: CompleteTimeline) => : {}), }, }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - 'elastic-api-version': '2023-10-31', - }, }); export const createTimelineTemplate = (timeline: CompleteTimeline) => @@ -106,14 +101,23 @@ export const createTimelineTemplate = (timeline: CompleteTimeline) => savedQueryId: null, }, }, - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'elastic-api-version': '2023-10-31', + }, }); export const loadPrepackagedTimelineTemplates = () => rootRequest({ method: 'POST', url: 'api/timeline/_prepackaged', - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + + 'elastic-api-version': '2023-10-31', + }, }); export const favoriteTimeline = ({ @@ -136,5 +140,4 @@ export const favoriteTimeline = ({ templateTimelineId: templateTimelineId || null, templateTimelineVersion: templateTimelineVersion || null, }, - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common.ts index a9b019fc1f6f..b7d0062cd5d0 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/common.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/common.ts @@ -5,13 +5,8 @@ * 2.0. */ -import { DATA_VIEW_PATH, INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { KIBANA_LOADING_ICON } from '../screens/security_header'; import { EUI_BASIC_TABLE_LOADING } from '../screens/common/controls'; -import { deleteAllDocuments } from './api_calls/elasticsearch'; -import { DEFAULT_ALERTS_INDEX_PATTERN } from './api_calls/alerts'; -import { ELASTICSEARCH_PASSWORD, ELASTICSEARCH_USERNAME } from '../env_var_names_constants'; const primaryButton = 0; @@ -21,30 +16,6 @@ const primaryButton = 0; */ const dndSloppyClickDetectionThreshold = 5; -export const API_AUTH = Object.freeze({ - user: Cypress.env(ELASTICSEARCH_USERNAME), - pass: Cypress.env(ELASTICSEARCH_PASSWORD), -}); - -export const API_HEADERS = Object.freeze({ - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - [ELASTIC_HTTP_VERSION_HEADER]: [INITIAL_REST_VERSION], -}); - -export const rootRequest = ({ - headers: optionHeaders, - ...restOptions -}: Partial): Cypress.Chainable> => - cy.request({ - auth: API_AUTH, - headers: { - ...API_HEADERS, - ...(optionHeaders || {}), - }, - ...restOptions, - }); - /** Starts dragging the subject */ export const drag = (subject: JQuery) => { const subjectLocation = subject[0].getBoundingClientRect(); @@ -99,243 +70,6 @@ export const resetRulesTableState = () => { clearSessionStorage(); }; -export const deleteAlertsAndRules = () => { - cy.log('Delete all alerts and rules'); - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; - - rootRequest({ - method: 'POST', - url: '/api/detection_engine/rules/_bulk_action', - body: { - query: '', - action: 'delete', - }, - failOnStatusCode: false, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - }, - timeout: 300000, - }); - - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'alert', - }, - }, - ], - }, - }, - }, - }); - - deleteAllDocuments(`.lists-*,.items-*,${DEFAULT_ALERTS_INDEX_PATTERN}`); -}; - -export const deleteExceptionLists = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'exception-list', - }, - }, - ], - }, - }, - }, - }); -}; - -export const deleteEndpointExceptionList = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'exception-list-agnostic', - }, - }, - ], - }, - }, - }, - }); -}; - -export const deleteTimelines = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'siem-ui-timeline', - }, - }, - ], - }, - }, - }, - }); -}; - -export const deleteAlertsIndex = () => { - rootRequest({ - method: 'POST', - url: '/api/index_management/indices/delete', - body: { indices: ['.internal.alerts-security.alerts-default-000001'] }, - failOnStatusCode: false, - }); -}; - -export const deleteAllCasesItems = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_alerting_cases_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - bool: { - should: [ - { - term: { - type: 'cases', - }, - }, - { - term: { - type: 'cases-configure', - }, - }, - { - term: { - type: 'cases-comments', - }, - }, - { - term: { - type: 'cases-user-action', - }, - }, - { - term: { - type: 'cases-connector-mappings', - }, - }, - ], - }, - }, - ], - }, - }, - }, - }); -}; - -export const deleteConnectors = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_alerting_cases_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'action', - }, - }, - ], - }, - }, - }, - }); -}; - -export const deletePrebuiltRulesAssets = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; - rootRequest({ - method: 'POST', - url: `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed&refresh`, - body: { - query: { - bool: { - filter: [ - { - match: { - type: 'security-rule', - }, - }, - ], - }, - }, - }, - }); -}; - -export const postDataView = (indexPattern: string, name?: string, id?: string) => { - rootRequest({ - method: 'POST', - url: DATA_VIEW_PATH, - body: { - data_view: { - id: id || indexPattern, - name: name || indexPattern, - fieldAttrs: '{}', - title: indexPattern, - timeFieldName: '@timestamp', - }, - }, - headers: { - 'kbn-xsrf': 'cypress-creds', - 'x-elastic-internal-origin': 'security-solution', - }, - failOnStatusCode: false, - }); -}; - -export const deleteDataView = (dataViewId: string) => { - rootRequest({ - method: 'POST', - url: 'api/content_management/rpc/delete', - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, - body: { - contentTypeId: 'index-pattern', - id: dataViewId, - options: { force: true }, - version: 1, - }, - failOnStatusCode: false, - }); -}; - export const scrollToBottom = () => cy.scrollTo('bottom'); export const waitForWelcomePanelToBeLoaded = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts index 65da5e0a7d5f..aa154cd15b03 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts @@ -12,7 +12,7 @@ import type { TestCase, TestCaseWithoutTimeline, } from '../objects/case'; -import { ALL_CASES_OPEN_CASES_COUNT, ALL_CASES_OPEN_FILTER } from '../screens/all_cases'; +import { ALL_CASES_STATUS_FILTER, ALL_CASES_OPEN_FILTER } from '../screens/all_cases'; import { TIMELINE_SEARCHBOX } from '../screens/common/controls'; import { @@ -46,7 +46,7 @@ export const backToCases = () => { }; export const filterStatusOpen = () => { - cy.get(ALL_CASES_OPEN_CASES_COUNT).click(); + cy.get(ALL_CASES_STATUS_FILTER).click(); cy.get(ALL_CASES_OPEN_FILTER).click(); }; @@ -80,7 +80,7 @@ export const attachTimeline = (newCase: TestCase) => { }, { interval: 500, timeout: 12000 } ); - cy.get(TIMELINE).eq(1).click(); + cy.get(TIMELINE).first().click(); }; export const createCase = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts index 0f3d9ee86529..14c9ef05aa87 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts @@ -5,13 +5,12 @@ * 2.0. */ -import type { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; import { BACK_TO_RULE_DETAILS, EDIT_SUBMIT_BUTTON } from '../screens/edit_rule'; import { editRuleUrl } from '../urls/edit_rule'; import { visit } from './navigation'; -export function visitEditRulePage(ruleId: string, role?: SecurityRoleName): void { - visit(editRuleUrl(ruleId), { role }); +export function visitEditRulePage(ruleId: string): void { + visit(editRuleUrl(ruleId)); } export const saveEditedRule = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts index c3af909131cd..710526bdff18 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { INPUT_FILE, TOASTER, TOASTER_BODY } from '../screens/alerts_detection_rules'; +import { + INPUT_FILE, + TOASTER, + TOASTER_BODY, + TOASTER_CLOSE_ICON, +} from '../screens/alerts_detection_rules'; import { EXCEPTIONS_TABLE, EXCEPTIONS_TABLE_SEARCH, @@ -70,6 +75,12 @@ export const exportExceptionList = (listId: string) => { .click(); cy.get(EXCEPTIONS_TABLE_EXPORT_MODAL_BTN).first().click(); cy.get(EXCEPTIONS_TABLE_EXPIRED_EXCEPTION_ITEMS_MODAL_CONFIRM_BTN).first().click(); + cy.root().then(($page) => { + const element = $page.find(TOASTER_CLOSE_ICON); + if (element.length > 0) { + closeErrorToast(); + } + }); }; export const assertNumberLinkedRules = (listId: string, numberOfRulesAsString: string) => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts index abc08842c2fc..cf023e4bd9a6 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts @@ -14,7 +14,3 @@ export const openCorrelationsTab = () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON).scrollIntoView(); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON).should('be.visible').click(); }; - -export const expandCorrelationsSection = (sectionSelector: string) => { - cy.get(`${sectionSelector} button`).should('be.visible').click(); -}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts index fe578fd14517..0e87a938d627 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts @@ -7,7 +7,6 @@ import { DOCUMENT_DETAILS_FLYOUT_BODY } from '../../screens/expandable_flyout/alert_details_right_panel'; import { - DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CLEAR_FILTER, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_FILTER, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_ADD_TO_TIMELINE, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_FILTER_IN, @@ -24,14 +23,6 @@ export const filterTableTabTable = (filterValue: string) => cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_FILTER).type(filterValue); }); -/** - * Clear table filter under the Table tab in the alert details expandable flyout right section - */ -export const clearFilterTableTabTable = () => - cy.get(DOCUMENT_DETAILS_FLYOUT_BODY).within(() => { - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CLEAR_FILTER).click(); - }); - /** * Filter In action in the first table row under the Table tab in the alert details expandable flyout right section */ @@ -65,11 +56,3 @@ export const toggleColumnTableTabTable = () => { cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_CELL).first().realHover(); cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_TOGGLE_COLUMN).click(); }; - -/** - * Clear filters in the alert page KQL bar - */ -export const clearFilters = () => - cy.get(DOCUMENT_DETAILS_FLYOUT_BODY).within(() => { - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_FILTER_OUT).first().click(); - }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/login.ts b/x-pack/test/security_solution_cypress/cypress/tasks/login.ts index 07a91a903536..884c0a656df5 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/login.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/login.ts @@ -6,19 +6,17 @@ */ import * as yaml from 'js-yaml'; -import type { UrlObject } from 'url'; -import Url from 'url'; import { LoginState } from '@kbn/security-plugin/common/login_state'; import type { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; import { KNOWN_SERVERLESS_ROLE_DEFINITIONS } from '@kbn/security-solution-plugin/common/test'; import { LOGOUT_URL } from '../urls/navigation'; -import { rootRequest } from './common'; import { CLOUD_SERVERLESS, ELASTICSEARCH_PASSWORD, ELASTICSEARCH_USERNAME, IS_SERVERLESS, } from '../env_var_names_constants'; +import { API_HEADERS, rootRequest } from './api_calls/common'; /** * Credentials in the `kibana.dev.yml` config file will be used to authenticate @@ -65,29 +63,6 @@ export const loginWithUser = (user: User): void => { loginWithUsernameAndPassword(user.username, user.password); }; -/** - * cy.visit will default to the baseUrl which uses the default kibana test user - * This function will override that functionality in cy.visit by building the baseUrl - * directly from the environment variables set up in x-pack/test/security_solution_cypress/runner.ts - * - * @param role string role/user to log in with - * @param route string route to visit - */ -export const getUrlWithRoute = (role: SecurityRoleName, route: string): string => { - const url = Cypress.config().baseUrl; - const kibana = new URL(String(url)); - const theUrl = `${Url.format({ - auth: `${role}:changeme`, - username: role, - password: 'changeme', - protocol: kibana.protocol.replace(':', ''), - hostname: kibana.hostname, - port: kibana.port, - } as UrlObject)}${route.startsWith('/') ? '' : '/'}${route}`; - cy.log(`origin: ${theUrl}`); - return theUrl; -}; - /** * Builds a URL with basic auth using the passed in user. * @@ -210,7 +185,7 @@ const loginWithUsernameAndPassword = (username: string, password: string): void (provider) => provider.type === 'basic' ); - return rootRequest({ + cy.request({ url: `${baseUrl}/internal/security/login`, method: 'POST', body: { @@ -219,6 +194,7 @@ const loginWithUsernameAndPassword = (username: string, password: string): void currentURL: '/', params: { username, password }, }, + headers: API_HEADERS, }); }); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/navigation.ts b/x-pack/test/security_solution_cypress/cypress/tasks/navigation.ts index b7c6f55386c3..47914bbf7552 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/navigation.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/navigation.ts @@ -8,34 +8,24 @@ import { encode } from '@kbn/rison'; import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants'; -import type { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; import { GET_STARTED_URL, hostDetailsUrl, userDetailsUrl } from '../urls/navigation'; -import { constructUrlWithUser, getUrlWithRoute, User } from './login'; export const visit = ( url: string, options?: { visitOptions?: Partial; - role?: SecurityRoleName; } ) => { - cy.visit(options?.role ? getUrlWithRoute(options.role, url) : url, { + cy.visit(url, { onBeforeLoad: disableNewFeaturesTours, ...options?.visitOptions, }); }; -export const visitWithUser = (url: string, user: User) => { - cy.visit(constructUrlWithUser(user, url), { - onBeforeLoad: disableNewFeaturesTours, - }); -}; - export const visitWithTimeRange = ( url: string, options?: { visitOptions?: Partial; - role?: SecurityRoleName; } ) => { const timerangeConfig = { @@ -57,7 +47,7 @@ export const visitWithTimeRange = ( }, }); - cy.visit(options?.role ? getUrlWithRoute(options.role, url) : url, { + cy.visit(url, { ...options, qs: { ...options?.visitOptions?.qs, @@ -74,9 +64,9 @@ export const visitWithTimeRange = ( }); }; -export const visitTimeline = (timelineId: string, role?: SecurityRoleName) => { +export const visitTimeline = (timelineId: string) => { const route = `/app/security/timelines?timeline=(id:'${timelineId}',isOpen:!t)`; - cy.visit(role ? getUrlWithRoute(role, route) : route, { + cy.visit(route, { onBeforeLoad: disableNewFeaturesTours, }); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts index 1dadb67a9698..f9dd302d5956 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts @@ -51,7 +51,7 @@ interface VisitRuleDetailsPageOptions { } export function visitRuleDetailsPage(ruleId: string, options?: VisitRuleDetailsPageOptions): void { - visit(ruleDetailsUrl(ruleId, options?.tab), { role: options?.role }); + visit(ruleDetailsUrl(ruleId, options?.tab)); } export const enablesRule = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/rules_management.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rules_management.ts index 663692aa905d..79af9992b9c1 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/rules_management.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/rules_management.ts @@ -5,15 +5,14 @@ * 2.0. */ -import type { SecurityRoleName } from '@kbn/security-solution-plugin/common/test'; import { LAST_BREADCRUMB, RULE_MANAGEMENT_PAGE_BREADCRUMB } from '../screens/breadcrumbs'; import { RULES_MANAGEMENT_URL } from '../urls/rules_management'; import { resetRulesTableState } from './common'; import { visit } from './navigation'; -export function visitRulesManagementTable(role?: SecurityRoleName): void { +export function visitRulesManagementTable(): void { resetRulesTableState(); // Clear persistent rules filter data before page loading - visit(RULES_MANAGEMENT_URL, { role }); + visit(RULES_MANAGEMENT_URL); } export function openRuleManagementPageViaBreadcrumbs(): void { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts b/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts index 9b8af6c5ceef..15c171676c95 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts @@ -5,21 +5,13 @@ * 2.0. */ -import { - CLOSE_TIMELINE_BUTTON, - TIMELINE_TOGGLE_BUTTON, - TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON, -} from '../screens/security_main'; +import { CLOSE_TIMELINE_BUTTON, TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON } from '../screens/security_main'; import { TIMELINE_EXIT_FULL_SCREEN_BUTTON, TIMELINE_FULL_SCREEN_BUTTON } from '../screens/timeline'; export const openTimelineUsingToggle = () => { cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).click(); }; -export const closeTimelineUsingToggle = () => { - cy.get(TIMELINE_TOGGLE_BUTTON).filter(':visible').click(); -}; - export const closeTimelineUsingCloseButton = () => { cy.get(CLOSE_TIMELINE_BUTTON).filter(':visible').click(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/serverless/navigation.ts b/x-pack/test/security_solution_cypress/cypress/tasks/serverless/navigation.ts index 90c380e8f88b..8f5e597f375e 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/serverless/navigation.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/serverless/navigation.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { ALERTS } from '../../screens/serverless_security_header'; +import { ALERTS, DISCOVER, EXPLORE } from '../../screens/serverless_security_header'; +import { + EXPLORE_BREADCRUMB, + HOSTS_BREADCRUMB, +} from '../../screens/serverless_security_breadcrumbs'; const navigateTo = (page: string) => { cy.get(page).click(); @@ -14,3 +18,19 @@ const navigateTo = (page: string) => { export const navigateToAlertsPageInServerless = () => { navigateTo(ALERTS); }; + +export const navigateToDiscoverPageInServerless = () => { + navigateTo(DISCOVER); +}; + +export const navigateToExplorePageInServerless = () => { + navigateTo(EXPLORE); +}; + +export const navigateToHostsUsingBreadcrumb = () => { + cy.get(HOSTS_BREADCRUMB).click(); +}; + +export const navigateToExploreUsingBreadcrumb = () => { + cy.get(EXPLORE_BREADCRUMB).click(); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts b/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts index 39a6ed99b1b2..a534fb3e6d3d 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts @@ -9,7 +9,6 @@ import { DEFAULT_ALERTS_INDEX } from '@kbn/security-solution-plugin/common/const import { HOSTS_STAT, SOURCERER } from '../screens/sourcerer'; import { hostsUrl } from '../urls/navigation'; import { openTimelineUsingToggle } from './security_main'; -import { rootRequest } from './common'; import { visitWithTimeRange } from './navigation'; export const openSourcerer = (sourcererScope?: string) => { @@ -130,14 +129,3 @@ export const refreshUntilAlertsIndexExists = async () => { { interval: 500, timeout: 12000 } ); }; - -export const deleteRuntimeField = (dataView: string, fieldName: string) => { - const deleteRuntimeFieldPath = `/api/data_views/data_view/${dataView}/runtime_field/${fieldName}`; - - rootRequest({ - url: deleteRuntimeFieldPath, - method: 'DELETE', - headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, - failOnStatusCode: false, - }); -}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts index 2579e3794a07..ddf432a86092 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts @@ -54,8 +54,8 @@ import { CREATE_NEW_TIMELINE_TEMPLATE, OPEN_TIMELINE_TEMPLATE_ICON, TIMELINE_SAVE_MODAL, - TIMELINE_SAVE_MODAL_OPEN_BUTTON, TIMELINE_EDIT_MODAL_SAVE_BUTTON, + TIMELINE_EDIT_MODAL_SAVE_AS_NEW_SWITCH, TIMELINE_PROGRESS_BAR, QUERY_TAB_BUTTON, CLOSE_OPEN_TIMELINE_MODAL_BTN, @@ -89,6 +89,10 @@ import { OPEN_TIMELINE_MODAL_TIMELINE_NAMES, OPEN_TIMELINE_MODAL_SEARCH_BAR, OPEN_TIMELINE_MODAL, + NEW_TIMELINE_ACTION, + SAVE_TIMELINE_ACTION, + TOGGLE_DATA_PROVIDER_BTN, + SAVE_TIMELINE_ACTION_BTN, } from '../screens/timeline'; import { REFRESH_BUTTON, TIMELINE } from '../screens/timelines'; import { drag, drop } from './common'; @@ -102,7 +106,7 @@ export const addDescriptionToTimeline = ( modalAlreadyOpen: boolean = false ) => { if (!modalAlreadyOpen) { - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).first().click(); + cy.get(SAVE_TIMELINE_ACTION_BTN).first().click(); } cy.get(TIMELINE_DESCRIPTION_INPUT).should('not.be.disabled').type(description); cy.get(TIMELINE_DESCRIPTION_INPUT).invoke('val').should('equal', description); @@ -111,7 +115,7 @@ export const addDescriptionToTimeline = ( }; export const addNameToTimelineAndSave = (name: string) => { - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).first().click(); + cy.get(SAVE_TIMELINE_ACTION_BTN).first().click(); cy.get(TIMELINE_TITLE_INPUT).should('not.be.disabled').clear(); cy.get(TIMELINE_TITLE_INPUT).type(`${name}{enter}`); cy.get(TIMELINE_TITLE_INPUT).should('have.attr', 'value', name); @@ -119,12 +123,23 @@ export const addNameToTimelineAndSave = (name: string) => { cy.get(TIMELINE_TITLE_INPUT).should('not.exist'); }; +export const addNameToTimelineAndSaveAsNew = (name: string) => { + cy.get(SAVE_TIMELINE_ACTION_BTN).first().click(); + cy.get(TIMELINE_TITLE_INPUT).should('not.be.disabled').clear(); + cy.get(TIMELINE_TITLE_INPUT).type(`${name}{enter}`); + cy.get(TIMELINE_TITLE_INPUT).should('have.attr', 'value', name); + cy.get(TIMELINE_EDIT_MODAL_SAVE_AS_NEW_SWITCH).should('exist'); + cy.get(TIMELINE_EDIT_MODAL_SAVE_AS_NEW_SWITCH).click(); + cy.get(TIMELINE_EDIT_MODAL_SAVE_BUTTON).click(); + cy.get(TIMELINE_TITLE_INPUT).should('not.exist'); +}; + export const addNameAndDescriptionToTimeline = ( timeline: Timeline, modalAlreadyOpen: boolean = false ) => { if (!modalAlreadyOpen) { - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).first().click(); + cy.get(SAVE_TIMELINE_ACTION).click(); } cy.get(TIMELINE_TITLE_INPUT).type(`${timeline.title}{enter}`); cy.get(TIMELINE_TITLE_INPUT).should('have.attr', 'value', timeline.title); @@ -197,7 +212,7 @@ export const addFilter = (filter: TimelineFilter): Cypress.Chainable { }; export const createNewTimeline = () => { - cy.get(TIMELINE_SETTINGS_ICON).filter(':visible').click(); - cy.get(TIMELINE_SETTINGS_ICON).should('be.visible'); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(1000); + cy.get(NEW_TIMELINE_ACTION).should('be.visible').trigger('click'); cy.get(CREATE_NEW_TIMELINE).eq(0).should('be.visible').click({ force: true }); }; export const openCreateTimelineOptionsPopover = () => { - cy.get(TIMELINE_SETTINGS_ICON).filter(':visible').should('be.visible').click(); + cy.get(NEW_TIMELINE_ACTION).filter(':visible').should('be.visible').click(); }; export const closeCreateTimelineOptionsPopover = () => { @@ -351,7 +363,7 @@ export const expandFirstTimelineEventDetails = () => { * before you're using this task. Otherwise it will fail to save. */ export const saveTimeline = () => { - cy.get(TIMELINE_SAVE_MODAL_OPEN_BUTTON).first().click(); + cy.get(SAVE_TIMELINE_ACTION_BTN).first().click(); cy.get(TIMELINE_SAVE_MODAL).within(() => { cy.get(TIMELINE_PROGRESS_BAR).should('not.exist'); @@ -387,7 +399,6 @@ export const openTimelineInspectButton = () => { }; export const openTimelineFromSettings = () => { - openCreateTimelineOptionsPopover(); cy.get(OPEN_TIMELINE_ICON).should('be.visible'); cy.get(OPEN_TIMELINE_ICON).click(); }; @@ -521,3 +532,9 @@ export const openTimelineFromOpenTimelineModal = (timelineName: string) => { cy.get(OPEN_TIMELINE_MODAL).should('contain.text', timelineName); cy.get(OPEN_TIMELINE_MODAL_TIMELINE_NAMES).first().click(); }; + +export const showDataProviderQueryBuilder = () => { + cy.get(TOGGLE_DATA_PROVIDER_BTN).should('have.attr', 'aria-pressed', 'false'); + cy.get(TOGGLE_DATA_PROVIDER_BTN).trigger('click'); + cy.get(TOGGLE_DATA_PROVIDER_BTN).should('have.attr', 'aria-pressed', 'true'); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tsconfig.json b/x-pack/test/security_solution_cypress/cypress/tsconfig.json index ad3ad00e19af..3e3563fa2e97 100644 --- a/x-pack/test/security_solution_cypress/cypress/tsconfig.json +++ b/x-pack/test/security_solution_cypress/cypress/tsconfig.json @@ -33,7 +33,6 @@ "@kbn/cases-components", "@kbn/security-solution-plugin", "@kbn/dev-utils", - "@kbn/expandable-flyout", "@kbn/config-schema", "@kbn/lists-plugin", "@kbn/securitysolution-list-constants", diff --git a/x-pack/test/security_solution_cypress/package.json b/x-pack/test/security_solution_cypress/package.json index e43f32a44757..e1f552fdba9d 100644 --- a/x-pack/test/security_solution_cypress/package.json +++ b/x-pack/test/security_solution_cypress/package.json @@ -7,9 +7,11 @@ "scripts": { "cypress": "NODE_OPTIONS=--openssl-legacy-provider ../../../node_modules/.bin/cypress", "cypress:open:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../plugins/security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../test/security_solution_cypress/cypress/cypress.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config", - "cypress:run:ess": "yarn cypress:ess --spec './cypress/e2e/!(investigations|explore)/**/*.cy.ts'", + "cypress:run:ess": "yarn cypress:ess --spec './cypress/e2e/!(investigations|explore|detection_response/rule_management)/**/*.cy.ts'", "cypress:run:cases:ess": "yarn cypress:ess --spec './cypress/e2e/explore/cases/*.cy.ts'", "cypress:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../plugins/security_solution/scripts/start_cypress_parallel run --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config", + "cypress:rule_management:run:ess":"yarn cypress:ess --spec './cypress/e2e/detection_response/rule_management/!(prebuilt_rules)/**/*.cy.ts'", + "cypress:rule_management:prebuilt_rules:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/rule_management/prebuilt_rules/**/*.cy.ts'", "cypress:run:respops:ess": "yarn cypress:ess --spec './cypress/e2e/(detection_response|exceptions)/**/*.cy.ts'", "cypress:investigations:run:ess": "yarn cypress:ess --spec './cypress/e2e/investigations/**/*.cy.ts'", "cypress:explore:run:ess": "yarn cypress:ess --spec './cypress/e2e/explore/**/*.cy.ts'", @@ -21,16 +23,20 @@ "cypress:cloud:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider NODE_TLS_REJECT_UNAUTHORIZED=0 ../../../node_modules/.bin/cypress", "cypress:open:cloud:serverless": "yarn cypress:cloud:serverless open --config-file ./cypress/cypress_serverless.config.ts --env CLOUD_SERVERLESS=true", "cypress:open:serverless": "yarn cypress:serverless open --config-file ../../test/security_solution_cypress/cypress/cypress_serverless.config.ts --spec './cypress/e2e/**/*.cy.ts'", - "cypress:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/!(investigations|explore)/**/*.cy.ts'", + "cypress:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/!(investigations|explore|detection_response/rule_management)/**/*.cy.ts'", "cypress:run:cloud:serverless": "yarn cypress:cloud:serverless run --config-file ./cypress/cypress_ci_serverless.config.ts --env CLOUD_SERVERLESS=true", + "cypress:rule_management:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/rule_management/!(prebuilt_rules)/**/*.cy.ts'", + "cypress:rule_management:prebuilt_rules:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/rule_management/prebuilt_rules/**/*.cy.ts'", "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'", "cypress:explore:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/explore/**/*.cy.ts'", "cypress:changed-specs-only:serverless": "yarn cypress:serverless --changed-specs-only --env burn=5", "cypress:burn:serverless": "yarn cypress:serverless --env burn=2", "cypress:qa:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../plugins/security_solution/scripts/start_cypress_parallel_serverless --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts", "cypress:open:qa:serverless": "yarn cypress:qa:serverless open", - "cypress:run:qa:serverless": "yarn cypress:qa:serverless --spec './cypress/e2e/!(investigations|explore)/**/*.cy.ts'", + "cypress:run:qa:serverless": "yarn cypress:qa:serverless --spec './cypress/e2e/!(investigations|explore|detection_response/rule_management)/**/*.cy.ts'", "cypress:run:qa:serverless:investigations": "yarn cypress:qa:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'", - "cypress:run:qa:serverless:explore": "yarn cypress:qa:serverless --spec './cypress/e2e/explore/**/*.cy.ts'" + "cypress:run:qa:serverless:explore": "yarn cypress:qa:serverless --spec './cypress/e2e/explore/**/*.cy.ts'", + "cypress:run:qa:serverless:rule_management": "yarn cypress:qa:serverless --spec './cypress/e2e/detection_response/rule_management/!(prebuilt_rules)/**/*.cy.ts'", + "cypress:run:qa:serverless:rule_management:prebuilt_rules": "yarn cypress:qa:serverless --spec './cypress/e2e/detection_response/rule_management/prebuilt_rules/**/*.cy.ts'" } } \ No newline at end of file diff --git a/x-pack/test/security_solution_cypress/serverless_config.ts b/x-pack/test/security_solution_cypress/serverless_config.ts index f302617f0e74..d0ee1613f6e4 100644 --- a/x-pack/test/security_solution_cypress/serverless_config.ts +++ b/x-pack/test/security_solution_cypress/serverless_config.ts @@ -34,9 +34,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { { product_line: 'endpoint', product_tier: 'complete' }, { product_line: 'cloud', product_tier: 'complete' }, ])}`, - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'disableTimelineSaveTour', - ])}`, ], }, testRunner: SecuritySolutionConfigurableCypressTestRunner, diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_permissions.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_permissions.ts index 061e8936bf24..3c31e714ae10 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_permissions.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_permissions.ts @@ -17,7 +17,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const endpointTestResources = getService('endpointTestResources'); - describe('Endpoint permissions:', function () { + // FLAKY: https://github.com/elastic/kibana/issues/171649 + // FLAKY: https://github.com/elastic/kibana/issues/171650 + describe.skip('Endpoint permissions:', function () { targetTags(this, ['@ess']); let indexedData: IndexedHostsAndAlertsResponse; diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts index 90729abd4e25..bcc3177846d3 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts @@ -82,8 +82,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); }; - // FLAKY: https://github.com/elastic/kibana/issues/170435 - describe.skip('Response Actions Responder', function () { + describe('Response Actions Responder', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; @@ -197,8 +196,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.clickWhenNotDisabled('endpointResponseActions-action-item'); await testSubjects.existOrFail('consolePageOverlay'); - await performResponderSanityChecks(); + // close tour popup + if (await testSubjects.exists('timeline-save-tour-close-button')) { + await testSubjects.click('timeline-save-tour-close-button'); + } + await performResponderSanityChecks(); await pageObjects.timeline.closeTimeline(); }); }); diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts index 9fcc87ceffa8..45dbff31170f 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts @@ -52,8 +52,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true'); }; + // Several flaky tests from this file in serverless, hence @skipInServerless + // - https://github.com/elastic/kibana/issues?q=is%3Aissue+is%3Aopen+X-pack+endpoint+integrations++artifact+entries+list + // https://github.com/elastic/kibana/issues/171475 + // https://github.com/elastic/kibana/issues/171476 + // https://github.com/elastic/kibana/issues/171477 + // https://github.com/elastic/kibana/issues/171478 + // https://github.com/elastic/kibana/issues/171487 + // https://github.com/elastic/kibana/issues/171488 + // https://github.com/elastic/kibana/issues/171489 + // https://github.com/elastic/kibana/issues/171491 + // https://github.com/elastic/kibana/issues/171492 describe('For each artifact list under management', function () { - targetTags(this, ['@ess', '@serverless']); + targetTags(this, ['@ess', '@serverless', '@skipInServerless']); this.timeout(60_000 * 5); let indexedData: IndexedHostsAndAlertsResponse; @@ -235,7 +246,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; for (const testData of getArtifactsListTestsData()) { - describe(`When on the ${testData.title} entries list`, function () { + // FLAKY: https://github.com/elastic/kibana/issues/171489 + // FLAKY: https://github.com/elastic/kibana/issues/171475 + describe.skip(`When on the ${testData.title} entries list`, function () { beforeEach(async () => { policyInfo = await policyTestResources.createPolicy(); await removeAllArtifacts(); @@ -321,7 +334,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); } - describe('Should check artifacts are correctly generated when multiple entries', function () { + // FLAKY: https://github.com/elastic/kibana/issues/171476 + describe.skip('Should check artifacts are correctly generated when multiple entries', function () { let firstPolicy: PolicyTestResourceInfo; let secondPolicy: PolicyTestResourceInfo; diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts index b48c64b5e9dd..a2b1feaabd7c 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts @@ -28,7 +28,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const endpointTestResources = getService('endpointTestResources'); const retry = getService('retry'); - describe('When on the Endpoint Policy Details Page', function () { + // FLAKY: https://github.com/elastic/kibana/issues/171653 + // FLAKY: https://github.com/elastic/kibana/issues/171654 + describe.skip('When on the Endpoint Policy Details Page', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts index e00dde08d58f..1d48a415b157 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/trusted_apps_list.ts @@ -16,7 +16,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const endpointTestResources = getService('endpointTestResources'); - describe('When on the Trusted Apps list', function () { + // FLAKY: https://github.com/elastic/kibana/issues/171481 + describe.skip('When on the Trusted Apps list', function () { targetTags(this, ['@ess', '@serverless']); let indexedData: IndexedHostsAndAlertsResponse; @@ -33,7 +34,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.missingOrFail('header-page-title'); }); - it('should be able to add a new trusted app and remove it', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/171481 + it.skip('should be able to add a new trusted app and remove it', async () => { const SHA256 = 'A4370C0CF81686C0B696FA6261c9d3e0d810ae704ab8301839dffd5d5112f476'; // Add it diff --git a/x-pack/test/security_solution_endpoint/config.base.ts b/x-pack/test/security_solution_endpoint/config.base.ts index d75458a4c581..e3be9a2a6934 100644 --- a/x-pack/test/security_solution_endpoint/config.base.ts +++ b/x-pack/test/security_solution_endpoint/config.base.ts @@ -90,10 +90,6 @@ export const generateConfig = async ({ `--xpack.fleet.packages.0.version=latest`, // this will be removed in 8.7 when the file upload feature is released `--xpack.fleet.enableExperimental.0=diagnosticFileUploadEnabled`, - // disable a tour that prevents tests from passing - `--xpack.securitySolution.enableExperimental=${JSON.stringify([ - 'disableTimelineSaveTour', - ])}`, ...kbnServerArgs, ], }, diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts index 7434f46ca35b..5a13045af0ba 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_authz.ts @@ -10,10 +10,11 @@ import { ACTION_DETAILS_ROUTE, ACTION_STATUS_ROUTE, AGENT_POLICY_SUMMARY_ROUTE, - BASE_POLICY_RESPONSE_ROUTE, BASE_ENDPOINT_ACTION_ROUTE, - GET_PROCESSES_ROUTE, + BASE_POLICY_RESPONSE_ROUTE, + EXECUTE_ROUTE, GET_FILE_ROUTE, + GET_PROCESSES_ROUTE, HOST_METADATA_GET_ROUTE, HOST_METADATA_LIST_ROUTE, ISOLATE_HOST_ROUTE_V2, @@ -21,7 +22,6 @@ import { METADATA_TRANSFORMS_STATUS_ROUTE, SUSPEND_PROCESS_ROUTE, UNISOLATE_HOST_ROUTE_V2, - EXECUTE_ROUTE, } from '@kbn/security-solution-plugin/common/endpoint/constants'; import { IndexedHostsAndAlertsResponse } from '@kbn/security-solution-plugin/common/endpoint/index_data'; import { targetTags } from '../../security_solution_endpoint/target_tags'; diff --git a/x-pack/test/security_solution_ftr/page_objects/timeline/index.ts b/x-pack/test/security_solution_ftr/page_objects/timeline/index.ts index b6c41a813b07..e7f35e31702c 100644 --- a/x-pack/test/security_solution_ftr/page_objects/timeline/index.ts +++ b/x-pack/test/security_solution_ftr/page_objects/timeline/index.ts @@ -15,11 +15,9 @@ const TIMELINE_MODAL_PAGE_TEST_SUBJ = 'timeline'; const TIMELINE_TAB_QUERY_TEST_SUBJ = 'timeline-tab-content-query'; const TIMELINE_CSS_SELECTOR = Object.freeze({ - /** The Plus icon to add a new timeline located in the bottom timeline sticky bar */ - buttonBarAddButton: `${testSubjSelector( + bottomBarTimelineTitle: `${testSubjSelector( TIMELINE_BOTTOM_BAR_CONTAINER_TEST_SUBJ - )} ${testSubjSelector('settings-plus-in-circle')}`, - + )} ${testSubjSelector('timeline-title')}`, /** The refresh button on the timeline view (top of view, next to the date selector) */ refreshButton: `${testSubjSelector(TIMELINE_TAB_QUERY_TEST_SUBJ)} ${testSubjSelector( 'superDatePickerApplyTimeButton' @@ -45,16 +43,15 @@ export class TimelinePageObject extends FtrService { await this.testSubjects.existOrFail(TIMELINE_BOTTOM_BAR_CONTAINER_TEST_SUBJ); } - async showOpenTimelinePopupFromBottomBar(): Promise { + async openTimelineFromBottomBar() { await this.ensureTimelineAccessible(); await this.testSubjects.findService.clickByCssSelector( - TIMELINE_CSS_SELECTOR.buttonBarAddButton + TIMELINE_CSS_SELECTOR.bottomBarTimelineTitle ); - await this.testSubjects.existOrFail('timeline-addPopupPanel'); } async openTimelineById(id: string): Promise { - await this.showOpenTimelinePopupFromBottomBar(); + await this.openTimelineFromBottomBar(); await this.testSubjects.click('open-timeline-button'); await this.testSubjects.findService.clickByCssSelector( `${testSubjSelector('open-timeline-modal')} ${testSubjSelector(`timeline-title-${id}`)}` diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 3d9c0dfd47d9..0c763cbf20c5 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -67,7 +67,6 @@ "@kbn/ftr-common-functional-services", "@kbn/securitysolution-io-ts-list-types", "@kbn/securitysolution-list-constants", - "@kbn/securitysolution-es-utils", "@kbn/expect", "@kbn/dev-cli-errors", "@kbn/ci-stats-reporter", @@ -86,7 +85,6 @@ "@kbn/data-views-plugin", "@kbn/datemath", "@kbn/safer-lodash-set", - "@kbn/securitysolution-rules", "@kbn/es-archiver", "@kbn/config-schema", "@kbn/kubernetes-security-plugin", @@ -146,6 +144,7 @@ "@kbn/coloring", "@kbn/es", "@kbn/metrics-data-access-plugin", + "@kbn/dataset-quality-plugin", "@kbn/reporting-export-types-csv-common", "@kbn/reporting-export-types-pdf-common", "@kbn/reporting-export-types-png-common", diff --git a/x-pack/test/upgrade/apps/dashboard/dashboard_smoke_tests.ts b/x-pack/test/upgrade/apps/dashboard/dashboard_smoke_tests.ts index 105620f90d6b..2d54d3ba0a52 100644 --- a/x-pack/test/upgrade/apps/dashboard/dashboard_smoke_tests.ts +++ b/x-pack/test/upgrade/apps/dashboard/dashboard_smoke_tests.ts @@ -14,6 +14,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const log = getService('log'); const renderable = getService('renderable'); const dashboardExpect = getService('dashboardExpect'); + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['common', 'header', 'home', 'dashboard', 'timePicker']); const browser = getService('browser'); @@ -40,8 +41,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); dashboardTests.forEach(({ name, numPanels }) => { it('should launch sample ' + name + ' data set dashboard', async () => { + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': `{ "from": "now-5y", "to": "now"}`, + }); await PageObjects.home.launchSampleDashboard(name); - await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); const panelCount = await PageObjects.dashboard.getPanelCount(); @@ -49,9 +52,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); it('should render visualizations', async () => { + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': `{ "from": "now-5y", "to": "now"}`, + }); await PageObjects.home.launchSampleDashboard('flights'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); await renderable.waitForRender(); log.debug('Checking saved searches rendered'); await dashboardExpect.savedSearchRowCount(49); diff --git a/x-pack/test_serverless/api_integration/services/saml_tools.ts b/x-pack/test_serverless/api_integration/services/saml_tools.ts index 4756109fc667..bd5cd03a7edb 100644 --- a/x-pack/test_serverless/api_integration/services/saml_tools.ts +++ b/x-pack/test_serverless/api_integration/services/saml_tools.ts @@ -6,33 +6,35 @@ */ import expect from '@kbn/expect'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { getSAMLResponse } from '@kbn/security-api-integration-helpers/saml/saml_tools'; -import { kbnTestConfig } from '@kbn/test'; - import { parse as parseCookie } from 'tough-cookie'; +import Url from 'url'; +import { createSAMLResponse } from '@kbn/mock-idp-plugin/common'; import { FtrProviderContext } from '../ftr_provider_context'; export function SamlToolsProvider({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); - const randomness = getService('randomness'); const svlCommonApi = getService('svlCommonApi'); - - function createSAMLResponse(options = {}) { - return getSAMLResponse({ - destination: `http://localhost:${kbnTestConfig.getPort()}/api/security/saml/callback`, - sessionIndex: String(randomness.naturalNumber()), - ...options, - }); - } + const config = getService('config'); return { async login(username: string) { + const kibanaUrl = Url.format({ + protocol: config.get('servers.kibana.protocol'), + hostname: config.get('servers.kibana.hostname'), + port: config.get('servers.kibana.port'), + pathname: '/api/security/saml/callback', + }); const samlAuthenticationResponse = await supertestWithoutAuth .post('/api/security/saml/callback') .set(svlCommonApi.getCommonRequestHeader()) - .send({ SAMLResponse: await createSAMLResponse({ username }) }); + .send({ + SAMLResponse: await createSAMLResponse({ + username, + roles: [], + kibanaUrl, + }), + }); expect(samlAuthenticationResponse.status).to.equal(302); expect(samlAuthenticationResponse.header.location).to.equal('/'); const sessionCookie = parseCookie(samlAuthenticationResponse.header['set-cookie'][0])!; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/core/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/core/index.ts index aa847e0c0ece..d48a40baa22f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/core/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/core/index.ts @@ -14,5 +14,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./compression')); loadTestFile(require.resolve('./translations')); loadTestFile(require.resolve('./capabilities')); + loadTestFile(require.resolve('./ui_settings')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/core/ui_settings.ts b/x-pack/test_serverless/api_integration/test_suites/common/core/ui_settings.ts new file mode 100644 index 000000000000..028b0ab69b43 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/core/ui_settings.ts @@ -0,0 +1,189 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +// To test setting validations we are using the existing 'defaultColumns' setting that is available in all serverless projects +// (See list of common serverless settings in /packages/serverless/settings/common/index.ts) +// The 'defaultColumns' setting is of type array of strings +const DEFAULT_COLUMNS_SETTING = 'defaultColumns'; + +// We will also create a test setting +const TEST_SETTING = 'testSetting'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const svlCommonApi = getService('svlCommonApi'); + describe('ui settings service', () => { + before(async () => { + // Creating a test setting + await supertest + .post(`/internal/kibana/settings/${TEST_SETTING}`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: 100 }) + .expect(200); + }); + + // We don't test the public routes as they are not available in serverless + describe('internal routes', () => { + describe('get', () => { + it('returns list of settings', async () => { + const { body } = await supertest + .get('/internal/kibana/settings') + .set(svlCommonApi.getInternalRequestHeader()) + .expect(200); + + // The returned list of settings should contain the created test setting + expect(body).to.have.property('settings'); + expect(body.settings).to.have.property(TEST_SETTING); + }); + }); + + describe('set', () => { + it('validates value', async () => { + const { body } = await supertest + .post(`/internal/kibana/settings/${DEFAULT_COLUMNS_SETTING}`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: 100 }) + .expect(400); + + expect(body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + '[validation [defaultColumns]]: expected value of type [array] but got [number]', + }); + }); + + it('sets value of a setting', async () => { + await supertest + .post(`/internal/kibana/settings/${TEST_SETTING}`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: 999 }) + .expect(200); + + // Verify that the setting has a new value + const { body } = await supertest + .get('/internal/kibana/settings') + .set(svlCommonApi.getInternalRequestHeader()) + .expect(200); + + // The returned list of settings should contain the created test setting + expect(body.settings[TEST_SETTING].userValue).to.equal(999); + }); + }); + + describe('set many', () => { + it('validates value', async () => { + const { body } = await supertest + .post('/internal/kibana/settings') + .set(svlCommonApi.getInternalRequestHeader()) + .send({ changes: { [TEST_SETTING]: 100, [DEFAULT_COLUMNS_SETTING]: 100 } }) + .expect(400); + + expect(body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + '[validation [defaultColumns]]: expected value of type [array] but got [number]', + }); + }); + + it('sets values of settings', async () => { + await supertest + .post(`/internal/kibana/settings`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ changes: { [TEST_SETTING]: 500 } }) + .expect(200); + + // Verify that the setting has a new value + const { body } = await supertest + .get('/internal/kibana/settings') + .set(svlCommonApi.getInternalRequestHeader()) + .expect(200); + + // The returned list of settings should contain the created test setting + expect(body.settings[TEST_SETTING].userValue).to.equal(500); + }); + }); + + describe('validate', () => { + it('returns correct validation error message for invalid value', async () => { + const { body } = await supertest + .post(`/internal/kibana/settings/${DEFAULT_COLUMNS_SETTING}/validate`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: 100 }) + .expect(200); + + expect(body).to.eql({ + valid: false, + errorMessage: 'expected value of type [array] but got [number]', + }); + }); + + it('returns no validation error message for valid value', async () => { + const { body } = await supertest + .post(`/internal/kibana/settings/${DEFAULT_COLUMNS_SETTING}/validate`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: ['test'] }) + .expect(200); + + expect(body).to.eql({ + valid: true, + }); + }); + + it('returns a 404 for non-existing key', async () => { + const { body } = await supertest + .post(`/internal/kibana/settings/nonExisting/validate`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: ['test'] }) + .expect(404); + + expect(body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Setting with a key [nonExisting] does not exist.', + }); + }); + + it('returns a 400 for a null value', async () => { + const { body } = await supertest + .post(`/internal/kibana/settings/${DEFAULT_COLUMNS_SETTING}/validate`) + .set(svlCommonApi.getInternalRequestHeader()) + .send({ value: null }) + .expect(400); + + expect(body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: 'No value was specified.', + }); + }); + }); + + describe('delete', () => { + it('deletes setting', async () => { + await supertest + .delete(`/internal/kibana/settings/${TEST_SETTING}`) + .set(svlCommonApi.getInternalRequestHeader()) + .expect(200); + + // Verify that the setting is not returned in the Get response anymore + const { body } = await supertest + .get('/internal/kibana/settings') + .set(svlCommonApi.getInternalRequestHeader()) + .expect(200); + + // The returned list of settings should contain the created test setting + expect(body.settings).to.not.have.property(TEST_SETTING); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/grok_debugger.ts b/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/grok_debugger.ts new file mode 100644 index 000000000000..dd9176fb74fe --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/grok_debugger.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const API_BASE_PATH = '/api/grokdebugger'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const svlCommonApi = getService('svlCommonApi'); + + describe('Grok Debugger Routes', function () { + describe('Simulate', () => { + it('should simulate a valid pattern', async () => { + const rawEvent = '55.3.244.1 GET /index.html 15824 0.043'; + const pattern = + '%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}'; + const requestBody = { rawEvent, pattern }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + const expectedStructuredEvent = { + duration: '0.043', + request: '/index.html', + method: 'GET', + bytes: '15824', + client: '55.3.244.1', + }; + + expect(body.structuredEvent).to.eql(expectedStructuredEvent); + expect(body.error).to.be.empty(); + }); + + it('should return error response for invalid pattern', async () => { + const rawEvent = '55.3.244.1 GET /index.html 15824 0.043'; + const invalidPattern = 'test'; + const requestBody = { rawEvent, pattern: invalidPattern }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + expect(body.error).to.eql('Provided Grok patterns do not match data in the input'); + expect(body.structuredEvent).to.be.empty(); + }); + + it('should simulate with a valid custom pattern', async () => { + const rawEvent = + 'Jan 1 06:25:43 mailserver14 postfix/cleanup[21403]: BEF25A72965: message-id=<20130101142543.5828399CCAF@mailserver14.example.com>'; + const pattern = '%{SYSLOGBASE} %{POSTFIX_QUEUEID:queue_id}: %{MSG:syslog_message}'; + const customPatterns = { + MSG: 'message-id=<%{GREEDYDATA}>', + POSTFIX_QUEUEID: '[0-9A-F]{10,11}', + }; + const requestBody = { rawEvent, pattern, customPatterns }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(requestBody) + .expect(200); + + const expectedStructuredEvent = { + pid: '21403', + program: 'postfix/cleanup', + logsource: 'mailserver14', + syslog_message: 'message-id=<20130101142543.5828399CCAF@mailserver14.example.com>', + queue_id: 'BEF25A72965', + timestamp: 'Jan 1 06:25:43', + }; + + expect(body.structuredEvent).to.eql(expectedStructuredEvent); + expect(body.error).to.be.empty(); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/index.ts new file mode 100644 index 000000000000..25f6258b394d --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/grok_debugger/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Grok Debugger API', function () { + this.tags(['esGate']); + + loadTestFile(require.resolve('./grok_debugger')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/cluster_nodes.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/cluster_nodes.ts new file mode 100644 index 000000000000..60110dd5af3f --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/cluster_nodes.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const indexManagementService = getService('indexManagement'); + + describe('nodes', () => { + let getNodesPlugins: typeof indexManagementService['clusterNodes']['api']['getNodesPlugins']; + + before(async () => { + ({ + clusterNodes: { + api: { getNodesPlugins }, + }, + } = indexManagementService); + }); + + it('should fetch the nodes plugins', async () => { + const { body } = await getNodesPlugins().expect(200); + + expect(Array.isArray(body)).to.be(true); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/datastreams.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/datastreams.ts new file mode 100644 index 000000000000..adc84ffecb63 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/datastreams.ts @@ -0,0 +1,325 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { DataStream } from '@kbn/index-management-plugin/common'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const API_BASE_PATH = '/api/index_management'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const indexManagementService = getService('indexManagement'); + let helpers: typeof indexManagementService['datastreams']['helpers']; + let createDataStream: typeof helpers['createDataStream']; + let deleteDataStream: typeof helpers['deleteDataStream']; + let deleteComposableIndexTemplate: typeof helpers['deleteComposableIndexTemplate']; + let updateIndexTemplateMappings: typeof helpers['updateIndexTemplateMappings']; + let getMapping: typeof helpers['getMapping']; + let getDatastream: typeof helpers['getDatastream']; + + describe('Data streams', function () { + before(async () => { + ({ + datastreams: { helpers }, + } = indexManagementService); + ({ + createDataStream, + deleteDataStream, + deleteComposableIndexTemplate, + updateIndexTemplateMappings, + getMapping, + getDatastream, + } = helpers); + }); + describe('Get', () => { + const testDataStreamName = 'test-data-stream'; + + before(async () => await createDataStream(testDataStreamName)); + after(async () => await deleteDataStream(testDataStreamName)); + + it('returns an array of data streams', async () => { + const { body: dataStreams } = await supertest + .get(`${API_BASE_PATH}/data_streams`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + expect(dataStreams).to.be.an('array'); + + // returned array can contain automatically created data streams + const testDataStream = dataStreams.find( + (dataStream: DataStream) => dataStream.name === testDataStreamName + ); + + expect(testDataStream).to.be.ok(); + + // ES determines these values so we'll just echo them back. + const { name: indexName, uuid } = testDataStream!.indices[0]; + + expect(testDataStream).to.eql({ + name: testDataStreamName, + lifecycle: { + enabled: true, + }, + privileges: { + delete_index: true, + manage_data_stream_lifecycle: true, + }, + timeStampField: { name: '@timestamp' }, + indices: [ + { + name: indexName, + uuid, + preferILM: true, + managedBy: 'Data stream lifecycle', + }, + ], + nextGenerationManagedBy: 'Data stream lifecycle', + generation: 1, + health: 'green', + indexTemplateName: testDataStreamName, + hidden: false, + }); + }); + + it('includes stats when provided the includeStats query parameter', async () => { + const { body: dataStreams } = await supertest + .get(`${API_BASE_PATH}/data_streams?includeStats=true`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + expect(dataStreams).to.be.an('array'); + + // returned array can contain automatically created data streams + const testDataStream = dataStreams.find( + (dataStream: DataStream) => dataStream.name === testDataStreamName + ); + + expect(testDataStream).to.be.ok(); + + // ES determines these values so we'll just echo them back. + const { name: indexName, uuid } = testDataStream!.indices[0]; + const { storageSize, storageSizeBytes, ...dataStreamWithoutStorageSize } = testDataStream!; + + expect(dataStreamWithoutStorageSize).to.eql({ + name: testDataStreamName, + privileges: { + delete_index: true, + manage_data_stream_lifecycle: true, + }, + timeStampField: { name: '@timestamp' }, + indices: [ + { + name: indexName, + managedBy: 'Data stream lifecycle', + preferILM: true, + uuid, + }, + ], + generation: 1, + health: 'green', + indexTemplateName: testDataStreamName, + nextGenerationManagedBy: 'Data stream lifecycle', + maxTimeStamp: 0, + hidden: false, + lifecycle: { + enabled: true, + }, + }); + }); + + it('returns a single data stream by ID', async () => { + const { body: dataStream } = await supertest + .get(`${API_BASE_PATH}/data_streams/${testDataStreamName}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + // ES determines these values so we'll just echo them back. + const { name: indexName, uuid } = dataStream.indices[0]; + const { storageSize, storageSizeBytes, ...dataStreamWithoutStorageSize } = dataStream; + + expect(dataStreamWithoutStorageSize).to.eql({ + name: testDataStreamName, + privileges: { + delete_index: true, + manage_data_stream_lifecycle: true, + }, + timeStampField: { name: '@timestamp' }, + indices: [ + { + name: indexName, + managedBy: 'Data stream lifecycle', + preferILM: true, + uuid, + }, + ], + generation: 1, + health: 'green', + indexTemplateName: testDataStreamName, + nextGenerationManagedBy: 'Data stream lifecycle', + maxTimeStamp: 0, + hidden: false, + lifecycle: { + enabled: true, + }, + }); + }); + }); + + describe('Update', () => { + const testDataStreamName = 'test-data-stream'; + + before(async () => await createDataStream(testDataStreamName)); + after(async () => await deleteDataStream(testDataStreamName)); + + it('updates the data retention of a DS', async () => { + const { body } = await supertest + .put(`${API_BASE_PATH}/data_streams/${testDataStreamName}/data_retention`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({ + dataRetention: '7d', + }) + .expect(200); + + expect(body).to.eql({ success: true }); + }); + + it('sets data retention to infinite', async () => { + const { body } = await supertest + .put(`${API_BASE_PATH}/data_streams/${testDataStreamName}/data_retention`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({}) + .expect(200); + + expect(body).to.eql({ success: true }); + }); + + it('can disable lifecycle for a given policy', async () => { + const { body } = await supertest + .put(`${API_BASE_PATH}/data_streams/${testDataStreamName}/data_retention`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({ enabled: false }) + .expect(200); + + expect(body).to.eql({ success: true }); + + const datastream = await getDatastream(testDataStreamName); + expect(datastream.lifecycle).to.be(undefined); + }); + }); + + describe('Delete', () => { + const testDataStreamName1 = 'test-data-stream1'; + const testDataStreamName2 = 'test-data-stream2'; + + before(async () => { + await Promise.all([ + createDataStream(testDataStreamName1), + createDataStream(testDataStreamName2), + ]); + }); + + after(async () => { + // The Delete API only deletes the data streams, so we still need to manually delete their + // related index patterns to clean up. + await Promise.all([ + deleteComposableIndexTemplate(testDataStreamName1), + deleteComposableIndexTemplate(testDataStreamName2), + ]); + }); + + it('deletes multiple data streams', async () => { + await supertest + .post(`${API_BASE_PATH}/delete_data_streams`) + .set('x-elastic-internal-origin', 'xxx') + .set('kbn-xsrf', 'xxx') + .send({ + dataStreams: [testDataStreamName1, testDataStreamName2], + }) + .expect(200); + + await supertest + .get(`${API_BASE_PATH}/data_streams/${testDataStreamName1}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(404); + + await supertest + .get(`${API_BASE_PATH}/data_streams/${testDataStreamName2}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(404); + }); + }); + + describe('Mappings from template', () => { + const testDataStreamName1 = 'test-data-stream-mappings-1'; + + before(async () => { + await createDataStream(testDataStreamName1); + }); + + after(async () => { + await deleteDataStream(testDataStreamName1); + }); + + it('Apply mapping from index template', async () => { + const beforeMapping = await getMapping(testDataStreamName1); + expect(beforeMapping.properties).eql({ + '@timestamp': { type: 'date' }, + }); + await updateIndexTemplateMappings(testDataStreamName1, { + properties: { + test: { type: 'integer' }, + }, + }); + await supertest + .post(`${API_BASE_PATH}/data_streams/${testDataStreamName1}/mappings_from_template`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + const afterMapping = await getMapping(testDataStreamName1); + expect(afterMapping.properties).eql({ + '@timestamp': { type: 'date' }, + test: { type: 'integer' }, + }); + }); + }); + + describe('Rollover', () => { + const testDataStreamName1 = 'test-data-stream-rollover-1'; + + before(async () => { + await createDataStream(testDataStreamName1); + }); + + after(async () => { + await deleteDataStream(testDataStreamName1); + }); + + it('Rollover datastreams', async () => { + await supertest + .post(`${API_BASE_PATH}/data_streams/${testDataStreamName1}/rollover`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + const datastream = await getDatastream(testDataStreamName1); + + expect(datastream.generation).equal(2); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index.ts index 7dff563bf43b..abed984a8624 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index_management/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index.ts @@ -14,5 +14,10 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./index_templates')); loadTestFile(require.resolve('./indices')); loadTestFile(require.resolve('./create_enrich_policies')); + loadTestFile(require.resolve('./index_component_templates')); + loadTestFile(require.resolve('./cluster_nodes')); + loadTestFile(require.resolve('./datastreams')); + loadTestFile(require.resolve('./mappings')); + loadTestFile(require.resolve('./settings')); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_component_templates.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_component_templates.ts new file mode 100644 index 000000000000..9781a34fe080 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_component_templates.ts @@ -0,0 +1,437 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const CACHE_TEMPLATES = true; + +export default function ({ getService }: FtrProviderContext) { + const log = getService('log'); + const indexManagementService = getService('indexManagement'); + + describe('component templates', () => { + // Api methods + let getAllComponentTemplates: typeof indexManagementService['componentTemplates']['api']['getAllComponentTemplates']; + let getOneComponentTemplate: typeof indexManagementService['componentTemplates']['api']['getOneComponentTemplate']; + let updateComponentTemplate: typeof indexManagementService['componentTemplates']['api']['updateComponentTemplate']; + let deleteComponentTemplate: typeof indexManagementService['componentTemplates']['api']['deleteComponentTemplate']; + let getComponentTemplateDatastreams: typeof indexManagementService['componentTemplates']['api']['getComponentTemplateDatastreams']; + // Helpers + let addDatastream: typeof indexManagementService['componentTemplates']['helpers']['addDatastream']; + let addIndexTemplate: typeof indexManagementService['componentTemplates']['helpers']['addIndexTemplate']; + let addComponentTemplate: typeof indexManagementService['componentTemplates']['helpers']['addComponentTemplate']; + let cleanupDatastreams: typeof indexManagementService['componentTemplates']['helpers']['cleanupDatastreams']; + let cleanUpIndexTemplates: typeof indexManagementService['componentTemplates']['helpers']['cleanUpIndexTemplates']; + let cleanUpComponentTemplates: typeof indexManagementService['componentTemplates']['helpers']['cleanUpComponentTemplates']; + + before(async () => { + ({ + componentTemplates: { + api: { + getAllComponentTemplates, + getOneComponentTemplate, + updateComponentTemplate, + deleteComponentTemplate, + getComponentTemplateDatastreams, + }, + helpers: { + addDatastream, + addIndexTemplate, + addComponentTemplate, + cleanupDatastreams, + cleanUpIndexTemplates, + cleanUpComponentTemplates, + }, + }, + } = indexManagementService); + }); + + after(async () => { + await cleanUpIndexTemplates(); + await cleanUpComponentTemplates(); + await cleanupDatastreams(); + }); + + describe('Get', () => { + const COMPONENT_NAME = 'test_get_component_template'; + const COMPONENT = { + template: { + settings: { + index: { + number_of_shards: 1, + }, + }, + mappings: { + _source: { + enabled: false, + }, + properties: { + host_name: { + type: 'keyword', + }, + created_at: { + type: 'date', + format: 'EEE MMM dd HH:mm:ss Z yyyy', + }, + }, + }, + }, + }; + + // Create component template to verify GET requests + before(async () => { + try { + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); + } catch (err) { + log.debug('[Setup error] Error creating component template'); + throw err; + } + }); + + describe('all component templates', () => { + it('should return an array of component templates', async () => { + const { body: componentTemplates } = await getAllComponentTemplates().expect(200); + + const testComponentTemplate = componentTemplates.find( + ({ name }: { name: string }) => name === COMPONENT_NAME + ); + + expect(testComponentTemplate).to.eql({ + name: COMPONENT_NAME, + usedBy: [], + isManaged: false, + hasSettings: true, + hasMappings: true, + hasAliases: false, + }); + }); + }); + + describe('one component template', () => { + it('should return a single component template', async () => { + const { body } = await getOneComponentTemplate(COMPONENT_NAME).expect(200); + + expect(body).to.eql({ + name: COMPONENT_NAME, + ...COMPONENT, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }); + }); + }); + }); + + describe('Update', () => { + const COMPONENT_NAME = 'test_update_component_template'; + const COMPONENT = { + template: { + settings: { + index: { + number_of_shards: 1, + }, + }, + mappings: { + _source: { + enabled: false, + }, + properties: { + host_name: { + type: 'keyword', + }, + created_at: { + type: 'date', + format: 'EEE MMM dd HH:mm:ss Z yyyy', + }, + }, + }, + }, + }; + + before(async () => { + // Create component template that can be used to test PUT request + try { + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); + } catch (err) { + log.debug('[Setup error] Error creating component template'); + throw err; + } + }); + + it('should allow an existing component template to be updated', async () => { + const { body } = await updateComponentTemplate(COMPONENT_NAME, { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(200); + + expect(body).to.eql({ + acknowledged: true, + }); + }); + + it('should not allow a non-existing component template to be updated', async () => { + const { body } = await updateComponentTemplate('component_does_not_exist', { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(404); + + expect(body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'component template matching [component_does_not_exist] not found', + attributes: { + error: { + reason: 'component template matching [component_does_not_exist] not found', + root_cause: [ + { + reason: 'component template matching [component_does_not_exist] not found', + type: 'resource_not_found_exception', + }, + ], + type: 'resource_not_found_exception', + }, + }, + }); + }); + }); + + describe('Update', () => { + const COMPONENT_NAME = 'test_update_component_template'; + const COMPONENT = { + template: { + settings: { + index: { + number_of_shards: 1, + }, + }, + mappings: { + _source: { + enabled: false, + }, + properties: { + host_name: { + type: 'keyword', + }, + created_at: { + type: 'date', + format: 'EEE MMM dd HH:mm:ss Z yyyy', + }, + }, + }, + }, + }; + + before(async () => { + // Create component template that can be used to test PUT request + try { + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); + } catch (err) { + log.debug('[Setup error] Error creating component template'); + throw err; + } + }); + + it('should allow an existing component template to be updated', async () => { + const { body } = await updateComponentTemplate(COMPONENT_NAME, { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(200); + + expect(body).to.eql({ + acknowledged: true, + }); + }); + + it('should not allow a non-existing component template to be updated', async () => { + const { body } = await updateComponentTemplate('component_does_not_exist', { + ...COMPONENT, + version: 1, + _kbnMeta: { + usedBy: [], + isManaged: false, + }, + }).expect(404); + + expect(body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'component template matching [component_does_not_exist] not found', + attributes: { + error: { + reason: 'component template matching [component_does_not_exist] not found', + root_cause: [ + { + reason: 'component template matching [component_does_not_exist] not found', + type: 'resource_not_found_exception', + }, + ], + type: 'resource_not_found_exception', + }, + }, + }); + }); + }); + + describe('Delete', () => { + const COMPONENT = { + template: { + settings: { + index: { + number_of_shards: 1, + }, + }, + }, + }; + + const componentTemplateA = { body: COMPONENT, name: 'test_delete_component_template_a' }; + const componentTemplateB = { body: COMPONENT, name: 'test_delete_component_template_b' }; + const componentTemplateC = { body: COMPONENT, name: 'test_delete_component_template_c' }; + const componentTemplateD = { body: COMPONENT, name: 'test_delete_component_template_d' }; + + before(async () => { + // Create several component templates that can be used to test deletion + await Promise.all( + [componentTemplateA, componentTemplateB, componentTemplateC, componentTemplateD].map( + (template) => addComponentTemplate(template, !CACHE_TEMPLATES) + ) + ).catch((err) => { + log.debug(`[Setup error] Error creating component templates: ${err.message}`); + throw err; + }); + }); + + it('should delete a component template', async () => { + const { name } = componentTemplateA; + const { body } = await deleteComponentTemplate(name).expect(200); + + expect(body).to.eql({ + itemsDeleted: [name], + errors: [], + }); + }); + + it('should delete multiple component templates', async () => { + const { name: componentTemplate1Name } = componentTemplateB; + const { name: componentTemplate2Name } = componentTemplateC; + + const { + body: { itemsDeleted, errors }, + } = await deleteComponentTemplate( + `${componentTemplate1Name},${componentTemplate2Name}` + ).expect(200); + + expect(errors).to.eql([]); + + // The itemsDeleted array order isn't guaranteed, so we assert against each name instead + [componentTemplate1Name, componentTemplate2Name].forEach((componentName) => { + expect(itemsDeleted.includes(componentName)).to.be(true); + }); + }); + + it('should return an error for any component templates not sucessfully deleted', async () => { + const COMPONENT_DOES_NOT_EXIST = 'component_does_not_exist'; + const { name: componentTemplateName } = componentTemplateD; + + const { body } = await deleteComponentTemplate( + `${componentTemplateName},${COMPONENT_DOES_NOT_EXIST}` + ).expect(200); + expect(body.itemsDeleted).to.eql([componentTemplateName]); + expect(body.errors[0].name).to.eql(COMPONENT_DOES_NOT_EXIST); + + expect(body.errors[0].error.payload.attributes.error).to.eql({ + root_cause: [ + { + type: 'resource_not_found_exception', + reason: 'component_does_not_exist', + }, + ], + type: 'resource_not_found_exception', + reason: 'component_does_not_exist', + }); + }); + }); + + describe('Get datastreams', () => { + const COMPONENT_NAME = 'test_get_component_template_datastreams'; + const COMPONENT = { + template: { + settings: { + index: { + number_of_shards: 1, + }, + }, + mappings: { + _source: { + enabled: false, + }, + properties: { + host_name: { + type: 'keyword', + }, + created_at: { + type: 'date', + format: 'EEE MMM dd HH:mm:ss Z yyyy', + }, + }, + }, + }, + }; + const DATASTREAM_NAME = 'logs-test-component-template-default'; + const INDEX_PATTERN = 'logs-test-component-template-*'; + const TEMPLATE_NAME = 'test_get_component_template_datastreams'; + const TEMPLATE = { + index_patterns: INDEX_PATTERN, + composed_of: [COMPONENT_NAME], + }; + + // Create component template to verify GET requests + before(async () => { + try { + await addComponentTemplate({ body: COMPONENT, name: COMPONENT_NAME }, CACHE_TEMPLATES); + await addIndexTemplate({ body: TEMPLATE, name: TEMPLATE_NAME }, CACHE_TEMPLATES); + } catch (err) { + log.debug('[Setup error] Error creating component template'); + throw err; + } + }); + + describe('without datastreams', () => { + it('should return no datastreams', async () => { + const { body } = await getComponentTemplateDatastreams(COMPONENT_NAME).expect(200); + + expect(body).to.eql({ data_streams: [] }); + }); + }); + + describe('with datastreams', () => { + before(async () => { + await addDatastream(DATASTREAM_NAME, CACHE_TEMPLATES); + }); + it('should return datastreams', async () => { + const { body } = await getComponentTemplateDatastreams(COMPONENT_NAME).expect(200); + + expect(body).to.eql({ data_streams: ['logs-test-component-template-default'] }); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_templates.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_templates.ts index a4e082387ab4..0b94803bcd76 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_templates.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/index_templates.ts @@ -5,7 +5,7 @@ * 2.0. */ -import expect from 'expect'; +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; const API_BASE_PATH = '/api/index_management'; @@ -14,80 +14,266 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); const log = getService('log'); + const randomness = getService('randomness'); + const indexManagementService = getService('indexManagement'); + let getTemplatePayload: typeof indexManagementService['templates']['helpers']['getTemplatePayload']; + let catTemplate: typeof indexManagementService['templates']['helpers']['catTemplate']; + let getSerializedTemplate: typeof indexManagementService['templates']['helpers']['getSerializedTemplate']; + let createTemplate: typeof indexManagementService['templates']['api']['createTemplate']; + let updateTemplate: typeof indexManagementService['templates']['api']['updateTemplate']; + let deleteTemplates: typeof indexManagementService['templates']['api']['deleteTemplates']; + let simulateTemplate: typeof indexManagementService['templates']['api']['simulateTemplate']; + let getRandomString: () => string; describe('Index templates', function () { - const templateName = `template-${Math.random()}`; - const indexTemplate = { - name: templateName, - body: { - index_patterns: ['test*'], - }, - }; - before(async () => { - // Create a new index template to test against - try { - await es.indices.putIndexTemplate(indexTemplate); - } catch (err) { - log.debug('[Setup error] Error creating index template'); - throw err; - } + ({ + templates: { + helpers: { getTemplatePayload, catTemplate, getSerializedTemplate }, + api: { createTemplate, updateTemplate, deleteTemplates, simulateTemplate }, + }, + } = indexManagementService); + getRandomString = () => randomness.string({ casing: 'lower', alpha: true }); }); - after(async () => { - // Cleanup template created for testing purposes - try { - await es.indices.deleteIndexTemplate({ + describe('get', () => { + let templateName: string; + + before(async () => { + templateName = `template-${getRandomString()}`; + const indexTemplate = { name: templateName, + body: { + index_patterns: ['test*'], + }, + }; + // Create a new index template to test against + try { + await es.indices.putIndexTemplate(indexTemplate); + } catch (err) { + log.debug('[Setup error] Error creating index template'); + throw err; + } + }); + + after(async () => { + // Cleanup template created for testing purposes + try { + await es.indices.deleteIndexTemplate({ + name: templateName, + }); + } catch (err) { + log.debug('[Cleanup error] Error deleting index template'); + throw err; + } + }); + + describe('all', () => { + it('should list all the index templates with the expected parameters', async () => { + const { body: allTemplates } = await supertest + .get(`${API_BASE_PATH}/index_templates`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + // Legacy templates are not applicable on serverless + expect(allTemplates.legacyTemplates.length).to.eql(0); + + const indexTemplateFound = allTemplates.templates.find( + (template: { name: string }) => template.name === templateName + ); + + expect(indexTemplateFound).to.be.ok(); + + const expectedKeys = [ + 'name', + 'indexPatterns', + 'hasSettings', + 'hasAliases', + 'hasMappings', + '_kbnMeta', + 'composedOf', + ].sort(); + + expect(Object.keys(indexTemplateFound).sort()).to.eql(expectedKeys); + }); + }); + + describe('one', () => { + it('should return an index template with the expected parameters', async () => { + const { body } = await supertest + .get(`${API_BASE_PATH}/index_templates/${templateName}`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + const expectedKeys = [ + 'name', + 'indexPatterns', + 'template', + '_kbnMeta', + 'composedOf', + ].sort(); + + expect(body.name).to.eql(templateName); + expect(Object.keys(body).sort()).to.eql(expectedKeys); }); - } catch (err) { - log.debug('[Cleanup error] Error deleting index template'); - throw err; - } + }); + }); + + describe('create', () => { + it('should create an index template', async () => { + const payload = getTemplatePayload(`template-${getRandomString()}`, [getRandomString()]); + await createTemplate(payload).set('x-elastic-internal-origin', 'xxx').expect(200); + }); + + it('should throw a 409 conflict when trying to create 2 templates with the same name', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()]); + + await createTemplate(payload).set('x-elastic-internal-origin', 'xxx'); + + await createTemplate(payload).set('x-elastic-internal-origin', 'xxx').expect(409); + }); + + it('should validate the request payload', async () => { + const templateName = `template-${getRandomString()}`; + // need to cast as any to avoid errors after deleting index patterns + const payload = getTemplatePayload(templateName, [getRandomString()]) as any; + + delete payload.indexPatterns; // index patterns are required + + const { body } = await createTemplate(payload).set('x-elastic-internal-origin', 'xxx'); + expect(body.message).to.contain( + '[request body.indexPatterns]: expected value of type [array] ' + ); + }); + + it('should parse the ES error and return the cause', async () => { + const templateName = `template-create-parse-es-error`; + const payload = getTemplatePayload(templateName, ['create-parse-es-error']); + const runtime = { + myRuntimeField: { + type: 'boolean', + script: { + source: 'emit("hello with error', // error in script + }, + }, + }; + payload.template!.mappings = { ...payload.template!.mappings, runtime }; + const { body } = await createTemplate(payload) + .set('x-elastic-internal-origin', 'xxx') + .expect(400); + + expect(body.attributes).an('object'); + expect(body.attributes.error.reason).contain('template after composition is invalid'); + // one of the item of the cause array should point to our script + expect(body.attributes.causes.join(',')).contain('"hello with error'); + }); }); - describe('get all', () => { - it('should list all the index templates with the expected parameters', async () => { - const { body: allTemplates } = await supertest - .get(`${API_BASE_PATH}/index_templates`) - .set('kbn-xsrf', 'xxx') + describe('update', () => { + it('should update an index template', async () => { + const templateName = `template-${getRandomString()}`; + const indexTemplate = getTemplatePayload(templateName, [getRandomString()]); + + await createTemplate(indexTemplate).set('x-elastic-internal-origin', 'xxx').expect(200); + + let { body: catTemplateResponse } = await catTemplate(templateName); + + const { name, version } = indexTemplate; + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(version?.toString()); + + // Update template with new version + const updatedVersion = 2; + await updateTemplate({ ...indexTemplate, version: updatedVersion }, templateName) .set('x-elastic-internal-origin', 'xxx') .expect(200); - // Legacy templates are not applicable on serverless - expect(allTemplates.legacyTemplates.length).toEqual(0); + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect( + catTemplateResponse.find(({ name: catTemplateName }) => catTemplateName === name)?.version + ).to.equal(updatedVersion.toString()); + }); + + it('should parse the ES error and return the cause', async () => { + const templateName = `template-update-parse-es-error`; + const payload = getTemplatePayload(templateName, ['update-parse-es-error']); + const runtime = { + myRuntimeField: { + type: 'keyword', + script: { + source: 'emit("hello")', + }, + }, + }; + + // Add runtime field + payload.template!.mappings = { ...payload.template!.mappings, runtime }; - const indexTemplateFound = allTemplates.templates.find( - (template: { name: string }) => template.name === indexTemplate.name + await createTemplate(payload).set('x-elastic-internal-origin', 'xxx').expect(200); + + // Update template with an error in the runtime field script + payload.template!.mappings.runtime.myRuntimeField.script = 'emit("hello with error'; + const { body } = await updateTemplate(payload, templateName) + .set('x-elastic-internal-origin', 'xxx') + .expect(400); + + expect(body.attributes).an('object'); + // one of the item of the cause array should point to our script + expect(body.attributes.causes.join(',')).contain('"hello with error'); + }); + }); + + describe('delete', () => { + it('should delete an index template', async () => { + const templateName = `template-${getRandomString()}`; + const payload = getTemplatePayload(templateName, [getRandomString()]); + + const { status: createStatus, body: createBody } = await createTemplate(payload).set( + 'x-elastic-internal-origin', + 'xxx' ); + if (createStatus !== 200) { + throw new Error(`Error creating template: ${createStatus} ${createBody.message}`); + } - expect(indexTemplateFound).toBeTruthy(); + let { body: catTemplateResponse } = await catTemplate(templateName); - const expectedKeys = [ - 'name', - 'indexPatterns', - 'hasSettings', - 'hasAliases', - 'hasMappings', - '_kbnMeta', - ].sort(); + expect( + catTemplateResponse.find((template) => template.name === payload.name)?.name + ).to.equal(templateName); - expect(Object.keys(indexTemplateFound).sort()).toEqual(expectedKeys); + const { status: deleteStatus, body: deleteBody } = await deleteTemplates([ + { name: templateName }, + ]).set('x-elastic-internal-origin', 'xxx'); + if (deleteStatus !== 200) { + throw new Error(`Error deleting template: ${deleteBody.message}`); + } + + expect(deleteBody.errors).to.be.empty(); + expect(deleteBody.templatesDeleted[0]).to.equal(templateName); + + ({ body: catTemplateResponse } = await catTemplate(templateName)); + + expect(catTemplateResponse.find((template) => template.name === payload.name)).to.equal( + undefined + ); }); }); - describe('get one', () => { - it('should return an index template with the expected parameters', async () => { - const { body } = await supertest - .get(`${API_BASE_PATH}/index_templates/${templateName}`) - .set('kbn-xsrf', 'xxx') + describe('simulate', () => { + it('should simulate an index template', async () => { + const payload = getSerializedTemplate([getRandomString()]); + + const { body } = await simulateTemplate(payload) .set('x-elastic-internal-origin', 'xxx') .expect(200); - - const expectedKeys = ['name', 'indexPatterns', 'template', '_kbnMeta'].sort(); - - expect(body.name).toEqual(templateName); - expect(Object.keys(body).sort()).toEqual(expectedKeys); + expect(body.template).to.be.ok(); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts index 9c4fd7b19633..70de83c949cf 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts @@ -5,10 +5,9 @@ * 2.0. */ -import expect from 'expect'; +import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -const API_BASE_PATH = '/api/index_management'; const INTERNAL_API_BASE_PATH = '/internal/index_management'; const expectedKeys = ['aliases', 'hidden', 'isFrozen', 'primary', 'replica', 'name'].sort(); @@ -16,22 +15,27 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); const log = getService('log'); + const indexManagementService = getService('indexManagement'); describe('Indices', function () { - const indexName = `index-${Math.random()}`; + let indexName: string; + let reload: typeof indexManagementService['indices']['api']['reload']; + let list: typeof indexManagementService['indices']['api']['list']; + let deleteIndex: typeof indexManagementService['indices']['api']['deleteIndex']; + let createIndex: typeof indexManagementService['indices']['helpers']['createIndex']; + let deleteAllIndices: typeof indexManagementService['indices']['helpers']['deleteAllIndices']; + let catIndex: typeof indexManagementService['indices']['helpers']['catIndex']; before(async () => { - // Create a new index to test against - const indexExists = await es.indices.exists({ index: indexName }); - - // Index should not exist, but in the case that it already does, we bypass the create request - if (indexExists) { - return; - } - + ({ + indices: { + api: { reload, list, deleteIndex }, + helpers: { createIndex, deleteAllIndices, catIndex }, + }, + } = indexManagementService); log.debug(`Creating index: '${indexName}'`); try { - await es.indices.create({ index: indexName }); + indexName = await createIndex(); } catch (err) { log.debug('[Setup error] Error creating index'); throw err; @@ -41,28 +45,27 @@ export default function ({ getService }: FtrProviderContext) { after(async () => { // Cleanup index created for testing purposes try { - await es.indices.delete({ - index: indexName, - }); + await deleteAllIndices(); } catch (err) { log.debug('[Cleanup error] Error deleting index'); throw err; } }); - describe('get all', () => { - it('should list indices with the expected parameters', async () => { - const { body: indices } = await supertest - .get(`${API_BASE_PATH}/indices`) - .set('kbn-xsrf', 'xxx') - .set('x-elastic-internal-origin', 'xxx') - .expect(200); + describe('list', () => { + it('should list all the indices with the expected properties', async function () { + // Create an index that we can assert against + await createIndex('test_index'); - const indexFound = indices.find((index: { name: string }) => index.name === indexName); + // Verify indices request + const { body: indices } = await list().set('x-elastic-internal-origin', 'xxx').expect(200); - expect(indexFound).toBeTruthy(); + // Find the "test_index" created to verify expected keys + const indexCreated = indices.find((index: { name: string }) => index.name === 'test_index'); - expect(Object.keys(indexFound).sort()).toEqual(expectedKeys); + const sortedReceivedKeys = Object.keys(indexCreated).sort(); + + expect(sortedReceivedKeys).to.eql(expectedKeys); }); }); @@ -74,9 +77,9 @@ export default function ({ getService }: FtrProviderContext) { .set('x-elastic-internal-origin', 'xxx') .expect(200); - expect(index).toBeTruthy(); + expect(index).to.be.ok(); - expect(Object.keys(index).sort()).toEqual(expectedKeys); + expect(Object.keys(index).sort()).to.eql(expectedKeys); }); it('throws 404 for a non-existent index', async () => { @@ -118,9 +121,9 @@ export default function ({ getService }: FtrProviderContext) { .set('x-elastic-internal-origin', 'xxx') .expect(200); - expect(index).toBeTruthy(); + expect(index).to.be.ok(); - expect(Object.keys(index).sort()).toEqual(expectedKeys); + expect(Object.keys(index).sort()).to.eql(expectedKeys); }); it('fails to re-create the same index', async () => { @@ -134,5 +137,47 @@ export default function ({ getService }: FtrProviderContext) { .expect(400); }); }); + + describe('reload', function () { + it('should list all the indices with the expected properties', async function () { + // create an index to assert against, otherwise the test is flaky + await createIndex('reload-test-index'); + const { body } = await reload().set('x-elastic-internal-origin', 'xxx').expect(200); + + const indexCreated = body.find( + (index: { name: string }) => index.name === 'reload-test-index' + ); + const sortedReceivedKeys = Object.keys(indexCreated).sort(); + expect(sortedReceivedKeys).to.eql(expectedKeys); + expect(body.length > 1).to.be(true); // to contrast it with the next test + }); + + it('should allow reloading only certain indices', async () => { + const index = await createIndex(); + const { body } = await reload([index]).set('x-elastic-internal-origin', 'xxx'); + + expect(body.length === 1).to.be(true); + expect(body[0].name).to.be(index); + }); + }); + + describe('delete indices', () => { + it('should delete an index', async () => { + const index = await createIndex(); + + const { body: indices1 } = await catIndex(undefined, 'i'); + expect(indices1.map((indexItem) => indexItem.i)).to.contain(index); + + await deleteIndex(index).set('x-elastic-internal-origin', 'xxx').expect(200); + + const { body: indices2 } = await catIndex(undefined, 'i'); + expect(indices2.map((indexItem) => indexItem.i)).not.to.contain(index); + }); + + it('should require index or indices to be provided', async () => { + const { body } = await deleteIndex().set('x-elastic-internal-origin', 'xxx').expect(400); + expect(body.message).to.contain('expected value of type [string]'); + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/mappings.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/mappings.ts new file mode 100644 index 000000000000..eb28c77fc440 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/mappings.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const log = getService('log'); + const indexManagementService = getService('indexManagement'); + + describe('mappings', () => { + let indexName: string; + let getMapping: typeof indexManagementService['mappings']['api']['getMapping']; + let createIndex: typeof indexManagementService['indices']['helpers']['createIndex']; + let deleteAllIndices: typeof indexManagementService['indices']['helpers']['deleteAllIndices']; + + const mappings = { + properties: { + total: { type: 'long' }, + tag: { type: 'keyword' }, + createdAt: { type: 'date' }, + }, + }; + + before(async () => { + ({ + indices: { + helpers: { createIndex, deleteAllIndices }, + }, + mappings: { + api: { getMapping }, + }, + } = indexManagementService); + + log.debug('Creating index'); + try { + indexName = await createIndex(undefined, mappings); + } catch (err) { + log.debug('[Setup error] Error creating index'); + throw err; + } + }); + + after(async () => { + try { + await deleteAllIndices(); + } catch (err) { + log.debug('[Cleanup error] Error deleting index'); + throw err; + } + }); + + it('should get the index mappings', async () => { + const { body } = await getMapping(indexName).expect(200); + + expect(body.mappings).to.eql(mappings); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/settings.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/settings.ts new file mode 100644 index 000000000000..d5cd93060737 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/settings.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const indexManagementService = getService('indexManagement'); + + describe('settings', () => { + let getIndexSettings: typeof indexManagementService['settings']['api']['getIndexSettings']; + let updateIndexSettings: typeof indexManagementService['settings']['api']['updateIndexSettings']; + let createIndex: typeof indexManagementService['indices']['helpers']['createIndex']; + let deleteAllIndices: typeof indexManagementService['indices']['helpers']['deleteAllIndices']; + + before(async () => { + ({ + settings: { + api: { getIndexSettings, updateIndexSettings }, + }, + indices: { + helpers: { createIndex, deleteAllIndices }, + }, + } = indexManagementService); + }); + + after(async () => await deleteAllIndices()); + + it('should fetch an index settings', async () => { + const index = await createIndex(); + + const { body } = await getIndexSettings(index).expect(200); + + // Verify we fetch the corret index settings + expect(body.settings.index.provided_name).to.be(index); + + const expectedSettings = [ + 'max_inner_result_window', + 'unassigned', + 'max_terms_count', + 'lifecycle', + 'routing_partition_size', + 'max_docvalue_fields_search', + 'merge', + 'max_refresh_listeners', + 'max_regex_length', + 'load_fixed_bitset_filters_eagerly', + 'number_of_routing_shards', + 'write', + 'verified_before_close', + 'mapping', + 'source_only', + 'soft_deletes', + 'max_script_fields', + 'query', + 'format', + 'frozen', + 'sort', + 'priority', + 'codec', + 'max_rescore_window', + 'analyze', + 'gc_deletes', + 'max_ngram_diff', + 'translog', + 'auto_expand_replicas', + 'requests', + 'data_path', + 'highlight', + 'routing', + 'search', + 'fielddata', + 'default_pipeline', + 'max_slices_per_scroll', + 'shard', + 'xpack', + 'percolator', + 'allocation', + 'refresh_interval', + 'indexing', + 'compound_format', + 'blocks', + 'max_result_window', + 'store', + 'queries', + 'warmer', + 'max_shingle_diff', + 'query_string', + ]; + + // Make sure none of the settings have been removed from ES API + expectedSettings.forEach((setting) => { + try { + expect(body.defaults.index.hasOwnProperty(setting)).to.be(true); + } catch { + throw new Error(`Expected setting "${setting}" not found.`); + } + }); + }); + + it('should update an index settings', async () => { + const index = await createIndex(); + + const { body: body1 } = await getIndexSettings(index); + expect(body1.settings.index.number_of_replicas).to.be('1'); + + const settings = { + index: { + number_of_replicas: 2, + }, + }; + await updateIndexSettings(index, settings); + + const { body: body2 } = await getIndexSettings(index); + expect(body2.settings.index.number_of_replicas).to.be('2'); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/index.ts new file mode 100644 index 000000000000..b3316533be70 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Painless Lab API', function () { + this.tags(['esGate']); + + loadTestFile(require.resolve('./painless_lab')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/painless_lab.ts b/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/painless_lab.ts new file mode 100644 index 000000000000..1d0d5cefedb8 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/painless_lab/painless_lab.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const API_BASE_PATH = '/api/painless_lab'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const svlCommonApi = getService('svlCommonApi'); + + describe('Painless Lab Routes', function () { + describe('Execute', () => { + it('should execute a valid painless script', async () => { + const script = + '"{\\n \\"script\\": {\\n \\"source\\": \\"return true;\\",\\n \\"params\\": {\\n \\"string_parameter\\": \\"string value\\",\\n \\"number_parameter\\": 1.5,\\n \\"boolean_parameter\\": true\\n}\\n }\\n}"'; + + const { body } = await supertest + .post(`${API_BASE_PATH}/execute`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(script) + .expect(200); + + expect(body).to.eql({ + result: 'true', + }); + }); + + it('should return error response for invalid painless script', async () => { + const invalidScript = + '"{\\n \\"script\\": {\\n \\"source\\": \\"foobar\\",\\n \\"params\\": {\\n \\"string_parameter\\": \\"string value\\",\\n \\"number_parameter\\": 1.5,\\n \\"boolean_parameter\\": true\\n}\\n }\\n}"'; + + const { body } = await supertest + .post(`${API_BASE_PATH}/execute`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(invalidScript) + .expect(200); + + expect(body.error).to.not.be(undefined); + expect(body.error.reason).to.eql('compile error'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/index.ts new file mode 100644 index 000000000000..1df060c65862 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Search profiler APIs', function () { + this.tags(['esGate']); + + loadTestFile(require.resolve('./search_profiler')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/search_profiler.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/search_profiler.ts new file mode 100644 index 000000000000..45d515dff488 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_profiler/search_profiler.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const API_BASE_PATH = '/api/searchprofiler'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const svlCommonApi = getService('svlCommonApi'); + + describe('Profile', () => { + it('should return profile results for a valid index', async () => { + const payload = { + index: '_all', + query: { + query: { + match_all: {}, + }, + }, + }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/profile`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(payload) + .expect(200); + + expect(body.ok).to.eql(true); + }); + + it('should return error for invalid index', async () => { + const payloadWithInvalidIndex = { + index: 'index_does_not_exist', + query: { + query: { + match_all: {}, + }, + }, + }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/profile`) + .set(svlCommonApi.getInternalRequestHeader()) + .set('Content-Type', 'application/json;charset=UTF-8') + .send(payloadWithInvalidIndex) + .expect(404); + + expect(body.error).to.eql('Not Found'); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts index 0fb268605276..9a0ce57eda10 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts @@ -23,9 +23,12 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/platform_security'), require.resolve('../../common/scripts_tests'), require.resolve('../../common/search_oss'), + require.resolve('../../common/search_profiler'), require.resolve('../../common/search_xpack'), require.resolve('../../common/core'), require.resolve('../../common/reporting'), + require.resolve('../../common/grok_debugger'), + require.resolve('../../common/painless_lab'), ], junit: { reportName: 'Serverless Observability API Integration Tests - Common Group 1', diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts index 2b7fc3653c3b..018f326a0aa9 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_fired.ts @@ -6,7 +6,6 @@ */ import { cleanup, generate } from '@kbn/infra-forge'; -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -89,7 +88,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.5], timeSize: 5, @@ -154,7 +152,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -184,7 +182,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>', threshold: [0.5], timeSize: 5, diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts index 4f1e9a4ab080..0411c6948eae 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/avg_pct_no_data.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -75,7 +74,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.5], timeSize: 5, @@ -140,7 +138,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -170,7 +168,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>', threshold: [0.5], timeSize: 5, diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts index 47ed54412296..d11a06ee3562 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/custom_eq_avg_bytes_fired.ts @@ -12,7 +12,6 @@ */ import { cleanup, generate } from '@kbn/infra-forge'; -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -91,7 +90,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.9], timeSize: 1, @@ -158,7 +156,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -188,7 +186,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT, threshold: [0.9], timeSize: 1, diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts index 0f47627be5e2..1c055b21c37a 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/documents_count_fired.ts @@ -6,7 +6,6 @@ */ import { cleanup, generate } from '@kbn/infra-forge'; -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { Aggregators, Comparator, @@ -85,9 +84,8 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, - comparator: Comparator.GT, - threshold: [2], + comparator: Comparator.OUTSIDE_RANGE, + threshold: [1, 2], timeSize: 1, timeUnit: 'm', metrics: [{ name: 'A', filter: '', aggType: Aggregators.COUNT }], @@ -148,7 +146,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -178,9 +176,8 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', - comparator: '>', - threshold: [2], + comparator: Comparator.OUTSIDE_RANGE, + threshold: [1, 2], timeSize: 1, timeUnit: 'm', metrics: [{ name: 'A', filter: '', aggType: 'count' }], diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts index 78daabb1eb13..9c5eaf281a81 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/custom_threshold_rule/group_by_fired.ts @@ -11,7 +11,6 @@ * 2.0. */ -import { CUSTOM_AGGREGATOR } from '@kbn/observability-plugin/common/custom_threshold_rule/constants'; import { kbnTestConfig } from '@kbn/test'; import moment from 'moment'; import { cleanup, generate } from '@kbn/infra-forge'; @@ -95,7 +94,6 @@ export default function ({ getService }: FtrProviderContext) { params: { criteria: [ { - aggType: CUSTOM_AGGREGATOR, comparator: Comparator.GT_OR_EQ, threshold: [0.2], timeSize: 1, @@ -167,7 +165,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source).property( 'kibana.alert.rule.category', - 'Custom threshold (Technical Preview)' + 'Custom threshold (Beta)' ); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.consumer', 'observability'); expect(resp.hits.hits[0]._source).property('kibana.alert.rule.name', 'Threshold rule'); @@ -205,7 +203,6 @@ export default function ({ getService }: FtrProviderContext) { .eql({ criteria: [ { - aggType: 'custom', comparator: '>=', threshold: [0.2], timeSize: 1, @@ -235,8 +232,7 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.hits.hits[0]._source?.ruleType).eql('observability.rules.custom_threshold'); expect(resp.hits.hits[0]._source?.alertDetailsUrl).eql( - // Added the S to protocol.getUrlParts as not returning the correct value. - `${protocol}s://${hostname}:${port}/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)` + `${protocol}://${hostname}:${port}/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)` ); expect(resp.hits.hits[0]._source?.reason).eql( `Average system.cpu.total.norm.pct is 80%, above the threshold of 20%. (duration: 1 min, data view: ${DATE_VIEW}, group: host-0)` diff --git a/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts index 5a1834f91b7a..1d83268723dd 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts @@ -23,6 +23,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/platform_security'), require.resolve('../../common/scripts_tests'), require.resolve('../../common/search_oss'), + require.resolve('../../common/search_profiler'), require.resolve('../../common/search_xpack'), require.resolve('../../common/core'), require.resolve('../../common/reporting'), diff --git a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts index cf9314ce8201..8fcab232142f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts @@ -23,9 +23,12 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/platform_security'), require.resolve('../../common/scripts_tests'), require.resolve('../../common/search_oss'), + require.resolve('../../common/search_profiler'), require.resolve('../../common/search_xpack'), require.resolve('../../common/core'), require.resolve('../../common/reporting'), + require.resolve('../../common/grok_debugger'), + require.resolve('../../common/painless_lab'), ], junit: { reportName: 'Serverless Security API Integration Tests - Common Group 1', diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index 1090f0a96aa6..538316b61e80 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -75,6 +75,9 @@ export function createTestConfig(options: CreateTestConfigOptions) { connectors: { pathname: '/app/management/insightsAndAlerting/triggersActionsConnectors/', }, + triggersActions: { + pathname: '/app/management/insightsAndAlerting/triggersActions', + }, settings: { pathname: '/app/management/kibana/settings', }, @@ -87,6 +90,16 @@ export function createTestConfig(options: CreateTestConfigOptions) { securitySolution: { pathname: '/app/security', }, + dashboard: { + pathname: '/app/dashboards', + }, + discover: { + pathname: '/app/discover', + }, + context: { + pathname: '/app/discover', + hash: '/context', + }, }, // choose where screenshots should be saved screenshots: { diff --git a/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/data.json.gz b/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/data.json.gz new file mode 100644 index 000000000000..45c293daa472 Binary files /dev/null and b/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/data.json.gz differ diff --git a/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/mappings.json b/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/mappings.json new file mode 100644 index 000000000000..f852c18ebcc1 --- /dev/null +++ b/x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern/mappings.json @@ -0,0 +1,100 @@ +{ + "type": "index", + "value": { + "aliases": { + }, + "index": "kibana_sample_data_flights", + "mappings": { + "properties": { + "AvgTicketPrice": { + "type": "float" + }, + "Cancelled": { + "type": "boolean" + }, + "Carrier": { + "type": "keyword" + }, + "Dest": { + "type": "keyword" + }, + "DestAirportID": { + "type": "keyword" + }, + "DestCityName": { + "type": "keyword" + }, + "DestCountry": { + "type": "keyword" + }, + "DestLocation": { + "type": "geo_point" + }, + "DestRegion": { + "type": "keyword" + }, + "DestWeather": { + "type": "keyword" + }, + "DistanceKilometers": { + "type": "float" + }, + "DistanceMiles": { + "type": "float" + }, + "FlightDelay": { + "type": "boolean" + }, + "FlightDelayMin": { + "type": "integer" + }, + "FlightDelayType": { + "type": "keyword" + }, + "FlightNum": { + "type": "keyword" + }, + "FlightTimeHour": { + "type": "keyword" + }, + "FlightTimeMin": { + "type": "float" + }, + "Origin": { + "type": "keyword" + }, + "OriginAirportID": { + "type": "keyword" + }, + "OriginCityName": { + "type": "keyword" + }, + "OriginCountry": { + "type": "keyword" + }, + "OriginLocation": { + "type": "geo_point" + }, + "OriginRegion": { + "type": "keyword" + }, + "OriginWeather": { + "type": "keyword" + }, + "dayOfWeek": { + "type": "integer" + }, + "timestamp": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} \ No newline at end of file diff --git a/x-pack/test_serverless/functional/fixtures/kbn_archiver/reporting/logs.json b/x-pack/test_serverless/functional/fixtures/kbn_archiver/reporting/logs.json new file mode 100644 index 000000000000..05e92981916a --- /dev/null +++ b/x-pack/test_serverless/functional/fixtures/kbn_archiver/reporting/logs.json @@ -0,0 +1,560 @@ +{ + "attributes": { + "fieldAttrs": "{\"@message\":{\"count\":2},\"@tags\":{\"count\":2},\"url\":{\"count\":2}}", + "fieldFormatMap": "{}", + "fields": "[]", + "name": "logstash-*", + "runtimeFieldMap": "{}", + "sourceFilters": "[]", + "timeFieldName": "@timestamp", + "title": "logstash-*", + "typeMeta": "{}" + }, + "coreMigrationVersion": "8.7.0", + "id": "logstash-*", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2023-01-19T00:49:47.963Z", + "version": "WzMxNCwyXQ==" +} + +{ + "attributes": { + "columns": [ + "clientip", + "extension" + ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[{\"meta\":{\"alias\":\"datefilter🥜\",\"negate\":false,\"type\":\"range\",\"key\":\"@timestamp\",\"value\":\"Sep 20, 2015 @ 03:19:40.307 to Sep 20, 2015 @ 03:26:56.221\",\"params\":{\"gte\":\"2015-09-20T10:19:40.307Z\",\"lt\":\"2015-09-20T10:26:56.221Z\"},\"disabled\":false,\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"range\":{\"@timestamp\":{\"gte\":\"2015-09-20T10:19:40.307Z\",\"lt\":\"2015-09-20T10:26:56.221Z\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "title": "A Saved Search With a DATE FILTER", + "version": 1 + }, + "coreMigrationVersion": "8.0.0", + "id": "d7a79750-3edd-11e9-99cc-4d80163ee9e7", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + }, + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2019-03-05T00:34:28.706Z", + "version": "WzMsMl0=" +} + +{ + "attributes": { + "buildNum": 9007199254740991, + "dateFormat:tz": "UTC", + "defaultIndex": "89655130-5013-11e9-bce7-4dabcb8bef24", + "csv:quoteValues": true, + "csv:separator": ",", + "search:queryLanguage": "lucene" + }, + "coreMigrationVersion": "8.0.0", + "id": "8.0.0", + "migrationVersion": { + "config": "8.0.0" + }, + "references": [], + "type": "config", + "updated_at": "2019-07-09T21:57:57.129Z", + "version": "WzMsMl0=" +} + +{ + "attributes": { + "fieldFormatMap": "{\"date\":{\"id\":\"date_nanos\"}}", + "fields": "[{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"esTypes\":[\"_type\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"date\",\"type\":\"date\",\"esTypes\":[\"date_nanos\"],\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", + "title": "nanos" + }, + "coreMigrationVersion": "8.0.0", + "id": "907bc200-a294-11e9-a900-ef10e0ac769e", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2019-07-09T22:07:17.154Z", + "version": "WzQsMl0=" +} + +{ + "attributes": { + "columns": [ + "date", + "message", + "_id" + ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "date", + "desc" + ] + ], + "title": "TESTS DATE NANOS", + "version": 1 + }, + "coreMigrationVersion": "8.0.0", + "id": "e4035040-a295-11e9-a900-ef10e0ac769e", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "907bc200-a294-11e9-a900-ef10e0ac769e", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2019-07-09T22:07:22.318Z", + "version": "WzUsMl0=" +} + +{ + "id": "timeless-sales", + "attributes": { + "fields": "[{\"name\":\"@date\",\"type\":\"date\",\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"metric\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"name\",\"type\":\"string\",\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"power\",\"type\":\"number\",\"count\":1,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"success\",\"type\":\"boolean\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", + "title": "sales" + }, + "migrationVersion": { + "index-pattern": "6.5.0" + }, + "references": [ + ], + "type": "index-pattern", + "updated_at": "2019-03-05T22:52:35.474Z" +} + +{ + "id": "71e3ee20-3f99-11e9-b8ee-6b9604f2f877", + "migrationVersion": { + "search": "7.0.0" + }, + "references": [ + { + "id": "timeless-sales", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + }, + { + "id": "timeless-sales", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + } + ], + "attributes": { + "columns": [ + "name", + "power" + ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"$state\":{\"store\":\"appState\"},\"meta\":{\"alias\":null,\"disabled\":false,\"key\":\"power\",\"negate\":false,\"params\":{\"gte\":1,\"lt\":null},\"type\":\"range\",\"value\":\"1 to \",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"range\":{\"power\":{\"gte\":1,\"lt\":null}}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [[ + "power", + "asc" + ]], + "title": "SALE POWER", + "version": 1 + }, + "type": "search", + "updated_at": "2019-03-05T22:53:08.481Z" +} + +{ + "attributes": { + "state": { + "datasourceStates": { + "indexpattern": { + "layers": { + "0385075d-0f3b-4a12-b3c0-68a95781d48d": { + "columnOrder": [ + "03195b79-6315-40f7-b513-5222330367d7", + "2cb8226c-bfe5-4505-9c66-9f99ff6b5822" + ], + "columns": { + "03195b79-6315-40f7-b513-5222330367d7": { + "dataType": "date", + "isBucketed": true, + "label": "date", + "operationType": "date_histogram", + "params": { + "interval": "auto" + }, + "scale": "interval", + "sourceField": "date" + }, + "2cb8226c-bfe5-4505-9c66-9f99ff6b5822": { + "dataType": "number", + "isBucketed": false, + "label": "Count of records", + "operationType": "count", + "scale": "ratio", + "sourceField": "Records" + } + }, + "incompleteColumns": {} + } + } + } + }, + "filters": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "layers": [ + { + "accessors": [ + "2cb8226c-bfe5-4505-9c66-9f99ff6b5822" + ], + "layerId": "0385075d-0f3b-4a12-b3c0-68a95781d48d", + "layerType": "data", + "position": "top", + "seriesType": "bar_stacked", + "showGridlines": false, + "xAccessor": "03195b79-6315-40f7-b513-5222330367d7" + } + ], + "legend": { + "isVisible": true, + "position": "right" + }, + "preferredSeriesType": "bar_stacked", + "title": "Empty XY chart", + "valueLabels": "hide" + } + }, + "title": "distogram", + "visualizationType": "lnsXY" + }, + "coreMigrationVersion": "8.0.0", + "id": "4b498150-6821-11eb-9375-4bd700f7d8d4", + "migrationVersion": { + "lens": "8.0.0" + }, + "references": [], + "type": "lens", + "updated_at": "2021-02-06T02:16:17.129Z", + "version": "WzgsMl0=" +} + +{ + "attributes": { + "fieldAttrs": "{\"_id\":{\"count\":1},\"gender\":{\"count\":1},\"name\":{\"count\":1},\"value\":{\"count\":1},\"year\":{\"count\":1},\"years_ago\":{\"count\":1},\"date_informal\":{\"count\":1}}", + "fieldFormatMap": "{\"years_ago\":{\"id\":\"number\",\"params\":{\"pattern\":\"0,0.00000000000000000000\"}},\"year\":{\"id\":\"number\",\"params\":{\"pattern\":\"0\"}},\"date_informal\":{\"id\":\"date\",\"params\":{\"parsedUrl\":{\"origin\":\"http://localhost:5620\",\"pathname\":\"/app/dashboards\",\"basePath\":\"\"},\"pattern\":\"MMM Do YY\"}}}", + "fields": "[{\"count\":1,\"script\":\"2019 - doc['year'].value\",\"lang\":\"painless\",\"name\":\"years_ago\",\"type\":\"number\",\"scripted\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":1,\"script\":\"doc['date'].value\",\"lang\":\"painless\",\"name\":\"date_informal\",\"type\":\"date\",\"scripted\":true,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]", + "runtimeFieldMap": "{}", + "timeFieldName": "date", + "title": "babynames" + }, + "coreMigrationVersion": "8.0.0", + "id": "89655130-5013-11e9-bce7-4dabcb8bef24", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2021-02-06T02:15:25.565Z", + "version": "WzcsMl0=" +} + +{ + "attributes": { + "columns": [ + "_id", + "name", + "gender", + "value", + "year", + "years_ago", + "date_informal" + ], + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"highlightAll\":true,\"version\":true,\"sort\":[{\"date\":\"desc\"}],\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"fieldsFromSource\":[\"_id\",\"_index\",\"_score\",\"_source\",\"_type\",\"date\",\"gender\",\"name\",\"percent\",\"value\",\"year\",\"years_ago\",\"date_informal\"],\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "date", + "desc" + ] + ], + "title": "namessearch", + "version": 1 + }, + "coreMigrationVersion": "8.0.0", + "id": "cdb908f0-6820-11eb-9375-4bd700f7d8d4", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "89655130-5013-11e9-bce7-4dabcb8bef24", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2021-02-06T02:15:31.253Z", + "version": "WzYsMl0=" +} + +{ + "attributes": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}" + }, + "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", + "panelsJSON": "[{\"version\":\"7.11.0\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":13,\"i\":\"56f914c9-9597-4781-bfc6-229d40b382c7\"},\"panelIndex\":\"56f914c9-9597-4781-bfc6-229d40b382c7\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_56f914c9-9597-4781-bfc6-229d40b382c7\"},{\"version\":\"7.11.0\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":13,\"w\":48,\"h\":14,\"i\":\"f3ea512f-e441-4206-8aa7-000b1418ea2b\"},\"panelIndex\":\"f3ea512f-e441-4206-8aa7-000b1418ea2b\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_f3ea512f-e441-4206-8aa7-000b1418ea2b\"}]", + "timeRestore": false, + "title": "names dashboard", + "version": 1 + }, + "coreMigrationVersion": "8.0.0", + "id": "52af6d10-6821-11eb-9375-4bd700f7d8d4", + "migrationVersion": { + "dashboard": "8.0.0" + }, + "references": [ + { + "id": "cdb908f0-6820-11eb-9375-4bd700f7d8d4", + "name": "56f914c9-9597-4781-bfc6-229d40b382c7:panel_56f914c9-9597-4781-bfc6-229d40b382c7", + "type": "search" + }, + { + "id": "4b498150-6821-11eb-9375-4bd700f7d8d4", + "name": "f3ea512f-e441-4206-8aa7-000b1418ea2b:panel_f3ea512f-e441-4206-8aa7-000b1418ea2b", + "type": "lens" + } + ], + "type": "dashboard", + "updated_at": "2021-02-06T02:16:29.540Z", + "version": "WzksMl0=" +} + +{ + "attributes": { + "fieldAttrs": "{\"name\":{\"count\":1},\"updated_at\":{\"count\":1}}", + "fields": "[]", + "runtimeFieldMap": "{}", + "timeFieldName": "timestamp", + "title": "sparse_data", + "typeMeta": "{}" + }, + "coreMigrationVersion": "8.1.0", + "id": "8e5af470-62de-11ec-a5fd-9f30aac1abbf", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2021-12-22T04:22:06.170Z", + "version": "WzI0MTQsMV0=" +} + +{ + "attributes": { + "columns": [ + "name", + "updated_at" + ], + "description": "", + "grid": {}, + "hideChart": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "timestamp", + "desc" + ] + ], + "title": "Sparse Columns" + }, + "coreMigrationVersion": "8.1.0", + "id": "c4367dd0-62de-11ec-a5fd-9f30aac1abbf", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "8e5af470-62de-11ec-a5fd-9f30aac1abbf", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2021-12-22T04:22:25.584Z", + "version": "WzI0MjAsMV0=" +} + +{ + "attributes": { + "columns": [], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"type\":\"custom\",\"disabled\":false,\"negate\":false,\"alias\":null,\"key\":\"query\",\"value\":\"{\\\"bool\\\":{\\\"minimum_should_match\\\":1,\\\"should\\\":[{\\\"match_phrase\\\":{\\\"@tags\\\":\\\"info\\\"}}]}}\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"bool\":{\"minimum_should_match\":1,\"should\":[{\"match_phrase\":{\"@tags\":\"info\"}}]}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRestore": false, + "title": "A saved search with match_phrase filter and no columns selected", + "usesAdHocDataView": false + }, + "coreMigrationVersion": "8.7.0", + "created_at": "2023-01-19T00:36:50.456Z", + "id": "5cfe1180-9791-11ed-97f7-93bc26fd388d", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + }, + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2023-01-19T00:37:22.716Z", + "version": "WzE5NiwyXQ==" +} + +{ + "attributes": { + "columns": [ + "@message", + "url", + "@tags" + ], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"host:media-for-the-masses\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "refreshInterval": { + "pause": true, + "value": 60000 + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRange": { + "from": "2015-07-30T15:49:33.702Z", + "to": "2015-11-01T01:39:01.782Z" + }, + "timeRestore": true, + "title": "A saved search with the time stored and a query", + "usesAdHocDataView": false + }, + "coreMigrationVersion": "8.7.0", + "created_at": "2023-01-19T00:38:13.779Z", + "id": "8ea82630-9791-11ed-97f7-93bc26fd388d", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2023-01-19T00:50:04.124Z", + "version": "WzMxNiwyXQ==" +} + +{ + "attributes": { + "columns": [ + "@message", + "@tags", + "url" + ], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"host:media-for-the-masses\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRestore": false, + "title": "A saved search with a query", + "usesAdHocDataView": false + }, + "coreMigrationVersion": "8.7.0", + "created_at": "2023-01-19T00:31:57.708Z", + "id": "ae8044c0-9790-11ed-97f7-93bc26fd388d", + "migrationVersion": { + "search": "8.0.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "search", + "updated_at": "2023-01-19T00:39:15.770Z", + "version": "WzI2MCwyXQ==" +} diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 5c497b47a6e1..93b5dea4f049 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -106,6 +106,19 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { }); } }, + async findLink(by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string }) { + await this.expectLinkExists(by); + if ('deepLinkId' in by) { + return testSubjects.find(`~nav-item-deepLinkId-${by.deepLinkId}`); + } else if ('navId' in by) { + return testSubjects.find(`~nav-item-id-${by.navId}`); + } else { + return retry.try(async () => { + const link = await getByVisibleText('~nav-item', by.text); + return link; + }); + } + }, async expectSectionExists(sectionId: NavigationId) { log.debug('ServerlessCommonNavigation.sidenav.expectSectionExists', sectionId); await testSubjects.existOrFail(getSectionIdTestSubj(sectionId)); @@ -153,6 +166,20 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { async expectExists() { await testSubjects.existOrFail('breadcrumbs'); }, + async clickBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + if ('deepLinkId' in by) { + await testSubjects.click(`~breadcrumb-deepLinkId-${by.deepLinkId}`); + } else { + (await getByVisibleText('~breadcrumb', by.text))?.click(); + } + }, + getBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + if ('deepLinkId' in by) { + return testSubjects.find(`~breadcrumb-deepLinkId-${by.deepLinkId}`); + } else { + return getByVisibleText('~breadcrumb', by.text); + } + }, async expectBreadcrumbExists(by: { deepLinkId: AppDeepLinkId } | { text: string }) { log.debug( 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbExists', diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_landing_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_landing_page.ts index 672ec3aeada4..a9de87ca60d7 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_search_landing_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_search_landing_page.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export function SvlSearchLandingPageProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const browser = getService('browser'); return { async assertSvlSearchSideNavExists() { @@ -75,5 +76,15 @@ export function SvlSearchLandingPageProvider({ getService }: FtrProviderContext) }); }, }, + pipeline: { + async click() { + await testSubjects.click('create-a-pipeline-button'); + }, + async expectNavigateToCreatePipelinePage() { + expect(await browser.getCurrentUrl()).contain( + '/app/management/ingest/ingest_pipelines/create' + ); + }, + }, }; } diff --git a/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts b/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts index 4ba56987416d..d453101e55e2 100644 --- a/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts +++ b/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts @@ -57,6 +57,7 @@ const deploymentAgnosticFunctionalServices = _.pick(functionalServices, [ 'queryBar', 'random', 'renderable', + 'reporting', 'retryOnStale', 'rules', 'sampleData', diff --git a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts index 3dd18587a914..91c149dab37a 100644 --- a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts +++ b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts @@ -16,10 +16,10 @@ export function MachineLearningNavigationProviderObservability({ async function navigateToArea(id: string) { await svlCommonNavigation.sidenav.openSection('observability_project_nav.aiops'); - await testSubjects.existOrFail(`~nav-item-id-observability_project_nav.aiops.ml:${id}`, { + await testSubjects.existOrFail(`~nav-item-observability_project_nav.aiops.ml:${id}`, { timeout: 60 * 1000, }); - await testSubjects.click(`~nav-item-id-observability_project_nav.aiops.ml:${id}`); + await testSubjects.click(`~nav-item-observability_project_nav.aiops.ml:${id}`); } return { diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_context_navigation.ts b/x-pack/test_serverless/functional/test_suites/common/context/_context_navigation.ts new file mode 100644 index 000000000000..f23ebd55f107 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/context/_context_navigation.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const TEST_FILTER_COLUMN_NAMES = [ + [ + 'agent', + 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24', + ], + ['extension', 'jpg'], +]; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const browser = getService('browser'); + const dataGrid = getService('dataGrid'); + const PageObjects = getPageObjects([ + 'common', + 'header', + 'context', + 'discover', + 'timePicker', + 'svlCommonNavigation', + ]); + const kibanaServer = getService('kibanaServer'); + const filterBar = getService('filterBar'); + + const checkMainViewFilters = async () => { + for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { + expect(await filterBar.hasFilter(columnName, value, true)).to.eql(true); + } + expect(await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes()).to.eql({ + start: PageObjects.timePicker.defaultStartTime, + end: PageObjects.timePicker.defaultEndTime, + }); + }; + + describe('discover - context - back navigation', function contextSize() { + before(async () => { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update({ + defaultIndex: 'logstash-*', + }); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { + await filterBar.addFilter({ field: columnName, operation: 'is', value }); + } + // TODO: Serverless sidebar causes the grid to be hidden, so set a larger window size + await browser.setWindowSize(1920, 1080); + }); + + after(async function () { + await kibanaServer.uiSettings.replace({}); + }); + + it('should go back after loading', async function () { + await retry.waitFor('user navigating to context and returning to discover', async () => { + // navigate to the context view + const initialHitCount = await PageObjects.discover.getHitCount(); + await dataGrid.clickRowToggle({ rowIndex: 0 }); + + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + await PageObjects.context.clickSuccessorLoadMoreButton(); + await PageObjects.context.clickSuccessorLoadMoreButton(); + await PageObjects.context.clickSuccessorLoadMoreButton(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + await browser.goBack(); + await PageObjects.discover.waitForDocTableLoadingComplete(); + const hitCount = await PageObjects.discover.getHitCount(); + return initialHitCount === hitCount; + }); + }); + + it('should go back via breadcrumbs with preserved state', async function () { + await retry.waitFor( + 'user navigating to context and returning to discover via breadcrumbs', + async () => { + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ + deepLinkId: 'discover', + }); + await PageObjects.discover.waitForDocTableLoadingComplete(); + + await checkMainViewFilters(); + return true; + } + ); + }); + + it('should go back via breadcrumbs with preserved state after a page refresh', async function () { + await retry.waitFor( + 'user navigating to context and returning to discover via breadcrumbs', + async () => { + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + await browser.refresh(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ + deepLinkId: 'discover', + }); + await PageObjects.discover.waitForDocTableLoadingComplete(); + + await checkMainViewFilters(); + return true; + } + ); + }); + + it('should go back via breadcrumbs with updated state after a goBack browser', async function () { + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + await PageObjects.common.sleep(5000); + + // update url state + await filterBar.removeFilter('agent'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ + deepLinkId: 'discover', + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await filterBar.getFilterCount()).to.eql(2); + await checkMainViewFilters(); + + await browser.goBack(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + expect(await filterBar.getFilterCount()).to.eql(1); + const [filterName, filterValue] = TEST_FILTER_COLUMN_NAMES[1]; + expect(await filterBar.hasFilter(filterName, filterValue, false)).to.eql(true); + + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ + deepLinkId: 'discover', + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await filterBar.getFilterCount()).to.eql(2); + await checkMainViewFilters(); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts new file mode 100644 index 000000000000..296a8245f9d1 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const TEST_COLUMN_NAMES = ['@message']; +const TEST_FILTER_COLUMN_NAMES = [ + ['extension.raw', 'jpg'], + ['geo.src', 'IN'], +]; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const dataGrid = getService('dataGrid'); + const filterBar = getService('filterBar'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'timePicker', + 'settings', + 'dashboard', + 'context', + 'header', + 'unifiedFieldList', + 'svlCommonNavigation', + ]); + const testSubjects = getService('testSubjects'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const browser = getService('browser'); + const kibanaServer = getService('kibanaServer'); + + describe('context link in discover', () => { + before(async () => { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update({ + defaultIndex: 'logstash-*', + }); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + for (const columnName of TEST_COLUMN_NAMES) { + await PageObjects.unifiedFieldList.clickFieldListItemAdd(columnName); + } + + for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { + await filterBar.addFilter({ field: columnName, operation: 'is', value }); + await PageObjects.header.waitUntilLoadingHasFinished(); + } + // TODO: Serverless sidebar causes the grid to be hidden, so set a larger window size + await browser.setWindowSize(1920, 1080); + }); + + after(async () => { + await kibanaServer.uiSettings.replace({}); + }); + + it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { + /** + * Helper function to get the first timestamp of the document table + * @param isAnchorRow - determins if just the anchor row of context should be selected + */ + const getTimestamp = async (isAnchorRow: boolean = false) => { + const contextFields = await dataGrid.getFields({ isAnchorRow }); + return contextFields[0][0]; + }; + // get the timestamp of the first row + const firstDiscoverTimestamp = await getTimestamp(); + + // check the anchor timestamp in the context view + await retry.waitFor('selected document timestamp matches anchor timestamp', async () => { + // navigate to the context view + await dataGrid.clickRowToggle({ rowIndex: 0 }); + + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + const anchorTimestamp = await getTimestamp(true); + return anchorTimestamp === firstDiscoverTimestamp; + }); + + await retry.waitFor('next anchor timestamp matches previous anchor timestamp', async () => { + // get the timestamp of the first row + const firstContextTimestamp = await getTimestamp(false); + await dataGrid.clickRowToggle({ rowIndex: 0 }); + + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + const anchorTimestamp = await getTimestamp(true); + return anchorTimestamp === firstContextTimestamp; + }); + }); + + it('should open the context view with the same columns', async () => { + const columnNames = await dataGrid.getHeaderFields(); + expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); + }); + + it('should open the context view with the filters disabled', async () => { + let disabledFilterCounter = 0; + for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { + if (await filterBar.hasFilter(columnName, value, false)) { + disabledFilterCounter++; + } + } + expect(disabledFilterCounter).to.be(TEST_FILTER_COLUMN_NAMES.length); + }); + + it('should navigate to the first document and then back to discover', async () => { + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + // click the open action + await retry.try(async () => { + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + if (!rowActions.length) { + throw new Error('row actions empty, trying again'); + } + await rowActions[0].click(); + }); + + const hasDocHit = await testSubjects.exists('doc-hit'); + expect(hasDocHit).to.be(true); + + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ + deepLinkId: 'discover', + }); + await PageObjects.discover.waitForDiscoverAppOnScreen(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + it('navigates to doc view from embeddable', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.saveSearch('my search'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await PageObjects.dashboard.navigateToApp(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + + await dashboardAddPanel.addSavedSearch('my search'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[0].click(); + await PageObjects.common.sleep(250); + + // close popup + const alert = await browser.getAlert(); + await alert?.accept(); + if (await testSubjects.exists('confirmModalConfirmButton')) { + await testSubjects.click('confirmModalConfirmButton'); + } + + await retry.waitFor('navigate to doc view', async () => { + const currentUrl = await browser.getCurrentUrl(); + return currentUrl.includes('#/doc'); + }); + await retry.waitFor('doc view being rendered', async () => { + return await PageObjects.discover.isShowingDocViewer(); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts b/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts new file mode 100644 index 000000000000..c27998a65889 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts @@ -0,0 +1,255 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const TEST_INDEX_PATTERN = 'logstash-*'; +const TEST_ANCHOR_ID = 'AU_x3_BrGFA8no6QjjaI'; +const TEST_ANCHOR_FILTER_FIELD = 'geo.src'; +const TEST_ANCHOR_FILTER_VALUE = 'IN'; +const TEST_COLUMN_NAMES = ['extension', 'geo.src']; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const dataGrid = getService('dataGrid'); + const filterBar = getService('filterBar'); + const retry = getService('retry'); + const browser = getService('browser'); + const kibanaServer = getService('kibanaServer'); + + const PageObjects = getPageObjects(['common', 'context']); + const testSubjects = getService('testSubjects'); + + describe('context filters', function contextSize() { + before(async function () { + await kibanaServer.uiSettings.update({ + 'discover:rowHeightOption': 0, // to have more grid rows visible at once + }); + }); + + beforeEach(async function () { + await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID, { + columns: TEST_COLUMN_NAMES, + }); + }); + + it('inclusive filter should be addable via expanded data grid rows', async function () { + await retry.waitFor(`filter ${TEST_ANCHOR_FILTER_FIELD} in filterbar`, async () => { + await dataGrid.clickRowToggle({ isAnchorRow: true, renderMoreRows: true }); + await dataGrid.clickFieldActionInFlyout( + TEST_ANCHOR_FILTER_FIELD, + 'addFilterForValueButton' + ); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, true); + }); + + await dataGrid.closeFlyout(); + + await retry.waitFor(`filter matching docs in data grid`, async () => { + const fields = await dataGrid.getFields(); + return fields + .map((row) => row[2]) + .every((fieldContent) => fieldContent === TEST_ANCHOR_FILTER_VALUE); + }); + }); + + it('inclusive filter should be toggleable via the filter bar', async function () { + await filterBar.addFilter({ + field: TEST_ANCHOR_FILTER_FIELD, + operation: 'is', + value: TEST_ANCHOR_FILTER_VALUE, + }); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + // disable filter + await filterBar.toggleFilterEnabled(TEST_ANCHOR_FILTER_FIELD); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + await retry.waitFor(`a disabled filter in filterbar`, async () => { + return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, false); + }); + + await retry.waitFor('filters are disabled', async () => { + const fields = await dataGrid.getFields(); + const hasOnlyFilteredRows = fields + .map((row) => row[2]) + .every((fieldContent) => fieldContent === TEST_ANCHOR_FILTER_VALUE); + return hasOnlyFilteredRows === false; + }); + }); + + it('filter for presence should be addable via expanded data grid rows', async function () { + await retry.waitFor('an exists filter in the filterbar', async () => { + await dataGrid.clickRowToggle({ isAnchorRow: true, renderMoreRows: true }); + await dataGrid.clickFieldActionInFlyout(TEST_ANCHOR_FILTER_FIELD, 'addExistsFilterButton'); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, 'exists', true); + }); + }); + + const addPinnedFilter = async () => { + await filterBar.addFilter({ + field: TEST_ANCHOR_FILTER_FIELD, + operation: 'is', + value: TEST_ANCHOR_FILTER_VALUE, + }); + await filterBar.toggleFilterPinned(TEST_ANCHOR_FILTER_FIELD); + }; + + const everyFieldMatches = async (matches: (field: string[]) => boolean) => { + const fields = await dataGrid.getFields(); + return fields.every(matches); + }; + + it('should update the data grid when a pinned filter is modified', async function () { + await addPinnedFilter(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await everyFieldMatches((field) => field[2] === TEST_ANCHOR_FILTER_VALUE)).to.be(true); + await filterBar.toggleFilterNegated(TEST_ANCHOR_FILTER_FIELD); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await everyFieldMatches((field) => field[2] === TEST_ANCHOR_FILTER_VALUE)).to.be( + false + ); + }); + + const expectFiltersToExist = async () => { + expect(await filterBar.getFilterCount()).to.be(2); + expect( + await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, true, true) + ).to.be(true); + expect(await filterBar.hasFilter('extension', 'png')).to.be(true); + expect( + await everyFieldMatches( + (field) => field[1] === 'png' && field[2] === TEST_ANCHOR_FILTER_VALUE + ) + ).to.be(true); + }; + + it('should preserve filters when the page is refreshed', async function () { + await addPinnedFilter(); + await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'png' }); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + await expectFiltersToExist(); + await browser.refresh(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + await expectFiltersToExist(); + }); + + it('should update filters when navigating forward and backward in history', async () => { + await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'png' }); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilter('extension', 'png')).to.be(true); + expect(await everyFieldMatches((field) => field[1] === 'png')).to.be(true); + await browser.goBack(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(0); + expect(await everyFieldMatches((field) => field[1] === 'png')).to.be(false); + await browser.goForward(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilter('extension', 'png')).to.be(true); + expect(await everyFieldMatches((field) => field[1] === 'png')).to.be(true); + }); + + it('should add or filter', async () => { + await filterBar.addFilter({ + condition: 'OR', + filters: [ + { field: 'extension', operation: 'is', value: 'png' }, + { field: 'bytes', operation: 'is between', value: { from: '1000', to: '2000' } }, + ], + }); + + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilterWithId('0')).to.be(true); + + await filterBar.clickEditFilterById('0'); + + expect(await filterBar.getFilterEditorPreview()).to.equal( + 'extension: png OR bytes: 1,000B to 2KB' + ); + }); + + it('should add and filter', async () => { + await filterBar.addFilter({ + condition: 'AND', + filters: [ + { field: 'extension', operation: 'is one of', value: ['png', 'jpeg'] }, + { field: 'bytes', operation: 'is between', value: { from: '1000', to: '2000' } }, + ], + }); + + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilterWithId('0')).to.be(true); + + await filterBar.clickEditFilterById('0'); + + expect(await filterBar.getFilterEditorPreview()).to.equal( + 'extension: is one of png, jpeg AND bytes: 1,000B to 2KB' + ); + }); + + it('should add nested filters', async () => { + await filterBar.addFilter({ + condition: 'AND', + filters: [ + { + condition: 'OR', + filters: [ + { field: 'clientip', operation: 'does not exist' }, + { field: 'extension', operation: 'is one of', value: ['png', 'jpeg'] }, + ], + }, + { field: 'bytes', operation: 'is between', value: { from: '1000', to: '2000' } }, + ], + }); + + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilterWithId('0')).to.be(true); + + await filterBar.clickEditFilterById('0'); + + expect(await filterBar.getFilterEditorPreview()).to.equal( + '(NOT clientip: exists OR extension: is one of png, jpeg) AND bytes: 1,000B to 2KB' + ); + }); + + it('should add comma delimiter values', async () => { + await filterBar.addFilter({ field: 'extension', operation: 'is one of', value: 'png, jpeg' }); + + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + expect(await filterBar.hasFilterWithId('0')).to.be(true); + + await filterBar.clickEditFilterById('0'); + + expect(await filterBar.getFilterEditorPreview()).to.equal('extension: is one of png, jpeg'); + }); + + it('should display the negated values correctly', async () => { + await filterBar.addFilter({ field: 'extension', operation: 'is not', value: 'png' }); + + await PageObjects.context.waitUntilContextLoadingHasFinished(); + expect(await filterBar.getFilterCount()).to.be(1); + const filterLabel = await filterBar.getFiltersLabel(); + expect(filterLabel[0]).to.be('NOT extension: png'); + + await filterBar.clickEditFilterById('0'); + await filterBar.addAndFilter('0'); + await filterBar.createFilter({ field: 'extension', operation: 'is', value: 'jpeg' }, '0.1'); + await testSubjects.clickWhenNotDisabled('saveFilter'); + + const filterLabelUpdated = await filterBar.getFiltersLabel(); + expect(filterLabelUpdated[0]).to.be('NOT extension: png AND extension: jpeg'); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_size.ts b/x-pack/test_serverless/functional/test_suites/common/context/_size.ts new file mode 100644 index 000000000000..2daebf6ed0f8 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/context/_size.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const TEST_INDEX_PATTERN = 'logstash-*'; +const TEST_ANCHOR_ID = 'AU_x3_BrGFA8no6QjjaI'; +const TEST_DEFAULT_CONTEXT_SIZE = 2; +const TEST_STEP_SIZE = 2; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const security = getService('security'); + const retry = getService('retry'); + const dataGrid = getService('dataGrid'); + const browser = getService('browser'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['context']); + let expectedRowLength = 2 * TEST_DEFAULT_CONTEXT_SIZE + 1; + + describe('context size', function contextSize() { + before(async function () { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + await kibanaServer.uiSettings.update({ + 'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`, + 'context:step': `${TEST_STEP_SIZE}`, + }); + await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID); + }); + + it('should default to the `context:defaultSize` setting', async function () { + await retry.waitFor( + `number of rows displayed initially is ${expectedRowLength}`, + async function () { + const rows = await dataGrid.getRowsText(); + return rows.length === expectedRowLength; + } + ); + await retry.waitFor( + `predecessor count picker is set to ${TEST_DEFAULT_CONTEXT_SIZE}`, + async function () { + const predecessorCountPicker = await PageObjects.context.getPredecessorCountPicker(); + const value = await predecessorCountPicker.getAttribute('value'); + return value === String(TEST_DEFAULT_CONTEXT_SIZE); + } + ); + }); + + it('should increase according to the `context:step` setting when clicking the `load newer` button', async function () { + await PageObjects.context.clickPredecessorLoadMoreButton(); + expectedRowLength += TEST_STEP_SIZE; + + await retry.waitFor( + `number of rows displayed after clicking load more predecessors is ${expectedRowLength}`, + async function () { + const rows = await dataGrid.getRowsText(true); + return rows.length === expectedRowLength; + } + ); + }); + + it('should increase according to the `context:step` setting when clicking the `load older` button', async function () { + await PageObjects.context.clickSuccessorLoadMoreButton(); + expectedRowLength += TEST_STEP_SIZE; + + await retry.waitFor( + `number of rows displayed after clicking load more successors is ${expectedRowLength}`, + async function () { + const rows = await dataGrid.getRowsText(true); + return rows.length === expectedRowLength; + } + ); + }); + + it('should show 101 records when 50 newer and 50 older records are requests', async function () { + const predecessorCountPicker = await PageObjects.context.getPredecessorCountPicker(); + await predecessorCountPicker.clearValueWithKeyboard(); + await predecessorCountPicker.pressKeys('50'); + await predecessorCountPicker.pressKeys(browser.keys.ENTER); + + const successorCountPicker = await PageObjects.context.getSuccessorCountPicker(); + await successorCountPicker.clearValueWithKeyboard(); + await successorCountPicker.pressKeys('50'); + await successorCountPicker.pressKeys(browser.keys.ENTER); + + await retry.waitFor( + `number of rows displayed after clicking load more successors is ${expectedRowLength}`, + async function () { + const dataGridWrapper = await testSubjects.find('discoverDocTable'); + const length = await dataGridWrapper.getAttribute('data-document-number'); + return Number(length) === 101; + } + ); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/context/index.ts b/x-pack/test_serverless/functional/test_suites/common/context/index.ts new file mode 100644 index 000000000000..9ed486999e9f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/context/index.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ + getService, + getPageObjects, + loadTestFile, + getPageObject, +}: FtrProviderContext) { + const browser = getService('browser'); + const esArchiver = getService('esArchiver'); + const PageObjects = getPageObjects(['common']); + const kibanaServer = getService('kibanaServer'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('context app', function () { + before(async () => { + await browser.setWindowSize(1200, 800); + // TODO: Serverless tests require login first + await svlCommonPage.login(); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/visualize.json'); + await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); + await PageObjects.common.navigateToApp('discover'); + }); + + after(async () => { + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/visualize.json' + ); + }); + + loadTestFile(require.resolve('./_context_navigation')); + loadTestFile(require.resolve('./_discover_navigation')); + loadTestFile(require.resolve('./_filters')); + loadTestFile(require.resolve('./_size')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/_saved_search_embeddable.ts b/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/_saved_search_embeddable.ts new file mode 100644 index 000000000000..5b95dace01a6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/_saved_search_embeddable.ts @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const browser = getService('browser'); + const dataGrid = getService('dataGrid'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const dashboardPanelActions = getService('dashboardPanelActions'); + const dashboardReplacePanel = getService('dashboardReplacePanel'); + const filterBar = getService('filterBar'); + const queryBar = getService('queryBar'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'timePicker', 'discover']); + + describe('discover saved search embeddable', () => { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/dashboard/current/data'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/dashboard/current/kibana' + ); + await kibanaServer.uiSettings.replace({ + defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', + }); + await PageObjects.common.setTime({ + from: 'Sep 22, 2015 @ 00:00:00.000', + to: 'Sep 23, 2015 @ 00:00:00.000', + }); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await PageObjects.common.unsetTime(); + }); + + beforeEach(async () => { + await PageObjects.dashboard.navigateToApp(); + await filterBar.ensureFieldEditorModalIsClosed(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + }); + + const addSearchEmbeddableToDashboard = async () => { + await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + const rows = await dataGrid.getDocTableRows(); + expect(rows.length).to.be.above(0); + }; + + const refreshDashboardPage = async () => { + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + }; + + it('can save a search embeddable with a defined rows per page number', async function () { + const dashboardName = 'Dashboard with a Paginated Saved Search'; + await addSearchEmbeddableToDashboard(); + await dataGrid.checkCurrentRowsPerPageToBe(100); + + await PageObjects.dashboard.saveDashboard(dashboardName, { + waitDialogIsClosed: true, + exitFromEditMode: false, + }); + + await refreshDashboardPage(); + + await dataGrid.checkCurrentRowsPerPageToBe(100); + + await dataGrid.changeRowsPerPageTo(10); + + await PageObjects.dashboard.saveDashboard(dashboardName); + await refreshDashboardPage(); + + await dataGrid.checkCurrentRowsPerPageToBe(10); + }); + + it('should control columns correctly', async () => { + await addSearchEmbeddableToDashboard(); + await PageObjects.dashboard.switchToEditMode(); + + const cell = await dataGrid.getCellElement(0, 2); + expect(await cell.getVisibleText()).to.be('Sep 22, 2015 @ 23:50:13.253'); + await dataGrid.clickMoveColumnLeft('agent'); + + const cellAfter = await dataGrid.getCellElement(0, 2); + expect(await cellAfter.getVisibleText()).to.be( + 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)' + ); + + await dataGrid.clickRemoveColumn('agent'); + expect(await cell.getVisibleText()).to.be('Sep 22, 2015 @ 23:50:13.253'); + }); + + it('should render duplicate saved search embeddables', async () => { + await addSearchEmbeddableToDashboard(); + await addSearchEmbeddableToDashboard(); + const [firstGridCell, secondGridCell] = await dataGrid.getAllCellElements(); + const firstGridCellContent = await firstGridCell.getVisibleText(); + const secondGridCellContent = await secondGridCell.getVisibleText(); + + expect(firstGridCellContent).to.be.equal(secondGridCellContent); + }); + + it('should display an error', async () => { + await addSearchEmbeddableToDashboard(); + await queryBar.setQuery('bytes > 5000'); + await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.discover.getSavedSearchDocumentCount()).to.be('2,572 documents'); + await queryBar.setQuery('this < is not : a valid > query'); + await queryBar.submitQuery(); + await PageObjects.header.waitUntilLoadingHasFinished(); + const embeddableError = await testSubjects.find('embeddableError'); + const errorMessage = await embeddableError.findByTestSubject('errorMessageMarkdown'); + expect(await errorMessage.getVisibleText()).to.equal( + 'Expected AND, OR, end of input, whitespace but "n" found. this < is not : a valid > query ----------^' + ); + }); + + it('should replace a panel with a saved search', async () => { + await dashboardAddPanel.addVisualization('Rendering Test: datatable'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + await dashboardPanelActions.replacePanelByTitle('Rendering Test: datatable'); + await dashboardReplacePanel.replaceEmbeddable('Rendering-Test:-saved-search'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + await testSubjects.missingOrFail('embeddableError'); + expect(await PageObjects.discover.getSavedSearchDocumentCount()).to.be('4,633 documents'); + }); + + it('should not show the full screen button', async () => { + await addSearchEmbeddableToDashboard(); + await testSubjects.missingOrFail('dataGridFullScreenButton'); + }); + + it('should show the the grid toolbar', async () => { + await addSearchEmbeddableToDashboard(); + await testSubjects.existOrFail('dscGridToolbar'); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/index.ts new file mode 100644 index 000000000000..c27f827e74ff --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/embeddable/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile, getPageObject }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('discover/embeddable', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_saved_search_embeddable')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts new file mode 100644 index 000000000000..684278f7e863 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover.ts @@ -0,0 +1,341 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const browser = getService('browser'); + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const queryBar = getService('queryBar'); + const inspector = getService('inspector'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'header', + 'timePicker', + 'unifiedFieldList', + ]); + + const defaultSettings = { + defaultIndex: 'logstash-*', + }; + + describe('discover test', function describeIndexTests() { + before(async function () { + log.debug('load kibana index with default index pattern'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + // and load a set of makelogs data + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + }); + after(async () => { + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + }); + describe('query', function () { + const queryName1 = 'Query # 1'; + + it('should show correct time range string by timepicker', async function () { + const time = await PageObjects.timePicker.getTimeConfig(); + expect(time.start).to.be(PageObjects.timePicker.defaultStartTime); + expect(time.end).to.be(PageObjects.timePicker.defaultEndTime); + const rowData = await PageObjects.discover.getDocTableIndex(1); + log.debug('check the newest doc timestamp in UTC (check diff timezone in last test)'); + expect(rowData).to.contain('Sep 22, 2015 @ 23:50:13.253'); + }); + + it('save query should show toast message and display query name', async function () { + await PageObjects.discover.saveSearch(queryName1); + const actualQueryNameString = await PageObjects.discover.getCurrentQueryName(); + expect(actualQueryNameString).to.be(queryName1); + }); + + it('load query should show query name', async function () { + await PageObjects.discover.loadSavedSearch(queryName1); + + await retry.try(async function () { + expect(await PageObjects.discover.getCurrentQueryName()).to.be(queryName1); + }); + }); + + it('renaming a saved query should modify name in breadcrumb', async function () { + const queryName2 = 'Modified Query # 1'; + await PageObjects.discover.loadSavedSearch(queryName1); + await PageObjects.discover.saveSearch(queryName2); + + await retry.try(async function () { + expect(await PageObjects.discover.getCurrentQueryName()).to.be(queryName2); + }); + }); + + it('should show the correct hit count', async function () { + const expectedHitCount = '14,004'; + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be(expectedHitCount); + }); + }); + + it('should show correct time range string in chart', async function () { + const actualTimeString = await PageObjects.discover.getChartTimespan(); + const expectedTimeString = `${PageObjects.timePicker.defaultStartTime} - ${PageObjects.timePicker.defaultEndTime} (interval: Auto - 3 hours)`; + expect(actualTimeString).to.be(expectedTimeString); + }); + + it('should modify the time range when a bar is clicked', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.clickHistogramBar(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const time = await PageObjects.timePicker.getTimeConfig(); + // TODO: The Serverless sidebar causes `PageObjects.discover.clickHistogramBar()` + // to click a different range in the histogram, resulting in a different duration + expect(time.start).to.be('Sep 19, 2015 @ 06:31:44.000'); + expect(time.end).to.be('Sep 23, 2015 @ 18:31:44.000'); + await retry.waitForWithTimeout( + 'table to contain the right search result', + 3000, + async () => { + const rowData = await PageObjects.discover.getDocTableField(1); + log.debug(`The first timestamp value in doc table: ${rowData}`); + // TODO: The Serverless sidebar causes `PageObjects.discover.clickHistogramBar()` + // to click a different range in the histogram, resulting in a different timestamp + return rowData.includes('Sep 22, 2015 @ 23:50:13.253'); + } + ); + }); + + it('should show correct initial chart interval of Auto', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await testSubjects.click('unifiedHistogramQueryHits'); // to cancel out tooltips + const actualInterval = await PageObjects.discover.getChartInterval(); + + const expectedInterval = 'Auto'; + expect(actualInterval).to.be(expectedInterval); + }); + + it('should not show "no results"', async () => { + const isVisible = await PageObjects.discover.hasNoResults(); + expect(isVisible).to.be(false); + }); + + it('should reload the saved search with persisted query to show the initial hit count', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + // apply query some changes + await queryBar.setQuery('test'); + await queryBar.submitQuery(); + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('22'); + }); + + // reset to persisted state + await queryBar.clearQuery(); + await PageObjects.discover.revertUnsavedChanges(); + const expectedHitCount = '14,004'; + await retry.try(async function () { + expect(await queryBar.getQueryString()).to.be(''); + expect(await PageObjects.discover.getHitCount()).to.be(expectedHitCount); + }); + }); + }); + + describe('query #2, which has an empty time range', () => { + const fromTime = 'Jun 11, 1999 @ 09:22:11.000'; + const toTime = 'Jun 12, 1999 @ 11:21:04.000'; + + before(async () => { + log.debug('setAbsoluteRangeForAnotherQuery'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + it('should show "no results"', async () => { + await retry.waitFor('no results screen is displayed', async function () { + const isVisible = await PageObjects.discover.hasNoResults(); + return isVisible === true; + }); + }); + + it('should suggest a new time range is picked', async () => { + const isVisible = await PageObjects.discover.hasNoResultsTimepicker(); + expect(isVisible).to.be(true); + }); + + it('should show matches when time range is expanded', async () => { + await PageObjects.discover.expandTimeRangeAsSuggestedInNoResultsMessage(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await retry.try(async function () { + expect(await PageObjects.discover.hasNoResults()).to.be(false); + expect(await PageObjects.discover.getHitCountInt()).to.be.above(0); + }); + }); + }); + + describe('nested query', () => { + before(async () => { + log.debug('setAbsoluteRangeForAnotherQuery'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + it('should support querying on nested fields', async function () { + await queryBar.setQuery('nestedField:{ child: nestedValue }'); + await queryBar.submitQuery(); + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('1'); + }); + }); + }); + + describe('data-shared-item', function () { + it('should have correct data-shared-item title and description', async () => { + const expected = { + title: 'A Saved Search', + description: 'A Saved Search Description', + }; + + await retry.try(async () => { + await PageObjects.discover.loadSavedSearch(expected.title); + const { title, description } = + await PageObjects.common.getSharedItemTitleAndDescription(); + expect(title).to.eql(expected.title); + expect(description).to.eql(expected.description); + }); + }); + }); + + describe('time zone switch', () => { + it('should show bars in the correct time zone after switching', async function () { + await kibanaServer.uiSettings.update({ 'dateFormat:tz': 'America/Phoenix' }); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.awaitKibanaChrome(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await queryBar.clearQuery(); + + log.debug( + 'check that the newest doc timestamp is now -7 hours from the UTC time in the first test' + ); + const rowData = await PageObjects.discover.getDocTableIndex(1); + expect(rowData.startsWith('Sep 22, 2015 @ 16:50:13.253')).to.be.ok(); + }); + }); + + describe('invalid time range in URL', function () { + it('should get the default timerange', async function () { + await PageObjects.common.navigateToUrl('discover', '#/?_g=(time:(from:now-15m,to:null))', { + useActualUrl: true, + }); + await PageObjects.header.awaitKibanaChrome(); + const time = await PageObjects.timePicker.getTimeConfig(); + expect(time.start).to.be('~ 15 minutes ago'); + expect(time.end).to.be('now'); + }); + }); + + describe('managing fields', function () { + it('should add a field, sort by it, remove it and also sorting by it', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('_score'); + await PageObjects.discover.clickFieldSort('_score', 'Sort Low-High'); + const currentUrlWithScore = await browser.getCurrentUrl(); + expect(currentUrlWithScore).to.contain('_score'); + await PageObjects.unifiedFieldList.clickFieldListItemRemove('_score'); + const currentUrlWithoutScore = await browser.getCurrentUrl(); + expect(currentUrlWithoutScore).not.to.contain('_score'); + }); + it('should add a field with customLabel, sort by it, display it correctly', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('referer'); + await PageObjects.discover.clickFieldSort('referer', 'Sort A-Z'); + expect(await PageObjects.discover.getDocHeader()).to.have.string('Referer custom'); + expect(await PageObjects.unifiedFieldList.getAllFieldNames()).to.contain('Referer custom'); + const url = await browser.getCurrentUrl(); + expect(url).to.contain('referer'); + }); + }); + + describe('refresh interval', function () { + it('should refetch when autofresh is enabled', async () => { + const intervalS = 5; + await PageObjects.timePicker.startAutoRefresh(intervalS); + + const getRequestTimestamp = async () => { + // check inspector panel request stats for timestamp + await inspector.open(); + const requestStats = await inspector.getTableData(); + const requestStatsRow = requestStats.filter( + (r) => r && r[0] && r[0].includes('Request timestamp') + ); + if (!requestStatsRow || !requestStatsRow[0] || !requestStatsRow[0][1]) { + return ''; + } + await inspector.close(); + return requestStatsRow[0][1]; + }; + + const requestTimestampBefore = await getRequestTimestamp(); + await retry.waitFor('refetch because of refresh interval', async () => { + const requestTimestampAfter = await getRequestTimestamp(); + log.debug( + `Timestamp before: ${requestTimestampBefore}, Timestamp after: ${requestTimestampAfter}` + ); + return Boolean(requestTimestampAfter) && requestTimestampBefore !== requestTimestampAfter; + }); + }); + + after(async () => { + await inspector.close(); + await PageObjects.timePicker.pauseAutoRefresh(); + }); + }); + + describe('resizable layout panels', () => { + it('should allow resizing the histogram layout panels', async () => { + const resizeDistance = 100; + const topPanel = await testSubjects.find('unifiedHistogramResizablePanelFixed'); + const mainPanel = await testSubjects.find('unifiedHistogramResizablePanelFlex'); + const resizeButton = await testSubjects.find('unifiedHistogramResizableButton'); + const topPanelSize = (await topPanel.getPosition()).height; + const mainPanelSize = (await mainPanel.getPosition()).height; + await browser.dragAndDrop( + { location: resizeButton }, + { location: { x: 0, y: resizeDistance } } + ); + const newTopPanelSize = (await topPanel.getPosition()).height; + const newMainPanelSize = (await mainPanel.getPosition()).height; + expect(newTopPanelSize).to.be(topPanelSize + resizeDistance); + expect(newMainPanelSize).to.be(mainPanelSize - resizeDistance); + }); + + it('should allow resizing the sidebar layout panels', async () => { + const resizeDistance = 100; + const leftPanel = await testSubjects.find('discoverLayoutResizablePanelFixed'); + const mainPanel = await testSubjects.find('discoverLayoutResizablePanelFlex'); + const resizeButton = await testSubjects.find('discoverLayoutResizableButton'); + const leftPanelSize = (await leftPanel.getPosition()).width; + const mainPanelSize = (await mainPanel.getPosition()).width; + await browser.dragAndDrop( + { location: resizeButton }, + { location: { x: resizeDistance, y: 0 } } + ); + const newLeftPanelSize = (await leftPanel.getPosition()).width; + const newMainPanelSize = (await mainPanel.getPosition()).width; + expect(newLeftPanelSize).to.be(leftPanelSize + resizeDistance); + expect(newMainPanelSize).to.be(mainPanelSize - resizeDistance); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover_histogram.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover_histogram.ts new file mode 100644 index 000000000000..becf81ab3da9 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_discover_histogram.ts @@ -0,0 +1,336 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { TimeStrings } from '../../../../../../../test/functional/page_objects/common_page'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const elasticChart = getService('elasticChart'); + const kibanaServer = getService('kibanaServer'); + const security = getService('security'); + const PageObjects = getPageObjects([ + 'timePicker', + 'dashboard', + 'settings', + 'discover', + 'common', + 'header', + ]); + const defaultSettings = { + defaultIndex: 'long-window-logstash-*', + 'dateFormat:tz': 'Europe/Berlin', + }; + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const retry = getService('retry'); + const log = getService('log'); + const queryBar = getService('queryBar'); + + describe('discover histogram', function describeIndexTests() { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.load('test/functional/fixtures/es_archiver/long_window_logstash'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern' + ); + await security.testUser.setRoles(['kibana_admin', 'long_window_logstash']); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + }); + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/long_window_logstash'); + await kibanaServer.savedObjects.cleanStandardList(); + await security.testUser.restoreDefaults(); + await PageObjects.common.unsetTime(); + }); + + async function prepareTest(time: TimeStrings, interval?: string) { + await PageObjects.common.setTime(time); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + if (interval) { + await PageObjects.discover.setChartInterval(interval); + await PageObjects.header.waitUntilLoadingHasFinished(); + } + } + + it('should modify the time range when the histogram is brushed', async function () { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + // this is the number of renderings of the histogram needed when new data is fetched + let renderingCountInc = 1; + const prevRenderingCount = await elasticChart.getVisualizationRenderingCount(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await retry.waitFor('chart rendering complete', async () => { + const actualCount = await elasticChart.getVisualizationRenderingCount(); + const expectedCount = prevRenderingCount + renderingCountInc; + log.debug(`renderings before brushing - actual: ${actualCount} expected: ${expectedCount}`); + return actualCount === expectedCount; + }); + let prevRowData = ''; + // to make sure the table is already rendered + await retry.try(async () => { + prevRowData = await PageObjects.discover.getDocTableField(1); + log.debug(`The first timestamp value in doc table before brushing: ${prevRowData}`); + }); + + await PageObjects.discover.brushHistogram(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + renderingCountInc = 2; + await retry.waitFor('chart rendering complete after being brushed', async () => { + const actualCount = await elasticChart.getVisualizationRenderingCount(); + const expectedCount = prevRenderingCount + renderingCountInc * 2; + log.debug(`renderings after brushing - actual: ${actualCount} expected: ${expectedCount}`); + return actualCount <= expectedCount; + }); + const newDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + // TODO: The Serverless sidebar causes `PageObjects.discover.brushHistogram()` + // to brush a different range in the histogram, resulting in a different duration + expect(Math.round(newDurationHours)).to.be(31); + + await retry.waitFor('doc table containing the documents of the brushed range', async () => { + const rowData = await PageObjects.discover.getDocTableField(1); + log.debug(`The first timestamp value in doc table after brushing: ${rowData}`); + return prevRowData !== rowData; + }); + }); + + it('should update correctly when switching data views and brushing the histogram', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.selectIndexPattern('logstash-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.selectIndexPattern('long-window-logstash-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.brushHistogram(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + // TODO: The Serverless sidebar causes `PageObjects.discover.brushHistogram()` + // to brush a different range in the histogram, resulting in a different count + expect(await PageObjects.discover.getHitCount()).to.be('12'); + }); + + it('should update the histogram timerange when the query is resubmitted', async function () { + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': '{ "from": "2015-09-18T19:37:13.000Z", "to": "now"}', + }); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.awaitKibanaChrome(); + const initialTimeString = await PageObjects.discover.getChartTimespan(); + await queryBar.clickQuerySubmitButton(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await retry.waitFor('chart timespan to have changed', async () => { + const refreshedTimeString = await PageObjects.discover.getChartTimespan(); + await queryBar.clickQuerySubmitButton(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + log.debug( + `Timestamp before: ${initialTimeString}, Timestamp after: ${refreshedTimeString}` + ); + return refreshedTimeString !== initialTimeString; + }); + }); + + it('should visualize monthly data with different day intervals', async () => { + const from = 'Nov 1, 2017 @ 00:00:00.000'; + const to = 'Mar 21, 2018 @ 00:00:00.000'; + await prepareTest({ from, to }, 'Month'); + const chartCanvasExist = await elasticChart.canvasExists(); + expect(chartCanvasExist).to.be(true); + }); + it('should visualize weekly data with within DST changes', async () => { + const from = 'Mar 1, 2018 @ 00:00:00.000'; + const to = 'May 1, 2018 @ 00:00:00.000'; + await prepareTest({ from, to }, 'Week'); + const chartCanvasExist = await elasticChart.canvasExists(); + expect(chartCanvasExist).to.be(true); + }); + it('should visualize monthly data with different years scaled to 30 days', async () => { + const from = 'Jan 1, 2010 @ 00:00:00.000'; + const to = 'Mar 21, 2019 @ 00:00:00.000'; + await prepareTest({ from, to }, 'Day'); + const chartCanvasExist = await elasticChart.canvasExists(); + expect(chartCanvasExist).to.be(true); + const chartIntervalIconTip = await PageObjects.discover.getChartIntervalWarningIcon(); + expect(chartIntervalIconTip).to.be(true); + }); + it('should allow hide/show histogram, persisted in url state', async () => { + const from = 'Jan 1, 2010 @ 00:00:00.000'; + const to = 'Mar 21, 2019 @ 00:00:00.000'; + await prepareTest({ from, to }); + let canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + }); + // histogram is hidden, when reloading the page it should remain hidden + await browser.refresh(); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + }); + }); + it('should allow hiding the histogram, persisted in saved search', async () => { + const from = 'Jan 1, 2010 @ 00:00:00.000'; + const to = 'Mar 21, 2019 @ 00:00:00.000'; + const savedSearch = 'persisted hidden histogram'; + await prepareTest({ from, to }); + + // close chart for saved search + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + let canvasExists: boolean; + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + }); + + // save search + await PageObjects.discover.saveSearch(savedSearch); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // open new search + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // load saved search + await PageObjects.discover.loadSavedSearch(savedSearch); + await PageObjects.header.waitUntilLoadingHasFinished(); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + + // open chart for saved search + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await retry.waitFor(`Discover histogram to be displayed`, async () => { + canvasExists = await elasticChart.canvasExists(); + return canvasExists; + }); + + // save search + await PageObjects.discover.saveSearch(savedSearch); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // open new search + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // load saved search + await PageObjects.discover.loadSavedSearch(savedSearch); + await PageObjects.header.waitUntilLoadingHasFinished(); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + }); + it('should show permitted hidden histogram state when returning back to discover', async () => { + // close chart + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + let canvasExists: boolean; + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + }); + + // save search + await PageObjects.discover.saveSearch('persisted hidden histogram'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // open chart + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + }); + + // go to dashboard + await PageObjects.dashboard.navigateToApp(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // go to discover + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + + // close chart + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await retry.try(async () => { + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + }); + }); + + it('should recover from broken query search when clearing the query bar', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + // Make sure the chart is visible + await testSubjects.click('unifiedHistogramChartOptionsToggle'); + await testSubjects.click('unifiedHistogramChartToggle'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + // type an invalid search query, hit refresh + await queryBar.setQuery('this is > not valid'); + await queryBar.submitQuery(); + + await PageObjects.discover.showsErrorCallout(); + + // now remove the query + await queryBar.clearQuery(); + await queryBar.submitQuery(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + // check no error state + expect(await PageObjects.discover.isChartVisible()).to.be(true); + }); + + it('should reset all histogram state when resetting the saved search', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + const savedSearch = 'histogram state'; + await PageObjects.discover.saveSearch(savedSearch); + await PageObjects.discover.chooseBreakdownField('extension.keyword'); + await PageObjects.discover.setChartInterval('Second'); + let requestData = await testSubjects.getAttribute( + 'unifiedHistogramChart', + 'data-request-data' + ); + expect(JSON.parse(requestData)).to.eql({ + dataViewId: 'long-window-logstash-*', + timeField: '@timestamp', + timeInterval: 's', + breakdownField: 'extension.keyword', + }); + await PageObjects.discover.toggleChartVisibility(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.revertUnsavedChanges(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + requestData = await testSubjects.getAttribute('unifiedHistogramChart', 'data-request-data'); + expect(JSON.parse(requestData)).to.eql({ + dataViewId: 'long-window-logstash-*', + timeField: '@timestamp', + timeInterval: 'auto', + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_url_state.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_url_state.ts new file mode 100644 index 000000000000..13629a600793 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/_url_state.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const browser = getService('browser'); + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const filterBar = getService('filterBar'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'header', + 'timePicker', + 'unifiedFieldList', + 'visualize', + 'svlCommonNavigation', + ]); + + const defaultSettings = { + defaultIndex: 'logstash-*', + }; + + describe('discover URL state', () => { + before(async function () { + log.debug('load kibana index with default index pattern'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + // and load a set of makelogs data + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + }); + + after(async () => { + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + }); + + it('should show a warning and fall back to the default data view when navigating to a URL with an invalid data view ID', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + const dataViewId = await PageObjects.discover.getCurrentDataViewId(); + const originalUrl = await browser.getCurrentUrl(); + const newUrl = originalUrl.replace(dataViewId, 'invalid-data-view-id'); + await browser.get(newUrl); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async () => { + expect(await browser.getCurrentUrl()).to.be(originalUrl); + expect(await testSubjects.exists('dscDataViewNotFoundShowDefaultWarning')).to.be(true); + }); + }); + + it('should show a warning and fall back to the current data view if the URL is updated to an invalid data view ID', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + const originalHash = await browser.execute<[], string>('return window.location.hash'); + const dataViewId = await PageObjects.discover.getCurrentDataViewId(); + const newHash = originalHash.replace(dataViewId, 'invalid-data-view-id'); + await browser.execute(`window.location.hash = "${newHash}"`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async () => { + const currentHash = await browser.execute<[], string>('return window.location.hash'); + expect(currentHash).to.be(originalHash); + expect(await testSubjects.exists('dscDataViewNotFoundShowSavedWarning')).to.be(true); + }); + }); + + describe('Side nav', function () { + // Discover does not exist in Serverless O11y side nav (Log Explorer instead) + this.tags('skipSvlOblt'); + + it('should sync Lens global state to Discover sidebar link and carry over the state when navigating to Discover', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.common.navigateToApp('lens'); + // TODO: Sidebar links works differently in Serverless + let discoverLink = await PageObjects.svlCommonNavigation.sidenav.findLink({ + deepLinkId: 'discover', + }); + expect(await discoverLink?.getAttribute('href')).to.contain( + '/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-15m,to:now))' + + "&_a=(columns:!(),filters:!(),index:'logstash-*',interval:auto,query:(language:kuery,query:''),sort:!(!('@timestamp',desc)))" + ); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await filterBar.addFilter({ + field: 'extension.raw', + operation: 'is one of', + value: ['jpg', 'css'], + }); + await filterBar.toggleFilterPinned('extension.raw'); + await PageObjects.header.waitUntilLoadingHasFinished(); + discoverLink = await PageObjects.svlCommonNavigation.sidenav.findLink({ + deepLinkId: 'discover', + }); + expect(await discoverLink?.getAttribute('href')).to.contain( + "/app/discover#/?_g=(filters:!(('$state':(store:globalState)," + + "meta:(alias:!n,disabled:!f,field:extension.raw,index:'logstash-*'," + + 'key:extension.raw,negate:!f,params:!(jpg,css),type:phrases,value:!(jpg,css)),' + + 'query:(bool:(minimum_should_match:1,should:!((match_phrase:(extension.raw:jpg)),' + + "(match_phrase:(extension.raw:css))))))),query:(language:kuery,query:'')," + + "refreshInterval:(pause:!t,value:60000),time:(from:'2015-09-19T06:31:44.000Z'," + + "to:'2015-09-23T18:31:44.000Z'))&_a=(columns:!(),filters:!(),index:'logstash-*'," + + "interval:auto,query:(language:kuery,query:''),sort:!(!('@timestamp',desc)))" + ); + await PageObjects.svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await filterBar.hasFilter('extension.raw', '', undefined, true)).to.be(true); + expect(await filterBar.isFilterPinned('extension.raw')).to.be(true); + expect(await PageObjects.timePicker.getTimeConfig()).to.eql({ + start: 'Sep 19, 2015 @ 06:31:44.000', + end: 'Sep 23, 2015 @ 18:31:44.000', + }); + expect(await PageObjects.discover.getHitCount()).to.be('11,268'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts new file mode 100644 index 000000000000..0365d037e8f3 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile, getPageObject }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('discover/group1', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_discover')); + loadTestFile(require.resolve('./_discover_histogram')); + loadTestFile(require.resolve('./_url_state')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_adhoc_data_views.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_adhoc_data_views.ts new file mode 100644 index 000000000000..03dd58892e5c --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_adhoc_data_views.ts @@ -0,0 +1,279 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const dataGrid = getService('dataGrid'); + const toasts = getService('toasts'); + const esArchiver = getService('esArchiver'); + const filterBar = getService('filterBar'); + const fieldEditor = getService('fieldEditor'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); + const queryBar = getService('queryBar'); + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const PageObjects = getPageObjects([ + 'common', + 'unifiedSearch', + 'discover', + 'timePicker', + 'settings', + 'header', + 'context', + 'dashboard', + 'unifiedFieldList', + 'svlCommonNavigation', + ]); + const security = getService('security'); + + const addSearchToDashboard = async (name: string) => { + await dashboardAddPanel.addSavedSearch(name); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + }; + + describe('adhoc data views', function () { + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); + }); + + it('should navigate back correctly from to surrounding and single views', async () => { + await PageObjects.discover.createAdHocDataView('logstash', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + const first = await PageObjects.discover.getCurrentDataViewId(); + + await PageObjects.discover.addRuntimeField( + '_bytes-runtimefield', + `emit(doc["bytes"].value.toString())` + ); + await PageObjects.unifiedFieldList.clickFieldListItemToggle('_bytes-runtimefield'); + + const second = await PageObjects.discover.getCurrentDataViewId(); + expect(first).not.to.equal(second); + + // navigate to context view + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const [, surrDocs] = await dataGrid.getRowActions({ rowIndex: 0 }); + await surrDocs.click(); + await PageObjects.context.waitUntilContextLoadingHasFinished(); + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ deepLinkId: 'discover' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await PageObjects.discover.getCurrentlySelectedDataView()).to.be('logstash*'); + + // navigate to single doc view + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const [singleView] = await dataGrid.getRowActions({ rowIndex: 0 }); + await singleView.click(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ deepLinkId: 'discover' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await PageObjects.discover.getCurrentlySelectedDataView()).to.be('logstash*'); + }); + + it('should support query and filtering', async () => { + await filterBar.addFilter({ + field: 'nestedField.child', + operation: 'is', + value: 'nestedValue', + }); + expect(await filterBar.hasFilter('nestedField.child', 'nestedValue')).to.be(true); + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('1'); + }); + await filterBar.removeFilter('nestedField.child'); + + await queryBar.setQuery('test'); + await queryBar.submitQuery(); + await retry.try(async () => expect(await PageObjects.discover.getHitCount()).to.be('22')); + + await queryBar.clearQuery(); + await queryBar.submitQuery(); + }); + + it('should not update data view id when saving search first time', async () => { + const prevDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + await PageObjects.discover.saveSearch('logstash*-ss'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const newDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + expect(prevDataViewId).to.equal(newDataViewId); + }); + + it('should update data view id when saving new search copy', async () => { + const prevDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + await PageObjects.discover.saveSearch('logstash*-ss-new', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const newDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + expect(prevDataViewId).not.to.equal(newDataViewId); + }); + + it('search results should be different after data view update', async () => { + await PageObjects.discover.createAdHocDataView('logst', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + const prevDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + // trigger data view id update + await PageObjects.discover.addRuntimeField( + '_bytes-runtimefield', + `emit(doc["bytes"].value.toString())` + ); + await PageObjects.unifiedFieldList.clickFieldListItemToggle('_bytes-runtimefield'); + const newDataViewId = await PageObjects.discover.getCurrentDataViewId(); + expect(newDataViewId).not.to.equal(prevDataViewId); + + // save first search + await PageObjects.discover.saveSearch('logst*-ss-_bytes-runtimefield'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // remove field and create with the same name, but different value + await PageObjects.unifiedFieldList.clickFieldListItemRemove('_bytes-runtimefield'); + await PageObjects.discover.removeField('_bytes-runtimefield'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // trigger data view id update + await PageObjects.discover.addRuntimeField( + '_bytes-runtimefield', + `emit((doc["bytes"].value * 2).toString())` + ); + await PageObjects.unifiedFieldList.clickFieldListItemToggle('_bytes-runtimefield'); + + // save second search + await PageObjects.discover.saveSearch('logst*-ss-_bytes-runtimefield-updated', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // open searches on dashboard + await PageObjects.dashboard.navigateToApp(); + await filterBar.ensureFieldEditorModalIsClosed(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + + await addSearchToDashboard('logst*-ss-_bytes-runtimefield'); + await addSearchToDashboard('logst*-ss-_bytes-runtimefield-updated'); + + const [firstSearchCell, secondSearchCell] = await dataGrid.getAllCellElements(0, 3); + const first = await firstSearchCell.getVisibleText(); + const second = await secondSearchCell.getVisibleText(); + + expect(+second).to.equal(+first * 2); + }); + + it('should open saved search by navigation to context from embeddable', async () => { + // navigate to context view + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const [, surrDocs] = await dataGrid.getRowActions({ rowIndex: 0 }); + await surrDocs.click(); + + // close popup + const alert = await browser.getAlert(); + await alert?.accept(); + if (await testSubjects.exists('confirmModalConfirmButton')) { + await testSubjects.click('confirmModalConfirmButton'); + } + await PageObjects.context.waitUntilContextLoadingHasFinished(); + + // open saved search + // TODO: Clicking breadcrumbs works differently in Serverless + await PageObjects.svlCommonNavigation.breadcrumbs.clickBreadcrumb({ deepLinkId: 'discover' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // TODO: Getting breadcrumbs works differently in Serverless + const savedSearch = await PageObjects.svlCommonNavigation.breadcrumbs.getBreadcrumb({ + deepLinkId: 'discover', + }); + const savedSearchName = await savedSearch?.getVisibleText(); + // TODO: This functionality is broken in Serverless: https://github.com/elastic/kibana/issues/163488 + expect(savedSearchName).to.be.equal('Discover'); + await PageObjects.discover.loadSavedSearch('logst*-ss-_bytes-runtimefield'); + + // test the header now + const header = await dataGrid.getHeaderFields(); + expect(header.join(' ')).to.have.string('_bytes-runtimefield'); + }); + + it('should update id after data view field edit', async () => { + await PageObjects.discover.loadSavedSearch('logst*-ss-_bytes-runtimefield'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const prevDataViewId = await PageObjects.discover.getCurrentDataViewId(); + + // trigger data view id update + await dataGrid.clickEditField('_bytes-runtimefield'); + await fieldEditor.setName('_bytes-runtimefield-edited', true); + await fieldEditor.save(); + await fieldEditor.confirmSave(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const newDataViewId = await PageObjects.discover.getCurrentDataViewId(); + expect(prevDataViewId).not.to.equal(newDataViewId); + }); + + it('should notify about invalid filter reffs', async () => { + await PageObjects.discover.createAdHocDataView('logstas', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await filterBar.addFilter({ + field: 'nestedField.child', + operation: 'is', + value: 'nestedValue', + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'jpg' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const first = await PageObjects.discover.getCurrentDataViewId(); + // trigger data view id update + await PageObjects.discover.addRuntimeField( + '_bytes-runtimefield', + `emit((doc["bytes"].value * 2).toString())` + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const second = await PageObjects.discover.getCurrentDataViewId(); + expect(first).not.equal(second); + + await toasts.dismissAllToasts(); + + await browser.goBack(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const [firstToast, secondToast] = await toasts.getAllToastElements(); + + expect([await firstToast.getVisibleText(), await secondToast.getVisibleText()].sort()).to.eql( + [ + `"${first}" is not a configured data view ID\nShowing the saved data view: "logstas*" (${second})`, + `Different index references\nData view id references in some of the applied filters differ from the current data view.`, + ].sort() + ); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_navigation.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_navigation.ts new file mode 100644 index 000000000000..d690efea7693 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_navigation.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const filterBar = getService('filterBar'); + const dataGrid = getService('dataGrid'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'discover', 'timePicker', 'context']); + const esArchiver = getService('esArchiver'); + const retry = getService('retry'); + const kibanaServer = getService('kibanaServer'); + const security = getService('security'); + const defaultSettings = { defaultIndex: 'logstash-*' }; + + describe('discover data grid doc link', function () { + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + }); + + after(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + beforeEach(async function () { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + }); + + it('should open the doc view of the selected document', async function () { + // navigate to the doc view + await dataGrid.clickRowToggle({ rowIndex: 0 }); + + // click the open action + await retry.try(async () => { + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + if (!rowActions.length) { + throw new Error('row actions empty, trying again'); + } + await rowActions[0].click(); + }); + + await retry.waitFor('hit loaded', async () => { + const hasDocHit = await testSubjects.exists('doc-hit'); + return !!hasDocHit; + }); + }); + + it('should create an exists filter from doc view of the selected document', async function () { + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await dataGrid.clickRowToggle({ rowIndex: 0 }); + await dataGrid.clickFieldActionInFlyout('@timestamp', 'addExistsFilterButton'); + + const hasExistsFilter = await filterBar.hasFilter('@timestamp', 'exists', true, false, false); + expect(hasExistsFilter).to.be(true); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts new file mode 100644 index 000000000000..99e9cd721fed --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts @@ -0,0 +1,254 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const dataGrid = getService('dataGrid'); + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const monacoEditor = getService('monacoEditor'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'header', + 'timePicker', + 'dashboard', + 'unifiedFieldList', + ]); + const defaultSettings = { + defaultIndex: 'logstash-*', + 'discover:rowHeightOption': 0, // single line + }; + const testSubjects = getService('testSubjects'); + const security = getService('security'); + + describe('discover data grid doc table', function describeIndexTests() { + before(async function () { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + log.debug('load kibana index with default index pattern'); + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + }); + + beforeEach(async () => { + await PageObjects.common.navigateToApp('discover'); + }); + + after(async function () { + log.debug('reset uiSettings'); + await kibanaServer.uiSettings.replace({}); + }); + + it('should show rows by default', async function () { + // with the default range the number of hits is ~14000 + const rows = await dataGrid.getDocTableRows(); + expect(rows.length).to.be.above(0); + }); + + it('should refresh the table content when changing time window', async function () { + const initialRows = await dataGrid.getDocTableRows(); + + const fromTime = 'Sep 20, 2015 @ 23:00:00.000'; + const toTime = 'Sep 20, 2015 @ 23:14:00.000'; + + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + const finalRows = await PageObjects.discover.getDocTableRows(); + expect(finalRows.length).to.be.below(initialRows.length); + }); + + it('should show popover with expanded cell content by click on expand button', async () => { + log.debug('open popover with expanded cell content to get json from the editor'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await retry.waitForWithTimeout('timestamp matches expected doc', 5000, async () => { + const cell = await dataGrid.getCellElement(0, 2); + const text = await cell.getVisibleText(); + log.debug(`row document timestamp: ${text}`); + return text === 'Sep 22, 2015 @ 23:50:13.253'; + }); + + await dataGrid.clickCellExpandButton(0, 3); + + let expandDocId = ''; + await retry.waitForWithTimeout('expandDocId to be valid', 5000, async () => { + const text = await monacoEditor.getCodeEditorValue(); + const flyoutJson = JSON.parse(text); + expandDocId = flyoutJson._id; + return expandDocId === 'AU_x3_g4GFA8no6QjkYX'; + }); + log.debug(`expanded document id: ${expandDocId}`); + + await dataGrid.clickRowToggle(); + await find.clickByCssSelectorWhenNotDisabledWithoutRetry('#kbn_doc_viewer_tab_1'); + + await retry.waitForWithTimeout( + 'document id in flyout matching the expanded document id', + 5000, + async () => { + const text = await monacoEditor.getCodeEditorValue(); + const flyoutJson = JSON.parse(text); + log.debug(`flyout document id: ${flyoutJson._id}`); + return flyoutJson._id === expandDocId; + } + ); + }); + + it('should show popover with expanded cell content by click on expand button on embeddable', async () => { + log.debug('open popover with expanded cell content to get json from the editor'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.saveSearch('expand-cell-search'); + + await PageObjects.dashboard.navigateToApp(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await dashboardAddPanel.addSavedSearch('expand-cell-search'); + + await retry.waitForWithTimeout('timestamp matches expected doc', 5000, async () => { + const cell = await dataGrid.getCellElement(0, 2); + const text = await cell.getVisibleText(); + log.debug(`row document timestamp: ${text}`); + return text === 'Sep 22, 2015 @ 23:50:13.253'; + }); + await dataGrid.clickCellExpandButton(0, 3); + + let expandDocId = ''; + await retry.waitForWithTimeout('expandDocId to be valid', 5000, async () => { + const text = await monacoEditor.getCodeEditorValue(); + return (expandDocId = JSON.parse(text)._id) === 'AU_x3_g4GFA8no6QjkYX'; + }); + log.debug(`expanded document id: ${expandDocId}`); + + await dataGrid.clickRowToggle(); + await find.clickByCssSelectorWhenNotDisabledWithoutRetry('#kbn_doc_viewer_tab_1'); + + await retry.waitForWithTimeout( + 'document id in flyout matching the expanded document id', + 5000, + async () => { + const text = await monacoEditor.getCodeEditorValue(); + const flyoutJson = JSON.parse(text); + log.debug(`flyout document id: ${flyoutJson._id}`); + return flyoutJson._id === expandDocId; + } + ); + }); + + describe('expand a document row', function () { + const rowToInspect = 1; + + it('should expand the detail row when the toggle arrow is clicked', async function () { + await retry.try(async function () { + await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); + const detailsEl = await dataGrid.getDetailsRows(); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + expect(defaultMessageEl).to.be.ok(); + await dataGrid.closeFlyout(); + }); + }); + + it('should show the detail panel actions', async function () { + await retry.try(async function () { + await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); + const [surroundingActionEl, singleActionEl] = await dataGrid.getRowActions({ + isAnchorRow: false, + rowIndex: rowToInspect - 1, + }); + expect(surroundingActionEl).to.be.ok(); + expect(singleActionEl).to.be.ok(); + await dataGrid.closeFlyout(); + }); + }); + + it('should allow paginating docs in the flyout by clicking in the doc table', async function () { + await retry.try(async function () { + await dataGrid.clickRowToggle({ rowIndex: rowToInspect - 1 }); + await testSubjects.exists(`dscDocNavigationPage0`); + await dataGrid.clickRowToggle({ rowIndex: rowToInspect }); + await testSubjects.exists(`dscDocNavigationPage1`); + await dataGrid.closeFlyout(); + }); + }); + + it('should show allow adding columns from the detail panel', async function () { + await retry.try(async function () { + await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); + + // add columns + const fields = ['_id', '_index', 'agent']; + for (const field of fields) { + await dataGrid.clickFieldActionInFlyout(field, 'toggleColumnButton'); + } + + const headerWithFields = await dataGrid.getHeaderFields(); + expect(headerWithFields.join(' ')).to.contain(fields.join(' ')); + + // remove columns + for (const field of fields) { + await dataGrid.clickFieldActionInFlyout(field, 'toggleColumnButton'); + } + + const headerWithoutFields = await dataGrid.getHeaderFields(); + expect(headerWithoutFields.join(' ')).not.to.contain(fields.join(' ')); + + await dataGrid.closeFlyout(); + }); + }); + }); + + describe('add and remove columns', function () { + const extraColumns = ['phpmemory', 'ip']; + + afterEach(async function () { + for (const column of extraColumns) { + await PageObjects.unifiedFieldList.clickFieldListItemRemove(column); + await PageObjects.header.waitUntilLoadingHasFinished(); + } + }); + + it('should add more columns to the table', async function () { + for (const column of extraColumns) { + await PageObjects.unifiedFieldList.clearFieldSearchInput(); + await PageObjects.unifiedFieldList.findFieldByName(column); + await PageObjects.unifiedFieldList.clickFieldListItemAdd(column); + await PageObjects.header.waitUntilLoadingHasFinished(); + // test the header now + const header = await dataGrid.getHeaderFields(); + expect(header.join(' ')).to.have.string(column); + } + }); + + it('should remove columns from the table', async function () { + for (const column of extraColumns) { + await PageObjects.unifiedFieldList.clearFieldSearchInput(); + await PageObjects.unifiedFieldList.findFieldByName(column); + await PageObjects.unifiedFieldList.clickFieldListItemAdd(column); + await PageObjects.header.waitUntilLoadingHasFinished(); + } + // remove the second column + await PageObjects.unifiedFieldList.clickFieldListItemRemove(extraColumns[1]); + await PageObjects.header.waitUntilLoadingHasFinished(); + // test that the second column is no longer there + const header = await dataGrid.getHeaderFields(); + expect(header.join(' ')).to.not.have.string(extraColumns[1]); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts new file mode 100644 index 000000000000..72243eaa2404 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile, getPageObject }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('discover/group2', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_data_grid_doc_navigation')); + loadTestFile(require.resolve('./_data_grid_doc_table')); + loadTestFile(require.resolve('./_adhoc_data_views')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts new file mode 100644 index 000000000000..8e373bae57ad --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts @@ -0,0 +1,226 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'timePicker', + 'header', + 'unifiedSearch', + 'settings', + ]); + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const filterBar = getService('filterBar'); + const queryBar = getService('queryBar'); + const elasticChart = getService('elasticChart'); + + describe('discover request counts', function describeIndexTests() { + before(async function () { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/long_window_logstash'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern' + ); + await kibanaServer.uiSettings.replace({ + defaultIndex: 'logstash-*', + 'bfetch:disable': true, + // TODO: Removed ES|QL setting since ES|QL isn't supported in Serverless + }); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + }); + + after(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.replace({}); + }); + + beforeEach(async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + + const getSearchCount = async (type: 'ese' | 'esql') => { + const requests = await browser.execute(() => + performance + .getEntries() + .filter((entry: any) => ['fetch', 'xmlhttprequest'].includes(entry.initiatorType)) + ); + return requests.filter((entry) => entry.name.endsWith(`/internal/search/${type}`)).length; + }; + + const waitForLoadingToFinish = async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitForDocTableLoadingComplete(); + await elasticChart.canvasExists(); + }; + + const expectSearches = async (type: 'ese' | 'esql', expected: number, cb: Function) => { + await browser.execute(async () => { + performance.clearResourceTimings(); + }); + let searchCount = await getSearchCount(type); + expect(searchCount).to.be(0); + await cb(); + await waitForLoadingToFinish(); + searchCount = await getSearchCount(type); + expect(searchCount).to.be(expected); + }; + + const getSharedTests = ({ + type, + savedSearch, + query1, + query2, + savedSearchesRequests, + setQuery, + }: { + type: 'ese' | 'esql'; + savedSearch: string; + query1: string; + query2: string; + savedSearchesRequests?: number; + setQuery: (query: string) => Promise; + }) => { + it('should send 2 search requests (documents + chart) on page load', async () => { + await browser.refresh(); + await browser.execute(async () => { + performance.setResourceTimingBufferSize(Number.MAX_SAFE_INTEGER); + }); + await waitForLoadingToFinish(); + const searchCount = await getSearchCount(type); + expect(searchCount).to.be(2); + }); + + it('should send 2 requests (documents + chart) when refreshing', async () => { + await expectSearches(type, 2, async () => { + await queryBar.clickQuerySubmitButton(); + }); + }); + + it('should send 2 requests (documents + chart) when changing the query', async () => { + await expectSearches(type, 2, async () => { + await setQuery(query1); + await queryBar.clickQuerySubmitButton(); + }); + }); + + it('should send 2 requests (documents + chart) when changing the time range', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.timePicker.setAbsoluteRange( + 'Sep 21, 2015 @ 06:31:44.000', + 'Sep 23, 2015 @ 00:00:00.000' + ); + }); + }); + + it('should send 2 requests (documents + chart) when toggling the chart visibility', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.discover.toggleChartVisibility(); + }); + await expectSearches(type, 2, async () => { + await PageObjects.discover.toggleChartVisibility(); + }); + }); + + it('should send 2 requests for saved search changes', async () => { + await setQuery(query1); + await queryBar.clickQuerySubmitButton(); + await PageObjects.timePicker.setAbsoluteRange( + 'Sep 21, 2015 @ 06:31:44.000', + 'Sep 23, 2015 @ 00:00:00.000' + ); + await waitForLoadingToFinish(); + // TODO: Check why the request happens 4 times in case of opening a saved search + // https://github.com/elastic/kibana/issues/165192 + // creating the saved search + await expectSearches(type, savedSearchesRequests ?? 2, async () => { + await PageObjects.discover.saveSearch(savedSearch); + }); + // resetting the saved search + await setQuery(query2); + await queryBar.clickQuerySubmitButton(); + await waitForLoadingToFinish(); + await expectSearches(type, 2, async () => { + await PageObjects.discover.revertUnsavedChanges(); + }); + // clearing the saved search + await expectSearches('ese', 2, async () => { + await testSubjects.click('discoverNewButton'); + await waitForLoadingToFinish(); + }); + // loading the saved search + // TODO: https://github.com/elastic/kibana/issues/165192 + await expectSearches(type, savedSearchesRequests ?? 2, async () => { + await PageObjects.discover.loadSavedSearch(savedSearch); + }); + }); + }; + + describe('data view mode', () => { + const type = 'ese'; + + getSharedTests({ + type, + savedSearch: 'data view test', + query1: 'bytes > 1000', + query2: 'bytes < 2000', + setQuery: (query) => queryBar.setQuery(query), + }); + + it('should send 2 requests (documents + chart) when adding a filter', async () => { + await expectSearches(type, 2, async () => { + await filterBar.addFilter({ + field: 'extension', + operation: 'is', + value: 'jpg', + }); + }); + }); + + it('should send 2 requests (documents + chart) when sorting', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.discover.clickFieldSort('@timestamp', 'Sort Old-New'); + }); + }); + + it('should send 2 requests (documents + chart) when changing to a breakdown field without an other bucket', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.discover.chooseBreakdownField('type'); + }); + }); + + it('should send 3 requests (documents + chart + other bucket) when changing to a breakdown field with an other bucket', async () => { + await expectSearches(type, 3, async () => { + await PageObjects.discover.chooseBreakdownField('extension.raw'); + }); + }); + + it('should send 2 requests (documents + chart) when changing the chart interval', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.discover.setChartInterval('Day'); + }); + }); + + it('should send 2 requests (documents + chart) when changing the data view', async () => { + await expectSearches(type, 2, async () => { + await PageObjects.discover.selectIndexPattern('long-window-logstash-*'); + }); + }); + }); + + // TODO: ES|QL tests removed since ES|QL isn't supported in Serverless + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_sidebar.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_sidebar.ts new file mode 100644 index 000000000000..17606ac87a42 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_sidebar.ts @@ -0,0 +1,740 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'timePicker', + 'header', + 'unifiedSearch', + 'unifiedFieldList', + ]); + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const browser = getService('browser'); + const filterBar = getService('filterBar'); + const fieldEditor = getService('fieldEditor'); + const retry = getService('retry'); + const dataGrid = getService('dataGrid'); + const INITIAL_FIELD_LIST_SUMMARY = '53 available fields. 0 empty fields. 3 meta fields.'; + + describe('discover sidebar', function describeIndexTests() { + before(async function () { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + beforeEach(async () => { + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({ + defaultIndex: 'logstash-*', + }); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + afterEach(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.replace({}); + await PageObjects.unifiedFieldList.cleanSidebarLocalStorage(); + }); + + describe('field filtering', function () { + it('should reveal and hide the filter form when the toggle is clicked', async function () { + await PageObjects.unifiedFieldList.openSidebarFieldFilter(); + await PageObjects.unifiedFieldList.closeSidebarFieldFilter(); + }); + + it('should filter by field type', async function () { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + await PageObjects.unifiedFieldList.openSidebarFieldFilter(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await testSubjects.click('typeFilter-keyword'); + + await retry.waitFor('first updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '7 available fields. 0 empty fields. 2 meta fields.' + ); + }); + + await testSubjects.click('typeFilter-number'); + + await retry.waitFor('second updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '13 available fields. 0 empty fields. 3 meta fields.' + ); + }); + + await testSubjects.click('fieldListFiltersFieldTypeFilterClearAll'); + + await retry.waitFor('reset', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + INITIAL_FIELD_LIST_SUMMARY + ); + }); + }); + + // TODO: ES|QL tests removed since ES|QL isn't supported in Serverless + }); + + describe('search', function () { + beforeEach(async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + }); + + afterEach(async () => { + const fieldSearch = await testSubjects.find('clearSearchButton'); + await fieldSearch.click(); + + await retry.waitFor('reset', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + INITIAL_FIELD_LIST_SUMMARY + ); + }); + }); + + it('should be able to search by string', async function () { + await PageObjects.unifiedFieldList.findFieldByName('i'); + + await retry.waitFor('first updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '30 available fields. 0 empty fields. 2 meta fields.' + ); + }); + + await PageObjects.unifiedFieldList.findFieldByName('p'); + + await retry.waitFor('second updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '4 available fields. 0 empty fields. 0 meta fields.' + ); + }); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') + ).to.be('clientip, ip, relatedContent.og:description, relatedContent.twitter:description'); + }); + + it('should be able to search by wildcard', async function () { + await PageObjects.unifiedFieldList.findFieldByName('relatedContent*image'); + + await retry.waitFor('updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '2 available fields. 0 empty fields. 0 meta fields.' + ); + }); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') + ).to.be('relatedContent.og:image, relatedContent.twitter:image'); + }); + + it('should be able to search with spaces as wildcard', async function () { + await PageObjects.unifiedFieldList.findFieldByName('relatedContent image'); + + await retry.waitFor('updates', async () => { + return ( + (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === + '4 available fields. 0 empty fields. 0 meta fields.' + ); + }); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') + ).to.be( + 'relatedContent.og:image, relatedContent.og:image:height, relatedContent.og:image:width, relatedContent.twitter:image' + ); + }); + + it('should ignore empty search', async function () { + await PageObjects.unifiedFieldList.findFieldByName(' '); // only spaces + + await retry.waitFor('the clear button', async () => { + return await testSubjects.exists('clearSearchButton'); + }); + + // expect no changes in the list + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + }); + }); + + describe('field stats', function () { + it('should work for regular and pinned filters', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + + const allTermsResult = 'jpg\n65.0%\ncss\n15.4%\npng\n9.8%\ngif\n6.6%\nphp\n3.2%'; + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be(allTermsResult); + + await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'jpg' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const onlyJpgResult = 'jpg\n100%'; + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be(onlyJpgResult); + + await filterBar.toggleFilterNegated('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const jpgExcludedResult = 'css\n44.1%\npng\n28.0%\ngif\n18.8%\nphp\n9.1%'; + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( + jpgExcludedResult + ); + + await filterBar.toggleFilterPinned('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( + jpgExcludedResult + ); + + await browser.refresh(); + + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( + jpgExcludedResult + ); + + await filterBar.toggleFilterEnabled('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be(allTermsResult); + }); + }); + + describe('collapse expand', function () { + it('should initially be expanded', async function () { + await testSubjects.existOrFail('discover-sidebar'); + await testSubjects.existOrFail('fieldList'); + }); + + it('should collapse when clicked', async function () { + await PageObjects.discover.toggleSidebarCollapse(); + await testSubjects.existOrFail('discover-sidebar'); + await testSubjects.missingOrFail('fieldList'); + }); + + it('should expand when clicked', async function () { + await PageObjects.discover.toggleSidebarCollapse(); + await testSubjects.existOrFail('discover-sidebar'); + await testSubjects.existOrFail('fieldList'); + }); + }); + + describe('renders field groups', function () { + it('should show field list groups excluding subfields', async function () { + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + expect(await PageObjects.unifiedFieldList.doesSidebarShowFields()).to.be(true); + + // Initial Available fields + const expectedInitialAvailableFields = + '@message, @tags, @timestamp, agent, bytes, clientip, extension, geo.coordinates, geo.dest, geo.src, geo.srcdest, headings, host, id, index, ip, links, machine.os, machine.ram, machine.ram_range, memory, meta.char, meta.related, meta.user.firstname, meta.user.lastname, nestedField.child, phpmemory, referer, relatedContent.article:modified_time, relatedContent.article:published_time, relatedContent.article:section, relatedContent.article:tag, relatedContent.og:description, relatedContent.og:image, relatedContent.og:image:height, relatedContent.og:image:width, relatedContent.og:site_name, relatedContent.og:title, relatedContent.og:type, relatedContent.og:url, relatedContent.twitter:card, relatedContent.twitter:description, relatedContent.twitter:image, relatedContent.twitter:site, relatedContent.twitter:title, relatedContent.url, request, response, spaces, type'; + let availableFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames( + 'available' + ); + expect(availableFields.length).to.be(50); + expect(availableFields.join(', ')).to.be(expectedInitialAvailableFields); + + // Available fields after scrolling down + const emptySectionButton = await find.byCssSelector( + PageObjects.unifiedFieldList.getSidebarSectionSelector('empty', true) + ); + await emptySectionButton.scrollIntoViewIfNecessary(); + + await retry.waitFor('list to update after scrolling', async () => { + availableFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames( + 'available' + ); + return availableFields.length === 53; + }); + + expect(availableFields.join(', ')).to.be( + `${expectedInitialAvailableFields}, url, utc_time, xss` + ); + + // Expand Empty section + await PageObjects.unifiedFieldList.toggleSidebarSection('empty'); + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('empty')).join(', ') + ).to.be(''); + + // Expand Meta section + await PageObjects.unifiedFieldList.toggleSidebarSection('meta'); + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('meta')).join(', ') + ).to.be('_id, _index, _score'); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + }); + + it('should show field list groups excluding subfields when searched from source', async function () { + await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': true }); + await browser.refresh(); + + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + expect(await PageObjects.unifiedFieldList.doesSidebarShowFields()).to.be(true); + + // Initial Available fields + const availableFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames( + 'available' + ); + expect(availableFields.length).to.be(50); + expect( + availableFields + .join(', ') + .startsWith( + '@message, @tags, @timestamp, agent, bytes, clientip, extension, geo.coordinates' + ) + ).to.be(true); + + // Available fields after scrolling down + const emptySectionButton = await find.byCssSelector( + PageObjects.unifiedFieldList.getSidebarSectionSelector('empty', true) + ); + await emptySectionButton.scrollIntoViewIfNecessary(); + + // Expand Empty section + await PageObjects.unifiedFieldList.toggleSidebarSection('empty'); + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('empty')).join(', ') + ).to.be(''); + + // Expand Meta section + await PageObjects.unifiedFieldList.toggleSidebarSection('meta'); + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('meta')).join(', ') + ).to.be('_id, _index, _score'); + + // Expand Unmapped section + await PageObjects.unifiedFieldList.toggleSidebarSection('unmapped'); + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('unmapped')).join(', ') + ).to.be('relatedContent'); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '53 available fields. 1 unmapped field. 0 empty fields. 3 meta fields.' + ); + }); + + it('should show selected and popular fields', async function () { + await PageObjects.unifiedFieldList.clickFieldListItemAdd('extension'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@message'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('selected')).join(', ') + ).to.be('extension, @message'); + + const availableFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames( + 'available' + ); + expect(availableFields.includes('extension')).to.be(true); + expect(availableFields.includes('@message')).to.be(true); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '2 selected fields. 2 popular fields. 53 available fields. 0 empty fields. 3 meta fields.' + ); + + await PageObjects.unifiedFieldList.clickFieldListItemRemove('@message'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd('_id'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@message'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('selected')).join(', ') + ).to.be('extension, _id, @message'); + + expect( + (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('popular')).join(', ') + ).to.be('@message, _id, extension'); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '3 selected fields. 3 popular fields. 53 available fields. 0 empty fields. 3 meta fields.' + ); + }); + + // TODO: ES|QL tests removed since ES|QL isn't supported in Serverless + + it('should work correctly for a data view for a missing index', async function () { + // but we are skipping importing the index itself + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + await browser.refresh(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.selectIndexPattern('with-timefield'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '0 available fields. 0 empty fields. 0 meta fields.' + ); + await testSubjects.missingOrFail( + `${PageObjects.unifiedFieldList.getSidebarSectionSelector('available')}-fetchWarning` + ); + await testSubjects.existOrFail( + `${PageObjects.unifiedFieldList.getSidebarSectionSelector( + 'available' + )}NoFieldsCallout-noFieldsExist` + ); + + await PageObjects.discover.selectIndexPattern('logstash-*'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + }); + + it('should work correctly when switching data views', async function () { + await esArchiver.loadIfNeeded( + 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' + ); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + + await browser.refresh(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.selectIndexPattern('without-timefield'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '6 available fields. 0 empty fields. 3 meta fields.' + ); + + await PageObjects.discover.selectIndexPattern('with-timefield'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '0 available fields. 7 empty fields. 3 meta fields.' + ); + await testSubjects.existOrFail( + `${PageObjects.unifiedFieldList.getSidebarSectionSelector( + 'available' + )}NoFieldsCallout-noFieldsMatch` + ); + + await PageObjects.discover.selectIndexPattern('logstash-*'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + + await esArchiver.unload( + 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' + ); + }); + + it('should work when filters change', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( + 'jpg\n65.0%\ncss\n15.4%\npng\n9.8%\ngif\n6.6%\nphp\n3.2%' + ); + + await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'jpg' }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + // check that the filter was passed down to the sidebar + await PageObjects.unifiedFieldList.clickFieldListItem('extension'); + expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be('jpg\n100%'); + }); + + it('should work for many fields', async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/many_fields'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/many_fields_data_view' + ); + + await browser.refresh(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.selectIndexPattern('indices-stats*'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '6873 available fields. 0 empty fields. 3 meta fields.' + ); + + await PageObjects.discover.selectIndexPattern('logstash-*'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/many_fields_data_view' + ); + await esArchiver.unload('test/functional/fixtures/es_archiver/many_fields'); + }); + + it('should work with ad-hoc data views and runtime fields', async () => { + await PageObjects.discover.createAdHocDataView('logstash', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.addRuntimeField( + '_bytes-runtimefield', + `emit((doc["bytes"].value * 2).toString())` + ); + + await retry.waitFor('form to close', async () => { + return !(await testSubjects.exists('fieldEditor')); + }); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '54 available fields. 0 empty fields. 3 meta fields.' + ); + + let allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); + expect(allFields.includes('_bytes-runtimefield')).to.be(true); + + await PageObjects.discover.editField('_bytes-runtimefield'); + await fieldEditor.enableCustomLabel(); + await fieldEditor.setCustomLabel('_bytes-runtimefield2'); + await fieldEditor.save(); + + await retry.waitFor('form to close', async () => { + return !(await testSubjects.exists('fieldEditor')); + }); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '54 available fields. 0 empty fields. 3 meta fields.' + ); + + allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); + expect(allFields.includes('_bytes-runtimefield2')).to.be(true); + expect(allFields.includes('_bytes-runtimefield')).to.be(false); + await PageObjects.discover.removeField('_bytes-runtimefield'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); + expect(allFields.includes('_bytes-runtimefield2')).to.be(false); + expect(allFields.includes('_bytes-runtimefield')).to.be(false); + }); + + it('should render even when retrieving documents failed with an error', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.addRuntimeField('_invalid-runtimefield', `emit(‘’);`); + + await PageObjects.header.waitUntilLoadingHasFinished(); + + // error in fetching documents because of the invalid runtime field + await PageObjects.discover.showsErrorCallout(); + + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + // check that the sidebar is rendered + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '54 available fields. 0 empty fields. 3 meta fields.' + ); + let allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); + expect(allFields.includes('_invalid-runtimefield')).to.be(true); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.showsErrorCallout(); // still has error + + // check that the sidebar is rendered event after a refresh + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); + expect(allFields.includes('_invalid-runtimefield')).to.be(true); + + await PageObjects.discover.removeField('_invalid-runtimefield'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + }); + + it('should work correctly when time range is updated', async function () { + await esArchiver.loadIfNeeded( + 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' + ); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + + await browser.refresh(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + INITIAL_FIELD_LIST_SUMMARY + ); + + await PageObjects.discover.selectIndexPattern('with-timefield'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '0 available fields. 7 empty fields. 3 meta fields.' + ); + await testSubjects.existOrFail( + `${PageObjects.unifiedFieldList.getSidebarSectionSelector( + 'available' + )}NoFieldsCallout-noFieldsMatch` + ); + + await PageObjects.timePicker.setAbsoluteRange( + 'Sep 21, 2019 @ 00:00:00.000', + 'Sep 23, 2019 @ 00:00:00.000' + ); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '7 available fields. 0 empty fields. 3 meta fields.' + ); + + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' + ); + + await esArchiver.unload( + 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' + ); + }); + + it('should remove the table column after a field was deleted', async () => { + const newField = '_test_field_and_column_removal'; + await PageObjects.discover.addRuntimeField(newField, `emit("hi there")`); + + await retry.waitFor('form to close', async () => { + return !(await testSubjects.exists('fieldEditor')); + }); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + let selectedFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames( + 'selected' + ); + expect(selectedFields.includes(newField)).to.be(false); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd(newField); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + selectedFields = await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('selected'); + expect(selectedFields.includes(newField)).to.be(true); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', newField]); + + await PageObjects.discover.removeField(newField); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + await retry.waitFor('sidebar to update', async () => { + return !(await PageObjects.unifiedFieldList.getAllFieldNames()).includes(newField); + }); + + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_unsaved_changes_badge.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_unsaved_changes_badge.ts new file mode 100644 index 000000000000..f063a805635f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_unsaved_changes_badge.ts @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +const SAVED_SEARCH_NAME = 'test saved search'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); + const PageObjects = getPageObjects([ + 'settings', + 'common', + 'discover', + 'header', + 'timePicker', + 'dashboard', + 'unifiedFieldList', + ]); + const security = getService('security'); + const defaultSettings = { + defaultIndex: 'logstash-*', + hideAnnouncements: true, + }; + + describe('discover unsaved changes badge', function describeIndexTests() { + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + }); + + after(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({}); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + beforeEach(async function () { + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + it('should not show the badge initially nor after changes to a draft saved search', async () => { + await testSubjects.missingOrFail('unsavedChangesBadge'); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd('bytes'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + }); + + it('should show the badge only after changes to a persisted saved search', async () => { + await PageObjects.discover.saveSearch(SAVED_SEARCH_NAME); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd('bytes'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.existOrFail('unsavedChangesBadge'); + + await PageObjects.discover.saveUnsavedChanges(); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + }); + + it('should not show a badge after loading a saved search, only after changes', async () => { + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_NAME); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + + await PageObjects.discover.chooseBreakdownField('_index'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.existOrFail('unsavedChangesBadge'); + }); + + it('should allow to revert changes', async () => { + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_NAME); + await testSubjects.missingOrFail('unsavedChangesBadge'); + + // test changes to columns + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes']); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes', 'extension']); + await testSubjects.existOrFail('unsavedChangesBadge'); + await PageObjects.discover.revertUnsavedChanges(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes']); + await testSubjects.missingOrFail('unsavedChangesBadge'); + + // test changes to sample size + await dataGrid.clickGridSettings(); + expect(await dataGrid.getCurrentSampleSizeValue()).to.be(500); + await dataGrid.changeSampleSizeValue(250); + await dataGrid.clickGridSettings(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await testSubjects.existOrFail('unsavedChangesBadge'); + await dataGrid.clickGridSettings(); + expect(await dataGrid.getCurrentSampleSizeValue()).to.be(250); + await dataGrid.clickGridSettings(); + await PageObjects.discover.revertUnsavedChanges(); + await testSubjects.missingOrFail('unsavedChangesBadge'); + await dataGrid.clickGridSettings(); + expect(await dataGrid.getCurrentSampleSizeValue()).to.be(500); + await dataGrid.clickGridSettings(); + + // test changes to rows per page + await dataGrid.checkCurrentRowsPerPageToBe(100); + await dataGrid.changeRowsPerPageTo(25); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await testSubjects.existOrFail('unsavedChangesBadge'); + await dataGrid.checkCurrentRowsPerPageToBe(25); + await PageObjects.discover.revertUnsavedChanges(); + await testSubjects.missingOrFail('unsavedChangesBadge'); + await dataGrid.checkCurrentRowsPerPageToBe(100); + }); + + it('should hide the badge once user manually reverts changes', async () => { + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_NAME); + await testSubjects.missingOrFail('unsavedChangesBadge'); + + // changes to columns + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes']); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes', 'extension']); + await testSubjects.existOrFail('unsavedChangesBadge'); + await PageObjects.unifiedFieldList.clickFieldListItemRemove('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'bytes']); + await testSubjects.missingOrFail('unsavedChangesBadge'); + + // test changes to breakdown field + await PageObjects.discover.chooseBreakdownField('_index'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await testSubjects.existOrFail('unsavedChangesBadge'); + await PageObjects.discover.clearBreakdownField(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await testSubjects.missingOrFail('unsavedChangesBadge'); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts new file mode 100644 index 000000000000..75b2e6c9cd25 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile, getPageObject }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('discover/group3', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_sidebar')); + loadTestFile(require.resolve('./_request_counts')); + loadTestFile(require.resolve('./_unsaved_changes_badge')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/__snapshots__/reporting.snap b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/__snapshots__/reporting.snap new file mode 100644 index 000000000000..9d1f3633eb37 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/__snapshots__/reporting.snap @@ -0,0 +1,3071 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with data 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,12,570552,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0216402164, ZO0666306663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570520,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618906189, ZO0289502895\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0643506435, ZO0646406464\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,45,570133,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0320503205, ZO0049500495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,4,570161,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0606606066, ZO0596305963\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,570200,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0025100251, ZO0101901019\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,732050,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0101201012, ZO0230902309, ZO0325603256, ZO0056400564\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,570396,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495604956, ZO0208802088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,570037,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0321503215, ZO0200102001\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569311,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0024600246, ZO0660706607\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,29,570632,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0432404324, ZO0313603136\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569674,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0423104231, ZO0408804088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569716,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146701467, ZO0212902129\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,569962,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0129901299, ZO0440704407\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,569821,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0066600666, ZO0049000490\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,569898,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0591805918, ZO0474004740\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,721217,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0567705677, ZO0414204142, ZO0415904159, ZO0119801198\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569610,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0140001400, ZO0219302193\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,570087,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0308403084, ZO0623506235\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570442,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175501755, ZO0103601036\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,4,569548,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0587605876, ZO0463904639\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,16,569577,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0464404644, ZO0128401284\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569611,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0450604506, ZO0440304403\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570594,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0111901119, ZO0540605406\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,570077,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433904339, ZO0627706277\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,24,570056,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0131801318, ZO0215802158\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,725669,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0234102341, ZO0353703537, ZO0265102651, ZO0149501495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,570694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0376703767, ZO0350603506\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,570542,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0565405654\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,570576,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0637906379, ZO0325103251\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Clothing\\",EUR,52,716588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318303183, ZO0310503105, ZO0584605846, ZO0609706097\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,569531,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0664106641, ZO0549105491\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0070600706, ZO0488704887\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569614,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0226202262, ZO0647006470\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,570484,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0712407124, ZO0095600956\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569679,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433604336, ZO0275702757\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,570250,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0638906389, ZO0148001480\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,7,569746,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0484004840, ZO0605906059\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570353,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0413704137, ZO0559205592\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570021,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0709807098, ZO0166301663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570502,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0280602806, ZO0408504085\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,570263,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0041800418, ZO0194901949\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,570304,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053000530, ZO0360203602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,569529,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0264102641, ZO0658706587\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,712856,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263202632 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing, Men's Accessories\\",EUR,52,713377,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318803188, ZO0535005350, ZO0445504455, ZO0599605996\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,570472,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478704787, ZO0591205912\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,570177,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0532905329, ZO0524105241\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570209,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0658306583, ZO0570705707\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570254,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495304953, ZO0634906349\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,569734,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0348703487, ZO0141401414\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,48,569814,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0298402984\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,41,570079,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0598505985, ZO0449304493\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,570588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0092000920, ZO0152001520\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,569567,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0361403614\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,570658,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0003600036, ZO0016800168\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,712926,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263002630 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570264,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0627206272, ZO0285702857\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,569424,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175201752, ZO0206202062\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569468,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0285202852, ZO0448304483\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569505,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0608906089, ZO0478504785\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569337,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0634106341, ZO0066900669\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,569375,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0347603476, ZO0668806688\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569387,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0125201252\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569919,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0051200512, ZO0232602326\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569768,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0231502315, ZO0131401314\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,570374,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0674906749, ZO0073200732\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,570024,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0631506315, ZO0426804268\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,730736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0074200742, ZO0266602666, ZO0364503645, ZO0134601346\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570075,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0621706217, ZO0114301143\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,43,569623,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0208302083, ZO0307603076\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,569546,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0559105591, ZO0563205632\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,570532,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0557405574, ZO0118601186\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,569452,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0159301593, ZO0250502505\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569496,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0659006590, ZO0103801038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,569370,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0358603586, ZO0641106411\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,45,569411,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0094200942, ZO0003700037\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570663,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0152501525, ZO0104201042\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570491,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0198901989, ZO0104701047\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,570608,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478504785, ZO0663306633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,569371,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0225702257, ZO0186601866\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,46,570065,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0027300273, ZO0698606986\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569624,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0333803338, ZO0138901389\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,569953,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0021100211, ZO0193601936\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569822,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0271402714, ZO0047200472\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,20,569880,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0325303253, ZO0244002440\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,570234,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0707007070, ZO0016200162\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,570512,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0332003320, ZO0357103571\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569422,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0102501025, ZO0063500635\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,30,569958,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0311903119, ZO0563305633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,569868,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0200702007, ZO0106501065\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569710,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053600536, ZO0239702397\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,570151,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0589105891, ZO0587705877\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,725499,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0678306783, ZO0305503055, ZO0369203692, ZO0006700067\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,569338,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0702507025, ZO0528105281\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,712590,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0262202622 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,570643,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0119701197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,44,570687,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135501355, ZO0675806758\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569939,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0471304713, ZO0528905289\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,569968,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0047300473, ZO0142401424\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569995,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0125701257, ZO0664706647\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,569834,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0076900769, ZO0151501515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,569869,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0362803628, ZO0237802378\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,569900,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0644506445, ZO0104901049\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570164,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0210002100, ZO0068200682\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569761,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0166101661, ZO0337203372\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,570335,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0337703377, ZO0048500485\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570372,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0124001240, ZO0560205602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,570040,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146901469, ZO0673806738\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,569835,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0077800778, ZO0177301773\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569873,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0165701657, ZO0485004850\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,570508,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0002600026, ZO0328703287\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,570280,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0341703417, ZO0168701687\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569815,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0269602696, ZO0067400674\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,570350,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0460004600, ZO0569705697\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569925,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0437004370, ZO0475204752\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,570061,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0604606046, ZO0416004160\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0533305333, ZO0565105651\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569510,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0312203122, ZO0115101151\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,570309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0496504965, ZO0269202692\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569787,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0055900559, ZO0224002240\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,569309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0364103641, ZO0708807088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,570671,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0240702407, ZO0099400994\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,43,569652,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0665906659, ZO0240002400\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,51,569469,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0434204342, ZO0600206002\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,569513,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135701357, ZO0097600976\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,569356,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0010500105, ZO0172201722\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568397,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0112101121, ZO0530405304\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568044,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0630406304, ZO0120201202\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,44,568229,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192201922, ZO0192801928\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,10,568292,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0534205342, ZO0599605996\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568386,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0422404224, ZO0291702917\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,568023,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0075900759, ZO0489304893\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,42,568789,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0197501975, ZO0079300793\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,568589,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0114401144, ZO0564705647\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568640,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0125901259, ZO0443204432\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,569259,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0335503355, ZO0381003810\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,568793,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0312503125, ZO0545505455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,568068,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0583005830, ZO0602706027\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568070,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0575605756, ZO0293302933\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568106,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068700687, ZO0101301013\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,568439,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0170601706, ZO0251502515\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568507,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0431304313, ZO0523605236\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,568236,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0416604166, ZO0581605816\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,568275,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0330903309, ZO0214802148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568434,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362203622, ZO0000300003\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,568458,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0164501645, ZO0195501955\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,568503,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0643306433, ZO0376203762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568232,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0282902829, ZO0566605666\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,48,568269,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0318603186, ZO0407904079\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,568301,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146401464, ZO0014700147\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568469,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0659806598, ZO0070100701\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,568499,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0474604746, ZO0113801138\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,17,568083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0200902009, ZO0092300923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,569214,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0490104901, ZO0087200872\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,11,568875,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0613606136, ZO0463804638\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569103,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0636506365, ZO0345503455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,720661,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,569144,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0108101081, ZO0501105011\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,569198,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0464304643, ZO0581905819\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,24,568894,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0141801418, ZO0206302063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,568938,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0642806428, ZO0632506325\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,11,569045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315903159, ZO0461104611\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,727370,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,49,568751,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0308703087, ZO0613106131\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,569010,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0090700907, ZO0265002650\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,568745,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0309203092\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,5,728962,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568069,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530305303, ZO0528405284\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,732546,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,568218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0227402274, ZO0079000790\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,568278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536705367, ZO0449804498\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568428,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0408404084, ZO0422304223\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568492,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0346103461, ZO0054100541\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,569262,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609906099, ZO0614806148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569306,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0412004120, ZO0625406254\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,21,569223,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0444004440, ZO0596805968\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,568039,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599705997, ZO0416704167\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568165,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0065600656, ZO0337003370\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568393,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0374103741, ZO0242102421\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567996,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0105401054, ZO0046200462\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,569173,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0452204522, ZO0631206312\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568865,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294502945, ZO0560605606\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568926,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0298302983, ZO0300003000\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568955,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068900689, ZO0076200762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,569056,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0494804948, ZO0096000960\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,569083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0099000990, ZO0631606316\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,568149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0342503425, ZO0675206752\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,568192,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0485504855, ZO0355603556\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569183,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0641206412, ZO0165301653\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,568818,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294802948, ZO0451404514\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,4,568901,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0427104271\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,569033,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0015700157, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568019,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530805308, ZO0563905639\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,568182,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0338603386, ZO0641006410\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569123,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609006090, ZO0441504415\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,728335,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726874,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,569218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0633206332, ZO0488604886\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,722613,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,568152,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0349303493, ZO0043900439\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567994,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0430904309, ZO0288402884\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,568045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0160501605, ZO0069500695\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568308,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0138701387, ZO0024600246\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,568515,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0159901599, ZO0238702387\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,569250,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228902289, ZO0005400054\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568776,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616906169, ZO0296902969\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,568014,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0523905239, ZO0556605566\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,568702,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0142801428, ZO0182801828\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568128,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0087500875, ZO0007100071\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,569178,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0177001770, ZO0260502605\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,568877,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0132401324, ZO0058200582\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,568941,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0076600766, ZO0068800688\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,12,569027,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0245402454, ZO0060100601\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,569055,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0375903759, ZO0269402694\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569107,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0339603396, ZO0504705047\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,714385,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,723213,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568360,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0480304803, ZO0274402744\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0271802718, ZO0057100571\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568816,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146601466, ZO0108601086\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,21,568375,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0605306053\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,38,568559,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599005990, ZO0626506265\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,45,568611,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0174701747, ZO0305103051\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,568706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0672206722, ZO0331903319\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,728580,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568762,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0052200522, ZO0265602656\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568571,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0034100341, ZO0343103431\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568671,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0637406374, ZO0219002190\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,568774,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0037200372, ZO0369303693\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,568363,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0629806298, ZO0467104671\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568541,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0428904289, ZO0588205882\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,568586,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0232202322, ZO0208402084\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568636,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0503905039, ZO0631806318\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568674,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192301923, ZO0011400114\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,567868,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0310403104, ZO0416604166\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,567446,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0322803228, ZO0002700027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567736,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0663706637, ZO0620906209\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,715455,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566768,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0217702177, ZO0331703317\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,566812,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0266902669, ZO0244202442\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,566944,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0497004970, ZO0054900549\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566979,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0071900719, ZO0493404934\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567094,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0442904429, ZO0629706297\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566892,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589505895, ZO0575405754\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,567950,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273002730, ZO0541105411\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,566826,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0575305753, ZO0540605406\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,24,567669,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148301483, ZO0202902029\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567365,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0008600086, ZO0266002660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566845,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0547905479, ZO0583305833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567048,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0566905669, ZO0564005640\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,567281,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0221402214, ZO0632806328\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,567119,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0711507115, ZO0350903509\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,567169,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558805588, ZO0622206222\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567869,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0565105651, ZO0443804438\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567909,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0609606096, ZO0588905889\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,567524,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0096300963, ZO0377403774\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,567565,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0015600156, ZO0323603236\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567019,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0151301513, ZO0204902049\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567069,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0503805038, ZO0047500475\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,567935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0116101161, ZO0574305743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566831,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0341103411, ZO0648406484\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,567543,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0608106081, ZO0296502965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567598,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0039400394, ZO0672906729\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567876,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0705707057, ZO0047700477\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,567684,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0201202012, ZO0035000350\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,50,567256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0461004610, ZO0702707027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,716462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566775,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0671006710, ZO0708007080\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,567926,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113301133, ZO0562105621\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566829,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0100901009, ZO0235102351\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567666,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0311403114, ZO0282002820\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567383,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0647406474, ZO0330703307\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567381,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278402784, ZO0458304583\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,567437,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0275902759, ZO0545005450\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,567324,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426604266, ZO0629406294\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,21,567504,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0606506065, ZO0277702777\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,42,567623,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0239802398, ZO0645406454\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,567400,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0605606056, ZO0588105881\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,566757,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0196201962, ZO0168601686\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,566884,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0490204902, ZO0025000250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567815,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0263602636, ZO0241002410\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,567177,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0197301973, ZO0180401804\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,733060,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,567486,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0058200582, ZO0365503655\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,567625,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0328603286, ZO0328803288\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,10,567224,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0128501285, ZO0606306063\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567252,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0369803698, ZO0220502205\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567822,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0244802448, ZO0346303463\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,31,567852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0523805238, ZO0596505965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567042,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0243002430, ZO0103901039\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,731037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567384,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426704267, ZO0612006120\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,566690,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0449004490, ZO0118501185\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,566982,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0149301493, ZO0099800998\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566725,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0444404444, ZO0584205842\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,566856,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0216502165, ZO0327503275\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567039,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0184101841, ZO0711207112\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567068,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0038000380, ZO0711007110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,732229,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,724806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567769,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0414004140, ZO0630106301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,566772,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0152901529, ZO0019100191\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,567615,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0013500135, ZO0174501745\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,566896,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0242702427, ZO0090000900\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0644406444, ZO0709307093\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,567667,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273802738, ZO0300303003\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,567703,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0037900379, ZO0134901349\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567260,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0068100681, ZO0674106741\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,724844,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,567308,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0181601816, ZO0011000110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,567538,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0596905969, ZO0450804508\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,567593,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0655306553, ZO0208902089\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,15,567294,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0317403174, ZO0457204572\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,728256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,567544,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0585005850, ZO0120301203\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567592,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0535405354, ZO0291302913\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,566942,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0084000840, ZO0636606366\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,567015,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558605586, ZO0527805278\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,28,567081,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0209702097, ZO0186301863\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567631,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0101101011, ZO0667406674\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567454,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0645406454, ZO0166001660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567855,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0657106571, ZO0084800848\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,5,567037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0206402064, ZO0365903659\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,38,567143,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0573005730, ZO0313203132\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,567191,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113901139, ZO0478904789\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,567135,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0549305493\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,727730,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,567939,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0127201272, ZO0425504255\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,567301,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0577605776, ZO0438104381\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566801,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0279702797, ZO0573705737\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566685,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0296902969, ZO0530205302\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566924,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0673606736, ZO0161801618\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,20,567708,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0090500905, ZO0466204662\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567573,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0215602156, ZO0336803368\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,566986,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0360903609, ZO0030100301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0632406324, ZO0060300603\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,566881,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0419604196, ZO0559705597\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,20,566790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0699206992, ZO0641306413\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0473704737, ZO0121501215\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,566985,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0044700447, ZO0502105021\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0110401104\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,567095,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0339803398, ZO0098200982\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,724326,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,567973,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0495104951, ZO0305903059\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,567341,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0674506745, ZO0219202192\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567492,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0277302773, ZO0443004430\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,567403,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0138601386, ZO0259202592\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567207,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0033600336, ZO0109401094\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,13,567356,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0319503195, ZO0409904099\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565855,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417504175, ZO0535205352\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566343,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0185101851, ZO0052800528\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,26,566400,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0204702047, ZO0009600096\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565776,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343103431, ZO0345803458\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566607,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0572205722, ZO0585205852\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565452,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0133601336, ZO0643906439\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566051,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0025600256, ZO0270202702\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565466,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285402854, ZO0538605386\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566553,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0435004350, ZO0544005440\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565446,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0643206432, ZO0140101401\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566053,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0284702847, ZO0299202992\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,566170,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0324803248, ZO0703907039\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,566187,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0548905489, ZO0459404594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,566125,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0433104331, ZO0549505495\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566156,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0117901179\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,566100,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0013400134, ZO0667306673\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566280,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0116701167\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,566256,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227302273, ZO0668706687\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,27,565639,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0193901939, ZO0080400804\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565945,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0270602706, ZO0269502695\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,18,565988,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0074700747, ZO0645206452\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,15,565732,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0603006030\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,29,566042,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0451804518, ZO0127901279\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,566456,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0597105971, ZO0283702837\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565542,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224302243, ZO0359103591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,566121,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227202272, ZO0357003570\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,566653,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0666506665, ZO0216602166\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,565838,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343703437, ZO0207102071\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,565804,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0306803068, ZO0174601746\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,565459,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0242302423, ZO0676006760\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565819,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0031700317, ZO0157701577\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,731352,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565900,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0266102661, ZO0169701697\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,566360,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285102851, ZO0658306583\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,565796,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081500815, ZO0342603426\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,566261,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0577105771, ZO0289302893\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,565567,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0437604376, ZO0618906189\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565596,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0332903329, ZO0159401594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566428,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0136501365, ZO0339103391\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,566334,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0010800108, ZO0635706357\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566391,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228302283, ZO0167501675\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,566315,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0703707037, ZO0139601396\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565698,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0336503365, ZO0637006370\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566167,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623006230, ZO0419304193\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566070,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046100461, ZO0151201512\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,16,566621,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0579605796, ZO0315803158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,566284,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0541405414, ZO0588205882\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,566518,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0554605546, ZO0569005690\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565830,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0215702157, ZO0638806388\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,565948,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0190701907, ZO0654806548\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,565998,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0238802388, ZO0066600666\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565401,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0014800148, ZO0154501545\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,565728,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486404864, ZO0248602486\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,565489,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0077200772, ZO0643006430\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,720445,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565768,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0458004580, ZO0273402734\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,565538,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486804868, ZO0371603716\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565404,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0048900489, ZO0228702287\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,715961,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,566382,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0503505035, ZO0240302403\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,565877,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0125401254, ZO0123701237\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,48,565479,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0588805888, ZO0314903149\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565360,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0450704507\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,565970,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0673406734, ZO0165601656\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,27,723242,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,566580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417304173, ZO0123001230\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,566671,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0427604276, ZO0113801138\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,566176,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0607206072, ZO0431404314\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,566146,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0646206462, ZO0146201462\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565760,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0504505045, ZO0223802238\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565521,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0660406604, ZO0484504845\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566320,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0105001050, ZO0652306523\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,566357,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0061600616, ZO0180701807\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,566415,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0261102611, ZO0667106671\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566044,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0552605526, ZO0292702927\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,565473,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0365303653, ZO0235802358\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,565339,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0346503465, ZO0678406784\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,730725,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,566443,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0160201602, ZO0261502615\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,565985,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0436604366, ZO0280302803\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565640,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0631606316, ZO0045300453\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,49,565683,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0310303103\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565767,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0414304143, ZO0425204252\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,566452,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0706307063, ZO0011300113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,565982,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0410804108, ZO0309303093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726754,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,24,565723,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0302303023, ZO0246602466\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,31,565896,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0466104661, ZO0444104441\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,718085,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,566248,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0678806788, ZO0186101861\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,565560,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0567505675, ZO0442104421\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,566155,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501005010, ZO0214002140\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,28,566628,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0195601956, ZO0098900989\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,566519,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0700907009, ZO0115801158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,565697,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0498904989, ZO0641706417\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,45,566417,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0084900849, ZO0194701947\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,565722,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0656406564, ZO0495504955\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,565330,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0621606216, ZO0628806288\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,565381,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0060200602, ZO0076300763\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,565564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0576305763, ZO0116801168\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565392,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0616606166, ZO0592205922\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,565410,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0023600236, ZO0704307043\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565504,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0653406534, ZO0049300493\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,565334,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0641706417, ZO0382303823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566622,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228402284, ZO0082300823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,566650,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0049100491, ZO0194801948\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,566295,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0635606356, ZO0043100431\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566538,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224402244, ZO0342403424\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,565918,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0155001550, ZO0072100721\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,565678,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081800818, ZO0485604856\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0503305033\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565793,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0712807128, ZO0007500075\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,566232,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0545205452, ZO0437304373\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,566591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0502405024, ZO0366003660\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564710,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0263402634, ZO0499404994\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564429,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0495804958\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564479,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0409304093, ZO0436904369\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,6,564885,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303803038, ZO0192501925\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565150,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0624906249, ZO0411604116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564759,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218802188, ZO0492604926\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,564144,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218602186, ZO0501005010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563909,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452804528, ZO0453604536\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,28,564869,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0192401924, ZO0366703667\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,564269,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0281102811, ZO0555705557\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,564893,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0322403224, ZO0227802278\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564215,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0147201472, ZO0152201522\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564725,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0071700717, ZO0364303643\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564331,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0229402294, ZO0303303033\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564350,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444104441, ZO0476804768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564398,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0328703287, ZO0351003510\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,564409,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0178501785, ZO0503805038\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,564024,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0619006190\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564676,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0108401084, ZO0139301393\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,564445,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0701407014\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,50,564241,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0605506055, ZO0547505475\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564844,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0553205532, ZO0526205262\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,564883,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0705607056, ZO0334703347\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,564307,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0246602466, ZO0195201952\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564148,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0057900579, ZO0211602116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,564009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0487904879, ZO0027100271\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,564532,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0474704747, ZO0622006220\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565308,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0172401724, ZO0184901849\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,564339,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0082900829, ZO0347903479\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,564361,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0422304223, ZO0600506005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564394,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0269902699, ZO0667906679\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564030,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0179901799, ZO0637606376\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564661,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415004150, ZO0125501255\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564706,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0709007090, ZO0362103621\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564460,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0655106551, ZO0349403494\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,564536,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0304603046, ZO0370603706\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,564559,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0015500155, ZO0650806508\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564609,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0156001560\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,565138,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0615506155, ZO0445304453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,565025,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0280802808, ZO0549005490\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,564000,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0364603646, ZO0018200182\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,564557,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0664606646, ZO0460404604\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,564604,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0237702377, ZO0304303043\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,564777,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452704527, ZO0122201222\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,564812,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0266002660, ZO0031900319\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,563964,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0001200012, ZO0251902519\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564315,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0263702637\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0323303233, ZO0172101721\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564510,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093600936, ZO0145301453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,565222,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0102001020, ZO0252402524\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,565233,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0614906149, ZO0430404304\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565084,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0549805498, ZO0541205412\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564796,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0022100221, ZO0172301723\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564627,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0211702117, ZO0499004990\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,564257,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539205392, ZO0577705777\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,564701,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0585205852, ZO0418104181\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,564954,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0362903629, ZO0048100481\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0225302253, ZO0183101831\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564065,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711207112, ZO0646106461\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,563927,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0009800098, ZO0362803628\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,564994,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0180601806, ZO0710007100\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,564070,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0234202342, ZO0245102451\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,727071,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,564380,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0050400504, ZO0660006600\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,565276,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0131501315, ZO0668806688\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564819,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0697106971\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,717243,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,564140,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0268502685\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,564164,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0673506735, ZO0213002130\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564207,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711807118, ZO0073100731\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565077,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118701187, ZO0123901239\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564274,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0542905429, ZO0423604236\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565161,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0441404414, ZO0430504305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,565039,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0489804898, ZO0695006950\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,723683,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563967,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0493404934, ZO0640806408\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,564533,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0496704967, ZO0049700497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,564818,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0475004750, ZO0412304123\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,23,564932,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0607806078\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,564968,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0134101341, ZO0062400624\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565002,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0354203542, ZO0338503385\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,563924,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539805398, ZO0554205542\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,564770,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0704907049, ZO0024700247\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563965,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0045800458, ZO0503405034\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564957,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0171601716, ZO0214602146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,564075,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0525405254\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,563931,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444304443, ZO0596505965\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,564940,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0026800268, ZO0003600036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564987,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0526805268, ZO0478104781\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,564080,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415804158, ZO0460804608\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,8,564106,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0298002980, ZO0313103131\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563947,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0348103481, ZO0164501645\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,725995,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565137,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118501185, ZO0561905619\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,565173,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0203802038, ZO0014900149\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564804,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0259702597, ZO0640606406\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,565052,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697006970, ZO0711407114\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,565091,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0324703247, ZO0088600886\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,565231,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0235202352, ZO0135001350\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564190,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0243902439, ZO0208702087\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,564876,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0215502155, ZO0168101681\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,564902,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0698406984, ZO0704207042\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564761,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0665006650, ZO0709407094\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,731788,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,564395,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0236702367, ZO0660706607\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,564686,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0373303733, ZO0131201312\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,564446,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093400934, ZO0679406794\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,43,564481,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0321603216, ZO0078000780\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,563953,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0376203762, ZO0303603036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565100,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0069000690, ZO0490004900\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565263,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0582705827, ZO0111801118\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563984,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0294102941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,12,565262,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303503035, ZO0197601976\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,565304,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0017800178, ZO0229602296\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564121,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0291902919, ZO0617206172\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,23,564166,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0607106071, ZO0470704707\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,564739,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0335603356, ZO0236502365\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564016,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0290402904\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,564605,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0333103331, ZO0694806948\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,17,730663,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,564221,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0487404874\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,564174,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0032300323, ZO0236302363\\" +" +`; + +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with discover:searchFieldsFromSource = true 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,12,570552,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0216402164, ZO0666306663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570520,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618906189, ZO0289502895\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0643506435, ZO0646406464\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,45,570133,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0320503205, ZO0049500495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,4,570161,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0606606066, ZO0596305963\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,570200,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0025100251, ZO0101901019\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,732050,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0101201012, ZO0230902309, ZO0325603256, ZO0056400564\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,570396,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495604956, ZO0208802088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,570037,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0321503215, ZO0200102001\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569311,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0024600246, ZO0660706607\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,29,570632,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0432404324, ZO0313603136\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569674,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0423104231, ZO0408804088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569716,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146701467, ZO0212902129\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,569962,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0129901299, ZO0440704407\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,569821,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0066600666, ZO0049000490\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,569898,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0591805918, ZO0474004740\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,721217,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0567705677, ZO0414204142, ZO0415904159, ZO0119801198\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,569610,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0140001400, ZO0219302193\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,29,570087,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0308403084, ZO0623506235\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,570442,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175501755, ZO0103601036\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,4,569548,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0587605876, ZO0463904639\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,16,569577,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0464404644, ZO0128401284\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569611,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0450604506, ZO0440304403\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570594,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0111901119, ZO0540605406\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,570077,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433904339, ZO0627706277\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,24,570056,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0131801318, ZO0215802158\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,725669,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0234102341, ZO0353703537, ZO0265102651, ZO0149501495\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,570694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0376703767, ZO0350603506\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,570542,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0565405654\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,570576,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0637906379, ZO0325103251\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Accessories, Men's Clothing\\",EUR,52,716588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318303183, ZO0310503105, ZO0584605846, ZO0609706097\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,569531,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0664106641, ZO0549105491\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569569,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0070600706, ZO0488704887\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569614,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0226202262, ZO0647006470\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,570484,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0712407124, ZO0095600956\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569679,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0433604336, ZO0275702757\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,570250,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0638906389, ZO0148001480\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Women's Accessories\\",EUR,7,569746,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0484004840, ZO0605906059\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570353,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0413704137, ZO0559205592\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570021,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0709807098, ZO0166301663\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570502,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0280602806, ZO0408504085\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,570263,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0041800418, ZO0194901949\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,570304,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053000530, ZO0360203602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,5,569529,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0264102641, ZO0658706587\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,712856,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263202632 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing, Men's Accessories\\",EUR,52,713377,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0318803188, ZO0535005350, ZO0445504455, ZO0599605996\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,570472,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478704787, ZO0591205912\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,570177,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0532905329, ZO0524105241\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,570209,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0658306583, ZO0570705707\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570254,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0495304953, ZO0634906349\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,20,569734,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0348703487, ZO0141401414\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,48,569814,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0602606026, ZO0298402984\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,41,570079,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0598505985, ZO0449304493\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,570588,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0092000920, ZO0152001520\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,569567,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0366203662, ZO0361403614\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,570658,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0003600036, ZO0016800168\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,712926,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0263002630 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,570264,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0627206272, ZO0285702857\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,569424,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0175201752, ZO0206202062\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569468,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0285202852, ZO0448304483\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569505,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0608906089, ZO0478504785\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569337,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0634106341, ZO0066900669\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,569375,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0347603476, ZO0668806688\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569387,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0125201252\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569919,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0051200512, ZO0232602326\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569768,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0231502315, ZO0131401314\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,570374,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0674906749, ZO0073200732\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,570024,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0631506315, ZO0426804268\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,730736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0074200742, ZO0266602666, ZO0364503645, ZO0134601346\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,570075,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0621706217, ZO0114301143\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,43,569623,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0208302083, ZO0307603076\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,569546,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0559105591, ZO0563205632\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,570532,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0557405574, ZO0118601186\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,569452,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0159301593, ZO0250502505\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569496,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0659006590, ZO0103801038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,569370,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0358603586, ZO0641106411\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,45,569411,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0094200942, ZO0003700037\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,570663,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0152501525, ZO0104201042\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570491,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0198901989, ZO0104701047\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,570608,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0478504785, ZO0663306633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,20,569371,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0225702257, ZO0186601866\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,46,570065,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0027300273, ZO0698606986\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569624,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0333803338, ZO0138901389\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,569953,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0021100211, ZO0193601936\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,569822,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0271402714, ZO0047200472\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,20,569880,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0325303253, ZO0244002440\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,570234,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0707007070, ZO0016200162\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,570512,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0332003320, ZO0357103571\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,569422,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0102501025, ZO0063500635\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,30,569958,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0311903119, ZO0563305633\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,569868,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0200702007, ZO0106501065\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,569710,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0053600536, ZO0239702397\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,570151,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0589105891, ZO0587705877\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,17,725499,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0678306783, ZO0305503055, ZO0369203692, ZO0006700067\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,569338,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0702507025, ZO0528105281\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,712590,3,\\"Dec 15, 2016 @ 00:00:00.000\\",ZO0262202622 +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,570643,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0119701197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,44,570687,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135501355, ZO0675806758\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569939,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0471304713, ZO0528905289\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,569968,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0047300473, ZO0142401424\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,569995,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0125701257, ZO0664706647\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,569834,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0076900769, ZO0151501515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,569869,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0362803628, ZO0237802378\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,569900,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0644506445, ZO0104901049\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,570164,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0210002100, ZO0068200682\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,569761,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0166101661, ZO0337203372\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,570335,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0337703377, ZO0048500485\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,570372,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0124001240, ZO0560205602\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,570040,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0146901469, ZO0673806738\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,569835,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0077800778, ZO0177301773\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569873,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0165701657, ZO0485004850\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,570508,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0002600026, ZO0328703287\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,570280,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0341703417, ZO0168701687\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569815,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0269602696, ZO0067400674\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,570350,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0460004600, ZO0569705697\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,569925,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0437004370, ZO0475204752\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,570061,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0604606046, ZO0416004160\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,569477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0533305333, ZO0565105651\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,14,569510,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0312203122, ZO0115101151\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,570309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0496504965, ZO0269202692\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569787,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0055900559, ZO0224002240\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,569309,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0364103641, ZO0708807088\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,570671,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0240702407, ZO0099400994\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,43,569652,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0665906659, ZO0240002400\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,51,569469,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0434204342, ZO0600206002\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,569513,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0135701357, ZO0097600976\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,569356,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0010500105, ZO0172201722\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568397,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0112101121, ZO0530405304\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568044,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0630406304, ZO0120201202\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,44,568229,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192201922, ZO0192801928\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,10,568292,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0534205342, ZO0599605996\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568386,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0422404224, ZO0291702917\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,568023,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0075900759, ZO0489304893\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,42,568789,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0197501975, ZO0079300793\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,10,568589,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0114401144, ZO0564705647\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,568640,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0125901259, ZO0443204432\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,569259,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0335503355, ZO0381003810\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,8,568793,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0312503125, ZO0545505455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,568068,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0583005830, ZO0602706027\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568070,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0575605756, ZO0293302933\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568106,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068700687, ZO0101301013\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,568439,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0170601706, ZO0251502515\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568507,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0431304313, ZO0523605236\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,568236,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0416604166, ZO0581605816\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,568275,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0330903309, ZO0214802148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568434,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362203622, ZO0000300003\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,568458,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0164501645, ZO0195501955\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,568503,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0643306433, ZO0376203762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568232,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0282902829, ZO0566605666\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,48,568269,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0318603186, ZO0407904079\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,568301,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146401464, ZO0014700147\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568469,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0659806598, ZO0070100701\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,568499,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0474604746, ZO0113801138\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,17,568083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0200902009, ZO0092300923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,569214,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0490104901, ZO0087200872\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,11,568875,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0613606136, ZO0463804638\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569103,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0636506365, ZO0345503455\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,720661,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,569144,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0108101081, ZO0501105011\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,569198,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0464304643, ZO0581905819\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,24,568894,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0141801418, ZO0206302063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,568938,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0642806428, ZO0632506325\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,11,569045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315903159, ZO0461104611\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,727370,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,49,568751,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0308703087, ZO0613106131\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,569010,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0090700907, ZO0265002650\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,568745,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0309203092\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,5,728962,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568069,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530305303, ZO0528405284\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,732546,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,17,568218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0227402274, ZO0079000790\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,568278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536705367, ZO0449804498\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,568428,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0408404084, ZO0422304223\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568492,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0346103461, ZO0054100541\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,569262,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609906099, ZO0614806148\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,569306,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0412004120, ZO0625406254\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,21,569223,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0444004440, ZO0596805968\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,568039,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599705997, ZO0416704167\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,568165,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0065600656, ZO0337003370\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568393,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0374103741, ZO0242102421\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567996,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0105401054, ZO0046200462\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,569173,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0452204522, ZO0631206312\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,568865,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294502945, ZO0560605606\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,568926,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0298302983, ZO0300003000\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,568955,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0068900689, ZO0076200762\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,569056,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0494804948, ZO0096000960\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,569083,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0099000990, ZO0631606316\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,568149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0342503425, ZO0675206752\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,568192,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0485504855, ZO0355603556\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,569183,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0641206412, ZO0165301653\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,568818,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0294802948, ZO0451404514\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,4,568901,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0466704667, ZO0427104271\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,569033,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0015700157, ZO0362503625\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,568019,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0530805308, ZO0563905639\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,568182,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0338603386, ZO0641006410\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,13,569123,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0609006090, ZO0441504415\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,728335,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726874,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,569218,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0633206332, ZO0488604886\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,722613,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,568152,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0349303493, ZO0043900439\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567994,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0430904309, ZO0288402884\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,568045,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0160501605, ZO0069500695\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,568308,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0138701387, ZO0024600246\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,6,568515,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0159901599, ZO0238702387\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,569250,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0228902289, ZO0005400054\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568776,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616906169, ZO0296902969\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,568014,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0523905239, ZO0556605566\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,568702,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0142801428, ZO0182801828\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568128,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0087500875, ZO0007100071\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,569178,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0177001770, ZO0260502605\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,568877,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0132401324, ZO0058200582\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,42,568941,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0076600766, ZO0068800688\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,12,569027,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0245402454, ZO0060100601\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,569055,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0375903759, ZO0269402694\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,569107,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0339603396, ZO0504705047\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,714385,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,723213,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,568360,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0480304803, ZO0274402744\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,569278,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0271802718, ZO0057100571\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568816,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0146601466, ZO0108601086\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,21,568375,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0623606236, ZO0605306053\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,38,568559,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0599005990, ZO0626506265\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,45,568611,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0174701747, ZO0305103051\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,568706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0672206722, ZO0331903319\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,728580,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568762,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0052200522, ZO0265602656\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,568571,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0034100341, ZO0343103431\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,568671,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0637406374, ZO0219002190\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,568774,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0037200372, ZO0369303693\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,568363,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0629806298, ZO0467104671\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,568541,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0428904289, ZO0588205882\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,568586,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0232202322, ZO0208402084\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,568636,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0503905039, ZO0631806318\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,568674,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0192301923, ZO0011400114\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,567868,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0310403104, ZO0416604166\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,42,567446,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0322803228, ZO0002700027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567736,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0663706637, ZO0620906209\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,715455,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566768,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0217702177, ZO0331703317\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,566812,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0266902669, ZO0244202442\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,566944,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0497004970, ZO0054900549\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566979,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0071900719, ZO0493404934\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,567094,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0442904429, ZO0629706297\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566892,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589505895, ZO0575405754\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,567950,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273002730, ZO0541105411\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,566826,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0575305753, ZO0540605406\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,24,567669,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148301483, ZO0202902029\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567365,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0008600086, ZO0266002660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566845,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0547905479, ZO0583305833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567048,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0566905669, ZO0564005640\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,567281,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0221402214, ZO0632806328\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,567119,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0711507115, ZO0350903509\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,567169,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558805588, ZO0622206222\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567869,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0565105651, ZO0443804438\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567909,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0609606096, ZO0588905889\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,567524,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0096300963, ZO0377403774\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,567565,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0015600156, ZO0323603236\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567019,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0151301513, ZO0204902049\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567069,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0503805038, ZO0047500475\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,567935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0116101161, ZO0574305743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566831,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0341103411, ZO0648406484\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,51,567543,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0608106081, ZO0296502965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567598,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0039400394, ZO0672906729\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567876,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0705707057, ZO0047700477\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,567684,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0201202012, ZO0035000350\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,50,567256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0461004610, ZO0702707027\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,716462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566775,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0671006710, ZO0708007080\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,567926,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113301133, ZO0562105621\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566829,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0100901009, ZO0235102351\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,37,567666,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0311403114, ZO0282002820\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,567383,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0647406474, ZO0330703307\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567381,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278402784, ZO0458304583\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,567437,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0275902759, ZO0545005450\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,567324,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426604266, ZO0629406294\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,21,567504,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0606506065, ZO0277702777\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,42,567623,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0239802398, ZO0645406454\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,567400,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0605606056, ZO0588105881\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,566757,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0196201962, ZO0168601686\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,566884,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0490204902, ZO0025000250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567815,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0263602636, ZO0241002410\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,17,567177,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0197301973, ZO0180401804\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,733060,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,567486,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0058200582, ZO0365503655\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,567625,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0328603286, ZO0328803288\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,10,567224,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0128501285, ZO0606306063\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567252,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0369803698, ZO0220502205\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,567822,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0244802448, ZO0346303463\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,31,567852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0523805238, ZO0596505965\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,567042,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0243002430, ZO0103901039\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,731037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567384,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0426704267, ZO0612006120\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,566690,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0449004490, ZO0118501185\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,566982,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0149301493, ZO0099800998\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566725,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0444404444, ZO0584205842\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,566856,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0216502165, ZO0327503275\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567039,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0184101841, ZO0711207112\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,567068,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0038000380, ZO0711007110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,732229,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,724806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,567769,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0414004140, ZO0630106301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,566772,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0152901529, ZO0019100191\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,6,567615,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0013500135, ZO0174501745\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,566896,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0242702427, ZO0090000900\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,567462,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0644406444, ZO0709307093\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,567667,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0273802738, ZO0300303003\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,567703,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0037900379, ZO0134901349\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,567260,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0068100681, ZO0674106741\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,724844,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,45,567308,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0181601816, ZO0011000110\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,31,567538,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0596905969, ZO0450804508\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,46,567593,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0655306553, ZO0208902089\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,15,567294,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0317403174, ZO0457204572\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,728256,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,567544,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0585005850, ZO0120301203\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,41,567592,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0535405354, ZO0291302913\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,44,566942,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0084000840, ZO0636606366\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,567015,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0558605586, ZO0527805278\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,28,567081,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0209702097, ZO0186301863\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,46,567631,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0101101011, ZO0667406674\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567454,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0645406454, ZO0166001660\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,567855,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0657106571, ZO0084800848\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,5,567037,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0206402064, ZO0365903659\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,38,567143,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0573005730, ZO0313203132\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,567191,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0113901139, ZO0478904789\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,567135,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0528305283, ZO0549305493\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,727730,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,567939,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0127201272, ZO0425504255\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,567301,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0577605776, ZO0438104381\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566801,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0279702797, ZO0573705737\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566685,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0296902969, ZO0530205302\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566924,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0673606736, ZO0161801618\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,20,567708,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0090500905, ZO0466204662\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,567573,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0215602156, ZO0336803368\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,17,566986,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0360903609, ZO0030100301\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0632406324, ZO0060300603\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,14,566881,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0419604196, ZO0559705597\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,20,566790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0699206992, ZO0641306413\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,50,566935,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0473704737, ZO0121501215\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,566985,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0044700447, ZO0502105021\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,566729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0110401104\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,26,567095,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0339803398, ZO0098200982\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,724326,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,18,567973,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0495104951, ZO0305903059\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,567341,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0674506745, ZO0219202192\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,567492,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0277302773, ZO0443004430\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,567403,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0138601386, ZO0259202592\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,567207,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0033600336, ZO0109401094\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,13,567356,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0319503195, ZO0409904099\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565855,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417504175, ZO0535205352\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566343,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0185101851, ZO0052800528\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,26,566400,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0204702047, ZO0009600096\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565776,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343103431, ZO0345803458\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,566607,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0572205722, ZO0585205852\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565452,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0133601336, ZO0643906439\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,566051,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0025600256, ZO0270202702\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565466,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285402854, ZO0538605386\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566553,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0435004350, ZO0544005440\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565446,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0643206432, ZO0140101401\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566053,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0284702847, ZO0299202992\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,566170,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0324803248, ZO0703907039\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,566187,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0548905489, ZO0459404594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,566125,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0433104331, ZO0549505495\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566156,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0117901179\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,566100,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0013400134, ZO0667306673\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,32,566280,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0116701167\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,566256,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227302273, ZO0668706687\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,27,565639,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0193901939, ZO0080400804\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565945,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0270602706, ZO0269502695\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,18,565988,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0074700747, ZO0645206452\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,15,565732,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0291402914, ZO0603006030\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,29,566042,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0451804518, ZO0127901279\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,25,566456,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0597105971, ZO0283702837\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565542,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224302243, ZO0359103591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,566121,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0227202272, ZO0357003570\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,566653,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0666506665, ZO0216602166\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,28,565838,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0343703437, ZO0207102071\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,6,565804,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0306803068, ZO0174601746\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,565459,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0242302423, ZO0676006760\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565819,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0031700317, ZO0157701577\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,17,731352,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565900,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0266102661, ZO0169701697\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,566360,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0285102851, ZO0658306583\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,46,565796,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081500815, ZO0342603426\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,34,566261,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0577105771, ZO0289302893\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,565567,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0437604376, ZO0618906189\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565596,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0332903329, ZO0159401594\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,20,566428,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0136501365, ZO0339103391\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,45,566334,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0010800108, ZO0635706357\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,566391,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228302283, ZO0167501675\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,566315,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0703707037, ZO0139601396\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565698,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0336503365, ZO0637006370\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,15,566167,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623006230, ZO0419304193\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566070,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046100461, ZO0151201512\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,16,566621,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0579605796, ZO0315803158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,566284,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0541405414, ZO0588205882\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,566518,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0554605546, ZO0569005690\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565830,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0215702157, ZO0638806388\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,22,565948,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0190701907, ZO0654806548\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,26,565998,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0238802388, ZO0066600666\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565401,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0014800148, ZO0154501545\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,565728,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486404864, ZO0248602486\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,565489,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0077200772, ZO0643006430\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Women's Accessories\\",EUR,25,720445,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565768,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0458004580, ZO0273402734\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,565538,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0486804868, ZO0371603716\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,12,565404,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0048900489, ZO0228702287\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,715961,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,5,566382,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0503505035, ZO0240302403\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,49,565877,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0125401254, ZO0123701237\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,48,565479,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0588805888, ZO0314903149\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565360,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0450704507\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,565970,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0673406734, ZO0165601656\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,27,723242,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,566580,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0417304173, ZO0123001230\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,48,566671,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0427604276, ZO0113801138\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,52,566176,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0607206072, ZO0431404314\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,566146,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0646206462, ZO0146201462\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565760,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0504505045, ZO0223802238\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,565521,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0660406604, ZO0484504845\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,566320,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0105001050, ZO0652306523\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,566357,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0061600616, ZO0180701807\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,566415,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0261102611, ZO0667106671\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,566044,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0552605526, ZO0292702927\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,565473,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0365303653, ZO0235802358\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,18,565339,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0346503465, ZO0678406784\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,5,730725,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,566443,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0160201602, ZO0261502615\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,565985,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0436604366, ZO0280302803\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565640,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0631606316, ZO0045300453\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,49,565683,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0573205732, ZO0310303103\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565767,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0414304143, ZO0425204252\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,566452,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0706307063, ZO0011300113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,13,565982,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0410804108, ZO0309303093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,726754,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,24,565723,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0302303023, ZO0246602466\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Men's Clothing\\",EUR,31,565896,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0466104661, ZO0444104441\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,52,718085,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,566248,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0678806788, ZO0186101861\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,565560,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0567505675, ZO0442104421\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,566155,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0501005010, ZO0214002140\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,28,566628,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0195601956, ZO0098900989\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,9,566519,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0700907009, ZO0115801158\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,565697,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0498904989, ZO0641706417\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,45,566417,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0084900849, ZO0194701947\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,565722,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0656406564, ZO0495504955\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,36,565330,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0621606216, ZO0628806288\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,44,565381,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0060200602, ZO0076300763\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,39,565564,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0576305763, ZO0116801168\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565392,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0616606166, ZO0592205922\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,6,565410,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0023600236, ZO0704307043\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565504,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0653406534, ZO0049300493\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,565334,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0641706417, ZO0382303823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,566622,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0228402284, ZO0082300823\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,27,566650,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0049100491, ZO0194801948\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,566295,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0635606356, ZO0043100431\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,566538,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0224402244, ZO0342403424\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,565918,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0155001550, ZO0072100721\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,565678,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0081800818, ZO0485604856\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,565498,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0046600466, ZO0503305033\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,565793,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0712807128, ZO0007500075\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,566232,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0545205452, ZO0437304373\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,566591,\\"-\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0502405024, ZO0366003660\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564710,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0263402634, ZO0499404994\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564429,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0260702607, ZO0495804958\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564479,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0409304093, ZO0436904369\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,6,564885,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303803038, ZO0192501925\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,565150,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0624906249, ZO0411604116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564759,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218802188, ZO0492604926\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,17,564144,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0218602186, ZO0501005010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,563909,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452804528, ZO0453604536\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,28,564869,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0192401924, ZO0366703667\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,11,564269,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0281102811, ZO0555705557\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,43,564893,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0322403224, ZO0227802278\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564215,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0147201472, ZO0152201522\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564725,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0071700717, ZO0364303643\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564331,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0229402294, ZO0303303033\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564350,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444104441, ZO0476804768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564398,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0328703287, ZO0351003510\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,22,564409,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0178501785, ZO0503805038\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,8,564024,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0619006190\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564676,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0108401084, ZO0139301393\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,19,564445,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0593805938, ZO0701407014\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing\\",EUR,50,564241,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0605506055, ZO0547505475\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564844,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0553205532, ZO0526205262\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,28,564883,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0705607056, ZO0334703347\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,5,564307,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0246602466, ZO0195201952\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,5,564148,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0057900579, ZO0211602116\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,44,564009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0487904879, ZO0027100271\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,52,564532,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0474704747, ZO0622006220\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,565308,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0172401724, ZO0184901849\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,27,564339,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0082900829, ZO0347903479\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,37,564361,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0422304223, ZO0600506005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,28,564394,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0269902699, ZO0667906679\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564030,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0179901799, ZO0637606376\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564661,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415004150, ZO0125501255\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,43,564706,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0709007090, ZO0362103621\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564460,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0655106551, ZO0349403494\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,22,564536,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0304603046, ZO0370603706\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,46,564559,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0015500155, ZO0650806508\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,18,564609,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0162401624, ZO0156001560\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,25,565138,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0615506155, ZO0445304453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,51,565025,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0280802808, ZO0549005490\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,27,564000,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0364603646, ZO0018200182\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,564557,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0664606646, ZO0460404604\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,27,564604,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0237702377, ZO0304303043\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,23,564777,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0452704527, ZO0122201222\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,26,564812,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0266002660, ZO0031900319\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,22,563964,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0001200012, ZO0251902519\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564315,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0263702637\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,565237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0323303233, ZO0172101721\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564510,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093600936, ZO0145301453\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,12,565222,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0102001020, ZO0252402524\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,565233,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0614906149, ZO0430404304\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,31,565084,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0549805498, ZO0541205412\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564796,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0022100221, ZO0172301723\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,26,564627,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0211702117, ZO0499004990\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,29,564257,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539205392, ZO0577705777\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,564701,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0585205852, ZO0418104181\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,22,564954,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0362903629, ZO0048100481\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,565009,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0225302253, ZO0183101831\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564065,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711207112, ZO0646106461\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,46,563927,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0009800098, ZO0362803628\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,43,564994,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0180601806, ZO0710007100\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,24,564070,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0234202342, ZO0245102451\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,5,727071,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,564380,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0050400504, ZO0660006600\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,565276,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0131501315, ZO0668806688\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564819,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0374603746, ZO0697106971\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,38,717243,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,45,564140,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0221002210, ZO0268502685\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,5,564164,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0673506735, ZO0213002130\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,564207,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0711807118, ZO0073100731\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,19,565077,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118701187, ZO0123901239\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,13,564274,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0542905429, ZO0423604236\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,30,565161,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0441404414, ZO0430504305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,42,565039,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0489804898, ZO0695006950\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,723683,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,6,563967,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0493404934, ZO0640806408\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,46,564533,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0496704967, ZO0049700497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,4,564818,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0475004750, ZO0412304123\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,23,564932,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0557305573, ZO0607806078\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,18,564968,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0134101341, ZO0062400624\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,44,565002,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0354203542, ZO0338503385\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,563924,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0539805398, ZO0554205542\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,564770,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0704907049, ZO0024700247\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,563965,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0045800458, ZO0503405034\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,24,564957,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0171601716, ZO0214602146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,37,564075,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0622706227, ZO0525405254\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,34,563931,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0444304443, ZO0596505965\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,18,564940,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0026800268, ZO0003600036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564987,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0526805268, ZO0478104781\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,25,564080,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0415804158, ZO0460804608\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Accessories\\",EUR,8,564106,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0298002980, ZO0313103131\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,26,563947,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0348103481, ZO0164501645\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,725995,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,21,565137,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0118501185, ZO0561905619\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,565173,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0203802038, ZO0014900149\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,20,564804,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0259702597, ZO0640606406\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Clothing\\",EUR,43,565052,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697006970, ZO0711407114\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,45,565091,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0324703247, ZO0088600886\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,565231,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0235202352, ZO0135001350\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,6,564190,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0243902439, ZO0208702087\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,42,564876,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0215502155, ZO0168101681\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,27,564902,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0698406984, ZO0704207042\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,27,564761,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0665006650, ZO0709407094\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,27,731788,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,24,564395,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0236702367, ZO0660706607\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes\\",EUR,45,564686,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0373303733, ZO0131201312\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,44,564446,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0093400934, ZO0679406794\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,43,564481,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0321603216, ZO0078000780\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Accessories\\",EUR,20,563953,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0376203762, ZO0303603036\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing\\",EUR,27,565100,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0069000690, ZO0490004900\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,7,565263,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0582705827, ZO0111801118\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,33,563984,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0294102941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories\\",EUR,12,565262,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0303503035, ZO0197601976\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,28,565304,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0017800178, ZO0229602296\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,9,564121,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0291902919, ZO0617206172\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories\\",EUR,23,564166,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0607106071, ZO0470704707\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,17,564739,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0335603356, ZO0236502365\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing\\",EUR,16,564016,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0436904369, ZO0290402904\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Accessories\\",EUR,43,564605,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0333103331, ZO0694806948\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Accessories, Women's Shoes\\",EUR,17,730663,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Shoes, Women's Clothing\\",EUR,44,564221,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0249702497, ZO0487404874\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Women's Clothing, Women's Shoes\\",EUR,42,564174,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0032300323, ZO0236302363\\" +" +`; + +exports[`discover Discover CSV Export Generate CSV: archived search generates a report with filtered data 1`] = ` +"\\"order_date\\",category,currency,\\"customer_id\\",\\"order_id\\",\\"day_of_week_i\\",\\"products.created_on\\",sku +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,719675,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0448604486, ZO0686206862, ZO0395403954, ZO0528505285\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,570232,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0682006820, ZO0399103991\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570111,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0253002530, ZO0117101171\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,570480,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0286202862, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,719459,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0410004100, ZO0513605136, ZO0431404314, ZO0662906629\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,25,570303,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0573305733, ZO0513205132\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,569806,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0558305583\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,570477,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0299202992, ZO0392403924\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,569743,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0610306103\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,38,714566,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0430204302, ZO0397303973, ZO0686806868, ZO0320403204\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,570120,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392903929, ZO0254802548\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,32,570414,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0481704817, ZO0396503965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,39,569436,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0386103861, ZO0451504515\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,569637,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0300103001, ZO0688106881\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,569645,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0392803928, ZO0277102771\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569362,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0292402924, ZO0681006810\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes, Women's Accessories\\",EUR,52,713556,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0592105921, ZO0421204212, ZO0400604006, ZO0319403194\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,570334,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0520205202, ZO0545205452\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,570143,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0482904829\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,570586,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0596505965\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,569336,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0384103841\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,569984,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0537205372, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,34,570003,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0298902989, ZO0694506945\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,569392,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0516405164, ZO0532705327\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,31,569312,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0425104251, ZO0107901079\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,570009,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0510705107, ZO0594605946\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,569985,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0554005540, ZO0403504035\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,569905,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0599605996, ZO0403804038\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569699,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398603986, ZO0521305213\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,29,569736,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0517305173, ZO0319703197\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569777,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0254302543, ZO0289102891\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,36,570388,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0405604056, ZO0604506045\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,51,570620,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0422204222, ZO0256502565\\" +\\"Jun 26, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,50,569694,3,\\"Dec 15, 2016 @ 00:00:00.000, Dec 15, 2016 @ 00:00:00.000\\",\\"ZO0398703987, ZO0687806878\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,568331,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0385903859, ZO0516605166\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,568524,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0694706947\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,14,568682,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0680706807, ZO0392603926\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,31,568350,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0317303173, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,31,568531,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0482104821, ZO0447104471\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,29,568578,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0520005200, ZO0421104211\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,568609,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0570405704, ZO0256102561\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,568652,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0403304033, ZO0125901259\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,25,714149,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,52,569163,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0682706827\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,15,568943,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0445804458, ZO0686106861\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,23,569046,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0393103931, ZO0619906199\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,33,568993,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482604826\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,568845,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0657906579, ZO0258102581\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,30,569097,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0511605116, ZO0483004830\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,52,568117,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0315203152, ZO0406304063\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,49,569209,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0472304723, ZO0403504035\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,717726,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568854,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0616706167, ZO0255402554\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,9,568954,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0399603996, ZO0685906859\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,11,569091,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0258602586, ZO0552205522\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,4,569003,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0414704147, ZO0387503875\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,41,568707,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0513305133, ZO0253302533\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,569299,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519605196, ZO0630806308\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,568212,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0536405364, ZO0688306883\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,568228,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0580005800\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,568455,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0413104131, ZO0392303923\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,721706,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568177,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0584505845, ZO0403804038\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,33,568898,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0542205422, ZO0517805178\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,568325,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0288202882, ZO0391803918\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,568638,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0388003880, ZO0478304783\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,25,716889,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\" +\\"Jun 25, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,568319,2,\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"ZO0535105351, ZO0403504035\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,7,567340,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0615606156, ZO0514905149\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567755,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0571405714, ZO0255402554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,9,566680,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0316703167, ZO0393303933\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,11,566734,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0691006910, ZO0314203142\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567240,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421004210, ZO0689006890\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,567290,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0442704427\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,7,567790,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0522405224, ZO0405104051\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,567465,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0274502745, ZO0686006860\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,567735,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0129701297, ZO0518705187\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,8,566861,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0520305203, ZO0462204622\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,19,567729,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0395103951, ZO0296102961\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,49,566951,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0517405174\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,567318,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0421104211, ZO0256202562\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,37,567316,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0403004030\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,567418,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400404004, ZO0625006250\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,567404,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0107101071, ZO0537905379\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567475,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0578805788, ZO0520405204\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,567835,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0589405894, ZO0483304833\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,29,567889,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0282202822, ZO0393003930\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,566852,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0257002570, ZO0455404554\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,721778,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567970,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0441504415, ZO0691606916\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,11,567662,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0308903089, ZO0614306143\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,717603,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,9,567082,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0278802788, ZO0515605156\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,566706,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0521505215, ZO0130501305\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,4,567806,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0517705177, ZO0569305693\\" +\\"Jun 24, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,14,567654,1,\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"ZO0121301213, ZO0399403994\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,19,565915,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0515005150, ZO0509805098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,13,565605,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0113301133\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,31,565708,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0253302533, ZO0605706057\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,30,565809,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0557905579, ZO0513705137\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,38,565684,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0507705077, ZO0409804098\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,36,566101,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0691406914, ZO0617806178\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,31,566247,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0403504035\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,37,566036,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0583605836, ZO0510605106\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,11,565667,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0618706187, ZO0388503885\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,33,566416,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0396903969, ZO0607906079\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Women's Accessories\\",EUR,52,717206,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,715081,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,715133,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,52,717057,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,9,566215,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0384903849, ZO0579305793\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,25,565580,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0395303953, ZO0386703867\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,16,566454,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0547405474, ZO0401104011\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,30,566506,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0680806808, ZO0609306093\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565366,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0684906849, ZO0575905759\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,566364,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0512505125, ZO0525005250\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,39,565734,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0513205132, ZO0258202582\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,19,566514,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0539305393, ZO0522305223\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,720399,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565591,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0683806838, ZO0429204292\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,566498,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0387103871, ZO0550005500\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,8,566186,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0522105221, ZO0459104591\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,566079,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0663306633, ZO0687306873\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,16,566564,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0107301073, ZO0293002930\\" +\\"Jun 23, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,25,566259,0,\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"ZO0694206942, ZO0553805538\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,23,564670,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0531205312, ZO0684706847\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,52,564513,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0390003900, ZO0287902879\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,13,565206,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316303163, ZO0401004010\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,564619,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0470304703, ZO0406204062\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,34,564237,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0311203112, ZO0395703957\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,39,564842,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0432004320, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,37,564733,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0384303843, ZO0273702737\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,48,564271,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0507905079, ZO0430804308\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,50,564272,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0534405344, ZO0512105121\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,715752,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,34,565090,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0690306903, ZO0521005210\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,21,564649,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0405704057, ZO0411704117\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,8,564915,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0286502865, ZO0394703947\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,51,564937,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0520605206, ZO0432204322\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,13,563928,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0424104241, ZO0394103941\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,50,565284,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0687206872, ZO0422304223\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,30,564735,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0509705097, ZO0120501205\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Accessories\\",EUR,49,565266,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0255602556, ZO0468304683\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,48,564095,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0613806138, ZO0403504035\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,41,564032,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0478404784, ZO0521905219\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Clothing, Men's Shoes\\",EUR,32,564756,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0556805568, ZO0481504815\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,33,565214,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0403504035, ZO0588705887\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,10,564340,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0399703997, ZO0565805658\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,49,565061,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681106811, ZO0286402864\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Accessories, Men's Shoes\\",EUR,10,565123,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0316903169, ZO0400504005\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes\\",EUR,48,565160,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0693306933, ZO0514605146\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,14,565224,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0406604066, ZO0576805768\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,41,564576,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681206812, ZO0441904419\\" +\\"Jun 22, 2019 @ 00:00:00.000\\",\\"Men's Shoes, Men's Clothing\\",EUR,34,564366,6,\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"ZO0681906819, ZO0549705497\\" +" +`; + +exports[`discover Discover CSV Export Generate CSV: new search generates a large export 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +3AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Boone\\",\\"Sultan Al Boone\\",MALE,19,Boone,Boone,\\"(empty)\\",Saturday,5,\\"sultan al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan +9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,\\"(empty)\\",Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia +BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte +KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Govern" +`; + +exports[`discover Discover CSV Export Generate CSV: new search generates a large export 2`] = ` +"es\\",\\"21, 6.109\\",\\"42, 11.992\\",\\"13,181, 23,660\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"Briefcase - navy, Sports shirt - Seashell\\",\\"1, 1\\",\\"ZO0466704667, ZO0617306173\\",\\"0, 0\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"0, 0\\",\\"ZO0466704667, ZO0617306173\\",\\"53.969\\",\\"53.969\\",2,2,order,kamal +7QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Graves\\",\\"Elyssa Graves\\",FEMALE,27,Graves,Graves,\\"(empty)\\",Thursday,3,\\"elyssa@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 12, 2019 @ 00:00:00.000\\",551204,\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"sold_product_551204_16805, sold_product_551204_12896\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.129, 9.656\\",\\"13.992, 20.984\\",\\"16,805, 12,896\\",\\"Bustier - white, Across body bag - cognac\\",\\"Bustier - white, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0212602126, ZO0200702007\\",\\"0, 0\\",\\"13.992, 20.984\\",\\"13.992, 20.984\\",\\"0, 0\\",\\"ZO0212602126, ZO0200702007\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa +7gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Rose\\",\\"Pia Rose\\",FEMALE,45,Rose,Rose,\\"(empty)\\",Thursday,3,\\"pia@rose-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550466,\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"sold_product_550466_19198, sold_product_550466_16409\\",\\"50, 100\\",\\"50, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Primemaster\\",\\"Oceanavigations, Primemaster\\",\\"24, 52\\",\\"50, 100\\",\\"19,198, 16,409\\",\\"Summer dress - grey, Boots - passion\\",\\"Summer dress - grey, Boots - passion\\",\\"1, 1\\",\\"ZO0260702607, ZO0363203632\\",\\"0, 0\\",\\"50, 100\\",\\"50, 100\\",\\"0, 0\\",\\"ZO0260702607, ZO0363203632\\",150,150,2,2,order,pia +7wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Boone\\",\\"Wagdi Boone\\",MALE,15,Boone,Boone,\\"(empty)\\",Thursday,3,\\"wagdi@boone-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 12, 2019 @ 00:00:00.000\\",550503,\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"sold_product_550503_13211, sold_product_550503_24369\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.641, 6.109\\",\\"34, 11.992\\",\\"13,211, 24,369\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"Tracksuit top - black, Print T-shirt - khaki\\",\\"1, 1\\",\\"ZO0587505875, ZO0566405664\\",\\"0, 0\\",\\"34, 11.992\\",\\"34, 11.992\\",\\"0, 0\\",\\"ZO0587505875, ZO0566405664\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi +8AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hale\\",\\"Elyssa Hale\\",FEMALE,27,Hale,Hale,\\"(empty)\\",Thursday,3,\\"elyssa@hale-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550538,\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"sold_product_550538_15047, sold_product_550538_18189\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.5, 28.797\\",\\"75, 60\\",\\"15,047, 18,189\\",\\"Handbag - black, Ankle boots - grey\\",\\"Handbag - black, Ankle boots - grey\\",\\"1, 1\\",\\"ZO0699406994, ZO0246202462\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0699406994, ZO0246202462\\",135,135,2,2,order,elyssa +8QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Love\\",\\"Jackson Love\\",MALE,13,Love,Love,\\"(empty)\\",Thursday,3,\\"jackson@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 12, 2019 @ 00:00:00.000\\",550568,\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"sold_product_550568_17210, sold_product_550568_12524\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 1, 2016 @ 00:00:00.000, Dec 1, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25, 12.492\\",\\"50, 24.984\\",\\"17,210, 12,524\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"Casual lace-ups - navy, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0388403884, ZO0447604476\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0388403884, ZO0447604476\\",75,75,2,2,order,jackson +" +`; + +exports[`discover Discover CSV Export Generate CSV: new search generates a report from a new search with data: default 1`] = ` +"\\"_id\\",\\"_index\\",\\"_score\\",category,\\"category.keyword\\",currency,\\"customer_first_name\\",\\"customer_first_name.keyword\\",\\"customer_full_name\\",\\"customer_full_name.keyword\\",\\"customer_gender\\",\\"customer_id\\",\\"customer_last_name\\",\\"customer_last_name.keyword\\",\\"customer_phone\\",\\"day_of_week\\",\\"day_of_week_i\\",email,\\"geoip.city_name\\",\\"geoip.continent_name\\",\\"geoip.country_iso_code\\",\\"geoip.location\\",\\"geoip.region_name\\",manufacturer,\\"manufacturer.keyword\\",\\"order_date\\",\\"order_id\\",\\"products._id\\",\\"products._id.keyword\\",\\"products.base_price\\",\\"products.base_unit_price\\",\\"products.category\\",\\"products.category.keyword\\",\\"products.created_on\\",\\"products.discount_amount\\",\\"products.discount_percentage\\",\\"products.manufacturer\\",\\"products.manufacturer.keyword\\",\\"products.min_price\\",\\"products.price\\",\\"products.product_id\\",\\"products.product_name\\",\\"products.product_name.keyword\\",\\"products.quantity\\",\\"products.sku\\",\\"products.tax_amount\\",\\"products.taxful_price\\",\\"products.taxless_price\\",\\"products.unit_discount_amount\\",sku,\\"taxful_total_price\\",\\"taxless_total_price\\",\\"total_quantity\\",\\"total_unique_products\\",type,user +9AMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Bradley\\",\\"Boris Bradley\\",MALE,36,Bradley,Bradley,\\"(empty)\\",Wednesday,2,\\"boris@bradley-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568397,\\"sold_product_568397_24419, sold_product_568397_20207\\",\\"sold_product_568397_24419, sold_product_568397_20207\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"17.484, 13.922\\",\\"33, 28.984\\",\\"24,419, 20,207\\",\\"Cargo trousers - oliv, Trousers - black\\",\\"Cargo trousers - oliv, Trousers - black\\",\\"1, 1\\",\\"ZO0112101121, ZO0530405304\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0112101121, ZO0530405304\\",\\"61.969\\",\\"61.969\\",2,2,order,boris +9QMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Hubbard\\",\\"Oliver Hubbard\\",MALE,7,Hubbard,Hubbard,\\"(empty)\\",Wednesday,2,\\"oliver@hubbard-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spritechnologies, Microlutions\\",\\"Spritechnologies, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568044,\\"sold_product_568044_12799, sold_product_568044_18008\\",\\"sold_product_568044_12799, sold_product_568044_18008\\",\\"14.992, 16.984\\",\\"14.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Microlutions\\",\\"Spritechnologies, Microlutions\\",\\"6.898, 8.828\\",\\"14.992, 16.984\\",\\"12,799, 18,008\\",\\"Undershirt - dark grey multicolor, Long sleeved top - purple\\",\\"Undershirt - dark grey multicolor, Long sleeved top - purple\\",\\"1, 1\\",\\"ZO0630406304, ZO0120201202\\",\\"0, 0\\",\\"14.992, 16.984\\",\\"14.992, 16.984\\",\\"0, 0\\",\\"ZO0630406304, ZO0120201202\\",\\"31.984\\",\\"31.984\\",2,2,order,oliver +OAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Betty,Betty,\\"Betty Reese\\",\\"Betty Reese\\",FEMALE,44,Reese,Reese,\\"(empty)\\",Wednesday,2,\\"betty@reese-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568229,\\"sold_product_568229_24991, sold_product_568229_12039\\",\\"sold_product_568229_24991, sold_product_568229_12039\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.352, 5.82\\",\\"11.992, 10.992\\",\\"24,991, 12,039\\",\\"Scarf - rose/white, Scarf - nude/black/turquoise\\",\\"Scarf - rose/white, Scarf - nude/black/turquoise\\",\\"1, 1\\",\\"ZO0192201922, ZO0192801928\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0192201922, ZO0192801928\\",\\"22.984\\",\\"22.984\\",2,2,order,betty +OQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Recip,Recip,\\"Recip Salazar\\",\\"Recip Salazar\\",MALE,10,Salazar,Salazar,\\"(empty)\\",Wednesday,2,\\"recip@salazar-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568292,\\"sold_product_568292_23627, sold_product_568292_11149\\",\\"sold_product_568292_23627, sold_product_568292_11149\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.492, 5.059\\",\\"24.984, 10.992\\",\\"23,627, 11,149\\",\\"Slim fit jeans - grey, Sunglasses - black\\",\\"Slim fit jeans - grey, Sunglasses - black\\",\\"1, 1\\",\\"ZO0534205342, ZO0599605996\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0534205342, ZO0599605996\\",\\"35.969\\",\\"35.969\\",2,2,order,recip +jwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Harper\\",\\"Jackson Harper\\",MALE,13,Harper,Harper,\\"(empty)\\",Wednesday,2,\\"jackson@harper-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568386,\\"sold_product_568386_11959, sold_product_568386_2774\\",\\"sold_product_568386_11959, sold_product_568386_2774\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"12.742, 45.875\\",\\"24.984, 85\\",\\"11,959, 2,774\\",\\"SLIM FIT - Formal shirt - lila, Classic coat - black\\",\\"SLIM FIT - Formal shirt - lila, Classic coat - black\\",\\"1, 1\\",\\"ZO0422404224, ZO0291702917\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0422404224, ZO0291702917\\",110,110,2,2,order,jackson +kAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Brewer\\",\\"Betty Brewer\\",FEMALE,44,Brewer,Brewer,\\"(empty)\\",Wednesday,2,\\"betty@brewer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568023,\\"sold_product_568023_22309, sold_product_568023_22315\\",\\"sold_product_568023_22309, sold_product_568023_22315\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"5.879, 8.656\\",\\"11.992, 16.984\\",\\"22,309, 22,315\\",\\"Wallet - brown, Summer dress - black\\",\\"Wallet - brown, Summer dress - black\\",\\"1, 1\\",\\"ZO0075900759, ZO0489304893\\",\\"0, 0\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"0, 0\\",\\"ZO0075900759, ZO0489304893\\",\\"28.984\\",\\"28.984\\",2,2,order,betty +9wMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Selena,Selena,\\"Selena Hernandez\\",\\"Selena Hernandez\\",FEMALE,42,Hernandez,Hernandez,\\"(empty)\\",Wednesday,2,\\"selena@hernandez-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568789,\\"sold_product_568789_11481, sold_product_568789_17046\\",\\"sold_product_568789_11481, sold_product_568789_17046\\",\\"24.984, 30.984\\",\\"24.984, 30.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"12.492, 15.797\\",\\"24.984, 30.984\\",\\"11,481, 17,046\\",\\"Tote bag - black, SET - Watch - rose gold-coloured\\",\\"Tote bag - black, SET - Watch - rose gold-coloured\\",\\"1, 1\\",\\"ZO0197501975, ZO0079300793\\",\\"0, 0\\",\\"24.984, 30.984\\",\\"24.984, 30.984\\",\\"0, 0\\",\\"ZO0197501975, ZO0079300793\\",\\"55.969\\",\\"55.969\\",2,2,order,selena +\\"-AMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Greene\\",\\"Kamal Greene\\",MALE,39,Greene,Greene,\\"(empty)\\",Wednesday,2,\\"kamal@greene-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568331,\\"sold_product_568331_11375, sold_product_568331_14190\\",\\"sold_product_568331_11375, sold_product_568331_14190\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"19.734, 13.344\\",\\"42, 28.984\\",\\"11,375, 14,190\\",\\"Lace-ups - Midnight Blue, Trainers - grey\\",\\"Lace-ups - Midnight Blue, Trainers - grey\\",\\"1, 1\\",\\"ZO0385903859, ZO0516605166\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0385903859, ZO0516605166\\",71,71,2,2,order,kamal +\\"-QMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Ryan\\",\\"Kamal Ryan\\",MALE,39,Ryan,Ryan,\\"(empty)\\",Wednesday,2,\\"kamal@ryan-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568524,\\"sold_product_568524_17644, sold_product_568524_12625\\",\\"sold_product_568524_17644, sold_product_568524_12625\\",\\"60, 60\\",\\"60, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"29.406, 31.188\\",\\"60, 60\\",\\"17,644, 12,625\\",\\"Suit jacket - dark blue, T-bar sandals - cognac\\",\\"Suit jacket - dark blue, T-bar sandals - cognac\\",\\"1, 1\\",\\"ZO0424104241, ZO0694706947\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0424104241, ZO0694706947\\",120,120,2,2,order,kamal +\\"-gMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Recip,Recip,\\"Recip Reese\\",\\"Recip Reese\\",MALE,10,Reese,Reese,\\"(empty)\\",Wednesday,2,\\"recip@reese-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568589,\\"sold_product_568589_19575, sold_product_568589_21053\\",\\"sold_product_568589_19575, sold_product_568589_21053\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"35.094, 5.391\\",\\"65, 10.992\\",\\"19,575, 21,053\\",\\"Short coat - oliv, Print T-shirt - white/blue\\",\\"Short coat - oliv, Print T-shirt - white/blue\\",\\"1, 1\\",\\"ZO0114401144, ZO0564705647\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0114401144, ZO0564705647\\",76,76,2,2,order,recip +\\"-wMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Pope\\",\\"Oliver Pope\\",MALE,7,Pope,Pope,\\"(empty)\\",Wednesday,2,\\"oliver@pope-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568640,\\"sold_product_568640_20196, sold_product_568640_12339\\",\\"sold_product_568640_20196, sold_product_568640_12339\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"13.344, 10.906\\",\\"28.984, 20.984\\",\\"20,196, 12,339\\",\\"Sweatshirt - bright white, Polo shirt - grey multicolor\\",\\"Sweatshirt - bright white, Polo shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0125901259, ZO0443204432\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0125901259, ZO0443204432\\",\\"49.969\\",\\"49.969\\",2,2,order,oliver +\\"_AMtOW0BH63Xcmy432HJ\\",ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Henderson\\",\\"Irwin Henderson\\",MALE,14,Henderson,Henderson,\\"(empty)\\",Wednesday,2,\\"irwin@henderson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568682,\\"sold_product_568682_21985, sold_product_568682_15522\\",\\"sold_product_568682_21985, sold_product_568682_15522\\",\\"60, 42\\",\\"60, 42\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"28.797, 19.734\\",\\"60, 42\\",\\"21,985, 15,522\\",\\"Smart lace-ups - black, Smart lace-ups - cognac\\",\\"Smart lace-ups - black, Smart lace-ups - cognac\\",\\"1, 1\\",\\"ZO0680706807, ZO0392603926\\",\\"0, 0\\",\\"60, 42\\",\\"60, 42\\",\\"0, 0\\",\\"ZO0680706807, ZO0392603926\\",102,102,2,2,order,irwin +XQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Miller\\",\\"Rabbia Al Miller\\",FEMALE,5,Miller,Miller,\\"(empty)\\",Wednesday,2,\\"rabbia al@miller-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569259,\\"sold_product_569259_18845, sold_product_569259_21703\\",\\"sold_product_569259_18845, sold_product_569259_21703\\",\\"55, 60\\",\\"55, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"25.844, 28.203\\",\\"55, 60\\",\\"18,845, 21,703\\",\\"Summer dress - navy blazer, Ankle boots - tan \\",\\"Summer dress - navy blazer, Ankle boots - tan \\",\\"1, 1\\",\\"ZO0335503355, ZO0381003810\\",\\"0, 0\\",\\"55, 60\\",\\"55, 60\\",\\"0, 0\\",\\"ZO0335503355, ZO0381003810\\",115,115,2,2,order,rabbia +HAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Washington\\",\\"Hicham Washington\\",MALE,8,Washington,Washington,\\"(empty)\\",Wednesday,2,\\"hicham@washington-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568793,\\"sold_product_568793_17004, sold_product_568793_20936\\",\\"sold_product_568793_17004, sold_product_568793_20936\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"18.141, 4.23\\",\\"33, 7.988\\",\\"17,004, 20,936\\",\\"Watch - dark brown, Basic T-shirt - dark blue\\",\\"Watch - dark brown, Basic T-shirt - dark blue\\",\\"1, 1\\",\\"ZO0312503125, ZO0545505455\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0312503125, ZO0545505455\\",\\"40.969\\",\\"40.969\\",2,2,order,hicham +HQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Youssef,Youssef,\\"Youssef Porter\\",\\"Youssef Porter\\",MALE,31,Porter,Porter,\\"(empty)\\",Wednesday,2,\\"youssef@porter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568350,\\"sold_product_568350_14392, sold_product_568350_24934\\",\\"sold_product_568350_14392, sold_product_568350_24934\\",\\"42, 50\\",\\"42, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"21.406, 22.5\\",\\"42, 50\\",\\"14,392, 24,934\\",\\"Zantos - Wash bag - black, Lace-up boots - resin coffee\\",\\"Zantos - Wash bag - black, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0317303173, ZO0403504035\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0317303173, ZO0403504035\\",92,92,2,2,order,youssef +HgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Moss\\",\\"Youssef Moss\\",MALE,31,Moss,Moss,\\"(empty)\\",Wednesday,2,\\"youssef@moss-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"(empty), Low Tide Media\\",\\"(empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568531,\\"sold_product_568531_12837, sold_product_568531_13153\\",\\"sold_product_568531_12837, sold_product_568531_13153\\",\\"165, 24.984\\",\\"165, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"(empty), Low Tide Media\\",\\"(empty), Low Tide Media\\",\\"77.563, 12\\",\\"165, 24.984\\",\\"12,837, 13,153\\",\\"Smart lace-ups - cognac, Cardigan - grey\\",\\"Smart lace-ups - cognac, Cardigan - grey\\",\\"1, 1\\",\\"ZO0482104821, ZO0447104471\\",\\"0, 0\\",\\"165, 24.984\\",\\"165, 24.984\\",\\"0, 0\\",\\"ZO0482104821, ZO0447104471\\",190,190,2,2,order,youssef +HwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Cross\\",\\"Robert Cross\\",MALE,29,Cross,Cross,\\"(empty)\\",Wednesday,2,\\"robert@cross-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568578,\\"sold_product_568578_17925, sold_product_568578_16500\\",\\"sold_product_568578_17925, sold_product_568578_16500\\",\\"47, 33\\",\\"47, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"24.438, 16.813\\",\\"47, 33\\",\\"17,925, 16,500\\",\\"Boots - tan, Casual Cuffed Pants\\",\\"Boots - tan, Casual Cuffed Pants\\",\\"1, 1\\",\\"ZO0520005200, ZO0421104211\\",\\"0, 0\\",\\"47, 33\\",\\"47, 33\\",\\"0, 0\\",\\"ZO0520005200, ZO0421104211\\",80,80,2,2,order,robert +IAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Cunningham\\",\\"Phil Cunningham\\",MALE,50,Cunningham,Cunningham,\\"(empty)\\",Wednesday,2,\\"phil@cunningham-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568609,\\"sold_product_568609_11893, sold_product_568609_2361\\",\\"sold_product_568609_11893, sold_product_568609_2361\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.172, 30\\",\\"10.992, 60\\",\\"11,893, 2,361\\",\\"Polo shirt - dark blue, Lace-up boots - dark brown\\",\\"Polo shirt - dark blue, Lace-up boots - dark brown\\",\\"1, 1\\",\\"ZO0570405704, ZO0256102561\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0570405704, ZO0256102561\\",71,71,2,2,order,phil +IQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Carr\\",\\"Thad Carr\\",MALE,30,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"thad@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568652,\\"sold_product_568652_23582, sold_product_568652_20196\\",\\"sold_product_568652_23582, sold_product_568652_20196\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"24, 13.344\\",\\"50, 28.984\\",\\"23,582, 20,196\\",\\"Boots - black, Sweatshirt - bright white\\",\\"Boots - black, Sweatshirt - bright white\\",\\"1, 1\\",\\"ZO0403304033, ZO0125901259\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0403304033, ZO0125901259\\",79,79,2,2,order,thad +TAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Muniz,Muniz,\\"Muniz Jackson\\",\\"Muniz Jackson\\",MALE,37,Jackson,Jackson,\\"(empty)\\",Wednesday,2,\\"muniz@jackson-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568068,\\"sold_product_568068_12333, sold_product_568068_15128\\",\\"sold_product_568068_12333, sold_product_568068_15128\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.648, 5.059\\",\\"16.984, 10.992\\",\\"12,333, 15,128\\",\\"Tracksuit top - black, Wallet - brown\\",\\"Tracksuit top - black, Wallet - brown\\",\\"1, 1\\",\\"ZO0583005830, ZO0602706027\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0583005830, ZO0602706027\\",\\"27.984\\",\\"27.984\\",2,2,order,muniz +jgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Pope\\",\\"George Pope\\",MALE,32,Pope,Pope,\\"(empty)\\",Wednesday,2,\\"george@pope-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568070,\\"sold_product_568070_14421, sold_product_568070_13685\\",\\"sold_product_568070_14421, sold_product_568070_13685\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.703, 8.328\\",\\"20.984, 16.984\\",\\"14,421, 13,685\\",\\"Jumper - mottled grey/camel/khaki, Print T-shirt - grey multicolor\\",\\"Jumper - mottled grey/camel/khaki, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0575605756, ZO0293302933\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0575605756, ZO0293302933\\",\\"37.969\\",\\"37.969\\",2,2,order,george +jwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Duncan\\",\\"Selena Duncan\\",FEMALE,42,Duncan,Duncan,\\"(empty)\\",Wednesday,2,\\"selena@duncan-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568106,\\"sold_product_568106_8745, sold_product_568106_15742\\",\\"sold_product_568106_8745, sold_product_568106_15742\\",\\"33, 8.992\\",\\"33, 8.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"17.156, 4.941\\",\\"33, 8.992\\",\\"8,745, 15,742\\",\\"Cardigan - mottled brown, Tights - dark navy\\",\\"Cardigan - mottled brown, Tights - dark navy\\",\\"1, 1\\",\\"ZO0068700687, ZO0101301013\\",\\"0, 0\\",\\"33, 8.992\\",\\"33, 8.992\\",\\"0, 0\\",\\"ZO0068700687, ZO0101301013\\",\\"41.969\\",\\"41.969\\",2,2,order,selena +swMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Jensen\\",\\"Wilhemina St. Jensen\\",FEMALE,17,Jensen,Jensen,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@jensen-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568439,\\"sold_product_568439_16712, sold_product_568439_5602\\",\\"sold_product_568439_16712, sold_product_568439_5602\\",\\"20.984, 100\\",\\"20.984, 100\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"9.656, 46\\",\\"20.984, 100\\",\\"16,712, 5,602\\",\\"Blouse - black/pink/blue, Winter boots - black\\",\\"Blouse - black/pink/blue, Winter boots - black\\",\\"1, 1\\",\\"ZO0170601706, ZO0251502515\\",\\"0, 0\\",\\"20.984, 100\\",\\"20.984, 100\\",\\"0, 0\\",\\"ZO0170601706, ZO0251502515\\",121,121,2,2,order,wilhemina +tAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Lawrence\\",\\"Thad Lawrence\\",MALE,30,Lawrence,Lawrence,\\"(empty)\\",Wednesday,2,\\"thad@lawrence-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568507,\\"sold_product_568507_6098, sold_product_568507_24890\\",\\"sold_product_568507_6098, sold_product_568507_24890\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"41.25, 10.438\\",\\"75, 18.984\\",\\"6,098, 24,890\\",\\"Parka - black, Shirt - mottled grey\\",\\"Parka - black, Shirt - mottled grey\\",\\"1, 1\\",\\"ZO0431304313, ZO0523605236\\",\\"0, 0\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"0, 0\\",\\"ZO0431304313, ZO0523605236\\",94,94,2,2,order,thad +KgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Daniels\\",\\"Marwan Daniels\\",MALE,51,Daniels,Daniels,\\"(empty)\\",Wednesday,2,\\"marwan@daniels-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568236,\\"sold_product_568236_6221, sold_product_568236_11869\\",\\"sold_product_568236_6221, sold_product_568236_11869\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.07, 10.906\\",\\"28.984, 20.984\\",\\"6,221, 11,869\\",\\"Shirt - dark blue, Sweatshirt - grey multicolor\\",\\"Shirt - dark blue, Sweatshirt - grey multicolor\\",\\"1, 1\\",\\"ZO0416604166, ZO0581605816\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0416604166, ZO0581605816\\",\\"49.969\\",\\"49.969\\",2,2,order,marwan +KwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568275,\\"sold_product_568275_17190, sold_product_568275_15978\\",\\"sold_product_568275_17190, sold_product_568275_15978\\",\\"60, 6.988\\",\\"60, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"27, 3.43\\",\\"60, 6.988\\",\\"17,190, 15,978\\",\\"Pleated skirt - grey, 2 PACK - Socks - black \\",\\"Pleated skirt - grey, 2 PACK - Socks - black \\",\\"1, 1\\",\\"ZO0330903309, ZO0214802148\\",\\"0, 0\\",\\"60, 6.988\\",\\"60, 6.988\\",\\"0, 0\\",\\"ZO0330903309, ZO0214802148\\",67,67,2,2,order,brigitte +LAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Padilla\\",\\"Elyssa Padilla\\",FEMALE,27,Padilla,Padilla,\\"(empty)\\",Wednesday,2,\\"elyssa@padilla-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568434,\\"sold_product_568434_15265, sold_product_568434_22206\\",\\"sold_product_568434_15265, sold_product_568434_22206\\",\\"145, 14.992\\",\\"145, 14.992\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"78.313, 7.051\\",\\"145, 14.992\\",\\"15,265, 22,206\\",\\"High heeled boots - brown, Ballet pumps - navy\\",\\"High heeled boots - brown, Ballet pumps - navy\\",\\"1, 1\\",\\"ZO0362203622, ZO0000300003\\",\\"0, 0\\",\\"145, 14.992\\",\\"145, 14.992\\",\\"0, 0\\",\\"ZO0362203622, ZO0000300003\\",160,160,2,2,order,elyssa +LQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Dawson\\",\\"Elyssa Dawson\\",FEMALE,27,Dawson,Dawson,\\"(empty)\\",Wednesday,2,\\"elyssa@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568458,\\"sold_product_568458_19261, sold_product_568458_24302\\",\\"sold_product_568458_19261, sold_product_568458_24302\\",\\"13.992, 10.992\\",\\"13.992, 10.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7, 5.711\\",\\"13.992, 10.992\\",\\"19,261, 24,302\\",\\"Vest - black, Snood - dark grey/light grey\\",\\"Vest - black, Snood - dark grey/light grey\\",\\"1, 1\\",\\"ZO0164501645, ZO0195501955\\",\\"0, 0\\",\\"13.992, 10.992\\",\\"13.992, 10.992\\",\\"0, 0\\",\\"ZO0164501645, ZO0195501955\\",\\"24.984\\",\\"24.984\\",2,2,order,elyssa +LgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryant\\",\\"Betty Bryant\\",FEMALE,44,Bryant,Bryant,\\"(empty)\\",Wednesday,2,\\"betty@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568503,\\"sold_product_568503_12451, sold_product_568503_22678\\",\\"sold_product_568503_12451, sold_product_568503_22678\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"3.68, 31.188\\",\\"7.988, 60\\",\\"12,451, 22,678\\",\\"Vest - black, Ankle boots - Midnight Blue\\",\\"Vest - black, Ankle boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0643306433, ZO0376203762\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0643306433, ZO0376203762\\",68,68,2,2,order,betty +fQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",\\"Men's Accessories, Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Salazar\\",\\"Tariq Salazar\\",MALE,25,Salazar,Salazar,\\"(empty)\\",Wednesday,2,\\"tariq@salazar-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Low Tide Media, Angeldale\\",\\"Oceanavigations, Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",714149,\\"sold_product_714149_19588, sold_product_714149_6158, sold_product_714149_1422, sold_product_714149_18002\\",\\"sold_product_714149_19588, sold_product_714149_6158, sold_product_714149_1422, sold_product_714149_18002\\",\\"13.992, 22.984, 65, 42\\",\\"13.992, 22.984, 65, 42\\",\\"Men's Accessories, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Men's Accessories, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Low Tide Media, Angeldale, Low Tide Media\\",\\"Oceanavigations, Low Tide Media, Angeldale, Low Tide Media\\",\\"7.41, 11.492, 33.781, 21.406\\",\\"13.992, 22.984, 65, 42\\",\\"19,588, 6,158, 1,422, 18,002\\",\\"Belt - black, Shirt - black, Lace-ups - cognac, Boots - brown\\",\\"Belt - black, Shirt - black, Lace-ups - cognac, Boots - brown\\",\\"1, 1, 1, 1\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\",\\"0, 0, 0, 0\\",\\"13.992, 22.984, 65, 42\\",\\"13.992, 22.984, 65, 42\\",\\"0, 0, 0, 0\\",\\"ZO0309503095, ZO0411904119, ZO0683306833, ZO0397103971\\",144,144,4,4,order,tariq +QAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Wise\\",\\"Wagdi Wise\\",MALE,15,Wise,Wise,\\"(empty)\\",Wednesday,2,\\"wagdi@wise-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568232,\\"sold_product_568232_18129, sold_product_568232_19774\\",\\"sold_product_568232_18129, sold_product_568232_19774\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"18.859, 5.879\\",\\"37, 11.992\\",\\"18,129, 19,774\\",\\"Trousers - grey, Print T-shirt - black/orange\\",\\"Trousers - grey, Print T-shirt - black/orange\\",\\"1, 1\\",\\"ZO0282902829, ZO0566605666\\",\\"0, 0\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"0, 0\\",\\"ZO0282902829, ZO0566605666\\",\\"48.969\\",\\"48.969\\",2,2,order,wagdi +QQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Reyes\\",\\"Robbie Reyes\\",MALE,48,Reyes,Reyes,\\"(empty)\\",Wednesday,2,\\"robbie@reyes-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568269,\\"sold_product_568269_19175, sold_product_568269_2764\\",\\"sold_product_568269_19175, sold_product_568269_2764\\",\\"33, 135\\",\\"33, 135\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"15.844, 67.5\\",\\"33, 135\\",\\"19,175, 2,764\\",\\"Watch - dark brown, Suit - dark blue\\",\\"Watch - dark brown, Suit - dark blue\\",\\"1, 1\\",\\"ZO0318603186, ZO0407904079\\",\\"0, 0\\",\\"33, 135\\",\\"33, 135\\",\\"0, 0\\",\\"ZO0318603186, ZO0407904079\\",168,168,2,2,order,robbie +QgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Stokes\\",\\"Yasmine Stokes\\",FEMALE,43,Stokes,Stokes,\\"(empty)\\",Wednesday,2,\\"yasmine@stokes-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568301,\\"sold_product_568301_20011, sold_product_568301_20152\\",\\"sold_product_568301_20011, sold_product_568301_20152\\",\\"33, 42\\",\\"33, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.844, 22.25\\",\\"33, 42\\",\\"20,011, 20,152\\",\\"Jumpsuit - black, Platform boots - dark blue\\",\\"Jumpsuit - black, Platform boots - dark blue\\",\\"1, 1\\",\\"ZO0146401464, ZO0014700147\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0146401464, ZO0014700147\\",75,75,2,2,order,yasmine +QwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Ryan\\",\\"Clarice Ryan\\",FEMALE,18,Ryan,Ryan,\\"(empty)\\",Wednesday,2,\\"clarice@ryan-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568469,\\"sold_product_568469_10902, sold_product_568469_8739\\",\\"sold_product_568469_10902, sold_product_568469_8739\\",\\"26.984, 28.984\\",\\"26.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"13.758, 15.938\\",\\"26.984, 28.984\\",\\"10,902, 8,739\\",\\"Pyjamas - black, Jumper - anthractie multicolor\\",\\"Pyjamas - black, Jumper - anthractie multicolor\\",\\"1, 1\\",\\"ZO0659806598, ZO0070100701\\",\\"0, 0\\",\\"26.984, 28.984\\",\\"26.984, 28.984\\",\\"0, 0\\",\\"ZO0659806598, ZO0070100701\\",\\"55.969\\",\\"55.969\\",2,2,order,clarice +RAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Shaw\\",\\"Sultan Al Shaw\\",MALE,19,Shaw,Shaw,\\"(empty)\\",Wednesday,2,\\"sultan al@shaw-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568499,\\"sold_product_568499_23865, sold_product_568499_17752\\",\\"sold_product_568499_23865, sold_product_568499_17752\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"5.879, 17.391\\",\\"11.992, 37\\",\\"23,865, 17,752\\",\\"2 PACK - Basic T-shirt - dark grey multicolor, Slim fit jeans - black denim\\",\\"2 PACK - Basic T-shirt - dark grey multicolor, Slim fit jeans - black denim\\",\\"1, 1\\",\\"ZO0474604746, ZO0113801138\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0474604746, ZO0113801138\\",\\"48.969\\",\\"48.969\\",2,2,order,sultan +UQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Austin\\",\\"Wilhemina St. Austin\\",FEMALE,17,Austin,Austin,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@austin-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568083,\\"sold_product_568083_14459, sold_product_568083_18901\\",\\"sold_product_568083_14459, sold_product_568083_18901\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 8.328\\",\\"11.992, 16.984\\",\\"14,459, 18,901\\",\\"Across body bag - cognac, Clutch - white/black\\",\\"Across body bag - cognac, Clutch - white/black\\",\\"1, 1\\",\\"ZO0200902009, ZO0092300923\\",\\"0, 0\\",\\"11.992, 16.984\\",\\"11.992, 16.984\\",\\"0, 0\\",\\"ZO0200902009, ZO0092300923\\",\\"28.984\\",\\"28.984\\",2,2,order,wilhemina +VAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Abd,Abd,\\"Abd Lamb\\",\\"Abd Lamb\\",MALE,52,Lamb,Lamb,\\"(empty)\\",Wednesday,2,\\"abd@lamb-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Angeldale,Angeldale,\\"Jun 25, 2019 @ 00:00:00.000\\",569163,\\"sold_product_569163_1774, sold_product_569163_23724\\",\\"sold_product_569163_1774, sold_product_569163_23724\\",\\"60, 75\\",\\"60, 75\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Angeldale\\",\\"Angeldale, Angeldale\\",\\"27.594, 37.5\\",\\"60, 75\\",\\"1,774, 23,724\\",\\"Lace-ups - cognac, Lace-ups - bordeaux\\",\\"Lace-ups - cognac, Lace-ups - bordeaux\\",\\"1, 1\\",\\"ZO0681106811, ZO0682706827\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0681106811, ZO0682706827\\",135,135,2,2,order,abd +VQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Potter\\",\\"Clarice Potter\\",FEMALE,18,Potter,Potter,\\"(empty)\\",Wednesday,2,\\"clarice@potter-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569214,\\"sold_product_569214_15372, sold_product_569214_13660\\",\\"sold_product_569214_15372, sold_product_569214_13660\\",\\"20.984, 25.984\\",\\"20.984, 25.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"10.703, 13.25\\",\\"20.984, 25.984\\",\\"15,372, 13,660\\",\\"Jersey dress - khaki, Across body bag - brown\\",\\"Jersey dress - khaki, Across body bag - brown\\",\\"1, 1\\",\\"ZO0490104901, ZO0087200872\\",\\"0, 0\\",\\"20.984, 25.984\\",\\"20.984, 25.984\\",\\"0, 0\\",\\"ZO0490104901, ZO0087200872\\",\\"46.969\\",\\"46.969\\",2,2,order,clarice +VgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Lawrence\\",\\"Fitzgerald Lawrence\\",MALE,11,Lawrence,Lawrence,\\"(empty)\\",Wednesday,2,\\"fitzgerald@lawrence-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568875,\\"sold_product_568875_22460, sold_product_568875_12482\\",\\"sold_product_568875_22460, sold_product_568875_12482\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.92, 30\\",\\"7.988, 60\\",\\"22,460, 12,482\\",\\"3 PACK - Socks - white, Across body bag - black\\",\\"3 PACK - Socks - white, Across body bag - black\\",\\"1, 1\\",\\"ZO0613606136, ZO0463804638\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0613606136, ZO0463804638\\",68,68,2,2,order,fuzzy +VwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Wagdi,Wagdi,\\"Wagdi Griffin\\",\\"Wagdi Griffin\\",MALE,15,Griffin,Griffin,\\"(empty)\\",Wednesday,2,\\"wagdi@griffin-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568943,\\"sold_product_568943_22910, sold_product_568943_1665\\",\\"sold_product_568943_22910, sold_product_568943_1665\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"13.242, 31.203\\",\\"24.984, 65\\",\\"22,910, 1,665\\",\\"Cardigan - black, Boots - light brown\\",\\"Cardigan - black, Boots - light brown\\",\\"1, 1\\",\\"ZO0445804458, ZO0686106861\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0445804458, ZO0686106861\\",90,90,2,2,order,wagdi +WAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Dennis\\",\\"Yahya Dennis\\",MALE,23,Dennis,Dennis,\\"(empty)\\",Wednesday,2,\\"yahya@dennis-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569046,\\"sold_product_569046_15527, sold_product_569046_3489\\",\\"sold_product_569046_15527, sold_product_569046_3489\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"15.844, 12.18\\",\\"33, 22.984\\",\\"15,527, 3,489\\",\\"Lace-ups - black, Tights - black\\",\\"Lace-ups - black, Tights - black\\",\\"1, 1\\",\\"ZO0393103931, ZO0619906199\\",\\"0, 0\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"0, 0\\",\\"ZO0393103931, ZO0619906199\\",\\"55.969\\",\\"55.969\\",2,2,order,yahya +WQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Cortez\\",\\"Brigitte Cortez\\",FEMALE,12,Cortez,Cortez,\\"(empty)\\",Wednesday,2,\\"brigitte@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569103,\\"sold_product_569103_23059, sold_product_569103_19509\\",\\"sold_product_569103_23059, sold_product_569103_19509\\",\\"21.984, 28.984\\",\\"21.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"11.648, 15.648\\",\\"21.984, 28.984\\",\\"23,059, 19,509\\",\\"Jumper dress - bordeaux, Blouse - dark red\\",\\"Jumper dress - bordeaux, Blouse - dark red\\",\\"1, 1\\",\\"ZO0636506365, ZO0345503455\\",\\"0, 0\\",\\"21.984, 28.984\\",\\"21.984, 28.984\\",\\"0, 0\\",\\"ZO0636506365, ZO0345503455\\",\\"50.969\\",\\"50.969\\",2,2,order,brigitte +WgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Morgan\\",\\"Abdulraheem Al Morgan\\",MALE,33,Morgan,Morgan,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568993,\\"sold_product_568993_21293, sold_product_568993_13143\\",\\"sold_product_568993_21293, sold_product_568993_13143\\",\\"24.984, 155\\",\\"24.984, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"12.742, 79.063\\",\\"24.984, 155\\",\\"21,293, 13,143\\",\\"Trainers - white, Slip-ons - black\\",\\"Trainers - white, Slip-ons - black\\",\\"1, 1\\",\\"ZO0510505105, ZO0482604826\\",\\"0, 0\\",\\"24.984, 155\\",\\"24.984, 155\\",\\"0, 0\\",\\"ZO0510505105, ZO0482604826\\",180,180,2,2,order,abdulraheem +EAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Lloyd\\",\\"Sultan Al Lloyd\\",MALE,19,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"sultan al@lloyd-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",720661,\\"sold_product_720661_22855, sold_product_720661_15602, sold_product_720661_15204, sold_product_720661_22811\\",\\"sold_product_720661_22855, sold_product_720661_15602, sold_product_720661_15204, sold_product_720661_22811\\",\\"22.984, 42, 42, 24.984\\",\\"22.984, 42, 42, 24.984\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Low Tide Media\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Low Tide Media\\",\\"10.813, 21.828, 21.406, 11.5\\",\\"22.984, 42, 42, 24.984\\",\\"22,855, 15,602, 15,204, 22,811\\",\\"Shorts - black, Weekend bag - black , Weekend bag - black, Cardigan - beige multicolor\\",\\"Shorts - black, Weekend bag - black , Weekend bag - black, Cardigan - beige multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\",\\"0, 0, 0, 0\\",\\"22.984, 42, 42, 24.984\\",\\"22.984, 42, 42, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0423004230, ZO0471604716, ZO0315303153, ZO0445604456\\",132,132,4,4,order,sultan +RQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Perkins\\",\\"Betty Perkins\\",FEMALE,44,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"betty@perkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Microlutions, Champion Arts\\",\\"Microlutions, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569144,\\"sold_product_569144_9379, sold_product_569144_15599\\",\\"sold_product_569144_9379, sold_product_569144_15599\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Champion Arts\\",\\"Microlutions, Champion Arts\\",\\"16.813, 15.648\\",\\"33, 28.984\\",\\"9,379, 15,599\\",\\"Trousers - black, Tracksuit top - dark grey multicolor\\",\\"Trousers - black, Tracksuit top - dark grey multicolor\\",\\"1, 1\\",\\"ZO0108101081, ZO0501105011\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0108101081, ZO0501105011\\",\\"61.969\\",\\"61.969\\",2,2,order,betty +RgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Mullins\\",\\"Muniz Mullins\\",MALE,37,Mullins,Mullins,\\"(empty)\\",Wednesday,2,\\"muniz@mullins-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569198,\\"sold_product_569198_13676, sold_product_569198_6033\\",\\"sold_product_569198_13676, sold_product_569198_6033\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.938, 9.117\\",\\"28.984, 18.984\\",\\"13,676, 6,033\\",\\"Across body bag - brown , Sweatshirt - white\\",\\"Across body bag - brown , Sweatshirt - white\\",\\"1, 1\\",\\"ZO0464304643, ZO0581905819\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0464304643, ZO0581905819\\",\\"47.969\\",\\"47.969\\",2,2,order,muniz +RwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya Brady\\",\\"Yahya Brady\\",MALE,23,Brady,Brady,\\"(empty)\\",Wednesday,2,\\"yahya@brady-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568845,\\"sold_product_568845_11493, sold_product_568845_18854\\",\\"sold_product_568845_11493, sold_product_568845_18854\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"10.078, 46.75\\",\\"20.984, 85\\",\\"11,493, 18,854\\",\\"Tracksuit bottoms - light grey multicolor, Boots - Midnight Blue\\",\\"Tracksuit bottoms - light grey multicolor, Boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0657906579, ZO0258102581\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0657906579, ZO0258102581\\",106,106,2,2,order,yahya +SAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,rania,rania,\\"rania Byrd\\",\\"rania Byrd\\",FEMALE,24,Byrd,Byrd,\\"(empty)\\",Wednesday,2,\\"rania@byrd-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568894,\\"sold_product_568894_21617, sold_product_568894_16951\\",\\"sold_product_568894_21617, sold_product_568894_16951\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"21, 11.117\\",\\"42, 20.984\\",\\"21,617, 16,951\\",\\"Cowboy/Biker boots - black, Clutch - black\\",\\"Cowboy/Biker boots - black, Clutch - black\\",\\"1, 1\\",\\"ZO0141801418, ZO0206302063\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0141801418, ZO0206302063\\",\\"62.969\\",\\"62.969\\",2,2,order,rani +SQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Carpenter\\",\\"rania Carpenter\\",FEMALE,24,Carpenter,Carpenter,\\"(empty)\\",Wednesday,2,\\"rania@carpenter-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Spherecords,Spherecords,\\"Jun 25, 2019 @ 00:00:00.000\\",568938,\\"sold_product_568938_18398, sold_product_568938_19241\\",\\"sold_product_568938_18398, sold_product_568938_19241\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords\\",\\"Spherecords, Spherecords\\",\\"5.391, 9.172\\",\\"10.992, 16.984\\",\\"18,398, 19,241\\",\\"Vest - black, Tracksuit bottoms - navy\\",\\"Vest - black, Tracksuit bottoms - navy\\",\\"1, 1\\",\\"ZO0642806428, ZO0632506325\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0642806428, ZO0632506325\\",\\"27.984\\",\\"27.984\\",2,2,order,rani +SgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Meyer\\",\\"Fitzgerald Meyer\\",MALE,11,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"fitzgerald@meyer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569045,\\"sold_product_569045_17857, sold_product_569045_12592\\",\\"sold_product_569045_17857, sold_product_569045_12592\\",\\"85, 14.992\\",\\"85, 14.992\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"39.938, 7.051\\",\\"85, 14.992\\",\\"17,857, 12,592\\",\\"Laptop bag - black, Belt - dark brown \\",\\"Laptop bag - black, Belt - dark brown \\",\\"1, 1\\",\\"ZO0315903159, ZO0461104611\\",\\"0, 0\\",\\"85, 14.992\\",\\"85, 14.992\\",\\"0, 0\\",\\"ZO0315903159, ZO0461104611\\",100,100,2,2,order,fuzzy +SwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Thad,Thad,\\"Thad Munoz\\",\\"Thad Munoz\\",MALE,30,Munoz,Munoz,\\"(empty)\\",Wednesday,2,\\"thad@munoz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569097,\\"sold_product_569097_20740, sold_product_569097_12607\\",\\"sold_product_569097_20740, sold_product_569097_12607\\",\\"33, 155\\",\\"33, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"14.852, 83.688\\",\\"33, 155\\",\\"20,740, 12,607\\",\\"High-top trainers - beige, Smart slip-ons - black\\",\\"High-top trainers - beige, Smart slip-ons - black\\",\\"1, 1\\",\\"ZO0511605116, ZO0483004830\\",\\"0, 0\\",\\"33, 155\\",\\"33, 155\\",\\"0, 0\\",\\"ZO0511605116, ZO0483004830\\",188,188,2,2,order,thad +dwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Franklin\\",\\"Elyssa Franklin\\",FEMALE,27,Franklin,Franklin,\\"(empty)\\",Wednesday,2,\\"elyssa@franklin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Gnomehouse, Tigress Enterprises\\",\\"Angeldale, Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",727370,\\"sold_product_727370_24280, sold_product_727370_20519, sold_product_727370_18829, sold_product_727370_16904\\",\\"sold_product_727370_24280, sold_product_727370_20519, sold_product_727370_18829, sold_product_727370_16904\\",\\"85, 50, 37, 33\\",\\"85, 50, 37, 33\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Gnomehouse, Tigress Enterprises, Tigress Enterprises\\",\\"Angeldale, Gnomehouse, Tigress Enterprises, Tigress Enterprises\\",\\"45.875, 24.5, 17.391, 15.508\\",\\"85, 50, 37, 33\\",\\"24,280, 20,519, 18,829, 16,904\\",\\"Boots - black, Classic heels - Midnight Blue, Jersey dress - Blue Violety/black, Trainers - black\\",\\"Boots - black, Classic heels - Midnight Blue, Jersey dress - Blue Violety/black, Trainers - black\\",\\"1, 1, 1, 1\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\",\\"0, 0, 0, 0\\",\\"85, 50, 37, 33\\",\\"85, 50, 37, 33\\",\\"0, 0, 0, 0\\",\\"ZO0680206802, ZO0321703217, ZO0049900499, ZO0029400294\\",205,205,4,4,order,elyssa +kwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Davidson\\",\\"Frances Davidson\\",FEMALE,49,Davidson,Davidson,\\"(empty)\\",Wednesday,2,\\"frances@davidson-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568751,\\"sold_product_568751_22085, sold_product_568751_22963\\",\\"sold_product_568751_22085, sold_product_568751_22963\\",\\"11.992, 7.988\\",\\"11.992, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.352, 4.148\\",\\"11.992, 7.988\\",\\"22,085, 22,963\\",\\"Hat - black, 3 PACK - Socks - grey/white/black\\",\\"Hat - black, 3 PACK - Socks - grey/white/black\\",\\"1, 1\\",\\"ZO0308703087, ZO0613106131\\",\\"0, 0\\",\\"11.992, 7.988\\",\\"11.992, 7.988\\",\\"0, 0\\",\\"ZO0308703087, ZO0613106131\\",\\"19.984\\",\\"19.984\\",2,2,order,frances +oQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Nash\\",\\"Yasmine Nash\\",FEMALE,43,Nash,Nash,\\"(empty)\\",Wednesday,2,\\"yasmine@nash-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569010,\\"sold_product_569010_17948, sold_product_569010_22803\\",\\"sold_product_569010_17948, sold_product_569010_22803\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"15.359, 17.484\\",\\"28.984, 33\\",\\"17,948, 22,803\\",\\"Tote bag - old rose, Blouse - red\\",\\"Tote bag - old rose, Blouse - red\\",\\"1, 1\\",\\"ZO0090700907, ZO0265002650\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0090700907, ZO0265002650\\",\\"61.969\\",\\"61.969\\",2,2,order,yasmine +uwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Rivera\\",\\"Tariq Rivera\\",MALE,25,Rivera,Rivera,\\"(empty)\\",Wednesday,2,\\"tariq@rivera-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568745,\\"sold_product_568745_24487, sold_product_568745_17279\\",\\"sold_product_568745_24487, sold_product_568745_17279\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.906, 6.109\\",\\"20.984, 11.992\\",\\"24,487, 17,279\\",\\"Chinos - grey, Hat - navy\\",\\"Chinos - grey, Hat - navy\\",\\"1, 1\\",\\"ZO0528305283, ZO0309203092\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0528305283, ZO0309203092\\",\\"32.969\\",\\"32.969\\",2,2,order,tariq +AwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Simpson\\",\\"Rabbia Al Simpson\\",FEMALE,5,Simpson,Simpson,\\"(empty)\\",Wednesday,2,\\"rabbia al@simpson-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728962,\\"sold_product_728962_24881, sold_product_728962_18382, sold_product_728962_14470, sold_product_728962_18450\\",\\"sold_product_728962_24881, sold_product_728962_18382, sold_product_728962_14470, sold_product_728962_18450\\",\\"42, 24.984, 28.984, 50\\",\\"42, 24.984, 28.984, 50\\",\\"Women's Shoes, Women's Accessories, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Accessories, Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Tigress Enterprises, Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Tigress Enterprises, Tigress Enterprises, Gnomehouse\\",\\"20.578, 12.992, 15.648, 22.5\\",\\"42, 24.984, 28.984, 50\\",\\"24,881, 18,382, 14,470, 18,450\\",\\"Ankle boots - black, Across body bag - taupe/black/pink, Cardigan - tan, Summer dress - flame scarlet\\",\\"Ankle boots - black, Across body bag - taupe/black/pink, Cardigan - tan, Summer dress - flame scarlet\\",\\"1, 1, 1, 1\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\",\\"0, 0, 0, 0\\",\\"42, 24.984, 28.984, 50\\",\\"42, 24.984, 28.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0019800198, ZO0089200892, ZO0069700697, ZO0332303323\\",146,146,4,4,order,rabbia +XAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Love\\",\\"Yahya Love\\",MALE,23,Love,Love,\\"(empty)\\",Wednesday,2,\\"yahya@love-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568069,\\"sold_product_568069_14245, sold_product_568069_19287\\",\\"sold_product_568069_14245, sold_product_568069_19287\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"13.922, 10.563\\",\\"28.984, 21.984\\",\\"14,245, 19,287\\",\\"Trousers - grey, Chinos - dark blue\\",\\"Trousers - grey, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0530305303, ZO0528405284\\",\\"0, 0\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"0, 0\\",\\"ZO0530305303, ZO0528405284\\",\\"50.969\\",\\"50.969\\",2,2,order,yahya +jQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Massey\\",\\"Rabbia Al Massey\\",FEMALE,5,Massey,Massey,\\"(empty)\\",Wednesday,2,\\"rabbia al@massey-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Jun 25, 2019 @ 00:00:00.000\\",732546,\\"sold_product_732546_17971, sold_product_732546_18249, sold_product_732546_18483, sold_product_732546_18726\\",\\"sold_product_732546_17971, sold_product_732546_18249, sold_product_732546_18483, sold_product_732546_18726\\",\\"36, 24.984, 20.984, 140\\",\\"36, 24.984, 20.984, 140\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"Tigress Enterprises MAMA, Champion Arts, Microlutions, Primemaster\\",\\"19.063, 13.742, 10.078, 64.375\\",\\"36, 24.984, 20.984, 140\\",\\"17,971, 18,249, 18,483, 18,726\\",\\"Jersey dress - navy/offwhite, Hoodie - off-white, Print T-shirt - olive night, High heeled boots - stone\\",\\"Jersey dress - navy/offwhite, Hoodie - off-white, Print T-shirt - olive night, High heeled boots - stone\\",\\"1, 1, 1, 1\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\",\\"0, 0, 0, 0\\",\\"36, 24.984, 20.984, 140\\",\\"36, 24.984, 20.984, 140\\",\\"0, 0, 0, 0\\",\\"ZO0228602286, ZO0502605026, ZO0108901089, ZO0362503625\\",222,222,4,4,order,rabbia +BwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Simpson\\",\\"Wilhemina St. Simpson\\",FEMALE,17,Simpson,Simpson,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@simpson-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568218,\\"sold_product_568218_10736, sold_product_568218_16297\\",\\"sold_product_568218_10736, sold_product_568218_16297\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries active, Tigress Enterprises\\",\\"16.172, 9.344\\",\\"33, 16.984\\",\\"10,736, 16,297\\",\\"Tracksuit top - grey multicolor , Watch - nude\\",\\"Tracksuit top - grey multicolor , Watch - nude\\",\\"1, 1\\",\\"ZO0227402274, ZO0079000790\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0227402274, ZO0079000790\\",\\"49.969\\",\\"49.969\\",2,2,order,wilhemina +CAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perkins\\",\\"Robbie Perkins\\",MALE,48,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"robbie@perkins-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568278,\\"sold_product_568278_6696, sold_product_568278_21136\\",\\"sold_product_568278_6696, sold_product_568278_21136\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"15.844, 17.813\\",\\"33, 33\\",\\"6,696, 21,136\\",\\"Slim fit jeans - dark blue, Jumper - dark blue\\",\\"Slim fit jeans - dark blue, Jumper - dark blue\\",\\"1, 1\\",\\"ZO0536705367, ZO0449804498\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0536705367, ZO0449804498\\",66,66,2,2,order,robbie +CQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Ruiz\\",\\"Boris Ruiz\\",MALE,36,Ruiz,Ruiz,\\"(empty)\\",Wednesday,2,\\"boris@ruiz-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568428,\\"sold_product_568428_22274, sold_product_568428_12864\\",\\"sold_product_568428_22274, sold_product_568428_12864\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"34.438, 11.719\\",\\"65, 22.984\\",\\"22,274, 12,864\\",\\"Suit jacket - black, SLIM FIT - Formal shirt - black\\",\\"Suit jacket - black, SLIM FIT - Formal shirt - black\\",\\"1, 1\\",\\"ZO0408404084, ZO0422304223\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0408404084, ZO0422304223\\",88,88,2,2,order,boris +CgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hopkins\\",\\"Abigail Hopkins\\",FEMALE,46,Hopkins,Hopkins,\\"(empty)\\",Wednesday,2,\\"abigail@hopkins-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568492,\\"sold_product_568492_21002, sold_product_568492_19078\\",\\"sold_product_568492_21002, sold_product_568492_19078\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.156, 8.828\\",\\"33, 16.984\\",\\"21,002, 19,078\\",\\"Shirt - Dark Turquoise, Print T-shirt - black\\",\\"Shirt - Dark Turquoise, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0346103461, ZO0054100541\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0346103461, ZO0054100541\\",\\"49.969\\",\\"49.969\\",2,2,order,abigail +GgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Greene\\",\\"Abdulraheem Al Greene\\",MALE,33,Greene,Greene,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@greene-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569262,\\"sold_product_569262_11467, sold_product_569262_11510\\",\\"sold_product_569262_11467, sold_product_569262_11510\\",\\"12.992, 10.992\\",\\"12.992, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.109, 5.82\\",\\"12.992, 10.992\\",\\"11,467, 11,510\\",\\"3 PACK - Shorts - black/royal/mint, Sports shirt - black\\",\\"3 PACK - Shorts - black/royal/mint, Sports shirt - black\\",\\"1, 1\\",\\"ZO0609906099, ZO0614806148\\",\\"0, 0\\",\\"12.992, 10.992\\",\\"12.992, 10.992\\",\\"0, 0\\",\\"ZO0609906099, ZO0614806148\\",\\"23.984\\",\\"23.984\\",2,2,order,abdulraheem +GwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mckenzie\\",\\"Abd Mckenzie\\",MALE,52,Mckenzie,Mckenzie,\\"(empty)\\",Wednesday,2,\\"abd@mckenzie-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569306,\\"sold_product_569306_13753, sold_product_569306_19486\\",\\"sold_product_569306_13753, sold_product_569306_19486\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"13.742, 44.188\\",\\"24.984, 85\\",\\"13,753, 19,486\\",\\"Formal shirt - white/blue, Snowboard jacket - black\\",\\"Formal shirt - white/blue, Snowboard jacket - black\\",\\"1, 1\\",\\"ZO0412004120, ZO0625406254\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0412004120, ZO0625406254\\",110,110,2,2,order,abd +0gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Perry\\",\\"Yuri Perry\\",MALE,21,Perry,Perry,\\"(empty)\\",Wednesday,2,\\"yuri@perry-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569223,\\"sold_product_569223_12715, sold_product_569223_20466\\",\\"sold_product_569223_12715, sold_product_569223_20466\\",\\"18.984, 7.988\\",\\"18.984, 7.988\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"8.742, 4.23\\",\\"18.984, 7.988\\",\\"12,715, 20,466\\",\\"Polo shirt - off-white, Hat - black\\",\\"Polo shirt - off-white, Hat - black\\",\\"1, 1\\",\\"ZO0444004440, ZO0596805968\\",\\"0, 0\\",\\"18.984, 7.988\\",\\"18.984, 7.988\\",\\"0, 0\\",\\"ZO0444004440, ZO0596805968\\",\\"26.984\\",\\"26.984\\",2,2,order,yuri +GAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Perkins\\",\\"Muniz Perkins\\",MALE,37,Perkins,Perkins,\\"(empty)\\",Wednesday,2,\\"muniz@perkins-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568039,\\"sold_product_568039_13197, sold_product_568039_11137\\",\\"sold_product_568039_13197, sold_product_568039_11137\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.172, 15.359\\",\\"10.992, 28.984\\",\\"13,197, 11,137\\",\\"Sunglasses - black/silver-coloured, Shirt - white\\",\\"Sunglasses - black/silver-coloured, Shirt - white\\",\\"1, 1\\",\\"ZO0599705997, ZO0416704167\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0599705997, ZO0416704167\\",\\"39.969\\",\\"39.969\\",2,2,order,muniz +YgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Parker\\",\\"Abd Parker\\",MALE,52,Parker,Parker,\\"(empty)\\",Wednesday,2,\\"abd@parker-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568117,\\"sold_product_568117_13602, sold_product_568117_20020\\",\\"sold_product_568117_13602, sold_product_568117_20020\\",\\"20.984, 60\\",\\"20.984, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.289, 28.797\\",\\"20.984, 60\\",\\"13,602, 20,020\\",\\"Across body bag - dark brown, Boots - navy\\",\\"Across body bag - dark brown, Boots - navy\\",\\"1, 1\\",\\"ZO0315203152, ZO0406304063\\",\\"0, 0\\",\\"20.984, 60\\",\\"20.984, 60\\",\\"0, 0\\",\\"ZO0315203152, ZO0406304063\\",81,81,2,2,order,abd +YwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Figueroa\\",\\"Clarice Figueroa\\",FEMALE,18,Figueroa,Figueroa,\\"(empty)\\",Wednesday,2,\\"clarice@figueroa-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568165,\\"sold_product_568165_22895, sold_product_568165_20510\\",\\"sold_product_568165_22895, sold_product_568165_20510\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"13.492, 28.797\\",\\"24.984, 60\\",\\"22,895, 20,510\\",\\"Vest - moroccan blue, Dress - navy blazer\\",\\"Vest - moroccan blue, Dress - navy blazer\\",\\"1, 1\\",\\"ZO0065600656, ZO0337003370\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0065600656, ZO0337003370\\",85,85,2,2,order,clarice +hQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Wednesday,2,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568393,\\"sold_product_568393_5224, sold_product_568393_18968\\",\\"sold_product_568393_5224, sold_product_568393_18968\\",\\"85, 50\\",\\"85, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"41.656, 25\\",\\"85, 50\\",\\"5,224, 18,968\\",\\"Boots - cognac, High heeled sandals - black\\",\\"Boots - cognac, High heeled sandals - black\\",\\"1, 1\\",\\"ZO0374103741, ZO0242102421\\",\\"0, 0\\",\\"85, 50\\",\\"85, 50\\",\\"0, 0\\",\\"ZO0374103741, ZO0242102421\\",135,135,2,2,order,elyssa +1QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cunningham\\",\\"Gwen Cunningham\\",FEMALE,26,Cunningham,Cunningham,\\"(empty)\\",Wednesday,2,\\"gwen@cunningham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",567996,\\"sold_product_567996_21740, sold_product_567996_20451\\",\\"sold_product_567996_21740, sold_product_567996_20451\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"11.25, 15.648\\",\\"24.984, 28.984\\",\\"21,740, 20,451\\",\\"Print T-shirt - scarab, Jersey dress - port royal\\",\\"Print T-shirt - scarab, Jersey dress - port royal\\",\\"1, 1\\",\\"ZO0105401054, ZO0046200462\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0105401054, ZO0046200462\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +BwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Carr\\",\\"Marwan Carr\\",MALE,51,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"marwan@carr-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569173,\\"sold_product_569173_17602, sold_product_569173_2924\\",\\"sold_product_569173_17602, sold_product_569173_2924\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"11.75, 18.125\\",\\"24.984, 37\\",\\"17,602, 2,924\\",\\"Jumper - mulitcoloured/dark blue, Tracksuit - navy blazer\\",\\"Jumper - mulitcoloured/dark blue, Tracksuit - navy blazer\\",\\"1, 1\\",\\"ZO0452204522, ZO0631206312\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0452204522, ZO0631206312\\",\\"61.969\\",\\"61.969\\",2,2,order,marwan +CAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Frances,Frances,\\"Frances Wells\\",\\"Frances Wells\\",FEMALE,49,Wells,Wells,\\"(empty)\\",Wednesday,2,\\"frances@wells-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569209,\\"sold_product_569209_16819, sold_product_569209_24934\\",\\"sold_product_569209_16819, sold_product_569209_24934\\",\\"42, 50\\",\\"42, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"19.734, 22.5\\",\\"42, 50\\",\\"16,819, 24,934\\",\\"Weekend bag - cognac, Lace-up boots - resin coffee\\",\\"Weekend bag - cognac, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0472304723, ZO0403504035\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0472304723, ZO0403504035\\",92,92,2,2,order,frances +CQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Gibbs\\",\\"Jackson Gibbs\\",MALE,13,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"jackson@gibbs-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568865,\\"sold_product_568865_15772, sold_product_568865_13481\\",\\"sold_product_568865_15772, sold_product_568865_13481\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.23, 5.281\\",\\"11.992, 10.992\\",\\"15,772, 13,481\\",\\"Print T-shirt - white, Print T-shirt - white\\",\\"Print T-shirt - white, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0294502945, ZO0560605606\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0294502945, ZO0560605606\\",\\"22.984\\",\\"22.984\\",2,2,order,jackson +CgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Holland\\",\\"Yahya Holland\\",MALE,23,Holland,Holland,\\"(empty)\\",Wednesday,2,\\"yahya@holland-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 25, 2019 @ 00:00:00.000\\",568926,\\"sold_product_568926_19082, sold_product_568926_17588\\",\\"sold_product_568926_19082, sold_product_568926_17588\\",\\"70, 20.984\\",\\"70, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"37.094, 10.906\\",\\"70, 20.984\\",\\"19,082, 17,588\\",\\"Jumper - ecru, Sweatshirt - mustard\\",\\"Jumper - ecru, Sweatshirt - mustard\\",\\"1, 1\\",\\"ZO0298302983, ZO0300003000\\",\\"0, 0\\",\\"70, 20.984\\",\\"70, 20.984\\",\\"0, 0\\",\\"ZO0298302983, ZO0300003000\\",91,91,2,2,order,yahya +CwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Haynes\\",\\"Selena Haynes\\",FEMALE,42,Haynes,Haynes,\\"(empty)\\",Wednesday,2,\\"selena@haynes-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568955,\\"sold_product_568955_7789, sold_product_568955_11911\\",\\"sold_product_568955_7789, sold_product_568955_11911\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.359, 6\\",\\"28.984, 11.992\\",\\"7,789, 11,911\\",\\"Cardigan - blue grey, Leggings - black/white\\",\\"Cardigan - blue grey, Leggings - black/white\\",\\"1, 1\\",\\"ZO0068900689, ZO0076200762\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0068900689, ZO0076200762\\",\\"40.969\\",\\"40.969\\",2,2,order,selena +DAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Roberson\\",\\"Yasmine Roberson\\",FEMALE,43,Roberson,Roberson,\\"(empty)\\",Wednesday,2,\\"yasmine@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569056,\\"sold_product_569056_18276, sold_product_569056_16315\\",\\"sold_product_569056_18276, sold_product_569056_16315\\",\\"10.992, 33\\",\\"10.992, 33\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"5.82, 16.813\\",\\"10.992, 33\\",\\"18,276, 16,315\\",\\"Print T-shirt - dark grey, Handbag - taupe\\",\\"Print T-shirt - dark grey, Handbag - taupe\\",\\"1, 1\\",\\"ZO0494804948, ZO0096000960\\",\\"0, 0\\",\\"10.992, 33\\",\\"10.992, 33\\",\\"0, 0\\",\\"ZO0494804948, ZO0096000960\\",\\"43.969\\",\\"43.969\\",2,2,order,yasmine +DQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hudson\\",\\"Yasmine Hudson\\",FEMALE,43,Hudson,Hudson,\\"(empty)\\",Wednesday,2,\\"yasmine@hudson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569083,\\"sold_product_569083_17188, sold_product_569083_11983\\",\\"sold_product_569083_17188, sold_product_569083_11983\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"7.551, 12.492\\",\\"13.992, 24.984\\",\\"17,188, 11,983\\",\\"Bustier - dark blue, Summer dress - red\\",\\"Bustier - dark blue, Summer dress - red\\",\\"1, 1\\",\\"ZO0099000990, ZO0631606316\\",\\"0, 0\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"0, 0\\",\\"ZO0099000990, ZO0631606316\\",\\"38.969\\",\\"38.969\\",2,2,order,yasmine +EgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Conner\\",\\"Jackson Conner\\",MALE,13,Conner,Conner,\\"(empty)\\",Wednesday,2,\\"jackson@conner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, (empty), Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",717726,\\"sold_product_717726_23932, sold_product_717726_12833, sold_product_717726_20363, sold_product_717726_13390\\",\\"sold_product_717726_23932, sold_product_717726_12833, sold_product_717726_20363, sold_product_717726_13390\\",\\"28.984, 155, 50, 24.984\\",\\"28.984, 155, 50, 24.984\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, (empty), Low Tide Media, Oceanavigations\\",\\"Oceanavigations, (empty), Low Tide Media, Oceanavigations\\",\\"13.922, 79.063, 24, 12\\",\\"28.984, 155, 50, 24.984\\",\\"23,932, 12,833, 20,363, 13,390\\",\\"SVEN - Jeans Tapered Fit - light blue, Smart lace-ups - cognac, Boots - Lime, Chinos - military green\\",\\"SVEN - Jeans Tapered Fit - light blue, Smart lace-ups - cognac, Boots - Lime, Chinos - military green\\",\\"1, 1, 1, 1\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\",\\"0, 0, 0, 0\\",\\"28.984, 155, 50, 24.984\\",\\"28.984, 155, 50, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0284902849, ZO0481204812, ZO0398403984, ZO0282402824\\",259,259,4,4,order,jackson +QwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Chapman\\",\\"rania Chapman\\",FEMALE,24,Chapman,Chapman,\\"(empty)\\",Wednesday,2,\\"rania@chapman-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568149,\\"sold_product_568149_12205, sold_product_568149_24905\\",\\"sold_product_568149_12205, sold_product_568149_24905\\",\\"33, 80\\",\\"33, 80\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"15.18, 42.375\\",\\"33, 80\\",\\"12,205, 24,905\\",\\"Jacket - black, Lace-up boots - black\\",\\"Jacket - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0342503425, ZO0675206752\\",\\"0, 0\\",\\"33, 80\\",\\"33, 80\\",\\"0, 0\\",\\"ZO0342503425, ZO0675206752\\",113,113,2,2,order,rani +RAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Howell\\",\\"Rabbia Al Howell\\",FEMALE,5,Howell,Howell,\\"(empty)\\",Wednesday,2,\\"rabbia al@howell-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Crystal Lighting, Gnomehouse\\",\\"Crystal Lighting, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568192,\\"sold_product_568192_23290, sold_product_568192_11670\\",\\"sold_product_568192_23290, sold_product_568192_11670\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Crystal Lighting, Gnomehouse\\",\\"Crystal Lighting, Gnomehouse\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"23,290, 11,670\\",\\"Wool jumper - dark blue, Hat - beige\\",\\"Wool jumper - dark blue, Hat - beige\\",\\"1, 1\\",\\"ZO0485504855, ZO0355603556\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0485504855, ZO0355603556\\",\\"41.969\\",\\"41.969\\",2,2,order,rabbia +YQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Gibbs\\",\\"Elyssa Gibbs\\",FEMALE,27,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"elyssa@gibbs-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569183,\\"sold_product_569183_12081, sold_product_569183_8623\\",\\"sold_product_569183_12081, sold_product_569183_8623\\",\\"10.992, 17.984\\",\\"10.992, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.172, 8.102\\",\\"10.992, 17.984\\",\\"12,081, 8,623\\",\\"Long sleeved top - dark brown, Long sleeved top - red ochre\\",\\"Long sleeved top - dark brown, Long sleeved top - red ochre\\",\\"1, 1\\",\\"ZO0641206412, ZO0165301653\\",\\"0, 0\\",\\"10.992, 17.984\\",\\"10.992, 17.984\\",\\"0, 0\\",\\"ZO0641206412, ZO0165301653\\",\\"28.984\\",\\"28.984\\",2,2,order,elyssa +YgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Mckinney\\",\\"Kamal Mckinney\\",MALE,39,Mckinney,Mckinney,\\"(empty)\\",Wednesday,2,\\"kamal@mckinney-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568818,\\"sold_product_568818_12415, sold_product_568818_24390\\",\\"sold_product_568818_12415, sold_product_568818_24390\\",\\"18.984, 16.984\\",\\"18.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"9.313, 8.828\\",\\"18.984, 16.984\\",\\"12,415, 24,390\\",\\"Polo shirt - mottled grey, Jumper - dark brown multicolor\\",\\"Polo shirt - mottled grey, Jumper - dark brown multicolor\\",\\"1, 1\\",\\"ZO0294802948, ZO0451404514\\",\\"0, 0\\",\\"18.984, 16.984\\",\\"18.984, 16.984\\",\\"0, 0\\",\\"ZO0294802948, ZO0451404514\\",\\"35.969\\",\\"35.969\\",2,2,order,kamal +YwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Rivera\\",\\"Robert Rivera\\",MALE,29,Rivera,Rivera,\\"(empty)\\",Wednesday,2,\\"robert@rivera-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568854,\\"sold_product_568854_12479, sold_product_568854_1820\\",\\"sold_product_568854_12479, sold_product_568854_1820\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"5.059, 36.75\\",\\"10.992, 75\\",\\"12,479, 1,820\\",\\"Print T-shirt - black, Smart slip-ons - oro\\",\\"Print T-shirt - black, Smart slip-ons - oro\\",\\"1, 1\\",\\"ZO0616706167, ZO0255402554\\",\\"0, 0\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"0, 0\\",\\"ZO0616706167, ZO0255402554\\",86,86,2,2,order,robert +ZAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Carpenter\\",\\"Ahmed Al Carpenter\\",MALE,4,Carpenter,Carpenter,\\"(empty)\\",Wednesday,2,\\"ahmed al@carpenter-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568901,\\"sold_product_568901_13181, sold_product_568901_23144\\",\\"sold_product_568901_13181, sold_product_568901_23144\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"21, 15.359\\",\\"42, 28.984\\",\\"13,181, 23,144\\",\\"Briefcase - navy, Slim fit jeans - grey\\",\\"Briefcase - navy, Slim fit jeans - grey\\",\\"1, 1\\",\\"ZO0466704667, ZO0427104271\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0466704667, ZO0427104271\\",71,71,2,2,order,ahmed +ZQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Hansen\\",\\"Mostafa Hansen\\",MALE,9,Hansen,Hansen,\\"(empty)\\",Wednesday,2,\\"mostafa@hansen-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568954,\\"sold_product_568954_591, sold_product_568954_1974\\",\\"sold_product_568954_591, sold_product_568954_1974\\",\\"65, 60\\",\\"65, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"29.906, 28.203\\",\\"65, 60\\",\\"591, 1,974\\",\\"Lace-up boots - black barro, Lace-up boots - black\\",\\"Lace-up boots - black barro, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0399603996, ZO0685906859\\",\\"0, 0\\",\\"65, 60\\",\\"65, 60\\",\\"0, 0\\",\\"ZO0399603996, ZO0685906859\\",125,125,2,2,order,mostafa +ZgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Palmer\\",\\"Pia Palmer\\",FEMALE,45,Palmer,Palmer,\\"(empty)\\",Wednesday,2,\\"pia@palmer-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569033,\\"sold_product_569033_7233, sold_product_569033_18726\\",\\"sold_product_569033_7233, sold_product_569033_18726\\",\\"50, 140\\",\\"50, 140\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"26.484, 64.375\\",\\"50, 140\\",\\"7,233, 18,726\\",\\"Over-the-knee boots - cognac, High heeled boots - stone\\",\\"Over-the-knee boots - cognac, High heeled boots - stone\\",\\"1, 1\\",\\"ZO0015700157, ZO0362503625\\",\\"0, 0\\",\\"50, 140\\",\\"50, 140\\",\\"0, 0\\",\\"ZO0015700157, ZO0362503625\\",190,190,2,2,order,pia +ZwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Mcdonald\\",\\"Fitzgerald Mcdonald\\",MALE,11,Mcdonald,Mcdonald,\\"(empty)\\",Wednesday,2,\\"fitzgerald@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569091,\\"sold_product_569091_13103, sold_product_569091_12677\\",\\"sold_product_569091_13103, sold_product_569091_12677\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"17.156, 8.492\\",\\"33, 16.984\\",\\"13,103, 12,677\\",\\"T-bar sandals - black, Long sleeved top - black\\",\\"T-bar sandals - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0258602586, ZO0552205522\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0258602586, ZO0552205522\\",\\"49.969\\",\\"49.969\\",2,2,order,fuzzy +aAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Gibbs\\",\\"Ahmed Al Gibbs\\",MALE,4,Gibbs,Gibbs,\\"(empty)\\",Wednesday,2,\\"ahmed al@gibbs-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569003,\\"sold_product_569003_13719, sold_product_569003_12174\\",\\"sold_product_569003_13719, sold_product_569003_12174\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.242, 27\\",\\"24.984, 60\\",\\"13,719, 12,174\\",\\"Shirt - blue/grey, Smart lace-ups - Dark Red\\",\\"Shirt - blue/grey, Smart lace-ups - Dark Red\\",\\"1, 1\\",\\"ZO0414704147, ZO0387503875\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0414704147, ZO0387503875\\",85,85,2,2,order,ahmed +bQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Jim,Jim,\\"Jim Potter\\",\\"Jim Potter\\",MALE,41,Potter,Potter,\\"(empty)\\",Wednesday,2,\\"jim@potter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568707,\\"sold_product_568707_24723, sold_product_568707_24246\\",\\"sold_product_568707_24723, sold_product_568707_24246\\",\\"33, 65\\",\\"33, 65\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"17.484, 33.781\\",\\"33, 65\\",\\"24,723, 24,246\\",\\"High-top trainers - multicolor, Lace-up boots - black\\",\\"High-top trainers - multicolor, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0513305133, ZO0253302533\\",\\"0, 0\\",\\"33, 65\\",\\"33, 65\\",\\"0, 0\\",\\"ZO0513305133, ZO0253302533\\",98,98,2,2,order,jim +eQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Underwood\\",\\"George Underwood\\",MALE,32,Underwood,Underwood,\\"(empty)\\",Wednesday,2,\\"george@underwood-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568019,\\"sold_product_568019_17179, sold_product_568019_20306\\",\\"sold_product_568019_17179, sold_product_568019_20306\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"15.07, 5.52\\",\\"28.984, 11.992\\",\\"17,179, 20,306\\",\\"Chinos - black, Long sleeved top - mottled dark grey\\",\\"Chinos - black, Long sleeved top - mottled dark grey\\",\\"1, 1\\",\\"ZO0530805308, ZO0563905639\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0530805308, ZO0563905639\\",\\"40.969\\",\\"40.969\\",2,2,order,george +qQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Ruiz\\",\\"Yasmine Ruiz\\",FEMALE,43,Ruiz,Ruiz,\\"(empty)\\",Wednesday,2,\\"yasmine@ruiz-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568182,\\"sold_product_568182_18562, sold_product_568182_21438\\",\\"sold_product_568182_18562, sold_product_568182_21438\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"18.906, 5.711\\",\\"42, 10.992\\",\\"18,562, 21,438\\",\\"Jersey dress - black, Long sleeved top - light grey multicolor\\",\\"Jersey dress - black, Long sleeved top - light grey multicolor\\",\\"1, 1\\",\\"ZO0338603386, ZO0641006410\\",\\"0, 0\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"0, 0\\",\\"ZO0338603386, ZO0641006410\\",\\"52.969\\",\\"52.969\\",2,2,order,yasmine +CwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Munoz\\",\\"Jim Munoz\\",MALE,41,Munoz,Munoz,\\"(empty)\\",Wednesday,2,\\"jim@munoz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569299,\\"sold_product_569299_18493, sold_product_569299_22273\\",\\"sold_product_569299_18493, sold_product_569299_22273\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"15.18, 5.93\\",\\"33, 10.992\\",\\"18,493, 22,273\\",\\"Lace-up boots - camel, Shorts - black\\",\\"Lace-up boots - camel, Shorts - black\\",\\"1, 1\\",\\"ZO0519605196, ZO0630806308\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0519605196, ZO0630806308\\",\\"43.969\\",\\"43.969\\",2,2,order,jim +DAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Watkins\\",\\"Jackson Watkins\\",MALE,13,Watkins,Watkins,\\"(empty)\\",Wednesday,2,\\"jackson@watkins-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569123,\\"sold_product_569123_15429, sold_product_569123_23856\\",\\"sold_product_569123_15429, sold_product_569123_23856\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 5.398\\",\\"20.984, 11.992\\",\\"15,429, 23,856\\",\\"Rucksack - black, Polo shirt - dark grey multicolor\\",\\"Rucksack - black, Polo shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0609006090, ZO0441504415\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0609006090, ZO0441504415\\",\\"32.969\\",\\"32.969\\",2,2,order,jackson +kAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Austin\\",\\"Elyssa Austin\\",FEMALE,27,Austin,Austin,\\"(empty)\\",Wednesday,2,\\"elyssa@austin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728335,\\"sold_product_728335_15156, sold_product_728335_21016, sold_product_728335_24932, sold_product_728335_18891\\",\\"sold_product_728335_15156, sold_product_728335_21016, sold_product_728335_24932, sold_product_728335_18891\\",\\"24.984, 33, 21.984, 33\\",\\"24.984, 33, 21.984, 33\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises, Pyramidustries active, Tigress Enterprises\\",\\"12.992, 15.844, 12.094, 18.141\\",\\"24.984, 33, 21.984, 33\\",\\"15,156, 21,016, 24,932, 18,891\\",\\"Classic heels - light blue, Ankle boots - black, Tights - grey multicolor, Ankle boots - black\\",\\"Classic heels - light blue, Ankle boots - black, Tights - grey multicolor, Ankle boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\",\\"0, 0, 0, 0\\",\\"24.984, 33, 21.984, 33\\",\\"24.984, 33, 21.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0134701347, ZO0026200262, ZO0223102231, ZO0022900229\\",\\"112.938\\",\\"112.938\\",4,4,order,elyssa +mgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Powell\\",\\"Rabbia Al Powell\\",FEMALE,5,Powell,Powell,\\"(empty)\\",Wednesday,2,\\"rabbia al@powell-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",726874,\\"sold_product_726874_12603, sold_product_726874_14008, sold_product_726874_16407, sold_product_726874_23268\\",\\"sold_product_726874_12603, sold_product_726874_14008, sold_product_726874_16407, sold_product_726874_23268\\",\\"140, 37, 13.992, 42\\",\\"140, 37, 13.992, 42\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"Primemaster, Tigress Enterprises, Spherecords Maternity, Champion Arts\\",\\"70, 18.5, 7, 19.734\\",\\"140, 37, 13.992, 42\\",\\"12,603, 14,008, 16,407, 23,268\\",\\"Boots - Midnight Blue, Summer dress - rose/black, Maxi skirt - mid grey multicolor, Light jacket - black/off-white\\",\\"Boots - Midnight Blue, Summer dress - rose/black, Maxi skirt - mid grey multicolor, Light jacket - black/off-white\\",\\"1, 1, 1, 1\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\",\\"0, 0, 0, 0\\",\\"140, 37, 13.992, 42\\",\\"140, 37, 13.992, 42\\",\\"0, 0, 0, 0\\",\\"ZO0362303623, ZO0035400354, ZO0705207052, ZO0504005040\\",233,233,4,4,order,rabbia +vAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Benson\\",\\"Stephanie Benson\\",FEMALE,6,Benson,Benson,\\"(empty)\\",Wednesday,2,\\"stephanie@benson-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569218,\\"sold_product_569218_18040, sold_product_569218_14398\\",\\"sold_product_569218_18040, sold_product_569218_14398\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"12.25, 10.906\\",\\"24.984, 20.984\\",\\"18,040, 14,398\\",\\"Trousers - black, Tracksuit bottoms - dark grey\\",\\"Trousers - black, Tracksuit bottoms - dark grey\\",\\"1, 1\\",\\"ZO0633206332, ZO0488604886\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0633206332, ZO0488604886\\",\\"45.969\\",\\"45.969\\",2,2,order,stephanie +0wMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Nash\\",\\"Jackson Nash\\",MALE,13,Nash,Nash,\\"(empty)\\",Wednesday,2,\\"jackson@nash-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Spritechnologies, Low Tide Media, Elitelligence\\",\\"Spritechnologies, Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",722613,\\"sold_product_722613_11046, sold_product_722613_11747, sold_product_722613_16568, sold_product_722613_15828\\",\\"sold_product_722613_11046, sold_product_722613_11747, sold_product_722613_16568, sold_product_722613_15828\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spritechnologies, Low Tide Media, Elitelligence, Low Tide Media\\",\\"Spritechnologies, Low Tide Media, Elitelligence, Low Tide Media\\",\\"9.453, 10.906, 15.938, 5.172\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"11,046, 11,747, 16,568, 15,828\\",\\"Tracksuit bottoms - black, Polo shirt - blue, Chinos - dark blue, Tie - black\\",\\"Tracksuit bottoms - black, Polo shirt - blue, Chinos - dark blue, Tie - black\\",\\"1, 1, 1, 1\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"20.984, 20.984, 28.984, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0618806188, ZO0442804428, ZO0530705307, ZO0410804108\\",\\"81.938\\",\\"81.938\\",4,4,order,jackson +1AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Kim\\",\\"Sonya Kim\\",FEMALE,28,Kim,Kim,\\"(empty)\\",Wednesday,2,\\"sonya@kim-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568152,\\"sold_product_568152_16870, sold_product_568152_17608\\",\\"sold_product_568152_16870, sold_product_568152_17608\\",\\"37, 28.984\\",\\"37, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.391, 14.211\\",\\"37, 28.984\\",\\"16,870, 17,608\\",\\"Blouse - multicolored, Summer dress - black/berry\\",\\"Blouse - multicolored, Summer dress - black/berry\\",\\"1, 1\\",\\"ZO0349303493, ZO0043900439\\",\\"0, 0\\",\\"37, 28.984\\",\\"37, 28.984\\",\\"0, 0\\",\\"ZO0349303493, ZO0043900439\\",66,66,2,2,order,sonya +1QMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Hampton\\",\\"Irwin Hampton\\",MALE,14,Hampton,Hampton,\\"(empty)\\",Wednesday,2,\\"irwin@hampton-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568212,\\"sold_product_568212_19457, sold_product_568212_1471\\",\\"sold_product_568212_19457, sold_product_568212_1471\\",\\"25.984, 60\\",\\"25.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"12.219, 30\\",\\"25.984, 60\\",\\"19,457, 1,471\\",\\"Slim fit jeans - khaki, Lace-up boots - tan\\",\\"Slim fit jeans - khaki, Lace-up boots - tan\\",\\"1, 1\\",\\"ZO0536405364, ZO0688306883\\",\\"0, 0\\",\\"25.984, 60\\",\\"25.984, 60\\",\\"0, 0\\",\\"ZO0536405364, ZO0688306883\\",86,86,2,2,order,irwin +5AMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Gomez\\",\\"Abdulraheem Al Gomez\\",MALE,33,Gomez,Gomez,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@gomez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568228,\\"sold_product_568228_17075, sold_product_568228_21129\\",\\"sold_product_568228_17075, sold_product_568228_21129\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"31.797, 11.039\\",\\"60, 22.984\\",\\"17,075, 21,129\\",\\"Smart lace-ups - cognac, Jumper - khaki\\",\\"Smart lace-ups - cognac, Jumper - khaki\\",\\"1, 1\\",\\"ZO0387103871, ZO0580005800\\",\\"0, 0\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"0, 0\\",\\"ZO0387103871, ZO0580005800\\",83,83,2,2,order,abdulraheem +5QMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Lloyd\\",\\"Robert Lloyd\\",MALE,29,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"robert@lloyd-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568455,\\"sold_product_568455_13779, sold_product_568455_15022\\",\\"sold_product_568455_13779, sold_product_568455_15022\\",\\"22.984, 60\\",\\"22.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"11.273, 30.594\\",\\"22.984, 60\\",\\"13,779, 15,022\\",\\"Formal shirt - light blue, Lace-ups - cognac\\",\\"Formal shirt - light blue, Lace-ups - cognac\\",\\"1, 1\\",\\"ZO0413104131, ZO0392303923\\",\\"0, 0\\",\\"22.984, 60\\",\\"22.984, 60\\",\\"0, 0\\",\\"ZO0413104131, ZO0392303923\\",83,83,2,2,order,robert +7wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Evans\\",\\"Abdulraheem Al Evans\\",MALE,33,Evans,Evans,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@evans-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",567994,\\"sold_product_567994_12464, sold_product_567994_14037\\",\\"sold_product_567994_12464, sold_product_567994_14037\\",\\"75, 140\\",\\"75, 140\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"33.75, 68.625\\",\\"75, 140\\",\\"12,464, 14,037\\",\\"Short coat - dark grey, Leather jacket - black\\",\\"Short coat - dark grey, Leather jacket - black\\",\\"1, 1\\",\\"ZO0430904309, ZO0288402884\\",\\"0, 0\\",\\"75, 140\\",\\"75, 140\\",\\"0, 0\\",\\"ZO0430904309, ZO0288402884\\",215,215,2,2,order,abdulraheem +CAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Hayes\\",\\"Elyssa Hayes\\",FEMALE,27,Hayes,Hayes,\\"(empty)\\",Wednesday,2,\\"elyssa@hayes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568045,\\"sold_product_568045_16186, sold_product_568045_24601\\",\\"sold_product_568045_16186, sold_product_568045_24601\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 14.492\\",\\"11.992, 28.984\\",\\"16,186, 24,601\\",\\"Print T-shirt - white, Cardigan - white/black\\",\\"Print T-shirt - white, Cardigan - white/black\\",\\"1, 1\\",\\"ZO0160501605, ZO0069500695\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0160501605, ZO0069500695\\",\\"40.969\\",\\"40.969\\",2,2,order,elyssa +VQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryant\\",\\"Elyssa Bryant\\",FEMALE,27,Bryant,Bryant,\\"(empty)\\",Wednesday,2,\\"elyssa@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568308,\\"sold_product_568308_15499, sold_product_568308_17990\\",\\"sold_product_568308_15499, sold_product_568308_17990\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"29.906, 12.992\\",\\"65, 24.984\\",\\"15,499, 17,990\\",\\"Over-the-knee boots - black, Ankle boots - cognac\\",\\"Over-the-knee boots - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0138701387, ZO0024600246\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0138701387, ZO0024600246\\",90,90,2,2,order,elyssa +VgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Chapman\\",\\"Stephanie Chapman\\",FEMALE,6,Chapman,Chapman,\\"(empty)\\",Wednesday,2,\\"stephanie@chapman-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568515,\\"sold_product_568515_19990, sold_product_568515_18594\\",\\"sold_product_568515_19990, sold_product_568515_18594\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"5.762, 34.438\\",\\"11.992, 65\\",\\"19,990, 18,594\\",\\"Vest - Forest Green, Classic heels - black\\",\\"Vest - Forest Green, Classic heels - black\\",\\"1, 1\\",\\"ZO0159901599, ZO0238702387\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0159901599, ZO0238702387\\",77,77,2,2,order,stephanie +dgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Marshall\\",\\"Eddie Marshall\\",MALE,38,Marshall,Marshall,\\"(empty)\\",Wednesday,2,\\"eddie@marshall-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",721706,\\"sold_product_721706_21844, sold_product_721706_11106, sold_product_721706_1850, sold_product_721706_22242\\",\\"sold_product_721706_21844, sold_product_721706_11106, sold_product_721706_1850, sold_product_721706_22242\\",\\"33, 10.992, 28.984, 24.984\\",\\"33, 10.992, 28.984, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence, Elitelligence, Elitelligence\\",\\"17.484, 5.711, 14.211, 12.992\\",\\"33, 10.992, 28.984, 24.984\\",\\"21,844, 11,106, 1,850, 22,242\\",\\"Lace-up boots - red, 2 PACK - Shorts - black/stripe, Trainers - black/grey, Sweatshirt - black\\",\\"Lace-up boots - red, 2 PACK - Shorts - black/stripe, Trainers - black/grey, Sweatshirt - black\\",\\"1, 1, 1, 1\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\",\\"0, 0, 0, 0\\",\\"33, 10.992, 28.984, 24.984\\",\\"33, 10.992, 28.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0519005190, ZO0610206102, ZO0514405144, ZO0586505865\\",\\"97.938\\",\\"97.938\\",4,4,order,eddie +fQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Roberson\\",\\"Wilhemina St. Roberson\\",FEMALE,17,Roberson,Roberson,\\"(empty)\\",Wednesday,2,\\"wilhemina st.@roberson-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569250,\\"sold_product_569250_22975, sold_product_569250_16886\\",\\"sold_product_569250_22975, sold_product_569250_16886\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"17.484, 14.781\\",\\"33, 28.984\\",\\"22,975, 16,886\\",\\"Jersey dress - Medium Sea Green, Wedges - black\\",\\"Jersey dress - Medium Sea Green, Wedges - black\\",\\"1, 1\\",\\"ZO0228902289, ZO0005400054\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0228902289, ZO0005400054\\",\\"61.969\\",\\"61.969\\",2,2,order,wilhemina +3wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Washington\\",\\"Thad Washington\\",MALE,30,Washington,Washington,\\"(empty)\\",Wednesday,2,\\"thad@washington-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568776,\\"sold_product_568776_22271, sold_product_568776_18957\\",\\"sold_product_568776_22271, sold_product_568776_18957\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"5.711, 11.75\\",\\"10.992, 24.984\\",\\"22,271, 18,957\\",\\"Sports shirt - dark green, Jumper - black\\",\\"Sports shirt - dark green, Jumper - black\\",\\"1, 1\\",\\"ZO0616906169, ZO0296902969\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0616906169, ZO0296902969\\",\\"35.969\\",\\"35.969\\",2,2,order,thad +\\"-wMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Moran\\",\\"Samir Moran\\",MALE,34,Moran,Moran,\\"(empty)\\",Wednesday,2,\\"samir@moran-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568014,\\"sold_product_568014_6401, sold_product_568014_19633\\",\\"sold_product_568014_6401, sold_product_568014_19633\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 6.352\\",\\"20.984, 11.992\\",\\"6,401, 19,633\\",\\"Shirt - Blue Violety, Long sleeved top - white and red\\",\\"Shirt - Blue Violety, Long sleeved top - white and red\\",\\"1, 1\\",\\"ZO0523905239, ZO0556605566\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0523905239, ZO0556605566\\",\\"32.969\\",\\"32.969\\",2,2,order,samir +8wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Riley\\",\\"Elyssa Riley\\",FEMALE,27,Riley,Riley,\\"(empty)\\",Wednesday,2,\\"elyssa@riley-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 25, 2019 @ 00:00:00.000\\",568702,\\"sold_product_568702_18286, sold_product_568702_14025\\",\\"sold_product_568702_18286, sold_product_568702_14025\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"16.5, 11.5\\",\\"33, 24.984\\",\\"18,286, 14,025\\",\\"Ankle boots - black, Blazer - black\\",\\"Ankle boots - black, Blazer - black\\",\\"1, 1\\",\\"ZO0142801428, ZO0182801828\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0142801428, ZO0182801828\\",\\"57.969\\",\\"57.969\\",2,2,order,elyssa +HwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Lloyd\\",\\"Diane Lloyd\\",FEMALE,22,Lloyd,Lloyd,\\"(empty)\\",Wednesday,2,\\"diane@lloyd-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568128,\\"sold_product_568128_11766, sold_product_568128_22927\\",\\"sold_product_568128_11766, sold_product_568128_22927\\",\\"24.984, 34\\",\\"24.984, 34\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"12.992, 17.672\\",\\"24.984, 34\\",\\"11,766, 22,927\\",\\"Tote bag - berry, Lace-ups - black\\",\\"Tote bag - berry, Lace-ups - black\\",\\"1, 1\\",\\"ZO0087500875, ZO0007100071\\",\\"0, 0\\",\\"24.984, 34\\",\\"24.984, 34\\",\\"0, 0\\",\\"ZO0087500875, ZO0007100071\\",\\"58.969\\",\\"58.969\\",2,2,order,diane +IAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Fleming\\",\\"Jackson Fleming\\",MALE,13,Fleming,Fleming,\\"(empty)\\",Wednesday,2,\\"jackson@fleming-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568177,\\"sold_product_568177_15382, sold_product_568177_18515\\",\\"sold_product_568177_15382, sold_product_568177_18515\\",\\"37, 65\\",\\"37, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"19.594, 31.844\\",\\"37, 65\\",\\"15,382, 18,515\\",\\"Tracksuit top - mottled grey, Lace-up boots - tan\\",\\"Tracksuit top - mottled grey, Lace-up boots - tan\\",\\"1, 1\\",\\"ZO0584505845, ZO0403804038\\",\\"0, 0\\",\\"37, 65\\",\\"37, 65\\",\\"0, 0\\",\\"ZO0584505845, ZO0403804038\\",102,102,2,2,order,jackson +cwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Franklin\\",\\"rania Franklin\\",FEMALE,24,Franklin,Franklin,\\"(empty)\\",Wednesday,2,\\"rania@franklin-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569178,\\"sold_product_569178_15398, sold_product_569178_23456\\",\\"sold_product_569178_15398, sold_product_569178_23456\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"15.359, 25.484\\",\\"28.984, 50\\",\\"15,398, 23,456\\",\\"Jumper - offwhite, Maxi dress - black/white\\",\\"Jumper - offwhite, Maxi dress - black/white\\",\\"1, 1\\",\\"ZO0177001770, ZO0260502605\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0177001770, ZO0260502605\\",79,79,2,2,order,rani +dAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Griffin\\",\\"Sonya Griffin\\",FEMALE,28,Griffin,Griffin,\\"(empty)\\",Wednesday,2,\\"sonya@griffin-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568877,\\"sold_product_568877_19521, sold_product_568877_19378\\",\\"sold_product_568877_19521, sold_product_568877_19378\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"11.5, 13.492\\",\\"24.984, 24.984\\",\\"19,521, 19,378\\",\\"Classic heels - cognac, Long sleeved top - winternude\\",\\"Classic heels - cognac, Long sleeved top - winternude\\",\\"1, 1\\",\\"ZO0132401324, ZO0058200582\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0132401324, ZO0058200582\\",\\"49.969\\",\\"49.969\\",2,2,order,sonya +dQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Little\\",\\"Abdulraheem Al Little\\",MALE,33,Little,Little,\\"(empty)\\",Wednesday,2,\\"abdulraheem al@little-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 25, 2019 @ 00:00:00.000\\",568898,\\"sold_product_568898_11865, sold_product_568898_21764\\",\\"sold_product_568898_11865, sold_product_568898_21764\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"25.984, 15.359\\",\\"50, 28.984\\",\\"11,865, 21,764\\",\\"Down jacket - gru00fcn, Trainers - black\\",\\"Down jacket - gru00fcn, Trainers - black\\",\\"1, 1\\",\\"ZO0542205422, ZO0517805178\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0542205422, ZO0517805178\\",79,79,2,2,order,abdulraheem +dgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Padilla\\",\\"Selena Padilla\\",FEMALE,42,Padilla,Padilla,\\"(empty)\\",Wednesday,2,\\"selena@padilla-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568941,\\"sold_product_568941_14120, sold_product_568941_8820\\",\\"sold_product_568941_14120, sold_product_568941_8820\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"5.641, 13.344\\",\\"11.992, 28.984\\",\\"14,120, 8,820\\",\\"3 PACK - Belt - black/red/gunmetal, Jumper - peacoat/light blue\\",\\"3 PACK - Belt - black/red/gunmetal, Jumper - peacoat/light blue\\",\\"1, 1\\",\\"ZO0076600766, ZO0068800688\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0076600766, ZO0068800688\\",\\"40.969\\",\\"40.969\\",2,2,order,selena +dwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Ramsey\\",\\"Brigitte Ramsey\\",FEMALE,12,Ramsey,Ramsey,\\"(empty)\\",Wednesday,2,\\"brigitte@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569027,\\"sold_product_569027_15733, sold_product_569027_20410\\",\\"sold_product_569027_15733, sold_product_569027_20410\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"36, 9.492\\",\\"75, 18.984\\",\\"15,733, 20,410\\",\\"Boots - tan, Long sleeved top - black\\",\\"Boots - tan, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0245402454, ZO0060100601\\",\\"0, 0\\",\\"75, 18.984\\",\\"75, 18.984\\",\\"0, 0\\",\\"ZO0245402454, ZO0060100601\\",94,94,2,2,order,brigitte +eAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Morgan\\",\\"Sonya Morgan\\",FEMALE,28,Morgan,Morgan,\\"(empty)\\",Wednesday,2,\\"sonya@morgan-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569055,\\"sold_product_569055_12453, sold_product_569055_13828\\",\\"sold_product_569055_12453, sold_product_569055_13828\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"31.797, 15.18\\",\\"60, 33\\",\\"12,453, 13,828\\",\\"Ankle boots - Midnight Blue, Jumper - white/black\\",\\"Ankle boots - Midnight Blue, Jumper - white/black\\",\\"1, 1\\",\\"ZO0375903759, ZO0269402694\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0375903759, ZO0269402694\\",93,93,2,2,order,sonya +eQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Hubbard\\",\\"Pia Hubbard\\",FEMALE,45,Hubbard,Hubbard,\\"(empty)\\",Wednesday,2,\\"pia@hubbard-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Champion Arts\\",\\"Gnomehouse, Champion Arts\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569107,\\"sold_product_569107_24376, sold_product_569107_8430\\",\\"sold_product_569107_24376, sold_product_569107_8430\\",\\"60, 60\\",\\"60, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Champion Arts\\",\\"Gnomehouse, Champion Arts\\",\\"27, 30.594\\",\\"60, 60\\",\\"24,376, 8,430\\",\\"Fun and Flowery Dress, Winter coat - red\\",\\"Fun and Flowery Dress, Winter coat - red\\",\\"1, 1\\",\\"ZO0339603396, ZO0504705047\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0339603396, ZO0504705047\\",120,120,2,2,order,pia +iQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Clayton\\",\\"Tariq Clayton\\",MALE,25,Clayton,Clayton,\\"(empty)\\",Wednesday,2,\\"tariq@clayton-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations, Low Tide Media\\",\\"Elitelligence, Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",714385,\\"sold_product_714385_13039, sold_product_714385_16435, sold_product_714385_15502, sold_product_714385_6719\\",\\"sold_product_714385_13039, sold_product_714385_16435, sold_product_714385_15502, sold_product_714385_6719\\",\\"24.984, 21.984, 33, 28.984\\",\\"24.984, 21.984, 33, 28.984\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Oceanavigations, Low Tide Media\\",\\"Elitelligence, Elitelligence, Oceanavigations, Low Tide Media\\",\\"12.492, 12.094, 15.844, 15.359\\",\\"24.984, 21.984, 33, 28.984\\",\\"13,039, 16,435, 15,502, 6,719\\",\\"Sweatshirt - dark blue, Across body bag - dark grey, Watch - black, Trousers - dark blue\\",\\"Sweatshirt - dark blue, Across body bag - dark grey, Watch - black, Trousers - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\",\\"0, 0, 0, 0\\",\\"24.984, 21.984, 33, 28.984\\",\\"24.984, 21.984, 33, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0586805868, ZO0609106091, ZO0310903109, ZO0420104201\\",\\"108.938\\",\\"108.938\\",4,4,order,tariq +hQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mcdonald\\",\\"Abd Mcdonald\\",MALE,52,Mcdonald,Mcdonald,\\"(empty)\\",Wednesday,2,\\"abd@mcdonald-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",723213,\\"sold_product_723213_6457, sold_product_723213_19528, sold_product_723213_12063, sold_product_723213_14510\\",\\"sold_product_723213_6457, sold_product_723213_19528, sold_product_723213_12063, sold_product_723213_14510\\",\\"28.984, 20.984, 20.984, 33\\",\\"28.984, 20.984, 20.984, 33\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Low Tide Media, Elitelligence, Oceanavigations\\",\\"Oceanavigations, Low Tide Media, Elitelligence, Oceanavigations\\",\\"15.359, 11.117, 9.867, 15.18\\",\\"28.984, 20.984, 20.984, 33\\",\\"6,457, 19,528, 12,063, 14,510\\",\\"Jumper - offwhite, Sweatshirt - navy, Cardigan - offwhite multicolor, Shirt - grey multicolor\\",\\"Jumper - offwhite, Sweatshirt - navy, Cardigan - offwhite multicolor, Shirt - grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\",\\"0, 0, 0, 0\\",\\"28.984, 20.984, 20.984, 33\\",\\"28.984, 20.984, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0297802978, ZO0456704567, ZO0572105721, ZO0280502805\\",\\"103.938\\",\\"103.938\\",4,4,order,abd +zQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Carr\\",\\"Thad Carr\\",MALE,30,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"thad@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568325,\\"sold_product_568325_11553, sold_product_568325_17851\\",\\"sold_product_568325_11553, sold_product_568325_17851\\",\\"140, 50\\",\\"140, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"72.813, 25.984\\",\\"140, 50\\",\\"11,553, 17,851\\",\\"Leather jacket - camel, Casual lace-ups - dark blue\\",\\"Leather jacket - camel, Casual lace-ups - dark blue\\",\\"1, 1\\",\\"ZO0288202882, ZO0391803918\\",\\"0, 0\\",\\"140, 50\\",\\"140, 50\\",\\"0, 0\\",\\"ZO0288202882, ZO0391803918\\",190,190,2,2,order,thad +zgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Cook\\",\\"Wagdi Cook\\",MALE,15,Cook,Cook,\\"(empty)\\",Wednesday,2,\\"wagdi@cook-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568360,\\"sold_product_568360_13315, sold_product_568360_18355\\",\\"sold_product_568360_13315, sold_product_568360_18355\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.398, 32.5\\",\\"11.992, 65\\",\\"13,315, 18,355\\",\\"5 PACK - Socks - blue/red/grey/green/black, Suit jacket - offwhite\\",\\"5 PACK - Socks - blue/red/grey/green/black, Suit jacket - offwhite\\",\\"1, 1\\",\\"ZO0480304803, ZO0274402744\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0480304803, ZO0274402744\\",77,77,2,2,order,wagdi +EAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,\\"(empty)\\",Wednesday,2,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",569278,\\"sold_product_569278_7811, sold_product_569278_19226\\",\\"sold_product_569278_7811, sold_product_569278_19226\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"48, 9.68\\",\\"100, 18.984\\",\\"7,811, 19,226\\",\\"Short coat - dark blue multicolor, Print T-shirt - black\\",\\"Short coat - dark blue multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0271802718, ZO0057100571\\",\\"0, 0\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"0, 0\\",\\"ZO0271802718, ZO0057100571\\",119,119,2,2,order,brigitte +UgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Underwood\\",\\"Gwen Underwood\\",FEMALE,26,Underwood,Underwood,\\"(empty)\\",Wednesday,2,\\"gwen@underwood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568816,\\"sold_product_568816_24602, sold_product_568816_21413\\",\\"sold_product_568816_24602, sold_product_568816_21413\\",\\"21.984, 37\\",\\"21.984, 37\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"12.094, 18.5\\",\\"21.984, 37\\",\\"24,602, 21,413\\",\\"Trousers - black, Jersey dress - black\\",\\"Trousers - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0146601466, ZO0108601086\\",\\"0, 0\\",\\"21.984, 37\\",\\"21.984, 37\\",\\"0, 0\\",\\"ZO0146601466, ZO0108601086\\",\\"58.969\\",\\"58.969\\",2,2,order,gwen +UwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Carr\\",\\"Yuri Carr\\",MALE,21,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"yuri@carr-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568375,\\"sold_product_568375_11121, sold_product_568375_14185\\",\\"sold_product_568375_11121, sold_product_568375_14185\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"30.547, 11.75\\",\\"65, 24.984\\",\\"11,121, 14,185\\",\\"Winter jacket - black, Rucksack - washed black/black\\",\\"Winter jacket - black, Rucksack - washed black/black\\",\\"1, 1\\",\\"ZO0623606236, ZO0605306053\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0623606236, ZO0605306053\\",90,90,2,2,order,yuri +VAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Taylor\\",\\"Eddie Taylor\\",MALE,38,Taylor,Taylor,\\"(empty)\\",Wednesday,2,\\"eddie@taylor-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568559,\\"sold_product_568559_17305, sold_product_568559_15031\\",\\"sold_product_568559_17305, sold_product_568559_15031\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.109, 16.813\\",\\"11.992, 33\\",\\"17,305, 15,031\\",\\"Belt - black, Wool - black\\",\\"Belt - black, Wool - black\\",\\"1, 1\\",\\"ZO0599005990, ZO0626506265\\",\\"0, 0\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"0, 0\\",\\"ZO0599005990, ZO0626506265\\",\\"44.969\\",\\"44.969\\",2,2,order,eddie +VQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Valdez\\",\\"Pia Valdez\\",FEMALE,45,Valdez,Valdez,\\"(empty)\\",Wednesday,2,\\"pia@valdez-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568611,\\"sold_product_568611_12564, sold_product_568611_12268\\",\\"sold_product_568611_12564, sold_product_568611_12268\\",\\"38, 42\\",\\"38, 42\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"17.484, 19.734\\",\\"38, 42\\",\\"12,564, 12,268\\",\\"Short coat - black, Tote bag - light brown\\",\\"Short coat - black, Tote bag - light brown\\",\\"1, 1\\",\\"ZO0174701747, ZO0305103051\\",\\"0, 0\\",\\"38, 42\\",\\"38, 42\\",\\"0, 0\\",\\"ZO0174701747, ZO0305103051\\",80,80,2,2,order,pia +VgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Hodges\\",\\"Jason Hodges\\",MALE,16,Hodges,Hodges,\\"(empty)\\",Wednesday,2,\\"jason@hodges-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568638,\\"sold_product_568638_18188, sold_product_568638_6975\\",\\"sold_product_568638_18188, sold_product_568638_6975\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"17.484, 8.742\\",\\"33, 18.984\\",\\"18,188, 6,975\\",\\"Smart lace-ups - cognac, Pyjama bottoms - green\\",\\"Smart lace-ups - cognac, Pyjama bottoms - green\\",\\"1, 1\\",\\"ZO0388003880, ZO0478304783\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0388003880, ZO0478304783\\",\\"51.969\\",\\"51.969\\",2,2,order,jason +VwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hampton\\",\\"Mary Hampton\\",FEMALE,20,Hampton,Hampton,\\"(empty)\\",Wednesday,2,\\"mary@hampton-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568706,\\"sold_product_568706_15826, sold_product_568706_11255\\",\\"sold_product_568706_15826, sold_product_568706_11255\\",\\"110, 50\\",\\"110, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"55, 25.984\\",\\"110, 50\\",\\"15,826, 11,255\\",\\"Over-the-knee boots - black, Jersey dress - dark navy and white\\",\\"Over-the-knee boots - black, Jersey dress - dark navy and white\\",\\"1, 1\\",\\"ZO0672206722, ZO0331903319\\",\\"0, 0\\",\\"110, 50\\",\\"110, 50\\",\\"0, 0\\",\\"ZO0672206722, ZO0331903319\\",160,160,2,2,order,mary +mgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Shoes, Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Banks\\",\\"Tariq Banks\\",MALE,25,Banks,Banks,\\"(empty)\\",Wednesday,2,\\"tariq@banks-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, (empty), Low Tide Media\\",\\"Elitelligence, (empty), Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",716889,\\"sold_product_716889_21293, sold_product_716889_12288, sold_product_716889_22189, sold_product_716889_19058\\",\\"sold_product_716889_21293, sold_product_716889_12288, sold_product_716889_22189, sold_product_716889_19058\\",\\"24.984, 155, 10.992, 16.984\\",\\"24.984, 155, 10.992, 16.984\\",\\"Men's Shoes, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Shoes, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, (empty), Elitelligence, Low Tide Media\\",\\"Elitelligence, (empty), Elitelligence, Low Tide Media\\",\\"12.742, 71.313, 5.82, 7.648\\",\\"24.984, 155, 10.992, 16.984\\",\\"21,293, 12,288, 22,189, 19,058\\",\\"Trainers - white, Smart slip-ons - brown, Wallet - black, Jumper - dark grey multicolor\\",\\"Trainers - white, Smart slip-ons - brown, Wallet - black, Jumper - dark grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\",\\"0, 0, 0, 0\\",\\"24.984, 155, 10.992, 16.984\\",\\"24.984, 155, 10.992, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0510505105, ZO0482404824, ZO0602306023, ZO0445904459\\",208,208,4,4,order,tariq +1wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Butler\\",\\"Rabbia Al Butler\\",FEMALE,5,Butler,Butler,\\"(empty)\\",Wednesday,2,\\"rabbia al@butler-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Champion Arts, Tigress Enterprises\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",728580,\\"sold_product_728580_12102, sold_product_728580_24113, sold_product_728580_22614, sold_product_728580_19229\\",\\"sold_product_728580_12102, sold_product_728580_24113, sold_product_728580_22614, sold_product_728580_19229\\",\\"10.992, 33, 28.984, 16.984\\",\\"10.992, 33, 28.984, 16.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises, Tigress Enterprises\\",\\"Pyramidustries, Champion Arts, Tigress Enterprises, Tigress Enterprises\\",\\"5.059, 15.508, 13.633, 7.988\\",\\"10.992, 33, 28.984, 16.984\\",\\"12,102, 24,113, 22,614, 19,229\\",\\"Vest - white, Cardigan - dark blue/off-white, Cardigan - black, Clutch - black\\",\\"Vest - white, Cardigan - dark blue/off-white, Cardigan - black, Clutch - black\\",\\"1, 1, 1, 1\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\",\\"0, 0, 0, 0\\",\\"10.992, 33, 28.984, 16.984\\",\\"10.992, 33, 28.984, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0156601566, ZO0498004980, ZO0070700707, ZO0086700867\\",\\"89.938\\",\\"89.938\\",4,4,order,rabbia +3wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane King\\",\\"Diane King\\",FEMALE,22,King,King,\\"(empty)\\",Wednesday,2,\\"diane@king-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568762,\\"sold_product_568762_22428, sold_product_568762_9391\\",\\"sold_product_568762_22428, sold_product_568762_9391\\",\\"37, 33\\",\\"37, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"17.391, 17.484\\",\\"37, 33\\",\\"22,428, 9,391\\",\\"Jersey dress - royal blue, Shirt - white\\",\\"Jersey dress - royal blue, Shirt - white\\",\\"1, 1\\",\\"ZO0052200522, ZO0265602656\\",\\"0, 0\\",\\"37, 33\\",\\"37, 33\\",\\"0, 0\\",\\"ZO0052200522, ZO0265602656\\",70,70,2,2,order,diane +6QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Graves\\",\\"Abigail Graves\\",FEMALE,46,Graves,Graves,\\"(empty)\\",Wednesday,2,\\"abigail@graves-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568571,\\"sold_product_568571_23698, sold_product_568571_23882\\",\\"sold_product_568571_23698, sold_product_568571_23882\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"17.156, 16.813\\",\\"33, 33\\",\\"23,698, 23,882\\",\\"Pleated skirt - black, Long sleeved top - chinese red\\",\\"Pleated skirt - black, Long sleeved top - chinese red\\",\\"1, 1\\",\\"ZO0034100341, ZO0343103431\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0034100341, ZO0343103431\\",66,66,2,2,order,abigail +6gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Hale\\",\\"Diane Hale\\",FEMALE,22,Hale,Hale,\\"(empty)\\",Wednesday,2,\\"diane@hale-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spherecords, Pyramidustries active\\",\\"Spherecords, Pyramidustries active\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568671,\\"sold_product_568671_18674, sold_product_568671_9937\\",\\"sold_product_568671_18674, sold_product_568671_9937\\",\\"5.988, 11.992\\",\\"5.988, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries active\\",\\"Spherecords, Pyramidustries active\\",\\"2.76, 6.352\\",\\"5.988, 11.992\\",\\"18,674, 9,937\\",\\"Vest - white, Sports shirt - black \\",\\"Vest - white, Sports shirt - black \\",\\"1, 1\\",\\"ZO0637406374, ZO0219002190\\",\\"0, 0\\",\\"5.988, 11.992\\",\\"5.988, 11.992\\",\\"0, 0\\",\\"ZO0637406374, ZO0219002190\\",\\"17.984\\",\\"17.984\\",2,2,order,diane +9AMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Summers\\",\\"Elyssa Summers\\",FEMALE,27,Summers,Summers,\\"(empty)\\",Wednesday,2,\\"elyssa@summers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568774,\\"sold_product_568774_24937, sold_product_568774_24748\\",\\"sold_product_568774_24937, sold_product_568774_24748\\",\\"34, 60\\",\\"34, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"17, 33\\",\\"34, 60\\",\\"24,937, 24,748\\",\\"Jersey dress - dark green, Lace-ups - bianco\\",\\"Jersey dress - dark green, Lace-ups - bianco\\",\\"1, 1\\",\\"ZO0037200372, ZO0369303693\\",\\"0, 0\\",\\"34, 60\\",\\"34, 60\\",\\"0, 0\\",\\"ZO0037200372, ZO0369303693\\",94,94,2,2,order,elyssa +9QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Summers\\",\\"Jackson Summers\\",MALE,13,Summers,Summers,\\"(empty)\\",Wednesday,2,\\"jackson@summers-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568319,\\"sold_product_568319_16715, sold_product_568319_24934\\",\\"sold_product_568319_16715, sold_product_568319_24934\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"14.492, 22.5\\",\\"28.984, 50\\",\\"16,715, 24,934\\",\\"Slim fit jeans - black, Lace-up boots - resin coffee\\",\\"Slim fit jeans - black, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0535105351, ZO0403504035\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0535105351, ZO0403504035\\",79,79,2,2,order,jackson +9gMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Gregory\\",\\"Sultan Al Gregory\\",MALE,19,Gregory,Gregory,\\"(empty)\\",Wednesday,2,\\"sultan al@gregory-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568363,\\"sold_product_568363_19188, sold_product_568363_14507\\",\\"sold_product_568363_19188, sold_product_568363_14507\\",\\"20.984, 115\\",\\"20.984, 115\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"9.453, 59.781\\",\\"20.984, 115\\",\\"19,188, 14,507\\",\\"Swimming shorts - dark grey , Weekend bag - black\\",\\"Swimming shorts - dark grey , Weekend bag - black\\",\\"1, 1\\",\\"ZO0629806298, ZO0467104671\\",\\"0, 0\\",\\"20.984, 115\\",\\"20.984, 115\\",\\"0, 0\\",\\"ZO0629806298, ZO0467104671\\",136,136,2,2,order,sultan +9wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Garner\\",\\"Thad Garner\\",MALE,30,Garner,Garner,\\"(empty)\\",Wednesday,2,\\"thad@garner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568541,\\"sold_product_568541_14083, sold_product_568541_11234\\",\\"sold_product_568541_14083, sold_product_568541_11234\\",\\"75, 42\\",\\"75, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"35.25, 21.828\\",\\"75, 42\\",\\"14,083, 11,234\\",\\"Light jacket - dark blue, Tracksuit top - black\\",\\"Light jacket - dark blue, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0428904289, ZO0588205882\\",\\"0, 0\\",\\"75, 42\\",\\"75, 42\\",\\"0, 0\\",\\"ZO0428904289, ZO0588205882\\",117,117,2,2,order,thad +\\"-AMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Simmons\\",\\"Selena Simmons\\",FEMALE,42,Simmons,Simmons,\\"(empty)\\",Wednesday,2,\\"selena@simmons-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568586,\\"sold_product_568586_14747, sold_product_568586_15677\\",\\"sold_product_568586_14747, sold_product_568586_15677\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"16.5, 8.742\\",\\"33, 18.984\\",\\"14,747, 15,677\\",\\"Blouse - pomegranate, Across body bag - black\\",\\"Blouse - pomegranate, Across body bag - black\\",\\"1, 1\\",\\"ZO0232202322, ZO0208402084\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0232202322, ZO0208402084\\",\\"51.969\\",\\"51.969\\",2,2,order,selena +\\"-QMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Carr\\",\\"Gwen Carr\\",FEMALE,26,Carr,Carr,\\"(empty)\\",Wednesday,2,\\"gwen@carr-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Champion Arts, (empty)\\",\\"Champion Arts, (empty)\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568636,\\"sold_product_568636_17497, sold_product_568636_11982\\",\\"sold_product_568636_17497, sold_product_568636_11982\\",\\"42, 50\\",\\"42, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, (empty)\\",\\"Champion Arts, (empty)\\",\\"23.094, 22.5\\",\\"42, 50\\",\\"17,497, 11,982\\",\\"Winter jacket - navy, Blazer - white\\",\\"Winter jacket - navy, Blazer - white\\",\\"1, 1\\",\\"ZO0503905039, ZO0631806318\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0503905039, ZO0631806318\\",92,92,2,2,order,gwen +\\"-gMtOW0BH63Xcmy46HLV\\",ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Rice\\",\\"Diane Rice\\",FEMALE,22,Rice,Rice,\\"(empty)\\",Wednesday,2,\\"diane@rice-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 25, 2019 @ 00:00:00.000\\",568674,\\"sold_product_568674_16704, sold_product_568674_16971\\",\\"sold_product_568674_16704, sold_product_568674_16971\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 14, 2016 @ 00:00:00.000, Dec 14, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.711, 13.922\\",\\"10.992, 28.984\\",\\"16,704, 16,971\\",\\"Scarf - black/white, High heeled sandals - black\\",\\"Scarf - black/white, High heeled sandals - black\\",\\"1, 1\\",\\"ZO0192301923, ZO0011400114\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0192301923, ZO0011400114\\",\\"39.969\\",\\"39.969\\",2,2,order,diane +NwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Lambert\\",\\"Mostafa Lambert\\",MALE,9,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"mostafa@lambert-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567868,\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"sold_product_567868_15827, sold_product_567868_6221\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"9.867, 15.07\\",\\"20.984, 28.984\\",\\"15,827, 6,221\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"Belt - black/brown, Shirt - dark blue\\",\\"1, 1\\",\\"ZO0310403104, ZO0416604166\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0310403104, ZO0416604166\\",\\"49.969\\",\\"49.969\\",2,2,order,mostafa +SgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Selena,Selena,\\"Selena Lewis\\",\\"Selena Lewis\\",FEMALE,42,Lewis,Lewis,\\"(empty)\\",Tuesday,1,\\"selena@lewis-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567446,\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"sold_product_567446_12751, sold_product_567446_12494\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"31.844, 11.25\\",\\"65, 24.984\\",\\"12,751, 12,494\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"Lace-ups - black, Classic heels - cognac/beige\\",\\"1, 1\\",\\"ZO0322803228, ZO0002700027\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0322803228, ZO0002700027\\",90,90,2,2,order,selena +bwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Martin\\",\\"Oliver Martin\\",MALE,7,Martin,Martin,\\"(empty)\\",Tuesday,1,\\"oliver@martin-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567340,\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"sold_product_567340_3840, sold_product_567340_14835\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"7.82, 21.406\\",\\"16.984, 42\\",\\"3,840, 14,835\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"Sports shirt - dark grey multicolor, High-top trainers - grey\\",\\"1, 1\\",\\"ZO0615606156, ZO0514905149\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0615606156, ZO0514905149\\",\\"58.969\\",\\"58.969\\",2,2,order,oliver +5AMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Salazar\\",\\"Kamal Salazar\\",MALE,39,Salazar,Salazar,\\"(empty)\\",Tuesday,1,\\"kamal@salazar-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567736,\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"sold_product_567736_24718, sold_product_567736_24306\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spritechnologies\\",\\"Spherecords, Spritechnologies\\",\\"6.109, 36.75\\",\\"11.992, 75\\",\\"24,718, 24,306\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"Pyjama bottoms - light grey multicolor, Waterproof trousers - scarlet\\",\\"1, 1\\",\\"ZO0663706637, ZO0620906209\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0663706637, ZO0620906209\\",87,87,2,2,order,kamal +EQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Fleming\\",\\"Kamal Fleming\\",MALE,39,Fleming,Fleming,\\"(empty)\\",Tuesday,1,\\"kamal@fleming-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567755,\\"sold_product_567755_16941, sold_product_567755_1820\\",\\"sold_product_567755_16941, sold_product_567755_1820\\",\\"16.984, 75\\",\\"16.984, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"8.492, 36.75\\",\\"16.984, 75\\",\\"16,941, 1,820\\",\\"Vibrant Pattern Polo, Smart slip-ons - oro\\",\\"Vibrant Pattern Polo, Smart slip-ons - oro\\",\\"1, 1\\",\\"ZO0571405714, ZO0255402554\\",\\"0, 0\\",\\"16.984, 75\\",\\"16.984, 75\\",\\"0, 0\\",\\"ZO0571405714, ZO0255402554\\",92,92,2,2,order,kamal +OQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Meyer\\",\\"Sultan Al Meyer\\",MALE,19,Meyer,Meyer,\\"(empty)\\",Tuesday,1,\\"sultan al@meyer-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence, Microlutions\\",\\"Low Tide Media, Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",715455,\\"sold_product_715455_11902, sold_product_715455_19957, sold_product_715455_17361, sold_product_715455_12368\\",\\"sold_product_715455_11902, sold_product_715455_19957, sold_product_715455_17361, sold_product_715455_12368\\",\\"13.992, 7.988, 28.984, 33\\",\\"13.992, 7.988, 28.984, 33\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Elitelligence, Microlutions\\",\\"Low Tide Media, Elitelligence, Elitelligence, Microlutions\\",\\"7.551, 4.07, 14.211, 17.156\\",\\"13.992, 7.988, 28.984, 33\\",\\"11,902, 19,957, 17,361, 12,368\\",\\"3 PACK - Shorts - black, 3 PACK - Socks - black/grey/orange, Sweatshirt - multicoloured, Shirt - dark green\\",\\"3 PACK - Shorts - black, 3 PACK - Socks - black/grey/orange, Sweatshirt - multicoloured, Shirt - dark green\\",\\"1, 1, 1, 1\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\",\\"0, 0, 0, 0\\",\\"13.992, 7.988, 28.984, 33\\",\\"13.992, 7.988, 28.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0477504775, ZO0613206132, ZO0585405854, ZO0110701107\\",\\"83.938\\",\\"83.938\\",4,4,order,sultan +ggMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Holland\\",\\"Clarice Holland\\",FEMALE,18,Holland,Holland,\\"(empty)\\",Tuesday,1,\\"clarice@holland-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566768,\\"sold_product_566768_12004, sold_product_566768_23314\\",\\"sold_product_566768_12004, sold_product_566768_23314\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"8.656, 25.984\\",\\"16.984, 50\\",\\"12,004, 23,314\\",\\"Zelda - Long sleeved top - black, A-line skirt - navy blazer\\",\\"Zelda - Long sleeved top - black, A-line skirt - navy blazer\\",\\"1, 1\\",\\"ZO0217702177, ZO0331703317\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0217702177, ZO0331703317\\",67,67,2,2,order,clarice +gwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Boone\\",\\"Pia Boone\\",FEMALE,45,Boone,Boone,\\"(empty)\\",Tuesday,1,\\"pia@boone-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",566812,\\"sold_product_566812_19012, sold_product_566812_5941\\",\\"sold_product_566812_19012, sold_product_566812_5941\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"9.453, 41.656\\",\\"20.984, 85\\",\\"19,012, 5,941\\",\\"Vest - black/rose, Boots - tan\\",\\"Vest - black/rose, Boots - tan\\",\\"1, 1\\",\\"ZO0266902669, ZO0244202442\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0266902669, ZO0244202442\\",106,106,2,2,order,pia +jgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Underwood\\",\\"Mostafa Underwood\\",MALE,9,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"mostafa@underwood-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566680,\\"sold_product_566680_15413, sold_product_566680_16394\\",\\"sold_product_566680_15413, sold_product_566680_16394\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"16.172, 20.156\\",\\"33, 42\\",\\"15,413, 16,394\\",\\"Laptop bag - brown, Lace-ups - black\\",\\"Laptop bag - brown, Lace-ups - black\\",\\"1, 1\\",\\"ZO0316703167, ZO0393303933\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0316703167, ZO0393303933\\",75,75,2,2,order,mostafa +jwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Larson\\",\\"Yasmine Larson\\",FEMALE,43,Larson,Larson,\\"(empty)\\",Tuesday,1,\\"yasmine@larson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566944,\\"sold_product_566944_13250, sold_product_566944_13079\\",\\"sold_product_566944_13250, sold_product_566944_13079\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"13.742, 8.828\\",\\"24.984, 16.984\\",\\"13,250, 13,079\\",\\"Jumper - black/white, Print T-shirt - black\\",\\"Jumper - black/white, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0497004970, ZO0054900549\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0497004970, ZO0054900549\\",\\"41.969\\",\\"41.969\\",2,2,order,yasmine +kAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Palmer\\",\\"Clarice Palmer\\",FEMALE,18,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"clarice@palmer-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566979,\\"sold_product_566979_19260, sold_product_566979_21565\\",\\"sold_product_566979_19260, sold_product_566979_21565\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"17.156, 5.281\\",\\"33, 10.992\\",\\"19,260, 21,565\\",\\"Cardigan - grey, Print T-shirt - dark grey multicolor\\",\\"Cardigan - grey, Print T-shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0071900719, ZO0493404934\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0071900719, ZO0493404934\\",\\"43.969\\",\\"43.969\\",2,2,order,clarice +kQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Duncan\\",\\"Fitzgerald Duncan\\",MALE,11,Duncan,Duncan,\\"(empty)\\",Tuesday,1,\\"fitzgerald@duncan-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566734,\\"sold_product_566734_17263, sold_product_566734_13452\\",\\"sold_product_566734_17263, sold_product_566734_13452\\",\\"75, 42\\",\\"75, 42\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.5, 20.578\\",\\"75, 42\\",\\"17,263, 13,452\\",\\"Lace-up boots - cognac, Weekend bag - black\\",\\"Lace-up boots - cognac, Weekend bag - black\\",\\"1, 1\\",\\"ZO0691006910, ZO0314203142\\",\\"0, 0\\",\\"75, 42\\",\\"75, 42\\",\\"0, 0\\",\\"ZO0691006910, ZO0314203142\\",117,117,2,2,order,fuzzy +kgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Howell\\",\\"Abdulraheem Al Howell\\",MALE,33,Howell,Howell,\\"(empty)\\",Tuesday,1,\\"abdulraheem al@howell-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567094,\\"sold_product_567094_12311, sold_product_567094_12182\\",\\"sold_product_567094_12311, sold_product_567094_12182\\",\\"16.984, 12.992\\",\\"16.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"8.656, 7.141\\",\\"16.984, 12.992\\",\\"12,311, 12,182\\",\\"Polo shirt - white, Swimming shorts - black\\",\\"Polo shirt - white, Swimming shorts - black\\",\\"1, 1\\",\\"ZO0442904429, ZO0629706297\\",\\"0, 0\\",\\"16.984, 12.992\\",\\"16.984, 12.992\\",\\"0, 0\\",\\"ZO0442904429, ZO0629706297\\",\\"29.984\\",\\"29.984\\",2,2,order,abdulraheem +kwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie King\\",\\"Eddie King\\",MALE,38,King,King,\\"(empty)\\",Tuesday,1,\\"eddie@king-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566892,\\"sold_product_566892_21978, sold_product_566892_14543\\",\\"sold_product_566892_21978, sold_product_566892_14543\\",\\"24.984, 17.984\\",\\"24.984, 17.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.492, 8.992\\",\\"24.984, 17.984\\",\\"21,978, 14,543\\",\\"Hoodie - dark blue, Jumper - black\\",\\"Hoodie - dark blue, Jumper - black\\",\\"1, 1\\",\\"ZO0589505895, ZO0575405754\\",\\"0, 0\\",\\"24.984, 17.984\\",\\"24.984, 17.984\\",\\"0, 0\\",\\"ZO0589505895, ZO0575405754\\",\\"42.969\\",\\"42.969\\",2,2,order,eddie +tQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Morgan\\",\\"Sultan Al Morgan\\",MALE,19,Morgan,Morgan,\\"(empty)\\",Tuesday,1,\\"sultan al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567950,\\"sold_product_567950_24164, sold_product_567950_11096\\",\\"sold_product_567950_24164, sold_product_567950_11096\\",\\"110, 42\\",\\"110, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"52.813, 20.156\\",\\"110, 42\\",\\"24,164, 11,096\\",\\"Suit - dark blue, Bomber Jacket - black\\",\\"Suit - dark blue, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0273002730, ZO0541105411\\",\\"0, 0\\",\\"110, 42\\",\\"110, 42\\",\\"0, 0\\",\\"ZO0273002730, ZO0541105411\\",152,152,2,2,order,sultan +uAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Rose\\",\\"Sultan Al Rose\\",MALE,19,Rose,Rose,\\"(empty)\\",Tuesday,1,\\"sultan al@rose-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566826,\\"sold_product_566826_15908, sold_product_566826_13927\\",\\"sold_product_566826_15908, sold_product_566826_13927\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.172, 21.406\\",\\"16.984, 42\\",\\"15,908, 13,927\\",\\"Jumper - camel, Bomber Jacket - khaki\\",\\"Jumper - camel, Bomber Jacket - khaki\\",\\"1, 1\\",\\"ZO0575305753, ZO0540605406\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0575305753, ZO0540605406\\",\\"58.969\\",\\"58.969\\",2,2,order,sultan +fQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Franklin\\",\\"Fitzgerald Franklin\\",MALE,11,Franklin,Franklin,\\"(empty)\\",Tuesday,1,\\"fitzgerald@franklin-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567240,\\"sold_product_567240_23744, sold_product_567240_2098\\",\\"sold_product_567240_23744, sold_product_567240_2098\\",\\"31.984, 80\\",\\"31.984, 80\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"15.68, 41.594\\",\\"31.984, 80\\",\\"23,744, 2,098\\",\\"Chinos - dark blue, Lace-up boots - black\\",\\"Chinos - dark blue, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0421004210, ZO0689006890\\",\\"0, 0\\",\\"31.984, 80\\",\\"31.984, 80\\",\\"0, 0\\",\\"ZO0421004210, ZO0689006890\\",112,112,2,2,order,fuzzy +fgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Byrd\\",\\"Mostafa Byrd\\",MALE,9,Byrd,Byrd,\\"(empty)\\",Tuesday,1,\\"mostafa@byrd-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567290,\\"sold_product_567290_24934, sold_product_567290_15288\\",\\"sold_product_567290_24934, sold_product_567290_15288\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"22.5, 11.211\\",\\"50, 21.984\\",\\"24,934, 15,288\\",\\"Lace-up boots - resin coffee, Polo shirt - grey\\",\\"Lace-up boots - resin coffee, Polo shirt - grey\\",\\"1, 1\\",\\"ZO0403504035, ZO0442704427\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0442704427\\",72,72,2,2,order,mostafa +kAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,rania,rania,\\"rania Goodwin\\",\\"rania Goodwin\\",FEMALE,24,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"rania@goodwin-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567669,\\"sold_product_567669_22893, sold_product_567669_17796\\",\\"sold_product_567669_22893, sold_product_567669_17796\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"8.156, 9.344\\",\\"16.984, 16.984\\",\\"22,893, 17,796\\",\\"A-line skirt - dark purple, Across body bag - black \\",\\"A-line skirt - dark purple, Across body bag - black \\",\\"1, 1\\",\\"ZO0148301483, ZO0202902029\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0148301483, ZO0202902029\\",\\"33.969\\",\\"33.969\\",2,2,order,rani +rgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Simpson\\",\\"Gwen Simpson\\",FEMALE,26,Simpson,Simpson,\\"(empty)\\",Tuesday,1,\\"gwen@simpson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567365,\\"sold_product_567365_11663, sold_product_567365_24272\\",\\"sold_product_567365_11663, sold_product_567365_24272\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"5.879, 18.125\\",\\"11.992, 37\\",\\"11,663, 24,272\\",\\"Slip-ons - white, Shirt - white\\",\\"Slip-ons - white, Shirt - white\\",\\"1, 1\\",\\"ZO0008600086, ZO0266002660\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0008600086, ZO0266002660\\",\\"48.969\\",\\"48.969\\",2,2,order,gwen +1AMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Sanders\\",\\"George Sanders\\",MALE,32,Sanders,Sanders,\\"(empty)\\",Tuesday,1,\\"george@sanders-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",566845,\\"sold_product_566845_24161, sold_product_566845_13674\\",\\"sold_product_566845_24161, sold_product_566845_13674\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"3.92, 12.25\\",\\"7.988, 24.984\\",\\"24,161, 13,674\\",\\"Basic T-shirt - white, Hoodie - black\\",\\"Basic T-shirt - white, Hoodie - black\\",\\"1, 1\\",\\"ZO0547905479, ZO0583305833\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0547905479, ZO0583305833\\",\\"32.969\\",\\"32.969\\",2,2,order,george +1QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Fletcher\\",\\"Jim Fletcher\\",MALE,41,Fletcher,Fletcher,\\"(empty)\\",Tuesday,1,\\"jim@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567048,\\"sold_product_567048_19089, sold_product_567048_20261\\",\\"sold_product_567048_19089, sold_product_567048_20261\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.012, 5.52\\",\\"12.992, 11.992\\",\\"19,089, 20,261\\",\\"Vest - white/dark blue, Vest - black\\",\\"Vest - white/dark blue, Vest - black\\",\\"1, 1\\",\\"ZO0566905669, ZO0564005640\\",\\"0, 0\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"0, 0\\",\\"ZO0566905669, ZO0564005640\\",\\"24.984\\",\\"24.984\\",2,2,order,jim +EQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hudson\\",\\"Yasmine Hudson\\",FEMALE,43,Hudson,Hudson,\\"(empty)\\",Tuesday,1,\\"yasmine@hudson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Pyramidustries active, Spherecords\\",\\"Pyramidustries active, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567281,\\"sold_product_567281_14758, sold_product_567281_23174\\",\\"sold_product_567281_14758, sold_product_567281_23174\\",\\"13.992, 22.984\\",\\"13.992, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Spherecords\\",\\"Pyramidustries active, Spherecords\\",\\"7.27, 12.18\\",\\"13.992, 22.984\\",\\"14,758, 23,174\\",\\"Print T-shirt - black, Chinos - dark blue\\",\\"Print T-shirt - black, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0221402214, ZO0632806328\\",\\"0, 0\\",\\"13.992, 22.984\\",\\"13.992, 22.984\\",\\"0, 0\\",\\"ZO0221402214, ZO0632806328\\",\\"36.969\\",\\"36.969\\",2,2,order,yasmine +FAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Chapman\\",\\"rania Chapman\\",FEMALE,24,Chapman,Chapman,\\"(empty)\\",Tuesday,1,\\"rania@chapman-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567119,\\"sold_product_567119_22695, sold_product_567119_23515\\",\\"sold_product_567119_22695, sold_product_567119_23515\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Gnomehouse\\",\\"Spherecords Curvy, Gnomehouse\\",\\"7.82, 27.594\\",\\"16.984, 60\\",\\"22,695, 23,515\\",\\"Cardigan - grey multicolor/black, Blazer - black/white\\",\\"Cardigan - grey multicolor/black, Blazer - black/white\\",\\"1, 1\\",\\"ZO0711507115, ZO0350903509\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0711507115, ZO0350903509\\",77,77,2,2,order,rani +FQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Harper\\",\\"Samir Harper\\",MALE,34,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"samir@harper-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567169,\\"sold_product_567169_20800, sold_product_567169_18749\\",\\"sold_product_567169_20800, sold_product_567169_18749\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"5.602, 9.344\\",\\"10.992, 16.984\\",\\"20,800, 18,749\\",\\"Print T-shirt - white, Sports shorts - black\\",\\"Print T-shirt - white, Sports shorts - black\\",\\"1, 1\\",\\"ZO0558805588, ZO0622206222\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0558805588, ZO0622206222\\",\\"27.984\\",\\"27.984\\",2,2,order,samir +KAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Underwood\\",\\"Abd Underwood\\",MALE,52,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"abd@underwood-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567869,\\"sold_product_567869_14147, sold_product_567869_16719\\",\\"sold_product_567869_14147, sold_product_567869_16719\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.656, 8.328\\",\\"16.984, 16.984\\",\\"14,147, 16,719\\",\\"Print T-shirt - black/green, Polo shirt - blue multicolor\\",\\"Print T-shirt - black/green, Polo shirt - blue multicolor\\",\\"1, 1\\",\\"ZO0565105651, ZO0443804438\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0565105651, ZO0443804438\\",\\"33.969\\",\\"33.969\\",2,2,order,abd +KQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Strickland\\",\\"Muniz Strickland\\",MALE,37,Strickland,Strickland,\\"(empty)\\",Tuesday,1,\\"muniz@strickland-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567909,\\"sold_product_567909_24768, sold_product_567909_11414\\",\\"sold_product_567909_24768, sold_product_567909_11414\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.25, 8.93\\",\\"24.984, 18.984\\",\\"24,768, 11,414\\",\\"SET - Gloves - dark grey multicolor, Sweatshirt - light blue\\",\\"SET - Gloves - dark grey multicolor, Sweatshirt - light blue\\",\\"1, 1\\",\\"ZO0609606096, ZO0588905889\\",\\"0, 0\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"0, 0\\",\\"ZO0609606096, ZO0588905889\\",\\"43.969\\",\\"43.969\\",2,2,order,muniz +eQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Stokes\\",\\"Betty Stokes\\",FEMALE,44,Stokes,Stokes,\\"(empty)\\",Tuesday,1,\\"betty@stokes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567524,\\"sold_product_567524_14033, sold_product_567524_24564\\",\\"sold_product_567524_14033, sold_product_567524_24564\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"10.906, 35.094\\",\\"20.984, 65\\",\\"14,033, 24,564\\",\\"Clutch - black , Ankle boots - cognac\\",\\"Clutch - black , Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0096300963, ZO0377403774\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0096300963, ZO0377403774\\",86,86,2,2,order,betty +egMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Turner\\",\\"Elyssa Turner\\",FEMALE,27,Turner,Turner,\\"(empty)\\",Tuesday,1,\\"elyssa@turner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567565,\\"sold_product_567565_4684, sold_product_567565_18489\\",\\"sold_product_567565_4684, sold_product_567565_18489\\",\\"50, 60\\",\\"50, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"23.5, 33\\",\\"50, 60\\",\\"4,684, 18,489\\",\\"Boots - black, Slip-ons - Midnight Blue\\",\\"Boots - black, Slip-ons - Midnight Blue\\",\\"1, 1\\",\\"ZO0015600156, ZO0323603236\\",\\"0, 0\\",\\"50, 60\\",\\"50, 60\\",\\"0, 0\\",\\"ZO0015600156, ZO0323603236\\",110,110,2,2,order,elyssa +nQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Powell\\",\\"Sonya Powell\\",FEMALE,28,Powell,Powell,\\"(empty)\\",Tuesday,1,\\"sonya@powell-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567019,\\"sold_product_567019_14411, sold_product_567019_24149\\",\\"sold_product_567019_14411, sold_product_567019_24149\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"13.344, 10.344\\",\\"28.984, 21.984\\",\\"14,411, 24,149\\",\\"Summer dress - black, Rucksack - black\\",\\"Summer dress - black, Rucksack - black\\",\\"1, 1\\",\\"ZO0151301513, ZO0204902049\\",\\"0, 0\\",\\"28.984, 21.984\\",\\"28.984, 21.984\\",\\"0, 0\\",\\"ZO0151301513, ZO0204902049\\",\\"50.969\\",\\"50.969\\",2,2,order,sonya +ngMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Massey\\",\\"Pia Massey\\",FEMALE,45,Massey,Massey,\\"(empty)\\",Tuesday,1,\\"pia@massey-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567069,\\"sold_product_567069_22261, sold_product_567069_16325\\",\\"sold_product_567069_22261, sold_product_567069_16325\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"22.5, 17.156\\",\\"50, 33\\",\\"22,261, 16,325\\",\\"Winter jacket - bordeaux, Summer dress - black\\",\\"Winter jacket - bordeaux, Summer dress - black\\",\\"1, 1\\",\\"ZO0503805038, ZO0047500475\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0503805038, ZO0047500475\\",83,83,2,2,order,pia +qAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Lamb\\",\\"Frances Lamb\\",FEMALE,49,Lamb,Lamb,\\"(empty)\\",Tuesday,1,\\"frances@lamb-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567935,\\"sold_product_567935_13174, sold_product_567935_14395\\",\\"sold_product_567935_13174, sold_product_567935_14395\\",\\"14.992, 24.984\\",\\"14.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"7.789, 12.25\\",\\"14.992, 24.984\\",\\"13,174, 14,395\\",\\"Print T-shirt - bright white, Jumper - offwhite\\",\\"Print T-shirt - bright white, Jumper - offwhite\\",\\"1, 1\\",\\"ZO0116101161, ZO0574305743\\",\\"0, 0\\",\\"14.992, 24.984\\",\\"14.992, 24.984\\",\\"0, 0\\",\\"ZO0116101161, ZO0574305743\\",\\"39.969\\",\\"39.969\\",2,2,order,frances +qwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Jackson\\",\\"Betty Jackson\\",FEMALE,44,Jackson,Jackson,\\"(empty)\\",Tuesday,1,\\"betty@jackson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566831,\\"sold_product_566831_22424, sold_product_566831_17957\\",\\"sold_product_566831_22424, sold_product_566831_17957\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"23.5, 5.5\\",\\"50, 10.992\\",\\"22,424, 17,957\\",\\"Jersey dress - chinese red, Long sleeved top - black\\",\\"Jersey dress - chinese red, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0341103411, ZO0648406484\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0341103411, ZO0648406484\\",\\"60.969\\",\\"60.969\\",2,2,order,betty +5AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Sharp\\",\\"Marwan Sharp\\",MALE,51,Sharp,Sharp,\\"(empty)\\",Tuesday,1,\\"marwan@sharp-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567543,\\"sold_product_567543_14075, sold_product_567543_20484\\",\\"sold_product_567543_14075, sold_product_567543_20484\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"12.742, 9.867\\",\\"24.984, 20.984\\",\\"14,075, 20,484\\",\\"Rucksack - black, Jumper - dark grey\\",\\"Rucksack - black, Jumper - dark grey\\",\\"1, 1\\",\\"ZO0608106081, ZO0296502965\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0608106081, ZO0296502965\\",\\"45.969\\",\\"45.969\\",2,2,order,marwan +5QMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Tran\\",\\"Gwen Tran\\",FEMALE,26,Tran,Tran,\\"(empty)\\",Tuesday,1,\\"gwen@tran-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567598,\\"sold_product_567598_11254, sold_product_567598_11666\\",\\"sold_product_567598_11254, sold_product_567598_11666\\",\\"29.984, 75\\",\\"29.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"14.398, 41.25\\",\\"29.984, 75\\",\\"11,254, 11,666\\",\\"Jersey dress - black, Boots - blue\\",\\"Jersey dress - black, Boots - blue\\",\\"1, 1\\",\\"ZO0039400394, ZO0672906729\\",\\"0, 0\\",\\"29.984, 75\\",\\"29.984, 75\\",\\"0, 0\\",\\"ZO0039400394, ZO0672906729\\",105,105,2,2,order,gwen +PwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Lloyd\\",\\"Wilhemina St. Lloyd\\",FEMALE,17,Lloyd,Lloyd,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@lloyd-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567876,\\"sold_product_567876_21798, sold_product_567876_24299\\",\\"sold_product_567876_21798, sold_product_567876_24299\\",\\"14.992, 42\\",\\"14.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"7.789, 19.313\\",\\"14.992, 42\\",\\"21,798, 24,299\\",\\"Jersey dress - black, Summer dress - black\\",\\"Jersey dress - black, Summer dress - black\\",\\"1, 1\\",\\"ZO0705707057, ZO0047700477\\",\\"0, 0\\",\\"14.992, 42\\",\\"14.992, 42\\",\\"0, 0\\",\\"ZO0705707057, ZO0047700477\\",\\"56.969\\",\\"56.969\\",2,2,order,wilhemina +UwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Jacobs\\",\\"Stephanie Jacobs\\",FEMALE,6,Jacobs,Jacobs,\\"(empty)\\",Tuesday,1,\\"stephanie@jacobs-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567684,\\"sold_product_567684_13627, sold_product_567684_21755\\",\\"sold_product_567684_13627, sold_product_567684_21755\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9, 9.453\\",\\"16.984, 20.984\\",\\"13,627, 21,755\\",\\"Across body bag - black , Pencil skirt - black\\",\\"Across body bag - black , Pencil skirt - black\\",\\"1, 1\\",\\"ZO0201202012, ZO0035000350\\",\\"0, 0\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"0, 0\\",\\"ZO0201202012, ZO0035000350\\",\\"37.969\\",\\"37.969\\",2,2,order,stephanie +aAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Smith\\",\\"Oliver Smith\\",MALE,7,Smith,Smith,\\"(empty)\\",Tuesday,1,\\"oliver@smith-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567790,\\"sold_product_567790_13490, sold_product_567790_22013\\",\\"sold_product_567790_13490, sold_product_567790_22013\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.602, 29.406\\",\\"10.992, 60\\",\\"13,490, 22,013\\",\\"T-bar sandals - black/green, Boots - black\\",\\"T-bar sandals - black/green, Boots - black\\",\\"1, 1\\",\\"ZO0522405224, ZO0405104051\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0522405224, ZO0405104051\\",71,71,2,2,order,oliver +rAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,George,George,\\"George Hubbard\\",\\"George Hubbard\\",MALE,32,Hubbard,Hubbard,\\"(empty)\\",Tuesday,1,\\"george@hubbard-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567465,\\"sold_product_567465_19025, sold_product_567465_1753\\",\\"sold_product_567465_19025, sold_product_567465_1753\\",\\"65, 65\\",\\"65, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"31.844, 30.547\\",\\"65, 65\\",\\"19,025, 1,753\\",\\"Suit jacket - black, Boots - dark blue\\",\\"Suit jacket - black, Boots - dark blue\\",\\"1, 1\\",\\"ZO0274502745, ZO0686006860\\",\\"0, 0\\",\\"65, 65\\",\\"65, 65\\",\\"0, 0\\",\\"ZO0274502745, ZO0686006860\\",130,130,2,2,order,george +zwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Phil,Phil,\\"Phil Alvarez\\",\\"Phil Alvarez\\",MALE,50,Alvarez,Alvarez,\\"(empty)\\",Tuesday,1,\\"phil@alvarez-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567256,\\"sold_product_567256_24717, sold_product_567256_23939\\",\\"sold_product_567256_24717, sold_product_567256_23939\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"7.789, 24.5\\",\\"14.992, 50\\",\\"24,717, 23,939\\",\\"Belt - dark brown , Weekend bag - black\\",\\"Belt - dark brown , Weekend bag - black\\",\\"1, 1\\",\\"ZO0461004610, ZO0702707027\\",\\"0, 0\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"0, 0\\",\\"ZO0461004610, ZO0702707027\\",65,65,2,2,order,phil +CwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jackson,Jackson,\\"Jackson Bryant\\",\\"Jackson Bryant\\",MALE,13,Bryant,Bryant,\\"(empty)\\",Tuesday,1,\\"jackson@bryant-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media, Spritechnologies\\",\\"Elitelligence, Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",716462,\\"sold_product_716462_13612, sold_product_716462_21781, sold_product_716462_17754, sold_product_716462_17020\\",\\"sold_product_716462_13612, sold_product_716462_21781, sold_product_716462_17754, sold_product_716462_17020\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Low Tide Media, Elitelligence, Spritechnologies\\",\\"Elitelligence, Low Tide Media, Elitelligence, Spritechnologies\\",\\"6.469, 10.289, 5.059, 10.078\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"13,612, 21,781, 17,754, 17,020\\",\\"Basic T-shirt - light red/white, Sweatshirt - mottled light grey, Wallet - cognac/black, Sports shirt - grey multicolor\\",\\"Basic T-shirt - light red/white, Sweatshirt - mottled light grey, Wallet - cognac/black, Sports shirt - grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\",\\"0, 0, 0, 0\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"11.992, 20.984, 10.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0549505495, ZO0458504585, ZO0602506025, ZO0617506175\\",\\"64.938\\",\\"64.938\\",4,4,order,jackson +GQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Elliott\\",\\"Abigail Elliott\\",FEMALE,46,Elliott,Elliott,\\"(empty)\\",Tuesday,1,\\"abigail@elliott-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Angeldale, Spherecords Maternity\\",\\"Angeldale, Spherecords Maternity\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566775,\\"sold_product_566775_7253, sold_product_566775_25143\\",\\"sold_product_566775_7253, sold_product_566775_25143\\",\\"110, 16.984\\",\\"110, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Maternity\\",\\"Angeldale, Spherecords Maternity\\",\\"53.906, 7.988\\",\\"110, 16.984\\",\\"7,253, 25,143\\",\\"Over-the-knee boots - bison, Long sleeved top - mid grey multicolor\\",\\"Over-the-knee boots - bison, Long sleeved top - mid grey multicolor\\",\\"1, 1\\",\\"ZO0671006710, ZO0708007080\\",\\"0, 0\\",\\"110, 16.984\\",\\"110, 16.984\\",\\"0, 0\\",\\"ZO0671006710, ZO0708007080\\",127,127,2,2,order,abigail +IQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Mccarthy\\",\\"Jason Mccarthy\\",MALE,16,Mccarthy,Mccarthy,\\"(empty)\\",Tuesday,1,\\"jason@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567926,\\"sold_product_567926_22732, sold_product_567926_11389\\",\\"sold_product_567926_22732, sold_product_567926_11389\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"16.172, 3.6\\",\\"33, 7.988\\",\\"22,732, 11,389\\",\\"Relaxed fit jeans - black denim, Basic T-shirt - green\\",\\"Relaxed fit jeans - black denim, Basic T-shirt - green\\",\\"1, 1\\",\\"ZO0113301133, ZO0562105621\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0113301133, ZO0562105621\\",\\"40.969\\",\\"40.969\\",2,2,order,jason +JAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Miller\\",\\"Elyssa Miller\\",FEMALE,27,Miller,Miller,\\"(empty)\\",Tuesday,1,\\"elyssa@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566829,\\"sold_product_566829_21605, sold_product_566829_17889\\",\\"sold_product_566829_21605, sold_product_566829_17889\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"Tigress Enterprises, Gnomehouse mom\\",\\"12.25, 15.07\\",\\"24.984, 28.984\\",\\"21,605, 17,889\\",\\"Pyjama top - navy, Blouse - black\\",\\"Pyjama top - navy, Blouse - black\\",\\"1, 1\\",\\"ZO0100901009, ZO0235102351\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0100901009, ZO0235102351\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +RAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Fleming\\",\\"Muniz Fleming\\",MALE,37,Fleming,Fleming,\\"(empty)\\",Tuesday,1,\\"muniz@fleming-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567666,\\"sold_product_567666_17099, sold_product_567666_2908\\",\\"sold_product_567666_17099, sold_product_567666_2908\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.242, 14.781\\",\\"24.984, 28.984\\",\\"17,099, 2,908\\",\\"Watch - black, Chinos - beige \\",\\"Watch - black, Chinos - beige \\",\\"1, 1\\",\\"ZO0311403114, ZO0282002820\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0311403114, ZO0282002820\\",\\"53.969\\",\\"53.969\\",2,2,order,muniz +kgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Austin\\",\\"Pia Austin\\",FEMALE,45,Austin,Austin,\\"(empty)\\",Tuesday,1,\\"pia@austin-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567383,\\"sold_product_567383_16258, sold_product_567383_15314\\",\\"sold_product_567383_16258, sold_product_567383_15314\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"5.059, 20.578\\",\\"10.992, 42\\",\\"16,258, 15,314\\",\\"Print T-shirt - light grey/white, A-line skirt - navy blazer\\",\\"Print T-shirt - light grey/white, A-line skirt - navy blazer\\",\\"1, 1\\",\\"ZO0647406474, ZO0330703307\\",\\"0, 0\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"0, 0\\",\\"ZO0647406474, ZO0330703307\\",\\"52.969\\",\\"52.969\\",2,2,order,pia +ugMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Greene\\",\\"Abd Greene\\",MALE,52,Greene,Greene,\\"(empty)\\",Tuesday,1,\\"abd@greene-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567381,\\"sold_product_567381_13005, sold_product_567381_18590\\",\\"sold_product_567381_13005, sold_product_567381_18590\\",\\"22.984, 42\\",\\"22.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.352, 19.313\\",\\"22.984, 42\\",\\"13,005, 18,590\\",\\"Shirt - grey, Light jacket - mottled light grey\\",\\"Shirt - grey, Light jacket - mottled light grey\\",\\"1, 1\\",\\"ZO0278402784, ZO0458304583\\",\\"0, 0\\",\\"22.984, 42\\",\\"22.984, 42\\",\\"0, 0\\",\\"ZO0278402784, ZO0458304583\\",65,65,2,2,order,abd +zwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Simpson\\",\\"Jackson Simpson\\",MALE,13,Simpson,Simpson,\\"(empty)\\",Tuesday,1,\\"jackson@simpson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567437,\\"sold_product_567437_16571, sold_product_567437_11872\\",\\"sold_product_567437_16571, sold_product_567437_11872\\",\\"65, 7.988\\",\\"65, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"35.094, 3.68\\",\\"65, 7.988\\",\\"16,571, 11,872\\",\\"Suit jacket - black, Basic T-shirt - light red multicolor\\",\\"Suit jacket - black, Basic T-shirt - light red multicolor\\",\\"1, 1\\",\\"ZO0275902759, ZO0545005450\\",\\"0, 0\\",\\"65, 7.988\\",\\"65, 7.988\\",\\"0, 0\\",\\"ZO0275902759, ZO0545005450\\",73,73,2,2,order,jackson +CwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Gomez\\",\\"Irwin Gomez\\",MALE,14,Gomez,Gomez,\\"(empty)\\",Tuesday,1,\\"irwin@gomez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567324,\\"sold_product_567324_15839, sold_product_567324_11429\\",\\"sold_product_567324_15839, sold_product_567324_11429\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"16.813, 5.391\\",\\"33, 10.992\\",\\"15,839, 11,429\\",\\"Slim fit jeans - sand , Swimming shorts - lime punch\\",\\"Slim fit jeans - sand , Swimming shorts - lime punch\\",\\"1, 1\\",\\"ZO0426604266, ZO0629406294\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0426604266, ZO0629406294\\",\\"43.969\\",\\"43.969\\",2,2,order,irwin +QwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Hubbard\\",\\"Yuri Hubbard\\",MALE,21,Hubbard,Hubbard,\\"(empty)\\",Tuesday,1,\\"yuri@hubbard-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567504,\\"sold_product_567504_18713, sold_product_567504_23235\\",\\"sold_product_567504_18713, sold_product_567504_23235\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 13.242\\",\\"24.984, 24.984\\",\\"18,713, 23,235\\",\\"Rucksack - navy/Blue Violety, Shirt - grey/black\\",\\"Rucksack - navy/Blue Violety, Shirt - grey/black\\",\\"1, 1\\",\\"ZO0606506065, ZO0277702777\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0606506065, ZO0277702777\\",\\"49.969\\",\\"49.969\\",2,2,order,yuri +RAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Gregory\\",\\"Selena Gregory\\",FEMALE,42,Gregory,Gregory,\\"(empty)\\",Tuesday,1,\\"selena@gregory-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567623,\\"sold_product_567623_14283, sold_product_567623_22330\\",\\"sold_product_567623_14283, sold_product_567623_22330\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"32.375, 5.52\\",\\"60, 11.992\\",\\"14,283, 22,330\\",\\"Lace-ups - nude, Long sleeved top - off white/navy\\",\\"Lace-ups - nude, Long sleeved top - off white/navy\\",\\"1, 1\\",\\"ZO0239802398, ZO0645406454\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0239802398, ZO0645406454\\",72,72,2,2,order,selena +RwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Rios\\",\\"Abd Rios\\",MALE,52,Rios,Rios,\\"(empty)\\",Tuesday,1,\\"abd@rios-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567400,\\"sold_product_567400_13372, sold_product_567400_7092\\",\\"sold_product_567400_13372, sold_product_567400_7092\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.75, 23.094\\",\\"24.984, 42\\",\\"13,372, 7,092\\",\\"Rucksack - navy/cognac , Tracksuit top - oliv\\",\\"Rucksack - navy/cognac , Tracksuit top - oliv\\",\\"1, 1\\",\\"ZO0605606056, ZO0588105881\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0605606056, ZO0588105881\\",67,67,2,2,order,abd +TwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Garner\\",\\"Yasmine Garner\\",FEMALE,43,Garner,Garner,\\"(empty)\\",Tuesday,1,\\"yasmine@garner-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",566757,\\"sold_product_566757_16685, sold_product_566757_20906\\",\\"sold_product_566757_16685, sold_product_566757_20906\\",\\"18.984, 11.992\\",\\"18.984, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"9.492, 6.23\\",\\"18.984, 11.992\\",\\"16,685, 20,906\\",\\"Across body bag - black, Print T-shirt - white\\",\\"Across body bag - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0196201962, ZO0168601686\\",\\"0, 0\\",\\"18.984, 11.992\\",\\"18.984, 11.992\\",\\"0, 0\\",\\"ZO0196201962, ZO0168601686\\",\\"30.984\\",\\"30.984\\",2,2,order,yasmine +UAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Gregory\\",\\"Brigitte Gregory\\",FEMALE,12,Gregory,Gregory,\\"(empty)\\",Tuesday,1,\\"brigitte@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566884,\\"sold_product_566884_23198, sold_product_566884_5945\\",\\"sold_product_566884_23198, sold_product_566884_5945\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"10.492, 11.5\\",\\"20.984, 24.984\\",\\"23,198, 5,945\\",\\"Jersey dress - black, Ankle boots - black\\",\\"Jersey dress - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0490204902, ZO0025000250\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0490204902, ZO0025000250\\",\\"45.969\\",\\"45.969\\",2,2,order,brigitte +pwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Brewer\\",\\"Abigail Brewer\\",FEMALE,46,Brewer,Brewer,\\"(empty)\\",Tuesday,1,\\"abigail@brewer-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567815,\\"sold_product_567815_24802, sold_product_567815_7476\\",\\"sold_product_567815_24802, sold_product_567815_7476\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"8.328, 32.375\\",\\"16.984, 60\\",\\"24,802, 7,476\\",\\"Print T-shirt - red, Slip-ons - Wheat\\",\\"Print T-shirt - red, Slip-ons - Wheat\\",\\"1, 1\\",\\"ZO0263602636, ZO0241002410\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0263602636, ZO0241002410\\",77,77,2,2,order,abigail +GwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Massey\\",\\"Wilhemina St. Massey\\",FEMALE,17,Massey,Massey,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@massey-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567177,\\"sold_product_567177_12365, sold_product_567177_23200\\",\\"sold_product_567177_12365, sold_product_567177_23200\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"15.492, 12.25\\",\\"30.984, 24.984\\",\\"12,365, 23,200\\",\\"Rucksack - grey , Bomber Jacket - black\\",\\"Rucksack - grey , Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0197301973, ZO0180401804\\",\\"0, 0\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"0, 0\\",\\"ZO0197301973, ZO0180401804\\",\\"55.969\\",\\"55.969\\",2,2,order,wilhemina +lwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Lambert\\",\\"Elyssa Lambert\\",FEMALE,27,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"elyssa@lambert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",733060,\\"sold_product_733060_13851, sold_product_733060_7400, sold_product_733060_20106, sold_product_733060_5045\\",\\"sold_product_733060_13851, sold_product_733060_7400, sold_product_733060_20106, sold_product_733060_5045\\",\\"20.984, 50, 50, 60\\",\\"20.984, 50, 50, 60\\",\\"Women's Clothing, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Women's Clothing, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"Pyramidustries, Tigress Enterprises, Oceanavigations, Low Tide Media\\",\\"10.492, 23.5, 22.5, 30.594\\",\\"20.984, 50, 50, 60\\",\\"13,851, 7,400, 20,106, 5,045\\",\\"Summer dress - black, Lace-up boots - black, Ballet pumps - bronze, Boots - black\\",\\"Summer dress - black, Lace-up boots - black, Ballet pumps - bronze, Boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\",\\"0, 0, 0, 0\\",\\"20.984, 50, 50, 60\\",\\"20.984, 50, 50, 60\\",\\"0, 0, 0, 0\\",\\"ZO0155601556, ZO0013600136, ZO0235702357, ZO0383203832\\",181,181,4,4,order,elyssa +zgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Rose\\",\\"Selena Rose\\",FEMALE,42,Rose,Rose,\\"(empty)\\",Tuesday,1,\\"selena@rose-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567486,\\"sold_product_567486_19378, sold_product_567486_21859\\",\\"sold_product_567486_19378, sold_product_567486_21859\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"13.492, 20.156\\",\\"24.984, 42\\",\\"19,378, 21,859\\",\\"Long sleeved top - winternude, Wedge sandals - black\\",\\"Long sleeved top - winternude, Wedge sandals - black\\",\\"1, 1\\",\\"ZO0058200582, ZO0365503655\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0058200582, ZO0365503655\\",67,67,2,2,order,selena +zwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Goodwin\\",\\"Abigail Goodwin\\",FEMALE,46,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"abigail@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Gnomehouse,Gnomehouse,\\"Jun 24, 2019 @ 00:00:00.000\\",567625,\\"sold_product_567625_21570, sold_product_567625_16910\\",\\"sold_product_567625_21570, sold_product_567625_16910\\",\\"55, 42\\",\\"55, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"28.047, 19.734\\",\\"55, 42\\",\\"21,570, 16,910\\",\\"A-line skirt - flame scarlet, Pleated skirt - black\\",\\"A-line skirt - flame scarlet, Pleated skirt - black\\",\\"1, 1\\",\\"ZO0328603286, ZO0328803288\\",\\"0, 0\\",\\"55, 42\\",\\"55, 42\\",\\"0, 0\\",\\"ZO0328603286, ZO0328803288\\",97,97,2,2,order,abigail +2gMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Recip,Recip,\\"Recip Brock\\",\\"Recip Brock\\",MALE,10,Brock,Brock,\\"(empty)\\",Tuesday,1,\\"recip@brock-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567224,\\"sold_product_567224_16809, sold_product_567224_18808\\",\\"sold_product_567224_16809, sold_product_567224_18808\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"14.211, 10.078\\",\\"28.984, 20.984\\",\\"16,809, 18,808\\",\\"Rucksack - black, Rucksack - black/cognac\\",\\"Rucksack - black, Rucksack - black/cognac\\",\\"1, 1\\",\\"ZO0128501285, ZO0606306063\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0128501285, ZO0606306063\\",\\"49.969\\",\\"49.969\\",2,2,order,recip +2wMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Kim\\",\\"Diane Kim\\",FEMALE,22,Kim,Kim,\\"(empty)\\",Tuesday,1,\\"diane@kim-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries active\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567252,\\"sold_product_567252_16632, sold_product_567252_16333\\",\\"sold_product_567252_16632, sold_product_567252_16333\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries active\\",\\"19.313, 12\\",\\"42, 24.984\\",\\"16,632, 16,333\\",\\"Slip-ons - mud, Long sleeved top - black \\",\\"Slip-ons - mud, Long sleeved top - black \\",\\"1, 1\\",\\"ZO0369803698, ZO0220502205\\",\\"0, 0\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"0, 0\\",\\"ZO0369803698, ZO0220502205\\",67,67,2,2,order,diane +\\"-AMtOW0BH63Xcmy45GjD\\",ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Bowers\\",\\"Thad Bowers\\",MALE,30,Bowers,Bowers,\\"(empty)\\",Tuesday,1,\\"thad@bowers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567735,\\"sold_product_567735_14414, sold_product_567735_20047\\",\\"sold_product_567735_14414, sold_product_567735_20047\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"4.148, 11.5\\",\\"7.988, 24.984\\",\\"14,414, 20,047\\",\\"3 PACK - Socks - black/white, Slip-ons - navy\\",\\"3 PACK - Socks - black/white, Slip-ons - navy\\",\\"1, 1\\",\\"ZO0129701297, ZO0518705187\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0129701297, ZO0518705187\\",\\"32.969\\",\\"32.969\\",2,2,order,thad +BQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Rice\\",\\"Diane Rice\\",FEMALE,22,Rice,Rice,\\"(empty)\\",Tuesday,1,\\"diane@rice-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567822,\\"sold_product_567822_5501, sold_product_567822_25039\\",\\"sold_product_567822_5501, sold_product_567822_25039\\",\\"75, 33\\",\\"75, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"40.5, 17.813\\",\\"75, 33\\",\\"5,501, 25,039\\",\\"Ankle boots - Midnight Blue, Shirt - Lemon Chiffon\\",\\"Ankle boots - Midnight Blue, Shirt - Lemon Chiffon\\",\\"1, 1\\",\\"ZO0244802448, ZO0346303463\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0244802448, ZO0346303463\\",108,108,2,2,order,diane +BgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Baker\\",\\"Youssef Baker\\",MALE,31,Baker,Baker,\\"(empty)\\",Tuesday,1,\\"youssef@baker-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567852,\\"sold_product_567852_12928, sold_product_567852_11153\\",\\"sold_product_567852_12928, sold_product_567852_11153\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.656, 5.172\\",\\"20.984, 10.992\\",\\"12,928, 11,153\\",\\"Shirt - black /grey, Cap - black/black\\",\\"Shirt - black /grey, Cap - black/black\\",\\"1, 1\\",\\"ZO0523805238, ZO0596505965\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0523805238, ZO0596505965\\",\\"31.984\\",\\"31.984\\",2,2,order,youssef +JwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Hicham,Hicham,\\"Hicham Carpenter\\",\\"Hicham Carpenter\\",MALE,8,Carpenter,Carpenter,\\"(empty)\\",Tuesday,1,\\"hicham@carpenter-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566861,\\"sold_product_566861_1978, sold_product_566861_11748\\",\\"sold_product_566861_1978, sold_product_566861_11748\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"27.484, 8.328\\",\\"50, 16.984\\",\\"1,978, 11,748\\",\\"Lace-up boots - black, Wallet - grey\\",\\"Lace-up boots - black, Wallet - grey\\",\\"1, 1\\",\\"ZO0520305203, ZO0462204622\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0520305203, ZO0462204622\\",67,67,2,2,order,hicham +KAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Reyes\\",\\"Gwen Reyes\\",FEMALE,26,Reyes,Reyes,\\"(empty)\\",Tuesday,1,\\"gwen@reyes-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567042,\\"sold_product_567042_23822, sold_product_567042_11786\\",\\"sold_product_567042_23822, sold_product_567042_11786\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"32.375, 11.117\\",\\"60, 20.984\\",\\"23,822, 11,786\\",\\"Sandals - Midnight Blue, Print T-shirt - black\\",\\"Sandals - Midnight Blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0243002430, ZO0103901039\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0243002430, ZO0103901039\\",81,81,2,2,order,gwen +SAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Cook\\",\\"Elyssa Cook\\",FEMALE,27,Cook,Cook,\\"(empty)\\",Tuesday,1,\\"elyssa@cook-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Gnomehouse, Tigress Enterprises\\",\\"Pyramidustries, Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",731037,\\"sold_product_731037_17669, sold_product_731037_9413, sold_product_731037_8035, sold_product_731037_24229\\",\\"sold_product_731037_17669, sold_product_731037_9413, sold_product_731037_8035, sold_product_731037_24229\\",\\"13.992, 50, 13.992, 29.984\\",\\"13.992, 50, 13.992, 29.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Gnomehouse, Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Gnomehouse, Pyramidustries, Tigress Enterprises\\",\\"6.441, 22.5, 7, 15.289\\",\\"13.992, 50, 13.992, 29.984\\",\\"17,669, 9,413, 8,035, 24,229\\",\\"Pencil skirt - black, Summer dress - Pale Violet Red, Jersey dress - black, Trousers - black\\",\\"Pencil skirt - black, Summer dress - Pale Violet Red, Jersey dress - black, Trousers - black\\",\\"1, 1, 1, 1\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\",\\"0, 0, 0, 0\\",\\"13.992, 50, 13.992, 29.984\\",\\"13.992, 50, 13.992, 29.984\\",\\"0, 0, 0, 0\\",\\"ZO0148801488, ZO0335003350, ZO0155301553, ZO0074300743\\",\\"107.938\\",\\"107.938\\",4,4,order,elyssa +gQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Morgan\\",\\"Sultan Al Morgan\\",MALE,19,Morgan,Morgan,\\"(empty)\\",Tuesday,1,\\"sultan al@morgan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567729,\\"sold_product_567729_1196, sold_product_567729_13331\\",\\"sold_product_567729_1196, sold_product_567729_13331\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"20.156, 9.656\\",\\"42, 20.984\\",\\"1,196, 13,331\\",\\"Trainers - white, Jumper - black\\",\\"Trainers - white, Jumper - black\\",\\"1, 1\\",\\"ZO0395103951, ZO0296102961\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0395103951, ZO0296102961\\",\\"62.969\\",\\"62.969\\",2,2,order,sultan +iQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Carpenter\\",\\"Jim Carpenter\\",MALE,41,Carpenter,Carpenter,\\"(empty)\\",Tuesday,1,\\"jim@carpenter-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567384,\\"sold_product_567384_22462, sold_product_567384_21856\\",\\"sold_product_567384_22462, sold_product_567384_21856\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"14.852, 12.742\\",\\"33, 24.984\\",\\"22,462, 21,856\\",\\"Slim fit jeans - dark grey , Pyjama set - grey\\",\\"Slim fit jeans - dark grey , Pyjama set - grey\\",\\"1, 1\\",\\"ZO0426704267, ZO0612006120\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0426704267, ZO0612006120\\",\\"57.969\\",\\"57.969\\",2,2,order,jim +kwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Goodman\\",\\"Fitzgerald Goodman\\",MALE,11,Goodman,Goodman,\\"(empty)\\",Tuesday,1,\\"fitzgerald@goodman-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566690,\\"sold_product_566690_11851, sold_product_566690_18257\\",\\"sold_product_566690_11851, sold_product_566690_18257\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"13.922, 7.051\\",\\"28.984, 14.992\\",\\"11,851, 18,257\\",\\"Jumper - dark blue, Print T-shirt - black\\",\\"Jumper - dark blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0449004490, ZO0118501185\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0449004490, ZO0118501185\\",\\"43.969\\",\\"43.969\\",2,2,order,fuzzy +lAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Frances,Frances,\\"Frances Mullins\\",\\"Frances Mullins\\",FEMALE,49,Mullins,Mullins,\\"(empty)\\",Tuesday,1,\\"frances@mullins-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566951,\\"sold_product_566951_2269, sold_product_566951_14250\\",\\"sold_product_566951_2269, sold_product_566951_14250\\",\\"50, 33\\",\\"50, 33\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23, 15.508\\",\\"50, 33\\",\\"2,269, 14,250\\",\\"Boots - Slate Gray, High-top trainers - grey\\",\\"Boots - Slate Gray, High-top trainers - grey\\",\\"1, 1\\",\\"ZO0406604066, ZO0517405174\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0406604066, ZO0517405174\\",83,83,2,2,order,frances +lQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Washington\\",\\"Diane Washington\\",FEMALE,22,Washington,Washington,\\"(empty)\\",Tuesday,1,\\"diane@washington-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566982,\\"sold_product_566982_13852, sold_product_566982_21858\\",\\"sold_product_566982_13852, sold_product_566982_21858\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.648, 8.156\\",\\"16.984, 16.984\\",\\"13,852, 21,858\\",\\"A-line skirt - black/white, Nightie - off white\\",\\"A-line skirt - black/white, Nightie - off white\\",\\"1, 1\\",\\"ZO0149301493, ZO0099800998\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0149301493, ZO0099800998\\",\\"33.969\\",\\"33.969\\",2,2,order,diane +lgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Bailey\\",\\"Phil Bailey\\",MALE,50,Bailey,Bailey,\\"(empty)\\",Tuesday,1,\\"phil@bailey-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566725,\\"sold_product_566725_17721, sold_product_566725_19679\\",\\"sold_product_566725_17721, sold_product_566725_19679\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"7.988, 15.648\\",\\"16.984, 28.984\\",\\"17,721, 19,679\\",\\"Polo shirt - light grey multicolor, Hoodie - black/dark blue/white\\",\\"Polo shirt - light grey multicolor, Hoodie - black/dark blue/white\\",\\"1, 1\\",\\"ZO0444404444, ZO0584205842\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0444404444, ZO0584205842\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +wgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Fletcher\\",\\"Yasmine Fletcher\\",FEMALE,43,Fletcher,Fletcher,\\"(empty)\\",Tuesday,1,\\"yasmine@fletcher-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566856,\\"sold_product_566856_10829, sold_product_566856_25007\\",\\"sold_product_566856_10829, sold_product_566856_25007\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"15.07, 26.484\\",\\"28.984, 50\\",\\"10,829, 25,007\\",\\"Sports shoes - black/pink, Jumpsuit - Pale Violet Red\\",\\"Sports shoes - black/pink, Jumpsuit - Pale Violet Red\\",\\"1, 1\\",\\"ZO0216502165, ZO0327503275\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0216502165, ZO0327503275\\",79,79,2,2,order,yasmine +wwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Moss\\",\\"Selena Moss\\",FEMALE,42,Moss,Moss,\\"(empty)\\",Tuesday,1,\\"selena@moss-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567039,\\"sold_product_567039_16085, sold_product_567039_16220\\",\\"sold_product_567039_16085, sold_product_567039_16220\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"11.75, 7.789\\",\\"24.984, 14.992\\",\\"16,085, 16,220\\",\\"Jeans Skinny Fit - dark blue denim, Vest - white\\",\\"Jeans Skinny Fit - dark blue denim, Vest - white\\",\\"1, 1\\",\\"ZO0184101841, ZO0711207112\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0184101841, ZO0711207112\\",\\"39.969\\",\\"39.969\\",2,2,order,selena +xAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Greene\\",\\"Wilhemina St. Greene\\",FEMALE,17,Greene,Greene,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@greene-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567068,\\"sold_product_567068_13637, sold_product_567068_21700\\",\\"sold_product_567068_13637, sold_product_567068_21700\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"Tigress Enterprises, Spherecords Curvy\\",\\"13.633, 7.051\\",\\"28.984, 14.992\\",\\"13,637, 21,700\\",\\"Jersey dress - multicolor, Basic T-shirt - black\\",\\"Jersey dress - multicolor, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0038000380, ZO0711007110\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0038000380, ZO0711007110\\",\\"43.969\\",\\"43.969\\",2,2,order,wilhemina +0wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Cunningham\\",\\"Rabbia Al Cunningham\\",FEMALE,5,Cunningham,Cunningham,\\"(empty)\\",Tuesday,1,\\"rabbia al@cunningham-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Angeldale, Oceanavigations\\",\\"Pyramidustries, Angeldale, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",732229,\\"sold_product_732229_21857, sold_product_732229_23802, sold_product_732229_12401, sold_product_732229_21229\\",\\"sold_product_732229_21857, sold_product_732229_23802, sold_product_732229_12401, sold_product_732229_21229\\",\\"20.984, 20.984, 65, 80\\",\\"20.984, 20.984, 65, 80\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Pyramidustries, Angeldale, Oceanavigations\\",\\"Pyramidustries, Pyramidustries, Angeldale, Oceanavigations\\",\\"10.078, 11.539, 31.203, 40.781\\",\\"20.984, 20.984, 65, 80\\",\\"21,857, 23,802, 12,401, 21,229\\",\\"Cardigan - black/white, Long sleeved top - off white, Handbag - black, Boots - navy\\",\\"Cardigan - black/white, Long sleeved top - off white, Handbag - black, Boots - navy\\",\\"1, 1, 1, 1\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 65, 80\\",\\"20.984, 20.984, 65, 80\\",\\"0, 0, 0, 0\\",\\"ZO0175701757, ZO0163801638, ZO0697506975, ZO0245602456\\",187,187,4,4,order,rabbia +1AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ball\\",\\"Rabbia Al Ball\\",FEMALE,5,Ball,Ball,\\"(empty)\\",Tuesday,1,\\"rabbia al@ball-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Tigress Enterprises, Angeldale\\",\\"Spherecords, Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724806,\\"sold_product_724806_13062, sold_product_724806_12709, sold_product_724806_19614, sold_product_724806_21000\\",\\"sold_product_724806_13062, sold_product_724806_12709, sold_product_724806_19614, sold_product_724806_21000\\",\\"11.992, 28.984, 60, 20.984\\",\\"11.992, 28.984, 60, 20.984\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Tigress Enterprises, Angeldale, Spherecords\\",\\"Spherecords, Tigress Enterprises, Angeldale, Spherecords\\",\\"6.23, 14.781, 27, 11.539\\",\\"11.992, 28.984, 60, 20.984\\",\\"13,062, 12,709, 19,614, 21,000\\",\\"Long sleeved top - dark green, Pleated skirt - Blue Violety, Tote bag - terracotta, Shirt - light blue\\",\\"Long sleeved top - dark green, Pleated skirt - Blue Violety, Tote bag - terracotta, Shirt - light blue\\",\\"1, 1, 1, 1\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\",\\"0, 0, 0, 0\\",\\"11.992, 28.984, 60, 20.984\\",\\"11.992, 28.984, 60, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0643106431, ZO0033300333, ZO0696206962, ZO0651206512\\",\\"121.938\\",\\"121.938\\",4,4,order,rabbia +8QMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Graham\\",\\"Abd Graham\\",MALE,52,Graham,Graham,\\"(empty)\\",Tuesday,1,\\"abd@graham-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567769,\\"sold_product_567769_24888, sold_product_567769_16104\\",\\"sold_product_567769_24888, sold_product_567769_16104\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"14.211, 9.117\\",\\"28.984, 18.984\\",\\"24,888, 16,104\\",\\"Formal shirt - blue, Swimming shorts - blue atol\\",\\"Formal shirt - blue, Swimming shorts - blue atol\\",\\"1, 1\\",\\"ZO0414004140, ZO0630106301\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0414004140, ZO0630106301\\",\\"47.969\\",\\"47.969\\",2,2,order,abd +AgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Potter\\",\\"Abigail Potter\\",FEMALE,46,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"abigail@potter-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566772,\\"sold_product_566772_17102, sold_product_566772_7361\\",\\"sold_product_566772_17102, sold_product_566772_7361\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"10.703, 13.633\\",\\"20.984, 28.984\\",\\"17,102, 7,361\\",\\"Jersey dress - black/white, Ankle boots - black\\",\\"Jersey dress - black/white, Ankle boots - black\\",\\"1, 1\\",\\"ZO0152901529, ZO0019100191\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0152901529, ZO0019100191\\",\\"49.969\\",\\"49.969\\",2,2,order,abigail +2gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Palmer\\",\\"Kamal Palmer\\",MALE,39,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"kamal@palmer-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567318,\\"sold_product_567318_16500, sold_product_567318_1539\\",\\"sold_product_567318_16500, sold_product_567318_1539\\",\\"33, 60\\",\\"33, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"16.813, 30\\",\\"33, 60\\",\\"16,500, 1,539\\",\\"Casual Cuffed Pants, Lace-up boots - black\\",\\"Casual Cuffed Pants, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0421104211, ZO0256202562\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0421104211, ZO0256202562\\",93,93,2,2,order,kamal +OQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Potter\\",\\"Stephanie Potter\\",FEMALE,6,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"stephanie@potter-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567615,\\"sold_product_567615_21067, sold_product_567615_16863\\",\\"sold_product_567615_21067, sold_product_567615_16863\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"25.484, 13.922\\",\\"50, 28.984\\",\\"21,067, 16,863\\",\\"Lace-up boots - brown, Bomber Jacket - black\\",\\"Lace-up boots - brown, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0013500135, ZO0174501745\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0013500135, ZO0174501745\\",79,79,2,2,order,stephanie +QgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Weber\\",\\"Muniz Weber\\",MALE,37,Weber,Weber,\\"(empty)\\",Tuesday,1,\\"muniz@weber-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567316,\\"sold_product_567316_13588, sold_product_567316_24014\\",\\"sold_product_567316_13588, sold_product_567316_24014\\",\\"60, 50\\",\\"60, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"28.797, 24.5\\",\\"60, 50\\",\\"13,588, 24,014\\",\\"Lace-ups - cognac, Boots - saphire\\",\\"Lace-ups - cognac, Boots - saphire\\",\\"1, 1\\",\\"ZO0390403904, ZO0403004030\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0390403904, ZO0403004030\\",110,110,2,2,order,muniz +RQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Mary,Mary,\\"Mary Kelley\\",\\"Mary Kelley\\",FEMALE,20,Kelley,Kelley,\\"(empty)\\",Tuesday,1,\\"mary@kelley-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566896,\\"sold_product_566896_16021, sold_product_566896_17331\\",\\"sold_product_566896_16021, sold_product_566896_17331\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"23, 10.492\\",\\"50, 20.984\\",\\"16,021, 17,331\\",\\"High heeled sandals - electric blue, Tote bag - Blue Violety\\",\\"High heeled sandals - electric blue, Tote bag - Blue Violety\\",\\"1, 1\\",\\"ZO0242702427, ZO0090000900\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0242702427, ZO0090000900\\",71,71,2,2,order,mary +WAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Henderson\\",\\"Phil Henderson\\",MALE,50,Henderson,Henderson,\\"(empty)\\",Tuesday,1,\\"phil@henderson-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567418,\\"sold_product_567418_22276, sold_product_567418_18190\\",\\"sold_product_567418_22276, sold_product_567418_18190\\",\\"75, 110\\",\\"75, 110\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"36.75, 58.281\\",\\"75, 110\\",\\"22,276, 18,190\\",\\"Lace-up boots - cognac, Ski jacket - bright white\\",\\"Lace-up boots - cognac, Ski jacket - bright white\\",\\"1, 1\\",\\"ZO0400404004, ZO0625006250\\",\\"0, 0\\",\\"75, 110\\",\\"75, 110\\",\\"0, 0\\",\\"ZO0400404004, ZO0625006250\\",185,185,2,2,order,phil +WQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Duncan\\",\\"Selena Duncan\\",FEMALE,42,Duncan,Duncan,\\"(empty)\\",Tuesday,1,\\"selena@duncan-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Spherecords Curvy\\",\\"Spherecords, Spherecords Curvy\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567462,\\"sold_product_567462_9295, sold_product_567462_18220\\",\\"sold_product_567462_9295, sold_product_567462_18220\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords Curvy\\",\\"Spherecords, Spherecords Curvy\\",\\"3.6, 8.656\\",\\"7.988, 16.984\\",\\"9,295, 18,220\\",\\"Print T-shirt - dark grey/white, Jersey dress - dark blue\\",\\"Print T-shirt - dark grey/white, Jersey dress - dark blue\\",\\"1, 1\\",\\"ZO0644406444, ZO0709307093\\",\\"0, 0\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"0, 0\\",\\"ZO0644406444, ZO0709307093\\",\\"24.984\\",\\"24.984\\",2,2,order,selena +XwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Perkins\\",\\"George Perkins\\",MALE,32,Perkins,Perkins,\\"(empty)\\",Tuesday,1,\\"george@perkins-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Oceanavigations,Oceanavigations,\\"Jun 24, 2019 @ 00:00:00.000\\",567667,\\"sold_product_567667_22878, sold_product_567667_19733\\",\\"sold_product_567667_22878, sold_product_567667_19733\\",\\"75, 33\\",\\"75, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"34.5, 16.813\\",\\"75, 33\\",\\"22,878, 19,733\\",\\"Suit jacket - dark blue, Sweatshirt - black\\",\\"Suit jacket - dark blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0273802738, ZO0300303003\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0273802738, ZO0300303003\\",108,108,2,2,order,george +YAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Carr\\",\\"Elyssa Carr\\",FEMALE,27,Carr,Carr,\\"(empty)\\",Tuesday,1,\\"elyssa@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567703,\\"sold_product_567703_11574, sold_product_567703_16709\\",\\"sold_product_567703_11574, sold_product_567703_16709\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"19.313, 21.828\\",\\"42, 42\\",\\"11,574, 16,709\\",\\"Maxi dress - multicolor, Lace-up boots - Amethyst\\",\\"Maxi dress - multicolor, Lace-up boots - Amethyst\\",\\"1, 1\\",\\"ZO0037900379, ZO0134901349\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0037900379, ZO0134901349\\",84,84,2,2,order,elyssa +iwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Powell\\",\\"Gwen Powell\\",FEMALE,26,Powell,Powell,\\"(empty)\\",Tuesday,1,\\"gwen@powell-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567260,\\"sold_product_567260_9302, sold_product_567260_7402\\",\\"sold_product_567260_9302, sold_product_567260_7402\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"16.172, 34.5\\",\\"33, 75\\",\\"9,302, 7,402\\",\\"Cardigan - red, Ankle boots - black \\",\\"Cardigan - red, Ankle boots - black \\",\\"1, 1\\",\\"ZO0068100681, ZO0674106741\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0068100681, ZO0674106741\\",108,108,2,2,order,gwen +jAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Washington\\",\\"Rabbia Al Washington\\",FEMALE,5,Washington,Washington,\\"(empty)\\",Tuesday,1,\\"rabbia al@washington-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724844,\\"sold_product_724844_19797, sold_product_724844_13322, sold_product_724844_10099, sold_product_724844_8107\\",\\"sold_product_724844_19797, sold_product_724844_13322, sold_product_724844_10099, sold_product_724844_8107\\",\\"20.984, 65, 20.984, 33\\",\\"20.984, 65, 20.984, 33\\",\\"Women's Clothing, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"Spherecords Maternity, Oceanavigations, Pyramidustries active, Gnomehouse\\",\\"10.703, 33.781, 9.453, 17.484\\",\\"20.984, 65, 20.984, 33\\",\\"19,797, 13,322, 10,099, 8,107\\",\\"Shirt - white, High heeled ankle boots - black, Sweatshirt - black, Blouse - off-white\\",\\"Shirt - white, High heeled ankle boots - black, Sweatshirt - black, Blouse - off-white\\",\\"1, 1, 1, 1\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\",\\"0, 0, 0, 0\\",\\"20.984, 65, 20.984, 33\\",\\"20.984, 65, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0707507075, ZO0246402464, ZO0226802268, ZO0343503435\\",140,140,4,4,order,rabbia +qAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Chapman\\",\\"Pia Chapman\\",FEMALE,45,Chapman,Chapman,\\"(empty)\\",Tuesday,1,\\"pia@chapman-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567308,\\"sold_product_567308_16474, sold_product_567308_18779\\",\\"sold_product_567308_16474, sold_product_567308_18779\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9.344, 15.648\\",\\"16.984, 28.984\\",\\"16,474, 18,779\\",\\"Sweatshirt - grey multicolor, High heeled sandals - silver\\",\\"Sweatshirt - grey multicolor, High heeled sandals - silver\\",\\"1, 1\\",\\"ZO0181601816, ZO0011000110\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0181601816, ZO0011000110\\",\\"45.969\\",\\"45.969\\",2,2,order,pia +7gMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Morrison\\",\\"Abd Morrison\\",MALE,52,Morrison,Morrison,\\"(empty)\\",Tuesday,1,\\"abd@morrison-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567404,\\"sold_product_567404_22845, sold_product_567404_21489\\",\\"sold_product_567404_22845, sold_product_567404_21489\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"25.984, 13.633\\",\\"50, 28.984\\",\\"22,845, 21,489\\",\\"High-top trainers - red, Jeans Tapered Fit - blue denim\\",\\"High-top trainers - red, Jeans Tapered Fit - blue denim\\",\\"1, 1\\",\\"ZO0107101071, ZO0537905379\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0107101071, ZO0537905379\\",79,79,2,2,order,abd +PgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Hopkins\\",\\"Youssef Hopkins\\",MALE,31,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"youssef@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567538,\\"sold_product_567538_16200, sold_product_567538_17404\\",\\"sold_product_567538_16200, sold_product_567538_17404\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 27.594\\",\\"10.992, 60\\",\\"16,200, 17,404\\",\\"Hat - grey, Colorful Cardigan\\",\\"Hat - grey, Colorful Cardigan\\",\\"1, 1\\",\\"ZO0596905969, ZO0450804508\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0596905969, ZO0450804508\\",71,71,2,2,order,youssef +PwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Abigail,Abigail,\\"Abigail Perry\\",\\"Abigail Perry\\",FEMALE,46,Perry,Perry,\\"(empty)\\",Tuesday,1,\\"abigail@perry-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567593,\\"sold_product_567593_25072, sold_product_567593_17024\\",\\"sold_product_567593_25072, sold_product_567593_17024\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"8.93, 12.992\\",\\"18.984, 24.984\\",\\"25,072, 17,024\\",\\"Jumper - off white, Across body bag - black\\",\\"Jumper - off white, Across body bag - black\\",\\"1, 1\\",\\"ZO0655306553, ZO0208902089\\",\\"0, 0\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"0, 0\\",\\"ZO0655306553, ZO0208902089\\",\\"43.969\\",\\"43.969\\",2,2,order,abigail +fQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Williams\\",\\"Wagdi Williams\\",MALE,15,Williams,Williams,\\"(empty)\\",Tuesday,1,\\"wagdi@williams-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567294,\\"sold_product_567294_21723, sold_product_567294_20325\\",\\"sold_product_567294_21723, sold_product_567294_20325\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"12.992, 10.078\\",\\"24.984, 20.984\\",\\"21,723, 20,325\\",\\"SET - Hat - Medium Slate Blue, Sweatshirt - dark blue\\",\\"SET - Hat - Medium Slate Blue, Sweatshirt - dark blue\\",\\"1, 1\\",\\"ZO0317403174, ZO0457204572\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0317403174, ZO0457204572\\",\\"45.969\\",\\"45.969\\",2,2,order,wagdi +kQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Underwood\\",\\"Wilhemina St. Underwood\\",FEMALE,17,Underwood,Underwood,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@underwood-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Jun 24, 2019 @ 00:00:00.000\\",728256,\\"sold_product_728256_17123, sold_product_728256_19925, sold_product_728256_23613, sold_product_728256_17666\\",\\"sold_product_728256_17123, sold_product_728256_19925, sold_product_728256_23613, sold_product_728256_17666\\",\\"42, 33, 33, 37\\",\\"42, 33, 33, 37\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Low Tide Media, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"22.672, 15.18, 17.156, 19.234\\",\\"42, 33, 33, 37\\",\\"17,123, 19,925, 23,613, 17,666\\",\\"Sandals - black, Jumper - Lemon Chiffon, Platform sandals - black, Summer dress - peacoat\\",\\"Sandals - black, Jumper - Lemon Chiffon, Platform sandals - black, Summer dress - peacoat\\",\\"1, 1, 1, 1\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\",\\"0, 0, 0, 0\\",\\"42, 33, 33, 37\\",\\"42, 33, 33, 37\\",\\"0, 0, 0, 0\\",\\"ZO0371903719, ZO0352803528, ZO0137501375, ZO0229202292\\",145,145,4,4,order,wilhemina +wgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Miller\\",\\"Thad Miller\\",MALE,30,Miller,Miller,\\"(empty)\\",Tuesday,1,\\"thad@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567544,\\"sold_product_567544_18963, sold_product_567544_19459\\",\\"sold_product_567544_18963, sold_product_567544_19459\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"10.078, 7.988\\",\\"20.984, 16.984\\",\\"18,963, 19,459\\",\\"Sweatshirt - white, Long sleeved top - Dark Salmon\\",\\"Sweatshirt - white, Long sleeved top - Dark Salmon\\",\\"1, 1\\",\\"ZO0585005850, ZO0120301203\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0585005850, ZO0120301203\\",\\"37.969\\",\\"37.969\\",2,2,order,thad +wwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Stewart\\",\\"Jim Stewart\\",MALE,41,Stewart,Stewart,\\"(empty)\\",Tuesday,1,\\"jim@stewart-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567592,\\"sold_product_567592_2843, sold_product_567592_16403\\",\\"sold_product_567592_2843, sold_product_567592_16403\\",\\"28.984, 200\\",\\"28.984, 200\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"13.344, 98\\",\\"28.984, 200\\",\\"2,843, 16,403\\",\\"Jeans Tapered Fit - washed black, Short coat - light grey\\",\\"Jeans Tapered Fit - washed black, Short coat - light grey\\",\\"1, 1\\",\\"ZO0535405354, ZO0291302913\\",\\"0, 0\\",\\"28.984, 200\\",\\"28.984, 200\\",\\"0, 0\\",\\"ZO0535405354, ZO0291302913\\",229,229,2,2,order,jim +ywMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Farmer\\",\\"Betty Farmer\\",FEMALE,44,Farmer,Farmer,\\"(empty)\\",Tuesday,1,\\"betty@farmer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566942,\\"sold_product_566942_14928, sold_product_566942_23534\\",\\"sold_product_566942_14928, sold_product_566942_23534\\",\\"11.992, 22.984\\",\\"11.992, 22.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"6, 11.719\\",\\"11.992, 22.984\\",\\"14,928, 23,534\\",\\"Scarf - red, Jumper dress - dark green\\",\\"Scarf - red, Jumper dress - dark green\\",\\"1, 1\\",\\"ZO0084000840, ZO0636606366\\",\\"0, 0\\",\\"11.992, 22.984\\",\\"11.992, 22.984\\",\\"0, 0\\",\\"ZO0084000840, ZO0636606366\\",\\"34.969\\",\\"34.969\\",2,2,order,betty +zAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Foster\\",\\"Youssef Foster\\",MALE,31,Foster,Foster,\\"(empty)\\",Tuesday,1,\\"youssef@foster-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567015,\\"sold_product_567015_22305, sold_product_567015_11284\\",\\"sold_product_567015_22305, sold_product_567015_11284\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.879, 10.078\\",\\"11.992, 20.984\\",\\"22,305, 11,284\\",\\"Print T-shirt - white, Chinos - dark blue\\",\\"Print T-shirt - white, Chinos - dark blue\\",\\"1, 1\\",\\"ZO0558605586, ZO0527805278\\",\\"0, 0\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"0, 0\\",\\"ZO0558605586, ZO0527805278\\",\\"32.969\\",\\"32.969\\",2,2,order,youssef +zQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Hopkins\\",\\"Sonya Hopkins\\",FEMALE,28,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"sonya@hopkins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",Pyramidustries,Pyramidustries,\\"Jun 24, 2019 @ 00:00:00.000\\",567081,\\"sold_product_567081_25066, sold_product_567081_13016\\",\\"sold_product_567081_25066, sold_product_567081_13016\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"7.41, 11.75\\",\\"13.992, 24.984\\",\\"25,066, 13,016\\",\\"Across body bag - red, Tote bag - cognac\\",\\"Across body bag - red, Tote bag - cognac\\",\\"1, 1\\",\\"ZO0209702097, ZO0186301863\\",\\"0, 0\\",\\"13.992, 24.984\\",\\"13.992, 24.984\\",\\"0, 0\\",\\"ZO0209702097, ZO0186301863\\",\\"38.969\\",\\"38.969\\",2,2,order,sonya +SgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Hayes\\",\\"Irwin Hayes\\",MALE,14,Hayes,Hayes,\\"(empty)\\",Tuesday,1,\\"irwin@hayes-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567475,\\"sold_product_567475_21824, sold_product_567475_23277\\",\\"sold_product_567475_21824, sold_product_567475_23277\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.906, 20.578\\",\\"20.984, 42\\",\\"21,824, 23,277\\",\\"Jumper - black, Boots - black\\",\\"Jumper - black, Boots - black\\",\\"1, 1\\",\\"ZO0578805788, ZO0520405204\\",\\"0, 0\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"0, 0\\",\\"ZO0578805788, ZO0520405204\\",\\"62.969\\",\\"62.969\\",2,2,order,irwin +SwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Adams\\",\\"Abigail Adams\\",FEMALE,46,Adams,Adams,\\"(empty)\\",Tuesday,1,\\"abigail@adams-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567631,\\"sold_product_567631_18119, sold_product_567631_5772\\",\\"sold_product_567631_18119, sold_product_567631_5772\\",\\"6.988, 65\\",\\"6.988, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"3.289, 33.781\\",\\"6.988, 65\\",\\"18,119, 5,772\\",\\"2 PACK - Socks - red/grey, Classic heels - nude\\",\\"2 PACK - Socks - red/grey, Classic heels - nude\\",\\"1, 1\\",\\"ZO0101101011, ZO0667406674\\",\\"0, 0\\",\\"6.988, 65\\",\\"6.988, 65\\",\\"0, 0\\",\\"ZO0101101011, ZO0667406674\\",72,72,2,2,order,abigail +oAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Gilbert\\",\\"Mary Gilbert\\",FEMALE,20,Gilbert,Gilbert,\\"(empty)\\",Tuesday,1,\\"mary@gilbert-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567454,\\"sold_product_567454_22330, sold_product_567454_8083\\",\\"sold_product_567454_22330, sold_product_567454_8083\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.52, 7.691\\",\\"11.992, 13.992\\",\\"22,330, 8,083\\",\\"Long sleeved top - off white/navy, Long sleeved top - light blue\\",\\"Long sleeved top - off white/navy, Long sleeved top - light blue\\",\\"1, 1\\",\\"ZO0645406454, ZO0166001660\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0645406454, ZO0166001660\\",\\"25.984\\",\\"25.984\\",2,2,order,mary +4wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Gilbert\\",\\"Sonya Gilbert\\",FEMALE,28,Gilbert,Gilbert,\\"(empty)\\",Tuesday,1,\\"sonya@gilbert-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567855,\\"sold_product_567855_12032, sold_product_567855_11434\\",\\"sold_product_567855_12032, sold_product_567855_11434\\",\\"21.984, 11.992\\",\\"21.984, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"10.781, 6.23\\",\\"21.984, 11.992\\",\\"12,032, 11,434\\",\\"Jeggings - grey denim, Snood - black\\",\\"Jeggings - grey denim, Snood - black\\",\\"1, 1\\",\\"ZO0657106571, ZO0084800848\\",\\"0, 0\\",\\"21.984, 11.992\\",\\"21.984, 11.992\\",\\"0, 0\\",\\"ZO0657106571, ZO0084800848\\",\\"33.969\\",\\"33.969\\",2,2,order,sonya +UwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Palmer\\",\\"Fitzgerald Palmer\\",MALE,11,Palmer,Palmer,\\"(empty)\\",Tuesday,1,\\"fitzgerald@palmer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567835,\\"sold_product_567835_12431, sold_product_567835_12612\\",\\"sold_product_567835_12431, sold_product_567835_12612\\",\\"24.984, 165\\",\\"24.984, 165\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"11.25, 89.063\\",\\"24.984, 165\\",\\"12,431, 12,612\\",\\"Hoodie - white, Boots - taupe\\",\\"Hoodie - white, Boots - taupe\\",\\"1, 1\\",\\"ZO0589405894, ZO0483304833\\",\\"0, 0\\",\\"24.984, 165\\",\\"24.984, 165\\",\\"0, 0\\",\\"ZO0589405894, ZO0483304833\\",190,190,2,2,order,fuzzy +VAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Stewart\\",\\"Robert Stewart\\",MALE,29,Stewart,Stewart,\\"(empty)\\",Tuesday,1,\\"robert@stewart-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567889,\\"sold_product_567889_14775, sold_product_567889_15520\\",\\"sold_product_567889_14775, sold_product_567889_15520\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"14.211, 20.156\\",\\"28.984, 42\\",\\"14,775, 15,520\\",\\"Chinos - black, Smart lace-ups - black\\",\\"Chinos - black, Smart lace-ups - black\\",\\"1, 1\\",\\"ZO0282202822, ZO0393003930\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0282202822, ZO0393003930\\",71,71,2,2,order,robert +dAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Goodwin\\",\\"Frances Goodwin\\",FEMALE,49,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"frances@goodwin-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566852,\\"sold_product_566852_1709, sold_product_566852_11513\\",\\"sold_product_566852_1709, sold_product_566852_11513\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"35.094, 10.078\\",\\"65, 20.984\\",\\"1,709, 11,513\\",\\"Boots - black, Tracksuit top - bordeaux multicolor\\",\\"Boots - black, Tracksuit top - bordeaux multicolor\\",\\"1, 1\\",\\"ZO0257002570, ZO0455404554\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0257002570, ZO0455404554\\",86,86,2,2,order,frances +dQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mccarthy\\",\\"Rabbia Al Mccarthy\\",FEMALE,5,Mccarthy,Mccarthy,\\"(empty)\\",Tuesday,1,\\"rabbia al@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567037,\\"sold_product_567037_16060, sold_product_567037_11158\\",\\"sold_product_567037_16060, sold_product_567037_11158\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"9.867, 22.672\\",\\"20.984, 42\\",\\"16,060, 11,158\\",\\"Clutch - gold, Classic heels - yellow\\",\\"Clutch - gold, Classic heels - yellow\\",\\"1, 1\\",\\"ZO0206402064, ZO0365903659\\",\\"0, 0\\",\\"20.984, 42\\",\\"20.984, 42\\",\\"0, 0\\",\\"ZO0206402064, ZO0365903659\\",\\"62.969\\",\\"62.969\\",2,2,order,rabbia +mAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Harper\\",\\"Jackson Harper\\",MALE,13,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"jackson@harper-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Elitelligence, (empty)\\",\\"Low Tide Media, Elitelligence, (empty)\\",\\"Jun 24, 2019 @ 00:00:00.000\\",721778,\\"sold_product_721778_1710, sold_product_721778_1718, sold_product_721778_12836, sold_product_721778_21677\\",\\"sold_product_721778_1710, sold_product_721778_1718, sold_product_721778_12836, sold_product_721778_21677\\",\\"65, 28.984, 165, 42\\",\\"65, 28.984, 165, 42\\",\\"Men's Shoes, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, (empty), Elitelligence\\",\\"Low Tide Media, Elitelligence, (empty), Elitelligence\\",\\"35.094, 15.359, 80.875, 22.25\\",\\"65, 28.984, 165, 42\\",\\"1,710, 1,718, 12,836, 21,677\\",\\"Boots - cognac, Lace-up boots - black, Lace-ups - brown, Light jacket - black\\",\\"Boots - cognac, Lace-up boots - black, Lace-ups - brown, Light jacket - black\\",\\"1, 1, 1, 1\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\",\\"0, 0, 0, 0\\",\\"65, 28.984, 165, 42\\",\\"65, 28.984, 165, 42\\",\\"0, 0, 0, 0\\",\\"ZO0400004000, ZO0519305193, ZO0482004820, ZO0540305403\\",301,301,4,4,order,jackson +2QMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Eddie,Eddie,\\"Eddie Foster\\",\\"Eddie Foster\\",MALE,38,Foster,Foster,\\"(empty)\\",Tuesday,1,\\"eddie@foster-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567143,\\"sold_product_567143_11605, sold_product_567143_16593\\",\\"sold_product_567143_11605, sold_product_567143_16593\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 9.453\\",\\"24.984, 20.984\\",\\"11,605, 16,593\\",\\"Jumper - navy/offwhite/black, Wallet - brown\\",\\"Jumper - navy/offwhite/black, Wallet - brown\\",\\"1, 1\\",\\"ZO0573005730, ZO0313203132\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0573005730, ZO0313203132\\",\\"45.969\\",\\"45.969\\",2,2,order,eddie +2gMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Love\\",\\"Fitzgerald Love\\",MALE,11,Love,Love,\\"(empty)\\",Tuesday,1,\\"fitzgerald@love-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567191,\\"sold_product_567191_20587, sold_product_567191_16436\\",\\"sold_product_567191_20587, sold_product_567191_16436\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"22.672, 6.578\\",\\"42, 13.992\\",\\"20,587, 16,436\\",\\"Slim fit jeans - black denim, Pyjama bottoms - blue\\",\\"Slim fit jeans - black denim, Pyjama bottoms - blue\\",\\"1, 1\\",\\"ZO0113901139, ZO0478904789\\",\\"0, 0\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"0, 0\\",\\"ZO0113901139, ZO0478904789\\",\\"55.969\\",\\"55.969\\",2,2,order,fuzzy +IQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Graves\\",\\"Wagdi Graves\\",MALE,15,Graves,Graves,\\"(empty)\\",Tuesday,1,\\"wagdi@graves-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567135,\\"sold_product_567135_24487, sold_product_567135_13221\\",\\"sold_product_567135_24487, sold_product_567135_13221\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.906, 4.309\\",\\"20.984, 7.988\\",\\"24,487, 13,221\\",\\"Chinos - grey, Print T-shirt - white/dark blue\\",\\"Chinos - grey, Print T-shirt - white/dark blue\\",\\"1, 1\\",\\"ZO0528305283, ZO0549305493\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0528305283, ZO0549305493\\",\\"28.984\\",\\"28.984\\",2,2,order,wagdi +UQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Martin\\",\\"Elyssa Martin\\",FEMALE,27,Martin,Martin,\\"(empty)\\",Tuesday,1,\\"elyssa@martin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Spherecords Curvy, Gnomehouse\\",\\"Tigress Enterprises, Spherecords Curvy, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",727730,\\"sold_product_727730_17183, sold_product_727730_23436, sold_product_727730_25006, sold_product_727730_19624\\",\\"sold_product_727730_17183, sold_product_727730_23436, sold_product_727730_25006, sold_product_727730_19624\\",\\"28.984, 14.992, 34, 50\\",\\"28.984, 14.992, 34, 50\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords Curvy, Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Spherecords Curvy, Tigress Enterprises, Gnomehouse\\",\\"13.922, 7.199, 17, 27.484\\",\\"28.984, 14.992, 34, 50\\",\\"17,183, 23,436, 25,006, 19,624\\",\\"Shift dress - black/gold, Blouse - grey, Boots - cognac, Dress - inca gold\\",\\"Shift dress - black/gold, Blouse - grey, Boots - cognac, Dress - inca gold\\",\\"1, 1, 1, 1\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\",\\"0, 0, 0, 0\\",\\"28.984, 14.992, 34, 50\\",\\"28.984, 14.992, 34, 50\\",\\"0, 0, 0, 0\\",\\"ZO0050600506, ZO0710907109, ZO0023300233, ZO0334603346\\",\\"127.938\\",\\"127.938\\",4,4,order,elyssa +ywMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Jimenez\\",\\"Tariq Jimenez\\",MALE,25,Jimenez,Jimenez,\\"(empty)\\",Tuesday,1,\\"tariq@jimenez-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567939,\\"sold_product_567939_12984, sold_product_567939_3061\\",\\"sold_product_567939_12984, sold_product_567939_3061\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"6.352, 12\\",\\"11.992, 24.984\\",\\"12,984, 3,061\\",\\"Scarf - black/grey, Jeans Skinny Fit - dark blue\\",\\"Scarf - black/grey, Jeans Skinny Fit - dark blue\\",\\"1, 1\\",\\"ZO0127201272, ZO0425504255\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0127201272, ZO0425504255\\",\\"36.969\\",\\"36.969\\",2,2,order,tariq +zAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Baker\\",\\"Irwin Baker\\",MALE,14,Baker,Baker,\\"(empty)\\",Tuesday,1,\\"irwin@baker-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567970,\\"sold_product_567970_23856, sold_product_567970_21614\\",\\"sold_product_567970_23856, sold_product_567970_21614\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"5.398, 31.844\\",\\"11.992, 65\\",\\"23,856, 21,614\\",\\"Polo shirt - dark grey multicolor, Casual lace-ups - taupe\\",\\"Polo shirt - dark grey multicolor, Casual lace-ups - taupe\\",\\"1, 1\\",\\"ZO0441504415, ZO0691606916\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0441504415, ZO0691606916\\",77,77,2,2,order,irwin +HgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Garner\\",\\"Robbie Garner\\",MALE,48,Garner,Garner,\\"(empty)\\",Tuesday,1,\\"robbie@garner-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567301,\\"sold_product_567301_15025, sold_product_567301_24034\\",\\"sold_product_567301_15025, sold_product_567301_24034\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"12.992, 5.711\\",\\"24.984, 10.992\\",\\"15,025, 24,034\\",\\"Jumper - black, Print T-shirt - blue/dark blue\\",\\"Jumper - black, Print T-shirt - blue/dark blue\\",\\"1, 1\\",\\"ZO0577605776, ZO0438104381\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0577605776, ZO0438104381\\",\\"35.969\\",\\"35.969\\",2,2,order,robbie +TgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Allison\\",\\"Yuri Allison\\",MALE,21,Allison,Allison,\\"(empty)\\",Tuesday,1,\\"yuri@allison-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566801,\\"sold_product_566801_10990, sold_product_566801_11992\\",\\"sold_product_566801_10990, sold_product_566801_11992\\",\\"25.984, 22.984\\",\\"25.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.508, 10.813\\",\\"25.984, 22.984\\",\\"10,990, 11,992\\",\\"Shirt - aubergine, Jumper - grey multicolor\\",\\"Shirt - aubergine, Jumper - grey multicolor\\",\\"1, 1\\",\\"ZO0279702797, ZO0573705737\\",\\"0, 0\\",\\"25.984, 22.984\\",\\"25.984, 22.984\\",\\"0, 0\\",\\"ZO0279702797, ZO0573705737\\",\\"48.969\\",\\"48.969\\",2,2,order,yuri +WgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Goodwin\\",\\"Yuri Goodwin\\",MALE,21,Goodwin,Goodwin,\\"(empty)\\",Tuesday,1,\\"yuri@goodwin-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566685,\\"sold_product_566685_18957, sold_product_566685_20093\\",\\"sold_product_566685_18957, sold_product_566685_20093\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.75, 9.656\\",\\"24.984, 20.984\\",\\"18,957, 20,093\\",\\"Jumper - black, Tracksuit bottoms - mottled light grey\\",\\"Jumper - black, Tracksuit bottoms - mottled light grey\\",\\"1, 1\\",\\"ZO0296902969, ZO0530205302\\",\\"0, 0\\",\\"24.984, 20.984\\",\\"24.984, 20.984\\",\\"0, 0\\",\\"ZO0296902969, ZO0530205302\\",\\"45.969\\",\\"45.969\\",2,2,order,yuri +WwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hansen\\",\\"Mary Hansen\\",FEMALE,20,Hansen,Hansen,\\"(empty)\\",Tuesday,1,\\"mary@hansen-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566924,\\"sold_product_566924_17824, sold_product_566924_24036\\",\\"sold_product_566924_17824, sold_product_566924_24036\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"35.25, 6.301\\",\\"75, 13.992\\",\\"17,824, 24,036\\",\\"Ankle boots - light brown, Print T-shirt - light grey multicolor\\",\\"Ankle boots - light brown, Print T-shirt - light grey multicolor\\",\\"1, 1\\",\\"ZO0673606736, ZO0161801618\\",\\"0, 0\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"0, 0\\",\\"ZO0673606736, ZO0161801618\\",89,89,2,2,order,mary +cQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Lambert\\",\\"Fitzgerald Lambert\\",MALE,11,Lambert,Lambert,\\"(empty)\\",Tuesday,1,\\"fitzgerald@lambert-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567662,\\"sold_product_567662_24046, sold_product_567662_19131\\",\\"sold_product_567662_24046, sold_product_567662_19131\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"5.762, 16.172\\",\\"11.992, 33\\",\\"24,046, 19,131\\",\\"Hat - black, Neutral running shoes - black/yellow\\",\\"Hat - black, Neutral running shoes - black/yellow\\",\\"1, 1\\",\\"ZO0308903089, ZO0614306143\\",\\"0, 0\\",\\"11.992, 33\\",\\"11.992, 33\\",\\"0, 0\\",\\"ZO0308903089, ZO0614306143\\",\\"44.969\\",\\"44.969\\",2,2,order,fuzzy +cgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Mary,Mary,\\"Mary Reese\\",\\"Mary Reese\\",FEMALE,20,Reese,Reese,\\"(empty)\\",Tuesday,1,\\"mary@reese-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567708,\\"sold_product_567708_21991, sold_product_567708_14420\\",\\"sold_product_567708_21991, sold_product_567708_14420\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"12.492, 19.313\\",\\"24.984, 42\\",\\"21,991, 14,420\\",\\"Rucksack - black, Across body bag - black\\",\\"Rucksack - black, Across body bag - black\\",\\"1, 1\\",\\"ZO0090500905, ZO0466204662\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0090500905, ZO0466204662\\",67,67,2,2,order,mary +yQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Dennis\\",\\"Gwen Dennis\\",FEMALE,26,Dennis,Dennis,\\"(empty)\\",Tuesday,1,\\"gwen@dennis-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567573,\\"sold_product_567573_18097, sold_product_567573_23199\\",\\"sold_product_567573_18097, sold_product_567573_23199\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"5.879, 20.156\\",\\"11.992, 42\\",\\"18,097, 23,199\\",\\"7 PACK - Socks - multicoloured, Dress - navy blazer\\",\\"7 PACK - Socks - multicoloured, Dress - navy blazer\\",\\"1, 1\\",\\"ZO0215602156, ZO0336803368\\",\\"0, 0\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"0, 0\\",\\"ZO0215602156, ZO0336803368\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +AQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Banks\\",\\"Jackson Banks\\",MALE,13,Banks,Banks,\\"(empty)\\",Tuesday,1,\\"jackson@banks-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Angeldale, Elitelligence, Low Tide Media\\",\\"Angeldale, Elitelligence, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",717603,\\"sold_product_717603_12011, sold_product_717603_6533, sold_product_717603_6991, sold_product_717603_6182\\",\\"sold_product_717603_12011, sold_product_717603_6533, sold_product_717603_6991, sold_product_717603_6182\\",\\"55, 28.984, 38, 10.992\\",\\"55, 28.984, 38, 10.992\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Elitelligence, Low Tide Media, Elitelligence\\",\\"Angeldale, Elitelligence, Low Tide Media, Elitelligence\\",\\"28.047, 13.344, 20.125, 5.82\\",\\"55, 28.984, 38, 10.992\\",\\"12,011, 6,533, 6,991, 6,182\\",\\"Slip-ons - black, Sweatshirt - black/white/mottled grey, Jumper - dark blue, Print T-shirt - white\\",\\"Slip-ons - black, Sweatshirt - black/white/mottled grey, Jumper - dark blue, Print T-shirt - white\\",\\"1, 1, 1, 1\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\",\\"0, 0, 0, 0\\",\\"55, 28.984, 38, 10.992\\",\\"55, 28.984, 38, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0685306853, ZO0585305853, ZO0450504505, ZO0552405524\\",133,133,4,4,order,jackson +HQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Padilla\\",\\"Wilhemina St. Padilla\\",FEMALE,17,Padilla,Padilla,\\"(empty)\\",Tuesday,1,\\"wilhemina st.@padilla-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566986,\\"sold_product_566986_11438, sold_product_566986_5014\\",\\"sold_product_566986_11438, sold_product_566986_5014\\",\\"75, 33\\",\\"75, 33\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"39.75, 15.18\\",\\"75, 33\\",\\"11,438, 5,014\\",\\"High heeled sandals - Midnight Blue, Boots - cognac\\",\\"High heeled sandals - Midnight Blue, Boots - cognac\\",\\"1, 1\\",\\"ZO0360903609, ZO0030100301\\",\\"0, 0\\",\\"75, 33\\",\\"75, 33\\",\\"0, 0\\",\\"ZO0360903609, ZO0030100301\\",108,108,2,2,order,wilhemina +HgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Rice\\",\\"Clarice Rice\\",FEMALE,18,Rice,Rice,\\"(empty)\\",Tuesday,1,\\"clarice@rice-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566735,\\"sold_product_566735_24785, sold_product_566735_19239\\",\\"sold_product_566735_24785, sold_product_566735_19239\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"9.172, 12.992\\",\\"16.984, 24.984\\",\\"24,785, 19,239\\",\\"Tracksuit bottoms - dark grey multicolor, Long sleeved top - black\\",\\"Tracksuit bottoms - dark grey multicolor, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0632406324, ZO0060300603\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0632406324, ZO0060300603\\",\\"41.969\\",\\"41.969\\",2,2,order,clarice +HwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Conner\\",\\"Mostafa Conner\\",MALE,9,Conner,Conner,\\"(empty)\\",Tuesday,1,\\"mostafa@conner-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567082,\\"sold_product_567082_18373, sold_product_567082_15037\\",\\"sold_product_567082_18373, sold_product_567082_15037\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.492, 12.992\\",\\"24.984, 24.984\\",\\"18,373, 15,037\\",\\"Shirt - grey, Trainers - dusty blue\\",\\"Shirt - grey, Trainers - dusty blue\\",\\"1, 1\\",\\"ZO0278802788, ZO0515605156\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0278802788, ZO0515605156\\",\\"49.969\\",\\"49.969\\",2,2,order,mostafa +IAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Potter\\",\\"Irwin Potter\\",MALE,14,Potter,Potter,\\"(empty)\\",Tuesday,1,\\"irwin@potter-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566881,\\"sold_product_566881_16129, sold_product_566881_19224\\",\\"sold_product_566881_16129, sold_product_566881_19224\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"12.492, 8.094\\",\\"24.984, 14.992\\",\\"16,129, 19,224\\",\\"Trousers - navy, Long sleeved top - white/blue/red\\",\\"Trousers - navy, Long sleeved top - white/blue/red\\",\\"1, 1\\",\\"ZO0419604196, ZO0559705597\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0419604196, ZO0559705597\\",\\"39.969\\",\\"39.969\\",2,2,order,irwin +YwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Reese\\",\\"Mary Reese\\",FEMALE,20,Reese,Reese,\\"(empty)\\",Tuesday,1,\\"mary@reese-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Spherecords\\",\\"Angeldale, Spherecords\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566790,\\"sold_product_566790_18851, sold_product_566790_22361\\",\\"sold_product_566790_18851, sold_product_566790_22361\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords\\",\\"Angeldale, Spherecords\\",\\"31.844, 4.949\\",\\"65, 10.992\\",\\"18,851, 22,361\\",\\"Tote bag - black, Long sleeved top - black\\",\\"Tote bag - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0699206992, ZO0641306413\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0699206992, ZO0641306413\\",76,76,2,2,order,mary +bwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Gomez\\",\\"Eddie Gomez\\",MALE,38,Gomez,Gomez,\\"(empty)\\",Tuesday,1,\\"eddie@gomez-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566706,\\"sold_product_566706_1717, sold_product_566706_17829\\",\\"sold_product_566706_1717, sold_product_566706_17829\\",\\"46, 10.992\\",\\"46, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"23.453, 5.602\\",\\"46, 10.992\\",\\"1,717, 17,829\\",\\"Boots - grey, 3 PACK - Socks - khaki/grey\\",\\"Boots - grey, 3 PACK - Socks - khaki/grey\\",\\"1, 1\\",\\"ZO0521505215, ZO0130501305\\",\\"0, 0\\",\\"46, 10.992\\",\\"46, 10.992\\",\\"0, 0\\",\\"ZO0521505215, ZO0130501305\\",\\"56.969\\",\\"56.969\\",2,2,order,eddie +cAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Boone\\",\\"Phil Boone\\",MALE,50,Boone,Boone,\\"(empty)\\",Tuesday,1,\\"phil@boone-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566935,\\"sold_product_566935_7024, sold_product_566935_20507\\",\\"sold_product_566935_7024, sold_product_566935_20507\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"9, 15.938\\",\\"16.984, 28.984\\",\\"7,024, 20,507\\",\\"3 PACK - Basic T-shirt - white/black/grey, Jumper - dark green\\",\\"3 PACK - Basic T-shirt - white/black/grey, Jumper - dark green\\",\\"1, 1\\",\\"ZO0473704737, ZO0121501215\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0473704737, ZO0121501215\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +cQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Burton\\",\\"Selena Burton\\",FEMALE,42,Burton,Burton,\\"(empty)\\",Tuesday,1,\\"selena@burton-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566985,\\"sold_product_566985_18522, sold_product_566985_22213\\",\\"sold_product_566985_18522, sold_product_566985_22213\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"25.484, 12.742\\",\\"50, 24.984\\",\\"18,522, 22,213\\",\\"Cocktail dress / Party dress - taupe, Sweatshirt - blue\\",\\"Cocktail dress / Party dress - taupe, Sweatshirt - blue\\",\\"1, 1\\",\\"ZO0044700447, ZO0502105021\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0044700447, ZO0502105021\\",75,75,2,2,order,selena +cgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Clayton\\",\\"Eddie Clayton\\",MALE,38,Clayton,Clayton,\\"(empty)\\",Tuesday,1,\\"eddie@clayton-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",566729,\\"sold_product_566729_23918, sold_product_566729_11251\\",\\"sold_product_566729_23918, sold_product_566729_11251\\",\\"7.988, 28.984\\",\\"7.988, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"4.148, 13.633\\",\\"7.988, 28.984\\",\\"23,918, 11,251\\",\\"Print T-shirt - red, Shirt - red/black\\",\\"Print T-shirt - red, Shirt - red/black\\",\\"1, 1\\",\\"ZO0557305573, ZO0110401104\\",\\"0, 0\\",\\"7.988, 28.984\\",\\"7.988, 28.984\\",\\"0, 0\\",\\"ZO0557305573, ZO0110401104\\",\\"36.969\\",\\"36.969\\",2,2,order,eddie +cwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Gwen,Gwen,\\"Gwen Weber\\",\\"Gwen Weber\\",FEMALE,26,Weber,Weber,\\"(empty)\\",Tuesday,1,\\"gwen@weber-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567095,\\"sold_product_567095_18015, sold_product_567095_16489\\",\\"sold_product_567095_18015, sold_product_567095_16489\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"30, 7.82\\",\\"60, 16.984\\",\\"18,015, 16,489\\",\\"Summer dress - blue fog, Clutch - red \\",\\"Summer dress - blue fog, Clutch - red \\",\\"1, 1\\",\\"ZO0339803398, ZO0098200982\\",\\"0, 0\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"0, 0\\",\\"ZO0339803398, ZO0098200982\\",77,77,2,2,order,gwen +igMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Shaw\\",\\"Elyssa Shaw\\",FEMALE,27,Shaw,Shaw,\\"(empty)\\",Tuesday,1,\\"elyssa@shaw-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Jun 24, 2019 @ 00:00:00.000\\",724326,\\"sold_product_724326_10916, sold_product_724326_19683, sold_product_724326_24375, sold_product_724326_22263\\",\\"sold_product_724326_10916, sold_product_724326_19683, sold_product_724326_24375, sold_product_724326_22263\\",\\"20.984, 10.992, 42, 75\\",\\"20.984, 10.992, 42, 75\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"Champion Arts, Spherecords, Gnomehouse, Angeldale\\",\\"10.906, 5.82, 22.672, 35.25\\",\\"20.984, 10.992, 42, 75\\",\\"10,916, 19,683, 24,375, 22,263\\",\\"Sweatshirt - black, 2 PACK - Vest - black/white, Summer dress - soft pink, Platform boots - black\\",\\"Sweatshirt - black, 2 PACK - Vest - black/white, Summer dress - soft pink, Platform boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\",\\"0, 0, 0, 0\\",\\"20.984, 10.992, 42, 75\\",\\"20.984, 10.992, 42, 75\\",\\"0, 0, 0, 0\\",\\"ZO0499404994, ZO0641606416, ZO0334303343, ZO0676706767\\",149,149,4,4,order,elyssa +DAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Cunningham\\",\\"Ahmed Al Cunningham\\",MALE,4,Cunningham,Cunningham,\\"(empty)\\",Tuesday,1,\\"ahmed al@cunningham-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 24, 2019 @ 00:00:00.000\\",567806,\\"sold_product_567806_17139, sold_product_567806_14215\\",\\"sold_product_567806_17139, sold_product_567806_14215\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.328, 5.641\\",\\"20.984, 11.992\\",\\"17,139, 14,215\\",\\"Trainers - grey, Print T-shirt - black\\",\\"Trainers - grey, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0517705177, ZO0569305693\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0517705177, ZO0569305693\\",\\"32.969\\",\\"32.969\\",2,2,order,ahmed +fAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Walters\\",\\"Clarice Walters\\",FEMALE,18,Walters,Walters,\\"(empty)\\",Tuesday,1,\\"clarice@walters-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567973,\\"sold_product_567973_24178, sold_product_567973_13294\\",\\"sold_product_567973_24178, sold_product_567973_13294\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"5.762, 34.438\\",\\"11.992, 65\\",\\"24,178, 13,294\\",\\"Print T-shirt - white, Tote bag - Blue Violety\\",\\"Print T-shirt - white, Tote bag - Blue Violety\\",\\"1, 1\\",\\"ZO0495104951, ZO0305903059\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0495104951, ZO0305903059\\",77,77,2,2,order,clarice +qQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Harper\\",\\"Rabbia Al Harper\\",FEMALE,5,Harper,Harper,\\"(empty)\\",Tuesday,1,\\"rabbia al@harper-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567341,\\"sold_product_567341_5526, sold_product_567341_18975\\",\\"sold_product_567341_5526, sold_product_567341_18975\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"47.688, 8.992\\",\\"90, 17.984\\",\\"5,526, 18,975\\",\\"Boots - black, Long sleeved top - black\\",\\"Boots - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0674506745, ZO0219202192\\",\\"0, 0\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"0, 0\\",\\"ZO0674506745, ZO0219202192\\",108,108,2,2,order,rabbia +tQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Shaw\\",\\"Kamal Shaw\\",MALE,39,Shaw,Shaw,\\"(empty)\\",Tuesday,1,\\"kamal@shaw-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567492,\\"sold_product_567492_14648, sold_product_567492_12310\\",\\"sold_product_567492_14648, sold_product_567492_12310\\",\\"13.992, 17.984\\",\\"13.992, 17.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.719, 9.352\\",\\"13.992, 17.984\\",\\"14,648, 12,310\\",\\"Tie - dark grey, Polo shirt - grey\\",\\"Tie - dark grey, Polo shirt - grey\\",\\"1, 1\\",\\"ZO0277302773, ZO0443004430\\",\\"0, 0\\",\\"13.992, 17.984\\",\\"13.992, 17.984\\",\\"0, 0\\",\\"ZO0277302773, ZO0443004430\\",\\"31.984\\",\\"31.984\\",2,2,order,kamal +tgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Irwin,Irwin,\\"Irwin Jenkins\\",\\"Irwin Jenkins\\",MALE,14,Jenkins,Jenkins,\\"(empty)\\",Tuesday,1,\\"irwin@jenkins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567654,\\"sold_product_567654_22409, sold_product_567654_1312\\",\\"sold_product_567654_22409, sold_product_567654_1312\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"5.762, 24\\",\\"11.992, 50\\",\\"22,409, 1,312\\",\\"Basic T-shirt - Dark Salmon, Lace-up boots - black\\",\\"Basic T-shirt - Dark Salmon, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0121301213, ZO0399403994\\",\\"0, 0\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"0, 0\\",\\"ZO0121301213, ZO0399403994\\",\\"61.969\\",\\"61.969\\",2,2,order,irwin +uAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Rivera\\",\\"Betty Rivera\\",FEMALE,44,Rivera,Rivera,\\"(empty)\\",Tuesday,1,\\"betty@rivera-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567403,\\"sold_product_567403_20386, sold_product_567403_23991\\",\\"sold_product_567403_20386, sold_product_567403_23991\\",\\"60, 42\\",\\"60, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"30, 19.313\\",\\"60, 42\\",\\"20,386, 23,991\\",\\"Over-the-knee boots - cognac, Trousers - black\\",\\"Over-the-knee boots - cognac, Trousers - black\\",\\"1, 1\\",\\"ZO0138601386, ZO0259202592\\",\\"0, 0\\",\\"60, 42\\",\\"60, 42\\",\\"0, 0\\",\\"ZO0138601386, ZO0259202592\\",102,102,2,2,order,betty +DgMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Hampton\\",\\"Mary Hampton\\",FEMALE,20,Hampton,Hampton,\\"(empty)\\",Tuesday,1,\\"mary@hampton-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Microlutions\\",\\"Tigress Enterprises, Microlutions\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567207,\\"sold_product_567207_17489, sold_product_567207_14916\\",\\"sold_product_567207_17489, sold_product_567207_14916\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Microlutions\\",\\"Tigress Enterprises, Microlutions\\",\\"12, 28.203\\",\\"24.984, 60\\",\\"17,489, 14,916\\",\\"Denim skirt - dark blue denim, Bomber Jacket - black\\",\\"Denim skirt - dark blue denim, Bomber Jacket - black\\",\\"1, 1\\",\\"ZO0033600336, ZO0109401094\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0033600336, ZO0109401094\\",85,85,2,2,order,mary +DwMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Hopkins\\",\\"Jackson Hopkins\\",MALE,13,Hopkins,Hopkins,\\"(empty)\\",Tuesday,1,\\"jackson@hopkins-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 24, 2019 @ 00:00:00.000\\",567356,\\"sold_product_567356_13525, sold_product_567356_11169\\",\\"sold_product_567356_13525, sold_product_567356_11169\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 13, 2016 @ 00:00:00.000, Dec 13, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"24.5, 5.602\\",\\"50, 10.992\\",\\"13,525, 11,169\\",\\"Weekend bag - sand, Tie - grey\\",\\"Weekend bag - sand, Tie - grey\\",\\"1, 1\\",\\"ZO0319503195, ZO0409904099\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0319503195, ZO0409904099\\",\\"60.969\\",\\"60.969\\",2,2,order,jackson +0wMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Rios\\",\\"Oliver Rios\\",MALE,7,Rios,Rios,\\"(empty)\\",Monday,0,\\"oliver@rios-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565855,\\"sold_product_565855_19919, sold_product_565855_24502\\",\\"sold_product_565855_19919, sold_product_565855_24502\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"9.867, 12.492\\",\\"20.984, 24.984\\",\\"19,919, 24,502\\",\\"Shirt - dark blue white, Slim fit jeans - raw blue\\",\\"Shirt - dark blue white, Slim fit jeans - raw blue\\",\\"1, 1\\",\\"ZO0417504175, ZO0535205352\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0417504175, ZO0535205352\\",\\"45.969\\",\\"45.969\\",2,2,order,oliver +NgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Ball\\",\\"Sultan Al Ball\\",MALE,19,Ball,Ball,\\"(empty)\\",Monday,0,\\"sultan al@ball-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",565915,\\"sold_product_565915_13822, sold_product_565915_13150\\",\\"sold_product_565915_13822, sold_product_565915_13150\\",\\"42, 16.984\\",\\"42, 16.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"21, 9\\",\\"42, 16.984\\",\\"13,822, 13,150\\",\\"High-top trainers - black, High-top trainers - brown\\",\\"High-top trainers - black, High-top trainers - brown\\",\\"1, 1\\",\\"ZO0515005150, ZO0509805098\\",\\"0, 0\\",\\"42, 16.984\\",\\"42, 16.984\\",\\"0, 0\\",\\"ZO0515005150, ZO0509805098\\",\\"58.969\\",\\"58.969\\",2,2,order,sultan +SAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Dixon\\",\\"Elyssa Dixon\\",FEMALE,27,Dixon,Dixon,\\"(empty)\\",Monday,0,\\"elyssa@dixon-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566343,\\"sold_product_566343_16050, sold_product_566343_14327\\",\\"sold_product_566343_16050, sold_product_566343_14327\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"14.781, 22.25\\",\\"28.984, 42\\",\\"16,050, 14,327\\",\\"Winter jacket - black, Summer dress - black/Chocolate\\",\\"Winter jacket - black, Summer dress - black/Chocolate\\",\\"1, 1\\",\\"ZO0185101851, ZO0052800528\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0185101851, ZO0052800528\\",71,71,2,2,order,elyssa +SQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Ball\\",\\"Gwen Ball\\",FEMALE,26,Ball,Ball,\\"(empty)\\",Monday,0,\\"gwen@ball-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566400,\\"sold_product_566400_18643, sold_product_566400_24426\\",\\"sold_product_566400_18643, sold_product_566400_24426\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"9.867, 13.633\\",\\"20.984, 28.984\\",\\"18,643, 24,426\\",\\"Handbag - Blue Violety, Slip-ons - nude\\",\\"Handbag - Blue Violety, Slip-ons - nude\\",\\"1, 1\\",\\"ZO0204702047, ZO0009600096\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0204702047, ZO0009600096\\",\\"49.969\\",\\"49.969\\",2,2,order,gwen +aAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Palmer\\",\\"Gwen Palmer\\",FEMALE,26,Palmer,Palmer,\\"(empty)\\",Monday,0,\\"gwen@palmer-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,Gnomehouse,Gnomehouse,\\"Jun 23, 2019 @ 00:00:00.000\\",565776,\\"sold_product_565776_23882, sold_product_565776_8692\\",\\"sold_product_565776_23882, sold_product_565776_8692\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"16.813, 13.797\\",\\"33, 29.984\\",\\"23,882, 8,692\\",\\"Long sleeved top - chinese red, Blouse - blue fog\\",\\"Long sleeved top - chinese red, Blouse - blue fog\\",\\"1, 1\\",\\"ZO0343103431, ZO0345803458\\",\\"0, 0\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"0, 0\\",\\"ZO0343103431, ZO0345803458\\",\\"62.969\\",\\"62.969\\",2,2,order,gwen +bgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Greer\\",\\"Yuri Greer\\",MALE,21,Greer,Greer,\\"(empty)\\",Monday,0,\\"yuri@greer-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566607,\\"sold_product_566607_3014, sold_product_566607_18884\\",\\"sold_product_566607_3014, sold_product_566607_18884\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.492, 9.656\\",\\"20.984, 20.984\\",\\"3,014, 18,884\\",\\"Cardigan - grey multicolor, Sweatshirt - black /white\\",\\"Cardigan - grey multicolor, Sweatshirt - black /white\\",\\"1, 1\\",\\"ZO0572205722, ZO0585205852\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0572205722, ZO0585205852\\",\\"41.969\\",\\"41.969\\",2,2,order,yuri +jgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Cortez\\",\\"Elyssa Cortez\\",FEMALE,27,Cortez,Cortez,\\"(empty)\\",Monday,0,\\"elyssa@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565452,\\"sold_product_565452_22934, sold_product_565452_13388\\",\\"sold_product_565452_22934, sold_product_565452_13388\\",\\"42, 14.992\\",\\"42, 14.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"22.25, 7.352\\",\\"42, 14.992\\",\\"22,934, 13,388\\",\\"High heels - black, 2 PACK - Vest - white/dark blue/dark blue\\",\\"High heels - black, 2 PACK - Vest - white/dark blue/dark blue\\",\\"1, 1\\",\\"ZO0133601336, ZO0643906439\\",\\"0, 0\\",\\"42, 14.992\\",\\"42, 14.992\\",\\"0, 0\\",\\"ZO0133601336, ZO0643906439\\",\\"56.969\\",\\"56.969\\",2,2,order,elyssa +kQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Smith\\",\\"Abigail Smith\\",FEMALE,46,Smith,Smith,\\"(empty)\\",Monday,0,\\"abigail@smith-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566051,\\"sold_product_566051_16134, sold_product_566051_23328\\",\\"sold_product_566051_16134, sold_product_566051_23328\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"13.492, 26.484\\",\\"24.984, 50\\",\\"16,134, 23,328\\",\\"Cowboy/Biker boots - light grey, Blazer - black\\",\\"Cowboy/Biker boots - light grey, Blazer - black\\",\\"1, 1\\",\\"ZO0025600256, ZO0270202702\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0025600256, ZO0270202702\\",75,75,2,2,order,abigail +qgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Mccarthy\\",\\"Sultan Al Mccarthy\\",MALE,19,Mccarthy,Mccarthy,\\"(empty)\\",Monday,0,\\"sultan al@mccarthy-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565466,\\"sold_product_565466_10951, sold_product_565466_11989\\",\\"sold_product_565466_10951, sold_product_565466_11989\\",\\"42, 45\\",\\"42, 45\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"19.313, 24.734\\",\\"42, 45\\",\\"10,951, 11,989\\",\\"Summer jacket - navy, Light jacket - khaki\\",\\"Summer jacket - navy, Light jacket - khaki\\",\\"1, 1\\",\\"ZO0285402854, ZO0538605386\\",\\"0, 0\\",\\"42, 45\\",\\"42, 45\\",\\"0, 0\\",\\"ZO0285402854, ZO0538605386\\",87,87,2,2,order,sultan +9gMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Riley\\",\\"Mostafa Riley\\",MALE,9,Riley,Riley,\\"(empty)\\",Monday,0,\\"mostafa@riley-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566553,\\"sold_product_566553_18385, sold_product_566553_15343\\",\\"sold_product_566553_18385, sold_product_566553_15343\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"4.07, 32.375\\",\\"7.988, 60\\",\\"18,385, 15,343\\",\\"Basic T-shirt - dark grey multicolor, Parka - khaki\\",\\"Basic T-shirt - dark grey multicolor, Parka - khaki\\",\\"1, 1\\",\\"ZO0435004350, ZO0544005440\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0435004350, ZO0544005440\\",68,68,2,2,order,mostafa +AQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Wolfe\\",\\"Yasmine Wolfe\\",FEMALE,43,Wolfe,Wolfe,\\"(empty)\\",Monday,0,\\"yasmine@wolfe-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565446,\\"sold_product_565446_12090, sold_product_565446_12122\\",\\"sold_product_565446_12090, sold_product_565446_12122\\",\\"11.992, 29.984\\",\\"11.992, 29.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.641, 15.594\\",\\"11.992, 29.984\\",\\"12,090, 12,122\\",\\"Long sleeved top - black, Winter boots - black\\",\\"Long sleeved top - black, Winter boots - black\\",\\"1, 1\\",\\"ZO0643206432, ZO0140101401\\",\\"0, 0\\",\\"11.992, 29.984\\",\\"11.992, 29.984\\",\\"0, 0\\",\\"ZO0643206432, ZO0140101401\\",\\"41.969\\",\\"41.969\\",2,2,order,yasmine +MQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Carpenter\\",\\"Wagdi Carpenter\\",MALE,15,Carpenter,Carpenter,\\"(empty)\\",Monday,0,\\"wagdi@carpenter-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",566053,\\"sold_product_566053_2650, sold_product_566053_21018\\",\\"sold_product_566053_2650, sold_product_566053_21018\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.344, 9.867\\",\\"28.984, 20.984\\",\\"2,650, 21,018\\",\\"Slim fit jeans - black, Jumper - charcoal\\",\\"Slim fit jeans - black, Jumper - charcoal\\",\\"1, 1\\",\\"ZO0284702847, ZO0299202992\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0284702847, ZO0299202992\\",\\"49.969\\",\\"49.969\\",2,2,order,wagdi +UgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Schultz\\",\\"Jackson Schultz\\",MALE,13,Schultz,Schultz,\\"(empty)\\",Monday,0,\\"jackson@schultz-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565605,\\"sold_product_565605_24934, sold_product_565605_22732\\",\\"sold_product_565605_24934, sold_product_565605_22732\\",\\"50, 33\\",\\"50, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 16.172\\",\\"50, 33\\",\\"24,934, 22,732\\",\\"Lace-up boots - resin coffee, Relaxed fit jeans - black denim\\",\\"Lace-up boots - resin coffee, Relaxed fit jeans - black denim\\",\\"1, 1\\",\\"ZO0403504035, ZO0113301133\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0403504035, ZO0113301133\\",83,83,2,2,order,jackson +lAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Phelps\\",\\"Abigail Phelps\\",FEMALE,46,Phelps,Phelps,\\"(empty)\\",Monday,0,\\"abigail@phelps-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Gnomehouse, Karmanite\\",\\"Gnomehouse, Karmanite\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566170,\\"sold_product_566170_7278, sold_product_566170_5214\\",\\"sold_product_566170_7278, sold_product_566170_5214\\",\\"65, 85\\",\\"65, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Karmanite\\",\\"Gnomehouse, Karmanite\\",\\"31.844, 43.344\\",\\"65, 85\\",\\"7,278, 5,214\\",\\"Boots - navy, Ankle boots - wood\\",\\"Boots - navy, Ankle boots - wood\\",\\"1, 1\\",\\"ZO0324803248, ZO0703907039\\",\\"0, 0\\",\\"65, 85\\",\\"65, 85\\",\\"0, 0\\",\\"ZO0324803248, ZO0703907039\\",150,150,2,2,order,abigail +lQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Perkins\\",\\"Abd Perkins\\",MALE,52,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"abd@perkins-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566187,\\"sold_product_566187_12028, sold_product_566187_21937\\",\\"sold_product_566187_12028, sold_product_566187_21937\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.92, 12.742\\",\\"7.988, 24.984\\",\\"12,028, 21,937\\",\\"Vest - light blue multicolor, Sweatshirt - navy multicolor\\",\\"Vest - light blue multicolor, Sweatshirt - navy multicolor\\",\\"1, 1\\",\\"ZO0548905489, ZO0459404594\\",\\"0, 0\\",\\"7.988, 24.984\\",\\"7.988, 24.984\\",\\"0, 0\\",\\"ZO0548905489, ZO0459404594\\",\\"32.969\\",\\"32.969\\",2,2,order,abd +lgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Love\\",\\"Frances Love\\",FEMALE,49,Love,Love,\\"(empty)\\",Monday,0,\\"frances@love-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566125,\\"sold_product_566125_14168, sold_product_566125_13612\\",\\"sold_product_566125_14168, sold_product_566125_13612\\",\\"100, 11.992\\",\\"100, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"48, 6.469\\",\\"100, 11.992\\",\\"14,168, 13,612\\",\\"Classic coat - grey, Basic T-shirt - light red/white\\",\\"Classic coat - grey, Basic T-shirt - light red/white\\",\\"1, 1\\",\\"ZO0433104331, ZO0549505495\\",\\"0, 0\\",\\"100, 11.992\\",\\"100, 11.992\\",\\"0, 0\\",\\"ZO0433104331, ZO0549505495\\",112,112,2,2,order,frances +lwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Butler\\",\\"Mostafa Butler\\",MALE,9,Butler,Butler,\\"(empty)\\",Monday,0,\\"mostafa@butler-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566156,\\"sold_product_566156_17644, sold_product_566156_17414\\",\\"sold_product_566156_17644, sold_product_566156_17414\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"29.406, 7.648\\",\\"60, 16.984\\",\\"17,644, 17,414\\",\\"Suit jacket - dark blue, Print T-shirt - black\\",\\"Suit jacket - dark blue, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0424104241, ZO0117901179\\",\\"0, 0\\",\\"60, 16.984\\",\\"60, 16.984\\",\\"0, 0\\",\\"ZO0424104241, ZO0117901179\\",77,77,2,2,order,mostafa +mAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Mckenzie\\",\\"Stephanie Mckenzie\\",FEMALE,6,Mckenzie,Mckenzie,\\"(empty)\\",Monday,0,\\"stephanie@mckenzie-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566100,\\"sold_product_566100_15198, sold_product_566100_22284\\",\\"sold_product_566100_15198, sold_product_566100_22284\\",\\"50, 65\\",\\"50, 65\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"25.484, 31.203\\",\\"50, 65\\",\\"15,198, 22,284\\",\\"Boots - taupe, Classic heels - black\\",\\"Boots - taupe, Classic heels - black\\",\\"1, 1\\",\\"ZO0013400134, ZO0667306673\\",\\"0, 0\\",\\"50, 65\\",\\"50, 65\\",\\"0, 0\\",\\"ZO0013400134, ZO0667306673\\",115,115,2,2,order,stephanie +mQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Boone\\",\\"George Boone\\",MALE,32,Boone,Boone,\\"(empty)\\",Monday,0,\\"george@boone-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566280,\\"sold_product_566280_11862, sold_product_566280_11570\\",\\"sold_product_566280_11862, sold_product_566280_11570\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"11.492, 9.172\\",\\"22.984, 16.984\\",\\"11,862, 11,570\\",\\"Jumper - black, Print T-shirt - beige\\",\\"Jumper - black, Print T-shirt - beige\\",\\"1, 1\\",\\"ZO0573205732, ZO0116701167\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0573205732, ZO0116701167\\",\\"39.969\\",\\"39.969\\",2,2,order,george +mgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Alvarez\\",\\"Youssef Alvarez\\",MALE,31,Alvarez,Alvarez,\\"(empty)\\",Monday,0,\\"youssef@alvarez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565708,\\"sold_product_565708_24246, sold_product_565708_11444\\",\\"sold_product_565708_24246, sold_product_565708_11444\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"33.781, 13.742\\",\\"65, 24.984\\",\\"24,246, 11,444\\",\\"Lace-up boots - black, Rucksack - black/cognac\\",\\"Lace-up boots - black, Rucksack - black/cognac\\",\\"1, 1\\",\\"ZO0253302533, ZO0605706057\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0253302533, ZO0605706057\\",90,90,2,2,order,youssef +tgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Taylor\\",\\"Thad Taylor\\",MALE,30,Taylor,Taylor,\\"(empty)\\",Monday,0,\\"thad@taylor-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",565809,\\"sold_product_565809_18321, sold_product_565809_19707\\",\\"sold_product_565809_18321, sold_product_565809_19707\\",\\"12.992, 20.984\\",\\"12.992, 20.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"7.141, 10.289\\",\\"12.992, 20.984\\",\\"18,321, 19,707\\",\\"Vest - white/grey, Trainers - black\\",\\"Vest - white/grey, Trainers - black\\",\\"1, 1\\",\\"ZO0557905579, ZO0513705137\\",\\"0, 0\\",\\"12.992, 20.984\\",\\"12.992, 20.984\\",\\"0, 0\\",\\"ZO0557905579, ZO0513705137\\",\\"33.969\\",\\"33.969\\",2,2,order,thad +twMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Daniels\\",\\"Clarice Daniels\\",FEMALE,18,Daniels,Daniels,\\"(empty)\\",Monday,0,\\"clarice@daniels-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries active, Angeldale\\",\\"Pyramidustries active, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566256,\\"sold_product_566256_9787, sold_product_566256_18737\\",\\"sold_product_566256_9787, sold_product_566256_18737\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Angeldale\\",\\"Pyramidustries active, Angeldale\\",\\"12.992, 31.844\\",\\"24.984, 65\\",\\"9,787, 18,737\\",\\"Sweatshirt - duffle bag, Lace-ups - black\\",\\"Sweatshirt - duffle bag, Lace-ups - black\\",\\"1, 1\\",\\"ZO0227302273, ZO0668706687\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0227302273, ZO0668706687\\",90,90,2,2,order,clarice +GgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Chapman\\",\\"Elyssa Chapman\\",FEMALE,27,Chapman,Chapman,\\"(empty)\\",Monday,0,\\"elyssa@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565639,\\"sold_product_565639_15334, sold_product_565639_18810\\",\\"sold_product_565639_15334, sold_product_565639_18810\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"5.762, 6.578\\",\\"11.992, 13.992\\",\\"15,334, 18,810\\",\\"Scarf - bordeaux, Wallet - dark turquoise\\",\\"Scarf - bordeaux, Wallet - dark turquoise\\",\\"1, 1\\",\\"ZO0193901939, ZO0080400804\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0193901939, ZO0080400804\\",\\"25.984\\",\\"25.984\\",2,2,order,elyssa +GwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Roberson\\",\\"Eddie Roberson\\",MALE,38,Roberson,Roberson,\\"(empty)\\",Monday,0,\\"eddie@roberson-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565684,\\"sold_product_565684_11098, sold_product_565684_11488\\",\\"sold_product_565684_11098, sold_product_565684_11488\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.656, 5.059\\",\\"16.984, 10.992\\",\\"11,098, 11,488\\",\\"Trainers - Blue Violety, Tie - black\\",\\"Trainers - Blue Violety, Tie - black\\",\\"1, 1\\",\\"ZO0507705077, ZO0409804098\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0507705077, ZO0409804098\\",\\"27.984\\",\\"27.984\\",2,2,order,eddie +ngMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty King\\",\\"Betty King\\",FEMALE,44,King,King,\\"(empty)\\",Monday,0,\\"betty@king-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",565945,\\"sold_product_565945_13129, sold_product_565945_14400\\",\\"sold_product_565945_13129, sold_product_565945_14400\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"20.578, 22.25\\",\\"42, 42\\",\\"13,129, 14,400\\",\\"Jeans Skinny Fit - dark blue denim, Jumper - white\\",\\"Jeans Skinny Fit - dark blue denim, Jumper - white\\",\\"1, 1\\",\\"ZO0270602706, ZO0269502695\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0270602706, ZO0269502695\\",84,84,2,2,order,betty +nwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Harvey\\",\\"Clarice Harvey\\",FEMALE,18,Harvey,Harvey,\\"(empty)\\",Monday,0,\\"clarice@harvey-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565988,\\"sold_product_565988_12794, sold_product_565988_15193\\",\\"sold_product_565988_12794, sold_product_565988_15193\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"16.172, 10.289\\",\\"33, 20.984\\",\\"12,794, 15,193\\",\\"Tote bag - cognac, 3 PACK - Long sleeved top - dark grey multicolor/black/white\\",\\"Tote bag - cognac, 3 PACK - Long sleeved top - dark grey multicolor/black/white\\",\\"1, 1\\",\\"ZO0074700747, ZO0645206452\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0074700747, ZO0645206452\\",\\"53.969\\",\\"53.969\\",2,2,order,clarice +pAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Wagdi,Wagdi,\\"Wagdi Underwood\\",\\"Wagdi Underwood\\",MALE,15,Underwood,Underwood,\\"(empty)\\",Monday,0,\\"wagdi@underwood-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565732,\\"sold_product_565732_16955, sold_product_565732_13808\\",\\"sold_product_565732_16955, sold_product_565732_13808\\",\\"200, 16.984\\",\\"200, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"92, 9.344\\",\\"200, 16.984\\",\\"16,955, 13,808\\",\\"Classic coat - navy, Scarf - red/blue\\",\\"Classic coat - navy, Scarf - red/blue\\",\\"1, 1\\",\\"ZO0291402914, ZO0603006030\\",\\"0, 0\\",\\"200, 16.984\\",\\"200, 16.984\\",\\"0, 0\\",\\"ZO0291402914, ZO0603006030\\",217,217,2,2,order,wagdi +AQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Robert,Robert,\\"Robert Cross\\",\\"Robert Cross\\",MALE,29,Cross,Cross,\\"(empty)\\",Monday,0,\\"robert@cross-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566042,\\"sold_product_566042_2775, sold_product_566042_20500\\",\\"sold_product_566042_2775, sold_product_566042_20500\\",\\"28.984, 29.984\\",\\"28.984, 29.984\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"15.938, 15.594\\",\\"28.984, 29.984\\",\\"2,775, 20,500\\",\\"Jumper - white/dark blue, Rucksack - black\\",\\"Jumper - white/dark blue, Rucksack - black\\",\\"1, 1\\",\\"ZO0451804518, ZO0127901279\\",\\"0, 0\\",\\"28.984, 29.984\\",\\"28.984, 29.984\\",\\"0, 0\\",\\"ZO0451804518, ZO0127901279\\",\\"58.969\\",\\"58.969\\",2,2,order,robert +EwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Swanson\\",\\"Tariq Swanson\\",MALE,25,Swanson,Swanson,\\"(empty)\\",Monday,0,\\"tariq@swanson-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566456,\\"sold_product_566456_14947, sold_product_566456_16714\\",\\"sold_product_566456_14947, sold_product_566456_16714\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.93, 11.5\\",\\"10.992, 24.984\\",\\"14,947, 16,714\\",\\"Hat - black, Shorts - ice\\",\\"Hat - black, Shorts - ice\\",\\"1, 1\\",\\"ZO0597105971, ZO0283702837\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0597105971, ZO0283702837\\",\\"35.969\\",\\"35.969\\",2,2,order,tariq +TgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Chandler\\",\\"Diane Chandler\\",FEMALE,22,Chandler,Chandler,\\"(empty)\\",Monday,0,\\"diane@chandler-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565542,\\"sold_product_565542_24084, sold_product_565542_19410\\",\\"sold_product_565542_24084, sold_product_565542_19410\\",\\"16.984, 26.984\\",\\"16.984, 26.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"8.828, 13.492\\",\\"16.984, 26.984\\",\\"24,084, 19,410\\",\\"Tights - black/nasturium, Swimsuit - navy\\",\\"Tights - black/nasturium, Swimsuit - navy\\",\\"1, 1\\",\\"ZO0224302243, ZO0359103591\\",\\"0, 0\\",\\"16.984, 26.984\\",\\"16.984, 26.984\\",\\"0, 0\\",\\"ZO0224302243, ZO0359103591\\",\\"43.969\\",\\"43.969\\",2,2,order,diane +XgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Caldwell\\",\\"Rabbia Al Caldwell\\",FEMALE,5,Caldwell,Caldwell,\\"(empty)\\",Monday,0,\\"rabbia al@caldwell-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566121,\\"sold_product_566121_10723, sold_product_566121_12693\\",\\"sold_product_566121_10723, sold_product_566121_12693\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"10.492, 7.82\\",\\"20.984, 16.984\\",\\"10,723, 12,693\\",\\"Sweatshirt - black, Clutch - red\\",\\"Sweatshirt - black, Clutch - red\\",\\"1, 1\\",\\"ZO0227202272, ZO0357003570\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0227202272, ZO0357003570\\",\\"37.969\\",\\"37.969\\",2,2,order,rabbia +XwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Boris,Boris,\\"Boris Bowers\\",\\"Boris Bowers\\",MALE,36,Bowers,Bowers,\\"(empty)\\",Monday,0,\\"boris@bowers-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Angeldale, Spritechnologies\\",\\"Angeldale, Spritechnologies\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566101,\\"sold_product_566101_738, sold_product_566101_24537\\",\\"sold_product_566101_738, sold_product_566101_24537\\",\\"75, 7.988\\",\\"75, 7.988\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spritechnologies\\",\\"Angeldale, Spritechnologies\\",\\"39.75, 4.309\\",\\"75, 7.988\\",\\"738, 24,537\\",\\"Lace-up boots - azul, Sports shirt - black\\",\\"Lace-up boots - azul, Sports shirt - black\\",\\"1, 1\\",\\"ZO0691406914, ZO0617806178\\",\\"0, 0\\",\\"75, 7.988\\",\\"75, 7.988\\",\\"0, 0\\",\\"ZO0691406914, ZO0617806178\\",83,83,2,2,order,boris +YAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryant\\",\\"Elyssa Bryant\\",FEMALE,27,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"elyssa@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566653,\\"sold_product_566653_17818, sold_product_566653_18275\\",\\"sold_product_566653_17818, sold_product_566653_18275\\",\\"65, 28.984\\",\\"65, 28.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries active\\",\\"Angeldale, Pyramidustries active\\",\\"31.203, 15.359\\",\\"65, 28.984\\",\\"17,818, 18,275\\",\\"Classic heels - ginger, Trainers - white\\",\\"Classic heels - ginger, Trainers - white\\",\\"1, 1\\",\\"ZO0666506665, ZO0216602166\\",\\"0, 0\\",\\"65, 28.984\\",\\"65, 28.984\\",\\"0, 0\\",\\"ZO0666506665, ZO0216602166\\",94,94,2,2,order,elyssa +pwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Mullins\\",\\"Sonya Mullins\\",FEMALE,28,Mullins,Mullins,\\"(empty)\\",Monday,0,\\"sonya@mullins-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565838,\\"sold_product_565838_17639, sold_product_565838_16507\\",\\"sold_product_565838_17639, sold_product_565838_16507\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"18.5, 9.344\\",\\"37, 16.984\\",\\"17,639, 16,507\\",\\"Blouse - black, Across body bag - gunmetal\\",\\"Blouse - black, Across body bag - gunmetal\\",\\"1, 1\\",\\"ZO0343703437, ZO0207102071\\",\\"0, 0\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"0, 0\\",\\"ZO0343703437, ZO0207102071\\",\\"53.969\\",\\"53.969\\",2,2,order,sonya +qQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Larson\\",\\"Stephanie Larson\\",FEMALE,6,Larson,Larson,\\"(empty)\\",Monday,0,\\"stephanie@larson-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565804,\\"sold_product_565804_23705, sold_product_565804_11330\\",\\"sold_product_565804_23705, sold_product_565804_11330\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"12.492, 25.984\\",\\"24.984, 50\\",\\"23,705, 11,330\\",\\"Clutch - Deep Pink, Short coat - dark grey\\",\\"Clutch - Deep Pink, Short coat - dark grey\\",\\"1, 1\\",\\"ZO0306803068, ZO0174601746\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0306803068, ZO0174601746\\",75,75,2,2,order,stephanie +qgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Youssef,Youssef,\\"Youssef Summers\\",\\"Youssef Summers\\",MALE,31,Summers,Summers,\\"(empty)\\",Monday,0,\\"youssef@summers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566247,\\"sold_product_566247_864, sold_product_566247_24934\\",\\"sold_product_566247_864, sold_product_566247_24934\\",\\"50, 50\\",\\"50, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"23.5, 22.5\\",\\"50, 50\\",\\"864, 24,934\\",\\"Smart lace-ups - brown, Lace-up boots - resin coffee\\",\\"Smart lace-ups - brown, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0384903849, ZO0403504035\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0384903849, ZO0403504035\\",100,100,2,2,order,youssef +twMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Schultz\\",\\"Muniz Schultz\\",MALE,37,Schultz,Schultz,\\"(empty)\\",Monday,0,\\"muniz@schultz-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566036,\\"sold_product_566036_21739, sold_product_566036_19292\\",\\"sold_product_566036_21739, sold_product_566036_19292\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.117, 12.25\\",\\"20.984, 24.984\\",\\"21,739, 19,292\\",\\"Tracksuit top - mottled grey, Trainers - black\\",\\"Tracksuit top - mottled grey, Trainers - black\\",\\"1, 1\\",\\"ZO0583605836, ZO0510605106\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0583605836, ZO0510605106\\",\\"45.969\\",\\"45.969\\",2,2,order,muniz +1AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Rodriguez\\",\\"Elyssa Rodriguez\\",FEMALE,27,Rodriguez,Rodriguez,\\"(empty)\\",Monday,0,\\"elyssa@rodriguez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565459,\\"sold_product_565459_18966, sold_product_565459_22336\\",\\"sold_product_565459_18966, sold_product_565459_22336\\",\\"60, 75\\",\\"60, 75\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"31.188, 39.75\\",\\"60, 75\\",\\"18,966, 22,336\\",\\"High heeled sandals - red, Boots - black\\",\\"High heeled sandals - red, Boots - black\\",\\"1, 1\\",\\"ZO0242302423, ZO0676006760\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0242302423, ZO0676006760\\",135,135,2,2,order,elyssa +2gMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Hansen\\",\\"Elyssa Hansen\\",FEMALE,27,Hansen,Hansen,\\"(empty)\\",Monday,0,\\"elyssa@hansen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565819,\\"sold_product_565819_11025, sold_product_565819_20135\\",\\"sold_product_565819_11025, sold_product_565819_20135\\",\\"14.992, 11.992\\",\\"14.992, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.75, 6.109\\",\\"14.992, 11.992\\",\\"11,025, 20,135\\",\\"T-bar sandals - black, Vest - red\\",\\"T-bar sandals - black, Vest - red\\",\\"1, 1\\",\\"ZO0031700317, ZO0157701577\\",\\"0, 0\\",\\"14.992, 11.992\\",\\"14.992, 11.992\\",\\"0, 0\\",\\"ZO0031700317, ZO0157701577\\",\\"26.984\\",\\"26.984\\",2,2,order,elyssa +2wMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mullins\\",\\"Wilhemina St. Mullins\\",FEMALE,17,Mullins,Mullins,\\"(empty)\\",Monday,0,\\"wilhemina st.@mullins-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",731352,\\"sold_product_731352_12880, sold_product_731352_5477, sold_product_731352_13837, sold_product_731352_24675\\",\\"sold_product_731352_12880, sold_product_731352_5477, sold_product_731352_13837, sold_product_731352_24675\\",\\"24.984, 42, 37, 16.984\\",\\"24.984, 42, 37, 16.984\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Tigress Enterprises, Gnomehouse, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises, Gnomehouse, Tigress Enterprises\\",\\"13.492, 22.25, 18.859, 8.492\\",\\"24.984, 42, 37, 16.984\\",\\"12,880, 5,477, 13,837, 24,675\\",\\"Ankle boots - blue, Over-the-knee boots - taupe, Mini skirt - multicoloured, Vest - black\\",\\"Ankle boots - blue, Over-the-knee boots - taupe, Mini skirt - multicoloured, Vest - black\\",\\"1, 1, 1, 1\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\",\\"0, 0, 0, 0\\",\\"24.984, 42, 37, 16.984\\",\\"24.984, 42, 37, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0018200182, ZO0016100161, ZO0329703297, ZO0057800578\\",\\"120.938\\",\\"120.938\\",4,4,order,wilhemina +BwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Graham\\",\\"Fitzgerald Graham\\",MALE,11,Graham,Graham,\\"(empty)\\",Monday,0,\\"fitzgerald@graham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565667,\\"sold_product_565667_19066, sold_product_565667_22279\\",\\"sold_product_565667_19066, sold_product_565667_22279\\",\\"18.984, 50\\",\\"18.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"8.547, 23.5\\",\\"18.984, 50\\",\\"19,066, 22,279\\",\\"Tights - black, Casual lace-ups - Sea Green\\",\\"Tights - black, Casual lace-ups - Sea Green\\",\\"1, 1\\",\\"ZO0618706187, ZO0388503885\\",\\"0, 0\\",\\"18.984, 50\\",\\"18.984, 50\\",\\"0, 0\\",\\"ZO0618706187, ZO0388503885\\",69,69,2,2,order,fuzzy +UgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Sutton\\",\\"Abigail Sutton\\",FEMALE,46,Sutton,Sutton,\\"(empty)\\",Monday,0,\\"abigail@sutton-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565900,\\"sold_product_565900_17711, sold_product_565900_14662\\",\\"sold_product_565900_17711, sold_product_565900_14662\\",\\"34, 16.984\\",\\"34, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"18.016, 8.492\\",\\"34, 16.984\\",\\"17,711, 14,662\\",\\"Blouse - black, Print T-shirt - black\\",\\"Blouse - black, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0266102661, ZO0169701697\\",\\"0, 0\\",\\"34, 16.984\\",\\"34, 16.984\\",\\"0, 0\\",\\"ZO0266102661, ZO0169701697\\",\\"50.969\\",\\"50.969\\",2,2,order,abigail +qgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Rose\\",\\"Boris Rose\\",MALE,36,Rose,Rose,\\"(empty)\\",Monday,0,\\"boris@rose-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566360,\\"sold_product_566360_15319, sold_product_566360_10913\\",\\"sold_product_566360_15319, sold_product_566360_10913\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"15.844, 6.039\\",\\"33, 10.992\\",\\"15,319, 10,913\\",\\"Relaxed fit jeans - grey denim, Long sleeved top - grey/dark blue\\",\\"Relaxed fit jeans - grey denim, Long sleeved top - grey/dark blue\\",\\"1, 1\\",\\"ZO0285102851, ZO0658306583\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0285102851, ZO0658306583\\",\\"43.969\\",\\"43.969\\",2,2,order,boris +qwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Soto\\",\\"Abdulraheem Al Soto\\",MALE,33,Soto,Soto,\\"(empty)\\",Monday,0,\\"abdulraheem al@soto-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566416,\\"sold_product_566416_17928, sold_product_566416_24672\\",\\"sold_product_566416_17928, sold_product_566416_24672\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23.5, 9.898\\",\\"50, 21.984\\",\\"17,928, 24,672\\",\\"Boots - dark brown, Across body bag - black/cognac\\",\\"Boots - dark brown, Across body bag - black/cognac\\",\\"1, 1\\",\\"ZO0396903969, ZO0607906079\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0396903969, ZO0607906079\\",72,72,2,2,order,abdulraheem +IgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hansen\\",\\"Abigail Hansen\\",FEMALE,46,Hansen,Hansen,\\"(empty)\\",Monday,0,\\"abigail@hansen-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565796,\\"sold_product_565796_11879, sold_product_565796_8405\\",\\"sold_product_565796_11879, sold_product_565796_8405\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"4.23, 14.852\\",\\"7.988, 33\\",\\"11,879, 8,405\\",\\"Snood - offwhite/red/black, Long sleeved top - alison white\\",\\"Snood - offwhite/red/black, Long sleeved top - alison white\\",\\"1, 1\\",\\"ZO0081500815, ZO0342603426\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0081500815, ZO0342603426\\",\\"40.969\\",\\"40.969\\",2,2,order,abigail +IwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Sherman\\",\\"Samir Sherman\\",MALE,34,Sherman,Sherman,\\"(empty)\\",Monday,0,\\"samir@sherman-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566261,\\"sold_product_566261_20514, sold_product_566261_13193\\",\\"sold_product_566261_20514, sold_product_566261_13193\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.5, 42.5\\",\\"24.984, 85\\",\\"20,514, 13,193\\",\\"Jumper - black, Parka - black\\",\\"Jumper - black, Parka - black\\",\\"1, 1\\",\\"ZO0577105771, ZO0289302893\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0577105771, ZO0289302893\\",110,110,2,2,order,samir +QgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Daniels\\",\\"Robbie Daniels\\",MALE,48,Daniels,Daniels,\\"(empty)\\",Monday,0,\\"robbie@daniels-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565567,\\"sold_product_565567_18531, sold_product_565567_11331\\",\\"sold_product_565567_18531, sold_product_565567_11331\\",\\"11.992, 18.984\\",\\"11.992, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"5.398, 8.93\\",\\"11.992, 18.984\\",\\"18,531, 11,331\\",\\"Basic T-shirt - tan, Tracksuit bottoms - black\\",\\"Basic T-shirt - tan, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0437604376, ZO0618906189\\",\\"0, 0\\",\\"11.992, 18.984\\",\\"11.992, 18.984\\",\\"0, 0\\",\\"ZO0437604376, ZO0618906189\\",\\"30.984\\",\\"30.984\\",2,2,order,robbie +QwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Byrd\\",\\"Brigitte Byrd\\",FEMALE,12,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"brigitte@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565596,\\"sold_product_565596_19599, sold_product_565596_13051\\",\\"sold_product_565596_19599, sold_product_565596_13051\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"25.484, 7\\",\\"50, 13.992\\",\\"19,599, 13,051\\",\\"Maxi dress - Pale Violet Red, Print T-shirt - black\\",\\"Maxi dress - Pale Violet Red, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0332903329, ZO0159401594\\",\\"0, 0\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"0, 0\\",\\"ZO0332903329, ZO0159401594\\",\\"63.969\\",\\"63.969\\",2,2,order,brigitte +VgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Abd,Abd,\\"Abd Foster\\",\\"Abd Foster\\",MALE,52,Foster,Foster,\\"(empty)\\",Monday,0,\\"abd@foster-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence, Angeldale\\",\\"Low Tide Media, Elitelligence, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",717206,\\"sold_product_717206_13588, sold_product_717206_16372, sold_product_717206_20757, sold_product_717206_22434\\",\\"sold_product_717206_13588, sold_product_717206_16372, sold_product_717206_20757, sold_product_717206_22434\\",\\"60, 24.984, 80, 60\\",\\"60, 24.984, 80, 60\\",\\"Men's Shoes, Women's Accessories, Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Women's Accessories, Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Angeldale, Low Tide Media\\",\\"Low Tide Media, Elitelligence, Angeldale, Low Tide Media\\",\\"28.797, 12.742, 40.781, 30\\",\\"60, 24.984, 80, 60\\",\\"13,588, 16,372, 20,757, 22,434\\",\\"Lace-ups - cognac, Rucksack - black, Lace-up boots - dark brown, Casual lace-ups - cognac\\",\\"Lace-ups - cognac, Rucksack - black, Lace-up boots - dark brown, Casual lace-ups - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\",\\"0, 0, 0, 0\\",\\"60, 24.984, 80, 60\\",\\"60, 24.984, 80, 60\\",\\"0, 0, 0, 0\\",\\"ZO0390403904, ZO0608306083, ZO0690906909, ZO0394403944\\",225,225,4,4,order,abd +ggMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Bailey\\",\\"Abd Bailey\\",MALE,52,Bailey,Bailey,\\"(empty)\\",Monday,0,\\"abd@bailey-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715081,\\"sold_product_715081_20855, sold_product_715081_15922, sold_product_715081_6851, sold_product_715081_1808\\",\\"sold_product_715081_20855, sold_product_715081_15922, sold_product_715081_6851, sold_product_715081_1808\\",\\"65, 65, 24.984, 50\\",\\"65, 65, 24.984, 50\\",\\"Men's Shoes, Men's Shoes, Men's Clothing, Men's Shoes\\",\\"Men's Shoes, Men's Shoes, Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"Angeldale, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"29.906, 32.5, 12.492, 23\\",\\"65, 65, 24.984, 50\\",\\"20,855, 15,922, 6,851, 1,808\\",\\"Lace-up boots - black, Lace-up boots - cognac, SLIM FIT - Formal shirt - dark blue, Lace-up boots - black\\",\\"Lace-up boots - black, Lace-up boots - cognac, SLIM FIT - Formal shirt - dark blue, Lace-up boots - black\\",\\"1, 1, 1, 1\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\",\\"0, 0, 0, 0\\",\\"65, 65, 24.984, 50\\",\\"65, 65, 24.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0688806888, ZO0399003990, ZO0412404124, ZO0405304053\\",205,205,4,4,order,abd +mwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Davidson\\",\\"Mary Davidson\\",FEMALE,20,Davidson,Davidson,\\"(empty)\\",Monday,0,\\"mary@davidson-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566428,\\"sold_product_566428_20712, sold_product_566428_18581\\",\\"sold_product_566428_20712, sold_product_566428_18581\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"15.07, 24\\",\\"28.984, 50\\",\\"20,712, 18,581\\",\\"Trainers - black, Summer dress - red ochre\\",\\"Trainers - black, Summer dress - red ochre\\",\\"1, 1\\",\\"ZO0136501365, ZO0339103391\\",\\"0, 0\\",\\"28.984, 50\\",\\"28.984, 50\\",\\"0, 0\\",\\"ZO0136501365, ZO0339103391\\",79,79,2,2,order,mary +zQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Pope\\",\\"Pia Pope\\",FEMALE,45,Pope,Pope,\\"(empty)\\",Monday,0,\\"pia@pope-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566334,\\"sold_product_566334_17905, sold_product_566334_24273\\",\\"sold_product_566334_17905, sold_product_566334_24273\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"14.781, 6.469\\",\\"28.984, 11.992\\",\\"17,905, 24,273\\",\\"High heeled sandals - Rosy Brown, Jersey dress - beige\\",\\"High heeled sandals - Rosy Brown, Jersey dress - beige\\",\\"1, 1\\",\\"ZO0010800108, ZO0635706357\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0010800108, ZO0635706357\\",\\"40.969\\",\\"40.969\\",2,2,order,pia +zgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Jacobs\\",\\"Elyssa Jacobs\\",FEMALE,27,Jacobs,Jacobs,\\"(empty)\\",Monday,0,\\"elyssa@jacobs-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566391,\\"sold_product_566391_15927, sold_product_566391_15841\\",\\"sold_product_566391_15927, sold_product_566391_15841\\",\\"33, 13.992\\",\\"33, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"Tigress Enterprises MAMA, Pyramidustries\\",\\"15.18, 6.719\\",\\"33, 13.992\\",\\"15,927, 15,841\\",\\"Jersey dress - peacoat, Long sleeved top - black\\",\\"Jersey dress - peacoat, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0228302283, ZO0167501675\\",\\"0, 0\\",\\"33, 13.992\\",\\"33, 13.992\\",\\"0, 0\\",\\"ZO0228302283, ZO0167501675\\",\\"46.969\\",\\"46.969\\",2,2,order,elyssa +IQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Adams\\",\\"Sultan Al Adams\\",MALE,19,Adams,Adams,\\"(empty)\\",Monday,0,\\"sultan al@adams-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715133,\\"sold_product_715133_22059, sold_product_715133_13763, sold_product_715133_19774, sold_product_715133_15185\\",\\"sold_product_715133_22059, sold_product_715133_13763, sold_product_715133_19774, sold_product_715133_15185\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"15.07, 9.344, 5.879, 11.5\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"22,059, 13,763, 19,774, 15,185\\",\\"Relaxed fit jeans - black, Trainers - dark brown, Print T-shirt - black/orange, Tracksuit bottoms - mottled grey\\",\\"Relaxed fit jeans - black, Trainers - dark brown, Print T-shirt - black/orange, Tracksuit bottoms - mottled grey\\",\\"1, 1, 1, 1\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\",\\"0, 0, 0, 0\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"28.984, 16.984, 11.992, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0537005370, ZO0508605086, ZO0566605666, ZO0111301113\\",\\"82.938\\",\\"82.938\\",4,4,order,sultan +QAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Barnes\\",\\"Abd Barnes\\",MALE,52,Barnes,Barnes,\\"(empty)\\",Monday,0,\\"abd@barnes-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",717057,\\"sold_product_717057_18764, sold_product_717057_1195, sold_product_717057_13086, sold_product_717057_13470\\",\\"sold_product_717057_18764, sold_product_717057_1195, sold_product_717057_13086, sold_product_717057_13470\\",\\"65, 60, 50, 15.992\\",\\"65, 60, 50, 15.992\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spritechnologies, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"Spritechnologies, Low Tide Media, Low Tide Media, Low Tide Media\\",\\"30.547, 28.203, 23, 8.313\\",\\"65, 60, 50, 15.992\\",\\"18,764, 1,195, 13,086, 13,470\\",\\"Winter jacket - rubber, Lace-up boots - cognac, Casual lace-ups - light brown, 4 PACK - Shorts - grey\\",\\"Winter jacket - rubber, Lace-up boots - cognac, Casual lace-ups - light brown, 4 PACK - Shorts - grey\\",\\"1, 1, 1, 1\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\",\\"0, 0, 0, 0\\",\\"65, 60, 50, 15.992\\",\\"65, 60, 50, 15.992\\",\\"0, 0, 0, 0\\",\\"ZO0623406234, ZO0404704047, ZO0384603846, ZO0476204762\\",191,191,4,4,order,abd +SQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Parker\\",\\"Diane Parker\\",FEMALE,22,Parker,Parker,\\"(empty)\\",Monday,0,\\"diane@parker-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Karmanite, Pyramidustries\\",\\"Karmanite, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566315,\\"sold_product_566315_11724, sold_product_566315_18465\\",\\"sold_product_566315_11724, sold_product_566315_18465\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Karmanite, Pyramidustries\\",\\"Karmanite, Pyramidustries\\",\\"33.125, 19.313\\",\\"65, 42\\",\\"11,724, 18,465\\",\\"Sandals - black, Boots - black\\",\\"Sandals - black, Boots - black\\",\\"1, 1\\",\\"ZO0703707037, ZO0139601396\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0703707037, ZO0139601396\\",107,107,2,2,order,diane +SgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cross\\",\\"Abigail Cross\\",FEMALE,46,Cross,Cross,\\"(empty)\\",Monday,0,\\"abigail@cross-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565698,\\"sold_product_565698_13951, sold_product_565698_21969\\",\\"sold_product_565698_13951, sold_product_565698_21969\\",\\"50, 7.988\\",\\"50, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"26.484, 3.68\\",\\"50, 7.988\\",\\"13,951, 21,969\\",\\"Summer dress - black, Vest - bordeaux\\",\\"Summer dress - black, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0336503365, ZO0637006370\\",\\"0, 0\\",\\"50, 7.988\\",\\"50, 7.988\\",\\"0, 0\\",\\"ZO0336503365, ZO0637006370\\",\\"57.969\\",\\"57.969\\",2,2,order,abigail +UQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Valdez\\",\\"Wagdi Valdez\\",MALE,15,Valdez,Valdez,\\"(empty)\\",Monday,0,\\"wagdi@valdez-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566167,\\"sold_product_566167_3499, sold_product_566167_13386\\",\\"sold_product_566167_3499, sold_product_566167_13386\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"28.203, 11.75\\",\\"60, 24.984\\",\\"3,499, 13,386\\",\\"Hardshell jacket - jet black, Trousers - black\\",\\"Hardshell jacket - jet black, Trousers - black\\",\\"1, 1\\",\\"ZO0623006230, ZO0419304193\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0623006230, ZO0419304193\\",85,85,2,2,order,wagdi +UgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Rivera\\",\\"Mostafa Rivera\\",MALE,9,Rivera,Rivera,\\"(empty)\\",Monday,0,\\"mostafa@rivera-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566215,\\"sold_product_566215_864, sold_product_566215_23260\\",\\"sold_product_566215_864, sold_product_566215_23260\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23.5, 13.742\\",\\"50, 24.984\\",\\"864, 23,260\\",\\"Smart lace-ups - brown, Jumper - khaki\\",\\"Smart lace-ups - brown, Jumper - khaki\\",\\"1, 1\\",\\"ZO0384903849, ZO0579305793\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0384903849, ZO0579305793\\",75,75,2,2,order,mostafa +UwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Underwood\\",\\"Mary Underwood\\",FEMALE,20,Underwood,Underwood,\\"(empty)\\",Monday,0,\\"mary@underwood-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566070,\\"sold_product_566070_23447, sold_product_566070_17406\\",\\"sold_product_566070_23447, sold_product_566070_17406\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"17.813, 16.813\\",\\"33, 33\\",\\"23,447, 17,406\\",\\"Cocktail dress / Party dress - black, Summer dress - black\\",\\"Cocktail dress / Party dress - black, Summer dress - black\\",\\"1, 1\\",\\"ZO0046100461, ZO0151201512\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0046100461, ZO0151201512\\",66,66,2,2,order,mary +VAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jason,Jason,\\"Jason Jimenez\\",\\"Jason Jimenez\\",MALE,16,Jimenez,Jimenez,\\"(empty)\\",Monday,0,\\"jason@jimenez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566621,\\"sold_product_566621_21825, sold_product_566621_21628\\",\\"sold_product_566621_21825, sold_product_566621_21628\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.906, 33.75\\",\\"20.984, 75\\",\\"21,825, 21,628\\",\\"Jumper - khaki, Weekend bag - black\\",\\"Jumper - khaki, Weekend bag - black\\",\\"1, 1\\",\\"ZO0579605796, ZO0315803158\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0579605796, ZO0315803158\\",96,96,2,2,order,jason +VQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Miller\\",\\"Youssef Miller\\",MALE,31,Miller,Miller,\\"(empty)\\",Monday,0,\\"youssef@miller-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566284,\\"sold_product_566284_6763, sold_product_566284_11234\\",\\"sold_product_566284_6763, sold_product_566284_11234\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9, 21.828\\",\\"16.984, 42\\",\\"6,763, 11,234\\",\\"Jumper - black, Tracksuit top - black\\",\\"Jumper - black, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0541405414, ZO0588205882\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0541405414, ZO0588205882\\",\\"58.969\\",\\"58.969\\",2,2,order,youssef +VgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Byrd\\",\\"Thad Byrd\\",MALE,30,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"thad@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566518,\\"sold_product_566518_22342, sold_product_566518_14729\\",\\"sold_product_566518_22342, sold_product_566518_14729\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.762, 5.641\\",\\"11.992, 11.992\\",\\"22,342, 14,729\\",\\"Long sleeved top - mottled grey black, Long sleeved top - black\\",\\"Long sleeved top - mottled grey black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0554605546, ZO0569005690\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",\\"ZO0554605546, ZO0569005690\\",\\"23.984\\",\\"23.984\\",2,2,order,thad +agMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Byrd\\",\\"Tariq Byrd\\",MALE,25,Byrd,Byrd,\\"(empty)\\",Monday,0,\\"tariq@byrd-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565580,\\"sold_product_565580_1927, sold_product_565580_12828\\",\\"sold_product_565580_1927, sold_product_565580_12828\\",\\"60, 60\\",\\"60, 60\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"28.203, 29.406\\",\\"60, 60\\",\\"1,927, 12,828\\",\\"High-top trainers - nyco, Lace-ups - marron\\",\\"High-top trainers - nyco, Lace-ups - marron\\",\\"1, 1\\",\\"ZO0395303953, ZO0386703867\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0395303953, ZO0386703867\\",120,120,2,2,order,tariq +cwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Valdez\\",\\"rania Valdez\\",FEMALE,24,Valdez,Valdez,\\"(empty)\\",Monday,0,\\"rania@valdez-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565830,\\"sold_product_565830_17256, sold_product_565830_23136\\",\\"sold_product_565830_17256, sold_product_565830_23136\\",\\"7.988, 7.988\\",\\"7.988, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"4.148, 4.309\\",\\"7.988, 7.988\\",\\"17,256, 23,136\\",\\"3 PACK - Socks - off white/pink, Basic T-shirt - purple\\",\\"3 PACK - Socks - off white/pink, Basic T-shirt - purple\\",\\"1, 1\\",\\"ZO0215702157, ZO0638806388\\",\\"0, 0\\",\\"7.988, 7.988\\",\\"7.988, 7.988\\",\\"0, 0\\",\\"ZO0215702157, ZO0638806388\\",\\"15.977\\",\\"15.977\\",2,2,order,rani +GQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jason,Jason,\\"Jason Morrison\\",\\"Jason Morrison\\",MALE,16,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"jason@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566454,\\"sold_product_566454_15937, sold_product_566454_1557\\",\\"sold_product_566454_15937, sold_product_566454_1557\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.84, 31.188\\",\\"7.988, 60\\",\\"15,937, 1,557\\",\\"Basic T-shirt - dark grey, Lace-up boots - brown\\",\\"Basic T-shirt - dark grey, Lace-up boots - brown\\",\\"1, 1\\",\\"ZO0547405474, ZO0401104011\\",\\"0, 0\\",\\"7.988, 60\\",\\"7.988, 60\\",\\"0, 0\\",\\"ZO0547405474, ZO0401104011\\",68,68,2,2,order,jason +GgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Thad,Thad,\\"Thad Larson\\",\\"Thad Larson\\",MALE,30,Larson,Larson,\\"(empty)\\",Monday,0,\\"thad@larson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566506,\\"sold_product_566506_12060, sold_product_566506_16803\\",\\"sold_product_566506_12060, sold_product_566506_16803\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"25.984, 8.492\\",\\"50, 16.984\\",\\"12,060, 16,803\\",\\"Lace-ups - black/red, Rucksack - grey/black\\",\\"Lace-ups - black/red, Rucksack - grey/black\\",\\"1, 1\\",\\"ZO0680806808, ZO0609306093\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0680806808, ZO0609306093\\",67,67,2,2,order,thad +HAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Romero\\",\\"Diane Romero\\",FEMALE,22,Romero,Romero,\\"(empty)\\",Monday,0,\\"diane@romero-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565948,\\"sold_product_565948_18390, sold_product_565948_24310\\",\\"sold_product_565948_18390, sold_product_565948_24310\\",\\"10.992, 22.984\\",\\"10.992, 22.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"5.93, 10.578\\",\\"10.992, 22.984\\",\\"18,390, 24,310\\",\\"Wallet - black, Jumper - light grey multicolor\\",\\"Wallet - black, Jumper - light grey multicolor\\",\\"1, 1\\",\\"ZO0190701907, ZO0654806548\\",\\"0, 0\\",\\"10.992, 22.984\\",\\"10.992, 22.984\\",\\"0, 0\\",\\"ZO0190701907, ZO0654806548\\",\\"33.969\\",\\"33.969\\",2,2,order,diane +HQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Morrison\\",\\"Gwen Morrison\\",FEMALE,26,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"gwen@morrison-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565998,\\"sold_product_565998_15531, sold_product_565998_8992\\",\\"sold_product_565998_15531, sold_product_565998_8992\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"29.906, 10.703\\",\\"65, 20.984\\",\\"15,531, 8,992\\",\\"Classic heels - black, Blouse - black\\",\\"Classic heels - black, Blouse - black\\",\\"1, 1\\",\\"ZO0238802388, ZO0066600666\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0238802388, ZO0066600666\\",86,86,2,2,order,gwen +kAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Reese\\",\\"Elyssa Reese\\",FEMALE,27,Reese,Reese,\\"(empty)\\",Monday,0,\\"elyssa@reese-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565401,\\"sold_product_565401_24966, sold_product_565401_14951\\",\\"sold_product_565401_24966, sold_product_565401_14951\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"21.828, 11.75\\",\\"42, 24.984\\",\\"24,966, 14,951\\",\\"High heeled boots - black, Jersey dress - black\\",\\"High heeled boots - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0014800148, ZO0154501545\\",\\"0, 0\\",\\"42, 24.984\\",\\"42, 24.984\\",\\"0, 0\\",\\"ZO0014800148, ZO0154501545\\",67,67,2,2,order,elyssa +MQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hopkins\\",\\"Elyssa Hopkins\\",FEMALE,27,Hopkins,Hopkins,\\"(empty)\\",Monday,0,\\"elyssa@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565728,\\"sold_product_565728_22660, sold_product_565728_17747\\",\\"sold_product_565728_22660, sold_product_565728_17747\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"11.117, 38.25\\",\\"20.984, 75\\",\\"22,660, 17,747\\",\\"Tracksuit bottoms - dark grey multicolor, Ankle boots - black\\",\\"Tracksuit bottoms - dark grey multicolor, Ankle boots - black\\",\\"1, 1\\",\\"ZO0486404864, ZO0248602486\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0486404864, ZO0248602486\\",96,96,2,2,order,elyssa +DQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Craig\\",\\"Rabbia Al Craig\\",FEMALE,5,Craig,Craig,\\"(empty)\\",Monday,0,\\"rabbia al@craig-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565489,\\"sold_product_565489_17610, sold_product_565489_23396\\",\\"sold_product_565489_17610, sold_product_565489_23396\\",\\"13.992, 7.988\\",\\"13.992, 7.988\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"7.41, 3.6\\",\\"13.992, 7.988\\",\\"17,610, 23,396\\",\\"Belt - black, Vest - black\\",\\"Belt - black, Vest - black\\",\\"1, 1\\",\\"ZO0077200772, ZO0643006430\\",\\"0, 0\\",\\"13.992, 7.988\\",\\"13.992, 7.988\\",\\"0, 0\\",\\"ZO0077200772, ZO0643006430\\",\\"21.984\\",\\"21.984\\",2,2,order,rabbia +EAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Padilla\\",\\"Abdulraheem Al Padilla\\",MALE,33,Padilla,Padilla,\\"(empty)\\",Monday,0,\\"abdulraheem al@padilla-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565366,\\"sold_product_565366_2077, sold_product_565366_14547\\",\\"sold_product_565366_2077, sold_product_565366_14547\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"37.5, 12.25\\",\\"75, 24.984\\",\\"2,077, 14,547\\",\\"Trainers - black, Jumper - camel/black\\",\\"Trainers - black, Jumper - camel/black\\",\\"1, 1\\",\\"ZO0684906849, ZO0575905759\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0684906849, ZO0575905759\\",100,100,2,2,order,abdulraheem +xwMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Gilbert\\",\\"Tariq Gilbert\\",MALE,25,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"tariq@gilbert-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",720445,\\"sold_product_720445_22855, sold_product_720445_19704, sold_product_720445_12699, sold_product_720445_13347\\",\\"sold_product_720445_22855, sold_product_720445_19704, sold_product_720445_12699, sold_product_720445_13347\\",\\"22.984, 13.992, 42, 11.992\\",\\"22.984, 13.992, 42, 11.992\\",\\"Men's Clothing, Men's Clothing, Women's Accessories, Women's Accessories\\",\\"Men's Clothing, Men's Clothing, Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Oceanavigations, Oceanavigations, Oceanavigations\\",\\"Low Tide Media, Oceanavigations, Oceanavigations, Oceanavigations\\",\\"10.813, 6.859, 22.672, 6.23\\",\\"22.984, 13.992, 42, 11.992\\",\\"22,855, 19,704, 12,699, 13,347\\",\\"Shorts - black, Print T-shirt - grey multicolor, Weekend bag - dessert, Sunglasses - black\\",\\"Shorts - black, Print T-shirt - grey multicolor, Weekend bag - dessert, Sunglasses - black\\",\\"1, 1, 1, 1\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\",\\"0, 0, 0, 0\\",\\"22.984, 13.992, 42, 11.992\\",\\"22.984, 13.992, 42, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0423004230, ZO0292702927, ZO0320003200, ZO0318303183\\",\\"90.938\\",\\"90.938\\",4,4,order,tariq +0wMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Graham\\",\\"Youssef Graham\\",MALE,31,Graham,Graham,\\"(empty)\\",Monday,0,\\"youssef@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565768,\\"sold_product_565768_19338, sold_product_565768_19206\\",\\"sold_product_565768_19338, sold_product_565768_19206\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"12.18, 15.18\\",\\"22.984, 33\\",\\"19,338, 19,206\\",\\"Sweatshirt - dark grey multicolor, Suit trousers - navy\\",\\"Sweatshirt - dark grey multicolor, Suit trousers - navy\\",\\"1, 1\\",\\"ZO0458004580, ZO0273402734\\",\\"0, 0\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"0, 0\\",\\"ZO0458004580, ZO0273402734\\",\\"55.969\\",\\"55.969\\",2,2,order,youssef +7gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Harvey\\",\\"Gwen Harvey\\",FEMALE,26,Harvey,Harvey,\\"(empty)\\",Monday,0,\\"gwen@harvey-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565538,\\"sold_product_565538_23676, sold_product_565538_16054\\",\\"sold_product_565538_23676, sold_product_565538_16054\\",\\"24.984, 55\\",\\"24.984, 55\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"12.25, 25.297\\",\\"24.984, 55\\",\\"23,676, 16,054\\",\\"Slim fit jeans - brown, Platform sandals - black\\",\\"Slim fit jeans - brown, Platform sandals - black\\",\\"1, 1\\",\\"ZO0486804868, ZO0371603716\\",\\"0, 0\\",\\"24.984, 55\\",\\"24.984, 55\\",\\"0, 0\\",\\"ZO0486804868, ZO0371603716\\",80,80,2,2,order,gwen +\\"-wMtOW0BH63Xcmy45Wq4\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Gilbert\\",\\"Brigitte Gilbert\\",FEMALE,12,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"brigitte@gilbert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565404,\\"sold_product_565404_23482, sold_product_565404_19328\\",\\"sold_product_565404_23482, sold_product_565404_19328\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"22.672, 17.813\\",\\"42, 33\\",\\"23,482, 19,328\\",\\"Cocktail dress / Party dress - pomegranate/black, Shift dress - black/champagne\\",\\"Cocktail dress / Party dress - pomegranate/black, Shift dress - black/champagne\\",\\"1, 1\\",\\"ZO0048900489, ZO0228702287\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0048900489, ZO0228702287\\",75,75,2,2,order,brigitte +EwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Jimenez\\",\\"Sultan Al Jimenez\\",MALE,19,Jimenez,Jimenez,\\"(empty)\\",Monday,0,\\"sultan al@jimenez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",715961,\\"sold_product_715961_18507, sold_product_715961_19182, sold_product_715961_17545, sold_product_715961_15806\\",\\"sold_product_715961_18507, sold_product_715961_19182, sold_product_715961_17545, sold_product_715961_15806\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Oceanavigations, Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Oceanavigations, Low Tide Media, Low Tide Media\\",\\"11.25, 8.156, 4.148, 7.27\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"18,507, 19,182, 17,545, 15,806\\",\\"Vibrant Pattern Polo, Print T-shirt - light grey multicolor, Basic T-shirt - blue multicolor, Belt - dark brown\\",\\"Vibrant Pattern Polo, Print T-shirt - light grey multicolor, Basic T-shirt - blue multicolor, Belt - dark brown\\",\\"1, 1, 1, 1\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\",\\"0, 0, 0, 0\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"24.984, 16.984, 7.988, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0444904449, ZO0292502925, ZO0434604346, ZO0461804618\\",\\"63.969\\",\\"63.969\\",4,4,order,sultan +VwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Wise\\",\\"Rabbia Al Wise\\",FEMALE,5,Wise,Wise,\\"(empty)\\",Monday,0,\\"rabbia al@wise-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566382,\\"sold_product_566382_15477, sold_product_566382_20551\\",\\"sold_product_566382_15477, sold_product_566382_20551\\",\\"18.984, 65\\",\\"18.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"9.68, 33.781\\",\\"18.984, 65\\",\\"15,477, 20,551\\",\\"Sweatshirt - black, Lace-ups - Purple\\",\\"Sweatshirt - black, Lace-ups - Purple\\",\\"1, 1\\",\\"ZO0503505035, ZO0240302403\\",\\"0, 0\\",\\"18.984, 65\\",\\"18.984, 65\\",\\"0, 0\\",\\"ZO0503505035, ZO0240302403\\",84,84,2,2,order,rabbia +XgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Frances,Frances,\\"Frances Salazar\\",\\"Frances Salazar\\",FEMALE,49,Salazar,Salazar,\\"(empty)\\",Monday,0,\\"frances@salazar-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Microlutions,Microlutions,\\"Jun 23, 2019 @ 00:00:00.000\\",565877,\\"sold_product_565877_20689, sold_product_565877_19983\\",\\"sold_product_565877_20689, sold_product_565877_19983\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"15.18, 15.07\\",\\"33, 28.984\\",\\"20,689, 19,983\\",\\"Sweatshirt - light grey, Sweatshirt - black\\",\\"Sweatshirt - light grey, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0125401254, ZO0123701237\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0125401254, ZO0123701237\\",\\"61.969\\",\\"61.969\\",2,2,order,frances +bgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Farmer\\",\\"Robbie Farmer\\",MALE,48,Farmer,Farmer,\\"(empty)\\",Monday,0,\\"robbie@farmer-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566364,\\"sold_product_566364_15434, sold_product_566364_15384\\",\\"sold_product_566364_15434, sold_product_566364_15384\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"16.813, 17.156\\",\\"33, 33\\",\\"15,434, 15,384\\",\\"High-top trainers - black, Denim jacket - grey\\",\\"High-top trainers - black, Denim jacket - grey\\",\\"1, 1\\",\\"ZO0512505125, ZO0525005250\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0512505125, ZO0525005250\\",66,66,2,2,order,robbie +vwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Robbie,Robbie,\\"Robbie Holland\\",\\"Robbie Holland\\",MALE,48,Holland,Holland,\\"(empty)\\",Monday,0,\\"robbie@holland-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565479,\\"sold_product_565479_16738, sold_product_565479_14474\\",\\"sold_product_565479_16738, sold_product_565479_14474\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.539, 34.438\\",\\"20.984, 65\\",\\"16,738, 14,474\\",\\"Tracksuit top - red, Briefcase - dark brown\\",\\"Tracksuit top - red, Briefcase - dark brown\\",\\"1, 1\\",\\"ZO0588805888, ZO0314903149\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0588805888, ZO0314903149\\",86,86,2,2,order,robbie +wwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Butler\\",\\"Mostafa Butler\\",MALE,9,Butler,Butler,\\"(empty)\\",Monday,0,\\"mostafa@butler-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565360,\\"sold_product_565360_11937, sold_product_565360_6497\\",\\"sold_product_565360_11937, sold_product_565360_6497\\",\\"33, 60\\",\\"33, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"18.141, 31.188\\",\\"33, 60\\",\\"11,937, 6,497\\",\\"Jumper - navy, Colorful Cardigan\\",\\"Jumper - navy, Colorful Cardigan\\",\\"1, 1\\",\\"ZO0448604486, ZO0450704507\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0448604486, ZO0450704507\\",93,93,2,2,order,mostafa +zwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Perkins\\",\\"Kamal Perkins\\",MALE,39,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"kamal@perkins-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565734,\\"sold_product_565734_23476, sold_product_565734_15158\\",\\"sold_product_565734_23476, sold_product_565734_15158\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"12.492, 33.125\\",\\"24.984, 65\\",\\"23,476, 15,158\\",\\"High-top trainers - allblack, Boots - grey\\",\\"High-top trainers - allblack, Boots - grey\\",\\"1, 1\\",\\"ZO0513205132, ZO0258202582\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0513205132, ZO0258202582\\",90,90,2,2,order,kamal +gAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Powell\\",\\"Sultan Al Powell\\",MALE,19,Powell,Powell,\\"(empty)\\",Monday,0,\\"sultan al@powell-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Elitelligence,Elitelligence,\\"Jun 23, 2019 @ 00:00:00.000\\",566514,\\"sold_product_566514_6827, sold_product_566514_11745\\",\\"sold_product_566514_6827, sold_product_566514_11745\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.156, 5.281\\",\\"33, 10.992\\",\\"6,827, 11,745\\",\\"Denim jacket - black denim, T-bar sandals - black/orange\\",\\"Denim jacket - black denim, T-bar sandals - black/orange\\",\\"1, 1\\",\\"ZO0539305393, ZO0522305223\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0539305393, ZO0522305223\\",\\"43.969\\",\\"43.969\\",2,2,order,sultan +gQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Summers\\",\\"Clarice Summers\\",FEMALE,18,Summers,Summers,\\"(empty)\\",Monday,0,\\"clarice@summers-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565970,\\"sold_product_565970_25000, sold_product_565970_20678\\",\\"sold_product_565970_25000, sold_product_565970_20678\\",\\"85, 16.984\\",\\"85, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"40.813, 7.82\\",\\"85, 16.984\\",\\"25,000, 20,678\\",\\"Ankle boots - setter, Long sleeved top - black\\",\\"Ankle boots - setter, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0673406734, ZO0165601656\\",\\"0, 0\\",\\"85, 16.984\\",\\"85, 16.984\\",\\"0, 0\\",\\"ZO0673406734, ZO0165601656\\",102,102,2,2,order,clarice +kgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Richards\\",\\"Elyssa Richards\\",FEMALE,27,Richards,Richards,\\"(empty)\\",Monday,0,\\"elyssa@richards-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Spherecords, Tigress Enterprises\\",\\"Oceanavigations, Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",723242,\\"sold_product_723242_5979, sold_product_723242_12451, sold_product_723242_13462, sold_product_723242_14976\\",\\"sold_product_723242_5979, sold_product_723242_12451, sold_product_723242_13462, sold_product_723242_14976\\",\\"75, 7.988, 24.984, 16.984\\",\\"75, 7.988, 24.984, 16.984\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Spherecords, Tigress Enterprises, Spherecords\\",\\"Oceanavigations, Spherecords, Tigress Enterprises, Spherecords\\",\\"33.75, 3.68, 11.75, 9.172\\",\\"75, 7.988, 24.984, 16.984\\",\\"5,979, 12,451, 13,462, 14,976\\",\\"Ankle boots - Antique White, Vest - black, Handbag - cognac , Mini skirt - dark blue\\",\\"Ankle boots - Antique White, Vest - black, Handbag - cognac , Mini skirt - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\",\\"0, 0, 0, 0\\",\\"75, 7.988, 24.984, 16.984\\",\\"75, 7.988, 24.984, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0249702497, ZO0643306433, ZO0088900889, ZO0634406344\\",\\"124.938\\",\\"124.938\\",4,4,order,elyssa +mAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Cook\\",\\"Abd Cook\\",MALE,52,Cook,Cook,\\"(empty)\\",Monday,0,\\"abd@cook-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",720399,\\"sold_product_720399_11133, sold_product_720399_24282, sold_product_720399_1435, sold_product_720399_13054\\",\\"sold_product_720399_11133, sold_product_720399_24282, sold_product_720399_1435, sold_product_720399_13054\\",\\"24.984, 7.988, 75, 24.984\\",\\"24.984, 7.988, 75, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence, Low Tide Media, Elitelligence\\",\\"12.25, 4.148, 34.5, 13.742\\",\\"24.984, 7.988, 75, 24.984\\",\\"11,133, 24,282, 1,435, 13,054\\",\\"Smart lace-ups - black, Print T-shirt - bordeaux, Lace-up boots - Peru, Sweatshirt - black/red/white\\",\\"Smart lace-ups - black, Print T-shirt - bordeaux, Lace-up boots - Peru, Sweatshirt - black/red/white\\",\\"1, 1, 1, 1\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\",\\"0, 0, 0, 0\\",\\"24.984, 7.988, 75, 24.984\\",\\"24.984, 7.988, 75, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0386303863, ZO0561905619, ZO0397903979, ZO0590105901\\",133,133,4,4,order,abd +vQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Hopkins\\",\\"Hicham Hopkins\\",MALE,8,Hopkins,Hopkins,\\"(empty)\\",Monday,0,\\"hicham@hopkins-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566580,\\"sold_product_566580_19404, sold_product_566580_16718\\",\\"sold_product_566580_19404, sold_product_566580_16718\\",\\"33, 33\\",\\"33, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"17.484, 17.813\\",\\"33, 33\\",\\"19,404, 16,718\\",\\"Shirt - olive, Tracksuit top - black\\",\\"Shirt - olive, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0417304173, ZO0123001230\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0417304173, ZO0123001230\\",66,66,2,2,order,hicham +ygMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Moran\\",\\"Robbie Moran\\",MALE,48,Moran,Moran,\\"(empty)\\",Monday,0,\\"robbie@moran-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566671,\\"sold_product_566671_22991, sold_product_566671_17752\\",\\"sold_product_566671_22991, sold_product_566671_17752\\",\\"50, 37\\",\\"50, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"23, 17.391\\",\\"50, 37\\",\\"22,991, 17,752\\",\\"SOLID - Summer jacket - mustard, Slim fit jeans - black denim\\",\\"SOLID - Summer jacket - mustard, Slim fit jeans - black denim\\",\\"1, 1\\",\\"ZO0427604276, ZO0113801138\\",\\"0, 0\\",\\"50, 37\\",\\"50, 37\\",\\"0, 0\\",\\"ZO0427604276, ZO0113801138\\",87,87,2,2,order,robbie +zgMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Watkins\\",\\"Abd Watkins\\",MALE,52,Watkins,Watkins,\\"(empty)\\",Monday,0,\\"abd@watkins-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566176,\\"sold_product_566176_15205, sold_product_566176_7038\\",\\"sold_product_566176_15205, sold_product_566176_7038\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"13.242, 44.188\\",\\"24.984, 85\\",\\"15,205, 7,038\\",\\"Briefcase - black , Parka - mustard\\",\\"Briefcase - black , Parka - mustard\\",\\"1, 1\\",\\"ZO0607206072, ZO0431404314\\",\\"0, 0\\",\\"24.984, 85\\",\\"24.984, 85\\",\\"0, 0\\",\\"ZO0607206072, ZO0431404314\\",110,110,2,2,order,abd +zwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Carr\\",\\"rania Carr\\",FEMALE,24,Carr,Carr,\\"(empty)\\",Monday,0,\\"rania@carr-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566146,\\"sold_product_566146_24862, sold_product_566146_22163\\",\\"sold_product_566146_24862, sold_product_566146_22163\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.5, 10.703\\",\\"10.992, 20.984\\",\\"24,862, 22,163\\",\\"Print T-shirt - dark blue/off white, Leggings - black\\",\\"Print T-shirt - dark blue/off white, Leggings - black\\",\\"1, 1\\",\\"ZO0646206462, ZO0146201462\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0646206462, ZO0146201462\\",\\"31.984\\",\\"31.984\\",2,2,order,rani +kgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Dawson\\",\\"Abigail Dawson\\",FEMALE,46,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"abigail@dawson-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Champion Arts, Pyramidustries active\\",\\"Champion Arts, Pyramidustries active\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565760,\\"sold_product_565760_21930, sold_product_565760_9980\\",\\"sold_product_565760_21930, sold_product_565760_9980\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Pyramidustries active\\",\\"Champion Arts, Pyramidustries active\\",\\"22.5, 9.867\\",\\"50, 20.984\\",\\"21,930, 9,980\\",\\"Classic coat - black/white, Tights - poseidon\\",\\"Classic coat - black/white, Tights - poseidon\\",\\"1, 1\\",\\"ZO0504505045, ZO0223802238\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0504505045, ZO0223802238\\",71,71,2,2,order,abigail +mAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Lloyd\\",\\"Diane Lloyd\\",FEMALE,22,Lloyd,Lloyd,\\"(empty)\\",Monday,0,\\"diane@lloyd-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565521,\\"sold_product_565521_12423, sold_product_565521_11487\\",\\"sold_product_565521_12423, sold_product_565521_11487\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"6.898, 38.25\\",\\"14.992, 85\\",\\"12,423, 11,487\\",\\"Nightie - black/off white, Snowboard jacket - coralle/grey multicolor\\",\\"Nightie - black/off white, Snowboard jacket - coralle/grey multicolor\\",\\"1, 1\\",\\"ZO0660406604, ZO0484504845\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0660406604, ZO0484504845\\",100,100,2,2,order,diane +nQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Martin\\",\\"Mary Martin\\",FEMALE,20,Martin,Martin,\\"(empty)\\",Monday,0,\\"mary@martin-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises Curvy, Spherecords\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566320,\\"sold_product_566320_14149, sold_product_566320_23774\\",\\"sold_product_566320_14149, sold_product_566320_23774\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"Tigress Enterprises Curvy, Spherecords\\",\\"13.492, 7.941\\",\\"24.984, 14.992\\",\\"14,149, 23,774\\",\\"Blouse - Medium Sea Green, Cardigan - dark blue\\",\\"Blouse - Medium Sea Green, Cardigan - dark blue\\",\\"1, 1\\",\\"ZO0105001050, ZO0652306523\\",\\"0, 0\\",\\"24.984, 14.992\\",\\"24.984, 14.992\\",\\"0, 0\\",\\"ZO0105001050, ZO0652306523\\",\\"39.969\\",\\"39.969\\",2,2,order,mary +ngMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cortez\\",\\"Stephanie Cortez\\",FEMALE,6,Cortez,Cortez,\\"(empty)\\",Monday,0,\\"stephanie@cortez-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566357,\\"sold_product_566357_14019, sold_product_566357_14225\\",\\"sold_product_566357_14019, sold_product_566357_14225\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"13.242, 7.82\\",\\"24.984, 16.984\\",\\"14,019, 14,225\\",\\"Vest - black, Sweatshirt - dark grey multicolor\\",\\"Vest - black, Sweatshirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0061600616, ZO0180701807\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0061600616, ZO0180701807\\",\\"41.969\\",\\"41.969\\",2,2,order,stephanie +nwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Howell\\",\\"rania Howell\\",FEMALE,24,Howell,Howell,\\"(empty)\\",Monday,0,\\"rania@howell-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566415,\\"sold_product_566415_18928, sold_product_566415_17913\\",\\"sold_product_566415_18928, sold_product_566415_17913\\",\\"50, 75\\",\\"50, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"25.984, 36.75\\",\\"50, 75\\",\\"18,928, 17,913\\",\\"Summer dress - black/red, Wedges - white\\",\\"Summer dress - black/red, Wedges - white\\",\\"1, 1\\",\\"ZO0261102611, ZO0667106671\\",\\"0, 0\\",\\"50, 75\\",\\"50, 75\\",\\"0, 0\\",\\"ZO0261102611, ZO0667106671\\",125,125,2,2,order,rani +wQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Jackson\\",\\"Mostafa Jackson\\",MALE,9,Jackson,Jackson,\\"(empty)\\",Monday,0,\\"mostafa@jackson-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566044,\\"sold_product_566044_19539, sold_product_566044_19704\\",\\"sold_product_566044_19539, sold_product_566044_19704\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"5.059, 6.859\\",\\"10.992, 13.992\\",\\"19,539, 19,704\\",\\"Print T-shirt - white, Print T-shirt - grey multicolor\\",\\"Print T-shirt - white, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0552605526, ZO0292702927\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0552605526, ZO0292702927\\",\\"24.984\\",\\"24.984\\",2,2,order,mostafa +8QMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Reese\\",\\"Diane Reese\\",FEMALE,22,Reese,Reese,\\"(empty)\\",Monday,0,\\"diane@reese-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565473,\\"sold_product_565473_13838, sold_product_565473_13437\\",\\"sold_product_565473_13838, sold_product_565473_13437\\",\\"42, 50\\",\\"42, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"19.734, 22.5\\",\\"42, 50\\",\\"13,838, 13,437\\",\\"Ballet pumps - cognac, Ballet pumps - black\\",\\"Ballet pumps - cognac, Ballet pumps - black\\",\\"1, 1\\",\\"ZO0365303653, ZO0235802358\\",\\"0, 0\\",\\"42, 50\\",\\"42, 50\\",\\"0, 0\\",\\"ZO0365303653, ZO0235802358\\",92,92,2,2,order,diane +9AMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Mccormick\\",\\"Clarice Mccormick\\",FEMALE,18,Mccormick,Mccormick,\\"(empty)\\",Monday,0,\\"clarice@mccormick-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565339,\\"sold_product_565339_21573, sold_product_565339_15153\\",\\"sold_product_565339_21573, sold_product_565339_15153\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"17.156, 39\\",\\"33, 75\\",\\"21,573, 15,153\\",\\"Print T-shirt - Yellow, Ankle boots - black\\",\\"Print T-shirt - Yellow, Ankle boots - black\\",\\"1, 1\\",\\"ZO0346503465, ZO0678406784\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0346503465, ZO0678406784\\",108,108,2,2,order,clarice +ZgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Bryant\\",\\"Irwin Bryant\\",MALE,14,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"irwin@bryant-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565591,\\"sold_product_565591_1910, sold_product_565591_12445\\",\\"sold_product_565591_1910, sold_product_565591_12445\\",\\"65, 42\\",\\"65, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.844, 21.406\\",\\"65, 42\\",\\"1,910, 12,445\\",\\"Smart lace-ups - black, Waistcoat - light grey\\",\\"Smart lace-ups - black, Waistcoat - light grey\\",\\"1, 1\\",\\"ZO0683806838, ZO0429204292\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0683806838, ZO0429204292\\",107,107,2,2,order,irwin +eAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",\\"Women's Clothing, Women's Accessories, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Maldonado\\",\\"Rabbia Al Maldonado\\",FEMALE,5,Maldonado,Maldonado,\\"(empty)\\",Monday,0,\\"rabbia al@maldonado-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",730725,\\"sold_product_730725_17276, sold_product_730725_15007, sold_product_730725_5421, sold_product_730725_16594\\",\\"sold_product_730725_17276, sold_product_730725_15007, sold_product_730725_5421, sold_product_730725_16594\\",\\"20.984, 11.992, 185, 65\\",\\"20.984, 11.992, 185, 65\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Shoes, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"Champion Arts, Pyramidustries, Primemaster, Angeldale\\",\\"10.078, 5.52, 83.25, 29.906\\",\\"20.984, 11.992, 185, 65\\",\\"17,276, 15,007, 5,421, 16,594\\",\\"Jumper - blue multicolor, Watch - grey, High heeled boots - brown, Handbag - black\\",\\"Jumper - blue multicolor, Watch - grey, High heeled boots - brown, Handbag - black\\",\\"1, 1, 1, 1\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\",\\"0, 0, 0, 0\\",\\"20.984, 11.992, 185, 65\\",\\"20.984, 11.992, 185, 65\\",\\"0, 0, 0, 0\\",\\"ZO0501605016, ZO0189601896, ZO0363003630, ZO0699306993\\",283,283,4,4,order,rabbia +1wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Craig\\",\\"Pia Craig\\",FEMALE,45,Craig,Craig,\\"(empty)\\",Monday,0,\\"pia@craig-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566443,\\"sold_product_566443_22619, sold_product_566443_24107\\",\\"sold_product_566443_22619, sold_product_566443_24107\\",\\"17.984, 33\\",\\"17.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"8.102, 15.18\\",\\"17.984, 33\\",\\"22,619, 24,107\\",\\"Long sleeved top - black, Jumper dress - grey multicolor\\",\\"Long sleeved top - black, Jumper dress - grey multicolor\\",\\"1, 1\\",\\"ZO0160201602, ZO0261502615\\",\\"0, 0\\",\\"17.984, 33\\",\\"17.984, 33\\",\\"0, 0\\",\\"ZO0160201602, ZO0261502615\\",\\"50.969\\",\\"50.969\\",2,2,order,pia +2AMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Little\\",\\"Marwan Little\\",MALE,51,Little,Little,\\"(empty)\\",Monday,0,\\"marwan@little-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566498,\\"sold_product_566498_17075, sold_product_566498_11878\\",\\"sold_product_566498_17075, sold_product_566498_11878\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"31.797, 5.059\\",\\"60, 10.992\\",\\"17,075, 11,878\\",\\"Smart lace-ups - cognac, Long sleeved top - bordeaux\\",\\"Smart lace-ups - cognac, Long sleeved top - bordeaux\\",\\"1, 1\\",\\"ZO0387103871, ZO0550005500\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0387103871, ZO0550005500\\",71,71,2,2,order,marwan +2wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Perkins\\",\\"Abdulraheem Al Perkins\\",MALE,33,Perkins,Perkins,\\"(empty)\\",Monday,0,\\"abdulraheem al@perkins-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565985,\\"sold_product_565985_22376, sold_product_565985_6969\\",\\"sold_product_565985_22376, sold_product_565985_6969\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.602, 12.742\\",\\"10.992, 24.984\\",\\"22,376, 6,969\\",\\"Long sleeved top - white, Shirt - blue\\",\\"Long sleeved top - white, Shirt - blue\\",\\"1, 1\\",\\"ZO0436604366, ZO0280302803\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0436604366, ZO0280302803\\",\\"35.969\\",\\"35.969\\",2,2,order,abdulraheem +3QMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Dawson\\",\\"Abigail Dawson\\",FEMALE,46,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"abigail@dawson-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565640,\\"sold_product_565640_11983, sold_product_565640_18500\\",\\"sold_product_565640_11983, sold_product_565640_18500\\",\\"24.984, 44\\",\\"24.984, 44\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"12.492, 22\\",\\"24.984, 44\\",\\"11,983, 18,500\\",\\"Summer dress - red, Jersey dress - black/grey\\",\\"Summer dress - red, Jersey dress - black/grey\\",\\"1, 1\\",\\"ZO0631606316, ZO0045300453\\",\\"0, 0\\",\\"24.984, 44\\",\\"24.984, 44\\",\\"0, 0\\",\\"ZO0631606316, ZO0045300453\\",69,69,2,2,order,abigail +3gMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Frances,Frances,\\"Frances Morrison\\",\\"Frances Morrison\\",FEMALE,49,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"frances@morrison-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565683,\\"sold_product_565683_11862, sold_product_565683_16135\\",\\"sold_product_565683_11862, sold_product_565683_16135\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.492, 8.656\\",\\"22.984, 16.984\\",\\"11,862, 16,135\\",\\"Jumper - black, Belt - dark brown\\",\\"Jumper - black, Belt - dark brown\\",\\"1, 1\\",\\"ZO0573205732, ZO0310303103\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0573205732, ZO0310303103\\",\\"39.969\\",\\"39.969\\",2,2,order,frances +\\"-QMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Wise\\",\\"Yuri Wise\\",MALE,21,Wise,Wise,\\"(empty)\\",Monday,0,\\"yuri@wise-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565767,\\"sold_product_565767_18958, sold_product_565767_24243\\",\\"sold_product_565767_18958, sold_product_565767_24243\\",\\"26.984, 24.984\\",\\"26.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.031, 13.242\\",\\"26.984, 24.984\\",\\"18,958, 24,243\\",\\"Formal shirt - white, Slim fit jeans - dirty denim\\",\\"Formal shirt - white, Slim fit jeans - dirty denim\\",\\"1, 1\\",\\"ZO0414304143, ZO0425204252\\",\\"0, 0\\",\\"26.984, 24.984\\",\\"26.984, 24.984\\",\\"0, 0\\",\\"ZO0414304143, ZO0425204252\\",\\"51.969\\",\\"51.969\\",2,2,order,yuri +IAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Salazar\\",\\"Sonya Salazar\\",FEMALE,28,Salazar,Salazar,\\"(empty)\\",Monday,0,\\"sonya@salazar-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566452,\\"sold_product_566452_11504, sold_product_566452_16385\\",\\"sold_product_566452_11504, sold_product_566452_16385\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"5.879, 13.047\\",\\"11.992, 28.984\\",\\"11,504, 16,385\\",\\"Basic T-shirt - darkblue/white, Sandals - gold\\",\\"Basic T-shirt - darkblue/white, Sandals - gold\\",\\"1, 1\\",\\"ZO0706307063, ZO0011300113\\",\\"0, 0\\",\\"11.992, 28.984\\",\\"11.992, 28.984\\",\\"0, 0\\",\\"ZO0706307063, ZO0011300113\\",\\"40.969\\",\\"40.969\\",2,2,order,sonya +IgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jackson,Jackson,\\"Jackson Willis\\",\\"Jackson Willis\\",MALE,13,Willis,Willis,\\"(empty)\\",Monday,0,\\"jackson@willis-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565982,\\"sold_product_565982_15828, sold_product_565982_15722\\",\\"sold_product_565982_15828, sold_product_565982_15722\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.172, 7.41\\",\\"10.992, 13.992\\",\\"15,828, 15,722\\",\\"Tie - black, Belt - brown\\",\\"Tie - black, Belt - brown\\",\\"1, 1\\",\\"ZO0410804108, ZO0309303093\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0410804108, ZO0309303093\\",\\"24.984\\",\\"24.984\\",2,2,order,jackson +UAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Simpson\\",\\"Rabbia Al Simpson\\",FEMALE,5,Simpson,Simpson,\\"(empty)\\",Monday,0,\\"rabbia al@simpson-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Spherecords, Tigress Enterprises MAMA\\",\\"Pyramidustries, Spherecords, Tigress Enterprises MAMA\\",\\"Jun 23, 2019 @ 00:00:00.000\\",726754,\\"sold_product_726754_17171, sold_product_726754_25083, sold_product_726754_21081, sold_product_726754_13554\\",\\"sold_product_726754_17171, sold_product_726754_25083, sold_product_726754_21081, sold_product_726754_13554\\",\\"33, 10.992, 16.984, 24.984\\",\\"33, 10.992, 16.984, 24.984\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Spherecords, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries, Spherecords, Pyramidustries, Tigress Enterprises MAMA\\",\\"16.813, 5.172, 8.156, 12.25\\",\\"33, 10.992, 16.984, 24.984\\",\\"17,171, 25,083, 21,081, 13,554\\",\\"Platform sandals - black, Basic T-shirt - dark blue, Cape - black/offwhite, Jersey dress - black\\",\\"Platform sandals - black, Basic T-shirt - dark blue, Cape - black/offwhite, Jersey dress - black\\",\\"1, 1, 1, 1\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\",\\"0, 0, 0, 0\\",\\"33, 10.992, 16.984, 24.984\\",\\"33, 10.992, 16.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0138001380, ZO0648006480, ZO0193501935, ZO0228402284\\",\\"85.938\\",\\"85.938\\",4,4,order,rabbia +YAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,rania,rania,\\"rania Nash\\",\\"rania Nash\\",FEMALE,24,Nash,Nash,\\"(empty)\\",Monday,0,\\"rania@nash-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Oceanavigations,Oceanavigations,\\"Jun 23, 2019 @ 00:00:00.000\\",565723,\\"sold_product_565723_15629, sold_product_565723_18709\\",\\"sold_product_565723_15629, sold_product_565723_18709\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"15.18, 39.75\\",\\"33, 75\\",\\"15,629, 18,709\\",\\"Watch - gold-coloured, Boots - nude\\",\\"Watch - gold-coloured, Boots - nude\\",\\"1, 1\\",\\"ZO0302303023, ZO0246602466\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0302303023, ZO0246602466\\",108,108,2,2,order,rani +agMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Hayes\\",\\"Youssef Hayes\\",MALE,31,Hayes,Hayes,\\"(empty)\\",Monday,0,\\"youssef@hayes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565896,\\"sold_product_565896_13186, sold_product_565896_15296\\",\\"sold_product_565896_13186, sold_product_565896_15296\\",\\"42, 18.984\\",\\"42, 18.984\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"21.828, 9.117\\",\\"42, 18.984\\",\\"13,186, 15,296\\",\\"Across body bag - navy, Polo shirt - red\\",\\"Across body bag - navy, Polo shirt - red\\",\\"1, 1\\",\\"ZO0466104661, ZO0444104441\\",\\"0, 0\\",\\"42, 18.984\\",\\"42, 18.984\\",\\"0, 0\\",\\"ZO0466104661, ZO0444104441\\",\\"60.969\\",\\"60.969\\",2,2,order,youssef +jgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Summers\\",\\"Abd Summers\\",MALE,52,Summers,Summers,\\"(empty)\\",Monday,0,\\"abd@summers-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Microlutions, Oceanavigations, Elitelligence\\",\\"Microlutions, Oceanavigations, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",718085,\\"sold_product_718085_20302, sold_product_718085_15787, sold_product_718085_11532, sold_product_718085_13238\\",\\"sold_product_718085_20302, sold_product_718085_15787, sold_product_718085_11532, sold_product_718085_13238\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Oceanavigations, Elitelligence, Elitelligence\\",\\"Microlutions, Oceanavigations, Elitelligence, Elitelligence\\",\\"7.27, 8.469, 3.76, 4.949\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"20,302, 15,787, 11,532, 13,238\\",\\"3 PACK - Shorts - khaki/camo, Belt - black, Basic T-shirt - khaki, Print T-shirt - beige\\",\\"3 PACK - Shorts - khaki/camo, Belt - black, Basic T-shirt - khaki, Print T-shirt - beige\\",\\"1, 1, 1, 1\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\",\\"0, 0, 0, 0\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"13.992, 15.992, 7.988, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0129001290, ZO0310103101, ZO0547805478, ZO0560805608\\",\\"48.969\\",\\"48.969\\",4,4,order,abd +zQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Bryant\\",\\"Rabbia Al Bryant\\",FEMALE,5,Bryant,Bryant,\\"(empty)\\",Monday,0,\\"rabbia al@bryant-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566248,\\"sold_product_566248_14303, sold_product_566248_14542\\",\\"sold_product_566248_14303, sold_product_566248_14542\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"36, 13.242\\",\\"75, 24.984\\",\\"14,303, 14,542\\",\\"Ankle boots - black, Tote bag - black\\",\\"Ankle boots - black, Tote bag - black\\",\\"1, 1\\",\\"ZO0678806788, ZO0186101861\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0678806788, ZO0186101861\\",100,100,2,2,order,rabbia +2QMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Alvarez\\",\\"Fitzgerald Alvarez\\",MALE,11,Alvarez,Alvarez,\\"(empty)\\",Monday,0,\\"fitzgerald@alvarez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565560,\\"sold_product_565560_23771, sold_product_565560_18408\\",\\"sold_product_565560_23771, sold_product_565560_18408\\",\\"10.992, 11.992\\",\\"10.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.5, 6.352\\",\\"10.992, 11.992\\",\\"23,771, 18,408\\",\\"Basic T-shirt - Medium Slate Blue, Polo shirt - black\\",\\"Basic T-shirt - Medium Slate Blue, Polo shirt - black\\",\\"1, 1\\",\\"ZO0567505675, ZO0442104421\\",\\"0, 0\\",\\"10.992, 11.992\\",\\"10.992, 11.992\\",\\"0, 0\\",\\"ZO0567505675, ZO0442104421\\",\\"22.984\\",\\"22.984\\",2,2,order,fuzzy +IQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Hale\\",\\"Hicham Hale\\",MALE,8,Hale,Hale,\\"(empty)\\",Monday,0,\\"hicham@hale-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566186,\\"sold_product_566186_24868, sold_product_566186_23962\\",\\"sold_product_566186_24868, sold_product_566186_23962\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 11.5\\",\\"20.984, 24.984\\",\\"24,868, 23,962\\",\\"Walking sandals - white/grey/black, Sweatshirt - navy multicolor \\",\\"Walking sandals - white/grey/black, Sweatshirt - navy multicolor \\",\\"1, 1\\",\\"ZO0522105221, ZO0459104591\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0522105221, ZO0459104591\\",\\"45.969\\",\\"45.969\\",2,2,order,hicham +IgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Foster\\",\\"Wilhemina St. Foster\\",FEMALE,17,Foster,Foster,\\"(empty)\\",Monday,0,\\"wilhemina st.@foster-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Champion Arts, Pyramidustries\\",\\"Champion Arts, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566155,\\"sold_product_566155_13946, sold_product_566155_21158\\",\\"sold_product_566155_13946, sold_product_566155_21158\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Pyramidustries\\",\\"Champion Arts, Pyramidustries\\",\\"9.656, 12.25\\",\\"20.984, 24.984\\",\\"13,946, 21,158\\",\\"Hoodie - dark grey multicolor, Pyjamas - light pink\\",\\"Hoodie - dark grey multicolor, Pyjamas - light pink\\",\\"1, 1\\",\\"ZO0501005010, ZO0214002140\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0501005010, ZO0214002140\\",\\"45.969\\",\\"45.969\\",2,2,order,wilhemina +IwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Dawson\\",\\"Sonya Dawson\\",FEMALE,28,Dawson,Dawson,\\"(empty)\\",Monday,0,\\"sonya@dawson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566628,\\"sold_product_566628_11077, sold_product_566628_19514\\",\\"sold_product_566628_11077, sold_product_566628_19514\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"12.492, 6.352\\",\\"24.984, 11.992\\",\\"11,077, 19,514\\",\\"Tote bag - cognac, 3 PACK - Shorts - teal/dark purple/black\\",\\"Tote bag - cognac, 3 PACK - Shorts - teal/dark purple/black\\",\\"1, 1\\",\\"ZO0195601956, ZO0098900989\\",\\"0, 0\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"0, 0\\",\\"ZO0195601956, ZO0098900989\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +JAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Phillips\\",\\"Mostafa Phillips\\",MALE,9,Phillips,Phillips,\\"(empty)\\",Monday,0,\\"mostafa@phillips-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Microlutions\\",\\"Angeldale, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566519,\\"sold_product_566519_21909, sold_product_566519_12714\\",\\"sold_product_566519_21909, sold_product_566519_12714\\",\\"16.984, 85\\",\\"16.984, 85\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Microlutions\\",\\"Angeldale, Microlutions\\",\\"9.172, 40.813\\",\\"16.984, 85\\",\\"21,909, 12,714\\",\\"Belt - black, Classic coat - black\\",\\"Belt - black, Classic coat - black\\",\\"1, 1\\",\\"ZO0700907009, ZO0115801158\\",\\"0, 0\\",\\"16.984, 85\\",\\"16.984, 85\\",\\"0, 0\\",\\"ZO0700907009, ZO0115801158\\",102,102,2,2,order,mostafa +JQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Powell\\",\\"Stephanie Powell\\",FEMALE,6,Powell,Powell,\\"(empty)\\",Monday,0,\\"stephanie@powell-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565697,\\"sold_product_565697_11530, sold_product_565697_17565\\",\\"sold_product_565697_11530, sold_product_565697_17565\\",\\"16.984, 11.992\\",\\"16.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"8.156, 6\\",\\"16.984, 11.992\\",\\"11,530, 17,565\\",\\"Hoodie - dark red, 2 PACK - Vest - black/nude\\",\\"Hoodie - dark red, 2 PACK - Vest - black/nude\\",\\"1, 1\\",\\"ZO0498904989, ZO0641706417\\",\\"0, 0\\",\\"16.984, 11.992\\",\\"16.984, 11.992\\",\\"0, 0\\",\\"ZO0498904989, ZO0641706417\\",\\"28.984\\",\\"28.984\\",2,2,order,stephanie +JgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Pia,Pia,\\"Pia Ramsey\\",\\"Pia Ramsey\\",FEMALE,45,Ramsey,Ramsey,\\"(empty)\\",Monday,0,\\"pia@ramsey-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566417,\\"sold_product_566417_14379, sold_product_566417_13936\\",\\"sold_product_566417_14379, sold_product_566417_13936\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.469, 5.52\\",\\"11.992, 11.992\\",\\"14,379, 13,936\\",\\"Snood - grey, Scarf - bordeaux\\",\\"Snood - grey, Scarf - bordeaux\\",\\"1, 1\\",\\"ZO0084900849, ZO0194701947\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",\\"ZO0084900849, ZO0194701947\\",\\"23.984\\",\\"23.984\\",2,2,order,pia +fwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Mccarthy\\",\\"Pia Mccarthy\\",FEMALE,45,Mccarthy,Mccarthy,\\"(empty)\\",Monday,0,\\"pia@mccarthy-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565722,\\"sold_product_565722_12551, sold_product_565722_22941\\",\\"sold_product_565722_12551, sold_product_565722_22941\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"8.328, 5.82\\",\\"16.984, 10.992\\",\\"12,551, 22,941\\",\\"Cardigan - light grey multicolor, Print T-shirt - dark blue/red\\",\\"Cardigan - light grey multicolor, Print T-shirt - dark blue/red\\",\\"1, 1\\",\\"ZO0656406564, ZO0495504955\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0656406564, ZO0495504955\\",\\"27.984\\",\\"27.984\\",2,2,order,pia +lAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Foster\\",\\"Boris Foster\\",MALE,36,Foster,Foster,\\"(empty)\\",Monday,0,\\"boris@foster-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",Spritechnologies,Spritechnologies,\\"Jun 23, 2019 @ 00:00:00.000\\",565330,\\"sold_product_565330_16276, sold_product_565330_24760\\",\\"sold_product_565330_16276, sold_product_565330_24760\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Spritechnologies\\",\\"Spritechnologies, Spritechnologies\\",\\"9.453, 26.484\\",\\"20.984, 50\\",\\"16,276, 24,760\\",\\"Tracksuit bottoms - dark grey multicolor, Sweatshirt - black\\",\\"Tracksuit bottoms - dark grey multicolor, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0621606216, ZO0628806288\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0621606216, ZO0628806288\\",71,71,2,2,order,boris +lQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Graham\\",\\"Betty Graham\\",FEMALE,44,Graham,Graham,\\"(empty)\\",Monday,0,\\"betty@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565381,\\"sold_product_565381_23349, sold_product_565381_12141\\",\\"sold_product_565381_23349, sold_product_565381_12141\\",\\"16.984, 7.988\\",\\"16.984, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"8.328, 4.148\\",\\"16.984, 7.988\\",\\"23,349, 12,141\\",\\"Basic T-shirt - black, Belt - taupe\\",\\"Basic T-shirt - black, Belt - taupe\\",\\"1, 1\\",\\"ZO0060200602, ZO0076300763\\",\\"0, 0\\",\\"16.984, 7.988\\",\\"16.984, 7.988\\",\\"0, 0\\",\\"ZO0060200602, ZO0076300763\\",\\"24.984\\",\\"24.984\\",2,2,order,betty +vQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Riley\\",\\"Kamal Riley\\",MALE,39,Riley,Riley,\\"(empty)\\",Monday,0,\\"kamal@riley-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565564,\\"sold_product_565564_19843, sold_product_565564_10979\\",\\"sold_product_565564_19843, sold_product_565564_10979\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"12.492, 7.988\\",\\"24.984, 16.984\\",\\"19,843, 10,979\\",\\"Cardigan - white/blue/khaki, Print T-shirt - dark green\\",\\"Cardigan - white/blue/khaki, Print T-shirt - dark green\\",\\"1, 1\\",\\"ZO0576305763, ZO0116801168\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0576305763, ZO0116801168\\",\\"41.969\\",\\"41.969\\",2,2,order,kamal +wAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Parker\\",\\"Thad Parker\\",MALE,30,Parker,Parker,\\"(empty)\\",Monday,0,\\"thad@parker-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565392,\\"sold_product_565392_17873, sold_product_565392_14058\\",\\"sold_product_565392_17873, sold_product_565392_14058\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.602, 10.492\\",\\"10.992, 20.984\\",\\"17,873, 14,058\\",\\"Sports shirt - Seashell, Sweatshirt - mottled light grey\\",\\"Sports shirt - Seashell, Sweatshirt - mottled light grey\\",\\"1, 1\\",\\"ZO0616606166, ZO0592205922\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0616606166, ZO0592205922\\",\\"31.984\\",\\"31.984\\",2,2,order,thad +wQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Henderson\\",\\"Stephanie Henderson\\",FEMALE,6,Henderson,Henderson,\\"(empty)\\",Monday,0,\\"stephanie@henderson-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Karmanite\\",\\"Tigress Enterprises, Karmanite\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565410,\\"sold_product_565410_22028, sold_product_565410_5066\\",\\"sold_product_565410_22028, sold_product_565410_5066\\",\\"33, 100\\",\\"33, 100\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Karmanite\\",\\"Tigress Enterprises, Karmanite\\",\\"15.844, 45\\",\\"33, 100\\",\\"22,028, 5,066\\",\\"Ankle boots - cognac, Boots - black\\",\\"Ankle boots - cognac, Boots - black\\",\\"1, 1\\",\\"ZO0023600236, ZO0704307043\\",\\"0, 0\\",\\"33, 100\\",\\"33, 100\\",\\"0, 0\\",\\"ZO0023600236, ZO0704307043\\",133,133,2,2,order,stephanie +\\"-AMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Walters\\",\\"Elyssa Walters\\",FEMALE,27,Walters,Walters,\\"(empty)\\",Monday,0,\\"elyssa@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565504,\\"sold_product_565504_21839, sold_product_565504_19546\\",\\"sold_product_565504_21839, sold_product_565504_19546\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"11.75, 21\\",\\"24.984, 42\\",\\"21,839, 19,546\\",\\"Jumper - dark grey multicolor, Summer dress - black\\",\\"Jumper - dark grey multicolor, Summer dress - black\\",\\"1, 1\\",\\"ZO0653406534, ZO0049300493\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0653406534, ZO0049300493\\",67,67,2,2,order,elyssa +\\"-wMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Allison\\",\\"Betty Allison\\",FEMALE,44,Allison,Allison,\\"(empty)\\",Monday,0,\\"betty@allison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565334,\\"sold_product_565334_17565, sold_product_565334_24798\\",\\"sold_product_565334_17565, sold_product_565334_24798\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"6, 35.25\\",\\"11.992, 75\\",\\"17,565, 24,798\\",\\"2 PACK - Vest - black/nude, Lace-up boots - black\\",\\"2 PACK - Vest - black/nude, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0641706417, ZO0382303823\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0641706417, ZO0382303823\\",87,87,2,2,order,betty +IQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Strickland\\",\\"Phil Strickland\\",MALE,50,Strickland,Strickland,\\"(empty)\\",Monday,0,\\"phil@strickland-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spherecords, Angeldale\\",\\"Spherecords, Angeldale\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566079,\\"sold_product_566079_22969, sold_product_566079_775\\",\\"sold_product_566079_22969, sold_product_566079_775\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Angeldale\\",\\"Spherecords, Angeldale\\",\\"12.992, 30.594\\",\\"24.984, 60\\",\\"22,969, 775\\",\\"Pyjamas - blue, Boots - black\\",\\"Pyjamas - blue, Boots - black\\",\\"1, 1\\",\\"ZO0663306633, ZO0687306873\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0663306633, ZO0687306873\\",85,85,2,2,order,phil +IgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Gilbert\\",\\"Betty Gilbert\\",FEMALE,44,Gilbert,Gilbert,\\"(empty)\\",Monday,0,\\"betty@gilbert-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566622,\\"sold_product_566622_13554, sold_product_566622_11691\\",\\"sold_product_566622_13554, sold_product_566622_11691\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Tigress Enterprises MAMA, Tigress Enterprises\\",\\"12.25, 13.492\\",\\"24.984, 24.984\\",\\"13,554, 11,691\\",\\"Jersey dress - black, Cape - grey multicolor\\",\\"Jersey dress - black, Cape - grey multicolor\\",\\"1, 1\\",\\"ZO0228402284, ZO0082300823\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0228402284, ZO0082300823\\",\\"49.969\\",\\"49.969\\",2,2,order,betty +IwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Long\\",\\"Elyssa Long\\",FEMALE,27,Long,Long,\\"(empty)\\",Monday,0,\\"elyssa@long-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566650,\\"sold_product_566650_20286, sold_product_566650_16948\\",\\"sold_product_566650_20286, sold_product_566650_16948\\",\\"65, 14.992\\",\\"65, 14.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"34.438, 7.941\\",\\"65, 14.992\\",\\"20,286, 16,948\\",\\"Long-sleeved Maxi Dress, Scarf - black\\",\\"Long-sleeved Maxi Dress, Scarf - black\\",\\"1, 1\\",\\"ZO0049100491, ZO0194801948\\",\\"0, 0\\",\\"65, 14.992\\",\\"65, 14.992\\",\\"0, 0\\",\\"ZO0049100491, ZO0194801948\\",80,80,2,2,order,elyssa +JAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Strickland\\",\\"Abigail Strickland\\",FEMALE,46,Strickland,Strickland,\\"(empty)\\",Monday,0,\\"abigail@strickland-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566295,\\"sold_product_566295_17554, sold_product_566295_22815\\",\\"sold_product_566295_17554, sold_product_566295_22815\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"9.313, 13.242\\",\\"18.984, 24.984\\",\\"17,554, 22,815\\",\\"Maxi dress - black, Jersey dress - black\\",\\"Maxi dress - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0635606356, ZO0043100431\\",\\"0, 0\\",\\"18.984, 24.984\\",\\"18.984, 24.984\\",\\"0, 0\\",\\"ZO0635606356, ZO0043100431\\",\\"43.969\\",\\"43.969\\",2,2,order,abigail +JQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Kim\\",\\"Clarice Kim\\",FEMALE,18,Kim,Kim,\\"(empty)\\",Monday,0,\\"clarice@kim-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566538,\\"sold_product_566538_9847, sold_product_566538_16537\\",\\"sold_product_566538_9847, sold_product_566538_16537\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Gnomehouse\\",\\"Pyramidustries active, Gnomehouse\\",\\"13.492, 25.984\\",\\"24.984, 50\\",\\"9,847, 16,537\\",\\"Tights - black, Cocktail dress / Party dress - rose cloud\\",\\"Tights - black, Cocktail dress / Party dress - rose cloud\\",\\"1, 1\\",\\"ZO0224402244, ZO0342403424\\",\\"0, 0\\",\\"24.984, 50\\",\\"24.984, 50\\",\\"0, 0\\",\\"ZO0224402244, ZO0342403424\\",75,75,2,2,order,clarice +JgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Allison\\",\\"Clarice Allison\\",FEMALE,18,Allison,Allison,\\"(empty)\\",Monday,0,\\"clarice@allison-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565918,\\"sold_product_565918_14195, sold_product_565918_7629\\",\\"sold_product_565918_14195, sold_product_565918_7629\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.648, 14.492\\",\\"16.984, 28.984\\",\\"14,195, 7,629\\",\\"Jersey dress - black, Jumper - peacoat/winter white\\",\\"Jersey dress - black, Jumper - peacoat/winter white\\",\\"1, 1\\",\\"ZO0155001550, ZO0072100721\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0155001550, ZO0072100721\\",\\"45.969\\",\\"45.969\\",2,2,order,clarice +UAMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Morrison\\",\\"Gwen Morrison\\",FEMALE,26,Morrison,Morrison,\\"(empty)\\",Monday,0,\\"gwen@morrison-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Crystal Lighting\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565678,\\"sold_product_565678_13792, sold_product_565678_22639\\",\\"sold_product_565678_13792, sold_product_565678_22639\\",\\"12.992, 24.984\\",\\"12.992, 24.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"Tigress Enterprises, Crystal Lighting\\",\\"6.109, 11.25\\",\\"12.992, 24.984\\",\\"13,792, 22,639\\",\\"Scarf - white/grey, Wool jumper - white\\",\\"Scarf - white/grey, Wool jumper - white\\",\\"1, 1\\",\\"ZO0081800818, ZO0485604856\\",\\"0, 0\\",\\"12.992, 24.984\\",\\"12.992, 24.984\\",\\"0, 0\\",\\"ZO0081800818, ZO0485604856\\",\\"37.969\\",\\"37.969\\",2,2,order,gwen +UQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Graves\\",\\"Jason Graves\\",MALE,16,Graves,Graves,\\"(empty)\\",Monday,0,\\"jason@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566564,\\"sold_product_566564_11560, sold_product_566564_17533\\",\\"sold_product_566564_11560, sold_product_566564_17533\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"29.406, 5.641\\",\\"60, 11.992\\",\\"11,560, 17,533\\",\\"Trainers - white, Print T-shirt - dark grey\\",\\"Trainers - white, Print T-shirt - dark grey\\",\\"1, 1\\",\\"ZO0107301073, ZO0293002930\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0107301073, ZO0293002930\\",72,72,2,2,order,jason +ZgMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Dixon\\",\\"rania Dixon\\",FEMALE,24,Dixon,Dixon,\\"(empty)\\",Monday,0,\\"rania@dixon-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565498,\\"sold_product_565498_15436, sold_product_565498_16548\\",\\"sold_product_565498_15436, sold_product_565498_16548\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"14.781, 9\\",\\"28.984, 16.984\\",\\"15,436, 16,548\\",\\"Jersey dress - anthra/black, Sweatshirt - black\\",\\"Jersey dress - anthra/black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0046600466, ZO0503305033\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0046600466, ZO0503305033\\",\\"45.969\\",\\"45.969\\",2,2,order,rani +gAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Sutton\\",\\"Yasmine Sutton\\",FEMALE,43,Sutton,Sutton,\\"(empty)\\",Monday,0,\\"yasmine@sutton-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 23, 2019 @ 00:00:00.000\\",565793,\\"sold_product_565793_14151, sold_product_565793_22488\\",\\"sold_product_565793_14151, sold_product_565793_22488\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"11.75, 15.07\\",\\"24.984, 28.984\\",\\"14,151, 22,488\\",\\"Slim fit jeans - mid blue denim, Lace-ups - black glitter\\",\\"Slim fit jeans - mid blue denim, Lace-ups - black glitter\\",\\"1, 1\\",\\"ZO0712807128, ZO0007500075\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0712807128, ZO0007500075\\",\\"53.969\\",\\"53.969\\",2,2,order,yasmine +gQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Fletcher\\",\\"Jason Fletcher\\",MALE,16,Fletcher,Fletcher,\\"(empty)\\",Monday,0,\\"jason@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566232,\\"sold_product_566232_21255, sold_product_566232_12532\\",\\"sold_product_566232_21255, sold_product_566232_12532\\",\\"7.988, 11.992\\",\\"7.988, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.76, 6.352\\",\\"7.988, 11.992\\",\\"21,255, 12,532\\",\\"Basic T-shirt - black, Print T-shirt - navy ecru\\",\\"Basic T-shirt - black, Print T-shirt - navy ecru\\",\\"1, 1\\",\\"ZO0545205452, ZO0437304373\\",\\"0, 0\\",\\"7.988, 11.992\\",\\"7.988, 11.992\\",\\"0, 0\\",\\"ZO0545205452, ZO0437304373\\",\\"19.984\\",\\"19.984\\",2,2,order,jason +ggMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Larson\\",\\"Tariq Larson\\",MALE,25,Larson,Larson,\\"(empty)\\",Monday,0,\\"tariq@larson-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566259,\\"sold_product_566259_22713, sold_product_566259_21314\\",\\"sold_product_566259_22713, sold_product_566259_21314\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"32.375, 6.039\\",\\"60, 10.992\\",\\"22,713, 21,314\\",\\"Boots - black, Print T-shirt - white\\",\\"Boots - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0694206942, ZO0553805538\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0694206942, ZO0553805538\\",71,71,2,2,order,tariq +pwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Walters\\",\\"Gwen Walters\\",FEMALE,26,Walters,Walters,\\"(empty)\\",Monday,0,\\"gwen@walters-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"Jun 23, 2019 @ 00:00:00.000\\",566591,\\"sold_product_566591_19909, sold_product_566591_12575\\",\\"sold_product_566591_19909, sold_product_566591_12575\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 12, 2016 @ 00:00:00.000, Dec 12, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Low Tide Media\\",\\"Champion Arts, Low Tide Media\\",\\"13.047, 19.313\\",\\"28.984, 42\\",\\"19,909, 12,575\\",\\"Hoodie - black/white, Classic heels - nude\\",\\"Hoodie - black/white, Classic heels - nude\\",\\"1, 1\\",\\"ZO0502405024, ZO0366003660\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0502405024, ZO0366003660\\",71,71,2,2,order,gwen +WQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya Foster\\",\\"Yahya Foster\\",MALE,23,Foster,Foster,\\"(empty)\\",Sunday,6,\\"yahya@foster-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564670,\\"sold_product_564670_11411, sold_product_564670_23904\\",\\"sold_product_564670_11411, sold_product_564670_23904\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"8.094, 38.25\\",\\"14.992, 85\\",\\"11,411, 23,904\\",\\"Shorts - bordeaux mel, High-top trainers - black\\",\\"Shorts - bordeaux mel, High-top trainers - black\\",\\"1, 1\\",\\"ZO0531205312, ZO0684706847\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0531205312, ZO0684706847\\",100,100,2,2,order,yahya +WgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Jimenez\\",\\"Betty Jimenez\\",FEMALE,44,Jimenez,Jimenez,\\"(empty)\\",Sunday,6,\\"betty@jimenez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564710,\\"sold_product_564710_21089, sold_product_564710_10916\\",\\"sold_product_564710_21089, sold_product_564710_10916\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"17.156, 10.906\\",\\"33, 20.984\\",\\"21,089, 10,916\\",\\"Jersey dress - black, Sweatshirt - black\\",\\"Jersey dress - black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0263402634, ZO0499404994\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0263402634, ZO0499404994\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +YAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Daniels\\",\\"Clarice Daniels\\",FEMALE,18,Daniels,Daniels,\\"(empty)\\",Sunday,6,\\"clarice@daniels-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564429,\\"sold_product_564429_19198, sold_product_564429_20939\\",\\"sold_product_564429_19198, sold_product_564429_20939\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"24, 11.75\\",\\"50, 24.984\\",\\"19,198, 20,939\\",\\"Summer dress - grey, Shirt - black/white\\",\\"Summer dress - grey, Shirt - black/white\\",\\"1, 1\\",\\"ZO0260702607, ZO0495804958\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0260702607, ZO0495804958\\",75,75,2,2,order,clarice +YQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Clayton\\",\\"Jackson Clayton\\",MALE,13,Clayton,Clayton,\\"(empty)\\",Sunday,6,\\"jackson@clayton-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564479,\\"sold_product_564479_6603, sold_product_564479_21164\\",\\"sold_product_564479_6603, sold_product_564479_21164\\",\\"75, 10.992\\",\\"75, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"39, 5.93\\",\\"75, 10.992\\",\\"6,603, 21,164\\",\\"Suit jacket - navy, Long sleeved top - dark blue\\",\\"Suit jacket - navy, Long sleeved top - dark blue\\",\\"1, 1\\",\\"ZO0409304093, ZO0436904369\\",\\"0, 0\\",\\"75, 10.992\\",\\"75, 10.992\\",\\"0, 0\\",\\"ZO0409304093, ZO0436904369\\",86,86,2,2,order,jackson +YgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Davidson\\",\\"Abd Davidson\\",MALE,52,Davidson,Davidson,\\"(empty)\\",Sunday,6,\\"abd@davidson-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564513,\\"sold_product_564513_1824, sold_product_564513_19618\\",\\"sold_product_564513_1824, sold_product_564513_19618\\",\\"42, 42\\",\\"42, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"20.156, 21\\",\\"42, 42\\",\\"1,824, 19,618\\",\\"Casual lace-ups - Violet, Waistcoat - petrol\\",\\"Casual lace-ups - Violet, Waistcoat - petrol\\",\\"1, 1\\",\\"ZO0390003900, ZO0287902879\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0390003900, ZO0287902879\\",84,84,2,2,order,abd +xAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Rowe\\",\\"Stephanie Rowe\\",FEMALE,6,Rowe,Rowe,\\"(empty)\\",Sunday,6,\\"stephanie@rowe-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564885,\\"sold_product_564885_16366, sold_product_564885_11518\\",\\"sold_product_564885_16366, sold_product_564885_11518\\",\\"21.984, 10.992\\",\\"21.984, 10.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"10.344, 5.281\\",\\"21.984, 10.992\\",\\"16,366, 11,518\\",\\"Wallet - red, Scarf - white/navy/red\\",\\"Wallet - red, Scarf - white/navy/red\\",\\"1, 1\\",\\"ZO0303803038, ZO0192501925\\",\\"0, 0\\",\\"21.984, 10.992\\",\\"21.984, 10.992\\",\\"0, 0\\",\\"ZO0303803038, ZO0192501925\\",\\"32.969\\",\\"32.969\\",2,2,order,stephanie +UwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Bryant\\",\\"Mostafa Bryant\\",MALE,9,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"mostafa@bryant-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565150,\\"sold_product_565150_14275, sold_product_565150_22504\\",\\"sold_product_565150_14275, sold_product_565150_22504\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"25, 13.492\\",\\"50, 24.984\\",\\"14,275, 22,504\\",\\"Winter jacket - black, Shirt - red-blue\\",\\"Winter jacket - black, Shirt - red-blue\\",\\"1, 1\\",\\"ZO0624906249, ZO0411604116\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0624906249, ZO0411604116\\",75,75,2,2,order,mostafa +VAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Wood\\",\\"Jackson Wood\\",MALE,13,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jackson@wood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565206,\\"sold_product_565206_18416, sold_product_565206_16131\\",\\"sold_product_565206_18416, sold_product_565206_16131\\",\\"85, 60\\",\\"85, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"45.031, 27\\",\\"85, 60\\",\\"18,416, 16,131\\",\\"Briefcase - dark brown, Lace-up boots - black\\",\\"Briefcase - dark brown, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0316303163, ZO0401004010\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0316303163, ZO0401004010\\",145,145,2,2,order,jackson +9QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Baker\\",\\"rania Baker\\",FEMALE,24,Baker,Baker,\\"(empty)\\",Sunday,6,\\"rania@baker-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564759,\\"sold_product_564759_10104, sold_product_564759_20756\\",\\"sold_product_564759_10104, sold_product_564759_20756\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"8.828, 5.059\\",\\"16.984, 10.992\\",\\"10,104, 20,756\\",\\"Print T-shirt - black, Print T-shirt - red\\",\\"Print T-shirt - black, Print T-shirt - red\\",\\"1, 1\\",\\"ZO0218802188, ZO0492604926\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0218802188, ZO0492604926\\",\\"27.984\\",\\"27.984\\",2,2,order,rani +BAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Massey\\",\\"Wilhemina St. Massey\\",FEMALE,17,Massey,Massey,\\"(empty)\\",Sunday,6,\\"wilhemina st.@massey-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564144,\\"sold_product_564144_20744, sold_product_564144_13946\\",\\"sold_product_564144_20744, sold_product_564144_13946\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Champion Arts\\",\\"Pyramidustries active, Champion Arts\\",\\"8.328, 9.656\\",\\"16.984, 20.984\\",\\"20,744, 13,946\\",\\"Long sleeved top - black, Hoodie - dark grey multicolor\\",\\"Long sleeved top - black, Hoodie - dark grey multicolor\\",\\"1, 1\\",\\"ZO0218602186, ZO0501005010\\",\\"0, 0\\",\\"16.984, 20.984\\",\\"16.984, 20.984\\",\\"0, 0\\",\\"ZO0218602186, ZO0501005010\\",\\"37.969\\",\\"37.969\\",2,2,order,wilhemina +BgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Smith\\",\\"Abd Smith\\",MALE,52,Smith,Smith,\\"(empty)\\",Sunday,6,\\"abd@smith-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563909,\\"sold_product_563909_15619, sold_product_563909_17976\\",\\"sold_product_563909_15619, sold_product_563909_17976\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.633, 12.25\\",\\"28.984, 24.984\\",\\"15,619, 17,976\\",\\"Jumper - dark blue, Jumper - blue\\",\\"Jumper - dark blue, Jumper - blue\\",\\"1, 1\\",\\"ZO0452804528, ZO0453604536\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0452804528, ZO0453604536\\",\\"53.969\\",\\"53.969\\",2,2,order,abd +QgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Thompson\\",\\"Sonya Thompson\\",FEMALE,28,Thompson,Thompson,\\"(empty)\\",Sunday,6,\\"sonya@thompson-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564869,\\"sold_product_564869_19715, sold_product_564869_7445\\",\\"sold_product_564869_19715, sold_product_564869_7445\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"5.93, 20.578\\",\\"10.992, 42\\",\\"19,715, 7,445\\",\\"Snood - nude/turquoise/pink, High heels - black\\",\\"Snood - nude/turquoise/pink, High heels - black\\",\\"1, 1\\",\\"ZO0192401924, ZO0366703667\\",\\"0, 0\\",\\"10.992, 42\\",\\"10.992, 42\\",\\"0, 0\\",\\"ZO0192401924, ZO0366703667\\",\\"52.969\\",\\"52.969\\",2,2,order,sonya +jQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Tran\\",\\"Recip Tran\\",MALE,10,Tran,Tran,\\"(empty)\\",Sunday,6,\\"recip@tran-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564619,\\"sold_product_564619_19268, sold_product_564619_20016\\",\\"sold_product_564619_19268, sold_product_564619_20016\\",\\"85, 60\\",\\"85, 60\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"42.5, 28.203\\",\\"85, 60\\",\\"19,268, 20,016\\",\\"Briefcase - antique cognac, Lace-up boots - khaki\\",\\"Briefcase - antique cognac, Lace-up boots - khaki\\",\\"1, 1\\",\\"ZO0470304703, ZO0406204062\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0470304703, ZO0406204062\\",145,145,2,2,order,recip +mwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Samir,Samir,\\"Samir Moss\\",\\"Samir Moss\\",MALE,34,Moss,Moss,\\"(empty)\\",Sunday,6,\\"samir@moss-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564237,\\"sold_product_564237_19840, sold_product_564237_13857\\",\\"sold_product_564237_19840, sold_product_564237_13857\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"10.289, 17.156\\",\\"20.984, 33\\",\\"19,840, 13,857\\",\\"Watch - black, Trainers - beige\\",\\"Watch - black, Trainers - beige\\",\\"1, 1\\",\\"ZO0311203112, ZO0395703957\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0311203112, ZO0395703957\\",\\"53.969\\",\\"53.969\\",2,2,order,samir +\\"-QMtOW0BH63Xcmy44WNv\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Moss\\",\\"Fitzgerald Moss\\",MALE,11,Moss,Moss,\\"(empty)\\",Sunday,6,\\"fitzgerald@moss-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564269,\\"sold_product_564269_18446, sold_product_564269_19731\\",\\"sold_product_564269_18446, sold_product_564269_19731\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"17.016, 5.059\\",\\"37, 10.992\\",\\"18,446, 19,731\\",\\"Shirt - dark grey multicolor, Print T-shirt - white/dark blue\\",\\"Shirt - dark grey multicolor, Print T-shirt - white/dark blue\\",\\"1, 1\\",\\"ZO0281102811, ZO0555705557\\",\\"0, 0\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"0, 0\\",\\"ZO0281102811, ZO0555705557\\",\\"47.969\\",\\"47.969\\",2,2,order,fuzzy +NAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Kamal,Kamal,\\"Kamal Schultz\\",\\"Kamal Schultz\\",MALE,39,Schultz,Schultz,\\"(empty)\\",Sunday,6,\\"kamal@schultz-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564842,\\"sold_product_564842_13508, sold_product_564842_24934\\",\\"sold_product_564842_13508, sold_product_564842_24934\\",\\"85, 50\\",\\"85, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"43.344, 22.5\\",\\"85, 50\\",\\"13,508, 24,934\\",\\"Light jacket - tan, Lace-up boots - resin coffee\\",\\"Light jacket - tan, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0432004320, ZO0403504035\\",\\"0, 0\\",\\"85, 50\\",\\"85, 50\\",\\"0, 0\\",\\"ZO0432004320, ZO0403504035\\",135,135,2,2,order,kamal +NQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Roberson\\",\\"Yasmine Roberson\\",FEMALE,43,Roberson,Roberson,\\"(empty)\\",Sunday,6,\\"yasmine@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564893,\\"sold_product_564893_24371, sold_product_564893_20755\\",\\"sold_product_564893_24371, sold_product_564893_20755\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"Gnomehouse, Tigress Enterprises MAMA\\",\\"25.984, 14.781\\",\\"50, 28.984\\",\\"24,371, 20,755\\",\\"Lace-ups - rose, Trousers - black denim\\",\\"Lace-ups - rose, Trousers - black denim\\",\\"1, 1\\",\\"ZO0322403224, ZO0227802278\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0322403224, ZO0227802278\\",79,79,2,2,order,yasmine +SQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Fletcher\\",\\"Betty Fletcher\\",FEMALE,44,Fletcher,Fletcher,\\"(empty)\\",Sunday,6,\\"betty@fletcher-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564215,\\"sold_product_564215_17589, sold_product_564215_17920\\",\\"sold_product_564215_17589, sold_product_564215_17920\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"17.484, 12.492\\",\\"33, 24.984\\",\\"17,589, 17,920\\",\\"Jumpsuit - black, Maxi dress - black\\",\\"Jumpsuit - black, Maxi dress - black\\",\\"1, 1\\",\\"ZO0147201472, ZO0152201522\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0147201472, ZO0152201522\\",\\"57.969\\",\\"57.969\\",2,2,order,betty +TAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Marshall\\",\\"Yasmine Marshall\\",FEMALE,43,Marshall,Marshall,\\"(empty)\\",Sunday,6,\\"yasmine@marshall-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564725,\\"sold_product_564725_21497, sold_product_564725_14166\\",\\"sold_product_564725_21497, sold_product_564725_14166\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"13.492, 61.25\\",\\"24.984, 125\\",\\"21,497, 14,166\\",\\"Jumper - sand, Platform boots - golden\\",\\"Jumper - sand, Platform boots - golden\\",\\"1, 1\\",\\"ZO0071700717, ZO0364303643\\",\\"0, 0\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"0, 0\\",\\"ZO0071700717, ZO0364303643\\",150,150,2,2,order,yasmine +TQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Allison\\",\\"Muniz Allison\\",MALE,37,Allison,Allison,\\"(empty)\\",Sunday,6,\\"muniz@allison-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564733,\\"sold_product_564733_1550, sold_product_564733_13038\\",\\"sold_product_564733_1550, sold_product_564733_13038\\",\\"33, 65\\",\\"33, 65\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"14.852, 31.203\\",\\"33, 65\\",\\"1,550, 13,038\\",\\"Casual lace-ups - dark brown, Suit jacket - grey\\",\\"Casual lace-ups - dark brown, Suit jacket - grey\\",\\"1, 1\\",\\"ZO0384303843, ZO0273702737\\",\\"0, 0\\",\\"33, 65\\",\\"33, 65\\",\\"0, 0\\",\\"ZO0384303843, ZO0273702737\\",98,98,2,2,order,muniz +mAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mccarthy\\",\\"Rabbia Al Mccarthy\\",FEMALE,5,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"rabbia al@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564331,\\"sold_product_564331_24927, sold_product_564331_11378\\",\\"sold_product_564331_24927, sold_product_564331_11378\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"Tigress Enterprises MAMA, Oceanavigations\\",\\"18.859, 5.762\\",\\"37, 11.992\\",\\"24,927, 11,378\\",\\"Summer dress - black, Wallet - black\\",\\"Summer dress - black, Wallet - black\\",\\"1, 1\\",\\"ZO0229402294, ZO0303303033\\",\\"0, 0\\",\\"37, 11.992\\",\\"37, 11.992\\",\\"0, 0\\",\\"ZO0229402294, ZO0303303033\\",\\"48.969\\",\\"48.969\\",2,2,order,rabbia +mQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Gregory\\",\\"Jason Gregory\\",MALE,16,Gregory,Gregory,\\"(empty)\\",Sunday,6,\\"jason@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564350,\\"sold_product_564350_15296, sold_product_564350_19902\\",\\"sold_product_564350_15296, sold_product_564350_19902\\",\\"18.984, 13.992\\",\\"18.984, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"9.117, 7.41\\",\\"18.984, 13.992\\",\\"15,296, 19,902\\",\\"Polo shirt - red, TARTAN 3 PACK - Shorts - tartan/Blue Violety/dark grey\\",\\"Polo shirt - red, TARTAN 3 PACK - Shorts - tartan/Blue Violety/dark grey\\",\\"1, 1\\",\\"ZO0444104441, ZO0476804768\\",\\"0, 0\\",\\"18.984, 13.992\\",\\"18.984, 13.992\\",\\"0, 0\\",\\"ZO0444104441, ZO0476804768\\",\\"32.969\\",\\"32.969\\",2,2,order,jason +mgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Mccarthy\\",\\"Betty Mccarthy\\",FEMALE,44,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"betty@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 22, 2019 @ 00:00:00.000\\",564398,\\"sold_product_564398_15957, sold_product_564398_18712\\",\\"sold_product_564398_15957, sold_product_564398_18712\\",\\"37, 75\\",\\"37, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"19.234, 39.75\\",\\"37, 75\\",\\"15,957, 18,712\\",\\"A-line skirt - Pale Violet Red, Classic coat - navy blazer\\",\\"A-line skirt - Pale Violet Red, Classic coat - navy blazer\\",\\"1, 1\\",\\"ZO0328703287, ZO0351003510\\",\\"0, 0\\",\\"37, 75\\",\\"37, 75\\",\\"0, 0\\",\\"ZO0328703287, ZO0351003510\\",112,112,2,2,order,betty +mwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Gibbs\\",\\"Diane Gibbs\\",FEMALE,22,Gibbs,Gibbs,\\"(empty)\\",Sunday,6,\\"diane@gibbs-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564409,\\"sold_product_564409_23179, sold_product_564409_22261\\",\\"sold_product_564409_23179, sold_product_564409_22261\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"9.656, 22.5\\",\\"20.984, 50\\",\\"23,179, 22,261\\",\\"Sweatshirt - berry, Winter jacket - bordeaux\\",\\"Sweatshirt - berry, Winter jacket - bordeaux\\",\\"1, 1\\",\\"ZO0178501785, ZO0503805038\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0178501785, ZO0503805038\\",71,71,2,2,order,diane +nAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Baker\\",\\"Hicham Baker\\",MALE,8,Baker,Baker,\\"(empty)\\",Sunday,6,\\"hicham@baker-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564024,\\"sold_product_564024_24786, sold_product_564024_19600\\",\\"sold_product_564024_24786, sold_product_564024_19600\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"11.25, 7.648\\",\\"24.984, 16.984\\",\\"24,786, 19,600\\",\\"Slim fit jeans - black, Sports shorts - mottled grey\\",\\"Slim fit jeans - black, Sports shorts - mottled grey\\",\\"1, 1\\",\\"ZO0534405344, ZO0619006190\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0534405344, ZO0619006190\\",\\"41.969\\",\\"41.969\\",2,2,order,hicham +sgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perkins\\",\\"Robbie Perkins\\",MALE,48,Perkins,Perkins,\\"(empty)\\",Sunday,6,\\"robbie@perkins-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564271,\\"sold_product_564271_12818, sold_product_564271_18444\\",\\"sold_product_564271_12818, sold_product_564271_18444\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"8.328, 26.984\\",\\"16.984, 50\\",\\"12,818, 18,444\\",\\"Trainers - black, Summer jacket - dark blue\\",\\"Trainers - black, Summer jacket - dark blue\\",\\"1, 1\\",\\"ZO0507905079, ZO0430804308\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0507905079, ZO0430804308\\",67,67,2,2,order,robbie +DgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Rodriguez\\",\\"Sonya Rodriguez\\",FEMALE,28,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"sonya@rodriguez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Microlutions, Pyramidustries\\",\\"Microlutions, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564676,\\"sold_product_564676_22697, sold_product_564676_12704\\",\\"sold_product_564676_22697, sold_product_564676_12704\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Pyramidustries\\",\\"Microlutions, Pyramidustries\\",\\"14.852, 16.172\\",\\"33, 33\\",\\"22,697, 12,704\\",\\"Dress - red/black, Ankle boots - cognac\\",\\"Dress - red/black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0108401084, ZO0139301393\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0108401084, ZO0139301393\\",66,66,2,2,order,sonya +FAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Bryan\\",\\"Sultan Al Bryan\\",MALE,19,Bryan,Bryan,\\"(empty)\\",Sunday,6,\\"sultan al@bryan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564445,\\"sold_product_564445_14799, sold_product_564445_15411\\",\\"sold_product_564445_14799, sold_product_564445_15411\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"11.953, 7.82\\",\\"22.984, 16.984\\",\\"14,799, 15,411\\",\\"Sweatshirt - mottled grey, Belt - black\\",\\"Sweatshirt - mottled grey, Belt - black\\",\\"1, 1\\",\\"ZO0593805938, ZO0701407014\\",\\"0, 0\\",\\"22.984, 16.984\\",\\"22.984, 16.984\\",\\"0, 0\\",\\"ZO0593805938, ZO0701407014\\",\\"39.969\\",\\"39.969\\",2,2,order,sultan +fgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Hodges\\",\\"Phil Hodges\\",MALE,50,Hodges,Hodges,\\"(empty)\\",Sunday,6,\\"phil@hodges-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564241,\\"sold_product_564241_11300, sold_product_564241_16698\\",\\"sold_product_564241_11300, sold_product_564241_16698\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.867, 4.309\\",\\"20.984, 7.988\\",\\"11,300, 16,698\\",\\"Rucksack - black/grey multicolor , Basic T-shirt - light red\\",\\"Rucksack - black/grey multicolor , Basic T-shirt - light red\\",\\"1, 1\\",\\"ZO0605506055, ZO0547505475\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0605506055, ZO0547505475\\",\\"28.984\\",\\"28.984\\",2,2,order,phil +fwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Phil,Phil,\\"Phil Hernandez\\",\\"Phil Hernandez\\",MALE,50,Hernandez,Hernandez,\\"(empty)\\",Sunday,6,\\"phil@hernandez-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564272,\\"sold_product_564272_24786, sold_product_564272_19965\\",\\"sold_product_564272_24786, sold_product_564272_19965\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"11.25, 14.211\\",\\"24.984, 28.984\\",\\"24,786, 19,965\\",\\"Slim fit jeans - black, Casual lace-ups - dark grey\\",\\"Slim fit jeans - black, Casual lace-ups - dark grey\\",\\"1, 1\\",\\"ZO0534405344, ZO0512105121\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0534405344, ZO0512105121\\",\\"53.969\\",\\"53.969\\",2,2,order,phil +0AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Jacobs\\",\\"Mostafa Jacobs\\",MALE,9,Jacobs,Jacobs,\\"(empty)\\",Sunday,6,\\"mostafa@jacobs-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564844,\\"sold_product_564844_24343, sold_product_564844_13084\\",\\"sold_product_564844_24343, sold_product_564844_13084\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.391, 12.742\\",\\"10.992, 24.984\\",\\"24,343, 13,084\\",\\"Print T-shirt - white, Chinos - Forest Green\\",\\"Print T-shirt - white, Chinos - Forest Green\\",\\"1, 1\\",\\"ZO0553205532, ZO0526205262\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0553205532, ZO0526205262\\",\\"35.969\\",\\"35.969\\",2,2,order,mostafa +0QMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Hansen\\",\\"Sonya Hansen\\",FEMALE,28,Hansen,Hansen,\\"(empty)\\",Sunday,6,\\"sonya@hansen-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564883,\\"sold_product_564883_16522, sold_product_564883_25026\\",\\"sold_product_564883_16522, sold_product_564883_25026\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Gnomehouse\\",\\"Spherecords Maternity, Gnomehouse\\",\\"7.988, 22.5\\",\\"16.984, 50\\",\\"16,522, 25,026\\",\\"Jersey dress - black/white , Summer dress - multicolour\\",\\"Jersey dress - black/white , Summer dress - multicolour\\",\\"1, 1\\",\\"ZO0705607056, ZO0334703347\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0705607056, ZO0334703347\\",67,67,2,2,order,sonya +7wMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ryan\\",\\"Rabbia Al Ryan\\",FEMALE,5,Ryan,Ryan,\\"(empty)\\",Sunday,6,\\"rabbia al@ryan-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564307,\\"sold_product_564307_18709, sold_product_564307_19883\\",\\"sold_product_564307_18709, sold_product_564307_19883\\",\\"75, 11.992\\",\\"75, 11.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"39.75, 5.52\\",\\"75, 11.992\\",\\"18,709, 19,883\\",\\"Boots - nude, Scarf - bordeaux/blue/rose\\",\\"Boots - nude, Scarf - bordeaux/blue/rose\\",\\"1, 1\\",\\"ZO0246602466, ZO0195201952\\",\\"0, 0\\",\\"75, 11.992\\",\\"75, 11.992\\",\\"0, 0\\",\\"ZO0246602466, ZO0195201952\\",87,87,2,2,order,rabbia +8AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ball\\",\\"Rabbia Al Ball\\",FEMALE,5,Ball,Ball,\\"(empty)\\",Sunday,6,\\"rabbia al@ball-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564148,\\"sold_product_564148_24106, sold_product_564148_16891\\",\\"sold_product_564148_24106, sold_product_564148_16891\\",\\"20.984, 21.984\\",\\"20.984, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"9.867, 11.867\\",\\"20.984, 21.984\\",\\"24,106, 16,891\\",\\"Basic T-shirt - scarab, Rucksack - black \\",\\"Basic T-shirt - scarab, Rucksack - black \\",\\"1, 1\\",\\"ZO0057900579, ZO0211602116\\",\\"0, 0\\",\\"20.984, 21.984\\",\\"20.984, 21.984\\",\\"0, 0\\",\\"ZO0057900579, ZO0211602116\\",\\"42.969\\",\\"42.969\\",2,2,order,rabbia +\\"_wMtOW0BH63Xcmy44mWR\\",ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryant\\",\\"Betty Bryant\\",FEMALE,44,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"betty@bryant-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564009,\\"sold_product_564009_13956, sold_product_564009_21367\\",\\"sold_product_564009_13956, sold_product_564009_21367\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"11.328, 14.781\\",\\"20.984, 28.984\\",\\"13,956, 21,367\\",\\"Tracksuit bottoms - black, Trainers - black/silver\\",\\"Tracksuit bottoms - black, Trainers - black/silver\\",\\"1, 1\\",\\"ZO0487904879, ZO0027100271\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0487904879, ZO0027100271\\",\\"49.969\\",\\"49.969\\",2,2,order,betty +AAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Harvey\\",\\"Abd Harvey\\",MALE,52,Harvey,Harvey,\\"(empty)\\",Sunday,6,\\"abd@harvey-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564532,\\"sold_product_564532_21335, sold_product_564532_20709\\",\\"sold_product_564532_21335, sold_product_564532_20709\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"6.352, 12\\",\\"11.992, 24.984\\",\\"21,335, 20,709\\",\\"2 PACK - Basic T-shirt - red multicolor, Tracksuit bottoms - black\\",\\"2 PACK - Basic T-shirt - red multicolor, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0474704747, ZO0622006220\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0474704747, ZO0622006220\\",\\"36.969\\",\\"36.969\\",2,2,order,abd +cwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cummings\\",\\"Abigail Cummings\\",FEMALE,46,Cummings,Cummings,\\"(empty)\\",Sunday,6,\\"abigail@cummings-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",565308,\\"sold_product_565308_16405, sold_product_565308_8985\\",\\"sold_product_565308_16405, sold_product_565308_8985\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"11.5, 27.594\\",\\"24.984, 60\\",\\"16,405, 8,985\\",\\"Vest - black, Light jacket - cognac\\",\\"Vest - black, Light jacket - cognac\\",\\"1, 1\\",\\"ZO0172401724, ZO0184901849\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0172401724, ZO0184901849\\",85,85,2,2,order,abigail +lQMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Moss\\",\\"Elyssa Moss\\",FEMALE,27,Moss,Moss,\\"(empty)\\",Sunday,6,\\"elyssa@moss-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564339,\\"sold_product_564339_24835, sold_product_564339_7932\\",\\"sold_product_564339_24835, sold_product_564339_7932\\",\\"13.992, 37\\",\\"13.992, 37\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"7.129, 19.594\\",\\"13.992, 37\\",\\"24,835, 7,932\\",\\"Scarf - red, Shirt - navy blazer\\",\\"Scarf - red, Shirt - navy blazer\\",\\"1, 1\\",\\"ZO0082900829, ZO0347903479\\",\\"0, 0\\",\\"13.992, 37\\",\\"13.992, 37\\",\\"0, 0\\",\\"ZO0082900829, ZO0347903479\\",\\"50.969\\",\\"50.969\\",2,2,order,elyssa +lgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Muniz,Muniz,\\"Muniz Parker\\",\\"Muniz Parker\\",MALE,37,Parker,Parker,\\"(empty)\\",Sunday,6,\\"muniz@parker-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564361,\\"sold_product_564361_12864, sold_product_564361_14121\\",\\"sold_product_564361_12864, sold_product_564361_14121\\",\\"22.984, 17.984\\",\\"22.984, 17.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"11.719, 9.172\\",\\"22.984, 17.984\\",\\"12,864, 14,121\\",\\"SLIM FIT - Formal shirt - black, Watch - grey\\",\\"SLIM FIT - Formal shirt - black, Watch - grey\\",\\"1, 1\\",\\"ZO0422304223, ZO0600506005\\",\\"0, 0\\",\\"22.984, 17.984\\",\\"22.984, 17.984\\",\\"0, 0\\",\\"ZO0422304223, ZO0600506005\\",\\"40.969\\",\\"40.969\\",2,2,order,muniz +lwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Boone\\",\\"Sonya Boone\\",FEMALE,28,Boone,Boone,\\"(empty)\\",Sunday,6,\\"sonya@boone-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564394,\\"sold_product_564394_18592, sold_product_564394_11914\\",\\"sold_product_564394_18592, sold_product_564394_11914\\",\\"25.984, 75\\",\\"25.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"14.031, 39\\",\\"25.984, 75\\",\\"18,592, 11,914\\",\\"Long sleeved top - grey, Wedge boots - white\\",\\"Long sleeved top - grey, Wedge boots - white\\",\\"1, 1\\",\\"ZO0269902699, ZO0667906679\\",\\"0, 0\\",\\"25.984, 75\\",\\"25.984, 75\\",\\"0, 0\\",\\"ZO0269902699, ZO0667906679\\",101,101,2,2,order,sonya +mAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Hopkins\\",\\"rania Hopkins\\",FEMALE,24,Hopkins,Hopkins,\\"(empty)\\",Sunday,6,\\"rania@hopkins-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564030,\\"sold_product_564030_24668, sold_product_564030_20234\\",\\"sold_product_564030_24668, sold_product_564030_20234\\",\\"16.984, 6.988\\",\\"16.984, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords\\",\\"Pyramidustries, Spherecords\\",\\"8.828, 3.221\\",\\"16.984, 6.988\\",\\"24,668, 20,234\\",\\"Sweatshirt - black, Vest - bordeaux\\",\\"Sweatshirt - black, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0179901799, ZO0637606376\\",\\"0, 0\\",\\"16.984, 6.988\\",\\"16.984, 6.988\\",\\"0, 0\\",\\"ZO0179901799, ZO0637606376\\",\\"23.984\\",\\"23.984\\",2,2,order,rani +qwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Salazar\\",\\"Mostafa Salazar\\",MALE,9,Salazar,Salazar,\\"(empty)\\",Sunday,6,\\"mostafa@salazar-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564661,\\"sold_product_564661_20323, sold_product_564661_20690\\",\\"sold_product_564661_20323, sold_product_564661_20690\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"12.18, 18.141\\",\\"22.984, 33\\",\\"20,323, 20,690\\",\\"Formal shirt - light blue, Sweatshirt - black\\",\\"Formal shirt - light blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0415004150, ZO0125501255\\",\\"0, 0\\",\\"22.984, 33\\",\\"22.984, 33\\",\\"0, 0\\",\\"ZO0415004150, ZO0125501255\\",\\"55.969\\",\\"55.969\\",2,2,order,mostafa +rAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Yasmine,Yasmine,\\"Yasmine Estrada\\",\\"Yasmine Estrada\\",FEMALE,43,Estrada,Estrada,\\"(empty)\\",Sunday,6,\\"yasmine@estrada-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spherecords Curvy, Primemaster\\",\\"Spherecords Curvy, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564706,\\"sold_product_564706_13450, sold_product_564706_11576\\",\\"sold_product_564706_13450, sold_product_564706_11576\\",\\"11.992, 115\\",\\"11.992, 115\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Primemaster\\",\\"Spherecords Curvy, Primemaster\\",\\"5.879, 60.938\\",\\"11.992, 115\\",\\"13,450, 11,576\\",\\"Pencil skirt - black, High heeled boots - Midnight Blue\\",\\"Pencil skirt - black, High heeled boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0709007090, ZO0362103621\\",\\"0, 0\\",\\"11.992, 115\\",\\"11.992, 115\\",\\"0, 0\\",\\"ZO0709007090, ZO0362103621\\",127,127,2,2,order,yasmine +sgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Tran\\",\\"rania Tran\\",FEMALE,24,Tran,Tran,\\"(empty)\\",Sunday,6,\\"rania@tran-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564460,\\"sold_product_564460_24985, sold_product_564460_16158\\",\\"sold_product_564460_24985, sold_product_564460_16158\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"12, 15.508\\",\\"24.984, 33\\",\\"24,985, 16,158\\",\\"Cardigan - peacoat, Blouse - Dark Turquoise\\",\\"Cardigan - peacoat, Blouse - Dark Turquoise\\",\\"1, 1\\",\\"ZO0655106551, ZO0349403494\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0655106551, ZO0349403494\\",\\"57.969\\",\\"57.969\\",2,2,order,rani +FwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Palmer\\",\\"Diane Palmer\\",FEMALE,22,Palmer,Palmer,\\"(empty)\\",Sunday,6,\\"diane@palmer-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564536,\\"sold_product_564536_17282, sold_product_564536_12577\\",\\"sold_product_564536_17282, sold_product_564536_12577\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.719, 24.5\\",\\"13.992, 50\\",\\"17,282, 12,577\\",\\"Scarf - black, Sandals - beige\\",\\"Scarf - black, Sandals - beige\\",\\"1, 1\\",\\"ZO0304603046, ZO0370603706\\",\\"0, 0\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"0, 0\\",\\"ZO0304603046, ZO0370603706\\",\\"63.969\\",\\"63.969\\",2,2,order,diane +GAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Bowers\\",\\"Abigail Bowers\\",FEMALE,46,Bowers,Bowers,\\"(empty)\\",Sunday,6,\\"abigail@bowers-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564559,\\"sold_product_564559_4882, sold_product_564559_16317\\",\\"sold_product_564559_4882, sold_product_564559_16317\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"26.484, 12.094\\",\\"50, 21.984\\",\\"4,882, 16,317\\",\\"Boots - brown, Shirt - light blue\\",\\"Boots - brown, Shirt - light blue\\",\\"1, 1\\",\\"ZO0015500155, ZO0650806508\\",\\"0, 0\\",\\"50, 21.984\\",\\"50, 21.984\\",\\"0, 0\\",\\"ZO0015500155, ZO0650806508\\",72,72,2,2,order,abigail +GQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Wood\\",\\"Clarice Wood\\",FEMALE,18,Wood,Wood,\\"(empty)\\",Sunday,6,\\"clarice@wood-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564609,\\"sold_product_564609_23139, sold_product_564609_23243\\",\\"sold_product_564609_23139, sold_product_564609_23243\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.23, 12.492\\",\\"11.992, 24.984\\",\\"23,139, 23,243\\",\\"Print T-shirt - black/berry, Summer dress - dark purple\\",\\"Print T-shirt - black/berry, Summer dress - dark purple\\",\\"1, 1\\",\\"ZO0162401624, ZO0156001560\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0162401624, ZO0156001560\\",\\"36.969\\",\\"36.969\\",2,2,order,clarice +awMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Caldwell\\",\\"Tariq Caldwell\\",MALE,25,Caldwell,Caldwell,\\"(empty)\\",Sunday,6,\\"tariq@caldwell-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565138,\\"sold_product_565138_18229, sold_product_565138_19505\\",\\"sold_product_565138_18229, sold_product_565138_19505\\",\\"8.992, 16.984\\",\\"8.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"4.578, 8.656\\",\\"8.992, 16.984\\",\\"18,229, 19,505\\",\\"Sports shirt - black, Polo shirt - dark blue\\",\\"Sports shirt - black, Polo shirt - dark blue\\",\\"1, 1\\",\\"ZO0615506155, ZO0445304453\\",\\"0, 0\\",\\"8.992, 16.984\\",\\"8.992, 16.984\\",\\"0, 0\\",\\"ZO0615506155, ZO0445304453\\",\\"25.984\\",\\"25.984\\",2,2,order,tariq +bAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Taylor\\",\\"Marwan Taylor\\",MALE,51,Taylor,Taylor,\\"(empty)\\",Sunday,6,\\"marwan@taylor-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565025,\\"sold_product_565025_10984, sold_product_565025_12566\\",\\"sold_product_565025_10984, sold_product_565025_12566\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.5, 3.92\\",\\"24.984, 7.988\\",\\"10,984, 12,566\\",\\"Shirt - navy, Vest - dark blue\\",\\"Shirt - navy, Vest - dark blue\\",\\"1, 1\\",\\"ZO0280802808, ZO0549005490\\",\\"0, 0\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"0, 0\\",\\"ZO0280802808, ZO0549005490\\",\\"32.969\\",\\"32.969\\",2,2,order,marwan +hgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Bowers\\",\\"Elyssa Bowers\\",FEMALE,27,Bowers,Bowers,\\"(empty)\\",Sunday,6,\\"elyssa@bowers-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564000,\\"sold_product_564000_21941, sold_product_564000_12880\\",\\"sold_product_564000_21941, sold_product_564000_12880\\",\\"110, 24.984\\",\\"110, 24.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"55, 13.492\\",\\"110, 24.984\\",\\"21,941, 12,880\\",\\"Boots - grey/silver, Ankle boots - blue\\",\\"Boots - grey/silver, Ankle boots - blue\\",\\"1, 1\\",\\"ZO0364603646, ZO0018200182\\",\\"0, 0\\",\\"110, 24.984\\",\\"110, 24.984\\",\\"0, 0\\",\\"ZO0364603646, ZO0018200182\\",135,135,2,2,order,elyssa +hwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Samir,Samir,\\"Samir Meyer\\",\\"Samir Meyer\\",MALE,34,Meyer,Meyer,\\"(empty)\\",Sunday,6,\\"samir@meyer-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564557,\\"sold_product_564557_24657, sold_product_564557_24558\\",\\"sold_product_564557_24657, sold_product_564557_24558\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"5.93, 5.5\\",\\"10.992, 10.992\\",\\"24,657, 24,558\\",\\"7 PACK - Socks - black/grey/white/navy, Hat - dark grey multicolor\\",\\"7 PACK - Socks - black/grey/white/navy, Hat - dark grey multicolor\\",\\"1, 1\\",\\"ZO0664606646, ZO0460404604\\",\\"0, 0\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"0, 0\\",\\"ZO0664606646, ZO0460404604\\",\\"21.984\\",\\"21.984\\",2,2,order,samir +iAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Cortez\\",\\"Elyssa Cortez\\",FEMALE,27,Cortez,Cortez,\\"(empty)\\",Sunday,6,\\"elyssa@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 22, 2019 @ 00:00:00.000\\",564604,\\"sold_product_564604_20084, sold_product_564604_22900\\",\\"sold_product_564604_20084, sold_product_564604_22900\\",\\"60, 13.992\\",\\"60, 13.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"28.797, 6.578\\",\\"60, 13.992\\",\\"20,084, 22,900\\",\\"High heels - black, Scarf - black/taupe\\",\\"High heels - black, Scarf - black/taupe\\",\\"1, 1\\",\\"ZO0237702377, ZO0304303043\\",\\"0, 0\\",\\"60, 13.992\\",\\"60, 13.992\\",\\"0, 0\\",\\"ZO0237702377, ZO0304303043\\",74,74,2,2,order,elyssa +mAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Graham\\",\\"Yahya Graham\\",MALE,23,Graham,Graham,\\"(empty)\\",Sunday,6,\\"yahya@graham-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564777,\\"sold_product_564777_15017, sold_product_564777_22683\\",\\"sold_product_564777_15017, sold_product_564777_22683\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"13.633, 15.18\\",\\"28.984, 33\\",\\"15,017, 22,683\\",\\"Jumper - off-white, Jumper - black\\",\\"Jumper - off-white, Jumper - black\\",\\"1, 1\\",\\"ZO0452704527, ZO0122201222\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0452704527, ZO0122201222\\",\\"61.969\\",\\"61.969\\",2,2,order,yahya +mQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Gwen,Gwen,\\"Gwen Rodriguez\\",\\"Gwen Rodriguez\\",FEMALE,26,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"gwen@rodriguez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564812,\\"sold_product_564812_24272, sold_product_564812_12257\\",\\"sold_product_564812_24272, sold_product_564812_12257\\",\\"37, 20.984\\",\\"37, 20.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"18.125, 10.703\\",\\"37, 20.984\\",\\"24,272, 12,257\\",\\"Shirt - white, T-bar sandals - black\\",\\"Shirt - white, T-bar sandals - black\\",\\"1, 1\\",\\"ZO0266002660, ZO0031900319\\",\\"0, 0\\",\\"37, 20.984\\",\\"37, 20.984\\",\\"0, 0\\",\\"ZO0266002660, ZO0031900319\\",\\"57.969\\",\\"57.969\\",2,2,order,gwen +owMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Mcdonald\\",\\"Jackson Mcdonald\\",MALE,13,Mcdonald,Mcdonald,\\"(empty)\\",Sunday,6,\\"jackson@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",715752,\\"sold_product_715752_18080, sold_product_715752_18512, sold_product_715752_3636, sold_product_715752_6169\\",\\"sold_product_715752_18080, sold_product_715752_18512, sold_product_715752_3636, sold_product_715752_6169\\",\\"6.988, 65, 14.992, 20.984\\",\\"6.988, 65, 14.992, 20.984\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"Microlutions, Low Tide Media, Spritechnologies, Oceanavigations\\",\\"3.699, 34.438, 7.941, 11.539\\",\\"6.988, 65, 14.992, 20.984\\",\\"18,080, 18,512, 3,636, 6,169\\",\\"3 PACK - Socks - khaki/black, Lace-up boots - black/grey, Undershirt - black, Jumper - grey\\",\\"3 PACK - Socks - khaki/black, Lace-up boots - black/grey, Undershirt - black, Jumper - grey\\",\\"1, 1, 1, 1\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\",\\"0, 0, 0, 0\\",\\"6.988, 65, 14.992, 20.984\\",\\"6.988, 65, 14.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0130801308, ZO0402604026, ZO0630506305, ZO0297402974\\",\\"107.938\\",\\"107.938\\",4,4,order,jackson +sQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Diane,Diane,\\"Diane Watkins\\",\\"Diane Watkins\\",FEMALE,22,Watkins,Watkins,\\"(empty)\\",Sunday,6,\\"diane@watkins-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563964,\\"sold_product_563964_12582, sold_product_563964_18661\\",\\"sold_product_563964_12582, sold_product_563964_18661\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"6.898, 38.25\\",\\"14.992, 85\\",\\"12,582, 18,661\\",\\"Ballet pumps - nude, Winter boots - black\\",\\"Ballet pumps - nude, Winter boots - black\\",\\"1, 1\\",\\"ZO0001200012, ZO0251902519\\",\\"0, 0\\",\\"14.992, 85\\",\\"14.992, 85\\",\\"0, 0\\",\\"ZO0001200012, ZO0251902519\\",100,100,2,2,order,diane +2wMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Maldonado\\",\\"Betty Maldonado\\",FEMALE,44,Maldonado,Maldonado,\\"(empty)\\",Sunday,6,\\"betty@maldonado-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564315,\\"sold_product_564315_14794, sold_product_564315_25010\\",\\"sold_product_564315_14794, sold_product_564315_25010\\",\\"11.992, 17.984\\",\\"11.992, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"5.762, 9.891\\",\\"11.992, 17.984\\",\\"14,794, 25,010\\",\\"Vest - sheer pink, Print T-shirt - white\\",\\"Vest - sheer pink, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0221002210, ZO0263702637\\",\\"0, 0\\",\\"11.992, 17.984\\",\\"11.992, 17.984\\",\\"0, 0\\",\\"ZO0221002210, ZO0263702637\\",\\"29.984\\",\\"29.984\\",2,2,order,betty +CwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Barber\\",\\"Elyssa Barber\\",FEMALE,27,Barber,Barber,\\"(empty)\\",Sunday,6,\\"elyssa@barber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565237,\\"sold_product_565237_15847, sold_product_565237_9482\\",\\"sold_product_565237_15847, sold_product_565237_9482\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"23.5, 12.992\\",\\"50, 24.984\\",\\"15,847, 9,482\\",\\"Lace-ups - platino, Blouse - off white\\",\\"Lace-ups - platino, Blouse - off white\\",\\"1, 1\\",\\"ZO0323303233, ZO0172101721\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0323303233, ZO0172101721\\",75,75,2,2,order,elyssa +DgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Samir,Samir,\\"Samir Tyler\\",\\"Samir Tyler\\",MALE,34,Tyler,Tyler,\\"(empty)\\",Sunday,6,\\"samir@tyler-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565090,\\"sold_product_565090_21928, sold_product_565090_1424\\",\\"sold_product_565090_21928, sold_product_565090_1424\\",\\"85, 42\\",\\"85, 42\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"46.75, 20.156\\",\\"85, 42\\",\\"21,928, 1,424\\",\\"Lace-up boots - black, Lace-up boots - black\\",\\"Lace-up boots - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0690306903, ZO0521005210\\",\\"0, 0\\",\\"85, 42\\",\\"85, 42\\",\\"0, 0\\",\\"ZO0690306903, ZO0521005210\\",127,127,2,2,order,samir +JAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Porter\\",\\"Yuri Porter\\",MALE,21,Porter,Porter,\\"(empty)\\",Sunday,6,\\"yuri@porter-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564649,\\"sold_product_564649_1961, sold_product_564649_6945\\",\\"sold_product_564649_1961, sold_product_564649_6945\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"30.547, 11.273\\",\\"65, 22.984\\",\\"1,961, 6,945\\",\\"Lace-up boots - dark blue, Shirt - navy\\",\\"Lace-up boots - dark blue, Shirt - navy\\",\\"1, 1\\",\\"ZO0405704057, ZO0411704117\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0405704057, ZO0411704117\\",88,88,2,2,order,yuri +KAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cummings\\",\\"Gwen Cummings\\",FEMALE,26,Cummings,Cummings,\\"(empty)\\",Sunday,6,\\"gwen@cummings-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564510,\\"sold_product_564510_15201, sold_product_564510_10898\\",\\"sold_product_564510_15201, sold_product_564510_10898\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.75, 14.781\\",\\"24.984, 28.984\\",\\"15,201, 10,898\\",\\"Handbag - black, Jumpsuit - black\\",\\"Handbag - black, Jumpsuit - black\\",\\"1, 1\\",\\"ZO0093600936, ZO0145301453\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0093600936, ZO0145301453\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +YwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Cortez\\",\\"Brigitte Cortez\\",FEMALE,12,Cortez,Cortez,\\"(empty)\\",Sunday,6,\\"brigitte@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565222,\\"sold_product_565222_20561, sold_product_565222_22115\\",\\"sold_product_565222_20561, sold_product_565222_22115\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"Tigress Enterprises Curvy, Oceanavigations\\",\\"12.992, 34.5\\",\\"24.984, 75\\",\\"20,561, 22,115\\",\\"Tracksuit bottoms - black, Winter boots - taupe\\",\\"Tracksuit bottoms - black, Winter boots - taupe\\",\\"1, 1\\",\\"ZO0102001020, ZO0252402524\\",\\"0, 0\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"0, 0\\",\\"ZO0102001020, ZO0252402524\\",100,100,2,2,order,brigitte +kQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Lawrence\\",\\"Robert Lawrence\\",MALE,29,Lawrence,Lawrence,\\"(empty)\\",Sunday,6,\\"robert@lawrence-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565233,\\"sold_product_565233_24859, sold_product_565233_12805\\",\\"sold_product_565233_24859, sold_product_565233_12805\\",\\"11.992, 55\\",\\"11.992, 55\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Low Tide Media\\",\\"Spritechnologies, Low Tide Media\\",\\"5.879, 29.141\\",\\"11.992, 55\\",\\"24,859, 12,805\\",\\"Sports shirt - black, Down jacket - dark beige\\",\\"Sports shirt - black, Down jacket - dark beige\\",\\"1, 1\\",\\"ZO0614906149, ZO0430404304\\",\\"0, 0\\",\\"11.992, 55\\",\\"11.992, 55\\",\\"0, 0\\",\\"ZO0614906149, ZO0430404304\\",67,67,2,2,order,robert +mgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Brock\\",\\"Youssef Brock\\",MALE,31,Brock,Brock,\\"(empty)\\",Sunday,6,\\"youssef@brock-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",565084,\\"sold_product_565084_11612, sold_product_565084_6793\\",\\"sold_product_565084_11612, sold_product_565084_6793\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.82, 7.82\\",\\"10.992, 16.984\\",\\"11,612, 6,793\\",\\"Print T-shirt - grey, Jumper - grey multicolor\\",\\"Print T-shirt - grey, Jumper - grey multicolor\\",\\"1, 1\\",\\"ZO0549805498, ZO0541205412\\",\\"0, 0\\",\\"10.992, 16.984\\",\\"10.992, 16.984\\",\\"0, 0\\",\\"ZO0549805498, ZO0541205412\\",\\"27.984\\",\\"27.984\\",2,2,order,youssef +sQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Mckenzie\\",\\"Elyssa Mckenzie\\",FEMALE,27,Mckenzie,Mckenzie,\\"(empty)\\",Sunday,6,\\"elyssa@mckenzie-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564796,\\"sold_product_564796_13332, sold_product_564796_23987\\",\\"sold_product_564796_13332, sold_product_564796_23987\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.18, 13.492\\",\\"33, 24.984\\",\\"13,332, 23,987\\",\\"Cowboy/Biker boots - cognac, Shirt - red/black\\",\\"Cowboy/Biker boots - cognac, Shirt - red/black\\",\\"1, 1\\",\\"ZO0022100221, ZO0172301723\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0022100221, ZO0172301723\\",\\"57.969\\",\\"57.969\\",2,2,order,elyssa +sgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Burton\\",\\"Gwen Burton\\",FEMALE,26,Burton,Burton,\\"(empty)\\",Sunday,6,\\"gwen@burton-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564627,\\"sold_product_564627_16073, sold_product_564627_15494\\",\\"sold_product_564627_16073, sold_product_564627_15494\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Champion Arts\\",\\"Pyramidustries, Champion Arts\\",\\"11.75, 8.328\\",\\"24.984, 16.984\\",\\"16,073, 15,494\\",\\"Rucksack - black , Sweatshirt - black\\",\\"Rucksack - black , Sweatshirt - black\\",\\"1, 1\\",\\"ZO0211702117, ZO0499004990\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0211702117, ZO0499004990\\",\\"41.969\\",\\"41.969\\",2,2,order,gwen +twMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert James\\",\\"Robert James\\",MALE,29,James,James,\\"(empty)\\",Sunday,6,\\"robert@james-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564257,\\"sold_product_564257_23012, sold_product_564257_14015\\",\\"sold_product_564257_23012, sold_product_564257_14015\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.813, 15.648\\",\\"33, 28.984\\",\\"23,012, 14,015\\",\\"Denim jacket - grey denim, Jumper - blue\\",\\"Denim jacket - grey denim, Jumper - blue\\",\\"1, 1\\",\\"ZO0539205392, ZO0577705777\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0539205392, ZO0577705777\\",\\"61.969\\",\\"61.969\\",2,2,order,robert +uwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Boone\\",\\"Yuri Boone\\",MALE,21,Boone,Boone,\\"(empty)\\",Sunday,6,\\"yuri@boone-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564701,\\"sold_product_564701_18884, sold_product_564701_20066\\",\\"sold_product_564701_18884, sold_product_564701_20066\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9.656, 13.242\\",\\"20.984, 24.984\\",\\"18,884, 20,066\\",\\"Sweatshirt - black /white, Shirt - oliv\\",\\"Sweatshirt - black /white, Shirt - oliv\\",\\"1, 1\\",\\"ZO0585205852, ZO0418104181\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0585205852, ZO0418104181\\",\\"45.969\\",\\"45.969\\",2,2,order,yuri +DwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Bryant\\",\\"Hicham Bryant\\",MALE,8,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"hicham@bryant-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564915,\\"sold_product_564915_13194, sold_product_564915_13091\\",\\"sold_product_564915_13194, sold_product_564915_13091\\",\\"50, 29.984\\",\\"50, 29.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"24, 15.289\\",\\"50, 29.984\\",\\"13,194, 13,091\\",\\"Summer jacket - petrol, Trainers - navy\\",\\"Summer jacket - petrol, Trainers - navy\\",\\"1, 1\\",\\"ZO0286502865, ZO0394703947\\",\\"0, 0\\",\\"50, 29.984\\",\\"50, 29.984\\",\\"0, 0\\",\\"ZO0286502865, ZO0394703947\\",80,80,2,2,order,hicham +EAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Ball\\",\\"Diane Ball\\",FEMALE,22,Ball,Ball,\\"(empty)\\",Sunday,6,\\"diane@ball-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564954,\\"sold_product_564954_20928, sold_product_564954_13902\\",\\"sold_product_564954_20928, sold_product_564954_13902\\",\\"150, 42\\",\\"150, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Tigress Enterprises\\",\\"Primemaster, Tigress Enterprises\\",\\"70.5, 22.672\\",\\"150, 42\\",\\"20,928, 13,902\\",\\"Over-the-knee boots - passion, Lohan - Summer dress - black/black\\",\\"Over-the-knee boots - passion, Lohan - Summer dress - black/black\\",\\"1, 1\\",\\"ZO0362903629, ZO0048100481\\",\\"0, 0\\",\\"150, 42\\",\\"150, 42\\",\\"0, 0\\",\\"ZO0362903629, ZO0048100481\\",192,192,2,2,order,diane +EQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Gregory\\",\\"Gwen Gregory\\",FEMALE,26,Gregory,Gregory,\\"(empty)\\",Sunday,6,\\"gwen@gregory-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Pyramidustries active, Pyramidustries\\",\\"Pyramidustries active, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565009,\\"sold_product_565009_17113, sold_product_565009_24241\\",\\"sold_product_565009_17113, sold_product_565009_24241\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Pyramidustries\\",\\"Pyramidustries active, Pyramidustries\\",\\"8.328, 11.25\\",\\"16.984, 24.984\\",\\"17,113, 24,241\\",\\"Tights - duffle bag, Jeans Skinny Fit - black denim\\",\\"Tights - duffle bag, Jeans Skinny Fit - black denim\\",\\"1, 1\\",\\"ZO0225302253, ZO0183101831\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0225302253, ZO0183101831\\",\\"41.969\\",\\"41.969\\",2,2,order,gwen +EgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Sherman\\",\\"Mary Sherman\\",FEMALE,20,Sherman,Sherman,\\"(empty)\\",Sunday,6,\\"mary@sherman-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords Curvy, Spherecords\\",\\"Spherecords Curvy, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564065,\\"sold_product_564065_16220, sold_product_564065_13835\\",\\"sold_product_564065_16220, sold_product_564065_13835\\",\\"14.992, 10.992\\",\\"14.992, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Spherecords\\",\\"Spherecords Curvy, Spherecords\\",\\"7.789, 5.82\\",\\"14.992, 10.992\\",\\"16,220, 13,835\\",\\"Vest - white, Print T-shirt - light grey multicolor/white\\",\\"Vest - white, Print T-shirt - light grey multicolor/white\\",\\"1, 1\\",\\"ZO0711207112, ZO0646106461\\",\\"0, 0\\",\\"14.992, 10.992\\",\\"14.992, 10.992\\",\\"0, 0\\",\\"ZO0711207112, ZO0646106461\\",\\"25.984\\",\\"25.984\\",2,2,order,mary +EwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Stewart\\",\\"Abigail Stewart\\",FEMALE,46,Stewart,Stewart,\\"(empty)\\",Sunday,6,\\"abigail@stewart-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563927,\\"sold_product_563927_11755, sold_product_563927_17765\\",\\"sold_product_563927_11755, sold_product_563927_17765\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Primemaster\\",\\"Tigress Enterprises, Primemaster\\",\\"12.25, 57.5\\",\\"24.984, 125\\",\\"11,755, 17,765\\",\\"Sandals - cognac, High heeled boots - Midnight Blue\\",\\"Sandals - cognac, High heeled boots - Midnight Blue\\",\\"1, 1\\",\\"ZO0009800098, ZO0362803628\\",\\"0, 0\\",\\"24.984, 125\\",\\"24.984, 125\\",\\"0, 0\\",\\"ZO0009800098, ZO0362803628\\",150,150,2,2,order,abigail +XQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Mckinney\\",\\"Marwan Mckinney\\",MALE,51,Mckinney,Mckinney,\\"(empty)\\",Sunday,6,\\"marwan@mckinney-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564937,\\"sold_product_564937_1994, sold_product_564937_6646\\",\\"sold_product_564937_1994, sold_product_564937_6646\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"17.484, 35.25\\",\\"33, 75\\",\\"1,994, 6,646\\",\\"Lace-up boots - dark grey, Winter jacket - dark camel\\",\\"Lace-up boots - dark grey, Winter jacket - dark camel\\",\\"1, 1\\",\\"ZO0520605206, ZO0432204322\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0520605206, ZO0432204322\\",108,108,2,2,order,marwan +XgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Henderson\\",\\"Yasmine Henderson\\",FEMALE,43,Henderson,Henderson,\\"(empty)\\",Sunday,6,\\"yasmine@henderson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564994,\\"sold_product_564994_16814, sold_product_564994_17456\\",\\"sold_product_564994_16814, sold_product_564994_17456\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Spherecords Curvy\\",\\"Pyramidustries, Spherecords Curvy\\",\\"12.992, 6.109\\",\\"24.984, 11.992\\",\\"16,814, 17,456\\",\\"Sweatshirt - light grey multicolor, Long sleeved top - dark grey multicolor\\",\\"Sweatshirt - light grey multicolor, Long sleeved top - dark grey multicolor\\",\\"1, 1\\",\\"ZO0180601806, ZO0710007100\\",\\"0, 0\\",\\"24.984, 11.992\\",\\"24.984, 11.992\\",\\"0, 0\\",\\"ZO0180601806, ZO0710007100\\",\\"36.969\\",\\"36.969\\",2,2,order,yasmine +XwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Howell\\",\\"rania Howell\\",FEMALE,24,Howell,Howell,\\"(empty)\\",Sunday,6,\\"rania@howell-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564070,\\"sold_product_564070_23824, sold_product_564070_5275\\",\\"sold_product_564070_23824, sold_product_564070_5275\\",\\"55, 65\\",\\"55, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Oceanavigations\\",\\"Gnomehouse mom, Oceanavigations\\",\\"29.688, 35.094\\",\\"55, 65\\",\\"23,824, 5,275\\",\\"Summer dress - red ochre, Boots - dark brown\\",\\"Summer dress - red ochre, Boots - dark brown\\",\\"1, 1\\",\\"ZO0234202342, ZO0245102451\\",\\"0, 0\\",\\"55, 65\\",\\"55, 65\\",\\"0, 0\\",\\"ZO0234202342, ZO0245102451\\",120,120,2,2,order,rani +YAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Miller\\",\\"Jackson Miller\\",MALE,13,Miller,Miller,\\"(empty)\\",Sunday,6,\\"jackson@miller-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563928,\\"sold_product_563928_17644, sold_product_563928_11004\\",\\"sold_product_563928_17644, sold_product_563928_11004\\",\\"60, 50\\",\\"60, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"29.406, 26.484\\",\\"60, 50\\",\\"17,644, 11,004\\",\\"Suit jacket - dark blue, Casual lace-ups - Gold/cognac/lion\\",\\"Suit jacket - dark blue, Casual lace-ups - Gold/cognac/lion\\",\\"1, 1\\",\\"ZO0424104241, ZO0394103941\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0424104241, ZO0394103941\\",110,110,2,2,order,jackson +xQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Morrison\\",\\"Rabbia Al Morrison\\",FEMALE,5,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"rabbia al@morrison-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Spherecords, Pyramidustries\\",\\"Tigress Enterprises, Spherecords, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",727071,\\"sold_product_727071_20781, sold_product_727071_23338, sold_product_727071_15267, sold_product_727071_12138\\",\\"sold_product_727071_20781, sold_product_727071_23338, sold_product_727071_15267, sold_product_727071_12138\\",\\"17.984, 16.984, 16.984, 32\\",\\"17.984, 16.984, 16.984, 32\\",\\"Women's Accessories, Women's Clothing, Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Clothing, Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Tigress Enterprises, Spherecords, Pyramidustries, Tigress Enterprises\\",\\"8.102, 9.172, 7.988, 16.953\\",\\"17.984, 16.984, 16.984, 32\\",\\"20,781, 23,338, 15,267, 12,138\\",\\"Across body bag - old rose , Pyjama set - grey/pink, Handbag - grey, Handbag - black\\",\\"Across body bag - old rose , Pyjama set - grey/pink, Handbag - grey, Handbag - black\\",\\"1, 1, 1, 1\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\",\\"0, 0, 0, 0\\",\\"17.984, 16.984, 16.984, 32\\",\\"17.984, 16.984, 16.984, 32\\",\\"0, 0, 0, 0\\",\\"ZO0091900919, ZO0660006600, ZO0197001970, ZO0074600746\\",84,84,4,4,order,rabbia +zAMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Benson\\",\\"Phil Benson\\",MALE,50,Benson,Benson,\\"(empty)\\",Sunday,6,\\"phil@benson-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565284,\\"sold_product_565284_587, sold_product_565284_12864\\",\\"sold_product_565284_587, sold_product_565284_12864\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"27.594, 11.719\\",\\"60, 22.984\\",\\"587, 12,864\\",\\"Boots - cognac, SLIM FIT - Formal shirt - black\\",\\"Boots - cognac, SLIM FIT - Formal shirt - black\\",\\"1, 1\\",\\"ZO0687206872, ZO0422304223\\",\\"0, 0\\",\\"60, 22.984\\",\\"60, 22.984\\",\\"0, 0\\",\\"ZO0687206872, ZO0422304223\\",83,83,2,2,order,phil +0AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cook\\",\\"Stephanie Cook\\",FEMALE,6,Cook,Cook,\\"(empty)\\",Sunday,6,\\"stephanie@cook-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564380,\\"sold_product_564380_13907, sold_product_564380_23338\\",\\"sold_product_564380_13907, sold_product_564380_23338\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"16.656, 9.172\\",\\"37, 16.984\\",\\"13,907, 23,338\\",\\"Summer dress - black/Blue Violety, Pyjama set - grey/pink\\",\\"Summer dress - black/Blue Violety, Pyjama set - grey/pink\\",\\"1, 1\\",\\"ZO0050400504, ZO0660006600\\",\\"0, 0\\",\\"37, 16.984\\",\\"37, 16.984\\",\\"0, 0\\",\\"ZO0050400504, ZO0660006600\\",\\"53.969\\",\\"53.969\\",2,2,order,stephanie +JQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Howell\\",\\"Clarice Howell\\",FEMALE,18,Howell,Howell,\\"(empty)\\",Sunday,6,\\"clarice@howell-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565276,\\"sold_product_565276_19432, sold_product_565276_23037\\",\\"sold_product_565276_19432, sold_product_565276_23037\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"10.906, 34.5\\",\\"20.984, 75\\",\\"19,432, 23,037\\",\\"Slip-ons - black, Lace-ups - black\\",\\"Slip-ons - black, Lace-ups - black\\",\\"1, 1\\",\\"ZO0131501315, ZO0668806688\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0131501315, ZO0668806688\\",96,96,2,2,order,clarice +JgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Marshall\\",\\"Stephanie Marshall\\",FEMALE,6,Marshall,Marshall,\\"(empty)\\",Sunday,6,\\"stephanie@marshall-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564819,\\"sold_product_564819_22794, sold_product_564819_20865\\",\\"sold_product_564819_22794, sold_product_564819_20865\\",\\"100, 65\\",\\"100, 65\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"46, 34.438\\",\\"100, 65\\",\\"22,794, 20,865\\",\\"Boots - Midnight Blue, Handbag - black\\",\\"Boots - Midnight Blue, Handbag - black\\",\\"1, 1\\",\\"ZO0374603746, ZO0697106971\\",\\"0, 0\\",\\"100, 65\\",\\"100, 65\\",\\"0, 0\\",\\"ZO0374603746, ZO0697106971\\",165,165,2,2,order,stephanie +yQMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Foster\\",\\"Eddie Foster\\",MALE,38,Foster,Foster,\\"(empty)\\",Sunday,6,\\"eddie@foster-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions, Elitelligence\\",\\"Low Tide Media, Microlutions, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",717243,\\"sold_product_717243_19724, sold_product_717243_20018, sold_product_717243_21122, sold_product_717243_13406\\",\\"sold_product_717243_19724, sold_product_717243_20018, sold_product_717243_21122, sold_product_717243_13406\\",\\"18.984, 33, 20.984, 11.992\\",\\"18.984, 33, 20.984, 11.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Microlutions, Low Tide Media, Elitelligence\\",\\"Low Tide Media, Microlutions, Low Tide Media, Elitelligence\\",\\"9.117, 16.172, 10.289, 6.59\\",\\"18.984, 33, 20.984, 11.992\\",\\"19,724, 20,018, 21,122, 13,406\\",\\"Swimming shorts - dark blue, Sweatshirt - Medium Spring Green, Sweatshirt - green , Basic T-shirt - blue\\",\\"Swimming shorts - dark blue, Sweatshirt - Medium Spring Green, Sweatshirt - green , Basic T-shirt - blue\\",\\"1, 1, 1, 1\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\",\\"0, 0, 0, 0\\",\\"18.984, 33, 20.984, 11.992\\",\\"18.984, 33, 20.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0479104791, ZO0125301253, ZO0459004590, ZO0549905499\\",\\"84.938\\",\\"84.938\\",4,4,order,eddie +6QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Phelps\\",\\"Pia Phelps\\",FEMALE,45,Phelps,Phelps,\\"(empty)\\",Sunday,6,\\"pia@phelps-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564140,\\"sold_product_564140_14794, sold_product_564140_18586\\",\\"sold_product_564140_14794, sold_product_564140_18586\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Oceanavigations\\",\\"Pyramidustries active, Oceanavigations\\",\\"5.762, 21.828\\",\\"11.992, 42\\",\\"14,794, 18,586\\",\\"Vest - sheer pink, Cardigan - dark green\\",\\"Vest - sheer pink, Cardigan - dark green\\",\\"1, 1\\",\\"ZO0221002210, ZO0268502685\\",\\"0, 0\\",\\"11.992, 42\\",\\"11.992, 42\\",\\"0, 0\\",\\"ZO0221002210, ZO0268502685\\",\\"53.969\\",\\"53.969\\",2,2,order,pia +6gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Jenkins\\",\\"Rabbia Al Jenkins\\",FEMALE,5,Jenkins,Jenkins,\\"(empty)\\",Sunday,6,\\"rabbia al@jenkins-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564164,\\"sold_product_564164_17391, sold_product_564164_11357\\",\\"sold_product_564164_17391, sold_product_564164_11357\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Pyramidustries\\",\\"Angeldale, Pyramidustries\\",\\"46.75, 6.469\\",\\"85, 11.992\\",\\"17,391, 11,357\\",\\"Ankle boots - black, Pyjama bottoms - grey\\",\\"Ankle boots - black, Pyjama bottoms - grey\\",\\"1, 1\\",\\"ZO0673506735, ZO0213002130\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0673506735, ZO0213002130\\",97,97,2,2,order,rabbia +6wMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Ruiz\\",\\"Betty Ruiz\\",FEMALE,44,Ruiz,Ruiz,\\"(empty)\\",Sunday,6,\\"betty@ruiz-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564207,\\"sold_product_564207_11825, sold_product_564207_17988\\",\\"sold_product_564207_11825, sold_product_564207_17988\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"11.5, 18.125\\",\\"24.984, 37\\",\\"11,825, 17,988\\",\\"Cardigan - black, Cardigan - sand mel/black\\",\\"Cardigan - black, Cardigan - sand mel/black\\",\\"1, 1\\",\\"ZO0711807118, ZO0073100731\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0711807118, ZO0073100731\\",\\"61.969\\",\\"61.969\\",2,2,order,betty +7QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Kim\\",\\"Thad Kim\\",MALE,30,Kim,Kim,\\"(empty)\\",Sunday,6,\\"thad@kim-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564735,\\"sold_product_564735_13418, sold_product_564735_14150\\",\\"sold_product_564735_13418, sold_product_564735_14150\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"9, 8.492\\",\\"16.984, 16.984\\",\\"13,418, 14,150\\",\\"High-top trainers - navy, Print T-shirt - black\\",\\"High-top trainers - navy, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0509705097, ZO0120501205\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0509705097, ZO0120501205\\",\\"33.969\\",\\"33.969\\",2,2,order,thad +8gMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Hudson\\",\\"Sultan Al Hudson\\",MALE,19,Hudson,Hudson,\\"(empty)\\",Sunday,6,\\"sultan al@hudson-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Microlutions,Microlutions,\\"Jun 22, 2019 @ 00:00:00.000\\",565077,\\"sold_product_565077_21138, sold_product_565077_20998\\",\\"sold_product_565077_21138, sold_product_565077_20998\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"9.172, 14.781\\",\\"16.984, 28.984\\",\\"21,138, 20,998\\",\\"Basic T-shirt - black, Sweatshirt - black\\",\\"Basic T-shirt - black, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0118701187, ZO0123901239\\",\\"0, 0\\",\\"16.984, 28.984\\",\\"16.984, 28.984\\",\\"0, 0\\",\\"ZO0118701187, ZO0123901239\\",\\"45.969\\",\\"45.969\\",2,2,order,sultan +AAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Wood\\",\\"Jackson Wood\\",MALE,13,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jackson@wood-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564274,\\"sold_product_564274_23599, sold_product_564274_23910\\",\\"sold_product_564274_23599, sold_product_564274_23910\\",\\"75, 26.984\\",\\"75, 26.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"34.5, 13.758\\",\\"75, 26.984\\",\\"23,599, 23,910\\",\\"Winter jacket - oliv, Shorts - dark blue\\",\\"Winter jacket - oliv, Shorts - dark blue\\",\\"1, 1\\",\\"ZO0542905429, ZO0423604236\\",\\"0, 0\\",\\"75, 26.984\\",\\"75, 26.984\\",\\"0, 0\\",\\"ZO0542905429, ZO0423604236\\",102,102,2,2,order,jackson +HgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Walters\\",\\"Thad Walters\\",MALE,30,Walters,Walters,\\"(empty)\\",Sunday,6,\\"thad@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565161,\\"sold_product_565161_23831, sold_product_565161_13178\\",\\"sold_product_565161_23831, sold_product_565161_13178\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.5, 32.375\\",\\"10.992, 60\\",\\"23,831, 13,178\\",\\"Basic T-shirt - oliv , Light jacket - navy\\",\\"Basic T-shirt - oliv , Light jacket - navy\\",\\"1, 1\\",\\"ZO0441404414, ZO0430504305\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0441404414, ZO0430504305\\",71,71,2,2,order,thad +HwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Taylor\\",\\"Selena Taylor\\",FEMALE,42,Taylor,Taylor,\\"(empty)\\",Sunday,6,\\"selena@taylor-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Champion Arts, Angeldale\\",\\"Champion Arts, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565039,\\"sold_product_565039_17587, sold_product_565039_19471\\",\\"sold_product_565039_17587, sold_product_565039_19471\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Angeldale\\",\\"Champion Arts, Angeldale\\",\\"8.328, 6.859\\",\\"16.984, 13.992\\",\\"17,587, 19,471\\",\\"Jersey dress - khaki, Belt - dark brown\\",\\"Jersey dress - khaki, Belt - dark brown\\",\\"1, 1\\",\\"ZO0489804898, ZO0695006950\\",\\"0, 0\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"0, 0\\",\\"ZO0489804898, ZO0695006950\\",\\"30.984\\",\\"30.984\\",2,2,order,selena +PwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Stokes\\",\\"Elyssa Stokes\\",FEMALE,27,Stokes,Stokes,\\"(empty)\\",Sunday,6,\\"elyssa@stokes-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Champion Arts, Pyramidustries\\",\\"Spherecords, Champion Arts, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",723683,\\"sold_product_723683_19440, sold_product_723683_17349, sold_product_723683_14873, sold_product_723683_24863\\",\\"sold_product_723683_19440, sold_product_723683_17349, sold_product_723683_14873, sold_product_723683_24863\\",\\"10.992, 33, 42, 11.992\\",\\"10.992, 33, 42, 11.992\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Champion Arts, Pyramidustries, Champion Arts\\",\\"Spherecords, Champion Arts, Pyramidustries, Champion Arts\\",\\"5.93, 18.141, 21, 5.879\\",\\"10.992, 33, 42, 11.992\\",\\"19,440, 17,349, 14,873, 24,863\\",\\"Long sleeved top - dark green, Bomber Jacket - khaki/black, Platform boots - grey, Vest - black/white\\",\\"Long sleeved top - dark green, Bomber Jacket - khaki/black, Platform boots - grey, Vest - black/white\\",\\"1, 1, 1, 1\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\",\\"0, 0, 0, 0\\",\\"10.992, 33, 42, 11.992\\",\\"10.992, 33, 42, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0648206482, ZO0496104961, ZO0142601426, ZO0491504915\\",\\"97.938\\",\\"97.938\\",4,4,order,elyssa +CAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Lloyd\\",\\"Stephanie Lloyd\\",FEMALE,6,Lloyd,Lloyd,\\"(empty)\\",Sunday,6,\\"stephanie@lloyd-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563967,\\"sold_product_563967_21565, sold_product_563967_8534\\",\\"sold_product_563967_21565, sold_product_563967_8534\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Spherecords\\",\\"Champion Arts, Spherecords\\",\\"5.281, 5.82\\",\\"10.992, 10.992\\",\\"21,565, 8,534\\",\\"Print T-shirt - dark grey multicolor, Long sleeved top - black\\",\\"Print T-shirt - dark grey multicolor, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0493404934, ZO0640806408\\",\\"0, 0\\",\\"10.992, 10.992\\",\\"10.992, 10.992\\",\\"0, 0\\",\\"ZO0493404934, ZO0640806408\\",\\"21.984\\",\\"21.984\\",2,2,order,stephanie +LwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Rodriguez\\",\\"Abigail Rodriguez\\",FEMALE,46,Rodriguez,Rodriguez,\\"(empty)\\",Sunday,6,\\"abigail@rodriguez-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564533,\\"sold_product_564533_15845, sold_product_564533_17192\\",\\"sold_product_564533_15845, sold_product_564533_17192\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Tigress Enterprises\\",\\"Champion Arts, Tigress Enterprises\\",\\"23.094, 16.5\\",\\"42, 33\\",\\"15,845, 17,192\\",\\"Summer jacket - black, Jersey dress - black\\",\\"Summer jacket - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0496704967, ZO0049700497\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0496704967, ZO0049700497\\",75,75,2,2,order,abigail +NwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Frances,Frances,\\"Frances Dennis\\",\\"Frances Dennis\\",FEMALE,49,Dennis,Dennis,\\"(empty)\\",Sunday,6,\\"frances@dennis-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565266,\\"sold_product_565266_18617, sold_product_565266_17793\\",\\"sold_product_565266_18617, sold_product_565266_17793\\",\\"60, 35\\",\\"60, 35\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"31.797, 16.453\\",\\"60, 35\\",\\"18,617, 17,793\\",\\"Slip-ons - black, Briefcase - black\\",\\"Slip-ons - black, Briefcase - black\\",\\"1, 1\\",\\"ZO0255602556, ZO0468304683\\",\\"0, 0\\",\\"60, 35\\",\\"60, 35\\",\\"0, 0\\",\\"ZO0255602556, ZO0468304683\\",95,95,2,2,order,frances +OAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al James\\",\\"Ahmed Al James\\",MALE,4,James,James,\\"(empty)\\",Sunday,6,\\"ahmed al@james-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564818,\\"sold_product_564818_12813, sold_product_564818_24108\\",\\"sold_product_564818_12813, sold_product_564818_24108\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.52, 11.25\\",\\"11.992, 24.984\\",\\"12,813, 24,108\\",\\"2 PACK - Basic T-shirt - black, SLIM FIT - Formal shirt - light blue\\",\\"2 PACK - Basic T-shirt - black, SLIM FIT - Formal shirt - light blue\\",\\"1, 1\\",\\"ZO0475004750, ZO0412304123\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0475004750, ZO0412304123\\",\\"36.969\\",\\"36.969\\",2,2,order,ahmed +XQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Yahya,Yahya,\\"Yahya Turner\\",\\"Yahya Turner\\",MALE,23,Turner,Turner,\\"(empty)\\",Sunday,6,\\"yahya@turner-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",564932,\\"sold_product_564932_23918, sold_product_564932_23529\\",\\"sold_product_564932_23918, sold_product_564932_23529\\",\\"7.988, 20.984\\",\\"7.988, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"4.148, 10.906\\",\\"7.988, 20.984\\",\\"23,918, 23,529\\",\\"Print T-shirt - red, Across body bag - blue/cognac\\",\\"Print T-shirt - red, Across body bag - blue/cognac\\",\\"1, 1\\",\\"ZO0557305573, ZO0607806078\\",\\"0, 0\\",\\"7.988, 20.984\\",\\"7.988, 20.984\\",\\"0, 0\\",\\"ZO0557305573, ZO0607806078\\",\\"28.984\\",\\"28.984\\",2,2,order,yahya +XgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Banks\\",\\"Clarice Banks\\",FEMALE,18,Banks,Banks,\\"(empty)\\",Sunday,6,\\"clarice@banks-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564968,\\"sold_product_564968_14312, sold_product_564968_22436\\",\\"sold_product_564968_14312, sold_product_564968_22436\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.844, 9.492\\",\\"33, 18.984\\",\\"14,312, 22,436\\",\\"High heels - yellow, Vest - gold metallic\\",\\"High heels - yellow, Vest - gold metallic\\",\\"1, 1\\",\\"ZO0134101341, ZO0062400624\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0134101341, ZO0062400624\\",\\"51.969\\",\\"51.969\\",2,2,order,clarice +XwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Morrison\\",\\"Betty Morrison\\",FEMALE,44,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"betty@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 22, 2019 @ 00:00:00.000\\",565002,\\"sold_product_565002_22932, sold_product_565002_21168\\",\\"sold_product_565002_22932, sold_product_565002_21168\\",\\"100, 75\\",\\"100, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"54, 33.75\\",\\"100, 75\\",\\"22,932, 21,168\\",\\"Classic coat - grey, Cocktail dress / Party dress - eclipse\\",\\"Classic coat - grey, Cocktail dress / Party dress - eclipse\\",\\"1, 1\\",\\"ZO0354203542, ZO0338503385\\",\\"0, 0\\",\\"100, 75\\",\\"100, 75\\",\\"0, 0\\",\\"ZO0354203542, ZO0338503385\\",175,175,2,2,order,betty +YQMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Conner\\",\\"Robbie Conner\\",MALE,48,Conner,Conner,\\"(empty)\\",Sunday,6,\\"robbie@conner-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564095,\\"sold_product_564095_23104, sold_product_564095_24934\\",\\"sold_product_564095_23104, sold_product_564095_24934\\",\\"10.992, 50\\",\\"10.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 22.5\\",\\"10.992, 50\\",\\"23,104, 24,934\\",\\"5 PACK - Socks - multicoloured, Lace-up boots - resin coffee\\",\\"5 PACK - Socks - multicoloured, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0613806138, ZO0403504035\\",\\"0, 0\\",\\"10.992, 50\\",\\"10.992, 50\\",\\"0, 0\\",\\"ZO0613806138, ZO0403504035\\",\\"60.969\\",\\"60.969\\",2,2,order,robbie +YgMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Clayton\\",\\"Yuri Clayton\\",MALE,21,Clayton,Clayton,\\"(empty)\\",Sunday,6,\\"yuri@clayton-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Elitelligence,Elitelligence,\\"Jun 22, 2019 @ 00:00:00.000\\",563924,\\"sold_product_563924_14271, sold_product_563924_15400\\",\\"sold_product_563924_14271, sold_product_563924_15400\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"23, 7.051\\",\\"50, 14.992\\",\\"14,271, 15,400\\",\\"Bomber Jacket - blue mix, Long sleeved top - khaki\\",\\"Bomber Jacket - blue mix, Long sleeved top - khaki\\",\\"1, 1\\",\\"ZO0539805398, ZO0554205542\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0539805398, ZO0554205542\\",65,65,2,2,order,yuri +7AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Sunday,6,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564770,\\"sold_product_564770_15776, sold_product_564770_17904\\",\\"sold_product_564770_15776, sold_product_564770_17904\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"Spherecords Maternity, Tigress Enterprises\\",\\"10.078, 17.156\\",\\"20.984, 33\\",\\"15,776, 17,904\\",\\"2 PACK - Leggings - black, Ankle boots - black\\",\\"2 PACK - Leggings - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0704907049, ZO0024700247\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0704907049, ZO0024700247\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +SQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Adams\\",\\"Elyssa Adams\\",FEMALE,27,Adams,Adams,\\"(empty)\\",Sunday,6,\\"elyssa@adams-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563965,\\"sold_product_563965_18560, sold_product_563965_14856\\",\\"sold_product_563965_18560, sold_product_563965_14856\\",\\"34, 18.984\\",\\"34, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"18.016, 9.313\\",\\"34, 18.984\\",\\"18,560, 14,856\\",\\"Summer dress - peacoat/pomegranade, Sweatshirt - grey\\",\\"Summer dress - peacoat/pomegranade, Sweatshirt - grey\\",\\"1, 1\\",\\"ZO0045800458, ZO0503405034\\",\\"0, 0\\",\\"34, 18.984\\",\\"34, 18.984\\",\\"0, 0\\",\\"ZO0045800458, ZO0503405034\\",\\"52.969\\",\\"52.969\\",2,2,order,elyssa +ZAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Powell\\",\\"rania Powell\\",FEMALE,24,Powell,Powell,\\"(empty)\\",Sunday,6,\\"rania@powell-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564957,\\"sold_product_564957_22053, sold_product_564957_17382\\",\\"sold_product_564957_22053, sold_product_564957_17382\\",\\"28.984, 6.988\\",\\"28.984, 6.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"15.648, 3.359\\",\\"28.984, 6.988\\",\\"22,053, 17,382\\",\\"Shirt - light blue, Tights - black\\",\\"Shirt - light blue, Tights - black\\",\\"1, 1\\",\\"ZO0171601716, ZO0214602146\\",\\"0, 0\\",\\"28.984, 6.988\\",\\"28.984, 6.988\\",\\"0, 0\\",\\"ZO0171601716, ZO0214602146\\",\\"35.969\\",\\"35.969\\",2,2,order,rani +ZQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jim,Jim,\\"Jim Brewer\\",\\"Jim Brewer\\",MALE,41,Brewer,Brewer,\\"(empty)\\",Sunday,6,\\"jim@brewer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564032,\\"sold_product_564032_20226, sold_product_564032_16558\\",\\"sold_product_564032_20226, sold_product_564032_16558\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"15.648, 15.508\\",\\"28.984, 33\\",\\"20,226, 16,558\\",\\"Pyjamas - grey/blue, Boots - dark brown\\",\\"Pyjamas - grey/blue, Boots - dark brown\\",\\"1, 1\\",\\"ZO0478404784, ZO0521905219\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0478404784, ZO0521905219\\",\\"61.969\\",\\"61.969\\",2,2,order,jim +ZgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Estrada\\",\\"Muniz Estrada\\",MALE,37,Estrada,Estrada,\\"(empty)\\",Sunday,6,\\"muniz@estrada-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564075,\\"sold_product_564075_21248, sold_product_564075_12047\\",\\"sold_product_564075_21248, sold_product_564075_12047\\",\\"27.984, 20.984\\",\\"27.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"13.992, 10.289\\",\\"27.984, 20.984\\",\\"21,248, 12,047\\",\\"Windbreaker - navy blazer, Tracksuit bottoms - dark red\\",\\"Windbreaker - navy blazer, Tracksuit bottoms - dark red\\",\\"1, 1\\",\\"ZO0622706227, ZO0525405254\\",\\"0, 0\\",\\"27.984, 20.984\\",\\"27.984, 20.984\\",\\"0, 0\\",\\"ZO0622706227, ZO0525405254\\",\\"48.969\\",\\"48.969\\",2,2,order,muniz +ZwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Samir,Samir,\\"Samir Mckinney\\",\\"Samir Mckinney\\",MALE,34,Mckinney,Mckinney,\\"(empty)\\",Sunday,6,\\"samir@mckinney-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563931,\\"sold_product_563931_3103, sold_product_563931_11153\\",\\"sold_product_563931_3103, sold_product_563931_11153\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.703, 5.172\\",\\"20.984, 10.992\\",\\"3,103, 11,153\\",\\"Polo shirt - light grey multicolor, Cap - black/black\\",\\"Polo shirt - light grey multicolor, Cap - black/black\\",\\"1, 1\\",\\"ZO0444304443, ZO0596505965\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0444304443, ZO0596505965\\",\\"31.984\\",\\"31.984\\",2,2,order,samir +lgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Palmer\\",\\"Clarice Palmer\\",FEMALE,18,Palmer,Palmer,\\"(empty)\\",Sunday,6,\\"clarice@palmer-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564940,\\"sold_product_564940_13407, sold_product_564940_15116\\",\\"sold_product_564940_13407, sold_product_564940_15116\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.922, 11.328\\",\\"28.984, 20.984\\",\\"13,407, 15,116\\",\\"Trainers - offwhite, Wedges - Blue Violety\\",\\"Trainers - offwhite, Wedges - Blue Violety\\",\\"1, 1\\",\\"ZO0026800268, ZO0003600036\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0026800268, ZO0003600036\\",\\"49.969\\",\\"49.969\\",2,2,order,clarice +lwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Hampton\\",\\"Jason Hampton\\",MALE,16,Hampton,Hampton,\\"(empty)\\",Sunday,6,\\"jason@hampton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564987,\\"sold_product_564987_24440, sold_product_564987_12655\\",\\"sold_product_564987_24440, sold_product_564987_12655\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.703, 13.242\\",\\"20.984, 24.984\\",\\"24,440, 12,655\\",\\"Chinos - dark blue, SET - Pyjamas - grey/blue\\",\\"Chinos - dark blue, SET - Pyjamas - grey/blue\\",\\"1, 1\\",\\"ZO0526805268, ZO0478104781\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0526805268, ZO0478104781\\",\\"45.969\\",\\"45.969\\",2,2,order,jason +mQMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Lewis\\",\\"Tariq Lewis\\",MALE,25,Lewis,Lewis,\\"(empty)\\",Sunday,6,\\"tariq@lewis-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564080,\\"sold_product_564080_13013, sold_product_564080_16957\\",\\"sold_product_564080_13013, sold_product_564080_16957\\",\\"28.984, 10.992\\",\\"28.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.211, 5.711\\",\\"28.984, 10.992\\",\\"13,013, 16,957\\",\\"Shirt - light blue, Cap - navy\\",\\"Shirt - light blue, Cap - navy\\",\\"1, 1\\",\\"ZO0415804158, ZO0460804608\\",\\"0, 0\\",\\"28.984, 10.992\\",\\"28.984, 10.992\\",\\"0, 0\\",\\"ZO0415804158, ZO0460804608\\",\\"39.969\\",\\"39.969\\",2,2,order,tariq +mgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Hicham,Hicham,\\"Hicham Love\\",\\"Hicham Love\\",MALE,8,Love,Love,\\"(empty)\\",Sunday,6,\\"hicham@love-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Oceanavigations,Oceanavigations,\\"Jun 22, 2019 @ 00:00:00.000\\",564106,\\"sold_product_564106_14672, sold_product_564106_15019\\",\\"sold_product_564106_14672, sold_product_564106_15019\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"13.922, 8.547\\",\\"28.984, 18.984\\",\\"14,672, 15,019\\",\\"Jumper - dark blue, Wallet - black\\",\\"Jumper - dark blue, Wallet - black\\",\\"1, 1\\",\\"ZO0298002980, ZO0313103131\\",\\"0, 0\\",\\"28.984, 18.984\\",\\"28.984, 18.984\\",\\"0, 0\\",\\"ZO0298002980, ZO0313103131\\",\\"47.969\\",\\"47.969\\",2,2,order,hicham +mwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Foster\\",\\"Gwen Foster\\",FEMALE,26,Foster,Foster,\\"(empty)\\",Sunday,6,\\"gwen@foster-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563947,\\"sold_product_563947_8960, sold_product_563947_19261\\",\\"sold_product_563947_8960, sold_product_563947_19261\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"18.5, 7\\",\\"37, 13.992\\",\\"8,960, 19,261\\",\\"Shirt - soft pink nude, Vest - black\\",\\"Shirt - soft pink nude, Vest - black\\",\\"1, 1\\",\\"ZO0348103481, ZO0164501645\\",\\"0, 0\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"0, 0\\",\\"ZO0348103481, ZO0164501645\\",\\"50.969\\",\\"50.969\\",2,2,order,gwen +FAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Lewis\\",\\"Elyssa Lewis\\",FEMALE,27,Lewis,Lewis,\\"(empty)\\",Sunday,6,\\"elyssa@lewis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",725995,\\"sold_product_725995_10498, sold_product_725995_15404, sold_product_725995_16378, sold_product_725995_12398\\",\\"sold_product_725995_10498, sold_product_725995_15404, sold_product_725995_16378, sold_product_725995_12398\\",\\"20.984, 42, 34, 18.984\\",\\"20.984, 42, 34, 18.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"Pyramidustries active, Gnomehouse, Pyramidustries, Tigress Enterprises MAMA\\",\\"11.328, 21.406, 15.641, 9.68\\",\\"20.984, 42, 34, 18.984\\",\\"10,498, 15,404, 16,378, 12,398\\",\\"Tracksuit bottoms - grey multicolor, Shift dress - Lemon Chiffon, Blazer - black/grey, Vest - navy\\",\\"Tracksuit bottoms - grey multicolor, Shift dress - Lemon Chiffon, Blazer - black/grey, Vest - navy\\",\\"1, 1, 1, 1\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\",\\"0, 0, 0, 0\\",\\"20.984, 42, 34, 18.984\\",\\"20.984, 42, 34, 18.984\\",\\"0, 0, 0, 0\\",\\"ZO0222102221, ZO0332103321, ZO0182701827, ZO0230502305\\",\\"115.938\\",\\"115.938\\",4,4,order,elyssa +JwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,George,George,\\"George Butler\\",\\"George Butler\\",MALE,32,Butler,Butler,\\"(empty)\\",Sunday,6,\\"george@butler-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564756,\\"sold_product_564756_16646, sold_product_564756_21840\\",\\"sold_product_564756_16646, sold_product_564756_21840\\",\\"9.992, 155\\",\\"9.992, 155\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, (empty)\\",\\"Elitelligence, (empty)\\",\\"5.191, 83.688\\",\\"9.992, 155\\",\\"16,646, 21,840\\",\\"Long sleeved top - Medium Slate Blue, Lace-ups - brown\\",\\"Long sleeved top - Medium Slate Blue, Lace-ups - brown\\",\\"1, 1\\",\\"ZO0556805568, ZO0481504815\\",\\"0, 0\\",\\"9.992, 155\\",\\"9.992, 155\\",\\"0, 0\\",\\"ZO0556805568, ZO0481504815\\",165,165,2,2,order,george +ZwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Austin\\",\\"Yuri Austin\\",MALE,21,Austin,Austin,\\"(empty)\\",Sunday,6,\\"yuri@austin-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565137,\\"sold_product_565137_18257, sold_product_565137_24282\\",\\"sold_product_565137_18257, sold_product_565137_24282\\",\\"14.992, 7.988\\",\\"14.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"7.051, 4.148\\",\\"14.992, 7.988\\",\\"18,257, 24,282\\",\\"Print T-shirt - black, Print T-shirt - bordeaux\\",\\"Print T-shirt - black, Print T-shirt - bordeaux\\",\\"1, 1\\",\\"ZO0118501185, ZO0561905619\\",\\"0, 0\\",\\"14.992, 7.988\\",\\"14.992, 7.988\\",\\"0, 0\\",\\"ZO0118501185, ZO0561905619\\",\\"22.984\\",\\"22.984\\",2,2,order,yuri +aAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Evans\\",\\"Elyssa Evans\\",FEMALE,27,Evans,Evans,\\"(empty)\\",Sunday,6,\\"elyssa@evans-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565173,\\"sold_product_565173_20610, sold_product_565173_23026\\",\\"sold_product_565173_20610, sold_product_565173_23026\\",\\"12.992, 42\\",\\"12.992, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"6.879, 20.156\\",\\"12.992, 42\\",\\"20,610, 23,026\\",\\"Clutch - rose, Platform boots - cognac\\",\\"Clutch - rose, Platform boots - cognac\\",\\"1, 1\\",\\"ZO0203802038, ZO0014900149\\",\\"0, 0\\",\\"12.992, 42\\",\\"12.992, 42\\",\\"0, 0\\",\\"ZO0203802038, ZO0014900149\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +aQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Valdez\\",\\"Abdulraheem Al Valdez\\",MALE,33,Valdez,Valdez,\\"(empty)\\",Sunday,6,\\"abdulraheem al@valdez-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565214,\\"sold_product_565214_24934, sold_product_565214_11845\\",\\"sold_product_565214_24934, sold_product_565214_11845\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 9.492\\",\\"50, 18.984\\",\\"24,934, 11,845\\",\\"Lace-up boots - resin coffee, Hoodie - light red\\",\\"Lace-up boots - resin coffee, Hoodie - light red\\",\\"1, 1\\",\\"ZO0403504035, ZO0588705887\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0588705887\\",69,69,2,2,order,abdulraheem +mQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Mary,Mary,\\"Mary Frank\\",\\"Mary Frank\\",FEMALE,20,Frank,Frank,\\"(empty)\\",Sunday,6,\\"mary@frank-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564804,\\"sold_product_564804_16840, sold_product_564804_21361\\",\\"sold_product_564804_16840, sold_product_564804_21361\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"17.766, 5.172\\",\\"37, 10.992\\",\\"16,840, 21,361\\",\\"Pencil skirt - black, Long sleeved top - dark brown\\",\\"Pencil skirt - black, Long sleeved top - dark brown\\",\\"1, 1\\",\\"ZO0259702597, ZO0640606406\\",\\"0, 0\\",\\"37, 10.992\\",\\"37, 10.992\\",\\"0, 0\\",\\"ZO0259702597, ZO0640606406\\",\\"47.969\\",\\"47.969\\",2,2,order,mary +pAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Hubbard\\",\\"Yasmine Hubbard\\",FEMALE,43,Hubbard,Hubbard,\\"(empty)\\",Sunday,6,\\"yasmine@hubbard-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565052,\\"sold_product_565052_20949, sold_product_565052_16543\\",\\"sold_product_565052_20949, sold_product_565052_16543\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"30.594, 9.453\\",\\"60, 20.984\\",\\"20,949, 16,543\\",\\"Tote bag - cognac, Blouse - black\\",\\"Tote bag - cognac, Blouse - black\\",\\"1, 1\\",\\"ZO0697006970, ZO0711407114\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0697006970, ZO0711407114\\",81,81,2,2,order,yasmine +pQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Reyes\\",\\"Pia Reyes\\",FEMALE,45,Reyes,Reyes,\\"(empty)\\",Sunday,6,\\"pia@reyes-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565091,\\"sold_product_565091_5862, sold_product_565091_12548\\",\\"sold_product_565091_5862, sold_product_565091_12548\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"31.203, 11.5\\",\\"65, 24.984\\",\\"5,862, 12,548\\",\\"Boots - taupe, Handbag - creme/grey\\",\\"Boots - taupe, Handbag - creme/grey\\",\\"1, 1\\",\\"ZO0324703247, ZO0088600886\\",\\"0, 0\\",\\"65, 24.984\\",\\"65, 24.984\\",\\"0, 0\\",\\"ZO0324703247, ZO0088600886\\",90,90,2,2,order,pia +rgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Stokes\\",\\"Wilhemina St. Stokes\\",FEMALE,17,Stokes,Stokes,\\"(empty)\\",Sunday,6,\\"wilhemina st.@stokes-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565231,\\"sold_product_565231_17601, sold_product_565231_11904\\",\\"sold_product_565231_17601, sold_product_565231_11904\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"20.156, 15.07\\",\\"42, 28.984\\",\\"17,601, 11,904\\",\\"Cape - Pale Violet Red, Trainers - rose\\",\\"Cape - Pale Violet Red, Trainers - rose\\",\\"1, 1\\",\\"ZO0235202352, ZO0135001350\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0235202352, ZO0135001350\\",71,71,2,2,order,wilhemina +9wMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Hodges\\",\\"Stephanie Hodges\\",FEMALE,6,Hodges,Hodges,\\"(empty)\\",Sunday,6,\\"stephanie@hodges-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564190,\\"sold_product_564190_5329, sold_product_564190_16930\\",\\"sold_product_564190_5329, sold_product_564190_16930\\",\\"115, 24.984\\",\\"115, 24.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"62.094, 13.242\\",\\"115, 24.984\\",\\"5,329, 16,930\\",\\"Over-the-knee boots - Midnight Blue, Across body bag - Blue Violety \\",\\"Over-the-knee boots - Midnight Blue, Across body bag - Blue Violety \\",\\"1, 1\\",\\"ZO0243902439, ZO0208702087\\",\\"0, 0\\",\\"115, 24.984\\",\\"115, 24.984\\",\\"0, 0\\",\\"ZO0243902439, ZO0208702087\\",140,140,2,2,order,stephanie +EgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Kim\\",\\"Selena Kim\\",FEMALE,42,Kim,Kim,\\"(empty)\\",Sunday,6,\\"selena@kim-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Pyramidustries,Pyramidustries,\\"Jun 22, 2019 @ 00:00:00.000\\",564876,\\"sold_product_564876_12273, sold_product_564876_21758\\",\\"sold_product_564876_12273, sold_product_564876_21758\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"6.371, 6.23\\",\\"12.992, 11.992\\",\\"12,273, 21,758\\",\\"2 PACK - Over-the-knee socks - black, Print T-shirt - black\\",\\"2 PACK - Over-the-knee socks - black, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0215502155, ZO0168101681\\",\\"0, 0\\",\\"12.992, 11.992\\",\\"12.992, 11.992\\",\\"0, 0\\",\\"ZO0215502155, ZO0168101681\\",\\"24.984\\",\\"24.984\\",2,2,order,selena +EwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Garza\\",\\"Elyssa Garza\\",FEMALE,27,Garza,Garza,\\"(empty)\\",Sunday,6,\\"elyssa@garza-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Karmanite\\",\\"Angeldale, Karmanite\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564902,\\"sold_product_564902_13639, sold_product_564902_22060\\",\\"sold_product_564902_13639, sold_product_564902_22060\\",\\"60, 100\\",\\"60, 100\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Karmanite\\",\\"Angeldale, Karmanite\\",\\"28.203, 51\\",\\"60, 100\\",\\"13,639, 22,060\\",\\"Handbag - taupe, Boots - grey\\",\\"Handbag - taupe, Boots - grey\\",\\"1, 1\\",\\"ZO0698406984, ZO0704207042\\",\\"0, 0\\",\\"60, 100\\",\\"60, 100\\",\\"0, 0\\",\\"ZO0698406984, ZO0704207042\\",160,160,2,2,order,elyssa +JwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Garza\\",\\"Elyssa Garza\\",FEMALE,27,Garza,Garza,\\"(empty)\\",Sunday,6,\\"elyssa@garza-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564761,\\"sold_product_564761_12146, sold_product_564761_24585\\",\\"sold_product_564761_12146, sold_product_564761_24585\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Spherecords Curvy\\",\\"Angeldale, Spherecords Curvy\\",\\"29.25, 9\\",\\"65, 16.984\\",\\"12,146, 24,585\\",\\"Slip-ons - red, Jersey dress - black\\",\\"Slip-ons - red, Jersey dress - black\\",\\"1, 1\\",\\"ZO0665006650, ZO0709407094\\",\\"0, 0\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"0, 0\\",\\"ZO0665006650, ZO0709407094\\",82,82,2,2,order,elyssa +MQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Underwood\\",\\"Elyssa Underwood\\",FEMALE,27,Underwood,Underwood,\\"(empty)\\",Sunday,6,\\"elyssa@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Jun 22, 2019 @ 00:00:00.000\\",731788,\\"sold_product_731788_22537, sold_product_731788_11189, sold_product_731788_14323, sold_product_731788_15479\\",\\"sold_product_731788_22537, sold_product_731788_11189, sold_product_731788_14323, sold_product_731788_15479\\",\\"20.984, 16.984, 85, 50\\",\\"20.984, 16.984, 85, 50\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"Champion Arts, Pyramidustries, Angeldale, Gnomehouse\\",\\"10.289, 8.656, 39.938, 22.5\\",\\"20.984, 16.984, 85, 50\\",\\"22,537, 11,189, 14,323, 15,479\\",\\"Tracksuit bottoms - dark grey multicolor, Cardigan - black, Ankle boots - black, Summer dress - dusty rose\\",\\"Tracksuit bottoms - dark grey multicolor, Cardigan - black, Ankle boots - black, Summer dress - dusty rose\\",\\"1, 1, 1, 1\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\",\\"0, 0, 0, 0\\",\\"20.984, 16.984, 85, 50\\",\\"20.984, 16.984, 85, 50\\",\\"0, 0, 0, 0\\",\\"ZO0486004860, ZO0177901779, ZO0680506805, ZO0340503405\\",173,173,4,4,order,elyssa +TQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Recip,Recip,\\"Recip Morrison\\",\\"Recip Morrison\\",MALE,10,Morrison,Morrison,\\"(empty)\\",Sunday,6,\\"recip@morrison-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564340,\\"sold_product_564340_12840, sold_product_564340_24691\\",\\"sold_product_564340_12840, sold_product_564340_24691\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"30.547, 8.156\\",\\"65, 16.984\\",\\"12,840, 24,691\\",\\"Lace-up boots - black, Long sleeved top - olive\\",\\"Lace-up boots - black, Long sleeved top - olive\\",\\"1, 1\\",\\"ZO0399703997, ZO0565805658\\",\\"0, 0\\",\\"65, 16.984\\",\\"65, 16.984\\",\\"0, 0\\",\\"ZO0399703997, ZO0565805658\\",82,82,2,2,order,recip +TgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,rania,rania,\\"rania Wise\\",\\"rania Wise\\",FEMALE,24,Wise,Wise,\\"(empty)\\",Sunday,6,\\"rania@wise-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564395,\\"sold_product_564395_16857, sold_product_564395_21378\\",\\"sold_product_564395_16857, sold_product_564395_21378\\",\\"50, 11.992\\",\\"50, 11.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"24, 6.109\\",\\"50, 11.992\\",\\"16,857, 21,378\\",\\"Ballet pumps - night, Pyjama bottoms - pink\\",\\"Ballet pumps - night, Pyjama bottoms - pink\\",\\"1, 1\\",\\"ZO0236702367, ZO0660706607\\",\\"0, 0\\",\\"50, 11.992\\",\\"50, 11.992\\",\\"0, 0\\",\\"ZO0236702367, ZO0660706607\\",\\"61.969\\",\\"61.969\\",2,2,order,rani +awMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Chapman\\",\\"Pia Chapman\\",FEMALE,45,Chapman,Chapman,\\"(empty)\\",Sunday,6,\\"pia@chapman-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564686,\\"sold_product_564686_4640, sold_product_564686_12658\\",\\"sold_product_564686_4640, sold_product_564686_12658\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"36, 8.492\\",\\"75, 16.984\\",\\"4,640, 12,658\\",\\"Winter boots - black, Ballet pumps - nude\\",\\"Winter boots - black, Ballet pumps - nude\\",\\"1, 1\\",\\"ZO0373303733, ZO0131201312\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0373303733, ZO0131201312\\",92,92,2,2,order,pia +dAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Cross\\",\\"Betty Cross\\",FEMALE,44,Cross,Cross,\\"(empty)\\",Sunday,6,\\"betty@cross-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564446,\\"sold_product_564446_12508, sold_product_564446_25164\\",\\"sold_product_564446_12508, sold_product_564446_25164\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Angeldale\\",\\"Tigress Enterprises, Angeldale\\",\\"14.492, 30.547\\",\\"28.984, 65\\",\\"12,508, 25,164\\",\\"Tote bag - black, Trainers - grey\\",\\"Tote bag - black, Trainers - grey\\",\\"1, 1\\",\\"ZO0093400934, ZO0679406794\\",\\"0, 0\\",\\"28.984, 65\\",\\"28.984, 65\\",\\"0, 0\\",\\"ZO0093400934, ZO0679406794\\",94,94,2,2,order,betty +dQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Mcdonald\\",\\"Yasmine Mcdonald\\",FEMALE,43,Mcdonald,Mcdonald,\\"(empty)\\",Sunday,6,\\"yasmine@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564481,\\"sold_product_564481_17689, sold_product_564481_11690\\",\\"sold_product_564481_17689, sold_product_564481_11690\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"25.984, 5.5\\",\\"50, 10.992\\",\\"17,689, 11,690\\",\\"Classic heels - navy/white, Necklace - imitation rhodium\\",\\"Classic heels - navy/white, Necklace - imitation rhodium\\",\\"1, 1\\",\\"ZO0321603216, ZO0078000780\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0321603216, ZO0078000780\\",\\"60.969\\",\\"60.969\\",2,2,order,yasmine +fAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Mary,Mary,\\"Mary Griffin\\",\\"Mary Griffin\\",FEMALE,20,Griffin,Griffin,\\"(empty)\\",Sunday,6,\\"mary@griffin-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563953,\\"sold_product_563953_22678, sold_product_563953_17921\\",\\"sold_product_563953_22678, sold_product_563953_17921\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"31.188, 9.867\\",\\"60, 20.984\\",\\"22,678, 17,921\\",\\"Ankle boots - Midnight Blue, Amber - Wallet - black\\",\\"Ankle boots - Midnight Blue, Amber - Wallet - black\\",\\"1, 1\\",\\"ZO0376203762, ZO0303603036\\",\\"0, 0\\",\\"60, 20.984\\",\\"60, 20.984\\",\\"0, 0\\",\\"ZO0376203762, ZO0303603036\\",81,81,2,2,order,mary +9gMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Gibbs\\",\\"Frances Gibbs\\",FEMALE,49,Gibbs,Gibbs,\\"(empty)\\",Sunday,6,\\"frances@gibbs-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565061,\\"sold_product_565061_1774, sold_product_565061_20952\\",\\"sold_product_565061_1774, sold_product_565061_20952\\",\\"60, 33\\",\\"60, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"27.594, 16.172\\",\\"60, 33\\",\\"1,774, 20,952\\",\\"Lace-ups - cognac, Light jacket - navy\\",\\"Lace-ups - cognac, Light jacket - navy\\",\\"1, 1\\",\\"ZO0681106811, ZO0286402864\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0681106811, ZO0286402864\\",93,93,2,2,order,frances +9wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Jenkins\\",\\"Elyssa Jenkins\\",FEMALE,27,Jenkins,Jenkins,\\"(empty)\\",Sunday,6,\\"elyssa@jenkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565100,\\"sold_product_565100_13722, sold_product_565100_21376\\",\\"sold_product_565100_13722, sold_product_565100_21376\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"15.844, 8.828\\",\\"33, 16.984\\",\\"13,722, 21,376\\",\\"Cardigan - grey multicolor, Jersey dress - mid grey multicolor\\",\\"Cardigan - grey multicolor, Jersey dress - mid grey multicolor\\",\\"1, 1\\",\\"ZO0069000690, ZO0490004900\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0069000690, ZO0490004900\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +3AMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Sharp\\",\\"Oliver Sharp\\",MALE,7,Sharp,Sharp,\\"(empty)\\",Sunday,6,\\"oliver@sharp-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565263,\\"sold_product_565263_15239, sold_product_565263_14475\\",\\"sold_product_565263_15239, sold_product_565263_14475\\",\\"22.984, 25.984\\",\\"22.984, 25.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"11.039, 12.219\\",\\"22.984, 25.984\\",\\"15,239, 14,475\\",\\"Hoodie - light grey/navy, Tracksuit bottoms - black\\",\\"Hoodie - light grey/navy, Tracksuit bottoms - black\\",\\"1, 1\\",\\"ZO0582705827, ZO0111801118\\",\\"0, 0\\",\\"22.984, 25.984\\",\\"22.984, 25.984\\",\\"0, 0\\",\\"ZO0582705827, ZO0111801118\\",\\"48.969\\",\\"48.969\\",2,2,order,oliver +dgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Garner\\",\\"Abdulraheem Al Garner\\",MALE,33,Garner,Garner,\\"(empty)\\",Sunday,6,\\"abdulraheem al@garner-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",563984,\\"sold_product_563984_22409, sold_product_563984_20424\\",\\"sold_product_563984_22409, sold_product_563984_20424\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"5.762, 7.129\\",\\"11.992, 13.992\\",\\"22,409, 20,424\\",\\"Basic T-shirt - Dark Salmon, Basic T-shirt - navy\\",\\"Basic T-shirt - Dark Salmon, Basic T-shirt - navy\\",\\"1, 1\\",\\"ZO0121301213, ZO0294102941\\",\\"0, 0\\",\\"11.992, 13.992\\",\\"11.992, 13.992\\",\\"0, 0\\",\\"ZO0121301213, ZO0294102941\\",\\"25.984\\",\\"25.984\\",2,2,order,abdulraheem +rgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Ramsey\\",\\"Brigitte Ramsey\\",FEMALE,12,Ramsey,Ramsey,\\"(empty)\\",Sunday,6,\\"brigitte@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565262,\\"sold_product_565262_18767, sold_product_565262_11190\\",\\"sold_product_565262_18767, sold_product_565262_11190\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"10.906, 11.5\\",\\"20.984, 24.984\\",\\"18,767, 11,190\\",\\"Amber - Wallet - cognac, Rucksack - black\\",\\"Amber - Wallet - cognac, Rucksack - black\\",\\"1, 1\\",\\"ZO0303503035, ZO0197601976\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0303503035, ZO0197601976\\",\\"45.969\\",\\"45.969\\",2,2,order,brigitte +rwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Smith\\",\\"Sonya Smith\\",FEMALE,28,Smith,Smith,\\"(empty)\\",Sunday,6,\\"sonya@smith-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565304,\\"sold_product_565304_22359, sold_product_565304_19969\\",\\"sold_product_565304_22359, sold_product_565304_19969\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"12.492, 17.391\\",\\"24.984, 37\\",\\"22,359, 19,969\\",\\"Boots - dark grey, Maxi dress - black/rose gold\\",\\"Boots - dark grey, Maxi dress - black/rose gold\\",\\"1, 1\\",\\"ZO0017800178, ZO0229602296\\",\\"0, 0\\",\\"24.984, 37\\",\\"24.984, 37\\",\\"0, 0\\",\\"ZO0017800178, ZO0229602296\\",\\"61.969\\",\\"61.969\\",2,2,order,sonya +vgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Ryan\\",\\"Recip Ryan\\",MALE,10,Ryan,Ryan,\\"(empty)\\",Sunday,6,\\"recip@ryan-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565123,\\"sold_product_565123_14743, sold_product_565123_22906\\",\\"sold_product_565123_14743, sold_product_565123_22906\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"17.156, 35.25\\",\\"33, 75\\",\\"14,743, 22,906\\",\\"Laptop bag - black, Lace-up boots - black\\",\\"Laptop bag - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0316903169, ZO0400504005\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0316903169, ZO0400504005\\",108,108,2,2,order,recip +vwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Hansen\\",\\"Robbie Hansen\\",MALE,48,Hansen,Hansen,\\"(empty)\\",Sunday,6,\\"robbie@hansen-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565160,\\"sold_product_565160_19961, sold_product_565160_19172\\",\\"sold_product_565160_19961, sold_product_565160_19172\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"36, 10.078\\",\\"75, 20.984\\",\\"19,961, 19,172\\",\\"Lace-up boots - Burly Wood , Trainers - black/white\\",\\"Lace-up boots - Burly Wood , Trainers - black/white\\",\\"1, 1\\",\\"ZO0693306933, ZO0514605146\\",\\"0, 0\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"0, 0\\",\\"ZO0693306933, ZO0514605146\\",96,96,2,2,order,robbie +wgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Bryant\\",\\"Irwin Bryant\\",MALE,14,Bryant,Bryant,\\"(empty)\\",Sunday,6,\\"irwin@bryant-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",565224,\\"sold_product_565224_2269, sold_product_565224_23958\\",\\"sold_product_565224_2269, sold_product_565224_23958\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"23, 13.242\\",\\"50, 24.984\\",\\"2,269, 23,958\\",\\"Boots - Slate Gray, Jumper - black\\",\\"Boots - Slate Gray, Jumper - black\\",\\"1, 1\\",\\"ZO0406604066, ZO0576805768\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0406604066, ZO0576805768\\",75,75,2,2,order,irwin +2wMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Rivera\\",\\"Mostafa Rivera\\",MALE,9,Rivera,Rivera,\\"(empty)\\",Sunday,6,\\"mostafa@rivera-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564121,\\"sold_product_564121_24202, sold_product_564121_21006\\",\\"sold_product_564121_24202, sold_product_564121_21006\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"3.92, 5.5\\",\\"7.988, 10.992\\",\\"24,202, 21,006\\",\\"Basic T-shirt - white, Sports shirt - bright white\\",\\"Basic T-shirt - white, Sports shirt - bright white\\",\\"1, 1\\",\\"ZO0291902919, ZO0617206172\\",\\"0, 0\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"0, 0\\",\\"ZO0291902919, ZO0617206172\\",\\"18.984\\",\\"18.984\\",2,2,order,mostafa +3AMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Yahya,Yahya,\\"Yahya Tyler\\",\\"Yahya Tyler\\",MALE,23,Tyler,Tyler,\\"(empty)\\",Sunday,6,\\"yahya@tyler-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564166,\\"sold_product_564166_14500, sold_product_564166_17015\\",\\"sold_product_564166_14500, sold_product_564166_17015\\",\\"28.984, 85\\",\\"28.984, 85\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"15.07, 41.656\\",\\"28.984, 85\\",\\"14,500, 17,015\\",\\"Laptop bag - black, Briefcase - brown\\",\\"Laptop bag - black, Briefcase - brown\\",\\"1, 1\\",\\"ZO0607106071, ZO0470704707\\",\\"0, 0\\",\\"28.984, 85\\",\\"28.984, 85\\",\\"0, 0\\",\\"ZO0607106071, ZO0470704707\\",114,114,2,2,order,yahya +3wMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Rivera\\",\\"Wilhemina St. Rivera\\",FEMALE,17,Rivera,Rivera,\\"(empty)\\",Sunday,6,\\"wilhemina st.@rivera-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Gnomehouse, Oceanavigations\\",\\"Gnomehouse, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564739,\\"sold_product_564739_21607, sold_product_564739_14854\\",\\"sold_product_564739_21607, sold_product_564739_14854\\",\\"55, 50\\",\\"55, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Oceanavigations\\",\\"Gnomehouse, Oceanavigations\\",\\"25.844, 23.5\\",\\"55, 50\\",\\"21,607, 14,854\\",\\"Jersey dress - inca gold, Ballet pumps - argento\\",\\"Jersey dress - inca gold, Ballet pumps - argento\\",\\"1, 1\\",\\"ZO0335603356, ZO0236502365\\",\\"0, 0\\",\\"55, 50\\",\\"55, 50\\",\\"0, 0\\",\\"ZO0335603356, ZO0236502365\\",105,105,2,2,order,wilhemina +OQMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Wood\\",\\"Jason Wood\\",MALE,16,Wood,Wood,\\"(empty)\\",Sunday,6,\\"jason@wood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564016,\\"sold_product_564016_21164, sold_product_564016_3074\\",\\"sold_product_564016_21164, sold_product_564016_3074\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"5.93, 27.594\\",\\"10.992, 60\\",\\"21,164, 3,074\\",\\"Long sleeved top - dark blue, Trenchcoat - navy\\",\\"Long sleeved top - dark blue, Trenchcoat - navy\\",\\"1, 1\\",\\"ZO0436904369, ZO0290402904\\",\\"0, 0\\",\\"10.992, 60\\",\\"10.992, 60\\",\\"0, 0\\",\\"ZO0436904369, ZO0290402904\\",71,71,2,2,order,jason +OgMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Duncan\\",\\"Jim Duncan\\",MALE,41,Duncan,Duncan,\\"(empty)\\",Sunday,6,\\"jim@duncan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564576,\\"sold_product_564576_1384, sold_product_564576_12074\\",\\"sold_product_564576_1384, sold_product_564576_12074\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.188, 5.641\\",\\"60, 11.992\\",\\"1,384, 12,074\\",\\"Lace-ups - black , Polo shirt - blue\\",\\"Lace-ups - black , Polo shirt - blue\\",\\"1, 1\\",\\"ZO0681206812, ZO0441904419\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0681206812, ZO0441904419\\",72,72,2,2,order,jim +OwMtOW0BH63Xcmy453L9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Fletcher\\",\\"Yasmine Fletcher\\",FEMALE,43,Fletcher,Fletcher,\\"(empty)\\",Sunday,6,\\"yasmine@fletcher-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564605,\\"sold_product_564605_17630, sold_product_564605_14381\\",\\"sold_product_564605_17630, sold_product_564605_14381\\",\\"60, 75\\",\\"60, 75\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Angeldale\\",\\"Gnomehouse, Angeldale\\",\\"31.188, 34.5\\",\\"60, 75\\",\\"17,630, 14,381\\",\\"Summer dress - navy blazer, Tote bag - cognac\\",\\"Summer dress - navy blazer, Tote bag - cognac\\",\\"1, 1\\",\\"ZO0333103331, ZO0694806948\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0333103331, ZO0694806948\\",135,135,2,2,order,yasmine +5QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mullins\\",\\"Wilhemina St. Mullins\\",FEMALE,17,Mullins,Mullins,\\"(empty)\\",Sunday,6,\\"wilhemina st.@mullins-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Angeldale, Low Tide Media, Tigress Enterprises\\",\\"Angeldale, Low Tide Media, Tigress Enterprises\\",\\"Jun 22, 2019 @ 00:00:00.000\\",730663,\\"sold_product_730663_12404, sold_product_730663_15087, sold_product_730663_13055, sold_product_730663_5529\\",\\"sold_product_730663_12404, sold_product_730663_15087, sold_product_730663_13055, sold_product_730663_5529\\",\\"33, 42, 60, 33\\",\\"33, 42, 60, 33\\",\\"Women's Accessories, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Women's Accessories, Women's Shoes, Women's Shoes, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Low Tide Media, Low Tide Media, Tigress Enterprises\\",\\"Angeldale, Low Tide Media, Low Tide Media, Tigress Enterprises\\",\\"17.156, 21.406, 27.594, 17.813\\",\\"33, 42, 60, 33\\",\\"12,404, 15,087, 13,055, 5,529\\",\\"Clutch - black, Sandals - cognac, Lace-ups - perla, Lace-up boots - cognac\\",\\"Clutch - black, Sandals - cognac, Lace-ups - perla, Lace-up boots - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\",\\"0, 0, 0, 0\\",\\"33, 42, 60, 33\\",\\"33, 42, 60, 33\\",\\"0, 0, 0, 0\\",\\"ZO0697406974, ZO0370303703, ZO0368103681, ZO0013800138\\",168,168,4,4,order,wilhemina +BAMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Samir,Samir,\\"Samir Chapman\\",\\"Samir Chapman\\",MALE,34,Chapman,Chapman,\\"(empty)\\",Sunday,6,\\"samir@chapman-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564366,\\"sold_product_564366_810, sold_product_564366_11140\\",\\"sold_product_564366_810, sold_product_564366_11140\\",\\"80, 10.992\\",\\"80, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"38.406, 5.5\\",\\"80, 10.992\\",\\"810, 11,140\\",\\"Smart lace-ups - dark brown, Print T-shirt - dark blue\\",\\"Smart lace-ups - dark brown, Print T-shirt - dark blue\\",\\"1, 1\\",\\"ZO0681906819, ZO0549705497\\",\\"0, 0\\",\\"80, 10.992\\",\\"80, 10.992\\",\\"0, 0\\",\\"ZO0681906819, ZO0549705497\\",91,91,2,2,order,samir +BQMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Swanson\\",\\"Betty Swanson\\",FEMALE,44,Swanson,Swanson,\\"(empty)\\",Sunday,6,\\"betty@swanson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564221,\\"sold_product_564221_5979, sold_product_564221_19823\\",\\"sold_product_564221_5979, sold_product_564221_19823\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Champion Arts\\",\\"Oceanavigations, Champion Arts\\",\\"33.75, 12.25\\",\\"75, 24.984\\",\\"5,979, 19,823\\",\\"Ankle boots - Antique White, Slim fit jeans - dark grey\\",\\"Ankle boots - Antique White, Slim fit jeans - dark grey\\",\\"1, 1\\",\\"ZO0249702497, ZO0487404874\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0249702497, ZO0487404874\\",100,100,2,2,order,betty +CgMtOW0BH63Xcmy46HPV,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Rose\\",\\"Selena Rose\\",FEMALE,42,Rose,Rose,\\"(empty)\\",Sunday,6,\\"selena@rose-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 22, 2019 @ 00:00:00.000\\",564174,\\"sold_product_564174_12644, sold_product_564174_20872\\",\\"sold_product_564174_12644, sold_product_564174_20872\\",\\"33, 50\\",\\"33, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 11, 2016 @ 00:00:00.000, Dec 11, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"16.172, 25.484\\",\\"33, 50\\",\\"12,644, 20,872\\",\\"Jumpsuit - black, Ballet pumps - grey\\",\\"Jumpsuit - black, Ballet pumps - grey\\",\\"1, 1\\",\\"ZO0032300323, ZO0236302363\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0032300323, ZO0236302363\\",83,83,2,2,order,selena +DgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Powell\\",\\"Diane Powell\\",FEMALE,22,Powell,Powell,\\"(empty)\\",Saturday,5,\\"diane@powell-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Pyramidustries active\\",\\"Pyramidustries active\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562835,\\"sold_product_562835_23805, sold_product_562835_22240\\",\\"sold_product_562835_23805, sold_product_562835_22240\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Pyramidustries active\\",\\"Pyramidustries active, Pyramidustries active\\",\\"9.453, 7.051\\",\\"20.984, 14.992\\",\\"23,805, 22,240\\",\\"Tights - black , Tights - mid grey multicolor\\",\\"Tights - black , Tights - mid grey multicolor\\",\\"1, 1\\",\\"ZO0222302223, ZO0223502235\\",\\"0, 0\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"0, 0\\",\\"ZO0222302223, ZO0223502235\\",\\"35.969\\",\\"35.969\\",2,2,order,diane +DwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Dixon\\",\\"Tariq Dixon\\",MALE,25,Dixon,Dixon,\\"(empty)\\",Saturday,5,\\"tariq@dixon-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562882,\\"sold_product_562882_16957, sold_product_562882_6401\\",\\"sold_product_562882_16957, sold_product_562882_6401\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"5.711, 10.078\\",\\"10.992, 20.984\\",\\"16,957, 6,401\\",\\"Cap - navy, Shirt - Blue Violety\\",\\"Cap - navy, Shirt - Blue Violety\\",\\"1, 1\\",\\"ZO0460804608, ZO0523905239\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0460804608, ZO0523905239\\",\\"31.984\\",\\"31.984\\",2,2,order,tariq +EAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Daniels\\",\\"Sonya Daniels\\",FEMALE,28,Daniels,Daniels,\\"(empty)\\",Saturday,5,\\"sonya@daniels-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562629,\\"sold_product_562629_21956, sold_product_562629_24341\\",\\"sold_product_562629_21956, sold_product_562629_24341\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"5.82, 6.859\\",\\"10.992, 13.992\\",\\"21,956, 24,341\\",\\"Long sleeved top - royal blue, Scarf - rose\\",\\"Long sleeved top - royal blue, Scarf - rose\\",\\"1, 1\\",\\"ZO0639506395, ZO0083000830\\",\\"0, 0\\",\\"10.992, 13.992\\",\\"10.992, 13.992\\",\\"0, 0\\",\\"ZO0639506395, ZO0083000830\\",\\"24.984\\",\\"24.984\\",2,2,order,sonya +EQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Maldonado\\",\\"Jim Maldonado\\",MALE,41,Maldonado,Maldonado,\\"(empty)\\",Saturday,5,\\"jim@maldonado-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562672,\\"sold_product_562672_14354, sold_product_562672_18181\\",\\"sold_product_562672_14354, sold_product_562672_18181\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"3.68, 5.711\\",\\"7.988, 10.992\\",\\"14,354, 18,181\\",\\"(3) Pack - Socks - white/black , Long sleeved top - bordeaux\\",\\"(3) Pack - Socks - white/black , Long sleeved top - bordeaux\\",\\"1, 1\\",\\"ZO0613406134, ZO0436304363\\",\\"0, 0\\",\\"7.988, 10.992\\",\\"7.988, 10.992\\",\\"0, 0\\",\\"ZO0613406134, ZO0436304363\\",\\"18.984\\",\\"18.984\\",2,2,order,jim +YwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Munoz\\",\\"rania Munoz\\",FEMALE,24,Munoz,Munoz,\\"(empty)\\",Saturday,5,\\"rania@munoz-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563193,\\"sold_product_563193_13167, sold_product_563193_12035\\",\\"sold_product_563193_13167, sold_product_563193_12035\\",\\"7.988, 14.992\\",\\"7.988, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"3.68, 7.051\\",\\"7.988, 14.992\\",\\"13,167, 12,035\\",\\"Vest - dark grey, Jersey dress - black\\",\\"Vest - dark grey, Jersey dress - black\\",\\"1, 1\\",\\"ZO0636906369, ZO0150301503\\",\\"0, 0\\",\\"7.988, 14.992\\",\\"7.988, 14.992\\",\\"0, 0\\",\\"ZO0636906369, ZO0150301503\\",\\"22.984\\",\\"22.984\\",2,2,order,rani +ZAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Swanson\\",\\"Fitzgerald Swanson\\",MALE,11,Swanson,Swanson,\\"(empty)\\",Saturday,5,\\"fitzgerald@swanson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563440,\\"sold_product_563440_17325, sold_product_563440_1907\\",\\"sold_product_563440_17325, sold_product_563440_1907\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"9.867, 33.75\\",\\"20.984, 75\\",\\"17,325, 1,907\\",\\"Sweatshirt - white, Lace-up boots - black\\",\\"Sweatshirt - white, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0589605896, ZO0257202572\\",\\"0, 0\\",\\"20.984, 75\\",\\"20.984, 75\\",\\"0, 0\\",\\"ZO0589605896, ZO0257202572\\",96,96,2,2,order,fuzzy +ZQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Jim,Jim,\\"Jim Cortez\\",\\"Jim Cortez\\",MALE,41,Cortez,Cortez,\\"(empty)\\",Saturday,5,\\"jim@cortez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563485,\\"sold_product_563485_23858, sold_product_563485_16559\\",\\"sold_product_563485_23858, sold_product_563485_16559\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"6.23, 18.5\\",\\"11.992, 37\\",\\"23,858, 16,559\\",\\"Wallet - cognac, Boots - black\\",\\"Wallet - cognac, Boots - black\\",\\"1, 1\\",\\"ZO0602606026, ZO0522005220\\",\\"0, 0\\",\\"11.992, 37\\",\\"11.992, 37\\",\\"0, 0\\",\\"ZO0602606026, ZO0522005220\\",\\"48.969\\",\\"48.969\\",2,2,order,jim +1QMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Underwood\\",\\"Diane Underwood\\",FEMALE,22,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"diane@underwood-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562792,\\"sold_product_562792_14720, sold_product_562792_9051\\",\\"sold_product_562792_14720, sold_product_562792_9051\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"26.984, 17.156\\",\\"50, 33\\",\\"14,720, 9,051\\",\\"High heeled sandals - nude, Jersey dress - navy blazer\\",\\"High heeled sandals - nude, Jersey dress - navy blazer\\",\\"1, 1\\",\\"ZO0242602426, ZO0336103361\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0242602426, ZO0336103361\\",83,83,2,2,order,diane +dwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Boone\\",\\"Stephanie Boone\\",FEMALE,6,Boone,Boone,\\"(empty)\\",Saturday,5,\\"stephanie@boone-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563365,\\"sold_product_563365_24862, sold_product_563365_20441\\",\\"sold_product_563365_24862, sold_product_563365_20441\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"5.5, 14.211\\",\\"10.992, 28.984\\",\\"24,862, 20,441\\",\\"Print T-shirt - dark blue/off white, Blouse - black/white\\",\\"Print T-shirt - dark blue/off white, Blouse - black/white\\",\\"1, 1\\",\\"ZO0646206462, ZO0065200652\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0646206462, ZO0065200652\\",\\"39.969\\",\\"39.969\\",2,2,order,stephanie +iwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Wood\\",\\"Marwan Wood\\",MALE,51,Wood,Wood,\\"(empty)\\",Saturday,5,\\"marwan@wood-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562688,\\"sold_product_562688_22319, sold_product_562688_11707\\",\\"sold_product_562688_22319, sold_product_562688_11707\\",\\"24.984, 13.992\\",\\"24.984, 13.992\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"13.742, 7.41\\",\\"24.984, 13.992\\",\\"22,319, 11,707\\",\\"Trainers - black, Wash bag - dark grey \\",\\"Trainers - black, Wash bag - dark grey \\",\\"1, 1\\",\\"ZO0394603946, ZO0608406084\\",\\"0, 0\\",\\"24.984, 13.992\\",\\"24.984, 13.992\\",\\"0, 0\\",\\"ZO0394603946, ZO0608406084\\",\\"38.969\\",\\"38.969\\",2,2,order,marwan +jAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Barnes\\",\\"Marwan Barnes\\",MALE,51,Barnes,Barnes,\\"(empty)\\",Saturday,5,\\"marwan@barnes-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563647,\\"sold_product_563647_20757, sold_product_563647_11341\\",\\"sold_product_563647_20757, sold_product_563647_11341\\",\\"80, 42\\",\\"80, 42\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.781, 22.25\\",\\"80, 42\\",\\"20,757, 11,341\\",\\"Lace-up boots - dark brown, Weekend bag - classic navy\\",\\"Lace-up boots - dark brown, Weekend bag - classic navy\\",\\"1, 1\\",\\"ZO0690906909, ZO0319003190\\",\\"0, 0\\",\\"80, 42\\",\\"80, 42\\",\\"0, 0\\",\\"ZO0690906909, ZO0319003190\\",122,122,2,2,order,marwan +jQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Reese\\",\\"Kamal Reese\\",MALE,39,Reese,Reese,\\"(empty)\\",Saturday,5,\\"kamal@reese-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563711,\\"sold_product_563711_22407, sold_product_563711_11553\\",\\"sold_product_563711_22407, sold_product_563711_11553\\",\\"60, 140\\",\\"60, 140\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"33, 72.813\\",\\"60, 140\\",\\"22,407, 11,553\\",\\"Lace-ups - grey, Leather jacket - camel\\",\\"Lace-ups - grey, Leather jacket - camel\\",\\"1, 1\\",\\"ZO0254202542, ZO0288202882\\",\\"0, 0\\",\\"60, 140\\",\\"60, 140\\",\\"0, 0\\",\\"ZO0254202542, ZO0288202882\\",200,200,2,2,order,kamal +2AMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Willis\\",\\"Phil Willis\\",MALE,50,Willis,Willis,\\"(empty)\\",Saturday,5,\\"phil@willis-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563763,\\"sold_product_563763_16794, sold_product_563763_13661\\",\\"sold_product_563763_16794, sold_product_563763_13661\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.703, 10.492\\",\\"20.984, 20.984\\",\\"16,794, 13,661\\",\\"Swimming shorts - white, Tracksuit bottoms - light grey\\",\\"Swimming shorts - white, Tracksuit bottoms - light grey\\",\\"1, 1\\",\\"ZO0479404794, ZO0525305253\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0479404794, ZO0525305253\\",\\"41.969\\",\\"41.969\\",2,2,order,phil +BQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Mary,Mary,\\"Mary Brock\\",\\"Mary Brock\\",FEMALE,20,Brock,Brock,\\"(empty)\\",Saturday,5,\\"mary@brock-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563825,\\"sold_product_563825_25104, sold_product_563825_5962\\",\\"sold_product_563825_25104, sold_product_563825_5962\\",\\"65, 65\\",\\"65, 65\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"35.094, 33.125\\",\\"65, 65\\",\\"25,104, 5,962\\",\\"Classic heels - rose/true nude, High heels - black\\",\\"Classic heels - rose/true nude, High heels - black\\",\\"1, 1\\",\\"ZO0238202382, ZO0237102371\\",\\"0, 0\\",\\"65, 65\\",\\"65, 65\\",\\"0, 0\\",\\"ZO0238202382, ZO0237102371\\",130,130,2,2,order,mary +HAMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Irwin,Irwin,\\"Irwin Cook\\",\\"Irwin Cook\\",MALE,14,Cook,Cook,\\"(empty)\\",Saturday,5,\\"irwin@cook-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562797,\\"sold_product_562797_20442, sold_product_562797_20442\\",\\"sold_product_562797_20442, sold_product_562797_20442\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.398, 5.398\\",\\"11.992, 11.992\\",\\"20,442, 20,442\\",\\"Polo shirt - dark grey multicolor, Polo shirt - dark grey multicolor\\",\\"Polo shirt - dark grey multicolor, Polo shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0442504425, ZO0442504425\\",\\"0, 0\\",\\"11.992, 11.992\\",\\"11.992, 11.992\\",\\"0, 0\\",ZO0442504425,\\"23.984\\",\\"23.984\\",2,2,order,irwin +SgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Goodwin\\",\\"Abigail Goodwin\\",FEMALE,46,Goodwin,Goodwin,\\"(empty)\\",Saturday,5,\\"abigail@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563846,\\"sold_product_563846_23161, sold_product_563846_13874\\",\\"sold_product_563846_23161, sold_product_563846_13874\\",\\"100, 16.984\\",\\"100, 16.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"53, 9\\",\\"100, 16.984\\",\\"23,161, 13,874\\",\\"Boots - brandy, Long sleeved top - khaki\\",\\"Boots - brandy, Long sleeved top - khaki\\",\\"1, 1\\",\\"ZO0244102441, ZO0169301693\\",\\"0, 0\\",\\"100, 16.984\\",\\"100, 16.984\\",\\"0, 0\\",\\"ZO0244102441, ZO0169301693\\",117,117,2,2,order,abigail +SwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Burton\\",\\"Youssef Burton\\",MALE,31,Burton,Burton,\\"(empty)\\",Saturday,5,\\"youssef@burton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563887,\\"sold_product_563887_11751, sold_product_563887_18663\\",\\"sold_product_563887_11751, sold_product_563887_18663\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"14.781, 8.156\\",\\"28.984, 16.984\\",\\"11,751, 18,663\\",\\"Shorts - beige, Print T-shirt - dark blue multicolor\\",\\"Shorts - beige, Print T-shirt - dark blue multicolor\\",\\"1, 1\\",\\"ZO0423104231, ZO0438204382\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0423104231, ZO0438204382\\",\\"45.969\\",\\"45.969\\",2,2,order,youssef +UgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Willis\\",\\"Rabbia Al Willis\\",FEMALE,5,Willis,Willis,\\"(empty)\\",Saturday,5,\\"rabbia al@willis-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563607,\\"sold_product_563607_23412, sold_product_563607_14303\\",\\"sold_product_563607_23412, sold_product_563607_14303\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"17.813, 36\\",\\"33, 75\\",\\"23,412, 14,303\\",\\"Jeans Skinny Fit - black, Ankle boots - black\\",\\"Jeans Skinny Fit - black, Ankle boots - black\\",\\"1, 1\\",\\"ZO0271002710, ZO0678806788\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0271002710, ZO0678806788\\",108,108,2,2,order,rabbia +jgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Bryan\\",\\"Betty Bryan\\",FEMALE,44,Bryan,Bryan,\\"(empty)\\",Saturday,5,\\"betty@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562762,\\"sold_product_562762_23139, sold_product_562762_13840\\",\\"sold_product_562762_23139, sold_product_562762_13840\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"6.23, 29.906\\",\\"11.992, 65\\",\\"23,139, 13,840\\",\\"Print T-shirt - black/berry, Boots - Royal Blue\\",\\"Print T-shirt - black/berry, Boots - Royal Blue\\",\\"1, 1\\",\\"ZO0162401624, ZO0375203752\\",\\"0, 0\\",\\"11.992, 65\\",\\"11.992, 65\\",\\"0, 0\\",\\"ZO0162401624, ZO0375203752\\",77,77,2,2,order,betty +9AMtOW0BH63Xcmy44mSR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Sutton\\",\\"Elyssa Sutton\\",FEMALE,27,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"elyssa@sutton-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Primemaster, Spherecords\\",\\"Tigress Enterprises, Primemaster, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",723905,\\"sold_product_723905_24589, sold_product_723905_11977, sold_product_723905_13368, sold_product_723905_14021\\",\\"sold_product_723905_24589, sold_product_723905_11977, sold_product_723905_13368, sold_product_723905_14021\\",\\"24.984, 100, 21.984, 20.984\\",\\"24.984, 100, 21.984, 20.984\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Women's Shoes, Women's Shoes, Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Primemaster, Spherecords, Spherecords\\",\\"Tigress Enterprises, Primemaster, Spherecords, Spherecords\\",\\"13.492, 54, 11.867, 10.906\\",\\"24.984, 100, 21.984, 20.984\\",\\"24,589, 11,977, 13,368, 14,021\\",\\"Boots - black, Ankle boots - Midnight Blue, Chinos - light blue, Shirt - black\\",\\"Boots - black, Ankle boots - Midnight Blue, Chinos - light blue, Shirt - black\\",\\"1, 1, 1, 1\\",\\"ZO0030300303, ZO0360003600, ZO0632906329, ZO0650906509\\",\\"0, 0, 0, 0\\",\\"24.984, 100, 21.984, 20.984\\",\\"24.984, 100, 21.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0030300303, ZO0360003600, ZO0632906329, ZO0650906509\\",168,168,4,4,order,elyssa +FQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Boone\\",\\"Elyssa Boone\\",FEMALE,27,Boone,Boone,\\"(empty)\\",Saturday,5,\\"elyssa@boone-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563195,\\"sold_product_563195_14393, sold_product_563195_22789\\",\\"sold_product_563195_14393, sold_product_563195_22789\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"Tigress Enterprises MAMA, Champion Arts\\",\\"9.453, 13.633\\",\\"20.984, 28.984\\",\\"14,393, 22,789\\",\\"Print T-shirt - grey metallic, Tracksuit top - blue\\",\\"Print T-shirt - grey metallic, Tracksuit top - blue\\",\\"1, 1\\",\\"ZO0231802318, ZO0501805018\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0231802318, ZO0501805018\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +FgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Bowers\\",\\"Selena Bowers\\",FEMALE,42,Bowers,Bowers,\\"(empty)\\",Saturday,5,\\"selena@bowers-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563436,\\"sold_product_563436_24555, sold_product_563436_11768\\",\\"sold_product_563436_24555, sold_product_563436_11768\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"10.492, 4.07\\",\\"20.984, 7.988\\",\\"24,555, 11,768\\",\\"Blouse - dark red, Bracelet - black\\",\\"Blouse - dark red, Bracelet - black\\",\\"1, 1\\",\\"ZO0651606516, ZO0078100781\\",\\"0, 0\\",\\"20.984, 7.988\\",\\"20.984, 7.988\\",\\"0, 0\\",\\"ZO0651606516, ZO0078100781\\",\\"28.984\\",\\"28.984\\",2,2,order,selena +FwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Robert,Robert,\\"Robert Phelps\\",\\"Robert Phelps\\",MALE,29,Phelps,Phelps,\\"(empty)\\",Saturday,5,\\"robert@phelps-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Microlutions, (empty)\\",\\"Microlutions, (empty)\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563489,\\"sold_product_563489_21239, sold_product_563489_13428\\",\\"sold_product_563489_21239, sold_product_563489_13428\\",\\"11.992, 165\\",\\"11.992, 165\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, (empty)\\",\\"Microlutions, (empty)\\",\\"6.469, 90.75\\",\\"11.992, 165\\",\\"21,239, 13,428\\",\\"Hat - multicolor/black, Demi-Boots\\",\\"Hat - multicolor/black, Demi-Boots\\",\\"1, 1\\",\\"ZO0126101261, ZO0483704837\\",\\"0, 0\\",\\"11.992, 165\\",\\"11.992, 165\\",\\"0, 0\\",\\"ZO0126101261, ZO0483704837\\",177,177,2,2,order,robert +dgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Graham\\",\\"Elyssa Graham\\",FEMALE,27,Graham,Graham,\\"(empty)\\",Saturday,5,\\"elyssa@graham-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",727576,\\"sold_product_727576_18143, sold_product_727576_19012, sold_product_727576_16454, sold_product_727576_11955\\",\\"sold_product_727576_18143, sold_product_727576_19012, sold_product_727576_16454, sold_product_727576_11955\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"Pyramidustries, Oceanavigations, Tigress Enterprises MAMA, Tigress Enterprises\\",\\"11.117, 9.453, 10.063, 10.438\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"18,143, 19,012, 16,454, 11,955\\",\\"Jumper - bordeaux, Vest - black/rose, Vest - black, Print T-shirt - red\\",\\"Jumper - bordeaux, Vest - black/rose, Vest - black, Print T-shirt - red\\",\\"1, 1, 1, 1\\",\\"ZO0181201812, ZO0266902669, ZO0231702317, ZO0055800558\\",\\"0, 0, 0, 0\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"20.984, 20.984, 18.984, 18.984\\",\\"0, 0, 0, 0\\",\\"ZO0181201812, ZO0266902669, ZO0231702317, ZO0055800558\\",\\"79.938\\",\\"79.938\\",4,4,order,elyssa +swMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Stewart\\",\\"Marwan Stewart\\",MALE,51,Stewart,Stewart,\\"(empty)\\",Saturday,5,\\"marwan@stewart-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563167,\\"sold_product_563167_24934, sold_product_563167_11541\\",\\"sold_product_563167_24934, sold_product_563167_11541\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"22.5, 8.547\\",\\"50, 18.984\\",\\"24,934, 11,541\\",\\"Lace-up boots - resin coffee, Polo shirt - black\\",\\"Lace-up boots - resin coffee, Polo shirt - black\\",\\"1, 1\\",\\"ZO0403504035, ZO0295602956\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0295602956\\",69,69,2,2,order,marwan +tAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Gibbs\\",\\"Selena Gibbs\\",FEMALE,42,Gibbs,Gibbs,\\"(empty)\\",Saturday,5,\\"selena@gibbs-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563212,\\"sold_product_563212_21217, sold_product_563212_22846\\",\\"sold_product_563212_21217, sold_product_563212_22846\\",\\"33, 50\\",\\"33, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.844, 25\\",\\"33, 50\\",\\"21,217, 22,846\\",\\"Jumper dress - grey/Medium Slate Blue multicolor, Over-the-knee boots - cognac\\",\\"Jumper dress - grey/Medium Slate Blue multicolor, Over-the-knee boots - cognac\\",\\"1, 1\\",\\"ZO0043700437, ZO0139001390\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0043700437, ZO0139001390\\",83,83,2,2,order,selena +tQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Abbott\\",\\"Muniz Abbott\\",MALE,37,Abbott,Abbott,\\"(empty)\\",Saturday,5,\\"muniz@abbott-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563460,\\"sold_product_563460_2036, sold_product_563460_17157\\",\\"sold_product_563460_2036, sold_product_563460_17157\\",\\"80, 20.984\\",\\"80, 20.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"40, 10.289\\",\\"80, 20.984\\",\\"2,036, 17,157\\",\\"Lace-ups - Midnight Blue, Sweatshirt - off white\\",\\"Lace-ups - Midnight Blue, Sweatshirt - off white\\",\\"1, 1\\",\\"ZO0682506825, ZO0594505945\\",\\"0, 0\\",\\"80, 20.984\\",\\"80, 20.984\\",\\"0, 0\\",\\"ZO0682506825, ZO0594505945\\",101,101,2,2,order,muniz +tgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Reese\\",\\"Robbie Reese\\",MALE,48,Reese,Reese,\\"(empty)\\",Saturday,5,\\"robbie@reese-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563492,\\"sold_product_563492_13753, sold_product_563492_16739\\",\\"sold_product_563492_13753, sold_product_563492_16739\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"13.742, 29.25\\",\\"24.984, 65\\",\\"13,753, 16,739\\",\\"Formal shirt - white/blue, Suit jacket - dark grey\\",\\"Formal shirt - white/blue, Suit jacket - dark grey\\",\\"1, 1\\",\\"ZO0412004120, ZO0274102741\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0412004120, ZO0274102741\\",90,90,2,2,order,robbie +0wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Phil,Phil,\\"Phil Graham\\",\\"Phil Graham\\",MALE,50,Graham,Graham,\\"(empty)\\",Saturday,5,\\"phil@graham-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562729,\\"sold_product_562729_12601, sold_product_562729_22654\\",\\"sold_product_562729_12601, sold_product_562729_22654\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"10.906, 12.25\\",\\"20.984, 24.984\\",\\"12,601, 22,654\\",\\"Sweatshirt - bordeaux multicolor, Relaxed fit jeans - vintage blue\\",\\"Sweatshirt - bordeaux multicolor, Relaxed fit jeans - vintage blue\\",\\"1, 1\\",\\"ZO0456404564, ZO0535605356\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0456404564, ZO0535605356\\",\\"45.969\\",\\"45.969\\",2,2,order,phil +4AMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Caldwell\\",\\"Sonya Caldwell\\",FEMALE,28,Caldwell,Caldwell,\\"(empty)\\",Saturday,5,\\"sonya@caldwell-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562978,\\"sold_product_562978_12226, sold_product_562978_11632\\",\\"sold_product_562978_12226, sold_product_562978_11632\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"21.828, 9.867\\",\\"42, 20.984\\",\\"12,226, 11,632\\",\\"Sandals - beige, Summer dress - coral/pink\\",\\"Sandals - beige, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0371003710, ZO0150601506\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0371003710, ZO0150601506\\",\\"62.969\\",\\"62.969\\",2,2,order,sonya +4gMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Mcdonald\\",\\"Wagdi Mcdonald\\",MALE,15,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"wagdi@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563324,\\"sold_product_563324_24573, sold_product_563324_20665\\",\\"sold_product_563324_24573, sold_product_563324_20665\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"9.344, 4.949\\",\\"16.984, 10.992\\",\\"24,573, 20,665\\",\\"Basic T-shirt - dark blue multicolor, 3 PACK - Socks - black/white/grey\\",\\"Basic T-shirt - dark blue multicolor, 3 PACK - Socks - black/white/grey\\",\\"1, 1\\",\\"ZO0440004400, ZO0130401304\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0440004400, ZO0130401304\\",\\"27.984\\",\\"27.984\\",2,2,order,wagdi +4wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Byrd\\",\\"Elyssa Byrd\\",FEMALE,27,Byrd,Byrd,\\"(empty)\\",Saturday,5,\\"elyssa@byrd-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563249,\\"sold_product_563249_14397, sold_product_563249_5141\\",\\"sold_product_563249_14397, sold_product_563249_5141\\",\\"21.984, 60\\",\\"21.984, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Low Tide Media\\",\\"Pyramidustries, Low Tide Media\\",\\"10.344, 33\\",\\"21.984, 60\\",\\"14,397, 5,141\\",\\"Sweatshirt - light grey multicolor, Ankle boots - black\\",\\"Sweatshirt - light grey multicolor, Ankle boots - black\\",\\"1, 1\\",\\"ZO0181001810, ZO0378903789\\",\\"0, 0\\",\\"21.984, 60\\",\\"21.984, 60\\",\\"0, 0\\",\\"ZO0181001810, ZO0378903789\\",82,82,2,2,order,elyssa +5AMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Chandler\\",\\"Brigitte Chandler\\",FEMALE,12,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"brigitte@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563286,\\"sold_product_563286_11887, sold_product_563286_22261\\",\\"sold_product_563286_11887, sold_product_563286_22261\\",\\"50, 50\\",\\"50, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"24.5, 22.5\\",\\"50, 50\\",\\"11,887, 22,261\\",\\"Maxi dress - black, Winter jacket - bordeaux\\",\\"Maxi dress - black, Winter jacket - bordeaux\\",\\"1, 1\\",\\"ZO0040000400, ZO0503805038\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0040000400, ZO0503805038\\",100,100,2,2,order,brigitte +dgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Shaw\\",\\"Abd Shaw\\",MALE,52,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"abd@shaw-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563187,\\"sold_product_563187_12040, sold_product_563187_21172\\",\\"sold_product_563187_12040, sold_product_563187_21172\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"12.492, 12.992\\",\\"24.984, 24.984\\",\\"12,040, 21,172\\",\\"Shirt - navy, Jeans Skinny Fit - blue\\",\\"Shirt - navy, Jeans Skinny Fit - blue\\",\\"1, 1\\",\\"ZO0278702787, ZO0425404254\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0278702787, ZO0425404254\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +dwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Gregory\\",\\"Elyssa Gregory\\",FEMALE,27,Gregory,Gregory,\\"(empty)\\",Saturday,5,\\"elyssa@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563503,\\"sold_product_563503_23310, sold_product_563503_16900\\",\\"sold_product_563503_23310, sold_product_563503_16900\\",\\"19.984, 24.984\\",\\"19.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"9.797, 13.742\\",\\"19.984, 24.984\\",\\"23,310, 16,900\\",\\"Blouse - dark green, Jersey dress - black/white\\",\\"Blouse - dark green, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0649306493, ZO0490704907\\",\\"0, 0\\",\\"19.984, 24.984\\",\\"19.984, 24.984\\",\\"0, 0\\",\\"ZO0649306493, ZO0490704907\\",\\"44.969\\",\\"44.969\\",2,2,order,elyssa +ewMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Moran\\",\\"Robert Moran\\",MALE,29,Moran,Moran,\\"(empty)\\",Saturday,5,\\"robert@moran-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563275,\\"sold_product_563275_21731, sold_product_563275_19441\\",\\"sold_product_563275_21731, sold_product_563275_19441\\",\\"37, 24.984\\",\\"37, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"17.016, 11.5\\",\\"37, 24.984\\",\\"21,731, 19,441\\",\\"Bomber Jacket - black, Jumper - green multicolor\\",\\"Bomber Jacket - black, Jumper - green multicolor\\",\\"1, 1\\",\\"ZO0287402874, ZO0453404534\\",\\"0, 0\\",\\"37, 24.984\\",\\"37, 24.984\\",\\"0, 0\\",\\"ZO0287402874, ZO0453404534\\",\\"61.969\\",\\"61.969\\",2,2,order,robert +kgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,rania,rania,\\"rania Mccarthy\\",\\"rania Mccarthy\\",FEMALE,24,Mccarthy,Mccarthy,\\"(empty)\\",Saturday,5,\\"rania@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563737,\\"sold_product_563737_12413, sold_product_563737_19717\\",\\"sold_product_563737_12413, sold_product_563737_19717\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"12.25, 22.25\\",\\"24.984, 42\\",\\"12,413, 19,717\\",\\"Clutch - black, Ballet pumps - blue/white\\",\\"Clutch - black, Ballet pumps - blue/white\\",\\"1, 1\\",\\"ZO0306903069, ZO0320703207\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0306903069, ZO0320703207\\",67,67,2,2,order,rani +kwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Foster\\",\\"Boris Foster\\",MALE,36,Foster,Foster,\\"(empty)\\",Saturday,5,\\"boris@foster-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563796,\\"sold_product_563796_15607, sold_product_563796_14438\\",\\"sold_product_563796_15607, sold_product_563796_14438\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Oceanavigations\\",\\"Spritechnologies, Oceanavigations\\",\\"21.406, 13.344\\",\\"42, 28.984\\",\\"15,607, 14,438\\",\\"Soft shell jacket - dark grey, Jumper - dark grey multicolor\\",\\"Soft shell jacket - dark grey, Jumper - dark grey multicolor\\",\\"1, 1\\",\\"ZO0625806258, ZO0297602976\\",\\"0, 0\\",\\"42, 28.984\\",\\"42, 28.984\\",\\"0, 0\\",\\"ZO0625806258, ZO0297602976\\",71,71,2,2,order,boris +vgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Mcdonald\\",\\"Robert Mcdonald\\",MALE,29,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"robert@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562853,\\"sold_product_562853_21053, sold_product_562853_23834\\",\\"sold_product_562853_21053, sold_product_562853_23834\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.391, 4.07\\",\\"10.992, 7.988\\",\\"21,053, 23,834\\",\\"Print T-shirt - white/blue, 3 PACK - Socks - blue/grey\\",\\"Print T-shirt - white/blue, 3 PACK - Socks - blue/grey\\",\\"1, 1\\",\\"ZO0564705647, ZO0481004810\\",\\"0, 0\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"0, 0\\",\\"ZO0564705647, ZO0481004810\\",\\"18.984\\",\\"18.984\\",2,2,order,robert +vwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Love\\",\\"Elyssa Love\\",FEMALE,27,Love,Love,\\"(empty)\\",Saturday,5,\\"elyssa@love-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562900,\\"sold_product_562900_15312, sold_product_562900_12544\\",\\"sold_product_562900_15312, sold_product_562900_12544\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"14.211, 12.992\\",\\"28.984, 24.984\\",\\"15,312, 12,544\\",\\"Print T-shirt - coronet blue, Faux leather jacket - black\\",\\"Print T-shirt - coronet blue, Faux leather jacket - black\\",\\"1, 1\\",\\"ZO0349203492, ZO0173801738\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0349203492, ZO0173801738\\",\\"53.969\\",\\"53.969\\",2,2,order,elyssa +wAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Thompson\\",\\"Betty Thompson\\",FEMALE,44,Thompson,Thompson,\\"(empty)\\",Saturday,5,\\"betty@thompson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562668,\\"sold_product_562668_22190, sold_product_562668_24239\\",\\"sold_product_562668_22190, sold_product_562668_24239\\",\\"33, 25.984\\",\\"33, 25.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"15.844, 12.219\\",\\"33, 25.984\\",\\"22,190, 24,239\\",\\"Vest - black, Long sleeved top - winter white/peacoat\\",\\"Vest - black, Long sleeved top - winter white/peacoat\\",\\"1, 1\\",\\"ZO0348503485, ZO0059100591\\",\\"0, 0\\",\\"33, 25.984\\",\\"33, 25.984\\",\\"0, 0\\",\\"ZO0348503485, ZO0059100591\\",\\"58.969\\",\\"58.969\\",2,2,order,betty +zgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Perkins\\",\\"Muniz Perkins\\",MALE,37,Perkins,Perkins,\\"(empty)\\",Saturday,5,\\"muniz@perkins-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562794,\\"sold_product_562794_12403, sold_product_562794_24539\\",\\"sold_product_562794_12403, sold_product_562794_24539\\",\\"75, 15.992\\",\\"75, 15.992\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"35.25, 8.148\\",\\"75, 15.992\\",\\"12,403, 24,539\\",\\"Rucksack - brandy, Long sleeved top - off-white\\",\\"Rucksack - brandy, Long sleeved top - off-white\\",\\"1, 1\\",\\"ZO0701707017, ZO0440404404\\",\\"0, 0\\",\\"75, 15.992\\",\\"75, 15.992\\",\\"0, 0\\",\\"ZO0701707017, ZO0440404404\\",91,91,2,2,order,muniz +\\"-QMtOW0BH63Xcmy442fU\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Caldwell\\",\\"Marwan Caldwell\\",MALE,51,Caldwell,Caldwell,\\"(empty)\\",Saturday,5,\\"marwan@caldwell-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",562720,\\"sold_product_562720_17428, sold_product_562720_13612\\",\\"sold_product_562720_17428, sold_product_562720_13612\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.078, 6.469\\",\\"20.984, 11.992\\",\\"17,428, 13,612\\",\\"Sweatshirt - bordeaux, Basic T-shirt - light red/white\\",\\"Sweatshirt - bordeaux, Basic T-shirt - light red/white\\",\\"1, 1\\",\\"ZO0585605856, ZO0549505495\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0585605856, ZO0549505495\\",\\"32.969\\",\\"32.969\\",2,2,order,marwan +\\"-gMtOW0BH63Xcmy442fU\\",ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Reyes\\",\\"Robert Reyes\\",MALE,29,Reyes,Reyes,\\"(empty)\\",Saturday,5,\\"robert@reyes-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562759,\\"sold_product_562759_15827, sold_product_562759_22599\\",\\"sold_product_562759_15827, sold_product_562759_22599\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"9.867, 11.5\\",\\"20.984, 24.984\\",\\"15,827, 22,599\\",\\"Belt - black/brown, Sweatshirt - black\\",\\"Belt - black/brown, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0310403104, ZO0595005950\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0310403104, ZO0595005950\\",\\"45.969\\",\\"45.969\\",2,2,order,robert +KQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Boris,Boris,\\"Boris Little\\",\\"Boris Little\\",MALE,36,Little,Little,\\"(empty)\\",Saturday,5,\\"boris@little-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563442,\\"sold_product_563442_23887, sold_product_563442_17436\\",\\"sold_product_563442_23887, sold_product_563442_17436\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"27, 5.391\\",\\"60, 10.992\\",\\"23,887, 17,436\\",\\"Casual lace-ups - blue, Print T-shirt - white/orange\\",\\"Casual lace-ups - blue, Print T-shirt - white/orange\\",\\"1, 1\\",\\"ZO0394303943, ZO0556305563\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0394303943, ZO0556305563\\",71,71,2,2,order,boris +qwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Valdez\\",\\"Samir Valdez\\",MALE,34,Valdez,Valdez,\\"(empty)\\",Saturday,5,\\"samir@valdez-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563775,\\"sold_product_563775_16063, sold_product_563775_12691\\",\\"sold_product_563775_16063, sold_product_563775_12691\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"6.469, 11.75\\",\\"11.992, 24.984\\",\\"16,063, 12,691\\",\\"Long sleeved top - tan, Windbreaker - Cornflower Blue\\",\\"Long sleeved top - tan, Windbreaker - Cornflower Blue\\",\\"1, 1\\",\\"ZO0562805628, ZO0622806228\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0562805628, ZO0622806228\\",\\"36.969\\",\\"36.969\\",2,2,order,samir +rAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Samir,Samir,\\"Samir Cross\\",\\"Samir Cross\\",MALE,34,Cross,Cross,\\"(empty)\\",Saturday,5,\\"samir@cross-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563813,\\"sold_product_563813_20520, sold_product_563813_19613\\",\\"sold_product_563813_20520, sold_product_563813_19613\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"7.352, 25.484\\",\\"14.992, 50\\",\\"20,520, 19,613\\",\\"Print T-shirt - bright white, Summer jacket - black\\",\\"Print T-shirt - bright white, Summer jacket - black\\",\\"1, 1\\",\\"ZO0120001200, ZO0286602866\\",\\"0, 0\\",\\"14.992, 50\\",\\"14.992, 50\\",\\"0, 0\\",\\"ZO0120001200, ZO0286602866\\",65,65,2,2,order,samir +NgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Marwan,Marwan,\\"Marwan Reyes\\",\\"Marwan Reyes\\",MALE,51,Reyes,Reyes,\\"(empty)\\",Saturday,5,\\"marwan@reyes-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563250,\\"sold_product_563250_18528, sold_product_563250_12730\\",\\"sold_product_563250_18528, sold_product_563250_12730\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.281, 38.25\\",\\"10.992, 75\\",\\"18,528, 12,730\\",\\"Print T-shirt - black, Crossover Strap Bag\\",\\"Print T-shirt - black, Crossover Strap Bag\\",\\"1, 1\\",\\"ZO0557805578, ZO0463904639\\",\\"0, 0\\",\\"10.992, 75\\",\\"10.992, 75\\",\\"0, 0\\",\\"ZO0557805578, ZO0463904639\\",86,86,2,2,order,marwan +NwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Gilbert\\",\\"Pia Gilbert\\",FEMALE,45,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"pia@gilbert-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563282,\\"sold_product_563282_19216, sold_product_563282_16990\\",\\"sold_product_563282_19216, sold_product_563282_16990\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"13.25, 9.656\\",\\"25.984, 20.984\\",\\"19,216, 16,990\\",\\"SET - Pyjamas - black/light pink, Shirt - white/blue\\",\\"SET - Pyjamas - black/light pink, Shirt - white/blue\\",\\"1, 1\\",\\"ZO0100701007, ZO0651106511\\",\\"0, 0\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"0, 0\\",\\"ZO0100701007, ZO0651106511\\",\\"46.969\\",\\"46.969\\",2,2,order,pia +bQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Washington\\",\\"Tariq Washington\\",MALE,25,Washington,Washington,\\"(empty)\\",Saturday,5,\\"tariq@washington-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563392,\\"sold_product_563392_12047, sold_product_563392_17700\\",\\"sold_product_563392_12047, sold_product_563392_17700\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.289, 9\\",\\"20.984, 16.984\\",\\"12,047, 17,700\\",\\"Tracksuit bottoms - dark red, Belt - black\\",\\"Tracksuit bottoms - dark red, Belt - black\\",\\"1, 1\\",\\"ZO0525405254, ZO0310203102\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0525405254, ZO0310203102\\",\\"37.969\\",\\"37.969\\",2,2,order,tariq +kgMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Martin\\",\\"Brigitte Martin\\",FEMALE,12,Martin,Martin,\\"(empty)\\",Saturday,5,\\"brigitte@martin-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563697,\\"sold_product_563697_15646, sold_product_563697_21369\\",\\"sold_product_563697_15646, sold_product_563697_21369\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"9.867, 5.602\\",\\"20.984, 10.992\\",\\"15,646, 21,369\\",\\"Jumper - off-white, Ballet pumps - yellow\\",\\"Jumper - off-white, Ballet pumps - yellow\\",\\"1, 1\\",\\"ZO0264702647, ZO0000700007\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0264702647, ZO0000700007\\",\\"31.984\\",\\"31.984\\",2,2,order,brigitte +lwMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Williams\\",\\"Phil Williams\\",MALE,50,Williams,Williams,\\"(empty)\\",Saturday,5,\\"phil@williams-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563246,\\"sold_product_563246_17897, sold_product_563246_20203\\",\\"sold_product_563246_17897, sold_product_563246_20203\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.703, 14.781\\",\\"20.984, 28.984\\",\\"17,897, 20,203\\",\\"Trainers - grey, Sweatshirt - black\\",\\"Trainers - grey, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0515205152, ZO0300803008\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0515205152, ZO0300803008\\",\\"49.969\\",\\"49.969\\",2,2,order,phil +2gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Garza\\",\\"Wilhemina St. Garza\\",FEMALE,17,Garza,Garza,\\"(empty)\\",Saturday,5,\\"wilhemina st.@garza-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562934,\\"sold_product_562934_5758, sold_product_562934_18453\\",\\"sold_product_562934_5758, sold_product_562934_18453\\",\\"75, 85\\",\\"75, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"33.75, 40.813\\",\\"75, 85\\",\\"5,758, 18,453\\",\\"Ankle boots - cognac, High heeled ankle boots - black\\",\\"Ankle boots - cognac, High heeled ankle boots - black\\",\\"1, 1\\",\\"ZO0674206742, ZO0326303263\\",\\"0, 0\\",\\"75, 85\\",\\"75, 85\\",\\"0, 0\\",\\"ZO0674206742, ZO0326303263\\",160,160,2,2,order,wilhemina +2wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",EUR,Yuri,Yuri,\\"Yuri Burton\\",\\"Yuri Burton\\",MALE,21,Burton,Burton,\\"(empty)\\",Saturday,5,\\"yuri@burton-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562994,\\"sold_product_562994_12714, sold_product_562994_21404\\",\\"sold_product_562994_12714, sold_product_562994_21404\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Men's Clothing, Women's Accessories\\",\\"Men's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"40.813, 6.352\\",\\"85, 11.992\\",\\"12,714, 21,404\\",\\"Classic coat - black, Wallet - brown\\",\\"Classic coat - black, Wallet - brown\\",\\"1, 1\\",\\"ZO0115801158, ZO0701507015\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0115801158, ZO0701507015\\",97,97,2,2,order,yuri +3gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,rania,rania,\\"rania James\\",\\"rania James\\",FEMALE,24,James,James,\\"(empty)\\",Saturday,5,\\"rania@james-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563317,\\"sold_product_563317_12022, sold_product_563317_12978\\",\\"sold_product_563317_12022, sold_product_563317_12978\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"5.762, 5.172\\",\\"11.992, 10.992\\",\\"12,022, 12,978\\",\\"T-Shirt - blue, Scarf - offwhite/black\\",\\"T-Shirt - blue, Scarf - offwhite/black\\",\\"1, 1\\",\\"ZO0631706317, ZO0192701927\\",\\"0, 0\\",\\"11.992, 10.992\\",\\"11.992, 10.992\\",\\"0, 0\\",\\"ZO0631706317, ZO0192701927\\",\\"22.984\\",\\"22.984\\",2,2,order,rani +3wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Webb\\",\\"Eddie Webb\\",MALE,38,Webb,Webb,\\"(empty)\\",Saturday,5,\\"eddie@webb-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563341,\\"sold_product_563341_18784, sold_product_563341_16207\\",\\"sold_product_563341_18784, sold_product_563341_16207\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"29.406, 5.82\\",\\"60, 10.992\\",\\"18,784, 16,207\\",\\"Smart slip-ons - blue, Bow tie - black\\",\\"Smart slip-ons - blue, Bow tie - black\\",\\"1, 1\\",\\"ZO0397303973, ZO0410304103\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0397303973, ZO0410304103\\",71,71,2,2,order,eddie +CgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Turner\\",\\"Gwen Turner\\",FEMALE,26,Turner,Turner,\\"(empty)\\",Saturday,5,\\"gwen@turner-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Gnomehouse, Pyramidustries active\\",\\"Gnomehouse, Pyramidustries active\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563622,\\"sold_product_563622_19912, sold_product_563622_10691\\",\\"sold_product_563622_19912, sold_product_563622_10691\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries active\\",\\"Gnomehouse, Pyramidustries active\\",\\"17.016, 6.719\\",\\"37, 13.992\\",\\"19,912, 10,691\\",\\"A-line skirt - june bug, 3/4 sports trousers - magnet \\",\\"A-line skirt - june bug, 3/4 sports trousers - magnet \\",\\"1, 1\\",\\"ZO0328103281, ZO0224602246\\",\\"0, 0\\",\\"37, 13.992\\",\\"37, 13.992\\",\\"0, 0\\",\\"ZO0328103281, ZO0224602246\\",\\"50.969\\",\\"50.969\\",2,2,order,gwen +CwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Boone\\",\\"Abdulraheem Al Boone\\",MALE,33,Boone,Boone,\\"(empty)\\",Saturday,5,\\"abdulraheem al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563666,\\"sold_product_563666_1967, sold_product_563666_15695\\",\\"sold_product_563666_1967, sold_product_563666_15695\\",\\"65, 33\\",\\"65, 33\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"34.438, 15.18\\",\\"65, 33\\",\\"1,967, 15,695\\",\\"Lace-ups - cognac, Watch - gunmetal\\",\\"Lace-ups - cognac, Watch - gunmetal\\",\\"1, 1\\",\\"ZO0390903909, ZO0126801268\\",\\"0, 0\\",\\"65, 33\\",\\"65, 33\\",\\"0, 0\\",\\"ZO0390903909, ZO0126801268\\",98,98,2,2,order,abdulraheem +DgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Clayton\\",\\"Mostafa Clayton\\",MALE,9,Clayton,Clayton,\\"(empty)\\",Saturday,5,\\"mostafa@clayton-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563026,\\"sold_product_563026_18853, sold_product_563026_17728\\",\\"sold_product_563026_18853, sold_product_563026_17728\\",\\"85, 60\\",\\"85, 60\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"40.813, 32.375\\",\\"85, 60\\",\\"18,853, 17,728\\",\\"Tote bag - black , Suit jacket - navy\\",\\"Tote bag - black , Suit jacket - navy\\",\\"1, 1\\",\\"ZO0703407034, ZO0275102751\\",\\"0, 0\\",\\"85, 60\\",\\"85, 60\\",\\"0, 0\\",\\"ZO0703407034, ZO0275102751\\",145,145,2,2,order,mostafa +DwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Marshall\\",\\"Brigitte Marshall\\",FEMALE,12,Marshall,Marshall,\\"(empty)\\",Saturday,5,\\"brigitte@marshall-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Gnomehouse,Gnomehouse,\\"Jun 21, 2019 @ 00:00:00.000\\",563084,\\"sold_product_563084_23929, sold_product_563084_13484\\",\\"sold_product_563084_23929, sold_product_563084_13484\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Gnomehouse\\",\\"Gnomehouse, Gnomehouse\\",\\"29.906, 19.313\\",\\"65, 42\\",\\"23,929, 13,484\\",\\"Summer dress - black, Summer dress - pastel blue\\",\\"Summer dress - black, Summer dress - pastel blue\\",\\"1, 1\\",\\"ZO0338803388, ZO0334203342\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0338803388, ZO0334203342\\",107,107,2,2,order,brigitte +GwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Rivera\\",\\"Sonya Rivera\\",FEMALE,28,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"sonya@rivera-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562963,\\"sold_product_562963_5747, sold_product_562963_19886\\",\\"sold_product_562963_5747, sold_product_562963_19886\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"13.633, 4.391\\",\\"28.984, 7.988\\",\\"5,747, 19,886\\",\\"High heels - nude, Mini skirt - dark grey multicolor\\",\\"High heels - nude, Mini skirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0004900049, ZO0633806338\\",\\"0, 0\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"0, 0\\",\\"ZO0004900049, ZO0633806338\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +HAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yahya,Yahya,\\"Yahya Jimenez\\",\\"Yahya Jimenez\\",MALE,23,Jimenez,Jimenez,\\"(empty)\\",Saturday,5,\\"yahya@jimenez-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563016,\\"sold_product_563016_19484, sold_product_563016_11795\\",\\"sold_product_563016_19484, sold_product_563016_11795\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"25.484, 10.289\\",\\"50, 20.984\\",\\"19,484, 11,795\\",\\"Summer jacket - khaki, Tracksuit bottoms - dark blue\\",\\"Summer jacket - khaki, Tracksuit bottoms - dark blue\\",\\"1, 1\\",\\"ZO0539605396, ZO0525505255\\",\\"0, 0\\",\\"50, 20.984\\",\\"50, 20.984\\",\\"0, 0\\",\\"ZO0539605396, ZO0525505255\\",71,71,2,2,order,yahya +HgMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Walters\\",\\"Diane Walters\\",FEMALE,22,Walters,Walters,\\"(empty)\\",Saturday,5,\\"diane@walters-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Spherecords\\",\\"Low Tide Media, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562598,\\"sold_product_562598_5045, sold_product_562598_18398\\",\\"sold_product_562598_5045, sold_product_562598_18398\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spherecords\\",\\"Low Tide Media, Spherecords\\",\\"30.594, 5.391\\",\\"60, 10.992\\",\\"5,045, 18,398\\",\\"Boots - black, Vest - black\\",\\"Boots - black, Vest - black\\",\\"1, 1\\",\\"ZO0383203832, ZO0642806428\\",\\"0, 0\\",\\"60, 10.992\\",\\"60, 10.992\\",\\"0, 0\\",\\"ZO0383203832, ZO0642806428\\",71,71,2,2,order,diane +HwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Underwood\\",\\"Brigitte Underwood\\",FEMALE,12,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"brigitte@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563336,\\"sold_product_563336_19599, sold_product_563336_21032\\",\\"sold_product_563336_19599, sold_product_563336_21032\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"25.484, 15.648\\",\\"50, 28.984\\",\\"19,599, 21,032\\",\\"Maxi dress - Pale Violet Red, Lace-ups - black\\",\\"Maxi dress - Pale Violet Red, Lace-ups - black\\",\\"1, 1\\",\\"ZO0332903329, ZO0008300083\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0332903329, ZO0008300083\\",79,79,2,2,order,brigitte +bAMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Roberson\\",\\"Wagdi Roberson\\",MALE,15,Roberson,Roberson,\\"(empty)\\",Saturday,5,\\"wagdi@roberson-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563558,\\"sold_product_563558_21248, sold_product_563558_15382\\",\\"sold_product_563558_21248, sold_product_563558_15382\\",\\"27.984, 37\\",\\"27.984, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"13.992, 19.594\\",\\"27.984, 37\\",\\"21,248, 15,382\\",\\"Windbreaker - navy blazer, Tracksuit top - mottled grey\\",\\"Windbreaker - navy blazer, Tracksuit top - mottled grey\\",\\"1, 1\\",\\"ZO0622706227, ZO0584505845\\",\\"0, 0\\",\\"27.984, 37\\",\\"27.984, 37\\",\\"0, 0\\",\\"ZO0622706227, ZO0584505845\\",65,65,2,2,order,wagdi +cwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Holland\\",\\"Tariq Holland\\",MALE,25,Holland,Holland,\\"(empty)\\",Saturday,5,\\"tariq@holland-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Microlutions\\",\\"Oceanavigations, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563150,\\"sold_product_563150_12819, sold_product_563150_19994\\",\\"sold_product_563150_12819, sold_product_563150_19994\\",\\"24.984, 6.988\\",\\"24.984, 6.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Microlutions\\",\\"Oceanavigations, Microlutions\\",\\"11.25, 3.631\\",\\"24.984, 6.988\\",\\"12,819, 19,994\\",\\"Chinos - dark green, STAY TRUE 2 PACK - Socks - white/grey/black\\",\\"Chinos - dark green, STAY TRUE 2 PACK - Socks - white/grey/black\\",\\"1, 1\\",\\"ZO0281802818, ZO0130201302\\",\\"0, 0\\",\\"24.984, 6.988\\",\\"24.984, 6.988\\",\\"0, 0\\",\\"ZO0281802818, ZO0130201302\\",\\"31.984\\",\\"31.984\\",2,2,order,tariq +eQMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Smith\\",\\"Wilhemina St. Smith\\",FEMALE,17,Smith,Smith,\\"(empty)\\",Saturday,5,\\"wilhemina st.@smith-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises, Oceanavigations, Pyramidustries\\",\\"Tigress Enterprises, Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",728845,\\"sold_product_728845_11691, sold_product_728845_23205, sold_product_728845_14170, sold_product_728845_8257\\",\\"sold_product_728845_11691, sold_product_728845_23205, sold_product_728845_14170, sold_product_728845_8257\\",\\"24.984, 65, 28.984, 13.992\\",\\"24.984, 65, 28.984, 13.992\\",\\"Women's Clothing, Women's Accessories, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Accessories, Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Pyramidustries\\",\\"13.492, 32.5, 13.047, 7.41\\",\\"24.984, 65, 28.984, 13.992\\",\\"11,691, 23,205, 14,170, 8,257\\",\\"Cape - grey multicolor, Handbag - black, Handbag - brown, Print T-shirt - dark grey\\",\\"Cape - grey multicolor, Handbag - black, Handbag - brown, Print T-shirt - dark grey\\",\\"1, 1, 1, 1\\",\\"ZO0082300823, ZO0306203062, ZO0094600946, ZO0158901589\\",\\"0, 0, 0, 0\\",\\"24.984, 65, 28.984, 13.992\\",\\"24.984, 65, 28.984, 13.992\\",\\"0, 0, 0, 0\\",\\"ZO0082300823, ZO0306203062, ZO0094600946, ZO0158901589\\",133,133,4,4,order,wilhemina +lQMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Craig\\",\\"Abd Craig\\",MALE,52,Craig,Craig,\\"(empty)\\",Saturday,5,\\"abd@craig-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562723,\\"sold_product_562723_15183, sold_product_562723_15983\\",\\"sold_product_562723_15183, sold_product_562723_15983\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"16.5, 11.25\\",\\"33, 24.984\\",\\"15,183, 15,983\\",\\"Shirt - blue/off white, Shirt - grey/white\\",\\"Shirt - blue/off white, Shirt - grey/white\\",\\"1, 1\\",\\"ZO0109901099, ZO0277802778\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0109901099, ZO0277802778\\",\\"57.969\\",\\"57.969\\",2,2,order,abd +lgMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Mullins\\",\\"Oliver Mullins\\",MALE,7,Mullins,Mullins,\\"(empty)\\",Saturday,5,\\"oliver@mullins-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562745,\\"sold_product_562745_12209, sold_product_562745_15674\\",\\"sold_product_562745_12209, sold_product_562745_15674\\",\\"22.984, 28.984\\",\\"22.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"11.953, 14.211\\",\\"22.984, 28.984\\",\\"12,209, 15,674\\",\\"Hoodie - black/olive, Sweatshirt - black\\",\\"Hoodie - black/olive, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0541905419, ZO0628306283\\",\\"0, 0\\",\\"22.984, 28.984\\",\\"22.984, 28.984\\",\\"0, 0\\",\\"ZO0541905419, ZO0628306283\\",\\"51.969\\",\\"51.969\\",2,2,order,oliver +lwMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Perry\\",\\"Robbie Perry\\",MALE,48,Perry,Perry,\\"(empty)\\",Saturday,5,\\"robbie@perry-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562763,\\"sold_product_562763_3029, sold_product_562763_23796\\",\\"sold_product_562763_3029, sold_product_562763_23796\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 10.063\\",\\"50, 18.984\\",\\"3,029, 23,796\\",\\"Light jacket - dark blue, Long sleeved top - mid grey multicolor\\",\\"Light jacket - dark blue, Long sleeved top - mid grey multicolor\\",\\"1, 1\\",\\"ZO0428604286, ZO0119601196\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0428604286, ZO0119601196\\",69,69,2,2,order,robbie +yAMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Mostafa,Mostafa,\\"Mostafa Graham\\",\\"Mostafa Graham\\",MALE,9,Graham,Graham,\\"(empty)\\",Saturday,5,\\"mostafa@graham-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563604,\\"sold_product_563604_11391, sold_product_563604_13058\\",\\"sold_product_563604_11391, sold_product_563604_13058\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9, 28.203\\",\\"16.984, 60\\",\\"11,391, 13,058\\",\\"Sweatshirt - mottled grey, Lace-ups - Midnight Blue\\",\\"Sweatshirt - mottled grey, Lace-ups - Midnight Blue\\",\\"1, 1\\",\\"ZO0588005880, ZO0388703887\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0588005880, ZO0388703887\\",77,77,2,2,order,mostafa +7AMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Women's Accessories\\",\\"Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Mckenzie\\",\\"Elyssa Mckenzie\\",FEMALE,27,Mckenzie,Mckenzie,\\"(empty)\\",Saturday,5,\\"elyssa@mckenzie-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563867,\\"sold_product_563867_15363, sold_product_563867_23604\\",\\"sold_product_563867_15363, sold_product_563867_23604\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"Women's Accessories, Women's Accessories\\",\\"Women's Accessories, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.289, 6.719\\",\\"20.984, 13.992\\",\\"15,363, 23,604\\",\\"Across body bag - red , Across body bag - rose\\",\\"Across body bag - red , Across body bag - rose\\",\\"1, 1\\",\\"ZO0097300973, ZO0196301963\\",\\"0, 0\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"0, 0\\",\\"ZO0097300973, ZO0196301963\\",\\"34.969\\",\\"34.969\\",2,2,order,elyssa +AQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Valdez\\",\\"Clarice Valdez\\",FEMALE,18,Valdez,Valdez,\\"(empty)\\",Saturday,5,\\"clarice@valdez-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563383,\\"sold_product_563383_21467, sold_product_563383_17467\\",\\"sold_product_563383_21467, sold_product_563383_17467\\",\\"60, 50\\",\\"60, 50\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"32.375, 26.484\\",\\"60, 50\\",\\"21,467, 17,467\\",\\"Lace-ups - black, Ankle boots - cognac\\",\\"Lace-ups - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0369103691, ZO0378603786\\",\\"0, 0\\",\\"60, 50\\",\\"60, 50\\",\\"0, 0\\",\\"ZO0369103691, ZO0378603786\\",110,110,2,2,order,clarice +AgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Wood\\",\\"Abd Wood\\",MALE,52,Wood,Wood,\\"(empty)\\",Saturday,5,\\"abd@wood-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563218,\\"sold_product_563218_16231, sold_product_563218_18727\\",\\"sold_product_563218_16231, sold_product_563218_18727\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"9, 5.391\\",\\"16.984, 10.992\\",\\"16,231, 18,727\\",\\"Print T-shirt - bright white, Belt - cognac \\",\\"Print T-shirt - bright white, Belt - cognac \\",\\"1, 1\\",\\"ZO0120401204, ZO0598605986\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0120401204, ZO0598605986\\",\\"27.984\\",\\"27.984\\",2,2,order,abd +TAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Betty,Betty,\\"Betty Ramsey\\",\\"Betty Ramsey\\",FEMALE,44,Ramsey,Ramsey,\\"(empty)\\",Saturday,5,\\"betty@ramsey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563554,\\"sold_product_563554_15671, sold_product_563554_13795\\",\\"sold_product_563554_15671, sold_product_563554_13795\\",\\"70, 33\\",\\"70, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"31.5, 16.5\\",\\"70, 33\\",\\"15,671, 13,795\\",\\"Ankle boots - taupe, Trousers - navy\\",\\"Ankle boots - taupe, Trousers - navy\\",\\"1, 1\\",\\"ZO0246502465, ZO0032100321\\",\\"0, 0\\",\\"70, 33\\",\\"70, 33\\",\\"0, 0\\",\\"ZO0246502465, ZO0032100321\\",103,103,2,2,order,betty +wAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,rania,rania,\\"rania Long\\",\\"rania Long\\",FEMALE,24,Long,Long,\\"(empty)\\",Saturday,5,\\"rania@long-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563023,\\"sold_product_563023_24484, sold_product_563023_21752\\",\\"sold_product_563023_24484, sold_product_563023_21752\\",\\"12.992, 13.992\\",\\"12.992, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"6.879, 6.301\\",\\"12.992, 13.992\\",\\"24,484, 21,752\\",\\"Print T-shirt - black, Pencil skirt - dark grey multicolor\\",\\"Print T-shirt - black, Pencil skirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0055100551, ZO0149701497\\",\\"0, 0\\",\\"12.992, 13.992\\",\\"12.992, 13.992\\",\\"0, 0\\",\\"ZO0055100551, ZO0149701497\\",\\"26.984\\",\\"26.984\\",2,2,order,rani +wQMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Webb\\",\\"Betty Webb\\",FEMALE,44,Webb,Webb,\\"(empty)\\",Saturday,5,\\"betty@webb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563060,\\"sold_product_563060_22520, sold_product_563060_22874\\",\\"sold_product_563060_22520, sold_product_563060_22874\\",\\"42, 42\\",\\"42, 42\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"22.672, 22.672\\",\\"42, 42\\",\\"22,520, 22,874\\",\\"Summer dress - black, Across body bag - black\\",\\"Summer dress - black, Across body bag - black\\",\\"1, 1\\",\\"ZO0040600406, ZO0356503565\\",\\"0, 0\\",\\"42, 42\\",\\"42, 42\\",\\"0, 0\\",\\"ZO0040600406, ZO0356503565\\",84,84,2,2,order,betty +wgMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Phil,Phil,\\"Phil Hudson\\",\\"Phil Hudson\\",MALE,50,Hudson,Hudson,\\"(empty)\\",Saturday,5,\\"phil@hudson-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563108,\\"sold_product_563108_13510, sold_product_563108_11051\\",\\"sold_product_563108_13510, sold_product_563108_11051\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"25.484, 13.344\\",\\"50, 28.984\\",\\"13,510, 11,051\\",\\"Waistcoat - dark blue, Across body bag - brown/brown\\",\\"Waistcoat - dark blue, Across body bag - brown/brown\\",\\"1, 1\\",\\"ZO0429604296, ZO0465204652\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0429604296, ZO0465204652\\",79,79,2,2,order,phil +hAMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Richards\\",\\"Selena Richards\\",FEMALE,42,Richards,Richards,\\"(empty)\\",Saturday,5,\\"selena@richards-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563778,\\"sold_product_563778_15546, sold_product_563778_11477\\",\\"sold_product_563778_15546, sold_product_563778_11477\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"8.328, 11.25\\",\\"16.984, 24.984\\",\\"15,546, 11,477\\",\\"Sweatshirt - coral, Across body bag - cognac\\",\\"Sweatshirt - coral, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0656606566, ZO0186001860\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0656606566, ZO0186001860\\",\\"41.969\\",\\"41.969\\",2,2,order,selena +xwMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Cortez\\",\\"Gwen Cortez\\",FEMALE,26,Cortez,Cortez,\\"(empty)\\",Saturday,5,\\"gwen@cortez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562705,\\"sold_product_562705_12529, sold_product_562705_22843\\",\\"sold_product_562705_12529, sold_product_562705_22843\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Champion Arts\\",\\"Spherecords, Champion Arts\\",\\"5.398, 12\\",\\"11.992, 24.984\\",\\"12,529, 22,843\\",\\"Jumpsuit - black, Shirt - black denim\\",\\"Jumpsuit - black, Shirt - black denim\\",\\"1, 1\\",\\"ZO0633106331, ZO0495904959\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0633106331, ZO0495904959\\",\\"36.969\\",\\"36.969\\",2,2,order,gwen +yAMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Phil,Phil,\\"Phil Sutton\\",\\"Phil Sutton\\",MALE,50,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"phil@sutton-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563639,\\"sold_product_563639_24934, sold_product_563639_3499\\",\\"sold_product_563639_24934, sold_product_563639_3499\\",\\"50, 60\\",\\"50, 60\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"22.5, 28.203\\",\\"50, 60\\",\\"24,934, 3,499\\",\\"Lace-up boots - resin coffee, Hardshell jacket - jet black\\",\\"Lace-up boots - resin coffee, Hardshell jacket - jet black\\",\\"1, 1\\",\\"ZO0403504035, ZO0623006230\\",\\"0, 0\\",\\"50, 60\\",\\"50, 60\\",\\"0, 0\\",\\"ZO0403504035, ZO0623006230\\",110,110,2,2,order,phil +yQMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Yasmine,Yasmine,\\"Yasmine Mcdonald\\",\\"Yasmine Mcdonald\\",FEMALE,43,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"yasmine@mcdonald-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563698,\\"sold_product_563698_23206, sold_product_563698_15645\\",\\"sold_product_563698_23206, sold_product_563698_15645\\",\\"33, 11.992\\",\\"33, 11.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.844, 6.109\\",\\"33, 11.992\\",\\"23,206, 15,645\\",\\"Cardigan - greymulticolor/black, Scarf - green\\",\\"Cardigan - greymulticolor/black, Scarf - green\\",\\"1, 1\\",\\"ZO0070800708, ZO0084100841\\",\\"0, 0\\",\\"33, 11.992\\",\\"33, 11.992\\",\\"0, 0\\",\\"ZO0070800708, ZO0084100841\\",\\"44.969\\",\\"44.969\\",2,2,order,yasmine +MwMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Banks\\",\\"Abd Banks\\",MALE,52,Banks,Banks,\\"(empty)\\",Saturday,5,\\"abd@banks-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations, Microlutions\\",\\"Elitelligence, Oceanavigations, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",714638,\\"sold_product_714638_14544, sold_product_714638_19885, sold_product_714638_13083, sold_product_714638_17585\\",\\"sold_product_714638_14544, sold_product_714638_19885, sold_product_714638_13083, sold_product_714638_17585\\",\\"28.984, 10.992, 24.984, 33\\",\\"28.984, 10.992, 24.984, 33\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Oceanavigations, Microlutions\\",\\"Elitelligence, Elitelligence, Oceanavigations, Microlutions\\",\\"13.633, 5.93, 12.25, 17.484\\",\\"28.984, 10.992, 24.984, 33\\",\\"14,544, 19,885, 13,083, 17,585\\",\\"Jumper - black, Wallet - grey/cognac, Chinos - sand, Shirt - black denim\\",\\"Jumper - black, Wallet - grey/cognac, Chinos - sand, Shirt - black denim\\",\\"1, 1, 1, 1\\",\\"ZO0576205762, ZO0602006020, ZO0281502815, ZO0111001110\\",\\"0, 0, 0, 0\\",\\"28.984, 10.992, 24.984, 33\\",\\"28.984, 10.992, 24.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0576205762, ZO0602006020, ZO0281502815, ZO0111001110\\",\\"97.938\\",\\"97.938\\",4,4,order,abd +bAMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Lloyd\\",\\"Mostafa Lloyd\\",MALE,9,Lloyd,Lloyd,\\"(empty)\\",Saturday,5,\\"mostafa@lloyd-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563602,\\"sold_product_563602_11928, sold_product_563602_13191\\",\\"sold_product_563602_11928, sold_product_563602_13191\\",\\"22.984, 50\\",\\"22.984, 50\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"11.039, 25.984\\",\\"22.984, 50\\",\\"11,928, 13,191\\",\\"Casual lace-ups - black, SOLID - Summer jacket - royal blue\\",\\"Casual lace-ups - black, SOLID - Summer jacket - royal blue\\",\\"1, 1\\",\\"ZO0508705087, ZO0427804278\\",\\"0, 0\\",\\"22.984, 50\\",\\"22.984, 50\\",\\"0, 0\\",\\"ZO0508705087, ZO0427804278\\",73,73,2,2,order,mostafa +8gMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Munoz\\",\\"Sultan Al Munoz\\",MALE,19,Munoz,Munoz,\\"(empty)\\",Saturday,5,\\"sultan al@munoz-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563054,\\"sold_product_563054_11706, sold_product_563054_13408\\",\\"sold_product_563054_11706, sold_product_563054_13408\\",\\"100, 50\\",\\"100, 50\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"49, 23\\",\\"100, 50\\",\\"11,706, 13,408\\",\\"Weekend bag - dark brown, Cowboy/Biker boots - dark brown/tan\\",\\"Weekend bag - dark brown, Cowboy/Biker boots - dark brown/tan\\",\\"1, 1\\",\\"ZO0701907019, ZO0519405194\\",\\"0, 0\\",\\"100, 50\\",\\"100, 50\\",\\"0, 0\\",\\"ZO0701907019, ZO0519405194\\",150,150,2,2,order,sultan +8wMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Shaw\\",\\"Abd Shaw\\",MALE,52,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"abd@shaw-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563093,\\"sold_product_563093_18385, sold_product_563093_16783\\",\\"sold_product_563093_18385, sold_product_563093_16783\\",\\"7.988, 42\\",\\"7.988, 42\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"4.07, 20.156\\",\\"7.988, 42\\",\\"18,385, 16,783\\",\\"Basic T-shirt - dark grey multicolor, Weekend bag - black\\",\\"Basic T-shirt - dark grey multicolor, Weekend bag - black\\",\\"1, 1\\",\\"ZO0435004350, ZO0472104721\\",\\"0, 0\\",\\"7.988, 42\\",\\"7.988, 42\\",\\"0, 0\\",\\"ZO0435004350, ZO0472104721\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +IQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Ryan\\",\\"Pia Ryan\\",FEMALE,45,Ryan,Ryan,\\"(empty)\\",Saturday,5,\\"pia@ryan-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562875,\\"sold_product_562875_19166, sold_product_562875_21969\\",\\"sold_product_562875_19166, sold_product_562875_21969\\",\\"60, 7.988\\",\\"60, 7.988\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords\\",\\"Gnomehouse, Spherecords\\",\\"29.406, 3.68\\",\\"60, 7.988\\",\\"19,166, 21,969\\",\\"Cardigan - camel, Vest - bordeaux\\",\\"Cardigan - camel, Vest - bordeaux\\",\\"1, 1\\",\\"ZO0353003530, ZO0637006370\\",\\"0, 0\\",\\"60, 7.988\\",\\"60, 7.988\\",\\"0, 0\\",\\"ZO0353003530, ZO0637006370\\",68,68,2,2,order,pia +IgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Brigitte,Brigitte,\\"Brigitte Holland\\",\\"Brigitte Holland\\",FEMALE,12,Holland,Holland,\\"(empty)\\",Saturday,5,\\"brigitte@holland-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Primemaster, Pyramidustries\\",\\"Primemaster, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562914,\\"sold_product_562914_16495, sold_product_562914_16949\\",\\"sold_product_562914_16495, sold_product_562914_16949\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Primemaster, Pyramidustries\\",\\"Primemaster, Pyramidustries\\",\\"39.75, 6.859\\",\\"75, 13.992\\",\\"16,495, 16,949\\",\\"Sandals - nuvola, Scarf - bordeaux/mustard\\",\\"Sandals - nuvola, Scarf - bordeaux/mustard\\",\\"1, 1\\",\\"ZO0360503605, ZO0194501945\\",\\"0, 0\\",\\"75, 13.992\\",\\"75, 13.992\\",\\"0, 0\\",\\"ZO0360503605, ZO0194501945\\",89,89,2,2,order,brigitte +IwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Bailey\\",\\"Brigitte Bailey\\",FEMALE,12,Bailey,Bailey,\\"(empty)\\",Saturday,5,\\"brigitte@bailey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562654,\\"sold_product_562654_13316, sold_product_562654_13303\\",\\"sold_product_562654_13316, sold_product_562654_13303\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"12, 5.602\\",\\"24.984, 10.992\\",\\"13,316, 13,303\\",\\"Blouse - black, Print T-shirt - white\\",\\"Blouse - black, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0065400654, ZO0158701587\\",\\"0, 0\\",\\"24.984, 10.992\\",\\"24.984, 10.992\\",\\"0, 0\\",\\"ZO0065400654, ZO0158701587\\",\\"35.969\\",\\"35.969\\",2,2,order,brigitte +JQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Betty,Betty,\\"Betty Massey\\",\\"Betty Massey\\",FEMALE,44,Massey,Massey,\\"(empty)\\",Saturday,5,\\"betty@massey-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563860,\\"sold_product_563860_17204, sold_product_563860_5970\\",\\"sold_product_563860_17204, sold_product_563860_5970\\",\\"33, 33\\",\\"33, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.156, 15.844\\",\\"33, 33\\",\\"17,204, 5,970\\",\\"Blouse - potent purple, Wedge boots - toffee\\",\\"Blouse - potent purple, Wedge boots - toffee\\",\\"1, 1\\",\\"ZO0344703447, ZO0031000310\\",\\"0, 0\\",\\"33, 33\\",\\"33, 33\\",\\"0, 0\\",\\"ZO0344703447, ZO0031000310\\",66,66,2,2,order,betty +JgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Rivera\\",\\"Yasmine Rivera\\",FEMALE,43,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"yasmine@rivera-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563907,\\"sold_product_563907_11709, sold_product_563907_20859\\",\\"sold_product_563907_11709, sold_product_563907_20859\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"11.328, 10.063\\",\\"20.984, 18.984\\",\\"11,709, 20,859\\",\\"Jersey dress - black, Long sleeved top - navy\\",\\"Jersey dress - black, Long sleeved top - navy\\",\\"1, 1\\",\\"ZO0036700367, ZO0054300543\\",\\"0, 0\\",\\"20.984, 18.984\\",\\"20.984, 18.984\\",\\"0, 0\\",\\"ZO0036700367, ZO0054300543\\",\\"39.969\\",\\"39.969\\",2,2,order,yasmine +QQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Youssef,Youssef,\\"Youssef Conner\\",\\"Youssef Conner\\",MALE,31,Conner,Conner,\\"(empty)\\",Saturday,5,\\"youssef@conner-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562833,\\"sold_product_562833_21511, sold_product_562833_14742\\",\\"sold_product_562833_21511, sold_product_562833_14742\\",\\"13.992, 33\\",\\"13.992, 33\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"7.41, 15.18\\",\\"13.992, 33\\",\\"21,511, 14,742\\",\\"3 PACK - Shorts - black, Laptop bag - brown\\",\\"3 PACK - Shorts - black, Laptop bag - brown\\",\\"1, 1\\",\\"ZO0610806108, ZO0316803168\\",\\"0, 0\\",\\"13.992, 33\\",\\"13.992, 33\\",\\"0, 0\\",\\"ZO0610806108, ZO0316803168\\",\\"46.969\\",\\"46.969\\",2,2,order,youssef +QgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Soto\\",\\"Abd Soto\\",MALE,52,Soto,Soto,\\"(empty)\\",Saturday,5,\\"abd@soto-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562899,\\"sold_product_562899_21057, sold_product_562899_13717\\",\\"sold_product_562899_21057, sold_product_562899_13717\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"6.859, 15.359\\",\\"13.992, 28.984\\",\\"21,057, 13,717\\",\\"Scarf - navy/grey, Tracksuit top - blue\\",\\"Scarf - navy/grey, Tracksuit top - blue\\",\\"1, 1\\",\\"ZO0313403134, ZO0587105871\\",\\"0, 0\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"0, 0\\",\\"ZO0313403134, ZO0587105871\\",\\"42.969\\",\\"42.969\\",2,2,order,abd +QwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Soto\\",\\"Ahmed Al Soto\\",MALE,4,Soto,Soto,\\"(empty)\\",Saturday,5,\\"ahmed al@soto-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Spherecords\\",\\"Elitelligence, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562665,\\"sold_product_562665_15130, sold_product_562665_14446\\",\\"sold_product_562665_15130, sold_product_562665_14446\\",\\"11.992, 8.992\\",\\"11.992, 8.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spherecords\\",\\"Elitelligence, Spherecords\\",\\"6.469, 4.578\\",\\"11.992, 8.992\\",\\"15,130, 14,446\\",\\"Long sleeved top - white, 5 PACK - Socks - dark grey\\",\\"Long sleeved top - white, 5 PACK - Socks - dark grey\\",\\"1, 1\\",\\"ZO0569205692, ZO0664006640\\",\\"0, 0\\",\\"11.992, 8.992\\",\\"11.992, 8.992\\",\\"0, 0\\",\\"ZO0569205692, ZO0664006640\\",\\"20.984\\",\\"20.984\\",2,2,order,ahmed +RwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Mostafa,Mostafa,\\"Mostafa Clayton\\",\\"Mostafa Clayton\\",MALE,9,Clayton,Clayton,\\"(empty)\\",Saturday,5,\\"mostafa@clayton-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563579,\\"sold_product_563579_12028, sold_product_563579_14742\\",\\"sold_product_563579_12028, sold_product_563579_14742\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"3.92, 15.18\\",\\"7.988, 33\\",\\"12,028, 14,742\\",\\"Vest - light blue multicolor, Laptop bag - brown\\",\\"Vest - light blue multicolor, Laptop bag - brown\\",\\"1, 1\\",\\"ZO0548905489, ZO0316803168\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0548905489, ZO0316803168\\",\\"40.969\\",\\"40.969\\",2,2,order,mostafa +SAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Chandler\\",\\"Elyssa Chandler\\",FEMALE,27,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"elyssa@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563119,\\"sold_product_563119_22794, sold_product_563119_23300\\",\\"sold_product_563119_22794, sold_product_563119_23300\\",\\"100, 35\\",\\"100, 35\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"46, 16.453\\",\\"100, 35\\",\\"22,794, 23,300\\",\\"Boots - Midnight Blue, Shift dress - black\\",\\"Boots - Midnight Blue, Shift dress - black\\",\\"1, 1\\",\\"ZO0374603746, ZO0041300413\\",\\"0, 0\\",\\"100, 35\\",\\"100, 35\\",\\"0, 0\\",\\"ZO0374603746, ZO0041300413\\",135,135,2,2,order,elyssa +SQMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Accessories, Women's Accessories\\",\\"Men's Accessories, Women's Accessories\\",EUR,Recip,Recip,\\"Recip Gilbert\\",\\"Recip Gilbert\\",MALE,10,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"recip@gilbert-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563152,\\"sold_product_563152_22166, sold_product_563152_14897\\",\\"sold_product_563152_22166, sold_product_563152_14897\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"Men's Accessories, Women's Accessories\\",\\"Men's Accessories, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"6.469, 12.992\\",\\"11.992, 24.984\\",\\"22,166, 14,897\\",\\"Scarf - navy/turqoise, Rucksack - olive \\",\\"Scarf - navy/turqoise, Rucksack - olive \\",\\"1, 1\\",\\"ZO0603606036, ZO0608206082\\",\\"0, 0\\",\\"11.992, 24.984\\",\\"11.992, 24.984\\",\\"0, 0\\",\\"ZO0603606036, ZO0608206082\\",\\"36.969\\",\\"36.969\\",2,2,order,recip +dwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Chandler\\",\\"Wilhemina St. Chandler\\",FEMALE,17,Chandler,Chandler,\\"(empty)\\",Saturday,5,\\"wilhemina st.@chandler-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",725079,\\"sold_product_725079_18356, sold_product_725079_16691, sold_product_725079_9233, sold_product_725079_13733\\",\\"sold_product_725079_18356, sold_product_725079_16691, sold_product_725079_9233, sold_product_725079_13733\\",\\"10.992, 20.984, 42, 14.992\\",\\"10.992, 20.984, 42, 14.992\\",\\"Women's Clothing, Women's Accessories, Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories, Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Tigress Enterprises, Tigress Enterprises, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises, Tigress Enterprises, Tigress Enterprises\\",\\"5.391, 10.492, 22.672, 7.641\\",\\"10.992, 20.984, 42, 14.992\\",\\"18,356, 16,691, 9,233, 13,733\\",\\"2 PACK - Vest - white/white, Across body bag - black, Jumper - grey multicolor, Scarf - mint\\",\\"2 PACK - Vest - white/white, Across body bag - black, Jumper - grey multicolor, Scarf - mint\\",\\"1, 1, 1, 1\\",\\"ZO0641506415, ZO0086200862, ZO0071500715, ZO0085700857\\",\\"0, 0, 0, 0\\",\\"10.992, 20.984, 42, 14.992\\",\\"10.992, 20.984, 42, 14.992\\",\\"0, 0, 0, 0\\",\\"ZO0641506415, ZO0086200862, ZO0071500715, ZO0085700857\\",\\"88.938\\",\\"88.938\\",4,4,order,wilhemina +kQMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Robbie,Robbie,\\"Robbie Harvey\\",\\"Robbie Harvey\\",MALE,48,Harvey,Harvey,\\"(empty)\\",Saturday,5,\\"robbie@harvey-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563736,\\"sold_product_563736_22302, sold_product_563736_14502\\",\\"sold_product_563736_22302, sold_product_563736_14502\\",\\"28.984, 15.992\\",\\"28.984, 15.992\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.633, 7.84\\",\\"28.984, 15.992\\",\\"22,302, 14,502\\",\\"Shirt - white, Belt - black\\",\\"Shirt - white, Belt - black\\",\\"1, 1\\",\\"ZO0415604156, ZO0461704617\\",\\"0, 0\\",\\"28.984, 15.992\\",\\"28.984, 15.992\\",\\"0, 0\\",\\"ZO0415604156, ZO0461704617\\",\\"44.969\\",\\"44.969\\",2,2,order,robbie +kgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Bryant\\",\\"Stephanie Bryant\\",FEMALE,6,Bryant,Bryant,\\"(empty)\\",Saturday,5,\\"stephanie@bryant-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563761,\\"sold_product_563761_13657, sold_product_563761_15397\\",\\"sold_product_563761_13657, sold_product_563761_15397\\",\\"33, 42\\",\\"33, 42\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"15.844, 20.156\\",\\"33, 42\\",\\"13,657, 15,397\\",\\"Tote bag - black, A-line skirt - coronet blue\\",\\"Tote bag - black, A-line skirt - coronet blue\\",\\"1, 1\\",\\"ZO0087700877, ZO0330603306\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0087700877, ZO0330603306\\",75,75,2,2,order,stephanie +kwMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Jackson\\",\\"Gwen Jackson\\",FEMALE,26,Jackson,Jackson,\\"(empty)\\",Saturday,5,\\"gwen@jackson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563800,\\"sold_product_563800_19249, sold_product_563800_20352\\",\\"sold_product_563800_19249, sold_product_563800_20352\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Pyramidustries\\",\\"Oceanavigations, Pyramidustries\\",\\"41.656, 6\\",\\"85, 11.992\\",\\"19,249, 20,352\\",\\"Handbag - black, Vest - red\\",\\"Handbag - black, Vest - red\\",\\"1, 1\\",\\"ZO0307303073, ZO0161601616\\",\\"0, 0\\",\\"85, 11.992\\",\\"85, 11.992\\",\\"0, 0\\",\\"ZO0307303073, ZO0161601616\\",97,97,2,2,order,gwen +\\"-AMtOW0BH63Xcmy4524Z\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Austin\\",\\"Eddie Austin\\",MALE,38,Austin,Austin,\\"(empty)\\",Saturday,5,\\"eddie@austin-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563822,\\"sold_product_563822_13869, sold_product_563822_12632\\",\\"sold_product_563822_13869, sold_product_563822_12632\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"6.859, 26.484\\",\\"13.992, 50\\",\\"13,869, 12,632\\",\\"Tie - black, Down jacket - black\\",\\"Tie - black, Down jacket - black\\",\\"1, 1\\",\\"ZO0277402774, ZO0288502885\\",\\"0, 0\\",\\"13.992, 50\\",\\"13.992, 50\\",\\"0, 0\\",\\"ZO0277402774, ZO0288502885\\",\\"63.969\\",\\"63.969\\",2,2,order,eddie +GQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Hansen\\",\\"Oliver Hansen\\",MALE,7,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"oliver@hansen-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562948,\\"sold_product_562948_23445, sold_product_562948_17355\\",\\"sold_product_562948_23445, sold_product_562948_17355\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.633, 4\\",\\"28.984, 7.988\\",\\"23,445, 17,355\\",\\"Chinos - navy, Print T-shirt - white\\",\\"Chinos - navy, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0282102821, ZO0554405544\\",\\"0, 0\\",\\"28.984, 7.988\\",\\"28.984, 7.988\\",\\"0, 0\\",\\"ZO0282102821, ZO0554405544\\",\\"36.969\\",\\"36.969\\",2,2,order,oliver +GgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Frances,Frances,\\"Frances Moran\\",\\"Frances Moran\\",FEMALE,49,Moran,Moran,\\"(empty)\\",Saturday,5,\\"frances@moran-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562993,\\"sold_product_562993_17227, sold_product_562993_17918\\",\\"sold_product_562993_17227, sold_product_562993_17918\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"27.594, 6.23\\",\\"60, 11.992\\",\\"17,227, 17,918\\",\\"Trainers - bianco, Basic T-shirt - lilac\\",\\"Trainers - bianco, Basic T-shirt - lilac\\",\\"1, 1\\",\\"ZO0255202552, ZO0560005600\\",\\"0, 0\\",\\"60, 11.992\\",\\"60, 11.992\\",\\"0, 0\\",\\"ZO0255202552, ZO0560005600\\",72,72,2,2,order,frances +HAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Morrison\\",\\"Sonya Morrison\\",FEMALE,28,Morrison,Morrison,\\"(empty)\\",Saturday,5,\\"sonya@morrison-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562585,\\"sold_product_562585_16665, sold_product_562585_8623\\",\\"sold_product_562585_16665, sold_product_562585_8623\\",\\"20.984, 17.984\\",\\"20.984, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.539, 8.102\\",\\"20.984, 17.984\\",\\"16,665, 8,623\\",\\"Vest - black, Long sleeved top - red ochre\\",\\"Vest - black, Long sleeved top - red ochre\\",\\"1, 1\\",\\"ZO0063800638, ZO0165301653\\",\\"0, 0\\",\\"20.984, 17.984\\",\\"20.984, 17.984\\",\\"0, 0\\",\\"ZO0063800638, ZO0165301653\\",\\"38.969\\",\\"38.969\\",2,2,order,sonya +HQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Ball\\",\\"Diane Ball\\",FEMALE,22,Ball,Ball,\\"(empty)\\",Saturday,5,\\"diane@ball-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563326,\\"sold_product_563326_22030, sold_product_563326_23066\\",\\"sold_product_563326_22030, sold_product_563326_23066\\",\\"42, 85\\",\\"42, 85\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"21.406, 44.188\\",\\"42, 85\\",\\"22,030, 23,066\\",\\"Blouse - black, Lace-up boots - black\\",\\"Blouse - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0266702667, ZO0680306803\\",\\"0, 0\\",\\"42, 85\\",\\"42, 85\\",\\"0, 0\\",\\"ZO0266702667, ZO0680306803\\",127,127,2,2,order,diane +JQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Fletcher\\",\\"Stephanie Fletcher\\",FEMALE,6,Fletcher,Fletcher,\\"(empty)\\",Saturday,5,\\"stephanie@fletcher-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563755,\\"sold_product_563755_13226, sold_product_563755_12114\\",\\"sold_product_563755_13226, sold_product_563755_12114\\",\\"16.984, 29.984\\",\\"16.984, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"Spherecords Curvy, Tigress Enterprises\\",\\"8.828, 16.188\\",\\"16.984, 29.984\\",\\"13,226, 12,114\\",\\"Blouse - offwhite, Jersey dress - black/white\\",\\"Blouse - offwhite, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0710707107, ZO0038300383\\",\\"0, 0\\",\\"16.984, 29.984\\",\\"16.984, 29.984\\",\\"0, 0\\",\\"ZO0710707107, ZO0038300383\\",\\"46.969\\",\\"46.969\\",2,2,order,stephanie +TwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Hopkins\\",\\"Abd Hopkins\\",MALE,52,Hopkins,Hopkins,\\"(empty)\\",Saturday,5,\\"abd@hopkins-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations, Spherecords\\",\\"Low Tide Media, Oceanavigations, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",715450,\\"sold_product_715450_13559, sold_product_715450_21852, sold_product_715450_16570, sold_product_715450_11336\\",\\"sold_product_715450_13559, sold_product_715450_21852, sold_product_715450_16570, sold_product_715450_11336\\",\\"13.992, 20.984, 65, 10.992\\",\\"13.992, 20.984, 65, 10.992\\",\\"Men's Clothing, Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Spherecords\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Spherecords\\",\\"6.441, 10.078, 31.844, 5.059\\",\\"13.992, 20.984, 65, 10.992\\",\\"13,559, 21,852, 16,570, 11,336\\",\\"3 PACK - Shorts - light blue/dark blue/white, Wallet - brown, Boots - navy, Long sleeved top - white/black\\",\\"3 PACK - Shorts - light blue/dark blue/white, Wallet - brown, Boots - navy, Long sleeved top - white/black\\",\\"1, 1, 1, 1\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\",\\"0, 0, 0, 0\\",\\"13.992, 20.984, 65, 10.992\\",\\"13.992, 20.984, 65, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0476604766, ZO0462404624, ZO0258302583, ZO0658206582\\",\\"110.938\\",\\"110.938\\",4,4,order,abd +dgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Boone\\",\\"Abdulraheem Al Boone\\",MALE,33,Boone,Boone,\\"(empty)\\",Saturday,5,\\"abdulraheem al@boone-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Oceanavigations,Oceanavigations,\\"Jun 21, 2019 @ 00:00:00.000\\",563181,\\"sold_product_563181_15447, sold_product_563181_19692\\",\\"sold_product_563181_15447, sold_product_563181_19692\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"24.5, 6.859\\",\\"50, 13.992\\",\\"15,447, 19,692\\",\\"Suit jacket - grey, Print T-shirt - black\\",\\"Suit jacket - grey, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0274902749, ZO0293902939\\",\\"0, 0\\",\\"50, 13.992\\",\\"50, 13.992\\",\\"0, 0\\",\\"ZO0274902749, ZO0293902939\\",\\"63.969\\",\\"63.969\\",2,2,order,abdulraheem +jQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Diane,Diane,\\"Diane Graves\\",\\"Diane Graves\\",FEMALE,22,Graves,Graves,\\"(empty)\\",Saturday,5,\\"diane@graves-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563131,\\"sold_product_563131_15426, sold_product_563131_21432\\",\\"sold_product_563131_15426, sold_product_563131_21432\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"39, 11.539\\",\\"75, 20.984\\",\\"15,426, 21,432\\",\\"Cowboy/Biker boots - black, Blouse - peacoat\\",\\"Cowboy/Biker boots - black, Blouse - peacoat\\",\\"1, 1\\",\\"ZO0326803268, ZO0059600596\\",\\"0, 0\\",\\"75, 20.984\\",\\"75, 20.984\\",\\"0, 0\\",\\"ZO0326803268, ZO0059600596\\",96,96,2,2,order,diane +0gMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Wood\\",\\"Selena Wood\\",FEMALE,42,Wood,Wood,\\"(empty)\\",Saturday,5,\\"selena@wood-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563254,\\"sold_product_563254_23719, sold_product_563254_11095\\",\\"sold_product_563254_23719, sold_product_563254_11095\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Champion Arts\\",\\"13.922, 9.867\\",\\"28.984, 20.984\\",\\"23,719, 11,095\\",\\"Jersey dress - peacoat, Tracksuit top - pink multicolor\\",\\"Jersey dress - peacoat, Tracksuit top - pink multicolor\\",\\"1, 1\\",\\"ZO0052100521, ZO0498804988\\",\\"0, 0\\",\\"28.984, 20.984\\",\\"28.984, 20.984\\",\\"0, 0\\",\\"ZO0052100521, ZO0498804988\\",\\"49.969\\",\\"49.969\\",2,2,order,selena +OQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Tran\\",\\"Brigitte Tran\\",FEMALE,12,Tran,Tran,\\"(empty)\\",Saturday,5,\\"brigitte@tran-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563573,\\"sold_product_563573_22735, sold_product_563573_23822\\",\\"sold_product_563573_22735, sold_product_563573_23822\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Oceanavigations\\",\\"Pyramidustries, Oceanavigations\\",\\"13.742, 32.375\\",\\"24.984, 60\\",\\"22,735, 23,822\\",\\"Platform heels - black, Sandals - Midnight Blue\\",\\"Platform heels - black, Sandals - Midnight Blue\\",\\"1, 1\\",\\"ZO0132601326, ZO0243002430\\",\\"0, 0\\",\\"24.984, 60\\",\\"24.984, 60\\",\\"0, 0\\",\\"ZO0132601326, ZO0243002430\\",85,85,2,2,order,brigitte +VwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Chapman\\",\\"Thad Chapman\\",MALE,30,Chapman,Chapman,\\"(empty)\\",Saturday,5,\\"thad@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562699,\\"sold_product_562699_24934, sold_product_562699_20799\\",\\"sold_product_562699_24934, sold_product_562699_20799\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 7.5\\",\\"50, 14.992\\",\\"24,934, 20,799\\",\\"Lace-up boots - resin coffee, Long sleeved top - white/black\\",\\"Lace-up boots - resin coffee, Long sleeved top - white/black\\",\\"1, 1\\",\\"ZO0403504035, ZO0558905589\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0558905589\\",65,65,2,2,order,thad +WAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Accessories\\",\\"Men's Accessories\\",EUR,Tariq,Tariq,\\"Tariq Rivera\\",\\"Tariq Rivera\\",MALE,25,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"tariq@rivera-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563644,\\"sold_product_563644_20541, sold_product_563644_14121\\",\\"sold_product_563644_20541, sold_product_563644_14121\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"Men's Accessories, Men's Accessories\\",\\"Men's Accessories, Men's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"44.094, 9.172\\",\\"90, 17.984\\",\\"20,541, 14,121\\",\\"Laptop bag - Dark Sea Green, Watch - grey\\",\\"Laptop bag - Dark Sea Green, Watch - grey\\",\\"1, 1\\",\\"ZO0470104701, ZO0600506005\\",\\"0, 0\\",\\"90, 17.984\\",\\"90, 17.984\\",\\"0, 0\\",\\"ZO0470104701, ZO0600506005\\",108,108,2,2,order,tariq +WQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Eddie,Eddie,\\"Eddie Davidson\\",\\"Eddie Davidson\\",MALE,38,Davidson,Davidson,\\"(empty)\\",Saturday,5,\\"eddie@davidson-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563701,\\"sold_product_563701_20743, sold_product_563701_23294\\",\\"sold_product_563701_20743, sold_product_563701_23294\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.75, 15.938\\",\\"24.984, 28.984\\",\\"20,743, 23,294\\",\\"Slim fit jeans - grey, Tracksuit bottoms - dark blue\\",\\"Slim fit jeans - grey, Tracksuit bottoms - dark blue\\",\\"1, 1\\",\\"ZO0536305363, ZO0282702827\\",\\"0, 0\\",\\"24.984, 28.984\\",\\"24.984, 28.984\\",\\"0, 0\\",\\"ZO0536305363, ZO0282702827\\",\\"53.969\\",\\"53.969\\",2,2,order,eddie +ZQMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Frank\\",\\"Ahmed Al Frank\\",MALE,4,Frank,Frank,\\"(empty)\\",Saturday,5,\\"ahmed al@frank-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562817,\\"sold_product_562817_1438, sold_product_562817_22804\\",\\"sold_product_562817_1438, sold_product_562817_22804\\",\\"60, 29.984\\",\\"60, 29.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"32.375, 15.891\\",\\"60, 29.984\\",\\"1,438, 22,804\\",\\"Trainers - black, Bomber Jacket - navy\\",\\"Trainers - black, Bomber Jacket - navy\\",\\"1, 1\\",\\"ZO0254702547, ZO0457804578\\",\\"0, 0\\",\\"60, 29.984\\",\\"60, 29.984\\",\\"0, 0\\",\\"ZO0254702547, ZO0457804578\\",90,90,2,2,order,ahmed +ZgMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Stokes\\",\\"Stephanie Stokes\\",FEMALE,6,Stokes,Stokes,\\"(empty)\\",Saturday,5,\\"stephanie@stokes-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562881,\\"sold_product_562881_20244, sold_product_562881_21108\\",\\"sold_product_562881_20244, sold_product_562881_21108\\",\\"28.984, 9.992\\",\\"28.984, 9.992\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"15.359, 5\\",\\"28.984, 9.992\\",\\"20,244, 21,108\\",\\"Handbag - black, Jersey dress - black\\",\\"Handbag - black, Jersey dress - black\\",\\"1, 1\\",\\"ZO0091700917, ZO0635406354\\",\\"0, 0\\",\\"28.984, 9.992\\",\\"28.984, 9.992\\",\\"0, 0\\",\\"ZO0091700917, ZO0635406354\\",\\"38.969\\",\\"38.969\\",2,2,order,stephanie +ZwMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Sherman\\",\\"Brigitte Sherman\\",FEMALE,12,Sherman,Sherman,\\"(empty)\\",Saturday,5,\\"brigitte@sherman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562630,\\"sold_product_562630_18015, sold_product_562630_15858\\",\\"sold_product_562630_18015, sold_product_562630_15858\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"30, 13.492\\",\\"60, 24.984\\",\\"18,015, 15,858\\",\\"Summer dress - blue fog, Slip-ons - gold\\",\\"Summer dress - blue fog, Slip-ons - gold\\",\\"1, 1\\",\\"ZO0339803398, ZO0009700097\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0339803398, ZO0009700097\\",85,85,2,2,order,brigitte +aAMtOW0BH63Xcmy453AZ,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Hudson\\",\\"Hicham Hudson\\",MALE,8,Hudson,Hudson,\\"(empty)\\",Saturday,5,\\"hicham@hudson-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spherecords, Elitelligence\\",\\"Spherecords, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562667,\\"sold_product_562667_21772, sold_product_562667_1559\\",\\"sold_product_562667_21772, sold_product_562667_1559\\",\\"8.992, 33\\",\\"8.992, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Elitelligence\\",\\"Spherecords, Elitelligence\\",\\"4.672, 17.813\\",\\"8.992, 33\\",\\"21,772, 1,559\\",\\"3 PACK - Socks - white, Lace-ups - light brown\\",\\"3 PACK - Socks - white, Lace-ups - light brown\\",\\"1, 1\\",\\"ZO0664706647, ZO0506005060\\",\\"0, 0\\",\\"8.992, 33\\",\\"8.992, 33\\",\\"0, 0\\",\\"ZO0664706647, ZO0506005060\\",\\"41.969\\",\\"41.969\\",2,2,order,hicham +jQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Palmer\\",\\"Abd Palmer\\",MALE,52,Palmer,Palmer,\\"(empty)\\",Saturday,5,\\"abd@palmer-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563342,\\"sold_product_563342_24934, sold_product_563342_21049\\",\\"sold_product_563342_24934, sold_product_563342_21049\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"22.5, 7.941\\",\\"50, 14.992\\",\\"24,934, 21,049\\",\\"Lace-up boots - resin coffee, Print T-shirt - dark grey\\",\\"Lace-up boots - resin coffee, Print T-shirt - dark grey\\",\\"1, 1\\",\\"ZO0403504035, ZO0121101211\\",\\"0, 0\\",\\"50, 14.992\\",\\"50, 14.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0121101211\\",65,65,2,2,order,abd +mgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Hansen\\",\\"Jackson Hansen\\",MALE,13,Hansen,Hansen,\\"(empty)\\",Saturday,5,\\"jackson@hansen-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563366,\\"sold_product_563366_13189, sold_product_563366_18905\\",\\"sold_product_563366_13189, sold_product_563366_18905\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"17.156, 20.156\\",\\"33, 42\\",\\"13,189, 18,905\\",\\"Smart lace-ups - black , Light jacket - khaki\\",\\"Smart lace-ups - black , Light jacket - khaki\\",\\"1, 1\\",\\"ZO0388103881, ZO0540005400\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0388103881, ZO0540005400\\",75,75,2,2,order,jackson +oAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Recip,Recip,\\"Recip Webb\\",\\"Recip Webb\\",MALE,10,Webb,Webb,\\"(empty)\\",Saturday,5,\\"recip@webb-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562919,\\"sold_product_562919_24934, sold_product_562919_22599\\",\\"sold_product_562919_24934, sold_product_562919_22599\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"22.5, 11.5\\",\\"50, 24.984\\",\\"24,934, 22,599\\",\\"Lace-up boots - resin coffee, Sweatshirt - black\\",\\"Lace-up boots - resin coffee, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0403504035, ZO0595005950\\",\\"0, 0\\",\\"50, 24.984\\",\\"50, 24.984\\",\\"0, 0\\",\\"ZO0403504035, ZO0595005950\\",75,75,2,2,order,recip +oQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Hicham,Hicham,\\"Hicham Sutton\\",\\"Hicham Sutton\\",MALE,8,Sutton,Sutton,\\"(empty)\\",Saturday,5,\\"hicham@sutton-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562976,\\"sold_product_562976_23426, sold_product_562976_1978\\",\\"sold_product_562976_23426, sold_product_562976_1978\\",\\"33, 50\\",\\"33, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"16.813, 27.484\\",\\"33, 50\\",\\"23,426, 1,978\\",\\"Slim fit jeans - navy coated , Lace-up boots - black\\",\\"Slim fit jeans - navy coated , Lace-up boots - black\\",\\"1, 1\\",\\"ZO0426904269, ZO0520305203\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0426904269, ZO0520305203\\",83,83,2,2,order,hicham +sgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Barber\\",\\"Elyssa Barber\\",FEMALE,27,Barber,Barber,\\"(empty)\\",Saturday,5,\\"elyssa@barber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563371,\\"sold_product_563371_16009, sold_product_563371_24465\\",\\"sold_product_563371_16009, sold_product_563371_24465\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"16.734, 11.5\\",\\"30.984, 24.984\\",\\"16,009, 24,465\\",\\"Handbag - black, Cowboy/Biker boots - black\\",\\"Handbag - black, Cowboy/Biker boots - black\\",\\"1, 1\\",\\"ZO0097500975, ZO0017100171\\",\\"0, 0\\",\\"30.984, 24.984\\",\\"30.984, 24.984\\",\\"0, 0\\",\\"ZO0097500975, ZO0017100171\\",\\"55.969\\",\\"55.969\\",2,2,order,elyssa +1wMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Oliver,Oliver,\\"Oliver Graves\\",\\"Oliver Graves\\",MALE,7,Graves,Graves,\\"(empty)\\",Saturday,5,\\"oliver@graves-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562989,\\"sold_product_562989_22919, sold_product_562989_22668\\",\\"sold_product_562989_22919, sold_product_562989_22668\\",\\"22.984, 22.984\\",\\"22.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"10.813, 11.492\\",\\"22.984, 22.984\\",\\"22,919, 22,668\\",\\"Sweatshirt - white, Shirt - petrol\\",\\"Sweatshirt - white, Shirt - petrol\\",\\"1, 1\\",\\"ZO0590905909, ZO0279902799\\",\\"0, 0\\",\\"22.984, 22.984\\",\\"22.984, 22.984\\",\\"0, 0\\",\\"ZO0590905909, ZO0279902799\\",\\"45.969\\",\\"45.969\\",2,2,order,oliver +2QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Pia,Pia,\\"Pia Harmon\\",\\"Pia Harmon\\",FEMALE,45,Harmon,Harmon,\\"(empty)\\",Saturday,5,\\"pia@harmon-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562597,\\"sold_product_562597_24187, sold_product_562597_14371\\",\\"sold_product_562597_24187, sold_product_562597_14371\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"25.984, 10.063\\",\\"50, 18.984\\",\\"24,187, 14,371\\",\\"Boots - cognac, Across body bag - black\\",\\"Boots - cognac, Across body bag - black\\",\\"1, 1\\",\\"ZO0013200132, ZO0093800938\\",\\"0, 0\\",\\"50, 18.984\\",\\"50, 18.984\\",\\"0, 0\\",\\"ZO0013200132, ZO0093800938\\",69,69,2,2,order,pia +TwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Goodwin\\",\\"Clarice Goodwin\\",FEMALE,18,Goodwin,Goodwin,\\"(empty)\\",Saturday,5,\\"clarice@goodwin-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563548,\\"sold_product_563548_5972, sold_product_563548_20864\\",\\"sold_product_563548_5972, sold_product_563548_20864\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"12.992, 16.172\\",\\"24.984, 33\\",\\"5,972, 20,864\\",\\"Ankle boots - black, Winter boots - cognac\\",\\"Ankle boots - black, Winter boots - cognac\\",\\"1, 1\\",\\"ZO0021600216, ZO0031600316\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0021600216, ZO0031600316\\",\\"57.969\\",\\"57.969\\",2,2,order,clarice +awMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Marwan,Marwan,\\"Marwan Shaw\\",\\"Marwan Shaw\\",MALE,51,Shaw,Shaw,\\"(empty)\\",Saturday,5,\\"marwan@shaw-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 21, 2019 @ 00:00:00.000\\",562715,\\"sold_product_562715_21515, sold_product_562715_13710\\",\\"sold_product_562715_21515, sold_product_562715_13710\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"13.922, 5.52\\",\\"28.984, 11.992\\",\\"21,515, 13,710\\",\\"Shirt - dark blue, Print T-shirt - blue\\",\\"Shirt - dark blue, Print T-shirt - blue\\",\\"1, 1\\",\\"ZO0413404134, ZO0437204372\\",\\"0, 0\\",\\"28.984, 11.992\\",\\"28.984, 11.992\\",\\"0, 0\\",\\"ZO0413404134, ZO0437204372\\",\\"40.969\\",\\"40.969\\",2,2,order,marwan +bAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Dennis\\",\\"Mary Dennis\\",FEMALE,20,Dennis,Dennis,\\"(empty)\\",Saturday,5,\\"mary@dennis-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563657,\\"sold_product_563657_21922, sold_product_563657_16149\\",\\"sold_product_563657_21922, sold_product_563657_16149\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"10.492, 29.906\\",\\"20.984, 65\\",\\"21,922, 16,149\\",\\"Jumper - dark blue/off white , Lace-up heels - cognac\\",\\"Jumper - dark blue/off white , Lace-up heels - cognac\\",\\"1, 1\\",\\"ZO0653506535, ZO0322303223\\",\\"0, 0\\",\\"20.984, 65\\",\\"20.984, 65\\",\\"0, 0\\",\\"ZO0653506535, ZO0322303223\\",86,86,2,2,order,mary +bQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Chapman\\",\\"Wilhemina St. Chapman\\",FEMALE,17,Chapman,Chapman,\\"(empty)\\",Saturday,5,\\"wilhemina st.@chapman-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563704,\\"sold_product_563704_21823, sold_product_563704_19078\\",\\"sold_product_563704_21823, sold_product_563704_19078\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"9.656, 8.828\\",\\"20.984, 16.984\\",\\"21,823, 19,078\\",\\"Long sleeved top - peacoat, Print T-shirt - black\\",\\"Long sleeved top - peacoat, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0062700627, ZO0054100541\\",\\"0, 0\\",\\"20.984, 16.984\\",\\"20.984, 16.984\\",\\"0, 0\\",\\"ZO0062700627, ZO0054100541\\",\\"37.969\\",\\"37.969\\",2,2,order,wilhemina +bgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Underwood\\",\\"Elyssa Underwood\\",FEMALE,27,Underwood,Underwood,\\"(empty)\\",Saturday,5,\\"elyssa@underwood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563534,\\"sold_product_563534_18172, sold_product_563534_19097\\",\\"sold_product_563534_18172, sold_product_563534_19097\\",\\"42, 60\\",\\"42, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"22.25, 29.406\\",\\"42, 60\\",\\"18,172, 19,097\\",\\"Boots - black, Ankle boots - camel\\",\\"Boots - black, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0014300143, ZO0249202492\\",\\"0, 0\\",\\"42, 60\\",\\"42, 60\\",\\"0, 0\\",\\"ZO0014300143, ZO0249202492\\",102,102,2,2,order,elyssa +jgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",\\"Men's Accessories, Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Rivera\\",\\"Sultan Al Rivera\\",MALE,19,Rivera,Rivera,\\"(empty)\\",Saturday,5,\\"sultan al@rivera-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",716616,\\"sold_product_716616_11922, sold_product_716616_19741, sold_product_716616_6283, sold_product_716616_6868\\",\\"sold_product_716616_11922, sold_product_716616_19741, sold_product_716616_6283, sold_product_716616_6868\\",\\"18.984, 16.984, 11.992, 42\\",\\"18.984, 16.984, 11.992, 42\\",\\"Men's Accessories, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Men's Accessories, Men's Shoes, Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"Elitelligence, Elitelligence, Elitelligence, Microlutions\\",\\"9.68, 7.988, 6.352, 20.156\\",\\"18.984, 16.984, 11.992, 42\\",\\"11,922, 19,741, 6,283, 6,868\\",\\"Watch - black, Trainers - black, Basic T-shirt - dark blue/white, Bomber Jacket - bordeaux\\",\\"Watch - black, Trainers - black, Basic T-shirt - dark blue/white, Bomber Jacket - bordeaux\\",\\"1, 1, 1, 1\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\",\\"0, 0, 0, 0\\",\\"18.984, 16.984, 11.992, 42\\",\\"18.984, 16.984, 11.992, 42\\",\\"0, 0, 0, 0\\",\\"ZO0601506015, ZO0507505075, ZO0549605496, ZO0114701147\\",\\"89.938\\",\\"89.938\\",4,4,order,sultan +oQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jason,Jason,\\"Jason Rice\\",\\"Jason Rice\\",MALE,16,Rice,Rice,\\"(empty)\\",Saturday,5,\\"jason@rice-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 21, 2019 @ 00:00:00.000\\",563419,\\"sold_product_563419_17629, sold_product_563419_21599\\",\\"sold_product_563419_17629, sold_product_563419_21599\\",\\"24.984, 26.984\\",\\"24.984, 26.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12.992, 13.492\\",\\"24.984, 26.984\\",\\"17,629, 21,599\\",\\"Tracksuit bottoms - mottled grey, Jumper - black\\",\\"Tracksuit bottoms - mottled grey, Jumper - black\\",\\"1, 1\\",\\"ZO0528605286, ZO0578505785\\",\\"0, 0\\",\\"24.984, 26.984\\",\\"24.984, 26.984\\",\\"0, 0\\",\\"ZO0528605286, ZO0578505785\\",\\"51.969\\",\\"51.969\\",2,2,order,jason +ogMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Wise\\",\\"Elyssa Wise\\",FEMALE,27,Wise,Wise,\\"(empty)\\",Saturday,5,\\"elyssa@wise-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563468,\\"sold_product_563468_18486, sold_product_563468_18903\\",\\"sold_product_563468_18486, sold_product_563468_18903\\",\\"100, 26.984\\",\\"100, 26.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Spherecords Curvy\\",\\"Gnomehouse, Spherecords Curvy\\",\\"46, 13.758\\",\\"100, 26.984\\",\\"18,486, 18,903\\",\\"Over-the-knee boots - black, Shirt - white\\",\\"Over-the-knee boots - black, Shirt - white\\",\\"1, 1\\",\\"ZO0324003240, ZO0711107111\\",\\"0, 0\\",\\"100, 26.984\\",\\"100, 26.984\\",\\"0, 0\\",\\"ZO0324003240, ZO0711107111\\",127,127,2,2,order,elyssa +owMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mcdonald\\",\\"Rabbia Al Mcdonald\\",FEMALE,5,Mcdonald,Mcdonald,\\"(empty)\\",Saturday,5,\\"rabbia al@mcdonald-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563496,\\"sold_product_563496_19888, sold_product_563496_15294\\",\\"sold_product_563496_19888, sold_product_563496_15294\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"51, 9.68\\",\\"100, 18.984\\",\\"19,888, 15,294\\",\\"Classic coat - camel, Across body bag - cognac\\",\\"Classic coat - camel, Across body bag - cognac\\",\\"1, 1\\",\\"ZO0354103541, ZO0196101961\\",\\"0, 0\\",\\"100, 18.984\\",\\"100, 18.984\\",\\"0, 0\\",\\"ZO0354103541, ZO0196101961\\",119,119,2,2,order,rabbia +3QMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Gilbert\\",\\"Yasmine Gilbert\\",FEMALE,43,Gilbert,Gilbert,\\"(empty)\\",Saturday,5,\\"yasmine@gilbert-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563829,\\"sold_product_563829_18348, sold_product_563829_22842\\",\\"sold_product_563829_18348, sold_product_563829_22842\\",\\"50, 50\\",\\"50, 50\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"26.484, 26.984\\",\\"50, 50\\",\\"18,348, 22,842\\",\\"Summer dress - apple butter, Beaded Occasion Dress\\",\\"Summer dress - apple butter, Beaded Occasion Dress\\",\\"1, 1\\",\\"ZO0335103351, ZO0043000430\\",\\"0, 0\\",\\"50, 50\\",\\"50, 50\\",\\"0, 0\\",\\"ZO0335103351, ZO0043000430\\",100,100,2,2,order,yasmine +3gMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Selena,Selena,\\"Selena Wells\\",\\"Selena Wells\\",FEMALE,42,Wells,Wells,\\"(empty)\\",Saturday,5,\\"selena@wells-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563888,\\"sold_product_563888_24162, sold_product_563888_20172\\",\\"sold_product_563888_24162, sold_product_563888_20172\\",\\"24.984, 21.984\\",\\"24.984, 21.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.242, 11.648\\",\\"24.984, 21.984\\",\\"24,162, 20,172\\",\\"Rucksack - cognac, Nightie - dark green\\",\\"Rucksack - cognac, Nightie - dark green\\",\\"1, 1\\",\\"ZO0090400904, ZO0100501005\\",\\"0, 0\\",\\"24.984, 21.984\\",\\"24.984, 21.984\\",\\"0, 0\\",\\"ZO0090400904, ZO0100501005\\",\\"46.969\\",\\"46.969\\",2,2,order,selena +\\"-QMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Hodges\\",\\"Pia Hodges\\",FEMALE,45,Hodges,Hodges,\\"(empty)\\",Saturday,5,\\"pia@hodges-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563037,\\"sold_product_563037_20079, sold_product_563037_11032\\",\\"sold_product_563037_20079, sold_product_563037_11032\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"12, 38.25\\",\\"24.984, 75\\",\\"20,079, 11,032\\",\\"Vest - black, Parka - mottled grey\\",\\"Vest - black, Parka - mottled grey\\",\\"1, 1\\",\\"ZO0172801728, ZO0115701157\\",\\"0, 0\\",\\"24.984, 75\\",\\"24.984, 75\\",\\"0, 0\\",\\"ZO0172801728, ZO0115701157\\",100,100,2,2,order,pia +\\"-gMtOW0BH63Xcmy453H9\\",ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Brewer\\",\\"Mostafa Brewer\\",MALE,9,Brewer,Brewer,\\"(empty)\\",Saturday,5,\\"mostafa@brewer-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563105,\\"sold_product_563105_23911, sold_product_563105_15250\\",\\"sold_product_563105_23911, sold_product_563105_15250\\",\\"6.988, 33\\",\\"6.988, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"3.5, 18.141\\",\\"6.988, 33\\",\\"23,911, 15,250\\",\\"Basic T-shirt - black, Shirt - beige\\",\\"Basic T-shirt - black, Shirt - beige\\",\\"1, 1\\",\\"ZO0562205622, ZO0110901109\\",\\"0, 0\\",\\"6.988, 33\\",\\"6.988, 33\\",\\"0, 0\\",\\"ZO0562205622, ZO0110901109\\",\\"39.969\\",\\"39.969\\",2,2,order,mostafa +ZwMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Rose\\",\\"Wilhemina St. Rose\\",FEMALE,17,Rose,Rose,\\"(empty)\\",Saturday,5,\\"wilhemina st.@rose-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563066,\\"sold_product_563066_18616, sold_product_563066_17298\\",\\"sold_product_563066_18616, sold_product_563066_17298\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"36.75, 9.344\\",\\"75, 16.984\\",\\"18,616, 17,298\\",\\"Boots - brown, Across body bag - turquoise\\",\\"Boots - brown, Across body bag - turquoise\\",\\"1, 1\\",\\"ZO0373503735, ZO0206902069\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0373503735, ZO0206902069\\",92,92,2,2,order,wilhemina +aAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine King\\",\\"Yasmine King\\",FEMALE,43,King,King,\\"(empty)\\",Saturday,5,\\"yasmine@king-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 21, 2019 @ 00:00:00.000\\",563113,\\"sold_product_563113_13234, sold_product_563113_18481\\",\\"sold_product_563113_13234, sold_product_563113_18481\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 10, 2016 @ 00:00:00.000, Dec 10, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"17.156, 13.242\\",\\"33, 24.984\\",\\"13,234, 18,481\\",\\"Jersey dress - red ochre, Jersey dress - dark red\\",\\"Jersey dress - red ochre, Jersey dress - dark red\\",\\"1, 1\\",\\"ZO0333903339, ZO0151801518\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0333903339, ZO0151801518\\",\\"57.969\\",\\"57.969\\",2,2,order,yasmine +\\"_QMtOW0BH63Xcmy432DJ\\",ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Parker\\",\\"Wilhemina St. Parker\\",FEMALE,17,Parker,Parker,\\"(empty)\\",Friday,4,\\"wilhemina st.@parker-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562351,\\"sold_product_562351_18495, sold_product_562351_22598\\",\\"sold_product_562351_18495, sold_product_562351_22598\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"25, 14.781\\",\\"50, 28.984\\",\\"18,495, 22,598\\",\\"Ankle boots - cognac, Shift dress - black\\",\\"Ankle boots - cognac, Shift dress - black\\",\\"1, 1\\",\\"ZO0376403764, ZO0050800508\\",\\"0, 0\\",\\"50, 28.984\\",\\"50, 28.984\\",\\"0, 0\\",\\"ZO0376403764, ZO0050800508\\",79,79,2,2,order,wilhemina +WwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Graham\\",\\"Gwen Graham\\",FEMALE,26,Graham,Graham,\\"(empty)\\",Friday,4,\\"gwen@graham-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561666,\\"sold_product_561666_24242, sold_product_561666_16817\\",\\"sold_product_561666_24242, sold_product_561666_16817\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"17.813, 10.25\\",\\"33, 18.984\\",\\"24,242, 16,817\\",\\"Jersey dress - black/white, Long sleeved top - black\\",\\"Jersey dress - black/white, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0042600426, ZO0166401664\\",\\"0, 0\\",\\"33, 18.984\\",\\"33, 18.984\\",\\"0, 0\\",\\"ZO0042600426, ZO0166401664\\",\\"51.969\\",\\"51.969\\",2,2,order,gwen +XAMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Porter\\",\\"Rabbia Al Porter\\",FEMALE,5,Porter,Porter,\\"(empty)\\",Friday,4,\\"rabbia al@porter-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561236,\\"sold_product_561236_23790, sold_product_561236_19511\\",\\"sold_product_561236_23790, sold_product_561236_19511\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"14.492, 8.656\\",\\"28.984, 16.984\\",\\"23,790, 19,511\\",\\"Jumper - peacoat, Nightie - black\\",\\"Jumper - peacoat, Nightie - black\\",\\"1, 1\\",\\"ZO0072700727, ZO0101001010\\",\\"0, 0\\",\\"28.984, 16.984\\",\\"28.984, 16.984\\",\\"0, 0\\",\\"ZO0072700727, ZO0101001010\\",\\"45.969\\",\\"45.969\\",2,2,order,rabbia +XQMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Shaw\\",\\"Hicham Shaw\\",MALE,8,Shaw,Shaw,\\"(empty)\\",Friday,4,\\"hicham@shaw-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561290,\\"sold_product_561290_1694, sold_product_561290_15025\\",\\"sold_product_561290_1694, sold_product_561290_15025\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"38.25, 12.992\\",\\"75, 24.984\\",\\"1,694, 15,025\\",\\"Slip-ons - Midnight Blue, Jumper - black\\",\\"Slip-ons - Midnight Blue, Jumper - black\\",\\"1, 1\\",\\"ZO0255702557, ZO0577605776\\",\\"0, 0\\",\\"75, 24.984\\",\\"75, 24.984\\",\\"0, 0\\",\\"ZO0255702557, ZO0577605776\\",100,100,2,2,order,hicham +XgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Washington\\",\\"Abd Washington\\",MALE,52,Washington,Washington,\\"(empty)\\",Friday,4,\\"abd@washington-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561739,\\"sold_product_561739_16553, sold_product_561739_14242\\",\\"sold_product_561739_16553, sold_product_561739_14242\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"12, 11.75\\",\\"24.984, 24.984\\",\\"16,553, 14,242\\",\\"Straight leg jeans - blue denim, Jeans Tapered Fit - black denim \\",\\"Straight leg jeans - blue denim, Jeans Tapered Fit - black denim \\",\\"1, 1\\",\\"ZO0537805378, ZO0538005380\\",\\"0, 0\\",\\"24.984, 24.984\\",\\"24.984, 24.984\\",\\"0, 0\\",\\"ZO0537805378, ZO0538005380\\",\\"49.969\\",\\"49.969\\",2,2,order,abd +XwMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tran\\",\\"Rabbia Al Tran\\",FEMALE,5,Tran,Tran,\\"(empty)\\",Friday,4,\\"rabbia al@tran-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561786,\\"sold_product_561786_12183, sold_product_561786_15264\\",\\"sold_product_561786_12183, sold_product_561786_15264\\",\\"25.984, 29.984\\",\\"25.984, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"13.508, 14.102\\",\\"25.984, 29.984\\",\\"12,183, 15,264\\",\\"Blouse - navy, Cardigan - black/anthrazit \\",\\"Blouse - navy, Cardigan - black/anthrazit \\",\\"1, 1\\",\\"ZO0064100641, ZO0068600686\\",\\"0, 0\\",\\"25.984, 29.984\\",\\"25.984, 29.984\\",\\"0, 0\\",\\"ZO0064100641, ZO0068600686\\",\\"55.969\\",\\"55.969\\",2,2,order,rabbia +hgMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Diane,Diane,\\"Diane Willis\\",\\"Diane Willis\\",FEMALE,22,Willis,Willis,\\"(empty)\\",Friday,4,\\"diane@willis-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562400,\\"sold_product_562400_16415, sold_product_562400_5857\\",\\"sold_product_562400_16415, sold_product_562400_5857\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Low Tide Media\\",\\"Tigress Enterprises, Low Tide Media\\",\\"8.156, 23.5\\",\\"16.984, 50\\",\\"16,415, 5,857\\",\\"Across body bag - black, Ankle boots - cognac\\",\\"Across body bag - black, Ankle boots - cognac\\",\\"1, 1\\",\\"ZO0094200942, ZO0376603766\\",\\"0, 0\\",\\"16.984, 50\\",\\"16.984, 50\\",\\"0, 0\\",\\"ZO0094200942, ZO0376603766\\",67,67,2,2,order,diane +1gMtOW0BH63Xcmy432HJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Weber\\",\\"Elyssa Weber\\",FEMALE,27,Weber,Weber,\\"(empty)\\",Friday,4,\\"elyssa@weber-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562352,\\"sold_product_562352_19189, sold_product_562352_8284\\",\\"sold_product_562352_19189, sold_product_562352_8284\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"13.344, 16.813\\",\\"28.984, 33\\",\\"19,189, 8,284\\",\\"Blouse - black, Shirt - soft pink nude\\",\\"Blouse - black, Shirt - soft pink nude\\",\\"1, 1\\",\\"ZO0265302653, ZO0348203482\\",\\"0, 0\\",\\"28.984, 33\\",\\"28.984, 33\\",\\"0, 0\\",\\"ZO0265302653, ZO0348203482\\",\\"61.969\\",\\"61.969\\",2,2,order,elyssa +BwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Garza\\",\\"Jackson Garza\\",MALE,13,Garza,Garza,\\"(empty)\\",Friday,4,\\"jackson@garza-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561343,\\"sold_product_561343_23977, sold_product_561343_19776\\",\\"sold_product_561343_23977, sold_product_561343_19776\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"30.547, 5.5\\",\\"65, 10.992\\",\\"23,977, 19,776\\",\\"Waterproof trousers - pumpkin spice, Print T-shirt - white\\",\\"Waterproof trousers - pumpkin spice, Print T-shirt - white\\",\\"1, 1\\",\\"ZO0620706207, ZO0566705667\\",\\"0, 0\\",\\"65, 10.992\\",\\"65, 10.992\\",\\"0, 0\\",\\"ZO0620706207, ZO0566705667\\",76,76,2,2,order,jackson +VQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Lewis\\",\\"Elyssa Lewis\\",FEMALE,27,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"elyssa@lewis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561543,\\"sold_product_561543_13132, sold_product_561543_19621\\",\\"sold_product_561543_13132, sold_product_561543_19621\\",\\"42, 34\\",\\"42, 34\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"Tigress Enterprises Curvy, Pyramidustries\\",\\"22.672, 17.328\\",\\"42, 34\\",\\"13,132, 19,621\\",\\"Blazer - black, Waterproof jacket - black\\",\\"Blazer - black, Waterproof jacket - black\\",\\"1, 1\\",\\"ZO0106701067, ZO0175101751\\",\\"0, 0\\",\\"42, 34\\",\\"42, 34\\",\\"0, 0\\",\\"ZO0106701067, ZO0175101751\\",76,76,2,2,order,elyssa +VgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Davidson\\",\\"Fitzgerald Davidson\\",MALE,11,Davidson,Davidson,\\"(empty)\\",Friday,4,\\"fitzgerald@davidson-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561577,\\"sold_product_561577_15263, sold_product_561577_6820\\",\\"sold_product_561577_15263, sold_product_561577_6820\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"15.844, 12.992\\",\\"33, 24.984\\",\\"15,263, 6,820\\",\\"Briefcase - brown, Cardigan - dark blue\\",\\"Briefcase - brown, Cardigan - dark blue\\",\\"1, 1\\",\\"ZO0604406044, ZO0296302963\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0604406044, ZO0296302963\\",\\"57.969\\",\\"57.969\\",2,2,order,fuzzy +WQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Barnes\\",\\"Abd Barnes\\",MALE,52,Barnes,Barnes,\\"(empty)\\",Friday,4,\\"abd@barnes-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561429,\\"sold_product_561429_1791, sold_product_561429_3467\\",\\"sold_product_561429_1791, sold_product_561429_3467\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"14.852, 13.922\\",\\"33, 28.984\\",\\"1,791, 3,467\\",\\"Lace-up boots - green, Tights - black\\",\\"Lace-up boots - green, Tights - black\\",\\"1, 1\\",\\"ZO0511405114, ZO0621506215\\",\\"0, 0\\",\\"33, 28.984\\",\\"33, 28.984\\",\\"0, 0\\",\\"ZO0511405114, ZO0621506215\\",\\"61.969\\",\\"61.969\\",2,2,order,abd +egMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Pia,Pia,\\"Pia Willis\\",\\"Pia Willis\\",FEMALE,45,Willis,Willis,\\"(empty)\\",Friday,4,\\"pia@willis-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562050,\\"sold_product_562050_14157, sold_product_562050_19227\\",\\"sold_product_562050_14157, sold_product_562050_19227\\",\\"50, 90\\",\\"50, 90\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Low Tide Media\\",\\"Gnomehouse, Low Tide Media\\",\\"24.5, 44.094\\",\\"50, 90\\",\\"14,157, 19,227\\",\\"Classic heels - black, Boots - cognac\\",\\"Classic heels - black, Boots - cognac\\",\\"1, 1\\",\\"ZO0322103221, ZO0373903739\\",\\"0, 0\\",\\"50, 90\\",\\"50, 90\\",\\"0, 0\\",\\"ZO0322103221, ZO0373903739\\",140,140,2,2,order,pia +ewMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Jim,Jim,\\"Jim Chandler\\",\\"Jim Chandler\\",MALE,41,Chandler,Chandler,\\"(empty)\\",Friday,4,\\"jim@chandler-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562101,\\"sold_product_562101_24315, sold_product_562101_11349\\",\\"sold_product_562101_24315, sold_product_562101_11349\\",\\"33, 42\\",\\"33, 42\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"16.813, 21.406\\",\\"33, 42\\",\\"24,315, 11,349\\",\\"Weekend bag - navy/brown, Summer jacket - black\\",\\"Weekend bag - navy/brown, Summer jacket - black\\",\\"1, 1\\",\\"ZO0468804688, ZO0285502855\\",\\"0, 0\\",\\"33, 42\\",\\"33, 42\\",\\"0, 0\\",\\"ZO0468804688, ZO0285502855\\",75,75,2,2,order,jim +fAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,Betty,Betty,\\"Betty Salazar\\",\\"Betty Salazar\\",FEMALE,44,Salazar,Salazar,\\"(empty)\\",Friday,4,\\"betty@salazar-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Angeldale,Angeldale,\\"Jun 20, 2019 @ 00:00:00.000\\",562247,\\"sold_product_562247_14495, sold_product_562247_5292\\",\\"sold_product_562247_14495, sold_product_562247_5292\\",\\"70, 85\\",\\"70, 85\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Angeldale\\",\\"Angeldale, Angeldale\\",\\"34.313, 43.344\\",\\"70, 85\\",\\"14,495, 5,292\\",\\"Classic Heels with Straps, Ankle boots - camel\\",\\"Classic Heels with Straps, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0666206662, ZO0673206732\\",\\"0, 0\\",\\"70, 85\\",\\"70, 85\\",\\"0, 0\\",\\"ZO0666206662, ZO0673206732\\",155,155,2,2,order,betty +fQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Ball\\",\\"Robbie Ball\\",MALE,48,Ball,Ball,\\"(empty)\\",Friday,4,\\"robbie@ball-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562285,\\"sold_product_562285_15123, sold_product_562285_21357\\",\\"sold_product_562285_15123, sold_product_562285_21357\\",\\"10.992, 9.992\\",\\"10.992, 9.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.93, 4.699\\",\\"10.992, 9.992\\",\\"15,123, 21,357\\",\\"Print T-shirt - black, Basic T-shirt - white\\",\\"Print T-shirt - black, Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0618306183, ZO0563105631\\",\\"0, 0\\",\\"10.992, 9.992\\",\\"10.992, 9.992\\",\\"0, 0\\",\\"ZO0618306183, ZO0563105631\\",\\"20.984\\",\\"20.984\\",2,2,order,robbie +ugMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Dawson\\",\\"Betty Dawson\\",FEMALE,44,Dawson,Dawson,\\"(empty)\\",Friday,4,\\"betty@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561965,\\"sold_product_561965_8728, sold_product_561965_24101\\",\\"sold_product_561965_8728, sold_product_561965_24101\\",\\"65, 42\\",\\"65, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Gnomehouse\\",\\"Spherecords, Gnomehouse\\",\\"35.094, 18.906\\",\\"65, 42\\",\\"8,728, 24,101\\",\\"Jumper - dark red, Jersey dress - jester red\\",\\"Jumper - dark red, Jersey dress - jester red\\",\\"1, 1\\",\\"ZO0655806558, ZO0334503345\\",\\"0, 0\\",\\"65, 42\\",\\"65, 42\\",\\"0, 0\\",\\"ZO0655806558, ZO0334503345\\",107,107,2,2,order,betty +uwMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Hart\\",\\"Sonya Hart\\",FEMALE,28,Hart,Hart,\\"(empty)\\",Friday,4,\\"sonya@hart-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562008,\\"sold_product_562008_21990, sold_product_562008_22639\\",\\"sold_product_562008_21990, sold_product_562008_22639\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Crystal Lighting\\",\\"Spherecords, Crystal Lighting\\",\\"15.844, 11.25\\",\\"33, 24.984\\",\\"21,990, 22,639\\",\\"Blazer - black, Wool jumper - white\\",\\"Blazer - black, Wool jumper - white\\",\\"1, 1\\",\\"ZO0657006570, ZO0485604856\\",\\"0, 0\\",\\"33, 24.984\\",\\"33, 24.984\\",\\"0, 0\\",\\"ZO0657006570, ZO0485604856\\",\\"57.969\\",\\"57.969\\",2,2,order,sonya +wAMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Simmons\\",\\"Sultan Al Simmons\\",MALE,19,Simmons,Simmons,\\"(empty)\\",Friday,4,\\"sultan al@simmons-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561472,\\"sold_product_561472_12840, sold_product_561472_24625\\",\\"sold_product_561472_12840, sold_product_561472_24625\\",\\"65, 13.992\\",\\"65, 13.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"30.547, 6.301\\",\\"65, 13.992\\",\\"12,840, 24,625\\",\\"Lace-up boots - black, Print T-shirt - dark blue multicolor\\",\\"Lace-up boots - black, Print T-shirt - dark blue multicolor\\",\\"1, 1\\",\\"ZO0399703997, ZO0439904399\\",\\"0, 0\\",\\"65, 13.992\\",\\"65, 13.992\\",\\"0, 0\\",\\"ZO0399703997, ZO0439904399\\",79,79,2,2,order,sultan +wQMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Carr\\",\\"Abdulraheem Al Carr\\",MALE,33,Carr,Carr,\\"(empty)\\",Friday,4,\\"abdulraheem al@carr-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561490,\\"sold_product_561490_12150, sold_product_561490_20378\\",\\"sold_product_561490_12150, sold_product_561490_20378\\",\\"50, 8.992\\",\\"50, 8.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Elitelligence\\",\\"Angeldale, Elitelligence\\",\\"22.5, 4.23\\",\\"50, 8.992\\",\\"12,150, 20,378\\",\\"Casual lace-ups - dark brown , Basic T-shirt - white\\",\\"Casual lace-ups - dark brown , Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0681306813, ZO0545705457\\",\\"0, 0\\",\\"50, 8.992\\",\\"50, 8.992\\",\\"0, 0\\",\\"ZO0681306813, ZO0545705457\\",\\"58.969\\",\\"58.969\\",2,2,order,abdulraheem +wgMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Allison\\",\\"Selena Allison\\",FEMALE,42,Allison,Allison,\\"(empty)\\",Friday,4,\\"selena@allison-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561317,\\"sold_product_561317_20991, sold_product_561317_22586\\",\\"sold_product_561317_20991, sold_product_561317_22586\\",\\"42, 33\\",\\"42, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"21.828, 16.172\\",\\"42, 33\\",\\"20,991, 22,586\\",\\"Mini skirt - navy blazer, Cardigan - navy/brown\\",\\"Mini skirt - navy blazer, Cardigan - navy/brown\\",\\"1, 1\\",\\"ZO0329303293, ZO0074000740\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0329303293, ZO0074000740\\",75,75,2,2,order,selena +0gMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Thad,Thad,\\"Thad Walters\\",\\"Thad Walters\\",MALE,30,Walters,Walters,\\"(empty)\\",Friday,4,\\"thad@walters-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562424,\\"sold_product_562424_11737, sold_product_562424_13228\\",\\"sold_product_562424_11737, sold_product_562424_13228\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"9.867, 11.5\\",\\"20.984, 24.984\\",\\"11,737, 13,228\\",\\"Sweatshirt - dark blue, Jumper - dark blue multicolor\\",\\"Sweatshirt - dark blue, Jumper - dark blue multicolor\\",\\"1, 1\\",\\"ZO0581705817, ZO0448804488\\",\\"0, 0\\",\\"20.984, 24.984\\",\\"20.984, 24.984\\",\\"0, 0\\",\\"ZO0581705817, ZO0448804488\\",\\"45.969\\",\\"45.969\\",2,2,order,thad +0wMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Potter\\",\\"Sultan Al Potter\\",MALE,19,Potter,Potter,\\"(empty)\\",Friday,4,\\"sultan al@potter-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562473,\\"sold_product_562473_13192, sold_product_562473_21203\\",\\"sold_product_562473_13192, sold_product_562473_21203\\",\\"85, 75\\",\\"85, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"39.094, 36.75\\",\\"85, 75\\",\\"13,192, 21,203\\",\\"Parka - navy, Winter jacket - dark blue\\",\\"Parka - navy, Winter jacket - dark blue\\",\\"1, 1\\",\\"ZO0289202892, ZO0432304323\\",\\"0, 0\\",\\"85, 75\\",\\"85, 75\\",\\"0, 0\\",\\"ZO0289202892, ZO0432304323\\",160,160,2,2,order,sultan +1AMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Jimenez\\",\\"Hicham Jimenez\\",MALE,8,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"hicham@jimenez-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562488,\\"sold_product_562488_13297, sold_product_562488_13138\\",\\"sold_product_562488_13297, sold_product_562488_13138\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"32.375, 13.492\\",\\"60, 24.984\\",\\"13,297, 13,138\\",\\"Light jacket - navy, Jumper - black\\",\\"Light jacket - navy, Jumper - black\\",\\"1, 1\\",\\"ZO0275202752, ZO0574405744\\",\\"0, 0\\",\\"60, 24.984\\",\\"60, 24.984\\",\\"0, 0\\",\\"ZO0275202752, ZO0574405744\\",85,85,2,2,order,hicham +1QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri Richards\\",\\"Yuri Richards\\",MALE,21,Richards,Richards,\\"(empty)\\",Friday,4,\\"yuri@richards-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562118,\\"sold_product_562118_18280, sold_product_562118_15033\\",\\"sold_product_562118_18280, sold_product_562118_15033\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"7.82, 13.492\\",\\"16.984, 24.984\\",\\"18,280, 15,033\\",\\"Tights - black, Hoodie - mottled grey\\",\\"Tights - black, Hoodie - mottled grey\\",\\"1, 1\\",\\"ZO0622406224, ZO0591405914\\",\\"0, 0\\",\\"16.984, 24.984\\",\\"16.984, 24.984\\",\\"0, 0\\",\\"ZO0622406224, ZO0591405914\\",\\"41.969\\",\\"41.969\\",2,2,order,yuri +1gMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Padilla\\",\\"Yasmine Padilla\\",FEMALE,43,Padilla,Padilla,\\"(empty)\\",Friday,4,\\"yasmine@padilla-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Crystal Lighting, Spherecords\\",\\"Crystal Lighting, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562159,\\"sold_product_562159_8592, sold_product_562159_19303\\",\\"sold_product_562159_8592, sold_product_562159_19303\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Crystal Lighting, Spherecords\\",\\"Crystal Lighting, Spherecords\\",\\"11.25, 5.488\\",\\"24.984, 9.992\\",\\"8,592, 19,303\\",\\"Wool jumper - pink, 5 PACK - Trainer socks - black\\",\\"Wool jumper - pink, 5 PACK - Trainer socks - black\\",\\"1, 1\\",\\"ZO0485704857, ZO0662006620\\",\\"0, 0\\",\\"24.984, 9.992\\",\\"24.984, 9.992\\",\\"0, 0\\",\\"ZO0485704857, ZO0662006620\\",\\"34.969\\",\\"34.969\\",2,2,order,yasmine +1wMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Mcdonald\\",\\"Robbie Mcdonald\\",MALE,48,Mcdonald,Mcdonald,\\"(empty)\\",Friday,4,\\"robbie@mcdonald-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"(empty)\\",\\"(empty)\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562198,\\"sold_product_562198_12308, sold_product_562198_12830\\",\\"sold_product_562198_12308, sold_product_562198_12830\\",\\"155, 155\\",\\"155, 155\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"(empty), (empty)\\",\\"(empty), (empty)\\",\\"72.875, 72.875\\",\\"155, 155\\",\\"12,308, 12,830\\",\\"Smart slip-ons - brown, Lace-ups - black\\",\\"Smart slip-ons - brown, Lace-ups - black\\",\\"1, 1\\",\\"ZO0482504825, ZO0481304813\\",\\"0, 0\\",\\"155, 155\\",\\"155, 155\\",\\"0, 0\\",\\"ZO0482504825, ZO0481304813\\",310,310,2,2,order,robbie +2QMtOW0BH63Xcmy44WJv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Betty,Betty,\\"Betty Frank\\",\\"Betty Frank\\",FEMALE,44,Frank,Frank,\\"(empty)\\",Friday,4,\\"betty@frank-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562523,\\"sold_product_562523_11110, sold_product_562523_20613\\",\\"sold_product_562523_11110, sold_product_562523_20613\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"15.359, 11.5\\",\\"28.984, 24.984\\",\\"11,110, 20,613\\",\\"Tracksuit top - black, Watch - silver-coloured\\",\\"Tracksuit top - black, Watch - silver-coloured\\",\\"1, 1\\",\\"ZO0178001780, ZO0078400784\\",\\"0, 0\\",\\"28.984, 24.984\\",\\"28.984, 24.984\\",\\"0, 0\\",\\"ZO0178001780, ZO0078400784\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +lwMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Valdez\\",\\"Youssef Valdez\\",MALE,31,Valdez,Valdez,\\"(empty)\\",Friday,4,\\"youssef@valdez-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561373,\\"sold_product_561373_20306, sold_product_561373_18262\\",\\"sold_product_561373_20306, sold_product_561373_18262\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.52, 10.703\\",\\"11.992, 20.984\\",\\"20,306, 18,262\\",\\"Long sleeved top - mottled dark grey, Chinos - khaki\\",\\"Long sleeved top - mottled dark grey, Chinos - khaki\\",\\"1, 1\\",\\"ZO0563905639, ZO0528805288\\",\\"0, 0\\",\\"11.992, 20.984\\",\\"11.992, 20.984\\",\\"0, 0\\",\\"ZO0563905639, ZO0528805288\\",\\"32.969\\",\\"32.969\\",2,2,order,youssef +mAMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jason,Jason,\\"Jason Webb\\",\\"Jason Webb\\",MALE,16,Webb,Webb,\\"(empty)\\",Friday,4,\\"jason@webb-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561409,\\"sold_product_561409_1438, sold_product_561409_15672\\",\\"sold_product_561409_1438, sold_product_561409_15672\\",\\"60, 65\\",\\"60, 65\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spritechnologies\\",\\"Oceanavigations, Spritechnologies\\",\\"32.375, 33.125\\",\\"60, 65\\",\\"1,438, 15,672\\",\\"Trainers - black, Waterproof jacket - black\\",\\"Trainers - black, Waterproof jacket - black\\",\\"1, 1\\",\\"ZO0254702547, ZO0626306263\\",\\"0, 0\\",\\"60, 65\\",\\"60, 65\\",\\"0, 0\\",\\"ZO0254702547, ZO0626306263\\",125,125,2,2,order,jason +mQMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Stephanie,Stephanie,\\"Stephanie Munoz\\",\\"Stephanie Munoz\\",FEMALE,6,Munoz,Munoz,\\"(empty)\\",Friday,4,\\"stephanie@munoz-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561858,\\"sold_product_561858_22426, sold_product_561858_12672\\",\\"sold_product_561858_22426, sold_product_561858_12672\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"Tigress Enterprises Curvy, Low Tide Media\\",\\"13.742, 16.813\\",\\"24.984, 33\\",\\"22,426, 12,672\\",\\"Print T-shirt - Chocolate, Ballet pumps - black\\",\\"Print T-shirt - Chocolate, Ballet pumps - black\\",\\"1, 1\\",\\"ZO0105301053, ZO0364803648\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0105301053, ZO0364803648\\",\\"57.969\\",\\"57.969\\",2,2,order,stephanie +mgMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Marshall\\",\\"Fitzgerald Marshall\\",MALE,11,Marshall,Marshall,\\"(empty)\\",Friday,4,\\"fitzgerald@marshall-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561904,\\"sold_product_561904_15204, sold_product_561904_12074\\",\\"sold_product_561904_15204, sold_product_561904_12074\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"21.406, 5.641\\",\\"42, 11.992\\",\\"15,204, 12,074\\",\\"Weekend bag - black, Polo shirt - blue\\",\\"Weekend bag - black, Polo shirt - blue\\",\\"1, 1\\",\\"ZO0315303153, ZO0441904419\\",\\"0, 0\\",\\"42, 11.992\\",\\"42, 11.992\\",\\"0, 0\\",\\"ZO0315303153, ZO0441904419\\",\\"53.969\\",\\"53.969\\",2,2,order,fuzzy +9QMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Tran\\",\\"Betty Tran\\",FEMALE,44,Tran,Tran,\\"(empty)\\",Friday,4,\\"betty@tran-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561381,\\"sold_product_561381_16065, sold_product_561381_20409\\",\\"sold_product_561381_16065, sold_product_561381_20409\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"Tigress Enterprises MAMA, Tigress Enterprises Curvy\\",\\"10.289, 15.844\\",\\"20.984, 33\\",\\"16,065, 20,409\\",\\"Vest - rose/black, Cardigan - black/offwhite\\",\\"Vest - rose/black, Cardigan - black/offwhite\\",\\"1, 1\\",\\"ZO0231202312, ZO0106401064\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0231202312, ZO0106401064\\",\\"53.969\\",\\"53.969\\",2,2,order,betty +9gMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Nash\\",\\"Abd Nash\\",MALE,52,Nash,Nash,\\"(empty)\\",Friday,4,\\"abd@nash-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561830,\\"sold_product_561830_15032, sold_product_561830_12189\\",\\"sold_product_561830_15032, sold_product_561830_12189\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"13.922, 7.199\\",\\"28.984, 14.992\\",\\"15,032, 12,189\\",\\"Sweatshirt - mottled grey, Tracksuit bottoms - mottled grey\\",\\"Sweatshirt - mottled grey, Tracksuit bottoms - mottled grey\\",\\"1, 1\\",\\"ZO0591105911, ZO0532805328\\",\\"0, 0\\",\\"28.984, 14.992\\",\\"28.984, 14.992\\",\\"0, 0\\",\\"ZO0591105911, ZO0532805328\\",\\"43.969\\",\\"43.969\\",2,2,order,abd +9wMtOW0BH63Xcmy44WNv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Wagdi,Wagdi,\\"Wagdi Gomez\\",\\"Wagdi Gomez\\",MALE,15,Gomez,Gomez,\\"(empty)\\",Friday,4,\\"wagdi@gomez-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561878,\\"sold_product_561878_17804, sold_product_561878_17209\\",\\"sold_product_561878_17804, sold_product_561878_17209\\",\\"12.992, 50\\",\\"12.992, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"6.5, 26.484\\",\\"12.992, 50\\",\\"17,804, 17,209\\",\\"Long sleeved top - mottled dark grey, Casual lace-ups - grey\\",\\"Long sleeved top - mottled dark grey, Casual lace-ups - grey\\",\\"1, 1\\",\\"ZO0562905629, ZO0388303883\\",\\"0, 0\\",\\"12.992, 50\\",\\"12.992, 50\\",\\"0, 0\\",\\"ZO0562905629, ZO0388303883\\",\\"62.969\\",\\"62.969\\",2,2,order,wagdi +\\"-AMtOW0BH63Xcmy44WNv\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Baker\\",\\"Stephanie Baker\\",FEMALE,6,Baker,Baker,\\"(empty)\\",Friday,4,\\"stephanie@baker-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561916,\\"sold_product_561916_15403, sold_product_561916_11041\\",\\"sold_product_561916_15403, sold_product_561916_11041\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"10.703, 7.27\\",\\"20.984, 13.992\\",\\"15,403, 11,041\\",\\"Sweatshirt - dark grey multicolor, Basic T-shirt - dark grey multicolor\\",\\"Sweatshirt - dark grey multicolor, Basic T-shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0180101801, ZO0157101571\\",\\"0, 0\\",\\"20.984, 13.992\\",\\"20.984, 13.992\\",\\"0, 0\\",\\"ZO0180101801, ZO0157101571\\",\\"34.969\\",\\"34.969\\",2,2,order,stephanie +HQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Recip,Recip,\\"Recip Shaw\\",\\"Recip Shaw\\",MALE,10,Shaw,Shaw,\\"(empty)\\",Friday,4,\\"recip@shaw-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562324,\\"sold_product_562324_20112, sold_product_562324_12375\\",\\"sold_product_562324_20112, sold_product_562324_12375\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"12.477, 10.289\\",\\"25.984, 20.984\\",\\"20,112, 12,375\\",\\"Shirt - blue, Trainers - red\\",\\"Shirt - blue, Trainers - red\\",\\"1, 1\\",\\"ZO0413604136, ZO0509005090\\",\\"0, 0\\",\\"25.984, 20.984\\",\\"25.984, 20.984\\",\\"0, 0\\",\\"ZO0413604136, ZO0509005090\\",\\"46.969\\",\\"46.969\\",2,2,order,recip +HgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Sonya,Sonya,\\"Sonya Ruiz\\",\\"Sonya Ruiz\\",FEMALE,28,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"sonya@ruiz-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562367,\\"sold_product_562367_19018, sold_product_562367_15868\\",\\"sold_product_562367_19018, sold_product_562367_15868\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"19.734, 5.711\\",\\"42, 10.992\\",\\"19,018, 15,868\\",\\"High heeled sandals - red, Scarf - black/white\\",\\"High heeled sandals - red, Scarf - black/white\\",\\"1, 1\\",\\"ZO0371803718, ZO0195401954\\",\\"0, 0\\",\\"42, 10.992\\",\\"42, 10.992\\",\\"0, 0\\",\\"ZO0371803718, ZO0195401954\\",\\"52.969\\",\\"52.969\\",2,2,order,sonya +UwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Ryan\\",\\"Wilhemina St. Ryan\\",FEMALE,17,Ryan,Ryan,\\"(empty)\\",Friday,4,\\"wilhemina st.@ryan-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",729673,\\"sold_product_729673_23755, sold_product_729673_23467, sold_product_729673_15159, sold_product_729673_5415\\",\\"sold_product_729673_23755, sold_product_729673_23467, sold_product_729673_15159, sold_product_729673_5415\\",\\"50, 60, 24.984, 65\\",\\"50, 60, 24.984, 65\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Shoes\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"Oceanavigations, Tigress Enterprises, Pyramidustries, Angeldale\\",\\"23, 31.188, 11.75, 31.844\\",\\"50, 60, 24.984, 65\\",\\"23,755, 23,467, 15,159, 5,415\\",\\"Cardigan - blue & white, Lohan - Maxi dress - silver/black, High heels - blue, Lace-ups - grey\\",\\"Cardigan - blue & white, Lohan - Maxi dress - silver/black, High heels - blue, Lace-ups - grey\\",\\"1, 1, 1, 1\\",\\"ZO0268202682, ZO0048200482, ZO0134801348, ZO0668406684\\",\\"0, 0, 0, 0\\",\\"50, 60, 24.984, 65\\",\\"50, 60, 24.984, 65\\",\\"0, 0, 0, 0\\",\\"ZO0268202682, ZO0048200482, ZO0134801348, ZO0668406684\\",200,200,4,4,order,wilhemina +rQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Ruiz\\",\\"Rabbia Al Ruiz\\",FEMALE,5,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"rabbia al@ruiz-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises MAMA\\",\\"Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561953,\\"sold_product_561953_22114, sold_product_561953_19225\\",\\"sold_product_561953_22114, sold_product_561953_19225\\",\\"29.984, 22.984\\",\\"29.984, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises MAMA, Tigress Enterprises MAMA\\",\\"Tigress Enterprises MAMA, Tigress Enterprises MAMA\\",\\"15.891, 11.273\\",\\"29.984, 22.984\\",\\"22,114, 19,225\\",\\"Blouse - black/white, Blouse - black\\",\\"Blouse - black/white, Blouse - black\\",\\"1, 1\\",\\"ZO0232002320, ZO0231402314\\",\\"0, 0\\",\\"29.984, 22.984\\",\\"29.984, 22.984\\",\\"0, 0\\",\\"ZO0232002320, ZO0231402314\\",\\"52.969\\",\\"52.969\\",2,2,order,rabbia +rgMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,rania,rania,\\"rania Brady\\",\\"rania Brady\\",FEMALE,24,Brady,Brady,\\"(empty)\\",Friday,4,\\"rania@brady-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561997,\\"sold_product_561997_16402, sold_product_561997_12822\\",\\"sold_product_561997_16402, sold_product_561997_12822\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"17.484, 7.82\\",\\"33, 16.984\\",\\"16,402, 12,822\\",\\"Shirt - navy blazer, Platform sandals - navy\\",\\"Shirt - navy blazer, Platform sandals - navy\\",\\"1, 1\\",\\"ZO0346203462, ZO0010700107\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0346203462, ZO0010700107\\",\\"49.969\\",\\"49.969\\",2,2,order,rani +rwMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",EUR,Gwen,Gwen,\\"Gwen Butler\\",\\"Gwen Butler\\",FEMALE,26,Butler,Butler,\\"(empty)\\",Friday,4,\\"gwen@butler-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561534,\\"sold_product_561534_25055, sold_product_561534_15461\\",\\"sold_product_561534_25055, sold_product_561534_15461\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"Women's Shoes, Women's Accessories\\",\\"Women's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"23, 8.492\\",\\"50, 16.984\\",\\"25,055, 15,461\\",\\"Ankle boots - Dodger Blue, Across body bag - black \\",\\"Ankle boots - Dodger Blue, Across body bag - black \\",\\"1, 1\\",\\"ZO0380303803, ZO0211902119\\",\\"0, 0\\",\\"50, 16.984\\",\\"50, 16.984\\",\\"0, 0\\",\\"ZO0380303803, ZO0211902119\\",67,67,2,2,order,gwen +sQMtOW0BH63Xcmy44WRv,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Wagdi,Wagdi,\\"Wagdi Graham\\",\\"Wagdi Graham\\",MALE,15,Graham,Graham,\\"(empty)\\",Friday,4,\\"wagdi@graham-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",561632,\\"sold_product_561632_19048, sold_product_561632_15628\\",\\"sold_product_561632_19048, sold_product_561632_15628\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"5.93, 10.078\\",\\"10.992, 20.984\\",\\"19,048, 15,628\\",\\"Long sleeved top - lt grey/dk grey , Watch - brown\\",\\"Long sleeved top - lt grey/dk grey , Watch - brown\\",\\"1, 1\\",\\"ZO0546605466, ZO0600906009\\",\\"0, 0\\",\\"10.992, 20.984\\",\\"10.992, 20.984\\",\\"0, 0\\",\\"ZO0546605466, ZO0600906009\\",\\"31.984\\",\\"31.984\\",2,2,order,wagdi +DwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Romero\\",\\"Mostafa Romero\\",MALE,9,Romero,Romero,\\"(empty)\\",Friday,4,\\"mostafa@romero-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561676,\\"sold_product_561676_1702, sold_product_561676_11429\\",\\"sold_product_561676_1702, sold_product_561676_11429\\",\\"25.984, 10.992\\",\\"25.984, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Spritechnologies\\",\\"Elitelligence, Spritechnologies\\",\\"12.219, 5.391\\",\\"25.984, 10.992\\",\\"1,702, 11,429\\",\\"Trainers - black/grey, Swimming shorts - lime punch\\",\\"Trainers - black/grey, Swimming shorts - lime punch\\",\\"1, 1\\",\\"ZO0512705127, ZO0629406294\\",\\"0, 0\\",\\"25.984, 10.992\\",\\"25.984, 10.992\\",\\"0, 0\\",\\"ZO0512705127, ZO0629406294\\",\\"36.969\\",\\"36.969\\",2,2,order,mostafa +EAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Estrada\\",\\"Abdulraheem Al Estrada\\",MALE,33,Estrada,Estrada,\\"(empty)\\",Friday,4,\\"abdulraheem al@estrada-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561218,\\"sold_product_561218_14074, sold_product_561218_12696\\",\\"sold_product_561218_14074, sold_product_561218_12696\\",\\"60, 75\\",\\"60, 75\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"27.594, 36.75\\",\\"60, 75\\",\\"14,074, 12,696\\",\\"Suit jacket - dark blue, Briefcase - brandy\\",\\"Suit jacket - dark blue, Briefcase - brandy\\",\\"1, 1\\",\\"ZO0409604096, ZO0466904669\\",\\"0, 0\\",\\"60, 75\\",\\"60, 75\\",\\"0, 0\\",\\"ZO0409604096, ZO0466904669\\",135,135,2,2,order,abdulraheem +EQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Diane,Diane,\\"Diane Reese\\",\\"Diane Reese\\",FEMALE,22,Reese,Reese,\\"(empty)\\",Friday,4,\\"diane@reese-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561256,\\"sold_product_561256_23086, sold_product_561256_16589\\",\\"sold_product_561256_23086, sold_product_561256_16589\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"12.742, 8.492\\",\\"24.984, 16.984\\",\\"23,086, 16,589\\",\\"Jersey dress - black, Long sleeved top - black\\",\\"Jersey dress - black, Long sleeved top - black\\",\\"1, 1\\",\\"ZO0151601516, ZO0162901629\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0151601516, ZO0162901629\\",\\"41.969\\",\\"41.969\\",2,2,order,diane +EgMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Rivera\\",\\"Jackson Rivera\\",MALE,13,Rivera,Rivera,\\"(empty)\\",Friday,4,\\"jackson@rivera-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561311,\\"sold_product_561311_22466, sold_product_561311_13378\\",\\"sold_product_561311_22466, sold_product_561311_13378\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"10.703, 24.5\\",\\"20.984, 50\\",\\"22,466, 13,378\\",\\"Sweatshirt - black , Casual lace-ups - cognac\\",\\"Sweatshirt - black , Casual lace-ups - cognac\\",\\"1, 1\\",\\"ZO0458604586, ZO0391603916\\",\\"0, 0\\",\\"20.984, 50\\",\\"20.984, 50\\",\\"0, 0\\",\\"ZO0458604586, ZO0391603916\\",71,71,2,2,order,jackson +EwMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Mccarthy\\",\\"Wilhemina St. Mccarthy\\",FEMALE,17,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"wilhemina st.@mccarthy-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561781,\\"sold_product_561781_5453, sold_product_561781_15437\\",\\"sold_product_561781_5453, sold_product_561781_15437\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"26.984, 18.141\\",\\"50, 33\\",\\"5,453, 15,437\\",\\"Slip-ons - Midnight Blue, Summer dress - black\\",\\"Slip-ons - Midnight Blue, Summer dress - black\\",\\"1, 1\\",\\"ZO0235402354, ZO0048700487\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0235402354, ZO0048700487\\",83,83,2,2,order,wilhemina +ewMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Kamal,Kamal,\\"Kamal Garza\\",\\"Kamal Garza\\",MALE,39,Garza,Garza,\\"(empty)\\",Friday,4,\\"kamal@garza-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561375,\\"sold_product_561375_2773, sold_product_561375_18549\\",\\"sold_product_561375_2773, sold_product_561375_18549\\",\\"85, 24.984\\",\\"85, 24.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"39.094, 11.5\\",\\"85, 24.984\\",\\"2,773, 18,549\\",\\"Winter jacket - black, Trousers - dark blue\\",\\"Winter jacket - black, Trousers - dark blue\\",\\"1, 1\\",\\"ZO0115201152, ZO0420404204\\",\\"0, 0\\",\\"85, 24.984\\",\\"85, 24.984\\",\\"0, 0\\",\\"ZO0115201152, ZO0420404204\\",110,110,2,2,order,kamal +fAMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Brigitte,Brigitte,\\"Brigitte Simpson\\",\\"Brigitte Simpson\\",FEMALE,12,Simpson,Simpson,\\"(empty)\\",Friday,4,\\"brigitte@simpson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561876,\\"sold_product_561876_11067, sold_product_561876_20664\\",\\"sold_product_561876_11067, sold_product_561876_20664\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"7.27, 14.781\\",\\"13.992, 28.984\\",\\"11,067, 20,664\\",\\"Print T-shirt - black/turquoise, Trainers - navy/black\\",\\"Print T-shirt - black/turquoise, Trainers - navy/black\\",\\"1, 1\\",\\"ZO0170301703, ZO0027000270\\",\\"0, 0\\",\\"13.992, 28.984\\",\\"13.992, 28.984\\",\\"0, 0\\",\\"ZO0170301703, ZO0027000270\\",\\"42.969\\",\\"42.969\\",2,2,order,brigitte +fQMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Chapman\\",\\"Betty Chapman\\",FEMALE,44,Chapman,Chapman,\\"(empty)\\",Friday,4,\\"betty@chapman-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561633,\\"sold_product_561633_23859, sold_product_561633_7687\\",\\"sold_product_561633_23859, sold_product_561633_7687\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"8.328, 6.719\\",\\"16.984, 13.992\\",\\"23,859, 7,687\\",\\"Long sleeved top - berry, Print T-shirt - black\\",\\"Long sleeved top - berry, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0165001650, ZO0159001590\\",\\"0, 0\\",\\"16.984, 13.992\\",\\"16.984, 13.992\\",\\"0, 0\\",\\"ZO0165001650, ZO0159001590\\",\\"30.984\\",\\"30.984\\",2,2,order,betty +4wMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Wood\\",\\"Elyssa Wood\\",FEMALE,27,Wood,Wood,\\"(empty)\\",Friday,4,\\"elyssa@wood-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562323,\\"sold_product_562323_17653, sold_product_562323_25172\\",\\"sold_product_562323_17653, sold_product_562323_25172\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Spherecords\\",\\"Oceanavigations, Spherecords\\",\\"31.844, 11.539\\",\\"65, 20.984\\",\\"17,653, 25,172\\",\\"Classic heels - blush, Blouse - black\\",\\"Classic heels - blush, Blouse - black\\",\\"1, 1\\",\\"ZO0238502385, ZO0650406504\\",\\"0, 0\\",\\"65, 20.984\\",\\"65, 20.984\\",\\"0, 0\\",\\"ZO0238502385, ZO0650406504\\",86,86,2,2,order,elyssa +5AMtOW0BH63Xcmy44mWR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Elyssa,Elyssa,\\"Elyssa Nash\\",\\"Elyssa Nash\\",FEMALE,27,Nash,Nash,\\"(empty)\\",Friday,4,\\"elyssa@nash-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562358,\\"sold_product_562358_15777, sold_product_562358_20699\\",\\"sold_product_562358_15777, sold_product_562358_20699\\",\\"60, 18.984\\",\\"60, 18.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Tigress Enterprises\\",\\"Gnomehouse, Tigress Enterprises\\",\\"33, 9.68\\",\\"60, 18.984\\",\\"15,777, 20,699\\",\\"Summer dress - Lemon Chiffon, Watch - black\\",\\"Summer dress - Lemon Chiffon, Watch - black\\",\\"1, 1\\",\\"ZO0337303373, ZO0079600796\\",\\"0, 0\\",\\"60, 18.984\\",\\"60, 18.984\\",\\"0, 0\\",\\"ZO0337303373, ZO0079600796\\",79,79,2,2,order,elyssa +DwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",\\"Men's Clothing, Men's Shoes, Men's Accessories\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Bryan\\",\\"Sultan Al Bryan\\",MALE,19,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"sultan al@bryan-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",718360,\\"sold_product_718360_16955, sold_product_718360_20827, sold_product_718360_14564, sold_product_718360_21672\\",\\"sold_product_718360_16955, sold_product_718360_20827, sold_product_718360_14564, sold_product_718360_21672\\",\\"200, 165, 10.992, 16.984\\",\\"200, 165, 10.992, 16.984\\",\\"Men's Clothing, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Men's Clothing, Men's Shoes, Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, (empty), Low Tide Media, Low Tide Media\\",\\"Oceanavigations, (empty), Low Tide Media, Low Tide Media\\",\\"92, 85.813, 4.949, 9\\",\\"200, 165, 10.992, 16.984\\",\\"16,955, 20,827, 14,564, 21,672\\",\\"Classic coat - navy, Boots - black, Hat - light grey multicolor, Polo shirt - black multicolor\\",\\"Classic coat - navy, Boots - black, Hat - light grey multicolor, Polo shirt - black multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\",\\"0, 0, 0, 0\\",\\"200, 165, 10.992, 16.984\\",\\"200, 165, 10.992, 16.984\\",\\"0, 0, 0, 0\\",\\"ZO0291402914, ZO0483804838, ZO0460304603, ZO0443904439\\",393,393,4,4,order,sultan +JgMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Rowe\\",\\"Jim Rowe\\",MALE,41,Rowe,Rowe,\\"(empty)\\",Friday,4,\\"jim@rowe-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561969,\\"sold_product_561969_1737, sold_product_561969_14073\\",\\"sold_product_561969_1737, sold_product_561969_14073\\",\\"42, 33\\",\\"42, 33\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"18.906, 17.156\\",\\"42, 33\\",\\"1,737, 14,073\\",\\"Lace-up boots - brown, Briefcase - brown \\",\\"Lace-up boots - brown, Briefcase - brown \\",\\"1, 1\\",\\"ZO0521205212, ZO0316003160\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0521205212, ZO0316003160\\",75,75,2,2,order,jim +JwMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Garza\\",\\"Mary Garza\\",FEMALE,20,Garza,Garza,\\"(empty)\\",Friday,4,\\"mary@garza-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562011,\\"sold_product_562011_7816, sold_product_562011_13449\\",\\"sold_product_562011_7816, sold_product_562011_13449\\",\\"33, 75\\",\\"33, 75\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"16.5, 37.5\\",\\"33, 75\\",\\"7,816, 13,449\\",\\"Cardigan - Sky Blue, Ankle boots - black\\",\\"Cardigan - Sky Blue, Ankle boots - black\\",\\"1, 1\\",\\"ZO0068200682, ZO0245202452\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0068200682, ZO0245202452\\",108,108,2,2,order,mary +oAMtOW0BH63Xcmy44maR,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Accessories, Men's Shoes\\",EUR,Eddie,Eddie,\\"Eddie Hodges\\",\\"Eddie Hodges\\",MALE,38,Hodges,Hodges,\\"(empty)\\",Friday,4,\\"eddie@hodges-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Microlutions, Low Tide Media, Angeldale\\",\\"Microlutions, Low Tide Media, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719185,\\"sold_product_719185_18940, sold_product_719185_24924, sold_product_719185_20248, sold_product_719185_24003\\",\\"sold_product_719185_18940, sold_product_719185_24924, sold_product_719185_20248, sold_product_719185_24003\\",\\"14.992, 10.992, 60, 100\\",\\"14.992, 10.992, 60, 100\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Low Tide Media, Low Tide Media, Angeldale\\",\\"Microlutions, Low Tide Media, Low Tide Media, Angeldale\\",\\"7.352, 5.711, 33, 47\\",\\"14.992, 10.992, 60, 100\\",\\"18,940, 24,924, 20,248, 24,003\\",\\"Basic T-shirt - marshmallow, Print T-shirt - navy, Across body bag - black, Lace-ups - Midnight Blue\\",\\"Basic T-shirt - marshmallow, Print T-shirt - navy, Across body bag - black, Lace-ups - Midnight Blue\\",\\"1, 1, 1, 1\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\",\\"0, 0, 0, 0\\",\\"14.992, 10.992, 60, 100\\",\\"14.992, 10.992, 60, 100\\",\\"0, 0, 0, 0\\",\\"ZO0118601186, ZO0438904389, ZO0468004680, ZO0684106841\\",186,186,4,4,order,eddie +rQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Evans\\",\\"Selena Evans\\",FEMALE,42,Evans,Evans,\\"(empty)\\",Friday,4,\\"selena@evans-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561669,\\"sold_product_561669_11107, sold_product_561669_19052\\",\\"sold_product_561669_11107, sold_product_561669_19052\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"11.117, 7.051\\",\\"20.984, 14.992\\",\\"11,107, 19,052\\",\\"Pyjamas - grey/pink , 2 PACK - Basic T-shirt - black/white\\",\\"Pyjamas - grey/pink , 2 PACK - Basic T-shirt - black/white\\",\\"1, 1\\",\\"ZO0100001000, ZO0642406424\\",\\"0, 0\\",\\"20.984, 14.992\\",\\"20.984, 14.992\\",\\"0, 0\\",\\"ZO0100001000, ZO0642406424\\",\\"35.969\\",\\"35.969\\",2,2,order,selena +rgMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Wood\\",\\"Wilhemina St. Wood\\",FEMALE,17,Wood,Wood,\\"(empty)\\",Friday,4,\\"wilhemina st.@wood-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561225,\\"sold_product_561225_16493, sold_product_561225_13770\\",\\"sold_product_561225_16493, sold_product_561225_13770\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"Spherecords, Tigress Enterprises Curvy\\",\\"12.492, 22.672\\",\\"24.984, 42\\",\\"16,493, 13,770\\",\\"Dressing gown - pale pink, Summer dress - peacoat\\",\\"Dressing gown - pale pink, Summer dress - peacoat\\",\\"1, 1\\",\\"ZO0660906609, ZO0102801028\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0660906609, ZO0102801028\\",67,67,2,2,order,wilhemina +rwMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Hampton\\",\\"Abigail Hampton\\",FEMALE,46,Hampton,Hampton,\\"(empty)\\",Friday,4,\\"abigail@hampton-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561284,\\"sold_product_561284_13751, sold_product_561284_24729\\",\\"sold_product_561284_13751, sold_product_561284_24729\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"11.5, 8.156\\",\\"24.984, 16.984\\",\\"13,751, 24,729\\",\\"Rucksack - black, Vest - black\\",\\"Rucksack - black, Vest - black\\",\\"1, 1\\",\\"ZO0086300863, ZO0171901719\\",\\"0, 0\\",\\"24.984, 16.984\\",\\"24.984, 16.984\\",\\"0, 0\\",\\"ZO0086300863, ZO0171901719\\",\\"41.969\\",\\"41.969\\",2,2,order,abigail +sAMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Rodriguez\\",\\"Gwen Rodriguez\\",FEMALE,26,Rodriguez,Rodriguez,\\"(empty)\\",Friday,4,\\"gwen@rodriguez-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561735,\\"sold_product_561735_15452, sold_product_561735_17692\\",\\"sold_product_561735_15452, sold_product_561735_17692\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"17.813, 9.656\\",\\"33, 20.984\\",\\"15,452, 17,692\\",\\"High heels - black, Long sleeved top - peacoat\\",\\"High heels - black, Long sleeved top - peacoat\\",\\"1, 1\\",\\"ZO0006300063, ZO0058400584\\",\\"0, 0\\",\\"33, 20.984\\",\\"33, 20.984\\",\\"0, 0\\",\\"ZO0006300063, ZO0058400584\\",\\"53.969\\",\\"53.969\\",2,2,order,gwen +sQMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Abd,Abd,\\"Abd Fleming\\",\\"Abd Fleming\\",MALE,52,Fleming,Fleming,\\"(empty)\\",Friday,4,\\"abd@fleming-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561798,\\"sold_product_561798_23272, sold_product_561798_19140\\",\\"sold_product_561798_23272, sold_product_561798_19140\\",\\"100, 24.984\\",\\"100, 24.984\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"54, 13.742\\",\\"100, 24.984\\",\\"23,272, 19,140\\",\\"Lace-ups - bianco, Across body bag - black/dark brown\\",\\"Lace-ups - bianco, Across body bag - black/dark brown\\",\\"1, 1\\",\\"ZO0684006840, ZO0469104691\\",\\"0, 0\\",\\"100, 24.984\\",\\"100, 24.984\\",\\"0, 0\\",\\"ZO0684006840, ZO0469104691\\",125,125,2,2,order,abd +3QMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Morrison\\",\\"Elyssa Morrison\\",FEMALE,27,Morrison,Morrison,\\"(empty)\\",Friday,4,\\"elyssa@morrison-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562047,\\"sold_product_562047_19148, sold_product_562047_11032\\",\\"sold_product_562047_19148, sold_product_562047_11032\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Microlutions\\",\\"Pyramidustries, Microlutions\\",\\"6.109, 38.25\\",\\"11.992, 75\\",\\"19,148, 11,032\\",\\"Clutch - black, Parka - mottled grey\\",\\"Clutch - black, Parka - mottled grey\\",\\"1, 1\\",\\"ZO0203102031, ZO0115701157\\",\\"0, 0\\",\\"11.992, 75\\",\\"11.992, 75\\",\\"0, 0\\",\\"ZO0203102031, ZO0115701157\\",87,87,2,2,order,elyssa +3gMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Muniz,Muniz,\\"Muniz Reese\\",\\"Muniz Reese\\",MALE,37,Reese,Reese,\\"(empty)\\",Friday,4,\\"muniz@reese-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562107,\\"sold_product_562107_18292, sold_product_562107_23258\\",\\"sold_product_562107_18292, sold_product_562107_23258\\",\\"100, 20.984\\",\\"100, 20.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"52, 10.289\\",\\"100, 20.984\\",\\"18,292, 23,258\\",\\"Snowboard jacket - mottled grey, Jumper - grey/dark blue\\",\\"Snowboard jacket - mottled grey, Jumper - grey/dark blue\\",\\"1, 1\\",\\"ZO0624806248, ZO0579405794\\",\\"0, 0\\",\\"100, 20.984\\",\\"100, 20.984\\",\\"0, 0\\",\\"ZO0624806248, ZO0579405794\\",121,121,2,2,order,muniz +3wMtOW0BH63Xcmy442bU,ecommerce,\\"-\\",\\"Men's Shoes\\",\\"Men's Shoes\\",EUR,Samir,Samir,\\"Samir Foster\\",\\"Samir Foster\\",MALE,34,Foster,Foster,\\"(empty)\\",Friday,4,\\"samir@foster-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562290,\\"sold_product_562290_1665, sold_product_562290_24934\\",\\"sold_product_562290_1665, sold_product_562290_24934\\",\\"65, 50\\",\\"65, 50\\",\\"Men's Shoes, Men's Shoes\\",\\"Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"31.203, 22.5\\",\\"65, 50\\",\\"1,665, 24,934\\",\\"Boots - light brown, Lace-up boots - resin coffee\\",\\"Boots - light brown, Lace-up boots - resin coffee\\",\\"1, 1\\",\\"ZO0686106861, ZO0403504035\\",\\"0, 0\\",\\"65, 50\\",\\"65, 50\\",\\"0, 0\\",\\"ZO0686106861, ZO0403504035\\",115,115,2,2,order,samir +PAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Harvey\\",\\"Abd Harvey\\",MALE,52,Harvey,Harvey,\\"(empty)\\",Friday,4,\\"abd@harvey-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",720967,\\"sold_product_720967_24934, sold_product_720967_12278, sold_product_720967_14535, sold_product_720967_17629\\",\\"sold_product_720967_24934, sold_product_720967_12278, sold_product_720967_14535, sold_product_720967_17629\\",\\"50, 11.992, 28.984, 24.984\\",\\"50, 11.992, 28.984, 24.984\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Elitelligence, Elitelligence, Elitelligence\\",\\"Low Tide Media, Elitelligence, Elitelligence, Elitelligence\\",\\"22.5, 6, 13.922, 12.992\\",\\"50, 11.992, 28.984, 24.984\\",\\"24,934, 12,278, 14,535, 17,629\\",\\"Lace-up boots - resin coffee, Print T-shirt - black, Boots - brown, Tracksuit bottoms - mottled grey\\",\\"Lace-up boots - resin coffee, Print T-shirt - black, Boots - brown, Tracksuit bottoms - mottled grey\\",\\"1, 1, 1, 1\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\",\\"0, 0, 0, 0\\",\\"50, 11.992, 28.984, 24.984\\",\\"50, 11.992, 28.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0403504035, ZO0553005530, ZO0519905199, ZO0528605286\\",\\"115.938\\",\\"115.938\\",4,4,order,abd +bQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Nash\\",\\"Fitzgerald Nash\\",MALE,11,Nash,Nash,\\"(empty)\\",Friday,4,\\"fitzgerald@nash-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561564,\\"sold_product_561564_6597, sold_product_561564_12482\\",\\"sold_product_561564_6597, sold_product_561564_12482\\",\\"17.984, 60\\",\\"17.984, 60\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"9.531, 30\\",\\"17.984, 60\\",\\"6,597, 12,482\\",\\"Jumper - dark grey multicolor, Across body bag - black\\",\\"Jumper - dark grey multicolor, Across body bag - black\\",\\"1, 1\\",\\"ZO0451204512, ZO0463804638\\",\\"0, 0\\",\\"17.984, 60\\",\\"17.984, 60\\",\\"0, 0\\",\\"ZO0451204512, ZO0463804638\\",78,78,2,2,order,fuzzy +cAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Hopkins\\",\\"Elyssa Hopkins\\",FEMALE,27,Hopkins,Hopkins,\\"(empty)\\",Friday,4,\\"elyssa@hopkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561444,\\"sold_product_561444_21181, sold_product_561444_11368\\",\\"sold_product_561444_21181, sold_product_561444_11368\\",\\"21.984, 33\\",\\"21.984, 33\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"10.563, 15.18\\",\\"21.984, 33\\",\\"21,181, 11,368\\",\\"Cardigan - beige, Slip-ons - beige \\",\\"Cardigan - beige, Slip-ons - beige \\",\\"1, 1\\",\\"ZO0651806518, ZO0369703697\\",\\"0, 0\\",\\"21.984, 33\\",\\"21.984, 33\\",\\"0, 0\\",\\"ZO0651806518, ZO0369703697\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +cQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Brady\\",\\"Betty Brady\\",FEMALE,44,Brady,Brady,\\"(empty)\\",Friday,4,\\"betty@brady-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561482,\\"sold_product_561482_8985, sold_product_561482_15058\\",\\"sold_product_561482_8985, sold_product_561482_15058\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"27.594, 16.172\\",\\"60, 33\\",\\"8,985, 15,058\\",\\"Light jacket - cognac, Faux leather jacket - pink\\",\\"Light jacket - cognac, Faux leather jacket - pink\\",\\"1, 1\\",\\"ZO0184901849, ZO0174301743\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0184901849, ZO0174301743\\",93,93,2,2,order,betty +jgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Mostafa,Mostafa,\\"Mostafa Hopkins\\",\\"Mostafa Hopkins\\",MALE,9,Hopkins,Hopkins,\\"(empty)\\",Friday,4,\\"mostafa@hopkins-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562456,\\"sold_product_562456_11345, sold_product_562456_15411\\",\\"sold_product_562456_11345, sold_product_562456_15411\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"3.76, 7.82\\",\\"7.988, 16.984\\",\\"11,345, 15,411\\",\\"Tie - grey, Belt - black\\",\\"Tie - grey, Belt - black\\",\\"1, 1\\",\\"ZO0276302763, ZO0701407014\\",\\"0, 0\\",\\"7.988, 16.984\\",\\"7.988, 16.984\\",\\"0, 0\\",\\"ZO0276302763, ZO0701407014\\",\\"24.984\\",\\"24.984\\",2,2,order,mostafa +jwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tyler\\",\\"Rabbia Al Tyler\\",FEMALE,5,Tyler,Tyler,\\"(empty)\\",Friday,4,\\"rabbia al@tyler-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562499,\\"sold_product_562499_5501, sold_product_562499_20439\\",\\"sold_product_562499_5501, sold_product_562499_20439\\",\\"75, 22.984\\",\\"75, 22.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"Oceanavigations, Tigress Enterprises Curvy\\",\\"40.5, 11.492\\",\\"75, 22.984\\",\\"5,501, 20,439\\",\\"Ankle boots - Midnight Blue, Blouse - black\\",\\"Ankle boots - Midnight Blue, Blouse - black\\",\\"1, 1\\",\\"ZO0244802448, ZO0105701057\\",\\"0, 0\\",\\"75, 22.984\\",\\"75, 22.984\\",\\"0, 0\\",\\"ZO0244802448, ZO0105701057\\",98,98,2,2,order,rabbia +kAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Yuri,Yuri,\\"Yuri James\\",\\"Yuri James\\",MALE,21,James,James,\\"(empty)\\",Friday,4,\\"yuri@james-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562152,\\"sold_product_562152_17873, sold_product_562152_19670\\",\\"sold_product_562152_17873, sold_product_562152_19670\\",\\"10.992, 37\\",\\"10.992, 37\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"5.602, 19.594\\",\\"10.992, 37\\",\\"17,873, 19,670\\",\\"Sports shirt - Seashell, Tracksuit top - black\\",\\"Sports shirt - Seashell, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0616606166, ZO0589705897\\",\\"0, 0\\",\\"10.992, 37\\",\\"10.992, 37\\",\\"0, 0\\",\\"ZO0616606166, ZO0589705897\\",\\"47.969\\",\\"47.969\\",2,2,order,yuri +kQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Gibbs\\",\\"Wilhemina St. Gibbs\\",FEMALE,17,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"wilhemina st.@gibbs-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562192,\\"sold_product_562192_18762, sold_product_562192_21085\\",\\"sold_product_562192_18762, sold_product_562192_21085\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"8.656, 7.988\\",\\"16.984, 16.984\\",\\"18,762, 21,085\\",\\"Watch - nude, Vest - black\\",\\"Watch - nude, Vest - black\\",\\"1, 1\\",\\"ZO0079700797, ZO0168201682\\",\\"0, 0\\",\\"16.984, 16.984\\",\\"16.984, 16.984\\",\\"0, 0\\",\\"ZO0079700797, ZO0168201682\\",\\"33.969\\",\\"33.969\\",2,2,order,wilhemina +lAMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Graves\\",\\"Jim Graves\\",MALE,41,Graves,Graves,\\"(empty)\\",Friday,4,\\"jim@graves-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562528,\\"sold_product_562528_11997, sold_product_562528_14014\\",\\"sold_product_562528_11997, sold_product_562528_14014\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"9.172, 20.156\\",\\"16.984, 42\\",\\"11,997, 14,014\\",\\"College - Polo shirt - dark red, Weekend bag - dark brown\\",\\"College - Polo shirt - dark red, Weekend bag - dark brown\\",\\"1, 1\\",\\"ZO0522905229, ZO0608606086\\",\\"0, 0\\",\\"16.984, 42\\",\\"16.984, 42\\",\\"0, 0\\",\\"ZO0522905229, ZO0608606086\\",\\"58.969\\",\\"58.969\\",2,2,order,jim +mgMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Lewis\\",\\"Tariq Lewis\\",MALE,25,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"tariq@lewis-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",715286,\\"sold_product_715286_19758, sold_product_715286_12040, sold_product_715286_3096, sold_product_715286_13247\\",\\"sold_product_715286_19758, sold_product_715286_12040, sold_product_715286_3096, sold_product_715286_13247\\",\\"50, 24.984, 24.984, 11.992\\",\\"50, 24.984, 24.984, 11.992\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Oceanavigations, Low Tide Media, Elitelligence\\",\\"Oceanavigations, Oceanavigations, Low Tide Media, Elitelligence\\",\\"25, 12.492, 11.25, 5.641\\",\\"50, 24.984, 24.984, 11.992\\",\\"19,758, 12,040, 3,096, 13,247\\",\\"Sweatshirt - grey multicolor, Shirt - navy, Jumper - dark blue, Pyjama bottoms - light grey multicolor\\",\\"Sweatshirt - grey multicolor, Shirt - navy, Jumper - dark blue, Pyjama bottoms - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0299802998, ZO0278702787, ZO0448104481, ZO0611906119\\",\\"0, 0, 0, 0\\",\\"50, 24.984, 24.984, 11.992\\",\\"50, 24.984, 24.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0299802998, ZO0278702787, ZO0448104481, ZO0611906119\\",\\"111.938\\",\\"111.938\\",4,4,order,tariq +vQMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Mckenzie\\",\\"Jackson Mckenzie\\",MALE,13,Mckenzie,Mckenzie,\\"(empty)\\",Friday,4,\\"jackson@mckenzie-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561210,\\"sold_product_561210_11019, sold_product_561210_7024\\",\\"sold_product_561210_11019, sold_product_561210_7024\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"16.813, 9\\",\\"33, 16.984\\",\\"11,019, 7,024\\",\\"Sandals - black, 3 PACK - Basic T-shirt - white/black/grey\\",\\"Sandals - black, 3 PACK - Basic T-shirt - white/black/grey\\",\\"1, 1\\",\\"ZO0407404074, ZO0473704737\\",\\"0, 0\\",\\"33, 16.984\\",\\"33, 16.984\\",\\"0, 0\\",\\"ZO0407404074, ZO0473704737\\",\\"49.969\\",\\"49.969\\",2,2,order,jackson +zwMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",EUR,Jim,Jim,\\"Jim Jensen\\",\\"Jim Jensen\\",MALE,41,Jensen,Jensen,\\"(empty)\\",Friday,4,\\"jim@jensen-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562337,\\"sold_product_562337_18692, sold_product_562337_15189\\",\\"sold_product_562337_18692, sold_product_562337_15189\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Men's Shoes, Men's Accessories\\",\\"Men's Shoes, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"12.992, 35.75\\",\\"24.984, 65\\",\\"18,692, 15,189\\",\\"High-top trainers - green, Crossover Strap Bag\\",\\"High-top trainers - green, Crossover Strap Bag\\",\\"1, 1\\",\\"ZO0513005130, ZO0463704637\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0513005130, ZO0463704637\\",90,90,2,2,order,jim +5gMtOW0BH63Xcmy442fU,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Lamb\\",\\"Sultan Al Lamb\\",MALE,19,Lamb,Lamb,\\"(empty)\\",Friday,4,\\"sultan al@lamb-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",713242,\\"sold_product_713242_12836, sold_product_713242_20514, sold_product_713242_19994, sold_product_713242_11377\\",\\"sold_product_713242_12836, sold_product_713242_20514, sold_product_713242_19994, sold_product_713242_11377\\",\\"165, 24.984, 6.988, 10.992\\",\\"165, 24.984, 6.988, 10.992\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Shoes, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"(empty), Elitelligence, Microlutions, Spritechnologies\\",\\"80.875, 11.5, 3.631, 5.711\\",\\"165, 24.984, 6.988, 10.992\\",\\"12,836, 20,514, 19,994, 11,377\\",\\"Lace-ups - brown, Jumper - black, STAY TRUE 2 PACK - Socks - white/grey/black, Swimming shorts - dark red\\",\\"Lace-ups - brown, Jumper - black, STAY TRUE 2 PACK - Socks - white/grey/black, Swimming shorts - dark red\\",\\"1, 1, 1, 1\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\",\\"0, 0, 0, 0\\",\\"165, 24.984, 6.988, 10.992\\",\\"165, 24.984, 6.988, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0482004820, ZO0577105771, ZO0130201302, ZO0629006290\\",208,208,4,4,order,sultan +JQMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Palmer\\",\\"Boris Palmer\\",MALE,36,Palmer,Palmer,\\"(empty)\\",Friday,4,\\"boris@palmer-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561657,\\"sold_product_561657_13024, sold_product_561657_23055\\",\\"sold_product_561657_13024, sold_product_561657_23055\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Oceanavigations\\",\\"Microlutions, Oceanavigations\\",\\"12, 21.828\\",\\"24.984, 42\\",\\"13,024, 23,055\\",\\"Tracksuit bottoms - red, Waistcoat - black\\",\\"Tracksuit bottoms - red, Waistcoat - black\\",\\"1, 1\\",\\"ZO0111701117, ZO0288002880\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0111701117, ZO0288002880\\",67,67,2,2,order,boris +JgMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Mccarthy\\",\\"Elyssa Mccarthy\\",FEMALE,27,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"elyssa@mccarthy-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561254,\\"sold_product_561254_12768, sold_product_561254_20992\\",\\"sold_product_561254_12768, sold_product_561254_20992\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"5.5, 14.211\\",\\"10.992, 28.984\\",\\"12,768, 20,992\\",\\"Snood - nude, Ankle boots - black\\",\\"Snood - nude, Ankle boots - black\\",\\"1, 1\\",\\"ZO0081400814, ZO0022500225\\",\\"0, 0\\",\\"10.992, 28.984\\",\\"10.992, 28.984\\",\\"0, 0\\",\\"ZO0081400814, ZO0022500225\\",\\"39.969\\",\\"39.969\\",2,2,order,elyssa +JwMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Sonya,Sonya,\\"Sonya Jimenez\\",\\"Sonya Jimenez\\",FEMALE,28,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"sonya@jimenez-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561808,\\"sold_product_561808_17597, sold_product_561808_23716\\",\\"sold_product_561808_17597, sold_product_561808_23716\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"7.27, 29.406\\",\\"13.992, 60\\",\\"17,597, 23,716\\",\\"Print T-shirt - rose, Espadrilles - gold\\",\\"Print T-shirt - rose, Espadrilles - gold\\",\\"1, 1\\",\\"ZO0161401614, ZO0670406704\\",\\"0, 0\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"0, 0\\",\\"ZO0161401614, ZO0670406704\\",74,74,2,2,order,sonya +SAMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Baker\\",\\"Abdulraheem Al Baker\\",MALE,33,Baker,Baker,\\"(empty)\\",Friday,4,\\"abdulraheem al@baker-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Microlutions, Spritechnologies\\",\\"Microlutions, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562394,\\"sold_product_562394_11570, sold_product_562394_15124\\",\\"sold_product_562394_11570, sold_product_562394_15124\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Spritechnologies\\",\\"Microlutions, Spritechnologies\\",\\"9.172, 5.5\\",\\"16.984, 10.992\\",\\"11,570, 15,124\\",\\"Print T-shirt - beige, Print T-shirt - dark denim\\",\\"Print T-shirt - beige, Print T-shirt - dark denim\\",\\"1, 1\\",\\"ZO0116701167, ZO0618106181\\",\\"0, 0\\",\\"16.984, 10.992\\",\\"16.984, 10.992\\",\\"0, 0\\",\\"ZO0116701167, ZO0618106181\\",\\"27.984\\",\\"27.984\\",2,2,order,abdulraheem +igMtOW0BH63Xcmy442jU,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Taylor\\",\\"Wilhemina St. Taylor\\",FEMALE,17,Taylor,Taylor,\\"(empty)\\",Friday,4,\\"wilhemina st.@taylor-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",731424,\\"sold_product_731424_18737, sold_product_731424_18573, sold_product_731424_19121, sold_product_731424_11250\\",\\"sold_product_731424_18737, sold_product_731424_18573, sold_product_731424_19121, sold_product_731424_11250\\",\\"65, 11.992, 65, 7.988\\",\\"65, 11.992, 65, 7.988\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"Angeldale, Champion Arts, Gnomehouse, Spherecords\\",\\"31.844, 5.52, 33.781, 3.68\\",\\"65, 11.992, 65, 7.988\\",\\"18,737, 18,573, 19,121, 11,250\\",\\"Lace-ups - black, Print T-shirt - light grey, Ankle boots - khaki, Top - light grey \\",\\"Lace-ups - black, Print T-shirt - light grey, Ankle boots - khaki, Top - light grey \\",\\"1, 1, 1, 1\\",\\"ZO0668706687, ZO0494004940, ZO0326003260, ZO0644206442\\",\\"0, 0, 0, 0\\",\\"65, 11.992, 65, 7.988\\",\\"65, 11.992, 65, 7.988\\",\\"0, 0, 0, 0\\",\\"ZO0668706687, ZO0494004940, ZO0326003260, ZO0644206442\\",150,150,4,4,order,wilhemina +pgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Walters\\",\\"Mary Walters\\",FEMALE,20,Walters,Walters,\\"(empty)\\",Friday,4,\\"mary@walters-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562425,\\"sold_product_562425_22514, sold_product_562425_21356\\",\\"sold_product_562425_22514, sold_product_562425_21356\\",\\"50, 33\\",\\"50, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Tigress Enterprises\\",\\"Low Tide Media, Tigress Enterprises\\",\\"26.984, 16.5\\",\\"50, 33\\",\\"22,514, 21,356\\",\\"Ankle boots - grey, Jersey dress - peacoat\\",\\"Ankle boots - grey, Jersey dress - peacoat\\",\\"1, 1\\",\\"ZO0377603776, ZO0050500505\\",\\"0, 0\\",\\"50, 33\\",\\"50, 33\\",\\"0, 0\\",\\"ZO0377603776, ZO0050500505\\",83,83,2,2,order,mary +pwMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Robert,Robert,\\"Robert Ruiz\\",\\"Robert Ruiz\\",MALE,29,Ruiz,Ruiz,\\"(empty)\\",Friday,4,\\"robert@ruiz-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562464,\\"sold_product_562464_16779, sold_product_562464_24522\\",\\"sold_product_562464_16779, sold_product_562464_24522\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"11.539, 6\\",\\"20.984, 11.992\\",\\"16,779, 24,522\\",\\"Belt - light brown, Long sleeved top - off-white\\",\\"Belt - light brown, Long sleeved top - off-white\\",\\"1, 1\\",\\"ZO0462004620, ZO0568005680\\",\\"0, 0\\",\\"20.984, 11.992\\",\\"20.984, 11.992\\",\\"0, 0\\",\\"ZO0462004620, ZO0568005680\\",\\"32.969\\",\\"32.969\\",2,2,order,robert +qAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Selena,Selena,\\"Selena Bryant\\",\\"Selena Bryant\\",FEMALE,42,Bryant,Bryant,\\"(empty)\\",Friday,4,\\"selena@bryant-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562516,\\"sold_product_562516_23076, sold_product_562516_13345\\",\\"sold_product_562516_23076, sold_product_562516_13345\\",\\"42, 7.988\\",\\"42, 7.988\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Tigress Enterprises\\",\\"Oceanavigations, Tigress Enterprises\\",\\"21, 3.68\\",\\"42, 7.988\\",\\"23,076, 13,345\\",\\"Jeans Skinny Fit - blue, Snood - nude/lilac\\",\\"Jeans Skinny Fit - blue, Snood - nude/lilac\\",\\"1, 1\\",\\"ZO0271102711, ZO0081300813\\",\\"0, 0\\",\\"42, 7.988\\",\\"42, 7.988\\",\\"0, 0\\",\\"ZO0271102711, ZO0081300813\\",\\"49.969\\",\\"49.969\\",2,2,order,selena +qQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Marwan,Marwan,\\"Marwan Webb\\",\\"Marwan Webb\\",MALE,51,Webb,Webb,\\"(empty)\\",Friday,4,\\"marwan@webb-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562161,\\"sold_product_562161_11902, sold_product_562161_24125\\",\\"sold_product_562161_11902, sold_product_562161_24125\\",\\"13.992, 65\\",\\"13.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Angeldale\\",\\"Low Tide Media, Angeldale\\",\\"7.551, 31.203\\",\\"13.992, 65\\",\\"11,902, 24,125\\",\\"3 PACK - Shorts - black, Lace-up boots - black\\",\\"3 PACK - Shorts - black, Lace-up boots - black\\",\\"1, 1\\",\\"ZO0477504775, ZO0694406944\\",\\"0, 0\\",\\"13.992, 65\\",\\"13.992, 65\\",\\"0, 0\\",\\"ZO0477504775, ZO0694406944\\",79,79,2,2,order,marwan +qgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jim,Jim,\\"Jim Dawson\\",\\"Jim Dawson\\",MALE,41,Dawson,Dawson,\\"(empty)\\",Friday,4,\\"jim@dawson-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562211,\\"sold_product_562211_17044, sold_product_562211_19937\\",\\"sold_product_562211_17044, sold_product_562211_19937\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spritechnologies, Elitelligence\\",\\"Spritechnologies, Elitelligence\\",\\"6.039, 4\\",\\"10.992, 7.988\\",\\"17,044, 19,937\\",\\"Sports shirt - bright white, Basic T-shirt - rose\\",\\"Sports shirt - bright white, Basic T-shirt - rose\\",\\"1, 1\\",\\"ZO0616806168, ZO0551805518\\",\\"0, 0\\",\\"10.992, 7.988\\",\\"10.992, 7.988\\",\\"0, 0\\",\\"ZO0616806168, ZO0551805518\\",\\"18.984\\",\\"18.984\\",2,2,order,jim +tAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Selena,Selena,\\"Selena Graham\\",\\"Selena Graham\\",FEMALE,42,Graham,Graham,\\"(empty)\\",Friday,4,\\"selena@graham-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Pyramidustries active, Low Tide Media\\",\\"Pyramidustries active, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561831,\\"sold_product_561831_14088, sold_product_561831_20294\\",\\"sold_product_561831_14088, sold_product_561831_20294\\",\\"33, 60\\",\\"33, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries active, Low Tide Media\\",\\"Pyramidustries active, Low Tide Media\\",\\"16.813, 33\\",\\"33, 60\\",\\"14,088, 20,294\\",\\"Tights - duffle bag , Lace-ups - grey\\",\\"Tights - duffle bag , Lace-ups - grey\\",\\"1, 1\\",\\"ZO0225102251, ZO0368803688\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0225102251, ZO0368803688\\",93,93,2,2,order,selena +tQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Potter\\",\\"Robbie Potter\\",MALE,48,Potter,Potter,\\"(empty)\\",Friday,4,\\"robbie@potter-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561864,\\"sold_product_561864_14054, sold_product_561864_20029\\",\\"sold_product_561864_14054, sold_product_561864_20029\\",\\"75, 85\\",\\"75, 85\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Angeldale\\",\\"Oceanavigations, Angeldale\\",\\"36, 43.344\\",\\"75, 85\\",\\"14,054, 20,029\\",\\"Parka - olive, Lace-up boots - Burly Wood\\",\\"Parka - olive, Lace-up boots - Burly Wood\\",\\"1, 1\\",\\"ZO0287002870, ZO0692206922\\",\\"0, 0\\",\\"75, 85\\",\\"75, 85\\",\\"0, 0\\",\\"ZO0287002870, ZO0692206922\\",160,160,2,2,order,robbie +tgMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Abigail,Abigail,\\"Abigail Austin\\",\\"Abigail Austin\\",FEMALE,46,Austin,Austin,\\"(empty)\\",Friday,4,\\"abigail@austin-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561907,\\"sold_product_561907_17540, sold_product_561907_16988\\",\\"sold_product_561907_17540, sold_product_561907_16988\\",\\"60, 60\\",\\"60, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Gnomehouse\\",\\"Tigress Enterprises, Gnomehouse\\",\\"29.406, 30.594\\",\\"60, 60\\",\\"17,540, 16,988\\",\\"Maxi dress - silver blue, Classic heels - black\\",\\"Maxi dress - silver blue, Classic heels - black\\",\\"1, 1\\",\\"ZO0042300423, ZO0321403214\\",\\"0, 0\\",\\"60, 60\\",\\"60, 60\\",\\"0, 0\\",\\"ZO0042300423, ZO0321403214\\",120,120,2,2,order,abigail +vAMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",EUR,Kamal,Kamal,\\"Kamal Boone\\",\\"Kamal Boone\\",MALE,39,Boone,Boone,\\"(empty)\\",Friday,4,\\"kamal@boone-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561245,\\"sold_product_561245_18213, sold_product_561245_17792\\",\\"sold_product_561245_18213, sold_product_561245_17792\\",\\"10.992, 34\\",\\"10.992, 34\\",\\"Men's Clothing, Men's Accessories\\",\\"Men's Clothing, Men's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"5.711, 16.313\\",\\"10.992, 34\\",\\"18,213, 17,792\\",\\"Print T-shirt - white, Briefcase - brown\\",\\"Print T-shirt - white, Briefcase - brown\\",\\"1, 1\\",\\"ZO0554305543, ZO0468204682\\",\\"0, 0\\",\\"10.992, 34\\",\\"10.992, 34\\",\\"0, 0\\",\\"ZO0554305543, ZO0468204682\\",\\"44.969\\",\\"44.969\\",2,2,order,kamal +vQMtOW0BH63Xcmy45GjD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Rowe\\",\\"Clarice Rowe\\",FEMALE,18,Rowe,Rowe,\\"(empty)\\",Friday,4,\\"clarice@rowe-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561785,\\"sold_product_561785_15024, sold_product_561785_24186\\",\\"sold_product_561785_15024, sold_product_561785_24186\\",\\"60, 33\\",\\"60, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"31.797, 17.813\\",\\"60, 33\\",\\"15,024, 24,186\\",\\"Cocktail dress / Party dress - black, Beaded Occasion Dress\\",\\"Cocktail dress / Party dress - black, Beaded Occasion Dress\\",\\"1, 1\\",\\"ZO0048600486, ZO0155201552\\",\\"0, 0\\",\\"60, 33\\",\\"60, 33\\",\\"0, 0\\",\\"ZO0048600486, ZO0155201552\\",93,93,2,2,order,clarice +YQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Betty,Betty,\\"Betty Harmon\\",\\"Betty Harmon\\",FEMALE,44,Harmon,Harmon,\\"(empty)\\",Friday,4,\\"betty@harmon-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.7)\\",\\"New York\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561505,\\"sold_product_561505_21534, sold_product_561505_20521\\",\\"sold_product_561505_21534, sold_product_561505_20521\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"9.656, 10.703\\",\\"20.984, 20.984\\",\\"21,534, 20,521\\",\\"Vest - black and silver, Hoodie - dark grey multicolor\\",\\"Vest - black and silver, Hoodie - dark grey multicolor\\",\\"1, 1\\",\\"ZO0164001640, ZO0179301793\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0164001640, ZO0179301793\\",\\"41.969\\",\\"41.969\\",2,2,order,betty +agMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,Thad,Thad,\\"Thad Gregory\\",\\"Thad Gregory\\",MALE,30,Gregory,Gregory,\\"(empty)\\",Friday,4,\\"thad@gregory-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562403,\\"sold_product_562403_16259, sold_product_562403_15999\\",\\"sold_product_562403_16259, sold_product_562403_15999\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"21, 11.328\\",\\"42, 20.984\\",\\"16,259, 15,999\\",\\"Weekend bag - dark brown , Shirt - charcoal\\",\\"Weekend bag - dark brown , Shirt - charcoal\\",\\"1, 1\\",\\"ZO0471504715, ZO0524405244\\",\\"0, 0\\",\\"42, 20.984\\",\\"42, 20.984\\",\\"0, 0\\",\\"ZO0471504715, ZO0524405244\\",\\"62.969\\",\\"62.969\\",2,2,order,thad +cQMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq King\\",\\"Tariq King\\",MALE,25,King,King,\\"(empty)\\",Friday,4,\\"tariq@king-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561342,\\"sold_product_561342_16000, sold_product_561342_18188\\",\\"sold_product_561342_16000, sold_product_561342_18188\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.289, 17.484\\",\\"20.984, 33\\",\\"16,000, 18,188\\",\\"Shirt - Medium Slate Blue, Smart lace-ups - cognac\\",\\"Shirt - Medium Slate Blue, Smart lace-ups - cognac\\",\\"1, 1\\",\\"ZO0524505245, ZO0388003880\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0524505245, ZO0388003880\\",\\"53.969\\",\\"53.969\\",2,2,order,tariq +1gMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Pia,Pia,\\"Pia Turner\\",\\"Pia Turner\\",FEMALE,45,Turner,Turner,\\"(empty)\\",Friday,4,\\"pia@turner-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises\\",\\"Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562060,\\"sold_product_562060_15481, sold_product_562060_8432\\",\\"sold_product_562060_15481, sold_product_562060_8432\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Tigress Enterprises\\",\\"15.18, 11.953\\",\\"33, 22.984\\",\\"15,481, 8,432\\",\\"Blazer - creme, Vest - black\\",\\"Blazer - creme, Vest - black\\",\\"1, 1\\",\\"ZO0067300673, ZO0062100621\\",\\"0, 0\\",\\"33, 22.984\\",\\"33, 22.984\\",\\"0, 0\\",\\"ZO0067300673, ZO0062100621\\",\\"55.969\\",\\"55.969\\",2,2,order,pia +1wMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Perkins\\",\\"Abigail Perkins\\",FEMALE,46,Perkins,Perkins,\\"(empty)\\",Friday,4,\\"abigail@perkins-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562094,\\"sold_product_562094_4898, sold_product_562094_20011\\",\\"sold_product_562094_4898, sold_product_562094_20011\\",\\"90, 33\\",\\"90, 33\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Pyramidustries\\",\\"Low Tide Media, Pyramidustries\\",\\"45, 15.844\\",\\"90, 33\\",\\"4,898, 20,011\\",\\"Boots - cognac, Jumpsuit - black\\",\\"Boots - cognac, Jumpsuit - black\\",\\"1, 1\\",\\"ZO0374003740, ZO0146401464\\",\\"0, 0\\",\\"90, 33\\",\\"90, 33\\",\\"0, 0\\",\\"ZO0374003740, ZO0146401464\\",123,123,2,2,order,abigail +2AMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Jenkins\\",\\"Robbie Jenkins\\",MALE,48,Jenkins,Jenkins,\\"(empty)\\",Friday,4,\\"robbie@jenkins-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562236,\\"sold_product_562236_24934, sold_product_562236_14426\\",\\"sold_product_562236_24934, sold_product_562236_14426\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"22.5, 5.82\\",\\"50, 10.992\\",\\"24,934, 14,426\\",\\"Lace-up boots - resin coffee, Print T-shirt - grey multicolor\\",\\"Lace-up boots - resin coffee, Print T-shirt - grey multicolor\\",\\"1, 1\\",\\"ZO0403504035, ZO0438304383\\",\\"0, 0\\",\\"50, 10.992\\",\\"50, 10.992\\",\\"0, 0\\",\\"ZO0403504035, ZO0438304383\\",\\"60.969\\",\\"60.969\\",2,2,order,robbie +2QMtOW0BH63Xcmy45GnD,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Mary,Mary,\\"Mary Kim\\",\\"Mary Kim\\",FEMALE,20,Kim,Kim,\\"(empty)\\",Friday,4,\\"mary@kim-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562304,\\"sold_product_562304_5945, sold_product_562304_22770\\",\\"sold_product_562304_5945, sold_product_562304_22770\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"11.5, 19.734\\",\\"24.984, 42\\",\\"5,945, 22,770\\",\\"Ankle boots - black, Jumper - black/grey\\",\\"Ankle boots - black, Jumper - black/grey\\",\\"1, 1\\",\\"ZO0025000250, ZO0232702327\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0025000250, ZO0232702327\\",67,67,2,2,order,mary +FwMtOW0BH63Xcmy45GrD,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Thad,Thad,\\"Thad Perkins\\",\\"Thad Perkins\\",MALE,30,Perkins,Perkins,\\"(empty)\\",Friday,4,\\"thad@perkins-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562390,\\"sold_product_562390_19623, sold_product_562390_12060\\",\\"sold_product_562390_19623, sold_product_562390_12060\\",\\"33, 50\\",\\"33, 50\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Angeldale\\",\\"Microlutions, Angeldale\\",\\"15.844, 25.984\\",\\"33, 50\\",\\"19,623, 12,060\\",\\"Jumper - navy blazer, Lace-ups - black/red\\",\\"Jumper - navy blazer, Lace-ups - black/red\\",\\"1, 1\\",\\"ZO0121701217, ZO0680806808\\",\\"0, 0\\",\\"33, 50\\",\\"33, 50\\",\\"0, 0\\",\\"ZO0121701217, ZO0680806808\\",83,83,2,2,order,thad +3QMtOW0BH63Xcmy45Wq4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Tariq,Tariq,\\"Tariq Foster\\",\\"Tariq Foster\\",MALE,25,Foster,Foster,\\"(empty)\\",Friday,4,\\"tariq@foster-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Microlutions, Oceanavigations, Low Tide Media\\",\\"Microlutions, Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719041,\\"sold_product_719041_17412, sold_product_719041_17871, sold_product_719041_1720, sold_product_719041_15515\\",\\"sold_product_719041_17412, sold_product_719041_17871, sold_product_719041_1720, sold_product_719041_15515\\",\\"14.992, 14.992, 50, 50\\",\\"14.992, 14.992, 50, 50\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Microlutions, Oceanavigations, Low Tide Media, Oceanavigations\\",\\"Microlutions, Oceanavigations, Low Tide Media, Oceanavigations\\",\\"7.5, 6.898, 24.5, 23\\",\\"14.992, 14.992, 50, 50\\",\\"17,412, 17,871, 1,720, 15,515\\",\\"Print T-shirt - black, Print T-shirt - multicolored, Lace-ups - tan, Light jacket - dark blue\\",\\"Print T-shirt - black, Print T-shirt - multicolored, Lace-ups - tan, Light jacket - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\",\\"0, 0, 0, 0\\",\\"14.992, 14.992, 50, 50\\",\\"14.992, 14.992, 50, 50\\",\\"0, 0, 0, 0\\",\\"ZO0117701177, ZO0292902929, ZO0387403874, ZO0286902869\\",130,130,4,4,order,tariq +IAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Wagdi,Wagdi,\\"Wagdi Lawrence\\",\\"Wagdi Lawrence\\",MALE,15,Lawrence,Lawrence,\\"(empty)\\",Friday,4,\\"wagdi@lawrence-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561604,\\"sold_product_561604_24731, sold_product_561604_19673\\",\\"sold_product_561604_24731, sold_product_561604_19673\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"13.242, 4.148\\",\\"24.984, 7.988\\",\\"24,731, 19,673\\",\\"Tracksuit bottoms - mottled grey, Basic T-shirt - black\\",\\"Tracksuit bottoms - mottled grey, Basic T-shirt - black\\",\\"1, 1\\",\\"ZO0529605296, ZO0435404354\\",\\"0, 0\\",\\"24.984, 7.988\\",\\"24.984, 7.988\\",\\"0, 0\\",\\"ZO0529605296, ZO0435404354\\",\\"32.969\\",\\"32.969\\",2,2,order,wagdi +IwMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Mary,Mary,\\"Mary Fletcher\\",\\"Mary Fletcher\\",FEMALE,20,Fletcher,Fletcher,\\"(empty)\\",Friday,4,\\"mary@fletcher-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561455,\\"sold_product_561455_12855, sold_product_561455_5588\\",\\"sold_product_561455_12855, sold_product_561455_5588\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises\\",\\"14.492, 19.313\\",\\"28.984, 42\\",\\"12,855, 5,588\\",\\"Blazer - weiu00df/rosa, Ankle boots - teak\\",\\"Blazer - weiu00df/rosa, Ankle boots - teak\\",\\"1, 1\\",\\"ZO0182001820, ZO0018500185\\",\\"0, 0\\",\\"28.984, 42\\",\\"28.984, 42\\",\\"0, 0\\",\\"ZO0182001820, ZO0018500185\\",71,71,2,2,order,mary +JAMtOW0BH63Xcmy45Wu4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Robbie,Robbie,\\"Robbie Mccarthy\\",\\"Robbie Mccarthy\\",MALE,48,Mccarthy,Mccarthy,\\"(empty)\\",Friday,4,\\"robbie@mccarthy-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561509,\\"sold_product_561509_18177, sold_product_561509_2401\\",\\"sold_product_561509_18177, sold_product_561509_2401\\",\\"10.992, 65\\",\\"10.992, 65\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"5.82, 33.781\\",\\"10.992, 65\\",\\"18,177, 2,401\\",\\"Print T-shirt - navy, Boots - dark brown\\",\\"Print T-shirt - navy, Boots - dark brown\\",\\"1, 1\\",\\"ZO0438404384, ZO0405504055\\",\\"0, 0\\",\\"10.992, 65\\",\\"10.992, 65\\",\\"0, 0\\",\\"ZO0438404384, ZO0405504055\\",76,76,2,2,order,robbie +ggMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Caldwell\\",\\"Fitzgerald Caldwell\\",MALE,11,Caldwell,Caldwell,\\"(empty)\\",Friday,4,\\"fitzgerald@caldwell-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562439,\\"sold_product_562439_18548, sold_product_562439_23459\\",\\"sold_product_562439_18548, sold_product_562439_23459\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"10.492, 18.141\\",\\"20.984, 33\\",\\"18,548, 23,459\\",\\"Shorts - multicoloured, Smart lace-ups - dark brown\\",\\"Shorts - multicoloured, Smart lace-ups - dark brown\\",\\"1, 1\\",\\"ZO0533105331, ZO0384703847\\",\\"0, 0\\",\\"20.984, 33\\",\\"20.984, 33\\",\\"0, 0\\",\\"ZO0533105331, ZO0384703847\\",\\"53.969\\",\\"53.969\\",2,2,order,fuzzy +gwMtOW0BH63Xcmy45Wy4,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Schultz\\",\\"Wilhemina St. Schultz\\",FEMALE,17,Schultz,Schultz,\\"(empty)\\",Friday,4,\\"wilhemina st.@schultz-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562165,\\"sold_product_562165_12949, sold_product_562165_23197\\",\\"sold_product_562165_12949, sold_product_562165_23197\\",\\"33, 60\\",\\"33, 60\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"15.844, 28.203\\",\\"33, 60\\",\\"12,949, 23,197\\",\\"Summer jacket - dark blue, Maxi dress - eclipse\\",\\"Summer jacket - dark blue, Maxi dress - eclipse\\",\\"1, 1\\",\\"ZO0173701737, ZO0337903379\\",\\"0, 0\\",\\"33, 60\\",\\"33, 60\\",\\"0, 0\\",\\"ZO0173701737, ZO0337903379\\",93,93,2,2,order,wilhemina +2AMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Gibbs\\",\\"Jackson Gibbs\\",MALE,13,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"jackson@gibbs-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719343,\\"sold_product_719343_24169, sold_product_719343_18391, sold_product_719343_20707, sold_product_719343_21209\\",\\"sold_product_719343_24169, sold_product_719343_18391, sold_product_719343_20707, sold_product_719343_21209\\",\\"46, 24.984, 24.984, 65\\",\\"46, 24.984, 24.984, 65\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"Oceanavigations, Elitelligence, Spritechnologies, Angeldale\\",\\"22.078, 12.492, 12.492, 31.203\\",\\"46, 24.984, 24.984, 65\\",\\"24,169, 18,391, 20,707, 21,209\\",\\"Jumper - navy, Tracksuit top - mottled grey, Tracksuit top - black, Boots - sand\\",\\"Jumper - navy, Tracksuit top - mottled grey, Tracksuit top - black, Boots - sand\\",\\"1, 1, 1, 1\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\",\\"0, 0, 0, 0\\",\\"46, 24.984, 24.984, 65\\",\\"46, 24.984, 24.984, 65\\",\\"0, 0, 0, 0\\",\\"ZO0299002990, ZO0584005840, ZO0628406284, ZO0694306943\\",161,161,4,4,order,jackson +2wMtOW0BH63Xcmy45mxS,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Gilbert\\",\\"Abd Gilbert\\",MALE,52,Gilbert,Gilbert,\\"(empty)\\",Friday,4,\\"abd@gilbert-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",718183,\\"sold_product_718183_23834, sold_product_718183_11105, sold_product_718183_22142, sold_product_718183_2361\\",\\"sold_product_718183_23834, sold_product_718183_11105, sold_product_718183_22142, sold_product_718183_2361\\",\\"7.988, 13.992, 24.984, 60\\",\\"7.988, 13.992, 24.984, 60\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Oceanavigations\\",\\"Low Tide Media, Low Tide Media, Oceanavigations, Oceanavigations\\",\\"4.07, 7.27, 11.5, 30\\",\\"7.988, 13.992, 24.984, 60\\",\\"23,834, 11,105, 22,142, 2,361\\",\\"3 PACK - Socks - blue/grey, 3 PACK - Shorts - black, Jeans Skinny Fit - petrol, Lace-up boots - dark brown\\",\\"3 PACK - Socks - blue/grey, 3 PACK - Shorts - black, Jeans Skinny Fit - petrol, Lace-up boots - dark brown\\",\\"1, 1, 1, 1\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\",\\"0, 0, 0, 0\\",\\"7.988, 13.992, 24.984, 60\\",\\"7.988, 13.992, 24.984, 60\\",\\"0, 0, 0, 0\\",\\"ZO0481004810, ZO0476104761, ZO0284102841, ZO0256102561\\",\\"106.938\\",\\"106.938\\",4,4,order,abd +wgMtOW0BH63Xcmy45m1S,ecommerce,\\"-\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",EUR,Pia,Pia,\\"Pia Hayes\\",\\"Pia Hayes\\",FEMALE,45,Hayes,Hayes,\\"(empty)\\",Friday,4,\\"pia@hayes-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561215,\\"sold_product_561215_11054, sold_product_561215_25101\\",\\"sold_product_561215_11054, sold_product_561215_25101\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"Women's Accessories, Women's Shoes\\",\\"Women's Accessories, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Angeldale\\",\\"Pyramidustries, Angeldale\\",\\"10.703, 44.188\\",\\"20.984, 85\\",\\"11,054, 25,101\\",\\"Tote bag - cognac/blue, Ankle boots - Blue Violety\\",\\"Tote bag - cognac/blue, Ankle boots - Blue Violety\\",\\"1, 1\\",\\"ZO0196401964, ZO0673906739\\",\\"0, 0\\",\\"20.984, 85\\",\\"20.984, 85\\",\\"0, 0\\",\\"ZO0196401964, ZO0673906739\\",106,106,2,2,order,pia +\\"_QMtOW0BH63Xcmy45m1S\\",ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Yasmine,Yasmine,\\"Yasmine Gibbs\\",\\"Yasmine Gibbs\\",FEMALE,43,Gibbs,Gibbs,\\"(empty)\\",Friday,4,\\"yasmine@gibbs-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",Pyramidustries,Pyramidustries,\\"Jun 20, 2019 @ 00:00:00.000\\",561377,\\"sold_product_561377_24916, sold_product_561377_22033\\",\\"sold_product_561377_24916, sold_product_561377_22033\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Pyramidustries\\",\\"Pyramidustries, Pyramidustries\\",\\"13.742, 21.406\\",\\"24.984, 42\\",\\"24,916, 22,033\\",\\"A-line skirt - blue denim, Summer jacket - bordeaux/black\\",\\"A-line skirt - blue denim, Summer jacket - bordeaux/black\\",\\"1, 1\\",\\"ZO0147901479, ZO0185401854\\",\\"0, 0\\",\\"24.984, 42\\",\\"24.984, 42\\",\\"0, 0\\",\\"ZO0147901479, ZO0185401854\\",67,67,2,2,order,yasmine +EwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Romero\\",\\"Wilhemina St. Romero\\",FEMALE,17,Romero,Romero,\\"(empty)\\",Friday,4,\\"wilhemina st.@romero-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Pyramidustries, Tigress Enterprises, Spherecords\\",\\"Pyramidustries, Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",726377,\\"sold_product_726377_16552, sold_product_726377_8806, sold_product_726377_14193, sold_product_726377_22412\\",\\"sold_product_726377_16552, sold_product_726377_8806, sold_product_726377_14193, sold_product_726377_22412\\",\\"14.992, 42, 20.984, 33\\",\\"14.992, 42, 20.984, 33\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Pyramidustries, Tigress Enterprises, Spherecords, Tigress Enterprises\\",\\"Pyramidustries, Tigress Enterprises, Spherecords, Tigress Enterprises\\",\\"6.898, 20.578, 11.117, 17.156\\",\\"14.992, 42, 20.984, 33\\",\\"16,552, 8,806, 14,193, 22,412\\",\\"Print T-shirt - black, Jumper - peacoat, Shift dress - dark blue, Jumper dress - black/grey\\",\\"Print T-shirt - black, Jumper - peacoat, Shift dress - dark blue, Jumper dress - black/grey\\",\\"1, 1, 1, 1\\",\\"ZO0167001670, ZO0070900709, ZO0636006360, ZO0051900519\\",\\"0, 0, 0, 0\\",\\"14.992, 42, 20.984, 33\\",\\"14.992, 42, 20.984, 33\\",\\"0, 0, 0, 0\\",\\"ZO0167001670, ZO0070900709, ZO0636006360, ZO0051900519\\",\\"110.938\\",\\"110.938\\",4,4,order,wilhemina +GgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes, Women's Accessories\\",\\"Women's Clothing, Women's Shoes, Women's Accessories\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Gomez\\",\\"Rabbia Al Gomez\\",FEMALE,5,Gomez,Gomez,\\"(empty)\\",Friday,4,\\"rabbia al@gomez-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",730333,\\"sold_product_730333_18676, sold_product_730333_12860, sold_product_730333_15759, sold_product_730333_24348\\",\\"sold_product_730333_18676, sold_product_730333_12860, sold_product_730333_15759, sold_product_730333_24348\\",\\"28.984, 50, 30.984, 50\\",\\"28.984, 50, 30.984, 50\\",\\"Women's Clothing, Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Women's Clothing, Women's Shoes, Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Oceanavigations\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Oceanavigations\\",\\"13.633, 23, 15.492, 26.484\\",\\"28.984, 50, 30.984, 50\\",\\"18,676, 12,860, 15,759, 24,348\\",\\"Blouse - peach whip, Wedge sandals - gold, Rucksack - black, Summer dress - dark blue\\",\\"Blouse - peach whip, Wedge sandals - gold, Rucksack - black, Summer dress - dark blue\\",\\"1, 1, 1, 1\\",\\"ZO0065000650, ZO0241802418, ZO0098400984, ZO0262102621\\",\\"0, 0, 0, 0\\",\\"28.984, 50, 30.984, 50\\",\\"28.984, 50, 30.984, 50\\",\\"0, 0, 0, 0\\",\\"ZO0065000650, ZO0241802418, ZO0098400984, ZO0262102621\\",160,160,4,4,order,rabbia +agMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Harvey\\",\\"Ahmed Al Harvey\\",MALE,4,Harvey,Harvey,\\"(empty)\\",Friday,4,\\"ahmed al@harvey-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",Microlutions,Microlutions,\\"Jun 20, 2019 @ 00:00:00.000\\",561542,\\"sold_product_561542_6512, sold_product_561542_17698\\",\\"sold_product_561542_6512, sold_product_561542_17698\\",\\"33, 75\\",\\"33, 75\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Microlutions\\",\\"Microlutions, Microlutions\\",\\"16.5, 37.5\\",\\"33, 75\\",\\"6,512, 17,698\\",\\"Jeans Tapered Fit - black denim, Faux leather jacket - black\\",\\"Jeans Tapered Fit - black denim, Faux leather jacket - black\\",\\"1, 1\\",\\"ZO0113701137, ZO0114201142\\",\\"0, 0\\",\\"33, 75\\",\\"33, 75\\",\\"0, 0\\",\\"ZO0113701137, ZO0114201142\\",108,108,2,2,order,ahmed +awMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Jackson,Jackson,\\"Jackson Pratt\\",\\"Jackson Pratt\\",MALE,13,Pratt,Pratt,\\"(empty)\\",Friday,4,\\"jackson@pratt-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561586,\\"sold_product_561586_13927, sold_product_561586_1557\\",\\"sold_product_561586_13927, sold_product_561586_1557\\",\\"42, 60\\",\\"42, 60\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Low Tide Media\\",\\"Elitelligence, Low Tide Media\\",\\"21.406, 31.188\\",\\"42, 60\\",\\"13,927, 1,557\\",\\"Bomber Jacket - khaki, Lace-up boots - brown\\",\\"Bomber Jacket - khaki, Lace-up boots - brown\\",\\"1, 1\\",\\"ZO0540605406, ZO0401104011\\",\\"0, 0\\",\\"42, 60\\",\\"42, 60\\",\\"0, 0\\",\\"ZO0540605406, ZO0401104011\\",102,102,2,2,order,jackson +bgMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Gwen,Gwen,\\"Gwen Mcdonald\\",\\"Gwen Mcdonald\\",FEMALE,26,Mcdonald,Mcdonald,\\"(empty)\\",Friday,4,\\"gwen@mcdonald-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561442,\\"sold_product_561442_7232, sold_product_561442_10893\\",\\"sold_product_561442_7232, sold_product_561442_10893\\",\\"33, 9.992\\",\\"33, 9.992\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"15.508, 4.699\\",\\"33, 9.992\\",\\"7,232, 10,893\\",\\"Winter boots - black, 2 PACK - Leggings - black\\",\\"Winter boots - black, 2 PACK - Leggings - black\\",\\"1, 1\\",\\"ZO0030900309, ZO0212302123\\",\\"0, 0\\",\\"33, 9.992\\",\\"33, 9.992\\",\\"0, 0\\",\\"ZO0030900309, ZO0212302123\\",\\"42.969\\",\\"42.969\\",2,2,order,gwen +bwMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Ahmed Al\\",\\"Ahmed Al\\",\\"Ahmed Al Hampton\\",\\"Ahmed Al Hampton\\",MALE,4,Hampton,Hampton,\\"(empty)\\",Friday,4,\\"ahmed al@hampton-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561484,\\"sold_product_561484_24353, sold_product_561484_18666\\",\\"sold_product_561484_24353, sold_product_561484_18666\\",\\"75, 14.992\\",\\"75, 14.992\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Elitelligence\\",\\"Low Tide Media, Elitelligence\\",\\"34.5, 7.199\\",\\"75, 14.992\\",\\"24,353, 18,666\\",\\"Lace-up boots - black/brown, Long sleeved top - white\\",\\"Lace-up boots - black/brown, Long sleeved top - white\\",\\"1, 1\\",\\"ZO0400304003, ZO0559405594\\",\\"0, 0\\",\\"75, 14.992\\",\\"75, 14.992\\",\\"0, 0\\",\\"ZO0400304003, ZO0559405594\\",90,90,2,2,order,ahmed +cAMtOW0BH63Xcmy45m5S,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Clarice,Clarice,\\"Clarice Smith\\",\\"Clarice Smith\\",FEMALE,18,Smith,Smith,\\"(empty)\\",Friday,4,\\"clarice@smith-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561325,\\"sold_product_561325_21224, sold_product_561325_11110\\",\\"sold_product_561325_21224, sold_product_561325_11110\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse mom, Pyramidustries\\",\\"Gnomehouse mom, Pyramidustries\\",\\"14.781, 15.359\\",\\"28.984, 28.984\\",\\"21,224, 11,110\\",\\"Blouse - red, Tracksuit top - black\\",\\"Blouse - red, Tracksuit top - black\\",\\"1, 1\\",\\"ZO0234802348, ZO0178001780\\",\\"0, 0\\",\\"28.984, 28.984\\",\\"28.984, 28.984\\",\\"0, 0\\",\\"ZO0234802348, ZO0178001780\\",\\"57.969\\",\\"57.969\\",2,2,order,clarice +jgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Abigail,Abigail,\\"Abigail Cross\\",\\"Abigail Cross\\",FEMALE,46,Cross,Cross,\\"(empty)\\",Friday,4,\\"abigail@cross-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562463,\\"sold_product_562463_16341, sold_product_562463_25127\\",\\"sold_product_562463_16341, sold_product_562463_25127\\",\\"65, 50\\",\\"65, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Gnomehouse\\",\\"Angeldale, Gnomehouse\\",\\"29.906, 27.484\\",\\"65, 50\\",\\"16,341, 25,127\\",\\"Handbag - black, Maxi dress - red ochre\\",\\"Handbag - black, Maxi dress - red ochre\\",\\"1, 1\\",\\"ZO0700107001, ZO0341303413\\",\\"0, 0\\",\\"65, 50\\",\\"65, 50\\",\\"0, 0\\",\\"ZO0700107001, ZO0341303413\\",115,115,2,2,order,abigail +jwMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Selena,Selena,\\"Selena Hansen\\",\\"Selena Hansen\\",FEMALE,42,Hansen,Hansen,\\"(empty)\\",Friday,4,\\"selena@hansen-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",Spherecords,Spherecords,\\"Jun 20, 2019 @ 00:00:00.000\\",562513,\\"sold_product_562513_8078, sold_product_562513_9431\\",\\"sold_product_562513_8078, sold_product_562513_9431\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Spherecords\\",\\"Spherecords, Spherecords\\",\\"5.82, 12\\",\\"10.992, 24.984\\",\\"8,078, 9,431\\",\\"Long sleeved top - white, Pyjama set - grey/pink\\",\\"Long sleeved top - white, Pyjama set - grey/pink\\",\\"1, 1\\",\\"ZO0640906409, ZO0660206602\\",\\"0, 0\\",\\"10.992, 24.984\\",\\"10.992, 24.984\\",\\"0, 0\\",\\"ZO0640906409, ZO0660206602\\",\\"35.969\\",\\"35.969\\",2,2,order,selena +kAMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Estrada\\",\\"Abd Estrada\\",MALE,52,Estrada,Estrada,\\"(empty)\\",Friday,4,\\"abd@estrada-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562166,\\"sold_product_562166_16566, sold_product_562166_16701\\",\\"sold_product_562166_16566, sold_product_562166_16701\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"39, 7.988\\",\\"75, 16.984\\",\\"16,566, 16,701\\",\\"Boots - grey, 3 PACK - Basic T-shirt - white\\",\\"Boots - grey, 3 PACK - Basic T-shirt - white\\",\\"1, 1\\",\\"ZO0692406924, ZO0473504735\\",\\"0, 0\\",\\"75, 16.984\\",\\"75, 16.984\\",\\"0, 0\\",\\"ZO0692406924, ZO0473504735\\",92,92,2,2,order,abd +mgMtOW0BH63Xcmy4524Z,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Eddie,Eddie,\\"Eddie King\\",\\"Eddie King\\",MALE,38,King,King,\\"(empty)\\",Friday,4,\\"eddie@king-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",714021,\\"sold_product_714021_21164, sold_product_714021_13240, sold_product_714021_1704, sold_product_714021_15243\\",\\"sold_product_714021_21164, sold_product_714021_13240, sold_product_714021_1704, sold_product_714021_15243\\",\\"10.992, 7.988, 33, 65\\",\\"10.992, 7.988, 33, 65\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"Low Tide Media, Spherecords, Elitelligence, Oceanavigations\\",\\"5.93, 3.84, 15.508, 31.203\\",\\"10.992, 7.988, 33, 65\\",\\"21,164, 13,240, 1,704, 15,243\\",\\"Long sleeved top - dark blue, 5 PACK - Socks - black, High-top trainers - black, Trousers - bordeaux multicolor\\",\\"Long sleeved top - dark blue, 5 PACK - Socks - black, High-top trainers - black, Trousers - bordeaux multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\",\\"0, 0, 0, 0\\",\\"10.992, 7.988, 33, 65\\",\\"10.992, 7.988, 33, 65\\",\\"0, 0, 0, 0\\",\\"ZO0436904369, ZO0664106641, ZO0514805148, ZO0283302833\\",\\"116.938\\",\\"116.938\\",4,4,order,eddie +FgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Shoes\\",EUR,Frances,Frances,\\"Frances Butler\\",\\"Frances Butler\\",FEMALE,49,Butler,Butler,\\"(empty)\\",Friday,4,\\"frances@butler-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",Oceanavigations,Oceanavigations,\\"Jun 20, 2019 @ 00:00:00.000\\",562041,\\"sold_product_562041_17117, sold_product_562041_2398\\",\\"sold_product_562041_17117, sold_product_562041_2398\\",\\"110, 60\\",\\"110, 60\\",\\"Women's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"52.813, 29.406\\",\\"110, 60\\",\\"17,117, 2,398\\",\\"Weekend bag - cognac, Lace-ups - Midnight Blue\\",\\"Weekend bag - cognac, Lace-ups - Midnight Blue\\",\\"1, 1\\",\\"ZO0320303203, ZO0252802528\\",\\"0, 0\\",\\"110, 60\\",\\"110, 60\\",\\"0, 0\\",\\"ZO0320303203, ZO0252802528\\",170,170,2,2,order,frances +FwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Shoes\\",\\"Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Stewart\\",\\"Rabbia Al Stewart\\",FEMALE,5,Stewart,Stewart,\\"(empty)\\",Friday,4,\\"rabbia al@stewart-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562116,\\"sold_product_562116_5339, sold_product_562116_17619\\",\\"sold_product_562116_5339, sold_product_562116_17619\\",\\"75, 60\\",\\"75, 60\\",\\"Women's Shoes, Women's Shoes\\",\\"Women's Shoes, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Gnomehouse\\",\\"Oceanavigations, Gnomehouse\\",\\"38.25, 29.406\\",\\"75, 60\\",\\"5,339, 17,619\\",\\"Ankle boots - black, Lace-ups - silver\\",\\"Ankle boots - black, Lace-ups - silver\\",\\"1, 1\\",\\"ZO0247002470, ZO0322703227\\",\\"0, 0\\",\\"75, 60\\",\\"75, 60\\",\\"0, 0\\",\\"ZO0247002470, ZO0322703227\\",135,135,2,2,order,rabbia +GAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",EUR,Robert,Robert,\\"Robert Hart\\",\\"Robert Hart\\",MALE,29,Hart,Hart,\\"(empty)\\",Friday,4,\\"robert@hart-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562281,\\"sold_product_562281_17836, sold_product_562281_15582\\",\\"sold_product_562281_17836, sold_product_562281_15582\\",\\"85, 13.992\\",\\"85, 13.992\\",\\"Men's Shoes, Women's Accessories\\",\\"Men's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"42.5, 7.691\\",\\"85, 13.992\\",\\"17,836, 15,582\\",\\"Casual lace-ups - black, Belt - dark brown \\",\\"Casual lace-ups - black, Belt - dark brown \\",\\"1, 1\\",\\"ZO0683106831, ZO0317803178\\",\\"0, 0\\",\\"85, 13.992\\",\\"85, 13.992\\",\\"0, 0\\",\\"ZO0683106831, ZO0317803178\\",99,99,2,2,order,robert +IwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",EUR,George,George,\\"George King\\",\\"George King\\",MALE,32,King,King,\\"(empty)\\",Friday,4,\\"george@king-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562442,\\"sold_product_562442_24776, sold_product_562442_20891\\",\\"sold_product_562442_24776, sold_product_562442_20891\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"Men's Accessories, Men's Clothing\\",\\"Men's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Elitelligence\\",\\"Microlutions, Elitelligence\\",\\"15.844, 4\\",\\"33, 7.988\\",\\"24,776, 20,891\\",\\"Watch - black, Basic T-shirt - khaki\\",\\"Watch - black, Basic T-shirt - khaki\\",\\"1, 1\\",\\"ZO0126901269, ZO0563705637\\",\\"0, 0\\",\\"33, 7.988\\",\\"33, 7.988\\",\\"0, 0\\",\\"ZO0126901269, ZO0563705637\\",\\"40.969\\",\\"40.969\\",2,2,order,george +JAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Fitzgerald,Fitzgerald,\\"Fitzgerald Brady\\",\\"Fitzgerald Brady\\",MALE,11,Brady,Brady,\\"(empty)\\",Friday,4,\\"fitzgerald@brady-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562149,\\"sold_product_562149_16955, sold_product_562149_6827\\",\\"sold_product_562149_16955, sold_product_562149_6827\\",\\"200, 33\\",\\"200, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"92, 17.156\\",\\"200, 33\\",\\"16,955, 6,827\\",\\"Classic coat - navy, Denim jacket - black denim\\",\\"Classic coat - navy, Denim jacket - black denim\\",\\"1, 1\\",\\"ZO0291402914, ZO0539305393\\",\\"0, 0\\",\\"200, 33\\",\\"200, 33\\",\\"0, 0\\",\\"ZO0291402914, ZO0539305393\\",233,233,2,2,order,fuzzy +JgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,George,George,\\"George Haynes\\",\\"George Haynes\\",MALE,32,Haynes,Haynes,\\"(empty)\\",Friday,4,\\"george@haynes-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562553,\\"sold_product_562553_15384, sold_product_562553_11950\\",\\"sold_product_562553_15384, sold_product_562553_11950\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"17.156, 5.391\\",\\"33, 10.992\\",\\"15,384, 11,950\\",\\"Denim jacket - grey, Seratonin - Long sleeved top - dark blue\\",\\"Denim jacket - grey, Seratonin - Long sleeved top - dark blue\\",\\"1, 1\\",\\"ZO0525005250, ZO0547205472\\",\\"0, 0\\",\\"33, 10.992\\",\\"33, 10.992\\",\\"0, 0\\",\\"ZO0525005250, ZO0547205472\\",\\"43.969\\",\\"43.969\\",2,2,order,george +bAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Bradley\\",\\"Hicham Bradley\\",MALE,8,Bradley,Bradley,\\"(empty)\\",Friday,4,\\"hicham@bradley-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561677,\\"sold_product_561677_13662, sold_product_561677_20832\\",\\"sold_product_561677_13662, sold_product_561677_20832\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"9.656, 14.781\\",\\"20.984, 28.984\\",\\"13,662, 20,832\\",\\"Tracksuit bottoms - dark blue, Sweatshirt - black\\",\\"Tracksuit bottoms - dark blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0525605256, ZO0126001260\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0525605256, ZO0126001260\\",\\"49.969\\",\\"49.969\\",2,2,order,hicham +bQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Ramsey\\",\\"Abd Ramsey\\",MALE,52,Ramsey,Ramsey,\\"(empty)\\",Friday,4,\\"abd@ramsey-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561217,\\"sold_product_561217_17853, sold_product_561217_20690\\",\\"sold_product_561217_17853, sold_product_561217_20690\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Microlutions\\",\\"Low Tide Media, Microlutions\\",\\"11.25, 18.141\\",\\"24.984, 33\\",\\"17,853, 20,690\\",\\"Shirt - white blue, Sweatshirt - black\\",\\"Shirt - white blue, Sweatshirt - black\\",\\"1, 1\\",\\"ZO0417904179, ZO0125501255\\",\\"0, 0\\",\\"24.984, 33\\",\\"24.984, 33\\",\\"0, 0\\",\\"ZO0417904179, ZO0125501255\\",\\"57.969\\",\\"57.969\\",2,2,order,abd +bgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Tyler\\",\\"Rabbia Al Tyler\\",FEMALE,5,Tyler,Tyler,\\"(empty)\\",Friday,4,\\"rabbia al@tyler-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561251,\\"sold_product_561251_23966, sold_product_561251_18479\\",\\"sold_product_561251_23966, sold_product_561251_18479\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Champion Arts, Oceanavigations\\",\\"Champion Arts, Oceanavigations\\",\\"13.492, 29.906\\",\\"24.984, 65\\",\\"23,966, 18,479\\",\\"Sweatshirt - grey/off-white, Ankle boots - black\\",\\"Sweatshirt - grey/off-white, Ankle boots - black\\",\\"1, 1\\",\\"ZO0502905029, ZO0249102491\\",\\"0, 0\\",\\"24.984, 65\\",\\"24.984, 65\\",\\"0, 0\\",\\"ZO0502905029, ZO0249102491\\",90,90,2,2,order,rabbia +bwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Muniz,Muniz,\\"Muniz Pope\\",\\"Muniz Pope\\",MALE,37,Pope,Pope,\\"(empty)\\",Friday,4,\\"muniz@pope-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561291,\\"sold_product_561291_11706, sold_product_561291_1176\\",\\"sold_product_561291_11706, sold_product_561291_1176\\",\\"100, 42\\",\\"100, 42\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Low Tide Media\\",\\"Angeldale, Low Tide Media\\",\\"49, 21.828\\",\\"100, 42\\",\\"11,706, 1,176\\",\\"Weekend bag - dark brown, Trainers - black\\",\\"Weekend bag - dark brown, Trainers - black\\",\\"1, 1\\",\\"ZO0701907019, ZO0395203952\\",\\"0, 0\\",\\"100, 42\\",\\"100, 42\\",\\"0, 0\\",\\"ZO0701907019, ZO0395203952\\",142,142,2,2,order,muniz +cAMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Morris\\",\\"Boris Morris\\",MALE,36,Morris,Morris,\\"(empty)\\",Friday,4,\\"boris@morris-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561316,\\"sold_product_561316_18944, sold_product_561316_6709\\",\\"sold_product_561316_18944, sold_product_561316_6709\\",\\"24.984, 90\\",\\"24.984, 90\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"11.5, 45\\",\\"24.984, 90\\",\\"18,944, 6,709\\",\\"Shirt - white, Classic coat - navy\\",\\"Shirt - white, Classic coat - navy\\",\\"1, 1\\",\\"ZO0524305243, ZO0290702907\\",\\"0, 0\\",\\"24.984, 90\\",\\"24.984, 90\\",\\"0, 0\\",\\"ZO0524305243, ZO0290702907\\",115,115,2,2,order,boris +cQMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Lewis\\",\\"Wilhemina St. Lewis\\",FEMALE,17,Lewis,Lewis,\\"(empty)\\",Friday,4,\\"wilhemina st.@lewis-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561769,\\"sold_product_561769_18758, sold_product_561769_12114\\",\\"sold_product_561769_18758, sold_product_561769_12114\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"Tigress Enterprises Curvy, Tigress Enterprises\\",\\"14.852, 16.188\\",\\"33, 29.984\\",\\"18,758, 12,114\\",\\"Cardigan - sand multicolor/black, Jersey dress - black/white\\",\\"Cardigan - sand multicolor/black, Jersey dress - black/white\\",\\"1, 1\\",\\"ZO0106601066, ZO0038300383\\",\\"0, 0\\",\\"33, 29.984\\",\\"33, 29.984\\",\\"0, 0\\",\\"ZO0106601066, ZO0038300383\\",\\"62.969\\",\\"62.969\\",2,2,order,wilhemina +cgMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Clarice,Clarice,\\"Clarice Adams\\",\\"Clarice Adams\\",FEMALE,18,Adams,Adams,\\"(empty)\\",Friday,4,\\"clarice@adams-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561784,\\"sold_product_561784_19114, sold_product_561784_21141\\",\\"sold_product_561784_19114, sold_product_561784_21141\\",\\"7.988, 21.984\\",\\"7.988, 21.984\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Pyramidustries\\",\\"Spherecords, Pyramidustries\\",\\"4.309, 11.867\\",\\"7.988, 21.984\\",\\"19,114, 21,141\\",\\"Top - black/white, Xanadu - Across body bag - black\\",\\"Top - black/white, Xanadu - Across body bag - black\\",\\"1, 1\\",\\"ZO0644306443, ZO0205102051\\",\\"0, 0\\",\\"7.988, 21.984\\",\\"7.988, 21.984\\",\\"0, 0\\",\\"ZO0644306443, ZO0205102051\\",\\"29.984\\",\\"29.984\\",2,2,order,clarice +cwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Carr\\",\\"Elyssa Carr\\",FEMALE,27,Carr,Carr,\\"(empty)\\",Friday,4,\\"elyssa@carr-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561815,\\"sold_product_561815_20116, sold_product_561815_24086\\",\\"sold_product_561815_20116, sold_product_561815_24086\\",\\"33, 21.984\\",\\"33, 21.984\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"Tigress Enterprises, Tigress Enterprises MAMA\\",\\"15.844, 11.43\\",\\"33, 21.984\\",\\"20,116, 24,086\\",\\"Handbag - Blue Violety, Long sleeved top - peacoat\\",\\"Handbag - Blue Violety, Long sleeved top - peacoat\\",\\"1, 1\\",\\"ZO0091100911, ZO0231102311\\",\\"0, 0\\",\\"33, 21.984\\",\\"33, 21.984\\",\\"0, 0\\",\\"ZO0091100911, ZO0231102311\\",\\"54.969\\",\\"54.969\\",2,2,order,elyssa +ngMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Mclaughlin\\",\\"Rabbia Al Mclaughlin\\",FEMALE,5,Mclaughlin,Mclaughlin,\\"(empty)\\",Friday,4,\\"rabbia al@mclaughlin-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Jun 20, 2019 @ 00:00:00.000\\",724573,\\"sold_product_724573_12483, sold_product_724573_21459, sold_product_724573_9400, sold_product_724573_16900\\",\\"sold_product_724573_12483, sold_product_724573_21459, sold_product_724573_9400, sold_product_724573_16900\\",\\"24.984, 42, 24.984, 24.984\\",\\"24.984, 42, 24.984, 24.984\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Spherecords, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"12.742, 21.828, 12.992, 13.742\\",\\"24.984, 42, 24.984, 24.984\\",\\"12,483, 21,459, 9,400, 16,900\\",\\"Jumper - beige multicolor, Summer dress - black, Jersey dress - navy, Jersey dress - black/white\\",\\"Jumper - beige multicolor, Summer dress - black, Jersey dress - navy, Jersey dress - black/white\\",\\"1, 1, 1, 1\\",\\"ZO0653306533, ZO0261702617, ZO0036800368, ZO0490704907\\",\\"0, 0, 0, 0\\",\\"24.984, 42, 24.984, 24.984\\",\\"24.984, 42, 24.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0653306533, ZO0261702617, ZO0036800368, ZO0490704907\\",\\"116.938\\",\\"116.938\\",4,4,order,rabbia +zwMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Hernandez\\",\\"Wilhemina St. Hernandez\\",FEMALE,17,Hernandez,Hernandez,\\"(empty)\\",Friday,4,\\"wilhemina st.@hernandez-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561937,\\"sold_product_561937_23134, sold_product_561937_14750\\",\\"sold_product_561937_23134, sold_product_561937_14750\\",\\"7.988, 50\\",\\"7.988, 50\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Low Tide Media\\",\\"Spherecords, Low Tide Media\\",\\"3.68, 26.984\\",\\"7.988, 50\\",\\"23,134, 14,750\\",\\"Basic T-shirt - dark grey multicolor, High heeled sandals - pink\\",\\"Basic T-shirt - dark grey multicolor, High heeled sandals - pink\\",\\"1, 1\\",\\"ZO0638606386, ZO0371503715\\",\\"0, 0\\",\\"7.988, 50\\",\\"7.988, 50\\",\\"0, 0\\",\\"ZO0638606386, ZO0371503715\\",\\"57.969\\",\\"57.969\\",2,2,order,wilhemina +0AMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Youssef,Youssef,\\"Youssef Bryan\\",\\"Youssef Bryan\\",MALE,31,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"youssef@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561966,\\"sold_product_561966_23691, sold_product_561966_20112\\",\\"sold_product_561966_23691, sold_product_561966_20112\\",\\"28.984, 25.984\\",\\"28.984, 25.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Microlutions, Low Tide Media\\",\\"Microlutions, Low Tide Media\\",\\"13.922, 12.477\\",\\"28.984, 25.984\\",\\"23,691, 20,112\\",\\"Sweatshirt - black, Shirt - blue\\",\\"Sweatshirt - black, Shirt - blue\\",\\"1, 1\\",\\"ZO0124201242, ZO0413604136\\",\\"0, 0\\",\\"28.984, 25.984\\",\\"28.984, 25.984\\",\\"0, 0\\",\\"ZO0124201242, ZO0413604136\\",\\"54.969\\",\\"54.969\\",2,2,order,youssef +0QMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Stephanie,Stephanie,\\"Stephanie Cortez\\",\\"Stephanie Cortez\\",FEMALE,6,Cortez,Cortez,\\"(empty)\\",Friday,4,\\"stephanie@cortez-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561522,\\"sold_product_561522_15509, sold_product_561522_16044\\",\\"sold_product_561522_15509, sold_product_561522_16044\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Pyramidustries, Gnomehouse\\",\\"Pyramidustries, Gnomehouse\\",\\"6.469, 25\\",\\"11.992, 50\\",\\"15,509, 16,044\\",\\"Scarf - grey, Summer dress - navy blazer\\",\\"Scarf - grey, Summer dress - navy blazer\\",\\"1, 1\\",\\"ZO0194601946, ZO0340403404\\",\\"0, 0\\",\\"11.992, 50\\",\\"11.992, 50\\",\\"0, 0\\",\\"ZO0194601946, ZO0340403404\\",\\"61.969\\",\\"61.969\\",2,2,order,stephanie +7wMtOW0BH63Xcmy4528Z,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,Abd,Abd,\\"Abd Gregory\\",\\"Abd Gregory\\",MALE,52,Gregory,Gregory,\\"(empty)\\",Friday,4,\\"abd@gregory-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561330,\\"sold_product_561330_18701, sold_product_561330_11884\\",\\"sold_product_561330_18701, sold_product_561330_11884\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Angeldale, Oceanavigations\\",\\"Angeldale, Oceanavigations\\",\\"34.438, 10.578\\",\\"65, 22.984\\",\\"18,701, 11,884\\",\\"Lace-up boots - taupe, Jumper - navy\\",\\"Lace-up boots - taupe, Jumper - navy\\",\\"1, 1\\",\\"ZO0691106911, ZO0295902959\\",\\"0, 0\\",\\"65, 22.984\\",\\"65, 22.984\\",\\"0, 0\\",\\"ZO0691106911, ZO0295902959\\",88,88,2,2,order,abd +gwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",\\"Women's Shoes, Women's Clothing, Women's Accessories\\",EUR,\\"Wilhemina St.\\",\\"Wilhemina St.\\",\\"Wilhemina St. Jimenez\\",\\"Wilhemina St. Jimenez\\",FEMALE,17,Jimenez,Jimenez,\\"(empty)\\",Friday,4,\\"wilhemina st.@jimenez-family.zzz\\",\\"Monte Carlo\\",Europe,MC,\\"POINT (7.4 43.7)\\",\\"-\\",\\"Tigress Enterprises, Spherecords\\",\\"Tigress Enterprises, Spherecords\\",\\"Jun 20, 2019 @ 00:00:00.000\\",726879,\\"sold_product_726879_7151, sold_product_726879_13075, sold_product_726879_13564, sold_product_726879_15989\\",\\"sold_product_726879_7151, sold_product_726879_13075, sold_product_726879_13564, sold_product_726879_15989\\",\\"42, 10.992, 16.984, 28.984\\",\\"42, 10.992, 16.984, 28.984\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Women's Shoes, Women's Clothing, Women's Accessories, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Spherecords, Tigress Enterprises, Tigress Enterprises\\",\\"Tigress Enterprises, Spherecords, Tigress Enterprises, Tigress Enterprises\\",\\"22.25, 5.82, 9.344, 13.633\\",\\"42, 10.992, 16.984, 28.984\\",\\"7,151, 13,075, 13,564, 15,989\\",\\"Ankle boots - black, Body - black, Clutch - black, A-line skirt - blue\\",\\"Ankle boots - black, Body - black, Clutch - black, A-line skirt - blue\\",\\"1, 1, 1, 1\\",\\"ZO0020100201, ZO0659406594, ZO0087900879, ZO0032700327\\",\\"0, 0, 0, 0\\",\\"42, 10.992, 16.984, 28.984\\",\\"42, 10.992, 16.984, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0020100201, ZO0659406594, ZO0087900879, ZO0032700327\\",\\"98.938\\",\\"98.938\\",4,4,order,wilhemina +hAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Accessories, Women's Clothing\\",\\"Women's Accessories, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Abbott\\",\\"Elyssa Abbott\\",FEMALE,27,Abbott,Abbott,\\"(empty)\\",Friday,4,\\"elyssa@abbott-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Tigress Enterprises, Oceanavigations, Champion Arts\\",\\"Tigress Enterprises, Oceanavigations, Champion Arts\\",\\"Jun 20, 2019 @ 00:00:00.000\\",725944,\\"sold_product_725944_16292, sold_product_725944_18842, sold_product_725944_25188, sold_product_725944_15449\\",\\"sold_product_725944_16292, sold_product_725944_18842, sold_product_725944_25188, sold_product_725944_15449\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"Women's Accessories, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Women's Accessories, Women's Clothing, Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"Tigress Enterprises, Oceanavigations, Tigress Enterprises, Champion Arts\\",\\"11.25, 8.156, 15.648, 5.281\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"16,292, 18,842, 25,188, 15,449\\",\\"Watch - rose gold-coloured, Print T-shirt - black, Blouse - peacoat, Print T-shirt - coral\\",\\"Watch - rose gold-coloured, Print T-shirt - black, Blouse - peacoat, Print T-shirt - coral\\",\\"1, 1, 1, 1\\",\\"ZO0079200792, ZO0263902639, ZO0065900659, ZO0492304923\\",\\"0, 0, 0, 0\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"24.984, 16.984, 28.984, 10.992\\",\\"0, 0, 0, 0\\",\\"ZO0079200792, ZO0263902639, ZO0065900659, ZO0492304923\\",\\"81.938\\",\\"81.938\\",4,4,order,elyssa +jAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Elyssa,Elyssa,\\"Elyssa Dennis\\",\\"Elyssa Dennis\\",FEMALE,27,Dennis,Dennis,\\"(empty)\\",Friday,4,\\"elyssa@dennis-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562572,\\"sold_product_562572_13412, sold_product_562572_19097\\",\\"sold_product_562572_13412, sold_product_562572_19097\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Oceanavigations\\",\\"Spherecords, Oceanavigations\\",\\"7.551, 29.406\\",\\"13.992, 60\\",\\"13,412, 19,097\\",\\"Blouse - off white, Ankle boots - camel\\",\\"Blouse - off white, Ankle boots - camel\\",\\"1, 1\\",\\"ZO0649706497, ZO0249202492\\",\\"0, 0\\",\\"13.992, 60\\",\\"13.992, 60\\",\\"0, 0\\",\\"ZO0649706497, ZO0249202492\\",74,74,2,2,order,elyssa +nAMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",EUR,Stephanie,Stephanie,\\"Stephanie Marshall\\",\\"Stephanie Marshall\\",FEMALE,6,Marshall,Marshall,\\"(empty)\\",Friday,4,\\"stephanie@marshall-family.zzz\\",Cannes,Europe,FR,\\"POINT (7 43.6)\\",\\"Alpes-Maritimes\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562035,\\"sold_product_562035_9471, sold_product_562035_21453\\",\\"sold_product_562035_9471, sold_product_562035_21453\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"Women's Clothing, Women's Accessories\\",\\"Women's Clothing, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Gnomehouse, Pyramidustries\\",\\"Gnomehouse, Pyramidustries\\",\\"22.672, 7\\",\\"42, 13.992\\",\\"9,471, 21,453\\",\\"Summer dress - black/june bug, Handbag - black\\",\\"Summer dress - black/june bug, Handbag - black\\",\\"1, 1\\",\\"ZO0334403344, ZO0205002050\\",\\"0, 0\\",\\"42, 13.992\\",\\"42, 13.992\\",\\"0, 0\\",\\"ZO0334403344, ZO0205002050\\",\\"55.969\\",\\"55.969\\",2,2,order,stephanie +nQMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robbie,Robbie,\\"Robbie Hodges\\",\\"Robbie Hodges\\",MALE,48,Hodges,Hodges,\\"(empty)\\",Friday,4,\\"robbie@hodges-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,Elitelligence,Elitelligence,\\"Jun 20, 2019 @ 00:00:00.000\\",562112,\\"sold_product_562112_6789, sold_product_562112_20433\\",\\"sold_product_562112_6789, sold_product_562112_20433\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Elitelligence\\",\\"Elitelligence, Elitelligence\\",\\"10.703, 5.82\\",\\"20.984, 10.992\\",\\"6,789, 20,433\\",\\"Chinos - blue, Long sleeved top - black/white\\",\\"Chinos - blue, Long sleeved top - black/white\\",\\"1, 1\\",\\"ZO0527405274, ZO0547005470\\",\\"0, 0\\",\\"20.984, 10.992\\",\\"20.984, 10.992\\",\\"0, 0\\",\\"ZO0527405274, ZO0547005470\\",\\"31.984\\",\\"31.984\\",2,2,order,robbie +ngMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,Clarice,Clarice,\\"Clarice Ball\\",\\"Clarice Ball\\",FEMALE,18,Ball,Ball,\\"(empty)\\",Friday,4,\\"clarice@ball-family.zzz\\",Birmingham,Europe,GB,\\"POINT (-1.9 52.5)\\",Birmingham,\\"Tigress Enterprises Curvy, Karmanite\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562275,\\"sold_product_562275_19153, sold_product_562275_12720\\",\\"sold_product_562275_19153, sold_product_562275_12720\\",\\"29.984, 70\\",\\"29.984, 70\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"Tigress Enterprises Curvy, Karmanite\\",\\"14.992, 37.094\\",\\"29.984, 70\\",\\"19,153, 12,720\\",\\"Cardigan - jade, Sandals - black\\",\\"Cardigan - jade, Sandals - black\\",\\"1, 1\\",\\"ZO0106301063, ZO0703507035\\",\\"0, 0\\",\\"29.984, 70\\",\\"29.984, 70\\",\\"0, 0\\",\\"ZO0106301063, ZO0703507035\\",100,100,2,2,order,clarice +nwMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Mostafa,Mostafa,\\"Mostafa Greer\\",\\"Mostafa Greer\\",MALE,9,Greer,Greer,\\"(empty)\\",Friday,4,\\"mostafa@greer-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562287,\\"sold_product_562287_3022, sold_product_562287_23056\\",\\"sold_product_562287_3022, sold_product_562287_23056\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"9.172, 28.797\\",\\"16.984, 60\\",\\"3,022, 23,056\\",\\"3 PACK - Basic T-shirt - white, Suit jacket - grey multicolor\\",\\"3 PACK - Basic T-shirt - white, Suit jacket - grey multicolor\\",\\"1, 1\\",\\"ZO0473104731, ZO0274302743\\",\\"0, 0\\",\\"16.984, 60\\",\\"16.984, 60\\",\\"0, 0\\",\\"ZO0473104731, ZO0274302743\\",77,77,2,2,order,mostafa +rgMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Tariq,Tariq,\\"Tariq Schultz\\",\\"Tariq Schultz\\",MALE,25,Schultz,Schultz,\\"(empty)\\",Friday,4,\\"tariq@schultz-family.zzz\\",Istanbul,Asia,TR,\\"POINT (29 41)\\",Istanbul,\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562404,\\"sold_product_562404_19679, sold_product_562404_22477\\",\\"sold_product_562404_19679, sold_product_562404_22477\\",\\"28.984, 22.984\\",\\"28.984, 22.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Oceanavigations\\",\\"Elitelligence, Oceanavigations\\",\\"15.648, 12.18\\",\\"28.984, 22.984\\",\\"19,679, 22,477\\",\\"Hoodie - black/dark blue/white, Jumper - khaki\\",\\"Hoodie - black/dark blue/white, Jumper - khaki\\",\\"1, 1\\",\\"ZO0584205842, ZO0299102991\\",\\"0, 0\\",\\"28.984, 22.984\\",\\"28.984, 22.984\\",\\"0, 0\\",\\"ZO0584205842, ZO0299102991\\",\\"51.969\\",\\"51.969\\",2,2,order,tariq +1QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",EUR,Hicham,Hicham,\\"Hicham Abbott\\",\\"Hicham Abbott\\",MALE,8,Abbott,Abbott,\\"(empty)\\",Friday,4,\\"hicham@abbott-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562099,\\"sold_product_562099_18906, sold_product_562099_21672\\",\\"sold_product_562099_18906, sold_product_562099_21672\\",\\"13.992, 16.984\\",\\"13.992, 16.984\\",\\"Women's Accessories, Men's Clothing\\",\\"Women's Accessories, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Low Tide Media\\",\\"Oceanavigations, Low Tide Media\\",\\"6.578, 9\\",\\"13.992, 16.984\\",\\"18,906, 21,672\\",\\"Belt - black, Polo shirt - black multicolor\\",\\"Belt - black, Polo shirt - black multicolor\\",\\"1, 1\\",\\"ZO0317903179, ZO0443904439\\",\\"0, 0\\",\\"13.992, 16.984\\",\\"13.992, 16.984\\",\\"0, 0\\",\\"ZO0317903179, ZO0443904439\\",\\"30.984\\",\\"30.984\\",2,2,order,hicham +1gMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Boris,Boris,\\"Boris Morrison\\",\\"Boris Morrison\\",MALE,36,Morrison,Morrison,\\"(empty)\\",Friday,4,\\"boris@morrison-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562298,\\"sold_product_562298_22860, sold_product_562298_11728\\",\\"sold_product_562298_22860, sold_product_562298_11728\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"11.5, 8.547\\",\\"24.984, 18.984\\",\\"22,860, 11,728\\",\\"Shirt - offwhite, Sweatshirt - red\\",\\"Shirt - offwhite, Sweatshirt - red\\",\\"1, 1\\",\\"ZO0280002800, ZO0583105831\\",\\"0, 0\\",\\"24.984, 18.984\\",\\"24.984, 18.984\\",\\"0, 0\\",\\"ZO0280002800, ZO0583105831\\",\\"43.969\\",\\"43.969\\",2,2,order,boris +3QMtOW0BH63Xcmy453D9,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Oliver,Oliver,\\"Oliver Rios\\",\\"Oliver Rios\\",MALE,7,Rios,Rios,\\"(empty)\\",Friday,4,\\"oliver@rios-family.zzz\\",\\"-\\",Europe,GB,\\"POINT (-0.1 51.5)\\",\\"-\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",562025,\\"sold_product_562025_18322, sold_product_562025_1687\\",\\"sold_product_562025_18322, sold_product_562025_1687\\",\\"14.992, 80\\",\\"14.992, 80\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Elitelligence, Angeldale\\",\\"Elitelligence, Angeldale\\",\\"7.352, 43.188\\",\\"14.992, 80\\",\\"18,322, 1,687\\",\\"Print T-shirt - grey, Lace-ups - whisky\\",\\"Print T-shirt - grey, Lace-ups - whisky\\",\\"1, 1\\",\\"ZO0558205582, ZO0682406824\\",\\"0, 0\\",\\"14.992, 80\\",\\"14.992, 80\\",\\"0, 0\\",\\"ZO0558205582, ZO0682406824\\",95,95,2,2,order,oliver +hAMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing, Women's Shoes\\",\\"Women's Clothing, Women's Shoes\\",EUR,\\"Rabbia Al\\",\\"Rabbia Al\\",\\"Rabbia Al Palmer\\",\\"Rabbia Al Palmer\\",FEMALE,5,Palmer,Palmer,\\"(empty)\\",Friday,4,\\"rabbia al@palmer-family.zzz\\",Dubai,Asia,AE,\\"POINT (55.3 25.3)\\",Dubai,\\"Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Spherecords, Pyramidustries, Tigress Enterprises\\",\\"Jun 20, 2019 @ 00:00:00.000\\",732071,\\"sold_product_732071_23772, sold_product_732071_22922, sold_product_732071_24589, sold_product_732071_24761\\",\\"sold_product_732071_23772, sold_product_732071_22922, sold_product_732071_24589, sold_product_732071_24761\\",\\"18.984, 33, 24.984, 20.984\\",\\"18.984, 33, 24.984, 20.984\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Women's Clothing, Women's Clothing, Women's Shoes, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Spherecords, Pyramidustries, Tigress Enterprises, Tigress Enterprises\\",\\"Spherecords, Pyramidustries, Tigress Enterprises, Tigress Enterprises\\",\\"10.25, 15.508, 13.492, 10.289\\",\\"18.984, 33, 24.984, 20.984\\",\\"23,772, 22,922, 24,589, 24,761\\",\\"Jumper - turquoise, Jersey dress - dark red, Boots - black, Vest - black\\",\\"Jumper - turquoise, Jersey dress - dark red, Boots - black, Vest - black\\",\\"1, 1, 1, 1\\",\\"ZO0655406554, ZO0154001540, ZO0030300303, ZO0061100611\\",\\"0, 0, 0, 0\\",\\"18.984, 33, 24.984, 20.984\\",\\"18.984, 33, 24.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0655406554, ZO0154001540, ZO0030300303, ZO0061100611\\",\\"97.938\\",\\"97.938\\",4,4,order,rabbia +kQMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",EUR,Yahya,Yahya,\\"Yahya King\\",\\"Yahya King\\",MALE,23,King,King,\\"(empty)\\",Friday,4,\\"yahya@king-family.zzz\\",Marrakesh,Africa,MA,\\"POINT (-8 31.6)\\",\\"Marrakech-Tensift-Al Haouz\\",\\"Low Tide Media, (empty)\\",\\"Low Tide Media, (empty)\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561383,\\"sold_product_561383_15806, sold_product_561383_12605\\",\\"sold_product_561383_15806, sold_product_561383_12605\\",\\"13.992, 155\\",\\"13.992, 155\\",\\"Men's Accessories, Men's Shoes\\",\\"Men's Accessories, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, (empty)\\",\\"Low Tide Media, (empty)\\",\\"7.27, 82.125\\",\\"13.992, 155\\",\\"15,806, 12,605\\",\\"Belt - dark brown, Lace-ups - taupe\\",\\"Belt - dark brown, Lace-ups - taupe\\",\\"1, 1\\",\\"ZO0461804618, ZO0481404814\\",\\"0, 0\\",\\"13.992, 155\\",\\"13.992, 155\\",\\"0, 0\\",\\"ZO0461804618, ZO0481404814\\",169,169,2,2,order,yahya +kgMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Sonya,Sonya,\\"Sonya Strickland\\",\\"Sonya Strickland\\",FEMALE,28,Strickland,Strickland,\\"(empty)\\",Friday,4,\\"sonya@strickland-family.zzz\\",Bogotu00e1,\\"South America\\",CO,\\"POINT (-74.1 4.6)\\",\\"Bogota D.C.\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561825,\\"sold_product_561825_23332, sold_product_561825_8218\\",\\"sold_product_561825_23332, sold_product_561825_8218\\",\\"18.984, 17.984\\",\\"18.984, 17.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"9.117, 9.531\\",\\"18.984, 17.984\\",\\"23,332, 8,218\\",\\"Vest - black/dark green, Sweatshirt - rose\\",\\"Vest - black/dark green, Sweatshirt - rose\\",\\"1, 1\\",\\"ZO0062500625, ZO0179801798\\",\\"0, 0\\",\\"18.984, 17.984\\",\\"18.984, 17.984\\",\\"0, 0\\",\\"ZO0062500625, ZO0179801798\\",\\"36.969\\",\\"36.969\\",2,2,order,sonya +kwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Meyer\\",\\"Abd Meyer\\",MALE,52,Meyer,Meyer,\\"(empty)\\",Friday,4,\\"abd@meyer-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561870,\\"sold_product_561870_18909, sold_product_561870_18272\\",\\"sold_product_561870_18909, sold_product_561870_18272\\",\\"65, 12.992\\",\\"65, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Spritechnologies\\",\\"Low Tide Media, Spritechnologies\\",\\"33.125, 6.109\\",\\"65, 12.992\\",\\"18,909, 18,272\\",\\"Cardigan - grey multicolor, Sports shirt - dark grey multicolor\\",\\"Cardigan - grey multicolor, Sports shirt - dark grey multicolor\\",\\"1, 1\\",\\"ZO0450904509, ZO0615906159\\",\\"0, 0\\",\\"65, 12.992\\",\\"65, 12.992\\",\\"0, 0\\",\\"ZO0450904509, ZO0615906159\\",78,78,2,2,order,abd +wwMtOW0BH63Xcmy453H9,ecommerce,\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Salazar\\",\\"Elyssa Salazar\\",FEMALE,27,Salazar,Salazar,\\"(empty)\\",Friday,4,\\"elyssa@salazar-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",Oceanavigations,Oceanavigations,\\"Jun 20, 2019 @ 00:00:00.000\\",561569,\\"sold_product_561569_22788, sold_product_561569_20475\\",\\"sold_product_561569_22788, sold_product_561569_20475\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Oceanavigations\\",\\"Oceanavigations, Oceanavigations\\",\\"9.867, 15.359\\",\\"20.984, 28.984\\",\\"22,788, 20,475\\",\\"Print T-shirt - white/black, Blouse - red\\",\\"Print T-shirt - white/black, Blouse - red\\",\\"1, 1\\",\\"ZO0264602646, ZO0265202652\\",\\"0, 0\\",\\"20.984, 28.984\\",\\"20.984, 28.984\\",\\"0, 0\\",\\"ZO0264602646, ZO0265202652\\",\\"49.969\\",\\"49.969\\",2,2,order,elyssa +hAMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Robert,Robert,\\"Robert Brock\\",\\"Robert Brock\\",MALE,29,Brock,Brock,\\"(empty)\\",Friday,4,\\"robert@brock-family.zzz\\",\\"-\\",Asia,SA,\\"POINT (45 25)\\",\\"-\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561935,\\"sold_product_561935_20811, sold_product_561935_19107\\",\\"sold_product_561935_20811, sold_product_561935_19107\\",\\"37, 50\\",\\"37, 50\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Oceanavigations\\",\\"Low Tide Media, Oceanavigations\\",\\"17.391, 26.984\\",\\"37, 50\\",\\"20,811, 19,107\\",\\"Shirt - white/red, Suit jacket - navy\\",\\"Shirt - white/red, Suit jacket - navy\\",\\"1, 1\\",\\"ZO0417404174, ZO0275702757\\",\\"0, 0\\",\\"37, 50\\",\\"37, 50\\",\\"0, 0\\",\\"ZO0417404174, ZO0275702757\\",87,87,2,2,order,robert +hQMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",EUR,\\"Abdulraheem Al\\",\\"Abdulraheem Al\\",\\"Abdulraheem Al Graves\\",\\"Abdulraheem Al Graves\\",MALE,33,Graves,Graves,\\"(empty)\\",Friday,4,\\"abdulraheem al@graves-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Low Tide Media\\",\\"Low Tide Media\\",\\"Jun 20, 2019 @ 00:00:00.000\\",561976,\\"sold_product_561976_16395, sold_product_561976_2982\\",\\"sold_product_561976_16395, sold_product_561976_2982\\",\\"42, 33\\",\\"42, 33\\",\\"Men's Shoes, Men's Clothing\\",\\"Men's Shoes, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Low Tide Media, Low Tide Media\\",\\"Low Tide Media, Low Tide Media\\",\\"19.313, 17.484\\",\\"42, 33\\",\\"16,395, 2,982\\",\\"Lace-ups - black, Jumper - multicoloured\\",\\"Lace-ups - black, Jumper - multicoloured\\",\\"1, 1\\",\\"ZO0392703927, ZO0452004520\\",\\"0, 0\\",\\"42, 33\\",\\"42, 33\\",\\"0, 0\\",\\"ZO0392703927, ZO0452004520\\",75,75,2,2,order,abdulraheem +swMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",\\"Women's Accessories, Men's Accessories, Men's Shoes\\",EUR,\\"Sultan Al\\",\\"Sultan Al\\",\\"Sultan Al Goodman\\",\\"Sultan Al Goodman\\",MALE,19,Goodman,Goodman,\\"(empty)\\",Friday,4,\\"sultan al@goodman-family.zzz\\",\\"Abu Dhabi\\",Asia,AE,\\"POINT (54.4 24.5)\\",\\"Abu Dhabi\\",\\"Elitelligence, Oceanavigations, Angeldale\\",\\"Elitelligence, Oceanavigations, Angeldale\\",\\"Jun 20, 2019 @ 00:00:00.000\\",717426,\\"sold_product_717426_20776, sold_product_717426_13026, sold_product_717426_11738, sold_product_717426_15588\\",\\"sold_product_717426_20776, sold_product_717426_13026, sold_product_717426_11738, sold_product_717426_15588\\",\\"24.984, 100, 14.992, 20.984\\",\\"24.984, 100, 14.992, 20.984\\",\\"Women's Accessories, Men's Accessories, Men's Shoes, Women's Accessories\\",\\"Women's Accessories, Men's Accessories, Men's Shoes, Women's Accessories\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Oceanavigations, Elitelligence, Angeldale\\",\\"Elitelligence, Oceanavigations, Elitelligence, Angeldale\\",\\"12, 48, 7.5, 11.539\\",\\"24.984, 100, 14.992, 20.984\\",\\"20,776, 13,026, 11,738, 15,588\\",\\"Sports bag - navy/cognac, Weekend bag - dark brown, Espadrilles - navy, Wallet - cognac\\",\\"Sports bag - navy/cognac, Weekend bag - dark brown, Espadrilles - navy, Wallet - cognac\\",\\"1, 1, 1, 1\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\",\\"0, 0, 0, 0\\",\\"24.984, 100, 14.992, 20.984\\",\\"24.984, 100, 14.992, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0606006060, ZO0314703147, ZO0518005180, ZO0702907029\\",161,161,4,4,order,sultan +ywMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing, Men's Shoes\\",\\"Men's Clothing, Men's Shoes\\",EUR,Abd,Abd,\\"Abd Jacobs\\",\\"Abd Jacobs\\",MALE,52,Jacobs,Jacobs,\\"(empty)\\",Friday,4,\\"abd@jacobs-family.zzz\\",Cairo,Africa,EG,\\"POINT (31.3 30.1)\\",\\"Cairo Governorate\\",\\"Elitelligence, Microlutions\\",\\"Elitelligence, Microlutions\\",\\"Jun 20, 2019 @ 00:00:00.000\\",719082,\\"sold_product_719082_23782, sold_product_719082_12684, sold_product_719082_19741, sold_product_719082_19989\\",\\"sold_product_719082_23782, sold_product_719082_12684, sold_product_719082_19741, sold_product_719082_19989\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Men's Clothing, Men's Clothing, Men's Shoes, Men's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Microlutions, Elitelligence, Elitelligence\\",\\"Elitelligence, Microlutions, Elitelligence, Elitelligence\\",\\"15.07, 7.5, 7.988, 15.648\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"23,782, 12,684, 19,741, 19,989\\",\\"Tracksuit top - black, Print T-shirt - navy blazer, Trainers - black, Trainers - grey\\",\\"Tracksuit top - black, Print T-shirt - navy blazer, Trainers - black, Trainers - grey\\",\\"1, 1, 1, 1\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\",\\"0, 0, 0, 0\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"28.984, 14.992, 16.984, 28.984\\",\\"0, 0, 0, 0\\",\\"ZO0591005910, ZO0116501165, ZO0507505075, ZO0514305143\\",\\"89.938\\",\\"89.938\\",4,4,order,abd +0wMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Jackson,Jackson,\\"Jackson Pope\\",\\"Jackson Pope\\",MALE,13,Pope,Pope,\\"(empty)\\",Friday,4,\\"jackson@pope-family.zzz\\",\\"Los Angeles\\",\\"North America\\",US,\\"POINT (-118.2 34.1)\\",California,\\"Elitelligence, Microlutions, Oceanavigations\\",\\"Elitelligence, Microlutions, Oceanavigations\\",\\"Jun 20, 2019 @ 00:00:00.000\\",715688,\\"sold_product_715688_19518, sold_product_715688_21048, sold_product_715688_12333, sold_product_715688_21005\\",\\"sold_product_715688_19518, sold_product_715688_21048, sold_product_715688_12333, sold_product_715688_21005\\",\\"33, 14.992, 16.984, 20.984\\",\\"33, 14.992, 16.984, 20.984\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing, Men's Clothing, Men's Clothing\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Elitelligence, Microlutions, Elitelligence, Oceanavigations\\",\\"Elitelligence, Microlutions, Elitelligence, Oceanavigations\\",\\"16.813, 6.75, 7.648, 9.656\\",\\"33, 14.992, 16.984, 20.984\\",\\"19,518, 21,048, 12,333, 21,005\\",\\"Sweatshirt - mottled grey, Print T-shirt - bright white, Tracksuit top - black, Formal shirt - white\\",\\"Sweatshirt - mottled grey, Print T-shirt - bright white, Tracksuit top - black, Formal shirt - white\\",\\"1, 1, 1, 1\\",\\"ZO0585505855, ZO0121001210, ZO0583005830, ZO0279402794\\",\\"0, 0, 0, 0\\",\\"33, 14.992, 16.984, 20.984\\",\\"33, 14.992, 16.984, 20.984\\",\\"0, 0, 0, 0\\",\\"ZO0585505855, ZO0121001210, ZO0583005830, ZO0279402794\\",\\"85.938\\",\\"85.938\\",4,4,order,jackson +1QMtOW0BH63Xcmy46HLV,ecommerce,\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Elyssa,Elyssa,\\"Elyssa Bryan\\",\\"Elyssa Bryan\\",FEMALE,27,Bryan,Bryan,\\"(empty)\\",Friday,4,\\"elyssa@bryan-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"POINT (-74 40.8)\\",\\"New York\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active\\",\\"Jun 20, 2019 @ 00:00:00.000\\",729671,\\"sold_product_729671_5140, sold_product_729671_12381, sold_product_729671_16267, sold_product_729671_20230\\",\\"sold_product_729671_5140, sold_product_729671_12381, sold_product_729671_16267, sold_product_729671_20230\\",\\"60, 16.984, 24.984, 24.984\\",\\"60, 16.984, 24.984, 24.984\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Women's Shoes, Women's Clothing, Women's Clothing, Women's Shoes\\",\\"Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000, Dec 9, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active, Pyramidustries\\",\\"Low Tide Media, Pyramidustries, Pyramidustries active, Pyramidustries\\",\\"30, 7.648, 12.492, 12\\",\\"60, 16.984, 24.984, 24.984\\",\\"5,140, 12,381, 16,267, 20,230\\",\\"Ankle boots - onix, Sweatshirt - rose, Tights - black, Sandals - silver\\",\\"Ankle boots - onix, Sweatshirt - rose, Tights - black, Sandals - silver\\",\\"1, 1, 1, 1\\",\\"ZO0375303753, ZO0178301783, ZO0226002260, ZO0137601376\\",\\"0, 0, 0, 0\\",\\"60, 16.984, 24.984, 24.984\\",\\"60, 16.984, 24.984, 24.984\\",\\"0, 0, 0, 0\\",\\"ZO0375303753, ZO0178301783, ZO0226002260, ZO0137601376\\",\\"126.938\\",\\"126.938\\",4,4,order,elyssa +" +`; + +exports[`discover Discover CSV Export Generate CSV: sparse data handles field formatting for a field that doesn't exist initially 1`] = ` +"timestamp,name,\\"updated_at\\" +\\"Aug 13, 2006 @ 00:00:00.000\\",\\"test-510\\",\\"-\\" +\\"Aug 12, 2006 @ 00:00:00.000\\",\\"test-509\\",\\"-\\" +\\"Aug 11, 2006 @ 00:00:00.000\\",\\"test-508\\",\\"-\\" +\\"Aug 10, 2006 @ 00:00:00.000\\",\\"test-507\\",\\"-\\" +\\"Aug 9, 2006 @ 00:00:00.000\\",\\"test-506\\",\\"-\\" +\\"Aug 8, 2006 @ 00:00:00.000\\",\\"test-505\\",\\"-\\" +\\"Aug 7, 2006 @ 00:00:00.000\\",\\"test-504\\",\\"-\\" +\\"Aug 6, 2006 @ 00:00:00.000\\",\\"test-503\\",\\"-\\" +\\"Aug 5, 2006 @ 00:00:00.000\\",\\"test-502\\",\\"-\\" +\\"Aug 4, 2006 @ 00:00:00.000\\",\\"test-501\\",\\"-\\" +\\"Aug 3, 2006 @ 00:00:00.000\\",\\"test-500\\",\\"-\\" +\\"Aug 2, 2006 @ 00:00:00.000\\",\\"test-499\\",\\"-\\" +\\"Aug 1, 2006 @ 00:00:00.000\\",\\"test-498\\",\\"-\\" +\\"Jul 31, 2006 @ 00:00:00.000\\",\\"test-497\\",\\"-\\" +\\"Jul 30, 2006 @ 00:00:00.000\\",\\"test-496\\",\\"-\\" +\\"Jul 29, 2006 @ 00:00:00.000\\",\\"test-495\\",\\"-\\" +\\"Jul 28, 2006 @ 00:00:00.000\\",\\"test-494\\",\\"-\\" +\\"Jul 27, 2006 @ 00:00:00.000\\",\\"test-493\\",\\"-\\" +\\"Jul 26, 2006 @ 00:00:00.000\\",\\"test-492\\",\\"-\\" +\\"Jul 25, 2006 @ 00:00:00.000\\",\\"test-491\\",\\"-\\" +\\"Jul 24, 2006 @ 00:00:00.000\\",\\"test-490\\",\\"-\\" +\\"Jul 23, 2006 @ 00:00:00.000\\",\\"test-489\\",\\"-\\" +\\"Jul 22, 2006 @ 00:00:00.000\\",\\"test-488\\",\\"-\\" +\\"Jul 21, 2006 @ 00:00:00.000\\",\\"test-487\\",\\"-\\" +\\"Jul 20, 2006 @ 00:00:00.000\\",\\"test-486\\",\\"-\\" +\\"Jul 19, 2006 @ 00:00:00.000\\",\\"test-485\\",\\"-\\" +\\"Jul 18, 2006 @ 00:00:00.000\\",\\"test-484\\",\\"-\\" +\\"Jul 17, 2006 @ 00:00:00.000\\",\\"test-483\\",\\"-\\" +\\"Jul 16, 2006 @ 00:00:00.000\\",\\"test-482\\",\\"-\\" +\\"Jul 15, 2006 @ 00:00:00.000\\",\\"test-481\\",\\"-\\" +\\"Jul 14, 2006 @ 00:00:00.000\\",\\"test-480\\",\\"-\\" +\\"Jul 13, 2006 @ 00:00:00.000\\",\\"test-479\\",\\"-\\" +\\"Jul 12, 2006 @ 00:00:00.000\\",\\"test-478\\",\\"-\\" +\\"Jul 11, 2006 @ 00:00:00.000\\",\\"test-477\\",\\"-\\" +\\"Jul 10, 2006 @ 00:00:00.000\\",\\"test-476\\",\\"-\\" +\\"Jul 9, 2006 @ 00:00:00.000\\",\\"test-475\\",\\"-\\" +\\"Jul 8, 2006 @ 00:00:00.000\\",\\"test-474\\",\\"-\\" +\\"Jul 7, 2006 @ 00:00:00.000\\",\\"test-473\\",\\"-\\" +\\"Jul 6, 2006 @ 00:00:00.000\\",\\"test-472\\",\\"-\\" +\\"Jul 5, 2006 @ 00:00:00.000\\",\\"test-471\\",\\"-\\" +\\"Jul 4, 2006 @ 00:00:00.000\\",\\"test-470\\",\\"-\\" +\\"Jul 3, 2006 @ 00:00:00.000\\",\\"test-469\\",\\"-\\" +\\"Jul 2, 2006 @ 00:00:00.000\\",\\"test-468\\",\\"-\\" +\\"Jul 1, 2006 @ 00:00:00.000\\",\\"test-467\\",\\"-\\" +\\"Jun 30, 2006 @ 00:00:00.000\\",\\"test-466\\",\\"-\\" +\\"Jun 29, 2006 @ 00:00:00.000\\",\\"test-465\\",\\"-\\" +\\"Jun 28, 2006 @ 00:00:00.000\\",\\"test-464\\",\\"-\\" +\\"Jun 27, 2006 @ 00:00:00.000\\",\\"test-463\\",\\"-\\" +\\"Jun 26, 2006 @ 00:00:00.000\\",\\"test-462\\",\\"-\\" +\\"Jun 25, 2006 @ 00:00:00.000\\",\\"test-461\\",\\"-\\" +\\"Jun 24, 2006 @ 00:00:00.000\\",\\"test-460\\",\\"-\\" +\\"Jun 23, 2006 @ 00:00:00.000\\",\\"test-459\\",\\"-\\" +\\"Jun 22, 2006 @ 00:00:00.000\\",\\"test-458\\",\\"-\\" +\\"Jun 21, 2006 @ 00:00:00.000\\",\\"test-457\\",\\"-\\" +\\"Jun 20, 2006 @ 00:00:00.000\\",\\"test-456\\",\\"-\\" +\\"Jun 19, 2006 @ 00:00:00.000\\",\\"test-455\\",\\"-\\" +\\"Jun 18, 2006 @ 00:00:00.000\\",\\"test-454\\",\\"-\\" +\\"Jun 17, 2006 @ 00:00:00.000\\",\\"test-453\\",\\"-\\" +\\"Jun 16, 2006 @ 00:00:00.000\\",\\"test-452\\",\\"-\\" +\\"Jun 15, 2006 @ 00:00:00.000\\",\\"test-451\\",\\"-\\" +\\"Jun 14, 2006 @ 00:00:00.000\\",\\"test-450\\",\\"-\\" +\\"Jun 13, 2006 @ 00:00:00.000\\",\\"test-449\\",\\"-\\" +\\"Jun 12, 2006 @ 00:00:00.000\\",\\"test-448\\",\\"-\\" +\\"Jun 11, 2006 @ 00:00:00.000\\",\\"test-447\\",\\"-\\" +\\"Jun 10, 2006 @ 00:00:00.000\\",\\"test-446\\",\\"-\\" +\\"Jun 9, 2006 @ 00:00:00.000\\",\\"test-445\\",\\"-\\" +\\"Jun 8, 2006 @ 00:00:00.000\\",\\"test-444\\",\\"-\\" +\\"Jun 7, 2006 @ 00:00:00.000\\",\\"test-443\\",\\"-\\" +\\"Jun 6, 2006 @ 00:00:00.000\\",\\"test-442\\",\\"-\\" +\\"Jun 5, 2006 @ 00:00:00.000\\",\\"test-441\\",\\"-\\" +\\"Jun 4, 2006 @ 00:00:00.000\\",\\"test-440\\",\\"-\\" +\\"Jun 3, 2006 @ 00:00:00.000\\",\\"test-439\\",\\"-\\" +\\"Jun 2, 2006 @ 00:00:00.000\\",\\"test-438\\",\\"-\\" +\\"Jun 1, 2006 @ 00:00:00.000\\",\\"test-437\\",\\"-\\" +\\"May 31, 2006 @ 00:00:00.000\\",\\"test-436\\",\\"-\\" +\\"May 30, 2006 @ 00:00:00.000\\",\\"test-435\\",\\"-\\" +\\"May 29, 2006 @ 00:00:00.000\\",\\"test-434\\",\\"-\\" +\\"May 28, 2006 @ 00:00:00.000\\",\\"test-433\\",\\"-\\" +\\"May 27, 2006 @ 00:00:00.000\\",\\"test-432\\",\\"-\\" +\\"May 26, 2006 @ 00:00:00.000\\",\\"test-431\\",\\"-\\" +\\"May 25, 2006 @ 00:00:00.000\\",\\"test-430\\",\\"-\\" +\\"May 24, 2006 @ 00:00:00.000\\",\\"test-429\\",\\"-\\" +\\"May 23, 2006 @ 00:00:00.000\\",\\"test-428\\",\\"-\\" +\\"May 22, 2006 @ 00:00:00.000\\",\\"test-427\\",\\"-\\" +\\"May 21, 2006 @ 00:00:00.000\\",\\"test-426\\",\\"-\\" +\\"May 20, 2006 @ 00:00:00.000\\",\\"test-425\\",\\"-\\" +\\"May 19, 2006 @ 00:00:00.000\\",\\"test-424\\",\\"-\\" +\\"May 18, 2006 @ 00:00:00.000\\",\\"test-423\\",\\"-\\" +\\"May 17, 2006 @ 00:00:00.000\\",\\"test-422\\",\\"-\\" +\\"May 16, 2006 @ 00:00:00.000\\",\\"test-421\\",\\"-\\" +\\"May 15, 2006 @ 00:00:00.000\\",\\"test-420\\",\\"-\\" +\\"May 14, 2006 @ 00:00:00.000\\",\\"test-419\\",\\"-\\" +\\"May 13, 2006 @ 00:00:00.000\\",\\"test-418\\",\\"-\\" +\\"May 12, 2006 @ 00:00:00.000\\",\\"test-417\\",\\"-\\" +\\"May 11, 2006 @ 00:00:00.000\\",\\"test-416\\",\\"-\\" +\\"May 10, 2006 @ 00:00:00.000\\",\\"test-415\\",\\"-\\" +\\"May 9, 2006 @ 00:00:00.000\\",\\"test-414\\",\\"-\\" +\\"May 8, 2006 @ 00:00:00.000\\",\\"test-413\\",\\"-\\" +\\"May 7, 2006 @ 00:00:00.000\\",\\"test-412\\",\\"-\\" +\\"May 6, 2006 @ 00:00:00.000\\",\\"test-411\\",\\"-\\" +\\"May 5, 2006 @ 00:00:00.000\\",\\"test-410\\",\\"-\\" +\\"May 4, 2006 @ 00:00:00.000\\",\\"test-409\\",\\"-\\" +\\"May 3, 2006 @ 00:00:00.000\\",\\"test-408\\",\\"-\\" +\\"May 2, 2006 @ 00:00:00.000\\",\\"test-407\\",\\"-\\" +\\"May 1, 2006 @ 00:00:00.000\\",\\"test-406\\",\\"-\\" +\\"Apr 30, 2006 @ 00:00:00.000\\",\\"test-405\\",\\"-\\" +\\"Apr 29, 2006 @ 00:00:00.000\\",\\"test-404\\",\\"-\\" +\\"Apr 28, 2006 @ 00:00:00.000\\",\\"test-403\\",\\"-\\" +\\"Apr 27, 2006 @ 00:00:00.000\\",\\"test-402\\",\\"-\\" +\\"Apr 26, 2006 @ 00:00:00.000\\",\\"test-401\\",\\"-\\" +\\"Apr 25, 2006 @ 00:00:00.000\\",\\"test-400\\",\\"-\\" +\\"Apr 24, 2006 @ 00:00:00.000\\",\\"test-399\\",\\"-\\" +\\"Apr 23, 2006 @ 00:00:00.000\\",\\"test-398\\",\\"-\\" +\\"Apr 22, 2006 @ 00:00:00.000\\",\\"test-397\\",\\"-\\" +\\"Apr 21, 2006 @ 00:00:00.000\\",\\"test-396\\",\\"-\\" +\\"Apr 20, 2006 @ 00:00:00.000\\",\\"test-395\\",\\"-\\" +\\"Apr 19, 2006 @ 00:00:00.000\\",\\"test-394\\",\\"-\\" +\\"Apr 18, 2006 @ 00:00:00.000\\",\\"test-393\\",\\"-\\" +\\"Apr 17, 2006 @ 00:00:00.000\\",\\"test-392\\",\\"-\\" +\\"Apr 16, 2006 @ 00:00:00.000\\",\\"test-391\\",\\"-\\" +\\"Apr 15, 2006 @ 00:00:00.000\\",\\"test-390\\",\\"-\\" +\\"Apr 14, 2006 @ 00:00:00.000\\",\\"test-389\\",\\"-\\" +\\"Apr 13, 2006 @ 00:00:00.000\\",\\"test-388\\",\\"-\\" +\\"Apr 12, 2006 @ 00:00:00.000\\",\\"test-387\\",\\"-\\" +\\"Apr 11, 2006 @ 00:00:00.000\\",\\"test-386\\",\\"-\\" +\\"Apr 10, 2006 @ 00:00:00.000\\",\\"test-385\\",\\"-\\" +\\"Apr 9, 2006 @ 00:00:00.000\\",\\"test-384\\",\\"-\\" +\\"Apr 8, 2006 @ 00:00:00.000\\",\\"test-383\\",\\"-\\" +\\"Apr 7, 2006 @ 00:00:00.000\\",\\"test-382\\",\\"-\\" +\\"Apr 6, 2006 @ 00:00:00.000\\",\\"test-381\\",\\"-\\" +\\"Apr 5, 2006 @ 00:00:00.000\\",\\"test-380\\",\\"-\\" +\\"Apr 4, 2006 @ 00:00:00.000\\",\\"test-379\\",\\"-\\" +\\"Apr 3, 2006 @ 00:00:00.000\\",\\"test-378\\",\\"-\\" +\\"Apr 2, 2006 @ 00:00:00.000\\",\\"test-377\\",\\"-\\" +\\"Apr 1, 2006 @ 00:00:00.000\\",\\"test-376\\",\\"-\\" +\\"Mar 31, 2006 @ 00:00:00.000\\",\\"test-375\\",\\"-\\" +\\"Mar 30, 2006 @ 00:00:00.000\\",\\"test-374\\",\\"-\\" +\\"Mar 29, 2006 @ 00:00:00.000\\",\\"test-373\\",\\"-\\" +\\"Mar 28, 2006 @ 00:00:00.000\\",\\"test-372\\",\\"-\\" +\\"Mar 27, 2006 @ 00:00:00.000\\",\\"test-371\\",\\"-\\" +\\"Mar 26, 2006 @ 00:00:00.000\\",\\"test-370\\",\\"-\\" +\\"Mar 25, 2006 @ 00:00:00.000\\",\\"test-369\\",\\"-\\" +\\"Mar 24, 2006 @ 00:00:00.000\\",\\"test-368\\",\\"-\\" +\\"Mar 23, 2006 @ 00:00:00.000\\",\\"test-367\\",\\"-\\" +\\"Mar 22, 2006 @ 00:00:00.000\\",\\"test-366\\",\\"-\\" +\\"Mar 21, 2006 @ 00:00:00.000\\",\\"test-365\\",\\"-\\" +\\"Mar 20, 2006 @ 00:00:00.000\\",\\"test-364\\",\\"-\\" +\\"Mar 19, 2006 @ 00:00:00.000\\",\\"test-363\\",\\"-\\" +\\"Mar 18, 2006 @ 00:00:00.000\\",\\"test-362\\",\\"-\\" +\\"Mar 17, 2006 @ 00:00:00.000\\",\\"test-361\\",\\"-\\" +\\"Mar 16, 2006 @ 00:00:00.000\\",\\"test-360\\",\\"-\\" +\\"Mar 15, 2006 @ 00:00:00.000\\",\\"test-359\\",\\"-\\" +\\"Mar 14, 2006 @ 00:00:00.000\\",\\"test-358\\",\\"-\\" +\\"Mar 13, 2006 @ 00:00:00.000\\",\\"test-357\\",\\"-\\" +\\"Mar 12, 2006 @ 00:00:00.000\\",\\"test-356\\",\\"-\\" +\\"Mar 11, 2006 @ 00:00:00.000\\",\\"test-355\\",\\"-\\" +\\"Mar 10, 2006 @ 00:00:00.000\\",\\"test-354\\",\\"-\\" +\\"Mar 9, 2006 @ 00:00:00.000\\",\\"test-353\\",\\"-\\" +\\"Mar 8, 2006 @ 00:00:00.000\\",\\"test-352\\",\\"-\\" +\\"Mar 7, 2006 @ 00:00:00.000\\",\\"test-351\\",\\"-\\" +\\"Mar 6, 2006 @ 00:00:00.000\\",\\"test-350\\",\\"-\\" +\\"Mar 5, 2006 @ 00:00:00.000\\",\\"test-349\\",\\"-\\" +\\"Mar 4, 2006 @ 00:00:00.000\\",\\"test-348\\",\\"-\\" +\\"Mar 3, 2006 @ 00:00:00.000\\",\\"test-347\\",\\"-\\" +\\"Mar 2, 2006 @ 00:00:00.000\\",\\"test-346\\",\\"-\\" +\\"Mar 1, 2006 @ 00:00:00.000\\",\\"test-345\\",\\"-\\" +\\"Feb 28, 2006 @ 00:00:00.000\\",\\"test-344\\",\\"-\\" +\\"Feb 27, 2006 @ 00:00:00.000\\",\\"test-343\\",\\"-\\" +\\"Feb 26, 2006 @ 00:00:00.000\\",\\"test-342\\",\\"-\\" +\\"Feb 25, 2006 @ 00:00:00.000\\",\\"test-341\\",\\"-\\" +\\"Feb 24, 2006 @ 00:00:00.000\\",\\"test-340\\",\\"-\\" +\\"Feb 23, 2006 @ 00:00:00.000\\",\\"test-339\\",\\"-\\" +\\"Feb 22, 2006 @ 00:00:00.000\\",\\"test-338\\",\\"-\\" +\\"Feb 21, 2006 @ 00:00:00.000\\",\\"test-337\\",\\"-\\" +\\"Feb 20, 2006 @ 00:00:00.000\\",\\"test-336\\",\\"-\\" +\\"Feb 19, 2006 @ 00:00:00.000\\",\\"test-335\\",\\"-\\" +\\"Feb 18, 2006 @ 00:00:00.000\\",\\"test-334\\",\\"-\\" +\\"Feb 17, 2006 @ 00:00:00.000\\",\\"test-333\\",\\"-\\" +\\"Feb 16, 2006 @ 00:00:00.000\\",\\"test-332\\",\\"-\\" +\\"Feb 15, 2006 @ 00:00:00.000\\",\\"test-331\\",\\"-\\" +\\"Feb 14, 2006 @ 00:00:00.000\\",\\"test-330\\",\\"-\\" +\\"Feb 13, 2006 @ 00:00:00.000\\",\\"test-329\\",\\"-\\" +\\"Feb 12, 2006 @ 00:00:00.000\\",\\"test-328\\",\\"-\\" +\\"Feb 11, 2006 @ 00:00:00.000\\",\\"test-327\\",\\"-\\" +\\"Feb 10, 2006 @ 00:00:00.000\\",\\"test-326\\",\\"-\\" +\\"Feb 9, 2006 @ 00:00:00.000\\",\\"test-325\\",\\"-\\" +\\"Feb 8, 2006 @ 00:00:00.000\\",\\"test-324\\",\\"-\\" +\\"Feb 7, 2006 @ 00:00:00.000\\",\\"test-323\\",\\"-\\" +\\"Feb 6, 2006 @ 00:00:00.000\\",\\"test-322\\",\\"-\\" +\\"Feb 5, 2006 @ 00:00:00.000\\",\\"test-321\\",\\"-\\" +\\"Feb 4, 2006 @ 00:00:00.000\\",\\"test-320\\",\\"-\\" +\\"Feb 3, 2006 @ 00:00:00.000\\",\\"test-319\\",\\"-\\" +\\"Feb 2, 2006 @ 00:00:00.000\\",\\"test-318\\",\\"-\\" +\\"Feb 1, 2006 @ 00:00:00.000\\",\\"test-317\\",\\"-\\" +\\"Jan 31, 2006 @ 00:00:00.000\\",\\"test-316\\",\\"-\\" +\\"Jan 30, 2006 @ 00:00:00.000\\",\\"test-315\\",\\"-\\" +\\"Jan 29, 2006 @ 00:00:00.000\\",\\"test-314\\",\\"-\\" +\\"Jan 28, 2006 @ 00:00:00.000\\",\\"test-313\\",\\"-\\" +\\"Jan 27, 2006 @ 00:00:00.000\\",\\"test-312\\",\\"-\\" +\\"Jan 26, 2006 @ 00:00:00.000\\",\\"test-311\\",\\"-\\" +\\"Jan 25, 2006 @ 00:00:00.000\\",\\"test-310\\",\\"-\\" +\\"Jan 24, 2006 @ 00:00:00.000\\",\\"test-309\\",\\"-\\" +\\"Jan 23, 2006 @ 00:00:00.000\\",\\"test-308\\",\\"-\\" +\\"Jan 22, 2006 @ 00:00:00.000\\",\\"test-307\\",\\"-\\" +\\"Jan 21, 2006 @ 00:00:00.000\\",\\"test-306\\",\\"-\\" +\\"Jan 20, 2006 @ 00:00:00.000\\",\\"test-305\\",\\"-\\" +\\"Jan 19, 2006 @ 00:00:00.000\\",\\"test-304\\",\\"-\\" +\\"Jan 18, 2006 @ 00:00:00.000\\",\\"test-303\\",\\"-\\" +\\"Jan 17, 2006 @ 00:00:00.000\\",\\"test-302\\",\\"-\\" +\\"Jan 16, 2006 @ 00:00:00.000\\",\\"test-301\\",\\"-\\" +\\"Jan 15, 2006 @ 00:00:00.000\\",\\"test-300\\",\\"-\\" +\\"Jan 14, 2006 @ 00:00:00.000\\",\\"test-299\\",\\"-\\" +\\"Jan 13, 2006 @ 00:00:00.000\\",\\"test-298\\",\\"-\\" +\\"Jan 12, 2006 @ 00:00:00.000\\",\\"test-297\\",\\"-\\" +\\"Jan 11, 2006 @ 00:00:00.000\\",\\"test-296\\",\\"-\\" +\\"Jan 10, 2006 @ 00:00:00.000\\",\\"test-295\\",\\"-\\" +\\"Jan 9, 2006 @ 00:00:00.000\\",\\"test-294\\",\\"-\\" +\\"Jan 8, 2006 @ 00:00:00.000\\",\\"test-293\\",\\"-\\" +\\"Jan 7, 2006 @ 00:00:00.000\\",\\"test-292\\",\\"-\\" +\\"Jan 6, 2006 @ 00:00:00.000\\",\\"test-291\\",\\"-\\" +\\"Jan 5, 2006 @ 00:00:00.000\\",\\"test-290\\",\\"-\\" +\\"Jan 4, 2006 @ 00:00:00.000\\",\\"test-289\\",\\"-\\" +\\"Jan 3, 2006 @ 00:00:00.000\\",\\"test-288\\",\\"-\\" +\\"Jan 2, 2006 @ 00:00:00.000\\",\\"test-287\\",\\"-\\" +\\"Jan 1, 2006 @ 00:00:00.000\\",\\"test-286\\",\\"-\\" +\\"Dec 31, 2005 @ 00:00:00.000\\",\\"test-285\\",\\"-\\" +\\"Dec 30, 2005 @ 00:00:00.000\\",\\"test-284\\",\\"-\\" +\\"Dec 29, 2005 @ 00:00:00.000\\",\\"test-283\\",\\"-\\" +\\"Dec 28, 2005 @ 00:00:00.000\\",\\"test-282\\",\\"-\\" +\\"Dec 27, 2005 @ 00:00:00.000\\",\\"test-281\\",\\"-\\" +\\"Dec 26, 2005 @ 00:00:00.000\\",\\"test-280\\",\\"-\\" +\\"Dec 25, 2005 @ 00:00:00.000\\",\\"test-279\\",\\"-\\" +\\"Dec 24, 2005 @ 00:00:00.000\\",\\"test-278\\",\\"-\\" +\\"Dec 23, 2005 @ 00:00:00.000\\",\\"test-277\\",\\"-\\" +\\"Dec 22, 2005 @ 00:00:00.000\\",\\"test-276\\",\\"-\\" +\\"Dec 21, 2005 @ 00:00:00.000\\",\\"test-275\\",\\"-\\" +\\"Dec 20, 2005 @ 00:00:00.000\\",\\"test-274\\",\\"-\\" +\\"Dec 19, 2005 @ 00:00:00.000\\",\\"test-273\\",\\"-\\" +\\"Dec 18, 2005 @ 00:00:00.000\\",\\"test-272\\",\\"-\\" +\\"Dec 17, 2005 @ 00:00:00.000\\",\\"test-271\\",\\"-\\" +\\"Dec 16, 2005 @ 00:00:00.000\\",\\"test-270\\",\\"-\\" +\\"Dec 15, 2005 @ 00:00:00.000\\",\\"test-269\\",\\"-\\" +\\"Dec 14, 2005 @ 00:00:00.000\\",\\"test-268\\",\\"-\\" +\\"Dec 13, 2005 @ 00:00:00.000\\",\\"test-267\\",\\"-\\" +\\"Dec 12, 2005 @ 00:00:00.000\\",\\"test-266\\",\\"-\\" +\\"Dec 11, 2005 @ 00:00:00.000\\",\\"test-265\\",\\"-\\" +\\"Dec 10, 2005 @ 00:00:00.000\\",\\"test-264\\",\\"-\\" +\\"Dec 9, 2005 @ 00:00:00.000\\",\\"test-263\\",\\"-\\" +\\"Dec 8, 2005 @ 00:00:00.000\\",\\"test-262\\",\\"-\\" +\\"Dec 7, 2005 @ 00:00:00.000\\",\\"test-261\\",\\"-\\" +\\"Dec 6, 2005 @ 00:00:00.000\\",\\"test-260\\",\\"-\\" +\\"Dec 5, 2005 @ 00:00:00.000\\",\\"test-259\\",\\"-\\" +\\"Dec 4, 2005 @ 00:00:00.000\\",\\"test-258\\",\\"-\\" +\\"Dec 3, 2005 @ 00:00:00.000\\",\\"test-257\\",\\"-\\" +\\"Dec 2, 2005 @ 00:00:00.000\\",\\"test-256\\",\\"-\\" +\\"Dec 1, 2005 @ 00:00:00.000\\",\\"test-255\\",\\"-\\" +\\"Nov 30, 2005 @ 00:00:00.000\\",\\"test-254\\",\\"-\\" +\\"Nov 29, 2005 @ 00:00:00.000\\",\\"test-253\\",\\"-\\" +\\"Nov 28, 2005 @ 00:00:00.000\\",\\"test-252\\",\\"-\\" +\\"Nov 27, 2005 @ 00:00:00.000\\",\\"test-251\\",\\"-\\" +\\"Nov 26, 2005 @ 00:00:00.000\\",\\"test-250\\",\\"-\\" +\\"Nov 25, 2005 @ 00:00:00.000\\",\\"test-249\\",\\"-\\" +\\"Nov 24, 2005 @ 00:00:00.000\\",\\"test-248\\",\\"-\\" +\\"Nov 23, 2005 @ 00:00:00.000\\",\\"test-247\\",\\"-\\" +\\"Nov 22, 2005 @ 00:00:00.000\\",\\"test-246\\",\\"-\\" +\\"Nov 21, 2005 @ 00:00:00.000\\",\\"test-245\\",\\"-\\" +\\"Nov 20, 2005 @ 00:00:00.000\\",\\"test-244\\",\\"-\\" +\\"Nov 19, 2005 @ 00:00:00.000\\",\\"test-243\\",\\"-\\" +\\"Nov 18, 2005 @ 00:00:00.000\\",\\"test-242\\",\\"-\\" +\\"Nov 17, 2005 @ 00:00:00.000\\",\\"test-241\\",\\"-\\" +\\"Nov 16, 2005 @ 00:00:00.000\\",\\"test-240\\",\\"-\\" +\\"Nov 15, 2005 @ 00:00:00.000\\",\\"test-239\\",\\"-\\" +\\"Nov 14, 2005 @ 00:00:00.000\\",\\"test-238\\",\\"-\\" +\\"Nov 13, 2005 @ 00:00:00.000\\",\\"test-237\\",\\"-\\" +\\"Nov 12, 2005 @ 00:00:00.000\\",\\"test-236\\",\\"-\\" +\\"Nov 11, 2005 @ 00:00:00.000\\",\\"test-235\\",\\"-\\" +\\"Nov 10, 2005 @ 00:00:00.000\\",\\"test-234\\",\\"-\\" +\\"Nov 9, 2005 @ 00:00:00.000\\",\\"test-233\\",\\"-\\" +\\"Nov 8, 2005 @ 00:00:00.000\\",\\"test-232\\",\\"-\\" +\\"Nov 7, 2005 @ 00:00:00.000\\",\\"test-231\\",\\"-\\" +\\"Nov 6, 2005 @ 00:00:00.000\\",\\"test-230\\",\\"-\\" +\\"Nov 5, 2005 @ 00:00:00.000\\",\\"test-229\\",\\"-\\" +\\"Nov 4, 2005 @ 00:00:00.000\\",\\"test-228\\",\\"-\\" +\\"Nov 3, 2005 @ 00:00:00.000\\",\\"test-227\\",\\"-\\" +\\"Nov 2, 2005 @ 00:00:00.000\\",\\"test-226\\",\\"-\\" +\\"Nov 1, 2005 @ 00:00:00.000\\",\\"test-225\\",\\"-\\" +\\"Oct 31, 2005 @ 00:00:00.000\\",\\"test-224\\",\\"-\\" +\\"Oct 30, 2005 @ 00:00:00.000\\",\\"test-223\\",\\"-\\" +\\"Oct 29, 2005 @ 00:00:00.000\\",\\"test-222\\",\\"-\\" +\\"Oct 28, 2005 @ 00:00:00.000\\",\\"test-221\\",\\"-\\" +\\"Oct 27, 2005 @ 00:00:00.000\\",\\"test-220\\",\\"-\\" +\\"Oct 26, 2005 @ 00:00:00.000\\",\\"test-219\\",\\"-\\" +\\"Oct 25, 2005 @ 00:00:00.000\\",\\"test-218\\",\\"-\\" +\\"Oct 24, 2005 @ 00:00:00.000\\",\\"test-217\\",\\"-\\" +\\"Oct 23, 2005 @ 00:00:00.000\\",\\"test-216\\",\\"-\\" +\\"Oct 22, 2005 @ 00:00:00.000\\",\\"test-215\\",\\"-\\" +\\"Oct 21, 2005 @ 00:00:00.000\\",\\"test-214\\",\\"-\\" +\\"Oct 20, 2005 @ 00:00:00.000\\",\\"test-213\\",\\"-\\" +\\"Oct 19, 2005 @ 00:00:00.000\\",\\"test-212\\",\\"-\\" +\\"Oct 18, 2005 @ 00:00:00.000\\",\\"test-211\\",\\"-\\" +\\"Oct 17, 2005 @ 00:00:00.000\\",\\"test-210\\",\\"-\\" +\\"Oct 16, 2005 @ 00:00:00.000\\",\\"test-209\\",\\"-\\" +\\"Oct 15, 2005 @ 00:00:00.000\\",\\"test-208\\",\\"-\\" +\\"Oct 14, 2005 @ 00:00:00.000\\",\\"test-207\\",\\"-\\" +\\"Oct 13, 2005 @ 00:00:00.000\\",\\"test-206\\",\\"-\\" +\\"Oct 12, 2005 @ 00:00:00.000\\",\\"test-205\\",\\"-\\" +\\"Oct 11, 2005 @ 00:00:00.000\\",\\"test-204\\",\\"-\\" +\\"Oct 10, 2005 @ 00:00:00.000\\",\\"test-203\\",\\"-\\" +\\"Oct 9, 2005 @ 00:00:00.000\\",\\"test-202\\",\\"-\\" +\\"Oct 8, 2005 @ 00:00:00.000\\",\\"test-201\\",\\"-\\" +\\"Oct 7, 2005 @ 00:00:00.000\\",\\"test-200\\",\\"-\\" +\\"Oct 6, 2005 @ 00:00:00.000\\",\\"test-199\\",\\"-\\" +\\"Oct 5, 2005 @ 00:00:00.000\\",\\"test-198\\",\\"-\\" +\\"Oct 4, 2005 @ 00:00:00.000\\",\\"test-197\\",\\"-\\" +\\"Oct 3, 2005 @ 00:00:00.000\\",\\"test-196\\",\\"-\\" +\\"Oct 2, 2005 @ 00:00:00.000\\",\\"test-195\\",\\"-\\" +\\"Oct 1, 2005 @ 00:00:00.000\\",\\"test-194\\",\\"-\\" +\\"Sep 30, 2005 @ 00:00:00.000\\",\\"test-193\\",\\"-\\" +\\"Sep 29, 2005 @ 00:00:00.000\\",\\"test-192\\",\\"-\\" +\\"Sep 28, 2005 @ 00:00:00.000\\",\\"test-191\\",\\"-\\" +\\"Sep 27, 2005 @ 00:00:00.000\\",\\"test-190\\",\\"-\\" +\\"Sep 26, 2005 @ 00:00:00.000\\",\\"test-189\\",\\"-\\" +\\"Sep 25, 2005 @ 00:00:00.000\\",\\"test-188\\",\\"-\\" +\\"Sep 24, 2005 @ 00:00:00.000\\",\\"test-187\\",\\"-\\" +\\"Sep 23, 2005 @ 00:00:00.000\\",\\"test-186\\",\\"-\\" +\\"Sep 22, 2005 @ 00:00:00.000\\",\\"test-185\\",\\"-\\" +\\"Sep 21, 2005 @ 00:00:00.000\\",\\"test-184\\",\\"-\\" +\\"Sep 20, 2005 @ 00:00:00.000\\",\\"test-183\\",\\"-\\" +\\"Sep 19, 2005 @ 00:00:00.000\\",\\"test-182\\",\\"-\\" +\\"Sep 18, 2005 @ 00:00:00.000\\",\\"test-181\\",\\"-\\" +\\"Sep 17, 2005 @ 00:00:00.000\\",\\"test-180\\",\\"-\\" +\\"Sep 16, 2005 @ 00:00:00.000\\",\\"test-179\\",\\"-\\" +\\"Sep 15, 2005 @ 00:00:00.000\\",\\"test-178\\",\\"-\\" +\\"Sep 14, 2005 @ 00:00:00.000\\",\\"test-177\\",\\"-\\" +\\"Sep 13, 2005 @ 00:00:00.000\\",\\"test-176\\",\\"-\\" +\\"Sep 12, 2005 @ 00:00:00.000\\",\\"test-175\\",\\"-\\" +\\"Sep 11, 2005 @ 00:00:00.000\\",\\"test-174\\",\\"-\\" +\\"Sep 10, 2005 @ 00:00:00.000\\",\\"test-173\\",\\"-\\" +\\"Sep 9, 2005 @ 00:00:00.000\\",\\"test-172\\",\\"-\\" +\\"Sep 8, 2005 @ 00:00:00.000\\",\\"test-171\\",\\"-\\" +\\"Sep 7, 2005 @ 00:00:00.000\\",\\"test-170\\",\\"-\\" +\\"Sep 6, 2005 @ 00:00:00.000\\",\\"test-169\\",\\"-\\" +\\"Sep 5, 2005 @ 00:00:00.000\\",\\"test-168\\",\\"-\\" +\\"Sep 4, 2005 @ 00:00:00.000\\",\\"test-167\\",\\"-\\" +\\"Sep 3, 2005 @ 00:00:00.000\\",\\"test-166\\",\\"-\\" +\\"Sep 2, 2005 @ 00:00:00.000\\",\\"test-165\\",\\"-\\" +\\"Sep 1, 2005 @ 00:00:00.000\\",\\"test-164\\",\\"-\\" +\\"Aug 31, 2005 @ 00:00:00.000\\",\\"test-163\\",\\"-\\" +\\"Aug 30, 2005 @ 00:00:00.000\\",\\"test-162\\",\\"-\\" +\\"Aug 29, 2005 @ 00:00:00.000\\",\\"test-161\\",\\"-\\" +\\"Aug 28, 2005 @ 00:00:00.000\\",\\"test-160\\",\\"-\\" +\\"Aug 27, 2005 @ 00:00:00.000\\",\\"test-159\\",\\"-\\" +\\"Aug 26, 2005 @ 00:00:00.000\\",\\"test-158\\",\\"-\\" +\\"Aug 25, 2005 @ 00:00:00.000\\",\\"test-157\\",\\"-\\" +\\"Aug 24, 2005 @ 00:00:00.000\\",\\"test-156\\",\\"-\\" +\\"Aug 23, 2005 @ 00:00:00.000\\",\\"test-155\\",\\"-\\" +\\"Aug 22, 2005 @ 00:00:00.000\\",\\"test-154\\",\\"-\\" +\\"Aug 21, 2005 @ 00:00:00.000\\",\\"test-153\\",\\"-\\" +\\"Aug 20, 2005 @ 00:00:00.000\\",\\"test-152\\",\\"-\\" +\\"Aug 19, 2005 @ 00:00:00.000\\",\\"test-151\\",\\"-\\" +\\"Aug 18, 2005 @ 00:00:00.000\\",\\"test-150\\",\\"-\\" +\\"Aug 17, 2005 @ 00:00:00.000\\",\\"test-149\\",\\"-\\" +\\"Aug 16, 2005 @ 00:00:00.000\\",\\"test-148\\",\\"-\\" +\\"Aug 15, 2005 @ 00:00:00.000\\",\\"test-147\\",\\"-\\" +\\"Aug 14, 2005 @ 00:00:00.000\\",\\"test-146\\",\\"-\\" +\\"Aug 13, 2005 @ 00:00:00.000\\",\\"test-145\\",\\"-\\" +\\"Aug 12, 2005 @ 00:00:00.000\\",\\"test-144\\",\\"-\\" +\\"Aug 11, 2005 @ 00:00:00.000\\",\\"test-143\\",\\"-\\" +\\"Aug 10, 2005 @ 00:00:00.000\\",\\"test-142\\",\\"-\\" +\\"Aug 9, 2005 @ 00:00:00.000\\",\\"test-141\\",\\"-\\" +\\"Aug 8, 2005 @ 00:00:00.000\\",\\"test-140\\",\\"-\\" +\\"Aug 7, 2005 @ 00:00:00.000\\",\\"test-139\\",\\"-\\" +\\"Aug 6, 2005 @ 00:00:00.000\\",\\"test-138\\",\\"-\\" +\\"Aug 5, 2005 @ 00:00:00.000\\",\\"test-137\\",\\"-\\" +\\"Aug 4, 2005 @ 00:00:00.000\\",\\"test-136\\",\\"-\\" +\\"Aug 3, 2005 @ 00:00:00.000\\",\\"test-135\\",\\"-\\" +\\"Aug 2, 2005 @ 00:00:00.000\\",\\"test-134\\",\\"-\\" +\\"Aug 1, 2005 @ 00:00:00.000\\",\\"test-133\\",\\"-\\" +\\"Jul 31, 2005 @ 00:00:00.000\\",\\"test-132\\",\\"-\\" +\\"Jul 30, 2005 @ 00:00:00.000\\",\\"test-131\\",\\"-\\" +\\"Jul 29, 2005 @ 00:00:00.000\\",\\"test-130\\",\\"-\\" +\\"Jul 28, 2005 @ 00:00:00.000\\",\\"test-129\\",\\"-\\" +\\"Jul 27, 2005 @ 00:00:00.000\\",\\"test-128\\",\\"-\\" +\\"Jul 26, 2005 @ 00:00:00.000\\",\\"test-127\\",\\"-\\" +\\"Jul 25, 2005 @ 00:00:00.000\\",\\"test-126\\",\\"-\\" +\\"Jul 24, 2005 @ 00:00:00.000\\",\\"test-125\\",\\"-\\" +\\"Jul 23, 2005 @ 00:00:00.000\\",\\"test-124\\",\\"-\\" +\\"Jul 22, 2005 @ 00:00:00.000\\",\\"test-123\\",\\"-\\" +\\"Jul 21, 2005 @ 00:00:00.000\\",\\"test-122\\",\\"-\\" +\\"Jul 20, 2005 @ 00:00:00.000\\",\\"test-121\\",\\"-\\" +\\"Jul 19, 2005 @ 00:00:00.000\\",\\"test-120\\",\\"-\\" +\\"Jul 18, 2005 @ 00:00:00.000\\",\\"test-119\\",\\"-\\" +\\"Jul 17, 2005 @ 00:00:00.000\\",\\"test-118\\",\\"-\\" +\\"Jul 16, 2005 @ 00:00:00.000\\",\\"test-117\\",\\"-\\" +\\"Jul 15, 2005 @ 00:00:00.000\\",\\"test-116\\",\\"-\\" +\\"Jul 14, 2005 @ 00:00:00.000\\",\\"test-115\\",\\"-\\" +\\"Jul 13, 2005 @ 00:00:00.000\\",\\"test-114\\",\\"-\\" +\\"Jul 12, 2005 @ 00:00:00.000\\",\\"test-113\\",\\"-\\" +\\"Jul 11, 2005 @ 00:00:00.000\\",\\"test-112\\",\\"-\\" +\\"Jul 10, 2005 @ 00:00:00.000\\",\\"test-111\\",\\"-\\" +\\"Jul 9, 2005 @ 00:00:00.000\\",\\"test-110\\",\\"-\\" +\\"Jul 8, 2005 @ 00:00:00.000\\",\\"test-109\\",\\"-\\" +\\"Jul 7, 2005 @ 00:00:00.000\\",\\"test-108\\",\\"-\\" +\\"Jul 6, 2005 @ 00:00:00.000\\",\\"test-107\\",\\"-\\" +\\"Jul 5, 2005 @ 00:00:00.000\\",\\"test-106\\",\\"-\\" +\\"Jul 4, 2005 @ 00:00:00.000\\",\\"test-105\\",\\"-\\" +\\"Jul 3, 2005 @ 00:00:00.000\\",\\"test-104\\",\\"-\\" +\\"Jul 2, 2005 @ 00:00:00.000\\",\\"test-103\\",\\"-\\" +\\"Jul 1, 2005 @ 00:00:00.000\\",\\"test-102\\",\\"-\\" +\\"Jun 30, 2005 @ 00:00:00.000\\",\\"test-101\\",\\"-\\" +\\"Jun 29, 2005 @ 00:00:00.000\\",\\"test-100\\",\\"-\\" +\\"Jun 28, 2005 @ 00:00:00.000\\",\\"test-99\\",\\"-\\" +\\"Jun 27, 2005 @ 00:00:00.000\\",\\"test-98\\",\\"-\\" +\\"Jun 26, 2005 @ 00:00:00.000\\",\\"test-97\\",\\"-\\" +\\"Jun 25, 2005 @ 00:00:00.000\\",\\"test-96\\",\\"-\\" +\\"Jun 24, 2005 @ 00:00:00.000\\",\\"test-95\\",\\"-\\" +\\"Jun 23, 2005 @ 00:00:00.000\\",\\"test-94\\",\\"-\\" +\\"Jun 22, 2005 @ 00:00:00.000\\",\\"test-93\\",\\"-\\" +\\"Jun 21, 2005 @ 00:00:00.000\\",\\"test-92\\",\\"-\\" +\\"Jun 20, 2005 @ 00:00:00.000\\",\\"test-91\\",\\"-\\" +\\"Jun 19, 2005 @ 00:00:00.000\\",\\"test-90\\",\\"-\\" +\\"Jun 18, 2005 @ 00:00:00.000\\",\\"test-89\\",\\"-\\" +\\"Jun 17, 2005 @ 00:00:00.000\\",\\"test-88\\",\\"-\\" +\\"Jun 16, 2005 @ 00:00:00.000\\",\\"test-87\\",\\"-\\" +\\"Jun 15, 2005 @ 00:00:00.000\\",\\"test-86\\",\\"-\\" +\\"Jun 14, 2005 @ 00:00:00.000\\",\\"test-85\\",\\"-\\" +\\"Jun 13, 2005 @ 00:00:00.000\\",\\"test-84\\",\\"-\\" +\\"Jun 12, 2005 @ 00:00:00.000\\",\\"test-83\\",\\"-\\" +\\"Jun 11, 2005 @ 00:00:00.000\\",\\"test-82\\",\\"-\\" +\\"Jun 10, 2005 @ 00:00:00.000\\",\\"test-81\\",\\"-\\" +\\"Jun 9, 2005 @ 00:00:00.000\\",\\"test-80\\",\\"-\\" +\\"Jun 8, 2005 @ 00:00:00.000\\",\\"test-79\\",\\"-\\" +\\"Jun 7, 2005 @ 00:00:00.000\\",\\"test-78\\",\\"-\\" +\\"Jun 6, 2005 @ 00:00:00.000\\",\\"test-77\\",\\"-\\" +\\"Jun 5, 2005 @ 00:00:00.000\\",\\"test-76\\",\\"-\\" +\\"Jun 4, 2005 @ 00:00:00.000\\",\\"test-75\\",\\"-\\" +\\"Jun 3, 2005 @ 00:00:00.000\\",\\"test-74\\",\\"-\\" +\\"Jun 2, 2005 @ 00:00:00.000\\",\\"test-73\\",\\"-\\" +\\"Jun 1, 2005 @ 00:00:00.000\\",\\"test-72\\",\\"-\\" +\\"May 31, 2005 @ 00:00:00.000\\",\\"test-71\\",\\"-\\" +\\"May 30, 2005 @ 00:00:00.000\\",\\"test-70\\",\\"-\\" +\\"May 29, 2005 @ 00:00:00.000\\",\\"test-69\\",\\"-\\" +\\"May 28, 2005 @ 00:00:00.000\\",\\"test-68\\",\\"-\\" +\\"May 27, 2005 @ 00:00:00.000\\",\\"test-67\\",\\"-\\" +\\"May 26, 2005 @ 00:00:00.000\\",\\"test-66\\",\\"-\\" +\\"May 25, 2005 @ 00:00:00.000\\",\\"test-65\\",\\"-\\" +\\"May 24, 2005 @ 00:00:00.000\\",\\"test-64\\",\\"-\\" +\\"May 23, 2005 @ 00:00:00.000\\",\\"test-63\\",\\"-\\" +\\"May 22, 2005 @ 00:00:00.000\\",\\"test-62\\",\\"-\\" +\\"May 21, 2005 @ 00:00:00.000\\",\\"test-61\\",\\"-\\" +\\"May 20, 2005 @ 00:00:00.000\\",\\"test-60\\",\\"-\\" +\\"May 19, 2005 @ 00:00:00.000\\",\\"test-59\\",\\"-\\" +\\"May 18, 2005 @ 00:00:00.000\\",\\"test-58\\",\\"-\\" +\\"May 17, 2005 @ 00:00:00.000\\",\\"test-57\\",\\"-\\" +\\"May 16, 2005 @ 00:00:00.000\\",\\"test-56\\",\\"-\\" +\\"May 15, 2005 @ 00:00:00.000\\",\\"test-55\\",\\"-\\" +\\"May 14, 2005 @ 00:00:00.000\\",\\"test-54\\",\\"-\\" +\\"May 13, 2005 @ 00:00:00.000\\",\\"test-53\\",\\"-\\" +\\"May 12, 2005 @ 00:00:00.000\\",\\"test-52\\",\\"-\\" +\\"May 11, 2005 @ 00:00:00.000\\",\\"test-51\\",\\"-\\" +\\"May 10, 2005 @ 00:00:00.000\\",\\"test-50\\",\\"-\\" +\\"May 9, 2005 @ 00:00:00.000\\",\\"test-49\\",\\"-\\" +\\"May 8, 2005 @ 00:00:00.000\\",\\"test-48\\",\\"-\\" +\\"May 7, 2005 @ 00:00:00.000\\",\\"test-47\\",\\"-\\" +\\"May 6, 2005 @ 00:00:00.000\\",\\"test-46\\",\\"-\\" +\\"May 5, 2005 @ 00:00:00.000\\",\\"test-45\\",\\"-\\" +\\"May 4, 2005 @ 00:00:00.000\\",\\"test-44\\",\\"-\\" +\\"May 3, 2005 @ 00:00:00.000\\",\\"test-43\\",\\"-\\" +\\"May 2, 2005 @ 00:00:00.000\\",\\"test-42\\",\\"-\\" +\\"May 1, 2005 @ 00:00:00.000\\",\\"test-41\\",\\"-\\" +\\"Apr 30, 2005 @ 00:00:00.000\\",\\"test-40\\",\\"-\\" +\\"Apr 29, 2005 @ 00:00:00.000\\",\\"test-39\\",\\"-\\" +\\"Apr 28, 2005 @ 00:00:00.000\\",\\"test-38\\",\\"-\\" +\\"Apr 27, 2005 @ 00:00:00.000\\",\\"test-37\\",\\"-\\" +\\"Apr 26, 2005 @ 00:00:00.000\\",\\"test-36\\",\\"-\\" +\\"Apr 25, 2005 @ 00:00:00.000\\",\\"test-35\\",\\"-\\" +\\"Apr 24, 2005 @ 00:00:00.000\\",\\"test-34\\",\\"-\\" +\\"Apr 23, 2005 @ 00:00:00.000\\",\\"test-33\\",\\"-\\" +\\"Apr 22, 2005 @ 00:00:00.000\\",\\"test-32\\",\\"-\\" +\\"Apr 21, 2005 @ 00:00:00.000\\",\\"test-31\\",\\"-\\" +\\"Apr 20, 2005 @ 00:00:00.000\\",\\"test-30\\",\\"-\\" +\\"Apr 19, 2005 @ 00:00:00.000\\",\\"test-29\\",\\"-\\" +\\"Apr 18, 2005 @ 00:00:00.000\\",\\"test-28\\",\\"-\\" +\\"Apr 17, 2005 @ 00:00:00.000\\",\\"test-27\\",\\"-\\" +\\"Apr 16, 2005 @ 00:00:00.000\\",\\"test-26\\",\\"-\\" +\\"Apr 15, 2005 @ 00:00:00.000\\",\\"test-25\\",\\"-\\" +\\"Apr 14, 2005 @ 00:00:00.000\\",\\"test-24\\",\\"-\\" +\\"Apr 13, 2005 @ 00:00:00.000\\",\\"test-23\\",\\"-\\" +\\"Apr 12, 2005 @ 00:00:00.000\\",\\"test-22\\",\\"-\\" +\\"Apr 11, 2005 @ 00:00:00.000\\",\\"test-21\\",\\"-\\" +\\"Apr 10, 2005 @ 00:00:00.000\\",\\"test-20\\",\\"-\\" +\\"Apr 9, 2005 @ 00:00:00.000\\",\\"test-19\\",\\"-\\" +\\"Apr 8, 2005 @ 00:00:00.000\\",\\"test-18\\",\\"-\\" +\\"Apr 7, 2005 @ 00:00:00.000\\",\\"test-17\\",\\"-\\" +\\"Apr 6, 2005 @ 00:00:00.000\\",\\"test-16\\",\\"-\\" +\\"Apr 5, 2005 @ 00:00:00.000\\",\\"test-15\\",\\"-\\" +\\"Apr 4, 2005 @ 00:00:00.000\\",\\"test-14\\",\\"-\\" +\\"Apr 3, 2005 @ 00:00:00.000\\",\\"test-13\\",\\"-\\" +\\"Apr 2, 2005 @ 00:00:00.000\\",\\"test-12\\",\\"-\\" +\\"Apr 1, 2005 @ 00:00:00.000\\",\\"test-11\\",\\"-\\" +\\"Mar 31, 2005 @ 00:00:00.000\\",\\"test-10\\",\\"-\\" +\\"Mar 30, 2005 @ 00:00:00.000\\",\\"test-9\\",\\"-\\" +\\"Mar 29, 2005 @ 00:00:00.000\\",\\"test-8\\",\\"-\\" +\\"Mar 28, 2005 @ 00:00:00.000\\",\\"test-7\\",\\"-\\" +\\"Mar 27, 2005 @ 00:00:00.000\\",\\"test-6\\",\\"-\\" +\\"Mar 26, 2005 @ 00:00:00.000\\",\\"test-5\\",\\"-\\" +\\"Mar 25, 2005 @ 00:00:00.000\\",\\"test-4\\",\\"-\\" +\\"Mar 24, 2005 @ 00:00:00.000\\",\\"test-3\\",\\"-\\" +\\"Mar 23, 2005 @ 00:00:00.000\\",\\"test-2\\",\\"-\\" +\\"Mar 22, 2005 @ 00:00:00.000\\",\\"test-1\\",\\"Aug 14, 2006 @ 00:00:00.000\\" +" +`; diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/index.ts new file mode 100644 index 000000000000..96fad2c47d09 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ loadTestFile, getPageObject }: FtrProviderContext) { + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('discover', function () { + before(async function () { + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + loadTestFile(require.resolve('./reporting')); + loadTestFile(require.resolve('./visualize_field')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts new file mode 100644 index 000000000000..e2a491de828d --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts @@ -0,0 +1,372 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { Key } from 'selenium-webdriver'; +import moment from 'moment'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const reportingAPI = getService('reporting'); + const log = getService('log'); + const es = getService('es'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const browser = getService('browser'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker', 'share']); + const filterBar = getService('filterBar'); + const find = getService('find'); + const testSubjects = getService('testSubjects'); + + const setFieldsFromSource = async (setValue: boolean) => { + await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue }); + await browser.refresh(); + }; + + const getReport = async () => { + // close any open notification toasts + await PageObjects.reporting.clearToastNotifications(); + + await PageObjects.reporting.openCsvReportingPanel(); + await PageObjects.reporting.clickGenerateReportButton(); + + const url = await PageObjects.reporting.getReportURL(60000); + // TODO: Fetch CSV client side in Serverless since `PageObjects.reporting.getResponse()` + // doesn't work because it relies on `SecurityService.testUserSupertest` + const res: { status: number; contentType: string | null; text: string } = + await browser.executeAsync(async (downloadUrl, resolve) => { + const response = await fetch(downloadUrl); + resolve({ + status: response.status, + contentType: response.headers.get('content-type'), + text: await response.text(), + }); + }, url); + + expect(res.status).to.equal(200); + expect(res.contentType).to.equal('text/csv; charset=utf-8'); + return res; + }; + + describe('Discover CSV Export', () => { + describe('Check Available', () => { + before(async () => { + // TODO: emptyKibanaIndex fails in Serverless with + // "index_not_found_exception: no such index [.kibana_ingest]", + // so it was switched to `savedObjects.cleanStandardList()` + await kibanaServer.savedObjects.cleanStandardList(); + await reportingAPI.initEcommerce(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern('ecommerce'); + }); + + after(async () => { + await reportingAPI.teardownEcommerce(); + // TODO: emptyKibanaIndex fails in Serverless with + // "index_not_found_exception: no such index [.kibana_ingest]", + // so it was switched to `savedObjects.cleanStandardList()` + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('is available if new', async () => { + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); + }); + + it('becomes available when saved', async () => { + await PageObjects.discover.saveSearch('my search - expectEnabledGenerateReportButton'); + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); + }); + }); + + describe('Generate CSV: new search', () => { + before(async () => { + await reportingAPI.initEcommerce(); + }); + + after(async () => { + await reportingAPI.teardownEcommerce(); + // TODO: emptyKibanaIndex fails in Serverless with + // "index_not_found_exception: no such index [.kibana_ingest]", + // so it was switched to `savedObjects.cleanStandardList()` + await kibanaServer.savedObjects.cleanStandardList(); + }); + + beforeEach(async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern('ecommerce'); + }); + + it('generates a report with single timefilter', async () => { + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.timePicker.setCommonlyUsedTime('Last_24 hours'); + await PageObjects.discover.saveSearch('single-timefilter-search'); + + // get shared URL value + const sharedURL = await browser.getCurrentUrl(); + + // click 'Copy POST URL' + await PageObjects.share.clickShareTopNavButton(); + await PageObjects.reporting.openCsvReportingPanel(); + const advOpt = await find.byXPath(`//button[descendant::*[text()='Advanced options']]`); + await advOpt.click(); + const postUrl = await find.byXPath(`//button[descendant::*[text()='Copy POST URL']]`); + await postUrl.click(); + + // get clipboard value using field search input, since + // 'browser.getClipboardValue()' doesn't work, due to permissions + const textInput = await testSubjects.find('fieldListFiltersFieldSearch'); + await textInput.click(); + await browser + .getActions() + // TODO: Add Mac support since this wouldn't run locally before + .keyDown(Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL']) + .perform(); + await browser.getActions().keyDown('v').perform(); + + const reportURL = decodeURIComponent(await textInput.getAttribute('value')); + + // get number of filters in URLs + const timeFiltersNumberInReportURL = + reportURL.split('query:(range:(order_date:(format:strict_date_optional_time').length - 1; + const timeFiltersNumberInSharedURL = sharedURL.split('time:').length - 1; + + expect(timeFiltersNumberInSharedURL).to.be(1); + expect(sharedURL.includes('time:(from:now-24h%2Fh,to:now))')).to.be(true); + + expect(timeFiltersNumberInReportURL).to.be(1); + expect( + reportURL.includes( + 'query:(range:(order_date:(format:strict_date_optional_time,gte:now-24h/h,lte:now))))' + ) + ).to.be(true); + + // return keyboard state + await browser + .getActions() + // TODO: Add Mac support since this wouldn't run locally before + .keyUp(Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL']) + .perform(); + await browser.getActions().keyUp('v').perform(); + + // return field search input state + await textInput.clearValue(); + }); + + it('generates a report from a new search with data: default', async () => { + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.reporting.setTimepickerInEcommerceDataRange(); + + await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); + + const res = await getReport(); + expect(res.status).to.equal(200); + expect(res.contentType).to.equal('text/csv; charset=utf-8'); + + const csvFile = res.text; + expectSnapshot(csvFile).toMatch(); + }); + + it('generates a report with no data', async () => { + await PageObjects.reporting.setTimepickerInEcommerceNoDataRange(); + await PageObjects.discover.saveSearch('my search - no data - expectReportCanBeCreated'); + + const res = await getReport(); + expect(res.text).to.be(`\n`); + }); + + it('generates a large export', async () => { + const fromTime = 'Apr 27, 2019 @ 23:56:51.374'; + const toTime = 'Aug 23, 2019 @ 16:18:51.821'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.discover.clickNewSearchButton(); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('4,675'); + }); + await PageObjects.discover.saveSearch('large export'); + + // match file length, the beginning and the end of the csv file contents + const { text: csvFile } = await getReport(); + expect(csvFile.length).to.be(4826973); + expectSnapshot(csvFile.slice(0, 5000)).toMatch(); + expectSnapshot(csvFile.slice(-5000)).toMatch(); + }); + }); + + describe('Generate CSV: sparse data', () => { + const TEST_INDEX_NAME = 'sparse_data'; + const TEST_DOC_COUNT = 510; + + const reset = async () => { + try { + await es.indices.delete({ index: TEST_INDEX_NAME }); + } catch (err) { + // ignore 404 error + } + }; + + const createDocs = async () => { + interface TestDoc { + timestamp: string; + name: string; + updated_at?: string; + } + + const docs = Array(TEST_DOC_COUNT); + + for (let i = 0; i <= docs.length - 1; i++) { + const name = `test-${i + 1}`; + const timestamp = moment + .utc('2006-08-14T00:00:00') + .subtract(TEST_DOC_COUNT - i, 'days') + .format(); + + if (i === 0) { + // only the oldest document has a value for updated_at + docs[i] = { + timestamp, + name, + updated_at: moment.utc('2006-08-14T00:00:00').format(), + }; + } else { + // updated_at field does not exist in first 500 documents + docs[i] = { timestamp, name }; + } + } + + const res = await es.bulk({ + index: TEST_INDEX_NAME, + body: docs.map((d) => `{"index": {}}\n${JSON.stringify(d)}\n`), + }); + + log.info(`Indexed ${res.items.length} test data docs.`); + }; + + before(async () => { + await reset(); + await createDocs(); + // TODO: Manually loading logs archive and logs SOs in Serverless + // instead of using `reportingAPI.initLogs()` since the original + // logs SOs include a canvas SO which is not supported in Serverless + await esArchiver.load('x-pack/test/functional/es_archives/logstash_functional'); + await kibanaServer.importExport.load( + 'x-pack/test_serverless/functional/fixtures/kbn_archiver/reporting/logs' + ); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.loadSavedSearch('Sparse Columns'); + }); + + after(async () => { + // TODO: Manually unloading logs archive and logs SOs in Serverless + // instead of using `reportingAPI.teardownLogs()` since the original + // logs SOs include a canvas SO which is not supported in Serverless + await kibanaServer.importExport.unload( + 'x-pack/test_serverless/functional/fixtures/kbn_archiver/reporting/logs' + ); + await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); + await reset(); + }); + + beforeEach(async () => { + const fromTime = 'Jan 10, 2005 @ 00:00:00.000'; + const toTime = 'Dec 23, 2006 @ 00:00:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal(TEST_DOC_COUNT.toString()); + }); + }); + + it(`handles field formatting for a field that doesn't exist initially`, async () => { + const res = await getReport(); + expect(res.status).to.equal(200); + expect(res.contentType).to.equal('text/csv; charset=utf-8'); + + const csvFile = res.text; + expectSnapshot(csvFile).toMatch(); + }); + }); + + describe('Generate CSV: archived search', () => { + const setupPage = async () => { + const fromTime = 'Jun 22, 2019 @ 00:00:00.000'; + const toTime = 'Jun 26, 2019 @ 23:30:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + }; + + before(async () => { + await reportingAPI.initEcommerce(); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.selectIndexPattern('ecommerce'); + }); + + after(async () => { + await reportingAPI.teardownEcommerce(); + }); + + beforeEach(async () => { + await setupPage(); + }); + + // TODO: Allow skipping the toast check if we know + // there will be none since it will wait for 90s + let checkForReportingToasts = true; + + afterEach(async () => { + if (checkForReportingToasts) { + await PageObjects.reporting.checkForReportingToasts(); + } + checkForReportingToasts = true; + }); + + it('generates a report with data', async () => { + await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); + + const { text: csvFile } = await getReport(); + expectSnapshot(csvFile).toMatch(); + }); + + it('generates a report with filtered data', async () => { + await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); + + // filter + await filterBar.addFilter({ field: 'category', operation: 'is', value: `Men's Shoes` }); + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('154'); + }); + + const { text: csvFile } = await getReport(); + expectSnapshot(csvFile).toMatch(); + }); + + it('generates a report with discover:searchFieldsFromSource = true', async () => { + await PageObjects.discover.loadSavedSearch('Ecommerce Data'); + + await retry.try(async () => { + expect(await PageObjects.discover.getHitCount()).to.equal('740'); + }); + + await setFieldsFromSource(true); + + const { text: csvFile } = await getReport(); + expectSnapshot(csvFile).toMatch(); + + await setFieldsFromSource(false); + // TODO: We refreshed the page in `setFieldsFromSource`, + // so no toast will be shown + checkForReportingToasts = false; + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts new file mode 100644 index 000000000000..ab1ad279b886 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/visualize_field.ts @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const filterBar = getService('filterBar'); + const queryBar = getService('queryBar'); + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects([ + 'common', + 'error', + 'discover', + 'timePicker', + 'unifiedSearch', + 'lens', + 'security', + 'spaceSelector', + 'header', + 'unifiedFieldList', + ]); + + // TODO: ES|QL setting removed since ES|QL isn't supported in Serverless + + async function setDiscoverTimeRange() { + await PageObjects.timePicker.setDefaultAbsoluteRange(); + } + + describe('discover field visualize button', () => { + beforeEach(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' + ); + await PageObjects.common.navigateToApp('discover'); + await setDiscoverTimeRange(); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); + await kibanaServer.importExport.unload( + 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' + ); + }); + + it('shows "visualize" field button', async () => { + await PageObjects.unifiedFieldList.clickFieldListItem('bytes'); + await PageObjects.unifiedFieldList.expectFieldListItemVisualize('bytes'); + }); + + it('visualizes field to Lens and loads fields to the dimesion editor', async () => { + await PageObjects.unifiedFieldList.findFieldByName('bytes'); + await PageObjects.unifiedFieldList.clickFieldListItemVisualize('bytes'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async () => { + const dimensions = await testSubjects.findAll('lns-dimensionTrigger'); + expect(dimensions).to.have.length(2); + expect(await dimensions[1].getVisibleText()).to.be('Median of bytes'); + }); + }); + + it('should preserve app filters in lens', async () => { + await filterBar.addFilter({ + field: 'bytes', + operation: 'is between', + value: { from: '3500', to: '4000' }, + }); + await PageObjects.unifiedFieldList.findFieldByName('geo.src'); + await PageObjects.unifiedFieldList.clickFieldListItemVisualize('geo.src'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await filterBar.hasFilter('bytes', '3,500 to 4,000')).to.be(true); + }); + + it('should preserve query in lens', async () => { + await queryBar.setQuery('machine.os : ios'); + await queryBar.submitQuery(); + await PageObjects.unifiedFieldList.findFieldByName('geo.dest'); + await PageObjects.unifiedFieldList.clickFieldListItemVisualize('geo.dest'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + expect(await queryBar.getQueryString()).to.equal('machine.os : ios'); + }); + + it('should visualize correctly using breakdown field', async () => { + await PageObjects.discover.chooseBreakdownField('extension.raw'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('unifiedHistogramEditVisualization'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async () => { + const breakdownLabel = await testSubjects.find( + 'lnsDragDrop_draggable-Top 3 values of extension.raw' + ); + + const lnsWorkspace = await testSubjects.find('lnsWorkspace'); + const list = await lnsWorkspace.findAllByClassName('echLegendItem__label'); + const values = await Promise.all( + list.map((elem: WebElementWrapper) => elem.getVisibleText()) + ); + + expect(await breakdownLabel.getVisibleText()).to.eql('Top 3 values of extension.raw'); + expect(values).to.eql(['jpg', 'css', 'png', 'Other']); + }); + }); + + it('should visualize correctly using adhoc data view', async () => { + await PageObjects.discover.createAdHocDataView('logst', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await testSubjects.click('unifiedHistogramEditVisualization'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async () => { + const selectedPattern = await PageObjects.lens.getDataPanelIndexPattern(); + expect(selectedPattern).to.eql('logst*'); + }); + }); + + // TODO: ES|QL tests removed since ES|QL isn't supported in Serverless + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/index.ts new file mode 100644 index 000000000000..253effe65b46 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ loadTestFile, getPageObject }: FtrProviderContext) => { + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('Discover alerting', function () { + before(async function () { + // TODO: Serverless tests require login first + await svlCommonPage.login(); + }); + + loadTestFile(require.resolve('./search_source_alert')); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/search_source_alert.ts b/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/search_source_alert.ts new file mode 100644 index 000000000000..f683e0223799 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover_ml_uptime/discover/search_source_alert.ts @@ -0,0 +1,646 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { INGEST_SAVED_OBJECT_INDEX } from '@kbn/fleet-plugin/common/constants'; +import { asyncForEach } from '@kbn/std'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const es = getService('es'); + const monacoEditor = getService('monacoEditor'); + const PageObjects = getPageObjects([ + 'settings', + 'common', + 'header', + 'discover', + 'timePicker', + 'dashboard', + ]); + const deployment = getService('deployment'); + const dataGrid = getService('dataGrid'); + const browser = getService('browser'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const supertest = getService('supertest'); + const queryBar = getService('queryBar'); + const security = getService('security'); + const filterBar = getService('filterBar'); + const find = getService('find'); + const toasts = getService('toasts'); + const kibanaServer = getService('kibanaServer'); + const comboBox = getService('comboBox'); + + const SOURCE_DATA_VIEW = 'search-source-alert'; + const OUTPUT_DATA_VIEW = 'search-source-alert-output'; + const ACTION_TYPE_ID = '.index'; + const RULE_NAME = 'test-search-source-alert'; + const ADHOC_RULE_NAME = 'test-adhoc-alert'; + let sourceDataViewId: string; + let outputDataViewId: string; + let connectorId: string; + + const createSourceIndex = () => + es.index({ + index: SOURCE_DATA_VIEW, + body: { + settings: { number_of_shards: 1 }, + mappings: { + properties: { + '@timestamp': { type: 'date' }, + message: { type: 'keyword' }, + }, + }, + }, + }); + + const generateNewDocs = async (docsNumber: number) => { + const mockMessages = Array.from({ length: docsNumber }, (_, i) => `msg-${i}`); + const dateNow = new Date(); + const dateToSet = new Date(dateNow); + dateToSet.setMinutes(dateNow.getMinutes() - 10); + for await (const message of mockMessages) { + es.transport.request({ + path: `/${SOURCE_DATA_VIEW}/_doc`, + method: 'POST', + body: { + '@timestamp': dateToSet.toISOString(), + message, + }, + }); + } + }; + + const createOutputDataIndex = () => + es.index({ + index: OUTPUT_DATA_VIEW, + body: { + settings: { + number_of_shards: 1, + }, + mappings: { + properties: { + rule_id: { type: 'text' }, + rule_name: { type: 'text' }, + alert_id: { type: 'text' }, + context_link: { type: 'text' }, + }, + }, + }, + }); + + const deleteAlerts = (alertIds: string[]) => + asyncForEach(alertIds, async (alertId: string) => { + await supertest + .delete(`/api/alerting/rule/${alertId}`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .set('x-elastic-internal-origin', 'kibana') + .expect(204, ''); + }); + + const getAlertsByName = async (name: string) => { + const { + body: { data: alerts }, + } = await supertest + .get(`/api/alerting/rules/_find?search=${name}&search_fields=name`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .expect(200); + + return alerts; + }; + + const createDataView = async (dataView: string) => { + log.debug(`create data view ${dataView}`); + return await supertest + .post(`/api/data_views/data_view`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .send({ data_view: { title: dataView, timeFieldName: '@timestamp' } }) + .expect(200); + }; + + const deleteDataView = async (dataViewId: string) => { + return await supertest + .delete(`/api/data_views/data_view/${dataViewId}`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .expect(200); + }; + + const deleteIndexes = (indexes: string[]) => { + indexes.forEach((current) => { + es.transport.request({ + path: `/${current}`, + method: 'DELETE', + }); + }); + }; + + const createConnector = async (): Promise => { + const { body: createdAction } = await supertest + .post(`/api/actions/connector`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .send({ + name: 'search-source-alert-test-connector', + connector_type_id: ACTION_TYPE_ID, + config: { index: OUTPUT_DATA_VIEW }, + secrets: {}, + }) + .expect(200); + + return createdAction.id; + }; + + const deleteConnector = (id: string) => + supertest + .delete(`/api/actions/connector/${id}`) + // TODO: API requests in Serverless require internal request headers + .set({ + 'kbn-xsrf': 'some-xsrf-token', + 'x-elastic-internal-origin': 'kibana', + }) + .expect(204, ''); + + const defineSearchSourceAlert = async (alertName: string) => { + await retry.waitFor('rule name value is correct', async () => { + await testSubjects.setValue('ruleNameInput', alertName); + const ruleName = await testSubjects.getAttribute('ruleNameInput', 'value'); + return ruleName === alertName; + }); + await testSubjects.click('thresholdPopover'); + await testSubjects.setValue('alertThresholdInput', '1'); + + await testSubjects.click('forLastExpression'); + await testSubjects.setValue('timeWindowSizeNumber', '30'); + + await retry.waitFor('actions accordion to exist', async () => { + await testSubjects.click('.index-alerting-ActionTypeSelectOption'); + return await testSubjects.exists('alertActionAccordion-0'); + }); + + await monacoEditor.setCodeEditorValue(`{ + "rule_id": "{{rule.id}}", + "rule_name": "{{rule.name}}", + "alert_id": "{{alert.id}}", + "context_link": "{{context.link}}" + }`); + }; + + const openDiscoverAlertFlyout = async () => { + await testSubjects.click('discoverAlertsButton'); + await testSubjects.click('discoverCreateAlertButton'); + }; + + const openManagementAlertFlyout = async () => { + await PageObjects.common.navigateToApp('management'); + await PageObjects.header.waitUntilLoadingHasFinished(); + // TODO: Navigation to Rule Management is different in Serverless + await PageObjects.common.navigateToApp('triggersActions'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('createFirstRuleButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('.es-query-SelectOption'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('queryFormType_searchSource'); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + const getResultsLink = async () => { + // getting the link + await dataGrid.clickRowToggle(); + const contextMessageElement = await testSubjects.find('tableDocViewRow-context_link-value'); + const contextMessage = await contextMessageElement.getVisibleText(); + + return contextMessage; + }; + + const openAlertResults = async (value: string, type: 'id' | 'name' = 'name') => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.clickNewSearchButton(); // reset params + + await PageObjects.discover.selectIndexPattern(OUTPUT_DATA_VIEW); + + let ruleId: string; + if (type === 'name') { + const [{ id }] = await getAlertsByName(value); + ruleId = id; + } else { + ruleId = value; + } + + await filterBar.addFilter({ field: 'rule_id', operation: 'is', value: ruleId }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + const link = await getResultsLink(); + await filterBar.removeFilter('rule_id'); // clear filter bar + + // follow url provided by alert to see documents triggered the alert + const baseUrl = deployment.getHostPort(); + // TODO: In Serverless `link` is a full URL instead of just a path as in stateful + const fullLink = link.startsWith(baseUrl) ? link : baseUrl + link; + await browser.navigateTo(fullLink); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }; + + const openAlertRuleInManagement = async (ruleName: string) => { + await PageObjects.common.navigateToApp('management'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // TODO: Navigation to Rule Management is different in Serverless + await PageObjects.common.navigateToApp('triggersActions'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const rulesList = await testSubjects.find('rulesList'); + const alertRule = await rulesList.findByCssSelector(`[title="${ruleName}"]`); + await alertRule.click(); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + const clickViewInApp = async (ruleName: string) => { + // navigate to discover using view in app link + await openAlertRuleInManagement(ruleName); + await testSubjects.click('ruleDetails-viewInApp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + const checkInitialRuleParamsState = async (dataView: string, isViewInApp = false) => { + if (isViewInApp) { + expect(await toasts.getToastCount()).to.be(0); + } else { + expect(await toasts.getToastCount()).to.be(1); + expect((await toasts.getToastContent(1)).startsWith('Displayed documents may vary')).to.be( + true + ); + } + expect(await filterBar.getFilterCount()).to.be(0); + expect(await queryBar.getQueryString()).to.equal(''); + const selectedDataView = await PageObjects.discover.getCurrentlySelectedDataView(); + const { valid } = await PageObjects.discover.validateDataViewReffsEquality(); + expect(valid).to.equal(true); + expect(selectedDataView).to.be.equal(dataView); + expect(await dataGrid.getDocCount()).to.be(5); + }; + + const checkUpdatedRuleParamsState = async () => { + expect(await toasts.getToastCount()).to.be(0); + const queryString = await queryBar.getQueryString(); + const hasFilter = await filterBar.hasFilter('message.keyword', 'msg-1'); + expect(queryString).to.be.equal('message:msg-1'); + expect(hasFilter).to.be.equal(true); + expect(await dataGrid.getDocCount()).to.be(1); + }; + + const checkInitialDataViewState = async (dataView: string) => { + // validate prev field filter + await testSubjects.existOrFail(`field-message-showDetails`); // still exists + + // validate prev title + await PageObjects.discover.clickIndexPatternActions(); + await testSubjects.click('indexPattern-manage-field'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const titleElem = await testSubjects.find('createIndexPatternTitleInput'); + expect(await titleElem.getAttribute('value')).to.equal(dataView); + }; + + const checkUpdatedDataViewState = async (dataView: string) => { + // validate updated field filter + await testSubjects.missingOrFail(`field-message-showDetails`); + + // validate updated title + await PageObjects.discover.clickIndexPatternActions(); + await testSubjects.click('indexPattern-manage-field'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const titleElem = await testSubjects.find('createIndexPatternTitleInput'); + expect(await titleElem.getAttribute('value')).to.equal(dataView); + }; + + describe('Search source Alert', () => { + before(async () => { + await security.testUser.setRoles(['discover_alert']); + + log.debug('create source indices'); + await createSourceIndex(); + + log.debug('generate documents'); + await generateNewDocs(5); + + log.debug('create output index'); + await createOutputDataIndex(); + + log.debug('create connector'); + connectorId = await createConnector(); + + // TODO: fetching connectors fails server side in Serverless with + // "index_not_found_exception: no such index [.kibana_ingest]" + if (!(await es.indices.exists({ index: INGEST_SAVED_OBJECT_INDEX }))) { + await es.indices.create({ index: INGEST_SAVED_OBJECT_INDEX }); + } + }); + + after(async () => { + deleteIndexes([OUTPUT_DATA_VIEW, SOURCE_DATA_VIEW]); + const [{ id: adhocRuleId }] = await getAlertsByName(ADHOC_RULE_NAME); + await deleteAlerts([adhocRuleId]); + await deleteDataView(outputDataViewId); + await deleteConnector(connectorId); + await security.testUser.restoreDefaults(); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('should create an alert when there is no data view', async () => { + await openManagementAlertFlyout(); + + // should not have data view selected by default + const dataViewSelector = await testSubjects.find('selectDataViewExpression'); + // TODO: Serverless Security has an existing data view by default + const dataViewSelectorText = await dataViewSelector.getVisibleText(); + if (!dataViewSelectorText.includes('.alerts-security')) { + expect(await dataViewSelector.getVisibleText()).to.eql('DATA VIEW\nSelect a data view'); + } + + log.debug('create data views'); + const sourceDataViewResponse = await createDataView(SOURCE_DATA_VIEW); + const outputDataViewResponse = await createDataView(OUTPUT_DATA_VIEW); + + sourceDataViewId = sourceDataViewResponse.body.data_view.id; + outputDataViewId = outputDataViewResponse.body.data_view.id; + }); + + it('should show time field validation error', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.selectIndexPattern(SOURCE_DATA_VIEW); + await PageObjects.timePicker.setCommonlyUsedTime('Last_15 minutes'); + + await openDiscoverAlertFlyout(); + await defineSearchSourceAlert(RULE_NAME); + await testSubjects.click('selectDataViewExpression'); + + await testSubjects.click('indexPattern-switcher--input'); + const input = await find.activeElement(); + // search-source-alert-output index does not have time field + await input.type('search-source-alert-o*'); + await testSubjects.click('explore-matching-indices-button'); + + await retry.waitFor('selection to happen', async () => { + const dataViewSelector = await testSubjects.find('selectDataViewExpression'); + return (await dataViewSelector.getVisibleText()) === 'DATA VIEW\nsearch-source-alert-o*'; + }); + + await testSubjects.click('saveRuleButton'); + + const errorElem = await testSubjects.find('esQueryAlertExpressionError'); + const errorText = await errorElem.getVisibleText(); + expect(errorText).to.eql('Data view should have a time field.'); + }); + + it('should navigate to alert results via view in app link', async () => { + await testSubjects.click('selectDataViewExpression'); + await testSubjects.click('indexPattern-switcher--input'); + if (await testSubjects.exists('clearSearchButton')) { + await testSubjects.click('clearSearchButton'); + } + const dataViewsElem = await testSubjects.find('euiSelectableList'); + const sourceDataViewOption = await dataViewsElem.findByCssSelector( + `[title="${SOURCE_DATA_VIEW}"]` + ); + await sourceDataViewOption.click(); + + await testSubjects.click('saveRuleButton'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + + await openAlertRuleInManagement(RULE_NAME); + await testSubjects.click('ruleDetails-viewInApp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await checkInitialRuleParamsState(SOURCE_DATA_VIEW, true); + }); + + it('should navigate to alert results via link provided in notification', async () => { + await openAlertResults(RULE_NAME); + await checkInitialRuleParamsState(SOURCE_DATA_VIEW); + }); + + it('should display prev rule state after params update on clicking prev generated link', async () => { + await openAlertRuleInManagement(RULE_NAME); + + // change rule configuration + await testSubjects.click('openEditRuleFlyoutButton'); + await queryBar.setQuery('message:msg-1'); + await filterBar.addFilter({ field: 'message.keyword', operation: 'is', value: 'msg-1' }); + + await testSubjects.click('thresholdPopover'); + await testSubjects.setValue('alertThresholdInput', '1'); + await testSubjects.click('saveEditedRuleButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await openAlertResults(RULE_NAME); + await checkInitialRuleParamsState(SOURCE_DATA_VIEW); + }); + + it('should display actual state after rule params update on clicking viewInApp link', async () => { + await clickViewInApp(RULE_NAME); + + const selectedDataView = await PageObjects.discover.getCurrentlySelectedDataView(); + expect(selectedDataView).to.be.equal(SOURCE_DATA_VIEW); + + await checkUpdatedRuleParamsState(); + }); + + it('should display prev data view state after update on clicking prev generated link', async () => { + await PageObjects.common.navigateToUrlWithBrowserHistory( + 'management', + `/kibana/dataViews/dataView/${sourceDataViewId}`, + undefined + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // add source filter + await testSubjects.click('tab-sourceFilters'); + await testSubjects.click('fieldFilterInput'); + const filtersInput = await find.activeElement(); + await filtersInput.type('message'); + await testSubjects.click('addFieldFilterButton'); + + // change title + await testSubjects.click('editIndexPatternButton'); + await testSubjects.setValue('createIndexPatternTitleInput', 'search-s', { + clearWithKeyboard: true, + typeCharByChar: true, + }); + await testSubjects.click('saveIndexPatternButton'); + await testSubjects.click('confirmModalConfirmButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await openAlertResults(RULE_NAME); + + await checkInitialRuleParamsState(SOURCE_DATA_VIEW); + await checkInitialDataViewState(SOURCE_DATA_VIEW); + }); + + it('should display actual data view state after update on clicking viewInApp link', async () => { + await clickViewInApp(RULE_NAME); + await checkUpdatedRuleParamsState(); + await checkUpdatedDataViewState('search-s*'); + }); + + it('should navigate to alert results via link provided in notification using adhoc data view', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.createAdHocDataView('search-source-', true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await PageObjects.timePicker.setCommonlyUsedTime('Last_15 minutes'); + await PageObjects.discover.addRuntimeField('runtime-message-field', `emit('mock-message')`); + + // create an alert + await openDiscoverAlertFlyout(); + await defineSearchSourceAlert('test-adhoc-alert'); + await testSubjects.click('saveRuleButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await openAlertResults(ADHOC_RULE_NAME); + + const selectedDataView = await PageObjects.discover.getCurrentlySelectedDataView(); + expect(selectedDataView).to.be.equal('search-source-*'); + + const documentCell = await dataGrid.getCellElement(0, 3); + const firstRowContent = await documentCell.getVisibleText(); + expect(firstRowContent.includes('runtime-message-fieldmock-message')).to.be.equal(true); + + expect(await dataGrid.getDocCount()).to.be(5); + }); + + it('should navigate to alert results via view in app link using adhoc data view', async () => { + // navigate to discover using view in app link + await clickViewInApp(ADHOC_RULE_NAME); + + const selectedDataView = await PageObjects.discover.getCurrentlySelectedDataView(); + expect(selectedDataView).to.be.equal('search-source-*'); + + const documentCell = await dataGrid.getCellElement(0, 3); + const firstRowContent = await documentCell.getVisibleText(); + expect(firstRowContent.includes('runtime-message-fieldmock-message')).to.be.equal(true); + }); + + it('should display results after data view removal on clicking prev generated link', async () => { + await PageObjects.discover.selectIndexPattern(OUTPUT_DATA_VIEW); + await deleteDataView(sourceDataViewId); + + await openAlertResults(RULE_NAME); + + await checkInitialRuleParamsState(SOURCE_DATA_VIEW); + await checkInitialDataViewState(SOURCE_DATA_VIEW); + }); + + it('should not display results after data view removal on clicking viewInApp link', async () => { + await clickViewInApp(RULE_NAME); + + expect(await toasts.getToastCount()).to.be.equal(1); + const content = await toasts.getToastContent(1); + expect(content).to.equal( + `Error fetching search source\nCould not locate that data view (id: ${sourceDataViewId}), click here to re-create it` + ); + }); + + it('should display results after rule removal on following generated link', async () => { + await PageObjects.discover.selectIndexPattern(OUTPUT_DATA_VIEW); + const [{ id: firstAlertId }] = await getAlertsByName(RULE_NAME); + await deleteAlerts([firstAlertId]); + + await openAlertResults(firstAlertId, 'id'); + + await checkInitialRuleParamsState(SOURCE_DATA_VIEW); + await checkInitialDataViewState(SOURCE_DATA_VIEW); + }); + + it('should check that there are no errors detected after an alert is created', async () => { + const newAlert = 'New Alert for checking its status'; + await createDataView('search-source*'); + + await PageObjects.common.navigateToApp('management'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // TODO: Navigation to Rule Management is different in Serverless + await PageObjects.common.navigateToApp('triggersActions'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await testSubjects.click('createRuleButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.waitFor('rule name value is correct', async () => { + await testSubjects.setValue('ruleNameInput', newAlert); + const ruleName = await testSubjects.getAttribute('ruleNameInput', 'value'); + return ruleName === newAlert; + }); + + await testSubjects.click('.es-query-SelectOption'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('queryFormType_searchSource'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await testSubjects.click('selectDataViewExpression'); + await testSubjects.click('indexPattern-switcher--input'); + if (await testSubjects.exists('clearSearchButton')) { + await testSubjects.click('clearSearchButton'); + } + const dataViewsElem = await testSubjects.find('euiSelectableList'); + const sourceDataViewOption = await dataViewsElem.findByCssSelector( + `[title="search-source*"]` + ); + await sourceDataViewOption.click(); + + // TODO: Serverless O11y has a required "Role visibility" selector + // https://github.com/elastic/kibana/issues/168034 + if (await testSubjects.exists('ruleFormConsumerSelect')) { + await comboBox.set('ruleFormConsumerSelect', 'Stack Rules'); + } + + await testSubjects.click('saveRuleButton'); + + await retry.waitFor('confirmation modal', async () => { + return await testSubjects.exists('confirmModalConfirmButton'); + }); + + await testSubjects.click('confirmModalConfirmButton'); + + await PageObjects.header.waitUntilLoadingHasFinished(); + + await openAlertRuleInManagement(newAlert); + + await retry.waitFor('success status', async () => { + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + return await testSubjects.exists('ruleStatus-ok'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts b/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts index 106f504cae82..f8f96c0bbdd2 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts @@ -55,7 +55,15 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid } return false; }); - await PageObjects.settings.createIndexPattern('blogs', null); + // re-create default dataview : default_all_data_id which was created when serverles_search plugin was started. + await PageObjects.settings.createIndexPattern( + 'blogs', + null, + true, + 'default_all_data_id', + 'default:all-data' + ); + await PageObjects.common.navigateToApp('dataViewFieldEditorExample'); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts deleted file mode 100644 index e7905f687982..000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/management/data_view_mgmt.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from 'expect'; -import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const archivePath = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['settings', 'common', 'header', 'svlCommonPage']); - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - const testSubjects = getService('testSubjects'); - - describe('Data View Management', function () { - this.beforeAll(async () => { - await PageObjects.svlCommonPage.login(); - }); - describe('disables scripted fields', function () { - let dataViewId = ''; - - before(async () => { - await esArchiver.load(archivePath); - - const response = await supertest - .post(DATA_VIEW_PATH) - .set('kbn-xsrf', 'some-xsrf-token') - .send({ - data_view: { - title: 'basic_index', - }, - override: true, - }); - - expect(response.status).toBe(200); - dataViewId = response.body.data_view.id; - }); - - after(async () => { - await esArchiver.unload(archivePath); - await supertest - .delete(`${DATA_VIEW_PATH}/${dataViewId}`) - .set('kbn-xsrf', 'some-xsrf-token'); - }); - - it('Scripted fields tab is missing', async () => { - await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { - shouldUseHashForSubUrl: false, - }); - await testSubjects.click('detail-link-basic_index'); - await testSubjects.exists('tab-indexedFields'); - await testSubjects.missingOrFail('tab-scriptedFields'); - }); - }); - - describe('disables rollups', function () { - let dataViewId = ''; - before(async () => { - await esArchiver.load( - 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - - const response = await supertest - .post(DATA_VIEW_PATH) - .set('kbn-xsrf', 'some-xsrf-token') - .send({ - data_view: { - title: 'basic_index', - type: 'rollup', - }, - override: true, - }) - .set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION); - dataViewId = response.body.data_view.id; - }); - - after(async () => { - await esArchiver.unload( - 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - await supertest - .delete(`${DATA_VIEW_PATH}/${dataViewId}`) - .set('kbn-xsrf', 'some-xsrf-token'); - }); - - it('hides rollup UI tags', async () => { - await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { - shouldUseHashForSubUrl: false, - }); - await testSubjects.exists('detail-link-basic_index'); - await testSubjects.missingOrFail('rollup-tag'); - await testSubjects.click('detail-link-basic_index'); - await testSubjects.missingOrFail('rollup-tag'); - }); - }); - - describe('when in single space mode', function () { - let dataViewId = ''; - before(async () => { - await esArchiver.load( - 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - - const response = await supertest - .post(DATA_VIEW_PATH) - .set('kbn-xsrf', 'some-xsrf-token') - .send({ - data_view: { - title: 'basic_index', - }, - override: true, - }) - .set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION); - dataViewId = response.body.data_view.id; - }); - - after(async () => { - await esArchiver.unload( - 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' - ); - await supertest - .delete(`${DATA_VIEW_PATH}/${dataViewId}`) - .set('kbn-xsrf', 'some-xsrf-token'); - }); - - it('hides spaces UI', async () => { - await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { - shouldUseHashForSubUrl: false, - }); - await testSubjects.exists('detail-link-basic_index'); - await testSubjects.missingOrFail('tableHeaderCell_namespaces_1'); - }); - }); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_data_view_create_delete.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_data_view_create_delete.ts new file mode 100644 index 000000000000..ca7bc4bc5556 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_data_view_create_delete.ts @@ -0,0 +1,266 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const browser = getService('browser'); + const log = getService('log'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const PageObjects = getPageObjects(['settings', 'common', 'header']); + + describe('creating and deleting default data view', function describeIndexTests() { + // failsOnMKI, see https://github.com/elastic/kibana/issues/171479 + this.tags(['failsOnMKI']); + before(async function () { + // TODO: emptyKibanaIndex fails in Serverless with + // "index_not_found_exception: no such index [.kibana_ingest]", + // so it was switched to `savedObjects.cleanStandardList()` + await kibanaServer.savedObjects.cleanStandardList(); + // TODO: Loading this from `es_archives` in `test_serverless` + // instead since minor modifications were required + await esArchiver.loadIfNeeded( + 'x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern' + ); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace({}); + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + }); + + after(async function () { + // TODO: Loading this from `es_archives` in `test_serverless` + // instead since minor modifications were required + await esArchiver.unload( + 'x-pack/test_serverless/functional/es_archives/kibana_sample_data_flights_index_pattern' + ); + + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + describe('can open and close editor', function () { + it('without creating index pattern', async function () { + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickAddNewIndexPatternButton(); + await testSubjects.click('closeFlyoutButton'); + await testSubjects.find('createDataViewButton'); + }); + }); + + describe('validation', function () { + it('can display errors', async function () { + await PageObjects.settings.clickAddNewIndexPatternButton(); + await PageObjects.settings.setIndexPatternField('log-fake*'); + await (await PageObjects.settings.getSaveIndexPatternButton()).click(); + await find.byClassName('euiFormErrorText'); + }); + + it('can resolve errors and submit', async function () { + await PageObjects.settings.setIndexPatternField('log*'); + await new Promise((e) => setTimeout(e, 500)); + await (await PageObjects.settings.getSaveDataViewButtonActive()).click(); + await PageObjects.settings.removeIndexPattern(); + }); + + it('correctly validates timestamp after index pattern changes', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickAddNewIndexPatternButton(); + // setting the index pattern also sets the time field + await PageObjects.settings.setIndexPatternField('log*'); + // wait for timestamp fields to load + await new Promise((e) => setTimeout(e, 1000)); + // this won't have 'timestamp' field + await PageObjects.settings.setIndexPatternField('kibana*'); + // wait for timestamp fields to load + await new Promise((e) => setTimeout(e, 1000)); + await (await PageObjects.settings.getSaveIndexPatternButton()).click(); + // verify an error is displayed + await find.byClassName('euiFormErrorText'); + await testSubjects.click('closeFlyoutButton'); + }); + }); + + describe('special character handling', () => { + it('should handle special charaters in template input', async () => { + await PageObjects.settings.clickAddNewIndexPatternButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.settings.setIndexPatternField('❤️'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('createIndexPatternStatusMessage')).to.contain( + `The index pattern you entered doesn\'t match any data streams, indices, or index aliases.` + ); + }); + }); + + after(async () => { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + }); + }); + + describe('index pattern creation', function indexPatternCreation() { + let indexPatternId: string; + + before(function () { + return PageObjects.settings + .createIndexPattern('logstash-*') + .then((id) => (indexPatternId = id)); + }); + + it('should have index pattern in page header', async function () { + const patternName = await PageObjects.settings.getIndexPageHeading(); + expect(patternName).to.be('logstash-*'); + }); + + it('should have index pattern in url', function url() { + return retry.try(function tryingForTime() { + return browser.getCurrentUrl().then(function (currentUrl) { + expect(currentUrl).to.contain(indexPatternId); + }); + }); + }); + + it('should have expected table headers', function checkingHeader() { + return PageObjects.settings.getTableHeader().then(function (headers) { + log.debug('header.length = ' + headers.length); + const expectedHeaders = [ + 'Name', + 'Type', + 'Format', + 'Searchable', + 'Aggregatable', + 'Excluded', + ]; + + expect(headers.length).to.be(expectedHeaders.length); + + const comparedHeaders = headers.map(function compareHead(header, i) { + return header.getVisibleText().then(function (text) { + expect(text).to.be(expectedHeaders[i]); + }); + }); + + return Promise.all(comparedHeaders); + }); + }); + }); + + describe('edit index pattern', () => { + it('on edit click', async () => { + await PageObjects.settings.editIndexPattern('logstash-*', '@timestamp', 'Logstash Star'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('indexPatternTitle')).to.contain( + `Logstash Star` + ); + }); + }); + it('can save with same name', async () => { + await PageObjects.settings.editIndexPattern( + 'logstash-*,hello_world*', + '@timestamp', + 'Logstash Star', + true + ); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('indexPatternTitle')).to.contain( + `Logstash Star` + ); + }); + }); + it('shows edit confirm message when editing index-pattern', async () => { + await PageObjects.settings.editIndexPattern( + 'logstash-2*', + '@timestamp', + 'Index Star', + true + ); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('indexPatternTitle')).to.contain(`Index Star`); + }); + }); + }); + + describe('index pattern edit', function () { + it('should update field list', async function () { + await PageObjects.settings.editIndexPattern( + 'kibana_sample_data_flights', + 'timestamp', + undefined, + true + ); + + await retry.try(async () => { + // verify initial field list + expect(await testSubjects.exists('field-name-AvgTicketPrice')).to.be(true); + }); + + await PageObjects.settings.editIndexPattern('logstash-*', '@timestamp', undefined, true); + await retry.try(async () => { + // verify updated field list + expect(await testSubjects.exists('field-name-agent')).to.be(true); + }); + }); + + it('should disable Save button after pressing', async function () { + await PageObjects.settings.clickEditIndexButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async () => { + await PageObjects.settings.setIndexPatternField('logs*'); + }); + await PageObjects.settings.selectTimeFieldOption('@timestamp'); + + expect(await testSubjects.isEnabled('saveIndexPatternButton')).to.be(true); + await (await PageObjects.settings.getSaveDataViewButtonActive()).click(); + + // wait for the confirmation modal to open + await retry.waitFor('confirmation modal', async () => { + return await testSubjects.exists('confirmModalConfirmButton'); + }); + + // while the confirmation modal is open, we can check that the form button has actually become disabled + expect(await testSubjects.isEnabled('saveIndexPatternButton')).to.be(false); + + await testSubjects.click('confirmModalConfirmButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + }); + + describe('index pattern deletion', function indexDelete() { + before(function () { + const expectedAlertText = 'Delete data view'; + return PageObjects.settings.removeIndexPattern().then(function (alertText) { + expect(alertText).to.be(expectedAlertText); + }); + }); + + it('should return to index pattern list', function indexNotInUrl() { + // give the url time to settle + return retry.try(function tryingForTime() { + return browser.getCurrentUrl().then(function (currentUrl) { + log.debug('currentUrl = ' + currentUrl); + expect(currentUrl).to.contain('management/kibana/dataViews'); + }); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_edit_field.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_edit_field.ts new file mode 100644 index 000000000000..6ef2f01618a6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_edit_field.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['settings', 'common']); + const testSubjects = getService('testSubjects'); + + describe('edit field', function () { + before(async function () { + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + }); + + after(async function afterAll() { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + describe('field preview', function fieldPreview() { + before(async () => { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + }); + + it('should show preview for fields in _source', async function () { + await PageObjects.settings.filterField('extension'); + await testSubjects.click('editFieldFormat'); + await testSubjects.find('value'); + let previewText = ''; + await retry.waitForWithTimeout('get preview value', 1000, async () => { + previewText = await testSubjects.getVisibleText('value'); + return previewText !== 'Value not set'; + }); + expect(previewText).to.be('css'); + await PageObjects.settings.closeIndexPatternFieldEditor(); + }); + + it('should show preview for fields not in _source', async function () { + await PageObjects.settings.filterField('extension.raw'); + await testSubjects.click('editFieldFormat'); + await testSubjects.find('value'); + let previewText = ''; + await retry.waitForWithTimeout('get preview value', 1000, async () => { + previewText = await testSubjects.getVisibleText('value'); + return previewText !== 'Value not set'; + }); + expect(previewText).to.be('css'); + await PageObjects.settings.closeIndexPatternFieldEditor(); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_exclude_index_pattern.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_exclude_index_pattern.ts new file mode 100644 index 000000000000..05f2545c5a89 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_exclude_index_pattern.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['settings', 'common']); + const es = getService('es'); + const security = getService('security'); + const testSubjects = getService('testSubjects'); + + describe('creating and deleting default index', function describeIndexTests() { + before(async function () { + await security.testUser.setRoles(['kibana_admin', 'index_a', 'index_b']); + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await es.transport.request({ + path: '/index-a/_doc', + method: 'POST', + body: { user: 'matt' }, + }); + + await es.transport.request({ + path: '/index-b/_doc', + method: 'POST', + body: { title: 'hello' }, + }); + await PageObjects.settings.createIndexPattern('index-*,-index-b'); + }); + + it('data view creation with exclusion', async () => { + const fieldCount = await PageObjects.settings.getFieldsTabCount(); + // five metafields plus keyword and text version of 'user' field + expect(parseInt(fieldCount, 10)).to.be(6); + }); + + after(async () => { + await es.transport.request({ + path: '/index-a', + method: 'DELETE', + }); + await es.transport.request({ + path: '/index-b', + method: 'DELETE', + }); + await PageObjects.settings.removeIndexPattern(); + await security.testUser.restoreDefaults(); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_index_pattern_filter.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_index_pattern_filter.ts new file mode 100644 index 000000000000..9da55f122114 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_index_pattern_filter.ts @@ -0,0 +1,203 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['settings', 'common']); + const es = getService('es'); + + describe('index pattern filter', function describeIndexTests() { + before(async function () { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.replace({}); + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + }); + + beforeEach(async function () { + await PageObjects.settings.createIndexPattern('logstash-*'); + }); + + afterEach(async function () { + await PageObjects.settings.removeIndexPattern(); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('should filter indexed fields by type', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + await PageObjects.settings.getFieldTypes(); + await PageObjects.settings.setFieldTypeFilter('keyword'); + + await retry.try(async function () { + const fieldTypes = await PageObjects.settings.getFieldTypes(); + expect(fieldTypes.length).to.be.above(0); + for (const fieldType of fieldTypes) { + expect(fieldType).to.be('keyword'); + } + }); + await PageObjects.settings.clearFieldTypeFilter('keyword'); + + await PageObjects.settings.setFieldTypeFilter('long'); + + await retry.try(async function () { + const fieldTypes = await PageObjects.settings.getFieldTypes(); + expect(fieldTypes.length).to.be.above(0); + for (const fieldType of fieldTypes) { + expect(fieldType).to.be('long'); + } + }); + await PageObjects.settings.clearFieldTypeFilter('long'); + }); + + it('should filter indexed fields by schema type', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + + await PageObjects.settings.addRuntimeField('_test', 'keyword', "emit('hi')"); + + const unfilteredFields = [ + '@message', + '@message.raw', + '@tags', + '@tags.raw', + '@timestamp', + '_id', + '_index', + '_score', + '_source', + '_test', + ]; + + expect(await PageObjects.settings.getFieldNames()).to.eql(unfilteredFields); + + await PageObjects.settings.setSchemaFieldTypeFilter('runtime'); + + expect(await PageObjects.settings.getFieldNames()).to.eql(['_test']); + + await PageObjects.settings.setSchemaFieldTypeFilter('indexed'); + + expect(await PageObjects.settings.getFieldNames()).to.eql(unfilteredFields); + }); + + it('should filter indexed fields when searched', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + + const unfilteredFields = [ + '@message', + '@message.raw', + '@tags', + '@tags.raw', + '@timestamp', + '_id', + '_index', + '_score', + '_source', + 'agent', + ]; + + expect(await PageObjects.settings.getFieldNames()).to.eql(unfilteredFields); + + await PageObjects.settings.filterField('@'); + + expect(await PageObjects.settings.getFieldNames()).to.eql([ + '@message', + '@message.raw', + '@tags', + '@tags.raw', + '@timestamp', + ]); + + await PageObjects.settings.filterField('@message'); + + expect(await PageObjects.settings.getFieldNames()).to.eql(['@message', '@message.raw']); + + expect( + (await testSubjects.getVisibleText('tab-indexedFields')).startsWith('Fields (2 /') + ).to.be(true); + + await testSubjects.click('clearSearchButton'); + + expect(await PageObjects.settings.getFieldNames()).to.eql(unfilteredFields); + }); + + it('should set "conflict" filter when "View conflicts" button is pressed', async function () { + const additionalIndexWithWrongMapping = 'logstash-wrong'; + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + + if (await es.indices.exists({ index: additionalIndexWithWrongMapping })) { + await es.indices.delete({ index: additionalIndexWithWrongMapping }); + } + + await es.indices.create({ + index: additionalIndexWithWrongMapping, + body: { + mappings: { + properties: { + bytes: { + type: 'keyword', + }, + }, + }, + }, + }); + + await es.index({ + index: additionalIndexWithWrongMapping, + body: { + bytes: 'wrong_value', + }, + refresh: 'wait_for', + }); + + await PageObjects.settings.clickIndexPatternLogstash(); + + await testSubjects.existOrFail('dataViewMappingConflict'); + + expect(await PageObjects.settings.getFieldTypes()).to.eql([ + 'text', + 'keyword', + 'text', + 'keyword', + 'date', + '_id', + '_index', + '', + '_source', + 'text', + ]); + + // set other filters to check if they get reset after pressing the button + await PageObjects.settings.filterField('unknown'); + await PageObjects.settings.setFieldTypeFilter('text'); + await PageObjects.settings.setSchemaFieldTypeFilter('runtime'); + expect(await PageObjects.settings.getFieldTypes()).to.eql([]); + + // check that only a conflicting field is shown + await testSubjects.click('viewDataViewMappingConflictsButton'); + expect(await PageObjects.settings.getFieldTypes()).to.eql(['keyword, long\nConflict']); + expect(await PageObjects.settings.getFieldNames()).to.eql(['bytes']); + + await es.indices.delete({ index: additionalIndexWithWrongMapping }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts new file mode 100644 index 000000000000..810676e07df4 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const log = getService('log'); + const browser = getService('browser'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['settings', 'common']); + const testSubjects = getService('testSubjects'); + + describe('runtime fields', function () { + this.tags(['skipFirefox']); + + before(async function () { + await browser.setWindowSize(1200, 800); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({}); + }); + + after(async function afterAll() { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + describe('create runtime field', function describeIndexTests() { + const fieldName = 'atest'; + + it('should create runtime field', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getFieldsTabCount(), 10); + await log.debug('add runtime field'); + await PageObjects.settings.addRuntimeField( + fieldName, + 'Keyword', + "emit('hello world')", + false + ); + + await log.debug('check that field preview is rendered'); + expect(await testSubjects.exists('fieldPreviewItem', { timeout: 1500 })).to.be(true); + + await PageObjects.settings.clickSaveField(); + + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should modify runtime field', async function () { + await PageObjects.settings.filterField(fieldName); + await testSubjects.click('editFieldFormat'); + await PageObjects.settings.setFieldType('Long'); + await PageObjects.settings.setFieldScriptWithoutToggle('emit(6);'); + await PageObjects.settings.toggleRow('formatRow'); + await PageObjects.settings.setFieldFormat('bytes'); + await testSubjects.find('changeWarning'); + await PageObjects.settings.clickSaveField(); + await PageObjects.settings.confirmSave(); + }); + + it('verify field format', async function () { + await testSubjects.click('editFieldFormat'); + const select = await testSubjects.find('editorSelectedFormatId'); + expect(await select.getAttribute('value')).to.be('bytes'); + await PageObjects.settings.closeIndexPatternFieldEditor(); + }); + + it('should delete runtime field', async function () { + await testSubjects.click('deleteField'); + await PageObjects.settings.confirmDelete(); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields_composite.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields_composite.ts new file mode 100644 index 000000000000..a047a4f0e85a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/_runtime_fields_composite.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const log = getService('log'); + const browser = getService('browser'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['settings', 'common']); + const testSubjects = getService('testSubjects'); + + describe('runtime fields', function () { + this.tags(['skipFirefox']); + + before(async function () { + await browser.setWindowSize(1200, 800); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({}); + }); + + after(async function afterAll() { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + describe('create composite runtime field', function describeIndexTests() { + // Starting with '@' to sort toward start of field list + const fieldName = '@composite.test'; + + it('should create runtime field', async function () { + // TODO: Navigation to Data View Management is different in Serverless + await PageObjects.common.navigateToApp('management'); + await testSubjects.click('app-card-dataViews'); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getFieldsTabCount(), 10); + await log.debug('add runtime field'); + await PageObjects.settings.addCompositeRuntimeField( + fieldName, + "emit('a.a','hello world')", + false, + 1 + ); + + await log.debug('check that field preview is rendered'); + expect(await testSubjects.exists('fieldPreviewItem', { timeout: 1500 })).to.be(true); + + await PageObjects.settings.clickSaveField(); + + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should modify runtime field', async function () { + const startingCount = parseInt(await PageObjects.settings.getFieldsTabCount(), 10); + await PageObjects.settings.filterField(fieldName); + await testSubjects.click('editFieldFormat'); + // wait for subfields to render + await testSubjects.find(`typeField_0`); + await new Promise((e) => setTimeout(e, 2000)); + await PageObjects.settings.setCompositeScript("emit('a',6);emit('b',10);"); + + // wait for subfields to render + await testSubjects.find(`typeField_1`); + await new Promise((e) => setTimeout(e, 500)); + + await PageObjects.settings.clickSaveField(); + await testSubjects.click('clearSearchButton'); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should delete runtime field', async function () { + await testSubjects.click('deleteField'); + await PageObjects.settings.confirmDelete(); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/index.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/index.ts new file mode 100644 index 000000000000..6a512b6d6e27 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService, loadTestFile, getPageObject }: FtrProviderContext) => { + describe('Data View Management', function () { + const esArchiver = getService('esArchiver'); + const svlCommonPage = getPageObject('svlCommonPage'); + + before(async () => { + // TODO: Serverless tests require login first + await svlCommonPage.login(); + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/makelogs'); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/makelogs'); + }); + + loadTestFile(require.resolve('./serverless')); + loadTestFile(require.resolve('./_data_view_create_delete')); + loadTestFile(require.resolve('./_runtime_fields')); + loadTestFile(require.resolve('./_runtime_fields_composite')); + loadTestFile(require.resolve('./_exclude_index_pattern')); + loadTestFile(require.resolve('./_index_pattern_filter')); + loadTestFile(require.resolve('./_edit_field')); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/management/data_views/serverless.ts b/x-pack/test_serverless/functional/test_suites/common/management/data_views/serverless.ts new file mode 100644 index 000000000000..896c95b6dc2b --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/management/data_views/serverless.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from 'expect'; +import { DATA_VIEW_PATH } from '@kbn/data-views-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +const archivePath = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['settings', 'common', 'header', 'svlCommonPage']); + const esArchiver = getService('esArchiver'); + const supertest = getService('supertest'); + const testSubjects = getService('testSubjects'); + + describe('Serverless tests', function () { + this.beforeAll(async () => { + await PageObjects.svlCommonPage.login(); + }); + describe('disables scripted fields', function () { + let dataViewId = ''; + + before(async () => { + await esArchiver.load(archivePath); + + const response = await supertest + .post(DATA_VIEW_PATH) + .set('kbn-xsrf', 'some-xsrf-token') + .send({ + data_view: { + title: 'basic_index', + }, + override: true, + }); + + expect(response.status).toBe(200); + dataViewId = response.body.data_view.id; + }); + + after(async () => { + await esArchiver.unload(archivePath); + await supertest + .delete(`${DATA_VIEW_PATH}/${dataViewId}`) + .set('kbn-xsrf', 'some-xsrf-token'); + }); + + it('Scripted fields tab is missing', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { + shouldUseHashForSubUrl: false, + }); + await testSubjects.click('detail-link-basic_index'); + await testSubjects.exists('tab-indexedFields'); + await testSubjects.missingOrFail('tab-scriptedFields'); + }); + }); + + describe('disables rollups', function () { + let dataViewId = ''; + before(async () => { + await esArchiver.load( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + + const response = await supertest + .post(DATA_VIEW_PATH) + .set('kbn-xsrf', 'some-xsrf-token') + .send({ + data_view: { + title: 'basic_index', + type: 'rollup', + }, + override: true, + }) + .set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION); + dataViewId = response.body.data_view.id; + }); + + after(async () => { + await esArchiver.unload( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + await supertest + .delete(`${DATA_VIEW_PATH}/${dataViewId}`) + .set('kbn-xsrf', 'some-xsrf-token'); + }); + + it('hides rollup UI tags', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { + shouldUseHashForSubUrl: false, + }); + await testSubjects.exists('detail-link-basic_index'); + await testSubjects.missingOrFail('rollup-tag'); + await testSubjects.click('detail-link-basic_index'); + await testSubjects.missingOrFail('rollup-tag'); + }); + }); + + describe('when in single space mode', function () { + let dataViewId = ''; + before(async () => { + await esArchiver.load( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + + const response = await supertest + .post(DATA_VIEW_PATH) + .set('kbn-xsrf', 'some-xsrf-token') + .send({ + data_view: { + title: 'basic_index', + }, + override: true, + }) + .set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION); + dataViewId = response.body.data_view.id; + }); + + after(async () => { + await esArchiver.unload( + 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index' + ); + await supertest + .delete(`${DATA_VIEW_PATH}/${dataViewId}`) + .set('kbn-xsrf', 'some-xsrf-token'); + }); + + it('hides spaces UI', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/dataViews', { + shouldUseHashForSubUrl: false, + }); + await testSubjects.exists('detail-link-basic_index'); + await testSubjects.missingOrFail('tableHeaderCell_namespaces_1'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index.ts b/x-pack/test_serverless/functional/test_suites/common/management/index.ts index f20efc97b091..c4d33393c9a8 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index.ts @@ -15,7 +15,7 @@ export default ({ loadTestFile }: FtrProviderContext) => { loadTestFile(require.resolve('./transforms/search_bar_features')); loadTestFile(require.resolve('./transforms/transform_list')); loadTestFile(require.resolve('./advanced_settings')); - loadTestFile(require.resolve('./data_view_mgmt')); + loadTestFile(require.resolve('./data_views')); loadTestFile(require.resolve('./disabled_uis')); }); }; diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts index c54baeed3706..81a8551a0b8b 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/create_enrich_policy.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { SLO_SUMMARY_ENRICH_POLICY_NAME } from '@kbn/observability-plugin/server/assets/constants'; import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { @@ -26,8 +25,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { log.debug('Creating test index'); try { - await es.ingest.deletePipeline({ id: '.slo-*' }, { ignore: [404] }); - await es.enrich.deletePolicy({ name: SLO_SUMMARY_ENRICH_POLICY_NAME }, { ignore: [404] }); await es.indices.create({ index: INDEX_NAME, body: { diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts index bbcd138e2016..bbb66a984186 100644 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts @@ -11,5 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless Common UI - Platform Security', function () { loadTestFile(require.resolve('./api_keys')); loadTestFile(require.resolve('./navigation/avatar_menu')); + loadTestFile(require.resolve('./user_profiles/user_profiles')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts new file mode 100644 index 000000000000..57ef995a4f7a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['svlCommonPage', 'common', 'userProfiles']); + + describe('User Profile Page', async () => { + before(async () => { + await pageObjects.svlCommonPage.login(); + }); + + describe('Theme', async () => { + it('should change theme based on the User Profile Theme control', async () => { + await pageObjects.common.navigateToApp('security_account'); + + const themeKeyPadMenu = await pageObjects.userProfiles.getThemeKeypadMenu(); + expect(themeKeyPadMenu).not.to.be(null); + + await pageObjects.userProfiles.changeUserProfileTheme('Dark'); + const darkModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(darkModeTag).to.be('v8dark'); + + await pageObjects.userProfiles.changeUserProfileTheme('Light'); + const lightModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(lightModeTag).to.be('v8light'); + + await pageObjects.userProfiles.changeUserProfileTheme('Space default'); + const spaceDefaultModeTag = await pageObjects.userProfiles.getThemeTag(); + expect(spaceDefaultModeTag).to.be('v8light'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/cases/attachment_framework.ts b/x-pack/test_serverless/functional/test_suites/observability/cases/attachment_framework.ts index e1a13b456c0f..18cf4d4ebfc9 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cases/attachment_framework.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cases/attachment_framework.ts @@ -100,7 +100,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await testSubjects.click('embeddablePanelAction-embeddable_addToExistingCase'); // verify that solution filter is not visible - await testSubjects.missingOrFail('solution-filter-popover-button'); + await testSubjects.missingOrFail('options-filter-popover-button-owner'); await testSubjects.click(`cases-table-row-select-${theCase.id}`); diff --git a/x-pack/test_serverless/functional/test_suites/observability/cases/list_view.ts b/x-pack/test_serverless/functional/test_suites/observability/cases/list_view.ts index b001adb306a4..f4307aa674c6 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cases/list_view.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cases/list_view.ts @@ -7,7 +7,6 @@ import expect from '@kbn/expect'; import { CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; -import { SeverityAll } from '@kbn/cases-plugin/common/ui'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getPageObject, getService }: FtrProviderContext) => { @@ -177,20 +176,21 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { // by default filter by all await cases.casesTable.validateCasesTableHasNthRows(5); - // low await cases.casesTable.filterBySeverity(CaseSeverity.LOW); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.LOW); - // high await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); - // critical await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); await cases.casesTable.validateCasesTableHasNthRows(1); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); - // back to all - await cases.casesTable.filterBySeverity(SeverityAll); await cases.casesTable.validateCasesTableHasNthRows(5); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts new file mode 100644 index 000000000000..7b8fb4b07284 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/group1'), + require.resolve('../../common/discover/group2'), + require.resolve('../../common/discover/group3'), + ], + junit: { + reportName: 'Serverless Observability Functional Tests - Common Group 5', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group6.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group6.ts new file mode 100644 index 000000000000..9891e7b8ee48 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group6.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/embeddable'), + require.resolve('../../common/discover/x_pack'), + require.resolve('../../common/discover_ml_uptime/discover'), + require.resolve('../../common/context'), + ], + junit: { + reportName: 'Serverless Observability Functional Tests - Common Group 6', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/cases/attachment_framework.ts b/x-pack/test_serverless/functional/test_suites/search/cases/attachment_framework.ts index bff6144d44bb..3cf087eb1ae9 100644 --- a/x-pack/test_serverless/functional/test_suites/search/cases/attachment_framework.ts +++ b/x-pack/test_serverless/functional/test_suites/search/cases/attachment_framework.ts @@ -39,7 +39,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await dashboard.clickNewDashboard(); - await lens.createAndAddLensFromDashboard({}); + await lens.createAndAddLensFromDashboard({ ignoreTimeFilter: true }); }); after(async () => { diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts new file mode 100644 index 000000000000..70cabf59051a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/group1'), + require.resolve('../../common/discover/group2'), + require.resolve('../../common/discover/group3'), + ], + junit: { + reportName: 'Serverless Search Functional Tests - Common Group 5', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group6.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group6.ts new file mode 100644 index 000000000000..25b3a8802a6f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group6.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/embeddable'), + require.resolve('../../common/discover/x_pack'), + require.resolve('../../common/discover_ml_uptime/discover'), + require.resolve('../../common/context'), + ], + junit: { + reportName: 'Serverless Search Functional Tests - Common Group 6', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts b/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts index d91d296c7562..ea76872a5787 100644 --- a/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts +++ b/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts @@ -29,6 +29,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('Building a new dashboard', function () { before(async () => { await PageObjects.svlCommonPage.login(); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.importExport.load( 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' @@ -44,6 +45,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await kibanaServer.importExport.unload( 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' ); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.svlCommonPage.forceLogout(); }); diff --git a/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts b/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts new file mode 100644 index 000000000000..2beb234f688f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/default_dataview.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObject, getService }: FtrProviderContext) { + const svlSearchNavigation = getService('svlSearchNavigation'); + const testSubjects = getService('testSubjects'); + const svlCommonNavigation = getPageObject('svlCommonNavigation'); + const svlCommonPage = getPageObject('svlCommonPage'); + + describe('default dataView', function () { + // Error: expected testSubject(kbnOverviewElasticsearchGettingStarted) to exist + this.tags(['failsOnMKI']); + before(async () => { + await svlCommonPage.login(); + await svlSearchNavigation.navigateToLandingPage(); + }); + + after(async () => { + await svlCommonPage.forceLogout(); + }); + + it('should show dashboard but with no data', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); + await testSubjects.existOrFail('~breadcrumb-deepLinkId-discover'); + await testSubjects.existOrFail('discover-dataView-switch-link'); + await testSubjects.click('discover-dataView-switch-link'); + await testSubjects.existOrFail('indexPattern-add-field'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Discover' }); + }); + + it('should show dashboard but with no data in dashboard', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'dashboards' }); + await testSubjects.existOrFail('~breadcrumb-deepLinkId-dashboards'); + await testSubjects.existOrFail('emptyListPrompt'); + await testSubjects.click('newItemButton'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Editing New Dashboard', + }); + }); + + it('should show dashboard but with no data in visualize', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'visualize' }); + await testSubjects.existOrFail('~breadcrumb-deepLinkId-visualize'); + await testSubjects.existOrFail('top-nav'); + await testSubjects.click('newItemButton'); + await testSubjects.existOrFail('visType-lens'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Visualizations' }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/search/empty_page.ts b/x-pack/test_serverless/functional/test_suites/search/empty_page.ts deleted file mode 100644 index 18af7995b141..000000000000 --- a/x-pack/test_serverless/functional/test_suites/search/empty_page.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getPageObject, getService }: FtrProviderContext) { - const svlSearchNavigation = getService('svlSearchNavigation'); - const testSubjects = getService('testSubjects'); - const svlCommonNavigation = getPageObject('svlCommonNavigation'); - const svlCommonPage = getPageObject('svlCommonPage'); - - describe('empty pages', function () { - // Error: expected testSubject(kbnOverviewElasticsearchGettingStarted) to exist - this.tags(['failsOnMKI']); - before(async () => { - await svlCommonPage.login(); - await svlSearchNavigation.navigateToLandingPage(); - }); - - after(async () => { - await svlCommonPage.forceLogout(); - }); - - it('should show search specific empty page in discover', async () => { - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); - await testSubjects.existOrFail('~breadcrumb-deepLinkId-discover'); - await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); - await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Get started' }); - }); - - it('should show search specific empty page in visualize', async () => { - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'visualize' }); - await testSubjects.existOrFail('~breadcrumb-deepLinkId-visualize'); - await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); - await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Get started' }); - }); - - it('should show search specific empty page in dashboards', async () => { - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'dashboards' }); - await testSubjects.existOrFail('~breadcrumb-deepLinkId-dashboards'); - await testSubjects.existOrFail('kbnOverviewElasticsearchGettingStarted'); - await testSubjects.click('kbnOverviewElasticsearchGettingStarted'); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Get started' }); - }); - }); -} diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts index 6ed8a9f62c22..6d0987d0292c 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI', function () { loadTestFile(require.resolve('./landing_page')); - loadTestFile(require.resolve('./empty_page')); + loadTestFile(require.resolve('./default_dataview')); loadTestFile(require.resolve('./navigation')); loadTestFile(require.resolve('./cases/attachment_framework')); loadTestFile(require.resolve('./dashboards/build_dashboard')); diff --git a/x-pack/test_serverless/functional/test_suites/search/landing_page.ts b/x-pack/test_serverless/functional/test_suites/search/landing_page.ts index ee7fa320cc88..c15b88d5cb3e 100644 --- a/x-pack/test_serverless/functional/test_suites/search/landing_page.ts +++ b/x-pack/test_serverless/functional/test_suites/search/landing_page.ts @@ -81,5 +81,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchLandingPage.apiKeys.createApiKeyCancel(); }); }); + + describe('Pipeline creation', async () => { + it('can redirect to the pipeline creation index page', async () => { + await pageObjects.svlSearchLandingPage.pipeline.click(); + await pageObjects.svlSearchLandingPage.pipeline.expectNavigateToCreatePipelinePage(); + }); + }); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts new file mode 100644 index 000000000000..d1637bf34b4f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/group1'), + require.resolve('../../common/discover/group2'), + require.resolve('../../common/discover/group3'), + ], + junit: { + reportName: 'Serverless Security Functional Tests - Common Group 5', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group6.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group6.ts new file mode 100644 index 000000000000..f3276ecd3c67 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group6.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [ + require.resolve('../../common/discover/embeddable'), + require.resolve('../../common/discover/x_pack'), + require.resolve('../../common/discover_ml_uptime/discover'), + require.resolve('../../common/context'), + ], + junit: { + reportName: 'Serverless Security Functional Tests - Common Group 6', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cases/attachment_framework.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cases/attachment_framework.ts index c20c2da7235c..39973a9eed08 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cases/attachment_framework.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cases/attachment_framework.ts @@ -98,7 +98,7 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await testSubjects.click('embeddablePanelAction-embeddable_addToExistingCase'); // verify that solution filter is not visible - await testSubjects.missingOrFail('solution-filter-popover-button'); + await testSubjects.missingOrFail('options-filter-popover-button-owner'); await testSubjects.click(`cases-table-row-select-${theCase.id}`); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cases/list_view.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cases/list_view.ts index e672f99780fa..7fe3789ea64e 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cases/list_view.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cases/list_view.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import { SECURITY_SOLUTION_OWNER } from '@kbn/cases-plugin/common'; import { CaseSeverity, CaseStatuses } from '@kbn/cases-plugin/common/types/domain'; -import { SeverityAll } from '@kbn/cases-plugin/common/ui'; import { navigateToCasesApp } from '../../../../../shared/lib/cases/helpers'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -183,20 +182,21 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { // by default filter by all await cases.casesTable.validateCasesTableHasNthRows(5); - // low await cases.casesTable.filterBySeverity(CaseSeverity.LOW); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.LOW); - // high await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); await cases.casesTable.validateCasesTableHasNthRows(2); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.HIGH); - // critical await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); await cases.casesTable.validateCasesTableHasNthRows(1); + // to uncheck + await cases.casesTable.filterBySeverity(CaseSeverity.CRITICAL); - // back to all - await cases.casesTable.filterBySeverity(SeverityAll); await cases.casesTable.validateCasesTableHasNthRows(5); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts b/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts index f0dbed0ca9a7..3a4153b264cc 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts @@ -20,7 +20,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.svlCommonPage.login(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ihp_outlier'); - await ml.testResources.createIndexPatternIfNeeded('ft_ihp_outlier', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_ihp_outlier', '@timestamp'); await ml.api.createDataFrameAnalyticsJob( ml.commonConfig.getDFAIhpOutlierDetectionJobConfig(dfaJobId) diff --git a/x-pack/test_serverless/shared/config.base.ts b/x-pack/test_serverless/shared/config.base.ts index ec11099f946c..6dee26203b53 100644 --- a/x-pack/test_serverless/shared/config.base.ts +++ b/x-pack/test_serverless/shared/config.base.ts @@ -16,15 +16,16 @@ import { kibanaTestSuperuserServerless, getDockerFileMountPath, } from '@kbn/test'; -import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH, kibanaDevServiceAccount } from '@kbn/dev-utils'; +import { CA_CERT_PATH, kibanaDevServiceAccount } from '@kbn/dev-utils'; import { commonFunctionalServices } from '@kbn/ftr-common-functional-services'; +import { MOCK_IDP_REALM_NAME } from '@kbn/mock-idp-plugin/common'; import { services } from './services'; export default async () => { const servers = { kibana: { ...kbnTestConfig.getUrlParts(kibanaTestSuperuserServerless), - protocol: 'https', + protocol: process.env.TEST_CLOUD ? 'https' : 'http', certificateAuthorities: process.env.TEST_CLOUD ? undefined : [Fs.readFileSync(CA_CERT_PATH)], }, elasticsearch: { @@ -68,16 +69,6 @@ export default async () => { 'xpack.security.authc.realms.jwt.jwt1.order=-98', `xpack.security.authc.realms.jwt.jwt1.pkc_jwkset_path=${getDockerFileMountPath(jwksPath)}`, `xpack.security.authc.realms.jwt.jwt1.token_type=access_token`, - - 'xpack.security.authc.realms.saml.cloud-saml-kibana.attributes.principal=urn:oid:0.0.7', - 'xpack.security.authc.realms.saml.cloud-saml-kibana.idp.entity_id=http://www.elastic.co/saml1', - 'xpack.security.authc.realms.saml.cloud-saml-kibana.order=101', - `xpack.security.authc.realms.saml.cloud-saml-kibana.idp.metadata.path=${getDockerFileMountPath( - idpPath - )}`, - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.acs=http://localhost:${servers.kibana.port}/api/security/saml/callback`, - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.entity_id=http://localhost:${servers.kibana.port}`, - `xpack.security.authc.realms.saml.cloud-saml-kibana.sp.logout=http://localhost:${servers.kibana.port}/logout`, ], ssl: true, // SSL is required for SAML realm }, @@ -89,10 +80,6 @@ export default async () => { }, sourceArgs: ['--no-base-path', '--env.name=development'], serverArgs: [ - '--server.ssl.enabled=true', - `--server.ssl.key=${KBN_KEY_PATH}`, - `--server.ssl.certificate=${KBN_CERT_PATH}`, - `--server.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--server.restrictInternalApis=true`, `--server.port=${servers.kibana.port}`, '--status.allowAnonymous=true', @@ -147,7 +134,7 @@ export default async () => { // user navigates to `/login` page directly and enters username and password in the login form. '--xpack.security.authc.selector.enabled=false', `--xpack.security.authc.providers=${JSON.stringify({ - saml: { 'cloud-saml-kibana': { order: 0, realm: 'cloud-saml-kibana' } }, + saml: { 'cloud-saml-kibana': { order: 0, realm: MOCK_IDP_REALM_NAME } }, basic: { 'cloud-basic': { order: 1 } }, })}`, '--xpack.encryptedSavedObjects.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', diff --git a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml index a8f7adfc8577..8b0627d960a4 100644 --- a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml +++ b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml @@ -240,6 +240,7 @@ t3_analyst: privileges: - read - write + - maintenance - names: - .lists* - .items* @@ -293,12 +294,16 @@ threat_intelligence_analyst: - endgame-* - filebeat-* - logs-* - - .lists* - - .items* - packetbeat-* - winlogbeat-* privileges: - read + - names: + - .lists* + - .items* + privileges: + - read + - write - names: - .alerts-security* - .siem-signals-* @@ -317,8 +322,7 @@ threat_intelligence_analyst: - application: "kibana-.kibana" privileges: - feature_ml.read - - feature_siem.read - - feature_siem.read_alerts + - feature_siem.all - feature_siem.endpoint_list_read - feature_siem.blocklist_all - feature_securitySolutionCases.all @@ -603,6 +607,7 @@ endpoint_operations_analyst: privileges: - read - write + - maintenance applications: - application: "kibana-.kibana" privileges: @@ -653,11 +658,15 @@ endpoint_policy_manager: - logs-* - packetbeat-* - winlogbeat-* + - risk-score.risk-score-* + privileges: + - read + - names: - .lists* - .items* - - risk-score.risk-score-* privileges: - read + - write - names: - .alerts-security* - .siem-signals-* diff --git a/x-pack/test_serverless/shared/services/deployment_agnostic_services.ts b/x-pack/test_serverless/shared/services/deployment_agnostic_services.ts index 4721a6f71d10..ce922732796f 100644 --- a/x-pack/test_serverless/shared/services/deployment_agnostic_services.ts +++ b/x-pack/test_serverless/shared/services/deployment_agnostic_services.ts @@ -21,6 +21,7 @@ const deploymentAgnosticApiIntegrationServices = _.pick(apiIntegrationServices, 'esSupertest', 'indexPatterns', 'ingestPipelines', + 'indexManagement', 'kibanaServer', 'ml', 'randomness', diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index b4fdeb93c91c..af6f6e4b25e9 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -48,7 +48,7 @@ "@kbn/rison", "@kbn/discover-plugin", "@kbn/data-plugin", - "@kbn/security-api-integration-helpers", + "@kbn/std", "@kbn/data-view-field-editor-plugin", "@kbn/data-plugin", "@kbn/dev-utils", @@ -63,8 +63,11 @@ "@kbn/cloud-security-posture-plugin", "@kbn/reporting-plugin", "@kbn/management-settings-ids", + "@kbn/fleet-plugin", "@kbn/apm-synthtrace", "@kbn/apm-synthtrace-client", "@kbn/reporting-export-types-csv-common", + "@kbn/mock-idp-plugin", + "@kbn/index-management-plugin", ] } diff --git a/yarn.lock b/yarn.lock index b35cb584ca5c..a544bef1859d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -91,6 +91,39 @@ resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== +"@aws-crypto/crc32@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" + integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/util@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0" + integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/types@^3.222.0": + version "3.433.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.433.0.tgz#0f94eae2a4a3525ca872c9ab04e143c01806d755" + integrity sha512-0jEE2mSrNDd8VGFjTc1otYrwYPIkzZJEIK90ZxisKvQ/EURGBhNzWn7ejWB9XCMFT6XumYLBR0V9qq5UPisWtA== + dependencies: + "@smithy/types" "^2.4.0" + tslib "^2.5.0" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + "@babel/cli@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.21.0.tgz#1868eb70e9824b427fc607610cce8e9e7889e7e1" @@ -1544,19 +1577,17 @@ dependencies: tslib "^1.9.3" -"@elastic/ecs-helpers@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@elastic/ecs-helpers/-/ecs-helpers-1.1.0.tgz#ee7e6f870f75a2222c5d7179b36a628f1db4779e" - integrity sha512-MDLb2aFeGjg46O5mLpdCzT5yOUDnXToJSrco2ShqGIXxNJaM8uJjX+4nd+hRYV4Vex8YJyDtOFEVBldQct6ndg== - dependencies: - fast-json-stringify "^2.4.1" +"@elastic/ecs-helpers@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@elastic/ecs-helpers/-/ecs-helpers-2.1.1.tgz#8a375b307c33a959938d9ae8f9abb466eb9fb3bf" + integrity sha512-ItoNazMnYdlUCmkBYTXc3SG6PF7UlVTbvMdHPvXkfTMPdwGv2G1Xtp5CjDHaGHGOZSwaDrW4RSCXvA/lMSU+rg== -"@elastic/ecs-pino-format@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@elastic/ecs-pino-format/-/ecs-pino-format-1.2.0.tgz#3ee709eb2343b4d1a7a6d23bc467673d8c0de2c2" - integrity sha512-7TGPoxPMHkhqdp98u9F1+4aNwktgh8tlG/PX2c/d/RcAqHziaRCc72tuwGLMu9K/w/M5bWz0eKbcFXr4fSZGwg== +"@elastic/ecs-pino-format@^1.2.0", "@elastic/ecs-pino-format@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@elastic/ecs-pino-format/-/ecs-pino-format-1.5.0.tgz#48610e06e939b50bfa3629da0d2fcb1c74a69a20" + integrity sha512-7MMVmT50ucEl7no8mUgCIl+pffBVNRl36uZi0vmalWa2xPWISBxM9k9WSP/WTgOkmGj9G35e5g3UfCS1zxshBg== dependencies: - "@elastic/ecs-helpers" "^1.1.0" + "@elastic/ecs-helpers" "^2.1.1" "@elastic/elasticsearch-types@npm:@elastic/elasticsearch@^8.2.1": version "8.6.0" @@ -1594,10 +1625,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@90.0.0": - version "90.0.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-90.0.0.tgz#f105576513ed2fb31fefab5e1287be4e090ba0f3" - integrity sha512-4LXY4CwXU3FHeOiW76VPTaYcPVKEiqpb8GGHFEkYfBPWBgXyUJUVJyXwX9k8pzXElxM9I68OTDVRxIUzEzFiug== +"@elastic/eui@90.0.1": + version "90.0.1" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-90.0.1.tgz#f70391559a113d6df4622f5c0160fb94dc064885" + integrity sha512-KMr3blXQUBQjCjb4hskKaNMxLwJOOLSOwAvoZQjqj3ZxQS9yinZ1Ly8mn16ua8iC6HVra1GB0lsNyrCD+VlgwA== dependencies: "@hello-pangea/dnd" "^16.3.0" "@types/lodash" "^4.14.198" @@ -3108,6 +3139,14 @@ version "0.0.0" uid "" +"@kbn/calculate-auto@link:packages/kbn-calculate-auto": + version "0.0.0" + uid "" + +"@kbn/calculate-width-from-char-count@link:packages/kbn-calculate-width-from-char-count": + version "0.0.0" + uid "" + "@kbn/canvas-plugin@link:x-pack/plugins/canvas": version "0.0.0" uid "" @@ -4096,6 +4135,10 @@ version "0.0.0" uid "" +"@kbn/custom-icons@link:packages/kbn-custom-icons": + version "0.0.0" + uid "" + "@kbn/custom-integrations-plugin@link:src/plugins/custom_integrations": version "0.0.0" uid "" @@ -4268,6 +4311,10 @@ version "0.0.0" uid "" +"@kbn/elastic-agent-utils@link:packages/kbn-elastic-agent-utils": + version "0.0.0" + uid "" + "@kbn/elastic-assistant-plugin@link:x-pack/plugins/elastic_assistant": version "0.0.0" uid "" @@ -4944,6 +4991,10 @@ version "0.0.0" uid "" +"@kbn/ml-creation-wizard-utils@link:x-pack/packages/ml/creation_wizard_utils": + version "0.0.0" + uid "" + "@kbn/ml-data-frame-analytics-utils@link:x-pack/packages/ml/data_frame_analytics_utils": version "0.0.0" uid "" @@ -4952,6 +5003,10 @@ version "0.0.0" uid "" +"@kbn/ml-data-view-utils@link:x-pack/packages/ml/data_view_utils": + version "0.0.0" + uid "" + "@kbn/ml-date-picker@link:x-pack/packages/ml/date_picker": version "0.0.0" uid "" @@ -5024,10 +5079,18 @@ version "0.0.0" uid "" +"@kbn/ml-ui-actions@link:x-pack/packages/ml/ui_actions": + version "0.0.0" + uid "" + "@kbn/ml-url-state@link:x-pack/packages/ml/url_state": version "0.0.0" uid "" +"@kbn/mock-idp-plugin@link:packages/kbn-mock-idp-plugin": + version "0.0.0" + uid "" + "@kbn/monaco@link:packages/kbn-monaco": version "0.0.0" uid "" @@ -5080,6 +5143,10 @@ version "0.0.0" uid "" +"@kbn/observability-get-padded-alert-time-range-util@link:x-pack/packages/observability/get_padded_alert_time_range_util": + version "0.0.0" + uid "" + "@kbn/observability-log-explorer-plugin@link:x-pack/plugins/observability_log_explorer": version "0.0.0" uid "" @@ -5104,6 +5171,10 @@ version "0.0.0" uid "" +"@kbn/openapi-bundler@link:packages/kbn-openapi-bundler": + version "0.0.0" + uid "" + "@kbn/openapi-generator@link:packages/kbn-openapi-generator": version "0.0.0" uid "" @@ -5132,6 +5203,10 @@ version "0.0.0" uid "" +"@kbn/panel-loader@link:packages/kbn-panel-loader": + version "0.0.0" + uid "" + "@kbn/peggy-loader@link:packages/kbn-peggy-loader": version "0.0.0" uid "" @@ -5440,6 +5515,18 @@ version "0.0.0" uid "" +"@kbn/security-plugin-types-common@link:x-pack/packages/security/plugin_types_common": + version "0.0.0" + uid "" + +"@kbn/security-plugin-types-public@link:x-pack/packages/security/plugin_types_public": + version "0.0.0" + uid "" + +"@kbn/security-plugin-types-server@link:x-pack/packages/security/plugin_types_server": + version "0.0.0" + uid "" + "@kbn/security-plugin@link:x-pack/plugins/security": version "0.0.0" uid "" @@ -5884,10 +5971,6 @@ version "0.0.0" uid "" -"@kbn/subscription-tracking@link:packages/kbn-subscription-tracking": - version "0.0.0" - uid "" - "@kbn/synthetics-plugin@link:x-pack/plugins/synthetics": version "0.0.0" uid "" @@ -6624,6 +6707,17 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@npmcli/agent@^2.0.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.0.tgz#e81f00fdb2a670750ff7731bbefb47ecbf0ccf44" + integrity sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.1" + "@npmcli/fs@^1.0.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" @@ -7358,6 +7452,53 @@ "@types/node" ">=8.9.0" axios "^0.21.1" +"@smithy/eventstream-codec@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.12.tgz#99fab750d0ac3941f341d912d3c3a1ab985e1a7a" + integrity sha512-ZZQLzHBJkbiAAdj2C5K+lBlYp/XJ+eH2uy+jgJgYIFW/o5AM59Hlj7zyI44/ZTDIQWmBxb3EFv/c5t44V8/g8A== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@smithy/types" "^2.4.0" + "@smithy/util-hex-encoding" "^2.0.0" + tslib "^2.5.0" + +"@smithy/is-array-buffer@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz#8fa9b8040651e7ba0b2f6106e636a91354ff7d34" + integrity sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug== + dependencies: + tslib "^2.5.0" + +"@smithy/types@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.4.0.tgz#ed35e429e3ea3d089c68ed1bf951d0ccbdf2692e" + integrity sha512-iH1Xz68FWlmBJ9vvYeHifVMWJf82ONx+OybPW8ZGf5wnEv2S0UXcU4zwlwJkRXuLKpcSLHrraHbn2ucdVXLb4g== + dependencies: + tslib "^2.5.0" + +"@smithy/util-buffer-from@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz#7eb75d72288b6b3001bc5f75b48b711513091deb" + integrity sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw== + dependencies: + "@smithy/is-array-buffer" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-hex-encoding@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz#0aa3515acd2b005c6d55675e377080a7c513b59e" + integrity sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-utf8@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.0.0.tgz#b4da87566ea7757435e153799df9da717262ad42" + integrity sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ== + dependencies: + "@smithy/util-buffer-from" "^2.0.0" + tslib "^2.5.0" + "@storybook/addon-a11y@^6.5.16": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-6.5.16.tgz#9288a6c1d111fa4ec501d213100ffff91757d3fc" @@ -8294,10 +8435,10 @@ "@tanstack/query-core" "4.29.11" use-sync-external-store "^1.2.0" -"@testim/chrome-version@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.3.tgz#fbb68696899d7b8c1b9b891eded9c04fe2cd5529" - integrity sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A== +"@testim/chrome-version@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.4.tgz#86e04e677cd6c05fa230dd15ac223fa72d1d7090" + integrity sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g== "@testing-library/dom@^8.0.0": version "8.19.0" @@ -8702,10 +8843,10 @@ resolved "https://registry.yarnpkg.com/@types/chroma-js/-/chroma-js-2.1.3.tgz#0b03d737ff28fad10eb884e0c6cedd5ffdc4ba0a" integrity sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g== -"@types/chromedriver@^81.0.2": - version "81.0.2" - resolved "https://registry.yarnpkg.com/@types/chromedriver/-/chromedriver-81.0.2.tgz#b01a1007f9b39804e8ebaed07b2b86a33a21e121" - integrity sha512-sWozcf88uN5B5hh9wuLupSY1JRuN551NjhbNTK+4DGp1c1qiQGprpPy+hJkWuckQcEzyDAN3BbOezXfefWAI/Q== +"@types/chromedriver@^81.0.5": + version "81.0.5" + resolved "https://registry.yarnpkg.com/@types/chromedriver/-/chromedriver-81.0.5.tgz#c7b82f45c1cb9ebe47b7fb24a8641c9adf181b67" + integrity sha512-VwV+WTTFHYZotBn57QQ8gd4TE7CGJ15KPM+xJJrKbiQQSccTY7zVXuConSBlyWrO+AFpVxuzmluK3xvzxGmkCw== dependencies: "@types/node" "*" @@ -9799,10 +9940,10 @@ resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.28.tgz#9ce8fa048c1e8c85cb71d7fe4d704e000226036f" integrity sha512-SMA+fUwULwK7sd/ZJicUztiPs8F1yCPwF3O23Z9uQ32ME5Ha0NmDK9+QTsYE4O2tHXChzXomSWWeIhCnoN1LqA== -"@types/selenium-webdriver@^4.1.13": - version "4.1.13" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.1.13.tgz#c31e833a3e67a2d2c9e46da3aac8b6acbffc838a" - integrity sha512-kGpIh7bvu4HGCJXl4PEJ53kzpG4iXlRDd66SNNCfJ58QhFuk9skOm57lVffZap5ChEOJwbge/LJ9IVGVC8EEOg== +"@types/selenium-webdriver@^4.1.20": + version "4.1.20" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.1.20.tgz#00d10f0593c18fe72fabc55b8f62fa387a31a193" + integrity sha512-WxzARWDZVTbXlJgwYGhNoiV4OuHDabctSQmK5V88LqjW9TJiLETcknxRZ2xB1toecQnu0T2jt1pPXnSYkaWYiw== dependencies: "@types/ws" "*" @@ -10216,15 +10357,15 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@wdio/logger@^8.6.6": - version "8.6.6" - resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-8.6.6.tgz#6f3844a2506730ae1e4151dca0ed0242b5b69b63" - integrity sha512-MS+Y5yqFGx2zVXMOfuBQAVdFsP4DuYz+/hM552xwiDWjGg6EZHoccqUYgH3J5zpu3JFpYV3R/a5jExFiGGck6g== +"@wdio/logger@^8.11.0": + version "8.16.17" + resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-8.16.17.tgz#c2055857ed3e3cf12cfad843140fa79264c6a632" + integrity sha512-zeQ41z3T+b4IsrriZZipayXxLNDuGsm7TdExaviNGojPVrIsQUCSd/FvlLHM32b7ZrMyInHenu/zx1cjAZO71g== dependencies: chalk "^5.1.2" loglevel "^1.6.0" loglevel-plugin-prefix "^0.8.4" - strip-ansi "^6.0.0" + strip-ansi "^7.1.0" "@webassemblyjs/ast@1.11.1": version "1.11.1" @@ -10582,11 +10723,16 @@ abab@^2.0.4, abab@^2.0.6: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@1, abbrev@^1.0.0: +abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -10759,7 +10905,7 @@ ajv-keywords@^5.0.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.11.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -11482,7 +11628,7 @@ axios@^0.26.0: dependencies: follow-redirects "^1.14.8" -axios@^1.3.4, axios@^1.4.0, axios@^1.6.0: +axios@^1.3.4, axios@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== @@ -12362,16 +12508,16 @@ cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" -cacache@^17.0.0: - version "17.1.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.3.tgz#c6ac23bec56516a7c0c52020fd48b4909d7c7044" - integrity sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg== +cacache@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.0.tgz#17a9ecd6e1be2564ebe6cdca5f7cfed2bfeb6ddc" + integrity sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" glob "^10.2.2" - lru-cache "^7.7.1" - minipass "^5.0.0" + lru-cache "^10.0.1" + minipass "^7.0.3" minipass-collect "^1.0.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" @@ -12754,18 +12900,18 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^119.0.0: - version "119.0.0" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-119.0.0.tgz#f250c442e72266f3e28d2b1eebc6a671a8629340" - integrity sha512-3TmabGT7xg57/Jbsg6B/Kqk3HaSbCP1ZHkR5zNft5vT/IWKjZCAGTH9waMI+i5KHSEiMH0zOw/WF98l+1Npkpw== +chromedriver@^119.0.1: + version "119.0.1" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-119.0.1.tgz#064f3650790ccea055e9bfd95c600f5ea60295e9" + integrity sha512-lpCFFLaXPpvElTaUOWKdP74pFb/sJhWtWqMjn7Ju1YriWn8dT5JBk84BGXMPvZQs70WfCYWecxdMmwfIu1Mupg== dependencies: - "@testim/chrome-version" "^1.1.3" - axios "^1.4.0" - compare-versions "^6.0.0" + "@testim/chrome-version" "^1.1.4" + axios "^1.6.0" + compare-versions "^6.1.0" extract-zip "^2.0.1" https-proxy-agent "^5.0.1" proxy-from-env "^1.1.0" - tcp-port-used "^1.0.1" + tcp-port-used "^1.0.2" chromium-bidi@0.4.28: version "0.4.28" @@ -13174,7 +13320,7 @@ compare-versions@3.5.1: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393" integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== -compare-versions@^6.0.0: +compare-versions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== @@ -13342,6 +13488,11 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -14275,13 +14426,6 @@ debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, de dependencies: ms "2.1.2" -debug@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" - integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== - dependencies: - ms "^2.1.1" - debug@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -14289,6 +14433,13 @@ debug@4.1.1: dependencies: ms "^2.1.1" +debug@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -15160,12 +15311,12 @@ elastic-apm-node@3.46.0: traverse "^0.6.6" unicode-byte-truncate "^1.0.0" -elastic-apm-node@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.1.0.tgz#b1154a2d8e17b7762badf4fc696d8de7439ce928" - integrity sha512-8t9lbyfi4WUPxjPvRNO80QX2Ysf8I+D21wq+aphY+97Fk7kk6SDeZH+5U+o7HWSbqZpo/PYJGuKDUYc9PXuEWw== +elastic-apm-node@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.2.0.tgz#0b9fe675b94902734965d3b9da5424260e4e45a2" + integrity sha512-GbSjtQ+Q9lBZpY6bikatPCL7cMWPuBxHQ2yD0msfuP7JYXhWon42L8N7cqyepmp/F/YF++X8WJxuZM2G7J3kYQ== dependencies: - "@elastic/ecs-pino-format" "^1.2.0" + "@elastic/ecs-pino-format" "^1.4.0" "@opentelemetry/api" "^1.4.1" "@opentelemetry/core" "^1.11.0" "@opentelemetry/sdk-metrics" "^1.12.0" @@ -15174,7 +15325,7 @@ elastic-apm-node@^4.1.0: async-value-promise "^1.1.1" basic-auth "^2.0.1" breadth-filter "^2.0.0" - cookie "^0.5.0" + cookie "^0.6.0" core-util-is "^1.0.2" end-of-stream "^1.4.4" error-callsites "^2.0.4" @@ -16429,16 +16580,6 @@ fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-json-stringify@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.6.0.tgz#3dcb4835b63d4e17dbd17411594aa63df8c0f95b" - integrity sha512-xTZtZRopWp2Aun7sGX2EB2mFw4bMQ+xnR8BmD5Rn4K0hKXGkbcZAzTtxEX0P4KNaNx1RAwvf+FESfuM0+F4WZg== - dependencies: - ajv "^6.11.0" - deepmerge "^4.2.2" - rfdc "^1.2.0" - string-similarity "^4.0.1" - fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -17198,19 +17339,19 @@ gaze@^1.0.0: dependencies: globule "^1.0.0" -geckodriver@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-4.0.0.tgz#e078518f1b259b9c746bc4cea440dc9480abdbb2" - integrity sha512-1R1cuqqz+gqZ4Eux//TSbYDBpyYHHs9xLzG6BWJolORlaGkKWbg5qN3415fIi/5IkS7kTA2BEYvplB2GjH8oyw== +geckodriver@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-4.2.1.tgz#03ad628241417737b962966aa8f8b13fa0f8bf75" + integrity sha512-4m/CRk0OI8MaANRuFIahvOxYTSjlNAO2p9JmE14zxueknq6cdtB5M9UGRQ8R9aMV0bLGNVHHDnDXmoXdOwJfWg== dependencies: - "@wdio/logger" "^8.6.6" + "@wdio/logger" "^8.11.0" decamelize "^6.0.0" - http-proxy-agent "^6.0.1" - https-proxy-agent "^6.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" node-fetch "^3.3.1" - tar-fs "^2.1.1" + tar-fs "^3.0.4" unzipper "^0.10.14" - which "^3.0.1" + which "^4.0.0" gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -17457,16 +17598,16 @@ glob@8.1.0, glob@^8.0.1, glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" -glob@^10.2.2: - version "10.2.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.7.tgz#9dd2828cd5bc7bd861e7738d91e7113dda41d7d8" - integrity sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA== +glob@^10.2.2, glob@^10.3.10: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== dependencies: foreground-child "^3.1.0" - jackspeak "^2.0.3" + jackspeak "^2.3.5" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2" - path-scurry "^1.7.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0, glob@^7.2.3, glob@~7.2.0: version "7.2.3" @@ -17779,13 +17920,13 @@ handle-thing@^2.0.0: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== -handlebars@4.7.7, handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== +handlebars@4.7.8, handlebars@^4.7.7: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== dependencies: minimist "^1.2.5" - neo-async "^2.6.0" + neo-async "^2.6.2" source-map "^0.6.1" wordwrap "^1.0.0" optionalDependencies: @@ -18356,14 +18497,6 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-6.1.0.tgz#9bbaebd7d5afc8fae04a5820932b487405b95978" - integrity sha512-75t5ACHLOMnz/KsDAS4BdHx4J0sneT/HW+Sz070NR+n7RZ7SmYXYn2FXq6D0XwQid8hYgRVf6HZJrYuGzaEqtw== - dependencies: - agent-base "^7.0.2" - debug "^4.3.4" - http-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" @@ -18422,15 +18555,7 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: agent-base "6" debug "4" -https-proxy-agent@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-6.2.0.tgz#58c525a299663d958556969a8e3536dd1e007485" - integrity sha512-4xhCnMpxR9fupa7leh9uJK2P/qjYIeaM9uZ9c1bi1JDSwX2VH9NDk/oKSToNX4gBKa2WT31Mldne7e26ckohLQ== - dependencies: - agent-base "^7.0.2" - debug "4" - -https-proxy-agent@^7.0.2: +https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== @@ -18682,10 +18807,10 @@ inquirer@^8.2.5: through "^2.3.6" wrap-ansi "^7.0.0" -install-artifact-from-github@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.3.3.tgz#57d89bacfa0f47d7307fe41b6247cda9f9a8079c" - integrity sha512-x79SL0d8WOi1ZjXSTUqqs0GPQZ92YArJAN9O46wgU9wdH2U9ecyyhB9YGDbPe2OLV4ptmt6AZYRQZ2GydQZosQ== +install-artifact-from-github@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.3.5.tgz#88c96fe40e5eb21d45586d564208c648a1dbf38d" + integrity sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg== internal-slot@^1.0.3, internal-slot@^1.0.5: version "1.0.5" @@ -18762,10 +18887,10 @@ io-ts@^2.0.5: resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.0.5.tgz#e6e3db9df8b047f9cbd6b69e7d2ad3e6437a0b13" integrity sha512-pL7uUptryanI5Glv+GUv7xh+aLBjxGEDmLwmEYNSx0yOD3djK0Nw5Bt0N6BAkv9LadOUU7QKpRsLcqnTh3UlLA== -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= +ip-regex@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== ip@^1.1.8: version "1.1.8" @@ -19325,7 +19450,7 @@ is-url-superb@^4.0.0: resolved "https://registry.yarnpkg.com/is-url-superb/-/is-url-superb-4.0.0.tgz#b54d1d2499bb16792748ac967aa3ecb41a33a8c2" integrity sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA== -is-url@^1.2.2, is-url@^1.2.4: +is-url@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== @@ -19399,14 +19524,14 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== -is2@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is2/-/is2-2.0.1.tgz#8ac355644840921ce435d94f05d3a94634d3481a" - integrity sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA== +is2@^2.0.6: + version "2.0.9" + resolved "https://registry.yarnpkg.com/is2/-/is2-2.0.9.tgz#ff63b441f90de343fa8fac2125ee170da8e8240d" + integrity sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g== dependencies: deep-is "^0.1.3" - ip-regex "^2.1.0" - is-url "^1.2.2" + ip-regex "^4.1.0" + is-url "^1.2.4" isarray@0.0.1: version "0.0.1" @@ -19433,6 +19558,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + isnumber@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isnumber/-/isnumber-1.0.0.tgz#0e3f9759b581d99dd85086f0ec2a74909cfadd01" @@ -19571,10 +19701,10 @@ its-name@1.0.0: resolved "https://registry.yarnpkg.com/its-name/-/its-name-1.0.0.tgz#2065f1883ecb568c65f7112ddbf123401fae4af0" integrity sha1-IGXxiD7LVoxl9xEt2/EjQB+uSvA= -jackspeak@^2.0.3: - version "2.2.1" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.1.tgz#655e8cf025d872c9c03d3eb63e8f0c024fef16a6" - integrity sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw== +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -20608,10 +20738,10 @@ kuler@^2.0.0: resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== -langchain@^0.0.151: - version "0.0.151" - resolved "https://registry.yarnpkg.com/langchain/-/langchain-0.0.151.tgz#10c1ebdda0d772e49dbca755ada6307c9280f601" - integrity sha512-RA7/ELK5dqUgv5glIP5Wm5JmbnrjH/eeROYdKGDGaDUNZrRJ2CLuEu+oJH7hcE5hpPoPlkLBCs/vz4hvr/YtYw== +langchain@^0.0.186: + version "0.0.186" + resolved "https://registry.yarnpkg.com/langchain/-/langchain-0.0.186.tgz#59753972764d7ee4cf3e00dca1d74c95659bccbd" + integrity sha512-uXDipmw9aUrUmDNcFr2XH9ORmshWIlIb/qFKneS1K3X5upMUg7TSbaBxqV9WxuuenLUSYaoTcTy7P/pKkbqXPg== dependencies: "@anthropic-ai/sdk" "^0.6.2" ansi-styles "^5.0.0" @@ -20624,16 +20754,15 @@ langchain@^0.0.151: js-yaml "^4.1.0" jsonpointer "^5.0.1" langchainhub "~0.0.6" - langsmith "~0.0.31" + langsmith "~0.0.48" ml-distance "^4.0.0" - object-hash "^3.0.0" - openai "~4.4.0" + openai "^4.17.0" openapi-types "^12.1.3" p-queue "^6.6.2" p-retry "4" uuid "^9.0.0" yaml "^2.2.1" - zod "^3.21.4" + zod "^3.22.3" zod-to-json-schema "^3.20.4" langchainhub@~0.0.6: @@ -20641,10 +20770,10 @@ langchainhub@~0.0.6: resolved "https://registry.yarnpkg.com/langchainhub/-/langchainhub-0.0.6.tgz#9d2d06e4ce0807b4e8a31e19611f57aef990b54d" integrity sha512-SW6105T+YP1cTe0yMf//7kyshCgvCTyFBMTgH2H3s9rTAR4e+78DA/BBrUL/Mt4Q5eMWui7iGuAYb3pgGsdQ9w== -langsmith@~0.0.31: - version "0.0.33" - resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.0.33.tgz#0b8b0a7b9981777f37df86748892e417bdf94aea" - integrity sha512-8dVBjJsuIwsnUFtA6OJ85k2wWzpka+LsF2EFzpzpF3yOHO/Ui7oeCMobyp6L7QcgWIBdRUIJY6sNSxAW0uAMHg== +langsmith@^0.0.48, langsmith@~0.0.48: + version "0.0.48" + resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.0.48.tgz#3a9a8ce257271ddb43d01ebf585c4370a3a3ba79" + integrity sha512-s0hW8iZ90Q9XLTnDK0Pgee245URV3b1cXQjPDj5OKm1+KN7iSK1pKx+4CO7RcFLz58Ixe7Mt+mVcomYqUuryxQ== dependencies: "@types/uuid" "^9.0.1" commander "^10.0.1" @@ -21239,10 +21368,10 @@ lowlight@^1.14.0: fault "^1.0.0" highlight.js "~10.4.0" -lru-cache@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" - integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== +lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== lru-cache@^4.0.0, lru-cache@^4.1.5: version "4.1.5" @@ -21271,11 +21400,6 @@ lru-cache@^7.14.1, lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -lru-cache@^9.1.1: - version "9.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.2.tgz#255fdbc14b75589d6d0e73644ca167a8db506835" - integrity sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ== - lru-queue@0.1: version "0.1.0" resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" @@ -21352,25 +21476,21 @@ make-fetch-happen@^10.0.4: socks-proxy-agent "^7.0.0" ssri "^9.0.0" -make-fetch-happen@^11.0.3: - version "11.1.1" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz#85ceb98079584a9523d4bf71d32996e7e208549f" - integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w== +make-fetch-happen@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" + integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== dependencies: - agentkeepalive "^4.2.1" - cacache "^17.0.0" + "@npmcli/agent" "^2.0.0" + cacache "^18.0.0" http-cache-semantics "^4.1.1" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^5.0.0" + minipass "^7.0.2" minipass-fetch "^3.0.0" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" negotiator "^0.6.3" promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" ssri "^10.0.0" make-fetch-happen@^9.1.0: @@ -22116,10 +22236,10 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" - integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3: + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" @@ -22496,10 +22616,10 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nan@^2.17.0, nan@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" + integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== nano-css@^5.2.1: version "5.2.1" @@ -22582,7 +22702,7 @@ negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1, neo-async@^2.6.2: +neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -22728,33 +22848,32 @@ node-gyp-build@^4.2.2, node-gyp-build@^4.2.3, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== -node-gyp@^8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" - integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== +node-gyp@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" + integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== dependencies: env-paths "^2.2.0" - glob "^7.1.4" + exponential-backoff "^3.1.1" + glob "^10.3.10" graceful-fs "^4.2.6" - make-fetch-happen "^9.1.0" - nopt "^5.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" + make-fetch-happen "^13.0.0" + nopt "^7.0.0" + proc-log "^3.0.0" semver "^7.3.5" tar "^6.1.2" - which "^2.0.2" + which "^4.0.0" -node-gyp@^9.4.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.4.0.tgz#2a7a91c7cba4eccfd95e949369f27c9ba704f369" - integrity sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg== +node-gyp@^8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" + integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== dependencies: env-paths "^2.2.0" - exponential-backoff "^3.1.1" glob "^7.1.4" graceful-fs "^4.2.6" - make-fetch-happen "^11.0.3" - nopt "^6.0.0" + make-fetch-happen "^9.1.0" + nopt "^5.0.0" npmlog "^6.0.0" rimraf "^3.0.2" semver "^7.3.5" @@ -22869,12 +22988,12 @@ nopt@^5.0.0: dependencies: abbrev "1" -nopt@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" - integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g== +nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== dependencies: - abbrev "^1.0.0" + abbrev "^2.0.0" normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: version "2.5.0" @@ -23066,11 +23185,6 @@ object-hash@^1.3.0, object-hash@^1.3.1: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== -object-hash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" - integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== - object-identity-map@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/object-identity-map/-/object-identity-map-1.0.2.tgz#2b4213a4285ca3a8cd2e696782c9964f887524e7" @@ -23277,10 +23391,10 @@ openai@^3.3.0: axios "^0.26.0" form-data "^4.0.0" -openai@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/openai/-/openai-4.4.0.tgz#dbaab326eb044ddec479951b245850c482678031" - integrity sha512-JN0t628Kh95T0IrXl0HdBqnlJg+4Vq0Bnh55tio+dfCnyzHvMLiWyCM9m726MAJD2YkDU4/8RQB6rNbEq9ct2w== +openai@^4.17.0: + version "4.17.5" + resolved "https://registry.yarnpkg.com/openai/-/openai-4.17.5.tgz#096655741965656ec969731e97d4bce880112d66" + integrity sha512-SDgA933/QOjISCgWRc/JQhY1HweYZ6FOie3bWrCpj09FA5xIlaomldbyzICHNjtkh7SWEmGYFjRHIDtuwr+eTw== dependencies: "@types/node" "^18.11.18" "@types/node-fetch" "^2.6.4" @@ -23290,6 +23404,7 @@ openai@~4.4.0: form-data-encoder "1.7.2" formdata-node "^4.3.2" node-fetch "^2.6.7" + web-streams-polyfill "^3.2.1" openapi-types@^10.0.0: version "10.0.0" @@ -23808,13 +23923,13 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.7.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.9.2.tgz#90f9d296ac5e37e608028e28a447b11d385b3f63" - integrity sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== dependencies: - lru-cache "^9.1.1" - minipass "^5.0.0 || ^6.0.2" + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.7: version "0.1.7" @@ -24634,6 +24749,11 @@ prismjs@^1.22.0, prismjs@~1.27.0: resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -25150,14 +25270,14 @@ re-resizable@^6.9.9: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== -re2@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/re2/-/re2-1.20.1.tgz#27450f6de6299635f50305a670cc15ac30687f85" - integrity sha512-JbzIoI5adNCqGUK8wHG1dMSyggvPyA4kx2hewt1lma5sP7/iWCfM15XKbCZlX2yvu5k80jSKAOQqJF7KC+2n8Q== +re2@1.20.9: + version "1.20.9" + resolved "https://registry.yarnpkg.com/re2/-/re2-1.20.9.tgz#3e6e5b73cdd911cdbdfe5133cc6670600e33871b" + integrity sha512-ZYcPTFr5ha2xq3WQjBDTF9CWPSDK1z28MLh5UFRxc//7X8BNQ3A7yR7ITnP0jO346661ertdKVFqw1qoL3FMEQ== dependencies: - install-artifact-from-github "^1.3.3" - nan "^2.17.0" - node-gyp "^9.4.0" + install-artifact-from-github "^1.3.5" + nan "^2.18.0" + node-gyp "^10.0.1" react-ace@^7.0.5: version "7.0.5" @@ -26521,11 +26641,6 @@ rfc4648@^1.5.2: resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.2.tgz#cf5dac417dd83e7f4debf52e3797a723c1373383" integrity sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg== -rfdc@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - rgbcolor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d" @@ -26864,14 +26979,14 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@^4.9.1: - version "4.9.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.9.1.tgz#24c4055258b8be50792186fe52b60cd00f768481" - integrity sha512-6OBMaSXwn3/vzQJkfYpAjGaYAA+otsE7zu0omz74HQ9XBuAMUImdVS6hKXlB2G3Bt9WIuVfK0F4V8oye8JRc3Q== +selenium-webdriver@^4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.15.0.tgz#ee827f8993864dc0821df0d3b46d4f312d6f1aa3" + integrity sha512-BNG1bq+KWiBGHcJ/wULi0eKY0yaDqFIbEmtbsYJmfaEghdCkXBsx1akgOorhNwjBipOr0uwpvNXqT6/nzl+zjg== dependencies: jszip "^3.10.1" tmp "^0.2.1" - ws ">=8.13.0" + ws ">=8.14.2" selfsigned@^2.0.1: version "2.0.1" @@ -27357,7 +27472,7 @@ socks-proxy-agent@^7.0.0: debug "^4.3.3" socks "^2.6.2" -socks-proxy-agent@^8.0.2: +socks-proxy-agent@^8.0.1, socks-proxy-agent@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad" integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== @@ -27914,11 +28029,6 @@ string-replace-loader@^2.2.0: loader-utils "^1.2.3" schema-utils "^1.0.0" -string-similarity@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.3.tgz#ef52d6fc59c8a0fc93b6307fbbc08cc6e18cde21" - integrity sha512-QEwJzNFCqq+5AGImk5z4vbsEPTN/+gtyKfXBVLBcbPBRPNganZGfQnIuf9yJ+GiwSnD65sT8xrw/uwU1Q1WmfQ== - "string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -28073,7 +28183,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^7.0.1: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -28500,13 +28610,13 @@ tcomb@^3.0.0, tcomb@^3.2.17: resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-3.2.29.tgz#32404fe9456d90c2cf4798682d37439f1ccc386c" integrity sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ== -tcp-port-used@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.1.tgz#46061078e2d38c73979a2c2c12b5a674e6689d70" - integrity sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q== +tcp-port-used@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.2.tgz#9652b7436eb1f4cfae111c79b558a25769f6faea" + integrity sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA== dependencies: - debug "4.1.0" - is2 "2.0.1" + debug "4.3.1" + is2 "^2.0.6" teex@^1.0.1: version "1.0.1" @@ -29056,10 +29166,10 @@ tslib@2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: - version "1.13.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" - integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.2: version "2.6.2" @@ -30788,12 +30898,12 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -which@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" - integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== +which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== dependencies: - isexe "^2.0.0" + isexe "^3.1.1" wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" @@ -30952,7 +31062,7 @@ write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@8.14.2, ws@>=8.13.0, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: +ws@8.14.2, ws@>=8.14.2, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: version "8.14.2" resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== @@ -31269,7 +31379,7 @@ zod-to-json-schema@^3.20.4: resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.21.4.tgz#de97c5b6d4a25e9d444618486cb55c0c7fb949fd" integrity sha512-fjUZh4nQ1s6HMccgIeE0VP4QG/YRGPmyjO9sAh890aQKPEk3nqbfUXhMFaC+Dr5KvYBm8BCyvfpZf2jY9aGSsw== -zod@^3.21.4, zod@^3.22.3: +zod@^3.22.3: version "3.22.3" resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.3.tgz#2fbc96118b174290d94e8896371c95629e87a060" integrity sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==